efi/gop: Allow automatically choosing the best mode
Add the ability to automatically pick the highest resolution video mode (defined as the product of vertical and horizontal resolution) by using a command-line argument of the form video=efifb:auto If there are multiple modes with the highest resolution, pick one with the highest color depth. Signed-off-by: Arvind Sankar <nivedita@alum.mit.edu> Link: https://lore.kernel.org/r/20200328160601.378299-2-nivedita@alum.mit.edu Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
This commit is contained in:
parent
9a1663bc4d
commit
45d97a749e
@ -57,4 +57,10 @@ mode=n
|
|||||||
"rgb" or "bgr" to match specifically those pixel formats, or a number
|
"rgb" or "bgr" to match specifically those pixel formats, or a number
|
||||||
for a mode with matching bits per pixel.
|
for a mode with matching bits per pixel.
|
||||||
|
|
||||||
|
auto
|
||||||
|
The EFI stub will choose the mode with the highest resolution (product
|
||||||
|
of horizontal and vertical resolution). If there are multiple modes
|
||||||
|
with the highest resolution, it will choose one with the highest color
|
||||||
|
depth.
|
||||||
|
|
||||||
Edgar Hucek <gimli@dark-green.com>
|
Edgar Hucek <gimli@dark-green.com>
|
||||||
|
@ -18,7 +18,8 @@
|
|||||||
enum efi_cmdline_option {
|
enum efi_cmdline_option {
|
||||||
EFI_CMDLINE_NONE,
|
EFI_CMDLINE_NONE,
|
||||||
EFI_CMDLINE_MODE_NUM,
|
EFI_CMDLINE_MODE_NUM,
|
||||||
EFI_CMDLINE_RES
|
EFI_CMDLINE_RES,
|
||||||
|
EFI_CMDLINE_AUTO
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
@ -86,6 +87,19 @@ static bool parse_res(char *option, char **next)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool parse_auto(char *option, char **next)
|
||||||
|
{
|
||||||
|
if (!strstarts(option, "auto"))
|
||||||
|
return false;
|
||||||
|
option += strlen("auto");
|
||||||
|
if (*option && *option++ != ',')
|
||||||
|
return false;
|
||||||
|
cmdline.option = EFI_CMDLINE_AUTO;
|
||||||
|
|
||||||
|
*next = option;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void efi_parse_option_graphics(char *option)
|
void efi_parse_option_graphics(char *option)
|
||||||
{
|
{
|
||||||
while (*option) {
|
while (*option) {
|
||||||
@ -93,6 +107,8 @@ void efi_parse_option_graphics(char *option)
|
|||||||
continue;
|
continue;
|
||||||
if (parse_res(option, &option))
|
if (parse_res(option, &option))
|
||||||
continue;
|
continue;
|
||||||
|
if (parse_auto(option, &option))
|
||||||
|
continue;
|
||||||
|
|
||||||
while (*option && *option++ != ',')
|
while (*option && *option++ != ',')
|
||||||
;
|
;
|
||||||
@ -211,6 +227,69 @@ static u32 choose_mode_res(efi_graphics_output_protocol_t *gop)
|
|||||||
return cur_mode;
|
return cur_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 choose_mode_auto(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, best_mode, area;
|
||||||
|
u8 depth;
|
||||||
|
int pf;
|
||||||
|
efi_pixel_bitmask_t pi;
|
||||||
|
u32 m, w, h, a;
|
||||||
|
u8 d;
|
||||||
|
|
||||||
|
mode = efi_table_attr(gop, mode);
|
||||||
|
|
||||||
|
cur_mode = efi_table_attr(mode, mode);
|
||||||
|
max_mode = efi_table_attr(mode, max_mode);
|
||||||
|
|
||||||
|
info = efi_table_attr(mode, info);
|
||||||
|
|
||||||
|
pf = info->pixel_format;
|
||||||
|
pi = info->pixel_information;
|
||||||
|
w = info->horizontal_resolution;
|
||||||
|
h = info->vertical_resolution;
|
||||||
|
|
||||||
|
best_mode = cur_mode;
|
||||||
|
area = w * h;
|
||||||
|
depth = pixel_bpp(pf, pi);
|
||||||
|
|
||||||
|
for (m = 0; m < max_mode; m++) {
|
||||||
|
if (m == cur_mode)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
status = efi_call_proto(gop, query_mode, m,
|
||||||
|
&info_size, &info);
|
||||||
|
if (status != EFI_SUCCESS)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pf = info->pixel_format;
|
||||||
|
pi = info->pixel_information;
|
||||||
|
w = info->horizontal_resolution;
|
||||||
|
h = info->vertical_resolution;
|
||||||
|
|
||||||
|
efi_bs_call(free_pool, info);
|
||||||
|
|
||||||
|
if (pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX)
|
||||||
|
continue;
|
||||||
|
a = w * h;
|
||||||
|
if (a < area)
|
||||||
|
continue;
|
||||||
|
d = pixel_bpp(pf, pi);
|
||||||
|
if (a > area || d > depth) {
|
||||||
|
best_mode = m;
|
||||||
|
area = a;
|
||||||
|
depth = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return best_mode;
|
||||||
|
}
|
||||||
|
|
||||||
static void set_mode(efi_graphics_output_protocol_t *gop)
|
static void set_mode(efi_graphics_output_protocol_t *gop)
|
||||||
{
|
{
|
||||||
efi_graphics_output_protocol_mode_t *mode;
|
efi_graphics_output_protocol_mode_t *mode;
|
||||||
@ -223,6 +302,9 @@ static void set_mode(efi_graphics_output_protocol_t *gop)
|
|||||||
case EFI_CMDLINE_RES:
|
case EFI_CMDLINE_RES:
|
||||||
new_mode = choose_mode_res(gop);
|
new_mode = choose_mode_res(gop);
|
||||||
break;
|
break;
|
||||||
|
case EFI_CMDLINE_AUTO:
|
||||||
|
new_mode = choose_mode_auto(gop);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user