]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Drivers/LcdGraphicsOutputDxe/LcdGraphicsOutputDxe.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / ArmPlatformPkg / Drivers / LcdGraphicsOutputDxe / LcdGraphicsOutputDxe.c
1 /** @file
2 This file implements the Graphics Output protocol for Arm platforms
3
4 Copyright (c) 2011 - 2020, Arm Limited. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include <PiDxe.h>
10 #include <Library/BaseMemoryLib.h>
11 #include <Library/DevicePathLib.h>
12 #include <Library/UefiBootServicesTableLib.h>
13 #include <Library/UefiRuntimeServicesTableLib.h>
14 #include <Library/MemoryAllocationLib.h>
15
16 #include <Guid/GlobalVariable.h>
17
18 #include "LcdGraphicsOutputDxe.h"
19
20 //
21 // Global variables
22 //
23
24 BOOLEAN mDisplayInitialized = FALSE;
25
26 LCD_INSTANCE mLcdTemplate = {
27 LCD_INSTANCE_SIGNATURE,
28 NULL, // Handle
29 { // ModeInfo
30 0, // Version
31 0, // HorizontalResolution
32 0, // VerticalResolution
33 PixelBltOnly, // PixelFormat
34 { 0 }, // PixelInformation
35 0, // PixelsPerScanLine
36 },
37 {
38 0, // MaxMode;
39 0, // Mode;
40 NULL, // Info;
41 0, // SizeOfInfo;
42 0, // FrameBufferBase;
43 0 // FrameBufferSize;
44 },
45 { // Gop
46 LcdGraphicsQueryMode, // QueryMode
47 LcdGraphicsSetMode, // SetMode
48 LcdGraphicsBlt, // Blt
49 NULL // *Mode
50 },
51 { // DevicePath
52 {
53 {
54 HARDWARE_DEVICE_PATH, HW_VENDOR_DP,
55 {
56 (UINT8)(sizeof (VENDOR_DEVICE_PATH)),
57 (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)
58 },
59 },
60 // Hardware Device Path for Lcd
61 EFI_CALLER_ID_GUID // Use the driver's GUID
62 },
63
64 {
65 END_DEVICE_PATH_TYPE,
66 END_ENTIRE_DEVICE_PATH_SUBTYPE,
67 {
68 sizeof (EFI_DEVICE_PATH_PROTOCOL),
69 0
70 }
71 }
72 },
73 (EFI_EVENT)NULL // ExitBootServicesEvent
74 };
75
76 EFI_STATUS
77 LcdInstanceContructor (
78 OUT LCD_INSTANCE **NewInstance
79 )
80 {
81 LCD_INSTANCE *Instance;
82
83 Instance = AllocateCopyPool (sizeof (LCD_INSTANCE), &mLcdTemplate);
84 if (Instance == NULL) {
85 return EFI_OUT_OF_RESOURCES;
86 }
87
88 Instance->Gop.Mode = &Instance->Mode;
89 Instance->Gop.Mode->MaxMode = LcdPlatformGetMaxMode ();
90 Instance->Mode.Info = &Instance->ModeInfo;
91
92 *NewInstance = Instance;
93 return EFI_SUCCESS;
94 }
95
96 //
97 // Function Definitions
98 //
99
100 EFI_STATUS
101 InitializeDisplay (
102 IN LCD_INSTANCE *Instance
103 )
104 {
105 EFI_STATUS Status;
106 EFI_PHYSICAL_ADDRESS VramBaseAddress;
107 UINTN VramSize;
108
109 Status = LcdPlatformGetVram (&VramBaseAddress, &VramSize);
110 if (EFI_ERROR (Status)) {
111 return Status;
112 }
113
114 // Setup the LCD
115 Status = LcdInitialize (VramBaseAddress);
116 if (EFI_ERROR (Status)) {
117 goto EXIT_ERROR_LCD_SHUTDOWN;
118 }
119
120 Status = LcdPlatformInitializeDisplay (Instance->Handle);
121 if (EFI_ERROR (Status)) {
122 goto EXIT_ERROR_LCD_SHUTDOWN;
123 }
124
125 // Setup all the relevant mode information
126 Instance->Gop.Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
127 Instance->Gop.Mode->FrameBufferBase = VramBaseAddress;
128
129 // Set the flag before changing the mode, to avoid infinite loops
130 mDisplayInitialized = TRUE;
131
132 // All is ok, so don't deal with any errors
133 goto EXIT;
134
135 EXIT_ERROR_LCD_SHUTDOWN:
136 DEBUG ((DEBUG_ERROR, "InitializeDisplay: ERROR - Can not initialise the display. Exit Status=%r\n", Status));
137
138 LcdShutdown ();
139
140 EXIT:
141 return Status;
142 }
143
144 EFI_STATUS
145 EFIAPI
146 LcdGraphicsOutputDxeInitialize (
147 IN EFI_HANDLE ImageHandle,
148 IN EFI_SYSTEM_TABLE *SystemTable
149 )
150 {
151 EFI_STATUS Status;
152 LCD_INSTANCE *Instance;
153
154 Status = LcdIdentify ();
155 if (EFI_ERROR (Status)) {
156 goto EXIT;
157 }
158
159 Status = LcdInstanceContructor (&Instance);
160 if (EFI_ERROR (Status)) {
161 goto EXIT;
162 }
163
164 // Install the Graphics Output Protocol and the Device Path
165 Status = gBS->InstallMultipleProtocolInterfaces (
166 &Instance->Handle,
167 &gEfiGraphicsOutputProtocolGuid,
168 &Instance->Gop,
169 &gEfiDevicePathProtocolGuid,
170 &Instance->DevicePath,
171 NULL
172 );
173
174 if (EFI_ERROR (Status)) {
175 DEBUG ((DEBUG_ERROR, "LcdGraphicsOutputDxeInitialize: Can not install the protocol. Exit Status=%r\n", Status));
176 goto EXIT;
177 }
178
179 // Register for an ExitBootServicesEvent
180 // When ExitBootServices starts, this function will make sure that the
181 // graphics driver shuts down properly, i.e. it will free up all
182 // allocated memory and perform any necessary hardware re-configuration.
183 Status = gBS->CreateEvent (
184 EVT_SIGNAL_EXIT_BOOT_SERVICES,
185 TPL_NOTIFY,
186 LcdGraphicsExitBootServicesEvent,
187 NULL,
188 &Instance->ExitBootServicesEvent
189 );
190
191 if (EFI_ERROR (Status)) {
192 DEBUG ((DEBUG_ERROR, "LcdGraphicsOutputDxeInitialize: Can not install the ExitBootServicesEvent handler. Exit Status=%r\n", Status));
193 goto EXIT_ERROR_UNINSTALL_PROTOCOL;
194 }
195
196 // To get here, everything must be fine, so just exit
197 goto EXIT;
198
199 EXIT_ERROR_UNINSTALL_PROTOCOL:
200 // The following function could return an error message,
201 // however, to get here something must have gone wrong already,
202 // so preserve the original error, i.e. don't change
203 // the Status variable, even it fails to uninstall the protocol.
204 gBS->UninstallMultipleProtocolInterfaces (
205 Instance->Handle,
206 &gEfiGraphicsOutputProtocolGuid,
207 &Instance->Gop, // Uninstall Graphics Output protocol
208 &gEfiDevicePathProtocolGuid,
209 &Instance->DevicePath, // Uninstall device path
210 NULL
211 );
212
213 EXIT:
214 return Status;
215 }
216
217 /** This function should be called
218 on Event: ExitBootServices
219 to free up memory, stop the driver
220 and uninstall the protocols
221 **/
222 VOID
223 LcdGraphicsExitBootServicesEvent (
224 IN EFI_EVENT Event,
225 IN VOID *Context
226 )
227 {
228 // By default, this PCD is FALSE. But if a platform starts a predefined OS
229 // that does not use a framebuffer then we might want to disable the display
230 // controller to avoid to display corrupted information on the screen.
231 if (FeaturePcdGet (PcdGopDisableOnExitBootServices)) {
232 // Turn-off the Display controller
233 LcdShutdown ();
234 }
235 }
236
237 /** GraphicsOutput Protocol function, mapping to
238 EFI_GRAPHICS_OUTPUT_PROTOCOL.QueryMode
239 **/
240 EFI_STATUS
241 EFIAPI
242 LcdGraphicsQueryMode (
243 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
244 IN UINT32 ModeNumber,
245 OUT UINTN *SizeOfInfo,
246 OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
247 )
248 {
249 EFI_STATUS Status;
250 LCD_INSTANCE *Instance;
251
252 Instance = LCD_INSTANCE_FROM_GOP_THIS (This);
253
254 // Setup the hardware if not already done
255 if (!mDisplayInitialized) {
256 Status = InitializeDisplay (Instance);
257 if (EFI_ERROR (Status)) {
258 goto EXIT;
259 }
260 }
261
262 // Error checking
263 if ((This == NULL) ||
264 (Info == NULL) ||
265 (SizeOfInfo == NULL) ||
266 (ModeNumber >= This->Mode->MaxMode))
267 {
268 DEBUG ((DEBUG_ERROR, "LcdGraphicsQueryMode: ERROR - For mode number %d : Invalid Parameter.\n", ModeNumber));
269 Status = EFI_INVALID_PARAMETER;
270 goto EXIT;
271 }
272
273 *Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
274 if (*Info == NULL) {
275 Status = EFI_OUT_OF_RESOURCES;
276 goto EXIT;
277 }
278
279 *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
280
281 Status = LcdPlatformQueryMode (ModeNumber, *Info);
282 if (EFI_ERROR (Status)) {
283 FreePool (*Info);
284 }
285
286 EXIT:
287 return Status;
288 }
289
290 /** GraphicsOutput Protocol function, mapping to
291 EFI_GRAPHICS_OUTPUT_PROTOCOL.SetMode
292 **/
293 EFI_STATUS
294 EFIAPI
295 LcdGraphicsSetMode (
296 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
297 IN UINT32 ModeNumber
298 )
299 {
300 EFI_STATUS Status;
301 EFI_GRAPHICS_OUTPUT_BLT_PIXEL FillColour;
302 LCD_INSTANCE *Instance;
303 LCD_BPP Bpp;
304
305 Instance = LCD_INSTANCE_FROM_GOP_THIS (This);
306
307 // Setup the hardware if not already done
308 if (!mDisplayInitialized) {
309 Status = InitializeDisplay (Instance);
310 if (EFI_ERROR (Status)) {
311 goto EXIT;
312 }
313 }
314
315 // Check if this mode is supported
316 if (ModeNumber >= This->Mode->MaxMode) {
317 DEBUG ((DEBUG_ERROR, "LcdGraphicsSetMode: ERROR - Unsupported mode number %d .\n", ModeNumber));
318 Status = EFI_UNSUPPORTED;
319 goto EXIT;
320 }
321
322 // Set the oscillator frequency to support the new mode
323 Status = LcdPlatformSetMode (ModeNumber);
324 if (EFI_ERROR (Status)) {
325 Status = EFI_DEVICE_ERROR;
326 goto EXIT;
327 }
328
329 // Update the UEFI mode information
330 This->Mode->Mode = ModeNumber;
331 LcdPlatformQueryMode (ModeNumber, &Instance->ModeInfo);
332 Status = LcdPlatformGetBpp (ModeNumber, &Bpp);
333 if (EFI_ERROR (Status)) {
334 DEBUG ((DEBUG_ERROR, "LcdGraphicsSetMode: ERROR - Couldn't get bytes per pixel, status: %r\n", Status));
335 goto EXIT;
336 }
337
338 This->Mode->FrameBufferSize = Instance->ModeInfo.VerticalResolution
339 * Instance->ModeInfo.PixelsPerScanLine
340 * GetBytesPerPixel (Bpp);
341
342 // Set the hardware to the new mode
343 Status = LcdSetMode (ModeNumber);
344 if (EFI_ERROR (Status)) {
345 Status = EFI_DEVICE_ERROR;
346 goto EXIT;
347 }
348
349 // The UEFI spec requires that we now clear the visible portions of the
350 // output display to black.
351
352 // Set the fill colour to black
353 SetMem (&FillColour, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
354
355 // Fill the entire visible area with the same colour.
356 Status = This->Blt (
357 This,
358 &FillColour,
359 EfiBltVideoFill,
360 0,
361 0,
362 0,
363 0,
364 This->Mode->Info->HorizontalResolution,
365 This->Mode->Info->VerticalResolution,
366 0
367 );
368
369 EXIT:
370 return Status;
371 }
372
373 UINTN
374 GetBytesPerPixel (
375 IN LCD_BPP Bpp
376 )
377 {
378 switch (Bpp) {
379 case LcdBitsPerPixel_24:
380 return 4;
381
382 case LcdBitsPerPixel_16_565:
383 case LcdBitsPerPixel_16_555:
384 case LcdBitsPerPixel_12_444:
385 return 2;
386
387 case LcdBitsPerPixel_8:
388 case LcdBitsPerPixel_4:
389 case LcdBitsPerPixel_2:
390 case LcdBitsPerPixel_1:
391 return 1;
392
393 default:
394 return 0;
395 }
396 }