From: Mikhail Kshevetskiy <mikhail.kshevets...@iopsys.eu>

This adds more supported spinand devices from the Linux kernel
implementation.

This does not include the latest kernel implementation as this would
require a substantial amount of extra work due to the missing
ECC engine abstraction layer in U-Boot.

Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevets...@iopsys.eu>
Signed-off-by: Frieder Schrempf <frieder.schre...@kontron.de> (commit message)
---
 drivers/mtd/nand/spi/Makefile     |   2 +-
 drivers/mtd/nand/spi/core.c       |   1 +
 drivers/mtd/nand/spi/gigadevice.c | 223 ++++++++++++++++++++++++++----
 drivers/mtd/nand/spi/macronix.c   | 145 +++++++++++++++++--
 drivers/mtd/nand/spi/micron.c     | 144 +++++++++++++------
 drivers/mtd/nand/spi/paragon.c    | 133 ++++++++++++++++++
 drivers/mtd/nand/spi/toshiba.c    |  38 ++---
 drivers/mtd/nand/spi/winbond.c    |   6 +-
 include/linux/mtd/nand.h          |   5 +-
 include/linux/mtd/spinand.h       |  31 +++++
 10 files changed, 626 insertions(+), 102 deletions(-)
 create mode 100644 drivers/mtd/nand/spi/paragon.c

diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
index 6c65b187e86..3051de4f7ef 100644
--- a/drivers/mtd/nand/spi/Makefile
+++ b/drivers/mtd/nand/spi/Makefile
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 
-spinand-objs := core.o gigadevice.o macronix.o micron.o toshiba.o winbond.o
+spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o 
winbond.o
 obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 886e66e7847..631ccfdab6a 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -824,6 +824,7 @@ static const struct spinand_manufacturer 
*spinand_manufacturers[] = {
        &gigadevice_spinand_manufacturer,
        &macronix_spinand_manufacturer,
        &micron_spinand_manufacturer,
+       &paragon_spinand_manufacturer,
        &toshiba_spinand_manufacturer,
        &winbond_spinand_manufacturer,
 };
diff --git a/drivers/mtd/nand/spi/gigadevice.c 
b/drivers/mtd/nand/spi/gigadevice.c
index 43b353a3e7e..f2ecf47f8d4 100644
--- a/drivers/mtd/nand/spi/gigadevice.c
+++ b/drivers/mtd/nand/spi/gigadevice.c
@@ -7,13 +7,13 @@
  */
 
 #ifndef __UBOOT__
-#include <malloc.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
 #endif
 #include <linux/mtd/spinand.h>
 
 #define SPINAND_MFR_GIGADEVICE                 0xC8
+
 #define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS     (1 << 4)
 #define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS       (3 << 4)
 
@@ -22,8 +22,12 @@
 
 #define GD5FXGQXXEXXG_REG_STATUS2              0xf0
 
