]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
efi: Support EDID information
authorThomas Zimmermann <tzimmermann@suse.de>
Wed, 26 Nov 2025 16:03:25 +0000 (17:03 +0100)
committerArd Biesheuvel <ardb@kernel.org>
Tue, 16 Dec 2025 13:40:51 +0000 (14:40 +0100)
In the EFI config table, rename LINUX_EFI_SCREEN_INFO_TABLE_GUID to
LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID. Read sysfb_primary_display from
the entry. In addition to the screen_info, the entry now also contains
EDID information.

In libstub, replace struct screen_info with struct sysfb_display_info
from the kernel's sysfb_primary_display and rename functions
accordingly.  Transfer it to the runtime kernel using the kernel's
global state or the LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID config-table
entry.

With CONFIG_FIRMWARE_EDID=y, libstub now transfers the GOP device's EDID
information to the kernel. If CONFIG_FIRMWARE_EDID=n, EDID information
is disabled. Make the Kconfig symbol CONFIG_FIRMWARE_EDID available with
EFI. Setting the value to 'n' disables EDID support.

Also rename screen_info.c to primary_display.c and adapt the contained
comment according to the changes.

Link: https://lore.kernel.org/all/20251126160854.553077-8-tzimmermann@suse.de/
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
[ardb: depend on EFI_GENERIC_STUB not EFI, fix conflicts after dropping
       the preceding patch from the series]
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
12 files changed:
arch/loongarch/kernel/efi.c
drivers/firmware/efi/efi-init.c
drivers/firmware/efi/efi.c
drivers/firmware/efi/libstub/Makefile
drivers/firmware/efi/libstub/efi-stub-entry.c
drivers/firmware/efi/libstub/efi-stub.c
drivers/firmware/efi/libstub/efistub.h
drivers/firmware/efi/libstub/primary_display.c [new file with mode: 0644]
drivers/firmware/efi/libstub/screen_info.c [deleted file]
drivers/firmware/efi/libstub/zboot.c
drivers/video/Kconfig
include/linux/efi.h

index 95fb535daf1cd73a2cff99350222c52167e302d6..69dd83f8082fba00a6b58b40278f9e05d0d77435 100644 (file)
@@ -72,7 +72,7 @@ bool efi_poweroff_required(void)
                (acpi_gbl_reduced_hardware || acpi_no_s5);
 }
 
-unsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR;
+unsigned long __initdata primary_display_table = EFI_INVALID_TABLE_ADDR;
 
 #if defined(CONFIG_SYSFB) || defined(CONFIG_EFI_EARLYCON)
 struct sysfb_display_info sysfb_primary_display __section(".data");
