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 /* 113 * ecc bits: 0xC0[2,5] 114 * [0x0000], No bit errors were detected; 115 * [0x0001, 0x0111], Bit errors were detected and corrected. Not 116 * reach Flipping Bits; 117 * [0x1000], Multiple bit errors were detected and 118 * not corrected. 119 * [0x1100], Bit error count equals the bit flip 120 * detectionthreshold 121 * else, reserved 122 */ 123 static int xt26g0xa_ecc_get_status(struct spinand_device *spinand, 124 u8 status) 125 { 126 u8 eccsr = (status & GENMASK(5, 2)) >> 2; 127 128 if (eccsr <= 7) 129 return eccsr; 130 else if (eccsr == 12) 131 return 8; 132 else 133 return -EBADMSG; 134 } 135 136 /* 137 * ecc bits: 0xC0[4,6] 138 * [0x0], No bit errors were detected; 139 * [0x001, 0x011], Bit errors were detected and corrected. Not 140 * reach Flipping Bits; 141 * [0x100], Bit error count equals the bit flip 142 * detectionthreshold 143 * [0x101, 0x110], Reserved; 144 * [0x111], Multiple bit errors were detected and 145 * not corrected. 146 */ 147 static int xt26g02b_ecc_get_status(struct spinand_device *spinand, 148 u8 status) 149 { 150 u8 eccsr = (status & GENMASK(6, 4)) >> 4; 151 152 if (eccsr <= 4) 153 return eccsr; 154 else 155 return -EBADMSG; 156 } 157 158 /* 159 * ecc bits: 0xC0[4,7] 160 * [0b0000], No bit errors were detected; 161 * [0b0001, 0b0111], 1-7 Bit errors were detected and corrected. Not 162 * reach Flipping Bits; 163 * [0b1000], 8 Bit errors were detected and corrected. Bit error count 164 * equals the bit flip detectionthreshold; 165 * [0b1111], Bit errors greater than ECC capability(8 bits) and not corrected; 166 * others, Reserved. 167 */ 168 static int xt26g01c_ecc_get_status(struct spinand_device *spinand, 169 u8 status) 170 { 171 u8 eccsr = (status & GENMASK(7, 4)) >> 4; 172 173 if (eccsr <= 8) 174 return eccsr; 175 else 176 return -EBADMSG; 177 } 178 179 static const struct spinand_info xtx_spinand_table[] = { 180 SPINAND_INFO("XT26G01A", 0xE1, 181 NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1), 182 NAND_ECCREQ(8, 512), 183 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 184 &write_cache_variants, 185 &update_cache_variants), 186 SPINAND_HAS_QE_BIT, 187 SPINAND_ECCINFO(&xt26g0xa_ooblayout, 188 xt26g0xa_ecc_get_status)), 189 SPINAND_INFO("XT26G02A", 0xE2, 190 NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1), 191 NAND_ECCREQ(8, 512), 192 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 193 &write_cache_variants, 194 &update_cache_variants), 195 SPINAND_HAS_QE_BIT, 196 SPINAND_ECCINFO(&xt26g0xa_ooblayout, 197 xt26g0xa_ecc_get_status)), 198 SPINAND_INFO("XT26G04A", 0xE3, 199 NAND_MEMORG(1, 2048, 64, 128, 2048, 1, 1, 1), 200 NAND_ECCREQ(8, 512), 201 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 202 &write_cache_variants, 203 &update_cache_variants), 204 SPINAND_HAS_QE_BIT, 205 SPINAND_ECCINFO(&xt26g0xa_ooblayout, 206 xt26g0xa_ecc_get_status)), 207 SPINAND_INFO("XT26G01B", 0xF1, 208 NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1), 209 NAND_ECCREQ(8, 512), 210 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 211 &write_cache_variants, 212 &update_cache_variants), 213 SPINAND_HAS_QE_BIT, 214 SPINAND_ECCINFO(&xt26g01b_ooblayout, 215 xt26g0xa_ecc_get_status)), 216 SPINAND_INFO("XT26G02B", 0xF2, 217 NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1), 218 NAND_ECCREQ(4, 512), 219 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 220 &write_cache_variants, 221 &update_cache_variants), 222 SPINAND_HAS_QE_BIT, 223 SPINAND_ECCINFO(&xt26g02b_ooblayout, 224 xt26g02b_ecc_get_status)), 225 SPINAND_INFO("XT26G01C", 0x11, 226 NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1), 227 NAND_ECCREQ(8, 512), 228 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 229 &write_cache_variants, 230 &update_cache_variants), 231 SPINAND_HAS_QE_BIT, 232 SPINAND_ECCINFO(&xt26g01b_ooblayout, 233 xt26g01c_ecc_get_status)), 234 SPINAND_INFO("XT26G02C", 0x12, 235 NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1), 236 NAND_ECCREQ(8, 512), 237 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 238 &write_cache_variants, 239 &update_cache_variants), 240 SPINAND_HAS_QE_BIT, 241 SPINAND_ECCINFO(&xt26g01b_ooblayout, 242 xt26g01c_ecc_get_status)), 243 SPINAND_INFO("XT26G04C", 0x13, 244 NAND_MEMORG(1, 4096, 128, 64, 2048, 1, 1, 1), 245 NAND_ECCREQ(8, 512), 246 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 247 &write_cache_variants, 248 &update_cache_variants), 249 SPINAND_HAS_QE_BIT, 250 SPINAND_ECCINFO(&xt26g01b_ooblayout, 251 xt26g01c_ecc_get_status)), 252 }; 253 254 static int xtx_spinand_detect(struct spinand_device *spinand) 255 { 256 u8 *id = spinand->id.data; 257 int ret; 258 259 /* 260 * XTX SPI NAND read ID needs a dummy byte, so the first byte in 261 * raw_id is garbage. 262 */ 263 if (id[1] != SPINAND_MFR_XTX) 264 return 0; 265 266 ret = spinand_match_and_init(spinand, xtx_spinand_table, 267 ARRAY_SIZE(xtx_spinand_table), 268 id[2]); 269 if (ret) 270 return ret; 271 272 return 1; 273 } 274 275 static const struct spinand_manufacturer_ops xtx_spinand_manuf_ops = { 276 .detect = xtx_spinand_detect, 277 }; 278 279 const struct spinand_manufacturer xtx_spinand_manufacturer = { 280 .id = SPINAND_MFR_XTX, 281 .name = "xtx", 282 .ops = &xtx_spinand_manuf_ops, 283 }; 284