xref: /rk3399_rockchip-uboot/lib/efi_loader/efi_gop.c (revision 5395ac06d271209f5904a9da4392a3d8dad7597e)
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;
31ca9193d2SRob Clark 	void *fb;
32be8d3241SAlexander Graf };
33be8d3241SAlexander Graf 
gop_query_mode(struct efi_gop * this,u32 mode_number,unsigned long * size_of_info,struct efi_gop_mode_info ** info)34be8d3241SAlexander Graf static efi_status_t EFIAPI gop_query_mode(struct efi_gop *this, u32 mode_number,
35be8d3241SAlexander Graf 					  unsigned long *size_of_info,
36be8d3241SAlexander Graf 					  struct efi_gop_mode_info **info)
37be8d3241SAlexander Graf {
38be8d3241SAlexander Graf 	struct efi_gop_obj *gopobj;
39be8d3241SAlexander Graf 
40be8d3241SAlexander Graf 	EFI_ENTRY("%p, %x, %p, %p", this, mode_number, size_of_info, info);
41be8d3241SAlexander Graf 
42be8d3241SAlexander Graf 	gopobj = container_of(this, struct efi_gop_obj, ops);
43be8d3241SAlexander Graf 	*size_of_info = sizeof(gopobj->info);
44be8d3241SAlexander Graf 	*info = &gopobj->info;
45be8d3241SAlexander Graf 
46be8d3241SAlexander Graf 	return EFI_EXIT(EFI_SUCCESS);
47be8d3241SAlexander Graf }
48be8d3241SAlexander Graf 
gop_set_mode(struct efi_gop * this,u32 mode_number)49be8d3241SAlexander Graf static efi_status_t EFIAPI gop_set_mode(struct efi_gop *this, u32 mode_number)
50be8d3241SAlexander Graf {
51be8d3241SAlexander Graf 	EFI_ENTRY("%p, %x", this, mode_number);
52be8d3241SAlexander Graf 
53be8d3241SAlexander Graf 	if (mode_number != 0)
54be8d3241SAlexander Graf 		return EFI_EXIT(EFI_INVALID_PARAMETER);
55be8d3241SAlexander Graf 
56be8d3241SAlexander Graf 	return EFI_EXIT(EFI_SUCCESS);
57be8d3241SAlexander Graf }
58be8d3241SAlexander Graf 
gop_blt(struct efi_gop * this,void * buffer,unsigned long operation,unsigned long sx,unsigned long sy,unsigned long dx,unsigned long dy,unsigned long width,unsigned long height,unsigned long delta)59be8d3241SAlexander Graf static efi_status_t EFIAPI gop_blt(struct efi_gop *this, void *buffer,
60be8d3241SAlexander Graf 				   unsigned long operation, unsigned long sx,
61be8d3241SAlexander Graf 				   unsigned long sy, unsigned long dx,
62be8d3241SAlexander Graf 				   unsigned long dy, unsigned long width,
63be8d3241SAlexander Graf 				   unsigned long height, unsigned long delta)
64be8d3241SAlexander Graf {
65a8122410SAlexander Graf 	struct efi_gop_obj *gopobj = container_of(this, struct efi_gop_obj, ops);
66be8d3241SAlexander Graf 	int i, j, line_len16, line_len32;
67be8d3241SAlexander Graf 	void *fb;
68be8d3241SAlexander Graf 
69be8d3241SAlexander Graf 	EFI_ENTRY("%p, %p, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx", this,
70be8d3241SAlexander Graf 		  buffer, operation, sx, sy, dx, dy, width, height, delta);
71be8d3241SAlexander Graf 
72be8d3241SAlexander Graf 	if (operation != EFI_BLT_BUFFER_TO_VIDEO)
73be8d3241SAlexander Graf 		return EFI_EXIT(EFI_INVALID_PARAMETER);
74be8d3241SAlexander Graf 
75ca9193d2SRob Clark 	fb = gopobj->fb;
76a8122410SAlexander Graf 	line_len16 = gopobj->info.width * sizeof(u16);
77a8122410SAlexander Graf 	line_len32 = gopobj->info.width * sizeof(u32);
78be8d3241SAlexander Graf 
79be8d3241SAlexander Graf 	/* Copy the contents line by line */
80be8d3241SAlexander Graf 
81a8122410SAlexander Graf 	switch (gopobj->bpix) {
82a8122410SAlexander Graf #ifdef CONFIG_DM_VIDEO
83a8122410SAlexander Graf 	case VIDEO_BPP32:
84a8122410SAlexander Graf #else
85be8d3241SAlexander Graf 	case LCD_COLOR32:
86a8122410SAlexander Graf #endif
87be8d3241SAlexander Graf 		for (i = 0; i < height; i++) {
88be8d3241SAlexander Graf 			u32 *dest = fb + ((i + dy)  * line_len32) +
89be8d3241SAlexander Graf 					 (dx * sizeof(u32));
90be8d3241SAlexander Graf 			u32 *src = buffer + ((i + sy)  * line_len32) +
91be8d3241SAlexander Graf 					 (sx * sizeof(u32));
92be8d3241SAlexander Graf 
93be8d3241SAlexander Graf 			/* Same color format, just memcpy */
94be8d3241SAlexander Graf 			memcpy(dest, src, width * sizeof(u32));
95be8d3241SAlexander Graf 		}
96be8d3241SAlexander Graf 		break;
97a8122410SAlexander Graf #ifdef CONFIG_DM_VIDEO
98a8122410SAlexander Graf 	case VIDEO_BPP16:
99a8122410SAlexander Graf #else
100be8d3241SAlexander Graf 	case LCD_COLOR16:
101a8122410SAlexander Graf #endif
102be8d3241SAlexander Graf 		for (i = 0; i < height; i++) {
103be8d3241SAlexander Graf 			u16 *dest = fb + ((i + dy)  * line_len16) +
104be8d3241SAlexander Graf 					 (dx * sizeof(u16));
105be8d3241SAlexander Graf 			u32 *src = buffer + ((i + sy)  * line_len32) +
106be8d3241SAlexander Graf 					 (sx * sizeof(u32));
107be8d3241SAlexander Graf 
108be8d3241SAlexander Graf 			/* Convert from rgb888 to rgb565 */
109be8d3241SAlexander Graf 			for (j = 0; j < width; j++) {
110be8d3241SAlexander Graf 				u32 rgb888 = src[j];
111be8d3241SAlexander Graf 				dest[j] = ((((rgb888 >> (16 + 3)) & 0x1f) << 11) |
112be8d3241SAlexander Graf 					   (((rgb888 >> (8 + 2)) & 0x3f) << 5) |
113be8d3241SAlexander Graf 					   (((rgb888 >> (0 + 3)) & 0x1f) << 0));
114be8d3241SAlexander Graf 			}
115be8d3241SAlexander Graf 		}
116be8d3241SAlexander Graf 		break;
117be8d3241SAlexander Graf 	}
118be8d3241SAlexander Graf 
119a8122410SAlexander Graf #ifdef CONFIG_DM_VIDEO
120a8122410SAlexander Graf 	video_sync_all();
121a8122410SAlexander Graf #else
122be8d3241SAlexander Graf 	lcd_sync();
123a8122410SAlexander Graf #endif
124be8d3241SAlexander Graf 
125be8d3241SAlexander Graf 	return EFI_EXIT(EFI_SUCCESS);
126be8d3241SAlexander Graf }
127be8d3241SAlexander Graf 
128be8d3241SAlexander Graf /* This gets called from do_bootefi_exec(). */
efi_gop_register(void)129be8d3241SAlexander Graf int efi_gop_register(void)
130be8d3241SAlexander Graf {
131be8d3241SAlexander Graf 	struct efi_gop_obj *gopobj;
132a8122410SAlexander Graf 	u32 bpix, col, row;
1338f661a5bSAlexander Graf 	u64 fb_base, fb_size;
134ca9193d2SRob Clark 	void *fb;
135be8d3241SAlexander Graf 
136a8122410SAlexander Graf #ifdef CONFIG_DM_VIDEO
137a8122410SAlexander Graf 	struct udevice *vdev;
138a8122410SAlexander Graf 
139a8122410SAlexander Graf 	/* We only support a single video output device for now */
140*5395ac06SMichal Suchanek 	uclass_first_device(UCLASS_VIDEO, &vdev);
141*5395ac06SMichal Suchanek 	if (!vdev)
142a8122410SAlexander Graf 		return -1;
143a8122410SAlexander Graf 
144a8122410SAlexander Graf 	struct video_priv *priv = dev_get_uclass_priv(vdev);
145a8122410SAlexander Graf 	bpix = priv->bpix;
146a8122410SAlexander Graf 	col = video_get_xsize(vdev);
147a8122410SAlexander Graf 	row = video_get_ysize(vdev);
1488f661a5bSAlexander Graf 	fb_base = (uintptr_t)priv->fb;
1498f661a5bSAlexander Graf 	fb_size = priv->fb_size;
150ca9193d2SRob Clark 	fb = priv->fb;
151a8122410SAlexander Graf #else
1528f661a5bSAlexander Graf 	int line_len;
153a8122410SAlexander Graf 
154a8122410SAlexander Graf 	bpix = panel_info.vl_bpix;
155a8122410SAlexander Graf 	col = panel_info.vl_col;
156a8122410SAlexander Graf 	row = panel_info.vl_row;
1578f661a5bSAlexander Graf 	fb_base = gd->fb_base;
1588f661a5bSAlexander Graf 	fb_size = lcd_get_size(&line_len);
159c1ae1a16SAlexander Graf 	fb = (void*)gd->fb_base;
160a8122410SAlexander Graf #endif
161a8122410SAlexander Graf 
162a8122410SAlexander Graf 	switch (bpix) {
163a8122410SAlexander Graf #ifdef CONFIG_DM_VIDEO
164a8122410SAlexander Graf 	case VIDEO_BPP16:
165a8122410SAlexander Graf 	case VIDEO_BPP32:
166a8122410SAlexander Graf #else
167be8d3241SAlexander Graf 	case LCD_COLOR32:
168be8d3241SAlexander Graf 	case LCD_COLOR16:
169a8122410SAlexander Graf #endif
170be8d3241SAlexander Graf 		break;
171be8d3241SAlexander Graf 	default:
172be8d3241SAlexander Graf 		/* So far, we only work in 16 or 32 bit mode */
173be8d3241SAlexander Graf 		return -1;
174be8d3241SAlexander Graf 	}
175be8d3241SAlexander Graf 
176be8d3241SAlexander Graf 	gopobj = calloc(1, sizeof(*gopobj));
177be8d3241SAlexander Graf 
178be8d3241SAlexander Graf 	/* Fill in object data */
179be8d3241SAlexander Graf 	gopobj->parent.protocols[0].guid = &efi_gop_guid;
180b5349f74Sxypron.glpk@gmx.de 	gopobj->parent.protocols[0].protocol_interface = &gopobj->ops;
181be8d3241SAlexander Graf 	gopobj->parent.handle = &gopobj->ops;
182be8d3241SAlexander Graf 	gopobj->ops.query_mode = gop_query_mode;
183be8d3241SAlexander Graf 	gopobj->ops.set_mode = gop_set_mode;
184be8d3241SAlexander Graf 	gopobj->ops.blt = gop_blt;
185be8d3241SAlexander Graf 	gopobj->ops.mode = &gopobj->mode;
186be8d3241SAlexander Graf 
187be8d3241SAlexander Graf 	gopobj->mode.max_mode = 1;
188be8d3241SAlexander Graf 	gopobj->mode.info = &gopobj->info;
189be8d3241SAlexander Graf 	gopobj->mode.info_size = sizeof(gopobj->info);
190be8d3241SAlexander Graf 
1918f661a5bSAlexander Graf #ifdef CONFIG_DM_VIDEO
1928f661a5bSAlexander Graf 	if (bpix == VIDEO_BPP32) {
1938f661a5bSAlexander Graf #else
1948f661a5bSAlexander Graf 	if (bpix == LCD_COLOR32) {
1958f661a5bSAlexander Graf #endif
1968f661a5bSAlexander Graf 		/* With 32bit color space we can directly expose the fb */
1978f661a5bSAlexander Graf 		gopobj->mode.fb_base = fb_base;
1988f661a5bSAlexander Graf 		gopobj->mode.fb_size = fb_size;
1998f661a5bSAlexander Graf 	}
2008f661a5bSAlexander Graf 
201be8d3241SAlexander Graf 	gopobj->info.version = 0;
202a8122410SAlexander Graf 	gopobj->info.width = col;
203a8122410SAlexander Graf 	gopobj->info.height = row;
204be8d3241SAlexander Graf 	gopobj->info.pixel_format = EFI_GOT_RGBA8;
205a8122410SAlexander Graf 	gopobj->info.pixels_per_scanline = col;
206a8122410SAlexander Graf 
207a8122410SAlexander Graf 	gopobj->bpix = bpix;
208ca9193d2SRob Clark 	gopobj->fb = fb;
209be8d3241SAlexander Graf 
210be8d3241SAlexander Graf 	/* Hook up to the device list */
211be8d3241SAlexander Graf 	list_add_tail(&gopobj->parent.link, &efi_obj_list);
212be8d3241SAlexander Graf 
213be8d3241SAlexander Graf 	return 0;
214be8d3241SAlexander Graf }
215