xref: /rk3399_rockchip-uboot/drivers/rkflash/sfc_nand.c (revision 415cf08001eb16cbc669512e4e2111dd6c1cb4f0)
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_com.h"
12cd67f373SDingqiang Lin #include "rkflash_debug.h"
13cd67f373SDingqiang Lin #include "rk_sftl.h"
14ba0501acSDingqiang Lin #include "sfc.h"
15ba0501acSDingqiang Lin #include "sfc_nand.h"
16ba0501acSDingqiang Lin 
17ba0501acSDingqiang Lin static struct nand_info spi_nand_tbl[] = {
18ba0501acSDingqiang Lin 	/* TC58CVG0S0HxAIx */
19*415cf080Sjon.lin 	{0x98C2, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x02, 0xD8, 0x00, 18, 8, 0xFF, 0xFF, 4, 8, NULL},
20ba0501acSDingqiang Lin 	/* TC58CVG1S0HxAIx */
21*415cf080Sjon.lin 	{0x98CB, 4, 64, 2, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x02, 0xD8, 0x00, 19, 8, 0xFF, 0xFF, 4, 8, NULL},
22ba0501acSDingqiang Lin 	/* MX35LF1GE4AB */
236281205aSDingqiang 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 */
256281205aSDingqiang 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 */
276281205aSDingqiang Lin 	{0xC8F1, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 18, 8, 0xB0, 0, 4, 8, NULL},
28ba0501acSDingqiang Lin 	/* MT29F1G01ZAC */
296281205aSDingqiang 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},
306281205aSDingqiang Lin 	/* GD5F2GQ40BY2GR */
316281205aSDingqiang 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 */
336281205aSDingqiang 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*415cf080Sjon.lin 	{0xC821, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x00, 18, 1, 0xFF, 0xFF, 8, 12, &sfc_nand_ecc_status_sp1},
36ba0501acSDingqiang Lin 	/* W25N01GV */
37*415cf080Sjon.lin 	{0xEFAA, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x4C, 18, 1, 0xFF, 0xFF, 4, 20, &sfc_nand_ecc_status_sp1},
3840425644SDingqiang Lin 	/* HYF2GQ4UAACAE */
3925098c06SDingqiang Lin 	{0xC952, 4, 64, 1, 2048, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x4C, 19, 14, 0xB0, 0, 4, 36, NULL},
406281205aSDingqiang Lin 	/* HYF2GQ4UDACAE */
4125098c06SDingqiang Lin 	{0xC922, 4, 64, 1, 2048, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x4C, 19, 4, 0xB0, 0, 4, 20, NULL},
4240425644SDingqiang Lin 	/* HYF2GQ4UHCCAE */
4325098c06SDingqiang Lin 	{0xC95A, 4, 64, 1, 2048, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x4C, 19, 14, 0xB0, 0, 4, 36, NULL},
446281205aSDingqiang Lin 	/* HYF1GQ4UDACAE */
4525098c06SDingqiang Lin 	{0xC921, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x4C, 18, 4, 0xB0, 0, 4, 20, NULL},
4640425644SDingqiang Lin 	/* F50L1G41LB */
47*415cf080Sjon.lin 	{0xC801, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x4C, 18, 1, 0xFF, 0xFF, 20, 36, &sfc_nand_ecc_status_sp1},
4840425644SDingqiang Lin 	/* XT26G02A */
49*415cf080Sjon.lin 	{0x0BE2, 4, 64, 1, 2048, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x4C, 19, 1, 0xB0, 0x0, 8, 12, &sfc_nand_ecc_status_sp4},
5040425644SDingqiang Lin 	/* XT26G01A */
51*415cf080Sjon.lin 	{0x0BE1, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x4C, 18, 1, 0xB0, 0x0, 8, 12, &sfc_nand_ecc_status_sp4},
5225098c06SDingqiang Lin 	/* FS35ND01G-S1 */
5325098c06SDingqiang Lin 	{0xCDB1, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 18, 4, 0xB0, 0x0, 16, 20, &sfc_nand_ecc_status_sp5},
5425098c06SDingqiang Lin 	/* FS35ND02G-S2 */
5525098c06SDingqiang Lin 	{0xCDA2, 4, 64, 1, 2048, 0x13, 0x10, 0x03, 0x02, 0x03, 0x02, 0xD8, 0x00, 19, 4, 0xFF, 0xFF, 16, 20, &sfc_nand_ecc_status_sp5},
56*415cf080Sjon.lin 	/* DS35Q1GA-1B */
57*415cf080Sjon.lin 	{0xE571, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 18, 4, 0xB0, 0x0, 4, 20, &sfc_nand_ecc_status_sp1},
58*415cf080Sjon.lin 	/* DS35Q2GA-1B */
59*415cf080Sjon.lin 	{0xE572, 4, 64, 2, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 19, 4, 0xB0, 0x0, 4, 20, &sfc_nand_ecc_status_sp1},
60*415cf080Sjon.lin 	/* EM73C044SNC-G */
61*415cf080Sjon.lin 	{0xD522, 4, 64, 1, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 18, 8, 0xB0, 0x0, 4, 20, NULL},
62*415cf080Sjon.lin 	/* EM73D044SNB-G */
63*415cf080Sjon.lin 	{0xD520, 4, 64, 2, 1024, 0x13, 0x10, 0x03, 0x02, 0x6B, 0x32, 0xD8, 0x0C, 19, 8, 0xB0, 0x0, 4, 20, NULL}
64ba0501acSDingqiang Lin };
65ba0501acSDingqiang Lin 
66ba0501acSDingqiang Lin static u8 id_byte[8];
67ba0501acSDingqiang Lin static struct nand_info *p_nand_info;
68ba0501acSDingqiang Lin static u32 gp_page_buf[SFC_NAND_PAGE_MAX_SIZE / 4];
69ba0501acSDingqiang Lin static struct SFNAND_DEV sfc_nand_dev;
70ba0501acSDingqiang Lin 
71ba0501acSDingqiang Lin static struct nand_info *spi_nand_get_info(u8 *nand_id)
72ba0501acSDingqiang Lin {
73ba0501acSDingqiang Lin 	u32 i;
74ba0501acSDingqiang Lin 	u32 id = (nand_id[0] << 8) | (nand_id[1] << 0);
75ba0501acSDingqiang Lin 
76ba0501acSDingqiang Lin 	for (i = 0; i < ARRAY_SIZE(spi_nand_tbl); i++) {
77ba0501acSDingqiang Lin 		if (spi_nand_tbl[i].id == id)
78ba0501acSDingqiang Lin 			return &spi_nand_tbl[i];
79ba0501acSDingqiang Lin 	}
80ba0501acSDingqiang Lin 	return NULL;
81ba0501acSDingqiang Lin }
82ba0501acSDingqiang Lin 
83ba0501acSDingqiang Lin static int sfc_nand_write_en(void)
84ba0501acSDingqiang Lin {
85ba0501acSDingqiang Lin 	int ret;
86ba0501acSDingqiang Lin 	union SFCCMD_DATA sfcmd;
87ba0501acSDingqiang Lin 
88ba0501acSDingqiang Lin 	sfcmd.d32 = 0;
89ba0501acSDingqiang Lin 	sfcmd.b.cmd = CMD_WRITE_EN;
90ba0501acSDingqiang Lin 	ret = sfc_request(sfcmd.d32, 0, 0, NULL);
91ba0501acSDingqiang Lin 	return ret;
92ba0501acSDingqiang Lin }
93ba0501acSDingqiang Lin 
94ba0501acSDingqiang Lin static int sfc_nand_rw_preset(void)
95ba0501acSDingqiang Lin {
96ba0501acSDingqiang Lin 	int ret;
97ba0501acSDingqiang Lin 	union SFCCTRL_DATA sfctrl;
98ba0501acSDingqiang Lin 	union SFCCMD_DATA sfcmd;
99ba0501acSDingqiang Lin 	u8 status = 0xFF;
100ba0501acSDingqiang Lin 
101ba0501acSDingqiang Lin 	sfcmd.d32 = 0;
102ba0501acSDingqiang Lin 	sfcmd.b.cmd = 0;
103ba0501acSDingqiang Lin 	sfcmd.b.datasize = 1;
104ba0501acSDingqiang Lin 	sfcmd.b.rw = SFC_WRITE;
105ba0501acSDingqiang Lin 
106ba0501acSDingqiang Lin 	sfctrl.b.datalines = 2;
107ba0501acSDingqiang Lin 	ret = sfc_request(sfcmd.d32, sfctrl.d32, 0, &status);
108ba0501acSDingqiang Lin 	return ret;
109ba0501acSDingqiang Lin }
110ba0501acSDingqiang Lin 
111ba0501acSDingqiang Lin static int sfc_nand_read_feature(u8 addr, u8 *data)
112ba0501acSDingqiang Lin {
113ba0501acSDingqiang Lin 	int ret;
114ba0501acSDingqiang Lin 	union SFCCMD_DATA sfcmd;
115ba0501acSDingqiang Lin 
116ba0501acSDingqiang Lin 	sfcmd.d32 = 0;
117ba0501acSDingqiang Lin 	sfcmd.b.cmd = 0x0F;
118ba0501acSDingqiang Lin 	sfcmd.b.datasize = 1;
119ba0501acSDingqiang Lin 	sfcmd.b.addrbits = SFC_ADDR_XBITS;
120ba0501acSDingqiang Lin 	*data = 0;
121ba0501acSDingqiang Lin 
122ba0501acSDingqiang Lin 	ret = sfc_request(sfcmd.d32, 0x8 << 16, addr, data);
123ba0501acSDingqiang Lin 	if (ret != SFC_OK)
124ba0501acSDingqiang Lin 		return ret;
125ba0501acSDingqiang Lin 	return SFC_OK;
126ba0501acSDingqiang Lin }
127ba0501acSDingqiang Lin 
128ba0501acSDingqiang Lin static int sfc_nand_write_feature(u32 addr, u8 status)
129ba0501acSDingqiang Lin {
130ba0501acSDingqiang Lin 	int ret;
131ba0501acSDingqiang Lin 	union SFCCMD_DATA sfcmd;
132ba0501acSDingqiang Lin 
133ba0501acSDingqiang Lin 	sfc_nand_write_en();
134ba0501acSDingqiang Lin 
135ba0501acSDingqiang Lin 	sfcmd.d32 = 0;
136ba0501acSDingqiang Lin 	sfcmd.b.cmd = 0x1F;
137ba0501acSDingqiang Lin 	sfcmd.b.datasize = 1;
138ba0501acSDingqiang Lin 	sfcmd.b.addrbits = SFC_ADDR_XBITS;
139ba0501acSDingqiang Lin 	sfcmd.b.rw = SFC_WRITE;
140ba0501acSDingqiang Lin 
141ba0501acSDingqiang Lin 	ret = sfc_request(sfcmd.d32, 0x8 << 16, addr, &status);
142ba0501acSDingqiang Lin 	if (ret != SFC_OK)
143ba0501acSDingqiang Lin 		return ret;
144ba0501acSDingqiang Lin 	return ret;
145ba0501acSDingqiang Lin }
146ba0501acSDingqiang Lin 
147ba0501acSDingqiang Lin static int sfc_nand_wait_busy(u8 *data, int timeout)
148ba0501acSDingqiang Lin {
149ba0501acSDingqiang Lin 	int ret;
150ba0501acSDingqiang Lin 	int i;
151ba0501acSDingqiang Lin 	u8 status;
152ba0501acSDingqiang Lin 
153ba0501acSDingqiang Lin 	*data = 0;
154ba0501acSDingqiang Lin 	for (i = 0; i < timeout; i++) {
155ba0501acSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
156ba0501acSDingqiang Lin 		if (ret != SFC_OK)
157ba0501acSDingqiang Lin 			return ret;
158ba0501acSDingqiang Lin 		*data = status;
159ba0501acSDingqiang Lin 		if (!(status & (1 << 0)))
160ba0501acSDingqiang Lin 			return SFC_OK;
161ba0501acSDingqiang Lin 		sfc_delay(1);
162ba0501acSDingqiang Lin 	}
163ba0501acSDingqiang Lin 	return -1;
164ba0501acSDingqiang Lin }
165ba0501acSDingqiang Lin 
1666281205aSDingqiang Lin /*
1676281205aSDingqiang Lin  * ecc default:
1686281205aSDingqiang Lin  * 0, No bit errors were detected
1696281205aSDingqiang Lin  * 1, Bit errors were detected and corrected.
1706281205aSDingqiang Lin  * 2, Multiple bit errors were detected and not corrected.
1716281205aSDingqiang Lin  * 3, Bits errors were detected and corrected, bit error count
1726281205aSDingqiang Lin  *	exceed the bit flip detection threshold
1736281205aSDingqiang Lin  */
1746281205aSDingqiang Lin static u32 sfc_nand_ecc_status(void)
1756281205aSDingqiang Lin {
1766281205aSDingqiang Lin 	int ret;
1776281205aSDingqiang Lin 	u32 i;
1786281205aSDingqiang Lin 	u8 ecc;
1796281205aSDingqiang Lin 	u8 status;
1806281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
1816281205aSDingqiang Lin 
1826281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
1836281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
1846281205aSDingqiang Lin 		if (ret != SFC_OK)
1856281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
1866281205aSDingqiang Lin 		if (!(status & (1 << 0)))
1876281205aSDingqiang Lin 			break;
1886281205aSDingqiang Lin 		sfc_delay(1);
1896281205aSDingqiang Lin 	}
1906281205aSDingqiang Lin 
1916281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
1926281205aSDingqiang Lin 
1936281205aSDingqiang Lin 	if (ecc <= 1)
1946281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
1956281205aSDingqiang Lin 	else if (ecc == 2)
1966281205aSDingqiang Lin 		ret = SFC_NAND_ECC_ERROR;
1976281205aSDingqiang Lin 	else
1986281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
1996281205aSDingqiang Lin 
2006281205aSDingqiang Lin 	return ret;
2016281205aSDingqiang Lin }
2026281205aSDingqiang Lin 
2036281205aSDingqiang Lin /*
2046281205aSDingqiang Lin  * ecc spectial type1:
2056281205aSDingqiang Lin  * 0x00, No bit errors were detected;
2066281205aSDingqiang Lin  * 0x01, Bits errors were detected and corrected, bit error count
2076281205aSDingqiang Lin  *	may reach the bit flip detection threshold;
2086281205aSDingqiang Lin  * 0x10, Multiple bit errors were detected and not corrected;
2096281205aSDingqiang Lin  * 0x11, Reserved.
2106281205aSDingqiang Lin  */
2116281205aSDingqiang Lin u32 sfc_nand_ecc_status_sp1(void)
2126281205aSDingqiang Lin {
2136281205aSDingqiang Lin 	int ret;
2146281205aSDingqiang Lin 	u32 i;
2156281205aSDingqiang Lin 	u8 ecc;
2166281205aSDingqiang Lin 	u8 status;
2176281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
2186281205aSDingqiang Lin 
2196281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
2206281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
2216281205aSDingqiang Lin 		if (ret != SFC_OK)
2226281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
2236281205aSDingqiang Lin 		if (!(status & (1 << 0)))
2246281205aSDingqiang Lin 			break;
2256281205aSDingqiang Lin 		sfc_delay(1);
2266281205aSDingqiang Lin 	}
2276281205aSDingqiang Lin 
2286281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
2296281205aSDingqiang Lin 
2306281205aSDingqiang Lin 	if (ecc == 0)
2316281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
2326281205aSDingqiang Lin 	else if (ecc == 1)
2336281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
2346281205aSDingqiang Lin 	else
2356281205aSDingqiang Lin 		ret = SFC_NAND_ECC_ERROR;
2366281205aSDingqiang Lin 
2376281205aSDingqiang Lin 	return ret;
2386281205aSDingqiang Lin }
2396281205aSDingqiang Lin 
2406281205aSDingqiang Lin /*
2416281205aSDingqiang Lin  * ecc spectial type3:
2426281205aSDingqiang Lin  * [0x0000, 0x0011], No bit errors were detected;
2436281205aSDingqiang Lin  * [0x0100, 0x0111], Bit errors were detected and corrected. Not
2446281205aSDingqiang Lin  *	reach Flipping Bits;
2456281205aSDingqiang Lin  * [0x1000, 0x1011], Multiple bit errors were detected and
2466281205aSDingqiang Lin  *	not corrected.
2476281205aSDingqiang Lin  * [0x1100, 0x1111], Bit error count equals the bit flip
2486281205aSDingqiang Lin  *	detectionthreshold
2496281205aSDingqiang Lin  */
2506281205aSDingqiang Lin u32 sfc_nand_ecc_status_sp3(void)
2516281205aSDingqiang Lin {
2526281205aSDingqiang Lin 	int ret;
2536281205aSDingqiang Lin 	u32 i;
2546281205aSDingqiang Lin 	u8 ecc;
2556281205aSDingqiang Lin 	u8 status, status1;
2566281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
2576281205aSDingqiang Lin 
2586281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
2596281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
2606281205aSDingqiang Lin 		if (ret != SFC_OK)
2616281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
2626281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xF0, &status1);
2636281205aSDingqiang Lin 		if (ret != SFC_OK)
2646281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
2656281205aSDingqiang Lin 		if (!(status & (1 << 0)))
2666281205aSDingqiang Lin 			break;
2676281205aSDingqiang Lin 		sfc_delay(1);
2686281205aSDingqiang Lin 	}
2696281205aSDingqiang Lin 
2706281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
2716281205aSDingqiang Lin 	ecc = (ecc << 2) | ((status1 >> 4) & 0x03);
2726281205aSDingqiang Lin 	if (ecc < 7)
2736281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
2746281205aSDingqiang Lin 	else if (ecc == 7 || ecc >= 12)
2756281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
2766281205aSDingqiang Lin 	else
2776281205aSDingqiang Lin 		ret = SFC_NAND_ECC_ERROR;
2786281205aSDingqiang Lin 
2796281205aSDingqiang Lin 	return ret;
2806281205aSDingqiang Lin }
2816281205aSDingqiang Lin 
28225098c06SDingqiang Lin /*
28325098c06SDingqiang Lin  * ecc spectial type4:
28425098c06SDingqiang Lin  * [0x0000], No bit errors were detected;
28525098c06SDingqiang Lin  * [0x0001, 0x0111], Bit errors were detected and corrected. Not
28625098c06SDingqiang Lin  *	reach Flipping Bits;
28725098c06SDingqiang Lin  * [0x1000], Multiple bit errors were detected and
28825098c06SDingqiang Lin  *	not corrected.
28925098c06SDingqiang Lin  * [0x1100], Bit error count equals the bit flip
29025098c06SDingqiang Lin  *	detectionthreshold
29125098c06SDingqiang Lin  * else, reserved
29225098c06SDingqiang Lin  */
29325098c06SDingqiang Lin u32 sfc_nand_ecc_status_sp4(void)
29425098c06SDingqiang Lin {
29525098c06SDingqiang Lin 	int ret;
29625098c06SDingqiang Lin 	u32 i;
29725098c06SDingqiang Lin 	u8 ecc;
29825098c06SDingqiang Lin 	u8 status;
29925098c06SDingqiang Lin 	u32 timeout = 1000 * 1000;
30025098c06SDingqiang Lin 
30125098c06SDingqiang Lin 	for (i = 0; i < timeout; i++) {
30225098c06SDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
30325098c06SDingqiang Lin 		if (ret != SFC_OK)
30425098c06SDingqiang Lin 			return SFC_NAND_ECC_ERROR;
30525098c06SDingqiang Lin 		if (!(status & (1 << 0)))
30625098c06SDingqiang Lin 			break;
30725098c06SDingqiang Lin 		sfc_delay(1);
30825098c06SDingqiang Lin 	}
30925098c06SDingqiang Lin 
31025098c06SDingqiang Lin 	ecc = (status >> 2) & 0x0f;
31125098c06SDingqiang Lin 	if (ecc < 7)
31225098c06SDingqiang Lin 		ret = SFC_NAND_ECC_OK;
31325098c06SDingqiang Lin 	else if (ecc == 7 || ecc == 12)
31425098c06SDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
31525098c06SDingqiang Lin 	else
31625098c06SDingqiang Lin 		ret = SFC_NAND_ECC_ERROR;
31725098c06SDingqiang Lin 
31825098c06SDingqiang Lin 	return ret;
31925098c06SDingqiang Lin }
32025098c06SDingqiang Lin 
32125098c06SDingqiang Lin /*
32225098c06SDingqiang Lin  * ecc spectial type5:
32325098c06SDingqiang Lin  * [0x0], No bit errors were detected;
32425098c06SDingqiang Lin  * [0x001, 0x011], Bit errors were detected and corrected. Not
32525098c06SDingqiang Lin  *	reach Flipping Bits;
32625098c06SDingqiang Lin  * [0x100], Bit error count equals the bit flip
32725098c06SDingqiang Lin  *	detectionthreshold
32825098c06SDingqiang Lin  * [0x101, 0x110], Reserved;
32925098c06SDingqiang Lin  * [0x111], Multiple bit errors were detected and
33025098c06SDingqiang Lin  *	not corrected.
33125098c06SDingqiang Lin  */
33225098c06SDingqiang Lin u32 sfc_nand_ecc_status_sp5(void)
33325098c06SDingqiang Lin {
33425098c06SDingqiang Lin 	int ret;
33525098c06SDingqiang Lin 	u32 i;
33625098c06SDingqiang Lin 	u8 ecc;
33725098c06SDingqiang Lin 	u8 status;
33825098c06SDingqiang Lin 	u32 timeout = 1000 * 1000;
33925098c06SDingqiang Lin 
34025098c06SDingqiang Lin 	for (i = 0; i < timeout; i++) {
34125098c06SDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
34225098c06SDingqiang Lin 		if (ret != SFC_OK)
34325098c06SDingqiang Lin 			return SFC_NAND_ECC_ERROR;
34425098c06SDingqiang Lin 		if (!(status & (1 << 0)))
34525098c06SDingqiang Lin 			break;
34625098c06SDingqiang Lin 		sfc_delay(1);
34725098c06SDingqiang Lin 	}
34825098c06SDingqiang Lin 
34925098c06SDingqiang Lin 	ecc = (status >> 4) & 0x07;
35025098c06SDingqiang Lin 	if (ecc < 4)
35125098c06SDingqiang Lin 		ret = SFC_NAND_ECC_OK;
35225098c06SDingqiang Lin 	else if (ecc == 4)
35325098c06SDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
35425098c06SDingqiang Lin 	else
35525098c06SDingqiang Lin 		ret = SFC_NAND_ECC_ERROR;
35625098c06SDingqiang Lin 
35725098c06SDingqiang Lin 	return ret;
35825098c06SDingqiang Lin }
35925098c06SDingqiang Lin 
360ba0501acSDingqiang Lin static u32 sfc_nand_erase_block(u8 cs, u32 addr)
361ba0501acSDingqiang Lin {
362ba0501acSDingqiang Lin 	int ret;
363ba0501acSDingqiang Lin 	union SFCCMD_DATA sfcmd;
364ba0501acSDingqiang Lin 	u8 status;
365ba0501acSDingqiang Lin 
366ba0501acSDingqiang Lin 	sfcmd.d32 = 0;
367ba0501acSDingqiang Lin 	sfcmd.b.cmd = p_nand_info->block_erase_cmd;
368ba0501acSDingqiang Lin 	sfcmd.b.addrbits = SFC_ADDR_24BITS;
369ba0501acSDingqiang Lin 	sfc_nand_write_en();
370ba0501acSDingqiang Lin 	ret = sfc_request(sfcmd.d32, 0, addr, NULL);
371ba0501acSDingqiang Lin 	if (ret != SFC_OK)
372ba0501acSDingqiang Lin 		return ret;
373ba0501acSDingqiang Lin 	ret = sfc_nand_wait_busy(&status, 1000 * 1000);
374ba0501acSDingqiang Lin 	if (status & (1 << 2))
375ba0501acSDingqiang Lin 		return SFC_NAND_PROG_ERASE_ERROR;
376ba0501acSDingqiang Lin 	return ret;
377ba0501acSDingqiang Lin }
378ba0501acSDingqiang Lin 
379ba0501acSDingqiang Lin static u32 sfc_nand_prog_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare)
380ba0501acSDingqiang Lin {
381ba0501acSDingqiang Lin 	int ret;
382*415cf080Sjon.lin 	u32 plane;
383ba0501acSDingqiang Lin 	union SFCCMD_DATA sfcmd;
384ba0501acSDingqiang Lin 	union SFCCTRL_DATA sfctrl;
385ba0501acSDingqiang Lin 	u8 status;
386ba0501acSDingqiang Lin 	u32 data_sz = 2048;
387ba0501acSDingqiang Lin 	u32 spare_offs_1 = p_nand_info->spare_offs_1;
388ba0501acSDingqiang Lin 	u32 spare_offs_2 = p_nand_info->spare_offs_2;
389ba0501acSDingqiang Lin 
390ba0501acSDingqiang Lin 	memcpy(gp_page_buf, p_data, data_sz);
391*415cf080Sjon.lin 	ftl_memset(&gp_page_buf[data_sz / 4], 0xff, 64);
392ba0501acSDingqiang Lin 	gp_page_buf[(data_sz + spare_offs_1) / 4] = p_spare[0];
393ba0501acSDingqiang Lin 	gp_page_buf[(data_sz + spare_offs_2) / 4] = p_spare[1];
394ba0501acSDingqiang Lin 
395ba0501acSDingqiang Lin 	sfc_nand_write_en();
396ba0501acSDingqiang Lin 	if (sfc_nand_dev.prog_lines == DATA_LINES_X4 &&
39725098c06SDingqiang Lin 	    p_nand_info->feature & FEA_SOFT_QOP_BIT &&
39825098c06SDingqiang Lin 	    sfc_get_version() < SFC_VER_3)
399ba0501acSDingqiang Lin 		sfc_nand_rw_preset();
400ba0501acSDingqiang Lin 
401ba0501acSDingqiang Lin 	sfcmd.d32 = 0;
402ba0501acSDingqiang Lin 	sfcmd.b.cmd = sfc_nand_dev.page_prog_cmd;
403ba0501acSDingqiang Lin 	sfcmd.b.addrbits = SFC_ADDR_XBITS;
404ba0501acSDingqiang Lin 	sfcmd.b.datasize = SFC_NAND_PAGE_MAX_SIZE;
405ba0501acSDingqiang Lin 	sfcmd.b.rw = SFC_WRITE;
406ba0501acSDingqiang Lin 
407ba0501acSDingqiang Lin 	sfctrl.d32 = 0;
408ba0501acSDingqiang Lin 	sfctrl.b.datalines = sfc_nand_dev.prog_lines;
409ba0501acSDingqiang Lin 	sfctrl.b.addrbits = 16;
410*415cf080Sjon.lin 	plane = p_nand_info->plane_per_die == 2 ? ((addr >> 6) & 0x1) << 12 : 0;
411*415cf080Sjon.lin 	sfc_request(sfcmd.d32, sfctrl.d32, plane, gp_page_buf);
412ba0501acSDingqiang Lin 
413ba0501acSDingqiang Lin 	sfcmd.d32 = 0;
414ba0501acSDingqiang Lin 	sfcmd.b.cmd = p_nand_info->page_prog_cmd;
415ba0501acSDingqiang Lin 	sfcmd.b.addrbits = SFC_ADDR_24BITS;
416ba0501acSDingqiang Lin 	sfcmd.b.datasize = 0;
417ba0501acSDingqiang Lin 	sfcmd.b.rw = SFC_WRITE;
418ba0501acSDingqiang Lin 	ret = sfc_request(sfcmd.d32, 0, addr, p_data);
419ba0501acSDingqiang Lin 	if (ret != SFC_OK)
420ba0501acSDingqiang Lin 		return ret;
421ba0501acSDingqiang Lin 	ret = sfc_nand_wait_busy(&status, 1000 * 1000);
422ba0501acSDingqiang Lin 	if (status & (1 << 3))
423ba0501acSDingqiang Lin 		return SFC_NAND_PROG_ERASE_ERROR;
424ba0501acSDingqiang Lin 	return ret;
425ba0501acSDingqiang Lin }
426ba0501acSDingqiang Lin 
427ba0501acSDingqiang Lin static u32 sfc_nand_read_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare)
428ba0501acSDingqiang Lin {
429ba0501acSDingqiang Lin 	int ret;
430*415cf080Sjon.lin 	u32 plane;
431ba0501acSDingqiang Lin 	union SFCCMD_DATA sfcmd;
432ba0501acSDingqiang Lin 	union SFCCTRL_DATA sfctrl;
4336281205aSDingqiang Lin 	u32 ecc_result;
434ba0501acSDingqiang Lin 	u32 data_sz = 2048;
435ba0501acSDingqiang Lin 	u32 spare_offs_1 = p_nand_info->spare_offs_1;
436ba0501acSDingqiang Lin 	u32 spare_offs_2 = p_nand_info->spare_offs_2;
437ba0501acSDingqiang Lin 
438ba0501acSDingqiang Lin 	sfcmd.d32 = 0;
439ba0501acSDingqiang Lin 	sfcmd.b.cmd = p_nand_info->page_read_cmd;
440ba0501acSDingqiang Lin 	sfcmd.b.datasize = 0;
441ba0501acSDingqiang Lin 	sfcmd.b.addrbits = SFC_ADDR_24BITS;
442ba0501acSDingqiang Lin 	sfc_request(sfcmd.d32, 0, addr, p_data);
443ba0501acSDingqiang Lin 
4446281205aSDingqiang Lin 	if (p_nand_info->ecc_status)
4456281205aSDingqiang Lin 		ecc_result = p_nand_info->ecc_status();
4466281205aSDingqiang Lin 	else
4476281205aSDingqiang Lin 		ecc_result = sfc_nand_ecc_status();
4486281205aSDingqiang Lin 
449ba0501acSDingqiang Lin 	if (sfc_nand_dev.read_lines == DATA_LINES_X4 &&
45025098c06SDingqiang Lin 	    p_nand_info->feature & FEA_SOFT_QOP_BIT &&
45125098c06SDingqiang Lin 	    sfc_get_version() < SFC_VER_3)
452ba0501acSDingqiang Lin 		sfc_nand_rw_preset();
453ba0501acSDingqiang Lin 
454ba0501acSDingqiang Lin 	sfcmd.d32 = 0;
455ba0501acSDingqiang Lin 	sfcmd.b.cmd = sfc_nand_dev.page_read_cmd;
456ba0501acSDingqiang Lin 	sfcmd.b.datasize = SFC_NAND_PAGE_MAX_SIZE;
457ba0501acSDingqiang Lin 	sfcmd.b.addrbits = SFC_ADDR_24BITS;
458ba0501acSDingqiang Lin 	sfctrl.d32 = 0;
459ba0501acSDingqiang Lin 	sfctrl.b.datalines = sfc_nand_dev.read_lines;
460ba0501acSDingqiang Lin 
461*415cf080Sjon.lin 	plane = p_nand_info->plane_per_die == 2 ? ((addr >> 6) & 0x1) << 12 : 0;
462ba0501acSDingqiang Lin 	memset(gp_page_buf, 0, SFC_NAND_PAGE_MAX_SIZE);
463*415cf080Sjon.lin 	ret = sfc_request(sfcmd.d32, sfctrl.d32, plane << 8, gp_page_buf);
464ba0501acSDingqiang Lin 
465ba0501acSDingqiang Lin 	memcpy(p_data, gp_page_buf, data_sz);
466ba0501acSDingqiang Lin 	p_spare[0] = gp_page_buf[(data_sz + spare_offs_1) / 4];
467ba0501acSDingqiang Lin 	p_spare[1] = gp_page_buf[(data_sz + spare_offs_2) / 4];
468ba0501acSDingqiang Lin 	if (ret != SFC_OK)
469ba0501acSDingqiang Lin 		return SFC_NAND_ECC_ERROR;
470ba0501acSDingqiang Lin 
4716281205aSDingqiang Lin 	if (ecc_result != SFC_NAND_ECC_OK) {
4726281205aSDingqiang Lin 		PRINT_SFC_E("%s[0x%x], ret=0x%x\n", __func__, addr, ecc_result);
473ba0501acSDingqiang Lin 		if (p_data)
474ba0501acSDingqiang Lin 			PRINT_SFC_HEX("data:", p_data, 4, 8);
475ba0501acSDingqiang Lin 		if (p_spare)
476ba0501acSDingqiang Lin 			PRINT_SFC_HEX("spare:", p_spare, 4, 2);
477ba0501acSDingqiang Lin 	}
4786281205aSDingqiang Lin 	return ecc_result;
479ba0501acSDingqiang Lin }
480ba0501acSDingqiang Lin 
481ba0501acSDingqiang Lin static int sfc_nand_read_id_raw(u8 *data)
482ba0501acSDingqiang Lin {
483ba0501acSDingqiang Lin 	int ret;
484ba0501acSDingqiang Lin 	union SFCCMD_DATA sfcmd;
485ba0501acSDingqiang Lin 
486ba0501acSDingqiang Lin 	sfcmd.d32 = 0;
487ba0501acSDingqiang Lin 	sfcmd.b.cmd = CMD_READ_JEDECID;
488ba0501acSDingqiang Lin 	sfcmd.b.datasize = 3;
489ba0501acSDingqiang Lin 	sfcmd.b.addrbits = SFC_ADDR_XBITS;
490ba0501acSDingqiang Lin 
491ba0501acSDingqiang Lin 	ret = sfc_request(sfcmd.d32, 0x8 << 16, 0, data);
492ba0501acSDingqiang Lin 
493ba0501acSDingqiang Lin 	return ret;
494ba0501acSDingqiang Lin }
495ba0501acSDingqiang Lin 
496ba0501acSDingqiang Lin /*
497ba0501acSDingqiang Lin  * Read the 1st page's 1st byte of a phy_blk
498ba0501acSDingqiang Lin  * If not FF, it's bad blk
499ba0501acSDingqiang Lin  */
500ba0501acSDingqiang Lin static int sfc_nand_get_bad_block_list(u16 *table, u32 die)
501ba0501acSDingqiang Lin {
502ba0501acSDingqiang Lin 	u16 blk;
503ba0501acSDingqiang Lin 	u32 bad_cnt, page;
504ba0501acSDingqiang Lin 	u32 blk_per_die;
505ba0501acSDingqiang Lin 	u32 *pread;
506ba0501acSDingqiang Lin 	u32 *pspare_read;
507ba0501acSDingqiang Lin 
508ba0501acSDingqiang Lin 	PRINT_SFC_E("%s\n", __func__);
509ba0501acSDingqiang Lin 	pread = ftl_malloc(2048);
510ba0501acSDingqiang Lin 	pspare_read = ftl_malloc(8);
511ba0501acSDingqiang Lin 	bad_cnt = 0;
512ba0501acSDingqiang Lin 	blk_per_die = p_nand_info->plane_per_die *
513ba0501acSDingqiang Lin 			p_nand_info->blk_per_plane;
514ba0501acSDingqiang Lin 	for (blk = 0; blk < blk_per_die; blk++) {
515ba0501acSDingqiang Lin 		page = (blk + blk_per_die * die) *
516ba0501acSDingqiang Lin 			p_nand_info->page_per_blk;
517ba0501acSDingqiang Lin 		sfc_nand_read_page(0, page, pread, pspare_read);
518ba0501acSDingqiang Lin 
519ba0501acSDingqiang Lin 		if (pread[0] != 0xFFFFFFFF ||
520ba0501acSDingqiang Lin 		    pspare_read[0] != 0xFFFFFFFF) {
521ba0501acSDingqiang Lin 			table[bad_cnt++] = blk;
522ba0501acSDingqiang Lin 			PRINT_SFC_E("die[%d], bad_blk[%d]\n", die, blk);
523ba0501acSDingqiang Lin 		}
524ba0501acSDingqiang Lin 	}
525ba0501acSDingqiang Lin 	ftl_free(pread);
526ba0501acSDingqiang Lin 	ftl_free(pspare_read);
527ba0501acSDingqiang Lin 	return (int)bad_cnt;
528ba0501acSDingqiang Lin }
529ba0501acSDingqiang Lin 
530ba0501acSDingqiang Lin #if SFC_NAND_STRESS_TEST_EN
531ba0501acSDingqiang Lin 
532ba0501acSDingqiang Lin #define SFC_NAND_PAGE_SIZE	2048
533ba0501acSDingqiang Lin #define SFC_NAND_SPARE_SIZE	8
534ba0501acSDingqiang Lin 
535ba0501acSDingqiang Lin static u16 bad_blk_list[1024];
536ba0501acSDingqiang Lin static u32 pwrite[SFC_NAND_PAGE_SIZE / 4];
537ba0501acSDingqiang Lin static u32 pread[SFC_NAND_PAGE_SIZE / 4];
538ba0501acSDingqiang Lin static u32 pspare_write[SFC_NAND_SPARE_SIZE / 4];
539ba0501acSDingqiang Lin static u32 pspare_read[SFC_NAND_SPARE_SIZE / 4];
540ba0501acSDingqiang Lin static u32 bad_blk_num;
541ba0501acSDingqiang Lin static u32 bad_page_num;
542ba0501acSDingqiang Lin 
543ba0501acSDingqiang Lin static void sfc_nand_test(void)
544ba0501acSDingqiang Lin {
545ba0501acSDingqiang Lin 	u32 i, blk, page, bad_cnt, page_addr;
546ba0501acSDingqiang Lin 	int ret;
547ba0501acSDingqiang Lin 	u32 pages_num = 64;
548ba0501acSDingqiang Lin 	u32 blk_addr = 64;
549ba0501acSDingqiang Lin 	u32 is_bad_blk = 0;
550ba0501acSDingqiang Lin 
551ba0501acSDingqiang Lin 	PRINT_SFC_E("%s\n", __func__);
552ba0501acSDingqiang Lin 
553ba0501acSDingqiang Lin 	bad_blk_num = 0;
554ba0501acSDingqiang Lin 	bad_page_num = 0;
555ba0501acSDingqiang Lin 	bad_cnt	= sfc_nand_get_bad_block_list(bad_blk_list, 0);
556ba0501acSDingqiang Lin 
557ba0501acSDingqiang Lin 	for (blk = 0; blk < 1024; blk++) {
558ba0501acSDingqiang Lin 		for (i = 0; i < bad_cnt; i++) {
559ba0501acSDingqiang Lin 			if (bad_blk_list[i] == blk)
560ba0501acSDingqiang Lin 				break;
561ba0501acSDingqiang Lin 		}
562ba0501acSDingqiang Lin 		if (i < bad_cnt)
563ba0501acSDingqiang Lin 			continue;
564ba0501acSDingqiang Lin 		is_bad_blk = 0;
565ba0501acSDingqiang Lin 		PRINT_SFC_E("Flash prog block: %x\n", blk);
566ba0501acSDingqiang Lin 		sfc_nand_erase_block(0, blk * blk_addr);
567ba0501acSDingqiang Lin 		for (page = 0; page < pages_num; page++) {
568ba0501acSDingqiang Lin 			page_addr = blk * blk_addr + page;
569ba0501acSDingqiang Lin 			for (i = 0; i < 512; i++)
570ba0501acSDingqiang Lin 				pwrite[i] = (page_addr << 16) + i;
571ba0501acSDingqiang Lin 			pspare_write[0] = pwrite[0] + 0x5AF0;
572ba0501acSDingqiang Lin 			pspare_write[1] = pspare_write[0] + 1;
573ba0501acSDingqiang Lin 			sfc_nand_prog_page(0, page_addr, pwrite, pspare_write);
574ba0501acSDingqiang Lin 			memset(pread, 0, 2048);
575ba0501acSDingqiang Lin 			memset(pspare_read, 0, 8);
576ba0501acSDingqiang Lin 			ret = sfc_nand_read_page(0, page_addr, pread,
577ba0501acSDingqiang Lin 						 pspare_read);
578ba0501acSDingqiang Lin 			if (ret != SFC_NAND_ECC_OK)
579ba0501acSDingqiang Lin 				is_bad_blk = 1;
580ba0501acSDingqiang Lin 			for (i = 0; i < 512; i++) {
581ba0501acSDingqiang Lin 				if (pwrite[i] != pread[i]) {
582ba0501acSDingqiang Lin 					is_bad_blk = 1;
583ba0501acSDingqiang Lin 					break;
584ba0501acSDingqiang Lin 				}
585ba0501acSDingqiang Lin 			}
586ba0501acSDingqiang Lin 			for (i = 0; i < 2; i++) {
587ba0501acSDingqiang Lin 				if (pspare_write[i] != pspare_read[i]) {
588ba0501acSDingqiang Lin 					is_bad_blk = 1;
589ba0501acSDingqiang Lin 					break;
590ba0501acSDingqiang Lin 				}
591ba0501acSDingqiang Lin 			}
592ba0501acSDingqiang Lin 			if (is_bad_blk) {
593ba0501acSDingqiang Lin 				bad_page_num++;
594ba0501acSDingqiang Lin 				PRINT_SFC_E("ERR:page%x, ret=%x\n",
595ba0501acSDingqiang Lin 					    page_addr, ret);
596ba0501acSDingqiang Lin 				PRINT_SFC_HEX("data:", pread, 4, 8);
597ba0501acSDingqiang Lin 				PRINT_SFC_HEX("spare:", pspare_read, 4, 2);
598ba0501acSDingqiang Lin 			}
599ba0501acSDingqiang Lin 		}
600ba0501acSDingqiang Lin 		sfc_nand_erase_block(0, blk * blk_addr);
601ba0501acSDingqiang Lin 		if (is_bad_blk)
602ba0501acSDingqiang Lin 			bad_blk_num++;
603ba0501acSDingqiang Lin 	}
604ba0501acSDingqiang Lin 	PRINT_SFC_E("bad_blk_num = %d, bad_page_num = %d\n",
605ba0501acSDingqiang Lin 		    bad_blk_num, bad_page_num);
606ba0501acSDingqiang Lin 
607ba0501acSDingqiang Lin 	PRINT_SFC_E("Flash Test Finish!!!\n");
608ba0501acSDingqiang Lin 	while (1)
609ba0501acSDingqiang Lin 		;
610ba0501acSDingqiang Lin }
611ba0501acSDingqiang Lin #endif
612ba0501acSDingqiang Lin 
613ba0501acSDingqiang Lin static void ftl_flash_init(void)
614ba0501acSDingqiang Lin {
615ba0501acSDingqiang Lin 	/* para init */
616ba0501acSDingqiang Lin 	g_nand_phy_info.nand_type	= 1;
617ba0501acSDingqiang Lin 	g_nand_phy_info.die_num		= 1;
618ba0501acSDingqiang Lin 	g_nand_phy_info.plane_per_die	= p_nand_info->plane_per_die;
619ba0501acSDingqiang Lin 	g_nand_phy_info.blk_per_plane	= p_nand_info->blk_per_plane;
620ba0501acSDingqiang Lin 	g_nand_phy_info.page_per_blk	= p_nand_info->page_per_blk;
621ba0501acSDingqiang Lin 	g_nand_phy_info.page_per_slc_blk = p_nand_info->page_per_blk;
622ba0501acSDingqiang Lin 	g_nand_phy_info.byte_per_sec	= 512;
623ba0501acSDingqiang Lin 	g_nand_phy_info.sec_per_page	= p_nand_info->sec_per_page;
624ba0501acSDingqiang Lin 	g_nand_phy_info.sec_per_blk	= p_nand_info->sec_per_page *
625ba0501acSDingqiang Lin 					  p_nand_info->page_per_blk;
626ba0501acSDingqiang Lin 	g_nand_phy_info.reserved_blk	= 8;
627ba0501acSDingqiang Lin 	g_nand_phy_info.blk_per_die	= p_nand_info->plane_per_die *
628ba0501acSDingqiang Lin 					  p_nand_info->blk_per_plane;
629ba0501acSDingqiang Lin 	g_nand_phy_info.ecc_bits	= p_nand_info->max_ecc_bits;
630ba0501acSDingqiang Lin 
631ba0501acSDingqiang Lin 	/* driver register */
632ba0501acSDingqiang Lin 	g_nand_ops.get_bad_blk_list	= sfc_nand_get_bad_block_list;
633ba0501acSDingqiang Lin 	g_nand_ops.erase_blk		= sfc_nand_erase_block;
634ba0501acSDingqiang Lin 	g_nand_ops.prog_page		= sfc_nand_prog_page;
635ba0501acSDingqiang Lin 	g_nand_ops.read_page		= sfc_nand_read_page;
63657d18453Sjon.lin 	g_nand_ops.bch_sel		= NULL;
637ba0501acSDingqiang Lin }
638ba0501acSDingqiang Lin 
639ba0501acSDingqiang Lin static int spi_nand_enable_QE(void)
640ba0501acSDingqiang Lin {
641ba0501acSDingqiang Lin 	int ret = SFC_OK;
642ba0501acSDingqiang Lin 	u8 status;
643ba0501acSDingqiang Lin 	int bit_offset = p_nand_info->QE_bits;
644ba0501acSDingqiang Lin 
645ba0501acSDingqiang Lin 	if (bit_offset == 0xFF)
646ba0501acSDingqiang Lin 		return SFC_OK;
647ba0501acSDingqiang Lin 
648ba0501acSDingqiang Lin 	ret = sfc_nand_read_feature(p_nand_info->QE_address, &status);
649ba0501acSDingqiang Lin 	if (ret != SFC_OK)
650ba0501acSDingqiang Lin 		return ret;
651ba0501acSDingqiang Lin 
652ba0501acSDingqiang Lin 	if (status & (1 << bit_offset))   /* is QE bit set */
653ba0501acSDingqiang Lin 		return SFC_OK;
654ba0501acSDingqiang Lin 
655ba0501acSDingqiang Lin 	status |= (1 << bit_offset);
656ba0501acSDingqiang Lin 		return sfc_nand_write_feature(p_nand_info->QE_address, status);
657ba0501acSDingqiang Lin 
658ba0501acSDingqiang Lin 	return ret;
659ba0501acSDingqiang Lin }
660ba0501acSDingqiang Lin 
661ba0501acSDingqiang Lin u32 sfc_nand_init(void)
662ba0501acSDingqiang Lin {
663ba0501acSDingqiang Lin 	PRINT_SFC_I("...%s enter...\n", __func__);
664ba0501acSDingqiang Lin 
665ba0501acSDingqiang Lin 	sfc_nand_read_id_raw(id_byte);
6665727ee42Sjon.lin 	PRINT_SFC_E("sfc_nand id: %x %x %x\n",
667ba0501acSDingqiang Lin 		    id_byte[0], id_byte[1], id_byte[2]);
668ba0501acSDingqiang Lin 	if (id_byte[0] == 0xFF || id_byte[0] == 0x00)
669ba0501acSDingqiang Lin 		return FTL_NO_FLASH;
670ba0501acSDingqiang Lin 
671ba0501acSDingqiang Lin 	p_nand_info = spi_nand_get_info(id_byte);
672ba0501acSDingqiang Lin 	if (!p_nand_info)
673ba0501acSDingqiang Lin 		return FTL_UNSUPPORTED_FLASH;
674ba0501acSDingqiang Lin 
675ba0501acSDingqiang Lin 	sfc_nand_dev.manufacturer = id_byte[0];
676ba0501acSDingqiang Lin 	sfc_nand_dev.mem_type = id_byte[1];
677ba0501acSDingqiang Lin 
678ba0501acSDingqiang Lin 	/* disable block lock */
679ba0501acSDingqiang Lin 	sfc_nand_write_feature(0xA0, 0);
680ba0501acSDingqiang Lin 	sfc_nand_dev.read_lines = DATA_LINES_X1;
681ba0501acSDingqiang Lin 	sfc_nand_dev.prog_lines = DATA_LINES_X1;
682ba0501acSDingqiang Lin 	sfc_nand_dev.page_read_cmd = p_nand_info->read_cache_cmd_1;
683ba0501acSDingqiang Lin 	sfc_nand_dev.page_prog_cmd = p_nand_info->prog_cache_cmd_1;
684ba0501acSDingqiang Lin 	if (p_nand_info->feature & FEA_4BIT_READ) {
685ba0501acSDingqiang Lin 		if (spi_nand_enable_QE() == SFC_OK) {
686ba0501acSDingqiang Lin 			sfc_nand_dev.read_lines = DATA_LINES_X4;
687ba0501acSDingqiang Lin 			sfc_nand_dev.page_read_cmd =
688ba0501acSDingqiang Lin 				p_nand_info->read_cache_cmd_4;
689ba0501acSDingqiang Lin 		}
690ba0501acSDingqiang Lin 	}
691ba0501acSDingqiang Lin 
692ba0501acSDingqiang Lin 	if (p_nand_info->feature & FEA_4BIT_PROG &&
693ba0501acSDingqiang Lin 	    sfc_nand_dev.read_lines == DATA_LINES_X4) {
694ba0501acSDingqiang Lin 		sfc_nand_dev.prog_lines = DATA_LINES_X4;
695ba0501acSDingqiang Lin 		sfc_nand_dev.page_prog_cmd = p_nand_info->prog_cache_cmd_4;
696ba0501acSDingqiang Lin 	}
697ba0501acSDingqiang Lin 
698ba0501acSDingqiang Lin 	if (1) {
699ba0501acSDingqiang Lin 		u8 status;
700ba0501acSDingqiang Lin 
701ba0501acSDingqiang Lin 		sfc_nand_read_feature(0xA0, &status);
702ba0501acSDingqiang Lin 		PRINT_SFC_I("sfc_nand A0 = 0x%x\n", status);
703ba0501acSDingqiang Lin 		sfc_nand_read_feature(0xB0, &status);
704ba0501acSDingqiang Lin 		PRINT_SFC_I("sfc_nand B0 = 0x%x\n", status);
705ba0501acSDingqiang Lin 		sfc_nand_read_feature(0xC0, &status);
706ba0501acSDingqiang Lin 		PRINT_SFC_I("sfc_nand C0 = 0x%x\n", status);
707ba0501acSDingqiang Lin 		PRINT_SFC_I("read_lines = %x\n", sfc_nand_dev.read_lines);
708ba0501acSDingqiang Lin 		PRINT_SFC_I("prog_lines = %x\n", sfc_nand_dev.prog_lines);
709ba0501acSDingqiang Lin 		PRINT_SFC_I("page_read_cmd = %x\n", sfc_nand_dev.page_read_cmd);
710ba0501acSDingqiang Lin 		PRINT_SFC_I("page_prog_cmd = %x\n", sfc_nand_dev.page_prog_cmd);
711ba0501acSDingqiang Lin 	}
712ba0501acSDingqiang Lin 	ftl_flash_init();
713ba0501acSDingqiang Lin 
714ba0501acSDingqiang Lin 	#if SFC_NAND_STRESS_TEST_EN
715ba0501acSDingqiang Lin 	sfc_nand_test();
716ba0501acSDingqiang Lin 	#endif
717ba0501acSDingqiang Lin 
718ba0501acSDingqiang Lin 	return SFC_OK;
719ba0501acSDingqiang Lin }
720ba0501acSDingqiang Lin 
721ba0501acSDingqiang Lin int sfc_nand_read_id(u8 *data)
722ba0501acSDingqiang Lin {
723ba0501acSDingqiang Lin 	memcpy(data, id_byte, 3);
724ba0501acSDingqiang Lin 	return 0;
725ba0501acSDingqiang Lin }
726