]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Drivers/LcdGraphicsOutputDxe/LcdGraphicsOutputDxe.c
ArmPlatformPkg: Replace BSD License with BSD+Patent License
[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-2018, ARM Ltd. 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 = EFI_SUCCESS;
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 = EFI_SUCCESS;
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 = EFI_SUCCESS;
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 DEBUG ((DEBUG_ERROR, "LcdGraphicsQueryMode: ERROR - For mode number %d : Invalid Parameter.\n", ModeNumber));
268 Status = EFI_INVALID_PARAMETER;
269 goto EXIT;
270 }
271
272 *Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
273 if (*Info == NULL) {
274 Status = EFI_OUT_OF_RESOURCES;
275 goto EXIT;
276 }
277
278 *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
279
280 Status = LcdPlatformQueryMode (ModeNumber, *Info);
281 if (EFI_ERROR (Status)) {
282 FreePool (*Info);
283 }
284
285 EXIT:
286 return Status;
287 }
288
289 /** GraphicsOutput Protocol function, mapping to
290 EFI_GRAPHICS_OUTPUT_PROTOCOL.SetMode
291 **/
292 EFI_STATUS
293 EFIAPI
294 LcdGraphicsSetMode (
295 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
296 IN UINT32 ModeNumber
297 )
298 {
299 EFI_STATUS Status = EFI_SUCCESS;
300 EFI_GRAPHICS_OUTPUT_BLT_PIXEL FillColour;
301 LCD_INSTANCE* Instance;
302 LCD_BPP Bpp;
303
304 Instance = LCD_INSTANCE_FROM_GOP_THIS (This);
305
306 // Setup the hardware if not already done
307 if (!mDisplayInitialized) {
308 Status = InitializeDisplay (Instance);
309 if (EFI_ERROR (Status)) {
310 goto EXIT;
311 }
312 }
313
314 // Check if this mode is supported
315 if (ModeNumber >= This->Mode->MaxMode) {
316 DEBUG ((DEBUG_ERROR, "LcdGraphicsSetMode: ERROR - Unsupported mode number %d .\n", ModeNumber));
317 Status = EFI_UNSUPPORTED;
318 goto EXIT;
319 }
320
321 // Set the oscillator frequency to support the new mode
322 Status = LcdPlatformSetMode (ModeNumber);
323 if (EFI_ERROR (Status)) {
324 Status = EFI_DEVICE_ERROR;
325 goto EXIT;
326 }
327
328 // Update the UEFI mode information
329 This->Mode->Mode = ModeNumber;
330 LcdPlatformQueryMode (ModeNumber, &Instance->ModeInfo);
331 Status = LcdPlatformGetBpp (ModeNumber, &Bpp);
332 if (EFI_ERROR (Status)) {
333 DEBUG ((DEBUG_ERROR, "LcdGraphicsSetMode: ERROR - Couldn't get bytes per pixel, status: %r\n", Status));
334 goto EXIT;
335 }
336 This->Mode->FrameBufferSize = Instance->ModeInfo.VerticalResolution
337 * Instance->ModeInfo.PixelsPerScanLine
338 * GetBytesPerPixel (Bpp);
339
340 // Set the hardware to the new mode
341 Status = LcdSetMode (ModeNumber);
342 if (EFI_ERROR (Status)) {
343 Status = EFI_DEVICE_ERROR;
344 goto EXIT;
345 }
346
347 // The UEFI spec requires that we now clear the visible portions of the
348 // output display to black.
349
350 // Set the fill colour to black
351 SetMem (&FillColour, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
352
353 // Fill the entire visible area with the same colour.
354 Status = This->Blt (
355 This,
356 &FillColour,
357 EfiBltVideoFill,
358 0,
359 0,
360 0,
361 0,
362 This->Mode->Info->HorizontalResolution,
363 This->Mode->Info->VerticalResolution,
364 0
365 );
366
367 EXIT:
368 return Status;
369 }
370
371 UINTN
372 GetBytesPerPixel (
373 IN LCD_BPP Bpp
374 )
375 {
376 switch (Bpp) {
377 case LCD_BITS_PER_PIXEL_24:
378 return 4;
379
380 case LCD_BITS_PER_PIXEL_16_565:
381 case LCD_BITS_PER_PIXEL_16_555:
382 case LCD_BITS_PER_PIXEL_12_444:
383 return 2;
384
385 case LCD_BITS_PER_PIXEL_8:
386 case LCD_BITS_PER_PIXEL_4:
387 case LCD_BITS_PER_PIXEL_2:
388 case LCD_BITS_PER_PIXEL_1:
389 return 1;
390
391 default:
392 return 0;
393 }
394 }