]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/mtd/nand/sunxi_nand_spl.c
56c0be02f5b6c8ac93b979447aa126203a44eae4
[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         val = readl(SUNXI_NFC_BASE + NFC_CTL);
157         /* enable and reset CTL */
158         writel(val | NFC_CTL_EN | NFC_CTL_RESET,
159                SUNXI_NFC_BASE + NFC_CTL);
160
161         if (!check_value_negated(SUNXI_NFC_BASE + NFC_CTL,
162                                  NFC_CTL_RESET, MAX_RETRIES)) {
163                 printf("Couldn't initialize nand\n");
164         }
165
166         /* reset NAND */
167         writel(NFC_SEND_CMD1 | NFC_WAIT_FLAG | NAND_CMD_RESET,
168                SUNXI_NFC_BASE + NFC_CMD);
169
170         if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_CMD_INT_FLAG,
171                          MAX_RETRIES)) {
172                 printf("Error timeout waiting for nand reset\n");
173                 return;
174         }
175 }
176
177 static void nand_read_page(unsigned int real_addr, dma_addr_t dst,
178                            int syndrome, uint32_t *ecc_errors)
179 {
180         uint32_t val;
181         int ecc_off = 0;
182         uint16_t ecc_mode = 0;
183         uint16_t rand_seed;
184         uint32_t page;
185         uint16_t column;
186         uint32_t oob_offset;
187
188         switch (CONFIG_NAND_SUNXI_SPL_ECC_STRENGTH) {
189         case 16:
190                 ecc_mode = 0;
191                 ecc_off = 0x20;
192                 break;
193         case 24:
194                 ecc_mode = 1;
195                 ecc_off = 0x2e;
196                 break;
197         case 28:
198                 ecc_mode = 2;
199                 ecc_off = 0x32;
200                 break;
201         case 32:
202                 ecc_mode = 3;
203                 ecc_off = 0x3c;
204                 break;
205         case 40:
206                 ecc_mode = 4;
207                 ecc_off = 0x4a;
208                 break;
209         case 48:
210                 ecc_mode = 4;
211                 ecc_off = 0x52;
212                 break;
213         case 56:
214                 ecc_mode = 4;
215                 ecc_off = 0x60;
216                 break;
217         case 60:
218                 ecc_mode = 4;
219                 ecc_off = 0x0;
220                 break;
221         case 64:
222                 ecc_mode = 4;
223                 ecc_off = 0x0;
224                 break;
225         default:
226                 ecc_mode = 0;
227                 ecc_off = 0;
228         }
229
230         if (ecc_off == 0) {
231                 printf("Unsupported ECC strength (%d)!\n",
232                        CONFIG_NAND_SUNXI_SPL_ECC_STRENGTH);
233                 return;
234         }
235
236         page = real_addr / CONFIG_NAND_SUNXI_SPL_PAGE_SIZE;
237         column = real_addr % CONFIG_NAND_SUNXI_SPL_PAGE_SIZE;
238
239         if (syndrome)
240                 column += (column / CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE)
241                         * ecc_off;
242
243         /* clear ecc status */
244         writel(0, SUNXI_NFC_BASE + NFC_ECC_ST);
245
246         /* Choose correct seed */
247         if (syndrome)
248                 rand_seed = random_seed_syndrome;
249         else
250                 rand_seed = random_seed[page % 128];
251
252         writel((rand_seed << 16) | NFC_ECC_RANDOM_EN | NFC_ECC_EN
253                 | NFC_ECC_PIPELINE | (ecc_mode << 12),
254                 SUNXI_NFC_BASE + NFC_ECC_CTL);
255
256         val = readl(SUNXI_NFC_BASE + NFC_CTL);
257         writel(val | NFC_CTL_RAM_METHOD, SUNXI_NFC_BASE + NFC_CTL);
258
259         if (syndrome) {
260                 writel(CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE,
261                        SUNXI_NFC_BASE + NFC_SPARE_AREA);
262         } else {
263                 oob_offset = CONFIG_NAND_SUNXI_SPL_PAGE_SIZE
264                         + (column / CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE)
265                         * ecc_off;
266                 writel(oob_offset, SUNXI_NFC_BASE + NFC_SPARE_AREA);
267         }
268
269         /* SUNXI_DMA */
270         writel(0x0, SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0); /* clr dma cmd */
271         /* read from REG_IO_DATA */
272         writel(SUNXI_NFC_BASE + NFC_IO_DATA,
273                SUNXI_DMA_BASE + SUNXI_DMA_SRC_START_ADDR_REG0);
274         /* read to RAM */
275         writel(dst, SUNXI_DMA_BASE + SUNXI_DMA_DEST_START_ADDRR_REG0);
276         writel(SUNXI_DMA_DDMA_PARA_REG_SRC_WAIT_CYC
277                         | SUNXI_DMA_DDMA_PARA_REG_SRC_BLK_SIZE,
278                         SUNXI_DMA_BASE + SUNXI_DMA_DDMA_PARA_REG0);
279         writel(CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE,
280                SUNXI_DMA_BASE + SUNXI_DMA_DDMA_BC_REG0); /* 1kB */
281         writel(SUNXI_DMA_DDMA_CFG_REG_LOADING
282                 | SUNXI_DMA_DDMA_CFG_REG_DMA_DEST_DATA_WIDTH_32
283                 | SUNXI_DMA_DDMA_CFG_REG_DDMA_DST_DRQ_TYPE_DRAM
284                 | SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_DATA_WIDTH_32
285                 | SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_ADDR_MODE_IO
286                 | SUNXI_DMA_DDMA_CFG_REG_DDMA_SRC_DRQ_TYPE_NFC,
287                 SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0);
288
289         writel((NFC_CMD_RNDOUTSTART << NFC_RANDOM_READ_CMD1_OFFSET)
290                 | (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET)
291                 | (NFC_CMD_READSTART | NFC_READ_CMD_OFFSET), SUNXI_NFC_BASE
292                         + NFC_RCMD_SET);
293         writel(1, SUNXI_NFC_BASE + NFC_SECTOR_NUM);
294         writel(((page & 0xFFFF) << 16) | column,
295                SUNXI_NFC_BASE + NFC_ADDR_LOW);
296         writel((page >> 16) & 0xFF, SUNXI_NFC_BASE + NFC_ADDR_HIGH);
297         writel(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_DATA_TRANS |
298                 NFC_PAGE_CMD | NFC_WAIT_FLAG | (4 << NFC_ADDR_NUM_OFFSET) |
299                 NFC_SEND_ADR | NFC_DATA_SWAP_METHOD | (syndrome ? NFC_SEQ : 0),
300                 SUNXI_NFC_BASE + NFC_CMD);
301
302         if (!check_value(SUNXI_NFC_BASE + NFC_ST, (1 << 2),
303                          MAX_RETRIES)) {
304                 printf("Error while initializing dma interrupt\n");
305                 return;
306         }
307
308         if (!check_value_negated(SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0,
309                                  SUNXI_DMA_DDMA_CFG_REG_LOADING, MAX_RETRIES)) {
310                 printf("Error while waiting for dma transfer to finish\n");
311                 return;
312         }
313
314         if (readl(SUNXI_NFC_BASE + NFC_ECC_ST))
315                 (*ecc_errors)++;
316 }
317
318 int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest)
319 {
320         void *current_dest;
321         uint32_t ecc_errors = 0;
322
323         for (current_dest = dest;
324                         current_dest < (dest + size);
325                         current_dest += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE) {
326                 nand_read_page(offs, (dma_addr_t)current_dest,
327                         offs < CONFIG_NAND_SUNXI_SPL_SYNDROME_PARTITIONS_END,
328                         &ecc_errors);
329                 offs += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE;
330         }
331         return ecc_errors ? -1 : 0;
332 }
333
334 void nand_deselect(void) {}