[PATCH 1/3] mtd: spi-nor: handle JEDEC manufacturer bank

A. Zini alessandro.zini at siemens.com
Mon Jul 29 03:20:14 PDT 2024


From: Alessandro Zini <alessandro.zini at siemens.com>

JEDEC JEP106 maintains a list of manufacturers IDs, consisting in 7
bit of information plus 1 parity bit, for a total of 1 Byte. Since the
number of manufacturers is way larger than this, JEDEC additionally
defines the continuation code 0x7f to be used as a prefix to the
actual ID, subdividing IDs in different banks.

This commit handles such manufacturer bank code by introducing a new
mfr_bank field in flash_info struct. This field is intended to be
populated when specifying a manufacturer part, and for retro
compatibility it is assumed to be 1 if omitted.
Note that this assumption was already implicitly taken, as only a
couple of the already supported manufacturer parts have the
continuation code prefixed to the actual ID.

Given the fast expanding pace of JEP106, the read ID operation has
been expanded to 128 Bytes plus the pre-existing 6 Bytes for the ID
code, thus supporting up to 128 banks.

Signed-off-by: Alessandro Zini <alessandro.zini at siemens.com>
---
 drivers/mtd/spi-nor/core.c    | 71 ++++++++++++++++++++++++++++++-----
 drivers/mtd/spi-nor/core.h    | 10 ++++-
 drivers/mtd/spi-nor/debugfs.c |  2 +
 drivers/mtd/spi-nor/sysfs.c   | 13 +++++++
 4 files changed, 86 insertions(+), 10 deletions(-)

diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index e0c4efc424f4..07d2627c5850 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -407,6 +407,32 @@ int spi_nor_write_disable(struct spi_nor *nor)
 	return ret;
 }
 
+/**
+ * spi_nor_get_mfr_bank() - Get the JEDEC manufacturer bank number.
+ * @id:		pointer to the buffer where the JEDEC ID (incl. eventual
+ *		continuation codes) is stored.
+ * @bank:	pointer to a buffer where the bank number will be written.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+int spi_nor_get_mfr_bank(u8 *id, u8 *bank)
+{
+	u8 tmp_bank;
+
+	tmp_bank = 0;
+	while (tmp_bank < SPI_NOR_MAX_ID_READ_LEN &&
+	       id[tmp_bank] == SPI_NOR_CONTINUATION_CODE)
+		tmp_bank++;
+
+	/* Incomplete read of JEDEC id */
+	if (tmp_bank == SPI_NOR_MAX_ID_READ_LEN)
+		return -EIO;
+
+	*bank = tmp_bank;
+
+	return 0;
+}
+
 /**
  * spi_nor_read_id() - Read the JEDEC ID.
  * @nor:	pointer to 'struct spi_nor'.
@@ -415,7 +441,7 @@ int spi_nor_write_disable(struct spi_nor *nor)
  * @ndummy:	number of dummy bytes to send after an opcode or address. Can
  *		be zero if the operation does not require dummy bytes.
  * @id:		pointer to a DMA-able buffer where the value of the JEDEC ID
- *		will be written.
+ *		(incl. eventual continuation codes) will be written.
  * @proto:	the SPI protocol for register operation.
  *
  * Return: 0 on success, -errno otherwise.
@@ -427,13 +453,14 @@ int spi_nor_read_id(struct spi_nor *nor, u8 naddr, u8 ndummy, u8 *id,
 
 	if (nor->spimem) {
 		struct spi_mem_op op =
-			SPI_NOR_READID_OP(naddr, ndummy, id, SPI_NOR_MAX_ID_LEN);
+			SPI_NOR_READID_OP(naddr, ndummy, id,
+					  SPI_NOR_MAX_ID_READ_LEN);
 
 		spi_nor_spimem_setup_op(nor, &op, proto);
 		ret = spi_mem_exec_op(nor->spimem, &op);
 	} else {
 		ret = nor->controller_ops->read_reg(nor, SPINOR_OP_RDID, id,
-						    SPI_NOR_MAX_ID_LEN);
+						    SPI_NOR_MAX_ID_READ_LEN);
 	}
 	return ret;
 }
@@ -1984,7 +2011,8 @@ static const struct flash_info spi_nor_generic_flash = {
 };
 
 static const struct flash_info *spi_nor_match_id(struct spi_nor *nor,
-						 const u8 *id)
+						 const u8 *id,
+						 u8 bank)
 {
 	const struct flash_info *part;
 	unsigned int i, j;
@@ -1992,8 +2020,22 @@ static const struct flash_info *spi_nor_match_id(struct spi_nor *nor,
 	for (i = 0; i < ARRAY_SIZE(manufacturers); i++) {
 		for (j = 0; j < manufacturers[i]->nparts; j++) {
 			part = &manufacturers[i]->parts[j];
+
 			if (part->id &&
-			    !memcmp(part->id->bytes, id, part->id->len)) {
+			    !memcmp(part->id->bytes, id + bank, part->id->len)) {
+				/*
+				 * Subtract default bank number since
+				 * JEDEC does not count banks from 0
+				 */
+				if (part->mfr_bank && part->mfr_bank -
+					bank != SPI_NOR_DEFAULT_MFR_BANK)
+					continue;
+
+				/*
+				 * Either we found a matching bank or we
+				 * implicitly assume the default bank is
+				 * intended if not specified otherwise
+				 */
 				nor->manufacturer = manufacturers[i];
 				return part;
 			}
