xref: /rk3399_rockchip-uboot/lib/efi_loader/efi_gop.c (revision b5349f742a7684aabd3fb8f0e20c67ba033deec7)
1be8d3241SAlexander Graf /*
2be8d3241SAlexander Graf  *  EFI application disk support
3be8d3241SAlexander Graf  *
4be8d3241SAlexander Graf  *  Copyright (c) 2016 Alexander Graf
5be8d3241SAlexander Graf  *
6be8d3241SAlexander Graf  *  SPDX-License-Identifier:     GPL-2.0+
7be8d3241SAlexander Graf  */
8be8d3241SAlexander Graf 
9be8d3241SAlexander Graf #include <common.h>
10a8122410SAlexander Graf #include <dm.h>
11be8d3241SAlexander Graf #include <efi_loader.h>
12be8d3241SAlexander Graf #include <inttypes.h>
13be8d3241SAlexander Graf #include <lcd.h>
14be8d3241SAlexander Graf #include <malloc.h>
15a8122410SAlexander Graf #include <video.h>
16be8d3241SAlexander Graf 
17be8d3241SAlexander Graf DECLARE_GLOBAL_DATA_PTR;
18be8d3241SAlexander Graf 
19be8d3241SAlexander Graf static const efi_guid_t efi_gop_guid = EFI_GOP_GUID;
20be8d3241SAlexander Graf 
21be8d3241SAlexander Graf struct efi_gop_obj {
22be8d3241SAlexander Graf 	/* Generic EFI object parent class data */
23be8d3241SAlexander Graf 	struct efi_object parent;
24be8d3241SAlexander Graf 	/* EFI Interface callback struct for gop */
25be8d3241SAlexander Graf 	struct efi_gop ops;
26be8d3241SAlexander Graf 	/* The only mode we support */
27be8d3241SAlexander Graf 	struct efi_gop_mode_info info;
28be8d3241SAlexander Graf 	struct efi_gop_mode mode;
29a8122410SAlexander Graf 	/* Fields we only have acces to during init */
30a8122410SAlexander Graf 	u32 bpix;
31be8d3241SAlexander Graf };
32be8d3241SAlexander Graf 
33be8d3241SAlexander Graf static efi_status_t EFIAPI gop_query_mode(struct efi_gop *this, u32 mode_number,
34be8d3241SAlexander Graf 					  unsigned long *size_of_info,
35be8d3241SAlexander Graf 					  struct efi_gop_mode_info **info)
36be8d3241SAlexander Graf {
37be8d3241SAlexander Graf 	struct efi_gop_obj *gopobj;
38be8d3241SAlexander Graf 
39be8d3241SAlexander Graf 	EFI_ENTRY("%p, %x, %p, %p", this, mode_number, size_of_info, info);
40be8d3241SAlexander Graf 
41be8d3241SAlexander Graf 	gopobj = container_of(this, struct efi_gop_obj, ops);
42be8d3241SAlexander Graf 	*size_of_info = sizeof(gopobj->info);
43be8d3241SAlexander Graf 	*info = &gopobj->info;
44be8d3241SAlexander Graf 
45be8d3241SAlexander Graf 	return EFI_EXIT(EFI_SUCCESS);
46be8d3241SAlexander Graf }
47be8d3241SAlexander Graf 
48be8d3241SAlexander Graf static efi_status_t EFIAPI gop_set_mode(struct efi_gop *this, u32 mode_number)
49be8d3241SAlexander Graf {
50be8d3241SAlexander Graf 	EFI_ENTRY("%p, %x", this, mode_number);
51be8d3241SAlexander Graf 
52be8d3241SAlexander Graf 	if (mode_number != 0)
53be8d3241SAlexander Graf 		return EFI_EXIT(EFI_INVALID_PARAMETER);
54be8d3241SAlexander Graf 
55be8d3241SAlexander Graf 	return EFI_EXIT(EFI_SUCCESS);
56be8d3241SAlexander Graf }
57be8d3241SAlexander Graf 
58be8d3241SAlexander Graf static efi_status_t EFIAPI gop_blt(struct efi_gop *this, void *buffer,
59be8d3241SAlexander Graf 				   unsigned long operation, unsigned long sx,
60be8d3241SAlexander Graf 				   unsigned long sy, unsigned long dx,
61be8d3241SAlexander Graf 				   unsigned long dy, unsigned long width,
62be8d3241SAlexander Graf 				   unsigned long height, unsigned long delta)
63be8d3241SAlexander Graf {
64a8122410SAlexander Graf 	struct efi_gop_obj *gopobj = container_of(this, struct efi_gop_obj, ops);
65be8d3241SAlexander Graf 	int i, j, line_len16, line_len32;
66be8d3241SAlexander Graf 	void *fb;
67be8d3241SAlexander Graf 
68be8d3241SAlexander Graf 	EFI_ENTRY("%p, %p, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx", this,
69be8d3241SAlexander Graf 		  buffer, operation, sx, sy, dx, dy, width, height, delta);
70be8d3241SAlexander Graf 
71be8d3241SAlexander Graf 	if (operation != EFI_BLT_BUFFER_TO_VIDEO)
72be8d3241SAlexander Graf 		return EFI_EXIT(EFI_INVALID_PARAMETER);
73be8d3241SAlexander Graf 
74be8d3241SAlexander Graf 	fb = (void*)gd->fb_base;
75a8122410SAlexander Graf 	line_len16 = gopobj->info.width * sizeof(u16);
76a8122410SAlexander Graf 	line_len32 = gopobj->info.width * sizeof(u32);
77be8d3241SAlexander Graf 
78be8d3241SAlexander Graf 	/* Copy the contents line by line */
79be8d3241SAlexander Graf 
80a8122410SAlexander Graf 	switch (gopobj->bpix) {
81a8122410SAlexander Graf #ifdef CONFIG_DM_VIDEO
82a8122410SAlexander Graf 	case VIDEO_BPP32:
83a8122410SAlexander Graf #else
84be8d3241SAlexander Graf 	case LCD_COLOR32:
85a8122410SAlexander Graf #endif
86be8d3241SAlexander Graf 		for (i = 0; i < height; i++) {
87be8d3241SAlexander Graf 			u32 *dest = fb + ((i + dy)  * line_len32) +
88be8d3241SAlexander Graf 					 (dx * sizeof(u32));
89be8d3241SAlexander Graf 			u32 *src = buffer + ((i + sy)  * line_len32) +
90be8d3241SAlexander Graf 					 (sx * sizeof(u32));
91be8d3241SAlexander Graf 
92be8d3241SAlexander Graf 			/* Same color format, just memcpy */
93be8d3241SAlexander Graf 			memcpy(dest, src, width * sizeof(u32));
94be8d3241SAlexander Graf 		}
95be8d3241SAlexander Graf 		break;
96a8122410SAlexander Graf #ifdef CONFIG_DM_VIDEO
97a8122410SAlexander Graf 	case VIDEO_BPP16:
98a8122410SAlexander Graf #else
99be8d3241SAlexander Graf 	case LCD_COLOR16:
100a8122410SAlexander Graf #endif
101be8d3241SAlexander Graf 		for (i = 0; i < height; i++) {
102be8d3241SAlexander Graf 			u16 *dest = fb + ((i + dy)  * line_len16) +
103be8d3241SAlexander Graf 					 (dx * sizeof(u16));
104be8d3241SAlexander Graf 			u32 *src = buffer + ((i + sy)  * line_len32) +
105be8d3241SAlexander Graf 					 (sx * sizeof(u32));
106be8d3241SAlexander Graf 
107be8d3241SAlexander Graf 			/* Convert from rgb888 to rgb565 */
108be8d3241SAlexander Graf 			for (j = 0; j < width; j++) {
109be8d3241SAlexander Graf 				u32 rgb888 = src[j];
110be8d3241SAlexander Graf 				dest[j] = ((((rgb888 >> (16 + 3)) & 0x1f) << 11) |
111be8d3241SAlexander Graf 					   (((rgb888 >> (8 + 2)) & 0x3f) << 5) |
112be8d3241SAlexander Graf 					   (((rgb888 >> (0 + 3)) & 0x1f) << 0));
113be8d3241SAlexander Graf 			}
114be8d3241SAlexander Graf 		}
115be8d3241SAlexander Graf 		break;
116be8d3241SAlexander Graf 	}
117be8d3241SAlexander Graf 
118a8122410SAlexander Graf #ifdef CONFIG_DM_VIDEO
119a8122410SAlexander Graf 	video_sync_all();
120a8122410SAlexander Graf #else
121be8d3241SAlexander Graf 	lcd_sync();
122a8122410SAlexander Graf #endif
123be8d3241SAlexander Graf 
124be8d3241SAlexander Graf 	return EFI_EXIT(EFI_SUCCESS);
125be8d3241SAlexander Graf }
126be8d3241SAlexander Graf 
127be8d3241SAlexander Graf /* This gets called from do_bootefi_exec(). */
128be8d3241SAlexander Graf int efi_gop_register(void)
129be8d3241SAlexander Graf {
130be8d3241SAlexander Graf 	struct efi_gop_obj *gopobj;
131a8122410SAlexander Graf 	u32 bpix, col, row;
1328f661a5bSAlexander Graf 	u64 fb_base, fb_size;
133be8d3241SAlexander Graf 
134a8122410SAlexander Graf #ifdef CONFIG_DM_VIDEO
135a8122410SAlexander Graf 	struct udevice *vdev;
136a8122410SAlexander Graf 
137a8122410SAlexander Graf 	/* We only support a single video output device for now */
138a8122410SAlexander Graf 	if (uclass_first_device(UCLASS_VIDEO, &vdev))
139a8122410SAlexander Graf 		return -1;
140a8122410SAlexander Graf 
141a8122410SAlexander Graf 	struct video_priv *priv = dev_get_uclass_priv(vdev);
142a8122410SAlexander Graf 	bpix = priv->bpix;
143a8122410SAlexander Graf 	col = video_get_xsize(vdev);
144a8122410SAlexander Graf 	row = video_get_ysize(vdev);
1458f661a5bSAlexander Graf 	fb_base = (uintptr_t)priv->fb;
1468f661a5bSAlexander Graf 	fb_size = priv->fb_size;
147a8122410SAlexander Graf #else
1488f661a5bSAlexander Graf 	int line_len;
149a8122410SAlexander Graf 
150a8122410SAlexander Graf 	bpix = panel_info.vl_bpix;
151a8122410SAlexander Graf 	col = panel_info.vl_col;
152a8122410SAlexander Graf 	row = panel_info.vl_row;
1538f661a5bSAlexander Graf 	fb_base = gd->fb_base;
1548f661a5bSAlexander Graf 	fb_size = lcd_get_size(&line_len);
155a8122410SAlexander Graf #endif
156a8122410SAlexander Graf 
157a8122410SAlexander Graf 	switch (bpix) {
158a8122410SAlexander Graf #ifdef CONFIG_DM_VIDEO
159a8122410SAlexander Graf 	case VIDEO_BPP16:
160a8122410SAlexander Graf 	case VIDEO_BPP32:
161a8122410SAlexander Graf #else
162be8d3241SAlexander Graf 	case LCD_COLOR32:
163be8d3241SAlexander Graf 	case LCD_COLOR16:
164a8122410SAlexander Graf #endif
165be8d3241SAlexander Graf 		break;
166be8d3241SAlexander Graf 	default:
167be8d3241SAlexander Graf 		/* So far, we only work in 16 or 32 bit mode */
168be8d3241SAlexander Graf 		return -1;
169be8d3241SAlexander Graf 	}
170be8d3241SAlexander Graf 
171be8d3241SAlexander Graf 	gopobj = calloc(1, sizeof(*gopobj));
172be8d3241SAlexander Graf 
173be8d3241SAlexander Graf 	/* Fill in object data */
174be8d3241SAlexander Graf 	gopobj->parent.protocols[0].guid = &efi_gop_guid;
175*b5349f74Sxypron.glpk@gmx.de 	gopobj->parent.protocols[0].protocol_interface = &gopobj->ops;
176be8d3241SAlexander Graf 	gopobj->parent.handle = &gopobj->ops;
177be8d3241SAlexander Graf 	gopobj->ops.query_mode = gop_query_mode;
178be8d3241SAlexander Graf 	gopobj->ops.set_mode = gop_set_mode;
179be8d3241SAlexander Graf 	gopobj->ops.blt = gop_blt;
180be8d3241SAlexander Graf 	gopobj->ops.mode = &gopobj->mode;
181be8d3241SAlexander Graf 
182be8d3241SAlexander Graf 	gopobj->mode.max_mode = 1;
183be8d3241SAlexander Graf 	gopobj->mode.info = &gopobj->info;
184be8d3241SAlexander Graf 	gopobj->mode.info_size = sizeof(gopobj->info);
185be8d3241SAlexander Graf 
1868f661a5bSAlexander Graf #ifdef CONFIG_DM_VIDEO
1878f661a5bSAlexander Graf 	if (bpix == VIDEO_BPP32) {
1888f661a5bSAlexander Graf #else
1898f661a5bSAlexander Graf 	if (bpix == LCD_COLOR32) {
1908f661a5bSAlexander Graf #endif
1918f661a5bSAlexander Graf 		/* With 32bit color space we can directly expose the fb */
1928f661a5bSAlexander Graf 		gopobj->mode.fb_base = fb_base;
1938f661a5bSAlexander Graf 		gopobj->mode.fb_size = fb_size;
1948f661a5bSAlexander Graf 	}
1958f661a5bSAlexander Graf 
196be8d3241SAlexander Graf 	gopobj->info.version = 0;
197a8122410SAlexander Graf 	gopobj->info.width = col;
198a8122410SAlexander Graf 	gopobj->info.height = row;
199be8d3241SAlexander Graf 	gopobj->info.pixel_format = EFI_GOT_RGBA8;
200a8122410SAlexander Graf 	gopobj->info.pixels_per_scanline = col;
201a8122410SAlexander Graf 
202a8122410SAlexander Graf 	gopobj->bpix = bpix;
203be8d3241SAlexander Graf 
204be8d3241SAlexander Graf 	/* Hook up to the device list */
205be8d3241SAlexander Graf 	list_add_tail(&gopobj->parent.link, &efi_obj_list);
206be8d3241SAlexander Graf 
207be8d3241SAlexander Graf 	return 0;
208be8d3241SAlexander Graf }
209