xref: /rk3399_rockchip-uboot/drivers/rkflash/sfc_nand.c (revision 7bdae1e3d0e6cbc7b1a5300fcffd292d465a9b43)
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);
26f28847a8SJon Lin 
27ba0501acSDingqiang Lin static struct nand_info spi_nand_tbl[] = {
28ba0501acSDingqiang Lin 	/* TC58CVG0S0HxAIx */
29b833c879SJon Lin 	{ 0x98, 0xC2, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
30ba0501acSDingqiang Lin 	/* TC58CVG1S0HxAIx */
31b833c879SJon Lin 	{ 0x98, 0xCB, 0x00, 4, 0x40, 2, 1024, 0x00, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
32a6fcac41SJon Lin 	/* TC58CVG2S0HRAIJ */
33b833c879SJon Lin 	{ 0x98, 0xED, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 0, { 0x04, 0x0C, 0x08, 0x10 }, &sfc_nand_get_ecc_status0 },
34a6fcac41SJon Lin 	/* TC58CVG1S3HRAIJ */
35b833c879SJon Lin 	{ 0x98, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
36a6fcac41SJon Lin 	/* TC58CVG0S3HRAIJ */
37b833c879SJon Lin 	{ 0x98, 0xE2, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
38f28847a8SJon Lin 
39f28847a8SJon Lin 	/* MX35LF1GE4AB */
40b833c879SJon Lin 	{ 0xC2, 0x12, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
41f28847a8SJon Lin 	/* MX35LF2GE4AB */
42b833c879SJon Lin 	{ 0xC2, 0x22, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
43f28847a8SJon Lin 	/* MX35LF2GE4AD */
44b833c879SJon Lin 	{ 0xC2, 0x26, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
45f28847a8SJon Lin 	/* MX35LF4GE4AD */
46362b1be1SJon Lin 	{ 0xC2, 0x37, 0x00, 8, 0x40, 1, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status0 },
47362b1be1SJon Lin 	/* MX35UF1GE4AC */
48362b1be1SJon Lin 	{ 0xC2, 0x92, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
49362b1be1SJon Lin 	/* MX35UF2GE4AC */
50362b1be1SJon Lin 	{ 0xC2, 0xA2, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
51f28847a8SJon Lin 
52f28847a8SJon Lin 	/* GD5F1GQ4UAYIG */
53b833c879SJon Lin 	{ 0xC8, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
54f28847a8SJon Lin 	/* GD5F1GQ4RB9IGR */
55b833c879SJon Lin 	{ 0xC8, 0xD1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
56f28847a8SJon Lin 	/* GD5F2GQ40BY2GR */
57b833c879SJon Lin 	{ 0xC8, 0xD2, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
58f28847a8SJon Lin 	/* GD5F1GQ5UEYIG */
59b833c879SJon Lin 	{ 0xC8, 0x51, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
60f28847a8SJon Lin 	/* GD5F2GQ5UEYIG */
61b833c879SJon Lin 	{ 0xC8, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
62f28847a8SJon Lin 	/* GD5F1GQ4R */
63b833c879SJon Lin 	{ 0xC8, 0xC1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
64362b1be1SJon Lin 	/* GD5F4GQ6RExxG 1*4096 */
65362b1be1SJon Lin 	{ 0xC8, 0x45, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 1, { 0x04, 0x08, 0X14, 0x18 }, &sfc_nand_get_ecc_status2 },
66362b1be1SJon Lin 	/* GD5F4GQ6UExxG 1*4096 */
67362b1be1SJon Lin 	{ 0xC8, 0x55, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 1, { 0x04, 0x08, 0X14, 0x18 }, &sfc_nand_get_ecc_status2 },
688a654f32SJon Lin 	/* GD5F1GQ4UExxH */
698a654f32SJon Lin 	{ 0xC8, 0xD9, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
70bf620bf6SJon Lin 	/* GD5F1GQ5REYIG */
71bf620bf6SJon Lin 	{ 0xC8, 0x41, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
72bf620bf6SJon Lin 	/* GD5F2GQ5REYIG */
73bf620bf6SJon Lin 	{ 0xC8, 0x42, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
74bf620bf6SJon Lin 	/* GD5F2GM7RxG */
75bf620bf6SJon Lin 	{ 0xC8, 0x82, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
76bf620bf6SJon Lin 	/* GD5F2GM7UxG */
77bf620bf6SJon Lin 	{ 0xC8, 0x92, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
7845292245SJon Lin 	/* GD5F1GM7UxG */
7945292245SJon Lin 	{ 0xC8, 0x91, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
80f28847a8SJon Lin 
81f28847a8SJon Lin 	/* W25N01GV */
82b833c879SJon Lin 	{ 0xEF, 0xAA, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 },
83b833c879SJon Lin 	/* W25N02KVZEIR */
84b833c879SJon Lin 	{ 0xEF, 0xAA, 0x22, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status0 },
85629111d3SJon Lin 	/* W25N04KVZEIR */
86629111d3SJon Lin 	{ 0xEF, 0xAA, 0x23, 4, 0x40, 1, 4096, 0x4C, 20, 0x8, 0, { 0x04, 0x14, 0x24, 0x34 }, &sfc_nand_get_ecc_status0 },
87f28847a8SJon Lin 	/* W25N01GW */
88*7bdae1e3SJon Lin 	{ 0xEF, 0xBA, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 },
89*7bdae1e3SJon Lin 	/* W25N02KW */
90*7bdae1e3SJon Lin 	{ 0xEF, 0xBA, 0x22, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status0 },
918a654f32SJon Lin 	/* W25N512GVEIG */
928a654f32SJon Lin 	{ 0xEF, 0xAA, 0x20, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 },
93f28847a8SJon Lin 
94f28847a8SJon Lin 	/* HYF2GQ4UAACAE */
95b833c879SJon Lin 	{ 0xC9, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
96f28847a8SJon Lin 	/* HYF1GQ4UDACAE */
97b833c879SJon Lin 	{ 0xC9, 0x21, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
98f28847a8SJon Lin 	/* HYF1GQ4UPACAE */
99b833c879SJon Lin 	{ 0xC9, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
100f28847a8SJon Lin 	/* HYF2GQ4UDACAE */
101b833c879SJon Lin 	{ 0xC9, 0x22, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
102f28847a8SJon Lin 	/* HYF2GQ4UHCCAE */
103b833c879SJon Lin 	{ 0xC9, 0x5A, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
104f28847a8SJon Lin 	/* HYF4GQ4UAACBE */
105b833c879SJon Lin 	{ 0xC9, 0xD4, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x4, 1, { 0x20, 0x40, 0x24, 0x44 }, &sfc_nand_get_ecc_status0 },
106f28847a8SJon Lin 
107f28847a8SJon Lin 	/* FS35ND01G-S1 */
108b833c879SJon Lin 	{ 0xCD, 0xB1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
109f28847a8SJon Lin 	/* FS35ND02G-S2 */
110b833c879SJon Lin 	{ 0xCD, 0xA2, 0x00, 4, 0x40, 1, 2048, 0x00, 19, 0x4, 0, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
11158463f4dSJon Lin 	/* FS35ND01G-S1Y2 */
112b833c879SJon Lin 	{ 0xCD, 0xEA, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
113f1b20f5aSJon Lin 	/* FS35ND02G-S3Y2 */
114b833c879SJon Lin 	{ 0xCD, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
115f28847a8SJon Lin 	/* FS35ND04G-S2Y2 1*4096 */
116b833c879SJon Lin 	{ 0xCD, 0xEC, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
117bf620bf6SJon Lin 	/* F35SQA001G */
118bf620bf6SJon Lin 	{ 0xCD, 0x71, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
11945292245SJon Lin 	/* F35SQA002G */
12045292245SJon Lin 	{ 0xCD, 0x72, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
121f28847a8SJon Lin 
122f28847a8SJon Lin 	/* DS35Q1GA-IB */
123b833c879SJon Lin 	{ 0xE5, 0x71, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
124f28847a8SJon Lin 	/* DS35Q2GA-IB */
125b833c879SJon Lin 	{ 0xE5, 0x72, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
126f28847a8SJon Lin 	/* DS35M1GA-1B */
127b833c879SJon Lin 	{ 0xE5, 0x21, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
128bf620bf6SJon Lin 	/* DS35M2GA-IB */
129bf620bf6SJon Lin 	{ 0xE5, 0x22, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
130629111d3SJon Lin 	/* DS35Q2GB-IB */
131629111d3SJon Lin 	{ 0xE5, 0xF2, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
132bf620bf6SJon Lin 	/* DS35M1GB-IB */
133bf620bf6SJon Lin 	{ 0xE5, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
134f28847a8SJon Lin 
135f28847a8SJon Lin 	/* EM73C044VCC-H */
136b833c879SJon Lin 	{ 0xD5, 0x22, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
137f28847a8SJon Lin 	/* EM73D044VCE-H */
138b833c879SJon Lin 	{ 0xD5, 0x20, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
139f28847a8SJon Lin 	/* EM73E044SNA-G */
140b833c879SJon Lin 	{ 0xD5, 0x03, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x28, 0x08, 0x2C }, &sfc_nand_get_ecc_status0 },
141629111d3SJon Lin 	/* EM73C044VCF-H */
142629111d3SJon Lin 	{ 0xD5, 0x25, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
143f28847a8SJon Lin 
144f28847a8SJon Lin 	/* XT26G02A */
145362b1be1SJon Lin 	{ 0x0B, 0xE2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
146f28847a8SJon Lin 	/* XT26G01A */
147362b1be1SJon Lin 	{ 0x0B, 0xE1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
148f28847a8SJon Lin 	/* XT26G04A */
149362b1be1SJon Lin 	{ 0x0B, 0xE3, 0x00, 4, 0x80, 1, 2048, 0x4C, 20, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
150f28847a8SJon Lin 	/* XT26G01B */
151362b1be1SJon Lin 	{ 0x0B, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
152f28847a8SJon Lin 	/* XT26G02B */
153362b1be1SJon Lin 	{ 0x0B, 0xF2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
154362b1be1SJon Lin 	/* XT26G01C */
155362b1be1SJon Lin 	{ 0x0B, 0x11, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 },
156362b1be1SJon Lin 	/* XT26G02C */
157362b1be1SJon Lin 	{ 0x0B, 0x12, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 },
158362b1be1SJon Lin 	/* XT26G04C */
159362b1be1SJon Lin 	{ 0x0B, 0x13, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status7 },
160629111d3SJon Lin 	/* XT26G11C */
161629111d3SJon Lin 	{ 0x0B, 0x15, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
162a80fd396SJon Lin 
163362b1be1SJon Lin 	/* MT29F2G01ABA, XT26G02E, F50L2G41XA */
164629111d3SJon Lin 	{ 0x2C, 0x24, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x8, 0, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
165629111d3SJon Lin 	/* MT29F1G01ABA, F50L1G41XA */
166629111d3SJon Lin 	{ 0x2C, 0x14, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 0, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
167a80fd396SJon Lin 
168a80fd396SJon Lin 	/* FM25S01 */
169b833c879SJon Lin 	{ 0xA1, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x00, 0x04, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
170a80fd396SJon Lin 	/* FM25S01A */
171b833c879SJon Lin 	{ 0xA1, 0xE4, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
172a80fd396SJon Lin 	/* FM25S02A */
173b833c879SJon Lin 	{ 0xA1, 0xE5, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
174*7bdae1e3SJon Lin 	/* FM25LS01 */
175*7bdae1e3SJon Lin 	{ 0xA1, 0xA5, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
176f28847a8SJon Lin 
177f28847a8SJon Lin 	/* IS37SML01G1 */
178b833c879SJon Lin 	{ 0xC8, 0x21, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x1, 0, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
179f28847a8SJon Lin 	/* F50L1G41LB */
180b833c879SJon Lin 	{ 0xC8, 0x01, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
181f28847a8SJon Lin 	/* ATO25D1GA */
182b833c879SJon Lin 	{ 0x9B, 0x12, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x1, 1, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
183362b1be1SJon Lin 	/* BWJX08K-2Gb */
184362b1be1SJon Lin 	{ 0xBC, 0xB3, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x10, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
185629111d3SJon Lin 	/* JS28U1GQSCAHG-83 */
186629111d3SJon Lin 	{ 0xBF, 0x21, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x4, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status8 },
1878a654f32SJon Lin 	/* SGM7000I-S24W1GH */
1888a654f32SJon Lin 	{ 0xEA, 0xC1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
189bf620bf6SJon Lin 	/* TX25G01 */
190bf620bf6SJon Lin 	{ 0xA1, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status8 },
191ba0501acSDingqiang Lin };
192ba0501acSDingqiang Lin 
193ba0501acSDingqiang Lin static struct nand_info *p_nand_info;
194ba0501acSDingqiang Lin static u32 gp_page_buf[SFC_NAND_PAGE_MAX_SIZE / 4];
195ba0501acSDingqiang Lin static struct SFNAND_DEV sfc_nand_dev;
196ba0501acSDingqiang Lin 
197a6fcac41SJon Lin static struct nand_info *sfc_nand_get_info(u8 *nand_id)
198ba0501acSDingqiang Lin {
199ba0501acSDingqiang Lin 	u32 i;
200ba0501acSDingqiang Lin 
201ba0501acSDingqiang Lin 	for (i = 0; i < ARRAY_SIZE(spi_nand_tbl); i++) {
202b833c879SJon Lin 		if (spi_nand_tbl[i].id0 == nand_id[0] &&
203b833c879SJon Lin 		    spi_nand_tbl[i].id1 == nand_id[1]) {
204b833c879SJon Lin 			if (spi_nand_tbl[i].id2 &&
205b833c879SJon Lin 			    spi_nand_tbl[i].id2 != nand_id[2])
206b833c879SJon Lin 				continue;
207b833c879SJon Lin 
208ba0501acSDingqiang Lin 			return &spi_nand_tbl[i];
209ba0501acSDingqiang Lin 		}
210b833c879SJon Lin 	}
211f28847a8SJon Lin 
212ba0501acSDingqiang Lin 	return NULL;
213ba0501acSDingqiang Lin }
214ba0501acSDingqiang Lin 
215ba0501acSDingqiang Lin static int sfc_nand_write_en(void)
216ba0501acSDingqiang Lin {
217ba0501acSDingqiang Lin 	int ret;
21858463f4dSJon Lin 	struct rk_sfc_op op;
219ba0501acSDingqiang Lin 
22058463f4dSJon Lin 	op.sfcmd.d32 = 0;
22158463f4dSJon Lin 	op.sfcmd.b.cmd = CMD_WRITE_EN;
22258463f4dSJon Lin 
22358463f4dSJon Lin 	op.sfctrl.d32 = 0;
22458463f4dSJon Lin 
22558463f4dSJon Lin 	ret = sfc_request(&op, 0, NULL, 0);
226ba0501acSDingqiang Lin 	return ret;
227ba0501acSDingqiang Lin }
228ba0501acSDingqiang Lin 
229ba0501acSDingqiang Lin static int sfc_nand_rw_preset(void)
230ba0501acSDingqiang Lin {
231ba0501acSDingqiang Lin 	int ret;
23258463f4dSJon Lin 	struct rk_sfc_op op;
233ba0501acSDingqiang Lin 
23458463f4dSJon Lin 	op.sfcmd.d32 = 0;
235f28847a8SJon Lin 	op.sfcmd.b.cmd = 0xff;
236f28847a8SJon Lin 	op.sfcmd.b.cs = 2;
237ba0501acSDingqiang Lin 
23858463f4dSJon Lin 	op.sfctrl.d32 = 0;
23958463f4dSJon Lin 	op.sfctrl.b.datalines = 2;
240f28847a8SJon Lin 	op.sfctrl.b.cmdlines = 2;
241f28847a8SJon Lin 	op.sfctrl.b.addrlines = 2;
24258463f4dSJon Lin 
243f28847a8SJon Lin 	ret = sfc_request(&op, 0, NULL, 0);
244ba0501acSDingqiang Lin 	return ret;
245ba0501acSDingqiang Lin }
246ba0501acSDingqiang Lin 
247ba0501acSDingqiang Lin static int sfc_nand_read_feature(u8 addr, u8 *data)
248ba0501acSDingqiang Lin {
249ba0501acSDingqiang Lin 	int ret;
25058463f4dSJon Lin 	struct rk_sfc_op op;
251ba0501acSDingqiang Lin 
25258463f4dSJon Lin 	op.sfcmd.d32 = 0;
25358463f4dSJon Lin 	op.sfcmd.b.cmd = 0x0F;
25458463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
25558463f4dSJon Lin 
25658463f4dSJon Lin 	op.sfctrl.d32 = 0;
25758463f4dSJon Lin 	op.sfctrl.b.addrbits = 8;
25858463f4dSJon Lin 
259ba0501acSDingqiang Lin 	*data = 0;
260ba0501acSDingqiang Lin 
26158463f4dSJon Lin 	ret = sfc_request(&op, addr, data, 1);
262f28847a8SJon Lin 
263ba0501acSDingqiang Lin 	if (ret != SFC_OK)
264ba0501acSDingqiang Lin 		return ret;
265f28847a8SJon Lin 
266ba0501acSDingqiang Lin 	return SFC_OK;
267ba0501acSDingqiang Lin }
268ba0501acSDingqiang Lin 
269ba0501acSDingqiang Lin static int sfc_nand_write_feature(u32 addr, u8 status)
270ba0501acSDingqiang Lin {
271ba0501acSDingqiang Lin 	int ret;
27258463f4dSJon Lin 	struct rk_sfc_op op;
273ba0501acSDingqiang Lin 
274ba0501acSDingqiang Lin 	sfc_nand_write_en();
275ba0501acSDingqiang Lin 
27658463f4dSJon Lin 	op.sfcmd.d32 = 0;
27758463f4dSJon Lin 	op.sfcmd.b.cmd = 0x1F;
27858463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
27958463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
280ba0501acSDingqiang Lin 
28158463f4dSJon Lin 	op.sfctrl.d32 = 0;
28258463f4dSJon Lin 	op.sfctrl.b.addrbits = 8;
28358463f4dSJon Lin 
28458463f4dSJon Lin 	ret = sfc_request(&op, addr, &status, 1);
285f28847a8SJon Lin 
286ba0501acSDingqiang Lin 	if (ret != SFC_OK)
287ba0501acSDingqiang Lin 		return ret;
288f28847a8SJon Lin 
289ba0501acSDingqiang Lin 	return ret;
290ba0501acSDingqiang Lin }
291ba0501acSDingqiang Lin 
292ba0501acSDingqiang Lin static int sfc_nand_wait_busy(u8 *data, int timeout)
293ba0501acSDingqiang Lin {
294ba0501acSDingqiang Lin 	int ret;
295ba0501acSDingqiang Lin 	int i;
296ba0501acSDingqiang Lin 	u8 status;
297ba0501acSDingqiang Lin 
298ba0501acSDingqiang Lin 	*data = 0;
299f28847a8SJon Lin 
300ba0501acSDingqiang Lin 	for (i = 0; i < timeout; i++) {
301ba0501acSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
302f28847a8SJon Lin 
303ba0501acSDingqiang Lin 		if (ret != SFC_OK)
304ba0501acSDingqiang Lin 			return ret;
305f28847a8SJon Lin 
306ba0501acSDingqiang Lin 		*data = status;
307f28847a8SJon Lin 
308ba0501acSDingqiang Lin 		if (!(status & (1 << 0)))
309ba0501acSDingqiang Lin 			return SFC_OK;
310f28847a8SJon Lin 
311ba0501acSDingqiang Lin 		sfc_delay(1);
312ba0501acSDingqiang Lin 	}
313f28847a8SJon Lin 
314f28847a8SJon Lin 	return SFC_NAND_WAIT_TIME_OUT;
315ba0501acSDingqiang Lin }
316ba0501acSDingqiang Lin 
3176281205aSDingqiang Lin /*
3186281205aSDingqiang Lin  * ecc default:
319a6fcac41SJon Lin  * ecc bits: 0xC0[4,5]
320f28847a8SJon Lin  * 0b00, No bit errors were detected
321f28847a8SJon Lin  * 0b01, Bit errors were detected and corrected.
322f28847a8SJon Lin  * 0b10, Multiple bit errors were detected and not corrected.
323f28847a8SJon Lin  * 0b11, Bits errors were detected and corrected, bit error count
324362b1be1SJon Lin  *	reach the bit flip detection threshold
3256281205aSDingqiang Lin  */
326f28847a8SJon Lin static u32 sfc_nand_get_ecc_status0(void)
3276281205aSDingqiang Lin {
32858463f4dSJon Lin 	u32 ret;
3296281205aSDingqiang Lin 	u32 i;
3306281205aSDingqiang Lin 	u8 ecc;
3316281205aSDingqiang Lin 	u8 status;
3326281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
3336281205aSDingqiang Lin 
3346281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
3356281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
336f28847a8SJon Lin 
3376281205aSDingqiang Lin 		if (ret != SFC_OK)
3386281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
339f28847a8SJon Lin 
3406281205aSDingqiang Lin 		if (!(status & (1 << 0)))
3416281205aSDingqiang Lin 			break;
342f28847a8SJon Lin 
3436281205aSDingqiang Lin 		sfc_delay(1);
3446281205aSDingqiang Lin 	}
3456281205aSDingqiang Lin 
3466281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
3476281205aSDingqiang Lin 
3486281205aSDingqiang Lin 	if (ecc <= 1)
3496281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
3506281205aSDingqiang Lin 	else if (ecc == 2)
35158463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
3526281205aSDingqiang Lin 	else
3536281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
3546281205aSDingqiang Lin 
3556281205aSDingqiang Lin 	return ret;
3566281205aSDingqiang Lin }
3576281205aSDingqiang Lin 
3586281205aSDingqiang Lin /*
3596281205aSDingqiang Lin  * ecc spectial type1:
360a6fcac41SJon Lin  * ecc bits: 0xC0[4,5]
361f28847a8SJon Lin  * 0b00, No bit errors were detected;
362f28847a8SJon Lin  * 0b01, Bits errors were detected and corrected, bit error count
3636281205aSDingqiang Lin  *	may reach the bit flip detection threshold;
364f28847a8SJon Lin  * 0b10, Multiple bit errors were detected and not corrected;
365f28847a8SJon Lin  * 0b11, Reserved.
3666281205aSDingqiang Lin  */
367f28847a8SJon Lin static u32 sfc_nand_get_ecc_status1(void)
3686281205aSDingqiang Lin {
36958463f4dSJon Lin 	u32 ret;
3706281205aSDingqiang Lin 	u32 i;
3716281205aSDingqiang Lin 	u8 ecc;
3726281205aSDingqiang Lin 	u8 status;
3736281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
3746281205aSDingqiang Lin 
3756281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
3766281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
377f28847a8SJon Lin 
3786281205aSDingqiang Lin 		if (ret != SFC_OK)
3796281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
380f28847a8SJon Lin 
3816281205aSDingqiang Lin 		if (!(status & (1 << 0)))
3826281205aSDingqiang Lin 			break;
383f28847a8SJon Lin 
3846281205aSDingqiang Lin 		sfc_delay(1);
3856281205aSDingqiang Lin 	}
3866281205aSDingqiang Lin 
3876281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
3886281205aSDingqiang Lin 
3896281205aSDingqiang Lin 	if (ecc == 0)
3906281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
3916281205aSDingqiang Lin 	else if (ecc == 1)
3926281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
3936281205aSDingqiang Lin 	else
39458463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
3956281205aSDingqiang Lin 
3966281205aSDingqiang Lin 	return ret;
3976281205aSDingqiang Lin }
3986281205aSDingqiang Lin 
3996281205aSDingqiang Lin /*
400d9cdd318SJon Lin  * ecc spectial type2:
401a6fcac41SJon Lin  * ecc bits: 0xC0[4,5] 0xF0[4,5]
402f28847a8SJon Lin  * [0b0000, 0b0011], No bit errors were detected;
403f28847a8SJon Lin  * [0b0100, 0b0111], Bit errors were detected and corrected. Not
404d9cdd318SJon Lin  *	reach Flipping Bits;
405f28847a8SJon Lin  * [0b1000, 0b1011], Multiple bit errors were detected and
406c84f0ed8SJon Lin  *	not corrected.
407f28847a8SJon Lin  * [0b1100, 0b1111], reserved.
408d9cdd318SJon Lin  */
409f28847a8SJon Lin static u32 sfc_nand_get_ecc_status2(void)
410d9cdd318SJon Lin {
41158463f4dSJon Lin 	u32 ret;
412d9cdd318SJon Lin 	u32 i;
413d9cdd318SJon Lin 	u8 ecc;
414d9cdd318SJon Lin 	u8 status, status1;
415d9cdd318SJon Lin 	u32 timeout = 1000 * 1000;
416d9cdd318SJon Lin 
417d9cdd318SJon Lin 	for (i = 0; i < timeout; i++) {
418d9cdd318SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
419f28847a8SJon Lin 
420d9cdd318SJon Lin 		if (ret != SFC_OK)
421d9cdd318SJon Lin 			return SFC_NAND_ECC_ERROR;
422f28847a8SJon Lin 
423d9cdd318SJon Lin 		ret = sfc_nand_read_feature(0xF0, &status1);
424f28847a8SJon Lin 
425d9cdd318SJon Lin 		if (ret != SFC_OK)
426d9cdd318SJon Lin 			return SFC_NAND_ECC_ERROR;
427f28847a8SJon Lin 
428d9cdd318SJon Lin 		if (!(status & (1 << 0)))
429d9cdd318SJon Lin 			break;
430f28847a8SJon Lin 
431d9cdd318SJon Lin 		sfc_delay(1);
432d9cdd318SJon Lin 	}
433d9cdd318SJon Lin 
434d9cdd318SJon Lin 	ecc = (status >> 4) & 0x03;
435d9cdd318SJon Lin 	ecc = (ecc << 2) | ((status1 >> 4) & 0x03);
436f28847a8SJon Lin 
437d9cdd318SJon Lin 	if (ecc < 7)
438d9cdd318SJon Lin 		ret = SFC_NAND_ECC_OK;
439d9cdd318SJon Lin 	else if (ecc == 7)
440d9cdd318SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
441d9cdd318SJon Lin 	else
44258463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
443d9cdd318SJon Lin 
444d9cdd318SJon Lin 	return ret;
445d9cdd318SJon Lin }
446d9cdd318SJon Lin 
447d9cdd318SJon Lin /*
4486281205aSDingqiang Lin  * ecc spectial type3:
449a6fcac41SJon Lin  * ecc bits: 0xC0[4,5] 0xF0[4,5]
450f28847a8SJon Lin  * [0b0000, 0b0011], No bit errors were detected;
451f28847a8SJon Lin  * [0b0100, 0b0111], Bit errors were detected and corrected. Not
4526281205aSDingqiang Lin  *	reach Flipping Bits;
453f28847a8SJon Lin  * [0b1000, 0b1011], Multiple bit errors were detected and
4546281205aSDingqiang Lin  *	not corrected.
455f28847a8SJon Lin  * [0b1100, 0b1111], Bit error count equals the bit flip
4566281205aSDingqiang Lin  *	detectio nthreshold
4576281205aSDingqiang Lin  */
458f28847a8SJon Lin static u32 sfc_nand_get_ecc_status3(void)
4596281205aSDingqiang Lin {
46058463f4dSJon Lin 	u32 ret;
4616281205aSDingqiang Lin 	u32 i;
4626281205aSDingqiang Lin 	u8 ecc;
4636281205aSDingqiang Lin 	u8 status, status1;
4646281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
4656281205aSDingqiang Lin 
4666281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
4676281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
468f28847a8SJon Lin 
4696281205aSDingqiang Lin 		if (ret != SFC_OK)
4706281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
471f28847a8SJon Lin 
4726281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xF0, &status1);
473f28847a8SJon Lin 
4746281205aSDingqiang Lin 		if (ret != SFC_OK)
4756281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
476f28847a8SJon Lin 
4776281205aSDingqiang Lin 		if (!(status & (1 << 0)))
4786281205aSDingqiang Lin 			break;
479f28847a8SJon Lin 
4806281205aSDingqiang Lin 		sfc_delay(1);
4816281205aSDingqiang Lin 	}
4826281205aSDingqiang Lin 
4836281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
4846281205aSDingqiang Lin 	ecc = (ecc << 2) | ((status1 >> 4) & 0x03);
485f28847a8SJon Lin 
4866281205aSDingqiang Lin 	if (ecc < 7)
4876281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
4886281205aSDingqiang Lin 	else if (ecc == 7 || ecc >= 12)
4896281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
4906281205aSDingqiang Lin 	else
49158463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
4926281205aSDingqiang Lin 
4936281205aSDingqiang Lin 	return ret;
4946281205aSDingqiang Lin }
4956281205aSDingqiang Lin 
49625098c06SDingqiang Lin /*
49725098c06SDingqiang Lin  * ecc spectial type4:
498a6fcac41SJon Lin  * ecc bits: 0xC0[2,5]
499f28847a8SJon Lin  * [0b0000], No bit errors were detected;
500f28847a8SJon Lin  * [0b0001, 0b0111], Bit errors were detected and corrected. Not
50125098c06SDingqiang Lin  *	reach Flipping Bits;
502f28847a8SJon Lin  * [0b1000], Multiple bit errors were detected and
50325098c06SDingqiang Lin  *	not corrected.
504f28847a8SJon Lin  * [0b1100], Bit error count equals the bit flip
50525098c06SDingqiang Lin  *	detection threshold
50625098c06SDingqiang Lin  * else, reserved
50725098c06SDingqiang Lin  */
508f28847a8SJon Lin static u32 sfc_nand_get_ecc_status4(void)
50925098c06SDingqiang Lin {
51058463f4dSJon Lin 	u32 ret;
51125098c06SDingqiang Lin 	u32 i;
51225098c06SDingqiang Lin 	u8 ecc;
51325098c06SDingqiang Lin 	u8 status;
51425098c06SDingqiang Lin 	u32 timeout = 1000 * 1000;
51525098c06SDingqiang Lin 
51625098c06SDingqiang Lin 	for (i = 0; i < timeout; i++) {
51725098c06SDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
518f28847a8SJon Lin 
51925098c06SDingqiang Lin 		if (ret != SFC_OK)
52025098c06SDingqiang Lin 			return SFC_NAND_ECC_ERROR;
521f28847a8SJon Lin 
52225098c06SDingqiang Lin 		if (!(status & (1 << 0)))
52325098c06SDingqiang Lin 			break;
524f28847a8SJon Lin 
52525098c06SDingqiang Lin 		sfc_delay(1);
52625098c06SDingqiang Lin 	}
52725098c06SDingqiang Lin 
52825098c06SDingqiang Lin 	ecc = (status >> 2) & 0x0f;
529f28847a8SJon Lin 
53025098c06SDingqiang Lin 	if (ecc < 7)
53125098c06SDingqiang Lin 		ret = SFC_NAND_ECC_OK;
53225098c06SDingqiang Lin 	else if (ecc == 7 || ecc == 12)
53325098c06SDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
53425098c06SDingqiang Lin 	else
53558463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
53625098c06SDingqiang Lin 
53725098c06SDingqiang Lin 	return ret;
53825098c06SDingqiang Lin }
53925098c06SDingqiang Lin 
54025098c06SDingqiang Lin /*
54125098c06SDingqiang Lin  * ecc spectial type5:
542a6fcac41SJon Lin  * ecc bits: 0xC0[4,6]
543f28847a8SJon Lin  * [0b000], No bit errors were detected;
544f28847a8SJon Lin  * [0b001, 0b011], Bit errors were detected and corrected. Not
54525098c06SDingqiang Lin  *	reach Flipping Bits;
546f28847a8SJon Lin  * [0b100], Bit error count equals the bit flip
54725098c06SDingqiang Lin  *	detection threshold
548f28847a8SJon Lin  * [0b101, 0b110], Reserved;
549f28847a8SJon Lin  * [0b111], Multiple bit errors were detected and
55025098c06SDingqiang Lin  *	not corrected.
55125098c06SDingqiang Lin  */
552f28847a8SJon Lin static u32 sfc_nand_get_ecc_status5(void)
55325098c06SDingqiang Lin {
55458463f4dSJon Lin 	u32 ret;
55525098c06SDingqiang Lin 	u32 i;
55625098c06SDingqiang Lin 	u8 ecc;
55725098c06SDingqiang Lin 	u8 status;
55825098c06SDingqiang Lin 	u32 timeout = 1000 * 1000;
55925098c06SDingqiang Lin 
56025098c06SDingqiang Lin 	for (i = 0; i < timeout; i++) {
56125098c06SDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
562f28847a8SJon Lin 
56325098c06SDingqiang Lin 		if (ret != SFC_OK)
56425098c06SDingqiang Lin 			return SFC_NAND_ECC_ERROR;
565f28847a8SJon Lin 
56625098c06SDingqiang Lin 		if (!(status & (1 << 0)))
56725098c06SDingqiang Lin 			break;
568f28847a8SJon Lin 
56925098c06SDingqiang Lin 		sfc_delay(1);
57025098c06SDingqiang Lin 	}
57125098c06SDingqiang Lin 
57225098c06SDingqiang Lin 	ecc = (status >> 4) & 0x07;
573f28847a8SJon Lin 
57425098c06SDingqiang Lin 	if (ecc < 4)
57525098c06SDingqiang Lin 		ret = SFC_NAND_ECC_OK;
57625098c06SDingqiang Lin 	else if (ecc == 4)
57725098c06SDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
57825098c06SDingqiang Lin 	else
57958463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
58025098c06SDingqiang Lin 
58125098c06SDingqiang Lin 	return ret;
58225098c06SDingqiang Lin }
58325098c06SDingqiang Lin 
584f28847a8SJon Lin /*
585f28847a8SJon Lin  * ecc spectial type6:
586f28847a8SJon Lin  * ecc bits: 0xC0[4,6]
587f28847a8SJon Lin  * [0b000], No bit errors were detected;
588f28847a8SJon Lin  * [0b001], 1-3 Bit errors were detected and corrected. Not
589f28847a8SJon Lin  *	reach Flipping Bits;
590f28847a8SJon Lin  * [0b010], Multiple bit errors were detected and
591f28847a8SJon Lin  *	not corrected.
592f28847a8SJon Lin  * [0b011], 4-6 Bit errors were detected and corrected. Not
593f28847a8SJon Lin  *	reach Flipping Bits;
594f28847a8SJon Lin  * [0b101], Bit error count equals the bit flip
595f28847a8SJon Lin  *	detectionthreshold
596f28847a8SJon Lin  * others, Reserved.
597f28847a8SJon Lin  */
598f28847a8SJon Lin static u32 sfc_nand_get_ecc_status6(void)
599f28847a8SJon Lin {
600f28847a8SJon Lin 	u32 ret;
601f28847a8SJon Lin 	u32 i;
602f28847a8SJon Lin 	u8 ecc;
603f28847a8SJon Lin 	u8 status;
604f28847a8SJon Lin 	u32 timeout = 1000 * 1000;
605f28847a8SJon Lin 
606f28847a8SJon Lin 	for (i = 0; i < timeout; i++) {
607f28847a8SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
608f28847a8SJon Lin 
609f28847a8SJon Lin 		if (ret != SFC_OK)
610f28847a8SJon Lin 			return SFC_NAND_ECC_ERROR;
611f28847a8SJon Lin 
612f28847a8SJon Lin 		if (!(status & (1 << 0)))
613f28847a8SJon Lin 			break;
614f28847a8SJon Lin 
615f28847a8SJon Lin 		sfc_delay(1);
616f28847a8SJon Lin 	}
617f28847a8SJon Lin 
618f28847a8SJon Lin 	ecc = (status >> 4) & 0x07;
619f28847a8SJon Lin 
620f28847a8SJon Lin 	if (ecc == 0 || ecc == 1 || ecc == 3)
621f28847a8SJon Lin 		ret = SFC_NAND_ECC_OK;
622f28847a8SJon Lin 	else if (ecc == 5)
623f28847a8SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
624f28847a8SJon Lin 	else
625f28847a8SJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
626f28847a8SJon Lin 
627f28847a8SJon Lin 	return ret;
628f28847a8SJon Lin }
629f28847a8SJon Lin 
630362b1be1SJon Lin /*
631362b1be1SJon Lin  * ecc spectial type7:
632362b1be1SJon Lin  * ecc bits: 0xC0[4,7]
633362b1be1SJon Lin  * [0b0000], No bit errors were detected;
634362b1be1SJon Lin  * [0b0001, 0b0111], 1-7 Bit errors were detected and corrected. Not
635362b1be1SJon Lin  *	reach Flipping Bits;
636362b1be1SJon Lin  * [0b1000], 8 Bit errors were detected and corrected. Bit error count
637362b1be1SJon Lin  * 	equals the bit flip detectionthreshold;
638362b1be1SJon Lin  * [0b1111], Bit errors greater than ECC capability(8 bits) and not corrected;
639362b1be1SJon Lin  * others, Reserved.
640362b1be1SJon Lin  */
641362b1be1SJon Lin static u32 sfc_nand_get_ecc_status7(void)
642362b1be1SJon Lin {
643362b1be1SJon Lin 	u32 ret;
644362b1be1SJon Lin 	u32 i;
645362b1be1SJon Lin 	u8 ecc;
646362b1be1SJon Lin 	u8 status;
647362b1be1SJon Lin 	u32 timeout = 1000 * 1000;
648362b1be1SJon Lin 
649362b1be1SJon Lin 	for (i = 0; i < timeout; i++) {
650362b1be1SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
651362b1be1SJon Lin 
652362b1be1SJon Lin 		if (ret != SFC_OK)
653362b1be1SJon Lin 			return SFC_NAND_ECC_ERROR;
654362b1be1SJon Lin 
655362b1be1SJon Lin 		if (!(status & (1 << 0)))
656362b1be1SJon Lin 			break;
657362b1be1SJon Lin 
658362b1be1SJon Lin 		sfc_delay(1);
659362b1be1SJon Lin 	}
660362b1be1SJon Lin 
661362b1be1SJon Lin 	ecc = (status >> 4) & 0xf;
662362b1be1SJon Lin 
663362b1be1SJon Lin 	if (ecc < 7)
664362b1be1SJon Lin 		ret = SFC_NAND_ECC_OK;
665362b1be1SJon Lin 	else if (ecc == 7 || ecc == 8)
666362b1be1SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
667362b1be1SJon Lin 	else
668362b1be1SJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
669362b1be1SJon Lin 
670362b1be1SJon Lin 	return ret;
671362b1be1SJon Lin }
672362b1be1SJon Lin 
673629111d3SJon Lin /*
674629111d3SJon Lin  * ecc spectial type8:
675629111d3SJon Lin  * ecc bits: 0xC0[4,6]
676629111d3SJon Lin  * [0b000], No bit errors were detected;
677629111d3SJon Lin  * [0b001, 0b011], 1~3 Bit errors were detected and corrected. Not
678629111d3SJon Lin  *	reach Flipping Bits;
679629111d3SJon Lin  * [0b100], Bit error count equals the bit flip
680629111d3SJon Lin  *	detection threshold
681629111d3SJon Lin  * others, Reserved.
682629111d3SJon Lin  */
683629111d3SJon Lin static u32 sfc_nand_get_ecc_status8(void)
684629111d3SJon Lin {
685629111d3SJon Lin 	u32 ret;
686629111d3SJon Lin 	u32 i;
687629111d3SJon Lin 	u8 ecc;
688629111d3SJon Lin 	u8 status;
689629111d3SJon Lin 	u32 timeout = 1000 * 1000;
690629111d3SJon Lin 
691629111d3SJon Lin 	for (i = 0; i < timeout; i++) {
692629111d3SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
693629111d3SJon Lin 
694629111d3SJon Lin 		if (ret != SFC_OK)
695629111d3SJon Lin 			return SFC_NAND_ECC_ERROR;
696629111d3SJon Lin 
697629111d3SJon Lin 		if (!(status & (1 << 0)))
698629111d3SJon Lin 			break;
699629111d3SJon Lin 
700629111d3SJon Lin 		sfc_delay(1);
701629111d3SJon Lin 	}
702629111d3SJon Lin 
703629111d3SJon Lin 	ecc = (status >> 4) & 0x07;
704629111d3SJon Lin 
705629111d3SJon Lin 	if (ecc < 4)
706629111d3SJon Lin 		ret = SFC_NAND_ECC_OK;
707629111d3SJon Lin 	else if (ecc == 4)
708629111d3SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
709629111d3SJon Lin 	else
710629111d3SJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
711629111d3SJon Lin 
712629111d3SJon Lin 	return ret;
713629111d3SJon Lin }
714629111d3SJon Lin 
715c84f0ed8SJon Lin u32 sfc_nand_erase_block(u8 cs, u32 addr)
716ba0501acSDingqiang Lin {
717ba0501acSDingqiang Lin 	int ret;
71858463f4dSJon Lin 	struct rk_sfc_op op;
719ba0501acSDingqiang Lin 	u8 status;
720ba0501acSDingqiang Lin 
721c84f0ed8SJon Lin 	rkflash_print_dio("%s %x\n", __func__, addr);
72258463f4dSJon Lin 	op.sfcmd.d32 = 0;
723f28847a8SJon Lin 	op.sfcmd.b.cmd = 0xd8;
72458463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_24BITS;
72558463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
72658463f4dSJon Lin 
72758463f4dSJon Lin 	op.sfctrl.d32 = 0;
72858463f4dSJon Lin 
729ba0501acSDingqiang Lin 	sfc_nand_write_en();
73058463f4dSJon Lin 	ret = sfc_request(&op, addr, NULL, 0);
731f28847a8SJon Lin 
732ba0501acSDingqiang Lin 	if (ret != SFC_OK)
733ba0501acSDingqiang Lin 		return ret;
734f28847a8SJon Lin 
735ba0501acSDingqiang Lin 	ret = sfc_nand_wait_busy(&status, 1000 * 1000);
736f28847a8SJon Lin 
737ba0501acSDingqiang Lin 	if (status & (1 << 2))
738ba0501acSDingqiang Lin 		return SFC_NAND_PROG_ERASE_ERROR;
739c84f0ed8SJon Lin 
740ba0501acSDingqiang Lin 	return ret;
741ba0501acSDingqiang Lin }
742ba0501acSDingqiang Lin 
743629111d3SJon Lin static u32 sfc_nand_read_cache(u32 row, u32 *p_page_buf, u32 column, u32 len)
744629111d3SJon Lin {
745629111d3SJon Lin 	int ret;
746629111d3SJon Lin 	u32 plane;
747629111d3SJon Lin 	struct rk_sfc_op op;
748629111d3SJon Lin 
749629111d3SJon Lin 	op.sfcmd.d32 = 0;
750629111d3SJon Lin 	op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd;
751629111d3SJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
752629111d3SJon Lin 	op.sfcmd.b.dummybits = 8;
753629111d3SJon Lin 
754629111d3SJon Lin 	op.sfctrl.d32 = 0;
755629111d3SJon Lin 	op.sfctrl.b.datalines = sfc_nand_dev.read_lines;
756629111d3SJon Lin 	op.sfctrl.b.addrbits = 16;
757629111d3SJon Lin 
758629111d3SJon Lin 	plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0;
759629111d3SJon Lin 
760629111d3SJon Lin 	ret = sfc_request(&op, plane | column, p_page_buf, len);
761629111d3SJon Lin 	if (ret != SFC_OK)
762629111d3SJon Lin 		return SFC_NAND_HW_ERROR;
763629111d3SJon Lin 
764629111d3SJon Lin 	return ret;
765629111d3SJon Lin }
766629111d3SJon Lin 
767f28847a8SJon Lin u32 sfc_nand_prog_page_raw(u8 cs, u32 addr, u32 *p_page_buf)
768ba0501acSDingqiang Lin {
769ba0501acSDingqiang Lin 	int ret;
770415cf080Sjon.lin 	u32 plane;
77158463f4dSJon Lin 	struct rk_sfc_op op;
772ba0501acSDingqiang Lin 	u8 status;
77358463f4dSJon Lin 	u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page;
774629111d3SJon Lin 	u32 data_area_size = SFC_NAND_SECTOR_SIZE * p_nand_info->sec_per_page;
775ba0501acSDingqiang Lin 
776c84f0ed8SJon Lin 	rkflash_print_dio("%s %x %x\n", __func__, addr, p_page_buf[0]);
777ba0501acSDingqiang Lin 	sfc_nand_write_en();
778f28847a8SJon Lin 
779ba0501acSDingqiang Lin 	if (sfc_nand_dev.prog_lines == DATA_LINES_X4 &&
78025098c06SDingqiang Lin 	    p_nand_info->feature & FEA_SOFT_QOP_BIT &&
78125098c06SDingqiang Lin 	    sfc_get_version() < SFC_VER_3)
782ba0501acSDingqiang Lin 		sfc_nand_rw_preset();
783ba0501acSDingqiang Lin 
78458463f4dSJon Lin 	op.sfcmd.d32 = 0;
78558463f4dSJon Lin 	op.sfcmd.b.cmd = sfc_nand_dev.page_prog_cmd;
78658463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
78758463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
788ba0501acSDingqiang Lin 
78958463f4dSJon Lin 	op.sfctrl.d32 = 0;
79058463f4dSJon Lin 	op.sfctrl.b.datalines = sfc_nand_dev.prog_lines;
79158463f4dSJon Lin 	op.sfctrl.b.addrbits = 16;
792415cf080Sjon.lin 	plane = p_nand_info->plane_per_die == 2 ? ((addr >> 6) & 0x1) << 12 : 0;
79358463f4dSJon Lin 	sfc_request(&op, plane, p_page_buf, page_size);
794ba0501acSDingqiang Lin 
795629111d3SJon Lin 	/*
796c797b43aSJon Lin 	 * At the moment of power lost or dev running in harsh environment, flash
797c797b43aSJon Lin 	 * maybe work in a unkonw state and result in bit flip, when this situation
798c797b43aSJon Lin 	 * is detected by cache recheck, it's better to wait a second for a reliable
799c797b43aSJon Lin 	 * hardware environment to avoid abnormal data written to flash array.
800629111d3SJon Lin 	 */
801361684bfSJon Lin 	if (p_nand_info->id0 == MID_GIGADEV) {
802629111d3SJon Lin 		sfc_nand_read_cache(addr, (u32 *)sfc_nand_dev.recheck_buffer, 0, data_area_size);
803c797b43aSJon Lin 		if (memcmp(sfc_nand_dev.recheck_buffer, p_page_buf, data_area_size)) {
804c797b43aSJon Lin 			rkflash_print_error("%s %x cache bitflip\n", __func__, addr);
805c797b43aSJon Lin 			mdelay(1000);
806c797b43aSJon Lin 			sfc_request(&op, plane, p_page_buf, page_size);
807c797b43aSJon Lin 		}
808c797b43aSJon Lin 	}
809629111d3SJon Lin 
81058463f4dSJon Lin 	op.sfcmd.d32 = 0;
811f28847a8SJon Lin 	op.sfcmd.b.cmd = 0x10;
81258463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_24BITS;
81358463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
81458463f4dSJon Lin 
81558463f4dSJon Lin 	op.sfctrl.d32 = 0;
81658463f4dSJon Lin 	ret = sfc_request(&op, addr, p_page_buf, 0);
817f28847a8SJon Lin 
818ba0501acSDingqiang Lin 	if (ret != SFC_OK)
819ba0501acSDingqiang Lin 		return ret;
820f28847a8SJon Lin 
821ba0501acSDingqiang Lin 	ret = sfc_nand_wait_busy(&status, 1000 * 1000);
822ba0501acSDingqiang Lin 	if (status & (1 << 3))
823ba0501acSDingqiang Lin 		return SFC_NAND_PROG_ERASE_ERROR;
824c84f0ed8SJon Lin 
825ba0501acSDingqiang Lin 	return ret;
826ba0501acSDingqiang Lin }
827ba0501acSDingqiang Lin 
828c84f0ed8SJon Lin u32 sfc_nand_prog_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare)
829c84f0ed8SJon Lin {
830c84f0ed8SJon Lin 	int ret;
831c84f0ed8SJon Lin 	u32 sec_per_page = p_nand_info->sec_per_page;
832c84f0ed8SJon Lin 	u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE;
833a6fcac41SJon Lin 	struct nand_mega_area *meta = &p_nand_info->meta;
834c84f0ed8SJon Lin 
835c84f0ed8SJon Lin 	memcpy(gp_page_buf, p_data, data_size);
836c84f0ed8SJon Lin 	memset(&gp_page_buf[data_size / 4], 0xff, sec_per_page * 16);
837a6fcac41SJon Lin 	gp_page_buf[(data_size + meta->off0) / 4] = p_spare[0];
838a6fcac41SJon Lin 	gp_page_buf[(data_size + meta->off1) / 4] = p_spare[1];
839f28847a8SJon Lin 
840c84f0ed8SJon Lin 	if (sec_per_page == 8) {
841a6fcac41SJon Lin 		gp_page_buf[(data_size + meta->off2) / 4] = p_spare[2];
842a6fcac41SJon Lin 		gp_page_buf[(data_size + meta->off3) / 4] = p_spare[3];
843c84f0ed8SJon Lin 	}
844f28847a8SJon Lin 
845c84f0ed8SJon Lin 	ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf);
846c84f0ed8SJon Lin 
847c84f0ed8SJon Lin 	return ret;
848c84f0ed8SJon Lin }
849c84f0ed8SJon Lin 
850a80fd396SJon Lin u32 sfc_nand_read(u32 row, u32 *p_page_buf, u32 column, u32 len)
851ba0501acSDingqiang Lin {
852ba0501acSDingqiang Lin 	int ret;
853415cf080Sjon.lin 	u32 plane;
85458463f4dSJon Lin 	struct rk_sfc_op op;
8556281205aSDingqiang Lin 	u32 ecc_result;
856a6fcac41SJon Lin 	u8 status;
857ba0501acSDingqiang Lin 
85858463f4dSJon Lin 	op.sfcmd.d32 = 0;
859f28847a8SJon Lin 	op.sfcmd.b.cmd = 0x13;
86058463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
86158463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_24BITS;
86258463f4dSJon Lin 
86358463f4dSJon Lin 	op.sfctrl.d32 = 0;
86458463f4dSJon Lin 
865a80fd396SJon Lin 	sfc_request(&op, row, p_page_buf, 0);
866f28847a8SJon Lin 
867ba0501acSDingqiang Lin 	if (sfc_nand_dev.read_lines == DATA_LINES_X4 &&
86825098c06SDingqiang Lin 	    p_nand_info->feature & FEA_SOFT_QOP_BIT &&
86925098c06SDingqiang Lin 	    sfc_get_version() < SFC_VER_3)
870ba0501acSDingqiang Lin 		sfc_nand_rw_preset();
871ba0501acSDingqiang Lin 
872a6fcac41SJon Lin 	sfc_nand_wait_busy(&status, 1000 * 1000);
873a6fcac41SJon Lin 	ecc_result = p_nand_info->ecc_status();
874a6fcac41SJon Lin 
87558463f4dSJon Lin 	op.sfcmd.d32 = 0;
87658463f4dSJon Lin 	op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd;
877a80fd396SJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
878a80fd396SJon Lin 	op.sfcmd.b.dummybits = 8;
87958463f4dSJon Lin 
88058463f4dSJon Lin 	op.sfctrl.d32 = 0;
88158463f4dSJon Lin 	op.sfctrl.b.datalines = sfc_nand_dev.read_lines;
882a80fd396SJon Lin 	op.sfctrl.b.addrbits = 16;
883ba0501acSDingqiang Lin 
884a80fd396SJon Lin 	plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0;
885a80fd396SJon Lin 	ret = sfc_request(&op, plane | column, p_page_buf, len);
886a80fd396SJon Lin 	rkflash_print_dio("%s %x %x\n", __func__, row, p_page_buf[0]);
887c84f0ed8SJon Lin 
888c84f0ed8SJon Lin 	if (ret != SFC_OK)
889f28847a8SJon Lin 		return SFC_NAND_HW_ERROR;
890c84f0ed8SJon Lin 
891c84f0ed8SJon Lin 	return ecc_result;
892c84f0ed8SJon Lin }
893c84f0ed8SJon Lin 
894a80fd396SJon Lin u32 sfc_nand_read_page_raw(u8 cs, u32 addr, u32 *p_page_buf)
895a80fd396SJon Lin {
896a80fd396SJon Lin 	u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page;
897a80fd396SJon Lin 
898a80fd396SJon Lin 	return sfc_nand_read(addr, p_page_buf, 0, page_size);
899a80fd396SJon Lin }
900a80fd396SJon Lin 
901c84f0ed8SJon Lin u32 sfc_nand_read_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare)
902c84f0ed8SJon Lin {
90358463f4dSJon Lin 	u32 ret;
904c84f0ed8SJon Lin 	u32 sec_per_page = p_nand_info->sec_per_page;
905c84f0ed8SJon Lin 	u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE;
906a6fcac41SJon Lin 	struct nand_mega_area *meta = &p_nand_info->meta;
907c84f0ed8SJon Lin 
908c84f0ed8SJon Lin 	ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf);
909f25e3cafSJon Lin 	memcpy(p_data, gp_page_buf, data_size);
910a6fcac41SJon Lin 	p_spare[0] = gp_page_buf[(data_size + meta->off0) / 4];
911a6fcac41SJon Lin 	p_spare[1] = gp_page_buf[(data_size + meta->off1) / 4];
912f28847a8SJon Lin 
913f25e3cafSJon Lin 	if (p_nand_info->sec_per_page == 8) {
914a6fcac41SJon Lin 		p_spare[2] = gp_page_buf[(data_size + meta->off2) / 4];
915a6fcac41SJon Lin 		p_spare[3] = gp_page_buf[(data_size + meta->off3) / 4];
916f25e3cafSJon Lin 	}
917ba0501acSDingqiang Lin 
918f28847a8SJon Lin 	if (ret == SFC_NAND_HW_ERROR)
919f28847a8SJon Lin 		ret = SFC_NAND_ECC_ERROR;
920f28847a8SJon Lin 
921c84f0ed8SJon Lin 	if (ret != SFC_NAND_ECC_OK) {
922c84f0ed8SJon Lin 		rkflash_print_error("%s[0x%x], ret=0x%x\n", __func__, addr, ret);
923f28847a8SJon Lin 
924ba0501acSDingqiang Lin 		if (p_data)
925c84f0ed8SJon Lin 			rkflash_print_hex("data:", p_data, 4, 8);
926f28847a8SJon Lin 
927ba0501acSDingqiang Lin 		if (p_spare)
928c84f0ed8SJon Lin 			rkflash_print_hex("spare:", p_spare, 4, 2);
929ba0501acSDingqiang Lin 	}
930f25e3cafSJon Lin 
931c84f0ed8SJon Lin 	return ret;
932ba0501acSDingqiang Lin }
933ba0501acSDingqiang Lin 
934c84f0ed8SJon Lin u32 sfc_nand_check_bad_block(u8 cs, u32 addr)
935c84f0ed8SJon Lin {
936c84f0ed8SJon Lin 	u32 ret;
937c84f0ed8SJon Lin 	u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE;
938a80fd396SJon Lin 	u32 marker = 0;
939c84f0ed8SJon Lin 
940a80fd396SJon Lin 	ret = sfc_nand_read(addr, &marker, data_size, 2);
941f28847a8SJon Lin 
942f28847a8SJon Lin 	/* unify with mtd framework */
943629111d3SJon Lin 	if (ret == SFC_NAND_ECC_ERROR || (u16)marker != 0xffff)
944a80fd396SJon Lin 		rkflash_print_error("%s page= %x ret= %x spare= %x\n",
945a80fd396SJon Lin 				    __func__, addr, ret, marker);
946f28847a8SJon Lin 
947c84f0ed8SJon Lin 	/* Original bad block */
948a80fd396SJon Lin 	if ((u16)marker != 0xffff)
949c84f0ed8SJon Lin 		return true;
950c84f0ed8SJon Lin 
951c84f0ed8SJon Lin 	return false;
952c84f0ed8SJon Lin }
953c84f0ed8SJon Lin 
954c84f0ed8SJon Lin u32 sfc_nand_mark_bad_block(u8 cs, u32 addr)
955c84f0ed8SJon Lin {
956c84f0ed8SJon Lin 	u32 ret;
957c84f0ed8SJon Lin 	u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE;
958c84f0ed8SJon Lin 
959c84f0ed8SJon Lin 	ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf);
960f28847a8SJon Lin 
961c84f0ed8SJon Lin 	if (ret)
962c84f0ed8SJon Lin 		return SFC_NAND_HW_ERROR;
963f28847a8SJon Lin 
964c84f0ed8SJon Lin 	gp_page_buf[data_size / 4] = 0x0;
965c84f0ed8SJon Lin 	ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf);
966f28847a8SJon Lin 
967c84f0ed8SJon Lin 	if (ret)
968c84f0ed8SJon Lin 		return SFC_NAND_HW_ERROR;
969c84f0ed8SJon Lin 
970c84f0ed8SJon Lin 	return ret;
971c84f0ed8SJon Lin }
972c84f0ed8SJon Lin 
973c84f0ed8SJon Lin int sfc_nand_read_id(u8 *data)
974ba0501acSDingqiang Lin {
975ba0501acSDingqiang Lin 	int ret;
97658463f4dSJon Lin 	struct rk_sfc_op op;
977ba0501acSDingqiang Lin 
97858463f4dSJon Lin 	op.sfcmd.d32 = 0;
97958463f4dSJon Lin 	op.sfcmd.b.cmd = CMD_READ_JEDECID;
98058463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
981ba0501acSDingqiang Lin 
98258463f4dSJon Lin 	op.sfctrl.d32 = 0;
98358463f4dSJon Lin 	op.sfctrl.b.addrbits = 8;
98458463f4dSJon Lin 
98558463f4dSJon Lin 	ret = sfc_request(&op, 0, data, 3);
986ba0501acSDingqiang Lin 
987ba0501acSDingqiang Lin 	return ret;
988ba0501acSDingqiang Lin }
989ba0501acSDingqiang Lin 
990ba0501acSDingqiang Lin /*
991ba0501acSDingqiang Lin  * Read the 1st page's 1st byte of a phy_blk
992ba0501acSDingqiang Lin  * If not FF, it's bad blk
993ba0501acSDingqiang Lin  */
994ba0501acSDingqiang Lin static int sfc_nand_get_bad_block_list(u16 *table, u32 die)
995ba0501acSDingqiang Lin {
996ba0501acSDingqiang Lin 	u32 bad_cnt, page;
997ba0501acSDingqiang Lin 	u32 blk_per_die;
9982ac88c1bSJon Lin 	u16 blk;
999ba0501acSDingqiang Lin 
1000c84f0ed8SJon Lin 	rkflash_print_info("%s\n", __func__);
1001c84f0ed8SJon Lin 
1002ba0501acSDingqiang Lin 	bad_cnt = 0;
1003ba0501acSDingqiang Lin 	blk_per_die = p_nand_info->plane_per_die *
1004ba0501acSDingqiang Lin 		      p_nand_info->blk_per_plane;
1005f28847a8SJon Lin 
1006ba0501acSDingqiang Lin 	for (blk = 0; blk < blk_per_die; blk++) {
1007ba0501acSDingqiang Lin 		page = (blk + blk_per_die * die) *
1008ba0501acSDingqiang Lin 		       p_nand_info->page_per_blk;
1009ba0501acSDingqiang Lin 
10102ac88c1bSJon Lin 		if (sfc_nand_check_bad_block(die, page)) {
1011ba0501acSDingqiang Lin 			table[bad_cnt++] = blk;
1012c84f0ed8SJon Lin 			rkflash_print_error("die[%d], bad_blk[%d]\n", die, blk);
1013ba0501acSDingqiang Lin 		}
1014ba0501acSDingqiang Lin 	}
1015f28847a8SJon Lin 
1016ba0501acSDingqiang Lin 	return (int)bad_cnt;
1017ba0501acSDingqiang Lin }
1018ba0501acSDingqiang Lin 
1019c84f0ed8SJon Lin void sfc_nand_ftl_ops_init(void)
1020ba0501acSDingqiang Lin {
1021ba0501acSDingqiang Lin 	/* para init */
1022ba0501acSDingqiang Lin 	g_nand_phy_info.nand_type	= 1;
1023ba0501acSDingqiang Lin 	g_nand_phy_info.die_num		= 1;
1024ba0501acSDingqiang Lin 	g_nand_phy_info.plane_per_die	= p_nand_info->plane_per_die;
1025ba0501acSDingqiang Lin 	g_nand_phy_info.blk_per_plane	= p_nand_info->blk_per_plane;
1026ba0501acSDingqiang Lin 	g_nand_phy_info.page_per_blk	= p_nand_info->page_per_blk;
1027ba0501acSDingqiang Lin 	g_nand_phy_info.page_per_slc_blk = p_nand_info->page_per_blk;
1028c84f0ed8SJon Lin 	g_nand_phy_info.byte_per_sec	= SFC_NAND_SECTOR_SIZE;
1029ba0501acSDingqiang Lin 	g_nand_phy_info.sec_per_page	= p_nand_info->sec_per_page;
1030ba0501acSDingqiang Lin 	g_nand_phy_info.sec_per_blk	= p_nand_info->sec_per_page *
1031ba0501acSDingqiang Lin 					  p_nand_info->page_per_blk;
1032ba0501acSDingqiang Lin 	g_nand_phy_info.reserved_blk	= 8;
1033ba0501acSDingqiang Lin 	g_nand_phy_info.blk_per_die	= p_nand_info->plane_per_die *
1034ba0501acSDingqiang Lin 					  p_nand_info->blk_per_plane;
1035ba0501acSDingqiang Lin 	g_nand_phy_info.ecc_bits	= p_nand_info->max_ecc_bits;
1036ba0501acSDingqiang Lin 
1037ba0501acSDingqiang Lin 	/* driver register */
1038ba0501acSDingqiang Lin 	g_nand_ops.get_bad_blk_list	= sfc_nand_get_bad_block_list;
1039ba0501acSDingqiang Lin 	g_nand_ops.erase_blk		= sfc_nand_erase_block;
1040ba0501acSDingqiang Lin 	g_nand_ops.prog_page		= sfc_nand_prog_page;
1041ba0501acSDingqiang Lin 	g_nand_ops.read_page		= sfc_nand_read_page;
104257d18453Sjon.lin 	g_nand_ops.bch_sel		= NULL;
1043ba0501acSDingqiang Lin }
1044ba0501acSDingqiang Lin 
1045a6fcac41SJon Lin static int sfc_nand_enable_QE(void)
1046ba0501acSDingqiang Lin {
1047ba0501acSDingqiang Lin 	int ret = SFC_OK;
1048ba0501acSDingqiang Lin 	u8 status;
1049ba0501acSDingqiang Lin 
1050f28847a8SJon Lin 	ret = sfc_nand_read_feature(0xB0, &status);
1051ba0501acSDingqiang Lin 
1052ba0501acSDingqiang Lin 	if (ret != SFC_OK)
1053ba0501acSDingqiang Lin 		return ret;
1054ba0501acSDingqiang Lin 
1055f28847a8SJon Lin 	if (status & 1)   /* is QE bit set */
1056ba0501acSDingqiang Lin 		return SFC_OK;
1057ba0501acSDingqiang Lin 
1058f28847a8SJon Lin 	status |= 1;
1059ba0501acSDingqiang Lin 
1060f28847a8SJon Lin 	return sfc_nand_write_feature(0xB0, status);
1061ba0501acSDingqiang Lin }
1062ba0501acSDingqiang Lin 
1063ba0501acSDingqiang Lin u32 sfc_nand_init(void)
1064ba0501acSDingqiang Lin {
1065c84f0ed8SJon Lin 	u8 status, id_byte[8];
1066ba0501acSDingqiang Lin 
1067c84f0ed8SJon Lin 	sfc_nand_read_id(id_byte);
1068c84f0ed8SJon Lin 	rkflash_print_error("sfc_nand id: %x %x %x\n",
1069ba0501acSDingqiang Lin 			    id_byte[0], id_byte[1], id_byte[2]);
1070f28847a8SJon Lin 
1071ba0501acSDingqiang Lin 	if (id_byte[0] == 0xFF || id_byte[0] == 0x00)
107258463f4dSJon Lin 		return (u32)FTL_NO_FLASH;
1073ba0501acSDingqiang Lin 
1074a6fcac41SJon Lin 	p_nand_info = sfc_nand_get_info(id_byte);
1075f28847a8SJon Lin 
107645292245SJon Lin 	if (!p_nand_info) {
107745292245SJon Lin 		pr_err("The device not support yet!\n");
107845292245SJon Lin 
107958463f4dSJon Lin 		return (u32)FTL_UNSUPPORTED_FLASH;
108045292245SJon Lin 	}
1081ba0501acSDingqiang Lin 
1082ba0501acSDingqiang Lin 	sfc_nand_dev.manufacturer = id_byte[0];
1083ba0501acSDingqiang Lin 	sfc_nand_dev.mem_type = id_byte[1];
1084c84f0ed8SJon Lin 	sfc_nand_dev.capacity = p_nand_info->density;
1085c84f0ed8SJon Lin 	sfc_nand_dev.block_size = p_nand_info->page_per_blk * p_nand_info->sec_per_page;
1086c84f0ed8SJon Lin 	sfc_nand_dev.page_size = p_nand_info->sec_per_page;
1087ba0501acSDingqiang Lin 
1088ba0501acSDingqiang Lin 	/* disable block lock */
1089ba0501acSDingqiang Lin 	sfc_nand_write_feature(0xA0, 0);
1090ba0501acSDingqiang Lin 	sfc_nand_dev.read_lines = DATA_LINES_X1;
1091ba0501acSDingqiang Lin 	sfc_nand_dev.prog_lines = DATA_LINES_X1;
1092f28847a8SJon Lin 	sfc_nand_dev.page_read_cmd = 0x03;
1093f28847a8SJon Lin 	sfc_nand_dev.page_prog_cmd = 0x02;
1094629111d3SJon Lin 	sfc_nand_dev.recheck_buffer = ftl_malloc(SFC_NAND_PAGE_MAX_SIZE);
1095629111d3SJon Lin 	if (!sfc_nand_dev.recheck_buffer) {
1096629111d3SJon Lin 		rkflash_print_error("%s recheck_buffer alloc failed\n", __func__);
1097629111d3SJon Lin 		return -1;
1098629111d3SJon Lin 	}
1099f28847a8SJon Lin 
1100ba0501acSDingqiang Lin 	if (p_nand_info->feature & FEA_4BIT_READ) {
1101f28847a8SJon Lin 		if ((p_nand_info->has_qe_bits && sfc_nand_enable_QE() == SFC_OK) ||
1102f28847a8SJon Lin 		    !p_nand_info->has_qe_bits) {
1103ba0501acSDingqiang Lin 			sfc_nand_dev.read_lines = DATA_LINES_X4;
1104f28847a8SJon Lin 			sfc_nand_dev.page_read_cmd = 0x6b;
1105ba0501acSDingqiang Lin 		}
1106ba0501acSDingqiang Lin 	}
1107ba0501acSDingqiang Lin 
1108ba0501acSDingqiang Lin 	if (p_nand_info->feature & FEA_4BIT_PROG &&
1109ba0501acSDingqiang Lin 	    sfc_nand_dev.read_lines == DATA_LINES_X4) {
1110ba0501acSDingqiang Lin 		sfc_nand_dev.prog_lines = DATA_LINES_X4;
1111f28847a8SJon Lin 		sfc_nand_dev.page_prog_cmd = 0x32;
1112ba0501acSDingqiang Lin 	}
1113ba0501acSDingqiang Lin 
1114ba0501acSDingqiang Lin 	sfc_nand_read_feature(0xA0, &status);
1115c84f0ed8SJon Lin 	rkflash_print_info("sfc_nand A0 = 0x%x\n", status);
1116ba0501acSDingqiang Lin 	sfc_nand_read_feature(0xB0, &status);
1117c84f0ed8SJon Lin 	rkflash_print_info("sfc_nand B0 = 0x%x\n", status);
1118c84f0ed8SJon Lin 	rkflash_print_info("read_lines = %x\n", sfc_nand_dev.read_lines);
1119c84f0ed8SJon Lin 	rkflash_print_info("prog_lines = %x\n", sfc_nand_dev.prog_lines);
1120c84f0ed8SJon Lin 	rkflash_print_info("page_read_cmd = %x\n", sfc_nand_dev.page_read_cmd);
1121c84f0ed8SJon Lin 	rkflash_print_info("page_prog_cmd = %x\n", sfc_nand_dev.page_prog_cmd);
1122ba0501acSDingqiang Lin 
1123ba0501acSDingqiang Lin 	return SFC_OK;
1124ba0501acSDingqiang Lin }
1125ba0501acSDingqiang Lin 
1126c84f0ed8SJon Lin void sfc_nand_deinit(void)
1127ba0501acSDingqiang Lin {
1128c84f0ed8SJon Lin 	/* to-do */
1129629111d3SJon Lin 	kfree(sfc_nand_dev.recheck_buffer);
1130ba0501acSDingqiang Lin }
1131c84f0ed8SJon Lin 
1132c84f0ed8SJon Lin struct SFNAND_DEV *sfc_nand_get_private_dev(void)
1133c84f0ed8SJon Lin {
1134c84f0ed8SJon Lin 	return &sfc_nand_dev;
1135c84f0ed8SJon Lin }
1136c84f0ed8SJon Lin 
1137