diff mbox series

[RFC,04/14] efi: stub: add helpers to populate memory map and framebuffer

Message ID 20241124-b4-efistub-arm64-v1-4-3e33f0340071@linaro.org
State New
Headers show
Series efi: implement EFISTUB support for ARM64 and Qualcomm | expand

Commit Message

Caleb Connolly Nov. 24, 2024, 8:27 p.m. UTC
Introduce two new helpers dram_init_banksize_from_efi() and
of_populate_from_efi(). These populate the DRAM bank info and simplefb
framebuffer OF node respectively using the EFI table populated by the
EFI stub.

dram_init_banksize_from_efi() is directly moved from the x86 payload
code to make it available for other boards.

Populating the simplefb node allows for an easy way to bring up video
without the full heft of VIDEO_EFI which is not particularly well-suited
to ARM.

Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
 arch/x86/cpu/efi/payload.c |  31 +------------
 include/efi_stub.h         |  22 ++++++++++
 lib/efi/efi_info.c         | 107 +++++++++++++++++++++++++++++++++++++++++++++
 lib/of_live.c              |   9 ++++
 4 files changed, 139 insertions(+), 30 deletions(-)
diff mbox series

Patch

diff --git a/arch/x86/cpu/efi/payload.c b/arch/x86/cpu/efi/payload.c
index 68cda25aca63..b71917615d13 100644
--- a/arch/x86/cpu/efi/payload.c
+++ b/arch/x86/cpu/efi/payload.c
@@ -100,38 +100,9 @@  int dram_init(void)
 }
 
 int dram_init_banksize(void)
 {
-	struct efi_mem_desc *desc, *end;
-	struct efi_entry_memmap *map;
-	int ret, size;
-	int num_banks;
-
-	ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size);
-	if (ret) {
-		/* We should have stopped in dram_init(), something is wrong */
-		debug("%s: Missing memory map\n", __func__);
-		return -ENXIO;
-	}
-	end = (struct efi_mem_desc *)((ulong)map + size);
-	desc = map->desc;
-	for (num_banks = 0;
-	     desc < end && num_banks < CONFIG_NR_DRAM_BANKS;
-	     desc = efi_get_next_mem_desc(desc, map->desc_size)) {
-		/*
-		 * We only use conventional memory and ignore
-		 * anything less than 1MB.
-		 */
-		if (desc->type != EFI_CONVENTIONAL_MEMORY ||
-		    (desc->num_pages << EFI_PAGE_SHIFT) < 1 << 20)
-			continue;
-		gd->bd->bi_dram[num_banks].start = desc->physical_start;
-		gd->bd->bi_dram[num_banks].size = desc->num_pages <<
-			EFI_PAGE_SHIFT;
-		num_banks++;
-	}
-
-	return 0;
+	return dram_init_banksize_from_efi();
 }
 
 int arch_cpu_init(void)
 {
diff --git a/include/efi_stub.h b/include/efi_stub.h
index 4780badd3ac4..ff3befd4830b 100644
--- a/include/efi_stub.h
+++ b/include/efi_stub.h
@@ -34,5 +34,27 @@  enum efi_entry_t {
  * of the requested type, -EPROTONOSUPPORT if the table has the wrong version
  */
 int efi_info_get(enum efi_entry_t type, void **datap, int *sizep);
 
+struct device_node;
+
+/**
+ * of_populate_from_efi() - Populate the live tree from EFI tables
+ *
+ * @root: Root node of tree to populate
+ *
+ * This function populates the live tree with information from EFI tables
+ * it is only applicable when running U-Boot as an EFI payload with
+ * CONFIG_EFI_STUB enabled.
+ */
+int of_populate_from_efi(struct device_node *root);
+
+/**
+ * dram_init_banksize_from_efi() - Initialize the memory banks from EFI tables
+ *
+ * This function initializes the memory banks from the EFI memory map table we
+ * stashed from the EFI stub. It is only applicable when running U-Boot as an
+ * EFI payload with CONFIG_EFI_STUB enabled.
+ */
+int dram_init_banksize_from_efi(void);
+
 #endif /* _EFI_STUB_H */
diff --git a/lib/efi/efi_info.c b/lib/efi/efi_info.c
index 32ba7e499c57..3fa594b34b42 100644
--- a/lib/efi/efi_info.c
+++ b/lib/efi/efi_info.c
@@ -9,8 +9,13 @@ 
 #include <efi_stub.h>
 #include <errno.h>
 #include <mapmem.h>
 #include <asm/global_data.h>
+#include <efi_api.h>
+#include <dm/of.h>
+#include <dm/ofnode.h>
+#include <dm/of_access.h>
+#include <log.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
 int efi_info_get(enum efi_entry_t type, void **datap, int *sizep)
@@ -46,4 +51,106 @@  err:
 	unmap_sysmem(info);
 
 	return -ENOSYS;
 }
+
+#ifdef CONFIG_OF_LIVE
+static int of_populate_framebuffer(struct device_node *root)
+{
+	struct device_node *chosen, *fb;
+	struct efi_entry_gopmode *mode;
+	ofnode node;
+	int ret, size;
+	u64 reg[2];
+	char fb_node_name[50] = { 0 };
+
+	ret = efi_info_get(EFIET_GOP_MODE, (void **)&mode, &size);
+	if (ret) {
+		printf("EFI graphics output entry not found\n");
+		return ret;
+	}
+
+	fb = of_find_node_opts_by_path(root, "/chosen/framebuffer", NULL);
+	/* framebuffer already defined */
+	if (fb)
+		return 0;
+
+	chosen = of_find_node_opts_by_path(root, "/chosen", NULL);
+	if (!chosen) {
+		ret = of_add_subnode(root, "chosen", -1, &chosen);
+		if (ret) {
+			debug("Failed to add chosen node\n");
+			return ret;
+		}
+	}
+	node = np_to_ofnode(chosen);
+	ofnode_write_u32(node, "#address-cells", 2);
+	ofnode_write_u32(node, "#size-cells", 2);
+	/*
+	 * In order for of_translate_one() to correctly detect an empty ranges property, the value
+	 * pointer has to be non-null even though the length is 0.
+	 */
+	of_write_prop(chosen, "ranges", 0, (void *)FDT_ADDR_T_NONE);
+
+	snprintf(fb_node_name, sizeof(fb_node_name), "framebuffer@%llx", mode->fb_base);
+	ret = of_add_subnode(chosen, fb_node_name, -1, &fb);
+	if (ret) {
+		debug("Failed to add framebuffer node\n");
+		return ret;
+	}
+	node = np_to_ofnode(fb);
+	ofnode_write_string(node, "compatible", "simple-framebuffer");
+	reg[0] = cpu_to_fdt64(mode->fb_base);
+	reg[1] = cpu_to_fdt64(mode->fb_size);
+	ofnode_write_prop(node, "reg", reg, sizeof(reg), true);
+	ofnode_write_u32(node, "width", mode->info->width);
+	ofnode_write_u32(node, "height", mode->info->height);
+	ofnode_write_u32(node, "stride", mode->info->pixels_per_scanline * 4);
+	ofnode_write_string(node, "format", "a8r8g8b8");
+
+	return 0;
+}
+#endif
+
+int of_populate_from_efi(struct device_node *root)
+{
+	int ret = 0;
+
+	if (CONFIG_IS_ENABLED(VIDEO_SIMPLE) && CONFIG_IS_ENABLED(OF_LIVE))
+		ret = of_populate_framebuffer(root);
+
+	return ret;
+}
+
+int dram_init_banksize_from_efi(void)
+{
+	struct efi_mem_desc *desc, *end;
+	struct efi_entry_memmap *map;
+	int ret, size;
+	int num_banks;
+
+	ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size);
+	if (ret) {
+		/* We should have stopped in dram_init(), something is wrong */
+		debug("%s: Missing memory map\n", __func__);
+		return -ENXIO;
+	}
+	end = (struct efi_mem_desc *)((ulong)map + size);
+	desc = map->desc;
+	for (num_banks = 0;
+	     desc < end && num_banks < CONFIG_NR_DRAM_BANKS;
+	     desc = efi_get_next_mem_desc(desc, map->desc_size)) {
+		/*
+		 * We only use conventional memory and ignore
+		 * anything less than 1MB.
+		 */
+		if (desc->type != EFI_CONVENTIONAL_MEMORY ||
+		    (desc->num_pages << EFI_PAGE_SHIFT) < 1 << 20)
+			continue;
+		gd->bd->bi_dram[num_banks].start = desc->physical_start;
+		gd->bd->bi_dram[num_banks].size = desc->num_pages <<
+			EFI_PAGE_SHIFT;
+		num_banks++;
+	}
+
+	return 0;
+}
diff --git a/lib/of_live.c b/lib/of_live.c
index 90b9459ede31..572ae09d377b 100644
--- a/lib/of_live.c
+++ b/lib/of_live.c
@@ -10,8 +10,9 @@ 
 
 #define LOG_CATEGORY	LOGC_DT
 
 #include <abuf.h>
+#include <efi_stub.h>
 #include <log.h>
 #include <linux/libfdt.h>
 #include <of_live.h>
 #include <malloc.h>
@@ -334,8 +335,16 @@  int of_live_build(const void *fdt_blob, struct device_node **rootp)
 		return ret;
 	}
 	debug("%s: stop\n", __func__);
 
+	/*
+	 * When booting with EFI_STUB we can automatically generate a framebuffer
+	 * node based on the EFI data.
+	 */
+	ret = of_populate_from_efi(*rootp);
+	if (ret)
+		debug("Failed to populate live tree nodes from EFI: err=%d\n", ret);
+
 	return ret;
 }
 
 void of_live_free(struct device_node *root)