]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
4ccae81c BB |
2 | /* |
3 | * Copyright (C) 2013 Boris BREZILLON <b.brezillon.dev@gmail.com> | |
4 | * Copyright (C) 2015 Roy Spliet <r.spliet@ultimaker.com> | |
5 | * | |
6 | * Derived from: | |
7 | * https://github.com/yuq/sunxi-nfc-mtd | |
8 | * Copyright (C) 2013 Qiang Yu <yuq825@gmail.com> | |
9 | * | |
10 | * https://github.com/hno/Allwinner-Info | |
11 | * Copyright (C) 2013 Henrik Nordström <Henrik Nordström> | |
12 | * | |
13 | * Copyright (C) 2013 Dmitriy B. <rzk333@gmail.com> | |
14 | * Copyright (C) 2013 Sergey Lapin <slapin@ossfans.org> | |
15 | * | |
16 | * This program is free software; you can redistribute it and/or modify | |
17 | * it under the terms of the GNU General Public License as published by | |
18 | * the Free Software Foundation; either version 2 of the License, or | |
19 | * (at your option) any later version. | |
20 | * | |
21 | * This program is distributed in the hope that it will be useful, | |
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
24 | * GNU General Public License for more details. | |
4ccae81c BB |
25 | */ |
26 | ||
21b790fd | 27 | #include <clk.h> |
d678a59d | 28 | #include <common.h> |
1eb09081 | 29 | #include <dm.h> |
336d4615 | 30 | #include <malloc.h> |
4ccae81c BB |
31 | #include <memalign.h> |
32 | #include <nand.h> | |
21b790fd | 33 | #include <reset.h> |
336d4615 | 34 | #include <dm/device_compat.h> |
61b29b82 | 35 | #include <dm/devres.h> |
cd93d625 | 36 | #include <linux/bitops.h> |
c05ed00a | 37 | #include <linux/delay.h> |
61b29b82 | 38 | #include <linux/err.h> |
1e94b46f | 39 | #include <linux/printk.h> |
4ccae81c BB |
40 | |
41 | #include <linux/kernel.h> | |
42 | #include <linux/mtd/mtd.h> | |
6ae3900a | 43 | #include <linux/mtd/rawnand.h> |
4ccae81c BB |
44 | #include <linux/mtd/partitions.h> |
45 | #include <linux/io.h> | |
46 | ||
47 | #include <asm/gpio.h> | |
48 | #include <asm/arch/clock.h> | |
49 | ||
4ccae81c BB |
50 | #define NFC_REG_CTL 0x0000 |
51 | #define NFC_REG_ST 0x0004 | |
52 | #define NFC_REG_INT 0x0008 | |
53 | #define NFC_REG_TIMING_CTL 0x000C | |
54 | #define NFC_REG_TIMING_CFG 0x0010 | |
55 | #define NFC_REG_ADDR_LOW 0x0014 | |
56 | #define NFC_REG_ADDR_HIGH 0x0018 | |
57 | #define NFC_REG_SECTOR_NUM 0x001C | |
58 | #define NFC_REG_CNT 0x0020 | |
59 | #define NFC_REG_CMD 0x0024 | |
60 | #define NFC_REG_RCMD_SET 0x0028 | |
61 | #define NFC_REG_WCMD_SET 0x002C | |
62 | #define NFC_REG_IO_DATA 0x0030 | |
63 | #define NFC_REG_ECC_CTL 0x0034 | |
64 | #define NFC_REG_ECC_ST 0x0038 | |
65 | #define NFC_REG_DEBUG 0x003C | |
66 | #define NFC_REG_ECC_ERR_CNT(x) ((0x0040 + (x)) & ~0x3) | |
67 | #define NFC_REG_USER_DATA(x) (0x0050 + ((x) * 4)) | |
68 | #define NFC_REG_SPARE_AREA 0x00A0 | |
69 | #define NFC_REG_PAT_ID 0x00A4 | |
70 | #define NFC_RAM0_BASE 0x0400 | |
71 | #define NFC_RAM1_BASE 0x0800 | |
72 | ||
73 | /* define bit use in NFC_CTL */ | |
74 | #define NFC_EN BIT(0) | |
75 | #define NFC_RESET BIT(1) | |
76 | #define NFC_BUS_WIDTH_MSK BIT(2) | |
77 | #define NFC_BUS_WIDTH_8 (0 << 2) | |
78 | #define NFC_BUS_WIDTH_16 (1 << 2) | |
79 | #define NFC_RB_SEL_MSK BIT(3) | |
80 | #define NFC_RB_SEL(x) ((x) << 3) | |
81 | #define NFC_CE_SEL_MSK (0x7 << 24) | |
82 | #define NFC_CE_SEL(x) ((x) << 24) | |
83 | #define NFC_CE_CTL BIT(6) | |
84 | #define NFC_PAGE_SHIFT_MSK (0xf << 8) | |
85 | #define NFC_PAGE_SHIFT(x) (((x) < 10 ? 0 : (x) - 10) << 8) | |
86 | #define NFC_SAM BIT(12) | |
87 | #define NFC_RAM_METHOD BIT(14) | |
88 | #define NFC_DEBUG_CTL BIT(31) | |
89 | ||
90 | /* define bit use in NFC_ST */ | |
91 | #define NFC_RB_B2R BIT(0) | |
92 | #define NFC_CMD_INT_FLAG BIT(1) | |
93 | #define NFC_DMA_INT_FLAG BIT(2) | |
94 | #define NFC_CMD_FIFO_STATUS BIT(3) | |
95 | #define NFC_STA BIT(4) | |
96 | #define NFC_NATCH_INT_FLAG BIT(5) | |
97 | #define NFC_RB_STATE(x) BIT(x + 8) | |
98 | ||
99 | /* define bit use in NFC_INT */ | |
100 | #define NFC_B2R_INT_ENABLE BIT(0) | |
101 | #define NFC_CMD_INT_ENABLE BIT(1) | |
102 | #define NFC_DMA_INT_ENABLE BIT(2) | |
103 | #define NFC_INT_MASK (NFC_B2R_INT_ENABLE | \ | |
104 | NFC_CMD_INT_ENABLE | \ | |
105 | NFC_DMA_INT_ENABLE) | |
106 | ||
107 | /* define bit use in NFC_TIMING_CTL */ | |
108 | #define NFC_TIMING_CTL_EDO BIT(8) | |
109 | ||
110 | /* define NFC_TIMING_CFG register layout */ | |
111 | #define NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD) \ | |
112 | (((tWB) & 0x3) | (((tADL) & 0x3) << 2) | \ | |
113 | (((tWHR) & 0x3) << 4) | (((tRHW) & 0x3) << 6) | \ | |
114 | (((tCAD) & 0x7) << 8)) | |
115 | ||
116 | /* define bit use in NFC_CMD */ | |
117 | #define NFC_CMD_LOW_BYTE_MSK 0xff | |
118 | #define NFC_CMD_HIGH_BYTE_MSK (0xff << 8) | |
119 | #define NFC_CMD(x) (x) | |
120 | #define NFC_ADR_NUM_MSK (0x7 << 16) | |
121 | #define NFC_ADR_NUM(x) (((x) - 1) << 16) | |
122 | #define NFC_SEND_ADR BIT(19) | |
123 | #define NFC_ACCESS_DIR BIT(20) | |
124 | #define NFC_DATA_TRANS BIT(21) | |
125 | #define NFC_SEND_CMD1 BIT(22) | |
126 | #define NFC_WAIT_FLAG BIT(23) | |
127 | #define NFC_SEND_CMD2 BIT(24) | |
128 | #define NFC_SEQ BIT(25) | |
129 | #define NFC_DATA_SWAP_METHOD BIT(26) | |
130 | #define NFC_ROW_AUTO_INC BIT(27) | |
131 | #define NFC_SEND_CMD3 BIT(28) | |
132 | #define NFC_SEND_CMD4 BIT(29) | |
133 | #define NFC_CMD_TYPE_MSK (0x3 << 30) | |
134 | #define NFC_NORMAL_OP (0 << 30) | |
135 | #define NFC_ECC_OP (1 << 30) | |
136 | #define NFC_PAGE_OP (2 << 30) | |
137 | ||
138 | /* define bit use in NFC_RCMD_SET */ | |
139 | #define NFC_READ_CMD_MSK 0xff | |
140 | #define NFC_RND_READ_CMD0_MSK (0xff << 8) | |
141 | #define NFC_RND_READ_CMD1_MSK (0xff << 16) | |
142 | ||
143 | /* define bit use in NFC_WCMD_SET */ | |
144 | #define NFC_PROGRAM_CMD_MSK 0xff | |
145 | #define NFC_RND_WRITE_CMD_MSK (0xff << 8) | |
146 | #define NFC_READ_CMD0_MSK (0xff << 16) | |
147 | #define NFC_READ_CMD1_MSK (0xff << 24) | |
148 | ||
149 | /* define bit use in NFC_ECC_CTL */ | |
150 | #define NFC_ECC_EN BIT(0) | |
151 | #define NFC_ECC_PIPELINE BIT(3) | |
152 | #define NFC_ECC_EXCEPTION BIT(4) | |
153 | #define NFC_ECC_BLOCK_SIZE_MSK BIT(5) | |
154 | #define NFC_ECC_BLOCK_512 (1 << 5) | |
155 | #define NFC_RANDOM_EN BIT(9) | |
156 | #define NFC_RANDOM_DIRECTION BIT(10) | |
157 | #define NFC_ECC_MODE_MSK (0xf << 12) | |
158 | #define NFC_ECC_MODE(x) ((x) << 12) | |
159 | #define NFC_RANDOM_SEED_MSK (0x7fff << 16) | |
160 | #define NFC_RANDOM_SEED(x) ((x) << 16) | |
161 | ||
162 | /* define bit use in NFC_ECC_ST */ | |
163 | #define NFC_ECC_ERR(x) BIT(x) | |
164 | #define NFC_ECC_PAT_FOUND(x) BIT(x + 16) | |
165 | #define NFC_ECC_ERR_CNT(b, x) (((x) >> ((b) * 8)) & 0xff) | |
166 | ||
167 | #define NFC_DEFAULT_TIMEOUT_MS 1000 | |
168 | ||
169 | #define NFC_SRAM_SIZE 1024 | |
170 | ||
171 | #define NFC_MAX_CS 7 | |
172 | ||
173 | /* | |
174 | * Ready/Busy detection type: describes the Ready/Busy detection modes | |
175 | * | |
176 | * @RB_NONE: no external detection available, rely on STATUS command | |
177 | * and software timeouts | |
178 | * @RB_NATIVE: use sunxi NAND controller Ready/Busy support. The Ready/Busy | |
179 | * pin of the NAND flash chip must be connected to one of the | |
180 | * native NAND R/B pins (those which can be muxed to the NAND | |
181 | * Controller) | |
182 | * @RB_GPIO: use a simple GPIO to handle Ready/Busy status. The Ready/Busy | |
183 | * pin of the NAND flash chip must be connected to a GPIO capable | |
184 | * pin. | |
185 | */ | |
186 | enum sunxi_nand_rb_type { | |
187 | RB_NONE, | |
188 | RB_NATIVE, | |
189 | RB_GPIO, | |
190 | }; | |
191 | ||
192 | /* | |
193 | * Ready/Busy structure: stores information related to Ready/Busy detection | |
194 | * | |
195 | * @type: the Ready/Busy detection mode | |
196 | * @info: information related to the R/B detection mode. Either a gpio | |
197 | * id or a native R/B id (those supported by the NAND controller). | |
198 | */ | |
199 | struct sunxi_nand_rb { | |
200 | enum sunxi_nand_rb_type type; | |
201 | union { | |
202 | struct gpio_desc gpio; | |
203 | int nativeid; | |
204 | } info; | |
205 | }; | |
206 | ||
207 | /* | |
208 | * Chip Select structure: stores information related to NAND Chip Select | |
209 | * | |
210 | * @cs: the NAND CS id used to communicate with a NAND Chip | |
211 | * @rb: the Ready/Busy description | |
212 | */ | |
213 | struct sunxi_nand_chip_sel { | |
214 | u8 cs; | |
215 | struct sunxi_nand_rb rb; | |
216 | }; | |
217 | ||
218 | /* | |
219 | * sunxi HW ECC infos: stores information related to HW ECC support | |
220 | * | |
221 | * @mode: the sunxi ECC mode field deduced from ECC requirements | |
222 | * @layout: the OOB layout depending on the ECC requirements and the | |
223 | * selected ECC mode | |
224 | */ | |
225 | struct sunxi_nand_hw_ecc { | |
226 | int mode; | |
227 | struct nand_ecclayout layout; | |
228 | }; | |
229 | ||
230 | /* | |
231 | * NAND chip structure: stores NAND chip device related information | |
232 | * | |
233 | * @node: used to store NAND chips into a list | |
234 | * @nand: base NAND chip structure | |
235 | * @mtd: base MTD structure | |
236 | * @clk_rate: clk_rate required for this NAND chip | |
237 | * @timing_cfg TIMING_CFG register value for this NAND chip | |
238 | * @selected: current active CS | |
239 | * @nsels: number of CS lines required by the NAND chip | |
240 | * @sels: array of CS lines descriptions | |
241 | */ | |
242 | struct sunxi_nand_chip { | |
243 | struct list_head node; | |
244 | struct nand_chip nand; | |
245 | unsigned long clk_rate; | |
246 | u32 timing_cfg; | |
247 | u32 timing_ctl; | |
248 | int selected; | |
249 | int addr_cycles; | |
250 | u32 addr[2]; | |
251 | int cmd_cycles; | |
252 | u8 cmd[2]; | |
253 | int nsels; | |
254 | struct sunxi_nand_chip_sel sels[0]; | |
255 | }; | |
256 | ||
257 | static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand) | |
258 | { | |
259 | return container_of(nand, struct sunxi_nand_chip, nand); | |
260 | } | |
261 | ||
262 | /* | |
263 | * NAND Controller structure: stores sunxi NAND controller information | |
264 | * | |
265 | * @controller: base controller structure | |
21b790fd | 266 | * @dev: DM device (used to print error messages) |
4ccae81c BB |
267 | * @regs: NAND controller registers |
268 | * @ahb_clk: NAND Controller AHB clock | |
269 | * @mod_clk: NAND Controller mod clock | |
270 | * @assigned_cs: bitmask describing already assigned CS lines | |
271 | * @clk_rate: NAND controller current clock rate | |
272 | * @chips: a list containing all the NAND chips attached to | |
273 | * this NAND controller | |
274 | * @complete: a completion object used to wait for NAND | |
275 | * controller events | |
276 | */ | |
277 | struct sunxi_nfc { | |
278 | struct nand_hw_control controller; | |
21b790fd | 279 | struct udevice *dev; |
4ccae81c BB |
280 | void __iomem *regs; |
281 | struct clk *ahb_clk; | |
282 | struct clk *mod_clk; | |
283 | unsigned long assigned_cs; | |
284 | unsigned long clk_rate; | |
285 | struct list_head chips; | |
286 | }; | |
287 | ||
288 | static inline struct sunxi_nfc *to_sunxi_nfc(struct nand_hw_control *ctrl) | |
289 | { | |
290 | return container_of(ctrl, struct sunxi_nfc, controller); | |
291 | } | |
292 | ||
293 | static void sunxi_nfc_set_clk_rate(unsigned long hz) | |
294 | { | |
295 | struct sunxi_ccm_reg *const ccm = | |
296 | (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; | |
297 | int div_m, div_n; | |
298 | ||
299 | div_m = (clock_get_pll6() + hz - 1) / hz; | |
300 | for (div_n = 0; div_n < 3 && div_m > 16; div_n++) { | |
301 | if (div_m % 2) | |
302 | div_m++; | |
303 | div_m >>= 1; | |
304 | } | |
305 | if (div_m > 16) | |
306 | div_m = 16; | |
307 | ||
308 | /* config mod clock */ | |
309 | writel(CCM_NAND_CTRL_ENABLE | CCM_NAND_CTRL_PLL6 | | |
310 | CCM_NAND_CTRL_N(div_n) | CCM_NAND_CTRL_M(div_m), | |
311 | &ccm->nand0_clk_cfg); | |
312 | ||
313 | /* gate on nand clock */ | |
314 | setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_NAND0)); | |
315 | #ifdef CONFIG_MACH_SUN9I | |
316 | setbits_le32(&ccm->ahb_gate1, (1 << AHB_GATE_OFFSET_DMA)); | |
317 | #else | |
318 | setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_DMA)); | |
319 | #endif | |
320 | } | |
321 | ||
322 | static int sunxi_nfc_wait_int(struct sunxi_nfc *nfc, u32 flags, | |
323 | unsigned int timeout_ms) | |
324 | { | |
325 | unsigned int timeout_ticks; | |
326 | u32 time_start, status; | |
327 | int ret = -ETIMEDOUT; | |
328 | ||
329 | if (!timeout_ms) | |
330 | timeout_ms = NFC_DEFAULT_TIMEOUT_MS; | |
331 | ||
332 | timeout_ticks = (timeout_ms * CONFIG_SYS_HZ) / 1000; | |
333 | ||
334 | time_start = get_timer(0); | |
335 | ||
336 | do { | |
337 | status = readl(nfc->regs + NFC_REG_ST); | |
338 | if ((status & flags) == flags) { | |
339 | ret = 0; | |
340 | break; | |
341 | } | |
342 | ||
343 | udelay(1); | |
344 | } while (get_timer(time_start) < timeout_ticks); | |
345 | ||
346 | writel(status & flags, nfc->regs + NFC_REG_ST); | |
347 | ||
348 | return ret; | |
349 | } | |
350 | ||
351 | static int sunxi_nfc_wait_cmd_fifo_empty(struct sunxi_nfc *nfc) | |
352 | { | |
353 | unsigned long timeout = (CONFIG_SYS_HZ * | |
354 | NFC_DEFAULT_TIMEOUT_MS) / 1000; | |
355 | u32 time_start; | |
356 | ||
357 | time_start = get_timer(0); | |
358 | do { | |
359 | if (!(readl(nfc->regs + NFC_REG_ST) & NFC_CMD_FIFO_STATUS)) | |
360 | return 0; | |
361 | } while (get_timer(time_start) < timeout); | |
362 | ||
363 | dev_err(nfc->dev, "wait for empty cmd FIFO timedout\n"); | |
364 | return -ETIMEDOUT; | |
365 | } | |
366 | ||
367 | static int sunxi_nfc_rst(struct sunxi_nfc *nfc) | |
368 | { | |
369 | unsigned long timeout = (CONFIG_SYS_HZ * | |
370 | NFC_DEFAULT_TIMEOUT_MS) / 1000; | |
371 | u32 time_start; | |
372 | ||
373 | writel(0, nfc->regs + NFC_REG_ECC_CTL); | |
374 | writel(NFC_RESET, nfc->regs + NFC_REG_CTL); | |
375 | ||
376 | time_start = get_timer(0); | |
377 | do { | |
378 | if (!(readl(nfc->regs + NFC_REG_CTL) & NFC_RESET)) | |
379 | return 0; | |
380 | } while (get_timer(time_start) < timeout); | |
381 | ||
382 | dev_err(nfc->dev, "wait for NAND controller reset timedout\n"); | |
383 | return -ETIMEDOUT; | |
384 | } | |
385 | ||
386 | static int sunxi_nfc_dev_ready(struct mtd_info *mtd) | |
387 | { | |
388 | struct nand_chip *nand = mtd_to_nand(mtd); | |
389 | struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); | |
390 | struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); | |
391 | struct sunxi_nand_rb *rb; | |
392 | unsigned long timeo = (sunxi_nand->nand.state == FL_ERASING ? 400 : 20); | |
393 | int ret; | |
394 | ||
395 | if (sunxi_nand->selected < 0) | |
396 | return 0; | |
397 | ||
398 | rb = &sunxi_nand->sels[sunxi_nand->selected].rb; | |
399 | ||
400 | switch (rb->type) { | |
401 | case RB_NATIVE: | |
402 | ret = !!(readl(nfc->regs + NFC_REG_ST) & | |
403 | NFC_RB_STATE(rb->info.nativeid)); | |
404 | if (ret) | |
405 | break; | |
406 | ||
407 | sunxi_nfc_wait_int(nfc, NFC_RB_B2R, timeo); | |
408 | ret = !!(readl(nfc->regs + NFC_REG_ST) & | |
409 | NFC_RB_STATE(rb->info.nativeid)); | |
410 | break; | |
411 | case RB_GPIO: | |
412 | ret = dm_gpio_get_value(&rb->info.gpio); | |
413 | break; | |
414 | case RB_NONE: | |
415 | default: | |
416 | ret = 0; | |
417 | dev_err(nfc->dev, "cannot check R/B NAND status!\n"); | |
418 | break; | |
419 | } | |
420 | ||
421 | return ret; | |
422 | } | |
423 | ||
424 | static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip) | |
425 | { | |
426 | struct nand_chip *nand = mtd_to_nand(mtd); | |
427 | struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); | |
428 | struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); | |
429 | struct sunxi_nand_chip_sel *sel; | |
430 | u32 ctl; | |
431 | ||
432 | if (chip > 0 && chip >= sunxi_nand->nsels) | |
433 | return; | |
434 | ||
435 | if (chip == sunxi_nand->selected) | |
436 | return; | |
437 | ||
438 | ctl = readl(nfc->regs + NFC_REG_CTL) & | |
439 | ~(NFC_PAGE_SHIFT_MSK | NFC_CE_SEL_MSK | NFC_RB_SEL_MSK | NFC_EN); | |
440 | ||
441 | if (chip >= 0) { | |
442 | sel = &sunxi_nand->sels[chip]; | |
443 | ||
444 | ctl |= NFC_CE_SEL(sel->cs) | NFC_EN | | |
445 | NFC_PAGE_SHIFT(nand->page_shift - 10); | |
446 | if (sel->rb.type == RB_NONE) { | |
447 | nand->dev_ready = NULL; | |
448 | } else { | |
449 | nand->dev_ready = sunxi_nfc_dev_ready; | |
450 | if (sel->rb.type == RB_NATIVE) | |
451 | ctl |= NFC_RB_SEL(sel->rb.info.nativeid); | |
452 | } | |
453 | ||
454 | writel(mtd->writesize, nfc->regs + NFC_REG_SPARE_AREA); | |
455 | ||
456 | if (nfc->clk_rate != sunxi_nand->clk_rate) { | |
457 | sunxi_nfc_set_clk_rate(sunxi_nand->clk_rate); | |
458 | nfc->clk_rate = sunxi_nand->clk_rate; | |
459 | } | |
460 | } | |
461 | ||
462 | writel(sunxi_nand->timing_ctl, nfc->regs + NFC_REG_TIMING_CTL); | |
463 | writel(sunxi_nand->timing_cfg, nfc->regs + NFC_REG_TIMING_CFG); | |
464 | writel(ctl, nfc->regs + NFC_REG_CTL); | |
465 | ||
466 | sunxi_nand->selected = chip; | |
467 | } | |
468 | ||
469 | static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) | |
470 | { | |
471 | struct nand_chip *nand = mtd_to_nand(mtd); | |
472 | struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); | |
473 | struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); | |
474 | int ret; | |
475 | int cnt; | |
476 | int offs = 0; | |
477 | u32 tmp; | |
478 | ||
479 | while (len > offs) { | |
480 | cnt = min(len - offs, NFC_SRAM_SIZE); | |
481 | ||
482 | ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); | |
483 | if (ret) | |
484 | break; | |
485 | ||
486 | writel(cnt, nfc->regs + NFC_REG_CNT); | |
487 | tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD; | |
488 | writel(tmp, nfc->regs + NFC_REG_CMD); | |
489 | ||
490 | ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); | |
491 | if (ret) | |
492 | break; | |
493 | ||
494 | if (buf) | |
495 | memcpy_fromio(buf + offs, nfc->regs + NFC_RAM0_BASE, | |
496 | cnt); | |
497 | offs += cnt; | |
498 | } | |
499 | } | |
500 | ||
501 | static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, | |
502 | int len) | |
503 | { | |
504 | struct nand_chip *nand = mtd_to_nand(mtd); | |
505 | struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); | |
506 | struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); | |
507 | int ret; | |
508 | int cnt; | |
509 | int offs = 0; | |
510 | u32 tmp; | |
511 | ||
512 | while (len > offs) { | |
513 | cnt = min(len - offs, NFC_SRAM_SIZE); | |
514 | ||
515 | ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); | |
516 | if (ret) | |
517 | break; | |
518 | ||
519 | writel(cnt, nfc->regs + NFC_REG_CNT); | |
520 | memcpy_toio(nfc->regs + NFC_RAM0_BASE, buf + offs, cnt); | |
521 | tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | | |
522 | NFC_ACCESS_DIR; | |
523 | writel(tmp, nfc->regs + NFC_REG_CMD); | |
524 | ||
525 | ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); | |
526 | if (ret) | |
527 | break; | |
528 | ||
529 | offs += cnt; | |
530 | } | |
531 | } | |
532 | ||
533 | static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd) | |
534 | { | |
535 | uint8_t ret; | |
536 | ||
537 | sunxi_nfc_read_buf(mtd, &ret, 1); | |
538 | ||
539 | return ret; | |
540 | } | |
541 | ||
542 | static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, | |
543 | unsigned int ctrl) | |
544 | { | |
545 | struct nand_chip *nand = mtd_to_nand(mtd); | |
546 | struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); | |
547 | struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); | |
548 | int ret; | |
549 | u32 tmp; | |
550 | ||
551 | ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); | |
552 | if (ret) | |
553 | return; | |
554 | ||
555 | if (ctrl & NAND_CTRL_CHANGE) { | |
556 | tmp = readl(nfc->regs + NFC_REG_CTL); | |
557 | if (ctrl & NAND_NCE) | |
558 | tmp |= NFC_CE_CTL; | |
559 | else | |
560 | tmp &= ~NFC_CE_CTL; | |
561 | writel(tmp, nfc->regs + NFC_REG_CTL); | |
562 | } | |
563 | ||
564 | if (dat == NAND_CMD_NONE && (ctrl & NAND_NCE) && | |
565 | !(ctrl & (NAND_CLE | NAND_ALE))) { | |
566 | u32 cmd = 0; | |
567 | ||
568 | if (!sunxi_nand->addr_cycles && !sunxi_nand->cmd_cycles) | |
569 | return; | |
570 | ||
571 | if (sunxi_nand->cmd_cycles--) | |
572 | cmd |= NFC_SEND_CMD1 | sunxi_nand->cmd[0]; | |
573 | ||
574 | if (sunxi_nand->cmd_cycles--) { | |
575 | cmd |= NFC_SEND_CMD2; | |
576 | writel(sunxi_nand->cmd[1], | |
577 | nfc->regs + NFC_REG_RCMD_SET); | |
578 | } | |
579 | ||
580 | sunxi_nand->cmd_cycles = 0; | |
581 | ||
582 | if (sunxi_nand->addr_cycles) { | |
583 | cmd |= NFC_SEND_ADR | | |
584 | NFC_ADR_NUM(sunxi_nand->addr_cycles); | |
585 | writel(sunxi_nand->addr[0], | |
586 | nfc->regs + NFC_REG_ADDR_LOW); | |
587 | } | |
588 | ||
589 | if (sunxi_nand->addr_cycles > 4) | |
590 | writel(sunxi_nand->addr[1], | |
591 | nfc->regs + NFC_REG_ADDR_HIGH); | |
592 | ||
593 | writel(cmd, nfc->regs + NFC_REG_CMD); | |
594 | sunxi_nand->addr[0] = 0; | |
595 | sunxi_nand->addr[1] = 0; | |
596 | sunxi_nand->addr_cycles = 0; | |
597 | sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); | |
598 | } | |
599 | ||
600 | if (ctrl & NAND_CLE) { | |
601 | sunxi_nand->cmd[sunxi_nand->cmd_cycles++] = dat; | |
602 | } else if (ctrl & NAND_ALE) { | |
603 | sunxi_nand->addr[sunxi_nand->addr_cycles / 4] |= | |
604 | dat << ((sunxi_nand->addr_cycles % 4) * 8); | |
605 | sunxi_nand->addr_cycles++; | |
606 | } | |
607 | } | |
608 | ||
609 | /* These seed values have been extracted from Allwinner's BSP */ | |
610 | static const u16 sunxi_nfc_randomizer_page_seeds[] = { | |
611 | 0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72, | |
612 | 0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436, | |
613 | 0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d, | |
614 | 0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130, | |
615 | 0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56, | |
616 | 0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55, | |
617 | 0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb, | |
618 | 0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17, | |
619 | 0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62, | |
620 | 0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064, | |
621 | 0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126, | |
622 | 0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e, | |
623 | 0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3, | |
624 | 0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b, | |
625 | 0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d, | |
626 | 0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db, | |
627 | }; | |
628 | ||
629 | /* | |
630 | * sunxi_nfc_randomizer_ecc512_seeds and sunxi_nfc_randomizer_ecc1024_seeds | |
631 | * have been generated using | |
632 | * sunxi_nfc_randomizer_step(seed, (step_size * 8) + 15), which is what | |
633 | * the randomizer engine does internally before de/scrambling OOB data. | |
634 | * | |
635 | * Those tables are statically defined to avoid calculating randomizer state | |
636 | * at runtime. | |
637 | */ | |
638 | static const u16 sunxi_nfc_randomizer_ecc512_seeds[] = { | |
639 | 0x3346, 0x367f, 0x1f18, 0x769a, 0x4f64, 0x068c, 0x2ef1, 0x6b64, | |
640 | 0x28a9, 0x15d7, 0x30f8, 0x3659, 0x53db, 0x7c5f, 0x71d4, 0x4409, | |
641 | 0x26eb, 0x03cc, 0x655d, 0x47d4, 0x4daa, 0x0877, 0x712d, 0x3617, | |
642 | 0x3264, 0x49aa, 0x7f9e, 0x588e, 0x4fbc, 0x7176, 0x7f91, 0x6c6d, | |
643 | 0x4b95, 0x5fb7, 0x3844, 0x4037, 0x0184, 0x081b, 0x0ee8, 0x5b91, | |
644 | 0x293d, 0x1f71, 0x0e6f, 0x402b, 0x5122, 0x1e52, 0x22be, 0x3d2d, | |
645 | 0x75bc, 0x7c60, 0x6291, 0x1a2f, 0x61d4, 0x74aa, 0x4140, 0x29ab, | |
646 | 0x472d, 0x2852, 0x017e, 0x15e8, 0x5ec2, 0x17cf, 0x7d0f, 0x06b8, | |
647 | 0x117a, 0x6b94, 0x789b, 0x3126, 0x6ac5, 0x5be7, 0x150f, 0x51f8, | |
648 | 0x7889, 0x0aa5, 0x663d, 0x77e8, 0x0b87, 0x3dcb, 0x360d, 0x218b, | |
649 | 0x512f, 0x7dc9, 0x6a4d, 0x630a, 0x3547, 0x1dd2, 0x5aea, 0x69a5, | |
650 | 0x7bfa, 0x5e4f, 0x1519, 0x6430, 0x3a0e, 0x5eb3, 0x5425, 0x0c7a, | |
651 | 0x5540, 0x3670, 0x63c1, 0x31e9, 0x5a39, 0x2de7, 0x5979, 0x2891, | |
652 | 0x1562, 0x014b, 0x5b05, 0x2756, 0x5a34, 0x13aa, 0x6cb5, 0x2c36, | |
653 | 0x5e72, 0x1306, 0x0861, 0x15ef, 0x1ee8, 0x5a37, 0x7ac4, 0x45dd, | |
654 | 0x44c4, 0x7266, 0x2f41, 0x3ccc, 0x045e, 0x7d40, 0x7c66, 0x0fa0, | |
655 | }; | |
656 | ||
657 | static const u16 sunxi_nfc_randomizer_ecc1024_seeds[] = { | |
658 | 0x2cf5, 0x35f1, 0x63a4, 0x5274, 0x2bd2, 0x778b, 0x7285, 0x32b6, | |
659 | 0x6a5c, 0x70d6, 0x757d, 0x6769, 0x5375, 0x1e81, 0x0cf3, 0x3982, | |
660 | 0x6787, 0x042a, 0x6c49, 0x1925, 0x56a8, 0x40a9, 0x063e, 0x7bd9, | |
661 | 0x4dbf, 0x55ec, 0x672e, 0x7334, 0x5185, 0x4d00, 0x232a, 0x7e07, | |
662 | 0x445d, 0x6b92, 0x528f, 0x4255, 0x53ba, 0x7d82, 0x2a2e, 0x3a4e, | |
663 | 0x75eb, 0x450c, 0x6844, 0x1b5d, 0x581a, 0x4cc6, 0x0379, 0x37b2, | |
664 | 0x419f, 0x0e92, 0x6b27, 0x5624, 0x01e3, 0x07c1, 0x44a5, 0x130c, | |
665 | 0x13e8, 0x5910, 0x0876, 0x60c5, 0x54e3, 0x5b7f, 0x2269, 0x509f, | |
666 | 0x7665, 0x36fd, 0x3e9a, 0x0579, 0x6295, 0x14ef, 0x0a81, 0x1bcc, | |
667 | 0x4b16, 0x64db, 0x0514, 0x4f07, 0x0591, 0x3576, 0x6853, 0x0d9e, | |
668 | 0x259f, 0x38b7, 0x64fb, 0x3094, 0x4693, 0x6ddd, 0x29bb, 0x0bc8, | |
669 | 0x3f47, 0x490e, 0x0c0e, 0x7933, 0x3c9e, 0x5840, 0x398d, 0x3e68, | |
670 | 0x4af1, 0x71f5, 0x57cf, 0x1121, 0x64eb, 0x3579, 0x15ac, 0x584d, | |
671 | 0x5f2a, 0x47e2, 0x6528, 0x6eac, 0x196e, 0x6b96, 0x0450, 0x0179, | |
672 | 0x609c, 0x06e1, 0x4626, 0x42c7, 0x273e, 0x486f, 0x0705, 0x1601, | |
673 | 0x145b, 0x407e, 0x062b, 0x57a5, 0x53f9, 0x5659, 0x4410, 0x3ccd, | |
674 | }; | |
675 | ||
676 | static u16 sunxi_nfc_randomizer_step(u16 state, int count) | |
677 | { | |
678 | state &= 0x7fff; | |
679 | ||
680 | /* | |
681 | * This loop is just a simple implementation of a Fibonacci LFSR using | |
682 | * the x16 + x15 + 1 polynomial. | |
683 | */ | |
684 | while (count--) | |
685 | state = ((state >> 1) | | |
686 | (((state ^ (state >> 1)) & 1) << 14)) & 0x7fff; | |
687 | ||
688 | return state; | |
689 | } | |
690 | ||
691 | static u16 sunxi_nfc_randomizer_state(struct mtd_info *mtd, int page, bool ecc) | |
692 | { | |
693 | const u16 *seeds = sunxi_nfc_randomizer_page_seeds; | |
694 | int mod = mtd->erasesize / mtd->writesize; | |
695 | ||
696 | if (mod > ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds)) | |
697 | mod = ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds); | |
698 | ||
699 | if (ecc) { | |
700 | if (mtd->ecc_step_size == 512) | |
701 | seeds = sunxi_nfc_randomizer_ecc512_seeds; | |
702 | else | |
703 | seeds = sunxi_nfc_randomizer_ecc1024_seeds; | |
704 | } | |
705 | ||
706 | return seeds[page % mod]; | |
707 | } | |
708 | ||
709 | static void sunxi_nfc_randomizer_config(struct mtd_info *mtd, | |
710 | int page, bool ecc) | |
711 | { | |
712 | struct nand_chip *nand = mtd_to_nand(mtd); | |
713 | struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); | |
714 | u32 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL); | |
715 | u16 state; | |
716 | ||
717 | if (!(nand->options & NAND_NEED_SCRAMBLING)) | |
718 | return; | |
719 | ||
720 | ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL); | |
721 | state = sunxi_nfc_randomizer_state(mtd, page, ecc); | |
722 | ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_SEED_MSK; | |
723 | writel(ecc_ctl | NFC_RANDOM_SEED(state), nfc->regs + NFC_REG_ECC_CTL); | |
724 | } | |
725 | ||
726 | static void sunxi_nfc_randomizer_enable(struct mtd_info *mtd) | |
727 | { | |
728 | struct nand_chip *nand = mtd_to_nand(mtd); | |
729 | struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); | |
730 | ||
731 | if (!(nand->options & NAND_NEED_SCRAMBLING)) | |
732 | return; | |
733 | ||
734 | writel(readl(nfc->regs + NFC_REG_ECC_CTL) | NFC_RANDOM_EN, | |
735 | nfc->regs + NFC_REG_ECC_CTL); | |
736 | } | |
737 | ||
738 | static void sunxi_nfc_randomizer_disable(struct mtd_info *mtd) | |
739 | { | |
740 | struct nand_chip *nand = mtd_to_nand(mtd); | |
741 | struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); | |
742 | ||
743 | if (!(nand->options & NAND_NEED_SCRAMBLING)) | |
744 | return; | |
745 | ||
746 | writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN, | |
747 | nfc->regs + NFC_REG_ECC_CTL); | |
748 | } | |
749 | ||
750 | static void sunxi_nfc_randomize_bbm(struct mtd_info *mtd, int page, u8 *bbm) | |
751 | { | |
752 | u16 state = sunxi_nfc_randomizer_state(mtd, page, true); | |
753 | ||
754 | bbm[0] ^= state; | |
755 | bbm[1] ^= sunxi_nfc_randomizer_step(state, 8); | |
756 | } | |
757 | ||
758 | static void sunxi_nfc_randomizer_write_buf(struct mtd_info *mtd, | |
759 | const uint8_t *buf, int len, | |
760 | bool ecc, int page) | |
761 | { | |
762 | sunxi_nfc_randomizer_config(mtd, page, ecc); | |
763 | sunxi_nfc_randomizer_enable(mtd); | |
764 | sunxi_nfc_write_buf(mtd, buf, len); | |
765 | sunxi_nfc_randomizer_disable(mtd); | |
766 | } | |
767 | ||
768 | static void sunxi_nfc_randomizer_read_buf(struct mtd_info *mtd, uint8_t *buf, | |
769 | int len, bool ecc, int page) | |
770 | { | |
771 | sunxi_nfc_randomizer_config(mtd, page, ecc); | |
772 | sunxi_nfc_randomizer_enable(mtd); | |
773 | sunxi_nfc_read_buf(mtd, buf, len); | |
774 | sunxi_nfc_randomizer_disable(mtd); | |
775 | } | |
776 | ||
777 | static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd) | |
778 | { | |
779 | struct nand_chip *nand = mtd_to_nand(mtd); | |
780 | struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); | |
781 | struct sunxi_nand_hw_ecc *data = nand->ecc.priv; | |
782 | u32 ecc_ctl; | |
783 | ||
784 | ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL); | |
785 | ecc_ctl &= ~(NFC_ECC_MODE_MSK | NFC_ECC_PIPELINE | | |
786 | NFC_ECC_BLOCK_SIZE_MSK); | |
787 | ecc_ctl |= NFC_ECC_EN | NFC_ECC_MODE(data->mode) | NFC_ECC_EXCEPTION; | |
788 | ||
789 | if (nand->ecc.size == 512) | |
790 | ecc_ctl |= NFC_ECC_BLOCK_512; | |
791 | ||
792 | writel(ecc_ctl, nfc->regs + NFC_REG_ECC_CTL); | |
793 | } | |
794 | ||
795 | static void sunxi_nfc_hw_ecc_disable(struct mtd_info *mtd) | |
796 | { | |
797 | struct nand_chip *nand = mtd_to_nand(mtd); | |
798 | struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); | |
799 | ||
800 | writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN, | |
801 | nfc->regs + NFC_REG_ECC_CTL); | |
802 | } | |
803 | ||
804 | static inline void sunxi_nfc_user_data_to_buf(u32 user_data, u8 *buf) | |
805 | { | |
806 | buf[0] = user_data; | |
807 | buf[1] = user_data >> 8; | |
808 | buf[2] = user_data >> 16; | |
809 | buf[3] = user_data >> 24; | |
810 | } | |
811 | ||
812 | static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd, | |
813 | u8 *data, int data_off, | |
814 | u8 *oob, int oob_off, | |
815 | int *cur_off, | |
816 | unsigned int *max_bitflips, | |
817 | bool bbm, int page) | |
818 | { | |
819 | struct nand_chip *nand = mtd_to_nand(mtd); | |
820 | struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); | |
821 | struct nand_ecc_ctrl *ecc = &nand->ecc; | |
822 | int raw_mode = 0; | |
823 | u32 status; | |
824 | int ret; | |
825 | ||
826 | if (*cur_off != data_off) | |
827 | nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1); | |
828 | ||
829 | sunxi_nfc_randomizer_read_buf(mtd, NULL, ecc->size, false, page); | |
830 | ||
831 | if (data_off + ecc->size != oob_off) | |
832 | nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1); | |
833 | ||
834 | ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); | |
835 | if (ret) | |
836 | return ret; | |
837 | ||
838 | sunxi_nfc_randomizer_enable(mtd); | |
839 | writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP, | |
840 | nfc->regs + NFC_REG_CMD); | |
841 | ||
842 | ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); | |
843 | sunxi_nfc_randomizer_disable(mtd); | |
844 | if (ret) | |
845 | return ret; | |
846 | ||
847 | *cur_off = oob_off + ecc->bytes + 4; | |
848 | ||
849 | status = readl(nfc->regs + NFC_REG_ECC_ST); | |
850 | if (status & NFC_ECC_PAT_FOUND(0)) { | |
851 | u8 pattern = 0xff; | |
852 | ||
853 | if (unlikely(!(readl(nfc->regs + NFC_REG_PAT_ID) & 0x1))) | |
854 | pattern = 0x0; | |
855 | ||
856 | memset(data, pattern, ecc->size); | |
857 | memset(oob, pattern, ecc->bytes + 4); | |
858 | ||
859 | return 1; | |
860 | } | |
861 | ||
862 | ret = NFC_ECC_ERR_CNT(0, readl(nfc->regs + NFC_REG_ECC_ERR_CNT(0))); | |
863 | ||
864 | memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size); | |
865 | ||
866 | nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1); | |
867 | sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4, true, page); | |
868 | ||
869 | if (status & NFC_ECC_ERR(0)) { | |
870 | /* | |
871 | * Re-read the data with the randomizer disabled to identify | |
872 | * bitflips in erased pages. | |
873 | */ | |
874 | if (nand->options & NAND_NEED_SCRAMBLING) { | |
875 | nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1); | |
876 | nand->read_buf(mtd, data, ecc->size); | |
877 | nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1); | |
878 | nand->read_buf(mtd, oob, ecc->bytes + 4); | |
879 | } | |
880 | ||
881 | ret = nand_check_erased_ecc_chunk(data, ecc->size, | |
882 | oob, ecc->bytes + 4, | |
883 | NULL, 0, ecc->strength); | |
884 | if (ret >= 0) | |
885 | raw_mode = 1; | |
886 | } else { | |
887 | /* | |
888 | * The engine protects 4 bytes of OOB data per chunk. | |
889 | * Retrieve the corrected OOB bytes. | |
890 | */ | |
891 | sunxi_nfc_user_data_to_buf(readl(nfc->regs + | |
892 | NFC_REG_USER_DATA(0)), | |
893 | oob); | |
894 | ||
895 | /* De-randomize the Bad Block Marker. */ | |
896 | if (bbm && nand->options & NAND_NEED_SCRAMBLING) | |
897 | sunxi_nfc_randomize_bbm(mtd, page, oob); | |
898 | } | |
899 | ||
900 | if (ret < 0) { | |
901 | mtd->ecc_stats.failed++; | |
902 | } else { | |
903 | mtd->ecc_stats.corrected += ret; | |
904 | *max_bitflips = max_t(unsigned int, *max_bitflips, ret); | |
905 | } | |
906 | ||
907 | return raw_mode; | |
908 | } | |
909 | ||
910 | static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd, | |
911 | u8 *oob, int *cur_off, | |
912 | bool randomize, int page) | |
913 | { | |
914 | struct nand_chip *nand = mtd_to_nand(mtd); | |
915 | struct nand_ecc_ctrl *ecc = &nand->ecc; | |
916 | int offset = ((ecc->bytes + 4) * ecc->steps); | |
917 | int len = mtd->oobsize - offset; | |
918 | ||
919 | if (len <= 0) | |
920 | return; | |
921 | ||
922 | if (*cur_off != offset) | |
923 | nand->cmdfunc(mtd, NAND_CMD_RNDOUT, | |
924 | offset + mtd->writesize, -1); | |
925 | ||
926 | if (!randomize) | |
927 | sunxi_nfc_read_buf(mtd, oob + offset, len); | |
928 | else | |
929 | sunxi_nfc_randomizer_read_buf(mtd, oob + offset, len, | |
930 | false, page); | |
931 | ||
932 | *cur_off = mtd->oobsize + mtd->writesize; | |
933 | } | |
934 | ||
935 | static inline u32 sunxi_nfc_buf_to_user_data(const u8 *buf) | |
936 | { | |
937 | return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); | |
938 | } | |
939 | ||
940 | static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd, | |
941 | const u8 *data, int data_off, | |
942 | const u8 *oob, int oob_off, | |
943 | int *cur_off, bool bbm, | |
944 | int page) | |
945 | { | |
946 | struct nand_chip *nand = mtd_to_nand(mtd); | |
947 | struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); | |
948 | struct nand_ecc_ctrl *ecc = &nand->ecc; | |
949 | int ret; | |
950 | ||
951 | if (data_off != *cur_off) | |
952 | nand->cmdfunc(mtd, NAND_CMD_RNDIN, data_off, -1); | |
953 | ||
954 | sunxi_nfc_randomizer_write_buf(mtd, data, ecc->size, false, page); | |
955 | ||
956 | /* Fill OOB data in */ | |
957 | if ((nand->options & NAND_NEED_SCRAMBLING) && bbm) { | |
958 | u8 user_data[4]; | |
959 | ||
960 | memcpy(user_data, oob, 4); | |
961 | sunxi_nfc_randomize_bbm(mtd, page, user_data); | |
962 | writel(sunxi_nfc_buf_to_user_data(user_data), | |
963 | nfc->regs + NFC_REG_USER_DATA(0)); | |
964 | } else { | |
965 | writel(sunxi_nfc_buf_to_user_data(oob), | |
966 | nfc->regs + NFC_REG_USER_DATA(0)); | |
967 | } | |
968 | ||
969 | if (data_off + ecc->size != oob_off) | |
970 | nand->cmdfunc(mtd, NAND_CMD_RNDIN, oob_off, -1); | |
971 | ||
972 | ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); | |
973 | if (ret) | |
974 | return ret; | |
975 | ||
976 | sunxi_nfc_randomizer_enable(mtd); | |
977 | writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | | |
978 | NFC_ACCESS_DIR | NFC_ECC_OP, | |
979 | nfc->regs + NFC_REG_CMD); | |
980 | ||
981 | ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); | |
982 | sunxi_nfc_randomizer_disable(mtd); | |
983 | if (ret) | |
984 | return ret; | |
985 | ||
986 | *cur_off = oob_off + ecc->bytes + 4; | |
987 | ||
988 | return 0; | |
989 | } | |
990 | ||
991 | static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd, | |
992 | u8 *oob, int *cur_off, | |
993 | int page) | |
994 | { | |
995 | struct nand_chip *nand = mtd_to_nand(mtd); | |
996 | struct nand_ecc_ctrl *ecc = &nand->ecc; | |
997 | int offset = ((ecc->bytes + 4) * ecc->steps); | |
998 | int len = mtd->oobsize - offset; | |
999 | ||
1000 | if (len <= 0) | |
1001 | return; | |
1002 | ||
1003 | if (*cur_off != offset) | |
1004 | nand->cmdfunc(mtd, NAND_CMD_RNDIN, | |
1005 | offset + mtd->writesize, -1); | |
1006 | ||
1007 | sunxi_nfc_randomizer_write_buf(mtd, oob + offset, len, false, page); | |
1008 | ||
1009 | *cur_off = mtd->oobsize + mtd->writesize; | |
1010 | } | |
1011 | ||
1012 | static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd, | |
1013 | struct nand_chip *chip, uint8_t *buf, | |
1014 | int oob_required, int page) | |
1015 | { | |
1016 | struct nand_ecc_ctrl *ecc = &chip->ecc; | |
1017 | unsigned int max_bitflips = 0; | |
1018 | int ret, i, cur_off = 0; | |
1019 | bool raw_mode = false; | |
1020 | ||
1021 | sunxi_nfc_hw_ecc_enable(mtd); | |
1022 | ||
1023 | for (i = 0; i < ecc->steps; i++) { | |
1024 | int data_off = i * ecc->size; | |
1025 | int oob_off = i * (ecc->bytes + 4); | |
1026 | u8 *data = buf + data_off; | |
1027 | u8 *oob = chip->oob_poi + oob_off; | |
1028 | ||
1029 | ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob, | |
1030 | oob_off + mtd->writesize, | |
1031 | &cur_off, &max_bitflips, | |
1032 | !i, page); | |
1033 | if (ret < 0) | |
1034 | return ret; | |
1035 | else if (ret) | |
1036 | raw_mode = true; | |
1037 | } | |
1038 | ||
1039 | if (oob_required) | |
1040 | sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off, | |
1041 | !raw_mode, page); | |
1042 | ||
1043 | sunxi_nfc_hw_ecc_disable(mtd); | |
1044 | ||
1045 | return max_bitflips; | |
1046 | } | |
1047 | ||
1048 | static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd, | |
1049 | struct nand_chip *chip, | |
1050 | uint32_t data_offs, uint32_t readlen, | |
1051 | uint8_t *bufpoi, int page) | |
1052 | { | |
1053 | struct nand_ecc_ctrl *ecc = &chip->ecc; | |
1054 | int ret, i, cur_off = 0; | |
1055 | unsigned int max_bitflips = 0; | |
1056 | ||
1057 | sunxi_nfc_hw_ecc_enable(mtd); | |
1058 | ||
1059 | chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); | |
1060 | for (i = data_offs / ecc->size; | |
1061 | i < DIV_ROUND_UP(data_offs + readlen, ecc->size); i++) { | |
1062 | int data_off = i * ecc->size; | |
1063 | int oob_off = i * (ecc->bytes + 4); | |
1064 | u8 *data = bufpoi + data_off; | |
1065 | u8 *oob = chip->oob_poi + oob_off; | |
1066 | ||
1067 | ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, | |
1068 | oob, oob_off + mtd->writesize, | |
1069 | &cur_off, &max_bitflips, !i, page); | |
1070 | if (ret < 0) | |
1071 | return ret; | |
1072 | } | |
1073 | ||
1074 | sunxi_nfc_hw_ecc_disable(mtd); | |
1075 | ||
1076 | return max_bitflips; | |
1077 | } | |
1078 | ||
1079 | static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd, | |
1080 | struct nand_chip *chip, | |
1081 | const uint8_t *buf, int oob_required, | |
1082 | int page) | |
1083 | { | |
1084 | struct nand_ecc_ctrl *ecc = &chip->ecc; | |
1085 | int ret, i, cur_off = 0; | |
1086 | ||
1087 | sunxi_nfc_hw_ecc_enable(mtd); | |
1088 | ||
1089 | for (i = 0; i < ecc->steps; i++) { | |
1090 | int data_off = i * ecc->size; | |
1091 | int oob_off = i * (ecc->bytes + 4); | |
1092 | const u8 *data = buf + data_off; | |
1093 | const u8 *oob = chip->oob_poi + oob_off; | |
1094 | ||
1095 | ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob, | |
1096 | oob_off + mtd->writesize, | |
1097 | &cur_off, !i, page); | |
1098 | if (ret) | |
1099 | return ret; | |
1100 | } | |
1101 | ||
1102 | if (oob_required || (chip->options & NAND_NEED_SCRAMBLING)) | |
1103 | sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi, | |
1104 | &cur_off, page); | |
1105 | ||
1106 | sunxi_nfc_hw_ecc_disable(mtd); | |
1107 | ||
1108 | return 0; | |
1109 | } | |
1110 | ||
1111 | static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd, | |
1112 | struct nand_chip *chip, | |
1113 | u32 data_offs, u32 data_len, | |
1114 | const u8 *buf, int oob_required, | |
1115 | int page) | |
1116 | { | |
1117 | struct nand_ecc_ctrl *ecc = &chip->ecc; | |
1118 | int ret, i, cur_off = 0; | |
1119 | ||
1120 | sunxi_nfc_hw_ecc_enable(mtd); | |
1121 | ||
1122 | for (i = data_offs / ecc->size; | |
1123 | i < DIV_ROUND_UP(data_offs + data_len, ecc->size); i++) { | |
1124 | int data_off = i * ecc->size; | |
1125 | int oob_off = i * (ecc->bytes + 4); | |
1126 | const u8 *data = buf + data_off; | |
1127 | const u8 *oob = chip->oob_poi + oob_off; | |
1128 | ||
1129 | ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob, | |
1130 | oob_off + mtd->writesize, | |
1131 | &cur_off, !i, page); | |
1132 | if (ret) | |
1133 | return ret; | |
1134 | } | |
1135 | ||
1136 | sunxi_nfc_hw_ecc_disable(mtd); | |
1137 | ||
1138 | return 0; | |
1139 | } | |
1140 | ||
1141 | static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd, | |
1142 | struct nand_chip *chip, | |
1143 | uint8_t *buf, int oob_required, | |
1144 | int page) | |
1145 | { | |
1146 | struct nand_ecc_ctrl *ecc = &chip->ecc; | |
1147 | unsigned int max_bitflips = 0; | |
1148 | int ret, i, cur_off = 0; | |
1149 | bool raw_mode = false; | |
1150 | ||
1151 | sunxi_nfc_hw_ecc_enable(mtd); | |
1152 | ||
1153 | for (i = 0; i < ecc->steps; i++) { | |
1154 | int data_off = i * (ecc->size + ecc->bytes + 4); | |
1155 | int oob_off = data_off + ecc->size; | |
1156 | u8 *data = buf + (i * ecc->size); | |
1157 | u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4)); | |
1158 | ||
1159 | ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob, | |
1160 | oob_off, &cur_off, | |
1161 | &max_bitflips, !i, page); | |
1162 | if (ret < 0) | |
1163 | return ret; | |
1164 | else if (ret) | |
1165 | raw_mode = true; | |
1166 | } | |
1167 | ||
1168 | if (oob_required) | |
1169 | sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off, | |
1170 | !raw_mode, page); | |
1171 | ||
1172 | sunxi_nfc_hw_ecc_disable(mtd); | |
1173 | ||
1174 | return max_bitflips; | |
1175 | } | |
1176 | ||
1177 | static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd, | |
1178 | struct nand_chip *chip, | |
1179 | const uint8_t *buf, | |
1180 | int oob_required, int page) | |
1181 | { | |
1182 | struct nand_ecc_ctrl *ecc = &chip->ecc; | |
1183 | int ret, i, cur_off = 0; | |
1184 | ||
1185 | sunxi_nfc_hw_ecc_enable(mtd); | |
1186 | ||
1187 | for (i = 0; i < ecc->steps; i++) { | |
1188 | int data_off = i * (ecc->size + ecc->bytes + 4); | |
1189 | int oob_off = data_off + ecc->size; | |
1190 | const u8 *data = buf + (i * ecc->size); | |
1191 | const u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4)); | |
1192 | ||
1193 | ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, | |
1194 | oob, oob_off, &cur_off, | |
1195 | false, page); | |
1196 | if (ret) | |
1197 | return ret; | |
1198 | } | |
1199 | ||
1200 | if (oob_required || (chip->options & NAND_NEED_SCRAMBLING)) | |
1201 | sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi, | |
1202 | &cur_off, page); | |
1203 | ||
1204 | sunxi_nfc_hw_ecc_disable(mtd); | |
1205 | ||
1206 | return 0; | |
1207 | } | |
1208 | ||
1209 | static const s32 tWB_lut[] = {6, 12, 16, 20}; | |
1210 | static const s32 tRHW_lut[] = {4, 8, 12, 20}; | |
1211 | ||
1212 | static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration, | |
1213 | u32 clk_period) | |
1214 | { | |
1215 | u32 clk_cycles = DIV_ROUND_UP(duration, clk_period); | |
1216 | int i; | |
1217 | ||
1218 | for (i = 0; i < lut_size; i++) { | |
1219 | if (clk_cycles <= lut[i]) | |
1220 | return i; | |
1221 | } | |
1222 | ||
1223 | /* Doesn't fit */ | |
1224 | return -EINVAL; | |
1225 | } | |
1226 | ||
1227 | #define sunxi_nand_lookup_timing(l, p, c) \ | |
1228 | _sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c) | |
1229 | ||
75eed1a1 SA |
1230 | static int sunxi_nand_chip_set_timings(struct sunxi_nfc *nfc, |
1231 | struct sunxi_nand_chip *chip, | |
4ccae81c BB |
1232 | const struct nand_sdr_timings *timings) |
1233 | { | |
1234 | u32 min_clk_period = 0; | |
1235 | s32 tWB, tADL, tWHR, tRHW, tCAD; | |
1236 | ||
1237 | /* T1 <=> tCLS */ | |
1238 | if (timings->tCLS_min > min_clk_period) | |
1239 | min_clk_period = timings->tCLS_min; | |
1240 | ||
1241 | /* T2 <=> tCLH */ | |
1242 | if (timings->tCLH_min > min_clk_period) | |
1243 | min_clk_period = timings->tCLH_min; | |
1244 | ||
1245 | /* T3 <=> tCS */ | |
1246 | if (timings->tCS_min > min_clk_period) | |
1247 | min_clk_period = timings->tCS_min; | |
1248 | ||
1249 | /* T4 <=> tCH */ | |
1250 | if (timings->tCH_min > min_clk_period) | |
1251 | min_clk_period = timings->tCH_min; | |
1252 | ||
1253 | /* T5 <=> tWP */ | |
1254 | if (timings->tWP_min > min_clk_period) | |
1255 | min_clk_period = timings->tWP_min; | |
1256 | ||
1257 | /* T6 <=> tWH */ | |
1258 | if (timings->tWH_min > min_clk_period) | |
1259 | min_clk_period = timings->tWH_min; | |
1260 | ||
1261 | /* T7 <=> tALS */ | |
1262 | if (timings->tALS_min > min_clk_period) | |
1263 | min_clk_period = timings->tALS_min; | |
1264 | ||
1265 | /* T8 <=> tDS */ | |
1266 | if (timings->tDS_min > min_clk_period) | |
1267 | min_clk_period = timings->tDS_min; | |
1268 | ||
1269 | /* T9 <=> tDH */ | |
1270 | if (timings->tDH_min > min_clk_period) | |
1271 | min_clk_period = timings->tDH_min; | |
1272 | ||
1273 | /* T10 <=> tRR */ | |
1274 | if (timings->tRR_min > (min_clk_period * 3)) | |
1275 | min_clk_period = DIV_ROUND_UP(timings->tRR_min, 3); | |
1276 | ||
1277 | /* T11 <=> tALH */ | |
1278 | if (timings->tALH_min > min_clk_period) | |
1279 | min_clk_period = timings->tALH_min; | |
1280 | ||
1281 | /* T12 <=> tRP */ | |
1282 | if (timings->tRP_min > min_clk_period) | |
1283 | min_clk_period = timings->tRP_min; | |
1284 | ||
1285 | /* T13 <=> tREH */ | |
1286 | if (timings->tREH_min > min_clk_period) | |
1287 | min_clk_period = timings->tREH_min; | |
1288 | ||
1289 | /* T14 <=> tRC */ | |
1290 | if (timings->tRC_min > (min_clk_period * 2)) | |
1291 | min_clk_period = DIV_ROUND_UP(timings->tRC_min, 2); | |
1292 | ||
1293 | /* T15 <=> tWC */ | |
1294 | if (timings->tWC_min > (min_clk_period * 2)) | |
1295 | min_clk_period = DIV_ROUND_UP(timings->tWC_min, 2); | |
1296 | ||
1297 | /* T16 - T19 + tCAD */ | |
1298 | tWB = sunxi_nand_lookup_timing(tWB_lut, timings->tWB_max, | |
1299 | min_clk_period); | |
1300 | if (tWB < 0) { | |
1301 | dev_err(nfc->dev, "unsupported tWB\n"); | |
1302 | return tWB; | |
1303 | } | |
1304 | ||
1305 | tADL = DIV_ROUND_UP(timings->tADL_min, min_clk_period) >> 3; | |
1306 | if (tADL > 3) { | |
1307 | dev_err(nfc->dev, "unsupported tADL\n"); | |
1308 | return -EINVAL; | |
1309 | } | |
1310 | ||
1311 | tWHR = DIV_ROUND_UP(timings->tWHR_min, min_clk_period) >> 3; | |
1312 | if (tWHR > 3) { | |
1313 | dev_err(nfc->dev, "unsupported tWHR\n"); | |
1314 | return -EINVAL; | |
1315 | } | |
1316 | ||
1317 | tRHW = sunxi_nand_lookup_timing(tRHW_lut, timings->tRHW_min, | |
1318 | min_clk_period); | |
1319 | if (tRHW < 0) { | |
1320 | dev_err(nfc->dev, "unsupported tRHW\n"); | |
1321 | return tRHW; | |
1322 | } | |
1323 | ||
1324 | /* | |
1325 | * TODO: according to ONFI specs this value only applies for DDR NAND, | |
1326 | * but Allwinner seems to set this to 0x7. Mimic them for now. | |
1327 | */ | |
1328 | tCAD = 0x7; | |
1329 | ||
1330 | /* TODO: A83 has some more bits for CDQSS, CS, CLHZ, CCS, WC */ | |
1331 | chip->timing_cfg = NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD); | |
1332 | ||
1333 | /* | |
1334 | * ONFI specification 3.1, paragraph 4.15.2 dictates that EDO data | |
1335 | * output cycle timings shall be used if the host drives tRC less than | |
1336 | * 30 ns. | |
1337 | */ | |
1338 | chip->timing_ctl = (timings->tRC_min < 30000) ? NFC_TIMING_CTL_EDO : 0; | |
1339 | ||
1340 | /* Convert min_clk_period from picoseconds to nanoseconds */ | |
1341 | min_clk_period = DIV_ROUND_UP(min_clk_period, 1000); | |
1342 | ||
1343 | /* | |
1344 | * Convert min_clk_period into a clk frequency, then get the | |
1345 | * appropriate rate for the NAND controller IP given this formula | |
1346 | * (specified in the datasheet): | |
1347 | * nand clk_rate = min_clk_rate | |
1348 | */ | |
1349 | chip->clk_rate = 1000000000L / min_clk_period; | |
1350 | ||
1351 | return 0; | |
1352 | } | |
1353 | ||
75eed1a1 SA |
1354 | static int sunxi_nand_chip_init_timings(struct sunxi_nfc *nfc, |
1355 | struct sunxi_nand_chip *chip) | |
4ccae81c BB |
1356 | { |
1357 | struct mtd_info *mtd = nand_to_mtd(&chip->nand); | |
1358 | const struct nand_sdr_timings *timings; | |
1359 | int ret; | |
1360 | int mode; | |
1361 | ||
1362 | mode = onfi_get_async_timing_mode(&chip->nand); | |
1363 | if (mode == ONFI_TIMING_MODE_UNKNOWN) { | |
1364 | mode = chip->nand.onfi_timing_mode_default; | |
1365 | } else { | |
1366 | uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {}; | |
1367 | int i; | |
1368 | ||
1369 | mode = fls(mode) - 1; | |
1370 | if (mode < 0) | |
1371 | mode = 0; | |
1372 | ||
1373 | feature[0] = mode; | |
1374 | for (i = 0; i < chip->nsels; i++) { | |
1375 | chip->nand.select_chip(mtd, i); | |
1376 | ret = chip->nand.onfi_set_features(mtd, | |
1377 | &chip->nand, | |
1378 | ONFI_FEATURE_ADDR_TIMING_MODE, | |
1379 | feature); | |
1380 | chip->nand.select_chip(mtd, -1); | |
850bdafa | 1381 | if (ret && ret != -ENOTSUPP) |
4ccae81c BB |
1382 | return ret; |
1383 | } | |
1384 | } | |
1385 | ||
1386 | timings = onfi_async_timing_mode_to_sdr_timings(mode); | |
1387 | if (IS_ERR(timings)) | |
1388 | return PTR_ERR(timings); | |
1389 | ||
75eed1a1 | 1390 | return sunxi_nand_chip_set_timings(nfc, chip, timings); |
4ccae81c BB |
1391 | } |
1392 | ||
1393 | static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd, | |
1394 | struct nand_ecc_ctrl *ecc) | |
1395 | { | |
1396 | static const u8 strengths[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 }; | |
1397 | struct sunxi_nand_hw_ecc *data; | |
1398 | struct nand_ecclayout *layout; | |
1399 | int nsectors; | |
1400 | int ret; | |
1401 | int i; | |
1402 | ||
1403 | data = kzalloc(sizeof(*data), GFP_KERNEL); | |
1404 | if (!data) | |
1405 | return -ENOMEM; | |
1406 | ||
1407 | if (ecc->size != 512 && ecc->size != 1024) | |
1408 | return -EINVAL; | |
1409 | ||
1410 | /* Prefer 1k ECC chunk over 512 ones */ | |
1411 | if (ecc->size == 512 && mtd->writesize > 512) { | |
1412 | ecc->size = 1024; | |
1413 | ecc->strength *= 2; | |
1414 | } | |
1415 | ||
1416 | /* Add ECC info retrieval from DT */ | |
1417 | for (i = 0; i < ARRAY_SIZE(strengths); i++) { | |
f3aff376 MR |
1418 | if (ecc->strength <= strengths[i]) { |
1419 | /* | |
1420 | * Update ecc->strength value with the actual strength | |
1421 | * that will be used by the ECC engine. | |
1422 | */ | |
1423 | ecc->strength = strengths[i]; | |
4ccae81c | 1424 | break; |
f3aff376 | 1425 | } |
4ccae81c BB |
1426 | } |
1427 | ||
1428 | if (i >= ARRAY_SIZE(strengths)) { | |
75eed1a1 | 1429 | dev_err(mtd->dev, "unsupported strength\n"); |
4ccae81c BB |
1430 | ret = -ENOTSUPP; |
1431 | goto err; | |
1432 | } | |
1433 | ||
1434 | data->mode = i; | |
1435 | ||
1436 | /* HW ECC always request ECC bytes for 1024 bytes blocks */ | |
1437 | ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * 1024), 8); | |
1438 | ||
1439 | /* HW ECC always work with even numbers of ECC bytes */ | |
1440 | ecc->bytes = ALIGN(ecc->bytes, 2); | |
1441 | ||
1442 | layout = &data->layout; | |
1443 | nsectors = mtd->writesize / ecc->size; | |
1444 | ||
1445 | if (mtd->oobsize < ((ecc->bytes + 4) * nsectors)) { | |
1446 | ret = -EINVAL; | |
1447 | goto err; | |
1448 | } | |
1449 | ||
1450 | layout->eccbytes = (ecc->bytes * nsectors); | |
1451 | ||
1452 | ecc->layout = layout; | |
1453 | ecc->priv = data; | |
1454 | ||
1455 | return 0; | |
1456 | ||
1457 | err: | |
1458 | kfree(data); | |
1459 | ||
1460 | return ret; | |
1461 | } | |
1462 | ||
1463 | #ifndef __UBOOT__ | |
1464 | static void sunxi_nand_hw_common_ecc_ctrl_cleanup(struct nand_ecc_ctrl *ecc) | |
1465 | { | |
1466 | kfree(ecc->priv); | |
1467 | } | |
1468 | #endif /* __UBOOT__ */ | |
1469 | ||
1470 | static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd, | |
1471 | struct nand_ecc_ctrl *ecc) | |
1472 | { | |
1473 | struct nand_ecclayout *layout; | |
1474 | int nsectors; | |
1475 | int i, j; | |
1476 | int ret; | |
1477 | ||
1478 | ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc); | |
1479 | if (ret) | |
1480 | return ret; | |
1481 | ||
1482 | ecc->read_page = sunxi_nfc_hw_ecc_read_page; | |
1483 | ecc->write_page = sunxi_nfc_hw_ecc_write_page; | |
1484 | ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage; | |
1485 | ecc->write_subpage = sunxi_nfc_hw_ecc_write_subpage; | |
1486 | layout = ecc->layout; | |
1487 | nsectors = mtd->writesize / ecc->size; | |
1488 | ||
1489 | for (i = 0; i < nsectors; i++) { | |
1490 | if (i) { | |
1491 | layout->oobfree[i].offset = | |
1492 | layout->oobfree[i - 1].offset + | |
1493 | layout->oobfree[i - 1].length + | |
1494 | ecc->bytes; | |
1495 | layout->oobfree[i].length = 4; | |
1496 | } else { | |
1497 | /* | |
1498 | * The first 2 bytes are used for BB markers, hence we | |
1499 | * only have 2 bytes available in the first user data | |
1500 | * section. | |
1501 | */ | |
1502 | layout->oobfree[i].length = 2; | |
1503 | layout->oobfree[i].offset = 2; | |
1504 | } | |
1505 | ||
1506 | for (j = 0; j < ecc->bytes; j++) | |
1507 | layout->eccpos[(ecc->bytes * i) + j] = | |
1508 | layout->oobfree[i].offset + | |
1509 | layout->oobfree[i].length + j; | |
1510 | } | |
1511 | ||
1512 | if (mtd->oobsize > (ecc->bytes + 4) * nsectors) { | |
1513 | layout->oobfree[nsectors].offset = | |
1514 | layout->oobfree[nsectors - 1].offset + | |
1515 | layout->oobfree[nsectors - 1].length + | |
1516 | ecc->bytes; | |
1517 | layout->oobfree[nsectors].length = mtd->oobsize - | |
1518 | ((ecc->bytes + 4) * nsectors); | |
1519 | } | |
1520 | ||
1521 | return 0; | |
1522 | } | |
1523 | ||
1524 | static int sunxi_nand_hw_syndrome_ecc_ctrl_init(struct mtd_info *mtd, | |
1525 | struct nand_ecc_ctrl *ecc) | |
1526 | { | |
1527 | struct nand_ecclayout *layout; | |
1528 | int nsectors; | |
1529 | int i; | |
1530 | int ret; | |
1531 | ||
1532 | ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc); | |
1533 | if (ret) | |
1534 | return ret; | |
1535 | ||
1536 | ecc->prepad = 4; | |
1537 | ecc->read_page = sunxi_nfc_hw_syndrome_ecc_read_page; | |
1538 | ecc->write_page = sunxi_nfc_hw_syndrome_ecc_write_page; | |
1539 | ||
1540 | layout = ecc->layout; | |
1541 | nsectors = mtd->writesize / ecc->size; | |
1542 | ||
1543 | for (i = 0; i < (ecc->bytes * nsectors); i++) | |
1544 | layout->eccpos[i] = i; | |
1545 | ||
1546 | layout->oobfree[0].length = mtd->oobsize - i; | |
1547 | layout->oobfree[0].offset = i; | |
1548 | ||
1549 | return 0; | |
1550 | } | |
1551 | ||
1552 | #ifndef __UBOOT__ | |
1553 | static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc) | |
1554 | { | |
1555 | switch (ecc->mode) { | |
1556 | case NAND_ECC_HW: | |
1557 | case NAND_ECC_HW_SYNDROME: | |
1558 | sunxi_nand_hw_common_ecc_ctrl_cleanup(ecc); | |
1559 | break; | |
1560 | case NAND_ECC_NONE: | |
1561 | kfree(ecc->layout); | |
1562 | default: | |
1563 | break; | |
1564 | } | |
1565 | } | |
1566 | #endif /* __UBOOT__ */ | |
1567 | ||
1568 | static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc) | |
1569 | { | |
1570 | struct nand_chip *nand = mtd_to_nand(mtd); | |
1571 | int ret; | |
1572 | ||
1573 | if (!ecc->size) { | |
1574 | ecc->size = nand->ecc_step_ds; | |
1575 | ecc->strength = nand->ecc_strength_ds; | |
1576 | } | |
1577 | ||
1578 | if (!ecc->size || !ecc->strength) | |
1579 | return -EINVAL; | |
1580 | ||
1581 | switch (ecc->mode) { | |
1582 | case NAND_ECC_SOFT_BCH: | |
1583 | break; | |
1584 | case NAND_ECC_HW: | |
1585 | ret = sunxi_nand_hw_ecc_ctrl_init(mtd, ecc); | |
1586 | if (ret) | |
1587 | return ret; | |
1588 | break; | |
1589 | case NAND_ECC_HW_SYNDROME: | |
1590 | ret = sunxi_nand_hw_syndrome_ecc_ctrl_init(mtd, ecc); | |
1591 | if (ret) | |
1592 | return ret; | |
1593 | break; | |
1594 | case NAND_ECC_NONE: | |
1595 | ecc->layout = kzalloc(sizeof(*ecc->layout), GFP_KERNEL); | |
1596 | if (!ecc->layout) | |
1597 | return -ENOMEM; | |
1598 | ecc->layout->oobfree[0].length = mtd->oobsize; | |
1599 | case NAND_ECC_SOFT: | |
1600 | break; | |
1601 | default: | |
1602 | return -EINVAL; | |
1603 | } | |
1604 | ||
1605 | return 0; | |
1606 | } | |
1607 | ||
2a6805b5 SH |
1608 | static int sunxi_nand_chip_init(struct udevice *dev, struct sunxi_nfc *nfc, |
1609 | ofnode np, int devnum) | |
4ccae81c BB |
1610 | { |
1611 | const struct nand_sdr_timings *timings; | |
4ccae81c BB |
1612 | struct sunxi_nand_chip *chip; |
1613 | struct mtd_info *mtd; | |
1614 | struct nand_chip *nand; | |
1615 | int nsels; | |
1616 | int ret; | |
1617 | int i; | |
1eb09081 | 1618 | u32 tmp; |
4ccae81c | 1619 | |
1eb09081 | 1620 | if (!ofnode_get_property(np, "reg", &nsels)) |
4ccae81c BB |
1621 | return -EINVAL; |
1622 | ||
1623 | nsels /= sizeof(u32); | |
1624 | if (!nsels || nsels > 8) { | |
2a6805b5 | 1625 | dev_err(dev, "invalid reg property size\n"); |
4ccae81c BB |
1626 | return -EINVAL; |
1627 | } | |
1628 | ||
1629 | chip = kzalloc(sizeof(*chip) + | |
1630 | (nsels * sizeof(struct sunxi_nand_chip_sel)), | |
1631 | GFP_KERNEL); | |
1632 | if (!chip) { | |
2a6805b5 | 1633 | dev_err(dev, "could not allocate chip\n"); |
4ccae81c BB |
1634 | return -ENOMEM; |
1635 | } | |
1636 | ||
1637 | chip->nsels = nsels; | |
1638 | chip->selected = -1; | |
1639 | ||
1640 | for (i = 0; i < nsels; i++) { | |
1eb09081 SH |
1641 | ret = ofnode_read_u32_index(np, "reg", i, &tmp); |
1642 | if (ret) { | |
2a6805b5 | 1643 | dev_err(dev, "could not retrieve reg property: %d\n", |
1eb09081 SH |
1644 | ret); |
1645 | return ret; | |
1646 | } | |
4ccae81c BB |
1647 | |
1648 | if (tmp > NFC_MAX_CS) { | |
2a6805b5 | 1649 | dev_err(dev, |
75eed1a1 | 1650 | "invalid reg value: %u (max CS = 7)\n", tmp); |
4ccae81c BB |
1651 | return -EINVAL; |
1652 | } | |
1653 | ||
1654 | if (test_and_set_bit(tmp, &nfc->assigned_cs)) { | |
2a6805b5 | 1655 | dev_err(dev, "CS %d already assigned\n", tmp); |
4ccae81c BB |
1656 | return -EINVAL; |
1657 | } | |
1658 | ||
1659 | chip->sels[i].cs = tmp; | |
1660 | ||
1eb09081 SH |
1661 | if (!ofnode_read_u32_index(np, "allwinner,rb", i, &tmp) && |
1662 | tmp < 2) { | |
4ccae81c BB |
1663 | chip->sels[i].rb.type = RB_NATIVE; |
1664 | chip->sels[i].rb.info.nativeid = tmp; | |
1665 | } else { | |
2a6805b5 SH |
1666 | ret = gpio_request_by_name(dev, "rb-gpios", i, |
1667 | &chip->sels[i].rb.info.gpio, | |
1668 | GPIOD_IS_IN); | |
4ccae81c BB |
1669 | if (ret) |
1670 | chip->sels[i].rb.type = RB_GPIO; | |
1671 | else | |
1672 | chip->sels[i].rb.type = RB_NONE; | |
1673 | } | |
1674 | } | |
1675 | ||
1676 | timings = onfi_async_timing_mode_to_sdr_timings(0); | |
1677 | if (IS_ERR(timings)) { | |
1678 | ret = PTR_ERR(timings); | |
2a6805b5 | 1679 | dev_err(dev, |
4ccae81c BB |
1680 | "could not retrieve timings for ONFI mode 0: %d\n", |
1681 | ret); | |
1682 | return ret; | |
1683 | } | |
1684 | ||
75eed1a1 | 1685 | ret = sunxi_nand_chip_set_timings(nfc, chip, timings); |
4ccae81c | 1686 | if (ret) { |
2a6805b5 | 1687 | dev_err(dev, "could not configure chip timings: %d\n", ret); |
4ccae81c BB |
1688 | return ret; |
1689 | } | |
1690 | ||
1691 | nand = &chip->nand; | |
1692 | /* Default tR value specified in the ONFI spec (chapter 4.15.1) */ | |
1693 | nand->chip_delay = 200; | |
1694 | nand->controller = &nfc->controller; | |
1695 | /* | |
1696 | * Set the ECC mode to the default value in case nothing is specified | |
1697 | * in the DT. | |
1698 | */ | |
1699 | nand->ecc.mode = NAND_ECC_HW; | |
1eb09081 | 1700 | nand->flash_node = np; |
4ccae81c BB |
1701 | nand->select_chip = sunxi_nfc_select_chip; |
1702 | nand->cmd_ctrl = sunxi_nfc_cmd_ctrl; | |
1703 | nand->read_buf = sunxi_nfc_read_buf; | |
1704 | nand->write_buf = sunxi_nfc_write_buf; | |
1705 | nand->read_byte = sunxi_nfc_read_byte; | |
1706 | ||
1707 | mtd = nand_to_mtd(nand); | |
1708 | ret = nand_scan_ident(mtd, nsels, NULL); | |
1709 | if (ret) | |
1710 | return ret; | |
1711 | ||
1712 | if (nand->bbt_options & NAND_BBT_USE_FLASH) | |
1713 | nand->bbt_options |= NAND_BBT_NO_OOB; | |
1714 | ||
1715 | if (nand->options & NAND_NEED_SCRAMBLING) | |
1716 | nand->options |= NAND_NO_SUBPAGE_WRITE; | |
1717 | ||
1718 | nand->options |= NAND_SUBPAGE_READ; | |
1719 | ||
75eed1a1 | 1720 | ret = sunxi_nand_chip_init_timings(nfc, chip); |
4ccae81c | 1721 | if (ret) { |
2a6805b5 | 1722 | dev_err(dev, "could not configure chip timings: %d\n", ret); |
4ccae81c BB |
1723 | return ret; |
1724 | } | |
1725 | ||
1726 | ret = sunxi_nand_ecc_init(mtd, &nand->ecc); | |
1727 | if (ret) { | |
2a6805b5 | 1728 | dev_err(dev, "ECC init failed: %d\n", ret); |
4ccae81c BB |
1729 | return ret; |
1730 | } | |
1731 | ||
1732 | ret = nand_scan_tail(mtd); | |
1733 | if (ret) { | |
2a6805b5 | 1734 | dev_err(dev, "nand_scan_tail failed: %d\n", ret); |
4ccae81c BB |
1735 | return ret; |
1736 | } | |
1737 | ||
1738 | ret = nand_register(devnum, mtd); | |
1739 | if (ret) { | |
2a6805b5 | 1740 | dev_err(dev, "failed to register mtd device: %d\n", ret); |
4ccae81c BB |
1741 | return ret; |
1742 | } | |
1743 | ||
1744 | list_add_tail(&chip->node, &nfc->chips); | |
1745 | ||
1746 | return 0; | |
1747 | } | |
1748 | ||
2a6805b5 | 1749 | static int sunxi_nand_chips_init(struct udevice *dev, struct sunxi_nfc *nfc) |
4ccae81c | 1750 | { |
1eb09081 | 1751 | ofnode nand_np; |
4ccae81c BB |
1752 | int ret, i = 0; |
1753 | ||
2a6805b5 SH |
1754 | dev_for_each_subnode(nand_np, dev) { |
1755 | ret = sunxi_nand_chip_init(dev, nfc, nand_np, i++); | |
4ccae81c BB |
1756 | if (ret) |
1757 | return ret; | |
1758 | } | |
1759 | ||
1760 | return 0; | |
1761 | } | |
1762 | ||
1763 | #ifndef __UBOOT__ | |
1764 | static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc) | |
1765 | { | |
1766 | struct sunxi_nand_chip *chip; | |
1767 | ||
1768 | while (!list_empty(&nfc->chips)) { | |
1769 | chip = list_first_entry(&nfc->chips, struct sunxi_nand_chip, | |
1770 | node); | |
1771 | nand_release(&chip->mtd); | |
1772 | sunxi_nand_ecc_cleanup(&chip->nand.ecc); | |
1773 | list_del(&chip->node); | |
1774 | kfree(chip); | |
1775 | } | |
1776 | } | |
1777 | #endif /* __UBOOT__ */ | |
1778 | ||
21b790fd | 1779 | static int sunxi_nand_probe(struct udevice *dev) |
4ccae81c | 1780 | { |
21b790fd SH |
1781 | struct sunxi_nfc *nfc = dev_get_priv(dev); |
1782 | struct reset_ctl_bulk rst_bulk; | |
1783 | struct clk_bulk clk_bulk; | |
4ccae81c BB |
1784 | int ret; |
1785 | ||
21b790fd | 1786 | nfc->dev = dev; |
4ccae81c BB |
1787 | spin_lock_init(&nfc->controller.lock); |
1788 | init_waitqueue_head(&nfc->controller.wq); | |
1789 | INIT_LIST_HEAD(&nfc->chips); | |
1790 | ||
21b790fd SH |
1791 | nfc->regs = dev_read_addr_ptr(dev); |
1792 | if (!nfc->regs) | |
1793 | return -EINVAL; | |
4ccae81c | 1794 | |
21b790fd SH |
1795 | ret = reset_get_bulk(dev, &rst_bulk); |
1796 | if (!ret) | |
1797 | reset_deassert_bulk(&rst_bulk); | |
4ccae81c | 1798 | |
21b790fd SH |
1799 | ret = clk_get_bulk(dev, &clk_bulk); |
1800 | if (!ret) | |
1801 | clk_enable_bulk(&clk_bulk); | |
4ccae81c BB |
1802 | |
1803 | ret = sunxi_nfc_rst(nfc); | |
1804 | if (ret) | |
21b790fd | 1805 | return ret; |
4ccae81c | 1806 | |
2a6805b5 | 1807 | ret = sunxi_nand_chips_init(dev, nfc); |
4ccae81c | 1808 | if (ret) { |
21b790fd SH |
1809 | dev_err(dev, "failed to init nand chips\n"); |
1810 | return ret; | |
4ccae81c BB |
1811 | } |
1812 | ||
21b790fd SH |
1813 | return 0; |
1814 | } | |
4ccae81c | 1815 | |
21b790fd SH |
1816 | static const struct udevice_id sunxi_nand_ids[] = { |
1817 | { | |
1818 | .compatible = "allwinner,sun4i-a10-nand", | |
1819 | }, | |
1820 | { } | |
1821 | }; | |
1822 | ||
1823 | U_BOOT_DRIVER(sunxi_nand) = { | |
1824 | .name = "sunxi_nand", | |
1825 | .id = UCLASS_MTD, | |
1826 | .of_match = sunxi_nand_ids, | |
1827 | .probe = sunxi_nand_probe, | |
1828 | .priv_auto = sizeof(struct sunxi_nfc), | |
1829 | }; | |
1830 | ||
1831 | void board_nand_init(void) | |
1832 | { | |
1833 | struct udevice *dev; | |
1834 | int ret; | |
1835 | ||
1836 | ret = uclass_get_device_by_driver(UCLASS_MTD, | |
1837 | DM_DRIVER_GET(sunxi_nand), &dev); | |
1838 | if (ret && ret != -ENODEV) | |
1839 | pr_err("Failed to initialize sunxi NAND controller: %d\n", ret); | |
4ccae81c BB |
1840 | } |
1841 | ||
1842 | MODULE_LICENSE("GPL v2"); | |
1843 | MODULE_AUTHOR("Boris BREZILLON"); | |
1844 | MODULE_DESCRIPTION("Allwinner NAND Flash Controller driver"); |