cbc20343496be130cf2b07710bb3455d0720817a
[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 = 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, &Instance->Gop,
168 &gEfiDevicePathProtocolGuid, &Instance->DevicePath,
169 NULL
170 );
171
172 if (EFI_ERROR(Status)) {
173 DEBUG((DEBUG_ERROR, "GraphicsOutputDxeInitialize: Can not install the protocol. Exit Status=%r\n", Status));
174 goto EXIT;
175 }
176
177 // Register for an ExitBootServicesEvent
178 // When ExitBootServices starts, this function here will make sure that the graphics driver will shut down properly,
179 // i.e. it will free up all allocated memory and perform any necessary hardware re-configuration.
180 Status = gBS->CreateEvent (
181 EVT_SIGNAL_EXIT_BOOT_SERVICES,
182 TPL_NOTIFY,
183 LcdGraphicsExitBootServicesEvent, NULL,
184 &Instance->ExitBootServicesEvent
185 );
186
187 if (EFI_ERROR(Status)) {
188 DEBUG((DEBUG_ERROR, "GraphicsOutputDxeInitialize: Can not install the ExitBootServicesEvent handler. Exit Status=%r\n", Status));
189 goto EXIT_ERROR_UNINSTALL_PROTOCOL;
190 }
191
192 // To get here, everything must be fine, so just exit
193 goto EXIT;
194
195 EXIT_ERROR_UNINSTALL_PROTOCOL:
196 /* The following function could return an error message,
197 * however, to get here something must have gone wrong already,
198 * so preserve the original error, i.e. don't change
199 * the Status variable, even it fails to uninstall the protocol.
200 */
201 gBS->UninstallMultipleProtocolInterfaces (
202 Instance->Handle,
203 &gEfiGraphicsOutputProtocolGuid, &Instance->Gop, // Uninstall Graphics Output protocol
204 &gEfiDevicePathProtocolGuid, &Instance->DevicePath, // Uninstall device path
205 NULL
206 );
207
208 EXIT:
209 return Status;
210
211 }
212
213 /***************************************
214 * This function should be called
215 * on Event: ExitBootServices
216 * to free up memory, stop the driver
217 * and uninstall the protocols
218 ***************************************/
219 VOID
220 LcdGraphicsExitBootServicesEvent (
221 IN EFI_EVENT Event,
222 IN VOID *Context
223 )
224 {
225 // By default, this PCD is FALSE. But if a platform starts a predefined OS that
226 // does not use a framebuffer then we might want to disable the display controller
227 // to avoid to display corrupted information on the screen.
228 if (FeaturePcdGet (PcdGopDisableOnExitBootServices)) {
229 // Turn-off the Display controller
230 LcdShutdown ();
231 }
232 }
233
234 /***************************************
235 * GraphicsOutput Protocol function, mapping to
236 * EFI_GRAPHICS_OUTPUT_PROTOCOL.QueryMode
237 ***************************************/
238 EFI_STATUS
239 EFIAPI
240 LcdGraphicsQueryMode (
241 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
242 IN UINT32 ModeNumber,
243 OUT UINTN *SizeOfInfo,
244 OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
245 )
246 {
247 EFI_STATUS Status = EFI_SUCCESS;
248 LCD_INSTANCE *Instance;
249
250 Instance = LCD_INSTANCE_FROM_GOP_THIS(This);
251
252 // Setup the hardware if not already done
253 if( !mDisplayInitialized ) {
254 Status = InitializeDisplay(Instance);
255 if (EFI_ERROR(Status)) {
256 goto EXIT;
257 }
258 }
259
260 // Error checking
261 if ( (This == NULL) || (Info == NULL) || (SizeOfInfo == NULL) || (ModeNumber >= This->Mode->MaxMode) ) {
262 DEBUG((DEBUG_ERROR, "LcdGraphicsQueryMode: ERROR - For mode number %d : Invalid Parameter.\n", ModeNumber ));
263 Status = EFI_INVALID_PARAMETER;
264 goto EXIT;
265 }
266
267 *Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
268 if (*Info == NULL) {
269 Status = EFI_OUT_OF_RESOURCES;
270 goto EXIT;
271 }
272
273 *SizeOfInfo = sizeof( EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
274
275 Status = LcdPlatformQueryMode (ModeNumber,*Info);
276 if (EFI_ERROR(Status)) {
277 FreePool(*Info);
278 }
279
280 EXIT:
281 return Status;
282 }
283
284 /***************************************
285 * GraphicsOutput Protocol function, mapping to
286 * EFI_GRAPHICS_OUTPUT_PROTOCOL.SetMode
287 ***************************************/
288 EFI_STATUS
289 EFIAPI
290 LcdGraphicsSetMode (
291 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
292 IN UINT32 ModeNumber
293 )
294 {
295 EFI_STATUS Status = EFI_SUCCESS;
296 EFI_GRAPHICS_OUTPUT_BLT_PIXEL FillColour;
297 LCD_INSTANCE* Instance;
298 LCD_BPP Bpp;
299
300 Instance = LCD_INSTANCE_FROM_GOP_THIS (This);
301
302 // Setup the hardware if not already done
303 if(!mDisplayInitialized) {
304 Status = InitializeDisplay (Instance);
305 if (EFI_ERROR(Status)) {
306 goto EXIT;
307 }
308 }
309
310 // Check if this mode is supported
311 if( ModeNumber >= This->Mode->MaxMode ) {
312 DEBUG((DEBUG_ERROR, "LcdGraphicsSetMode: ERROR - Unsupported mode number %d .\n", ModeNumber ));
313 Status = EFI_UNSUPPORTED;
314 goto EXIT;
315 }
316
317 // Set the oscillator frequency to support the new mode
318 Status = LcdPlatformSetMode (ModeNumber);
319 if (EFI_ERROR(Status)) {
320 Status = EFI_DEVICE_ERROR;
321 goto EXIT;
322 }
323
324 // Update the UEFI mode information
325 This->Mode->Mode = ModeNumber;
326 LcdPlatformQueryMode (ModeNumber,&Instance->ModeInfo);
327 Status = LcdPlatformGetBpp(ModeNumber, &Bpp);
328 if (EFI_ERROR(Status)) {
329 DEBUG ((DEBUG_ERROR, "LcdGraphicsSetMode: ERROR - Couldn't get bytes per pixel, status: %r\n", Status));
330 goto EXIT;
331 }
332 This->Mode->FrameBufferSize = Instance->ModeInfo.VerticalResolution
333 * Instance->ModeInfo.PixelsPerScanLine
334 * GetBytesPerPixel(Bpp);
335
336 // Set the hardware to the new mode
337 Status = LcdSetMode (ModeNumber);
338 if (EFI_ERROR(Status)) {
339 Status = EFI_DEVICE_ERROR;
340 goto EXIT;
341 }
342
343 // The UEFI spec requires that we now clear the visible portions of the output display to black.
344
345 // Set the fill colour to black
346 SetMem (&FillColour, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
347
348 // Fill the entire visible area with the same colour.
349 Status = This->Blt (
350 This,
351 &FillColour,
352 EfiBltVideoFill,
353 0,
354 0,
355 0,
356 0,
357 This->Mode->Info->HorizontalResolution,
358 This->Mode->Info->VerticalResolution,
359 0);
360
361 EXIT:
362 return Status;
363 }
364
365 UINTN
366 GetBytesPerPixel (
367 IN LCD_BPP Bpp
368 )
369 {
370 switch(Bpp) {
371 case LCD_BITS_PER_PIXEL_24:
372 return 4;
373
374 case LCD_BITS_PER_PIXEL_16_565:
375 case LCD_BITS_PER_PIXEL_16_555:
376 case LCD_BITS_PER_PIXEL_12_444:
377 return 2;
378
379 case LCD_BITS_PER_PIXEL_8:
380 case LCD_BITS_PER_PIXEL_4:
381 case LCD_BITS_PER_PIXEL_2:
382 case LCD_BITS_PER_PIXEL_1:
383 return 1;
384
385 default:
386 return 0;
387 }
388 }