summaryrefslogtreecommitdiffstats
path: root/arch/x86/boot
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2015-08-25 16:32:55 +0100
committerMatt Fleming <matt.fleming@intel.com>2015-10-12 14:20:06 +0100
commitae2ee627dc87a70910de91b791b3cd0e9c6facdd (patch)
treeeaea57763339636e508428f537c7ab5526a5198d /arch/x86/boot
parent7968c0e338085eba0ee2f0e0b0d833057a966679 (diff)
downloadlinux-ae2ee627dc87a70910de91b791b3cd0e9c6facdd.tar.gz
linux-ae2ee627dc87a70910de91b791b3cd0e9c6facdd.tar.bz2
linux-ae2ee627dc87a70910de91b791b3cd0e9c6facdd.zip
efifb: Add support for 64-bit frame buffer addresses
The EFI Graphics Output Protocol uses 64-bit frame buffer addresses but these get truncated to 32-bit by the EFI boot stub when storing the address in the 'lfb_base' field of 'struct screen_info'. Add a 'ext_lfb_base' field for the upper 32-bits of the frame buffer address and set VIDEO_TYPE_CAPABILITY_64BIT_BASE when the field is useable. It turns out that the reason no one has required this support so far is that there's actually code in tianocore to "downgrade" PCI resources that have option ROMs and 64-bit BARS from 64-bit to 32-bit to cope with legacy option ROMs that can't handle 64-bit addresses. The upshot is that basically all GOP devices in the wild use a 32-bit frame buffer address. Still, it is possible to build firmware that uses a full 64-bit GOP frame buffer address. Chad did, which led to him reporting this issue. Add support in anticipation of GOP devices using 64-bit addresses more widely, and so that efifb works out of the box when that happens. Reported-by: Chad Page <chad.page@znyx.com> Cc: Pete Hawkins <pete.hawkins@znyx.com> Acked-by: Peter Jones <pjones@redhat.com> Cc: Matthew Garrett <mjg59@srcf.ucam.org> Cc: Geert Uytterhoeven <geert@linux-m68k.org> Signed-off-by: Matt Fleming <matt.fleming@intel.com>
Diffstat (limited to 'arch/x86/boot')
-rw-r--r--arch/x86/boot/compressed/eboot.c24
1 files changed, 20 insertions, 4 deletions
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index 7d69afd8b6fa..43473bb86ac0 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -624,7 +624,7 @@ setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line,
static efi_status_t
__gop_query32(struct efi_graphics_output_protocol_32 *gop32,
struct efi_graphics_output_mode_info **info,
- unsigned long *size, u32 *fb_base)
+ unsigned long *size, u64 *fb_base)
{
struct efi_graphics_output_protocol_mode_32 *mode;
efi_status_t status;
@@ -650,7 +650,8 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto,
unsigned long nr_gops;
u16 width, height;
u32 pixels_per_scan_line;
- u32 fb_base;
+ u32 ext_lfb_base;
+ u64 fb_base;
struct efi_pixel_bitmask pixel_info;
int pixel_format;
efi_status_t status;
@@ -713,6 +714,13 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto,
si->lfb_width = width;
si->lfb_height = height;
si->lfb_base = fb_base;
+
+ ext_lfb_base = (u64)(unsigned long)fb_base >> 32;
+ if (ext_lfb_base) {
+ si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
+ si->ext_lfb_base = ext_lfb_base;
+ }
+
si->pages = 1;
setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);
@@ -727,7 +735,7 @@ out:
static efi_status_t
__gop_query64(struct efi_graphics_output_protocol_64 *gop64,
struct efi_graphics_output_mode_info **info,
- unsigned long *size, u32 *fb_base)
+ unsigned long *size, u64 *fb_base)
{
struct efi_graphics_output_protocol_mode_64 *mode;
efi_status_t status;
@@ -753,7 +761,8 @@ setup_gop64(struct screen_info *si, efi_guid_t *proto,
unsigned long nr_gops;
u16 width, height;
u32 pixels_per_scan_line;
- u32 fb_base;
+ u32 ext_lfb_base;
+ u64 fb_base;
struct efi_pixel_bitmask pixel_info;
int pixel_format;
efi_status_t status;
@@ -816,6 +825,13 @@ setup_gop64(struct screen_info *si, efi_guid_t *proto,
si->lfb_width = width;
si->lfb_height = height;
si->lfb_base = fb_base;
+
+ ext_lfb_base = (u64)(unsigned long)fb_base >> 32;
+ if (ext_lfb_base) {
+ si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
+ si->ext_lfb_base = ext_lfb_base;
+ }
+
si->pages = 1;
setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);