Skip to content

Commit fffb680

Browse files
nivedita76ardbiesheuvel
authored andcommitted
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 <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Ard Biesheuvel <[email protected]>
1 parent b4b89a0 commit fffb680

File tree

4 files changed

+129
-3
lines changed

4 files changed

+129
-3
lines changed

Documentation/fb/efifb.rst

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
What is efifb?
33
==============
44

5-
This is a generic EFI platform driver for Intel based Apple computers.
6-
efifb is only for EFI booted Intel Macs.
5+
This is a generic EFI platform driver for systems with UEFI firmware. The
6+
system must be booted via the EFI stub for this to be usable. efifb supports
7+
both firmware with Graphics Output Protocol (GOP) displays as well as older
8+
systems with only Universal Graphics Adapter (UGA) displays.
79

810
Supported Hardware
911
==================
@@ -12,11 +14,14 @@ Supported Hardware
1214
- Macbook
1315
- Macbook Pro 15"/17"
1416
- MacMini
17+
- ARM/ARM64/X86 systems with UEFI firmware
1518

1619
How to use it?
1720
==============
1821

19-
efifb does not have any kind of autodetection of your machine.
22+
For UGA displays, efifb does not have any kind of autodetection of your
23+
machine.
24+
2025
You have to add the following kernel parameters in your elilo.conf::
2126

2227
Macbook :
@@ -28,6 +33,9 @@ You have to add the following kernel parameters in your elilo.conf::
2833
Macbook Pro 17", iMac 20" :
2934
video=efifb:i20
3035

36+
For GOP displays, efifb can autodetect the display's resolution and framebuffer
37+
address, so these should work out of the box without any special parameters.
38+
3139
Accepted options:
3240

3341
======= ===========================================================
@@ -36,4 +44,10 @@ nowc Don't map the framebuffer write combined. This can be used
3644
when large amounts of console data are written.
3745
======= ===========================================================
3846

47+
Options for GOP displays:
48+
49+
mode=n
50+
The EFI stub will set the mode of the display to mode number n if
51+
possible.
52+
3953
Edgar Hucek <[email protected]>

drivers/firmware/efi/libstub/efi-stub-helper.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ efi_status_t efi_parse_options(char const *cmdline)
105105
efi_disable_pci_dma = true;
106106
if (parse_option_str(val, "no_disable_early_pci_dma"))
107107
efi_disable_pci_dma = false;
108+
} else if (!strcmp(param, "video") &&
109+
val && strstarts(val, "efifb:")) {
110+
efi_parse_option_graphics(val + strlen("efifb:"));
108111
}
109112
}
110113
efi_bs_call(free_pool, buf);

drivers/firmware/efi/libstub/efistub.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,8 @@ efi_status_t efi_relocate_kernel(unsigned long *image_addr,
666666

667667
efi_status_t efi_parse_options(char const *cmdline);
668668

669+
void efi_parse_option_graphics(char *option);
670+
669671
efi_status_t efi_setup_gop(struct screen_info *si, efi_guid_t *proto,
670672
unsigned long size);
671673

drivers/firmware/efi/libstub/gop.c

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,115 @@
88
#include <linux/bitops.h>
99
#include <linux/efi.h>
1010
#include <linux/screen_info.h>
11+
#include <linux/string.h>
1112
#include <asm/efi.h>
1213
#include <asm/setup.h>
1314

1415
#include "efistub.h"
1516

17+
enum efi_cmdline_option {
18+
EFI_CMDLINE_NONE,
19+
EFI_CMDLINE_MODE_NUM,
20+
};
21+
22+
static struct {
23+
enum efi_cmdline_option option;
24+
u32 mode;
25+
} cmdline __efistub_global = { .option = EFI_CMDLINE_NONE };
26+
27+
static bool parse_modenum(char *option, char **next)
28+
{
29+
u32 m;
30+
31+
if (!strstarts(option, "mode="))
32+
return false;
33+
option += strlen("mode=");
34+
m = simple_strtoull(option, &option, 0);
35+
if (*option && *option++ != ',')
36+
return false;
37+
cmdline.option = EFI_CMDLINE_MODE_NUM;
38+
cmdline.mode = m;
39+
40+
*next = option;
41+
return true;
42+
}
43+
44+
void efi_parse_option_graphics(char *option)
45+
{
46+
while (*option) {
47+
if (parse_modenum(option, &option))
48+
continue;
49+
50+
while (*option && *option++ != ',')
51+
;
52+
}
53+
}
54+
55+
static u32 choose_mode_modenum(efi_graphics_output_protocol_t *gop)
56+
{
57+
efi_status_t status;
58+
59+
efi_graphics_output_protocol_mode_t *mode;
60+
efi_graphics_output_mode_info_t *info;
61+
unsigned long info_size;
62+
63+
u32 max_mode, cur_mode;
64+
int pf;
65+
66+
mode = efi_table_attr(gop, mode);
67+
68+
cur_mode = efi_table_attr(mode, mode);
69+
if (cmdline.mode == cur_mode)
70+
return cur_mode;
71+
72+
max_mode = efi_table_attr(mode, max_mode);
73+
if (cmdline.mode >= max_mode) {
74+
efi_printk("Requested mode is invalid\n");
75+
return cur_mode;
76+
}
77+
78+
status = efi_call_proto(gop, query_mode, cmdline.mode,
79+
&info_size, &info);
80+
if (status != EFI_SUCCESS) {
81+
efi_printk("Couldn't get mode information\n");
82+
return cur_mode;
83+
}
84+
85+
pf = info->pixel_format;
86+
87+
efi_bs_call(free_pool, info);
88+
89+
if (pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX) {
90+
efi_printk("Invalid PixelFormat\n");
91+
return cur_mode;
92+
}
93+
94+
return cmdline.mode;
95+
}
96+
97+
static void set_mode(efi_graphics_output_protocol_t *gop)
98+
{
99+
efi_graphics_output_protocol_mode_t *mode;
100+
u32 cur_mode, new_mode;
101+
102+
switch (cmdline.option) {
103+
case EFI_CMDLINE_MODE_NUM:
104+
new_mode = choose_mode_modenum(gop);
105+
break;
106+
default:
107+
return;
108+
}
109+
110+
mode = efi_table_attr(gop, mode);
111+
cur_mode = efi_table_attr(mode, mode);
112+
113+
if (new_mode == cur_mode)
114+
return;
115+
116+
if (efi_call_proto(gop, set_mode, new_mode) != EFI_SUCCESS)
117+
efi_printk("Failed to set requested mode\n");
118+
}
119+
16120
static void find_bits(u32 mask, u8 *pos, u8 *size)
17121
{
18122
if (!mask) {
@@ -124,6 +228,9 @@ static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
124228
if (!gop)
125229
return EFI_NOT_FOUND;
126230

231+
/* Change mode if requested */
232+
set_mode(gop);
233+
127234
/* EFI framebuffer */
128235
mode = efi_table_attr(gop, mode);
129236
info = efi_table_attr(mode, info);

0 commit comments

Comments
 (0)