summaryrefslogtreecommitdiffstats
path: root/commands
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2013-02-04 15:49:04 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2013-02-04 15:49:04 +0100
commit0b12784089b6a4372ed27cf1fd578d85a7d3dbd4 (patch)
tree6f25a55d72f51aeb1d42f02bf5f56edcc051b41a /commands
parent5c6cc8736ed4e14119fb2e8c0ed1ecab7caff9ae (diff)
parent9a554f8ff25685e44431079e73887b061d6f4a41 (diff)
downloadbarebox-0b12784089b6a4372ed27cf1fd578d85a7d3dbd4.tar.gz
barebox-0b12784089b6a4372ed27cf1fd578d85a7d3dbd4.tar.xz
Merge branch 'for-next/oftree'
Conflicts: drivers/of/base.c
Diffstat (limited to 'commands')
-rw-r--r--commands/Kconfig20
-rw-r--r--commands/Makefile2
-rw-r--r--commands/bootm.c32
-rw-r--r--commands/of_node.c111
-rw-r--r--commands/of_property.c280
-rw-r--r--commands/oftree.c130
6 files changed, 509 insertions, 66 deletions
diff --git a/commands/Kconfig b/commands/Kconfig
index 1addd91d24..d3c338c832 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -481,18 +481,28 @@ config CMD_GO
config CMD_OFTREE
tristate
select OFTREE
+ select OFDEVICE
prompt "oftree"
help
The oftree command has support for dumping devicetrees and, if
enabled, to probe devices from the devicetree
-config CMD_OFTREE_PROBE
- bool
- depends on CMD_OFTREE
+config CMD_OF_PROPERTY
+ tristate
+ select OFTREE
+ select OFDEVICE
+ prompt "of_property"
+ help
+ The of_property command allows setting and deleting of properties in
+ the currently loaded devicetree.
+
+config CMD_OF_NODE
+ tristate
+ select OFTREE
select OFDEVICE
- prompt "oftree probe support"
+ prompt "of_node"
help
- This enables the -p option to probe devices from the devicetree
+ The of_property command allows adding and removing devicetree nodes.
endmenu
diff --git a/commands/Makefile b/commands/Makefile
index c4baf6a470..0ae6b9546a 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -67,6 +67,8 @@ obj-$(CONFIG_CMD_LED_TRIGGER) += trigger.o
obj-$(CONFIG_CMD_USB) += usb.o
obj-$(CONFIG_CMD_TIME) += time.o
obj-$(CONFIG_CMD_OFTREE) += oftree.o
+obj-$(CONFIG_CMD_OF_PROPERTY) += of_property.o
+obj-$(CONFIG_CMD_OF_NODE) += of_node.o
obj-$(CONFIG_CMD_MAGICVAR) += magicvar.o
obj-$(CONFIG_CMD_IOMEM) += iomem.o
obj-$(CONFIG_CMD_LINUX_EXEC) += linux_exec.o
diff --git a/commands/bootm.c b/commands/bootm.c
index 5ccf2372ac..4d3f0221ca 100644
--- a/commands/bootm.c
+++ b/commands/bootm.c
@@ -139,9 +139,7 @@ static int bootm_open_oftree(struct image_data *data, const char *oftree, int nu
{
enum filetype ft;
struct fdt_header *fdt, *fixfdt;
- int ret;
size_t size;
- unsigned int align;
printf("Loading devicetree from '%s'\n", oftree);
@@ -189,36 +187,18 @@ static int bootm_open_oftree(struct image_data *data, const char *oftree, int nu
file_type_to_string(ft));
}
- /*
- * ARM Linux uses a single 1MiB section (with 1MiB alignment)
- * for mapping the devicetree, so we are not allowed to cross
- * 1MiB boundaries.
- */
- align = 1 << fls(size + OFTREE_SIZE_INCREASE - 1);
-
- fixfdt = xmemalign(align, size + OFTREE_SIZE_INCREASE);
- memcpy(fixfdt, fdt, size);
-
-
- ret = fdt_open_into(fdt, fixfdt, size + OFTREE_SIZE_INCREASE);
+ fixfdt = of_get_fixed_tree(fdt);
+ if (!fixfdt)
+ return -EINVAL;
free(fdt);
- if (ret) {
- printf("unable to parse %s\n", oftree);
- return -ENODEV;
- }
-
- ret = of_fix_tree(fixfdt);
- if (ret)
- return ret;
-
if (bootm_verbose(data) > 1)
fdt_print(fixfdt, "/");
data->oftree = fixfdt;
- return ret;
+ return 0;
}
#endif
@@ -420,6 +400,10 @@ static int do_bootm(int argc, char *argv[])
ret = bootm_open_oftree(&data, oftree, oftree_num);
if (ret)
goto err_out;
+ } else {
+ data.oftree = of_get_fixed_tree(NULL);
+ if (bootm_verbose(&data) && data.oftree)
+ printf("using internal devicetree\n");
}
#endif
if (data.os_address == UIMAGE_SOME_ADDRESS)
diff --git a/commands/of_node.c b/commands/of_node.c
new file mode 100644
index 0000000000..a370e2699a
--- /dev/null
+++ b/commands/of_node.c
@@ -0,0 +1,111 @@
+/*
+ * of_node.c - device tree node handling support
+ *
+ * Copyright (c) 2013 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <common.h>
+#include <environment.h>
+#include <fdt.h>
+#include <of.h>
+#include <command.h>
+#include <fs.h>
+#include <malloc.h>
+#include <libfdt.h>
+#include <linux/ctype.h>
+#include <asm/byteorder.h>
+#include <errno.h>
+#include <getopt.h>
+#include <init.h>
+#include <libgen.h>
+
+static int do_of_node(int argc, char *argv[])
+{
+ int opt;
+ int delete = 0;
+ int create = 0;
+ char *path = NULL;
+ struct device_node *node = NULL;
+
+ while ((opt = getopt(argc, argv, "cd")) > 0) {
+ switch (opt) {
+ case 'c':
+ create = 1;
+ break;
+ case 'd':
+ delete = 1;
+ break;
+ default:
+ return COMMAND_ERROR_USAGE;
+ }
+ }
+
+ if (optind < argc) {
+ path = argv[optind];
+ }
+
+ if (create) {
+ char *name;
+
+ if (!path)
+ return COMMAND_ERROR_USAGE;
+
+ name = xstrdup(basename(path));
+ path = dirname(path);
+
+ node = of_find_node_by_path(path);
+ if (!node) {
+ printf("Cannot find nodepath %s\n", path);
+ free(name);
+ return -ENOENT;
+ }
+
+ debug("create node \"%s\" \"%s\"\n", path, name);
+
+ of_new_node(node, name);
+
+ free(name);
+
+ return 0;
+ }
+
+ if (delete) {
+ if (!path)
+ return COMMAND_ERROR_USAGE;
+
+ node = of_find_node_by_path(path);
+ if (!node) {
+ printf("Cannot find nodepath %s\n", path);
+ return -ENOENT;
+ }
+
+ of_free(node);
+ }
+
+ return 0;
+}
+
+BAREBOX_CMD_HELP_START(of_node)
+BAREBOX_CMD_HELP_USAGE("of_node [OPTIONS] [NODE] [NAME]\n")
+BAREBOX_CMD_HELP_OPT ("-c", "create a new node\n")
+BAREBOX_CMD_HELP_OPT ("-d", "delete a node\n")
+BAREBOX_CMD_HELP_END
+
+BAREBOX_CMD_START(of_node)
+ .cmd = do_of_node,
+ .usage = "handle of nodes",
+ BAREBOX_CMD_HELP(cmd_of_node_help)
+BAREBOX_CMD_END
diff --git a/commands/of_property.c b/commands/of_property.c
new file mode 100644
index 0000000000..42b6f1123f
--- /dev/null
+++ b/commands/of_property.c
@@ -0,0 +1,280 @@
+/*
+ * of_property.c - device tree property handling support
+ *
+ * Copyright (c) 2013 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <common.h>
+#include <environment.h>
+#include <fdt.h>
+#include <of.h>
+#include <command.h>
+#include <fs.h>
+#include <malloc.h>
+#include <libfdt.h>
+#include <linux/ctype.h>
+#include <asm/byteorder.h>
+#include <errno.h>
+#include <getopt.h>
+#include <init.h>
+
+static int of_parse_prop_cells(char * const *newval, int count, char *data, int *len)
+{
+ char *cp;
+ unsigned long tmp; /* holds converted values */
+ int stridx = 0;
+ char *newp = newval[0];
+
+ newp++;
+
+ while (1) {
+ if (*newp == '>')
+ return 0;
+
+ if (*newp == '\0') {
+ newp = newval[++stridx];
+
+ if (stridx == count) {
+ printf("missing '>'\n");
+ return -EINVAL;
+ }
+
+ continue;
+ }
+
+ cp = newp;
+ tmp = simple_strtoul(cp, &newp, 0);
+ *(__be32 *)data = __cpu_to_be32(tmp);
+ data += 4;
+ *len += 4;
+
+ /* If the ptr didn't advance, something went wrong */
+ if ((newp - cp) <= 0) {
+ printf("cannot not convert \"%s\"\n", cp);
+ return -EINVAL;
+ }
+
+ while (*newp == ' ')
+ newp++;
+ }
+}
+
+static int of_parse_prop_stream(char * const *newval, int count, char *data, int *len)
+{
+ char *cp;
+ unsigned long tmp; /* holds converted values */
+ int stridx = 0;
+ char *newp = newval[0];
+
+ newp++;
+
+ while (1) {
+ if (*newp == ']')
+ return 0;
+
+ while (*newp == ' ')
+ newp++;
+
+ if (*newp == '\0') {
+ newp = newval[++stridx];
+
+ if (stridx == count) {
+ printf("missing ']'\n");
+ return -EINVAL;
+ }
+
+ continue;
+ }
+
+ cp = newp;
+ tmp = simple_strtoul(newp, &newp, 16);
+ *data++ = tmp & 0xff;
+ *len = *len + 1;
+
+ /* If the ptr didn't advance, something went wrong */
+ if ((newp - cp) <= 0) {
+ printf("cannot not convert \"%s\"\n", cp);
+ return -EINVAL;
+ }
+ }
+}
+
+static int of_parse_prop_string(char * const *newval, int count, char *data, int *len)
+{
+ int stridx = 0;
+ char *newp = newval[0];
+
+ /*
+ * Assume it is one or more strings. Copy it into our
+ * data area for convenience (including the
+ * terminating '\0's).
+ */
+ while (stridx < count) {
+ size_t length = strlen(newp) + 1;
+
+ strcpy(data, newp);
+ data += length;
+ *len += length;
+ newp = newval[++stridx];
+ }
+
+ return 0;
+}
+
+/*
+ * Parse the user's input, partially heuristic. Valid formats:
+ * <0x00112233 4 05> - an array of cells. Numbers follow standard
+ * C conventions.
+ * [00 11 22 .. nn] - byte stream
+ * "string" - If the the value doesn't start with "<" or "[", it is
+ * treated as a string. Note that the quotes are
+ * stripped by the parser before we get the string.
+ * newval: An array of strings containing the new property as specified
+ * on the command line
+ * count: The number of strings in the array
+ * data: A bytestream to be placed in the property
+ * len: The length of the resulting bytestream
+ */
+static int of_parse_prop(char * const *newval, int count, char *data, int *len)
+{
+ char *newp; /* temporary newval char pointer */
+
+ *len = 0;
+
+ if (!count)
+ return 0;
+
+ newp = newval[0];
+
+ switch (*newp) {
+ case '<':
+ return of_parse_prop_cells(newval, count, data, len);
+ case '[':
+ return of_parse_prop_stream(newval, count, data, len);
+ default:
+ return of_parse_prop_string(newval, count, data, len);
+ }
+}
+
+static int do_of_property(int argc, char *argv[])
+{
+ int opt;
+ int delete = 0;
+ int set = 0;
+ int ret;
+ char *path = NULL, *propname = NULL;
+ struct device_node *node = NULL;
+ struct property *pp = NULL;
+
+ while ((opt = getopt(argc, argv, "ds")) > 0) {
+ switch (opt) {
+ case 'd':
+ delete = 1;
+ break;
+ case 's':
+ set = 1;
+ break;
+ default:
+ return COMMAND_ERROR_USAGE;
+ }
+ }
+
+ if (optind < argc) {
+ path = argv[optind];
+ node = of_find_node_by_path(path);
+ if (!node) {
+ printf("Cannot find nodepath %s\n", path);
+ return -ENOENT;
+ }
+ }
+
+ if (optind + 1 < argc) {
+ propname = argv[optind + 1];
+
+ pp = of_find_property(node, propname);
+ if (!set && !pp) {
+ printf("Cannot find property %s\n", propname);
+ return -ENOENT;
+ }
+ }
+
+ debug("path: %s propname: %s\n", path, propname);
+
+ if (delete) {
+ if (!node || !pp)
+ return COMMAND_ERROR_USAGE;
+
+ of_delete_property(pp);
+
+ return 0;
+ }
+
+ if (set) {
+ int num_args = argc - optind - 2;
+ int len;
+ void *data;
+
+ if (!node)
+ return COMMAND_ERROR_USAGE;
+
+ /*
+ * standard console buffer size. The result won't be bigger than the
+ * string input.
+ */
+ data = malloc(1024);
+ if (!data)
+ return -ENOMEM;
+
+ ret = of_parse_prop(&argv[optind + 2], num_args, data, &len);
+ if (ret) {
+ free(data);
+ return ret;
+ }
+
+ if (pp) {
+ free(pp->value);
+ /* limit property data to the actual size */
+ data = xrealloc(data, len);
+ pp->value = data;
+ pp->length = len;
+ } else {
+ pp = of_new_property(node, propname, data, len);
+ if (!pp) {
+ printf("Cannot create property %s\n", propname);
+ free(data);
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+BAREBOX_CMD_HELP_START(of_property)
+BAREBOX_CMD_HELP_USAGE("of_property [OPTIONS] [NODE] [PROPERTY] [VALUES]\n")
+BAREBOX_CMD_HELP_OPT ("-s", "set property to value\n")
+BAREBOX_CMD_HELP_OPT ("-d", "delete property\n")
+BAREBOX_CMD_HELP_TEXT ("\nvalid formats for values:\n")
+BAREBOX_CMD_HELP_TEXT ("<0x00112233 4 05> - an array of cells\n")
+BAREBOX_CMD_HELP_TEXT ("[00 11 22 .. nn] - byte stream\n")
+BAREBOX_CMD_HELP_TEXT ("If the value does not start with '<' or '[' it is interpreted as strings\n")
+BAREBOX_CMD_HELP_END
+
+BAREBOX_CMD_START(of_property)
+ .cmd = do_of_property,
+ .usage = "handle of properties",
+ BAREBOX_CMD_HELP(cmd_of_property_help)
+BAREBOX_CMD_END
diff --git a/commands/oftree.c b/commands/oftree.c
index 7404db56b1..ddbff3e374 100644
--- a/commands/oftree.c
+++ b/commands/oftree.c
@@ -36,20 +36,28 @@
#include <errno.h>
#include <getopt.h>
#include <init.h>
+#include <fcntl.h>
static int do_oftree(int argc, char *argv[])
{
- struct fdt_header *fdt;
+ struct fdt_header *fdt = NULL;
+ void *fdt_free = NULL;
int size;
int opt;
char *file = NULL;
const char *node = "/";
int dump = 0;
int probe = 0;
+ int load = 0;
+ int save = 0;
+ int free_of = 0;
int ret;
- while ((opt = getopt(argc, argv, "dpfn:")) > 0) {
+ while ((opt = getopt(argc, argv, "dpfn:ls")) > 0) {
switch (opt) {
+ case 'l':
+ load = 1;
+ break;
case 'd':
dump = 1;
break;
@@ -62,73 +70,121 @@ static int do_oftree(int argc, char *argv[])
}
break;
case 'f':
- free(barebox_fdt);
- barebox_fdt = NULL;
- return 0;
+ free_of = 1;
+ break;
case 'n':
node = optarg;
break;
+ case 's':
+ save = 1;
+ break;
}
}
+ if (free_of) {
+ struct device_node *root = of_get_root_node();
+
+ if (root)
+ of_free(root);
+
+ return 0;
+ }
+
if (optind < argc)
file = argv[optind];
- if (!dump && !probe)
+ if (!dump && !probe && !load && !save)
return COMMAND_ERROR_USAGE;
- if (dump) {
- if (file) {
- fdt = read_file(file, &size);
- if (!fdt) {
- printf("unable to read %s\n", file);
- return 1;
- }
+ if (save) {
+ if (!file) {
+ printf("no file given\n");
+ ret = -ENOENT;
- fdt_print(fdt, node);
- free(fdt);
- } else {
- if (barebox_fdt) {
- fdt_print(barebox_fdt, node);
- return 0;
- } else {
- return 1;
- }
+ goto out;
}
- return 0;
- }
- if (probe) {
- if (!file)
- return COMMAND_ERROR_USAGE;
+ fdt = of_get_fixed_tree(NULL);
+ if (!fdt) {
+ printf("no devicetree available\n");
+ ret = -EINVAL;
+
+ goto out;
+ }
+
+ ret = write_file(file, fdt, fdt_totalsize(fdt));
+
+ goto out;
+ }
+ if (file) {
fdt = read_file(file, &size);
if (!fdt) {
- perror("open");
+ printf("unable to read %s\n", file);
return 1;
}
- ret = of_parse_dtb(fdt);
+ fdt_free = fdt;
+ }
+
+ if (load) {
+ if (!fdt) {
+ printf("no fdt given\n");
+ ret = -ENOENT;
+
+ goto out;
+ }
+
+ ret = of_unflatten_dtb(fdt);
if (ret) {
printf("parse oftree: %s\n", strerror(-ret));
- return 1;
+ goto out;
}
+ }
- of_probe();
+ if (dump) {
+ if (fdt) {
+ ret = fdt_print(fdt, node);
+ } else {
+ struct device_node *n = of_find_node_by_path(node);
+
+ if (!n) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ of_print_nodes(n, 0);
+
+ ret = 0;
+ }
+
+ goto out;
}
- return 0;
+ if (probe) {
+ ret = of_probe();
+ if (ret)
+ goto out;
+ }
+
+ ret = 0;
+out:
+ free(fdt_free);
+
+ return ret;
}
BAREBOX_CMD_HELP_START(oftree)
-BAREBOX_CMD_HELP_USAGE("oftree [OPTIONS]\n")
-BAREBOX_CMD_HELP_OPT ("-p <FILE>", "probe devices in oftree from <file>\n")
-BAREBOX_CMD_HELP_OPT ("-d [FILE]", "dump oftree from [FILE] or the parsed tree if no file is given\n")
-BAREBOX_CMD_HELP_OPT ("-f", "free stored oftree\n")
+BAREBOX_CMD_HELP_USAGE("oftree [OPTIONS] [DTB]\n")
+BAREBOX_CMD_HELP_OPT ("-l", "Load [DTB] to internal devicetree\n")
+BAREBOX_CMD_HELP_OPT ("-p", "probe devices from stored devicetree\n")
+BAREBOX_CMD_HELP_OPT ("-d", "dump oftree from [DTB] or the parsed tree if no dtb is given\n")
+BAREBOX_CMD_HELP_OPT ("-f", "free stored devicetree\n")
+BAREBOX_CMD_HELP_OPT ("-n <node>", "specify root devicenode to dump for -d\n")
BAREBOX_CMD_HELP_END
BAREBOX_CMD_START(oftree)
.cmd = do_oftree,
- .usage = "handle oftrees",
+ .usage = "handle devicetrees",
BAREBOX_CMD_HELP(cmd_oftree_help)
BAREBOX_CMD_END