[PATCH RFC 00/14] efi: implement EFISTUB support for ARM64 and Qualcomm

This series implements support for launching U-Boot as an EFI payload on ARM64 devices that already have an EFI capable bootloader.
Patches 9 through 14 in tandem with another series [1] provide all the pieces necessary to build and run U-Boot on Snapdragon X Elite laptops. They're only here to demonstrate the usecase and either already have or will be sent separately, they should not be reviewed as part of this RFC.
Initial support is provided for: * Building U-Boot with an EFI stub on ARM64 * Inheriting DRAM banks from the EFI memory map * Creating a framebuffer node in the OF tree based on EFI GOP info
This allows for booting Linux on top of U-Boot's EFI implementation on Qualcomm Snapdragon X Elite platforms.
The primary motivation for this is to provide a more standard EFI interface on devices like Qualcomm powered Windows laptops. While these devices ship an EFI capable bootloader, it has no understanding of devicetree, requiring distros (or more often, users) to handle devicetree selection and applying necessary fixups.
Additionally, the EFI implementation on these devices is often very far from being systemready compliant, with a variety of bugs like broken keyboards, crashes in OS loaders like systemd-boot, and other small idiosyncrocies.
As a result, simply running U-Boot as an EFI app isn't a suitable solution.
[1]: 20241124-b4-modernise-smem-v1-0-b7852c11b67c@linaro.org
--- Caleb Connolly (10): cmd: efi: avoid unitialized read efi: stub: support running U-Boot as an EFI payload on ARM64 efi: move efi_info_get() to a new header file efi: stub: add helpers to populate memory map and framebuffer efi: stub: add additional types of memory efi: stub: log EFI memory banks efi: stub: add known memory to U-Boot's EFI memory map mach-snapdragon: support booting with EFISTUB common/board_f: init malloc earlier configs: add x1e_defconfig
Neil Armstrong (4): clk: qcom: Add X1E80100 clock driver qcom_defconfig: enable X1E80100 clock driver pinctrl: qcom: Add X1E80100 pinctrl driver qcom_defconfig: enable X1E80100 pinctrl driver
Makefile | 15 +- arch/arm/cpu/armv8/config.mk | 11 + arch/arm/include/asm/global_data.h | 3 + arch/arm/lib/Makefile | 2 + arch/arm/mach-snapdragon/board.c | 15 ++ arch/arm/mach-snapdragon/dram.c | 15 +- arch/arm/mach-snapdragon/qcom-priv.h | 2 + arch/x86/cpu/efi/payload.c | 32 +-- board/qualcomm/efistub.env | 11 + cmd/efi.c | 3 +- common/board_f.c | 2 +- configs/qcom_defconfig | 2 + configs/x1e_defconfig | 17 ++ drivers/clk/qcom/Kconfig | 8 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/clock-x1e80100.c | 348 ++++++++++++++++++++++++++++++++ drivers/pinctrl/qcom/Kconfig | 7 + drivers/pinctrl/qcom/Makefile | 1 + drivers/pinctrl/qcom/pinctrl-x1e80100.c | 100 +++++++++ drivers/video/efi.c | 1 + include/efi.h | 27 +-- include/efi_stub.h | 67 ++++++ lib/efi/Kconfig | 9 +- lib/efi/Makefile | 28 ++- lib/efi/efi_app.c | 1 + lib/efi/efi_info.c | 165 +++++++++++++++ lib/efi/efi_stub_arm64.c | 237 ++++++++++++++++++++++ lib/efi/{efi_stub.c => efi_stub_x86.c} | 1 + lib/efi_loader/efi_memory.c | 5 + lib/of_live.c | 9 + 30 files changed, 1072 insertions(+), 73 deletions(-) --- base-commit: 1e327ec30e48902fff65fb58337b8f80cc526f08
// Caleb (they/them)