@@ -2007,6 +2049,7 @@ static const struct flash_info *spi_nor_detect(struct spi_nor *nor)
 {
 	const struct flash_info *info;
 	u8 *id = nor->bouncebuf;
+	u8 bank;
 	int ret;
 
 	ret = spi_nor_read_id(nor, 0, 0, id, nor->reg_proto);
@@ -2015,13 +2058,21 @@ static const struct flash_info *spi_nor_detect(struct spi_nor *nor)
 		return ERR_PTR(ret);
 	}
 
+	ret = spi_nor_get_mfr_bank(id, &bank);
+	if (ret) {
+		dev_dbg(nor->dev,
+			"error %d getting JEDEC manufacturer bank\n", ret);
+		return ERR_PTR(ret);
+	}
+
+	info = spi_nor_match_id(nor, id, bank);
+
 	/* Cache the complete flash ID. */
-	nor->id = devm_kmemdup(nor->dev, id, SPI_NOR_MAX_ID_LEN, GFP_KERNEL);
+	nor->id = devm_kmemdup(nor->dev, id + bank,
+			       SPI_NOR_MAX_ID_LEN, GFP_KERNEL);
 	if (!nor->id)
 		return ERR_PTR(-ENOMEM);
 
-	info = spi_nor_match_id(nor, id);
-
 	/* Fallback to a generic flash described only by its SFDP data. */
 	if (!info) {
 		ret = spi_nor_check_sfdp_signature(nor);
@@ -3502,7 +3553,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
 	if (ret)
 		return ret;
 
-	dev_dbg(dev, "Manufacturer and device ID: %*phN\n",
+	dev_dbg(dev, "Manufacturer bank: %u, device ID: %*phN\n",
+		nor->info->mfr_bank ?
+			  nor->info->mfr_bank : SPI_NOR_DEFAULT_MFR_BANK,
 		SPI_NOR_MAX_ID_LEN, nor->id);
 
 	return 0;
diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h
index 1516b6d0dc37..5091d720eba6 100644
--- a/drivers/mtd/spi-nor/core.h
+++ b/drivers/mtd/spi-nor/core.h
@@ -9,7 +9,11 @@
 
 #include "sfdp.h"
 
-#define SPI_NOR_MAX_ID_LEN	6
+#define SPI_NOR_MAX_ID_LEN		6
+/* Account for up to 128 banks  */
+#define SPI_NOR_MAX_ID_READ_LEN		(SPI_NOR_MAX_ID_LEN + 128)
+#define SPI_NOR_DEFAULT_MFR_BANK	1
+#define SPI_NOR_CONTINUATION_CODE	0x7f
 /*
  * 256 bytes is a sane default for most older flashes. Newer flashes will
  * have the page size defined within their SFDP tables.
@@ -498,6 +502,8 @@ struct spi_nor_id {
  * @mfr_flags:      manufacturer private flags. Used in the manufacturer fixup
  *                  hooks to differentiate support between flashes of the same
  *                  manufacturer.
+ * @mfr_bank:       (optional) manufacturer ID bank as per JEDEC JEP106.
+ *                  Defaults to 1.
  * @otp_org:        flash's OTP organization.
  * @fixups:         part specific fixup hooks.
  */
@@ -535,6 +541,7 @@ struct flash_info {
 #define SPI_NOR_IO_MODE_EN_VOLATILE	BIT(1)
 
 	u8 mfr_flags;
+	u8 mfr_bank;
 
 	const struct spi_nor_otp_organization *otp;
 	const struct spi_nor_fixups *fixups;
@@ -613,6 +620,7 @@ void spi_nor_unlock_and_unprep(struct spi_nor *nor);
 int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor);
 int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor);
 int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor);
