]> git.ipfire.org Git - people/ms/u-boot.git/blame - drivers/mtd/nand/sunxi_nand_spl.c
Move defaults from config_cmd_default.h to Kconfig
[people/ms/u-boot.git] / drivers / mtd / nand / sunxi_nand_spl.c
CommitLineData
f76eba38
DK
1/*
2 * Copyright (c) 2014, Antmicro Ltd <www.antmicro.com>
3 * Copyright (c) 2015, Turtle Solutions <www.turtle-solutions.eu>
4 * Copyright (c) 2015, Roy Spliet <rspliet@ultimaker.com>
5 *
6 * SPDX-License-Identifier: GPL-2.0+
7 *
8 * \todo Detect chip parameters (page size, ECC mode, randomisation...)
9 */
10
11#include <common.h>
12#include <config.h>
13#include <asm/io.h>
14#include <nand.h>
15#include <asm/arch/cpu.h>
16#include <asm/arch/clock.h>
17#include <asm/arch/dma.h>
18#include <asm/arch/nand.h>
19
20void
21nand_init(void)
22{
23 struct sunxi_ccm_reg * const ccm =
24 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
25 struct sunxi_nand * const nand = (struct sunxi_nand *)SUNXI_NFC_BASE;
26 u32 val;
27
28 board_nand_init();
29
30 /* "un-gate" NAND clock and clock source
31 * This assumes that the clock was already correctly configured by
32 * BootROM */
33 setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_NAND0));
34#ifdef CONFIG_MACH_SUN9I
35 setbits_le32(&ccm->ahb_gate1, (1 << AHB_GATE_OFFSET_DMA));
36#else
37 setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_DMA));
38#endif
39 setbits_le32(&ccm->nand0_clk_cfg, 0x80000000);
40
41 val = readl(&nand->ctl);
42 val |= SUNXI_NAND_CTL_RST;
43 writel(val, &nand->ctl);
44
45 /* Wait until reset pin is deasserted */
46 do {
47 val = readl(&nand->ctl);
48 if (!(val & SUNXI_NAND_CTL_RST))
49 break;
50 } while (1);
51
52 /** \todo Chip select, currently kind of static */
53 val = readl(&nand->ctl);
54 val &= 0xf0fff0f2;
55 val |= SUNXI_NAND_CTL_EN;
56 val |= SUNXI_NAND_CTL_PAGE_SIZE(CONFIG_NAND_SUNXI_PAGE_SIZE);
57 writel(val, &nand->ctl);
58
59 writel(0x100, &nand->timing_ctl);
60 writel(0x7ff, &nand->timing_cfg);
61
62 /* reset CMD */
63 val = SUNXI_NAND_CMD_SEND_CMD1 | SUNXI_NAND_CMD_WAIT_FLAG |
64 NAND_CMD_RESET;
65 writel(val, &nand->cmd);
66 do {
67 val = readl(&nand->st);
68 if (val & (1<<1))
69 break;
70 udelay(1000);
71 } while (1);
72
73 printf("Nand initialised\n");
74}
75
76int
77nand_wait_timeout(u32 *reg, u32 mask, u32 val)
78{
79 unsigned long tmo = timer_get_us() + 1000000; /* 1s */
80
81 while ((readl(reg) & mask) != val) {
82 if (timer_get_us() > tmo)
83 return -ETIMEDOUT;
84 }
85
86 return 0;
87}
88
89/* random seed */
90static const uint16_t random_seed[128] = {
91 0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72,
92 0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436,
93 0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d,
94 0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130,
95 0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56,
96 0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55,
97 0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb,
98 0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17,
99 0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62,
100 0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064,
101 0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126,
102 0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e,
103 0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3,
104 0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b,
105 0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d,
106 0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db,
107};
108
109uint32_t ecc_errors = 0;
110
111static void
112nand_config_ecc(struct sunxi_nand *nand, uint32_t page, int syndrome)
113{
114 static u8 strength[] = {16, 24, 28, 32, 40, 48, 56, 60, 64};
115 int i;
116 uint32_t ecc_mode;
117 u32 ecc;
118 u16 seed = 0;
119
120 for (i = 0; i < ARRAY_SIZE(strength); i++) {
121 if (CONFIG_NAND_SUNXI_ECC_STRENGTH == strength[i]) {
122 ecc_mode = i;
123 break;
124 }
125 }
126
127 if (i == ARRAY_SIZE(strength)) {
128 printf("ECC strength unsupported\n");
129 return;
130 }
131
132 ecc = SUNXI_NAND_ECC_CTL_ECC_EN |
133 SUNXI_NAND_ECC_CTL_PIPELINE |
134 SUNXI_NAND_ECC_CTL_RND_EN |
135 SUNXI_NAND_ECC_CTL_MODE(ecc_mode);
136
137 if (CONFIG_NAND_SUNXI_ECC_STEP == 512)
138 ecc |= SUNXI_NAND_ECC_CTL_BS_512B;
139
140 if (syndrome)
141 seed = 0x4A80;
142 else
143 seed = random_seed[page % ARRAY_SIZE(random_seed)];
144
145 ecc |= SUNXI_NAND_ECC_CTL_RND_SEED(seed);
146
147 writel(ecc, &nand->ecc_ctl);
148}
149
150/* read CONFIG_NAND_SUNXI_ECC_STEP bytes from real_addr to temp_buf */
151void
152nand_read_block(struct sunxi_nand *nand, phys_addr_t src, dma_addr_t dst,
153 int syndrome)
154{
155 struct sunxi_dma * const dma = (struct sunxi_dma *)SUNXI_DMA_BASE;
156 struct sunxi_dma_cfg * const dma_cfg = &dma->ddma[0];
157
158 uint32_t shift;
159 uint32_t page;
160 uint32_t addr;
161 uint32_t oob_offset;
162 uint32_t ecc_bytes;
163 u32 val;
164 u32 cmd;
165
166 page = src / CONFIG_NAND_SUNXI_PAGE_SIZE;
167 if (page > 0xFFFF) {
168 /* TODO: currently this is not supported */
169 printf("Reading from address >= %08X is not allowed.\n",
170 0xFFFF * CONFIG_NAND_SUNXI_PAGE_SIZE);
171 return;
172 }
173
174 shift = src % CONFIG_NAND_SUNXI_PAGE_SIZE;
175 writel(0, &nand->ecc_st);
176
177 /* ECC_CTL, randomization */
178 ecc_bytes = CONFIG_NAND_SUNXI_ECC_STRENGTH *
179 fls(CONFIG_NAND_SUNXI_ECC_STEP * 8);
180 ecc_bytes = DIV_ROUND_UP(ecc_bytes, 8);
181 ecc_bytes += (ecc_bytes & 1); /* Align to 2-bytes */
182 ecc_bytes += 4;
183
184 nand_config_ecc(nand, page, syndrome);
185 if (syndrome) {
186 /* shift every 1kB in syndrome */
187 shift += (shift / CONFIG_NAND_SUNXI_ECC_STEP) * ecc_bytes;
188 oob_offset = CONFIG_NAND_SUNXI_ECC_STEP + shift;
189 } else {
190 oob_offset = CONFIG_NAND_SUNXI_PAGE_SIZE +
191 (shift / CONFIG_NAND_SUNXI_ECC_STEP) * ecc_bytes;
192 }
193
194 addr = (page << 16) | shift;
195
196 /* DMA */
197 val = readl(&nand->ctl);
198 writel(val | SUNXI_NAND_CTL_RAM_METHOD_DMA, &nand->ctl);
199
200 writel(oob_offset, &nand->spare_area);
201
202 /* DMAC
203 * \todo Separate this into a tidy driver */
204 writel(0x0, &dma->irq_en); /* clear dma interrupts */
205 writel((uint32_t) &nand->io_data , &dma_cfg->src_addr);
206 writel(dst , &dma_cfg->dst_addr);
207 writel(0x00007F0F , &dma_cfg->ddma_para);
208 writel(CONFIG_NAND_SUNXI_ECC_STEP, &dma_cfg->bc);
209
210 val = SUNXI_DMA_CTL_SRC_DRQ(DDMA_SRC_DRQ_NAND) |
211 SUNXI_DMA_CTL_MODE_IO |
212 SUNXI_DMA_CTL_SRC_DATA_WIDTH_32 |
213 SUNXI_DMA_CTL_DST_DRQ(DDMA_DST_DRQ_SDRAM) |
214 SUNXI_DMA_CTL_DST_DATA_WIDTH_32 |
215 SUNXI_DMA_CTL_TRIGGER;
216 writel(val, &dma_cfg->ctl);
217
218 writel(0x00E00530, &nand->rcmd_set);
219 nand_wait_timeout(&nand->st, SUNXI_NAND_ST_FIFO_FULL, 0);
220
221 writel(1 , &nand->block_num);
222 writel(addr, &nand->addr_low);
223 writel(0 , &nand->addr_high);
224
225 /* CMD (PAGE READ) */
226 cmd = 0x85E80000;
227 cmd |= SUNXI_NAND_CMD_ADDR_CYCLES(CONFIG_NAND_SUNXI_ADDR_CYCLES);
228 cmd |= (syndrome ? SUNXI_NAND_CMD_ORDER_SEQ :
229 SUNXI_NAND_CMD_ORDER_INTERLEAVE);
230 writel(cmd, &nand->cmd);
231
232 if(nand_wait_timeout(&nand->st, SUNXI_NAND_ST_DMA_INT,
233 SUNXI_NAND_ST_DMA_INT)) {
234 printf("NAND timeout reading data\n");
235 return;
236 }
237
238 if(nand_wait_timeout(&dma_cfg->ctl, SUNXI_DMA_CTL_TRIGGER, 0)) {
239 printf("NAND timeout reading data\n");
240 return;
241 }
242
243 if (readl(&nand->ecc_st))
244 ecc_errors++;
245}
246
247int
248nand_spl_load_image(uint32_t offs, unsigned int size, void *dest)
249{
250 struct sunxi_nand * const nand = (struct sunxi_nand *)SUNXI_NFC_BASE;
251 dma_addr_t dst_block;
252 dma_addr_t dst_end;
253 phys_addr_t addr = offs;
254
255 dst_end = ((dma_addr_t) dest) + size;
256
257 memset((void *)dest, 0x0, size);
258 ecc_errors = 0;
259 for (dst_block = (dma_addr_t) dest; dst_block < dst_end;
260 dst_block += CONFIG_NAND_SUNXI_ECC_STEP,
261 addr += CONFIG_NAND_SUNXI_ECC_STEP) {
262 /* syndrome read first 4MiB to match Allwinner BootROM */
263 nand_read_block(nand, addr, dst_block, addr < 0x400000);
264 }
265
266 if (ecc_errors)
267 printf("Error: %d ECC failures detected\n", ecc_errors);
268 return ecc_errors == 0;
269}
270
271void
272nand_deselect(void)
273{}