Hi,

Probably a stupid question but in your commit message you speak about SPI-NOR  but fastboot support flash spi , why not enable it or update it if it's not exactly work as you want instead of create a new command ?

Thanks
Guillaume

Le 17/09/2026 à 11:01, Vandhiadevan Karunamoorthy a écrit :
Add fastboot_block_set_target() so an OEM command can point the
generic block fastboot backend at a different interface/device at
runtime, without requiring a rebuild. Falls back to the existing
build-time CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME/
CONFIG_FASTBOOT_FLASH_BLOCK_DEVICE_ID defaults when no override is
set.

Expose this to fastboot clients via a new "oem set-block-target
<interface> [device]" command, gated behind
CONFIG_FASTBOOT_CMD_OEM_SET_BLOCK_TARGET (depends on
CONFIG_FASTBOOT_FLASH_BLOCK).

This is needed to target storage devices, such as SPI-NOR exposed
through the MTD block uclass, that aren't known until runtime or
that coexist with another default block interface on the same
board.

To: [email protected]
To: [email protected]
Cc: Mattijs Korpershoek <[email protected]>
Cc: Tom Rini <[email protected]>
Cc: Quentin Schulz <[email protected]>
Cc: Ilias Apalodimas <[email protected]>
Cc: Dmitrii Merkurev <[email protected]>
Cc: Balaji Selvanathan <[email protected]>
Cc: Adrian Freihofer <[email protected]>
Cc: Heiko Schocher <[email protected]>
Cc: Neil Armstrong <[email protected]>

Signed-off-by: Vandhiadevan Karunamoorthy 
<[email protected]>
---
This series lets a fastboot client redirect the generic block
fastboot backend (CONFIG_FASTBOOT_FLASH_BLOCK) to a different
interface/device at runtime, instead of being fixed to the
build-time CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME /
CONFIG_FASTBOOT_FLASH_BLOCK_DEVICE_ID defaults.

