From bbdbcaf59dc518f26897f162f3512a8a596c5d97 Mon Sep 17 00:00:00 2001 From: Kory Maincent Date: Tue, 4 May 2021 19:31:21 +0200 Subject: fdt_support: move fdt_valid from cmd_fdt.c to fdt_support.c Move the fdt_valid function to fdt_support. This changes allow to be able to test the validity of a devicetree in other c files. Update code syntax. Signed-off-by: Kory Maincent Reviewed-by: Tom Rini Reviewed-by: Maxime Ripard --- cmd/fdt.c | 49 ------------------------------------------------- 1 file changed, 49 deletions(-) (limited to 'cmd') diff --git a/cmd/fdt.c b/cmd/fdt.c index 89ab572d8df..f1e2fc2fd8b 100644 --- a/cmd/fdt.c +++ b/cmd/fdt.c @@ -27,7 +27,6 @@ */ DECLARE_GLOBAL_DATA_PTR; -static int fdt_valid(struct fdt_header **blobp); static int fdt_parse_prop(char *const*newval, int count, char *data, int *len); static int fdt_print(const char *pathp, char *prop, int depth); static int is_printable_string(const void *data, int len); @@ -732,54 +731,6 @@ static int do_fdt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) /****************************************************************************/ -/** - * fdt_valid() - Check if an FDT is valid. If not, change it to NULL - * - * @blobp: Pointer to FDT pointer - * @return 1 if OK, 0 if bad (in which case *blobp is set to NULL) - */ -static int fdt_valid(struct fdt_header **blobp) -{ - const void *blob = *blobp; - int err; - - if (blob == NULL) { - printf ("The address of the fdt is invalid (NULL).\n"); - return 0; - } - - err = fdt_check_header(blob); - if (err == 0) - return 1; /* valid */ - - if (err < 0) { - printf("libfdt fdt_check_header(): %s", fdt_strerror(err)); - /* - * Be more informative on bad version. - */ - if (err == -FDT_ERR_BADVERSION) { - if (fdt_version(blob) < - FDT_FIRST_SUPPORTED_VERSION) { - printf (" - too old, fdt %d < %d", - fdt_version(blob), - FDT_FIRST_SUPPORTED_VERSION); - } - if (fdt_last_comp_version(blob) > - FDT_LAST_SUPPORTED_VERSION) { - printf (" - too new, fdt %d > %d", - fdt_version(blob), - FDT_LAST_SUPPORTED_VERSION); - } - } - printf("\n"); - *blobp = NULL; - return 0; - } - return 1; -} - -/****************************************************************************/ - /* * Parse the user's input, partially heuristic. Valid formats: * <0x00112233 4 05> - an array of cells. Numbers follow standard -- cgit v1.2.3 From 2f84e9cf06d31aa703ff31301bf811b3fcfc16cf Mon Sep 17 00:00:00 2001 From: Kory Maincent Date: Tue, 4 May 2021 19:31:22 +0200 Subject: cmd: add support for a new "extension" command 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 |all" allows to apply the Device Tree overlay(s) corresponding to one, or all, extension boards The latter requires two environment variables to exist and set one variable to run: - 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. - extension_overlay_name: set by the command: the name of the DT which will be load during the execution. 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 Reviewed-by: Maxime Ripard --- cmd/Kconfig | 12 ++++ cmd/Makefile | 1 + cmd/extension_board.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 180 insertions(+) create mode 100644 cmd/extension_board.c (limited to 'cmd') diff --git a/cmd/Kconfig b/cmd/Kconfig index 9e8b69258ff..f962bb71411 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -332,6 +332,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 4977fa15f43..9d10e07f0ef 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -54,6 +54,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 00000000000..bbb4812ff81 --- /dev/null +++ b/cmd/extension_board.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2021 + * Köry Maincent, Bootlin, + */ + +#include +#include +#include +#include +#include +#include +#include + +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
\" 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 = 0; + 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 - applies DT overlays corresponding to extension boards\n" +); -- cgit v1.2.3