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