This is useful for storage devices that aren't known until runtime,
or that coexist with another default block interface on the same
board -- for example, SPI-NOR exposed through the MTD block uclass
(see the companion "mtd: spi: Expose SPI-NOR as a GPT-capable MTD
block device" series).

The patch adds fastboot_block_set_target() to the generic block
backend, plus a new "oem set-block-target <interface> [device]"
fastboot command (gated behind
CONFIG_FASTBOOT_CMD_OEM_SET_BLOCK_TARGET, which depends on
CONFIG_FASTBOOT_FLASH_BLOCK) that lets a client invoke it.
---
Depends on: [PATCH v6 0/8] arm: snapdragon: Add snagboot support for Lemans-EVK
Link: 
https://lore.kernel.org/u-boot/[email protected]/
Depends on: [PATCH v2 0/4] fastboot: block: Add GPT/MBR and device selection
Link: 
https://lore.kernel.org/u-boot/[email protected]/
---
  drivers/fastboot/Kconfig      | 11 +++++++
  drivers/fastboot/fb_block.c   | 75 ++++++++++++++++++++++++++++++++++++-------
  drivers/fastboot/fb_command.c | 51 +++++++++++++++++++++++++++++
  include/fastboot.h            |  1 +
  include/fb_block.h            |  9 ++++++
  5 files changed, 136 insertions(+), 11 deletions(-)

diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig
index a4539844d89..c7e0509eaad 100644
--- a/drivers/fastboot/Kconfig
+++ b/drivers/fastboot/Kconfig
@@ -225,6 +225,17 @@ config FASTBOOT_FLASH_BLOCK_DEVICE_ID
          Device identifiers are numbered starting from 0 and the most
          common case is to use the first controller on the system.
+config FASTBOOT_CMD_OEM_SET_BLOCK_TARGET
+       bool "Enable the 'oem set-block-target' command"
+       depends on FASTBOOT_FLASH_BLOCK
+       help
+         Add support for the "oem set-block-target" command from a client.
+         This allows switching the block interface (e.g. scsi, mtd) and
+         device number used by the fastboot "flash"/"erase" commands at
+         runtime, instead of relying solely on the
+         CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME /
+         CONFIG_FASTBOOT_FLASH_BLOCK_DEVICE_ID build-time defaults.
+
  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_block.c b/drivers/fastboot/fb_block.c
index a8c74e35d0d..d3e5f6ed1f3 100644
--- a/drivers/fastboot/fb_block.c
+++ b/drivers/fastboot/fb_block.c
@@ -125,6 +125,66 @@ static lbaint_t fb_block_sparse_reserve(struct 
sparse_storage *info,
        return blkcnt;
  }
+/**
+ * block_interface_override - runtime-set block interface name, empty if unset
+ */
+static char block_interface_override[16];
+/**
+ * block_device_override - runtime-set block device number, -1 if unset
+ */
+static int block_device_override = -1;
+
+/**
+ * fb_block_interface() - Resolve the block interface name to use
+ *
+ * Returns the runtime override set via fastboot_block_set_target() if one
+ * is active, otherwise falls back to the build-time config default.
+ */
+static const char *fb_block_interface(void)
+{
+       if (!IS_ENABLED(CONFIG_FASTBOOT_FLASH_BLOCK))
+               return NULL;
+
+       if (block_interface_override[0])
+               return block_interface_override;
+
+       return config_opt_enabled(CONFIG_FASTBOOT_FLASH_BLOCK,
+                                 CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME, 
NULL);
+}
+
+/**
+ * fb_block_device() - Resolve the block device number to use
+ *
+ * Returns the runtime override set via fastboot_block_set_target() if one
+ * is active, otherwise falls back to the build-time config default.
+ */
+static int fb_block_device(void)
+{
+       if (!IS_ENABLED(CONFIG_FASTBOOT_FLASH_BLOCK))
+               return -1;
+
+       if (block_device_override >= 0)
+               return block_device_override;
+
+       return config_opt_enabled(CONFIG_FASTBOOT_FLASH_BLOCK,
+                                 CONFIG_FASTBOOT_FLASH_BLOCK_DEVICE_ID, -1);
+}
+
+int fastboot_block_set_target(const char *interface, int device)
+{
+       if (interface) {
+               if (strlen(interface) >= sizeof(block_interface_override))
+                       return -EINVAL;
+               strlcpy(block_interface_override, interface,
+                       sizeof(block_interface_override));
+       }
+
+       if (device >= 0)
+               block_device_override = device;
+
+       return 0;
+}
+
  /**
   * parse_device_partition() - Parse and validate device:partition format
   * @part_name: Input string in format "N:partition" or "partition"
@@ -140,8 +200,7 @@ static int parse_device_partition(const char *part_name, 
int *device,
  {
        const char *colon_pos;
- *device = config_opt_enabled(CONFIG_FASTBOOT_FLASH_BLOCK,
-                                    CONFIG_FASTBOOT_FLASH_BLOCK_DEVICE_ID, -1);
+       *device = fb_block_device();
/* Check for colon in partition name */
        colon_pos = strchr(part_name, ':');
@@ -190,9 +249,7 @@ int fastboot_block_get_part_info(const char *part_name,
                                 char *response)
  {
        int ret;
-       const char *interface = config_opt_enabled(CONFIG_FASTBOOT_FLASH_BLOCK,
-                                                  
CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME,
-                                                  NULL);
+       const char *interface = fb_block_interface();
        int device;
        const char *partition_name;
@@ -385,9 +442,7 @@ void fastboot_block_flash_write(const char *part_name, void *download_buffer,
  #if CONFIG_IS_ENABLED(EFI_PARTITION)
        if (is_partition_table_name(part_name, CONFIG_FASTBOOT_GPT_NAME)) {
                int device;
-               const char *interface = 
config_opt_enabled(CONFIG_FASTBOOT_FLASH_BLOCK,
-                                                          
CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME,
-                                                          NULL);
+               const char *interface = fb_block_interface();
parse_device_partition(part_name, &device, NULL);
                fastboot_flash_gpt_partition_table(interface, device,
@@ -399,9 +454,7 @@ void fastboot_block_flash_write(const char *part_name, void 
*download_buffer,
  #if CONFIG_IS_ENABLED(DOS_PARTITION)
        if (is_partition_table_name(part_name, CONFIG_FASTBOOT_MBR_NAME)) {
                int device;
-               const char *interface = 
config_opt_enabled(CONFIG_FASTBOOT_FLASH_BLOCK,
-                                                          
CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME,
-                                                          NULL);
+               const char *interface = fb_block_interface();
parse_device_partition(part_name, &device, NULL);
                fastboot_flash_mbr_partition_table(interface, device,
diff --git a/drivers/fastboot/fb_command.c b/drivers/fastboot/fb_command.c
index 18d86988f4c..235fae74fee 100644
--- a/drivers/fastboot/fb_command.c
+++ b/drivers/fastboot/fb_command.c
@@ -45,6 +45,7 @@ static void oem_partconf(char *, char *);
  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 run_ucmd(char *, char *);
  static void run_acmd(char *, char *);
@@ -120,6 +121,11 @@ static const struct {
                .command = "oem board",
                .dispatch = CONFIG_IS_ENABLED(FASTBOOT_OEM_BOARD, (oem_board), 
(NULL))
        },
+       [FASTBOOT_COMMAND_OEM_SET_BLOCK_TARGET] = {
+               .command = "oem set-block-target",
+               .dispatch = CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_SET_BLOCK_TARGET,
+                                             (oem_set_block_target), (NULL))
+       },
        [FASTBOOT_COMMAND_UCMD] = {
                .command = "UCmd",
                .dispatch = CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT, (run_ucmd), 
(NULL))
@@ -589,3 +595,48 @@ static void __maybe_unused oem_board(char *cmd_parameter, 
char *response)
  {
        fastboot_oem_board(cmd_parameter, (void *)fastboot_buf_addr, 
image_size, response);
  }
+
+/**
+ * oem_set_block_target() - Execute the OEM set-block-target command
+ *
+ * @cmd_parameter: Pointer to "<interface> [device]" command parameter
+ * @response: Pointer to fastboot response buffer
+ *
+ * Switches the block interface (e.g. "scsi", "mtd") and, optionally,
+ * device number used by the fastboot block backend at runtime.
+ */
+static void __maybe_unused oem_set_block_target(char *cmd_parameter, char 
*response)
+{
+       char interface[16] = { 0 };
+       int device = -1;
+       char *space;
+
+       if (!cmd_parameter) {
+               fastboot_fail("Expected command parameter", response);
+               return;
+       }
+
+       space = strchr(cmd_parameter, ' ');
+       if (space) {
+               size_t len = space - cmd_parameter;
+
+               if (len >= sizeof(interface)) {
+                       fastboot_fail("interface name too long", response);
+                       return;
+               }
+               memcpy(interface, cmd_parameter, len);
+               interface[len] = '\0';
+               device = simple_strtoul(space + 1, NULL, 10);
+       } else {
+               if (strlen(cmd_parameter) >= sizeof(interface)) {
+                       fastboot_fail("interface name too long", response);
+                       return;
+               }
+               strlcpy(interface, cmd_parameter, sizeof(interface));
+       }
+
+       if (fastboot_block_set_target(interface, device))
+               fastboot_fail("invalid interface name", response);
+       else
+               fastboot_okay(NULL, response);
+}
diff --git a/include/fastboot.h b/include/fastboot.h
index b106d617749..13dcdf919bc 100644
--- a/include/fastboot.h
+++ b/include/fastboot.h
@@ -51,6 +51,7 @@ enum {
        FASTBOOT_COMMAND_OEM_RUN,
        FASTBOOT_COMMAND_OEM_CONSOLE,
        FASTBOOT_COMMAND_OEM_BOARD,
+       FASTBOOT_COMMAND_OEM_SET_BLOCK_TARGET,
        FASTBOOT_COMMAND_ACMD,
        FASTBOOT_COMMAND_UCMD,
        FASTBOOT_COMMAND_COUNT
diff --git a/include/fb_block.h b/include/fb_block.h
index 189c708e2f0..fd981d95316 100644
--- a/include/fb_block.h
+++ b/include/fb_block.h
@@ -102,4 +102,13 @@ void fastboot_block_write_sparse_image(struct blk_desc 
*dev_desc, struct disk_pa
  void fastboot_block_flash_write(const char *part_name, void *download_buffer,
                                u32 download_bytes, char *response);
+/**
+ * fastboot_block_set_target() - Override block interface/device at runtime
+ *
+ * @interface: New interface name (e.g. "scsi", "mtd"), or NULL to leave 
unchanged
+ * @device: New device number, or -1 to leave unchanged
+ * Return: 0 on success, -EINVAL if interface name too long
+ */
+int fastboot_block_set_target(const char *interface, int device);
+
  #endif // _FB_BLOCK_H_

---
base-commit: 4d3823469724bca19ba4ed3a5a38fc8e951775e2
change-id: 20260824-series2-fastboot-block-target-c8e9418babdf

Best regards,
--
Vandhiadevan Karunamoorthy <[email protected]>


Reply via email to