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
)) {
154 * Systems that use the UEFI Console Splitter may
155 * provide multiple GOP devices, not all of which are
156 * backed by real hardware. The workaround is to search
157 * for a GOP implementing the ConOut protocol, and if
158 * one isn't found, to just fall back to the first GOP.
160 width
= info
->horizontal_resolution
;
161 height
= info
->vertical_resolution
;
162 pixel_format
= info
->pixel_format
;
163 pixel_info
= info
->pixel_information
;
164 pixels_per_scan_line
= info
->pixels_per_scan_line
;
165 fb_base
= current_fb_base
;
168 * Once we've found a GOP supporting ConOut,
169 * don't bother looking any further.
177 /* Did we find any GOPs? */
181 /* EFI framebuffer */
182 si
->orig_video_isVGA
= VIDEO_TYPE_EFI
;
184 si
->lfb_width
= width
;
185 si
->lfb_height
= height
;
186 si
->lfb_base
= fb_base
;
188 ext_lfb_base
= (u64
)(unsigned long)fb_base
>> 32;
190 si
->capabilities
|= VIDEO_CAPABILITY_64BIT_BASE
;
191 si
->ext_lfb_base
= ext_lfb_base
;
196 setup_pixel_info(si
, pixels_per_scan_line
, pixel_info
, pixel_format
);
198 si
->lfb_size
= si
->lfb_linelength
* si
->lfb_height
;
200 si
->capabilities
|= VIDEO_CAPABILITY_SKIP_QUIRKS
;
206 __gop_query64(efi_system_table_t
*sys_table_arg
,
207 struct efi_graphics_output_protocol_64
*gop64
,
208 struct efi_graphics_output_mode_info
**info
,
209 unsigned long *size
, u64
*fb_base
)
211 struct efi_graphics_output_protocol_mode_64
*mode
;
212 efi_graphics_output_protocol_query_mode query_mode
;
217 mode
= (struct efi_graphics_output_protocol_mode_64
*)m
;
218 query_mode
= (void *)(unsigned long)gop64
->query_mode
;
220 status
= __efi_call_early(query_mode
, (void *)gop64
, mode
->mode
, size
,
222 if (status
!= EFI_SUCCESS
)
225 *fb_base
= mode
->frame_buffer_base
;
230 setup_gop64(efi_system_table_t
*sys_table_arg
, struct screen_info
*si
,
231 efi_guid_t
*proto
, unsigned long size
, void **gop_handle
)
233 struct efi_graphics_output_protocol_64
*gop64
, *first_gop
;
234 unsigned long nr_gops
;
236 u32 pixels_per_scan_line
;
239 struct efi_pixel_bitmask pixel_info
;
241 efi_status_t status
= EFI_NOT_FOUND
;
242 u64
*handles
= (u64
*)(unsigned long)gop_handle
;
248 nr_gops
= size
/ sizeof(u64
);
249 for (i
= 0; i
< nr_gops
; i
++) {
250 struct efi_graphics_output_mode_info
*info
= NULL
;
251 efi_guid_t conout_proto
= EFI_CONSOLE_OUT_DEVICE_GUID
;
252 bool conout_found
= false;
254 efi_handle_t h
= (efi_handle_t
)(unsigned long)handles
[i
];
257 status
= efi_call_early(handle_protocol
, h
,
258 proto
, (void **)&gop64
);
259 if (status
!= EFI_SUCCESS
)
262 status
= efi_call_early(handle_protocol
, h
,
263 &conout_proto
, &dummy
);
264 if (status
== EFI_SUCCESS
)
267 status
= __gop_query64(sys_table_arg
, gop64
, &info
, &size
,
269 if (status
== EFI_SUCCESS
&& (!first_gop
|| conout_found
)) {
271 * Systems that use the UEFI Console Splitter may
272 * provide multiple GOP devices, not all of which are
273 * backed by real hardware. The workaround is to search
274 * for a GOP implementing the ConOut protocol, and if
275 * one isn't found, to just fall back to the first GOP.
277 width
= info
->horizontal_resolution
;
278 height
= info
->vertical_resolution
;
279 pixel_format
= info
->pixel_format
;
280 pixel_info
= info
->pixel_information
;
281 pixels_per_scan_line
= info
->pixels_per_scan_line
;
282 fb_base
= current_fb_base
;
285 * Once we've found a GOP supporting ConOut,
286 * don't bother looking any further.
294 /* Did we find any GOPs? */
298 /* EFI framebuffer */
299 si
->orig_video_isVGA
= VIDEO_TYPE_EFI
;
301 si
->lfb_width
= width
;
302 si
->lfb_height
= height
;
303 si
->lfb_base
= fb_base
;
305 ext_lfb_base
= (u64
)(unsigned long)fb_base
>> 32;
307 si
->capabilities
|= VIDEO_CAPABILITY_64BIT_BASE
;
308 si
->ext_lfb_base
= ext_lfb_base
;
313 setup_pixel_info(si
, pixels_per_scan_line
, pixel_info
, pixel_format
);
315 si
->lfb_size
= si
->lfb_linelength
* si
->lfb_height
;
317 si
->capabilities
|= VIDEO_CAPABILITY_SKIP_QUIRKS
;
323 * See if we have Graphics Output Protocol
325 efi_status_t
efi_setup_gop(efi_system_table_t
*sys_table_arg
,
326 struct screen_info
*si
, efi_guid_t
*proto
,
330 void **gop_handle
= NULL
;
332 status
= efi_call_early(allocate_pool
, EFI_LOADER_DATA
,
333 size
, (void **)&gop_handle
);
334 if (status
!= EFI_SUCCESS
)
337 status
= efi_call_early(locate_handle
,
338 EFI_LOCATE_BY_PROTOCOL
,
339 proto
, NULL
, &size
, gop_handle
);
340 if (status
!= EFI_SUCCESS
)
343 if (efi_is_64bit()) {
344 status
= setup_gop64(sys_table_arg
, si
, proto
, size
,
347 status
= setup_gop32(sys_table_arg
, si
, proto
, size
,
352 efi_call_early(free_pool
, gop_handle
);