-/* Q4 devices, QUADIO: Dummy bytes valid for 1 and 2 GBit variants */
-static SPINAND_OP_VARIANTS(gd5fxgq4_read_cache_variants,
+#define GD5FXGQ4UXFXXG_STATUS_ECC_MASK         (7 << 4)
+#define GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS  (0 << 4)
+#define GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS (1 << 4)
+#define GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR  (7 << 4)
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
                SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
                SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
                SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
@@ -31,14 +35,13 @@ static SPINAND_OP_VARIANTS(gd5fxgq4_read_cache_variants,
                SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
                SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
 
-/* Q5 devices, QUADIO: Dummy bytes only valid for 1 GBit variants */
-static SPINAND_OP_VARIANTS(gd5f1gq5_read_cache_variants,
-               SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
-               SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+static SPINAND_OP_VARIANTS(read_cache_variants_f,
+               SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(0, 1, NULL, 0),
                SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
-               SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
-               SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
-               SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+               SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_OP_3A(true, 0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_OP_3A(false, 0, 0, NULL, 0));
 
 static SPINAND_OP_VARIANTS(write_cache_variants,
                SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
@@ -48,7 +51,65 @@ static SPINAND_OP_VARIANTS(update_cache_variants,
                SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
                SPINAND_PROG_LOAD(false, 0, NULL, 0));
 
-static int gd5fxgqxxexxg_ooblayout_ecc(struct mtd_info *mtd, int section,
+static int gd5fxgq4xa_ooblayout_ecc(struct mtd_info *mtd, int section,
+                                 struct mtd_oob_region *region)
+{
+       if (section > 3)
+               return -ERANGE;
+
+       region->offset = (16 * section) + 8;
+       region->length = 8;
+
+       return 0;
+}
+
+static int gd5fxgq4xa_ooblayout_free(struct mtd_info *mtd, int section,
+                                  struct mtd_oob_region *region)
+{
+       if (section > 3)
+               return -ERANGE;
+
+       if (section) {
+               region->offset = 16 * section;
+               region->length = 8;
+       } else {
+               /* section 0 has one byte reserved for bad block mark */
+               region->offset = 1;
+               region->length = 7;
+       }
+       return 0;
+}
+
+static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = {
+       .ecc = gd5fxgq4xa_ooblayout_ecc,
+       .rfree = gd5fxgq4xa_ooblayout_free,
+};
+
+static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand,
+                                        u8 status)
+{
+       switch (status & STATUS_ECC_MASK) {
+       case STATUS_ECC_NO_BITFLIPS:
+               return 0;
+
+       case GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS:
+               /* 1-7 bits are flipped. return the maximum. */
+               return 7;
+
+       case GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS:
+               return 8;
+
+       case STATUS_ECC_UNCOR_ERROR:
+               return -EBADMSG;
+
+       default:
+               break;
+       }
+
+       return -EINVAL;
+}
+
+static int gd5fxgqx_variant2_ooblayout_ecc(struct mtd_info *mtd, int section,
                                       struct mtd_oob_region *region)
 {
        if (section)
@@ -60,7 +121,7 @@ static int gd5fxgqxxexxg_ooblayout_ecc(struct mtd_info *mtd, 
int section,
        return 0;
 }
 
-static int gd5fxgqxxexxg_ooblayout_free(struct mtd_info *mtd, int section,
+static int gd5fxgqx_variant2_ooblayout_free(struct mtd_info *mtd, int section,
                                        struct mtd_oob_region *region)
 {
        if (section)
@@ -73,7 +134,42 @@ static int gd5fxgqxxexxg_ooblayout_free(struct mtd_info 
*mtd, int section,
        return 0;
 }
 
-static int gd5fxgq4xexxg_ecc_get_status(struct spinand_device *spinand,
+/* Valid for Q4/Q5 and Q6 (untested) devices */
+static const struct mtd_ooblayout_ops gd5fxgqx_variant2_ooblayout = {
+       .ecc = gd5fxgqx_variant2_ooblayout_ecc,
+       .rfree = gd5fxgqx_variant2_ooblayout_free,
+};
+
+static int gd5fxgq4xc_ooblayout_256_ecc(struct mtd_info *mtd, int section,
+                                       struct mtd_oob_region *oobregion)
+{
+       if (section)
+               return -ERANGE;
+
+       oobregion->offset = 128;
+       oobregion->length = 128;
+
+       return 0;
+}
+
+static int gd5fxgq4xc_ooblayout_256_free(struct mtd_info *mtd, int section,
+                                        struct mtd_oob_region *oobregion)
+{
+       if (section)
+               return -ERANGE;
+
+       oobregion->offset = 1;
+       oobregion->length = 127;
+
+       return 0;
+}
+
+static const struct mtd_ooblayout_ops gd5fxgq4xc_oob_256_ops = {
+       .ecc = gd5fxgq4xc_ooblayout_256_ecc,
+       .rfree = gd5fxgq4xc_ooblayout_256_free,
+};
+
+static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
                                        u8 status)
 {
        u8 status2;
@@ -152,31 +248,106 @@ static int gd5fxgq5xexxg_ecc_get_status(struct 
spinand_device *spinand,
        return -EINVAL;
 }
 
-static const struct mtd_ooblayout_ops gd5fxgqxxexxg_ooblayout = {
-       .ecc = gd5fxgqxxexxg_ooblayout_ecc,
-       .rfree = gd5fxgqxxexxg_ooblayout_free,
-};
+static int gd5fxgq4ufxxg_ecc_get_status(struct spinand_device *spinand,
+                                       u8 status)
+{
+       switch (status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) {
+       case GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS:
+               return 0;
+
+       case GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS:
+               return 3;
+
+       case GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR:
+               return -EBADMSG;
+
+       default: /* (2 << 4) through (6 << 4) are 4-8 corrected errors */
+               return ((status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) >> 4) + 2;
+       }
+
+       return -EINVAL;
+}
 
 static const struct spinand_info gigadevice_spinand_table[] = {
+       SPINAND_INFO("GD5F1GQ4xA",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf1),
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
+                                    gd5fxgq4xa_ecc_get_status)),
+       SPINAND_INFO("GD5F2GQ4xA",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf2),
+                    NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
+                                    gd5fxgq4xa_ecc_get_status)),
+       SPINAND_INFO("GD5F4GQ4xA",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf4),
+                    NAND_MEMORG(1, 2048, 64, 64, 4096, 80, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
+                                    gd5fxgq4xa_ecc_get_status)),
+       SPINAND_INFO("GD5F4GQ4RC",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xa4, 0x68),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&gd5fxgq4xc_oob_256_ops,
+                                    gd5fxgq4ufxxg_ecc_get_status)),
+       SPINAND_INFO("GD5F4GQ4UC",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb4, 0x68),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&gd5fxgq4xc_oob_256_ops,
+                                    gd5fxgq4ufxxg_ecc_get_status)),
        SPINAND_INFO("GD5F1GQ4UExxG",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd1),
-                    NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
+                                    gd5fxgq4uexxg_ecc_get_status)),
+       SPINAND_INFO("GD5F1GQ4UFxxG",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb1, 0x48),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
-                    SPINAND_INFO_OP_VARIANTS(&gd5fxgq4_read_cache_variants,
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
                                              &write_cache_variants,
                                              &update_cache_variants),
