| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * SuperH FLCTL nand controller |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 5 | 6 | * Copyright (c) 2008 Atom Create Engineering Co., Ltd. |
|---|
| 6 | 7 | * |
|---|
| 7 | 8 | * Based on fsl_elbc_nand.c, Copyright (c) 2006-2007 Freescale Semiconductor |
|---|
| 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; version 2 of the License. |
|---|
| 12 | | - * |
|---|
| 13 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 14 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 15 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 16 | | - * GNU General Public License for more details. |
|---|
| 17 | | - * |
|---|
| 18 | | - * You should have received a copy of the GNU General Public License |
|---|
| 19 | | - * along with this program; if not, write to the Free Software |
|---|
| 20 | | - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
|---|
| 21 | | - * |
|---|
| 22 | 9 | */ |
|---|
| 23 | 10 | |
|---|
| 24 | 11 | #include <linux/module.h> |
|---|
| .. | .. |
|---|
| 114 | 101 | static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; |
|---|
| 115 | 102 | |
|---|
| 116 | 103 | static struct nand_bbt_descr flctl_4secc_smallpage = { |
|---|
| 117 | | - .options = NAND_BBT_SCAN2NDPAGE, |
|---|
| 118 | 104 | .offs = 11, |
|---|
| 119 | 105 | .len = 1, |
|---|
| 120 | 106 | .pattern = scan_ff_pattern, |
|---|
| 121 | 107 | }; |
|---|
| 122 | 108 | |
|---|
| 123 | 109 | static struct nand_bbt_descr flctl_4secc_largepage = { |
|---|
| 124 | | - .options = NAND_BBT_SCAN2NDPAGE, |
|---|
| 125 | 110 | .offs = 0, |
|---|
| 126 | 111 | .len = 2, |
|---|
| 127 | 112 | .pattern = scan_ff_pattern, |
|---|
| .. | .. |
|---|
| 399 | 384 | dma_addr_t dma_addr; |
|---|
| 400 | 385 | dma_cookie_t cookie; |
|---|
| 401 | 386 | uint32_t reg; |
|---|
| 402 | | - int ret; |
|---|
| 387 | + int ret = 0; |
|---|
| 388 | + unsigned long time_left; |
|---|
| 403 | 389 | |
|---|
| 404 | 390 | if (dir == DMA_FROM_DEVICE) { |
|---|
| 405 | 391 | chan = flctl->chan_fifo0_rx; |
|---|
| .. | .. |
|---|
| 440 | 426 | goto out; |
|---|
| 441 | 427 | } |
|---|
| 442 | 428 | |
|---|
| 443 | | - ret = |
|---|
| 429 | + time_left = |
|---|
| 444 | 430 | wait_for_completion_timeout(&flctl->dma_complete, |
|---|
| 445 | 431 | msecs_to_jiffies(3000)); |
|---|
| 446 | 432 | |
|---|
| 447 | | - if (ret <= 0) { |
|---|
| 433 | + if (time_left == 0) { |
|---|
| 448 | 434 | dmaengine_terminate_all(chan); |
|---|
| 449 | 435 | dev_err(&flctl->pdev->dev, "wait_for_completion_timeout\n"); |
|---|
| 436 | + ret = -ETIMEDOUT; |
|---|
| 450 | 437 | } |
|---|
| 451 | 438 | |
|---|
| 452 | 439 | out: |
|---|
| .. | .. |
|---|
| 456 | 443 | |
|---|
| 457 | 444 | dma_unmap_single(chan->device->dev, dma_addr, len, dir); |
|---|
| 458 | 445 | |
|---|
| 459 | | - /* ret > 0 is success */ |
|---|
| 446 | + /* ret == 0 is success */ |
|---|
| 460 | 447 | return ret; |
|---|
| 461 | 448 | } |
|---|
| 462 | 449 | |
|---|
| .. | .. |
|---|
| 480 | 467 | |
|---|
| 481 | 468 | /* initiate DMA transfer */ |
|---|
| 482 | 469 | if (flctl->chan_fifo0_rx && rlen >= 32 && |
|---|
| 483 | | - flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_FROM_DEVICE) > 0) |
|---|
| 470 | + !flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_FROM_DEVICE)) |
|---|
| 484 | 471 | goto convert; /* DMA success */ |
|---|
| 485 | 472 | |
|---|
| 486 | 473 | /* do polling transfer */ |
|---|
| .. | .. |
|---|
| 539 | 526 | |
|---|
| 540 | 527 | /* initiate DMA transfer */ |
|---|
| 541 | 528 | if (flctl->chan_fifo0_tx && rlen >= 32 && |
|---|
| 542 | | - flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_TO_DEVICE) > 0) |
|---|
| 529 | + !flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_TO_DEVICE)) |
|---|
| 543 | 530 | return; /* DMA success */ |
|---|
| 544 | 531 | |
|---|
| 545 | 532 | /* do polling transfer */ |
|---|
| .. | .. |
|---|
| 611 | 598 | writel(flcmcdr_val, FLCMCDR(flctl)); |
|---|
| 612 | 599 | } |
|---|
| 613 | 600 | |
|---|
| 614 | | -static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, |
|---|
| 615 | | - uint8_t *buf, int oob_required, int page) |
|---|
| 601 | +static int flctl_read_page_hwecc(struct nand_chip *chip, uint8_t *buf, |
|---|
| 602 | + int oob_required, int page) |
|---|
| 616 | 603 | { |
|---|
| 604 | + struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 605 | + |
|---|
| 617 | 606 | nand_read_page_op(chip, page, 0, buf, mtd->writesize); |
|---|
| 618 | 607 | if (oob_required) |
|---|
| 619 | | - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); |
|---|
| 608 | + chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize); |
|---|
| 620 | 609 | return 0; |
|---|
| 621 | 610 | } |
|---|
| 622 | 611 | |
|---|
| 623 | | -static int flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, |
|---|
| 624 | | - const uint8_t *buf, int oob_required, |
|---|
| 625 | | - int page) |
|---|
| 612 | +static int flctl_write_page_hwecc(struct nand_chip *chip, const uint8_t *buf, |
|---|
| 613 | + int oob_required, int page) |
|---|
| 626 | 614 | { |
|---|
| 615 | + struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 616 | + |
|---|
| 627 | 617 | nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize); |
|---|
| 628 | | - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); |
|---|
| 618 | + chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize); |
|---|
| 629 | 619 | return nand_prog_page_end_op(chip); |
|---|
| 630 | 620 | } |
|---|
| 631 | 621 | |
|---|
| .. | .. |
|---|
| 747 | 737 | } |
|---|
| 748 | 738 | } |
|---|
| 749 | 739 | |
|---|
| 750 | | -static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command, |
|---|
| 740 | +static void flctl_cmdfunc(struct nand_chip *chip, unsigned int command, |
|---|
| 751 | 741 | int column, int page_addr) |
|---|
| 752 | 742 | { |
|---|
| 743 | + struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 753 | 744 | struct sh_flctl *flctl = mtd_to_flctl(mtd); |
|---|
| 754 | 745 | uint32_t read_cmd = 0; |
|---|
| 755 | 746 | |
|---|
| .. | .. |
|---|
| 923 | 914 | return; |
|---|
| 924 | 915 | } |
|---|
| 925 | 916 | |
|---|
| 926 | | -static void flctl_select_chip(struct mtd_info *mtd, int chipnr) |
|---|
| 917 | +static void flctl_select_chip(struct nand_chip *chip, int chipnr) |
|---|
| 927 | 918 | { |
|---|
| 928 | | - struct sh_flctl *flctl = mtd_to_flctl(mtd); |
|---|
| 919 | + struct sh_flctl *flctl = mtd_to_flctl(nand_to_mtd(chip)); |
|---|
| 929 | 920 | int ret; |
|---|
| 930 | 921 | |
|---|
| 931 | 922 | switch (chipnr) { |
|---|
| .. | .. |
|---|
| 967 | 958 | } |
|---|
| 968 | 959 | } |
|---|
| 969 | 960 | |
|---|
| 970 | | -static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) |
|---|
| 961 | +static void flctl_write_buf(struct nand_chip *chip, const uint8_t *buf, int len) |
|---|
| 971 | 962 | { |
|---|
| 972 | | - struct sh_flctl *flctl = mtd_to_flctl(mtd); |
|---|
| 963 | + struct sh_flctl *flctl = mtd_to_flctl(nand_to_mtd(chip)); |
|---|
| 973 | 964 | |
|---|
| 974 | 965 | memcpy(&flctl->done_buff[flctl->index], buf, len); |
|---|
| 975 | 966 | flctl->index += len; |
|---|
| 976 | 967 | } |
|---|
| 977 | 968 | |
|---|
| 978 | | -static uint8_t flctl_read_byte(struct mtd_info *mtd) |
|---|
| 969 | +static uint8_t flctl_read_byte(struct nand_chip *chip) |
|---|
| 979 | 970 | { |
|---|
| 980 | | - struct sh_flctl *flctl = mtd_to_flctl(mtd); |
|---|
| 971 | + struct sh_flctl *flctl = mtd_to_flctl(nand_to_mtd(chip)); |
|---|
| 981 | 972 | uint8_t data; |
|---|
| 982 | 973 | |
|---|
| 983 | 974 | data = flctl->done_buff[flctl->index]; |
|---|
| .. | .. |
|---|
| 985 | 976 | return data; |
|---|
| 986 | 977 | } |
|---|
| 987 | 978 | |
|---|
| 988 | | -static uint16_t flctl_read_word(struct mtd_info *mtd) |
|---|
| 979 | +static void flctl_read_buf(struct nand_chip *chip, uint8_t *buf, int len) |
|---|
| 989 | 980 | { |
|---|
| 990 | | - struct sh_flctl *flctl = mtd_to_flctl(mtd); |
|---|
| 991 | | - uint16_t *buf = (uint16_t *)&flctl->done_buff[flctl->index]; |
|---|
| 992 | | - |
|---|
| 993 | | - flctl->index += 2; |
|---|
| 994 | | - return *buf; |
|---|
| 995 | | -} |
|---|
| 996 | | - |
|---|
| 997 | | -static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) |
|---|
| 998 | | -{ |
|---|
| 999 | | - struct sh_flctl *flctl = mtd_to_flctl(mtd); |
|---|
| 981 | + struct sh_flctl *flctl = mtd_to_flctl(nand_to_mtd(chip)); |
|---|
| 1000 | 982 | |
|---|
| 1001 | 983 | memcpy(buf, &flctl->done_buff[flctl->index], len); |
|---|
| 1002 | 984 | flctl->index += len; |
|---|
| .. | .. |
|---|
| 1004 | 986 | |
|---|
| 1005 | 987 | static int flctl_chip_attach_chip(struct nand_chip *chip) |
|---|
| 1006 | 988 | { |
|---|
| 989 | + u64 targetsize = nanddev_target_size(&chip->base); |
|---|
| 1007 | 990 | struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 1008 | 991 | struct sh_flctl *flctl = mtd_to_flctl(mtd); |
|---|
| 1009 | 992 | |
|---|
| .. | .. |
|---|
| 1016 | 999 | |
|---|
| 1017 | 1000 | if (mtd->writesize == 512) { |
|---|
| 1018 | 1001 | flctl->page_size = 0; |
|---|
| 1019 | | - if (chip->chipsize > (32 << 20)) { |
|---|
| 1002 | + if (targetsize > (32 << 20)) { |
|---|
| 1020 | 1003 | /* big than 32MB */ |
|---|
| 1021 | 1004 | flctl->rw_ADRCNT = ADRCNT_4; |
|---|
| 1022 | 1005 | flctl->erase_ADRCNT = ADRCNT_3; |
|---|
| 1023 | | - } else if (chip->chipsize > (2 << 16)) { |
|---|
| 1006 | + } else if (targetsize > (2 << 16)) { |
|---|
| 1024 | 1007 | /* big than 128KB */ |
|---|
| 1025 | 1008 | flctl->rw_ADRCNT = ADRCNT_3; |
|---|
| 1026 | 1009 | flctl->erase_ADRCNT = ADRCNT_2; |
|---|
| .. | .. |
|---|
| 1030 | 1013 | } |
|---|
| 1031 | 1014 | } else { |
|---|
| 1032 | 1015 | flctl->page_size = 1; |
|---|
| 1033 | | - if (chip->chipsize > (128 << 20)) { |
|---|
| 1016 | + if (targetsize > (128 << 20)) { |
|---|
| 1034 | 1017 | /* big than 128MB */ |
|---|
| 1035 | 1018 | flctl->rw_ADRCNT = ADRCNT2_E; |
|---|
| 1036 | 1019 | flctl->erase_ADRCNT = ADRCNT_3; |
|---|
| 1037 | | - } else if (chip->chipsize > (8 << 16)) { |
|---|
| 1020 | + } else if (targetsize > (8 << 16)) { |
|---|
| 1038 | 1021 | /* big than 512KB */ |
|---|
| 1039 | 1022 | flctl->rw_ADRCNT = ADRCNT_4; |
|---|
| 1040 | 1023 | flctl->erase_ADRCNT = ADRCNT_2; |
|---|
| .. | .. |
|---|
| 1058 | 1041 | chip->ecc.strength = 4; |
|---|
| 1059 | 1042 | chip->ecc.read_page = flctl_read_page_hwecc; |
|---|
| 1060 | 1043 | chip->ecc.write_page = flctl_write_page_hwecc; |
|---|
| 1061 | | - chip->ecc.mode = NAND_ECC_HW; |
|---|
| 1044 | + chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; |
|---|
| 1062 | 1045 | |
|---|
| 1063 | 1046 | /* 4 symbols ECC enabled */ |
|---|
| 1064 | 1047 | flctl->flcmncr_base |= _4ECCEN; |
|---|
| 1065 | 1048 | } else { |
|---|
| 1066 | | - chip->ecc.mode = NAND_ECC_SOFT; |
|---|
| 1067 | | - chip->ecc.algo = NAND_ECC_HAMMING; |
|---|
| 1049 | + chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; |
|---|
| 1050 | + chip->ecc.algo = NAND_ECC_ALGO_HAMMING; |
|---|
| 1068 | 1051 | } |
|---|
| 1069 | 1052 | |
|---|
| 1070 | 1053 | return 0; |
|---|
| .. | .. |
|---|
| 1148 | 1131 | flctl->fifo = res->start + 0x24; /* FLDTFIFO */ |
|---|
| 1149 | 1132 | |
|---|
| 1150 | 1133 | irq = platform_get_irq(pdev, 0); |
|---|
| 1151 | | - if (irq < 0) { |
|---|
| 1152 | | - dev_err(&pdev->dev, "failed to get flste irq data: %d\n", irq); |
|---|
| 1134 | + if (irq < 0) |
|---|
| 1153 | 1135 | return irq; |
|---|
| 1154 | | - } |
|---|
| 1155 | 1136 | |
|---|
| 1156 | 1137 | ret = devm_request_irq(&pdev->dev, irq, flctl_handle_flste, IRQF_SHARED, |
|---|
| 1157 | 1138 | "flste", flctl); |
|---|
| .. | .. |
|---|
| 1183 | 1164 | |
|---|
| 1184 | 1165 | /* Set address of hardware control function */ |
|---|
| 1185 | 1166 | /* 20 us command delay time */ |
|---|
| 1186 | | - nand->chip_delay = 20; |
|---|
| 1167 | + nand->legacy.chip_delay = 20; |
|---|
| 1187 | 1168 | |
|---|
| 1188 | | - nand->read_byte = flctl_read_byte; |
|---|
| 1189 | | - nand->read_word = flctl_read_word; |
|---|
| 1190 | | - nand->write_buf = flctl_write_buf; |
|---|
| 1191 | | - nand->read_buf = flctl_read_buf; |
|---|
| 1192 | | - nand->select_chip = flctl_select_chip; |
|---|
| 1193 | | - nand->cmdfunc = flctl_cmdfunc; |
|---|
| 1194 | | - nand->set_features = nand_get_set_features_notsupp; |
|---|
| 1195 | | - nand->get_features = nand_get_set_features_notsupp; |
|---|
| 1169 | + nand->legacy.read_byte = flctl_read_byte; |
|---|
| 1170 | + nand->legacy.write_buf = flctl_write_buf; |
|---|
| 1171 | + nand->legacy.read_buf = flctl_read_buf; |
|---|
| 1172 | + nand->legacy.select_chip = flctl_select_chip; |
|---|
| 1173 | + nand->legacy.cmdfunc = flctl_cmdfunc; |
|---|
| 1174 | + nand->legacy.set_features = nand_get_set_features_notsupp; |
|---|
| 1175 | + nand->legacy.get_features = nand_get_set_features_notsupp; |
|---|
| 1196 | 1176 | |
|---|
| 1197 | 1177 | if (pdata->flcmncr_val & SEL_16BIT) |
|---|
| 1198 | 1178 | nand->options |= NAND_BUSWIDTH_16; |
|---|
| 1179 | + |
|---|
| 1180 | + nand->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE; |
|---|
| 1199 | 1181 | |
|---|
| 1200 | 1182 | pm_runtime_enable(&pdev->dev); |
|---|
| 1201 | 1183 | pm_runtime_resume(&pdev->dev); |
|---|
| 1202 | 1184 | |
|---|
| 1203 | 1185 | flctl_setup_dma(flctl); |
|---|
| 1204 | 1186 | |
|---|
| 1205 | | - nand->dummy_controller.ops = &flctl_nand_controller_ops; |
|---|
| 1187 | + nand->legacy.dummy_controller.ops = &flctl_nand_controller_ops; |
|---|
| 1206 | 1188 | ret = nand_scan(nand, 1); |
|---|
| 1207 | 1189 | if (ret) |
|---|
| 1208 | 1190 | goto err_chip; |
|---|
| .. | .. |
|---|
| 1224 | 1206 | static int flctl_remove(struct platform_device *pdev) |
|---|
| 1225 | 1207 | { |
|---|
| 1226 | 1208 | struct sh_flctl *flctl = platform_get_drvdata(pdev); |
|---|
| 1209 | + struct nand_chip *chip = &flctl->chip; |
|---|
| 1210 | + int ret; |
|---|
| 1227 | 1211 | |
|---|
| 1228 | 1212 | flctl_release_dma(flctl); |
|---|
| 1229 | | - nand_release(&flctl->chip); |
|---|
| 1213 | + ret = mtd_device_unregister(nand_to_mtd(chip)); |
|---|
| 1214 | + WARN_ON(ret); |
|---|
| 1215 | + nand_cleanup(chip); |
|---|
| 1230 | 1216 | pm_runtime_disable(&pdev->dev); |
|---|
| 1231 | 1217 | |
|---|
| 1232 | 1218 | return 0; |
|---|
| .. | .. |
|---|
| 1242 | 1228 | |
|---|
| 1243 | 1229 | module_platform_driver_probe(flctl_driver, flctl_probe); |
|---|
| 1244 | 1230 | |
|---|
| 1245 | | -MODULE_LICENSE("GPL"); |
|---|
| 1231 | +MODULE_LICENSE("GPL v2"); |
|---|
| 1246 | 1232 | MODULE_AUTHOR("Yoshihiro Shimoda"); |
|---|
| 1247 | 1233 | MODULE_DESCRIPTION("SuperH FLCTL driver"); |
|---|
| 1248 | 1234 | MODULE_ALIAS("platform:sh_flctl"); |
|---|