xref: /rk3399_rockchip-uboot/board/socrates/nand.c (revision fd51b0e0e620b8bc9fd4f6daa3a4fa6f5e1316f4)
1*fd51b0e0SSergei Poselenov /*
2*fd51b0e0SSergei Poselenov  * (C) Copyright 2008
3*fd51b0e0SSergei Poselenov  * Sergei Poselenov, Emcraft Systems, sposelenov@emcraft.com.
4*fd51b0e0SSergei Poselenov  *
5*fd51b0e0SSergei Poselenov  * See file CREDITS for list of people who contributed to this
6*fd51b0e0SSergei Poselenov  * project.
7*fd51b0e0SSergei Poselenov  *
8*fd51b0e0SSergei Poselenov  * This program is free software; you can redistribute it and/or
9*fd51b0e0SSergei Poselenov  * modify it under the terms of the GNU General Public License as
10*fd51b0e0SSergei Poselenov  * published by the Free Software Foundation; either version 2 of
11*fd51b0e0SSergei Poselenov  * the License, or (at your option) any later version.
12*fd51b0e0SSergei Poselenov  *
13*fd51b0e0SSergei Poselenov  * This program is distributed in the hope that it will be useful,
14*fd51b0e0SSergei Poselenov  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15*fd51b0e0SSergei Poselenov  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
16*fd51b0e0SSergei Poselenov  * GNU General Public License for more details.
17*fd51b0e0SSergei Poselenov  *
18*fd51b0e0SSergei Poselenov  * You should have received a copy of the GNU General Public License
19*fd51b0e0SSergei Poselenov  * along with this program; if not, write to the Free Software
20*fd51b0e0SSergei Poselenov  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21*fd51b0e0SSergei Poselenov  * MA 02111-1307 USA
22*fd51b0e0SSergei Poselenov  */
23*fd51b0e0SSergei Poselenov 
24*fd51b0e0SSergei Poselenov #include <common.h>
25*fd51b0e0SSergei Poselenov 
26*fd51b0e0SSergei Poselenov #if defined(CFG_NAND_BASE)
27*fd51b0e0SSergei Poselenov #include <nand.h>
28*fd51b0e0SSergei Poselenov #include <asm/errno.h>
29*fd51b0e0SSergei Poselenov #include <asm/io.h>
30*fd51b0e0SSergei Poselenov 
31*fd51b0e0SSergei Poselenov static int state;
32*fd51b0e0SSergei Poselenov static void nand_write_byte(struct mtd_info *mtd, u_char byte);
33*fd51b0e0SSergei Poselenov static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len);
34*fd51b0e0SSergei Poselenov static void nand_write_word(struct mtd_info *mtd, u16 word);
35*fd51b0e0SSergei Poselenov static u_char nand_read_byte(struct mtd_info *mtd);
36*fd51b0e0SSergei Poselenov static u16 nand_read_word(struct mtd_info *mtd);
37*fd51b0e0SSergei Poselenov static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len);
38*fd51b0e0SSergei Poselenov static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len);
39*fd51b0e0SSergei Poselenov static int nand_device_ready(struct mtd_info *mtdinfo);
40*fd51b0e0SSergei Poselenov static void nand_hwcontrol(struct mtd_info *mtdinfo, int cmd);
41*fd51b0e0SSergei Poselenov 
42*fd51b0e0SSergei Poselenov #define FPGA_NAND_CMD_MASK		(0x7 << 28)
43*fd51b0e0SSergei Poselenov #define FPGA_NAND_CMD_COMMAND	(0x0 << 28)
44*fd51b0e0SSergei Poselenov #define FPGA_NAND_CMD_ADDR		(0x1 << 28)
45*fd51b0e0SSergei Poselenov #define FPGA_NAND_CMD_READ		(0x2 << 28)
46*fd51b0e0SSergei Poselenov #define FPGA_NAND_CMD_WRITE		(0x3 << 28)
47*fd51b0e0SSergei Poselenov #define FPGA_NAND_BUSY			(0x1 << 15)
48*fd51b0e0SSergei Poselenov #define FPGA_NAND_ENABLE		(0x1 << 31)
49*fd51b0e0SSergei Poselenov #define FPGA_NAND_DATA_SHIFT	16
50*fd51b0e0SSergei Poselenov 
51*fd51b0e0SSergei Poselenov /**
52*fd51b0e0SSergei Poselenov  * nand_write_byte -  write one byte to the chip
53*fd51b0e0SSergei Poselenov  * @mtd:	MTD device structure
54*fd51b0e0SSergei Poselenov  * @byte:	pointer to data byte to write
55*fd51b0e0SSergei Poselenov  */
56*fd51b0e0SSergei Poselenov static void nand_write_byte(struct mtd_info *mtd, u_char byte)
57*fd51b0e0SSergei Poselenov {
58*fd51b0e0SSergei Poselenov 	nand_write_buf(mtd, (const uchar *)&byte, sizeof(byte));
59*fd51b0e0SSergei Poselenov }
60*fd51b0e0SSergei Poselenov 
61*fd51b0e0SSergei Poselenov /**
62*fd51b0e0SSergei Poselenov  * nand_write_word -  write one word to the chip
63*fd51b0e0SSergei Poselenov  * @mtd:	MTD device structure
64*fd51b0e0SSergei Poselenov  * @word:	data word to write
65*fd51b0e0SSergei Poselenov  */
66*fd51b0e0SSergei Poselenov static void nand_write_word(struct mtd_info *mtd, u16 word)
67*fd51b0e0SSergei Poselenov {
68*fd51b0e0SSergei Poselenov 	nand_write_buf(mtd, (const uchar *)&word, sizeof(word));
69*fd51b0e0SSergei Poselenov }
70*fd51b0e0SSergei Poselenov 
71*fd51b0e0SSergei Poselenov /**
72*fd51b0e0SSergei Poselenov  * nand_write_buf -  write buffer to chip
73*fd51b0e0SSergei Poselenov  * @mtd:	MTD device structure
74*fd51b0e0SSergei Poselenov  * @buf:	data buffer
75*fd51b0e0SSergei Poselenov  * @len:	number of bytes to write
76*fd51b0e0SSergei Poselenov  */
77*fd51b0e0SSergei Poselenov static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
78*fd51b0e0SSergei Poselenov {
79*fd51b0e0SSergei Poselenov 	int i;
80*fd51b0e0SSergei Poselenov 	struct nand_chip *this = mtd->priv;
81*fd51b0e0SSergei Poselenov 	long val;
82*fd51b0e0SSergei Poselenov 
83*fd51b0e0SSergei Poselenov 	if ((state & FPGA_NAND_CMD_MASK) == FPGA_NAND_CMD_MASK) {
84*fd51b0e0SSergei Poselenov 		/* Write data */
85*fd51b0e0SSergei Poselenov 		val = (state & FPGA_NAND_ENABLE) | FPGA_NAND_CMD_WRITE;
86*fd51b0e0SSergei Poselenov 	} else {
87*fd51b0e0SSergei Poselenov 		/* Write address or command */
88*fd51b0e0SSergei Poselenov 		val = state;
89*fd51b0e0SSergei Poselenov 	}
90*fd51b0e0SSergei Poselenov 
91*fd51b0e0SSergei Poselenov 	for (i = 0; i < len; i++) {
92*fd51b0e0SSergei Poselenov 		out_be32(this->IO_ADDR_W, val | (buf[i] << FPGA_NAND_DATA_SHIFT));
93*fd51b0e0SSergei Poselenov 	}
94*fd51b0e0SSergei Poselenov }
95*fd51b0e0SSergei Poselenov 
96*fd51b0e0SSergei Poselenov 
97*fd51b0e0SSergei Poselenov /**
98*fd51b0e0SSergei Poselenov  * nand_read_byte -  read one byte from the chip
99*fd51b0e0SSergei Poselenov  * @mtd:	MTD device structure
100*fd51b0e0SSergei Poselenov  */
101*fd51b0e0SSergei Poselenov static u_char nand_read_byte(struct mtd_info *mtd)
102*fd51b0e0SSergei Poselenov {
103*fd51b0e0SSergei Poselenov 	u8 byte;
104*fd51b0e0SSergei Poselenov 	nand_read_buf(mtd, (uchar *)&byte, sizeof(byte));
105*fd51b0e0SSergei Poselenov 	return byte;
106*fd51b0e0SSergei Poselenov }
107*fd51b0e0SSergei Poselenov 
108*fd51b0e0SSergei Poselenov /**
109*fd51b0e0SSergei Poselenov  * nand_read_word -  read one word from the chip
110*fd51b0e0SSergei Poselenov  * @mtd:	MTD device structure
111*fd51b0e0SSergei Poselenov  */
112*fd51b0e0SSergei Poselenov static u16 nand_read_word(struct mtd_info *mtd)
113*fd51b0e0SSergei Poselenov {
114*fd51b0e0SSergei Poselenov 	u16 word;
115*fd51b0e0SSergei Poselenov 	nand_read_buf(mtd, (uchar *)&word, sizeof(word));
116*fd51b0e0SSergei Poselenov 	return word;
117*fd51b0e0SSergei Poselenov }
118*fd51b0e0SSergei Poselenov 
119*fd51b0e0SSergei Poselenov /**
120*fd51b0e0SSergei Poselenov  * nand_read_buf -  read chip data into buffer
121*fd51b0e0SSergei Poselenov  * @mtd:	MTD device structure
122*fd51b0e0SSergei Poselenov  * @buf:	buffer to store date
123*fd51b0e0SSergei Poselenov  * @len:	number of bytes to read
124*fd51b0e0SSergei Poselenov  */
125*fd51b0e0SSergei Poselenov static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
126*fd51b0e0SSergei Poselenov {
127*fd51b0e0SSergei Poselenov 	int i;
128*fd51b0e0SSergei Poselenov 	struct nand_chip *this = mtd->priv;
129*fd51b0e0SSergei Poselenov 	int val;
130*fd51b0e0SSergei Poselenov 
131*fd51b0e0SSergei Poselenov 	val = (state & FPGA_NAND_ENABLE) | FPGA_NAND_CMD_READ;
132*fd51b0e0SSergei Poselenov 
133*fd51b0e0SSergei Poselenov 	out_be32(this->IO_ADDR_W, val);
134*fd51b0e0SSergei Poselenov 	for (i = 0; i < len; i++) {
135*fd51b0e0SSergei Poselenov 		buf[i] = (in_be32(this->IO_ADDR_R) >> FPGA_NAND_DATA_SHIFT) & 0xff;
136*fd51b0e0SSergei Poselenov 	}
137*fd51b0e0SSergei Poselenov }
138*fd51b0e0SSergei Poselenov 
139*fd51b0e0SSergei Poselenov /**
140*fd51b0e0SSergei Poselenov  * nand_verify_buf -  Verify chip data against buffer
141*fd51b0e0SSergei Poselenov  * @mtd:	MTD device structure
142*fd51b0e0SSergei Poselenov  * @buf:	buffer containing the data to compare
143*fd51b0e0SSergei Poselenov  * @len:	number of bytes to compare
144*fd51b0e0SSergei Poselenov  */
145*fd51b0e0SSergei Poselenov static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
146*fd51b0e0SSergei Poselenov {
147*fd51b0e0SSergei Poselenov 	int i;
148*fd51b0e0SSergei Poselenov 
149*fd51b0e0SSergei Poselenov 	for (i = 0; i < len; i++) {
150*fd51b0e0SSergei Poselenov 		if (buf[i] != nand_read_byte(mtd));
151*fd51b0e0SSergei Poselenov 		return -EFAULT;
152*fd51b0e0SSergei Poselenov 	}
153*fd51b0e0SSergei Poselenov 	return 0;
154*fd51b0e0SSergei Poselenov }
155*fd51b0e0SSergei Poselenov 
156*fd51b0e0SSergei Poselenov /**
157*fd51b0e0SSergei Poselenov  * nand_device_ready - Check the NAND device is ready for next command.
158*fd51b0e0SSergei Poselenov  * @mtd:	MTD device structure
159*fd51b0e0SSergei Poselenov  */
160*fd51b0e0SSergei Poselenov static int nand_device_ready(struct mtd_info *mtdinfo)
161*fd51b0e0SSergei Poselenov {
162*fd51b0e0SSergei Poselenov 	struct nand_chip *this = mtdinfo->priv;
163*fd51b0e0SSergei Poselenov 
164*fd51b0e0SSergei Poselenov 	if (in_be32(this->IO_ADDR_W) & FPGA_NAND_BUSY)
165*fd51b0e0SSergei Poselenov 		return 0; /* busy */
166*fd51b0e0SSergei Poselenov 	return 1;
167*fd51b0e0SSergei Poselenov }
168*fd51b0e0SSergei Poselenov 
169*fd51b0e0SSergei Poselenov /**
170*fd51b0e0SSergei Poselenov  * nand_hwcontrol - NAND control functions wrapper.
171*fd51b0e0SSergei Poselenov  * @mtd:	MTD device structure
172*fd51b0e0SSergei Poselenov  * @cmd:	Command
173*fd51b0e0SSergei Poselenov  */
174*fd51b0e0SSergei Poselenov static void nand_hwcontrol(struct mtd_info *mtdinfo, int cmd)
175*fd51b0e0SSergei Poselenov {
176*fd51b0e0SSergei Poselenov 
177*fd51b0e0SSergei Poselenov 	switch(cmd) {
178*fd51b0e0SSergei Poselenov 	case NAND_CTL_CLRALE:
179*fd51b0e0SSergei Poselenov 		state |= FPGA_NAND_CMD_MASK; /* use all 1s to mark */
180*fd51b0e0SSergei Poselenov 		break;
181*fd51b0e0SSergei Poselenov 	case NAND_CTL_CLRCLE:
182*fd51b0e0SSergei Poselenov 		state |= FPGA_NAND_CMD_MASK; /* use all 1s to mark */
183*fd51b0e0SSergei Poselenov 		break;
184*fd51b0e0SSergei Poselenov 	case NAND_CTL_SETCLE:
185*fd51b0e0SSergei Poselenov 		state = (state & ~FPGA_NAND_CMD_MASK) | FPGA_NAND_CMD_COMMAND;
186*fd51b0e0SSergei Poselenov 		break;
187*fd51b0e0SSergei Poselenov 	case NAND_CTL_SETALE:
188*fd51b0e0SSergei Poselenov 		state = (state & ~FPGA_NAND_CMD_MASK) | FPGA_NAND_CMD_ADDR;
189*fd51b0e0SSergei Poselenov 		break;
190*fd51b0e0SSergei Poselenov 	case NAND_CTL_SETNCE:
191*fd51b0e0SSergei Poselenov 		state |= FPGA_NAND_ENABLE;
192*fd51b0e0SSergei Poselenov 		break;
193*fd51b0e0SSergei Poselenov 	case NAND_CTL_CLRNCE:
194*fd51b0e0SSergei Poselenov 		state &= ~FPGA_NAND_ENABLE;
195*fd51b0e0SSergei Poselenov 		break;
196*fd51b0e0SSergei Poselenov 	default:
197*fd51b0e0SSergei Poselenov 		printf("%s: unknown cmd %#x\n", __FUNCTION__, cmd);
198*fd51b0e0SSergei Poselenov 		break;
199*fd51b0e0SSergei Poselenov 	}
200*fd51b0e0SSergei Poselenov }
201*fd51b0e0SSergei Poselenov 
202*fd51b0e0SSergei Poselenov int board_nand_init(struct nand_chip *nand)
203*fd51b0e0SSergei Poselenov {
204*fd51b0e0SSergei Poselenov 	nand->hwcontrol = nand_hwcontrol;
205*fd51b0e0SSergei Poselenov 	nand->eccmode = NAND_ECC_SOFT;
206*fd51b0e0SSergei Poselenov 	nand->dev_ready = nand_device_ready;
207*fd51b0e0SSergei Poselenov 	nand->write_byte = nand_write_byte;
208*fd51b0e0SSergei Poselenov 	nand->read_byte = nand_read_byte;
209*fd51b0e0SSergei Poselenov 	nand->write_word = nand_write_word;
210*fd51b0e0SSergei Poselenov 	nand->read_word = nand_read_word;
211*fd51b0e0SSergei Poselenov 	nand->write_buf = nand_write_buf;
212*fd51b0e0SSergei Poselenov 	nand->read_buf = nand_read_buf;
213*fd51b0e0SSergei Poselenov 	nand->verify_buf = nand_verify_buf;
214*fd51b0e0SSergei Poselenov 
215*fd51b0e0SSergei Poselenov 	return 0;
216*fd51b0e0SSergei Poselenov }
217*fd51b0e0SSergei Poselenov 
218*fd51b0e0SSergei Poselenov #endif
219