uboot/lib/fdtdec.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2011 The Chromium OS Authors.
   4 */
   5
   6#ifndef USE_HOSTCC
   7#include <common.h>
   8#include <boot_fit.h>
   9#include <dm.h>
  10#include <hang.h>
  11#include <init.h>
  12#include <log.h>
  13#include <malloc.h>
  14#include <net.h>
  15#include <dm/of_extra.h>
  16#include <env.h>
  17#include <errno.h>
  18#include <fdtdec.h>
  19#include <fdt_support.h>
  20#include <gzip.h>
  21#include <mapmem.h>
  22#include <linux/libfdt.h>
  23#include <serial.h>
  24#include <asm/sections.h>
  25#include <linux/ctype.h>
  26#include <linux/lzo.h>
  27
  28DECLARE_GLOBAL_DATA_PTR;
  29
  30/*
  31 * Here are the type we know about. One day we might allow drivers to
  32 * register. For now we just put them here. The COMPAT macro allows us to
  33 * turn this into a sparse list later, and keeps the ID with the name.
  34 *
  35 * NOTE: This list is basically a TODO list for things that need to be
  36 * converted to driver model. So don't add new things here unless there is a
  37 * good reason why driver-model conversion is infeasible. Examples include
  38 * things which are used before driver model is available.
  39 */
  40#define COMPAT(id, name) name
  41static const char * const compat_names[COMPAT_COUNT] = {
  42        COMPAT(UNKNOWN, "<none>"),
  43        COMPAT(NVIDIA_TEGRA20_EMC, "nvidia,tegra20-emc"),
  44        COMPAT(NVIDIA_TEGRA20_EMC_TABLE, "nvidia,tegra20-emc-table"),
  45        COMPAT(NVIDIA_TEGRA20_NAND, "nvidia,tegra20-nand"),
  46        COMPAT(NVIDIA_TEGRA124_XUSB_PADCTL, "nvidia,tegra124-xusb-padctl"),
  47        COMPAT(NVIDIA_TEGRA210_XUSB_PADCTL, "nvidia,tegra210-xusb-padctl"),
  48        COMPAT(SMSC_LAN9215, "smsc,lan9215"),
  49        COMPAT(SAMSUNG_EXYNOS5_SROMC, "samsung,exynos-sromc"),
  50        COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"),
  51        COMPAT(SAMSUNG_EXYNOS5_USB3_PHY, "samsung,exynos5250-usb3-phy"),
  52        COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"),
  53        COMPAT(SAMSUNG_EXYNOS_MIPI_DSI, "samsung,exynos-mipi-dsi"),
  54        COMPAT(SAMSUNG_EXYNOS_DWMMC, "samsung,exynos-dwmmc"),
  55        COMPAT(GENERIC_SPI_FLASH, "jedec,spi-nor"),
  56        COMPAT(SAMSUNG_EXYNOS_SYSMMU, "samsung,sysmmu-v3.3"),
  57        COMPAT(INTEL_MICROCODE, "intel,microcode"),
  58        COMPAT(INTEL_QRK_MRC, "intel,quark-mrc"),
  59        COMPAT(ALTERA_SOCFPGA_DWMAC, "altr,socfpga-stmmac"),
  60        COMPAT(ALTERA_SOCFPGA_DWMMC, "altr,socfpga-dw-mshc"),
  61        COMPAT(ALTERA_SOCFPGA_DWC2USB, "snps,dwc2"),
  62        COMPAT(INTEL_BAYTRAIL_FSP, "intel,baytrail-fsp"),
  63        COMPAT(INTEL_BAYTRAIL_FSP_MDP, "intel,baytrail-fsp-mdp"),
  64        COMPAT(INTEL_IVYBRIDGE_FSP, "intel,ivybridge-fsp"),
  65        COMPAT(COMPAT_SUNXI_NAND, "allwinner,sun4i-a10-nand"),
  66        COMPAT(ALTERA_SOCFPGA_CLK, "altr,clk-mgr"),
  67        COMPAT(ALTERA_SOCFPGA_PINCTRL_SINGLE, "pinctrl-single"),
  68        COMPAT(ALTERA_SOCFPGA_H2F_BRG, "altr,socfpga-hps2fpga-bridge"),
  69        COMPAT(ALTERA_SOCFPGA_LWH2F_BRG, "altr,socfpga-lwhps2fpga-bridge"),
  70        COMPAT(ALTERA_SOCFPGA_F2H_BRG, "altr,socfpga-fpga2hps-bridge"),
  71        COMPAT(ALTERA_SOCFPGA_F2SDR0, "altr,socfpga-fpga2sdram0-bridge"),
  72        COMPAT(ALTERA_SOCFPGA_F2SDR1, "altr,socfpga-fpga2sdram1-bridge"),
  73        COMPAT(ALTERA_SOCFPGA_F2SDR2, "altr,socfpga-fpga2sdram2-bridge"),
  74        COMPAT(ALTERA_SOCFPGA_FPGA0, "altr,socfpga-a10-fpga-mgr"),
  75        COMPAT(ALTERA_SOCFPGA_NOC, "altr,socfpga-a10-noc"),
  76        COMPAT(ALTERA_SOCFPGA_CLK_INIT, "altr,socfpga-a10-clk-init")
  77};
  78
  79const char *fdtdec_get_compatible(enum fdt_compat_id id)
  80{
  81        /* We allow reading of the 'unknown' ID for testing purposes */
  82        assert(id >= 0 && id < COMPAT_COUNT);
  83        return compat_names[id];
  84}
  85
  86fdt_addr_t fdtdec_get_addr_size_fixed(const void *blob, int node,
  87                                      const char *prop_name, int index, int na,
  88                                      int ns, fdt_size_t *sizep,
  89                                      bool translate)
  90{
  91        const fdt32_t *prop, *prop_end;
  92        const fdt32_t *prop_addr, *prop_size, *prop_after_size;
  93        int len;
  94        fdt_addr_t addr;
  95
  96        debug("%s: %s: ", __func__, prop_name);
  97
  98        prop = fdt_getprop(blob, node, prop_name, &len);
  99        if (!prop) {
 100                debug("(not found)\n");
 101                return FDT_ADDR_T_NONE;
 102        }
 103        prop_end = prop + (len / sizeof(*prop));
 104
 105        prop_addr = prop + (index * (na + ns));
 106        prop_size = prop_addr + na;
 107        prop_after_size = prop_size + ns;
 108        if (prop_after_size > prop_end) {
 109                debug("(not enough data: expected >= %d cells, got %d cells)\n",
 110                      (u32)(prop_after_size - prop), ((u32)(prop_end - prop)));
 111                return FDT_ADDR_T_NONE;
 112        }
 113
 114#if CONFIG_IS_ENABLED(OF_TRANSLATE)
 115        if (translate)
 116                addr = fdt_translate_address(blob, node, prop_addr);
 117        else
 118#endif
 119                addr = fdtdec_get_number(prop_addr, na);
 120
 121        if (sizep) {
 122                *sizep = fdtdec_get_number(prop_size, ns);
 123                debug("addr=%08llx, size=%llx\n", (unsigned long long)addr,
 124                      (unsigned long long)*sizep);
 125        } else {
 126                debug("addr=%08llx\n", (unsigned long long)addr);
 127        }
 128
 129        return addr;
 130}
 131
 132fdt_addr_t fdtdec_get_addr_size_auto_parent(const void *blob, int parent,
 133                                            int node, const char *prop_name,
 134                                            int index, fdt_size_t *sizep,
 135                                            bool translate)
 136{
 137        int na, ns;
 138
 139        debug("%s: ", __func__);
 140
 141        na = fdt_address_cells(blob, parent);
 142        if (na < 1) {
 143                debug("(bad #address-cells)\n");
 144                return FDT_ADDR_T_NONE;
 145        }
 146
 147        ns = fdt_size_cells(blob, parent);
 148        if (ns < 0) {
 149                debug("(bad #size-cells)\n");
 150                return FDT_ADDR_T_NONE;
 151        }
 152
 153        debug("na=%d, ns=%d, ", na, ns);
 154
 155        return fdtdec_get_addr_size_fixed(blob, node, prop_name, index, na,
 156                                          ns, sizep, translate);
 157}
 158
 159fdt_addr_t fdtdec_get_addr_size_auto_noparent(const void *blob, int node,
 160                                              const char *prop_name, int index,
 161                                              fdt_size_t *sizep,
 162                                              bool translate)
 163{
 164        int parent;
 165
 166        debug("%s: ", __func__);
 167
 168        parent = fdt_parent_offset(blob, node);
 169        if (parent < 0) {
 170                debug("(no parent found)\n");
 171                return FDT_ADDR_T_NONE;
 172        }
 173
 174        return fdtdec_get_addr_size_auto_parent(blob, parent, node, prop_name,
 175                                                index, sizep, translate);
 176}
 177
 178fdt_addr_t fdtdec_get_addr_size(const void *blob, int node,
 179                                const char *prop_name, fdt_size_t *sizep)
 180{
 181        int ns = sizep ? (sizeof(fdt_size_t) / sizeof(fdt32_t)) : 0;
 182
 183        return fdtdec_get_addr_size_fixed(blob, node, prop_name, 0,
 184                                          sizeof(fdt_addr_t) / sizeof(fdt32_t),
 185                                          ns, sizep, false);
 186}
 187
 188fdt_addr_t fdtdec_get_addr(const void *blob, int node, const char *prop_name)
 189{
 190        return fdtdec_get_addr_size(blob, node, prop_name, NULL);
 191}
 192
 193#if CONFIG_IS_ENABLED(PCI) && defined(CONFIG_DM_PCI)
 194int fdtdec_get_pci_vendev(const void *blob, int node, u16 *vendor, u16 *device)
 195{
 196        const char *list, *end;
 197        int len;
 198
 199        list = fdt_getprop(blob, node, "compatible", &len);
 200        if (!list)
 201                return -ENOENT;
 202
 203        end = list + len;
 204        while (list < end) {
 205                len = strlen(list);
 206                if (len >= strlen("pciVVVV,DDDD")) {
 207                        char *s = strstr(list, "pci");
 208
 209                        /*
 210                         * check if the string is something like pciVVVV,DDDD.RR
 211                         * or just pciVVVV,DDDD
 212                         */
 213                        if (s && s[7] == ',' &&
 214                            (s[12] == '.' || s[12] == 0)) {
 215                                s += 3;
 216                                *vendor = simple_strtol(s, NULL, 16);
 217
 218                                s += 5;
 219                                *device = simple_strtol(s, NULL, 16);
 220
 221                                return 0;
 222                        }
 223                }
 224                list += (len + 1);
 225        }
 226
 227        return -ENOENT;
 228}
 229
 230int fdtdec_get_pci_bar32(const struct udevice *dev, struct fdt_pci_addr *addr,
 231                         u32 *bar)
 232{
 233        int barnum;
 234
 235        /* extract the bar number from fdt_pci_addr */
 236        barnum = addr->phys_hi & 0xff;
 237        if (barnum < PCI_BASE_ADDRESS_0 || barnum > PCI_CARDBUS_CIS)
 238                return -EINVAL;
 239
 240        barnum = (barnum - PCI_BASE_ADDRESS_0) / 4;
 241        *bar = dm_pci_read_bar32(dev, barnum);
 242
 243        return 0;
 244}
 245#endif
 246
 247uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name,
 248                           uint64_t default_val)
 249{
 250        const unaligned_fdt64_t *cell64;
 251        int length;
 252
 253        cell64 = fdt_getprop(blob, node, prop_name, &length);
 254        if (!cell64 || length < sizeof(*cell64))
 255                return default_val;
 256
 257        return fdt64_to_cpu(*cell64);
 258}
 259
 260int fdtdec_get_is_enabled(const void *blob, int node)
 261{
 262        const char *cell;
 263
 264        /*
 265         * It should say "okay", so only allow that. Some fdts use "ok" but
 266         * this is a bug. Please fix your device tree source file. See here
 267         * for discussion:
 268         *
 269         * http://www.mail-archive.com/u-boot@lists.denx.de/msg71598.html
 270         */
 271        cell = fdt_getprop(blob, node, "status", NULL);
 272        if (cell)
 273                return strcmp(cell, "okay") == 0;
 274        return 1;
 275}
 276
 277enum fdt_compat_id fdtdec_lookup(const void *blob, int node)
 278{
 279        enum fdt_compat_id id;
 280
 281        /* Search our drivers */
 282        for (id = COMPAT_UNKNOWN; id < COMPAT_COUNT; id++)
 283                if (fdt_node_check_compatible(blob, node,
 284                                              compat_names[id]) == 0)
 285                        return id;
 286        return COMPAT_UNKNOWN;
 287}
 288
 289int fdtdec_next_compatible(const void *blob, int node, enum fdt_compat_id id)
 290{
 291        return fdt_node_offset_by_compatible(blob, node, compat_names[id]);
 292}
 293
 294int fdtdec_next_compatible_subnode(const void *blob, int node,
 295                                   enum fdt_compat_id id, int *depthp)
 296{
 297        do {
 298                node = fdt_next_node(blob, node, depthp);
 299        } while (*depthp > 1);
 300
 301        /* If this is a direct subnode, and compatible, return it */
 302        if (*depthp == 1 && 0 == fdt_node_check_compatible(
 303                                                blob, node, compat_names[id]))
 304                return node;
 305
 306        return -FDT_ERR_NOTFOUND;
 307}
 308
 309int fdtdec_next_alias(const void *blob, const char *name, enum fdt_compat_id id,
 310                      int *upto)
 311{
 312#define MAX_STR_LEN 20
 313        char str[MAX_STR_LEN + 20];
 314        int node, err;
 315
 316        /* snprintf() is not available */
 317        assert(strlen(name) < MAX_STR_LEN);
 318        sprintf(str, "%.*s%d", MAX_STR_LEN, name, *upto);
 319        node = fdt_path_offset(blob, str);
 320        if (node < 0)
 321                return node;
 322        err = fdt_node_check_compatible(blob, node, compat_names[id]);
 323        if (err < 0)
 324                return err;
 325        if (err)
 326                return -FDT_ERR_NOTFOUND;
 327        (*upto)++;
 328        return node;
 329}
 330
 331int fdtdec_find_aliases_for_id(const void *blob, const char *name,
 332                               enum fdt_compat_id id, int *node_list,
 333                               int maxcount)
 334{
 335        memset(node_list, '\0', sizeof(*node_list) * maxcount);
 336
 337        return fdtdec_add_aliases_for_id(blob, name, id, node_list, maxcount);
 338}
 339
 340/* TODO: Can we tighten this code up a little? */
 341int fdtdec_add_aliases_for_id(const void *blob, const char *name,
 342                              enum fdt_compat_id id, int *node_list,
 343                              int maxcount)
 344{
 345        int name_len = strlen(name);
 346        int nodes[maxcount];
 347        int num_found = 0;
 348        int offset, node;
 349        int alias_node;
 350        int count;
 351        int i, j;
 352
 353        /* find the alias node if present */
 354        alias_node = fdt_path_offset(blob, "/aliases");
 355
 356        /*
 357         * start with nothing, and we can assume that the root node can't
 358         * match
 359         */
 360        memset(nodes, '\0', sizeof(nodes));
 361
 362        /* First find all the compatible nodes */
 363        for (node = count = 0; node >= 0 && count < maxcount;) {
 364                node = fdtdec_next_compatible(blob, node, id);
 365                if (node >= 0)
 366                        nodes[count++] = node;
 367        }
 368        if (node >= 0)
 369                debug("%s: warning: maxcount exceeded with alias '%s'\n",
 370                      __func__, name);
 371
 372        /* Now find all the aliases */
 373        for (offset = fdt_first_property_offset(blob, alias_node);
 374                        offset > 0;
 375                        offset = fdt_next_property_offset(blob, offset)) {
 376                const struct fdt_property *prop;
 377                const char *path;
 378                int number;
 379                int found;
 380
 381                node = 0;
 382                prop = fdt_get_property_by_offset(blob, offset, NULL);
 383                path = fdt_string(blob, fdt32_to_cpu(prop->nameoff));
 384                if (prop->len && 0 == strncmp(path, name, name_len))
 385                        node = fdt_path_offset(blob, prop->data);
 386                if (node <= 0)
 387                        continue;
 388
 389                /* Get the alias number */
 390                number = simple_strtoul(path + name_len, NULL, 10);
 391                if (number < 0 || number >= maxcount) {
 392                        debug("%s: warning: alias '%s' is out of range\n",
 393                              __func__, path);
 394                        continue;
 395                }
 396
 397                /* Make sure the node we found is actually in our list! */
 398                found = -1;
 399                for (j = 0; j < count; j++)
 400                        if (nodes[j] == node) {
 401                                found = j;
 402                                break;
 403                        }
 404
 405                if (found == -1) {
 406                        debug("%s: warning: alias '%s' points to a node "
 407                                "'%s' that is missing or is not compatible "
 408                                " with '%s'\n", __func__, path,
 409                                fdt_get_name(blob, node, NULL),
 410                               compat_names[id]);
 411                        continue;
 412                }
 413
 414                /*
 415                 * Add this node to our list in the right place, and mark
 416                 * it as done.
 417                 */
 418                if (fdtdec_get_is_enabled(blob, node)) {
 419                        if (node_list[number]) {
 420                                debug("%s: warning: alias '%s' requires that "
 421                                      "a node be placed in the list in a "
 422                                      "position which is already filled by "
 423                                      "node '%s'\n", __func__, path,
 424                                      fdt_get_name(blob, node, NULL));
 425                                continue;
 426                        }
 427                        node_list[number] = node;
 428                        if (number >= num_found)
 429                                num_found = number + 1;
 430                }
 431                nodes[found] = 0;
 432        }
 433
 434        /* Add any nodes not mentioned by an alias */
 435        for (i = j = 0; i < maxcount; i++) {
 436                if (!node_list[i]) {
 437                        for (; j < maxcount; j++)
 438                                if (nodes[j] &&
 439                                    fdtdec_get_is_enabled(blob, nodes[j]))
 440                                        break;
 441
 442                        /* Have we run out of nodes to add? */
 443                        if (j == maxcount)
 444                                break;
 445
 446                        assert(!node_list[i]);
 447                        node_list[i] = nodes[j++];
 448                        if (i >= num_found)
 449                                num_found = i + 1;
 450                }
 451        }
 452
 453        return num_found;
 454}
 455
 456int fdtdec_get_alias_seq(const void *blob, const char *base, int offset,
 457                         int *seqp)
 458{
 459        int base_len = strlen(base);
 460        const char *find_name;
 461        int find_namelen;
 462        int prop_offset;
 463        int aliases;
 464
 465        find_name = fdt_get_name(blob, offset, &find_namelen);
 466        debug("Looking for '%s' at %d, name %s\n", base, offset, find_name);
 467
 468        aliases = fdt_path_offset(blob, "/aliases");
 469        for (prop_offset = fdt_first_property_offset(blob, aliases);
 470             prop_offset > 0;
 471             prop_offset = fdt_next_property_offset(blob, prop_offset)) {
 472                const char *prop;
 473                const char *name;
 474                const char *slash;
 475                int len, val;
 476
 477                prop = fdt_getprop_by_offset(blob, prop_offset, &name, &len);
 478                debug("   - %s, %s\n", name, prop);
 479                if (len < find_namelen || *prop != '/' || prop[len - 1] ||
 480                    strncmp(name, base, base_len))
 481                        continue;
 482
 483                slash = strrchr(prop, '/');
 484                if (strcmp(slash + 1, find_name))
 485                        continue;
 486                val = trailing_strtol(name);
 487                if (val != -1) {
 488                        *seqp = val;
 489                        debug("Found seq %d\n", *seqp);
 490                        return 0;
 491                }
 492        }
 493
 494        debug("Not found\n");
 495        return -ENOENT;
 496}
 497
 498int fdtdec_get_alias_highest_id(const void *blob, const char *base)
 499{
 500        int base_len = strlen(base);
 501        int prop_offset;
 502        int aliases;
 503        int max = -1;
 504
 505        debug("Looking for highest alias id for '%s'\n", base);
 506
 507        aliases = fdt_path_offset(blob, "/aliases");
 508        for (prop_offset = fdt_first_property_offset(blob, aliases);
 509             prop_offset > 0;
 510             prop_offset = fdt_next_property_offset(blob, prop_offset)) {
 511                const char *prop;
 512                const char *name;
 513                int len, val;
 514
 515                prop = fdt_getprop_by_offset(blob, prop_offset, &name, &len);
 516                debug("   - %s, %s\n", name, prop);
 517                if (*prop != '/' || prop[len - 1] ||
 518                    strncmp(name, base, base_len))
 519                        continue;
 520
 521                val = trailing_strtol(name);
 522                if (val > max) {
 523                        debug("Found seq %d\n", val);
 524                        max = val;
 525                }
 526        }
 527
 528        return max;
 529}
 530
 531const char *fdtdec_get_chosen_prop(const void *blob, const char *name)
 532{
 533        int chosen_node;
 534
 535        if (!blob)
 536                return NULL;
 537        chosen_node = fdt_path_offset(blob, "/chosen");
 538        return fdt_getprop(blob, chosen_node, name, NULL);
 539}
 540
 541int fdtdec_get_chosen_node(const void *blob, const char *name)
 542{
 543        const char *prop;
 544
 545        prop = fdtdec_get_chosen_prop(blob, name);
 546        if (!prop)
 547                return -FDT_ERR_NOTFOUND;
 548        return fdt_path_offset(blob, prop);
 549}
 550
 551int fdtdec_check_fdt(void)
 552{
 553        /*
 554         * We must have an FDT, but we cannot panic() yet since the console
 555         * is not ready. So for now, just assert(). Boards which need an early
 556         * FDT (prior to console ready) will need to make their own
 557         * arrangements and do their own checks.
 558         */
 559        assert(!fdtdec_prepare_fdt());
 560        return 0;
 561}
 562
 563/*
 564 * This function is a little odd in that it accesses global data. At some
 565 * point if the architecture board.c files merge this will make more sense.
 566 * Even now, it is common code.
 567 */
 568int fdtdec_prepare_fdt(void)
 569{
 570        if (!gd->fdt_blob || ((uintptr_t)gd->fdt_blob & 3) ||
 571            fdt_check_header(gd->fdt_blob)) {
 572#ifdef CONFIG_SPL_BUILD
 573                puts("Missing DTB\n");
 574#else
 575                puts("No valid device tree binary found - please append one to U-Boot binary, use u-boot-dtb.bin or define CONFIG_OF_EMBED. For sandbox, use -d <file.dtb>\n");
 576# ifdef DEBUG
 577                if (gd->fdt_blob) {
 578                        printf("fdt_blob=%p\n", gd->fdt_blob);
 579                        print_buffer((ulong)gd->fdt_blob, gd->fdt_blob, 4,
 580                                     32, 0);
 581                }
 582# endif
 583#endif
 584                return -1;
 585        }
 586        return 0;
 587}
 588
 589int fdtdec_lookup_phandle(const void *blob, int node, const char *prop_name)
 590{
 591        const u32 *phandle;
 592        int lookup;
 593
 594        debug("%s: %s\n", __func__, prop_name);
 595        phandle = fdt_getprop(blob, node, prop_name, NULL);
 596        if (!phandle)
 597                return -FDT_ERR_NOTFOUND;
 598
 599        lookup = fdt_node_offset_by_phandle(blob, fdt32_to_cpu(*phandle));
 600        return lookup;
 601}
 602
 603/**
 604 * Look up a property in a node and check that it has a minimum length.
 605 *
 606 * @param blob          FDT blob
 607 * @param node          node to examine
 608 * @param prop_name     name of property to find
 609 * @param min_len       minimum property length in bytes
 610 * @param err           0 if ok, or -FDT_ERR_NOTFOUND if the property is not
 611                        found, or -FDT_ERR_BADLAYOUT if not enough data
 612 * @return pointer to cell, which is only valid if err == 0
 613 */
 614static const void *get_prop_check_min_len(const void *blob, int node,
 615                                          const char *prop_name, int min_len,
 616                                          int *err)
 617{
 618        const void *cell;
 619        int len;
 620
 621        debug("%s: %s\n", __func__, prop_name);
 622        cell = fdt_getprop(blob, node, prop_name, &len);
 623        if (!cell)
 624                *err = -FDT_ERR_NOTFOUND;
 625        else if (len < min_len)
 626                *err = -FDT_ERR_BADLAYOUT;
 627        else
 628                *err = 0;
 629        return cell;
 630}
 631
 632int fdtdec_get_int_array(const void *blob, int node, const char *prop_name,
 633                         u32 *array, int count)
 634{
 635        const u32 *cell;
 636        int err = 0;
 637
 638        debug("%s: %s\n", __func__, prop_name);
 639        cell = get_prop_check_min_len(blob, node, prop_name,
 640                                      sizeof(u32) * count, &err);
 641        if (!err) {
 642                int i;
 643
 644                for (i = 0; i < count; i++)
 645                        array[i] = fdt32_to_cpu(cell[i]);
 646        }
 647        return err;
 648}
 649
 650int fdtdec_get_int_array_count(const void *blob, int node,
 651                               const char *prop_name, u32 *array, int count)
 652{
 653        const u32 *cell;
 654        int len, elems;
 655        int i;
 656
 657        debug("%s: %s\n", __func__, prop_name);
 658        cell = fdt_getprop(blob, node, prop_name, &len);
 659        if (!cell)
 660                return -FDT_ERR_NOTFOUND;
 661        elems = len / sizeof(u32);
 662        if (count > elems)
 663                count = elems;
 664        for (i = 0; i < count; i++)
 665                array[i] = fdt32_to_cpu(cell[i]);
 666
 667        return count;
 668}
 669
 670const u32 *fdtdec_locate_array(const void *blob, int node,
 671                               const char *prop_name, int count)
 672{
 673        const u32 *cell;
 674        int err;
 675
 676        cell = get_prop_check_min_len(blob, node, prop_name,
 677                                      sizeof(u32) * count, &err);
 678        return err ? NULL : cell;
 679}
 680
 681int fdtdec_get_bool(const void *blob, int node, const char *prop_name)
 682{
 683        const s32 *cell;
 684        int len;
 685
 686        debug("%s: %s\n", __func__, prop_name);
 687        cell = fdt_getprop(blob, node, prop_name, &len);
 688        return cell != NULL;
 689}
 690
 691int fdtdec_parse_phandle_with_args(const void *blob, int src_node,
 692                                   const char *list_name,
 693                                   const char *cells_name,
 694                                   int cell_count, int index,
 695                                   struct fdtdec_phandle_args *out_args)
 696{
 697        const __be32 *list, *list_end;
 698        int rc = 0, size, cur_index = 0;
 699        uint32_t count = 0;
 700        int node = -1;
 701        int phandle;
 702
 703        /* Retrieve the phandle list property */
 704        list = fdt_getprop(blob, src_node, list_name, &size);
 705        if (!list)
 706                return -ENOENT;
 707        list_end = list + size / sizeof(*list);
 708
 709        /* Loop over the phandles until all the requested entry is found */
 710        while (list < list_end) {
 711                rc = -EINVAL;
 712                count = 0;
 713
 714                /*
 715                 * If phandle is 0, then it is an empty entry with no
 716                 * arguments.  Skip forward to the next entry.
 717                 */
 718                phandle = be32_to_cpup(list++);
 719                if (phandle) {
 720                        /*
 721                         * Find the provider node and parse the #*-cells
 722                         * property to determine the argument length.
 723                         *
 724                         * This is not needed if the cell count is hard-coded
 725                         * (i.e. cells_name not set, but cell_count is set),
 726                         * except when we're going to return the found node
 727                         * below.
 728                         */
 729                        if (cells_name || cur_index == index) {
 730                                node = fdt_node_offset_by_phandle(blob,
 731                                                                  phandle);
 732                                if (!node) {
 733                                        debug("%s: could not find phandle\n",
 734                                              fdt_get_name(blob, src_node,
 735                                                           NULL));
 736                                        goto err;
 737                                }
 738                        }
 739
 740                        if (cells_name) {
 741                                count = fdtdec_get_int(blob, node, cells_name,
 742                                                       -1);
 743                                if (count == -1) {
 744                                        debug("%s: could not get %s for %s\n",
 745                                              fdt_get_name(blob, src_node,
 746                                                           NULL),
 747                                              cells_name,
 748                                              fdt_get_name(blob, node,
 749                                                           NULL));
 750                                        goto err;
 751                                }
 752                        } else {
 753                                count = cell_count;
 754                        }
 755
 756                        /*
 757                         * Make sure that the arguments actually fit in the
 758                         * remaining property data length
 759                         */
 760                        if (list + count > list_end) {
 761                                debug("%s: arguments longer than property\n",
 762                                      fdt_get_name(blob, src_node, NULL));
 763                                goto err;
 764                        }
 765                }
 766
 767                /*
 768                 * All of the error cases above bail out of the loop, so at
 769                 * this point, the parsing is successful. If the requested
 770                 * index matches, then fill the out_args structure and return,
 771                 * or return -ENOENT for an empty entry.
 772                 */
 773                rc = -ENOENT;
 774                if (cur_index == index) {
 775                        if (!phandle)
 776                                goto err;
 777
 778                        if (out_args) {
 779                                int i;
 780
 781                                if (count > MAX_PHANDLE_ARGS) {
 782                                        debug("%s: too many arguments %d\n",
 783                                              fdt_get_name(blob, src_node,
 784                                                           NULL), count);
 785                                        count = MAX_PHANDLE_ARGS;
 786                                }
 787                                out_args->node = node;
 788                                out_args->args_count = count;
 789                                for (i = 0; i < count; i++) {
 790                                        out_args->args[i] =
 791                                                        be32_to_cpup(list++);
 792                                }
 793                        }
 794
 795                        /* Found it! return success */
 796                        return 0;
 797                }
 798
 799                node = -1;
 800                list += count;
 801                cur_index++;
 802        }
 803
 804        /*
 805         * Result will be one of:
 806         * -ENOENT : index is for empty phandle
 807         * -EINVAL : parsing error on data
 808         * [1..n]  : Number of phandle (count mode; when index = -1)
 809         */
 810        rc = index < 0 ? cur_index : -ENOENT;
 811 err:
 812        return rc;
 813}
 814
 815int fdtdec_get_byte_array(const void *blob, int node, const char *prop_name,
 816                          u8 *array, int count)
 817{
 818        const u8 *cell;
 819        int err;
 820
 821        cell = get_prop_check_min_len(blob, node, prop_name, count, &err);
 822        if (!err)
 823                memcpy(array, cell, count);
 824        return err;
 825}
 826
 827const u8 *fdtdec_locate_byte_array(const void *blob, int node,
 828                                   const char *prop_name, int count)
 829{
 830        const u8 *cell;
 831        int err;
 832
 833        cell = get_prop_check_min_len(blob, node, prop_name, count, &err);
 834        if (err)
 835                return NULL;
 836        return cell;
 837}
 838
 839int fdtdec_get_config_int(const void *blob, const char *prop_name,
 840                          int default_val)
 841{
 842        int config_node;
 843
 844        debug("%s: %s\n", __func__, prop_name);
 845        config_node = fdt_path_offset(blob, "/config");
 846        if (config_node < 0)
 847                return default_val;
 848        return fdtdec_get_int(blob, config_node, prop_name, default_val);
 849}
 850
 851int fdtdec_get_config_bool(const void *blob, const char *prop_name)
 852{
 853        int config_node;
 854        const void *prop;
 855
 856        debug("%s: %s\n", __func__, prop_name);
 857        config_node = fdt_path_offset(blob, "/config");
 858        if (config_node < 0)
 859                return 0;
 860        prop = fdt_get_property(blob, config_node, prop_name, NULL);
 861
 862        return prop != NULL;
 863}
 864
 865char *fdtdec_get_config_string(const void *blob, const char *prop_name)
 866{
 867        const char *nodep;
 868        int nodeoffset;
 869        int len;
 870
 871        debug("%s: %s\n", __func__, prop_name);
 872        nodeoffset = fdt_path_offset(blob, "/config");
 873        if (nodeoffset < 0)
 874                return NULL;
 875
 876        nodep = fdt_getprop(blob, nodeoffset, prop_name, &len);
 877        if (!nodep)
 878                return NULL;
 879
 880        return (char *)nodep;
 881}
 882
 883u64 fdtdec_get_number(const fdt32_t *ptr, unsigned int cells)
 884{
 885        u64 number = 0;
 886
 887        while (cells--)
 888                number = (number << 32) | fdt32_to_cpu(*ptr++);
 889
 890        return number;
 891}
 892
 893int fdt_get_resource(const void *fdt, int node, const char *property,
 894                     unsigned int index, struct fdt_resource *res)
 895{
 896        const fdt32_t *ptr, *end;
 897        int na, ns, len, parent;
 898        unsigned int i = 0;
 899
 900        parent = fdt_parent_offset(fdt, node);
 901        if (parent < 0)
 902                return parent;
 903
 904        na = fdt_address_cells(fdt, parent);
 905        ns = fdt_size_cells(fdt, parent);
 906
 907        ptr = fdt_getprop(fdt, node, property, &len);
 908        if (!ptr)
 909                return len;
 910
 911        end = ptr + len / sizeof(*ptr);
 912
 913        while (ptr + na + ns <= end) {
 914                if (i == index) {
 915                        res->start = fdtdec_get_number(ptr, na);
 916                        res->end = res->start;
 917                        res->end += fdtdec_get_number(&ptr[na], ns) - 1;
 918                        return 0;
 919                }
 920
 921                ptr += na + ns;
 922                i++;
 923        }
 924
 925        return -FDT_ERR_NOTFOUND;
 926}
 927
 928int fdt_get_named_resource(const void *fdt, int node, const char *property,
 929                           const char *prop_names, const char *name,
 930                           struct fdt_resource *res)
 931{
 932        int index;
 933
 934        index = fdt_stringlist_search(fdt, node, prop_names, name);
 935        if (index < 0)
 936                return index;
 937
 938        return fdt_get_resource(fdt, node, property, index, res);
 939}
 940
 941static int decode_timing_property(const void *blob, int node, const char *name,
 942                                  struct timing_entry *result)
 943{
 944        int length, ret = 0;
 945        const u32 *prop;
 946
 947        prop = fdt_getprop(blob, node, name, &length);
 948        if (!prop) {
 949                debug("%s: could not find property %s\n",
 950                      fdt_get_name(blob, node, NULL), name);
 951                return length;
 952        }
 953
 954        if (length == sizeof(u32)) {
 955                result->typ = fdtdec_get_int(blob, node, name, 0);
 956                result->min = result->typ;
 957                result->max = result->typ;
 958        } else {
 959                ret = fdtdec_get_int_array(blob, node, name, &result->min, 3);
 960        }
 961
 962        return ret;
 963}
 964
 965int fdtdec_decode_display_timing(const void *blob, int parent, int index,
 966                                 struct display_timing *dt)
 967{
 968        int i, node, timings_node;
 969        u32 val = 0;
 970        int ret = 0;
 971
 972        timings_node = fdt_subnode_offset(blob, parent, "display-timings");
 973        if (timings_node < 0)
 974                return timings_node;
 975
 976        for (i = 0, node = fdt_first_subnode(blob, timings_node);
 977             node > 0 && i != index;
 978             node = fdt_next_subnode(blob, node))
 979                i++;
 980
 981        if (node < 0)
 982                return node;
 983
 984        memset(dt, 0, sizeof(*dt));
 985
 986        ret |= decode_timing_property(blob, node, "hback-porch",
 987                                      &dt->hback_porch);
 988        ret |= decode_timing_property(blob, node, "hfront-porch",
 989                                      &dt->hfront_porch);
 990        ret |= decode_timing_property(blob, node, "hactive", &dt->hactive);
 991        ret |= decode_timing_property(blob, node, "hsync-len", &dt->hsync_len);
 992        ret |= decode_timing_property(blob, node, "vback-porch",
 993                                      &dt->vback_porch);
 994        ret |= decode_timing_property(blob, node, "vfront-porch",
 995                                      &dt->vfront_porch);
 996        ret |= decode_timing_property(blob, node, "vactive", &dt->vactive);
 997        ret |= decode_timing_property(blob, node, "vsync-len", &dt->vsync_len);
 998        ret |= decode_timing_property(blob, node, "clock-frequency",
 999                                      &dt->pixelclock);
1000
1001        dt->flags = 0;
1002        val = fdtdec_get_int(blob, node, "vsync-active", -1);
1003        if (val != -1) {
1004                dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
1005                                DISPLAY_FLAGS_VSYNC_LOW;
1006        }
1007        val = fdtdec_get_int(blob, node, "hsync-active", -1);
1008        if (val != -1) {
1009                dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
1010                                DISPLAY_FLAGS_HSYNC_LOW;
1011        }
1012        val = fdtdec_get_int(blob, node, "de-active", -1);
1013        if (val != -1) {
1014                dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
1015                                DISPLAY_FLAGS_DE_LOW;
1016        }
1017        val = fdtdec_get_int(blob, node, "pixelclk-active", -1);
1018        if (val != -1) {
1019                dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
1020                                DISPLAY_FLAGS_PIXDATA_NEGEDGE;
1021        }
1022
1023        if (fdtdec_get_bool(blob, node, "interlaced"))
1024                dt->flags |= DISPLAY_FLAGS_INTERLACED;
1025        if (fdtdec_get_bool(blob, node, "doublescan"))
1026                dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
1027        if (fdtdec_get_bool(blob, node, "doubleclk"))
1028                dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
1029
1030        return ret;
1031}
1032
1033int fdtdec_setup_mem_size_base_fdt(const void *blob)
1034{
1035        int ret, mem;
1036        struct fdt_resource res;
1037
1038        mem = fdt_path_offset(blob, "/memory");
1039        if (mem < 0) {
1040                debug("%s: Missing /memory node\n", __func__);
1041                return -EINVAL;
1042        }
1043
1044        ret = fdt_get_resource(blob, mem, "reg", 0, &res);
1045        if (ret != 0) {
1046                debug("%s: Unable to decode first memory bank\n", __func__);
1047                return -EINVAL;
1048        }
1049
1050        gd->ram_size = (phys_size_t)(res.end - res.start + 1);
1051        gd->ram_base = (unsigned long)res.start;
1052        debug("%s: Initial DRAM size %llx\n", __func__,
1053              (unsigned long long)gd->ram_size);
1054
1055        return 0;
1056}
1057
1058int fdtdec_setup_mem_size_base(void)
1059{
1060        return fdtdec_setup_mem_size_base_fdt(gd->fdt_blob);
1061}
1062
1063#if defined(CONFIG_NR_DRAM_BANKS)
1064
1065static int get_next_memory_node(const void *blob, int mem)
1066{
1067        do {
1068                mem = fdt_node_offset_by_prop_value(blob, mem,
1069                                                    "device_type", "memory", 7);
1070        } while (!fdtdec_get_is_enabled(blob, mem));
1071
1072        return mem;
1073}
1074
1075int fdtdec_setup_memory_banksize_fdt(const void *blob)
1076{
1077        int bank, ret, mem, reg = 0;
1078        struct fdt_resource res;
1079
1080        mem = get_next_memory_node(blob, -1);
1081        if (mem < 0) {
1082                debug("%s: Missing /memory node\n", __func__);
1083                return -EINVAL;
1084        }
1085
1086        for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
1087                ret = fdt_get_resource(blob, mem, "reg", reg++, &res);
1088                if (ret == -FDT_ERR_NOTFOUND) {
1089                        reg = 0;
1090                        mem = get_next_memory_node(blob, mem);
1091                        if (mem == -FDT_ERR_NOTFOUND)
1092                                break;
1093
1094                        ret = fdt_get_resource(blob, mem, "reg", reg++, &res);
1095                        if (ret == -FDT_ERR_NOTFOUND)
1096                                break;
1097                }
1098                if (ret != 0) {
1099                        return -EINVAL;
1100                }
1101
1102                gd->bd->bi_dram[bank].start = (phys_addr_t)res.start;
1103                gd->bd->bi_dram[bank].size =
1104                        (phys_size_t)(res.end - res.start + 1);
1105
1106                debug("%s: DRAM Bank #%d: start = 0x%llx, size = 0x%llx\n",
1107                      __func__, bank,
1108                      (unsigned long long)gd->bd->bi_dram[bank].start,
1109                      (unsigned long long)gd->bd->bi_dram[bank].size);
1110        }
1111
1112        return 0;
1113}
1114
1115int fdtdec_setup_memory_banksize(void)
1116{
1117        return fdtdec_setup_memory_banksize_fdt(gd->fdt_blob);
1118
1119}
1120#endif
1121
1122#if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
1123# if CONFIG_IS_ENABLED(MULTI_DTB_FIT_GZIP) ||\
1124        CONFIG_IS_ENABLED(MULTI_DTB_FIT_LZO)
1125static int uncompress_blob(const void *src, ulong sz_src, void **dstp)
1126{
1127        size_t sz_out = CONFIG_VAL(MULTI_DTB_FIT_UNCOMPRESS_SZ);
1128        bool gzip = 0, lzo = 0;
1129        ulong sz_in = sz_src;
1130        void *dst;
1131        int rc;
1132
1133        if (CONFIG_IS_ENABLED(GZIP))
1134                if (gzip_parse_header(src, sz_in) >= 0)
1135                        gzip = 1;
1136        if (CONFIG_IS_ENABLED(LZO))
1137                if (!gzip && lzop_is_valid_header(src))
1138                        lzo = 1;
1139
1140        if (!gzip && !lzo)
1141                return -EBADMSG;
1142
1143
1144        if (CONFIG_IS_ENABLED(MULTI_DTB_FIT_DYN_ALLOC)) {
1145                dst = malloc(sz_out);
1146                if (!dst) {
1147                        puts("uncompress_blob: Unable to allocate memory\n");
1148                        return -ENOMEM;
1149                }
1150        } else  {
1151#  if CONFIG_IS_ENABLED(MULTI_DTB_FIT_USER_DEFINED_AREA)
1152                dst = (void *)CONFIG_VAL(MULTI_DTB_FIT_USER_DEF_ADDR);
1153#  else
1154                return -ENOTSUPP;
1155#  endif
1156        }
1157
1158        if (CONFIG_IS_ENABLED(GZIP) && gzip)
1159                rc = gunzip(dst, sz_out, (u8 *)src, &sz_in);
1160        else if (CONFIG_IS_ENABLED(LZO) && lzo)
1161                rc = lzop_decompress(src, sz_in, dst, &sz_out);
1162        else
1163                hang();
1164
1165        if (rc < 0) {
1166                /* not a valid compressed blob */
1167                puts("uncompress_blob: Unable to uncompress\n");
1168                if (CONFIG_IS_ENABLED(MULTI_DTB_FIT_DYN_ALLOC))
1169                        free(dst);
1170                return -EBADMSG;
1171        }
1172        *dstp = dst;
1173        return 0;
1174}
1175# else
1176static int uncompress_blob(const void *src, ulong sz_src, void **dstp)
1177{
1178        *dstp = (void *)src;
1179        return 0;
1180}
1181# endif
1182#endif
1183
1184#if defined(CONFIG_OF_BOARD) || defined(CONFIG_OF_SEPARATE)
1185/*
1186 * For CONFIG_OF_SEPARATE, the board may optionally implement this to
1187 * provide and/or fixup the fdt.
1188 */
1189__weak void *board_fdt_blob_setup(void)
1190{
1191        void *fdt_blob = NULL;
1192#ifdef CONFIG_SPL_BUILD
1193        /* FDT is at end of BSS unless it is in a different memory region */
1194        if (IS_ENABLED(CONFIG_SPL_SEPARATE_BSS))
1195                fdt_blob = (ulong *)&_image_binary_end;
1196        else
1197                fdt_blob = (ulong *)&__bss_end;
1198#else
1199        /* FDT is at end of image */
1200        fdt_blob = (ulong *)&_end;
1201#endif
1202        return fdt_blob;
1203}
1204#endif
1205
1206int fdtdec_set_ethernet_mac_address(void *fdt, const u8 *mac, size_t size)
1207{
1208        const char *path;
1209        int offset, err;
1210
1211        if (!is_valid_ethaddr(mac))
1212                return -EINVAL;
1213
1214        path = fdt_get_alias(fdt, "ethernet");
1215        if (!path)
1216                return 0;
1217
1218        debug("ethernet alias found: %s\n", path);
1219
1220        offset = fdt_path_offset(fdt, path);
1221        if (offset < 0) {
1222                debug("ethernet alias points to absent node %s\n", path);
1223                return -ENOENT;
1224        }
1225
1226        err = fdt_setprop_inplace(fdt, offset, "local-mac-address", mac, size);
1227        if (err < 0)
1228                return err;
1229
1230        debug("MAC address: %pM\n", mac);
1231
1232        return 0;
1233}
1234
1235static int fdtdec_init_reserved_memory(void *blob)
1236{
1237        int na, ns, node, err;
1238        fdt32_t value;
1239
1240        /* inherit #address-cells and #size-cells from the root node */
1241        na = fdt_address_cells(blob, 0);
1242        ns = fdt_size_cells(blob, 0);
1243
1244        node = fdt_add_subnode(blob, 0, "reserved-memory");
1245        if (node < 0)
1246                return node;
1247
1248        err = fdt_setprop(blob, node, "ranges", NULL, 0);
1249        if (err < 0)
1250                return err;
1251
1252        value = cpu_to_fdt32(ns);
1253
1254        err = fdt_setprop(blob, node, "#size-cells", &value, sizeof(value));
1255        if (err < 0)
1256                return err;
1257
1258        value = cpu_to_fdt32(na);
1259
1260        err = fdt_setprop(blob, node, "#address-cells", &value, sizeof(value));
1261        if (err < 0)
1262                return err;
1263
1264        return node;
1265}
1266
1267int fdtdec_add_reserved_memory(void *blob, const char *basename,
1268                               const struct fdt_memory *carveout,
1269                               uint32_t *phandlep)
1270{
1271        fdt32_t cells[4] = {}, *ptr = cells;
1272        uint32_t upper, lower, phandle;
1273        int parent, node, na, ns, err;
1274        fdt_size_t size;
1275        char name[64];
1276
1277        /* create an empty /reserved-memory node if one doesn't exist */
1278        parent = fdt_path_offset(blob, "/reserved-memory");
1279        if (parent < 0) {
1280                parent = fdtdec_init_reserved_memory(blob);
1281                if (parent < 0)
1282                        return parent;
1283        }
1284
1285        /* only 1 or 2 #address-cells and #size-cells are supported */
1286        na = fdt_address_cells(blob, parent);
1287        if (na < 1 || na > 2)
1288                return -FDT_ERR_BADNCELLS;
1289
1290        ns = fdt_size_cells(blob, parent);
1291        if (ns < 1 || ns > 2)
1292                return -FDT_ERR_BADNCELLS;
1293
1294        /* find a matching node and return the phandle to that */
1295        fdt_for_each_subnode(node, blob, parent) {
1296                const char *name = fdt_get_name(blob, node, NULL);
1297                phys_addr_t addr, size;
1298
1299                addr = fdtdec_get_addr_size(blob, node, "reg", &size);
1300                if (addr == FDT_ADDR_T_NONE) {
1301                        debug("failed to read address/size for %s\n", name);
1302                        continue;
1303                }
1304
1305                if (addr == carveout->start && (addr + size - 1) ==
1306                                                carveout->end) {
1307                        if (phandlep)
1308                                *phandlep = fdt_get_phandle(blob, node);
1309                        return 0;
1310                }
1311        }
1312
1313        /*
1314         * Unpack the start address and generate the name of the new node
1315         * base on the basename and the unit-address.
1316         */
1317        upper = upper_32_bits(carveout->start);
1318        lower = lower_32_bits(carveout->start);
1319
1320        if (na > 1 && upper > 0)
1321                snprintf(name, sizeof(name), "%s@%x,%x", basename, upper,
1322                         lower);
1323        else {
1324                if (upper > 0) {
1325                        debug("address %08x:%08x exceeds addressable space\n",
1326                              upper, lower);
1327                        return -FDT_ERR_BADVALUE;
1328                }
1329
1330                snprintf(name, sizeof(name), "%s@%x", basename, lower);
1331        }
1332
1333        node = fdt_add_subnode(blob, parent, name);
1334        if (node < 0)
1335                return node;
1336
1337        if (phandlep) {
1338                err = fdt_generate_phandle(blob, &phandle);
1339                if (err < 0)
1340                        return err;
1341
1342                err = fdtdec_set_phandle(blob, node, phandle);
1343                if (err < 0)
1344                        return err;
1345        }
1346
1347        /* store one or two address cells */
1348        if (na > 1)
1349                *ptr++ = cpu_to_fdt32(upper);
1350
1351        *ptr++ = cpu_to_fdt32(lower);
1352
1353        /* store one or two size cells */
1354        size = carveout->end - carveout->start + 1;
1355        upper = upper_32_bits(size);
1356        lower = lower_32_bits(size);
1357
1358        if (ns > 1)
1359                *ptr++ = cpu_to_fdt32(upper);
1360
1361        *ptr++ = cpu_to_fdt32(lower);
1362
1363        err = fdt_setprop(blob, node, "reg", cells, (na + ns) * sizeof(*cells));
1364        if (err < 0)
1365                return err;
1366
1367        /* return the phandle for the new node for the caller to use */
1368        if (phandlep)
1369                *phandlep = phandle;
1370
1371        return 0;
1372}
1373
1374int fdtdec_get_carveout(const void *blob, const char *node, const char *name,
1375                        unsigned int index, struct fdt_memory *carveout)
1376{
1377        const fdt32_t *prop;
1378        uint32_t phandle;
1379        int offset, len;
1380        fdt_size_t size;
1381
1382        offset = fdt_path_offset(blob, node);
1383        if (offset < 0)
1384                return offset;
1385
1386        prop = fdt_getprop(blob, offset, name, &len);
1387        if (!prop) {
1388                debug("failed to get %s for %s\n", name, node);
1389                return -FDT_ERR_NOTFOUND;
1390        }
1391
1392        if ((len % sizeof(phandle)) != 0) {
1393                debug("invalid phandle property\n");
1394                return -FDT_ERR_BADPHANDLE;
1395        }
1396
1397        if (len < (sizeof(phandle) * (index + 1))) {
1398                debug("invalid phandle index\n");
1399                return -FDT_ERR_BADPHANDLE;
1400        }
1401
1402        phandle = fdt32_to_cpu(prop[index]);
1403
1404        offset = fdt_node_offset_by_phandle(blob, phandle);
1405        if (offset < 0) {
1406                debug("failed to find node for phandle %u\n", phandle);
1407                return offset;
1408        }
1409
1410        carveout->start = fdtdec_get_addr_size_auto_noparent(blob, offset,
1411                                                             "reg", 0, &size,
1412                                                             true);
1413        if (carveout->start == FDT_ADDR_T_NONE) {
1414                debug("failed to read address/size from \"reg\" property\n");
1415                return -FDT_ERR_NOTFOUND;
1416        }
1417
1418        carveout->end = carveout->start + size - 1;
1419
1420        return 0;
1421}
1422
1423int fdtdec_set_carveout(void *blob, const char *node, const char *prop_name,
1424                        unsigned int index, const char *name,
1425                        const struct fdt_memory *carveout)
1426{
1427        uint32_t phandle;
1428        int err, offset, len;
1429        fdt32_t value;
1430        void *prop;
1431
1432        err = fdtdec_add_reserved_memory(blob, name, carveout, &phandle);
1433        if (err < 0) {
1434                debug("failed to add reserved memory: %d\n", err);
1435                return err;
1436        }
1437
1438        offset = fdt_path_offset(blob, node);
1439        if (offset < 0) {
1440                debug("failed to find offset for node %s: %d\n", node, offset);
1441                return offset;
1442        }
1443
1444        value = cpu_to_fdt32(phandle);
1445
1446        if (!fdt_getprop(blob, offset, prop_name, &len)) {
1447                if (len == -FDT_ERR_NOTFOUND)
1448                        len = 0;
1449                else
1450                        return len;
1451        }
1452
1453        if ((index + 1) * sizeof(value) > len) {
1454                err = fdt_setprop_placeholder(blob, offset, prop_name,
1455                                              (index + 1) * sizeof(value),
1456                                              &prop);
1457                if (err < 0) {
1458                        debug("failed to resize reserved memory property: %s\n",
1459                              fdt_strerror(err));
1460                        return err;
1461                }
1462        }
1463
1464        err = fdt_setprop_inplace_namelen_partial(blob, offset, prop_name,
1465                                                  strlen(prop_name),
1466                                                  index * sizeof(value),
1467                                                  &value, sizeof(value));
1468        if (err < 0) {
1469                debug("failed to update %s property for node %s: %s\n",
1470                      prop_name, node, fdt_strerror(err));
1471                return err;
1472        }
1473
1474        return 0;
1475}
1476
1477__weak int fdtdec_board_setup(const void *fdt_blob)
1478{
1479        return 0;
1480}
1481
1482int fdtdec_setup(void)
1483{
1484        int ret;
1485#if CONFIG_IS_ENABLED(OF_CONTROL)
1486# if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
1487        void *fdt_blob;
1488# endif
1489# ifdef CONFIG_OF_EMBED
1490        /* Get a pointer to the FDT */
1491#  ifdef CONFIG_SPL_BUILD
1492        gd->fdt_blob = __dtb_dt_spl_begin;
1493#  else
1494        gd->fdt_blob = __dtb_dt_begin;
1495#  endif
1496# elif defined(CONFIG_OF_BOARD) || defined(CONFIG_OF_SEPARATE)
1497        /* Allow the board to override the fdt address. */
1498        gd->fdt_blob = board_fdt_blob_setup();
1499# elif defined(CONFIG_OF_HOSTFILE)
1500        if (sandbox_read_fdt_from_file()) {
1501                puts("Failed to read control FDT\n");
1502                return -1;
1503        }
1504# elif defined(CONFIG_OF_PRIOR_STAGE)
1505        gd->fdt_blob = (void *)prior_stage_fdt_address;
1506# endif
1507# ifndef CONFIG_SPL_BUILD
1508        /* Allow the early environment to override the fdt address */
1509        gd->fdt_blob = map_sysmem
1510                (env_get_ulong("fdtcontroladdr", 16,
1511                               (unsigned long)map_to_sysmem(gd->fdt_blob)), 0);
1512# endif
1513
1514# if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
1515        /*
1516         * Try and uncompress the blob.
1517         * Unfortunately there is no way to know how big the input blob really
1518         * is. So let us set the maximum input size arbitrarily high. 16MB
1519         * ought to be more than enough for packed DTBs.
1520         */
1521        if (uncompress_blob(gd->fdt_blob, 0x1000000, &fdt_blob) == 0)
1522                gd->fdt_blob = fdt_blob;
1523
1524        /*
1525         * Check if blob is a FIT images containings DTBs.
1526         * If so, pick the most relevant
1527         */
1528        fdt_blob = locate_dtb_in_fit(gd->fdt_blob);
1529        if (fdt_blob) {
1530                gd->multi_dtb_fit = gd->fdt_blob;
1531                gd->fdt_blob = fdt_blob;
1532        }
1533
1534# endif
1535#endif
1536
1537        ret = fdtdec_prepare_fdt();
1538        if (!ret)
1539                ret = fdtdec_board_setup(gd->fdt_blob);
1540        return ret;
1541}
1542
1543#if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
1544int fdtdec_resetup(int *rescan)
1545{
1546        void *fdt_blob;
1547
1548        /*
1549         * If the current DTB is part of a compressed FIT image,
1550         * try to locate the best match from the uncompressed
1551         * FIT image stillpresent there. Save the time and space
1552         * required to uncompress it again.
1553         */
1554        if (gd->multi_dtb_fit) {
1555                fdt_blob = locate_dtb_in_fit(gd->multi_dtb_fit);
1556
1557                if (fdt_blob == gd->fdt_blob) {
1558                        /*
1559                         * The best match did not change. no need to tear down
1560                         * the DM and rescan the fdt.
1561                         */
1562                        *rescan = 0;
1563                        return 0;
1564                }
1565
1566                *rescan = 1;
1567                gd->fdt_blob = fdt_blob;
1568                return fdtdec_prepare_fdt();
1569        }
1570
1571        /*
1572         * If multi_dtb_fit is NULL, it means that blob appended to u-boot is
1573         * not a FIT image containings DTB, but a single DTB. There is no need
1574         * to teard down DM and rescan the DT in this case.
1575         */
1576        *rescan = 0;
1577        return 0;
1578}
1579#endif
1580
1581#ifdef CONFIG_NR_DRAM_BANKS
1582int fdtdec_decode_ram_size(const void *blob, const char *area, int board_id,
1583                           phys_addr_t *basep, phys_size_t *sizep, bd_t *bd)
1584{
1585        int addr_cells, size_cells;
1586        const u32 *cell, *end;
1587        u64 total_size, size, addr;
1588        int node, child;
1589        bool auto_size;
1590        int bank;
1591        int len;
1592
1593        debug("%s: board_id=%d\n", __func__, board_id);
1594        if (!area)
1595                area = "/memory";
1596        node = fdt_path_offset(blob, area);
1597        if (node < 0) {
1598                debug("No %s node found\n", area);
1599                return -ENOENT;
1600        }
1601
1602        cell = fdt_getprop(blob, node, "reg", &len);
1603        if (!cell) {
1604                debug("No reg property found\n");
1605                return -ENOENT;
1606        }
1607
1608        addr_cells = fdt_address_cells(blob, node);
1609        size_cells = fdt_size_cells(blob, node);
1610
1611        /* Check the board id and mask */
1612        for (child = fdt_first_subnode(blob, node);
1613             child >= 0;
1614             child = fdt_next_subnode(blob, child)) {
1615                int match_mask, match_value;
1616
1617                match_mask = fdtdec_get_int(blob, child, "match-mask", -1);
1618                match_value = fdtdec_get_int(blob, child, "match-value", -1);
1619
1620                if (match_value >= 0 &&
1621                    ((board_id & match_mask) == match_value)) {
1622                        /* Found matching mask */
1623                        debug("Found matching mask %d\n", match_mask);
1624                        node = child;
1625                        cell = fdt_getprop(blob, node, "reg", &len);
1626                        if (!cell) {
1627                                debug("No memory-banks property found\n");
1628                                return -EINVAL;
1629                        }
1630                        break;
1631                }
1632        }
1633        /* Note: if no matching subnode was found we use the parent node */
1634
1635        if (bd) {
1636                memset(bd->bi_dram, '\0', sizeof(bd->bi_dram[0]) *
1637                                                CONFIG_NR_DRAM_BANKS);
1638        }
1639
1640        auto_size = fdtdec_get_bool(blob, node, "auto-size");
1641
1642        total_size = 0;
1643        end = cell + len / 4 - addr_cells - size_cells;
1644        debug("cell at %p, end %p\n", cell, end);
1645        for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
1646                if (cell > end)
1647                        break;
1648                addr = 0;
1649                if (addr_cells == 2)
1650                        addr += (u64)fdt32_to_cpu(*cell++) << 32UL;
1651                addr += fdt32_to_cpu(*cell++);
1652                if (bd)
1653                        bd->bi_dram[bank].start = addr;
1654                if (basep && !bank)
1655                        *basep = (phys_addr_t)addr;
1656
1657                size = 0;
1658                if (size_cells == 2)
1659                        size += (u64)fdt32_to_cpu(*cell++) << 32UL;
1660                size += fdt32_to_cpu(*cell++);
1661
1662                if (auto_size) {
1663                        u64 new_size;
1664
1665                        debug("Auto-sizing %llx, size %llx: ", addr, size);
1666                        new_size = get_ram_size((long *)(uintptr_t)addr, size);
1667                        if (new_size == size) {
1668                                debug("OK\n");
1669                        } else {
1670                                debug("sized to %llx\n", new_size);
1671                                size = new_size;
1672                        }
1673                }
1674
1675                if (bd)
1676                        bd->bi_dram[bank].size = size;
1677                total_size += size;
1678        }
1679
1680        debug("Memory size %llu\n", total_size);
1681        if (sizep)
1682                *sizep = (phys_size_t)total_size;
1683
1684        return 0;
1685}
1686#endif /* CONFIG_NR_DRAM_BANKS */
1687
1688#endif /* !USE_HOSTCC */
1689