Add an "oem spi-nor-init" fastboot command that probes the default SPI flash device, so its driver's probe() can run now if it hasn't already.
On some boards, the SPI flash device fails to come up at boot because it depends on a one-time, driver-external step that isn't available yet (e.g. something that must first be flashed by fastboot itself). Bringing it up later just needs that step redone before the device is probed. To do that redo without hardcoding any SoC-specific call into generic fastboot code, add a weak fastboot_oem_spi_nor_reinit() hook that runs immediately before the probe. The default implementation is a no-op; SoC-specific code may override it. This is useful on boards where the SPI flash device is not usable until fastboot has flashed something it depends on. It is intended to be used together with "oem set-block-target" once the device has been brought up. Signed-off-by: Vandhiadevan Karunamoorthy <[email protected]> --- drivers/fastboot/Kconfig | 11 +++++++++ drivers/fastboot/fb_command.c | 55 +++++++++++++++++++++++++++++++++++++++++++ include/fastboot.h | 13 ++++++++++ 3 files changed, 79 insertions(+) diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig index c7e0509eaad..bb8184f6fb3 100644 --- a/drivers/fastboot/Kconfig +++ b/drivers/fastboot/Kconfig @@ -236,6 +236,17 @@ config FASTBOOT_CMD_OEM_SET_BLOCK_TARGET CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME / CONFIG_FASTBOOT_FLASH_BLOCK_DEVICE_ID build-time defaults. +config FASTBOOT_CMD_OEM_SPI_NOR_INIT + bool "Enable the 'oem spi-nor-init' command" + depends on DM_SPI_FLASH + help + Add support for the "oem spi-nor-init" command from a client. This + probes the default SPI-NOR device, letting its driver's probe() + run now that a dependency it needs may have just been flashed. + Use together with "oem set-block-target" on boards where SPI-NOR + is not usable until after fastboot has flashed something it + depends on. + config FASTBOOT_GPT_NAME string "Target name for updating GPT" depends on (FASTBOOT_FLASH_MMC || FASTBOOT_FLASH_BLOCK) && EFI_PARTITION diff --git a/drivers/fastboot/fb_command.c b/drivers/fastboot/fb_command.c index a015669c43a..2d09b2e65e9 100644 --- a/drivers/fastboot/fb_command.c +++ b/drivers/fastboot/fb_command.c @@ -5,6 +5,7 @@ #include <command.h> #include <console.h> +#include <dm.h> #include <env.h> #include <fastboot.h> #include <fastboot-internal.h> @@ -13,6 +14,7 @@ #include <fb_nand.h> #include <fb_spi_flash.h> #include <part.h> +#include <spi.h> #include <stdlib.h> #include <vsprintf.h> #include <linux/printk.h> @@ -46,6 +48,7 @@ static void oem_bootbus(char *, char *); static void oem_console(char *, char *); static void oem_board(char *, char *); static void oem_set_block_target(char *, char *); +static void oem_spi_nor_init(char *, char *); static void run_ucmd(char *, char *); static void run_acmd(char *, char *); @@ -126,6 +129,11 @@ static const struct { .dispatch = CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_SET_BLOCK_TARGET, (oem_set_block_target), (NULL)) }, + [FASTBOOT_COMMAND_OEM_SPI_NOR_INIT] = { + .command = "oem spi-nor-init", + .dispatch = CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_SPI_NOR_INIT, + (oem_spi_nor_init), (NULL)) + }, [FASTBOOT_COMMAND_UCMD] = { .command = "UCmd", .dispatch = CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT, (run_ucmd), (NULL)) @@ -648,3 +656,50 @@ static void __maybe_unused oem_set_block_target(char *cmd_parameter, char *respo else fastboot_okay(NULL, response); } + +/** + * fastboot_oem_spi_nor_reinit() - Vendor hook for SPI-NOR re-init. + * + * This is a default weak implementation, which may be overridden in + * SoC-specific code. It runs before the default SPI-NOR device is probed, + * and can be used to redo any one-time, driver-external bring-up that the + * device's own probe() cannot repeat on its own. + * + * Return: 0 on success, or a negative error code. + */ +int __weak fastboot_oem_spi_nor_reinit(void) +{ + return 0; +} + +/** + * oem_spi_nor_init() - Execute the OEM spi-nor-init command + * + * @cmd_parameter: Pointer to command parameter + * @response: Pointer to fastboot response buffer + * + * Runs the SPI-NOR reinit hook, then probes the default SPI-NOR device. + * Useful when SPI-NOR is not usable until after fastboot has flashed + * something it depends on. + */ +static void __maybe_unused oem_spi_nor_init(char *cmd_parameter, char *response) +{ + const int bus = config_opt_enabled(CONFIG_DM_SPI_FLASH, CONFIG_SF_DEFAULT_BUS, 0); + const int cs = config_opt_enabled(CONFIG_DM_SPI_FLASH, CONFIG_SF_DEFAULT_CS, 0); + struct udevice *bus_dev, *new; + int ret; + + ret = fastboot_oem_spi_nor_reinit(); + if (ret) { + fastboot_fail("SPI-NOR vendor reinit failed", response); + return; + } + + ret = spi_get_bus_and_cs(bus, cs, &bus_dev, (struct spi_slave **)&new); + if (ret) { + fastboot_fail("failed to probe SPI-NOR", response); + return; + } + + fastboot_okay(NULL, response); +} diff --git a/include/fastboot.h b/include/fastboot.h index 13dcdf919bc..3d444e125d8 100644 --- a/include/fastboot.h +++ b/include/fastboot.h @@ -52,6 +52,7 @@ enum { FASTBOOT_COMMAND_OEM_CONSOLE, FASTBOOT_COMMAND_OEM_BOARD, FASTBOOT_COMMAND_OEM_SET_BLOCK_TARGET, + FASTBOOT_COMMAND_OEM_SPI_NOR_INIT, FASTBOOT_COMMAND_ACMD, FASTBOOT_COMMAND_UCMD, FASTBOOT_COMMAND_COUNT @@ -106,6 +107,18 @@ void fastboot_okay(const char *reason, char *response); */ int fastboot_set_reboot_flag(enum fastboot_reboot_reason reason); +/** + * fastboot_oem_spi_nor_reinit() - Vendor hook for SPI-NOR re-init + * + * Called by the "oem spi-nor-init" command before probing the default + * SPI-NOR device. The default implementation is a no-op; SoC-specific + * code may override it to redo any one-time, driver-external bring-up + * that the device's own probe() cannot repeat on its own. + * + * Return: 0 on success, or a negative error code. + */ +int fastboot_oem_spi_nor_reinit(void); + /** * fastboot_set_progress_callback() - set progress callback * -- 2.34.1
