]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
mtd: spinand: add support for ESMT F50x1G41LB
authorIgor Prusov <ivprusov@salutedevices.com>
Tue, 17 Oct 2023 19:29:26 +0000 (22:29 +0300)
committerJagan Teki <jagan@edgeble.ai>
Thu, 14 Dec 2023 18:20:00 +0000 (23:50 +0530)
Adaptation of Linux commit d74c36480a67

This patch adds support for ESMT F50L1G41LB and F50D1G41LB.
It seems that ESMT likes to use random JEDEC ID from other vendors.
Their 1G chips uses 0xc8 from GigaDevice and 2G/4G chips uses 0x2c from
Micron. For this reason, the ESMT entry is named esmt_c8 with explicit
JEDEC ID in variable name.

Datasheets:
https://www.esmt.com.tw/upload/pdf/ESMT/datasheets/F50L1G41LB(2M).pdf
https://www.esmt.com.tw/upload/pdf/ESMT/datasheets/F50D1G41LB(2M).pdf

Signed-off-by: Igor Prusov <ivprusov@salutedevices.com>
Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
Signed-off-by: Martin Kurbanov <mmkurbanov@sberdevices.ru>
Signed-off-by: Dmitry Rokosov <ddrokosov@sberdevices.ru>
Tested-by: Martin Kurbanov <mmkurbanov@sberdevices.ru>
Reviewed-by: Frieder Schrempf <frieder.schrempf@kontron.de>
Reviewed-by: Jagan Teki <jagan@amarulasolutions.com>
drivers/mtd/nand/spi/Makefile
drivers/mtd/nand/spi/core.c
drivers/mtd/nand/spi/esmt.c [new file with mode: 0644]
include/linux/mtd/spinand.h

index 3051de4f7ef27c80a19cfb1dccf15d5f6721b298..f172f4787f8510ad699bee2a6eb47010c973824a 100644 (file)
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
 
-spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o
+spinand-objs := core.o esmt.o gigadevice.o macronix.o micron.o paragon.o
+spinand-objs += toshiba.o winbond.o
 obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
