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 setup_gop32(efi_system_table_t
*sys_table_arg
, struct screen_info
*si
,
90 efi_guid_t
*proto
, unsigned long size
, void **gop_handle
)
92 struct efi_graphics_output_protocol_32
*gop32
, *first_gop
;
93 unsigned long nr_gops
;
95 u32 pixels_per_scan_line
;
98 struct efi_pixel_bitmask pixel_info
;
101 u32
*handles
= (u32
*)(unsigned long)gop_handle
;
107 nr_gops
= size
/ sizeof(u32
);
108 for (i
= 0; i
< nr_gops
; i
++) {
109 struct efi_graphics_output_protocol_mode_32
*mode
;
110 struct efi_graphics_output_mode_info
*info
= NULL
;
111 efi_guid_t conout_proto
= EFI_CONSOLE_OUT_DEVICE_GUID
;
112 bool conout_found
= false;
114 efi_handle_t h
= (efi_handle_t
)(unsigned long)handles
[i
];
117 status
= efi_call_early(handle_protocol
, h
,
118 proto
, (void **)&gop32
);
119 if (status
!= EFI_SUCCESS
)
122 status
= efi_call_early(handle_protocol
, h
,
123 &conout_proto
, &dummy
);
124 if (status
== EFI_SUCCESS
)
127 mode
= (void *)(unsigned long)gop32
->mode
;
128 info
= (void *)(unsigned long)mode
->info
;
129 current_fb_base
= mode
->frame_buffer_base
;
131 if ((!first_gop
|| conout_found
) &&
132 info
->pixel_format
!= PIXEL_BLT_ONLY
) {
134 * Systems that use the UEFI Console Splitter may
135 * provide multiple GOP devices, not all of which are
136 * backed by real hardware. The workaround is to search
137 * for a GOP implementing the ConOut protocol, and if
138 * one isn't found, to just fall back to the first GOP.
140 width
= info
->horizontal_resolution
;
141 height
= info
->vertical_resolution
;
142 pixel_format
= info
->pixel_format
;
143 pixel_info
= info
->pixel_information
;
144 pixels_per_scan_line
= info
->pixels_per_scan_line
;
145 fb_base
= current_fb_base
;
148 * Once we've found a GOP supporting ConOut,
149 * don't bother looking any further.
157 /* Did we find any GOPs? */
159 return EFI_NOT_FOUND
;
161 /* EFI framebuffer */
162 si
->orig_video_isVGA
= VIDEO_TYPE_EFI
;
164 si
->lfb_width
= width
;
165 si
->lfb_height
= height
;
166 si
->lfb_base
= fb_base
;
168 ext_lfb_base
= (u64
)(unsigned long)fb_base
>> 32;
170 si
->capabilities
|= VIDEO_CAPABILITY_64BIT_BASE
;
171 si
->ext_lfb_base
= ext_lfb_base
;
176 setup_pixel_info(si
, pixels_per_scan_line
, pixel_info
, pixel_format
);
178 si
->lfb_size
= si
->lfb_linelength
* si
->lfb_height
;
180 si
->capabilities
|= VIDEO_CAPABILITY_SKIP_QUIRKS
;
186 setup_gop64(efi_system_table_t
*sys_table_arg
, struct screen_info
*si
,
187 efi_guid_t
*proto
, unsigned long size
, void **gop_handle
)
189 struct efi_graphics_output_protocol_64
*gop64
, *first_gop
;
190 unsigned long nr_gops
;
192 u32 pixels_per_scan_line
;
195 struct efi_pixel_bitmask pixel_info
;
198 u64
*handles
= (u64
*)(unsigned long)gop_handle
;
204 nr_gops
= size
/ sizeof(u64
);
205 for (i
= 0; i
< nr_gops
; i
++) {
206 struct efi_graphics_output_protocol_mode_64
*mode
;
207 struct efi_graphics_output_mode_info
*info
= NULL
;
208 efi_guid_t conout_proto
= EFI_CONSOLE_OUT_DEVICE_GUID
;
209 bool conout_found
= false;
211 efi_handle_t h
= (efi_handle_t
)(unsigned long)handles
[i
];
214 status
= efi_call_early(handle_protocol
, h
,
215 proto
, (void **)&gop64
);
216 if (status
!= EFI_SUCCESS
)
219 status
= efi_call_early(handle_protocol
, h
,
220 &conout_proto
, &dummy
);
221 if (status
== EFI_SUCCESS
)
224 mode
= (void *)(unsigned long)gop64
->mode
;
225 info
= (void *)(unsigned long)mode
->info
;
226 current_fb_base
= mode
->frame_buffer_base
;
228 if ((!first_gop
|| conout_found
) &&
229 info
->pixel_format
!= PIXEL_BLT_ONLY
) {
231 * Systems that use the UEFI Console Splitter may
232 * provide multiple GOP devices, not all of which are
233 * backed by real hardware. The workaround is to search
234 * for a GOP implementing the ConOut protocol, and if
235 * one isn't found, to just fall back to the first GOP.
237 width
= info
->horizontal_resolution
;
238 height
= info
->vertical_resolution
;
239 pixel_format
= info
->pixel_format
;
240 pixel_info
= info
->pixel_information
;
241 pixels_per_scan_line
= info
->pixels_per_scan_line
;
242 fb_base
= current_fb_base
;
245 * Once we've found a GOP supporting ConOut,
246 * don't bother looking any further.
254 /* Did we find any GOPs? */
256 return EFI_NOT_FOUND
;
258 /* EFI framebuffer */
259 si
->orig_video_isVGA
= VIDEO_TYPE_EFI
;
261 si
->lfb_width
= width
;
262 si
->lfb_height
= height
;
263 si
->lfb_base
= fb_base
;
265 ext_lfb_base
= (u64
)(unsigned long)fb_base
>> 32;
267 si
->capabilities
|= VIDEO_CAPABILITY_64BIT_BASE
;
268 si
->ext_lfb_base
= ext_lfb_base
;
273 setup_pixel_info(si
, pixels_per_scan_line
, pixel_info
, pixel_format
);
275 si
->lfb_size
= si
->lfb_linelength
* si
->lfb_height
;
277 si
->capabilities
|= VIDEO_CAPABILITY_SKIP_QUIRKS
;
283 * See if we have Graphics Output Protocol
285 efi_status_t
efi_setup_gop(efi_system_table_t
*sys_table_arg
,
286 struct screen_info
*si
, efi_guid_t
*proto
,
290 void **gop_handle
= NULL
;
292 status
= efi_call_early(allocate_pool
, EFI_LOADER_DATA
,
293 size
, (void **)&gop_handle
);
294 if (status
!= EFI_SUCCESS
)
297 status
= efi_call_early(locate_handle
,
298 EFI_LOCATE_BY_PROTOCOL
,
299 proto
, NULL
, &size
, gop_handle
);
300 if (status
!= EFI_SUCCESS
)
303 if (efi_is_64bit()) {
304 status
= setup_gop64(sys_table_arg
, si
, proto
, size
,
307 status
= setup_gop32(sys_table_arg
, si
, proto
, size
,
312 efi_call_early(free_pool
, gop_handle
);