@@ -81,19 +81,19 @@ EXPORT_SYMBOL_GPL(sysfb_primary_display);
 
 static void __init init_primary_display(void)
 {
-       struct screen_info *si;
+       struct sysfb_display_info *dpy;
 
-       if (screen_info_table == EFI_INVALID_TABLE_ADDR)
+       if (primary_display_table == EFI_INVALID_TABLE_ADDR)
                return;
 
-       si = early_memremap(screen_info_table, sizeof(*si));
-       if (!si) {
-               pr_err("Could not map screen_info config table\n");
+       dpy = early_memremap(primary_display_table, sizeof(*dpy));
+       if (!dpy) {
+               pr_err("Could not map primary_display config table\n");
                return;
        }
-       sysfb_primary_display.screen = *si;
-       memset(si, 0, sizeof(*si));
-       early_memunmap(si, sizeof(*si));
+       sysfb_primary_display = *dpy;
+       memset(dpy, 0, sizeof(*dpy));
+       early_memunmap(dpy, sizeof(*dpy));
 
        memblock_reserve(__screen_info_lfb_base(&sysfb_primary_display.screen),
                         sysfb_primary_display.screen.lfb_size);
index d1d418a34407721c166c0ab2656dba57442eb53d..432301dce76f460df34f89a5824048544d825736 100644 (file)
@@ -23,7 +23,7 @@
 
 #include <asm/efi.h>
 
-unsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR;
+unsigned long __initdata primary_display_table = EFI_INVALID_TABLE_ADDR;
 
 static int __init is_memory(efi_memory_desc_t *md)
 {
@@ -67,17 +67,17 @@ EXPORT_SYMBOL_GPL(sysfb_primary_display);
 
 static void __init init_primary_display(void)
 {
-       struct screen_info *si;
+       struct sysfb_display_info *dpy;
 
-       if (screen_info_table != EFI_INVALID_TABLE_ADDR) {
-               si = early_memremap(screen_info_table, sizeof(*si));
-               if (!si) {
-                       pr_err("Could not map screen_info config table\n");
+       if (primary_display_table != EFI_INVALID_TABLE_ADDR) {
+               dpy = early_memremap(primary_display_table, sizeof(*dpy));
+               if (!dpy) {
+                       pr_err("Could not map primary_display config table\n");
                        return;
                }
-               sysfb_primary_display.screen = *si;
-               memset(si, 0, sizeof(*si));
-               early_memunmap(si, sizeof(*si));
+               sysfb_primary_display = *dpy;
+               memset(dpy, 0, sizeof(*dpy));
+               early_memunmap(dpy, sizeof(*dpy));
 
                if (memblock_is_map_memory(sysfb_primary_display.screen.lfb_base))
                        memblock_mark_nomap(sysfb_primary_display.screen.lfb_base,
index a9070d00b833f70461c86eee0872ca5c55d7c33a..955193691f103a27b4a7cfd216aeb8c99692c248 100644 (file)
@@ -63,7 +63,7 @@ static unsigned long __initdata mem_reserve = EFI_INVALID_TABLE_ADDR;
 static unsigned long __initdata rt_prop = EFI_INVALID_TABLE_ADDR;
 static unsigned long __initdata initrd = EFI_INVALID_TABLE_ADDR;
 
-extern unsigned long screen_info_table;
+extern unsigned long primary_display_table;
 
 struct mm_struct efi_mm = {
        .mm_mt                  = MTREE_INIT_EXT(mm_mt, MM_MT_FLAGS, efi_mm.mmap_lock),
@@ -641,7 +641,7 @@ static const efi_config_table_type_t common_tables[] __initconst = {
        {LINUX_EFI_UNACCEPTED_MEM_TABLE_GUID,   &efi.unaccepted,        "Unaccepted"    },
 #endif
 #ifdef CONFIG_EFI_GENERIC_STUB
-       {LINUX_EFI_SCREEN_INFO_TABLE_GUID,      &screen_info_table                      },
+       {LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID,  &primary_display_table                  },
 #endif
        {},
 };
index 7d15a85d579fac9666bed6cf74c1573cd4c3769c..e386ffd009b7ef6a94ea398285915f38caf2bbe5 100644 (file)
@@ -80,7 +80,7 @@ $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
        $(call if_changed_rule,cc_o_c)
 
 lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o string.o intrinsics.o systable.o \
-                                  screen_info.o efi-stub-entry.o
+                                  primary_display.o efi-stub-entry.o
 
 lib-$(CONFIG_ARM)              += arm32-stub.o
 lib-$(CONFIG_ARM64)            += kaslr.o arm64.o arm64-stub.o smbios.o
index 401ecbbdf3317e7994bf6f9fabefe28a7f3844d2..aa85e910fe595efac21ccbd4a216f015315e8ab2 100644 (file)
@@ -14,18 +14,15 @@ static void *kernel_image_addr(void *addr)
        return addr + kernel_image_offset;
 }
 
-struct screen_info *alloc_screen_info(void)
+struct sysfb_display_info *alloc_primary_display(void)
 {
        if (IS_ENABLED(CONFIG_ARM))
-               return __alloc_screen_info();
+               return __alloc_primary_display();
 
        if (IS_ENABLED(CONFIG_X86) ||
            IS_ENABLED(CONFIG_EFI_EARLYCON) ||
-           IS_ENABLED(CONFIG_SYSFB)) {
-               struct sysfb_display_info *dpy = kernel_image_addr(&sysfb_primary_display);
-
-               return &dpy->screen;
-       }
+           IS_ENABLED(CONFIG_SYSFB))
+               return kernel_image_addr(&sysfb_primary_display);
 
        return NULL;
 }
index 9cb814c5ba1bd71bda99f1ec3c5b2bf0eeb2a571..42d6073bcd062a0598dc27fa30d107cf02e30dcb 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 #include <linux/efi.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
 #include <asm/efi.h>
 
 #include "efistub.h"
 static u64 virtmap_base = EFI_RT_VIRTUAL_BASE;
 static bool flat_va_mapping = (EFI_RT_VIRTUAL_OFFSET != 0);
 
-void __weak free_screen_info(struct screen_info *si)
-{
-}
+void __weak free_primary_display(struct sysfb_display_info *dpy)
+{ }
 
-static struct screen_info *setup_graphics(void)
+static struct sysfb_display_info *setup_primary_display(void)
 {
-       struct screen_info *si, tmp = {};
+       struct sysfb_display_info *dpy;
+       struct screen_info *screen = NULL;
+       struct edid_info *edid = NULL;
+       efi_status_t status;
 
-       if (efi_setup_graphics(&tmp, NULL) != EFI_SUCCESS)
+       dpy = alloc_primary_display();
+       if (!dpy)
                return NULL;
+       screen = &dpy->screen;
+#if defined(CONFIG_FIRMWARE_EDID)
+       edid = &dpy->edid;
+#endif
 
-       si = alloc_screen_info();
-       if (!si)
-               return NULL;
+       status = efi_setup_graphics(screen, edid);
+       if (status != EFI_SUCCESS)
+               goto err_free_primary_display;
 
-       *si = tmp;
-       return si;
+       return dpy;
+
+err_free_primary_display:
+       free_primary_display(dpy);
+       return NULL;
 }
 
 static void install_memreserve_table(void)
@@ -145,14 +155,14 @@ efi_status_t efi_stub_common(efi_handle_t handle,
                             unsigned long image_addr,
                             char *cmdline_ptr)
 {
-       struct screen_info *si;
+       struct sysfb_display_info *dpy;
        efi_status_t status;
 
        status = check_platform_features();
        if (status != EFI_SUCCESS)
                return status;
 
-       si = setup_graphics();
+       dpy = setup_primary_display();
 
        efi_retrieve_eventlog();
 
@@ -172,7 +182,8 @@ efi_status_t efi_stub_common(efi_handle_t handle,
 
        status = efi_boot_kernel(handle, image, image_addr, cmdline_ptr);
 
-       free_screen_info(si);
+       free_primary_display(dpy);
+
        return status;
 }
 
index b2fb0c3fa7217db3f47b73aa385e59fc68326dc4..979a21818cc1c6534b4d8e113631cbf32923e3c2 100644 (file)
@@ -36,6 +36,7 @@
 
 struct edid_info;
 struct screen_info;
+struct sysfb_display_info;
 
 extern bool efi_no5lvl;
 extern bool efi_nochunk;
@@ -1175,9 +1176,9 @@ efi_enable_reset_attack_mitigation(void) { }
 
 void efi_retrieve_eventlog(void);
 
-struct screen_info *alloc_screen_info(void);
-struct screen_info *__alloc_screen_info(void);
-void free_screen_info(struct screen_info *si);
+struct sysfb_display_info *alloc_primary_display(void);
+struct sysfb_display_info *__alloc_primary_display(void);
+void free_primary_display(struct sysfb_display_info *dpy);
 
 void efi_cache_sync_image(unsigned long image_base,
                          unsigned long alloc_size);
diff --git a/drivers/firmware/efi/libstub/primary_display.c b/drivers/firmware/efi/libstub/primary_display.c
new file mode 100644 (file)
index 0000000..cdaebab
--- /dev/null
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/efi.h>
+#include <linux/sysfb.h>
+
+#include <asm/efi.h>
+
+#include "efistub.h"
+
+/*
+ * There are two ways of populating the core kernel's sysfb_primary_display
+ * via the stub:
+ *
+ *   - using a configuration table, which relies on the EFI init code to
+ *     locate the table and copy the contents; or
+ *
+ *   - by linking directly to the core kernel's copy of the global symbol.
+ *
+ * The latter is preferred because it makes the EFIFB earlycon available very
+ * early, but it only works if the EFI stub is part of the core kernel image
+ * itself. The zboot decompressor can only use the configuration table
+ * approach.
+ */
+
+static efi_guid_t primary_display_guid = LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID;
+
+struct sysfb_display_info *__alloc_primary_display(void)
+{
+       struct sysfb_display_info *dpy;
+       efi_status_t status;
+
+       status = efi_bs_call(allocate_pool, EFI_ACPI_RECLAIM_MEMORY,
+                            sizeof(*dpy), (void **)&dpy);
+
+       if (status != EFI_SUCCESS)
+               return NULL;
+
+       memset(dpy, 0, sizeof(*dpy));
+
+       status = efi_bs_call(install_configuration_table,
+                            &primary_display_guid, dpy);
+       if (status == EFI_SUCCESS)
+               return dpy;
+
+       efi_bs_call(free_pool, dpy);
+       return NULL;
+}
+
+void free_primary_display(struct sysfb_display_info *dpy)
+{
+       if (!dpy)
+               return;
+
+       efi_bs_call(install_configuration_table, &primary_display_guid, NULL);
+       efi_bs_call(free_pool, dpy);
+}
diff --git a/drivers/firmware/efi/libstub/screen_info.c b/drivers/firmware/efi/libstub/screen_info.c
deleted file mode 100644 (file)
index 5d3a1e3..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include <linux/efi.h>
-#include <linux/screen_info.h>
-
-#include <asm/efi.h>
-
-#include "efistub.h"
-
-/*
- * There are two ways of populating the core kernel's struct screen_info via the stub:
- * - using a configuration table, like below, which relies on the EFI init code
- *   to locate the table and copy the contents;
- * - by linking directly to the core kernel's copy of the global symbol.
- *
- * The latter is preferred because it makes the EFIFB earlycon available very
- * early, but it only works if the EFI stub is part of the core kernel image
- * itself. The zboot decompressor can only use the configuration table
- * approach.
- */
-
-static efi_guid_t screen_info_guid = LINUX_EFI_SCREEN_INFO_TABLE_GUID;
-
-struct screen_info *__alloc_screen_info(void)
-{
-       struct screen_info *si;
-       efi_status_t status;
-
-       status = efi_bs_call(allocate_pool, EFI_ACPI_RECLAIM_MEMORY,
-                            sizeof(*si), (void **)&si);
-
-       if (status != EFI_SUCCESS)
-               return NULL;
-
-       memset(si, 0, sizeof(*si));
-
-       status = efi_bs_call(install_configuration_table,
-                            &screen_info_guid, si);
-       if (status == EFI_SUCCESS)
-               return si;
-
-       efi_bs_call(free_pool, si);
-       return NULL;
-}
-
-void free_screen_info(struct screen_info *si)
-{
-       if (!si)
-               return;
-
-       efi_bs_call(install_configuration_table, &screen_info_guid, NULL);
-       efi_bs_call(free_pool, si);
-}
index c47ace06f010079cbb53ca9ec6daab70a20519e9..4b76f74c56dae019ab6dbd7dd574cdd1c09819a3 100644 (file)
@@ -26,9 +26,9 @@ void __weak efi_cache_sync_image(unsigned long image_base,
        // executable code loaded into memory to be safe for execution.
 }
 
-struct screen_info *alloc_screen_info(void)
+struct sysfb_display_info *alloc_primary_display(void)
 {
-       return __alloc_screen_info();
+       return __alloc_primary_display();
 }
 
 asmlinkage efi_status_t __efiapi
index d51777df12d164d3ed937775664586a006c3e300..9884f003247d8f29cb5e04f4a5d2b3fadac62ff0 100644 (file)
@@ -63,11 +63,13 @@ endif # HAS_IOMEM
 
 config FIRMWARE_EDID
        bool "Enable firmware EDID"
-       depends on X86
+       depends on EFI_GENERIC_STUB || X86
        help
          This enables access to the EDID transferred from the firmware.
-         On x86, this is from the VESA BIOS. DRM display drivers will
-         be able to export the information to userspace.
+         On EFI systems, the EDID comes from the same device as the
+         primary GOP. On x86 with BIOS, it comes from the VESA BIOS.
+         DRM display drivers will be able to export the information
+         to userspace.
 
          Also enable this if DDC/I2C transfers do not work for your driver
          and if you are using nvidiafb, i810fb or savagefb.
index 2a43094e23f7038503ae8051801f2f10c2dfd6b8..664898d09ff5720cca79bc3207ba75db03f5794a 100644 (file)
@@ -406,11 +406,12 @@ void efi_native_runtime_setup(void);
 #define EFI_CC_FINAL_EVENTS_TABLE_GUID         EFI_GUID(0xdd4a4648, 0x2de7, 0x4665, 0x96, 0x4d, 0x21, 0xd9, 0xef, 0x5f, 0xb4, 0x46)
 
 /*
- * This GUID is used to pass to the kernel proper the struct screen_info
- * structure that was populated by the stub based on the GOP protocol instance
- * associated with ConOut
+ * This GUIDs are used to pass to the kernel proper the primary
+ * display that has been populated by the stub based on the GOP
+ * instance associated with ConOut.
  */
-#define LINUX_EFI_SCREEN_INFO_TABLE_GUID       EFI_GUID(0xe03fc20a, 0x85dc, 0x406e,  0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95)
+#define LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID   EFI_GUID(0xe03fc20a, 0x85dc, 0x406e,  0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95)
+
 #define LINUX_EFI_ARM_CPU_STATE_TABLE_GUID     EFI_GUID(0xef79e4aa, 0x3c3d, 0x4989,  0xb9, 0x02, 0x07, 0xa9, 0x43, 0xe5, 0x50, 0xd2)
 #define LINUX_EFI_LOADER_ENTRY_GUID            EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf,  0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f)
 #define LINUX_EFI_RANDOM_SEED_TABLE_GUID       EFI_GUID(0x1ce1e5bc, 0x7ceb, 0x42f2,  0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b)