[PATCH v3 01/15] mtd: spi-nor: core: add flag for doing optional SFDP parsing

From: Esben Haabendal
Date: Thu Jul 11 2024 - 09:00:55 EST


This is the first step in replacing the old deprecated mechanism for
initializing flash parameters and settings based on SFDP, with fallback to
static parameters from struct flash_info.

A dedicated SPI_NOR_TRY_SFDP flag is used to request this handling, where
as the deprecated mechanism relies on the setting of either of the
SPI_NOR_DUAL_READ, SPI_NOR_QUAD_READ, SPI_NOR_OCTAL_READ or
SPI_NOR_OCTAL_DTR_READ bits.

Compared to the deprecated mechanism, SPI_NOR_TRY_SFDP flags allow optional
SFDP parsing for flashes where the fallback does not include
dual/quad/octal read.

This kind of mechanism is needed for flashes that reuses flash id from old
non-SFDP flashes for newer flashes with SFDP, with different parameters and
settings required. Macronix is known to reuse flash ids for replacement
parts, so for those lines where the initial part did not have SFDP, this
mechanism is needed.

Signed-off-by: Esben Haabendal <esben@xxxxxxxxxx>
---
drivers/mtd/spi-nor/core.c | 49 ++++++++++++++--------------------------------
drivers/mtd/spi-nor/core.h | 35 ++++++++++++++++++++++++++++++++-
2 files changed, 49 insertions(+), 35 deletions(-)

diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index 3e1f1913536b..39b28700ce28 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -2717,11 +2717,10 @@ static void spi_nor_manufacturer_init_params(struct spi_nor *nor)

/**
* spi_nor_no_sfdp_init_params() - Initialize the flash's parameters and
- * settings based on nor->info->sfdp_flags. This method should be called only by
- * flashes that do not define SFDP tables. If the flash supports SFDP but the
- * information is wrong and the settings from this function can not be retrieved
- * by parsing SFDP, one should instead use the fixup hooks and update the wrong
- * bits.
+ * settings based on nor->info->sfdp_flags. This method is for flashes that do
+ * not define SFDP tables. If the flash supports SFDP but the information is
+ * wrong and the settings from this function can not be retrieved by parsing
+ * SFDP, one should instead use the fixup hooks and update the wrong bits.
* @nor: pointer to a 'struct spi_nor'.
*/
static void spi_nor_no_sfdp_init_params(struct spi_nor *nor)
@@ -2899,14 +2898,15 @@ static int spi_nor_late_init_params(struct spi_nor *nor)
}

/**
- * spi_nor_sfdp_init_params_deprecated() - Deprecated way of initializing flash
- * parameters and settings based on JESD216 SFDP standard.
+ * spi_nor_try_sfdp_init_params() - Try to initialize flash parameters and
+ * settings based on JESD216 SFDP standard, with fallback to pre-initialized
+ * flash parameters and settings if SFP parsing fails.
* @nor: pointer to a 'struct spi_nor'.
*
* The method has a roll-back mechanism: in case the SFDP parsing fails, the
* legacy flash parameters and settings will be restored.
*/
-static void spi_nor_sfdp_init_params_deprecated(struct spi_nor *nor)
+static void spi_nor_try_sfdp_init_params(struct spi_nor *nor)
{
struct spi_nor_flash_parameter sfdp_params;

@@ -2918,28 +2918,6 @@ static void spi_nor_sfdp_init_params_deprecated(struct spi_nor *nor)
}
}

