efi/gop: Allow specifying mode number on command line
Add the ability to choose a video mode for the selected gop by using a command-line argument of the form video=efifb:mode=<n> Signed-off-by: Arvind Sankar <nivedita@alum.mit.edu> Link: https://lore.kernel.org/r/20200320020028.1936003-12-nivedita@alum.mit.edu Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
This commit is contained in:

committed by
Ard Biesheuvel

parent
b4b89a0272
commit
fffb68047e
@@ -105,6 +105,9 @@ efi_status_t efi_parse_options(char const *cmdline)
|
||||
efi_disable_pci_dma = true;
|
||||
if (parse_option_str(val, "no_disable_early_pci_dma"))
|
||||
efi_disable_pci_dma = false;
|
||||
} else if (!strcmp(param, "video") &&
|
||||
val && strstarts(val, "efifb:")) {
|
||||
efi_parse_option_graphics(val + strlen("efifb:"));
|
||||
}
|
||||
}
|
||||
efi_bs_call(free_pool, buf);
|
||||
|
@@ -666,6 +666,8 @@ efi_status_t efi_relocate_kernel(unsigned long *image_addr,
|
||||
|
||||
efi_status_t efi_parse_options(char const *cmdline);
|
||||
|
||||
void efi_parse_option_graphics(char *option);
|
||||
|
||||
efi_status_t efi_setup_gop(struct screen_info *si, efi_guid_t *proto,
|
||||
unsigned long size);
|
||||
|
||||
|
@@ -8,11 +8,115 @@
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/screen_info.h>
|
||||
#include <linux/string.h>
|
||||
#include <asm/efi.h>
|
||||
#include <asm/setup.h>
|
||||
|
||||
#include "efistub.h"
|
||||
|
||||
enum efi_cmdline_option {
|
||||
EFI_CMDLINE_NONE,
|
||||
EFI_CMDLINE_MODE_NUM,
|
||||
};
|
||||
|
||||
static struct {
|
||||
enum efi_cmdline_option option;
|
||||
u32 mode;
|
||||
} cmdline __efistub_global = { .option = EFI_CMDLINE_NONE };
|
||||
|
||||
static bool parse_modenum(char *option, char **next)
|
||||
{
|
||||
u32 m;
|
||||
|
||||
if (!strstarts(option, "mode="))
|
||||
return false;
|
||||
option += strlen("mode=");
|
||||
m = simple_strtoull(option, &option, 0);
|
||||
if (*option && *option++ != ',')
|
||||
return false;
|
||||
cmdline.option = EFI_CMDLINE_MODE_NUM;
|
||||
cmdline.mode = m;
|
||||
|
||||
*next = option;
|
||||
return true;
|
||||
}
|
||||
|
||||
void efi_parse_option_graphics(char *option)
|
||||
{
|
||||
while (*option) {
|
||||
if (parse_modenum(option, &option))
|
||||
continue;
|
||||
|
||||
while (*option && *option++ != ',')
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 choose_mode_modenum(efi_graphics_output_protocol_t *gop)
|
||||
{
|
||||
efi_status_t status;
|
||||
|
||||
efi_graphics_output_protocol_mode_t *mode;
|
||||
efi_graphics_output_mode_info_t *info;
|
||||
unsigned long info_size;
|
||||
|
||||
u32 max_mode, cur_mode;
|
||||
int pf;
|
||||
|
||||
mode = efi_table_attr(gop, mode);
|
||||
|
||||
cur_mode = efi_table_attr(mode, mode);
|
||||
if (cmdline.mode == cur_mode)
|
||||
return cur_mode;
|
||||
|
||||
max_mode = efi_table_attr(mode, max_mode);
|
||||
if (cmdline.mode >= max_mode) {
|
||||
efi_printk("Requested mode is invalid\n");
|
||||
return cur_mode;
|
||||
}
|
||||
|
||||
status = efi_call_proto(gop, query_mode, cmdline.mode,
|
||||
&info_size, &info);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_printk("Couldn't get mode information\n");
|
||||
return cur_mode;
|
||||
}
|
||||
|
||||
pf = info->pixel_format;
|
||||
|
||||
efi_bs_call(free_pool, info);
|
||||
|
||||
if (pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX) {
|
||||
efi_printk("Invalid PixelFormat\n");
|
||||
return cur_mode;
|
||||
}
|
||||
|
||||
return cmdline.mode;
|
||||
}
|
||||
|
||||
static void set_mode(efi_graphics_output_protocol_t *gop)
|
||||
{
|
||||
efi_graphics_output_protocol_mode_t *mode;
|
||||
u32 cur_mode, new_mode;
|
||||
|
||||
switch (cmdline.option) {
|
||||
case EFI_CMDLINE_MODE_NUM:
|
||||
new_mode = choose_mode_modenum(gop);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
mode = efi_table_attr(gop, mode);
|
||||
cur_mode = efi_table_attr(mode, mode);
|
||||
|
||||
if (new_mode == cur_mode)
|
||||
return;
|
||||
|
||||
if (efi_call_proto(gop, set_mode, new_mode) != EFI_SUCCESS)
|
||||
efi_printk("Failed to set requested mode\n");
|
||||
}
|
||||
|
||||
static void find_bits(u32 mask, u8 *pos, u8 *size)
|
||||
{
|
||||
if (!mask) {
|
||||
@@ -124,6 +228,9 @@ static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
|
||||
if (!gop)
|
||||
return EFI_NOT_FOUND;
|
||||
|
||||
/* Change mode if requested */
|
||||
set_mode(gop);
|
||||
|
||||
/* EFI framebuffer */
|
||||
mode = efi_table_attr(gop, mode);
|
||||
info = efi_table_attr(mode, info);
|
||||
|
Reference in New Issue
Block a user