fdt: Add get commands to fdt
authorJoe Hershberger <joe.hershberger@ni.com>
Fri, 17 Aug 2012 10:34:37 +0000 (10:34 +0000)
committerGerald Van Baren <gvb@unssw.com>
Mon, 15 Oct 2012 23:20:22 +0000 (19:20 -0400)
Add commands to access data in the fdt.  This allows data from a dtb
or itb to be accessed from the shell scripts.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
common/cmd_fdt.c

index 699441b51ad31f48d4eed59357fb0c608dccde52..2997452370e29672e1207b951c2e3179cf19f4d9 100644 (file)
@@ -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"