1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2018 exceet electronics GmbH 4 * Copyright (c) 2018 Kontron Electronics GmbH 5 * 6 * Author: Frieder Schrempf <frieder.schrempf@kontron.de> 7 */ 8 9 #ifndef __UBOOT__ 10 #include <malloc.h> 11 #include <linux/device.h> 12 #include <linux/kernel.h> 13 #endif 14 #include <linux/mtd/spinand.h> 15 16 #define SPINAND_MFR_TOSHIBA 0x98 17 #define TOSH_STATUS_ECC_HAS_BITFLIPS_T (3 << 4) 18 19 static SPINAND_OP_VARIANTS(read_cache_variants, 20 SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), 21 SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), 22 SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), 23 SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); 24 25 static SPINAND_OP_VARIANTS(write_cache_variants, 26 SPINAND_PROG_LOAD(true, 0, NULL, 0)); 27 28 static SPINAND_OP_VARIANTS(update_cache_variants, 29 SPINAND_PROG_LOAD(false, 0, NULL, 0)); 30 31 static int tc58cxgxsx_ooblayout_ecc(struct mtd_info *mtd, int section, 32 struct mtd_oob_region *region) 33 { 34 if (section > 0) 35 return -ERANGE; 36 37 region->offset = mtd->oobsize / 2; 38 region->length = mtd->oobsize / 2; 39 40 return 0; 41 } 42 43 static int tc58cxgxsx_ooblayout_free(struct mtd_info *mtd, int section, 44 struct mtd_oob_region *region) 45 { 46 if (section > 0) 47 return -ERANGE; 48 49 /* 2 bytes reserved for BBM */ 50 region->offset = 2; 51 region->length = (mtd->oobsize / 2) - 2; 52 53 return 0; 54 } 55 56 static const struct mtd_ooblayout_ops tc58cxgxsx_ooblayout = { 57 .ecc = tc58cxgxsx_ooblayout_ecc, 58 .rfree = tc58cxgxsx_ooblayout_free, 59 }; 60 61 static int tc58cxgxsx_ecc_get_status(struct spinand_device *spinand, 62 u8 status) 63 { 64 struct nand_device *nand = spinand_to_nand(spinand); 65 u8 mbf = 0; 66 struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, &mbf); 67 68 switch (status & STATUS_ECC_MASK) { 69 case STATUS_ECC_NO_BITFLIPS: 70 return 0; 71 72 case STATUS_ECC_UNCOR_ERROR: 73 return -EBADMSG; 74 75 case STATUS_ECC_HAS_BITFLIPS: 76 case TOSH_STATUS_ECC_HAS_BITFLIPS_T: 77 /* 78 * Let's try to retrieve the real maximum number of bitflips 79 * in order to avoid forcing the wear-leveling layer to move 80 * data around if it's not necessary. 81 */ 82 if (spi_mem_exec_op(spinand->slave, &op)) 83 return nand->eccreq.strength; 84 85 mbf >>= 4; 86 87 if (WARN_ON(mbf > nand->eccreq.strength || !mbf)) 88 return nand->eccreq.strength; 89 90 return mbf; 91 92 default: 93 break; 94 } 95 96 return -EINVAL; 97 } 98 99 static const struct spinand_info toshiba_spinand_table[] = { 100 /* 3.3V 1Gb */ 101 SPINAND_INFO("TC58CVG0S3", 0xC2, 102 NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1), 103 NAND_ECCREQ(8, 512), 104 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 105 &write_cache_variants, 106 &update_cache_variants), 107 0, 108 SPINAND_ECCINFO(&tc58cxgxsx_ooblayout, 109 tc58cxgxsx_ecc_get_status)), 110 /* 3.3V 2Gb */ 111 SPINAND_INFO("TC58CVG1S3", 0xCB, 112 NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1), 113 NAND_ECCREQ(8, 512), 114 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 115 &write_cache_variants, 116 &update_cache_variants), 117 0, 118 SPINAND_ECCINFO(&tc58cxgxsx_ooblayout, 119 tc58cxgxsx_ecc_get_status)), 120 /* 3.3V 4Gb */ 121 SPINAND_INFO("TC58CVG2S0", 0xCD, 122 NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1), 123 NAND_ECCREQ(8, 512), 124 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 125 &write_cache_variants, 126 &update_cache_variants), 127 0, 128 SPINAND_ECCINFO(&tc58cxgxsx_ooblayout, 129 tc58cxgxsx_ecc_get_status)), 130 /* 1.8V 1Gb */ 131 SPINAND_INFO("TC58CYG0S3", 0xB2, 132 NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1), 133 NAND_ECCREQ(8, 512), 134 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 135 &write_cache_variants, 136 &update_cache_variants), 137 0, 138 SPINAND_ECCINFO(&tc58cxgxsx_ooblayout, 139 tc58cxgxsx_ecc_get_status)), 140 /* 1.8V 2Gb */ 141 SPINAND_INFO("TC58CYG1S3", 0xBB, 142 NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1), 143 NAND_ECCREQ(8, 512), 144 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 145 &write_cache_variants, 146 &update_cache_variants), 147 0, 148 SPINAND_ECCINFO(&tc58cxgxsx_ooblayout, 149 tc58cxgxsx_ecc_get_status)), 150 /* 1.8V 4Gb */ 151 SPINAND_INFO("TC58CYG2S0", 0xBD, 152 NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1), 153 NAND_ECCREQ(8, 512), 154 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 155 &write_cache_variants, 156 &update_cache_variants), 157 0, 158 SPINAND_ECCINFO(&tc58cxgxsx_ooblayout, 159 tc58cxgxsx_ecc_get_status)), 160 /* 3.3V 1Gb */ 161 SPINAND_INFO("TC58CVG0S3HRAIJ", 0xE2, 162 NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1), 163 NAND_ECCREQ(8, 512), 164 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 165 &write_cache_variants, 166 &update_cache_variants), 167 0, 168 SPINAND_ECCINFO(&tc58cxgxsx_ooblayout, 169 tc58cxgxsx_ecc_get_status)), 170 /* 3.3V 2Gb */ 171 SPINAND_INFO("TC58CVG1S3HRAIJ", 0xEB, 172 NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1), 173 NAND_ECCREQ(8, 512), 174 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 175 &write_cache_variants, 176 &update_cache_variants), 177 0, 178 SPINAND_ECCINFO(&tc58cxgxsx_ooblayout, 179 tc58cxgxsx_ecc_get_status)), 180 }; 181 182 static int toshiba_spinand_detect(struct spinand_device *spinand) 183 { 184 u8 *id = spinand->id.data; 185 int ret; 186 187 /* 188 * Toshiba SPI NAND read ID needs a dummy byte, 189 * so the first byte in id is garbage. 190 */ 191 if (id[1] != SPINAND_MFR_TOSHIBA) 192 return 0; 193 194 ret = spinand_match_and_init(spinand, toshiba_spinand_table, 195 ARRAY_SIZE(toshiba_spinand_table), 196 id[2]); 197 if (ret) 198 return ret; 199 200 return 1; 201 } 202 203 static const struct spinand_manufacturer_ops toshiba_spinand_manuf_ops = { 204 .detect = toshiba_spinand_detect, 205 }; 206 207 const struct spinand_manufacturer toshiba_spinand_manufacturer = { 208 .id = SPINAND_MFR_TOSHIBA, 209 .name = "Toshiba", 210 .ops = &toshiba_spinand_manuf_ops, 211 }; 212