| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Driver for NAND MLC Controller in LPC32xx |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 5 | 6 | * |
|---|
| 6 | 7 | * Copyright © 2011 WORK Microwave GmbH |
|---|
| 7 | 8 | * Copyright © 2011, 2012 Roland Stigge |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 10 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 11 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 12 | | - * (at your option) any later version. |
|---|
| 13 | | - * |
|---|
| 14 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 15 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 16 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 17 | | - * GNU General Public License for more details. |
|---|
| 18 | | - * |
|---|
| 19 | 9 | * |
|---|
| 20 | 10 | * NAND Flash Controller Operation: |
|---|
| 21 | 11 | * - Read: Auto Decode |
|---|
| .. | .. |
|---|
| 286 | 276 | /* |
|---|
| 287 | 277 | * Hardware specific access to control lines |
|---|
| 288 | 278 | */ |
|---|
| 289 | | -static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, |
|---|
| 279 | +static void lpc32xx_nand_cmd_ctrl(struct nand_chip *nand_chip, int cmd, |
|---|
| 290 | 280 | unsigned int ctrl) |
|---|
| 291 | 281 | { |
|---|
| 292 | | - struct nand_chip *nand_chip = mtd_to_nand(mtd); |
|---|
| 293 | 282 | struct lpc32xx_nand_host *host = nand_get_controller_data(nand_chip); |
|---|
| 294 | 283 | |
|---|
| 295 | 284 | if (cmd != NAND_CMD_NONE) { |
|---|
| .. | .. |
|---|
| 303 | 292 | /* |
|---|
| 304 | 293 | * Read Device Ready (NAND device _and_ controller ready) |
|---|
| 305 | 294 | */ |
|---|
| 306 | | -static int lpc32xx_nand_device_ready(struct mtd_info *mtd) |
|---|
| 295 | +static int lpc32xx_nand_device_ready(struct nand_chip *nand_chip) |
|---|
| 307 | 296 | { |
|---|
| 308 | | - struct nand_chip *nand_chip = mtd_to_nand(mtd); |
|---|
| 309 | 297 | struct lpc32xx_nand_host *host = nand_get_controller_data(nand_chip); |
|---|
| 310 | 298 | |
|---|
| 311 | 299 | if ((readb(MLC_ISR(host->io_base)) & |
|---|
| .. | .. |
|---|
| 330 | 318 | return IRQ_HANDLED; |
|---|
| 331 | 319 | } |
|---|
| 332 | 320 | |
|---|
| 333 | | -static int lpc32xx_waitfunc_nand(struct mtd_info *mtd, struct nand_chip *chip) |
|---|
| 321 | +static int lpc32xx_waitfunc_nand(struct nand_chip *chip) |
|---|
| 334 | 322 | { |
|---|
| 323 | + struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 335 | 324 | struct lpc32xx_nand_host *host = nand_get_controller_data(chip); |
|---|
| 336 | 325 | |
|---|
| 337 | 326 | if (readb(MLC_ISR(host->io_base)) & MLCISR_NAND_READY) |
|---|
| .. | .. |
|---|
| 349 | 338 | return NAND_STATUS_READY; |
|---|
| 350 | 339 | } |
|---|
| 351 | 340 | |
|---|
| 352 | | -static int lpc32xx_waitfunc_controller(struct mtd_info *mtd, |
|---|
| 353 | | - struct nand_chip *chip) |
|---|
| 341 | +static int lpc32xx_waitfunc_controller(struct nand_chip *chip) |
|---|
| 354 | 342 | { |
|---|
| 343 | + struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 355 | 344 | struct lpc32xx_nand_host *host = nand_get_controller_data(chip); |
|---|
| 356 | 345 | |
|---|
| 357 | 346 | if (readb(MLC_ISR(host->io_base)) & MLCISR_CONTROLLER_READY) |
|---|
| .. | .. |
|---|
| 369 | 358 | return NAND_STATUS_READY; |
|---|
| 370 | 359 | } |
|---|
| 371 | 360 | |
|---|
| 372 | | -static int lpc32xx_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) |
|---|
| 361 | +static int lpc32xx_waitfunc(struct nand_chip *chip) |
|---|
| 373 | 362 | { |
|---|
| 374 | | - lpc32xx_waitfunc_nand(mtd, chip); |
|---|
| 375 | | - lpc32xx_waitfunc_controller(mtd, chip); |
|---|
| 363 | + lpc32xx_waitfunc_nand(chip); |
|---|
| 364 | + lpc32xx_waitfunc_controller(chip); |
|---|
| 376 | 365 | |
|---|
| 377 | 366 | return NAND_STATUS_READY; |
|---|
| 378 | 367 | } |
|---|
| .. | .. |
|---|
| 442 | 431 | return -ENXIO; |
|---|
| 443 | 432 | } |
|---|
| 444 | 433 | |
|---|
| 445 | | -static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip, |
|---|
| 446 | | - uint8_t *buf, int oob_required, int page) |
|---|
| 434 | +static int lpc32xx_read_page(struct nand_chip *chip, uint8_t *buf, |
|---|
| 435 | + int oob_required, int page) |
|---|
| 447 | 436 | { |
|---|
| 437 | + struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 448 | 438 | struct lpc32xx_nand_host *host = nand_get_controller_data(chip); |
|---|
| 449 | 439 | int i, j; |
|---|
| 450 | 440 | uint8_t *oobbuf = chip->oob_poi; |
|---|
| .. | .. |
|---|
| 470 | 460 | writeb(0x00, MLC_ECC_AUTO_DEC_REG(host->io_base)); |
|---|
| 471 | 461 | |
|---|
| 472 | 462 | /* Wait for Controller Ready */ |
|---|
| 473 | | - lpc32xx_waitfunc_controller(mtd, chip); |
|---|
| 463 | + lpc32xx_waitfunc_controller(chip); |
|---|
| 474 | 464 | |
|---|
| 475 | 465 | /* Check ECC Error status */ |
|---|
| 476 | 466 | mlc_isr = readl(MLC_ISR(host->io_base)); |
|---|
| .. | .. |
|---|
| 507 | 497 | return 0; |
|---|
| 508 | 498 | } |
|---|
| 509 | 499 | |
|---|
| 510 | | -static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd, |
|---|
| 511 | | - struct nand_chip *chip, |
|---|
| 500 | +static int lpc32xx_write_page_lowlevel(struct nand_chip *chip, |
|---|
| 512 | 501 | const uint8_t *buf, int oob_required, |
|---|
| 513 | 502 | int page) |
|---|
| 514 | 503 | { |
|---|
| 504 | + struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 515 | 505 | struct lpc32xx_nand_host *host = nand_get_controller_data(chip); |
|---|
| 516 | 506 | const uint8_t *oobbuf = chip->oob_poi; |
|---|
| 517 | 507 | uint8_t *dma_buf = (uint8_t *)buf; |
|---|
| .. | .. |
|---|
| 551 | 541 | writeb(0x00, MLC_ECC_AUTO_ENC_REG(host->io_base)); |
|---|
| 552 | 542 | |
|---|
| 553 | 543 | /* Wait for Controller Ready */ |
|---|
| 554 | | - lpc32xx_waitfunc_controller(mtd, chip); |
|---|
| 544 | + lpc32xx_waitfunc_controller(chip); |
|---|
| 555 | 545 | } |
|---|
| 556 | 546 | |
|---|
| 557 | 547 | return nand_prog_page_end_op(chip); |
|---|
| 558 | 548 | } |
|---|
| 559 | 549 | |
|---|
| 560 | | -static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip, |
|---|
| 561 | | - int page) |
|---|
| 550 | +static int lpc32xx_read_oob(struct nand_chip *chip, int page) |
|---|
| 562 | 551 | { |
|---|
| 563 | 552 | struct lpc32xx_nand_host *host = nand_get_controller_data(chip); |
|---|
| 564 | 553 | |
|---|
| 565 | 554 | /* Read whole page - necessary with MLC controller! */ |
|---|
| 566 | | - lpc32xx_read_page(mtd, chip, host->dummy_buf, 1, page); |
|---|
| 555 | + lpc32xx_read_page(chip, host->dummy_buf, 1, page); |
|---|
| 567 | 556 | |
|---|
| 568 | 557 | return 0; |
|---|
| 569 | 558 | } |
|---|
| 570 | 559 | |
|---|
| 571 | | -static int lpc32xx_write_oob(struct mtd_info *mtd, struct nand_chip *chip, |
|---|
| 572 | | - int page) |
|---|
| 560 | +static int lpc32xx_write_oob(struct nand_chip *chip, int page) |
|---|
| 573 | 561 | { |
|---|
| 574 | 562 | /* None, write_oob conflicts with the automatic LPC MLC ECC decoder! */ |
|---|
| 575 | 563 | return 0; |
|---|
| 576 | 564 | } |
|---|
| 577 | 565 | |
|---|
| 578 | 566 | /* Prepares MLC for transfers with H/W ECC enabled: always enabled anyway */ |
|---|
| 579 | | -static void lpc32xx_ecc_enable(struct mtd_info *mtd, int mode) |
|---|
| 567 | +static void lpc32xx_ecc_enable(struct nand_chip *chip, int mode) |
|---|
| 580 | 568 | { |
|---|
| 581 | 569 | /* Always enabled! */ |
|---|
| 582 | 570 | } |
|---|
| .. | .. |
|---|
| 660 | 648 | struct lpc32xx_nand_host *host = nand_get_controller_data(chip); |
|---|
| 661 | 649 | struct device *dev = &host->pdev->dev; |
|---|
| 662 | 650 | |
|---|
| 651 | + if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST) |
|---|
| 652 | + return 0; |
|---|
| 653 | + |
|---|
| 663 | 654 | host->dma_buf = devm_kzalloc(dev, mtd->writesize, GFP_KERNEL); |
|---|
| 664 | 655 | if (!host->dma_buf) |
|---|
| 665 | 656 | return -ENOMEM; |
|---|
| .. | .. |
|---|
| 668 | 659 | if (!host->dummy_buf) |
|---|
| 669 | 660 | return -ENOMEM; |
|---|
| 670 | 661 | |
|---|
| 671 | | - chip->ecc.mode = NAND_ECC_HW; |
|---|
| 672 | 662 | chip->ecc.size = 512; |
|---|
| 663 | + chip->ecc.hwctl = lpc32xx_ecc_enable; |
|---|
| 664 | + chip->ecc.read_page_raw = lpc32xx_read_page; |
|---|
| 665 | + chip->ecc.read_page = lpc32xx_read_page; |
|---|
| 666 | + chip->ecc.write_page_raw = lpc32xx_write_page_lowlevel; |
|---|
| 667 | + chip->ecc.write_page = lpc32xx_write_page_lowlevel; |
|---|
| 668 | + chip->ecc.write_oob = lpc32xx_write_oob; |
|---|
| 669 | + chip->ecc.read_oob = lpc32xx_read_oob; |
|---|
| 670 | + chip->ecc.strength = 4; |
|---|
| 671 | + chip->ecc.bytes = 10; |
|---|
| 672 | + |
|---|
| 673 | 673 | mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops); |
|---|
| 674 | 674 | host->mlcsubpages = mtd->writesize / 512; |
|---|
| 675 | 675 | |
|---|
| .. | .. |
|---|
| 741 | 741 | if (res) |
|---|
| 742 | 742 | goto put_clk; |
|---|
| 743 | 743 | |
|---|
| 744 | | - nand_chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl; |
|---|
| 745 | | - nand_chip->dev_ready = lpc32xx_nand_device_ready; |
|---|
| 746 | | - nand_chip->chip_delay = 25; /* us */ |
|---|
| 747 | | - nand_chip->IO_ADDR_R = MLC_DATA(host->io_base); |
|---|
| 748 | | - nand_chip->IO_ADDR_W = MLC_DATA(host->io_base); |
|---|
| 744 | + nand_chip->legacy.cmd_ctrl = lpc32xx_nand_cmd_ctrl; |
|---|
| 745 | + nand_chip->legacy.dev_ready = lpc32xx_nand_device_ready; |
|---|
| 746 | + nand_chip->legacy.chip_delay = 25; /* us */ |
|---|
| 747 | + nand_chip->legacy.IO_ADDR_R = MLC_DATA(host->io_base); |
|---|
| 748 | + nand_chip->legacy.IO_ADDR_W = MLC_DATA(host->io_base); |
|---|
| 749 | 749 | |
|---|
| 750 | 750 | /* Init NAND controller */ |
|---|
| 751 | 751 | lpc32xx_nand_setup(host); |
|---|
| .. | .. |
|---|
| 753 | 753 | platform_set_drvdata(pdev, host); |
|---|
| 754 | 754 | |
|---|
| 755 | 755 | /* Initialize function pointers */ |
|---|
| 756 | | - nand_chip->ecc.hwctl = lpc32xx_ecc_enable; |
|---|
| 757 | | - nand_chip->ecc.read_page_raw = lpc32xx_read_page; |
|---|
| 758 | | - nand_chip->ecc.read_page = lpc32xx_read_page; |
|---|
| 759 | | - nand_chip->ecc.write_page_raw = lpc32xx_write_page_lowlevel; |
|---|
| 760 | | - nand_chip->ecc.write_page = lpc32xx_write_page_lowlevel; |
|---|
| 761 | | - nand_chip->ecc.write_oob = lpc32xx_write_oob; |
|---|
| 762 | | - nand_chip->ecc.read_oob = lpc32xx_read_oob; |
|---|
| 763 | | - nand_chip->ecc.strength = 4; |
|---|
| 764 | | - nand_chip->ecc.bytes = 10; |
|---|
| 765 | | - nand_chip->waitfunc = lpc32xx_waitfunc; |
|---|
| 756 | + nand_chip->legacy.waitfunc = lpc32xx_waitfunc; |
|---|
| 766 | 757 | |
|---|
| 767 | 758 | nand_chip->options = NAND_NO_SUBPAGE_WRITE; |
|---|
| 768 | 759 | nand_chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; |
|---|
| .. | .. |
|---|
| 785 | 776 | |
|---|
| 786 | 777 | host->irq = platform_get_irq(pdev, 0); |
|---|
| 787 | 778 | if (host->irq < 0) { |
|---|
| 788 | | - dev_err(&pdev->dev, "failed to get platform irq\n"); |
|---|
| 789 | 779 | res = -EINVAL; |
|---|
| 790 | 780 | goto release_dma_chan; |
|---|
| 791 | 781 | } |
|---|
| .. | .. |
|---|
| 801 | 791 | * Scan to find existence of the device and get the type of NAND device: |
|---|
| 802 | 792 | * SMALL block or LARGE block. |
|---|
| 803 | 793 | */ |
|---|
| 804 | | - nand_chip->dummy_controller.ops = &lpc32xx_nand_controller_ops; |
|---|
| 794 | + nand_chip->legacy.dummy_controller.ops = &lpc32xx_nand_controller_ops; |
|---|
| 805 | 795 | res = nand_scan(nand_chip, 1); |
|---|
| 806 | 796 | if (res) |
|---|
| 807 | 797 | goto free_irq; |
|---|
| .. | .. |
|---|
| 839 | 829 | static int lpc32xx_nand_remove(struct platform_device *pdev) |
|---|
| 840 | 830 | { |
|---|
| 841 | 831 | struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); |
|---|
| 832 | + struct nand_chip *chip = &host->nand_chip; |
|---|
| 833 | + int ret; |
|---|
| 842 | 834 | |
|---|
| 843 | | - nand_release(&host->nand_chip); |
|---|
| 835 | + ret = mtd_device_unregister(nand_to_mtd(chip)); |
|---|
| 836 | + WARN_ON(ret); |
|---|
| 837 | + nand_cleanup(chip); |
|---|
| 838 | + |
|---|
| 844 | 839 | free_irq(host->irq, host); |
|---|
| 845 | 840 | if (use_dma) |
|---|
| 846 | 841 | dma_release_channel(host->dma_chan); |
|---|