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

Attachment: signature.asc
Description: PGP signature

Reply via email to