public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
* [PATCH v4] spl: Add support for Device Firmware Upgrade (DFU) over PCIe
@ 2025-10-23  8:09 Hrushikesh Salunke
  2025-10-31 14:52 ` Mattijs Korpershoek
  2025-11-06  9:18 ` Mattijs Korpershoek
  0 siblings, 2 replies; 5+ messages in thread
From: Hrushikesh Salunke @ 2025-10-23  8:09 UTC (permalink / raw)
  To: trini, lukma, mkorpershoek, peng.fan, marek.vasut+renesas,
	anshuld, andre.przywara, xypron.glpk, ye.li, sjg, dario.binacchi,
	a-dutta, dinesh.maniyam
  Cc: u-boot, h-salunke, s-vadapalli, danishanwar

Introduces support for Device Firmware Upgrade (DFU) over PCIe in
U-Boot. Traditionally, the DFU protocol is used over USB, where a
device enters DFU mode and allows a host to upload firmware or binary
images directly via the USB interface. This is a widely adopted and
convenient method for updating firmware.

In the context of Texas Instruments (TI) SoCs, PCIe can be used as a
boot interface in a manner that differs from the conventional
"PCIe Boot" process, which typically refers to booting an OS or
firmware image from an NVMe SSD or other PCIe-attached storage devices.
Instead, TI SoCs can be configured as a PCIe Endpoint, allowing a
connected PCIe Root Complex (host) to transfer images directly into the
device’s memory over the PCIe bus for boot purposes. This mechanism is
analogous to DFU over USB, but leverages the high-speed PCIe link and
does not depend on traditional storage devices.

By extending the DFU framework in U-Boot to support PCIe, it will be
possible to flash images over PCIe. While this implementation is
motivated by TI SoC use cases, the framework is generic and can be
adopted by everyone for platforms that support PCIe Endpoint mode.
Platforms with hardware support for PCIe-based memory loading can use
this to implement PCIe as a boot mode, as well as to enable flashing
and recovery scenarios similar to DFU over USB.

In summary, enable support for:
- DFU-style flashing of firmware/images over PCIe, analogous to existing
USB DFU workflows
- PCIe as a boot mode where a host can load images directly into device
memory using DFU over PCIe

Signed-off-by: Hrushikesh Salunke <h-salunke@ti.com>
---
This patch is based on commit
4e4a9de31de  Merge branch 'next' of git://source.denx.de/u-boot-usb into next

Changes since v3
- Addressed feedback from Mattijs Korpershoek
- Renamed all Kconfig symbols to include SPL_ prefix to avoid potential
  naming clashes with future U-Boot proper DFU over PCIe implementation:
  * PCI_DFU_SPL_LOAD_FIT_ADDRESS -> SPL_PCI_DFU_LOAD_FIT_ADDRESS
  * PCI_DFU_BAR_SIZE -> SPL_PCI_DFU_BAR_SIZE
  * PCI_DFU_MAGIC_WORD -> SPL_PCI_DFU_MAGIC_WORD
  * PCI_DFU_VENDOR_ID -> SPL_PCI_DFU_VENDOR_ID
  * PCI_DFU_DEVICE_ID -> SPL_PCI_DFU_DEVICE_ID
  * PCI_DFU_BOOT_PHASE -> SPL_PCI_DFU_BOOT_PHASE
- Changed strncpy to strlcpy for safer string copying
- Fixed boot phase string length check to enforce 63 character max as
  documented in Kconfig
- Improved error message clarity for boot phase string length validation
- Removed verbose debug print statements from normal operation

v3 : https://patchwork.ozlabs.org/project/uboot/patch/20250619071841.1265364-1-h-salunke@ti.com/

 common/spl/Kconfig   | 62 ++++++++++++++++++++++++++++++
 common/spl/spl_dfu.c | 91 ++++++++++++++++++++++++++++++++++++++++++++
 common/spl/spl_ram.c | 18 +++++++++
 drivers/Makefile     |  1 +
 4 files changed, 172 insertions(+)

diff --git a/common/spl/Kconfig b/common/spl/Kconfig
index f34b96efc02..86464c17799 100644
--- a/common/spl/Kconfig
+++ b/common/spl/Kconfig
@@ -1278,6 +1278,14 @@ config SPL_PCI
 	  necessary driver support. This enables the drivers in drivers/pci
 	  as part of an SPL build.
 
+config SPL_PCI_ENDPOINT
+	bool "Support for PCI endpoint drivers"
+	help
+	   Enable this configuration option to support configurable PCI
+	   endpoints at SPL. This should be enabled if the platform has
+	   a PCI controllers that can operate in endpoint mode (as a device
+	   connected to PCI host or bridge).
+
 config SPL_PCH
 	bool "Support PCH drivers"
 	help
@@ -1338,6 +1346,60 @@ config SPL_RAM_DEVICE
 	  be already in memory when SPL takes over, e.g. loaded by the boot
 	  ROM.
 
+config SPL_PCI_DFU
+	bool "PCIe boot support"
+	depends on SPL_PCI_ENDPOINT
+	help
+	  This config enables support to download bootloaders over PCIe
+	  when device is acting as an PCI endpoint.
+
+if SPL_PCI_DFU
+
+config SPL_PCI_DFU_SPL_LOAD_FIT_ADDRESS
+	hex "Address to load FIT image when booting via DFU over PCIe"
+	help
+	  Specify the load address of the fit image that will be loaded
+	  by SPL via DFU over PCIe.
+
+config SPL_PCI_DFU_BAR_SIZE
+	hex "BAR size to advertise for PCIe DFU"
+	default 0x800000
+	help
+	  This config sets the size of BAR to be advertised to the Root
+	  Complex. The size should be large enough to fit the FIT image
+	  being downloaded via DFU over PCIe.
+
+config SPL_PCI_DFU_MAGIC_WORD
+	hex "Completion magic word for PCIe DFU boot"
+	default 0xdeadbeef
+	help
+	  Specify the magic word which will be written to a specific
+	  address to signal the completion of transfer of FIT image
+	  when using DFU over PCIe to download the image. Size of magic
+	  word should be 32-bit.
+
+config SPL_PCI_DFU_VENDOR_ID
+	hex "PCI Vendor ID for PCI endpoint"
+	help
+	  PCI Vendor ID for endpoint device for DFU over PCIe. This should
+	  be set to your assigned 16-bit PCI Vendor ID.
+
+config SPL_PCI_DFU_DEVICE_ID
+	hex "PCI Vendor ID for PCI endpoint"
+	help
+	  A 16-bit PCI Vendor ID for endpoint device for DFU over PCIe.
+
+config SPL_PCI_DFU_BOOT_PHASE
+	string "Current boot phase for PCI DFU boot"
+	help
+	  Specify the current boot phase when booting via DFU over PCIe.
+	  This value can be read by the root complex to determine the
+	  current boot phase. Value of this config is written to memory
+	  location (BAR_start + PCI_DFU_BAR_SIZE - 70). Max size of this
+	  config is 63 bytes.
+
+endif
+
 config SPL_REMOTEPROC
 	bool "Support REMOTEPROCS"
 	default y if (CPU_V7R && ARCH_K3)
