mtd: spinand: Add support for XTX XT26xxxDxxxxx
authorBruce Suen <bruce_suen@163.com>
Thu, 12 Oct 2023 10:24:12 +0000 (06:24 -0400)
committerMiquel Raynal <miquel.raynal@bootlin.com>
Mon, 16 Oct 2023 09:17:00 +0000 (11:17 +0200)
Add Support XTX Technology XT26G01DXXXXX, XT26G11DXXXXX, XT26Q01DXXXXX,
XT26G02DXXXXX, XT26G12DXXXXX, XT26Q02DXXXXX, XT26G04DXXXXX, and
XT26Q04DXXXXX SPI NAND.

These are 3V/1.8V 1G/2G/4Gbit serial SLC NAND flash device with on-die
ECC(8bit strength per 512bytes).

Datasheet Links:
- http://www.xtxtech.com/download/?AId=458
- http://www.xtxtech.com/download/?AId=495

Signed-off-by: Bruce Suen <bruce_suen@163.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20231012102412.10581-1-bruce_suen@163.com
drivers/mtd/nand/spi/xtx.c

index 3911520f718c8d843e8a1dbe6fdc53f5c9e43dc0..66a4255bdf06617f76f502ddaa873c1334c24ea4 100644 (file)
@@ -4,6 +4,7 @@
  * Felix Matouschek <felix@matouschek.org>
  */
 
+#include <linux/bitfield.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
 #include <linux/mtd/spinand.h>
 #define XT26G0XA_STATUS_ECC_8_CORRECTED        (3 << 4)
 #define XT26G0XA_STATUS_ECC_UNCOR_ERROR        (2 << 4)
 
+#define XT26XXXD_STATUS_ECC3_ECC2_MASK     GENMASK(7, 6)
+#define XT26XXXD_STATUS_ECC_NO_DETECTED     (0)
+#define XT26XXXD_STATUS_ECC_1_7_CORRECTED   (1)
+#define XT26XXXD_STATUS_ECC_8_CORRECTED     (3)
+#define XT26XXXD_STATUS_ECC_UNCOR_ERROR     (2)
+
 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),
@@ -84,6 +91,53 @@ static int xt26g0xa_ecc_get_status(struct spinand_device *spinand,
        return status >> 2;
 }
 
+static int xt26xxxd_ooblayout_ecc(struct mtd_info *mtd, int section,
+                                 struct mtd_oob_region *region)
+{
+       if (section)
+               return -ERANGE;
+
+       region->offset = mtd->oobsize / 2;
+       region->length = mtd->oobsize / 2;
+
+       return 0;
+}
+
+static int xt26xxxd_ooblayout_free(struct mtd_info *mtd, int section,
+                                  struct mtd_oob_region *region)
+{
+       if (section)
+               return -ERANGE;
+
+       region->offset = 2;
+       region->length = mtd->oobsize / 2 - 2;
+
+       return 0;
+}
+
+static const struct mtd_ooblayout_ops xt26xxxd_ooblayout = {
+       .ecc = xt26xxxd_ooblayout_ecc,
+       .free = xt26xxxd_ooblayout_free,
+};
+
+static int xt26xxxd_ecc_get_status(struct spinand_device *spinand,
+                                  u8 status)
+{
+       switch (FIELD_GET(STATUS_ECC_MASK, status)) {
+       case XT26XXXD_STATUS_ECC_NO_DETECTED:
+               return 0;
+       case XT26XXXD_STATUS_ECC_UNCOR_ERROR:
+               return -EBADMSG;
+       case XT26XXXD_STATUS_ECC_1_7_CORRECTED:
+               return 4 + FIELD_GET(XT26XXXD_STATUS_ECC3_ECC2_MASK, status);
+       case XT26XXXD_STATUS_ECC_8_CORRECTED:
+               return 8;
+       default:
+               break;
+       }
+
+       return -EINVAL;
+}
 static const struct spinand_info xtx_spinand_table[] = {
        SPINAND_INFO("XT26G01A",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE1),
@@ -115,6 +169,86 @@ static const struct spinand_info xtx_spinand_table[] = {
                     SPINAND_HAS_QE_BIT,
                     SPINAND_ECCINFO(&xt26g0xa_ooblayout,
                                     xt26g0xa_ecc_get_status)),
+       SPINAND_INFO("XT26G01D",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x31),
+                    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),
+                    0,
+                    SPINAND_ECCINFO(&xt26xxxd_ooblayout,
+                                    xt26xxxd_ecc_get_status)),
+       SPINAND_INFO("XT26G11D",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x34),
+                    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),
+                    0,
+                    SPINAND_ECCINFO(&xt26xxxd_ooblayout,
+                                    xt26xxxd_ecc_get_status)),
+       SPINAND_INFO("XT26Q01D",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x51),
+                    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),
+                    0,
+                    SPINAND_ECCINFO(&xt26xxxd_ooblayout,
+                                    xt26xxxd_ecc_get_status)),
+       SPINAND_INFO("XT26G02D",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x32),
+                    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,
+                                             &update_cache_variants),
+                    0,
+                    SPINAND_ECCINFO(&xt26xxxd_ooblayout,
+                                    xt26xxxd_ecc_get_status)),
+       SPINAND_INFO("XT26G12D",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x35),
+                    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,
+                                             &update_cache_variants),
+                    0,
+                    SPINAND_ECCINFO(&xt26xxxd_ooblayout,
+                                    xt26xxxd_ecc_get_status)),
+       SPINAND_INFO("XT26Q02D",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x52),
+                    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,
+                                             &update_cache_variants),
+                    0,
+                    SPINAND_ECCINFO(&xt26xxxd_ooblayout,
+                                    xt26xxxd_ecc_get_status)),
+       SPINAND_INFO("XT26G04D",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x33),
+                    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),
+                    0,
+                    SPINAND_ECCINFO(&xt26xxxd_ooblayout,
+                                    xt26xxxd_ecc_get_status)),
+       SPINAND_INFO("XT26Q04D",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x53),
+                    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),
+                    0,
+                    SPINAND_ECCINFO(&xt26xxxd_ooblayout,
+                                    xt26xxxd_ecc_get_status)),
 };
 
 static const struct spinand_manufacturer_ops xtx_spinand_manuf_ops = {