[PATCH 4/4] mtd: spi-nor: add generic flash driver

tkuw584924 at gmail.com tkuw584924 at gmail.com
Thu Aug 8 08:00:10 CEST 2024


From: Takahiro Kuwano <Takahiro.Kuwano at infineon.com>

Our SFDP parsing is everything we need to support all basic operations
of a flash device. If the flash isn't found in our in-kernel flash
database, gracefully fall back to a driver described solely by its SFDP
tables.

This patch ports the commit in Linux:
773bbe104497 ("mtd: spi-nor: add generic flash driver")

A new flag named SPI_NOR_PARSE_SFDP is defined to perform SFDP parse for
the spi-nor-generic. And spi_nor_read_id() is moved to later part than
SFDP functions.

Signed-off-by: Takahiro Kuwano <Takahiro.Kuwano at infineon.com>
---
 drivers/mtd/spi/sf_internal.h  |  1 +
 drivers/mtd/spi/spi-nor-core.c | 95 ++++++++++++++++++++++++----------
 2 files changed, 70 insertions(+), 26 deletions(-)

diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 57608750c9..f7b0cea983 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -68,6 +68,7 @@ struct flash_info {
 #define SPI_NOR_HAS_SST26LOCK	BIT(14)	/* Flash supports lock/unlock via BPR */
 #define SPI_NOR_OCTAL_READ	BIT(15)	/* Flash supports Octal Read */
 #define SPI_NOR_OCTAL_DTR_READ	BIT(16)	/* Flash supports Octal DTR Read */
+#define SPI_NOR_PARSE_SFDP	BIT(17)	/* Parse SFDP tables */
 };
 
 extern const struct flash_info spi_nor_ids[];
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index feafc48a49..c1186271a4 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -1509,31 +1509,6 @@ static int stm_is_unlocked(struct spi_nor *nor, loff_t ofs, uint64_t len)
 #endif /* CONFIG_SPI_FLASH_STMICRO */
 #endif
 
-static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
-{
-	int			tmp;
-	u8			id[SPI_NOR_MAX_ID_LEN];
-	const struct flash_info	*info;
-
-	tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);
-	if (tmp < 0) {
-		dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp);
-		return ERR_PTR(tmp);
-	}
-
-	info = spi_nor_ids;
-	for (; info->name; info++) {
-		if (info->id_len) {
-			if (!memcmp(info->id, id, info->id_len))
-				return info;
-		}
-	}
-
-	dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n",
-		id[0], id[1], id[2]);
-	return ERR_PTR(-ENODEV);
-}
-
 static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
 			size_t *retlen, u_char *buf)
 {
@@ -2154,6 +2129,17 @@ spi_nor_set_pp_settings(struct spi_nor_pp_command *pp,
 }
 
 #if CONFIG_IS_ENABLED(SPI_FLASH_SFDP_SUPPORT)
+
+static const struct flash_info spi_nor_generic_flash = {
+	.name = "spi-nor-generic",
+	/*
+	 * JESD216 rev A doesn't specify the page size, therefore we need a
+	 * sane default.
+	 */
+	.page_size = 256,
+	.flags = SPI_NOR_PARSE_SFDP,
+};
+
 /*
  * Serial Flash Discoverable Parameters (SFDP) parsing.
  */
@@ -2724,6 +2710,32 @@ out:
 	return ret;
 }
 
+/**
+ * spi_nor_check_sfdp_signature() - check for a valid SFDP signature
+ * @nor:	pointer to a 'struct spi_nor'
+ *
+ * Used to detect if the flash supports the RDSFDP command as well as the
+ * presence of a valid SFDP table.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_check_sfdp_signature(struct spi_nor *nor)
+{
+	u32 signature;
+	int err;
+
+	/* Get the SFDP header. */
+	err = spi_nor_read_sfdp(nor, 0, sizeof(signature), &signature);
+	if (err < 0)
+		return err;
+
+	/* Check the SFDP signature. */
+	if (le32_to_cpu(signature) != SFDP_SIGNATURE)
+		return -EINVAL;
+
+	return 0;
+}
+
 /**
  * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters.
  * @nor:		pointer to a 'struct spi_nor'
@@ -3014,7 +3026,7 @@ static int spi_nor_init_params(struct spi_nor *nor,
 	nor->addr_width = 0;
 	nor->mtd.erasesize = 0;
 	if (info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
-	    SPI_NOR_OCTAL_DTR_READ)) {
+	    SPI_NOR_OCTAL_DTR_READ | SPI_NOR_PARSE_SFDP)) {
 		struct spi_nor_flash_parameter sfdp_params;
 
 		memcpy(&sfdp_params, params, sizeof(sfdp_params));
@@ -4170,6 +4182,37 @@ void spi_nor_set_fixups(struct spi_nor *nor)
 #endif /* SPI_FLASH_MACRONIX */
 }
 
+static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
+{
+	int			tmp;
+	u8			id[SPI_NOR_MAX_ID_LEN];
+	const struct flash_info	*info;
+
+	tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);
+	if (tmp < 0) {
+		dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp);
+		return ERR_PTR(tmp);
+	}
+
+	info = spi_nor_ids;
+	for (; info->name; info++) {
+		if (info->id_len) {
+			if (!memcmp(info->id, id, info->id_len))
+				return info;
+		}
+	}
+
+#if CONFIG_IS_ENABLED(SPI_FLASH_SFDP_SUPPORT)
+	/* Fallback to a generic flash described only by its SFDP data. */
+	if (!spi_nor_check_sfdp_signature(nor))
+		return &spi_nor_generic_flash;
+#endif
+
+	dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n",
+		id[0], id[1], id[2]);
+	return ERR_PTR(-ENODEV);
+}
+
 int spi_nor_scan(struct spi_nor *nor)
 {
 	struct spi_nor_flash_parameter params;
-- 
2.34.1



More information about the U-Boot mailing list