]> git.ipfire.org Git - thirdparty/u-boot.git/blobdiff - lib/fdtdec.c
Merge tag 'u-boot-dfu-20240516' of https://source.denx.de/u-boot/custodians/u-boot-dfu
[thirdparty/u-boot.git] / lib / fdtdec.c
index 96b6b71a606fe117ab98882c2d6d86069b44135d..b2c59ab3818b3235e36b61b054c76a803423de63 100644 (file)
@@ -1,10 +1,16 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
  * Copyright (c) 2011 The Chromium OS Authors.
+ *
+ * NOTE: Please do not add new devicetree-reading functionality into this file.
+ * Add it to the ofnode API instead, since that is compatible with livetree.
  */
 
 #ifndef USE_HOSTCC
-#include <common.h>
+
+#define LOG_CATEGORY   LOGC_DT
+
+#include <bloblist.h>
 #include <boot_fit.h>
 #include <display_options.h>
 #include <dm.h>
@@ -13,7 +19,7 @@
 #include <log.h>
 #include <malloc.h>
 #include <net.h>
-#include <dm/of_extra.h>
+#include <spl.h>
 #include <env.h>
 #include <errno.h>
 #include <fdtdec.h>
@@ -24,6 +30,8 @@
 #include <serial.h>
 #include <asm/global_data.h>
 #include <asm/sections.h>
+#include <dm/ofnode.h>
+#include <dm/of_extra.h>
 #include <linux/ctype.h>
 #include <linux/lzo.h>
 #include <linux/ioport.h>
