2 * EFI application disk support
4 * Copyright (c) 2016 Alexander Graf
6 * SPDX-License-Identifier: GPL-2.0+
11 #include <efi_loader.h>
17 DECLARE_GLOBAL_DATA_PTR;
19 static const efi_guid_t efi_gop_guid = EFI_GOP_GUID;
22 /* Generic EFI object parent class data */
23 struct efi_object parent;
24 /* EFI Interface callback struct for gop */
26 /* The only mode we support */
27 struct efi_gop_mode_info info;
28 struct efi_gop_mode mode;
29 /* Fields we only have acces to during init */
34 static efi_status_t EFIAPI gop_query_mode(struct efi_gop *this, u32 mode_number,
35 efi_uintn_t *size_of_info,
36 struct efi_gop_mode_info **info)
38 struct efi_gop_obj *gopobj;
40 EFI_ENTRY("%p, %x, %p, %p", this, mode_number, size_of_info, info);
42 gopobj = container_of(this, struct efi_gop_obj, ops);
43 *size_of_info = sizeof(gopobj->info);
44 *info = &gopobj->info;
46 return EFI_EXIT(EFI_SUCCESS);
49 static efi_status_t EFIAPI gop_set_mode(struct efi_gop *this, u32 mode_number)
51 EFI_ENTRY("%p, %x", this, mode_number);
54 return EFI_EXIT(EFI_INVALID_PARAMETER);
56 return EFI_EXIT(EFI_SUCCESS);
59 static __always_inline struct efi_gop_pixel efi_vid16_to_blt_col(u16 vid)
61 struct efi_gop_pixel blt = {
65 blt.blue = (vid & 0x1f) << 3;
67 blt.green = (vid & 0x3f) << 2;
69 blt.red = (vid & 0x1f) << 3;
73 static __always_inline u16 efi_blt_col_to_vid16(struct efi_gop_pixel *blt)
75 return (u16)(blt->red >> 3) << 11 |
76 (u16)(blt->green >> 2) << 5 |
77 (u16)(blt->blue >> 3);
83 * This function implements the Blt service of the EFI_GRAPHICS_OUTPUT_PROTOCOL.
84 * See the Unified Extensible Firmware Interface (UEFI) specification for
87 * @this: EFI_GRAPHICS_OUTPUT_PROTOCOL
88 * @buffer: pixel buffer
89 * @sx: source x-coordinate
90 * @sy: source y-coordinate
91 * @dx: destination x-coordinate
92 * @dy: destination y-coordinate
93 * @width: width of rectangle
94 * @height: height of rectangle
95 * @delta: length in bytes of a line in the pixel buffer (optional)
96 * @return: status code
98 efi_status_t EFIAPI gop_blt(struct efi_gop *this, struct efi_gop_pixel *buffer,
99 u32 operation, efi_uintn_t sx,
100 efi_uintn_t sy, efi_uintn_t dx,
101 efi_uintn_t dy, efi_uintn_t width,
102 efi_uintn_t height, efi_uintn_t delta)
104 struct efi_gop_obj *gopobj = container_of(this, struct efi_gop_obj, ops);
105 efi_uintn_t i, j, linelen;
106 u32 *fb32 = gopobj->fb;
107 u16 *fb16 = gopobj->fb;
109 EFI_ENTRY("%p, %p, %u, %zu, %zu, %zu, %zu, %zu, %zu, %zu", this,
110 buffer, operation, sx, sy, dx, dy, width, height, delta);
113 /* Check for 4 byte alignment */
115 return EFI_EXIT(EFI_INVALID_PARAMETER);
116 linelen = delta >> 2;
121 /* Check source rectangle */
123 case EFI_BLT_VIDEO_FILL:
125 case EFI_BLT_BUFFER_TO_VIDEO:
126 if (sx + width > linelen)
127 return EFI_EXIT(EFI_INVALID_PARAMETER);
129 case EFI_BLT_VIDEO_TO_BLT_BUFFER:
130 case EFI_BLT_VIDEO_TO_VIDEO:
131 if (sx + width > gopobj->info.width ||
132 sy + height > gopobj->info.height)
133 return EFI_EXIT(EFI_INVALID_PARAMETER);
136 return EFI_EXIT(EFI_INVALID_PARAMETER);
139 /* Check destination rectangle */
141 case EFI_BLT_VIDEO_FILL:
142 case EFI_BLT_BUFFER_TO_VIDEO:
143 case EFI_BLT_VIDEO_TO_VIDEO:
144 if (dx + width > gopobj->info.width ||
145 dy + height > gopobj->info.height)
146 return EFI_EXIT(EFI_INVALID_PARAMETER);
148 case EFI_BLT_VIDEO_TO_BLT_BUFFER:
149 if (dx + width > linelen)
150 return EFI_EXIT(EFI_INVALID_PARAMETER);
154 for (i = 0; i < height; i++) {
155 for (j = 0; j < width; j++) {
156 struct efi_gop_pixel pix;
158 /* Read source pixel */
160 case EFI_BLT_VIDEO_FILL:
163 case EFI_BLT_BUFFER_TO_VIDEO:
164 pix = buffer[linelen * (i + sy) + j + sx];
166 case EFI_BLT_VIDEO_TO_BLT_BUFFER:
167 case EFI_BLT_VIDEO_TO_VIDEO:
168 switch (gopobj->bpix) {
169 #ifdef CONFIG_DM_VIDEO
174 pix = *(struct efi_gop_pixel *)&fb32[
178 #ifdef CONFIG_DM_VIDEO
183 pix = efi_vid16_to_blt_col(fb16[
188 return EFI_EXIT(EFI_UNSUPPORTED);
193 /* Write destination pixel */
195 case EFI_BLT_VIDEO_TO_BLT_BUFFER:
196 buffer[linelen * (i + dy) + j + dx] = pix;
198 case EFI_BLT_BUFFER_TO_VIDEO:
199 case EFI_BLT_VIDEO_FILL:
200 case EFI_BLT_VIDEO_TO_VIDEO:
201 switch (gopobj->bpix) {
202 #ifdef CONFIG_DM_VIDEO
207 fb32[gopobj->info.width *
208 (i + dy) + j + dx] = *(u32 *)&pix;
210 #ifdef CONFIG_DM_VIDEO
215 fb16[gopobj->info.width *
217 efi_blt_col_to_vid16(&pix);
220 return EFI_EXIT(EFI_UNSUPPORTED);
227 #ifdef CONFIG_DM_VIDEO
233 return EFI_EXIT(EFI_SUCCESS);
237 * Install graphical output protocol.
239 * If no supported video device exists this is not considered as an
242 efi_status_t efi_gop_register(void)
244 struct efi_gop_obj *gopobj;
246 u64 fb_base, fb_size;
250 #ifdef CONFIG_DM_VIDEO
251 struct udevice *vdev;
252 struct video_priv *priv;
254 /* We only support a single video output device for now */
255 if (uclass_first_device(UCLASS_VIDEO, &vdev) || !vdev) {
256 debug("WARNING: No video device\n");
260 priv = dev_get_uclass_priv(vdev);
262 col = video_get_xsize(vdev);
263 row = video_get_ysize(vdev);
264 fb_base = (uintptr_t)priv->fb;
265 fb_size = priv->fb_size;
270 bpix = panel_info.vl_bpix;
271 col = panel_info.vl_col;
272 row = panel_info.vl_row;
273 fb_base = gd->fb_base;
274 fb_size = lcd_get_size(&line_len);
275 fb = (void*)gd->fb_base;
279 #ifdef CONFIG_DM_VIDEO
288 /* So far, we only work in 16 or 32 bit mode */
289 debug("WARNING: Unsupported video mode\n");
293 gopobj = calloc(1, sizeof(*gopobj));
295 printf("ERROR: Out of memory\n");
296 return EFI_OUT_OF_RESOURCES;
299 /* Hook up to the device list */
300 efi_add_handle(&gopobj->parent);
302 /* Fill in object data */
303 ret = efi_add_protocol(gopobj->parent.handle, &efi_gop_guid,
305 if (ret != EFI_SUCCESS) {
306 printf("ERROR: Failure adding gop protocol\n");
309 gopobj->ops.query_mode = gop_query_mode;
310 gopobj->ops.set_mode = gop_set_mode;
311 gopobj->ops.blt = gop_blt;
312 gopobj->ops.mode = &gopobj->mode;
314 gopobj->mode.max_mode = 1;
315 gopobj->mode.info = &gopobj->info;
316 gopobj->mode.info_size = sizeof(gopobj->info);
318 #ifdef CONFIG_DM_VIDEO
319 if (bpix == VIDEO_BPP32)
321 if (bpix == LCD_COLOR32)
324 /* With 32bit color space we can directly expose the fb */
325 gopobj->mode.fb_base = fb_base;
326 gopobj->mode.fb_size = fb_size;
329 gopobj->info.version = 0;
330 gopobj->info.width = col;
331 gopobj->info.height = row;
332 gopobj->info.pixel_format = EFI_GOT_RGBA8;
333 gopobj->info.pixels_per_scanline = col;