/** @file This file implements the Graphics Output protocol for Arm platforms Copyright (c) 2011 - 2020, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include "LcdGraphicsOutputDxe.h" // // 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_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; 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, "LcdGraphicsOutputDxeInitialize: Can not install the protocol. Exit Status=%r\n", Status)); goto EXIT; } // Register for an ExitBootServicesEvent // When ExitBootServices starts, this function will make sure that the // graphics driver shuts 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, "LcdGraphicsOutputDxeInitialize: 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; 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_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 LcdBitsPerPixel_24: return 4; case LcdBitsPerPixel_16_565: case LcdBitsPerPixel_16_555: case LcdBitsPerPixel_12_444: return 2; case LcdBitsPerPixel_8: case LcdBitsPerPixel_4: case LcdBitsPerPixel_2: case LcdBitsPerPixel_1: return 1; default: return 0; } }