.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0+ |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright 2009-2015 Freescale Semiconductor, Inc. and others |
---|
3 | 4 | * |
---|
.. | .. |
---|
9 | 10 | * Jason Jin <Jason.jin@freescale.com> |
---|
10 | 11 | * |
---|
11 | 12 | * Based on original driver mpc5121_nfc.c. |
---|
12 | | - * |
---|
13 | | - * This is free software; you can redistribute it and/or modify it |
---|
14 | | - * under the terms of the GNU General Public License as published by |
---|
15 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
16 | | - * (at your option) any later version. |
---|
17 | 13 | * |
---|
18 | 14 | * Limitations: |
---|
19 | 15 | * - Untested on MPC5125 and M54418. |
---|
.. | .. |
---|
152 | 148 | }; |
---|
153 | 149 | |
---|
154 | 150 | struct vf610_nfc { |
---|
| 151 | + struct nand_controller base; |
---|
155 | 152 | struct nand_chip chip; |
---|
156 | 153 | struct device *dev; |
---|
157 | 154 | void __iomem *regs; |
---|
.. | .. |
---|
167 | 164 | bool data_access; |
---|
168 | 165 | u32 ecc_mode; |
---|
169 | 166 | }; |
---|
170 | | - |
---|
171 | | -static inline struct vf610_nfc *mtd_to_nfc(struct mtd_info *mtd) |
---|
172 | | -{ |
---|
173 | | - return container_of(mtd_to_nand(mtd), struct vf610_nfc, chip); |
---|
174 | | -} |
---|
175 | 167 | |
---|
176 | 168 | static inline struct vf610_nfc *chip_to_nfc(struct nand_chip *chip) |
---|
177 | 169 | { |
---|
.. | .. |
---|
316 | 308 | |
---|
317 | 309 | static irqreturn_t vf610_nfc_irq(int irq, void *data) |
---|
318 | 310 | { |
---|
319 | | - struct mtd_info *mtd = data; |
---|
320 | | - struct vf610_nfc *nfc = mtd_to_nfc(mtd); |
---|
| 311 | + struct vf610_nfc *nfc = data; |
---|
321 | 312 | |
---|
322 | 313 | vf610_nfc_clear(nfc, NFC_IRQ_STATUS, IDLE_EN_BIT); |
---|
323 | 314 | complete(&nfc->cmd_done); |
---|
.. | .. |
---|
330 | 321 | vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG, |
---|
331 | 322 | CONFIG_ECC_MODE_MASK, |
---|
332 | 323 | CONFIG_ECC_MODE_SHIFT, ecc_mode); |
---|
333 | | -} |
---|
334 | | - |
---|
335 | | -static inline void vf610_nfc_transfer_size(struct vf610_nfc *nfc, int size) |
---|
336 | | -{ |
---|
337 | | - vf610_nfc_write(nfc, NFC_SECTOR_SIZE, size); |
---|
338 | 324 | } |
---|
339 | 325 | |
---|
340 | 326 | static inline void vf610_nfc_run(struct vf610_nfc *nfc, u32 col, u32 row, |
---|
.. | .. |
---|
373 | 359 | { |
---|
374 | 360 | const struct nand_op_instr *instr; |
---|
375 | 361 | struct vf610_nfc *nfc = chip_to_nfc(chip); |
---|
376 | | - int op_id = -1, trfr_sz = 0, offset; |
---|
| 362 | + int op_id = -1, trfr_sz = 0, offset = 0; |
---|
377 | 363 | u32 col = 0, row = 0, cmd1 = 0, cmd2 = 0, code = 0; |
---|
378 | 364 | bool force8bit = false; |
---|
379 | 365 | |
---|
.. | .. |
---|
487 | 473 | NAND_OP_PARSER_PAT_DATA_IN_ELEM(true, PAGE_2K + OOB_MAX)), |
---|
488 | 474 | ); |
---|
489 | 475 | |
---|
490 | | -static int vf610_nfc_exec_op(struct nand_chip *chip, |
---|
491 | | - const struct nand_operation *op, |
---|
492 | | - bool check_only) |
---|
493 | | -{ |
---|
494 | | - return nand_op_parser_exec_op(chip, &vf610_nfc_op_parser, op, |
---|
495 | | - check_only); |
---|
496 | | -} |
---|
497 | | - |
---|
498 | 476 | /* |
---|
499 | 477 | * This function supports Vybrid only (MPC5125 would have full RB and four CS) |
---|
500 | 478 | */ |
---|
501 | | -static void vf610_nfc_select_chip(struct mtd_info *mtd, int chip) |
---|
| 479 | +static void vf610_nfc_select_target(struct nand_chip *chip, unsigned int cs) |
---|
502 | 480 | { |
---|
503 | | - struct vf610_nfc *nfc = mtd_to_nfc(mtd); |
---|
504 | | - u32 tmp = vf610_nfc_read(nfc, NFC_ROW_ADDR); |
---|
| 481 | + struct vf610_nfc *nfc = chip_to_nfc(chip); |
---|
| 482 | + u32 tmp; |
---|
505 | 483 | |
---|
506 | 484 | /* Vybrid only (MPC5125 would have full RB and four CS) */ |
---|
507 | 485 | if (nfc->variant != NFC_VFC610) |
---|
508 | 486 | return; |
---|
509 | 487 | |
---|
| 488 | + tmp = vf610_nfc_read(nfc, NFC_ROW_ADDR); |
---|
510 | 489 | tmp &= ~(ROW_ADDR_CHIP_SEL_RB_MASK | ROW_ADDR_CHIP_SEL_MASK); |
---|
511 | | - |
---|
512 | | - if (chip >= 0) { |
---|
513 | | - tmp |= 1 << ROW_ADDR_CHIP_SEL_RB_SHIFT; |
---|
514 | | - tmp |= BIT(chip) << ROW_ADDR_CHIP_SEL_SHIFT; |
---|
515 | | - } |
---|
| 490 | + tmp |= 1 << ROW_ADDR_CHIP_SEL_RB_SHIFT; |
---|
| 491 | + tmp |= BIT(cs) << ROW_ADDR_CHIP_SEL_SHIFT; |
---|
516 | 492 | |
---|
517 | 493 | vf610_nfc_write(nfc, NFC_ROW_ADDR, tmp); |
---|
518 | 494 | } |
---|
519 | 495 | |
---|
520 | | -static inline int vf610_nfc_correct_data(struct mtd_info *mtd, uint8_t *dat, |
---|
| 496 | +static int vf610_nfc_exec_op(struct nand_chip *chip, |
---|
| 497 | + const struct nand_operation *op, |
---|
| 498 | + bool check_only) |
---|
| 499 | +{ |
---|
| 500 | + if (!check_only) |
---|
| 501 | + vf610_nfc_select_target(chip, op->cs); |
---|
| 502 | + |
---|
| 503 | + return nand_op_parser_exec_op(chip, &vf610_nfc_op_parser, op, |
---|
| 504 | + check_only); |
---|
| 505 | +} |
---|
| 506 | + |
---|
| 507 | +static inline int vf610_nfc_correct_data(struct nand_chip *chip, uint8_t *dat, |
---|
521 | 508 | uint8_t *oob, int page) |
---|
522 | 509 | { |
---|
523 | | - struct vf610_nfc *nfc = mtd_to_nfc(mtd); |
---|
| 510 | + struct vf610_nfc *nfc = chip_to_nfc(chip); |
---|
| 511 | + struct mtd_info *mtd = nand_to_mtd(chip); |
---|
524 | 512 | u32 ecc_status_off = NFC_MAIN_AREA(0) + ECC_SRAM_ADDR + ECC_STATUS; |
---|
525 | 513 | u8 ecc_status; |
---|
526 | 514 | u8 ecc_count; |
---|
.. | .. |
---|
557 | 545 | } |
---|
558 | 546 | } |
---|
559 | 547 | |
---|
560 | | -static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip, |
---|
561 | | - uint8_t *buf, int oob_required, int page) |
---|
| 548 | +static int vf610_nfc_read_page(struct nand_chip *chip, uint8_t *buf, |
---|
| 549 | + int oob_required, int page) |
---|
562 | 550 | { |
---|
563 | | - struct vf610_nfc *nfc = mtd_to_nfc(mtd); |
---|
| 551 | + struct vf610_nfc *nfc = chip_to_nfc(chip); |
---|
| 552 | + struct mtd_info *mtd = nand_to_mtd(chip); |
---|
564 | 553 | int trfr_sz = mtd->writesize + mtd->oobsize; |
---|
565 | 554 | u32 row = 0, cmd1 = 0, cmd2 = 0, code = 0; |
---|
566 | 555 | int stat; |
---|
| 556 | + |
---|
| 557 | + vf610_nfc_select_target(chip, chip->cur_cs); |
---|
567 | 558 | |
---|
568 | 559 | cmd2 |= NAND_CMD_READ0 << CMD_BYTE1_SHIFT; |
---|
569 | 560 | code |= COMMAND_CMD_BYTE1 | COMMAND_CAR_BYTE1 | COMMAND_CAR_BYTE2; |
---|
.. | .. |
---|
591 | 582 | mtd->writesize, |
---|
592 | 583 | mtd->oobsize, false); |
---|
593 | 584 | |
---|
594 | | - stat = vf610_nfc_correct_data(mtd, buf, chip->oob_poi, page); |
---|
| 585 | + stat = vf610_nfc_correct_data(chip, buf, chip->oob_poi, page); |
---|
595 | 586 | |
---|
596 | 587 | if (stat < 0) { |
---|
597 | 588 | mtd->ecc_stats.failed++; |
---|
.. | .. |
---|
602 | 593 | } |
---|
603 | 594 | } |
---|
604 | 595 | |
---|
605 | | -static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip, |
---|
606 | | - const uint8_t *buf, int oob_required, int page) |
---|
| 596 | +static int vf610_nfc_write_page(struct nand_chip *chip, const uint8_t *buf, |
---|
| 597 | + int oob_required, int page) |
---|
607 | 598 | { |
---|
608 | | - struct vf610_nfc *nfc = mtd_to_nfc(mtd); |
---|
| 599 | + struct vf610_nfc *nfc = chip_to_nfc(chip); |
---|
| 600 | + struct mtd_info *mtd = nand_to_mtd(chip); |
---|
609 | 601 | int trfr_sz = mtd->writesize + mtd->oobsize; |
---|
610 | 602 | u32 row = 0, cmd1 = 0, cmd2 = 0, code = 0; |
---|
611 | 603 | u8 status; |
---|
612 | 604 | int ret; |
---|
| 605 | + |
---|
| 606 | + vf610_nfc_select_target(chip, chip->cur_cs); |
---|
613 | 607 | |
---|
614 | 608 | cmd2 |= NAND_CMD_SEQIN << CMD_BYTE1_SHIFT; |
---|
615 | 609 | code |= COMMAND_CMD_BYTE1 | COMMAND_CAR_BYTE1 | COMMAND_CAR_BYTE2; |
---|
.. | .. |
---|
643 | 637 | return 0; |
---|
644 | 638 | } |
---|
645 | 639 | |
---|
646 | | -static int vf610_nfc_read_page_raw(struct mtd_info *mtd, |
---|
647 | | - struct nand_chip *chip, u8 *buf, |
---|
| 640 | +static int vf610_nfc_read_page_raw(struct nand_chip *chip, u8 *buf, |
---|
648 | 641 | int oob_required, int page) |
---|
649 | 642 | { |
---|
650 | | - struct vf610_nfc *nfc = mtd_to_nfc(mtd); |
---|
| 643 | + struct vf610_nfc *nfc = chip_to_nfc(chip); |
---|
651 | 644 | int ret; |
---|
652 | 645 | |
---|
653 | 646 | nfc->data_access = true; |
---|
654 | | - ret = nand_read_page_raw(mtd, chip, buf, oob_required, page); |
---|
| 647 | + ret = nand_read_page_raw(chip, buf, oob_required, page); |
---|
655 | 648 | nfc->data_access = false; |
---|
656 | 649 | |
---|
657 | 650 | return ret; |
---|
658 | 651 | } |
---|
659 | 652 | |
---|
660 | | -static int vf610_nfc_write_page_raw(struct mtd_info *mtd, |
---|
661 | | - struct nand_chip *chip, const u8 *buf, |
---|
| 653 | +static int vf610_nfc_write_page_raw(struct nand_chip *chip, const u8 *buf, |
---|
662 | 654 | int oob_required, int page) |
---|
663 | 655 | { |
---|
664 | | - struct vf610_nfc *nfc = mtd_to_nfc(mtd); |
---|
| 656 | + struct vf610_nfc *nfc = chip_to_nfc(chip); |
---|
| 657 | + struct mtd_info *mtd = nand_to_mtd(chip); |
---|
665 | 658 | int ret; |
---|
666 | 659 | |
---|
667 | 660 | nfc->data_access = true; |
---|
.. | .. |
---|
677 | 670 | return nand_prog_page_end_op(chip); |
---|
678 | 671 | } |
---|
679 | 672 | |
---|
680 | | -static int vf610_nfc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, |
---|
681 | | - int page) |
---|
| 673 | +static int vf610_nfc_read_oob(struct nand_chip *chip, int page) |
---|
682 | 674 | { |
---|
683 | | - struct vf610_nfc *nfc = mtd_to_nfc(mtd); |
---|
| 675 | + struct vf610_nfc *nfc = chip_to_nfc(chip); |
---|
684 | 676 | int ret; |
---|
685 | 677 | |
---|
686 | 678 | nfc->data_access = true; |
---|
687 | | - ret = nand_read_oob_std(mtd, chip, page); |
---|
| 679 | + ret = nand_read_oob_std(chip, page); |
---|
688 | 680 | nfc->data_access = false; |
---|
689 | 681 | |
---|
690 | 682 | return ret; |
---|
691 | 683 | } |
---|
692 | 684 | |
---|
693 | | -static int vf610_nfc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, |
---|
694 | | - int page) |
---|
| 685 | +static int vf610_nfc_write_oob(struct nand_chip *chip, int page) |
---|
695 | 686 | { |
---|
696 | | - struct vf610_nfc *nfc = mtd_to_nfc(mtd); |
---|
| 687 | + struct mtd_info *mtd = nand_to_mtd(chip); |
---|
| 688 | + struct vf610_nfc *nfc = chip_to_nfc(chip); |
---|
697 | 689 | int ret; |
---|
698 | 690 | |
---|
699 | 691 | nfc->data_access = true; |
---|
.. | .. |
---|
735 | 727 | else |
---|
736 | 728 | vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT); |
---|
737 | 729 | |
---|
738 | | - if (nfc->chip.ecc.mode == NAND_ECC_HW) { |
---|
| 730 | + if (nfc->chip.ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST) { |
---|
739 | 731 | /* Set ECC status offset in SRAM */ |
---|
740 | 732 | vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG, |
---|
741 | 733 | CONFIG_ECC_SRAM_ADDR_MASK, |
---|
.. | .. |
---|
750 | 742 | static int vf610_nfc_attach_chip(struct nand_chip *chip) |
---|
751 | 743 | { |
---|
752 | 744 | struct mtd_info *mtd = nand_to_mtd(chip); |
---|
753 | | - struct vf610_nfc *nfc = mtd_to_nfc(mtd); |
---|
| 745 | + struct vf610_nfc *nfc = chip_to_nfc(chip); |
---|
754 | 746 | |
---|
755 | 747 | vf610_nfc_init_controller(nfc); |
---|
756 | 748 | |
---|
.. | .. |
---|
764 | 756 | return -ENXIO; |
---|
765 | 757 | } |
---|
766 | 758 | |
---|
767 | | - if (chip->ecc.mode != NAND_ECC_HW) |
---|
| 759 | + if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST) |
---|
768 | 760 | return 0; |
---|
769 | 761 | |
---|
770 | 762 | if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) { |
---|
.. | .. |
---|
782 | 774 | mtd->oobsize = 64; |
---|
783 | 775 | |
---|
784 | 776 | /* Use default large page ECC layout defined in NAND core */ |
---|
785 | | - mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops); |
---|
| 777 | + mtd_set_ooblayout(mtd, nand_get_large_page_ooblayout()); |
---|
786 | 778 | if (chip->ecc.strength == 32) { |
---|
787 | 779 | nfc->ecc_mode = ECC_60_BYTE; |
---|
788 | 780 | chip->ecc.bytes = 60; |
---|
.. | .. |
---|
808 | 800 | |
---|
809 | 801 | static const struct nand_controller_ops vf610_nfc_controller_ops = { |
---|
810 | 802 | .attach_chip = vf610_nfc_attach_chip, |
---|
| 803 | + .exec_op = vf610_nfc_exec_op, |
---|
| 804 | + |
---|
811 | 805 | }; |
---|
812 | 806 | |
---|
813 | 807 | static int vf610_nfc_probe(struct platform_device *pdev) |
---|
.. | .. |
---|
853 | 847 | } |
---|
854 | 848 | |
---|
855 | 849 | of_id = of_match_device(vf610_nfc_dt_ids, &pdev->dev); |
---|
| 850 | + if (!of_id) { |
---|
| 851 | + err = -ENODEV; |
---|
| 852 | + goto err_disable_clk; |
---|
| 853 | + } |
---|
| 854 | + |
---|
856 | 855 | nfc->variant = (enum vf610_nfc_variant)of_id->data; |
---|
857 | 856 | |
---|
858 | 857 | for_each_available_child_of_node(nfc->dev->of_node, child) { |
---|
.. | .. |
---|
862 | 861 | dev_err(nfc->dev, |
---|
863 | 862 | "Only one NAND chip supported!\n"); |
---|
864 | 863 | err = -EINVAL; |
---|
| 864 | + of_node_put(child); |
---|
865 | 865 | goto err_disable_clk; |
---|
866 | 866 | } |
---|
867 | 867 | |
---|
.. | .. |
---|
875 | 875 | goto err_disable_clk; |
---|
876 | 876 | } |
---|
877 | 877 | |
---|
878 | | - chip->exec_op = vf610_nfc_exec_op; |
---|
879 | | - chip->select_chip = vf610_nfc_select_chip; |
---|
880 | | - |
---|
881 | 878 | chip->options |= NAND_NO_SUBPAGE_WRITE; |
---|
882 | 879 | |
---|
883 | 880 | init_completion(&nfc->cmd_done); |
---|
884 | 881 | |
---|
885 | | - err = devm_request_irq(nfc->dev, irq, vf610_nfc_irq, 0, DRV_NAME, mtd); |
---|
| 882 | + err = devm_request_irq(nfc->dev, irq, vf610_nfc_irq, 0, DRV_NAME, nfc); |
---|
886 | 883 | if (err) { |
---|
887 | 884 | dev_err(nfc->dev, "Error requesting IRQ!\n"); |
---|
888 | 885 | goto err_disable_clk; |
---|
.. | .. |
---|
890 | 887 | |
---|
891 | 888 | vf610_nfc_preinit_controller(nfc); |
---|
892 | 889 | |
---|
| 890 | + nand_controller_init(&nfc->base); |
---|
| 891 | + nfc->base.ops = &vf610_nfc_controller_ops; |
---|
| 892 | + chip->controller = &nfc->base; |
---|
| 893 | + |
---|
893 | 894 | /* Scan the NAND chip */ |
---|
894 | | - chip->dummy_controller.ops = &vf610_nfc_controller_ops; |
---|
895 | 895 | err = nand_scan(chip, 1); |
---|
896 | 896 | if (err) |
---|
897 | 897 | goto err_disable_clk; |
---|
898 | 898 | |
---|
899 | | - platform_set_drvdata(pdev, mtd); |
---|
| 899 | + platform_set_drvdata(pdev, nfc); |
---|
900 | 900 | |
---|
901 | 901 | /* Register device in MTD */ |
---|
902 | 902 | err = mtd_device_register(mtd, NULL, 0); |
---|
.. | .. |
---|
913 | 913 | |
---|
914 | 914 | static int vf610_nfc_remove(struct platform_device *pdev) |
---|
915 | 915 | { |
---|
916 | | - struct mtd_info *mtd = platform_get_drvdata(pdev); |
---|
917 | | - struct vf610_nfc *nfc = mtd_to_nfc(mtd); |
---|
| 916 | + struct vf610_nfc *nfc = platform_get_drvdata(pdev); |
---|
| 917 | + struct nand_chip *chip = &nfc->chip; |
---|
| 918 | + int ret; |
---|
918 | 919 | |
---|
919 | | - nand_release(mtd_to_nand(mtd)); |
---|
| 920 | + ret = mtd_device_unregister(nand_to_mtd(chip)); |
---|
| 921 | + WARN_ON(ret); |
---|
| 922 | + nand_cleanup(chip); |
---|
920 | 923 | clk_disable_unprepare(nfc->clk); |
---|
921 | 924 | return 0; |
---|
922 | 925 | } |
---|
.. | .. |
---|
924 | 927 | #ifdef CONFIG_PM_SLEEP |
---|
925 | 928 | static int vf610_nfc_suspend(struct device *dev) |
---|
926 | 929 | { |
---|
927 | | - struct mtd_info *mtd = dev_get_drvdata(dev); |
---|
928 | | - struct vf610_nfc *nfc = mtd_to_nfc(mtd); |
---|
| 930 | + struct vf610_nfc *nfc = dev_get_drvdata(dev); |
---|
929 | 931 | |
---|
930 | 932 | clk_disable_unprepare(nfc->clk); |
---|
931 | 933 | return 0; |
---|
.. | .. |
---|
933 | 935 | |
---|
934 | 936 | static int vf610_nfc_resume(struct device *dev) |
---|
935 | 937 | { |
---|
| 938 | + struct vf610_nfc *nfc = dev_get_drvdata(dev); |
---|
936 | 939 | int err; |
---|
937 | | - |
---|
938 | | - struct mtd_info *mtd = dev_get_drvdata(dev); |
---|
939 | | - struct vf610_nfc *nfc = mtd_to_nfc(mtd); |
---|
940 | 940 | |
---|
941 | 941 | err = clk_prepare_enable(nfc->clk); |
---|
942 | 942 | if (err) |
---|