110949af1SSchrempf Frieder // SPDX-License-Identifier: GPL-2.0 210949af1SSchrempf Frieder /* 310949af1SSchrempf Frieder * Copyright (c) 2018 exceet electronics GmbH 410949af1SSchrempf Frieder * Copyright (c) 2018 Kontron Electronics GmbH 510949af1SSchrempf Frieder * 610949af1SSchrempf Frieder * Author: Frieder Schrempf <frieder.schrempf@kontron.de> 710949af1SSchrempf Frieder */ 810949af1SSchrempf Frieder 910949af1SSchrempf Frieder #include <linux/device.h> 1010949af1SSchrempf Frieder #include <linux/kernel.h> 1110949af1SSchrempf Frieder #include <linux/mtd/spinand.h> 1210949af1SSchrempf Frieder 13a91f8170SYoshio Furuyama /* Kioxia is new name of Toshiba memory. */ 1410949af1SSchrempf Frieder #define SPINAND_MFR_TOSHIBA 0x98 1510949af1SSchrempf Frieder #define TOSH_STATUS_ECC_HAS_BITFLIPS_T (3 << 4) 1610949af1SSchrempf Frieder 1710949af1SSchrempf Frieder static SPINAND_OP_VARIANTS(read_cache_variants, 1810949af1SSchrempf Frieder SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), 1910949af1SSchrempf Frieder SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), 2010949af1SSchrempf Frieder SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), 2110949af1SSchrempf Frieder SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); 2210949af1SSchrempf Frieder 23798fcdd0SYoshio Furuyama static SPINAND_OP_VARIANTS(write_cache_x4_variants, 24798fcdd0SYoshio Furuyama SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), 25798fcdd0SYoshio Furuyama SPINAND_PROG_LOAD(true, 0, NULL, 0)); 26798fcdd0SYoshio Furuyama 27798fcdd0SYoshio Furuyama static SPINAND_OP_VARIANTS(update_cache_x4_variants, 28798fcdd0SYoshio Furuyama SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), 29798fcdd0SYoshio Furuyama SPINAND_PROG_LOAD(false, 0, NULL, 0)); 30798fcdd0SYoshio Furuyama 31*6a21a117SLee Jones /* 32798fcdd0SYoshio Furuyama * Backward compatibility for 1st generation Serial NAND devices 33798fcdd0SYoshio Furuyama * which don't support Quad Program Load operation. 34798fcdd0SYoshio Furuyama */ 3510949af1SSchrempf Frieder static SPINAND_OP_VARIANTS(write_cache_variants, 3610949af1SSchrempf Frieder SPINAND_PROG_LOAD(true, 0, NULL, 0)); 3710949af1SSchrempf Frieder 3810949af1SSchrempf Frieder static SPINAND_OP_VARIANTS(update_cache_variants, 3910949af1SSchrempf Frieder SPINAND_PROG_LOAD(false, 0, NULL, 0)); 4010949af1SSchrempf Frieder 416b49e58dSYoshio Furuyama static int tx58cxgxsxraix_ooblayout_ecc(struct mtd_info *mtd, int section, 4210949af1SSchrempf Frieder struct mtd_oob_region *region) 4310949af1SSchrempf Frieder { 44db214513SYoshio Furuyama if (section > 0) 4510949af1SSchrempf Frieder return -ERANGE; 4610949af1SSchrempf Frieder 47db214513SYoshio Furuyama region->offset = mtd->oobsize / 2; 48db214513SYoshio Furuyama region->length = mtd->oobsize / 2; 4910949af1SSchrempf Frieder 5010949af1SSchrempf Frieder return 0; 5110949af1SSchrempf Frieder } 5210949af1SSchrempf Frieder 536b49e58dSYoshio Furuyama static int tx58cxgxsxraix_ooblayout_free(struct mtd_info *mtd, int section, 5410949af1SSchrempf Frieder struct mtd_oob_region *region) 5510949af1SSchrempf Frieder { 5610949af1SSchrempf Frieder if (section > 0) 5710949af1SSchrempf Frieder return -ERANGE; 5810949af1SSchrempf Frieder 5910949af1SSchrempf Frieder /* 2 bytes reserved for BBM */ 6010949af1SSchrempf Frieder region->offset = 2; 61db214513SYoshio Furuyama region->length = (mtd->oobsize / 2) - 2; 6210949af1SSchrempf Frieder 6310949af1SSchrempf Frieder return 0; 6410949af1SSchrempf Frieder } 6510949af1SSchrempf Frieder 666b49e58dSYoshio Furuyama static const struct mtd_ooblayout_ops tx58cxgxsxraix_ooblayout = { 676b49e58dSYoshio Furuyama .ecc = tx58cxgxsxraix_ooblayout_ecc, 686b49e58dSYoshio Furuyama .free = tx58cxgxsxraix_ooblayout_free, 6910949af1SSchrempf Frieder }; 7010949af1SSchrempf Frieder 716b49e58dSYoshio Furuyama static int tx58cxgxsxraix_ecc_get_status(struct spinand_device *spinand, 7210949af1SSchrempf Frieder u8 status) 7310949af1SSchrempf Frieder { 7410949af1SSchrempf Frieder struct nand_device *nand = spinand_to_nand(spinand); 7510949af1SSchrempf Frieder u8 mbf = 0; 7610949af1SSchrempf Frieder struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, &mbf); 7710949af1SSchrempf Frieder 7810949af1SSchrempf Frieder switch (status & STATUS_ECC_MASK) { 7910949af1SSchrempf Frieder case STATUS_ECC_NO_BITFLIPS: 8010949af1SSchrempf Frieder return 0; 8110949af1SSchrempf Frieder 8210949af1SSchrempf Frieder case STATUS_ECC_UNCOR_ERROR: 8310949af1SSchrempf Frieder return -EBADMSG; 8410949af1SSchrempf Frieder 8510949af1SSchrempf Frieder case STATUS_ECC_HAS_BITFLIPS: 8610949af1SSchrempf Frieder case TOSH_STATUS_ECC_HAS_BITFLIPS_T: 8710949af1SSchrempf Frieder /* 8810949af1SSchrempf Frieder * Let's try to retrieve the real maximum number of bitflips 8910949af1SSchrempf Frieder * in order to avoid forcing the wear-leveling layer to move 9010949af1SSchrempf Frieder * data around if it's not necessary. 9110949af1SSchrempf Frieder */ 9210949af1SSchrempf Frieder if (spi_mem_exec_op(spinand->spimem, &op)) 939a333a72SMiquel Raynal return nanddev_get_ecc_conf(nand)->strength; 9410949af1SSchrempf Frieder 9510949af1SSchrempf Frieder mbf >>= 4; 9610949af1SSchrempf Frieder 979a333a72SMiquel Raynal if (WARN_ON(mbf > nanddev_get_ecc_conf(nand)->strength || !mbf)) 989a333a72SMiquel Raynal return nanddev_get_ecc_conf(nand)->strength; 9910949af1SSchrempf Frieder 10010949af1SSchrempf Frieder return mbf; 10110949af1SSchrempf Frieder 10210949af1SSchrempf Frieder default: 10310949af1SSchrempf Frieder break; 10410949af1SSchrempf Frieder } 10510949af1SSchrempf Frieder 10610949af1SSchrempf Frieder return -EINVAL; 10710949af1SSchrempf Frieder } 10810949af1SSchrempf Frieder 10910949af1SSchrempf Frieder static const struct spinand_info toshiba_spinand_table[] = { 110798fcdd0SYoshio Furuyama /* 3.3V 1Gb (1st generation) */ 1116b49e58dSYoshio Furuyama SPINAND_INFO("TC58CVG0S3HRAIG", 112f1541773SChuanhong Guo SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xC2), 113377e517bSBoris Brezillon NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), 114db214513SYoshio Furuyama NAND_ECCREQ(8, 512), 115db214513SYoshio Furuyama SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 116db214513SYoshio Furuyama &write_cache_variants, 117db214513SYoshio Furuyama &update_cache_variants), 118db214513SYoshio Furuyama 0, 1196b49e58dSYoshio Furuyama SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, 1206b49e58dSYoshio Furuyama tx58cxgxsxraix_ecc_get_status)), 121798fcdd0SYoshio Furuyama /* 3.3V 2Gb (1st generation) */ 1226b49e58dSYoshio Furuyama SPINAND_INFO("TC58CVG1S3HRAIG", 123f1541773SChuanhong Guo SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xCB), 124377e517bSBoris Brezillon NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), 125db214513SYoshio Furuyama NAND_ECCREQ(8, 512), 126db214513SYoshio Furuyama SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 127db214513SYoshio Furuyama &write_cache_variants, 128db214513SYoshio Furuyama &update_cache_variants), 129db214513SYoshio Furuyama 0, 1306b49e58dSYoshio Furuyama SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, 1316b49e58dSYoshio Furuyama tx58cxgxsxraix_ecc_get_status)), 132798fcdd0SYoshio Furuyama /* 3.3V 4Gb (1st generation) */ 1336b49e58dSYoshio Furuyama SPINAND_INFO("TC58CVG2S0HRAIG", 134f1541773SChuanhong Guo SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xCD), 135377e517bSBoris Brezillon NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), 13610949af1SSchrempf Frieder NAND_ECCREQ(8, 512), 13710949af1SSchrempf Frieder SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 13810949af1SSchrempf Frieder &write_cache_variants, 13910949af1SSchrempf Frieder &update_cache_variants), 140db214513SYoshio Furuyama 0, 1416b49e58dSYoshio Furuyama SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, 1426b49e58dSYoshio Furuyama tx58cxgxsxraix_ecc_get_status)), 143798fcdd0SYoshio Furuyama /* 1.8V 1Gb (1st generation) */ 1446b49e58dSYoshio Furuyama SPINAND_INFO("TC58CYG0S3HRAIG", 145f1541773SChuanhong Guo SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xB2), 146377e517bSBoris Brezillon NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), 147db214513SYoshio Furuyama NAND_ECCREQ(8, 512), 148db214513SYoshio Furuyama SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 149db214513SYoshio Furuyama &write_cache_variants, 150db214513SYoshio Furuyama &update_cache_variants), 151db214513SYoshio Furuyama 0, 1526b49e58dSYoshio Furuyama SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, 1536b49e58dSYoshio Furuyama tx58cxgxsxraix_ecc_get_status)), 154798fcdd0SYoshio Furuyama /* 1.8V 2Gb (1st generation) */ 1556b49e58dSYoshio Furuyama SPINAND_INFO("TC58CYG1S3HRAIG", 156f1541773SChuanhong Guo SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBB), 157377e517bSBoris Brezillon NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), 158db214513SYoshio Furuyama NAND_ECCREQ(8, 512), 159db214513SYoshio Furuyama SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 160db214513SYoshio Furuyama &write_cache_variants, 161db214513SYoshio Furuyama &update_cache_variants), 162db214513SYoshio Furuyama 0, 1636b49e58dSYoshio Furuyama SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, 1646b49e58dSYoshio Furuyama tx58cxgxsxraix_ecc_get_status)), 165798fcdd0SYoshio Furuyama /* 1.8V 4Gb (1st generation) */ 1666b49e58dSYoshio Furuyama SPINAND_INFO("TC58CYG2S0HRAIG", 167f1541773SChuanhong Guo SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBD), 168377e517bSBoris Brezillon NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), 169db214513SYoshio Furuyama NAND_ECCREQ(8, 512), 170db214513SYoshio Furuyama SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 171db214513SYoshio Furuyama &write_cache_variants, 172db214513SYoshio Furuyama &update_cache_variants), 173db214513SYoshio Furuyama 0, 1746b49e58dSYoshio Furuyama SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, 1756b49e58dSYoshio Furuyama tx58cxgxsxraix_ecc_get_status)), 176798fcdd0SYoshio Furuyama 177798fcdd0SYoshio Furuyama /* 178798fcdd0SYoshio Furuyama * 2nd generation serial nand has HOLD_D which is equivalent to 179798fcdd0SYoshio Furuyama * QE_BIT. 180798fcdd0SYoshio Furuyama */ 181798fcdd0SYoshio Furuyama /* 3.3V 1Gb (2nd generation) */ 182798fcdd0SYoshio Furuyama SPINAND_INFO("TC58CVG0S3HRAIJ", 183798fcdd0SYoshio Furuyama SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE2), 184798fcdd0SYoshio Furuyama NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), 185798fcdd0SYoshio Furuyama NAND_ECCREQ(8, 512), 186798fcdd0SYoshio Furuyama SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 187798fcdd0SYoshio Furuyama &write_cache_x4_variants, 188798fcdd0SYoshio Furuyama &update_cache_x4_variants), 189798fcdd0SYoshio Furuyama SPINAND_HAS_QE_BIT, 190798fcdd0SYoshio Furuyama SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, 191798fcdd0SYoshio Furuyama tx58cxgxsxraix_ecc_get_status)), 192798fcdd0SYoshio Furuyama /* 3.3V 2Gb (2nd generation) */ 193798fcdd0SYoshio Furuyama SPINAND_INFO("TC58CVG1S3HRAIJ", 194798fcdd0SYoshio Furuyama SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xEB), 195798fcdd0SYoshio Furuyama NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), 196798fcdd0SYoshio Furuyama NAND_ECCREQ(8, 512), 197798fcdd0SYoshio Furuyama SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 198798fcdd0SYoshio Furuyama &write_cache_x4_variants, 199798fcdd0SYoshio Furuyama &update_cache_x4_variants), 200798fcdd0SYoshio Furuyama SPINAND_HAS_QE_BIT, 201798fcdd0SYoshio Furuyama SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, 202798fcdd0SYoshio Furuyama tx58cxgxsxraix_ecc_get_status)), 203798fcdd0SYoshio Furuyama /* 3.3V 4Gb (2nd generation) */ 204798fcdd0SYoshio Furuyama SPINAND_INFO("TC58CVG2S0HRAIJ", 205798fcdd0SYoshio Furuyama SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xED), 206798fcdd0SYoshio Furuyama NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), 207798fcdd0SYoshio Furuyama NAND_ECCREQ(8, 512), 208798fcdd0SYoshio Furuyama SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 209798fcdd0SYoshio Furuyama &write_cache_x4_variants, 210798fcdd0SYoshio Furuyama &update_cache_x4_variants), 211798fcdd0SYoshio Furuyama SPINAND_HAS_QE_BIT, 212798fcdd0SYoshio Furuyama SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, 213798fcdd0SYoshio Furuyama tx58cxgxsxraix_ecc_get_status)), 214798fcdd0SYoshio Furuyama /* 3.3V 8Gb (2nd generation) */ 215798fcdd0SYoshio Furuyama SPINAND_INFO("TH58CVG3S0HRAIJ", 216798fcdd0SYoshio Furuyama SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4), 217798fcdd0SYoshio Furuyama NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1), 218798fcdd0SYoshio Furuyama NAND_ECCREQ(8, 512), 219798fcdd0SYoshio Furuyama SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 220798fcdd0SYoshio Furuyama &write_cache_x4_variants, 221798fcdd0SYoshio Furuyama &update_cache_x4_variants), 222798fcdd0SYoshio Furuyama SPINAND_HAS_QE_BIT, 223798fcdd0SYoshio Furuyama SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, 224798fcdd0SYoshio Furuyama tx58cxgxsxraix_ecc_get_status)), 225798fcdd0SYoshio Furuyama /* 1.8V 1Gb (2nd generation) */ 226798fcdd0SYoshio Furuyama SPINAND_INFO("TC58CYG0S3HRAIJ", 227798fcdd0SYoshio Furuyama SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xD2), 228798fcdd0SYoshio Furuyama NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), 229798fcdd0SYoshio Furuyama NAND_ECCREQ(8, 512), 230798fcdd0SYoshio Furuyama SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 231798fcdd0SYoshio Furuyama &write_cache_x4_variants, 232798fcdd0SYoshio Furuyama &update_cache_x4_variants), 233798fcdd0SYoshio Furuyama SPINAND_HAS_QE_BIT, 234798fcdd0SYoshio Furuyama SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, 235798fcdd0SYoshio Furuyama tx58cxgxsxraix_ecc_get_status)), 236798fcdd0SYoshio Furuyama /* 1.8V 2Gb (2nd generation) */ 237798fcdd0SYoshio Furuyama SPINAND_INFO("TC58CYG1S3HRAIJ", 238798fcdd0SYoshio Furuyama SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xDB), 239798fcdd0SYoshio Furuyama NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), 240798fcdd0SYoshio Furuyama NAND_ECCREQ(8, 512), 241798fcdd0SYoshio Furuyama SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 242798fcdd0SYoshio Furuyama &write_cache_x4_variants, 243798fcdd0SYoshio Furuyama &update_cache_x4_variants), 244798fcdd0SYoshio Furuyama SPINAND_HAS_QE_BIT, 245798fcdd0SYoshio Furuyama SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, 246798fcdd0SYoshio Furuyama tx58cxgxsxraix_ecc_get_status)), 247798fcdd0SYoshio Furuyama /* 1.8V 4Gb (2nd generation) */ 248798fcdd0SYoshio Furuyama SPINAND_INFO("TC58CYG2S0HRAIJ", 249798fcdd0SYoshio Furuyama SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xDD), 250798fcdd0SYoshio Furuyama NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), 251798fcdd0SYoshio Furuyama NAND_ECCREQ(8, 512), 252798fcdd0SYoshio Furuyama SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 253798fcdd0SYoshio Furuyama &write_cache_x4_variants, 254798fcdd0SYoshio Furuyama &update_cache_x4_variants), 255798fcdd0SYoshio Furuyama SPINAND_HAS_QE_BIT, 256798fcdd0SYoshio Furuyama SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, 257798fcdd0SYoshio Furuyama tx58cxgxsxraix_ecc_get_status)), 258798fcdd0SYoshio Furuyama /* 1.8V 8Gb (2nd generation) */ 259798fcdd0SYoshio Furuyama SPINAND_INFO("TH58CYG3S0HRAIJ", 260798fcdd0SYoshio Furuyama SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xD4), 261798fcdd0SYoshio Furuyama NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1), 262798fcdd0SYoshio Furuyama NAND_ECCREQ(8, 512), 263798fcdd0SYoshio Furuyama SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 264798fcdd0SYoshio Furuyama &write_cache_x4_variants, 265798fcdd0SYoshio Furuyama &update_cache_x4_variants), 266798fcdd0SYoshio Furuyama SPINAND_HAS_QE_BIT, 267798fcdd0SYoshio Furuyama SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, 268798fcdd0SYoshio Furuyama tx58cxgxsxraix_ecc_get_status)), 26910949af1SSchrempf Frieder }; 27010949af1SSchrempf Frieder 27110949af1SSchrempf Frieder static const struct spinand_manufacturer_ops toshiba_spinand_manuf_ops = { 27210949af1SSchrempf Frieder }; 27310949af1SSchrempf Frieder 27410949af1SSchrempf Frieder const struct spinand_manufacturer toshiba_spinand_manufacturer = { 27510949af1SSchrempf Frieder .id = SPINAND_MFR_TOSHIBA, 27610949af1SSchrempf Frieder .name = "Toshiba", 277f1541773SChuanhong Guo .chips = toshiba_spinand_table, 278f1541773SChuanhong Guo .nchips = ARRAY_SIZE(toshiba_spinand_table), 27910949af1SSchrempf Frieder .ops = &toshiba_spinand_manuf_ops, 28010949af1SSchrempf Frieder }; 281