xref: /rk3399_rockchip-uboot/drivers/rkflash/sfc_nand.c (revision 50b7ce0b7ec12ebc2746d282d35207a09832b557)
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);
26d4db0b8dSJon Lin static u32 sfc_nand_get_ecc_status9(void);
27a4bd704eSJon Lin static u32 sfc_nand_get_ecc_status10(void);
2835c70cf8SJon Lin static u32 sfc_nand_get_ecc_status11(void);
29f28847a8SJon Lin 
30ba0501acSDingqiang Lin static struct nand_info spi_nand_tbl[] = {
31ba0501acSDingqiang Lin 	/* TC58CVG0S0HxAIx */
32b833c879SJon Lin 	{ 0x98, 0xC2, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
33ba0501acSDingqiang Lin 	/* TC58CVG1S0HxAIx */
34b833c879SJon Lin 	{ 0x98, 0xCB, 0x00, 4, 0x40, 2, 1024, 0x00, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
35a6fcac41SJon Lin 	/* TC58CVG2S0HRAIJ */
36b833c879SJon Lin 	{ 0x98, 0xED, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 0, { 0x04, 0x0C, 0x08, 0x10 }, &sfc_nand_get_ecc_status0 },
37a6fcac41SJon Lin 	/* TC58CVG1S3HRAIJ */
38b833c879SJon Lin 	{ 0x98, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
39a6fcac41SJon Lin 	/* TC58CVG0S3HRAIJ */
40b833c879SJon Lin 	{ 0x98, 0xE2, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
41f28847a8SJon Lin 
42f28847a8SJon Lin 	/* MX35LF1GE4AB */
43b833c879SJon Lin 	{ 0xC2, 0x12, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
44f28847a8SJon Lin 	/* MX35LF2GE4AB */
45b833c879SJon Lin 	{ 0xC2, 0x22, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
46f28847a8SJon Lin 	/* MX35LF2GE4AD */
47b833c879SJon Lin 	{ 0xC2, 0x26, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
48f28847a8SJon Lin 	/* MX35LF4GE4AD */
49362b1be1SJon Lin 	{ 0xC2, 0x37, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status0 },
50362b1be1SJon Lin 	/* MX35UF1GE4AC */
51362b1be1SJon Lin 	{ 0xC2, 0x92, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
52362b1be1SJon Lin 	/* MX35UF2GE4AC */
53362b1be1SJon Lin 	{ 0xC2, 0xA2, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
54f5e7a59fSJon Lin 	/* MX35UF1GE4AD */
55f5e7a59fSJon Lin 	{ 0xC2, 0x96, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
56f5e7a59fSJon Lin 	/* MX35UF2GE4AD */
57f5e7a59fSJon Lin 	{ 0xC2, 0xA6, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
58f5e7a59fSJon Lin 	/* MX35UF4GE4AD */
59f5e7a59fSJon Lin 	{ 0xC2, 0xB7, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status0 },
60f28847a8SJon Lin 
61f28847a8SJon Lin 	/* GD5F1GQ4UAYIG */
62b833c879SJon Lin 	{ 0xC8, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
63f28847a8SJon Lin 	/* GD5F1GQ4RB9IGR */
64b833c879SJon Lin 	{ 0xC8, 0xD1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
65f28847a8SJon Lin 	/* GD5F2GQ40BY2GR */
66b833c879SJon Lin 	{ 0xC8, 0xD2, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
67f28847a8SJon Lin 	/* GD5F1GQ5UEYIG */
68b833c879SJon Lin 	{ 0xC8, 0x51, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
69f28847a8SJon Lin 	/* GD5F2GQ5UEYIG */
70b833c879SJon Lin 	{ 0xC8, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
71f28847a8SJon Lin 	/* GD5F1GQ4R */
72b833c879SJon Lin 	{ 0xC8, 0xC1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
73362b1be1SJon Lin 	/* GD5F4GQ6RExxG 1*4096 */
74d4db0b8dSJon Lin 	{ 0xC8, 0x45, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status2 },
75362b1be1SJon Lin 	/* GD5F4GQ6UExxG 1*4096 */
76d4db0b8dSJon Lin 	{ 0xC8, 0x55, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status2 },
778a654f32SJon Lin 	/* GD5F1GQ4UExxH */
788a654f32SJon Lin 	{ 0xC8, 0xD9, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
79e5e85009SJon Lin 	/* GD5F1GQ5REYIG Add 3rd code to distingush with F50L2G41KA */
80e5e85009SJon Lin 	{ 0xC8, 0x41, 0xC8, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
81bf620bf6SJon Lin 	/* GD5F2GQ5REYIG */
82bf620bf6SJon Lin 	{ 0xC8, 0x42, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
83bf620bf6SJon Lin 	/* GD5F2GM7RxG */
84e5e85009SJon Lin 	{ 0xC8, 0x82, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
85bf620bf6SJon Lin 	/* GD5F2GM7UxG */
86e5e85009SJon Lin 	{ 0xC8, 0x92, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
8745292245SJon Lin 	/* GD5F1GM7UxG */
88e5e85009SJon Lin 	{ 0xC8, 0x91, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
89d4db0b8dSJon Lin 	/* GD5F4GQ4UAYIG 1*4096 */
90d4db0b8dSJon Lin 	{ 0xC8, 0xF4, 0x00, 4, 0x40, 2, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status0 },
91e5e85009SJon Lin 	/* GD5F1GM7REYIGR */
92e5e85009SJon Lin 	{ 0xC8, 0x81, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
93e5e85009SJon Lin 	/* GD5F4GM8UEYIGR */
94*50b7ce0bSJon Lin 	{ 0xC8, 0x95, 0x00, 4, 0x40, 1, 4096, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status3 },
95f28847a8SJon Lin 
96f28847a8SJon Lin 	/* W25N01GV */
97b833c879SJon Lin 	{ 0xEF, 0xAA, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 },
98b833c879SJon Lin 	/* W25N02KVZEIR */
99b833c879SJon Lin 	{ 0xEF, 0xAA, 0x22, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status0 },
100629111d3SJon Lin 	/* W25N04KVZEIR */
101629111d3SJon Lin 	{ 0xEF, 0xAA, 0x23, 4, 0x40, 1, 4096, 0x4C, 20, 0x8, 0, { 0x04, 0x14, 0x24, 0x34 }, &sfc_nand_get_ecc_status0 },
102f28847a8SJon Lin 	/* W25N01GW */
1037bdae1e3SJon Lin 	{ 0xEF, 0xBA, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 },
1047bdae1e3SJon Lin 	/* W25N02KW */
1057bdae1e3SJon Lin 	{ 0xEF, 0xBA, 0x22, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status0 },
1068a654f32SJon Lin 	/* W25N512GVEIG */
1078a654f32SJon Lin 	{ 0xEF, 0xAA, 0x20, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 },
108f5e7a59fSJon Lin 	/* W25N01KV */
109f5e7a59fSJon Lin 	{ 0xEF, 0xAE, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
110a4bd704eSJon Lin 	/* W25N01JWZEIG */
111a4bd704eSJon Lin 	{ 0xEF, 0xBC, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
112a4bd704eSJon Lin 	/* W25N01KWZPIG */
113a4bd704eSJon Lin 	{ 0xEF, 0xBE, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
114f28847a8SJon Lin 
115f28847a8SJon Lin 	/* HYF2GQ4UAACAE */
116b833c879SJon Lin 	{ 0xC9, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
117f28847a8SJon Lin 	/* HYF1GQ4UDACAE */
118b833c879SJon Lin 	{ 0xC9, 0x21, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
119f28847a8SJon Lin 	/* HYF1GQ4UPACAE */
120b833c879SJon Lin 	{ 0xC9, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
121f28847a8SJon Lin 	/* HYF2GQ4UDACAE */
122b833c879SJon Lin 	{ 0xC9, 0x22, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
123f28847a8SJon Lin 	/* HYF2GQ4UHCCAE */
124b833c879SJon Lin 	{ 0xC9, 0x5A, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
125f28847a8SJon Lin 	/* HYF4GQ4UAACBE */
12606efa4f9SJon Lin 	{ 0xC9, 0xD4, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0xE, 1, { 0x20, 0x40, 0x24, 0x44 }, &sfc_nand_get_ecc_status0 },
12706efa4f9SJon Lin 	/* HYF2GQ4IAACAE */
128*50b7ce0bSJon Lin 	{ 0xC9, 0x82, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
12906efa4f9SJon Lin 	/* HYF1GQ4IDACAE */
130*50b7ce0bSJon Lin 	{ 0xC9, 0x81, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
131f28847a8SJon Lin 
132f28847a8SJon Lin 	/* FS35ND01G-S1 */
133b833c879SJon Lin 	{ 0xCD, 0xB1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
134f28847a8SJon Lin 	/* FS35ND02G-S2 */
135b833c879SJon Lin 	{ 0xCD, 0xA2, 0x00, 4, 0x40, 1, 2048, 0x00, 19, 0x4, 0, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
13658463f4dSJon Lin 	/* FS35ND01G-S1Y2 */
137b833c879SJon Lin 	{ 0xCD, 0xEA, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
138f1b20f5aSJon Lin 	/* FS35ND02G-S3Y2 */
139b833c879SJon Lin 	{ 0xCD, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
140f28847a8SJon Lin 	/* FS35ND04G-S2Y2 1*4096 */
141*50b7ce0bSJon Lin 	{ 0xCD, 0xEC, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 0, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status1 },
142bf620bf6SJon Lin 	/* F35SQA001G */
143bf620bf6SJon Lin 	{ 0xCD, 0x71, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
14445292245SJon Lin 	/* F35SQA002G */
14545292245SJon Lin 	{ 0xCD, 0x72, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
146d4db0b8dSJon Lin 	/* F35SQA512M */
147d4db0b8dSJon Lin 	{ 0xCD, 0x70, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
148d4db0b8dSJon Lin 	/* F35UQA512M */
149f5e7a59fSJon Lin 	{ 0xCD, 0x60, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
150e5e85009SJon Lin 	/* F35UQA002G-WWT */
151e5e85009SJon Lin 	{ 0xCD, 0x62, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
152a4bd704eSJon Lin 	/* F35SQB004G-WWT */
153e5e85009SJon Lin 	{ 0xCD, 0x61, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
154a4bd704eSJon Lin 	/* F35SQB004G */
155a4bd704eSJon Lin 	{ 0xCD, 0x53, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status10 },
156a4bd704eSJon Lin 	/* F35SQB002G */
157a4bd704eSJon Lin 	{ 0xCD, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status10 },
158f28847a8SJon Lin 
159f28847a8SJon Lin 	/* DS35Q1GA-IB */
160b833c879SJon Lin 	{ 0xE5, 0x71, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
161f28847a8SJon Lin 	/* DS35Q2GA-IB */
162b833c879SJon Lin 	{ 0xE5, 0x72, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
163f28847a8SJon Lin 	/* DS35M1GA-1B */
164b833c879SJon Lin 	{ 0xE5, 0x21, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
165bf620bf6SJon Lin 	/* DS35M2GA-IB */
166bf620bf6SJon Lin 	{ 0xE5, 0x22, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
167d4db0b8dSJon Lin 	/* DS35Q1GB-IB */
168d4db0b8dSJon Lin 	{ 0xE5, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
169629111d3SJon Lin 	/* DS35Q2GB-IB */
170629111d3SJon Lin 	{ 0xE5, 0xF2, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
171d4db0b8dSJon Lin 	/* DS35Q4GM */
172*50b7ce0bSJon Lin 	{ 0xE5, 0xF4, 0x00, 4, 0x40, 2, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x14, 0x0C, 0x10 }, &sfc_nand_get_ecc_status6 },
173bf620bf6SJon Lin 	/* DS35M1GB-IB */
174bf620bf6SJon Lin 	{ 0xE5, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
175f5e7a59fSJon Lin 	/* DS35Q12B-IB */
176f5e7a59fSJon Lin 	{ 0xE5, 0xF5, 0x00, 4, 0x40, 1, 512, 0x0C, 17, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
177f5e7a59fSJon Lin 	/* DS35M12B-IB */
178f5e7a59fSJon Lin 	{ 0xE5, 0xA5, 0x00, 4, 0x40, 1, 512, 0x0C, 17, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
179e5e85009SJon Lin 	/* DS35Q1GD-IB */
180e5e85009SJon Lin 	{ 0xE5, 0x51, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
181a4bd704eSJon Lin 	/* DS35M4GB-IB */
182*50b7ce0bSJon Lin 	{ 0xE5, 0x64, 0x00, 4, 0x40, 1, 4096, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status6 },
183a4bd704eSJon Lin 	/* DS35Q4GB-IB */
184*50b7ce0bSJon Lin 	{ 0xE5, 0xB4, 0x00, 4, 0x40, 1, 4096, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status6 },
185a4bd704eSJon Lin 	/* DS35M12C-IB */
186a4bd704eSJon Lin 	{ 0xE5, 0x25, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
187a4bd704eSJon Lin 	/* DS35Q12C-IB */
188a4bd704eSJon Lin 	{ 0xE5, 0x75, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
189a4bd704eSJon Lin 	/* DS35Q2GBS */
190a4bd704eSJon Lin 	{ 0xE5, 0xB2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
191f28847a8SJon Lin 
192f28847a8SJon Lin 	/* EM73C044VCC-H */
193b833c879SJon Lin 	{ 0xD5, 0x22, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
194f28847a8SJon Lin 	/* EM73D044VCE-H */
195b833c879SJon Lin 	{ 0xD5, 0x20, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
196f28847a8SJon Lin 	/* EM73E044SNA-G */
197b833c879SJon Lin 	{ 0xD5, 0x03, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x28, 0x08, 0x2C }, &sfc_nand_get_ecc_status0 },
198629111d3SJon Lin 	/* EM73C044VCF-H */
199629111d3SJon Lin 	{ 0xD5, 0x25, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
200*50b7ce0bSJon Lin 	/* EM73E044VCE-H */
201*50b7ce0bSJon Lin 	{ 0xD5, 0x3B, 0x00, 4, 0x40, 1, 4096, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status0 },
202f28847a8SJon Lin 
203f28847a8SJon Lin 	/* XT26G02A */
204362b1be1SJon Lin 	{ 0x0B, 0xE2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
205f28847a8SJon Lin 	/* XT26G01A */
206362b1be1SJon Lin 	{ 0x0B, 0xE1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
207f28847a8SJon Lin 	/* XT26G04A */
208*50b7ce0bSJon Lin 	{ 0x0B, 0xE3, 0x00, 4, 0x80, 1, 2048, 0x4C, 20, 0x8, 1, { 0x08, 0x0C, 0x0C, 0x10 }, &sfc_nand_get_ecc_status4 },
209f28847a8SJon Lin 	/* XT26G01B */
210362b1be1SJon Lin 	{ 0x0B, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
211f28847a8SJon Lin 	/* XT26G02B */
212362b1be1SJon Lin 	{ 0x0B, 0xF2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
213362b1be1SJon Lin 	/* XT26G01C */
214362b1be1SJon Lin 	{ 0x0B, 0x11, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 },
215362b1be1SJon Lin 	/* XT26G02C */
216362b1be1SJon Lin 	{ 0x0B, 0x12, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 },
217362b1be1SJon Lin 	/* XT26G04C */
218362b1be1SJon Lin 	{ 0x0B, 0x13, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status7 },
219629111d3SJon Lin 	/* XT26G11C */
220629111d3SJon Lin 	{ 0x0B, 0x15, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
221e5e85009SJon Lin 	/* XT26Q02DWSIGA */
222e5e85009SJon Lin 	{ 0x0B, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
223e5e85009SJon Lin 	/* XT26Q01DWSIGA */
224e5e85009SJon Lin 	{ 0x0B, 0x51, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
225e5e85009SJon Lin 	/* XT26Q04DWSIGA */
226e5e85009SJon Lin 	{ 0x0B, 0x53, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status0 },
227e5e85009SJon Lin 	/* XT26G01DWSIGA */
228e5e85009SJon Lin 	{ 0x0B, 0x31, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
229e5e85009SJon Lin 	/* XT26G02DWSIGA */
230e5e85009SJon Lin 	{ 0x0B, 0x32, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
231e5e85009SJon Lin 	/* XT26G04DWSIGA */
232e5e85009SJon Lin 	{ 0x0B, 0x33, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status0 },
233a4bd704eSJon Lin 	/* XT26Q04DWSIGT-B */
234a4bd704eSJon Lin 	{ 0x0B, 0x53, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x14, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status0 },
235a4bd704eSJon Lin 	/* XT26Q01DWSIGA */
236a4bd704eSJon Lin 	{ 0x0B, 0x51, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
237a80fd396SJon Lin 
238362b1be1SJon Lin 	/* MT29F2G01ABA, XT26G02E, F50L2G41XA */
239629111d3SJon Lin 	{ 0x2C, 0x24, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x8, 0, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
240629111d3SJon Lin 	/* MT29F1G01ABA, F50L1G41XA */
241629111d3SJon Lin 	{ 0x2C, 0x14, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 0, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
242a80fd396SJon Lin 
243a80fd396SJon Lin 	/* FM25S01 */
244b833c879SJon Lin 	{ 0xA1, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x00, 0x04, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
245a80fd396SJon Lin 	/* FM25S01A */
246b833c879SJon Lin 	{ 0xA1, 0xE4, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
247a80fd396SJon Lin 	/* FM25S02A */
248b833c879SJon Lin 	{ 0xA1, 0xE5, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
2497bdae1e3SJon Lin 	/* FM25LS01 */
2507bdae1e3SJon Lin 	{ 0xA1, 0xA5, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
251e5e85009SJon Lin 	/* FM25S01BI3 */
252e5e85009SJon Lin 	{ 0xA1, 0xD4, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
253e5e85009SJon Lin 	/* FM25G02BI3 */
254e5e85009SJon Lin 	{ 0xA1, 0xD2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
255a4bd704eSJon Lin 	/* FM25S02BI3-DND-A-G3 */
256a4bd704eSJon Lin 	{ 0xA1, 0xD6, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
257a4bd704eSJon Lin 	/* FM25G02D */
258a4bd704eSJon Lin 	{ 0xA1, 0xF2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
259f28847a8SJon Lin 
260f28847a8SJon Lin 	/* IS37SML01G1 */
261b833c879SJon Lin 	{ 0xC8, 0x21, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x1, 0, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
262f28847a8SJon Lin 	/* F50L1G41LB */
263b833c879SJon Lin 	{ 0xC8, 0x01, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
264e5e85009SJon Lin 	/* F50L2G41KA */
265e5e85009SJon Lin 	{ 0xC8, 0x41, 0x7F, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
266e5e85009SJon Lin 
267e5e85009SJon Lin 	/* UM19A1HISW */
268e5e85009SJon Lin 	{ 0xB0, 0x24, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
269e5e85009SJon Lin 	/* UM19A0HCSW */
270e5e85009SJon Lin 	{ 0xB0, 0x14, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
271e5e85009SJon Lin 	/* UM19A0LCSW */
272e5e85009SJon Lin 	{ 0xB0, 0x15, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
273e5e85009SJon Lin 	/* UM19A1LISW */
274e5e85009SJon Lin 	{ 0xB0, 0x25, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
275a4bd704eSJon Lin 	/* UM19A9LISW */
276a4bd704eSJon Lin 	{ 0xB0, 0x0D, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
277a4bd704eSJon Lin 	/* UM19A9HISW */
278a4bd704eSJon Lin 	{ 0xB0, 0x0C, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
27935c70cf8SJon Lin 	/* UM19A0HISW */
28035c70cf8SJon Lin 	{ 0xB0, 0x14, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status11 },
28135c70cf8SJon Lin 	/* UM19A0LISW */
28235c70cf8SJon Lin 	{ 0xB0, 0x15, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status11 },
283e5e85009SJon Lin 
284f28847a8SJon Lin 	/* ATO25D1GA */
285b833c879SJon Lin 	{ 0x9B, 0x12, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x1, 1, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
286362b1be1SJon Lin 	/* BWJX08K-2Gb */
287362b1be1SJon Lin 	{ 0xBC, 0xB3, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x10, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
288629111d3SJon Lin 	/* JS28U1GQSCAHG-83 */
289629111d3SJon Lin 	{ 0xBF, 0x21, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x4, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status8 },
2908a654f32SJon Lin 	/* SGM7000I-S24W1GH */
2918a654f32SJon Lin 	{ 0xEA, 0xC1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
292bf620bf6SJon Lin 	/* TX25G01 */
293bf620bf6SJon Lin 	{ 0xA1, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status8 },
294e5e85009SJon Lin 
295a4bd704eSJon Lin 	/* S35ML01G3, ANV1GCP0CLG, HYF1GQ4UTXCAE, YX25G1E, GSS01GSAM0 */
296f5e7a59fSJon Lin 	{ 0x01, 0x15, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status9 },
297e5e85009SJon Lin 	/* S35ML02G3, ANV2GCP0CLG, HYF2GQ4UTXCAE, YX25G2E */
298f5e7a59fSJon Lin 	{ 0x01, 0x25, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status9 },
299d4db0b8dSJon Lin 	/* S35ML04G3 */
300f5e7a59fSJon Lin 	{ 0x01, 0x35, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 0, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status9 },
301e5e85009SJon Lin 
30206efa4f9SJon Lin 	/* GSS01GSAK1 */
30306efa4f9SJon Lin 	{ 0x52, 0xBA, 0x13, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
30406efa4f9SJon Lin 	/* GSS02GSAK1 */
30506efa4f9SJon Lin 	{ 0x52, 0xBA, 0x23, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
306a4bd704eSJon Lin 	/* GSS02GSAX1 */
307a4bd704eSJon Lin 	{ 0x52, 0xCA, 0x23, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
308a4bd704eSJon Lin 	/* GSS01GSAX1 */
309a4bd704eSJon Lin 	{ 0x52, 0xCA, 0x13, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
310e5e85009SJon Lin 
311e5e85009SJon Lin 	/* XCSP2AAPK */
312e5e85009SJon Lin 	{ 0x8C, 0xA1, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
313e5e85009SJon Lin 	/* XCSP1AAPK */
314e5e85009SJon Lin 	{ 0x8C, 0x01, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
315a4bd704eSJon Lin 	/* F50L1G41LC */
316a4bd704eSJon Lin 	{ 0x8C, 0x2C, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x1, 0, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
317a4bd704eSJon Lin 
318a4bd704eSJon Lin 	/* ZB35Q01BYIG */
319a4bd704eSJon Lin 	{ 0x5E, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
320a4bd704eSJon Lin 	/* ZB35Q04BYIG */
321*50b7ce0bSJon Lin 	{ 0x5E, 0xA3, 0x00, 4, 0x80, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status1 },
322a4bd704eSJon Lin 
323a4bd704eSJon Lin 	/* HSESYHDSW2G */
324a4bd704eSJon Lin 	{ 0x3C, 0xD2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
325ba0501acSDingqiang Lin };
326ba0501acSDingqiang Lin 
327ba0501acSDingqiang Lin static struct nand_info *p_nand_info;
328ba0501acSDingqiang Lin static u32 gp_page_buf[SFC_NAND_PAGE_MAX_SIZE / 4];
329ba0501acSDingqiang Lin static struct SFNAND_DEV sfc_nand_dev;
330ba0501acSDingqiang Lin 
sfc_nand_get_info(u8 * nand_id)331a6fcac41SJon Lin static struct nand_info *sfc_nand_get_info(u8 *nand_id)
332ba0501acSDingqiang Lin {
333ba0501acSDingqiang Lin 	u32 i;
334ba0501acSDingqiang Lin 
335ba0501acSDingqiang Lin 	for (i = 0; i < ARRAY_SIZE(spi_nand_tbl); i++) {
336b833c879SJon Lin 		if (spi_nand_tbl[i].id0 == nand_id[0] &&
337b833c879SJon Lin 		    spi_nand_tbl[i].id1 == nand_id[1]) {
338b833c879SJon Lin 			if (spi_nand_tbl[i].id2 &&
339b833c879SJon Lin 			    spi_nand_tbl[i].id2 != nand_id[2])
340b833c879SJon Lin 				continue;
341b833c879SJon Lin 
342ba0501acSDingqiang Lin 			return &spi_nand_tbl[i];
343ba0501acSDingqiang Lin 		}
344b833c879SJon Lin 	}
345f28847a8SJon Lin 
346ba0501acSDingqiang Lin 	return NULL;
347ba0501acSDingqiang Lin }
348ba0501acSDingqiang Lin 
sfc_nand_write_en(void)349ba0501acSDingqiang Lin static int sfc_nand_write_en(void)
350ba0501acSDingqiang Lin {
351ba0501acSDingqiang Lin 	int ret;
35258463f4dSJon Lin 	struct rk_sfc_op op;
353ba0501acSDingqiang Lin 
35458463f4dSJon Lin 	op.sfcmd.d32 = 0;
35558463f4dSJon Lin 	op.sfcmd.b.cmd = CMD_WRITE_EN;
35658463f4dSJon Lin 
35758463f4dSJon Lin 	op.sfctrl.d32 = 0;
35858463f4dSJon Lin 
35958463f4dSJon Lin 	ret = sfc_request(&op, 0, NULL, 0);
360ba0501acSDingqiang Lin 	return ret;
361ba0501acSDingqiang Lin }
362ba0501acSDingqiang Lin 
sfc_nand_rw_preset(void)363ba0501acSDingqiang Lin static int sfc_nand_rw_preset(void)
364ba0501acSDingqiang Lin {
365ba0501acSDingqiang Lin 	int ret;
36658463f4dSJon Lin 	struct rk_sfc_op op;
367ba0501acSDingqiang Lin 
36858463f4dSJon Lin 	op.sfcmd.d32 = 0;
369f28847a8SJon Lin 	op.sfcmd.b.cmd = 0xff;
370f28847a8SJon Lin 	op.sfcmd.b.cs = 2;
371ba0501acSDingqiang Lin 
37258463f4dSJon Lin 	op.sfctrl.d32 = 0;
37358463f4dSJon Lin 	op.sfctrl.b.datalines = 2;
374f28847a8SJon Lin 	op.sfctrl.b.cmdlines = 2;
375f28847a8SJon Lin 	op.sfctrl.b.addrlines = 2;
37658463f4dSJon Lin 
377f28847a8SJon Lin 	ret = sfc_request(&op, 0, NULL, 0);
378ba0501acSDingqiang Lin 	return ret;
379ba0501acSDingqiang Lin }
380ba0501acSDingqiang Lin 
sfc_nand_read_feature(u8 addr,u8 * data)381ba0501acSDingqiang Lin static int sfc_nand_read_feature(u8 addr, u8 *data)
382ba0501acSDingqiang Lin {
383ba0501acSDingqiang Lin 	int ret;
38458463f4dSJon Lin 	struct rk_sfc_op op;
385ba0501acSDingqiang Lin 
38658463f4dSJon Lin 	op.sfcmd.d32 = 0;
38758463f4dSJon Lin 	op.sfcmd.b.cmd = 0x0F;
38858463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
38958463f4dSJon Lin 
39058463f4dSJon Lin 	op.sfctrl.d32 = 0;
39158463f4dSJon Lin 	op.sfctrl.b.addrbits = 8;
39258463f4dSJon Lin 
393ba0501acSDingqiang Lin 	*data = 0;
394ba0501acSDingqiang Lin 
39558463f4dSJon Lin 	ret = sfc_request(&op, addr, data, 1);
396f28847a8SJon Lin 
397ba0501acSDingqiang Lin 	if (ret != SFC_OK)
398ba0501acSDingqiang Lin 		return ret;
399f28847a8SJon Lin 
400ba0501acSDingqiang Lin 	return SFC_OK;
401ba0501acSDingqiang Lin }
402ba0501acSDingqiang Lin 
sfc_nand_write_feature(u32 addr,u8 status)403ba0501acSDingqiang Lin static int sfc_nand_write_feature(u32 addr, u8 status)
404ba0501acSDingqiang Lin {
405ba0501acSDingqiang Lin 	int ret;
40658463f4dSJon Lin 	struct rk_sfc_op op;
407ba0501acSDingqiang Lin 
408ba0501acSDingqiang Lin 	sfc_nand_write_en();
409ba0501acSDingqiang Lin 
41058463f4dSJon Lin 	op.sfcmd.d32 = 0;
41158463f4dSJon Lin 	op.sfcmd.b.cmd = 0x1F;
41258463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
41358463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
414ba0501acSDingqiang Lin 
41558463f4dSJon Lin 	op.sfctrl.d32 = 0;
41658463f4dSJon Lin 	op.sfctrl.b.addrbits = 8;
41758463f4dSJon Lin 
41858463f4dSJon Lin 	ret = sfc_request(&op, addr, &status, 1);
419f28847a8SJon Lin 
420ba0501acSDingqiang Lin 	if (ret != SFC_OK)
421ba0501acSDingqiang Lin 		return ret;
422f28847a8SJon Lin 
423ba0501acSDingqiang Lin 	return ret;
424ba0501acSDingqiang Lin }
425ba0501acSDingqiang Lin 
sfc_nand_wait_busy(u8 * data,int timeout)426ba0501acSDingqiang Lin static int sfc_nand_wait_busy(u8 *data, int timeout)
427ba0501acSDingqiang Lin {
428ba0501acSDingqiang Lin 	int ret;
429ba0501acSDingqiang Lin 	int i;
430ba0501acSDingqiang Lin 	u8 status;
431ba0501acSDingqiang Lin 
432ba0501acSDingqiang Lin 	*data = 0;
433f28847a8SJon Lin 
434ba0501acSDingqiang Lin 	for (i = 0; i < timeout; i++) {
435ba0501acSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
436f28847a8SJon Lin 
437ba0501acSDingqiang Lin 		if (ret != SFC_OK)
438ba0501acSDingqiang Lin 			return ret;
439f28847a8SJon Lin 
440ba0501acSDingqiang Lin 		*data = status;
441f28847a8SJon Lin 
442ba0501acSDingqiang Lin 		if (!(status & (1 << 0)))
443ba0501acSDingqiang Lin 			return SFC_OK;
444f28847a8SJon Lin 
445ba0501acSDingqiang Lin 		sfc_delay(1);
446ba0501acSDingqiang Lin 	}
447f28847a8SJon Lin 
448f28847a8SJon Lin 	return SFC_NAND_WAIT_TIME_OUT;
449ba0501acSDingqiang Lin }
450ba0501acSDingqiang Lin 
4516281205aSDingqiang Lin /*
4526281205aSDingqiang Lin  * ecc default:
453a6fcac41SJon Lin  * ecc bits: 0xC0[4,5]
454f28847a8SJon Lin  * 0b00, No bit errors were detected
455f28847a8SJon Lin  * 0b01, Bit errors were detected and corrected.
456f28847a8SJon Lin  * 0b10, Multiple bit errors were detected and not corrected.
457f28847a8SJon Lin  * 0b11, Bits errors were detected and corrected, bit error count
458362b1be1SJon Lin  *	reach the bit flip detection threshold
4596281205aSDingqiang Lin  */
sfc_nand_get_ecc_status0(void)460f28847a8SJon Lin static u32 sfc_nand_get_ecc_status0(void)
4616281205aSDingqiang Lin {
46258463f4dSJon Lin 	u32 ret;
4636281205aSDingqiang Lin 	u32 i;
4646281205aSDingqiang Lin 	u8 ecc;
4656281205aSDingqiang Lin 	u8 status;
4666281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
4676281205aSDingqiang Lin 
4686281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
4696281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
470f28847a8SJon Lin 
4716281205aSDingqiang Lin 		if (ret != SFC_OK)
4726281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
473f28847a8SJon Lin 
4746281205aSDingqiang Lin 		if (!(status & (1 << 0)))
4756281205aSDingqiang Lin 			break;
476f28847a8SJon Lin 
4776281205aSDingqiang Lin 		sfc_delay(1);
4786281205aSDingqiang Lin 	}
4796281205aSDingqiang Lin 
4806281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
4816281205aSDingqiang Lin 
4826281205aSDingqiang Lin 	if (ecc <= 1)
4836281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
4846281205aSDingqiang Lin 	else if (ecc == 2)
48558463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
4866281205aSDingqiang Lin 	else
4876281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
4886281205aSDingqiang Lin 
4896281205aSDingqiang Lin 	return ret;
4906281205aSDingqiang Lin }
4916281205aSDingqiang Lin 
4926281205aSDingqiang Lin /*
4936281205aSDingqiang Lin  * ecc spectial type1:
494a6fcac41SJon Lin  * ecc bits: 0xC0[4,5]
495f28847a8SJon Lin  * 0b00, No bit errors were detected;
496f28847a8SJon Lin  * 0b01, Bits errors were detected and corrected, bit error count
4976281205aSDingqiang Lin  *	may reach the bit flip detection threshold;
498f28847a8SJon Lin  * 0b10, Multiple bit errors were detected and not corrected;
499f28847a8SJon Lin  * 0b11, Reserved.
5006281205aSDingqiang Lin  */
sfc_nand_get_ecc_status1(void)501f28847a8SJon Lin static u32 sfc_nand_get_ecc_status1(void)
5026281205aSDingqiang Lin {
50358463f4dSJon Lin 	u32 ret;
5046281205aSDingqiang Lin 	u32 i;
5056281205aSDingqiang Lin 	u8 ecc;
5066281205aSDingqiang Lin 	u8 status;
5076281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
5086281205aSDingqiang Lin 
5096281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
5106281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
511f28847a8SJon Lin 
5126281205aSDingqiang Lin 		if (ret != SFC_OK)
5136281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
514f28847a8SJon Lin 
5156281205aSDingqiang Lin 		if (!(status & (1 << 0)))
5166281205aSDingqiang Lin 			break;
517f28847a8SJon Lin 
5186281205aSDingqiang Lin 		sfc_delay(1);
5196281205aSDingqiang Lin 	}
5206281205aSDingqiang Lin 
5216281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
5226281205aSDingqiang Lin 
5236281205aSDingqiang Lin 	if (ecc == 0)
5246281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
5256281205aSDingqiang Lin 	else if (ecc == 1)
5266281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
5276281205aSDingqiang Lin 	else
52858463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
5296281205aSDingqiang Lin 
5306281205aSDingqiang Lin 	return ret;
5316281205aSDingqiang Lin }
5326281205aSDingqiang Lin 
5336281205aSDingqiang Lin /*
534d9cdd318SJon Lin  * ecc spectial type2:
535a6fcac41SJon Lin  * ecc bits: 0xC0[4,5] 0xF0[4,5]
536f28847a8SJon Lin  * [0b0000, 0b0011], No bit errors were detected;
537f28847a8SJon Lin  * [0b0100, 0b0111], Bit errors were detected and corrected. Not
538d9cdd318SJon Lin  *	reach Flipping Bits;
539f28847a8SJon Lin  * [0b1000, 0b1011], Multiple bit errors were detected and
540c84f0ed8SJon Lin  *	not corrected.
541f28847a8SJon Lin  * [0b1100, 0b1111], reserved.
542d9cdd318SJon Lin  */
sfc_nand_get_ecc_status2(void)543f28847a8SJon Lin static u32 sfc_nand_get_ecc_status2(void)
544d9cdd318SJon Lin {
54558463f4dSJon Lin 	u32 ret;
546d9cdd318SJon Lin 	u32 i;
547d9cdd318SJon Lin 	u8 ecc;
548d9cdd318SJon Lin 	u8 status, status1;
549d9cdd318SJon Lin 	u32 timeout = 1000 * 1000;
550d9cdd318SJon Lin 
551d9cdd318SJon Lin 	for (i = 0; i < timeout; i++) {
552d9cdd318SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
553f28847a8SJon Lin 
554d9cdd318SJon Lin 		if (ret != SFC_OK)
555d9cdd318SJon Lin 			return SFC_NAND_ECC_ERROR;
556f28847a8SJon Lin 
557d9cdd318SJon Lin 		ret = sfc_nand_read_feature(0xF0, &status1);
558f28847a8SJon Lin 
559d9cdd318SJon Lin 		if (ret != SFC_OK)
560d9cdd318SJon Lin 			return SFC_NAND_ECC_ERROR;
561f28847a8SJon Lin 
562d9cdd318SJon Lin 		if (!(status & (1 << 0)))
563d9cdd318SJon Lin 			break;
564f28847a8SJon Lin 
565d9cdd318SJon Lin 		sfc_delay(1);
566d9cdd318SJon Lin 	}
567d9cdd318SJon Lin 
568d9cdd318SJon Lin 	ecc = (status >> 4) & 0x03;
569d9cdd318SJon Lin 	ecc = (ecc << 2) | ((status1 >> 4) & 0x03);
570f28847a8SJon Lin 
571d9cdd318SJon Lin 	if (ecc < 7)
572d9cdd318SJon Lin 		ret = SFC_NAND_ECC_OK;
573d9cdd318SJon Lin 	else if (ecc == 7)
574d9cdd318SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
575d9cdd318SJon Lin 	else
57658463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
577d9cdd318SJon Lin 
578d9cdd318SJon Lin 	return ret;
579d9cdd318SJon Lin }
580d9cdd318SJon Lin 
581d9cdd318SJon Lin /*
5826281205aSDingqiang Lin  * ecc spectial type3:
583a6fcac41SJon Lin  * ecc bits: 0xC0[4,5] 0xF0[4,5]
584f28847a8SJon Lin  * [0b0000, 0b0011], No bit errors were detected;
585f28847a8SJon Lin  * [0b0100, 0b0111], Bit errors were detected and corrected. Not
5866281205aSDingqiang Lin  *	reach Flipping Bits;
587f28847a8SJon Lin  * [0b1000, 0b1011], Multiple bit errors were detected and
5886281205aSDingqiang Lin  *	not corrected.
589f28847a8SJon Lin  * [0b1100, 0b1111], Bit error count equals the bit flip
5906281205aSDingqiang Lin  *	detectio nthreshold
5916281205aSDingqiang Lin  */
sfc_nand_get_ecc_status3(void)592f28847a8SJon Lin static u32 sfc_nand_get_ecc_status3(void)
5936281205aSDingqiang Lin {
59458463f4dSJon Lin 	u32 ret;
5956281205aSDingqiang Lin 	u32 i;
5966281205aSDingqiang Lin 	u8 ecc;
5976281205aSDingqiang Lin 	u8 status, status1;
5986281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
5996281205aSDingqiang Lin 
6006281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
6016281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
602f28847a8SJon Lin 
6036281205aSDingqiang Lin 		if (ret != SFC_OK)
6046281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
605f28847a8SJon Lin 
6066281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xF0, &status1);
607f28847a8SJon Lin 
6086281205aSDingqiang Lin 		if (ret != SFC_OK)
6096281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
610f28847a8SJon Lin 
6116281205aSDingqiang Lin 		if (!(status & (1 << 0)))
6126281205aSDingqiang Lin 			break;
613f28847a8SJon Lin 
6146281205aSDingqiang Lin 		sfc_delay(1);
6156281205aSDingqiang Lin 	}
6166281205aSDingqiang Lin 
6176281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
6186281205aSDingqiang Lin 	ecc = (ecc << 2) | ((status1 >> 4) & 0x03);
619f28847a8SJon Lin 
6206281205aSDingqiang Lin 	if (ecc < 7)
6216281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
6226281205aSDingqiang Lin 	else if (ecc == 7 || ecc >= 12)
6236281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
6246281205aSDingqiang Lin 	else
62558463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
6266281205aSDingqiang Lin 
6276281205aSDingqiang Lin 	return ret;
6286281205aSDingqiang Lin }
6296281205aSDingqiang Lin 
63025098c06SDingqiang Lin /*
63125098c06SDingqiang Lin  * ecc spectial type4:
632a6fcac41SJon Lin  * ecc bits: 0xC0[2,5]
633f28847a8SJon Lin  * [0b0000], No bit errors were detected;
634f28847a8SJon Lin  * [0b0001, 0b0111], Bit errors were detected and corrected. Not
63525098c06SDingqiang Lin  *	reach Flipping Bits;
636f28847a8SJon Lin  * [0b1000], Multiple bit errors were detected and
63725098c06SDingqiang Lin  *	not corrected.
638f28847a8SJon Lin  * [0b1100], Bit error count equals the bit flip
63925098c06SDingqiang Lin  *	detection threshold
64025098c06SDingqiang Lin  * else, reserved
64125098c06SDingqiang Lin  */
sfc_nand_get_ecc_status4(void)642f28847a8SJon Lin static u32 sfc_nand_get_ecc_status4(void)
64325098c06SDingqiang Lin {
64458463f4dSJon Lin 	u32 ret;
64525098c06SDingqiang Lin 	u32 i;
64625098c06SDingqiang Lin 	u8 ecc;
64725098c06SDingqiang Lin 	u8 status;
64825098c06SDingqiang Lin 	u32 timeout = 1000 * 1000;
64925098c06SDingqiang Lin 
65025098c06SDingqiang Lin 	for (i = 0; i < timeout; i++) {
65125098c06SDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
652f28847a8SJon Lin 
65325098c06SDingqiang Lin 		if (ret != SFC_OK)
65425098c06SDingqiang Lin 			return SFC_NAND_ECC_ERROR;
655f28847a8SJon Lin 
65625098c06SDingqiang Lin 		if (!(status & (1 << 0)))
65725098c06SDingqiang Lin 			break;
658f28847a8SJon Lin 
65925098c06SDingqiang Lin 		sfc_delay(1);
66025098c06SDingqiang Lin 	}
66125098c06SDingqiang Lin 
66225098c06SDingqiang Lin 	ecc = (status >> 2) & 0x0f;
663f28847a8SJon Lin 
66425098c06SDingqiang Lin 	if (ecc < 7)
66525098c06SDingqiang Lin 		ret = SFC_NAND_ECC_OK;
66625098c06SDingqiang Lin 	else if (ecc == 7 || ecc == 12)
66725098c06SDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
66825098c06SDingqiang Lin 	else
66958463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
67025098c06SDingqiang Lin 
67125098c06SDingqiang Lin 	return ret;
67225098c06SDingqiang Lin }
67325098c06SDingqiang Lin 
67425098c06SDingqiang Lin /*
67525098c06SDingqiang Lin  * ecc spectial type5:
676a6fcac41SJon Lin  * ecc bits: 0xC0[4,6]
677f28847a8SJon Lin  * [0b000], No bit errors were detected;
678f28847a8SJon Lin  * [0b001, 0b011], Bit errors were detected and corrected. Not
67925098c06SDingqiang Lin  *	reach Flipping Bits;
680f28847a8SJon Lin  * [0b100], Bit error count equals the bit flip
68125098c06SDingqiang Lin  *	detection threshold
682f28847a8SJon Lin  * [0b101, 0b110], Reserved;
683f28847a8SJon Lin  * [0b111], Multiple bit errors were detected and
68425098c06SDingqiang Lin  *	not corrected.
68525098c06SDingqiang Lin  */
sfc_nand_get_ecc_status5(void)686f28847a8SJon Lin static u32 sfc_nand_get_ecc_status5(void)
68725098c06SDingqiang Lin {
68858463f4dSJon Lin 	u32 ret;
68925098c06SDingqiang Lin 	u32 i;
69025098c06SDingqiang Lin 	u8 ecc;
69125098c06SDingqiang Lin 	u8 status;
69225098c06SDingqiang Lin 	u32 timeout = 1000 * 1000;
69325098c06SDingqiang Lin 
69425098c06SDingqiang Lin 	for (i = 0; i < timeout; i++) {
69525098c06SDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
696f28847a8SJon Lin 
69725098c06SDingqiang Lin 		if (ret != SFC_OK)
69825098c06SDingqiang Lin 			return SFC_NAND_ECC_ERROR;
699f28847a8SJon Lin 
70025098c06SDingqiang Lin 		if (!(status & (1 << 0)))
70125098c06SDingqiang Lin 			break;
702f28847a8SJon Lin 
70325098c06SDingqiang Lin 		sfc_delay(1);
70425098c06SDingqiang Lin 	}
70525098c06SDingqiang Lin 
70625098c06SDingqiang Lin 	ecc = (status >> 4) & 0x07;
707f28847a8SJon Lin 
70825098c06SDingqiang Lin 	if (ecc < 4)
70925098c06SDingqiang Lin 		ret = SFC_NAND_ECC_OK;
71025098c06SDingqiang Lin 	else if (ecc == 4)
71125098c06SDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
71225098c06SDingqiang Lin 	else
71358463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
71425098c06SDingqiang Lin 
71525098c06SDingqiang Lin 	return ret;
71625098c06SDingqiang Lin }
71725098c06SDingqiang Lin 
718f28847a8SJon Lin /*
719f28847a8SJon Lin  * ecc spectial type6:
720f28847a8SJon Lin  * ecc bits: 0xC0[4,6]
721f28847a8SJon Lin  * [0b000], No bit errors were detected;
722f28847a8SJon Lin  * [0b001], 1-3 Bit errors were detected and corrected. Not
723f28847a8SJon Lin  *	reach Flipping Bits;
724f28847a8SJon Lin  * [0b010], Multiple bit errors were detected and
725f28847a8SJon Lin  *	not corrected.
726f28847a8SJon Lin  * [0b011], 4-6 Bit errors were detected and corrected. Not
727f28847a8SJon Lin  *	reach Flipping Bits;
728f28847a8SJon Lin  * [0b101], Bit error count equals the bit flip
729f28847a8SJon Lin  *	detectionthreshold
730f28847a8SJon Lin  * others, Reserved.
731f28847a8SJon Lin  */
sfc_nand_get_ecc_status6(void)732f28847a8SJon Lin static u32 sfc_nand_get_ecc_status6(void)
733f28847a8SJon Lin {
734f28847a8SJon Lin 	u32 ret;
735f28847a8SJon Lin 	u32 i;
736f28847a8SJon Lin 	u8 ecc;
737f28847a8SJon Lin 	u8 status;
738f28847a8SJon Lin 	u32 timeout = 1000 * 1000;
739f28847a8SJon Lin 
740f28847a8SJon Lin 	for (i = 0; i < timeout; i++) {
741f28847a8SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
742f28847a8SJon Lin 
743f28847a8SJon Lin 		if (ret != SFC_OK)
744f28847a8SJon Lin 			return SFC_NAND_ECC_ERROR;
745f28847a8SJon Lin 
746f28847a8SJon Lin 		if (!(status & (1 << 0)))
747f28847a8SJon Lin 			break;
748f28847a8SJon Lin 
749f28847a8SJon Lin 		sfc_delay(1);
750f28847a8SJon Lin 	}
751f28847a8SJon Lin 
752f28847a8SJon Lin 	ecc = (status >> 4) & 0x07;
753f28847a8SJon Lin 
754f28847a8SJon Lin 	if (ecc == 0 || ecc == 1 || ecc == 3)
755f28847a8SJon Lin 		ret = SFC_NAND_ECC_OK;
756f28847a8SJon Lin 	else if (ecc == 5)
757f28847a8SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
758f28847a8SJon Lin 	else
759f28847a8SJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
760f28847a8SJon Lin 
761f28847a8SJon Lin 	return ret;
762f28847a8SJon Lin }
763f28847a8SJon Lin 
764362b1be1SJon Lin /*
765362b1be1SJon Lin  * ecc spectial type7:
766362b1be1SJon Lin  * ecc bits: 0xC0[4,7]
767362b1be1SJon Lin  * [0b0000], No bit errors were detected;
768362b1be1SJon Lin  * [0b0001, 0b0111], 1-7 Bit errors were detected and corrected. Not
769362b1be1SJon Lin  *	reach Flipping Bits;
770362b1be1SJon Lin  * [0b1000], 8 Bit errors were detected and corrected. Bit error count
771362b1be1SJon Lin  * 	equals the bit flip detectionthreshold;
772362b1be1SJon Lin  * [0b1111], Bit errors greater than ECC capability(8 bits) and not corrected;
773362b1be1SJon Lin  * others, Reserved.
774362b1be1SJon Lin  */
sfc_nand_get_ecc_status7(void)775362b1be1SJon Lin static u32 sfc_nand_get_ecc_status7(void)
776362b1be1SJon Lin {
777362b1be1SJon Lin 	u32 ret;
778362b1be1SJon Lin 	u32 i;
779362b1be1SJon Lin 	u8 ecc;
780362b1be1SJon Lin 	u8 status;
781362b1be1SJon Lin 	u32 timeout = 1000 * 1000;
782362b1be1SJon Lin 
783362b1be1SJon Lin 	for (i = 0; i < timeout; i++) {
784362b1be1SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
785362b1be1SJon Lin 
786362b1be1SJon Lin 		if (ret != SFC_OK)
787362b1be1SJon Lin 			return SFC_NAND_ECC_ERROR;
788362b1be1SJon Lin 
789362b1be1SJon Lin 		if (!(status & (1 << 0)))
790362b1be1SJon Lin 			break;
791362b1be1SJon Lin 
792362b1be1SJon Lin 		sfc_delay(1);
793362b1be1SJon Lin 	}
794362b1be1SJon Lin 
795362b1be1SJon Lin 	ecc = (status >> 4) & 0xf;
796362b1be1SJon Lin 
797362b1be1SJon Lin 	if (ecc < 7)
798362b1be1SJon Lin 		ret = SFC_NAND_ECC_OK;
799362b1be1SJon Lin 	else if (ecc == 7 || ecc == 8)
800362b1be1SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
801362b1be1SJon Lin 	else
802362b1be1SJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
803362b1be1SJon Lin 
804362b1be1SJon Lin 	return ret;
805362b1be1SJon Lin }
806362b1be1SJon Lin 
807629111d3SJon Lin /*
808629111d3SJon Lin  * ecc spectial type8:
809629111d3SJon Lin  * ecc bits: 0xC0[4,6]
810629111d3SJon Lin  * [0b000], No bit errors were detected;
811629111d3SJon Lin  * [0b001, 0b011], 1~3 Bit errors were detected and corrected. Not
812629111d3SJon Lin  *	reach Flipping Bits;
813629111d3SJon Lin  * [0b100], Bit error count equals the bit flip
814629111d3SJon Lin  *	detection threshold
815629111d3SJon Lin  * others, Reserved.
816629111d3SJon Lin  */
sfc_nand_get_ecc_status8(void)817629111d3SJon Lin static u32 sfc_nand_get_ecc_status8(void)
818629111d3SJon Lin {
819629111d3SJon Lin 	u32 ret;
820629111d3SJon Lin 	u32 i;
821629111d3SJon Lin 	u8 ecc;
822629111d3SJon Lin 	u8 status;
823629111d3SJon Lin 	u32 timeout = 1000 * 1000;
824629111d3SJon Lin 
825629111d3SJon Lin 	for (i = 0; i < timeout; i++) {
826629111d3SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
827629111d3SJon Lin 
828629111d3SJon Lin 		if (ret != SFC_OK)
829629111d3SJon Lin 			return SFC_NAND_ECC_ERROR;
830629111d3SJon Lin 
831629111d3SJon Lin 		if (!(status & (1 << 0)))
832629111d3SJon Lin 			break;
833629111d3SJon Lin 
834629111d3SJon Lin 		sfc_delay(1);
835629111d3SJon Lin 	}
836629111d3SJon Lin 
837629111d3SJon Lin 	ecc = (status >> 4) & 0x07;
838629111d3SJon Lin 
839629111d3SJon Lin 	if (ecc < 4)
840629111d3SJon Lin 		ret = SFC_NAND_ECC_OK;
841629111d3SJon Lin 	else if (ecc == 4)
842629111d3SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
843629111d3SJon Lin 	else
844629111d3SJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
845629111d3SJon Lin 
846629111d3SJon Lin 	return ret;
847629111d3SJon Lin }
848629111d3SJon Lin 
849d4db0b8dSJon Lin /*
850d4db0b8dSJon Lin  * ecc spectial type9:
851d4db0b8dSJon Lin  * ecc bits: 0xC0[4,5]
852d4db0b8dSJon Lin  * 0b00, No bit errors were detected
853d4db0b8dSJon Lin  * 0b01, 1-2Bit errors were detected and corrected.
854d4db0b8dSJon Lin  * 0b10, 3-4Bit errors were detected and corrected.
855d4db0b8dSJon Lin  * 0b11, 11 can be used as uncorrectable
856d4db0b8dSJon Lin  */
sfc_nand_get_ecc_status9(void)857d4db0b8dSJon Lin static u32 sfc_nand_get_ecc_status9(void)
858d4db0b8dSJon Lin {
859d4db0b8dSJon Lin 	u32 ret;
860d4db0b8dSJon Lin 	u32 i;
861d4db0b8dSJon Lin 	u8 ecc;
862d4db0b8dSJon Lin 	u8 status;
863d4db0b8dSJon Lin 	u32 timeout = 1000 * 1000;
864d4db0b8dSJon Lin 
865d4db0b8dSJon Lin 	for (i = 0; i < timeout; i++) {
866d4db0b8dSJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
867d4db0b8dSJon Lin 
868d4db0b8dSJon Lin 		if (ret != SFC_OK)
869d4db0b8dSJon Lin 			return SFC_NAND_ECC_ERROR;
870d4db0b8dSJon Lin 
871d4db0b8dSJon Lin 		if (!(status & (1 << 0)))
872d4db0b8dSJon Lin 			break;
873d4db0b8dSJon Lin 
874d4db0b8dSJon Lin 		sfc_delay(1);
875d4db0b8dSJon Lin 	}
876d4db0b8dSJon Lin 
877d4db0b8dSJon Lin 	ecc = (status >> 4) & 0x03;
878d4db0b8dSJon Lin 
879d4db0b8dSJon Lin 	if (ecc <= 1)
880d4db0b8dSJon Lin 		ret = SFC_NAND_ECC_OK;
881d4db0b8dSJon Lin 	else if (ecc == 2)
882d4db0b8dSJon Lin 		ret = SFC_NAND_ECC_REFRESH;
883d4db0b8dSJon Lin 	else
884d4db0b8dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
885d4db0b8dSJon Lin 
886d4db0b8dSJon Lin 	return ret;
887d4db0b8dSJon Lin }
888d4db0b8dSJon Lin 
889a4bd704eSJon Lin /*
89035c70cf8SJon Lin  * ecc spectial type10:
891a4bd704eSJon Lin  * ecc bits: 0xC0[4,6]
892a4bd704eSJon Lin  * [0b000], No bit errors were detected;
893a4bd704eSJon Lin  * [0b001, 0b101], 3~7 Bit errors were detected and corrected. Not
894a4bd704eSJon Lin  *	reach Flipping Bits;
895a4bd704eSJon Lin  * [0b110], Bit error count equals the bit flip detection threshold
896a4bd704eSJon Lin  * [0b111], Bit errors greater than ECC capability(8 bits) and not corrected;
897a4bd704eSJon Lin  */
sfc_nand_get_ecc_status10(void)898a4bd704eSJon Lin static u32 sfc_nand_get_ecc_status10(void)
899a4bd704eSJon Lin {
900a4bd704eSJon Lin 	u32 ret;
901a4bd704eSJon Lin 	u32 i;
902a4bd704eSJon Lin 	u8 ecc;
903a4bd704eSJon Lin 	u8 status;
904a4bd704eSJon Lin 	u32 timeout = 1000 * 1000;
905a4bd704eSJon Lin 
906a4bd704eSJon Lin 	for (i = 0; i < timeout; i++) {
907a4bd704eSJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
908a4bd704eSJon Lin 
909a4bd704eSJon Lin 		if (ret != SFC_OK)
910a4bd704eSJon Lin 			return SFC_NAND_ECC_ERROR;
911a4bd704eSJon Lin 
912a4bd704eSJon Lin 		if (!(status & (1 << 0)))
913a4bd704eSJon Lin 			break;
914a4bd704eSJon Lin 
915a4bd704eSJon Lin 		sfc_delay(1);
916a4bd704eSJon Lin 	}
917a4bd704eSJon Lin 
918a4bd704eSJon Lin 	ecc = (status >> 4) & 0x07;
919a4bd704eSJon Lin 
920a4bd704eSJon Lin 	if (ecc < 6)
921a4bd704eSJon Lin 		ret = SFC_NAND_ECC_OK;
922a4bd704eSJon Lin 	else if (ecc == 6)
923a4bd704eSJon Lin 		ret = SFC_NAND_ECC_REFRESH;
924a4bd704eSJon Lin 	else
925a4bd704eSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
926a4bd704eSJon Lin 
927a4bd704eSJon Lin 	return ret;
928a4bd704eSJon Lin }
929a4bd704eSJon Lin 
93035c70cf8SJon Lin /*
93135c70cf8SJon Lin  * ecc spectial type11:
93235c70cf8SJon Lin  * ecc bits: 0xC0[4,6]
93335c70cf8SJon Lin  * [0b000], No bit errors were detected;
93435c70cf8SJon Lin  * [0b001, 0b101], 3~7 Bit errors were detected and corrected. Not
93535c70cf8SJon Lin  *	reach Flipping Bits;
93635c70cf8SJon Lin  * [0b110], Bit error count equals the bit flip detection threshold
93735c70cf8SJon Lin  * [0b111], Bit errors greater than ECC capability(8 bits) and not corrected;
93835c70cf8SJon Lin  */
sfc_nand_get_ecc_status11(void)93935c70cf8SJon Lin static u32 sfc_nand_get_ecc_status11(void)
94035c70cf8SJon Lin {
94135c70cf8SJon Lin 	u32 ret;
94235c70cf8SJon Lin 	u32 i;
94335c70cf8SJon Lin 	u8 ecc;
94435c70cf8SJon Lin 	u8 status;
94535c70cf8SJon Lin 	u32 timeout = 1000 * 1000;
94635c70cf8SJon Lin 
94735c70cf8SJon Lin 	for (i = 0; i < timeout; i++) {
94835c70cf8SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
94935c70cf8SJon Lin 
95035c70cf8SJon Lin 		if (ret != SFC_OK)
95135c70cf8SJon Lin 			return SFC_NAND_ECC_ERROR;
95235c70cf8SJon Lin 
95335c70cf8SJon Lin 		if (!(status & (1 << 0)))
95435c70cf8SJon Lin 			break;
95535c70cf8SJon Lin 
95635c70cf8SJon Lin 		sfc_delay(1);
95735c70cf8SJon Lin 	}
95835c70cf8SJon Lin 
95935c70cf8SJon Lin 	ecc = (status >> 4) & 0x07;
96035c70cf8SJon Lin 
96135c70cf8SJon Lin 	if (ecc <= 1)
96235c70cf8SJon Lin 		ret = SFC_NAND_ECC_OK;
96335c70cf8SJon Lin 	else if (ecc == 3 || ecc == 5)
96435c70cf8SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
96535c70cf8SJon Lin 	else
96635c70cf8SJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
96735c70cf8SJon Lin 
96835c70cf8SJon Lin 	return ret;
96935c70cf8SJon Lin }
97035c70cf8SJon Lin 
sfc_nand_erase_block(u8 cs,u32 addr)971c84f0ed8SJon Lin u32 sfc_nand_erase_block(u8 cs, u32 addr)
972ba0501acSDingqiang Lin {
973ba0501acSDingqiang Lin 	int ret;
97458463f4dSJon Lin 	struct rk_sfc_op op;
975ba0501acSDingqiang Lin 	u8 status;
976ba0501acSDingqiang Lin 
977c84f0ed8SJon Lin 	rkflash_print_dio("%s %x\n", __func__, addr);
97858463f4dSJon Lin 	op.sfcmd.d32 = 0;
979f28847a8SJon Lin 	op.sfcmd.b.cmd = 0xd8;
98058463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_24BITS;
98158463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
98258463f4dSJon Lin 
98358463f4dSJon Lin 	op.sfctrl.d32 = 0;
98458463f4dSJon Lin 
985ba0501acSDingqiang Lin 	sfc_nand_write_en();
98658463f4dSJon Lin 	ret = sfc_request(&op, addr, NULL, 0);
987f28847a8SJon Lin 
988ba0501acSDingqiang Lin 	if (ret != SFC_OK)
989ba0501acSDingqiang Lin 		return ret;
990f28847a8SJon Lin 
991ba0501acSDingqiang Lin 	ret = sfc_nand_wait_busy(&status, 1000 * 1000);
992f28847a8SJon Lin 
993ba0501acSDingqiang Lin 	if (status & (1 << 2))
994ba0501acSDingqiang Lin 		return SFC_NAND_PROG_ERASE_ERROR;
995c84f0ed8SJon Lin 
996ba0501acSDingqiang Lin 	return ret;
997ba0501acSDingqiang Lin }
998ba0501acSDingqiang Lin 
sfc_nand_read_cache(u32 row,u32 * p_page_buf,u32 column,u32 len)999629111d3SJon Lin static u32 sfc_nand_read_cache(u32 row, u32 *p_page_buf, u32 column, u32 len)
1000629111d3SJon Lin {
1001629111d3SJon Lin 	int ret;
1002629111d3SJon Lin 	u32 plane;
1003629111d3SJon Lin 	struct rk_sfc_op op;
1004629111d3SJon Lin 
1005629111d3SJon Lin 	op.sfcmd.d32 = 0;
1006629111d3SJon Lin 	op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd;
1007629111d3SJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
1008629111d3SJon Lin 	op.sfcmd.b.dummybits = 8;
1009629111d3SJon Lin 
1010629111d3SJon Lin 	op.sfctrl.d32 = 0;
1011629111d3SJon Lin 	op.sfctrl.b.datalines = sfc_nand_dev.read_lines;
1012629111d3SJon Lin 	op.sfctrl.b.addrbits = 16;
1013629111d3SJon Lin 
1014629111d3SJon Lin 	plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0;
1015629111d3SJon Lin 
1016629111d3SJon Lin 	ret = sfc_request(&op, plane | column, p_page_buf, len);
1017629111d3SJon Lin 	if (ret != SFC_OK)
1018629111d3SJon Lin 		return SFC_NAND_HW_ERROR;
1019629111d3SJon Lin 
1020629111d3SJon Lin 	return ret;
1021629111d3SJon Lin }
1022629111d3SJon Lin 
sfc_nand_prog_page_raw(u8 cs,u32 addr,u32 * p_page_buf)1023f28847a8SJon Lin u32 sfc_nand_prog_page_raw(u8 cs, u32 addr, u32 *p_page_buf)
1024ba0501acSDingqiang Lin {
1025ba0501acSDingqiang Lin 	int ret;
1026415cf080Sjon.lin 	u32 plane;
102758463f4dSJon Lin 	struct rk_sfc_op op;
1028ba0501acSDingqiang Lin 	u8 status;
102958463f4dSJon Lin 	u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page;
1030629111d3SJon Lin 	u32 data_area_size = SFC_NAND_SECTOR_SIZE * p_nand_info->sec_per_page;
1031ba0501acSDingqiang Lin 
1032c84f0ed8SJon Lin 	rkflash_print_dio("%s %x %x\n", __func__, addr, p_page_buf[0]);
1033ba0501acSDingqiang Lin 	sfc_nand_write_en();
1034f28847a8SJon Lin 
1035ba0501acSDingqiang Lin 	if (sfc_nand_dev.prog_lines == DATA_LINES_X4 &&
103625098c06SDingqiang Lin 	    p_nand_info->feature & FEA_SOFT_QOP_BIT &&
103725098c06SDingqiang Lin 	    sfc_get_version() < SFC_VER_3)
1038ba0501acSDingqiang Lin 		sfc_nand_rw_preset();
1039ba0501acSDingqiang Lin 
104058463f4dSJon Lin 	op.sfcmd.d32 = 0;
104158463f4dSJon Lin 	op.sfcmd.b.cmd = sfc_nand_dev.page_prog_cmd;
104258463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
104358463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
1044ba0501acSDingqiang Lin 
104558463f4dSJon Lin 	op.sfctrl.d32 = 0;
104658463f4dSJon Lin 	op.sfctrl.b.datalines = sfc_nand_dev.prog_lines;
104758463f4dSJon Lin 	op.sfctrl.b.addrbits = 16;
1048415cf080Sjon.lin 	plane = p_nand_info->plane_per_die == 2 ? ((addr >> 6) & 0x1) << 12 : 0;
104958463f4dSJon Lin 	sfc_request(&op, plane, p_page_buf, page_size);
1050ba0501acSDingqiang Lin 
1051629111d3SJon Lin 	/*
1052c797b43aSJon Lin 	 * At the moment of power lost or dev running in harsh environment, flash
1053c797b43aSJon Lin 	 * maybe work in a unkonw state and result in bit flip, when this situation
1054c797b43aSJon Lin 	 * is detected by cache recheck, it's better to wait a second for a reliable
1055c797b43aSJon Lin 	 * hardware environment to avoid abnormal data written to flash array.
1056629111d3SJon Lin 	 */
1057361684bfSJon Lin 	if (p_nand_info->id0 == MID_GIGADEV) {
1058629111d3SJon Lin 		sfc_nand_read_cache(addr, (u32 *)sfc_nand_dev.recheck_buffer, 0, data_area_size);
1059c797b43aSJon Lin 		if (memcmp(sfc_nand_dev.recheck_buffer, p_page_buf, data_area_size)) {
1060c797b43aSJon Lin 			rkflash_print_error("%s %x cache bitflip\n", __func__, addr);
1061c797b43aSJon Lin 			mdelay(1000);
1062c797b43aSJon Lin 			sfc_request(&op, plane, p_page_buf, page_size);
1063c797b43aSJon Lin 		}
1064c797b43aSJon Lin 	}
1065629111d3SJon Lin 
106658463f4dSJon Lin 	op.sfcmd.d32 = 0;
1067f28847a8SJon Lin 	op.sfcmd.b.cmd = 0x10;
106858463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_24BITS;
106958463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
107058463f4dSJon Lin 
107158463f4dSJon Lin 	op.sfctrl.d32 = 0;
107258463f4dSJon Lin 	ret = sfc_request(&op, addr, p_page_buf, 0);
1073f28847a8SJon Lin 
1074ba0501acSDingqiang Lin 	if (ret != SFC_OK)
1075ba0501acSDingqiang Lin 		return ret;
1076f28847a8SJon Lin 
1077ba0501acSDingqiang Lin 	ret = sfc_nand_wait_busy(&status, 1000 * 1000);
1078ba0501acSDingqiang Lin 	if (status & (1 << 3))
1079ba0501acSDingqiang Lin 		return SFC_NAND_PROG_ERASE_ERROR;
1080c84f0ed8SJon Lin 
1081ba0501acSDingqiang Lin 	return ret;
1082ba0501acSDingqiang Lin }
1083ba0501acSDingqiang Lin 
sfc_nand_prog_page(u8 cs,u32 addr,u32 * p_data,u32 * p_spare)1084c84f0ed8SJon Lin u32 sfc_nand_prog_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare)
1085c84f0ed8SJon Lin {
1086c84f0ed8SJon Lin 	int ret;
1087c84f0ed8SJon Lin 	u32 sec_per_page = p_nand_info->sec_per_page;
1088c84f0ed8SJon Lin 	u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE;
1089a6fcac41SJon Lin 	struct nand_mega_area *meta = &p_nand_info->meta;
1090c84f0ed8SJon Lin 
1091c84f0ed8SJon Lin 	memcpy(gp_page_buf, p_data, data_size);
1092c84f0ed8SJon Lin 	memset(&gp_page_buf[data_size / 4], 0xff, sec_per_page * 16);
1093a6fcac41SJon Lin 	gp_page_buf[(data_size + meta->off0) / 4] = p_spare[0];
1094a6fcac41SJon Lin 	gp_page_buf[(data_size + meta->off1) / 4] = p_spare[1];
1095f28847a8SJon Lin 
1096c84f0ed8SJon Lin 	if (sec_per_page == 8) {
1097a6fcac41SJon Lin 		gp_page_buf[(data_size + meta->off2) / 4] = p_spare[2];
1098a6fcac41SJon Lin 		gp_page_buf[(data_size + meta->off3) / 4] = p_spare[3];
1099c84f0ed8SJon Lin 	}
1100f28847a8SJon Lin 
1101c84f0ed8SJon Lin 	ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf);
1102c84f0ed8SJon Lin 
1103c84f0ed8SJon Lin 	return ret;
1104c84f0ed8SJon Lin }
1105c84f0ed8SJon Lin 
sfc_nand_read(u32 row,u32 * p_page_buf,u32 column,u32 len)1106a80fd396SJon Lin u32 sfc_nand_read(u32 row, u32 *p_page_buf, u32 column, u32 len)
1107ba0501acSDingqiang Lin {
1108ba0501acSDingqiang Lin 	int ret;
1109415cf080Sjon.lin 	u32 plane;
111058463f4dSJon Lin 	struct rk_sfc_op op;
11116281205aSDingqiang Lin 	u32 ecc_result;
1112a6fcac41SJon Lin 	u8 status;
1113ba0501acSDingqiang Lin 
111458463f4dSJon Lin 	op.sfcmd.d32 = 0;
1115f28847a8SJon Lin 	op.sfcmd.b.cmd = 0x13;
111658463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
111758463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_24BITS;
111858463f4dSJon Lin 
111958463f4dSJon Lin 	op.sfctrl.d32 = 0;
112058463f4dSJon Lin 
1121a80fd396SJon Lin 	sfc_request(&op, row, p_page_buf, 0);
1122f28847a8SJon Lin 
1123ba0501acSDingqiang Lin 	if (sfc_nand_dev.read_lines == DATA_LINES_X4 &&
112425098c06SDingqiang Lin 	    p_nand_info->feature & FEA_SOFT_QOP_BIT &&
112525098c06SDingqiang Lin 	    sfc_get_version() < SFC_VER_3)
1126ba0501acSDingqiang Lin 		sfc_nand_rw_preset();
1127ba0501acSDingqiang Lin 
1128a6fcac41SJon Lin 	sfc_nand_wait_busy(&status, 1000 * 1000);
1129e5e85009SJon Lin 	if (sfc_nand_dev.manufacturer == 0x01 && status)
1130e5e85009SJon Lin 		sfc_nand_wait_busy(&status, 1000 * 1000);
1131e5e85009SJon Lin 
1132a6fcac41SJon Lin 	ecc_result = p_nand_info->ecc_status();
1133a6fcac41SJon Lin 
113458463f4dSJon Lin 	op.sfcmd.d32 = 0;
113558463f4dSJon Lin 	op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd;
1136a80fd396SJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
1137a80fd396SJon Lin 	op.sfcmd.b.dummybits = 8;
113858463f4dSJon Lin 
113958463f4dSJon Lin 	op.sfctrl.d32 = 0;
114058463f4dSJon Lin 	op.sfctrl.b.datalines = sfc_nand_dev.read_lines;
1141a80fd396SJon Lin 	op.sfctrl.b.addrbits = 16;
1142ba0501acSDingqiang Lin 
1143a80fd396SJon Lin 	plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0;
1144a80fd396SJon Lin 	ret = sfc_request(&op, plane | column, p_page_buf, len);
1145a80fd396SJon Lin 	rkflash_print_dio("%s %x %x\n", __func__, row, p_page_buf[0]);
1146c84f0ed8SJon Lin 
1147c84f0ed8SJon Lin 	if (ret != SFC_OK)
1148f28847a8SJon Lin 		return SFC_NAND_HW_ERROR;
1149c84f0ed8SJon Lin 
1150c84f0ed8SJon Lin 	return ecc_result;
1151c84f0ed8SJon Lin }
1152c84f0ed8SJon Lin 
sfc_nand_read_page_raw(u8 cs,u32 addr,u32 * p_page_buf)1153a80fd396SJon Lin u32 sfc_nand_read_page_raw(u8 cs, u32 addr, u32 *p_page_buf)
1154a80fd396SJon Lin {
1155a80fd396SJon Lin 	u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page;
1156a80fd396SJon Lin 
1157a80fd396SJon Lin 	return sfc_nand_read(addr, p_page_buf, 0, page_size);
1158a80fd396SJon Lin }
1159a80fd396SJon Lin 
sfc_nand_read_page(u8 cs,u32 addr,u32 * p_data,u32 * p_spare)1160c84f0ed8SJon Lin u32 sfc_nand_read_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare)
1161c84f0ed8SJon Lin {
116258463f4dSJon Lin 	u32 ret;
1163c84f0ed8SJon Lin 	u32 sec_per_page = p_nand_info->sec_per_page;
1164c84f0ed8SJon Lin 	u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE;
1165a6fcac41SJon Lin 	struct nand_mega_area *meta = &p_nand_info->meta;
1166c84f0ed8SJon Lin 
1167c84f0ed8SJon Lin 	ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf);
1168f25e3cafSJon Lin 	memcpy(p_data, gp_page_buf, data_size);
1169a6fcac41SJon Lin 	p_spare[0] = gp_page_buf[(data_size + meta->off0) / 4];
1170a6fcac41SJon Lin 	p_spare[1] = gp_page_buf[(data_size + meta->off1) / 4];
1171f28847a8SJon Lin 
1172f25e3cafSJon Lin 	if (p_nand_info->sec_per_page == 8) {
1173a6fcac41SJon Lin 		p_spare[2] = gp_page_buf[(data_size + meta->off2) / 4];
1174a6fcac41SJon Lin 		p_spare[3] = gp_page_buf[(data_size + meta->off3) / 4];
1175f25e3cafSJon Lin 	}
1176ba0501acSDingqiang Lin 
1177f28847a8SJon Lin 	if (ret == SFC_NAND_HW_ERROR)
1178f28847a8SJon Lin 		ret = SFC_NAND_ECC_ERROR;
1179f28847a8SJon Lin 
1180c84f0ed8SJon Lin 	if (ret != SFC_NAND_ECC_OK) {
1181c84f0ed8SJon Lin 		rkflash_print_error("%s[0x%x], ret=0x%x\n", __func__, addr, ret);
1182f28847a8SJon Lin 
1183ba0501acSDingqiang Lin 		if (p_data)
1184c84f0ed8SJon Lin 			rkflash_print_hex("data:", p_data, 4, 8);
1185f28847a8SJon Lin 
1186ba0501acSDingqiang Lin 		if (p_spare)
1187c84f0ed8SJon Lin 			rkflash_print_hex("spare:", p_spare, 4, 2);
1188ba0501acSDingqiang Lin 	}
1189f25e3cafSJon Lin 
1190c84f0ed8SJon Lin 	return ret;
1191ba0501acSDingqiang Lin }
1192ba0501acSDingqiang Lin 
sfc_nand_check_bad_block(u8 cs,u32 addr)1193c84f0ed8SJon Lin u32 sfc_nand_check_bad_block(u8 cs, u32 addr)
1194c84f0ed8SJon Lin {
1195c84f0ed8SJon Lin 	u32 ret;
1196c84f0ed8SJon Lin 	u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE;
1197a80fd396SJon Lin 	u32 marker = 0;
1198c84f0ed8SJon Lin 
1199a80fd396SJon Lin 	ret = sfc_nand_read(addr, &marker, data_size, 2);
1200f28847a8SJon Lin 
1201f28847a8SJon Lin 	/* unify with mtd framework */
1202629111d3SJon Lin 	if (ret == SFC_NAND_ECC_ERROR || (u16)marker != 0xffff)
1203a80fd396SJon Lin 		rkflash_print_error("%s page= %x ret= %x spare= %x\n",
1204a80fd396SJon Lin 				    __func__, addr, ret, marker);
1205f28847a8SJon Lin 
1206c84f0ed8SJon Lin 	/* Original bad block */
1207a80fd396SJon Lin 	if ((u16)marker != 0xffff)
1208c84f0ed8SJon Lin 		return true;
1209c84f0ed8SJon Lin 
1210c84f0ed8SJon Lin 	return false;
1211c84f0ed8SJon Lin }
1212c84f0ed8SJon Lin 
sfc_nand_mark_bad_block(u8 cs,u32 addr)1213c84f0ed8SJon Lin u32 sfc_nand_mark_bad_block(u8 cs, u32 addr)
1214c84f0ed8SJon Lin {
1215c84f0ed8SJon Lin 	u32 ret;
1216c84f0ed8SJon Lin 	u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE;
1217c84f0ed8SJon Lin 
1218c84f0ed8SJon Lin 	ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf);
1219f28847a8SJon Lin 
1220c84f0ed8SJon Lin 	if (ret)
1221c84f0ed8SJon Lin 		return SFC_NAND_HW_ERROR;
1222f28847a8SJon Lin 
1223c84f0ed8SJon Lin 	gp_page_buf[data_size / 4] = 0x0;
1224c84f0ed8SJon Lin 	ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf);
1225f28847a8SJon Lin 
1226c84f0ed8SJon Lin 	if (ret)
1227c84f0ed8SJon Lin 		return SFC_NAND_HW_ERROR;
1228c84f0ed8SJon Lin 
1229c84f0ed8SJon Lin 	return ret;
1230c84f0ed8SJon Lin }
1231c84f0ed8SJon Lin 
sfc_nand_read_id(u8 * data)1232c84f0ed8SJon Lin int sfc_nand_read_id(u8 *data)
1233ba0501acSDingqiang Lin {
1234ba0501acSDingqiang Lin 	int ret;
123558463f4dSJon Lin 	struct rk_sfc_op op;
1236ba0501acSDingqiang Lin 
123758463f4dSJon Lin 	op.sfcmd.d32 = 0;
123858463f4dSJon Lin 	op.sfcmd.b.cmd = CMD_READ_JEDECID;
123958463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
1240ba0501acSDingqiang Lin 
124158463f4dSJon Lin 	op.sfctrl.d32 = 0;
124258463f4dSJon Lin 	op.sfctrl.b.addrbits = 8;
124358463f4dSJon Lin 
124458463f4dSJon Lin 	ret = sfc_request(&op, 0, data, 3);
1245ba0501acSDingqiang Lin 
1246ba0501acSDingqiang Lin 	return ret;
1247ba0501acSDingqiang Lin }
1248ba0501acSDingqiang Lin 
1249ba0501acSDingqiang Lin /*
1250ba0501acSDingqiang Lin  * Read the 1st page's 1st byte of a phy_blk
1251ba0501acSDingqiang Lin  * If not FF, it's bad blk
1252ba0501acSDingqiang Lin  */
sfc_nand_get_bad_block_list(u16 * table,u32 die)1253ba0501acSDingqiang Lin static int sfc_nand_get_bad_block_list(u16 *table, u32 die)
1254ba0501acSDingqiang Lin {
1255ba0501acSDingqiang Lin 	u32 bad_cnt, page;
1256ba0501acSDingqiang Lin 	u32 blk_per_die;
12572ac88c1bSJon Lin 	u16 blk;
1258ba0501acSDingqiang Lin 
1259c84f0ed8SJon Lin 	rkflash_print_info("%s\n", __func__);
1260c84f0ed8SJon Lin 
1261ba0501acSDingqiang Lin 	bad_cnt = 0;
1262ba0501acSDingqiang Lin 	blk_per_die = p_nand_info->plane_per_die *
1263ba0501acSDingqiang Lin 		      p_nand_info->blk_per_plane;
1264f28847a8SJon Lin 
1265ba0501acSDingqiang Lin 	for (blk = 0; blk < blk_per_die; blk++) {
1266ba0501acSDingqiang Lin 		page = (blk + blk_per_die * die) *
1267ba0501acSDingqiang Lin 		       p_nand_info->page_per_blk;
1268ba0501acSDingqiang Lin 
12692ac88c1bSJon Lin 		if (sfc_nand_check_bad_block(die, page)) {
1270ba0501acSDingqiang Lin 			table[bad_cnt++] = blk;
1271c84f0ed8SJon Lin 			rkflash_print_error("die[%d], bad_blk[%d]\n", die, blk);
1272ba0501acSDingqiang Lin 		}
1273ba0501acSDingqiang Lin 	}
1274f28847a8SJon Lin 
1275ba0501acSDingqiang Lin 	return (int)bad_cnt;
1276ba0501acSDingqiang Lin }
1277ba0501acSDingqiang Lin 
sfc_nand_ftl_ops_init(void)1278c84f0ed8SJon Lin void sfc_nand_ftl_ops_init(void)
1279ba0501acSDingqiang Lin {
1280ba0501acSDingqiang Lin 	/* para init */
1281ba0501acSDingqiang Lin 	g_nand_phy_info.nand_type	= 1;
1282ba0501acSDingqiang Lin 	g_nand_phy_info.die_num		= 1;
1283ba0501acSDingqiang Lin 	g_nand_phy_info.plane_per_die	= p_nand_info->plane_per_die;
1284ba0501acSDingqiang Lin 	g_nand_phy_info.blk_per_plane	= p_nand_info->blk_per_plane;
1285ba0501acSDingqiang Lin 	g_nand_phy_info.page_per_blk	= p_nand_info->page_per_blk;
1286ba0501acSDingqiang Lin 	g_nand_phy_info.page_per_slc_blk = p_nand_info->page_per_blk;
1287c84f0ed8SJon Lin 	g_nand_phy_info.byte_per_sec	= SFC_NAND_SECTOR_SIZE;
1288ba0501acSDingqiang Lin 	g_nand_phy_info.sec_per_page	= p_nand_info->sec_per_page;
1289ba0501acSDingqiang Lin 	g_nand_phy_info.sec_per_blk	= p_nand_info->sec_per_page *
1290ba0501acSDingqiang Lin 					  p_nand_info->page_per_blk;
1291ba0501acSDingqiang Lin 	g_nand_phy_info.reserved_blk	= 8;
1292ba0501acSDingqiang Lin 	g_nand_phy_info.blk_per_die	= p_nand_info->plane_per_die *
1293ba0501acSDingqiang Lin 					  p_nand_info->blk_per_plane;
1294ba0501acSDingqiang Lin 	g_nand_phy_info.ecc_bits	= p_nand_info->max_ecc_bits;
1295ba0501acSDingqiang Lin 
1296ba0501acSDingqiang Lin 	/* driver register */
1297ba0501acSDingqiang Lin 	g_nand_ops.get_bad_blk_list	= sfc_nand_get_bad_block_list;
1298ba0501acSDingqiang Lin 	g_nand_ops.erase_blk		= sfc_nand_erase_block;
1299ba0501acSDingqiang Lin 	g_nand_ops.prog_page		= sfc_nand_prog_page;
1300ba0501acSDingqiang Lin 	g_nand_ops.read_page		= sfc_nand_read_page;
130157d18453Sjon.lin 	g_nand_ops.bch_sel		= NULL;
1302ba0501acSDingqiang Lin }
1303ba0501acSDingqiang Lin 
sfc_nand_enable_QE(void)1304a6fcac41SJon Lin static int sfc_nand_enable_QE(void)
1305ba0501acSDingqiang Lin {
1306ba0501acSDingqiang Lin 	int ret = SFC_OK;
1307ba0501acSDingqiang Lin 	u8 status;
1308ba0501acSDingqiang Lin 
1309f28847a8SJon Lin 	ret = sfc_nand_read_feature(0xB0, &status);
1310ba0501acSDingqiang Lin 
1311ba0501acSDingqiang Lin 	if (ret != SFC_OK)
1312ba0501acSDingqiang Lin 		return ret;
1313ba0501acSDingqiang Lin 
1314f28847a8SJon Lin 	if (status & 1)   /* is QE bit set */
1315ba0501acSDingqiang Lin 		return SFC_OK;
1316ba0501acSDingqiang Lin 
1317f28847a8SJon Lin 	status |= 1;
1318ba0501acSDingqiang Lin 
1319f28847a8SJon Lin 	return sfc_nand_write_feature(0xB0, status);
1320ba0501acSDingqiang Lin }
1321ba0501acSDingqiang Lin 
sfc_nand_init(void)1322ba0501acSDingqiang Lin u32 sfc_nand_init(void)
1323ba0501acSDingqiang Lin {
1324c84f0ed8SJon Lin 	u8 status, id_byte[8];
1325ba0501acSDingqiang Lin 
1326c84f0ed8SJon Lin 	sfc_nand_read_id(id_byte);
1327c84f0ed8SJon Lin 	rkflash_print_error("sfc_nand id: %x %x %x\n",
1328ba0501acSDingqiang Lin 			    id_byte[0], id_byte[1], id_byte[2]);
1329f28847a8SJon Lin 
1330ba0501acSDingqiang Lin 	if (id_byte[0] == 0xFF || id_byte[0] == 0x00)
133158463f4dSJon Lin 		return (u32)FTL_NO_FLASH;
1332ba0501acSDingqiang Lin 
1333a6fcac41SJon Lin 	p_nand_info = sfc_nand_get_info(id_byte);
1334f28847a8SJon Lin 
133545292245SJon Lin 	if (!p_nand_info) {
133645292245SJon Lin 		pr_err("The device not support yet!\n");
133745292245SJon Lin 
133858463f4dSJon Lin 		return (u32)FTL_UNSUPPORTED_FLASH;
133945292245SJon Lin 	}
1340ba0501acSDingqiang Lin 
1341ba0501acSDingqiang Lin 	sfc_nand_dev.manufacturer = id_byte[0];
1342ba0501acSDingqiang Lin 	sfc_nand_dev.mem_type = id_byte[1];
1343c84f0ed8SJon Lin 	sfc_nand_dev.capacity = p_nand_info->density;
1344c84f0ed8SJon Lin 	sfc_nand_dev.block_size = p_nand_info->page_per_blk * p_nand_info->sec_per_page;
1345c84f0ed8SJon Lin 	sfc_nand_dev.page_size = p_nand_info->sec_per_page;
1346ba0501acSDingqiang Lin 
1347ba0501acSDingqiang Lin 	/* disable block lock */
1348ba0501acSDingqiang Lin 	sfc_nand_write_feature(0xA0, 0);
1349ba0501acSDingqiang Lin 	sfc_nand_dev.read_lines = DATA_LINES_X1;
1350ba0501acSDingqiang Lin 	sfc_nand_dev.prog_lines = DATA_LINES_X1;
1351f28847a8SJon Lin 	sfc_nand_dev.page_read_cmd = 0x03;
1352f28847a8SJon Lin 	sfc_nand_dev.page_prog_cmd = 0x02;
1353629111d3SJon Lin 	sfc_nand_dev.recheck_buffer = ftl_malloc(SFC_NAND_PAGE_MAX_SIZE);
1354629111d3SJon Lin 	if (!sfc_nand_dev.recheck_buffer) {
1355629111d3SJon Lin 		rkflash_print_error("%s recheck_buffer alloc failed\n", __func__);
1356629111d3SJon Lin 		return -1;
1357629111d3SJon Lin 	}
1358f28847a8SJon Lin 
1359ba0501acSDingqiang Lin 	if (p_nand_info->feature & FEA_4BIT_READ) {
1360f28847a8SJon Lin 		if ((p_nand_info->has_qe_bits && sfc_nand_enable_QE() == SFC_OK) ||
1361f28847a8SJon Lin 		    !p_nand_info->has_qe_bits) {
1362ba0501acSDingqiang Lin 			sfc_nand_dev.read_lines = DATA_LINES_X4;
1363f28847a8SJon Lin 			sfc_nand_dev.page_read_cmd = 0x6b;
1364ba0501acSDingqiang Lin 		}
1365ba0501acSDingqiang Lin 	}
1366ba0501acSDingqiang Lin 
1367ba0501acSDingqiang Lin 	if (p_nand_info->feature & FEA_4BIT_PROG &&
1368ba0501acSDingqiang Lin 	    sfc_nand_dev.read_lines == DATA_LINES_X4) {
1369ba0501acSDingqiang Lin 		sfc_nand_dev.prog_lines = DATA_LINES_X4;
1370f28847a8SJon Lin 		sfc_nand_dev.page_prog_cmd = 0x32;
1371ba0501acSDingqiang Lin 	}
1372ba0501acSDingqiang Lin 
1373ba0501acSDingqiang Lin 	sfc_nand_read_feature(0xA0, &status);
1374c84f0ed8SJon Lin 	rkflash_print_info("sfc_nand A0 = 0x%x\n", status);
1375ba0501acSDingqiang Lin 	sfc_nand_read_feature(0xB0, &status);
1376c84f0ed8SJon Lin 	rkflash_print_info("sfc_nand B0 = 0x%x\n", status);
1377c84f0ed8SJon Lin 	rkflash_print_info("read_lines = %x\n", sfc_nand_dev.read_lines);
1378c84f0ed8SJon Lin 	rkflash_print_info("prog_lines = %x\n", sfc_nand_dev.prog_lines);
1379c84f0ed8SJon Lin 	rkflash_print_info("page_read_cmd = %x\n", sfc_nand_dev.page_read_cmd);
1380c84f0ed8SJon Lin 	rkflash_print_info("page_prog_cmd = %x\n", sfc_nand_dev.page_prog_cmd);
1381ba0501acSDingqiang Lin 
1382ba0501acSDingqiang Lin 	return SFC_OK;
1383ba0501acSDingqiang Lin }
1384ba0501acSDingqiang Lin 
sfc_nand_deinit(void)1385c84f0ed8SJon Lin void sfc_nand_deinit(void)
1386ba0501acSDingqiang Lin {
1387c84f0ed8SJon Lin 	/* to-do */
1388629111d3SJon Lin 	kfree(sfc_nand_dev.recheck_buffer);
1389ba0501acSDingqiang Lin }
1390c84f0ed8SJon Lin 
sfc_nand_get_private_dev(void)1391c84f0ed8SJon Lin struct SFNAND_DEV *sfc_nand_get_private_dev(void)
1392c84f0ed8SJon Lin {
1393c84f0ed8SJon Lin 	return &sfc_nand_dev;
1394c84f0ed8SJon Lin }
1395c84f0ed8SJon Lin 
1396