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