1 /* -----------------------------------------------------------------------
3 * Copyright 2011 Intel Corporation; author Matt Fleming
5 * This file is part of the Linux kernel, and is made available under
6 * the terms of the GNU General Public License version 2.
8 * ----------------------------------------------------------------------- */
10 #include <linux/efi.h>
11 #include <linux/screen_info.h>
13 #include <asm/setup.h>
15 static void find_bits(unsigned long mask
, u8
*pos
, u8
*size
)
23 while (!(mask
& 0x1)) {
39 setup_pixel_info(struct screen_info
*si
, u32 pixels_per_scan_line
,
40 struct efi_pixel_bitmask pixel_info
, int pixel_format
)
42 if (pixel_format
== PIXEL_RGB_RESERVED_8BIT_PER_COLOR
) {
44 si
->lfb_linelength
= pixels_per_scan_line
* 4;
53 } else if (pixel_format
== PIXEL_BGR_RESERVED_8BIT_PER_COLOR
) {
55 si
->lfb_linelength
= pixels_per_scan_line
* 4;
64 } else if (pixel_format
== PIXEL_BIT_MASK
) {
65 find_bits(pixel_info
.red_mask
, &si
->red_pos
, &si
->red_size
);
66 find_bits(pixel_info
.green_mask
, &si
->green_pos
,
68 find_bits(pixel_info
.blue_mask
, &si
->blue_pos
, &si
->blue_size
);
69 find_bits(pixel_info
.reserved_mask
, &si
->rsvd_pos
,
71 si
->lfb_depth
= si
->red_size
+ si
->green_size
+
72 si
->blue_size
+ si
->rsvd_size
;
73 si
->lfb_linelength
= (pixels_per_scan_line
* si
->lfb_depth
) / 8;
76 si
->lfb_linelength
= si
->lfb_width
/ 2;
89 __gop_query32(efi_system_table_t
*sys_table_arg
,
90 struct efi_graphics_output_protocol_32
*gop32
,
91 struct efi_graphics_output_mode_info
**info
,
92 unsigned long *size
, u64
*fb_base
)
94 struct efi_graphics_output_protocol_mode_32
*mode
;
95 efi_graphics_output_protocol_query_mode query_mode
;
100 mode
= (struct efi_graphics_output_protocol_mode_32
*)m
;
101 query_mode
= (void *)(unsigned long)gop32
->query_mode
;
103 status
= __efi_call_early(query_mode
, (void *)gop32
, mode
->mode
, size
,
105 if (status
!= EFI_SUCCESS
)
108 *fb_base
= mode
->frame_buffer_base
;
113 setup_gop32(efi_system_table_t
*sys_table_arg
, struct screen_info
*si
,
114 efi_guid_t
*proto
, unsigned long size
, void **gop_handle
)
116 struct efi_graphics_output_protocol_32
*gop32
, *first_gop
;
117 unsigned long nr_gops
;
119 u32 pixels_per_scan_line
;
122 struct efi_pixel_bitmask pixel_info
;
124 efi_status_t status
= EFI_NOT_FOUND
;
125 u32
*handles
= (u32
*)(unsigned long)gop_handle
;
131 nr_gops
= size
/ sizeof(u32
);
132 for (i
= 0; i
< nr_gops
; i
++) {
133 struct efi_graphics_output_mode_info
*info
= NULL
;
134 efi_guid_t conout_proto
= EFI_CONSOLE_OUT_DEVICE_GUID
;
135 bool conout_found
= false;
137 efi_handle_t h
= (efi_handle_t
)(unsigned long)handles
[i
];
140 status
= efi_call_early(handle_protocol
, h
,
141 proto
, (void **)&gop32
);
142 if (status
!= EFI_SUCCESS
)
145 status
= efi_call_early(handle_protocol
, h
,
146 &conout_proto
, &dummy
);
147 if (status
== EFI_SUCCESS
)
150 status
= __gop_query32(sys_table_arg
, gop32
, &info
, &size
,
152 if (status
== EFI_SUCCESS
&& (!first_gop
|| conout_found
) &&
153 info
->pixel_format
!= PIXEL_BLT_ONLY
) {
155 * Systems that use the UEFI Console Splitter may
156 * provide multiple GOP devices, not all of which are
157 * backed by real hardware. The workaround is to search
158 * for a GOP implementing the ConOut protocol, and if
159 * one isn't found, to just fall back to the first GOP.
161 width
= info
->horizontal_resolution
;
162 height
= info
->vertical_resolution
;
163 pixel_format
= info
->pixel_format
;
164 pixel_info
= info
->pixel_information
;
165 pixels_per_scan_line
= info
->pixels_per_scan_line
;
166 fb_base
= current_fb_base
;
169 * Once we've found a GOP supporting ConOut,
170 * don't bother looking any further.
178 /* Did we find any GOPs? */
182 /* EFI framebuffer */
183 si
->orig_video_isVGA
= VIDEO_TYPE_EFI
;
185 si
->lfb_width
= width
;
186 si
->lfb_height
= height
;
187 si
->lfb_base
= fb_base
;
189 ext_lfb_base
= (u64
)(unsigned long)fb_base
>> 32;
191 si
->capabilities
|= VIDEO_CAPABILITY_64BIT_BASE
;
192 si
->ext_lfb_base
= ext_lfb_base
;
197 setup_pixel_info(si
, pixels_per_scan_line
, pixel_info
, pixel_format
);
199 si
->lfb_size
= si
->lfb_linelength
* si
->lfb_height
;
201 si
->capabilities
|= VIDEO_CAPABILITY_SKIP_QUIRKS
;
207 __gop_query64(efi_system_table_t
*sys_table_arg
,
208 struct efi_graphics_output_protocol_64
*gop64
,
209 struct efi_graphics_output_mode_info
**info
,
210 unsigned long *size
, u64
*fb_base
)
212 struct efi_graphics_output_protocol_mode_64
*mode
;
213 efi_graphics_output_protocol_query_mode query_mode
;
218 mode
= (struct efi_graphics_output_protocol_mode_64
*)m
;
219 query_mode
= (void *)(unsigned long)gop64
->query_mode
;
221 status
= __efi_call_early(query_mode
, (void *)gop64
, mode
->mode
, size
,
223 if (status
!= EFI_SUCCESS
)
226 *fb_base
= mode
->frame_buffer_base
;
231 setup_gop64(efi_system_table_t
*sys_table_arg
, struct screen_info
*si
,
232 efi_guid_t
*proto
, unsigned long size
, void **gop_handle
)
234 struct efi_graphics_output_protocol_64
*gop64
, *first_gop
;
235 unsigned long nr_gops
;
237 u32 pixels_per_scan_line
;
240 struct efi_pixel_bitmask pixel_info
;
242 efi_status_t status
= EFI_NOT_FOUND
;
243 u64
*handles
= (u64
*)(unsigned long)gop_handle
;
249 nr_gops
= size
/ sizeof(u64
);
250 for (i
= 0; i
< nr_gops
; i
++) {
251 struct efi_graphics_output_mode_info
*info
= NULL
;
252 efi_guid_t conout_proto
= EFI_CONSOLE_OUT_DEVICE_GUID
;
253 bool conout_found
= false;
255 efi_handle_t h
= (efi_handle_t
)(unsigned long)handles
[i
];
258 status
= efi_call_early(handle_protocol
, h
,
259 proto
, (void **)&gop64
);
260 if (status
!= EFI_SUCCESS
)
263 status
= efi_call_early(handle_protocol
, h
,
264 &conout_proto
, &dummy
);
265 if (status
== EFI_SUCCESS
)
268 status
= __gop_query64(sys_table_arg
, gop64
, &info
, &size
,
270 if (status
== EFI_SUCCESS
&& (!first_gop
|| conout_found
) &&
271 info
->pixel_format
!= PIXEL_BLT_ONLY
) {
273 * Systems that use the UEFI Console Splitter may
274 * provide multiple GOP devices, not all of which are
275 * backed by real hardware. The workaround is to search
276 * for a GOP implementing the ConOut protocol, and if
277 * one isn't found, to just fall back to the first GOP.
279 width
= info
->horizontal_resolution
;
280 height
= info
->vertical_resolution
;
281 pixel_format
= info
->pixel_format
;
282 pixel_info
= info
->pixel_information
;
283 pixels_per_scan_line
= info
->pixels_per_scan_line
;
284 fb_base
= current_fb_base
;
287 * Once we've found a GOP supporting ConOut,
288 * don't bother looking any further.
296 /* Did we find any GOPs? */
300 /* EFI framebuffer */
301 si
->orig_video_isVGA
= VIDEO_TYPE_EFI
;
303 si
->lfb_width
= width
;
304 si
->lfb_height
= height
;
305 si
->lfb_base
= fb_base
;
307 ext_lfb_base
= (u64
)(unsigned long)fb_base
>> 32;
309 si
->capabilities
|= VIDEO_CAPABILITY_64BIT_BASE
;
310 si
->ext_lfb_base
= ext_lfb_base
;
315 setup_pixel_info(si
, pixels_per_scan_line
, pixel_info
, pixel_format
);
317 si
->lfb_size
= si
->lfb_linelength
* si
->lfb_height
;
319 si
->capabilities
|= VIDEO_CAPABILITY_SKIP_QUIRKS
;
325 * See if we have Graphics Output Protocol
327 efi_status_t
efi_setup_gop(efi_system_table_t
*sys_table_arg
,
328 struct screen_info
*si
, efi_guid_t
*proto
,
332 void **gop_handle
= NULL
;
334 status
= efi_call_early(allocate_pool
, EFI_LOADER_DATA
,
335 size
, (void **)&gop_handle
);
336 if (status
!= EFI_SUCCESS
)
339 status
= efi_call_early(locate_handle
,
340 EFI_LOCATE_BY_PROTOCOL
,
341 proto
, NULL
, &size
, gop_handle
);
342 if (status
!= EFI_SUCCESS
)
345 if (efi_is_64bit()) {
346 status
= setup_gop64(sys_table_arg
, si
, proto
, size
,
349 status
= setup_gop32(sys_table_arg
, si
, proto
, size
,
354 efi_call_early(free_pool
, gop_handle
);