1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2018 Stefan Roese <sr@denx.de> 4 * 5 * Derived from drivers/mtd/nand/spi/micron.c 6 * Copyright (c) 2016-2017 Micron Technology, Inc. 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_GIGADEVICE 0xC8 16 #define GD5FXGQ4XA_STATUS_ECC_BELOW_BITFLIPS (1 << 4) 17 #define GD5FXGQ4XA_STATUS_ECC_MAX_BITFLIPS (3 << 4) 18 19 #define GD5FXGQ4XEXXG_REG_STATUS2 0xf0 20 21 static SPINAND_OP_VARIANTS(read_cache_variants, 22 SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), 23 SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), 24 SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), 25 SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), 26 SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), 27 SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); 28 29 static SPINAND_OP_VARIANTS(write_cache_variants, 30 SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), 31 SPINAND_PROG_LOAD(true, 0, NULL, 0)); 32 33 static SPINAND_OP_VARIANTS(update_cache_variants, 34 SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), 35 SPINAND_PROG_LOAD(false, 0, NULL, 0)); 36 37 static int gd5fxgq4xexxg_ooblayout_ecc(struct mtd_info *mtd, int section, 38 struct mtd_oob_region *region) 39 { 40 if (section) 41 return -ERANGE; 42 43 region->offset = 64; 44 region->length = 64; 45 46 return 0; 47 } 48 49 static int gd5fxgq4xexxg_ooblayout_free(struct mtd_info *mtd, int section, 50 struct mtd_oob_region *region) 51 { 52 if (section) 53 return -ERANGE; 54 55 /* Reserve 1 bytes for the BBM. */ 56 region->offset = 1; 57 region->length = 63; 58 59 return 0; 60 } 61 62 static int gd5f1gq4xexxg_ecc_get_status(struct spinand_device *spinand, 63 u8 status) 64 { 65 u8 status2; 66 struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQ4XEXXG_REG_STATUS2, 67 &status2); 68 int ret; 69 70 switch (status & STATUS_ECC_MASK) { 71 case STATUS_ECC_NO_BITFLIPS: 72 return 0; 73 74 case GD5FXGQ4XA_STATUS_ECC_BELOW_BITFLIPS: 75 /* 76 * Read status2 register to determine a more fine grained 77 * bit error status 78 */ 79 ret = spi_mem_exec_op(spinand->slave, &op); 80 if (ret) 81 return ret; 82 83 /* 84 * 4 ... 7 bits are flipped (1..4 can't be detected, so 85 * report the maximum of 4 in this case 86 */ 87 /* bits sorted this way (3...0): ECCS1,ECCS0,ECCSE1,ECCSE0 */ 88 return ((status & STATUS_ECC_MASK) >> 2) | 89 ((status2 & STATUS_ECC_MASK) >> 4); 90 91 case GD5FXGQ4XA_STATUS_ECC_MAX_BITFLIPS: 92 return 8; 93 94 case STATUS_ECC_UNCOR_ERROR: 95 return -EBADMSG; 96 97 default: 98 break; 99 } 100 101 return -EINVAL; 102 } 103 104 static int gd5fxgq5xexxg_ecc_get_status(struct spinand_device *spinand, 105 u8 status) 106 { 107 u8 status2; 108 struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQ4XEXXG_REG_STATUS2, 109 &status2); 110 int ret; 111 112 switch (status & STATUS_ECC_MASK) { 113 case STATUS_ECC_NO_BITFLIPS: 114 return 0; 115 116 case GD5FXGQ4XA_STATUS_ECC_BELOW_BITFLIPS: 117 /* 118 * Read status2 register to determine a more fine grained 119 * bit error status 120 */ 121 ret = spi_mem_exec_op(spinand->slave, &op); 122 if (ret) 123 return ret; 124 125 /* 126 * 1 ... 4 bits are flipped (1..4 can't be detected, so 127 * report the maximum of 4 in this case 128 */ 129 /* bits sorted this way (3...0): ECCS1,ECCS0,ECCSE1,ECCSE0 */ 130 return (((status & STATUS_ECC_MASK) >> 2) | 131 ((status2 & STATUS_ECC_MASK) >> 4)) - 3; 132 133 case GD5FXGQ4XA_STATUS_ECC_MAX_BITFLIPS: 134 return -EBADMSG; 135 136 case STATUS_ECC_UNCOR_ERROR: 137 return -EBADMSG; 138 139 default: 140 break; 141 } 142 143 return -EINVAL; 144 } 145 146 static const struct mtd_ooblayout_ops gd5fxgq4xexxg_ooblayout = { 147 .ecc = gd5fxgq4xexxg_ooblayout_ecc, 148 .rfree = gd5fxgq4xexxg_ooblayout_free, 149 }; 150 151 static int gd5fxgq4xexxh_ooblayout_ecc(struct mtd_info *mtd, int section, 152 struct mtd_oob_region *region) 153 { 154 return -ERANGE; 155 } 156 157 static int gd5fxgq4xexxh_ooblayout_free(struct mtd_info *mtd, int section, 158 struct mtd_oob_region *region) 159 { 160 if (section) 161 return -ERANGE; 162 163 /* Reserve 1 bytes for the BBM. */ 164 region->offset = 1; 165 region->length = 63; 166 167 return 0; 168 } 169 170 static const struct mtd_ooblayout_ops gd5fxgq4xexxh_ooblayout = { 171 .ecc = gd5fxgq4xexxh_ooblayout_ecc, 172 .rfree = gd5fxgq4xexxh_ooblayout_free, 173 }; 174 175 static const struct spinand_info gigadevice_spinand_table[] = { 176 SPINAND_INFO("GD5F1GQ4UExxG", 177 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd1), 178 NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1), 179 NAND_ECCREQ(8, 512), 180 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 181 &write_cache_variants, 182 &update_cache_variants), 183 SPINAND_HAS_QE_BIT, 184 SPINAND_ECCINFO(&gd5fxgq4xexxg_ooblayout, 185 gd5f1gq4xexxg_ecc_get_status)), 186 SPINAND_INFO("GD5F1GQ5UExxG", 187 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x51), 188 NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1), 189 NAND_ECCREQ(4, 512), 190 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 191 &write_cache_variants, 192 &update_cache_variants), 193 SPINAND_HAS_QE_BIT, 194 SPINAND_ECCINFO(&gd5fxgq4xexxg_ooblayout, 195 gd5fxgq5xexxg_ecc_get_status)), 196 SPINAND_INFO("GD5F2GQ5UExxG", 197 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x52), 198 NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1), 199 NAND_ECCREQ(4, 512), 200 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 201 &write_cache_variants, 202 &update_cache_variants), 203 SPINAND_HAS_QE_BIT, 204 SPINAND_ECCINFO(&gd5fxgq4xexxg_ooblayout, 205 gd5fxgq5xexxg_ecc_get_status)), 206 SPINAND_INFO("GD5F2GQ4UBxxG", 207 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd2), 208 NAND_MEMORG(1, 2048, 128, 64, 2048, 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(&gd5fxgq4xexxg_ooblayout, 215 gd5f1gq4xexxg_ecc_get_status)), 216 SPINAND_INFO("GD5F4GQ6UExxG", 217 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x55), 218 NAND_MEMORG(1, 2048, 128, 64, 4096, 1, 1, 1), 219 NAND_ECCREQ(4, 512), 220 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 221 &write_cache_variants, 222 &update_cache_variants), 223 SPINAND_HAS_QE_BIT, 224 SPINAND_ECCINFO(&gd5fxgq4xexxg_ooblayout, 225 gd5fxgq5xexxg_ecc_get_status)), 226 SPINAND_INFO("GD5F1GQ4UExxH", 227 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd9), 228 NAND_MEMORG(1, 2048, 64, 64, 1024, 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(&gd5fxgq4xexxh_ooblayout, 235 gd5f1gq4xexxg_ecc_get_status)), 236 SPINAND_INFO("GD5F1GQ5RExxG", 237 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x41), 238 NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1), 239 NAND_ECCREQ(4, 512), 240 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 241 &write_cache_variants, 242 &update_cache_variants), 243 SPINAND_HAS_QE_BIT, 244 SPINAND_ECCINFO(&gd5fxgq4xexxg_ooblayout, 245 gd5fxgq5xexxg_ecc_get_status)), 246 SPINAND_INFO("GD5F2GQ5RExxG", 247 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x42), 248 NAND_MEMORG(1, 2048, 128, 64, 2048, 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(&gd5fxgq4xexxg_ooblayout, 255 gd5fxgq5xexxg_ecc_get_status)), 256 SPINAND_INFO("GD5F2GM7RxG", 257 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x82), 258 NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1), 259 NAND_ECCREQ(8, 512), 260 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 261 &write_cache_variants, 262 &update_cache_variants), 263 SPINAND_HAS_QE_BIT, 264 SPINAND_ECCINFO(&gd5fxgq4xexxg_ooblayout, 265 gd5f1gq4xexxg_ecc_get_status)), 266 SPINAND_INFO("GD5F2GM7UxG", 267 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x92), 268 NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1), 269 NAND_ECCREQ(8, 512), 270 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 271 &write_cache_variants, 272 &update_cache_variants), 273 SPINAND_HAS_QE_BIT, 274 SPINAND_ECCINFO(&gd5fxgq4xexxg_ooblayout, 275 gd5f1gq4xexxg_ecc_get_status)), 276 }; 277 278 static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = { 279 }; 280 281 const struct spinand_manufacturer gigadevice_spinand_manufacturer = { 282 .id = SPINAND_MFR_GIGADEVICE, 283 .name = "GigaDevice", 284 .chips = gigadevice_spinand_table, 285 .nchips = ARRAY_SIZE(gigadevice_spinand_table), 286 .ops = &gigadevice_spinand_manuf_ops, 287 }; 288