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