.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Driver for One Laptop Per Child ‘CAFÉ’ controller, aka Marvell 88ALP01 |
---|
3 | 4 | * |
---|
.. | .. |
---|
100 | 101 | #define cafe_readl(cafe, addr) readl((cafe)->mmio + CAFE_##addr) |
---|
101 | 102 | #define cafe_writel(cafe, datum, addr) writel(datum, (cafe)->mmio + CAFE_##addr) |
---|
102 | 103 | |
---|
103 | | -static int cafe_device_ready(struct mtd_info *mtd) |
---|
| 104 | +static int cafe_device_ready(struct nand_chip *chip) |
---|
104 | 105 | { |
---|
105 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
---|
106 | 106 | struct cafe_priv *cafe = nand_get_controller_data(chip); |
---|
107 | 107 | int result = !!(cafe_readl(cafe, NAND_STATUS) & 0x40000000); |
---|
108 | 108 | uint32_t irqs = cafe_readl(cafe, NAND_IRQ); |
---|
.. | .. |
---|
117 | 117 | } |
---|
118 | 118 | |
---|
119 | 119 | |
---|
120 | | -static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) |
---|
| 120 | +static void cafe_write_buf(struct nand_chip *chip, const uint8_t *buf, int len) |
---|
121 | 121 | { |
---|
122 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
---|
123 | 122 | struct cafe_priv *cafe = nand_get_controller_data(chip); |
---|
124 | 123 | |
---|
125 | 124 | if (cafe->usedma) |
---|
.. | .. |
---|
133 | 132 | len, cafe->datalen); |
---|
134 | 133 | } |
---|
135 | 134 | |
---|
136 | | -static void cafe_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) |
---|
| 135 | +static void cafe_read_buf(struct nand_chip *chip, uint8_t *buf, int len) |
---|
137 | 136 | { |
---|
138 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
---|
139 | 137 | struct cafe_priv *cafe = nand_get_controller_data(chip); |
---|
140 | 138 | |
---|
141 | 139 | if (cafe->usedma) |
---|
.. | .. |
---|
148 | 146 | cafe->datalen += len; |
---|
149 | 147 | } |
---|
150 | 148 | |
---|
151 | | -static uint8_t cafe_read_byte(struct mtd_info *mtd) |
---|
| 149 | +static uint8_t cafe_read_byte(struct nand_chip *chip) |
---|
152 | 150 | { |
---|
153 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
---|
154 | 151 | struct cafe_priv *cafe = nand_get_controller_data(chip); |
---|
155 | 152 | uint8_t d; |
---|
156 | 153 | |
---|
157 | | - cafe_read_buf(mtd, &d, 1); |
---|
| 154 | + cafe_read_buf(chip, &d, 1); |
---|
158 | 155 | cafe_dev_dbg(&cafe->pdev->dev, "Read %02x\n", d); |
---|
159 | 156 | |
---|
160 | 157 | return d; |
---|
161 | 158 | } |
---|
162 | 159 | |
---|
163 | | -static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command, |
---|
| 160 | +static void cafe_nand_cmdfunc(struct nand_chip *chip, unsigned command, |
---|
164 | 161 | int column, int page_addr) |
---|
165 | 162 | { |
---|
166 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
---|
| 163 | + struct mtd_info *mtd = nand_to_mtd(chip); |
---|
167 | 164 | struct cafe_priv *cafe = nand_get_controller_data(chip); |
---|
168 | 165 | int adrbytes = 0; |
---|
169 | 166 | uint32_t ctl1; |
---|
.. | .. |
---|
313 | 310 | cafe_writel(cafe, cafe->ctl2, NAND_CTRL2); |
---|
314 | 311 | return; |
---|
315 | 312 | } |
---|
316 | | - nand_wait_ready(mtd); |
---|
| 313 | + nand_wait_ready(chip); |
---|
317 | 314 | cafe_writel(cafe, cafe->ctl2, NAND_CTRL2); |
---|
318 | 315 | } |
---|
319 | 316 | |
---|
320 | | -static void cafe_select_chip(struct mtd_info *mtd, int chipnr) |
---|
| 317 | +static void cafe_select_chip(struct nand_chip *chip, int chipnr) |
---|
321 | 318 | { |
---|
322 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
---|
323 | 319 | struct cafe_priv *cafe = nand_get_controller_data(chip); |
---|
324 | 320 | |
---|
325 | 321 | cafe_dev_dbg(&cafe->pdev->dev, "select_chip %d\n", chipnr); |
---|
.. | .. |
---|
346 | 342 | return IRQ_HANDLED; |
---|
347 | 343 | } |
---|
348 | 344 | |
---|
349 | | -static int cafe_nand_write_oob(struct mtd_info *mtd, |
---|
350 | | - struct nand_chip *chip, int page) |
---|
| 345 | +static int cafe_nand_write_oob(struct nand_chip *chip, int page) |
---|
351 | 346 | { |
---|
| 347 | + struct mtd_info *mtd = nand_to_mtd(chip); |
---|
| 348 | + |
---|
352 | 349 | return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi, |
---|
353 | 350 | mtd->oobsize); |
---|
354 | 351 | } |
---|
355 | 352 | |
---|
356 | 353 | /* Don't use -- use nand_read_oob_std for now */ |
---|
357 | | -static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, |
---|
358 | | - int page) |
---|
| 354 | +static int cafe_nand_read_oob(struct nand_chip *chip, int page) |
---|
359 | 355 | { |
---|
| 356 | + struct mtd_info *mtd = nand_to_mtd(chip); |
---|
| 357 | + |
---|
360 | 358 | return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize); |
---|
361 | 359 | } |
---|
362 | 360 | /** |
---|
.. | .. |
---|
369 | 367 | * The hw generator calculates the error syndrome automatically. Therefore |
---|
370 | 368 | * we need a special oob layout and handling. |
---|
371 | 369 | */ |
---|
372 | | -static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, |
---|
373 | | - uint8_t *buf, int oob_required, int page) |
---|
| 370 | +static int cafe_nand_read_page(struct nand_chip *chip, uint8_t *buf, |
---|
| 371 | + int oob_required, int page) |
---|
374 | 372 | { |
---|
| 373 | + struct mtd_info *mtd = nand_to_mtd(chip); |
---|
375 | 374 | struct cafe_priv *cafe = nand_get_controller_data(chip); |
---|
376 | 375 | unsigned int max_bitflips = 0; |
---|
377 | 376 | |
---|
.. | .. |
---|
380 | 379 | cafe_readl(cafe, NAND_ECC_SYN01)); |
---|
381 | 380 | |
---|
382 | 381 | nand_read_page_op(chip, page, 0, buf, mtd->writesize); |
---|
383 | | - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); |
---|
| 382 | + chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize); |
---|
384 | 383 | |
---|
385 | 384 | if (checkecc && cafe_readl(cafe, NAND_ECC_RESULT) & (1<<18)) { |
---|
386 | 385 | unsigned short syn[8], pat[4]; |
---|
.. | .. |
---|
531 | 530 | }; |
---|
532 | 531 | |
---|
533 | 532 | |
---|
534 | | -static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd, |
---|
535 | | - struct nand_chip *chip, |
---|
536 | | - const uint8_t *buf, int oob_required, |
---|
537 | | - int page) |
---|
| 533 | +static int cafe_nand_write_page_lowlevel(struct nand_chip *chip, |
---|
| 534 | + const uint8_t *buf, int oob_required, |
---|
| 535 | + int page) |
---|
538 | 536 | { |
---|
| 537 | + struct mtd_info *mtd = nand_to_mtd(chip); |
---|
539 | 538 | struct cafe_priv *cafe = nand_get_controller_data(chip); |
---|
540 | 539 | |
---|
541 | 540 | nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize); |
---|
542 | | - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); |
---|
| 541 | + chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize); |
---|
543 | 542 | |
---|
544 | 543 | /* Set up ECC autogeneration */ |
---|
545 | 544 | cafe->ctl2 |= (1<<30); |
---|
546 | 545 | |
---|
547 | 546 | return nand_prog_page_end_op(chip); |
---|
548 | | -} |
---|
549 | | - |
---|
550 | | -static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs) |
---|
551 | | -{ |
---|
552 | | - return 0; |
---|
553 | 547 | } |
---|
554 | 548 | |
---|
555 | 549 | /* F_2[X]/(X**6+X+1) */ |
---|
.. | .. |
---|
635 | 629 | goto out_free_dma; |
---|
636 | 630 | } |
---|
637 | 631 | |
---|
638 | | - cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME; |
---|
| 632 | + cafe->nand.ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; |
---|
| 633 | + cafe->nand.ecc.placement = NAND_ECC_PLACEMENT_INTERLEAVED; |
---|
639 | 634 | cafe->nand.ecc.size = mtd->writesize; |
---|
640 | 635 | cafe->nand.ecc.bytes = 14; |
---|
641 | 636 | cafe->nand.ecc.strength = 4; |
---|
.. | .. |
---|
705 | 700 | goto out_ior; |
---|
706 | 701 | } |
---|
707 | 702 | |
---|
708 | | - cafe->nand.cmdfunc = cafe_nand_cmdfunc; |
---|
709 | | - cafe->nand.dev_ready = cafe_device_ready; |
---|
710 | | - cafe->nand.read_byte = cafe_read_byte; |
---|
711 | | - cafe->nand.read_buf = cafe_read_buf; |
---|
712 | | - cafe->nand.write_buf = cafe_write_buf; |
---|
713 | | - cafe->nand.select_chip = cafe_select_chip; |
---|
714 | | - cafe->nand.set_features = nand_get_set_features_notsupp; |
---|
715 | | - cafe->nand.get_features = nand_get_set_features_notsupp; |
---|
| 703 | + cafe->nand.legacy.cmdfunc = cafe_nand_cmdfunc; |
---|
| 704 | + cafe->nand.legacy.dev_ready = cafe_device_ready; |
---|
| 705 | + cafe->nand.legacy.read_byte = cafe_read_byte; |
---|
| 706 | + cafe->nand.legacy.read_buf = cafe_read_buf; |
---|
| 707 | + cafe->nand.legacy.write_buf = cafe_write_buf; |
---|
| 708 | + cafe->nand.legacy.select_chip = cafe_select_chip; |
---|
| 709 | + cafe->nand.legacy.set_features = nand_get_set_features_notsupp; |
---|
| 710 | + cafe->nand.legacy.get_features = nand_get_set_features_notsupp; |
---|
716 | 711 | |
---|
717 | | - cafe->nand.chip_delay = 0; |
---|
| 712 | + cafe->nand.legacy.chip_delay = 0; |
---|
718 | 713 | |
---|
719 | 714 | /* Enable the following for a flash based bad block table */ |
---|
720 | 715 | cafe->nand.bbt_options = NAND_BBT_USE_FLASH; |
---|
721 | 716 | |
---|
722 | | - if (skipbbt) { |
---|
723 | | - cafe->nand.options |= NAND_SKIP_BBTSCAN; |
---|
724 | | - cafe->nand.block_bad = cafe_nand_block_bad; |
---|
725 | | - } |
---|
| 717 | + if (skipbbt) |
---|
| 718 | + cafe->nand.options |= NAND_SKIP_BBTSCAN | NAND_NO_BBM_QUIRK; |
---|
726 | 719 | |
---|
727 | 720 | if (numtimings && numtimings != 3) { |
---|
728 | 721 | dev_warn(&cafe->pdev->dev, "%d timing register values ignored; precisely three are required\n", numtimings); |
---|
.. | .. |
---|
782 | 775 | cafe->usedma = 0; |
---|
783 | 776 | |
---|
784 | 777 | /* Scan to find existence of the device */ |
---|
785 | | - cafe->nand.dummy_controller.ops = &cafe_nand_controller_ops; |
---|
| 778 | + cafe->nand.legacy.dummy_controller.ops = &cafe_nand_controller_ops; |
---|
786 | 779 | err = nand_scan(&cafe->nand, 2); |
---|
787 | 780 | if (err) |
---|
788 | 781 | goto out_irq; |
---|
.. | .. |
---|
817 | 810 | struct mtd_info *mtd = pci_get_drvdata(pdev); |
---|
818 | 811 | struct nand_chip *chip = mtd_to_nand(mtd); |
---|
819 | 812 | struct cafe_priv *cafe = nand_get_controller_data(chip); |
---|
| 813 | + int ret; |
---|
820 | 814 | |
---|
821 | 815 | /* Disable NAND IRQ in global IRQ mask register */ |
---|
822 | 816 | cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK); |
---|
823 | 817 | free_irq(pdev->irq, mtd); |
---|
824 | | - nand_release(chip); |
---|
| 818 | + ret = mtd_device_unregister(mtd); |
---|
| 819 | + WARN_ON(ret); |
---|
| 820 | + nand_cleanup(chip); |
---|
825 | 821 | free_rs(cafe->rs); |
---|
826 | 822 | pci_iounmap(pdev, cafe->mmio); |
---|
827 | 823 | dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr); |
---|