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