xref: /rk3399_rockchip-uboot/drivers/rkflash/sfc_nand.c (revision f5e7a59f42cf166aff4be45264ca44814bde7d68)
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);
27f28847a8SJon Lin 
28ba0501acSDingqiang Lin static struct nand_info spi_nand_tbl[] = {
29ba0501acSDingqiang Lin 	/* TC58CVG0S0HxAIx */
30b833c879SJon Lin 	{ 0x98, 0xC2, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
31ba0501acSDingqiang Lin 	/* TC58CVG1S0HxAIx */
32b833c879SJon Lin 	{ 0x98, 0xCB, 0x00, 4, 0x40, 2, 1024, 0x00, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
33a6fcac41SJon Lin 	/* TC58CVG2S0HRAIJ */
34b833c879SJon Lin 	{ 0x98, 0xED, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 0, { 0x04, 0x0C, 0x08, 0x10 }, &sfc_nand_get_ecc_status0 },
35a6fcac41SJon Lin 	/* TC58CVG1S3HRAIJ */
36b833c879SJon Lin 	{ 0x98, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
37a6fcac41SJon Lin 	/* TC58CVG0S3HRAIJ */
38b833c879SJon Lin 	{ 0x98, 0xE2, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
39f28847a8SJon Lin 
40f28847a8SJon Lin 	/* MX35LF1GE4AB */
41b833c879SJon Lin 	{ 0xC2, 0x12, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
42f28847a8SJon Lin 	/* MX35LF2GE4AB */
43b833c879SJon Lin 	{ 0xC2, 0x22, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
44f28847a8SJon Lin 	/* MX35LF2GE4AD */
45b833c879SJon Lin 	{ 0xC2, 0x26, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
46f28847a8SJon Lin 	/* MX35LF4GE4AD */
47362b1be1SJon Lin 	{ 0xC2, 0x37, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status0 },
48362b1be1SJon Lin 	/* MX35UF1GE4AC */
49362b1be1SJon Lin 	{ 0xC2, 0x92, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
50362b1be1SJon Lin 	/* MX35UF2GE4AC */
51362b1be1SJon Lin 	{ 0xC2, 0xA2, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
52*f5e7a59fSJon Lin 	/* MX35UF1GE4AD */
53*f5e7a59fSJon Lin 	{ 0xC2, 0x96, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
54*f5e7a59fSJon Lin 	/* MX35UF2GE4AD */
55*f5e7a59fSJon Lin 	{ 0xC2, 0xA6, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
56*f5e7a59fSJon Lin 	/* MX35UF4GE4AD */
57*f5e7a59fSJon Lin 	{ 0xC2, 0xB7, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status0 },
58f28847a8SJon Lin 
59f28847a8SJon Lin 	/* GD5F1GQ4UAYIG */
60b833c879SJon Lin 	{ 0xC8, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
61f28847a8SJon Lin 	/* GD5F1GQ4RB9IGR */
62b833c879SJon Lin 	{ 0xC8, 0xD1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
63f28847a8SJon Lin 	/* GD5F2GQ40BY2GR */
64b833c879SJon Lin 	{ 0xC8, 0xD2, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
65f28847a8SJon Lin 	/* GD5F1GQ5UEYIG */
66b833c879SJon Lin 	{ 0xC8, 0x51, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
67f28847a8SJon Lin 	/* GD5F2GQ5UEYIG */
68b833c879SJon Lin 	{ 0xC8, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
69f28847a8SJon Lin 	/* GD5F1GQ4R */
70b833c879SJon Lin 	{ 0xC8, 0xC1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
71362b1be1SJon Lin 	/* GD5F4GQ6RExxG 1*4096 */
72d4db0b8dSJon Lin 	{ 0xC8, 0x45, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status2 },
73362b1be1SJon Lin 	/* GD5F4GQ6UExxG 1*4096 */
74d4db0b8dSJon Lin 	{ 0xC8, 0x55, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status2 },
758a654f32SJon Lin 	/* GD5F1GQ4UExxH */
768a654f32SJon Lin 	{ 0xC8, 0xD9, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
77bf620bf6SJon Lin 	/* GD5F1GQ5REYIG */
78bf620bf6SJon Lin 	{ 0xC8, 0x41, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
79bf620bf6SJon Lin 	/* GD5F2GQ5REYIG */
80bf620bf6SJon Lin 	{ 0xC8, 0x42, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
81bf620bf6SJon Lin 	/* GD5F2GM7RxG */
82bf620bf6SJon Lin 	{ 0xC8, 0x82, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
83bf620bf6SJon Lin 	/* GD5F2GM7UxG */
84bf620bf6SJon Lin 	{ 0xC8, 0x92, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
8545292245SJon Lin 	/* GD5F1GM7UxG */
8645292245SJon Lin 	{ 0xC8, 0x91, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
87d4db0b8dSJon Lin 	/* GD5F4GQ4UAYIG 1*4096 */
88d4db0b8dSJon Lin 	{ 0xC8, 0xF4, 0x00, 4, 0x40, 2, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status0 },
89f28847a8SJon Lin 
90f28847a8SJon Lin 	/* W25N01GV */
91b833c879SJon Lin 	{ 0xEF, 0xAA, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 },
92b833c879SJon Lin 	/* W25N02KVZEIR */
93b833c879SJon Lin 	{ 0xEF, 0xAA, 0x22, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status0 },
94629111d3SJon Lin 	/* W25N04KVZEIR */
95629111d3SJon Lin 	{ 0xEF, 0xAA, 0x23, 4, 0x40, 1, 4096, 0x4C, 20, 0x8, 0, { 0x04, 0x14, 0x24, 0x34 }, &sfc_nand_get_ecc_status0 },
96f28847a8SJon Lin 	/* W25N01GW */
977bdae1e3SJon Lin 	{ 0xEF, 0xBA, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 },
987bdae1e3SJon Lin 	/* W25N02KW */
997bdae1e3SJon Lin 	{ 0xEF, 0xBA, 0x22, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status0 },
1008a654f32SJon Lin 	/* W25N512GVEIG */
1018a654f32SJon Lin 	{ 0xEF, 0xAA, 0x20, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 },
102*f5e7a59fSJon Lin 	/* W25N01KV */
103*f5e7a59fSJon Lin 	{ 0xEF, 0xAE, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
104f28847a8SJon Lin 
105f28847a8SJon Lin 	/* HYF2GQ4UAACAE */
106b833c879SJon Lin 	{ 0xC9, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
107f28847a8SJon Lin 	/* HYF1GQ4UDACAE */
108b833c879SJon Lin 	{ 0xC9, 0x21, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
109f28847a8SJon Lin 	/* HYF1GQ4UPACAE */
110b833c879SJon Lin 	{ 0xC9, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
111f28847a8SJon Lin 	/* HYF2GQ4UDACAE */
112b833c879SJon Lin 	{ 0xC9, 0x22, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
113f28847a8SJon Lin 	/* HYF2GQ4UHCCAE */
114b833c879SJon Lin 	{ 0xC9, 0x5A, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
115f28847a8SJon Lin 	/* HYF4GQ4UAACBE */
116b833c879SJon Lin 	{ 0xC9, 0xD4, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x4, 1, { 0x20, 0x40, 0x24, 0x44 }, &sfc_nand_get_ecc_status0 },
117f28847a8SJon Lin 
118f28847a8SJon Lin 	/* FS35ND01G-S1 */
119b833c879SJon Lin 	{ 0xCD, 0xB1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
120f28847a8SJon Lin 	/* FS35ND02G-S2 */
121b833c879SJon Lin 	{ 0xCD, 0xA2, 0x00, 4, 0x40, 1, 2048, 0x00, 19, 0x4, 0, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
12258463f4dSJon Lin 	/* FS35ND01G-S1Y2 */
123b833c879SJon Lin 	{ 0xCD, 0xEA, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
124f1b20f5aSJon Lin 	/* FS35ND02G-S3Y2 */
125b833c879SJon Lin 	{ 0xCD, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
126f28847a8SJon Lin 	/* FS35ND04G-S2Y2 1*4096 */
127b833c879SJon Lin 	{ 0xCD, 0xEC, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
128bf620bf6SJon Lin 	/* F35SQA001G */
129bf620bf6SJon Lin 	{ 0xCD, 0x71, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
13045292245SJon Lin 	/* F35SQA002G */
13145292245SJon Lin 	{ 0xCD, 0x72, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
132d4db0b8dSJon Lin 	/* F35SQA512M */
133d4db0b8dSJon Lin 	{ 0xCD, 0x70, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
134d4db0b8dSJon Lin 	/* F35UQA512M */
135*f5e7a59fSJon Lin 	{ 0xCD, 0x60, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
136f28847a8SJon Lin 
137f28847a8SJon Lin 	/* DS35Q1GA-IB */
138b833c879SJon Lin 	{ 0xE5, 0x71, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
139f28847a8SJon Lin 	/* DS35Q2GA-IB */
140b833c879SJon Lin 	{ 0xE5, 0x72, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
141f28847a8SJon Lin 	/* DS35M1GA-1B */
142b833c879SJon Lin 	{ 0xE5, 0x21, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
143bf620bf6SJon Lin 	/* DS35M2GA-IB */
144bf620bf6SJon Lin 	{ 0xE5, 0x22, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
145d4db0b8dSJon Lin 	/* DS35Q1GB-IB */
146d4db0b8dSJon Lin 	{ 0xE5, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
147629111d3SJon Lin 	/* DS35Q2GB-IB */
148629111d3SJon Lin 	{ 0xE5, 0xF2, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
149d4db0b8dSJon Lin 	/* DS35Q4GM */
150d4db0b8dSJon Lin 	{ 0xE5, 0xF4, 0x00, 4, 0x40, 2, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
151bf620bf6SJon Lin 	/* DS35M1GB-IB */
152bf620bf6SJon Lin 	{ 0xE5, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
153*f5e7a59fSJon Lin 	/* DS35Q12B-IB */
154*f5e7a59fSJon Lin 	{ 0xE5, 0xF5, 0x00, 4, 0x40, 1, 512, 0x0C, 17, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
155*f5e7a59fSJon Lin 	/* DS35M12B-IB */
156*f5e7a59fSJon Lin 	{ 0xE5, 0xA5, 0x00, 4, 0x40, 1, 512, 0x0C, 17, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
157f28847a8SJon Lin 
158f28847a8SJon Lin 	/* EM73C044VCC-H */
159b833c879SJon Lin 	{ 0xD5, 0x22, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
160f28847a8SJon Lin 	/* EM73D044VCE-H */
161b833c879SJon Lin 	{ 0xD5, 0x20, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
162f28847a8SJon Lin 	/* EM73E044SNA-G */
163b833c879SJon Lin 	{ 0xD5, 0x03, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x28, 0x08, 0x2C }, &sfc_nand_get_ecc_status0 },
164629111d3SJon Lin 	/* EM73C044VCF-H */
165629111d3SJon Lin 	{ 0xD5, 0x25, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
166f28847a8SJon Lin 
167f28847a8SJon Lin 	/* XT26G02A */
168362b1be1SJon Lin 	{ 0x0B, 0xE2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
169f28847a8SJon Lin 	/* XT26G01A */
170362b1be1SJon Lin 	{ 0x0B, 0xE1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
171f28847a8SJon Lin 	/* XT26G04A */
172362b1be1SJon Lin 	{ 0x0B, 0xE3, 0x00, 4, 0x80, 1, 2048, 0x4C, 20, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
173f28847a8SJon Lin 	/* XT26G01B */
174362b1be1SJon Lin 	{ 0x0B, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
175f28847a8SJon Lin 	/* XT26G02B */
176362b1be1SJon Lin 	{ 0x0B, 0xF2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
177362b1be1SJon Lin 	/* XT26G01C */
178362b1be1SJon Lin 	{ 0x0B, 0x11, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 },
179362b1be1SJon Lin 	/* XT26G02C */
180362b1be1SJon Lin 	{ 0x0B, 0x12, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 },
181362b1be1SJon Lin 	/* XT26G04C */
182362b1be1SJon Lin 	{ 0x0B, 0x13, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status7 },
183629111d3SJon Lin 	/* XT26G11C */
184629111d3SJon Lin 	{ 0x0B, 0x15, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
185a80fd396SJon Lin 
186362b1be1SJon Lin 	/* MT29F2G01ABA, XT26G02E, F50L2G41XA */
187629111d3SJon Lin 	{ 0x2C, 0x24, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x8, 0, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
188629111d3SJon Lin 	/* MT29F1G01ABA, F50L1G41XA */
189629111d3SJon Lin 	{ 0x2C, 0x14, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 0, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
190a80fd396SJon Lin 
191a80fd396SJon Lin 	/* FM25S01 */
192b833c879SJon Lin 	{ 0xA1, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x00, 0x04, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
193a80fd396SJon Lin 	/* FM25S01A */
194b833c879SJon Lin 	{ 0xA1, 0xE4, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
195a80fd396SJon Lin 	/* FM25S02A */
196b833c879SJon Lin 	{ 0xA1, 0xE5, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
1977bdae1e3SJon Lin 	/* FM25LS01 */
1987bdae1e3SJon Lin 	{ 0xA1, 0xA5, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
199f28847a8SJon Lin 
200f28847a8SJon Lin 	/* IS37SML01G1 */
201b833c879SJon Lin 	{ 0xC8, 0x21, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x1, 0, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
202f28847a8SJon Lin 	/* F50L1G41LB */
203b833c879SJon Lin 	{ 0xC8, 0x01, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
204f28847a8SJon Lin 	/* ATO25D1GA */
205b833c879SJon Lin 	{ 0x9B, 0x12, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x1, 1, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
206362b1be1SJon Lin 	/* BWJX08K-2Gb */
207362b1be1SJon Lin 	{ 0xBC, 0xB3, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x10, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
208629111d3SJon Lin 	/* JS28U1GQSCAHG-83 */
209629111d3SJon Lin 	{ 0xBF, 0x21, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x4, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status8 },
2108a654f32SJon Lin 	/* SGM7000I-S24W1GH */
2118a654f32SJon Lin 	{ 0xEA, 0xC1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
212bf620bf6SJon Lin 	/* TX25G01 */
213bf620bf6SJon Lin 	{ 0xA1, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status8 },
214*f5e7a59fSJon Lin 	/* ANV1GCP0CLG */
215*f5e7a59fSJon Lin 	{ 0x01, 0x15, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status9 },
216*f5e7a59fSJon Lin 	/* S35ML02G3, ANV1GCP0CLG */
217*f5e7a59fSJon Lin 	{ 0x01, 0x25, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status9 },
218d4db0b8dSJon Lin 	/* S35ML04G3 */
219*f5e7a59fSJon Lin 	{ 0x01, 0x35, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 0, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status9 },
220ba0501acSDingqiang Lin };
221ba0501acSDingqiang Lin 
222ba0501acSDingqiang Lin static struct nand_info *p_nand_info;
223ba0501acSDingqiang Lin static u32 gp_page_buf[SFC_NAND_PAGE_MAX_SIZE / 4];
224ba0501acSDingqiang Lin static struct SFNAND_DEV sfc_nand_dev;
225ba0501acSDingqiang Lin 
226a6fcac41SJon Lin static struct nand_info *sfc_nand_get_info(u8 *nand_id)
227ba0501acSDingqiang Lin {
228ba0501acSDingqiang Lin 	u32 i;
229ba0501acSDingqiang Lin 
230ba0501acSDingqiang Lin 	for (i = 0; i < ARRAY_SIZE(spi_nand_tbl); i++) {
231b833c879SJon Lin 		if (spi_nand_tbl[i].id0 == nand_id[0] &&
232b833c879SJon Lin 		    spi_nand_tbl[i].id1 == nand_id[1]) {
233b833c879SJon Lin 			if (spi_nand_tbl[i].id2 &&
234b833c879SJon Lin 			    spi_nand_tbl[i].id2 != nand_id[2])
235b833c879SJon Lin 				continue;
236b833c879SJon Lin 
237ba0501acSDingqiang Lin 			return &spi_nand_tbl[i];
238ba0501acSDingqiang Lin 		}
239b833c879SJon Lin 	}
240f28847a8SJon Lin 
241ba0501acSDingqiang Lin 	return NULL;
242ba0501acSDingqiang Lin }
243ba0501acSDingqiang Lin 
244ba0501acSDingqiang Lin static int sfc_nand_write_en(void)
245ba0501acSDingqiang Lin {
246ba0501acSDingqiang Lin 	int ret;
24758463f4dSJon Lin 	struct rk_sfc_op op;
248ba0501acSDingqiang Lin 
24958463f4dSJon Lin 	op.sfcmd.d32 = 0;
25058463f4dSJon Lin 	op.sfcmd.b.cmd = CMD_WRITE_EN;
25158463f4dSJon Lin 
25258463f4dSJon Lin 	op.sfctrl.d32 = 0;
25358463f4dSJon Lin 
25458463f4dSJon Lin 	ret = sfc_request(&op, 0, NULL, 0);
255ba0501acSDingqiang Lin 	return ret;
256ba0501acSDingqiang Lin }
257ba0501acSDingqiang Lin 
258ba0501acSDingqiang Lin static int sfc_nand_rw_preset(void)
259ba0501acSDingqiang Lin {
260ba0501acSDingqiang Lin 	int ret;
26158463f4dSJon Lin 	struct rk_sfc_op op;
262ba0501acSDingqiang Lin 
26358463f4dSJon Lin 	op.sfcmd.d32 = 0;
264f28847a8SJon Lin 	op.sfcmd.b.cmd = 0xff;
265f28847a8SJon Lin 	op.sfcmd.b.cs = 2;
266ba0501acSDingqiang Lin 
26758463f4dSJon Lin 	op.sfctrl.d32 = 0;
26858463f4dSJon Lin 	op.sfctrl.b.datalines = 2;
269f28847a8SJon Lin 	op.sfctrl.b.cmdlines = 2;
270f28847a8SJon Lin 	op.sfctrl.b.addrlines = 2;
27158463f4dSJon Lin 
272f28847a8SJon Lin 	ret = sfc_request(&op, 0, NULL, 0);
273ba0501acSDingqiang Lin 	return ret;
274ba0501acSDingqiang Lin }
275ba0501acSDingqiang Lin 
276ba0501acSDingqiang Lin static int sfc_nand_read_feature(u8 addr, u8 *data)
277ba0501acSDingqiang Lin {
278ba0501acSDingqiang Lin 	int ret;
27958463f4dSJon Lin 	struct rk_sfc_op op;
280ba0501acSDingqiang Lin 
28158463f4dSJon Lin 	op.sfcmd.d32 = 0;
28258463f4dSJon Lin 	op.sfcmd.b.cmd = 0x0F;
28358463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
28458463f4dSJon Lin 
28558463f4dSJon Lin 	op.sfctrl.d32 = 0;
28658463f4dSJon Lin 	op.sfctrl.b.addrbits = 8;
28758463f4dSJon Lin 
288ba0501acSDingqiang Lin 	*data = 0;
289ba0501acSDingqiang Lin 
29058463f4dSJon Lin 	ret = sfc_request(&op, addr, data, 1);
291f28847a8SJon Lin 
292ba0501acSDingqiang Lin 	if (ret != SFC_OK)
293ba0501acSDingqiang Lin 		return ret;
294f28847a8SJon Lin 
295ba0501acSDingqiang Lin 	return SFC_OK;
296ba0501acSDingqiang Lin }
297ba0501acSDingqiang Lin 
298ba0501acSDingqiang Lin static int sfc_nand_write_feature(u32 addr, u8 status)
299ba0501acSDingqiang Lin {
300ba0501acSDingqiang Lin 	int ret;
30158463f4dSJon Lin 	struct rk_sfc_op op;
302ba0501acSDingqiang Lin 
303ba0501acSDingqiang Lin 	sfc_nand_write_en();
304ba0501acSDingqiang Lin 
30558463f4dSJon Lin 	op.sfcmd.d32 = 0;
30658463f4dSJon Lin 	op.sfcmd.b.cmd = 0x1F;
30758463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
30858463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
309ba0501acSDingqiang Lin 
31058463f4dSJon Lin 	op.sfctrl.d32 = 0;
31158463f4dSJon Lin 	op.sfctrl.b.addrbits = 8;
31258463f4dSJon Lin 
31358463f4dSJon Lin 	ret = sfc_request(&op, addr, &status, 1);
314f28847a8SJon Lin 
315ba0501acSDingqiang Lin 	if (ret != SFC_OK)
316ba0501acSDingqiang Lin 		return ret;
317f28847a8SJon Lin 
318ba0501acSDingqiang Lin 	return ret;
319ba0501acSDingqiang Lin }
320ba0501acSDingqiang Lin 
321ba0501acSDingqiang Lin static int sfc_nand_wait_busy(u8 *data, int timeout)
322ba0501acSDingqiang Lin {
323ba0501acSDingqiang Lin 	int ret;
324ba0501acSDingqiang Lin 	int i;
325ba0501acSDingqiang Lin 	u8 status;
326ba0501acSDingqiang Lin 
327ba0501acSDingqiang Lin 	*data = 0;
328f28847a8SJon Lin 
329ba0501acSDingqiang Lin 	for (i = 0; i < timeout; i++) {
330ba0501acSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
331f28847a8SJon Lin 
332ba0501acSDingqiang Lin 		if (ret != SFC_OK)
333ba0501acSDingqiang Lin 			return ret;
334f28847a8SJon Lin 
335ba0501acSDingqiang Lin 		*data = status;
336f28847a8SJon Lin 
337ba0501acSDingqiang Lin 		if (!(status & (1 << 0)))
338ba0501acSDingqiang Lin 			return SFC_OK;
339f28847a8SJon Lin 
340ba0501acSDingqiang Lin 		sfc_delay(1);
341ba0501acSDingqiang Lin 	}
342f28847a8SJon Lin 
343f28847a8SJon Lin 	return SFC_NAND_WAIT_TIME_OUT;
344ba0501acSDingqiang Lin }
345ba0501acSDingqiang Lin 
3466281205aSDingqiang Lin /*
3476281205aSDingqiang Lin  * ecc default:
348a6fcac41SJon Lin  * ecc bits: 0xC0[4,5]
349f28847a8SJon Lin  * 0b00, No bit errors were detected
350f28847a8SJon Lin  * 0b01, Bit errors were detected and corrected.
351f28847a8SJon Lin  * 0b10, Multiple bit errors were detected and not corrected.
352f28847a8SJon Lin  * 0b11, Bits errors were detected and corrected, bit error count
353362b1be1SJon Lin  *	reach the bit flip detection threshold
3546281205aSDingqiang Lin  */
355f28847a8SJon Lin static u32 sfc_nand_get_ecc_status0(void)
3566281205aSDingqiang Lin {
35758463f4dSJon Lin 	u32 ret;
3586281205aSDingqiang Lin 	u32 i;
3596281205aSDingqiang Lin 	u8 ecc;
3606281205aSDingqiang Lin 	u8 status;
3616281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
3626281205aSDingqiang Lin 
3636281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
3646281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
365f28847a8SJon Lin 
3666281205aSDingqiang Lin 		if (ret != SFC_OK)
3676281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
368f28847a8SJon Lin 
3696281205aSDingqiang Lin 		if (!(status & (1 << 0)))
3706281205aSDingqiang Lin 			break;
371f28847a8SJon Lin 
3726281205aSDingqiang Lin 		sfc_delay(1);
3736281205aSDingqiang Lin 	}
3746281205aSDingqiang Lin 
3756281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
3766281205aSDingqiang Lin 
3776281205aSDingqiang Lin 	if (ecc <= 1)
3786281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
3796281205aSDingqiang Lin 	else if (ecc == 2)
38058463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
3816281205aSDingqiang Lin 	else
3826281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
3836281205aSDingqiang Lin 
3846281205aSDingqiang Lin 	return ret;
3856281205aSDingqiang Lin }
3866281205aSDingqiang Lin 
3876281205aSDingqiang Lin /*
3886281205aSDingqiang Lin  * ecc spectial type1:
389a6fcac41SJon Lin  * ecc bits: 0xC0[4,5]
390f28847a8SJon Lin  * 0b00, No bit errors were detected;
391f28847a8SJon Lin  * 0b01, Bits errors were detected and corrected, bit error count
3926281205aSDingqiang Lin  *	may reach the bit flip detection threshold;
393f28847a8SJon Lin  * 0b10, Multiple bit errors were detected and not corrected;
394f28847a8SJon Lin  * 0b11, Reserved.
3956281205aSDingqiang Lin  */
396f28847a8SJon Lin static u32 sfc_nand_get_ecc_status1(void)
3976281205aSDingqiang Lin {
39858463f4dSJon Lin 	u32 ret;
3996281205aSDingqiang Lin 	u32 i;
4006281205aSDingqiang Lin 	u8 ecc;
4016281205aSDingqiang Lin 	u8 status;
4026281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
4036281205aSDingqiang Lin 
4046281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
4056281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
406f28847a8SJon Lin 
4076281205aSDingqiang Lin 		if (ret != SFC_OK)
4086281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
409f28847a8SJon Lin 
4106281205aSDingqiang Lin 		if (!(status & (1 << 0)))
4116281205aSDingqiang Lin 			break;
412f28847a8SJon Lin 
4136281205aSDingqiang Lin 		sfc_delay(1);
4146281205aSDingqiang Lin 	}
4156281205aSDingqiang Lin 
4166281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
4176281205aSDingqiang Lin 
4186281205aSDingqiang Lin 	if (ecc == 0)
4196281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
4206281205aSDingqiang Lin 	else if (ecc == 1)
4216281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
4226281205aSDingqiang Lin 	else
42358463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
4246281205aSDingqiang Lin 
4256281205aSDingqiang Lin 	return ret;
4266281205aSDingqiang Lin }
4276281205aSDingqiang Lin 
4286281205aSDingqiang Lin /*
429d9cdd318SJon Lin  * ecc spectial type2:
430a6fcac41SJon Lin  * ecc bits: 0xC0[4,5] 0xF0[4,5]
431f28847a8SJon Lin  * [0b0000, 0b0011], No bit errors were detected;
432f28847a8SJon Lin  * [0b0100, 0b0111], Bit errors were detected and corrected. Not
433d9cdd318SJon Lin  *	reach Flipping Bits;
434f28847a8SJon Lin  * [0b1000, 0b1011], Multiple bit errors were detected and
435c84f0ed8SJon Lin  *	not corrected.
436f28847a8SJon Lin  * [0b1100, 0b1111], reserved.
437d9cdd318SJon Lin  */
438f28847a8SJon Lin static u32 sfc_nand_get_ecc_status2(void)
439d9cdd318SJon Lin {
44058463f4dSJon Lin 	u32 ret;
441d9cdd318SJon Lin 	u32 i;
442d9cdd318SJon Lin 	u8 ecc;
443d9cdd318SJon Lin 	u8 status, status1;
444d9cdd318SJon Lin 	u32 timeout = 1000 * 1000;
445d9cdd318SJon Lin 
446d9cdd318SJon Lin 	for (i = 0; i < timeout; i++) {
447d9cdd318SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
448f28847a8SJon Lin 
449d9cdd318SJon Lin 		if (ret != SFC_OK)
450d9cdd318SJon Lin 			return SFC_NAND_ECC_ERROR;
451f28847a8SJon Lin 
452d9cdd318SJon Lin 		ret = sfc_nand_read_feature(0xF0, &status1);
453f28847a8SJon Lin 
454d9cdd318SJon Lin 		if (ret != SFC_OK)
455d9cdd318SJon Lin 			return SFC_NAND_ECC_ERROR;
456f28847a8SJon Lin 
457d9cdd318SJon Lin 		if (!(status & (1 << 0)))
458d9cdd318SJon Lin 			break;
459f28847a8SJon Lin 
460d9cdd318SJon Lin 		sfc_delay(1);
461d9cdd318SJon Lin 	}
462d9cdd318SJon Lin 
463d9cdd318SJon Lin 	ecc = (status >> 4) & 0x03;
464d9cdd318SJon Lin 	ecc = (ecc << 2) | ((status1 >> 4) & 0x03);
465f28847a8SJon Lin 
466d9cdd318SJon Lin 	if (ecc < 7)
467d9cdd318SJon Lin 		ret = SFC_NAND_ECC_OK;
468d9cdd318SJon Lin 	else if (ecc == 7)
469d9cdd318SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
470d9cdd318SJon Lin 	else
47158463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
472d9cdd318SJon Lin 
473d9cdd318SJon Lin 	return ret;
474d9cdd318SJon Lin }
475d9cdd318SJon Lin 
476d9cdd318SJon Lin /*
4776281205aSDingqiang Lin  * ecc spectial type3:
478a6fcac41SJon Lin  * ecc bits: 0xC0[4,5] 0xF0[4,5]
479f28847a8SJon Lin  * [0b0000, 0b0011], No bit errors were detected;
480f28847a8SJon Lin  * [0b0100, 0b0111], Bit errors were detected and corrected. Not
4816281205aSDingqiang Lin  *	reach Flipping Bits;
482f28847a8SJon Lin  * [0b1000, 0b1011], Multiple bit errors were detected and
4836281205aSDingqiang Lin  *	not corrected.
484f28847a8SJon Lin  * [0b1100, 0b1111], Bit error count equals the bit flip
4856281205aSDingqiang Lin  *	detectio nthreshold
4866281205aSDingqiang Lin  */
487f28847a8SJon Lin static u32 sfc_nand_get_ecc_status3(void)
4886281205aSDingqiang Lin {
48958463f4dSJon Lin 	u32 ret;
4906281205aSDingqiang Lin 	u32 i;
4916281205aSDingqiang Lin 	u8 ecc;
4926281205aSDingqiang Lin 	u8 status, status1;
4936281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
4946281205aSDingqiang Lin 
4956281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
4966281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
497f28847a8SJon Lin 
4986281205aSDingqiang Lin 		if (ret != SFC_OK)
4996281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
500f28847a8SJon Lin 
5016281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xF0, &status1);
502f28847a8SJon Lin 
5036281205aSDingqiang Lin 		if (ret != SFC_OK)
5046281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
505f28847a8SJon Lin 
5066281205aSDingqiang Lin 		if (!(status & (1 << 0)))
5076281205aSDingqiang Lin 			break;
508f28847a8SJon Lin 
5096281205aSDingqiang Lin 		sfc_delay(1);
5106281205aSDingqiang Lin 	}
5116281205aSDingqiang Lin 
5126281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
5136281205aSDingqiang Lin 	ecc = (ecc << 2) | ((status1 >> 4) & 0x03);
514f28847a8SJon Lin 
5156281205aSDingqiang Lin 	if (ecc < 7)
5166281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
5176281205aSDingqiang Lin 	else if (ecc == 7 || ecc >= 12)
5186281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
5196281205aSDingqiang Lin 	else
52058463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
5216281205aSDingqiang Lin 
5226281205aSDingqiang Lin 	return ret;
5236281205aSDingqiang Lin }
5246281205aSDingqiang Lin 
52525098c06SDingqiang Lin /*
52625098c06SDingqiang Lin  * ecc spectial type4:
527a6fcac41SJon Lin  * ecc bits: 0xC0[2,5]
528f28847a8SJon Lin  * [0b0000], No bit errors were detected;
529f28847a8SJon Lin  * [0b0001, 0b0111], Bit errors were detected and corrected. Not
53025098c06SDingqiang Lin  *	reach Flipping Bits;
531f28847a8SJon Lin  * [0b1000], Multiple bit errors were detected and
53225098c06SDingqiang Lin  *	not corrected.
533f28847a8SJon Lin  * [0b1100], Bit error count equals the bit flip
53425098c06SDingqiang Lin  *	detection threshold
53525098c06SDingqiang Lin  * else, reserved
53625098c06SDingqiang Lin  */
537f28847a8SJon Lin static u32 sfc_nand_get_ecc_status4(void)
53825098c06SDingqiang Lin {
53958463f4dSJon Lin 	u32 ret;
54025098c06SDingqiang Lin 	u32 i;
54125098c06SDingqiang Lin 	u8 ecc;
54225098c06SDingqiang Lin 	u8 status;
54325098c06SDingqiang Lin 	u32 timeout = 1000 * 1000;
54425098c06SDingqiang Lin 
54525098c06SDingqiang Lin 	for (i = 0; i < timeout; i++) {
54625098c06SDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
547f28847a8SJon Lin 
54825098c06SDingqiang Lin 		if (ret != SFC_OK)
54925098c06SDingqiang Lin 			return SFC_NAND_ECC_ERROR;
550f28847a8SJon Lin 
55125098c06SDingqiang Lin 		if (!(status & (1 << 0)))
55225098c06SDingqiang Lin 			break;
553f28847a8SJon Lin 
55425098c06SDingqiang Lin 		sfc_delay(1);
55525098c06SDingqiang Lin 	}
55625098c06SDingqiang Lin 
55725098c06SDingqiang Lin 	ecc = (status >> 2) & 0x0f;
558f28847a8SJon Lin 
55925098c06SDingqiang Lin 	if (ecc < 7)
56025098c06SDingqiang Lin 		ret = SFC_NAND_ECC_OK;
56125098c06SDingqiang Lin 	else if (ecc == 7 || ecc == 12)
56225098c06SDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
56325098c06SDingqiang Lin 	else
56458463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
56525098c06SDingqiang Lin 
56625098c06SDingqiang Lin 	return ret;
56725098c06SDingqiang Lin }
56825098c06SDingqiang Lin 
56925098c06SDingqiang Lin /*
57025098c06SDingqiang Lin  * ecc spectial type5:
571a6fcac41SJon Lin  * ecc bits: 0xC0[4,6]
572f28847a8SJon Lin  * [0b000], No bit errors were detected;
573f28847a8SJon Lin  * [0b001, 0b011], Bit errors were detected and corrected. Not
57425098c06SDingqiang Lin  *	reach Flipping Bits;
575f28847a8SJon Lin  * [0b100], Bit error count equals the bit flip
57625098c06SDingqiang Lin  *	detection threshold
577f28847a8SJon Lin  * [0b101, 0b110], Reserved;
578f28847a8SJon Lin  * [0b111], Multiple bit errors were detected and
57925098c06SDingqiang Lin  *	not corrected.
58025098c06SDingqiang Lin  */
581f28847a8SJon Lin static u32 sfc_nand_get_ecc_status5(void)
58225098c06SDingqiang Lin {
58358463f4dSJon Lin 	u32 ret;
58425098c06SDingqiang Lin 	u32 i;
58525098c06SDingqiang Lin 	u8 ecc;
58625098c06SDingqiang Lin 	u8 status;
58725098c06SDingqiang Lin 	u32 timeout = 1000 * 1000;
58825098c06SDingqiang Lin 
58925098c06SDingqiang Lin 	for (i = 0; i < timeout; i++) {
59025098c06SDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
591f28847a8SJon Lin 
59225098c06SDingqiang Lin 		if (ret != SFC_OK)
59325098c06SDingqiang Lin 			return SFC_NAND_ECC_ERROR;
594f28847a8SJon Lin 
59525098c06SDingqiang Lin 		if (!(status & (1 << 0)))
59625098c06SDingqiang Lin 			break;
597f28847a8SJon Lin 
59825098c06SDingqiang Lin 		sfc_delay(1);
59925098c06SDingqiang Lin 	}
60025098c06SDingqiang Lin 
60125098c06SDingqiang Lin 	ecc = (status >> 4) & 0x07;
602f28847a8SJon Lin 
60325098c06SDingqiang Lin 	if (ecc < 4)
60425098c06SDingqiang Lin 		ret = SFC_NAND_ECC_OK;
60525098c06SDingqiang Lin 	else if (ecc == 4)
60625098c06SDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
60725098c06SDingqiang Lin 	else
60858463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
60925098c06SDingqiang Lin 
61025098c06SDingqiang Lin 	return ret;
61125098c06SDingqiang Lin }
61225098c06SDingqiang Lin 
613f28847a8SJon Lin /*
614f28847a8SJon Lin  * ecc spectial type6:
615f28847a8SJon Lin  * ecc bits: 0xC0[4,6]
616f28847a8SJon Lin  * [0b000], No bit errors were detected;
617f28847a8SJon Lin  * [0b001], 1-3 Bit errors were detected and corrected. Not
618f28847a8SJon Lin  *	reach Flipping Bits;
619f28847a8SJon Lin  * [0b010], Multiple bit errors were detected and
620f28847a8SJon Lin  *	not corrected.
621f28847a8SJon Lin  * [0b011], 4-6 Bit errors were detected and corrected. Not
622f28847a8SJon Lin  *	reach Flipping Bits;
623f28847a8SJon Lin  * [0b101], Bit error count equals the bit flip
624f28847a8SJon Lin  *	detectionthreshold
625f28847a8SJon Lin  * others, Reserved.
626f28847a8SJon Lin  */
627f28847a8SJon Lin static u32 sfc_nand_get_ecc_status6(void)
628f28847a8SJon Lin {
629f28847a8SJon Lin 	u32 ret;
630f28847a8SJon Lin 	u32 i;
631f28847a8SJon Lin 	u8 ecc;
632f28847a8SJon Lin 	u8 status;
633f28847a8SJon Lin 	u32 timeout = 1000 * 1000;
634f28847a8SJon Lin 
635f28847a8SJon Lin 	for (i = 0; i < timeout; i++) {
636f28847a8SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
637f28847a8SJon Lin 
638f28847a8SJon Lin 		if (ret != SFC_OK)
639f28847a8SJon Lin 			return SFC_NAND_ECC_ERROR;
640f28847a8SJon Lin 
641f28847a8SJon Lin 		if (!(status & (1 << 0)))
642f28847a8SJon Lin 			break;
643f28847a8SJon Lin 
644f28847a8SJon Lin 		sfc_delay(1);
645f28847a8SJon Lin 	}
646f28847a8SJon Lin 
647f28847a8SJon Lin 	ecc = (status >> 4) & 0x07;
648f28847a8SJon Lin 
649f28847a8SJon Lin 	if (ecc == 0 || ecc == 1 || ecc == 3)
650f28847a8SJon Lin 		ret = SFC_NAND_ECC_OK;
651f28847a8SJon Lin 	else if (ecc == 5)
652f28847a8SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
653f28847a8SJon Lin 	else
654f28847a8SJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
655f28847a8SJon Lin 
656f28847a8SJon Lin 	return ret;
657f28847a8SJon Lin }
658f28847a8SJon Lin 
659362b1be1SJon Lin /*
660362b1be1SJon Lin  * ecc spectial type7:
661362b1be1SJon Lin  * ecc bits: 0xC0[4,7]
662362b1be1SJon Lin  * [0b0000], No bit errors were detected;
663362b1be1SJon Lin  * [0b0001, 0b0111], 1-7 Bit errors were detected and corrected. Not
664362b1be1SJon Lin  *	reach Flipping Bits;
665362b1be1SJon Lin  * [0b1000], 8 Bit errors were detected and corrected. Bit error count
666362b1be1SJon Lin  * 	equals the bit flip detectionthreshold;
667362b1be1SJon Lin  * [0b1111], Bit errors greater than ECC capability(8 bits) and not corrected;
668362b1be1SJon Lin  * others, Reserved.
669362b1be1SJon Lin  */
670362b1be1SJon Lin static u32 sfc_nand_get_ecc_status7(void)
671362b1be1SJon Lin {
672362b1be1SJon Lin 	u32 ret;
673362b1be1SJon Lin 	u32 i;
674362b1be1SJon Lin 	u8 ecc;
675362b1be1SJon Lin 	u8 status;
676362b1be1SJon Lin 	u32 timeout = 1000 * 1000;
677362b1be1SJon Lin 
678362b1be1SJon Lin 	for (i = 0; i < timeout; i++) {
679362b1be1SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
680362b1be1SJon Lin 
681362b1be1SJon Lin 		if (ret != SFC_OK)
682362b1be1SJon Lin 			return SFC_NAND_ECC_ERROR;
683362b1be1SJon Lin 
684362b1be1SJon Lin 		if (!(status & (1 << 0)))
685362b1be1SJon Lin 			break;
686362b1be1SJon Lin 
687362b1be1SJon Lin 		sfc_delay(1);
688362b1be1SJon Lin 	}
689362b1be1SJon Lin 
690362b1be1SJon Lin 	ecc = (status >> 4) & 0xf;
691362b1be1SJon Lin 
692362b1be1SJon Lin 	if (ecc < 7)
693362b1be1SJon Lin 		ret = SFC_NAND_ECC_OK;
694362b1be1SJon Lin 	else if (ecc == 7 || ecc == 8)
695362b1be1SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
696362b1be1SJon Lin 	else
697362b1be1SJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
698362b1be1SJon Lin 
699362b1be1SJon Lin 	return ret;
700362b1be1SJon Lin }
701362b1be1SJon Lin 
702629111d3SJon Lin /*
703629111d3SJon Lin  * ecc spectial type8:
704629111d3SJon Lin  * ecc bits: 0xC0[4,6]
705629111d3SJon Lin  * [0b000], No bit errors were detected;
706629111d3SJon Lin  * [0b001, 0b011], 1~3 Bit errors were detected and corrected. Not
707629111d3SJon Lin  *	reach Flipping Bits;
708629111d3SJon Lin  * [0b100], Bit error count equals the bit flip
709629111d3SJon Lin  *	detection threshold
710629111d3SJon Lin  * others, Reserved.
711629111d3SJon Lin  */
712629111d3SJon Lin static u32 sfc_nand_get_ecc_status8(void)
713629111d3SJon Lin {
714629111d3SJon Lin 	u32 ret;
715629111d3SJon Lin 	u32 i;
716629111d3SJon Lin 	u8 ecc;
717629111d3SJon Lin 	u8 status;
718629111d3SJon Lin 	u32 timeout = 1000 * 1000;
719629111d3SJon Lin 
720629111d3SJon Lin 	for (i = 0; i < timeout; i++) {
721629111d3SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
722629111d3SJon Lin 
723629111d3SJon Lin 		if (ret != SFC_OK)
724629111d3SJon Lin 			return SFC_NAND_ECC_ERROR;
725629111d3SJon Lin 
726629111d3SJon Lin 		if (!(status & (1 << 0)))
727629111d3SJon Lin 			break;
728629111d3SJon Lin 
729629111d3SJon Lin 		sfc_delay(1);
730629111d3SJon Lin 	}
731629111d3SJon Lin 
732629111d3SJon Lin 	ecc = (status >> 4) & 0x07;
733629111d3SJon Lin 
734629111d3SJon Lin 	if (ecc < 4)
735629111d3SJon Lin 		ret = SFC_NAND_ECC_OK;
736629111d3SJon Lin 	else if (ecc == 4)
737629111d3SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
738629111d3SJon Lin 	else
739629111d3SJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
740629111d3SJon Lin 
741629111d3SJon Lin 	return ret;
742629111d3SJon Lin }
743629111d3SJon Lin 
744d4db0b8dSJon Lin /*
745d4db0b8dSJon Lin  * ecc spectial type9:
746d4db0b8dSJon Lin  * ecc bits: 0xC0[4,5]
747d4db0b8dSJon Lin  * 0b00, No bit errors were detected
748d4db0b8dSJon Lin  * 0b01, 1-2Bit errors were detected and corrected.
749d4db0b8dSJon Lin  * 0b10, 3-4Bit errors were detected and corrected.
750d4db0b8dSJon Lin  * 0b11, 11 can be used as uncorrectable
751d4db0b8dSJon Lin  */
752d4db0b8dSJon Lin static u32 sfc_nand_get_ecc_status9(void)
753d4db0b8dSJon Lin {
754d4db0b8dSJon Lin 	u32 ret;
755d4db0b8dSJon Lin 	u32 i;
756d4db0b8dSJon Lin 	u8 ecc;
757d4db0b8dSJon Lin 	u8 status;
758d4db0b8dSJon Lin 	u32 timeout = 1000 * 1000;
759d4db0b8dSJon Lin 
760d4db0b8dSJon Lin 	for (i = 0; i < timeout; i++) {
761d4db0b8dSJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
762d4db0b8dSJon Lin 
763d4db0b8dSJon Lin 		if (ret != SFC_OK)
764d4db0b8dSJon Lin 			return SFC_NAND_ECC_ERROR;
765d4db0b8dSJon Lin 
766d4db0b8dSJon Lin 		if (!(status & (1 << 0)))
767d4db0b8dSJon Lin 			break;
768d4db0b8dSJon Lin 
769d4db0b8dSJon Lin 		sfc_delay(1);
770d4db0b8dSJon Lin 	}
771d4db0b8dSJon Lin 
772d4db0b8dSJon Lin 	ecc = (status >> 4) & 0x03;
773d4db0b8dSJon Lin 
774d4db0b8dSJon Lin 	if (ecc <= 1)
775d4db0b8dSJon Lin 		ret = SFC_NAND_ECC_OK;
776d4db0b8dSJon Lin 	else if (ecc == 2)
777d4db0b8dSJon Lin 		ret = SFC_NAND_ECC_REFRESH;
778d4db0b8dSJon Lin 	else
779d4db0b8dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
780d4db0b8dSJon Lin 
781d4db0b8dSJon Lin 	return ret;
782d4db0b8dSJon Lin }
783d4db0b8dSJon Lin 
784c84f0ed8SJon Lin u32 sfc_nand_erase_block(u8 cs, u32 addr)
785ba0501acSDingqiang Lin {
786ba0501acSDingqiang Lin 	int ret;
78758463f4dSJon Lin 	struct rk_sfc_op op;
788ba0501acSDingqiang Lin 	u8 status;
789ba0501acSDingqiang Lin 
790c84f0ed8SJon Lin 	rkflash_print_dio("%s %x\n", __func__, addr);
79158463f4dSJon Lin 	op.sfcmd.d32 = 0;
792f28847a8SJon Lin 	op.sfcmd.b.cmd = 0xd8;
79358463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_24BITS;
79458463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
79558463f4dSJon Lin 
79658463f4dSJon Lin 	op.sfctrl.d32 = 0;
79758463f4dSJon Lin 
798ba0501acSDingqiang Lin 	sfc_nand_write_en();
79958463f4dSJon Lin 	ret = sfc_request(&op, addr, NULL, 0);
800f28847a8SJon Lin 
801ba0501acSDingqiang Lin 	if (ret != SFC_OK)
802ba0501acSDingqiang Lin 		return ret;
803f28847a8SJon Lin 
804ba0501acSDingqiang Lin 	ret = sfc_nand_wait_busy(&status, 1000 * 1000);
805f28847a8SJon Lin 
806ba0501acSDingqiang Lin 	if (status & (1 << 2))
807ba0501acSDingqiang Lin 		return SFC_NAND_PROG_ERASE_ERROR;
808c84f0ed8SJon Lin 
809ba0501acSDingqiang Lin 	return ret;
810ba0501acSDingqiang Lin }
811ba0501acSDingqiang Lin 
812629111d3SJon Lin static u32 sfc_nand_read_cache(u32 row, u32 *p_page_buf, u32 column, u32 len)
813629111d3SJon Lin {
814629111d3SJon Lin 	int ret;
815629111d3SJon Lin 	u32 plane;
816629111d3SJon Lin 	struct rk_sfc_op op;
817629111d3SJon Lin 
818629111d3SJon Lin 	op.sfcmd.d32 = 0;
819629111d3SJon Lin 	op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd;
820629111d3SJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
821629111d3SJon Lin 	op.sfcmd.b.dummybits = 8;
822629111d3SJon Lin 
823629111d3SJon Lin 	op.sfctrl.d32 = 0;
824629111d3SJon Lin 	op.sfctrl.b.datalines = sfc_nand_dev.read_lines;
825629111d3SJon Lin 	op.sfctrl.b.addrbits = 16;
826629111d3SJon Lin 
827629111d3SJon Lin 	plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0;
828629111d3SJon Lin 
829629111d3SJon Lin 	ret = sfc_request(&op, plane | column, p_page_buf, len);
830629111d3SJon Lin 	if (ret != SFC_OK)
831629111d3SJon Lin 		return SFC_NAND_HW_ERROR;
832629111d3SJon Lin 
833629111d3SJon Lin 	return ret;
834629111d3SJon Lin }
835629111d3SJon Lin 
836f28847a8SJon Lin u32 sfc_nand_prog_page_raw(u8 cs, u32 addr, u32 *p_page_buf)
837ba0501acSDingqiang Lin {
838ba0501acSDingqiang Lin 	int ret;
839415cf080Sjon.lin 	u32 plane;
84058463f4dSJon Lin 	struct rk_sfc_op op;
841ba0501acSDingqiang Lin 	u8 status;
84258463f4dSJon Lin 	u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page;
843629111d3SJon Lin 	u32 data_area_size = SFC_NAND_SECTOR_SIZE * p_nand_info->sec_per_page;
844ba0501acSDingqiang Lin 
845c84f0ed8SJon Lin 	rkflash_print_dio("%s %x %x\n", __func__, addr, p_page_buf[0]);
846ba0501acSDingqiang Lin 	sfc_nand_write_en();
847f28847a8SJon Lin 
848ba0501acSDingqiang Lin 	if (sfc_nand_dev.prog_lines == DATA_LINES_X4 &&
84925098c06SDingqiang Lin 	    p_nand_info->feature & FEA_SOFT_QOP_BIT &&
85025098c06SDingqiang Lin 	    sfc_get_version() < SFC_VER_3)
851ba0501acSDingqiang Lin 		sfc_nand_rw_preset();
852ba0501acSDingqiang Lin 
85358463f4dSJon Lin 	op.sfcmd.d32 = 0;
85458463f4dSJon Lin 	op.sfcmd.b.cmd = sfc_nand_dev.page_prog_cmd;
85558463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
85658463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
857ba0501acSDingqiang Lin 
85858463f4dSJon Lin 	op.sfctrl.d32 = 0;
85958463f4dSJon Lin 	op.sfctrl.b.datalines = sfc_nand_dev.prog_lines;
86058463f4dSJon Lin 	op.sfctrl.b.addrbits = 16;
861415cf080Sjon.lin 	plane = p_nand_info->plane_per_die == 2 ? ((addr >> 6) & 0x1) << 12 : 0;
86258463f4dSJon Lin 	sfc_request(&op, plane, p_page_buf, page_size);
863ba0501acSDingqiang Lin 
864629111d3SJon Lin 	/*
865c797b43aSJon Lin 	 * At the moment of power lost or dev running in harsh environment, flash
866c797b43aSJon Lin 	 * maybe work in a unkonw state and result in bit flip, when this situation
867c797b43aSJon Lin 	 * is detected by cache recheck, it's better to wait a second for a reliable
868c797b43aSJon Lin 	 * hardware environment to avoid abnormal data written to flash array.
869629111d3SJon Lin 	 */
870361684bfSJon Lin 	if (p_nand_info->id0 == MID_GIGADEV) {
871629111d3SJon Lin 		sfc_nand_read_cache(addr, (u32 *)sfc_nand_dev.recheck_buffer, 0, data_area_size);
872c797b43aSJon Lin 		if (memcmp(sfc_nand_dev.recheck_buffer, p_page_buf, data_area_size)) {
873c797b43aSJon Lin 			rkflash_print_error("%s %x cache bitflip\n", __func__, addr);
874c797b43aSJon Lin 			mdelay(1000);
875c797b43aSJon Lin 			sfc_request(&op, plane, p_page_buf, page_size);
876c797b43aSJon Lin 		}
877c797b43aSJon Lin 	}
878629111d3SJon Lin 
87958463f4dSJon Lin 	op.sfcmd.d32 = 0;
880f28847a8SJon Lin 	op.sfcmd.b.cmd = 0x10;
88158463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_24BITS;
88258463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
88358463f4dSJon Lin 
88458463f4dSJon Lin 	op.sfctrl.d32 = 0;
88558463f4dSJon Lin 	ret = sfc_request(&op, addr, p_page_buf, 0);
886f28847a8SJon Lin 
887ba0501acSDingqiang Lin 	if (ret != SFC_OK)
888ba0501acSDingqiang Lin 		return ret;
889f28847a8SJon Lin 
890ba0501acSDingqiang Lin 	ret = sfc_nand_wait_busy(&status, 1000 * 1000);
891ba0501acSDingqiang Lin 	if (status & (1 << 3))
892ba0501acSDingqiang Lin 		return SFC_NAND_PROG_ERASE_ERROR;
893c84f0ed8SJon Lin 
894ba0501acSDingqiang Lin 	return ret;
895ba0501acSDingqiang Lin }
896ba0501acSDingqiang Lin 
897c84f0ed8SJon Lin u32 sfc_nand_prog_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare)
898c84f0ed8SJon Lin {
899c84f0ed8SJon Lin 	int ret;
900c84f0ed8SJon Lin 	u32 sec_per_page = p_nand_info->sec_per_page;
901c84f0ed8SJon Lin 	u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE;
902a6fcac41SJon Lin 	struct nand_mega_area *meta = &p_nand_info->meta;
903c84f0ed8SJon Lin 
904c84f0ed8SJon Lin 	memcpy(gp_page_buf, p_data, data_size);
905c84f0ed8SJon Lin 	memset(&gp_page_buf[data_size / 4], 0xff, sec_per_page * 16);
906a6fcac41SJon Lin 	gp_page_buf[(data_size + meta->off0) / 4] = p_spare[0];
907a6fcac41SJon Lin 	gp_page_buf[(data_size + meta->off1) / 4] = p_spare[1];
908f28847a8SJon Lin 
909c84f0ed8SJon Lin 	if (sec_per_page == 8) {
910a6fcac41SJon Lin 		gp_page_buf[(data_size + meta->off2) / 4] = p_spare[2];
911a6fcac41SJon Lin 		gp_page_buf[(data_size + meta->off3) / 4] = p_spare[3];
912c84f0ed8SJon Lin 	}
913f28847a8SJon Lin 
914c84f0ed8SJon Lin 	ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf);
915c84f0ed8SJon Lin 
916c84f0ed8SJon Lin 	return ret;
917c84f0ed8SJon Lin }
918c84f0ed8SJon Lin 
919a80fd396SJon Lin u32 sfc_nand_read(u32 row, u32 *p_page_buf, u32 column, u32 len)
920ba0501acSDingqiang Lin {
921ba0501acSDingqiang Lin 	int ret;
922415cf080Sjon.lin 	u32 plane;
92358463f4dSJon Lin 	struct rk_sfc_op op;
9246281205aSDingqiang Lin 	u32 ecc_result;
925a6fcac41SJon Lin 	u8 status;
926ba0501acSDingqiang Lin 
92758463f4dSJon Lin 	op.sfcmd.d32 = 0;
928f28847a8SJon Lin 	op.sfcmd.b.cmd = 0x13;
92958463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
93058463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_24BITS;
93158463f4dSJon Lin 
93258463f4dSJon Lin 	op.sfctrl.d32 = 0;
93358463f4dSJon Lin 
934a80fd396SJon Lin 	sfc_request(&op, row, p_page_buf, 0);
935f28847a8SJon Lin 
936ba0501acSDingqiang Lin 	if (sfc_nand_dev.read_lines == DATA_LINES_X4 &&
93725098c06SDingqiang Lin 	    p_nand_info->feature & FEA_SOFT_QOP_BIT &&
93825098c06SDingqiang Lin 	    sfc_get_version() < SFC_VER_3)
939ba0501acSDingqiang Lin 		sfc_nand_rw_preset();
940ba0501acSDingqiang Lin 
941a6fcac41SJon Lin 	sfc_nand_wait_busy(&status, 1000 * 1000);
942a6fcac41SJon Lin 	ecc_result = p_nand_info->ecc_status();
943a6fcac41SJon Lin 
94458463f4dSJon Lin 	op.sfcmd.d32 = 0;
94558463f4dSJon Lin 	op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd;
946a80fd396SJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
947a80fd396SJon Lin 	op.sfcmd.b.dummybits = 8;
94858463f4dSJon Lin 
94958463f4dSJon Lin 	op.sfctrl.d32 = 0;
95058463f4dSJon Lin 	op.sfctrl.b.datalines = sfc_nand_dev.read_lines;
951a80fd396SJon Lin 	op.sfctrl.b.addrbits = 16;
952ba0501acSDingqiang Lin 
953a80fd396SJon Lin 	plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0;
954a80fd396SJon Lin 	ret = sfc_request(&op, plane | column, p_page_buf, len);
955a80fd396SJon Lin 	rkflash_print_dio("%s %x %x\n", __func__, row, p_page_buf[0]);
956c84f0ed8SJon Lin 
957c84f0ed8SJon Lin 	if (ret != SFC_OK)
958f28847a8SJon Lin 		return SFC_NAND_HW_ERROR;
959c84f0ed8SJon Lin 
960c84f0ed8SJon Lin 	return ecc_result;
961c84f0ed8SJon Lin }
962c84f0ed8SJon Lin 
963a80fd396SJon Lin u32 sfc_nand_read_page_raw(u8 cs, u32 addr, u32 *p_page_buf)
964a80fd396SJon Lin {
965a80fd396SJon Lin 	u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page;
966a80fd396SJon Lin 
967a80fd396SJon Lin 	return sfc_nand_read(addr, p_page_buf, 0, page_size);
968a80fd396SJon Lin }
969a80fd396SJon Lin 
970c84f0ed8SJon Lin u32 sfc_nand_read_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare)
971c84f0ed8SJon Lin {
97258463f4dSJon Lin 	u32 ret;
973c84f0ed8SJon Lin 	u32 sec_per_page = p_nand_info->sec_per_page;
974c84f0ed8SJon Lin 	u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE;
975a6fcac41SJon Lin 	struct nand_mega_area *meta = &p_nand_info->meta;
976c84f0ed8SJon Lin 
977c84f0ed8SJon Lin 	ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf);
978f25e3cafSJon Lin 	memcpy(p_data, gp_page_buf, data_size);
979a6fcac41SJon Lin 	p_spare[0] = gp_page_buf[(data_size + meta->off0) / 4];
980a6fcac41SJon Lin 	p_spare[1] = gp_page_buf[(data_size + meta->off1) / 4];
981f28847a8SJon Lin 
982f25e3cafSJon Lin 	if (p_nand_info->sec_per_page == 8) {
983a6fcac41SJon Lin 		p_spare[2] = gp_page_buf[(data_size + meta->off2) / 4];
984a6fcac41SJon Lin 		p_spare[3] = gp_page_buf[(data_size + meta->off3) / 4];
985f25e3cafSJon Lin 	}
986ba0501acSDingqiang Lin 
987f28847a8SJon Lin 	if (ret == SFC_NAND_HW_ERROR)
988f28847a8SJon Lin 		ret = SFC_NAND_ECC_ERROR;
989f28847a8SJon Lin 
990c84f0ed8SJon Lin 	if (ret != SFC_NAND_ECC_OK) {
991c84f0ed8SJon Lin 		rkflash_print_error("%s[0x%x], ret=0x%x\n", __func__, addr, ret);
992f28847a8SJon Lin 
993ba0501acSDingqiang Lin 		if (p_data)
994c84f0ed8SJon Lin 			rkflash_print_hex("data:", p_data, 4, 8);
995f28847a8SJon Lin 
996ba0501acSDingqiang Lin 		if (p_spare)
997c84f0ed8SJon Lin 			rkflash_print_hex("spare:", p_spare, 4, 2);
998ba0501acSDingqiang Lin 	}
999f25e3cafSJon Lin 
1000c84f0ed8SJon Lin 	return ret;
1001ba0501acSDingqiang Lin }
1002ba0501acSDingqiang Lin 
1003c84f0ed8SJon Lin u32 sfc_nand_check_bad_block(u8 cs, u32 addr)
1004c84f0ed8SJon Lin {
1005c84f0ed8SJon Lin 	u32 ret;
1006c84f0ed8SJon Lin 	u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE;
1007a80fd396SJon Lin 	u32 marker = 0;
1008c84f0ed8SJon Lin 
1009a80fd396SJon Lin 	ret = sfc_nand_read(addr, &marker, data_size, 2);
1010f28847a8SJon Lin 
1011f28847a8SJon Lin 	/* unify with mtd framework */
1012629111d3SJon Lin 	if (ret == SFC_NAND_ECC_ERROR || (u16)marker != 0xffff)
1013a80fd396SJon Lin 		rkflash_print_error("%s page= %x ret= %x spare= %x\n",
1014a80fd396SJon Lin 				    __func__, addr, ret, marker);
1015f28847a8SJon Lin 
1016c84f0ed8SJon Lin 	/* Original bad block */
1017a80fd396SJon Lin 	if ((u16)marker != 0xffff)
1018c84f0ed8SJon Lin 		return true;
1019c84f0ed8SJon Lin 
1020c84f0ed8SJon Lin 	return false;
1021c84f0ed8SJon Lin }
1022c84f0ed8SJon Lin 
1023c84f0ed8SJon Lin u32 sfc_nand_mark_bad_block(u8 cs, u32 addr)
1024c84f0ed8SJon Lin {
1025c84f0ed8SJon Lin 	u32 ret;
1026c84f0ed8SJon Lin 	u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE;
1027c84f0ed8SJon Lin 
1028c84f0ed8SJon Lin 	ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf);
1029f28847a8SJon Lin 
1030c84f0ed8SJon Lin 	if (ret)
1031c84f0ed8SJon Lin 		return SFC_NAND_HW_ERROR;
1032f28847a8SJon Lin 
1033c84f0ed8SJon Lin 	gp_page_buf[data_size / 4] = 0x0;
1034c84f0ed8SJon Lin 	ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf);
1035f28847a8SJon Lin 
1036c84f0ed8SJon Lin 	if (ret)
1037c84f0ed8SJon Lin 		return SFC_NAND_HW_ERROR;
1038c84f0ed8SJon Lin 
1039c84f0ed8SJon Lin 	return ret;
1040c84f0ed8SJon Lin }
1041c84f0ed8SJon Lin 
1042c84f0ed8SJon Lin int sfc_nand_read_id(u8 *data)
1043ba0501acSDingqiang Lin {
1044ba0501acSDingqiang Lin 	int ret;
104558463f4dSJon Lin 	struct rk_sfc_op op;
1046ba0501acSDingqiang Lin 
104758463f4dSJon Lin 	op.sfcmd.d32 = 0;
104858463f4dSJon Lin 	op.sfcmd.b.cmd = CMD_READ_JEDECID;
104958463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
1050ba0501acSDingqiang Lin 
105158463f4dSJon Lin 	op.sfctrl.d32 = 0;
105258463f4dSJon Lin 	op.sfctrl.b.addrbits = 8;
105358463f4dSJon Lin 
105458463f4dSJon Lin 	ret = sfc_request(&op, 0, data, 3);
1055ba0501acSDingqiang Lin 
1056ba0501acSDingqiang Lin 	return ret;
1057ba0501acSDingqiang Lin }
1058ba0501acSDingqiang Lin 
1059ba0501acSDingqiang Lin /*
1060ba0501acSDingqiang Lin  * Read the 1st page's 1st byte of a phy_blk
1061ba0501acSDingqiang Lin  * If not FF, it's bad blk
1062ba0501acSDingqiang Lin  */
1063ba0501acSDingqiang Lin static int sfc_nand_get_bad_block_list(u16 *table, u32 die)
1064ba0501acSDingqiang Lin {
1065ba0501acSDingqiang Lin 	u32 bad_cnt, page;
1066ba0501acSDingqiang Lin 	u32 blk_per_die;
10672ac88c1bSJon Lin 	u16 blk;
1068ba0501acSDingqiang Lin 
1069c84f0ed8SJon Lin 	rkflash_print_info("%s\n", __func__);
1070c84f0ed8SJon Lin 
1071ba0501acSDingqiang Lin 	bad_cnt = 0;
1072ba0501acSDingqiang Lin 	blk_per_die = p_nand_info->plane_per_die *
1073ba0501acSDingqiang Lin 		      p_nand_info->blk_per_plane;
1074f28847a8SJon Lin 
1075ba0501acSDingqiang Lin 	for (blk = 0; blk < blk_per_die; blk++) {
1076ba0501acSDingqiang Lin 		page = (blk + blk_per_die * die) *
1077ba0501acSDingqiang Lin 		       p_nand_info->page_per_blk;
1078ba0501acSDingqiang Lin 
10792ac88c1bSJon Lin 		if (sfc_nand_check_bad_block(die, page)) {
1080ba0501acSDingqiang Lin 			table[bad_cnt++] = blk;
1081c84f0ed8SJon Lin 			rkflash_print_error("die[%d], bad_blk[%d]\n", die, blk);
1082ba0501acSDingqiang Lin 		}
1083ba0501acSDingqiang Lin 	}
1084f28847a8SJon Lin 
1085ba0501acSDingqiang Lin 	return (int)bad_cnt;
1086ba0501acSDingqiang Lin }
1087ba0501acSDingqiang Lin 
1088c84f0ed8SJon Lin void sfc_nand_ftl_ops_init(void)
1089ba0501acSDingqiang Lin {
1090ba0501acSDingqiang Lin 	/* para init */
1091ba0501acSDingqiang Lin 	g_nand_phy_info.nand_type	= 1;
1092ba0501acSDingqiang Lin 	g_nand_phy_info.die_num		= 1;
1093ba0501acSDingqiang Lin 	g_nand_phy_info.plane_per_die	= p_nand_info->plane_per_die;
1094ba0501acSDingqiang Lin 	g_nand_phy_info.blk_per_plane	= p_nand_info->blk_per_plane;
1095ba0501acSDingqiang Lin 	g_nand_phy_info.page_per_blk	= p_nand_info->page_per_blk;
1096ba0501acSDingqiang Lin 	g_nand_phy_info.page_per_slc_blk = p_nand_info->page_per_blk;
1097c84f0ed8SJon Lin 	g_nand_phy_info.byte_per_sec	= SFC_NAND_SECTOR_SIZE;
1098ba0501acSDingqiang Lin 	g_nand_phy_info.sec_per_page	= p_nand_info->sec_per_page;
1099ba0501acSDingqiang Lin 	g_nand_phy_info.sec_per_blk	= p_nand_info->sec_per_page *
1100ba0501acSDingqiang Lin 					  p_nand_info->page_per_blk;
1101ba0501acSDingqiang Lin 	g_nand_phy_info.reserved_blk	= 8;
1102ba0501acSDingqiang Lin 	g_nand_phy_info.blk_per_die	= p_nand_info->plane_per_die *
1103ba0501acSDingqiang Lin 					  p_nand_info->blk_per_plane;
1104ba0501acSDingqiang Lin 	g_nand_phy_info.ecc_bits	= p_nand_info->max_ecc_bits;
1105ba0501acSDingqiang Lin 
1106ba0501acSDingqiang Lin 	/* driver register */
1107ba0501acSDingqiang Lin 	g_nand_ops.get_bad_blk_list	= sfc_nand_get_bad_block_list;
1108ba0501acSDingqiang Lin 	g_nand_ops.erase_blk		= sfc_nand_erase_block;
1109ba0501acSDingqiang Lin 	g_nand_ops.prog_page		= sfc_nand_prog_page;
1110ba0501acSDingqiang Lin 	g_nand_ops.read_page		= sfc_nand_read_page;
111157d18453Sjon.lin 	g_nand_ops.bch_sel		= NULL;
1112ba0501acSDingqiang Lin }
1113ba0501acSDingqiang Lin 
1114a6fcac41SJon Lin static int sfc_nand_enable_QE(void)
1115ba0501acSDingqiang Lin {
1116ba0501acSDingqiang Lin 	int ret = SFC_OK;
1117ba0501acSDingqiang Lin 	u8 status;
1118ba0501acSDingqiang Lin 
1119f28847a8SJon Lin 	ret = sfc_nand_read_feature(0xB0, &status);
1120ba0501acSDingqiang Lin 
1121ba0501acSDingqiang Lin 	if (ret != SFC_OK)
1122ba0501acSDingqiang Lin 		return ret;
1123ba0501acSDingqiang Lin 
1124f28847a8SJon Lin 	if (status & 1)   /* is QE bit set */
1125ba0501acSDingqiang Lin 		return SFC_OK;
1126ba0501acSDingqiang Lin 
1127f28847a8SJon Lin 	status |= 1;
1128ba0501acSDingqiang Lin 
1129f28847a8SJon Lin 	return sfc_nand_write_feature(0xB0, status);
1130ba0501acSDingqiang Lin }
1131ba0501acSDingqiang Lin 
1132ba0501acSDingqiang Lin u32 sfc_nand_init(void)
1133ba0501acSDingqiang Lin {
1134c84f0ed8SJon Lin 	u8 status, id_byte[8];
1135ba0501acSDingqiang Lin 
1136c84f0ed8SJon Lin 	sfc_nand_read_id(id_byte);
1137c84f0ed8SJon Lin 	rkflash_print_error("sfc_nand id: %x %x %x\n",
1138ba0501acSDingqiang Lin 			    id_byte[0], id_byte[1], id_byte[2]);
1139f28847a8SJon Lin 
1140ba0501acSDingqiang Lin 	if (id_byte[0] == 0xFF || id_byte[0] == 0x00)
114158463f4dSJon Lin 		return (u32)FTL_NO_FLASH;
1142ba0501acSDingqiang Lin 
1143a6fcac41SJon Lin 	p_nand_info = sfc_nand_get_info(id_byte);
1144f28847a8SJon Lin 
114545292245SJon Lin 	if (!p_nand_info) {
114645292245SJon Lin 		pr_err("The device not support yet!\n");
114745292245SJon Lin 
114858463f4dSJon Lin 		return (u32)FTL_UNSUPPORTED_FLASH;
114945292245SJon Lin 	}
1150ba0501acSDingqiang Lin 
1151ba0501acSDingqiang Lin 	sfc_nand_dev.manufacturer = id_byte[0];
1152ba0501acSDingqiang Lin 	sfc_nand_dev.mem_type = id_byte[1];
1153c84f0ed8SJon Lin 	sfc_nand_dev.capacity = p_nand_info->density;
1154c84f0ed8SJon Lin 	sfc_nand_dev.block_size = p_nand_info->page_per_blk * p_nand_info->sec_per_page;
1155c84f0ed8SJon Lin 	sfc_nand_dev.page_size = p_nand_info->sec_per_page;
1156ba0501acSDingqiang Lin 
1157ba0501acSDingqiang Lin 	/* disable block lock */
1158ba0501acSDingqiang Lin 	sfc_nand_write_feature(0xA0, 0);
1159ba0501acSDingqiang Lin 	sfc_nand_dev.read_lines = DATA_LINES_X1;
1160ba0501acSDingqiang Lin 	sfc_nand_dev.prog_lines = DATA_LINES_X1;
1161f28847a8SJon Lin 	sfc_nand_dev.page_read_cmd = 0x03;
1162f28847a8SJon Lin 	sfc_nand_dev.page_prog_cmd = 0x02;
1163629111d3SJon Lin 	sfc_nand_dev.recheck_buffer = ftl_malloc(SFC_NAND_PAGE_MAX_SIZE);
1164629111d3SJon Lin 	if (!sfc_nand_dev.recheck_buffer) {
1165629111d3SJon Lin 		rkflash_print_error("%s recheck_buffer alloc failed\n", __func__);
1166629111d3SJon Lin 		return -1;
1167629111d3SJon Lin 	}
1168f28847a8SJon Lin 
1169ba0501acSDingqiang Lin 	if (p_nand_info->feature & FEA_4BIT_READ) {
1170f28847a8SJon Lin 		if ((p_nand_info->has_qe_bits && sfc_nand_enable_QE() == SFC_OK) ||
1171f28847a8SJon Lin 		    !p_nand_info->has_qe_bits) {
1172ba0501acSDingqiang Lin 			sfc_nand_dev.read_lines = DATA_LINES_X4;
1173f28847a8SJon Lin 			sfc_nand_dev.page_read_cmd = 0x6b;
1174ba0501acSDingqiang Lin 		}
1175ba0501acSDingqiang Lin 	}
1176ba0501acSDingqiang Lin 
1177ba0501acSDingqiang Lin 	if (p_nand_info->feature & FEA_4BIT_PROG &&
1178ba0501acSDingqiang Lin 	    sfc_nand_dev.read_lines == DATA_LINES_X4) {
1179ba0501acSDingqiang Lin 		sfc_nand_dev.prog_lines = DATA_LINES_X4;
1180f28847a8SJon Lin 		sfc_nand_dev.page_prog_cmd = 0x32;
1181ba0501acSDingqiang Lin 	}
1182ba0501acSDingqiang Lin 
1183ba0501acSDingqiang Lin 	sfc_nand_read_feature(0xA0, &status);
1184c84f0ed8SJon Lin 	rkflash_print_info("sfc_nand A0 = 0x%x\n", status);
1185ba0501acSDingqiang Lin 	sfc_nand_read_feature(0xB0, &status);
1186c84f0ed8SJon Lin 	rkflash_print_info("sfc_nand B0 = 0x%x\n", status);
1187c84f0ed8SJon Lin 	rkflash_print_info("read_lines = %x\n", sfc_nand_dev.read_lines);
1188c84f0ed8SJon Lin 	rkflash_print_info("prog_lines = %x\n", sfc_nand_dev.prog_lines);
1189c84f0ed8SJon Lin 	rkflash_print_info("page_read_cmd = %x\n", sfc_nand_dev.page_read_cmd);
1190c84f0ed8SJon Lin 	rkflash_print_info("page_prog_cmd = %x\n", sfc_nand_dev.page_prog_cmd);
1191ba0501acSDingqiang Lin 
1192ba0501acSDingqiang Lin 	return SFC_OK;
1193ba0501acSDingqiang Lin }
1194ba0501acSDingqiang Lin 
1195c84f0ed8SJon Lin void sfc_nand_deinit(void)
1196ba0501acSDingqiang Lin {
1197c84f0ed8SJon Lin 	/* to-do */
1198629111d3SJon Lin 	kfree(sfc_nand_dev.recheck_buffer);
1199ba0501acSDingqiang Lin }
1200c84f0ed8SJon Lin 
1201c84f0ed8SJon Lin struct SFNAND_DEV *sfc_nand_get_private_dev(void)
1202c84f0ed8SJon Lin {
1203c84f0ed8SJon Lin 	return &sfc_nand_dev;
1204c84f0ed8SJon Lin }
1205c84f0ed8SJon Lin 
1206