]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/mtd/nand/sunxi_nand_spl.c
sunxi_nand_spl: Use SYS_NAND_SELF_INIT and only do nand init when necessary
[karo-tx-uboot.git] / drivers / mtd / nand / sunxi_nand_spl.c
1 /*
2  * Copyright (c) 2014-2015, Antmicro Ltd <www.antmicro.com>
3  * Copyright (c) 2015, AW-SOM Technologies <www.aw-som.com>
4  *
5  * SPDX-License-Identifier:     GPL-2.0+
6  */
7
8 #include <common.h>
9 #include <config.h>
10 #include <asm/io.h>
11 #include <nand.h>
12
13 /* registers */
14 #define NFC_CTL                    0x00000000
15 #define NFC_ST                     0x00000004
16 #define NFC_INT                    0x00000008
17 #define NFC_TIMING_CTL             0x0000000C
18 #define NFC_TIMING_CFG             0x00000010
19 #define NFC_ADDR_LOW               0x00000014
20 #define NFC_ADDR_HIGH              0x00000018
21 #define NFC_SECTOR_NUM             0x0000001C
22 #define NFC_CNT                    0x00000020
23 #define NFC_CMD                    0x00000024
24 #define NFC_RCMD_SET               0x00000028
25 #define NFC_WCMD_SET               0x0000002C
26 #define NFC_IO_DATA                0x00000030
27 #define NFC_ECC_CTL                0x00000034
28 #define NFC_ECC_ST                 0x00000038
29 #define NFC_DEBUG                  0x0000003C
30 #define NFC_ECC_CNT0               0x00000040
31 #define NFC_ECC_CNT1               0x00000044
32 #define NFC_ECC_CNT2               0x00000048
33 #define NFC_ECC_CNT3               0x0000004C
34 #define NFC_USER_DATA_BASE         0x00000050
35 #define NFC_EFNAND_STATUS          0x00000090
36 #define NFC_SPARE_AREA             0x000000A0
37 #define NFC_PATTERN_ID             0x000000A4
38 #define NFC_RAM0_BASE              0x00000400
39 #define NFC_RAM1_BASE              0x00000800
40
41 #define NFC_CTL_EN                 (1 << 0)
42 #define NFC_CTL_RESET              (1 << 1)
43 #define NFC_CTL_RAM_METHOD         (1 << 14)
44
45
46 #define NFC_ECC_EN                 (1 << 0)
47 #define NFC_ECC_PIPELINE           (1 << 3)
48 #define NFC_ECC_EXCEPTION          (1 << 4)
49 #define NFC_ECC_BLOCK_SIZE         (1 << 5)
50 #define NFC_ECC_RANDOM_EN          (1 << 9)
51 #define NFC_ECC_RANDOM_DIRECTION   (1 << 10)
52
53
54 #define NFC_ADDR_NUM_OFFSET        16
55 #define NFC_SEND_ADR               (1 << 19)
56 #define NFC_ACCESS_DIR             (1 << 20)
57 #define NFC_DATA_TRANS             (1 << 21)
58 #define NFC_SEND_CMD1              (1 << 22)
59 #define NFC_WAIT_FLAG              (1 << 23)
60 #define NFC_SEND_CMD2              (1 << 24)
61 #define NFC_SEQ                    (1 << 25)
62 #define NFC_DATA_SWAP_METHOD       (1 << 26)
63 #define NFC_ROW_AUTO_INC           (1 << 27)
64 #define NFC_SEND_CMD3              (1 << 28)
65 #define NFC_SEND_CMD4              (1 << 29)
66
67 #define NFC_CMD_INT_FLAG           (1 << 1)
68
69 #define NFC_READ_CMD_OFFSET         0
70 #define NFC_RANDOM_READ_CMD0_OFFSET 8
71 #define NFC_RANDOM_READ_CMD1_OFFSET 16
72
73 #define NFC_CMD_RNDOUTSTART        0xE0
74 #define NFC_CMD_RNDOUT             0x05
75 #define NFC_CMD_READSTART          0x30
76
77
78 #define NFC_PAGE_CMD               (2 << 30)
79
80 #define SUNXI_DMA_CFG_REG0              0x300
81 #define SUNXI_DMA_SRC_START_ADDR_REG0   0x304
82 #define SUNXI_DMA_DEST_START_ADDRR_REG0 0x308
83 #define SUNXI_DMA_DDMA_BC_REG0          0x30C
84 #define SUNXI_DMA_DDMA_PARA_REG0        0x318
85
86 #define SUNXI_DMA_DDMA_CFG_REG_LOADING  (1 << 31)
87 #define SUNXI_DMA_DDMA_CFG_REG_DMA_DEST_DATA_WIDTH_32 (2 << 25)
88 #define SUNXI_DMA_DDMA_CFG_REG_DDMA_DST_DRQ_TYPE_DRAM (1 << 16)
89 #define SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_DATA_WIDTH_32 (2 << 9)
90 #define SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_ADDR_MODE_IO (1 << 5)
91 #define SUNXI_DMA_DDMA_CFG_REG_DDMA_SRC_DRQ_TYPE_NFC (3 << 0)
92
93 #define SUNXI_DMA_DDMA_PARA_REG_SRC_WAIT_CYC (0x0F << 0)
94 #define SUNXI_DMA_DDMA_PARA_REG_SRC_BLK_SIZE (0x7F << 8)
95
96 /* minimal "boot0" style NAND support for Allwinner A20 */
97
98 /* random seed used by linux */
99 const uint16_t random_seed[128] = {
100         0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72,
101         0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436,
102         0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d,
103         0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130,
104         0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56,
105         0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55,
106         0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb,
107         0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17,
108         0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62,
109         0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064,
110         0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126,
111         0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e,
112         0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3,
113         0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b,
114         0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d,
115         0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db,
116 };
117
118 /* random seed used for syndrome calls */
119 const uint16_t random_seed_syndrome = 0x4a80;
120
121 #define MAX_RETRIES 10
122
123 static int check_value_inner(int offset, int expected_bits,
124                                 int max_number_of_retries, int negation)
125 {
126         int retries = 0;
127         do {
128                 int val = readl(offset) & expected_bits;
129                 if (negation ? !val : val)
130                         return 1;
131                 mdelay(1);
132                 retries++;
133         } while (retries < max_number_of_retries);
134
135         return 0;
136 }
137
138 static inline int check_value(int offset, int expected_bits,
139                                 int max_number_of_retries)
140 {
141         return check_value_inner(offset, expected_bits,
142                                         max_number_of_retries, 0);
143 }
144
145 static inline int check_value_negated(int offset, int unexpected_bits,
146                                         int max_number_of_retries)
147 {
148         return check_value_inner(offset, unexpected_bits,
149                                         max_number_of_retries, 1);
150 }
151
152 void nand_init(void)
153 {
154         uint32_t val;
155
156         board_nand_init();
157
158         val = readl(SUNXI_NFC_BASE + NFC_CTL);
159         /* enable and reset CTL */
160         writel(val | NFC_CTL_EN | NFC_CTL_RESET,
161                SUNXI_NFC_BASE + NFC_CTL);
162
163         if (!check_value_negated(SUNXI_NFC_BASE + NFC_CTL,
164                                  NFC_CTL_RESET, MAX_RETRIES)) {
165                 printf("Couldn't initialize nand\n");
166         }
167
168         /* reset NAND */
169         writel(NFC_SEND_CMD1 | NFC_WAIT_FLAG | NAND_CMD_RESET,
170                SUNXI_NFC_BASE + NFC_CMD);
171
172         if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_CMD_INT_FLAG,
173                          MAX_RETRIES)) {
174                 printf("Error timeout waiting for nand reset\n");
175                 return;
176         }
177 }
178
179 static void nand_read_page(unsigned int real_addr, dma_addr_t dst,
180                            int syndrome, uint32_t *ecc_errors)
181 {
182         uint32_t val;
183         int ecc_off = 0;
184         uint16_t ecc_mode = 0;
185         uint16_t rand_seed;
186         uint32_t page;
187         uint16_t column;
188         uint32_t oob_offset;
189
190         switch (CONFIG_NAND_SUNXI_SPL_ECC_STRENGTH) {
191         case 16:
192                 ecc_mode = 0;
193                 ecc_off = 0x20;
194                 break;
195         case 24:
196                 ecc_mode = 1;
197                 ecc_off = 0x2e;
198                 break;
199         case 28:
200                 ecc_mode = 2;
201                 ecc_off = 0x32;
202                 break;
203         case 32:
204                 ecc_mode = 3;
205                 ecc_off = 0x3c;
206                 break;
207         case 40:
208                 ecc_mode = 4;
209                 ecc_off = 0x4a;
210                 break;
211         case 48:
212                 ecc_mode = 4;
213                 ecc_off = 0x52;
214                 break;
215         case 56:
216                 ecc_mode = 4;
217                 ecc_off = 0x60;
218                 break;
219         case 60:
220                 ecc_mode = 4;
221                 ecc_off = 0x0;
222                 break;
223         case 64:
224                 ecc_mode = 4;
225                 ecc_off = 0x0;
226                 break;
227         default:
228                 ecc_mode = 0;
229                 ecc_off = 0;
230         }
231
232         if (ecc_off == 0) {
233                 printf("Unsupported ECC strength (%d)!\n",
234                        CONFIG_NAND_SUNXI_SPL_ECC_STRENGTH);
235                 return;
236         }
237
238         page = real_addr / CONFIG_NAND_SUNXI_SPL_PAGE_SIZE;
239         column = real_addr % CONFIG_NAND_SUNXI_SPL_PAGE_SIZE;
240
241         if (syndrome)
242                 column += (column / CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE)
243                         * ecc_off;
244
245         /* clear ecc status */
246         writel(0, SUNXI_NFC_BASE + NFC_ECC_ST);
247
248         /* Choose correct seed */
249         if (syndrome)
250                 rand_seed = random_seed_syndrome;
251         else
252                 rand_seed = random_seed[page % 128];
253
254         writel((rand_seed << 16) | NFC_ECC_RANDOM_EN | NFC_ECC_EN
255                 | NFC_ECC_PIPELINE | (ecc_mode << 12),
256                 SUNXI_NFC_BASE + NFC_ECC_CTL);
257
258         val = readl(SUNXI_NFC_BASE + NFC_CTL);
259         writel(val | NFC_CTL_RAM_METHOD, SUNXI_NFC_BASE + NFC_CTL);
260
261         if (!syndrome) {
262                 oob_offset = CONFIG_NAND_SUNXI_SPL_PAGE_SIZE
263                         + (column / CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE)
264                         * ecc_off;
265                 writel(oob_offset, SUNXI_NFC_BASE + NFC_SPARE_AREA);
266         }
267
268         /* SUNXI_DMA */
269         writel(0x0, SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0); /* clr dma cmd */
270         /* read from REG_IO_DATA */
271         writel(SUNXI_NFC_BASE + NFC_IO_DATA,
272                SUNXI_DMA_BASE + SUNXI_DMA_SRC_START_ADDR_REG0);
273         /* read to RAM */
274         writel(dst, SUNXI_DMA_BASE + SUNXI_DMA_DEST_START_ADDRR_REG0);
275         writel(SUNXI_DMA_DDMA_PARA_REG_SRC_WAIT_CYC
276                         | SUNXI_DMA_DDMA_PARA_REG_SRC_BLK_SIZE,
277                         SUNXI_DMA_BASE + SUNXI_DMA_DDMA_PARA_REG0);
278         writel(CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE,
279                SUNXI_DMA_BASE + SUNXI_DMA_DDMA_BC_REG0); /* 1kB */
280         writel(SUNXI_DMA_DDMA_CFG_REG_LOADING
281                 | SUNXI_DMA_DDMA_CFG_REG_DMA_DEST_DATA_WIDTH_32
282                 | SUNXI_DMA_DDMA_CFG_REG_DDMA_DST_DRQ_TYPE_DRAM
283                 | SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_DATA_WIDTH_32
284                 | SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_ADDR_MODE_IO
285                 | SUNXI_DMA_DDMA_CFG_REG_DDMA_SRC_DRQ_TYPE_NFC,
286                 SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0);
287
288         writel((NFC_CMD_RNDOUTSTART << NFC_RANDOM_READ_CMD1_OFFSET)
289                 | (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET)
290                 | (NFC_CMD_READSTART | NFC_READ_CMD_OFFSET), SUNXI_NFC_BASE
291                         + NFC_RCMD_SET);
292         writel(1, SUNXI_NFC_BASE + NFC_SECTOR_NUM);
293         writel(((page & 0xFFFF) << 16) | column,
294                SUNXI_NFC_BASE + NFC_ADDR_LOW);
295         writel((page >> 16) & 0xFF, SUNXI_NFC_BASE + NFC_ADDR_HIGH);
296         writel(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_DATA_TRANS |
297                 NFC_PAGE_CMD | NFC_WAIT_FLAG | (4 << NFC_ADDR_NUM_OFFSET) |
298                 NFC_SEND_ADR | NFC_DATA_SWAP_METHOD | (syndrome ? NFC_SEQ : 0),
299                 SUNXI_NFC_BASE + NFC_CMD);
300
301         if (!check_value(SUNXI_NFC_BASE + NFC_ST, (1 << 2),
302                          MAX_RETRIES)) {
303                 printf("Error while initializing dma interrupt\n");
304                 return;
305         }
306
307         if (!check_value_negated(SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0,
308                                  SUNXI_DMA_DDMA_CFG_REG_LOADING, MAX_RETRIES)) {
309                 printf("Error while waiting for dma transfer to finish\n");
310                 return;
311         }
312
313         if (readl(SUNXI_NFC_BASE + NFC_ECC_ST))
314                 (*ecc_errors)++;
315 }
316
317 int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest)
318 {
319         void *current_dest;
320         uint32_t ecc_errors = 0;
321
322         for (current_dest = dest;
323                         current_dest < (dest + size);
324                         current_dest += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE) {
325                 nand_read_page(offs, (dma_addr_t)current_dest,
326                         offs < CONFIG_NAND_SUNXI_SPL_SYNDROME_PARTITIONS_END,
327                         &ecc_errors);
328                 offs += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE;
329         }
330         return ecc_errors ? -1 : 0;
331 }
332
333 void nand_deselect(void) {}