Hi Guillaume,

On 9/18/2026 9:55 PM, Guillaume La Roque wrote:
Hi ,

Thanks for clarification,

Le 17/09/2026 à 19:01, Vandhiadevan Karunamoorthy a écrit :
Hi Guillaume,

On 9/17/2026 5:59 PM, Guillaume La Roque wrote:
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 ?

This patch is not intended to add SPI-NOR support itself. I have a separate change that exposes SPI-NOR through the MTD Fastboot backend.

The purpose of this patch is to allow switching the generic block Fastboot backend between different storage interfaces at runtime. On some platforms multiple Fastboot-capable storage devices can coexist, for example a default SCSI/UFS device and an SPI-NOR device exposed through the MTD block uclass.

to not create a new command it's possible to just use fastboot_raw_partition_*[1] variable extend it to support spi or block fastboot support , actually only missing part is to parse this variable properly to  know in which FASTBOOT_FLASH_XXX use it.

or an other solution will be to extend series on flash[2] command to give possibility to select block device/interface to flash on flash command : for example fastboot flash mtd:0 bootloader XXX

you do a lot of patch to add some new oem command on fastboot not sure it's always the good solution for all , just my opinion .

finally you do this jsut because fastboot not work properly when you enable multiple FASTBOOT_FLASH_XXX Config.

[1] : https://docs.u-boot.org/en/latest/android/fastboot.html#raw-partition-descriptors

[2] : https://lore.kernel.org/u-boot/[email protected]/


Regards,
Guillaume

Thanks for the review and the suggestions.
> to not create a new command it's possible to just use
> fastboot_raw_partition_*[1] variable extend it to support spi or
> block fastboot support
I had initially considered that direction. One challenge I ran into is
that the current raw partition descriptor only describes an offset/size
within a device, but it does not provide a way to identify which
interface/device owns the partition when multiple Fastboot backends are
enabled.
That said, your feedback led me to reconsider the overall approach, and
the latest revision no longer uses the "oem set-block-target" command.
> or an other solution will be to extend series on flash[2] command
> to give possibility to select block device/interface to flash on
> flash command : for example fastboot flash mtd:0 bootloader XXX
I agree with this idea. The current revision follows that direction by
encoding the interface/device information in the partition argument
itself, e.g.:
fastboot flash mtd:0:bootloader <image>
This allows the request to be routed to the appropriate
FASTBOOT_FLASH_* backend without introducing additional Fastboot state
or requiring a separate target-selection command.
> you do a lot of patch to add some new oem command on fastboot not
> sure it's always the good solution for all , just my opinion .
That's a fair comment. I agree that OEM commands should be avoided when
the functionality can fit naturally into the existing Fastboot flow.
For this reason, the "oem set-block-target" command from the earlier
revision has been removed in favor of the inline partition syntax.
> finally you do this just because fastboot not work properly when
> you enable multiple FASTBOOT_FLASH_XXX Config.
Yes, that's the underlying motivation. With multiple
FASTBOOT_FLASH_* backends enabled, a partition name alone is no longer
sufficient to uniquely identify the intended target. The goal of this
series is to provide a generic way to disambiguate the target backend
and device while keeping the existing Fastboot workflow unchanged.
Thanks again for the feedback. It helped simplify the design
considerably.
Regards,
Vandhiadevan


Today the block backend is selected through the build-time
CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME and
CONFIG_FASTBOOT_FLASH_BLOCK_DEVICE_ID settings, so only a single target
can be accessed during a Fastboot session. The OEM command allows
changing the active interface/device at runtime and accessing either
storage device without rebuilding or restarting Fastboot.

SPI-NOR was mentioned only as an example use case for a runtime-selected
target rather than as a replacement for existing Fastboot SPI/MTD
support.
Thanks,
Vandhiadevan
``


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