-                    0,
-                    SPINAND_ECCINFO(&gd5fxgqxxexxg_ooblayout,
-                                    gd5fxgq4xexxg_ecc_get_status)),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
+                                    gd5fxgq4ufxxg_ecc_get_status)),
        SPINAND_INFO("GD5F1GQ5UExxG",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x51),
-                    NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
                     NAND_ECCREQ(4, 512),
-                    SPINAND_INFO_OP_VARIANTS(&gd5f1gq5_read_cache_variants,
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
                                              &update_cache_variants),
-                    0,
-                    SPINAND_ECCINFO(&gd5fxgqxxexxg_ooblayout,
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
                                     gd5fxgq5xexxg_ecc_get_status)),
 };
 
diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c
index 08f7d69d8c6..86bffc2800b 100644
--- a/drivers/mtd/nand/spi/macronix.c
+++ b/drivers/mtd/nand/spi/macronix.c
@@ -6,7 +6,6 @@
  */
 
 #ifndef __UBOOT__
-#include <malloc.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
 #endif
@@ -16,7 +15,6 @@
 #define SPINAND_MFR_MACRONIX           0xC2
 #define MACRONIX_ECCSR_MASK            0x0F
 
-
 static SPINAND_OP_VARIANTS(read_cache_variants,
                SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
                SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
@@ -62,7 +60,6 @@ static int mx35lf1ge4ab_get_eccsr(struct spinand_device 
*spinand, u8 *eccsr)
                                          SPI_MEM_OP_DATA_IN(1, eccsr, 1));
 
        int ret = spi_mem_exec_op(spinand->slave, &op);
-
        if (ret)
                return ret;
 
@@ -107,7 +104,7 @@ static int mx35lf1ge4ab_ecc_get_status(struct 
spinand_device *spinand,
 static const struct spinand_info macronix_spinand_table[] = {
        SPINAND_INFO("MX35LF1GE4AB",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x12),
-                    NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
                     NAND_ECCREQ(4, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -117,16 +114,124 @@ static const struct spinand_info 
macronix_spinand_table[] = {
                                     mx35lf1ge4ab_ecc_get_status)),
        SPINAND_INFO("MX35LF2GE4AB",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x22),
-                    NAND_MEMORG(1, 2048, 64, 64, 2048, 2, 1, 1),
+                    NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
                     NAND_ECCREQ(4, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
                                              &update_cache_variants),
                     SPINAND_HAS_QE_BIT,
                     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
+       SPINAND_INFO("MX35LF2GE4AD",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x26),
+                    NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+                                    mx35lf1ge4ab_ecc_get_status)),
+       SPINAND_INFO("MX35LF4GE4AD",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x37),
+                    NAND_MEMORG(1, 4096, 128, 64, 2048, 40, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+                                    mx35lf1ge4ab_ecc_get_status)),
+       SPINAND_INFO("MX35LF1G24AD",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
+       SPINAND_INFO("MX35LF2G24AD",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 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),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
+       SPINAND_INFO("MX35LF4G24AD",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 2, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
+       SPINAND_INFO("MX31LF1GE4BC",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x1e),
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+                                    mx35lf1ge4ab_ecc_get_status)),
+       SPINAND_INFO("MX31UF1GE4BC",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x9e),
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+                                    mx35lf1ge4ab_ecc_get_status)),
+
+       SPINAND_INFO("MX35LF2G14AC",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x20),
+                    NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
+                    NAND_ECCREQ(4, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+                                    mx35lf1ge4ab_ecc_get_status)),
+       SPINAND_INFO("MX35UF4G24AD",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb5),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 2, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+                                    mx35lf1ge4ab_ecc_get_status)),
        SPINAND_INFO("MX35UF4GE4AD",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb7),
-                    NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+                                    mx35lf1ge4ab_ecc_get_status)),
+       SPINAND_INFO("MX35UF2G14AC",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa0),
+                    NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
+                    NAND_ECCREQ(4, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+                                    mx35lf1ge4ab_ecc_get_status)),
+       SPINAND_INFO("MX35UF2G24AD",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa4),
+                    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,
@@ -136,7 +241,7 @@ static const struct spinand_info macronix_spinand_table[] = 
{
                                     mx35lf1ge4ab_ecc_get_status)),
        SPINAND_INFO("MX35UF2GE4AD",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa6),
-                    NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -146,7 +251,17 @@ static const struct spinand_info macronix_spinand_table[] 
= {
                                     mx35lf1ge4ab_ecc_get_status)),
        SPINAND_INFO("MX35UF2GE4AC",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa2),
-                    NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
+                    NAND_ECCREQ(4, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+                                    mx35lf1ge4ab_ecc_get_status)),
+       SPINAND_INFO("MX35UF1G14AC",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x90),
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
                     NAND_ECCREQ(4, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -154,9 +269,19 @@ static const struct spinand_info macronix_spinand_table[] 
= {
                     SPINAND_HAS_QE_BIT,
                     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
                                     mx35lf1ge4ab_ecc_get_status)),
