1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2020 Rockchip Electronics Co., Ltd 4 * 5 * Authors: 6 * Dingqiang Lin <jon.lin@rock-chips.com> 7 */ 8 9 #ifndef __UBOOT__ 10 #include <linux/device.h> 11 #include <linux/kernel.h> 12 #endif 13 #include <linux/mtd/spinand.h> 14 15 #define SPINAND_MFR_XTX 0x0B 16 17 static 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 23 static SPINAND_OP_VARIANTS(write_cache_variants, 24 SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), 25 SPINAND_PROG_LOAD(true, 0, NULL, 0)); 26 27 static SPINAND_OP_VARIANTS(update_cache_variants, 28 SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), 29 SPINAND_PROG_LOAD(false, 0, NULL, 0)); 30 31 static int xt26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section, 32 struct mtd_oob_region *region) 33 { 34 if (section) 35 return -ERANGE; 36 37 region->offset = 48; 38 region->length = 16; 39 40 return 0; 41 } 42 43 static int xt26g0xa_ooblayout_free(struct mtd_info *mtd, int section, 44 struct mtd_oob_region *region) 45 { 46 if (section) 47 return -ERANGE; 48 49 region->offset = 2; 50 region->length = mtd->oobsize - 18; 51 52 return 0; 53 } 54 55 static const struct mtd_ooblayout_ops xt26g0xa_ooblayout = { 56 .ecc = xt26g0xa_ooblayout_ecc, 57 .rfree = xt26g0xa_ooblayout_free, 58 }; 59 60 static int xt26g01b_ooblayout_ecc(struct mtd_info *mtd, int section, 61 struct mtd_oob_region *region) 62 { 63 return -ERANGE; 64 } 65 66 static int xt26g01b_ooblayout_free(struct mtd_info *mtd, int section, 67 struct mtd_oob_region *region) 68 { 69 if (section) 70 return -ERANGE; 71 72 region->offset = 2; 73 region->length = mtd->oobsize - 2; 74 75 return 0; 76 } 77 78 static const struct mtd_ooblayout_ops xt26g01b_ooblayout = { 79 .ecc = xt26g01b_ooblayout_ecc, 80 .rfree = xt26g01b_ooblayout_free, 81 }; 82 83 static int xt26g02b_ooblayout_ecc(struct mtd_info *mtd, int section, 84 struct mtd_oob_region *region) 85 { 86 if (section > 3) 87 return -ERANGE; 88 89 region->offset = (16 * section) + 8; 90 region->length = 8; 91 92 return 0; 93 } 94 95 static int xt26g02b_ooblayout_free(struct mtd_info *mtd, int section, 96 struct mtd_oob_region *region) 97 { 98 if (section > 3) 99 return -ERANGE; 100 101 region->offset = (16 * section) + 2; 102 region->length = 6; 103 104 return 0; 105 } 106 107 static const struct mtd_ooblayout_ops xt26g02b_ooblayout = { 108 .ecc = xt26g02b_ooblayout_ecc, 109 .rfree = xt26g02b_ooblayout_free, 110 }; 111 112 static int xt26g01c_ooblayout_ecc(struct mtd_info *mtd, int section, 113 struct mtd_oob_region *region) 114 { 115 if (section) 116 return -ERANGE; 117 118 region->offset = mtd->oobsize / 2; 119 region->length = mtd->oobsize / 2; 120 121 return 0; 122 } 123 124 static int xt26g01c_ooblayout_free(struct mtd_info *mtd, int section, 125 struct mtd_oob_region *region) 126 { 127 if (section) 128 return -ERANGE; 129 130 region->offset = 2; 131 region->length = mtd->oobsize / 2 - 2; 132 133 return 0; 134 } 135 136 static const struct mtd_ooblayout_ops xt26g01c_ooblayout = { 137 .ecc = xt26g01c_ooblayout_ecc, 138 .rfree = xt26g01c_ooblayout_free, 139 }; 140 141 /* 142 * ecc bits: 0xC0[2,5] 143 * [0x0000], No bit errors were detected; 144 * [0x0001, 0x0111], Bit errors were detected and corrected. Not 145 * reach Flipping Bits; 146 * [0x1000], Multiple bit errors were detected and 147 * not corrected. 148 * [0x1100], Bit error count equals the bit flip 149 * detectionthreshold 150 * else, reserved 151 */ 152 static int xt26g0xa_ecc_get_status(struct spinand_device *spinand, 153 u8 status) 154 { 155 u8 eccsr = (status & GENMASK(5, 2)) >> 2; 156 157 if (eccsr <= 7) 158 return eccsr; 159 else if (eccsr == 12) 160 return 8; 161 else 162 return -EBADMSG; 163 } 164 165 /* 166 * ecc bits: 0xC0[4,6] 167 * [0x0], No bit errors were detected; 168 * [0x001, 0x011], Bit errors were detected and corrected. Not 169 * reach Flipping Bits; 170 * [0x100], Bit error count equals the bit flip 171 * detectionthreshold 172 * [0x101, 0x110], Reserved; 173 * [0x111], Multiple bit errors were detected and 174 * not corrected. 175 */ 176 static int xt26g02b_ecc_get_status(struct spinand_device *spinand, 177 u8 status) 178 { 179 u8 eccsr = (status & GENMASK(6, 4)) >> 4; 180 181 if (eccsr <= 4) 182 return eccsr; 183 else 184 return -EBADMSG; 185 } 186 187 /* 188 * ecc bits: 0xC0[4,7] 189 * [0b0000], No bit errors were detected; 190 * [0b0001, 0b0111], 1-7 Bit errors were detected and corrected. Not 191 * reach Flipping Bits; 192 * [0b1000], 8 Bit errors were detected and corrected. Bit error count 193 * equals the bit flip detectionthreshold; 194 * [0b1111], Bit errors greater than ECC capability(8 bits) and not corrected; 195 * others, Reserved. 196 */ 197 static int xt26g01c_ecc_get_status(struct spinand_device *spinand, 198 u8 status) 199 { 200 u8 eccsr = (status & GENMASK(7, 4)) >> 4; 201 202 if (eccsr <= 8) 203 return eccsr; 204 else 205 return -EBADMSG; 206 } 207 208 static const struct spinand_info xtx_spinand_table[] = { 209 SPINAND_INFO("XT26G01A", 0xE1, 210 NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1), 211 NAND_ECCREQ(8, 512), 212 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 213 &write_cache_variants, 214 &update_cache_variants), 215 SPINAND_HAS_QE_BIT, 216 SPINAND_ECCINFO(&xt26g0xa_ooblayout, 217 xt26g0xa_ecc_get_status)), 218 SPINAND_INFO("XT26G02A", 0xE2, 219 NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1), 220 NAND_ECCREQ(8, 512), 221 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 222 &write_cache_variants, 223 &update_cache_variants), 224 SPINAND_HAS_QE_BIT, 225 SPINAND_ECCINFO(&xt26g0xa_ooblayout, 226 xt26g0xa_ecc_get_status)), 227 SPINAND_INFO("XT26G04A", 0xE3, 228 NAND_MEMORG(1, 2048, 64, 128, 2048, 1, 1, 1), 229 NAND_ECCREQ(8, 512), 230 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 231 &write_cache_variants, 232 &update_cache_variants), 233 SPINAND_HAS_QE_BIT, 234 SPINAND_ECCINFO(&xt26g0xa_ooblayout, 235 xt26g0xa_ecc_get_status)), 236 SPINAND_INFO("XT26G01B", 0xF1, 237 NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1), 238 NAND_ECCREQ(8, 512), 239 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 240 &write_cache_variants, 241 &update_cache_variants), 242 SPINAND_HAS_QE_BIT, 243 SPINAND_ECCINFO(&xt26g01b_ooblayout, 244 xt26g0xa_ecc_get_status)), 245 SPINAND_INFO("XT26G02B", 0xF2, 246 NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1), 247 NAND_ECCREQ(4, 512), 248 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 249 &write_cache_variants, 250 &update_cache_variants), 251 SPINAND_HAS_QE_BIT, 252 SPINAND_ECCINFO(&xt26g02b_ooblayout, 253 xt26g02b_ecc_get_status)), 254 SPINAND_INFO("XT26G01C", 0x11, 255 NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1), 256 NAND_ECCREQ(8, 512), 257 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 258 &write_cache_variants, 259 &update_cache_variants), 260 SPINAND_HAS_QE_BIT, 261 SPINAND_ECCINFO(&xt26g01c_ooblayout, 262 xt26g01c_ecc_get_status)), 263 SPINAND_INFO("XT26G02C", 0x12, 264 NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1), 265 NAND_ECCREQ(8, 512), 266 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 267 &write_cache_variants, 268 &update_cache_variants), 269 SPINAND_HAS_QE_BIT, 270 SPINAND_ECCINFO(&xt26g0xa_ooblayout, 271 xt26g01c_ecc_get_status)), 272 SPINAND_INFO("XT26G04C", 0x13, 273 NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1), 274 NAND_ECCREQ(8, 512), 275 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 276 &write_cache_variants, 277 &update_cache_variants), 278 SPINAND_HAS_QE_BIT, 279 SPINAND_ECCINFO(&xt26g01c_ooblayout, 280 xt26g01c_ecc_get_status)), 281 SPINAND_INFO("XT26G11C", 0x15, 282 NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1), 283 NAND_ECCREQ(8, 512), 284 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 285 &write_cache_variants, 286 &update_cache_variants), 287 SPINAND_HAS_QE_BIT, 288 SPINAND_ECCINFO(&xt26g01c_ooblayout, 289 xt26g01c_ecc_get_status)), 290 }; 291 292 static int xtx_spinand_detect(struct spinand_device *spinand) 293 { 294 u8 *id = spinand->id.data; 295 int ret; 296 297 /* 298 * XTX SPI NAND read ID needs a dummy byte, so the first byte in 299 * raw_id is garbage. 300 */ 301 if (id[1] != SPINAND_MFR_XTX) 302 return 0; 303 304 ret = spinand_match_and_init(spinand, xtx_spinand_table, 305 ARRAY_SIZE(xtx_spinand_table), 306 id[2]); 307 if (ret) 308 return ret; 309 310 return 1; 311 } 312 313 static const struct spinand_manufacturer_ops xtx_spinand_manuf_ops = { 314 .detect = xtx_spinand_detect, 315 }; 316 317 const struct spinand_manufacturer xtx_spinand_manufacturer = { 318 .id = SPINAND_MFR_XTX, 319 .name = "xtx", 320 .ops = &xtx_spinand_manuf_ops, 321 }; 322