1 // SPDX-License-Identifier: GPL-2.0 2 /* ----------------------------------------------------------------------- 3 * 4 * Copyright 2011 Intel Corporation; author Matt Fleming 5 * 6 * ----------------------------------------------------------------------- */ 7 8 #include <linux/bitops.h> 9 #include <linux/efi.h> 10 #include <linux/screen_info.h> 11 #include <linux/string.h> 12 #include <asm/efi.h> 13 #include <asm/setup.h> 14 15 #include "efistub.h" 16 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 120 static void find_bits(u32 mask, u8 *pos, u8 *size) 121 { 122 if (!mask) { 123 *pos = *size = 0; 124 return; 125 } 126 127 /* UEFI spec guarantees that the set bits are contiguous */ 128 *pos = __ffs(mask); 129 *size = __fls(mask) - *pos + 1; 130 } 131 132 static void 133 setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line, 134 efi_pixel_bitmask_t pixel_info, int pixel_format) 135 { 136 if (pixel_format == PIXEL_BIT_MASK) { 137 find_bits(pixel_info.red_mask, 138 &si->red_pos, &si->red_size); 139 find_bits(pixel_info.green_mask, 140 &si->green_pos, &si->green_size); 141 find_bits(pixel_info.blue_mask, 142 &si->blue_pos, &si->blue_size); 143 find_bits(pixel_info.reserved_mask, 144 &si->rsvd_pos, &si->rsvd_size); 145 si->lfb_depth = si->red_size + si->green_size + 146 si->blue_size + si->rsvd_size; 147 si->lfb_linelength = (pixels_per_scan_line * si->lfb_depth) / 8; 148 } else { 149 if (pixel_format == PIXEL_RGB_RESERVED_8BIT_PER_COLOR) { 150 si->red_pos = 0; 151 si->blue_pos = 16; 152 } else /* PIXEL_BGR_RESERVED_8BIT_PER_COLOR */ { 153 si->blue_pos = 0; 154 si->red_pos = 16; 155 } 156 157 si->green_pos = 8; 158 si->rsvd_pos = 24; 159 si->red_size = si->green_size = 160 si->blue_size = si->rsvd_size = 8; 161 162 si->lfb_depth = 32; 163 si->lfb_linelength = pixels_per_scan_line * 4; 164 } 165 } 166 167 static efi_graphics_output_protocol_t * 168 find_gop(efi_guid_t *proto, unsigned long size, void **handles) 169 { 170 efi_graphics_output_protocol_t *first_gop; 171 efi_handle_t h; 172 int i; 173 174 first_gop = NULL; 175 176 for_each_efi_handle(h, handles, size, i) { 177 efi_status_t status; 178 179 efi_graphics_output_protocol_t *gop; 180 efi_graphics_output_protocol_mode_t *mode; 181 efi_graphics_output_mode_info_t *info; 182 183 efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID; 184 void *dummy = NULL; 185 186 status = efi_bs_call(handle_protocol, h, proto, (void **)&gop); 187 if (status != EFI_SUCCESS) 188 continue; 189 190 mode = efi_table_attr(gop, mode); 191 info = efi_table_attr(mode, info); 192 if (info->pixel_format == PIXEL_BLT_ONLY || 193 info->pixel_format >= PIXEL_FORMAT_MAX) 194 continue; 195 196 /* 197 * Systems that use the UEFI Console Splitter may 198 * provide multiple GOP devices, not all of which are 199 * backed by real hardware. The workaround is to search 200 * for a GOP implementing the ConOut protocol, and if 201 * one isn't found, to just fall back to the first GOP. 202 * 203 * Once we've found a GOP supporting ConOut, 204 * don't bother looking any further. 205 */ 206 status = efi_bs_call(handle_protocol, h, &conout_proto, &dummy); 207 if (status == EFI_SUCCESS) 208 return gop; 209 210 if (!first_gop) 211 first_gop = gop; 212 } 213 214 return first_gop; 215 } 216 217 static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto, 218 unsigned long size, void **handles) 219 { 220 efi_graphics_output_protocol_t *gop; 221 efi_graphics_output_protocol_mode_t *mode; 222 efi_graphics_output_mode_info_t *info; 223 efi_physical_addr_t fb_base; 224 225 gop = find_gop(proto, size, handles); 226 227 /* Did we find any GOPs? */ 228 if (!gop) 229 return EFI_NOT_FOUND; 230 231 /* Change mode if requested */ 232 set_mode(gop); 233 234 /* EFI framebuffer */ 235 mode = efi_table_attr(gop, mode); 236 info = efi_table_attr(mode, info); 237 238 si->orig_video_isVGA = VIDEO_TYPE_EFI; 239 240 si->lfb_width = info->horizontal_resolution; 241 si->lfb_height = info->vertical_resolution; 242 243 fb_base = efi_table_attr(mode, frame_buffer_base); 244 si->lfb_base = lower_32_bits(fb_base); 245 si->ext_lfb_base = upper_32_bits(fb_base); 246 if (si->ext_lfb_base) 247 si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE; 248 249 si->pages = 1; 250 251 setup_pixel_info(si, info->pixels_per_scan_line, 252 info->pixel_information, info->pixel_format); 253 254 si->lfb_size = si->lfb_linelength * si->lfb_height; 255 256 si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS; 257 258 return EFI_SUCCESS; 259 } 260 261 /* 262 * See if we have Graphics Output Protocol 263 */ 264 efi_status_t efi_setup_gop(struct screen_info *si, efi_guid_t *proto, 265 unsigned long size) 266 { 267 efi_status_t status; 268 void **gop_handle = NULL; 269 270 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size, 271 (void **)&gop_handle); 272 if (status != EFI_SUCCESS) 273 return status; 274 275 status = efi_bs_call(locate_handle, EFI_LOCATE_BY_PROTOCOL, proto, NULL, 276 &size, gop_handle); 277 if (status != EFI_SUCCESS) 278 goto free_handle; 279 280 status = setup_gop(si, proto, size, gop_handle); 281 282 free_handle: 283 efi_bs_call(free_pool, gop_handle); 284 return status; 285 } 286