| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Hisilicon NAND Flash controller driver |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 7 | 8 | * Author: Zhou Wang <wangzhou.bry@gmail.com> |
|---|
| 8 | 9 | * The initial developer of the original code is Zhiyong Cai |
|---|
| 9 | 10 | * <caizhiyong@huawei.com> |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 12 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 13 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 14 | | - * (at your option) any later version. |
|---|
| 15 | | - * |
|---|
| 16 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 17 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 18 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 19 | | - * GNU General Public License for more details. |
|---|
| 20 | 11 | */ |
|---|
| 21 | 12 | #include <linux/of.h> |
|---|
| 22 | 13 | #include <linux/mtd/mtd.h> |
|---|
| .. | .. |
|---|
| 195 | 186 | hinfc_write(host, host->dma_buffer, HINFC504_DMA_ADDR_DATA); |
|---|
| 196 | 187 | hinfc_write(host, host->dma_oob, HINFC504_DMA_ADDR_OOB); |
|---|
| 197 | 188 | |
|---|
| 198 | | - if (chip->ecc.mode == NAND_ECC_NONE) { |
|---|
| 189 | + if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_NONE) { |
|---|
| 199 | 190 | hinfc_write(host, ((mtd->oobsize & HINFC504_DMA_LEN_OOB_MASK) |
|---|
| 200 | 191 | << HINFC504_DMA_LEN_OOB_SHIFT), HINFC504_DMA_LEN); |
|---|
| 201 | 192 | |
|---|
| .. | .. |
|---|
| 353 | 344 | return 0; |
|---|
| 354 | 345 | } |
|---|
| 355 | 346 | |
|---|
| 356 | | -static void hisi_nfc_select_chip(struct mtd_info *mtd, int chipselect) |
|---|
| 347 | +static void hisi_nfc_select_chip(struct nand_chip *chip, int chipselect) |
|---|
| 357 | 348 | { |
|---|
| 358 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
|---|
| 359 | 349 | struct hinfc_host *host = nand_get_controller_data(chip); |
|---|
| 360 | 350 | |
|---|
| 361 | 351 | if (chipselect < 0) |
|---|
| .. | .. |
|---|
| 364 | 354 | host->chipselect = chipselect; |
|---|
| 365 | 355 | } |
|---|
| 366 | 356 | |
|---|
| 367 | | -static uint8_t hisi_nfc_read_byte(struct mtd_info *mtd) |
|---|
| 357 | +static uint8_t hisi_nfc_read_byte(struct nand_chip *chip) |
|---|
| 368 | 358 | { |
|---|
| 369 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
|---|
| 370 | 359 | struct hinfc_host *host = nand_get_controller_data(chip); |
|---|
| 371 | 360 | |
|---|
| 372 | 361 | if (host->command == NAND_CMD_STATUS) |
|---|
| .. | .. |
|---|
| 380 | 369 | return *(uint8_t *)(host->buffer + host->offset - 1); |
|---|
| 381 | 370 | } |
|---|
| 382 | 371 | |
|---|
| 383 | | -static u16 hisi_nfc_read_word(struct mtd_info *mtd) |
|---|
| 384 | | -{ |
|---|
| 385 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
|---|
| 386 | | - struct hinfc_host *host = nand_get_controller_data(chip); |
|---|
| 387 | | - |
|---|
| 388 | | - host->offset += 2; |
|---|
| 389 | | - return *(u16 *)(host->buffer + host->offset - 2); |
|---|
| 390 | | -} |
|---|
| 391 | | - |
|---|
| 392 | 372 | static void |
|---|
| 393 | | -hisi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) |
|---|
| 373 | +hisi_nfc_write_buf(struct nand_chip *chip, const uint8_t *buf, int len) |
|---|
| 394 | 374 | { |
|---|
| 395 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
|---|
| 396 | 375 | struct hinfc_host *host = nand_get_controller_data(chip); |
|---|
| 397 | 376 | |
|---|
| 398 | 377 | memcpy(host->buffer + host->offset, buf, len); |
|---|
| 399 | 378 | host->offset += len; |
|---|
| 400 | 379 | } |
|---|
| 401 | 380 | |
|---|
| 402 | | -static void hisi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) |
|---|
| 381 | +static void hisi_nfc_read_buf(struct nand_chip *chip, uint8_t *buf, int len) |
|---|
| 403 | 382 | { |
|---|
| 404 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
|---|
| 405 | 383 | struct hinfc_host *host = nand_get_controller_data(chip); |
|---|
| 406 | 384 | |
|---|
| 407 | 385 | memcpy(buf, host->buffer + host->offset, len); |
|---|
| .. | .. |
|---|
| 442 | 420 | } |
|---|
| 443 | 421 | } |
|---|
| 444 | 422 | |
|---|
| 445 | | -static void hisi_nfc_cmdfunc(struct mtd_info *mtd, unsigned command, int column, |
|---|
| 446 | | - int page_addr) |
|---|
| 423 | +static void hisi_nfc_cmdfunc(struct nand_chip *chip, unsigned command, |
|---|
| 424 | + int column, int page_addr) |
|---|
| 447 | 425 | { |
|---|
| 448 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
|---|
| 426 | + struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 449 | 427 | struct hinfc_host *host = nand_get_controller_data(chip); |
|---|
| 450 | 428 | int is_cache_invalid = 1; |
|---|
| 451 | 429 | unsigned int flag = 0; |
|---|
| .. | .. |
|---|
| 490 | 468 | |
|---|
| 491 | 469 | case NAND_CMD_STATUS: |
|---|
| 492 | 470 | flag = hinfc_read(host, HINFC504_CON); |
|---|
| 493 | | - if (chip->ecc.mode == NAND_ECC_HW) |
|---|
| 471 | + if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST) |
|---|
| 494 | 472 | hinfc_write(host, |
|---|
| 495 | 473 | flag & ~(HINFC504_CON_ECCTYPE_MASK << |
|---|
| 496 | 474 | HINFC504_CON_ECCTYPE_SHIFT), HINFC504_CON); |
|---|
| .. | .. |
|---|
| 537 | 515 | return IRQ_HANDLED; |
|---|
| 538 | 516 | } |
|---|
| 539 | 517 | |
|---|
| 540 | | -static int hisi_nand_read_page_hwecc(struct mtd_info *mtd, |
|---|
| 541 | | - struct nand_chip *chip, uint8_t *buf, int oob_required, int page) |
|---|
| 518 | +static int hisi_nand_read_page_hwecc(struct nand_chip *chip, uint8_t *buf, |
|---|
| 519 | + int oob_required, int page) |
|---|
| 542 | 520 | { |
|---|
| 521 | + struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 543 | 522 | struct hinfc_host *host = nand_get_controller_data(chip); |
|---|
| 544 | 523 | int max_bitflips = 0, stat = 0, stat_max = 0, status_ecc; |
|---|
| 545 | 524 | int stat_1, stat_2; |
|---|
| 546 | 525 | |
|---|
| 547 | 526 | nand_read_page_op(chip, page, 0, buf, mtd->writesize); |
|---|
| 548 | | - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); |
|---|
| 527 | + chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize); |
|---|
| 549 | 528 | |
|---|
| 550 | 529 | /* errors which can not be corrected by ECC */ |
|---|
| 551 | 530 | if (host->irq_status & HINFC504_INTS_UE) { |
|---|
| .. | .. |
|---|
| 569 | 548 | return max_bitflips; |
|---|
| 570 | 549 | } |
|---|
| 571 | 550 | |
|---|
| 572 | | -static int hisi_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, |
|---|
| 573 | | - int page) |
|---|
| 551 | +static int hisi_nand_read_oob(struct nand_chip *chip, int page) |
|---|
| 574 | 552 | { |
|---|
| 553 | + struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 575 | 554 | struct hinfc_host *host = nand_get_controller_data(chip); |
|---|
| 576 | 555 | |
|---|
| 577 | 556 | nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize); |
|---|
| .. | .. |
|---|
| 585 | 564 | return 0; |
|---|
| 586 | 565 | } |
|---|
| 587 | 566 | |
|---|
| 588 | | -static int hisi_nand_write_page_hwecc(struct mtd_info *mtd, |
|---|
| 589 | | - struct nand_chip *chip, const uint8_t *buf, int oob_required, |
|---|
| 590 | | - int page) |
|---|
| 567 | +static int hisi_nand_write_page_hwecc(struct nand_chip *chip, |
|---|
| 568 | + const uint8_t *buf, int oob_required, |
|---|
| 569 | + int page) |
|---|
| 591 | 570 | { |
|---|
| 571 | + struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 572 | + |
|---|
| 592 | 573 | nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize); |
|---|
| 593 | 574 | if (oob_required) |
|---|
| 594 | | - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); |
|---|
| 575 | + chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize); |
|---|
| 595 | 576 | |
|---|
| 596 | 577 | return nand_prog_page_end_op(chip); |
|---|
| 597 | 578 | } |
|---|
| .. | .. |
|---|
| 740 | 721 | } |
|---|
| 741 | 722 | hinfc_write(host, flag, HINFC504_CON); |
|---|
| 742 | 723 | |
|---|
| 743 | | - if (chip->ecc.mode == NAND_ECC_HW) |
|---|
| 724 | + if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST) |
|---|
| 744 | 725 | hisi_nfc_ecc_probe(host); |
|---|
| 745 | 726 | |
|---|
| 746 | 727 | return 0; |
|---|
| .. | .. |
|---|
| 770 | 751 | mtd = nand_to_mtd(chip); |
|---|
| 771 | 752 | |
|---|
| 772 | 753 | irq = platform_get_irq(pdev, 0); |
|---|
| 773 | | - if (irq < 0) { |
|---|
| 774 | | - dev_err(dev, "no IRQ resource defined\n"); |
|---|
| 754 | + if (irq < 0) |
|---|
| 775 | 755 | return -ENXIO; |
|---|
| 776 | | - } |
|---|
| 777 | 756 | |
|---|
| 778 | 757 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 779 | 758 | host->iobase = devm_ioremap_resource(dev, res); |
|---|
| .. | .. |
|---|
| 792 | 771 | |
|---|
| 793 | 772 | nand_set_controller_data(chip, host); |
|---|
| 794 | 773 | nand_set_flash_node(chip, np); |
|---|
| 795 | | - chip->cmdfunc = hisi_nfc_cmdfunc; |
|---|
| 796 | | - chip->select_chip = hisi_nfc_select_chip; |
|---|
| 797 | | - chip->read_byte = hisi_nfc_read_byte; |
|---|
| 798 | | - chip->read_word = hisi_nfc_read_word; |
|---|
| 799 | | - chip->write_buf = hisi_nfc_write_buf; |
|---|
| 800 | | - chip->read_buf = hisi_nfc_read_buf; |
|---|
| 801 | | - chip->chip_delay = HINFC504_CHIP_DELAY; |
|---|
| 802 | | - chip->set_features = nand_get_set_features_notsupp; |
|---|
| 803 | | - chip->get_features = nand_get_set_features_notsupp; |
|---|
| 774 | + chip->legacy.cmdfunc = hisi_nfc_cmdfunc; |
|---|
| 775 | + chip->legacy.select_chip = hisi_nfc_select_chip; |
|---|
| 776 | + chip->legacy.read_byte = hisi_nfc_read_byte; |
|---|
| 777 | + chip->legacy.write_buf = hisi_nfc_write_buf; |
|---|
| 778 | + chip->legacy.read_buf = hisi_nfc_read_buf; |
|---|
| 779 | + chip->legacy.chip_delay = HINFC504_CHIP_DELAY; |
|---|
| 780 | + chip->legacy.set_features = nand_get_set_features_notsupp; |
|---|
| 781 | + chip->legacy.get_features = nand_get_set_features_notsupp; |
|---|
| 804 | 782 | |
|---|
| 805 | 783 | hisi_nfc_host_init(host); |
|---|
| 806 | 784 | |
|---|
| .. | .. |
|---|
| 810 | 788 | return ret; |
|---|
| 811 | 789 | } |
|---|
| 812 | 790 | |
|---|
| 813 | | - chip->dummy_controller.ops = &hisi_nfc_controller_ops; |
|---|
| 791 | + chip->legacy.dummy_controller.ops = &hisi_nfc_controller_ops; |
|---|
| 814 | 792 | ret = nand_scan(chip, max_chips); |
|---|
| 815 | 793 | if (ret) |
|---|
| 816 | 794 | return ret; |
|---|
| .. | .. |
|---|
| 828 | 806 | static int hisi_nfc_remove(struct platform_device *pdev) |
|---|
| 829 | 807 | { |
|---|
| 830 | 808 | struct hinfc_host *host = platform_get_drvdata(pdev); |
|---|
| 809 | + struct nand_chip *chip = &host->chip; |
|---|
| 810 | + int ret; |
|---|
| 831 | 811 | |
|---|
| 832 | | - nand_release(&host->chip); |
|---|
| 812 | + ret = mtd_device_unregister(nand_to_mtd(chip)); |
|---|
| 813 | + WARN_ON(ret); |
|---|
| 814 | + nand_cleanup(chip); |
|---|
| 833 | 815 | |
|---|
| 834 | 816 | return 0; |
|---|
| 835 | 817 | } |
|---|
| .. | .. |
|---|
| 860 | 842 | struct hinfc_host *host = dev_get_drvdata(dev); |
|---|
| 861 | 843 | struct nand_chip *chip = &host->chip; |
|---|
| 862 | 844 | |
|---|
| 863 | | - for (cs = 0; cs < chip->numchips; cs++) |
|---|
| 845 | + for (cs = 0; cs < nanddev_ntargets(&chip->base); cs++) |
|---|
| 864 | 846 | hisi_nfc_send_cmd_reset(host, cs); |
|---|
| 865 | 847 | hinfc_write(host, SET_HINFC504_PWIDTH(HINFC504_W_LATCH, |
|---|
| 866 | 848 | HINFC504_R_LATCH, HINFC504_RW_LATCH), HINFC504_PWIDTH); |
|---|