314 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2018 exceet electronics GmbH4 * Copyright (c) 2018 Kontron Electronics GmbH5 *6 * Author: Frieder Schrempf <frieder.schrempf@kontron.de>7 */8 9#include <linux/device.h>10#include <linux/kernel.h>11#include <linux/mtd/spinand.h>12 13/* Kioxia is new name of Toshiba memory. */14#define SPINAND_MFR_TOSHIBA 0x9815#define TOSH_STATUS_ECC_HAS_BITFLIPS_T (3 << 4)16 17static SPINAND_OP_VARIANTS(read_cache_variants,18 SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),19 SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),20 SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),21 SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));22 23static SPINAND_OP_VARIANTS(write_cache_x4_variants,24 SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),25 SPINAND_PROG_LOAD(true, 0, NULL, 0));26 27static SPINAND_OP_VARIANTS(update_cache_x4_variants,28 SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),29 SPINAND_PROG_LOAD(false, 0, NULL, 0));30 31/*32 * Backward compatibility for 1st generation Serial NAND devices33 * which don't support Quad Program Load operation.34 */35static SPINAND_OP_VARIANTS(write_cache_variants,36 SPINAND_PROG_LOAD(true, 0, NULL, 0));37 38static SPINAND_OP_VARIANTS(update_cache_variants,39 SPINAND_PROG_LOAD(false, 0, NULL, 0));40 41static int tx58cxgxsxraix_ooblayout_ecc(struct mtd_info *mtd, int section,42 struct mtd_oob_region *region)43{44 if (section > 0)45 return -ERANGE;46 47 region->offset = mtd->oobsize / 2;48 region->length = mtd->oobsize / 2;49 50 return 0;51}52 53static int tx58cxgxsxraix_ooblayout_free(struct mtd_info *mtd, int section,54 struct mtd_oob_region *region)55{56 if (section > 0)57 return -ERANGE;58 59 /* 2 bytes reserved for BBM */60 region->offset = 2;61 region->length = (mtd->oobsize / 2) - 2;62 63 return 0;64}65 66static const struct mtd_ooblayout_ops tx58cxgxsxraix_ooblayout = {67 .ecc = tx58cxgxsxraix_ooblayout_ecc,68 .free = tx58cxgxsxraix_ooblayout_free,69};70 71static int tx58cxgxsxraix_ecc_get_status(struct spinand_device *spinand,72 u8 status)73{74 struct nand_device *nand = spinand_to_nand(spinand);75 u8 mbf = 0;76 struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, spinand->scratchbuf);77 78 switch (status & STATUS_ECC_MASK) {79 case STATUS_ECC_NO_BITFLIPS:80 return 0;81 82 case STATUS_ECC_UNCOR_ERROR:83 return -EBADMSG;84 85 case STATUS_ECC_HAS_BITFLIPS:86 case TOSH_STATUS_ECC_HAS_BITFLIPS_T:87 /*88 * Let's try to retrieve the real maximum number of bitflips89 * in order to avoid forcing the wear-leveling layer to move90 * data around if it's not necessary.91 */92 if (spi_mem_exec_op(spinand->spimem, &op))93 return nanddev_get_ecc_conf(nand)->strength;94 95 mbf = *(spinand->scratchbuf) >> 4;96 97 if (WARN_ON(mbf > nanddev_get_ecc_conf(nand)->strength || !mbf))98 return nanddev_get_ecc_conf(nand)->strength;99 100 return mbf;101 102 default:103 break;104 }105 106 return -EINVAL;107}108 109static const struct spinand_info toshiba_spinand_table[] = {110 /* 3.3V 1Gb (1st generation) */111 SPINAND_INFO("TC58CVG0S3HRAIG",112 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xC2),113 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),114 NAND_ECCREQ(8, 512),115 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,116 &write_cache_variants,117 &update_cache_variants),118 0,119 SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,120 tx58cxgxsxraix_ecc_get_status)),121 /* 3.3V 2Gb (1st generation) */122 SPINAND_INFO("TC58CVG1S3HRAIG",123 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xCB),124 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),125 NAND_ECCREQ(8, 512),126 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,127 &write_cache_variants,128 &update_cache_variants),129 0,130 SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,131 tx58cxgxsxraix_ecc_get_status)),132 /* 3.3V 4Gb (1st generation) */133 SPINAND_INFO("TC58CVG2S0HRAIG",134 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xCD),135 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),136 NAND_ECCREQ(8, 512),137 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,138 &write_cache_variants,139 &update_cache_variants),140 0,141 SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,142 tx58cxgxsxraix_ecc_get_status)),143 /* 1.8V 1Gb (1st generation) */144 SPINAND_INFO("TC58CYG0S3HRAIG",145 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xB2),146 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),147 NAND_ECCREQ(8, 512),148 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,149 &write_cache_variants,150 &update_cache_variants),151 0,152 SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,153 tx58cxgxsxraix_ecc_get_status)),154 /* 1.8V 2Gb (1st generation) */155 SPINAND_INFO("TC58CYG1S3HRAIG",156 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBB),157 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),158 NAND_ECCREQ(8, 512),159 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,160 &write_cache_variants,161 &update_cache_variants),162 0,163 SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,164 tx58cxgxsxraix_ecc_get_status)),165 /* 1.8V 4Gb (1st generation) */166 SPINAND_INFO("TC58CYG2S0HRAIG",167 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBD),168 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),169 NAND_ECCREQ(8, 512),170 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,171 &write_cache_variants,172 &update_cache_variants),173 0,174 SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,175 tx58cxgxsxraix_ecc_get_status)),176 177 /*178 * 2nd generation serial nand has HOLD_D which is equivalent to179 * QE_BIT.180 */181 /* 3.3V 1Gb (2nd generation) */182 SPINAND_INFO("TC58CVG0S3HRAIJ",183 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE2),184 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),185 NAND_ECCREQ(8, 512),186 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,187 &write_cache_x4_variants,188 &update_cache_x4_variants),189 SPINAND_HAS_QE_BIT,190 SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,191 tx58cxgxsxraix_ecc_get_status)),192 /* 3.3V 2Gb (2nd generation) */193 SPINAND_INFO("TC58CVG1S3HRAIJ",194 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xEB),195 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),196 NAND_ECCREQ(8, 512),197 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,198 &write_cache_x4_variants,199 &update_cache_x4_variants),200 SPINAND_HAS_QE_BIT,201 SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,202 tx58cxgxsxraix_ecc_get_status)),203 /* 3.3V 4Gb (2nd generation) */204 SPINAND_INFO("TC58CVG2S0HRAIJ",205 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xED),206 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),207 NAND_ECCREQ(8, 512),208 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,209 &write_cache_x4_variants,210 &update_cache_x4_variants),211 SPINAND_HAS_QE_BIT,212 SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,213 tx58cxgxsxraix_ecc_get_status)),214 /* 3.3V 8Gb (2nd generation) */215 SPINAND_INFO("TH58CVG3S0HRAIJ",216 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4),217 NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1),218 NAND_ECCREQ(8, 512),219 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,220 &write_cache_x4_variants,221 &update_cache_x4_variants),222 SPINAND_HAS_QE_BIT,223 SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,224 tx58cxgxsxraix_ecc_get_status)),225 /* 1.8V 1Gb (2nd generation) */226 SPINAND_INFO("TC58CYG0S3HRAIJ",227 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xD2),228 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),229 NAND_ECCREQ(8, 512),230 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,231 &write_cache_x4_variants,232 &update_cache_x4_variants),233 SPINAND_HAS_QE_BIT,234 SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,235 tx58cxgxsxraix_ecc_get_status)),236 /* 1.8V 2Gb (2nd generation) */237 SPINAND_INFO("TC58CYG1S3HRAIJ",238 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xDB),239 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),240 NAND_ECCREQ(8, 512),241 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,242 &write_cache_x4_variants,243 &update_cache_x4_variants),244 SPINAND_HAS_QE_BIT,245 SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,246 tx58cxgxsxraix_ecc_get_status)),247 /* 1.8V 4Gb (2nd generation) */248 SPINAND_INFO("TC58CYG2S0HRAIJ",249 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xDD),250 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),251 NAND_ECCREQ(8, 512),252 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,253 &write_cache_x4_variants,254 &update_cache_x4_variants),255 SPINAND_HAS_QE_BIT,256 SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,257 tx58cxgxsxraix_ecc_get_status)),258 /* 1.8V 8Gb (2nd generation) */259 SPINAND_INFO("TH58CYG3S0HRAIJ",260 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xD4),261 NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1),262 NAND_ECCREQ(8, 512),263 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,264 &write_cache_x4_variants,265 &update_cache_x4_variants),266 SPINAND_HAS_QE_BIT,267 SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,268 tx58cxgxsxraix_ecc_get_status)),269 /* 1.8V 1Gb (1st generation) */270 SPINAND_INFO("TC58NYG0S3HBAI4",271 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xA1),272 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),273 NAND_ECCREQ(8, 512),274 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,275 &write_cache_variants,276 &update_cache_variants),277 0,278 SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,279 tx58cxgxsxraix_ecc_get_status)),280 /* 1.8V 4Gb (1st generation) */281 SPINAND_INFO("TH58NYG2S3HBAI4",282 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xAC),283 NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 2, 1),284 NAND_ECCREQ(8, 512),285 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,286 &write_cache_x4_variants,287 &update_cache_x4_variants),288 SPINAND_HAS_QE_BIT,289 SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,290 tx58cxgxsxraix_ecc_get_status)),291 /* 1.8V 8Gb (1st generation) */292 SPINAND_INFO("TH58NYG3S0HBAI6",293 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xA3),294 NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1),295 NAND_ECCREQ(8, 512),296 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,297 &write_cache_x4_variants,298 &update_cache_x4_variants),299 SPINAND_HAS_QE_BIT,300 SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,301 tx58cxgxsxraix_ecc_get_status)),302};303 304static const struct spinand_manufacturer_ops toshiba_spinand_manuf_ops = {305};306 307const struct spinand_manufacturer toshiba_spinand_manufacturer = {308 .id = SPINAND_MFR_TOSHIBA,309 .name = "Toshiba",310 .chips = toshiba_spinand_table,311 .nchips = ARRAY_SIZE(toshiba_spinand_table),312 .ops = &toshiba_spinand_manuf_ops,313};314