blob: 363ccbb78904a2c32bde7148dff5a3cfdc5632fc [file] [log] [blame]
Alexander Grafbe8d3242016-03-15 18:38:21 +01001/*
2 * EFI application disk support
3 *
4 * Copyright (c) 2016 Alexander Graf
5 *
6 * SPDX-License-Identifier: GPL-2.0+
7 */
8
9#include <common.h>
Alexander Grafa8122412016-06-05 22:34:31 +020010#include <dm.h>
Alexander Grafbe8d3242016-03-15 18:38:21 +010011#include <efi_loader.h>
12#include <inttypes.h>
13#include <lcd.h>
14#include <malloc.h>
Alexander Grafa8122412016-06-05 22:34:31 +020015#include <video.h>
Alexander Grafbe8d3242016-03-15 18:38:21 +010016
17DECLARE_GLOBAL_DATA_PTR;
18
19static const efi_guid_t efi_gop_guid = EFI_GOP_GUID;
20
21struct efi_gop_obj {
22 /* Generic EFI object parent class data */
23 struct efi_object parent;
24 /* EFI Interface callback struct for gop */
25 struct efi_gop ops;
26 /* The only mode we support */
27 struct efi_gop_mode_info info;
28 struct efi_gop_mode mode;
Alexander Grafa8122412016-06-05 22:34:31 +020029 /* Fields we only have acces to during init */
30 u32 bpix;
Rob Clarkca9193d2017-07-21 15:00:27 -040031 void *fb;
Alexander Grafbe8d3242016-03-15 18:38:21 +010032};
33
34static efi_status_t EFIAPI gop_query_mode(struct efi_gop *this, u32 mode_number,
Heinrich Schuchardt1c38a772017-10-26 19:25:51 +020035 efi_uintn_t *size_of_info,
Alexander Grafbe8d3242016-03-15 18:38:21 +010036 struct efi_gop_mode_info **info)
37{
38 struct efi_gop_obj *gopobj;
39
40 EFI_ENTRY("%p, %x, %p, %p", this, mode_number, size_of_info, info);
41
42 gopobj = container_of(this, struct efi_gop_obj, ops);
43 *size_of_info = sizeof(gopobj->info);
44 *info = &gopobj->info;
45
46 return EFI_EXIT(EFI_SUCCESS);
47}
48
49static efi_status_t EFIAPI gop_set_mode(struct efi_gop *this, u32 mode_number)
50{
51 EFI_ENTRY("%p, %x", this, mode_number);
52
53 if (mode_number != 0)
54 return EFI_EXIT(EFI_INVALID_PARAMETER);
55
56 return EFI_EXIT(EFI_SUCCESS);
57}
58
Heinrich Schuchardt90b658b2018-03-16 19:59:06 +010059static __always_inline struct efi_gop_pixel efi_vid16_to_blt_col(u16 vid)
Heinrich Schuchardt0e0a3ce2018-02-07 22:14:22 +010060{
61 struct efi_gop_pixel blt = {
62 .reserved = 0,
63 };
64
65 blt.blue = (vid & 0x1f) << 3;
66 vid >>= 5;
67 blt.green = (vid & 0x3f) << 2;
68 vid >>= 6;
69 blt.red = (vid & 0x1f) << 3;
70 return blt;
71}
72
Heinrich Schuchardt90b658b2018-03-16 19:59:06 +010073static __always_inline u16 efi_blt_col_to_vid16(struct efi_gop_pixel *blt)
Heinrich Schuchardt0e0a3ce2018-02-07 22:14:22 +010074{
75 return (u16)(blt->red >> 3) << 11 |
76 (u16)(blt->green >> 2) << 5 |
77 (u16)(blt->blue >> 3);
78}
79
Alexander Grafba718e62018-03-15 15:02:28 +010080static __always_inline efi_status_t gop_blt_int(struct efi_gop *this,
Alexander Graf8e475062018-03-15 15:02:29 +010081 struct efi_gop_pixel *bufferp,
Alexander Grafba718e62018-03-15 15:02:28 +010082 u32 operation, efi_uintn_t sx,
83 efi_uintn_t sy, efi_uintn_t dx,
84 efi_uintn_t dy,
85 efi_uintn_t width,
86 efi_uintn_t height,
Alexander Graf8e475062018-03-15 15:02:29 +010087 efi_uintn_t delta,
88 efi_uintn_t vid_bpp)
Alexander Grafbe8d3242016-03-15 18:38:21 +010089{
Alexander Grafa8122412016-06-05 22:34:31 +020090 struct efi_gop_obj *gopobj = container_of(this, struct efi_gop_obj, ops);
Alexander Graf8e475062018-03-15 15:02:29 +010091 efi_uintn_t i, j, linelen, slineoff = 0, dlineoff, swidth, dwidth;
Heinrich Schuchardt0e0a3ce2018-02-07 22:14:22 +010092 u32 *fb32 = gopobj->fb;
93 u16 *fb16 = gopobj->fb;
Alexander Graf8e475062018-03-15 15:02:29 +010094 struct efi_gop_pixel *buffer = __builtin_assume_aligned(bufferp, 4);
Heinrich Schuchardt0e0a3ce2018-02-07 22:14:22 +010095
Heinrich Schuchardt51a0f452018-03-14 19:57:02 +010096 if (delta) {
97 /* Check for 4 byte alignment */
98 if (delta & 3)
Alexander Grafba718e62018-03-15 15:02:28 +010099 return EFI_INVALID_PARAMETER;
Heinrich Schuchardt51a0f452018-03-14 19:57:02 +0100100 linelen = delta >> 2;
101 } else {
102 linelen = width;
103 }
104
Heinrich Schuchardt0e0a3ce2018-02-07 22:14:22 +0100105 /* Check source rectangle */
106 switch (operation) {
107 case EFI_BLT_VIDEO_FILL:
Alexander Grafbe8d3242016-03-15 18:38:21 +0100108 break;
Heinrich Schuchardt0e0a3ce2018-02-07 22:14:22 +0100109 case EFI_BLT_BUFFER_TO_VIDEO:
110 if (sx + width > linelen)
Alexander Grafba718e62018-03-15 15:02:28 +0100111 return EFI_INVALID_PARAMETER;
Heinrich Schuchardt0e0a3ce2018-02-07 22:14:22 +0100112 break;
113 case EFI_BLT_VIDEO_TO_BLT_BUFFER:
114 case EFI_BLT_VIDEO_TO_VIDEO:
115 if (sx + width > gopobj->info.width ||
116 sy + height > gopobj->info.height)
Alexander Grafba718e62018-03-15 15:02:28 +0100117 return EFI_INVALID_PARAMETER;
Heinrich Schuchardt0e0a3ce2018-02-07 22:14:22 +0100118 break;
119 default:
Alexander Grafba718e62018-03-15 15:02:28 +0100120 return EFI_INVALID_PARAMETER;
Heinrich Schuchardt0e0a3ce2018-02-07 22:14:22 +0100121 }
Alexander Grafbe8d3242016-03-15 18:38:21 +0100122
Heinrich Schuchardt0e0a3ce2018-02-07 22:14:22 +0100123 /* Check destination rectangle */
124 switch (operation) {
125 case EFI_BLT_VIDEO_FILL:
126 case EFI_BLT_BUFFER_TO_VIDEO:
127 case EFI_BLT_VIDEO_TO_VIDEO:
128 if (dx + width > gopobj->info.width ||
129 dy + height > gopobj->info.height)
Alexander Grafba718e62018-03-15 15:02:28 +0100130 return EFI_INVALID_PARAMETER;
Heinrich Schuchardt0e0a3ce2018-02-07 22:14:22 +0100131 break;
132 case EFI_BLT_VIDEO_TO_BLT_BUFFER:
133 if (dx + width > linelen)
Alexander Grafba718e62018-03-15 15:02:28 +0100134 return EFI_INVALID_PARAMETER;
Heinrich Schuchardt0e0a3ce2018-02-07 22:14:22 +0100135 break;
136 }
137
Alexander Graf8e475062018-03-15 15:02:29 +0100138 /* Calculate line width */
139 switch (operation) {
140 case EFI_BLT_BUFFER_TO_VIDEO:
141 swidth = linelen;
142 break;
143 case EFI_BLT_VIDEO_TO_BLT_BUFFER:
144 case EFI_BLT_VIDEO_TO_VIDEO:
145 swidth = gopobj->info.width;
146 if (!vid_bpp)
147 return EFI_UNSUPPORTED;
148 break;
149 case EFI_BLT_VIDEO_FILL:
150 swidth = 0;
151 break;
152 }
153
154 switch (operation) {
155 case EFI_BLT_BUFFER_TO_VIDEO:
156 case EFI_BLT_VIDEO_FILL:
157 case EFI_BLT_VIDEO_TO_VIDEO:
158 dwidth = gopobj->info.width;
159 if (!vid_bpp)
160 return EFI_UNSUPPORTED;
161 break;
162 case EFI_BLT_VIDEO_TO_BLT_BUFFER:
163 dwidth = linelen;
164 break;
165 }
166
167 slineoff = swidth * sy;
168 dlineoff = dwidth * dy;
Heinrich Schuchardt0e0a3ce2018-02-07 22:14:22 +0100169 for (i = 0; i < height; i++) {
170 for (j = 0; j < width; j++) {
171 struct efi_gop_pixel pix;
172
173 /* Read source pixel */
174 switch (operation) {
175 case EFI_BLT_VIDEO_FILL:
176 pix = *buffer;
177 break;
178 case EFI_BLT_BUFFER_TO_VIDEO:
Alexander Graf8e475062018-03-15 15:02:29 +0100179 pix = buffer[slineoff + j + sx];
Heinrich Schuchardt0e0a3ce2018-02-07 22:14:22 +0100180 break;
181 case EFI_BLT_VIDEO_TO_BLT_BUFFER:
182 case EFI_BLT_VIDEO_TO_VIDEO:
Alexander Graf8e475062018-03-15 15:02:29 +0100183 if (vid_bpp == 32)
Heinrich Schuchardt0e0a3ce2018-02-07 22:14:22 +0100184 pix = *(struct efi_gop_pixel *)&fb32[
Alexander Graf8e475062018-03-15 15:02:29 +0100185 slineoff + j + sx];
186 else
Heinrich Schuchardt0e0a3ce2018-02-07 22:14:22 +0100187 pix = efi_vid16_to_blt_col(fb16[
Alexander Graf8e475062018-03-15 15:02:29 +0100188 slineoff + j + sx]);
Heinrich Schuchardt0e0a3ce2018-02-07 22:14:22 +0100189 break;
190 }
191
192 /* Write destination pixel */
193 switch (operation) {
194 case EFI_BLT_VIDEO_TO_BLT_BUFFER:
Alexander Graf8e475062018-03-15 15:02:29 +0100195 buffer[dlineoff + j + dx] = pix;
Heinrich Schuchardt0e0a3ce2018-02-07 22:14:22 +0100196 break;
197 case EFI_BLT_BUFFER_TO_VIDEO:
198 case EFI_BLT_VIDEO_FILL:
199 case EFI_BLT_VIDEO_TO_VIDEO:
Alexander Graf8e475062018-03-15 15:02:29 +0100200 if (vid_bpp == 32)
201 fb32[dlineoff + j + dx] = *(u32 *)&pix;
202 else
203 fb16[dlineoff + j + dx] =
Heinrich Schuchardt0e0a3ce2018-02-07 22:14:22 +0100204 efi_blt_col_to_vid16(&pix);
Heinrich Schuchardt0e0a3ce2018-02-07 22:14:22 +0100205 break;
Alexander Grafbe8d3242016-03-15 18:38:21 +0100206 }
207 }
Alexander Graf8e475062018-03-15 15:02:29 +0100208 slineoff += swidth;
209 dlineoff += dwidth;
Alexander Grafbe8d3242016-03-15 18:38:21 +0100210 }
211
Alexander Grafba718e62018-03-15 15:02:28 +0100212 return EFI_SUCCESS;
213}
214
Alexander Graf8e475062018-03-15 15:02:29 +0100215static efi_uintn_t gop_get_bpp(struct efi_gop *this)
216{
217 struct efi_gop_obj *gopobj = container_of(this, struct efi_gop_obj, ops);
218 efi_uintn_t vid_bpp = 0;
219
220 switch (gopobj->bpix) {
221#ifdef CONFIG_DM_VIDEO
222 case VIDEO_BPP32:
223#else
224 case LCD_COLOR32:
225#endif
226 vid_bpp = 32;
227 break;
228#ifdef CONFIG_DM_VIDEO
229 case VIDEO_BPP16:
230#else
231 case LCD_COLOR16:
232#endif
233 vid_bpp = 16;
234 break;
235 }
236
237 return vid_bpp;
238}
239
Alexander Grafba718e62018-03-15 15:02:28 +0100240/*
241 * Gcc can't optimize our BLT function well, but we need to make sure that
242 * our 2-dimensional loop gets executed very quickly, otherwise the system
243 * will feel slow.
244 *
245 * By manually putting all obvious branch targets into functions which call
246 * our generic blt function with constants, the compiler can successfully
247 * optimize for speed.
248 */
249static efi_status_t gop_blt_video_fill(struct efi_gop *this,
250 struct efi_gop_pixel *buffer,
251 u32 foo, efi_uintn_t sx,
252 efi_uintn_t sy, efi_uintn_t dx,
253 efi_uintn_t dy, efi_uintn_t width,
Alexander Graf8e475062018-03-15 15:02:29 +0100254 efi_uintn_t height, efi_uintn_t delta,
255 efi_uintn_t vid_bpp)
Alexander Grafba718e62018-03-15 15:02:28 +0100256{
257 return gop_blt_int(this, buffer, EFI_BLT_VIDEO_FILL, sx, sy, dx,
Alexander Graf8e475062018-03-15 15:02:29 +0100258 dy, width, height, delta, vid_bpp);
Alexander Grafba718e62018-03-15 15:02:28 +0100259}
260
Alexander Graf8e475062018-03-15 15:02:29 +0100261static efi_status_t gop_blt_buf_to_vid16(struct efi_gop *this,
262 struct efi_gop_pixel *buffer,
263 u32 foo, efi_uintn_t sx,
264 efi_uintn_t sy, efi_uintn_t dx,
265 efi_uintn_t dy, efi_uintn_t width,
266 efi_uintn_t height, efi_uintn_t delta)
Alexander Grafba718e62018-03-15 15:02:28 +0100267{
268 return gop_blt_int(this, buffer, EFI_BLT_BUFFER_TO_VIDEO, sx, sy, dx,
Alexander Graf8e475062018-03-15 15:02:29 +0100269 dy, width, height, delta, 16);
270}
271
272static efi_status_t gop_blt_buf_to_vid32(struct efi_gop *this,
273 struct efi_gop_pixel *buffer,
274 u32 foo, efi_uintn_t sx,
275 efi_uintn_t sy, efi_uintn_t dx,
276 efi_uintn_t dy, efi_uintn_t width,
277 efi_uintn_t height, efi_uintn_t delta)
278{
279 return gop_blt_int(this, buffer, EFI_BLT_BUFFER_TO_VIDEO, sx, sy, dx,
280 dy, width, height, delta, 32);
Alexander Grafba718e62018-03-15 15:02:28 +0100281}
282
283static efi_status_t gop_blt_vid_to_vid(struct efi_gop *this,
284 struct efi_gop_pixel *buffer,
285 u32 foo, efi_uintn_t sx,
286 efi_uintn_t sy, efi_uintn_t dx,
287 efi_uintn_t dy, efi_uintn_t width,
Alexander Graf8e475062018-03-15 15:02:29 +0100288 efi_uintn_t height, efi_uintn_t delta,
289 efi_uintn_t vid_bpp)
Alexander Grafba718e62018-03-15 15:02:28 +0100290{
291 return gop_blt_int(this, buffer, EFI_BLT_VIDEO_TO_VIDEO, sx, sy, dx,
Alexander Graf8e475062018-03-15 15:02:29 +0100292 dy, width, height, delta, vid_bpp);
Alexander Grafba718e62018-03-15 15:02:28 +0100293}
294
295static efi_status_t gop_blt_vid_to_buf(struct efi_gop *this,
296 struct efi_gop_pixel *buffer,
297 u32 foo, efi_uintn_t sx,
298 efi_uintn_t sy, efi_uintn_t dx,
299 efi_uintn_t dy, efi_uintn_t width,
Alexander Graf8e475062018-03-15 15:02:29 +0100300 efi_uintn_t height, efi_uintn_t delta,
301 efi_uintn_t vid_bpp)
Alexander Grafba718e62018-03-15 15:02:28 +0100302{
303 return gop_blt_int(this, buffer, EFI_BLT_VIDEO_TO_BLT_BUFFER, sx, sy,
Alexander Graf8e475062018-03-15 15:02:29 +0100304 dx, dy, width, height, delta, vid_bpp);
Alexander Grafba718e62018-03-15 15:02:28 +0100305}
306
307/*
308 * Copy rectangle.
309 *
310 * This function implements the Blt service of the EFI_GRAPHICS_OUTPUT_PROTOCOL.
311 * See the Unified Extensible Firmware Interface (UEFI) specification for
312 * details.
313 *
314 * @this: EFI_GRAPHICS_OUTPUT_PROTOCOL
315 * @buffer: pixel buffer
316 * @sx: source x-coordinate
317 * @sy: source y-coordinate
318 * @dx: destination x-coordinate
319 * @dy: destination y-coordinate
320 * @width: width of rectangle
321 * @height: height of rectangle
322 * @delta: length in bytes of a line in the pixel buffer (optional)
323 * @return: status code
324 */
325efi_status_t EFIAPI gop_blt(struct efi_gop *this, struct efi_gop_pixel *buffer,
326 u32 operation, efi_uintn_t sx,
327 efi_uintn_t sy, efi_uintn_t dx,
328 efi_uintn_t dy, efi_uintn_t width,
329 efi_uintn_t height, efi_uintn_t delta)
330{
331 efi_status_t ret = EFI_INVALID_PARAMETER;
Alexander Graf8e475062018-03-15 15:02:29 +0100332 efi_uintn_t vid_bpp;
Alexander Grafba718e62018-03-15 15:02:28 +0100333
334 EFI_ENTRY("%p, %p, %u, %zu, %zu, %zu, %zu, %zu, %zu, %zu", this,
335 buffer, operation, sx, sy, dx, dy, width, height, delta);
336
Alexander Graf8e475062018-03-15 15:02:29 +0100337 vid_bpp = gop_get_bpp(this);
338
Alexander Grafba718e62018-03-15 15:02:28 +0100339 /* Allow for compiler optimization */
340 switch (operation) {
341 case EFI_BLT_VIDEO_FILL:
342 ret = gop_blt_video_fill(this, buffer, operation, sx, sy, dx,
Alexander Graf8e475062018-03-15 15:02:29 +0100343 dy, width, height, delta, vid_bpp);
Alexander Grafba718e62018-03-15 15:02:28 +0100344 break;
345 case EFI_BLT_BUFFER_TO_VIDEO:
Alexander Graf8e475062018-03-15 15:02:29 +0100346 /* This needs to be super-fast, so duplicate for 16/32bpp */
347 if (vid_bpp == 32)
348 ret = gop_blt_buf_to_vid32(this, buffer, operation, sx,
349 sy, dx, dy, width, height,
350 delta);
351 else
352 ret = gop_blt_buf_to_vid16(this, buffer, operation, sx,
353 sy, dx, dy, width, height,
354 delta);
Alexander Grafba718e62018-03-15 15:02:28 +0100355 break;
356 case EFI_BLT_VIDEO_TO_VIDEO:
357 ret = gop_blt_vid_to_vid(this, buffer, operation, sx, sy, dx,
Alexander Graf8e475062018-03-15 15:02:29 +0100358 dy, width, height, delta, vid_bpp);
Alexander Grafba718e62018-03-15 15:02:28 +0100359 break;
360 case EFI_BLT_VIDEO_TO_BLT_BUFFER:
361 ret = gop_blt_vid_to_buf(this, buffer, operation, sx, sy, dx,
Alexander Graf8e475062018-03-15 15:02:29 +0100362 dy, width, height, delta, vid_bpp);
Alexander Grafba718e62018-03-15 15:02:28 +0100363 break;
364 default:
365 ret = EFI_UNSUPPORTED;
366 }
367
368 if (ret != EFI_SUCCESS)
369 return EFI_EXIT(ret);
370
Alexander Grafa8122412016-06-05 22:34:31 +0200371#ifdef CONFIG_DM_VIDEO
372 video_sync_all();
373#else
Alexander Grafbe8d3242016-03-15 18:38:21 +0100374 lcd_sync();
Alexander Grafa8122412016-06-05 22:34:31 +0200375#endif
Alexander Grafbe8d3242016-03-15 18:38:21 +0100376
377 return EFI_EXIT(EFI_SUCCESS);
378}
379
Heinrich Schuchardt80ea9b02018-03-03 15:28:55 +0100380/*
381 * Install graphical output protocol.
382 *
383 * If no supported video device exists this is not considered as an
384 * error.
385 */
386efi_status_t efi_gop_register(void)
Alexander Grafbe8d3242016-03-15 18:38:21 +0100387{
388 struct efi_gop_obj *gopobj;
Alexander Grafa8122412016-06-05 22:34:31 +0200389 u32 bpix, col, row;
Alexander Graf8f661a52016-06-07 00:57:05 +0200390 u64 fb_base, fb_size;
Rob Clarkca9193d2017-07-21 15:00:27 -0400391 void *fb;
Heinrich Schuchardt94493582017-11-26 14:05:14 +0100392 efi_status_t ret;
Alexander Grafbe8d3242016-03-15 18:38:21 +0100393
Alexander Grafa8122412016-06-05 22:34:31 +0200394#ifdef CONFIG_DM_VIDEO
395 struct udevice *vdev;
Heinrich Schuchardt80ea9b02018-03-03 15:28:55 +0100396 struct video_priv *priv;
Alexander Grafa8122412016-06-05 22:34:31 +0200397
398 /* We only support a single video output device for now */
Heinrich Schuchardt80ea9b02018-03-03 15:28:55 +0100399 if (uclass_first_device(UCLASS_VIDEO, &vdev) || !vdev) {
400 debug("WARNING: No video device\n");
401 return EFI_SUCCESS;
402 }
Alexander Grafa8122412016-06-05 22:34:31 +0200403
Heinrich Schuchardt80ea9b02018-03-03 15:28:55 +0100404 priv = dev_get_uclass_priv(vdev);
Alexander Grafa8122412016-06-05 22:34:31 +0200405 bpix = priv->bpix;
406 col = video_get_xsize(vdev);
407 row = video_get_ysize(vdev);
Alexander Graf8f661a52016-06-07 00:57:05 +0200408 fb_base = (uintptr_t)priv->fb;
409 fb_size = priv->fb_size;
Rob Clarkca9193d2017-07-21 15:00:27 -0400410 fb = priv->fb;
Alexander Grafa8122412016-06-05 22:34:31 +0200411#else
Alexander Graf8f661a52016-06-07 00:57:05 +0200412 int line_len;
Alexander Grafa8122412016-06-05 22:34:31 +0200413
414 bpix = panel_info.vl_bpix;
415 col = panel_info.vl_col;
416 row = panel_info.vl_row;
Alexander Graf8f661a52016-06-07 00:57:05 +0200417 fb_base = gd->fb_base;
418 fb_size = lcd_get_size(&line_len);
Alexander Grafc1ae1a12017-07-31 09:15:57 +0200419 fb = (void*)gd->fb_base;
Alexander Grafa8122412016-06-05 22:34:31 +0200420#endif
421
422 switch (bpix) {
423#ifdef CONFIG_DM_VIDEO
424 case VIDEO_BPP16:
425 case VIDEO_BPP32:
426#else
Alexander Grafbe8d3242016-03-15 18:38:21 +0100427 case LCD_COLOR32:
428 case LCD_COLOR16:
Alexander Grafa8122412016-06-05 22:34:31 +0200429#endif
Alexander Grafbe8d3242016-03-15 18:38:21 +0100430 break;
431 default:
432 /* So far, we only work in 16 or 32 bit mode */
Heinrich Schuchardt80ea9b02018-03-03 15:28:55 +0100433 debug("WARNING: Unsupported video mode\n");
434 return EFI_SUCCESS;
Alexander Grafbe8d3242016-03-15 18:38:21 +0100435 }
436
437 gopobj = calloc(1, sizeof(*gopobj));
Heinrich Schuchardt753edb12017-10-26 19:25:45 +0200438 if (!gopobj) {
439 printf("ERROR: Out of memory\n");
Heinrich Schuchardt80ea9b02018-03-03 15:28:55 +0100440 return EFI_OUT_OF_RESOURCES;
Heinrich Schuchardt753edb12017-10-26 19:25:45 +0200441 }
Alexander Grafbe8d3242016-03-15 18:38:21 +0100442
Heinrich Schuchardt94493582017-11-26 14:05:14 +0100443 /* Hook up to the device list */
Heinrich Schuchardt44549d62017-11-26 14:05:23 +0100444 efi_add_handle(&gopobj->parent);
Heinrich Schuchardt94493582017-11-26 14:05:14 +0100445
Alexander Grafbe8d3242016-03-15 18:38:21 +0100446 /* Fill in object data */
Heinrich Schuchardt94493582017-11-26 14:05:14 +0100447 ret = efi_add_protocol(gopobj->parent.handle, &efi_gop_guid,
448 &gopobj->ops);
449 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt80ea9b02018-03-03 15:28:55 +0100450 printf("ERROR: Failure adding gop protocol\n");
451 return ret;
Heinrich Schuchardt94493582017-11-26 14:05:14 +0100452 }
Alexander Grafbe8d3242016-03-15 18:38:21 +0100453 gopobj->ops.query_mode = gop_query_mode;
454 gopobj->ops.set_mode = gop_set_mode;
455 gopobj->ops.blt = gop_blt;
456 gopobj->ops.mode = &gopobj->mode;
457
458 gopobj->mode.max_mode = 1;
459 gopobj->mode.info = &gopobj->info;
460 gopobj->mode.info_size = sizeof(gopobj->info);
Alexander Grafbe8d3242016-03-15 18:38:21 +0100461
Alexander Graf8f661a52016-06-07 00:57:05 +0200462#ifdef CONFIG_DM_VIDEO
Heinrich Schuchardt80ea9b02018-03-03 15:28:55 +0100463 if (bpix == VIDEO_BPP32)
Alexander Graf8f661a52016-06-07 00:57:05 +0200464#else
Heinrich Schuchardt80ea9b02018-03-03 15:28:55 +0100465 if (bpix == LCD_COLOR32)
Alexander Graf8f661a52016-06-07 00:57:05 +0200466#endif
Heinrich Schuchardt80ea9b02018-03-03 15:28:55 +0100467 {
Alexander Graf8f661a52016-06-07 00:57:05 +0200468 /* With 32bit color space we can directly expose the fb */
469 gopobj->mode.fb_base = fb_base;
470 gopobj->mode.fb_size = fb_size;
471 }
472
Alexander Grafbe8d3242016-03-15 18:38:21 +0100473 gopobj->info.version = 0;
Alexander Grafa8122412016-06-05 22:34:31 +0200474 gopobj->info.width = col;
475 gopobj->info.height = row;
Alexander Grafbe8d3242016-03-15 18:38:21 +0100476 gopobj->info.pixel_format = EFI_GOT_RGBA8;
Alexander Grafa8122412016-06-05 22:34:31 +0200477 gopobj->info.pixels_per_scanline = col;
478
479 gopobj->bpix = bpix;
Rob Clarkca9193d2017-07-21 15:00:27 -0400480 gopobj->fb = fb;
Alexander Grafbe8d3242016-03-15 18:38:21 +0100481
Heinrich Schuchardt80ea9b02018-03-03 15:28:55 +0100482 return EFI_SUCCESS;
Alexander Grafbe8d3242016-03-15 18:38:21 +0100483}