summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2025-11-07 08:56:22 -0600
committerTom Rini <[email protected]>2025-11-07 08:56:22 -0600
commit64b3478eb51d246a2790dce99fe0be330b9c2cc6 (patch)
treecc91a54d37906fc73c8f5b7ed3dfbdaf1a6389e5
parentdf786b4c57f582b4f875effe68d3ae22bbb478a9 (diff)
parent10da28729949f3e2160f98d82df45833d4c175cf (diff)
Merge tag 'u-boot-dfu-20251107' of https://source.denx.de/u-boot/custodians/u-boot-dfu
u-boot-dfu-20251107: CI: https://source.denx.de/u-boot/custodians/u-boot-dfu/-/pipelines/28223 Android: * Add bootargs environment to kernel commandline DFU: * Support DFU over PCIe in SPL
-rw-r--r--boot/bootmeth_android.c35
-rw-r--r--common/spl/Kconfig62
-rw-r--r--common/spl/spl_dfu.c91
-rw-r--r--common/spl/spl_ram.c18
-rw-r--r--drivers/Makefile1
5 files changed, 207 insertions, 0 deletions
diff --git a/boot/bootmeth_android.c b/boot/bootmeth_android.c
index 8c2bde10e17..1374551dbeb 100644
--- a/boot/bootmeth_android.c
+++ b/boot/bootmeth_android.c
@@ -512,6 +512,37 @@ static int run_avb_verification(struct bootflow *bflow)
}
#endif /* AVB_VERIFY */
+static int append_bootargs_to_cmdline(struct bootflow *bflow)
+{
+ char *bootargs;
+ int len = 0;
+
+ /*
+ * Check any additionnal bootargs coming from U-Boot env. If any,
+ * merge them with the current cmdline
+ */
+ bootargs = env_get("bootargs");
+ if (bootargs) {
+ len += strlen(bootargs) + 1; /* Extra space character needed */
+ len += strlen(bflow->cmdline);
+
+ char *newcmdline = malloc(len + 1); /* +1 for the '\0' */
+
+ if (!newcmdline)
+ return log_msg_ret("newcmdline malloc", -ENOMEM);
+
+ strcpy(newcmdline, bootargs);
+ strcat(newcmdline, " ");
+ strcat(newcmdline, bflow->cmdline);
+
+ /* Free the previous cmdline and replace it */
+ free(bflow->cmdline);
+ bflow->cmdline = newcmdline;
+ }
+
+ return 0;
+}
+
static int boot_android_normal(struct bootflow *bflow)
{
struct blk_desc *desc = dev_get_uclass_plat(bflow->blk);
@@ -546,6 +577,10 @@ static int boot_android_normal(struct bootflow *bflow)
if (priv->slot)
free(priv->slot);
+ ret = append_bootargs_to_cmdline(bflow);
+ if (ret < 0)
+ return log_msg_ret("bootargs append", ret);
+
ret = bootm_boot_start(loadaddr, bflow->cmdline);
return log_msg_ret("boot", ret);
diff --git a/common/spl/Kconfig b/common/spl/Kconfig
index 9edea35e26a..8dade2b501e 100644
--- a/common/spl/Kconfig
+++ b/common/spl/Kconfig
@@ -1312,6 +1312,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
@@ -1372,6 +1380,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/