mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2025-12-19 16:31:27 +01:00
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> Reviewed-by: Mattijs Korpershoek <mkorpershoek@kernel.org> Link: https://lore.kernel.org/r/20251023080922.3527052-1-h-salunke@ti.com Signed-off-by: Mattijs Korpershoek <mkorpershoek@kernel.org>
123 lines
2.9 KiB
C
123 lines
2.9 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* (C) Copyright 2016
|
|
* Xilinx, Inc.
|
|
*
|
|
* (C) Copyright 2016
|
|
* Toradex AG
|
|
*
|
|
* Michal Simek <michal.simek@amd.com>
|
|
* Stefan Agner <stefan.agner@toradex.com>
|
|
*/
|
|
#include <binman_sym.h>
|
|
#include <image.h>
|
|
#include <log.h>
|
|
#include <mapmem.h>
|
|
#include <spl.h>
|
|
#include <linux/libfdt.h>
|
|
|
|
static ulong spl_ram_load_read(struct spl_load_info *load, ulong sector,
|
|
ulong count, void *buf)
|
|
{
|
|
ulong addr = 0;
|
|
|
|
debug("%s: sector %lx, count %lx, buf %lx\n",
|
|
__func__, sector, count, (ulong)buf);
|
|
|
|
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))
|
|
addr += image_load_offset;
|
|
|
|
memcpy(buf, (void *)addr, count);
|
|
|
|
return count;
|
|
}
|
|
|
|
static int spl_ram_load_image(struct spl_image_info *spl_image,
|
|
struct spl_boot_device *bootdev)
|
|
{
|
|
struct legacy_img_hdr *header;
|
|
ulong addr = 0;
|
|
int ret;
|
|
|
|
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)) {
|
|
ret = image_pre_load(addr);
|
|
|
|
if (ret)
|
|
return ret;
|
|
|
|
addr += image_load_offset;
|
|
}
|
|
header = map_sysmem(addr, 0);
|
|
|
|
#if CONFIG_IS_ENABLED(DFU)
|
|
if (bootdev->boot_device == BOOT_DEVICE_DFU)
|
|
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;
|
|
|
|
debug("Found FIT\n");
|
|
spl_load_init(&load, spl_ram_load_read, NULL, 1);
|
|
ret = spl_load_simple_fit(spl_image, &load, 0, header);
|
|
} else {
|
|
ulong u_boot_pos = spl_get_image_pos();
|
|
|
|
debug("Legacy image\n");
|
|
/*
|
|
* Get the header. It will point to an address defined by
|
|
* handoff which will tell where the image located inside
|
|
* the flash.
|
|
*/
|
|
debug("u_boot_pos = %lx\n", u_boot_pos);
|
|
if (u_boot_pos == BINMAN_SYM_MISSING) {
|
|
/*
|
|
* No binman support or no information. For now, fix it
|
|
* to the address pointed to by U-Boot.
|
|
*/
|
|
u_boot_pos = (ulong)spl_get_load_buffer(-sizeof(*header),
|
|
sizeof(*header));
|
|
}
|
|
header = map_sysmem(u_boot_pos, 0);
|
|
|
|
ret = spl_parse_image_header(spl_image, bootdev, header);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#if CONFIG_IS_ENABLED(RAM_DEVICE)
|
|
SPL_LOAD_IMAGE_METHOD("RAM", 0, BOOT_DEVICE_RAM, spl_ram_load_image);
|
|
#endif
|
|
#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
|