xref: /rk3399_rockchip-uboot/drivers/mtd/nand/raw/sunxi_nand_spl.c (revision cfcc706c901d603707657919484e4f65467be9ff)
1*cfcc706cSMiquel Raynal /*
2*cfcc706cSMiquel Raynal  * Copyright (c) 2014-2015, Antmicro Ltd <www.antmicro.com>
3*cfcc706cSMiquel Raynal  * Copyright (c) 2015, AW-SOM Technologies <www.aw-som.com>
4*cfcc706cSMiquel Raynal  *
5*cfcc706cSMiquel Raynal  * SPDX-License-Identifier:     GPL-2.0+
6*cfcc706cSMiquel Raynal  */
7*cfcc706cSMiquel Raynal 
8*cfcc706cSMiquel Raynal #include <asm/arch/clock.h>
9*cfcc706cSMiquel Raynal #include <asm/io.h>
10*cfcc706cSMiquel Raynal #include <common.h>
11*cfcc706cSMiquel Raynal #include <config.h>
12*cfcc706cSMiquel Raynal #include <nand.h>
13*cfcc706cSMiquel Raynal #include <linux/ctype.h>
14*cfcc706cSMiquel Raynal 
15*cfcc706cSMiquel Raynal /* registers */
16*cfcc706cSMiquel Raynal #define NFC_CTL                    0x00000000
17*cfcc706cSMiquel Raynal #define NFC_ST                     0x00000004
18*cfcc706cSMiquel Raynal #define NFC_INT                    0x00000008
19*cfcc706cSMiquel Raynal #define NFC_TIMING_CTL             0x0000000C
20*cfcc706cSMiquel Raynal #define NFC_TIMING_CFG             0x00000010
21*cfcc706cSMiquel Raynal #define NFC_ADDR_LOW               0x00000014
22*cfcc706cSMiquel Raynal #define NFC_ADDR_HIGH              0x00000018
23*cfcc706cSMiquel Raynal #define NFC_SECTOR_NUM             0x0000001C
24*cfcc706cSMiquel Raynal #define NFC_CNT                    0x00000020
25*cfcc706cSMiquel Raynal #define NFC_CMD                    0x00000024
26*cfcc706cSMiquel Raynal #define NFC_RCMD_SET               0x00000028
27*cfcc706cSMiquel Raynal #define NFC_WCMD_SET               0x0000002C
28*cfcc706cSMiquel Raynal #define NFC_IO_DATA                0x00000030
29*cfcc706cSMiquel Raynal #define NFC_ECC_CTL                0x00000034
30*cfcc706cSMiquel Raynal #define NFC_ECC_ST                 0x00000038
31*cfcc706cSMiquel Raynal #define NFC_DEBUG                  0x0000003C
32*cfcc706cSMiquel Raynal #define NFC_ECC_CNT0               0x00000040
33*cfcc706cSMiquel Raynal #define NFC_ECC_CNT1               0x00000044
34*cfcc706cSMiquel Raynal #define NFC_ECC_CNT2               0x00000048
35*cfcc706cSMiquel Raynal #define NFC_ECC_CNT3               0x0000004C
36*cfcc706cSMiquel Raynal #define NFC_USER_DATA_BASE         0x00000050
37*cfcc706cSMiquel Raynal #define NFC_EFNAND_STATUS          0x00000090
38*cfcc706cSMiquel Raynal #define NFC_SPARE_AREA             0x000000A0
39*cfcc706cSMiquel Raynal #define NFC_PATTERN_ID             0x000000A4
40*cfcc706cSMiquel Raynal #define NFC_RAM0_BASE              0x00000400
41*cfcc706cSMiquel Raynal #define NFC_RAM1_BASE              0x00000800
42*cfcc706cSMiquel Raynal 
43*cfcc706cSMiquel Raynal #define NFC_CTL_EN                 (1 << 0)
44*cfcc706cSMiquel Raynal #define NFC_CTL_RESET              (1 << 1)
45*cfcc706cSMiquel Raynal #define NFC_CTL_RAM_METHOD         (1 << 14)
46*cfcc706cSMiquel Raynal #define NFC_CTL_PAGE_SIZE_MASK     (0xf << 8)
47*cfcc706cSMiquel Raynal #define NFC_CTL_PAGE_SIZE(a)       ((fls(a) - 11) << 8)
48*cfcc706cSMiquel Raynal 
49*cfcc706cSMiquel Raynal 
50*cfcc706cSMiquel Raynal #define NFC_ECC_EN                 (1 << 0)
51*cfcc706cSMiquel Raynal #define NFC_ECC_PIPELINE           (1 << 3)
52*cfcc706cSMiquel Raynal #define NFC_ECC_EXCEPTION          (1 << 4)
53*cfcc706cSMiquel Raynal #define NFC_ECC_BLOCK_SIZE         (1 << 5)
54*cfcc706cSMiquel Raynal #define NFC_ECC_RANDOM_EN          (1 << 9)
55*cfcc706cSMiquel Raynal #define NFC_ECC_RANDOM_DIRECTION   (1 << 10)
56*cfcc706cSMiquel Raynal 
57*cfcc706cSMiquel Raynal 
58*cfcc706cSMiquel Raynal #define NFC_ADDR_NUM_OFFSET        16
59*cfcc706cSMiquel Raynal #define NFC_SEND_ADDR              (1 << 19)
60*cfcc706cSMiquel Raynal #define NFC_ACCESS_DIR             (1 << 20)
61*cfcc706cSMiquel Raynal #define NFC_DATA_TRANS             (1 << 21)
62*cfcc706cSMiquel Raynal #define NFC_SEND_CMD1              (1 << 22)
63*cfcc706cSMiquel Raynal #define NFC_WAIT_FLAG              (1 << 23)
64*cfcc706cSMiquel Raynal #define NFC_SEND_CMD2              (1 << 24)
65*cfcc706cSMiquel Raynal #define NFC_SEQ                    (1 << 25)
66*cfcc706cSMiquel Raynal #define NFC_DATA_SWAP_METHOD       (1 << 26)
67*cfcc706cSMiquel Raynal #define NFC_ROW_AUTO_INC           (1 << 27)
68*cfcc706cSMiquel Raynal #define NFC_SEND_CMD3              (1 << 28)
69*cfcc706cSMiquel Raynal #define NFC_SEND_CMD4              (1 << 29)
70*cfcc706cSMiquel Raynal #define NFC_RAW_CMD                (0 << 30)
71*cfcc706cSMiquel Raynal #define NFC_ECC_CMD                (1 << 30)
72*cfcc706cSMiquel Raynal #define NFC_PAGE_CMD               (2 << 30)
73*cfcc706cSMiquel Raynal 
74*cfcc706cSMiquel Raynal #define NFC_ST_CMD_INT_FLAG        (1 << 1)
75*cfcc706cSMiquel Raynal #define NFC_ST_DMA_INT_FLAG        (1 << 2)
76*cfcc706cSMiquel Raynal #define NFC_ST_CMD_FIFO_STAT       (1 << 3)
77*cfcc706cSMiquel Raynal 
78*cfcc706cSMiquel Raynal #define NFC_READ_CMD_OFFSET         0
79*cfcc706cSMiquel Raynal #define NFC_RANDOM_READ_CMD0_OFFSET 8
80*cfcc706cSMiquel Raynal #define NFC_RANDOM_READ_CMD1_OFFSET 16
81*cfcc706cSMiquel Raynal 
82*cfcc706cSMiquel Raynal #define NFC_CMD_RNDOUTSTART        0xE0
83*cfcc706cSMiquel Raynal #define NFC_CMD_RNDOUT             0x05
84*cfcc706cSMiquel Raynal #define NFC_CMD_READSTART          0x30
85*cfcc706cSMiquel Raynal 
86*cfcc706cSMiquel Raynal struct nfc_config {
87*cfcc706cSMiquel Raynal 	int page_size;
88*cfcc706cSMiquel Raynal 	int ecc_strength;
89*cfcc706cSMiquel Raynal 	int ecc_size;
90*cfcc706cSMiquel Raynal 	int addr_cycles;
91*cfcc706cSMiquel Raynal 	int nseeds;
92*cfcc706cSMiquel Raynal 	bool randomize;
93*cfcc706cSMiquel Raynal 	bool valid;
94*cfcc706cSMiquel Raynal };
95*cfcc706cSMiquel Raynal 
96*cfcc706cSMiquel Raynal /* minimal "boot0" style NAND support for Allwinner A20 */
97*cfcc706cSMiquel Raynal 
98*cfcc706cSMiquel Raynal /* random seed used by linux */
99*cfcc706cSMiquel Raynal const uint16_t random_seed[128] = {
100*cfcc706cSMiquel Raynal 	0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72,
101*cfcc706cSMiquel Raynal 	0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436,
102*cfcc706cSMiquel Raynal 	0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d,
103*cfcc706cSMiquel Raynal 	0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130,
104*cfcc706cSMiquel Raynal 	0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56,
105*cfcc706cSMiquel Raynal 	0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55,
106*cfcc706cSMiquel Raynal 	0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb,
107*cfcc706cSMiquel Raynal 	0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17,
108*cfcc706cSMiquel Raynal 	0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62,
109*cfcc706cSMiquel Raynal 	0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064,
110*cfcc706cSMiquel Raynal 	0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126,
111*cfcc706cSMiquel Raynal 	0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e,
112*cfcc706cSMiquel Raynal 	0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3,
113*cfcc706cSMiquel Raynal 	0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b,
114*cfcc706cSMiquel Raynal 	0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d,
115*cfcc706cSMiquel Raynal 	0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db,
116*cfcc706cSMiquel Raynal };
117*cfcc706cSMiquel Raynal 
118*cfcc706cSMiquel Raynal #define DEFAULT_TIMEOUT_US	100000
119*cfcc706cSMiquel Raynal 
check_value_inner(int offset,int expected_bits,int timeout_us,int negation)120*cfcc706cSMiquel Raynal static int check_value_inner(int offset, int expected_bits,
121*cfcc706cSMiquel Raynal 			     int timeout_us, int negation)
122*cfcc706cSMiquel Raynal {
123*cfcc706cSMiquel Raynal 	do {
124*cfcc706cSMiquel Raynal 		int val = readl(offset) & expected_bits;
125*cfcc706cSMiquel Raynal 		if (negation ? !val : val)
126*cfcc706cSMiquel Raynal 			return 1;
127*cfcc706cSMiquel Raynal 		udelay(1);
128*cfcc706cSMiquel Raynal 	} while (--timeout_us);
129*cfcc706cSMiquel Raynal 
130*cfcc706cSMiquel Raynal 	return 0;
131*cfcc706cSMiquel Raynal }
132*cfcc706cSMiquel Raynal 
check_value(int offset,int expected_bits,int timeout_us)133*cfcc706cSMiquel Raynal static inline int check_value(int offset, int expected_bits,
134*cfcc706cSMiquel Raynal 			      int timeout_us)
135*cfcc706cSMiquel Raynal {
136*cfcc706cSMiquel Raynal 	return check_value_inner(offset, expected_bits, timeout_us, 0);
137*cfcc706cSMiquel Raynal }
138*cfcc706cSMiquel Raynal 
check_value_negated(int offset,int unexpected_bits,int timeout_us)139*cfcc706cSMiquel Raynal static inline int check_value_negated(int offset, int unexpected_bits,
140*cfcc706cSMiquel Raynal 				      int timeout_us)
141*cfcc706cSMiquel Raynal {
142*cfcc706cSMiquel Raynal 	return check_value_inner(offset, unexpected_bits, timeout_us, 1);
143*cfcc706cSMiquel Raynal }
144*cfcc706cSMiquel Raynal 
nand_wait_cmd_fifo_empty(void)145*cfcc706cSMiquel Raynal static int nand_wait_cmd_fifo_empty(void)
146*cfcc706cSMiquel Raynal {
147*cfcc706cSMiquel Raynal 	if (!check_value_negated(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_FIFO_STAT,
148*cfcc706cSMiquel Raynal 				 DEFAULT_TIMEOUT_US)) {
149*cfcc706cSMiquel Raynal 		printf("nand: timeout waiting for empty cmd FIFO\n");
150*cfcc706cSMiquel Raynal 		return -ETIMEDOUT;
151*cfcc706cSMiquel Raynal 	}
152*cfcc706cSMiquel Raynal 
153*cfcc706cSMiquel Raynal 	return 0;
154*cfcc706cSMiquel Raynal }
155*cfcc706cSMiquel Raynal 
nand_wait_int(void)156*cfcc706cSMiquel Raynal static int nand_wait_int(void)
157*cfcc706cSMiquel Raynal {
158*cfcc706cSMiquel Raynal 	if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG,
159*cfcc706cSMiquel Raynal 			 DEFAULT_TIMEOUT_US)) {
160*cfcc706cSMiquel Raynal 		printf("nand: timeout waiting for interruption\n");
161*cfcc706cSMiquel Raynal 		return -ETIMEDOUT;
162*cfcc706cSMiquel Raynal 	}
163*cfcc706cSMiquel Raynal 
164*cfcc706cSMiquel Raynal 	return 0;
165*cfcc706cSMiquel Raynal }
166*cfcc706cSMiquel Raynal 
nand_exec_cmd(u32 cmd)167*cfcc706cSMiquel Raynal static int nand_exec_cmd(u32 cmd)
168*cfcc706cSMiquel Raynal {
169*cfcc706cSMiquel Raynal 	int ret;
170*cfcc706cSMiquel Raynal 
171*cfcc706cSMiquel Raynal 	ret = nand_wait_cmd_fifo_empty();
172*cfcc706cSMiquel Raynal 	if (ret)
173*cfcc706cSMiquel Raynal 		return ret;
174*cfcc706cSMiquel Raynal 
175*cfcc706cSMiquel Raynal 	writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST);
176*cfcc706cSMiquel Raynal 	writel(cmd, SUNXI_NFC_BASE + NFC_CMD);
177*cfcc706cSMiquel Raynal 
178*cfcc706cSMiquel Raynal 	return nand_wait_int();
179*cfcc706cSMiquel Raynal }
180*cfcc706cSMiquel Raynal 
nand_init(void)181*cfcc706cSMiquel Raynal void nand_init(void)
182*cfcc706cSMiquel Raynal {
183*cfcc706cSMiquel Raynal 	uint32_t val;
184*cfcc706cSMiquel Raynal 
185*cfcc706cSMiquel Raynal 	board_nand_init();
186*cfcc706cSMiquel Raynal 
187*cfcc706cSMiquel Raynal 	val = readl(SUNXI_NFC_BASE + NFC_CTL);
188*cfcc706cSMiquel Raynal 	/* enable and reset CTL */
189*cfcc706cSMiquel Raynal 	writel(val | NFC_CTL_EN | NFC_CTL_RESET,
190*cfcc706cSMiquel Raynal 	       SUNXI_NFC_BASE + NFC_CTL);
191*cfcc706cSMiquel Raynal 
192*cfcc706cSMiquel Raynal 	if (!check_value_negated(SUNXI_NFC_BASE + NFC_CTL,
193*cfcc706cSMiquel Raynal 				 NFC_CTL_RESET, DEFAULT_TIMEOUT_US)) {
194*cfcc706cSMiquel Raynal 		printf("Couldn't initialize nand\n");
195*cfcc706cSMiquel Raynal 	}
196*cfcc706cSMiquel Raynal 
197*cfcc706cSMiquel Raynal 	/* reset NAND */
198*cfcc706cSMiquel Raynal 	nand_exec_cmd(NFC_SEND_CMD1 | NFC_WAIT_FLAG | NAND_CMD_RESET);
199*cfcc706cSMiquel Raynal }
200*cfcc706cSMiquel Raynal 
nand_apply_config(const struct nfc_config * conf)201*cfcc706cSMiquel Raynal static void nand_apply_config(const struct nfc_config *conf)
202*cfcc706cSMiquel Raynal {
203*cfcc706cSMiquel Raynal 	u32 val;
204*cfcc706cSMiquel Raynal 
205*cfcc706cSMiquel Raynal 	nand_wait_cmd_fifo_empty();
206*cfcc706cSMiquel Raynal 
207*cfcc706cSMiquel Raynal 	val = readl(SUNXI_NFC_BASE + NFC_CTL);
208*cfcc706cSMiquel Raynal 	val &= ~NFC_CTL_PAGE_SIZE_MASK;
209*cfcc706cSMiquel Raynal 	writel(val | NFC_CTL_RAM_METHOD | NFC_CTL_PAGE_SIZE(conf->page_size),
210*cfcc706cSMiquel Raynal 	       SUNXI_NFC_BASE + NFC_CTL);
211*cfcc706cSMiquel Raynal 	writel(conf->ecc_size, SUNXI_NFC_BASE + NFC_CNT);
212*cfcc706cSMiquel Raynal 	writel(conf->page_size, SUNXI_NFC_BASE + NFC_SPARE_AREA);
213*cfcc706cSMiquel Raynal }
214*cfcc706cSMiquel Raynal 
nand_load_page(const struct nfc_config * conf,u32 offs)215*cfcc706cSMiquel Raynal static int nand_load_page(const struct nfc_config *conf, u32 offs)
216*cfcc706cSMiquel Raynal {
217*cfcc706cSMiquel Raynal 	int page = offs / conf->page_size;
218*cfcc706cSMiquel Raynal 
219*cfcc706cSMiquel Raynal 	writel((NFC_CMD_RNDOUTSTART << NFC_RANDOM_READ_CMD1_OFFSET) |
220*cfcc706cSMiquel Raynal 	       (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET) |
221*cfcc706cSMiquel Raynal 	       (NFC_CMD_READSTART << NFC_READ_CMD_OFFSET),
222*cfcc706cSMiquel Raynal 	       SUNXI_NFC_BASE + NFC_RCMD_SET);
223*cfcc706cSMiquel Raynal 	writel(((page & 0xFFFF) << 16), SUNXI_NFC_BASE + NFC_ADDR_LOW);
224*cfcc706cSMiquel Raynal 	writel((page >> 16) & 0xFF, SUNXI_NFC_BASE + NFC_ADDR_HIGH);
225*cfcc706cSMiquel Raynal 
226*cfcc706cSMiquel Raynal 	return nand_exec_cmd(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD |
227*cfcc706cSMiquel Raynal 			     NFC_SEND_ADDR | NFC_WAIT_FLAG |
228*cfcc706cSMiquel Raynal 			     ((conf->addr_cycles - 1) << NFC_ADDR_NUM_OFFSET));
229*cfcc706cSMiquel Raynal }
230*cfcc706cSMiquel Raynal 
nand_change_column(u16 column)231*cfcc706cSMiquel Raynal static int nand_change_column(u16 column)
232*cfcc706cSMiquel Raynal {
233*cfcc706cSMiquel Raynal 	int ret;
234*cfcc706cSMiquel Raynal 
235*cfcc706cSMiquel Raynal 	writel((NFC_CMD_RNDOUTSTART << NFC_RANDOM_READ_CMD1_OFFSET) |
236*cfcc706cSMiquel Raynal 	       (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET) |
237*cfcc706cSMiquel Raynal 	       (NFC_CMD_RNDOUTSTART << NFC_READ_CMD_OFFSET),
238*cfcc706cSMiquel Raynal 	       SUNXI_NFC_BASE + NFC_RCMD_SET);
239*cfcc706cSMiquel Raynal 	writel(column, SUNXI_NFC_BASE + NFC_ADDR_LOW);
240*cfcc706cSMiquel Raynal 
241*cfcc706cSMiquel Raynal 	ret = nand_exec_cmd(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD |
242*cfcc706cSMiquel Raynal 			    (1 << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADDR |
243*cfcc706cSMiquel Raynal 			    NFC_CMD_RNDOUT);
244*cfcc706cSMiquel Raynal 	if (ret)
245*cfcc706cSMiquel Raynal 		return ret;
246*cfcc706cSMiquel Raynal 
247*cfcc706cSMiquel Raynal 	/* Ensure tCCS has passed before reading data */
248*cfcc706cSMiquel Raynal 	udelay(1);
249*cfcc706cSMiquel Raynal 
250*cfcc706cSMiquel Raynal 	return 0;
251*cfcc706cSMiquel Raynal }
252*cfcc706cSMiquel Raynal 
253*cfcc706cSMiquel Raynal static const int ecc_bytes[] = {32, 46, 54, 60, 74, 88, 102, 110, 116};
254*cfcc706cSMiquel Raynal 
nand_read_page(const struct nfc_config * conf,u32 offs,void * dest,int len)255*cfcc706cSMiquel Raynal static int nand_read_page(const struct nfc_config *conf, u32 offs,
256*cfcc706cSMiquel Raynal 			  void *dest, int len)
257*cfcc706cSMiquel Raynal {
258*cfcc706cSMiquel Raynal 	int nsectors = len / conf->ecc_size;
259*cfcc706cSMiquel Raynal 	u16 rand_seed = 0;
260*cfcc706cSMiquel Raynal 	int oob_chunk_sz = ecc_bytes[conf->ecc_strength];
261*cfcc706cSMiquel Raynal 	int page = offs / conf->page_size;
262*cfcc706cSMiquel Raynal 	u32 ecc_st;
263*cfcc706cSMiquel Raynal 	int i;
264*cfcc706cSMiquel Raynal 
265*cfcc706cSMiquel Raynal 	if (offs % conf->page_size || len % conf->ecc_size ||
266*cfcc706cSMiquel Raynal 	    len > conf->page_size || len < 0)
267*cfcc706cSMiquel Raynal 		return -EINVAL;
268*cfcc706cSMiquel Raynal 
269*cfcc706cSMiquel Raynal 	/* Choose correct seed if randomized */
270*cfcc706cSMiquel Raynal 	if (conf->randomize)
271*cfcc706cSMiquel Raynal 		rand_seed = random_seed[page % conf->nseeds];
272*cfcc706cSMiquel Raynal 
273*cfcc706cSMiquel Raynal 	/* Retrieve data from SRAM (PIO) */
274*cfcc706cSMiquel Raynal 	for (i = 0; i < nsectors; i++) {
275*cfcc706cSMiquel Raynal 		int data_off = i * conf->ecc_size;
276*cfcc706cSMiquel Raynal 		int oob_off = conf->page_size + (i * oob_chunk_sz);
277*cfcc706cSMiquel Raynal 		u8 *data = dest + data_off;
278*cfcc706cSMiquel Raynal 
279*cfcc706cSMiquel Raynal 		/* Clear ECC status and restart ECC engine */
280*cfcc706cSMiquel Raynal 		writel(0, SUNXI_NFC_BASE + NFC_ECC_ST);
281*cfcc706cSMiquel Raynal 		writel((rand_seed << 16) | (conf->ecc_strength << 12) |
282*cfcc706cSMiquel Raynal 		       (conf->randomize ? NFC_ECC_RANDOM_EN : 0) |
283*cfcc706cSMiquel Raynal 		       (conf->ecc_size == 512 ? NFC_ECC_BLOCK_SIZE : 0) |
284*cfcc706cSMiquel Raynal 		       NFC_ECC_EN | NFC_ECC_EXCEPTION,
285*cfcc706cSMiquel Raynal 		       SUNXI_NFC_BASE + NFC_ECC_CTL);
286*cfcc706cSMiquel Raynal 
287*cfcc706cSMiquel Raynal 		/* Move the data in SRAM */
288*cfcc706cSMiquel Raynal 		nand_change_column(data_off);
289*cfcc706cSMiquel Raynal 		writel(conf->ecc_size, SUNXI_NFC_BASE + NFC_CNT);
290*cfcc706cSMiquel Raynal 		nand_exec_cmd(NFC_DATA_TRANS);
291*cfcc706cSMiquel Raynal 
292*cfcc706cSMiquel Raynal 		/*
293*cfcc706cSMiquel Raynal 		 * Let the ECC engine consume the ECC bytes and possibly correct
294*cfcc706cSMiquel Raynal 		 * the data.
295*cfcc706cSMiquel Raynal 		 */
296*cfcc706cSMiquel Raynal 		nand_change_column(oob_off);
297*cfcc706cSMiquel Raynal 		nand_exec_cmd(NFC_DATA_TRANS | NFC_ECC_CMD);
298*cfcc706cSMiquel Raynal 
299*cfcc706cSMiquel Raynal 		/* Get the ECC status */
300*cfcc706cSMiquel Raynal 		ecc_st = readl(SUNXI_NFC_BASE + NFC_ECC_ST);
301*cfcc706cSMiquel Raynal 
302*cfcc706cSMiquel Raynal 		/* ECC error detected. */
303*cfcc706cSMiquel Raynal 		if (ecc_st & 0xffff)
304*cfcc706cSMiquel Raynal 			return -EIO;
305*cfcc706cSMiquel Raynal 
306*cfcc706cSMiquel Raynal 		/*
307*cfcc706cSMiquel Raynal 		 * Return 1 if the first chunk is empty (needed for
308*cfcc706cSMiquel Raynal 		 * configuration detection).
309*cfcc706cSMiquel Raynal 		 */
310*cfcc706cSMiquel Raynal 		if (!i && (ecc_st & 0x10000))
311*cfcc706cSMiquel Raynal 			return 1;
312*cfcc706cSMiquel Raynal 
313*cfcc706cSMiquel Raynal 		/* Retrieve the data from SRAM */
314*cfcc706cSMiquel Raynal 		memcpy_fromio(data, SUNXI_NFC_BASE + NFC_RAM0_BASE,
315*cfcc706cSMiquel Raynal 			      conf->ecc_size);
316*cfcc706cSMiquel Raynal 
317*cfcc706cSMiquel Raynal 		/* Stop the ECC engine */
318*cfcc706cSMiquel Raynal 		writel(readl(SUNXI_NFC_BASE + NFC_ECC_CTL) & ~NFC_ECC_EN,
319*cfcc706cSMiquel Raynal 		       SUNXI_NFC_BASE + NFC_ECC_CTL);
320*cfcc706cSMiquel Raynal 
321*cfcc706cSMiquel Raynal 		if (data_off + conf->ecc_size >= len)
322*cfcc706cSMiquel Raynal 			break;
323*cfcc706cSMiquel Raynal 	}
324*cfcc706cSMiquel Raynal 
325*cfcc706cSMiquel Raynal 	return 0;
326*cfcc706cSMiquel Raynal }
327*cfcc706cSMiquel Raynal 
nand_max_ecc_strength(struct nfc_config * conf)328*cfcc706cSMiquel Raynal static int nand_max_ecc_strength(struct nfc_config *conf)
329*cfcc706cSMiquel Raynal {
330*cfcc706cSMiquel Raynal 	int max_oobsize, max_ecc_bytes;
331*cfcc706cSMiquel Raynal 	int nsectors = conf->page_size / conf->ecc_size;
332*cfcc706cSMiquel Raynal 	int i;
333*cfcc706cSMiquel Raynal 
334*cfcc706cSMiquel Raynal 	/*
335*cfcc706cSMiquel Raynal 	 * ECC strength is limited by the size of the OOB area which is
336*cfcc706cSMiquel Raynal 	 * correlated with the page size.
337*cfcc706cSMiquel Raynal 	 */
338*cfcc706cSMiquel Raynal 	switch (conf->page_size) {
339*cfcc706cSMiquel Raynal 	case 2048:
340*cfcc706cSMiquel Raynal 		max_oobsize = 64;
341*cfcc706cSMiquel Raynal 		break;
342*cfcc706cSMiquel Raynal 	case 4096:
343*cfcc706cSMiquel Raynal 		max_oobsize = 256;
344*cfcc706cSMiquel Raynal 		break;
345*cfcc706cSMiquel Raynal 	case 8192:
346*cfcc706cSMiquel Raynal 		max_oobsize = 640;
347*cfcc706cSMiquel Raynal 		break;
348*cfcc706cSMiquel Raynal 	case 16384:
349*cfcc706cSMiquel Raynal 		max_oobsize = 1664;
350*cfcc706cSMiquel Raynal 		break;
351*cfcc706cSMiquel Raynal 	default:
352*cfcc706cSMiquel Raynal 		return -EINVAL;
353*cfcc706cSMiquel Raynal 	}
354*cfcc706cSMiquel Raynal 
355*cfcc706cSMiquel Raynal 	max_ecc_bytes = max_oobsize / nsectors;
356*cfcc706cSMiquel Raynal 
357*cfcc706cSMiquel Raynal 	for (i = 0; i < ARRAY_SIZE(ecc_bytes); i++) {
358*cfcc706cSMiquel Raynal 		if (ecc_bytes[i] > max_ecc_bytes)
359*cfcc706cSMiquel Raynal 			break;
360*cfcc706cSMiquel Raynal 	}
361*cfcc706cSMiquel Raynal 
362*cfcc706cSMiquel Raynal 	if (!i)
363*cfcc706cSMiquel Raynal 		return -EINVAL;
364*cfcc706cSMiquel Raynal 
365*cfcc706cSMiquel Raynal 	return i - 1;
366*cfcc706cSMiquel Raynal }
367*cfcc706cSMiquel Raynal 
nand_detect_ecc_config(struct nfc_config * conf,u32 offs,void * dest)368*cfcc706cSMiquel Raynal static int nand_detect_ecc_config(struct nfc_config *conf, u32 offs,
369*cfcc706cSMiquel Raynal 				  void *dest)
370*cfcc706cSMiquel Raynal {
371*cfcc706cSMiquel Raynal 	/* NAND with pages > 4k will likely require 1k sector size. */
372*cfcc706cSMiquel Raynal 	int min_ecc_size = conf->page_size > 4096 ? 1024 : 512;
373*cfcc706cSMiquel Raynal 	int page = offs / conf->page_size;
374*cfcc706cSMiquel Raynal 	int ret;
375*cfcc706cSMiquel Raynal 
376*cfcc706cSMiquel Raynal 	/*
377*cfcc706cSMiquel Raynal 	 * In most cases, 1k sectors are preferred over 512b ones, start
378*cfcc706cSMiquel Raynal 	 * testing this config first.
379*cfcc706cSMiquel Raynal 	 */
380*cfcc706cSMiquel Raynal 	for (conf->ecc_size = 1024; conf->ecc_size >= min_ecc_size;
381*cfcc706cSMiquel Raynal 	     conf->ecc_size >>= 1) {
382*cfcc706cSMiquel Raynal 		int max_ecc_strength = nand_max_ecc_strength(conf);
383*cfcc706cSMiquel Raynal 
384*cfcc706cSMiquel Raynal 		nand_apply_config(conf);
385*cfcc706cSMiquel Raynal 
386*cfcc706cSMiquel Raynal 		/*
387*cfcc706cSMiquel Raynal 		 * We are starting from the maximum ECC strength because
388*cfcc706cSMiquel Raynal 		 * most of the time NAND vendors provide an OOB area that
389*cfcc706cSMiquel Raynal 		 * barely meets the ECC requirements.
390*cfcc706cSMiquel Raynal 		 */
391*cfcc706cSMiquel Raynal 		for (conf->ecc_strength = max_ecc_strength;
392*cfcc706cSMiquel Raynal 		     conf->ecc_strength >= 0;
393*cfcc706cSMiquel Raynal 		     conf->ecc_strength--) {
394*cfcc706cSMiquel Raynal 			conf->randomize = false;
395*cfcc706cSMiquel Raynal 			if (nand_change_column(0))
396*cfcc706cSMiquel Raynal 				return -EIO;
397*cfcc706cSMiquel Raynal 
398*cfcc706cSMiquel Raynal 			/*
399*cfcc706cSMiquel Raynal 			 * Only read the first sector to speedup detection.
400*cfcc706cSMiquel Raynal 			 */
401*cfcc706cSMiquel Raynal 			ret = nand_read_page(conf, offs, dest, conf->ecc_size);
402*cfcc706cSMiquel Raynal 			if (!ret) {
403*cfcc706cSMiquel Raynal 				return 0;
404*cfcc706cSMiquel Raynal 			} else if (ret > 0) {
405*cfcc706cSMiquel Raynal 				/*
406*cfcc706cSMiquel Raynal 				 * If page is empty we can't deduce anything
407*cfcc706cSMiquel Raynal 				 * about the ECC config => stop the detection.
408*cfcc706cSMiquel Raynal 				 */
409*cfcc706cSMiquel Raynal 				return -EINVAL;
410*cfcc706cSMiquel Raynal 			}
411*cfcc706cSMiquel Raynal 
412*cfcc706cSMiquel Raynal 			conf->randomize = true;
413*cfcc706cSMiquel Raynal 			conf->nseeds = ARRAY_SIZE(random_seed);
414*cfcc706cSMiquel Raynal 			do {
415*cfcc706cSMiquel Raynal 				if (nand_change_column(0))
416*cfcc706cSMiquel Raynal 					return -EIO;
417*cfcc706cSMiquel Raynal 
418*cfcc706cSMiquel Raynal 				if (!nand_read_page(conf, offs, dest,
419*cfcc706cSMiquel Raynal 						    conf->ecc_size))
420*cfcc706cSMiquel Raynal 					return 0;
421*cfcc706cSMiquel Raynal 
422*cfcc706cSMiquel Raynal 				/*
423*cfcc706cSMiquel Raynal 				 * Find the next ->nseeds value that would
424*cfcc706cSMiquel Raynal 				 * change the randomizer seed for the page
425*cfcc706cSMiquel Raynal 				 * we're trying to read.
426*cfcc706cSMiquel Raynal 				 */
427*cfcc706cSMiquel Raynal 				while (conf->nseeds >= 16) {
428*cfcc706cSMiquel Raynal 					int seed = page % conf->nseeds;
429*cfcc706cSMiquel Raynal 
430*cfcc706cSMiquel Raynal 					conf->nseeds >>= 1;
431*cfcc706cSMiquel Raynal 					if (seed != page % conf->nseeds)
432*cfcc706cSMiquel Raynal 						break;
433*cfcc706cSMiquel Raynal 				}
434*cfcc706cSMiquel Raynal 			} while (conf->nseeds >= 16);
435*cfcc706cSMiquel Raynal 		}
436*cfcc706cSMiquel Raynal 	}
437*cfcc706cSMiquel Raynal 
438*cfcc706cSMiquel Raynal 	return -EINVAL;
439*cfcc706cSMiquel Raynal }
440*cfcc706cSMiquel Raynal 
nand_detect_config(struct nfc_config * conf,u32 offs,void * dest)441*cfcc706cSMiquel Raynal static int nand_detect_config(struct nfc_config *conf, u32 offs, void *dest)
442*cfcc706cSMiquel Raynal {
443*cfcc706cSMiquel Raynal 	if (conf->valid)
444*cfcc706cSMiquel Raynal 		return 0;
445*cfcc706cSMiquel Raynal 
446*cfcc706cSMiquel Raynal 	/*
447*cfcc706cSMiquel Raynal 	 * Modern NANDs are more likely than legacy ones, so we start testing
448*cfcc706cSMiquel Raynal 	 * with 5 address cycles.
449*cfcc706cSMiquel Raynal 	 */
450*cfcc706cSMiquel Raynal 	for (conf->addr_cycles = 5;
451*cfcc706cSMiquel Raynal 	     conf->addr_cycles >= 4;
452*cfcc706cSMiquel Raynal 	     conf->addr_cycles--) {
453*cfcc706cSMiquel Raynal 		int max_page_size = conf->addr_cycles == 4 ? 2048 : 16384;
454*cfcc706cSMiquel Raynal 
455*cfcc706cSMiquel Raynal 		/*
456*cfcc706cSMiquel Raynal 		 * Ignoring 1k pages cause I'm not even sure this case exist
457*cfcc706cSMiquel Raynal 		 * in the real world.
458*cfcc706cSMiquel Raynal 		 */
459*cfcc706cSMiquel Raynal 		for (conf->page_size = 2048; conf->page_size <= max_page_size;
460*cfcc706cSMiquel Raynal 		     conf->page_size <<= 1) {
461*cfcc706cSMiquel Raynal 			if (nand_load_page(conf, offs))
462*cfcc706cSMiquel Raynal 				return -1;
463*cfcc706cSMiquel Raynal 
464*cfcc706cSMiquel Raynal 			if (!nand_detect_ecc_config(conf, offs, dest)) {
465*cfcc706cSMiquel Raynal 				conf->valid = true;
466*cfcc706cSMiquel Raynal 				return 0;
467*cfcc706cSMiquel Raynal 			}
468*cfcc706cSMiquel Raynal 		}
469*cfcc706cSMiquel Raynal 	}
470*cfcc706cSMiquel Raynal 
471*cfcc706cSMiquel Raynal 	return -EINVAL;
472*cfcc706cSMiquel Raynal }
473*cfcc706cSMiquel Raynal 
nand_read_buffer(struct nfc_config * conf,uint32_t offs,unsigned int size,void * dest)474*cfcc706cSMiquel Raynal static int nand_read_buffer(struct nfc_config *conf, uint32_t offs,
475*cfcc706cSMiquel Raynal 			    unsigned int size, void *dest)
476*cfcc706cSMiquel Raynal {
477*cfcc706cSMiquel Raynal 	int first_seed = 0, page, ret;
478*cfcc706cSMiquel Raynal 
479*cfcc706cSMiquel Raynal 	size = ALIGN(size, conf->page_size);
480*cfcc706cSMiquel Raynal 	page = offs / conf->page_size;
481*cfcc706cSMiquel Raynal 	if (conf->randomize)
482*cfcc706cSMiquel Raynal 		first_seed = page % conf->nseeds;
483*cfcc706cSMiquel Raynal 
484*cfcc706cSMiquel Raynal 	for (; size; size -= conf->page_size) {
485*cfcc706cSMiquel Raynal 		if (nand_load_page(conf, offs))
486*cfcc706cSMiquel Raynal 			return -1;
487*cfcc706cSMiquel Raynal 
488*cfcc706cSMiquel Raynal 		ret = nand_read_page(conf, offs, dest, conf->page_size);
489*cfcc706cSMiquel Raynal 		/*
490*cfcc706cSMiquel Raynal 		 * The ->nseeds value should be equal to the number of pages
491*cfcc706cSMiquel Raynal 		 * in an eraseblock. Since we don't know this information in
492*cfcc706cSMiquel Raynal 		 * advance we might have picked a wrong value.
493*cfcc706cSMiquel Raynal 		 */
494*cfcc706cSMiquel Raynal 		if (ret < 0 && conf->randomize) {
495*cfcc706cSMiquel Raynal 			int cur_seed = page % conf->nseeds;
496*cfcc706cSMiquel Raynal 
497*cfcc706cSMiquel Raynal 			/*
498*cfcc706cSMiquel Raynal 			 * We already tried all the seed values => we are
499*cfcc706cSMiquel Raynal 			 * facing a real corruption.
500*cfcc706cSMiquel Raynal 			 */
501*cfcc706cSMiquel Raynal 			if (cur_seed < first_seed)
502*cfcc706cSMiquel Raynal 				return -EIO;
503*cfcc706cSMiquel Raynal 
504*cfcc706cSMiquel Raynal 			/* Try to adjust ->nseeds and read the page again... */
505*cfcc706cSMiquel Raynal 			conf->nseeds = cur_seed;
506*cfcc706cSMiquel Raynal 
507*cfcc706cSMiquel Raynal 			if (nand_change_column(0))
508*cfcc706cSMiquel Raynal 				return -EIO;
509*cfcc706cSMiquel Raynal 
510*cfcc706cSMiquel Raynal 			/* ... it still fails => it's a real corruption. */
511*cfcc706cSMiquel Raynal 			if (nand_read_page(conf, offs, dest, conf->page_size))
512*cfcc706cSMiquel Raynal 				return -EIO;
513*cfcc706cSMiquel Raynal 		} else if (ret && conf->randomize) {
514*cfcc706cSMiquel Raynal 			memset(dest, 0xff, conf->page_size);
515*cfcc706cSMiquel Raynal 		}
516*cfcc706cSMiquel Raynal 
517*cfcc706cSMiquel Raynal 		page++;
518*cfcc706cSMiquel Raynal 		offs += conf->page_size;
519*cfcc706cSMiquel Raynal 		dest += conf->page_size;
520*cfcc706cSMiquel Raynal 	}
521*cfcc706cSMiquel Raynal 
522*cfcc706cSMiquel Raynal 	return 0;
523*cfcc706cSMiquel Raynal }
524*cfcc706cSMiquel Raynal 
nand_spl_load_image(uint32_t offs,unsigned int size,void * dest)525*cfcc706cSMiquel Raynal int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest)
526*cfcc706cSMiquel Raynal {
527*cfcc706cSMiquel Raynal 	static struct nfc_config conf = { };
528*cfcc706cSMiquel Raynal 	int ret;
529*cfcc706cSMiquel Raynal 
530*cfcc706cSMiquel Raynal 	ret = nand_detect_config(&conf, offs, dest);
531*cfcc706cSMiquel Raynal 	if (ret)
532*cfcc706cSMiquel Raynal 		return ret;
533*cfcc706cSMiquel Raynal 
534*cfcc706cSMiquel Raynal 	return nand_read_buffer(&conf, offs, size, dest);
535*cfcc706cSMiquel Raynal }
536*cfcc706cSMiquel Raynal 
nand_deselect(void)537*cfcc706cSMiquel Raynal void nand_deselect(void)
538*cfcc706cSMiquel Raynal {
539*cfcc706cSMiquel Raynal 	struct sunxi_ccm_reg *const ccm =
540*cfcc706cSMiquel Raynal 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
541*cfcc706cSMiquel Raynal 
542*cfcc706cSMiquel Raynal 	clrbits_le32(&ccm->ahb_gate0, (CLK_GATE_OPEN << AHB_GATE_OFFSET_NAND0));
543*cfcc706cSMiquel Raynal #ifdef CONFIG_MACH_SUN9I
544*cfcc706cSMiquel Raynal 	clrbits_le32(&ccm->ahb_gate1, (1 << AHB_GATE_OFFSET_DMA));
545*cfcc706cSMiquel Raynal #else
546*cfcc706cSMiquel Raynal 	clrbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_DMA));
547*cfcc706cSMiquel Raynal #endif
548*cfcc706cSMiquel Raynal 	clrbits_le32(&ccm->nand0_clk_cfg, CCM_NAND_CTRL_ENABLE | AHB_DIV_1);
549*cfcc706cSMiquel Raynal }
550