Merge patch series "Convert extension support to UCLASS and adds its support to boot flows"
Kory Maincent (TI.com) <kory.maincent@bootlin.com> says: This series converts the extension board framework to use UCLASS as requested by Simon Glass, then adds extension support to pxe_utils and bootmeth_efi (not tested) to enable extension boards devicetree load in the standard boot process. I can't test the imx8 extension scan enabled by the imx8mm-cl-iot-gate_defconfig as I don't have this board. I also can't test the efi bootmeth change as I don't have such board. Link: https://lore.kernel.org/r/20251030-feature_sysboot_extension_board-v5-0-cfb77672fc68@bootlin.com
This commit is contained in:
@@ -1185,6 +1185,15 @@ F: scripts/event_dump.py
|
||||
F: test/common/event.c
|
||||
F: test/py/tests/test_event_dump.py
|
||||
|
||||
EXTENSION
|
||||
M: Kory Maincent <kory.maincent@bootlin.com>
|
||||
S: Maintained
|
||||
F: board/sunxi/chip.c
|
||||
F: board/ti/common/cape_detect.c
|
||||
F: boot/extension-uclass.c
|
||||
F: cmd/extension_board.c
|
||||
F: include/extension_board.h
|
||||
|
||||
FASTBOOT
|
||||
M: Mattijs Korpershoek <mkorpershoek@kernel.org>
|
||||
S: Maintained
|
||||
|
||||
@@ -249,6 +249,8 @@ int board_mmc_get_env_dev(int devno)
|
||||
#define IOT_GATE_IMX8_EXT_I2C_ADDR_GPIO 0x22 /* I2C address of the GPIO
|
||||
extender */
|
||||
|
||||
#if !IS_ENABLED(CONFIG_XPL_BUILD)
|
||||
|
||||
static int iot_gate_imx8_ext_id = IOT_GATE_EXT_EMPTY; /* Extension board ID */
|
||||
static int iot_gate_imx8_ext_ied_id [3] = {
|
||||
IOT_GATE_IMX8_CARD_ID_EMPTY,
|
||||
@@ -434,9 +436,10 @@ static int iot_gate_imx8_update_ext_ied(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int extension_board_scan(struct list_head *extension_list)
|
||||
static int iot_gate_imx8_extension_board_scan(struct udevice *dev,
|
||||
struct alist *extension_list)
|
||||
{
|
||||
struct extension *extension = NULL;
|
||||
struct extension extension = {0};
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
@@ -446,25 +449,21 @@ int extension_board_scan(struct list_head *extension_list)
|
||||
case IOT_GATE_EXT_EMPTY:
|
||||
break;
|
||||
case IOT_GATE_EXT_CAN:
|
||||
extension = calloc(1, sizeof(struct extension));
|
||||
snprintf(extension->name, sizeof(extension->name),
|
||||
snprintf(extension.name, sizeof(extension.name),
|
||||
"IOT_GATE_EXT_CAN");
|
||||
break;
|
||||
case IOT_GATE_EXT_IED:
|
||||
extension = calloc(1, sizeof(struct extension));
|
||||
snprintf(extension->name, sizeof(extension->name),
|
||||
snprintf(extension.name, sizeof(extension.name),
|
||||
"IOT_GATE_EXT_IED");
|
||||
snprintf(extension->overlay, sizeof(extension->overlay),
|
||||
snprintf(extension.overlay, sizeof(extension.overlay),
|
||||
"imx8mm-cl-iot-gate-ied.dtbo");
|
||||
break;
|
||||
case IOT_GATE_EXT_POE:
|
||||
extension = calloc(1, sizeof(struct extension));
|
||||
snprintf(extension->name, sizeof(extension->name),
|
||||
snprintf(extension.name, sizeof(extension.name),
|
||||
"IOT_GATE_EXT_POE");
|
||||
break;
|
||||
case IOT_GATE_EXT_POEV2:
|
||||
extension = calloc(1, sizeof(struct extension));
|
||||
snprintf(extension->name, sizeof(extension->name),
|
||||
snprintf(extension.name, sizeof(extension.name),
|
||||
"IOT_GATE_EXT_POEV2");
|
||||
break;
|
||||
default:
|
||||
@@ -472,10 +471,11 @@ int extension_board_scan(struct list_head *extension_list)
|
||||
break;
|
||||
}
|
||||
|
||||
if (extension) {
|
||||
snprintf(extension->owner, sizeof(extension->owner),
|
||||
if (extension.name[0]) {
|
||||
snprintf(extension.owner, sizeof(extension.owner),
|
||||
"Compulab");
|
||||
list_add_tail(&extension->list, extension_list);
|
||||
if (!alist_add(extension_list, extension))
|
||||
return -ENOMEM;
|
||||
ret = 1;
|
||||
} else
|
||||
return ret;
|
||||
@@ -484,44 +484,38 @@ int extension_board_scan(struct list_head *extension_list)
|
||||
|
||||
iot_gate_imx8_update_ext_ied();
|
||||
for (i=0; i<ARRAY_SIZE(iot_gate_imx8_ext_ied_id); i++) {
|
||||
extension = NULL;
|
||||
memset(&extension, 0, sizeof(extension));
|
||||
switch (iot_gate_imx8_ext_ied_id[i]) {
|
||||
case IOT_GATE_IMX8_CARD_ID_EMPTY:
|
||||
break;
|
||||
case IOT_GATE_IMX8_CARD_ID_RS_485:
|
||||
extension = calloc(1, sizeof(struct extension));
|
||||
snprintf(extension->name, sizeof(extension->name),
|
||||
snprintf(extension.name, sizeof(extension.name),
|
||||
"IOT_GATE_IMX8_CARD_ID_RS_485");
|
||||
break;
|
||||
case IOT_GATE_IMX8_CARD_ID_RS_232:
|
||||
extension = calloc(1, sizeof(struct extension));
|
||||
snprintf(extension->name, sizeof(extension->name),
|
||||
snprintf(extension.name, sizeof(extension.name),
|
||||
"IOT_GATE_IMX8_CARD_ID_RS_232");
|
||||
break;
|
||||
case IOT_GATE_IMX8_CARD_ID_CAN:
|
||||
extension = calloc(1, sizeof(struct extension));
|
||||
snprintf(extension->name, sizeof(extension->name),
|
||||
snprintf(extension.name, sizeof(extension.name),
|
||||
"IOT_GATE_IMX8_CARD_ID_CAN");
|
||||
snprintf(extension->overlay, sizeof(extension->overlay),
|
||||
snprintf(extension.overlay, sizeof(extension.overlay),
|
||||
"imx8mm-cl-iot-gate-ied-can%d.dtbo", i);
|
||||
break;
|
||||
case IOT_GATE_IMX8_CARD_ID_TPM:
|
||||
extension = calloc(1, sizeof(struct extension));
|
||||
snprintf(extension->name, sizeof(extension->name),
|
||||
snprintf(extension.name, sizeof(extension.name),
|
||||
"IOT_GATE_IMX8_CARD_ID_TPM");
|
||||
snprintf(extension->overlay, sizeof(extension->overlay),
|
||||
snprintf(extension.overlay, sizeof(extension.overlay),
|
||||
"imx8mm-cl-iot-gate-ied-tpm%d.dtbo", i);
|
||||
break;
|
||||
case IOT_GATE_IMX8_CARD_ID_CL420:
|
||||
extension = calloc(1, sizeof(struct extension));
|
||||
snprintf(extension->name, sizeof(extension->name),
|
||||
snprintf(extension.name, sizeof(extension.name),
|
||||
"IOT_GATE_IMX8_CARD_ID_CL420");
|
||||
snprintf(extension->overlay, sizeof(extension->overlay),
|
||||
snprintf(extension.overlay, sizeof(extension.overlay),
|
||||
"imx8mm-cl-iot-gate-ied-can%d.dtbo", i);
|
||||
break;
|
||||
case IOT_GATE_IMX8_CARD_ID_DI4O4:
|
||||
extension = calloc(1, sizeof(struct extension));
|
||||
snprintf(extension->name, sizeof(extension->name),
|
||||
snprintf(extension.name, sizeof(extension.name),
|
||||
"IOT_GATE_IMX8_CARD_ID_DI4O4");
|
||||
break;
|
||||
default:
|
||||
@@ -529,12 +523,13 @@ int extension_board_scan(struct list_head *extension_list)
|
||||
__func__, i, iot_gate_imx8_ext_ied_id[i]);
|
||||
break;
|
||||
}
|
||||
if (extension) {
|
||||
snprintf(extension->owner, sizeof(extension->owner),
|
||||
if (extension.name[0]) {
|
||||
snprintf(extension.owner, sizeof(extension.owner),
|
||||
"Compulab");
|
||||
snprintf(extension->other, sizeof(extension->other),
|
||||
snprintf(extension.other, sizeof(extension.other),
|
||||
"On slot %d", i);
|
||||
list_add_tail(&extension->list, extension_list);
|
||||
if (!alist_add(extension_list, extension))
|
||||
return -ENOMEM;
|
||||
ret = ret + 1;
|
||||
}
|
||||
}
|
||||
@@ -542,6 +537,13 @@ int extension_board_scan(struct list_head *extension_list)
|
||||
return ret;
|
||||
}
|
||||
|
||||
U_BOOT_EXTENSION(iot_gate_imx8_extension, iot_gate_imx8_extension_board_scan);
|
||||
|
||||
U_BOOT_DRVINFO(iot_gate_imx8_extension) = {
|
||||
.name = "iot_gate_imx8_extension",
|
||||
};
|
||||
#endif
|
||||
|
||||
static int setup_mac_address(void)
|
||||
{
|
||||
unsigned char enetaddr[6];
|
||||
|
||||
+19
-10
@@ -110,24 +110,33 @@ int ft_board_setup(void *fdt, struct bd_info *bd)
|
||||
return fdt_add_mem_rsv(fdt, 0x00d02000, 0x4000);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CMD_EXTENSION
|
||||
int extension_board_scan(struct list_head *extension_list)
|
||||
#if CONFIG_IS_ENABLED(SUPPORT_EXTENSION_SCAN) && \
|
||||
!CONFIG_IS_ENABLED(XPL_BUILD)
|
||||
static int sandbox_extension_board_scan(struct udevice *dev,
|
||||
struct alist *extension_list)
|
||||
{
|
||||
struct extension *extension;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
extension = calloc(1, sizeof(struct extension));
|
||||
snprintf(extension->overlay, sizeof(extension->overlay), "overlay%d.dtbo", i);
|
||||
snprintf(extension->name, sizeof(extension->name), "extension board %d", i);
|
||||
snprintf(extension->owner, sizeof(extension->owner), "sandbox");
|
||||
snprintf(extension->version, sizeof(extension->version), "1.1");
|
||||
snprintf(extension->other, sizeof(extension->other), "Fictional extension board");
|
||||
list_add_tail(&extension->list, extension_list);
|
||||
struct extension extension = {0};
|
||||
|
||||
snprintf(extension.overlay, sizeof(extension.overlay), "overlay%d.dtbo", i);
|
||||
snprintf(extension.name, sizeof(extension.name), "extension board %d", i);
|
||||
snprintf(extension.owner, sizeof(extension.owner), "sandbox");
|
||||
snprintf(extension.version, sizeof(extension.version), "1.1");
|
||||
snprintf(extension.other, sizeof(extension.other), "Fictional extension board");
|
||||
if (!alist_add(extension_list, extension))
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
U_BOOT_EXTENSION(sandbox_extension, sandbox_extension_board_scan);
|
||||
|
||||
U_BOOT_DRVINFO(sandbox_extension) = {
|
||||
.name = "sandbox_extension",
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BOARD_LATE_INIT
|
||||
|
||||
@@ -11,4 +11,4 @@ obj-$(CONFIG_SUN7I_GMAC) += gmac.o
|
||||
obj-$(CONFIG_MACH_SUN4I) += dram_sun4i_auto.o
|
||||
obj-$(CONFIG_MACH_SUN5I) += dram_sun5i_auto.o
|
||||
obj-$(CONFIG_MACH_SUN7I) += dram_sun5i_auto.o
|
||||
obj-$(CONFIG_CHIP_DIP_SCAN) += chip.o
|
||||
obj-$(CONFIG_$(PHASE_)CHIP_DIP_SCAN) += chip.o
|
||||
|
||||
+19
-17
@@ -40,16 +40,12 @@ struct dip_w1_header {
|
||||
u8 data[16]; /* user data, per-dip specific */
|
||||
} __packed;
|
||||
|
||||
int extension_board_scan(struct list_head *extension_list)
|
||||
static int sunxi_extension_board_scan(struct udevice *udev,
|
||||
struct alist *extension_list)
|
||||
{
|
||||
struct extension *dip;
|
||||
struct dip_w1_header w1_header;
|
||||
struct udevice *bus, *dev;
|
||||
u32 vid;
|
||||
u16 pid;
|
||||
int ret;
|
||||
|
||||
int num_dip = 0;
|
||||
int ret;
|
||||
|
||||
sunxi_gpio_set_pull(SUNXI_GPD(2), SUNXI_GPIO_PULL_UP);
|
||||
|
||||
@@ -60,6 +56,11 @@ int extension_board_scan(struct list_head *extension_list)
|
||||
}
|
||||
|
||||
for_each_w1_device(bus, &dev) {
|
||||
struct extension dip = {0};
|
||||
struct dip_w1_header w1_header;
|
||||
u32 vid;
|
||||
u16 pid;
|
||||
|
||||
if (w1_get_device_family(dev) != W1_FAMILY_DS2431)
|
||||
continue;
|
||||
|
||||
@@ -82,18 +83,19 @@ int extension_board_scan(struct list_head *extension_list)
|
||||
w1_header.product_name, pid,
|
||||
w1_header.vendor_name, vid);
|
||||
|
||||
dip = calloc(1, sizeof(struct extension));
|
||||
if (!dip) {
|
||||
printf("Error in memory allocation\n");
|
||||
return num_dip;
|
||||
}
|
||||
|
||||
snprintf(dip->overlay, sizeof(dip->overlay), "dip-%x-%x.dtbo",
|
||||
snprintf(dip.overlay, sizeof(dip.overlay), "dip-%x-%x.dtbo",
|
||||
vid, pid);
|
||||
strncpy(dip->name, w1_header.product_name, 32);
|
||||
strncpy(dip->owner, w1_header.vendor_name, 32);
|
||||
list_add_tail(&dip->list, extension_list);
|
||||
strlcpy(dip.name, w1_header.product_name, sizeof(dip.name));
|
||||
strlcpy(dip.owner, w1_header.vendor_name, sizeof(dip.owner));
|
||||
if (!alist_add(extension_list, dip))
|
||||
return -ENOMEM;
|
||||
num_dip++;
|
||||
}
|
||||
return num_dip;
|
||||
}
|
||||
|
||||
U_BOOT_EXTENSION(dip, sunxi_extension_board_scan);
|
||||
|
||||
U_BOOT_DRVINFO(dip) = {
|
||||
.name = "dip",
|
||||
};
|
||||
|
||||
@@ -20,7 +20,7 @@ config CAPE_EEPROM_BUS_NUM
|
||||
int "Cape EEPROM's I2C bus address"
|
||||
range 0 8
|
||||
default 2
|
||||
depends on CMD_EXTENSION
|
||||
depends on SUPPORT_EXTENSION_SCAN
|
||||
|
||||
config TI_COMMON_CMD_OPTIONS
|
||||
bool "Enable cmd options on TI platforms"
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
# Copyright (C) 2015-2016 Texas Instruments Incorporated - https://www.ti.com/
|
||||
|
||||
obj-${CONFIG_TI_I2C_BOARD_DETECT} += board_detect.o
|
||||
obj-${CONFIG_CMD_EXTENSION} += cape_detect.o
|
||||
obj-${CONFIG_$(PHASE_)SUPPORT_EXTENSION_SCAN} += cape_detect.o
|
||||
obj-${CONFIG_OF_LIBFDT} += fdt_ops.o
|
||||
obj-${CONFIG_ARCH_K3} += k3-ddr.o
|
||||
|
||||
@@ -22,21 +22,21 @@ static void sanitize_field(char *text, size_t size)
|
||||
}
|
||||
}
|
||||
|
||||
int extension_board_scan(struct list_head *extension_list)
|
||||
static int ti_extension_board_scan(struct udevice *dev,
|
||||
struct alist *extension_list)
|
||||
{
|
||||
struct extension *cape;
|
||||
struct am335x_cape_eeprom_id eeprom_header;
|
||||
|
||||
int num_capes = 0;
|
||||
int ret, i;
|
||||
struct udevice *dev;
|
||||
unsigned char addr;
|
||||
|
||||
char process_cape_part_number[17] = {'0'};
|
||||
char process_cape_version[5] = {'0'};
|
||||
uint8_t cursor = 0;
|
||||
int num_capes = 0;
|
||||
|
||||
for (addr = CAPE_EEPROM_FIRST_ADDR; addr <= CAPE_EEPROM_LAST_ADDR; addr++) {
|
||||
struct am335x_cape_eeprom_id eeprom_header;
|
||||
char process_cape_part_number[17] = {'0'};
|
||||
char process_cape_version[5] = {'0'};
|
||||
struct extension cape = {0};
|
||||
struct udevice *dev;
|
||||
u8 cursor = 0;
|
||||
int ret, i;
|
||||
|
||||
ret = i2c_get_chip_for_busnum(CONFIG_CAPE_EEPROM_BUS_NUM, addr, 1, &dev);
|
||||
if (ret)
|
||||
continue;
|
||||
@@ -59,8 +59,8 @@ int extension_board_scan(struct list_head *extension_list)
|
||||
sanitize_field(eeprom_header.part_number, sizeof(eeprom_header.part_number));
|
||||
|
||||
/* Process cape part_number */
|
||||
memset(process_cape_part_number, 0, sizeof(process_cape_part_number));
|
||||
strncpy(process_cape_part_number, eeprom_header.part_number, 16);
|
||||
strlcpy(process_cape_part_number, eeprom_header.part_number,
|
||||
sizeof(process_cape_part_number));
|
||||
/* Some capes end with '.' */
|
||||
for (i = 15; i >= 0; i--) {
|
||||
if (process_cape_part_number[i] == '.')
|
||||
@@ -70,8 +70,8 @@ int extension_board_scan(struct list_head *extension_list)
|
||||
}
|
||||
|
||||
/* Process cape version */
|
||||
memset(process_cape_version, 0, sizeof(process_cape_version));
|
||||
strncpy(process_cape_version, eeprom_header.version, 4);
|
||||
strlcpy(process_cape_version, eeprom_header.version,
|
||||
sizeof(process_cape_version));
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (process_cape_version[i] == 0)
|
||||
process_cape_version[i] = '0';
|
||||
@@ -79,19 +79,23 @@ int extension_board_scan(struct list_head *extension_list)
|
||||
|
||||
printf("BeagleBone Cape: %s (0x%x)\n", eeprom_header.board_name, addr);
|
||||
|
||||
cape = calloc(1, sizeof(struct extension));
|
||||
if (!cape) {
|
||||
printf("Error in memory allocation\n");
|
||||
return num_capes;
|
||||
}
|
||||
|
||||
snprintf(cape->overlay, sizeof(cape->overlay), "%s-%s.dtbo",
|
||||
snprintf(cape.overlay, sizeof(cape.overlay), "%s-%s.dtbo",
|
||||
process_cape_part_number, process_cape_version);
|
||||
strncpy(cape->name, eeprom_header.board_name, 32);
|
||||
strncpy(cape->version, process_cape_version, 4);
|
||||
strncpy(cape->owner, eeprom_header.manufacturer, 16);
|
||||
list_add_tail(&cape->list, extension_list);
|
||||
strlcpy(cape.name, eeprom_header.board_name,
|
||||
sizeof(eeprom_header.board_name));
|
||||
strlcpy(cape.version, process_cape_version,
|
||||
sizeof(process_cape_version));
|
||||
strlcpy(cape.owner, eeprom_header.manufacturer,
|
||||
sizeof(eeprom_header.manufacturer) + 1);
|
||||
if (!alist_add(extension_list, cape))
|
||||
return -ENOMEM;
|
||||
num_capes++;
|
||||
}
|
||||
return num_capes;
|
||||
}
|
||||
|
||||
U_BOOT_EXTENSION(cape, ti_extension_board_scan);
|
||||
|
||||
U_BOOT_DRVINFO(cape) = {
|
||||
.name = "cape",
|
||||
};
|
||||
|
||||
@@ -1909,6 +1909,10 @@ endmenu
|
||||
|
||||
endif # OF_LIBFDT
|
||||
|
||||
config SUPPORT_EXTENSION_SCAN
|
||||
select OF_LIBFDT_OVERLAY
|
||||
bool
|
||||
|
||||
config USE_BOOTARGS
|
||||
bool "Enable boot arguments"
|
||||
help
|
||||
|
||||
@@ -9,6 +9,7 @@ obj-$(CONFIG_BOOT_RETRY) += bootretry.o
|
||||
obj-$(CONFIG_CMD_BOOTM) += bootm.o bootm_os.o
|
||||
obj-$(CONFIG_CMD_BOOTZ) += bootm.o bootm_os.o
|
||||
obj-$(CONFIG_CMD_BOOTI) += bootm.o bootm_os.o
|
||||
obj-$(CONFIG_SUPPORT_EXTENSION_SCAN) += extension-uclass.o
|
||||
|
||||
obj-$(CONFIG_PXE_UTILS) += pxe_utils.o
|
||||
|
||||
|
||||
+63
-16
@@ -16,6 +16,7 @@
|
||||
#include <efi.h>
|
||||
#include <efi_loader.h>
|
||||
#include <env.h>
|
||||
#include <extension_board.h>
|
||||
#include <fs.h>
|
||||
#include <malloc.h>
|
||||
#include <mapmem.h>
|
||||
@@ -99,8 +100,11 @@ static int distro_efi_check(struct udevice *dev, struct bootflow_iter *iter)
|
||||
static int distro_efi_try_bootflow_files(struct udevice *dev,
|
||||
struct bootflow *bflow)
|
||||
{
|
||||
ulong fdt_addr, size, overlay_addr;
|
||||
const struct extension *extension;
|
||||
struct fdt_header *working_fdt;
|
||||
struct blk_desc *desc = NULL;
|
||||
ulong fdt_addr, size;
|
||||
struct alist *extension_list;
|
||||
char fname[256];
|
||||
int ret, seq;
|
||||
|
||||
@@ -148,23 +152,66 @@ static int distro_efi_try_bootflow_files(struct udevice *dev,
|
||||
return log_msg_ret("fil", -ENOMEM);
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
bflow->fdt_size = size;
|
||||
bflow->fdt_addr = fdt_addr;
|
||||
|
||||
/*
|
||||
* TODO: Apply extension overlay
|
||||
*
|
||||
* Here we need to load and apply the extension overlay. This is
|
||||
* not implemented. See do_extension_apply(). The extension
|
||||
* stuff needs an implementation in boot/extension.c so it is
|
||||
* separate from the command code. Really the extension stuff
|
||||
* should use the device tree and a uclass / driver interface
|
||||
* rather than implementing its own list
|
||||
*/
|
||||
} else {
|
||||
if (ret) {
|
||||
log_debug("No device tree available\n");
|
||||
bflow->flags |= BOOTFLOWF_USE_BUILTIN_FDT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bflow->fdt_size = size;
|
||||
bflow->fdt_addr = fdt_addr;
|
||||
|
||||
if (!CONFIG_IS_ENABLED(SUPPORT_EXTENSION_SCAN))
|
||||
return 0;
|
||||
|
||||
ret = extension_scan();
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
|
||||
extension_list = extension_get_list();
|
||||
if (!extension_list)
|
||||
return 0;
|
||||
|
||||
working_fdt = map_sysmem(fdt_addr, 0);
|
||||
if (fdt_check_header(working_fdt))
|
||||
return 0;
|
||||
|
||||
overlay_addr = env_get_hex("extension_overlay_addr", 0);
|
||||
if (!overlay_addr) {
|
||||
log_debug("Environment extension_overlay_addr is missing\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
alist_for_each(extension, extension_list) {
|
||||
char *overlay_file;
|
||||
int len;
|
||||
|
||||
len = sizeof(EFI_DIRNAME) + strlen(extension->overlay);
|
||||
overlay_file = calloc(1, len);
|
||||
if (!overlay_file)
|
||||
return -ENOMEM;
|
||||
|
||||
snprintf(overlay_file, len, "%s%s", EFI_DIRNAME,
|
||||
extension->overlay);
|
||||
|
||||
ret = bootmeth_common_read_file(dev, bflow, overlay_file,
|
||||
overlay_addr,
|
||||
(enum bootflow_img_t)IH_TYPE_FLATDT,
|
||||
&size);
|
||||
if (ret) {
|
||||
log_debug("Failed loading overlay %s\n", overlay_file);
|
||||
free(overlay_file);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = extension_apply(working_fdt, size);
|
||||
if (ret) {
|
||||
log_debug("Failed applying overlay %s\n", overlay_file);
|
||||
free(overlay_file);
|
||||
continue;
|
||||
}
|
||||
bflow->fdt_size += size;
|
||||
free(overlay_file);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2025 Köry Maincent <kory.maincent@bootlin.com>
|
||||
*/
|
||||
|
||||
#include <alist.h>
|
||||
#include <command.h>
|
||||
#include <env.h>
|
||||
#include <extension_board.h>
|
||||
#include <fdt_support.h>
|
||||
#include <malloc.h>
|
||||
#include <mapmem.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <dm/lists.h>
|
||||
#include <dm/uclass.h>
|
||||
|
||||
struct alist *extension_get_list(void)
|
||||
{
|
||||
struct udevice *dev;
|
||||
|
||||
if (uclass_first_device_err(UCLASS_EXTENSION, &dev))
|
||||
return NULL;
|
||||
|
||||
return dev_get_priv(dev);
|
||||
}
|
||||
|
||||
int extension_probe(struct udevice *dev)
|
||||
{
|
||||
struct alist *extension_list = dev_get_priv(dev);
|
||||
|
||||
alist_init_struct(extension_list, struct extension);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int extension_remove(struct udevice *dev)
|
||||
{
|
||||
struct alist *extension_list = dev_get_priv(dev);
|
||||
|
||||
alist_uninit(extension_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int extension_scan(void)
|
||||
{
|
||||
struct alist *extension_list = extension_get_list();
|
||||
const struct extension_ops *ops;
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
|
||||
ret = uclass_first_device_err(UCLASS_EXTENSION, &dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!extension_list)
|
||||
return -ENODEV;
|
||||
|
||||
ops = extension_get_ops(dev);
|
||||
alist_empty(extension_list);
|
||||
return ops->scan(dev, extension_list);
|
||||
}
|
||||
|
||||
int extension_apply(struct fdt_header *working_fdt, ulong size)
|
||||
{
|
||||
struct fdt_header *blob;
|
||||
ulong overlay_addr;
|
||||
int ret;
|
||||
|
||||
overlay_addr = env_get_hex("extension_overlay_addr", 0);
|
||||
if (!overlay_addr) {
|
||||
printf("Environment extension_overlay_addr is missing\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fdt_shrink_to_minimum(working_fdt, size);
|
||||
|
||||
blob = map_sysmem(overlay_addr, 0);
|
||||
if (!fdt_valid(&blob)) {
|
||||
printf("Invalid overlay devicetree\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Apply method prints messages on error */
|
||||
ret = fdt_overlay_apply_verbose(working_fdt, blob);
|
||||
if (ret)
|
||||
printf("Failed to apply overlay\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
UCLASS_DRIVER(extension) = {
|
||||
.name = "extension",
|
||||
.id = UCLASS_EXTENSION,
|
||||
};
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <command.h>
|
||||
#include <dm.h>
|
||||
#include <env.h>
|
||||
#include <extension_board.h>
|
||||
#include <image.h>
|
||||
#include <log.h>
|
||||
#include <malloc.h>
|
||||
@@ -432,6 +433,95 @@ skip_overlay:
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* label_boot_extension - scan extension boards and load overlay associated
|
||||
*/
|
||||
|
||||
static void label_boot_extension(struct pxe_context *ctx,
|
||||
struct pxe_label *label)
|
||||
{
|
||||
#if CONFIG_IS_ENABLED(SUPPORT_EXTENSION_SCAN)
|
||||
const struct extension *extension;
|
||||
struct fdt_header *working_fdt;
|
||||
struct alist *extension_list;
|
||||
int ret, dir_len, len;
|
||||
char *overlay_dir;
|
||||
const char *slash;
|
||||
ulong fdt_addr;
|
||||
|
||||
ret = extension_scan();
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
extension_list = extension_get_list();
|
||||
if (!extension_list)
|
||||
return;
|
||||
|
||||
/* Get the main fdt and map it */
|
||||
fdt_addr = env_get_hex("fdt_addr_r", 0);
|
||||
working_fdt = map_sysmem(fdt_addr, 0);
|
||||
if (fdt_check_header(working_fdt))
|
||||
return;
|
||||
|
||||
/* Use fdtdir for now as the overlay devicetree directory */
|
||||
if (label->fdtdir) {
|
||||
len = strlen(label->fdtdir);
|
||||
if (!len)
|
||||
slash = "./";
|
||||
else if (label->fdtdir[len - 1] != '/')
|
||||
slash = "/";
|
||||
else
|
||||
slash = "";
|
||||
|
||||
dir_len = strlen(label->fdtdir) + strlen(slash) + 1;
|
||||
overlay_dir = calloc(1, len);
|
||||
if (!overlay_dir)
|
||||
return;
|
||||
|
||||
snprintf(overlay_dir, dir_len, "%s%s", label->fdtdir,
|
||||
slash);
|
||||
} else {
|
||||
dir_len = 2;
|
||||
snprintf(overlay_dir, dir_len, "/");
|
||||
}
|
||||
|
||||
alist_for_each(extension, extension_list) {
|
||||
char *overlay_file;
|
||||
ulong size;
|
||||
|
||||
len = dir_len + strlen(extension->overlay);
|
||||
overlay_file = calloc(1, len);
|
||||
if (!overlay_file)
|
||||
goto cleanup;
|
||||
|
||||
snprintf(overlay_file, len, "%s%s", overlay_dir,
|
||||
extension->overlay);
|
||||
|
||||
/* Load extension overlay file */
|
||||
ret = get_relfile_envaddr(ctx, overlay_file,
|
||||
"extension_overlay_addr",
|
||||
(enum bootflow_img_t)IH_TYPE_FLATDT,
|
||||
&size);
|
||||
if (ret < 0) {
|
||||
printf("Failed loading overlay %s\n", overlay_file);
|
||||
free(overlay_file);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = extension_apply(working_fdt, size);
|
||||
if (ret) {
|
||||
printf("Failed applying overlay %s\n", overlay_file);
|
||||
free(overlay_file);
|
||||
continue;
|
||||
}
|
||||
free(overlay_file);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(overlay_dir);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* label_boot() - Boot according to the contents of a pxe_label
|
||||
*
|
||||
@@ -685,6 +775,8 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
|
||||
if (label->fdtoverlays)
|
||||
label_boot_fdtoverlay(ctx, label);
|
||||
#endif
|
||||
label_boot_extension(ctx, label);
|
||||
|
||||
} else {
|
||||
bootm_argv[3] = NULL;
|
||||
}
|
||||
|
||||
@@ -545,9 +545,6 @@ config CMD_FDT
|
||||
help
|
||||
Do FDT related setup before booting into the Operating System.
|
||||
|
||||
config SUPPORT_EXTENSION_SCAN
|
||||
bool
|
||||
|
||||
config CMD_EXTENSION
|
||||
bool "Extension board management command"
|
||||
select CMD_FDT
|
||||
|
||||
+87
-104
@@ -4,75 +4,107 @@
|
||||
* Köry Maincent, Bootlin, <kory.maincent@bootlin.com>
|
||||
*/
|
||||
|
||||
#include <bootdev.h>
|
||||
#include <alist.h>
|
||||
#include <exports.h>
|
||||
#include <command.h>
|
||||
#include <dm.h>
|
||||
#include <env.h>
|
||||
#include <malloc.h>
|
||||
#include <extension_board.h>
|
||||
#include <mapmem.h>
|
||||
#include <linux/libfdt.h>
|
||||
#include <fdt_support.h>
|
||||
|
||||
static LIST_HEAD(extension_list);
|
||||
|
||||
static int extension_apply(struct extension *extension)
|
||||
static int
|
||||
cmd_extension_load_overlay_from_env(const struct extension *extension,
|
||||
ulong *filesize)
|
||||
{
|
||||
ulong size, overlay_addr;
|
||||
char *overlay_cmd;
|
||||
ulong extrasize, overlay_addr;
|
||||
struct fdt_header *blob;
|
||||
|
||||
if (!working_fdt) {
|
||||
printf("No FDT memory address configured. Please configure\n"
|
||||
"the FDT address via \"fdt addr <address>\" command.\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
int ret;
|
||||
|
||||
overlay_cmd = env_get("extension_overlay_cmd");
|
||||
if (!overlay_cmd) {
|
||||
printf("Environment extension_overlay_cmd is missing\n");
|
||||
return CMD_RET_FAILURE;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
overlay_addr = env_get_hex("extension_overlay_addr", 0);
|
||||
if (!overlay_addr) {
|
||||
printf("Environment extension_overlay_addr is missing\n");
|
||||
return CMD_RET_FAILURE;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
env_set("extension_overlay_name", extension->overlay);
|
||||
if (run_command(overlay_cmd, 0) != 0)
|
||||
return CMD_RET_FAILURE;
|
||||
ret = run_command(overlay_cmd, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
extrasize = env_get_hex("filesize", 0);
|
||||
if (!extrasize)
|
||||
return CMD_RET_FAILURE;
|
||||
size = env_get_hex("filesize", 0);
|
||||
if (!size)
|
||||
return -EINVAL;
|
||||
|
||||
fdt_shrink_to_minimum(working_fdt, extrasize);
|
||||
*filesize = size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
blob = map_sysmem(overlay_addr, 0);
|
||||
if (!fdt_valid(&blob))
|
||||
return CMD_RET_FAILURE;
|
||||
static int cmd_extension_apply(int extension_num)
|
||||
{
|
||||
struct alist *extension_list = extension_get_list();
|
||||
const struct extension *extension;
|
||||
ulong size;
|
||||
int ret;
|
||||
|
||||
/* apply method prints messages on error */
|
||||
if (fdt_overlay_apply_verbose(working_fdt, blob))
|
||||
return CMD_RET_FAILURE;
|
||||
if (!extension_list)
|
||||
return -ENODEV;
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
extension = alist_get(extension_list, extension_num,
|
||||
struct extension);
|
||||
if (!extension) {
|
||||
printf("Wrong extension number\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = cmd_extension_load_overlay_from_env(extension, &size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return extension_apply(working_fdt, size);
|
||||
}
|
||||
|
||||
static int cmd_extension_apply_all(void)
|
||||
{
|
||||
struct alist *extension_list = extension_get_list();
|
||||
const struct extension *extension;
|
||||
int ret;
|
||||
|
||||
if (!extension_list)
|
||||
return -ENODEV;
|
||||
|
||||
alist_for_each(extension, extension_list) {
|
||||
ulong size;
|
||||
|
||||
ret = cmd_extension_load_overlay_from_env(extension, &size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = extension_apply(working_fdt, size);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_extension_list(struct cmd_tbl *cmdtp, int flag,
|
||||
int argc, char *const argv[])
|
||||
{
|
||||
int i = 0;
|
||||
struct alist *extension_list;
|
||||
struct extension *extension;
|
||||
int i = 0;
|
||||
|
||||
if (list_empty(&extension_list)) {
|
||||
extension_list = extension_get_list();
|
||||
if (!alist_get_ptr(extension_list, 0)) {
|
||||
printf("No extension registered - Please run \"extension scan\"\n");
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
list_for_each_entry(extension, &extension_list, list) {
|
||||
alist_for_each(extension, extension_list) {
|
||||
printf("Extension %d: %s\n", i++, extension->name);
|
||||
printf("\tManufacturer: \t\t%s\n", extension->owner);
|
||||
printf("\tVersion: \t\t%s\n", extension->version);
|
||||
@@ -82,71 +114,45 @@ static int do_extension_list(struct cmd_tbl *cmdtp, int flag,
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static int extension_scan(bool show)
|
||||
{
|
||||
struct extension *extension, *next;
|
||||
int extension_num;
|
||||
|
||||
list_for_each_entry_safe(extension, next, &extension_list, list) {
|
||||
list_del(&extension->list);
|
||||
free(extension);
|
||||
}
|
||||
extension_num = extension_board_scan(&extension_list);
|
||||
if (show && extension_num >= 0)
|
||||
printf("Found %d extension board(s).\n", extension_num);
|
||||
|
||||
/* either the number of extensions, or -ve for error */
|
||||
return extension_num;
|
||||
}
|
||||
|
||||
static int do_extension_scan(struct cmd_tbl *cmdtp, int flag,
|
||||
int argc, char *const argv[])
|
||||
{
|
||||
int extension_num;
|
||||
|
||||
extension_num = extension_scan(true);
|
||||
if (extension_num < 0)
|
||||
extension_num = extension_scan();
|
||||
if (extension_num == -ENODEV)
|
||||
extension_num = 0;
|
||||
else if (extension_num < 0)
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
printf("Found %d extension board(s).\n", extension_num);
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static int do_extension_apply(struct cmd_tbl *cmdtp, int flag,
|
||||
int argc, char *const argv[])
|
||||
{
|
||||
struct extension *extension = NULL;
|
||||
struct list_head *entry;
|
||||
int i = 0, extension_id, ret;
|
||||
int extension_id;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if (strcmp(argv[1], "all") == 0) {
|
||||
ret = CMD_RET_FAILURE;
|
||||
list_for_each_entry(extension, &extension_list, list) {
|
||||
ret = extension_apply(extension);
|
||||
if (ret != CMD_RET_SUCCESS)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
extension_id = simple_strtol(argv[1], NULL, 10);
|
||||
list_for_each(entry, &extension_list) {
|
||||
if (i == extension_id) {
|
||||
extension = list_entry(entry, struct extension, list);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (!extension) {
|
||||
printf("Wrong extension number\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
ret = extension_apply(extension);
|
||||
if (!working_fdt) {
|
||||
printf("No FDT memory address configured. Please configure\n"
|
||||
"the FDT address via \"fdt addr <address>\" command.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
if (strcmp(argv[1], "all") == 0) {
|
||||
if (cmd_extension_apply_all())
|
||||
return CMD_RET_FAILURE;
|
||||
} else {
|
||||
extension_id = simple_strtol(argv[1], NULL, 10);
|
||||
if (cmd_extension_apply(extension_id))
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static struct cmd_tbl cmd_extension[] = {
|
||||
@@ -177,26 +183,3 @@ U_BOOT_CMD(extension, 3, 1, do_extensionops,
|
||||
"extension list - lists available extension(s) board(s)\n"
|
||||
"extension apply <extension number|all> - applies DT overlays corresponding to extension boards\n"
|
||||
);
|
||||
|
||||
static int extension_bootdev_hunt(struct bootdev_hunter *info, bool show)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = env_set_hex("extension_overlay_addr",
|
||||
env_get_hex("fdtoverlay_addr_r", 0));
|
||||
if (ret)
|
||||
return log_msg_ret("env", ret);
|
||||
|
||||
ret = extension_scan(show);
|
||||
if (ret < 0)
|
||||
return log_msg_ret("ext", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* extensions should have a uclass - for now we use UCLASS_SIMPLE_BUS uclass */
|
||||
BOOTDEV_HUNTER(extension_bootdev_hunter) = {
|
||||
.prio = BOOTDEVP_1_PRE_SCAN,
|
||||
.uclass = UCLASS_SIMPLE_BUS,
|
||||
.hunt = extension_bootdev_hunt,
|
||||
};
|
||||
|
||||
+17
-12
@@ -25,9 +25,8 @@ Device Tree overlays depending on the detected extension boards.
|
||||
|
||||
The "extension" command comes with three sub-commands:
|
||||
|
||||
- "extension scan" makes the generic code call the board-specific
|
||||
extension_board_scan() function to retrieve the list of detected
|
||||
extension boards.
|
||||
- "extension scan" makes the generic code call a board-specific extension
|
||||
function to retrieve the list of detected extension boards.
|
||||
|
||||
- "extension list" allows to list the detected extension boards.
|
||||
|
||||
@@ -98,17 +97,23 @@ Simple extension_board_scan function example
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int extension_board_scan(struct list_head *extension_list)
|
||||
static int foo_extension_board_scan(struct alist *extension_list)
|
||||
{
|
||||
struct extension *extension;
|
||||
struct extension extension = {0};
|
||||
|
||||
extension = calloc(1, sizeof(struct extension));
|
||||
snprintf(extension->overlay, sizeof(extension->overlay), "overlay.dtbo");
|
||||
snprintf(extension->name, sizeof(extension->name), "extension board");
|
||||
snprintf(extension->owner, sizeof(extension->owner), "sandbox");
|
||||
snprintf(extension->version, sizeof(extension->version), "1.1");
|
||||
snprintf(extension->other, sizeof(extension->other), "Extension board information");
|
||||
list_add_tail(&extension->list, extension_list);
|
||||
snprintf(extension.overlay, sizeof(extension.overlay), "overlay.dtbo");
|
||||
snprintf(extension.name, sizeof(extension.name), "extension board");
|
||||
snprintf(extension.owner, sizeof(extension.owner), "sandbox");
|
||||
snprintf(extension.version, sizeof(extension.version), "1.1");
|
||||
snprintf(extension.other, sizeof(extension.other), "Extension board information");
|
||||
if (!alist_add(extension_list, extension))
|
||||
return -ENOMEM;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
U_BOOT_EXTENSION(foo_extension_name, foo_extension_board_scan);
|
||||
|
||||
U_BOOT_DRVINFO(foo_extension_name) = {
|
||||
.name = "foo_extension_name",
|
||||
};
|
||||
|
||||
@@ -103,6 +103,10 @@ Environment
|
||||
``fdt_addr_r``. Required to use the ``fdtoverlays`` command in
|
||||
the PXE file.
|
||||
|
||||
``extension_overlay_addr``
|
||||
Location in RAM to temporarily store extension fdt overlay(s)
|
||||
before applying them to the fdt blob stored at ``fdt_addr_r``.
|
||||
|
||||
``pxe_label_override``
|
||||
Override label to be used, if exists, instead of the default
|
||||
label. This will allow consumers to choose a pxe label at
|
||||
|
||||
@@ -63,6 +63,7 @@ enum uclass_id {
|
||||
UCLASS_ETH, /* Ethernet device */
|
||||
UCLASS_ETH_PHY, /* Ethernet PHY device */
|
||||
UCLASS_EXTCON, /* External Connector Class */
|
||||
UCLASS_EXTENSION, /* Extension board */
|
||||
UCLASS_FFA, /* Arm Firmware Framework for Armv8-A */
|
||||
UCLASS_FFA_EMUL, /* sandbox FF-A device emulator */
|
||||
UCLASS_FIRMWARE, /* Firmware */
|
||||
|
||||
+74
-12
@@ -7,10 +7,58 @@
|
||||
#ifndef __EXTENSION_SUPPORT_H
|
||||
#define __EXTENSION_SUPPORT_H
|
||||
|
||||
#include <alist.h>
|
||||
#include <dm/device.h>
|
||||
#include <linux/list.h>
|
||||
#include <dm/platdata.h>
|
||||
|
||||
extern struct list_head extension_list;
|
||||
|
||||
/**
|
||||
* extension_get_list - Get the extension list
|
||||
* Return: The extension alist pointer, or NULL if no such list exists.
|
||||
*
|
||||
* The caller must not free the list.
|
||||
*/
|
||||
struct alist *extension_get_list(void);
|
||||
|
||||
/**
|
||||
* extension_probe - Probe extension device
|
||||
* @dev: Extension device that needs to be probed
|
||||
* Return: Zero on success, negative on failure.
|
||||
*/
|
||||
int extension_probe(struct udevice *dev);
|
||||
|
||||
/**
|
||||
* extension_remove - Remove extension device
|
||||
* @dev: Extension device that needs to be removed
|
||||
* Return: Zero on success, negative on failure.
|
||||
*/
|
||||
int extension_remove(struct udevice *dev);
|
||||
|
||||
/**
|
||||
* extension_scan - Scan extension boards available.
|
||||
* Return: Zero on success, negative on failure.
|
||||
*/
|
||||
int extension_scan(void);
|
||||
|
||||
/**
|
||||
* extension_apply - Apply extension board overlay to the devicetree
|
||||
* @working_fdt: Pointer to working flattened device tree
|
||||
* @size: Size of the devicetree overlay
|
||||
* Return: Zero on success, negative on failure.
|
||||
*/
|
||||
int extension_apply(struct fdt_header *working_fdt, ulong size);
|
||||
|
||||
/**
|
||||
* extension - Description fields of an extension board
|
||||
* @name: Name of the extension
|
||||
* @owner: Owner of the extension
|
||||
* @version: Version of the extension
|
||||
* @overlay: Devicetree overlay name to be loaded for this extension
|
||||
* @other: Other information of this extension
|
||||
*/
|
||||
struct extension {
|
||||
struct list_head list;
|
||||
char name[32];
|
||||
char owner[32];
|
||||
char version[32];
|
||||
@@ -18,16 +66,30 @@ struct extension {
|
||||
char other[32];
|
||||
};
|
||||
|
||||
/**
|
||||
* extension_board_scan - Add system-specific function to scan extension board.
|
||||
* @param extension_list List of extension board information to update.
|
||||
* Return: the number of extension.
|
||||
*
|
||||
* This function is called if CONFIG_CMD_EXTENSION is defined.
|
||||
* Needs to fill the list extension_list with elements.
|
||||
* Each element need to be allocated to an extension structure.
|
||||
*
|
||||
*/
|
||||
int extension_board_scan(struct list_head *extension_list);
|
||||
struct extension_ops {
|
||||
/**
|
||||
* scan - Add system-specific function to scan extension boards.
|
||||
* @dev: extension device
|
||||
* @extension_list: alist of extension to expand
|
||||
* Return: The number of extension or a negative value in case of
|
||||
* error.
|
||||
*/
|
||||
int (*scan)(struct udevice *dev, struct alist *extension_list);
|
||||
};
|
||||
|
||||
#define extension_get_ops(dev) ((struct extension_ops *)(dev)->driver->ops)
|
||||
|
||||
/* Currently, only one extension driver enabled at a time is supported */
|
||||
#define U_BOOT_EXTENSION(_name, _scan_func) \
|
||||
U_BOOT_DRIVER(_name) = { \
|
||||
.name = #_name, \
|
||||
.id = UCLASS_EXTENSION, \
|
||||
.probe = extension_probe, \
|
||||
.remove = extension_remove, \
|
||||
.ops = &(struct extension_ops) { \
|
||||
.scan = _scan_func, \
|
||||
}, \
|
||||
.priv_auto = sizeof(struct alist), \
|
||||
}
|
||||
|
||||
#endif /* __EXTENSION_SUPPORT_H */
|
||||
|
||||
+13
-19
@@ -380,7 +380,6 @@ static int bootdev_test_hunter(struct unit_test_state *uts)
|
||||
ut_assert_nextline("Prio Used Uclass Hunter");
|
||||
ut_assert_nextlinen("----");
|
||||
ut_assert_nextline(" 6 ethernet eth_bootdev");
|
||||
ut_assert_nextline(" 1 simple_bus (none)");
|
||||
ut_assert_nextline(" 5 ide ide_bootdev");
|
||||
ut_assert_nextline(" 2 mmc mmc_bootdev");
|
||||
ut_assert_nextline(" 4 nvme nvme_bootdev");
|
||||
@@ -389,15 +388,15 @@ static int bootdev_test_hunter(struct unit_test_state *uts)
|
||||
ut_assert_nextline(" 4 spi_flash sf_bootdev");
|
||||
ut_assert_nextline(" 5 usb usb_bootdev");
|
||||
ut_assert_nextline(" 4 virtio virtio_bootdev");
|
||||
ut_assert_nextline("(total hunters: 10)");
|
||||
ut_assert_nextline("(total hunters: 9)");
|
||||
ut_assert_console_end();
|
||||
|
||||
ut_assertok(bootdev_hunt("usb1", false));
|
||||
ut_assert_skip_to_line("Bus usb@1: 5 USB Device(s) found");
|
||||
ut_assert_console_end();
|
||||
|
||||
/* USB is 7th in the list, so bit 8 */
|
||||
ut_asserteq(BIT(8), std->hunters_used);
|
||||
/* USB is 8th in the list, so bit 7 */
|
||||
ut_asserteq(BIT(7), std->hunters_used);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -418,7 +417,7 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts)
|
||||
ut_assert_nextline("Prio Used Uclass Hunter");
|
||||
ut_assert_nextlinen("----");
|
||||
ut_assert_nextline(" 6 ethernet eth_bootdev");
|
||||
ut_assert_skip_to_line("(total hunters: 10)");
|
||||
ut_assert_skip_to_line("(total hunters: 9)");
|
||||
ut_assert_console_end();
|
||||
|
||||
/* Use the MMC hunter and see that it updates */
|
||||
@@ -426,7 +425,7 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts)
|
||||
ut_assertok(run_command("bootdev hunt -l", 0));
|
||||
ut_assert_skip_to_line(" 5 ide ide_bootdev");
|
||||
ut_assert_nextline(" 2 * mmc mmc_bootdev");
|
||||
ut_assert_skip_to_line("(total hunters: 10)");
|
||||
ut_assert_skip_to_line("(total hunters: 9)");
|
||||
ut_assert_console_end();
|
||||
|
||||
/* Scan all hunters */
|
||||
@@ -436,8 +435,6 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts)
|
||||
ut_assert_nextline("Hunting with: ethernet");
|
||||
|
||||
/* This is the extension feature which has no uclass at present */
|
||||
ut_assert_nextline("Hunting with: simple_bus");
|
||||
ut_assert_nextline("Found 2 extension board(s).");
|
||||
ut_assert_nextline("Hunting with: ide");
|
||||
|
||||
/* mmc hunter has already been used so should not run again */
|
||||
@@ -457,7 +454,6 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts)
|
||||
ut_assert_nextlinen("Prio");
|
||||
ut_assert_nextlinen("----");
|
||||
ut_assert_nextline(" 6 * ethernet eth_bootdev");
|
||||
ut_assert_nextline(" 1 * simple_bus (none)");
|
||||
ut_assert_nextline(" 5 * ide ide_bootdev");
|
||||
ut_assert_nextline(" 2 * mmc mmc_bootdev");
|
||||
ut_assert_nextline(" 4 * nvme nvme_bootdev");
|
||||
@@ -466,7 +462,7 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts)
|
||||
ut_assert_nextline(" 4 * spi_flash sf_bootdev");
|
||||
ut_assert_nextline(" 5 * usb usb_bootdev");
|
||||
ut_assert_nextline(" 4 * virtio virtio_bootdev");
|
||||
ut_assert_nextline("(total hunters: 10)");
|
||||
ut_assert_nextline("(total hunters: 9)");
|
||||
ut_assert_console_end();
|
||||
|
||||
ut_asserteq(GENMASK(MAX_HUNTER, 0), std->hunters_used);
|
||||
@@ -490,7 +486,7 @@ static int bootdev_test_hunt_scan(struct unit_test_state *uts)
|
||||
ut_assertok(bootflow_scan_first(NULL, NULL, &iter,
|
||||
BOOTFLOWIF_SHOW | BOOTFLOWIF_HUNT |
|
||||
BOOTFLOWIF_SKIP_GLOBAL, &bflow));
|
||||
ut_asserteq(BIT(MMC_HUNTER) | BIT(1), std->hunters_used);
|
||||
ut_asserteq(BIT(MMC_HUNTER), std->hunters_used);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -650,8 +646,8 @@ static int bootdev_test_next_label(struct unit_test_state *uts)
|
||||
ut_asserteq_str("scsi.id0lun0.bootdev", dev->name);
|
||||
ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS, mflags);
|
||||
|
||||
/* SCSI is 7th in the list, so bit 6 */
|
||||
ut_asserteq(BIT(MMC_HUNTER) | BIT(6), std->hunters_used);
|
||||
/* SCSI is 6th in the list, so bit 5 */
|
||||
ut_asserteq(BIT(MMC_HUNTER) | BIT(5), std->hunters_used);
|
||||
|
||||
ut_assertok(bootdev_next_label(&iter, &dev, &mflags));
|
||||
ut_assert_console_end();
|
||||
@@ -661,7 +657,7 @@ static int bootdev_test_next_label(struct unit_test_state *uts)
|
||||
mflags);
|
||||
|
||||
/* dhcp: Ethernet is first so bit 0 */
|
||||
ut_asserteq(BIT(MMC_HUNTER) | BIT(6) | BIT(0), std->hunters_used);
|
||||
ut_asserteq(BIT(MMC_HUNTER) | BIT(5) | BIT(0), std->hunters_used);
|
||||
|
||||
ut_assertok(bootdev_next_label(&iter, &dev, &mflags));
|
||||
ut_assert_console_end();
|
||||
@@ -671,7 +667,7 @@ static int bootdev_test_next_label(struct unit_test_state *uts)
|
||||
mflags);
|
||||
|
||||
/* pxe: Ethernet is first so bit 0 */
|
||||
ut_asserteq(BIT(MMC_HUNTER) | BIT(6) | BIT(0), std->hunters_used);
|
||||
ut_asserteq(BIT(MMC_HUNTER) | BIT(5) | BIT(0), std->hunters_used);
|
||||
|
||||
mflags = 123;
|
||||
ut_asserteq(-ENODEV, bootdev_next_label(&iter, &dev, &mflags));
|
||||
@@ -679,7 +675,7 @@ static int bootdev_test_next_label(struct unit_test_state *uts)
|
||||
ut_assert_console_end();
|
||||
|
||||
/* no change */
|
||||
ut_asserteq(BIT(MMC_HUNTER) | BIT(6) | BIT(0), std->hunters_used);
|
||||
ut_asserteq(BIT(MMC_HUNTER) | BIT(5) | BIT(0), std->hunters_used);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -724,12 +720,10 @@ static int bootdev_test_next_prio(struct unit_test_state *uts)
|
||||
|
||||
ut_assertok(bootdev_next_prio(&iter, &dev));
|
||||
ut_asserteq_str("mmc2.bootdev", dev->name);
|
||||
ut_assert_nextline("Hunting with: simple_bus");
|
||||
ut_assert_nextline("Found 2 extension board(s).");
|
||||
ut_assert_nextline("Hunting with: mmc");
|
||||
ut_assert_console_end();
|
||||
|
||||
ut_asserteq(BIT(MMC_HUNTER) | BIT(1), std->hunters_used);
|
||||
ut_asserteq(BIT(MMC_HUNTER), std->hunters_used);
|
||||
|
||||
ut_assertok(bootdev_next_prio(&iter, &dev));
|
||||
ut_asserteq_str("mmc1.bootdev", dev->name);
|
||||
|
||||
@@ -861,7 +861,7 @@ static int bootflow_cmd_hunt_single(struct unit_test_state *uts)
|
||||
ut_assert_console_end();
|
||||
|
||||
/* check that the hunter was used */
|
||||
ut_asserteq(BIT(MMC_HUNTER) | BIT(1), std->hunters_used);
|
||||
ut_asserteq(BIT(MMC_HUNTER), std->hunters_used);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -883,14 +883,12 @@ static int bootflow_cmd_hunt_label(struct unit_test_state *uts)
|
||||
ut_assertok(run_command("bootflow scan -l mmc", 0));
|
||||
|
||||
/* check that the hunter was used */
|
||||
ut_asserteq(BIT(MMC_HUNTER) | BIT(1), std->hunters_used);
|
||||
ut_asserteq(BIT(MMC_HUNTER), std->hunters_used);
|
||||
|
||||
/* check that we got the mmc1 bootflow */
|
||||
ut_assert_nextline("Scanning for bootflows with label 'mmc'");
|
||||
ut_assert_nextlinen("Seq");
|
||||
ut_assert_nextlinen("---");
|
||||
ut_assert_nextline("Hunting with: simple_bus");
|
||||
ut_assert_nextline("Found 2 extension board(s).");
|
||||
ut_assert_nextline("Hunting with: mmc");
|
||||
ut_assert_nextline("Scanning bootdev 'mmc2.bootdev':");
|
||||
ut_assert_nextline("Scanning bootdev 'mmc1.bootdev':");
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
#define TEST_VERNUM 0x00010002
|
||||
|
||||
enum {
|
||||
MAX_HUNTER = 9,
|
||||
MMC_HUNTER = 3, /* ID of MMC hunter */
|
||||
MAX_HUNTER = 8,
|
||||
MMC_HUNTER = 2, /* ID of MMC hunter */
|
||||
};
|
||||
|
||||
struct unit_test_state;
|
||||
|
||||
Reference in New Issue
Block a user