]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/mtd/nand/sunxi_nand_spl.c
sunxi_nand_spl: Drop unnecessary temp buf
[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
167 static void nand_read_page(unsigned int real_addr, dma_addr_t dst,
168                            int syndrome, uint32_t *ecc_errors)
169 {
170         uint32_t val;
171         int ecc_off = 0;
172         uint16_t ecc_mode = 0;
173         uint16_t rand_seed;
174         uint32_t page;
175         uint16_t column;
176         uint32_t oob_offset;
177
178         switch (CONFIG_NAND_SUNXI_SPL_ECC_STRENGTH) {
179         case 16:
180                 ecc_mode = 0;
181                 ecc_off = 0x20;
182                 break;
183         case 24:
184                 ecc_mode = 1;
185                 ecc_off = 0x2e;
186                 break;
187         case 28:
188                 ecc_mode = 2;
189                 ecc_off = 0x32;
190                 break;
191         case 32:
192                 ecc_mode = 3;
193                 ecc_off = 0x3c;
194                 break;
195         case 40:
196                 ecc_mode = 4;
197                 ecc_off = 0x4a;
198                 break;
199         case 48:
200                 ecc_mode = 4;
201                 ecc_off = 0x52;
202                 break;
203         case 56:
204                 ecc_mode = 4;
205                 ecc_off = 0x60;
206                 break;
207         case 60:
208                 ecc_mode = 4;
209                 ecc_off = 0x0;
210                 break;
211         case 64:
212                 ecc_mode = 4;
213                 ecc_off = 0x0;
214                 break;
215         default:
216                 ecc_mode = 0;
217                 ecc_off = 0;
218         }
219
220         if (ecc_off == 0) {
221                 printf("Unsupported ECC strength (%d)!\n",
222                        CONFIG_NAND_SUNXI_SPL_ECC_STRENGTH);
223                 return;
224         }
225
226         /* set CMD  */
227         writel(NFC_SEND_CMD1 | NFC_WAIT_FLAG | NAND_CMD_RESET,
228                SUNXI_NFC_BASE + NFC_CMD);
229
230         if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_CMD_INT_FLAG,
231                          MAX_RETRIES)) {
232                 printf("Error while initilizing command interrupt\n");
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) {}