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 } 394