summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/README.fdt-control18
-rw-r--r--include/asm-generic/global_data.h4
-rw-r--r--include/fdtdec.h21
-rw-r--r--lib/fdtdec.c43
4 files changed, 85 insertions, 1 deletions
diff --git a/doc/README.fdt-control b/doc/README.fdt-control
index d6ab7bf570..446401c9e9 100644
--- a/doc/README.fdt-control
+++ b/doc/README.fdt-control
@@ -184,6 +184,24 @@ The full device tree is available to U-Boot proper, but normally only a subset
'SPL Support' in doc/driver-model/README.txt for more details.
+Using several DTBs in the SPL (CONFIG_SPL_MULTI_DTB)
+----------------------------------------------------
+In some rare cases it is desirable to let SPL be able to select one DTB among
+many. This usually not very useful as the DTB for the SPL is small and usually
+fits several platforms. However the DTB sometimes include information that do
+work on several platforms (like IO tuning parameters).
+In this case it is possible to use CONFIG_SPL_MULTI_DTB. This option appends to
+the SPL a FIT image containing several DTBs listed in SPL_OF_LIST.
+board_fit_config_name_match() is called to select the right DTB.
+
+If board_fit_config_name_match() relies on DM (DM driver to access an EEPROM
+containing the board ID for example), it possible to start with a generic DTB
+and then switch over to the right DTB after the detection. For this purpose,
+the platform code must call fdtdec_resetup(). Based on the returned flag, the
+platform may have to re-initiliaze the DM subusystem using dm_uninit() and
+dm_init_and_scan().
+
+
Limitations
-----------
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index dffd6b2602..78dcf40bff 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -77,6 +77,10 @@ typedef struct global_data {
#ifdef CONFIG_OF_LIVE
struct device_node *of_root;
#endif
+
+#if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
+ const void *multi_dtb_fit; /* uncompressed multi-dtb FIT image */
+#endif
struct jt_funcs *jt; /* jump table */
char env_buf[32]; /* buffer for env_get() before reloc. */
#ifdef CONFIG_TRACE
diff --git a/include/fdtdec.h b/include/fdtdec.h
index b15da00fb2..f1bcbf837f 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -951,6 +951,27 @@ int fdtdec_setup_memory_banksize(void);
*/
int fdtdec_setup(void);
+#if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
+/**
+ * fdtdec_resetup() - Set up the device tree again
+ *
+ * The main difference with fdtdec_setup() is that it returns if the fdt has
+ * changed because a better match has been found.
+ * This is typically used for boards that rely on a DM driver to detect the
+ * board type. This function sould be called by the board code after the stuff
+ * needed by board_fit_config_name_match() to operate porperly is available.
+ * If this functions signals that a rescan is necessary, the board code must
+ * unbind all the drivers using dm_uninit() and then rescan the DT with
+ * dm_init_and_scan().
+ *
+ * @param rescan Returns a flag indicating that fdt has changed and rescanning
+ * the fdt is required
+ *
+ * @return 0 if OK, -ve on error
+ */
+int fdtdec_resetup(int *rescan);
+#endif
+
/**
* Board-specific FDT initialization. Returns the address to a device tree blob.
* Called when CONFIG_OF_BOARD is defined, or if CONFIG_OF_SEPARATE is defined
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index cbdc077825..7bbc6d445e 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -1275,14 +1275,55 @@ int fdtdec_setup(void)
* If so, pick the most relevant
*/
fdt_blob = locate_dtb_in_fit(gd->fdt_blob);
- if (fdt_blob)
+ if (fdt_blob) {
+ gd->multi_dtb_fit = gd->fdt_blob;
gd->fdt_blob = fdt_blob;
+ }
+
# endif
#endif
return fdtdec_prepare_fdt();
}
+#if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
+int fdtdec_resetup(int *rescan)
+{
+ void *fdt_blob;
+
+ /*
+ * If the current DTB is part of a compressed FIT image,
+ * try to locate the best match from the uncompressed
+ * FIT image stillpresent there. Save the time and space
+ * required to uncompress it again.
+ */
+ if (gd->multi_dtb_fit) {
+ fdt_blob = locate_dtb_in_fit(gd->multi_dtb_fit);
+
+ if (fdt_blob == gd->fdt_blob) {
+ /*
+ * The best match did not change. no need to tear down
+ * the DM and rescan the fdt.
+ */
+ *rescan = 0;
+ return 0;
+ }
+
+ *rescan = 1;
+ gd->fdt_blob = fdt_blob;
+ return fdtdec_prepare_fdt();
+ }
+
+ /*
+ * If multi_dtb_fit is NULL, it means that blob appended to u-boot is
+ * not a FIT image containings DTB, but a single DTB. There is no need
+ * to teard down DM and rescan the DT in this case.
+ */
+ *rescan = 0;
+ return 0;
+}
+#endif
+
#ifdef CONFIG_NR_DRAM_BANKS
int fdtdec_decode_ram_size(const void *blob, const char *area, int board_id,
phys_addr_t *basep, phys_size_t *sizep, bd_t *bd)