[PATCH] mtd: spinand: add support for FudanMicro FM25S01BI3
Weijie Gao
weijie.gao at mediatek.com
Wed Apr 29 10:13:19 CEST 2026
Add support for FudanMicro FM25S01BI3 SPI-NAND.
This driver is ported from linux kernel with fix:
This SPI-NAND does not support 1S-4S-4S and 1S-2S-2S modes.
https://lore.kernel.org/linux-mtd/20251127195900.2562-1-csharper2005@gmail.com/
Datasheet link:
https://www.fmsh.com/nvm/FM25S01BI3_ds_eng.pdf
Tested on MediaTek's filogic platform reference board.
Signed-off-by: Weijie Gao <weijie.gao at mediatek.com>
---
drivers/mtd/nand/spi/fmsh.c | 77 +++++++++++++++++++++++++++++++++++++
1 file changed, 77 insertions(+)
diff --git a/drivers/mtd/nand/spi/fmsh.c b/drivers/mtd/nand/spi/fmsh.c
index 80837b7dd42..6740f30689f 100644
--- a/drivers/mtd/nand/spi/fmsh.c
+++ b/drivers/mtd/nand/spi/fmsh.c
@@ -11,6 +11,13 @@
#endif
#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,
@@ -21,6 +28,12 @@ static SPINAND_OP_VARIANTS(read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
+static SPINAND_OP_VARIANTS(fm25s01bi3_read_cache_variants,
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
+
static SPINAND_OP_VARIANTS(write_cache_variants,
SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
@@ -47,11 +60,65 @@ 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,
.rfree = fm25s01a_ooblayout_free,
};
+static const struct mtd_ooblayout_ops fm25s01bi3_ooblayout = {
+ .ecc = fm25s01bi3_ooblayout_ecc,
+ .rfree = fm25s01bi3_ooblayout_free,
+};
+
static const struct spinand_info fmsh_spinand_table[] = {
SPINAND_INFO("FM25S01A",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4),
@@ -62,6 +129,16 @@ static const struct spinand_info fmsh_spinand_table[] = {
&update_cache_variants),
0,
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(&fm25s01bi3_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 = {
--
2.45.2
More information about the U-Boot
mailing list