History

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.

Matt Fleming committed 11 years ago

Commit ae2ee621 parent 7968c0e3 files · +46 −7Browse files

Unified · Split

3 files
  1. arch/x86/boot/compressed/eboot.c +20 −4
  2. drivers/video/fbdev/efifb.c +23 −1
  3. include/uapi/linux/screen_info.h +3 −2
arch/x86/boot/compressed/eboot.c+20−4
@@ -624,7 +624,7 @@ setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line, · 623 unmodified lines
624624 static efi_status_t
625625 __gop_query32(struct efi_graphics_output_protocol_32 *gop32,
626626 struct efi_graphics_output_mode_info **info,
627− unsigned long *size, u32 *fb_base)
627+ unsigned long *size, u64 *fb_base)
628628 {
629629 struct efi_graphics_output_protocol_mode_32 *mode;
630630 efi_status_t status;
@@ -650,7 +650,8 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto, · 19 unmodified lines
650650 unsigned long nr_gops;
651651 u16 width, height;
652652 u32 pixels_per_scan_line;
653− u32 fb_base;
653+ u32 ext_lfb_base;
654+ u64 fb_base;
654655 struct efi_pixel_bitmask pixel_info;
655656 int pixel_format;
656657 efi_status_t status;
@@ -713,6 +714,13 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto, · 56 unmodified lines
713714 si->lfb_width = width;
714715 si->lfb_height = height;
715716 si->lfb_base = fb_base;
717+
718+ ext_lfb_base = (u64)(unsigned long)fb_base >> 32;
719+ if (ext_lfb_base) {
720+ si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
721+ si->ext_lfb_base = ext_lfb_base;
722+ }
723+
716724 si->pages = 1;
717725
718726 setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);
@@ -727,7 +735,7 @@ out: · 8 unmodified lines
727735 static efi_status_t
728736 __gop_query64(struct efi_graphics_output_protocol_64 *gop64,
729737 struct efi_graphics_output_mode_info **info,
730− unsigned long *size, u32 *fb_base)
738+ unsigned long *size, u64 *fb_base)
731739 {
732740 struct efi_graphics_output_protocol_mode_64 *mode;
733741 efi_status_t status;
@@ -753,7 +761,8 @@ setup_gop64(struct screen_info *si, efi_guid_t *proto, · 19 unmodified lines
753761 unsigned long nr_gops;
754762 u16 width, height;
755763 u32 pixels_per_scan_line;
756− u32 fb_base;
764+ u32 ext_lfb_base;
765+ u64 fb_base;
757766 struct efi_pixel_bitmask pixel_info;
758767 int pixel_format;
759768 efi_status_t status;
@@ -816,6 +825,13 @@ setup_gop64(struct screen_info *si, efi_guid_t *proto, · 56 unmodified lines
816825 si->lfb_width = width;
817826 si->lfb_height = height;
818827 si->lfb_base = fb_base;
828+
829+ ext_lfb_base = (u64)(unsigned long)fb_base >> 32;
830+ if (ext_lfb_base) {
831+ si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
832+ si->ext_lfb_base = ext_lfb_base;
833+ }
834+
819835 si->pages = 1;
820836
821837 setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);
drivers/video/fbdev/efifb.c+23−1
@@ -114,6 +114,20 @@ static int efifb_setup(char *options) · 113 unmodified lines
114114 return 0;
115115 }
116116
117+static inline bool fb_base_is_valid(void)
118+{
119+ if (screen_info.lfb_base)
120+ return true;
121+
122+ if (!(screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE))
123+ return false;
124+
125+ if (screen_info.ext_lfb_base)
126+ return true;
127+
128+ return false;
129+}
130+
117131 static int efifb_probe(struct platform_device *dev)
118132 {
119133 struct fb_info *info;
@@ -141,7 +155,7 @@ static int efifb_probe(struct platform_device *dev) · 21 unmodified lines
141155 screen_info.lfb_depth = 32;
142156 if (!screen_info.pages)
143157 screen_info.pages = 1;
144− if (!screen_info.lfb_base) {
158+ if (!fb_base_is_valid()) {
145159 printk(KERN_DEBUG "efifb: invalid framebuffer address\n");
146160 return -ENODEV;
147161 }
@@ -160,6 +174,14 @@ static int efifb_probe(struct platform_device *dev) · 12 unmodified lines
160174 }
161175
162176 efifb_fix.smem_start = screen_info.lfb_base;
177+
178+ if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE) {
179+ u64 ext_lfb_base;
180+
181+ ext_lfb_base = (u64)(unsigned long)screen_info.ext_lfb_base << 32;
182+ efifb_fix.smem_start |= ext_lfb_base;
183+ }
184+
163185 efifb_defined.bits_per_pixel = screen_info.lfb_depth;
164186 efifb_defined.xres = screen_info.lfb_width;
165187 efifb_defined.yres = screen_info.lfb_height;
include/uapi/linux/screen_info.h+3−2
@@ -43,7 +43,8 @@ struct screen_info { · 42 unmodified lines
4343 __u16 pages; /* 0x32 */
4444 __u16 vesa_attributes; /* 0x34 */
4545 __u32 capabilities; /* 0x36 */
46− __u8 _reserved[6]; /* 0x3a */
46+ __u32 ext_lfb_base; /* 0x3a */
47+ __u8 _reserved[2]; /* 0x3e */
4748 } __attribute__((packed));
4849
4950 #define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */
@@ -69,6 +70,6 @@ struct screen_info { · 19 unmodified lines
6970 #define VIDEO_FLAGS_NOCURSOR (1 << 0) /* The video mode has no cursor set */
7071
7172 #define VIDEO_CAPABILITY_SKIP_QUIRKS (1 << 0)
72−
73+#define VIDEO_CAPABILITY_64BIT_BASE (1 << 1) /* Frame buffer base is 64-bit */
7374
7475 #endif /* _UAPI_SCREEN_INFO_H */