]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
mtd: spinand: add support for FudanMicro FM25S01BI3
authorMikhail Zhilkin <csharper2005@gmail.com>
Thu, 27 Nov 2025 19:59:00 +0000 (22:59 +0300)
committerMiquel Raynal <miquel.raynal@bootlin.com>
Sat, 29 Nov 2025 12:46:40 +0000 (13:46 +0100)
Add support for FudanMicro FM25S01BI3 SPI NAND.

Link: https://www.fmsh.com/nvm/FM25S01BI3_ds_eng.pdf
Signed-off-by: Mikhail Zhilkin <csharper2005@gmail.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
drivers/mtd/nand/spi/fmsh.c

index 8b2097bfc771608788e4063957ddda61aee3b139..43689b91dc28df85691b6dfab235697035fdddec 100644 (file)
@@ -9,6 +9,13 @@
 #include <linux/kernel.h>
 #include <linux/mtd/spinand.h>
 
+#define FM25S01BI3_STATUS_ECC_MASK             (7 << 4)
+       #define FM25S01BI3_STATUS_ECC_NO_BITFLIPS       (0 << 4)
+       #define FM25S01BI3_STATUS_ECC_1_3_BITFLIPS      (1 << 4)
+       #define FM25S01BI3_STATUS_ECC_UNCOR_ERROR       (2 << 4)
+       #define FM25S01BI3_STATUS_ECC_4_6_BITFLIPS      (3 << 4)
+       #define FM25S01BI3_STATUS_ECC_7_8_BITFLIPS      (5 << 4)
+
 #define SPINAND_MFR_FMSH               0xA1
 
 static SPINAND_OP_VARIANTS(read_cache_variants,
@@ -45,11 +52,66 @@ static int fm25s01a_ooblayout_free(struct mtd_info *mtd, int section,
        return 0;
 }
 
+static int fm25s01bi3_ecc_get_status(struct spinand_device *spinand,
+                                    u8 status)
+{
+       switch (status & FM25S01BI3_STATUS_ECC_MASK) {
+       case FM25S01BI3_STATUS_ECC_NO_BITFLIPS:
+               return 0;
+
+       case FM25S01BI3_STATUS_ECC_UNCOR_ERROR:
+               return -EBADMSG;
+
+       case FM25S01BI3_STATUS_ECC_1_3_BITFLIPS:
+               return 3;
+
+       case FM25S01BI3_STATUS_ECC_4_6_BITFLIPS:
+               return 6;
+
+       case FM25S01BI3_STATUS_ECC_7_8_BITFLIPS:
+               return 8;
+
+       default:
+               break;
+       }
+
+       return -EINVAL;
+}
+
+static int fm25s01bi3_ooblayout_ecc(struct mtd_info *mtd, int section,
+                                   struct mtd_oob_region *region)
+{
+       if (section)
+               return -ERANGE;
+
+       region->offset = 64;
+       region->length = 64;
+
+       return 0;
+}
+
+static int fm25s01bi3_ooblayout_free(struct mtd_info *mtd, int section,
+                                    struct mtd_oob_region *region)
+{
+       if (section > 3)
+               return -ERANGE;
+
+       region->offset = (16 * section) + 4;
+       region->length = 12;
+
+       return 0;
+}
+
 static const struct mtd_ooblayout_ops fm25s01a_ooblayout = {
        .ecc = fm25s01a_ooblayout_ecc,
        .free = fm25s01a_ooblayout_free,
 };
 
+static const struct mtd_ooblayout_ops fm25s01bi3_ooblayout = {
+       .ecc = fm25s01bi3_ooblayout_ecc,
+       .free = fm25s01bi3_ooblayout_free,
+};
+
 static const struct spinand_info fmsh_spinand_table[] = {
        SPINAND_INFO("FM25S01A",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4),
@@ -60,6 +122,16 @@ static const struct spinand_info fmsh_spinand_table[] = {
                                              &update_cache_variants),
                     SPINAND_HAS_QE_BIT,
                     SPINAND_ECCINFO(&fm25s01a_ooblayout, NULL)),
+       SPINAND_INFO("FM25S01BI3",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xd4),
+                    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(&fm25s01bi3_ooblayout,
+                                     fm25s01bi3_ecc_get_status)),
 };
 
 static const struct spinand_manufacturer_ops fmsh_spinand_manuf_ops = {