xref: /rk3399_rockchip-uboot/drivers/rkflash/sfc_nand.c (revision b833c879cf982d487a089dbdfde83349ecf6b0be)
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 
17f28847a8SJon Lin static u32 sfc_nand_get_ecc_status0(void);
18f28847a8SJon Lin static u32 sfc_nand_get_ecc_status1(void);
19f28847a8SJon Lin static u32 sfc_nand_get_ecc_status2(void);
20f28847a8SJon Lin static u32 sfc_nand_get_ecc_status3(void);
21f28847a8SJon Lin static u32 sfc_nand_get_ecc_status4(void);
22f28847a8SJon Lin static u32 sfc_nand_get_ecc_status5(void);
23f28847a8SJon Lin static u32 sfc_nand_get_ecc_status6(void);
24f28847a8SJon Lin 
25ba0501acSDingqiang Lin static struct nand_info spi_nand_tbl[] = {
26ba0501acSDingqiang Lin 	/* TC58CVG0S0HxAIx */
27*b833c879SJon Lin 	{ 0x98, 0xC2, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
28ba0501acSDingqiang Lin 	/* TC58CVG1S0HxAIx */
29*b833c879SJon Lin 	{ 0x98, 0xCB, 0x00, 4, 0x40, 2, 1024, 0x00, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
30a6fcac41SJon Lin 	/* TC58CVG2S0HRAIJ */
31*b833c879SJon Lin 	{ 0x98, 0xED, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 0, { 0x04, 0x0C, 0x08, 0x10 }, &sfc_nand_get_ecc_status0 },
32a6fcac41SJon Lin 	/* TC58CVG1S3HRAIJ */
33*b833c879SJon Lin 	{ 0x98, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
34a6fcac41SJon Lin 	/* TC58CVG0S3HRAIJ */
35*b833c879SJon Lin 	{ 0x98, 0xE2, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
36f28847a8SJon Lin 
37f28847a8SJon Lin 	/* MX35LF1GE4AB */
38*b833c879SJon Lin 	{ 0xC2, 0x12, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
39f28847a8SJon Lin 	/* MX35LF2GE4AB */
40*b833c879SJon Lin 	{ 0xC2, 0x22, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
41f28847a8SJon Lin 	/* MX35LF2GE4AD */
42*b833c879SJon Lin 	{ 0xC2, 0x26, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
43f28847a8SJon Lin 	/* MX35LF4GE4AD */
44*b833c879SJon Lin 	{ 0xC2, 0x37, 0x00, 8, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status0 },
45f28847a8SJon Lin 	/* MT29F1G01ZAC */
46*b833c879SJon Lin 	{ 0x2C, 0x12, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
47f28847a8SJon Lin 
48f28847a8SJon Lin 	/* GD5F1GQ4UAYIG */
49*b833c879SJon Lin 	{ 0xC8, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
50f28847a8SJon Lin 	/* GD5F1GQ4RB9IGR */
51*b833c879SJon Lin 	{ 0xC8, 0xD1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
52f28847a8SJon Lin 	/* GD5F2GQ40BY2GR */
53*b833c879SJon Lin 	{ 0xC8, 0xD2, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
54f28847a8SJon Lin 	/* GD5F1GQ5UEYIG */
55*b833c879SJon Lin 	{ 0xC8, 0x51, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
56f28847a8SJon Lin 	/* GD5F2GQ5UEYIG */
57*b833c879SJon Lin 	{ 0xC8, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
58f28847a8SJon Lin 	/* GD5F1GQ4R */
59*b833c879SJon Lin 	{ 0xC8, 0xC1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
60f28847a8SJon Lin 
61f28847a8SJon Lin 	/* W25N01GV */
62*b833c879SJon Lin 	{ 0xEF, 0xAA, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 },
63*b833c879SJon Lin 	/* W25N02KVZEIR */
64*b833c879SJon Lin 	{ 0xEF, 0xAA, 0x22, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status0 },
65f28847a8SJon Lin 	/* W25N01GW */
66*b833c879SJon Lin 	{ 0xEF, 0xBA, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 },
67f28847a8SJon Lin 
68f28847a8SJon Lin 	/* HYF2GQ4UAACAE */
69*b833c879SJon Lin 	{ 0xC9, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
70f28847a8SJon Lin 	/* HYF1GQ4UDACAE */
71*b833c879SJon Lin 	{ 0xC9, 0x21, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
72f28847a8SJon Lin 	/* HYF1GQ4UPACAE */
73*b833c879SJon Lin 	{ 0xC9, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
74f28847a8SJon Lin 	/* HYF2GQ4UDACAE */
75*b833c879SJon Lin 	{ 0xC9, 0x22, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
76f28847a8SJon Lin 	/* HYF2GQ4UHCCAE */
77*b833c879SJon Lin 	{ 0xC9, 0x5A, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
78f28847a8SJon Lin 	/* HYF4GQ4UAACBE */
79*b833c879SJon Lin 	{ 0xC9, 0xD4, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x4, 1, { 0x20, 0x40, 0x24, 0x44 }, &sfc_nand_get_ecc_status0 },
80f28847a8SJon Lin 
81f28847a8SJon Lin 	/* FS35ND01G-S1 */
82*b833c879SJon Lin 	{ 0xCD, 0xB1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
83f28847a8SJon Lin 	/* FS35ND02G-S2 */
84*b833c879SJon Lin 	{ 0xCD, 0xA2, 0x00, 4, 0x40, 1, 2048, 0x00, 19, 0x4, 0, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
8558463f4dSJon Lin 	/* FS35ND01G-S1Y2 */
86*b833c879SJon Lin 	{ 0xCD, 0xEA, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
87f1b20f5aSJon Lin 	/* FS35ND02G-S3Y2 */
88*b833c879SJon Lin 	{ 0xCD, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
89f28847a8SJon Lin 	/* FS35ND04G-S2Y2 1*4096 */
90*b833c879SJon Lin 	{ 0xCD, 0xEC, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
91f28847a8SJon Lin 
92f28847a8SJon Lin 	/* DS35Q1GA-IB */
93*b833c879SJon Lin 	{ 0xE5, 0x71, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
94f28847a8SJon Lin 	/* DS35Q2GA-IB */
95*b833c879SJon Lin 	{ 0xE5, 0x72, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
96f28847a8SJon Lin 	/* DS35M1GA-1B */
97*b833c879SJon Lin 	{ 0xE5, 0x21, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
98f28847a8SJon Lin 
99f28847a8SJon Lin 	/* EM73C044VCC-H */
100*b833c879SJon Lin 	{ 0xD5, 0x22, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
101f28847a8SJon Lin 	/* EM73D044VCE-H */
102*b833c879SJon Lin 	{ 0xD5, 0x20, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
103f28847a8SJon Lin 	/* EM73E044SNA-G */
104*b833c879SJon Lin 	{ 0xD5, 0x03, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x28, 0x08, 0x2C }, &sfc_nand_get_ecc_status0 },
105f28847a8SJon Lin 
106f28847a8SJon Lin 	/* XT26G02A */
107*b833c879SJon Lin 	{ 0x0B, 0xE2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x1, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
108f28847a8SJon Lin 	/* XT26G01A */
109*b833c879SJon Lin 	{ 0x0B, 0xE1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
110f28847a8SJon Lin 	/* XT26G04A */
111*b833c879SJon Lin 	{ 0x0B, 0xE3, 0x00, 4, 0x80, 1, 2048, 0x4C, 20, 0x1, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
112f28847a8SJon Lin 	/* XT26G01B */
113*b833c879SJon Lin 	{ 0x0B, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
114f28847a8SJon Lin 	/* XT26G02B */
115*b833c879SJon Lin 	{ 0x0B, 0xF2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x1, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
116a80fd396SJon Lin 
117a80fd396SJon Lin 	/* MT29F2G1ABA, XT26G02E, F50L2G41XA */
118*b833c879SJon Lin 	{ 0x2C, 0x24, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x1, 1, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
119a80fd396SJon Lin 
120a80fd396SJon Lin 	/* FM25S01 */
121*b833c879SJon Lin 	{ 0xA1, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x00, 0x04, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
122a80fd396SJon Lin 	/* FM25S01A */
123*b833c879SJon Lin 	{ 0xA1, 0xE4, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
124a80fd396SJon Lin 	/* FM25S02A */
125*b833c879SJon Lin 	{ 0xA1, 0xE5, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
126f28847a8SJon Lin 
127f28847a8SJon Lin 	/* IS37SML01G1 */
128*b833c879SJon Lin 	{ 0xC8, 0x21, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x1, 0, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
129f28847a8SJon Lin 	/* F50L1G41LB */
130*b833c879SJon Lin 	{ 0xC8, 0x01, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
131f28847a8SJon Lin 	/* ATO25D1GA */
132*b833c879SJon Lin 	{ 0x9B, 0x12, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x1, 1, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
133ba0501acSDingqiang Lin };
134ba0501acSDingqiang Lin 
135ba0501acSDingqiang Lin static struct nand_info *p_nand_info;
136ba0501acSDingqiang Lin static u32 gp_page_buf[SFC_NAND_PAGE_MAX_SIZE / 4];
137ba0501acSDingqiang Lin static struct SFNAND_DEV sfc_nand_dev;
138ba0501acSDingqiang Lin 
139a6fcac41SJon Lin static struct nand_info *sfc_nand_get_info(u8 *nand_id)
140ba0501acSDingqiang Lin {
141ba0501acSDingqiang Lin 	u32 i;
142ba0501acSDingqiang Lin 
143ba0501acSDingqiang Lin 	for (i = 0; i < ARRAY_SIZE(spi_nand_tbl); i++) {
144*b833c879SJon Lin 		if (spi_nand_tbl[i].id0 == nand_id[0] &&
145*b833c879SJon Lin 		    spi_nand_tbl[i].id1 == nand_id[1]) {
146*b833c879SJon Lin 			if (spi_nand_tbl[i].id2 &&
147*b833c879SJon Lin 			    spi_nand_tbl[i].id2 != nand_id[2])
148*b833c879SJon Lin 				continue;
149*b833c879SJon Lin 
150ba0501acSDingqiang Lin 			return &spi_nand_tbl[i];
151ba0501acSDingqiang Lin 		}
152*b833c879SJon Lin 	}
153f28847a8SJon Lin 
154ba0501acSDingqiang Lin 	return NULL;
155ba0501acSDingqiang Lin }
156ba0501acSDingqiang Lin 
157ba0501acSDingqiang Lin static int sfc_nand_write_en(void)
158ba0501acSDingqiang Lin {
159ba0501acSDingqiang Lin 	int ret;
16058463f4dSJon Lin 	struct rk_sfc_op op;
161ba0501acSDingqiang Lin 
16258463f4dSJon Lin 	op.sfcmd.d32 = 0;
16358463f4dSJon Lin 	op.sfcmd.b.cmd = CMD_WRITE_EN;
16458463f4dSJon Lin 
16558463f4dSJon Lin 	op.sfctrl.d32 = 0;
16658463f4dSJon Lin 
16758463f4dSJon Lin 	ret = sfc_request(&op, 0, NULL, 0);
168ba0501acSDingqiang Lin 	return ret;
169ba0501acSDingqiang Lin }
170ba0501acSDingqiang Lin 
171ba0501acSDingqiang Lin static int sfc_nand_rw_preset(void)
172ba0501acSDingqiang Lin {
173ba0501acSDingqiang Lin 	int ret;
17458463f4dSJon Lin 	struct rk_sfc_op op;
175ba0501acSDingqiang Lin 
17658463f4dSJon Lin 	op.sfcmd.d32 = 0;
177f28847a8SJon Lin 	op.sfcmd.b.cmd = 0xff;
178f28847a8SJon Lin 	op.sfcmd.b.cs = 2;
179ba0501acSDingqiang Lin 
18058463f4dSJon Lin 	op.sfctrl.d32 = 0;
18158463f4dSJon Lin 	op.sfctrl.b.datalines = 2;
182f28847a8SJon Lin 	op.sfctrl.b.cmdlines = 2;
183f28847a8SJon Lin 	op.sfctrl.b.addrlines = 2;
18458463f4dSJon Lin 
185f28847a8SJon Lin 	ret = sfc_request(&op, 0, NULL, 0);
186ba0501acSDingqiang Lin 	return ret;
187ba0501acSDingqiang Lin }
188ba0501acSDingqiang Lin 
189ba0501acSDingqiang Lin static int sfc_nand_read_feature(u8 addr, u8 *data)
190ba0501acSDingqiang Lin {
191ba0501acSDingqiang Lin 	int ret;
19258463f4dSJon Lin 	struct rk_sfc_op op;
193ba0501acSDingqiang Lin 
19458463f4dSJon Lin 	op.sfcmd.d32 = 0;
19558463f4dSJon Lin 	op.sfcmd.b.cmd = 0x0F;
19658463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
19758463f4dSJon Lin 
19858463f4dSJon Lin 	op.sfctrl.d32 = 0;
19958463f4dSJon Lin 	op.sfctrl.b.addrbits = 8;
20058463f4dSJon Lin 
201ba0501acSDingqiang Lin 	*data = 0;
202ba0501acSDingqiang Lin 
20358463f4dSJon Lin 	ret = sfc_request(&op, addr, data, 1);
204f28847a8SJon Lin 
205ba0501acSDingqiang Lin 	if (ret != SFC_OK)
206ba0501acSDingqiang Lin 		return ret;
207f28847a8SJon Lin 
208ba0501acSDingqiang Lin 	return SFC_OK;
209ba0501acSDingqiang Lin }
210ba0501acSDingqiang Lin 
211ba0501acSDingqiang Lin static int sfc_nand_write_feature(u32 addr, u8 status)
212ba0501acSDingqiang Lin {
213ba0501acSDingqiang Lin 	int ret;
21458463f4dSJon Lin 	struct rk_sfc_op op;
215ba0501acSDingqiang Lin 
216ba0501acSDingqiang Lin 	sfc_nand_write_en();
217ba0501acSDingqiang Lin 
21858463f4dSJon Lin 	op.sfcmd.d32 = 0;
21958463f4dSJon Lin 	op.sfcmd.b.cmd = 0x1F;
22058463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
22158463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
222ba0501acSDingqiang Lin 
22358463f4dSJon Lin 	op.sfctrl.d32 = 0;
22458463f4dSJon Lin 	op.sfctrl.b.addrbits = 8;
22558463f4dSJon Lin 
22658463f4dSJon Lin 	ret = sfc_request(&op, addr, &status, 1);
227f28847a8SJon Lin 
228ba0501acSDingqiang Lin 	if (ret != SFC_OK)
229ba0501acSDingqiang Lin 		return ret;
230f28847a8SJon Lin 
231ba0501acSDingqiang Lin 	return ret;
232ba0501acSDingqiang Lin }
233ba0501acSDingqiang Lin 
234ba0501acSDingqiang Lin static int sfc_nand_wait_busy(u8 *data, int timeout)
235ba0501acSDingqiang Lin {
236ba0501acSDingqiang Lin 	int ret;
237ba0501acSDingqiang Lin 	int i;
238ba0501acSDingqiang Lin 	u8 status;
239ba0501acSDingqiang Lin 
240ba0501acSDingqiang Lin 	*data = 0;
241f28847a8SJon Lin 
242ba0501acSDingqiang Lin 	for (i = 0; i < timeout; i++) {
243ba0501acSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
244f28847a8SJon Lin 
245ba0501acSDingqiang Lin 		if (ret != SFC_OK)
246ba0501acSDingqiang Lin 			return ret;
247f28847a8SJon Lin 
248ba0501acSDingqiang Lin 		*data = status;
249f28847a8SJon Lin 
250ba0501acSDingqiang Lin 		if (!(status & (1 << 0)))
251ba0501acSDingqiang Lin 			return SFC_OK;
252f28847a8SJon Lin 
253ba0501acSDingqiang Lin 		sfc_delay(1);
254ba0501acSDingqiang Lin 	}
255f28847a8SJon Lin 
256f28847a8SJon Lin 	return SFC_NAND_WAIT_TIME_OUT;
257ba0501acSDingqiang Lin }
258ba0501acSDingqiang Lin 
2596281205aSDingqiang Lin /*
2606281205aSDingqiang Lin  * ecc default:
261a6fcac41SJon Lin  * ecc bits: 0xC0[4,5]
262f28847a8SJon Lin  * 0b00, No bit errors were detected
263f28847a8SJon Lin  * 0b01, Bit errors were detected and corrected.
264f28847a8SJon Lin  * 0b10, Multiple bit errors were detected and not corrected.
265f28847a8SJon Lin  * 0b11, Bits errors were detected and corrected, bit error count
2666281205aSDingqiang Lin  *	exceed the bit flip detection threshold
2676281205aSDingqiang Lin  */
268f28847a8SJon Lin static u32 sfc_nand_get_ecc_status0(void)
2696281205aSDingqiang Lin {
27058463f4dSJon Lin 	u32 ret;
2716281205aSDingqiang Lin 	u32 i;
2726281205aSDingqiang Lin 	u8 ecc;
2736281205aSDingqiang Lin 	u8 status;
2746281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
2756281205aSDingqiang Lin 
2766281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
2776281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
278f28847a8SJon Lin 
2796281205aSDingqiang Lin 		if (ret != SFC_OK)
2806281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
281f28847a8SJon Lin 
2826281205aSDingqiang Lin 		if (!(status & (1 << 0)))
2836281205aSDingqiang Lin 			break;
284f28847a8SJon Lin 
2856281205aSDingqiang Lin 		sfc_delay(1);
2866281205aSDingqiang Lin 	}
2876281205aSDingqiang Lin 
2886281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
2896281205aSDingqiang Lin 
2906281205aSDingqiang Lin 	if (ecc <= 1)
2916281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
2926281205aSDingqiang Lin 	else if (ecc == 2)
29358463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
2946281205aSDingqiang Lin 	else
2956281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
2966281205aSDingqiang Lin 
2976281205aSDingqiang Lin 	return ret;
2986281205aSDingqiang Lin }
2996281205aSDingqiang Lin 
3006281205aSDingqiang Lin /*
3016281205aSDingqiang Lin  * ecc spectial type1:
302a6fcac41SJon Lin  * ecc bits: 0xC0[4,5]
303f28847a8SJon Lin  * 0b00, No bit errors were detected;
304f28847a8SJon Lin  * 0b01, Bits errors were detected and corrected, bit error count
3056281205aSDingqiang Lin  *	may reach the bit flip detection threshold;
306f28847a8SJon Lin  * 0b10, Multiple bit errors were detected and not corrected;
307f28847a8SJon Lin  * 0b11, Reserved.
3086281205aSDingqiang Lin  */
309f28847a8SJon Lin static u32 sfc_nand_get_ecc_status1(void)
3106281205aSDingqiang Lin {
31158463f4dSJon Lin 	u32 ret;
3126281205aSDingqiang Lin 	u32 i;
3136281205aSDingqiang Lin 	u8 ecc;
3146281205aSDingqiang Lin 	u8 status;
3156281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
3166281205aSDingqiang Lin 
3176281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
3186281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
319f28847a8SJon Lin 
3206281205aSDingqiang Lin 		if (ret != SFC_OK)
3216281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
322f28847a8SJon Lin 
3236281205aSDingqiang Lin 		if (!(status & (1 << 0)))
3246281205aSDingqiang Lin 			break;
325f28847a8SJon Lin 
3266281205aSDingqiang Lin 		sfc_delay(1);
3276281205aSDingqiang Lin 	}
3286281205aSDingqiang Lin 
3296281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
3306281205aSDingqiang Lin 
3316281205aSDingqiang Lin 	if (ecc == 0)
3326281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
3336281205aSDingqiang Lin 	else if (ecc == 1)
3346281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
3356281205aSDingqiang Lin 	else
33658463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
3376281205aSDingqiang Lin 
3386281205aSDingqiang Lin 	return ret;
3396281205aSDingqiang Lin }
3406281205aSDingqiang Lin 
3416281205aSDingqiang Lin /*
342d9cdd318SJon Lin  * ecc spectial type2:
343a6fcac41SJon Lin  * ecc bits: 0xC0[4,5] 0xF0[4,5]
344f28847a8SJon Lin  * [0b0000, 0b0011], No bit errors were detected;
345f28847a8SJon Lin  * [0b0100, 0b0111], Bit errors were detected and corrected. Not
346d9cdd318SJon Lin  *	reach Flipping Bits;
347f28847a8SJon Lin  * [0b1000, 0b1011], Multiple bit errors were detected and
348c84f0ed8SJon Lin  *	not corrected.
349f28847a8SJon Lin  * [0b1100, 0b1111], reserved.
350d9cdd318SJon Lin  */
351f28847a8SJon Lin static u32 sfc_nand_get_ecc_status2(void)
352d9cdd318SJon Lin {
35358463f4dSJon Lin 	u32 ret;
354d9cdd318SJon Lin 	u32 i;
355d9cdd318SJon Lin 	u8 ecc;
356d9cdd318SJon Lin 	u8 status, status1;
357d9cdd318SJon Lin 	u32 timeout = 1000 * 1000;
358d9cdd318SJon Lin 
359d9cdd318SJon Lin 	for (i = 0; i < timeout; i++) {
360d9cdd318SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
361f28847a8SJon Lin 
362d9cdd318SJon Lin 		if (ret != SFC_OK)
363d9cdd318SJon Lin 			return SFC_NAND_ECC_ERROR;
364f28847a8SJon Lin 
365d9cdd318SJon Lin 		ret = sfc_nand_read_feature(0xF0, &status1);
366f28847a8SJon Lin 
367d9cdd318SJon Lin 		if (ret != SFC_OK)
368d9cdd318SJon Lin 			return SFC_NAND_ECC_ERROR;
369f28847a8SJon Lin 
370d9cdd318SJon Lin 		if (!(status & (1 << 0)))
371d9cdd318SJon Lin 			break;
372f28847a8SJon Lin 
373d9cdd318SJon Lin 		sfc_delay(1);
374d9cdd318SJon Lin 	}
375d9cdd318SJon Lin 
376d9cdd318SJon Lin 	ecc = (status >> 4) & 0x03;
377d9cdd318SJon Lin 	ecc = (ecc << 2) | ((status1 >> 4) & 0x03);
378f28847a8SJon Lin 
379d9cdd318SJon Lin 	if (ecc < 7)
380d9cdd318SJon Lin 		ret = SFC_NAND_ECC_OK;
381d9cdd318SJon Lin 	else if (ecc == 7)
382d9cdd318SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
383d9cdd318SJon Lin 	else
38458463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
385d9cdd318SJon Lin 
386d9cdd318SJon Lin 	return ret;
387d9cdd318SJon Lin }
388d9cdd318SJon Lin 
389d9cdd318SJon Lin /*
3906281205aSDingqiang Lin  * ecc spectial type3:
391a6fcac41SJon Lin  * ecc bits: 0xC0[4,5] 0xF0[4,5]
392f28847a8SJon Lin  * [0b0000, 0b0011], No bit errors were detected;
393f28847a8SJon Lin  * [0b0100, 0b0111], Bit errors were detected and corrected. Not
3946281205aSDingqiang Lin  *	reach Flipping Bits;
395f28847a8SJon Lin  * [0b1000, 0b1011], Multiple bit errors were detected and
3966281205aSDingqiang Lin  *	not corrected.
397f28847a8SJon Lin  * [0b1100, 0b1111], Bit error count equals the bit flip
3986281205aSDingqiang Lin  *	detectio nthreshold
3996281205aSDingqiang Lin  */
400f28847a8SJon Lin static u32 sfc_nand_get_ecc_status3(void)
4016281205aSDingqiang Lin {
40258463f4dSJon Lin 	u32 ret;
4036281205aSDingqiang Lin 	u32 i;
4046281205aSDingqiang Lin 	u8 ecc;
4056281205aSDingqiang Lin 	u8 status, status1;
4066281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
4076281205aSDingqiang Lin 
4086281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
4096281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
410f28847a8SJon Lin 
4116281205aSDingqiang Lin 		if (ret != SFC_OK)
4126281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
413f28847a8SJon Lin 
4146281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xF0, &status1);
415f28847a8SJon Lin 
4166281205aSDingqiang Lin 		if (ret != SFC_OK)
4176281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
418f28847a8SJon Lin 
4196281205aSDingqiang Lin 		if (!(status & (1 << 0)))
4206281205aSDingqiang Lin 			break;
421f28847a8SJon Lin 
4226281205aSDingqiang Lin 		sfc_delay(1);
4236281205aSDingqiang Lin 	}
4246281205aSDingqiang Lin 
4256281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
4266281205aSDingqiang Lin 	ecc = (ecc << 2) | ((status1 >> 4) & 0x03);
427f28847a8SJon Lin 
4286281205aSDingqiang Lin 	if (ecc < 7)
4296281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
4306281205aSDingqiang Lin 	else if (ecc == 7 || ecc >= 12)
4316281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
4326281205aSDingqiang Lin 	else
43358463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
4346281205aSDingqiang Lin 
4356281205aSDingqiang Lin 	return ret;
4366281205aSDingqiang Lin }
4376281205aSDingqiang Lin 
43825098c06SDingqiang Lin /*
43925098c06SDingqiang Lin  * ecc spectial type4:
440a6fcac41SJon Lin  * ecc bits: 0xC0[2,5]
441f28847a8SJon Lin  * [0b0000], No bit errors were detected;
442f28847a8SJon Lin  * [0b0001, 0b0111], Bit errors were detected and corrected. Not
44325098c06SDingqiang Lin  *	reach Flipping Bits;
444f28847a8SJon Lin  * [0b1000], Multiple bit errors were detected and
44525098c06SDingqiang Lin  *	not corrected.
446f28847a8SJon Lin  * [0b1100], Bit error count equals the bit flip
44725098c06SDingqiang Lin  *	detectionthreshold
44825098c06SDingqiang Lin  * else, reserved
44925098c06SDingqiang Lin  */
450f28847a8SJon Lin static u32 sfc_nand_get_ecc_status4(void)
45125098c06SDingqiang Lin {
45258463f4dSJon Lin 	u32 ret;
45325098c06SDingqiang Lin 	u32 i;
45425098c06SDingqiang Lin 	u8 ecc;
45525098c06SDingqiang Lin 	u8 status;
45625098c06SDingqiang Lin 	u32 timeout = 1000 * 1000;
45725098c06SDingqiang Lin 
45825098c06SDingqiang Lin 	for (i = 0; i < timeout; i++) {
45925098c06SDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
460f28847a8SJon Lin 
46125098c06SDingqiang Lin 		if (ret != SFC_OK)
46225098c06SDingqiang Lin 			return SFC_NAND_ECC_ERROR;
463f28847a8SJon Lin 
46425098c06SDingqiang Lin 		if (!(status & (1 << 0)))
46525098c06SDingqiang Lin 			break;
466f28847a8SJon Lin 
46725098c06SDingqiang Lin 		sfc_delay(1);
46825098c06SDingqiang Lin 	}
46925098c06SDingqiang Lin 
47025098c06SDingqiang Lin 	ecc = (status >> 2) & 0x0f;
471f28847a8SJon Lin 
47225098c06SDingqiang Lin 	if (ecc < 7)
47325098c06SDingqiang Lin 		ret = SFC_NAND_ECC_OK;
47425098c06SDingqiang Lin 	else if (ecc == 7 || ecc == 12)
47525098c06SDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
47625098c06SDingqiang Lin 	else
47758463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
47825098c06SDingqiang Lin 
47925098c06SDingqiang Lin 	return ret;
48025098c06SDingqiang Lin }
48125098c06SDingqiang Lin 
48225098c06SDingqiang Lin /*
48325098c06SDingqiang Lin  * ecc spectial type5:
484a6fcac41SJon Lin  * ecc bits: 0xC0[4,6]
485f28847a8SJon Lin  * [0b000], No bit errors were detected;
486f28847a8SJon Lin  * [0b001, 0b011], Bit errors were detected and corrected. Not
48725098c06SDingqiang Lin  *	reach Flipping Bits;
488f28847a8SJon Lin  * [0b100], Bit error count equals the bit flip
48925098c06SDingqiang Lin  *	detectionthreshold
490f28847a8SJon Lin  * [0b101, 0b110], Reserved;
491f28847a8SJon Lin  * [0b111], Multiple bit errors were detected and
49225098c06SDingqiang Lin  *	not corrected.
49325098c06SDingqiang Lin  */
494f28847a8SJon Lin static u32 sfc_nand_get_ecc_status5(void)
49525098c06SDingqiang Lin {
49658463f4dSJon Lin 	u32 ret;
49725098c06SDingqiang Lin 	u32 i;
49825098c06SDingqiang Lin 	u8 ecc;
49925098c06SDingqiang Lin 	u8 status;
50025098c06SDingqiang Lin 	u32 timeout = 1000 * 1000;
50125098c06SDingqiang Lin 
50225098c06SDingqiang Lin 	for (i = 0; i < timeout; i++) {
50325098c06SDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
504f28847a8SJon Lin 
50525098c06SDingqiang Lin 		if (ret != SFC_OK)
50625098c06SDingqiang Lin 			return SFC_NAND_ECC_ERROR;
507f28847a8SJon Lin 
50825098c06SDingqiang Lin 		if (!(status & (1 << 0)))
50925098c06SDingqiang Lin 			break;
510f28847a8SJon Lin 
51125098c06SDingqiang Lin 		sfc_delay(1);
51225098c06SDingqiang Lin 	}
51325098c06SDingqiang Lin 
51425098c06SDingqiang Lin 	ecc = (status >> 4) & 0x07;
515f28847a8SJon Lin 
51625098c06SDingqiang Lin 	if (ecc < 4)
51725098c06SDingqiang Lin 		ret = SFC_NAND_ECC_OK;
51825098c06SDingqiang Lin 	else if (ecc == 4)
51925098c06SDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
52025098c06SDingqiang Lin 	else
52158463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
52225098c06SDingqiang Lin 
52325098c06SDingqiang Lin 	return ret;
52425098c06SDingqiang Lin }
52525098c06SDingqiang Lin 
526f28847a8SJon Lin /*
527f28847a8SJon Lin  * ecc spectial type6:
528f28847a8SJon Lin  * ecc bits: 0xC0[4,6]
529f28847a8SJon Lin  * [0b000], No bit errors were detected;
530f28847a8SJon Lin  * [0b001], 1-3 Bit errors were detected and corrected. Not
531f28847a8SJon Lin  *	reach Flipping Bits;
532f28847a8SJon Lin  * [0b010], Multiple bit errors were detected and
533f28847a8SJon Lin  *	not corrected.
534f28847a8SJon Lin  * [0b011], 4-6 Bit errors were detected and corrected. Not
535f28847a8SJon Lin  *	reach Flipping Bits;
536f28847a8SJon Lin  * [0b101], Bit error count equals the bit flip
537f28847a8SJon Lin  *	detectionthreshold
538f28847a8SJon Lin  * others, Reserved.
539f28847a8SJon Lin  */
540f28847a8SJon Lin static u32 sfc_nand_get_ecc_status6(void)
541f28847a8SJon Lin {
542f28847a8SJon Lin 	u32 ret;
543f28847a8SJon Lin 	u32 i;
544f28847a8SJon Lin 	u8 ecc;
545f28847a8SJon Lin 	u8 status;
546f28847a8SJon Lin 	u32 timeout = 1000 * 1000;
547f28847a8SJon Lin 
548f28847a8SJon Lin 	for (i = 0; i < timeout; i++) {
549f28847a8SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
550f28847a8SJon Lin 
551f28847a8SJon Lin 		if (ret != SFC_OK)
552f28847a8SJon Lin 			return SFC_NAND_ECC_ERROR;
553f28847a8SJon Lin 
554f28847a8SJon Lin 		if (!(status & (1 << 0)))
555f28847a8SJon Lin 			break;
556f28847a8SJon Lin 
557f28847a8SJon Lin 		sfc_delay(1);
558f28847a8SJon Lin 	}
559f28847a8SJon Lin 
560f28847a8SJon Lin 	ecc = (status >> 4) & 0x07;
561f28847a8SJon Lin 
562f28847a8SJon Lin 	if (ecc == 0 || ecc == 1 || ecc == 3)
563f28847a8SJon Lin 		ret = SFC_NAND_ECC_OK;
564f28847a8SJon Lin 	else if (ecc == 5)
565f28847a8SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
566f28847a8SJon Lin 	else
567f28847a8SJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
568f28847a8SJon Lin 
569f28847a8SJon Lin 	return ret;
570f28847a8SJon Lin }
571f28847a8SJon Lin 
572c84f0ed8SJon Lin u32 sfc_nand_erase_block(u8 cs, u32 addr)
573ba0501acSDingqiang Lin {
574ba0501acSDingqiang Lin 	int ret;
57558463f4dSJon Lin 	struct rk_sfc_op op;
576ba0501acSDingqiang Lin 	u8 status;
577ba0501acSDingqiang Lin 
578c84f0ed8SJon Lin 	rkflash_print_dio("%s %x\n", __func__, addr);
57958463f4dSJon Lin 	op.sfcmd.d32 = 0;
580f28847a8SJon Lin 	op.sfcmd.b.cmd = 0xd8;
58158463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_24BITS;
58258463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
58358463f4dSJon Lin 
58458463f4dSJon Lin 	op.sfctrl.d32 = 0;
58558463f4dSJon Lin 
586ba0501acSDingqiang Lin 	sfc_nand_write_en();
58758463f4dSJon Lin 	ret = sfc_request(&op, addr, NULL, 0);
588f28847a8SJon Lin 
589ba0501acSDingqiang Lin 	if (ret != SFC_OK)
590ba0501acSDingqiang Lin 		return ret;
591f28847a8SJon Lin 
592ba0501acSDingqiang Lin 	ret = sfc_nand_wait_busy(&status, 1000 * 1000);
593f28847a8SJon Lin 
594ba0501acSDingqiang Lin 	if (status & (1 << 2))
595ba0501acSDingqiang Lin 		return SFC_NAND_PROG_ERASE_ERROR;
596c84f0ed8SJon Lin 
597ba0501acSDingqiang Lin 	return ret;
598ba0501acSDingqiang Lin }
599ba0501acSDingqiang Lin 
600f28847a8SJon Lin u32 sfc_nand_prog_page_raw(u8 cs, u32 addr, u32 *p_page_buf)
601ba0501acSDingqiang Lin {
602ba0501acSDingqiang Lin 	int ret;
603415cf080Sjon.lin 	u32 plane;
60458463f4dSJon Lin 	struct rk_sfc_op op;
605ba0501acSDingqiang Lin 	u8 status;
60658463f4dSJon Lin 	u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page;
607ba0501acSDingqiang Lin 
608c84f0ed8SJon Lin 	rkflash_print_dio("%s %x %x\n", __func__, addr, p_page_buf[0]);
609ba0501acSDingqiang Lin 	sfc_nand_write_en();
610f28847a8SJon Lin 
611ba0501acSDingqiang Lin 	if (sfc_nand_dev.prog_lines == DATA_LINES_X4 &&
61225098c06SDingqiang Lin 	    p_nand_info->feature & FEA_SOFT_QOP_BIT &&
61325098c06SDingqiang Lin 	    sfc_get_version() < SFC_VER_3)
614ba0501acSDingqiang Lin 		sfc_nand_rw_preset();
615ba0501acSDingqiang Lin 
61658463f4dSJon Lin 	op.sfcmd.d32 = 0;
61758463f4dSJon Lin 	op.sfcmd.b.cmd = sfc_nand_dev.page_prog_cmd;
61858463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
61958463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
620ba0501acSDingqiang Lin 
62158463f4dSJon Lin 	op.sfctrl.d32 = 0;
62258463f4dSJon Lin 	op.sfctrl.b.datalines = sfc_nand_dev.prog_lines;
62358463f4dSJon Lin 	op.sfctrl.b.addrbits = 16;
624415cf080Sjon.lin 	plane = p_nand_info->plane_per_die == 2 ? ((addr >> 6) & 0x1) << 12 : 0;
62558463f4dSJon Lin 	sfc_request(&op, plane, p_page_buf, page_size);
626ba0501acSDingqiang Lin 
62758463f4dSJon Lin 	op.sfcmd.d32 = 0;
628f28847a8SJon Lin 	op.sfcmd.b.cmd = 0x10;
62958463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_24BITS;
63058463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
63158463f4dSJon Lin 
63258463f4dSJon Lin 	op.sfctrl.d32 = 0;
63358463f4dSJon Lin 	ret = sfc_request(&op, addr, p_page_buf, 0);
634f28847a8SJon Lin 
635ba0501acSDingqiang Lin 	if (ret != SFC_OK)
636ba0501acSDingqiang Lin 		return ret;
637f28847a8SJon Lin 
638ba0501acSDingqiang Lin 	ret = sfc_nand_wait_busy(&status, 1000 * 1000);
639f28847a8SJon Lin 
640ba0501acSDingqiang Lin 	if (status & (1 << 3))
641ba0501acSDingqiang Lin 		return SFC_NAND_PROG_ERASE_ERROR;
642c84f0ed8SJon Lin 
643ba0501acSDingqiang Lin 	return ret;
644ba0501acSDingqiang Lin }
645ba0501acSDingqiang Lin 
646c84f0ed8SJon Lin u32 sfc_nand_prog_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare)
647c84f0ed8SJon Lin {
648c84f0ed8SJon Lin 	int ret;
649c84f0ed8SJon Lin 	u32 sec_per_page = p_nand_info->sec_per_page;
650c84f0ed8SJon Lin 	u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE;
651a6fcac41SJon Lin 	struct nand_mega_area *meta = &p_nand_info->meta;
652c84f0ed8SJon Lin 
653c84f0ed8SJon Lin 	memcpy(gp_page_buf, p_data, data_size);
654c84f0ed8SJon Lin 	memset(&gp_page_buf[data_size / 4], 0xff, sec_per_page * 16);
655a6fcac41SJon Lin 	gp_page_buf[(data_size + meta->off0) / 4] = p_spare[0];
656a6fcac41SJon Lin 	gp_page_buf[(data_size + meta->off1) / 4] = p_spare[1];
657f28847a8SJon Lin 
658c84f0ed8SJon Lin 	if (sec_per_page == 8) {
659a6fcac41SJon Lin 		gp_page_buf[(data_size + meta->off2) / 4] = p_spare[2];
660a6fcac41SJon Lin 		gp_page_buf[(data_size + meta->off3) / 4] = p_spare[3];
661c84f0ed8SJon Lin 	}
662f28847a8SJon Lin 
663c84f0ed8SJon Lin 	ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf);
664c84f0ed8SJon Lin 
665c84f0ed8SJon Lin 	return ret;
666c84f0ed8SJon Lin }
667c84f0ed8SJon Lin 
668a80fd396SJon Lin u32 sfc_nand_read(u32 row, u32 *p_page_buf, u32 column, u32 len)
669ba0501acSDingqiang Lin {
670ba0501acSDingqiang Lin 	int ret;
671415cf080Sjon.lin 	u32 plane;
67258463f4dSJon Lin 	struct rk_sfc_op op;
6736281205aSDingqiang Lin 	u32 ecc_result;
674a6fcac41SJon Lin 	u8 status;
675ba0501acSDingqiang Lin 
67658463f4dSJon Lin 	op.sfcmd.d32 = 0;
677f28847a8SJon Lin 	op.sfcmd.b.cmd = 0x13;
67858463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
67958463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_24BITS;
68058463f4dSJon Lin 
68158463f4dSJon Lin 	op.sfctrl.d32 = 0;
68258463f4dSJon Lin 
683a80fd396SJon Lin 	sfc_request(&op, row, p_page_buf, 0);
684f28847a8SJon Lin 
685ba0501acSDingqiang Lin 	if (sfc_nand_dev.read_lines == DATA_LINES_X4 &&
68625098c06SDingqiang Lin 	    p_nand_info->feature & FEA_SOFT_QOP_BIT &&
68725098c06SDingqiang Lin 	    sfc_get_version() < SFC_VER_3)
688ba0501acSDingqiang Lin 		sfc_nand_rw_preset();
689ba0501acSDingqiang Lin 
690a6fcac41SJon Lin 	sfc_nand_wait_busy(&status, 1000 * 1000);
691a6fcac41SJon Lin 	ecc_result = p_nand_info->ecc_status();
692a6fcac41SJon Lin 
69358463f4dSJon Lin 	op.sfcmd.d32 = 0;
69458463f4dSJon Lin 	op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd;
695a80fd396SJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
696a80fd396SJon Lin 	op.sfcmd.b.dummybits = 8;
69758463f4dSJon Lin 
69858463f4dSJon Lin 	op.sfctrl.d32 = 0;
69958463f4dSJon Lin 	op.sfctrl.b.datalines = sfc_nand_dev.read_lines;
700a80fd396SJon Lin 	op.sfctrl.b.addrbits = 16;
701ba0501acSDingqiang Lin 
702a80fd396SJon Lin 	plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0;
703a80fd396SJon Lin 	ret = sfc_request(&op, plane | column, p_page_buf, len);
704a80fd396SJon Lin 	rkflash_print_dio("%s %x %x\n", __func__, row, p_page_buf[0]);
705c84f0ed8SJon Lin 
706c84f0ed8SJon Lin 	if (ret != SFC_OK)
707f28847a8SJon Lin 		return SFC_NAND_HW_ERROR;
708c84f0ed8SJon Lin 
709c84f0ed8SJon Lin 	return ecc_result;
710c84f0ed8SJon Lin }
711c84f0ed8SJon Lin 
712a80fd396SJon Lin u32 sfc_nand_read_page_raw(u8 cs, u32 addr, u32 *p_page_buf)
713a80fd396SJon Lin {
714a80fd396SJon Lin 	u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page;
715a80fd396SJon Lin 
716a80fd396SJon Lin 	return sfc_nand_read(addr, p_page_buf, 0, page_size);
717a80fd396SJon Lin }
718a80fd396SJon Lin 
719c84f0ed8SJon Lin u32 sfc_nand_read_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare)
720c84f0ed8SJon Lin {
72158463f4dSJon Lin 	u32 ret;
722c84f0ed8SJon Lin 	u32 sec_per_page = p_nand_info->sec_per_page;
723c84f0ed8SJon Lin 	u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE;
724a6fcac41SJon Lin 	struct nand_mega_area *meta = &p_nand_info->meta;
725c84f0ed8SJon Lin 
726c84f0ed8SJon Lin 	ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf);
727f25e3cafSJon Lin 	memcpy(p_data, gp_page_buf, data_size);
728a6fcac41SJon Lin 	p_spare[0] = gp_page_buf[(data_size + meta->off0) / 4];
729a6fcac41SJon Lin 	p_spare[1] = gp_page_buf[(data_size + meta->off1) / 4];
730f28847a8SJon Lin 
731f25e3cafSJon Lin 	if (p_nand_info->sec_per_page == 8) {
732a6fcac41SJon Lin 		p_spare[2] = gp_page_buf[(data_size + meta->off2) / 4];
733a6fcac41SJon Lin 		p_spare[3] = gp_page_buf[(data_size + meta->off3) / 4];
734f25e3cafSJon Lin 	}
735ba0501acSDingqiang Lin 
736f28847a8SJon Lin 	if (ret == SFC_NAND_HW_ERROR)
737f28847a8SJon Lin 		ret = SFC_NAND_ECC_ERROR;
738f28847a8SJon Lin 
739c84f0ed8SJon Lin 	if (ret != SFC_NAND_ECC_OK) {
740c84f0ed8SJon Lin 		rkflash_print_error("%s[0x%x], ret=0x%x\n", __func__, addr, ret);
741f28847a8SJon Lin 
742ba0501acSDingqiang Lin 		if (p_data)
743c84f0ed8SJon Lin 			rkflash_print_hex("data:", p_data, 4, 8);
744f28847a8SJon Lin 
745ba0501acSDingqiang Lin 		if (p_spare)
746c84f0ed8SJon Lin 			rkflash_print_hex("spare:", p_spare, 4, 2);
747ba0501acSDingqiang Lin 	}
748f25e3cafSJon Lin 
749c84f0ed8SJon Lin 	return ret;
750ba0501acSDingqiang Lin }
751ba0501acSDingqiang Lin 
752c84f0ed8SJon Lin u32 sfc_nand_check_bad_block(u8 cs, u32 addr)
753c84f0ed8SJon Lin {
754c84f0ed8SJon Lin 	u32 ret;
755c84f0ed8SJon Lin 	u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE;
756a80fd396SJon Lin 	u32 marker = 0;
757c84f0ed8SJon Lin 
758a80fd396SJon Lin 	ret = sfc_nand_read(addr, &marker, data_size, 2);
759f28847a8SJon Lin 
760f28847a8SJon Lin 	/* unify with mtd framework */
761a6fcac41SJon Lin 	if (ret == SFC_NAND_ECC_ERROR)
762a80fd396SJon Lin 		rkflash_print_error("%s page= %x ret= %x spare= %x\n",
763a80fd396SJon Lin 				    __func__, addr, ret, marker);
764f28847a8SJon Lin 
765c84f0ed8SJon Lin 	/* Original bad block */
766a80fd396SJon Lin 	if ((u16)marker != 0xffff)
767c84f0ed8SJon Lin 		return true;
768c84f0ed8SJon Lin 
769c84f0ed8SJon Lin 	return false;
770c84f0ed8SJon Lin }
771c84f0ed8SJon Lin 
772c84f0ed8SJon Lin u32 sfc_nand_mark_bad_block(u8 cs, u32 addr)
773c84f0ed8SJon Lin {
774c84f0ed8SJon Lin 	u32 ret;
775c84f0ed8SJon Lin 	u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE;
776c84f0ed8SJon Lin 
777c84f0ed8SJon Lin 	ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf);
778f28847a8SJon Lin 
779c84f0ed8SJon Lin 	if (ret)
780c84f0ed8SJon Lin 		return SFC_NAND_HW_ERROR;
781f28847a8SJon Lin 
782c84f0ed8SJon Lin 	gp_page_buf[data_size / 4] = 0x0;
783c84f0ed8SJon Lin 	ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf);
784f28847a8SJon Lin 
785c84f0ed8SJon Lin 	if (ret)
786c84f0ed8SJon Lin 		return SFC_NAND_HW_ERROR;
787c84f0ed8SJon Lin 
788c84f0ed8SJon Lin 	return ret;
789c84f0ed8SJon Lin }
790c84f0ed8SJon Lin 
791c84f0ed8SJon Lin int sfc_nand_read_id(u8 *data)
792ba0501acSDingqiang Lin {
793ba0501acSDingqiang Lin 	int ret;
79458463f4dSJon Lin 	struct rk_sfc_op op;
795ba0501acSDingqiang Lin 
79658463f4dSJon Lin 	op.sfcmd.d32 = 0;
79758463f4dSJon Lin 	op.sfcmd.b.cmd = CMD_READ_JEDECID;
79858463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
799ba0501acSDingqiang Lin 
80058463f4dSJon Lin 	op.sfctrl.d32 = 0;
80158463f4dSJon Lin 	op.sfctrl.b.addrbits = 8;
80258463f4dSJon Lin 
80358463f4dSJon Lin 	ret = sfc_request(&op, 0, data, 3);
804ba0501acSDingqiang Lin 
805ba0501acSDingqiang Lin 	return ret;
806ba0501acSDingqiang Lin }
807ba0501acSDingqiang Lin 
808ba0501acSDingqiang Lin /*
809ba0501acSDingqiang Lin  * Read the 1st page's 1st byte of a phy_blk
810ba0501acSDingqiang Lin  * If not FF, it's bad blk
811ba0501acSDingqiang Lin  */
812ba0501acSDingqiang Lin static int sfc_nand_get_bad_block_list(u16 *table, u32 die)
813ba0501acSDingqiang Lin {
814ba0501acSDingqiang Lin 	u32 bad_cnt, page;
815ba0501acSDingqiang Lin 	u32 blk_per_die;
8162ac88c1bSJon Lin 	u16 blk;
817ba0501acSDingqiang Lin 
818c84f0ed8SJon Lin 	rkflash_print_info("%s\n", __func__);
819c84f0ed8SJon Lin 
820ba0501acSDingqiang Lin 	bad_cnt = 0;
821ba0501acSDingqiang Lin 	blk_per_die = p_nand_info->plane_per_die *
822ba0501acSDingqiang Lin 		      p_nand_info->blk_per_plane;
823f28847a8SJon Lin 
824ba0501acSDingqiang Lin 	for (blk = 0; blk < blk_per_die; blk++) {
825ba0501acSDingqiang Lin 		page = (blk + blk_per_die * die) *
826ba0501acSDingqiang Lin 		       p_nand_info->page_per_blk;
827ba0501acSDingqiang Lin 
8282ac88c1bSJon Lin 		if (sfc_nand_check_bad_block(die, page)) {
829ba0501acSDingqiang Lin 			table[bad_cnt++] = blk;
830c84f0ed8SJon Lin 			rkflash_print_error("die[%d], bad_blk[%d]\n", die, blk);
831ba0501acSDingqiang Lin 		}
832ba0501acSDingqiang Lin 	}
833f28847a8SJon Lin 
834ba0501acSDingqiang Lin 	return (int)bad_cnt;
835ba0501acSDingqiang Lin }
836ba0501acSDingqiang Lin 
837c84f0ed8SJon Lin void sfc_nand_ftl_ops_init(void)
838ba0501acSDingqiang Lin {
839ba0501acSDingqiang Lin 	/* para init */
840ba0501acSDingqiang Lin 	g_nand_phy_info.nand_type	= 1;
841ba0501acSDingqiang Lin 	g_nand_phy_info.die_num		= 1;
842ba0501acSDingqiang Lin 	g_nand_phy_info.plane_per_die	= p_nand_info->plane_per_die;
843ba0501acSDingqiang Lin 	g_nand_phy_info.blk_per_plane	= p_nand_info->blk_per_plane;
844ba0501acSDingqiang Lin 	g_nand_phy_info.page_per_blk	= p_nand_info->page_per_blk;
845ba0501acSDingqiang Lin 	g_nand_phy_info.page_per_slc_blk = p_nand_info->page_per_blk;
846c84f0ed8SJon Lin 	g_nand_phy_info.byte_per_sec	= SFC_NAND_SECTOR_SIZE;
847ba0501acSDingqiang Lin 	g_nand_phy_info.sec_per_page	= p_nand_info->sec_per_page;
848ba0501acSDingqiang Lin 	g_nand_phy_info.sec_per_blk	= p_nand_info->sec_per_page *
849ba0501acSDingqiang Lin 					  p_nand_info->page_per_blk;
850ba0501acSDingqiang Lin 	g_nand_phy_info.reserved_blk	= 8;
851ba0501acSDingqiang Lin 	g_nand_phy_info.blk_per_die	= p_nand_info->plane_per_die *
852ba0501acSDingqiang Lin 					  p_nand_info->blk_per_plane;
853ba0501acSDingqiang Lin 	g_nand_phy_info.ecc_bits	= p_nand_info->max_ecc_bits;
854ba0501acSDingqiang Lin 
855ba0501acSDingqiang Lin 	/* driver register */
856ba0501acSDingqiang Lin 	g_nand_ops.get_bad_blk_list	= sfc_nand_get_bad_block_list;
857ba0501acSDingqiang Lin 	g_nand_ops.erase_blk		= sfc_nand_erase_block;
858ba0501acSDingqiang Lin 	g_nand_ops.prog_page		= sfc_nand_prog_page;
859ba0501acSDingqiang Lin 	g_nand_ops.read_page		= sfc_nand_read_page;
86057d18453Sjon.lin 	g_nand_ops.bch_sel		= NULL;
861ba0501acSDingqiang Lin }
862ba0501acSDingqiang Lin 
863a6fcac41SJon Lin static int sfc_nand_enable_QE(void)
864ba0501acSDingqiang Lin {
865ba0501acSDingqiang Lin 	int ret = SFC_OK;
866ba0501acSDingqiang Lin 	u8 status;
867ba0501acSDingqiang Lin 
868f28847a8SJon Lin 	ret = sfc_nand_read_feature(0xB0, &status);
869ba0501acSDingqiang Lin 
870ba0501acSDingqiang Lin 	if (ret != SFC_OK)
871ba0501acSDingqiang Lin 		return ret;
872ba0501acSDingqiang Lin 
873f28847a8SJon Lin 	if (status & 1)   /* is QE bit set */
874ba0501acSDingqiang Lin 		return SFC_OK;
875ba0501acSDingqiang Lin 
876f28847a8SJon Lin 	status |= 1;
877ba0501acSDingqiang Lin 
878f28847a8SJon Lin 	return sfc_nand_write_feature(0xB0, status);
879ba0501acSDingqiang Lin }
880ba0501acSDingqiang Lin 
881ba0501acSDingqiang Lin u32 sfc_nand_init(void)
882ba0501acSDingqiang Lin {
883c84f0ed8SJon Lin 	u8 status, id_byte[8];
884ba0501acSDingqiang Lin 
885c84f0ed8SJon Lin 	sfc_nand_read_id(id_byte);
886c84f0ed8SJon Lin 	rkflash_print_error("sfc_nand id: %x %x %x\n",
887ba0501acSDingqiang Lin 			    id_byte[0], id_byte[1], id_byte[2]);
888f28847a8SJon Lin 
889ba0501acSDingqiang Lin 	if (id_byte[0] == 0xFF || id_byte[0] == 0x00)
89058463f4dSJon Lin 		return (u32)FTL_NO_FLASH;
891ba0501acSDingqiang Lin 
892a6fcac41SJon Lin 	p_nand_info = sfc_nand_get_info(id_byte);
893f28847a8SJon Lin 
894ba0501acSDingqiang Lin 	if (!p_nand_info)
89558463f4dSJon Lin 		return (u32)FTL_UNSUPPORTED_FLASH;
896ba0501acSDingqiang Lin 
897ba0501acSDingqiang Lin 	sfc_nand_dev.manufacturer = id_byte[0];
898ba0501acSDingqiang Lin 	sfc_nand_dev.mem_type = id_byte[1];
899c84f0ed8SJon Lin 	sfc_nand_dev.capacity = p_nand_info->density;
900c84f0ed8SJon Lin 	sfc_nand_dev.block_size = p_nand_info->page_per_blk * p_nand_info->sec_per_page;
901c84f0ed8SJon Lin 	sfc_nand_dev.page_size = p_nand_info->sec_per_page;
902ba0501acSDingqiang Lin 
903ba0501acSDingqiang Lin 	/* disable block lock */
904ba0501acSDingqiang Lin 	sfc_nand_write_feature(0xA0, 0);
905ba0501acSDingqiang Lin 	sfc_nand_dev.read_lines = DATA_LINES_X1;
906ba0501acSDingqiang Lin 	sfc_nand_dev.prog_lines = DATA_LINES_X1;
907f28847a8SJon Lin 	sfc_nand_dev.page_read_cmd = 0x03;
908f28847a8SJon Lin 	sfc_nand_dev.page_prog_cmd = 0x02;
909f28847a8SJon Lin 
910ba0501acSDingqiang Lin 	if (p_nand_info->feature & FEA_4BIT_READ) {
911f28847a8SJon Lin 		if ((p_nand_info->has_qe_bits && sfc_nand_enable_QE() == SFC_OK) ||
912f28847a8SJon Lin 		    !p_nand_info->has_qe_bits) {
913ba0501acSDingqiang Lin 			sfc_nand_dev.read_lines = DATA_LINES_X4;
914f28847a8SJon Lin 			sfc_nand_dev.page_read_cmd = 0x6b;
915ba0501acSDingqiang Lin 		}
916ba0501acSDingqiang Lin 	}
917ba0501acSDingqiang Lin 
918ba0501acSDingqiang Lin 	if (p_nand_info->feature & FEA_4BIT_PROG &&
919ba0501acSDingqiang Lin 	    sfc_nand_dev.read_lines == DATA_LINES_X4) {
920ba0501acSDingqiang Lin 		sfc_nand_dev.prog_lines = DATA_LINES_X4;
921f28847a8SJon Lin 		sfc_nand_dev.page_prog_cmd = 0x32;
922ba0501acSDingqiang Lin 	}
923ba0501acSDingqiang Lin 
924ba0501acSDingqiang Lin 	sfc_nand_read_feature(0xA0, &status);
925c84f0ed8SJon Lin 	rkflash_print_info("sfc_nand A0 = 0x%x\n", status);
926ba0501acSDingqiang Lin 	sfc_nand_read_feature(0xB0, &status);
927c84f0ed8SJon Lin 	rkflash_print_info("sfc_nand B0 = 0x%x\n", status);
928c84f0ed8SJon Lin 	rkflash_print_info("read_lines = %x\n", sfc_nand_dev.read_lines);
929c84f0ed8SJon Lin 	rkflash_print_info("prog_lines = %x\n", sfc_nand_dev.prog_lines);
930c84f0ed8SJon Lin 	rkflash_print_info("page_read_cmd = %x\n", sfc_nand_dev.page_read_cmd);
931c84f0ed8SJon Lin 	rkflash_print_info("page_prog_cmd = %x\n", sfc_nand_dev.page_prog_cmd);
932ba0501acSDingqiang Lin 
933ba0501acSDingqiang Lin 	return SFC_OK;
934ba0501acSDingqiang Lin }
935ba0501acSDingqiang Lin 
936c84f0ed8SJon Lin void sfc_nand_deinit(void)
937ba0501acSDingqiang Lin {
938c84f0ed8SJon Lin 	/* to-do */
939ba0501acSDingqiang Lin }
940c84f0ed8SJon Lin 
941c84f0ed8SJon Lin struct SFNAND_DEV *sfc_nand_get_private_dev(void)
942c84f0ed8SJon Lin {
943c84f0ed8SJon Lin 	return &sfc_nand_dev;
944c84f0ed8SJon Lin }
945c84f0ed8SJon Lin 
946