14febfb8dSArd Biesheuvel // SPDX-License-Identifier: GPL-2.0 2fc372064SArd Biesheuvel /* ----------------------------------------------------------------------- 3fc372064SArd Biesheuvel * 4fc372064SArd Biesheuvel * Copyright 2011 Intel Corporation; author Matt Fleming 5fc372064SArd Biesheuvel * 6fc372064SArd Biesheuvel * ----------------------------------------------------------------------- */ 7fc372064SArd Biesheuvel 89867fc9dSArvind Sankar #include <linux/bitops.h> 9d9ff0323SArvind Sankar #include <linux/ctype.h> 10fc372064SArd Biesheuvel #include <linux/efi.h> 11fc372064SArd Biesheuvel #include <linux/screen_info.h> 12fffb6804SArvind Sankar #include <linux/string.h> 13fc372064SArd Biesheuvel #include <asm/efi.h> 14fc372064SArd Biesheuvel #include <asm/setup.h> 15fc372064SArd Biesheuvel 162fcdad2aSArd Biesheuvel #include "efistub.h" 172fcdad2aSArd Biesheuvel 18fffb6804SArvind Sankar enum efi_cmdline_option { 19fffb6804SArvind Sankar EFI_CMDLINE_NONE, 20fffb6804SArvind Sankar EFI_CMDLINE_MODE_NUM, 2145d97a74SArvind Sankar EFI_CMDLINE_RES, 2245d97a74SArvind Sankar EFI_CMDLINE_AUTO 23fffb6804SArvind Sankar }; 24fffb6804SArvind Sankar 25fffb6804SArvind Sankar static struct { 26fffb6804SArvind Sankar enum efi_cmdline_option option; 27d9ff0323SArvind Sankar union { 28fffb6804SArvind Sankar u32 mode; 29d9ff0323SArvind Sankar struct { 30d9ff0323SArvind Sankar u32 width, height; 319a1663bcSArvind Sankar int format; 329a1663bcSArvind Sankar u8 depth; 33d9ff0323SArvind Sankar } res; 34d9ff0323SArvind Sankar }; 3554439370SArvind Sankar } cmdline = { .option = EFI_CMDLINE_NONE }; 36fffb6804SArvind Sankar 37fffb6804SArvind Sankar static bool parse_modenum(char *option, char **next) 38fffb6804SArvind Sankar { 39fffb6804SArvind Sankar u32 m; 40fffb6804SArvind Sankar 41fffb6804SArvind Sankar if (!strstarts(option, "mode=")) 42fffb6804SArvind Sankar return false; 43fffb6804SArvind Sankar option += strlen("mode="); 44fffb6804SArvind Sankar m = simple_strtoull(option, &option, 0); 45fffb6804SArvind Sankar if (*option && *option++ != ',') 46fffb6804SArvind Sankar return false; 47fffb6804SArvind Sankar cmdline.option = EFI_CMDLINE_MODE_NUM; 48fffb6804SArvind Sankar cmdline.mode = m; 49fffb6804SArvind Sankar 50fffb6804SArvind Sankar *next = option; 51fffb6804SArvind Sankar return true; 52fffb6804SArvind Sankar } 53fffb6804SArvind Sankar 54d9ff0323SArvind Sankar static bool parse_res(char *option, char **next) 55d9ff0323SArvind Sankar { 569a1663bcSArvind Sankar u32 w, h, d = 0; 579a1663bcSArvind Sankar int pf = -1; 58d9ff0323SArvind Sankar 59d9ff0323SArvind Sankar if (!isdigit(*option)) 60d9ff0323SArvind Sankar return false; 61d9ff0323SArvind Sankar w = simple_strtoull(option, &option, 10); 62d9ff0323SArvind Sankar if (*option++ != 'x' || !isdigit(*option)) 63d9ff0323SArvind Sankar return false; 64d9ff0323SArvind Sankar h = simple_strtoull(option, &option, 10); 659a1663bcSArvind Sankar if (*option == '-') { 669a1663bcSArvind Sankar option++; 679a1663bcSArvind Sankar if (strstarts(option, "rgb")) { 689a1663bcSArvind Sankar option += strlen("rgb"); 699a1663bcSArvind Sankar pf = PIXEL_RGB_RESERVED_8BIT_PER_COLOR; 709a1663bcSArvind Sankar } else if (strstarts(option, "bgr")) { 719a1663bcSArvind Sankar option += strlen("bgr"); 729a1663bcSArvind Sankar pf = PIXEL_BGR_RESERVED_8BIT_PER_COLOR; 739a1663bcSArvind Sankar } else if (isdigit(*option)) 749a1663bcSArvind Sankar d = simple_strtoull(option, &option, 10); 759a1663bcSArvind Sankar else 769a1663bcSArvind Sankar return false; 779a1663bcSArvind Sankar } 78d9ff0323SArvind Sankar if (*option && *option++ != ',') 79d9ff0323SArvind Sankar return false; 80d9ff0323SArvind Sankar cmdline.option = EFI_CMDLINE_RES; 81d9ff0323SArvind Sankar cmdline.res.width = w; 82d9ff0323SArvind Sankar cmdline.res.height = h; 839a1663bcSArvind Sankar cmdline.res.format = pf; 849a1663bcSArvind Sankar cmdline.res.depth = d; 85d9ff0323SArvind Sankar 86d9ff0323SArvind Sankar *next = option; 87d9ff0323SArvind Sankar return true; 88d9ff0323SArvind Sankar } 89d9ff0323SArvind Sankar 9045d97a74SArvind Sankar static bool parse_auto(char *option, char **next) 9145d97a74SArvind Sankar { 9245d97a74SArvind Sankar if (!strstarts(option, "auto")) 9345d97a74SArvind Sankar return false; 9445d97a74SArvind Sankar option += strlen("auto"); 9545d97a74SArvind Sankar if (*option && *option++ != ',') 9645d97a74SArvind Sankar return false; 9745d97a74SArvind Sankar cmdline.option = EFI_CMDLINE_AUTO; 9845d97a74SArvind Sankar 9945d97a74SArvind Sankar *next = option; 10045d97a74SArvind Sankar return true; 10145d97a74SArvind Sankar } 10245d97a74SArvind Sankar 103fffb6804SArvind Sankar void efi_parse_option_graphics(char *option) 104fffb6804SArvind Sankar { 105fffb6804SArvind Sankar while (*option) { 106fffb6804SArvind Sankar if (parse_modenum(option, &option)) 107fffb6804SArvind Sankar continue; 108d9ff0323SArvind Sankar if (parse_res(option, &option)) 109d9ff0323SArvind Sankar continue; 11045d97a74SArvind Sankar if (parse_auto(option, &option)) 11145d97a74SArvind Sankar continue; 112fffb6804SArvind Sankar 113fffb6804SArvind Sankar while (*option && *option++ != ',') 114fffb6804SArvind Sankar ; 115fffb6804SArvind Sankar } 116fffb6804SArvind Sankar } 117fffb6804SArvind Sankar 118fffb6804SArvind Sankar static u32 choose_mode_modenum(efi_graphics_output_protocol_t *gop) 119fffb6804SArvind Sankar { 120fffb6804SArvind Sankar efi_status_t status; 121fffb6804SArvind Sankar 122fffb6804SArvind Sankar efi_graphics_output_protocol_mode_t *mode; 123fffb6804SArvind Sankar efi_graphics_output_mode_info_t *info; 124fffb6804SArvind Sankar unsigned long info_size; 125fffb6804SArvind Sankar 126fffb6804SArvind Sankar u32 max_mode, cur_mode; 127fffb6804SArvind Sankar int pf; 128fffb6804SArvind Sankar 129fffb6804SArvind Sankar mode = efi_table_attr(gop, mode); 130fffb6804SArvind Sankar 131fffb6804SArvind Sankar cur_mode = efi_table_attr(mode, mode); 132fffb6804SArvind Sankar if (cmdline.mode == cur_mode) 133fffb6804SArvind Sankar return cur_mode; 134fffb6804SArvind Sankar 135fffb6804SArvind Sankar max_mode = efi_table_attr(mode, max_mode); 136fffb6804SArvind Sankar if (cmdline.mode >= max_mode) { 13761eac6d9SArvind Sankar efi_err("Requested mode is invalid\n"); 138fffb6804SArvind Sankar return cur_mode; 139fffb6804SArvind Sankar } 140fffb6804SArvind Sankar 141fffb6804SArvind Sankar status = efi_call_proto(gop, query_mode, cmdline.mode, 142fffb6804SArvind Sankar &info_size, &info); 143fffb6804SArvind Sankar if (status != EFI_SUCCESS) { 14461eac6d9SArvind Sankar efi_err("Couldn't get mode information\n"); 145fffb6804SArvind Sankar return cur_mode; 146fffb6804SArvind Sankar } 147fffb6804SArvind Sankar 148fffb6804SArvind Sankar pf = info->pixel_format; 149fffb6804SArvind Sankar 150fffb6804SArvind Sankar efi_bs_call(free_pool, info); 151fffb6804SArvind Sankar 152fffb6804SArvind Sankar if (pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX) { 15361eac6d9SArvind Sankar efi_err("Invalid PixelFormat\n"); 154fffb6804SArvind Sankar return cur_mode; 155fffb6804SArvind Sankar } 156fffb6804SArvind Sankar 157fffb6804SArvind Sankar return cmdline.mode; 158fffb6804SArvind Sankar } 159fffb6804SArvind Sankar 1609a1663bcSArvind Sankar static u8 pixel_bpp(int pixel_format, efi_pixel_bitmask_t pixel_info) 1619a1663bcSArvind Sankar { 1629a1663bcSArvind Sankar if (pixel_format == PIXEL_BIT_MASK) { 1639a1663bcSArvind Sankar u32 mask = pixel_info.red_mask | pixel_info.green_mask | 1649a1663bcSArvind Sankar pixel_info.blue_mask | pixel_info.reserved_mask; 1659a1663bcSArvind Sankar if (!mask) 1669a1663bcSArvind Sankar return 0; 1679a1663bcSArvind Sankar return __fls(mask) - __ffs(mask) + 1; 1689a1663bcSArvind Sankar } else 1699a1663bcSArvind Sankar return 32; 1709a1663bcSArvind Sankar } 1719a1663bcSArvind Sankar 172d9ff0323SArvind Sankar static u32 choose_mode_res(efi_graphics_output_protocol_t *gop) 173d9ff0323SArvind Sankar { 174d9ff0323SArvind Sankar efi_status_t status; 175d9ff0323SArvind Sankar 176d9ff0323SArvind Sankar efi_graphics_output_protocol_mode_t *mode; 177d9ff0323SArvind Sankar efi_graphics_output_mode_info_t *info; 178d9ff0323SArvind Sankar unsigned long info_size; 179d9ff0323SArvind Sankar 180d9ff0323SArvind Sankar u32 max_mode, cur_mode; 181d9ff0323SArvind Sankar int pf; 1829a1663bcSArvind Sankar efi_pixel_bitmask_t pi; 183d9ff0323SArvind Sankar u32 m, w, h; 184d9ff0323SArvind Sankar 185d9ff0323SArvind Sankar mode = efi_table_attr(gop, mode); 186d9ff0323SArvind Sankar 187d9ff0323SArvind Sankar cur_mode = efi_table_attr(mode, mode); 188d9ff0323SArvind Sankar info = efi_table_attr(mode, info); 1899a1663bcSArvind Sankar pf = info->pixel_format; 1909a1663bcSArvind Sankar pi = info->pixel_information; 191d9ff0323SArvind Sankar w = info->horizontal_resolution; 192d9ff0323SArvind Sankar h = info->vertical_resolution; 193d9ff0323SArvind Sankar 1949a1663bcSArvind Sankar if (w == cmdline.res.width && h == cmdline.res.height && 1959a1663bcSArvind Sankar (cmdline.res.format < 0 || cmdline.res.format == pf) && 1969a1663bcSArvind Sankar (!cmdline.res.depth || cmdline.res.depth == pixel_bpp(pf, pi))) 197d9ff0323SArvind Sankar return cur_mode; 198d9ff0323SArvind Sankar 199d9ff0323SArvind Sankar max_mode = efi_table_attr(mode, max_mode); 200d9ff0323SArvind Sankar 201d9ff0323SArvind Sankar for (m = 0; m < max_mode; m++) { 202d9ff0323SArvind Sankar if (m == cur_mode) 203d9ff0323SArvind Sankar continue; 204d9ff0323SArvind Sankar 205d9ff0323SArvind Sankar status = efi_call_proto(gop, query_mode, m, 206d9ff0323SArvind Sankar &info_size, &info); 207d9ff0323SArvind Sankar if (status != EFI_SUCCESS) 208d9ff0323SArvind Sankar continue; 209d9ff0323SArvind Sankar 210d9ff0323SArvind Sankar pf = info->pixel_format; 2119a1663bcSArvind Sankar pi = info->pixel_information; 212d9ff0323SArvind Sankar w = info->horizontal_resolution; 213d9ff0323SArvind Sankar h = info->vertical_resolution; 214d9ff0323SArvind Sankar 215d9ff0323SArvind Sankar efi_bs_call(free_pool, info); 216d9ff0323SArvind Sankar 217d9ff0323SArvind Sankar if (pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX) 218d9ff0323SArvind Sankar continue; 2199a1663bcSArvind Sankar if (w == cmdline.res.width && h == cmdline.res.height && 2209a1663bcSArvind Sankar (cmdline.res.format < 0 || cmdline.res.format == pf) && 2219a1663bcSArvind Sankar (!cmdline.res.depth || cmdline.res.depth == pixel_bpp(pf, pi))) 222d9ff0323SArvind Sankar return m; 223d9ff0323SArvind Sankar } 224d9ff0323SArvind Sankar 22561eac6d9SArvind Sankar efi_err("Couldn't find requested mode\n"); 226d9ff0323SArvind Sankar 227d9ff0323SArvind Sankar return cur_mode; 228d9ff0323SArvind Sankar } 229d9ff0323SArvind Sankar 23045d97a74SArvind Sankar static u32 choose_mode_auto(efi_graphics_output_protocol_t *gop) 23145d97a74SArvind Sankar { 23245d97a74SArvind Sankar efi_status_t status; 23345d97a74SArvind Sankar 23445d97a74SArvind Sankar efi_graphics_output_protocol_mode_t *mode; 23545d97a74SArvind Sankar efi_graphics_output_mode_info_t *info; 23645d97a74SArvind Sankar unsigned long info_size; 23745d97a74SArvind Sankar 23845d97a74SArvind Sankar u32 max_mode, cur_mode, best_mode, area; 23945d97a74SArvind Sankar u8 depth; 24045d97a74SArvind Sankar int pf; 24145d97a74SArvind Sankar efi_pixel_bitmask_t pi; 24245d97a74SArvind Sankar u32 m, w, h, a; 24345d97a74SArvind Sankar u8 d; 24445d97a74SArvind Sankar 24545d97a74SArvind Sankar mode = efi_table_attr(gop, mode); 24645d97a74SArvind Sankar 24745d97a74SArvind Sankar cur_mode = efi_table_attr(mode, mode); 24845d97a74SArvind Sankar max_mode = efi_table_attr(mode, max_mode); 24945d97a74SArvind Sankar 25045d97a74SArvind Sankar info = efi_table_attr(mode, info); 25145d97a74SArvind Sankar 25245d97a74SArvind Sankar pf = info->pixel_format; 25345d97a74SArvind Sankar pi = info->pixel_information; 25445d97a74SArvind Sankar w = info->horizontal_resolution; 25545d97a74SArvind Sankar h = info->vertical_resolution; 25645d97a74SArvind Sankar 25745d97a74SArvind Sankar best_mode = cur_mode; 25845d97a74SArvind Sankar area = w * h; 25945d97a74SArvind Sankar depth = pixel_bpp(pf, pi); 26045d97a74SArvind Sankar 26145d97a74SArvind Sankar for (m = 0; m < max_mode; m++) { 26245d97a74SArvind Sankar if (m == cur_mode) 26345d97a74SArvind Sankar continue; 26445d97a74SArvind Sankar 26545d97a74SArvind Sankar status = efi_call_proto(gop, query_mode, m, 26645d97a74SArvind Sankar &info_size, &info); 26745d97a74SArvind Sankar if (status != EFI_SUCCESS) 26845d97a74SArvind Sankar continue; 26945d97a74SArvind Sankar 27045d97a74SArvind Sankar pf = info->pixel_format; 27145d97a74SArvind Sankar pi = info->pixel_information; 27245d97a74SArvind Sankar w = info->horizontal_resolution; 27345d97a74SArvind Sankar h = info->vertical_resolution; 27445d97a74SArvind Sankar 27545d97a74SArvind Sankar efi_bs_call(free_pool, info); 27645d97a74SArvind Sankar 27745d97a74SArvind Sankar if (pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX) 27845d97a74SArvind Sankar continue; 27945d97a74SArvind Sankar a = w * h; 28045d97a74SArvind Sankar if (a < area) 28145d97a74SArvind Sankar continue; 28245d97a74SArvind Sankar d = pixel_bpp(pf, pi); 28345d97a74SArvind Sankar if (a > area || d > depth) { 28445d97a74SArvind Sankar best_mode = m; 28545d97a74SArvind Sankar area = a; 28645d97a74SArvind Sankar depth = d; 28745d97a74SArvind Sankar } 28845d97a74SArvind Sankar } 28945d97a74SArvind Sankar 29045d97a74SArvind Sankar return best_mode; 29145d97a74SArvind Sankar } 29245d97a74SArvind Sankar 293fffb6804SArvind Sankar static void set_mode(efi_graphics_output_protocol_t *gop) 294fffb6804SArvind Sankar { 295fffb6804SArvind Sankar efi_graphics_output_protocol_mode_t *mode; 296fffb6804SArvind Sankar u32 cur_mode, new_mode; 297fffb6804SArvind Sankar 298fffb6804SArvind Sankar switch (cmdline.option) { 299fffb6804SArvind Sankar case EFI_CMDLINE_MODE_NUM: 300fffb6804SArvind Sankar new_mode = choose_mode_modenum(gop); 301fffb6804SArvind Sankar break; 302d9ff0323SArvind Sankar case EFI_CMDLINE_RES: 303d9ff0323SArvind Sankar new_mode = choose_mode_res(gop); 304d9ff0323SArvind Sankar break; 30545d97a74SArvind Sankar case EFI_CMDLINE_AUTO: 30645d97a74SArvind Sankar new_mode = choose_mode_auto(gop); 30745d97a74SArvind Sankar break; 308fffb6804SArvind Sankar default: 309fffb6804SArvind Sankar return; 310fffb6804SArvind Sankar } 311fffb6804SArvind Sankar 312fffb6804SArvind Sankar mode = efi_table_attr(gop, mode); 313fffb6804SArvind Sankar cur_mode = efi_table_attr(mode, mode); 314fffb6804SArvind Sankar 315fffb6804SArvind Sankar if (new_mode == cur_mode) 316fffb6804SArvind Sankar return; 317fffb6804SArvind Sankar 318fffb6804SArvind Sankar if (efi_call_proto(gop, set_mode, new_mode) != EFI_SUCCESS) 31961eac6d9SArvind Sankar efi_err("Failed to set requested mode\n"); 320fffb6804SArvind Sankar } 321fffb6804SArvind Sankar 3229867fc9dSArvind Sankar static void find_bits(u32 mask, u8 *pos, u8 *size) 323fc372064SArd Biesheuvel { 3249867fc9dSArvind Sankar if (!mask) { 3259867fc9dSArvind Sankar *pos = *size = 0; 3269867fc9dSArvind Sankar return; 327fc372064SArd Biesheuvel } 328fc372064SArd Biesheuvel 3299867fc9dSArvind Sankar /* UEFI spec guarantees that the set bits are contiguous */ 3309867fc9dSArvind Sankar *pos = __ffs(mask); 3319867fc9dSArvind Sankar *size = __fls(mask) - *pos + 1; 332fc372064SArd Biesheuvel } 333fc372064SArd Biesheuvel 334fc372064SArd Biesheuvel static void 335fc372064SArd Biesheuvel setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line, 33644c84b4aSArvind Sankar efi_pixel_bitmask_t pixel_info, int pixel_format) 337fc372064SArd Biesheuvel { 338d49fd4bbSArvind Sankar if (pixel_format == PIXEL_BIT_MASK) { 339d49fd4bbSArvind Sankar find_bits(pixel_info.red_mask, 340d49fd4bbSArvind Sankar &si->red_pos, &si->red_size); 341d49fd4bbSArvind Sankar find_bits(pixel_info.green_mask, 342d49fd4bbSArvind Sankar &si->green_pos, &si->green_size); 343d49fd4bbSArvind Sankar find_bits(pixel_info.blue_mask, 344d49fd4bbSArvind Sankar &si->blue_pos, &si->blue_size); 345d49fd4bbSArvind Sankar find_bits(pixel_info.reserved_mask, 346d49fd4bbSArvind Sankar &si->rsvd_pos, &si->rsvd_size); 347fc372064SArd Biesheuvel si->lfb_depth = si->red_size + si->green_size + 348fc372064SArd Biesheuvel si->blue_size + si->rsvd_size; 349fc372064SArd Biesheuvel si->lfb_linelength = (pixels_per_scan_line * si->lfb_depth) / 8; 350fc372064SArd Biesheuvel } else { 351d49fd4bbSArvind Sankar if (pixel_format == PIXEL_RGB_RESERVED_8BIT_PER_COLOR) { 352fc372064SArd Biesheuvel si->red_pos = 0; 353d49fd4bbSArvind Sankar si->blue_pos = 16; 354d49fd4bbSArvind Sankar } else /* PIXEL_BGR_RESERVED_8BIT_PER_COLOR */ { 355fc372064SArd Biesheuvel si->blue_pos = 0; 356d49fd4bbSArvind Sankar si->red_pos = 16; 357d49fd4bbSArvind Sankar } 358d49fd4bbSArvind Sankar 359d49fd4bbSArvind Sankar si->green_pos = 8; 360d49fd4bbSArvind Sankar si->rsvd_pos = 24; 361d49fd4bbSArvind Sankar si->red_size = si->green_size = 362d49fd4bbSArvind Sankar si->blue_size = si->rsvd_size = 8; 363d49fd4bbSArvind Sankar 364d49fd4bbSArvind Sankar si->lfb_depth = 32; 365d49fd4bbSArvind Sankar si->lfb_linelength = pixels_per_scan_line * 4; 366fc372064SArd Biesheuvel } 367fc372064SArd Biesheuvel } 368fc372064SArd Biesheuvel 369ecf53091SArvind Sankar static efi_graphics_output_protocol_t * 370ecf53091SArvind Sankar find_gop(efi_guid_t *proto, unsigned long size, void **handles) 371fc372064SArd Biesheuvel { 372e484c594SArvind Sankar efi_graphics_output_protocol_t *first_gop; 3732732ea0dSArd Biesheuvel efi_handle_t h; 374fc372064SArd Biesheuvel int i; 375fc372064SArd Biesheuvel 376fc372064SArd Biesheuvel first_gop = NULL; 377fc372064SArd Biesheuvel 3782732ea0dSArd Biesheuvel for_each_efi_handle(h, handles, size, i) { 379e484c594SArvind Sankar efi_status_t status; 380e484c594SArvind Sankar 381e484c594SArvind Sankar efi_graphics_output_protocol_t *gop; 382e484c594SArvind Sankar efi_graphics_output_protocol_mode_t *mode; 383e484c594SArvind Sankar efi_graphics_output_mode_info_t *info; 384e484c594SArvind Sankar 385fc372064SArd Biesheuvel efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID; 386fc372064SArd Biesheuvel void *dummy = NULL; 387fc372064SArd Biesheuvel 388966291f6SArd Biesheuvel status = efi_bs_call(handle_protocol, h, proto, (void **)&gop); 389fc372064SArd Biesheuvel if (status != EFI_SUCCESS) 390fc372064SArd Biesheuvel continue; 391fc372064SArd Biesheuvel 3928cd20797SArvind Sankar mode = efi_table_attr(gop, mode); 3938cd20797SArvind Sankar info = efi_table_attr(mode, info); 394d49fd4bbSArvind Sankar if (info->pixel_format == PIXEL_BLT_ONLY || 395d49fd4bbSArvind Sankar info->pixel_format >= PIXEL_FORMAT_MAX) 3968cd20797SArvind Sankar continue; 3978cd20797SArvind Sankar 398fc372064SArd Biesheuvel /* 399fc372064SArd Biesheuvel * Systems that use the UEFI Console Splitter may 400fc372064SArd Biesheuvel * provide multiple GOP devices, not all of which are 401fc372064SArd Biesheuvel * backed by real hardware. The workaround is to search 402fc372064SArd Biesheuvel * for a GOP implementing the ConOut protocol, and if 403fc372064SArd Biesheuvel * one isn't found, to just fall back to the first GOP. 4046327e6d0SArvind Sankar * 405fc372064SArd Biesheuvel * Once we've found a GOP supporting ConOut, 406fc372064SArd Biesheuvel * don't bother looking any further. 407fc372064SArd Biesheuvel */ 4088e0a22e2SArvind Sankar status = efi_bs_call(handle_protocol, h, &conout_proto, &dummy); 4098e0a22e2SArvind Sankar if (status == EFI_SUCCESS) 4108e0a22e2SArvind Sankar return gop; 4118e0a22e2SArvind Sankar 4128e0a22e2SArvind Sankar if (!first_gop) 4138de8788dSArvind Sankar first_gop = gop; 414fc372064SArd Biesheuvel } 415fc372064SArd Biesheuvel 416ecf53091SArvind Sankar return first_gop; 417ecf53091SArvind Sankar } 418ecf53091SArvind Sankar 419ecf53091SArvind Sankar static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto, 420ecf53091SArvind Sankar unsigned long size, void **handles) 421ecf53091SArvind Sankar { 422ecf53091SArvind Sankar efi_graphics_output_protocol_t *gop; 423ecf53091SArvind Sankar efi_graphics_output_protocol_mode_t *mode; 424e484c594SArvind Sankar efi_graphics_output_mode_info_t *info; 425ecf53091SArvind Sankar 426ecf53091SArvind Sankar gop = find_gop(proto, size, handles); 427ecf53091SArvind Sankar 428fc372064SArd Biesheuvel /* Did we find any GOPs? */ 429ecf53091SArvind Sankar if (!gop) 4306fc3cec3SArvind Sankar return EFI_NOT_FOUND; 431fc372064SArd Biesheuvel 432fffb6804SArvind Sankar /* Change mode if requested */ 433fffb6804SArvind Sankar set_mode(gop); 434fffb6804SArvind Sankar 435fc372064SArd Biesheuvel /* EFI framebuffer */ 436ecf53091SArvind Sankar mode = efi_table_attr(gop, mode); 4376327e6d0SArvind Sankar info = efi_table_attr(mode, info); 4386327e6d0SArvind Sankar 439fc372064SArd Biesheuvel si->orig_video_isVGA = VIDEO_TYPE_EFI; 440fc372064SArd Biesheuvel 4416327e6d0SArvind Sankar si->lfb_width = info->horizontal_resolution; 4426327e6d0SArvind Sankar si->lfb_height = info->vertical_resolution; 443fc372064SArd Biesheuvel 444eed4e019SArvind Sankar efi_set_u64_split(efi_table_attr(mode, frame_buffer_base), 445eed4e019SArvind Sankar &si->lfb_base, &si->ext_lfb_base); 4466327e6d0SArvind Sankar if (si->ext_lfb_base) 447fc372064SArd Biesheuvel si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE; 448fc372064SArd Biesheuvel 449fc372064SArd Biesheuvel si->pages = 1; 450fc372064SArd Biesheuvel 4516327e6d0SArvind Sankar setup_pixel_info(si, info->pixels_per_scan_line, 4526327e6d0SArvind Sankar info->pixel_information, info->pixel_format); 453fc372064SArd Biesheuvel 454fc372064SArd Biesheuvel si->lfb_size = si->lfb_linelength * si->lfb_height; 455fc372064SArd Biesheuvel 456fc372064SArd Biesheuvel si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS; 4576fc3cec3SArvind Sankar 458dbd89c30SArvind Sankar return EFI_SUCCESS; 459fc372064SArd Biesheuvel } 460fc372064SArd Biesheuvel 461fc372064SArd Biesheuvel /* 462fc372064SArd Biesheuvel * See if we have Graphics Output Protocol 463fc372064SArd Biesheuvel */ 464cd33a5c1SArd Biesheuvel efi_status_t efi_setup_gop(struct screen_info *si, efi_guid_t *proto, 465fc372064SArd Biesheuvel unsigned long size) 466fc372064SArd Biesheuvel { 467fc372064SArd Biesheuvel efi_status_t status; 468fc372064SArd Biesheuvel void **gop_handle = NULL; 469fc372064SArd Biesheuvel 470966291f6SArd Biesheuvel status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size, 471966291f6SArd Biesheuvel (void **)&gop_handle); 472fc372064SArd Biesheuvel if (status != EFI_SUCCESS) 473fc372064SArd Biesheuvel return status; 474fc372064SArd Biesheuvel 475966291f6SArd Biesheuvel status = efi_bs_call(locate_handle, EFI_LOCATE_BY_PROTOCOL, proto, NULL, 476966291f6SArd Biesheuvel &size, gop_handle); 477fc372064SArd Biesheuvel if (status != EFI_SUCCESS) 478fc372064SArd Biesheuvel goto free_handle; 479fc372064SArd Biesheuvel 480cd33a5c1SArd Biesheuvel status = setup_gop(si, proto, size, gop_handle); 481fc372064SArd Biesheuvel 482fc372064SArd Biesheuvel free_handle: 483966291f6SArd Biesheuvel efi_bs_call(free_pool, gop_handle); 484fc372064SArd Biesheuvel return status; 485fc372064SArd Biesheuvel } 486