Home | History | Annotate | Download | only in LcdGraphicsOutputDxe
      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