uboot/boot/image-fdt.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2013, Google Inc.
   4 *
   5 * (C) Copyright 2008 Semihalf
   6 *
   7 * (C) Copyright 2000-2006
   8 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   9 */
  10
  11#include <common.h>
  12#include <fdt_support.h>
  13#include <fdtdec.h>
  14#include <env.h>
  15#include <errno.h>
  16#include <image.h>
  17#include <lmb.h>
  18#include <log.h>
  19#include <malloc.h>
  20#include <asm/global_data.h>
  21#include <linux/libfdt.h>
  22#include <mapmem.h>
  23#include <asm/io.h>
  24#include <tee/optee.h>
  25
  26#ifndef CONFIG_SYS_FDT_PAD
  27#define CONFIG_SYS_FDT_PAD 0x3000
  28#endif
  29
  30/* adding a ramdisk needs 0x44 bytes in version 2008.10 */
  31#define FDT_RAMDISK_OVERHEAD    0x80
  32
  33DECLARE_GLOBAL_DATA_PTR;
  34
  35static void fdt_error(const char *msg)
  36{
  37        puts("ERROR: ");
  38        puts(msg);
  39        puts(" - must RESET the board to recover.\n");
  40}
  41
  42#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
  43static const image_header_t *image_get_fdt(ulong fdt_addr)
  44{
  45        const image_header_t *fdt_hdr = map_sysmem(fdt_addr, 0);
  46
  47        image_print_contents(fdt_hdr);
  48
  49        puts("   Verifying Checksum ... ");
  50        if (!image_check_hcrc(fdt_hdr)) {
  51                fdt_error("fdt header checksum invalid");
  52                return NULL;
  53        }
  54
  55        if (!image_check_dcrc(fdt_hdr)) {
  56                fdt_error("fdt checksum invalid");
  57                return NULL;
  58        }
  59        puts("OK\n");
  60
  61        if (!image_check_type(fdt_hdr, IH_TYPE_FLATDT)) {
  62                fdt_error("uImage is not a fdt");
  63                return NULL;
  64        }
  65        if (image_get_comp(fdt_hdr) != IH_COMP_NONE) {
  66                fdt_error("uImage is compressed");
  67                return NULL;
  68        }
  69        if (fdt_check_header((void *)image_get_data(fdt_hdr)) != 0) {
  70                fdt_error("uImage data is not a fdt");
  71                return NULL;
  72        }
  73        return fdt_hdr;
  74}
  75#endif
  76
  77static void boot_fdt_reserve_region(struct lmb *lmb, uint64_t addr,
  78                                    uint64_t size, enum lmb_flags flags)
  79{
  80        long ret;
  81
  82        ret = lmb_reserve_flags(lmb, addr, size, flags);
  83        if (ret >= 0) {
  84                debug("   reserving fdt memory region: addr=%llx size=%llx flags=%x\n",
  85                      (unsigned long long)addr,
  86                      (unsigned long long)size, flags);
  87        } else {
  88                puts("ERROR: reserving fdt memory region failed ");
  89                printf("(addr=%llx size=%llx flags=%x)\n",
  90                       (unsigned long long)addr,
  91                       (unsigned long long)size, flags);
  92        }
  93}
  94
  95/**
  96 * boot_fdt_add_mem_rsv_regions - Mark the memreserve and reserved-memory
  97 * sections as unusable
  98 * @lmb: pointer to lmb handle, will be used for memory mgmt
  99 * @fdt_blob: pointer to fdt blob base address
 100 *
 101 * Adds the and reserved-memorymemreserve regions in the dtb to the lmb block.
 102 * Adding the memreserve regions prevents u-boot from using them to store the
 103 * initrd or the fdt blob.
 104 */
 105void boot_fdt_add_mem_rsv_regions(struct lmb *lmb, void *fdt_blob)
 106{
 107        uint64_t addr, size;
 108        int i, total, ret;
 109        int nodeoffset, subnode;
 110        struct fdt_resource res;
 111        enum lmb_flags flags;
 112
 113        if (fdt_check_header(fdt_blob) != 0)
 114                return;
 115
 116        /* process memreserve sections */
 117        total = fdt_num_mem_rsv(fdt_blob);
 118        for (i = 0; i < total; i++) {
 119                if (fdt_get_mem_rsv(fdt_blob, i, &addr, &size) != 0)
 120                        continue;
 121                boot_fdt_reserve_region(lmb, addr, size, LMB_NONE);
 122        }
 123
 124        /* process reserved-memory */
 125        nodeoffset = fdt_subnode_offset(fdt_blob, 0, "reserved-memory");
 126        if (nodeoffset >= 0) {
 127                subnode = fdt_first_subnode(fdt_blob, nodeoffset);
 128                while (subnode >= 0) {
 129                        /* check if this subnode has a reg property */
 130                        ret = fdt_get_resource(fdt_blob, subnode, "reg", 0,
 131                                               &res);
 132                        if (!ret && fdtdec_get_is_enabled(fdt_blob, subnode)) {
 133                                flags = LMB_NONE;
 134                                if (fdtdec_get_bool(fdt_blob, subnode,
 135                                                    "no-map"))
 136                                        flags = LMB_NOMAP;
 137                                addr = res.start;
 138                                size = res.end - res.start + 1;
 139                                boot_fdt_reserve_region(lmb, addr, size, flags);
 140                        }
 141
 142                        subnode = fdt_next_subnode(fdt_blob, subnode);
 143                }
 144        }
 145}
 146
 147/**
 148 * boot_relocate_fdt - relocate flat device tree
 149 * @lmb: pointer to lmb handle, will be used for memory mgmt
 150 * @of_flat_tree: pointer to a char* variable, will hold fdt start address
 151 * @of_size: pointer to a ulong variable, will hold fdt length
 152 *
 153 * boot_relocate_fdt() allocates a region of memory within the bootmap and
 154 * relocates the of_flat_tree into that region, even if the fdt is already in
 155 * the bootmap.  It also expands the size of the fdt by CONFIG_SYS_FDT_PAD
 156 * bytes.
 157 *
 158 * of_flat_tree and of_size are set to final (after relocation) values
 159 *
 160 * returns:
 161 *      0 - success
 162 *      1 - failure
 163 */
 164int boot_relocate_fdt(struct lmb *lmb, char **of_flat_tree, ulong *of_size)
 165{
 166        void    *fdt_blob = *of_flat_tree;
 167        void    *of_start = NULL;
 168        char    *fdt_high;
 169        ulong   of_len = 0;
 170        int     err;
 171        int     disable_relocation = 0;
 172
 173        /* nothing to do */
 174        if (*of_size == 0)
 175                return 0;
 176
 177        if (fdt_check_header(fdt_blob) != 0) {
 178                fdt_error("image is not a fdt");
 179                goto error;
 180        }
 181
 182        /* position on a 4K boundary before the alloc_current */
 183        /* Pad the FDT by a specified amount */
 184        of_len = *of_size + CONFIG_SYS_FDT_PAD;
 185
 186        /* If fdt_high is set use it to select the relocation address */
 187        fdt_high = env_get("fdt_high");
 188        if (fdt_high) {
 189                void *desired_addr = (void *)hextoul(fdt_high, NULL);
 190
 191                if (((ulong) desired_addr) == ~0UL) {
 192                        /* All ones means use fdt in place */
 193                        of_start = fdt_blob;
 194                        lmb_reserve(lmb, (ulong)of_start, of_len);
 195                        disable_relocation = 1;
 196                } else if (desired_addr) {
 197                        of_start =
 198                            (void *)(ulong) lmb_alloc_base(lmb, of_len, 0x1000,
 199                                                           (ulong)desired_addr);
 200                        if (of_start == NULL) {
 201                                puts("Failed using fdt_high value for Device Tree");
 202                                goto error;
 203                        }
 204                } else {
 205                        of_start =
 206                            (void *)(ulong) lmb_alloc(lmb, of_len, 0x1000);
 207                }
 208        } else {
 209                of_start =
 210                    (void *)(ulong) lmb_alloc_base(lmb, of_len, 0x1000,
 211                                                   env_get_bootm_mapsize()
 212                                                   + env_get_bootm_low());
 213        }
 214
 215        if (of_start == NULL) {
 216                puts("device tree - allocation error\n");
 217                goto error;
 218        }
 219
 220        if (disable_relocation) {
 221                /*
 222                 * We assume there is space after the existing fdt to use
 223                 * for padding
 224                 */
 225                fdt_set_totalsize(of_start, of_len);
 226                printf("   Using Device Tree in place at %p, end %p\n",
 227                       of_start, of_start + of_len - 1);
 228        } else {
 229                debug("## device tree at %p ... %p (len=%ld [0x%lX])\n",
 230                      fdt_blob, fdt_blob + *of_size - 1, of_len, of_len);
 231
 232                printf("   Loading Device Tree to %p, end %p ... ",
 233                       of_start, of_start + of_len - 1);
 234
 235                err = fdt_open_into(fdt_blob, of_start, of_len);
 236                if (err != 0) {
 237                        fdt_error("fdt move failed");
 238                        goto error;
 239                }
 240                puts("OK\n");
 241        }
 242
 243        *of_flat_tree = of_start;
 244        *of_size = of_len;
 245
 246        if (CONFIG_IS_ENABLED(CMD_FDT))
 247                set_working_fdt_addr(map_to_sysmem(*of_flat_tree));
 248        return 0;
 249
 250error:
 251        return 1;
 252}
 253
 254/**
 255 * select_fdt() - Select and locate the FDT to use
 256 *
 257 * @images: pointer to the bootm images structure
 258 * @select: name of FDT to select, or NULL for any
 259 * @arch: expected FDT architecture
 260 * @fdt_addrp: pointer to a ulong variable, will hold FDT pointer
 261 * @return 0 if OK, -ENOPKG if no FDT (but an error should not be reported),
 262 *      other -ve value on other error
 263 */
 264
 265static int select_fdt(bootm_headers_t *images, const char *select, u8 arch,
 266                      ulong *fdt_addrp)
 267{
 268        const char *buf;
 269        ulong fdt_addr;
 270
 271#if CONFIG_IS_ENABLED(FIT)
 272        const char *fit_uname_config = images->fit_uname_cfg;
 273        const char *fit_uname_fdt = NULL;
 274        ulong default_addr;
 275        int fdt_noffset;
 276
 277        if (select) {
 278                        /*
 279                         * If the FDT blob comes from the FIT image and the
 280                         * FIT image address is omitted in the command line
 281                         * argument, try to use ramdisk or os FIT image
 282                         * address or default load address.
 283                         */
 284                        if (images->fit_uname_rd)
 285                                default_addr = (ulong)images->fit_hdr_rd;
 286                        else if (images->fit_uname_os)
 287                                default_addr = (ulong)images->fit_hdr_os;
 288                        else
 289                                default_addr = image_load_addr;
 290
 291                        if (fit_parse_conf(select, default_addr, &fdt_addr,
 292                                           &fit_uname_config)) {
 293                                debug("*  fdt: config '%s' from image at 0x%08lx\n",
 294                                      fit_uname_config, fdt_addr);
 295                        } else if (fit_parse_subimage(select, default_addr, &fdt_addr,
 296                                   &fit_uname_fdt)) {
 297                                debug("*  fdt: subimage '%s' from image at 0x%08lx\n",
 298                                      fit_uname_fdt, fdt_addr);
 299                        } else
 300#endif
 301                {
 302                        fdt_addr = hextoul(select, NULL);
 303                        debug("*  fdt: cmdline image address = 0x%08lx\n",
 304                              fdt_addr);
 305                }
 306#if CONFIG_IS_ENABLED(FIT)
 307        } else {
 308                /* use FIT configuration provided in first bootm
 309                 * command argument
 310                 */
 311                fdt_addr = map_to_sysmem(images->fit_hdr_os);
 312                fdt_noffset = fit_get_node_from_config(images, FIT_FDT_PROP,
 313                                                       fdt_addr);
 314                if (fdt_noffset == -ENOENT)
 315                        return -ENOPKG;
 316                else if (fdt_noffset < 0)
 317                        return fdt_noffset;
 318        }
 319#endif
 320        debug("## Checking for 'FDT'/'FDT Image' at %08lx\n",
 321              fdt_addr);
 322
 323        /*
 324         * Check if there is an FDT image at the
 325         * address provided in the second bootm argument
 326         * check image type, for FIT images get a FIT node.
 327         */
 328        buf = map_sysmem(fdt_addr, 0);
 329        switch (genimg_get_format(buf)) {
 330#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
 331        case IMAGE_FORMAT_LEGACY: {
 332                        const image_header_t *fdt_hdr;
 333                        ulong load, load_end;
 334                        ulong image_start, image_data, image_end;
 335
 336                        /* verify fdt_addr points to a valid image header */
 337                        printf("## Flattened Device Tree from Legacy Image at %08lx\n",
 338                               fdt_addr);
 339                        fdt_hdr = image_get_fdt(fdt_addr);
 340                        if (!fdt_hdr)
 341                                return -ENOPKG;
 342
 343                        /*
 344                         * move image data to the load address,
 345                         * make sure we don't overwrite initial image
 346                         */
 347                        image_start = (ulong)fdt_hdr;
 348                        image_data = (ulong)image_get_data(fdt_hdr);
 349                        image_end = image_get_image_end(fdt_hdr);
 350
 351                        load = image_get_load(fdt_hdr);
 352                        load_end = load + image_get_data_size(fdt_hdr);
 353
 354                        if (load == image_start ||
 355                            load == image_data) {
 356                                fdt_addr = load;
 357                                break;
 358                        }
 359
 360                        if ((load < image_end) && (load_end > image_start)) {
 361                                fdt_error("fdt overwritten");
 362                                return -EFAULT;
 363                        }
 364
 365                        debug("   Loading FDT from 0x%08lx to 0x%08lx\n",
 366                              image_data, load);
 367
 368                        memmove((void *)load,
 369                                (void *)image_data,
 370                                image_get_data_size(fdt_hdr));
 371
 372                        fdt_addr = load;
 373                        break;
 374                }
 375#endif
 376        case IMAGE_FORMAT_FIT:
 377                /*
 378                 * This case will catch both: new uImage format
 379                 * (libfdt based) and raw FDT blob (also libfdt
 380                 * based).
 381                 */
 382#if CONFIG_IS_ENABLED(FIT)
 383                        /* check FDT blob vs FIT blob */
 384                        if (!fit_check_format(buf, IMAGE_SIZE_INVAL)) {
 385                                ulong load, len;
 386
 387                                fdt_noffset = boot_get_fdt_fit(images, fdt_addr,
 388                                                               &fit_uname_fdt,
 389                                                               &fit_uname_config,
 390                                                               arch, &load, &len);
 391
 392                                if (fdt_noffset < 0)
 393                                        return -ENOENT;
 394
 395                                images->fit_hdr_fdt = map_sysmem(fdt_addr, 0);
 396                                images->fit_uname_fdt = fit_uname_fdt;
 397                                images->fit_noffset_fdt = fdt_noffset;
 398                                fdt_addr = load;
 399
 400                                break;
 401                } else
 402#endif
 403                {
 404                        /*
 405                         * FDT blob
 406                         */
 407                        debug("*  fdt: raw FDT blob\n");
 408                        printf("## Flattened Device Tree blob at %08lx\n",
 409                               (long)fdt_addr);
 410                }
 411                break;
 412        default:
 413                puts("ERROR: Did not find a cmdline Flattened Device Tree\n");
 414                return -ENOENT;
 415        }
 416        *fdt_addrp = fdt_addr;
 417
 418        return 0;
 419}
 420
 421/**
 422 * boot_get_fdt - main fdt handling routine
 423 * @argc: command argument count
 424 * @argv: command argument list
 425 * @arch: architecture (IH_ARCH_...)
 426 * @images: pointer to the bootm images structure
 427 * @of_flat_tree: pointer to a char* variable, will hold fdt start address
 428 * @of_size: pointer to a ulong variable, will hold fdt length
 429 *
 430 * boot_get_fdt() is responsible for finding a valid flat device tree image.
 431 * Currently supported are the following ramdisk sources:
 432 *      - multicomponent kernel/ramdisk image,
 433 *      - commandline provided address of decicated ramdisk image.
 434 *
 435 * returns:
 436 *     0, if fdt image was found and valid, or skipped
 437 *     of_flat_tree and of_size are set to fdt start address and length if
 438 *     fdt image is found and valid
 439 *
 440 *     1, if fdt image is found but corrupted
 441 *     of_flat_tree and of_size are set to 0 if no fdt exists
 442 */
 443int boot_get_fdt(int flag, int argc, char *const argv[], uint8_t arch,
 444                 bootm_headers_t *images, char **of_flat_tree, ulong *of_size)
 445{
 446        ulong           img_addr;
 447        ulong           fdt_addr;
 448        char            *fdt_blob = NULL;
 449        void            *buf;
 450        const char *select = NULL;
 451
 452        *of_flat_tree = NULL;
 453        *of_size = 0;
 454
 455        img_addr = (argc == 0) ? image_load_addr : hextoul(argv[0], NULL);
 456        buf = map_sysmem(img_addr, 0);
 457
 458        if (argc > 2)
 459                select = argv[2];
 460        if (select || genimg_has_config(images)) {
 461                int ret;
 462
 463                ret = select_fdt(images, select, arch, &fdt_addr);
 464                if (ret == -ENOPKG)
 465                        goto no_fdt;
 466                else if (ret)
 467                        return 1;
 468                printf("   Booting using the fdt blob at %#08lx\n", fdt_addr);
 469                fdt_blob = map_sysmem(fdt_addr, 0);
 470        } else if (images->legacy_hdr_valid &&
 471                        image_check_type(&images->legacy_hdr_os_copy,
 472                                         IH_TYPE_MULTI)) {
 473                ulong fdt_data, fdt_len;
 474
 475                /*
 476                 * Now check if we have a legacy multi-component image,
 477                 * get second entry data start address and len.
 478                 */
 479                printf("## Flattened Device Tree from multi component Image at %08lX\n",
 480                       (ulong)images->legacy_hdr_os);
 481
 482                image_multi_getimg(images->legacy_hdr_os, 2, &fdt_data,
 483                                   &fdt_len);
 484                if (fdt_len) {
 485                        fdt_blob = (char *)fdt_data;
 486                        printf("   Booting using the fdt at 0x%p\n", fdt_blob);
 487
 488                        if (fdt_check_header(fdt_blob) != 0) {
 489                                fdt_error("image is not a fdt");
 490                                goto error;
 491                        }
 492
 493                        if (fdt_totalsize(fdt_blob) != fdt_len) {
 494                                fdt_error("fdt size != image size");
 495                                goto error;
 496                        }
 497                } else {
 498                        debug("## No Flattened Device Tree\n");
 499                        goto no_fdt;
 500                }
 501#ifdef CONFIG_ANDROID_BOOT_IMAGE
 502        } else if (genimg_get_format(buf) == IMAGE_FORMAT_ANDROID) {
 503                struct andr_img_hdr *hdr = buf;
 504                ulong           fdt_data, fdt_len;
 505                u32                     fdt_size, dtb_idx;
 506                /*
 507                 * Firstly check if this android boot image has dtb field.
 508                 */
 509                dtb_idx = (u32)env_get_ulong("adtb_idx", 10, 0);
 510                if (android_image_get_dtb_by_index((ulong)hdr, dtb_idx, &fdt_addr, &fdt_size)) {
 511                        fdt_blob = (char *)map_sysmem(fdt_addr, 0);
 512                        if (fdt_check_header(fdt_blob))
 513                                goto no_fdt;
 514
 515                        debug("## Using FDT in Android image dtb area with idx %u\n", dtb_idx);
 516                } else if (!android_image_get_second(hdr, &fdt_data, &fdt_len) &&
 517                        !fdt_check_header((char *)fdt_data)) {
 518                        fdt_blob = (char *)fdt_data;
 519                        if (fdt_totalsize(fdt_blob) != fdt_len)
 520                                goto error;
 521
 522                        debug("## Using FDT in Android image second area\n");
 523                } else {
 524                        fdt_addr = env_get_hex("fdtaddr", 0);
 525                        if (!fdt_addr)
 526                                goto no_fdt;
 527
 528                        fdt_blob = map_sysmem(fdt_addr, 0);
 529                        if (fdt_check_header(fdt_blob))
 530                                goto no_fdt;
 531
 532                        debug("## Using FDT at ${fdtaddr}=Ox%lx\n", fdt_addr);
 533                }
 534#endif
 535        } else {
 536                debug("## No Flattened Device Tree\n");
 537                goto no_fdt;
 538        }
 539
 540        *of_flat_tree = fdt_blob;
 541        *of_size = fdt_totalsize(fdt_blob);
 542        debug("   of_flat_tree at 0x%08lx size 0x%08lx\n",
 543              (ulong)*of_flat_tree, *of_size);
 544
 545        return 0;
 546
 547no_fdt:
 548        debug("Continuing to boot without FDT\n");
 549        return 0;
 550error:
 551        return 1;
 552}
 553
 554/*
 555 * Verify the device tree.
 556 *
 557 * This function is called after all device tree fix-ups have been enacted,
 558 * so that the final device tree can be verified.  The definition of "verified"
 559 * is up to the specific implementation.  However, it generally means that the
 560 * addresses of some of the devices in the device tree are compared with the
 561 * actual addresses at which U-Boot has placed them.
 562 *
 563 * Returns 1 on success, 0 on failure.  If 0 is returned, U-Boot will halt the
 564 * boot process.
 565 */
 566__weak int ft_verify_fdt(void *fdt)
 567{
 568        return 1;
 569}
 570
 571__weak int arch_fixup_fdt(void *blob)
 572{
 573        return 0;
 574}
 575
 576int image_setup_libfdt(bootm_headers_t *images, void *blob,
 577                       int of_size, struct lmb *lmb)
 578{
 579        ulong *initrd_start = &images->initrd_start;
 580        ulong *initrd_end = &images->initrd_end;
 581        int ret = -EPERM;
 582        int fdt_ret;
 583
 584        if (fdt_root(blob) < 0) {
 585                printf("ERROR: root node setup failed\n");
 586                goto err;
 587        }
 588        if (fdt_chosen(blob) < 0) {
 589                printf("ERROR: /chosen node create failed\n");
 590                goto err;
 591        }
 592        if (arch_fixup_fdt(blob) < 0) {
 593                printf("ERROR: arch-specific fdt fixup failed\n");
 594                goto err;
 595        }
 596
 597        fdt_ret = optee_copy_fdt_nodes(blob);
 598        if (fdt_ret) {
 599                printf("ERROR: transfer of optee nodes to new fdt failed: %s\n",
 600                       fdt_strerror(fdt_ret));
 601                goto err;
 602        }
 603
 604        /* Update ethernet nodes */
 605        fdt_fixup_ethernet(blob);
 606#if CONFIG_IS_ENABLED(CMD_PSTORE)
 607        /* Append PStore configuration */
 608        fdt_fixup_pstore(blob);
 609#endif
 610        if (IS_ENABLED(CONFIG_OF_BOARD_SETUP)) {
 611                const char *skip_board_fixup;
 612
 613                skip_board_fixup = env_get("skip_board_fixup");
 614                if (skip_board_fixup && ((int)simple_strtol(skip_board_fixup, NULL, 10) == 1)) {
 615                        printf("skip board fdt fixup\n");
 616                } else {
 617                        fdt_ret = ft_board_setup(blob, gd->bd);
 618                        if (fdt_ret) {
 619                                printf("ERROR: board-specific fdt fixup failed: %s\n",
 620                                       fdt_strerror(fdt_ret));
 621                                goto err;
 622                        }
 623                }
 624        }
 625        if (IS_ENABLED(CONFIG_OF_SYSTEM_SETUP)) {
 626                fdt_ret = ft_system_setup(blob, gd->bd);
 627                if (fdt_ret) {
 628                        printf("ERROR: system-specific fdt fixup failed: %s\n",
 629                               fdt_strerror(fdt_ret));
 630                        goto err;
 631                }
 632        }
 633
 634        /* Delete the old LMB reservation */
 635        if (lmb)
 636                lmb_free(lmb, (phys_addr_t)(u32)(uintptr_t)blob,
 637                         (phys_size_t)fdt_totalsize(blob));
 638
 639        ret = fdt_shrink_to_minimum(blob, 0);
 640        if (ret < 0)
 641                goto err;
 642        of_size = ret;
 643
 644        if (*initrd_start && *initrd_end) {
 645                of_size += FDT_RAMDISK_OVERHEAD;
 646                fdt_set_totalsize(blob, of_size);
 647        }
 648        /* Create a new LMB reservation */
 649        if (lmb)
 650                lmb_reserve(lmb, (ulong)blob, of_size);
 651
 652        fdt_initrd(blob, *initrd_start, *initrd_end);
 653        if (!ft_verify_fdt(blob))
 654                goto err;
 655
 656#if defined(CONFIG_ARCH_KEYSTONE)
 657        if (IS_ENABLED(CONFIG_OF_BOARD_SETUP))
 658                ft_board_setup_ex(blob, gd->bd);
 659#endif
 660
 661        return 0;
 662err:
 663        printf(" - must RESET the board to recover.\n\n");
 664
 665        return ret;
 666}
 667