|
@@ -47,6 +47,7 @@ DECLARE_GLOBAL_DATA_PTR;
|
|
|
static int fdt_valid(void);
|
|
|
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);
|
|
|
|
|
|
/*
|
|
|
* The working_fdt points to our working flattened device tree.
|
|
@@ -63,6 +64,34 @@ void set_working_fdt_addr(void *addr)
|
|
|
setenv("fdtaddr", buf);
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Get a value from the fdt and format it to be set in the environment
|
|
|
+ */
|
|
|
+static int fdt_value_setenv(const void *nodep, int len, const char *var)
|
|
|
+{
|
|
|
+ if (is_printable_string(nodep, len))
|
|
|
+ setenv(var, (void *)nodep);
|
|
|
+ else if (len == 4) {
|
|
|
+ char buf[11];
|
|
|
+
|
|
|
+ sprintf(buf, "0x%08X", *(uint32_t *)nodep);
|
|
|
+ setenv(var, buf);
|
|
|
+ } else if (len%4 == 0 && len <= 20) {
|
|
|
+ /* Needed to print things like sha1 hashes. */
|
|
|
+ char buf[41];
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < len; i += sizeof(unsigned int))
|
|
|
+ sprintf(buf + (i * 2), "%08x",
|
|
|
+ *(unsigned int *)(nodep + i));
|
|
|
+ setenv(var, buf);
|
|
|
+ } else {
|
|
|
+ printf("error: unprintable value\n");
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Flattened Device Tree command, see the help for parameter definitions.
|
|
|
*/
|
|
@@ -253,6 +282,117 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
+ /********************************************************************
|
|
|
+ * Get the value of a property in the working_fdt.
|
|
|
+ ********************************************************************/
|
|
|
+ } else if (argv[1][0] == 'g') {
|
|
|
+ char *subcmd; /* sub-command */
|
|
|
+ char *pathp; /* path */
|
|
|
+ char *prop; /* property */
|
|
|
+ char *var; /* variable to store result */
|
|
|
+ int nodeoffset; /* node offset from libfdt */
|
|
|
+ const void *nodep; /* property node pointer */
|
|
|
+ int len = 0; /* new length of the property */
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Parameters: Node path, property, optional value.
|
|
|
+ */
|
|
|
+ if (argc < 5)
|
|
|
+ return CMD_RET_USAGE;
|
|
|
+
|
|
|
+ subcmd = argv[2];
|
|
|
+
|
|
|
+ if (argc < 6 && subcmd[0] != 's')
|
|
|
+ return CMD_RET_USAGE;
|
|
|
+
|
|
|
+ var = argv[3];
|
|
|
+ pathp = argv[4];
|
|
|
+ prop = argv[5];
|
|
|
+
|
|
|
+ nodeoffset = fdt_path_offset(working_fdt, pathp);
|
|
|
+ if (nodeoffset < 0) {
|
|
|
+ /*
|
|
|
+ * Not found or something else bad happened.
|
|
|
+ */
|
|
|
+ printf("libfdt fdt_path_offset() returned %s\n",
|
|
|
+ fdt_strerror(nodeoffset));
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (subcmd[0] == 'n' || (subcmd[0] == 's' && argc == 5)) {
|
|
|
+ int reqIndex = -1;
|
|
|
+ int startDepth = fdt_node_depth(
|
|
|
+ working_fdt, nodeoffset);
|
|
|
+ int curDepth = startDepth;
|
|
|
+ int curIndex = -1;
|
|
|
+ int nextNodeOffset = fdt_next_node(
|
|
|
+ working_fdt, nodeoffset, &curDepth);
|
|
|
+
|
|
|
+ if (subcmd[0] == 'n')
|
|
|
+ reqIndex = simple_strtoul(argv[5], NULL, 16);
|
|
|
+
|
|
|
+ while (curDepth > startDepth) {
|
|
|
+ if (curDepth == startDepth + 1)
|
|
|
+ curIndex++;
|
|
|
+ if (subcmd[0] == 'n' && curIndex == reqIndex) {
|
|
|
+ const char *nodeName = fdt_get_name(
|
|
|
+ working_fdt, nextNodeOffset, NULL);
|
|
|
+
|
|
|
+ setenv(var, (char *)nodeName);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ nextNodeOffset = fdt_next_node(
|
|
|
+ working_fdt, nextNodeOffset, &curDepth);
|
|
|
+ if (nextNodeOffset < 0)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (subcmd[0] == 's') {
|
|
|
+ /* get the num nodes at this level */
|
|
|
+ char buf[11];
|
|
|
+
|
|
|
+ sprintf(buf, "%d", curIndex + 1);
|
|
|
+ setenv(var, buf);
|
|
|
+ } else {
|
|
|
+ /* node index not found */
|
|
|
+ printf("libfdt node not found\n");
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ nodep = fdt_getprop(
|
|
|
+ working_fdt, nodeoffset, prop, &len);
|
|
|
+ if (len == 0) {
|
|
|
+ /* no property value */
|
|
|
+ setenv(var, "");
|
|
|
+ return 0;
|
|
|
+ } else if (len > 0) {
|
|
|
+ if (subcmd[0] == 'v') {
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = fdt_value_setenv(nodep, len, var);
|
|
|
+ if (ret != 0)
|
|
|
+ return ret;
|
|
|
+ } else if (subcmd[0] == 'a') {
|
|
|
+ /* Get address */
|
|
|
+ char buf[11];
|
|
|
+
|
|
|
+ sprintf(buf, "0x%08X", (uint32_t)nodep);
|
|
|
+ setenv(var, buf);
|
|
|
+ } else if (subcmd[0] == 's') {
|
|
|
+ /* Get size */
|
|
|
+ char buf[11];
|
|
|
+
|
|
|
+ sprintf(buf, "0x%08X", len);
|
|
|
+ setenv(var, buf);
|
|
|
+ } else
|
|
|
+ return CMD_RET_USAGE;
|
|
|
+ return 0;
|
|
|
+ } else {
|
|
|
+ printf("libfdt fdt_getprop(): %s\n",
|
|
|
+ fdt_strerror(len));
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
* Print (recursive) / List (single level)
|
|
|
*/
|
|
@@ -836,6 +976,10 @@ U_BOOT_CMD(
|
|
|
"fdt resize - Resize fdt to size + padding to 4k addr\n"
|
|
|
"fdt print <path> [<prop>] - Recursive print starting at <path>\n"
|
|
|
"fdt list <path> [<prop>] - Print one level starting at <path>\n"
|
|
|
+ "fdt get value <var> <path> <prop> - Get <property> and store in <var>\n"
|
|
|
+ "fdt get name <var> <path> <index> - Get name of node <index> and store in <var>\n"
|
|
|
+ "fdt get addr <var> <path> <prop> - Get start address of <property> and store in <var>\n"
|
|
|
+ "fdt get size <var> <path> [<prop>] - Get size of [<property>] or num nodes and store in <var>\n"
|
|
|
"fdt set <path> <prop> [<val>] - Set <property> [to <val>]\n"
|
|
|
"fdt mknode <path> <node> - Create a new node after <path>\n"
|
|
|
"fdt rm <path> [<prop>] - Delete the node or <property>\n"
|