+       SPINAND_INFO("MX35UF1G24AD",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x94),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+                                    mx35lf1ge4ab_ecc_get_status)),
        SPINAND_INFO("MX35UF1GE4AD",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x96),
-                    NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -166,7 +291,7 @@ static const struct spinand_info macronix_spinand_table[] = 
{
                                     mx35lf1ge4ab_ecc_get_status)),
        SPINAND_INFO("MX35UF1GE4AC",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x92),
-                    NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
                     NAND_ECCREQ(4, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
diff --git a/drivers/mtd/nand/spi/micron.c b/drivers/mtd/nand/spi/micron.c
index cecd3db9584..b538213ed8e 100644
--- a/drivers/mtd/nand/spi/micron.c
+++ b/drivers/mtd/nand/spi/micron.c
@@ -7,11 +7,9 @@
  */
 
 #ifndef __UBOOT__
-#include <malloc.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
 #endif
-#include <linux/bitops.h>
 #include <linux/mtd/spinand.h>
 
 #define SPINAND_MFR_MICRON             0x2c
@@ -32,7 +30,7 @@
 
 #define MICRON_SELECT_DIE(x)   ((x) << 6)
 
-static SPINAND_OP_VARIANTS(read_cache_variants,
+static SPINAND_OP_VARIANTS(quadio_read_cache_variants,
                SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
                SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
                SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
@@ -40,14 +38,27 @@ static SPINAND_OP_VARIANTS(read_cache_variants,
                SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
                SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
 
-static SPINAND_OP_VARIANTS(write_cache_variants,
+static SPINAND_OP_VARIANTS(x4_write_cache_variants,
                SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
                SPINAND_PROG_LOAD(true, 0, NULL, 0));
 
-static SPINAND_OP_VARIANTS(update_cache_variants,
+static SPINAND_OP_VARIANTS(x4_update_cache_variants,
                SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
                SPINAND_PROG_LOAD(false, 0, NULL, 0));
 
+/* Micron  MT29F2G01AAAED Device */
+static SPINAND_OP_VARIANTS(x4_read_cache_variants,
+                          SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+                          SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
+                          SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
+                          SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 
0));
+
+static SPINAND_OP_VARIANTS(x1_write_cache_variants,
+                          SPINAND_PROG_LOAD(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(x1_update_cache_variants,
+                          SPINAND_PROG_LOAD(false, 0, NULL, 0));
+
 static int micron_8_ooblayout_ecc(struct mtd_info *mtd, int section,
                                  struct mtd_oob_region *region)
 {
@@ -78,6 +89,47 @@ static const struct mtd_ooblayout_ops micron_8_ooblayout = {
        .rfree = micron_8_ooblayout_free,
 };
 
+static int micron_4_ooblayout_ecc(struct mtd_info *mtd, int section,
+                                 struct mtd_oob_region *region)
+{
+       struct spinand_device *spinand = mtd_to_spinand(mtd);
+
+       if (section >= spinand->base.memorg.pagesize /
+                       mtd->ecc_step_size)
+               return -ERANGE;
+
+       region->offset = (section * 16) + 8;
+       region->length = 8;
+
+       return 0;
+}
+
+static int micron_4_ooblayout_free(struct mtd_info *mtd, int section,
+                                  struct mtd_oob_region *region)
+{
+       struct spinand_device *spinand = mtd_to_spinand(mtd);
+
+       if (section >= spinand->base.memorg.pagesize /
+                       mtd->ecc_step_size)
+               return -ERANGE;
+
+       if (section) {
+               region->offset = 16 * section;
+               region->length = 8;
+       } else {
+               /* section 0 has two bytes reserved for the BBM */
+               region->offset = 2;
+               region->length = 6;
+       }
+
+       return 0;
+}
+
+static const struct mtd_ooblayout_ops micron_4_ooblayout = {
+       .ecc = micron_4_ooblayout_ecc,
+       .rfree = micron_4_ooblayout_free,
+};
+
 static int micron_select_target(struct spinand_device *spinand,
                                unsigned int target)
 {
@@ -122,55 +174,55 @@ static const struct spinand_info micron_spinand_table[] = 
{
        /* M79A 2Gb 3.3V */
        SPINAND_INFO("MT29F2G01ABAGD",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24),
-                    NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
+                    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),
+                    SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+                                             &x4_write_cache_variants,
+                                             &x4_update_cache_variants),
                     0,
                     SPINAND_ECCINFO(&micron_8_ooblayout,
                                     micron_8_ecc_get_status)),
        /* M79A 2Gb 1.8V */
        SPINAND_INFO("MT29F2G01ABBGD",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25),
-                    NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
+                    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),
+                    SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+                                             &x4_write_cache_variants,
+                                             &x4_update_cache_variants),
                     0,
                     SPINAND_ECCINFO(&micron_8_ooblayout,
                                     micron_8_ecc_get_status)),
        /* M78A 1Gb 3.3V */
        SPINAND_INFO("MT29F1G01ABAFD",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
-                    NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
-                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-                                             &write_cache_variants,
-                                             &update_cache_variants),
+                    SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+                                             &x4_write_cache_variants,
+                                             &x4_update_cache_variants),
                     0,
                     SPINAND_ECCINFO(&micron_8_ooblayout,
                                     micron_8_ecc_get_status)),
        /* M78A 1Gb 1.8V */
        SPINAND_INFO("MT29F1G01ABAFD",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15),
-                    NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
-                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-                                             &write_cache_variants,
-                                             &update_cache_variants),
+                    SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+                                             &x4_write_cache_variants,
+                                             &x4_update_cache_variants),
                     0,
                     SPINAND_ECCINFO(&micron_8_ooblayout,
                                     micron_8_ecc_get_status)),
        /* M79A 4Gb 3.3V */
        SPINAND_INFO("MT29F4G01ADAGD",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x36),
