xref: /rk3399_rockchip-uboot/drivers/rkflash/sfc_nand.c (revision c797b43aebb6ae23c51b21bf3eb3bb6feea5e16c)
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 },
70f28847a8SJon Lin 
71f28847a8SJon Lin 	/* W25N01GV */
72b833c879SJon Lin 	{ 0xEF, 0xAA, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 },
73b833c879SJon Lin 	/* W25N02KVZEIR */
74b833c879SJon Lin 	{ 0xEF, 0xAA, 0x22, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status0 },
75629111d3SJon Lin 	/* W25N04KVZEIR */
76629111d3SJon Lin 	{ 0xEF, 0xAA, 0x23, 4, 0x40, 1, 4096, 0x4C, 20, 0x8, 0, { 0x04, 0x14, 0x24, 0x34 }, &sfc_nand_get_ecc_status0 },
77f28847a8SJon Lin 	/* W25N01GW */
78b833c879SJon Lin 	{ 0xEF, 0xBA, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 },
798a654f32SJon Lin 	/* W25N512GVEIG */
808a654f32SJon Lin 	{ 0xEF, 0xAA, 0x20, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 },
81f28847a8SJon Lin 
82f28847a8SJon Lin 	/* HYF2GQ4UAACAE */
83b833c879SJon Lin 	{ 0xC9, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
84f28847a8SJon Lin 	/* HYF1GQ4UDACAE */
85b833c879SJon Lin 	{ 0xC9, 0x21, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
86f28847a8SJon Lin 	/* HYF1GQ4UPACAE */
87b833c879SJon Lin 	{ 0xC9, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
88f28847a8SJon Lin 	/* HYF2GQ4UDACAE */
89b833c879SJon Lin 	{ 0xC9, 0x22, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
90f28847a8SJon Lin 	/* HYF2GQ4UHCCAE */
91b833c879SJon Lin 	{ 0xC9, 0x5A, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0xE, 1, { 0x04, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
92f28847a8SJon Lin 	/* HYF4GQ4UAACBE */
93b833c879SJon Lin 	{ 0xC9, 0xD4, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x4, 1, { 0x20, 0x40, 0x24, 0x44 }, &sfc_nand_get_ecc_status0 },
94f28847a8SJon Lin 
95f28847a8SJon Lin 	/* FS35ND01G-S1 */
96b833c879SJon Lin 	{ 0xCD, 0xB1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
97f28847a8SJon Lin 	/* FS35ND02G-S2 */
98b833c879SJon Lin 	{ 0xCD, 0xA2, 0x00, 4, 0x40, 1, 2048, 0x00, 19, 0x4, 0, { 0x10, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
9958463f4dSJon Lin 	/* FS35ND01G-S1Y2 */
100b833c879SJon Lin 	{ 0xCD, 0xEA, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
101f1b20f5aSJon Lin 	/* FS35ND02G-S3Y2 */
102b833c879SJon Lin 	{ 0xCD, 0xEB, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
103f28847a8SJon Lin 	/* FS35ND04G-S2Y2 1*4096 */
104b833c879SJon Lin 	{ 0xCD, 0xEC, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
105f28847a8SJon Lin 
106f28847a8SJon Lin 	/* DS35Q1GA-IB */
107b833c879SJon Lin 	{ 0xE5, 0x71, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
108f28847a8SJon Lin 	/* DS35Q2GA-IB */
109b833c879SJon Lin 	{ 0xE5, 0x72, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
110f28847a8SJon Lin 	/* DS35M1GA-1B */
111b833c879SJon Lin 	{ 0xE5, 0x21, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
112629111d3SJon Lin 	/* DS35Q2GB-IB */
113629111d3SJon Lin 	{ 0xE5, 0xF2, 0x00, 4, 0x40, 2, 1024, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
114f28847a8SJon Lin 
115f28847a8SJon Lin 	/* EM73C044VCC-H */
116b833c879SJon Lin 	{ 0xD5, 0x22, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
117f28847a8SJon Lin 	/* EM73D044VCE-H */
118b833c879SJon Lin 	{ 0xD5, 0x20, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
119f28847a8SJon Lin 	/* EM73E044SNA-G */
120b833c879SJon Lin 	{ 0xD5, 0x03, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x28, 0x08, 0x2C }, &sfc_nand_get_ecc_status0 },
121629111d3SJon Lin 	/* EM73C044VCF-H */
122629111d3SJon Lin 	{ 0xD5, 0x25, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
123f28847a8SJon Lin 
124f28847a8SJon Lin 	/* XT26G02A */
125362b1be1SJon Lin 	{ 0x0B, 0xE2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
126f28847a8SJon Lin 	/* XT26G01A */
127362b1be1SJon Lin 	{ 0x0B, 0xE1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
128f28847a8SJon Lin 	/* XT26G04A */
129362b1be1SJon Lin 	{ 0x0B, 0xE3, 0x00, 4, 0x80, 1, 2048, 0x4C, 20, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
130f28847a8SJon Lin 	/* XT26G01B */
131362b1be1SJon Lin 	{ 0x0B, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status4 },
132f28847a8SJon Lin 	/* XT26G02B */
133362b1be1SJon Lin 	{ 0x0B, 0xF2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status5 },
134362b1be1SJon Lin 	/* XT26G01C */
135362b1be1SJon Lin 	{ 0x0B, 0x11, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 },
136362b1be1SJon Lin 	/* XT26G02C */
137362b1be1SJon Lin 	{ 0x0B, 0x12, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status7 },
138362b1be1SJon Lin 	/* XT26G04C */
139362b1be1SJon Lin 	{ 0x0B, 0x13, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status7 },
140629111d3SJon Lin 	/* XT26G11C */
141629111d3SJon Lin 	{ 0x0B, 0x15, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
142a80fd396SJon Lin 
143362b1be1SJon Lin 	/* MT29F2G01ABA, XT26G02E, F50L2G41XA */
144629111d3SJon Lin 	{ 0x2C, 0x24, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x8, 0, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
145629111d3SJon Lin 	/* MT29F1G01ABA, F50L1G41XA */
146629111d3SJon Lin 	{ 0x2C, 0x14, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 0, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
147a80fd396SJon Lin 
148a80fd396SJon Lin 	/* FM25S01 */
149b833c879SJon Lin 	{ 0xA1, 0xA1, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x00, 0x04, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
150a80fd396SJon Lin 	/* FM25S01A */
151b833c879SJon Lin 	{ 0xA1, 0xE4, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
152a80fd396SJon Lin 	/* FM25S02A */
153b833c879SJon Lin 	{ 0xA1, 0xE5, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
154f28847a8SJon Lin 
155f28847a8SJon Lin 	/* IS37SML01G1 */
156b833c879SJon Lin 	{ 0xC8, 0x21, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x1, 0, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
157f28847a8SJon Lin 	/* F50L1G41LB */
158b833c879SJon Lin 	{ 0xC8, 0x01, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
159f28847a8SJon Lin 	/* ATO25D1GA */
160b833c879SJon Lin 	{ 0x9B, 0x12, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x1, 1, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
161362b1be1SJon Lin 	/* BWJX08K-2Gb */
162362b1be1SJon Lin 	{ 0xBC, 0xB3, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x10, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
163629111d3SJon Lin 	/* JS28U1GQSCAHG-83 */
164629111d3SJon Lin 	{ 0xBF, 0x21, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x4, 1, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status8 },
1658a654f32SJon Lin 	/* SGM7000I-S24W1GH */
1668a654f32SJon Lin 	{ 0xEA, 0xC1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
167ba0501acSDingqiang Lin };
168ba0501acSDingqiang Lin 
169ba0501acSDingqiang Lin static struct nand_info *p_nand_info;
170ba0501acSDingqiang Lin static u32 gp_page_buf[SFC_NAND_PAGE_MAX_SIZE / 4];
171ba0501acSDingqiang Lin static struct SFNAND_DEV sfc_nand_dev;
172ba0501acSDingqiang Lin 
173a6fcac41SJon Lin static struct nand_info *sfc_nand_get_info(u8 *nand_id)
174ba0501acSDingqiang Lin {
175ba0501acSDingqiang Lin 	u32 i;
176ba0501acSDingqiang Lin 
177ba0501acSDingqiang Lin 	for (i = 0; i < ARRAY_SIZE(spi_nand_tbl); i++) {
178b833c879SJon Lin 		if (spi_nand_tbl[i].id0 == nand_id[0] &&
179b833c879SJon Lin 		    spi_nand_tbl[i].id1 == nand_id[1]) {
180b833c879SJon Lin 			if (spi_nand_tbl[i].id2 &&
181b833c879SJon Lin 			    spi_nand_tbl[i].id2 != nand_id[2])
182b833c879SJon Lin 				continue;
183b833c879SJon Lin 
184ba0501acSDingqiang Lin 			return &spi_nand_tbl[i];
185ba0501acSDingqiang Lin 		}
186b833c879SJon Lin 	}
187f28847a8SJon Lin 
188ba0501acSDingqiang Lin 	return NULL;
189ba0501acSDingqiang Lin }
190ba0501acSDingqiang Lin 
191ba0501acSDingqiang Lin static int sfc_nand_write_en(void)
192ba0501acSDingqiang Lin {
193ba0501acSDingqiang Lin 	int ret;
19458463f4dSJon Lin 	struct rk_sfc_op op;
195ba0501acSDingqiang Lin 
19658463f4dSJon Lin 	op.sfcmd.d32 = 0;
19758463f4dSJon Lin 	op.sfcmd.b.cmd = CMD_WRITE_EN;
19858463f4dSJon Lin 
19958463f4dSJon Lin 	op.sfctrl.d32 = 0;
20058463f4dSJon Lin 
20158463f4dSJon Lin 	ret = sfc_request(&op, 0, NULL, 0);
202ba0501acSDingqiang Lin 	return ret;
203ba0501acSDingqiang Lin }
204ba0501acSDingqiang Lin 
205ba0501acSDingqiang Lin static int sfc_nand_rw_preset(void)
206ba0501acSDingqiang Lin {
207ba0501acSDingqiang Lin 	int ret;
20858463f4dSJon Lin 	struct rk_sfc_op op;
209ba0501acSDingqiang Lin 
21058463f4dSJon Lin 	op.sfcmd.d32 = 0;
211f28847a8SJon Lin 	op.sfcmd.b.cmd = 0xff;
212f28847a8SJon Lin 	op.sfcmd.b.cs = 2;
213ba0501acSDingqiang Lin 
21458463f4dSJon Lin 	op.sfctrl.d32 = 0;
21558463f4dSJon Lin 	op.sfctrl.b.datalines = 2;
216f28847a8SJon Lin 	op.sfctrl.b.cmdlines = 2;
217f28847a8SJon Lin 	op.sfctrl.b.addrlines = 2;
21858463f4dSJon Lin 
219f28847a8SJon Lin 	ret = sfc_request(&op, 0, NULL, 0);
220ba0501acSDingqiang Lin 	return ret;
221ba0501acSDingqiang Lin }
222ba0501acSDingqiang Lin 
223ba0501acSDingqiang Lin static int sfc_nand_read_feature(u8 addr, u8 *data)
224ba0501acSDingqiang Lin {
225ba0501acSDingqiang Lin 	int ret;
22658463f4dSJon Lin 	struct rk_sfc_op op;
227ba0501acSDingqiang Lin 
22858463f4dSJon Lin 	op.sfcmd.d32 = 0;
22958463f4dSJon Lin 	op.sfcmd.b.cmd = 0x0F;
23058463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
23158463f4dSJon Lin 
23258463f4dSJon Lin 	op.sfctrl.d32 = 0;
23358463f4dSJon Lin 	op.sfctrl.b.addrbits = 8;
23458463f4dSJon Lin 
235ba0501acSDingqiang Lin 	*data = 0;
236ba0501acSDingqiang Lin 
23758463f4dSJon Lin 	ret = sfc_request(&op, addr, data, 1);
238f28847a8SJon Lin 
239ba0501acSDingqiang Lin 	if (ret != SFC_OK)
240ba0501acSDingqiang Lin 		return ret;
241f28847a8SJon Lin 
242ba0501acSDingqiang Lin 	return SFC_OK;
243ba0501acSDingqiang Lin }
244ba0501acSDingqiang Lin 
245ba0501acSDingqiang Lin static int sfc_nand_write_feature(u32 addr, u8 status)
246ba0501acSDingqiang Lin {
247ba0501acSDingqiang Lin 	int ret;
24858463f4dSJon Lin 	struct rk_sfc_op op;
249ba0501acSDingqiang Lin 
250ba0501acSDingqiang Lin 	sfc_nand_write_en();
251ba0501acSDingqiang Lin 
25258463f4dSJon Lin 	op.sfcmd.d32 = 0;
25358463f4dSJon Lin 	op.sfcmd.b.cmd = 0x1F;
25458463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
25558463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
256ba0501acSDingqiang Lin 
25758463f4dSJon Lin 	op.sfctrl.d32 = 0;
25858463f4dSJon Lin 	op.sfctrl.b.addrbits = 8;
25958463f4dSJon Lin 
26058463f4dSJon Lin 	ret = sfc_request(&op, addr, &status, 1);
261f28847a8SJon Lin 
262ba0501acSDingqiang Lin 	if (ret != SFC_OK)
263ba0501acSDingqiang Lin 		return ret;
264f28847a8SJon Lin 
265ba0501acSDingqiang Lin 	return ret;
266ba0501acSDingqiang Lin }
267ba0501acSDingqiang Lin 
268ba0501acSDingqiang Lin static int sfc_nand_wait_busy(u8 *data, int timeout)
269ba0501acSDingqiang Lin {
270ba0501acSDingqiang Lin 	int ret;
271ba0501acSDingqiang Lin 	int i;
272ba0501acSDingqiang Lin 	u8 status;
273ba0501acSDingqiang Lin 
274ba0501acSDingqiang Lin 	*data = 0;
275f28847a8SJon Lin 
276ba0501acSDingqiang Lin 	for (i = 0; i < timeout; i++) {
277ba0501acSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
278f28847a8SJon Lin 
279ba0501acSDingqiang Lin 		if (ret != SFC_OK)
280ba0501acSDingqiang Lin 			return ret;
281f28847a8SJon Lin 
282ba0501acSDingqiang Lin 		*data = status;
283f28847a8SJon Lin 
284ba0501acSDingqiang Lin 		if (!(status & (1 << 0)))
285ba0501acSDingqiang Lin 			return SFC_OK;
286f28847a8SJon Lin 
287ba0501acSDingqiang Lin 		sfc_delay(1);
288ba0501acSDingqiang Lin 	}
289f28847a8SJon Lin 
290f28847a8SJon Lin 	return SFC_NAND_WAIT_TIME_OUT;
291ba0501acSDingqiang Lin }
292ba0501acSDingqiang Lin 
2936281205aSDingqiang Lin /*
2946281205aSDingqiang Lin  * ecc default:
295a6fcac41SJon Lin  * ecc bits: 0xC0[4,5]
296f28847a8SJon Lin  * 0b00, No bit errors were detected
297f28847a8SJon Lin  * 0b01, Bit errors were detected and corrected.
298f28847a8SJon Lin  * 0b10, Multiple bit errors were detected and not corrected.
299f28847a8SJon Lin  * 0b11, Bits errors were detected and corrected, bit error count
300362b1be1SJon Lin  *	reach the bit flip detection threshold
3016281205aSDingqiang Lin  */
302f28847a8SJon Lin static u32 sfc_nand_get_ecc_status0(void)
3036281205aSDingqiang Lin {
30458463f4dSJon Lin 	u32 ret;
3056281205aSDingqiang Lin 	u32 i;
3066281205aSDingqiang Lin 	u8 ecc;
3076281205aSDingqiang Lin 	u8 status;
3086281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
3096281205aSDingqiang Lin 
3106281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
3116281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
312f28847a8SJon Lin 
3136281205aSDingqiang Lin 		if (ret != SFC_OK)
3146281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
315f28847a8SJon Lin 
3166281205aSDingqiang Lin 		if (!(status & (1 << 0)))
3176281205aSDingqiang Lin 			break;
318f28847a8SJon Lin 
3196281205aSDingqiang Lin 		sfc_delay(1);
3206281205aSDingqiang Lin 	}
3216281205aSDingqiang Lin 
3226281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
3236281205aSDingqiang Lin 
3246281205aSDingqiang Lin 	if (ecc <= 1)
3256281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
3266281205aSDingqiang Lin 	else if (ecc == 2)
32758463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
3286281205aSDingqiang Lin 	else
3296281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
3306281205aSDingqiang Lin 
3316281205aSDingqiang Lin 	return ret;
3326281205aSDingqiang Lin }
3336281205aSDingqiang Lin 
3346281205aSDingqiang Lin /*
3356281205aSDingqiang Lin  * ecc spectial type1:
336a6fcac41SJon Lin  * ecc bits: 0xC0[4,5]
337f28847a8SJon Lin  * 0b00, No bit errors were detected;
338f28847a8SJon Lin  * 0b01, Bits errors were detected and corrected, bit error count
3396281205aSDingqiang Lin  *	may reach the bit flip detection threshold;
340f28847a8SJon Lin  * 0b10, Multiple bit errors were detected and not corrected;
341f28847a8SJon Lin  * 0b11, Reserved.
3426281205aSDingqiang Lin  */
343f28847a8SJon Lin static u32 sfc_nand_get_ecc_status1(void)
3446281205aSDingqiang Lin {
34558463f4dSJon Lin 	u32 ret;
3466281205aSDingqiang Lin 	u32 i;
3476281205aSDingqiang Lin 	u8 ecc;
3486281205aSDingqiang Lin 	u8 status;
3496281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
3506281205aSDingqiang Lin 
3516281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
3526281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
353f28847a8SJon Lin 
3546281205aSDingqiang Lin 		if (ret != SFC_OK)
3556281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
356f28847a8SJon Lin 
3576281205aSDingqiang Lin 		if (!(status & (1 << 0)))
3586281205aSDingqiang Lin 			break;
359f28847a8SJon Lin 
3606281205aSDingqiang Lin 		sfc_delay(1);
3616281205aSDingqiang Lin 	}
3626281205aSDingqiang Lin 
3636281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
3646281205aSDingqiang Lin 
3656281205aSDingqiang Lin 	if (ecc == 0)
3666281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
3676281205aSDingqiang Lin 	else if (ecc == 1)
3686281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
3696281205aSDingqiang Lin 	else
37058463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
3716281205aSDingqiang Lin 
3726281205aSDingqiang Lin 	return ret;
3736281205aSDingqiang Lin }
3746281205aSDingqiang Lin 
3756281205aSDingqiang Lin /*
376d9cdd318SJon Lin  * ecc spectial type2:
377a6fcac41SJon Lin  * ecc bits: 0xC0[4,5] 0xF0[4,5]
378f28847a8SJon Lin  * [0b0000, 0b0011], No bit errors were detected;
379f28847a8SJon Lin  * [0b0100, 0b0111], Bit errors were detected and corrected. Not
380d9cdd318SJon Lin  *	reach Flipping Bits;
381f28847a8SJon Lin  * [0b1000, 0b1011], Multiple bit errors were detected and
382c84f0ed8SJon Lin  *	not corrected.
383f28847a8SJon Lin  * [0b1100, 0b1111], reserved.
384d9cdd318SJon Lin  */
385f28847a8SJon Lin static u32 sfc_nand_get_ecc_status2(void)
386d9cdd318SJon Lin {
38758463f4dSJon Lin 	u32 ret;
388d9cdd318SJon Lin 	u32 i;
389d9cdd318SJon Lin 	u8 ecc;
390d9cdd318SJon Lin 	u8 status, status1;
391d9cdd318SJon Lin 	u32 timeout = 1000 * 1000;
392d9cdd318SJon Lin 
393d9cdd318SJon Lin 	for (i = 0; i < timeout; i++) {
394d9cdd318SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
395f28847a8SJon Lin 
396d9cdd318SJon Lin 		if (ret != SFC_OK)
397d9cdd318SJon Lin 			return SFC_NAND_ECC_ERROR;
398f28847a8SJon Lin 
399d9cdd318SJon Lin 		ret = sfc_nand_read_feature(0xF0, &status1);
400f28847a8SJon Lin 
401d9cdd318SJon Lin 		if (ret != SFC_OK)
402d9cdd318SJon Lin 			return SFC_NAND_ECC_ERROR;
403f28847a8SJon Lin 
404d9cdd318SJon Lin 		if (!(status & (1 << 0)))
405d9cdd318SJon Lin 			break;
406f28847a8SJon Lin 
407d9cdd318SJon Lin 		sfc_delay(1);
408d9cdd318SJon Lin 	}
409d9cdd318SJon Lin 
410d9cdd318SJon Lin 	ecc = (status >> 4) & 0x03;
411d9cdd318SJon Lin 	ecc = (ecc << 2) | ((status1 >> 4) & 0x03);
412f28847a8SJon Lin 
413d9cdd318SJon Lin 	if (ecc < 7)
414d9cdd318SJon Lin 		ret = SFC_NAND_ECC_OK;
415d9cdd318SJon Lin 	else if (ecc == 7)
416d9cdd318SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
417d9cdd318SJon Lin 	else
41858463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
419d9cdd318SJon Lin 
420d9cdd318SJon Lin 	return ret;
421d9cdd318SJon Lin }
422d9cdd318SJon Lin 
423d9cdd318SJon Lin /*
4246281205aSDingqiang Lin  * ecc spectial type3:
425a6fcac41SJon Lin  * ecc bits: 0xC0[4,5] 0xF0[4,5]
426f28847a8SJon Lin  * [0b0000, 0b0011], No bit errors were detected;
427f28847a8SJon Lin  * [0b0100, 0b0111], Bit errors were detected and corrected. Not
4286281205aSDingqiang Lin  *	reach Flipping Bits;
429f28847a8SJon Lin  * [0b1000, 0b1011], Multiple bit errors were detected and
4306281205aSDingqiang Lin  *	not corrected.
431f28847a8SJon Lin  * [0b1100, 0b1111], Bit error count equals the bit flip
4326281205aSDingqiang Lin  *	detectio nthreshold
4336281205aSDingqiang Lin  */
434f28847a8SJon Lin static u32 sfc_nand_get_ecc_status3(void)
4356281205aSDingqiang Lin {
43658463f4dSJon Lin 	u32 ret;
4376281205aSDingqiang Lin 	u32 i;
4386281205aSDingqiang Lin 	u8 ecc;
4396281205aSDingqiang Lin 	u8 status, status1;
4406281205aSDingqiang Lin 	u32 timeout = 1000 * 1000;
4416281205aSDingqiang Lin 
4426281205aSDingqiang Lin 	for (i = 0; i < timeout; i++) {
4436281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
444f28847a8SJon Lin 
4456281205aSDingqiang Lin 		if (ret != SFC_OK)
4466281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
447f28847a8SJon Lin 
4486281205aSDingqiang Lin 		ret = sfc_nand_read_feature(0xF0, &status1);
449f28847a8SJon Lin 
4506281205aSDingqiang Lin 		if (ret != SFC_OK)
4516281205aSDingqiang Lin 			return SFC_NAND_ECC_ERROR;
452f28847a8SJon Lin 
4536281205aSDingqiang Lin 		if (!(status & (1 << 0)))
4546281205aSDingqiang Lin 			break;
455f28847a8SJon Lin 
4566281205aSDingqiang Lin 		sfc_delay(1);
4576281205aSDingqiang Lin 	}
4586281205aSDingqiang Lin 
4596281205aSDingqiang Lin 	ecc = (status >> 4) & 0x03;
4606281205aSDingqiang Lin 	ecc = (ecc << 2) | ((status1 >> 4) & 0x03);
461f28847a8SJon Lin 
4626281205aSDingqiang Lin 	if (ecc < 7)
4636281205aSDingqiang Lin 		ret = SFC_NAND_ECC_OK;
4646281205aSDingqiang Lin 	else if (ecc == 7 || ecc >= 12)
4656281205aSDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
4666281205aSDingqiang Lin 	else
46758463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
4686281205aSDingqiang Lin 
4696281205aSDingqiang Lin 	return ret;
4706281205aSDingqiang Lin }
4716281205aSDingqiang Lin 
47225098c06SDingqiang Lin /*
47325098c06SDingqiang Lin  * ecc spectial type4:
474a6fcac41SJon Lin  * ecc bits: 0xC0[2,5]
475f28847a8SJon Lin  * [0b0000], No bit errors were detected;
476f28847a8SJon Lin  * [0b0001, 0b0111], Bit errors were detected and corrected. Not
47725098c06SDingqiang Lin  *	reach Flipping Bits;
478f28847a8SJon Lin  * [0b1000], Multiple bit errors were detected and
47925098c06SDingqiang Lin  *	not corrected.
480f28847a8SJon Lin  * [0b1100], Bit error count equals the bit flip
48125098c06SDingqiang Lin  *	detection threshold
48225098c06SDingqiang Lin  * else, reserved
48325098c06SDingqiang Lin  */
484f28847a8SJon Lin static u32 sfc_nand_get_ecc_status4(void)
48525098c06SDingqiang Lin {
48658463f4dSJon Lin 	u32 ret;
48725098c06SDingqiang Lin 	u32 i;
48825098c06SDingqiang Lin 	u8 ecc;
48925098c06SDingqiang Lin 	u8 status;
49025098c06SDingqiang Lin 	u32 timeout = 1000 * 1000;
49125098c06SDingqiang Lin 
49225098c06SDingqiang Lin 	for (i = 0; i < timeout; i++) {
49325098c06SDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
494f28847a8SJon Lin 
49525098c06SDingqiang Lin 		if (ret != SFC_OK)
49625098c06SDingqiang Lin 			return SFC_NAND_ECC_ERROR;
497f28847a8SJon Lin 
49825098c06SDingqiang Lin 		if (!(status & (1 << 0)))
49925098c06SDingqiang Lin 			break;
500f28847a8SJon Lin 
50125098c06SDingqiang Lin 		sfc_delay(1);
50225098c06SDingqiang Lin 	}
50325098c06SDingqiang Lin 
50425098c06SDingqiang Lin 	ecc = (status >> 2) & 0x0f;
505f28847a8SJon Lin 
50625098c06SDingqiang Lin 	if (ecc < 7)
50725098c06SDingqiang Lin 		ret = SFC_NAND_ECC_OK;
50825098c06SDingqiang Lin 	else if (ecc == 7 || ecc == 12)
50925098c06SDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
51025098c06SDingqiang Lin 	else
51158463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
51225098c06SDingqiang Lin 
51325098c06SDingqiang Lin 	return ret;
51425098c06SDingqiang Lin }
51525098c06SDingqiang Lin 
51625098c06SDingqiang Lin /*
51725098c06SDingqiang Lin  * ecc spectial type5:
518a6fcac41SJon Lin  * ecc bits: 0xC0[4,6]
519f28847a8SJon Lin  * [0b000], No bit errors were detected;
520f28847a8SJon Lin  * [0b001, 0b011], Bit errors were detected and corrected. Not
52125098c06SDingqiang Lin  *	reach Flipping Bits;
522f28847a8SJon Lin  * [0b100], Bit error count equals the bit flip
52325098c06SDingqiang Lin  *	detection threshold
524f28847a8SJon Lin  * [0b101, 0b110], Reserved;
525f28847a8SJon Lin  * [0b111], Multiple bit errors were detected and
52625098c06SDingqiang Lin  *	not corrected.
52725098c06SDingqiang Lin  */
528f28847a8SJon Lin static u32 sfc_nand_get_ecc_status5(void)
52925098c06SDingqiang Lin {
53058463f4dSJon Lin 	u32 ret;
53125098c06SDingqiang Lin 	u32 i;
53225098c06SDingqiang Lin 	u8 ecc;
53325098c06SDingqiang Lin 	u8 status;
53425098c06SDingqiang Lin 	u32 timeout = 1000 * 1000;
53525098c06SDingqiang Lin 
53625098c06SDingqiang Lin 	for (i = 0; i < timeout; i++) {
53725098c06SDingqiang Lin 		ret = sfc_nand_read_feature(0xC0, &status);
538f28847a8SJon Lin 
53925098c06SDingqiang Lin 		if (ret != SFC_OK)
54025098c06SDingqiang Lin 			return SFC_NAND_ECC_ERROR;
541f28847a8SJon Lin 
54225098c06SDingqiang Lin 		if (!(status & (1 << 0)))
54325098c06SDingqiang Lin 			break;
544f28847a8SJon Lin 
54525098c06SDingqiang Lin 		sfc_delay(1);
54625098c06SDingqiang Lin 	}
54725098c06SDingqiang Lin 
54825098c06SDingqiang Lin 	ecc = (status >> 4) & 0x07;
549f28847a8SJon Lin 
55025098c06SDingqiang Lin 	if (ecc < 4)
55125098c06SDingqiang Lin 		ret = SFC_NAND_ECC_OK;
55225098c06SDingqiang Lin 	else if (ecc == 4)
55325098c06SDingqiang Lin 		ret = SFC_NAND_ECC_REFRESH;
55425098c06SDingqiang Lin 	else
55558463f4dSJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
55625098c06SDingqiang Lin 
55725098c06SDingqiang Lin 	return ret;
55825098c06SDingqiang Lin }
55925098c06SDingqiang Lin 
560f28847a8SJon Lin /*
561f28847a8SJon Lin  * ecc spectial type6:
562f28847a8SJon Lin  * ecc bits: 0xC0[4,6]
563f28847a8SJon Lin  * [0b000], No bit errors were detected;
564f28847a8SJon Lin  * [0b001], 1-3 Bit errors were detected and corrected. Not
565f28847a8SJon Lin  *	reach Flipping Bits;
566f28847a8SJon Lin  * [0b010], Multiple bit errors were detected and
567f28847a8SJon Lin  *	not corrected.
568f28847a8SJon Lin  * [0b011], 4-6 Bit errors were detected and corrected. Not
569f28847a8SJon Lin  *	reach Flipping Bits;
570f28847a8SJon Lin  * [0b101], Bit error count equals the bit flip
571f28847a8SJon Lin  *	detectionthreshold
572f28847a8SJon Lin  * others, Reserved.
573f28847a8SJon Lin  */
574f28847a8SJon Lin static u32 sfc_nand_get_ecc_status6(void)
575f28847a8SJon Lin {
576f28847a8SJon Lin 	u32 ret;
577f28847a8SJon Lin 	u32 i;
578f28847a8SJon Lin 	u8 ecc;
579f28847a8SJon Lin 	u8 status;
580f28847a8SJon Lin 	u32 timeout = 1000 * 1000;
581f28847a8SJon Lin 
582f28847a8SJon Lin 	for (i = 0; i < timeout; i++) {
583f28847a8SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
584f28847a8SJon Lin 
585f28847a8SJon Lin 		if (ret != SFC_OK)
586f28847a8SJon Lin 			return SFC_NAND_ECC_ERROR;
587f28847a8SJon Lin 
588f28847a8SJon Lin 		if (!(status & (1 << 0)))
589f28847a8SJon Lin 			break;
590f28847a8SJon Lin 
591f28847a8SJon Lin 		sfc_delay(1);
592f28847a8SJon Lin 	}
593f28847a8SJon Lin 
594f28847a8SJon Lin 	ecc = (status >> 4) & 0x07;
595f28847a8SJon Lin 
596f28847a8SJon Lin 	if (ecc == 0 || ecc == 1 || ecc == 3)
597f28847a8SJon Lin 		ret = SFC_NAND_ECC_OK;
598f28847a8SJon Lin 	else if (ecc == 5)
599f28847a8SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
600f28847a8SJon Lin 	else
601f28847a8SJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
602f28847a8SJon Lin 
603f28847a8SJon Lin 	return ret;
604f28847a8SJon Lin }
605f28847a8SJon Lin 
606362b1be1SJon Lin /*
607362b1be1SJon Lin  * ecc spectial type7:
608362b1be1SJon Lin  * ecc bits: 0xC0[4,7]
609362b1be1SJon Lin  * [0b0000], No bit errors were detected;
610362b1be1SJon Lin  * [0b0001, 0b0111], 1-7 Bit errors were detected and corrected. Not
611362b1be1SJon Lin  *	reach Flipping Bits;
612362b1be1SJon Lin  * [0b1000], 8 Bit errors were detected and corrected. Bit error count
613362b1be1SJon Lin  * 	equals the bit flip detectionthreshold;
614362b1be1SJon Lin  * [0b1111], Bit errors greater than ECC capability(8 bits) and not corrected;
615362b1be1SJon Lin  * others, Reserved.
616362b1be1SJon Lin  */
617362b1be1SJon Lin static u32 sfc_nand_get_ecc_status7(void)
618362b1be1SJon Lin {
619362b1be1SJon Lin 	u32 ret;
620362b1be1SJon Lin 	u32 i;
621362b1be1SJon Lin 	u8 ecc;
622362b1be1SJon Lin 	u8 status;
623362b1be1SJon Lin 	u32 timeout = 1000 * 1000;
624362b1be1SJon Lin 
625362b1be1SJon Lin 	for (i = 0; i < timeout; i++) {
626362b1be1SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
627362b1be1SJon Lin 
628362b1be1SJon Lin 		if (ret != SFC_OK)
629362b1be1SJon Lin 			return SFC_NAND_ECC_ERROR;
630362b1be1SJon Lin 
631362b1be1SJon Lin 		if (!(status & (1 << 0)))
632362b1be1SJon Lin 			break;
633362b1be1SJon Lin 
634362b1be1SJon Lin 		sfc_delay(1);
635362b1be1SJon Lin 	}
636362b1be1SJon Lin 
637362b1be1SJon Lin 	ecc = (status >> 4) & 0xf;
638362b1be1SJon Lin 
639362b1be1SJon Lin 	if (ecc < 7)
640362b1be1SJon Lin 		ret = SFC_NAND_ECC_OK;
641362b1be1SJon Lin 	else if (ecc == 7 || ecc == 8)
642362b1be1SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
643362b1be1SJon Lin 	else
644362b1be1SJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
645362b1be1SJon Lin 
646362b1be1SJon Lin 	return ret;
647362b1be1SJon Lin }
648362b1be1SJon Lin 
649629111d3SJon Lin /*
650629111d3SJon Lin  * ecc spectial type8:
651629111d3SJon Lin  * ecc bits: 0xC0[4,6]
652629111d3SJon Lin  * [0b000], No bit errors were detected;
653629111d3SJon Lin  * [0b001, 0b011], 1~3 Bit errors were detected and corrected. Not
654629111d3SJon Lin  *	reach Flipping Bits;
655629111d3SJon Lin  * [0b100], Bit error count equals the bit flip
656629111d3SJon Lin  *	detection threshold
657629111d3SJon Lin  * others, Reserved.
658629111d3SJon Lin  */
659629111d3SJon Lin static u32 sfc_nand_get_ecc_status8(void)
660629111d3SJon Lin {
661629111d3SJon Lin 	u32 ret;
662629111d3SJon Lin 	u32 i;
663629111d3SJon Lin 	u8 ecc;
664629111d3SJon Lin 	u8 status;
665629111d3SJon Lin 	u32 timeout = 1000 * 1000;
666629111d3SJon Lin 
667629111d3SJon Lin 	for (i = 0; i < timeout; i++) {
668629111d3SJon Lin 		ret = sfc_nand_read_feature(0xC0, &status);
669629111d3SJon Lin 
670629111d3SJon Lin 		if (ret != SFC_OK)
671629111d3SJon Lin 			return SFC_NAND_ECC_ERROR;
672629111d3SJon Lin 
673629111d3SJon Lin 		if (!(status & (1 << 0)))
674629111d3SJon Lin 			break;
675629111d3SJon Lin 
676629111d3SJon Lin 		sfc_delay(1);
677629111d3SJon Lin 	}
678629111d3SJon Lin 
679629111d3SJon Lin 	ecc = (status >> 4) & 0x07;
680629111d3SJon Lin 
681629111d3SJon Lin 	if (ecc < 4)
682629111d3SJon Lin 		ret = SFC_NAND_ECC_OK;
683629111d3SJon Lin 	else if (ecc == 4)
684629111d3SJon Lin 		ret = SFC_NAND_ECC_REFRESH;
685629111d3SJon Lin 	else
686629111d3SJon Lin 		ret = (u32)SFC_NAND_ECC_ERROR;
687629111d3SJon Lin 
688629111d3SJon Lin 	return ret;
689629111d3SJon Lin }
690629111d3SJon Lin 
691c84f0ed8SJon Lin u32 sfc_nand_erase_block(u8 cs, u32 addr)
692ba0501acSDingqiang Lin {
693ba0501acSDingqiang Lin 	int ret;
69458463f4dSJon Lin 	struct rk_sfc_op op;
695ba0501acSDingqiang Lin 	u8 status;
696ba0501acSDingqiang Lin 
697c84f0ed8SJon Lin 	rkflash_print_dio("%s %x\n", __func__, addr);
69858463f4dSJon Lin 	op.sfcmd.d32 = 0;
699f28847a8SJon Lin 	op.sfcmd.b.cmd = 0xd8;
70058463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_24BITS;
70158463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
70258463f4dSJon Lin 
70358463f4dSJon Lin 	op.sfctrl.d32 = 0;
70458463f4dSJon Lin 
705ba0501acSDingqiang Lin 	sfc_nand_write_en();
70658463f4dSJon Lin 	ret = sfc_request(&op, addr, NULL, 0);
707f28847a8SJon Lin 
708ba0501acSDingqiang Lin 	if (ret != SFC_OK)
709ba0501acSDingqiang Lin 		return ret;
710f28847a8SJon Lin 
711ba0501acSDingqiang Lin 	ret = sfc_nand_wait_busy(&status, 1000 * 1000);
712f28847a8SJon Lin 
713ba0501acSDingqiang Lin 	if (status & (1 << 2))
714ba0501acSDingqiang Lin 		return SFC_NAND_PROG_ERASE_ERROR;
715c84f0ed8SJon Lin 
716ba0501acSDingqiang Lin 	return ret;
717ba0501acSDingqiang Lin }
718ba0501acSDingqiang Lin 
719629111d3SJon Lin static u32 sfc_nand_read_cache(u32 row, u32 *p_page_buf, u32 column, u32 len)
720629111d3SJon Lin {
721629111d3SJon Lin 	int ret;
722629111d3SJon Lin 	u32 plane;
723629111d3SJon Lin 	struct rk_sfc_op op;
724629111d3SJon Lin 
725629111d3SJon Lin 	op.sfcmd.d32 = 0;
726629111d3SJon Lin 	op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd;
727629111d3SJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
728629111d3SJon Lin 	op.sfcmd.b.dummybits = 8;
729629111d3SJon Lin 
730629111d3SJon Lin 	op.sfctrl.d32 = 0;
731629111d3SJon Lin 	op.sfctrl.b.datalines = sfc_nand_dev.read_lines;
732629111d3SJon Lin 	op.sfctrl.b.addrbits = 16;
733629111d3SJon Lin 
734629111d3SJon Lin 	plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0;
735629111d3SJon Lin 
736629111d3SJon Lin 	ret = sfc_request(&op, plane | column, p_page_buf, len);
737629111d3SJon Lin 	if (ret != SFC_OK)
738629111d3SJon Lin 		return SFC_NAND_HW_ERROR;
739629111d3SJon Lin 
740629111d3SJon Lin 	return ret;
741629111d3SJon Lin }
742629111d3SJon Lin 
743f28847a8SJon Lin u32 sfc_nand_prog_page_raw(u8 cs, u32 addr, u32 *p_page_buf)
744ba0501acSDingqiang Lin {
745ba0501acSDingqiang Lin 	int ret;
746415cf080Sjon.lin 	u32 plane;
74758463f4dSJon Lin 	struct rk_sfc_op op;
748ba0501acSDingqiang Lin 	u8 status;
74958463f4dSJon Lin 	u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page;
750629111d3SJon Lin 	u32 data_area_size = SFC_NAND_SECTOR_SIZE * p_nand_info->sec_per_page;
751ba0501acSDingqiang Lin 
752c84f0ed8SJon Lin 	rkflash_print_dio("%s %x %x\n", __func__, addr, p_page_buf[0]);
753ba0501acSDingqiang Lin 	sfc_nand_write_en();
754f28847a8SJon Lin 
755ba0501acSDingqiang Lin 	if (sfc_nand_dev.prog_lines == DATA_LINES_X4 &&
75625098c06SDingqiang Lin 	    p_nand_info->feature & FEA_SOFT_QOP_BIT &&
75725098c06SDingqiang Lin 	    sfc_get_version() < SFC_VER_3)
758ba0501acSDingqiang Lin 		sfc_nand_rw_preset();
759ba0501acSDingqiang Lin 
76058463f4dSJon Lin 	op.sfcmd.d32 = 0;
76158463f4dSJon Lin 	op.sfcmd.b.cmd = sfc_nand_dev.page_prog_cmd;
76258463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
76358463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
764ba0501acSDingqiang Lin 
76558463f4dSJon Lin 	op.sfctrl.d32 = 0;
76658463f4dSJon Lin 	op.sfctrl.b.datalines = sfc_nand_dev.prog_lines;
76758463f4dSJon Lin 	op.sfctrl.b.addrbits = 16;
768415cf080Sjon.lin 	plane = p_nand_info->plane_per_die == 2 ? ((addr >> 6) & 0x1) << 12 : 0;
76958463f4dSJon Lin 	sfc_request(&op, plane, p_page_buf, page_size);
770ba0501acSDingqiang Lin 
771629111d3SJon Lin 	/*
772*c797b43aSJon Lin 	 * At the moment of power lost or dev running in harsh environment, flash
773*c797b43aSJon Lin 	 * maybe work in a unkonw state and result in bit flip, when this situation
774*c797b43aSJon Lin 	 * is detected by cache recheck, it's better to wait a second for a reliable
775*c797b43aSJon Lin 	 * hardware environment to avoid abnormal data written to flash array.
776629111d3SJon Lin 	 */
777*c797b43aSJon Lin 	if (p_nand_info->id0 != MID_XTX) {
778629111d3SJon Lin 		sfc_nand_read_cache(addr, (u32 *)sfc_nand_dev.recheck_buffer, 0, data_area_size);
779*c797b43aSJon Lin 		if (memcmp(sfc_nand_dev.recheck_buffer, p_page_buf, data_area_size)) {
780*c797b43aSJon Lin 			rkflash_print_error("%s %x cache bitflip\n", __func__, addr);
781*c797b43aSJon Lin 			mdelay(1000);
782*c797b43aSJon Lin 			sfc_request(&op, plane, p_page_buf, page_size);
783*c797b43aSJon Lin 		}
784*c797b43aSJon Lin 	}
785629111d3SJon Lin 
78658463f4dSJon Lin 	op.sfcmd.d32 = 0;
787f28847a8SJon Lin 	op.sfcmd.b.cmd = 0x10;
78858463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_24BITS;
78958463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
79058463f4dSJon Lin 
79158463f4dSJon Lin 	op.sfctrl.d32 = 0;
79258463f4dSJon Lin 	ret = sfc_request(&op, addr, p_page_buf, 0);
793f28847a8SJon Lin 
794ba0501acSDingqiang Lin 	if (ret != SFC_OK)
795ba0501acSDingqiang Lin 		return ret;
796f28847a8SJon Lin 
797ba0501acSDingqiang Lin 	ret = sfc_nand_wait_busy(&status, 1000 * 1000);
798ba0501acSDingqiang Lin 	if (status & (1 << 3))
799ba0501acSDingqiang Lin 		return SFC_NAND_PROG_ERASE_ERROR;
800c84f0ed8SJon Lin 
801ba0501acSDingqiang Lin 	return ret;
802ba0501acSDingqiang Lin }
803ba0501acSDingqiang Lin 
804c84f0ed8SJon Lin u32 sfc_nand_prog_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare)
805c84f0ed8SJon Lin {
806c84f0ed8SJon Lin 	int ret;
807c84f0ed8SJon Lin 	u32 sec_per_page = p_nand_info->sec_per_page;
808c84f0ed8SJon Lin 	u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE;
809a6fcac41SJon Lin 	struct nand_mega_area *meta = &p_nand_info->meta;
810c84f0ed8SJon Lin 
811c84f0ed8SJon Lin 	memcpy(gp_page_buf, p_data, data_size);
812c84f0ed8SJon Lin 	memset(&gp_page_buf[data_size / 4], 0xff, sec_per_page * 16);
813a6fcac41SJon Lin 	gp_page_buf[(data_size + meta->off0) / 4] = p_spare[0];
814a6fcac41SJon Lin 	gp_page_buf[(data_size + meta->off1) / 4] = p_spare[1];
815f28847a8SJon Lin 
816c84f0ed8SJon Lin 	if (sec_per_page == 8) {
817a6fcac41SJon Lin 		gp_page_buf[(data_size + meta->off2) / 4] = p_spare[2];
818a6fcac41SJon Lin 		gp_page_buf[(data_size + meta->off3) / 4] = p_spare[3];
819c84f0ed8SJon Lin 	}
820f28847a8SJon Lin 
821c84f0ed8SJon Lin 	ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf);
822c84f0ed8SJon Lin 
823c84f0ed8SJon Lin 	return ret;
824c84f0ed8SJon Lin }
825c84f0ed8SJon Lin 
826a80fd396SJon Lin u32 sfc_nand_read(u32 row, u32 *p_page_buf, u32 column, u32 len)
827ba0501acSDingqiang Lin {
828ba0501acSDingqiang Lin 	int ret;
829415cf080Sjon.lin 	u32 plane;
83058463f4dSJon Lin 	struct rk_sfc_op op;
8316281205aSDingqiang Lin 	u32 ecc_result;
832a6fcac41SJon Lin 	u8 status;
833ba0501acSDingqiang Lin 
83458463f4dSJon Lin 	op.sfcmd.d32 = 0;
835f28847a8SJon Lin 	op.sfcmd.b.cmd = 0x13;
83658463f4dSJon Lin 	op.sfcmd.b.rw = SFC_WRITE;
83758463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_24BITS;
83858463f4dSJon Lin 
83958463f4dSJon Lin 	op.sfctrl.d32 = 0;
84058463f4dSJon Lin 
841a80fd396SJon Lin 	sfc_request(&op, row, p_page_buf, 0);
842f28847a8SJon Lin 
843ba0501acSDingqiang Lin 	if (sfc_nand_dev.read_lines == DATA_LINES_X4 &&
84425098c06SDingqiang Lin 	    p_nand_info->feature & FEA_SOFT_QOP_BIT &&
84525098c06SDingqiang Lin 	    sfc_get_version() < SFC_VER_3)
846ba0501acSDingqiang Lin 		sfc_nand_rw_preset();
847ba0501acSDingqiang Lin 
848a6fcac41SJon Lin 	sfc_nand_wait_busy(&status, 1000 * 1000);
849a6fcac41SJon Lin 	ecc_result = p_nand_info->ecc_status();
850a6fcac41SJon Lin 
85158463f4dSJon Lin 	op.sfcmd.d32 = 0;
85258463f4dSJon Lin 	op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd;
853a80fd396SJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
854a80fd396SJon Lin 	op.sfcmd.b.dummybits = 8;
85558463f4dSJon Lin 
85658463f4dSJon Lin 	op.sfctrl.d32 = 0;
85758463f4dSJon Lin 	op.sfctrl.b.datalines = sfc_nand_dev.read_lines;
858a80fd396SJon Lin 	op.sfctrl.b.addrbits = 16;
859ba0501acSDingqiang Lin 
860a80fd396SJon Lin 	plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0;
861a80fd396SJon Lin 	ret = sfc_request(&op, plane | column, p_page_buf, len);
862a80fd396SJon Lin 	rkflash_print_dio("%s %x %x\n", __func__, row, p_page_buf[0]);
863c84f0ed8SJon Lin 
864c84f0ed8SJon Lin 	if (ret != SFC_OK)
865f28847a8SJon Lin 		return SFC_NAND_HW_ERROR;
866c84f0ed8SJon Lin 
867c84f0ed8SJon Lin 	return ecc_result;
868c84f0ed8SJon Lin }
869c84f0ed8SJon Lin 
870a80fd396SJon Lin u32 sfc_nand_read_page_raw(u8 cs, u32 addr, u32 *p_page_buf)
871a80fd396SJon Lin {
872a80fd396SJon Lin 	u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page;
873a80fd396SJon Lin 
874a80fd396SJon Lin 	return sfc_nand_read(addr, p_page_buf, 0, page_size);
875a80fd396SJon Lin }
876a80fd396SJon Lin 
877c84f0ed8SJon Lin u32 sfc_nand_read_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare)
878c84f0ed8SJon Lin {
87958463f4dSJon Lin 	u32 ret;
880c84f0ed8SJon Lin 	u32 sec_per_page = p_nand_info->sec_per_page;
881c84f0ed8SJon Lin 	u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE;
882a6fcac41SJon Lin 	struct nand_mega_area *meta = &p_nand_info->meta;
883c84f0ed8SJon Lin 
884c84f0ed8SJon Lin 	ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf);
885f25e3cafSJon Lin 	memcpy(p_data, gp_page_buf, data_size);
886a6fcac41SJon Lin 	p_spare[0] = gp_page_buf[(data_size + meta->off0) / 4];
887a6fcac41SJon Lin 	p_spare[1] = gp_page_buf[(data_size + meta->off1) / 4];
888f28847a8SJon Lin 
889f25e3cafSJon Lin 	if (p_nand_info->sec_per_page == 8) {
890a6fcac41SJon Lin 		p_spare[2] = gp_page_buf[(data_size + meta->off2) / 4];
891a6fcac41SJon Lin 		p_spare[3] = gp_page_buf[(data_size + meta->off3) / 4];
892f25e3cafSJon Lin 	}
893ba0501acSDingqiang Lin 
894f28847a8SJon Lin 	if (ret == SFC_NAND_HW_ERROR)
895f28847a8SJon Lin 		ret = SFC_NAND_ECC_ERROR;
896f28847a8SJon Lin 
897c84f0ed8SJon Lin 	if (ret != SFC_NAND_ECC_OK) {
898c84f0ed8SJon Lin 		rkflash_print_error("%s[0x%x], ret=0x%x\n", __func__, addr, ret);
899f28847a8SJon Lin 
900ba0501acSDingqiang Lin 		if (p_data)
901c84f0ed8SJon Lin 			rkflash_print_hex("data:", p_data, 4, 8);
902f28847a8SJon Lin 
903ba0501acSDingqiang Lin 		if (p_spare)
904c84f0ed8SJon Lin 			rkflash_print_hex("spare:", p_spare, 4, 2);
905ba0501acSDingqiang Lin 	}
906f25e3cafSJon Lin 
907c84f0ed8SJon Lin 	return ret;
908ba0501acSDingqiang Lin }
909ba0501acSDingqiang Lin 
910c84f0ed8SJon Lin u32 sfc_nand_check_bad_block(u8 cs, u32 addr)
911c84f0ed8SJon Lin {
912c84f0ed8SJon Lin 	u32 ret;
913c84f0ed8SJon Lin 	u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE;
914a80fd396SJon Lin 	u32 marker = 0;
915c84f0ed8SJon Lin 
916a80fd396SJon Lin 	ret = sfc_nand_read(addr, &marker, data_size, 2);
917f28847a8SJon Lin 
918f28847a8SJon Lin 	/* unify with mtd framework */
919629111d3SJon Lin 	if (ret == SFC_NAND_ECC_ERROR || (u16)marker != 0xffff)
920a80fd396SJon Lin 		rkflash_print_error("%s page= %x ret= %x spare= %x\n",
921a80fd396SJon Lin 				    __func__, addr, ret, marker);
922f28847a8SJon Lin 
923c84f0ed8SJon Lin 	/* Original bad block */
924a80fd396SJon Lin 	if ((u16)marker != 0xffff)
925c84f0ed8SJon Lin 		return true;
926c84f0ed8SJon Lin 
927c84f0ed8SJon Lin 	return false;
928c84f0ed8SJon Lin }
929c84f0ed8SJon Lin 
930c84f0ed8SJon Lin u32 sfc_nand_mark_bad_block(u8 cs, u32 addr)
931c84f0ed8SJon Lin {
932c84f0ed8SJon Lin 	u32 ret;
933c84f0ed8SJon Lin 	u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE;
934c84f0ed8SJon Lin 
935c84f0ed8SJon Lin 	ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf);
936f28847a8SJon Lin 
937c84f0ed8SJon Lin 	if (ret)
938c84f0ed8SJon Lin 		return SFC_NAND_HW_ERROR;
939f28847a8SJon Lin 
940c84f0ed8SJon Lin 	gp_page_buf[data_size / 4] = 0x0;
941c84f0ed8SJon Lin 	ret = sfc_nand_prog_page_raw(cs, addr, gp_page_buf);
942f28847a8SJon Lin 
943c84f0ed8SJon Lin 	if (ret)
944c84f0ed8SJon Lin 		return SFC_NAND_HW_ERROR;
945c84f0ed8SJon Lin 
946c84f0ed8SJon Lin 	return ret;
947c84f0ed8SJon Lin }
948c84f0ed8SJon Lin 
949c84f0ed8SJon Lin int sfc_nand_read_id(u8 *data)
950ba0501acSDingqiang Lin {
951ba0501acSDingqiang Lin 	int ret;
95258463f4dSJon Lin 	struct rk_sfc_op op;
953ba0501acSDingqiang Lin 
95458463f4dSJon Lin 	op.sfcmd.d32 = 0;
95558463f4dSJon Lin 	op.sfcmd.b.cmd = CMD_READ_JEDECID;
95658463f4dSJon Lin 	op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
957ba0501acSDingqiang Lin 
95858463f4dSJon Lin 	op.sfctrl.d32 = 0;
95958463f4dSJon Lin 	op.sfctrl.b.addrbits = 8;
96058463f4dSJon Lin 
96158463f4dSJon Lin 	ret = sfc_request(&op, 0, data, 3);
962ba0501acSDingqiang Lin 
963ba0501acSDingqiang Lin 	return ret;
964ba0501acSDingqiang Lin }
965ba0501acSDingqiang Lin 
966ba0501acSDingqiang Lin /*
967ba0501acSDingqiang Lin  * Read the 1st page's 1st byte of a phy_blk
968ba0501acSDingqiang Lin  * If not FF, it's bad blk
969ba0501acSDingqiang Lin  */
970ba0501acSDingqiang Lin static int sfc_nand_get_bad_block_list(u16 *table, u32 die)
971ba0501acSDingqiang Lin {
972ba0501acSDingqiang Lin 	u32 bad_cnt, page;
973ba0501acSDingqiang Lin 	u32 blk_per_die;
9742ac88c1bSJon Lin 	u16 blk;
975ba0501acSDingqiang Lin 
976c84f0ed8SJon Lin 	rkflash_print_info("%s\n", __func__);
977c84f0ed8SJon Lin 
978ba0501acSDingqiang Lin 	bad_cnt = 0;
979ba0501acSDingqiang Lin 	blk_per_die = p_nand_info->plane_per_die *
980ba0501acSDingqiang Lin 		      p_nand_info->blk_per_plane;
981f28847a8SJon Lin 
982ba0501acSDingqiang Lin 	for (blk = 0; blk < blk_per_die; blk++) {
983ba0501acSDingqiang Lin 		page = (blk + blk_per_die * die) *
984ba0501acSDingqiang Lin 		       p_nand_info->page_per_blk;
985ba0501acSDingqiang Lin 
9862ac88c1bSJon Lin 		if (sfc_nand_check_bad_block(die, page)) {
987ba0501acSDingqiang Lin 			table[bad_cnt++] = blk;
988c84f0ed8SJon Lin 			rkflash_print_error("die[%d], bad_blk[%d]\n", die, blk);
989ba0501acSDingqiang Lin 		}
990ba0501acSDingqiang Lin 	}
991f28847a8SJon Lin 
992ba0501acSDingqiang Lin 	return (int)bad_cnt;
993ba0501acSDingqiang Lin }
994ba0501acSDingqiang Lin 
995c84f0ed8SJon Lin void sfc_nand_ftl_ops_init(void)
996ba0501acSDingqiang Lin {
997ba0501acSDingqiang Lin 	/* para init */
998ba0501acSDingqiang Lin 	g_nand_phy_info.nand_type	= 1;
999ba0501acSDingqiang Lin 	g_nand_phy_info.die_num		= 1;
1000ba0501acSDingqiang Lin 	g_nand_phy_info.plane_per_die	= p_nand_info->plane_per_die;
1001ba0501acSDingqiang Lin 	g_nand_phy_info.blk_per_plane	= p_nand_info->blk_per_plane;
1002ba0501acSDingqiang Lin 	g_nand_phy_info.page_per_blk	= p_nand_info->page_per_blk;
1003ba0501acSDingqiang Lin 	g_nand_phy_info.page_per_slc_blk = p_nand_info->page_per_blk;
1004c84f0ed8SJon Lin 	g_nand_phy_info.byte_per_sec	= SFC_NAND_SECTOR_SIZE;
1005ba0501acSDingqiang Lin 	g_nand_phy_info.sec_per_page	= p_nand_info->sec_per_page;
1006ba0501acSDingqiang Lin 	g_nand_phy_info.sec_per_blk	= p_nand_info->sec_per_page *
1007ba0501acSDingqiang Lin 					  p_nand_info->page_per_blk;
1008ba0501acSDingqiang Lin 	g_nand_phy_info.reserved_blk	= 8;
1009ba0501acSDingqiang Lin 	g_nand_phy_info.blk_per_die	= p_nand_info->plane_per_die *
1010ba0501acSDingqiang Lin 					  p_nand_info->blk_per_plane;
1011ba0501acSDingqiang Lin 	g_nand_phy_info.ecc_bits	= p_nand_info->max_ecc_bits;
1012ba0501acSDingqiang Lin 
1013ba0501acSDingqiang Lin 	/* driver register */
1014ba0501acSDingqiang Lin 	g_nand_ops.get_bad_blk_list	= sfc_nand_get_bad_block_list;
1015ba0501acSDingqiang Lin 	g_nand_ops.erase_blk		= sfc_nand_erase_block;
1016ba0501acSDingqiang Lin 	g_nand_ops.prog_page		= sfc_nand_prog_page;
1017ba0501acSDingqiang Lin 	g_nand_ops.read_page		= sfc_nand_read_page;
101857d18453Sjon.lin 	g_nand_ops.bch_sel		= NULL;
1019ba0501acSDingqiang Lin }
1020ba0501acSDingqiang Lin 
1021a6fcac41SJon Lin static int sfc_nand_enable_QE(void)
1022ba0501acSDingqiang Lin {
1023ba0501acSDingqiang Lin 	int ret = SFC_OK;
1024ba0501acSDingqiang Lin 	u8 status;
1025ba0501acSDingqiang Lin 
1026f28847a8SJon Lin 	ret = sfc_nand_read_feature(0xB0, &status);
1027ba0501acSDingqiang Lin 
1028ba0501acSDingqiang Lin 	if (ret != SFC_OK)
1029ba0501acSDingqiang Lin 		return ret;
1030ba0501acSDingqiang Lin 
1031f28847a8SJon Lin 	if (status & 1)   /* is QE bit set */
1032ba0501acSDingqiang Lin 		return SFC_OK;
1033ba0501acSDingqiang Lin 
1034f28847a8SJon Lin 	status |= 1;
1035ba0501acSDingqiang Lin 
1036f28847a8SJon Lin 	return sfc_nand_write_feature(0xB0, status);
1037ba0501acSDingqiang Lin }
1038ba0501acSDingqiang Lin 
1039ba0501acSDingqiang Lin u32 sfc_nand_init(void)
1040ba0501acSDingqiang Lin {
1041c84f0ed8SJon Lin 	u8 status, id_byte[8];
1042ba0501acSDingqiang Lin 
1043c84f0ed8SJon Lin 	sfc_nand_read_id(id_byte);
1044c84f0ed8SJon Lin 	rkflash_print_error("sfc_nand id: %x %x %x\n",
1045ba0501acSDingqiang Lin 			    id_byte[0], id_byte[1], id_byte[2]);
1046f28847a8SJon Lin 
1047ba0501acSDingqiang Lin 	if (id_byte[0] == 0xFF || id_byte[0] == 0x00)
104858463f4dSJon Lin 		return (u32)FTL_NO_FLASH;
1049ba0501acSDingqiang Lin 
1050a6fcac41SJon Lin 	p_nand_info = sfc_nand_get_info(id_byte);
1051f28847a8SJon Lin 
1052ba0501acSDingqiang Lin 	if (!p_nand_info)
105358463f4dSJon Lin 		return (u32)FTL_UNSUPPORTED_FLASH;
1054ba0501acSDingqiang Lin 
1055ba0501acSDingqiang Lin 	sfc_nand_dev.manufacturer = id_byte[0];
1056ba0501acSDingqiang Lin 	sfc_nand_dev.mem_type = id_byte[1];
1057c84f0ed8SJon Lin 	sfc_nand_dev.capacity = p_nand_info->density;
1058c84f0ed8SJon Lin 	sfc_nand_dev.block_size = p_nand_info->page_per_blk * p_nand_info->sec_per_page;
1059c84f0ed8SJon Lin 	sfc_nand_dev.page_size = p_nand_info->sec_per_page;
1060ba0501acSDingqiang Lin 
1061ba0501acSDingqiang Lin 	/* disable block lock */
1062ba0501acSDingqiang Lin 	sfc_nand_write_feature(0xA0, 0);
1063ba0501acSDingqiang Lin 	sfc_nand_dev.read_lines = DATA_LINES_X1;
1064ba0501acSDingqiang Lin 	sfc_nand_dev.prog_lines = DATA_LINES_X1;
1065f28847a8SJon Lin 	sfc_nand_dev.page_read_cmd = 0x03;
1066f28847a8SJon Lin 	sfc_nand_dev.page_prog_cmd = 0x02;
1067629111d3SJon Lin 	sfc_nand_dev.recheck_buffer = ftl_malloc(SFC_NAND_PAGE_MAX_SIZE);
1068629111d3SJon Lin 	if (!sfc_nand_dev.recheck_buffer) {
1069629111d3SJon Lin 		rkflash_print_error("%s recheck_buffer alloc failed\n", __func__);
1070629111d3SJon Lin 		return -1;
1071629111d3SJon Lin 	}
1072f28847a8SJon Lin 
1073ba0501acSDingqiang Lin 	if (p_nand_info->feature & FEA_4BIT_READ) {
1074f28847a8SJon Lin 		if ((p_nand_info->has_qe_bits && sfc_nand_enable_QE() == SFC_OK) ||
1075f28847a8SJon Lin 		    !p_nand_info->has_qe_bits) {
1076ba0501acSDingqiang Lin 			sfc_nand_dev.read_lines = DATA_LINES_X4;
1077f28847a8SJon Lin 			sfc_nand_dev.page_read_cmd = 0x6b;
1078ba0501acSDingqiang Lin 		}
1079ba0501acSDingqiang Lin 	}
1080ba0501acSDingqiang Lin 
1081ba0501acSDingqiang Lin 	if (p_nand_info->feature & FEA_4BIT_PROG &&
1082ba0501acSDingqiang Lin 	    sfc_nand_dev.read_lines == DATA_LINES_X4) {
1083ba0501acSDingqiang Lin 		sfc_nand_dev.prog_lines = DATA_LINES_X4;
1084f28847a8SJon Lin 		sfc_nand_dev.page_prog_cmd = 0x32;
1085ba0501acSDingqiang Lin 	}
1086ba0501acSDingqiang Lin 
1087ba0501acSDingqiang Lin 	sfc_nand_read_feature(0xA0, &status);
1088c84f0ed8SJon Lin 	rkflash_print_info("sfc_nand A0 = 0x%x\n", status);
1089ba0501acSDingqiang Lin 	sfc_nand_read_feature(0xB0, &status);
1090c84f0ed8SJon Lin 	rkflash_print_info("sfc_nand B0 = 0x%x\n", status);
1091c84f0ed8SJon Lin 	rkflash_print_info("read_lines = %x\n", sfc_nand_dev.read_lines);
1092c84f0ed8SJon Lin 	rkflash_print_info("prog_lines = %x\n", sfc_nand_dev.prog_lines);
1093c84f0ed8SJon Lin 	rkflash_print_info("page_read_cmd = %x\n", sfc_nand_dev.page_read_cmd);
1094c84f0ed8SJon Lin 	rkflash_print_info("page_prog_cmd = %x\n", sfc_nand_dev.page_prog_cmd);
1095ba0501acSDingqiang Lin 
1096ba0501acSDingqiang Lin 	return SFC_OK;
1097ba0501acSDingqiang Lin }
1098ba0501acSDingqiang Lin 
1099c84f0ed8SJon Lin void sfc_nand_deinit(void)
1100ba0501acSDingqiang Lin {
1101c84f0ed8SJon Lin 	/* to-do */
1102629111d3SJon Lin 	kfree(sfc_nand_dev.recheck_buffer);
1103ba0501acSDingqiang Lin }
1104c84f0ed8SJon Lin 
1105c84f0ed8SJon Lin struct SFNAND_DEV *sfc_nand_get_private_dev(void)
1106c84f0ed8SJon Lin {
1107c84f0ed8SJon Lin 	return &sfc_nand_dev;
1108c84f0ed8SJon Lin }
1109c84f0ed8SJon Lin 
1110