summaryrefslogtreecommitdiffstats
path: root/commands
diff options
context:
space:
mode:
authorAhmad Fatoum <a.fatoum@pengutronix.de>2023-05-19 12:01:20 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2023-05-25 09:36:01 +0200
commitbf7405c00016beb7860729d18d4fe53772b81db7 (patch)
tree9862d953301cb9eb4808bdf3188266fb6ae1791a /commands
parent1d4e0a09991c7d8dbe7aad2b299c999f416b6377 (diff)
downloadbarebox-bf7405c00016beb7860729d18d4fe53772b81db7.tar.gz
barebox-bf7405c00016beb7860729d18d4fe53772b81db7.tar.xz
commands: implement of_compatible command
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@pengutronix.de> Link: https://lore.barebox.org/20230519100120.2365970-7-a.fatoum@pengutronix.de Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'commands')
-rw-r--r--commands/Kconfig15
-rw-r--r--commands/Makefile1
-rw-r--r--commands/of_compatible.c124
3 files changed, 140 insertions, 0 deletions
diff --git a/commands/Kconfig b/commands/Kconfig
index 4d3ff631a8..824e01690e 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -2190,6 +2190,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 compatible (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 98625a0373..0c3980d463 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 0000000000..b460fecd3a
--- /dev/null
+++ b/commands/of_compatible.c
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: © 2023 Ahmad Fatoum <a.fatoum@pengutronix.de>
+
+#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 **compats, **compat, *dtbfile = NULL;
+ const char *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;
+
+ compats = &argv[optind];
+
+ if (dtbfile) {
+ root = of_read_file(dtbfile);
+ if (IS_ERR(root))
+ return PTR_ERR(root);
+
+ of_free = root;
+ } else {
+ root = of_get_root_node();
+
+ /* copy internal device tree to apply fixups onto it */
+ if (fix)
+ root = of_free = of_dup(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;
+ }
+
+ ret = COMMAND_ERROR;
+
+ 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() ?: "";
+ for (compat = compats; *compat; compat++) {
+ if (strcmp(*compat, compat_override) == 0) {
+ ret = COMMAND_SUCCESS;
+ goto out;
+ }
+ }
+ }
+
+ for (compat = compats; *compat; compat++) {
+ int score;
+
+ score = of_device_is_compatible(node, *compat);
+ if (score > 0) {
+ ret = COMMAND_SUCCESS;
+ break;
+ }
+ }
+
+out:
+ 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] [COMPATS..]")
+ BAREBOX_CMD_GROUP(CMD_GRP_MISC)
+ BAREBOX_CMD_COMPLETE(empty_complete)
+ BAREBOX_CMD_HELP(cmd_of_compatible_help)
+BAREBOX_CMD_END