]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/mtd/nand/sunxi_nand_spl.c
f6f49289f8f69a3ad47965fab482d222256a27fa
[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                 oob_offset = CONFIG_NAND_SUNXI_SPL_PAGE_SIZE
261                         + (column / CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE)
262                         * ecc_off;
263                 writel(oob_offset, SUNXI_NFC_BASE + NFC_SPARE_AREA);
264         }
265
266         /* SUNXI_DMA */
267         writel(0x0, SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0); /* clr dma cmd */
268         /* read from REG_IO_DATA */
269         writel(SUNXI_NFC_BASE + NFC_IO_DATA,
270                SUNXI_DMA_BASE + SUNXI_DMA_SRC_START_ADDR_REG0);
271         /* read to RAM */
272         writel(dst, SUNXI_DMA_BASE + SUNXI_DMA_DEST_START_ADDRR_REG0);
273         writel(SUNXI_DMA_DDMA_PARA_REG_SRC_WAIT_CYC
274                         | SUNXI_DMA_DDMA_PARA_REG_SRC_BLK_SIZE,
275                         SUNXI_DMA_BASE + SUNXI_DMA_DDMA_PARA_REG0);
276         writel(CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE,
277                SUNXI_DMA_BASE + SUNXI_DMA_DDMA_BC_REG0); /* 1kB */
278         writel(SUNXI_DMA_DDMA_CFG_REG_LOADING
279                 | SUNXI_DMA_DDMA_CFG_REG_DMA_DEST_DATA_WIDTH_32
280                 | SUNXI_DMA_DDMA_CFG_REG_DDMA_DST_DRQ_TYPE_DRAM
281                 | SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_DATA_WIDTH_32
282                 | SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_ADDR_MODE_IO
283                 | SUNXI_DMA_DDMA_CFG_REG_DDMA_SRC_DRQ_TYPE_NFC,
284                 SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0);
285
286         writel((NFC_CMD_RNDOUTSTART << NFC_RANDOM_READ_CMD1_OFFSET)
287                 | (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET)
288                 | (NFC_CMD_READSTART | NFC_READ_CMD_OFFSET), SUNXI_NFC_BASE
289                         + NFC_RCMD_SET);
290         writel(1, SUNXI_NFC_BASE + NFC_SECTOR_NUM);
291         writel(((page & 0xFFFF) << 16) | column,
292                SUNXI_NFC_BASE + NFC_ADDR_LOW);
293         writel((page >> 16) & 0xFF, SUNXI_NFC_BASE + NFC_ADDR_HIGH);
294         writel(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_DATA_TRANS |
295                 NFC_PAGE_CMD | NFC_WAIT_FLAG | (4 << NFC_ADDR_NUM_OFFSET) |
296                 NFC_SEND_ADR | NFC_DATA_SWAP_METHOD | (syndrome ? NFC_SEQ : 0),
297                 SUNXI_NFC_BASE + NFC_CMD);
298
299         if (!check_value(SUNXI_NFC_BASE + NFC_ST, (1 << 2),
300                          MAX_RETRIES)) {
301                 printf("Error while initializing dma interrupt\n");
302                 return;
303         }
304
305         if (!check_value_negated(SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0,
306                                  SUNXI_DMA_DDMA_CFG_REG_LOADING, MAX_RETRIES)) {
307                 printf("Error while waiting for dma transfer to finish\n");
308                 return;
309         }
310
311         if (readl(SUNXI_NFC_BASE + NFC_ECC_ST))
312                 (*ecc_errors)++;
313 }
314
315 int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest)
316 {
317         void *current_dest;
318         uint32_t ecc_errors = 0;
319
320         for (current_dest = dest;
321                         current_dest < (dest + size);
322                         current_dest += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE) {
323                 nand_read_page(offs, (dma_addr_t)current_dest,
324                         offs < CONFIG_NAND_SUNXI_SPL_SYNDROME_PARTITIONS_END,
325                         &ecc_errors);
326                 offs += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE;
327         }
328         return ecc_errors ? -1 : 0;
329 }
330
331 void nand_deselect(void) {}