Hi, On Wed, Mar 24, 2021 at 11:04:12AM +0100, Kory Maincent wrote: > This patch adds a new "extension" command, which aims at detecting > extension boards connected to the hardware platform, and apply the > Device Tree overlays that describe the hardware present on those > extension boards. > > In order to enable this mechanism, board-specific code must implement > the extension_board_scan() function that fills in a linked list of > "struct extension", each describing one extension board. In addition, > the board-specific code must select the SUPPORT_EXTENSION_SCAN Kconfig > boolean. > > Based on this: > > - "extension scan" makes the generic code call the board-specific > extension_board_scan() function to retrieve the list of detected > extension boards. > > - "extension list" allows to list the detected extension boards. > > - "extension apply <number>|all" allows to apply the Device Tree > overlay(s) corresponding to one, or all, extension boards > > The latter requires two environment variables to exist: > > - extension_overlay_addr: the RAM address where to load the Device > Tree overlays > > - extension_overlay_cmd: the U-Boot command to load one overlay. > Indeed, the location and mechanism to load DT overlays is very setup > specific. > > When calling the command described in the extension_overlay_cmd > variable, the variable extension_overlay_name will be defined. So a > typical extension_overlay_cmd will look like this: > > extension_overlay_cmd=load mmc 0:1 $extension_overlay_addr > /boot/$extension_overlay_name > > Here is an example on how to use it: > => run loadfdt > => fdt addr $fdtaddr > => setenv extension_overlay_addr 0x1000 > => setenv extension_overlay_cmd 'load mmc 0:1 ${extension_overlay_addr} > /boot/${extension_overlay_name}' > => extension scan > Found 1 extension board(s). > => extension apply 0 > 519 bytes read in 3 ms (168.9 KiB/s) > > Signed-off-by: Kory Maincent <kory.mainc...@bootlin.com> > --- > > Change since v1: > - add list_for_each_entry loop bracket > - move doc location and update it to rST > > cmd/Kconfig | 12 +++ > cmd/Makefile | 1 + > cmd/extension_board.c | 167 ++++++++++++++++++++++++++++++++++++++ > doc/usage/extension.rst | 111 +++++++++++++++++++++++++ > include/extension_board.h | 31 +++++++ > 5 files changed, 322 insertions(+) > create mode 100644 cmd/extension_board.c > create mode 100644 doc/usage/extension.rst > create mode 100644 include/extension_board.h > > diff --git a/cmd/Kconfig b/cmd/Kconfig > index 1595de999b..90be5c260a 100644 > --- a/cmd/Kconfig > +++ b/cmd/Kconfig > @@ -314,6 +314,18 @@ 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 > + depends on SUPPORT_EXTENSION_SCAN > + help > + Enables the "extension" command, which allows to detect > + extension boards connected to the system, and apply > + corresponding Device Tree overlays. > + > config CMD_GO > bool "go" > default y > diff --git a/cmd/Makefile b/cmd/Makefile > index dd86675bf2..87da67d27d 100644 > --- a/cmd/Makefile > +++ b/cmd/Makefile > @@ -53,6 +53,7 @@ obj-$(CONFIG_CMD_DIAG) += diag.o > endif > obj-$(CONFIG_CMD_ADTIMG) += adtimg.o > obj-$(CONFIG_CMD_ABOOTIMG) += abootimg.o > +obj-$(CONFIG_CMD_EXTENSION) += extension_board.o > obj-$(CONFIG_CMD_ECHO) += echo.o > obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o > obj-$(CONFIG_CMD_EEPROM) += eeprom.o > diff --git a/cmd/extension_board.c b/cmd/extension_board.c > new file mode 100644 > index 0000000000..6ad9765d84 > --- /dev/null > +++ b/cmd/extension_board.c > @@ -0,0 +1,167 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * (C) Copyright 2021 > + * Köry Maincent, Bootlin, <kory.mainc...@bootlin.com> > + */ > + > +#include <common.h> > +#include <command.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) > +{ > + 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; > + } > + > + overlay_cmd = env_get("extension_overlay_cmd"); > + if (!overlay_cmd) { > + printf("Environment extension_overlay_cmd is missing\n"); > + return CMD_RET_FAILURE; > + } > + > + overlay_addr = env_get_hex("extension_overlay_addr", 0); > + if (!overlay_addr) { > + printf("Environment extension_overlay_addr is missing\n"); > + return CMD_RET_FAILURE; > + } > + > + env_set("extension_overlay_name", extension->overlay); > + if (run_command(overlay_cmd, 0) != 0) > + return CMD_RET_FAILURE; > + > + extrasize = env_get_hex("filesize", 0); > + if (!extrasize) > + return CMD_RET_FAILURE; > + > + fdt_shrink_to_minimum(working_fdt, extrasize); > + > + blob = map_sysmem(overlay_addr, 0); > + if (!fdt_valid(&blob)) > + return CMD_RET_FAILURE; > + > + /* apply method prints messages on error */ > + if (fdt_overlay_apply_verbose(working_fdt, blob)) > + return CMD_RET_FAILURE; > + > + return CMD_RET_SUCCESS; > +} > + > +static int do_extension_list(struct cmd_tbl *cmdtp, int flag, > + int argc, char *const argv[]) > +{ > + int i; > + struct extension *extension; > + > + if (list_empty(&extension_list)) { > + printf("No extension registered - Please run \"extension > scan\"\n"); > + return CMD_RET_SUCCESS; > + } > + > + list_for_each_entry(extension, &extension_list, 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); > + printf("\tDevicetree overlay: \t%s\n", extension->overlay); > + printf("\tOther information: \t%s\n", extension->other); > + } > + return CMD_RET_SUCCESS; > +} > + > +static int do_extension_scan(struct cmd_tbl *cmdtp, int flag, > + int argc, char *const argv[]) > +{ > + 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 (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; > + > + if (argc < 2) > + return CMD_RET_USAGE; > + > + if (strcmp(argv[1], "all") == 0) { > + 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); > + } > + > + return ret; > +} > + > +static struct cmd_tbl cmd_extension[] = { > + U_BOOT_CMD_MKENT(scan, 1, 1, do_extension_scan, "", ""), > + U_BOOT_CMD_MKENT(list, 1, 0, do_extension_list, "", ""), > + U_BOOT_CMD_MKENT(apply, 2, 0, do_extension_apply, "", ""), > +}; > + > +static int do_extensionops(struct cmd_tbl *cmdtp, int flag, int argc, > + char *const argv[]) > +{ > + struct cmd_tbl *cp; > + > + /* Drop the extension command */ > + argc--; > + argv++; > + > + cp = find_cmd_tbl(argv[0], cmd_extension, ARRAY_SIZE(cmd_extension)); > + if (cp) > + return cp->cmd(cmdtp, flag, argc, argv); > + > + return CMD_RET_USAGE; > +} > + > +U_BOOT_CMD(extension, 3, 1, do_extensionops, > + "Extension board management sub system", > + "scan - scan plugged extension(s) board(s)\n" > + "extension list - lists available extension(s) board(s)\n" > + "extension apply <extension number|all> - applies DT overlays > corresponding to extension boards\n" > +); > diff --git a/doc/usage/extension.rst b/doc/usage/extension.rst > new file mode 100644 > index 0000000000..2b88398b18 > --- /dev/null > +++ b/doc/usage/extension.rst > @@ -0,0 +1,111 @@ > +.. SPDX-License-Identifier: GPL-2.0+ > +.. Copyright 2021, Kory Maincent <kory.mainc...@bootlin.com> > + > +U-Boot extension board usage (CONFIG_EXTENSION) > +=============================================== > + > +Synopsis > +-------- > + > +:: > + > + extension scan > + extension list > + extension apply <extension number|all> > + > +Description > +----------- > + > +The "extension" command proposes a generic U-Boot mechanism to detect > +extension boards connected to the HW platform, and apply the appropriate > +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 list" allows to list the detected extension boards. > + > + - "extension apply <number>|all" allows to apply the Device Tree > + overlay(s) corresponding to one, or all, extension boards > + > +The latter requires two environment variables to exist: > + > + - extension_overlay_addr: the RAM address where to load the Device > + Tree overlays > + > + - extension_overlay_cmd: the U-Boot command to load one overlay. > + Indeed, the location and mechanism to load DT overlays is very setup > + specific.
I guess we should make it explicit that the extension_overlay_name variable will be set and usable by that command With that fixed, Reviewed-by: Maxime Ripard <max...@cerno.tech> Maxime
signature.asc
Description: PGP signature