xref: /rk3399_rockchip-uboot/drivers/rkflash/sfc_nand.c (revision a4bd704e4bcea7ee9a12adc8165af36b5f1f916d)
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);
27*a4bd704eSJon Lin static u32 sfc_nand_get_ecc_status10(void);
28f28847a8SJon Lin 
29ba0501acSDingqiang Lin static struct nand_info spi_nand_tbl[] = {
30ba0501acSDingqiang Lin 	/* TC58CVG0S0HxAIx */
31b833c879SJon Lin 	{ 0x98, 0xC2, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
32ba0501acSDingqiang Lin 	/* TC58CVG1S0HxAIx */
33b833c879SJon Lin 	{ 0x98, 0xCB, 0x00, 4, 0x40, 2, 1024, 0x00, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
34a6fcac41SJon Lin 	/* TC58CVG2S0HRAIJ */
35b833c879SJon Lin 	{ 0x98, 0xED, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 0, { 0x04, 0x0C, 0x08, 0x10 }, &sfc_nand_get_ecc_status0 },
36a6fcac41SJon Lin 	/* TC58CVG1S3HRAIJ */
37b833c879SJon Lin 	{ 0x98, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
38a6fcac41SJon Lin 	/* TC58CVG0S3HRAIJ */
39b833c879SJon Lin 	{ 0x98, 0xE2, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
40f28847a8SJon Lin 
41f28847a8SJon Lin 	/* MX35LF1GE4AB */
42b833c879SJon Lin 	{ 0xC2, 0x12, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
43f28847a8SJon Lin 	/* MX35LF2GE4AB */
44b833c879SJon Lin 	{ 0xC2, 0x22, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
45f28847a8SJon Lin 	/* MX35LF2GE4AD */
46b833c879SJon Lin 	{ 0xC2, 0x26, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
47f28847a8SJon Lin 	/* MX35LF4GE4AD */
48362b1be1SJon Lin 	{ 0xC2, 0x37, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status0 },
49362b1be1SJon Lin 	/* MX35UF1GE4AC */
50362b1be1SJon Lin 	{ 0xC2, 0x92, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
51362b1be1SJon Lin 	/* MX35UF2GE4AC */
52362b1be1SJon Lin 	{ 0xC2, 0xA2, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
53f5e7a59fSJon Lin 	/* MX35UF1GE4AD */
54f5e7a59fSJon Lin 	{ 0xC2, 0x96, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
55f5e7a59fSJon Lin 	/* MX35UF2GE4AD */
56f5e7a59fSJon Lin 	{ 0xC2, 0xA6, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
57f5e7a59fSJon Lin 	/* MX35UF4GE4AD */
58f5e7a59fSJon Lin 	{ 0xC2, 0xB7, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status0 },
59f28847a8SJon Lin 
60f28847a8SJon Lin 	/* GD5F1GQ4UAYIG */
61b833c879SJon Lin 	{ 0xC8, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
62f28847a8SJon Lin 	/* GD5F1GQ4RB9IGR */
63b833c879SJon Lin 	{ 0xC8, 0xD1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
64f28847a8SJon Lin 	/* GD5F2GQ40BY2GR */
65b833c879SJon Lin 	{ 0xC8, 0xD2, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
66f28847a8SJon Lin 	/* GD5F1GQ5UEYIG */
67b833c879SJon Lin 	{ 0xC8, 0x51, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
68f28847a8SJon Lin 	/* GD5F2GQ5UEYIG */
69b833c879SJon Lin 	{ 0xC8, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
70f28847a8SJon Lin 	/* GD5F1GQ4R */
71b833c879SJon Lin 	{ 0xC8, 0xC1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
72362b1be1SJon Lin 	/* GD5F4GQ6RExxG 1*4096 */
73d4db0b8dSJon Lin 	{ 0xC8, 0x45, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status2 },
74362b1be1SJon Lin 	/* GD5F4GQ6UExxG 1*4096 */
75d4db0b8dSJon Lin 	{ 0xC8, 0x55, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status2 },
768a654f32SJon Lin 	/* GD5F1GQ4UExxH */
778a654f32SJon Lin 	{ 0xC8, 0xD9, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
78e5e85009SJon Lin 	/* GD5F1GQ5REYIG Add 3rd code to distingush with F50L2G41KA */
79e5e85009SJon Lin 	{ 0xC8, 0x41, 0xC8, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
80bf620bf6SJon Lin 	/* GD5F2GQ5REYIG */
81bf620bf6SJon Lin 	{ 0xC8, 0x42, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
82bf620bf6SJon Lin 	/* GD5F2GM7RxG */
83e5e85009SJon Lin 	{ 0xC8, 0x82, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
84bf620bf6SJon Lin 	/* GD5F2GM7UxG */
85e5e85009SJon Lin 	{ 0xC8, 0x92, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
8645292245SJon Lin 	/* GD5F1GM7UxG */
87e5e85009SJon Lin 	{ 0xC8, 0x91, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
88d4db0b8dSJon Lin 	/* GD5F4GQ4UAYIG 1*4096 */
89d4db0b8dSJon Lin 	{ 0xC8, 0xF4, 0x00, 4, 0x40, 2, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status0 },
90e5e85009SJon Lin 	/* GD5F1GM7REYIGR */
91e5e85009SJon Lin 	{ 0xC8, 0x81, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
92e5e85009SJon Lin 	/* GD5F4GM8UEYIGR */
93e5e85009SJon Lin 	{ 0xC8, 0x95, 0x00, 4, 0x40, 1, 4096, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
94f28847a8SJon Lin 
95f28847a8SJon Lin 	/* W25N01GV */
96b833c879SJon Lin 	{ 0xEF, 0xAA, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 },
97b833c879SJon Lin 	/* W25N02KVZEIR */
98b833c879SJon Lin 	{ 0xEF, 0xAA, 0x22, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status0 },
99629111d3SJon Lin 	/* W25N04KVZEIR */
100629111d3SJon Lin 	{ 0xEF, 0xAA, 0x23, 4, 0x40, 1, 4096, 0x4C, 20, 0x8, 0, { 0x04, 0x14, 0x24, 0x34 }, &sfc_nand_get_ecc_status0 },
101f28847a8SJon Lin 	/* W25N01GW */
1027bdae1e3SJon Lin 	{ 0xEF, 0xBA, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 },
1037bdae1e3SJon Lin 	/* W25N02KW */
1047bdae1e3SJon Lin 	{ 0xEF, 0xBA, 0x22, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status0 },
1058a654f32SJon Lin 	/* W25N512GVEIG */
1068a654f32SJon Lin 	{ 0xEF, 0xAA, 0x20, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 },
107f5e7a59fSJon Lin 	/* W25N01KV */
108f5e7a59fSJon Lin 	{ 0xEF, 0xAE, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
109*a4bd704eSJon Lin 	/* W25N01JWZEIG */
110*a4bd704eSJon Lin 	{ 0xEF, 0xBC, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
111*a4bd704eSJon Lin 	/* W25N01KWZPIG */
112*a4bd704eSJon Lin 	{ 0xEF, 0xBE, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
113f28847a8SJon Lin 
114f28847a8SJon Lin 	/* HYF2GQ4UAACAE */
115b833c879SJon Lin 	{ 0xC9, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
116f28847a8SJon Lin 	/* HYF1GQ4UDACAE */
117b833c879SJon Lin 	{ 0xC9, 0x21, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
118f28847a8SJon Lin 	/* HYF1GQ4UPACAE */
119b833c879SJon Lin 	{ 0xC9, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
120f28847a8SJon Lin 	/* HYF2GQ4UDACAE */
121b833c879SJon Lin 	{ 0xC9, 0x22, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
122f28847a8SJon Lin 	/* HYF2GQ4UHCCAE */
123b833c879SJon Lin 	{ 0xC9, 0x5A, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
124f28847a8SJon Lin 	/* HYF4GQ4UAACBE */
12506efa4f9SJon Lin 	{ 0xC9, 0xD4, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0xE, 1, { 0x20, 0x40, 0x24, 0x44 }, &sfc_nand_get_ecc_status0 },
12606efa4f9SJon Lin 	/* HYF2GQ4IAACAE */
12706efa4f9SJon Lin 	{ 0xC9, 0x82, 0x00, 4, 0x40, 1, 2048, 0x4C, 20, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
12806efa4f9SJon Lin 	/* HYF1GQ4IDACAE */
12906efa4f9SJon Lin 	{ 0xC9, 0x81, 0x00, 4, 0x40, 1, 1024, 0x4C, 20, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
130f28847a8SJon Lin 
131f28847a8SJon Lin 	/* FS35ND01G-S1 */
132b833c879SJon Lin 	{ 0xCD, 0xB1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
133f28847a8SJon Lin 	/* FS35ND02G-S2 */
134b833c879SJon Lin 	{ 0xCD, 0xA2, 0x00, 4, 0x40, 1, 2048, 0x00, 19, 0x4, 0, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
13558463f4dSJon Lin 	/* FS35ND01G-S1Y2 */
136b833c879SJon Lin 	{ 0xCD, 0xEA, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
137f1b20f5aSJon Lin 	/* FS35ND02G-S3Y2 */
138b833c879SJon Lin 	{ 0xCD, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
139f28847a8SJon Lin 	/* FS35ND04G-S2Y2 1*4096 */
140b833c879SJon Lin 	{ 0xCD, 0xEC, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
141bf620bf6SJon Lin 	/* F35SQA001G */
142bf620bf6SJon Lin 	{ 0xCD, 0x71, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
14345292245SJon Lin 	/* F35SQA002G */
14445292245SJon Lin 	{ 0xCD, 0x72, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
145d4db0b8dSJon Lin 	/* F35SQA512M */
146d4db0b8dSJon Lin 	{ 0xCD, 0x70, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
147d4db0b8dSJon Lin 	/* F35UQA512M */
148f5e7a59fSJon Lin 	{ 0xCD, 0x60, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
149e5e85009SJon Lin 	/* F35UQA002G-WWT */
150e5e85009SJon Lin 	{ 0xCD, 0x62, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
151*a4bd704eSJon Lin 	/* F35SQB004G-WWT */
152e5e85009SJon Lin 	{ 0xCD, 0x61, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
153*a4bd704eSJon Lin 	/* F35SQB004G */
154*a4bd704eSJon Lin 	{ 0xCD, 0x53, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status10 },
155*a4bd704eSJon Lin 	/* F35SQB002G */
156*a4bd704eSJon Lin 	{ 0xCD, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status10 },
157f28847a8SJon Lin 
158f28847a8SJon Lin 	/* DS35Q1GA-IB */
159b833c879SJon Lin 	{ 0xE5, 0x71, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
160f28847a8SJon Lin 	/* DS35Q2GA-IB */
161b833c879SJon Lin 	{ 0xE5, 0x72, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
162f28847a8SJon Lin 	/* DS35M1GA-1B */
163b833c879SJon Lin 	{ 0xE5, 0x21, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
164bf620bf6SJon Lin 	/* DS35M2GA-IB */
165bf620bf6SJon Lin 	{ 0xE5, 0x22, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
166d4db0b8dSJon Lin 	/* DS35Q1GB-IB */
167d4db0b8dSJon Lin 	{ 0xE5, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
168629111d3SJon Lin 	/* DS35Q2GB-IB */
169629111d3SJon Lin 	{ 0xE5, 0xF2, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
170d4db0b8dSJon Lin 	/* DS35Q4GM */
171d4db0b8dSJon Lin 	{ 0xE5, 0xF4, 0x00, 4, 0x40, 2, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
172bf620bf6SJon Lin 	/* DS35M1GB-IB */
173bf620bf6SJon Lin 	{ 0xE5, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
174f5e7a59fSJon Lin 	/* DS35Q12B-IB */
175f5e7a59fSJon Lin 	{ 0xE5, 0xF5, 0x00, 4, 0x40, 1, 512, 0x0C, 17, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
176f5e7a59fSJon Lin 	/* DS35M12B-IB */
177f5e7a59fSJon Lin 	{ 0xE5, 0xA5, 0x00, 4, 0x40, 1, 512, 0x0C, 17, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
178e5e85009SJon Lin 	/* DS35Q1GD-IB */
179e5e85009SJon Lin 	{ 0xE5, 0x51, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
180*a4bd704eSJon Lin 	/* DS35M4GB-IB */
181*a4bd704eSJon Lin 	{ 0xE5, 0x64, 0x00, 4, 0x40, 1, 4096, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
182*a4bd704eSJon Lin 	/* DS35Q4GB-IB */
183*a4bd704eSJon Lin 	{ 0xE5, 0xB4, 0x00, 4, 0x40, 1, 4096, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
184*a4bd704eSJon Lin 	/* DS35M12C-IB */
185*a4bd704eSJon Lin 	{ 0xE5, 0x25, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
186*a4bd704eSJon Lin 	/* DS35Q12C-IB */
187*a4bd704eSJon Lin 	{ 0xE5, 0x75, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
188*a4bd704eSJon Lin 	/* DS35Q2GBS */
189*a4bd704eSJon Lin 	{ 0xE5, 0xB2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
190f28847a8SJon Lin 
191f28847a8SJon Lin 	/* EM73C044VCC-H */
192b833c879SJon Lin 	{ 0xD5, 0x22, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
193f28847a8SJon Lin 	/* EM73D044VCE-H */
194b833c879SJon Lin 	{ 0xD5, 0x20, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
195f28847a8SJon Lin 	/* EM73E044SNA-G */
196b833c879SJon Lin 	{ 0xD5, 0x03, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x28, 0x08, 0x2C }, &sfc_nand_get_ecc_status0 },
197629111d3SJon Lin 	/* EM73C044VCF-H */
198629111d3SJon Lin 	{ 0xD5, 0x25, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
199f28847a8SJon Lin 
200f28847a8SJon Lin 	/* XT26G02A */
201362b1be1SJon Lin 	{ 0x0B, 0xE2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
202f28847a8SJon Lin 	/* XT26G01A */
203362b1be1SJon Lin 	{ 0x0B, 0xE1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
204f28847a8SJon Lin 	/* XT26G04A */
205362b1be1SJon Lin 	{ 0x0B, 0xE3, 0x00, 4, 0x80, 1, 2048, 0x4C, 20, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
206f28847a8SJon Lin 	/* XT26G01B */
207362b1be1SJon Lin 	{ 0x0B, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
208f28847a8SJon Lin 	/* XT26G02B */
209362b1be1SJon Lin 	{ 0x0B, 0xF2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
210362b1be1SJon Lin 	/* XT26G01C */
211362b1be1SJon Lin 	{ 0x0B, 0x11, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 },
212362b1be1SJon Lin 	/* XT26G02C */
213362b1be1SJon Lin 	{ 0x0B, 0x12, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 },
214362b1be1SJon Lin 	/* XT26G04C */
215362b1be1SJon Lin 	{ 0x0B, 0x13, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status7 },
216629111d3SJon Lin 	/* XT26G11C */
217629111d3SJon Lin 	{ 0x0B, 0x15, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
218e5e85009SJon Lin 	/* XT26Q02DWSIGA */
219e5e85009SJon Lin 	{ 0x0B, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
220e5e85009SJon Lin 	/* XT26Q01DWSIGA */
221e5e85009SJon Lin 	{ 0x0B, 0x51, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
222e5e85009SJon Lin 	/* XT26Q04DWSIGA */
223e5e85009SJon Lin 	{ 0x0B, 0x53, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status0 },
224e5e85009SJon Lin 	/* XT26G01DWSIGA */
225e5e85009SJon Lin 	{ 0x0B, 0x31, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
226e5e85009SJon Lin 	/* XT26G02DWSIGA */
227e5e85009SJon Lin 	{ 0x0B, 0x32, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
228e5e85009SJon Lin 	/* XT26G04DWSIGA */
229e5e85009SJon Lin 	{ 0x0B, 0x33, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status0 },
230*a4bd704eSJon Lin 	/* XT26Q04DWSIGT-B */
231*a4bd704eSJon Lin 	{ 0x0B, 0x53, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x14, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status0 },
232*a4bd704eSJon Lin 	/* XT26Q01DWSIGA */
233*a4bd704eSJon Lin 	{ 0x0B, 0x51, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
234a80fd396SJon Lin 
235362b1be1SJon Lin 	/* MT29F2G01ABA, XT26G02E, F50L2G41XA */
236629111d3SJon Lin 	{ 0x2C, 0x24, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x8, 0, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
237629111d3SJon Lin 	/* MT29F1G01ABA, F50L1G41XA */
238629111d3SJon Lin 	{ 0x2C, 0x14, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 0, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
239a80fd396SJon Lin 
240a80fd396SJon Lin 	/* FM25S01 */
241b833c879SJon Lin 	{ 0xA1, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x00, 0x04, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
242a80fd396SJon Lin 	/* FM25S01A */
243b833c879SJon Lin 	{ 0xA1, 0xE4, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
244a80fd396SJon Lin 	/* FM25S02A */
245b833c879SJon Lin 	{ 0xA1, 0xE5, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
2467bdae1e3SJon Lin 	/* FM25LS01 */
2477bdae1e3SJon Lin 	{ 0xA1, 0xA5, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
248e5e85009SJon Lin 	/* FM25S01BI3 */
249e5e85009SJon Lin 	{ 0xA1, 0xD4, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
250e5e85009SJon Lin 	/* FM25G02BI3 */
251e5e85009SJon Lin 	{ 0xA1, 0xD2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
252*a4bd704eSJon Lin 	/* FM25S02BI3-DND-A-G3 */
253*a4bd704eSJon Lin 	{ 0xA1, 0xD6, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
254*a4bd704eSJon Lin 	/* FM25G02D */
255*a4bd704eSJon Lin 	{ 0xA1, 0xF2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
256f28847a8SJon Lin 
257f28847a8SJon Lin 	/* IS37SML01G1 */
258b833c879SJon Lin 	{ 0xC8, 0x21, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x1, 0, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
259f28847a8SJon Lin 	/* F50L1G41LB */
260b833c879SJon Lin 	{ 0xC8, 0x01, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
261e5e85009SJon Lin 	/* F50L2G41KA */
262e5e85009SJon Lin 	{ 0xC8, 0x41, 0x7F, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
263e5e85009SJon Lin 
264e5e85009SJon Lin 	/* UM19A1HISW */
265e5e85009SJon Lin 	{ 0xB0, 0x24, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
266e5e85009SJon Lin 	/* UM19A0HCSW */
267e5e85009SJon Lin 	{ 0xB0, 0x14, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
268e5e85009SJon Lin 	/* UM19A0LCSW */
269e5e85009SJon Lin 	{ 0xB0, 0x15, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
270e5e85009SJon Lin 	/* UM19A1LISW */
271e5e85009SJon Lin 	{ 0xB0, 0x25, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
272*a4bd704eSJon Lin 	/* UM19A9LISW */
273*a4bd704eSJon Lin 	{ 0xB0, 0x0D, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
274*a4bd704eSJon Lin 	/* UM19A9HISW */
275*a4bd704eSJon Lin 	{ 0xB0, 0x0C, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
276e5e85009SJon Lin 
277f28847a8SJon Lin 	/* ATO25D1GA */
278b833c879SJon Lin 	{ 0x9B, 0x12, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x1, 1, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
279362b1be1SJon Lin 	/* BWJX08K-2Gb */
280362b1be1SJon Lin 	{ 0xBC, 0xB3, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x10, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
281629111d3SJon Lin 	/* JS28U1GQSCAHG-83 */
282629111d3SJon Lin 	{ 0xBF, 0x21, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x4, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status8 },
2838a654f32SJon Lin 	/* SGM7000I-S24W1GH */
2848a654f32SJon Lin 	{ 0xEA, 0xC1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
285bf620bf6SJon Lin 	/* TX25G01 */
286bf620bf6SJon Lin 	{ 0xA1, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status8 },
287e5e85009SJon Lin 
288*a4bd704eSJon Lin 	/* S35ML01G3, ANV1GCP0CLG, HYF1GQ4UTXCAE, YX25G1E, GSS01GSAM0 */
289f5e7a59fSJon Lin 	{ 0x01, 0x15, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status9 },
290e5e85009SJon Lin 	/* S35ML02G3, ANV2GCP0CLG, HYF2GQ4UTXCAE, YX25G2E */
291f5e7a59fSJon Lin 	{ 0x01, 0x25, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status9 },
292d4db0b8dSJon Lin 	/* S35ML04G3 */
293f5e7a59fSJon Lin 	{ 0x01, 0x35, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 0, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status9 },
294e5e85009SJon Lin 
29506efa4f9SJon Lin 	/* GSS01GSAK1 */
29606efa4f9SJon Lin 	{ 0x52, 0xBA, 0x13, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
29706efa4f9SJon Lin 	/* GSS02GSAK1 */
29806efa4f9SJon Lin 	{ 0x52, 0xBA, 0x23, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
299*a4bd704eSJon Lin 	/* GSS02GSAX1 */
300*a4bd704eSJon Lin 	{ 0x52, 0xCA, 0x23, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
301*a4bd704eSJon Lin 	/* GSS01GSAX1 */
302*a4bd704eSJon Lin 	{ 0x52, 0xCA, 0x13, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
303e5e85009SJon Lin 
304e5e85009SJon Lin 	/* XCSP2AAPK */
305e5e85009SJon Lin 	{ 0x8C, 0xA1, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
306e5e85009SJon Lin 	/* XCSP1AAPK */
307e5e85009SJon Lin 	{ 0x8C, 0x01, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
308*a4bd704eSJon Lin 	/* F50L1G41LC */
309*a4bd704eSJon Lin 	{ 0x8C, 0x2C, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x1, 0, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
310*a4bd704eSJon Lin 
311*a4bd704eSJon Lin 	/* ZB35Q01BYIG */
312*a4bd704eSJon Lin 	{ 0x5E, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
313*a4bd704eSJon Lin 	/* ZB35Q04BYIG */
314*a4bd704eSJon Lin 	{ 0x5E, 0xA3, 0x00, 4, 0x80, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
315*a4bd704eSJon Lin 
316*a4bd704eSJon Lin 	/* HSESYHDSW2G */
317*a4bd704eSJon Lin 	{ 0x3C, 0xD2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
318ba0501acSDingqiang Lin };
319ba0501acSDingqiang Lin 
320ba0501acSDingqiang Lin static struct nand_info *p_nand_info;
321ba0501acSDingqiang Lin static u32 gp_page_buf[SFC_NAND_PAGE_MAX_SIZE / 4];
322ba0501acSDingqiang Lin static struct SFNAND_DEV sfc_nand_dev;
323ba0501acSDingqiang Lin 
324a6fcac41SJon Lin static struct nand_info *sfc_nand_get_info(u8 *nand_id)
325ba0501acSDingqiang Lin {
326ba0501acSDingqiang Lin 	u32 i;
327ba0501acSDingqiang Lin 
328ba0501acSDingqiang Lin 	for (i = 0; i < ARRAY_SIZE(spi_nand_tbl); i++) {
329b833c879SJon Lin 		if (spi_nand_tbl[i].id0 == nand_id[0] &&
330b833c879SJon Lin 		    spi_nand_tbl[i].id1 == nand_id[1]) {
331b833c879SJon Lin 			if (spi_nand_tbl[i].id2 &&
332b833c879SJon Lin 			    spi_nand_tbl[i].id2 != nand_id[2])
333b833c879SJon Lin 				continue;
334b833c879SJon Lin 
335ba0501acSDingqiang Lin 			return &spi_nand_tbl[i];
336ba0501acSDingqiang Lin 		}
337b833c879SJon Lin 	}
338f28847a8SJon Lin 
339ba0501acSDingqiang Lin 	return NULL;
340ba0501acSDingqiang Lin }
341ba0501acSDingqiang Lin 
342ba0501acSDingqiang Lin static int sfc_nand_write_en(void)
343ba0501acSDingqiang Lin {
344ba0501acSDingqiang Lin 	int ret;
34558463f4dSJon Lin 	struct rk_sfc_op op;
346ba0501acSDingqiang Lin 
34758463f4dSJon Lin 	op.sfcmd.d32 = 0;
34858463f4dSJon Lin 	op.sfcmd.b.cmd = CMD_WRITE_EN;
34958463f4dSJon Lin 
35058463f4dSJon Lin 	op.sfctrl.d32 = 0;
35158463f4dSJon Lin 
35258463f4dSJon Lin 	ret = sfc_request(&op, 0, NULL, 0);
353ba0501acSDingqiang Lin 	return ret;
354ba0501acSDingqiang Lin }
355ba0501acSDingqiang Lin 
356ba0501acSDingqiang Lin static int sfc_nand_rw_preset(void)
357ba0501acSDingqiang Lin {
358ba0501acSDingqiang Lin 	int ret;
35958463f4dSJon Lin 	struct rk_sfc_op op;
360ba0501acSDingqiang Lin 
36158463f4dSJon Lin 	op.sfcmd.d32 = 0;
362f28847a8SJon Lin 	op.sfcmd.b.cmd = 0xff;
363f28847a8SJon Lin 	op.sfcmd.b.cs = 2;
364ba0501acSDingqiang Lin 
36558463f4dSJon Lin 	op.sfctrl.d32 = 0;
36658463f4dSJon Lin 	op.sfctrl.b.datalines = 2;
367f28847a8SJon Lin 	op.sfctrl.b.cmdlines = 2;
368f28847a8SJon Lin 	op.sfctrl.b.addrlines = 2;
36958463f4dSJon Lin 
370f28847a8SJon Lin 	ret = sfc_request(&op, 0, NULL, 0);
371ba0501acSDingqiang Lin 	return ret;
372ba0501acSDingqiang Lin }
373ba0501acSDingqiang Lin 
374ba0501acSDingqiang Lin static int sfc_nand_read_feature(u8 addr, u8 *data)
375ba0501acSDingqiang Lin {
376ba0501acSDingqiang Lin 	int ret;
37758463f4dSJon Lin 	struct rk_sfc_op op;
378ba0501acSDingqiang Lin 
37958463f4dSJon Lin 	op.sfcmd.d32 = 0;
38058463f4dSJon Lin 	op.sfcmd.b.cmd = 0x0F;
38158463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
38258463f4dSJon Lin 
38358463f4dSJon Lin 	op.sfctrl.d32 = 0;
38458463f4dSJon Lin 	op.sfctrl.b.addrbits = 8;
38558463f4dSJon Lin 
386ba0501acSDingqiang Lin 	*data = 0;
387ba0501acSDingqiang Lin 
38858463f4dSJon Lin 	ret = sfc_request(&op, addr, data, 1);
389f28847a8SJon Lin 
390ba0501acSDingqiang Lin 	if (ret != SFC_OK)
391ba0501acSDingqiang Lin 		return ret;
392f28847a8SJon Lin 
393ba0501acSDingqiang Lin 	return SFC_OK;
394ba0501acSDingqiang Lin }
395ba0501acSDingqiang Lin 
396ba0501acSDingqiang Lin static int sfc_nand_write_feature(u32 addr, u8 status)
397ba0501acSDingqiang Lin {
398ba0501acSDingqiang Lin 	int ret;
39958463f4dSJon Lin 	struct rk_sfc_op op;
400ba0501acSDingqiang Lin 
401ba0501acSDingqiang Lin 	sfc_nand_write_en();
402ba0501acSDingqiang Lin 
40358463f4dSJon Lin 	op.sfcmd.d32 = 0;
40458463f4dSJon Lin 	op.sfcmd.b.cmd = 0x1F;
40558463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
40658463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
407ba0501acSDingqiang Lin 
40858463f4dSJon Lin 	op.sfctrl.d32 = 0;
40958463f4dSJon Lin 	op.sfctrl.b.addrbits = 8;
41058463f4dSJon Lin 
41158463f4dSJon Lin 	ret = sfc_request(&op, addr, &status, 1);
412f28847a8SJon Lin 
413ba0501acSDingqiang Lin 	if (ret != SFC_OK)
414ba0501acSDingqiang Lin 		return ret;
415f28847a8SJon Lin 
416ba0501acSDingqiang Lin 	return ret;
417ba0501acSDingqiang Lin }
418ba0501acSDingqiang Lin 
419ba0501acSDingqiang Lin static int sfc_nand_wait_busy(u8 *data, int timeout)
420ba0501acSDingqiang Lin {
421ba0501acSDingqiang Lin 	int ret;
422ba0501acSDingqiang Lin 	int i;
423ba0501acSDingqiang Lin 	u8 status;
424ba0501acSDingqiang Lin 
425ba0501acSDingqiang Lin 	*data = 0;
426f28847a8SJon Lin 
427ba0501acSDingqiang Lin 	for (i = 0; i < timeout; i++) {
428ba0501acSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
429f28847a8SJon Lin 
430ba0501acSDingqiang Lin 		if (ret != SFC_OK)
431ba0501acSDingqiang Lin 			return ret;
432f28847a8SJon Lin 
433ba0501acSDingqiang Lin 		*data = status;
434f28847a8SJon Lin 
435ba0501acSDingqiang Lin 		if (!(status & (1 << 0)))
436ba0501acSDingqiang Lin 			return SFC_OK;
437f28847a8SJon Lin 
438ba0501acSDingqiang Lin 		sfc_delay(1);
439ba0501acSDingqiang Lin 	}
440f28847a8SJon Lin 
441f28847a8SJon Lin 	return SFC_NAND_WAIT_TIME_OUT;
442ba0501acSDingqiang Lin }
443ba0501acSDingqiang Lin 
4446281205aSDingqiang Lin /*
4456281205aSDingqiang Lin  * ecc default:
446a6fcac41SJon Lin  * ecc bits: 0xC0[4,5]
447f28847a8SJon Lin  * 0b00, No bit errors were detected
448f28847a8SJon Lin  * 0b01, Bit errors were detected and corrected.
449f28847a8SJon Lin  * 0b10, Multiple bit errors were detected and not corrected.
450f28847a8SJon Lin  * 0b11, Bits errors were detected and corrected, bit error count
451362b1be1SJon Lin  *	reach the bit flip detection threshold
4526281205aSDingqiang Lin  */
453f28847a8SJon Lin static u32 sfc_nand_get_ecc_status0(void)
4546281205aSDingqiang Lin {
45558463f4dSJon Lin 	u32 ret;
4566281205aSDingqiang Lin 	u32 i;
4576281205aSDingqiang Lin 	u8 ecc;
4586281205aSDingqiang Lin 	u8 status;
4596281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
4606281205aSDingqiang Lin 
4616281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
4626281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
463f28847a8SJon Lin 
4646281205aSDingqiang Lin 		if (ret != SFC_OK)
4656281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
466f28847a8SJon Lin 
4676281205aSDingqiang Lin 		if (!(status & (1 << 0)))
4686281205aSDingqiang Lin 			break;
469f28847a8SJon Lin 
4706281205aSDingqiang Lin 		sfc_delay(1);
4716281205aSDingqiang Lin 	}
4726281205aSDingqiang Lin 
4736281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
4746281205aSDingqiang Lin 
4756281205aSDingqiang Lin 	if (ecc <= 1)
4766281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
4776281205aSDingqiang Lin 	else if (ecc == 2)
47858463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
4796281205aSDingqiang Lin 	else
4806281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
4816281205aSDingqiang Lin 
4826281205aSDingqiang Lin 	return ret;
4836281205aSDingqiang Lin }
4846281205aSDingqiang Lin 
4856281205aSDingqiang Lin /*
4866281205aSDingqiang Lin  * ecc spectial type1:
487a6fcac41SJon Lin  * ecc bits: 0xC0[4,5]
488f28847a8SJon Lin  * 0b00, No bit errors were detected;
489f28847a8SJon Lin  * 0b01, Bits errors were detected and corrected, bit error count
4906281205aSDingqiang Lin  *	may reach the bit flip detection threshold;
491f28847a8SJon Lin  * 0b10, Multiple bit errors were detected and not corrected;
492f28847a8SJon Lin  * 0b11, Reserved.
4936281205aSDingqiang Lin  */
494f28847a8SJon Lin static u32 sfc_nand_get_ecc_status1(void)
4956281205aSDingqiang Lin {
49658463f4dSJon Lin 	u32 ret;
4976281205aSDingqiang Lin 	u32 i;
4986281205aSDingqiang Lin 	u8 ecc;
4996281205aSDingqiang Lin 	u8 status;
5006281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
5016281205aSDingqiang Lin 
5026281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
5036281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
504f28847a8SJon Lin 
5056281205aSDingqiang Lin 		if (ret != SFC_OK)
5066281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
507f28847a8SJon Lin 
5086281205aSDingqiang Lin 		if (!(status & (1 << 0)))
5096281205aSDingqiang Lin 			break;
510f28847a8SJon Lin 
5116281205aSDingqiang Lin 		sfc_delay(1);
5126281205aSDingqiang Lin 	}
5136281205aSDingqiang Lin 
5146281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
5156281205aSDingqiang Lin 
5166281205aSDingqiang Lin 	if (ecc == 0)
5176281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
5186281205aSDingqiang Lin 	else if (ecc == 1)
5196281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
5206281205aSDingqiang Lin 	else
52158463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
5226281205aSDingqiang Lin 
5236281205aSDingqiang Lin 	return ret;
5246281205aSDingqiang Lin }
5256281205aSDingqiang Lin 
5266281205aSDingqiang Lin /*
527d9cdd318SJon Lin  * ecc spectial type2:
528a6fcac41SJon Lin  * ecc bits: 0xC0[4,5] 0xF0[4,5]
529f28847a8SJon Lin  * [0b0000, 0b0011], No bit errors were detected;
530f28847a8SJon Lin  * [0b0100, 0b0111], Bit errors were detected and corrected. Not
531d9cdd318SJon Lin  *	reach Flipping Bits;
532f28847a8SJon Lin  * [0b1000, 0b1011], Multiple bit errors were detected and
533c84f0ed8SJon Lin  *	not corrected.
534f28847a8SJon Lin  * [0b1100, 0b1111], reserved.
535d9cdd318SJon Lin  */
536f28847a8SJon Lin static u32 sfc_nand_get_ecc_status2(void)
537d9cdd318SJon Lin {
53858463f4dSJon Lin 	u32 ret;
539d9cdd318SJon Lin 	u32 i;
540d9cdd318SJon Lin 	u8 ecc;
541d9cdd318SJon Lin 	u8 status, status1;
542d9cdd318SJon Lin 	u32 timeout = 1000 * 1000;
543d9cdd318SJon Lin 
544d9cdd318SJon Lin 	for (i = 0; i < timeout; i++) {
545d9cdd318SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
546f28847a8SJon Lin 
547d9cdd318SJon Lin 		if (ret != SFC_OK)
548d9cdd318SJon Lin 			return SFC_NAND_ECC_ERROR;
549f28847a8SJon Lin 
550d9cdd318SJon Lin 		ret = sfc_nand_read_feature(0xF0, &status1);
551f28847a8SJon Lin 
552d9cdd318SJon Lin 		if (ret != SFC_OK)
553d9cdd318SJon Lin 			return SFC_NAND_ECC_ERROR;
554f28847a8SJon Lin 
555d9cdd318SJon Lin 		if (!(status & (1 << 0)))
556d9cdd318SJon Lin 			break;
557f28847a8SJon Lin 
558d9cdd318SJon Lin 		sfc_delay(1);
559d9cdd318SJon Lin 	}
560d9cdd318SJon Lin 
561d9cdd318SJon Lin 	ecc = (status >> 4) & 0x03;
562d9cdd318SJon Lin 	ecc = (ecc << 2) | ((status1 >> 4) & 0x03);
563f28847a8SJon Lin 
564d9cdd318SJon Lin 	if (ecc < 7)
565d9cdd318SJon Lin 		ret = SFC_NAND_ECC_OK;
566d9cdd318SJon Lin 	else if (ecc == 7)
567d9cdd318SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
568d9cdd318SJon Lin 	else
56958463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
570d9cdd318SJon Lin 
571d9cdd318SJon Lin 	return ret;
572d9cdd318SJon Lin }
573d9cdd318SJon Lin 
574d9cdd318SJon Lin /*
5756281205aSDingqiang Lin  * ecc spectial type3:
576a6fcac41SJon Lin  * ecc bits: 0xC0[4,5] 0xF0[4,5]
577f28847a8SJon Lin  * [0b0000, 0b0011], No bit errors were detected;
578f28847a8SJon Lin  * [0b0100, 0b0111], Bit errors were detected and corrected. Not
5796281205aSDingqiang Lin  *	reach Flipping Bits;
580f28847a8SJon Lin  * [0b1000, 0b1011], Multiple bit errors were detected and
5816281205aSDingqiang Lin  *	not corrected.
582f28847a8SJon Lin  * [0b1100, 0b1111], Bit error count equals the bit flip
5836281205aSDingqiang Lin  *	detectio nthreshold
5846281205aSDingqiang Lin  */
585f28847a8SJon Lin static u32 sfc_nand_get_ecc_status3(void)
5866281205aSDingqiang Lin {
58758463f4dSJon Lin 	u32 ret;
5886281205aSDingqiang Lin 	u32 i;
5896281205aSDingqiang Lin 	u8 ecc;
5906281205aSDingqiang Lin 	u8 status, status1;
5916281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
5926281205aSDingqiang Lin 
5936281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
5946281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
595f28847a8SJon Lin 
5966281205aSDingqiang Lin 		if (ret != SFC_OK)
5976281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
598f28847a8SJon Lin 
5996281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xF0, &status1);
600f28847a8SJon Lin 
6016281205aSDingqiang Lin 		if (ret != SFC_OK)
6026281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
603f28847a8SJon Lin 
6046281205aSDingqiang Lin 		if (!(status & (1 << 0)))
6056281205aSDingqiang Lin 			break;
606f28847a8SJon Lin 
6076281205aSDingqiang Lin 		sfc_delay(1);
6086281205aSDingqiang Lin 	}
6096281205aSDingqiang Lin 
6106281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
6116281205aSDingqiang Lin 	ecc = (ecc << 2) | ((status1 >> 4) & 0x03);
612f28847a8SJon Lin 
6136281205aSDingqiang Lin 	if (ecc < 7)
6146281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
6156281205aSDingqiang Lin 	else if (ecc == 7 || ecc >= 12)
6166281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
6176281205aSDingqiang Lin 	else
61858463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
6196281205aSDingqiang Lin 
6206281205aSDingqiang Lin 	return ret;
6216281205aSDingqiang Lin }
6226281205aSDingqiang Lin 
62325098c06SDingqiang Lin /*
62425098c06SDingqiang Lin  * ecc spectial type4:
625a6fcac41SJon Lin  * ecc bits: 0xC0[2,5]
626f28847a8SJon Lin  * [0b0000], No bit errors were detected;
627f28847a8SJon Lin  * [0b0001, 0b0111], Bit errors were detected and corrected. Not
62825098c06SDingqiang Lin  *	reach Flipping Bits;
629f28847a8SJon Lin  * [0b1000], Multiple bit errors were detected and
63025098c06SDingqiang Lin  *	not corrected.
631f28847a8SJon Lin  * [0b1100], Bit error count equals the bit flip
63225098c06SDingqiang Lin  *	detection threshold
63325098c06SDingqiang Lin  * else, reserved
63425098c06SDingqiang Lin  */
635f28847a8SJon Lin static u32 sfc_nand_get_ecc_status4(void)
63625098c06SDingqiang Lin {
63758463f4dSJon Lin 	u32 ret;
63825098c06SDingqiang Lin 	u32 i;
63925098c06SDingqiang Lin 	u8 ecc;
64025098c06SDingqiang Lin 	u8 status;
64125098c06SDingqiang Lin 	u32 timeout = 1000 * 1000;
64225098c06SDingqiang Lin 
64325098c06SDingqiang Lin 	for (i = 0; i < timeout; i++) {
64425098c06SDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
645f28847a8SJon Lin 
64625098c06SDingqiang Lin 		if (ret != SFC_OK)
64725098c06SDingqiang Lin 			return SFC_NAND_ECC_ERROR;
648f28847a8SJon Lin 
64925098c06SDingqiang Lin 		if (!(status & (1 << 0)))
65025098c06SDingqiang Lin 			break;
651f28847a8SJon Lin 
65225098c06SDingqiang Lin 		sfc_delay(1);
65325098c06SDingqiang Lin 	}
65425098c06SDingqiang Lin 
65525098c06SDingqiang Lin 	ecc = (status >> 2) & 0x0f;
656f28847a8SJon Lin 
65725098c06SDingqiang Lin 	if (ecc < 7)
65825098c06SDingqiang Lin 		ret = SFC_NAND_ECC_OK;
65925098c06SDingqiang Lin 	else if (ecc == 7 || ecc == 12)
66025098c06SDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
66125098c06SDingqiang Lin 	else
66258463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
66325098c06SDingqiang Lin 
66425098c06SDingqiang Lin 	return ret;
66525098c06SDingqiang Lin }
66625098c06SDingqiang Lin 
66725098c06SDingqiang Lin /*
66825098c06SDingqiang Lin  * ecc spectial type5:
669a6fcac41SJon Lin  * ecc bits: 0xC0[4,6]
670f28847a8SJon Lin  * [0b000], No bit errors were detected;
671f28847a8SJon Lin  * [0b001, 0b011], Bit errors were detected and corrected. Not
67225098c06SDingqiang Lin  *	reach Flipping Bits;
673f28847a8SJon Lin  * [0b100], Bit error count equals the bit flip
67425098c06SDingqiang Lin  *	detection threshold
675f28847a8SJon Lin  * [0b101, 0b110], Reserved;
676f28847a8SJon Lin  * [0b111], Multiple bit errors were detected and
67725098c06SDingqiang Lin  *	not corrected.
67825098c06SDingqiang Lin  */
679f28847a8SJon Lin static u32 sfc_nand_get_ecc_status5(void)
68025098c06SDingqiang Lin {
68158463f4dSJon Lin 	u32 ret;
68225098c06SDingqiang Lin 	u32 i;
68325098c06SDingqiang Lin 	u8 ecc;
68425098c06SDingqiang Lin 	u8 status;
68525098c06SDingqiang Lin 	u32 timeout = 1000 * 1000;
68625098c06SDingqiang Lin 
68725098c06SDingqiang Lin 	for (i = 0; i < timeout; i++) {
68825098c06SDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
689f28847a8SJon Lin 
69025098c06SDingqiang Lin 		if (ret != SFC_OK)
69125098c06SDingqiang Lin 			return SFC_NAND_ECC_ERROR;
692f28847a8SJon Lin 
69325098c06SDingqiang Lin 		if (!(status & (1 << 0)))
69425098c06SDingqiang Lin 			break;
695f28847a8SJon Lin 
69625098c06SDingqiang Lin 		sfc_delay(1);
69725098c06SDingqiang Lin 	}
69825098c06SDingqiang Lin 
69925098c06SDingqiang Lin 	ecc = (status >> 4) & 0x07;
700f28847a8SJon Lin 
70125098c06SDingqiang Lin 	if (ecc < 4)
70225098c06SDingqiang Lin 		ret = SFC_NAND_ECC_OK;
70325098c06SDingqiang Lin 	else if (ecc == 4)
70425098c06SDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
70525098c06SDingqiang Lin 	else
70658463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
70725098c06SDingqiang Lin 
70825098c06SDingqiang Lin 	return ret;
70925098c06SDingqiang Lin }
71025098c06SDingqiang Lin 
711f28847a8SJon Lin /*
712f28847a8SJon Lin  * ecc spectial type6:
713f28847a8SJon Lin  * ecc bits: 0xC0[4,6]
714f28847a8SJon Lin  * [0b000], No bit errors were detected;
715f28847a8SJon Lin  * [0b001], 1-3 Bit errors were detected and corrected. Not
716f28847a8SJon Lin  *	reach Flipping Bits;
717f28847a8SJon Lin  * [0b010], Multiple bit errors were detected and
718f28847a8SJon Lin  *	not corrected.
719f28847a8SJon Lin  * [0b011], 4-6 Bit errors were detected and corrected. Not
720f28847a8SJon Lin  *	reach Flipping Bits;
721f28847a8SJon Lin  * [0b101], Bit error count equals the bit flip
722f28847a8SJon Lin  *	detectionthreshold
723f28847a8SJon Lin  * others, Reserved.
724f28847a8SJon Lin  */
725f28847a8SJon Lin static u32 sfc_nand_get_ecc_status6(void)
726f28847a8SJon Lin {
727f28847a8SJon Lin 	u32 ret;
728f28847a8SJon Lin 	u32 i;
729f28847a8SJon Lin 	u8 ecc;
730f28847a8SJon Lin 	u8 status;
731f28847a8SJon Lin 	u32 timeout = 1000 * 1000;
732f28847a8SJon Lin 
733f28847a8SJon Lin 	for (i = 0; i < timeout; i++) {
734f28847a8SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
735f28847a8SJon Lin 
736f28847a8SJon Lin 		if (ret != SFC_OK)
737f28847a8SJon Lin 			return SFC_NAND_ECC_ERROR;
738f28847a8SJon Lin 
739f28847a8SJon Lin 		if (!(status & (1 << 0)))
740f28847a8SJon Lin 			break;
741f28847a8SJon Lin 
742f28847a8SJon Lin 		sfc_delay(1);
743f28847a8SJon Lin 	}
744f28847a8SJon Lin 
745f28847a8SJon Lin 	ecc = (status >> 4) & 0x07;
746f28847a8SJon Lin 
747f28847a8SJon Lin 	if (ecc == 0 || ecc == 1 || ecc == 3)
748f28847a8SJon Lin 		ret = SFC_NAND_ECC_OK;
749f28847a8SJon Lin 	else if (ecc == 5)
750f28847a8SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
751f28847a8SJon Lin 	else
752f28847a8SJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
753f28847a8SJon Lin 
754f28847a8SJon Lin 	return ret;
755f28847a8SJon Lin }
756f28847a8SJon Lin 
757362b1be1SJon Lin /*
758362b1be1SJon Lin  * ecc spectial type7:
759362b1be1SJon Lin  * ecc bits: 0xC0[4,7]
760362b1be1SJon Lin  * [0b0000], No bit errors were detected;
761362b1be1SJon Lin  * [0b0001, 0b0111], 1-7 Bit errors were detected and corrected. Not
762362b1be1SJon Lin  *	reach Flipping Bits;
763362b1be1SJon Lin  * [0b1000], 8 Bit errors were detected and corrected. Bit error count
764362b1be1SJon Lin  * 	equals the bit flip detectionthreshold;
765362b1be1SJon Lin  * [0b1111], Bit errors greater than ECC capability(8 bits) and not corrected;
766362b1be1SJon Lin  * others, Reserved.
767362b1be1SJon Lin  */
768362b1be1SJon Lin static u32 sfc_nand_get_ecc_status7(void)
769362b1be1SJon Lin {
770362b1be1SJon Lin 	u32 ret;
771362b1be1SJon Lin 	u32 i;
772362b1be1SJon Lin 	u8 ecc;
773362b1be1SJon Lin 	u8 status;
774362b1be1SJon Lin 	u32 timeout = 1000 * 1000;
775362b1be1SJon Lin 
776362b1be1SJon Lin 	for (i = 0; i < timeout; i++) {
777362b1be1SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
778362b1be1SJon Lin 
779362b1be1SJon Lin 		if (ret != SFC_OK)
780362b1be1SJon Lin 			return SFC_NAND_ECC_ERROR;
781362b1be1SJon Lin 
782362b1be1SJon Lin 		if (!(status & (1 << 0)))
783362b1be1SJon Lin 			break;
784362b1be1SJon Lin 
785362b1be1SJon Lin 		sfc_delay(1);
786362b1be1SJon Lin 	}
787362b1be1SJon Lin 
788362b1be1SJon Lin 	ecc = (status >> 4) & 0xf;
789362b1be1SJon Lin 
790362b1be1SJon Lin 	if (ecc < 7)
791362b1be1SJon Lin 		ret = SFC_NAND_ECC_OK;
792362b1be1SJon Lin 	else if (ecc == 7 || ecc == 8)
793362b1be1SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
794362b1be1SJon Lin 	else
795362b1be1SJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
796362b1be1SJon Lin 
797362b1be1SJon Lin 	return ret;
798362b1be1SJon Lin }
799362b1be1SJon Lin 
800629111d3SJon Lin /*
801629111d3SJon Lin  * ecc spectial type8:
802629111d3SJon Lin  * ecc bits: 0xC0[4,6]
803629111d3SJon Lin  * [0b000], No bit errors were detected;
804629111d3SJon Lin  * [0b001, 0b011], 1~3 Bit errors were detected and corrected. Not
805629111d3SJon Lin  *	reach Flipping Bits;
806629111d3SJon Lin  * [0b100], Bit error count equals the bit flip
807629111d3SJon Lin  *	detection threshold
808629111d3SJon Lin  * others, Reserved.
809629111d3SJon Lin  */
810629111d3SJon Lin static u32 sfc_nand_get_ecc_status8(void)
811629111d3SJon Lin {
812629111d3SJon Lin 	u32 ret;
813629111d3SJon Lin 	u32 i;
814629111d3SJon Lin 	u8 ecc;
815629111d3SJon Lin 	u8 status;
816629111d3SJon Lin 	u32 timeout = 1000 * 1000;
817629111d3SJon Lin 
818629111d3SJon Lin 	for (i = 0; i < timeout; i++) {
819629111d3SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
820629111d3SJon Lin 
821629111d3SJon Lin 		if (ret != SFC_OK)
822629111d3SJon Lin 			return SFC_NAND_ECC_ERROR;
823629111d3SJon Lin 
824629111d3SJon Lin 		if (!(status & (1 << 0)))
825629111d3SJon Lin 			break;
826629111d3SJon Lin 
827629111d3SJon Lin 		sfc_delay(1);
828629111d3SJon Lin 	}
829629111d3SJon Lin 
830629111d3SJon Lin 	ecc = (status >> 4) & 0x07;
831629111d3SJon Lin 
832629111d3SJon Lin 	if (ecc < 4)
833629111d3SJon Lin 		ret = SFC_NAND_ECC_OK;
834629111d3SJon Lin 	else if (ecc == 4)
835629111d3SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
836629111d3SJon Lin 	else
837629111d3SJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
838629111d3SJon Lin 
839629111d3SJon Lin 	return ret;
840629111d3SJon Lin }
841629111d3SJon Lin 
842d4db0b8dSJon Lin /*
843d4db0b8dSJon Lin  * ecc spectial type9:
844d4db0b8dSJon Lin  * ecc bits: 0xC0[4,5]
845d4db0b8dSJon Lin  * 0b00, No bit errors were detected
846d4db0b8dSJon Lin  * 0b01, 1-2Bit errors were detected and corrected.
847d4db0b8dSJon Lin  * 0b10, 3-4Bit errors were detected and corrected.
848d4db0b8dSJon Lin  * 0b11, 11 can be used as uncorrectable
849d4db0b8dSJon Lin  */
850d4db0b8dSJon Lin static u32 sfc_nand_get_ecc_status9(void)
851d4db0b8dSJon Lin {
852d4db0b8dSJon Lin 	u32 ret;
853d4db0b8dSJon Lin 	u32 i;
854d4db0b8dSJon Lin 	u8 ecc;
855d4db0b8dSJon Lin 	u8 status;
856d4db0b8dSJon Lin 	u32 timeout = 1000 * 1000;
857d4db0b8dSJon Lin 
858d4db0b8dSJon Lin 	for (i = 0; i < timeout; i++) {
859d4db0b8dSJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
860d4db0b8dSJon Lin 
861d4db0b8dSJon Lin 		if (ret != SFC_OK)
862d4db0b8dSJon Lin 			return SFC_NAND_ECC_ERROR;
863d4db0b8dSJon Lin 
864d4db0b8dSJon Lin 		if (!(status & (1 << 0)))
865d4db0b8dSJon Lin 			break;
866d4db0b8dSJon Lin 
867d4db0b8dSJon Lin 		sfc_delay(1);
868d4db0b8dSJon Lin 	}
869d4db0b8dSJon Lin 
870d4db0b8dSJon Lin 	ecc = (status >> 4) & 0x03;
871d4db0b8dSJon Lin 
872d4db0b8dSJon Lin 	if (ecc <= 1)
873d4db0b8dSJon Lin 		ret = SFC_NAND_ECC_OK;
874d4db0b8dSJon Lin 	else if (ecc == 2)
875d4db0b8dSJon Lin 		ret = SFC_NAND_ECC_REFRESH;
876d4db0b8dSJon Lin 	else
877d4db0b8dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
878d4db0b8dSJon Lin 
879d4db0b8dSJon Lin 	return ret;
880d4db0b8dSJon Lin }
881d4db0b8dSJon Lin 
882*a4bd704eSJon Lin /*
883*a4bd704eSJon Lin  * ecc spectial type8:
884*a4bd704eSJon Lin  * ecc bits: 0xC0[4,6]
885*a4bd704eSJon Lin  * [0b000], No bit errors were detected;
886*a4bd704eSJon Lin  * [0b001, 0b101], 3~7 Bit errors were detected and corrected. Not
887*a4bd704eSJon Lin  *	reach Flipping Bits;
888*a4bd704eSJon Lin  * [0b110], Bit error count equals the bit flip detection threshold
889*a4bd704eSJon Lin  * [0b111], Bit errors greater than ECC capability(8 bits) and not corrected;
890*a4bd704eSJon Lin  */
891*a4bd704eSJon Lin static u32 sfc_nand_get_ecc_status10(void)
892*a4bd704eSJon Lin {
893*a4bd704eSJon Lin 	u32 ret;
894*a4bd704eSJon Lin 	u32 i;
895*a4bd704eSJon Lin 	u8 ecc;
896*a4bd704eSJon Lin 	u8 status;
897*a4bd704eSJon Lin 	u32 timeout = 1000 * 1000;
898*a4bd704eSJon Lin 
899*a4bd704eSJon Lin 	for (i = 0; i < timeout; i++) {
900*a4bd704eSJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
901*a4bd704eSJon Lin 
902*a4bd704eSJon Lin 		if (ret != SFC_OK)
903*a4bd704eSJon Lin 			return SFC_NAND_ECC_ERROR;
904*a4bd704eSJon Lin 
905*a4bd704eSJon Lin 		if (!(status & (1 << 0)))
906*a4bd704eSJon Lin 			break;
907*a4bd704eSJon Lin 
908*a4bd704eSJon Lin 		sfc_delay(1);
909*a4bd704eSJon Lin 	}
910*a4bd704eSJon Lin 
911*a4bd704eSJon Lin 	ecc = (status >> 4) & 0x07;
912*a4bd704eSJon Lin 
913*a4bd704eSJon Lin 	if (ecc < 6)
914*a4bd704eSJon Lin 		ret = SFC_NAND_ECC_OK;
915*a4bd704eSJon Lin 	else if (ecc == 6)
916*a4bd704eSJon Lin 		ret = SFC_NAND_ECC_REFRESH;
917*a4bd704eSJon Lin 	else
918*a4bd704eSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
919*a4bd704eSJon Lin 
920*a4bd704eSJon Lin 	return ret;
921*a4bd704eSJon Lin }
922*a4bd704eSJon Lin 
923c84f0ed8SJon Lin u32 sfc_nand_erase_block(u8 cs, u32 addr)
924ba0501acSDingqiang Lin {
925ba0501acSDingqiang Lin 	int ret;
92658463f4dSJon Lin 	struct rk_sfc_op op;
927ba0501acSDingqiang Lin 	u8 status;
928ba0501acSDingqiang Lin 
929c84f0ed8SJon Lin 	rkflash_print_dio("%s %x\n", __func__, addr);
93058463f4dSJon Lin 	op.sfcmd.d32 = 0;
931f28847a8SJon Lin 	op.sfcmd.b.cmd = 0xd8;
93258463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_24BITS;
93358463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
93458463f4dSJon Lin 
93558463f4dSJon Lin 	op.sfctrl.d32 = 0;
93658463f4dSJon Lin 
937ba0501acSDingqiang Lin 	sfc_nand_write_en();
93858463f4dSJon Lin 	ret = sfc_request(&op, addr, NULL, 0);
939f28847a8SJon Lin 
940ba0501acSDingqiang Lin 	if (ret != SFC_OK)
941ba0501acSDingqiang Lin 		return ret;
942f28847a8SJon Lin 
943ba0501acSDingqiang Lin 	ret = sfc_nand_wait_busy(&status, 1000 * 1000);
944f28847a8SJon Lin 
945ba0501acSDingqiang Lin 	if (status & (1 << 2))
946ba0501acSDingqiang Lin 		return SFC_NAND_PROG_ERASE_ERROR;
947c84f0ed8SJon Lin 
948ba0501acSDingqiang Lin 	return ret;
949ba0501acSDingqiang Lin }
950ba0501acSDingqiang Lin 
951629111d3SJon Lin static u32 sfc_nand_read_cache(u32 row, u32 *p_page_buf, u32 column, u32 len)
952629111d3SJon Lin {
953629111d3SJon Lin 	int ret;
954629111d3SJon Lin 	u32 plane;
955629111d3SJon Lin 	struct rk_sfc_op op;
956629111d3SJon Lin 
957629111d3SJon Lin 	op.sfcmd.d32 = 0;
958629111d3SJon Lin 	op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd;
959629111d3SJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
960629111d3SJon Lin 	op.sfcmd.b.dummybits = 8;
961629111d3SJon Lin 
962629111d3SJon Lin 	op.sfctrl.d32 = 0;
963629111d3SJon Lin 	op.sfctrl.b.datalines = sfc_nand_dev.read_lines;
964629111d3SJon Lin 	op.sfctrl.b.addrbits = 16;
965629111d3SJon Lin 
966629111d3SJon Lin 	plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0;
967629111d3SJon Lin 
968629111d3SJon Lin 	ret = sfc_request(&op, plane | column, p_page_buf, len);
969629111d3SJon Lin 	if (ret != SFC_OK)
970629111d3SJon Lin 		return SFC_NAND_HW_ERROR;
971629111d3SJon Lin 
972629111d3SJon Lin 	return ret;
973629111d3SJon Lin }
974629111d3SJon Lin 
975f28847a8SJon Lin u32 sfc_nand_prog_page_raw(u8 cs, u32 addr, u32 *p_page_buf)
976ba0501acSDingqiang Lin {
977ba0501acSDingqiang Lin 	int ret;
978415cf080Sjon.lin 	u32 plane;
97958463f4dSJon Lin 	struct rk_sfc_op op;
980ba0501acSDingqiang Lin 	u8 status;
98158463f4dSJon Lin 	u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page;
982629111d3SJon Lin 	u32 data_area_size = SFC_NAND_SECTOR_SIZE * p_nand_info->sec_per_page;
983ba0501acSDingqiang Lin 
984c84f0ed8SJon Lin 	rkflash_print_dio("%s %x %x\n", __func__, addr, p_page_buf[0]);
985ba0501acSDingqiang Lin 	sfc_nand_write_en();
986f28847a8SJon Lin 
987ba0501acSDingqiang Lin 	if (sfc_nand_dev.prog_lines == DATA_LINES_X4 &&
98825098c06SDingqiang Lin 	    p_nand_info->feature & FEA_SOFT_QOP_BIT &&
98925098c06SDingqiang Lin 	    sfc_get_version() < SFC_VER_3)
990ba0501acSDingqiang Lin 		sfc_nand_rw_preset();
991ba0501acSDingqiang Lin 
99258463f4dSJon Lin 	op.sfcmd.d32 = 0;
99358463f4dSJon Lin 	op.sfcmd.b.cmd = sfc_nand_dev.page_prog_cmd;
99458463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
99558463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
996ba0501acSDingqiang Lin 
99758463f4dSJon Lin 	op.sfctrl.d32 = 0;
99858463f4dSJon Lin 	op.sfctrl.b.datalines = sfc_nand_dev.prog_lines;
99958463f4dSJon Lin 	op.sfctrl.b.addrbits = 16;
1000415cf080Sjon.lin 	plane = p_nand_info->plane_per_die == 2 ? ((addr >> 6) & 0x1) << 12 : 0;
100158463f4dSJon Lin 	sfc_request(&op, plane, p_page_buf, page_size);
1002ba0501acSDingqiang Lin 
1003629111d3SJon Lin 	/*
1004c797b43aSJon Lin 	 * At the moment of power lost or dev running in harsh environment, flash
1005c797b43aSJon Lin 	 * maybe work in a unkonw state and result in bit flip, when this situation
1006c797b43aSJon Lin 	 * is detected by cache recheck, it's better to wait a second for a reliable
1007c797b43aSJon Lin 	 * hardware environment to avoid abnormal data written to flash array.
1008629111d3SJon Lin 	 */
1009361684bfSJon Lin 	if (p_nand_info->id0 == MID_GIGADEV) {
1010629111d3SJon Lin 		sfc_nand_read_cache(addr, (u32 *)sfc_nand_dev.recheck_buffer, 0, data_area_size);
1011c797b43aSJon Lin 		if (memcmp(sfc_nand_dev.recheck_buffer, p_page_buf, data_area_size)) {
1012c797b43aSJon Lin 			rkflash_print_error("%s %x cache bitflip\n", __func__, addr);
1013c797b43aSJon Lin 			mdelay(1000);
1014c797b43aSJon Lin 			sfc_request(&op, plane, p_page_buf, page_size);
1015c797b43aSJon Lin 		}
1016c797b43aSJon Lin 	}
1017629111d3SJon Lin 
101858463f4dSJon Lin 	op.sfcmd.d32 = 0;
1019f28847a8SJon Lin 	op.sfcmd.b.cmd = 0x10;
102058463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_24BITS;
102158463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
102258463f4dSJon Lin 
102358463f4dSJon Lin 	op.sfctrl.d32 = 0;
102458463f4dSJon Lin 	ret = sfc_request(&op, addr, p_page_buf, 0);
1025f28847a8SJon Lin 
1026ba0501acSDingqiang Lin 	if (ret != SFC_OK)
1027ba0501acSDingqiang Lin 		return ret;
1028f28847a8SJon Lin 
1029ba0501acSDingqiang Lin 	ret = sfc_nand_wait_busy(&status, 1000 * 1000);
1030ba0501acSDingqiang Lin 	if (status & (1 << 3))
1031ba0501acSDingqiang Lin 		return SFC_NAND_PROG_ERASE_ERROR;
1032c84f0ed8SJon Lin 
1033ba0501acSDingqiang Lin 	return ret;
1034ba0501acSDingqiang Lin }
1035ba0501acSDingqiang Lin 
1036c84f0ed8SJon Lin u32 sfc_nand_prog_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare)
1037c84f0ed8SJon Lin {
1038c84f0ed8SJon Lin 	int ret;
1039c84f0ed8SJon Lin 	u32 sec_per_page = p_nand_info->sec_per_page;
1040c84f0ed8SJon Lin 	u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE;
1041a6fcac41SJon Lin 	struct nand_mega_area *meta = &p_nand_info->meta;
1042c84f0ed8SJon Lin 
1043c84f0ed8SJon Lin 	memcpy(gp_page_buf, p_data, data_size);
1044c84f0ed8SJon Lin 	memset(&gp_page_buf[data_size / 4], 0xff, sec_per_page * 16);
1045a6fcac41SJon Lin 	gp_page_buf[(data_size + meta->off0) / 4] = p_spare[0];
1046a6fcac41SJon Lin 	gp_page_buf[(data_size + meta->off1) / 4] = p_spare[1];
1047f28847a8SJon Lin 
1048c84f0ed8SJon Lin 	if (sec_per_page == 8) {
1049a6fcac41SJon Lin 		gp_page_buf[(data_size + meta->off2) / 4] = p_spare[2];
1050a6fcac41SJon Lin 		gp_page_buf[(data_size + meta->off3) / 4] = p_spare[3];
1051c84f0ed8SJon Lin 	}
1052f28847a8SJon Lin 
1053c84f0ed8SJon Lin 	ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf);
1054c84f0ed8SJon Lin 
1055c84f0ed8SJon Lin 	return ret;
1056c84f0ed8SJon Lin }
1057c84f0ed8SJon Lin 
1058a80fd396SJon Lin u32 sfc_nand_read(u32 row, u32 *p_page_buf, u32 column, u32 len)
1059ba0501acSDingqiang Lin {
1060ba0501acSDingqiang Lin 	int ret;
1061415cf080Sjon.lin 	u32 plane;
106258463f4dSJon Lin 	struct rk_sfc_op op;
10636281205aSDingqiang Lin 	u32 ecc_result;
1064a6fcac41SJon Lin 	u8 status;
1065ba0501acSDingqiang Lin 
106658463f4dSJon Lin 	op.sfcmd.d32 = 0;
1067f28847a8SJon Lin 	op.sfcmd.b.cmd = 0x13;
106858463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
106958463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_24BITS;
107058463f4dSJon Lin 
107158463f4dSJon Lin 	op.sfctrl.d32 = 0;
107258463f4dSJon Lin 
1073a80fd396SJon Lin 	sfc_request(&op, row, p_page_buf, 0);
1074f28847a8SJon Lin 
1075ba0501acSDingqiang Lin 	if (sfc_nand_dev.read_lines == DATA_LINES_X4 &&
107625098c06SDingqiang Lin 	    p_nand_info->feature & FEA_SOFT_QOP_BIT &&
107725098c06SDingqiang Lin 	    sfc_get_version() < SFC_VER_3)
1078ba0501acSDingqiang Lin 		sfc_nand_rw_preset();
1079ba0501acSDingqiang Lin 
1080a6fcac41SJon Lin 	sfc_nand_wait_busy(&status, 1000 * 1000);
1081e5e85009SJon Lin 	if (sfc_nand_dev.manufacturer == 0x01 && status)
1082e5e85009SJon Lin 		sfc_nand_wait_busy(&status, 1000 * 1000);
1083e5e85009SJon Lin 
1084a6fcac41SJon Lin 	ecc_result = p_nand_info->ecc_status();
1085a6fcac41SJon Lin 
108658463f4dSJon Lin 	op.sfcmd.d32 = 0;
108758463f4dSJon Lin 	op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd;
1088a80fd396SJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
1089a80fd396SJon Lin 	op.sfcmd.b.dummybits = 8;
109058463f4dSJon Lin 
109158463f4dSJon Lin 	op.sfctrl.d32 = 0;
109258463f4dSJon Lin 	op.sfctrl.b.datalines = sfc_nand_dev.read_lines;
1093a80fd396SJon Lin 	op.sfctrl.b.addrbits = 16;
1094ba0501acSDingqiang Lin 
1095a80fd396SJon Lin 	plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0;
1096a80fd396SJon Lin 	ret = sfc_request(&op, plane | column, p_page_buf, len);
1097a80fd396SJon Lin 	rkflash_print_dio("%s %x %x\n", __func__, row, p_page_buf[0]);
1098c84f0ed8SJon Lin 
1099c84f0ed8SJon Lin 	if (ret != SFC_OK)
1100f28847a8SJon Lin 		return SFC_NAND_HW_ERROR;
1101c84f0ed8SJon Lin 
1102c84f0ed8SJon Lin 	return ecc_result;
1103c84f0ed8SJon Lin }
1104c84f0ed8SJon Lin 
1105a80fd396SJon Lin u32 sfc_nand_read_page_raw(u8 cs, u32 addr, u32 *p_page_buf)
1106a80fd396SJon Lin {
1107a80fd396SJon Lin 	u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page;
1108a80fd396SJon Lin 
1109a80fd396SJon Lin 	return sfc_nand_read(addr, p_page_buf, 0, page_size);
1110a80fd396SJon Lin }
1111a80fd396SJon Lin 
1112c84f0ed8SJon Lin u32 sfc_nand_read_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare)
1113c84f0ed8SJon Lin {
111458463f4dSJon Lin 	u32 ret;
1115c84f0ed8SJon Lin 	u32 sec_per_page = p_nand_info->sec_per_page;
1116c84f0ed8SJon Lin 	u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE;
1117a6fcac41SJon Lin 	struct nand_mega_area *meta = &p_nand_info->meta;
1118c84f0ed8SJon Lin 
1119c84f0ed8SJon Lin 	ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf);
1120f25e3cafSJon Lin 	memcpy(p_data, gp_page_buf, data_size);
1121a6fcac41SJon Lin 	p_spare[0] = gp_page_buf[(data_size + meta->off0) / 4];
1122a6fcac41SJon Lin 	p_spare[1] = gp_page_buf[(data_size + meta->off1) / 4];
1123f28847a8SJon Lin 
1124f25e3cafSJon Lin 	if (p_nand_info->sec_per_page == 8) {
1125a6fcac41SJon Lin 		p_spare[2] = gp_page_buf[(data_size + meta->off2) / 4];
1126a6fcac41SJon Lin 		p_spare[3] = gp_page_buf[(data_size + meta->off3) / 4];
1127f25e3cafSJon Lin 	}
1128ba0501acSDingqiang Lin 
1129f28847a8SJon Lin 	if (ret == SFC_NAND_HW_ERROR)
1130f28847a8SJon Lin 		ret = SFC_NAND_ECC_ERROR;
1131f28847a8SJon Lin 
1132c84f0ed8SJon Lin 	if (ret != SFC_NAND_ECC_OK) {
1133c84f0ed8SJon Lin 		rkflash_print_error("%s[0x%x], ret=0x%x\n", __func__, addr, ret);
1134f28847a8SJon Lin 
1135ba0501acSDingqiang Lin 		if (p_data)
1136c84f0ed8SJon Lin 			rkflash_print_hex("data:", p_data, 4, 8);
1137f28847a8SJon Lin 
1138ba0501acSDingqiang Lin 		if (p_spare)
1139c84f0ed8SJon Lin 			rkflash_print_hex("spare:", p_spare, 4, 2);
1140ba0501acSDingqiang Lin 	}
1141f25e3cafSJon Lin 
1142c84f0ed8SJon Lin 	return ret;
1143ba0501acSDingqiang Lin }
1144ba0501acSDingqiang Lin 
1145c84f0ed8SJon Lin u32 sfc_nand_check_bad_block(u8 cs, u32 addr)
1146c84f0ed8SJon Lin {
1147c84f0ed8SJon Lin 	u32 ret;
1148c84f0ed8SJon Lin 	u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE;
1149a80fd396SJon Lin 	u32 marker = 0;
1150c84f0ed8SJon Lin 
1151a80fd396SJon Lin 	ret = sfc_nand_read(addr, &marker, data_size, 2);
1152f28847a8SJon Lin 
1153f28847a8SJon Lin 	/* unify with mtd framework */
1154629111d3SJon Lin 	if (ret == SFC_NAND_ECC_ERROR || (u16)marker != 0xffff)
1155a80fd396SJon Lin 		rkflash_print_error("%s page= %x ret= %x spare= %x\n",
1156a80fd396SJon Lin 				    __func__, addr, ret, marker);
1157f28847a8SJon Lin 
1158c84f0ed8SJon Lin 	/* Original bad block */
1159a80fd396SJon Lin 	if ((u16)marker != 0xffff)
1160c84f0ed8SJon Lin 		return true;
1161c84f0ed8SJon Lin 
1162c84f0ed8SJon Lin 	return false;
1163c84f0ed8SJon Lin }
1164c84f0ed8SJon Lin 
1165c84f0ed8SJon Lin u32 sfc_nand_mark_bad_block(u8 cs, u32 addr)
1166c84f0ed8SJon Lin {
1167c84f0ed8SJon Lin 	u32 ret;
1168c84f0ed8SJon Lin 	u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE;
1169c84f0ed8SJon Lin 
1170c84f0ed8SJon Lin 	ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf);
1171f28847a8SJon Lin 
1172c84f0ed8SJon Lin 	if (ret)
1173c84f0ed8SJon Lin 		return SFC_NAND_HW_ERROR;
1174f28847a8SJon Lin 
1175c84f0ed8SJon Lin 	gp_page_buf[data_size / 4] = 0x0;
1176c84f0ed8SJon Lin 	ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf);
1177f28847a8SJon Lin 
1178c84f0ed8SJon Lin 	if (ret)
1179c84f0ed8SJon Lin 		return SFC_NAND_HW_ERROR;
1180c84f0ed8SJon Lin 
1181c84f0ed8SJon Lin 	return ret;
1182c84f0ed8SJon Lin }
1183c84f0ed8SJon Lin 
1184c84f0ed8SJon Lin int sfc_nand_read_id(u8 *data)
1185ba0501acSDingqiang Lin {
1186ba0501acSDingqiang Lin 	int ret;
118758463f4dSJon Lin 	struct rk_sfc_op op;
1188ba0501acSDingqiang Lin 
118958463f4dSJon Lin 	op.sfcmd.d32 = 0;
119058463f4dSJon Lin 	op.sfcmd.b.cmd = CMD_READ_JEDECID;
119158463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
1192ba0501acSDingqiang Lin 
119358463f4dSJon Lin 	op.sfctrl.d32 = 0;
119458463f4dSJon Lin 	op.sfctrl.b.addrbits = 8;
119558463f4dSJon Lin 
119658463f4dSJon Lin 	ret = sfc_request(&op, 0, data, 3);
1197ba0501acSDingqiang Lin 
1198ba0501acSDingqiang Lin 	return ret;
1199ba0501acSDingqiang Lin }
1200ba0501acSDingqiang Lin 
1201ba0501acSDingqiang Lin /*
1202ba0501acSDingqiang Lin  * Read the 1st page's 1st byte of a phy_blk
1203ba0501acSDingqiang Lin  * If not FF, it's bad blk
1204ba0501acSDingqiang Lin  */
1205ba0501acSDingqiang Lin static int sfc_nand_get_bad_block_list(u16 *table, u32 die)
1206ba0501acSDingqiang Lin {
1207ba0501acSDingqiang Lin 	u32 bad_cnt, page;
1208ba0501acSDingqiang Lin 	u32 blk_per_die;
12092ac88c1bSJon Lin 	u16 blk;
1210ba0501acSDingqiang Lin 
1211c84f0ed8SJon Lin 	rkflash_print_info("%s\n", __func__);
1212c84f0ed8SJon Lin 
1213ba0501acSDingqiang Lin 	bad_cnt = 0;
1214ba0501acSDingqiang Lin 	blk_per_die = p_nand_info->plane_per_die *
1215ba0501acSDingqiang Lin 		      p_nand_info->blk_per_plane;
1216f28847a8SJon Lin 
1217ba0501acSDingqiang Lin 	for (blk = 0; blk < blk_per_die; blk++) {
1218ba0501acSDingqiang Lin 		page = (blk + blk_per_die * die) *
1219ba0501acSDingqiang Lin 		       p_nand_info->page_per_blk;
1220ba0501acSDingqiang Lin 
12212ac88c1bSJon Lin 		if (sfc_nand_check_bad_block(die, page)) {
1222ba0501acSDingqiang Lin 			table[bad_cnt++] = blk;
1223c84f0ed8SJon Lin 			rkflash_print_error("die[%d], bad_blk[%d]\n", die, blk);
1224ba0501acSDingqiang Lin 		}
1225ba0501acSDingqiang Lin 	}
1226f28847a8SJon Lin 
1227ba0501acSDingqiang Lin 	return (int)bad_cnt;
1228ba0501acSDingqiang Lin }
1229ba0501acSDingqiang Lin 
1230c84f0ed8SJon Lin void sfc_nand_ftl_ops_init(void)
1231ba0501acSDingqiang Lin {
1232ba0501acSDingqiang Lin 	/* para init */
1233ba0501acSDingqiang Lin 	g_nand_phy_info.nand_type	= 1;
1234ba0501acSDingqiang Lin 	g_nand_phy_info.die_num		= 1;
1235ba0501acSDingqiang Lin 	g_nand_phy_info.plane_per_die	= p_nand_info->plane_per_die;
1236ba0501acSDingqiang Lin 	g_nand_phy_info.blk_per_plane	= p_nand_info->blk_per_plane;
1237ba0501acSDingqiang Lin 	g_nand_phy_info.page_per_blk	= p_nand_info->page_per_blk;
1238ba0501acSDingqiang Lin 	g_nand_phy_info.page_per_slc_blk = p_nand_info->page_per_blk;
1239c84f0ed8SJon Lin 	g_nand_phy_info.byte_per_sec	= SFC_NAND_SECTOR_SIZE;
1240ba0501acSDingqiang Lin 	g_nand_phy_info.sec_per_page	= p_nand_info->sec_per_page;
1241ba0501acSDingqiang Lin 	g_nand_phy_info.sec_per_blk	= p_nand_info->sec_per_page *
1242ba0501acSDingqiang Lin 					  p_nand_info->page_per_blk;
1243ba0501acSDingqiang Lin 	g_nand_phy_info.reserved_blk	= 8;
1244ba0501acSDingqiang Lin 	g_nand_phy_info.blk_per_die	= p_nand_info->plane_per_die *
1245ba0501acSDingqiang Lin 					  p_nand_info->blk_per_plane;
1246ba0501acSDingqiang Lin 	g_nand_phy_info.ecc_bits	= p_nand_info->max_ecc_bits;
1247ba0501acSDingqiang Lin 
1248ba0501acSDingqiang Lin 	/* driver register */
1249ba0501acSDingqiang Lin 	g_nand_ops.get_bad_blk_list	= sfc_nand_get_bad_block_list;
1250ba0501acSDingqiang Lin 	g_nand_ops.erase_blk		= sfc_nand_erase_block;
1251ba0501acSDingqiang Lin 	g_nand_ops.prog_page		= sfc_nand_prog_page;
1252ba0501acSDingqiang Lin 	g_nand_ops.read_page		= sfc_nand_read_page;
125357d18453Sjon.lin 	g_nand_ops.bch_sel		= NULL;
1254ba0501acSDingqiang Lin }
1255ba0501acSDingqiang Lin 
1256a6fcac41SJon Lin static int sfc_nand_enable_QE(void)
1257ba0501acSDingqiang Lin {
1258ba0501acSDingqiang Lin 	int ret = SFC_OK;
1259ba0501acSDingqiang Lin 	u8 status;
1260ba0501acSDingqiang Lin 
1261f28847a8SJon Lin 	ret = sfc_nand_read_feature(0xB0, &status);
1262ba0501acSDingqiang Lin 
1263ba0501acSDingqiang Lin 	if (ret != SFC_OK)
1264ba0501acSDingqiang Lin 		return ret;
1265ba0501acSDingqiang Lin 
1266f28847a8SJon Lin 	if (status & 1)   /* is QE bit set */
1267ba0501acSDingqiang Lin 		return SFC_OK;
1268ba0501acSDingqiang Lin 
1269f28847a8SJon Lin 	status |= 1;
1270ba0501acSDingqiang Lin 
1271f28847a8SJon Lin 	return sfc_nand_write_feature(0xB0, status);
1272ba0501acSDingqiang Lin }
1273ba0501acSDingqiang Lin 
1274ba0501acSDingqiang Lin u32 sfc_nand_init(void)
1275ba0501acSDingqiang Lin {
1276c84f0ed8SJon Lin 	u8 status, id_byte[8];
1277ba0501acSDingqiang Lin 
1278c84f0ed8SJon Lin 	sfc_nand_read_id(id_byte);
1279c84f0ed8SJon Lin 	rkflash_print_error("sfc_nand id: %x %x %x\n",
1280ba0501acSDingqiang Lin 			    id_byte[0], id_byte[1], id_byte[2]);
1281f28847a8SJon Lin 
1282ba0501acSDingqiang Lin 	if (id_byte[0] == 0xFF || id_byte[0] == 0x00)
128358463f4dSJon Lin 		return (u32)FTL_NO_FLASH;
1284ba0501acSDingqiang Lin 
1285a6fcac41SJon Lin 	p_nand_info = sfc_nand_get_info(id_byte);
1286f28847a8SJon Lin 
128745292245SJon Lin 	if (!p_nand_info) {
128845292245SJon Lin 		pr_err("The device not support yet!\n");
128945292245SJon Lin 
129058463f4dSJon Lin 		return (u32)FTL_UNSUPPORTED_FLASH;
129145292245SJon Lin 	}
1292ba0501acSDingqiang Lin 
1293ba0501acSDingqiang Lin 	sfc_nand_dev.manufacturer = id_byte[0];
1294ba0501acSDingqiang Lin 	sfc_nand_dev.mem_type = id_byte[1];
1295c84f0ed8SJon Lin 	sfc_nand_dev.capacity = p_nand_info->density;
1296c84f0ed8SJon Lin 	sfc_nand_dev.block_size = p_nand_info->page_per_blk * p_nand_info->sec_per_page;
1297c84f0ed8SJon Lin 	sfc_nand_dev.page_size = p_nand_info->sec_per_page;
1298ba0501acSDingqiang Lin 
1299ba0501acSDingqiang Lin 	/* disable block lock */
1300ba0501acSDingqiang Lin 	sfc_nand_write_feature(0xA0, 0);
1301ba0501acSDingqiang Lin 	sfc_nand_dev.read_lines = DATA_LINES_X1;
1302ba0501acSDingqiang Lin 	sfc_nand_dev.prog_lines = DATA_LINES_X1;
1303f28847a8SJon Lin 	sfc_nand_dev.page_read_cmd = 0x03;
1304f28847a8SJon Lin 	sfc_nand_dev.page_prog_cmd = 0x02;
1305629111d3SJon Lin 	sfc_nand_dev.recheck_buffer = ftl_malloc(SFC_NAND_PAGE_MAX_SIZE);
1306629111d3SJon Lin 	if (!sfc_nand_dev.recheck_buffer) {
1307629111d3SJon Lin 		rkflash_print_error("%s recheck_buffer alloc failed\n", __func__);
1308629111d3SJon Lin 		return -1;
1309629111d3SJon Lin 	}
1310f28847a8SJon Lin 
1311ba0501acSDingqiang Lin 	if (p_nand_info->feature & FEA_4BIT_READ) {
1312f28847a8SJon Lin 		if ((p_nand_info->has_qe_bits && sfc_nand_enable_QE() == SFC_OK) ||
1313f28847a8SJon Lin 		    !p_nand_info->has_qe_bits) {
1314ba0501acSDingqiang Lin 			sfc_nand_dev.read_lines = DATA_LINES_X4;
1315f28847a8SJon Lin 			sfc_nand_dev.page_read_cmd = 0x6b;
1316ba0501acSDingqiang Lin 		}
1317ba0501acSDingqiang Lin 	}
1318ba0501acSDingqiang Lin 
1319ba0501acSDingqiang Lin 	if (p_nand_info->feature & FEA_4BIT_PROG &&
1320ba0501acSDingqiang Lin 	    sfc_nand_dev.read_lines == DATA_LINES_X4) {
1321ba0501acSDingqiang Lin 		sfc_nand_dev.prog_lines = DATA_LINES_X4;
1322f28847a8SJon Lin 		sfc_nand_dev.page_prog_cmd = 0x32;
1323ba0501acSDingqiang Lin 	}
1324ba0501acSDingqiang Lin 
1325ba0501acSDingqiang Lin 	sfc_nand_read_feature(0xA0, &status);
1326c84f0ed8SJon Lin 	rkflash_print_info("sfc_nand A0 = 0x%x\n", status);
1327ba0501acSDingqiang Lin 	sfc_nand_read_feature(0xB0, &status);
1328c84f0ed8SJon Lin 	rkflash_print_info("sfc_nand B0 = 0x%x\n", status);
1329c84f0ed8SJon Lin 	rkflash_print_info("read_lines = %x\n", sfc_nand_dev.read_lines);
1330c84f0ed8SJon Lin 	rkflash_print_info("prog_lines = %x\n", sfc_nand_dev.prog_lines);
1331c84f0ed8SJon Lin 	rkflash_print_info("page_read_cmd = %x\n", sfc_nand_dev.page_read_cmd);
1332c84f0ed8SJon Lin 	rkflash_print_info("page_prog_cmd = %x\n", sfc_nand_dev.page_prog_cmd);
1333ba0501acSDingqiang Lin 
1334ba0501acSDingqiang Lin 	return SFC_OK;
1335ba0501acSDingqiang Lin }
1336ba0501acSDingqiang Lin 
1337c84f0ed8SJon Lin void sfc_nand_deinit(void)
1338ba0501acSDingqiang Lin {
1339c84f0ed8SJon Lin 	/* to-do */
1340629111d3SJon Lin 	kfree(sfc_nand_dev.recheck_buffer);
1341ba0501acSDingqiang Lin }
1342c84f0ed8SJon Lin 
1343c84f0ed8SJon Lin struct SFNAND_DEV *sfc_nand_get_private_dev(void)
1344c84f0ed8SJon Lin {
1345c84f0ed8SJon Lin 	return &sfc_nand_dev;
1346c84f0ed8SJon Lin }
1347c84f0ed8SJon Lin 
1348