xref: /rk3399_rockchip-uboot/drivers/rkflash/sfc_nand.c (revision d4db0b8d91ed26ee68e33d2d4627374ca4576a43)
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);
24362b1be1SJon Lin static u32 sfc_nand_get_ecc_status7(void);
25629111d3SJon Lin static u32 sfc_nand_get_ecc_status8(void);
26*d4db0b8dSJon Lin static u32 sfc_nand_get_ecc_status9(void);
27f28847a8SJon Lin 
28ba0501acSDingqiang Lin static struct nand_info spi_nand_tbl[] = {
29ba0501acSDingqiang Lin 	/* TC58CVG0S0HxAIx */
30b833c879SJon Lin 	{ 0x98, 0xC2, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
31ba0501acSDingqiang Lin 	/* TC58CVG1S0HxAIx */
32b833c879SJon Lin 	{ 0x98, 0xCB, 0x00, 4, 0x40, 2, 1024, 0x00, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
33a6fcac41SJon Lin 	/* TC58CVG2S0HRAIJ */
34b833c879SJon Lin 	{ 0x98, 0xED, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 0, { 0x04, 0x0C, 0x08, 0x10 }, &sfc_nand_get_ecc_status0 },
35a6fcac41SJon Lin 	/* TC58CVG1S3HRAIJ */
36b833c879SJon Lin 	{ 0x98, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
37a6fcac41SJon Lin 	/* TC58CVG0S3HRAIJ */
38b833c879SJon Lin 	{ 0x98, 0xE2, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
39f28847a8SJon Lin 
40f28847a8SJon Lin 	/* MX35LF1GE4AB */
41b833c879SJon Lin 	{ 0xC2, 0x12, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
42f28847a8SJon Lin 	/* MX35LF2GE4AB */
43b833c879SJon Lin 	{ 0xC2, 0x22, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
44f28847a8SJon Lin 	/* MX35LF2GE4AD */
45b833c879SJon Lin 	{ 0xC2, 0x26, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
46f28847a8SJon Lin 	/* MX35LF4GE4AD */
47362b1be1SJon Lin 	{ 0xC2, 0x37, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status0 },
48362b1be1SJon Lin 	/* MX35UF1GE4AC */
49362b1be1SJon Lin 	{ 0xC2, 0x92, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
50362b1be1SJon Lin 	/* MX35UF2GE4AC */
51362b1be1SJon Lin 	{ 0xC2, 0xA2, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
52f28847a8SJon Lin 
53f28847a8SJon Lin 	/* GD5F1GQ4UAYIG */
54b833c879SJon Lin 	{ 0xC8, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
55f28847a8SJon Lin 	/* GD5F1GQ4RB9IGR */
56b833c879SJon Lin 	{ 0xC8, 0xD1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
57f28847a8SJon Lin 	/* GD5F2GQ40BY2GR */
58b833c879SJon Lin 	{ 0xC8, 0xD2, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
59f28847a8SJon Lin 	/* GD5F1GQ5UEYIG */
60b833c879SJon Lin 	{ 0xC8, 0x51, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
61f28847a8SJon Lin 	/* GD5F2GQ5UEYIG */
62b833c879SJon Lin 	{ 0xC8, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
63f28847a8SJon Lin 	/* GD5F1GQ4R */
64b833c879SJon Lin 	{ 0xC8, 0xC1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
65362b1be1SJon Lin 	/* GD5F4GQ6RExxG 1*4096 */
66*d4db0b8dSJon Lin 	{ 0xC8, 0x45, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status2 },
67362b1be1SJon Lin 	/* GD5F4GQ6UExxG 1*4096 */
68*d4db0b8dSJon Lin 	{ 0xC8, 0x55, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status2 },
698a654f32SJon Lin 	/* GD5F1GQ4UExxH */
708a654f32SJon Lin 	{ 0xC8, 0xD9, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
71bf620bf6SJon Lin 	/* GD5F1GQ5REYIG */
72bf620bf6SJon Lin 	{ 0xC8, 0x41, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
73bf620bf6SJon Lin 	/* GD5F2GQ5REYIG */
74bf620bf6SJon Lin 	{ 0xC8, 0x42, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
75bf620bf6SJon Lin 	/* GD5F2GM7RxG */
76bf620bf6SJon Lin 	{ 0xC8, 0x82, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
77bf620bf6SJon Lin 	/* GD5F2GM7UxG */
78bf620bf6SJon Lin 	{ 0xC8, 0x92, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
7945292245SJon Lin 	/* GD5F1GM7UxG */
8045292245SJon Lin 	{ 0xC8, 0x91, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
81*d4db0b8dSJon Lin 	/* GD5F4GQ4UAYIG 1*4096 */
82*d4db0b8dSJon Lin 	{ 0xC8, 0xF4, 0x00, 4, 0x40, 2, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status0 },
83f28847a8SJon Lin 
84f28847a8SJon Lin 	/* W25N01GV */
85b833c879SJon Lin 	{ 0xEF, 0xAA, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 },
86b833c879SJon Lin 	/* W25N02KVZEIR */
87b833c879SJon Lin 	{ 0xEF, 0xAA, 0x22, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status0 },
88629111d3SJon Lin 	/* W25N04KVZEIR */
89629111d3SJon Lin 	{ 0xEF, 0xAA, 0x23, 4, 0x40, 1, 4096, 0x4C, 20, 0x8, 0, { 0x04, 0x14, 0x24, 0x34 }, &sfc_nand_get_ecc_status0 },
90f28847a8SJon Lin 	/* W25N01GW */
917bdae1e3SJon Lin 	{ 0xEF, 0xBA, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 },
927bdae1e3SJon Lin 	/* W25N02KW */
937bdae1e3SJon Lin 	{ 0xEF, 0xBA, 0x22, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status0 },
948a654f32SJon Lin 	/* W25N512GVEIG */
958a654f32SJon Lin 	{ 0xEF, 0xAA, 0x20, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 },
96f28847a8SJon Lin 
97f28847a8SJon Lin 	/* HYF2GQ4UAACAE */
98b833c879SJon Lin 	{ 0xC9, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
99f28847a8SJon Lin 	/* HYF1GQ4UDACAE */
100b833c879SJon Lin 	{ 0xC9, 0x21, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
101f28847a8SJon Lin 	/* HYF1GQ4UPACAE */
102b833c879SJon Lin 	{ 0xC9, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
103f28847a8SJon Lin 	/* HYF2GQ4UDACAE */
104b833c879SJon Lin 	{ 0xC9, 0x22, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
105f28847a8SJon Lin 	/* HYF2GQ4UHCCAE */
106b833c879SJon Lin 	{ 0xC9, 0x5A, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
107f28847a8SJon Lin 	/* HYF4GQ4UAACBE */
108b833c879SJon Lin 	{ 0xC9, 0xD4, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x4, 1, { 0x20, 0x40, 0x24, 0x44 }, &sfc_nand_get_ecc_status0 },
109f28847a8SJon Lin 
110f28847a8SJon Lin 	/* FS35ND01G-S1 */
111b833c879SJon Lin 	{ 0xCD, 0xB1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
112f28847a8SJon Lin 	/* FS35ND02G-S2 */
113b833c879SJon Lin 	{ 0xCD, 0xA2, 0x00, 4, 0x40, 1, 2048, 0x00, 19, 0x4, 0, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
11458463f4dSJon Lin 	/* FS35ND01G-S1Y2 */
115b833c879SJon Lin 	{ 0xCD, 0xEA, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
116f1b20f5aSJon Lin 	/* FS35ND02G-S3Y2 */
117b833c879SJon Lin 	{ 0xCD, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
118f28847a8SJon Lin 	/* FS35ND04G-S2Y2 1*4096 */
119b833c879SJon Lin 	{ 0xCD, 0xEC, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
120bf620bf6SJon Lin 	/* F35SQA001G */
121bf620bf6SJon Lin 	{ 0xCD, 0x71, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
12245292245SJon Lin 	/* F35SQA002G */
12345292245SJon Lin 	{ 0xCD, 0x72, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
124*d4db0b8dSJon Lin 	/* F35SQA512M */
125*d4db0b8dSJon Lin 	{ 0xCD, 0x70, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
126*d4db0b8dSJon Lin 	/* F35UQA512M */
127*d4db0b8dSJon Lin 	{ 0xCD, 0x70, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
128f28847a8SJon Lin 
129f28847a8SJon Lin 	/* DS35Q1GA-IB */
130b833c879SJon Lin 	{ 0xE5, 0x71, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
131f28847a8SJon Lin 	/* DS35Q2GA-IB */
132b833c879SJon Lin 	{ 0xE5, 0x72, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
133f28847a8SJon Lin 	/* DS35M1GA-1B */
134b833c879SJon Lin 	{ 0xE5, 0x21, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
135bf620bf6SJon Lin 	/* DS35M2GA-IB */
136bf620bf6SJon Lin 	{ 0xE5, 0x22, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
137*d4db0b8dSJon Lin 	/* DS35Q1GB-IB */
138*d4db0b8dSJon Lin 	{ 0xE5, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
139629111d3SJon Lin 	/* DS35Q2GB-IB */
140629111d3SJon Lin 	{ 0xE5, 0xF2, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
141*d4db0b8dSJon Lin 	/* DS35Q4GM */
142*d4db0b8dSJon Lin 	{ 0xE5, 0xF4, 0x00, 4, 0x40, 2, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
143bf620bf6SJon Lin 	/* DS35M1GB-IB */
144bf620bf6SJon Lin 	{ 0xE5, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
145f28847a8SJon Lin 
146f28847a8SJon Lin 	/* EM73C044VCC-H */
147b833c879SJon Lin 	{ 0xD5, 0x22, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
148f28847a8SJon Lin 	/* EM73D044VCE-H */
149b833c879SJon Lin 	{ 0xD5, 0x20, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
150f28847a8SJon Lin 	/* EM73E044SNA-G */
151b833c879SJon Lin 	{ 0xD5, 0x03, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x28, 0x08, 0x2C }, &sfc_nand_get_ecc_status0 },
152629111d3SJon Lin 	/* EM73C044VCF-H */
153629111d3SJon Lin 	{ 0xD5, 0x25, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
154f28847a8SJon Lin 
155f28847a8SJon Lin 	/* XT26G02A */
156362b1be1SJon Lin 	{ 0x0B, 0xE2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
157f28847a8SJon Lin 	/* XT26G01A */
158362b1be1SJon Lin 	{ 0x0B, 0xE1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
159f28847a8SJon Lin 	/* XT26G04A */
160362b1be1SJon Lin 	{ 0x0B, 0xE3, 0x00, 4, 0x80, 1, 2048, 0x4C, 20, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
161f28847a8SJon Lin 	/* XT26G01B */
162362b1be1SJon Lin 	{ 0x0B, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
163f28847a8SJon Lin 	/* XT26G02B */
164362b1be1SJon Lin 	{ 0x0B, 0xF2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
165362b1be1SJon Lin 	/* XT26G01C */
166362b1be1SJon Lin 	{ 0x0B, 0x11, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 },
167362b1be1SJon Lin 	/* XT26G02C */
168362b1be1SJon Lin 	{ 0x0B, 0x12, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 },
169362b1be1SJon Lin 	/* XT26G04C */
170362b1be1SJon Lin 	{ 0x0B, 0x13, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status7 },
171629111d3SJon Lin 	/* XT26G11C */
172629111d3SJon Lin 	{ 0x0B, 0x15, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
173a80fd396SJon Lin 
174362b1be1SJon Lin 	/* MT29F2G01ABA, XT26G02E, F50L2G41XA */
175629111d3SJon Lin 	{ 0x2C, 0x24, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x8, 0, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
176629111d3SJon Lin 	/* MT29F1G01ABA, F50L1G41XA */
177629111d3SJon Lin 	{ 0x2C, 0x14, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 0, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
178a80fd396SJon Lin 
179a80fd396SJon Lin 	/* FM25S01 */
180b833c879SJon Lin 	{ 0xA1, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x00, 0x04, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
181a80fd396SJon Lin 	/* FM25S01A */
182b833c879SJon Lin 	{ 0xA1, 0xE4, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
183a80fd396SJon Lin 	/* FM25S02A */
184b833c879SJon Lin 	{ 0xA1, 0xE5, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
1857bdae1e3SJon Lin 	/* FM25LS01 */
1867bdae1e3SJon Lin 	{ 0xA1, 0xA5, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
187f28847a8SJon Lin 
188f28847a8SJon Lin 	/* IS37SML01G1 */
189b833c879SJon Lin 	{ 0xC8, 0x21, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x1, 0, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
190f28847a8SJon Lin 	/* F50L1G41LB */
191b833c879SJon Lin 	{ 0xC8, 0x01, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
192f28847a8SJon Lin 	/* ATO25D1GA */
193b833c879SJon Lin 	{ 0x9B, 0x12, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x1, 1, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
194362b1be1SJon Lin 	/* BWJX08K-2Gb */
195362b1be1SJon Lin 	{ 0xBC, 0xB3, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x10, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
196629111d3SJon Lin 	/* JS28U1GQSCAHG-83 */
197629111d3SJon Lin 	{ 0xBF, 0x21, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x4, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status8 },
1988a654f32SJon Lin 	/* SGM7000I-S24W1GH */
1998a654f32SJon Lin 	{ 0xEA, 0xC1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
200bf620bf6SJon Lin 	/* TX25G01 */
201bf620bf6SJon Lin 	{ 0xA1, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status8 },
202*d4db0b8dSJon Lin 	/* S35ML04G3 */
203*d4db0b8dSJon Lin 	{ 0x01, 0x35, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status9 },
204ba0501acSDingqiang Lin };
205ba0501acSDingqiang Lin 
206ba0501acSDingqiang Lin static struct nand_info *p_nand_info;
207ba0501acSDingqiang Lin static u32 gp_page_buf[SFC_NAND_PAGE_MAX_SIZE / 4];
208ba0501acSDingqiang Lin static struct SFNAND_DEV sfc_nand_dev;
209ba0501acSDingqiang Lin 
210a6fcac41SJon Lin static struct nand_info *sfc_nand_get_info(u8 *nand_id)
211ba0501acSDingqiang Lin {
212ba0501acSDingqiang Lin 	u32 i;
213ba0501acSDingqiang Lin 
214ba0501acSDingqiang Lin 	for (i = 0; i < ARRAY_SIZE(spi_nand_tbl); i++) {
215b833c879SJon Lin 		if (spi_nand_tbl[i].id0 == nand_id[0] &&
216b833c879SJon Lin 		    spi_nand_tbl[i].id1 == nand_id[1]) {
217b833c879SJon Lin 			if (spi_nand_tbl[i].id2 &&
218b833c879SJon Lin 			    spi_nand_tbl[i].id2 != nand_id[2])
219b833c879SJon Lin 				continue;
220b833c879SJon Lin 
221ba0501acSDingqiang Lin 			return &spi_nand_tbl[i];
222ba0501acSDingqiang Lin 		}
223b833c879SJon Lin 	}
224f28847a8SJon Lin 
225ba0501acSDingqiang Lin 	return NULL;
226ba0501acSDingqiang Lin }
227ba0501acSDingqiang Lin 
228ba0501acSDingqiang Lin static int sfc_nand_write_en(void)
229ba0501acSDingqiang Lin {
230ba0501acSDingqiang Lin 	int ret;
23158463f4dSJon Lin 	struct rk_sfc_op op;
232ba0501acSDingqiang Lin 
23358463f4dSJon Lin 	op.sfcmd.d32 = 0;
23458463f4dSJon Lin 	op.sfcmd.b.cmd = CMD_WRITE_EN;
23558463f4dSJon Lin 
23658463f4dSJon Lin 	op.sfctrl.d32 = 0;
23758463f4dSJon Lin 
23858463f4dSJon Lin 	ret = sfc_request(&op, 0, NULL, 0);
239ba0501acSDingqiang Lin 	return ret;
240ba0501acSDingqiang Lin }
241ba0501acSDingqiang Lin 
242ba0501acSDingqiang Lin static int sfc_nand_rw_preset(void)
243ba0501acSDingqiang Lin {
244ba0501acSDingqiang Lin 	int ret;
24558463f4dSJon Lin 	struct rk_sfc_op op;
246ba0501acSDingqiang Lin 
24758463f4dSJon Lin 	op.sfcmd.d32 = 0;
248f28847a8SJon Lin 	op.sfcmd.b.cmd = 0xff;
249f28847a8SJon Lin 	op.sfcmd.b.cs = 2;
250ba0501acSDingqiang Lin 
25158463f4dSJon Lin 	op.sfctrl.d32 = 0;
25258463f4dSJon Lin 	op.sfctrl.b.datalines = 2;
253f28847a8SJon Lin 	op.sfctrl.b.cmdlines = 2;
254f28847a8SJon Lin 	op.sfctrl.b.addrlines = 2;
25558463f4dSJon Lin 
256f28847a8SJon Lin 	ret = sfc_request(&op, 0, NULL, 0);
257ba0501acSDingqiang Lin 	return ret;
258ba0501acSDingqiang Lin }
259ba0501acSDingqiang Lin 
260ba0501acSDingqiang Lin static int sfc_nand_read_feature(u8 addr, u8 *data)
261ba0501acSDingqiang Lin {
262ba0501acSDingqiang Lin 	int ret;
26358463f4dSJon Lin 	struct rk_sfc_op op;
264ba0501acSDingqiang Lin 
26558463f4dSJon Lin 	op.sfcmd.d32 = 0;
26658463f4dSJon Lin 	op.sfcmd.b.cmd = 0x0F;
26758463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
26858463f4dSJon Lin 
26958463f4dSJon Lin 	op.sfctrl.d32 = 0;
27058463f4dSJon Lin 	op.sfctrl.b.addrbits = 8;
27158463f4dSJon Lin 
272ba0501acSDingqiang Lin 	*data = 0;
273ba0501acSDingqiang Lin 
27458463f4dSJon Lin 	ret = sfc_request(&op, addr, data, 1);
275f28847a8SJon Lin 
276ba0501acSDingqiang Lin 	if (ret != SFC_OK)
277ba0501acSDingqiang Lin 		return ret;
278f28847a8SJon Lin 
279ba0501acSDingqiang Lin 	return SFC_OK;
280ba0501acSDingqiang Lin }
281ba0501acSDingqiang Lin 
282ba0501acSDingqiang Lin static int sfc_nand_write_feature(u32 addr, u8 status)
283ba0501acSDingqiang Lin {
284ba0501acSDingqiang Lin 	int ret;
28558463f4dSJon Lin 	struct rk_sfc_op op;
286ba0501acSDingqiang Lin 
287ba0501acSDingqiang Lin 	sfc_nand_write_en();
288ba0501acSDingqiang Lin 
28958463f4dSJon Lin 	op.sfcmd.d32 = 0;
29058463f4dSJon Lin 	op.sfcmd.b.cmd = 0x1F;
29158463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
29258463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
293ba0501acSDingqiang Lin 
29458463f4dSJon Lin 	op.sfctrl.d32 = 0;
29558463f4dSJon Lin 	op.sfctrl.b.addrbits = 8;
29658463f4dSJon Lin 
29758463f4dSJon Lin 	ret = sfc_request(&op, addr, &status, 1);
298f28847a8SJon Lin 
299ba0501acSDingqiang Lin 	if (ret != SFC_OK)
300ba0501acSDingqiang Lin 		return ret;
301f28847a8SJon Lin 
302ba0501acSDingqiang Lin 	return ret;
303ba0501acSDingqiang Lin }
304ba0501acSDingqiang Lin 
305ba0501acSDingqiang Lin static int sfc_nand_wait_busy(u8 *data, int timeout)
306ba0501acSDingqiang Lin {
307ba0501acSDingqiang Lin 	int ret;
308ba0501acSDingqiang Lin 	int i;
309ba0501acSDingqiang Lin 	u8 status;
310ba0501acSDingqiang Lin 
311ba0501acSDingqiang Lin 	*data = 0;
312f28847a8SJon Lin 
313ba0501acSDingqiang Lin 	for (i = 0; i < timeout; i++) {
314ba0501acSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
315f28847a8SJon Lin 
316ba0501acSDingqiang Lin 		if (ret != SFC_OK)
317ba0501acSDingqiang Lin 			return ret;
318f28847a8SJon Lin 
319ba0501acSDingqiang Lin 		*data = status;
320f28847a8SJon Lin 
321ba0501acSDingqiang Lin 		if (!(status & (1 << 0)))
322ba0501acSDingqiang Lin 			return SFC_OK;
323f28847a8SJon Lin 
324ba0501acSDingqiang Lin 		sfc_delay(1);
325ba0501acSDingqiang Lin 	}
326f28847a8SJon Lin 
327f28847a8SJon Lin 	return SFC_NAND_WAIT_TIME_OUT;
328ba0501acSDingqiang Lin }
329ba0501acSDingqiang Lin 
3306281205aSDingqiang Lin /*
3316281205aSDingqiang Lin  * ecc default:
332a6fcac41SJon Lin  * ecc bits: 0xC0[4,5]
333f28847a8SJon Lin  * 0b00, No bit errors were detected
334f28847a8SJon Lin  * 0b01, Bit errors were detected and corrected.
335f28847a8SJon Lin  * 0b10, Multiple bit errors were detected and not corrected.
336f28847a8SJon Lin  * 0b11, Bits errors were detected and corrected, bit error count
337362b1be1SJon Lin  *	reach the bit flip detection threshold
3386281205aSDingqiang Lin  */
339f28847a8SJon Lin static u32 sfc_nand_get_ecc_status0(void)
3406281205aSDingqiang Lin {
34158463f4dSJon Lin 	u32 ret;
3426281205aSDingqiang Lin 	u32 i;
3436281205aSDingqiang Lin 	u8 ecc;
3446281205aSDingqiang Lin 	u8 status;
3456281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
3466281205aSDingqiang Lin 
3476281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
3486281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
349f28847a8SJon Lin 
3506281205aSDingqiang Lin 		if (ret != SFC_OK)
3516281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
352f28847a8SJon Lin 
3536281205aSDingqiang Lin 		if (!(status & (1 << 0)))
3546281205aSDingqiang Lin 			break;
355f28847a8SJon Lin 
3566281205aSDingqiang Lin 		sfc_delay(1);
3576281205aSDingqiang Lin 	}
3586281205aSDingqiang Lin 
3596281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
3606281205aSDingqiang Lin 
3616281205aSDingqiang Lin 	if (ecc <= 1)
3626281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
3636281205aSDingqiang Lin 	else if (ecc == 2)
36458463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
3656281205aSDingqiang Lin 	else
3666281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
3676281205aSDingqiang Lin 
3686281205aSDingqiang Lin 	return ret;
3696281205aSDingqiang Lin }
3706281205aSDingqiang Lin 
3716281205aSDingqiang Lin /*
3726281205aSDingqiang Lin  * ecc spectial type1:
373a6fcac41SJon Lin  * ecc bits: 0xC0[4,5]
374f28847a8SJon Lin  * 0b00, No bit errors were detected;
375f28847a8SJon Lin  * 0b01, Bits errors were detected and corrected, bit error count
3766281205aSDingqiang Lin  *	may reach the bit flip detection threshold;
377f28847a8SJon Lin  * 0b10, Multiple bit errors were detected and not corrected;
378f28847a8SJon Lin  * 0b11, Reserved.
3796281205aSDingqiang Lin  */
380f28847a8SJon Lin static u32 sfc_nand_get_ecc_status1(void)
3816281205aSDingqiang Lin {
38258463f4dSJon Lin 	u32 ret;
3836281205aSDingqiang Lin 	u32 i;
3846281205aSDingqiang Lin 	u8 ecc;
3856281205aSDingqiang Lin 	u8 status;
3866281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
3876281205aSDingqiang Lin 
3886281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
3896281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
390f28847a8SJon Lin 
3916281205aSDingqiang Lin 		if (ret != SFC_OK)
3926281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
393f28847a8SJon Lin 
3946281205aSDingqiang Lin 		if (!(status & (1 << 0)))
3956281205aSDingqiang Lin 			break;
396f28847a8SJon Lin 
3976281205aSDingqiang Lin 		sfc_delay(1);
3986281205aSDingqiang Lin 	}
3996281205aSDingqiang Lin 
4006281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
4016281205aSDingqiang Lin 
4026281205aSDingqiang Lin 	if (ecc == 0)
4036281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
4046281205aSDingqiang Lin 	else if (ecc == 1)
4056281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
4066281205aSDingqiang Lin 	else
40758463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
4086281205aSDingqiang Lin 
4096281205aSDingqiang Lin 	return ret;
4106281205aSDingqiang Lin }
4116281205aSDingqiang Lin 
4126281205aSDingqiang Lin /*
413d9cdd318SJon Lin  * ecc spectial type2:
414a6fcac41SJon Lin  * ecc bits: 0xC0[4,5] 0xF0[4,5]
415f28847a8SJon Lin  * [0b0000, 0b0011], No bit errors were detected;
416f28847a8SJon Lin  * [0b0100, 0b0111], Bit errors were detected and corrected. Not
417d9cdd318SJon Lin  *	reach Flipping Bits;
418f28847a8SJon Lin  * [0b1000, 0b1011], Multiple bit errors were detected and
419c84f0ed8SJon Lin  *	not corrected.
420f28847a8SJon Lin  * [0b1100, 0b1111], reserved.
421d9cdd318SJon Lin  */
422f28847a8SJon Lin static u32 sfc_nand_get_ecc_status2(void)
423d9cdd318SJon Lin {
42458463f4dSJon Lin 	u32 ret;
425d9cdd318SJon Lin 	u32 i;
426d9cdd318SJon Lin 	u8 ecc;
427d9cdd318SJon Lin 	u8 status, status1;
428d9cdd318SJon Lin 	u32 timeout = 1000 * 1000;
429d9cdd318SJon Lin 
430d9cdd318SJon Lin 	for (i = 0; i < timeout; i++) {
431d9cdd318SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
432f28847a8SJon Lin 
433d9cdd318SJon Lin 		if (ret != SFC_OK)
434d9cdd318SJon Lin 			return SFC_NAND_ECC_ERROR;
435f28847a8SJon Lin 
436d9cdd318SJon Lin 		ret = sfc_nand_read_feature(0xF0, &status1);
437f28847a8SJon Lin 
438d9cdd318SJon Lin 		if (ret != SFC_OK)
439d9cdd318SJon Lin 			return SFC_NAND_ECC_ERROR;
440f28847a8SJon Lin 
441d9cdd318SJon Lin 		if (!(status & (1 << 0)))
442d9cdd318SJon Lin 			break;
443f28847a8SJon Lin 
444d9cdd318SJon Lin 		sfc_delay(1);
445d9cdd318SJon Lin 	}
446d9cdd318SJon Lin 
447d9cdd318SJon Lin 	ecc = (status >> 4) & 0x03;
448d9cdd318SJon Lin 	ecc = (ecc << 2) | ((status1 >> 4) & 0x03);
449f28847a8SJon Lin 
450d9cdd318SJon Lin 	if (ecc < 7)
451d9cdd318SJon Lin 		ret = SFC_NAND_ECC_OK;
452d9cdd318SJon Lin 	else if (ecc == 7)
453d9cdd318SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
454d9cdd318SJon Lin 	else
45558463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
456d9cdd318SJon Lin 
457d9cdd318SJon Lin 	return ret;
458d9cdd318SJon Lin }
459d9cdd318SJon Lin 
460d9cdd318SJon Lin /*
4616281205aSDingqiang Lin  * ecc spectial type3:
462a6fcac41SJon Lin  * ecc bits: 0xC0[4,5] 0xF0[4,5]
463f28847a8SJon Lin  * [0b0000, 0b0011], No bit errors were detected;
464f28847a8SJon Lin  * [0b0100, 0b0111], Bit errors were detected and corrected. Not
4656281205aSDingqiang Lin  *	reach Flipping Bits;
466f28847a8SJon Lin  * [0b1000, 0b1011], Multiple bit errors were detected and
4676281205aSDingqiang Lin  *	not corrected.
468f28847a8SJon Lin  * [0b1100, 0b1111], Bit error count equals the bit flip
4696281205aSDingqiang Lin  *	detectio nthreshold
4706281205aSDingqiang Lin  */
471f28847a8SJon Lin static u32 sfc_nand_get_ecc_status3(void)
4726281205aSDingqiang Lin {
47358463f4dSJon Lin 	u32 ret;
4746281205aSDingqiang Lin 	u32 i;
4756281205aSDingqiang Lin 	u8 ecc;
4766281205aSDingqiang Lin 	u8 status, status1;
4776281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
4786281205aSDingqiang Lin 
4796281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
4806281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
481f28847a8SJon Lin 
4826281205aSDingqiang Lin 		if (ret != SFC_OK)
4836281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
484f28847a8SJon Lin 
4856281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xF0, &status1);
486f28847a8SJon Lin 
4876281205aSDingqiang Lin 		if (ret != SFC_OK)
4886281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
489f28847a8SJon Lin 
4906281205aSDingqiang Lin 		if (!(status & (1 << 0)))
4916281205aSDingqiang Lin 			break;
492f28847a8SJon Lin 
4936281205aSDingqiang Lin 		sfc_delay(1);
4946281205aSDingqiang Lin 	}
4956281205aSDingqiang Lin 
4966281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
4976281205aSDingqiang Lin 	ecc = (ecc << 2) | ((status1 >> 4) & 0x03);
498f28847a8SJon Lin 
4996281205aSDingqiang Lin 	if (ecc < 7)
5006281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
5016281205aSDingqiang Lin 	else if (ecc == 7 || ecc >= 12)
5026281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
5036281205aSDingqiang Lin 	else
50458463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
5056281205aSDingqiang Lin 
5066281205aSDingqiang Lin 	return ret;
5076281205aSDingqiang Lin }
5086281205aSDingqiang Lin 
50925098c06SDingqiang Lin /*
51025098c06SDingqiang Lin  * ecc spectial type4:
511a6fcac41SJon Lin  * ecc bits: 0xC0[2,5]
512f28847a8SJon Lin  * [0b0000], No bit errors were detected;
513f28847a8SJon Lin  * [0b0001, 0b0111], Bit errors were detected and corrected. Not
51425098c06SDingqiang Lin  *	reach Flipping Bits;
515f28847a8SJon Lin  * [0b1000], Multiple bit errors were detected and
51625098c06SDingqiang Lin  *	not corrected.
517f28847a8SJon Lin  * [0b1100], Bit error count equals the bit flip
51825098c06SDingqiang Lin  *	detection threshold
51925098c06SDingqiang Lin  * else, reserved
52025098c06SDingqiang Lin  */
521f28847a8SJon Lin static u32 sfc_nand_get_ecc_status4(void)
52225098c06SDingqiang Lin {
52358463f4dSJon Lin 	u32 ret;
52425098c06SDingqiang Lin 	u32 i;
52525098c06SDingqiang Lin 	u8 ecc;
52625098c06SDingqiang Lin 	u8 status;
52725098c06SDingqiang Lin 	u32 timeout = 1000 * 1000;
52825098c06SDingqiang Lin 
52925098c06SDingqiang Lin 	for (i = 0; i < timeout; i++) {
53025098c06SDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
531f28847a8SJon Lin 
53225098c06SDingqiang Lin 		if (ret != SFC_OK)
53325098c06SDingqiang Lin 			return SFC_NAND_ECC_ERROR;
534f28847a8SJon Lin 
53525098c06SDingqiang Lin 		if (!(status & (1 << 0)))
53625098c06SDingqiang Lin 			break;
537f28847a8SJon Lin 
53825098c06SDingqiang Lin 		sfc_delay(1);
53925098c06SDingqiang Lin 	}
54025098c06SDingqiang Lin 
54125098c06SDingqiang Lin 	ecc = (status >> 2) & 0x0f;
542f28847a8SJon Lin 
54325098c06SDingqiang Lin 	if (ecc < 7)
54425098c06SDingqiang Lin 		ret = SFC_NAND_ECC_OK;
54525098c06SDingqiang Lin 	else if (ecc == 7 || ecc == 12)
54625098c06SDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
54725098c06SDingqiang Lin 	else
54858463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
54925098c06SDingqiang Lin 
55025098c06SDingqiang Lin 	return ret;
55125098c06SDingqiang Lin }
55225098c06SDingqiang Lin 
55325098c06SDingqiang Lin /*
55425098c06SDingqiang Lin  * ecc spectial type5:
555a6fcac41SJon Lin  * ecc bits: 0xC0[4,6]
556f28847a8SJon Lin  * [0b000], No bit errors were detected;
557f28847a8SJon Lin  * [0b001, 0b011], Bit errors were detected and corrected. Not
55825098c06SDingqiang Lin  *	reach Flipping Bits;
559f28847a8SJon Lin  * [0b100], Bit error count equals the bit flip
56025098c06SDingqiang Lin  *	detection threshold
561f28847a8SJon Lin  * [0b101, 0b110], Reserved;
562f28847a8SJon Lin  * [0b111], Multiple bit errors were detected and
56325098c06SDingqiang Lin  *	not corrected.
56425098c06SDingqiang Lin  */
565f28847a8SJon Lin static u32 sfc_nand_get_ecc_status5(void)
56625098c06SDingqiang Lin {
56758463f4dSJon Lin 	u32 ret;
56825098c06SDingqiang Lin 	u32 i;
56925098c06SDingqiang Lin 	u8 ecc;
57025098c06SDingqiang Lin 	u8 status;
57125098c06SDingqiang Lin 	u32 timeout = 1000 * 1000;
57225098c06SDingqiang Lin 
57325098c06SDingqiang Lin 	for (i = 0; i < timeout; i++) {
57425098c06SDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
575f28847a8SJon Lin 
57625098c06SDingqiang Lin 		if (ret != SFC_OK)
57725098c06SDingqiang Lin 			return SFC_NAND_ECC_ERROR;
578f28847a8SJon Lin 
57925098c06SDingqiang Lin 		if (!(status & (1 << 0)))
58025098c06SDingqiang Lin 			break;
581f28847a8SJon Lin 
58225098c06SDingqiang Lin 		sfc_delay(1);
58325098c06SDingqiang Lin 	}
58425098c06SDingqiang Lin 
58525098c06SDingqiang Lin 	ecc = (status >> 4) & 0x07;
586f28847a8SJon Lin 
58725098c06SDingqiang Lin 	if (ecc < 4)
58825098c06SDingqiang Lin 		ret = SFC_NAND_ECC_OK;
58925098c06SDingqiang Lin 	else if (ecc == 4)
59025098c06SDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
59125098c06SDingqiang Lin 	else
59258463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
59325098c06SDingqiang Lin 
59425098c06SDingqiang Lin 	return ret;
59525098c06SDingqiang Lin }
59625098c06SDingqiang Lin 
597f28847a8SJon Lin /*
598f28847a8SJon Lin  * ecc spectial type6:
599f28847a8SJon Lin  * ecc bits: 0xC0[4,6]
600f28847a8SJon Lin  * [0b000], No bit errors were detected;
601f28847a8SJon Lin  * [0b001], 1-3 Bit errors were detected and corrected. Not
602f28847a8SJon Lin  *	reach Flipping Bits;
603f28847a8SJon Lin  * [0b010], Multiple bit errors were detected and
604f28847a8SJon Lin  *	not corrected.
605f28847a8SJon Lin  * [0b011], 4-6 Bit errors were detected and corrected. Not
606f28847a8SJon Lin  *	reach Flipping Bits;
607f28847a8SJon Lin  * [0b101], Bit error count equals the bit flip
608f28847a8SJon Lin  *	detectionthreshold
609f28847a8SJon Lin  * others, Reserved.
610f28847a8SJon Lin  */
611f28847a8SJon Lin static u32 sfc_nand_get_ecc_status6(void)
612f28847a8SJon Lin {
613f28847a8SJon Lin 	u32 ret;
614f28847a8SJon Lin 	u32 i;
615f28847a8SJon Lin 	u8 ecc;
616f28847a8SJon Lin 	u8 status;
617f28847a8SJon Lin 	u32 timeout = 1000 * 1000;
618f28847a8SJon Lin 
619f28847a8SJon Lin 	for (i = 0; i < timeout; i++) {
620f28847a8SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
621f28847a8SJon Lin 
622f28847a8SJon Lin 		if (ret != SFC_OK)
623f28847a8SJon Lin 			return SFC_NAND_ECC_ERROR;
624f28847a8SJon Lin 
625f28847a8SJon Lin 		if (!(status & (1 << 0)))
626f28847a8SJon Lin 			break;
627f28847a8SJon Lin 
628f28847a8SJon Lin 		sfc_delay(1);
629f28847a8SJon Lin 	}
630f28847a8SJon Lin 
631f28847a8SJon Lin 	ecc = (status >> 4) & 0x07;
632f28847a8SJon Lin 
633f28847a8SJon Lin 	if (ecc == 0 || ecc == 1 || ecc == 3)
634f28847a8SJon Lin 		ret = SFC_NAND_ECC_OK;
635f28847a8SJon Lin 	else if (ecc == 5)
636f28847a8SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
637f28847a8SJon Lin 	else
638f28847a8SJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
639f28847a8SJon Lin 
640f28847a8SJon Lin 	return ret;
641f28847a8SJon Lin }
642f28847a8SJon Lin 
643362b1be1SJon Lin /*
644362b1be1SJon Lin  * ecc spectial type7:
645362b1be1SJon Lin  * ecc bits: 0xC0[4,7]
646362b1be1SJon Lin  * [0b0000], No bit errors were detected;
647362b1be1SJon Lin  * [0b0001, 0b0111], 1-7 Bit errors were detected and corrected. Not
648362b1be1SJon Lin  *	reach Flipping Bits;
649362b1be1SJon Lin  * [0b1000], 8 Bit errors were detected and corrected. Bit error count
650362b1be1SJon Lin  * 	equals the bit flip detectionthreshold;
651362b1be1SJon Lin  * [0b1111], Bit errors greater than ECC capability(8 bits) and not corrected;
652362b1be1SJon Lin  * others, Reserved.
653362b1be1SJon Lin  */
654362b1be1SJon Lin static u32 sfc_nand_get_ecc_status7(void)
655362b1be1SJon Lin {
656362b1be1SJon Lin 	u32 ret;
657362b1be1SJon Lin 	u32 i;
658362b1be1SJon Lin 	u8 ecc;
659362b1be1SJon Lin 	u8 status;
660362b1be1SJon Lin 	u32 timeout = 1000 * 1000;
661362b1be1SJon Lin 
662362b1be1SJon Lin 	for (i = 0; i < timeout; i++) {
663362b1be1SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
664362b1be1SJon Lin 
665362b1be1SJon Lin 		if (ret != SFC_OK)
666362b1be1SJon Lin 			return SFC_NAND_ECC_ERROR;
667362b1be1SJon Lin 
668362b1be1SJon Lin 		if (!(status & (1 << 0)))
669362b1be1SJon Lin 			break;
670362b1be1SJon Lin 
671362b1be1SJon Lin 		sfc_delay(1);
672362b1be1SJon Lin 	}
673362b1be1SJon Lin 
674362b1be1SJon Lin 	ecc = (status >> 4) & 0xf;
675362b1be1SJon Lin 
676362b1be1SJon Lin 	if (ecc < 7)
677362b1be1SJon Lin 		ret = SFC_NAND_ECC_OK;
678362b1be1SJon Lin 	else if (ecc == 7 || ecc == 8)
679362b1be1SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
680362b1be1SJon Lin 	else
681362b1be1SJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
682362b1be1SJon Lin 
683362b1be1SJon Lin 	return ret;
684362b1be1SJon Lin }
685362b1be1SJon Lin 
686629111d3SJon Lin /*
687629111d3SJon Lin  * ecc spectial type8:
688629111d3SJon Lin  * ecc bits: 0xC0[4,6]
689629111d3SJon Lin  * [0b000], No bit errors were detected;
690629111d3SJon Lin  * [0b001, 0b011], 1~3 Bit errors were detected and corrected. Not
691629111d3SJon Lin  *	reach Flipping Bits;
692629111d3SJon Lin  * [0b100], Bit error count equals the bit flip
693629111d3SJon Lin  *	detection threshold
694629111d3SJon Lin  * others, Reserved.
695629111d3SJon Lin  */
696629111d3SJon Lin static u32 sfc_nand_get_ecc_status8(void)
697629111d3SJon Lin {
698629111d3SJon Lin 	u32 ret;
699629111d3SJon Lin 	u32 i;
700629111d3SJon Lin 	u8 ecc;
701629111d3SJon Lin 	u8 status;
702629111d3SJon Lin 	u32 timeout = 1000 * 1000;
703629111d3SJon Lin 
704629111d3SJon Lin 	for (i = 0; i < timeout; i++) {
705629111d3SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
706629111d3SJon Lin 
707629111d3SJon Lin 		if (ret != SFC_OK)
708629111d3SJon Lin 			return SFC_NAND_ECC_ERROR;
709629111d3SJon Lin 
710629111d3SJon Lin 		if (!(status & (1 << 0)))
711629111d3SJon Lin 			break;
712629111d3SJon Lin 
713629111d3SJon Lin 		sfc_delay(1);
714629111d3SJon Lin 	}
715629111d3SJon Lin 
716629111d3SJon Lin 	ecc = (status >> 4) & 0x07;
717629111d3SJon Lin 
718629111d3SJon Lin 	if (ecc < 4)
719629111d3SJon Lin 		ret = SFC_NAND_ECC_OK;
720629111d3SJon Lin 	else if (ecc == 4)
721629111d3SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
722629111d3SJon Lin 	else
723629111d3SJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
724629111d3SJon Lin 
725629111d3SJon Lin 	return ret;
726629111d3SJon Lin }
727629111d3SJon Lin 
728*d4db0b8dSJon Lin /*
729*d4db0b8dSJon Lin  * ecc spectial type9:
730*d4db0b8dSJon Lin  * ecc bits: 0xC0[4,5]
731*d4db0b8dSJon Lin  * 0b00, No bit errors were detected
732*d4db0b8dSJon Lin  * 0b01, 1-2Bit errors were detected and corrected.
733*d4db0b8dSJon Lin  * 0b10, 3-4Bit errors were detected and corrected.
734*d4db0b8dSJon Lin  * 0b11, 11 can be used as uncorrectable
735*d4db0b8dSJon Lin  */
736*d4db0b8dSJon Lin static u32 sfc_nand_get_ecc_status9(void)
737*d4db0b8dSJon Lin {
738*d4db0b8dSJon Lin 	u32 ret;
739*d4db0b8dSJon Lin 	u32 i;
740*d4db0b8dSJon Lin 	u8 ecc;
741*d4db0b8dSJon Lin 	u8 status;
742*d4db0b8dSJon Lin 	u32 timeout = 1000 * 1000;
743*d4db0b8dSJon Lin 
744*d4db0b8dSJon Lin 	for (i = 0; i < timeout; i++) {
745*d4db0b8dSJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
746*d4db0b8dSJon Lin 
747*d4db0b8dSJon Lin 		if (ret != SFC_OK)
748*d4db0b8dSJon Lin 			return SFC_NAND_ECC_ERROR;
749*d4db0b8dSJon Lin 
750*d4db0b8dSJon Lin 		if (!(status & (1 << 0)))
751*d4db0b8dSJon Lin 			break;
752*d4db0b8dSJon Lin 
753*d4db0b8dSJon Lin 		sfc_delay(1);
754*d4db0b8dSJon Lin 	}
755*d4db0b8dSJon Lin 
756*d4db0b8dSJon Lin 	ecc = (status >> 4) & 0x03;
757*d4db0b8dSJon Lin 
758*d4db0b8dSJon Lin 	if (ecc <= 1)
759*d4db0b8dSJon Lin 		ret = SFC_NAND_ECC_OK;
760*d4db0b8dSJon Lin 	else if (ecc == 2)
761*d4db0b8dSJon Lin 		ret = SFC_NAND_ECC_REFRESH;
762*d4db0b8dSJon Lin 	else
763*d4db0b8dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
764*d4db0b8dSJon Lin 
765*d4db0b8dSJon Lin 	return ret;
766*d4db0b8dSJon Lin }
767*d4db0b8dSJon Lin 
768c84f0ed8SJon Lin u32 sfc_nand_erase_block(u8 cs, u32 addr)
769ba0501acSDingqiang Lin {
770ba0501acSDingqiang Lin 	int ret;
77158463f4dSJon Lin 	struct rk_sfc_op op;
772ba0501acSDingqiang Lin 	u8 status;
773ba0501acSDingqiang Lin 
774c84f0ed8SJon Lin 	rkflash_print_dio("%s %x\n", __func__, addr);
77558463f4dSJon Lin 	op.sfcmd.d32 = 0;
776f28847a8SJon Lin 	op.sfcmd.b.cmd = 0xd8;
77758463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_24BITS;
77858463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
77958463f4dSJon Lin 
78058463f4dSJon Lin 	op.sfctrl.d32 = 0;
78158463f4dSJon Lin 
782ba0501acSDingqiang Lin 	sfc_nand_write_en();
78358463f4dSJon Lin 	ret = sfc_request(&op, addr, NULL, 0);
784f28847a8SJon Lin 
785ba0501acSDingqiang Lin 	if (ret != SFC_OK)
786ba0501acSDingqiang Lin 		return ret;
787f28847a8SJon Lin 
788ba0501acSDingqiang Lin 	ret = sfc_nand_wait_busy(&status, 1000 * 1000);
789f28847a8SJon Lin 
790ba0501acSDingqiang Lin 	if (status & (1 << 2))
791ba0501acSDingqiang Lin 		return SFC_NAND_PROG_ERASE_ERROR;
792c84f0ed8SJon Lin 
793ba0501acSDingqiang Lin 	return ret;
794ba0501acSDingqiang Lin }
795ba0501acSDingqiang Lin 
796629111d3SJon Lin static u32 sfc_nand_read_cache(u32 row, u32 *p_page_buf, u32 column, u32 len)
797629111d3SJon Lin {
798629111d3SJon Lin 	int ret;
799629111d3SJon Lin 	u32 plane;
800629111d3SJon Lin 	struct rk_sfc_op op;
801629111d3SJon Lin 
802629111d3SJon Lin 	op.sfcmd.d32 = 0;
803629111d3SJon Lin 	op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd;
804629111d3SJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
805629111d3SJon Lin 	op.sfcmd.b.dummybits = 8;
806629111d3SJon Lin 
807629111d3SJon Lin 	op.sfctrl.d32 = 0;
808629111d3SJon Lin 	op.sfctrl.b.datalines = sfc_nand_dev.read_lines;
809629111d3SJon Lin 	op.sfctrl.b.addrbits = 16;
810629111d3SJon Lin 
811629111d3SJon Lin 	plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0;
812629111d3SJon Lin 
813629111d3SJon Lin 	ret = sfc_request(&op, plane | column, p_page_buf, len);
814629111d3SJon Lin 	if (ret != SFC_OK)
815629111d3SJon Lin 		return SFC_NAND_HW_ERROR;
816629111d3SJon Lin 
817629111d3SJon Lin 	return ret;
818629111d3SJon Lin }
819629111d3SJon Lin 
820f28847a8SJon Lin u32 sfc_nand_prog_page_raw(u8 cs, u32 addr, u32 *p_page_buf)
821ba0501acSDingqiang Lin {
822ba0501acSDingqiang Lin 	int ret;
823415cf080Sjon.lin 	u32 plane;
82458463f4dSJon Lin 	struct rk_sfc_op op;
825ba0501acSDingqiang Lin 	u8 status;
82658463f4dSJon Lin 	u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page;
827629111d3SJon Lin 	u32 data_area_size = SFC_NAND_SECTOR_SIZE * p_nand_info->sec_per_page;
828ba0501acSDingqiang Lin 
829c84f0ed8SJon Lin 	rkflash_print_dio("%s %x %x\n", __func__, addr, p_page_buf[0]);
830ba0501acSDingqiang Lin 	sfc_nand_write_en();
831f28847a8SJon Lin 
832ba0501acSDingqiang Lin 	if (sfc_nand_dev.prog_lines == DATA_LINES_X4 &&
83325098c06SDingqiang Lin 	    p_nand_info->feature & FEA_SOFT_QOP_BIT &&
83425098c06SDingqiang Lin 	    sfc_get_version() < SFC_VER_3)
835ba0501acSDingqiang Lin 		sfc_nand_rw_preset();
836ba0501acSDingqiang Lin 
83758463f4dSJon Lin 	op.sfcmd.d32 = 0;
83858463f4dSJon Lin 	op.sfcmd.b.cmd = sfc_nand_dev.page_prog_cmd;
83958463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
84058463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
841ba0501acSDingqiang Lin 
84258463f4dSJon Lin 	op.sfctrl.d32 = 0;
84358463f4dSJon Lin 	op.sfctrl.b.datalines = sfc_nand_dev.prog_lines;
84458463f4dSJon Lin 	op.sfctrl.b.addrbits = 16;
845415cf080Sjon.lin 	plane = p_nand_info->plane_per_die == 2 ? ((addr >> 6) & 0x1) << 12 : 0;
84658463f4dSJon Lin 	sfc_request(&op, plane, p_page_buf, page_size);
847ba0501acSDingqiang Lin 
848629111d3SJon Lin 	/*
849c797b43aSJon Lin 	 * At the moment of power lost or dev running in harsh environment, flash
850c797b43aSJon Lin 	 * maybe work in a unkonw state and result in bit flip, when this situation
851c797b43aSJon Lin 	 * is detected by cache recheck, it's better to wait a second for a reliable
852c797b43aSJon Lin 	 * hardware environment to avoid abnormal data written to flash array.
853629111d3SJon Lin 	 */
854361684bfSJon Lin 	if (p_nand_info->id0 == MID_GIGADEV) {
855629111d3SJon Lin 		sfc_nand_read_cache(addr, (u32 *)sfc_nand_dev.recheck_buffer, 0, data_area_size);
856c797b43aSJon Lin 		if (memcmp(sfc_nand_dev.recheck_buffer, p_page_buf, data_area_size)) {
857c797b43aSJon Lin 			rkflash_print_error("%s %x cache bitflip\n", __func__, addr);
858c797b43aSJon Lin 			mdelay(1000);
859c797b43aSJon Lin 			sfc_request(&op, plane, p_page_buf, page_size);
860c797b43aSJon Lin 		}
861c797b43aSJon Lin 	}
862629111d3SJon Lin 
86358463f4dSJon Lin 	op.sfcmd.d32 = 0;
864f28847a8SJon Lin 	op.sfcmd.b.cmd = 0x10;
86558463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_24BITS;
86658463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
86758463f4dSJon Lin 
86858463f4dSJon Lin 	op.sfctrl.d32 = 0;
86958463f4dSJon Lin 	ret = sfc_request(&op, addr, p_page_buf, 0);
870f28847a8SJon Lin 
871ba0501acSDingqiang Lin 	if (ret != SFC_OK)
872ba0501acSDingqiang Lin 		return ret;
873f28847a8SJon Lin 
874ba0501acSDingqiang Lin 	ret = sfc_nand_wait_busy(&status, 1000 * 1000);
875ba0501acSDingqiang Lin 	if (status & (1 << 3))
876ba0501acSDingqiang Lin 		return SFC_NAND_PROG_ERASE_ERROR;
877c84f0ed8SJon Lin 
878ba0501acSDingqiang Lin 	return ret;
879ba0501acSDingqiang Lin }
880ba0501acSDingqiang Lin 
881c84f0ed8SJon Lin u32 sfc_nand_prog_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare)
882c84f0ed8SJon Lin {
883c84f0ed8SJon Lin 	int ret;
884c84f0ed8SJon Lin 	u32 sec_per_page = p_nand_info->sec_per_page;
885c84f0ed8SJon Lin 	u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE;
886a6fcac41SJon Lin 	struct nand_mega_area *meta = &p_nand_info->meta;
887c84f0ed8SJon Lin 
888c84f0ed8SJon Lin 	memcpy(gp_page_buf, p_data, data_size);
889c84f0ed8SJon Lin 	memset(&gp_page_buf[data_size / 4], 0xff, sec_per_page * 16);
890a6fcac41SJon Lin 	gp_page_buf[(data_size + meta->off0) / 4] = p_spare[0];
891a6fcac41SJon Lin 	gp_page_buf[(data_size + meta->off1) / 4] = p_spare[1];
892f28847a8SJon Lin 
893c84f0ed8SJon Lin 	if (sec_per_page == 8) {
894a6fcac41SJon Lin 		gp_page_buf[(data_size + meta->off2) / 4] = p_spare[2];
895a6fcac41SJon Lin 		gp_page_buf[(data_size + meta->off3) / 4] = p_spare[3];
896c84f0ed8SJon Lin 	}
897f28847a8SJon Lin 
898c84f0ed8SJon Lin 	ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf);
899c84f0ed8SJon Lin 
900c84f0ed8SJon Lin 	return ret;
901c84f0ed8SJon Lin }
902c84f0ed8SJon Lin 
903a80fd396SJon Lin u32 sfc_nand_read(u32 row, u32 *p_page_buf, u32 column, u32 len)
904ba0501acSDingqiang Lin {
905ba0501acSDingqiang Lin 	int ret;
906415cf080Sjon.lin 	u32 plane;
90758463f4dSJon Lin 	struct rk_sfc_op op;
9086281205aSDingqiang Lin 	u32 ecc_result;
909a6fcac41SJon Lin 	u8 status;
910ba0501acSDingqiang Lin 
91158463f4dSJon Lin 	op.sfcmd.d32 = 0;
912f28847a8SJon Lin 	op.sfcmd.b.cmd = 0x13;
91358463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
91458463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_24BITS;
91558463f4dSJon Lin 
91658463f4dSJon Lin 	op.sfctrl.d32 = 0;
91758463f4dSJon Lin 
918a80fd396SJon Lin 	sfc_request(&op, row, p_page_buf, 0);
919f28847a8SJon Lin 
920ba0501acSDingqiang Lin 	if (sfc_nand_dev.read_lines == DATA_LINES_X4 &&
92125098c06SDingqiang Lin 	    p_nand_info->feature & FEA_SOFT_QOP_BIT &&
92225098c06SDingqiang Lin 	    sfc_get_version() < SFC_VER_3)
923ba0501acSDingqiang Lin 		sfc_nand_rw_preset();
924ba0501acSDingqiang Lin 
925a6fcac41SJon Lin 	sfc_nand_wait_busy(&status, 1000 * 1000);
926a6fcac41SJon Lin 	ecc_result = p_nand_info->ecc_status();
927a6fcac41SJon Lin 
92858463f4dSJon Lin 	op.sfcmd.d32 = 0;
92958463f4dSJon Lin 	op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd;
930a80fd396SJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
931a80fd396SJon Lin 	op.sfcmd.b.dummybits = 8;
93258463f4dSJon Lin 
93358463f4dSJon Lin 	op.sfctrl.d32 = 0;
93458463f4dSJon Lin 	op.sfctrl.b.datalines = sfc_nand_dev.read_lines;
935a80fd396SJon Lin 	op.sfctrl.b.addrbits = 16;
936ba0501acSDingqiang Lin 
937a80fd396SJon Lin 	plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0;
938a80fd396SJon Lin 	ret = sfc_request(&op, plane | column, p_page_buf, len);
939a80fd396SJon Lin 	rkflash_print_dio("%s %x %x\n", __func__, row, p_page_buf[0]);
940c84f0ed8SJon Lin 
941c84f0ed8SJon Lin 	if (ret != SFC_OK)
942f28847a8SJon Lin 		return SFC_NAND_HW_ERROR;
943c84f0ed8SJon Lin 
944c84f0ed8SJon Lin 	return ecc_result;
945c84f0ed8SJon Lin }
946c84f0ed8SJon Lin 
947a80fd396SJon Lin u32 sfc_nand_read_page_raw(u8 cs, u32 addr, u32 *p_page_buf)
948a80fd396SJon Lin {
949a80fd396SJon Lin 	u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page;
950a80fd396SJon Lin 
951a80fd396SJon Lin 	return sfc_nand_read(addr, p_page_buf, 0, page_size);
952a80fd396SJon Lin }
953a80fd396SJon Lin 
954c84f0ed8SJon Lin u32 sfc_nand_read_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare)
955c84f0ed8SJon Lin {
95658463f4dSJon Lin 	u32 ret;
957c84f0ed8SJon Lin 	u32 sec_per_page = p_nand_info->sec_per_page;
958c84f0ed8SJon Lin 	u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE;
959a6fcac41SJon Lin 	struct nand_mega_area *meta = &p_nand_info->meta;
960c84f0ed8SJon Lin 
961c84f0ed8SJon Lin 	ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf);
962f25e3cafSJon Lin 	memcpy(p_data, gp_page_buf, data_size);
963a6fcac41SJon Lin 	p_spare[0] = gp_page_buf[(data_size + meta->off0) / 4];
964a6fcac41SJon Lin 	p_spare[1] = gp_page_buf[(data_size + meta->off1) / 4];
965f28847a8SJon Lin 
966f25e3cafSJon Lin 	if (p_nand_info->sec_per_page == 8) {
967a6fcac41SJon Lin 		p_spare[2] = gp_page_buf[(data_size + meta->off2) / 4];
968a6fcac41SJon Lin 		p_spare[3] = gp_page_buf[(data_size + meta->off3) / 4];
969f25e3cafSJon Lin 	}
970ba0501acSDingqiang Lin 
971f28847a8SJon Lin 	if (ret == SFC_NAND_HW_ERROR)
972f28847a8SJon Lin 		ret = SFC_NAND_ECC_ERROR;
973f28847a8SJon Lin 
974c84f0ed8SJon Lin 	if (ret != SFC_NAND_ECC_OK) {
975c84f0ed8SJon Lin 		rkflash_print_error("%s[0x%x], ret=0x%x\n", __func__, addr, ret);
976f28847a8SJon Lin 
977ba0501acSDingqiang Lin 		if (p_data)
978c84f0ed8SJon Lin 			rkflash_print_hex("data:", p_data, 4, 8);
979f28847a8SJon Lin 
980ba0501acSDingqiang Lin 		if (p_spare)
981c84f0ed8SJon Lin 			rkflash_print_hex("spare:", p_spare, 4, 2);
982ba0501acSDingqiang Lin 	}
983f25e3cafSJon Lin 
984c84f0ed8SJon Lin 	return ret;
985ba0501acSDingqiang Lin }
986ba0501acSDingqiang Lin 
987c84f0ed8SJon Lin u32 sfc_nand_check_bad_block(u8 cs, u32 addr)
988c84f0ed8SJon Lin {
989c84f0ed8SJon Lin 	u32 ret;
990c84f0ed8SJon Lin 	u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE;
991a80fd396SJon Lin 	u32 marker = 0;
992c84f0ed8SJon Lin 
993a80fd396SJon Lin 	ret = sfc_nand_read(addr, &marker, data_size, 2);
994f28847a8SJon Lin 
995f28847a8SJon Lin 	/* unify with mtd framework */
996629111d3SJon Lin 	if (ret == SFC_NAND_ECC_ERROR || (u16)marker != 0xffff)
997a80fd396SJon Lin 		rkflash_print_error("%s page= %x ret= %x spare= %x\n",
998a80fd396SJon Lin 				    __func__, addr, ret, marker);
999f28847a8SJon Lin 
1000c84f0ed8SJon Lin 	/* Original bad block */
1001a80fd396SJon Lin 	if ((u16)marker != 0xffff)
1002c84f0ed8SJon Lin 		return true;
1003c84f0ed8SJon Lin 
1004c84f0ed8SJon Lin 	return false;
1005c84f0ed8SJon Lin }
1006c84f0ed8SJon Lin 
1007c84f0ed8SJon Lin u32 sfc_nand_mark_bad_block(u8 cs, u32 addr)
1008c84f0ed8SJon Lin {
1009c84f0ed8SJon Lin 	u32 ret;
1010c84f0ed8SJon Lin 	u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE;
1011c84f0ed8SJon Lin 
1012c84f0ed8SJon Lin 	ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf);
1013f28847a8SJon Lin 
1014c84f0ed8SJon Lin 	if (ret)
1015c84f0ed8SJon Lin 		return SFC_NAND_HW_ERROR;
1016f28847a8SJon Lin 
1017c84f0ed8SJon Lin 	gp_page_buf[data_size / 4] = 0x0;
1018c84f0ed8SJon Lin 	ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf);
1019f28847a8SJon Lin 
1020c84f0ed8SJon Lin 	if (ret)
1021c84f0ed8SJon Lin 		return SFC_NAND_HW_ERROR;
1022c84f0ed8SJon Lin 
1023c84f0ed8SJon Lin 	return ret;
1024c84f0ed8SJon Lin }
1025c84f0ed8SJon Lin 
1026c84f0ed8SJon Lin int sfc_nand_read_id(u8 *data)
1027ba0501acSDingqiang Lin {
1028ba0501acSDingqiang Lin 	int ret;
102958463f4dSJon Lin 	struct rk_sfc_op op;
1030ba0501acSDingqiang Lin 
103158463f4dSJon Lin 	op.sfcmd.d32 = 0;
103258463f4dSJon Lin 	op.sfcmd.b.cmd = CMD_READ_JEDECID;
103358463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
1034ba0501acSDingqiang Lin 
103558463f4dSJon Lin 	op.sfctrl.d32 = 0;
103658463f4dSJon Lin 	op.sfctrl.b.addrbits = 8;
103758463f4dSJon Lin 
103858463f4dSJon Lin 	ret = sfc_request(&op, 0, data, 3);
1039ba0501acSDingqiang Lin 
1040ba0501acSDingqiang Lin 	return ret;
1041ba0501acSDingqiang Lin }
1042ba0501acSDingqiang Lin 
1043ba0501acSDingqiang Lin /*
1044ba0501acSDingqiang Lin  * Read the 1st page's 1st byte of a phy_blk
1045ba0501acSDingqiang Lin  * If not FF, it's bad blk
1046ba0501acSDingqiang Lin  */
1047ba0501acSDingqiang Lin static int sfc_nand_get_bad_block_list(u16 *table, u32 die)
1048ba0501acSDingqiang Lin {
1049ba0501acSDingqiang Lin 	u32 bad_cnt, page;
1050ba0501acSDingqiang Lin 	u32 blk_per_die;
10512ac88c1bSJon Lin 	u16 blk;
1052ba0501acSDingqiang Lin 
1053c84f0ed8SJon Lin 	rkflash_print_info("%s\n", __func__);
1054c84f0ed8SJon Lin 
1055ba0501acSDingqiang Lin 	bad_cnt = 0;
1056ba0501acSDingqiang Lin 	blk_per_die = p_nand_info->plane_per_die *
1057ba0501acSDingqiang Lin 		      p_nand_info->blk_per_plane;
1058f28847a8SJon Lin 
1059ba0501acSDingqiang Lin 	for (blk = 0; blk < blk_per_die; blk++) {
1060ba0501acSDingqiang Lin 		page = (blk + blk_per_die * die) *
1061ba0501acSDingqiang Lin 		       p_nand_info->page_per_blk;
1062ba0501acSDingqiang Lin 
10632ac88c1bSJon Lin 		if (sfc_nand_check_bad_block(die, page)) {
1064ba0501acSDingqiang Lin 			table[bad_cnt++] = blk;
1065c84f0ed8SJon Lin 			rkflash_print_error("die[%d], bad_blk[%d]\n", die, blk);
1066ba0501acSDingqiang Lin 		}
1067ba0501acSDingqiang Lin 	}
1068f28847a8SJon Lin 
1069ba0501acSDingqiang Lin 	return (int)bad_cnt;
1070ba0501acSDingqiang Lin }
1071ba0501acSDingqiang Lin 
1072c84f0ed8SJon Lin void sfc_nand_ftl_ops_init(void)
1073ba0501acSDingqiang Lin {
1074ba0501acSDingqiang Lin 	/* para init */
1075ba0501acSDingqiang Lin 	g_nand_phy_info.nand_type	= 1;
1076ba0501acSDingqiang Lin 	g_nand_phy_info.die_num		= 1;
1077ba0501acSDingqiang Lin 	g_nand_phy_info.plane_per_die	= p_nand_info->plane_per_die;
1078ba0501acSDingqiang Lin 	g_nand_phy_info.blk_per_plane	= p_nand_info->blk_per_plane;
1079ba0501acSDingqiang Lin 	g_nand_phy_info.page_per_blk	= p_nand_info->page_per_blk;
1080ba0501acSDingqiang Lin 	g_nand_phy_info.page_per_slc_blk = p_nand_info->page_per_blk;
1081c84f0ed8SJon Lin 	g_nand_phy_info.byte_per_sec	= SFC_NAND_SECTOR_SIZE;
1082ba0501acSDingqiang Lin 	g_nand_phy_info.sec_per_page	= p_nand_info->sec_per_page;
1083ba0501acSDingqiang Lin 	g_nand_phy_info.sec_per_blk	= p_nand_info->sec_per_page *
1084ba0501acSDingqiang Lin 					  p_nand_info->page_per_blk;
1085ba0501acSDingqiang Lin 	g_nand_phy_info.reserved_blk	= 8;
1086ba0501acSDingqiang Lin 	g_nand_phy_info.blk_per_die	= p_nand_info->plane_per_die *
1087ba0501acSDingqiang Lin 					  p_nand_info->blk_per_plane;
1088ba0501acSDingqiang Lin 	g_nand_phy_info.ecc_bits	= p_nand_info->max_ecc_bits;
1089ba0501acSDingqiang Lin 
1090ba0501acSDingqiang Lin 	/* driver register */
1091ba0501acSDingqiang Lin 	g_nand_ops.get_bad_blk_list	= sfc_nand_get_bad_block_list;
1092ba0501acSDingqiang Lin 	g_nand_ops.erase_blk		= sfc_nand_erase_block;
1093ba0501acSDingqiang Lin 	g_nand_ops.prog_page		= sfc_nand_prog_page;
1094ba0501acSDingqiang Lin 	g_nand_ops.read_page		= sfc_nand_read_page;
109557d18453Sjon.lin 	g_nand_ops.bch_sel		= NULL;
1096ba0501acSDingqiang Lin }
1097ba0501acSDingqiang Lin 
1098a6fcac41SJon Lin static int sfc_nand_enable_QE(void)
1099ba0501acSDingqiang Lin {
1100ba0501acSDingqiang Lin 	int ret = SFC_OK;
1101ba0501acSDingqiang Lin 	u8 status;
1102ba0501acSDingqiang Lin 
1103f28847a8SJon Lin 	ret = sfc_nand_read_feature(0xB0, &status);
1104ba0501acSDingqiang Lin 
1105ba0501acSDingqiang Lin 	if (ret != SFC_OK)
1106ba0501acSDingqiang Lin 		return ret;
1107ba0501acSDingqiang Lin 
1108f28847a8SJon Lin 	if (status & 1)   /* is QE bit set */
1109ba0501acSDingqiang Lin 		return SFC_OK;
1110ba0501acSDingqiang Lin 
1111f28847a8SJon Lin 	status |= 1;
1112ba0501acSDingqiang Lin 
1113f28847a8SJon Lin 	return sfc_nand_write_feature(0xB0, status);
1114ba0501acSDingqiang Lin }
1115ba0501acSDingqiang Lin 
1116ba0501acSDingqiang Lin u32 sfc_nand_init(void)
1117ba0501acSDingqiang Lin {
1118c84f0ed8SJon Lin 	u8 status, id_byte[8];
1119ba0501acSDingqiang Lin 
1120c84f0ed8SJon Lin 	sfc_nand_read_id(id_byte);
1121c84f0ed8SJon Lin 	rkflash_print_error("sfc_nand id: %x %x %x\n",
1122ba0501acSDingqiang Lin 			    id_byte[0], id_byte[1], id_byte[2]);
1123f28847a8SJon Lin 
1124ba0501acSDingqiang Lin 	if (id_byte[0] == 0xFF || id_byte[0] == 0x00)
112558463f4dSJon Lin 		return (u32)FTL_NO_FLASH;
1126ba0501acSDingqiang Lin 
1127a6fcac41SJon Lin 	p_nand_info = sfc_nand_get_info(id_byte);
1128f28847a8SJon Lin 
112945292245SJon Lin 	if (!p_nand_info) {
113045292245SJon Lin 		pr_err("The device not support yet!\n");
113145292245SJon Lin 
113258463f4dSJon Lin 		return (u32)FTL_UNSUPPORTED_FLASH;
113345292245SJon Lin 	}
1134ba0501acSDingqiang Lin 
1135ba0501acSDingqiang Lin 	sfc_nand_dev.manufacturer = id_byte[0];
1136ba0501acSDingqiang Lin 	sfc_nand_dev.mem_type = id_byte[1];
1137c84f0ed8SJon Lin 	sfc_nand_dev.capacity = p_nand_info->density;
1138c84f0ed8SJon Lin 	sfc_nand_dev.block_size = p_nand_info->page_per_blk * p_nand_info->sec_per_page;
1139c84f0ed8SJon Lin 	sfc_nand_dev.page_size = p_nand_info->sec_per_page;
1140ba0501acSDingqiang Lin 
1141ba0501acSDingqiang Lin 	/* disable block lock */
1142ba0501acSDingqiang Lin 	sfc_nand_write_feature(0xA0, 0);
1143ba0501acSDingqiang Lin 	sfc_nand_dev.read_lines = DATA_LINES_X1;
1144ba0501acSDingqiang Lin 	sfc_nand_dev.prog_lines = DATA_LINES_X1;
1145f28847a8SJon Lin 	sfc_nand_dev.page_read_cmd = 0x03;
1146f28847a8SJon Lin 	sfc_nand_dev.page_prog_cmd = 0x02;
1147629111d3SJon Lin 	sfc_nand_dev.recheck_buffer = ftl_malloc(SFC_NAND_PAGE_MAX_SIZE);
1148629111d3SJon Lin 	if (!sfc_nand_dev.recheck_buffer) {
1149629111d3SJon Lin 		rkflash_print_error("%s recheck_buffer alloc failed\n", __func__);
1150629111d3SJon Lin 		return -1;
1151629111d3SJon Lin 	}
1152f28847a8SJon Lin 
1153ba0501acSDingqiang Lin 	if (p_nand_info->feature & FEA_4BIT_READ) {
1154f28847a8SJon Lin 		if ((p_nand_info->has_qe_bits && sfc_nand_enable_QE() == SFC_OK) ||
1155f28847a8SJon Lin 		    !p_nand_info->has_qe_bits) {
1156ba0501acSDingqiang Lin 			sfc_nand_dev.read_lines = DATA_LINES_X4;
1157f28847a8SJon Lin 			sfc_nand_dev.page_read_cmd = 0x6b;
1158ba0501acSDingqiang Lin 		}
1159ba0501acSDingqiang Lin 	}
1160ba0501acSDingqiang Lin 
1161ba0501acSDingqiang Lin 	if (p_nand_info->feature & FEA_4BIT_PROG &&
1162ba0501acSDingqiang Lin 	    sfc_nand_dev.read_lines == DATA_LINES_X4) {
1163ba0501acSDingqiang Lin 		sfc_nand_dev.prog_lines = DATA_LINES_X4;
1164f28847a8SJon Lin 		sfc_nand_dev.page_prog_cmd = 0x32;
1165ba0501acSDingqiang Lin 	}
1166ba0501acSDingqiang Lin 
1167ba0501acSDingqiang Lin 	sfc_nand_read_feature(0xA0, &status);
1168c84f0ed8SJon Lin 	rkflash_print_info("sfc_nand A0 = 0x%x\n", status);
1169ba0501acSDingqiang Lin 	sfc_nand_read_feature(0xB0, &status);
1170c84f0ed8SJon Lin 	rkflash_print_info("sfc_nand B0 = 0x%x\n", status);
1171c84f0ed8SJon Lin 	rkflash_print_info("read_lines = %x\n", sfc_nand_dev.read_lines);
1172c84f0ed8SJon Lin 	rkflash_print_info("prog_lines = %x\n", sfc_nand_dev.prog_lines);
1173c84f0ed8SJon Lin 	rkflash_print_info("page_read_cmd = %x\n", sfc_nand_dev.page_read_cmd);
1174c84f0ed8SJon Lin 	rkflash_print_info("page_prog_cmd = %x\n", sfc_nand_dev.page_prog_cmd);
1175ba0501acSDingqiang Lin 
1176ba0501acSDingqiang Lin 	return SFC_OK;
1177ba0501acSDingqiang Lin }
1178ba0501acSDingqiang Lin 
1179c84f0ed8SJon Lin void sfc_nand_deinit(void)
1180ba0501acSDingqiang Lin {
1181c84f0ed8SJon Lin 	/* to-do */
1182629111d3SJon Lin 	kfree(sfc_nand_dev.recheck_buffer);
1183ba0501acSDingqiang Lin }
1184c84f0ed8SJon Lin 
1185c84f0ed8SJon Lin struct SFNAND_DEV *sfc_nand_get_private_dev(void)
1186c84f0ed8SJon Lin {
1187c84f0ed8SJon Lin 	return &sfc_nand_dev;
1188c84f0ed8SJon Lin }
1189c84f0ed8SJon Lin 
1190