| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (C) 2017 Free Electrons |
|---|
| 3 | 4 | * Copyright (C) 2017 NextThing Co |
|---|
| 4 | 5 | * |
|---|
| 5 | 6 | * Author: Boris Brezillon <boris.brezillon@free-electrons.com> |
|---|
| 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 as published by |
|---|
| 9 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 10 | | - * (at your option) any later version. |
|---|
| 11 | | - * |
|---|
| 12 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 13 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 14 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 15 | | - * GNU General Public License for more details. |
|---|
| 16 | 7 | */ |
|---|
| 17 | 8 | |
|---|
| 18 | | -#include <linux/mtd/rawnand.h> |
|---|
| 9 | +#include "internals.h" |
|---|
| 10 | + |
|---|
| 11 | +/* Bit for detecting BENAND */ |
|---|
| 12 | +#define TOSHIBA_NAND_ID4_IS_BENAND BIT(7) |
|---|
| 13 | + |
|---|
| 14 | +/* Recommended to rewrite for BENAND */ |
|---|
| 15 | +#define TOSHIBA_NAND_STATUS_REWRITE_RECOMMENDED BIT(3) |
|---|
| 16 | + |
|---|
| 17 | +/* ECC Status Read Command for BENAND */ |
|---|
| 18 | +#define TOSHIBA_NAND_CMD_ECC_STATUS_READ 0x7A |
|---|
| 19 | + |
|---|
| 20 | +/* ECC Status Mask for BENAND */ |
|---|
| 21 | +#define TOSHIBA_NAND_ECC_STATUS_MASK 0x0F |
|---|
| 22 | + |
|---|
| 23 | +/* Uncorrectable Error for BENAND */ |
|---|
| 24 | +#define TOSHIBA_NAND_ECC_STATUS_UNCORR 0x0F |
|---|
| 25 | + |
|---|
| 26 | +/* Max ECC Steps for BENAND */ |
|---|
| 27 | +#define TOSHIBA_NAND_MAX_ECC_STEPS 8 |
|---|
| 28 | + |
|---|
| 29 | +static int toshiba_nand_benand_read_eccstatus_op(struct nand_chip *chip, |
|---|
| 30 | + u8 *buf) |
|---|
| 31 | +{ |
|---|
| 32 | + u8 *ecc_status = buf; |
|---|
| 33 | + |
|---|
| 34 | + if (nand_has_exec_op(chip)) { |
|---|
| 35 | + const struct nand_sdr_timings *sdr = |
|---|
| 36 | + nand_get_sdr_timings(nand_get_interface_config(chip)); |
|---|
| 37 | + struct nand_op_instr instrs[] = { |
|---|
| 38 | + NAND_OP_CMD(TOSHIBA_NAND_CMD_ECC_STATUS_READ, |
|---|
| 39 | + PSEC_TO_NSEC(sdr->tADL_min)), |
|---|
| 40 | + NAND_OP_8BIT_DATA_IN(chip->ecc.steps, ecc_status, 0), |
|---|
| 41 | + }; |
|---|
| 42 | + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); |
|---|
| 43 | + |
|---|
| 44 | + return nand_exec_op(chip, &op); |
|---|
| 45 | + } |
|---|
| 46 | + |
|---|
| 47 | + return -ENOTSUPP; |
|---|
| 48 | +} |
|---|
| 49 | + |
|---|
| 50 | +static int toshiba_nand_benand_eccstatus(struct nand_chip *chip) |
|---|
| 51 | +{ |
|---|
| 52 | + struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 53 | + int ret; |
|---|
| 54 | + unsigned int max_bitflips = 0; |
|---|
| 55 | + u8 status, ecc_status[TOSHIBA_NAND_MAX_ECC_STEPS]; |
|---|
| 56 | + |
|---|
| 57 | + /* Check Status */ |
|---|
| 58 | + ret = toshiba_nand_benand_read_eccstatus_op(chip, ecc_status); |
|---|
| 59 | + if (!ret) { |
|---|
| 60 | + unsigned int i, bitflips = 0; |
|---|
| 61 | + |
|---|
| 62 | + for (i = 0; i < chip->ecc.steps; i++) { |
|---|
| 63 | + bitflips = ecc_status[i] & TOSHIBA_NAND_ECC_STATUS_MASK; |
|---|
| 64 | + if (bitflips == TOSHIBA_NAND_ECC_STATUS_UNCORR) { |
|---|
| 65 | + mtd->ecc_stats.failed++; |
|---|
| 66 | + } else { |
|---|
| 67 | + mtd->ecc_stats.corrected += bitflips; |
|---|
| 68 | + max_bitflips = max(max_bitflips, bitflips); |
|---|
| 69 | + } |
|---|
| 70 | + } |
|---|
| 71 | + |
|---|
| 72 | + return max_bitflips; |
|---|
| 73 | + } |
|---|
| 74 | + |
|---|
| 75 | + /* |
|---|
| 76 | + * Fallback to regular status check if |
|---|
| 77 | + * toshiba_nand_benand_read_eccstatus_op() failed. |
|---|
| 78 | + */ |
|---|
| 79 | + ret = nand_status_op(chip, &status); |
|---|
| 80 | + if (ret) |
|---|
| 81 | + return ret; |
|---|
| 82 | + |
|---|
| 83 | + if (status & NAND_STATUS_FAIL) { |
|---|
| 84 | + /* uncorrected */ |
|---|
| 85 | + mtd->ecc_stats.failed++; |
|---|
| 86 | + } else if (status & TOSHIBA_NAND_STATUS_REWRITE_RECOMMENDED) { |
|---|
| 87 | + /* corrected */ |
|---|
| 88 | + max_bitflips = mtd->bitflip_threshold; |
|---|
| 89 | + mtd->ecc_stats.corrected += max_bitflips; |
|---|
| 90 | + } |
|---|
| 91 | + |
|---|
| 92 | + return max_bitflips; |
|---|
| 93 | +} |
|---|
| 94 | + |
|---|
| 95 | +static int |
|---|
| 96 | +toshiba_nand_read_page_benand(struct nand_chip *chip, uint8_t *buf, |
|---|
| 97 | + int oob_required, int page) |
|---|
| 98 | +{ |
|---|
| 99 | + int ret; |
|---|
| 100 | + |
|---|
| 101 | + ret = nand_read_page_raw(chip, buf, oob_required, page); |
|---|
| 102 | + if (ret) |
|---|
| 103 | + return ret; |
|---|
| 104 | + |
|---|
| 105 | + return toshiba_nand_benand_eccstatus(chip); |
|---|
| 106 | +} |
|---|
| 107 | + |
|---|
| 108 | +static int |
|---|
| 109 | +toshiba_nand_read_subpage_benand(struct nand_chip *chip, uint32_t data_offs, |
|---|
| 110 | + uint32_t readlen, uint8_t *bufpoi, int page) |
|---|
| 111 | +{ |
|---|
| 112 | + int ret; |
|---|
| 113 | + |
|---|
| 114 | + ret = nand_read_page_op(chip, page, data_offs, |
|---|
| 115 | + bufpoi + data_offs, readlen); |
|---|
| 116 | + if (ret) |
|---|
| 117 | + return ret; |
|---|
| 118 | + |
|---|
| 119 | + return toshiba_nand_benand_eccstatus(chip); |
|---|
| 120 | +} |
|---|
| 121 | + |
|---|
| 122 | +static void toshiba_nand_benand_init(struct nand_chip *chip) |
|---|
| 123 | +{ |
|---|
| 124 | + struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 125 | + |
|---|
| 126 | + /* |
|---|
| 127 | + * On BENAND, the entire OOB region can be used by the MTD user. |
|---|
| 128 | + * The calculated ECC bytes are stored into other isolated |
|---|
| 129 | + * area which is not accessible to users. |
|---|
| 130 | + * This is why chip->ecc.bytes = 0. |
|---|
| 131 | + */ |
|---|
| 132 | + chip->ecc.bytes = 0; |
|---|
| 133 | + chip->ecc.size = 512; |
|---|
| 134 | + chip->ecc.strength = 8; |
|---|
| 135 | + chip->ecc.read_page = toshiba_nand_read_page_benand; |
|---|
| 136 | + chip->ecc.read_subpage = toshiba_nand_read_subpage_benand; |
|---|
| 137 | + chip->ecc.write_page = nand_write_page_raw; |
|---|
| 138 | + chip->ecc.read_page_raw = nand_read_page_raw_notsupp; |
|---|
| 139 | + chip->ecc.write_page_raw = nand_write_page_raw_notsupp; |
|---|
| 140 | + |
|---|
| 141 | + chip->options |= NAND_SUBPAGE_READ; |
|---|
| 142 | + |
|---|
| 143 | + mtd_set_ooblayout(mtd, nand_get_large_page_ooblayout()); |
|---|
| 144 | +} |
|---|
| 19 | 145 | |
|---|
| 20 | 146 | static void toshiba_nand_decode_id(struct nand_chip *chip) |
|---|
| 21 | 147 | { |
|---|
| 148 | + struct nand_device *base = &chip->base; |
|---|
| 149 | + struct nand_ecc_props requirements = {}; |
|---|
| 22 | 150 | struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 151 | + struct nand_memory_organization *memorg; |
|---|
| 152 | + |
|---|
| 153 | + memorg = nanddev_get_memorg(&chip->base); |
|---|
| 23 | 154 | |
|---|
| 24 | 155 | nand_decode_ext_id(chip); |
|---|
| 25 | 156 | |
|---|
| .. | .. |
|---|
| 33 | 164 | */ |
|---|
| 34 | 165 | if (chip->id.len >= 6 && nand_is_slc(chip) && |
|---|
| 35 | 166 | (chip->id.data[5] & 0x7) == 0x6 /* 24nm */ && |
|---|
| 36 | | - !(chip->id.data[4] & 0x80) /* !BENAND */) |
|---|
| 37 | | - mtd->oobsize = 32 * mtd->writesize >> 9; |
|---|
| 167 | + !(chip->id.data[4] & TOSHIBA_NAND_ID4_IS_BENAND) /* !BENAND */) { |
|---|
| 168 | + memorg->oobsize = 32 * memorg->pagesize >> 9; |
|---|
| 169 | + mtd->oobsize = memorg->oobsize; |
|---|
| 170 | + } |
|---|
| 38 | 171 | |
|---|
| 39 | 172 | /* |
|---|
| 40 | 173 | * Extract ECC requirements from 6th id byte. |
|---|
| .. | .. |
|---|
| 44 | 177 | * - 24nm: 8 bit ECC for each 512Byte is required. |
|---|
| 45 | 178 | */ |
|---|
| 46 | 179 | if (chip->id.len >= 6 && nand_is_slc(chip)) { |
|---|
| 47 | | - chip->ecc_step_ds = 512; |
|---|
| 180 | + requirements.step_size = 512; |
|---|
| 48 | 181 | switch (chip->id.data[5] & 0x7) { |
|---|
| 49 | 182 | case 0x4: |
|---|
| 50 | | - chip->ecc_strength_ds = 1; |
|---|
| 183 | + requirements.strength = 1; |
|---|
| 51 | 184 | break; |
|---|
| 52 | 185 | case 0x5: |
|---|
| 53 | | - chip->ecc_strength_ds = 4; |
|---|
| 186 | + requirements.strength = 4; |
|---|
| 54 | 187 | break; |
|---|
| 55 | 188 | case 0x6: |
|---|
| 56 | | - chip->ecc_strength_ds = 8; |
|---|
| 189 | + requirements.strength = 8; |
|---|
| 57 | 190 | break; |
|---|
| 58 | 191 | default: |
|---|
| 59 | 192 | WARN(1, "Could not get ECC info"); |
|---|
| 60 | | - chip->ecc_step_ds = 0; |
|---|
| 193 | + requirements.step_size = 0; |
|---|
| 61 | 194 | break; |
|---|
| 62 | 195 | } |
|---|
| 63 | 196 | } |
|---|
| 197 | + |
|---|
| 198 | + nanddev_set_ecc_requirements(base, &requirements); |
|---|
| 199 | +} |
|---|
| 200 | + |
|---|
| 201 | +static int |
|---|
| 202 | +tc58teg5dclta00_choose_interface_config(struct nand_chip *chip, |
|---|
| 203 | + struct nand_interface_config *iface) |
|---|
| 204 | +{ |
|---|
| 205 | + onfi_fill_interface_config(chip, iface, NAND_SDR_IFACE, 5); |
|---|
| 206 | + |
|---|
| 207 | + return nand_choose_best_sdr_timings(chip, iface, NULL); |
|---|
| 208 | +} |
|---|
| 209 | + |
|---|
| 210 | +static int |
|---|
| 211 | +tc58nvg0s3e_choose_interface_config(struct nand_chip *chip, |
|---|
| 212 | + struct nand_interface_config *iface) |
|---|
| 213 | +{ |
|---|
| 214 | + onfi_fill_interface_config(chip, iface, NAND_SDR_IFACE, 2); |
|---|
| 215 | + |
|---|
| 216 | + return nand_choose_best_sdr_timings(chip, iface, NULL); |
|---|
| 217 | +} |
|---|
| 218 | + |
|---|
| 219 | +static int |
|---|
| 220 | +th58nvg2s3hbai4_choose_interface_config(struct nand_chip *chip, |
|---|
| 221 | + struct nand_interface_config *iface) |
|---|
| 222 | +{ |
|---|
| 223 | + struct nand_sdr_timings *sdr = &iface->timings.sdr; |
|---|
| 224 | + |
|---|
| 225 | + /* Start with timings from the closest timing mode, mode 4. */ |
|---|
| 226 | + onfi_fill_interface_config(chip, iface, NAND_SDR_IFACE, 4); |
|---|
| 227 | + |
|---|
| 228 | + /* Patch timings that differ from mode 4. */ |
|---|
| 229 | + sdr->tALS_min = 12000; |
|---|
| 230 | + sdr->tCHZ_max = 20000; |
|---|
| 231 | + sdr->tCLS_min = 12000; |
|---|
| 232 | + sdr->tCOH_min = 0; |
|---|
| 233 | + sdr->tDS_min = 12000; |
|---|
| 234 | + sdr->tRHOH_min = 25000; |
|---|
| 235 | + sdr->tRHW_min = 30000; |
|---|
| 236 | + sdr->tRHZ_max = 60000; |
|---|
| 237 | + sdr->tWHR_min = 60000; |
|---|
| 238 | + |
|---|
| 239 | + /* Patch timings not part of onfi timing mode. */ |
|---|
| 240 | + sdr->tPROG_max = 700000000; |
|---|
| 241 | + sdr->tBERS_max = 5000000000; |
|---|
| 242 | + |
|---|
| 243 | + return nand_choose_best_sdr_timings(chip, iface, sdr); |
|---|
| 244 | +} |
|---|
| 245 | + |
|---|
| 246 | +static int tc58teg5dclta00_init(struct nand_chip *chip) |
|---|
| 247 | +{ |
|---|
| 248 | + struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 249 | + |
|---|
| 250 | + chip->ops.choose_interface_config = |
|---|
| 251 | + &tc58teg5dclta00_choose_interface_config; |
|---|
| 252 | + chip->options |= NAND_NEED_SCRAMBLING; |
|---|
| 253 | + mtd_set_pairing_scheme(mtd, &dist3_pairing_scheme); |
|---|
| 254 | + |
|---|
| 255 | + return 0; |
|---|
| 256 | +} |
|---|
| 257 | + |
|---|
| 258 | +static int tc58nvg0s3e_init(struct nand_chip *chip) |
|---|
| 259 | +{ |
|---|
| 260 | + chip->ops.choose_interface_config = |
|---|
| 261 | + &tc58nvg0s3e_choose_interface_config; |
|---|
| 262 | + |
|---|
| 263 | + return 0; |
|---|
| 264 | +} |
|---|
| 265 | + |
|---|
| 266 | +static int th58nvg2s3hbai4_init(struct nand_chip *chip) |
|---|
| 267 | +{ |
|---|
| 268 | + chip->ops.choose_interface_config = |
|---|
| 269 | + &th58nvg2s3hbai4_choose_interface_config; |
|---|
| 270 | + |
|---|
| 271 | + return 0; |
|---|
| 64 | 272 | } |
|---|
| 65 | 273 | |
|---|
| 66 | 274 | static int toshiba_nand_init(struct nand_chip *chip) |
|---|
| 67 | 275 | { |
|---|
| 68 | 276 | if (nand_is_slc(chip)) |
|---|
| 69 | | - chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; |
|---|
| 277 | + chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE; |
|---|
| 278 | + |
|---|
| 279 | + /* Check that chip is BENAND and ECC mode is on-die */ |
|---|
| 280 | + if (nand_is_slc(chip) && |
|---|
| 281 | + chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_DIE && |
|---|
| 282 | + chip->id.data[4] & TOSHIBA_NAND_ID4_IS_BENAND) |
|---|
| 283 | + toshiba_nand_benand_init(chip); |
|---|
| 284 | + |
|---|
| 285 | + if (!strcmp("TC58TEG5DCLTA00", chip->parameters.model)) |
|---|
| 286 | + tc58teg5dclta00_init(chip); |
|---|
| 287 | + if (!strncmp("TC58NVG0S3E", chip->parameters.model, |
|---|
| 288 | + sizeof("TC58NVG0S3E") - 1)) |
|---|
| 289 | + tc58nvg0s3e_init(chip); |
|---|
| 290 | + if (!strncmp("TH58NVG2S3HBAI4", chip->parameters.model, |
|---|
| 291 | + sizeof("TH58NVG2S3HBAI4") - 1)) |
|---|
| 292 | + th58nvg2s3hbai4_init(chip); |
|---|
| 70 | 293 | |
|---|
| 71 | 294 | return 0; |
|---|
| 72 | 295 | } |
|---|