0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/device.h>
0010 #include <linux/kernel.h>
0011 #include <linux/mtd/spinand.h>
0012
0013 #define SPINAND_MFR_MICRON 0x2c
0014
0015 #define MICRON_STATUS_ECC_MASK GENMASK(7, 4)
0016 #define MICRON_STATUS_ECC_NO_BITFLIPS (0 << 4)
0017 #define MICRON_STATUS_ECC_1TO3_BITFLIPS (1 << 4)
0018 #define MICRON_STATUS_ECC_4TO6_BITFLIPS (3 << 4)
0019 #define MICRON_STATUS_ECC_7TO8_BITFLIPS (5 << 4)
0020
0021 #define MICRON_CFG_CR BIT(0)
0022
0023
0024
0025
0026
0027 #define MICRON_DIE_SELECT_REG 0xD0
0028
0029 #define MICRON_SELECT_DIE(x) ((x) << 6)
0030
0031 static SPINAND_OP_VARIANTS(quadio_read_cache_variants,
0032 SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
0033 SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
0034 SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
0035 SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
0036 SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
0037 SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
0038
0039 static SPINAND_OP_VARIANTS(x4_write_cache_variants,
0040 SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
0041 SPINAND_PROG_LOAD(true, 0, NULL, 0));
0042
0043 static SPINAND_OP_VARIANTS(x4_update_cache_variants,
0044 SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
0045 SPINAND_PROG_LOAD(false, 0, NULL, 0));
0046
0047
0048 static SPINAND_OP_VARIANTS(x4_read_cache_variants,
0049 SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
0050 SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
0051 SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
0052 SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
0053
0054 static SPINAND_OP_VARIANTS(x1_write_cache_variants,
0055 SPINAND_PROG_LOAD(true, 0, NULL, 0));
0056
0057 static SPINAND_OP_VARIANTS(x1_update_cache_variants,
0058 SPINAND_PROG_LOAD(false, 0, NULL, 0));
0059
0060 static int micron_8_ooblayout_ecc(struct mtd_info *mtd, int section,
0061 struct mtd_oob_region *region)
0062 {
0063 if (section)
0064 return -ERANGE;
0065
0066 region->offset = mtd->oobsize / 2;
0067 region->length = mtd->oobsize / 2;
0068
0069 return 0;
0070 }
0071
0072 static int micron_8_ooblayout_free(struct mtd_info *mtd, int section,
0073 struct mtd_oob_region *region)
0074 {
0075 if (section)
0076 return -ERANGE;
0077
0078
0079 region->offset = 2;
0080 region->length = (mtd->oobsize / 2) - 2;
0081
0082 return 0;
0083 }
0084
0085 static const struct mtd_ooblayout_ops micron_8_ooblayout = {
0086 .ecc = micron_8_ooblayout_ecc,
0087 .free = micron_8_ooblayout_free,
0088 };
0089
0090 static int micron_4_ooblayout_ecc(struct mtd_info *mtd, int section,
0091 struct mtd_oob_region *region)
0092 {
0093 struct spinand_device *spinand = mtd_to_spinand(mtd);
0094
0095 if (section >= spinand->base.memorg.pagesize /
0096 mtd->ecc_step_size)
0097 return -ERANGE;
0098
0099 region->offset = (section * 16) + 8;
0100 region->length = 8;
0101
0102 return 0;
0103 }
0104
0105 static int micron_4_ooblayout_free(struct mtd_info *mtd, int section,
0106 struct mtd_oob_region *region)
0107 {
0108 struct spinand_device *spinand = mtd_to_spinand(mtd);
0109
0110 if (section >= spinand->base.memorg.pagesize /
0111 mtd->ecc_step_size)
0112 return -ERANGE;
0113
0114 if (section) {
0115 region->offset = 16 * section;
0116 region->length = 8;
0117 } else {
0118
0119 region->offset = 2;
0120 region->length = 6;
0121 }
0122
0123 return 0;
0124 }
0125
0126 static const struct mtd_ooblayout_ops micron_4_ooblayout = {
0127 .ecc = micron_4_ooblayout_ecc,
0128 .free = micron_4_ooblayout_free,
0129 };
0130
0131 static int micron_select_target(struct spinand_device *spinand,
0132 unsigned int target)
0133 {
0134 struct spi_mem_op op = SPINAND_SET_FEATURE_OP(MICRON_DIE_SELECT_REG,
0135 spinand->scratchbuf);
0136
0137 if (target > 1)
0138 return -EINVAL;
0139
0140 *spinand->scratchbuf = MICRON_SELECT_DIE(target);
0141
0142 return spi_mem_exec_op(spinand->spimem, &op);
0143 }
0144
0145 static int micron_8_ecc_get_status(struct spinand_device *spinand,
0146 u8 status)
0147 {
0148 switch (status & MICRON_STATUS_ECC_MASK) {
0149 case STATUS_ECC_NO_BITFLIPS:
0150 return 0;
0151
0152 case STATUS_ECC_UNCOR_ERROR:
0153 return -EBADMSG;
0154
0155 case MICRON_STATUS_ECC_1TO3_BITFLIPS:
0156 return 3;
0157
0158 case MICRON_STATUS_ECC_4TO6_BITFLIPS:
0159 return 6;
0160
0161 case MICRON_STATUS_ECC_7TO8_BITFLIPS:
0162 return 8;
0163
0164 default:
0165 break;
0166 }
0167
0168 return -EINVAL;
0169 }
0170
0171 static const struct spinand_info micron_spinand_table[] = {
0172
0173 SPINAND_INFO("MT29F2G01ABAGD",
0174 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24),
0175 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
0176 NAND_ECCREQ(8, 512),
0177 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
0178 &x4_write_cache_variants,
0179 &x4_update_cache_variants),
0180 0,
0181 SPINAND_ECCINFO(µn_8_ooblayout,
0182 micron_8_ecc_get_status)),
0183
0184 SPINAND_INFO("MT29F2G01ABBGD",
0185 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25),
0186 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
0187 NAND_ECCREQ(8, 512),
0188 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
0189 &x4_write_cache_variants,
0190 &x4_update_cache_variants),
0191 0,
0192 SPINAND_ECCINFO(µn_8_ooblayout,
0193 micron_8_ecc_get_status)),
0194
0195 SPINAND_INFO("MT29F1G01ABAFD",
0196 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
0197 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
0198 NAND_ECCREQ(8, 512),
0199 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
0200 &x4_write_cache_variants,
0201 &x4_update_cache_variants),
0202 0,
0203 SPINAND_ECCINFO(µn_8_ooblayout,
0204 micron_8_ecc_get_status)),
0205
0206 SPINAND_INFO("MT29F1G01ABAFD",
0207 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15),
0208 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
0209 NAND_ECCREQ(8, 512),
0210 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
0211 &x4_write_cache_variants,
0212 &x4_update_cache_variants),
0213 0,
0214 SPINAND_ECCINFO(µn_8_ooblayout,
0215 micron_8_ecc_get_status)),
0216
0217 SPINAND_INFO("MT29F4G01ADAGD",
0218 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x36),
0219 NAND_MEMORG(1, 2048, 128, 64, 2048, 80, 2, 1, 2),
0220 NAND_ECCREQ(8, 512),
0221 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
0222 &x4_write_cache_variants,
0223 &x4_update_cache_variants),
0224 0,
0225 SPINAND_ECCINFO(µn_8_ooblayout,
0226 micron_8_ecc_get_status),
0227 SPINAND_SELECT_TARGET(micron_select_target)),
0228
0229 SPINAND_INFO("MT29F4G01ABAFD",
0230 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x34),
0231 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
0232 NAND_ECCREQ(8, 512),
0233 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
0234 &x4_write_cache_variants,
0235 &x4_update_cache_variants),
0236 SPINAND_HAS_CR_FEAT_BIT,
0237 SPINAND_ECCINFO(µn_8_ooblayout,
0238 micron_8_ecc_get_status)),
0239
0240 SPINAND_INFO("MT29F4G01ABBFD",
0241 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
0242 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
0243 NAND_ECCREQ(8, 512),
0244 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
0245 &x4_write_cache_variants,
0246 &x4_update_cache_variants),
0247 SPINAND_HAS_CR_FEAT_BIT,
0248 SPINAND_ECCINFO(µn_8_ooblayout,
0249 micron_8_ecc_get_status)),
0250
0251 SPINAND_INFO("MT29F8G01ADAFD",
0252 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x46),
0253 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 2),
0254 NAND_ECCREQ(8, 512),
0255 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
0256 &x4_write_cache_variants,
0257 &x4_update_cache_variants),
0258 SPINAND_HAS_CR_FEAT_BIT,
0259 SPINAND_ECCINFO(µn_8_ooblayout,
0260 micron_8_ecc_get_status),
0261 SPINAND_SELECT_TARGET(micron_select_target)),
0262
0263 SPINAND_INFO("MT29F8G01ADBFD",
0264 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x47),
0265 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 2),
0266 NAND_ECCREQ(8, 512),
0267 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
0268 &x4_write_cache_variants,
0269 &x4_update_cache_variants),
0270 SPINAND_HAS_CR_FEAT_BIT,
0271 SPINAND_ECCINFO(µn_8_ooblayout,
0272 micron_8_ecc_get_status),
0273 SPINAND_SELECT_TARGET(micron_select_target)),
0274
0275 SPINAND_INFO("MT29F2G01AAAED",
0276 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x9F),
0277 NAND_MEMORG(1, 2048, 64, 64, 2048, 80, 2, 1, 1),
0278 NAND_ECCREQ(4, 512),
0279 SPINAND_INFO_OP_VARIANTS(&x4_read_cache_variants,
0280 &x1_write_cache_variants,
0281 &x1_update_cache_variants),
0282 0,
0283 SPINAND_ECCINFO(µn_4_ooblayout, NULL)),
0284 };
0285
0286 static int micron_spinand_init(struct spinand_device *spinand)
0287 {
0288
0289
0290
0291
0292
0293 if (spinand->flags & SPINAND_HAS_CR_FEAT_BIT)
0294 return spinand_upd_cfg(spinand, MICRON_CFG_CR, 0);
0295
0296 return 0;
0297 }
0298
0299 static const struct spinand_manufacturer_ops micron_spinand_manuf_ops = {
0300 .init = micron_spinand_init,
0301 };
0302
0303 const struct spinand_manufacturer micron_spinand_manufacturer = {
0304 .id = SPINAND_MFR_MICRON,
0305 .name = "Micron",
0306 .chips = micron_spinand_table,
0307 .nchips = ARRAY_SIZE(micron_spinand_table),
0308 .ops = µn_spinand_manuf_ops,
0309 };