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 <sshivamur...@micron.com>
---
 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

Reply via email to