The S25FS512S chip datasheet rev.O Table 71 on page 153 JEDEC Sector Map Parameter Dword-6 Config. Detect-3 does use CR3NV bit 1 to discern 64kiB and 256kiB uniform sectors device configuration, however according to section 7.5.5.1 Configuration Register 3 Non-volatile (CR3NV) page 61, the CR3NV bit 1 is RFU Reserved for Future Use, and is set to 0 on newly manufactured devices, which means 64kiB sectors. Since the device does not support 64kiB uniform sectors in any configuration, parsing SMPT table cannot find a valid sector map entry and fails. Fix this up by setting SMPT configuration index bit 0, which is populated exactly by the CR3NV bit 1 being 1. This is implemented via new .post_smpt fixup hook and a wrapper function. The only implementation of the hook is currently specific to S25FS512S. This fixes the following failure on S25FS512S: spi-nor spi0.0: Failed to parse optional parameter table: ff81 (err=-22) Signed-off-by: Marek Vasut <marek.vasut+renesas@xxxxxxxxxxx> --- Cc: Geert Uytterhoeven <geert+renesas@xxxxxxxxx> Cc: Michael Walle <mwalle@xxxxxxxxxx> Cc: Miquel Raynal <miquel.raynal@xxxxxxxxxxx> Cc: Pratyush Yadav <pratyush@xxxxxxxxxx> Cc: Richard Weinberger <richard@xxxxxx> Cc: Tudor Ambarus <tudor.ambarus@xxxxxxxxxx> Cc: Vignesh Raghavendra <vigneshr@xxxxxx> Cc: linux-mtd@xxxxxxxxxxxxxxxxxxx Cc: linux-renesas-soc@xxxxxxxxxxxxxxx --- drivers/mtd/spi-nor/core.c | 17 +++++++++++++++++ drivers/mtd/spi-nor/core.h | 5 +++++ drivers/mtd/spi-nor/sfdp.c | 4 ++++ drivers/mtd/spi-nor/spansion.c | 27 ++++++++++++++++++++++++++- 4 files changed, 52 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 9d6e85bf227b..ca65f36e5638 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -2405,6 +2405,23 @@ int spi_nor_post_bfpt_fixups(struct spi_nor *nor, return 0; } +int spi_nor_post_smpt_fixups(struct spi_nor *nor, u8 *smpt) +{ + int ret; + + if (nor->manufacturer && nor->manufacturer->fixups && + nor->manufacturer->fixups->post_smpt) { + ret = nor->manufacturer->fixups->post_smpt(nor, smpt); + if (ret) + return ret; + } + + if (nor->info->fixups && nor->info->fixups->post_smpt) + return nor->info->fixups->post_smpt(nor, smpt); + + return 0; +} + static int spi_nor_select_read(struct spi_nor *nor, u32 shared_hwcaps) { diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index 1516b6d0dc37..d5294424ab9d 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -413,6 +413,8 @@ struct spi_nor_flash_parameter { * parameters that could not be extracted by other means (i.e. * when information provided by the SFDP/flash_info tables are * incomplete or wrong). + * @post_smpt: update sector map configuration ID selector according to + * chip-specific quirks. * @late_init: used to initialize flash parameters that are not declared in the * JESD216 SFDP standard, or where SFDP tables not defined at all. * Will replace the default_init() hook. @@ -426,6 +428,7 @@ struct spi_nor_fixups { const struct sfdp_parameter_header *bfpt_header, const struct sfdp_bfpt *bfpt); int (*post_sfdp)(struct spi_nor *nor); + int (*post_smpt)(struct spi_nor *nor, u8 *smpt); int (*late_init)(struct spi_nor *nor); }; @@ -660,6 +663,8 @@ int spi_nor_post_bfpt_fixups(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, const struct sfdp_bfpt *bfpt); +int spi_nor_post_smpt_fixups(struct spi_nor *nor, u8 *stmp); + void spi_nor_init_default_locking_ops(struct spi_nor *nor); void spi_nor_try_unlock_all(struct spi_nor *nor); void spi_nor_set_mtd_locking_ops(struct spi_nor *nor); diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c index 5b1117265bd2..542c775918ad 100644 --- a/drivers/mtd/spi-nor/sfdp.c +++ b/drivers/mtd/spi-nor/sfdp.c @@ -765,6 +765,10 @@ static const u32 *spi_nor_get_map_in_use(struct spi_nor *nor, const u32 *smpt, map_id = map_id << 1 | !!(*buf & read_data_mask); } + err = spi_nor_post_smpt_fixups(nor, &map_id); + if (err) + return ERR_PTR(err); + /* * If command descriptors are provided, they always precede map * descriptors in the table. There is no need to start the iteration diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index d6c92595f6bc..d446d12371e1 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -757,6 +757,31 @@ static const struct spi_nor_fixups s25fs_s_nor_fixups = { .post_bfpt = s25fs_s_nor_post_bfpt_fixups, }; +static int s25fs512s_nor_post_smpt_fixups(struct spi_nor *nor, u8 *smpt) +{ + /* + * The S25FS512S chip datasheet rev.O Table 71 on page 153 + * JEDEC Sector Map Parameter Dword-6 Config. Detect-3 does + * use CR3NV bit 1 to discern 64kiB/256kiB uniform sectors + * device configuration, however according to section 7.5.5.1 + * Configuration Register 3 Non-volatile (CR3NV) page 61, the + * CR3NV bit 1 is RFU Reserved for Future Use, and is set to + * 0 on newly manufactured devices, which means 64kiB sectors. + * Since the device does not support 64kiB uniform sectors in + * any configuration, parsing SMPT table cannot find a valid + * sector map entry and fails. Fix this up by setting SMPT + * configuration index bit 0, which is populated exactly by + * the CR3NV bit 1 being 1. + */ + *smpt |= BIT(0); + return 0; +} + +static const struct spi_nor_fixups s25fs512s_nor_fixups = { + .post_bfpt = s25fs_s_nor_post_bfpt_fixups, + .post_smpt = s25fs512s_nor_post_smpt_fixups, +}; + static const struct flash_info spansion_nor_parts[] = { { .id = SNOR_ID(0x01, 0x02, 0x12), @@ -829,7 +854,7 @@ static const struct flash_info spansion_nor_parts[] = { .sector_size = SZ_256K, .no_sfdp_flags = SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, .mfr_flags = USE_CLSR, - .fixups = &s25fs_s_nor_fixups, + .fixups = &s25fs512s_nor_fixups, }, { .id = SNOR_ID(0x01, 0x20, 0x18, 0x03, 0x00), .name = "s25sl12800", -- 2.45.2