+int spi_nor_get_mfr_bank(u8 *id, u8 *bank);
 int spi_nor_read_id(struct spi_nor *nor, u8 naddr, u8 ndummy, u8 *id,
 		    enum spi_nor_protocol reg_proto);
 int spi_nor_read_sr(struct spi_nor *nor, u8 *sr);
diff --git a/drivers/mtd/spi-nor/debugfs.c b/drivers/mtd/spi-nor/debugfs.c
index fa6956144d2e..035f0cf97111 100644
--- a/drivers/mtd/spi-nor/debugfs.c
+++ b/drivers/mtd/spi-nor/debugfs.c
@@ -85,6 +85,8 @@ static int spi_nor_params_show(struct seq_file *s, void *data)
 
 	seq_printf(s, "name\t\t%s\n", info->name);
 	seq_printf(s, "id\t\t%*ph\n", SPI_NOR_MAX_ID_LEN, nor->id);
+	seq_printf(s, "mfr bank\t%u\n",
+		info->mfr_bank ? info->mfr_bank : SPI_NOR_DEFAULT_MFR_BANK);
 	string_get_size(params->size, 1, STRING_UNITS_2, buf, sizeof(buf));
 	seq_printf(s, "size\t\t%s\n", buf);
 	seq_printf(s, "write size\t%u\n", params->writesize);
diff --git a/drivers/mtd/spi-nor/sysfs.c b/drivers/mtd/spi-nor/sysfs.c
index 96064e4babf0..4b8bda191c73 100644
--- a/drivers/mtd/spi-nor/sysfs.c
+++ b/drivers/mtd/spi-nor/sysfs.c
@@ -42,10 +42,23 @@ static ssize_t jedec_id_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(jedec_id);
 
+static ssize_t jedec_mfr_bank_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct spi_mem *spimem = spi_get_drvdata(spi);
+	struct spi_nor *nor = spi_mem_get_drvdata(spimem);
+
+	return sysfs_emit(buf, "%u\n", nor->info->mfr_bank ?
+			  nor->info->mfr_bank : SPI_NOR_DEFAULT_MFR_BANK);
+}
+static DEVICE_ATTR_RO(jedec_mfr_bank);
+
 static struct attribute *spi_nor_sysfs_entries[] = {
 	&dev_attr_manufacturer.attr,
 	&dev_attr_partname.attr,
 	&dev_attr_jedec_id.attr,
+	&dev_attr_jedec_mfr_bank.attr,
 	NULL
 };
 
-- 
2.45.2




More information about the linux-mtd mailing list