
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 ---
common/bloblist.c | 1 + common/board_f.c | 16 ++++++++++++---- dts/Kconfig | 12 ++++++++++++ include/asm-generic/global_data.h | 4 ++++ include/bloblist.h | 1 + lib/fdtdec.c | 30 ++++++++++++++++++++++++++++++ 6 files changed, 60 insertions(+), 4 deletions(-)
diff --git a/common/bloblist.c b/common/bloblist.c index d36e0a94dff..310ca87dbc4 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 86c77a42847..3684c21a0f7 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) { @@ -819,6 +824,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 @@ -828,7 +836,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, @@ -938,9 +946,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 5dcc79d5192..7e4d9852a44 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 diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index ef4119f27f4..717fe2edb46 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -627,6 +627,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 2ede0ce3150..607e42129d4 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/lib/fdtdec.c b/lib/fdtdec.c index 31a509bc221..4ca56e06b2f 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> @@ -1631,6 +1634,33 @@ int fdtdec_setup(void) else /* embed dtb in ELF file for testing / development */ gd->fdt_blob = dtb_dt_embedded();
+ /* Passed in via the standard passage */ + if (IS_ENABLED(CONFIG_OF_PASSAGE) && gd->passage_dtb_off) { + void *fdt = NULL; + + /* Use the bloblist if available */ + if (CONFIG_IS_ENABLED(BLOBLIST)) { + fdt = bloblist_find(BLOBLISTT_CONTROL_DTB, 0); + + if (fdt) + 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 = bloblist + gd->passage_dtb_off; + log_debug("passage: Found dtb offset %lx\n", + gd->passage_dtb_off); + } + } + if (fdt) { + gd->fdt_blob = fdt; + 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);