summaryrefslogtreecommitdiff
path: root/drivers/firmware
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-02-09 20:49:19 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2026-02-09 20:49:19 -0800
commit0c61526621ec1916527d6f6226d8a466340cca22 (patch)
tree22ee5ea165acd724cca10cac89659a5f8e2666fe /drivers/firmware
parent33120a2f8fc47f388506b7df1209bd5ac85dd584 (diff)
parentc5a8f13f1e476c90f4bc184a58751d3e7ff88f2b (diff)
downloadlinux-0c61526621ec1916527d6f6226d8a466340cca22.tar.gz
linux-0c61526621ec1916527d6f6226d8a466340cca22.zip
Merge tag 'efi-next-for-v7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi
Pull EFI updates from Ard Biesheuvel: - Quirk the broken EFI framebuffer geometry on the Valve Steam Deck - Capture the EDID information of the primary display also on non-x86 EFI systems when booting via the EFI stub. * tag 'efi-next-for-v7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi: efi: Support EDID information sysfb: Move edid_info into sysfb_primary_display sysfb: Pass sysfb_primary_display to devices sysfb: Replace screen_info with sysfb_primary_display sysfb: Add struct sysfb_display_info efi: sysfb_efi: Reduce number of references to global screen_info efi: earlycon: Reduce number of references to global screen_info efi: sysfb_efi: Fix efidrmfb and simpledrmfb on Valve Steam Deck efi: sysfb_efi: Convert swap width and height quirk to a callback efi: sysfb_efi: Fix lfb_linelength calculation when applying quirks efi: sysfb_efi: Replace open coded swap with the macro
Diffstat (limited to 'drivers/firmware')
-rw-r--r--drivers/firmware/efi/earlycon.c42
-rw-r--r--drivers/firmware/efi/efi-init.c38
-rw-r--r--drivers/firmware/efi/efi.c4
-rw-r--r--drivers/firmware/efi/libstub/Makefile2
-rw-r--r--drivers/firmware/efi/libstub/efi-stub-entry.c17
-rw-r--r--drivers/firmware/efi/libstub/efi-stub.c41
-rw-r--r--drivers/firmware/efi/libstub/efistub.h7
-rw-r--r--drivers/firmware/efi/libstub/primary_display.c56
-rw-r--r--drivers/firmware/efi/libstub/screen_info.c53
-rw-r--r--drivers/firmware/efi/libstub/zboot.c4
-rw-r--r--drivers/firmware/efi/sysfb_efi.c144
-rw-r--r--drivers/firmware/sysfb.c13
-rw-r--r--drivers/firmware/sysfb_simplefb.c2
13 files changed, 253 insertions, 170 deletions
diff --git a/drivers/firmware/efi/earlycon.c b/drivers/firmware/efi/earlycon.c
index d18a1a5de1449..3d060d59968cf 100644
--- a/drivers/firmware/efi/earlycon.c
+++ b/drivers/firmware/efi/earlycon.c
@@ -9,7 +9,7 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/serial_core.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
#include <linux/string.h>
#include <asm/early_ioremap.h>
@@ -32,12 +32,13 @@ static void *efi_fb;
*/
static int __init efi_earlycon_remap_fb(void)
{
+ const struct screen_info *si = &sysfb_primary_display.screen;
+
/* bail if there is no bootconsole or it was unregistered already */
if (!earlycon_console || !console_is_registered(earlycon_console))
return 0;
- efi_fb = memremap(fb_base, screen_info.lfb_size,
- fb_wb ? MEMREMAP_WB : MEMREMAP_WC);
+ efi_fb = memremap(fb_base, si->lfb_size, fb_wb ? MEMREMAP_WB : MEMREMAP_WC);
return efi_fb ? 0 : -ENOMEM;
}
@@ -71,12 +72,12 @@ static __ref void efi_earlycon_unmap(void *addr, unsigned long len)
early_memunmap(addr, len);
}
-static void efi_earlycon_clear_scanline(unsigned int y)
+static void efi_earlycon_clear_scanline(unsigned int y, const struct screen_info *si)
{
unsigned long *dst;
u16 len;
- len = screen_info.lfb_linelength;
+ len = si->lfb_linelength;
dst = efi_earlycon_map(y*len, len);
if (!dst)
return;
@@ -85,7 +86,7 @@ static void efi_earlycon_clear_scanline(unsigned int y)
efi_earlycon_unmap(dst, len);
}
-static void efi_earlycon_scroll_up(void)
+static void efi_earlycon_scroll_up(const struct screen_info *si)
{
unsigned long *dst, *src;
u16 maxlen = 0;
@@ -99,8 +100,8 @@ static void efi_earlycon_scroll_up(void)
}
maxlen *= 4;
- len = screen_info.lfb_linelength;
- height = screen_info.lfb_height;
+ len = si->lfb_linelength;
+ height = si->lfb_height;
for (i = 0; i < height - font->height; i++) {
dst = efi_earlycon_map(i*len, len);
@@ -120,7 +121,8 @@ static void efi_earlycon_scroll_up(void)
}
}
-static void efi_earlycon_write_char(u32 *dst, unsigned char c, unsigned int h)
+static void efi_earlycon_write_char(u32 *dst, unsigned char c, unsigned int h,
+ const struct screen_info *si)
{
const u32 color_black = 0x00000000;
const u32 color_white = 0x00ffffff;
@@ -145,13 +147,12 @@ static void efi_earlycon_write_char(u32 *dst, unsigned char c, unsigned int h)
static void
efi_earlycon_write(struct console *con, const char *str, unsigned int num)
{
- struct screen_info *si;
+ const struct screen_info *si = &sysfb_primary_display.screen;
u32 cur_efi_x = efi_x;
unsigned int len;
const char *s;
void *dst;
- si = &screen_info;
len = si->lfb_linelength;
while (num) {
@@ -174,7 +175,7 @@ efi_earlycon_write(struct console *con, const char *str, unsigned int num)
x = efi_x;
while (n-- > 0) {
- efi_earlycon_write_char(dst + x*4, *s, h);
+ efi_earlycon_write_char(dst + x * 4, *s, h, si);
x += font->width;
s++;
}
@@ -207,10 +208,10 @@ efi_earlycon_write(struct console *con, const char *str, unsigned int num)
cur_line_y = (cur_line_y + 1) % max_line_y;
efi_y -= font->height;
- efi_earlycon_scroll_up();
+ efi_earlycon_scroll_up(si);
for (i = 0; i < font->height; i++)
- efi_earlycon_clear_scanline(efi_y + i);
+ efi_earlycon_clear_scanline(efi_y + i, si);
}
}
}
@@ -226,22 +227,21 @@ void __init efi_earlycon_reprobe(void)
static int __init efi_earlycon_setup(struct earlycon_device *device,
const char *opt)
{
- struct screen_info *si;
+ const struct screen_info *si = &sysfb_primary_display.screen;
u16 xres, yres;
u32 i;
fb_wb = opt && !strcmp(opt, "ram");
- if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI) {
+ if (si->orig_video_isVGA != VIDEO_TYPE_EFI) {
fb_probed = true;
return -ENODEV;
}
- fb_base = screen_info.lfb_base;
- if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)
- fb_base |= (u64)screen_info.ext_lfb_base << 32;
+ fb_base = si->lfb_base;
+ if (si->capabilities & VIDEO_CAPABILITY_64BIT_BASE)
+ fb_base |= (u64)si->ext_lfb_base << 32;
- si = &screen_info;
xres = si->lfb_width;
yres = si->lfb_height;
@@ -266,7 +266,7 @@ static int __init efi_earlycon_setup(struct earlycon_device *device,
efi_y -= font->height;
for (i = 0; i < (yres - efi_y) / font->height; i++)
- efi_earlycon_scroll_up();
+ efi_earlycon_scroll_up(si);
device->con->write = efi_earlycon_write;
earlycon_console = device->con;
diff --git a/drivers/firmware/efi/efi-init.c b/drivers/firmware/efi/efi-init.c
index a65c2d5b9e7b6..432301dce76f4 100644
--- a/drivers/firmware/efi/efi-init.c
+++ b/drivers/firmware/efi/efi-init.c
@@ -19,11 +19,11 @@
#include <linux/of_address.h>
#include <linux/of_fdt.h>
#include <linux/platform_device.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
#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)
{
@@ -57,31 +57,31 @@ static phys_addr_t __init efi_to_phys(unsigned long addr)
extern __weak const efi_config_table_type_t efi_arch_tables[];
/*
- * x86 defines its own screen_info and uses it even without EFI,
- * everything else can get it from here.
+ * x86 defines its own instance of sysfb_primary_display and uses
+ * it even without EFI, everything else can get them from here.
*/
#if !defined(CONFIG_X86) && (defined(CONFIG_SYSFB) || defined(CONFIG_EFI_EARLYCON))
-struct screen_info screen_info __section(".data");
-EXPORT_SYMBOL_GPL(screen_info);
+struct sysfb_display_info sysfb_primary_display __section(".data");
+EXPORT_SYMBOL_GPL(sysfb_primary_display);
#endif
-static void __init init_screen_info(void)
+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;
}
- screen_info = *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(screen_info.lfb_base))
- memblock_mark_nomap(screen_info.lfb_base,
- screen_info.lfb_size);
+ if (memblock_is_map_memory(sysfb_primary_display.screen.lfb_base))
+ memblock_mark_nomap(sysfb_primary_display.screen.lfb_base,
+ sysfb_primary_display.screen.lfb_size);
if (IS_ENABLED(CONFIG_EFI_EARLYCON))
efi_earlycon_reprobe();
@@ -274,5 +274,5 @@ void __init efi_init(void)
if (IS_ENABLED(CONFIG_X86) ||
IS_ENABLED(CONFIG_SYSFB) ||
IS_ENABLED(CONFIG_EFI_EARLYCON))
- init_screen_info();
+ init_primary_display();
}
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 17b5f3415465e..111e87a618e5f 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -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),
@@ -642,7 +642,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
{},
};
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index 7d15a85d579fa..e386ffd009b7e 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -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
diff --git a/drivers/firmware/efi/libstub/efi-stub-entry.c b/drivers/firmware/efi/libstub/efi-stub-entry.c
index a6c0498351905..aa85e910fe595 100644
--- a/drivers/firmware/efi/libstub/efi-stub-entry.c
+++ b/drivers/firmware/efi/libstub/efi-stub-entry.c
@@ -1,23 +1,28 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/efi.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
#include <asm/efi.h>
#include "efistub.h"
-static unsigned long screen_info_offset;
+static unsigned long kernel_image_offset;
-struct screen_info *alloc_screen_info(void)
+static void *kernel_image_addr(void *addr)
+{
+ return addr + kernel_image_offset;
+}
+
+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))
- return (void *)&screen_info + screen_info_offset;
+ return kernel_image_addr(&sysfb_primary_display);
return NULL;
}
@@ -73,7 +78,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
return status;
}
- screen_info_offset = image_addr - (unsigned long)image->image_base;
+ kernel_image_offset = image_addr - (unsigned long)image->image_base;
status = efi_stub_common(handle, image, image_addr, cmdline_ptr);
diff --git a/drivers/firmware/efi/libstub/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c
index 9cb814c5ba1bd..42d6073bcd062 100644
--- a/drivers/firmware/efi/libstub/efi-stub.c
+++ b/drivers/firmware/efi/libstub/efi-stub.c
@@ -10,7 +10,7 @@
*/
#include <linux/efi.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
#include <asm/efi.h>
#include "efistub.h"
@@ -48,23 +48,33 @@
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;
}
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index b2fb0c3fa7217..979a21818cc1c 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -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
index 0000000000000..cdaebab265142
--- /dev/null
+++ b/drivers/firmware/efi/libstub/primary_display.c
@@ -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
index 5d3a1e32d1776..0000000000000
--- a/drivers/firmware/efi/libstub/screen_info.c
+++ /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);
-}
diff --git a/drivers/firmware/efi/libstub/zboot.c b/drivers/firmware/efi/libstub/zboot.c
index c47ace06f0100..4b76f74c56dae 100644
--- a/drivers/firmware/efi/libstub/zboot.c
+++ b/drivers/firmware/efi/libstub/zboot.c
@@ -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
diff --git a/drivers/firmware/efi/sysfb_efi.c b/drivers/firmware/efi/sysfb_efi.c
index 1e509595ac034..4c3986ddcd54a 100644
--- a/drivers/firmware/efi/sysfb_efi.c
+++ b/drivers/firmware/efi/sysfb_efi.c
@@ -92,7 +92,7 @@ void efifb_setup_from_dmi(struct screen_info *si, const char *opt)
})
#ifdef CONFIG_EFI
-static int __init efifb_set_system(const struct dmi_system_id *id)
+static int __init efifb_set_system(struct screen_info *si, const struct dmi_system_id *id)
{
struct efifb_dmi_info *info = id->driver_data;
@@ -101,14 +101,14 @@ static int __init efifb_set_system(const struct dmi_system_id *id)
return 0;
/* Trust the bootloader over the DMI tables */
- if (screen_info.lfb_base == 0) {
+ if (si->lfb_base == 0) {
#if defined(CONFIG_PCI)
struct pci_dev *dev = NULL;
int found_bar = 0;
#endif
if (info->base) {
- screen_info.lfb_base = choose_value(info->base,
- screen_info.lfb_base, OVERRIDE_BASE,
+ si->lfb_base = choose_value(info->base,
+ si->lfb_base, OVERRIDE_BASE,
info->flags);
#if defined(CONFIG_PCI)
@@ -135,49 +135,53 @@ static int __init efifb_set_system(const struct dmi_system_id *id)
start = pci_resource_start(dev, i);
end = pci_resource_end(dev, i);
- if (screen_info.lfb_base >= start &&
- screen_info.lfb_base < end) {
+ if (si->lfb_base >= start && si->lfb_base < end) {
found_bar = 1;
break;
}
}
}
if (!found_bar)
- screen_info.lfb_base = 0;
+ si->lfb_base = 0;
#endif
}
}
- if (screen_info.lfb_base) {
- screen_info.lfb_linelength = choose_value(info->stride,
- screen_info.lfb_linelength, OVERRIDE_STRIDE,
+ if (si->lfb_base) {
+ si->lfb_linelength = choose_value(info->stride,
+ si->lfb_linelength, OVERRIDE_STRIDE,
info->flags);
- screen_info.lfb_width = choose_value(info->width,
- screen_info.lfb_width, OVERRIDE_WIDTH,
+ si->lfb_width = choose_value(info->width,
+ si->lfb_width, OVERRIDE_WIDTH,
info->flags);
- screen_info.lfb_height = choose_value(info->height,
- screen_info.lfb_height, OVERRIDE_HEIGHT,
+ si->lfb_height = choose_value(info->height,
+ si->lfb_height, OVERRIDE_HEIGHT,
info->flags);
- if (screen_info.orig_video_isVGA == 0)
- screen_info.orig_video_isVGA = VIDEO_TYPE_EFI;
+ if (si->orig_video_isVGA == 0)
+ si->orig_video_isVGA = VIDEO_TYPE_EFI;
} else {
- screen_info.lfb_linelength = 0;
- screen_info.lfb_width = 0;
- screen_info.lfb_height = 0;
- screen_info.orig_video_isVGA = 0;
+ si->lfb_linelength = 0;
+ si->lfb_width = 0;
+ si->lfb_height = 0;
+ si->orig_video_isVGA = 0;
return 0;
}
printk(KERN_INFO "efifb: dmi detected %s - framebuffer at 0x%08x "
"(%dx%d, stride %d)\n", id->ident,
- screen_info.lfb_base, screen_info.lfb_width,
- screen_info.lfb_height, screen_info.lfb_linelength);
+ si->lfb_base, si->lfb_width,
+ si->lfb_height, si->lfb_linelength);
return 1;
}
+static int __init efifb_set_system_callback(const struct dmi_system_id *id)
+{
+ return efifb_set_system(&sysfb_primary_display.screen, id);
+}
+
#define EFIFB_DMI_SYSTEM_ID(vendor, name, enumid) \
{ \
- efifb_set_system, \
+ efifb_set_system_callback, \
name, \
{ \
DMI_MATCH(DMI_BIOS_VENDOR, vendor), \
@@ -231,6 +235,44 @@ static const struct dmi_system_id efifb_dmi_system_table[] __initconst = {
{},
};
+static int __init efifb_swap_width_height(const struct dmi_system_id *id)
+{
+ struct screen_info *si = &sysfb_primary_display.screen;
+ u32 bpp = __screen_info_lfb_bits_per_pixel(si);
+
+ swap(si->lfb_width, si->lfb_height);
+ si->lfb_linelength = bpp * si->lfb_width / BITS_PER_BYTE;
+
+ return 1;
+}
+
+struct efifb_mode_fixup {
+ unsigned int width;
+ unsigned int height;
+ unsigned int linelength;
+};
+
+static int __init
+efifb_check_and_swap_width_height(const struct dmi_system_id *id)
+{
+ const struct efifb_mode_fixup *data = id->driver_data;
+ struct screen_info *si = &sysfb_primary_display.screen;
+
+ if (data->width == si->lfb_width && data->height == si->lfb_height) {
+ swap(si->lfb_width, si->lfb_height);
+ si->lfb_linelength = data->linelength;
+ si->lfb_size = data->linelength * data->width;
+ }
+
+ return 1;
+}
+
+static const struct efifb_mode_fixup efifb_steamdeck_mode_fixup __initconst = {
+ .width = 1280,
+ .height = 800,
+ .linelength = 3328,
+};
+
/*
* Some devices have a portrait LCD but advertise a landscape resolution (and
* pitch). We simply swap width and height for these devices so that we can
@@ -248,6 +290,7 @@ static const struct dmi_system_id efifb_dmi_swap_width_height[] __initconst = {
DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "MIIX 310-10ICR"),
DMI_EXACT_MATCH(DMI_BIOS_VERSION, "1HCN44WW"),
},
+ .callback = efifb_swap_width_height,
},
{
/* Lenovo MIIX 320-10ICR with 800x1280 portrait screen */
@@ -256,6 +299,7 @@ static const struct dmi_system_id efifb_dmi_swap_width_height[] __initconst = {
DMI_EXACT_MATCH(DMI_PRODUCT_VERSION,
"Lenovo MIIX 320-10ICR"),
},
+ .callback = efifb_swap_width_height,
},
{
/* Lenovo D330 with 800x1280 or 1200x1920 portrait screen */
@@ -264,6 +308,7 @@ static const struct dmi_system_id efifb_dmi_swap_width_height[] __initconst = {
DMI_EXACT_MATCH(DMI_PRODUCT_VERSION,
"Lenovo ideapad D330-10IGM"),
},
+ .callback = efifb_swap_width_height,
},
{
/* Lenovo IdeaPad Duet 3 10IGL5 with 1200x1920 portrait screen */
@@ -272,6 +317,7 @@ static const struct dmi_system_id efifb_dmi_swap_width_height[] __initconst = {
DMI_EXACT_MATCH(DMI_PRODUCT_VERSION,
"IdeaPad Duet 3 10IGL5"),
},
+ .callback = efifb_swap_width_height,
},
{
/* Lenovo Yoga Book X91F / X91L */
@@ -280,16 +326,38 @@ static const struct dmi_system_id efifb_dmi_swap_width_height[] __initconst = {
/* Non exact match to match F + L versions */
DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X91"),
},
+ .callback = efifb_swap_width_height,
+ },
+ {
+ /* Valve Steam Deck (Jupiter) */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Valve"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Jupiter"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "1"),
+ },
+ .callback = efifb_check_and_swap_width_height,
+ .driver_data = (void *)&efifb_steamdeck_mode_fixup,
+ },
+ {
+ /* Valve Steam Deck (Galileo) */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Valve"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Galileo"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "1"),
+ },
+ .callback = efifb_check_and_swap_width_height,
+ .driver_data = (void *)&efifb_steamdeck_mode_fixup,
},
{},
};
-static bool efifb_overlaps_pci_range(const struct of_pci_range *range)
+static bool efifb_overlaps_pci_range(const struct screen_info *si,
+ const struct of_pci_range *range)
{
- u64 fb_base = screen_info.lfb_base;
+ u64 fb_base = si->lfb_base;
- if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)
- fb_base |= (u64)(unsigned long)screen_info.ext_lfb_base << 32;
+ if (si->capabilities & VIDEO_CAPABILITY_64BIT_BASE)
+ fb_base |= (u64)(unsigned long)si->ext_lfb_base << 32;
return fb_base >= range->cpu_addr &&
fb_base < (range->cpu_addr + range->size);
@@ -311,7 +379,7 @@ static struct device_node *find_pci_overlap_node(void)
}
for_each_of_pci_range(&parser, &range)
- if (efifb_overlaps_pci_range(&range))
+ if (efifb_overlaps_pci_range(&sysfb_primary_display.screen, &range))
return np;
}
return NULL;
@@ -349,25 +417,19 @@ static const struct fwnode_operations efifb_fwnode_ops = {
static struct fwnode_handle efifb_fwnode;
-__init void sysfb_apply_efi_quirks(void)
+__init void sysfb_apply_efi_quirks(struct screen_info *si)
{
- if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI ||
- !(screen_info.capabilities & VIDEO_CAPABILITY_SKIP_QUIRKS))
+ if (si->orig_video_isVGA != VIDEO_TYPE_EFI ||
+ !(si->capabilities & VIDEO_CAPABILITY_SKIP_QUIRKS))
dmi_check_system(efifb_dmi_system_table);
- if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI &&
- dmi_check_system(efifb_dmi_swap_width_height)) {
- u16 temp = screen_info.lfb_width;
-
- screen_info.lfb_width = screen_info.lfb_height;
- screen_info.lfb_height = temp;
- screen_info.lfb_linelength = 4 * screen_info.lfb_width;
- }
+ if (si->orig_video_isVGA == VIDEO_TYPE_EFI)
+ dmi_check_system(efifb_dmi_swap_width_height);
}
-__init void sysfb_set_efifb_fwnode(struct platform_device *pd)
+__init void sysfb_set_efifb_fwnode(const struct screen_info *si, struct platform_device *pd)
{
- if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI && IS_ENABLED(CONFIG_PCI)) {
+ if (si->orig_video_isVGA == VIDEO_TYPE_EFI && IS_ENABLED(CONFIG_PCI)) {
fwnode_init(&efifb_fwnode, &efifb_fwnode_ops);
pd->dev.fwnode = &efifb_fwnode;
}
diff --git a/drivers/firmware/sysfb.c b/drivers/firmware/sysfb.c
index 889e5b05c739c..8833582c18830 100644
--- a/drivers/firmware/sysfb.c
+++ b/drivers/firmware/sysfb.c
@@ -66,7 +66,7 @@ static bool sysfb_unregister(void)
*/
void sysfb_disable(struct device *dev)
{
- struct screen_info *si = &screen_info;
+ struct screen_info *si = &sysfb_primary_display.screen;
struct device *parent;
mutex_lock(&disable_lock);
@@ -92,7 +92,7 @@ EXPORT_SYMBOL_GPL(sysfb_disable);
*/
bool sysfb_handles_screen_info(void)
{
- const struct screen_info *si = &screen_info;
+ const struct screen_info *si = &sysfb_primary_display.screen;
return !!screen_info_video_type(si);
}
@@ -141,7 +141,8 @@ static struct device *sysfb_parent_dev(const struct screen_info *si)
static __init int sysfb_init(void)
{
- struct screen_info *si = &screen_info;
+ struct sysfb_display_info *dpy = &sysfb_primary_display;
+ struct screen_info *si = &dpy->screen;
struct device *parent;
unsigned int type;
struct simplefb_platform_data mode;
@@ -155,7 +156,7 @@ static __init int sysfb_init(void)
if (disabled)
goto unlock_mutex;
- sysfb_apply_efi_quirks();
+ sysfb_apply_efi_quirks(si);
parent = sysfb_parent_dev(si);
if (IS_ERR(parent)) {
@@ -200,9 +201,9 @@ static __init int sysfb_init(void)
pd->dev.parent = parent;
- sysfb_set_efifb_fwnode(pd);
+ sysfb_set_efifb_fwnode(si, pd);
- ret = platform_device_add_data(pd, si, sizeof(*si));
+ ret = platform_device_add_data(pd, dpy, sizeof(*dpy));
if (ret)
goto err;
diff --git a/drivers/firmware/sysfb_simplefb.c b/drivers/firmware/sysfb_simplefb.c
index 592d8a6446192..71f542e377327 100644
--- a/drivers/firmware/sysfb_simplefb.c
+++ b/drivers/firmware/sysfb_simplefb.c
@@ -117,7 +117,7 @@ __init struct platform_device *sysfb_create_simplefb(const struct screen_info *s
pd->dev.parent = parent;
- sysfb_set_efifb_fwnode(pd);
+ sysfb_set_efifb_fwnode(si, pd);
ret = platform_device_add_resources(pd, &res, 1);
if (ret)