xref: /rk3399_rockchip-uboot/drivers/rkflash/sfc_nand.c (revision 6281205a07d87a6722d342cddc8a4dfd33eafa20)
1ba0501acSDingqiang Lin /*
2ba0501acSDingqiang Lin  * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
3ba0501acSDingqiang Lin  *
4ba0501acSDingqiang Lin  * SPDX-License-Identifier:	GPL-2.0
5ba0501acSDingqiang Lin  */
6ba0501acSDingqiang Lin 
7ba0501acSDingqiang Lin #include <common.h>
8ba0501acSDingqiang Lin #include <linux/bug.h>
9ba0501acSDingqiang Lin #include <linux/delay.h>
10ba0501acSDingqiang Lin 
11ba0501acSDingqiang Lin #include "flash.h"
12ba0501acSDingqiang Lin #include "flash_com.h"
13ba0501acSDingqiang Lin #include "sfc.h"
14ba0501acSDingqiang Lin #include "sfc_nand.h"
15ba0501acSDingqiang Lin #include "rkflash_debug.h"
16ba0501acSDingqiang Lin 
17ba0501acSDingqiang Lin static struct nand_info spi_nand_tbl[] = {
18ba0501acSDingqiang Lin 	/* TC58CVG0S0HxAIx */
19*6281205aSDingqiang Lin 	{0x98C2, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x02, 0xD8, 0x00, 18, 8, 0xB0, 0XFF, 4, 8, NULL},
20ba0501acSDingqiang Lin 	/* TC58CVG1S0HxAIx */
21*6281205aSDingqiang Lin 	{0x98CB, 4, 64, 2, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x02, 0xD8, 0x00, 19, 8, 0xB0, 0XFF, 4, 8, NULL},
22ba0501acSDingqiang Lin 	/* MX35LF1GE4AB */
23*6281205aSDingqiang Lin 	{0xC212, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 18, 4, 0xB0, 0, 4, 8, &sfc_nand_ecc_status_sp1},
24ba0501acSDingqiang Lin 	/* MX35LF2GE4AB */
25*6281205aSDingqiang Lin 	{0xC222, 4, 64, 2, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 19, 4, 0xB0, 0, 4, 8, &sfc_nand_ecc_status_sp1},
26ba0501acSDingqiang Lin 	/* GD5F1GQ4UAYIG */
27*6281205aSDingqiang Lin 	{0xC8F1, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 18, 8, 0xB0, 0, 4, 8, NULL},
28ba0501acSDingqiang Lin 	/* MT29F1G01ZAC */
29*6281205aSDingqiang Lin 	{0x2C12, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x00, 18, 1, 0xB0, 0, 4, 8, &sfc_nand_ecc_status_sp1},
30*6281205aSDingqiang Lin 	/* GD5F2GQ40BY2GR */
31*6281205aSDingqiang Lin 	{0xC8D2, 4, 64, 2, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 19, 8, 0xB0, 0, 4, 8, &sfc_nand_ecc_status_sp3},
32ba0501acSDingqiang Lin 	/* GD5F1GQ4U */
33*6281205aSDingqiang Lin 	{0xC8D1, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 18, 8, 0xB0, 0, 4, 8, &sfc_nand_ecc_status_sp3},
34ba0501acSDingqiang Lin 	/* IS37SML01G1 */
35*6281205aSDingqiang Lin 	{0xC821, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x00, 18, 1, 0xB0, 0XFF, 8, 12, &sfc_nand_ecc_status_sp1},
36ba0501acSDingqiang Lin 	/* W25N01GV */
37*6281205aSDingqiang Lin 	{0xEFAA, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 18, 1, 0xFF, 0XFF, 4, 20, &sfc_nand_ecc_status_sp1},
38*6281205aSDingqiang Lin 	/* HYF2GQ4UAACAE */
39*6281205aSDingqiang Lin 	{0xC952, 4, 64, 2, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 19, 14, 0xB0, 0, 4, 36, NULL},
40*6281205aSDingqiang Lin 	/* HYF2GQ4UDACAE */
41*6281205aSDingqiang Lin 	{0xC922, 4, 64, 2, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 19, 4, 0xB0, 0, 4, 20, NULL},
42*6281205aSDingqiang Lin 	/* HYF1GQ4UDACAE */
43*6281205aSDingqiang Lin 	{0xC921, 4, 64, 2, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 18, 4, 0xB0, 0, 4, 20, NULL},
44ba0501acSDingqiang Lin };
45ba0501acSDingqiang Lin 
46ba0501acSDingqiang Lin static u8 id_byte[8];
47ba0501acSDingqiang Lin static struct nand_info *p_nand_info;
48ba0501acSDingqiang Lin static u32 gp_page_buf[SFC_NAND_PAGE_MAX_SIZE / 4];
49ba0501acSDingqiang Lin static struct SFNAND_DEV sfc_nand_dev;
50ba0501acSDingqiang Lin 
51ba0501acSDingqiang Lin static struct nand_info *spi_nand_get_info(u8 *nand_id)
52ba0501acSDingqiang Lin {
53ba0501acSDingqiang Lin 	u32 i;
54ba0501acSDingqiang Lin 	u32 id = (nand_id[0] << 8) | (nand_id[1] << 0);
55ba0501acSDingqiang Lin 
56ba0501acSDingqiang Lin 	for (i = 0; i < ARRAY_SIZE(spi_nand_tbl); i++) {
57ba0501acSDingqiang Lin 		if (spi_nand_tbl[i].id == id)
58ba0501acSDingqiang Lin 			return &spi_nand_tbl[i];
59ba0501acSDingqiang Lin 	}
60ba0501acSDingqiang Lin 	return NULL;
61ba0501acSDingqiang Lin }
62ba0501acSDingqiang Lin 
63ba0501acSDingqiang Lin static int sfc_nand_write_en(void)
64ba0501acSDingqiang Lin {
65ba0501acSDingqiang Lin 	int ret;
66ba0501acSDingqiang Lin 	union SFCCMD_DATA sfcmd;
67ba0501acSDingqiang Lin 
68ba0501acSDingqiang Lin 	sfcmd.d32 = 0;
69ba0501acSDingqiang Lin 	sfcmd.b.cmd = CMD_WRITE_EN;
70ba0501acSDingqiang Lin 	ret = sfc_request(sfcmd.d32, 0, 0, NULL);
71ba0501acSDingqiang Lin 	return ret;
72ba0501acSDingqiang Lin }
73ba0501acSDingqiang Lin 
74ba0501acSDingqiang Lin static int sfc_nand_rw_preset(void)
75ba0501acSDingqiang Lin {
76ba0501acSDingqiang Lin 	int ret;
77ba0501acSDingqiang Lin 	union SFCCTRL_DATA sfctrl;
78ba0501acSDingqiang Lin 	union SFCCMD_DATA sfcmd;
79ba0501acSDingqiang Lin 	u8 status = 0xFF;
80ba0501acSDingqiang Lin 
81ba0501acSDingqiang Lin 	sfcmd.d32 = 0;
82ba0501acSDingqiang Lin 	sfcmd.b.cmd = 0;
83ba0501acSDingqiang Lin 	sfcmd.b.datasize = 1;
84ba0501acSDingqiang Lin 	sfcmd.b.rw = SFC_WRITE;
85ba0501acSDingqiang Lin 
86ba0501acSDingqiang Lin 	sfctrl.b.datalines = 2;
87ba0501acSDingqiang Lin 	ret = sfc_request(sfcmd.d32, sfctrl.d32, 0, &status);
88ba0501acSDingqiang Lin 	return ret;
89ba0501acSDingqiang Lin }
90ba0501acSDingqiang Lin 
91ba0501acSDingqiang Lin static int sfc_nand_read_feature(u8 addr, u8 *data)
92ba0501acSDingqiang Lin {
93ba0501acSDingqiang Lin 	int ret;
94ba0501acSDingqiang Lin 	union SFCCMD_DATA sfcmd;
95ba0501acSDingqiang Lin 
96ba0501acSDingqiang Lin 	sfcmd.d32 = 0;
97ba0501acSDingqiang Lin 	sfcmd.b.cmd = 0x0F;
98ba0501acSDingqiang Lin 	sfcmd.b.datasize = 1;
99ba0501acSDingqiang Lin 	sfcmd.b.addrbits = SFC_ADDR_XBITS;
100ba0501acSDingqiang Lin 	*data = 0;
101ba0501acSDingqiang Lin 
102ba0501acSDingqiang Lin 	ret = sfc_request(sfcmd.d32, 0x8 << 16, addr, data);
103ba0501acSDingqiang Lin 	if (ret != SFC_OK)
104ba0501acSDingqiang Lin 		return ret;
105ba0501acSDingqiang Lin 	return SFC_OK;
106ba0501acSDingqiang Lin }
107ba0501acSDingqiang Lin 
108ba0501acSDingqiang Lin static int sfc_nand_write_feature(u32 addr, u8 status)
109ba0501acSDingqiang Lin {
110ba0501acSDingqiang Lin 	int ret;
111ba0501acSDingqiang Lin 	union SFCCMD_DATA sfcmd;
112ba0501acSDingqiang Lin 
113ba0501acSDingqiang Lin 	sfc_nand_write_en();
114ba0501acSDingqiang Lin 
115ba0501acSDingqiang Lin 	sfcmd.d32 = 0;
116ba0501acSDingqiang Lin 	sfcmd.b.cmd = 0x1F;
117ba0501acSDingqiang Lin 	sfcmd.b.datasize = 1;
118ba0501acSDingqiang Lin 	sfcmd.b.addrbits = SFC_ADDR_XBITS;
119ba0501acSDingqiang Lin 	sfcmd.b.rw = SFC_WRITE;
120ba0501acSDingqiang Lin 
121ba0501acSDingqiang Lin 	ret = sfc_request(sfcmd.d32, 0x8 << 16, addr, &status);
122ba0501acSDingqiang Lin 	if (ret != SFC_OK)
123ba0501acSDingqiang Lin 		return ret;
124ba0501acSDingqiang Lin 	return ret;
125ba0501acSDingqiang Lin }
126ba0501acSDingqiang Lin 
127ba0501acSDingqiang Lin static int sfc_nand_wait_busy(u8 *data, int timeout)
128ba0501acSDingqiang Lin {
129ba0501acSDingqiang Lin 	int ret;
130ba0501acSDingqiang Lin 	int i;
131ba0501acSDingqiang Lin 	u8 status;
132ba0501acSDingqiang Lin 
133ba0501acSDingqiang Lin 	*data = 0;
134ba0501acSDingqiang Lin 	for (i = 0; i < timeout; i++) {
135ba0501acSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
136ba0501acSDingqiang Lin 		if (ret != SFC_OK)
137ba0501acSDingqiang Lin 			return ret;
138ba0501acSDingqiang Lin 		*data = status;
139ba0501acSDingqiang Lin 		if (!(status & (1 << 0)))
140ba0501acSDingqiang Lin 			return SFC_OK;
141ba0501acSDingqiang Lin 		sfc_delay(1);
142ba0501acSDingqiang Lin 	}
143ba0501acSDingqiang Lin 	return -1;
144ba0501acSDingqiang Lin }
145ba0501acSDingqiang Lin 
146*6281205aSDingqiang Lin /*
147*6281205aSDingqiang Lin  * ecc default:
148*6281205aSDingqiang Lin  * 0, No bit errors were detected
149*6281205aSDingqiang Lin  * 1, Bit errors were detected and corrected.
150*6281205aSDingqiang Lin  * 2, Multiple bit errors were detected and not corrected.
151*6281205aSDingqiang Lin  * 3, Bits errors were detected and corrected, bit error count
152*6281205aSDingqiang Lin  *	exceed the bit flip detection threshold
153*6281205aSDingqiang Lin  */
154*6281205aSDingqiang Lin static u32 sfc_nand_ecc_status(void)
155*6281205aSDingqiang Lin {
156*6281205aSDingqiang Lin 	int ret;
157*6281205aSDingqiang Lin 	u32 i;
158*6281205aSDingqiang Lin 	u8 ecc;
159*6281205aSDingqiang Lin 	u8 status;
160*6281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
161*6281205aSDingqiang Lin 
162*6281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
163*6281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
164*6281205aSDingqiang Lin 		if (ret != SFC_OK)
165*6281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
166*6281205aSDingqiang Lin 		if (!(status & (1 << 0)))
167*6281205aSDingqiang Lin 			break;
168*6281205aSDingqiang Lin 		sfc_delay(1);
169*6281205aSDingqiang Lin 	}
170*6281205aSDingqiang Lin 
171*6281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
172*6281205aSDingqiang Lin 
173*6281205aSDingqiang Lin 	if (ecc <= 1)
174*6281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
175*6281205aSDingqiang Lin 	else if (ecc == 2)
176*6281205aSDingqiang Lin 		ret = SFC_NAND_ECC_ERROR;
177*6281205aSDingqiang Lin 	else
178*6281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
179*6281205aSDingqiang Lin 
180*6281205aSDingqiang Lin 	return ret;
181*6281205aSDingqiang Lin }
182*6281205aSDingqiang Lin 
183*6281205aSDingqiang Lin /*
184*6281205aSDingqiang Lin  * ecc spectial type1:
185*6281205aSDingqiang Lin  * 0x00, No bit errors were detected;
186*6281205aSDingqiang Lin  * 0x01, Bits errors were detected and corrected, bit error count
187*6281205aSDingqiang Lin  *	may reach the bit flip detection threshold;
188*6281205aSDingqiang Lin  * 0x10, Multiple bit errors were detected and not corrected;
189*6281205aSDingqiang Lin  * 0x11, Reserved.
190*6281205aSDingqiang Lin  */
191*6281205aSDingqiang Lin u32 sfc_nand_ecc_status_sp1(void)
192*6281205aSDingqiang Lin {
193*6281205aSDingqiang Lin 	int ret;
194*6281205aSDingqiang Lin 	u32 i;
195*6281205aSDingqiang Lin 	u8 ecc;
196*6281205aSDingqiang Lin 	u8 status;
197*6281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
198*6281205aSDingqiang Lin 
199*6281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
200*6281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
201*6281205aSDingqiang Lin 		if (ret != SFC_OK)
202*6281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
203*6281205aSDingqiang Lin 		if (!(status & (1 << 0)))
204*6281205aSDingqiang Lin 			break;
205*6281205aSDingqiang Lin 		sfc_delay(1);
206*6281205aSDingqiang Lin 	}
207*6281205aSDingqiang Lin 
208*6281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
209*6281205aSDingqiang Lin 
210*6281205aSDingqiang Lin 	if (ecc == 0)
211*6281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
212*6281205aSDingqiang Lin 	else if (ecc == 1)
213*6281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
214*6281205aSDingqiang Lin 	else
215*6281205aSDingqiang Lin 		ret = SFC_NAND_ECC_ERROR;
216*6281205aSDingqiang Lin 
217*6281205aSDingqiang Lin 	return ret;
218*6281205aSDingqiang Lin }
219*6281205aSDingqiang Lin 
220*6281205aSDingqiang Lin /*
221*6281205aSDingqiang Lin  * ecc spectial type3:
222*6281205aSDingqiang Lin  * [0x0000, 0x0011], No bit errors were detected;
223*6281205aSDingqiang Lin  * [0x0100, 0x0111], Bit errors were detected and corrected. Not
224*6281205aSDingqiang Lin  *	reach Flipping Bits;
225*6281205aSDingqiang Lin  * [0x1000, 0x1011], Multiple bit errors were detected and
226*6281205aSDingqiang Lin  *	not corrected.
227*6281205aSDingqiang Lin  * [0x1100, 0x1111], Bit error count equals the bit flip
228*6281205aSDingqiang Lin  *	detectionthreshold
229*6281205aSDingqiang Lin  */
230*6281205aSDingqiang Lin u32 sfc_nand_ecc_status_sp3(void)
231*6281205aSDingqiang Lin {
232*6281205aSDingqiang Lin 	int ret;
233*6281205aSDingqiang Lin 	u32 i;
234*6281205aSDingqiang Lin 	u8 ecc;
235*6281205aSDingqiang Lin 	u8 status, status1;
236*6281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
237*6281205aSDingqiang Lin 
238*6281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
239*6281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
240*6281205aSDingqiang Lin 		if (ret != SFC_OK)
241*6281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
242*6281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xF0, &status1);
243*6281205aSDingqiang Lin 		if (ret != SFC_OK)
244*6281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
245*6281205aSDingqiang Lin 		if (!(status & (1 << 0)))
246*6281205aSDingqiang Lin 			break;
247*6281205aSDingqiang Lin 		sfc_delay(1);
248*6281205aSDingqiang Lin 	}
249*6281205aSDingqiang Lin 
250*6281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
251*6281205aSDingqiang Lin 	ecc = (ecc << 2) | ((status1 >> 4) & 0x03);
252*6281205aSDingqiang Lin 	if (ecc < 7)
253*6281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
254*6281205aSDingqiang Lin 	else if (ecc == 7 || ecc >= 12)
255*6281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
256*6281205aSDingqiang Lin 	else
257*6281205aSDingqiang Lin 		ret = SFC_NAND_ECC_ERROR;
258*6281205aSDingqiang Lin 
259*6281205aSDingqiang Lin 	return ret;
260*6281205aSDingqiang Lin }
261*6281205aSDingqiang Lin 
262ba0501acSDingqiang Lin static u32 sfc_nand_erase_block(u8 cs, u32 addr)
263ba0501acSDingqiang Lin {
264ba0501acSDingqiang Lin 	int ret;
265ba0501acSDingqiang Lin 	union SFCCMD_DATA sfcmd;
266ba0501acSDingqiang Lin 	u8 status;
267ba0501acSDingqiang Lin 
268ba0501acSDingqiang Lin 	sfcmd.d32 = 0;
269ba0501acSDingqiang Lin 	sfcmd.b.cmd = p_nand_info->block_erase_cmd;
270ba0501acSDingqiang Lin 	sfcmd.b.addrbits = SFC_ADDR_24BITS;
271ba0501acSDingqiang Lin 	sfc_nand_write_en();
272ba0501acSDingqiang Lin 	ret = sfc_request(sfcmd.d32, 0, addr, NULL);
273ba0501acSDingqiang Lin 	if (ret != SFC_OK)
274ba0501acSDingqiang Lin 		return ret;
275ba0501acSDingqiang Lin 	ret = sfc_nand_wait_busy(&status, 1000 * 1000);
276ba0501acSDingqiang Lin 	if (status & (1 << 2))
277ba0501acSDingqiang Lin 		return SFC_NAND_PROG_ERASE_ERROR;
278ba0501acSDingqiang Lin 	return ret;
279ba0501acSDingqiang Lin }
280ba0501acSDingqiang Lin 
281ba0501acSDingqiang Lin static u32 sfc_nand_prog_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare)
282ba0501acSDingqiang Lin {
283ba0501acSDingqiang Lin 	int ret;
284ba0501acSDingqiang Lin 	union SFCCMD_DATA sfcmd;
285ba0501acSDingqiang Lin 	union SFCCTRL_DATA sfctrl;
286ba0501acSDingqiang Lin 	u8 status;
287ba0501acSDingqiang Lin 	u32 data_sz = 2048;
288ba0501acSDingqiang Lin 	u32 spare_offs_1 = p_nand_info->spare_offs_1;
289ba0501acSDingqiang Lin 	u32 spare_offs_2 = p_nand_info->spare_offs_2;
290ba0501acSDingqiang Lin 
291ba0501acSDingqiang Lin 	memcpy(gp_page_buf, p_data, data_sz);
292ba0501acSDingqiang Lin 	gp_page_buf[(data_sz + spare_offs_1) / 4] = p_spare[0];
293ba0501acSDingqiang Lin 	gp_page_buf[(data_sz + spare_offs_2) / 4] = p_spare[1];
294ba0501acSDingqiang Lin 
295ba0501acSDingqiang Lin 	sfc_nand_write_en();
296ba0501acSDingqiang Lin 	if (sfc_nand_dev.prog_lines == DATA_LINES_X4 &&
297ba0501acSDingqiang Lin 	    p_nand_info->QE_address == 0xFF &&
298ba0501acSDingqiang Lin 	    sfc_get_version() != SFC_VER_3)
299ba0501acSDingqiang Lin 		sfc_nand_rw_preset();
300ba0501acSDingqiang Lin 
301ba0501acSDingqiang Lin 	sfcmd.d32 = 0;
302ba0501acSDingqiang Lin 	sfcmd.b.cmd = sfc_nand_dev.page_prog_cmd;
303ba0501acSDingqiang Lin 	sfcmd.b.addrbits = SFC_ADDR_XBITS;
304ba0501acSDingqiang Lin 	sfcmd.b.datasize = SFC_NAND_PAGE_MAX_SIZE;
305ba0501acSDingqiang Lin 	sfcmd.b.rw = SFC_WRITE;
306ba0501acSDingqiang Lin 
307ba0501acSDingqiang Lin 	sfctrl.d32 = 0;
308ba0501acSDingqiang Lin 	sfctrl.b.datalines = sfc_nand_dev.prog_lines;
309ba0501acSDingqiang Lin 	sfctrl.b.addrbits = 16;
310ba0501acSDingqiang Lin 	sfc_request(sfcmd.d32, sfctrl.d32, 0, gp_page_buf);
311ba0501acSDingqiang Lin 
312ba0501acSDingqiang Lin 	sfcmd.d32 = 0;
313ba0501acSDingqiang Lin 	sfcmd.b.cmd = p_nand_info->page_prog_cmd;
314ba0501acSDingqiang Lin 	sfcmd.b.addrbits = SFC_ADDR_24BITS;
315ba0501acSDingqiang Lin 	sfcmd.b.datasize = 0;
316ba0501acSDingqiang Lin 	sfcmd.b.rw = SFC_WRITE;
317ba0501acSDingqiang Lin 	ret = sfc_request(sfcmd.d32, 0, addr, p_data);
318ba0501acSDingqiang Lin 	if (ret != SFC_OK)
319ba0501acSDingqiang Lin 		return ret;
320ba0501acSDingqiang Lin 	ret = sfc_nand_wait_busy(&status, 1000 * 1000);
321ba0501acSDingqiang Lin 	if (status & (1 << 3))
322ba0501acSDingqiang Lin 		return SFC_NAND_PROG_ERASE_ERROR;
323ba0501acSDingqiang Lin 	return ret;
324ba0501acSDingqiang Lin }
325ba0501acSDingqiang Lin 
326ba0501acSDingqiang Lin static u32 sfc_nand_read_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare)
327ba0501acSDingqiang Lin {
328ba0501acSDingqiang Lin 	int ret;
329ba0501acSDingqiang Lin 	union SFCCMD_DATA sfcmd;
330ba0501acSDingqiang Lin 	union SFCCTRL_DATA sfctrl;
331*6281205aSDingqiang Lin 	u32 ecc_result;
332ba0501acSDingqiang Lin 	u32 data_sz = 2048;
333ba0501acSDingqiang Lin 	u32 spare_offs_1 = p_nand_info->spare_offs_1;
334ba0501acSDingqiang Lin 	u32 spare_offs_2 = p_nand_info->spare_offs_2;
335ba0501acSDingqiang Lin 
336ba0501acSDingqiang Lin 	sfcmd.d32 = 0;
337ba0501acSDingqiang Lin 	sfcmd.b.cmd = p_nand_info->page_read_cmd;
338ba0501acSDingqiang Lin 	sfcmd.b.datasize = 0;
339ba0501acSDingqiang Lin 	sfcmd.b.addrbits = SFC_ADDR_24BITS;
340ba0501acSDingqiang Lin 	sfc_request(sfcmd.d32, 0, addr, p_data);
341ba0501acSDingqiang Lin 
342*6281205aSDingqiang Lin 	if (p_nand_info->ecc_status)
343*6281205aSDingqiang Lin 		ecc_result = p_nand_info->ecc_status();
344*6281205aSDingqiang Lin 	else
345*6281205aSDingqiang Lin 		ecc_result = sfc_nand_ecc_status();
346*6281205aSDingqiang Lin 
347ba0501acSDingqiang Lin 	if (sfc_nand_dev.read_lines == DATA_LINES_X4 &&
348ba0501acSDingqiang Lin 	    p_nand_info->QE_address == 0xFF &&
349ba0501acSDingqiang Lin 	    sfc_get_version() != SFC_VER_3)
350ba0501acSDingqiang Lin 		sfc_nand_rw_preset();
351ba0501acSDingqiang Lin 
352ba0501acSDingqiang Lin 	sfcmd.d32 = 0;
353ba0501acSDingqiang Lin 	sfcmd.b.cmd = sfc_nand_dev.page_read_cmd;
354ba0501acSDingqiang Lin 	sfcmd.b.datasize = SFC_NAND_PAGE_MAX_SIZE;
355ba0501acSDingqiang Lin 	sfcmd.b.addrbits = SFC_ADDR_24BITS;
356ba0501acSDingqiang Lin 	sfctrl.d32 = 0;
357ba0501acSDingqiang Lin 	sfctrl.b.datalines = sfc_nand_dev.read_lines;
358ba0501acSDingqiang Lin 
359ba0501acSDingqiang Lin 	memset(gp_page_buf, 0, SFC_NAND_PAGE_MAX_SIZE);
360ba0501acSDingqiang Lin 	ret = sfc_request(sfcmd.d32, sfctrl.d32, 0, gp_page_buf);
361ba0501acSDingqiang Lin 
362ba0501acSDingqiang Lin 	memcpy(p_data, gp_page_buf, data_sz);
363ba0501acSDingqiang Lin 	p_spare[0] = gp_page_buf[(data_sz + spare_offs_1) / 4];
364ba0501acSDingqiang Lin 	p_spare[1] = gp_page_buf[(data_sz + spare_offs_2) / 4];
365ba0501acSDingqiang Lin 	if (ret != SFC_OK)
366ba0501acSDingqiang Lin 		return SFC_NAND_ECC_ERROR;
367ba0501acSDingqiang Lin 
368*6281205aSDingqiang Lin 	if (ecc_result != SFC_NAND_ECC_OK) {
369*6281205aSDingqiang Lin 		PRINT_SFC_E("%s[0x%x], ret=0x%x\n", __func__, addr, ecc_result);
370ba0501acSDingqiang Lin 		if (p_data)
371ba0501acSDingqiang Lin 			PRINT_SFC_HEX("data:", p_data, 4, 8);
372ba0501acSDingqiang Lin 		if (p_spare)
373ba0501acSDingqiang Lin 			PRINT_SFC_HEX("spare:", p_spare, 4, 2);
374ba0501acSDingqiang Lin 	}
375*6281205aSDingqiang Lin 	return ecc_result;
376ba0501acSDingqiang Lin }
377ba0501acSDingqiang Lin 
378ba0501acSDingqiang Lin static int sfc_nand_read_id_raw(u8 *data)
379ba0501acSDingqiang Lin {
380ba0501acSDingqiang Lin 	int ret;
381ba0501acSDingqiang Lin 	union SFCCMD_DATA sfcmd;
382ba0501acSDingqiang Lin 
383ba0501acSDingqiang Lin 	sfcmd.d32 = 0;
384ba0501acSDingqiang Lin 	sfcmd.b.cmd = CMD_READ_JEDECID;
385ba0501acSDingqiang Lin 	sfcmd.b.datasize = 3;
386ba0501acSDingqiang Lin 	sfcmd.b.addrbits = SFC_ADDR_XBITS;
387ba0501acSDingqiang Lin 
388ba0501acSDingqiang Lin 	ret = sfc_request(sfcmd.d32, 0x8 << 16, 0, data);
389ba0501acSDingqiang Lin 
390ba0501acSDingqiang Lin 	return ret;
391ba0501acSDingqiang Lin }
392ba0501acSDingqiang Lin 
393ba0501acSDingqiang Lin /*
394ba0501acSDingqiang Lin  * Read the 1st page's 1st byte of a phy_blk
395ba0501acSDingqiang Lin  * If not FF, it's bad blk
396ba0501acSDingqiang Lin  */
397ba0501acSDingqiang Lin static int sfc_nand_get_bad_block_list(u16 *table, u32 die)
398ba0501acSDingqiang Lin {
399ba0501acSDingqiang Lin 	u16 blk;
400ba0501acSDingqiang Lin 	u32 bad_cnt, page;
401ba0501acSDingqiang Lin 	u32 blk_per_die;
402ba0501acSDingqiang Lin 	u32 *pread;
403ba0501acSDingqiang Lin 	u32 *pspare_read;
404ba0501acSDingqiang Lin 
405ba0501acSDingqiang Lin 	PRINT_SFC_E("%s\n", __func__);
406ba0501acSDingqiang Lin 	pread = ftl_malloc(2048);
407ba0501acSDingqiang Lin 	pspare_read = ftl_malloc(8);
408ba0501acSDingqiang Lin 	bad_cnt = 0;
409ba0501acSDingqiang Lin 	blk_per_die = p_nand_info->plane_per_die *
410ba0501acSDingqiang Lin 			p_nand_info->blk_per_plane;
411ba0501acSDingqiang Lin 	for (blk = 0; blk < blk_per_die; blk++) {
412ba0501acSDingqiang Lin 		page = (blk + blk_per_die * die) *
413ba0501acSDingqiang Lin 			p_nand_info->page_per_blk;
414ba0501acSDingqiang Lin 		sfc_nand_read_page(0, page, pread, pspare_read);
415ba0501acSDingqiang Lin 
416ba0501acSDingqiang Lin 		if (pread[0] != 0xFFFFFFFF ||
417ba0501acSDingqiang Lin 		    pspare_read[0] != 0xFFFFFFFF) {
418ba0501acSDingqiang Lin 			table[bad_cnt++] = blk;
419ba0501acSDingqiang Lin 			PRINT_SFC_E("die[%d], bad_blk[%d]\n", die, blk);
420ba0501acSDingqiang Lin 		}
421ba0501acSDingqiang Lin 	}
422ba0501acSDingqiang Lin 	ftl_free(pread);
423ba0501acSDingqiang Lin 	ftl_free(pspare_read);
424ba0501acSDingqiang Lin 	return (int)bad_cnt;
425ba0501acSDingqiang Lin }
426ba0501acSDingqiang Lin 
427ba0501acSDingqiang Lin #if SFC_NAND_STRESS_TEST_EN
428ba0501acSDingqiang Lin 
429ba0501acSDingqiang Lin #define SFC_NAND_PAGE_SIZE	2048
430ba0501acSDingqiang Lin #define SFC_NAND_SPARE_SIZE	8
431ba0501acSDingqiang Lin 
432ba0501acSDingqiang Lin static u16 bad_blk_list[1024];
433ba0501acSDingqiang Lin static u32 pwrite[SFC_NAND_PAGE_SIZE / 4];
434ba0501acSDingqiang Lin static u32 pread[SFC_NAND_PAGE_SIZE / 4];
435ba0501acSDingqiang Lin static u32 pspare_write[SFC_NAND_SPARE_SIZE / 4];
436ba0501acSDingqiang Lin static u32 pspare_read[SFC_NAND_SPARE_SIZE / 4];
437ba0501acSDingqiang Lin static u32 bad_blk_num;
438ba0501acSDingqiang Lin static u32 bad_page_num;
439ba0501acSDingqiang Lin 
440ba0501acSDingqiang Lin static void sfc_nand_test(void)
441ba0501acSDingqiang Lin {
442ba0501acSDingqiang Lin 	u32 i, blk, page, bad_cnt, page_addr;
443ba0501acSDingqiang Lin 	int ret;
444ba0501acSDingqiang Lin 	u32 pages_num = 64;
445ba0501acSDingqiang Lin 	u32 blk_addr = 64;
446ba0501acSDingqiang Lin 	u32 is_bad_blk = 0;
447ba0501acSDingqiang Lin 
448ba0501acSDingqiang Lin 	PRINT_SFC_E("%s\n", __func__);
449ba0501acSDingqiang Lin 
450ba0501acSDingqiang Lin 	bad_blk_num = 0;
451ba0501acSDingqiang Lin 	bad_page_num = 0;
452ba0501acSDingqiang Lin 	bad_cnt	= sfc_nand_get_bad_block_list(bad_blk_list, 0);
453ba0501acSDingqiang Lin 
454ba0501acSDingqiang Lin 	for (blk = 0; blk < 1024; blk++) {
455ba0501acSDingqiang Lin 		for (i = 0; i < bad_cnt; i++) {
456ba0501acSDingqiang Lin 			if (bad_blk_list[i] == blk)
457ba0501acSDingqiang Lin 				break;
458ba0501acSDingqiang Lin 		}
459ba0501acSDingqiang Lin 		if (i < bad_cnt)
460ba0501acSDingqiang Lin 			continue;
461ba0501acSDingqiang Lin 		is_bad_blk = 0;
462ba0501acSDingqiang Lin 		PRINT_SFC_E("Flash prog block: %x\n", blk);
463ba0501acSDingqiang Lin 		sfc_nand_erase_block(0, blk * blk_addr);
464ba0501acSDingqiang Lin 		for (page = 0; page < pages_num; page++) {
465ba0501acSDingqiang Lin 			page_addr = blk * blk_addr + page;
466ba0501acSDingqiang Lin 			for (i = 0; i < 512; i++)
467ba0501acSDingqiang Lin 				pwrite[i] = (page_addr << 16) + i;
468ba0501acSDingqiang Lin 			pspare_write[0] = pwrite[0] + 0x5AF0;
469ba0501acSDingqiang Lin 			pspare_write[1] = pspare_write[0] + 1;
470ba0501acSDingqiang Lin 			sfc_nand_prog_page(0, page_addr, pwrite, pspare_write);
471ba0501acSDingqiang Lin 			memset(pread, 0, 2048);
472ba0501acSDingqiang Lin 			memset(pspare_read, 0, 8);
473ba0501acSDingqiang Lin 			ret = sfc_nand_read_page(0, page_addr, pread,
474ba0501acSDingqiang Lin 						 pspare_read);
475ba0501acSDingqiang Lin 			if (ret != SFC_NAND_ECC_OK)
476ba0501acSDingqiang Lin 				is_bad_blk = 1;
477ba0501acSDingqiang Lin 			for (i = 0; i < 512; i++) {
478ba0501acSDingqiang Lin 				if (pwrite[i] != pread[i]) {
479ba0501acSDingqiang Lin 					is_bad_blk = 1;
480ba0501acSDingqiang Lin 					break;
481ba0501acSDingqiang Lin 				}
482ba0501acSDingqiang Lin 			}
483ba0501acSDingqiang Lin 			for (i = 0; i < 2; i++) {
484ba0501acSDingqiang Lin 				if (pspare_write[i] != pspare_read[i]) {
485ba0501acSDingqiang Lin 					is_bad_blk = 1;
486ba0501acSDingqiang Lin 					break;
487ba0501acSDingqiang Lin 				}
488ba0501acSDingqiang Lin 			}
489ba0501acSDingqiang Lin 			if (is_bad_blk) {
490ba0501acSDingqiang Lin 				bad_page_num++;
491ba0501acSDingqiang Lin 				PRINT_SFC_E("ERR:page%x, ret=%x\n",
492ba0501acSDingqiang Lin 					    page_addr, ret);
493ba0501acSDingqiang Lin 				PRINT_SFC_HEX("data:", pread, 4, 8);
494ba0501acSDingqiang Lin 				PRINT_SFC_HEX("spare:", pspare_read, 4, 2);
495ba0501acSDingqiang Lin 			}
496ba0501acSDingqiang Lin 		}
497ba0501acSDingqiang Lin 		sfc_nand_erase_block(0, blk * blk_addr);
498ba0501acSDingqiang Lin 		if (is_bad_blk)
499ba0501acSDingqiang Lin 			bad_blk_num++;
500ba0501acSDingqiang Lin 	}
501ba0501acSDingqiang Lin 	PRINT_SFC_E("bad_blk_num = %d, bad_page_num = %d\n",
502ba0501acSDingqiang Lin 		    bad_blk_num, bad_page_num);
503ba0501acSDingqiang Lin 
504ba0501acSDingqiang Lin 	PRINT_SFC_E("Flash Test Finish!!!\n");
505ba0501acSDingqiang Lin 	while (1)
506ba0501acSDingqiang Lin 		;
507ba0501acSDingqiang Lin }
508ba0501acSDingqiang Lin #endif
509ba0501acSDingqiang Lin 
510ba0501acSDingqiang Lin static void ftl_flash_init(void)
511ba0501acSDingqiang Lin {
512ba0501acSDingqiang Lin 	/* para init */
513ba0501acSDingqiang Lin 	g_nand_phy_info.nand_type	= 1;
514ba0501acSDingqiang Lin 	g_nand_phy_info.die_num		= 1;
515ba0501acSDingqiang Lin 	g_nand_phy_info.plane_per_die	= p_nand_info->plane_per_die;
516ba0501acSDingqiang Lin 	g_nand_phy_info.blk_per_plane	= p_nand_info->blk_per_plane;
517ba0501acSDingqiang Lin 	g_nand_phy_info.page_per_blk	= p_nand_info->page_per_blk;
518ba0501acSDingqiang Lin 	g_nand_phy_info.page_per_slc_blk = p_nand_info->page_per_blk;
519ba0501acSDingqiang Lin 	g_nand_phy_info.byte_per_sec	= 512;
520ba0501acSDingqiang Lin 	g_nand_phy_info.sec_per_page	= p_nand_info->sec_per_page;
521ba0501acSDingqiang Lin 	g_nand_phy_info.sec_per_blk	= p_nand_info->sec_per_page *
522ba0501acSDingqiang Lin 					  p_nand_info->page_per_blk;
523ba0501acSDingqiang Lin 	g_nand_phy_info.reserved_blk	= 8;
524ba0501acSDingqiang Lin 	g_nand_phy_info.blk_per_die	= p_nand_info->plane_per_die *
525ba0501acSDingqiang Lin 					  p_nand_info->blk_per_plane;
526ba0501acSDingqiang Lin 	g_nand_phy_info.ecc_bits	= p_nand_info->max_ecc_bits;
527ba0501acSDingqiang Lin 
528ba0501acSDingqiang Lin 	/* driver register */
529ba0501acSDingqiang Lin 	g_nand_ops.get_bad_blk_list	= sfc_nand_get_bad_block_list;
530ba0501acSDingqiang Lin 	g_nand_ops.erase_blk		= sfc_nand_erase_block;
531ba0501acSDingqiang Lin 	g_nand_ops.prog_page		= sfc_nand_prog_page;
532ba0501acSDingqiang Lin 	g_nand_ops.read_page		= sfc_nand_read_page;
533ba0501acSDingqiang Lin }
534ba0501acSDingqiang Lin 
535ba0501acSDingqiang Lin static int spi_nand_enable_QE(void)
536ba0501acSDingqiang Lin {
537ba0501acSDingqiang Lin 	int ret = SFC_OK;
538ba0501acSDingqiang Lin 	u8 status;
539ba0501acSDingqiang Lin 	int bit_offset = p_nand_info->QE_bits;
540ba0501acSDingqiang Lin 
541ba0501acSDingqiang Lin 	if (bit_offset == 0xFF)
542ba0501acSDingqiang Lin 		return SFC_OK;
543ba0501acSDingqiang Lin 
544ba0501acSDingqiang Lin 	ret = sfc_nand_read_feature(p_nand_info->QE_address, &status);
545ba0501acSDingqiang Lin 	if (ret != SFC_OK)
546ba0501acSDingqiang Lin 		return ret;
547ba0501acSDingqiang Lin 
548ba0501acSDingqiang Lin 	if (status & (1 << bit_offset))   /* is QE bit set */
549ba0501acSDingqiang Lin 		return SFC_OK;
550ba0501acSDingqiang Lin 
551ba0501acSDingqiang Lin 	status |= (1 << bit_offset);
552ba0501acSDingqiang Lin 		return sfc_nand_write_feature(p_nand_info->QE_address, status);
553ba0501acSDingqiang Lin 
554ba0501acSDingqiang Lin 	return ret;
555ba0501acSDingqiang Lin }
556ba0501acSDingqiang Lin 
557ba0501acSDingqiang Lin u32 sfc_nand_init(void)
558ba0501acSDingqiang Lin {
559ba0501acSDingqiang Lin 	PRINT_SFC_I("...%s enter...\n", __func__);
560ba0501acSDingqiang Lin 
561ba0501acSDingqiang Lin 	sfc_nand_read_id_raw(id_byte);
562ba0501acSDingqiang Lin 	PRINT_SFC_E("sfc_nand id: %x %x %x\n",
563ba0501acSDingqiang Lin 		    id_byte[0], id_byte[1], id_byte[2]);
564ba0501acSDingqiang Lin 	if (id_byte[0] == 0xFF || id_byte[0] == 0x00)
565ba0501acSDingqiang Lin 		return FTL_NO_FLASH;
566ba0501acSDingqiang Lin 
567ba0501acSDingqiang Lin 	p_nand_info = spi_nand_get_info(id_byte);
568ba0501acSDingqiang Lin 	if (!p_nand_info)
569ba0501acSDingqiang Lin 		return FTL_UNSUPPORTED_FLASH;
570ba0501acSDingqiang Lin 
571ba0501acSDingqiang Lin 	sfc_nand_dev.manufacturer = id_byte[0];
572ba0501acSDingqiang Lin 	sfc_nand_dev.mem_type = id_byte[1];
573ba0501acSDingqiang Lin 
574ba0501acSDingqiang Lin 	/* disable block lock */
575ba0501acSDingqiang Lin 	sfc_nand_write_feature(0xA0, 0);
576ba0501acSDingqiang Lin 	sfc_nand_dev.read_lines = DATA_LINES_X1;
577ba0501acSDingqiang Lin 	sfc_nand_dev.prog_lines = DATA_LINES_X1;
578ba0501acSDingqiang Lin 	sfc_nand_dev.page_read_cmd = p_nand_info->read_cache_cmd_1;
579ba0501acSDingqiang Lin 	sfc_nand_dev.page_prog_cmd = p_nand_info->prog_cache_cmd_1;
580ba0501acSDingqiang Lin 	if (p_nand_info->feature & FEA_4BIT_READ) {
581ba0501acSDingqiang Lin 		if (spi_nand_enable_QE() == SFC_OK) {
582ba0501acSDingqiang Lin 			sfc_nand_dev.read_lines = DATA_LINES_X4;
583ba0501acSDingqiang Lin 			sfc_nand_dev.page_read_cmd =
584ba0501acSDingqiang Lin 				p_nand_info->read_cache_cmd_4;
585ba0501acSDingqiang Lin 		}
586ba0501acSDingqiang Lin 	}
587ba0501acSDingqiang Lin 
588ba0501acSDingqiang Lin 	if (p_nand_info->feature & FEA_4BIT_PROG &&
589ba0501acSDingqiang Lin 	    sfc_nand_dev.read_lines == DATA_LINES_X4) {
590ba0501acSDingqiang Lin 		sfc_nand_dev.prog_lines = DATA_LINES_X4;
591ba0501acSDingqiang Lin 		sfc_nand_dev.page_prog_cmd = p_nand_info->prog_cache_cmd_4;
592ba0501acSDingqiang Lin 	}
593ba0501acSDingqiang Lin 
594ba0501acSDingqiang Lin 	if (1) {
595ba0501acSDingqiang Lin 		u8 status;
596ba0501acSDingqiang Lin 
597ba0501acSDingqiang Lin 		sfc_nand_read_feature(0xA0, &status);
598ba0501acSDingqiang Lin 		PRINT_SFC_I("sfc_nand A0 = 0x%x\n", status);
599ba0501acSDingqiang Lin 		sfc_nand_read_feature(0xB0, &status);
600ba0501acSDingqiang Lin 		PRINT_SFC_I("sfc_nand B0 = 0x%x\n", status);
601ba0501acSDingqiang Lin 		sfc_nand_read_feature(0xC0, &status);
602ba0501acSDingqiang Lin 		PRINT_SFC_I("sfc_nand C0 = 0x%x\n", status);
603ba0501acSDingqiang Lin 		PRINT_SFC_I("read_lines = %x\n", sfc_nand_dev.read_lines);
604ba0501acSDingqiang Lin 		PRINT_SFC_I("prog_lines = %x\n", sfc_nand_dev.prog_lines);
605ba0501acSDingqiang Lin 		PRINT_SFC_I("page_read_cmd = %x\n", sfc_nand_dev.page_read_cmd);
606ba0501acSDingqiang Lin 		PRINT_SFC_I("page_prog_cmd = %x\n", sfc_nand_dev.page_prog_cmd);
607ba0501acSDingqiang Lin 	}
608ba0501acSDingqiang Lin 	ftl_flash_init();
609ba0501acSDingqiang Lin 
610ba0501acSDingqiang Lin 	#if SFC_NAND_STRESS_TEST_EN
611ba0501acSDingqiang Lin 	sfc_nand_test();
612ba0501acSDingqiang Lin 	#endif
613ba0501acSDingqiang Lin 
614ba0501acSDingqiang Lin 	return SFC_OK;
615ba0501acSDingqiang Lin }
616ba0501acSDingqiang Lin 
617ba0501acSDingqiang Lin int sfc_nand_read_id(u8 *data)
618ba0501acSDingqiang Lin {
619ba0501acSDingqiang Lin 	memcpy(data, id_byte, 3);
620ba0501acSDingqiang Lin 	return 0;
621ba0501acSDingqiang Lin }
622