index 597b088ca7e8c73db104f5a31884ea797c0a7b99..8ca33459f96aa1548a9d351f0f325dcb6bf5a923 100644 (file)
@@ -828,6 +828,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = {
        &paragon_spinand_manufacturer,
        &toshiba_spinand_manufacturer,
        &winbond_spinand_manufacturer,
+       &esmt_c8_spinand_manufacturer,
 };
 
 static int spinand_manufacturer_match(struct spinand_device *spinand,
diff --git a/drivers/mtd/nand/spi/esmt.c b/drivers/mtd/nand/spi/esmt.c
new file mode 100644 (file)
index 0000000..7e07b26
--- /dev/null
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Author:
+ *     Chuanhong Guo <gch981213@gmail.com> - the main driver logic
+ *     Martin Kurbanov <mmkurbanov@sberdevices.ru> - OOB layout
+ */
+
+#ifndef __UBOOT__
+#include <linux/device.h>
+#include <linux/kernel.h>
+#endif
+#include <linux/mtd/spinand.h>
+
+/* ESMT uses GigaDevice 0xc8 JECDEC ID on some SPI NANDs */
+#define SPINAND_MFR_ESMT_C8                    0xc8
+
+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),
+                          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));
+
+/*
+ * OOB spare area map (64 bytes)
+ *
+ * Bad Block Markers
+ * filled by HW and kernel                 Reserved
+ *   |                 +-----------------------+-----------------------+
+ *   |                 |                       |                       |
+ *   |                 |    OOB free data Area |non ECC protected      |
+ *   |   +-------------|-----+-----------------|-----+-----------------|-----+
+ *   |   |             |     |                 |     |                 |     |
+ * +-|---|----------+--|-----|--------------+--|-----|--------------+--|-----|--------------+
+ * | |   | section0 |  |     |    section1  |  |     |    section2  |  |     |    section3  |
+ * +-v-+-v-+---+----+--v--+--v--+-----+-----+--v--+--v--+-----+-----+--v--+--v--+-----+-----+
+ * |   |   |   |    |     |     |     |     |     |     |     |     |     |     |     |     |
+ * |0:1|2:3|4:7|8:15|16:17|18:19|20:23|24:31|32:33|34:35|36:39|40:47|48:49|50:51|52:55|56:63|
+ * |   |   |   |    |     |     |     |     |     |     |     |     |     |     |     |     |
+ * +---+---+-^-+--^-+-----+-----+--^--+--^--+-----+-----+--^--+--^--+-----+-----+--^--+--^--+
+ *           |    |                |     |                 |     |                 |     |
+ *           |    +----------------|-----+-----------------|-----+-----------------|-----+
+ *           |             ECC Area|(Main + Spare) - filled|by ESMT NAND HW        |
+ *           |                     |                       |                       |
+ *           +---------------------+-----------------------+-----------------------+
+ *                         OOB ECC protected Area - not used due to
+ *                         partial programming from some filesystems
+ *                             (like JFFS2 with cleanmarkers)
+ */
+
+#define ESMT_OOB_SECTION_COUNT                 4
+#define ESMT_OOB_SECTION_SIZE(nand) \
+       (nanddev_per_page_oobsize(nand) / ESMT_OOB_SECTION_COUNT)
+#define ESMT_OOB_FREE_SIZE(nand) \
+       (ESMT_OOB_SECTION_SIZE(nand) / 2)
+#define ESMT_OOB_ECC_SIZE(nand) \
+       (ESMT_OOB_SECTION_SIZE(nand) - ESMT_OOB_FREE_SIZE(nand))
+#define ESMT_OOB_BBM_SIZE                      2
+
+static int f50l1g41lb_ooblayout_ecc(struct mtd_info *mtd, int section,
+                                   struct mtd_oob_region *region)
+{
+       struct nand_device *nand = mtd_to_nanddev(mtd);
+
+       if (section >= ESMT_OOB_SECTION_COUNT)
+               return -ERANGE;
+
+       region->offset = section * ESMT_OOB_SECTION_SIZE(nand) +
+                        ESMT_OOB_FREE_SIZE(nand);
+       region->length = ESMT_OOB_ECC_SIZE(nand);
+
+       return 0;
+}
+
+static int f50l1g41lb_ooblayout_free(struct mtd_info *mtd, int section,
+                                    struct mtd_oob_region *region)
+{
+       struct nand_device *nand = mtd_to_nanddev(mtd);
+
+       if (section >= ESMT_OOB_SECTION_COUNT)
+               return -ERANGE;
+
+       /*
+        * Reserve space for bad blocks markers (section0) and
+        * reserved bytes (sections 1-3)
+        */
+       region->offset = section * ESMT_OOB_SECTION_SIZE(nand) + 2;
+
+       /* Use only 2 non-protected ECC bytes per each OOB section */
+       region->length = 2;
+
+       return 0;
+}
+
+static const struct mtd_ooblayout_ops f50l1g41lb_ooblayout = {
+       .ecc = f50l1g41lb_ooblayout_ecc,
+       .rfree = f50l1g41lb_ooblayout_free,
+};
+
+static const struct spinand_info esmt_c8_spinand_table[] = {
+       SPINAND_INFO("F50L1G41LB",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01),
+                    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,
+                                             &update_cache_variants),
+                    0,
+                    SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
+       SPINAND_INFO("F50D1G41LB",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x11),
+                    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,
+                                             &update_cache_variants),
+                    0,
+                    SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
+};
+
+static const struct spinand_manufacturer_ops esmt_spinand_manuf_ops = {
+};
+
+const struct spinand_manufacturer esmt_c8_spinand_manufacturer = {
+       .id = SPINAND_MFR_ESMT_C8,
+       .name = "ESMT",
+       .chips = esmt_c8_spinand_table,
+       .nchips = ARRAY_SIZE(esmt_c8_spinand_table),
+       .ops = &esmt_spinand_manuf_ops,
+};
index e8d6feb9705e22d84a72b38b6c85e40a235680ea..91e61ce86463d89ce21d8a1812175091e80511fc 100644 (file)
@@ -251,6 +251,7 @@ 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;
+extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;
 
 /**
  * struct spinand_op_variants - SPI NAND operation variants