提交 fffb6804 编写于 作者: A Arvind Sankar 提交者: Ard Biesheuvel

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: NArvind Sankar <nivedita@alum.mit.edu>
Link: https://lore.kernel.org/r/20200320020028.1936003-12-nivedita@alum.mit.eduSigned-off-by: NArd Biesheuvel <ardb@kernel.org>
上级 b4b89a02
...@@ -2,8 +2,10 @@ ...@@ -2,8 +2,10 @@
What is efifb? What is efifb?
============== ==============
This is a generic EFI platform driver for Intel based Apple computers. This is a generic EFI platform driver for systems with UEFI firmware. The
efifb is only for EFI booted Intel Macs. system must be booted via the EFI stub for this to be usable. efifb supports
both firmware with Graphics Output Protocol (GOP) displays as well as older
systems with only Universal Graphics Adapter (UGA) displays.
Supported Hardware Supported Hardware
================== ==================
...@@ -12,11 +14,14 @@ Supported Hardware ...@@ -12,11 +14,14 @@ Supported Hardware
- Macbook - Macbook
- Macbook Pro 15"/17" - Macbook Pro 15"/17"
- MacMini - MacMini
- ARM/ARM64/X86 systems with UEFI firmware
How to use it? How to use it?
============== ==============
efifb does not have any kind of autodetection of your machine. For UGA displays, efifb does not have any kind of autodetection of your
machine.
You have to add the following kernel parameters in your elilo.conf:: You have to add the following kernel parameters in your elilo.conf::
Macbook : Macbook :
...@@ -28,6 +33,9 @@ You have to add the following kernel parameters in your elilo.conf:: ...@@ -28,6 +33,9 @@ You have to add the following kernel parameters in your elilo.conf::
Macbook Pro 17", iMac 20" : Macbook Pro 17", iMac 20" :
video=efifb:i20 video=efifb:i20
For GOP displays, efifb can autodetect the display's resolution and framebuffer
address, so these should work out of the box without any special parameters.
Accepted options: Accepted options:
======= =========================================================== ======= ===========================================================
...@@ -36,4 +44,10 @@ nowc Don't map the framebuffer write combined. This can be used ...@@ -36,4 +44,10 @@ nowc Don't map the framebuffer write combined. This can be used
when large amounts of console data are written. when large amounts of console data are written.
======= =========================================================== ======= ===========================================================
Options for GOP displays:
mode=n
The EFI stub will set the mode of the display to mode number n if
possible.
Edgar Hucek <gimli@dark-green.com> Edgar Hucek <gimli@dark-green.com>
...@@ -105,6 +105,9 @@ efi_status_t efi_parse_options(char const *cmdline) ...@@ -105,6 +105,9 @@ efi_status_t efi_parse_options(char const *cmdline)
efi_disable_pci_dma = true; efi_disable_pci_dma = true;
if (parse_option_str(val, "no_disable_early_pci_dma")) if (parse_option_str(val, "no_disable_early_pci_dma"))
efi_disable_pci_dma = false; 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); efi_bs_call(free_pool, buf);
......
...@@ -666,6 +666,8 @@ efi_status_t efi_relocate_kernel(unsigned long *image_addr, ...@@ -666,6 +666,8 @@ efi_status_t efi_relocate_kernel(unsigned long *image_addr,
efi_status_t efi_parse_options(char const *cmdline); 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, efi_status_t efi_setup_gop(struct screen_info *si, efi_guid_t *proto,
unsigned long size); unsigned long size);
......
...@@ -8,11 +8,115 @@ ...@@ -8,11 +8,115 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/efi.h> #include <linux/efi.h>
#include <linux/screen_info.h> #include <linux/screen_info.h>
#include <linux/string.h>
#include <asm/efi.h> #include <asm/efi.h>
#include <asm/setup.h> #include <asm/setup.h>
#include "efistub.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) static void find_bits(u32 mask, u8 *pos, u8 *size)
{ {
if (!mask) { if (!mask) {
...@@ -124,6 +228,9 @@ static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto, ...@@ -124,6 +228,9 @@ static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
if (!gop) if (!gop)
return EFI_NOT_FOUND; return EFI_NOT_FOUND;
/* Change mode if requested */
set_mode(gop);
/* EFI framebuffer */ /* EFI framebuffer */
mode = efi_table_attr(gop, mode); mode = efi_table_attr(gop, mode);
info = efi_table_attr(mode, info); info = efi_table_attr(mode, info);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册