diff --git a/common/spl/spl_dfu.c b/common/spl/spl_dfu.c
index e9f381c392c..b09f82790c9 100644
--- a/common/spl/spl_dfu.c
+++ b/common/spl/spl_dfu.c
@@ -15,6 +15,17 @@
 #include <usb.h>
 #include <dfu.h>
 #include <linux/printk.h>
+#include <pci_ep.h>
+#include <dm/uclass.h>
+#include <cpu_func.h>
+#include <linux/io.h>
+
+/*
+ * Macros define size of magic word and boot phase string
+ * in bytes.
+ */
+#define MAGIC_WORD_SIZE 4
+#define BOOT_PHASE_STRING_SIZE 63
 
 static int run_dfu(int usb_index, char *interface, char *devstring)
 {
@@ -32,11 +43,91 @@ exit:
 	return ret;
 }
 
+#ifdef CONFIG_SPL_PCI_DFU
+static int dfu_over_pcie(void)
+{
+	u32 offset, magic_word;
+	volatile void *addr;
+	struct udevice *dev;
+	struct pci_bar bar;
+	struct pci_ep_header hdr;
+	uint fn = 0;
+	int ret;
+	char *bootphase;
+
+	uclass_get_device_by_seq(UCLASS_PCI_EP, 0, &dev);
+	if (!dev) {
+		pr_err("Failed to get pci ep device\n");
+		return -ENODEV;
+	}
+
+	hdr.deviceid = CONFIG_SPL_PCI_DFU_DEVICE_ID;
+	hdr.vendorid = CONFIG_SPL_PCI_DFU_VENDOR_ID;
+	hdr.baseclass_code = PCI_BASE_CLASS_MEMORY;
+	hdr.subclass_code = PCI_CLASS_MEMORY_RAM;
+
+	ret = pci_ep_write_header(dev, fn, &hdr);
+	if (ret) {
+		pr_err("Failed to write header: %d\n", ret);
+		return ret;
+	}
+
+	bar.barno = BAR_0;
+	bar.phys_addr = (dma_addr_t)CONFIG_SPL_PCI_DFU_SPL_LOAD_FIT_ADDRESS;
+	bar.flags = PCI_BASE_ADDRESS_SPACE_MEMORY |
+			  PCI_BASE_ADDRESS_MEM_TYPE_32 |
+			  PCI_BASE_ADDRESS_MEM_PREFETCH;
+
+	bar.size = CONFIG_SPL_PCI_DFU_BAR_SIZE;
+
+	ret = pci_ep_set_bar(dev, fn, &bar);
+	if (ret) {
+		pr_err("Failed to set bar: %d\n", ret);
+		return ret;
+	}
+
+	ret = pci_ep_start(dev);
+	if (ret) {
+		pr_err("Failed to start ep: %d\n", ret);
+		return ret;
+	}
+
+	addr = (void *)CONFIG_SPL_PCI_DFU_SPL_LOAD_FIT_ADDRESS;
+	offset = CONFIG_SPL_PCI_DFU_BAR_SIZE - MAGIC_WORD_SIZE;
+
+	if (sizeof(CONFIG_SPL_PCI_DFU_BOOT_PHASE) > BOOT_PHASE_STRING_SIZE) {
+		pr_err("Not copying boot phase. String too long\n");
+	} else {
+		bootphase = (char *)(addr + CONFIG_SPL_PCI_DFU_BAR_SIZE -
+				  (BOOT_PHASE_STRING_SIZE + MAGIC_WORD_SIZE + 1));
+		strlcpy(bootphase, CONFIG_SPL_PCI_DFU_BOOT_PHASE,
+			sizeof(CONFIG_SPL_PCI_DFU_BOOT_PHASE) + 1);
+	}
+
+	addr = addr + offset;
+	magic_word = CONFIG_SPL_PCI_DFU_MAGIC_WORD;
+	(*(int *)addr) = 0;
+	flush_dcache_all();
+	for (;;) {
+		if (*(int *)addr == magic_word)
+			break;
+		invalidate_dcache_all();
+	}
+
+	return 0;
+}
+#endif
+
 int spl_dfu_cmd(int usbctrl, char *dfu_alt_info, char *interface, char *devstr)
 {
 	char *str_env;
 	int ret;
 
+#ifdef CONFIG_SPL_PCI_DFU
+	if (spl_boot_device() == BOOT_DEVICE_PCIE)
+		return dfu_over_pcie();
+#endif
+
 	/* set default environment */
 	env_set_default(NULL, 0);
 	str_env = env_get(dfu_alt_info);
diff --git a/common/spl/spl_ram.c b/common/spl/spl_ram.c
index 71b7a8374bb..0c501cf02f2 100644
--- a/common/spl/spl_ram.c
+++ b/common/spl/spl_ram.c
@@ -27,6 +27,11 @@ static ulong spl_ram_load_read(struct spl_load_info *load, ulong sector,
 	if (IS_ENABLED(CONFIG_SPL_LOAD_FIT)) {
 		addr = IF_ENABLED_INT(CONFIG_SPL_LOAD_FIT,
 				      CONFIG_SPL_LOAD_FIT_ADDRESS);
+
+#ifdef	CONFIG_SPL_PCI_DFU
+		if (spl_boot_device() == BOOT_DEVICE_PCIE)
+			addr = CONFIG_SPL_PCI_DFU_SPL_LOAD_FIT_ADDRESS;
+#endif
 	}
 	addr += sector;
 	if (CONFIG_IS_ENABLED(IMAGE_PRE_LOAD))
@@ -47,6 +52,11 @@ static int spl_ram_load_image(struct spl_image_info *spl_image,
 	if (IS_ENABLED(CONFIG_SPL_LOAD_FIT)) {
 		addr = IF_ENABLED_INT(CONFIG_SPL_LOAD_FIT,
 				      CONFIG_SPL_LOAD_FIT_ADDRESS);
+
+#ifdef CONFIG_SPL_PCI_DFU
+		if (spl_boot_device() == BOOT_DEVICE_PCIE)
+			addr = CONFIG_SPL_PCI_DFU_SPL_LOAD_FIT_ADDRESS;
+#endif
 	}
 
 	if (CONFIG_IS_ENABLED(IMAGE_PRE_LOAD)) {
@@ -64,6 +74,11 @@ static int spl_ram_load_image(struct spl_image_info *spl_image,
 		spl_dfu_cmd(0, "dfu_alt_info_ram", "ram", "0");
 #endif
 
+#if CONFIG_IS_ENABLED(PCI_DFU)
+	if (bootdev->boot_device == BOOT_DEVICE_PCIE)
+		spl_dfu_cmd(0, "dfu_alt_info_ram", "ram", "0");
+#endif
+
 	if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
 	    image_get_magic(header) == FDT_MAGIC) {
 		struct spl_load_info load;
@@ -102,3 +117,6 @@ SPL_LOAD_IMAGE_METHOD("RAM", 0, BOOT_DEVICE_RAM, spl_ram_load_image);
 #if CONFIG_IS_ENABLED(DFU)
 SPL_LOAD_IMAGE_METHOD("DFU", 0, BOOT_DEVICE_DFU, spl_ram_load_image);
 #endif
+#if CONFIG_IS_ENABLED(PCI_DFU)
+SPL_LOAD_IMAGE_METHOD("PCIE", 0, BOOT_DEVICE_PCIE, spl_ram_load_image);
+#endif
diff --git a/drivers/Makefile b/drivers/Makefile
index 7560008a842..77fc66eb8ba 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_MULTIPLEXER) += mux/
 obj-$(CONFIG_$(PHASE_)ETH) += net/
 obj-$(CONFIG_$(PHASE_)PCH) += pch/
 obj-$(CONFIG_$(PHASE_)PCI) += pci/
+obj-$(CONFIG_$(PHASE_)PCI_ENDPOINT) += pci_endpoint/
 obj-$(CONFIG_$(PHASE_)PHY) += phy/
 obj-$(CONFIG_$(PHASE_)PINCTRL) += pinctrl/
 obj-$(CONFIG_$(PHASE_)POWER) += power/
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH v4] spl: Add support for Device Firmware Upgrade (DFU) over PCIe
  2025-10-23  8:09 [PATCH v4] spl: Add support for Device Firmware Upgrade (DFU) over PCIe Hrushikesh Salunke
@ 2025-10-31 14:52 ` Mattijs Korpershoek
  2025-11-03  5:40   ` Hrushikesh Salunke
  2025-11-06  9:18 ` Mattijs Korpershoek
  1 sibling, 1 reply; 5+ messages in thread
From: Mattijs Korpershoek @ 2025-10-31 14:52 UTC (permalink / raw)
  To: Hrushikesh Salunke, trini, lukma, mkorpershoek, peng.fan,
	marek.vasut+renesas, anshuld, andre.przywara, xypron.glpk, ye.li,
	sjg, dario.binacchi, a-dutta, dinesh.maniyam
  Cc: u-boot, h-salunke, s-vadapalli, danishanwar

Hi Hrushikesh,

Thank you for the patch.

v4 is in good shape already. I have a couple of small remarks below.
Please have a look.

On Thu, Oct 23, 2025 at 13:39, Hrushikesh Salunke <h-salunke@ti.com> wrote:

> Introduces support for Device Firmware Upgrade (DFU) over PCIe in
> U-Boot. Traditionally, the DFU protocol is used over USB, where a
> device enters DFU mode and allows a host to upload firmware or binary
> images directly via the USB interface. This is a widely adopted and
> convenient method for updating firmware.
>
> In the context of Texas Instruments (TI) SoCs, PCIe can be used as a
> boot interface in a manner that differs from the conventional
> "PCIe Boot" process, which typically refers to booting an OS or
> firmware image from an NVMe SSD or other PCIe-attached storage devices.
> Instead, TI SoCs can be configured as a PCIe Endpoint, allowing a
> connected PCIe Root Complex (host) to transfer images directly into the
> device’s memory over the PCIe bus for boot purposes. This mechanism is
> analogous to DFU over USB, but leverages the high-speed PCIe link and
> does not depend on traditional storage devices.
>
> By extending the DFU framework in U-Boot to support PCIe, it will be
> possible to flash images over PCIe. While this implementation is
> motivated by TI SoC use cases, the framework is generic and can be
> adopted by everyone for platforms that support PCIe Endpoint mode.
> Platforms with hardware support for PCIe-based memory loading can use
> this to implement PCIe as a boot mode, as well as to enable flashing
> and recovery scenarios similar to DFU over USB.
>
> In summary, enable support for:
> - DFU-style flashing of firmware/images over PCIe, analogous to existing
> USB DFU workflows
> - PCIe as a boot mode where a host can load images directly into device
> memory using DFU over PCIe
>
> Signed-off-by: Hrushikesh Salunke <h-salunke@ti.com>
> ---
> This patch is based on commit
> 4e4a9de31de  Merge branch 'next' of git://source.denx.de/u-boot-usb into next
>
> Changes since v3
> - Addressed feedback from Mattijs Korpershoek
> - Renamed all Kconfig symbols to include SPL_ prefix to avoid potential
>   naming clashes with future U-Boot proper DFU over PCIe implementation:
>   * PCI_DFU_SPL_LOAD_FIT_ADDRESS -> SPL_PCI_DFU_LOAD_FIT_ADDRESS
>   * PCI_DFU_BAR_SIZE -> SPL_PCI_DFU_BAR_SIZE
>   * PCI_DFU_MAGIC_WORD -> SPL_PCI_DFU_MAGIC_WORD
>   * PCI_DFU_VENDOR_ID -> SPL_PCI_DFU_VENDOR_ID
>   * PCI_DFU_DEVICE_ID -> SPL_PCI_DFU_DEVICE_ID
>   * PCI_DFU_BOOT_PHASE -> SPL_PCI_DFU_BOOT_PHASE
> - Changed strncpy to strlcpy for safer string copying
> - Fixed boot phase string length check to enforce 63 character max as
>   documented in Kconfig
> - Improved error message clarity for boot phase string length validation
> - Removed verbose debug print statements from normal operation
>
> v3 : https://patchwork.ozlabs.org/project/uboot/patch/20250619071841.1265364-1-h-salunke@ti.com/
>
>  common/spl/Kconfig   | 62 ++++++++++++++++++++++++++++++
>  common/spl/spl_dfu.c | 91 ++++++++++++++++++++++++++++++++++++++++++++
>  common/spl/spl_ram.c | 18 +++++++++
>  drivers/Makefile     |  1 +
>  4 files changed, 172 insertions(+)
>
> diff --git a/common/spl/Kconfig b/common/spl/Kconfig
> index f34b96efc02..86464c17799 100644
> --- a/common/spl/Kconfig
> +++ b/common/spl/Kconfig
> @@ -1278,6 +1278,14 @@ config SPL_PCI
>  	  necessary driver support. This enables the drivers in drivers/pci
>  	  as part of an SPL build.
>  
> +config SPL_PCI_ENDPOINT
> +	bool "Support for PCI endpoint drivers"
> +	help
> +	   Enable this configuration option to support configurable PCI
> +	   endpoints at SPL. This should be enabled if the platform has
> +	   a PCI controllers that can operate in endpoint mode (as a device
> +	   connected to PCI host or bridge).
> +
>  config SPL_PCH
>  	bool "Support PCH drivers"
>  	help
> @@ -1338,6 +1346,60 @@ config SPL_RAM_DEVICE
>  	  be already in memory when SPL takes over, e.g. loaded by the boot
>  	  ROM.
>  
> +config SPL_PCI_DFU
> +	bool "PCIe boot support"
> +	depends on SPL_PCI_ENDPOINT
> +	help
> +	  This config enables support to download bootloaders over PCIe
> +	  when device is acting as an PCI endpoint.
> +
> +if SPL_PCI_DFU
> +
> +config SPL_PCI_DFU_SPL_LOAD_FIT_ADDRESS
> +	hex "Address to load FIT image when booting via DFU over PCIe"
> +	help
> +	  Specify the load address of the fit image that will be loaded
> +	  by SPL via DFU over PCIe.
> +
> +config SPL_PCI_DFU_BAR_SIZE
> +	hex "BAR size to advertise for PCIe DFU"
> +	default 0x800000
> +	help
> +	  This config sets the size of BAR to be advertised to the Root
> +	  Complex. The size should be large enough to fit the FIT image
> +	  being downloaded via DFU over PCIe.
> +
> +config SPL_PCI_DFU_MAGIC_WORD
> +	hex "Completion magic word for PCIe DFU boot"
> +	default 0xdeadbeef
> +	help
> +	  Specify the magic word which will be written to a specific
> +	  address to signal the completion of transfer of FIT image
> +	  when using DFU over PCIe to download the image. Size of magic
> +	  word should be 32-bit.
> +
> +config SPL_PCI_DFU_VENDOR_ID
> +	hex "PCI Vendor ID for PCI endpoint"
> +	help
> +	  PCI Vendor ID for endpoint device for DFU over PCIe. This should
> +	  be set to your assigned 16-bit PCI Vendor ID.
> +
> +config SPL_PCI_DFU_DEVICE_ID
> +	hex "PCI Vendor ID for PCI endpoint"
> +	help
> +	  A 16-bit PCI Vendor ID for endpoint device for DFU over PCIe.
> +
> +config SPL_PCI_DFU_BOOT_PHASE
> +	string "Current boot phase for PCI DFU boot"
> +	help
> +	  Specify the current boot phase when booting via DFU over PCIe.
> +	  This value can be read by the root complex to determine the
> +	  current boot phase. Value of this config is written to memory
> +	  location (BAR_start + PCI_DFU_BAR_SIZE - 70). Max size of this
> +	  config is 63 bytes.
> +
> +endif
> +
>  config SPL_REMOTEPROC
>  	bool "Support REMOTEPROCS"
>  	default y if (CPU_V7R && ARCH_K3)
> diff --git a/common/spl/spl_dfu.c b/common/spl/spl_dfu.c
> index e9f381c392c..b09f82790c9 100644
> --- a/common/spl/spl_dfu.c
> +++ b/common/spl/spl_dfu.c
> @@ -15,6 +15,17 @@
>  #include <usb.h>
>  #include <dfu.h>
>  #include <linux/printk.h>
> +#include <pci_ep.h>
> +#include <dm/uclass.h>
> +#include <cpu_func.h>
> +#include <linux/io.h>
> +
> +/*
> + * Macros define size of magic word and boot phase string
> + * in bytes.
> + */
> +#define MAGIC_WORD_SIZE 4
> +#define BOOT_PHASE_STRING_SIZE 63
>  
>  static int run_dfu(int usb_index, char *interface, char *devstring)
>  {
> @@ -32,11 +43,91 @@ exit:
>  	return ret;
>  }
>  
> +#ifdef CONFIG_SPL_PCI_DFU
> +static int dfu_over_pcie(void)
> +{
> +	u32 offset, magic_word;
> +	volatile void *addr;
> +	struct udevice *dev;
> +	struct pci_bar bar;
> +	struct pci_ep_header hdr;
> +	uint fn = 0;
> +	int ret;
> +	char *bootphase;
> +
> +	uclass_get_device_by_seq(UCLASS_PCI_EP, 0, &dev);
> +	if (!dev) {
> +		pr_err("Failed to get pci ep device\n");
> +		return -ENODEV;
> +	}
> +
> +	hdr.deviceid = CONFIG_SPL_PCI_DFU_DEVICE_ID;
> +	hdr.vendorid = CONFIG_SPL_PCI_DFU_VENDOR_ID;
> +	hdr.baseclass_code = PCI_BASE_CLASS_MEMORY;
> +	hdr.subclass_code = PCI_CLASS_MEMORY_RAM;
> +
> +	ret = pci_ep_write_header(dev, fn, &hdr);
> +	if (ret) {
> +		pr_err("Failed to write header: %d\n", ret);
> +		return ret;
> +	}
> +
> +	bar.barno = BAR_0;
> +	bar.phys_addr = (dma_addr_t)CONFIG_SPL_PCI_DFU_SPL_LOAD_FIT_ADDRESS;
> +	bar.flags = PCI_BASE_ADDRESS_SPACE_MEMORY |
> +			  PCI_BASE_ADDRESS_MEM_TYPE_32 |
> +			  PCI_BASE_ADDRESS_MEM_PREFETCH;
> +
> +	bar.size = CONFIG_SPL_PCI_DFU_BAR_SIZE;
> +
> +	ret = pci_ep_set_bar(dev, fn, &bar);
> +	if (ret) {
> +		pr_err("Failed to set bar: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = pci_ep_start(dev);
> +	if (ret) {
> +		pr_err("Failed to start ep: %d\n", ret);
> +		return ret;
> +	}
> +
> +	addr = (void *)CONFIG_SPL_PCI_DFU_SPL_LOAD_FIT_ADDRESS;
> +	offset = CONFIG_SPL_PCI_DFU_BAR_SIZE - MAGIC_WORD_SIZE;
> +
> +	if (sizeof(CONFIG_SPL_PCI_DFU_BOOT_PHASE) > BOOT_PHASE_STRING_SIZE) {
> +		pr_err("Not copying boot phase. String too long\n");
> +	} else {
> +		bootphase = (char *)(addr + CONFIG_SPL_PCI_DFU_BAR_SIZE -
> +				  (BOOT_PHASE_STRING_SIZE + MAGIC_WORD_SIZE + 1));
> +		strlcpy(bootphase, CONFIG_SPL_PCI_DFU_BOOT_PHASE,
> +			sizeof(CONFIG_SPL_PCI_DFU_BOOT_PHASE) + 1);
> +	}
> +
> +	addr = addr + offset;
> +	magic_word = CONFIG_SPL_PCI_DFU_MAGIC_WORD;
> +	(*(int *)addr) = 0;
> +	flush_dcache_all();
> +	for (;;) {
> +		if (*(int *)addr == magic_word)
> +			break;
> +		invalidate_dcache_all();
> +	}
> +
> +	return 0;
> +}
> +#endif
> +
>  int spl_dfu_cmd(int usbctrl, char *dfu_alt_info, char *interface, char *devstr)
>  {
>  	char *str_env;
>  	int ret;
>  
> +#ifdef CONFIG_SPL_PCI_DFU
> +	if (spl_boot_device() == BOOT_DEVICE_PCIE)
> +		return dfu_over_pcie();
> +#endif
> +
>  	/* set default environment */
>  	env_set_default(NULL, 0);
>  	str_env = env_get(dfu_alt_info);
> diff --git a/common/spl/spl_ram.c b/common/spl/spl_ram.c
> index 71b7a8374bb..0c501cf02f2 100644
> --- a/common/spl/spl_ram.c
> +++ b/common/spl/spl_ram.c
> @@ -27,6 +27,11 @@ static ulong spl_ram_load_read(struct spl_load_info *load, ulong sector,
>  	if (IS_ENABLED(CONFIG_SPL_LOAD_FIT)) {
>  		addr = IF_ENABLED_INT(CONFIG_SPL_LOAD_FIT,
>  				      CONFIG_SPL_LOAD_FIT_ADDRESS);
> +
> +#ifdef	CONFIG_SPL_PCI_DFU
> +		if (spl_boot_device() == BOOT_DEVICE_PCIE)
> +			addr = CONFIG_SPL_PCI_DFU_SPL_LOAD_FIT_ADDRESS;
> +#endif

Can't we rewrite this using IF_ENABLED_INT() similarly to what has been
done for CONFIG_SPL_LOAD_FIT_ADDRESS ?

This should allow us to get rid of the #ifdef CONFIG_SPL_PCI_DFU part.

>  	}
>  	addr += sector;
>  	if (CONFIG_IS_ENABLED(IMAGE_PRE_LOAD))
> @@ -47,6 +52,11 @@ static int spl_ram_load_image(struct spl_image_info *spl_image,
>  	if (IS_ENABLED(CONFIG_SPL_LOAD_FIT)) {
>  		addr = IF_ENABLED_INT(CONFIG_SPL_LOAD_FIT,
>  				      CONFIG_SPL_LOAD_FIT_ADDRESS);
> +
> +#ifdef CONFIG_SPL_PCI_DFU
> +		if (spl_boot_device() == BOOT_DEVICE_PCIE)
> +			addr = CONFIG_SPL_PCI_DFU_SPL_LOAD_FIT_ADDRESS;
> +#endif

Same here

>  	}
>  
>  	if (CONFIG_IS_ENABLED(IMAGE_PRE_LOAD)) {
> @@ -64,6 +74,11 @@ static int spl_ram_load_image(struct spl_image_info *spl_image,
>  		spl_dfu_cmd(0, "dfu_alt_info_ram", "ram", "0");
>  #endif
>  
> +#if CONFIG_IS_ENABLED(PCI_DFU)
> +	if (bootdev->boot_device == BOOT_DEVICE_PCIE)
> +		spl_dfu_cmd(0, "dfu_alt_info_ram", "ram", "0");
> +#endif
> +

Same here. Please rewrite using if (IS_ENABLED(CONFIG_SPL_PCI_DFU)).
This way we are consistent with the rest of the file.

>  	if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
>  	    image_get_magic(header) == FDT_MAGIC) {
>  		struct spl_load_info load;
> @@ -102,3 +117,6 @@ SPL_LOAD_IMAGE_METHOD("RAM", 0, BOOT_DEVICE_RAM, spl_ram_load_image);
>  #if CONFIG_IS_ENABLED(DFU)
>  SPL_LOAD_IMAGE_METHOD("DFU", 0, BOOT_DEVICE_DFU, spl_ram_load_image);
>  #endif
> +#if CONFIG_IS_ENABLED(PCI_DFU)
> +SPL_LOAD_IMAGE_METHOD("PCIE", 0, BOOT_DEVICE_PCIE, spl_ram_load_image);
> +#endif
> diff --git a/drivers/Makefile b/drivers/Makefile
> index 7560008a842..77fc66eb8ba 100644
> --- a/drivers/Makefile
> +++ b/drivers/Makefile
> @@ -26,6 +26,7 @@ obj-$(CONFIG_MULTIPLEXER) += mux/
>  obj-$(CONFIG_$(PHASE_)ETH) += net/
>  obj-$(CONFIG_$(PHASE_)PCH) += pch/
>  obj-$(CONFIG_$(PHASE_)PCI) += pci/
> +obj-$(CONFIG_$(PHASE_)PCI_ENDPOINT) += pci_endpoint/
>  obj-$(CONFIG_$(PHASE_)PHY) += phy/
>  obj-$(CONFIG_$(PHASE_)PINCTRL) += pinctrl/
>  obj-$(CONFIG_$(PHASE_)POWER) += power/
> -- 
> 2.34.1

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v4] spl: Add support for Device Firmware Upgrade (DFU) over PCIe
  2025-10-31 14:52 ` Mattijs Korpershoek
@ 2025-11-03  5:40   ` Hrushikesh Salunke
  2025-11-06  9:11     ` Mattijs Korpershoek
  0 siblings, 1 reply; 5+ messages in thread
From: Hrushikesh Salunke @ 2025-11-03  5:40 UTC (permalink / raw)
  To: Mattijs Korpershoek, trini, lukma, peng.fan, marek.vasut+renesas,
	anshuld, andre.przywara, xypron.glpk, ye.li, sjg, dario.binacchi,
	a-dutta, dinesh.maniyam
  Cc: u-boot, s-vadapalli, danishanwar



On 31/10/25 20:22, Mattijs Korpershoek wrote:
> Hi Hrushikesh,
> 
> Thank you for the patch.
> 
> v4 is in good shape already. I have a couple of small remarks below.
> Please have a look.
> 
> On Thu, Oct 23, 2025 at 13:39, Hrushikesh Salunke <h-salunke@ti.com> wrote:
> 
>> Introduces support for Device Firmware Upgrade (DFU) over PCIe in
>> U-Boot. Traditionally, the DFU protocol is used over USB, where a

[...]

>>   
>> +#ifdef CONFIG_SPL_PCI_DFU
>> +	if (spl_boot_device() == BOOT_DEVICE_PCIE)
>> +		return dfu_over_pcie();
>> +#endif
>> +
>>   	/* set default environment */
>>   	env_set_default(NULL, 0);
>>   	str_env = env_get(dfu_alt_info);
>> diff --git a/common/spl/spl_ram.c b/common/spl/spl_ram.c
>> index 71b7a8374bb..0c501cf02f2 100644
>> --- a/common/spl/spl_ram.c
>> +++ b/common/spl/spl_ram.c
>> @@ -27,6 +27,11 @@ static ulong spl_ram_load_read(struct spl_load_info *load, ulong sector,
>>   	if (IS_ENABLED(CONFIG_SPL_LOAD_FIT)) {
>>   		addr = IF_ENABLED_INT(CONFIG_SPL_LOAD_FIT,
>>   				      CONFIG_SPL_LOAD_FIT_ADDRESS);
>> +
>> +#ifdef	CONFIG_SPL_PCI_DFU
>> +		if (spl_boot_device() == BOOT_DEVICE_PCIE)
>> +			addr = CONFIG_SPL_PCI_DFU_SPL_LOAD_FIT_ADDRESS;
>> +#endif
> 
> Can't we rewrite this using IF_ENABLED_INT() similarly to what has been
> done for CONFIG_SPL_LOAD_FIT_ADDRESS ?
> 
> This should allow us to get rid of the #ifdef CONFIG_SPL_PCI_DFU part.
> 
>>   	}
>>   	addr += sector;
>>   	if (CONFIG_IS_ENABLED(IMAGE_PRE_LOAD))
>> @@ -47,6 +52,11 @@ static int spl_ram_load_image(struct spl_image_info *spl_image,
>>   	if (IS_ENABLED(CONFIG_SPL_LOAD_FIT)) {
>>   		addr = IF_ENABLED_INT(CONFIG_SPL_LOAD_FIT,
>>   				      CONFIG_SPL_LOAD_FIT_ADDRESS);
>> +
>> +#ifdef CONFIG_SPL_PCI_DFU
>> +		if (spl_boot_device() == BOOT_DEVICE_PCIE)
>> +			addr = CONFIG_SPL_PCI_DFU_SPL_LOAD_FIT_ADDRESS;
>> +#endif
> 
> Same here
> 
>>   	}
>>   
>>   	if (CONFIG_IS_ENABLED(IMAGE_PRE_LOAD)) {
>> @@ -64,6 +74,11 @@ static int spl_ram_load_image(struct spl_image_info *spl_image,
>>   		spl_dfu_cmd(0, "dfu_alt_info_ram", "ram", "0");
>>   #endif
>>   
>> +#if CONFIG_IS_ENABLED(PCI_DFU)
>> +	if (bootdev->boot_device == BOOT_DEVICE_PCIE)
>> +		spl_dfu_cmd(0, "dfu_alt_info_ram", "ram", "0");
>> +#endif
>> +
> 
> Same here. Please rewrite using if (IS_ENABLED(CONFIG_SPL_PCI_DFU)).
> This way we are consistent with the rest of the file.
> 


Thank you for the feedback. However, using IS_ENABLED() instead of
#ifdef in these locations causes compilation errors on platforms where
BOOT_DEVICE_PCIE is not defined. The BOOT_DEVICE_PCIE macro is only
defined in platform-specific headers, and is not available universally
across all architectures. With IS_ENABLED(CONFIG_SPL_PCI_DFU), the code
inside the conditional is still visible to the compiler even when the
config is disabled. This means the compiler will try to evaluate
BOOT_DEVICE_PCIE on platforms where it doesn't exist, resulting in a
compilation error like:

error: 'BOOT_DEVICE_PCIE' undeclared

The #ifdef CONFIG_SPL_PCI_DFU approach ensures that the code referencing
BOOT_DEVICE_PCIE is completely removed during preprocessing on platforms
that don't support PCIe DFU, preventing the compilation error. This is
similar to how other boot device checks are handled in U-Boot when the
boot device macro may not be universally defined across all platforms.

Regards,
Hrushikesh.



>>   	if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
>>   	    image_get_magic(header) == FDT_MAGIC) {
>>   		struct spl_load_info load;
>> @@ -102,3 +117,6 @@ SPL_LOAD_IMAGE_METHOD("RAM", 0, BOOT_DEVICE_RAM, spl_ram_load_image);
>>   #if CONFIG_IS_ENABLED(DFU)
>>   SPL_LOAD_IMAGE_METHOD("DFU", 0, BOOT_DEVICE_DFU, spl_ram_load_image);
>>   #endif
>> +#if CONFIG_IS_ENABLED(PCI_DFU)
>> +SPL_LOAD_IMAGE_METHOD("PCIE", 0, BOOT_DEVICE_PCIE, spl_ram_load_image);
>> +#endif
>> diff --git a/drivers/Makefile b/drivers/Makefile
>> index 7560008a842..77fc66eb8ba 100644
>> --- a/drivers/Makefile
>> +++ b/drivers/Makefile
>> @@ -26,6 +26,7 @@ obj-$(CONFIG_MULTIPLEXER) += mux/
>>   obj-$(CONFIG_$(PHASE_)ETH) += net/
>>   obj-$(CONFIG_$(PHASE_)PCH) += pch/
>>   obj-$(CONFIG_$(PHASE_)PCI) += pci/
>> +obj-$(CONFIG_$(PHASE_)PCI_ENDPOINT) += pci_endpoint/
>>   obj-$(CONFIG_$(PHASE_)PHY) += phy/
>>   obj-$(CONFIG_$(PHASE_)PINCTRL) += pinctrl/
>>   obj-$(CONFIG_$(PHASE_)POWER) += power/
>> -- 
>> 2.34.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v4] spl: Add support for Device Firmware Upgrade (DFU) over PCIe
  2025-11-03  5:40   ` Hrushikesh Salunke
@ 2025-11-06  9:11     ` Mattijs Korpershoek
  0 siblings, 0 replies; 5+ messages in thread
From: Mattijs Korpershoek @ 2025-11-06  9:11 UTC (permalink / raw)
  To: Hrushikesh Salunke, Mattijs Korpershoek, trini, lukma, peng.fan,
	marek.vasut+renesas, anshuld, andre.przywara, xypron.glpk, ye.li,
	sjg, dario.binacchi, a-dutta, dinesh.maniyam
  Cc: u-boot, s-vadapalli, danishanwar

Hi Hrushikesh,

On Mon, Nov 03, 2025 at 11:10, Hrushikesh Salunke <h-salunke@ti.com> wrote:

> On 31/10/25 20:22, Mattijs Korpershoek wrote:
>> Hi Hrushikesh,
>> 
>> Thank you for the patch.
>> 
>> v4 is in good shape already. I have a couple of small remarks below.
>> Please have a look.
>> 
>> On Thu, Oct 23, 2025 at 13:39, Hrushikesh Salunke <h-salunke@ti.com> wrote:
>> 
>>> Introduces support for Device Firmware Upgrade (DFU) over PCIe in
>>> U-Boot. Traditionally, the DFU protocol is used over USB, where a
>
> [...]
>
>>>   
>>> +#ifdef CONFIG_SPL_PCI_DFU
>>> +	if (spl_boot_device() == BOOT_DEVICE_PCIE)
>>> +		return dfu_over_pcie();
>>> +#endif
>>> +
>>>   	/* set default environment */
>>>   	env_set_default(NULL, 0);
>>>   	str_env = env_get(dfu_alt_info);
>>> diff --git a/common/spl/spl_ram.c b/common/spl/spl_ram.c
>>> index 71b7a8374bb..0c501cf02f2 100644
>>> --- a/common/spl/spl_ram.c
>>> +++ b/common/spl/spl_ram.c
>>> @@ -27,6 +27,11 @@ static ulong spl_ram_load_read(struct spl_load_info *load, ulong sector,
>>>   	if (IS_ENABLED(CONFIG_SPL_LOAD_FIT)) {
>>>   		addr = IF_ENABLED_INT(CONFIG_SPL_LOAD_FIT,
>>>   				      CONFIG_SPL_LOAD_FIT_ADDRESS);
>>> +
>>> +#ifdef	CONFIG_SPL_PCI_DFU
>>> +		if (spl_boot_device() == BOOT_DEVICE_PCIE)
>>> +			addr = CONFIG_SPL_PCI_DFU_SPL_LOAD_FIT_ADDRESS;
>>> +#endif
>> 
>> Can't we rewrite this using IF_ENABLED_INT() similarly to what has been
>> done for CONFIG_SPL_LOAD_FIT_ADDRESS ?
>> 
>> This should allow us to get rid of the #ifdef CONFIG_SPL_PCI_DFU part.
>> 
>>>   	}
>>>   	addr += sector;
>>>   	if (CONFIG_IS_ENABLED(IMAGE_PRE_LOAD))
>>> @@ -47,6 +52,11 @@ static int spl_ram_load_image(struct spl_image_info *spl_image,
>>>   	if (IS_ENABLED(CONFIG_SPL_LOAD_FIT)) {
>>>   		addr = IF_ENABLED_INT(CONFIG_SPL_LOAD_FIT,
>>>   				      CONFIG_SPL_LOAD_FIT_ADDRESS);
>>> +
>>> +#ifdef CONFIG_SPL_PCI_DFU
>>> +		if (spl_boot_device() == BOOT_DEVICE_PCIE)
>>> +			addr = CONFIG_SPL_PCI_DFU_SPL_LOAD_FIT_ADDRESS;
>>> +#endif
>> 
>> Same here
>> 
>>>   	}
>>>   
>>>   	if (CONFIG_IS_ENABLED(IMAGE_PRE_LOAD)) {
>>> @@ -64,6 +74,11 @@ static int spl_ram_load_image(struct spl_image_info *spl_image,
>>>   		spl_dfu_cmd(0, "dfu_alt_info_ram", "ram", "0");
>>>   #endif
>>>   
>>> +#if CONFIG_IS_ENABLED(PCI_DFU)
>>> +	if (bootdev->boot_device == BOOT_DEVICE_PCIE)
>>> +		spl_dfu_cmd(0, "dfu_alt_info_ram", "ram", "0");
>>> +#endif
>>> +
>> 
>> Same here. Please rewrite using if (IS_ENABLED(CONFIG_SPL_PCI_DFU)).
>> This way we are consistent with the rest of the file.
>> 
>
>
> Thank you for the feedback. However, using IS_ENABLED() instead of
> #ifdef in these locations causes compilation errors on platforms where
> BOOT_DEVICE_PCIE is not defined. The BOOT_DEVICE_PCIE macro is only
> defined in platform-specific headers, and is not available universally
> across all architectures. With IS_ENABLED(CONFIG_SPL_PCI_DFU), the code
> inside the conditional is still visible to the compiler even when the
> config is disabled. This means the compiler will try to evaluate
> BOOT_DEVICE_PCIE on platforms where it doesn't exist, resulting in a
> compilation error like:
>
> error: 'BOOT_DEVICE_PCIE' undeclared

I see. Sorry I missed that.

Reviewed-by: Mattijs Korpershoek <mkorpershoek@kernel.org>

I'll pick this up shortly to try to make it for v2026.01

>
> The #ifdef CONFIG_SPL_PCI_DFU approach ensures that the code referencing
> BOOT_DEVICE_PCIE is completely removed during preprocessing on platforms
> that don't support PCIe DFU, preventing the compilation error. This is
> similar to how other boot device checks are handled in U-Boot when the
> boot device macro may not be universally defined across all platforms.
>
> Regards,
> Hrushikesh.
>
>
>
>>>   	if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
>>>   	    image_get_magic(header) == FDT_MAGIC) {
>>>   		struct spl_load_info load;
>>> @@ -102,3 +117,6 @@ SPL_LOAD_IMAGE_METHOD("RAM", 0, BOOT_DEVICE_RAM, spl_ram_load_image);
>>>   #if CONFIG_IS_ENABLED(DFU)
>>>   SPL_LOAD_IMAGE_METHOD("DFU", 0, BOOT_DEVICE_DFU, spl_ram_load_image);
>>>   #endif
>>> +#if CONFIG_IS_ENABLED(PCI_DFU)
>>> +SPL_LOAD_IMAGE_METHOD("PCIE", 0, BOOT_DEVICE_PCIE, spl_ram_load_image);
>>> +#endif
>>> diff --git a/drivers/Makefile b/drivers/Makefile
>>> index 7560008a842..77fc66eb8ba 100644
>>> --- a/drivers/Makefile
>>> +++ b/drivers/Makefile
>>> @@ -26,6 +26,7 @@ obj-$(CONFIG_MULTIPLEXER) += mux/
>>>   obj-$(CONFIG_$(PHASE_)ETH) += net/
>>>   obj-$(CONFIG_$(PHASE_)PCH) += pch/
>>>   obj-$(CONFIG_$(PHASE_)PCI) += pci/
>>> +obj-$(CONFIG_$(PHASE_)PCI_ENDPOINT) += pci_endpoint/
>>>   obj-$(CONFIG_$(PHASE_)PHY) += phy/
>>>   obj-$(CONFIG_$(PHASE_)PINCTRL) += pinctrl/
>>>   obj-$(CONFIG_$(PHASE_)POWER) += power/
>>> -- 
>>> 2.34.1

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v4] spl: Add support for Device Firmware Upgrade (DFU) over PCIe
  2025-10-23  8:09 [PATCH v4] spl: Add support for Device Firmware Upgrade (DFU) over PCIe Hrushikesh Salunke
  2025-10-31 14:52 ` Mattijs Korpershoek
@ 2025-11-06  9:18 ` Mattijs Korpershoek
  1 sibling, 0 replies; 5+ messages in thread
From: Mattijs Korpershoek @ 2025-11-06  9:18 UTC (permalink / raw)
  To: trini, lukma, peng.fan, marek.vasut+renesas, anshuld,
	andre.przywara, xypron.glpk, ye.li, sjg, dario.binacchi, a-dutta,
	dinesh.maniyam, Hrushikesh Salunke
  Cc: u-boot, s-vadapalli, danishanwar

Hi,

On Thu, 23 Oct 2025 13:39:22 +0530, Hrushikesh Salunke wrote:
> Introduces support for Device Firmware Upgrade (DFU) over PCIe in
> U-Boot. Traditionally, the DFU protocol is used over USB, where a
> device enters DFU mode and allows a host to upload firmware or binary
> images directly via the USB interface. This is a widely adopted and
> convenient method for updating firmware.
> 
> In the context of Texas Instruments (TI) SoCs, PCIe can be used as a
> boot interface in a manner that differs from the conventional
> "PCIe Boot" process, which typically refers to booting an OS or
> firmware image from an NVMe SSD or other PCIe-attached storage devices.
> Instead, TI SoCs can be configured as a PCIe Endpoint, allowing a
> connected PCIe Root Complex (host) to transfer images directly into the
> device’s memory over the PCIe bus for boot purposes. This mechanism is
> analogous to DFU over USB, but leverages the high-speed PCIe link and
> does not depend on traditional storage devices.
> 
> [...]

Thanks, Applied to https://source.denx.de/u-boot/custodians/u-boot-dfu (u-boot-dfu)

[1/1] spl: Add support for Device Firmware Upgrade (DFU) over PCIe
      https://source.denx.de/u-boot/custodians/u-boot-dfu/-/commit/cde77583cf0b54dd572a38acd159ded7dd5e3e86

--
Mattijs

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2025-11-06  9:18 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-23  8:09 [PATCH v4] spl: Add support for Device Firmware Upgrade (DFU) over PCIe Hrushikesh Salunke
2025-10-31 14:52 ` Mattijs Korpershoek
2025-11-03  5:40   ` Hrushikesh Salunke
2025-11-06  9:11     ` Mattijs Korpershoek
2025-11-06  9:18 ` Mattijs Korpershoek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox