1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2021 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_UNIM_ZL 0xA1 16 #define SPINAND_MFR_UNIM 0xB0 17 18 static SPINAND_OP_VARIANTS(read_cache_variants, 19 SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), 20 SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), 21 SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), 22 SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), 23 SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), 24 SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); 25 26 static SPINAND_OP_VARIANTS(write_cache_variants, 27 SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), 28 SPINAND_PROG_LOAD(true, 0, NULL, 0)); 29 30 static SPINAND_OP_VARIANTS(update_cache_variants, 31 SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), 32 SPINAND_PROG_LOAD(true, 0, NULL, 0)); 33 34 static int tx25g01_ooblayout_ecc(struct mtd_info *mtd, int section, 35 struct mtd_oob_region *region) 36 { 37 if (section > 3) 38 return -ERANGE; 39 40 region->offset = (16 * section) + 8; 41 region->length = 8; 42 43 return 0; 44 } 45 46 static int tx25g01_ooblayout_free(struct mtd_info *mtd, int section, 47 struct mtd_oob_region *region) 48 { 49 if (section > 3) 50 return -ERANGE; 51 52 region->offset = (16 * section) + 2; 53 region->length = 6; 54 55 return 0; 56 } 57 58 static const struct mtd_ooblayout_ops tx25g01_ooblayout = { 59 .ecc = tx25g01_ooblayout_ecc, 60 .rfree = tx25g01_ooblayout_free, 61 }; 62 63 64 static int um19a0xisw_ooblayout_ecc(struct mtd_info *mtd, int section, 65 struct mtd_oob_region *region) 66 { 67 return -ERANGE; 68 } 69 70 static int um19a0xisw_ooblayout_free(struct mtd_info *mtd, int section, 71 struct mtd_oob_region *region) 72 { 73 if (section) 74 return -ERANGE; 75 76 region->offset = 2; 77 region->length = 62; 78 79 return 0; 80 } 81 82 static const struct mtd_ooblayout_ops um19a0xisw_ooblayout = { 83 .ecc = um19a0xisw_ooblayout_ecc, 84 .rfree = um19a0xisw_ooblayout_free, 85 }; 86 87 static int um19a1xisw_ooblayout_ecc(struct mtd_info *mtd, int section, 88 struct mtd_oob_region *region) 89 { 90 if (section) 91 return -ERANGE; 92 93 region->offset = 64; 94 region->length = 64; 95 96 return 0; 97 } 98 99 static int um19a1xisw_ooblayout_free(struct mtd_info *mtd, int section, 100 struct mtd_oob_region *region) 101 { 102 if (section) 103 return -ERANGE; 104 105 region->offset = 2; 106 region->length = 62; 107 108 return 0; 109 } 110 111 static const struct mtd_ooblayout_ops um19a1xisw_ooblayout = { 112 .ecc = um19a1xisw_ooblayout_ecc, 113 .rfree = um19a1xisw_ooblayout_free, 114 }; 115 116 /* 117 * ecc bits: 0xC0[4,6] 118 * [0b000], No bit errors were detected; 119 * [0b001, 0b011], 1~3 Bit errors were detected and corrected. Not 120 * reach Flipping Bits; 121 * [0b100], Bit error count equals the bit flip 122 * detection threshold 123 * others, Reserved. 124 */ 125 static int tx25g01_ecc_get_status(struct spinand_device *spinand, 126 u8 status) 127 { 128 struct nand_device *nand = spinand_to_nand(spinand); 129 u8 eccsr = (status & GENMASK(6, 4)) >> 4; 130 131 if (eccsr < 4) 132 return eccsr; 133 else if (eccsr == 4) 134 return nand->eccreq.strength; 135 else 136 return -EBADMSG; 137 } 138 139 /* 140 * ecc bits: 0xC0[4,6] 141 * [0b000], No bit errors were detected; 142 * [0b001] and [0b011], 1~6 Bit errors were detected and corrected. Not 143 * reach Flipping Bits; 144 * [0b101], Bit error count equals the bit flip 145 * detection threshold 146 * [0b010], Multiple bit errors were detected and 147 * not corrected. 148 * others, Reserved. 149 */ 150 static int um19axxisw_ecc_ecc_get_status(struct spinand_device *spinand, 151 u8 status) 152 { 153 struct nand_device *nand = spinand_to_nand(spinand); 154 u8 eccsr = (status & GENMASK(6, 4)) >> 4; 155 156 if (eccsr <= 1 || eccsr == 3) 157 return eccsr; 158 else if (eccsr == 5) 159 return nand->eccreq.strength; 160 else 161 return -EBADMSG; 162 } 163 164 /* 165 * ecc bits: 0xC0[4,5] 166 * 0b00, No bit errors were detected 167 * 0b01, Bit errors were detected and corrected. 168 * 0b10, Multiple bit errors were detected and not corrected. 169 * 0b11, Bits errors were detected and corrected, bit error count 170 * reach the bit flip detection threshold 171 */ 172 static int um19a9xisw_ecc_get_status(struct spinand_device *spinand, 173 u8 status) 174 { 175 struct nand_device *nand = spinand_to_nand(spinand); 176 177 switch (status & STATUS_ECC_MASK) { 178 case STATUS_ECC_NO_BITFLIPS: 179 case STATUS_ECC_HAS_BITFLIPS: 180 return 0; 181 case STATUS_ECC_UNCOR_ERROR: 182 return -EBADMSG; 183 default: 184 return nand->eccreq.strength; 185 } 186 } 187 188 static const struct spinand_info unim_zl_spinand_table[] = { 189 SPINAND_INFO("TX25G01", 190 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xF1), 191 NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1), 192 NAND_ECCREQ(4, 512), 193 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 194 &write_cache_variants, 195 &update_cache_variants), 196 SPINAND_HAS_QE_BIT, 197 SPINAND_ECCINFO(&tx25g01_ooblayout, tx25g01_ecc_get_status)), 198 }; 199 200 static const struct spinand_info unim_spinand_table[] = { 201 SPINAND_INFO("UM19A1HISW", 202 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24), 203 NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1), 204 NAND_ECCREQ(8, 512), 205 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 206 &write_cache_variants, 207 &update_cache_variants), 208 SPINAND_HAS_QE_BIT, 209 SPINAND_ECCINFO(&um19a1xisw_ooblayout, um19axxisw_ecc_ecc_get_status)), 210 SPINAND_INFO("UM19A0HCSW", 211 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14), 212 NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1), 213 NAND_ECCREQ(8, 512), 214 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 215 &write_cache_variants, 216 &update_cache_variants), 217 SPINAND_HAS_QE_BIT, 218 SPINAND_ECCINFO(&um19a0xisw_ooblayout, um19axxisw_ecc_ecc_get_status)), 219 SPINAND_INFO("UM19A0LCSW", 220 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15), 221 NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1), 222 NAND_ECCREQ(8, 512), 223 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 224 &write_cache_variants, 225 &update_cache_variants), 226 SPINAND_HAS_QE_BIT, 227 SPINAND_ECCINFO(&um19a0xisw_ooblayout, um19axxisw_ecc_ecc_get_status)), 228 SPINAND_INFO("UM19A1LISW", 229 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25), 230 NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1), 231 NAND_ECCREQ(8, 512), 232 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 233 &write_cache_variants, 234 &update_cache_variants), 235 SPINAND_HAS_QE_BIT, 236 SPINAND_ECCINFO(&um19a1xisw_ooblayout, um19axxisw_ecc_ecc_get_status)), 237 SPINAND_INFO("UM19A9LISW", 238 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x0D), 239 NAND_MEMORG(1, 2048, 128, 64, 512, 1, 1, 1), 240 NAND_ECCREQ(4, 512), 241 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 242 &write_cache_variants, 243 &update_cache_variants), 244 SPINAND_HAS_QE_BIT, 245 SPINAND_ECCINFO(&um19a1xisw_ooblayout, um19a9xisw_ecc_get_status)), 246 SPINAND_INFO("UM19A9HISW", 247 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x0C), 248 NAND_MEMORG(1, 2048, 128, 64, 512, 1, 1, 1), 249 NAND_ECCREQ(4, 512), 250 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 251 &write_cache_variants, 252 &update_cache_variants), 253 SPINAND_HAS_QE_BIT, 254 SPINAND_ECCINFO(&um19a1xisw_ooblayout, um19a9xisw_ecc_get_status)), 255 }; 256 257 static const struct spinand_manufacturer_ops unim_spinand_manuf_ops = { 258 }; 259 260 const struct spinand_manufacturer unim_zl_spinand_manufacturer = { 261 .id = SPINAND_MFR_UNIM_ZL, 262 .name = "UNIM_ZL", 263 .chips = unim_zl_spinand_table, 264 .nchips = ARRAY_SIZE(unim_zl_spinand_table), 265 .ops = &unim_spinand_manuf_ops, 266 }; 267 268 const struct spinand_manufacturer unim_spinand_manufacturer = { 269 .id = SPINAND_MFR_UNIM, 270 .name = "UNIM", 271 .chips = unim_spinand_table, 272 .nchips = ARRAY_SIZE(unim_spinand_table), 273 .ops = &unim_spinand_manuf_ops, 274 }; 275