Currently, the usual way within scripts to differentiate between machines is to compare global.model or global.hostname. Both are suboptimal, because they may change between releases or overridden by the user. In C code, the machine compatible is used for this purpose. Add a new of_compatible command that makes of_machine_is_compatible/ of_device_is_compatible available to scripts. Example use: /env/init/fixups: #!/bin/sh if of_compatible -k radxa,rock3a ; then of_property -df mmc0 sd-uhs-sdr104 fi Signed-off-by: Ahmad Fatoum <a.fatoum@xxxxxxxxxxxxxx> --- commands/Kconfig | 15 +++++ commands/Makefile | 1 + commands/of_compatible.c | 139 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 commands/of_compatible.c diff --git a/commands/Kconfig b/commands/Kconfig index b9abd8565523..59e8d6fb382d 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -2201,6 +2201,21 @@ config CMD_LSMOD help List loaded barebox modules. +config CMD_OF_COMPATIBLE + tristate + select OFTREE + prompt "of_compatible" + help + Check DT node's compatible + + Usage: [-fFnk] [COMPAT] + + Options: + -f dtb work on dtb instead of internal devicetree + -F apply fixups on devicetree before compare + -n node node path or alias to compare its comptible (default is /) + -k compare $global.of.kernel.add_machine_compatible as well + config CMD_OF_DIFF tristate select OFTREE diff --git a/commands/Makefile b/commands/Makefile index e5cc21f1970a..0ac84076f83d 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_CMD_USB) += usb.o obj-$(CONFIG_CMD_TIME) += time.o obj-$(CONFIG_CMD_UPTIME) += uptime.o obj-$(CONFIG_CMD_OFTREE) += oftree.o +obj-$(CONFIG_CMD_OF_COMPATIBLE) += of_compatible.o obj-$(CONFIG_CMD_OF_DIFF) += of_diff.o obj-$(CONFIG_CMD_OF_PROPERTY) += of_property.o obj-$(CONFIG_CMD_OF_NODE) += of_node.o diff --git a/commands/of_compatible.c b/commands/of_compatible.c new file mode 100644 index 000000000000..e4684f23b71d --- /dev/null +++ b/commands/of_compatible.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: © 2023 Ahmad Fatoum <a.fatoum@xxxxxxxxxxxxxx> + +#include <common.h> +#include <libfile.h> +#include <fdt.h> +#include <of.h> +#include <command.h> +#include <complete.h> +#include <errno.h> +#include <getopt.h> + +static int do_of_compatible(int argc, char *argv[]) +{ + int opt; + int ret = 0; + bool fix = false, kernel_compat = false; + struct device_node *root = NULL, *node, *of_free = NULL; + char *dtbfile = NULL; + const char *compat, *nodename = "/"; + + while ((opt = getopt(argc, argv, "f:n:Fk")) > 0) { + switch (opt) { + case 'f': + dtbfile = optarg; + break; + case 'n': + nodename = optarg; + break; + case 'F': + fix = true; + break; + case 'k': + kernel_compat = true; + break; + default: + return COMMAND_ERROR_USAGE; + } + } + + if (argc - optind != 1) + return COMMAND_ERROR_USAGE; + + compat = argv[optind]; + + if (dtbfile) { + size_t size; + void *fdt; + + fdt = read_file(dtbfile, &size); + if (!fdt) { + printf("unable to read %s: %s\n", dtbfile, strerror(errno)); + return -errno; + } + + root = of_unflatten_dtb(fdt, size); + + free(fdt); + + if (IS_ERR(root)) { + ret = PTR_ERR(root); + goto out; + } + + of_free = root; + } else { + root = of_get_root_node(); + + if (fix) { + /* create a copy of internal devicetree */ + void *fdt; + fdt = of_flatten_dtb(root); + root = of_unflatten_dtb(fdt, fdt_totalsize(fdt)); + + free(fdt); + + if (IS_ERR(root)) { + ret = PTR_ERR(root); + goto out; + } + + of_free = root; + } + } + + if (fix) { + ret = of_fix_tree(root); + if (ret) + goto out; + } + + node = of_find_node_by_path_or_alias(root, nodename); + if (!node) { + printf("Cannot find nodepath %s\n", nodename); + ret = -ENOENT; + goto out; + } + + if (kernel_compat) { + const char *compat_override; + + if (node->parent) { + printf("-k only valid for root node\n"); + ret = COMMAND_ERROR_USAGE; + goto out; + } + + compat_override = barebox_get_of_machine_compatible() ?: ""; + if (strcmp(compat_override, compat) == 0) { + ret = 0; + goto out; + } + } + + ret = !of_device_is_compatible(node, compat); + +out: + if (of_free) + of_delete_node(of_free); + + return ret; +} + +BAREBOX_CMD_HELP_START(of_compatible) +BAREBOX_CMD_HELP_TEXT("Options:") +BAREBOX_CMD_HELP_OPT ("-f dtb", "work on dtb instead of internal devicetree") +BAREBOX_CMD_HELP_OPT ("-F", "apply fixups on devicetree before compare") +BAREBOX_CMD_HELP_OPT ("-n NODE", "node path or alias to compare its compatible (default is /)") +BAREBOX_CMD_HELP_OPT ("-k", "compare $global.of.kernel.add_machine_compatible as well") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(of_compatible) + .cmd = do_of_compatible, + BAREBOX_CMD_DESC("Check DT node's compatible") + BAREBOX_CMD_OPTS("[-fFnk] [COMPAT]") + BAREBOX_CMD_GROUP(CMD_GRP_MISC) + BAREBOX_CMD_COMPLETE(empty_complete) + BAREBOX_CMD_HELP(cmd_of_compatible_help) +BAREBOX_CMD_END -- 2.39.2