The key variable might be unitialised when accessed for the printf(). Zero initialise it to avoid this.
Signed-off-by: Caleb Connolly caleb.connolly@linaro.org --- cmd/efi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cmd/efi.c b/cmd/efi.c index 687ccb520428..1fb67a83aae5 100644 --- a/cmd/efi.c +++ b/cmd/efi.c @@ -220,9 +220,9 @@ static void efi_print_mem_table(struct efi_mem_desc *desc, int desc_size, static int do_efi_mem(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { struct efi_mem_desc *orig, *desc; - uint version, key; + uint version, key = 0; int desc_size; int size, ret; bool skip_bs;

On Sun, 24 Nov 2024 at 22:27, Caleb Connolly caleb.connolly@linaro.org wrote:
The key variable might be unitialised when accessed for the printf(). Zero initialise it to avoid this.
Signed-off-by: Caleb Connolly caleb.connolly@linaro.org
cmd/efi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cmd/efi.c b/cmd/efi.c index 687ccb520428..1fb67a83aae5 100644 --- a/cmd/efi.c +++ b/cmd/efi.c @@ -220,9 +220,9 @@ static void efi_print_mem_table(struct efi_mem_desc *desc, int desc_size, static int do_efi_mem(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { struct efi_mem_desc *orig, *desc;
uint version, key;
uint version, key = 0; int desc_size; int size, ret; bool skip_bs;
-- 2.47.0
Reviewed-by: Ilias Apalodimas ilias.apalodimas@linaro.org

Implement support for launching U-Boot via an EFI stub app on ARM64.
This is more or less a straight port of the x86 implementation, but due to the highly x86/qemu specific nature of that implementation I decided to just split it out to its own file.
Unlike the x86 implementation, there is no debug UART here since ARM platforms don't have a standard UART interface. However it is usually possible to port over the debug uart implementation for you platform for bringup purposes.
Currently this implementation doesn't provide a DTB to U-Boot and expects U-Boot to use a built-in one, however this ought to be a fairly trivial addition in the future.
The other significant difference to the x86 version is that rather than copying U-Boot to CONFIG_TEXT_OFFSET, we require that U-Boot is built position independent and copy it to EFI allocated memory.
Signed-off-by: Caleb Connolly caleb.connolly@linaro.org --- Makefile | 15 ++- arch/arm/cpu/armv8/config.mk | 11 ++ arch/arm/include/asm/global_data.h | 3 + arch/arm/lib/Makefile | 2 + include/efi.h | 2 +- lib/efi/Kconfig | 9 +- lib/efi/Makefile | 28 ++-- lib/efi/efi_info.c | 4 +- lib/efi/efi_stub_arm64.c | 236 +++++++++++++++++++++++++++++++++ lib/efi/{efi_stub.c => efi_stub_x86.c} | 0 10 files changed, 294 insertions(+), 16 deletions(-)
diff --git a/Makefile b/Makefile index da742ceae76e..8d0340622d7c 100644 --- a/Makefile +++ b/Makefile @@ -1681,21 +1681,32 @@ u-boot.bin.o: u-boot.bin FORCE
u-boot-payload.lds: $(LDSCRIPT_EFI) FORCE $(call if_changed_dep,cpp_lds)
+# Determine the file suffix for the efi stub implementation +EFI_STUB_ARCH := $(if $(CONFIG_ARM64),arm64,$(if $(CONFIG_X86_64),x86,$(ARCH))) + # Rule to link the EFI payload which contains a stub and a U-Boot binary quiet_cmd_u-boot_payload ?= LD $@ cmd_u-boot_payload ?= $(LD) $(LDFLAGS_EFI_PAYLOAD) -o $@ \ - -T u-boot-payload.lds arch/x86/cpu/call32.o \ - lib/efi/efi.o lib/efi/efi_stub.o u-boot.bin.o \ + -T u-boot-payload.lds $(if $(CONFIG_X86),arch/x86/cpu/call32.o,) \ + lib/efi/efi.o lib/efi/efi_stub_$(EFI_STUB_ARCH).o u-boot.bin.o \ $(addprefix arch/$(ARCH)/lib/,$(EFISTUB))
+quiet_cmd_u-boot_payload_arm64.efi ?= OBJCOPY $@ + cmd_u-boot_payload_arm64.efi ?= $(OBJCOPY) -O binary u-boot-payload $@ + u-boot-payload: u-boot.bin.o u-boot-payload.lds FORCE $(call if_changed,u-boot_payload)
OBJCOPYFLAGS_u-boot-payload.efi := $(OBJCOPYFLAGS_EFI) +ifeq ($(CONFIG_X86),y) u-boot-payload.efi: u-boot-payload FORCE $(call if_changed,zobjcopy) +else +u-boot-payload.efi: u-boot-payload FORCE + $(call if_changed,u-boot_payload_$(EFI_STUB_ARCH).efi) +endif
u-boot-img.bin: spl/u-boot-spl.bin u-boot.img FORCE $(call if_changed,cat)
diff --git a/arch/arm/cpu/armv8/config.mk b/arch/arm/cpu/armv8/config.mk index 4d74b2a533e0..1ee316801064 100644 --- a/arch/arm/cpu/armv8/config.mk +++ b/arch/arm/cpu/armv8/config.mk @@ -9,4 +9,15 @@ PLATFORM_CPPFLAGS += $(PF_NO_UNALIGNED)
EFI_LDS := elf_aarch64_efi.lds EFI_CRT0 := crt0_aarch64_efi.o EFI_RELOC := reloc_aarch64_efi.o + +LDSCRIPT_EFI := $(srctree)/arch/arm/lib/elf_aarch64_efi.lds +EFISTUB := crt0_aarch64_efi.o reloc_aarch64_efi.o +OBJCOPYFLAGS_EFI += --target=pei-aarch64-little +EFIPAYLOAD_BFDTARGET := pei-aarch64-little +EFIPAYLOAD_BFDARCH := aarch64 +LDFLAGS_EFI_PAYLOAD := -Bsymbolic -Bsymbolic-functions -shared --no-undefined \ + -s -zexecstack + +CPPFLAGS_REMOVE_crt0-efi-aarch64.o += $(CFLAGS_NON_EFI) +CPPFLAGS_crt0-efi-aarch64.o += $(CFLAGS_EFI) diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h index 45401d5e3c8a..6e4471662a38 100644 --- a/arch/arm/include/asm/global_data.h +++ b/arch/arm/include/asm/global_data.h @@ -107,8 +107,11 @@ struct arch_global_data { #endif #ifdef CONFIG_SMBIOS ulong smbios_start; /* Start address of SMBIOS table */ #endif +#ifdef CONFIG_EFI_STUB + ulong table; +#endif };
#include <asm-generic/global_data.h>
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index 1c95dd6fed21..14e3990925a7 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -130,4 +130,6 @@ CFLAGS_$(EFI_CRT0) := $(CFLAGS_EFI) CFLAGS_REMOVE_$(EFI_CRT0) := $(CFLAGS_NON_EFI)
CFLAGS_$(EFI_RELOC) := $(CFLAGS_EFI) CFLAGS_REMOVE_$(EFI_RELOC) := $(CFLAGS_NON_EFI) + +extra-$(CONFIG_EFI_STUB) += $(EFI_CRT0) $(EFI_RELOC) diff --git a/include/efi.h b/include/efi.h index c559fda3004c..a6eff13a6bbb 100644 --- a/include/efi.h +++ b/include/efi.h @@ -496,9 +496,9 @@ struct efi_media_plat { /* Base address of the EFI image */ extern char image_base[];
/* Start and end of U-Boot image (for payload) */ -extern char _binary_u_boot_bin_start[], _binary_u_boot_bin_end[]; +extern char _binary_u_boot_bin_start[], _binary_u_boot_bin_end[], _binary_u_boot_bin_size[];
/* * Variable Attributes */ diff --git a/lib/efi/Kconfig b/lib/efi/Kconfig index 81ed3e66b34d..18f69bdcfbec 100644 --- a/lib/efi/Kconfig +++ b/lib/efi/Kconfig @@ -1,10 +1,10 @@ menu "U-Boot as UEFI application" - depends on X86 + depends on X86 || ARM
config EFI bool "Support running U-Boot from EFI" - depends on X86 + depends on X86 || ARM imply X86_TSC_READ_BASE help U-Boot can be started from EFI on certain platforms. This allows EFI to perform most of the system init and then jump to U-Boot for @@ -12,12 +12,13 @@ config EFI application, with U-Boot using EFI's drivers instead of its own.
choice prompt "Select EFI mode to use" - depends on X86 && EFI + depends on EFI
config EFI_APP bool "Support running as an EFI application" + depends on !ARM select CHARSET help Build U-Boot as an application which can be started from EFI. This is useful for examining a platform in the early stages of porting @@ -25,8 +26,9 @@ config EFI_APP command prompt and memory and I/O functions. Use 'reset' to return to EFI.
config EFI_STUB + select POSITION_INDEPENDENT if ARM bool "Support running as an EFI payload"
endchoice
@@ -58,8 +60,9 @@ choice 32-bit EFI, select 32-bit here, else select 64-bit. Failure to do this may produce no error message - it just won't start!
config EFI_STUB_32BIT + depends on !ARM bool "Produce a stub for running with 32-bit EFI"
config EFI_STUB_64BIT bool "Produce a stub for running with 64-bit EFI" diff --git a/lib/efi/Makefile b/lib/efi/Makefile index 232fa684360e..bf65bacf47e7 100644 --- a/lib/efi/Makefile +++ b/lib/efi/Makefile @@ -4,14 +4,24 @@
obj-$(CONFIG_EFI_APP) += efi_app.o efi.o efi_app_init.o obj-$(CONFIG_EFI_STUB) += efi_info.o
-CFLAGS_REMOVE_efi_stub.o := -mregparm=3 \ - $(if $(CONFIG_EFI_STUB_64BIT),-march=i386 -m32) -CFLAGS_efi_stub.o := -fpic -fshort-wchar \ - $(if $(CONFIG_EFI_STUB_64BIT),-m64) -CFLAGS_REMOVE_efi.o := -mregparm=3 \ - $(if $(CONFIG_EFI_STUB_64BIT),-march=i386 -m32) -CFLAGS_efi.o := -fpic -fshort-wchar \ - $(if $(CONFIG_EFI_STUB_64BIT),-m64) +ifeq ($(CONFIG_ARM64),y) +efi_stub.o := efi_stub_arm64.o +else +efi_stub.o := efi_stub_x86.o
-extra-$(CONFIG_EFI_STUB) += efi_stub.o efi.o +ifeq ($(CONFIG_EFI_STUB_64BIT),y) # && !CONFIG_ARM64 +CFLAGS_REMOVE_$(efi_stub.o) := -march=i386 -m32 +CFLAGS_$(efi_stub.o) := -m64 +CFLAGS_REMOVE_efi.o := -march=i386 -m32 +CFLAGS_efi.o := -fpic -m64 +endif +endif + +CFLAGS_REMOVE_$(efi_stub.o) += -mregparm=3 +CFLAGS_$(efi_stub.o) += -fpic -fshort-wchar +CFLAGS_REMOVE_efi.o += -mregparm=3 +CFLAGS_efi.o += -fpic -fshort-wchar + +$(info removing flags $(CFLAGS_REMOVE_$(efi_stub.o))) +extra-$(CONFIG_EFI_STUB) += $(efi_stub.o) efi.o diff --git a/lib/efi/efi_info.c b/lib/efi/efi_info.c index 5b564c5651d5..5fa4baeec635 100644 --- a/lib/efi/efi_info.c +++ b/lib/efi/efi_info.c @@ -9,8 +9,10 @@ #include <errno.h> #include <mapmem.h> #include <asm/global_data.h>
+DECLARE_GLOBAL_DATA_PTR; + int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) { struct efi_entry_hdr *entry; struct efi_info_hdr *info; @@ -41,6 +43,6 @@ int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) ret = -ENOENT; err: unmap_sysmem(info);
- return ret; + return -ENOSYS; } diff --git a/lib/efi/efi_stub_arm64.c b/lib/efi/efi_stub_arm64.c new file mode 100644 index 000000000000..54bee6c55d7e --- /dev/null +++ b/lib/efi/efi_stub_arm64.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2015 Google, Inc + * Copyright (c) 2024 Linaro, Ltd. + * + * EFI information obtained here: + * http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES + * + * Call ExitBootServices() and launch U-Boot from an EFI environment. + */ + +#include <debug_uart.h> +#include <efi.h> +#include <efi_api.h> +#include <malloc.h> +#include <asm/io.h> +#include <linux/err.h> +#include <linux/types.h> + +static bool ebs_called; + +void _debug_uart_putc(int ch) +{ + struct efi_priv *priv = efi_get_priv(); + + if (ch == '\n') + _debug_uart_putc('\r'); + /* + * After calling EBS we can't log anywhere. + * NOTE: for development it is possible to re-implement + * your boards debug uart here like in efi_stub.c for x86. + */ + if (!ebs_called) + efi_putc(priv, ch); +} + +void _debug_uart_init(void) {} + +DEBUG_UART_FUNCS; + +void putc(const char ch) +{ + _debug_uart_putc(ch); +} + +void puts(const char *str) +{ + while (*str) + putc(*str++); +} + + +void *memcpy(void *dest, const void *src, size_t size) +{ + unsigned char *dptr = dest; + const unsigned char *ptr = src; + const unsigned char *end = src + size; + + while (ptr < end) + *dptr++ = *ptr++; + + return dest; +} + +void *memset(void *inptr, int ch, size_t size) +{ + char *ptr = inptr; + char *end = ptr + size; + + while (ptr < end) + *ptr++ = ch; + + return ptr; +} + +/** + * setup_info_table() - sets up a table containing information from EFI + * + * We must call exit_boot_services() before jumping out of the stub into U-Boot + * proper, so that U-Boot has full control of peripherals, memory, etc. + * + * Once we do this, we cannot call any boot-services functions so we must find + * out everything we need to before doing that. + * + * Set up a struct efi_info_hdr table which can hold various records (e.g. + * struct efi_entry_memmap) with information obtained from EFI. + * + * @priv: Pointer to our private information which contains the list + * @size: Size of the table to allocate + * Return: 0 if OK, non-zero on error + */ +static int setup_info_table(struct efi_priv *priv, int size) +{ + struct efi_info_hdr *info; + efi_status_t ret; + + /* Get some memory for our info table */ + priv->info_size = size; + info = efi_malloc(priv, priv->info_size, &ret); + if (ret) { + printhex2(ret); + puts(" No memory for info table: "); + return ret; + } + + memset(info, '\0', sizeof(*info)); + info->version = EFI_TABLE_VERSION; + info->hdr_size = sizeof(*info); + priv->info = info; + priv->next_hdr = (char *)info + info->hdr_size; + + return 0; +} + +/** + * add_entry_addr() - Add a new entry to the efi_info list + * + * This adds an entry, consisting of a tag and two lots of data. This avoids the + * caller having to coalesce the data first + * + * @priv: Pointer to our private information which contains the list + * @type: Type of the entry to add + * @ptr1: Pointer to first data block to add + * @size1: Size of first data block in bytes (can be 0) + * @ptr2: Pointer to second data block to add + * @size2: Size of second data block in bytes (can be 0) + */ +static void add_entry_addr(struct efi_priv *priv, enum efi_entry_t type, + void *ptr1, int size1, void *ptr2, int size2) +{ + struct efi_entry_hdr *hdr = priv->next_hdr; + + hdr->type = type; + hdr->size = size1 + size2; + hdr->addr = 0; + hdr->link = ALIGN(sizeof(*hdr) + hdr->size, 16); + priv->next_hdr += hdr->link; + memcpy(hdr + 1, ptr1, size1); + memcpy((void *)(hdr + 1) + size1, ptr2, size2); + priv->info->total_size = (ulong)priv->next_hdr - (ulong)priv->info; +} + +/** + * efi_main() - Start an EFI image + * + * This function is called by our EFI start-up code. It handles running + * U-Boot. If it returns, EFI will continue. + */ +efi_status_t EFIAPI efi_main(efi_handle_t image, + struct efi_system_table *sys_table) +{ + struct efi_priv local_priv, *priv = &local_priv; + struct efi_boot_services *boot = sys_table->boottime; + struct efi_entry_memmap map; + struct efi_gop *gop; + struct efi_entry_gopmode mode; + struct efi_entry_systable table; + efi_guid_t efi_gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; + efi_status_t ret; + + ebs_called = false; + + ret = efi_init(priv, "Payload", image, sys_table); + if (ret) { + printhex2(ret); + puts(" efi_init() failed\n"); + return ret; + } + efi_set_priv(priv); + + phys_addr_t reloc_addr = ULONG_MAX; + ret = boot->allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, EFI_LOADER_CODE, + (phys_addr_t)_binary_u_boot_bin_size / EFI_PAGE_SIZE, + &reloc_addr); + if (ret != EFI_SUCCESS) { + puts("Failed to allocate memory for U-Boot: "); + printhex2(ret); + putc('\n'); + return ret; + } + + ret = efi_store_memory_map(priv); + if (ret) + return ret; + + ret = setup_info_table(priv, priv->memmap_size + 128); + if (ret) + return ret; + + ret = boot->locate_protocol(&efi_gop_guid, NULL, (void **)&gop); + if (ret) { + puts(" GOP unavailable\n"); + } else { + mode.fb_base = gop->mode->fb_base; + mode.fb_size = gop->mode->fb_size; + mode.info_size = gop->mode->info_size; + add_entry_addr(priv, EFIET_GOP_MODE, &mode, sizeof(mode), + gop->mode->info, + sizeof(struct efi_gop_mode_info)); + } + + table.sys_table = (ulong)sys_table; + add_entry_addr(priv, EFIET_SYS_TABLE, &table, sizeof(table), NULL, 0); + + ret = efi_call_exit_boot_services(); + if (ret) + return ret; + + /* The EFI console won't work now :( */ + ebs_called = true; + + map.version = priv->memmap_version; + map.desc_size = priv->memmap_desc_size; + add_entry_addr(priv, EFIET_MEMORY_MAP, &map, sizeof(map), + priv->memmap_desc, priv->memmap_size); + add_entry_addr(priv, EFIET_END, NULL, 0, 0, 0); + + memcpy((void *)reloc_addr, _binary_u_boot_bin_start, + (ulong)_binary_u_boot_bin_end - + (ulong)_binary_u_boot_bin_start); + +/* This will only work if you patched your own debug uart into this file. */ +#ifdef DEBUG + puts("EFI table at "); + printhex8((ulong)priv->info); + puts(" size "); + printhex8(priv->info->total_size); + putc('\n'); +#endif + typedef void (*func_t)(u64 x0, u64 x1, u64 x2, u64 x3); + + puts("Jumping to U-Boot\n"); + ((func_t)reloc_addr)((phys_addr_t)priv->info, 0, 0, 0); + + return EFI_LOAD_ERROR; +} diff --git a/lib/efi/efi_stub.c b/lib/efi/efi_stub_x86.c similarity index 100% rename from lib/efi/efi_stub.c rename to lib/efi/efi_stub_x86.c

Hi Caleb,
On Sun, 24 Nov 2024 at 22:27, Caleb Connolly caleb.connolly@linaro.org wrote:
Implement support for launching U-Boot via an EFI stub app on ARM64.
This is more or less a straight port of the x86 implementation, but due to the highly x86/qemu specific nature of that implementation I decided to just split it out to its own file.
Unlike the x86 implementation, there is no debug UART here since ARM platforms don't have a standard UART interface. However it is usually possible to port over the debug uart implementation for you platform for bringup purposes.
Currently this implementation doesn't provide a DTB to U-Boot and expects U-Boot to use a built-in one, however this ought to be a fairly trivial addition in the future.
The other significant difference to the x86 version is that rather than copying U-Boot to CONFIG_TEXT_OFFSET, we require that U-Boot is built position independent and copy it to EFI allocated memory.
This isn't bad, but there's lots of duplication from x86. For an RFC that's fine but for a v1, please create an efi_stub_common.c and move code in there
Cheers /Ilias
Signed-off-by: Caleb Connolly caleb.connolly@linaro.org
Makefile | 15 ++- arch/arm/cpu/armv8/config.mk | 11 ++ arch/arm/include/asm/global_data.h | 3 + arch/arm/lib/Makefile | 2 + include/efi.h | 2 +- lib/efi/Kconfig | 9 +- lib/efi/Makefile | 28 ++-- lib/efi/efi_info.c | 4 +- lib/efi/efi_stub_arm64.c | 236 +++++++++++++++++++++++++++++++++ lib/efi/{efi_stub.c => efi_stub_x86.c} | 0 10 files changed, 294 insertions(+), 16 deletions(-)
diff --git a/Makefile b/Makefile index da742ceae76e..8d0340622d7c 100644 --- a/Makefile +++ b/Makefile @@ -1681,21 +1681,32 @@ u-boot.bin.o: u-boot.bin FORCE
u-boot-payload.lds: $(LDSCRIPT_EFI) FORCE $(call if_changed_dep,cpp_lds)
+# Determine the file suffix for the efi stub implementation +EFI_STUB_ARCH := $(if $(CONFIG_ARM64),arm64,$(if $(CONFIG_X86_64),x86,$(ARCH)))
# Rule to link the EFI payload which contains a stub and a U-Boot binary quiet_cmd_u-boot_payload ?= LD $@ cmd_u-boot_payload ?= $(LD) $(LDFLAGS_EFI_PAYLOAD) -o $@ \
-T u-boot-payload.lds arch/x86/cpu/call32.o \
lib/efi/efi.o lib/efi/efi_stub.o u-boot.bin.o \
-T u-boot-payload.lds $(if $(CONFIG_X86),arch/x86/cpu/call32.o,) \
lib/efi/efi.o lib/efi/efi_stub_$(EFI_STUB_ARCH).o u-boot.bin.o \ $(addprefix arch/$(ARCH)/lib/,$(EFISTUB))
+quiet_cmd_u-boot_payload_arm64.efi ?= OBJCOPY $@
cmd_u-boot_payload_arm64.efi ?= $(OBJCOPY) -O binary u-boot-payload $@
u-boot-payload: u-boot.bin.o u-boot-payload.lds FORCE $(call if_changed,u-boot_payload)
OBJCOPYFLAGS_u-boot-payload.efi := $(OBJCOPYFLAGS_EFI) +ifeq ($(CONFIG_X86),y) u-boot-payload.efi: u-boot-payload FORCE $(call if_changed,zobjcopy) +else +u-boot-payload.efi: u-boot-payload FORCE
$(call if_changed,u-boot_payload_$(EFI_STUB_ARCH).efi)
+endif
u-boot-img.bin: spl/u-boot-spl.bin u-boot.img FORCE $(call if_changed,cat)
diff --git a/arch/arm/cpu/armv8/config.mk b/arch/arm/cpu/armv8/config.mk index 4d74b2a533e0..1ee316801064 100644 --- a/arch/arm/cpu/armv8/config.mk +++ b/arch/arm/cpu/armv8/config.mk @@ -9,4 +9,15 @@ PLATFORM_CPPFLAGS += $(PF_NO_UNALIGNED)
EFI_LDS := elf_aarch64_efi.lds EFI_CRT0 := crt0_aarch64_efi.o EFI_RELOC := reloc_aarch64_efi.o
+LDSCRIPT_EFI := $(srctree)/arch/arm/lib/elf_aarch64_efi.lds +EFISTUB := crt0_aarch64_efi.o reloc_aarch64_efi.o +OBJCOPYFLAGS_EFI += --target=pei-aarch64-little +EFIPAYLOAD_BFDTARGET := pei-aarch64-little +EFIPAYLOAD_BFDARCH := aarch64 +LDFLAGS_EFI_PAYLOAD := -Bsymbolic -Bsymbolic-functions -shared --no-undefined \
-s -zexecstack
+CPPFLAGS_REMOVE_crt0-efi-aarch64.o += $(CFLAGS_NON_EFI) +CPPFLAGS_crt0-efi-aarch64.o += $(CFLAGS_EFI) diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h index 45401d5e3c8a..6e4471662a38 100644 --- a/arch/arm/include/asm/global_data.h +++ b/arch/arm/include/asm/global_data.h @@ -107,8 +107,11 @@ struct arch_global_data { #endif #ifdef CONFIG_SMBIOS ulong smbios_start; /* Start address of SMBIOS table */ #endif +#ifdef CONFIG_EFI_STUB
ulong table;
+#endif };
#include <asm-generic/global_data.h>
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index 1c95dd6fed21..14e3990925a7 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -130,4 +130,6 @@ CFLAGS_$(EFI_CRT0) := $(CFLAGS_EFI) CFLAGS_REMOVE_$(EFI_CRT0) := $(CFLAGS_NON_EFI)
CFLAGS_$(EFI_RELOC) := $(CFLAGS_EFI) CFLAGS_REMOVE_$(EFI_RELOC) := $(CFLAGS_NON_EFI)
+extra-$(CONFIG_EFI_STUB) += $(EFI_CRT0) $(EFI_RELOC) diff --git a/include/efi.h b/include/efi.h index c559fda3004c..a6eff13a6bbb 100644 --- a/include/efi.h +++ b/include/efi.h @@ -496,9 +496,9 @@ struct efi_media_plat { /* Base address of the EFI image */ extern char image_base[];
/* Start and end of U-Boot image (for payload) */ -extern char _binary_u_boot_bin_start[], _binary_u_boot_bin_end[]; +extern char _binary_u_boot_bin_start[], _binary_u_boot_bin_end[], _binary_u_boot_bin_size[];
/*
- Variable Attributes
*/ diff --git a/lib/efi/Kconfig b/lib/efi/Kconfig index 81ed3e66b34d..18f69bdcfbec 100644 --- a/lib/efi/Kconfig +++ b/lib/efi/Kconfig @@ -1,10 +1,10 @@ menu "U-Boot as UEFI application"
depends on X86
depends on X86 || ARM
config EFI bool "Support running U-Boot from EFI"
depends on X86
depends on X86 || ARM imply X86_TSC_READ_BASE help U-Boot can be started from EFI on certain platforms. This allows EFI to perform most of the system init and then jump to U-Boot for
@@ -12,12 +12,13 @@ config EFI application, with U-Boot using EFI's drivers instead of its own.
choice prompt "Select EFI mode to use"
depends on X86 && EFI
depends on EFI
config EFI_APP bool "Support running as an EFI application"
depends on !ARM select CHARSET help Build U-Boot as an application which can be started from EFI. This is useful for examining a platform in the early stages of porting
@@ -25,8 +26,9 @@ config EFI_APP command prompt and memory and I/O functions. Use 'reset' to return to EFI.
config EFI_STUB
select POSITION_INDEPENDENT if ARM bool "Support running as an EFI payload"
endchoice
@@ -58,8 +60,9 @@ choice 32-bit EFI, select 32-bit here, else select 64-bit. Failure to do this may produce no error message - it just won't start!
config EFI_STUB_32BIT
depends on !ARM bool "Produce a stub for running with 32-bit EFI"
config EFI_STUB_64BIT bool "Produce a stub for running with 64-bit EFI" diff --git a/lib/efi/Makefile b/lib/efi/Makefile index 232fa684360e..bf65bacf47e7 100644 --- a/lib/efi/Makefile +++ b/lib/efi/Makefile @@ -4,14 +4,24 @@
obj-$(CONFIG_EFI_APP) += efi_app.o efi.o efi_app_init.o obj-$(CONFIG_EFI_STUB) += efi_info.o
-CFLAGS_REMOVE_efi_stub.o := -mregparm=3 \
$(if $(CONFIG_EFI_STUB_64BIT),-march=i386 -m32)
-CFLAGS_efi_stub.o := -fpic -fshort-wchar \
$(if $(CONFIG_EFI_STUB_64BIT),-m64)
-CFLAGS_REMOVE_efi.o := -mregparm=3 \
$(if $(CONFIG_EFI_STUB_64BIT),-march=i386 -m32)
-CFLAGS_efi.o := -fpic -fshort-wchar \
$(if $(CONFIG_EFI_STUB_64BIT),-m64)
+ifeq ($(CONFIG_ARM64),y) +efi_stub.o := efi_stub_arm64.o +else +efi_stub.o := efi_stub_x86.o
-extra-$(CONFIG_EFI_STUB) += efi_stub.o efi.o +ifeq ($(CONFIG_EFI_STUB_64BIT),y) # && !CONFIG_ARM64 +CFLAGS_REMOVE_$(efi_stub.o) := -march=i386 -m32 +CFLAGS_$(efi_stub.o) := -m64 +CFLAGS_REMOVE_efi.o := -march=i386 -m32 +CFLAGS_efi.o := -fpic -m64 +endif +endif
+CFLAGS_REMOVE_$(efi_stub.o) += -mregparm=3 +CFLAGS_$(efi_stub.o) += -fpic -fshort-wchar +CFLAGS_REMOVE_efi.o += -mregparm=3 +CFLAGS_efi.o += -fpic -fshort-wchar
+$(info removing flags $(CFLAGS_REMOVE_$(efi_stub.o))) +extra-$(CONFIG_EFI_STUB) += $(efi_stub.o) efi.o diff --git a/lib/efi/efi_info.c b/lib/efi/efi_info.c index 5b564c5651d5..5fa4baeec635 100644 --- a/lib/efi/efi_info.c +++ b/lib/efi/efi_info.c @@ -9,8 +9,10 @@ #include <errno.h> #include <mapmem.h> #include <asm/global_data.h>
+DECLARE_GLOBAL_DATA_PTR;
int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) { struct efi_entry_hdr *entry; struct efi_info_hdr *info; @@ -41,6 +43,6 @@ int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) ret = -ENOENT; err: unmap_sysmem(info);
return ret;
return -ENOSYS;
} diff --git a/lib/efi/efi_stub_arm64.c b/lib/efi/efi_stub_arm64.c new file mode 100644 index 000000000000..54bee6c55d7e --- /dev/null +++ b/lib/efi/efi_stub_arm64.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (c) 2015 Google, Inc
- Copyright (c) 2024 Linaro, Ltd.
- EFI information obtained here:
- Call ExitBootServices() and launch U-Boot from an EFI environment.
- */
+#include <debug_uart.h> +#include <efi.h> +#include <efi_api.h> +#include <malloc.h> +#include <asm/io.h> +#include <linux/err.h> +#include <linux/types.h>
+static bool ebs_called;
+void _debug_uart_putc(int ch) +{
struct efi_priv *priv = efi_get_priv();
if (ch == '\n')
_debug_uart_putc('\r');
/*
* After calling EBS we can't log anywhere.
* NOTE: for development it is possible to re-implement
* your boards debug uart here like in efi_stub.c for x86.
*/
if (!ebs_called)
efi_putc(priv, ch);
+}
+void _debug_uart_init(void) {}
+DEBUG_UART_FUNCS;
+void putc(const char ch) +{
_debug_uart_putc(ch);
+}
+void puts(const char *str) +{
while (*str)
putc(*str++);
+}
+void *memcpy(void *dest, const void *src, size_t size) +{
unsigned char *dptr = dest;
const unsigned char *ptr = src;
const unsigned char *end = src + size;
while (ptr < end)
*dptr++ = *ptr++;
return dest;
+}
+void *memset(void *inptr, int ch, size_t size) +{
char *ptr = inptr;
char *end = ptr + size;
while (ptr < end)
*ptr++ = ch;
return ptr;
+}
+/**
- setup_info_table() - sets up a table containing information from EFI
- We must call exit_boot_services() before jumping out of the stub into U-Boot
- proper, so that U-Boot has full control of peripherals, memory, etc.
- Once we do this, we cannot call any boot-services functions so we must find
- out everything we need to before doing that.
- Set up a struct efi_info_hdr table which can hold various records (e.g.
- struct efi_entry_memmap) with information obtained from EFI.
- @priv: Pointer to our private information which contains the list
- @size: Size of the table to allocate
- Return: 0 if OK, non-zero on error
- */
+static int setup_info_table(struct efi_priv *priv, int size) +{
struct efi_info_hdr *info;
efi_status_t ret;
/* Get some memory for our info table */
priv->info_size = size;
info = efi_malloc(priv, priv->info_size, &ret);
if (ret) {
printhex2(ret);
puts(" No memory for info table: ");
return ret;
}
memset(info, '\0', sizeof(*info));
info->version = EFI_TABLE_VERSION;
info->hdr_size = sizeof(*info);
priv->info = info;
priv->next_hdr = (char *)info + info->hdr_size;
return 0;
+}
+/**
- add_entry_addr() - Add a new entry to the efi_info list
- This adds an entry, consisting of a tag and two lots of data. This avoids the
- caller having to coalesce the data first
- @priv: Pointer to our private information which contains the list
- @type: Type of the entry to add
- @ptr1: Pointer to first data block to add
- @size1: Size of first data block in bytes (can be 0)
- @ptr2: Pointer to second data block to add
- @size2: Size of second data block in bytes (can be 0)
- */
+static void add_entry_addr(struct efi_priv *priv, enum efi_entry_t type,
void *ptr1, int size1, void *ptr2, int size2)
+{
struct efi_entry_hdr *hdr = priv->next_hdr;
hdr->type = type;
hdr->size = size1 + size2;
hdr->addr = 0;
hdr->link = ALIGN(sizeof(*hdr) + hdr->size, 16);
priv->next_hdr += hdr->link;
memcpy(hdr + 1, ptr1, size1);
memcpy((void *)(hdr + 1) + size1, ptr2, size2);
priv->info->total_size = (ulong)priv->next_hdr - (ulong)priv->info;
+}
+/**
- efi_main() - Start an EFI image
- This function is called by our EFI start-up code. It handles running
- U-Boot. If it returns, EFI will continue.
- */
+efi_status_t EFIAPI efi_main(efi_handle_t image,
struct efi_system_table *sys_table)
+{
struct efi_priv local_priv, *priv = &local_priv;
struct efi_boot_services *boot = sys_table->boottime;
struct efi_entry_memmap map;
struct efi_gop *gop;
struct efi_entry_gopmode mode;
struct efi_entry_systable table;
efi_guid_t efi_gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
efi_status_t ret;
ebs_called = false;
ret = efi_init(priv, "Payload", image, sys_table);
if (ret) {
printhex2(ret);
puts(" efi_init() failed\n");
return ret;
}
efi_set_priv(priv);
phys_addr_t reloc_addr = ULONG_MAX;
ret = boot->allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, EFI_LOADER_CODE,
(phys_addr_t)_binary_u_boot_bin_size / EFI_PAGE_SIZE,
&reloc_addr);
if (ret != EFI_SUCCESS) {
puts("Failed to allocate memory for U-Boot: ");
printhex2(ret);
putc('\n');
return ret;
}
ret = efi_store_memory_map(priv);
if (ret)
return ret;
ret = setup_info_table(priv, priv->memmap_size + 128);
if (ret)
return ret;
ret = boot->locate_protocol(&efi_gop_guid, NULL, (void **)&gop);
if (ret) {
puts(" GOP unavailable\n");
} else {
mode.fb_base = gop->mode->fb_base;
mode.fb_size = gop->mode->fb_size;
mode.info_size = gop->mode->info_size;
add_entry_addr(priv, EFIET_GOP_MODE, &mode, sizeof(mode),
gop->mode->info,
sizeof(struct efi_gop_mode_info));
}
table.sys_table = (ulong)sys_table;
add_entry_addr(priv, EFIET_SYS_TABLE, &table, sizeof(table), NULL, 0);
ret = efi_call_exit_boot_services();
if (ret)
return ret;
/* The EFI console won't work now :( */
ebs_called = true;
map.version = priv->memmap_version;
map.desc_size = priv->memmap_desc_size;
add_entry_addr(priv, EFIET_MEMORY_MAP, &map, sizeof(map),
priv->memmap_desc, priv->memmap_size);
add_entry_addr(priv, EFIET_END, NULL, 0, 0, 0);
memcpy((void *)reloc_addr, _binary_u_boot_bin_start,
(ulong)_binary_u_boot_bin_end -
(ulong)_binary_u_boot_bin_start);
+/* This will only work if you patched your own debug uart into this file. */ +#ifdef DEBUG
puts("EFI table at ");
printhex8((ulong)priv->info);
puts(" size ");
printhex8(priv->info->total_size);
putc('\n');
+#endif
typedef void (*func_t)(u64 x0, u64 x1, u64 x2, u64 x3);
puts("Jumping to U-Boot\n");
((func_t)reloc_addr)((phys_addr_t)priv->info, 0, 0, 0);
return EFI_LOAD_ERROR;
+} diff --git a/lib/efi/efi_stub.c b/lib/efi/efi_stub_x86.c similarity index 100% rename from lib/efi/efi_stub.c rename to lib/efi/efi_stub_x86.c
-- 2.47.0

Split out the EFI stub specific code to a new efi_stub.h header file.
Signed-off-by: Caleb Connolly caleb.connolly@linaro.org --- arch/x86/cpu/efi/payload.c | 1 + cmd/efi.c | 1 + drivers/video/efi.c | 1 + include/efi.h | 25 ------------------------- include/efi_stub.h | 38 ++++++++++++++++++++++++++++++++++++++ lib/efi/efi_app.c | 1 + lib/efi/efi_info.c | 1 + lib/efi/efi_stub_arm64.c | 1 + lib/efi/efi_stub_x86.c | 1 + 9 files changed, 45 insertions(+), 25 deletions(-)
diff --git a/arch/x86/cpu/efi/payload.c b/arch/x86/cpu/efi/payload.c index 6845ce72ff94..68cda25aca63 100644 --- a/arch/x86/cpu/efi/payload.c +++ b/arch/x86/cpu/efi/payload.c @@ -6,8 +6,9 @@
#include <cpu_func.h> #include <efi.h> #include <efi_api.h> +#include <efi_stub.h> #include <errno.h> #include <event.h> #include <init.h> #include <log.h> diff --git a/cmd/efi.c b/cmd/efi.c index 1fb67a83aae5..53213be0a2fa 100644 --- a/cmd/efi.c +++ b/cmd/efi.c @@ -6,8 +6,9 @@
#include <command.h> #include <efi.h> #include <efi_api.h> +#include <efi_stub.h> #include <errno.h> #include <log.h> #include <malloc.h> #include <sort.h> diff --git a/drivers/video/efi.c b/drivers/video/efi.c index 78d123fad4be..a7b6d47f9a15 100644 --- a/drivers/video/efi.c +++ b/drivers/video/efi.c @@ -8,8 +8,9 @@ #define LOG_CATEGORY LOGC_EFI
#include <dm.h> #include <efi_api.h> +#include <efi_stub.h> #include <log.h> #include <vesa.h> #include <video.h>
diff --git a/include/efi.h b/include/efi.h index a6eff13a6bbb..933be35852df 100644 --- a/include/efi.h +++ b/include/efi.h @@ -321,18 +321,8 @@ struct efi_open_protocol_info_entry { u32 attributes; u32 open_count; };
-enum efi_entry_t { - EFIET_END, /* Signals this is the last (empty) entry */ - EFIET_MEMORY_MAP, - EFIET_GOP_MODE, - EFIET_SYS_TABLE, - - /* Number of entries */ - EFIET_MEMORY_COUNT, -}; - #define EFI_TABLE_VERSION 1
/** * struct efi_info_hdr - Header for the EFI info table @@ -609,23 +599,8 @@ void efi_puts(struct efi_priv *priv, const char *str); * @ch: Character to write (note this is not unicode) */ void efi_putc(struct efi_priv *priv, const char ch);
-/** - * efi_info_get() - get an entry from an EFI table - * - * This function is called from U-Boot proper to read information set up by the - * EFI stub. It can only be used when running from the EFI stub, not when U-Boot - * is running as an app. - * - * @type: Entry type to search for - * @datap: Returns pointer to entry data - * @sizep: Returns entry size - * Return: 0 if OK, -ENODATA if there is no table, -ENOENT if there is no entry - * 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); - /** * efi_store_memory_map() - Collect the memory-map info from EFI * * Collect the memory info and store it for later use, e.g. in calling diff --git a/include/efi_stub.h b/include/efi_stub.h new file mode 100644 index 000000000000..4780badd3ac4 --- /dev/null +++ b/include/efi_stub.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Helpers for U-Boot running as an EFI payload. + * + * Copyright (c) 2024 Linaro, Ltd + */ + +#ifndef _EFI_STUB_H +#define _EFI_STUB_H + +#include <linux/types.h> + +enum efi_entry_t { + EFIET_END, /* Signals this is the last (empty) entry */ + EFIET_MEMORY_MAP, + EFIET_GOP_MODE, + EFIET_SYS_TABLE, + + /* Number of entries */ + EFIET_MEMORY_COUNT, +}; + +/** + * efi_info_get() - get an entry from an EFI table + * + * This function is called from U-Boot proper to read information set up by the + * EFI stub. It can only be used when running from the EFI stub, not when U-Boot + * is running as an app. + * + * @type: Entry type to search for + * @datap: Returns pointer to entry data + * @sizep: Returns entry size + * Return: 0 if OK, -ENODATA if there is no table, -ENOENT if there is no entry + * 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); + +#endif /* _EFI_STUB_H */ diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index 9b94a93ee4f1..2c66133648e4 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -12,8 +12,9 @@ #include <debug_uart.h> #include <dm.h> #include <efi.h> #include <efi_api.h> +#include <efi_stub.h> #include <errno.h> #include <init.h> #include <malloc.h> #include <sysreset.h> diff --git a/lib/efi/efi_info.c b/lib/efi/efi_info.c index 5fa4baeec635..32ba7e499c57 100644 --- a/lib/efi/efi_info.c +++ b/lib/efi/efi_info.c @@ -5,8 +5,9 @@ * Access to the EFI information table */
#include <efi.h> +#include <efi_stub.h> #include <errno.h> #include <mapmem.h> #include <asm/global_data.h>
diff --git a/lib/efi/efi_stub_arm64.c b/lib/efi/efi_stub_arm64.c index 54bee6c55d7e..2cabb16f2414 100644 --- a/lib/efi/efi_stub_arm64.c +++ b/lib/efi/efi_stub_arm64.c @@ -11,8 +11,9 @@
#include <debug_uart.h> #include <efi.h> #include <efi_api.h> +#include <efi_stub.h> #include <malloc.h> #include <asm/io.h> #include <linux/err.h> #include <linux/types.h> diff --git a/lib/efi/efi_stub_x86.c b/lib/efi/efi_stub_x86.c index 40fc29d9adf7..ea1993f745d3 100644 --- a/lib/efi/efi_stub_x86.c +++ b/lib/efi/efi_stub_x86.c @@ -11,8 +11,9 @@
#include <debug_uart.h> #include <efi.h> #include <efi_api.h> +#include <efi_stub.h> #include <errno.h> #include <malloc.h> #include <ns16550.h> #include <asm/cpu.h>

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

U-Boot itself might be mapped as LOADER_CODE, there's also no reason not to make additional pages accessible to the OS. This fixes an issue where U-Boot can't run EFI apps because it gets relocated somewhere outside of its own memory map.
Signed-off-by: Caleb Connolly caleb.connolly@linaro.org --- lib/efi/efi_info.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-)
diff --git a/lib/efi/efi_info.c b/lib/efi/efi_info.c index 3fa594b34b42..3754c913b54d 100644 --- a/lib/efi/efi_info.c +++ b/lib/efi/efi_info.c @@ -120,8 +120,28 @@ int of_populate_from_efi(struct device_node *root)
return ret; }
+static bool efi_mem_type_is_usable(u32 type) +{ + switch (type) { + case EFI_CONVENTIONAL_MEMORY: + case EFI_LOADER_DATA: + case EFI_LOADER_CODE: + case EFI_BOOT_SERVICES_CODE: + return true; + case EFI_RESERVED_MEMORY_TYPE: + case EFI_UNUSABLE_MEMORY: + case EFI_UNACCEPTED_MEMORY_TYPE: + case EFI_RUNTIME_SERVICES_DATA: + case EFI_MMAP_IO: + case EFI_MMAP_IO_PORT: + case EFI_PERSISTENT_MEMORY_TYPE: + default: + return false; + } +} + int dram_init_banksize_from_efi(void) { struct efi_mem_desc *desc, *end; struct efi_entry_memmap *map; @@ -142,10 +162,9 @@ int dram_init_banksize_from_efi(void) /* * 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) + if (!efi_mem_type_is_usable(desc->type) || (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;

Add a debug log for these since its often useful to inspect the memory map from the EFI we're jumping from.
Signed-off-by: Caleb Connolly caleb.connolly@linaro.org --- lib/efi/efi_info.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/lib/efi/efi_info.c b/lib/efi/efi_info.c index 3754c913b54d..f9743a3e7fad 100644 --- a/lib/efi/efi_info.c +++ b/lib/efi/efi_info.c @@ -144,9 +144,9 @@ static bool efi_mem_type_is_usable(u32 type) int dram_init_banksize_from_efi(void) { struct efi_mem_desc *desc, *end; struct efi_entry_memmap *map; - int ret, size; + int ret, size, bank = 0; int num_banks;
ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size); if (ret) { @@ -162,9 +162,14 @@ int dram_init_banksize_from_efi(void) /* * We only use conventional memory and ignore * anything less than 1MB. */ - if (!efi_mem_type_is_usable(desc->type) || (desc->num_pages << EFI_PAGE_SHIFT) < 1 << 20) + log_debug("EFI bank #%d: start %llx, size %llx type %u\n", + bank, desc->physical_start, + desc->num_pages << EFI_PAGE_SHIFT, desc->type); + bank++; + if (!efi_mem_type_is_usable(desc->type) || + (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;

When running U-Boot as an EFI payload with CONFIG_EFI_STUB, the reserved regions from the previous stage EFI bootloader should be carried over since they may not fully align with the reserved-memory regions in devicetree.
Implement a helper to map these pages when the EFI subsystem starts up.
Signed-off-by: Caleb Connolly caleb.connolly@linaro.org --- include/efi_stub.h | 7 +++++++ lib/efi/efi_info.c | 31 +++++++++++++++++++++++++++++++ lib/efi_loader/efi_memory.c | 5 +++++ 3 files changed, 43 insertions(+)
diff --git a/include/efi_stub.h b/include/efi_stub.h index ff3befd4830b..343c84435970 100644 --- a/include/efi_stub.h +++ b/include/efi_stub.h @@ -56,5 +56,12 @@ int of_populate_from_efi(struct device_node *root); * EFI payload with CONFIG_EFI_STUB enabled. */ int dram_init_banksize_from_efi(void);
+/** + * efi_add_known_memory_from_efi() - Add known memory pages from the memory map + * of the EFI bootloader that booted U-Boot. This is only applicable when running + * U-Boot as an EFI payload with CONFIG_EFI_STUB enabled. + */ +void efi_add_known_memory_from_efi(void); + #endif /* _EFI_STUB_H */ diff --git a/lib/efi/efi_info.c b/lib/efi/efi_info.c index f9743a3e7fad..ef4e646b082b 100644 --- a/lib/efi/efi_info.c +++ b/lib/efi/efi_info.c @@ -5,8 +5,9 @@ * Access to the EFI information table */
#include <efi.h> +#include <efi_loader.h> #include <efi_stub.h> #include <errno.h> #include <mapmem.h> #include <asm/global_data.h> @@ -177,4 +178,34 @@ int dram_init_banksize_from_efi(void) }
return 0; } + +/* Called by U-Boot's EFI subsystem to add known memory. In our case + * we need to add some specific memory types from the original bootloaders + * EFI memory map + */ +void efi_add_known_memory_from_efi(void) +{ + struct efi_mem_desc *desc, *end; + struct efi_entry_memmap *map; + int ret, size; + + EFI_PRINT("Adding known memory from previous stage EFI bootloader\n"); + + ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size); + if (ret) { + EFI_PRINT("%s: Missing memory map\n", __func__); + return; + } + end = (struct efi_mem_desc *)((ulong)map + size); + + for (desc = map->desc; desc < end; desc = efi_get_next_mem_desc(desc, map->desc_size)) { + switch (desc->type) { + case EFI_RESERVED_MEMORY_TYPE: + efi_add_memory_map_pg(desc->physical_start, desc->num_pages, desc->type, false); + break; + default: + continue; + } + } +} diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index d2f5d563f2a0..50b0010608e7 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -7,8 +7,9 @@
#define LOG_CATEGORY LOGC_EFI
#include <efi_loader.h> +#include <efi_stub.h> #include <init.h> #include <lmb.h> #include <log.h> #include <malloc.h> @@ -834,8 +835,12 @@ static void add_u_boot_and_runtime(void) int efi_memory_init(void) { efi_add_known_memory();
+#ifdef CONFIG_EFI_STUB + efi_add_known_memory_from_efi(); +#endif + add_u_boot_and_runtime();
#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER /* Request a 32bit 64MB bounce buffer region */

On Mon, 25 Nov 2024 at 01:58, Caleb Connolly caleb.connolly@linaro.org wrote:
When running U-Boot as an EFI payload with CONFIG_EFI_STUB, the reserved regions from the previous stage EFI bootloader should be carried over since they may not fully align with the reserved-memory regions in devicetree.
Implement a helper to map these pages when the EFI subsystem starts up.
Signed-off-by: Caleb Connolly caleb.connolly@linaro.org
include/efi_stub.h | 7 +++++++ lib/efi/efi_info.c | 31 +++++++++++++++++++++++++++++++ lib/efi_loader/efi_memory.c | 5 +++++ 3 files changed, 43 insertions(+)
diff --git a/include/efi_stub.h b/include/efi_stub.h index ff3befd4830b..343c84435970 100644 --- a/include/efi_stub.h +++ b/include/efi_stub.h @@ -56,5 +56,12 @@ int of_populate_from_efi(struct device_node *root);
- EFI payload with CONFIG_EFI_STUB enabled.
*/ int dram_init_banksize_from_efi(void);
+/**
- efi_add_known_memory_from_efi() - Add known memory pages from the memory map
- of the EFI bootloader that booted U-Boot. This is only applicable when running
- U-Boot as an EFI payload with CONFIG_EFI_STUB enabled.
- */
+void efi_add_known_memory_from_efi(void);
#endif /* _EFI_STUB_H */ diff --git a/lib/efi/efi_info.c b/lib/efi/efi_info.c index f9743a3e7fad..ef4e646b082b 100644 --- a/lib/efi/efi_info.c +++ b/lib/efi/efi_info.c @@ -5,8 +5,9 @@
- Access to the EFI information table
*/
#include <efi.h> +#include <efi_loader.h> #include <efi_stub.h> #include <errno.h> #include <mapmem.h> #include <asm/global_data.h> @@ -177,4 +178,34 @@ int dram_init_banksize_from_efi(void) }
return 0;
}
+/* Called by U-Boot's EFI subsystem to add known memory. In our case
- we need to add some specific memory types from the original bootloaders
- EFI memory map
- */
+void efi_add_known_memory_from_efi(void) +{
struct efi_mem_desc *desc, *end;
struct efi_entry_memmap *map;
int ret, size;
EFI_PRINT("Adding known memory from previous stage EFI bootloader\n");
ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size);
if (ret) {
EFI_PRINT("%s: Missing memory map\n", __func__);
return;
}
end = (struct efi_mem_desc *)((ulong)map + size);
for (desc = map->desc; desc < end; desc = efi_get_next_mem_desc(desc, map->desc_size)) {
switch (desc->type) {
case EFI_RESERVED_MEMORY_TYPE:
efi_add_memory_map_pg(desc->physical_start, desc->num_pages, desc->type, false);
break;
default:
continue;
}
}
+}
If this is DRAM memory that is being added, this now needs to happen through LMB to ensure that these reserved memory regions don't get used by the LMB allocator. You can check if something can be added to the lmb_reserve_common() function. These regions will get marked as boot services data. If these are to be kept as reserved memory even in the OS, the memory type of these regions can be updated by keeping this function. But the point to consider is that this needs to be updated in the LMB memory map also.
-sughosh
diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index d2f5d563f2a0..50b0010608e7 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -7,8 +7,9 @@
#define LOG_CATEGORY LOGC_EFI
#include <efi_loader.h>da +#include <efi_stub.h> #include <init.h> #include <lmb.h> #include <log.h> #include <malloc.h> @@ -834,8 +835,12 @@ static void add_u_boot_and_runtime(void) int efi_memory_init(void) { efi_add_known_memory();
+#ifdef CONFIG_EFI_STUB
efi_add_known_memory_from_efi();
+#endif
add_u_boot_and_runtime();
#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER /* Request a 32bit 64MB bounce buffer region */
-- 2.47.0

Hi Sughosh,
Thanks for the review.
On 28/11/2024 07:38, Sughosh Ganu wrote:
On Mon, 25 Nov 2024 at 01:58, Caleb Connolly caleb.connolly@linaro.org wrote:
When running U-Boot as an EFI payload with CONFIG_EFI_STUB, the reserved regions from the previous stage EFI bootloader should be carried over since they may not fully align with the reserved-memory regions in devicetree.
Implement a helper to map these pages when the EFI subsystem starts up.
Signed-off-by: Caleb Connolly caleb.connolly@linaro.org
include/efi_stub.h | 7 +++++++ lib/efi/efi_info.c | 31 +++++++++++++++++++++++++++++++ lib/efi_loader/efi_memory.c | 5 +++++ 3 files changed, 43 insertions(+)
diff --git a/include/efi_stub.h b/include/efi_stub.h index ff3befd4830b..343c84435970 100644 --- a/include/efi_stub.h +++ b/include/efi_stub.h @@ -56,5 +56,12 @@ int of_populate_from_efi(struct device_node *root);
- EFI payload with CONFIG_EFI_STUB enabled.
*/ int dram_init_banksize_from_efi(void);
+/**
- efi_add_known_memory_from_efi() - Add known memory pages from the memory map
- of the EFI bootloader that booted U-Boot. This is only applicable when running
- U-Boot as an EFI payload with CONFIG_EFI_STUB enabled.
- */
+void efi_add_known_memory_from_efi(void);
#endif /* _EFI_STUB_H */ diff --git a/lib/efi/efi_info.c b/lib/efi/efi_info.c index f9743a3e7fad..ef4e646b082b 100644 --- a/lib/efi/efi_info.c +++ b/lib/efi/efi_info.c @@ -5,8 +5,9 @@
- Access to the EFI information table
*/
#include <efi.h> +#include <efi_loader.h> #include <efi_stub.h> #include <errno.h> #include <mapmem.h> #include <asm/global_data.h> @@ -177,4 +178,34 @@ int dram_init_banksize_from_efi(void) }
return 0;
}
+/* Called by U-Boot's EFI subsystem to add known memory. In our case
- we need to add some specific memory types from the original bootloaders
- EFI memory map
- */
+void efi_add_known_memory_from_efi(void) +{
struct efi_mem_desc *desc, *end;
struct efi_entry_memmap *map;
int ret, size;
EFI_PRINT("Adding known memory from previous stage EFI bootloader\n");
ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size);
if (ret) {
EFI_PRINT("%s: Missing memory map\n", __func__);
return;
}
end = (struct efi_mem_desc *)((ulong)map + size);
for (desc = map->desc; desc < end; desc = efi_get_next_mem_desc(desc, map->desc_size)) {
switch (desc->type) {
case EFI_RESERVED_MEMORY_TYPE:
efi_add_memory_map_pg(desc->physical_start, desc->num_pages, desc->type, false);
break;
default:
continue;
}
}
+}
If this is DRAM memory that is being added, this now needs to happen through LMB to ensure that these reserved memory regions don't get used by the LMB allocator. You can check if something can be added to the lmb_reserve_common() function. These regions will get marked as boot services data. If these are to be kept as reserved memory even in the OS, the memory type of these regions can be updated by keeping this function. But the point to consider is that this needs to be updated in the LMB memory map also.
Right I see. Thanks.
I'm not sure if this function is really necessary, I added it while trying to debug some EFI crash but the cause was something else.
In theory the DT reserved-memory regions should match the reserved regions from the EFI (I'm fairly sure this is the case for the X1E laptops anyways), and I suppose there's no risk of mapping these as normal memory anyway since we populate the dram banks from the same EFI memory map.
So probably I'll remove this function from the next revision.
Kind regards,
-sughosh
diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index d2f5d563f2a0..50b0010608e7 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -7,8 +7,9 @@
#define LOG_CATEGORY LOGC_EFI
#include <efi_loader.h>da +#include <efi_stub.h> #include <init.h> #include <lmb.h> #include <log.h> #include <malloc.h> @@ -834,8 +835,12 @@ static void add_u_boot_and_runtime(void) int efi_memory_init(void) { efi_add_known_memory();
+#ifdef CONFIG_EFI_STUB
efi_add_known_memory_from_efi();
+#endif
add_u_boot_and_runtime();
#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER /* Request a 32bit 64MB bounce buffer region */
-- 2.47.0

Retrieve the EFI info header passed in via x0 and use it to populate the memory banks when booting with CONFIG_EFI_STUB.
Signed-off-by: Caleb Connolly caleb.connolly@linaro.org --- arch/arm/mach-snapdragon/board.c | 15 +++++++++++++++ arch/arm/mach-snapdragon/dram.c | 15 ++++++++++++++- arch/arm/mach-snapdragon/qcom-priv.h | 2 ++ 3 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-snapdragon/board.c b/arch/arm/mach-snapdragon/board.c index dbac8aa2709a..f92b26c88d46 100644 --- a/arch/arm/mach-snapdragon/board.c +++ b/arch/arm/mach-snapdragon/board.c @@ -41,8 +41,10 @@ DECLARE_GLOBAL_DATA_PTR; static struct mm_region rbx_mem_map[CONFIG_NR_DRAM_BANKS + 2] = { { 0 } };
struct mm_region *mem_map = rbx_mem_map;
+struct efi_info_hdr *efi_info __section(".data") = NULL; + static void show_psci_version(void) { struct arm_smccc_res res;
@@ -59,15 +61,28 @@ static void show_psci_version(void) */ void *board_fdt_blob_setup(int *err) { struct fdt_header *fdt; + struct efi_info_hdr *info = NULL; bool internal_valid, external_valid;
*err = 0; fdt = (struct fdt_header *)get_prev_bl_fdt_addr(); external_valid = fdt && !fdt_check_header(fdt); internal_valid = !fdt_check_header(gd->fdt_blob);
+ /* + * If EFI_STUB is enabled, we got handed a pointer and it's NOT + * a valid FDT, then it might be the efi_info table! + */ + if (CONFIG_IS_ENABLED(EFI_STUB) && fdt && !external_valid) + info = (struct efi_info_hdr *)fdt; + + if (info->version == 1) { + debug("Got EFI info header!\n"); + efi_info = info; + } + /* * There is no point returning an error here, U-Boot can't do anything useful in this situation. * Bail out while we can still print a useful error message. */ diff --git a/arch/arm/mach-snapdragon/dram.c b/arch/arm/mach-snapdragon/dram.c index ef226e000858..0493653e432b 100644 --- a/arch/arm/mach-snapdragon/dram.c +++ b/arch/arm/mach-snapdragon/dram.c @@ -7,12 +7,15 @@ #define pr_fmt(fmt) "QCOM-DRAM: " fmt
#include <asm-generic/unaligned.h> #include <dm.h> +#include <efi_stub.h> #include <log.h> #include <sort.h> #include <soc/qcom/smem.h>
+#include "qcom-priv.h" + #define SMEM_USABLE_RAM_PARTITION_TABLE 402 #define RAM_PART_NAME_LENGTH 16 #define RAM_NUM_PART_ENTRIES 32 #define CATEGORY_SDRAM 0x0E @@ -89,9 +92,19 @@ static void qcom_configure_bi_dram(void) }
int dram_init_banksize(void) { - qcom_configure_bi_dram(); +#ifdef CONFIG_EFI_STUB + gd->arch.table = (phys_addr_t)efi_info; + /* We actually parsed a memory map from SMEM (and used it to + * set ram_base/ram_top), but it's better to respect the table + * from the EFI bootloader. + */ + if (efi_info) + dram_init_banksize_from_efi(); + else +#endif + qcom_configure_bi_dram();
return 0; }
diff --git a/arch/arm/mach-snapdragon/qcom-priv.h b/arch/arm/mach-snapdragon/qcom-priv.h index 690557463642..58b8cb497482 100644 --- a/arch/arm/mach-snapdragon/qcom-priv.h +++ b/arch/arm/mach-snapdragon/qcom-priv.h @@ -4,8 +4,10 @@ #define __QCOM_PRIV_H__
#include <stdbool.h>
+extern struct efi_info_hdr *efi_info; + #if IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) void qcom_configure_capsule_updates(void); #else void qcom_configure_capsule_updates(void) {}

Currently the early malloc initialisation is done partially in board_init_f_init_reserve() (on arm64 at least), which configures gd->malloc_base. But it isn't actually usable until initf_malloc() is called which doesn't happen until after fdtdec_setup().
This causes problems in a few scenarios:
1. when using MULTI_DTB_FIT as this needs a working malloc (especially for compressed FIT). 2. Some platforms may need to allocate memory as part of memory map initialisation (e.g. Qualcomm will need this to parse the memory map from SMEM).
Move the initf_malloc() call earlier so that malloc is available during fdtdec_setup().
Signed-off-by: Caleb Connolly caleb.connolly@linaro.org --- common/board_f.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/common/board_f.c b/common/board_f.c index 98dc2591e1d0..bddfa6b992b9 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -867,15 +867,15 @@ static int initf_upl(void) }
static const init_fnc_t init_sequence_f[] = { setup_mon_len, + initf_malloc, #ifdef CONFIG_OF_CONTROL fdtdec_setup, #endif #ifdef CONFIG_TRACE_EARLY trace_early_init, #endif - initf_malloc, initf_upl, log_init, initf_bootstage, /* uses its own timer, so does not need DM */ event_init,

From: Neil Armstrong neil.armstrong@linaro.org
Add Clock driver for the GCC block found in the X1E80100 SoC.
Signed-off-by: Neil Armstrong neil.armstrong@linaro.org --- drivers/clk/qcom/Kconfig | 8 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/clock-x1e80100.c | 348 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 357 insertions(+)
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index d76fca5dba41..c69eb7d11679 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -102,7 +102,15 @@ config CLK_QCOM_SC7280 Say Y here to enable support for the Global Clock Controller on the Snapdragon SC7280 SoC. This driver supports the clocks and resets exposed by the GCC hardware block.
+config CLK_QCOM_X1E80100 + bool "Qualcomm X1E80100 GCC" + select CLK_QCOM + help + Say Y here to enable support for the Global Clock Controller + on the Snapdragon X1E80100 SoC. This driver supports the clocks + and resets exposed by the GCC hardware block. + endmenu
endif diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index ab33f1c5faf9..0189e053f23c 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -14,4 +14,5 @@ obj-$(CONFIG_CLK_QCOM_SM6115) += clock-sm6115.o obj-$(CONFIG_CLK_QCOM_SM8150) += clock-sm8150.o obj-$(CONFIG_CLK_QCOM_SM8250) += clock-sm8250.o obj-$(CONFIG_CLK_QCOM_SM8550) += clock-sm8550.o obj-$(CONFIG_CLK_QCOM_SM8650) += clock-sm8650.o +obj-$(CONFIG_CLK_QCOM_X1E80100) += clock-x1e80100.o diff --git a/drivers/clk/qcom/clock-x1e80100.c b/drivers/clk/qcom/clock-x1e80100.c new file mode 100644 index 000000000000..6bcd705f6c8d --- /dev/null +++ b/drivers/clk/qcom/clock-x1e80100.c @@ -0,0 +1,348 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Clock drivers for Qualcomm x1e80100 + * + * (C) Copyright 2024 Linaro Ltd. + */ + +#include <clk-uclass.h> +#include <dm.h> +#include <linux/delay.h> +#include <errno.h> +#include <asm/io.h> +#include <linux/bug.h> +#include <linux/bitops.h> +#include <dt-bindings/clock/qcom,x1e80100-gcc.h> +#include <dt-bindings/clock/qcom,x1e80100-tcsr.h> + +#include "clock-qcom.h" + +/* On-board TCXO, TOFIX get from DT */ +#define TCXO_RATE 38400000 + +/* bi_tcxo_div2 divided after RPMh output */ +#define TCXO_DIV2_RATE (TCXO_RATE / 2) + +static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s4_clk_src[] = { + F(7372800, CFG_CLK_SRC_GPLL0_EVEN, 1, 384, 15625), + F(14745600, CFG_CLK_SRC_GPLL0_EVEN, 1, 768, 15625), + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + F(29491200, CFG_CLK_SRC_GPLL0_EVEN, 1, 1536, 15625), + F(32000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 75), + F(48000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 25), + F(64000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 16, 75), + F(75000000, CFG_CLK_SRC_GPLL0_EVEN, 4, 0, 0), + F(80000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 15), + F(96000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 25), + F(100000000, CFG_CLK_SRC_GPLL0, 6, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { + F(400000, CFG_CLK_SRC_CXO, 12, 1, 4), + F(25000000, CFG_CLK_SRC_GPLL0_EVEN, 12, 0, 0), + F(100000000, CFG_CLK_SRC_GPLL0_EVEN, 3, 0, 0), + /* TOFIX F(202000000, CFG_CLK_SRC_GPLL9, 4, 0, 0), */ + { } +}; + +static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = { + F(66666667, CFG_CLK_SRC_GPLL0_EVEN, 4.5, 0, 0), + F(133333333, CFG_CLK_SRC_GPLL0, 4.5, 0, 0), + F(200000000, CFG_CLK_SRC_GPLL0, 3, 0, 0), + F(240000000, CFG_CLK_SRC_GPLL0, 2.5, 0, 0), + { } +}; + +static ulong x1e80100_set_rate(struct clk *clk, ulong rate) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + const struct freq_tbl *freq; + + switch (clk->id) { + case GCC_QUPV3_WRAP2_S5_CLK: /* UART21 */ + freq = qcom_find_freq(ftbl_gcc_qupv3_wrap0_s4_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, 0x1e500, + freq->pre_div, freq->m, freq->n, freq->src, 16); + return freq->freq; + case GCC_SDCC2_APPS_CLK: + freq = qcom_find_freq(ftbl_gcc_sdcc2_apps_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, 0x14018, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_USB30_PRIM_MASTER_CLK: + freq = qcom_find_freq(ftbl_gcc_usb30_prim_master_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, 0x3902c, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_USB30_PRIM_MOCK_UTMI_CLK: + clk_rcg_set_rate(priv->base, 0x39044, 0, 0); + return TCXO_DIV2_RATE; + default: + return 0; + } +} + +static const struct gate_clk x1e80100_clks[] = { + GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x770e4, BIT(0)), + GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0x3908c, BIT(0)), + GATE_CLK(GCC_QUPV3_WRAP2_CORE_2X_CLK, 0x52010, BIT(3)), + GATE_CLK(GCC_QUPV3_WRAP2_CORE_CLK, 0x52010, BIT(0)), + GATE_CLK(GCC_QUPV3_WRAP2_S0_CLK, 0x52010, BIT(4)), + GATE_CLK(GCC_QUPV3_WRAP2_S1_CLK, 0x52010, BIT(5)), + GATE_CLK(GCC_QUPV3_WRAP2_S2_CLK, 0x52010, BIT(6)), + GATE_CLK(GCC_QUPV3_WRAP2_S3_CLK, 0x52010, BIT(7)), + GATE_CLK(GCC_QUPV3_WRAP2_S4_CLK, 0x52010, BIT(8)), + GATE_CLK(GCC_QUPV3_WRAP2_S5_CLK, 0x52010, BIT(9)), + GATE_CLK(GCC_QUPV3_WRAP2_S6_CLK, 0x52010, BIT(10)), + GATE_CLK(GCC_QUPV3_WRAP2_S7_CLK, 0x52010, BIT(17)), + GATE_CLK(GCC_QUPV3_WRAP_2_M_AHB_CLK, 0x52010, BIT(2)), + GATE_CLK(GCC_QUPV3_WRAP_2_S_AHB_CLK, 0x52010, BIT(1)), + GATE_CLK(GCC_USB30_PRIM_MASTER_CLK, 0x39018, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0x39028, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_SLEEP_CLK, 0x39024, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_PHY_AUX_CLK, 0x39060, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0x39064, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_PHY_PIPE_CLK, 0x39068, BIT(0)), +}; + +static int x1e80100_enable(struct clk *clk) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + switch (clk->id) { + case GCC_AGGRE_USB3_PRIM_AXI_CLK: + qcom_gate_clk_en(priv, GCC_USB30_PRIM_MASTER_CLK); + fallthrough; + case GCC_USB30_PRIM_MASTER_CLK: + qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_AUX_CLK); + qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_COM_AUX_CLK); + break; + } + + qcom_gate_clk_en(priv, clk->id); + + return 0; +} + +static const struct qcom_reset_map x1e80100_gcc_resets[] = { + [GCC_AV1E_BCR] = { 0x4a000 }, + [GCC_CAMERA_BCR] = { 0x26000 }, + [GCC_DISPLAY_BCR] = { 0x27000 }, + [GCC_GPU_BCR] = { 0x71000 }, + [GCC_PCIE_0_LINK_DOWN_BCR] = { 0x6c014 }, + [GCC_PCIE_0_NOCSR_COM_PHY_BCR] = { 0x6c020 }, + [GCC_PCIE_0_PHY_BCR] = { 0x6c01c }, + [GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR] = { 0x6c028 }, + [GCC_PCIE_0_TUNNEL_BCR] = { 0xa0000 }, + [GCC_PCIE_1_LINK_DOWN_BCR] = { 0x8e014 }, + [GCC_PCIE_1_NOCSR_COM_PHY_BCR] = { 0x8e020 }, + [GCC_PCIE_1_PHY_BCR] = { 0x8e01c }, + [GCC_PCIE_1_PHY_NOCSR_COM_PHY_BCR] = { 0x8e024 }, + [GCC_PCIE_1_TUNNEL_BCR] = { 0x2c000 }, + [GCC_PCIE_2_LINK_DOWN_BCR] = { 0xa5014 }, + [GCC_PCIE_2_NOCSR_COM_PHY_BCR] = { 0xa5020 }, + [GCC_PCIE_2_PHY_BCR] = { 0xa501c }, + [GCC_PCIE_2_PHY_NOCSR_COM_PHY_BCR] = { 0xa5028 }, + [GCC_PCIE_2_TUNNEL_BCR] = { 0x13000 }, + [GCC_PCIE_3_BCR] = { 0x58000 }, + [GCC_PCIE_3_LINK_DOWN_BCR] = { 0xab014 }, + [GCC_PCIE_3_NOCSR_COM_PHY_BCR] = { 0xab020 }, + [GCC_PCIE_3_PHY_BCR] = { 0xab01c }, + [GCC_PCIE_3_PHY_NOCSR_COM_PHY_BCR] = { 0xab024 }, + [GCC_PCIE_4_BCR] = { 0x6b000 }, + [GCC_PCIE_4_LINK_DOWN_BCR] = { 0xb3014 }, + [GCC_PCIE_4_NOCSR_COM_PHY_BCR] = { 0xb3020 }, + [GCC_PCIE_4_PHY_BCR] = { 0xb301c }, + [GCC_PCIE_4_PHY_NOCSR_COM_PHY_BCR] = { 0xb3028 }, + [GCC_PCIE_5_BCR] = { 0x2f000 }, + [GCC_PCIE_5_LINK_DOWN_BCR] = { 0xaa014 }, + [GCC_PCIE_5_NOCSR_COM_PHY_BCR] = { 0xaa020 }, + [GCC_PCIE_5_PHY_BCR] = { 0xaa01c }, + [GCC_PCIE_5_PHY_NOCSR_COM_PHY_BCR] = { 0xaa028 }, + [GCC_PCIE_6A_BCR] = { 0x31000 }, + [GCC_PCIE_6A_LINK_DOWN_BCR] = { 0xac014 }, + [GCC_PCIE_6A_NOCSR_COM_PHY_BCR] = { 0xac020 }, + [GCC_PCIE_6A_PHY_BCR] = { 0xac01c }, + [GCC_PCIE_6A_PHY_NOCSR_COM_PHY_BCR] = { 0xac024 }, + [GCC_PCIE_6B_BCR] = { 0x8d000 }, + [GCC_PCIE_6B_LINK_DOWN_BCR] = { 0xb5014 }, + [GCC_PCIE_6B_NOCSR_COM_PHY_BCR] = { 0xb5020 }, + [GCC_PCIE_6B_PHY_BCR] = { 0xb501c }, + [GCC_PCIE_6B_PHY_NOCSR_COM_PHY_BCR] = { 0xb5024 }, + [GCC_PCIE_PHY_BCR] = { 0x6f000 }, + [GCC_PCIE_PHY_CFG_AHB_BCR] = { 0x6f00c }, + [GCC_PCIE_PHY_COM_BCR] = { 0x6f010 }, + [GCC_PCIE_RSCC_BCR] = { 0xa4000 }, + [GCC_PDM_BCR] = { 0x33000 }, + [GCC_QUPV3_WRAPPER_0_BCR] = { 0x42000 }, + [GCC_QUPV3_WRAPPER_1_BCR] = { 0x18000 }, + [GCC_QUPV3_WRAPPER_2_BCR] = { 0x1e000 }, + [GCC_QUSB2PHY_HS0_MP_BCR] = { 0x1200c }, + [GCC_QUSB2PHY_HS1_MP_BCR] = { 0x12010 }, + [GCC_QUSB2PHY_PRIM_BCR] = { 0x12000 }, + [GCC_QUSB2PHY_SEC_BCR] = { 0x12004 }, + [GCC_QUSB2PHY_TERT_BCR] = { 0x12008 }, + [GCC_QUSB2PHY_USB20_HS_BCR] = { 0x12014 }, + [GCC_SDCC2_BCR] = { 0x14000 }, + [GCC_SDCC4_BCR] = { 0x16000 }, + [GCC_UFS_PHY_BCR] = { 0x77000 }, + [GCC_USB20_PRIM_BCR] = { 0x29000 }, + [GCC_USB30_MP_BCR] = { 0x17000 }, + [GCC_USB30_PRIM_BCR] = { 0x39000 }, + [GCC_USB30_SEC_BCR] = { 0xa1000 }, + [GCC_USB30_TERT_BCR] = { 0xa2000 }, + [GCC_USB3_MP_SS0_PHY_BCR] = { 0x19008 }, + [GCC_USB3_MP_SS1_PHY_BCR] = { 0x54008 }, + [GCC_USB3_PHY_PRIM_BCR] = { 0x50000 }, + [GCC_USB3_PHY_SEC_BCR] = { 0x2a000 }, + [GCC_USB3_PHY_TERT_BCR] = { 0xa3000 }, + [GCC_USB3_UNIPHY_MP0_BCR] = { 0x19000 }, + [GCC_USB3_UNIPHY_MP1_BCR] = { 0x54000 }, + [GCC_USB3PHY_PHY_PRIM_BCR] = { 0x50004 }, + [GCC_USB3PHY_PHY_SEC_BCR] = { 0x2a004 }, + [GCC_USB3PHY_PHY_TERT_BCR] = { 0xa3004 }, + [GCC_USB3UNIPHY_PHY_MP0_BCR] = { 0x19004 }, + [GCC_USB3UNIPHY_PHY_MP1_BCR] = { 0x54004 }, + [GCC_USB4_0_BCR] = { 0x9f000 }, + [GCC_USB4_0_DP0_PHY_PRIM_BCR] = { 0x50010 }, + [GCC_USB4_1_DP0_PHY_SEC_BCR] = { 0x2a010 }, + [GCC_USB4_2_DP0_PHY_TERT_BCR] = { 0xa3010 }, + [GCC_USB4_1_BCR] = { 0x2b000 }, + [GCC_USB4_2_BCR] = { 0x11000 }, + [GCC_USB_0_PHY_BCR] = { 0x50020 }, + [GCC_USB_1_PHY_BCR] = { 0x2a020 }, + [GCC_USB_2_PHY_BCR] = { 0xa3020 }, + [GCC_VIDEO_BCR] = { 0x32000 }, +}; + +static const struct qcom_power_map x1e80100_gdscs[] = { + [GCC_PCIE_0_TUNNEL_GDSC] = { 0xa0004 }, + [GCC_PCIE_1_TUNNEL_GDSC] = { 0x2c004 }, + [GCC_PCIE_2_TUNNEL_GDSC] = { 0x13004 }, + [GCC_PCIE_3_GDSC] = { 0x58004 }, + [GCC_PCIE_3_PHY_GDSC] = { 0x3e000 }, + [GCC_PCIE_4_GDSC] = { 0x6b004 }, + [GCC_PCIE_4_PHY_GDSC] = { 0x6c000 }, + [GCC_PCIE_5_GDSC] = { 0x2f004 }, + [GCC_PCIE_5_PHY_GDSC] = { 0x30000 }, + [GCC_PCIE_6_PHY_GDSC] = { 0x8e000 }, + [GCC_PCIE_6A_GDSC] = { 0x31004 }, + [GCC_PCIE_6B_GDSC] = { 0x8d004 }, + [GCC_UFS_MEM_PHY_GDSC] = { 0x9e000 }, + [GCC_UFS_PHY_GDSC] = { 0x77004 }, + [GCC_USB20_PRIM_GDSC] = { 0x29004 }, + [GCC_USB30_MP_GDSC] = { 0x17004 }, + [GCC_USB30_PRIM_GDSC] = { 0x39004 }, + [GCC_USB30_SEC_GDSC] = { 0xa1004 }, + [GCC_USB30_TERT_GDSC] = { 0xa2004 }, + [GCC_USB3_MP_SS0_PHY_GDSC] = { 0x1900c }, + [GCC_USB3_MP_SS1_PHY_GDSC] = { 0x5400c }, + [GCC_USB4_0_GDSC] = { 0x9f004 }, + [GCC_USB4_1_GDSC] = { 0x2b004 }, + [GCC_USB4_2_GDSC] = { 0x11004 }, + [GCC_USB_0_PHY_GDSC] = { 0x50024 }, + [GCC_USB_1_PHY_GDSC] = { 0x2a024 }, + [GCC_USB_2_PHY_GDSC] = { 0xa3024 }, +}; + +static struct msm_clk_data x1e80100_gcc_data = { + .resets = x1e80100_gcc_resets, + .num_resets = ARRAY_SIZE(x1e80100_gcc_resets), + .clks = x1e80100_clks, + .num_clks = ARRAY_SIZE(x1e80100_clks), + .power_domains = x1e80100_gdscs, + .num_power_domains = ARRAY_SIZE(x1e80100_gdscs), + + .enable = x1e80100_enable, + .set_rate = x1e80100_set_rate, +}; + +static const struct udevice_id gcc_x1e80100_of_match[] = { + { + .compatible = "qcom,x1e80100-gcc", + .data = (ulong)&x1e80100_gcc_data, + }, + { } +}; + +U_BOOT_DRIVER(gcc_x1e80100) = { + .name = "gcc_x1e80100", + .id = UCLASS_NOP, + .of_match = gcc_x1e80100_of_match, + .bind = qcom_cc_bind, + .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF, +}; + +/* TCSRCC */ + +static const struct gate_clk x1e80100_tcsr_clks[] = { + GATE_CLK(TCSR_PCIE_2L_4_CLKREF_EN, 0x15100, BIT(0)), + GATE_CLK(TCSR_PCIE_2L_5_CLKREF_EN, 0x15104, BIT(0)), + GATE_CLK(TCSR_PCIE_8L_CLKREF_EN, 0x15108, BIT(0)), + GATE_CLK(TCSR_USB3_MP0_CLKREF_EN, 0x1510c, BIT(0)), + GATE_CLK(TCSR_USB3_MP1_CLKREF_EN, 0x15110, BIT(0)), + GATE_CLK(TCSR_USB2_1_CLKREF_EN, 0x15114, BIT(0)), + GATE_CLK(TCSR_UFS_PHY_CLKREF_EN, 0x15118, BIT(0)), + GATE_CLK(TCSR_USB4_1_CLKREF_EN, 0x15120, BIT(0)), + GATE_CLK(TCSR_USB4_2_CLKREF_EN, 0x15124, BIT(0)), + GATE_CLK(TCSR_USB2_2_CLKREF_EN, 0x15128, BIT(0)), + GATE_CLK(TCSR_PCIE_4L_CLKREF_EN, 0x1512c, BIT(0)), + GATE_CLK(TCSR_EDP_CLKREF_EN, 0x15130, BIT(0)), +}; + +static struct msm_clk_data x1e80100_tcsrcc_data = { + .clks = x1e80100_tcsr_clks, + .num_clks = ARRAY_SIZE(x1e80100_tcsr_clks), +}; + +static int tcsrcc_x1e80100_clk_enable(struct clk *clk) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + qcom_gate_clk_en(priv, clk->id); + + return 0; +} + +static ulong tcsrcc_x1e80100_clk_get_rate(struct clk *clk) +{ + return TCXO_RATE; +} + +static int tcsrcc_x1e80100_clk_probe(struct udevice *dev) +{ + struct msm_clk_data *data = (struct msm_clk_data *)dev_get_driver_data(dev); + struct msm_clk_priv *priv = dev_get_priv(dev); + + priv->base = dev_read_addr(dev); + if (priv->base == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->data = data; + + return 0; +} + +static struct clk_ops tcsrcc_x1e80100_clk_ops = { + .enable = tcsrcc_x1e80100_clk_enable, + .get_rate = tcsrcc_x1e80100_clk_get_rate, +}; + +static const struct udevice_id tcsrcc_x1e80100_of_match[] = { + { + .compatible = "qcom,x1e80100-tcsr", + .data = (ulong)&x1e80100_tcsrcc_data, + }, + { } +}; + +U_BOOT_DRIVER(tcsrcc_x1e80100) = { + .name = "tcsrcc_x1e80100", + .id = UCLASS_CLK, + .of_match = tcsrcc_x1e80100_of_match, + .ops = &tcsrcc_x1e80100_clk_ops, + .priv_auto = sizeof(struct msm_clk_priv), + .probe = tcsrcc_x1e80100_clk_probe, + .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF, +};

From: Neil Armstrong neil.armstrong@linaro.org
Enable the X1E80100 clock driver in the Qualcomm defconfig.
Signed-off-by: Neil Armstrong neil.armstrong@linaro.org --- configs/qcom_defconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/configs/qcom_defconfig b/configs/qcom_defconfig index b49d897123c1..8e9cb3cddaa3 100644 --- a/configs/qcom_defconfig +++ b/configs/qcom_defconfig @@ -53,8 +53,9 @@ CONFIG_CLK_QCOM_SM6115=y CONFIG_CLK_QCOM_SM8150=y CONFIG_CLK_QCOM_SM8250=y CONFIG_CLK_QCOM_SM8550=y CONFIG_CLK_QCOM_SM8650=y +CONFIG_CLK_QCOM_X1E80100=y CONFIG_CLK_QCOM_SC7280=y CONFIG_DFU_MMC=y CONFIG_DFU_SCSI=y CONFIG_SYS_DFU_DATA_BUF_SIZE=0x200000

From: Neil Armstrong neil.armstrong@linaro.org
Add pinctrl driver for the TLMM block found in the X1E80100 SoC.
Signed-off-by: Neil Armstrong neil.armstrong@linaro.org --- drivers/pinctrl/qcom/Kconfig | 7 +++ drivers/pinctrl/qcom/Makefile | 1 + drivers/pinctrl/qcom/pinctrl-x1e80100.c | 100 ++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+)
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index 4f93a34281d5..d3eb69985510 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -82,7 +82,14 @@ config PINCTRL_QCOM_SM8650 help Say Y here to enable support for pinctrl on the Snapdragon SM8650 SoC, as well as the associated GPIO driver.
+config PINCTRL_QCOM_X1E80100 + bool "Qualcomm X1E80100 GCC" + select PINCTRL_QCOM + help + Say Y here to enable support for pinctrl on the Snapdragon X1E80100 SoC, + as well as the associated GPIO driver. + endmenu
endif diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index 43d0dd292225..06d3c95f93a6 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -13,4 +13,5 @@ obj-$(CONFIG_PINCTRL_QCOM_SM6115) += pinctrl-sm6115.o obj-$(CONFIG_PINCTRL_QCOM_SM8150) += pinctrl-sm8150.o obj-$(CONFIG_PINCTRL_QCOM_SM8250) += pinctrl-sm8250.o obj-$(CONFIG_PINCTRL_QCOM_SM8550) += pinctrl-sm8550.o obj-$(CONFIG_PINCTRL_QCOM_SM8650) += pinctrl-sm8650.o +obj-$(CONFIG_PINCTRL_QCOM_X1E80100) += pinctrl-x1e80100.o diff --git a/drivers/pinctrl/qcom/pinctrl-x1e80100.c b/drivers/pinctrl/qcom/pinctrl-x1e80100.c new file mode 100644 index 000000000000..2e2f5093272c --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-x1e80100.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Qualcomm x1e80100 pinctrl + * + * (C) Copyright 2024 Linaro Ltd. + * + */ + +#include <dm.h> + +#include "pinctrl-qcom.h" + +#define MAX_PIN_NAME_LEN 32 +static char pin_name[MAX_PIN_NAME_LEN] __section(".data"); + +static const struct pinctrl_function msm_pinctrl_functions[] = { + {"qup2_se5", 1}, + {"gpio", 0}, +}; + +#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \ + { \ + .name = pg_name, \ + .ctl_reg = ctl, \ + .io_reg = 0, \ + .pull_bit = pull, \ + .drv_bit = drv, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = -1, \ + } + +#define UFS_RESET(pg_name, ctl) \ + { \ + .name = pg_name, \ + .ctl_reg = ctl, \ + .io_reg = ctl + 0x4, \ + .pull_bit = 3, \ + .drv_bit = 0, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = 0, \ + } + +static const struct msm_special_pin_data msm_special_pins_data[] = { + [0] = UFS_RESET("ufs_reset", 0xf9000), + [1] = SDC_QDSD_PINGROUP("sdc2_clk", 0xf2000, 14, 6), + [2] = SDC_QDSD_PINGROUP("sdc2_cmd", 0xf2000, 11, 3), + [3] = SDC_QDSD_PINGROUP("sdc2_data", 0xf2000, 9, 0), +}; + +static const char *x1e80100_get_function_name(struct udevice *dev, + unsigned int selector) +{ + return msm_pinctrl_functions[selector].name; +} + +static const char *x1e80100_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + if (selector >= 238 && selector <= 241) + snprintf(pin_name, MAX_PIN_NAME_LEN, + msm_special_pins_data[selector - 238].name); + else + snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); + + return pin_name; +} + +static unsigned int x1e80100_get_function_mux(__maybe_unused unsigned int pin, + unsigned int selector) +{ + return msm_pinctrl_functions[selector].val; +} + +static struct msm_pinctrl_data x1e80100_data = { + .pin_data = { + .pin_count = 242, + .special_pins_start = 238, + .special_pins_data = msm_special_pins_data, + }, + .functions_count = ARRAY_SIZE(msm_pinctrl_functions), + .get_function_name = x1e80100_get_function_name, + .get_function_mux = x1e80100_get_function_mux, + .get_pin_name = x1e80100_get_pin_name, +}; + +static const struct udevice_id msm_pinctrl_ids[] = { + { .compatible = "qcom,x1e80100-tlmm", .data = (ulong)&x1e80100_data }, + { /* Sentinel */ } +}; + +U_BOOT_DRIVER(pinctrl_x1e80100) = { + .name = "pinctrl_x1e80100", + .id = UCLASS_NOP, + .of_match = msm_pinctrl_ids, + .ops = &msm_pinctrl_ops, + .bind = msm_pinctrl_bind, +}; +

On 11/24/24 23:27, Caleb Connolly via groups.io wrote:
From: Neil Armstrong neil.armstrong@linaro.org
Add pinctrl driver for the TLMM block found in the X1E80100 SoC.
Signed-off-by: Neil Armstrong neil.armstrong@linaro.org
+config PINCTRL_QCOM_X1E80100
- bool "Qualcomm X1E80100 GCC"
That's not GCC though. Pin controllers on qcom SoCs are called TLMM (Top Level Mode Multiplexer). GCC is for Global Clock Controller.
- select PINCTRL_QCOM
- help
Say Y here to enable support for pinctrl on the Snapdragon X1E80100 SoC,
as well as the associated GPIO driver.
-- Regards, Alexey

From: Neil Armstrong neil.armstrong@linaro.org
Enable the X1E80100 pinctrl driver in the Qualcomm defconfig.
Signed-off-by: Neil Armstrong neil.armstrong@linaro.org --- configs/qcom_defconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/configs/qcom_defconfig b/configs/qcom_defconfig index 8e9cb3cddaa3..877c48b5684c 100644 --- a/configs/qcom_defconfig +++ b/configs/qcom_defconfig @@ -99,8 +99,9 @@ CONFIG_PINCTRL_QCOM_SM6115=y CONFIG_PINCTRL_QCOM_SM8150=y CONFIG_PINCTRL_QCOM_SM8250=y CONFIG_PINCTRL_QCOM_SM8550=y CONFIG_PINCTRL_QCOM_SM8650=y +CONFIG_PINCTRL_QCOM_X1E80100=y CONFIG_DM_PMIC=y CONFIG_PMIC_QCOM=y CONFIG_DM_REGULATOR=y CONFIG_DM_REGULATOR_FIXED=y

Add a defconfig for Qualcomm X1 Elite based devices. These boot U-Boot using EFISTUB from their stock EFI bootloader.
Initially we support display and USB, keyboard will require i2c-hid, NVME will require PCIe support.
Signed-off-by: Caleb Connolly caleb.connolly@linaro.org --- board/qualcomm/efistub.env | 11 +++++++++++ configs/x1e_defconfig | 17 +++++++++++++++++ 2 files changed, 28 insertions(+)
diff --git a/board/qualcomm/efistub.env b/board/qualcomm/efistub.env new file mode 100644 index 000000000000..5264603556ad --- /dev/null +++ b/board/qualcomm/efistub.env @@ -0,0 +1,11 @@ +stdin=serial,button-kbd +stdout=serial,vidconsole +stderr=serial,vidconsole +preboot=usb start; pci enum; nvme scan; +fastboot=fastboot -l $fastboot_addr_r usb 0 +do_boot=bootefi bootmgr +bootmenu_0=Boot first available device=run do_boot +bootmenu_1=Enable fastboot mode=run fastboot +bootmenu_2=Reset device=reset +menucmd=bootmenu +bootcmd=run do_boot diff --git a/configs/x1e_defconfig b/configs/x1e_defconfig new file mode 100644 index 000000000000..d60210f2ca5b --- /dev/null +++ b/configs/x1e_defconfig @@ -0,0 +1,17 @@ +#include "qcom_defconfig" + +# Broken?? Probably an issue with mapping the memory +CONFIG_QCOM_COMMAND_DB=n + +CONFIG_EFI=y +CONFIG_EFI_STUB=y +CONFIG_EFI_STUB_64BIT=y + +CONFIG_DEBUG_UART=y +CONFIG_DEBUG_UART_ANNOUNCE=y +CONFIG_DEBUG_UART_BASE=0x894000 +CONFIG_DEBUG_UART_MSM_GENI=y +CONFIG_DEBUG_UART_CLOCK=14745600 + +CONFIG_DEFAULT_ENV_FILE="board/qualcomm/efistub.env" +CONFIG_DEFAULT_DEVICE_TREE="qcom/x1e80100-crd"
participants (4)
-
Alexey Minnekhanov
-
Caleb Connolly
-
Ilias Apalodimas
-
Sughosh Ganu