12e192b24SSimon Glass /* 22e192b24SSimon Glass * (C) Copyright 2007 32e192b24SSimon Glass * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com 42e192b24SSimon Glass * Based on code written by: 52e192b24SSimon Glass * Pantelis Antoniou <pantelis.antoniou@gmail.com> and 62e192b24SSimon Glass * Matthew McClintock <msm@freescale.com> 72e192b24SSimon Glass * 82e192b24SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 92e192b24SSimon Glass */ 102e192b24SSimon Glass 112e192b24SSimon Glass #include <common.h> 122e192b24SSimon Glass #include <command.h> 132e192b24SSimon Glass #include <linux/ctype.h> 142e192b24SSimon Glass #include <linux/types.h> 152e192b24SSimon Glass #include <asm/global_data.h> 162e192b24SSimon Glass #include <libfdt.h> 172e192b24SSimon Glass #include <fdt_support.h> 182e192b24SSimon Glass #include <mapmem.h> 192e192b24SSimon Glass #include <asm/io.h> 202e192b24SSimon Glass 212e192b24SSimon Glass #define MAX_LEVEL 32 /* how deeply nested we will go */ 222e192b24SSimon Glass #define SCRATCHPAD 1024 /* bytes of scratchpad memory */ 232e192b24SSimon Glass #ifndef CONFIG_CMD_FDT_MAX_DUMP 242e192b24SSimon Glass #define CONFIG_CMD_FDT_MAX_DUMP 64 252e192b24SSimon Glass #endif 262e192b24SSimon Glass 272e192b24SSimon Glass /* 282e192b24SSimon Glass * Global data (for the gd->bd) 292e192b24SSimon Glass */ 302e192b24SSimon Glass DECLARE_GLOBAL_DATA_PTR; 312e192b24SSimon Glass 322e192b24SSimon Glass static int fdt_valid(struct fdt_header **blobp); 332e192b24SSimon Glass static int fdt_parse_prop(char *const*newval, int count, char *data, int *len); 342e192b24SSimon Glass static int fdt_print(const char *pathp, char *prop, int depth); 352e192b24SSimon Glass static int is_printable_string(const void *data, int len); 362e192b24SSimon Glass 372e192b24SSimon Glass /* 382e192b24SSimon Glass * The working_fdt points to our working flattened device tree. 392e192b24SSimon Glass */ 402e192b24SSimon Glass struct fdt_header *working_fdt; 412e192b24SSimon Glass 422e192b24SSimon Glass void set_working_fdt_addr(ulong addr) 432e192b24SSimon Glass { 442e192b24SSimon Glass void *buf; 452e192b24SSimon Glass 462e192b24SSimon Glass buf = map_sysmem(addr, 0); 472e192b24SSimon Glass working_fdt = buf; 482e192b24SSimon Glass setenv_hex("fdtaddr", addr); 492e192b24SSimon Glass } 502e192b24SSimon Glass 512e192b24SSimon Glass /* 522e192b24SSimon Glass * Get a value from the fdt and format it to be set in the environment 532e192b24SSimon Glass */ 542e192b24SSimon Glass static int fdt_value_setenv(const void *nodep, int len, const char *var) 552e192b24SSimon Glass { 562e192b24SSimon Glass if (is_printable_string(nodep, len)) 572e192b24SSimon Glass setenv(var, (void *)nodep); 582e192b24SSimon Glass else if (len == 4) { 592e192b24SSimon Glass char buf[11]; 602e192b24SSimon Glass 612e192b24SSimon Glass sprintf(buf, "0x%08X", *(uint32_t *)nodep); 622e192b24SSimon Glass setenv(var, buf); 632e192b24SSimon Glass } else if (len%4 == 0 && len <= 20) { 642e192b24SSimon Glass /* Needed to print things like sha1 hashes. */ 652e192b24SSimon Glass char buf[41]; 662e192b24SSimon Glass int i; 672e192b24SSimon Glass 682e192b24SSimon Glass for (i = 0; i < len; i += sizeof(unsigned int)) 692e192b24SSimon Glass sprintf(buf + (i * 2), "%08x", 702e192b24SSimon Glass *(unsigned int *)(nodep + i)); 712e192b24SSimon Glass setenv(var, buf); 722e192b24SSimon Glass } else { 732e192b24SSimon Glass printf("error: unprintable value\n"); 742e192b24SSimon Glass return 1; 752e192b24SSimon Glass } 762e192b24SSimon Glass return 0; 772e192b24SSimon Glass } 782e192b24SSimon Glass 792e192b24SSimon Glass /* 802e192b24SSimon Glass * Flattened Device Tree command, see the help for parameter definitions. 812e192b24SSimon Glass */ 822e192b24SSimon Glass static int do_fdt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 832e192b24SSimon Glass { 842e192b24SSimon Glass if (argc < 2) 852e192b24SSimon Glass return CMD_RET_USAGE; 862e192b24SSimon Glass 872e192b24SSimon Glass /* 882e192b24SSimon Glass * Set the address of the fdt 892e192b24SSimon Glass */ 90*f0ed68e2SMaxime Ripard if (strncmp(argv[1], "ad", 2) == 0) { 912e192b24SSimon Glass unsigned long addr; 922e192b24SSimon Glass int control = 0; 932e192b24SSimon Glass struct fdt_header *blob; 942e192b24SSimon Glass /* 952e192b24SSimon Glass * Set the address [and length] of the fdt. 962e192b24SSimon Glass */ 972e192b24SSimon Glass argc -= 2; 982e192b24SSimon Glass argv += 2; 992e192b24SSimon Glass /* Temporary #ifdef - some archs don't have fdt_blob yet */ 1002e192b24SSimon Glass #ifdef CONFIG_OF_CONTROL 1012e192b24SSimon Glass if (argc && !strcmp(*argv, "-c")) { 1022e192b24SSimon Glass control = 1; 1032e192b24SSimon Glass argc--; 1042e192b24SSimon Glass argv++; 1052e192b24SSimon Glass } 1062e192b24SSimon Glass #endif 1072e192b24SSimon Glass if (argc == 0) { 1082e192b24SSimon Glass if (control) 1092e192b24SSimon Glass blob = (struct fdt_header *)gd->fdt_blob; 1102e192b24SSimon Glass else 1112e192b24SSimon Glass blob = working_fdt; 1122e192b24SSimon Glass if (!blob || !fdt_valid(&blob)) 1132e192b24SSimon Glass return 1; 1142e192b24SSimon Glass printf("The address of the fdt is %#08lx\n", 1152e192b24SSimon Glass control ? (ulong)map_to_sysmem(blob) : 1162e192b24SSimon Glass getenv_hex("fdtaddr", 0)); 1172e192b24SSimon Glass return 0; 1182e192b24SSimon Glass } 1192e192b24SSimon Glass 1202e192b24SSimon Glass addr = simple_strtoul(argv[0], NULL, 16); 1212e192b24SSimon Glass blob = map_sysmem(addr, 0); 1222e192b24SSimon Glass if (!fdt_valid(&blob)) 1232e192b24SSimon Glass return 1; 1242e192b24SSimon Glass if (control) 1252e192b24SSimon Glass gd->fdt_blob = blob; 1262e192b24SSimon Glass else 1272e192b24SSimon Glass set_working_fdt_addr(addr); 1282e192b24SSimon Glass 1292e192b24SSimon Glass if (argc >= 2) { 1302e192b24SSimon Glass int len; 1312e192b24SSimon Glass int err; 1322e192b24SSimon Glass /* 1332e192b24SSimon Glass * Optional new length 1342e192b24SSimon Glass */ 1352e192b24SSimon Glass len = simple_strtoul(argv[1], NULL, 16); 1362e192b24SSimon Glass if (len < fdt_totalsize(blob)) { 1372e192b24SSimon Glass printf ("New length %d < existing length %d, " 1382e192b24SSimon Glass "ignoring.\n", 1392e192b24SSimon Glass len, fdt_totalsize(blob)); 1402e192b24SSimon Glass } else { 1412e192b24SSimon Glass /* 1422e192b24SSimon Glass * Open in place with a new length. 1432e192b24SSimon Glass */ 1442e192b24SSimon Glass err = fdt_open_into(blob, blob, len); 1452e192b24SSimon Glass if (err != 0) { 1462e192b24SSimon Glass printf ("libfdt fdt_open_into(): %s\n", 1472e192b24SSimon Glass fdt_strerror(err)); 1482e192b24SSimon Glass } 1492e192b24SSimon Glass } 1502e192b24SSimon Glass } 1512e192b24SSimon Glass 1522e192b24SSimon Glass return CMD_RET_SUCCESS; 1532e192b24SSimon Glass } 1542e192b24SSimon Glass 1552e192b24SSimon Glass if (!working_fdt) { 1562e192b24SSimon Glass puts( 1572e192b24SSimon Glass "No FDT memory address configured. Please configure\n" 1582e192b24SSimon Glass "the FDT address via \"fdt addr <address>\" command.\n" 1592e192b24SSimon Glass "Aborting!\n"); 1602e192b24SSimon Glass return CMD_RET_FAILURE; 1612e192b24SSimon Glass } 1622e192b24SSimon Glass 1632e192b24SSimon Glass /* 1642e192b24SSimon Glass * Move the working_fdt 1652e192b24SSimon Glass */ 1662e192b24SSimon Glass if (strncmp(argv[1], "mo", 2) == 0) { 1672e192b24SSimon Glass struct fdt_header *newaddr; 1682e192b24SSimon Glass int len; 1692e192b24SSimon Glass int err; 1702e192b24SSimon Glass 1712e192b24SSimon Glass if (argc < 4) 1722e192b24SSimon Glass return CMD_RET_USAGE; 1732e192b24SSimon Glass 1742e192b24SSimon Glass /* 1752e192b24SSimon Glass * Set the address and length of the fdt. 1762e192b24SSimon Glass */ 1772e192b24SSimon Glass working_fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16); 1782e192b24SSimon Glass if (!fdt_valid(&working_fdt)) 1792e192b24SSimon Glass return 1; 1802e192b24SSimon Glass 1812e192b24SSimon Glass newaddr = (struct fdt_header *)simple_strtoul(argv[3],NULL,16); 1822e192b24SSimon Glass 1832e192b24SSimon Glass /* 1842e192b24SSimon Glass * If the user specifies a length, use that. Otherwise use the 1852e192b24SSimon Glass * current length. 1862e192b24SSimon Glass */ 1872e192b24SSimon Glass if (argc <= 4) { 1882e192b24SSimon Glass len = fdt_totalsize(working_fdt); 1892e192b24SSimon Glass } else { 1902e192b24SSimon Glass len = simple_strtoul(argv[4], NULL, 16); 1912e192b24SSimon Glass if (len < fdt_totalsize(working_fdt)) { 1922e192b24SSimon Glass printf ("New length 0x%X < existing length " 1932e192b24SSimon Glass "0x%X, aborting.\n", 1942e192b24SSimon Glass len, fdt_totalsize(working_fdt)); 1952e192b24SSimon Glass return 1; 1962e192b24SSimon Glass } 1972e192b24SSimon Glass } 1982e192b24SSimon Glass 1992e192b24SSimon Glass /* 2002e192b24SSimon Glass * Copy to the new location. 2012e192b24SSimon Glass */ 2022e192b24SSimon Glass err = fdt_open_into(working_fdt, newaddr, len); 2032e192b24SSimon Glass if (err != 0) { 2042e192b24SSimon Glass printf ("libfdt fdt_open_into(): %s\n", 2052e192b24SSimon Glass fdt_strerror(err)); 2062e192b24SSimon Glass return 1; 2072e192b24SSimon Glass } 2082e192b24SSimon Glass working_fdt = newaddr; 2092e192b24SSimon Glass 2102e192b24SSimon Glass /* 2112e192b24SSimon Glass * Make a new node 2122e192b24SSimon Glass */ 2132e192b24SSimon Glass } else if (strncmp(argv[1], "mk", 2) == 0) { 2142e192b24SSimon Glass char *pathp; /* path */ 2152e192b24SSimon Glass char *nodep; /* new node to add */ 2162e192b24SSimon Glass int nodeoffset; /* node offset from libfdt */ 2172e192b24SSimon Glass int err; 2182e192b24SSimon Glass 2192e192b24SSimon Glass /* 2202e192b24SSimon Glass * Parameters: Node path, new node to be appended to the path. 2212e192b24SSimon Glass */ 2222e192b24SSimon Glass if (argc < 4) 2232e192b24SSimon Glass return CMD_RET_USAGE; 2242e192b24SSimon Glass 2252e192b24SSimon Glass pathp = argv[2]; 2262e192b24SSimon Glass nodep = argv[3]; 2272e192b24SSimon Glass 2282e192b24SSimon Glass nodeoffset = fdt_path_offset (working_fdt, pathp); 2292e192b24SSimon Glass if (nodeoffset < 0) { 2302e192b24SSimon Glass /* 2312e192b24SSimon Glass * Not found or something else bad happened. 2322e192b24SSimon Glass */ 2332e192b24SSimon Glass printf ("libfdt fdt_path_offset() returned %s\n", 2342e192b24SSimon Glass fdt_strerror(nodeoffset)); 2352e192b24SSimon Glass return 1; 2362e192b24SSimon Glass } 2372e192b24SSimon Glass err = fdt_add_subnode(working_fdt, nodeoffset, nodep); 2382e192b24SSimon Glass if (err < 0) { 2392e192b24SSimon Glass printf ("libfdt fdt_add_subnode(): %s\n", 2402e192b24SSimon Glass fdt_strerror(err)); 2412e192b24SSimon Glass return 1; 2422e192b24SSimon Glass } 2432e192b24SSimon Glass 2442e192b24SSimon Glass /* 2452e192b24SSimon Glass * Set the value of a property in the working_fdt. 2462e192b24SSimon Glass */ 2472e192b24SSimon Glass } else if (argv[1][0] == 's') { 2482e192b24SSimon Glass char *pathp; /* path */ 2492e192b24SSimon Glass char *prop; /* property */ 2502e192b24SSimon Glass int nodeoffset; /* node offset from libfdt */ 2512e192b24SSimon Glass static char data[SCRATCHPAD]; /* storage for the property */ 2522e192b24SSimon Glass int len; /* new length of the property */ 2532e192b24SSimon Glass int ret; /* return value */ 2542e192b24SSimon Glass 2552e192b24SSimon Glass /* 2562e192b24SSimon Glass * Parameters: Node path, property, optional value. 2572e192b24SSimon Glass */ 2582e192b24SSimon Glass if (argc < 4) 2592e192b24SSimon Glass return CMD_RET_USAGE; 2602e192b24SSimon Glass 2612e192b24SSimon Glass pathp = argv[2]; 2622e192b24SSimon Glass prop = argv[3]; 2632e192b24SSimon Glass if (argc == 4) { 2642e192b24SSimon Glass len = 0; 2652e192b24SSimon Glass } else { 2662e192b24SSimon Glass ret = fdt_parse_prop(&argv[4], argc - 4, data, &len); 2672e192b24SSimon Glass if (ret != 0) 2682e192b24SSimon Glass return ret; 2692e192b24SSimon Glass } 2702e192b24SSimon Glass 2712e192b24SSimon Glass nodeoffset = fdt_path_offset (working_fdt, pathp); 2722e192b24SSimon Glass if (nodeoffset < 0) { 2732e192b24SSimon Glass /* 2742e192b24SSimon Glass * Not found or something else bad happened. 2752e192b24SSimon Glass */ 2762e192b24SSimon Glass printf ("libfdt fdt_path_offset() returned %s\n", 2772e192b24SSimon Glass fdt_strerror(nodeoffset)); 2782e192b24SSimon Glass return 1; 2792e192b24SSimon Glass } 2802e192b24SSimon Glass 2812e192b24SSimon Glass ret = fdt_setprop(working_fdt, nodeoffset, prop, data, len); 2822e192b24SSimon Glass if (ret < 0) { 2832e192b24SSimon Glass printf ("libfdt fdt_setprop(): %s\n", fdt_strerror(ret)); 2842e192b24SSimon Glass return 1; 2852e192b24SSimon Glass } 2862e192b24SSimon Glass 2872e192b24SSimon Glass /******************************************************************** 2882e192b24SSimon Glass * Get the value of a property in the working_fdt. 2892e192b24SSimon Glass ********************************************************************/ 2902e192b24SSimon Glass } else if (argv[1][0] == 'g') { 2912e192b24SSimon Glass char *subcmd; /* sub-command */ 2922e192b24SSimon Glass char *pathp; /* path */ 2932e192b24SSimon Glass char *prop; /* property */ 2942e192b24SSimon Glass char *var; /* variable to store result */ 2952e192b24SSimon Glass int nodeoffset; /* node offset from libfdt */ 2962e192b24SSimon Glass const void *nodep; /* property node pointer */ 2972e192b24SSimon Glass int len = 0; /* new length of the property */ 2982e192b24SSimon Glass 2992e192b24SSimon Glass /* 3002e192b24SSimon Glass * Parameters: Node path, property, optional value. 3012e192b24SSimon Glass */ 3022e192b24SSimon Glass if (argc < 5) 3032e192b24SSimon Glass return CMD_RET_USAGE; 3042e192b24SSimon Glass 3052e192b24SSimon Glass subcmd = argv[2]; 3062e192b24SSimon Glass 3072e192b24SSimon Glass if (argc < 6 && subcmd[0] != 's') 3082e192b24SSimon Glass return CMD_RET_USAGE; 3092e192b24SSimon Glass 3102e192b24SSimon Glass var = argv[3]; 3112e192b24SSimon Glass pathp = argv[4]; 3122e192b24SSimon Glass prop = argv[5]; 3132e192b24SSimon Glass 3142e192b24SSimon Glass nodeoffset = fdt_path_offset(working_fdt, pathp); 3152e192b24SSimon Glass if (nodeoffset < 0) { 3162e192b24SSimon Glass /* 3172e192b24SSimon Glass * Not found or something else bad happened. 3182e192b24SSimon Glass */ 3192e192b24SSimon Glass printf("libfdt fdt_path_offset() returned %s\n", 3202e192b24SSimon Glass fdt_strerror(nodeoffset)); 3212e192b24SSimon Glass return 1; 3222e192b24SSimon Glass } 3232e192b24SSimon Glass 3242e192b24SSimon Glass if (subcmd[0] == 'n' || (subcmd[0] == 's' && argc == 5)) { 3252e192b24SSimon Glass int reqIndex = -1; 3262e192b24SSimon Glass int startDepth = fdt_node_depth( 3272e192b24SSimon Glass working_fdt, nodeoffset); 3282e192b24SSimon Glass int curDepth = startDepth; 3292e192b24SSimon Glass int curIndex = -1; 3302e192b24SSimon Glass int nextNodeOffset = fdt_next_node( 3312e192b24SSimon Glass working_fdt, nodeoffset, &curDepth); 3322e192b24SSimon Glass 3332e192b24SSimon Glass if (subcmd[0] == 'n') 3342e192b24SSimon Glass reqIndex = simple_strtoul(argv[5], NULL, 16); 3352e192b24SSimon Glass 3362e192b24SSimon Glass while (curDepth > startDepth) { 3372e192b24SSimon Glass if (curDepth == startDepth + 1) 3382e192b24SSimon Glass curIndex++; 3392e192b24SSimon Glass if (subcmd[0] == 'n' && curIndex == reqIndex) { 3402e192b24SSimon Glass const char *nodeName = fdt_get_name( 3412e192b24SSimon Glass working_fdt, nextNodeOffset, NULL); 3422e192b24SSimon Glass 3432e192b24SSimon Glass setenv(var, (char *)nodeName); 3442e192b24SSimon Glass return 0; 3452e192b24SSimon Glass } 3462e192b24SSimon Glass nextNodeOffset = fdt_next_node( 3472e192b24SSimon Glass working_fdt, nextNodeOffset, &curDepth); 3482e192b24SSimon Glass if (nextNodeOffset < 0) 3492e192b24SSimon Glass break; 3502e192b24SSimon Glass } 3512e192b24SSimon Glass if (subcmd[0] == 's') { 3522e192b24SSimon Glass /* get the num nodes at this level */ 3532e192b24SSimon Glass setenv_ulong(var, curIndex + 1); 3542e192b24SSimon Glass } else { 3552e192b24SSimon Glass /* node index not found */ 3562e192b24SSimon Glass printf("libfdt node not found\n"); 3572e192b24SSimon Glass return 1; 3582e192b24SSimon Glass } 3592e192b24SSimon Glass } else { 3602e192b24SSimon Glass nodep = fdt_getprop( 3612e192b24SSimon Glass working_fdt, nodeoffset, prop, &len); 3622e192b24SSimon Glass if (len == 0) { 3632e192b24SSimon Glass /* no property value */ 3642e192b24SSimon Glass setenv(var, ""); 3652e192b24SSimon Glass return 0; 3662e192b24SSimon Glass } else if (len > 0) { 3672e192b24SSimon Glass if (subcmd[0] == 'v') { 3682e192b24SSimon Glass int ret; 3692e192b24SSimon Glass 3702e192b24SSimon Glass ret = fdt_value_setenv(nodep, len, var); 3712e192b24SSimon Glass if (ret != 0) 3722e192b24SSimon Glass return ret; 3732e192b24SSimon Glass } else if (subcmd[0] == 'a') { 3742e192b24SSimon Glass /* Get address */ 3752e192b24SSimon Glass char buf[11]; 3762e192b24SSimon Glass 3772e192b24SSimon Glass sprintf(buf, "0x%p", nodep); 3782e192b24SSimon Glass setenv(var, buf); 3792e192b24SSimon Glass } else if (subcmd[0] == 's') { 3802e192b24SSimon Glass /* Get size */ 3812e192b24SSimon Glass char buf[11]; 3822e192b24SSimon Glass 3832e192b24SSimon Glass sprintf(buf, "0x%08X", len); 3842e192b24SSimon Glass setenv(var, buf); 3852e192b24SSimon Glass } else 3862e192b24SSimon Glass return CMD_RET_USAGE; 3872e192b24SSimon Glass return 0; 3882e192b24SSimon Glass } else { 3892e192b24SSimon Glass printf("libfdt fdt_getprop(): %s\n", 3902e192b24SSimon Glass fdt_strerror(len)); 3912e192b24SSimon Glass return 1; 3922e192b24SSimon Glass } 3932e192b24SSimon Glass } 3942e192b24SSimon Glass 3952e192b24SSimon Glass /* 3962e192b24SSimon Glass * Print (recursive) / List (single level) 3972e192b24SSimon Glass */ 3982e192b24SSimon Glass } else if ((argv[1][0] == 'p') || (argv[1][0] == 'l')) { 3992e192b24SSimon Glass int depth = MAX_LEVEL; /* how deep to print */ 4002e192b24SSimon Glass char *pathp; /* path */ 4012e192b24SSimon Glass char *prop; /* property */ 4022e192b24SSimon Glass int ret; /* return value */ 4032e192b24SSimon Glass static char root[2] = "/"; 4042e192b24SSimon Glass 4052e192b24SSimon Glass /* 4062e192b24SSimon Glass * list is an alias for print, but limited to 1 level 4072e192b24SSimon Glass */ 4082e192b24SSimon Glass if (argv[1][0] == 'l') { 4092e192b24SSimon Glass depth = 1; 4102e192b24SSimon Glass } 4112e192b24SSimon Glass 4122e192b24SSimon Glass /* 4132e192b24SSimon Glass * Get the starting path. The root node is an oddball, 4142e192b24SSimon Glass * the offset is zero and has no name. 4152e192b24SSimon Glass */ 4162e192b24SSimon Glass if (argc == 2) 4172e192b24SSimon Glass pathp = root; 4182e192b24SSimon Glass else 4192e192b24SSimon Glass pathp = argv[2]; 4202e192b24SSimon Glass if (argc > 3) 4212e192b24SSimon Glass prop = argv[3]; 4222e192b24SSimon Glass else 4232e192b24SSimon Glass prop = NULL; 4242e192b24SSimon Glass 4252e192b24SSimon Glass ret = fdt_print(pathp, prop, depth); 4262e192b24SSimon Glass if (ret != 0) 4272e192b24SSimon Glass return ret; 4282e192b24SSimon Glass 4292e192b24SSimon Glass /* 4302e192b24SSimon Glass * Remove a property/node 4312e192b24SSimon Glass */ 4322e192b24SSimon Glass } else if (strncmp(argv[1], "rm", 2) == 0) { 4332e192b24SSimon Glass int nodeoffset; /* node offset from libfdt */ 4342e192b24SSimon Glass int err; 4352e192b24SSimon Glass 4362e192b24SSimon Glass /* 4372e192b24SSimon Glass * Get the path. The root node is an oddball, the offset 4382e192b24SSimon Glass * is zero and has no name. 4392e192b24SSimon Glass */ 4402e192b24SSimon Glass nodeoffset = fdt_path_offset (working_fdt, argv[2]); 4412e192b24SSimon Glass if (nodeoffset < 0) { 4422e192b24SSimon Glass /* 4432e192b24SSimon Glass * Not found or something else bad happened. 4442e192b24SSimon Glass */ 4452e192b24SSimon Glass printf ("libfdt fdt_path_offset() returned %s\n", 4462e192b24SSimon Glass fdt_strerror(nodeoffset)); 4472e192b24SSimon Glass return 1; 4482e192b24SSimon Glass } 4492e192b24SSimon Glass /* 4502e192b24SSimon Glass * Do the delete. A fourth parameter means delete a property, 4512e192b24SSimon Glass * otherwise delete the node. 4522e192b24SSimon Glass */ 4532e192b24SSimon Glass if (argc > 3) { 4542e192b24SSimon Glass err = fdt_delprop(working_fdt, nodeoffset, argv[3]); 4552e192b24SSimon Glass if (err < 0) { 4562e192b24SSimon Glass printf("libfdt fdt_delprop(): %s\n", 4572e192b24SSimon Glass fdt_strerror(err)); 4582e192b24SSimon Glass return err; 4592e192b24SSimon Glass } 4602e192b24SSimon Glass } else { 4612e192b24SSimon Glass err = fdt_del_node(working_fdt, nodeoffset); 4622e192b24SSimon Glass if (err < 0) { 4632e192b24SSimon Glass printf("libfdt fdt_del_node(): %s\n", 4642e192b24SSimon Glass fdt_strerror(err)); 4652e192b24SSimon Glass return err; 4662e192b24SSimon Glass } 4672e192b24SSimon Glass } 4682e192b24SSimon Glass 4692e192b24SSimon Glass /* 4702e192b24SSimon Glass * Display header info 4712e192b24SSimon Glass */ 4722e192b24SSimon Glass } else if (argv[1][0] == 'h') { 4732e192b24SSimon Glass u32 version = fdt_version(working_fdt); 4742e192b24SSimon Glass printf("magic:\t\t\t0x%x\n", fdt_magic(working_fdt)); 4752e192b24SSimon Glass printf("totalsize:\t\t0x%x (%d)\n", fdt_totalsize(working_fdt), 4762e192b24SSimon Glass fdt_totalsize(working_fdt)); 4772e192b24SSimon Glass printf("off_dt_struct:\t\t0x%x\n", 4782e192b24SSimon Glass fdt_off_dt_struct(working_fdt)); 4792e192b24SSimon Glass printf("off_dt_strings:\t\t0x%x\n", 4802e192b24SSimon Glass fdt_off_dt_strings(working_fdt)); 4812e192b24SSimon Glass printf("off_mem_rsvmap:\t\t0x%x\n", 4822e192b24SSimon Glass fdt_off_mem_rsvmap(working_fdt)); 4832e192b24SSimon Glass printf("version:\t\t%d\n", version); 4842e192b24SSimon Glass printf("last_comp_version:\t%d\n", 4852e192b24SSimon Glass fdt_last_comp_version(working_fdt)); 4862e192b24SSimon Glass if (version >= 2) 4872e192b24SSimon Glass printf("boot_cpuid_phys:\t0x%x\n", 4882e192b24SSimon Glass fdt_boot_cpuid_phys(working_fdt)); 4892e192b24SSimon Glass if (version >= 3) 4902e192b24SSimon Glass printf("size_dt_strings:\t0x%x\n", 4912e192b24SSimon Glass fdt_size_dt_strings(working_fdt)); 4922e192b24SSimon Glass if (version >= 17) 4932e192b24SSimon Glass printf("size_dt_struct:\t\t0x%x\n", 4942e192b24SSimon Glass fdt_size_dt_struct(working_fdt)); 4952e192b24SSimon Glass printf("number mem_rsv:\t\t0x%x\n", 4962e192b24SSimon Glass fdt_num_mem_rsv(working_fdt)); 4972e192b24SSimon Glass printf("\n"); 4982e192b24SSimon Glass 4992e192b24SSimon Glass /* 5002e192b24SSimon Glass * Set boot cpu id 5012e192b24SSimon Glass */ 5022e192b24SSimon Glass } else if (strncmp(argv[1], "boo", 3) == 0) { 5032e192b24SSimon Glass unsigned long tmp = simple_strtoul(argv[2], NULL, 16); 5042e192b24SSimon Glass fdt_set_boot_cpuid_phys(working_fdt, tmp); 5052e192b24SSimon Glass 5062e192b24SSimon Glass /* 5072e192b24SSimon Glass * memory command 5082e192b24SSimon Glass */ 5092e192b24SSimon Glass } else if (strncmp(argv[1], "me", 2) == 0) { 5102e192b24SSimon Glass uint64_t addr, size; 5112e192b24SSimon Glass int err; 5122e192b24SSimon Glass addr = simple_strtoull(argv[2], NULL, 16); 5132e192b24SSimon Glass size = simple_strtoull(argv[3], NULL, 16); 5142e192b24SSimon Glass err = fdt_fixup_memory(working_fdt, addr, size); 5152e192b24SSimon Glass if (err < 0) 5162e192b24SSimon Glass return err; 5172e192b24SSimon Glass 5182e192b24SSimon Glass /* 5192e192b24SSimon Glass * mem reserve commands 5202e192b24SSimon Glass */ 5212e192b24SSimon Glass } else if (strncmp(argv[1], "rs", 2) == 0) { 5222e192b24SSimon Glass if (argv[2][0] == 'p') { 5232e192b24SSimon Glass uint64_t addr, size; 5242e192b24SSimon Glass int total = fdt_num_mem_rsv(working_fdt); 5252e192b24SSimon Glass int j, err; 5262e192b24SSimon Glass printf("index\t\t start\t\t size\n"); 5272e192b24SSimon Glass printf("-------------------------------" 5282e192b24SSimon Glass "-----------------\n"); 5292e192b24SSimon Glass for (j = 0; j < total; j++) { 5302e192b24SSimon Glass err = fdt_get_mem_rsv(working_fdt, j, &addr, &size); 5312e192b24SSimon Glass if (err < 0) { 5322e192b24SSimon Glass printf("libfdt fdt_get_mem_rsv(): %s\n", 5332e192b24SSimon Glass fdt_strerror(err)); 5342e192b24SSimon Glass return err; 5352e192b24SSimon Glass } 5362e192b24SSimon Glass printf(" %x\t%08x%08x\t%08x%08x\n", j, 5372e192b24SSimon Glass (u32)(addr >> 32), 5382e192b24SSimon Glass (u32)(addr & 0xffffffff), 5392e192b24SSimon Glass (u32)(size >> 32), 5402e192b24SSimon Glass (u32)(size & 0xffffffff)); 5412e192b24SSimon Glass } 5422e192b24SSimon Glass } else if (argv[2][0] == 'a') { 5432e192b24SSimon Glass uint64_t addr, size; 5442e192b24SSimon Glass int err; 5452e192b24SSimon Glass addr = simple_strtoull(argv[3], NULL, 16); 5462e192b24SSimon Glass size = simple_strtoull(argv[4], NULL, 16); 5472e192b24SSimon Glass err = fdt_add_mem_rsv(working_fdt, addr, size); 5482e192b24SSimon Glass 5492e192b24SSimon Glass if (err < 0) { 5502e192b24SSimon Glass printf("libfdt fdt_add_mem_rsv(): %s\n", 5512e192b24SSimon Glass fdt_strerror(err)); 5522e192b24SSimon Glass return err; 5532e192b24SSimon Glass } 5542e192b24SSimon Glass } else if (argv[2][0] == 'd') { 5552e192b24SSimon Glass unsigned long idx = simple_strtoul(argv[3], NULL, 16); 5562e192b24SSimon Glass int err = fdt_del_mem_rsv(working_fdt, idx); 5572e192b24SSimon Glass 5582e192b24SSimon Glass if (err < 0) { 5592e192b24SSimon Glass printf("libfdt fdt_del_mem_rsv(): %s\n", 5602e192b24SSimon Glass fdt_strerror(err)); 5612e192b24SSimon Glass return err; 5622e192b24SSimon Glass } 5632e192b24SSimon Glass } else { 5642e192b24SSimon Glass /* Unrecognized command */ 5652e192b24SSimon Glass return CMD_RET_USAGE; 5662e192b24SSimon Glass } 5672e192b24SSimon Glass } 5682e192b24SSimon Glass #ifdef CONFIG_OF_BOARD_SETUP 5692e192b24SSimon Glass /* Call the board-specific fixup routine */ 5702e192b24SSimon Glass else if (strncmp(argv[1], "boa", 3) == 0) { 5712e192b24SSimon Glass int err = ft_board_setup(working_fdt, gd->bd); 5722e192b24SSimon Glass 5732e192b24SSimon Glass if (err) { 5742e192b24SSimon Glass printf("Failed to update board information in FDT: %s\n", 5752e192b24SSimon Glass fdt_strerror(err)); 5762e192b24SSimon Glass return CMD_RET_FAILURE; 5772e192b24SSimon Glass } 5782e192b24SSimon Glass } 5792e192b24SSimon Glass #endif 5802e192b24SSimon Glass #ifdef CONFIG_OF_SYSTEM_SETUP 5812e192b24SSimon Glass /* Call the board-specific fixup routine */ 5822e192b24SSimon Glass else if (strncmp(argv[1], "sys", 3) == 0) { 5832e192b24SSimon Glass int err = ft_system_setup(working_fdt, gd->bd); 5842e192b24SSimon Glass 5852e192b24SSimon Glass if (err) { 5862e192b24SSimon Glass printf("Failed to add system information to FDT: %s\n", 5872e192b24SSimon Glass fdt_strerror(err)); 5882e192b24SSimon Glass return CMD_RET_FAILURE; 5892e192b24SSimon Glass } 5902e192b24SSimon Glass } 5912e192b24SSimon Glass #endif 5922e192b24SSimon Glass /* Create a chosen node */ 5932e192b24SSimon Glass else if (strncmp(argv[1], "cho", 3) == 0) { 5942e192b24SSimon Glass unsigned long initrd_start = 0, initrd_end = 0; 5952e192b24SSimon Glass 5962e192b24SSimon Glass if ((argc != 2) && (argc != 4)) 5972e192b24SSimon Glass return CMD_RET_USAGE; 5982e192b24SSimon Glass 5992e192b24SSimon Glass if (argc == 4) { 6002e192b24SSimon Glass initrd_start = simple_strtoul(argv[2], NULL, 16); 6012e192b24SSimon Glass initrd_end = simple_strtoul(argv[3], NULL, 16); 6022e192b24SSimon Glass } 6032e192b24SSimon Glass 6042e192b24SSimon Glass fdt_chosen(working_fdt); 6052e192b24SSimon Glass fdt_initrd(working_fdt, initrd_start, initrd_end); 6062e192b24SSimon Glass 6072e192b24SSimon Glass #if defined(CONFIG_FIT_SIGNATURE) 6082e192b24SSimon Glass } else if (strncmp(argv[1], "che", 3) == 0) { 6092e192b24SSimon Glass int cfg_noffset; 6102e192b24SSimon Glass int ret; 6112e192b24SSimon Glass unsigned long addr; 6122e192b24SSimon Glass struct fdt_header *blob; 6132e192b24SSimon Glass 6142e192b24SSimon Glass if (!working_fdt) 6152e192b24SSimon Glass return CMD_RET_FAILURE; 6162e192b24SSimon Glass 6172e192b24SSimon Glass if (argc > 2) { 6182e192b24SSimon Glass addr = simple_strtoul(argv[2], NULL, 16); 6192e192b24SSimon Glass blob = map_sysmem(addr, 0); 6202e192b24SSimon Glass } else { 6212e192b24SSimon Glass blob = (struct fdt_header *)gd->fdt_blob; 6222e192b24SSimon Glass } 6232e192b24SSimon Glass if (!fdt_valid(&blob)) 6242e192b24SSimon Glass return 1; 6252e192b24SSimon Glass 6262e192b24SSimon Glass gd->fdt_blob = blob; 6272e192b24SSimon Glass cfg_noffset = fit_conf_get_node(working_fdt, NULL); 6282e192b24SSimon Glass if (!cfg_noffset) { 6292e192b24SSimon Glass printf("Could not find configuration node: %s\n", 6302e192b24SSimon Glass fdt_strerror(cfg_noffset)); 6312e192b24SSimon Glass return CMD_RET_FAILURE; 6322e192b24SSimon Glass } 6332e192b24SSimon Glass 6342e192b24SSimon Glass ret = fit_config_verify(working_fdt, cfg_noffset); 6352e192b24SSimon Glass if (ret == 0) 6362e192b24SSimon Glass return CMD_RET_SUCCESS; 6372e192b24SSimon Glass else 6382e192b24SSimon Glass return CMD_RET_FAILURE; 6392e192b24SSimon Glass #endif 6402e192b24SSimon Glass 6412e192b24SSimon Glass } 6422e192b24SSimon Glass /* resize the fdt */ 6432e192b24SSimon Glass else if (strncmp(argv[1], "re", 2) == 0) { 6442e192b24SSimon Glass fdt_shrink_to_minimum(working_fdt); 6452e192b24SSimon Glass } 6462e192b24SSimon Glass else { 6472e192b24SSimon Glass /* Unrecognized command */ 6482e192b24SSimon Glass return CMD_RET_USAGE; 6492e192b24SSimon Glass } 6502e192b24SSimon Glass 6512e192b24SSimon Glass return 0; 6522e192b24SSimon Glass } 6532e192b24SSimon Glass 6542e192b24SSimon Glass /****************************************************************************/ 6552e192b24SSimon Glass 6562e192b24SSimon Glass /** 6572e192b24SSimon Glass * fdt_valid() - Check if an FDT is valid. If not, change it to NULL 6582e192b24SSimon Glass * 6592e192b24SSimon Glass * @blobp: Pointer to FDT pointer 6602e192b24SSimon Glass * @return 1 if OK, 0 if bad (in which case *blobp is set to NULL) 6612e192b24SSimon Glass */ 6622e192b24SSimon Glass static int fdt_valid(struct fdt_header **blobp) 6632e192b24SSimon Glass { 6642e192b24SSimon Glass const void *blob = *blobp; 6652e192b24SSimon Glass int err; 6662e192b24SSimon Glass 6672e192b24SSimon Glass if (blob == NULL) { 6682e192b24SSimon Glass printf ("The address of the fdt is invalid (NULL).\n"); 6692e192b24SSimon Glass return 0; 6702e192b24SSimon Glass } 6712e192b24SSimon Glass 6722e192b24SSimon Glass err = fdt_check_header(blob); 6732e192b24SSimon Glass if (err == 0) 6742e192b24SSimon Glass return 1; /* valid */ 6752e192b24SSimon Glass 6762e192b24SSimon Glass if (err < 0) { 6772e192b24SSimon Glass printf("libfdt fdt_check_header(): %s", fdt_strerror(err)); 6782e192b24SSimon Glass /* 6792e192b24SSimon Glass * Be more informative on bad version. 6802e192b24SSimon Glass */ 6812e192b24SSimon Glass if (err == -FDT_ERR_BADVERSION) { 6822e192b24SSimon Glass if (fdt_version(blob) < 6832e192b24SSimon Glass FDT_FIRST_SUPPORTED_VERSION) { 6842e192b24SSimon Glass printf (" - too old, fdt %d < %d", 6852e192b24SSimon Glass fdt_version(blob), 6862e192b24SSimon Glass FDT_FIRST_SUPPORTED_VERSION); 6872e192b24SSimon Glass } 6882e192b24SSimon Glass if (fdt_last_comp_version(blob) > 6892e192b24SSimon Glass FDT_LAST_SUPPORTED_VERSION) { 6902e192b24SSimon Glass printf (" - too new, fdt %d > %d", 6912e192b24SSimon Glass fdt_version(blob), 6922e192b24SSimon Glass FDT_LAST_SUPPORTED_VERSION); 6932e192b24SSimon Glass } 6942e192b24SSimon Glass } 6952e192b24SSimon Glass printf("\n"); 6962e192b24SSimon Glass *blobp = NULL; 6972e192b24SSimon Glass return 0; 6982e192b24SSimon Glass } 6992e192b24SSimon Glass return 1; 7002e192b24SSimon Glass } 7012e192b24SSimon Glass 7022e192b24SSimon Glass /****************************************************************************/ 7032e192b24SSimon Glass 7042e192b24SSimon Glass /* 7052e192b24SSimon Glass * Parse the user's input, partially heuristic. Valid formats: 7062e192b24SSimon Glass * <0x00112233 4 05> - an array of cells. Numbers follow standard 7072e192b24SSimon Glass * C conventions. 7082e192b24SSimon Glass * [00 11 22 .. nn] - byte stream 7092e192b24SSimon Glass * "string" - If the the value doesn't start with "<" or "[", it is 7102e192b24SSimon Glass * treated as a string. Note that the quotes are 7112e192b24SSimon Glass * stripped by the parser before we get the string. 7122e192b24SSimon Glass * newval: An array of strings containing the new property as specified 7132e192b24SSimon Glass * on the command line 7142e192b24SSimon Glass * count: The number of strings in the array 7152e192b24SSimon Glass * data: A bytestream to be placed in the property 7162e192b24SSimon Glass * len: The length of the resulting bytestream 7172e192b24SSimon Glass */ 7182e192b24SSimon Glass static int fdt_parse_prop(char * const *newval, int count, char *data, int *len) 7192e192b24SSimon Glass { 7202e192b24SSimon Glass char *cp; /* temporary char pointer */ 7212e192b24SSimon Glass char *newp; /* temporary newval char pointer */ 7222e192b24SSimon Glass unsigned long tmp; /* holds converted values */ 7232e192b24SSimon Glass int stridx = 0; 7242e192b24SSimon Glass 7252e192b24SSimon Glass *len = 0; 7262e192b24SSimon Glass newp = newval[0]; 7272e192b24SSimon Glass 7282e192b24SSimon Glass /* An array of cells */ 7292e192b24SSimon Glass if (*newp == '<') { 7302e192b24SSimon Glass newp++; 7312e192b24SSimon Glass while ((*newp != '>') && (stridx < count)) { 7322e192b24SSimon Glass /* 7332e192b24SSimon Glass * Keep searching until we find that last ">" 7342e192b24SSimon Glass * That way users don't have to escape the spaces 7352e192b24SSimon Glass */ 7362e192b24SSimon Glass if (*newp == '\0') { 7372e192b24SSimon Glass newp = newval[++stridx]; 7382e192b24SSimon Glass continue; 7392e192b24SSimon Glass } 7402e192b24SSimon Glass 7412e192b24SSimon Glass cp = newp; 7422e192b24SSimon Glass tmp = simple_strtoul(cp, &newp, 0); 7432e192b24SSimon Glass *(__be32 *)data = __cpu_to_be32(tmp); 7442e192b24SSimon Glass data += 4; 7452e192b24SSimon Glass *len += 4; 7462e192b24SSimon Glass 7472e192b24SSimon Glass /* If the ptr didn't advance, something went wrong */ 7482e192b24SSimon Glass if ((newp - cp) <= 0) { 7492e192b24SSimon Glass printf("Sorry, I could not convert \"%s\"\n", 7502e192b24SSimon Glass cp); 7512e192b24SSimon Glass return 1; 7522e192b24SSimon Glass } 7532e192b24SSimon Glass 7542e192b24SSimon Glass while (*newp == ' ') 7552e192b24SSimon Glass newp++; 7562e192b24SSimon Glass } 7572e192b24SSimon Glass 7582e192b24SSimon Glass if (*newp != '>') { 7592e192b24SSimon Glass printf("Unexpected character '%c'\n", *newp); 7602e192b24SSimon Glass return 1; 7612e192b24SSimon Glass } 7622e192b24SSimon Glass } else if (*newp == '[') { 7632e192b24SSimon Glass /* 7642e192b24SSimon Glass * Byte stream. Convert the values. 7652e192b24SSimon Glass */ 7662e192b24SSimon Glass newp++; 7672e192b24SSimon Glass while ((stridx < count) && (*newp != ']')) { 7682e192b24SSimon Glass while (*newp == ' ') 7692e192b24SSimon Glass newp++; 7702e192b24SSimon Glass if (*newp == '\0') { 7712e192b24SSimon Glass newp = newval[++stridx]; 7722e192b24SSimon Glass continue; 7732e192b24SSimon Glass } 7742e192b24SSimon Glass if (!isxdigit(*newp)) 7752e192b24SSimon Glass break; 7762e192b24SSimon Glass tmp = simple_strtoul(newp, &newp, 16); 7772e192b24SSimon Glass *data++ = tmp & 0xFF; 7782e192b24SSimon Glass *len = *len + 1; 7792e192b24SSimon Glass } 7802e192b24SSimon Glass if (*newp != ']') { 7812e192b24SSimon Glass printf("Unexpected character '%c'\n", *newp); 7822e192b24SSimon Glass return 1; 7832e192b24SSimon Glass } 7842e192b24SSimon Glass } else { 7852e192b24SSimon Glass /* 7862e192b24SSimon Glass * Assume it is one or more strings. Copy it into our 7872e192b24SSimon Glass * data area for convenience (including the 7882e192b24SSimon Glass * terminating '\0's). 7892e192b24SSimon Glass */ 7902e192b24SSimon Glass while (stridx < count) { 7912e192b24SSimon Glass size_t length = strlen(newp) + 1; 7922e192b24SSimon Glass strcpy(data, newp); 7932e192b24SSimon Glass data += length; 7942e192b24SSimon Glass *len += length; 7952e192b24SSimon Glass newp = newval[++stridx]; 7962e192b24SSimon Glass } 7972e192b24SSimon Glass } 7982e192b24SSimon Glass return 0; 7992e192b24SSimon Glass } 8002e192b24SSimon Glass 8012e192b24SSimon Glass /****************************************************************************/ 8022e192b24SSimon Glass 8032e192b24SSimon Glass /* 8042e192b24SSimon Glass * Heuristic to guess if this is a string or concatenated strings. 8052e192b24SSimon Glass */ 8062e192b24SSimon Glass 8072e192b24SSimon Glass static int is_printable_string(const void *data, int len) 8082e192b24SSimon Glass { 8092e192b24SSimon Glass const char *s = data; 8102e192b24SSimon Glass 8112e192b24SSimon Glass /* zero length is not */ 8122e192b24SSimon Glass if (len == 0) 8132e192b24SSimon Glass return 0; 8142e192b24SSimon Glass 8152e192b24SSimon Glass /* must terminate with zero or '\n' */ 8162e192b24SSimon Glass if (s[len - 1] != '\0' && s[len - 1] != '\n') 8172e192b24SSimon Glass return 0; 8182e192b24SSimon Glass 8192e192b24SSimon Glass /* printable or a null byte (concatenated strings) */ 8202e192b24SSimon Glass while (((*s == '\0') || isprint(*s) || isspace(*s)) && (len > 0)) { 8212e192b24SSimon Glass /* 8222e192b24SSimon Glass * If we see a null, there are three possibilities: 8232e192b24SSimon Glass * 1) If len == 1, it is the end of the string, printable 8242e192b24SSimon Glass * 2) Next character also a null, not printable. 8252e192b24SSimon Glass * 3) Next character not a null, continue to check. 8262e192b24SSimon Glass */ 8272e192b24SSimon Glass if (s[0] == '\0') { 8282e192b24SSimon Glass if (len == 1) 8292e192b24SSimon Glass return 1; 8302e192b24SSimon Glass if (s[1] == '\0') 8312e192b24SSimon Glass return 0; 8322e192b24SSimon Glass } 8332e192b24SSimon Glass s++; 8342e192b24SSimon Glass len--; 8352e192b24SSimon Glass } 8362e192b24SSimon Glass 8372e192b24SSimon Glass /* Not the null termination, or not done yet: not printable */ 8382e192b24SSimon Glass if (*s != '\0' || (len != 0)) 8392e192b24SSimon Glass return 0; 8402e192b24SSimon Glass 8412e192b24SSimon Glass return 1; 8422e192b24SSimon Glass } 8432e192b24SSimon Glass 8442e192b24SSimon Glass 8452e192b24SSimon Glass /* 8462e192b24SSimon Glass * Print the property in the best format, a heuristic guess. Print as 8472e192b24SSimon Glass * a string, concatenated strings, a byte, word, double word, or (if all 8482e192b24SSimon Glass * else fails) it is printed as a stream of bytes. 8492e192b24SSimon Glass */ 8502e192b24SSimon Glass static void print_data(const void *data, int len) 8512e192b24SSimon Glass { 8522e192b24SSimon Glass int j; 8532e192b24SSimon Glass 8542e192b24SSimon Glass /* no data, don't print */ 8552e192b24SSimon Glass if (len == 0) 8562e192b24SSimon Glass return; 8572e192b24SSimon Glass 8582e192b24SSimon Glass /* 8592e192b24SSimon Glass * It is a string, but it may have multiple strings (embedded '\0's). 8602e192b24SSimon Glass */ 8612e192b24SSimon Glass if (is_printable_string(data, len)) { 8622e192b24SSimon Glass puts("\""); 8632e192b24SSimon Glass j = 0; 8642e192b24SSimon Glass while (j < len) { 8652e192b24SSimon Glass if (j > 0) 8662e192b24SSimon Glass puts("\", \""); 8672e192b24SSimon Glass puts(data); 8682e192b24SSimon Glass j += strlen(data) + 1; 8692e192b24SSimon Glass data += strlen(data) + 1; 8702e192b24SSimon Glass } 8712e192b24SSimon Glass puts("\""); 8722e192b24SSimon Glass return; 8732e192b24SSimon Glass } 8742e192b24SSimon Glass 8752e192b24SSimon Glass if ((len %4) == 0) { 8762e192b24SSimon Glass if (len > CONFIG_CMD_FDT_MAX_DUMP) 8772e192b24SSimon Glass printf("* 0x%p [0x%08x]", data, len); 8782e192b24SSimon Glass else { 8792e192b24SSimon Glass const __be32 *p; 8802e192b24SSimon Glass 8812e192b24SSimon Glass printf("<"); 8822e192b24SSimon Glass for (j = 0, p = data; j < len/4; j++) 8832e192b24SSimon Glass printf("0x%08x%s", fdt32_to_cpu(p[j]), 8842e192b24SSimon Glass j < (len/4 - 1) ? " " : ""); 8852e192b24SSimon Glass printf(">"); 8862e192b24SSimon Glass } 8872e192b24SSimon Glass } else { /* anything else... hexdump */ 8882e192b24SSimon Glass if (len > CONFIG_CMD_FDT_MAX_DUMP) 8892e192b24SSimon Glass printf("* 0x%p [0x%08x]", data, len); 8902e192b24SSimon Glass else { 8912e192b24SSimon Glass const u8 *s; 8922e192b24SSimon Glass 8932e192b24SSimon Glass printf("["); 8942e192b24SSimon Glass for (j = 0, s = data; j < len; j++) 8952e192b24SSimon Glass printf("%02x%s", s[j], j < len - 1 ? " " : ""); 8962e192b24SSimon Glass printf("]"); 8972e192b24SSimon Glass } 8982e192b24SSimon Glass } 8992e192b24SSimon Glass } 9002e192b24SSimon Glass 9012e192b24SSimon Glass /****************************************************************************/ 9022e192b24SSimon Glass 9032e192b24SSimon Glass /* 9042e192b24SSimon Glass * Recursively print (a portion of) the working_fdt. The depth parameter 9052e192b24SSimon Glass * determines how deeply nested the fdt is printed. 9062e192b24SSimon Glass */ 9072e192b24SSimon Glass static int fdt_print(const char *pathp, char *prop, int depth) 9082e192b24SSimon Glass { 9092e192b24SSimon Glass static char tabs[MAX_LEVEL+1] = 9102e192b24SSimon Glass "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" 9112e192b24SSimon Glass "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; 9122e192b24SSimon Glass const void *nodep; /* property node pointer */ 9132e192b24SSimon Glass int nodeoffset; /* node offset from libfdt */ 9142e192b24SSimon Glass int nextoffset; /* next node offset from libfdt */ 9152e192b24SSimon Glass uint32_t tag; /* tag */ 9162e192b24SSimon Glass int len; /* length of the property */ 9172e192b24SSimon Glass int level = 0; /* keep track of nesting level */ 9182e192b24SSimon Glass const struct fdt_property *fdt_prop; 9192e192b24SSimon Glass 9202e192b24SSimon Glass nodeoffset = fdt_path_offset (working_fdt, pathp); 9212e192b24SSimon Glass if (nodeoffset < 0) { 9222e192b24SSimon Glass /* 9232e192b24SSimon Glass * Not found or something else bad happened. 9242e192b24SSimon Glass */ 9252e192b24SSimon Glass printf ("libfdt fdt_path_offset() returned %s\n", 9262e192b24SSimon Glass fdt_strerror(nodeoffset)); 9272e192b24SSimon Glass return 1; 9282e192b24SSimon Glass } 9292e192b24SSimon Glass /* 9302e192b24SSimon Glass * The user passed in a property as well as node path. 9312e192b24SSimon Glass * Print only the given property and then return. 9322e192b24SSimon Glass */ 9332e192b24SSimon Glass if (prop) { 9342e192b24SSimon Glass nodep = fdt_getprop (working_fdt, nodeoffset, prop, &len); 9352e192b24SSimon Glass if (len == 0) { 9362e192b24SSimon Glass /* no property value */ 9372e192b24SSimon Glass printf("%s %s\n", pathp, prop); 9382e192b24SSimon Glass return 0; 9392e192b24SSimon Glass } else if (len > 0) { 9402e192b24SSimon Glass printf("%s = ", prop); 9412e192b24SSimon Glass print_data (nodep, len); 9422e192b24SSimon Glass printf("\n"); 9432e192b24SSimon Glass return 0; 9442e192b24SSimon Glass } else { 9452e192b24SSimon Glass printf ("libfdt fdt_getprop(): %s\n", 9462e192b24SSimon Glass fdt_strerror(len)); 9472e192b24SSimon Glass return 1; 9482e192b24SSimon Glass } 9492e192b24SSimon Glass } 9502e192b24SSimon Glass 9512e192b24SSimon Glass /* 9522e192b24SSimon Glass * The user passed in a node path and no property, 9532e192b24SSimon Glass * print the node and all subnodes. 9542e192b24SSimon Glass */ 9552e192b24SSimon Glass while(level >= 0) { 9562e192b24SSimon Glass tag = fdt_next_tag(working_fdt, nodeoffset, &nextoffset); 9572e192b24SSimon Glass switch(tag) { 9582e192b24SSimon Glass case FDT_BEGIN_NODE: 9592e192b24SSimon Glass pathp = fdt_get_name(working_fdt, nodeoffset, NULL); 9602e192b24SSimon Glass if (level <= depth) { 9612e192b24SSimon Glass if (pathp == NULL) 9622e192b24SSimon Glass pathp = "/* NULL pointer error */"; 9632e192b24SSimon Glass if (*pathp == '\0') 9642e192b24SSimon Glass pathp = "/"; /* root is nameless */ 9652e192b24SSimon Glass printf("%s%s {\n", 9662e192b24SSimon Glass &tabs[MAX_LEVEL - level], pathp); 9672e192b24SSimon Glass } 9682e192b24SSimon Glass level++; 9692e192b24SSimon Glass if (level >= MAX_LEVEL) { 9702e192b24SSimon Glass printf("Nested too deep, aborting.\n"); 9712e192b24SSimon Glass return 1; 9722e192b24SSimon Glass } 9732e192b24SSimon Glass break; 9742e192b24SSimon Glass case FDT_END_NODE: 9752e192b24SSimon Glass level--; 9762e192b24SSimon Glass if (level <= depth) 9772e192b24SSimon Glass printf("%s};\n", &tabs[MAX_LEVEL - level]); 9782e192b24SSimon Glass if (level == 0) { 9792e192b24SSimon Glass level = -1; /* exit the loop */ 9802e192b24SSimon Glass } 9812e192b24SSimon Glass break; 9822e192b24SSimon Glass case FDT_PROP: 9832e192b24SSimon Glass fdt_prop = fdt_offset_ptr(working_fdt, nodeoffset, 9842e192b24SSimon Glass sizeof(*fdt_prop)); 9852e192b24SSimon Glass pathp = fdt_string(working_fdt, 9862e192b24SSimon Glass fdt32_to_cpu(fdt_prop->nameoff)); 9872e192b24SSimon Glass len = fdt32_to_cpu(fdt_prop->len); 9882e192b24SSimon Glass nodep = fdt_prop->data; 9892e192b24SSimon Glass if (len < 0) { 9902e192b24SSimon Glass printf ("libfdt fdt_getprop(): %s\n", 9912e192b24SSimon Glass fdt_strerror(len)); 9922e192b24SSimon Glass return 1; 9932e192b24SSimon Glass } else if (len == 0) { 9942e192b24SSimon Glass /* the property has no value */ 9952e192b24SSimon Glass if (level <= depth) 9962e192b24SSimon Glass printf("%s%s;\n", 9972e192b24SSimon Glass &tabs[MAX_LEVEL - level], 9982e192b24SSimon Glass pathp); 9992e192b24SSimon Glass } else { 10002e192b24SSimon Glass if (level <= depth) { 10012e192b24SSimon Glass printf("%s%s = ", 10022e192b24SSimon Glass &tabs[MAX_LEVEL - level], 10032e192b24SSimon Glass pathp); 10042e192b24SSimon Glass print_data (nodep, len); 10052e192b24SSimon Glass printf(";\n"); 10062e192b24SSimon Glass } 10072e192b24SSimon Glass } 10082e192b24SSimon Glass break; 10092e192b24SSimon Glass case FDT_NOP: 10102e192b24SSimon Glass printf("%s/* NOP */\n", &tabs[MAX_LEVEL - level]); 10112e192b24SSimon Glass break; 10122e192b24SSimon Glass case FDT_END: 10132e192b24SSimon Glass return 1; 10142e192b24SSimon Glass default: 10152e192b24SSimon Glass if (level <= depth) 10162e192b24SSimon Glass printf("Unknown tag 0x%08X\n", tag); 10172e192b24SSimon Glass return 1; 10182e192b24SSimon Glass } 10192e192b24SSimon Glass nodeoffset = nextoffset; 10202e192b24SSimon Glass } 10212e192b24SSimon Glass return 0; 10222e192b24SSimon Glass } 10232e192b24SSimon Glass 10242e192b24SSimon Glass /********************************************************************/ 10252e192b24SSimon Glass #ifdef CONFIG_SYS_LONGHELP 10262e192b24SSimon Glass static char fdt_help_text[] = 10272e192b24SSimon Glass "addr [-c] <addr> [<length>] - Set the [control] fdt location to <addr>\n" 10282e192b24SSimon Glass #ifdef CONFIG_OF_BOARD_SETUP 10292e192b24SSimon Glass "fdt boardsetup - Do board-specific set up\n" 10302e192b24SSimon Glass #endif 10312e192b24SSimon Glass #ifdef CONFIG_OF_SYSTEM_SETUP 10322e192b24SSimon Glass "fdt systemsetup - Do system-specific set up\n" 10332e192b24SSimon Glass #endif 10342e192b24SSimon Glass "fdt move <fdt> <newaddr> <length> - Copy the fdt to <addr> and make it active\n" 10352e192b24SSimon Glass "fdt resize - Resize fdt to size + padding to 4k addr\n" 10362e192b24SSimon Glass "fdt print <path> [<prop>] - Recursive print starting at <path>\n" 10372e192b24SSimon Glass "fdt list <path> [<prop>] - Print one level starting at <path>\n" 10382e192b24SSimon Glass "fdt get value <var> <path> <prop> - Get <property> and store in <var>\n" 10392e192b24SSimon Glass "fdt get name <var> <path> <index> - Get name of node <index> and store in <var>\n" 10402e192b24SSimon Glass "fdt get addr <var> <path> <prop> - Get start address of <property> and store in <var>\n" 10412e192b24SSimon Glass "fdt get size <var> <path> [<prop>] - Get size of [<property>] or num nodes and store in <var>\n" 10422e192b24SSimon Glass "fdt set <path> <prop> [<val>] - Set <property> [to <val>]\n" 10432e192b24SSimon Glass "fdt mknode <path> <node> - Create a new node after <path>\n" 10442e192b24SSimon Glass "fdt rm <path> [<prop>] - Delete the node or <property>\n" 10452e192b24SSimon Glass "fdt header - Display header info\n" 10462e192b24SSimon Glass "fdt bootcpu <id> - Set boot cpuid\n" 10472e192b24SSimon Glass "fdt memory <addr> <size> - Add/Update memory node\n" 10482e192b24SSimon Glass "fdt rsvmem print - Show current mem reserves\n" 10492e192b24SSimon Glass "fdt rsvmem add <addr> <size> - Add a mem reserve\n" 10502e192b24SSimon Glass "fdt rsvmem delete <index> - Delete a mem reserves\n" 10512e192b24SSimon Glass "fdt chosen [<start> <end>] - Add/update the /chosen branch in the tree\n" 10522e192b24SSimon Glass " <start>/<end> - initrd start/end addr\n" 10532e192b24SSimon Glass #if defined(CONFIG_FIT_SIGNATURE) 10542e192b24SSimon Glass "fdt checksign [<addr>] - check FIT signature\n" 10552e192b24SSimon Glass " <start> - addr of key blob\n" 10562e192b24SSimon Glass " default gd->fdt_blob\n" 10572e192b24SSimon Glass #endif 10581cc0a9f4SRobert P. J. Day "NOTE: Dereference aliases by omitting the leading '/', " 10592e192b24SSimon Glass "e.g. fdt print ethernet0."; 10602e192b24SSimon Glass #endif 10612e192b24SSimon Glass 10622e192b24SSimon Glass U_BOOT_CMD( 10632e192b24SSimon Glass fdt, 255, 0, do_fdt, 10642e192b24SSimon Glass "flattened device tree utility commands", fdt_help_text 10652e192b24SSimon Glass ); 1066