]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blob - drivers/firmware/efi/libstub/gop.c
efi/gop: Allow specifying mode number on command line
[mirror_ubuntu-hirsute-kernel.git] / drivers / firmware / efi / libstub / gop.c
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 }