
Add support for accepting a control devicetree from the incoming passage. This allows SPL (or some other program) to pass a devicetree to U-Boot proper in a standard way.
Pass the devicetree through the early parts of U-Boot needs a list care. If it is in the bloblist, there is no need to reserve a separate space for it to relocate into, since it will be relocated as part of the bloblist.
Also we must init the bloblist before calling fdtdec_setup(), so the devicetree can be read from the bloblist*. This is not normally safe, since malloc() is be called by bloblist_init() if CONFIG_BLOBLIST_ALLOC is enabled. But in the case of a devicetree in the incoming passage, we know we won't need to allocate the bloblist, since the previous phase has set it up for us.
Finally, move the reloc_fdt() call after the reloc_bloblist() since, as mentioned above, when the passage is used there is no need to relocate the devicetree.
There is one subtlety here. If bloblist support is not enabled in U-Boot, it can still receive a control devicetree, using the passage_dtb_off value added to passage_bloblist. This allows the devicetree passing to work even if the bloblist itself is ignored. In that case we do need to relocate the devicetree. Use a global_data flag for this case.
* Actually we could init the bloblist later, since we have the offset of the devicetree in a register, but that seems like an extreme measure, bypassing U-Boot's own bloblist implementation to get at the data.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Incorporate devicetree source - Rebase to master
common/bloblist.c | 1 + common/board_f.c | 16 +++++++++++---- dts/Kconfig | 12 +++++++++++ include/asm-generic/global_data.h | 4 ++++ include/bloblist.h | 1 + include/fdtdec.h | 4 ++++ lib/fdtdec.c | 33 +++++++++++++++++++++++++++++++ 7 files changed, 67 insertions(+), 4 deletions(-)
diff --git a/common/bloblist.c b/common/bloblist.c index df45d45de90..3a2fba212c9 100644 --- a/common/bloblist.c +++ b/common/bloblist.c @@ -39,6 +39,7 @@ static struct tag_name { { BLOBLISTT_NONE, "(none)" },
/* BLOBLISTT_AREA_FIRMWARE_TOP */ + { BLOBLISTT_CONTROL_DTB, "Control DTB" },
/* BLOBLISTT_AREA_FIRMWARE */ { BLOBLISTT_ACPI_GNVS, "ACPI GNVS" }, diff --git a/common/board_f.c b/common/board_f.c index 04d98366bd6..0794cc50a57 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -517,7 +517,7 @@ static int reserve_global_data(void)
static int reserve_fdt(void) { - if (!IS_ENABLED(CONFIG_OF_EMBED)) { + if (!IS_ENABLED(CONFIG_OF_EMBED) && !(gd->flags & GD_FLG_OF_PASSAGE)) { /* * If the device tree is sitting immediately above our image * then we must relocate it. If it is embedded in the data @@ -622,7 +622,12 @@ static int init_post(void)
static int reloc_fdt(void) { - if (!IS_ENABLED(CONFIG_OF_EMBED)) { + if (IS_ENABLED(CONFIG_OF_PASSAGE) && (gd->flags & GD_FLG_OF_PASSAGE)) { + void *blob = bloblist_find(BLOBLISTT_CONTROL_DTB, 0); + + log_info("passage: Control dtb relocated to %p\n", blob); + gd->fdt_blob = blob; + } else if (!IS_ENABLED(CONFIG_OF_EMBED)) { if (gd->flags & GD_FLG_SKIP_RELOC) return 0; if (gd->new_fdt) { @@ -821,6 +826,9 @@ __weak int clear_bss(void)
static const init_fnc_t init_sequence_f[] = { setup_mon_len, +#ifdef CONFIG_OF_PASSAGE + bloblist_init, +#endif #ifdef CONFIG_OF_CONTROL fdtdec_setup, #endif @@ -830,7 +838,7 @@ static const init_fnc_t init_sequence_f[] = { initf_malloc, log_init, initf_bootstage, /* uses its own timer, so does not need DM */ -#ifdef CONFIG_BLOBLIST +#if !defined(CONFIG_OF_PASSAGE) && defined(CONFIG_BLOBLIST) bloblist_init, #endif setup_spl_handoff, @@ -940,9 +948,9 @@ static const init_fnc_t init_sequence_f[] = { setup_bdinfo, display_new_sp, INIT_FUNC_WATCHDOG_RESET - reloc_fdt, reloc_bootstage, reloc_bloblist, + reloc_fdt, setup_reloc, #if defined(CONFIG_X86) || defined(CONFIG_ARC) copy_uboot_to_ram, diff --git a/dts/Kconfig b/dts/Kconfig index fb7df533f92..65d129453c6 100644 --- a/dts/Kconfig +++ b/dts/Kconfig @@ -96,6 +96,18 @@ config OF_EMBED
endchoice
+config OF_PASSAGE + bool "Devicetree provided by the standard passage protocol" + help + If this option is enabled, the device tree may be provided by the + standard passage, meaning that a previous phase/stage passes a + bloblist containing this. This is the standard way to pass a + devicetree between firmware components at runtime. The device tree + bundled with the image (if any) will be overridden / ignored. + + Note: If BLOBLIST is not enabled, this does not decode the + bloblist, but just picks up the devicetree by itself. + config OF_BOARD bool "Provided by the board (e.g a previous loader) at runtime" default y if SANDBOX || OF_HAS_PRIOR_STAGE diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index 3fe1534ed9d..34b4139e498 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -638,6 +638,10 @@ enum gd_flags { * @GD_FLG_SMP_READY: SMP initialization is complete */ GD_FLG_SMP_READY = 0x80000, + /** + * @GD_FLG_OF_PASSAGE: Using devicetree from standard passage protocol + */ + GD_FLG_OF_PASSAGE = 0x80000, };
#endif /* __ASSEMBLY__ */ diff --git a/include/bloblist.h b/include/bloblist.h index d0e128acf10..c0045572275 100644 --- a/include/bloblist.h +++ b/include/bloblist.h @@ -31,6 +31,7 @@ enum bloblist_tag_t { * projects. */ BLOBLISTT_AREA_FIRMWARE_TOP = 0x1, + BLOBLISTT_CONTROL_DTB = 1, /* Devicetree used for control */
/* Standard area to allocate blobs used across firmware components */ BLOBLISTT_AREA_FIRMWARE = 0x100, diff --git a/include/fdtdec.h b/include/fdtdec.h index 15f2d2bbbaa..b4e452326b3 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -56,6 +56,9 @@ struct bd_info; * * @FDTSRC_SEPARATE: Appended to U-Boot. This is the normal approach if U-Boot * is the only firmware being booted + * @FDTSRC_PASSAGE: From the standard passage (passed in from previous + * phase/stage). This is the normal approach if prior-stage firmware is + * used, such as TF-A * @FDTSRC_FIT: Found in a multi-dtb FIT. This should be used when U-Boot must * select a devicetree from many options * @FDTSRC_BOARD: Located by custom board code. This should only be used when @@ -68,6 +71,7 @@ struct bd_info; */ enum fdt_source_t { FDTSRC_SEPARATE, + FDTSRC_PASSAGE, FDTSRC_FIT, FDTSRC_BOARD, FDTSRC_EMBED, diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 280cda61a72..86613208b14 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -3,8 +3,11 @@ * Copyright (c) 2011 The Chromium OS Authors. */
+#define LOG_CATEGORY LOGC_DT + #ifndef USE_HOSTCC #include <common.h> +#include <bloblist.h> #include <boot_fit.h> #include <dm.h> #include <hang.h> @@ -78,6 +81,7 @@ static const char * const compat_names[COMPAT_COUNT] = {
static const char *const fdt_src_name[] = { [FDTSRC_SEPARATE] = "separate", + [FDTSRC_PASSAGE] = "passage", [FDTSRC_FIT] = "fit", [FDTSRC_BOARD] = "board", [FDTSRC_EMBED] = "embed", @@ -1649,6 +1653,35 @@ int fdtdec_setup(void) gd->fdt_src = FDTSRC_EMBED; }
+ /* Passed in via the standard passage */ + if (IS_ENABLED(CONFIG_OF_PASSAGE) && gd->passage_dtb) { + void *passage_dtb = map_sysmem(gd->passage_dtb, 0); + void *fdt = NULL; + + /* Use the bloblist if available */ + if (CONFIG_IS_ENABLED(BLOBLIST)) { + fdt = bloblist_find(BLOBLISTT_CONTROL_DTB, 0); + + if (fdt == passage_dtb) + gd->flags |= GD_FLG_OF_PASSAGE; + } else { + void *bloblist; + + /* Cursory check for a valid bloblist; use the offset */ + bloblist = bloblist_check_magic(gd->passage_bloblist); + if (bloblist) { + fdt = passage_dtb; + log_debug("passage: Found dtb addr %lx\n", + gd->passage_dtb); + } + } + if (fdt) { + gd->fdt_blob = fdt; + gd->fdt_src = FDTSRC_PASSAGE; + log_debug("passage: Found control dtb at %p\n", fdt); + } + } + /* Allow the board to override the fdt address. */ if (IS_ENABLED(CONFIG_OF_BOARD)) { gd->fdt_blob = board_fdt_blob_setup(&ret);