| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 OR MIT |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * MTK NAND Flash controller driver. |
|---|
| 3 | 4 | * Copyright (C) 2016 MediaTek Inc. |
|---|
| 4 | 5 | * Authors: Xiaolei Li <xiaolei.li@mediatek.com> |
|---|
| 5 | 6 | * Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org> |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 8 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 9 | | - * published by the Free Software Foundation. |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 12 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 14 | | - * GNU General Public License for more details. |
|---|
| 15 | 7 | */ |
|---|
| 16 | 8 | |
|---|
| 17 | 9 | #include <linux/platform_device.h> |
|---|
| .. | .. |
|---|
| 87 | 79 | #define NFI_FDMM(x) (0xA4 + (x) * sizeof(u32) * 2) |
|---|
| 88 | 80 | #define NFI_FDM_MAX_SIZE (8) |
|---|
| 89 | 81 | #define NFI_FDM_MIN_SIZE (1) |
|---|
| 82 | +#define NFI_DEBUG_CON1 (0x220) |
|---|
| 83 | +#define STROBE_MASK GENMASK(4, 3) |
|---|
| 84 | +#define STROBE_SHIFT (3) |
|---|
| 85 | +#define MAX_STROBE_DLY (3) |
|---|
| 90 | 86 | #define NFI_MASTER_STA (0x224) |
|---|
| 91 | 87 | #define MASTER_STA_MASK (0x0FFF) |
|---|
| 92 | 88 | #define NFI_EMPTY_THRESH (0x23C) |
|---|
| .. | .. |
|---|
| 135 | 131 | u32 spare_per_sector; |
|---|
| 136 | 132 | |
|---|
| 137 | 133 | int nsels; |
|---|
| 138 | | - u8 sels[0]; |
|---|
| 134 | + u8 sels[]; |
|---|
| 139 | 135 | /* nothing after this field */ |
|---|
| 140 | 136 | }; |
|---|
| 141 | 137 | |
|---|
| .. | .. |
|---|
| 158 | 154 | struct list_head chips; |
|---|
| 159 | 155 | |
|---|
| 160 | 156 | u8 *buffer; |
|---|
| 157 | + |
|---|
| 158 | + unsigned long assigned_cs; |
|---|
| 161 | 159 | }; |
|---|
| 162 | 160 | |
|---|
| 163 | 161 | /* |
|---|
| .. | .. |
|---|
| 389 | 387 | return 0; |
|---|
| 390 | 388 | } |
|---|
| 391 | 389 | |
|---|
| 392 | | -static void mtk_nfc_select_chip(struct mtd_info *mtd, int chip) |
|---|
| 393 | | -{ |
|---|
| 394 | | - struct nand_chip *nand = mtd_to_nand(mtd); |
|---|
| 395 | | - struct mtk_nfc *nfc = nand_get_controller_data(nand); |
|---|
| 396 | | - struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(nand); |
|---|
| 397 | | - |
|---|
| 398 | | - if (chip < 0) |
|---|
| 399 | | - return; |
|---|
| 400 | | - |
|---|
| 401 | | - mtk_nfc_hw_runtime_config(mtd); |
|---|
| 402 | | - |
|---|
| 403 | | - nfi_writel(nfc, mtk_nand->sels[chip], NFI_CSEL); |
|---|
| 404 | | -} |
|---|
| 405 | | - |
|---|
| 406 | | -static int mtk_nfc_dev_ready(struct mtd_info *mtd) |
|---|
| 407 | | -{ |
|---|
| 408 | | - struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd)); |
|---|
| 409 | | - |
|---|
| 410 | | - if (nfi_readl(nfc, NFI_STA) & STA_BUSY) |
|---|
| 411 | | - return 0; |
|---|
| 412 | | - |
|---|
| 413 | | - return 1; |
|---|
| 414 | | -} |
|---|
| 415 | | - |
|---|
| 416 | | -static void mtk_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) |
|---|
| 417 | | -{ |
|---|
| 418 | | - struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd)); |
|---|
| 419 | | - |
|---|
| 420 | | - if (ctrl & NAND_ALE) { |
|---|
| 421 | | - mtk_nfc_send_address(nfc, dat); |
|---|
| 422 | | - } else if (ctrl & NAND_CLE) { |
|---|
| 423 | | - mtk_nfc_hw_reset(nfc); |
|---|
| 424 | | - |
|---|
| 425 | | - nfi_writew(nfc, CNFG_OP_CUST, NFI_CNFG); |
|---|
| 426 | | - mtk_nfc_send_command(nfc, dat); |
|---|
| 427 | | - } |
|---|
| 428 | | -} |
|---|
| 429 | | - |
|---|
| 430 | 390 | static inline void mtk_nfc_wait_ioready(struct mtk_nfc *nfc) |
|---|
| 431 | 391 | { |
|---|
| 432 | 392 | int rc; |
|---|
| .. | .. |
|---|
| 438 | 398 | dev_err(nfc->dev, "data not ready\n"); |
|---|
| 439 | 399 | } |
|---|
| 440 | 400 | |
|---|
| 441 | | -static inline u8 mtk_nfc_read_byte(struct mtd_info *mtd) |
|---|
| 401 | +static inline u8 mtk_nfc_read_byte(struct nand_chip *chip) |
|---|
| 442 | 402 | { |
|---|
| 443 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
|---|
| 444 | 403 | struct mtk_nfc *nfc = nand_get_controller_data(chip); |
|---|
| 445 | 404 | u32 reg; |
|---|
| 446 | 405 | |
|---|
| .. | .. |
|---|
| 467 | 426 | return nfi_readb(nfc, NFI_DATAR); |
|---|
| 468 | 427 | } |
|---|
| 469 | 428 | |
|---|
| 470 | | -static void mtk_nfc_read_buf(struct mtd_info *mtd, u8 *buf, int len) |
|---|
| 429 | +static void mtk_nfc_read_buf(struct nand_chip *chip, u8 *buf, int len) |
|---|
| 471 | 430 | { |
|---|
| 472 | 431 | int i; |
|---|
| 473 | 432 | |
|---|
| 474 | 433 | for (i = 0; i < len; i++) |
|---|
| 475 | | - buf[i] = mtk_nfc_read_byte(mtd); |
|---|
| 434 | + buf[i] = mtk_nfc_read_byte(chip); |
|---|
| 476 | 435 | } |
|---|
| 477 | 436 | |
|---|
| 478 | | -static void mtk_nfc_write_byte(struct mtd_info *mtd, u8 byte) |
|---|
| 437 | +static void mtk_nfc_write_byte(struct nand_chip *chip, u8 byte) |
|---|
| 479 | 438 | { |
|---|
| 480 | | - struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd)); |
|---|
| 439 | + struct mtk_nfc *nfc = nand_get_controller_data(chip); |
|---|
| 481 | 440 | u32 reg; |
|---|
| 482 | 441 | |
|---|
| 483 | 442 | reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK; |
|---|
| .. | .. |
|---|
| 496 | 455 | nfi_writeb(nfc, byte, NFI_DATAW); |
|---|
| 497 | 456 | } |
|---|
| 498 | 457 | |
|---|
| 499 | | -static void mtk_nfc_write_buf(struct mtd_info *mtd, const u8 *buf, int len) |
|---|
| 458 | +static void mtk_nfc_write_buf(struct nand_chip *chip, const u8 *buf, int len) |
|---|
| 500 | 459 | { |
|---|
| 501 | 460 | int i; |
|---|
| 502 | 461 | |
|---|
| 503 | 462 | for (i = 0; i < len; i++) |
|---|
| 504 | | - mtk_nfc_write_byte(mtd, buf[i]); |
|---|
| 463 | + mtk_nfc_write_byte(chip, buf[i]); |
|---|
| 505 | 464 | } |
|---|
| 506 | 465 | |
|---|
| 507 | | -static int mtk_nfc_setup_data_interface(struct mtd_info *mtd, int csline, |
|---|
| 508 | | - const struct nand_data_interface *conf) |
|---|
| 466 | +static int mtk_nfc_exec_instr(struct nand_chip *chip, |
|---|
| 467 | + const struct nand_op_instr *instr) |
|---|
| 509 | 468 | { |
|---|
| 510 | | - struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd)); |
|---|
| 469 | + struct mtk_nfc *nfc = nand_get_controller_data(chip); |
|---|
| 470 | + unsigned int i; |
|---|
| 471 | + u32 status; |
|---|
| 472 | + |
|---|
| 473 | + switch (instr->type) { |
|---|
| 474 | + case NAND_OP_CMD_INSTR: |
|---|
| 475 | + mtk_nfc_send_command(nfc, instr->ctx.cmd.opcode); |
|---|
| 476 | + return 0; |
|---|
| 477 | + case NAND_OP_ADDR_INSTR: |
|---|
| 478 | + for (i = 0; i < instr->ctx.addr.naddrs; i++) |
|---|
| 479 | + mtk_nfc_send_address(nfc, instr->ctx.addr.addrs[i]); |
|---|
| 480 | + return 0; |
|---|
| 481 | + case NAND_OP_DATA_IN_INSTR: |
|---|
| 482 | + mtk_nfc_read_buf(chip, instr->ctx.data.buf.in, |
|---|
| 483 | + instr->ctx.data.len); |
|---|
| 484 | + return 0; |
|---|
| 485 | + case NAND_OP_DATA_OUT_INSTR: |
|---|
| 486 | + mtk_nfc_write_buf(chip, instr->ctx.data.buf.out, |
|---|
| 487 | + instr->ctx.data.len); |
|---|
| 488 | + return 0; |
|---|
| 489 | + case NAND_OP_WAITRDY_INSTR: |
|---|
| 490 | + return readl_poll_timeout(nfc->regs + NFI_STA, status, |
|---|
| 491 | + !(status & STA_BUSY), 20, |
|---|
| 492 | + instr->ctx.waitrdy.timeout_ms * 1000); |
|---|
| 493 | + default: |
|---|
| 494 | + break; |
|---|
| 495 | + } |
|---|
| 496 | + |
|---|
| 497 | + return -EINVAL; |
|---|
| 498 | +} |
|---|
| 499 | + |
|---|
| 500 | +static void mtk_nfc_select_target(struct nand_chip *nand, unsigned int cs) |
|---|
| 501 | +{ |
|---|
| 502 | + struct mtk_nfc *nfc = nand_get_controller_data(nand); |
|---|
| 503 | + struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(nand); |
|---|
| 504 | + |
|---|
| 505 | + mtk_nfc_hw_runtime_config(nand_to_mtd(nand)); |
|---|
| 506 | + |
|---|
| 507 | + nfi_writel(nfc, mtk_nand->sels[cs], NFI_CSEL); |
|---|
| 508 | +} |
|---|
| 509 | + |
|---|
| 510 | +static int mtk_nfc_exec_op(struct nand_chip *chip, |
|---|
| 511 | + const struct nand_operation *op, |
|---|
| 512 | + bool check_only) |
|---|
| 513 | +{ |
|---|
| 514 | + struct mtk_nfc *nfc = nand_get_controller_data(chip); |
|---|
| 515 | + unsigned int i; |
|---|
| 516 | + int ret = 0; |
|---|
| 517 | + |
|---|
| 518 | + if (check_only) |
|---|
| 519 | + return 0; |
|---|
| 520 | + |
|---|
| 521 | + mtk_nfc_hw_reset(nfc); |
|---|
| 522 | + nfi_writew(nfc, CNFG_OP_CUST, NFI_CNFG); |
|---|
| 523 | + mtk_nfc_select_target(chip, op->cs); |
|---|
| 524 | + |
|---|
| 525 | + for (i = 0; i < op->ninstrs; i++) { |
|---|
| 526 | + ret = mtk_nfc_exec_instr(chip, &op->instrs[i]); |
|---|
| 527 | + if (ret) |
|---|
| 528 | + break; |
|---|
| 529 | + } |
|---|
| 530 | + |
|---|
| 531 | + return ret; |
|---|
| 532 | +} |
|---|
| 533 | + |
|---|
| 534 | +static int mtk_nfc_setup_interface(struct nand_chip *chip, int csline, |
|---|
| 535 | + const struct nand_interface_config *conf) |
|---|
| 536 | +{ |
|---|
| 537 | + struct mtk_nfc *nfc = nand_get_controller_data(chip); |
|---|
| 511 | 538 | const struct nand_sdr_timings *timings; |
|---|
| 512 | 539 | u32 rate, tpoecs, tprecs, tc2r, tw2r, twh, twst = 0, trlt = 0; |
|---|
| 513 | | - u32 thold; |
|---|
| 540 | + u32 temp, tsel = 0; |
|---|
| 514 | 541 | |
|---|
| 515 | 542 | timings = nand_get_sdr_timings(conf); |
|---|
| 516 | 543 | if (IS_ERR(timings)) |
|---|
| .. | .. |
|---|
| 547 | 574 | twh &= 0xf; |
|---|
| 548 | 575 | |
|---|
| 549 | 576 | /* Calculate real WE#/RE# hold time in nanosecond */ |
|---|
| 550 | | - thold = (twh + 1) * 1000000 / rate; |
|---|
| 577 | + temp = (twh + 1) * 1000000 / rate; |
|---|
| 551 | 578 | /* nanosecond to picosecond */ |
|---|
| 552 | | - thold *= 1000; |
|---|
| 579 | + temp *= 1000; |
|---|
| 553 | 580 | |
|---|
| 554 | 581 | /* |
|---|
| 555 | 582 | * WE# low level time should be expaned to meet WE# pulse time |
|---|
| 556 | 583 | * and WE# cycle time at the same time. |
|---|
| 557 | 584 | */ |
|---|
| 558 | | - if (thold < timings->tWC_min) |
|---|
| 559 | | - twst = timings->tWC_min - thold; |
|---|
| 585 | + if (temp < timings->tWC_min) |
|---|
| 586 | + twst = timings->tWC_min - temp; |
|---|
| 560 | 587 | twst = max(timings->tWP_min, twst) / 1000; |
|---|
| 561 | 588 | twst = DIV_ROUND_UP(twst * rate, 1000000) - 1; |
|---|
| 562 | 589 | twst &= 0xf; |
|---|
| 563 | 590 | |
|---|
| 564 | 591 | /* |
|---|
| 565 | | - * RE# low level time should be expaned to meet RE# pulse time, |
|---|
| 566 | | - * RE# access time and RE# cycle time at the same time. |
|---|
| 592 | + * RE# low level time should be expaned to meet RE# pulse time |
|---|
| 593 | + * and RE# cycle time at the same time. |
|---|
| 567 | 594 | */ |
|---|
| 568 | | - if (thold < timings->tRC_min) |
|---|
| 569 | | - trlt = timings->tRC_min - thold; |
|---|
| 570 | | - trlt = max3(trlt, timings->tREA_max, timings->tRP_min) / 1000; |
|---|
| 595 | + if (temp < timings->tRC_min) |
|---|
| 596 | + trlt = timings->tRC_min - temp; |
|---|
| 597 | + trlt = max(trlt, timings->tRP_min) / 1000; |
|---|
| 571 | 598 | trlt = DIV_ROUND_UP(trlt * rate, 1000000) - 1; |
|---|
| 572 | 599 | trlt &= 0xf; |
|---|
| 600 | + |
|---|
| 601 | + /* Calculate RE# pulse time in nanosecond. */ |
|---|
| 602 | + temp = (trlt + 1) * 1000000 / rate; |
|---|
| 603 | + /* nanosecond to picosecond */ |
|---|
| 604 | + temp *= 1000; |
|---|
| 605 | + /* |
|---|
| 606 | + * If RE# access time is bigger than RE# pulse time, |
|---|
| 607 | + * delay sampling data timing. |
|---|
| 608 | + */ |
|---|
| 609 | + if (temp < timings->tREA_max) { |
|---|
| 610 | + tsel = timings->tREA_max / 1000; |
|---|
| 611 | + tsel = DIV_ROUND_UP(tsel * rate, 1000000); |
|---|
| 612 | + tsel -= (trlt + 1); |
|---|
| 613 | + if (tsel > MAX_STROBE_DLY) { |
|---|
| 614 | + trlt += tsel - MAX_STROBE_DLY; |
|---|
| 615 | + tsel = MAX_STROBE_DLY; |
|---|
| 616 | + } |
|---|
| 617 | + } |
|---|
| 618 | + temp = nfi_readl(nfc, NFI_DEBUG_CON1); |
|---|
| 619 | + temp &= ~STROBE_MASK; |
|---|
| 620 | + temp |= tsel << STROBE_SHIFT; |
|---|
| 621 | + nfi_writel(nfc, temp, NFI_DEBUG_CON1); |
|---|
| 573 | 622 | |
|---|
| 574 | 623 | /* |
|---|
| 575 | 624 | * ACCON: access timing control register |
|---|
| .. | .. |
|---|
| 784 | 833 | u32 reg; |
|---|
| 785 | 834 | int ret; |
|---|
| 786 | 835 | |
|---|
| 836 | + mtk_nfc_select_target(chip, chip->cur_cs); |
|---|
| 787 | 837 | nand_prog_page_begin_op(chip, page, 0, NULL, 0); |
|---|
| 788 | 838 | |
|---|
| 789 | 839 | if (!raw) { |
|---|
| .. | .. |
|---|
| 825 | 875 | return nand_prog_page_end_op(chip); |
|---|
| 826 | 876 | } |
|---|
| 827 | 877 | |
|---|
| 828 | | -static int mtk_nfc_write_page_hwecc(struct mtd_info *mtd, |
|---|
| 829 | | - struct nand_chip *chip, const u8 *buf, |
|---|
| 878 | +static int mtk_nfc_write_page_hwecc(struct nand_chip *chip, const u8 *buf, |
|---|
| 830 | 879 | int oob_on, int page) |
|---|
| 831 | 880 | { |
|---|
| 832 | | - return mtk_nfc_write_page(mtd, chip, buf, page, 0); |
|---|
| 881 | + return mtk_nfc_write_page(nand_to_mtd(chip), chip, buf, page, 0); |
|---|
| 833 | 882 | } |
|---|
| 834 | 883 | |
|---|
| 835 | | -static int mtk_nfc_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, |
|---|
| 836 | | - const u8 *buf, int oob_on, int pg) |
|---|
| 884 | +static int mtk_nfc_write_page_raw(struct nand_chip *chip, const u8 *buf, |
|---|
| 885 | + int oob_on, int pg) |
|---|
| 837 | 886 | { |
|---|
| 887 | + struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 838 | 888 | struct mtk_nfc *nfc = nand_get_controller_data(chip); |
|---|
| 839 | 889 | |
|---|
| 840 | 890 | mtk_nfc_format_page(mtd, buf); |
|---|
| 841 | 891 | return mtk_nfc_write_page(mtd, chip, nfc->buffer, pg, 1); |
|---|
| 842 | 892 | } |
|---|
| 843 | 893 | |
|---|
| 844 | | -static int mtk_nfc_write_subpage_hwecc(struct mtd_info *mtd, |
|---|
| 845 | | - struct nand_chip *chip, u32 offset, |
|---|
| 894 | +static int mtk_nfc_write_subpage_hwecc(struct nand_chip *chip, u32 offset, |
|---|
| 846 | 895 | u32 data_len, const u8 *buf, |
|---|
| 847 | 896 | int oob_on, int page) |
|---|
| 848 | 897 | { |
|---|
| 898 | + struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 849 | 899 | struct mtk_nfc *nfc = nand_get_controller_data(chip); |
|---|
| 850 | 900 | int ret; |
|---|
| 851 | 901 | |
|---|
| .. | .. |
|---|
| 857 | 907 | return mtk_nfc_write_page(mtd, chip, nfc->buffer, page, 1); |
|---|
| 858 | 908 | } |
|---|
| 859 | 909 | |
|---|
| 860 | | -static int mtk_nfc_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, |
|---|
| 861 | | - int page) |
|---|
| 910 | +static int mtk_nfc_write_oob_std(struct nand_chip *chip, int page) |
|---|
| 862 | 911 | { |
|---|
| 863 | | - return mtk_nfc_write_page_raw(mtd, chip, NULL, 1, page); |
|---|
| 912 | + return mtk_nfc_write_page_raw(chip, NULL, 1, page); |
|---|
| 864 | 913 | } |
|---|
| 865 | 914 | |
|---|
| 866 | 915 | static int mtk_nfc_update_ecc_stats(struct mtd_info *mtd, u8 *buf, u32 start, |
|---|
| .. | .. |
|---|
| 902 | 951 | u8 *buf; |
|---|
| 903 | 952 | int rc; |
|---|
| 904 | 953 | |
|---|
| 954 | + mtk_nfc_select_target(chip, chip->cur_cs); |
|---|
| 905 | 955 | start = data_offs / chip->ecc.size; |
|---|
| 906 | 956 | end = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size); |
|---|
| 907 | 957 | |
|---|
| .. | .. |
|---|
| 986 | 1036 | return bitflips; |
|---|
| 987 | 1037 | } |
|---|
| 988 | 1038 | |
|---|
| 989 | | -static int mtk_nfc_read_subpage_hwecc(struct mtd_info *mtd, |
|---|
| 990 | | - struct nand_chip *chip, u32 off, |
|---|
| 1039 | +static int mtk_nfc_read_subpage_hwecc(struct nand_chip *chip, u32 off, |
|---|
| 991 | 1040 | u32 len, u8 *p, int pg) |
|---|
| 992 | 1041 | { |
|---|
| 993 | | - return mtk_nfc_read_subpage(mtd, chip, off, len, p, pg, 0); |
|---|
| 1042 | + return mtk_nfc_read_subpage(nand_to_mtd(chip), chip, off, len, p, pg, |
|---|
| 1043 | + 0); |
|---|
| 994 | 1044 | } |
|---|
| 995 | 1045 | |
|---|
| 996 | | -static int mtk_nfc_read_page_hwecc(struct mtd_info *mtd, |
|---|
| 997 | | - struct nand_chip *chip, u8 *p, |
|---|
| 998 | | - int oob_on, int pg) |
|---|
| 1046 | +static int mtk_nfc_read_page_hwecc(struct nand_chip *chip, u8 *p, int oob_on, |
|---|
| 1047 | + int pg) |
|---|
| 999 | 1048 | { |
|---|
| 1049 | + struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 1050 | + |
|---|
| 1000 | 1051 | return mtk_nfc_read_subpage(mtd, chip, 0, mtd->writesize, p, pg, 0); |
|---|
| 1001 | 1052 | } |
|---|
| 1002 | 1053 | |
|---|
| 1003 | | -static int mtk_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, |
|---|
| 1004 | | - u8 *buf, int oob_on, int page) |
|---|
| 1054 | +static int mtk_nfc_read_page_raw(struct nand_chip *chip, u8 *buf, int oob_on, |
|---|
| 1055 | + int page) |
|---|
| 1005 | 1056 | { |
|---|
| 1057 | + struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 1006 | 1058 | struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip); |
|---|
| 1007 | 1059 | struct mtk_nfc *nfc = nand_get_controller_data(chip); |
|---|
| 1008 | 1060 | struct mtk_nfc_fdm *fdm = &mtk_nand->fdm; |
|---|
| .. | .. |
|---|
| 1028 | 1080 | return ret; |
|---|
| 1029 | 1081 | } |
|---|
| 1030 | 1082 | |
|---|
| 1031 | | -static int mtk_nfc_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, |
|---|
| 1032 | | - int page) |
|---|
| 1083 | +static int mtk_nfc_read_oob_std(struct nand_chip *chip, int page) |
|---|
| 1033 | 1084 | { |
|---|
| 1034 | | - return mtk_nfc_read_page_raw(mtd, chip, NULL, 1, page); |
|---|
| 1085 | + return mtk_nfc_read_page_raw(chip, NULL, 1, page); |
|---|
| 1035 | 1086 | } |
|---|
| 1036 | 1087 | |
|---|
| 1037 | 1088 | static inline void mtk_nfc_hw_init(struct mtk_nfc *nfc) |
|---|
| .. | .. |
|---|
| 1202 | 1253 | static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd) |
|---|
| 1203 | 1254 | { |
|---|
| 1204 | 1255 | struct nand_chip *nand = mtd_to_nand(mtd); |
|---|
| 1256 | + const struct nand_ecc_props *requirements = |
|---|
| 1257 | + nanddev_get_ecc_requirements(&nand->base); |
|---|
| 1205 | 1258 | struct mtk_nfc *nfc = nand_get_controller_data(nand); |
|---|
| 1206 | 1259 | u32 spare; |
|---|
| 1207 | 1260 | int free, ret; |
|---|
| 1208 | 1261 | |
|---|
| 1209 | 1262 | /* support only ecc hw mode */ |
|---|
| 1210 | | - if (nand->ecc.mode != NAND_ECC_HW) { |
|---|
| 1211 | | - dev_err(dev, "ecc.mode not supported\n"); |
|---|
| 1263 | + if (nand->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST) { |
|---|
| 1264 | + dev_err(dev, "ecc.engine_type not supported\n"); |
|---|
| 1212 | 1265 | return -EINVAL; |
|---|
| 1213 | 1266 | } |
|---|
| 1214 | 1267 | |
|---|
| 1215 | 1268 | /* if optional dt settings not present */ |
|---|
| 1216 | 1269 | if (!nand->ecc.size || !nand->ecc.strength) { |
|---|
| 1217 | 1270 | /* use datasheet requirements */ |
|---|
| 1218 | | - nand->ecc.strength = nand->ecc_strength_ds; |
|---|
| 1219 | | - nand->ecc.size = nand->ecc_step_ds; |
|---|
| 1271 | + nand->ecc.strength = requirements->strength; |
|---|
| 1272 | + nand->ecc.size = requirements->step_size; |
|---|
| 1220 | 1273 | |
|---|
| 1221 | 1274 | /* |
|---|
| 1222 | 1275 | * align eccstrength and eccsize |
|---|
| .. | .. |
|---|
| 1306 | 1359 | |
|---|
| 1307 | 1360 | static const struct nand_controller_ops mtk_nfc_controller_ops = { |
|---|
| 1308 | 1361 | .attach_chip = mtk_nfc_attach_chip, |
|---|
| 1362 | + .setup_interface = mtk_nfc_setup_interface, |
|---|
| 1363 | + .exec_op = mtk_nfc_exec_op, |
|---|
| 1309 | 1364 | }; |
|---|
| 1310 | 1365 | |
|---|
| 1311 | 1366 | static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc, |
|---|
| .. | .. |
|---|
| 1340 | 1395 | dev_err(dev, "reg property failure : %d\n", ret); |
|---|
| 1341 | 1396 | return ret; |
|---|
| 1342 | 1397 | } |
|---|
| 1398 | + |
|---|
| 1399 | + if (tmp >= MTK_NAND_MAX_NSELS) { |
|---|
| 1400 | + dev_err(dev, "invalid CS: %u\n", tmp); |
|---|
| 1401 | + return -EINVAL; |
|---|
| 1402 | + } |
|---|
| 1403 | + |
|---|
| 1404 | + if (test_and_set_bit(tmp, &nfc->assigned_cs)) { |
|---|
| 1405 | + dev_err(dev, "CS %u already assigned\n", tmp); |
|---|
| 1406 | + return -EINVAL; |
|---|
| 1407 | + } |
|---|
| 1408 | + |
|---|
| 1343 | 1409 | chip->sels[i] = tmp; |
|---|
| 1344 | 1410 | } |
|---|
| 1345 | 1411 | |
|---|
| .. | .. |
|---|
| 1349 | 1415 | nand_set_flash_node(nand, np); |
|---|
| 1350 | 1416 | nand_set_controller_data(nand, nfc); |
|---|
| 1351 | 1417 | |
|---|
| 1352 | | - nand->options |= NAND_USE_BOUNCE_BUFFER | NAND_SUBPAGE_READ; |
|---|
| 1353 | | - nand->dev_ready = mtk_nfc_dev_ready; |
|---|
| 1354 | | - nand->select_chip = mtk_nfc_select_chip; |
|---|
| 1355 | | - nand->write_byte = mtk_nfc_write_byte; |
|---|
| 1356 | | - nand->write_buf = mtk_nfc_write_buf; |
|---|
| 1357 | | - nand->read_byte = mtk_nfc_read_byte; |
|---|
| 1358 | | - nand->read_buf = mtk_nfc_read_buf; |
|---|
| 1359 | | - nand->cmd_ctrl = mtk_nfc_cmd_ctrl; |
|---|
| 1360 | | - nand->setup_data_interface = mtk_nfc_setup_data_interface; |
|---|
| 1418 | + nand->options |= NAND_USES_DMA | NAND_SUBPAGE_READ; |
|---|
| 1361 | 1419 | |
|---|
| 1362 | 1420 | /* set default mode in case dt entry is missing */ |
|---|
| 1363 | | - nand->ecc.mode = NAND_ECC_HW; |
|---|
| 1421 | + nand->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; |
|---|
| 1364 | 1422 | |
|---|
| 1365 | 1423 | nand->ecc.write_subpage = mtk_nfc_write_subpage_hwecc; |
|---|
| 1366 | 1424 | nand->ecc.write_page_raw = mtk_nfc_write_page_raw; |
|---|
| .. | .. |
|---|
| 1469 | 1527 | if (!nfc) |
|---|
| 1470 | 1528 | return -ENOMEM; |
|---|
| 1471 | 1529 | |
|---|
| 1472 | | - spin_lock_init(&nfc->controller.lock); |
|---|
| 1473 | | - init_waitqueue_head(&nfc->controller.wq); |
|---|
| 1530 | + nand_controller_init(&nfc->controller); |
|---|
| 1474 | 1531 | INIT_LIST_HEAD(&nfc->chips); |
|---|
| 1475 | 1532 | nfc->controller.ops = &mtk_nfc_controller_ops; |
|---|
| 1476 | 1533 | |
|---|
| .. | .. |
|---|
| 1511 | 1568 | |
|---|
| 1512 | 1569 | irq = platform_get_irq(pdev, 0); |
|---|
| 1513 | 1570 | if (irq < 0) { |
|---|
| 1514 | | - dev_err(dev, "no nfi irq resource\n"); |
|---|
| 1515 | 1571 | ret = -EINVAL; |
|---|
| 1516 | 1572 | goto clk_disable; |
|---|
| 1517 | 1573 | } |
|---|
| .. | .. |
|---|
| 1550 | 1606 | static int mtk_nfc_remove(struct platform_device *pdev) |
|---|
| 1551 | 1607 | { |
|---|
| 1552 | 1608 | struct mtk_nfc *nfc = platform_get_drvdata(pdev); |
|---|
| 1553 | | - struct mtk_nfc_nand_chip *chip; |
|---|
| 1609 | + struct mtk_nfc_nand_chip *mtk_chip; |
|---|
| 1610 | + struct nand_chip *chip; |
|---|
| 1611 | + int ret; |
|---|
| 1554 | 1612 | |
|---|
| 1555 | 1613 | while (!list_empty(&nfc->chips)) { |
|---|
| 1556 | | - chip = list_first_entry(&nfc->chips, struct mtk_nfc_nand_chip, |
|---|
| 1557 | | - node); |
|---|
| 1558 | | - nand_release(&chip->nand); |
|---|
| 1559 | | - list_del(&chip->node); |
|---|
| 1614 | + mtk_chip = list_first_entry(&nfc->chips, |
|---|
| 1615 | + struct mtk_nfc_nand_chip, node); |
|---|
| 1616 | + chip = &mtk_chip->nand; |
|---|
| 1617 | + ret = mtd_device_unregister(nand_to_mtd(chip)); |
|---|
| 1618 | + WARN_ON(ret); |
|---|
| 1619 | + nand_cleanup(chip); |
|---|
| 1620 | + list_del(&mtk_chip->node); |
|---|
| 1560 | 1621 | } |
|---|
| 1561 | 1622 | |
|---|
| 1562 | 1623 | mtk_ecc_release(nfc->ecc); |
|---|
| .. | .. |
|---|
| 1616 | 1677 | |
|---|
| 1617 | 1678 | module_platform_driver(mtk_nfc_driver); |
|---|
| 1618 | 1679 | |
|---|
| 1619 | | -MODULE_LICENSE("GPL"); |
|---|
| 1680 | +MODULE_LICENSE("Dual MIT/GPL"); |
|---|
| 1620 | 1681 | MODULE_AUTHOR("Xiaolei Li <xiaolei.li@mediatek.com>"); |
|---|
| 1621 | 1682 | MODULE_DESCRIPTION("MTK Nand Flash Controller Driver"); |
|---|