-                    NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 2),
+                    NAND_MEMORG(1, 2048, 128, 64, 2048, 80, 2, 1, 2),
                     NAND_ECCREQ(8, 512),
-                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-                                             &write_cache_variants,
-                                             &update_cache_variants),
+                    SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+                                             &x4_write_cache_variants,
+                                             &x4_update_cache_variants),
                     0,
                     SPINAND_ECCINFO(&micron_8_ooblayout,
                                     micron_8_ecc_get_status),
@@ -178,33 +230,33 @@ static const struct spinand_info micron_spinand_table[] = 
{
        /* M70A 4Gb 3.3V */
        SPINAND_INFO("MT29F4G01ABAFD",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x34),
-                    NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
-                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-                                             &write_cache_variants,
-                                             &update_cache_variants),
+                    SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+                                             &x4_write_cache_variants,
+                                             &x4_update_cache_variants),
                     SPINAND_HAS_CR_FEAT_BIT,
                     SPINAND_ECCINFO(&micron_8_ooblayout,
                                     micron_8_ecc_get_status)),
        /* M70A 4Gb 1.8V */
        SPINAND_INFO("MT29F4G01ABBFD",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
-                    NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
-                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-                                             &write_cache_variants,
-                                             &update_cache_variants),
+                    SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+                                             &x4_write_cache_variants,
+                                             &x4_update_cache_variants),
                     SPINAND_HAS_CR_FEAT_BIT,
                     SPINAND_ECCINFO(&micron_8_ooblayout,
                                     micron_8_ecc_get_status)),
        /* M70A 8Gb 3.3V */
        SPINAND_INFO("MT29F8G01ADAFD",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x46),
-                    NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 2),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 2),
                     NAND_ECCREQ(8, 512),
-                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-                                             &write_cache_variants,
-                                             &update_cache_variants),
+                    SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+                                             &x4_write_cache_variants,
+                                             &x4_update_cache_variants),
                     SPINAND_HAS_CR_FEAT_BIT,
                     SPINAND_ECCINFO(&micron_8_ooblayout,
                                     micron_8_ecc_get_status),
@@ -212,15 +264,25 @@ static const struct spinand_info micron_spinand_table[] = 
{
        /* M70A 8Gb 1.8V */
        SPINAND_INFO("MT29F8G01ADBFD",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x47),
-                    NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 2),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 2),
                     NAND_ECCREQ(8, 512),
-                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-                                             &write_cache_variants,
-                                             &update_cache_variants),
+                    SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+                                             &x4_write_cache_variants,
+                                             &x4_update_cache_variants),
                     SPINAND_HAS_CR_FEAT_BIT,
                     SPINAND_ECCINFO(&micron_8_ooblayout,
                                     micron_8_ecc_get_status),
                     SPINAND_SELECT_TARGET(micron_select_target)),
+       /* M69A 2Gb 3.3V */
+       SPINAND_INFO("MT29F2G01AAAED",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x9F),
+                    NAND_MEMORG(1, 2048, 64, 64, 2048, 80, 2, 1, 1),
+                    NAND_ECCREQ(4, 512),
+                    SPINAND_INFO_OP_VARIANTS(&x4_read_cache_variants,
+                                             &x1_write_cache_variants,
+                                             &x1_update_cache_variants),
+                    0,
+                    SPINAND_ECCINFO(&micron_4_ooblayout, NULL)),
 };
 
 static int micron_spinand_init(struct spinand_device *spinand)
