1*2e192b24SSimon Glass /* 2*2e192b24SSimon Glass * (C) Copyright 2007 3*2e192b24SSimon Glass * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com 4*2e192b24SSimon Glass * Based on code written by: 5*2e192b24SSimon Glass * Pantelis Antoniou <pantelis.antoniou@gmail.com> and 6*2e192b24SSimon Glass * Matthew McClintock <msm@freescale.com> 7*2e192b24SSimon Glass * 8*2e192b24SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 9*2e192b24SSimon Glass */ 10*2e192b24SSimon Glass 11*2e192b24SSimon Glass #include <common.h> 12*2e192b24SSimon Glass #include <command.h> 13*2e192b24SSimon Glass #include <linux/ctype.h> 14*2e192b24SSimon Glass #include <linux/types.h> 15*2e192b24SSimon Glass #include <asm/global_data.h> 16*2e192b24SSimon Glass #include <libfdt.h> 17*2e192b24SSimon Glass #include <fdt_support.h> 18*2e192b24SSimon Glass #include <mapmem.h> 19*2e192b24SSimon Glass #include <asm/io.h> 20*2e192b24SSimon Glass 21*2e192b24SSimon Glass #define MAX_LEVEL 32 /* how deeply nested we will go */ 22*2e192b24SSimon Glass #define SCRATCHPAD 1024 /* bytes of scratchpad memory */ 23*2e192b24SSimon Glass #ifndef CONFIG_CMD_FDT_MAX_DUMP 24*2e192b24SSimon Glass #define CONFIG_CMD_FDT_MAX_DUMP 64 25*2e192b24SSimon Glass #endif 26*2e192b24SSimon Glass 27*2e192b24SSimon Glass /* 28*2e192b24SSimon Glass * Global data (for the gd->bd) 29*2e192b24SSimon Glass */ 30*2e192b24SSimon Glass DECLARE_GLOBAL_DATA_PTR; 31*2e192b24SSimon Glass 32*2e192b24SSimon Glass static int fdt_valid(struct fdt_header **blobp); 33*2e192b24SSimon Glass static int fdt_parse_prop(char *const*newval, int count, char *data, int *len); 34*2e192b24SSimon Glass static int fdt_print(const char *pathp, char *prop, int depth); 35*2e192b24SSimon Glass static int is_printable_string(const void *data, int len); 36*2e192b24SSimon Glass 37*2e192b24SSimon Glass /* 38*2e192b24SSimon Glass * The working_fdt points to our working flattened device tree. 39*2e192b24SSimon Glass */ 40*2e192b24SSimon Glass struct fdt_header *working_fdt; 41*2e192b24SSimon Glass 42*2e192b24SSimon Glass void set_working_fdt_addr(ulong addr) 43*2e192b24SSimon Glass { 44*2e192b24SSimon Glass void *buf; 45*2e192b24SSimon Glass 46*2e192b24SSimon Glass buf = map_sysmem(addr, 0); 47*2e192b24SSimon Glass working_fdt = buf; 48*2e192b24SSimon Glass setenv_hex("fdtaddr", addr); 49*2e192b24SSimon Glass } 50*2e192b24SSimon Glass 51*2e192b24SSimon Glass /* 52*2e192b24SSimon Glass * Get a value from the fdt and format it to be set in the environment 53*2e192b24SSimon Glass */ 54*2e192b24SSimon Glass static int fdt_value_setenv(const void *nodep, int len, const char *var) 55*2e192b24SSimon Glass { 56*2e192b24SSimon Glass if (is_printable_string(nodep, len)) 57*2e192b24SSimon Glass setenv(var, (void *)nodep); 58*2e192b24SSimon Glass else if (len == 4) { 59*2e192b24SSimon Glass char buf[11]; 60*2e192b24SSimon Glass 61*2e192b24SSimon Glass sprintf(buf, "0x%08X", *(uint32_t *)nodep); 62*2e192b24SSimon Glass setenv(var, buf); 63*2e192b24SSimon Glass } else if (len%4 == 0 && len <= 20) { 64*2e192b24SSimon Glass /* Needed to print things like sha1 hashes. */ 65*2e192b24SSimon Glass char buf[41]; 66*2e192b24SSimon Glass int i; 67*2e192b24SSimon Glass 68*2e192b24SSimon Glass for (i = 0; i < len; i += sizeof(unsigned int)) 69*2e192b24SSimon Glass sprintf(buf + (i * 2), "%08x", 70*2e192b24SSimon Glass *(unsigned int *)(nodep + i)); 71*2e192b24SSimon Glass setenv(var, buf); 72*2e192b24SSimon Glass } else { 73*2e192b24SSimon Glass printf("error: unprintable value\n"); 74*2e192b24SSimon Glass return 1; 75*2e192b24SSimon Glass } 76*2e192b24SSimon Glass return 0; 77*2e192b24SSimon Glass } 78*2e192b24SSimon Glass 79*2e192b24SSimon Glass /* 80*2e192b24SSimon Glass * Flattened Device Tree command, see the help for parameter definitions. 81*2e192b24SSimon Glass */ 82*2e192b24SSimon Glass static int do_fdt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 83*2e192b24SSimon Glass { 84*2e192b24SSimon Glass if (argc < 2) 85*2e192b24SSimon Glass return CMD_RET_USAGE; 86*2e192b24SSimon Glass 87*2e192b24SSimon Glass /* 88*2e192b24SSimon Glass * Set the address of the fdt 89*2e192b24SSimon Glass */ 90*2e192b24SSimon Glass if (argv[1][0] == 'a') { 91*2e192b24SSimon Glass unsigned long addr; 92*2e192b24SSimon Glass int control = 0; 93*2e192b24SSimon Glass struct fdt_header *blob; 94*2e192b24SSimon Glass /* 95*2e192b24SSimon Glass * Set the address [and length] of the fdt. 96*2e192b24SSimon Glass */ 97*2e192b24SSimon Glass argc -= 2; 98*2e192b24SSimon Glass argv += 2; 99*2e192b24SSimon Glass /* Temporary #ifdef - some archs don't have fdt_blob yet */ 100*2e192b24SSimon Glass #ifdef CONFIG_OF_CONTROL 101*2e192b24SSimon Glass if (argc && !strcmp(*argv, "-c")) { 102*2e192b24SSimon Glass control = 1; 103*2e192b24SSimon Glass argc--; 104*2e192b24SSimon Glass argv++; 105*2e192b24SSimon Glass } 106*2e192b24SSimon Glass #endif 107*2e192b24SSimon Glass if (argc == 0) { 108*2e192b24SSimon Glass if (control) 109*2e192b24SSimon Glass blob = (struct fdt_header *)gd->fdt_blob; 110*2e192b24SSimon Glass else 111*2e192b24SSimon Glass blob = working_fdt; 112*2e192b24SSimon Glass if (!blob || !fdt_valid(&blob)) 113*2e192b24SSimon Glass return 1; 114*2e192b24SSimon Glass printf("The address of the fdt is %#08lx\n", 115*2e192b24SSimon Glass control ? (ulong)map_to_sysmem(blob) : 116*2e192b24SSimon Glass getenv_hex("fdtaddr", 0)); 117*2e192b24SSimon Glass return 0; 118*2e192b24SSimon Glass } 119*2e192b24SSimon Glass 120*2e192b24SSimon Glass addr = simple_strtoul(argv[0], NULL, 16); 121*2e192b24SSimon Glass blob = map_sysmem(addr, 0); 122*2e192b24SSimon Glass if (!fdt_valid(&blob)) 123*2e192b24SSimon Glass return 1; 124*2e192b24SSimon Glass if (control) 125*2e192b24SSimon Glass gd->fdt_blob = blob; 126*2e192b24SSimon Glass else 127*2e192b24SSimon Glass set_working_fdt_addr(addr); 128*2e192b24SSimon Glass 129*2e192b24SSimon Glass if (argc >= 2) { 130*2e192b24SSimon Glass int len; 131*2e192b24SSimon Glass int err; 132*2e192b24SSimon Glass /* 133*2e192b24SSimon Glass * Optional new length 134*2e192b24SSimon Glass */ 135*2e192b24SSimon Glass len = simple_strtoul(argv[1], NULL, 16); 136*2e192b24SSimon Glass if (len < fdt_totalsize(blob)) { 137*2e192b24SSimon Glass printf ("New length %d < existing length %d, " 138*2e192b24SSimon Glass "ignoring.\n", 139*2e192b24SSimon Glass len, fdt_totalsize(blob)); 140*2e192b24SSimon Glass } else { 141*2e192b24SSimon Glass /* 142*2e192b24SSimon Glass * Open in place with a new length. 143*2e192b24SSimon Glass */ 144*2e192b24SSimon Glass err = fdt_open_into(blob, blob, len); 145*2e192b24SSimon Glass if (err != 0) { 146*2e192b24SSimon Glass printf ("libfdt fdt_open_into(): %s\n", 147*2e192b24SSimon Glass fdt_strerror(err)); 148*2e192b24SSimon Glass } 149*2e192b24SSimon Glass } 150*2e192b24SSimon Glass } 151*2e192b24SSimon Glass 152*2e192b24SSimon Glass return CMD_RET_SUCCESS; 153*2e192b24SSimon Glass } 154*2e192b24SSimon Glass 155*2e192b24SSimon Glass if (!working_fdt) { 156*2e192b24SSimon Glass puts( 157*2e192b24SSimon Glass "No FDT memory address configured. Please configure\n" 158*2e192b24SSimon Glass "the FDT address via \"fdt addr <address>\" command.\n" 159*2e192b24SSimon Glass "Aborting!\n"); 160*2e192b24SSimon Glass return CMD_RET_FAILURE; 161*2e192b24SSimon Glass } 162*2e192b24SSimon Glass 163*2e192b24SSimon Glass /* 164*2e192b24SSimon Glass * Move the working_fdt 165*2e192b24SSimon Glass */ 166*2e192b24SSimon Glass if (strncmp(argv[1], "mo", 2) == 0) { 167*2e192b24SSimon Glass struct fdt_header *newaddr; 168*2e192b24SSimon Glass int len; 169*2e192b24SSimon Glass int err; 170*2e192b24SSimon Glass 171*2e192b24SSimon Glass if (argc < 4) 172*2e192b24SSimon Glass return CMD_RET_USAGE; 173*2e192b24SSimon Glass 174*2e192b24SSimon Glass /* 175*2e192b24SSimon Glass * Set the address and length of the fdt. 176*2e192b24SSimon Glass */ 177*2e192b24SSimon Glass working_fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16); 178*2e192b24SSimon Glass if (!fdt_valid(&working_fdt)) 179*2e192b24SSimon Glass return 1; 180*2e192b24SSimon Glass 181*2e192b24SSimon Glass newaddr = (struct fdt_header *)simple_strtoul(argv[3],NULL,16); 182*2e192b24SSimon Glass 183*2e192b24SSimon Glass /* 184*2e192b24SSimon Glass * If the user specifies a length, use that. Otherwise use the 185*2e192b24SSimon Glass * current length. 186*2e192b24SSimon Glass */ 187*2e192b24SSimon Glass if (argc <= 4) { 188*2e192b24SSimon Glass len = fdt_totalsize(working_fdt); 189*2e192b24SSimon Glass } else { 190*2e192b24SSimon Glass len = simple_strtoul(argv[4], NULL, 16); 191*2e192b24SSimon Glass if (len < fdt_totalsize(working_fdt)) { 192*2e192b24SSimon Glass printf ("New length 0x%X < existing length " 193*2e192b24SSimon Glass "0x%X, aborting.\n", 194*2e192b24SSimon Glass len, fdt_totalsize(working_fdt)); 195*2e192b24SSimon Glass return 1; 196*2e192b24SSimon Glass } 197*2e192b24SSimon Glass } 198*2e192b24SSimon Glass 199*2e192b24SSimon Glass /* 200*2e192b24SSimon Glass * Copy to the new location. 201*2e192b24SSimon Glass */ 202*2e192b24SSimon Glass err = fdt_open_into(working_fdt, newaddr, len); 203*2e192b24SSimon Glass if (err != 0) { 204*2e192b24SSimon Glass printf ("libfdt fdt_open_into(): %s\n", 205*2e192b24SSimon Glass fdt_strerror(err)); 206*2e192b24SSimon Glass return 1; 207*2e192b24SSimon Glass } 208*2e192b24SSimon Glass working_fdt = newaddr; 209*2e192b24SSimon Glass 210*2e192b24SSimon Glass /* 211*2e192b24SSimon Glass * Make a new node 212*2e192b24SSimon Glass */ 213*2e192b24SSimon Glass } else if (strncmp(argv[1], "mk", 2) == 0) { 214*2e192b24SSimon Glass char *pathp; /* path */ 215*2e192b24SSimon Glass char *nodep; /* new node to add */ 216*2e192b24SSimon Glass int nodeoffset; /* node offset from libfdt */ 217*2e192b24SSimon Glass int err; 218*2e192b24SSimon Glass 219*2e192b24SSimon Glass /* 220*2e192b24SSimon Glass * Parameters: Node path, new node to be appended to the path. 221*2e192b24SSimon Glass */ 222*2e192b24SSimon Glass if (argc < 4) 223*2e192b24SSimon Glass return CMD_RET_USAGE; 224*2e192b24SSimon Glass 225*2e192b24SSimon Glass pathp = argv[2]; 226*2e192b24SSimon Glass nodep = argv[3]; 227*2e192b24SSimon Glass 228*2e192b24SSimon Glass nodeoffset = fdt_path_offset (working_fdt, pathp); 229*2e192b24SSimon Glass if (nodeoffset < 0) { 230*2e192b24SSimon Glass /* 231*2e192b24SSimon Glass * Not found or something else bad happened. 232*2e192b24SSimon Glass */ 233*2e192b24SSimon Glass printf ("libfdt fdt_path_offset() returned %s\n", 234*2e192b24SSimon Glass fdt_strerror(nodeoffset)); 235*2e192b24SSimon Glass return 1; 236*2e192b24SSimon Glass } 237*2e192b24SSimon Glass err = fdt_add_subnode(working_fdt, nodeoffset, nodep); 238*2e192b24SSimon Glass if (err < 0) { 239*2e192b24SSimon Glass printf ("libfdt fdt_add_subnode(): %s\n", 240*2e192b24SSimon Glass fdt_strerror(err)); 241*2e192b24SSimon Glass return 1; 242*2e192b24SSimon Glass } 243*2e192b24SSimon Glass 244*2e192b24SSimon Glass /* 245*2e192b24SSimon Glass * Set the value of a property in the working_fdt. 246*2e192b24SSimon Glass */ 247*2e192b24SSimon Glass } else if (argv[1][0] == 's') { 248*2e192b24SSimon Glass char *pathp; /* path */ 249*2e192b24SSimon Glass char *prop; /* property */ 250*2e192b24SSimon Glass int nodeoffset; /* node offset from libfdt */ 251*2e192b24SSimon Glass static char data[SCRATCHPAD]; /* storage for the property */ 252*2e192b24SSimon Glass int len; /* new length of the property */ 253*2e192b24SSimon Glass int ret; /* return value */ 254*2e192b24SSimon Glass 255*2e192b24SSimon Glass /* 256*2e192b24SSimon Glass * Parameters: Node path, property, optional value. 257*2e192b24SSimon Glass */ 258*2e192b24SSimon Glass if (argc < 4) 259*2e192b24SSimon Glass return CMD_RET_USAGE; 260*2e192b24SSimon Glass 261*2e192b24SSimon Glass pathp = argv[2]; 262*2e192b24SSimon Glass prop = argv[3]; 263*2e192b24SSimon Glass if (argc == 4) { 264*2e192b24SSimon Glass len = 0; 265*2e192b24SSimon Glass } else { 266*2e192b24SSimon Glass ret = fdt_parse_prop(&argv[4], argc - 4, data, &len); 267*2e192b24SSimon Glass if (ret != 0) 268*2e192b24SSimon Glass return ret; 269*2e192b24SSimon Glass } 270*2e192b24SSimon Glass 271*2e192b24SSimon Glass nodeoffset = fdt_path_offset (working_fdt, pathp); 272*2e192b24SSimon Glass if (nodeoffset < 0) { 273*2e192b24SSimon Glass /* 274*2e192b24SSimon Glass * Not found or something else bad happened. 275*2e192b24SSimon Glass */ 276*2e192b24SSimon Glass printf ("libfdt fdt_path_offset() returned %s\n", 277*2e192b24SSimon Glass fdt_strerror(nodeoffset)); 278*2e192b24SSimon Glass return 1; 279*2e192b24SSimon Glass } 280*2e192b24SSimon Glass 281*2e192b24SSimon Glass ret = fdt_setprop(working_fdt, nodeoffset, prop, data, len); 282*2e192b24SSimon Glass if (ret < 0) { 283*2e192b24SSimon Glass printf ("libfdt fdt_setprop(): %s\n", fdt_strerror(ret)); 284*2e192b24SSimon Glass return 1; 285*2e192b24SSimon Glass } 286*2e192b24SSimon Glass 287*2e192b24SSimon Glass /******************************************************************** 288*2e192b24SSimon Glass * Get the value of a property in the working_fdt. 289*2e192b24SSimon Glass ********************************************************************/ 290*2e192b24SSimon Glass } else if (argv[1][0] == 'g') { 291*2e192b24SSimon Glass char *subcmd; /* sub-command */ 292*2e192b24SSimon Glass char *pathp; /* path */ 293*2e192b24SSimon Glass char *prop; /* property */ 294*2e192b24SSimon Glass char *var; /* variable to store result */ 295*2e192b24SSimon Glass int nodeoffset; /* node offset from libfdt */ 296*2e192b24SSimon Glass const void *nodep; /* property node pointer */ 297*2e192b24SSimon Glass int len = 0; /* new length of the property */ 298*2e192b24SSimon Glass 299*2e192b24SSimon Glass /* 300*2e192b24SSimon Glass * Parameters: Node path, property, optional value. 301*2e192b24SSimon Glass */ 302*2e192b24SSimon Glass if (argc < 5) 303*2e192b24SSimon Glass return CMD_RET_USAGE; 304*2e192b24SSimon Glass 305*2e192b24SSimon Glass subcmd = argv[2]; 306*2e192b24SSimon Glass 307*2e192b24SSimon Glass if (argc < 6 && subcmd[0] != 's') 308*2e192b24SSimon Glass return CMD_RET_USAGE; 309*2e192b24SSimon Glass 310*2e192b24SSimon Glass var = argv[3]; 311*2e192b24SSimon Glass pathp = argv[4]; 312*2e192b24SSimon Glass prop = argv[5]; 313*2e192b24SSimon Glass 314*2e192b24SSimon Glass nodeoffset = fdt_path_offset(working_fdt, pathp); 315*2e192b24SSimon Glass if (nodeoffset < 0) { 316*2e192b24SSimon Glass /* 317*2e192b24SSimon Glass * Not found or something else bad happened. 318*2e192b24SSimon Glass */ 319*2e192b24SSimon Glass printf("libfdt fdt_path_offset() returned %s\n", 320*2e192b24SSimon Glass fdt_strerror(nodeoffset)); 321*2e192b24SSimon Glass return 1; 322*2e192b24SSimon Glass } 323*2e192b24SSimon Glass 324*2e192b24SSimon Glass if (subcmd[0] == 'n' || (subcmd[0] == 's' && argc == 5)) { 325*2e192b24SSimon Glass int reqIndex = -1; 326*2e192b24SSimon Glass int startDepth = fdt_node_depth( 327*2e192b24SSimon Glass working_fdt, nodeoffset); 328*2e192b24SSimon Glass int curDepth = startDepth; 329*2e192b24SSimon Glass int curIndex = -1; 330*2e192b24SSimon Glass int nextNodeOffset = fdt_next_node( 331*2e192b24SSimon Glass working_fdt, nodeoffset, &curDepth); 332*2e192b24SSimon Glass 333*2e192b24SSimon Glass if (subcmd[0] == 'n') 334*2e192b24SSimon Glass reqIndex = simple_strtoul(argv[5], NULL, 16); 335*2e192b24SSimon Glass 336*2e192b24SSimon Glass while (curDepth > startDepth) { 337*2e192b24SSimon Glass if (curDepth == startDepth + 1) 338*2e192b24SSimon Glass curIndex++; 339*2e192b24SSimon Glass if (subcmd[0] == 'n' && curIndex == reqIndex) { 340*2e192b24SSimon Glass const char *nodeName = fdt_get_name( 341*2e192b24SSimon Glass working_fdt, nextNodeOffset, NULL); 342*2e192b24SSimon Glass 343*2e192b24SSimon Glass setenv(var, (char *)nodeName); 344*2e192b24SSimon Glass return 0; 345*2e192b24SSimon Glass } 346*2e192b24SSimon Glass nextNodeOffset = fdt_next_node( 347*2e192b24SSimon Glass working_fdt, nextNodeOffset, &curDepth); 348*2e192b24SSimon Glass if (nextNodeOffset < 0) 349*2e192b24SSimon Glass break; 350*2e192b24SSimon Glass } 351*2e192b24SSimon Glass if (subcmd[0] == 's') { 352*2e192b24SSimon Glass /* get the num nodes at this level */ 353*2e192b24SSimon Glass setenv_ulong(var, curIndex + 1); 354*2e192b24SSimon Glass } else { 355*2e192b24SSimon Glass /* node index not found */ 356*2e192b24SSimon Glass printf("libfdt node not found\n"); 357*2e192b24SSimon Glass return 1; 358*2e192b24SSimon Glass } 359*2e192b24SSimon Glass } else { 360*2e192b24SSimon Glass nodep = fdt_getprop( 361*2e192b24SSimon Glass working_fdt, nodeoffset, prop, &len); 362*2e192b24SSimon Glass if (len == 0) { 363*2e192b24SSimon Glass /* no property value */ 364*2e192b24SSimon Glass setenv(var, ""); 365*2e192b24SSimon Glass return 0; 366*2e192b24SSimon Glass } else if (len > 0) { 367*2e192b24SSimon Glass if (subcmd[0] == 'v') { 368*2e192b24SSimon Glass int ret; 369*2e192b24SSimon Glass 370*2e192b24SSimon Glass ret = fdt_value_setenv(nodep, len, var); 371*2e192b24SSimon Glass if (ret != 0) 372*2e192b24SSimon Glass return ret; 373*2e192b24SSimon Glass } else if (subcmd[0] == 'a') { 374*2e192b24SSimon Glass /* Get address */ 375*2e192b24SSimon Glass char buf[11]; 376*2e192b24SSimon Glass 377*2e192b24SSimon Glass sprintf(buf, "0x%p", nodep); 378*2e192b24SSimon Glass setenv(var, buf); 379*2e192b24SSimon Glass } else if (subcmd[0] == 's') { 380*2e192b24SSimon Glass /* Get size */ 381*2e192b24SSimon Glass char buf[11]; 382*2e192b24SSimon Glass 383*2e192b24SSimon Glass sprintf(buf, "0x%08X", len); 384*2e192b24SSimon Glass setenv(var, buf); 385*2e192b24SSimon Glass } else 386*2e192b24SSimon Glass return CMD_RET_USAGE; 387*2e192b24SSimon Glass return 0; 388*2e192b24SSimon Glass } else { 389*2e192b24SSimon Glass printf("libfdt fdt_getprop(): %s\n", 390*2e192b24SSimon Glass fdt_strerror(len)); 391*2e192b24SSimon Glass return 1; 392*2e192b24SSimon Glass } 393*2e192b24SSimon Glass } 394*2e192b24SSimon Glass 395*2e192b24SSimon Glass /* 396*2e192b24SSimon Glass * Print (recursive) / List (single level) 397*2e192b24SSimon Glass */ 398*2e192b24SSimon Glass } else if ((argv[1][0] == 'p') || (argv[1][0] == 'l')) { 399*2e192b24SSimon Glass int depth = MAX_LEVEL; /* how deep to print */ 400*2e192b24SSimon Glass char *pathp; /* path */ 401*2e192b24SSimon Glass char *prop; /* property */ 402*2e192b24SSimon Glass int ret; /* return value */ 403*2e192b24SSimon Glass static char root[2] = "/"; 404*2e192b24SSimon Glass 405*2e192b24SSimon Glass /* 406*2e192b24SSimon Glass * list is an alias for print, but limited to 1 level 407*2e192b24SSimon Glass */ 408*2e192b24SSimon Glass if (argv[1][0] == 'l') { 409*2e192b24SSimon Glass depth = 1; 410*2e192b24SSimon Glass } 411*2e192b24SSimon Glass 412*2e192b24SSimon Glass /* 413*2e192b24SSimon Glass * Get the starting path. The root node is an oddball, 414*2e192b24SSimon Glass * the offset is zero and has no name. 415*2e192b24SSimon Glass */ 416*2e192b24SSimon Glass if (argc == 2) 417*2e192b24SSimon Glass pathp = root; 418*2e192b24SSimon Glass else 419*2e192b24SSimon Glass pathp = argv[2]; 420*2e192b24SSimon Glass if (argc > 3) 421*2e192b24SSimon Glass prop = argv[3]; 422*2e192b24SSimon Glass else 423*2e192b24SSimon Glass prop = NULL; 424*2e192b24SSimon Glass 425*2e192b24SSimon Glass ret = fdt_print(pathp, prop, depth); 426*2e192b24SSimon Glass if (ret != 0) 427*2e192b24SSimon Glass return ret; 428*2e192b24SSimon Glass 429*2e192b24SSimon Glass /* 430*2e192b24SSimon Glass * Remove a property/node 431*2e192b24SSimon Glass */ 432*2e192b24SSimon Glass } else if (strncmp(argv[1], "rm", 2) == 0) { 433*2e192b24SSimon Glass int nodeoffset; /* node offset from libfdt */ 434*2e192b24SSimon Glass int err; 435*2e192b24SSimon Glass 436*2e192b24SSimon Glass /* 437*2e192b24SSimon Glass * Get the path. The root node is an oddball, the offset 438*2e192b24SSimon Glass * is zero and has no name. 439*2e192b24SSimon Glass */ 440*2e192b24SSimon Glass nodeoffset = fdt_path_offset (working_fdt, argv[2]); 441*2e192b24SSimon Glass if (nodeoffset < 0) { 442*2e192b24SSimon Glass /* 443*2e192b24SSimon Glass * Not found or something else bad happened. 444*2e192b24SSimon Glass */ 445*2e192b24SSimon Glass printf ("libfdt fdt_path_offset() returned %s\n", 446*2e192b24SSimon Glass fdt_strerror(nodeoffset)); 447*2e192b24SSimon Glass return 1; 448*2e192b24SSimon Glass } 449*2e192b24SSimon Glass /* 450*2e192b24SSimon Glass * Do the delete. A fourth parameter means delete a property, 451*2e192b24SSimon Glass * otherwise delete the node. 452*2e192b24SSimon Glass */ 453*2e192b24SSimon Glass if (argc > 3) { 454*2e192b24SSimon Glass err = fdt_delprop(working_fdt, nodeoffset, argv[3]); 455*2e192b24SSimon Glass if (err < 0) { 456*2e192b24SSimon Glass printf("libfdt fdt_delprop(): %s\n", 457*2e192b24SSimon Glass fdt_strerror(err)); 458*2e192b24SSimon Glass return err; 459*2e192b24SSimon Glass } 460*2e192b24SSimon Glass } else { 461*2e192b24SSimon Glass err = fdt_del_node(working_fdt, nodeoffset); 462*2e192b24SSimon Glass if (err < 0) { 463*2e192b24SSimon Glass printf("libfdt fdt_del_node(): %s\n", 464*2e192b24SSimon Glass fdt_strerror(err)); 465*2e192b24SSimon Glass return err; 466*2e192b24SSimon Glass } 467*2e192b24SSimon Glass } 468*2e192b24SSimon Glass 469*2e192b24SSimon Glass /* 470*2e192b24SSimon Glass * Display header info 471*2e192b24SSimon Glass */ 472*2e192b24SSimon Glass } else if (argv[1][0] == 'h') { 473*2e192b24SSimon Glass u32 version = fdt_version(working_fdt); 474*2e192b24SSimon Glass printf("magic:\t\t\t0x%x\n", fdt_magic(working_fdt)); 475*2e192b24SSimon Glass printf("totalsize:\t\t0x%x (%d)\n", fdt_totalsize(working_fdt), 476*2e192b24SSimon Glass fdt_totalsize(working_fdt)); 477*2e192b24SSimon Glass printf("off_dt_struct:\t\t0x%x\n", 478*2e192b24SSimon Glass fdt_off_dt_struct(working_fdt)); 479*2e192b24SSimon Glass printf("off_dt_strings:\t\t0x%x\n", 480*2e192b24SSimon Glass fdt_off_dt_strings(working_fdt)); 481*2e192b24SSimon Glass printf("off_mem_rsvmap:\t\t0x%x\n", 482*2e192b24SSimon Glass fdt_off_mem_rsvmap(working_fdt)); 483*2e192b24SSimon Glass printf("version:\t\t%d\n", version); 484*2e192b24SSimon Glass printf("last_comp_version:\t%d\n", 485*2e192b24SSimon Glass fdt_last_comp_version(working_fdt)); 486*2e192b24SSimon Glass if (version >= 2) 487*2e192b24SSimon Glass printf("boot_cpuid_phys:\t0x%x\n", 488*2e192b24SSimon Glass fdt_boot_cpuid_phys(working_fdt)); 489*2e192b24SSimon Glass if (version >= 3) 490*2e192b24SSimon Glass printf("size_dt_strings:\t0x%x\n", 491*2e192b24SSimon Glass fdt_size_dt_strings(working_fdt)); 492*2e192b24SSimon Glass if (version >= 17) 493*2e192b24SSimon Glass printf("size_dt_struct:\t\t0x%x\n", 494*2e192b24SSimon Glass fdt_size_dt_struct(working_fdt)); 495*2e192b24SSimon Glass printf("number mem_rsv:\t\t0x%x\n", 496*2e192b24SSimon Glass fdt_num_mem_rsv(working_fdt)); 497*2e192b24SSimon Glass printf("\n"); 498*2e192b24SSimon Glass 499*2e192b24SSimon Glass /* 500*2e192b24SSimon Glass * Set boot cpu id 501*2e192b24SSimon Glass */ 502*2e192b24SSimon Glass } else if (strncmp(argv[1], "boo", 3) == 0) { 503*2e192b24SSimon Glass unsigned long tmp = simple_strtoul(argv[2], NULL, 16); 504*2e192b24SSimon Glass fdt_set_boot_cpuid_phys(working_fdt, tmp); 505*2e192b24SSimon Glass 506*2e192b24SSimon Glass /* 507*2e192b24SSimon Glass * memory command 508*2e192b24SSimon Glass */ 509*2e192b24SSimon Glass } else if (strncmp(argv[1], "me", 2) == 0) { 510*2e192b24SSimon Glass uint64_t addr, size; 511*2e192b24SSimon Glass int err; 512*2e192b24SSimon Glass addr = simple_strtoull(argv[2], NULL, 16); 513*2e192b24SSimon Glass size = simple_strtoull(argv[3], NULL, 16); 514*2e192b24SSimon Glass err = fdt_fixup_memory(working_fdt, addr, size); 515*2e192b24SSimon Glass if (err < 0) 516*2e192b24SSimon Glass return err; 517*2e192b24SSimon Glass 518*2e192b24SSimon Glass /* 519*2e192b24SSimon Glass * mem reserve commands 520*2e192b24SSimon Glass */ 521*2e192b24SSimon Glass } else if (strncmp(argv[1], "rs", 2) == 0) { 522*2e192b24SSimon Glass if (argv[2][0] == 'p') { 523*2e192b24SSimon Glass uint64_t addr, size; 524*2e192b24SSimon Glass int total = fdt_num_mem_rsv(working_fdt); 525*2e192b24SSimon Glass int j, err; 526*2e192b24SSimon Glass printf("index\t\t start\t\t size\n"); 527*2e192b24SSimon Glass printf("-------------------------------" 528*2e192b24SSimon Glass "-----------------\n"); 529*2e192b24SSimon Glass for (j = 0; j < total; j++) { 530*2e192b24SSimon Glass err = fdt_get_mem_rsv(working_fdt, j, &addr, &size); 531*2e192b24SSimon Glass if (err < 0) { 532*2e192b24SSimon Glass printf("libfdt fdt_get_mem_rsv(): %s\n", 533*2e192b24SSimon Glass fdt_strerror(err)); 534*2e192b24SSimon Glass return err; 535*2e192b24SSimon Glass } 536*2e192b24SSimon Glass printf(" %x\t%08x%08x\t%08x%08x\n", j, 537*2e192b24SSimon Glass (u32)(addr >> 32), 538*2e192b24SSimon Glass (u32)(addr & 0xffffffff), 539*2e192b24SSimon Glass (u32)(size >> 32), 540*2e192b24SSimon Glass (u32)(size & 0xffffffff)); 541*2e192b24SSimon Glass } 542*2e192b24SSimon Glass } else if (argv[2][0] == 'a') { 543*2e192b24SSimon Glass uint64_t addr, size; 544*2e192b24SSimon Glass int err; 545*2e192b24SSimon Glass addr = simple_strtoull(argv[3], NULL, 16); 546*2e192b24SSimon Glass size = simple_strtoull(argv[4], NULL, 16); 547*2e192b24SSimon Glass err = fdt_add_mem_rsv(working_fdt, addr, size); 548*2e192b24SSimon Glass 549*2e192b24SSimon Glass if (err < 0) { 550*2e192b24SSimon Glass printf("libfdt fdt_add_mem_rsv(): %s\n", 551*2e192b24SSimon Glass fdt_strerror(err)); 552*2e192b24SSimon Glass return err; 553*2e192b24SSimon Glass } 554*2e192b24SSimon Glass } else if (argv[2][0] == 'd') { 555*2e192b24SSimon Glass unsigned long idx = simple_strtoul(argv[3], NULL, 16); 556*2e192b24SSimon Glass int err = fdt_del_mem_rsv(working_fdt, idx); 557*2e192b24SSimon Glass 558*2e192b24SSimon Glass if (err < 0) { 559*2e192b24SSimon Glass printf("libfdt fdt_del_mem_rsv(): %s\n", 560*2e192b24SSimon Glass fdt_strerror(err)); 561*2e192b24SSimon Glass return err; 562*2e192b24SSimon Glass } 563*2e192b24SSimon Glass } else { 564*2e192b24SSimon Glass /* Unrecognized command */ 565*2e192b24SSimon Glass return CMD_RET_USAGE; 566*2e192b24SSimon Glass } 567*2e192b24SSimon Glass } 568*2e192b24SSimon Glass #ifdef CONFIG_OF_BOARD_SETUP 569*2e192b24SSimon Glass /* Call the board-specific fixup routine */ 570*2e192b24SSimon Glass else if (strncmp(argv[1], "boa", 3) == 0) { 571*2e192b24SSimon Glass int err = ft_board_setup(working_fdt, gd->bd); 572*2e192b24SSimon Glass 573*2e192b24SSimon Glass if (err) { 574*2e192b24SSimon Glass printf("Failed to update board information in FDT: %s\n", 575*2e192b24SSimon Glass fdt_strerror(err)); 576*2e192b24SSimon Glass return CMD_RET_FAILURE; 577*2e192b24SSimon Glass } 578*2e192b24SSimon Glass } 579*2e192b24SSimon Glass #endif 580*2e192b24SSimon Glass #ifdef CONFIG_OF_SYSTEM_SETUP 581*2e192b24SSimon Glass /* Call the board-specific fixup routine */ 582*2e192b24SSimon Glass else if (strncmp(argv[1], "sys", 3) == 0) { 583*2e192b24SSimon Glass int err = ft_system_setup(working_fdt, gd->bd); 584*2e192b24SSimon Glass 585*2e192b24SSimon Glass if (err) { 586*2e192b24SSimon Glass printf("Failed to add system information to FDT: %s\n", 587*2e192b24SSimon Glass fdt_strerror(err)); 588*2e192b24SSimon Glass return CMD_RET_FAILURE; 589*2e192b24SSimon Glass } 590*2e192b24SSimon Glass } 591*2e192b24SSimon Glass #endif 592*2e192b24SSimon Glass /* Create a chosen node */ 593*2e192b24SSimon Glass else if (strncmp(argv[1], "cho", 3) == 0) { 594*2e192b24SSimon Glass unsigned long initrd_start = 0, initrd_end = 0; 595*2e192b24SSimon Glass 596*2e192b24SSimon Glass if ((argc != 2) && (argc != 4)) 597*2e192b24SSimon Glass return CMD_RET_USAGE; 598*2e192b24SSimon Glass 599*2e192b24SSimon Glass if (argc == 4) { 600*2e192b24SSimon Glass initrd_start = simple_strtoul(argv[2], NULL, 16); 601*2e192b24SSimon Glass initrd_end = simple_strtoul(argv[3], NULL, 16); 602*2e192b24SSimon Glass } 603*2e192b24SSimon Glass 604*2e192b24SSimon Glass fdt_chosen(working_fdt); 605*2e192b24SSimon Glass fdt_initrd(working_fdt, initrd_start, initrd_end); 606*2e192b24SSimon Glass 607*2e192b24SSimon Glass #if defined(CONFIG_FIT_SIGNATURE) 608*2e192b24SSimon Glass } else if (strncmp(argv[1], "che", 3) == 0) { 609*2e192b24SSimon Glass int cfg_noffset; 610*2e192b24SSimon Glass int ret; 611*2e192b24SSimon Glass unsigned long addr; 612*2e192b24SSimon Glass struct fdt_header *blob; 613*2e192b24SSimon Glass 614*2e192b24SSimon Glass if (!working_fdt) 615*2e192b24SSimon Glass return CMD_RET_FAILURE; 616*2e192b24SSimon Glass 617*2e192b24SSimon Glass if (argc > 2) { 618*2e192b24SSimon Glass addr = simple_strtoul(argv[2], NULL, 16); 619*2e192b24SSimon Glass blob = map_sysmem(addr, 0); 620*2e192b24SSimon Glass } else { 621*2e192b24SSimon Glass blob = (struct fdt_header *)gd->fdt_blob; 622*2e192b24SSimon Glass } 623*2e192b24SSimon Glass if (!fdt_valid(&blob)) 624*2e192b24SSimon Glass return 1; 625*2e192b24SSimon Glass 626*2e192b24SSimon Glass gd->fdt_blob = blob; 627*2e192b24SSimon Glass cfg_noffset = fit_conf_get_node(working_fdt, NULL); 628*2e192b24SSimon Glass if (!cfg_noffset) { 629*2e192b24SSimon Glass printf("Could not find configuration node: %s\n", 630*2e192b24SSimon Glass fdt_strerror(cfg_noffset)); 631*2e192b24SSimon Glass return CMD_RET_FAILURE; 632*2e192b24SSimon Glass } 633*2e192b24SSimon Glass 634*2e192b24SSimon Glass ret = fit_config_verify(working_fdt, cfg_noffset); 635*2e192b24SSimon Glass if (ret == 0) 636*2e192b24SSimon Glass return CMD_RET_SUCCESS; 637*2e192b24SSimon Glass else 638*2e192b24SSimon Glass return CMD_RET_FAILURE; 639*2e192b24SSimon Glass #endif 640*2e192b24SSimon Glass 641*2e192b24SSimon Glass } 642*2e192b24SSimon Glass /* resize the fdt */ 643*2e192b24SSimon Glass else if (strncmp(argv[1], "re", 2) == 0) { 644*2e192b24SSimon Glass fdt_shrink_to_minimum(working_fdt); 645*2e192b24SSimon Glass } 646*2e192b24SSimon Glass else { 647*2e192b24SSimon Glass /* Unrecognized command */ 648*2e192b24SSimon Glass return CMD_RET_USAGE; 649*2e192b24SSimon Glass } 650*2e192b24SSimon Glass 651*2e192b24SSimon Glass return 0; 652*2e192b24SSimon Glass } 653*2e192b24SSimon Glass 654*2e192b24SSimon Glass /****************************************************************************/ 655*2e192b24SSimon Glass 656*2e192b24SSimon Glass /** 657*2e192b24SSimon Glass * fdt_valid() - Check if an FDT is valid. If not, change it to NULL 658*2e192b24SSimon Glass * 659*2e192b24SSimon Glass * @blobp: Pointer to FDT pointer 660*2e192b24SSimon Glass * @return 1 if OK, 0 if bad (in which case *blobp is set to NULL) 661*2e192b24SSimon Glass */ 662*2e192b24SSimon Glass static int fdt_valid(struct fdt_header **blobp) 663*2e192b24SSimon Glass { 664*2e192b24SSimon Glass const void *blob = *blobp; 665*2e192b24SSimon Glass int err; 666*2e192b24SSimon Glass 667*2e192b24SSimon Glass if (blob == NULL) { 668*2e192b24SSimon Glass printf ("The address of the fdt is invalid (NULL).\n"); 669*2e192b24SSimon Glass return 0; 670*2e192b24SSimon Glass } 671*2e192b24SSimon Glass 672*2e192b24SSimon Glass err = fdt_check_header(blob); 673*2e192b24SSimon Glass if (err == 0) 674*2e192b24SSimon Glass return 1; /* valid */ 675*2e192b24SSimon Glass 676*2e192b24SSimon Glass if (err < 0) { 677*2e192b24SSimon Glass printf("libfdt fdt_check_header(): %s", fdt_strerror(err)); 678*2e192b24SSimon Glass /* 679*2e192b24SSimon Glass * Be more informative on bad version. 680*2e192b24SSimon Glass */ 681*2e192b24SSimon Glass if (err == -FDT_ERR_BADVERSION) { 682*2e192b24SSimon Glass if (fdt_version(blob) < 683*2e192b24SSimon Glass FDT_FIRST_SUPPORTED_VERSION) { 684*2e192b24SSimon Glass printf (" - too old, fdt %d < %d", 685*2e192b24SSimon Glass fdt_version(blob), 686*2e192b24SSimon Glass FDT_FIRST_SUPPORTED_VERSION); 687*2e192b24SSimon Glass } 688*2e192b24SSimon Glass if (fdt_last_comp_version(blob) > 689*2e192b24SSimon Glass FDT_LAST_SUPPORTED_VERSION) { 690*2e192b24SSimon Glass printf (" - too new, fdt %d > %d", 691*2e192b24SSimon Glass fdt_version(blob), 692*2e192b24SSimon Glass FDT_LAST_SUPPORTED_VERSION); 693*2e192b24SSimon Glass } 694*2e192b24SSimon Glass } 695*2e192b24SSimon Glass printf("\n"); 696*2e192b24SSimon Glass *blobp = NULL; 697*2e192b24SSimon Glass return 0; 698*2e192b24SSimon Glass } 699*2e192b24SSimon Glass return 1; 700*2e192b24SSimon Glass } 701*2e192b24SSimon Glass 702*2e192b24SSimon Glass /****************************************************************************/ 703*2e192b24SSimon Glass 704*2e192b24SSimon Glass /* 705*2e192b24SSimon Glass * Parse the user's input, partially heuristic. Valid formats: 706*2e192b24SSimon Glass * <0x00112233 4 05> - an array of cells. Numbers follow standard 707*2e192b24SSimon Glass * C conventions. 708*2e192b24SSimon Glass * [00 11 22 .. nn] - byte stream 709*2e192b24SSimon Glass * "string" - If the the value doesn't start with "<" or "[", it is 710*2e192b24SSimon Glass * treated as a string. Note that the quotes are 711*2e192b24SSimon Glass * stripped by the parser before we get the string. 712*2e192b24SSimon Glass * newval: An array of strings containing the new property as specified 713*2e192b24SSimon Glass * on the command line 714*2e192b24SSimon Glass * count: The number of strings in the array 715*2e192b24SSimon Glass * data: A bytestream to be placed in the property 716*2e192b24SSimon Glass * len: The length of the resulting bytestream 717*2e192b24SSimon Glass */ 718*2e192b24SSimon Glass static int fdt_parse_prop(char * const *newval, int count, char *data, int *len) 719*2e192b24SSimon Glass { 720*2e192b24SSimon Glass char *cp; /* temporary char pointer */ 721*2e192b24SSimon Glass char *newp; /* temporary newval char pointer */ 722*2e192b24SSimon Glass unsigned long tmp; /* holds converted values */ 723*2e192b24SSimon Glass int stridx = 0; 724*2e192b24SSimon Glass 725*2e192b24SSimon Glass *len = 0; 726*2e192b24SSimon Glass newp = newval[0]; 727*2e192b24SSimon Glass 728*2e192b24SSimon Glass /* An array of cells */ 729*2e192b24SSimon Glass if (*newp == '<') { 730*2e192b24SSimon Glass newp++; 731*2e192b24SSimon Glass while ((*newp != '>') && (stridx < count)) { 732*2e192b24SSimon Glass /* 733*2e192b24SSimon Glass * Keep searching until we find that last ">" 734*2e192b24SSimon Glass * That way users don't have to escape the spaces 735*2e192b24SSimon Glass */ 736*2e192b24SSimon Glass if (*newp == '\0') { 737*2e192b24SSimon Glass newp = newval[++stridx]; 738*2e192b24SSimon Glass continue; 739*2e192b24SSimon Glass } 740*2e192b24SSimon Glass 741*2e192b24SSimon Glass cp = newp; 742*2e192b24SSimon Glass tmp = simple_strtoul(cp, &newp, 0); 743*2e192b24SSimon Glass *(__be32 *)data = __cpu_to_be32(tmp); 744*2e192b24SSimon Glass data += 4; 745*2e192b24SSimon Glass *len += 4; 746*2e192b24SSimon Glass 747*2e192b24SSimon Glass /* If the ptr didn't advance, something went wrong */ 748*2e192b24SSimon Glass if ((newp - cp) <= 0) { 749*2e192b24SSimon Glass printf("Sorry, I could not convert \"%s\"\n", 750*2e192b24SSimon Glass cp); 751*2e192b24SSimon Glass return 1; 752*2e192b24SSimon Glass } 753*2e192b24SSimon Glass 754*2e192b24SSimon Glass while (*newp == ' ') 755*2e192b24SSimon Glass newp++; 756*2e192b24SSimon Glass } 757*2e192b24SSimon Glass 758*2e192b24SSimon Glass if (*newp != '>') { 759*2e192b24SSimon Glass printf("Unexpected character '%c'\n", *newp); 760*2e192b24SSimon Glass return 1; 761*2e192b24SSimon Glass } 762*2e192b24SSimon Glass } else if (*newp == '[') { 763*2e192b24SSimon Glass /* 764*2e192b24SSimon Glass * Byte stream. Convert the values. 765*2e192b24SSimon Glass */ 766*2e192b24SSimon Glass newp++; 767*2e192b24SSimon Glass while ((stridx < count) && (*newp != ']')) { 768*2e192b24SSimon Glass while (*newp == ' ') 769*2e192b24SSimon Glass newp++; 770*2e192b24SSimon Glass if (*newp == '\0') { 771*2e192b24SSimon Glass newp = newval[++stridx]; 772*2e192b24SSimon Glass continue; 773*2e192b24SSimon Glass } 774*2e192b24SSimon Glass if (!isxdigit(*newp)) 775*2e192b24SSimon Glass break; 776*2e192b24SSimon Glass tmp = simple_strtoul(newp, &newp, 16); 777*2e192b24SSimon Glass *data++ = tmp & 0xFF; 778*2e192b24SSimon Glass *len = *len + 1; 779*2e192b24SSimon Glass } 780*2e192b24SSimon Glass if (*newp != ']') { 781*2e192b24SSimon Glass printf("Unexpected character '%c'\n", *newp); 782*2e192b24SSimon Glass return 1; 783*2e192b24SSimon Glass } 784*2e192b24SSimon Glass } else { 785*2e192b24SSimon Glass /* 786*2e192b24SSimon Glass * Assume it is one or more strings. Copy it into our 787*2e192b24SSimon Glass * data area for convenience (including the 788*2e192b24SSimon Glass * terminating '\0's). 789*2e192b24SSimon Glass */ 790*2e192b24SSimon Glass while (stridx < count) { 791*2e192b24SSimon Glass size_t length = strlen(newp) + 1; 792*2e192b24SSimon Glass strcpy(data, newp); 793*2e192b24SSimon Glass data += length; 794*2e192b24SSimon Glass *len += length; 795*2e192b24SSimon Glass newp = newval[++stridx]; 796*2e192b24SSimon Glass } 797*2e192b24SSimon Glass } 798*2e192b24SSimon Glass return 0; 799*2e192b24SSimon Glass } 800*2e192b24SSimon Glass 801*2e192b24SSimon Glass /****************************************************************************/ 802*2e192b24SSimon Glass 803*2e192b24SSimon Glass /* 804*2e192b24SSimon Glass * Heuristic to guess if this is a string or concatenated strings. 805*2e192b24SSimon Glass */ 806*2e192b24SSimon Glass 807*2e192b24SSimon Glass static int is_printable_string(const void *data, int len) 808*2e192b24SSimon Glass { 809*2e192b24SSimon Glass const char *s = data; 810*2e192b24SSimon Glass 811*2e192b24SSimon Glass /* zero length is not */ 812*2e192b24SSimon Glass if (len == 0) 813*2e192b24SSimon Glass return 0; 814*2e192b24SSimon Glass 815*2e192b24SSimon Glass /* must terminate with zero or '\n' */ 816*2e192b24SSimon Glass if (s[len - 1] != '\0' && s[len - 1] != '\n') 817*2e192b24SSimon Glass return 0; 818*2e192b24SSimon Glass 819*2e192b24SSimon Glass /* printable or a null byte (concatenated strings) */ 820*2e192b24SSimon Glass while (((*s == '\0') || isprint(*s) || isspace(*s)) && (len > 0)) { 821*2e192b24SSimon Glass /* 822*2e192b24SSimon Glass * If we see a null, there are three possibilities: 823*2e192b24SSimon Glass * 1) If len == 1, it is the end of the string, printable 824*2e192b24SSimon Glass * 2) Next character also a null, not printable. 825*2e192b24SSimon Glass * 3) Next character not a null, continue to check. 826*2e192b24SSimon Glass */ 827*2e192b24SSimon Glass if (s[0] == '\0') { 828*2e192b24SSimon Glass if (len == 1) 829*2e192b24SSimon Glass return 1; 830*2e192b24SSimon Glass if (s[1] == '\0') 831*2e192b24SSimon Glass return 0; 832*2e192b24SSimon Glass } 833*2e192b24SSimon Glass s++; 834*2e192b24SSimon Glass len--; 835*2e192b24SSimon Glass } 836*2e192b24SSimon Glass 837*2e192b24SSimon Glass /* Not the null termination, or not done yet: not printable */ 838*2e192b24SSimon Glass if (*s != '\0' || (len != 0)) 839*2e192b24SSimon Glass return 0; 840*2e192b24SSimon Glass 841*2e192b24SSimon Glass return 1; 842*2e192b24SSimon Glass } 843*2e192b24SSimon Glass 844*2e192b24SSimon Glass 845*2e192b24SSimon Glass /* 846*2e192b24SSimon Glass * Print the property in the best format, a heuristic guess. Print as 847*2e192b24SSimon Glass * a string, concatenated strings, a byte, word, double word, or (if all 848*2e192b24SSimon Glass * else fails) it is printed as a stream of bytes. 849*2e192b24SSimon Glass */ 850*2e192b24SSimon Glass static void print_data(const void *data, int len) 851*2e192b24SSimon Glass { 852*2e192b24SSimon Glass int j; 853*2e192b24SSimon Glass 854*2e192b24SSimon Glass /* no data, don't print */ 855*2e192b24SSimon Glass if (len == 0) 856*2e192b24SSimon Glass return; 857*2e192b24SSimon Glass 858*2e192b24SSimon Glass /* 859*2e192b24SSimon Glass * It is a string, but it may have multiple strings (embedded '\0's). 860*2e192b24SSimon Glass */ 861*2e192b24SSimon Glass if (is_printable_string(data, len)) { 862*2e192b24SSimon Glass puts("\""); 863*2e192b24SSimon Glass j = 0; 864*2e192b24SSimon Glass while (j < len) { 865*2e192b24SSimon Glass if (j > 0) 866*2e192b24SSimon Glass puts("\", \""); 867*2e192b24SSimon Glass puts(data); 868*2e192b24SSimon Glass j += strlen(data) + 1; 869*2e192b24SSimon Glass data += strlen(data) + 1; 870*2e192b24SSimon Glass } 871*2e192b24SSimon Glass puts("\""); 872*2e192b24SSimon Glass return; 873*2e192b24SSimon Glass } 874*2e192b24SSimon Glass 875*2e192b24SSimon Glass if ((len %4) == 0) { 876*2e192b24SSimon Glass if (len > CONFIG_CMD_FDT_MAX_DUMP) 877*2e192b24SSimon Glass printf("* 0x%p [0x%08x]", data, len); 878*2e192b24SSimon Glass else { 879*2e192b24SSimon Glass const __be32 *p; 880*2e192b24SSimon Glass 881*2e192b24SSimon Glass printf("<"); 882*2e192b24SSimon Glass for (j = 0, p = data; j < len/4; j++) 883*2e192b24SSimon Glass printf("0x%08x%s", fdt32_to_cpu(p[j]), 884*2e192b24SSimon Glass j < (len/4 - 1) ? " " : ""); 885*2e192b24SSimon Glass printf(">"); 886*2e192b24SSimon Glass } 887*2e192b24SSimon Glass } else { /* anything else... hexdump */ 888*2e192b24SSimon Glass if (len > CONFIG_CMD_FDT_MAX_DUMP) 889*2e192b24SSimon Glass printf("* 0x%p [0x%08x]", data, len); 890*2e192b24SSimon Glass else { 891*2e192b24SSimon Glass const u8 *s; 892*2e192b24SSimon Glass 893*2e192b24SSimon Glass printf("["); 894*2e192b24SSimon Glass for (j = 0, s = data; j < len; j++) 895*2e192b24SSimon Glass printf("%02x%s", s[j], j < len - 1 ? " " : ""); 896*2e192b24SSimon Glass printf("]"); 897*2e192b24SSimon Glass } 898*2e192b24SSimon Glass } 899*2e192b24SSimon Glass } 900*2e192b24SSimon Glass 901*2e192b24SSimon Glass /****************************************************************************/ 902*2e192b24SSimon Glass 903*2e192b24SSimon Glass /* 904*2e192b24SSimon Glass * Recursively print (a portion of) the working_fdt. The depth parameter 905*2e192b24SSimon Glass * determines how deeply nested the fdt is printed. 906*2e192b24SSimon Glass */ 907*2e192b24SSimon Glass static int fdt_print(const char *pathp, char *prop, int depth) 908*2e192b24SSimon Glass { 909*2e192b24SSimon Glass static char tabs[MAX_LEVEL+1] = 910*2e192b24SSimon Glass "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" 911*2e192b24SSimon Glass "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; 912*2e192b24SSimon Glass const void *nodep; /* property node pointer */ 913*2e192b24SSimon Glass int nodeoffset; /* node offset from libfdt */ 914*2e192b24SSimon Glass int nextoffset; /* next node offset from libfdt */ 915*2e192b24SSimon Glass uint32_t tag; /* tag */ 916*2e192b24SSimon Glass int len; /* length of the property */ 917*2e192b24SSimon Glass int level = 0; /* keep track of nesting level */ 918*2e192b24SSimon Glass const struct fdt_property *fdt_prop; 919*2e192b24SSimon Glass 920*2e192b24SSimon Glass nodeoffset = fdt_path_offset (working_fdt, pathp); 921*2e192b24SSimon Glass if (nodeoffset < 0) { 922*2e192b24SSimon Glass /* 923*2e192b24SSimon Glass * Not found or something else bad happened. 924*2e192b24SSimon Glass */ 925*2e192b24SSimon Glass printf ("libfdt fdt_path_offset() returned %s\n", 926*2e192b24SSimon Glass fdt_strerror(nodeoffset)); 927*2e192b24SSimon Glass return 1; 928*2e192b24SSimon Glass } 929*2e192b24SSimon Glass /* 930*2e192b24SSimon Glass * The user passed in a property as well as node path. 931*2e192b24SSimon Glass * Print only the given property and then return. 932*2e192b24SSimon Glass */ 933*2e192b24SSimon Glass if (prop) { 934*2e192b24SSimon Glass nodep = fdt_getprop (working_fdt, nodeoffset, prop, &len); 935*2e192b24SSimon Glass if (len == 0) { 936*2e192b24SSimon Glass /* no property value */ 937*2e192b24SSimon Glass printf("%s %s\n", pathp, prop); 938*2e192b24SSimon Glass return 0; 939*2e192b24SSimon Glass } else if (len > 0) { 940*2e192b24SSimon Glass printf("%s = ", prop); 941*2e192b24SSimon Glass print_data (nodep, len); 942*2e192b24SSimon Glass printf("\n"); 943*2e192b24SSimon Glass return 0; 944*2e192b24SSimon Glass } else { 945*2e192b24SSimon Glass printf ("libfdt fdt_getprop(): %s\n", 946*2e192b24SSimon Glass fdt_strerror(len)); 947*2e192b24SSimon Glass return 1; 948*2e192b24SSimon Glass } 949*2e192b24SSimon Glass } 950*2e192b24SSimon Glass 951*2e192b24SSimon Glass /* 952*2e192b24SSimon Glass * The user passed in a node path and no property, 953*2e192b24SSimon Glass * print the node and all subnodes. 954*2e192b24SSimon Glass */ 955*2e192b24SSimon Glass while(level >= 0) { 956*2e192b24SSimon Glass tag = fdt_next_tag(working_fdt, nodeoffset, &nextoffset); 957*2e192b24SSimon Glass switch(tag) { 958*2e192b24SSimon Glass case FDT_BEGIN_NODE: 959*2e192b24SSimon Glass pathp = fdt_get_name(working_fdt, nodeoffset, NULL); 960*2e192b24SSimon Glass if (level <= depth) { 961*2e192b24SSimon Glass if (pathp == NULL) 962*2e192b24SSimon Glass pathp = "/* NULL pointer error */"; 963*2e192b24SSimon Glass if (*pathp == '\0') 964*2e192b24SSimon Glass pathp = "/"; /* root is nameless */ 965*2e192b24SSimon Glass printf("%s%s {\n", 966*2e192b24SSimon Glass &tabs[MAX_LEVEL - level], pathp); 967*2e192b24SSimon Glass } 968*2e192b24SSimon Glass level++; 969*2e192b24SSimon Glass if (level >= MAX_LEVEL) { 970*2e192b24SSimon Glass printf("Nested too deep, aborting.\n"); 971*2e192b24SSimon Glass return 1; 972*2e192b24SSimon Glass } 973*2e192b24SSimon Glass break; 974*2e192b24SSimon Glass case FDT_END_NODE: 975*2e192b24SSimon Glass level--; 976*2e192b24SSimon Glass if (level <= depth) 977*2e192b24SSimon Glass printf("%s};\n", &tabs[MAX_LEVEL - level]); 978*2e192b24SSimon Glass if (level == 0) { 979*2e192b24SSimon Glass level = -1; /* exit the loop */ 980*2e192b24SSimon Glass } 981*2e192b24SSimon Glass break; 982*2e192b24SSimon Glass case FDT_PROP: 983*2e192b24SSimon Glass fdt_prop = fdt_offset_ptr(working_fdt, nodeoffset, 984*2e192b24SSimon Glass sizeof(*fdt_prop)); 985*2e192b24SSimon Glass pathp = fdt_string(working_fdt, 986*2e192b24SSimon Glass fdt32_to_cpu(fdt_prop->nameoff)); 987*2e192b24SSimon Glass len = fdt32_to_cpu(fdt_prop->len); 988*2e192b24SSimon Glass nodep = fdt_prop->data; 989*2e192b24SSimon Glass if (len < 0) { 990*2e192b24SSimon Glass printf ("libfdt fdt_getprop(): %s\n", 991*2e192b24SSimon Glass fdt_strerror(len)); 992*2e192b24SSimon Glass return 1; 993*2e192b24SSimon Glass } else if (len == 0) { 994*2e192b24SSimon Glass /* the property has no value */ 995*2e192b24SSimon Glass if (level <= depth) 996*2e192b24SSimon Glass printf("%s%s;\n", 997*2e192b24SSimon Glass &tabs[MAX_LEVEL - level], 998*2e192b24SSimon Glass pathp); 999*2e192b24SSimon Glass } else { 1000*2e192b24SSimon Glass if (level <= depth) { 1001*2e192b24SSimon Glass printf("%s%s = ", 1002*2e192b24SSimon Glass &tabs[MAX_LEVEL - level], 1003*2e192b24SSimon Glass pathp); 1004*2e192b24SSimon Glass print_data (nodep, len); 1005*2e192b24SSimon Glass printf(";\n"); 1006*2e192b24SSimon Glass } 1007*2e192b24SSimon Glass } 1008*2e192b24SSimon Glass break; 1009*2e192b24SSimon Glass case FDT_NOP: 1010*2e192b24SSimon Glass printf("%s/* NOP */\n", &tabs[MAX_LEVEL - level]); 1011*2e192b24SSimon Glass break; 1012*2e192b24SSimon Glass case FDT_END: 1013*2e192b24SSimon Glass return 1; 1014*2e192b24SSimon Glass default: 1015*2e192b24SSimon Glass if (level <= depth) 1016*2e192b24SSimon Glass printf("Unknown tag 0x%08X\n", tag); 1017*2e192b24SSimon Glass return 1; 1018*2e192b24SSimon Glass } 1019*2e192b24SSimon Glass nodeoffset = nextoffset; 1020*2e192b24SSimon Glass } 1021*2e192b24SSimon Glass return 0; 1022*2e192b24SSimon Glass } 1023*2e192b24SSimon Glass 1024*2e192b24SSimon Glass /********************************************************************/ 1025*2e192b24SSimon Glass #ifdef CONFIG_SYS_LONGHELP 1026*2e192b24SSimon Glass static char fdt_help_text[] = 1027*2e192b24SSimon Glass "addr [-c] <addr> [<length>] - Set the [control] fdt location to <addr>\n" 1028*2e192b24SSimon Glass #ifdef CONFIG_OF_BOARD_SETUP 1029*2e192b24SSimon Glass "fdt boardsetup - Do board-specific set up\n" 1030*2e192b24SSimon Glass #endif 1031*2e192b24SSimon Glass #ifdef CONFIG_OF_SYSTEM_SETUP 1032*2e192b24SSimon Glass "fdt systemsetup - Do system-specific set up\n" 1033*2e192b24SSimon Glass #endif 1034*2e192b24SSimon Glass "fdt move <fdt> <newaddr> <length> - Copy the fdt to <addr> and make it active\n" 1035*2e192b24SSimon Glass "fdt resize - Resize fdt to size + padding to 4k addr\n" 1036*2e192b24SSimon Glass "fdt print <path> [<prop>] - Recursive print starting at <path>\n" 1037*2e192b24SSimon Glass "fdt list <path> [<prop>] - Print one level starting at <path>\n" 1038*2e192b24SSimon Glass "fdt get value <var> <path> <prop> - Get <property> and store in <var>\n" 1039*2e192b24SSimon Glass "fdt get name <var> <path> <index> - Get name of node <index> and store in <var>\n" 1040*2e192b24SSimon Glass "fdt get addr <var> <path> <prop> - Get start address of <property> and store in <var>\n" 1041*2e192b24SSimon Glass "fdt get size <var> <path> [<prop>] - Get size of [<property>] or num nodes and store in <var>\n" 1042*2e192b24SSimon Glass "fdt set <path> <prop> [<val>] - Set <property> [to <val>]\n" 1043*2e192b24SSimon Glass "fdt mknode <path> <node> - Create a new node after <path>\n" 1044*2e192b24SSimon Glass "fdt rm <path> [<prop>] - Delete the node or <property>\n" 1045*2e192b24SSimon Glass "fdt header - Display header info\n" 1046*2e192b24SSimon Glass "fdt bootcpu <id> - Set boot cpuid\n" 1047*2e192b24SSimon Glass "fdt memory <addr> <size> - Add/Update memory node\n" 1048*2e192b24SSimon Glass "fdt rsvmem print - Show current mem reserves\n" 1049*2e192b24SSimon Glass "fdt rsvmem add <addr> <size> - Add a mem reserve\n" 1050*2e192b24SSimon Glass "fdt rsvmem delete <index> - Delete a mem reserves\n" 1051*2e192b24SSimon Glass "fdt chosen [<start> <end>] - Add/update the /chosen branch in the tree\n" 1052*2e192b24SSimon Glass " <start>/<end> - initrd start/end addr\n" 1053*2e192b24SSimon Glass #if defined(CONFIG_FIT_SIGNATURE) 1054*2e192b24SSimon Glass "fdt checksign [<addr>] - check FIT signature\n" 1055*2e192b24SSimon Glass " <start> - addr of key blob\n" 1056*2e192b24SSimon Glass " default gd->fdt_blob\n" 1057*2e192b24SSimon Glass #endif 1058*2e192b24SSimon Glass "NOTE: Dereference aliases by omiting the leading '/', " 1059*2e192b24SSimon Glass "e.g. fdt print ethernet0."; 1060*2e192b24SSimon Glass #endif 1061*2e192b24SSimon Glass 1062*2e192b24SSimon Glass U_BOOT_CMD( 1063*2e192b24SSimon Glass fdt, 255, 0, do_fdt, 1064*2e192b24SSimon Glass "flattened device tree utility commands", fdt_help_text 1065*2e192b24SSimon Glass ); 1066