-/**
- * spi_nor_init_params_deprecated() - Deprecated way of initializing flash
- * parameters and settings.
- * @nor: pointer to a 'struct spi_nor'.
- *
- * The method assumes that flash doesn't support SFDP so it initializes flash
- * parameters in spi_nor_no_sfdp_init_params() which later on can be overwritten
- * when parsing SFDP, if supported.
- */
-static void spi_nor_init_params_deprecated(struct spi_nor *nor)
-{
- spi_nor_no_sfdp_init_params(nor);
-
- spi_nor_manufacturer_init_params(nor);
-
- if (nor->info->no_sfdp_flags & (SPI_NOR_DUAL_READ |
- SPI_NOR_QUAD_READ |
- SPI_NOR_OCTAL_READ |
- SPI_NOR_OCTAL_DTR_READ))
- spi_nor_sfdp_init_params_deprecated(nor);
-}
-
/**
* spi_nor_init_default_params() - Default initialization of flash parameters
* and settings. Done for all flashes, regardless is they define SFDP tables
@@ -3046,13 +3024,16 @@ static int spi_nor_init_params(struct spi_nor *nor)
if (spi_nor_needs_sfdp(nor)) {
ret = spi_nor_parse_sfdp(nor);
if (ret) {
- dev_err(nor->dev, "BFPT parsing failed. Please consider using SPI_NOR_SKIP_SFDP when declaring the flash\n");
+ dev_err(nor->dev, "BFPT parsing failed. Please consider using SPI_NOR_SKIP_SFDP or SPI_NOR_TRY_SFDP when declaring the flash\n");
return ret;
}
- } else if (nor->info->no_sfdp_flags & SPI_NOR_SKIP_SFDP) {
- spi_nor_no_sfdp_init_params(nor);
} else {
- spi_nor_init_params_deprecated(nor);
+ spi_nor_no_sfdp_init_params(nor);
+ if (!(nor->info->no_sfdp_flags & SPI_NOR_SKIP_SFDP))
+ spi_nor_manufacturer_init_params(nor);
+
+ if (spi_nor_try_sfdp(nor))
+ spi_nor_try_sfdp_init_params(nor);
}

return spi_nor_late_init_params(nor);
diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h
index 442786685515..dfc81716e068 100644
--- a/drivers/mtd/spi-nor/core.h
+++ b/drivers/mtd/spi-nor/core.h
@@ -485,9 +485,12 @@ struct spi_nor_id {
*
* @no_sfdp_flags: flags that indicate support that can be discovered via SFDP.
* Used when SFDP tables are not defined in the flash. These
- * flags are used together with the SPI_NOR_SKIP_SFDP flag.
+ * flags are used together with the SPI_NOR_SKIP_SFDP or
+ * SPI_NOR_TRY_SFDP flag.
* SPI_NOR_SKIP_SFDP: skip parsing of SFDP tables.
* SECT_4K: SPINOR_OP_BE_4K works uniformly.
+ * SPI_NOR_TRY_SFDP: try parsing SFDP tables before using the
+ * parameters specified in this struct.
* SPI_NOR_DUAL_READ: flash supports Dual Read.
* SPI_NOR_QUAD_READ: flash supports Quad Read.
* SPI_NOR_OCTAL_READ: flash supports Octal Read.
@@ -535,6 +538,7 @@ struct flash_info {
u8 no_sfdp_flags;
#define SPI_NOR_SKIP_SFDP BIT(0)
#define SECT_4K BIT(1)
+#define SPI_NOR_TRY_SFDP BIT(2)
#define SPI_NOR_DUAL_READ BIT(3)
#define SPI_NOR_QUAD_READ BIT(4)
#define SPI_NOR_OCTAL_READ BIT(5)
@@ -706,6 +710,35 @@ static inline bool spi_nor_needs_sfdp(const struct spi_nor *nor)
return !nor->info->size;
}

+/**
+ * spi_nor_try_sfdp() - returns true if optional SFDP parsing should be tried
+ * for this flash, with fallback to static parameters and settings based on
+ * flash ID if SFDP parsing fails.
+ *
+ * Return: true if optional SFDP parsing should be tried
+ */
+static inline bool spi_nor_try_sfdp(const struct spi_nor *nor)
+{
+ if (nor->info->no_sfdp_flags & SPI_NOR_SKIP_SFDP)
+ return false;
+ if (nor->info->no_sfdp_flags & SPI_NOR_TRY_SFDP)
+ return true;
+
+ /* Deprecated/legacy way for triggering optional SFDP parsing.
+ * If one of the no_sfdp_flags indicating dual, quad or octal read is
+ * set, SFDP parsing will be tried.
+ * When all drivers have been converted to set SPI_NOR_TRY_SFDP where
+ * needed, this deprecated mechanism can be removed.
+ */
+ if (nor->info->no_sfdp_flags & (SPI_NOR_DUAL_READ |
+ SPI_NOR_QUAD_READ |
+ SPI_NOR_OCTAL_READ |
+ SPI_NOR_OCTAL_DTR_READ))
+ return true;
+
+ return false;
+}
+
#ifdef CONFIG_DEBUG_FS
void spi_nor_debugfs_register(struct spi_nor *nor);
void spi_nor_debugfs_shutdown(void);

--
2.45.2