diff --git a/drivers/mtd/nand/spi/paragon.c b/drivers/mtd/nand/spi/paragon.c
new file mode 100644
index 00000000000..0c123930f14
--- /dev/null
+++ b/drivers/mtd/nand/spi/paragon.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Jeff Kletsky
+ *
+ * Author: Jeff Kletsky <git-comm...@allycomm.com>
+ */
+
+#ifndef __UBOOT__
+#include <linux/device.h>
+#include <linux/kernel.h>
+#endif
+#include <linux/mtd/spinand.h>
+
+
+#define SPINAND_MFR_PARAGON    0xa1
+
+
+#define PN26G0XA_STATUS_ECC_BITMASK            (3 << 4)
+
+#define PN26G0XA_STATUS_ECC_NONE_DETECTED      (0 << 4)
+#define PN26G0XA_STATUS_ECC_1_7_CORRECTED      (1 << 4)
+#define PN26G0XA_STATUS_ECC_ERRORED            (2 << 4)
+#define PN26G0XA_STATUS_ECC_8_CORRECTED                (3 << 4)
+
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+               SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+               SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
+               SPINAND_PROG_LOAD(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants,
+               SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
+               SPINAND_PROG_LOAD(false, 0, NULL, 0));
+
+
+static int pn26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section,
+                                  struct mtd_oob_region *region)
+{
+       if (section > 3)
+               return -ERANGE;
+
+       region->offset = 6 + (15 * section); /* 4 BBM + 2 user bytes */
+       region->length = 13;
+
+       return 0;
+}
+
+static int pn26g0xa_ooblayout_free(struct mtd_info *mtd, int section,
+                                  struct mtd_oob_region *region)
+{
+       if (section > 4)
+               return -ERANGE;
+
+       if (section == 4) {
+               region->offset = 64;
+               region->length = 64;
+       } else {
+               region->offset = 4 + (15 * section);
+               region->length = 2;
+       }
+
+       return 0;
+}
+
+static int pn26g0xa_ecc_get_status(struct spinand_device *spinand,
+                                  u8 status)
+{
+       switch (status & PN26G0XA_STATUS_ECC_BITMASK) {
+       case PN26G0XA_STATUS_ECC_NONE_DETECTED:
+               return 0;
+
+       case PN26G0XA_STATUS_ECC_1_7_CORRECTED:
+               return 7;       /* Return upper limit by convention */
+
+       case PN26G0XA_STATUS_ECC_8_CORRECTED:
+               return 8;
+
+       case PN26G0XA_STATUS_ECC_ERRORED:
+               return -EBADMSG;
+
+       default:
+               break;
+       }
+
+       return -EINVAL;
+}
+
+static const struct mtd_ooblayout_ops pn26g0xa_ooblayout = {
+       .ecc = pn26g0xa_ooblayout_ecc,
+       .rfree = pn26g0xa_ooblayout_free,
+};
+
+
+static const struct spinand_info paragon_spinand_table[] = {
+       SPINAND_INFO("PN26G01A",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xe1),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 21, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    0,
+                    SPINAND_ECCINFO(&pn26g0xa_ooblayout,
+                                    pn26g0xa_ecc_get_status)),
+       SPINAND_INFO("PN26G02A",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xe2),
+                    NAND_MEMORG(1, 2048, 128, 64, 2048, 41, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    0,
+                    SPINAND_ECCINFO(&pn26g0xa_ooblayout,
+                                    pn26g0xa_ecc_get_status)),
+};
+
+static const struct spinand_manufacturer_ops paragon_spinand_manuf_ops = {
+};
+
+const struct spinand_manufacturer paragon_spinand_manufacturer = {
+       .id = SPINAND_MFR_PARAGON,
+       .name = "Paragon",
+       .chips = paragon_spinand_table,
+       .nchips = ARRAY_SIZE(paragon_spinand_table),
+       .ops = &paragon_spinand_manuf_ops,
+};
diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c
index e057b08c703..b9908e79271 100644
--- a/drivers/mtd/nand/spi/toshiba.c
+++ b/drivers/mtd/nand/spi/toshiba.c
@@ -7,13 +7,13 @@
  */
 
 #ifndef __UBOOT__
-#include <malloc.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
 #endif
 #include <linux/bug.h>
 #include <linux/mtd/spinand.h>
 
+/* Kioxia is new name of Toshiba memory. */
 #define SPINAND_MFR_TOSHIBA            0x98
 #define TOSH_STATUS_ECC_HAS_BITFLIPS_T (3 << 4)
 
@@ -31,7 +31,7 @@ static SPINAND_OP_VARIANTS(update_cache_x4_variants,
                SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
                SPINAND_PROG_LOAD(false, 0, NULL, 0));
 
-/**
+/*
  * Backward compatibility for 1st generation Serial NAND devices
  * which don't support Quad Program Load operation.
  */
