xref: /openbmc/linux/drivers/firmware/efi/libstub/gop.c (revision 9a1663bc)
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,
21d9ff0323SArvind Sankar 	EFI_CMDLINE_RES
22fffb6804SArvind Sankar };
23fffb6804SArvind Sankar 
24fffb6804SArvind Sankar static struct {
25fffb6804SArvind Sankar 	enum efi_cmdline_option option;
26d9ff0323SArvind Sankar 	union {
27fffb6804SArvind Sankar 		u32 mode;
28d9ff0323SArvind Sankar 		struct {
29d9ff0323SArvind Sankar 			u32 width, height;
309a1663bcSArvind Sankar 			int format;
319a1663bcSArvind Sankar 			u8 depth;
32d9ff0323SArvind Sankar 		} res;
33d9ff0323SArvind Sankar 	};
34fffb6804SArvind Sankar } cmdline __efistub_global = { .option = EFI_CMDLINE_NONE };
35fffb6804SArvind Sankar 
36fffb6804SArvind Sankar static bool parse_modenum(char *option, char **next)
37fffb6804SArvind Sankar {
38fffb6804SArvind Sankar 	u32 m;
39fffb6804SArvind Sankar 
40fffb6804SArvind Sankar 	if (!strstarts(option, "mode="))
41fffb6804SArvind Sankar 		return false;
42fffb6804SArvind Sankar 	option += strlen("mode=");
43fffb6804SArvind Sankar 	m = simple_strtoull(option, &option, 0);
44fffb6804SArvind Sankar 	if (*option && *option++ != ',')
45fffb6804SArvind Sankar 		return false;
46fffb6804SArvind Sankar 	cmdline.option = EFI_CMDLINE_MODE_NUM;
47fffb6804SArvind Sankar 	cmdline.mode   = m;
48fffb6804SArvind Sankar 
49fffb6804SArvind Sankar 	*next = option;
50fffb6804SArvind Sankar 	return true;
51fffb6804SArvind Sankar }
52fffb6804SArvind Sankar 
53d9ff0323SArvind Sankar static bool parse_res(char *option, char **next)
54d9ff0323SArvind Sankar {
559a1663bcSArvind Sankar 	u32 w, h, d = 0;
569a1663bcSArvind Sankar 	int pf = -1;
57d9ff0323SArvind Sankar 
58d9ff0323SArvind Sankar 	if (!isdigit(*option))
59d9ff0323SArvind Sankar 		return false;
60d9ff0323SArvind Sankar 	w = simple_strtoull(option, &option, 10);
61d9ff0323SArvind Sankar 	if (*option++ != 'x' || !isdigit(*option))
62d9ff0323SArvind Sankar 		return false;
63d9ff0323SArvind Sankar 	h = simple_strtoull(option, &option, 10);
649a1663bcSArvind Sankar 	if (*option == '-') {
659a1663bcSArvind Sankar 		option++;
669a1663bcSArvind Sankar 		if (strstarts(option, "rgb")) {
679a1663bcSArvind Sankar 			option += strlen("rgb");
689a1663bcSArvind Sankar 			pf = PIXEL_RGB_RESERVED_8BIT_PER_COLOR;
699a1663bcSArvind Sankar 		} else if (strstarts(option, "bgr")) {
709a1663bcSArvind Sankar 			option += strlen("bgr");
719a1663bcSArvind Sankar 			pf = PIXEL_BGR_RESERVED_8BIT_PER_COLOR;
729a1663bcSArvind Sankar 		} else if (isdigit(*option))
739a1663bcSArvind Sankar 			d = simple_strtoull(option, &option, 10);
749a1663bcSArvind Sankar 		else
759a1663bcSArvind Sankar 			return false;
769a1663bcSArvind Sankar 	}
77d9ff0323SArvind Sankar 	if (*option && *option++ != ',')
78d9ff0323SArvind Sankar 		return false;
79d9ff0323SArvind Sankar 	cmdline.option     = EFI_CMDLINE_RES;
80d9ff0323SArvind Sankar 	cmdline.res.width  = w;
81d9ff0323SArvind Sankar 	cmdline.res.height = h;
829a1663bcSArvind Sankar 	cmdline.res.format = pf;
839a1663bcSArvind Sankar 	cmdline.res.depth  = d;
84d9ff0323SArvind Sankar 
85d9ff0323SArvind Sankar 	*next = option;
86d9ff0323SArvind Sankar 	return true;
87d9ff0323SArvind Sankar }
88d9ff0323SArvind Sankar 
89fffb6804SArvind Sankar void efi_parse_option_graphics(char *option)
90fffb6804SArvind Sankar {
91fffb6804SArvind Sankar 	while (*option) {
92fffb6804SArvind Sankar 		if (parse_modenum(option, &option))
93fffb6804SArvind Sankar 			continue;
94d9ff0323SArvind Sankar 		if (parse_res(option, &option))
95d9ff0323SArvind Sankar 			continue;
96fffb6804SArvind Sankar 
97fffb6804SArvind Sankar 		while (*option && *option++ != ',')
98fffb6804SArvind Sankar 			;
99fffb6804SArvind Sankar 	}
100fffb6804SArvind Sankar }
101fffb6804SArvind Sankar 
102fffb6804SArvind Sankar static u32 choose_mode_modenum(efi_graphics_output_protocol_t *gop)
103fffb6804SArvind Sankar {
104fffb6804SArvind Sankar 	efi_status_t status;
105fffb6804SArvind Sankar 
106fffb6804SArvind Sankar 	efi_graphics_output_protocol_mode_t *mode;
107fffb6804SArvind Sankar 	efi_graphics_output_mode_info_t *info;
108fffb6804SArvind Sankar 	unsigned long info_size;
109fffb6804SArvind Sankar 
110fffb6804SArvind Sankar 	u32 max_mode, cur_mode;
111fffb6804SArvind Sankar 	int pf;
112fffb6804SArvind Sankar 
113fffb6804SArvind Sankar 	mode = efi_table_attr(gop, mode);
114fffb6804SArvind Sankar 
115fffb6804SArvind Sankar 	cur_mode = efi_table_attr(mode, mode);
116fffb6804SArvind Sankar 	if (cmdline.mode == cur_mode)
117fffb6804SArvind Sankar 		return cur_mode;
118fffb6804SArvind Sankar 
119fffb6804SArvind Sankar 	max_mode = efi_table_attr(mode, max_mode);
120fffb6804SArvind Sankar 	if (cmdline.mode >= max_mode) {
121fffb6804SArvind Sankar 		efi_printk("Requested mode is invalid\n");
122fffb6804SArvind Sankar 		return cur_mode;
123fffb6804SArvind Sankar 	}
124fffb6804SArvind Sankar 
125fffb6804SArvind Sankar 	status = efi_call_proto(gop, query_mode, cmdline.mode,
126fffb6804SArvind Sankar 				&info_size, &info);
127fffb6804SArvind Sankar 	if (status != EFI_SUCCESS) {
128fffb6804SArvind Sankar 		efi_printk("Couldn't get mode information\n");
129fffb6804SArvind Sankar 		return cur_mode;
130fffb6804SArvind Sankar 	}
131fffb6804SArvind Sankar 
132fffb6804SArvind Sankar 	pf = info->pixel_format;
133fffb6804SArvind Sankar 
134fffb6804SArvind Sankar 	efi_bs_call(free_pool, info);
135fffb6804SArvind Sankar 
136fffb6804SArvind Sankar 	if (pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX) {
137fffb6804SArvind Sankar 		efi_printk("Invalid PixelFormat\n");
138fffb6804SArvind Sankar 		return cur_mode;
139fffb6804SArvind Sankar 	}
140fffb6804SArvind Sankar 
141fffb6804SArvind Sankar 	return cmdline.mode;
142fffb6804SArvind Sankar }
143fffb6804SArvind Sankar 
1449a1663bcSArvind Sankar static u8 pixel_bpp(int pixel_format, efi_pixel_bitmask_t pixel_info)
1459a1663bcSArvind Sankar {
1469a1663bcSArvind Sankar 	if (pixel_format == PIXEL_BIT_MASK) {
1479a1663bcSArvind Sankar 		u32 mask = pixel_info.red_mask | pixel_info.green_mask |
1489a1663bcSArvind Sankar 			   pixel_info.blue_mask | pixel_info.reserved_mask;
1499a1663bcSArvind Sankar 		if (!mask)
1509a1663bcSArvind Sankar 			return 0;
1519a1663bcSArvind Sankar 		return __fls(mask) - __ffs(mask) + 1;
1529a1663bcSArvind Sankar 	} else
1539a1663bcSArvind Sankar 		return 32;
1549a1663bcSArvind Sankar }
1559a1663bcSArvind Sankar 
156d9ff0323SArvind Sankar static u32 choose_mode_res(efi_graphics_output_protocol_t *gop)
157d9ff0323SArvind Sankar {
158d9ff0323SArvind Sankar 	efi_status_t status;
159d9ff0323SArvind Sankar 
160d9ff0323SArvind Sankar 	efi_graphics_output_protocol_mode_t *mode;
161d9ff0323SArvind Sankar 	efi_graphics_output_mode_info_t *info;
162d9ff0323SArvind Sankar 	unsigned long info_size;
163d9ff0323SArvind Sankar 
164d9ff0323SArvind Sankar 	u32 max_mode, cur_mode;
165d9ff0323SArvind Sankar 	int pf;
1669a1663bcSArvind Sankar 	efi_pixel_bitmask_t pi;
167d9ff0323SArvind Sankar 	u32 m, w, h;
168d9ff0323SArvind Sankar 
169d9ff0323SArvind Sankar 	mode = efi_table_attr(gop, mode);
170d9ff0323SArvind Sankar 
171d9ff0323SArvind Sankar 	cur_mode = efi_table_attr(mode, mode);
172d9ff0323SArvind Sankar 	info = efi_table_attr(mode, info);
1739a1663bcSArvind Sankar 	pf = info->pixel_format;
1749a1663bcSArvind Sankar 	pi = info->pixel_information;
175d9ff0323SArvind Sankar 	w  = info->horizontal_resolution;
176d9ff0323SArvind Sankar 	h  = info->vertical_resolution;
177d9ff0323SArvind Sankar 
1789a1663bcSArvind Sankar 	if (w == cmdline.res.width && h == cmdline.res.height &&
1799a1663bcSArvind Sankar 	    (cmdline.res.format < 0 || cmdline.res.format == pf) &&
1809a1663bcSArvind Sankar 	    (!cmdline.res.depth || cmdline.res.depth == pixel_bpp(pf, pi)))
181d9ff0323SArvind Sankar 		return cur_mode;
182d9ff0323SArvind Sankar 
183d9ff0323SArvind Sankar 	max_mode = efi_table_attr(mode, max_mode);
184d9ff0323SArvind Sankar 
185d9ff0323SArvind Sankar 	for (m = 0; m < max_mode; m++) {
186d9ff0323SArvind Sankar 		if (m == cur_mode)
187d9ff0323SArvind Sankar 			continue;
188d9ff0323SArvind Sankar 
189d9ff0323SArvind Sankar 		status = efi_call_proto(gop, query_mode, m,
190d9ff0323SArvind Sankar 					&info_size, &info);
191d9ff0323SArvind Sankar 		if (status != EFI_SUCCESS)
192d9ff0323SArvind Sankar 			continue;
193d9ff0323SArvind Sankar 
194d9ff0323SArvind Sankar 		pf = info->pixel_format;
1959a1663bcSArvind Sankar 		pi = info->pixel_information;
196d9ff0323SArvind Sankar 		w  = info->horizontal_resolution;
197d9ff0323SArvind Sankar 		h  = info->vertical_resolution;
198d9ff0323SArvind Sankar 
199d9ff0323SArvind Sankar 		efi_bs_call(free_pool, info);
200d9ff0323SArvind Sankar 
201d9ff0323SArvind Sankar 		if (pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX)
202d9ff0323SArvind Sankar 			continue;
2039a1663bcSArvind Sankar 		if (w == cmdline.res.width && h == cmdline.res.height &&
2049a1663bcSArvind Sankar 		    (cmdline.res.format < 0 || cmdline.res.format == pf) &&
2059a1663bcSArvind Sankar 		    (!cmdline.res.depth || cmdline.res.depth == pixel_bpp(pf, pi)))
206d9ff0323SArvind Sankar 			return m;
207d9ff0323SArvind Sankar 	}
208d9ff0323SArvind Sankar 
209d9ff0323SArvind Sankar 	efi_printk("Couldn't find requested mode\n");
210d9ff0323SArvind Sankar 
211d9ff0323SArvind Sankar 	return cur_mode;
212d9ff0323SArvind Sankar }
213d9ff0323SArvind Sankar 
214fffb6804SArvind Sankar static void set_mode(efi_graphics_output_protocol_t *gop)
215fffb6804SArvind Sankar {
216fffb6804SArvind Sankar 	efi_graphics_output_protocol_mode_t *mode;
217fffb6804SArvind Sankar 	u32 cur_mode, new_mode;
218fffb6804SArvind Sankar 
219fffb6804SArvind Sankar 	switch (cmdline.option) {
220fffb6804SArvind Sankar 	case EFI_CMDLINE_MODE_NUM:
221fffb6804SArvind Sankar 		new_mode = choose_mode_modenum(gop);
222fffb6804SArvind Sankar 		break;
223d9ff0323SArvind Sankar 	case EFI_CMDLINE_RES:
224d9ff0323SArvind Sankar 		new_mode = choose_mode_res(gop);
225d9ff0323SArvind Sankar 		break;
226fffb6804SArvind Sankar 	default:
227fffb6804SArvind Sankar 		return;
228fffb6804SArvind Sankar 	}
229fffb6804SArvind Sankar 
230fffb6804SArvind Sankar 	mode = efi_table_attr(gop, mode);
231fffb6804SArvind Sankar 	cur_mode = efi_table_attr(mode, mode);
232fffb6804SArvind Sankar 
233fffb6804SArvind Sankar 	if (new_mode == cur_mode)
234fffb6804SArvind Sankar 		return;
235fffb6804SArvind Sankar 
236fffb6804SArvind Sankar 	if (efi_call_proto(gop, set_mode, new_mode) != EFI_SUCCESS)
237fffb6804SArvind Sankar 		efi_printk("Failed to set requested mode\n");
238fffb6804SArvind Sankar }
239fffb6804SArvind Sankar 
2409867fc9dSArvind Sankar static void find_bits(u32 mask, u8 *pos, u8 *size)
241fc372064SArd Biesheuvel {
2429867fc9dSArvind Sankar 	if (!mask) {
2439867fc9dSArvind Sankar 		*pos = *size = 0;
2449867fc9dSArvind Sankar 		return;
245fc372064SArd Biesheuvel 	}
246fc372064SArd Biesheuvel 
2479867fc9dSArvind Sankar 	/* UEFI spec guarantees that the set bits are contiguous */
2489867fc9dSArvind Sankar 	*pos  = __ffs(mask);
2499867fc9dSArvind Sankar 	*size = __fls(mask) - *pos + 1;
250fc372064SArd Biesheuvel }
251fc372064SArd Biesheuvel 
252fc372064SArd Biesheuvel static void
253fc372064SArd Biesheuvel setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line,
25444c84b4aSArvind Sankar 		 efi_pixel_bitmask_t pixel_info, int pixel_format)
255fc372064SArd Biesheuvel {
256d49fd4bbSArvind Sankar 	if (pixel_format == PIXEL_BIT_MASK) {
257d49fd4bbSArvind Sankar 		find_bits(pixel_info.red_mask,
258d49fd4bbSArvind Sankar 			  &si->red_pos, &si->red_size);
259d49fd4bbSArvind Sankar 		find_bits(pixel_info.green_mask,
260d49fd4bbSArvind Sankar 			  &si->green_pos, &si->green_size);
261d49fd4bbSArvind Sankar 		find_bits(pixel_info.blue_mask,
262d49fd4bbSArvind Sankar 			  &si->blue_pos, &si->blue_size);
263d49fd4bbSArvind Sankar 		find_bits(pixel_info.reserved_mask,
264d49fd4bbSArvind Sankar 			  &si->rsvd_pos, &si->rsvd_size);
265fc372064SArd Biesheuvel 		si->lfb_depth = si->red_size + si->green_size +
266fc372064SArd Biesheuvel 			si->blue_size + si->rsvd_size;
267fc372064SArd Biesheuvel 		si->lfb_linelength = (pixels_per_scan_line * si->lfb_depth) / 8;
268fc372064SArd Biesheuvel 	} else {
269d49fd4bbSArvind Sankar 		if (pixel_format == PIXEL_RGB_RESERVED_8BIT_PER_COLOR) {
270fc372064SArd Biesheuvel 			si->red_pos   = 0;
271d49fd4bbSArvind Sankar 			si->blue_pos  = 16;
272d49fd4bbSArvind Sankar 		} else /* PIXEL_BGR_RESERVED_8BIT_PER_COLOR */ {
273fc372064SArd Biesheuvel 			si->blue_pos  = 0;
274d49fd4bbSArvind Sankar 			si->red_pos   = 16;
275d49fd4bbSArvind Sankar 		}
276d49fd4bbSArvind Sankar 
277d49fd4bbSArvind Sankar 		si->green_pos = 8;
278d49fd4bbSArvind Sankar 		si->rsvd_pos  = 24;
279d49fd4bbSArvind Sankar 		si->red_size = si->green_size =
280d49fd4bbSArvind Sankar 			si->blue_size = si->rsvd_size = 8;
281d49fd4bbSArvind Sankar 
282d49fd4bbSArvind Sankar 		si->lfb_depth = 32;
283d49fd4bbSArvind Sankar 		si->lfb_linelength = pixels_per_scan_line * 4;
284fc372064SArd Biesheuvel 	}
285fc372064SArd Biesheuvel }
286fc372064SArd Biesheuvel 
287ecf53091SArvind Sankar static efi_graphics_output_protocol_t *
288ecf53091SArvind Sankar find_gop(efi_guid_t *proto, unsigned long size, void **handles)
289fc372064SArd Biesheuvel {
290e484c594SArvind Sankar 	efi_graphics_output_protocol_t *first_gop;
2912732ea0dSArd Biesheuvel 	efi_handle_t h;
292fc372064SArd Biesheuvel 	int i;
293fc372064SArd Biesheuvel 
294fc372064SArd Biesheuvel 	first_gop = NULL;
295fc372064SArd Biesheuvel 
2962732ea0dSArd Biesheuvel 	for_each_efi_handle(h, handles, size, i) {
297e484c594SArvind Sankar 		efi_status_t status;
298e484c594SArvind Sankar 
299e484c594SArvind Sankar 		efi_graphics_output_protocol_t *gop;
300e484c594SArvind Sankar 		efi_graphics_output_protocol_mode_t *mode;
301e484c594SArvind Sankar 		efi_graphics_output_mode_info_t *info;
302e484c594SArvind Sankar 
303fc372064SArd Biesheuvel 		efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
304fc372064SArd Biesheuvel 		void *dummy = NULL;
305fc372064SArd Biesheuvel 
306966291f6SArd Biesheuvel 		status = efi_bs_call(handle_protocol, h, proto, (void **)&gop);
307fc372064SArd Biesheuvel 		if (status != EFI_SUCCESS)
308fc372064SArd Biesheuvel 			continue;
309fc372064SArd Biesheuvel 
3108cd20797SArvind Sankar 		mode = efi_table_attr(gop, mode);
3118cd20797SArvind Sankar 		info = efi_table_attr(mode, info);
312d49fd4bbSArvind Sankar 		if (info->pixel_format == PIXEL_BLT_ONLY ||
313d49fd4bbSArvind Sankar 		    info->pixel_format >= PIXEL_FORMAT_MAX)
3148cd20797SArvind Sankar 			continue;
3158cd20797SArvind Sankar 
316fc372064SArd Biesheuvel 		/*
317fc372064SArd Biesheuvel 		 * Systems that use the UEFI Console Splitter may
318fc372064SArd Biesheuvel 		 * provide multiple GOP devices, not all of which are
319fc372064SArd Biesheuvel 		 * backed by real hardware. The workaround is to search
320fc372064SArd Biesheuvel 		 * for a GOP implementing the ConOut protocol, and if
321fc372064SArd Biesheuvel 		 * one isn't found, to just fall back to the first GOP.
3226327e6d0SArvind Sankar 		 *
323fc372064SArd Biesheuvel 		 * Once we've found a GOP supporting ConOut,
324fc372064SArd Biesheuvel 		 * don't bother looking any further.
325fc372064SArd Biesheuvel 		 */
3268e0a22e2SArvind Sankar 		status = efi_bs_call(handle_protocol, h, &conout_proto, &dummy);
3278e0a22e2SArvind Sankar 		if (status == EFI_SUCCESS)
3288e0a22e2SArvind Sankar 			return gop;
3298e0a22e2SArvind Sankar 
3308e0a22e2SArvind Sankar 		if (!first_gop)
3318de8788dSArvind Sankar 			first_gop = gop;
332fc372064SArd Biesheuvel 	}
333fc372064SArd Biesheuvel 
334ecf53091SArvind Sankar 	return first_gop;
335ecf53091SArvind Sankar }
336ecf53091SArvind Sankar 
337ecf53091SArvind Sankar static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
338ecf53091SArvind Sankar 			      unsigned long size, void **handles)
339ecf53091SArvind Sankar {
340ecf53091SArvind Sankar 	efi_graphics_output_protocol_t *gop;
341ecf53091SArvind Sankar 	efi_graphics_output_protocol_mode_t *mode;
342e484c594SArvind Sankar 	efi_graphics_output_mode_info_t *info;
343ecf53091SArvind Sankar 	efi_physical_addr_t fb_base;
344ecf53091SArvind Sankar 
345ecf53091SArvind Sankar 	gop = find_gop(proto, size, handles);
346ecf53091SArvind Sankar 
347fc372064SArd Biesheuvel 	/* Did we find any GOPs? */
348ecf53091SArvind Sankar 	if (!gop)
3496fc3cec3SArvind Sankar 		return EFI_NOT_FOUND;
350fc372064SArd Biesheuvel 
351fffb6804SArvind Sankar 	/* Change mode if requested */
352fffb6804SArvind Sankar 	set_mode(gop);
353fffb6804SArvind Sankar 
354fc372064SArd Biesheuvel 	/* EFI framebuffer */
355ecf53091SArvind Sankar 	mode = efi_table_attr(gop, mode);
3566327e6d0SArvind Sankar 	info = efi_table_attr(mode, info);
3576327e6d0SArvind Sankar 
358fc372064SArd Biesheuvel 	si->orig_video_isVGA = VIDEO_TYPE_EFI;
359fc372064SArd Biesheuvel 
3606327e6d0SArvind Sankar 	si->lfb_width  = info->horizontal_resolution;
3616327e6d0SArvind Sankar 	si->lfb_height = info->vertical_resolution;
362fc372064SArd Biesheuvel 
3636327e6d0SArvind Sankar 	fb_base		 = efi_table_attr(mode, frame_buffer_base);
364f1d1853bSArvind Sankar 	si->lfb_base	 = lower_32_bits(fb_base);
365f1d1853bSArvind Sankar 	si->ext_lfb_base = upper_32_bits(fb_base);
3666327e6d0SArvind Sankar 	if (si->ext_lfb_base)
367fc372064SArd Biesheuvel 		si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
368fc372064SArd Biesheuvel 
369fc372064SArd Biesheuvel 	si->pages = 1;
370fc372064SArd Biesheuvel 
3716327e6d0SArvind Sankar 	setup_pixel_info(si, info->pixels_per_scan_line,
3726327e6d0SArvind Sankar 			     info->pixel_information, info->pixel_format);
373fc372064SArd Biesheuvel 
374fc372064SArd Biesheuvel 	si->lfb_size = si->lfb_linelength * si->lfb_height;
375fc372064SArd Biesheuvel 
376fc372064SArd Biesheuvel 	si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
3776fc3cec3SArvind Sankar 
378dbd89c30SArvind Sankar 	return EFI_SUCCESS;
379fc372064SArd Biesheuvel }
380fc372064SArd Biesheuvel 
381fc372064SArd Biesheuvel /*
382fc372064SArd Biesheuvel  * See if we have Graphics Output Protocol
383fc372064SArd Biesheuvel  */
384cd33a5c1SArd Biesheuvel efi_status_t efi_setup_gop(struct screen_info *si, efi_guid_t *proto,
385fc372064SArd Biesheuvel 			   unsigned long size)
386fc372064SArd Biesheuvel {
387fc372064SArd Biesheuvel 	efi_status_t status;
388fc372064SArd Biesheuvel 	void **gop_handle = NULL;
389fc372064SArd Biesheuvel 
390966291f6SArd Biesheuvel 	status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size,
391966291f6SArd Biesheuvel 			     (void **)&gop_handle);
392fc372064SArd Biesheuvel 	if (status != EFI_SUCCESS)
393fc372064SArd Biesheuvel 		return status;
394fc372064SArd Biesheuvel 
395966291f6SArd Biesheuvel 	status = efi_bs_call(locate_handle, EFI_LOCATE_BY_PROTOCOL, proto, NULL,
396966291f6SArd Biesheuvel 			     &size, gop_handle);
397fc372064SArd Biesheuvel 	if (status != EFI_SUCCESS)
398fc372064SArd Biesheuvel 		goto free_handle;
399fc372064SArd Biesheuvel 
400cd33a5c1SArd Biesheuvel 	status = setup_gop(si, proto, size, gop_handle);
401fc372064SArd Biesheuvel 
402fc372064SArd Biesheuvel free_handle:
403966291f6SArd Biesheuvel 	efi_bs_call(free_pool, gop_handle);
404fc372064SArd Biesheuvel 	return status;
405fc372064SArd Biesheuvel }
406