To use the EFI firmware update "UX Capsule" extension, we need to know
what the GOP video mode number was during boot.  This patch adds it to
the efi-framebuffer.N devices in sysfs and adds the various files in
/sys/bus/platform/drivers/efi-framebuffer/efi-framebuffer.N/ to the
sysfs documentation.

Signed-off-by: Peter Jones <[email protected]>
---
 drivers/firmware/efi/libstub/gop.c           | 16 ++++++++++++----
 drivers/video/fbdev/efifb.c                  | 11 +++++++++++
 include/uapi/linux/screen_info.h             |  4 ++--
 Documentation/ABI/testing/sysfs-firmware-efi | 15 +++++++++++++++
 4 files changed, 40 insertions(+), 6 deletions(-)

diff --git a/drivers/firmware/efi/libstub/gop.c 
b/drivers/firmware/efi/libstub/gop.c
index 24c461dea7a..f9e174acb0b 100644
--- a/drivers/firmware/efi/libstub/gop.c
+++ b/drivers/firmware/efi/libstub/gop.c
@@ -89,7 +89,7 @@ static efi_status_t
 __gop_query32(efi_system_table_t *sys_table_arg,
              struct efi_graphics_output_protocol_32 *gop32,
              struct efi_graphics_output_mode_info **info,
-             unsigned long *size, u64 *fb_base)
+             unsigned long *size, u64 *fb_base, u32 *mode_num)
 {
        struct efi_graphics_output_protocol_mode_32 *mode;
        efi_graphics_output_protocol_query_mode query_mode;
@@ -106,6 +106,7 @@ __gop_query32(efi_system_table_t *sys_table_arg,
                return status;
 
        *fb_base = mode->frame_buffer_base;
+       *mode_num = mode->mode;
        return status;
 }
 
@@ -115,6 +116,7 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct 
screen_info *si,
 {
        struct efi_graphics_output_protocol_32 *gop32, *first_gop;
        unsigned long nr_gops;
+       u32 mode_num;
        u16 width, height;
        u32 pixels_per_scan_line;
        u32 ext_lfb_base;
@@ -148,7 +150,7 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct 
screen_info *si,
                        conout_found = true;
 
                status = __gop_query32(sys_table_arg, gop32, &info, &size,
-                                      &current_fb_base);
+                                      &current_fb_base, &mode_num);
                if (status == EFI_SUCCESS && (!first_gop || conout_found) &&
                    info->pixel_format != PIXEL_BLT_ONLY) {
                        /*
@@ -182,6 +184,8 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct 
screen_info *si,
        /* EFI framebuffer */
        si->orig_video_isVGA = VIDEO_TYPE_EFI;
 
+       si->efi_gop_mode_high = (mode_num & 0xff00) >> 16;
+       si->efi_gop_mode_low = (mode_num & 0xff);
        si->lfb_width = width;
        si->lfb_height = height;
        si->lfb_base = fb_base;
@@ -207,7 +211,7 @@ static efi_status_t
 __gop_query64(efi_system_table_t *sys_table_arg,
              struct efi_graphics_output_protocol_64 *gop64,
              struct efi_graphics_output_mode_info **info,
-             unsigned long *size, u64 *fb_base)
+             unsigned long *size, u64 *fb_base, u32 *mode_num)
 {
        struct efi_graphics_output_protocol_mode_64 *mode;
        efi_graphics_output_protocol_query_mode query_mode;
@@ -224,6 +228,7 @@ __gop_query64(efi_system_table_t *sys_table_arg,
                return status;
 
        *fb_base = mode->frame_buffer_base;
+       *mode_num = mode->mode;
        return status;
 }
 
@@ -233,6 +238,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct 
screen_info *si,
 {
        struct efi_graphics_output_protocol_64 *gop64, *first_gop;
        unsigned long nr_gops;
+       u32 mode_num;
        u16 width, height;
        u32 pixels_per_scan_line;
        u32 ext_lfb_base;
@@ -266,7 +272,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct 
screen_info *si,
                        conout_found = true;
 
                status = __gop_query64(sys_table_arg, gop64, &info, &size,
-                                      &current_fb_base);
+                                      &current_fb_base, &mode_num);
                if (status == EFI_SUCCESS && (!first_gop || conout_found) &&
                    info->pixel_format != PIXEL_BLT_ONLY) {
                        /*
@@ -300,6 +306,8 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct 
screen_info *si,
        /* EFI framebuffer */
        si->orig_video_isVGA = VIDEO_TYPE_EFI;
 
+       si->efi_gop_mode_high = (mode_num & 0xff00) >> 16;
+       si->efi_gop_mode_low = (mode_num & 0xff);
        si->lfb_width = width;
        si->lfb_height = height;
        si->lfb_base = fb_base;
diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c
index ba906876cc4..3250f3f9152 100644
--- a/drivers/video/fbdev/efifb.c
+++ b/drivers/video/fbdev/efifb.c
@@ -331,12 +331,23 @@ efifb_attr_decl(height, "%u");
 efifb_attr_decl(width, "%u");
 efifb_attr_decl(depth, "%u");
 
+static ssize_t gop_mode_show(struct device *dev,
+                            struct device_attribute *attr,
+                            char *buf)
+{
+       return sprintf(buf, "0x%04hx%04hx\n",
+                      screen_info.efi_gop_mode_high,
+                      screen_info.efi_gop_mode_low);
+}
+static DEVICE_ATTR_RO(gop_mode);
+
 static struct attribute *efifb_attrs[] = {
        &dev_attr_base.attr,
        &dev_attr_linelength.attr,
        &dev_attr_width.attr,
        &dev_attr_height.attr,
        &dev_attr_depth.attr,
+       &dev_attr_gop_mode.attr,
        NULL
 };
 ATTRIBUTE_GROUPS(efifb);
diff --git a/include/uapi/linux/screen_info.h b/include/uapi/linux/screen_info.h
index 87e5c086938..a8eb2d76167 100644
--- a/include/uapi/linux/screen_info.h
+++ b/include/uapi/linux/screen_info.h
@@ -18,7 +18,7 @@ struct screen_info {
        __u8  flags;            /* 0x08 */
        __u8  unused2;          /* 0x09 */
        __u16 orig_video_ega_bx;/* 0x0a */
-       __u16 unused3;          /* 0x0c */
+       __u16 efi_gop_mode_low; /* 0x0c */
        __u8  orig_video_lines; /* 0x0e */
        __u8  orig_video_isVGA; /* 0x0f */
        __u16 orig_video_points;/* 0x10 */
@@ -45,7 +45,7 @@ struct screen_info {
        __u16 vesa_attributes;  /* 0x34 */
        __u32 capabilities;     /* 0x36 */
        __u32 ext_lfb_base;     /* 0x3a */
-       __u8  _reserved[2];     /* 0x3e */
+       __u16 efi_gop_mode_high;/* 0x3e */
 } __attribute__((packed));
 
 #define VIDEO_TYPE_MDA         0x10    /* Monochrome Text Display      */
diff --git a/Documentation/ABI/testing/sysfs-firmware-efi 
b/Documentation/ABI/testing/sysfs-firmware-efi
index e794eac32a9..6c169599863 100644
--- a/Documentation/ABI/testing/sysfs-firmware-efi
+++ b/Documentation/ABI/testing/sysfs-firmware-efi
@@ -28,3 +28,18 @@ Description: Displays the physical addresses of all EFI 
Configuration
                versions are always printed first, i.e. ACPI20 comes
                before ACPI.
 Users:         dmidecode
+
+What:          /sys/bus/platform/drivers/efi-framebuffer/efi-framebuffer.N/
+Date:          October 2016
+Contact:       [email protected]
+Description:   The characteristics of the EFI GOP framebuffer device.
+
+               base: The physical address of the framebuffer memory.
+               depth: The color depth of the framebuffer, in bits.
+               height: The height of the displayed frame in pixels.
+               linelength: The size of one line (i.e. the stride) of the
+                           framebuffer memory, in bytes.
+               width: The width of the displayed frame in pixels.
+               gop_mode: The index into the EFI GOP mode table for the mode in
+                         use during boot-up.
+Users:         fwupd
-- 
2.20.1

Reply via email to