@@ -42,7 +42,7 @@ static SPINAND_OP_VARIANTS(update_cache_variants,
                SPINAND_PROG_LOAD(false, 0, NULL, 0));
 
 static int tx58cxgxsxraix_ooblayout_ecc(struct mtd_info *mtd, int section,
-                                    struct mtd_oob_region *region)
+                                       struct mtd_oob_region *region)
 {
        if (section > 0)
                return -ERANGE;
@@ -54,7 +54,7 @@ static int tx58cxgxsxraix_ooblayout_ecc(struct mtd_info *mtd, 
int section,
 }
 
 static int tx58cxgxsxraix_ooblayout_free(struct mtd_info *mtd, int section,
-                                     struct mtd_oob_region *region)
+                                        struct mtd_oob_region *region)
 {
        if (section > 0)
                return -ERANGE;
@@ -72,7 +72,7 @@ static const struct mtd_ooblayout_ops 
tx58cxgxsxraix_ooblayout = {
 };
 
 static int tx58cxgxsxraix_ecc_get_status(struct spinand_device *spinand,
-                                     u8 status)
+                                        u8 status)
 {
        struct nand_device *nand = spinand_to_nand(spinand);
        u8 mbf = 0;
@@ -113,7 +113,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
        /* 3.3V 1Gb (1st generation) */
        SPINAND_INFO("TC58CVG0S3HRAIG",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xC2),
-                    NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -124,7 +124,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
        /* 3.3V 2Gb (1st generation) */
        SPINAND_INFO("TC58CVG1S3HRAIG",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xCB),
-                    NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -135,7 +135,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
        /* 3.3V 4Gb (1st generation) */
        SPINAND_INFO("TC58CVG2S0HRAIG",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xCD),
-                    NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -146,7 +146,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
        /* 1.8V 1Gb (1st generation) */
        SPINAND_INFO("TC58CYG0S3HRAIG",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xB2),
-                    NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -157,7 +157,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
        /* 1.8V 2Gb (1st generation) */
        SPINAND_INFO("TC58CYG1S3HRAIG",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBB),
-                    NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -168,7 +168,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
        /* 1.8V 4Gb (1st generation) */
        SPINAND_INFO("TC58CYG2S0HRAIG",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBD),
-                    NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -184,7 +184,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
        /* 3.3V 1Gb (2nd generation) */
        SPINAND_INFO("TC58CVG0S3HRAIJ",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE2),
-                    NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_x4_variants,
@@ -195,7 +195,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
        /* 3.3V 2Gb (2nd generation) */
        SPINAND_INFO("TC58CVG1S3HRAIJ",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xEB),
-                    NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_x4_variants,
@@ -206,7 +206,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
        /* 3.3V 4Gb (2nd generation) */
        SPINAND_INFO("TC58CVG2S0HRAIJ",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xED),
-                    NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_x4_variants,
@@ -217,7 +217,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
        /* 3.3V 8Gb (2nd generation) */
        SPINAND_INFO("TH58CVG3S0HRAIJ",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4),
-                    NAND_MEMORG(1, 4096, 256, 64, 4096, 1, 1, 1),
+                    NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_x4_variants,
@@ -228,7 +228,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
        /* 1.8V 1Gb (2nd generation) */
        SPINAND_INFO("TC58CYG0S3HRAIJ",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xD2),
-                    NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_x4_variants,
@@ -239,7 +239,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
        /* 1.8V 2Gb (2nd generation) */
        SPINAND_INFO("TC58CYG1S3HRAIJ",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xDB),
-                    NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_x4_variants,
@@ -250,7 +250,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
        /* 1.8V 4Gb (2nd generation) */
        SPINAND_INFO("TC58CYG2S0HRAIJ",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xDD),
-                    NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_x4_variants,
@@ -261,7 +261,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
        /* 1.8V 8Gb (2nd generation) */
        SPINAND_INFO("TH58CYG3S0HRAIJ",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xD4),
-                    NAND_MEMORG(1, 4096, 256, 64, 4096, 1, 1, 1),
+                    NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_x4_variants,
diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 66ed0a51d2f..4e5a6eaecd7 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -8,11 +8,9 @@
  */
 
 #ifndef __UBOOT__
-#include <malloc.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
 #endif
-#include <linux/bitops.h>
 #include <linux/mtd/spinand.h>
 
 #define SPINAND_MFR_WINBOND            0xEF
@@ -81,7 +79,7 @@ static int w25m02gv_select_target(struct spinand_device 
*spinand,
 static const struct spinand_info winbond_spinand_table[] = {
        SPINAND_INFO("W25M02GV",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab),
-                    NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 2),
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2),
                     NAND_ECCREQ(1, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -91,7 +89,7 @@ static const struct spinand_info winbond_spinand_table[] = {
                     SPINAND_SELECT_TARGET(w25m02gv_select_target)),
        SPINAND_INFO("W25N01GV",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa),
-                    NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
                     NAND_ECCREQ(1, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index aeb38dec2e0..651f8706df5 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -19,6 +19,7 @@
  * @oobsize: OOB area size
  * @pages_per_eraseblock: number of pages per eraseblock
  * @eraseblocks_per_lun: number of eraseblocks per LUN (Logical Unit Number)
+ * @max_bad_eraseblocks_per_lun: maximum number of eraseblocks per LUN
  * @planes_per_lun: number of planes per LUN
  * @luns_per_target: number of LUN per target (target is a synonym for die)
  * @ntargets: total number of targets exposed by the NAND device
@@ -29,18 +30,20 @@ struct nand_memory_organization {
        unsigned int oobsize;
        unsigned int pages_per_eraseblock;
        unsigned int eraseblocks_per_lun;
+       unsigned int max_bad_eraseblocks_per_lun;
        unsigned int planes_per_lun;
        unsigned int luns_per_target;
        unsigned int ntargets;
 };
 
-#define NAND_MEMORG(bpc, ps, os, ppe, epl, ppl, lpt, nt)       \
+#define NAND_MEMORG(bpc, ps, os, ppe, epl, mbb, ppl, lpt, nt)  \
        {                                                       \
                .bits_per_cell = (bpc),                         \
                .pagesize = (ps),                               \
                .oobsize = (os),                                \
                .pages_per_eraseblock = (ppe),                  \
                .eraseblocks_per_lun = (epl),                   \
+               .max_bad_eraseblocks_per_lun = (mbb),           \
                .planes_per_lun = (ppl),                        \
                .luns_per_target = (lpt),                       \
                .ntargets = (nt),                               \
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 1ae4dc6b15b..e8d6feb9705 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -75,30 +75,60 @@
                   SPI_MEM_OP_DUMMY(ndummy, 1),                         \
                   SPI_MEM_OP_DATA_IN(len, buf, 1))
 
+#define SPINAND_PAGE_READ_FROM_CACHE_OP_3A(fast, addr, ndummy, buf, len) \
+       SPI_MEM_OP(SPI_MEM_OP_CMD(fast ? 0x0b : 0x03, 1),               \
+                  SPI_MEM_OP_ADDR(3, addr, 1),                         \
+                  SPI_MEM_OP_DUMMY(ndummy, 1),                         \
+                  SPI_MEM_OP_DATA_IN(len, buf, 1))
+
 #define SPINAND_PAGE_READ_FROM_CACHE_X2_OP(addr, ndummy, buf, len)     \
        SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1),                             \
                   SPI_MEM_OP_ADDR(2, addr, 1),                         \
                   SPI_MEM_OP_DUMMY(ndummy, 1),                         \
                   SPI_MEM_OP_DATA_IN(len, buf, 2))
 
+#define SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(addr, ndummy, buf, len)  \
+       SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1),                             \
+                  SPI_MEM_OP_ADDR(3, addr, 1),                         \
+                  SPI_MEM_OP_DUMMY(ndummy, 1),                         \
+                  SPI_MEM_OP_DATA_IN(len, buf, 2))
+
 #define SPINAND_PAGE_READ_FROM_CACHE_X4_OP(addr, ndummy, buf, len)     \
        SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1),                             \
                   SPI_MEM_OP_ADDR(2, addr, 1),                         \
                   SPI_MEM_OP_DUMMY(ndummy, 1),                         \
                   SPI_MEM_OP_DATA_IN(len, buf, 4))
 
