Driver is redesigned using parameter page to support Micron SPI NAND flashes. Support for selecting die is enabled for multi-die flashes. Turn OOB layout generic. Fixup some of the parameter page data as per Micron datasheet. Signed-off-by: Shivamurthy Shastri <sshivamurthy@xxxxxxxxxx> --- drivers/mtd/nand/spi/micron.c | 109 +++++++++++++++++++++++++--------- 1 file changed, 80 insertions(+), 29 deletions(-) diff --git a/drivers/mtd/nand/spi/micron.c b/drivers/mtd/nand/spi/micron.c index 7d7b1f7fcf71..663bb2809036 100644 --- a/drivers/mtd/nand/spi/micron.c +++ b/drivers/mtd/nand/spi/micron.c @@ -14,7 +14,7 @@ #define MICRON_STATUS_ECC_MASK GENMASK(7, 4) #define MICRON_STATUS_ECC_NO_BITFLIPS (0 << 4) -#define MICRON_STATUS_ECC_1TO3_BITFLIPS (1 << 4) +#define MICRON_STATUS_ECC_1TO3_BITFLIPS BIT(4) #define MICRON_STATUS_ECC_4TO6_BITFLIPS (3 << 4) #define MICRON_STATUS_ECC_7TO8_BITFLIPS (5 << 4) @@ -34,38 +34,38 @@ static SPINAND_OP_VARIANTS(update_cache_variants, SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), SPINAND_PROG_LOAD(false, 0, NULL, 0)); -static int mt29f2g01abagd_ooblayout_ecc(struct mtd_info *mtd, int section, - struct mtd_oob_region *region) +static int ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) { if (section) return -ERANGE; - region->offset = 64; - region->length = 64; + region->offset = mtd->oobsize / 2; + region->length = mtd->oobsize / 2; return 0; } -static int mt29f2g01abagd_ooblayout_free(struct mtd_info *mtd, int section, - struct mtd_oob_region *region) +static int ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) { if (section) return -ERANGE; /* Reserve 2 bytes for the BBM. */ region->offset = 2; - region->length = 62; + region->length = (mtd->oobsize / 2) - 2; return 0; } -static const struct mtd_ooblayout_ops mt29f2g01abagd_ooblayout = { - .ecc = mt29f2g01abagd_ooblayout_ecc, - .free = mt29f2g01abagd_ooblayout_free, +static const struct mtd_ooblayout_ops ooblayout = { + .ecc = ooblayout_ecc, + .free = ooblayout_free, }; -static int mt29f2g01abagd_ecc_get_status(struct spinand_device *spinand, - u8 status) +static int ecc_get_status(struct spinand_device *spinand, + u8 status) { switch (status & MICRON_STATUS_ECC_MASK) { case STATUS_ECC_NO_BITFLIPS: @@ -90,22 +90,23 @@ static int mt29f2g01abagd_ecc_get_status(struct spinand_device *spinand, return -EINVAL; } -static const struct spinand_info micron_spinand_table[] = { - SPINAND_INFO("MT29F2G01ABAGD", 0x24, - NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1), - NAND_ECCREQ(8, 512), - SPINAND_INFO_OP_VARIANTS(&read_cache_variants, - &write_cache_variants, - &update_cache_variants), - 0, - SPINAND_ECCINFO(&mt29f2g01abagd_ooblayout, - mt29f2g01abagd_ecc_get_status)), -}; +static int mt29f8g_select_target(struct spinand_device *spinand, + unsigned int target) +{ + struct spi_mem_op op = SPINAND_SET_FEATURE_OP(0xd0, + spinand->scratchbuf); + + if (target == 1) + target = 0x40; + + *spinand->scratchbuf = target; + return spi_mem_exec_op(spinand->spimem, &op); +} static int micron_spinand_detect(struct spinand_device *spinand) { + const struct spi_mem_op *op; u8 *id = spinand->id.data; - int ret; /* * Micron SPI NAND read ID need a dummy byte, @@ -114,16 +115,66 @@ static int micron_spinand_detect(struct spinand_device *spinand) if (id[1] != SPINAND_MFR_MICRON) return 0; - ret = spinand_match_and_init(spinand, micron_spinand_table, - ARRAY_SIZE(micron_spinand_table), id[2]); - if (ret) - return ret; + spinand->flags = 0; + spinand->eccinfo.get_status = ecc_get_status; + spinand->eccinfo.ooblayout = &ooblayout; + spinand->select_target = mt29f8g_select_target; + + op = spinand_select_op_variant(spinand, + &read_cache_variants); + if (!op) + return -ENOTSUPP; + + spinand->op_templates.read_cache = op; + + op = spinand_select_op_variant(spinand, + &write_cache_variants); + if (!op) + return -ENOTSUPP; + + spinand->op_templates.write_cache = op; + + op = spinand_select_op_variant(spinand, + &update_cache_variants); + spinand->op_templates.update_cache = op; return 1; } +static int micron_spinand_init(struct spinand_device *spinand) +{ + /* + * Some of the Micron flashes enable this BIT by default, + * and there is a chance of read failure due to this. + */ + return spinand_upd_cfg(spinand, CFG_QUAD_ENABLE, 0); +} + +static void micron_fixup_param_page(struct spinand_device *spinand, + struct nand_onfi_params *p) +{ + /** + * As per Micron datasheets vendor[88] is defined as + * die_select_feature + */ + if (p->vendor[83] && !p->interleaved_bits) + spinand->base.memorg.planes_per_lun = 1 << p->vendor[0]; + + spinand->base.memorg.ntargets = p->lun_count; + spinand->base.memorg.luns_per_target = 1; + + /** + * As per Micron datasheets, + * vendor[82] is ECC maximum correctability + */ + spinand->base.ecc.requirements.strength = p->vendor[82]; + spinand->base.ecc.requirements.step_size = 512; +} + static const struct spinand_manufacturer_ops micron_spinand_manuf_ops = { .detect = micron_spinand_detect, + .init = micron_spinand_init, + .fixup_param_page = micron_fixup_param_page, }; const struct spinand_manufacturer micron_spinand_manufacturer = { -- 2.17.1 ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/