micron.c (9397B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (c) 2016-2017 Micron Technology, Inc. 4 * 5 * Authors: 6 * Peter Pan <peterpandong@micron.com> 7 */ 8 9#include <linux/device.h> 10#include <linux/kernel.h> 11#include <linux/mtd/spinand.h> 12 13#define SPINAND_MFR_MICRON 0x2c 14 15#define MICRON_STATUS_ECC_MASK GENMASK(7, 4) 16#define MICRON_STATUS_ECC_NO_BITFLIPS (0 << 4) 17#define MICRON_STATUS_ECC_1TO3_BITFLIPS (1 << 4) 18#define MICRON_STATUS_ECC_4TO6_BITFLIPS (3 << 4) 19#define MICRON_STATUS_ECC_7TO8_BITFLIPS (5 << 4) 20 21#define MICRON_CFG_CR BIT(0) 22 23/* 24 * As per datasheet, die selection is done by the 6th bit of Die 25 * Select Register (Address 0xD0). 26 */ 27#define MICRON_DIE_SELECT_REG 0xD0 28 29#define MICRON_SELECT_DIE(x) ((x) << 6) 30 31static SPINAND_OP_VARIANTS(quadio_read_cache_variants, 32 SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), 33 SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), 34 SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), 35 SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), 36 SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), 37 SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); 38 39static SPINAND_OP_VARIANTS(x4_write_cache_variants, 40 SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), 41 SPINAND_PROG_LOAD(true, 0, NULL, 0)); 42 43static SPINAND_OP_VARIANTS(x4_update_cache_variants, 44 SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), 45 SPINAND_PROG_LOAD(false, 0, NULL, 0)); 46 47/* Micron MT29F2G01AAAED Device */ 48static SPINAND_OP_VARIANTS(x4_read_cache_variants, 49 SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), 50 SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), 51 SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), 52 SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); 53 54static SPINAND_OP_VARIANTS(x1_write_cache_variants, 55 SPINAND_PROG_LOAD(true, 0, NULL, 0)); 56 57static SPINAND_OP_VARIANTS(x1_update_cache_variants, 58 SPINAND_PROG_LOAD(false, 0, NULL, 0)); 59 60static int micron_8_ooblayout_ecc(struct mtd_info *mtd, int section, 61 struct mtd_oob_region *region) 62{ 63 if (section) 64 return -ERANGE; 65 66 region->offset = mtd->oobsize / 2; 67 region->length = mtd->oobsize / 2; 68 69 return 0; 70} 71 72static int micron_8_ooblayout_free(struct mtd_info *mtd, int section, 73 struct mtd_oob_region *region) 74{ 75 if (section) 76 return -ERANGE; 77 78 /* Reserve 2 bytes for the BBM. */ 79 region->offset = 2; 80 region->length = (mtd->oobsize / 2) - 2; 81 82 return 0; 83} 84 85static const struct mtd_ooblayout_ops micron_8_ooblayout = { 86 .ecc = micron_8_ooblayout_ecc, 87 .free = micron_8_ooblayout_free, 88}; 89 90static int micron_4_ooblayout_ecc(struct mtd_info *mtd, int section, 91 struct mtd_oob_region *region) 92{ 93 struct spinand_device *spinand = mtd_to_spinand(mtd); 94 95 if (section >= spinand->base.memorg.pagesize / 96 mtd->ecc_step_size) 97 return -ERANGE; 98 99 region->offset = (section * 16) + 8; 100 region->length = 8; 101 102 return 0; 103} 104 105static int micron_4_ooblayout_free(struct mtd_info *mtd, int section, 106 struct mtd_oob_region *region) 107{ 108 struct spinand_device *spinand = mtd_to_spinand(mtd); 109 110 if (section >= spinand->base.memorg.pagesize / 111 mtd->ecc_step_size) 112 return -ERANGE; 113 114 if (section) { 115 region->offset = 16 * section; 116 region->length = 8; 117 } else { 118 /* section 0 has two bytes reserved for the BBM */ 119 region->offset = 2; 120 region->length = 6; 121 } 122 123 return 0; 124} 125 126static const struct mtd_ooblayout_ops micron_4_ooblayout = { 127 .ecc = micron_4_ooblayout_ecc, 128 .free = micron_4_ooblayout_free, 129}; 130 131static int micron_select_target(struct spinand_device *spinand, 132 unsigned int target) 133{ 134 struct spi_mem_op op = SPINAND_SET_FEATURE_OP(MICRON_DIE_SELECT_REG, 135 spinand->scratchbuf); 136 137 if (target > 1) 138 return -EINVAL; 139 140 *spinand->scratchbuf = MICRON_SELECT_DIE(target); 141 142 return spi_mem_exec_op(spinand->spimem, &op); 143} 144 145static int micron_8_ecc_get_status(struct spinand_device *spinand, 146 u8 status) 147{ 148 switch (status & MICRON_STATUS_ECC_MASK) { 149 case STATUS_ECC_NO_BITFLIPS: 150 return 0; 151 152 case STATUS_ECC_UNCOR_ERROR: 153 return -EBADMSG; 154 155 case MICRON_STATUS_ECC_1TO3_BITFLIPS: 156 return 3; 157 158 case MICRON_STATUS_ECC_4TO6_BITFLIPS: 159 return 6; 160 161 case MICRON_STATUS_ECC_7TO8_BITFLIPS: 162 return 8; 163 164 default: 165 break; 166 } 167 168 return -EINVAL; 169} 170 171static const struct spinand_info micron_spinand_table[] = { 172 /* M79A 2Gb 3.3V */ 173 SPINAND_INFO("MT29F2G01ABAGD", 174 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24), 175 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1), 176 NAND_ECCREQ(8, 512), 177 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants, 178 &x4_write_cache_variants, 179 &x4_update_cache_variants), 180 0, 181 SPINAND_ECCINFO(µn_8_ooblayout, 182 micron_8_ecc_get_status)), 183 /* M79A 2Gb 1.8V */ 184 SPINAND_INFO("MT29F2G01ABBGD", 185 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25), 186 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1), 187 NAND_ECCREQ(8, 512), 188 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants, 189 &x4_write_cache_variants, 190 &x4_update_cache_variants), 191 0, 192 SPINAND_ECCINFO(µn_8_ooblayout, 193 micron_8_ecc_get_status)), 194 /* M78A 1Gb 3.3V */ 195 SPINAND_INFO("MT29F1G01ABAFD", 196 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14), 197 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), 198 NAND_ECCREQ(8, 512), 199 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants, 200 &x4_write_cache_variants, 201 &x4_update_cache_variants), 202 0, 203 SPINAND_ECCINFO(µn_8_ooblayout, 204 micron_8_ecc_get_status)), 205 /* M78A 1Gb 1.8V */ 206 SPINAND_INFO("MT29F1G01ABAFD", 207 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15), 208 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), 209 NAND_ECCREQ(8, 512), 210 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants, 211 &x4_write_cache_variants, 212 &x4_update_cache_variants), 213 0, 214 SPINAND_ECCINFO(µn_8_ooblayout, 215 micron_8_ecc_get_status)), 216 /* M79A 4Gb 3.3V */ 217 SPINAND_INFO("MT29F4G01ADAGD", 218 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x36), 219 NAND_MEMORG(1, 2048, 128, 64, 2048, 80, 2, 1, 2), 220 NAND_ECCREQ(8, 512), 221 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants, 222 &x4_write_cache_variants, 223 &x4_update_cache_variants), 224 0, 225 SPINAND_ECCINFO(µn_8_ooblayout, 226 micron_8_ecc_get_status), 227 SPINAND_SELECT_TARGET(micron_select_target)), 228 /* M70A 4Gb 3.3V */ 229 SPINAND_INFO("MT29F4G01ABAFD", 230 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x34), 231 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), 232 NAND_ECCREQ(8, 512), 233 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants, 234 &x4_write_cache_variants, 235 &x4_update_cache_variants), 236 SPINAND_HAS_CR_FEAT_BIT, 237 SPINAND_ECCINFO(µn_8_ooblayout, 238 micron_8_ecc_get_status)), 239 /* M70A 4Gb 1.8V */ 240 SPINAND_INFO("MT29F4G01ABBFD", 241 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35), 242 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), 243 NAND_ECCREQ(8, 512), 244 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants, 245 &x4_write_cache_variants, 246 &x4_update_cache_variants), 247 SPINAND_HAS_CR_FEAT_BIT, 248 SPINAND_ECCINFO(µn_8_ooblayout, 249 micron_8_ecc_get_status)), 250 /* M70A 8Gb 3.3V */ 251 SPINAND_INFO("MT29F8G01ADAFD", 252 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x46), 253 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 2), 254 NAND_ECCREQ(8, 512), 255 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants, 256 &x4_write_cache_variants, 257 &x4_update_cache_variants), 258 SPINAND_HAS_CR_FEAT_BIT, 259 SPINAND_ECCINFO(µn_8_ooblayout, 260 micron_8_ecc_get_status), 261 SPINAND_SELECT_TARGET(micron_select_target)), 262 /* M70A 8Gb 1.8V */ 263 SPINAND_INFO("MT29F8G01ADBFD", 264 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x47), 265 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 2), 266 NAND_ECCREQ(8, 512), 267 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants, 268 &x4_write_cache_variants, 269 &x4_update_cache_variants), 270 SPINAND_HAS_CR_FEAT_BIT, 271 SPINAND_ECCINFO(µn_8_ooblayout, 272 micron_8_ecc_get_status), 273 SPINAND_SELECT_TARGET(micron_select_target)), 274 /* M69A 2Gb 3.3V */ 275 SPINAND_INFO("MT29F2G01AAAED", 276 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x9F), 277 NAND_MEMORG(1, 2048, 64, 64, 2048, 80, 2, 1, 1), 278 NAND_ECCREQ(4, 512), 279 SPINAND_INFO_OP_VARIANTS(&x4_read_cache_variants, 280 &x1_write_cache_variants, 281 &x1_update_cache_variants), 282 0, 283 SPINAND_ECCINFO(µn_4_ooblayout, NULL)), 284}; 285 286static int micron_spinand_init(struct spinand_device *spinand) 287{ 288 /* 289 * M70A device series enable Continuous Read feature at Power-up, 290 * which is not supported. Disable this bit to avoid any possible 291 * failure. 292 */ 293 if (spinand->flags & SPINAND_HAS_CR_FEAT_BIT) 294 return spinand_upd_cfg(spinand, MICRON_CFG_CR, 0); 295 296 return 0; 297} 298 299static const struct spinand_manufacturer_ops micron_spinand_manuf_ops = { 300 .init = micron_spinand_init, 301}; 302 303const struct spinand_manufacturer micron_spinand_manufacturer = { 304 .id = SPINAND_MFR_MICRON, 305 .name = "Micron", 306 .chips = micron_spinand_table, 307 .nchips = ARRAY_SIZE(micron_spinand_table), 308 .ops = µn_spinand_manuf_ops, 309};