+#define SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(addr, ndummy, buf, len)  \
+       SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1),                             \
+                  SPI_MEM_OP_ADDR(3, addr, 1),                         \
+                  SPI_MEM_OP_DUMMY(ndummy, 1),                         \
+                  SPI_MEM_OP_DATA_IN(len, buf, 4))
+
 #define SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(addr, ndummy, buf, len) \
        SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1),                             \
                   SPI_MEM_OP_ADDR(2, addr, 2),                         \
                   SPI_MEM_OP_DUMMY(ndummy, 2),                         \
                   SPI_MEM_OP_DATA_IN(len, buf, 2))
 
+#define SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP_3A(addr, ndummy, buf, len) \
+       SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1),                             \
+                  SPI_MEM_OP_ADDR(3, addr, 2),                         \
+                  SPI_MEM_OP_DUMMY(ndummy, 2),                         \
+                  SPI_MEM_OP_DATA_IN(len, buf, 2))
+
 #define SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(addr, ndummy, buf, len) \
        SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1),                             \
                   SPI_MEM_OP_ADDR(2, addr, 4),                         \
                   SPI_MEM_OP_DUMMY(ndummy, 4),                         \
                   SPI_MEM_OP_DATA_IN(len, buf, 4))
 
+#define SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP_3A(addr, ndummy, buf, len) \
+       SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1),                             \
+                  SPI_MEM_OP_ADDR(3, addr, 4),                         \
+                  SPI_MEM_OP_DUMMY(ndummy, 4),                         \
+                  SPI_MEM_OP_DATA_IN(len, buf, 4))
+
 #define SPINAND_PROG_EXEC_OP(addr)                                     \
        SPI_MEM_OP(SPI_MEM_OP_CMD(0x10, 1),                             \
                   SPI_MEM_OP_ADDR(3, addr, 1),                         \
@@ -218,6 +248,7 @@ struct spinand_manufacturer {
 extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
 extern const struct spinand_manufacturer macronix_spinand_manufacturer;
 extern const struct spinand_manufacturer micron_spinand_manufacturer;
+extern const struct spinand_manufacturer paragon_spinand_manufacturer;
 extern const struct spinand_manufacturer toshiba_spinand_manufacturer;
 extern const struct spinand_manufacturer winbond_spinand_manufacturer;
 
-- 
2.39.0


Reply via email to