xref: /rk3399_rockchip-uboot/drivers/rkflash/sfc_nand.c (revision 362b1be1673decde03f1626c45e1dbd93bb2dab6)
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);
24*362b1be1SJon Lin static u32 sfc_nand_get_ecc_status7(void);
25f28847a8SJon Lin 
26ba0501acSDingqiang Lin static struct nand_info spi_nand_tbl[] = {
27ba0501acSDingqiang Lin 	/* TC58CVG0S0HxAIx */
28b833c879SJon Lin 	{ 0x98, 0xC2, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
29ba0501acSDingqiang Lin 	/* TC58CVG1S0HxAIx */
30b833c879SJon Lin 	{ 0x98, 0xCB, 0x00, 4, 0x40, 2, 1024, 0x00, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
31a6fcac41SJon Lin 	/* TC58CVG2S0HRAIJ */
32b833c879SJon Lin 	{ 0x98, 0xED, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 0, { 0x04, 0x0C, 0x08, 0x10 }, &sfc_nand_get_ecc_status0 },
33a6fcac41SJon Lin 	/* TC58CVG1S3HRAIJ */
34b833c879SJon Lin 	{ 0x98, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
35a6fcac41SJon Lin 	/* TC58CVG0S3HRAIJ */
36b833c879SJon Lin 	{ 0x98, 0xE2, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
37f28847a8SJon Lin 
38f28847a8SJon Lin 	/* MX35LF1GE4AB */
39b833c879SJon Lin 	{ 0xC2, 0x12, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
40f28847a8SJon Lin 	/* MX35LF2GE4AB */
41b833c879SJon Lin 	{ 0xC2, 0x22, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
42f28847a8SJon Lin 	/* MX35LF2GE4AD */
43b833c879SJon Lin 	{ 0xC2, 0x26, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
44f28847a8SJon Lin 	/* MX35LF4GE4AD */
45*362b1be1SJon Lin 	{ 0xC2, 0x37, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status0 },
46*362b1be1SJon Lin 	/* MX35UF1GE4AC */
47*362b1be1SJon Lin 	{ 0xC2, 0x92, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
48*362b1be1SJon Lin 	/* MX35UF2GE4AC */
49*362b1be1SJon Lin 	{ 0xC2, 0xA2, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
50f28847a8SJon Lin 
51f28847a8SJon Lin 	/* GD5F1GQ4UAYIG */
52b833c879SJon Lin 	{ 0xC8, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
53f28847a8SJon Lin 	/* GD5F1GQ4RB9IGR */
54b833c879SJon Lin 	{ 0xC8, 0xD1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
55f28847a8SJon Lin 	/* GD5F2GQ40BY2GR */
56b833c879SJon Lin 	{ 0xC8, 0xD2, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
57f28847a8SJon Lin 	/* GD5F1GQ5UEYIG */
58b833c879SJon Lin 	{ 0xC8, 0x51, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
59f28847a8SJon Lin 	/* GD5F2GQ5UEYIG */
60b833c879SJon Lin 	{ 0xC8, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
61f28847a8SJon Lin 	/* GD5F1GQ4R */
62b833c879SJon Lin 	{ 0xC8, 0xC1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
63*362b1be1SJon Lin 	/* GD5F4GQ6RExxG 1*4096 */
64*362b1be1SJon Lin 	{ 0xC8, 0x45, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 1, { 0x04, 0x08, 0X14, 0x18 }, &sfc_nand_get_ecc_status2 },
65*362b1be1SJon Lin 	/* GD5F4GQ6UExxG 1*4096 */
66*362b1be1SJon Lin 	{ 0xC8, 0x55, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 1, { 0x04, 0x08, 0X14, 0x18 }, &sfc_nand_get_ecc_status2 },
67f28847a8SJon Lin 
68f28847a8SJon Lin 	/* W25N01GV */
69b833c879SJon Lin 	{ 0xEF, 0xAA, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 },
70b833c879SJon Lin 	/* W25N02KVZEIR */
71b833c879SJon Lin 	{ 0xEF, 0xAA, 0x22, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status0 },
72f28847a8SJon Lin 	/* W25N01GW */
73b833c879SJon Lin 	{ 0xEF, 0xBA, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 },
74f28847a8SJon Lin 
75f28847a8SJon Lin 	/* HYF2GQ4UAACAE */
76b833c879SJon Lin 	{ 0xC9, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
77f28847a8SJon Lin 	/* HYF1GQ4UDACAE */
78b833c879SJon Lin 	{ 0xC9, 0x21, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
79f28847a8SJon Lin 	/* HYF1GQ4UPACAE */
80b833c879SJon Lin 	{ 0xC9, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
81f28847a8SJon Lin 	/* HYF2GQ4UDACAE */
82b833c879SJon Lin 	{ 0xC9, 0x22, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
83f28847a8SJon Lin 	/* HYF2GQ4UHCCAE */
84b833c879SJon Lin 	{ 0xC9, 0x5A, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
85f28847a8SJon Lin 	/* HYF4GQ4UAACBE */
86b833c879SJon Lin 	{ 0xC9, 0xD4, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x4, 1, { 0x20, 0x40, 0x24, 0x44 }, &sfc_nand_get_ecc_status0 },
87f28847a8SJon Lin 
88f28847a8SJon Lin 	/* FS35ND01G-S1 */
89b833c879SJon Lin 	{ 0xCD, 0xB1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
90f28847a8SJon Lin 	/* FS35ND02G-S2 */
91b833c879SJon Lin 	{ 0xCD, 0xA2, 0x00, 4, 0x40, 1, 2048, 0x00, 19, 0x4, 0, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
9258463f4dSJon Lin 	/* FS35ND01G-S1Y2 */
93b833c879SJon Lin 	{ 0xCD, 0xEA, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
94f1b20f5aSJon Lin 	/* FS35ND02G-S3Y2 */
95b833c879SJon Lin 	{ 0xCD, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
96f28847a8SJon Lin 	/* FS35ND04G-S2Y2 1*4096 */
97b833c879SJon Lin 	{ 0xCD, 0xEC, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
98f28847a8SJon Lin 
99f28847a8SJon Lin 	/* DS35Q1GA-IB */
100b833c879SJon Lin 	{ 0xE5, 0x71, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
101f28847a8SJon Lin 	/* DS35Q2GA-IB */
102b833c879SJon Lin 	{ 0xE5, 0x72, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
103f28847a8SJon Lin 	/* DS35M1GA-1B */
104b833c879SJon Lin 	{ 0xE5, 0x21, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
105f28847a8SJon Lin 
106f28847a8SJon Lin 	/* EM73C044VCC-H */
107b833c879SJon Lin 	{ 0xD5, 0x22, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
108f28847a8SJon Lin 	/* EM73D044VCE-H */
109b833c879SJon Lin 	{ 0xD5, 0x20, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
110f28847a8SJon Lin 	/* EM73E044SNA-G */
111b833c879SJon Lin 	{ 0xD5, 0x03, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x28, 0x08, 0x2C }, &sfc_nand_get_ecc_status0 },
112f28847a8SJon Lin 
113f28847a8SJon Lin 	/* XT26G02A */
114*362b1be1SJon Lin 	{ 0x0B, 0xE2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
115f28847a8SJon Lin 	/* XT26G01A */
116*362b1be1SJon Lin 	{ 0x0B, 0xE1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
117f28847a8SJon Lin 	/* XT26G04A */
118*362b1be1SJon Lin 	{ 0x0B, 0xE3, 0x00, 4, 0x80, 1, 2048, 0x4C, 20, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
119f28847a8SJon Lin 	/* XT26G01B */
120*362b1be1SJon Lin 	{ 0x0B, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
121f28847a8SJon Lin 	/* XT26G02B */
122*362b1be1SJon Lin 	{ 0x0B, 0xF2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
123*362b1be1SJon Lin 	/* XT26G01C */
124*362b1be1SJon Lin 	{ 0x0B, 0x11, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 },
125*362b1be1SJon Lin 	/* XT26G02C */
126*362b1be1SJon Lin 	{ 0x0B, 0x12, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 },
127*362b1be1SJon Lin 	/* XT26G04C */
128*362b1be1SJon Lin 	{ 0x0B, 0x13, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status7 },
129a80fd396SJon Lin 
130*362b1be1SJon Lin 	/* MT29F2G01ABA, XT26G02E, F50L2G41XA */
131b833c879SJon Lin 	{ 0x2C, 0x24, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x1, 1, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
132a80fd396SJon Lin 
133a80fd396SJon Lin 	/* FM25S01 */
134b833c879SJon Lin 	{ 0xA1, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x00, 0x04, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
135a80fd396SJon Lin 	/* FM25S01A */
136b833c879SJon Lin 	{ 0xA1, 0xE4, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
137a80fd396SJon Lin 	/* FM25S02A */
138b833c879SJon Lin 	{ 0xA1, 0xE5, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
139f28847a8SJon Lin 
140f28847a8SJon Lin 	/* IS37SML01G1 */
141b833c879SJon Lin 	{ 0xC8, 0x21, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x1, 0, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
142f28847a8SJon Lin 	/* F50L1G41LB */
143b833c879SJon Lin 	{ 0xC8, 0x01, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
144f28847a8SJon Lin 	/* ATO25D1GA */
145b833c879SJon Lin 	{ 0x9B, 0x12, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x1, 1, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
146*362b1be1SJon Lin 	/* BWJX08K-2Gb */
147*362b1be1SJon Lin 	{ 0xBC, 0xB3, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x10, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
148ba0501acSDingqiang Lin };
149ba0501acSDingqiang Lin 
150ba0501acSDingqiang Lin static struct nand_info *p_nand_info;
151ba0501acSDingqiang Lin static u32 gp_page_buf[SFC_NAND_PAGE_MAX_SIZE / 4];
152ba0501acSDingqiang Lin static struct SFNAND_DEV sfc_nand_dev;
153ba0501acSDingqiang Lin 
154a6fcac41SJon Lin static struct nand_info *sfc_nand_get_info(u8 *nand_id)
155ba0501acSDingqiang Lin {
156ba0501acSDingqiang Lin 	u32 i;
157ba0501acSDingqiang Lin 
158ba0501acSDingqiang Lin 	for (i = 0; i < ARRAY_SIZE(spi_nand_tbl); i++) {
159b833c879SJon Lin 		if (spi_nand_tbl[i].id0 == nand_id[0] &&
160b833c879SJon Lin 		    spi_nand_tbl[i].id1 == nand_id[1]) {
161b833c879SJon Lin 			if (spi_nand_tbl[i].id2 &&
162b833c879SJon Lin 			    spi_nand_tbl[i].id2 != nand_id[2])
163b833c879SJon Lin 				continue;
164b833c879SJon Lin 
165ba0501acSDingqiang Lin 			return &spi_nand_tbl[i];
166ba0501acSDingqiang Lin 		}
167b833c879SJon Lin 	}
168f28847a8SJon Lin 
169ba0501acSDingqiang Lin 	return NULL;
170ba0501acSDingqiang Lin }
171ba0501acSDingqiang Lin 
172ba0501acSDingqiang Lin static int sfc_nand_write_en(void)
173ba0501acSDingqiang Lin {
174ba0501acSDingqiang Lin 	int ret;
17558463f4dSJon Lin 	struct rk_sfc_op op;
176ba0501acSDingqiang Lin 
17758463f4dSJon Lin 	op.sfcmd.d32 = 0;
17858463f4dSJon Lin 	op.sfcmd.b.cmd = CMD_WRITE_EN;
17958463f4dSJon Lin 
18058463f4dSJon Lin 	op.sfctrl.d32 = 0;
18158463f4dSJon Lin 
18258463f4dSJon Lin 	ret = sfc_request(&op, 0, NULL, 0);
183ba0501acSDingqiang Lin 	return ret;
184ba0501acSDingqiang Lin }
185ba0501acSDingqiang Lin 
186ba0501acSDingqiang Lin static int sfc_nand_rw_preset(void)
187ba0501acSDingqiang Lin {
188ba0501acSDingqiang Lin 	int ret;
18958463f4dSJon Lin 	struct rk_sfc_op op;
190ba0501acSDingqiang Lin 
19158463f4dSJon Lin 	op.sfcmd.d32 = 0;
192f28847a8SJon Lin 	op.sfcmd.b.cmd = 0xff;
193f28847a8SJon Lin 	op.sfcmd.b.cs = 2;
194ba0501acSDingqiang Lin 
19558463f4dSJon Lin 	op.sfctrl.d32 = 0;
19658463f4dSJon Lin 	op.sfctrl.b.datalines = 2;
197f28847a8SJon Lin 	op.sfctrl.b.cmdlines = 2;
198f28847a8SJon Lin 	op.sfctrl.b.addrlines = 2;
19958463f4dSJon Lin 
200f28847a8SJon Lin 	ret = sfc_request(&op, 0, NULL, 0);
201ba0501acSDingqiang Lin 	return ret;
202ba0501acSDingqiang Lin }
203ba0501acSDingqiang Lin 
204ba0501acSDingqiang Lin static int sfc_nand_read_feature(u8 addr, u8 *data)
205ba0501acSDingqiang Lin {
206ba0501acSDingqiang Lin 	int ret;
20758463f4dSJon Lin 	struct rk_sfc_op op;
208ba0501acSDingqiang Lin 
20958463f4dSJon Lin 	op.sfcmd.d32 = 0;
21058463f4dSJon Lin 	op.sfcmd.b.cmd = 0x0F;
21158463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
21258463f4dSJon Lin 
21358463f4dSJon Lin 	op.sfctrl.d32 = 0;
21458463f4dSJon Lin 	op.sfctrl.b.addrbits = 8;
21558463f4dSJon Lin 
216ba0501acSDingqiang Lin 	*data = 0;
217ba0501acSDingqiang Lin 
21858463f4dSJon Lin 	ret = sfc_request(&op, addr, data, 1);
219f28847a8SJon Lin 
220ba0501acSDingqiang Lin 	if (ret != SFC_OK)
221ba0501acSDingqiang Lin 		return ret;
222f28847a8SJon Lin 
223ba0501acSDingqiang Lin 	return SFC_OK;
224ba0501acSDingqiang Lin }
225ba0501acSDingqiang Lin 
226ba0501acSDingqiang Lin static int sfc_nand_write_feature(u32 addr, u8 status)
227ba0501acSDingqiang Lin {
228ba0501acSDingqiang Lin 	int ret;
22958463f4dSJon Lin 	struct rk_sfc_op op;
230ba0501acSDingqiang Lin 
231ba0501acSDingqiang Lin 	sfc_nand_write_en();
232ba0501acSDingqiang Lin 
23358463f4dSJon Lin 	op.sfcmd.d32 = 0;
23458463f4dSJon Lin 	op.sfcmd.b.cmd = 0x1F;
23558463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
23658463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
237ba0501acSDingqiang Lin 
23858463f4dSJon Lin 	op.sfctrl.d32 = 0;
23958463f4dSJon Lin 	op.sfctrl.b.addrbits = 8;
24058463f4dSJon Lin 
24158463f4dSJon Lin 	ret = sfc_request(&op, addr, &status, 1);
242f28847a8SJon Lin 
243ba0501acSDingqiang Lin 	if (ret != SFC_OK)
244ba0501acSDingqiang Lin 		return ret;
245f28847a8SJon Lin 
246ba0501acSDingqiang Lin 	return ret;
247ba0501acSDingqiang Lin }
248ba0501acSDingqiang Lin 
249ba0501acSDingqiang Lin static int sfc_nand_wait_busy(u8 *data, int timeout)
250ba0501acSDingqiang Lin {
251ba0501acSDingqiang Lin 	int ret;
252ba0501acSDingqiang Lin 	int i;
253ba0501acSDingqiang Lin 	u8 status;
254ba0501acSDingqiang Lin 
255ba0501acSDingqiang Lin 	*data = 0;
256f28847a8SJon Lin 
257ba0501acSDingqiang Lin 	for (i = 0; i < timeout; i++) {
258ba0501acSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
259f28847a8SJon Lin 
260ba0501acSDingqiang Lin 		if (ret != SFC_OK)
261ba0501acSDingqiang Lin 			return ret;
262f28847a8SJon Lin 
263ba0501acSDingqiang Lin 		*data = status;
264f28847a8SJon Lin 
265ba0501acSDingqiang Lin 		if (!(status & (1 << 0)))
266ba0501acSDingqiang Lin 			return SFC_OK;
267f28847a8SJon Lin 
268ba0501acSDingqiang Lin 		sfc_delay(1);
269ba0501acSDingqiang Lin 	}
270f28847a8SJon Lin 
271f28847a8SJon Lin 	return SFC_NAND_WAIT_TIME_OUT;
272ba0501acSDingqiang Lin }
273ba0501acSDingqiang Lin 
2746281205aSDingqiang Lin /*
2756281205aSDingqiang Lin  * ecc default:
276a6fcac41SJon Lin  * ecc bits: 0xC0[4,5]
277f28847a8SJon Lin  * 0b00, No bit errors were detected
278f28847a8SJon Lin  * 0b01, Bit errors were detected and corrected.
279f28847a8SJon Lin  * 0b10, Multiple bit errors were detected and not corrected.
280f28847a8SJon Lin  * 0b11, Bits errors were detected and corrected, bit error count
281*362b1be1SJon Lin  *	reach the bit flip detection threshold
2826281205aSDingqiang Lin  */
283f28847a8SJon Lin static u32 sfc_nand_get_ecc_status0(void)
2846281205aSDingqiang Lin {
28558463f4dSJon Lin 	u32 ret;
2866281205aSDingqiang Lin 	u32 i;
2876281205aSDingqiang Lin 	u8 ecc;
2886281205aSDingqiang Lin 	u8 status;
2896281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
2906281205aSDingqiang Lin 
2916281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
2926281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
293f28847a8SJon Lin 
2946281205aSDingqiang Lin 		if (ret != SFC_OK)
2956281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
296f28847a8SJon Lin 
2976281205aSDingqiang Lin 		if (!(status & (1 << 0)))
2986281205aSDingqiang Lin 			break;
299f28847a8SJon Lin 
3006281205aSDingqiang Lin 		sfc_delay(1);
3016281205aSDingqiang Lin 	}
3026281205aSDingqiang Lin 
3036281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
3046281205aSDingqiang Lin 
3056281205aSDingqiang Lin 	if (ecc <= 1)
3066281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
3076281205aSDingqiang Lin 	else if (ecc == 2)
30858463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
3096281205aSDingqiang Lin 	else
3106281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
3116281205aSDingqiang Lin 
3126281205aSDingqiang Lin 	return ret;
3136281205aSDingqiang Lin }
3146281205aSDingqiang Lin 
3156281205aSDingqiang Lin /*
3166281205aSDingqiang Lin  * ecc spectial type1:
317a6fcac41SJon Lin  * ecc bits: 0xC0[4,5]
318f28847a8SJon Lin  * 0b00, No bit errors were detected;
319f28847a8SJon Lin  * 0b01, Bits errors were detected and corrected, bit error count
3206281205aSDingqiang Lin  *	may reach the bit flip detection threshold;
321f28847a8SJon Lin  * 0b10, Multiple bit errors were detected and not corrected;
322f28847a8SJon Lin  * 0b11, Reserved.
3236281205aSDingqiang Lin  */
324f28847a8SJon Lin static u32 sfc_nand_get_ecc_status1(void)
3256281205aSDingqiang Lin {
32658463f4dSJon Lin 	u32 ret;
3276281205aSDingqiang Lin 	u32 i;
3286281205aSDingqiang Lin 	u8 ecc;
3296281205aSDingqiang Lin 	u8 status;
3306281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
3316281205aSDingqiang Lin 
3326281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
3336281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
334f28847a8SJon Lin 
3356281205aSDingqiang Lin 		if (ret != SFC_OK)
3366281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
337f28847a8SJon Lin 
3386281205aSDingqiang Lin 		if (!(status & (1 << 0)))
3396281205aSDingqiang Lin 			break;
340f28847a8SJon Lin 
3416281205aSDingqiang Lin 		sfc_delay(1);
3426281205aSDingqiang Lin 	}
3436281205aSDingqiang Lin 
3446281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
3456281205aSDingqiang Lin 
3466281205aSDingqiang Lin 	if (ecc == 0)
3476281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
3486281205aSDingqiang Lin 	else if (ecc == 1)
3496281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
3506281205aSDingqiang Lin 	else
35158463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
3526281205aSDingqiang Lin 
3536281205aSDingqiang Lin 	return ret;
3546281205aSDingqiang Lin }
3556281205aSDingqiang Lin 
3566281205aSDingqiang Lin /*
357d9cdd318SJon Lin  * ecc spectial type2:
358a6fcac41SJon Lin  * ecc bits: 0xC0[4,5] 0xF0[4,5]
359f28847a8SJon Lin  * [0b0000, 0b0011], No bit errors were detected;
360f28847a8SJon Lin  * [0b0100, 0b0111], Bit errors were detected and corrected. Not
361d9cdd318SJon Lin  *	reach Flipping Bits;
362f28847a8SJon Lin  * [0b1000, 0b1011], Multiple bit errors were detected and
363c84f0ed8SJon Lin  *	not corrected.
364f28847a8SJon Lin  * [0b1100, 0b1111], reserved.
365d9cdd318SJon Lin  */
366f28847a8SJon Lin static u32 sfc_nand_get_ecc_status2(void)
367d9cdd318SJon Lin {
36858463f4dSJon Lin 	u32 ret;
369d9cdd318SJon Lin 	u32 i;
370d9cdd318SJon Lin 	u8 ecc;
371d9cdd318SJon Lin 	u8 status, status1;
372d9cdd318SJon Lin 	u32 timeout = 1000 * 1000;
373d9cdd318SJon Lin 
374d9cdd318SJon Lin 	for (i = 0; i < timeout; i++) {
375d9cdd318SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
376f28847a8SJon Lin 
377d9cdd318SJon Lin 		if (ret != SFC_OK)
378d9cdd318SJon Lin 			return SFC_NAND_ECC_ERROR;
379f28847a8SJon Lin 
380d9cdd318SJon Lin 		ret = sfc_nand_read_feature(0xF0, &status1);
381f28847a8SJon Lin 
382d9cdd318SJon Lin 		if (ret != SFC_OK)
383d9cdd318SJon Lin 			return SFC_NAND_ECC_ERROR;
384f28847a8SJon Lin 
385d9cdd318SJon Lin 		if (!(status & (1 << 0)))
386d9cdd318SJon Lin 			break;
387f28847a8SJon Lin 
388d9cdd318SJon Lin 		sfc_delay(1);
389d9cdd318SJon Lin 	}
390d9cdd318SJon Lin 
391d9cdd318SJon Lin 	ecc = (status >> 4) & 0x03;
392d9cdd318SJon Lin 	ecc = (ecc << 2) | ((status1 >> 4) & 0x03);
393f28847a8SJon Lin 
394d9cdd318SJon Lin 	if (ecc < 7)
395d9cdd318SJon Lin 		ret = SFC_NAND_ECC_OK;
396d9cdd318SJon Lin 	else if (ecc == 7)
397d9cdd318SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
398d9cdd318SJon Lin 	else
39958463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
400d9cdd318SJon Lin 
401d9cdd318SJon Lin 	return ret;
402d9cdd318SJon Lin }
403d9cdd318SJon Lin 
404d9cdd318SJon Lin /*
4056281205aSDingqiang Lin  * ecc spectial type3:
406a6fcac41SJon Lin  * ecc bits: 0xC0[4,5] 0xF0[4,5]
407f28847a8SJon Lin  * [0b0000, 0b0011], No bit errors were detected;
408f28847a8SJon Lin  * [0b0100, 0b0111], Bit errors were detected and corrected. Not
4096281205aSDingqiang Lin  *	reach Flipping Bits;
410f28847a8SJon Lin  * [0b1000, 0b1011], Multiple bit errors were detected and
4116281205aSDingqiang Lin  *	not corrected.
412f28847a8SJon Lin  * [0b1100, 0b1111], Bit error count equals the bit flip
4136281205aSDingqiang Lin  *	detectio nthreshold
4146281205aSDingqiang Lin  */
415f28847a8SJon Lin static u32 sfc_nand_get_ecc_status3(void)
4166281205aSDingqiang Lin {
41758463f4dSJon Lin 	u32 ret;
4186281205aSDingqiang Lin 	u32 i;
4196281205aSDingqiang Lin 	u8 ecc;
4206281205aSDingqiang Lin 	u8 status, status1;
4216281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
4226281205aSDingqiang Lin 
4236281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
4246281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
425f28847a8SJon Lin 
4266281205aSDingqiang Lin 		if (ret != SFC_OK)
4276281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
428f28847a8SJon Lin 
4296281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xF0, &status1);
430f28847a8SJon Lin 
4316281205aSDingqiang Lin 		if (ret != SFC_OK)
4326281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
433f28847a8SJon Lin 
4346281205aSDingqiang Lin 		if (!(status & (1 << 0)))
4356281205aSDingqiang Lin 			break;
436f28847a8SJon Lin 
4376281205aSDingqiang Lin 		sfc_delay(1);
4386281205aSDingqiang Lin 	}
4396281205aSDingqiang Lin 
4406281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
4416281205aSDingqiang Lin 	ecc = (ecc << 2) | ((status1 >> 4) & 0x03);
442f28847a8SJon Lin 
4436281205aSDingqiang Lin 	if (ecc < 7)
4446281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
4456281205aSDingqiang Lin 	else if (ecc == 7 || ecc >= 12)
4466281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
4476281205aSDingqiang Lin 	else
44858463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
4496281205aSDingqiang Lin 
4506281205aSDingqiang Lin 	return ret;
4516281205aSDingqiang Lin }
4526281205aSDingqiang Lin 
45325098c06SDingqiang Lin /*
45425098c06SDingqiang Lin  * ecc spectial type4:
455a6fcac41SJon Lin  * ecc bits: 0xC0[2,5]
456f28847a8SJon Lin  * [0b0000], No bit errors were detected;
457f28847a8SJon Lin  * [0b0001, 0b0111], Bit errors were detected and corrected. Not
45825098c06SDingqiang Lin  *	reach Flipping Bits;
459f28847a8SJon Lin  * [0b1000], Multiple bit errors were detected and
46025098c06SDingqiang Lin  *	not corrected.
461f28847a8SJon Lin  * [0b1100], Bit error count equals the bit flip
46225098c06SDingqiang Lin  *	detectionthreshold
46325098c06SDingqiang Lin  * else, reserved
46425098c06SDingqiang Lin  */
465f28847a8SJon Lin static u32 sfc_nand_get_ecc_status4(void)
46625098c06SDingqiang Lin {
46758463f4dSJon Lin 	u32 ret;
46825098c06SDingqiang Lin 	u32 i;
46925098c06SDingqiang Lin 	u8 ecc;
47025098c06SDingqiang Lin 	u8 status;
47125098c06SDingqiang Lin 	u32 timeout = 1000 * 1000;
47225098c06SDingqiang Lin 
47325098c06SDingqiang Lin 	for (i = 0; i < timeout; i++) {
47425098c06SDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
475f28847a8SJon Lin 
47625098c06SDingqiang Lin 		if (ret != SFC_OK)
47725098c06SDingqiang Lin 			return SFC_NAND_ECC_ERROR;
478f28847a8SJon Lin 
47925098c06SDingqiang Lin 		if (!(status & (1 << 0)))
48025098c06SDingqiang Lin 			break;
481f28847a8SJon Lin 
48225098c06SDingqiang Lin 		sfc_delay(1);
48325098c06SDingqiang Lin 	}
48425098c06SDingqiang Lin 
48525098c06SDingqiang Lin 	ecc = (status >> 2) & 0x0f;
486f28847a8SJon Lin 
48725098c06SDingqiang Lin 	if (ecc < 7)
48825098c06SDingqiang Lin 		ret = SFC_NAND_ECC_OK;
48925098c06SDingqiang Lin 	else if (ecc == 7 || ecc == 12)
49025098c06SDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
49125098c06SDingqiang Lin 	else
49258463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
49325098c06SDingqiang Lin 
49425098c06SDingqiang Lin 	return ret;
49525098c06SDingqiang Lin }
49625098c06SDingqiang Lin 
49725098c06SDingqiang Lin /*
49825098c06SDingqiang Lin  * ecc spectial type5:
499a6fcac41SJon Lin  * ecc bits: 0xC0[4,6]
500f28847a8SJon Lin  * [0b000], No bit errors were detected;
501f28847a8SJon Lin  * [0b001, 0b011], Bit errors were detected and corrected. Not
50225098c06SDingqiang Lin  *	reach Flipping Bits;
503f28847a8SJon Lin  * [0b100], Bit error count equals the bit flip
50425098c06SDingqiang Lin  *	detectionthreshold
505f28847a8SJon Lin  * [0b101, 0b110], Reserved;
506f28847a8SJon Lin  * [0b111], Multiple bit errors were detected and
50725098c06SDingqiang Lin  *	not corrected.
50825098c06SDingqiang Lin  */
509f28847a8SJon Lin static u32 sfc_nand_get_ecc_status5(void)
51025098c06SDingqiang Lin {
51158463f4dSJon Lin 	u32 ret;
51225098c06SDingqiang Lin 	u32 i;
51325098c06SDingqiang Lin 	u8 ecc;
51425098c06SDingqiang Lin 	u8 status;
51525098c06SDingqiang Lin 	u32 timeout = 1000 * 1000;
51625098c06SDingqiang Lin 
51725098c06SDingqiang Lin 	for (i = 0; i < timeout; i++) {
51825098c06SDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
519f28847a8SJon Lin 
52025098c06SDingqiang Lin 		if (ret != SFC_OK)
52125098c06SDingqiang Lin 			return SFC_NAND_ECC_ERROR;
522f28847a8SJon Lin 
52325098c06SDingqiang Lin 		if (!(status & (1 << 0)))
52425098c06SDingqiang Lin 			break;
525f28847a8SJon Lin 
52625098c06SDingqiang Lin 		sfc_delay(1);
52725098c06SDingqiang Lin 	}
52825098c06SDingqiang Lin 
52925098c06SDingqiang Lin 	ecc = (status >> 4) & 0x07;
530f28847a8SJon Lin 
53125098c06SDingqiang Lin 	if (ecc < 4)
53225098c06SDingqiang Lin 		ret = SFC_NAND_ECC_OK;
53325098c06SDingqiang Lin 	else if (ecc == 4)
53425098c06SDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
53525098c06SDingqiang Lin 	else
53658463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
53725098c06SDingqiang Lin 
53825098c06SDingqiang Lin 	return ret;
53925098c06SDingqiang Lin }
54025098c06SDingqiang Lin 
541f28847a8SJon Lin /*
542f28847a8SJon Lin  * ecc spectial type6:
543f28847a8SJon Lin  * ecc bits: 0xC0[4,6]
544f28847a8SJon Lin  * [0b000], No bit errors were detected;
545f28847a8SJon Lin  * [0b001], 1-3 Bit errors were detected and corrected. Not
546f28847a8SJon Lin  *	reach Flipping Bits;
547f28847a8SJon Lin  * [0b010], Multiple bit errors were detected and
548f28847a8SJon Lin  *	not corrected.
549f28847a8SJon Lin  * [0b011], 4-6 Bit errors were detected and corrected. Not
550f28847a8SJon Lin  *	reach Flipping Bits;
551f28847a8SJon Lin  * [0b101], Bit error count equals the bit flip
552f28847a8SJon Lin  *	detectionthreshold
553f28847a8SJon Lin  * others, Reserved.
554f28847a8SJon Lin  */
555f28847a8SJon Lin static u32 sfc_nand_get_ecc_status6(void)
556f28847a8SJon Lin {
557f28847a8SJon Lin 	u32 ret;
558f28847a8SJon Lin 	u32 i;
559f28847a8SJon Lin 	u8 ecc;
560f28847a8SJon Lin 	u8 status;
561f28847a8SJon Lin 	u32 timeout = 1000 * 1000;
562f28847a8SJon Lin 
563f28847a8SJon Lin 	for (i = 0; i < timeout; i++) {
564f28847a8SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
565f28847a8SJon Lin 
566f28847a8SJon Lin 		if (ret != SFC_OK)
567f28847a8SJon Lin 			return SFC_NAND_ECC_ERROR;
568f28847a8SJon Lin 
569f28847a8SJon Lin 		if (!(status & (1 << 0)))
570f28847a8SJon Lin 			break;
571f28847a8SJon Lin 
572f28847a8SJon Lin 		sfc_delay(1);
573f28847a8SJon Lin 	}
574f28847a8SJon Lin 
575f28847a8SJon Lin 	ecc = (status >> 4) & 0x07;
576f28847a8SJon Lin 
577f28847a8SJon Lin 	if (ecc == 0 || ecc == 1 || ecc == 3)
578f28847a8SJon Lin 		ret = SFC_NAND_ECC_OK;
579f28847a8SJon Lin 	else if (ecc == 5)
580f28847a8SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
581f28847a8SJon Lin 	else
582f28847a8SJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
583f28847a8SJon Lin 
584f28847a8SJon Lin 	return ret;
585f28847a8SJon Lin }
586f28847a8SJon Lin 
587*362b1be1SJon Lin /*
588*362b1be1SJon Lin  * ecc spectial type7:
589*362b1be1SJon Lin  * ecc bits: 0xC0[4,7]
590*362b1be1SJon Lin  * [0b0000], No bit errors were detected;
591*362b1be1SJon Lin  * [0b0001, 0b0111], 1-7 Bit errors were detected and corrected. Not
592*362b1be1SJon Lin  *	reach Flipping Bits;
593*362b1be1SJon Lin  * [0b1000], 8 Bit errors were detected and corrected. Bit error count
594*362b1be1SJon Lin  * 	equals the bit flip detectionthreshold;
595*362b1be1SJon Lin  * [0b1111], Bit errors greater than ECC capability(8 bits) and not corrected;
596*362b1be1SJon Lin  * others, Reserved.
597*362b1be1SJon Lin  */
598*362b1be1SJon Lin static u32 sfc_nand_get_ecc_status7(void)
599*362b1be1SJon Lin {
600*362b1be1SJon Lin 	u32 ret;
601*362b1be1SJon Lin 	u32 i;
602*362b1be1SJon Lin 	u8 ecc;
603*362b1be1SJon Lin 	u8 status;
604*362b1be1SJon Lin 	u32 timeout = 1000 * 1000;
605*362b1be1SJon Lin 
606*362b1be1SJon Lin 	for (i = 0; i < timeout; i++) {
607*362b1be1SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
608*362b1be1SJon Lin 
609*362b1be1SJon Lin 		if (ret != SFC_OK)
610*362b1be1SJon Lin 			return SFC_NAND_ECC_ERROR;
611*362b1be1SJon Lin 
612*362b1be1SJon Lin 		if (!(status & (1 << 0)))
613*362b1be1SJon Lin 			break;
614*362b1be1SJon Lin 
615*362b1be1SJon Lin 		sfc_delay(1);
616*362b1be1SJon Lin 	}
617*362b1be1SJon Lin 
618*362b1be1SJon Lin 	ecc = (status >> 4) & 0xf;
619*362b1be1SJon Lin 
620*362b1be1SJon Lin 	if (ecc < 7)
621*362b1be1SJon Lin 		ret = SFC_NAND_ECC_OK;
622*362b1be1SJon Lin 	else if (ecc == 7 || ecc == 8)
623*362b1be1SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
624*362b1be1SJon Lin 	else
625*362b1be1SJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
626*362b1be1SJon Lin 
627*362b1be1SJon Lin 	return ret;
628*362b1be1SJon Lin }
629*362b1be1SJon Lin 
630c84f0ed8SJon Lin u32 sfc_nand_erase_block(u8 cs, u32 addr)
631ba0501acSDingqiang Lin {
632ba0501acSDingqiang Lin 	int ret;
63358463f4dSJon Lin 	struct rk_sfc_op op;
634ba0501acSDingqiang Lin 	u8 status;
635ba0501acSDingqiang Lin 
636c84f0ed8SJon Lin 	rkflash_print_dio("%s %x\n", __func__, addr);
63758463f4dSJon Lin 	op.sfcmd.d32 = 0;
638f28847a8SJon Lin 	op.sfcmd.b.cmd = 0xd8;
63958463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_24BITS;
64058463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
64158463f4dSJon Lin 
64258463f4dSJon Lin 	op.sfctrl.d32 = 0;
64358463f4dSJon Lin 
644ba0501acSDingqiang Lin 	sfc_nand_write_en();
64558463f4dSJon Lin 	ret = sfc_request(&op, addr, NULL, 0);
646f28847a8SJon Lin 
647ba0501acSDingqiang Lin 	if (ret != SFC_OK)
648ba0501acSDingqiang Lin 		return ret;
649f28847a8SJon Lin 
650ba0501acSDingqiang Lin 	ret = sfc_nand_wait_busy(&status, 1000 * 1000);
651f28847a8SJon Lin 
652ba0501acSDingqiang Lin 	if (status & (1 << 2))
653ba0501acSDingqiang Lin 		return SFC_NAND_PROG_ERASE_ERROR;
654c84f0ed8SJon Lin 
655ba0501acSDingqiang Lin 	return ret;
656ba0501acSDingqiang Lin }
657ba0501acSDingqiang Lin 
658f28847a8SJon Lin u32 sfc_nand_prog_page_raw(u8 cs, u32 addr, u32 *p_page_buf)
659ba0501acSDingqiang Lin {
660ba0501acSDingqiang Lin 	int ret;
661415cf080Sjon.lin 	u32 plane;
66258463f4dSJon Lin 	struct rk_sfc_op op;
663ba0501acSDingqiang Lin 	u8 status;
66458463f4dSJon Lin 	u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page;
665ba0501acSDingqiang Lin 
666c84f0ed8SJon Lin 	rkflash_print_dio("%s %x %x\n", __func__, addr, p_page_buf[0]);
667ba0501acSDingqiang Lin 	sfc_nand_write_en();
668f28847a8SJon Lin 
669ba0501acSDingqiang Lin 	if (sfc_nand_dev.prog_lines == DATA_LINES_X4 &&
67025098c06SDingqiang Lin 	    p_nand_info->feature & FEA_SOFT_QOP_BIT &&
67125098c06SDingqiang Lin 	    sfc_get_version() < SFC_VER_3)
672ba0501acSDingqiang Lin 		sfc_nand_rw_preset();
673ba0501acSDingqiang Lin 
67458463f4dSJon Lin 	op.sfcmd.d32 = 0;
67558463f4dSJon Lin 	op.sfcmd.b.cmd = sfc_nand_dev.page_prog_cmd;
67658463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
67758463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
678ba0501acSDingqiang Lin 
67958463f4dSJon Lin 	op.sfctrl.d32 = 0;
68058463f4dSJon Lin 	op.sfctrl.b.datalines = sfc_nand_dev.prog_lines;
68158463f4dSJon Lin 	op.sfctrl.b.addrbits = 16;
682415cf080Sjon.lin 	plane = p_nand_info->plane_per_die == 2 ? ((addr >> 6) & 0x1) << 12 : 0;
68358463f4dSJon Lin 	sfc_request(&op, plane, p_page_buf, page_size);
684ba0501acSDingqiang Lin 
68558463f4dSJon Lin 	op.sfcmd.d32 = 0;
686f28847a8SJon Lin 	op.sfcmd.b.cmd = 0x10;
68758463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_24BITS;
68858463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
68958463f4dSJon Lin 
69058463f4dSJon Lin 	op.sfctrl.d32 = 0;
69158463f4dSJon Lin 	ret = sfc_request(&op, addr, p_page_buf, 0);
692f28847a8SJon Lin 
693ba0501acSDingqiang Lin 	if (ret != SFC_OK)
694ba0501acSDingqiang Lin 		return ret;
695f28847a8SJon Lin 
696ba0501acSDingqiang Lin 	ret = sfc_nand_wait_busy(&status, 1000 * 1000);
697f28847a8SJon Lin 
698ba0501acSDingqiang Lin 	if (status & (1 << 3))
699ba0501acSDingqiang Lin 		return SFC_NAND_PROG_ERASE_ERROR;
700c84f0ed8SJon Lin 
701ba0501acSDingqiang Lin 	return ret;
702ba0501acSDingqiang Lin }
703ba0501acSDingqiang Lin 
704c84f0ed8SJon Lin u32 sfc_nand_prog_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare)
705c84f0ed8SJon Lin {
706c84f0ed8SJon Lin 	int ret;
707c84f0ed8SJon Lin 	u32 sec_per_page = p_nand_info->sec_per_page;
708c84f0ed8SJon Lin 	u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE;
709a6fcac41SJon Lin 	struct nand_mega_area *meta = &p_nand_info->meta;
710c84f0ed8SJon Lin 
711c84f0ed8SJon Lin 	memcpy(gp_page_buf, p_data, data_size);
712c84f0ed8SJon Lin 	memset(&gp_page_buf[data_size / 4], 0xff, sec_per_page * 16);
713a6fcac41SJon Lin 	gp_page_buf[(data_size + meta->off0) / 4] = p_spare[0];
714a6fcac41SJon Lin 	gp_page_buf[(data_size + meta->off1) / 4] = p_spare[1];
715f28847a8SJon Lin 
716c84f0ed8SJon Lin 	if (sec_per_page == 8) {
717a6fcac41SJon Lin 		gp_page_buf[(data_size + meta->off2) / 4] = p_spare[2];
718a6fcac41SJon Lin 		gp_page_buf[(data_size + meta->off3) / 4] = p_spare[3];
719c84f0ed8SJon Lin 	}
720f28847a8SJon Lin 
721c84f0ed8SJon Lin 	ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf);
722c84f0ed8SJon Lin 
723c84f0ed8SJon Lin 	return ret;
724c84f0ed8SJon Lin }
725c84f0ed8SJon Lin 
726a80fd396SJon Lin u32 sfc_nand_read(u32 row, u32 *p_page_buf, u32 column, u32 len)
727ba0501acSDingqiang Lin {
728ba0501acSDingqiang Lin 	int ret;
729415cf080Sjon.lin 	u32 plane;
73058463f4dSJon Lin 	struct rk_sfc_op op;
7316281205aSDingqiang Lin 	u32 ecc_result;
732a6fcac41SJon Lin 	u8 status;
733ba0501acSDingqiang Lin 
73458463f4dSJon Lin 	op.sfcmd.d32 = 0;
735f28847a8SJon Lin 	op.sfcmd.b.cmd = 0x13;
73658463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
73758463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_24BITS;
73858463f4dSJon Lin 
73958463f4dSJon Lin 	op.sfctrl.d32 = 0;
74058463f4dSJon Lin 
741a80fd396SJon Lin 	sfc_request(&op, row, p_page_buf, 0);
742f28847a8SJon Lin 
743ba0501acSDingqiang Lin 	if (sfc_nand_dev.read_lines == DATA_LINES_X4 &&
74425098c06SDingqiang Lin 	    p_nand_info->feature & FEA_SOFT_QOP_BIT &&
74525098c06SDingqiang Lin 	    sfc_get_version() < SFC_VER_3)
746ba0501acSDingqiang Lin 		sfc_nand_rw_preset();
747ba0501acSDingqiang Lin 
748a6fcac41SJon Lin 	sfc_nand_wait_busy(&status, 1000 * 1000);
749a6fcac41SJon Lin 	ecc_result = p_nand_info->ecc_status();
750a6fcac41SJon Lin 
75158463f4dSJon Lin 	op.sfcmd.d32 = 0;
75258463f4dSJon Lin 	op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd;
753a80fd396SJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
754a80fd396SJon Lin 	op.sfcmd.b.dummybits = 8;
75558463f4dSJon Lin 
75658463f4dSJon Lin 	op.sfctrl.d32 = 0;
75758463f4dSJon Lin 	op.sfctrl.b.datalines = sfc_nand_dev.read_lines;
758a80fd396SJon Lin 	op.sfctrl.b.addrbits = 16;
759ba0501acSDingqiang Lin 
760a80fd396SJon Lin 	plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0;
761a80fd396SJon Lin 	ret = sfc_request(&op, plane | column, p_page_buf, len);
762a80fd396SJon Lin 	rkflash_print_dio("%s %x %x\n", __func__, row, p_page_buf[0]);
763c84f0ed8SJon Lin 
764c84f0ed8SJon Lin 	if (ret != SFC_OK)
765f28847a8SJon Lin 		return SFC_NAND_HW_ERROR;
766c84f0ed8SJon Lin 
767c84f0ed8SJon Lin 	return ecc_result;
768c84f0ed8SJon Lin }
769c84f0ed8SJon Lin 
770a80fd396SJon Lin u32 sfc_nand_read_page_raw(u8 cs, u32 addr, u32 *p_page_buf)
771a80fd396SJon Lin {
772a80fd396SJon Lin 	u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page;
773a80fd396SJon Lin 
774a80fd396SJon Lin 	return sfc_nand_read(addr, p_page_buf, 0, page_size);
775a80fd396SJon Lin }
776a80fd396SJon Lin 
777c84f0ed8SJon Lin u32 sfc_nand_read_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare)
778c84f0ed8SJon Lin {
77958463f4dSJon Lin 	u32 ret;
780c84f0ed8SJon Lin 	u32 sec_per_page = p_nand_info->sec_per_page;
781c84f0ed8SJon Lin 	u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE;
782a6fcac41SJon Lin 	struct nand_mega_area *meta = &p_nand_info->meta;
783c84f0ed8SJon Lin 
784c84f0ed8SJon Lin 	ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf);
785f25e3cafSJon Lin 	memcpy(p_data, gp_page_buf, data_size);
786a6fcac41SJon Lin 	p_spare[0] = gp_page_buf[(data_size + meta->off0) / 4];
787a6fcac41SJon Lin 	p_spare[1] = gp_page_buf[(data_size + meta->off1) / 4];
788f28847a8SJon Lin 
789f25e3cafSJon Lin 	if (p_nand_info->sec_per_page == 8) {
790a6fcac41SJon Lin 		p_spare[2] = gp_page_buf[(data_size + meta->off2) / 4];
791a6fcac41SJon Lin 		p_spare[3] = gp_page_buf[(data_size + meta->off3) / 4];
792f25e3cafSJon Lin 	}
793ba0501acSDingqiang Lin 
794f28847a8SJon Lin 	if (ret == SFC_NAND_HW_ERROR)
795f28847a8SJon Lin 		ret = SFC_NAND_ECC_ERROR;
796f28847a8SJon Lin 
797c84f0ed8SJon Lin 	if (ret != SFC_NAND_ECC_OK) {
798c84f0ed8SJon Lin 		rkflash_print_error("%s[0x%x], ret=0x%x\n", __func__, addr, ret);
799f28847a8SJon Lin 
800ba0501acSDingqiang Lin 		if (p_data)
801c84f0ed8SJon Lin 			rkflash_print_hex("data:", p_data, 4, 8);
802f28847a8SJon Lin 
803ba0501acSDingqiang Lin 		if (p_spare)
804c84f0ed8SJon Lin 			rkflash_print_hex("spare:", p_spare, 4, 2);
805ba0501acSDingqiang Lin 	}
806f25e3cafSJon Lin 
807c84f0ed8SJon Lin 	return ret;
808ba0501acSDingqiang Lin }
809ba0501acSDingqiang Lin 
810c84f0ed8SJon Lin u32 sfc_nand_check_bad_block(u8 cs, u32 addr)
811c84f0ed8SJon Lin {
812c84f0ed8SJon Lin 	u32 ret;
813c84f0ed8SJon Lin 	u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE;
814a80fd396SJon Lin 	u32 marker = 0;
815c84f0ed8SJon Lin 
816a80fd396SJon Lin 	ret = sfc_nand_read(addr, &marker, data_size, 2);
817f28847a8SJon Lin 
818f28847a8SJon Lin 	/* unify with mtd framework */
819a6fcac41SJon Lin 	if (ret == SFC_NAND_ECC_ERROR)
820a80fd396SJon Lin 		rkflash_print_error("%s page= %x ret= %x spare= %x\n",
821a80fd396SJon Lin 				    __func__, addr, ret, marker);
822f28847a8SJon Lin 
823c84f0ed8SJon Lin 	/* Original bad block */
824a80fd396SJon Lin 	if ((u16)marker != 0xffff)
825c84f0ed8SJon Lin 		return true;
826c84f0ed8SJon Lin 
827c84f0ed8SJon Lin 	return false;
828c84f0ed8SJon Lin }
829c84f0ed8SJon Lin 
830c84f0ed8SJon Lin u32 sfc_nand_mark_bad_block(u8 cs, u32 addr)
831c84f0ed8SJon Lin {
832c84f0ed8SJon Lin 	u32 ret;
833c84f0ed8SJon Lin 	u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE;
834c84f0ed8SJon Lin 
835c84f0ed8SJon Lin 	ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf);
836f28847a8SJon Lin 
837c84f0ed8SJon Lin 	if (ret)
838c84f0ed8SJon Lin 		return SFC_NAND_HW_ERROR;
839f28847a8SJon Lin 
840c84f0ed8SJon Lin 	gp_page_buf[data_size / 4] = 0x0;
841c84f0ed8SJon Lin 	ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf);
842f28847a8SJon Lin 
843c84f0ed8SJon Lin 	if (ret)
844c84f0ed8SJon Lin 		return SFC_NAND_HW_ERROR;
845c84f0ed8SJon Lin 
846c84f0ed8SJon Lin 	return ret;
847c84f0ed8SJon Lin }
848c84f0ed8SJon Lin 
849c84f0ed8SJon Lin int sfc_nand_read_id(u8 *data)
850ba0501acSDingqiang Lin {
851ba0501acSDingqiang Lin 	int ret;
85258463f4dSJon Lin 	struct rk_sfc_op op;
853ba0501acSDingqiang Lin 
85458463f4dSJon Lin 	op.sfcmd.d32 = 0;
85558463f4dSJon Lin 	op.sfcmd.b.cmd = CMD_READ_JEDECID;
85658463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
857ba0501acSDingqiang Lin 
85858463f4dSJon Lin 	op.sfctrl.d32 = 0;
85958463f4dSJon Lin 	op.sfctrl.b.addrbits = 8;
86058463f4dSJon Lin 
86158463f4dSJon Lin 	ret = sfc_request(&op, 0, data, 3);
862ba0501acSDingqiang Lin 
863ba0501acSDingqiang Lin 	return ret;
864ba0501acSDingqiang Lin }
865ba0501acSDingqiang Lin 
866ba0501acSDingqiang Lin /*
867ba0501acSDingqiang Lin  * Read the 1st page's 1st byte of a phy_blk
868ba0501acSDingqiang Lin  * If not FF, it's bad blk
869ba0501acSDingqiang Lin  */
870ba0501acSDingqiang Lin static int sfc_nand_get_bad_block_list(u16 *table, u32 die)
871ba0501acSDingqiang Lin {
872ba0501acSDingqiang Lin 	u32 bad_cnt, page;
873ba0501acSDingqiang Lin 	u32 blk_per_die;
8742ac88c1bSJon Lin 	u16 blk;
875ba0501acSDingqiang Lin 
876c84f0ed8SJon Lin 	rkflash_print_info("%s\n", __func__);
877c84f0ed8SJon Lin 
878ba0501acSDingqiang Lin 	bad_cnt = 0;
879ba0501acSDingqiang Lin 	blk_per_die = p_nand_info->plane_per_die *
880ba0501acSDingqiang Lin 		      p_nand_info->blk_per_plane;
881f28847a8SJon Lin 
882ba0501acSDingqiang Lin 	for (blk = 0; blk < blk_per_die; blk++) {
883ba0501acSDingqiang Lin 		page = (blk + blk_per_die * die) *
884ba0501acSDingqiang Lin 		       p_nand_info->page_per_blk;
885ba0501acSDingqiang Lin 
8862ac88c1bSJon Lin 		if (sfc_nand_check_bad_block(die, page)) {
887ba0501acSDingqiang Lin 			table[bad_cnt++] = blk;
888c84f0ed8SJon Lin 			rkflash_print_error("die[%d], bad_blk[%d]\n", die, blk);
889ba0501acSDingqiang Lin 		}
890ba0501acSDingqiang Lin 	}
891f28847a8SJon Lin 
892ba0501acSDingqiang Lin 	return (int)bad_cnt;
893ba0501acSDingqiang Lin }
894ba0501acSDingqiang Lin 
895c84f0ed8SJon Lin void sfc_nand_ftl_ops_init(void)
896ba0501acSDingqiang Lin {
897ba0501acSDingqiang Lin 	/* para init */
898ba0501acSDingqiang Lin 	g_nand_phy_info.nand_type	= 1;
899ba0501acSDingqiang Lin 	g_nand_phy_info.die_num		= 1;
900ba0501acSDingqiang Lin 	g_nand_phy_info.plane_per_die	= p_nand_info->plane_per_die;
901ba0501acSDingqiang Lin 	g_nand_phy_info.blk_per_plane	= p_nand_info->blk_per_plane;
902ba0501acSDingqiang Lin 	g_nand_phy_info.page_per_blk	= p_nand_info->page_per_blk;
903ba0501acSDingqiang Lin 	g_nand_phy_info.page_per_slc_blk = p_nand_info->page_per_blk;
904c84f0ed8SJon Lin 	g_nand_phy_info.byte_per_sec	= SFC_NAND_SECTOR_SIZE;
905ba0501acSDingqiang Lin 	g_nand_phy_info.sec_per_page	= p_nand_info->sec_per_page;
906ba0501acSDingqiang Lin 	g_nand_phy_info.sec_per_blk	= p_nand_info->sec_per_page *
907ba0501acSDingqiang Lin 					  p_nand_info->page_per_blk;
908ba0501acSDingqiang Lin 	g_nand_phy_info.reserved_blk	= 8;
909ba0501acSDingqiang Lin 	g_nand_phy_info.blk_per_die	= p_nand_info->plane_per_die *
910ba0501acSDingqiang Lin 					  p_nand_info->blk_per_plane;
911ba0501acSDingqiang Lin 	g_nand_phy_info.ecc_bits	= p_nand_info->max_ecc_bits;
912ba0501acSDingqiang Lin 
913ba0501acSDingqiang Lin 	/* driver register */
914ba0501acSDingqiang Lin 	g_nand_ops.get_bad_blk_list	= sfc_nand_get_bad_block_list;
915ba0501acSDingqiang Lin 	g_nand_ops.erase_blk		= sfc_nand_erase_block;
916ba0501acSDingqiang Lin 	g_nand_ops.prog_page		= sfc_nand_prog_page;
917ba0501acSDingqiang Lin 	g_nand_ops.read_page		= sfc_nand_read_page;
91857d18453Sjon.lin 	g_nand_ops.bch_sel		= NULL;
919ba0501acSDingqiang Lin }
920ba0501acSDingqiang Lin 
921a6fcac41SJon Lin static int sfc_nand_enable_QE(void)
922ba0501acSDingqiang Lin {
923ba0501acSDingqiang Lin 	int ret = SFC_OK;
924ba0501acSDingqiang Lin 	u8 status;
925ba0501acSDingqiang Lin 
926f28847a8SJon Lin 	ret = sfc_nand_read_feature(0xB0, &status);
927ba0501acSDingqiang Lin 
928ba0501acSDingqiang Lin 	if (ret != SFC_OK)
929ba0501acSDingqiang Lin 		return ret;
930ba0501acSDingqiang Lin 
931f28847a8SJon Lin 	if (status & 1)   /* is QE bit set */
932ba0501acSDingqiang Lin 		return SFC_OK;
933ba0501acSDingqiang Lin 
934f28847a8SJon Lin 	status |= 1;
935ba0501acSDingqiang Lin 
936f28847a8SJon Lin 	return sfc_nand_write_feature(0xB0, status);
937ba0501acSDingqiang Lin }
938ba0501acSDingqiang Lin 
939ba0501acSDingqiang Lin u32 sfc_nand_init(void)
940ba0501acSDingqiang Lin {
941c84f0ed8SJon Lin 	u8 status, id_byte[8];
942ba0501acSDingqiang Lin 
943c84f0ed8SJon Lin 	sfc_nand_read_id(id_byte);
944c84f0ed8SJon Lin 	rkflash_print_error("sfc_nand id: %x %x %x\n",
945ba0501acSDingqiang Lin 			    id_byte[0], id_byte[1], id_byte[2]);
946f28847a8SJon Lin 
947ba0501acSDingqiang Lin 	if (id_byte[0] == 0xFF || id_byte[0] == 0x00)
94858463f4dSJon Lin 		return (u32)FTL_NO_FLASH;
949ba0501acSDingqiang Lin 
950a6fcac41SJon Lin 	p_nand_info = sfc_nand_get_info(id_byte);
951f28847a8SJon Lin 
952ba0501acSDingqiang Lin 	if (!p_nand_info)
95358463f4dSJon Lin 		return (u32)FTL_UNSUPPORTED_FLASH;
954ba0501acSDingqiang Lin 
955ba0501acSDingqiang Lin 	sfc_nand_dev.manufacturer = id_byte[0];
956ba0501acSDingqiang Lin 	sfc_nand_dev.mem_type = id_byte[1];
957c84f0ed8SJon Lin 	sfc_nand_dev.capacity = p_nand_info->density;
958c84f0ed8SJon Lin 	sfc_nand_dev.block_size = p_nand_info->page_per_blk * p_nand_info->sec_per_page;
959c84f0ed8SJon Lin 	sfc_nand_dev.page_size = p_nand_info->sec_per_page;
960ba0501acSDingqiang Lin 
961ba0501acSDingqiang Lin 	/* disable block lock */
962ba0501acSDingqiang Lin 	sfc_nand_write_feature(0xA0, 0);
963ba0501acSDingqiang Lin 	sfc_nand_dev.read_lines = DATA_LINES_X1;
964ba0501acSDingqiang Lin 	sfc_nand_dev.prog_lines = DATA_LINES_X1;
965f28847a8SJon Lin 	sfc_nand_dev.page_read_cmd = 0x03;
966f28847a8SJon Lin 	sfc_nand_dev.page_prog_cmd = 0x02;
967f28847a8SJon Lin 
968ba0501acSDingqiang Lin 	if (p_nand_info->feature & FEA_4BIT_READ) {
969f28847a8SJon Lin 		if ((p_nand_info->has_qe_bits && sfc_nand_enable_QE() == SFC_OK) ||
970f28847a8SJon Lin 		    !p_nand_info->has_qe_bits) {
971ba0501acSDingqiang Lin 			sfc_nand_dev.read_lines = DATA_LINES_X4;
972f28847a8SJon Lin 			sfc_nand_dev.page_read_cmd = 0x6b;
973ba0501acSDingqiang Lin 		}
974ba0501acSDingqiang Lin 	}
975ba0501acSDingqiang Lin 
976ba0501acSDingqiang Lin 	if (p_nand_info->feature & FEA_4BIT_PROG &&
977ba0501acSDingqiang Lin 	    sfc_nand_dev.read_lines == DATA_LINES_X4) {
978ba0501acSDingqiang Lin 		sfc_nand_dev.prog_lines = DATA_LINES_X4;
979f28847a8SJon Lin 		sfc_nand_dev.page_prog_cmd = 0x32;
980ba0501acSDingqiang Lin 	}
981ba0501acSDingqiang Lin 
982ba0501acSDingqiang Lin 	sfc_nand_read_feature(0xA0, &status);
983c84f0ed8SJon Lin 	rkflash_print_info("sfc_nand A0 = 0x%x\n", status);
984ba0501acSDingqiang Lin 	sfc_nand_read_feature(0xB0, &status);
985c84f0ed8SJon Lin 	rkflash_print_info("sfc_nand B0 = 0x%x\n", status);
986c84f0ed8SJon Lin 	rkflash_print_info("read_lines = %x\n", sfc_nand_dev.read_lines);
987c84f0ed8SJon Lin 	rkflash_print_info("prog_lines = %x\n", sfc_nand_dev.prog_lines);
988c84f0ed8SJon Lin 	rkflash_print_info("page_read_cmd = %x\n", sfc_nand_dev.page_read_cmd);
989c84f0ed8SJon Lin 	rkflash_print_info("page_prog_cmd = %x\n", sfc_nand_dev.page_prog_cmd);
990ba0501acSDingqiang Lin 
991ba0501acSDingqiang Lin 	return SFC_OK;
992ba0501acSDingqiang Lin }
993ba0501acSDingqiang Lin 
994c84f0ed8SJon Lin void sfc_nand_deinit(void)
995ba0501acSDingqiang Lin {
996c84f0ed8SJon Lin 	/* to-do */
997ba0501acSDingqiang Lin }
998c84f0ed8SJon Lin 
999c84f0ed8SJon Lin struct SFNAND_DEV *sfc_nand_get_private_dev(void)
1000c84f0ed8SJon Lin {
1001c84f0ed8SJon Lin 	return &sfc_nand_dev;
1002c84f0ed8SJon Lin }
1003c84f0ed8SJon Lin 
1004