.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0+ |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2013 Boris BREZILLON <b.brezillon.dev@gmail.com> |
---|
3 | 4 | * |
---|
.. | .. |
---|
10 | 11 | * |
---|
11 | 12 | * Copyright (C) 2013 Dmitriy B. <rzk333@gmail.com> |
---|
12 | 13 | * Copyright (C) 2013 Sergey Lapin <slapin@ossfans.org> |
---|
13 | | - * |
---|
14 | | - * This program is free software; you can redistribute it and/or modify |
---|
15 | | - * it under the terms of the GNU General Public License as published by |
---|
16 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
17 | | - * (at your option) any later version. |
---|
18 | | - * |
---|
19 | | - * This program is distributed in the hope that it will be useful, |
---|
20 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
21 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
22 | | - * GNU General Public License for more details. |
---|
23 | 14 | */ |
---|
24 | 15 | |
---|
25 | 16 | #include <linux/dma-mapping.h> |
---|
.. | .. |
---|
51 | 42 | #define NFC_REG_CMD 0x0024 |
---|
52 | 43 | #define NFC_REG_RCMD_SET 0x0028 |
---|
53 | 44 | #define NFC_REG_WCMD_SET 0x002C |
---|
54 | | -#define NFC_REG_IO_DATA 0x0030 |
---|
| 45 | +#define NFC_REG_A10_IO_DATA 0x0030 |
---|
| 46 | +#define NFC_REG_A23_IO_DATA 0x0300 |
---|
55 | 47 | #define NFC_REG_ECC_CTL 0x0034 |
---|
56 | 48 | #define NFC_REG_ECC_ST 0x0038 |
---|
57 | 49 | #define NFC_REG_DEBUG 0x003C |
---|
.. | .. |
---|
59 | 51 | #define NFC_REG_USER_DATA(x) (0x0050 + ((x) * 4)) |
---|
60 | 52 | #define NFC_REG_SPARE_AREA 0x00A0 |
---|
61 | 53 | #define NFC_REG_PAT_ID 0x00A4 |
---|
| 54 | +#define NFC_REG_MDMA_CNT 0x00C4 |
---|
62 | 55 | #define NFC_RAM0_BASE 0x0400 |
---|
63 | 56 | #define NFC_RAM1_BASE 0x0800 |
---|
64 | 57 | |
---|
.. | .. |
---|
77 | 70 | #define NFC_PAGE_SHIFT(x) (((x) < 10 ? 0 : (x) - 10) << 8) |
---|
78 | 71 | #define NFC_SAM BIT(12) |
---|
79 | 72 | #define NFC_RAM_METHOD BIT(14) |
---|
| 73 | +#define NFC_DMA_TYPE_NORMAL BIT(15) |
---|
80 | 74 | #define NFC_DEBUG_CTL BIT(31) |
---|
81 | 75 | |
---|
82 | 76 | /* define bit use in NFC_ST */ |
---|
.. | .. |
---|
163 | 157 | |
---|
164 | 158 | #define NFC_MAX_CS 7 |
---|
165 | 159 | |
---|
166 | | -/* |
---|
167 | | - * Chip Select structure: stores information related to NAND Chip Select |
---|
| 160 | +/** |
---|
| 161 | + * struct sunxi_nand_chip_sel - stores information related to NAND Chip Select |
---|
168 | 162 | * |
---|
169 | | - * @cs: the NAND CS id used to communicate with a NAND Chip |
---|
170 | | - * @rb: the Ready/Busy pin ID. -1 means no R/B pin connected to the |
---|
171 | | - * NFC |
---|
| 163 | + * @cs: the NAND CS id used to communicate with a NAND Chip |
---|
| 164 | + * @rb: the Ready/Busy pin ID. -1 means no R/B pin connected to the NFC |
---|
172 | 165 | */ |
---|
173 | 166 | struct sunxi_nand_chip_sel { |
---|
174 | 167 | u8 cs; |
---|
175 | 168 | s8 rb; |
---|
176 | 169 | }; |
---|
177 | 170 | |
---|
178 | | -/* |
---|
179 | | - * sunxi HW ECC infos: stores information related to HW ECC support |
---|
| 171 | +/** |
---|
| 172 | + * struct sunxi_nand_hw_ecc - stores information related to HW ECC support |
---|
180 | 173 | * |
---|
181 | | - * @mode: the sunxi ECC mode field deduced from ECC requirements |
---|
| 174 | + * @mode: the sunxi ECC mode field deduced from ECC requirements |
---|
182 | 175 | */ |
---|
183 | 176 | struct sunxi_nand_hw_ecc { |
---|
184 | 177 | int mode; |
---|
185 | 178 | }; |
---|
186 | 179 | |
---|
187 | | -/* |
---|
188 | | - * NAND chip structure: stores NAND chip device related information |
---|
| 180 | +/** |
---|
| 181 | + * struct sunxi_nand_chip - stores NAND chip device related information |
---|
189 | 182 | * |
---|
190 | | - * @node: used to store NAND chips into a list |
---|
191 | | - * @nand: base NAND chip structure |
---|
192 | | - * @mtd: base MTD structure |
---|
193 | | - * @clk_rate: clk_rate required for this NAND chip |
---|
194 | | - * @timing_cfg TIMING_CFG register value for this NAND chip |
---|
195 | | - * @selected: current active CS |
---|
196 | | - * @nsels: number of CS lines required by the NAND chip |
---|
197 | | - * @sels: array of CS lines descriptions |
---|
| 183 | + * @node: used to store NAND chips into a list |
---|
| 184 | + * @nand: base NAND chip structure |
---|
| 185 | + * @clk_rate: clk_rate required for this NAND chip |
---|
| 186 | + * @timing_cfg: TIMING_CFG register value for this NAND chip |
---|
| 187 | + * @timing_ctl: TIMING_CTL register value for this NAND chip |
---|
| 188 | + * @nsels: number of CS lines required by the NAND chip |
---|
| 189 | + * @sels: array of CS lines descriptions |
---|
198 | 190 | */ |
---|
199 | 191 | struct sunxi_nand_chip { |
---|
200 | 192 | struct list_head node; |
---|
.. | .. |
---|
202 | 194 | unsigned long clk_rate; |
---|
203 | 195 | u32 timing_cfg; |
---|
204 | 196 | u32 timing_ctl; |
---|
205 | | - int selected; |
---|
206 | | - int addr_cycles; |
---|
207 | | - u32 addr[2]; |
---|
208 | | - int cmd_cycles; |
---|
209 | | - u8 cmd[2]; |
---|
210 | 197 | int nsels; |
---|
211 | | - struct sunxi_nand_chip_sel sels[0]; |
---|
| 198 | + struct sunxi_nand_chip_sel sels[]; |
---|
212 | 199 | }; |
---|
213 | 200 | |
---|
214 | 201 | static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand) |
---|
.. | .. |
---|
217 | 204 | } |
---|
218 | 205 | |
---|
219 | 206 | /* |
---|
220 | | - * NAND Controller structure: stores sunxi NAND controller information |
---|
| 207 | + * NAND Controller capabilities structure: stores NAND controller capabilities |
---|
| 208 | + * for distinction between compatible strings. |
---|
221 | 209 | * |
---|
222 | | - * @controller: base controller structure |
---|
223 | | - * @dev: parent device (used to print error messages) |
---|
224 | | - * @regs: NAND controller registers |
---|
225 | | - * @ahb_clk: NAND Controller AHB clock |
---|
226 | | - * @mod_clk: NAND Controller mod clock |
---|
227 | | - * @assigned_cs: bitmask describing already assigned CS lines |
---|
228 | | - * @clk_rate: NAND controller current clock rate |
---|
229 | | - * @chips: a list containing all the NAND chips attached to |
---|
230 | | - * this NAND controller |
---|
231 | | - * @complete: a completion object used to wait for NAND |
---|
232 | | - * controller events |
---|
| 210 | + * @extra_mbus_conf: Contrary to A10, A10s and A13, accessing internal RAM |
---|
| 211 | + * through MBUS on A23/A33 needs extra configuration. |
---|
| 212 | + * @reg_io_data: I/O data register |
---|
| 213 | + * @dma_maxburst: DMA maxburst |
---|
| 214 | + */ |
---|
| 215 | +struct sunxi_nfc_caps { |
---|
| 216 | + bool extra_mbus_conf; |
---|
| 217 | + unsigned int reg_io_data; |
---|
| 218 | + unsigned int dma_maxburst; |
---|
| 219 | +}; |
---|
| 220 | + |
---|
| 221 | +/** |
---|
| 222 | + * struct sunxi_nfc - stores sunxi NAND controller information |
---|
| 223 | + * |
---|
| 224 | + * @controller: base controller structure |
---|
| 225 | + * @dev: parent device (used to print error messages) |
---|
| 226 | + * @regs: NAND controller registers |
---|
| 227 | + * @ahb_clk: NAND controller AHB clock |
---|
| 228 | + * @mod_clk: NAND controller mod clock |
---|
| 229 | + * @reset: NAND controller reset line |
---|
| 230 | + * @assigned_cs: bitmask describing already assigned CS lines |
---|
| 231 | + * @clk_rate: NAND controller current clock rate |
---|
| 232 | + * @chips: a list containing all the NAND chips attached to this NAND |
---|
| 233 | + * controller |
---|
| 234 | + * @complete: a completion object used to wait for NAND controller events |
---|
| 235 | + * @dmac: the DMA channel attached to the NAND controller |
---|
233 | 236 | */ |
---|
234 | 237 | struct sunxi_nfc { |
---|
235 | 238 | struct nand_controller controller; |
---|
.. | .. |
---|
243 | 246 | struct list_head chips; |
---|
244 | 247 | struct completion complete; |
---|
245 | 248 | struct dma_chan *dmac; |
---|
| 249 | + const struct sunxi_nfc_caps *caps; |
---|
246 | 250 | }; |
---|
247 | 251 | |
---|
248 | 252 | static inline struct sunxi_nfc *to_sunxi_nfc(struct nand_controller *ctrl) |
---|
.. | .. |
---|
339 | 343 | return ret; |
---|
340 | 344 | } |
---|
341 | 345 | |
---|
342 | | -static int sunxi_nfc_dma_op_prepare(struct mtd_info *mtd, const void *buf, |
---|
| 346 | +static int sunxi_nfc_dma_op_prepare(struct sunxi_nfc *nfc, const void *buf, |
---|
343 | 347 | int chunksize, int nchunks, |
---|
344 | 348 | enum dma_data_direction ddir, |
---|
345 | 349 | struct scatterlist *sg) |
---|
346 | 350 | { |
---|
347 | | - struct nand_chip *nand = mtd_to_nand(mtd); |
---|
348 | | - struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); |
---|
349 | 351 | struct dma_async_tx_descriptor *dmad; |
---|
350 | 352 | enum dma_transfer_direction tdir; |
---|
351 | 353 | dma_cookie_t dmat; |
---|
.. | .. |
---|
371 | 373 | nfc->regs + NFC_REG_CTL); |
---|
372 | 374 | writel(nchunks, nfc->regs + NFC_REG_SECTOR_NUM); |
---|
373 | 375 | writel(chunksize, nfc->regs + NFC_REG_CNT); |
---|
| 376 | + if (nfc->caps->extra_mbus_conf) |
---|
| 377 | + writel(chunksize * nchunks, nfc->regs + NFC_REG_MDMA_CNT); |
---|
| 378 | + |
---|
374 | 379 | dmat = dmaengine_submit(dmad); |
---|
375 | 380 | |
---|
376 | 381 | ret = dma_submit_error(dmat); |
---|
.. | .. |
---|
388 | 393 | return ret; |
---|
389 | 394 | } |
---|
390 | 395 | |
---|
391 | | -static void sunxi_nfc_dma_op_cleanup(struct mtd_info *mtd, |
---|
| 396 | +static void sunxi_nfc_dma_op_cleanup(struct sunxi_nfc *nfc, |
---|
392 | 397 | enum dma_data_direction ddir, |
---|
393 | 398 | struct scatterlist *sg) |
---|
394 | 399 | { |
---|
395 | | - struct nand_chip *nand = mtd_to_nand(mtd); |
---|
396 | | - struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); |
---|
397 | | - |
---|
398 | 400 | dma_unmap_sg(nfc->dev, sg, 1, ddir); |
---|
399 | 401 | writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD, |
---|
400 | 402 | nfc->regs + NFC_REG_CTL); |
---|
401 | 403 | } |
---|
402 | 404 | |
---|
403 | | -static int sunxi_nfc_dev_ready(struct mtd_info *mtd) |
---|
| 405 | +static void sunxi_nfc_select_chip(struct nand_chip *nand, unsigned int cs) |
---|
404 | 406 | { |
---|
405 | | - struct nand_chip *nand = mtd_to_nand(mtd); |
---|
406 | | - struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); |
---|
407 | | - struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); |
---|
408 | | - u32 mask; |
---|
409 | | - |
---|
410 | | - if (sunxi_nand->selected < 0) |
---|
411 | | - return 0; |
---|
412 | | - |
---|
413 | | - if (sunxi_nand->sels[sunxi_nand->selected].rb < 0) { |
---|
414 | | - dev_err(nfc->dev, "cannot check R/B NAND status!\n"); |
---|
415 | | - return 0; |
---|
416 | | - } |
---|
417 | | - |
---|
418 | | - mask = NFC_RB_STATE(sunxi_nand->sels[sunxi_nand->selected].rb); |
---|
419 | | - |
---|
420 | | - return !!(readl(nfc->regs + NFC_REG_ST) & mask); |
---|
421 | | -} |
---|
422 | | - |
---|
423 | | -static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip) |
---|
424 | | -{ |
---|
425 | | - struct nand_chip *nand = mtd_to_nand(mtd); |
---|
| 407 | + struct mtd_info *mtd = nand_to_mtd(nand); |
---|
426 | 408 | struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); |
---|
427 | 409 | struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); |
---|
428 | 410 | struct sunxi_nand_chip_sel *sel; |
---|
429 | 411 | u32 ctl; |
---|
430 | 412 | |
---|
431 | | - if (chip > 0 && chip >= sunxi_nand->nsels) |
---|
432 | | - return; |
---|
433 | | - |
---|
434 | | - if (chip == sunxi_nand->selected) |
---|
| 413 | + if (cs > 0 && cs >= sunxi_nand->nsels) |
---|
435 | 414 | return; |
---|
436 | 415 | |
---|
437 | 416 | ctl = readl(nfc->regs + NFC_REG_CTL) & |
---|
438 | 417 | ~(NFC_PAGE_SHIFT_MSK | NFC_CE_SEL_MSK | NFC_RB_SEL_MSK | NFC_EN); |
---|
439 | 418 | |
---|
440 | | - if (chip >= 0) { |
---|
441 | | - sel = &sunxi_nand->sels[chip]; |
---|
| 419 | + sel = &sunxi_nand->sels[cs]; |
---|
| 420 | + ctl |= NFC_CE_SEL(sel->cs) | NFC_EN | NFC_PAGE_SHIFT(nand->page_shift); |
---|
| 421 | + if (sel->rb >= 0) |
---|
| 422 | + ctl |= NFC_RB_SEL(sel->rb); |
---|
442 | 423 | |
---|
443 | | - ctl |= NFC_CE_SEL(sel->cs) | NFC_EN | |
---|
444 | | - NFC_PAGE_SHIFT(nand->page_shift); |
---|
445 | | - if (sel->rb < 0) { |
---|
446 | | - nand->dev_ready = NULL; |
---|
447 | | - } else { |
---|
448 | | - nand->dev_ready = sunxi_nfc_dev_ready; |
---|
449 | | - ctl |= NFC_RB_SEL(sel->rb); |
---|
450 | | - } |
---|
| 424 | + writel(mtd->writesize, nfc->regs + NFC_REG_SPARE_AREA); |
---|
451 | 425 | |
---|
452 | | - writel(mtd->writesize, nfc->regs + NFC_REG_SPARE_AREA); |
---|
453 | | - |
---|
454 | | - if (nfc->clk_rate != sunxi_nand->clk_rate) { |
---|
455 | | - clk_set_rate(nfc->mod_clk, sunxi_nand->clk_rate); |
---|
456 | | - nfc->clk_rate = sunxi_nand->clk_rate; |
---|
457 | | - } |
---|
| 426 | + if (nfc->clk_rate != sunxi_nand->clk_rate) { |
---|
| 427 | + clk_set_rate(nfc->mod_clk, sunxi_nand->clk_rate); |
---|
| 428 | + nfc->clk_rate = sunxi_nand->clk_rate; |
---|
458 | 429 | } |
---|
459 | 430 | |
---|
460 | 431 | writel(sunxi_nand->timing_ctl, nfc->regs + NFC_REG_TIMING_CTL); |
---|
461 | 432 | writel(sunxi_nand->timing_cfg, nfc->regs + NFC_REG_TIMING_CFG); |
---|
462 | 433 | writel(ctl, nfc->regs + NFC_REG_CTL); |
---|
463 | | - |
---|
464 | | - sunxi_nand->selected = chip; |
---|
465 | 434 | } |
---|
466 | 435 | |
---|
467 | | -static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) |
---|
| 436 | +static void sunxi_nfc_read_buf(struct nand_chip *nand, uint8_t *buf, int len) |
---|
468 | 437 | { |
---|
469 | | - struct nand_chip *nand = mtd_to_nand(mtd); |
---|
470 | 438 | struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); |
---|
471 | 439 | struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); |
---|
472 | 440 | int ret; |
---|
.. | .. |
---|
502 | 470 | } |
---|
503 | 471 | } |
---|
504 | 472 | |
---|
505 | | -static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, |
---|
| 473 | +static void sunxi_nfc_write_buf(struct nand_chip *nand, const uint8_t *buf, |
---|
506 | 474 | int len) |
---|
507 | 475 | { |
---|
508 | | - struct nand_chip *nand = mtd_to_nand(mtd); |
---|
509 | 476 | struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); |
---|
510 | 477 | struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); |
---|
511 | 478 | int ret; |
---|
.. | .. |
---|
537 | 504 | break; |
---|
538 | 505 | |
---|
539 | 506 | offs += cnt; |
---|
540 | | - } |
---|
541 | | -} |
---|
542 | | - |
---|
543 | | -static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd) |
---|
544 | | -{ |
---|
545 | | - uint8_t ret = 0; |
---|
546 | | - |
---|
547 | | - sunxi_nfc_read_buf(mtd, &ret, 1); |
---|
548 | | - |
---|
549 | | - return ret; |
---|
550 | | -} |
---|
551 | | - |
---|
552 | | -static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, |
---|
553 | | - unsigned int ctrl) |
---|
554 | | -{ |
---|
555 | | - struct nand_chip *nand = mtd_to_nand(mtd); |
---|
556 | | - struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); |
---|
557 | | - struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); |
---|
558 | | - int ret; |
---|
559 | | - |
---|
560 | | - if (dat == NAND_CMD_NONE && (ctrl & NAND_NCE) && |
---|
561 | | - !(ctrl & (NAND_CLE | NAND_ALE))) { |
---|
562 | | - u32 cmd = 0; |
---|
563 | | - |
---|
564 | | - if (!sunxi_nand->addr_cycles && !sunxi_nand->cmd_cycles) |
---|
565 | | - return; |
---|
566 | | - |
---|
567 | | - if (sunxi_nand->cmd_cycles--) |
---|
568 | | - cmd |= NFC_SEND_CMD1 | sunxi_nand->cmd[0]; |
---|
569 | | - |
---|
570 | | - if (sunxi_nand->cmd_cycles--) { |
---|
571 | | - cmd |= NFC_SEND_CMD2; |
---|
572 | | - writel(sunxi_nand->cmd[1], |
---|
573 | | - nfc->regs + NFC_REG_RCMD_SET); |
---|
574 | | - } |
---|
575 | | - |
---|
576 | | - sunxi_nand->cmd_cycles = 0; |
---|
577 | | - |
---|
578 | | - if (sunxi_nand->addr_cycles) { |
---|
579 | | - cmd |= NFC_SEND_ADR | |
---|
580 | | - NFC_ADR_NUM(sunxi_nand->addr_cycles); |
---|
581 | | - writel(sunxi_nand->addr[0], |
---|
582 | | - nfc->regs + NFC_REG_ADDR_LOW); |
---|
583 | | - } |
---|
584 | | - |
---|
585 | | - if (sunxi_nand->addr_cycles > 4) |
---|
586 | | - writel(sunxi_nand->addr[1], |
---|
587 | | - nfc->regs + NFC_REG_ADDR_HIGH); |
---|
588 | | - |
---|
589 | | - ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); |
---|
590 | | - if (ret) |
---|
591 | | - return; |
---|
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_events(nfc, NFC_CMD_INT_FLAG, true, 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 | 507 | } |
---|
607 | 508 | } |
---|
608 | 509 | |
---|
.. | .. |
---|
688 | 589 | return state; |
---|
689 | 590 | } |
---|
690 | 591 | |
---|
691 | | -static u16 sunxi_nfc_randomizer_state(struct mtd_info *mtd, int page, bool ecc) |
---|
| 592 | +static u16 sunxi_nfc_randomizer_state(struct nand_chip *nand, int page, |
---|
| 593 | + bool ecc) |
---|
692 | 594 | { |
---|
| 595 | + struct mtd_info *mtd = nand_to_mtd(nand); |
---|
693 | 596 | const u16 *seeds = sunxi_nfc_randomizer_page_seeds; |
---|
694 | 597 | int mod = mtd_div_by_ws(mtd->erasesize, mtd); |
---|
695 | 598 | |
---|
.. | .. |
---|
706 | 609 | return seeds[page % mod]; |
---|
707 | 610 | } |
---|
708 | 611 | |
---|
709 | | -static void sunxi_nfc_randomizer_config(struct mtd_info *mtd, |
---|
710 | | - int page, bool ecc) |
---|
| 612 | +static void sunxi_nfc_randomizer_config(struct nand_chip *nand, int page, |
---|
| 613 | + bool ecc) |
---|
711 | 614 | { |
---|
712 | | - struct nand_chip *nand = mtd_to_nand(mtd); |
---|
713 | 615 | struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); |
---|
714 | 616 | u32 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL); |
---|
715 | 617 | u16 state; |
---|
.. | .. |
---|
718 | 620 | return; |
---|
719 | 621 | |
---|
720 | 622 | ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL); |
---|
721 | | - state = sunxi_nfc_randomizer_state(mtd, page, ecc); |
---|
| 623 | + state = sunxi_nfc_randomizer_state(nand, page, ecc); |
---|
722 | 624 | ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_SEED_MSK; |
---|
723 | 625 | writel(ecc_ctl | NFC_RANDOM_SEED(state), nfc->regs + NFC_REG_ECC_CTL); |
---|
724 | 626 | } |
---|
725 | 627 | |
---|
726 | | -static void sunxi_nfc_randomizer_enable(struct mtd_info *mtd) |
---|
| 628 | +static void sunxi_nfc_randomizer_enable(struct nand_chip *nand) |
---|
727 | 629 | { |
---|
728 | | - struct nand_chip *nand = mtd_to_nand(mtd); |
---|
729 | 630 | struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); |
---|
730 | 631 | |
---|
731 | 632 | if (!(nand->options & NAND_NEED_SCRAMBLING)) |
---|
.. | .. |
---|
735 | 636 | nfc->regs + NFC_REG_ECC_CTL); |
---|
736 | 637 | } |
---|
737 | 638 | |
---|
738 | | -static void sunxi_nfc_randomizer_disable(struct mtd_info *mtd) |
---|
| 639 | +static void sunxi_nfc_randomizer_disable(struct nand_chip *nand) |
---|
739 | 640 | { |
---|
740 | | - struct nand_chip *nand = mtd_to_nand(mtd); |
---|
741 | 641 | struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); |
---|
742 | 642 | |
---|
743 | 643 | if (!(nand->options & NAND_NEED_SCRAMBLING)) |
---|
.. | .. |
---|
747 | 647 | nfc->regs + NFC_REG_ECC_CTL); |
---|
748 | 648 | } |
---|
749 | 649 | |
---|
750 | | -static void sunxi_nfc_randomize_bbm(struct mtd_info *mtd, int page, u8 *bbm) |
---|
| 650 | +static void sunxi_nfc_randomize_bbm(struct nand_chip *nand, int page, u8 *bbm) |
---|
751 | 651 | { |
---|
752 | | - u16 state = sunxi_nfc_randomizer_state(mtd, page, true); |
---|
| 652 | + u16 state = sunxi_nfc_randomizer_state(nand, page, true); |
---|
753 | 653 | |
---|
754 | 654 | bbm[0] ^= state; |
---|
755 | 655 | bbm[1] ^= sunxi_nfc_randomizer_step(state, 8); |
---|
756 | 656 | } |
---|
757 | 657 | |
---|
758 | | -static void sunxi_nfc_randomizer_write_buf(struct mtd_info *mtd, |
---|
| 658 | +static void sunxi_nfc_randomizer_write_buf(struct nand_chip *nand, |
---|
759 | 659 | const uint8_t *buf, int len, |
---|
760 | 660 | bool ecc, int page) |
---|
761 | 661 | { |
---|
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); |
---|
| 662 | + sunxi_nfc_randomizer_config(nand, page, ecc); |
---|
| 663 | + sunxi_nfc_randomizer_enable(nand); |
---|
| 664 | + sunxi_nfc_write_buf(nand, buf, len); |
---|
| 665 | + sunxi_nfc_randomizer_disable(nand); |
---|
766 | 666 | } |
---|
767 | 667 | |
---|
768 | | -static void sunxi_nfc_randomizer_read_buf(struct mtd_info *mtd, uint8_t *buf, |
---|
| 668 | +static void sunxi_nfc_randomizer_read_buf(struct nand_chip *nand, uint8_t *buf, |
---|
769 | 669 | int len, bool ecc, int page) |
---|
770 | 670 | { |
---|
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); |
---|
| 671 | + sunxi_nfc_randomizer_config(nand, page, ecc); |
---|
| 672 | + sunxi_nfc_randomizer_enable(nand); |
---|
| 673 | + sunxi_nfc_read_buf(nand, buf, len); |
---|
| 674 | + sunxi_nfc_randomizer_disable(nand); |
---|
775 | 675 | } |
---|
776 | 676 | |
---|
777 | | -static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd) |
---|
| 677 | +static void sunxi_nfc_hw_ecc_enable(struct nand_chip *nand) |
---|
778 | 678 | { |
---|
779 | | - struct nand_chip *nand = mtd_to_nand(mtd); |
---|
780 | 679 | struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); |
---|
781 | 680 | struct sunxi_nand_hw_ecc *data = nand->ecc.priv; |
---|
782 | 681 | u32 ecc_ctl; |
---|
.. | .. |
---|
793 | 692 | writel(ecc_ctl, nfc->regs + NFC_REG_ECC_CTL); |
---|
794 | 693 | } |
---|
795 | 694 | |
---|
796 | | -static void sunxi_nfc_hw_ecc_disable(struct mtd_info *mtd) |
---|
| 695 | +static void sunxi_nfc_hw_ecc_disable(struct nand_chip *nand) |
---|
797 | 696 | { |
---|
798 | | - struct nand_chip *nand = mtd_to_nand(mtd); |
---|
799 | 697 | struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); |
---|
800 | 698 | |
---|
801 | 699 | writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN, |
---|
.. | .. |
---|
815 | 713 | return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); |
---|
816 | 714 | } |
---|
817 | 715 | |
---|
818 | | -static void sunxi_nfc_hw_ecc_get_prot_oob_bytes(struct mtd_info *mtd, u8 *oob, |
---|
| 716 | +static void sunxi_nfc_hw_ecc_get_prot_oob_bytes(struct nand_chip *nand, u8 *oob, |
---|
819 | 717 | int step, bool bbm, int page) |
---|
820 | 718 | { |
---|
821 | | - struct nand_chip *nand = mtd_to_nand(mtd); |
---|
822 | 719 | struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); |
---|
823 | 720 | |
---|
824 | 721 | sunxi_nfc_user_data_to_buf(readl(nfc->regs + NFC_REG_USER_DATA(step)), |
---|
.. | .. |
---|
826 | 723 | |
---|
827 | 724 | /* De-randomize the Bad Block Marker. */ |
---|
828 | 725 | if (bbm && (nand->options & NAND_NEED_SCRAMBLING)) |
---|
829 | | - sunxi_nfc_randomize_bbm(mtd, page, oob); |
---|
| 726 | + sunxi_nfc_randomize_bbm(nand, page, oob); |
---|
830 | 727 | } |
---|
831 | 728 | |
---|
832 | | -static void sunxi_nfc_hw_ecc_set_prot_oob_bytes(struct mtd_info *mtd, |
---|
| 729 | +static void sunxi_nfc_hw_ecc_set_prot_oob_bytes(struct nand_chip *nand, |
---|
833 | 730 | const u8 *oob, int step, |
---|
834 | 731 | bool bbm, int page) |
---|
835 | 732 | { |
---|
836 | | - struct nand_chip *nand = mtd_to_nand(mtd); |
---|
837 | 733 | struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); |
---|
838 | 734 | u8 user_data[4]; |
---|
839 | 735 | |
---|
840 | 736 | /* Randomize the Bad Block Marker. */ |
---|
841 | 737 | if (bbm && (nand->options & NAND_NEED_SCRAMBLING)) { |
---|
842 | 738 | memcpy(user_data, oob, sizeof(user_data)); |
---|
843 | | - sunxi_nfc_randomize_bbm(mtd, page, user_data); |
---|
| 739 | + sunxi_nfc_randomize_bbm(nand, page, user_data); |
---|
844 | 740 | oob = user_data; |
---|
845 | 741 | } |
---|
846 | 742 | |
---|
.. | .. |
---|
848 | 744 | nfc->regs + NFC_REG_USER_DATA(step)); |
---|
849 | 745 | } |
---|
850 | 746 | |
---|
851 | | -static void sunxi_nfc_hw_ecc_update_stats(struct mtd_info *mtd, |
---|
| 747 | +static void sunxi_nfc_hw_ecc_update_stats(struct nand_chip *nand, |
---|
852 | 748 | unsigned int *max_bitflips, int ret) |
---|
853 | 749 | { |
---|
| 750 | + struct mtd_info *mtd = nand_to_mtd(nand); |
---|
| 751 | + |
---|
854 | 752 | if (ret < 0) { |
---|
855 | 753 | mtd->ecc_stats.failed++; |
---|
856 | 754 | } else { |
---|
.. | .. |
---|
859 | 757 | } |
---|
860 | 758 | } |
---|
861 | 759 | |
---|
862 | | -static int sunxi_nfc_hw_ecc_correct(struct mtd_info *mtd, u8 *data, u8 *oob, |
---|
| 760 | +static int sunxi_nfc_hw_ecc_correct(struct nand_chip *nand, u8 *data, u8 *oob, |
---|
863 | 761 | int step, u32 status, bool *erased) |
---|
864 | 762 | { |
---|
865 | | - struct nand_chip *nand = mtd_to_nand(mtd); |
---|
866 | 763 | struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); |
---|
867 | 764 | struct nand_ecc_ctrl *ecc = &nand->ecc; |
---|
868 | 765 | u32 tmp; |
---|
.. | .. |
---|
896 | 793 | return NFC_ECC_ERR_CNT(step, tmp); |
---|
897 | 794 | } |
---|
898 | 795 | |
---|
899 | | -static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd, |
---|
| 796 | +static int sunxi_nfc_hw_ecc_read_chunk(struct nand_chip *nand, |
---|
900 | 797 | u8 *data, int data_off, |
---|
901 | 798 | u8 *oob, int oob_off, |
---|
902 | 799 | int *cur_off, |
---|
903 | 800 | unsigned int *max_bitflips, |
---|
904 | 801 | bool bbm, bool oob_required, int page) |
---|
905 | 802 | { |
---|
906 | | - struct nand_chip *nand = mtd_to_nand(mtd); |
---|
907 | 803 | struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); |
---|
908 | 804 | struct nand_ecc_ctrl *ecc = &nand->ecc; |
---|
909 | 805 | int raw_mode = 0; |
---|
.. | .. |
---|
913 | 809 | if (*cur_off != data_off) |
---|
914 | 810 | nand_change_read_column_op(nand, data_off, NULL, 0, false); |
---|
915 | 811 | |
---|
916 | | - sunxi_nfc_randomizer_read_buf(mtd, NULL, ecc->size, false, page); |
---|
| 812 | + sunxi_nfc_randomizer_read_buf(nand, NULL, ecc->size, false, page); |
---|
917 | 813 | |
---|
918 | 814 | if (data_off + ecc->size != oob_off) |
---|
919 | 815 | nand_change_read_column_op(nand, oob_off, NULL, 0, false); |
---|
.. | .. |
---|
922 | 818 | if (ret) |
---|
923 | 819 | return ret; |
---|
924 | 820 | |
---|
925 | | - sunxi_nfc_randomizer_enable(mtd); |
---|
| 821 | + sunxi_nfc_randomizer_enable(nand); |
---|
926 | 822 | writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP, |
---|
927 | 823 | nfc->regs + NFC_REG_CMD); |
---|
928 | 824 | |
---|
929 | 825 | ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0); |
---|
930 | | - sunxi_nfc_randomizer_disable(mtd); |
---|
| 826 | + sunxi_nfc_randomizer_disable(nand); |
---|
931 | 827 | if (ret) |
---|
932 | 828 | return ret; |
---|
933 | 829 | |
---|
934 | 830 | *cur_off = oob_off + ecc->bytes + 4; |
---|
935 | 831 | |
---|
936 | | - ret = sunxi_nfc_hw_ecc_correct(mtd, data, oob_required ? oob : NULL, 0, |
---|
| 832 | + ret = sunxi_nfc_hw_ecc_correct(nand, data, oob_required ? oob : NULL, 0, |
---|
937 | 833 | readl(nfc->regs + NFC_REG_ECC_ST), |
---|
938 | 834 | &erased); |
---|
939 | 835 | if (erased) |
---|
.. | .. |
---|
965 | 861 | if (oob_required) { |
---|
966 | 862 | nand_change_read_column_op(nand, oob_off, NULL, 0, |
---|
967 | 863 | false); |
---|
968 | | - sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4, |
---|
| 864 | + sunxi_nfc_randomizer_read_buf(nand, oob, ecc->bytes + 4, |
---|
969 | 865 | true, page); |
---|
970 | 866 | |
---|
971 | | - sunxi_nfc_hw_ecc_get_prot_oob_bytes(mtd, oob, 0, |
---|
| 867 | + sunxi_nfc_hw_ecc_get_prot_oob_bytes(nand, oob, 0, |
---|
972 | 868 | bbm, page); |
---|
973 | 869 | } |
---|
974 | 870 | } |
---|
975 | 871 | |
---|
976 | | - sunxi_nfc_hw_ecc_update_stats(mtd, max_bitflips, ret); |
---|
| 872 | + sunxi_nfc_hw_ecc_update_stats(nand, max_bitflips, ret); |
---|
977 | 873 | |
---|
978 | 874 | return raw_mode; |
---|
979 | 875 | } |
---|
980 | 876 | |
---|
981 | | -static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd, |
---|
| 877 | +static void sunxi_nfc_hw_ecc_read_extra_oob(struct nand_chip *nand, |
---|
982 | 878 | u8 *oob, int *cur_off, |
---|
983 | 879 | bool randomize, int page) |
---|
984 | 880 | { |
---|
985 | | - struct nand_chip *nand = mtd_to_nand(mtd); |
---|
| 881 | + struct mtd_info *mtd = nand_to_mtd(nand); |
---|
986 | 882 | struct nand_ecc_ctrl *ecc = &nand->ecc; |
---|
987 | 883 | int offset = ((ecc->bytes + 4) * ecc->steps); |
---|
988 | 884 | int len = mtd->oobsize - offset; |
---|
.. | .. |
---|
995 | 891 | false); |
---|
996 | 892 | |
---|
997 | 893 | if (!randomize) |
---|
998 | | - sunxi_nfc_read_buf(mtd, oob + offset, len); |
---|
| 894 | + sunxi_nfc_read_buf(nand, oob + offset, len); |
---|
999 | 895 | else |
---|
1000 | | - sunxi_nfc_randomizer_read_buf(mtd, oob + offset, len, |
---|
| 896 | + sunxi_nfc_randomizer_read_buf(nand, oob + offset, len, |
---|
1001 | 897 | false, page); |
---|
1002 | 898 | |
---|
1003 | 899 | if (cur_off) |
---|
1004 | 900 | *cur_off = mtd->oobsize + mtd->writesize; |
---|
1005 | 901 | } |
---|
1006 | 902 | |
---|
1007 | | -static int sunxi_nfc_hw_ecc_read_chunks_dma(struct mtd_info *mtd, uint8_t *buf, |
---|
| 903 | +static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *buf, |
---|
1008 | 904 | int oob_required, int page, |
---|
1009 | 905 | int nchunks) |
---|
1010 | 906 | { |
---|
1011 | | - struct nand_chip *nand = mtd_to_nand(mtd); |
---|
1012 | 907 | bool randomized = nand->options & NAND_NEED_SCRAMBLING; |
---|
1013 | 908 | struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); |
---|
| 909 | + struct mtd_info *mtd = nand_to_mtd(nand); |
---|
1014 | 910 | struct nand_ecc_ctrl *ecc = &nand->ecc; |
---|
1015 | 911 | unsigned int max_bitflips = 0; |
---|
1016 | 912 | int ret, i, raw_mode = 0; |
---|
.. | .. |
---|
1021 | 917 | if (ret) |
---|
1022 | 918 | return ret; |
---|
1023 | 919 | |
---|
1024 | | - ret = sunxi_nfc_dma_op_prepare(mtd, buf, ecc->size, nchunks, |
---|
| 920 | + ret = sunxi_nfc_dma_op_prepare(nfc, buf, ecc->size, nchunks, |
---|
1025 | 921 | DMA_FROM_DEVICE, &sg); |
---|
1026 | 922 | if (ret) |
---|
1027 | 923 | return ret; |
---|
1028 | 924 | |
---|
1029 | | - sunxi_nfc_hw_ecc_enable(mtd); |
---|
1030 | | - sunxi_nfc_randomizer_config(mtd, page, false); |
---|
1031 | | - sunxi_nfc_randomizer_enable(mtd); |
---|
| 925 | + sunxi_nfc_hw_ecc_enable(nand); |
---|
| 926 | + sunxi_nfc_randomizer_config(nand, page, false); |
---|
| 927 | + sunxi_nfc_randomizer_enable(nand); |
---|
1032 | 928 | |
---|
1033 | 929 | writel((NAND_CMD_RNDOUTSTART << 16) | (NAND_CMD_RNDOUT << 8) | |
---|
1034 | 930 | NAND_CMD_READSTART, nfc->regs + NFC_REG_RCMD_SET); |
---|
.. | .. |
---|
1042 | 938 | if (ret) |
---|
1043 | 939 | dmaengine_terminate_all(nfc->dmac); |
---|
1044 | 940 | |
---|
1045 | | - sunxi_nfc_randomizer_disable(mtd); |
---|
1046 | | - sunxi_nfc_hw_ecc_disable(mtd); |
---|
| 941 | + sunxi_nfc_randomizer_disable(nand); |
---|
| 942 | + sunxi_nfc_hw_ecc_disable(nand); |
---|
1047 | 943 | |
---|
1048 | | - sunxi_nfc_dma_op_cleanup(mtd, DMA_FROM_DEVICE, &sg); |
---|
| 944 | + sunxi_nfc_dma_op_cleanup(nfc, DMA_FROM_DEVICE, &sg); |
---|
1049 | 945 | |
---|
1050 | 946 | if (ret) |
---|
1051 | 947 | return ret; |
---|
.. | .. |
---|
1059 | 955 | u8 *oob = nand->oob_poi + oob_off; |
---|
1060 | 956 | bool erased; |
---|
1061 | 957 | |
---|
1062 | | - ret = sunxi_nfc_hw_ecc_correct(mtd, randomized ? data : NULL, |
---|
| 958 | + ret = sunxi_nfc_hw_ecc_correct(nand, randomized ? data : NULL, |
---|
1063 | 959 | oob_required ? oob : NULL, |
---|
1064 | 960 | i, status, &erased); |
---|
1065 | 961 | |
---|
.. | .. |
---|
1073 | 969 | mtd->writesize + oob_off, |
---|
1074 | 970 | oob, ecc->bytes + 4, false); |
---|
1075 | 971 | |
---|
1076 | | - sunxi_nfc_hw_ecc_get_prot_oob_bytes(mtd, oob, i, |
---|
| 972 | + sunxi_nfc_hw_ecc_get_prot_oob_bytes(nand, oob, i, |
---|
1077 | 973 | !i, page); |
---|
1078 | 974 | } |
---|
1079 | 975 | |
---|
1080 | 976 | if (erased) |
---|
1081 | 977 | raw_mode = 1; |
---|
1082 | 978 | |
---|
1083 | | - sunxi_nfc_hw_ecc_update_stats(mtd, &max_bitflips, ret); |
---|
| 979 | + sunxi_nfc_hw_ecc_update_stats(nand, &max_bitflips, ret); |
---|
1084 | 980 | } |
---|
1085 | 981 | |
---|
1086 | 982 | if (status & NFC_ECC_ERR_MSK) { |
---|
.. | .. |
---|
1115 | 1011 | if (ret >= 0) |
---|
1116 | 1012 | raw_mode = 1; |
---|
1117 | 1013 | |
---|
1118 | | - sunxi_nfc_hw_ecc_update_stats(mtd, &max_bitflips, ret); |
---|
| 1014 | + sunxi_nfc_hw_ecc_update_stats(nand, &max_bitflips, ret); |
---|
1119 | 1015 | } |
---|
1120 | 1016 | } |
---|
1121 | 1017 | |
---|
1122 | 1018 | if (oob_required) |
---|
1123 | | - sunxi_nfc_hw_ecc_read_extra_oob(mtd, nand->oob_poi, |
---|
| 1019 | + sunxi_nfc_hw_ecc_read_extra_oob(nand, nand->oob_poi, |
---|
1124 | 1020 | NULL, !raw_mode, |
---|
1125 | 1021 | page); |
---|
1126 | 1022 | |
---|
1127 | 1023 | return max_bitflips; |
---|
1128 | 1024 | } |
---|
1129 | 1025 | |
---|
1130 | | -static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd, |
---|
| 1026 | +static int sunxi_nfc_hw_ecc_write_chunk(struct nand_chip *nand, |
---|
1131 | 1027 | const u8 *data, int data_off, |
---|
1132 | 1028 | const u8 *oob, int oob_off, |
---|
1133 | 1029 | int *cur_off, bool bbm, |
---|
1134 | 1030 | int page) |
---|
1135 | 1031 | { |
---|
1136 | | - struct nand_chip *nand = mtd_to_nand(mtd); |
---|
1137 | 1032 | struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); |
---|
1138 | 1033 | struct nand_ecc_ctrl *ecc = &nand->ecc; |
---|
1139 | 1034 | int ret; |
---|
.. | .. |
---|
1141 | 1036 | if (data_off != *cur_off) |
---|
1142 | 1037 | nand_change_write_column_op(nand, data_off, NULL, 0, false); |
---|
1143 | 1038 | |
---|
1144 | | - sunxi_nfc_randomizer_write_buf(mtd, data, ecc->size, false, page); |
---|
| 1039 | + sunxi_nfc_randomizer_write_buf(nand, data, ecc->size, false, page); |
---|
1145 | 1040 | |
---|
1146 | 1041 | if (data_off + ecc->size != oob_off) |
---|
1147 | 1042 | nand_change_write_column_op(nand, oob_off, NULL, 0, false); |
---|
.. | .. |
---|
1150 | 1045 | if (ret) |
---|
1151 | 1046 | return ret; |
---|
1152 | 1047 | |
---|
1153 | | - sunxi_nfc_randomizer_enable(mtd); |
---|
1154 | | - sunxi_nfc_hw_ecc_set_prot_oob_bytes(mtd, oob, 0, bbm, page); |
---|
| 1048 | + sunxi_nfc_randomizer_enable(nand); |
---|
| 1049 | + sunxi_nfc_hw_ecc_set_prot_oob_bytes(nand, oob, 0, bbm, page); |
---|
1155 | 1050 | |
---|
1156 | 1051 | writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | |
---|
1157 | 1052 | NFC_ACCESS_DIR | NFC_ECC_OP, |
---|
1158 | 1053 | nfc->regs + NFC_REG_CMD); |
---|
1159 | 1054 | |
---|
1160 | 1055 | ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0); |
---|
1161 | | - sunxi_nfc_randomizer_disable(mtd); |
---|
| 1056 | + sunxi_nfc_randomizer_disable(nand); |
---|
1162 | 1057 | if (ret) |
---|
1163 | 1058 | return ret; |
---|
1164 | 1059 | |
---|
.. | .. |
---|
1167 | 1062 | return 0; |
---|
1168 | 1063 | } |
---|
1169 | 1064 | |
---|
1170 | | -static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd, |
---|
| 1065 | +static void sunxi_nfc_hw_ecc_write_extra_oob(struct nand_chip *nand, |
---|
1171 | 1066 | u8 *oob, int *cur_off, |
---|
1172 | 1067 | int page) |
---|
1173 | 1068 | { |
---|
1174 | | - struct nand_chip *nand = mtd_to_nand(mtd); |
---|
| 1069 | + struct mtd_info *mtd = nand_to_mtd(nand); |
---|
1175 | 1070 | struct nand_ecc_ctrl *ecc = &nand->ecc; |
---|
1176 | 1071 | int offset = ((ecc->bytes + 4) * ecc->steps); |
---|
1177 | 1072 | int len = mtd->oobsize - offset; |
---|
.. | .. |
---|
1183 | 1078 | nand_change_write_column_op(nand, offset + mtd->writesize, |
---|
1184 | 1079 | NULL, 0, false); |
---|
1185 | 1080 | |
---|
1186 | | - sunxi_nfc_randomizer_write_buf(mtd, oob + offset, len, false, page); |
---|
| 1081 | + sunxi_nfc_randomizer_write_buf(nand, oob + offset, len, false, page); |
---|
1187 | 1082 | |
---|
1188 | 1083 | if (cur_off) |
---|
1189 | 1084 | *cur_off = mtd->oobsize + mtd->writesize; |
---|
1190 | 1085 | } |
---|
1191 | 1086 | |
---|
1192 | | -static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd, |
---|
1193 | | - struct nand_chip *chip, uint8_t *buf, |
---|
| 1087 | +static int sunxi_nfc_hw_ecc_read_page(struct nand_chip *nand, uint8_t *buf, |
---|
1194 | 1088 | int oob_required, int page) |
---|
1195 | 1089 | { |
---|
1196 | | - struct nand_ecc_ctrl *ecc = &chip->ecc; |
---|
| 1090 | + struct mtd_info *mtd = nand_to_mtd(nand); |
---|
| 1091 | + struct nand_ecc_ctrl *ecc = &nand->ecc; |
---|
1197 | 1092 | unsigned int max_bitflips = 0; |
---|
1198 | 1093 | int ret, i, cur_off = 0; |
---|
1199 | 1094 | bool raw_mode = false; |
---|
1200 | 1095 | |
---|
1201 | | - nand_read_page_op(chip, page, 0, NULL, 0); |
---|
| 1096 | + sunxi_nfc_select_chip(nand, nand->cur_cs); |
---|
1202 | 1097 | |
---|
1203 | | - sunxi_nfc_hw_ecc_enable(mtd); |
---|
| 1098 | + nand_read_page_op(nand, page, 0, NULL, 0); |
---|
| 1099 | + |
---|
| 1100 | + sunxi_nfc_hw_ecc_enable(nand); |
---|
1204 | 1101 | |
---|
1205 | 1102 | for (i = 0; i < ecc->steps; i++) { |
---|
1206 | 1103 | int data_off = i * ecc->size; |
---|
1207 | 1104 | int oob_off = i * (ecc->bytes + 4); |
---|
1208 | 1105 | u8 *data = buf + data_off; |
---|
1209 | | - u8 *oob = chip->oob_poi + oob_off; |
---|
| 1106 | + u8 *oob = nand->oob_poi + oob_off; |
---|
1210 | 1107 | |
---|
1211 | | - ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob, |
---|
| 1108 | + ret = sunxi_nfc_hw_ecc_read_chunk(nand, data, data_off, oob, |
---|
1212 | 1109 | oob_off + mtd->writesize, |
---|
1213 | 1110 | &cur_off, &max_bitflips, |
---|
1214 | 1111 | !i, oob_required, page); |
---|
.. | .. |
---|
1219 | 1116 | } |
---|
1220 | 1117 | |
---|
1221 | 1118 | if (oob_required) |
---|
1222 | | - sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off, |
---|
| 1119 | + sunxi_nfc_hw_ecc_read_extra_oob(nand, nand->oob_poi, &cur_off, |
---|
1223 | 1120 | !raw_mode, page); |
---|
1224 | 1121 | |
---|
1225 | | - sunxi_nfc_hw_ecc_disable(mtd); |
---|
| 1122 | + sunxi_nfc_hw_ecc_disable(nand); |
---|
1226 | 1123 | |
---|
1227 | 1124 | return max_bitflips; |
---|
1228 | 1125 | } |
---|
1229 | 1126 | |
---|
1230 | | -static int sunxi_nfc_hw_ecc_read_page_dma(struct mtd_info *mtd, |
---|
1231 | | - struct nand_chip *chip, u8 *buf, |
---|
| 1127 | +static int sunxi_nfc_hw_ecc_read_page_dma(struct nand_chip *nand, u8 *buf, |
---|
1232 | 1128 | int oob_required, int page) |
---|
1233 | 1129 | { |
---|
1234 | 1130 | int ret; |
---|
1235 | 1131 | |
---|
1236 | | - nand_read_page_op(chip, page, 0, NULL, 0); |
---|
| 1132 | + sunxi_nfc_select_chip(nand, nand->cur_cs); |
---|
1237 | 1133 | |
---|
1238 | | - ret = sunxi_nfc_hw_ecc_read_chunks_dma(mtd, buf, oob_required, page, |
---|
1239 | | - chip->ecc.steps); |
---|
| 1134 | + nand_read_page_op(nand, page, 0, NULL, 0); |
---|
| 1135 | + |
---|
| 1136 | + ret = sunxi_nfc_hw_ecc_read_chunks_dma(nand, buf, oob_required, page, |
---|
| 1137 | + nand->ecc.steps); |
---|
1240 | 1138 | if (ret >= 0) |
---|
1241 | 1139 | return ret; |
---|
1242 | 1140 | |
---|
1243 | 1141 | /* Fallback to PIO mode */ |
---|
1244 | | - return sunxi_nfc_hw_ecc_read_page(mtd, chip, buf, oob_required, page); |
---|
| 1142 | + return sunxi_nfc_hw_ecc_read_page(nand, buf, oob_required, page); |
---|
1245 | 1143 | } |
---|
1246 | 1144 | |
---|
1247 | | -static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd, |
---|
1248 | | - struct nand_chip *chip, |
---|
| 1145 | +static int sunxi_nfc_hw_ecc_read_subpage(struct nand_chip *nand, |
---|
1249 | 1146 | u32 data_offs, u32 readlen, |
---|
1250 | 1147 | u8 *bufpoi, int page) |
---|
1251 | 1148 | { |
---|
1252 | | - struct nand_ecc_ctrl *ecc = &chip->ecc; |
---|
| 1149 | + struct mtd_info *mtd = nand_to_mtd(nand); |
---|
| 1150 | + struct nand_ecc_ctrl *ecc = &nand->ecc; |
---|
1253 | 1151 | int ret, i, cur_off = 0; |
---|
1254 | 1152 | unsigned int max_bitflips = 0; |
---|
1255 | 1153 | |
---|
1256 | | - nand_read_page_op(chip, page, 0, NULL, 0); |
---|
| 1154 | + sunxi_nfc_select_chip(nand, nand->cur_cs); |
---|
1257 | 1155 | |
---|
1258 | | - sunxi_nfc_hw_ecc_enable(mtd); |
---|
| 1156 | + nand_read_page_op(nand, page, 0, NULL, 0); |
---|
| 1157 | + |
---|
| 1158 | + sunxi_nfc_hw_ecc_enable(nand); |
---|
1259 | 1159 | |
---|
1260 | 1160 | for (i = data_offs / ecc->size; |
---|
1261 | 1161 | i < DIV_ROUND_UP(data_offs + readlen, ecc->size); i++) { |
---|
1262 | 1162 | int data_off = i * ecc->size; |
---|
1263 | 1163 | int oob_off = i * (ecc->bytes + 4); |
---|
1264 | 1164 | u8 *data = bufpoi + data_off; |
---|
1265 | | - u8 *oob = chip->oob_poi + oob_off; |
---|
| 1165 | + u8 *oob = nand->oob_poi + oob_off; |
---|
1266 | 1166 | |
---|
1267 | | - ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, |
---|
| 1167 | + ret = sunxi_nfc_hw_ecc_read_chunk(nand, data, data_off, |
---|
1268 | 1168 | oob, |
---|
1269 | 1169 | oob_off + mtd->writesize, |
---|
1270 | 1170 | &cur_off, &max_bitflips, !i, |
---|
.. | .. |
---|
1273 | 1173 | return ret; |
---|
1274 | 1174 | } |
---|
1275 | 1175 | |
---|
1276 | | - sunxi_nfc_hw_ecc_disable(mtd); |
---|
| 1176 | + sunxi_nfc_hw_ecc_disable(nand); |
---|
1277 | 1177 | |
---|
1278 | 1178 | return max_bitflips; |
---|
1279 | 1179 | } |
---|
1280 | 1180 | |
---|
1281 | | -static int sunxi_nfc_hw_ecc_read_subpage_dma(struct mtd_info *mtd, |
---|
1282 | | - struct nand_chip *chip, |
---|
| 1181 | +static int sunxi_nfc_hw_ecc_read_subpage_dma(struct nand_chip *nand, |
---|
1283 | 1182 | u32 data_offs, u32 readlen, |
---|
1284 | 1183 | u8 *buf, int page) |
---|
1285 | 1184 | { |
---|
1286 | | - int nchunks = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size); |
---|
| 1185 | + int nchunks = DIV_ROUND_UP(data_offs + readlen, nand->ecc.size); |
---|
1287 | 1186 | int ret; |
---|
1288 | 1187 | |
---|
1289 | | - nand_read_page_op(chip, page, 0, NULL, 0); |
---|
| 1188 | + sunxi_nfc_select_chip(nand, nand->cur_cs); |
---|
1290 | 1189 | |
---|
1291 | | - ret = sunxi_nfc_hw_ecc_read_chunks_dma(mtd, buf, false, page, nchunks); |
---|
| 1190 | + nand_read_page_op(nand, page, 0, NULL, 0); |
---|
| 1191 | + |
---|
| 1192 | + ret = sunxi_nfc_hw_ecc_read_chunks_dma(nand, buf, false, page, nchunks); |
---|
1292 | 1193 | if (ret >= 0) |
---|
1293 | 1194 | return ret; |
---|
1294 | 1195 | |
---|
1295 | 1196 | /* Fallback to PIO mode */ |
---|
1296 | | - return sunxi_nfc_hw_ecc_read_subpage(mtd, chip, data_offs, readlen, |
---|
| 1197 | + return sunxi_nfc_hw_ecc_read_subpage(nand, data_offs, readlen, |
---|
1297 | 1198 | buf, page); |
---|
1298 | 1199 | } |
---|
1299 | 1200 | |
---|
1300 | | -static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd, |
---|
1301 | | - struct nand_chip *chip, |
---|
| 1201 | +static int sunxi_nfc_hw_ecc_write_page(struct nand_chip *nand, |
---|
1302 | 1202 | const uint8_t *buf, int oob_required, |
---|
1303 | 1203 | int page) |
---|
1304 | 1204 | { |
---|
1305 | | - struct nand_ecc_ctrl *ecc = &chip->ecc; |
---|
| 1205 | + struct mtd_info *mtd = nand_to_mtd(nand); |
---|
| 1206 | + struct nand_ecc_ctrl *ecc = &nand->ecc; |
---|
1306 | 1207 | int ret, i, cur_off = 0; |
---|
1307 | 1208 | |
---|
1308 | | - nand_prog_page_begin_op(chip, page, 0, NULL, 0); |
---|
| 1209 | + sunxi_nfc_select_chip(nand, nand->cur_cs); |
---|
1309 | 1210 | |
---|
1310 | | - sunxi_nfc_hw_ecc_enable(mtd); |
---|
| 1211 | + nand_prog_page_begin_op(nand, page, 0, NULL, 0); |
---|
| 1212 | + |
---|
| 1213 | + sunxi_nfc_hw_ecc_enable(nand); |
---|
1311 | 1214 | |
---|
1312 | 1215 | for (i = 0; i < ecc->steps; i++) { |
---|
1313 | 1216 | int data_off = i * ecc->size; |
---|
1314 | 1217 | int oob_off = i * (ecc->bytes + 4); |
---|
1315 | 1218 | const u8 *data = buf + data_off; |
---|
1316 | | - const u8 *oob = chip->oob_poi + oob_off; |
---|
| 1219 | + const u8 *oob = nand->oob_poi + oob_off; |
---|
1317 | 1220 | |
---|
1318 | | - ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob, |
---|
| 1221 | + ret = sunxi_nfc_hw_ecc_write_chunk(nand, data, data_off, oob, |
---|
1319 | 1222 | oob_off + mtd->writesize, |
---|
1320 | 1223 | &cur_off, !i, page); |
---|
1321 | 1224 | if (ret) |
---|
1322 | 1225 | return ret; |
---|
1323 | 1226 | } |
---|
1324 | 1227 | |
---|
1325 | | - if (oob_required || (chip->options & NAND_NEED_SCRAMBLING)) |
---|
1326 | | - sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi, |
---|
| 1228 | + if (oob_required || (nand->options & NAND_NEED_SCRAMBLING)) |
---|
| 1229 | + sunxi_nfc_hw_ecc_write_extra_oob(nand, nand->oob_poi, |
---|
1327 | 1230 | &cur_off, page); |
---|
1328 | 1231 | |
---|
1329 | | - sunxi_nfc_hw_ecc_disable(mtd); |
---|
| 1232 | + sunxi_nfc_hw_ecc_disable(nand); |
---|
1330 | 1233 | |
---|
1331 | | - return nand_prog_page_end_op(chip); |
---|
| 1234 | + return nand_prog_page_end_op(nand); |
---|
1332 | 1235 | } |
---|
1333 | 1236 | |
---|
1334 | | -static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd, |
---|
1335 | | - struct nand_chip *chip, |
---|
| 1237 | +static int sunxi_nfc_hw_ecc_write_subpage(struct nand_chip *nand, |
---|
1336 | 1238 | u32 data_offs, u32 data_len, |
---|
1337 | 1239 | const u8 *buf, int oob_required, |
---|
1338 | 1240 | int page) |
---|
1339 | 1241 | { |
---|
1340 | | - struct nand_ecc_ctrl *ecc = &chip->ecc; |
---|
| 1242 | + struct mtd_info *mtd = nand_to_mtd(nand); |
---|
| 1243 | + struct nand_ecc_ctrl *ecc = &nand->ecc; |
---|
1341 | 1244 | int ret, i, cur_off = 0; |
---|
1342 | 1245 | |
---|
1343 | | - nand_prog_page_begin_op(chip, page, 0, NULL, 0); |
---|
| 1246 | + sunxi_nfc_select_chip(nand, nand->cur_cs); |
---|
1344 | 1247 | |
---|
1345 | | - sunxi_nfc_hw_ecc_enable(mtd); |
---|
| 1248 | + nand_prog_page_begin_op(nand, page, 0, NULL, 0); |
---|
| 1249 | + |
---|
| 1250 | + sunxi_nfc_hw_ecc_enable(nand); |
---|
1346 | 1251 | |
---|
1347 | 1252 | for (i = data_offs / ecc->size; |
---|
1348 | 1253 | i < DIV_ROUND_UP(data_offs + data_len, ecc->size); i++) { |
---|
1349 | 1254 | int data_off = i * ecc->size; |
---|
1350 | 1255 | int oob_off = i * (ecc->bytes + 4); |
---|
1351 | 1256 | const u8 *data = buf + data_off; |
---|
1352 | | - const u8 *oob = chip->oob_poi + oob_off; |
---|
| 1257 | + const u8 *oob = nand->oob_poi + oob_off; |
---|
1353 | 1258 | |
---|
1354 | | - ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob, |
---|
| 1259 | + ret = sunxi_nfc_hw_ecc_write_chunk(nand, data, data_off, oob, |
---|
1355 | 1260 | oob_off + mtd->writesize, |
---|
1356 | 1261 | &cur_off, !i, page); |
---|
1357 | 1262 | if (ret) |
---|
1358 | 1263 | return ret; |
---|
1359 | 1264 | } |
---|
1360 | 1265 | |
---|
1361 | | - sunxi_nfc_hw_ecc_disable(mtd); |
---|
| 1266 | + sunxi_nfc_hw_ecc_disable(nand); |
---|
1362 | 1267 | |
---|
1363 | | - return nand_prog_page_end_op(chip); |
---|
| 1268 | + return nand_prog_page_end_op(nand); |
---|
1364 | 1269 | } |
---|
1365 | 1270 | |
---|
1366 | | -static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd, |
---|
1367 | | - struct nand_chip *chip, |
---|
| 1271 | +static int sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip *nand, |
---|
1368 | 1272 | const u8 *buf, |
---|
1369 | 1273 | int oob_required, |
---|
1370 | 1274 | int page) |
---|
1371 | 1275 | { |
---|
1372 | | - struct nand_chip *nand = mtd_to_nand(mtd); |
---|
1373 | 1276 | struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); |
---|
1374 | 1277 | struct nand_ecc_ctrl *ecc = &nand->ecc; |
---|
1375 | 1278 | struct scatterlist sg; |
---|
1376 | 1279 | int ret, i; |
---|
1377 | 1280 | |
---|
| 1281 | + sunxi_nfc_select_chip(nand, nand->cur_cs); |
---|
| 1282 | + |
---|
1378 | 1283 | ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); |
---|
1379 | 1284 | if (ret) |
---|
1380 | 1285 | return ret; |
---|
1381 | 1286 | |
---|
1382 | | - ret = sunxi_nfc_dma_op_prepare(mtd, buf, ecc->size, ecc->steps, |
---|
| 1287 | + ret = sunxi_nfc_dma_op_prepare(nfc, buf, ecc->size, ecc->steps, |
---|
1383 | 1288 | DMA_TO_DEVICE, &sg); |
---|
1384 | 1289 | if (ret) |
---|
1385 | 1290 | goto pio_fallback; |
---|
.. | .. |
---|
1387 | 1292 | for (i = 0; i < ecc->steps; i++) { |
---|
1388 | 1293 | const u8 *oob = nand->oob_poi + (i * (ecc->bytes + 4)); |
---|
1389 | 1294 | |
---|
1390 | | - sunxi_nfc_hw_ecc_set_prot_oob_bytes(mtd, oob, i, !i, page); |
---|
| 1295 | + sunxi_nfc_hw_ecc_set_prot_oob_bytes(nand, oob, i, !i, page); |
---|
1391 | 1296 | } |
---|
1392 | 1297 | |
---|
1393 | | - nand_prog_page_begin_op(chip, page, 0, NULL, 0); |
---|
| 1298 | + nand_prog_page_begin_op(nand, page, 0, NULL, 0); |
---|
1394 | 1299 | |
---|
1395 | | - sunxi_nfc_hw_ecc_enable(mtd); |
---|
1396 | | - sunxi_nfc_randomizer_config(mtd, page, false); |
---|
1397 | | - sunxi_nfc_randomizer_enable(mtd); |
---|
| 1300 | + sunxi_nfc_hw_ecc_enable(nand); |
---|
| 1301 | + sunxi_nfc_randomizer_config(nand, page, false); |
---|
| 1302 | + sunxi_nfc_randomizer_enable(nand); |
---|
1398 | 1303 | |
---|
1399 | 1304 | writel((NAND_CMD_RNDIN << 8) | NAND_CMD_PAGEPROG, |
---|
1400 | 1305 | nfc->regs + NFC_REG_WCMD_SET); |
---|
.. | .. |
---|
1409 | 1314 | if (ret) |
---|
1410 | 1315 | dmaengine_terminate_all(nfc->dmac); |
---|
1411 | 1316 | |
---|
1412 | | - sunxi_nfc_randomizer_disable(mtd); |
---|
1413 | | - sunxi_nfc_hw_ecc_disable(mtd); |
---|
| 1317 | + sunxi_nfc_randomizer_disable(nand); |
---|
| 1318 | + sunxi_nfc_hw_ecc_disable(nand); |
---|
1414 | 1319 | |
---|
1415 | | - sunxi_nfc_dma_op_cleanup(mtd, DMA_TO_DEVICE, &sg); |
---|
| 1320 | + sunxi_nfc_dma_op_cleanup(nfc, DMA_TO_DEVICE, &sg); |
---|
1416 | 1321 | |
---|
1417 | 1322 | if (ret) |
---|
1418 | 1323 | return ret; |
---|
1419 | 1324 | |
---|
1420 | | - if (oob_required || (chip->options & NAND_NEED_SCRAMBLING)) |
---|
| 1325 | + if (oob_required || (nand->options & NAND_NEED_SCRAMBLING)) |
---|
1421 | 1326 | /* TODO: use DMA to transfer extra OOB bytes ? */ |
---|
1422 | | - sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi, |
---|
| 1327 | + sunxi_nfc_hw_ecc_write_extra_oob(nand, nand->oob_poi, |
---|
1423 | 1328 | NULL, page); |
---|
1424 | 1329 | |
---|
1425 | | - return nand_prog_page_end_op(chip); |
---|
| 1330 | + return nand_prog_page_end_op(nand); |
---|
1426 | 1331 | |
---|
1427 | 1332 | pio_fallback: |
---|
1428 | | - return sunxi_nfc_hw_ecc_write_page(mtd, chip, buf, oob_required, page); |
---|
| 1333 | + return sunxi_nfc_hw_ecc_write_page(nand, buf, oob_required, page); |
---|
1429 | 1334 | } |
---|
1430 | 1335 | |
---|
1431 | | -static int sunxi_nfc_hw_ecc_read_oob(struct mtd_info *mtd, |
---|
1432 | | - struct nand_chip *chip, |
---|
1433 | | - int page) |
---|
| 1336 | +static int sunxi_nfc_hw_ecc_read_oob(struct nand_chip *nand, int page) |
---|
1434 | 1337 | { |
---|
1435 | | - chip->pagebuf = -1; |
---|
| 1338 | + u8 *buf = nand_get_data_buf(nand); |
---|
1436 | 1339 | |
---|
1437 | | - return chip->ecc.read_page(mtd, chip, chip->data_buf, 1, page); |
---|
| 1340 | + return nand->ecc.read_page(nand, buf, 1, page); |
---|
1438 | 1341 | } |
---|
1439 | 1342 | |
---|
1440 | | -static int sunxi_nfc_hw_ecc_write_oob(struct mtd_info *mtd, |
---|
1441 | | - struct nand_chip *chip, |
---|
1442 | | - int page) |
---|
| 1343 | +static int sunxi_nfc_hw_ecc_write_oob(struct nand_chip *nand, int page) |
---|
1443 | 1344 | { |
---|
| 1345 | + struct mtd_info *mtd = nand_to_mtd(nand); |
---|
| 1346 | + u8 *buf = nand_get_data_buf(nand); |
---|
1444 | 1347 | int ret; |
---|
1445 | 1348 | |
---|
1446 | | - chip->pagebuf = -1; |
---|
1447 | | - |
---|
1448 | | - memset(chip->data_buf, 0xff, mtd->writesize); |
---|
1449 | | - ret = chip->ecc.write_page(mtd, chip, chip->data_buf, 1, page); |
---|
| 1349 | + memset(buf, 0xff, mtd->writesize); |
---|
| 1350 | + ret = nand->ecc.write_page(nand, buf, 1, page); |
---|
1450 | 1351 | if (ret) |
---|
1451 | 1352 | return ret; |
---|
1452 | 1353 | |
---|
1453 | 1354 | /* Send command to program the OOB data */ |
---|
1454 | | - return nand_prog_page_end_op(chip); |
---|
| 1355 | + return nand_prog_page_end_op(nand); |
---|
1455 | 1356 | } |
---|
1456 | 1357 | |
---|
1457 | 1358 | static const s32 tWB_lut[] = {6, 12, 16, 20}; |
---|
.. | .. |
---|
1475 | 1376 | #define sunxi_nand_lookup_timing(l, p, c) \ |
---|
1476 | 1377 | _sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c) |
---|
1477 | 1378 | |
---|
1478 | | -static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd, int csline, |
---|
1479 | | - const struct nand_data_interface *conf) |
---|
| 1379 | +static int sunxi_nfc_setup_interface(struct nand_chip *nand, int csline, |
---|
| 1380 | + const struct nand_interface_config *conf) |
---|
1480 | 1381 | { |
---|
1481 | | - struct nand_chip *nand = mtd_to_nand(mtd); |
---|
1482 | | - struct sunxi_nand_chip *chip = to_sunxi_nand(nand); |
---|
1483 | | - struct sunxi_nfc *nfc = to_sunxi_nfc(chip->nand.controller); |
---|
| 1382 | + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); |
---|
| 1383 | + struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); |
---|
1484 | 1384 | const struct nand_sdr_timings *timings; |
---|
1485 | 1385 | u32 min_clk_period = 0; |
---|
1486 | 1386 | s32 tWB, tADL, tWHR, tRHW, tCAD; |
---|
.. | .. |
---|
1563 | 1463 | if (timings->tRHW_min > (min_clk_period * 20)) |
---|
1564 | 1464 | min_clk_period = DIV_ROUND_UP(timings->tRHW_min, 20); |
---|
1565 | 1465 | |
---|
| 1466 | + /* |
---|
| 1467 | + * In non-EDO, tREA should be less than tRP to guarantee that the |
---|
| 1468 | + * controller does not sample the IO lines too early. Unfortunately, |
---|
| 1469 | + * the sunxi NAND controller does not allow us to have different |
---|
| 1470 | + * values for tRP and tREH (tRP = tREH = tRW / 2). |
---|
| 1471 | + * |
---|
| 1472 | + * We have 2 options to overcome this limitation: |
---|
| 1473 | + * |
---|
| 1474 | + * 1/ Extend tRC to fulfil the tREA <= tRC / 2 constraint |
---|
| 1475 | + * 2/ Use EDO mode (only works if timings->tRLOH > 0) |
---|
| 1476 | + */ |
---|
| 1477 | + if (timings->tREA_max > min_clk_period && !timings->tRLOH_min) |
---|
| 1478 | + min_clk_period = timings->tREA_max; |
---|
| 1479 | + |
---|
1566 | 1480 | tWB = sunxi_nand_lookup_timing(tWB_lut, timings->tWB_max, |
---|
1567 | 1481 | min_clk_period); |
---|
1568 | 1482 | if (tWB < 0) { |
---|
.. | .. |
---|
1599 | 1513 | tCAD = 0x7; |
---|
1600 | 1514 | |
---|
1601 | 1515 | /* TODO: A83 has some more bits for CDQSS, CS, CLHZ, CCS, WC */ |
---|
1602 | | - chip->timing_cfg = NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD); |
---|
| 1516 | + sunxi_nand->timing_cfg = NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD); |
---|
1603 | 1517 | |
---|
1604 | 1518 | /* Convert min_clk_period from picoseconds to nanoseconds */ |
---|
1605 | 1519 | min_clk_period = DIV_ROUND_UP(min_clk_period, 1000); |
---|
.. | .. |
---|
1610 | 1524 | * This new formula was verified with a scope and validated by |
---|
1611 | 1525 | * Allwinner engineers. |
---|
1612 | 1526 | */ |
---|
1613 | | - chip->clk_rate = NSEC_PER_SEC / min_clk_period; |
---|
1614 | | - real_clk_rate = clk_round_rate(nfc->mod_clk, chip->clk_rate); |
---|
| 1527 | + sunxi_nand->clk_rate = NSEC_PER_SEC / min_clk_period; |
---|
| 1528 | + real_clk_rate = clk_round_rate(nfc->mod_clk, sunxi_nand->clk_rate); |
---|
1615 | 1529 | if (real_clk_rate <= 0) { |
---|
1616 | | - dev_err(nfc->dev, "Unable to round clk %lu\n", chip->clk_rate); |
---|
| 1530 | + dev_err(nfc->dev, "Unable to round clk %lu\n", |
---|
| 1531 | + sunxi_nand->clk_rate); |
---|
1617 | 1532 | return -EINVAL; |
---|
1618 | 1533 | } |
---|
| 1534 | + |
---|
| 1535 | + sunxi_nand->timing_ctl = 0; |
---|
1619 | 1536 | |
---|
1620 | 1537 | /* |
---|
1621 | 1538 | * ONFI specification 3.1, paragraph 4.15.2 dictates that EDO data |
---|
1622 | 1539 | * output cycle timings shall be used if the host drives tRC less than |
---|
1623 | | - * 30 ns. |
---|
| 1540 | + * 30 ns. We should also use EDO mode if tREA is bigger than tRP. |
---|
1624 | 1541 | */ |
---|
1625 | 1542 | min_clk_period = NSEC_PER_SEC / real_clk_rate; |
---|
1626 | | - chip->timing_ctl = ((min_clk_period * 2) < 30) ? |
---|
1627 | | - NFC_TIMING_CTL_EDO : 0; |
---|
| 1543 | + if (min_clk_period * 2 < 30 || min_clk_period * 1000 < timings->tREA_max) |
---|
| 1544 | + sunxi_nand->timing_ctl = NFC_TIMING_CTL_EDO; |
---|
1628 | 1545 | |
---|
1629 | 1546 | return 0; |
---|
1630 | 1547 | } |
---|
.. | .. |
---|
1658 | 1575 | * only have 2 bytes available in the first user data |
---|
1659 | 1576 | * section. |
---|
1660 | 1577 | */ |
---|
1661 | | - if (!section && ecc->mode == NAND_ECC_HW) { |
---|
| 1578 | + if (!section && ecc->engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST) { |
---|
1662 | 1579 | oobregion->offset = 2; |
---|
1663 | 1580 | oobregion->length = 2; |
---|
1664 | 1581 | |
---|
.. | .. |
---|
1670 | 1587 | if (section < ecc->steps) |
---|
1671 | 1588 | oobregion->length = 4; |
---|
1672 | 1589 | else |
---|
1673 | | - oobregion->offset = mtd->oobsize - oobregion->offset; |
---|
| 1590 | + oobregion->length = mtd->oobsize - oobregion->offset; |
---|
1674 | 1591 | |
---|
1675 | 1592 | return 0; |
---|
1676 | 1593 | } |
---|
.. | .. |
---|
1685 | 1602 | kfree(ecc->priv); |
---|
1686 | 1603 | } |
---|
1687 | 1604 | |
---|
1688 | | -static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd, |
---|
| 1605 | +static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand, |
---|
1689 | 1606 | struct nand_ecc_ctrl *ecc, |
---|
1690 | 1607 | struct device_node *np) |
---|
1691 | 1608 | { |
---|
1692 | 1609 | static const u8 strengths[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 }; |
---|
1693 | | - struct nand_chip *nand = mtd_to_nand(mtd); |
---|
1694 | | - struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); |
---|
1695 | | - struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); |
---|
| 1610 | + struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); |
---|
| 1611 | + struct mtd_info *mtd = nand_to_mtd(nand); |
---|
| 1612 | + struct nand_device *nanddev = mtd_to_nanddev(mtd); |
---|
1696 | 1613 | struct sunxi_nand_hw_ecc *data; |
---|
1697 | 1614 | int nsectors; |
---|
1698 | 1615 | int ret; |
---|
1699 | 1616 | int i; |
---|
1700 | 1617 | |
---|
1701 | | - if (ecc->options & NAND_ECC_MAXIMIZE) { |
---|
| 1618 | + if (nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE_STRENGTH) { |
---|
1702 | 1619 | int bytes; |
---|
1703 | 1620 | |
---|
1704 | 1621 | ecc->size = 1024; |
---|
.. | .. |
---|
1782 | 1699 | ecc->read_page = sunxi_nfc_hw_ecc_read_page_dma; |
---|
1783 | 1700 | ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage_dma; |
---|
1784 | 1701 | ecc->write_page = sunxi_nfc_hw_ecc_write_page_dma; |
---|
1785 | | - nand->options |= NAND_USE_BOUNCE_BUFFER; |
---|
| 1702 | + nand->options |= NAND_USES_DMA; |
---|
1786 | 1703 | } else { |
---|
1787 | 1704 | ecc->read_page = sunxi_nfc_hw_ecc_read_page; |
---|
1788 | 1705 | ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage; |
---|
.. | .. |
---|
1804 | 1721 | |
---|
1805 | 1722 | static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc) |
---|
1806 | 1723 | { |
---|
1807 | | - switch (ecc->mode) { |
---|
1808 | | - case NAND_ECC_HW: |
---|
| 1724 | + switch (ecc->engine_type) { |
---|
| 1725 | + case NAND_ECC_ENGINE_TYPE_ON_HOST: |
---|
1809 | 1726 | sunxi_nand_hw_ecc_ctrl_cleanup(ecc); |
---|
1810 | 1727 | break; |
---|
1811 | | - case NAND_ECC_NONE: |
---|
| 1728 | + case NAND_ECC_ENGINE_TYPE_NONE: |
---|
1812 | 1729 | default: |
---|
1813 | 1730 | break; |
---|
1814 | 1731 | } |
---|
.. | .. |
---|
1816 | 1733 | |
---|
1817 | 1734 | static int sunxi_nand_attach_chip(struct nand_chip *nand) |
---|
1818 | 1735 | { |
---|
1819 | | - struct mtd_info *mtd = nand_to_mtd(nand); |
---|
| 1736 | + const struct nand_ecc_props *requirements = |
---|
| 1737 | + nanddev_get_ecc_requirements(&nand->base); |
---|
1820 | 1738 | struct nand_ecc_ctrl *ecc = &nand->ecc; |
---|
1821 | 1739 | struct device_node *np = nand_get_flash_node(nand); |
---|
1822 | 1740 | int ret; |
---|
.. | .. |
---|
1830 | 1748 | nand->options |= NAND_SUBPAGE_READ; |
---|
1831 | 1749 | |
---|
1832 | 1750 | if (!ecc->size) { |
---|
1833 | | - ecc->size = nand->ecc_step_ds; |
---|
1834 | | - ecc->strength = nand->ecc_strength_ds; |
---|
| 1751 | + ecc->size = requirements->step_size; |
---|
| 1752 | + ecc->strength = requirements->strength; |
---|
1835 | 1753 | } |
---|
1836 | 1754 | |
---|
1837 | 1755 | if (!ecc->size || !ecc->strength) |
---|
1838 | 1756 | return -EINVAL; |
---|
1839 | 1757 | |
---|
1840 | | - switch (ecc->mode) { |
---|
1841 | | - case NAND_ECC_HW: |
---|
1842 | | - ret = sunxi_nand_hw_ecc_ctrl_init(mtd, ecc, np); |
---|
| 1758 | + switch (ecc->engine_type) { |
---|
| 1759 | + case NAND_ECC_ENGINE_TYPE_ON_HOST: |
---|
| 1760 | + ret = sunxi_nand_hw_ecc_ctrl_init(nand, ecc, np); |
---|
1843 | 1761 | if (ret) |
---|
1844 | 1762 | return ret; |
---|
1845 | 1763 | break; |
---|
1846 | | - case NAND_ECC_NONE: |
---|
1847 | | - case NAND_ECC_SOFT: |
---|
| 1764 | + case NAND_ECC_ENGINE_TYPE_NONE: |
---|
| 1765 | + case NAND_ECC_ENGINE_TYPE_SOFT: |
---|
1848 | 1766 | break; |
---|
1849 | 1767 | default: |
---|
1850 | 1768 | return -EINVAL; |
---|
.. | .. |
---|
1853 | 1771 | return 0; |
---|
1854 | 1772 | } |
---|
1855 | 1773 | |
---|
| 1774 | +static int sunxi_nfc_exec_subop(struct nand_chip *nand, |
---|
| 1775 | + const struct nand_subop *subop) |
---|
| 1776 | +{ |
---|
| 1777 | + struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); |
---|
| 1778 | + u32 cmd = 0, extcmd = 0, cnt = 0, addrs[2] = { }; |
---|
| 1779 | + unsigned int i, j, remaining, start; |
---|
| 1780 | + void *inbuf = NULL; |
---|
| 1781 | + int ret; |
---|
| 1782 | + |
---|
| 1783 | + for (i = 0; i < subop->ninstrs; i++) { |
---|
| 1784 | + const struct nand_op_instr *instr = &subop->instrs[i]; |
---|
| 1785 | + |
---|
| 1786 | + switch (instr->type) { |
---|
| 1787 | + case NAND_OP_CMD_INSTR: |
---|
| 1788 | + if (cmd & NFC_SEND_CMD1) { |
---|
| 1789 | + if (WARN_ON(cmd & NFC_SEND_CMD2)) |
---|
| 1790 | + return -EINVAL; |
---|
| 1791 | + |
---|
| 1792 | + cmd |= NFC_SEND_CMD2; |
---|
| 1793 | + extcmd |= instr->ctx.cmd.opcode; |
---|
| 1794 | + } else { |
---|
| 1795 | + cmd |= NFC_SEND_CMD1 | |
---|
| 1796 | + NFC_CMD(instr->ctx.cmd.opcode); |
---|
| 1797 | + } |
---|
| 1798 | + break; |
---|
| 1799 | + |
---|
| 1800 | + case NAND_OP_ADDR_INSTR: |
---|
| 1801 | + remaining = nand_subop_get_num_addr_cyc(subop, i); |
---|
| 1802 | + start = nand_subop_get_addr_start_off(subop, i); |
---|
| 1803 | + for (j = 0; j < 8 && j + start < remaining; j++) { |
---|
| 1804 | + u32 addr = instr->ctx.addr.addrs[j + start]; |
---|
| 1805 | + |
---|
| 1806 | + addrs[j / 4] |= addr << (j % 4) * 8; |
---|
| 1807 | + } |
---|
| 1808 | + |
---|
| 1809 | + if (j) |
---|
| 1810 | + cmd |= NFC_SEND_ADR | NFC_ADR_NUM(j); |
---|
| 1811 | + |
---|
| 1812 | + break; |
---|
| 1813 | + |
---|
| 1814 | + case NAND_OP_DATA_IN_INSTR: |
---|
| 1815 | + case NAND_OP_DATA_OUT_INSTR: |
---|
| 1816 | + start = nand_subop_get_data_start_off(subop, i); |
---|
| 1817 | + remaining = nand_subop_get_data_len(subop, i); |
---|
| 1818 | + cnt = min_t(u32, remaining, NFC_SRAM_SIZE); |
---|
| 1819 | + cmd |= NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD; |
---|
| 1820 | + |
---|
| 1821 | + if (instr->type == NAND_OP_DATA_OUT_INSTR) { |
---|
| 1822 | + cmd |= NFC_ACCESS_DIR; |
---|
| 1823 | + memcpy_toio(nfc->regs + NFC_RAM0_BASE, |
---|
| 1824 | + instr->ctx.data.buf.out + start, |
---|
| 1825 | + cnt); |
---|
| 1826 | + } else { |
---|
| 1827 | + inbuf = instr->ctx.data.buf.in + start; |
---|
| 1828 | + } |
---|
| 1829 | + |
---|
| 1830 | + break; |
---|
| 1831 | + |
---|
| 1832 | + case NAND_OP_WAITRDY_INSTR: |
---|
| 1833 | + cmd |= NFC_WAIT_FLAG; |
---|
| 1834 | + break; |
---|
| 1835 | + } |
---|
| 1836 | + } |
---|
| 1837 | + |
---|
| 1838 | + ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); |
---|
| 1839 | + if (ret) |
---|
| 1840 | + return ret; |
---|
| 1841 | + |
---|
| 1842 | + if (cmd & NFC_SEND_ADR) { |
---|
| 1843 | + writel(addrs[0], nfc->regs + NFC_REG_ADDR_LOW); |
---|
| 1844 | + writel(addrs[1], nfc->regs + NFC_REG_ADDR_HIGH); |
---|
| 1845 | + } |
---|
| 1846 | + |
---|
| 1847 | + if (cmd & NFC_SEND_CMD2) |
---|
| 1848 | + writel(extcmd, |
---|
| 1849 | + nfc->regs + |
---|
| 1850 | + (cmd & NFC_ACCESS_DIR ? |
---|
| 1851 | + NFC_REG_WCMD_SET : NFC_REG_RCMD_SET)); |
---|
| 1852 | + |
---|
| 1853 | + if (cmd & NFC_DATA_TRANS) |
---|
| 1854 | + writel(cnt, nfc->regs + NFC_REG_CNT); |
---|
| 1855 | + |
---|
| 1856 | + writel(cmd, nfc->regs + NFC_REG_CMD); |
---|
| 1857 | + |
---|
| 1858 | + ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, |
---|
| 1859 | + !(cmd & NFC_WAIT_FLAG) && cnt < 64, |
---|
| 1860 | + 0); |
---|
| 1861 | + if (ret) |
---|
| 1862 | + return ret; |
---|
| 1863 | + |
---|
| 1864 | + if (inbuf) |
---|
| 1865 | + memcpy_fromio(inbuf, nfc->regs + NFC_RAM0_BASE, cnt); |
---|
| 1866 | + |
---|
| 1867 | + return 0; |
---|
| 1868 | +} |
---|
| 1869 | + |
---|
| 1870 | +static int sunxi_nfc_soft_waitrdy(struct nand_chip *nand, |
---|
| 1871 | + const struct nand_subop *subop) |
---|
| 1872 | +{ |
---|
| 1873 | + return nand_soft_waitrdy(nand, |
---|
| 1874 | + subop->instrs[0].ctx.waitrdy.timeout_ms); |
---|
| 1875 | +} |
---|
| 1876 | + |
---|
| 1877 | +static const struct nand_op_parser sunxi_nfc_op_parser = NAND_OP_PARSER( |
---|
| 1878 | + NAND_OP_PARSER_PATTERN(sunxi_nfc_exec_subop, |
---|
| 1879 | + NAND_OP_PARSER_PAT_CMD_ELEM(true), |
---|
| 1880 | + NAND_OP_PARSER_PAT_ADDR_ELEM(true, 8), |
---|
| 1881 | + NAND_OP_PARSER_PAT_CMD_ELEM(true), |
---|
| 1882 | + NAND_OP_PARSER_PAT_WAITRDY_ELEM(true), |
---|
| 1883 | + NAND_OP_PARSER_PAT_DATA_IN_ELEM(true, 1024)), |
---|
| 1884 | + NAND_OP_PARSER_PATTERN(sunxi_nfc_exec_subop, |
---|
| 1885 | + NAND_OP_PARSER_PAT_CMD_ELEM(true), |
---|
| 1886 | + NAND_OP_PARSER_PAT_ADDR_ELEM(true, 8), |
---|
| 1887 | + NAND_OP_PARSER_PAT_DATA_OUT_ELEM(true, 1024), |
---|
| 1888 | + NAND_OP_PARSER_PAT_CMD_ELEM(true), |
---|
| 1889 | + NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)), |
---|
| 1890 | +); |
---|
| 1891 | + |
---|
| 1892 | +static const struct nand_op_parser sunxi_nfc_norb_op_parser = NAND_OP_PARSER( |
---|
| 1893 | + NAND_OP_PARSER_PATTERN(sunxi_nfc_exec_subop, |
---|
| 1894 | + NAND_OP_PARSER_PAT_CMD_ELEM(true), |
---|
| 1895 | + NAND_OP_PARSER_PAT_ADDR_ELEM(true, 8), |
---|
| 1896 | + NAND_OP_PARSER_PAT_CMD_ELEM(true), |
---|
| 1897 | + NAND_OP_PARSER_PAT_DATA_IN_ELEM(true, 1024)), |
---|
| 1898 | + NAND_OP_PARSER_PATTERN(sunxi_nfc_exec_subop, |
---|
| 1899 | + NAND_OP_PARSER_PAT_CMD_ELEM(true), |
---|
| 1900 | + NAND_OP_PARSER_PAT_ADDR_ELEM(true, 8), |
---|
| 1901 | + NAND_OP_PARSER_PAT_DATA_OUT_ELEM(true, 1024), |
---|
| 1902 | + NAND_OP_PARSER_PAT_CMD_ELEM(true)), |
---|
| 1903 | + NAND_OP_PARSER_PATTERN(sunxi_nfc_soft_waitrdy, |
---|
| 1904 | + NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)), |
---|
| 1905 | +); |
---|
| 1906 | + |
---|
| 1907 | +static int sunxi_nfc_exec_op(struct nand_chip *nand, |
---|
| 1908 | + const struct nand_operation *op, bool check_only) |
---|
| 1909 | +{ |
---|
| 1910 | + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); |
---|
| 1911 | + const struct nand_op_parser *parser; |
---|
| 1912 | + |
---|
| 1913 | + if (!check_only) |
---|
| 1914 | + sunxi_nfc_select_chip(nand, op->cs); |
---|
| 1915 | + |
---|
| 1916 | + if (sunxi_nand->sels[op->cs].rb >= 0) |
---|
| 1917 | + parser = &sunxi_nfc_op_parser; |
---|
| 1918 | + else |
---|
| 1919 | + parser = &sunxi_nfc_norb_op_parser; |
---|
| 1920 | + |
---|
| 1921 | + return nand_op_parser_exec_op(nand, parser, op, check_only); |
---|
| 1922 | +} |
---|
| 1923 | + |
---|
1856 | 1924 | static const struct nand_controller_ops sunxi_nand_controller_ops = { |
---|
1857 | 1925 | .attach_chip = sunxi_nand_attach_chip, |
---|
| 1926 | + .setup_interface = sunxi_nfc_setup_interface, |
---|
| 1927 | + .exec_op = sunxi_nfc_exec_op, |
---|
1858 | 1928 | }; |
---|
1859 | 1929 | |
---|
1860 | 1930 | static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc, |
---|
1861 | 1931 | struct device_node *np) |
---|
1862 | 1932 | { |
---|
1863 | | - struct sunxi_nand_chip *chip; |
---|
| 1933 | + struct sunxi_nand_chip *sunxi_nand; |
---|
1864 | 1934 | struct mtd_info *mtd; |
---|
1865 | 1935 | struct nand_chip *nand; |
---|
1866 | 1936 | int nsels; |
---|
.. | .. |
---|
1877 | 1947 | return -EINVAL; |
---|
1878 | 1948 | } |
---|
1879 | 1949 | |
---|
1880 | | - chip = devm_kzalloc(dev, |
---|
1881 | | - sizeof(*chip) + |
---|
1882 | | - (nsels * sizeof(struct sunxi_nand_chip_sel)), |
---|
1883 | | - GFP_KERNEL); |
---|
1884 | | - if (!chip) { |
---|
| 1950 | + sunxi_nand = devm_kzalloc(dev, struct_size(sunxi_nand, sels, nsels), |
---|
| 1951 | + GFP_KERNEL); |
---|
| 1952 | + if (!sunxi_nand) { |
---|
1885 | 1953 | dev_err(dev, "could not allocate chip\n"); |
---|
1886 | 1954 | return -ENOMEM; |
---|
1887 | 1955 | } |
---|
1888 | 1956 | |
---|
1889 | | - chip->nsels = nsels; |
---|
1890 | | - chip->selected = -1; |
---|
| 1957 | + sunxi_nand->nsels = nsels; |
---|
1891 | 1958 | |
---|
1892 | 1959 | for (i = 0; i < nsels; i++) { |
---|
1893 | 1960 | ret = of_property_read_u32_index(np, "reg", i, &tmp); |
---|
.. | .. |
---|
1909 | 1976 | return -EINVAL; |
---|
1910 | 1977 | } |
---|
1911 | 1978 | |
---|
1912 | | - chip->sels[i].cs = tmp; |
---|
| 1979 | + sunxi_nand->sels[i].cs = tmp; |
---|
1913 | 1980 | |
---|
1914 | 1981 | if (!of_property_read_u32_index(np, "allwinner,rb", i, &tmp) && |
---|
1915 | 1982 | tmp < 2) |
---|
1916 | | - chip->sels[i].rb = tmp; |
---|
| 1983 | + sunxi_nand->sels[i].rb = tmp; |
---|
1917 | 1984 | else |
---|
1918 | | - chip->sels[i].rb = -1; |
---|
| 1985 | + sunxi_nand->sels[i].rb = -1; |
---|
1919 | 1986 | } |
---|
1920 | 1987 | |
---|
1921 | | - nand = &chip->nand; |
---|
| 1988 | + nand = &sunxi_nand->nand; |
---|
1922 | 1989 | /* Default tR value specified in the ONFI spec (chapter 4.15.1) */ |
---|
1923 | | - nand->chip_delay = 200; |
---|
1924 | 1990 | nand->controller = &nfc->controller; |
---|
1925 | 1991 | nand->controller->ops = &sunxi_nand_controller_ops; |
---|
1926 | 1992 | |
---|
.. | .. |
---|
1928 | 1994 | * Set the ECC mode to the default value in case nothing is specified |
---|
1929 | 1995 | * in the DT. |
---|
1930 | 1996 | */ |
---|
1931 | | - nand->ecc.mode = NAND_ECC_HW; |
---|
| 1997 | + nand->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; |
---|
1932 | 1998 | nand_set_flash_node(nand, np); |
---|
1933 | | - nand->select_chip = sunxi_nfc_select_chip; |
---|
1934 | | - nand->cmd_ctrl = sunxi_nfc_cmd_ctrl; |
---|
1935 | | - nand->read_buf = sunxi_nfc_read_buf; |
---|
1936 | | - nand->write_buf = sunxi_nfc_write_buf; |
---|
1937 | | - nand->read_byte = sunxi_nfc_read_byte; |
---|
1938 | | - nand->setup_data_interface = sunxi_nfc_setup_data_interface; |
---|
1939 | 1999 | |
---|
1940 | 2000 | mtd = nand_to_mtd(nand); |
---|
1941 | 2001 | mtd->dev.parent = dev; |
---|
.. | .. |
---|
1951 | 2011 | return ret; |
---|
1952 | 2012 | } |
---|
1953 | 2013 | |
---|
1954 | | - list_add_tail(&chip->node, &nfc->chips); |
---|
| 2014 | + list_add_tail(&sunxi_nand->node, &nfc->chips); |
---|
1955 | 2015 | |
---|
1956 | 2016 | return 0; |
---|
1957 | 2017 | } |
---|
.. | .. |
---|
1981 | 2041 | |
---|
1982 | 2042 | static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc) |
---|
1983 | 2043 | { |
---|
1984 | | - struct sunxi_nand_chip *chip; |
---|
| 2044 | + struct sunxi_nand_chip *sunxi_nand; |
---|
| 2045 | + struct nand_chip *chip; |
---|
| 2046 | + int ret; |
---|
1985 | 2047 | |
---|
1986 | 2048 | while (!list_empty(&nfc->chips)) { |
---|
1987 | | - chip = list_first_entry(&nfc->chips, struct sunxi_nand_chip, |
---|
1988 | | - node); |
---|
1989 | | - nand_release(&chip->nand); |
---|
1990 | | - sunxi_nand_ecc_cleanup(&chip->nand.ecc); |
---|
1991 | | - list_del(&chip->node); |
---|
| 2049 | + sunxi_nand = list_first_entry(&nfc->chips, |
---|
| 2050 | + struct sunxi_nand_chip, |
---|
| 2051 | + node); |
---|
| 2052 | + chip = &sunxi_nand->nand; |
---|
| 2053 | + ret = mtd_device_unregister(nand_to_mtd(chip)); |
---|
| 2054 | + WARN_ON(ret); |
---|
| 2055 | + nand_cleanup(chip); |
---|
| 2056 | + sunxi_nand_ecc_cleanup(&chip->ecc); |
---|
| 2057 | + list_del(&sunxi_nand->node); |
---|
1992 | 2058 | } |
---|
1993 | 2059 | } |
---|
1994 | 2060 | |
---|
.. | .. |
---|
2014 | 2080 | return PTR_ERR(nfc->regs); |
---|
2015 | 2081 | |
---|
2016 | 2082 | irq = platform_get_irq(pdev, 0); |
---|
2017 | | - if (irq < 0) { |
---|
2018 | | - dev_err(dev, "failed to retrieve irq\n"); |
---|
| 2083 | + if (irq < 0) |
---|
2019 | 2084 | return irq; |
---|
2020 | | - } |
---|
2021 | 2085 | |
---|
2022 | 2086 | nfc->ahb_clk = devm_clk_get(dev, "ahb"); |
---|
2023 | 2087 | if (IS_ERR(nfc->ahb_clk)) { |
---|
.. | .. |
---|
2052 | 2116 | goto out_mod_clk_unprepare; |
---|
2053 | 2117 | } |
---|
2054 | 2118 | |
---|
| 2119 | + nfc->caps = of_device_get_match_data(&pdev->dev); |
---|
| 2120 | + if (!nfc->caps) { |
---|
| 2121 | + ret = -EINVAL; |
---|
| 2122 | + goto out_ahb_reset_reassert; |
---|
| 2123 | + } |
---|
| 2124 | + |
---|
2055 | 2125 | ret = sunxi_nfc_rst(nfc); |
---|
2056 | 2126 | if (ret) |
---|
2057 | 2127 | goto out_ahb_reset_reassert; |
---|
.. | .. |
---|
2062 | 2132 | if (ret) |
---|
2063 | 2133 | goto out_ahb_reset_reassert; |
---|
2064 | 2134 | |
---|
2065 | | - nfc->dmac = dma_request_slave_channel(dev, "rxtx"); |
---|
2066 | | - if (nfc->dmac) { |
---|
| 2135 | + nfc->dmac = dma_request_chan(dev, "rxtx"); |
---|
| 2136 | + if (IS_ERR(nfc->dmac)) { |
---|
| 2137 | + ret = PTR_ERR(nfc->dmac); |
---|
| 2138 | + if (ret == -EPROBE_DEFER) |
---|
| 2139 | + goto out_ahb_reset_reassert; |
---|
| 2140 | + |
---|
| 2141 | + /* Ignore errors to fall back to PIO mode */ |
---|
| 2142 | + dev_warn(dev, "failed to request rxtx DMA channel: %d\n", ret); |
---|
| 2143 | + nfc->dmac = NULL; |
---|
| 2144 | + } else { |
---|
2067 | 2145 | struct dma_slave_config dmac_cfg = { }; |
---|
2068 | 2146 | |
---|
2069 | | - dmac_cfg.src_addr = r->start + NFC_REG_IO_DATA; |
---|
| 2147 | + dmac_cfg.src_addr = r->start + nfc->caps->reg_io_data; |
---|
2070 | 2148 | dmac_cfg.dst_addr = dmac_cfg.src_addr; |
---|
2071 | 2149 | dmac_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
---|
2072 | 2150 | dmac_cfg.dst_addr_width = dmac_cfg.src_addr_width; |
---|
2073 | | - dmac_cfg.src_maxburst = 4; |
---|
2074 | | - dmac_cfg.dst_maxburst = 4; |
---|
| 2151 | + dmac_cfg.src_maxburst = nfc->caps->dma_maxburst; |
---|
| 2152 | + dmac_cfg.dst_maxburst = nfc->caps->dma_maxburst; |
---|
2075 | 2153 | dmaengine_slave_config(nfc->dmac, &dmac_cfg); |
---|
2076 | | - } else { |
---|
2077 | | - dev_warn(dev, "failed to request rxtx DMA channel\n"); |
---|
| 2154 | + |
---|
| 2155 | + if (nfc->caps->extra_mbus_conf) |
---|
| 2156 | + writel(readl(nfc->regs + NFC_REG_CTL) | |
---|
| 2157 | + NFC_DMA_TYPE_NORMAL, nfc->regs + NFC_REG_CTL); |
---|
2078 | 2158 | } |
---|
2079 | 2159 | |
---|
2080 | 2160 | platform_set_drvdata(pdev, nfc); |
---|
.. | .. |
---|
2116 | 2196 | return 0; |
---|
2117 | 2197 | } |
---|
2118 | 2198 | |
---|
| 2199 | +static const struct sunxi_nfc_caps sunxi_nfc_a10_caps = { |
---|
| 2200 | + .reg_io_data = NFC_REG_A10_IO_DATA, |
---|
| 2201 | + .dma_maxburst = 4, |
---|
| 2202 | +}; |
---|
| 2203 | + |
---|
| 2204 | +static const struct sunxi_nfc_caps sunxi_nfc_a23_caps = { |
---|
| 2205 | + .extra_mbus_conf = true, |
---|
| 2206 | + .reg_io_data = NFC_REG_A23_IO_DATA, |
---|
| 2207 | + .dma_maxburst = 8, |
---|
| 2208 | +}; |
---|
| 2209 | + |
---|
2119 | 2210 | static const struct of_device_id sunxi_nfc_ids[] = { |
---|
2120 | | - { .compatible = "allwinner,sun4i-a10-nand" }, |
---|
| 2211 | + { |
---|
| 2212 | + .compatible = "allwinner,sun4i-a10-nand", |
---|
| 2213 | + .data = &sunxi_nfc_a10_caps, |
---|
| 2214 | + }, |
---|
| 2215 | + { |
---|
| 2216 | + .compatible = "allwinner,sun8i-a23-nand-controller", |
---|
| 2217 | + .data = &sunxi_nfc_a23_caps, |
---|
| 2218 | + }, |
---|
2121 | 2219 | { /* sentinel */ } |
---|
2122 | 2220 | }; |
---|
2123 | 2221 | MODULE_DEVICE_TABLE(of, sunxi_nfc_ids); |
---|
.. | .. |
---|
2132 | 2230 | }; |
---|
2133 | 2231 | module_platform_driver(sunxi_nfc_driver); |
---|
2134 | 2232 | |
---|
2135 | | -MODULE_LICENSE("GPL v2"); |
---|
| 2233 | +MODULE_LICENSE("GPL"); |
---|
2136 | 2234 | MODULE_AUTHOR("Boris BREZILLON"); |
---|
2137 | 2235 | MODULE_DESCRIPTION("Allwinner NAND Flash Controller driver"); |
---|
2138 | 2236 | MODULE_ALIAS("platform:sunxi_nand"); |
---|