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