| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright © 2005-2009 Samsung Electronics |
|---|
| 3 | 4 | * Copyright © 2007 Nokia Corporation |
|---|
| .. | .. |
|---|
| 12 | 13 | * Flex-OneNAND support |
|---|
| 13 | 14 | * Amul Kumar Saha <amul.saha at samsung.com> |
|---|
| 14 | 15 | * OTP support |
|---|
| 15 | | - * |
|---|
| 16 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 17 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 18 | | - * published by the Free Software Foundation. |
|---|
| 19 | 16 | */ |
|---|
| 20 | 17 | |
|---|
| 21 | 18 | #include <linux/kernel.h> |
|---|
| .. | .. |
|---|
| 1055 | 1052 | int thislen) |
|---|
| 1056 | 1053 | { |
|---|
| 1057 | 1054 | struct onenand_chip *this = mtd->priv; |
|---|
| 1058 | | - int ret; |
|---|
| 1059 | 1055 | |
|---|
| 1060 | 1056 | this->read_bufferram(mtd, ONENAND_SPARERAM, this->oob_buf, 0, |
|---|
| 1061 | 1057 | mtd->oobsize); |
|---|
| 1062 | | - ret = mtd_ooblayout_get_databytes(mtd, buf, this->oob_buf, |
|---|
| 1063 | | - column, thislen); |
|---|
| 1064 | | - if (ret) |
|---|
| 1065 | | - return ret; |
|---|
| 1066 | | - |
|---|
| 1067 | | - return 0; |
|---|
| 1058 | + return mtd_ooblayout_get_databytes(mtd, buf, this->oob_buf, |
|---|
| 1059 | + column, thislen); |
|---|
| 1068 | 1060 | } |
|---|
| 1069 | 1061 | |
|---|
| 1070 | 1062 | /** |
|---|
| .. | .. |
|---|
| 2458 | 2450 | bbm->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); |
|---|
| 2459 | 2451 | |
|---|
| 2460 | 2452 | /* We write two bytes, so we don't have to mess with 16-bit access */ |
|---|
| 2461 | | - ofs += mtd->oobsize + (bbm->badblockpos & ~0x01); |
|---|
| 2453 | + ofs += mtd->oobsize + (this->badblockpos & ~0x01); |
|---|
| 2462 | 2454 | /* FIXME : What to do when marking SLC block in partition |
|---|
| 2463 | 2455 | * with MLC erasesize? For now, it is not advisable to |
|---|
| 2464 | 2456 | * create partitions containing both SLC and MLC regions. |
|---|
| .. | .. |
|---|
| 2856 | 2848 | |
|---|
| 2857 | 2849 | /* Exit OTP access mode */ |
|---|
| 2858 | 2850 | this->command(mtd, ONENAND_CMD_RESET, 0, 0); |
|---|
| 2859 | | - this->wait(mtd, FL_RESETING); |
|---|
| 2851 | + this->wait(mtd, FL_RESETTING); |
|---|
| 2860 | 2852 | |
|---|
| 2861 | 2853 | status = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); |
|---|
| 2862 | 2854 | status &= 0x60; |
|---|
| .. | .. |
|---|
| 2927 | 2919 | |
|---|
| 2928 | 2920 | /* Exit OTP access mode */ |
|---|
| 2929 | 2921 | this->command(mtd, ONENAND_CMD_RESET, 0, 0); |
|---|
| 2930 | | - this->wait(mtd, FL_RESETING); |
|---|
| 2922 | + this->wait(mtd, FL_RESETTING); |
|---|
| 2931 | 2923 | |
|---|
| 2932 | 2924 | return ret; |
|---|
| 2933 | 2925 | } |
|---|
| .. | .. |
|---|
| 2971 | 2963 | |
|---|
| 2972 | 2964 | /* Exit OTP access mode */ |
|---|
| 2973 | 2965 | this->command(mtd, ONENAND_CMD_RESET, 0, 0); |
|---|
| 2974 | | - this->wait(mtd, FL_RESETING); |
|---|
| 2966 | + this->wait(mtd, FL_RESETTING); |
|---|
| 2975 | 2967 | |
|---|
| 2976 | 2968 | return ret; |
|---|
| 2977 | 2969 | } |
|---|
| .. | .. |
|---|
| 3011 | 3003 | |
|---|
| 3012 | 3004 | /* Exit OTP access mode */ |
|---|
| 3013 | 3005 | this->command(mtd, ONENAND_CMD_RESET, 0, 0); |
|---|
| 3014 | | - this->wait(mtd, FL_RESETING); |
|---|
| 3006 | + this->wait(mtd, FL_RESETTING); |
|---|
| 3015 | 3007 | } else { |
|---|
| 3016 | 3008 | ops.mode = MTD_OPS_PLACE_OOB; |
|---|
| 3017 | 3009 | ops.ooblen = len; |
|---|
| .. | .. |
|---|
| 3260 | 3252 | |
|---|
| 3261 | 3253 | /* Lock scheme */ |
|---|
| 3262 | 3254 | switch (density) { |
|---|
| 3255 | + case ONENAND_DEVICE_DENSITY_8Gb: |
|---|
| 3256 | + this->options |= ONENAND_HAS_NOP_1; |
|---|
| 3257 | + fallthrough; |
|---|
| 3263 | 3258 | case ONENAND_DEVICE_DENSITY_4Gb: |
|---|
| 3264 | 3259 | if (ONENAND_IS_DDP(this)) |
|---|
| 3265 | 3260 | this->options |= ONENAND_HAS_2PLANE; |
|---|
| .. | .. |
|---|
| 3280 | 3275 | if ((this->version_id & 0xf) == 0xe) |
|---|
| 3281 | 3276 | this->options |= ONENAND_HAS_NOP_1; |
|---|
| 3282 | 3277 | } |
|---|
| 3278 | + this->options |= ONENAND_HAS_UNLOCK_ALL; |
|---|
| 3279 | + break; |
|---|
| 3283 | 3280 | |
|---|
| 3284 | 3281 | case ONENAND_DEVICE_DENSITY_2Gb: |
|---|
| 3285 | 3282 | /* 2Gb DDP does not have 2 plane */ |
|---|
| 3286 | 3283 | if (!ONENAND_IS_DDP(this)) |
|---|
| 3287 | 3284 | this->options |= ONENAND_HAS_2PLANE; |
|---|
| 3288 | 3285 | this->options |= ONENAND_HAS_UNLOCK_ALL; |
|---|
| 3286 | + break; |
|---|
| 3289 | 3287 | |
|---|
| 3290 | 3288 | case ONENAND_DEVICE_DENSITY_1Gb: |
|---|
| 3291 | 3289 | /* A-Die has all block unlock */ |
|---|
| .. | .. |
|---|
| 3410 | 3408 | this->boundary[die] = bdry & FLEXONENAND_PI_MASK; |
|---|
| 3411 | 3409 | |
|---|
| 3412 | 3410 | this->command(mtd, ONENAND_CMD_RESET, 0, 0); |
|---|
| 3413 | | - this->wait(mtd, FL_RESETING); |
|---|
| 3411 | + this->wait(mtd, FL_RESETTING); |
|---|
| 3414 | 3412 | |
|---|
| 3415 | 3413 | printk(KERN_INFO "Die %d boundary: %d%s\n", die, |
|---|
| 3416 | 3414 | this->boundary[die], locked ? "(Locked)" : "(Unlocked)"); |
|---|
| .. | .. |
|---|
| 3632 | 3630 | ret = this->wait(mtd, FL_WRITING); |
|---|
| 3633 | 3631 | out: |
|---|
| 3634 | 3632 | this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_REG_COMMAND); |
|---|
| 3635 | | - this->wait(mtd, FL_RESETING); |
|---|
| 3633 | + this->wait(mtd, FL_RESETTING); |
|---|
| 3636 | 3634 | if (!ret) |
|---|
| 3637 | 3635 | /* Recalculate device size on boundary change*/ |
|---|
| 3638 | 3636 | flexonenand_get_size(mtd); |
|---|
| .. | .. |
|---|
| 3668 | 3666 | /* Reset OneNAND to read default register values */ |
|---|
| 3669 | 3667 | this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM); |
|---|
| 3670 | 3668 | /* Wait reset */ |
|---|
| 3671 | | - this->wait(mtd, FL_RESETING); |
|---|
| 3669 | + this->wait(mtd, FL_RESETTING); |
|---|
| 3672 | 3670 | |
|---|
| 3673 | 3671 | /* Restore system configuration 1 */ |
|---|
| 3674 | 3672 | this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1); |
|---|
| .. | .. |
|---|
| 3877 | 3875 | if (!this->oob_buf) { |
|---|
| 3878 | 3876 | if (this->options & ONENAND_PAGEBUF_ALLOC) { |
|---|
| 3879 | 3877 | this->options &= ~ONENAND_PAGEBUF_ALLOC; |
|---|
| 3878 | +#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE |
|---|
| 3879 | + kfree(this->verify_buf); |
|---|
| 3880 | +#endif |
|---|
| 3880 | 3881 | kfree(this->page_buf); |
|---|
| 3881 | 3882 | } |
|---|
| 3882 | 3883 | return -ENOMEM; |
|---|
| .. | .. |
|---|
| 3967 | 3968 | if (!(this->options & ONENAND_SKIP_INITIAL_UNLOCKING)) |
|---|
| 3968 | 3969 | this->unlock_all(mtd); |
|---|
| 3969 | 3970 | |
|---|
| 3971 | + /* Set the bad block marker position */ |
|---|
| 3972 | + this->badblockpos = ONENAND_BADBLOCK_POS; |
|---|
| 3973 | + |
|---|
| 3970 | 3974 | ret = this->scan_bbt(mtd); |
|---|
| 3971 | 3975 | if ((!FLEXONENAND(this)) || ret) |
|---|
| 3972 | 3976 | return ret; |
|---|