[RFC PATCH 0/5] Implement exiting 4-byte adressing mode before reset

This fixes the issue with 4-byte adressing mode being left enabled on board reset. That is an issue on Qualcomm IPQ4019 boards since the CPU expects flash to be in 3-byte adressing mode and will just hang otherwise.
Note that this does not fix a case where you remove the power while U-Boot is still running and in that case it will still be stuck in 4-byte mode.
Robert Marko (5): dm: core: add on_reset method dm: core: introduce uclass_id_on_reset() mtd: spi-nor: rename and export 4-byte adressing mode function mtd: spi: sf: implement .on_reset method sysreset: call .on_reset for UCLASS_SPI_FLASH before reset request
drivers/core/uclass.c | 13 +++++++++++++ drivers/mtd/spi/sf_probe.c | 10 ++++++++++ drivers/mtd/spi/spi-nor-core.c | 7 +++---- drivers/sysreset/sysreset-uclass.c | 7 +++++++ include/dm/device.h | 2 ++ include/dm/uclass.h | 8 ++++++++ include/linux/mtd/spi-nor.h | 10 ++++++++++ 7 files changed, 53 insertions(+), 4 deletions(-)

Currently, we dont have a specific method that is intented to be called right before calling board reset.
Intention for this method is to be able to exit 4-byte adressing mode on SPI-NOR devices before reset.
Signed-off-by: Robert Marko robert.marko@sartura.hr --- include/dm/device.h | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/include/dm/device.h b/include/dm/device.h index add67f9ec0..19713d958c 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -344,6 +344,7 @@ struct udevice_id { * @probe: Called to probe a device, i.e. activate it * @remove: Called to remove a device, i.e. de-activate it * @unbind: Called to unbind a device from its driver + * @on_reset: Called befora calling board reset * @of_to_plat: Called before probe to decode device tree data * @child_post_bind: Called after a new child has been bound * @child_pre_probe: Called before a child device is probed. The device has @@ -379,6 +380,7 @@ struct driver { int (*probe)(struct udevice *dev); int (*remove)(struct udevice *dev); int (*unbind)(struct udevice *dev); + int (*on_reset)(struct udevice *dev); int (*of_to_plat)(struct udevice *dev); int (*child_post_bind)(struct udevice *dev); int (*child_pre_probe)(struct udevice *dev);

Implement a helper to call .on_reset method for every device in a certain uclass.
Intention is to use this helper for UCLASS_SPI_FLASH before board reset to exit 4-byte adressing mode.
Signed-off-by: Robert Marko robert.marko@sartura.hr --- drivers/core/uclass.c | 13 +++++++++++++ include/dm/uclass.h | 8 ++++++++ 2 files changed, 21 insertions(+)
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index e46d5717aa..bed5553d5e 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -831,6 +831,19 @@ int uclass_id_count(enum uclass_id id) return count; }
+int uclass_id_on_reset(enum uclass_id id) +{ + struct udevice *dev; + struct uclass *uc; + + uclass_id_foreach_dev(id, dev, uc) { + if (dev->driver->on_reset) + return dev->driver->on_reset(dev); + } + + return 0; +} + UCLASS_DRIVER(nop) = { .id = UCLASS_NOP, .name = "nop", diff --git a/include/dm/uclass.h b/include/dm/uclass.h index 456eef7f2f..57eb1b144f 100644 --- a/include/dm/uclass.h +++ b/include/dm/uclass.h @@ -454,6 +454,14 @@ int uclass_probe_all(enum uclass_id id); */ int uclass_id_count(enum uclass_id id);
+/** + * uclass_id_on_reset() - call on_reset for devices of a given uclass ID + * + * @id: uclass ID to look up + * Return: 0 if OK, other -ve on error + */ +int uclass_id_on_reset(enum uclass_id id); + /** * uclass_id_foreach_dev() - iterate through devices of a given uclass ID *

Currently 4-byte adressing mode function is not exported, but since we plan to use it outside of the SPI NOR core we need to export it.
While we are here, rename it to align the naming with the rest of exported functions.
Signed-off-by: Robert Marko robert.marko@sartura.hr --- drivers/mtd/spi/spi-nor-core.c | 7 +++---- include/linux/mtd/spi-nor.h | 10 ++++++++++ 2 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 8882b045ce..8a64ee40c3 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -682,8 +682,7 @@ static void spi_nor_set_4byte_opcodes(struct spi_nor *nor, #endif /* !CONFIG_SPI_FLASH_BAR */
/* Enable/disable 4-byte addressing mode. */ -static int set_4byte(struct spi_nor *nor, const struct flash_info *info, - int enable) +int spi_nor_set_4byte(struct spi_nor *nor, const struct flash_info *info, int enable) { int status; bool need_wren = false; @@ -3481,7 +3480,7 @@ static int s25_s28_post_bfpt_fixup(struct spi_nor *nor, */ if (params->size > SZ_128M) { if (bfpt->dwords[BFPT_DWORD(16)] & BFPT_DWORD16_EX4B_PWRCYC) { - ret = set_4byte(nor, nor->info, 1); + ret = spi_nor_set_4byte(nor, nor->info, 1); if (ret) return ret; } @@ -3915,7 +3914,7 @@ static int spi_nor_init(struct spi_nor *nor) */ if (nor->flags & SNOR_F_BROKEN_RESET) debug("enabling reset hack; may not recover from unexpected reboots\n"); - set_4byte(nor, nor->info, 1); + spi_nor_set_4byte(nor, nor->info, 1); }
return 0; diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 80e56cf308..94c0e5e98f 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -646,6 +646,16 @@ static inline int spi_nor_remove(struct spi_nor *nor) * Return: 0 for success, -errno for failure. */ int spi_nor_remove(struct spi_nor *nor); + +/** + * spi_nor_set_4byte() - perform cleanup before booting to the next stage + * @nor: the spi_nor structure + * @flash_info: the flash_info structure + * @enable: enable or disable 4byte mode + * + * Return: 0 for success, -errno for failure. + */ +int spi_nor_set_4byte(struct spi_nor *nor, const struct flash_info *info, int enable); #endif
#endif

Implement .on_reset method for SPI flash, by extending the remove method to exit 4-byte adressing mode in case it was entered before.
This fixes the issue with 4-byte adressing mode being left enabled on board reset. That is an issue on Qualcomm IPQ4019 boards since the CPU expects flash to be in 3-byte adressing mode and will just hang otherwise.
Note that this does not fix a case where you remove the power while U-Boot is still running and in that case it will still be stuck in 4-byte mode.
Signed-off-by: Robert Marko robert.marko@sartura.hr --- drivers/mtd/spi/sf_probe.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index de6516f106..31dae17ba0 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -225,6 +225,15 @@ static int spi_flash_std_remove(struct udevice *dev) struct spi_flash *flash = dev_get_uclass_priv(dev); int ret;
+ if (flash->addr_width == 4 && + !(flash->info->flags & SPI_NOR_OCTAL_DTR_READ) && + (JEDEC_MFR(flash->info) != SNOR_MFR_SPANSION) && + !(flash->flags & SNOR_F_4B_OPCODES)) { + ret = spi_nor_set_4byte(flash, flash->info, 0); + if (ret) + return ret; + } + if (CONFIG_IS_ENABLED(SPI_DIRMAP)) { spi_mem_dirmap_destroy(flash->dirmap.wdesc); spi_mem_dirmap_destroy(flash->dirmap.rdesc); @@ -258,6 +267,7 @@ U_BOOT_DRIVER(jedec_spi_nor) = { .of_match = spi_flash_std_ids, .probe = spi_flash_std_probe, .remove = spi_flash_std_remove, + .on_reset = spi_flash_std_remove, .priv_auto = sizeof(struct spi_nor), .ops = &spi_flash_std_ops, .flags = DM_FLAG_OS_PREPARE,

Call .on_reset method for UCLASS_SPI_FLASH devices before requesting reset.
This fixes the issue with 4-byte adressing mode being left enabled on board reset. That is an issue on Qualcomm IPQ4019 boards since the CPU expects flash to be in 3-byte adressing mode and will just hang otherwise.
Note that this does not fix a case where you remove the power while U-Boot is still running and in that case it will still be stuck in 4-byte mode.
Signed-off-by: Robert Marko robert.marko@sartura.hr --- drivers/sysreset/sysreset-uclass.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/drivers/sysreset/sysreset-uclass.c b/drivers/sysreset/sysreset-uclass.c index 6151b5fe03..8321cc4230 100644 --- a/drivers/sysreset/sysreset-uclass.c +++ b/drivers/sysreset/sysreset-uclass.c @@ -30,6 +30,13 @@ int sysreset_request(struct udevice *dev, enum sysreset_t type) if (!ops->request) return -ENOSYS;
+ /* + * Call the .on_reset op for SPI flash devices. + * This is required for most devices in order to exit the + * 4-byte adressing mode. + */ + uclass_id_on_reset(UCLASS_SPI_FLASH); + return ops->request(dev, type); }
participants (1)
-
Robert Marko