mirror of https://github.com/acidanthera/audk.git
394 lines
11 KiB
C
394 lines
11 KiB
C
/** @file
|
|
|
|
Copyright (c) 2011-2014, ARM Ltd. All rights reserved.<BR>
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
**/
|
|
|
|
#include <PiDxe.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DevicePathLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Library/UefiRuntimeServicesTableLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
|
|
#include <Guid/GlobalVariable.h>
|
|
|
|
#include "LcdGraphicsOutputDxe.h"
|
|
|
|
/**********************************************************************
|
|
*
|
|
* This file implements the Graphics Output protocol on ArmVersatileExpress
|
|
* using the Lcd controller
|
|
*
|
|
**********************************************************************/
|
|
|
|
//
|
|
// Global variables
|
|
//
|
|
|
|
BOOLEAN mDisplayInitialized = FALSE;
|
|
|
|
LCD_INSTANCE mLcdTemplate = {
|
|
LCD_INSTANCE_SIGNATURE,
|
|
NULL, // Handle
|
|
{ // ModeInfo
|
|
0, // Version
|
|
0, // HorizontalResolution
|
|
0, // VerticalResolution
|
|
PixelBltOnly, // PixelFormat
|
|
{ 0 }, // PixelInformation
|
|
0, // PixelsPerScanLine
|
|
},
|
|
{
|
|
0, // MaxMode;
|
|
0, // Mode;
|
|
NULL, // Info;
|
|
0, // SizeOfInfo;
|
|
0, // FrameBufferBase;
|
|
0 // FrameBufferSize;
|
|
},
|
|
{ // Gop
|
|
LcdGraphicsQueryMode, // QueryMode
|
|
LcdGraphicsSetMode, // SetMode
|
|
LcdGraphicsBlt, // Blt
|
|
NULL // *Mode
|
|
},
|
|
{ // DevicePath
|
|
{
|
|
{
|
|
HARDWARE_DEVICE_PATH, HW_VENDOR_DP,
|
|
{ (UINT8) (sizeof(VENDOR_DEVICE_PATH)), (UINT8) ((sizeof(VENDOR_DEVICE_PATH)) >> 8) },
|
|
},
|
|
// Hardware Device Path for Lcd
|
|
EFI_CALLER_ID_GUID // Use the driver's GUID
|
|
},
|
|
|
|
{
|
|
END_DEVICE_PATH_TYPE,
|
|
END_ENTIRE_DEVICE_PATH_SUBTYPE,
|
|
{ sizeof(EFI_DEVICE_PATH_PROTOCOL), 0 }
|
|
}
|
|
},
|
|
(EFI_EVENT) NULL // ExitBootServicesEvent
|
|
};
|
|
|
|
EFI_STATUS
|
|
LcdInstanceContructor (
|
|
OUT LCD_INSTANCE** NewInstance
|
|
)
|
|
{
|
|
LCD_INSTANCE* Instance;
|
|
|
|
Instance = AllocateCopyPool (sizeof(LCD_INSTANCE), &mLcdTemplate);
|
|
if (Instance == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Instance->Gop.Mode = &Instance->Mode;
|
|
Instance->Gop.Mode->MaxMode = LcdPlatformGetMaxMode ();
|
|
Instance->Mode.Info = &Instance->ModeInfo;
|
|
|
|
*NewInstance = Instance;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Function Definitions
|
|
//
|
|
|
|
EFI_STATUS
|
|
InitializeDisplay (
|
|
IN LCD_INSTANCE* Instance
|
|
)
|
|
{
|
|
EFI_STATUS Status = EFI_SUCCESS;
|
|
EFI_PHYSICAL_ADDRESS VramBaseAddress;
|
|
UINTN VramSize;
|
|
|
|
Status = LcdPlatformGetVram (&VramBaseAddress, &VramSize);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
// Setup the LCD
|
|
Status = LcdInitialize (VramBaseAddress);
|
|
if (EFI_ERROR(Status)) {
|
|
goto EXIT_ERROR_LCD_SHUTDOWN;
|
|
}
|
|
|
|
Status = LcdPlatformInitializeDisplay (Instance->Handle);
|
|
if (EFI_ERROR(Status)) {
|
|
goto EXIT_ERROR_LCD_SHUTDOWN;
|
|
}
|
|
|
|
// Setup all the relevant mode information
|
|
Instance->Gop.Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
|
|
Instance->Gop.Mode->FrameBufferBase = VramBaseAddress;
|
|
|
|
// Set the flag before changing the mode, to avoid infinite loops
|
|
mDisplayInitialized = TRUE;
|
|
|
|
// All is ok, so don't deal with any errors
|
|
goto EXIT;
|
|
|
|
EXIT_ERROR_LCD_SHUTDOWN:
|
|
DEBUG((DEBUG_ERROR, "InitializeDisplay: ERROR - Can not initialise the display. Exit Status=%r\n", Status));
|
|
LcdShutdown ();
|
|
|
|
EXIT:
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
LcdGraphicsOutputDxeInitialize (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status = EFI_SUCCESS;
|
|
LCD_INSTANCE* Instance;
|
|
|
|
Status = LcdIdentify ();
|
|
if (EFI_ERROR(Status)) {
|
|
goto EXIT;
|
|
}
|
|
|
|
Status = LcdInstanceContructor (&Instance);
|
|
if (EFI_ERROR(Status)) {
|
|
goto EXIT;
|
|
}
|
|
|
|
// Install the Graphics Output Protocol and the Device Path
|
|
Status = gBS->InstallMultipleProtocolInterfaces(
|
|
&Instance->Handle,
|
|
&gEfiGraphicsOutputProtocolGuid, &Instance->Gop,
|
|
&gEfiDevicePathProtocolGuid, &Instance->DevicePath,
|
|
NULL
|
|
);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
DEBUG((DEBUG_ERROR, "GraphicsOutputDxeInitialize: Can not install the protocol. Exit Status=%r\n", Status));
|
|
goto EXIT;
|
|
}
|
|
|
|
// Register for an ExitBootServicesEvent
|
|
// When ExitBootServices starts, this function here will make sure that the graphics driver will shut down properly,
|
|
// i.e. it will free up all allocated memory and perform any necessary hardware re-configuration.
|
|
Status = gBS->CreateEvent (
|
|
EVT_SIGNAL_EXIT_BOOT_SERVICES,
|
|
TPL_NOTIFY,
|
|
LcdGraphicsExitBootServicesEvent, NULL,
|
|
&Instance->ExitBootServicesEvent
|
|
);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
DEBUG((DEBUG_ERROR, "GraphicsOutputDxeInitialize: Can not install the ExitBootServicesEvent handler. Exit Status=%r\n", Status));
|
|
goto EXIT_ERROR_UNINSTALL_PROTOCOL;
|
|
}
|
|
|
|
// To get here, everything must be fine, so just exit
|
|
goto EXIT;
|
|
|
|
EXIT_ERROR_UNINSTALL_PROTOCOL:
|
|
/* The following function could return an error message,
|
|
* however, to get here something must have gone wrong already,
|
|
* so preserve the original error, i.e. don't change
|
|
* the Status variable, even it fails to uninstall the protocol.
|
|
*/
|
|
gBS->UninstallMultipleProtocolInterfaces (
|
|
Instance->Handle,
|
|
&gEfiGraphicsOutputProtocolGuid, &Instance->Gop, // Uninstall Graphics Output protocol
|
|
&gEfiDevicePathProtocolGuid, &Instance->DevicePath, // Uninstall device path
|
|
NULL
|
|
);
|
|
|
|
EXIT:
|
|
return Status;
|
|
|
|
}
|
|
|
|
/***************************************
|
|
* This function should be called
|
|
* on Event: ExitBootServices
|
|
* to free up memory, stop the driver
|
|
* and uninstall the protocols
|
|
***************************************/
|
|
VOID
|
|
LcdGraphicsExitBootServicesEvent (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
// By default, this PCD is FALSE. But if a platform starts a predefined OS that
|
|
// does not use a framebuffer then we might want to disable the display controller
|
|
// to avoid to display corrupted information on the screen.
|
|
if (FeaturePcdGet (PcdGopDisableOnExitBootServices)) {
|
|
// Turn-off the Display controller
|
|
LcdShutdown ();
|
|
}
|
|
}
|
|
|
|
/***************************************
|
|
* GraphicsOutput Protocol function, mapping to
|
|
* EFI_GRAPHICS_OUTPUT_PROTOCOL.QueryMode
|
|
***************************************/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
LcdGraphicsQueryMode (
|
|
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
|
|
IN UINT32 ModeNumber,
|
|
OUT UINTN *SizeOfInfo,
|
|
OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
|
|
)
|
|
{
|
|
EFI_STATUS Status = EFI_SUCCESS;
|
|
LCD_INSTANCE *Instance;
|
|
|
|
Instance = LCD_INSTANCE_FROM_GOP_THIS(This);
|
|
|
|
// Setup the hardware if not already done
|
|
if( !mDisplayInitialized ) {
|
|
Status = InitializeDisplay(Instance);
|
|
if (EFI_ERROR(Status)) {
|
|
goto EXIT;
|
|
}
|
|
}
|
|
|
|
// Error checking
|
|
if ( (This == NULL) || (Info == NULL) || (SizeOfInfo == NULL) || (ModeNumber >= This->Mode->MaxMode) ) {
|
|
DEBUG((DEBUG_ERROR, "LcdGraphicsQueryMode: ERROR - For mode number %d : Invalid Parameter.\n", ModeNumber ));
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto EXIT;
|
|
}
|
|
|
|
*Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
|
|
if (*Info == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto EXIT;
|
|
}
|
|
|
|
*SizeOfInfo = sizeof( EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
|
|
|
|
Status = LcdPlatformQueryMode (ModeNumber,*Info);
|
|
if (EFI_ERROR(Status)) {
|
|
FreePool(*Info);
|
|
}
|
|
|
|
EXIT:
|
|
return Status;
|
|
}
|
|
|
|
/***************************************
|
|
* GraphicsOutput Protocol function, mapping to
|
|
* EFI_GRAPHICS_OUTPUT_PROTOCOL.SetMode
|
|
***************************************/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
LcdGraphicsSetMode (
|
|
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
|
|
IN UINT32 ModeNumber
|
|
)
|
|
{
|
|
EFI_STATUS Status = EFI_SUCCESS;
|
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL FillColour;
|
|
LCD_INSTANCE* Instance;
|
|
LCD_BPP Bpp;
|
|
|
|
Instance = LCD_INSTANCE_FROM_GOP_THIS (This);
|
|
|
|
// Setup the hardware if not already done
|
|
if(!mDisplayInitialized) {
|
|
Status = InitializeDisplay (Instance);
|
|
if (EFI_ERROR(Status)) {
|
|
goto EXIT;
|
|
}
|
|
}
|
|
|
|
// Check if this mode is supported
|
|
if( ModeNumber >= This->Mode->MaxMode ) {
|
|
DEBUG((DEBUG_ERROR, "LcdGraphicsSetMode: ERROR - Unsupported mode number %d .\n", ModeNumber ));
|
|
Status = EFI_UNSUPPORTED;
|
|
goto EXIT;
|
|
}
|
|
|
|
// Set the oscillator frequency to support the new mode
|
|
Status = LcdPlatformSetMode (ModeNumber);
|
|
if (EFI_ERROR(Status)) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
goto EXIT;
|
|
}
|
|
|
|
// Update the UEFI mode information
|
|
This->Mode->Mode = ModeNumber;
|
|
LcdPlatformQueryMode (ModeNumber,&Instance->ModeInfo);
|
|
Status = LcdPlatformGetBpp(ModeNumber, &Bpp);
|
|
if (EFI_ERROR(Status)) {
|
|
DEBUG ((DEBUG_ERROR, "LcdGraphicsSetMode: ERROR - Couldn't get bytes per pixel, status: %r\n", Status));
|
|
goto EXIT;
|
|
}
|
|
This->Mode->FrameBufferSize = Instance->ModeInfo.VerticalResolution
|
|
* Instance->ModeInfo.PixelsPerScanLine
|
|
* GetBytesPerPixel(Bpp);
|
|
|
|
// Set the hardware to the new mode
|
|
Status = LcdSetMode (ModeNumber);
|
|
if (EFI_ERROR(Status)) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
goto EXIT;
|
|
}
|
|
|
|
// The UEFI spec requires that we now clear the visible portions of the output display to black.
|
|
|
|
// Set the fill colour to black
|
|
SetMem (&FillColour, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
|
|
|
|
// Fill the entire visible area with the same colour.
|
|
Status = This->Blt (
|
|
This,
|
|
&FillColour,
|
|
EfiBltVideoFill,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
This->Mode->Info->HorizontalResolution,
|
|
This->Mode->Info->VerticalResolution,
|
|
0);
|
|
|
|
EXIT:
|
|
return Status;
|
|
}
|
|
|
|
UINTN
|
|
GetBytesPerPixel (
|
|
IN LCD_BPP Bpp
|
|
)
|
|
{
|
|
switch(Bpp) {
|
|
case LCD_BITS_PER_PIXEL_24:
|
|
return 4;
|
|
|
|
case LCD_BITS_PER_PIXEL_16_565:
|
|
case LCD_BITS_PER_PIXEL_16_555:
|
|
case LCD_BITS_PER_PIXEL_12_444:
|
|
return 2;
|
|
|
|
case LCD_BITS_PER_PIXEL_8:
|
|
case LCD_BITS_PER_PIXEL_4:
|
|
case LCD_BITS_PER_PIXEL_2:
|
|
case LCD_BITS_PER_PIXEL_1:
|
|
return 1;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|