@@ -63,7 +71,6 @@ static const char * const compat_names[COMPAT_COUNT] = {
        COMPAT(INTEL_BAYTRAIL_FSP, "intel,baytrail-fsp"),
        COMPAT(INTEL_BAYTRAIL_FSP_MDP, "intel,baytrail-fsp-mdp"),
        COMPAT(INTEL_IVYBRIDGE_FSP, "intel,ivybridge-fsp"),
-       COMPAT(COMPAT_SUNXI_NAND, "allwinner,sun4i-a10-nand"),
        COMPAT(ALTERA_SOCFPGA_CLK, "altr,clk-mgr"),
        COMPAT(ALTERA_SOCFPGA_PINCTRL_SINGLE, "pinctrl-single"),
        COMPAT(ALTERA_SOCFPGA_H2F_BRG, "altr,socfpga-hps2fpga-bridge"),
@@ -83,6 +90,7 @@ static const char *const fdt_src_name[] = {
        [FDTSRC_BOARD] = "board",
        [FDTSRC_EMBED] = "embed",
        [FDTSRC_ENV] = "env",
+       [FDTSRC_BLOBLIST] = "bloblist",
 };
 
 const char *fdtdec_get_srcname(void)
@@ -517,8 +525,11 @@ int fdtdec_get_alias_seq(const void *blob, const char *base, int offset,
                 * Adding an extra check to distinguish DT nodes with
                 * same name
                 */
-               if (offset != fdt_path_offset(blob, prop))
-                       continue;
+               if (IS_ENABLED(CONFIG_PHANDLE_CHECK_SEQ)) {
+                       if (fdt_get_phandle(blob, offset) !=
+                           fdt_get_phandle(blob, fdt_path_offset(blob, prop)))
+                               continue;
+               }
 
                val = trailing_strtol(name);
                if (val != -1) {
@@ -585,6 +596,34 @@ int fdtdec_get_chosen_node(const void *blob, const char *name)
        return fdt_path_offset(blob, prop);
 }
 
+/**
+ * fdtdec_prepare_fdt() - Check we have a valid fdt available to control U-Boot
+ *
+ * @blob: Blob to check
+ *
+ * If not, a message is printed to the console if the console is ready.
+ *
+ * Return: 0 if all ok, -ENOENT if not
+ */
+static int fdtdec_prepare_fdt(const void *blob)
+{
+       if (!blob || ((uintptr_t)blob & 3) || fdt_check_header(blob)) {
+               if (spl_phase() <= PHASE_SPL) {
+                       puts("Missing DTB\n");
+               } else {
+                       printf("No valid device tree binary found at %p\n",
+                              blob);
+                       if (_DEBUG && blob) {
+                               printf("fdt_blob=%p\n", blob);
+                               print_buffer((ulong)blob, blob, 4, 32, 0);
+                       }
+               }
+               return -ENOENT;
+       }
+
+       return 0;
+}
+
 int fdtdec_check_fdt(void)
 {
        /*
@@ -593,34 +632,7 @@ int fdtdec_check_fdt(void)
         * FDT (prior to console ready) will need to make their own
         * arrangements and do their own checks.
         */
-       assert(!fdtdec_prepare_fdt());
-       return 0;
-}
-
-/*
- * This function is a little odd in that it accesses global data. At some
- * point if the architecture board.c files merge this will make more sense.
- * Even now, it is common code.
- */
-int fdtdec_prepare_fdt(void)
-{
-       if (!gd->fdt_blob || ((uintptr_t)gd->fdt_blob & 3) ||
-           fdt_check_header(gd->fdt_blob)) {
-#ifdef CONFIG_SPL_BUILD
-               puts("Missing DTB\n");
-#else
-               printf("No valid device tree binary found at %p\n",
-                      gd->fdt_blob);
-# ifdef DEBUG
-               if (gd->fdt_blob) {
-                       printf("fdt_blob=%p\n", gd->fdt_blob);
-                       print_buffer((ulong)gd->fdt_blob, gd->fdt_blob, 4,
-                                    32, 0);
-               }
-# endif
-#endif
-               return -1;
-       }
+       assert(!fdtdec_prepare_fdt(gd->fdt_blob));
        return 0;
 }
 
@@ -1058,7 +1070,7 @@ ofnode get_next_memory_node(ofnode mem)
 {
        do {
                mem = ofnode_by_prop_value(mem, "device_type", "memory", 7);
-       } while (!ofnode_is_available(mem));
+       } while (!ofnode_is_enabled(mem));
 
        return mem;
 }
@@ -1222,12 +1234,35 @@ static void *fdt_find_separate(void)
 #ifdef CONFIG_SPL_BUILD
        /* FDT is at end of BSS unless it is in a different memory region */
        if (IS_ENABLED(CONFIG_SPL_SEPARATE_BSS))
-               fdt_blob = (ulong *)&_image_binary_end;
+               fdt_blob = (ulong *)_image_binary_end;
        else
-               fdt_blob = (ulong *)&__bss_end;
+               fdt_blob = (ulong *)__bss_end;
 #else
        /* FDT is at end of image */
-       fdt_blob = (ulong *)&_end;
+       fdt_blob = (ulong *)_end;
+
+       if (_DEBUG && !fdtdec_prepare_fdt(fdt_blob)) {
+               int stack_ptr;
+               const void *top = fdt_blob + fdt_totalsize(fdt_blob);
+
+               /*
+                * Perform a sanity check on the memory layout. If this fails,
+                * it indicates that the device tree is positioned above the
+                * global data pointer or the stack pointer. This should not
+                * happen.
+                *
+                * If this fails, check that SYS_INIT_SP_ADDR has enough space
+                * below it for SYS_MALLOC_F_LEN and global_data, as well as the
+                * stack, without overwriting the device tree or U-Boot itself.
+                * Since the device tree is sitting at _end (the start of the
+                * BSS region), we need the top of the device tree to be below
+                * any memory allocated by board_init_f_alloc_reserve().
+                */
+               if (top > (void *)gd || top > (void *)&stack_ptr) {
+                       printf("FDT %p gd %p\n", fdt_blob, gd);
+                       panic("FDT overlap");
+               }
+       }
 #endif
 
        return fdt_blob;
@@ -1632,23 +1667,42 @@ static void setup_multi_dtb_fit(void)
 
 int fdtdec_setup(void)
 {
-       int ret;
+       int ret = -ENOENT;
+
+       /* If allowing a bloblist, check that first */
+       if (CONFIG_IS_ENABLED(BLOBLIST)) {
+               ret = bloblist_maybe_init();
+               if (!ret) {
+                       gd->fdt_blob = bloblist_find(BLOBLISTT_CONTROL_FDT, 0);
+                       if (gd->fdt_blob) {
+                               gd->fdt_src = FDTSRC_BLOBLIST;
+                               log_debug("Devicetree is in bloblist at %p\n",
+                                         gd->fdt_blob);
+                       } else {
+                               log_debug("No FDT found in bloblist\n");
+                               ret = -ENOENT;
+                       }
+               }
+       }
 
-       /* The devicetree is typically appended to U-Boot */
-       if (IS_ENABLED(CONFIG_OF_SEPARATE)) {
-               gd->fdt_blob = fdt_find_separate();
-               gd->fdt_src = FDTSRC_SEPARATE;
-       } else { /* embed dtb in ELF file for testing / development */
-               gd->fdt_blob = dtb_dt_embedded();
-               gd->fdt_src = FDTSRC_EMBED;
+       /* Otherwise, the devicetree is typically appended to U-Boot */
+       if (ret) {
+               if (IS_ENABLED(CONFIG_OF_SEPARATE)) {
+                       gd->fdt_blob = fdt_find_separate();
+                       gd->fdt_src = FDTSRC_SEPARATE;
+               } else { /* embed dtb in ELF file for testing / development */
+                       gd->fdt_blob = dtb_dt_embedded();
+                       gd->fdt_src = FDTSRC_EMBED;
+               }
        }
 
        /* Allow the board to override the fdt address. */
        if (IS_ENABLED(CONFIG_OF_BOARD)) {
                gd->fdt_blob = board_fdt_blob_setup(&ret);
-               if (ret)
+               if (!ret)
+                       gd->fdt_src = FDTSRC_BOARD;
+               else if (ret != -EEXIST)
                        return ret;
-               gd->fdt_src = FDTSRC_BOARD;
        }
 
        /* Allow the early environment to override the fdt address */
@@ -1665,9 +1719,11 @@ int fdtdec_setup(void)
        if (CONFIG_IS_ENABLED(MULTI_DTB_FIT))
                setup_multi_dtb_fit();
 
-       ret = fdtdec_prepare_fdt();
+       ret = fdtdec_prepare_fdt(gd->fdt_blob);
        if (!ret)
                ret = fdtdec_board_setup(gd->fdt_blob);
+       oftree_reset();
+
        return ret;
 }
 
@@ -1695,7 +1751,7 @@ int fdtdec_resetup(int *rescan)
 
                *rescan = 1;
                gd->fdt_blob = fdt_blob;
-               return fdtdec_prepare_fdt();
+               return fdtdec_prepare_fdt(fdt_blob);
        }
 
        /*