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