diff mbox series

[v2,05/16] passage: Support a control devicetree

Message ID 20220117150428.1580273-4-sjg@chromium.org
State Deferred
Delegated to: Tom Rini
Headers show
Series passage: Define a standard for firmware data flow | expand

Commit Message

Simon Glass Jan. 17, 2022, 3:04 p.m. UTC
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 mbox series

Patch

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);