/** @file Copyright (c) 2011-2014, ARM Ltd. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "LcdGraphicsOutputDxe.h" BOOLEAN mDisplayInitialized = FALSE; LCD_MODE LcdModes[] = { { 0, 640, 480, 9, 4, 96, 16, 48, 2, 10, 33 }, { 1, 800, 600, 11, 2, 120, 56, 64, 5, 37, 22 }, { 2, 1024, 768, 6, 2, 96, 16, 48, 2, 10, 33 }, }; LCD_INSTANCE mLcdTemplate = { LCD_INSTANCE_SIGNATURE, NULL, // Handle { // ModeInfo 0, // Version 0, // HorizontalResolution 0, // VerticalResolution PixelBltOnly, // PixelFormat { 0xF800, //RedMask; 0x7E0, //GreenMask; 0x1F, //BlueMask; 0x0//ReservedMask }, // PixelInformation 0, // PixelsPerScanLine }, { // Mode 3, // 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_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->Mode.Info = &Instance->ModeInfo; *NewInstance = Instance; return EFI_SUCCESS; } EFI_STATUS LcdPlatformGetVram ( OUT EFI_PHYSICAL_ADDRESS* VramBaseAddress, OUT UINTN* VramSize ) { EFI_STATUS Status; EFI_CPU_ARCH_PROTOCOL *Cpu; UINTN MaxSize; MaxSize = 0x500000; *VramSize = MaxSize; // Allocate VRAM from DRAM Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, EFI_SIZE_TO_PAGES((MaxSize)), VramBaseAddress); if (EFI_ERROR(Status)) { return Status; } // Ensure the Cpu architectural protocol is already installed Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu); ASSERT_EFI_ERROR(Status); // Mark the VRAM as un-cacheable. The VRAM is inside the DRAM, which is cacheable. Status = Cpu->SetMemoryAttributes (Cpu, *VramBaseAddress, *VramSize, EFI_MEMORY_UC); if (EFI_ERROR(Status)) { gBS->FreePool (VramBaseAddress); return Status; } return EFI_SUCCESS; } EFI_STATUS DssSetMode ( UINT32 VramBaseAddress, UINTN ModeNumber ) { // Make sure the interface clock is running MmioWrite32 (CM_ICLKEN_DSS, EN_DSS); // Stop the functional clocks MmioAnd32 (CM_FCLKEN_DSS, ~(EN_DSS1 | EN_DSS2 | EN_TV)); // Program the DSS clock divisor MmioWrite32 (CM_CLKSEL_DSS, 0x1000 | (LcdModes[ModeNumber].DssDivisor)); // Start the functional clocks MmioOr32 (CM_FCLKEN_DSS, (EN_DSS1 | EN_DSS2 | EN_TV)); // Wait for DSS to stabilize gBS->Stall(1); // Reset the subsystem MmioWrite32(DSS_SYSCONFIG, DSS_SOFTRESET); while (!(MmioRead32 (DSS_SYSSTATUS) & DSS_RESETDONE)); // Configure LCD parameters MmioWrite32 (DISPC_SIZE_LCD, ((LcdModes[ModeNumber].HorizontalResolution - 1) | ((LcdModes[ModeNumber].VerticalResolution - 1) << 16)) ); MmioWrite32 (DISPC_TIMING_H, ( (LcdModes[ModeNumber].HSync - 1) | ((LcdModes[ModeNumber].HFrontPorch - 1) << 8) | ((LcdModes[ModeNumber].HBackPorch - 1) << 20)) ); MmioWrite32 (DISPC_TIMING_V, ( (LcdModes[ModeNumber].VSync - 1) | ((LcdModes[ModeNumber].VFrontPorch - 1) << 8) | ((LcdModes[ModeNumber].VBackPorch - 1) << 20)) ); // Set the framebuffer to only load frames (no gamma tables) MmioAnd32 (DISPC_CONFIG, CLEARLOADMODE); MmioOr32 (DISPC_CONFIG, LOAD_FRAME_ONLY); // Divisor for the pixel clock MmioWrite32(DISPC_DIVISOR, ((1 << 16) | LcdModes[ModeNumber].DispcDivisor) ); // Set up the graphics layer MmioWrite32 (DISPC_GFX_PRELD, 0x2D8); MmioWrite32 (DISPC_GFX_BA0, VramBaseAddress); MmioWrite32 (DISPC_GFX_SIZE, ((LcdModes[ModeNumber].HorizontalResolution - 1) | ((LcdModes[ModeNumber].VerticalResolution - 1) << 16)) ); MmioWrite32(DISPC_GFX_ATTR, (GFXENABLE | RGB16 | BURSTSIZE16)); // Start it all MmioOr32 (DISPC_CONTROL, (LCDENABLE | ACTIVEMATRIX | DATALINES24 | BYPASS_MODE | LCDENABLESIGNAL)); MmioOr32 (DISPC_CONTROL, GOLCD); return EFI_SUCCESS; } EFI_STATUS HwInitializeDisplay ( UINTN VramBaseAddress, UINTN VramSize ) { EFI_STATUS Status; UINT8 Data; EFI_TPL OldTpl; EMBEDDED_EXTERNAL_DEVICE *gTPS65950; // Enable power lines used by TFP410 Status = gBS->LocateProtocol (&gEmbeddedExternalDeviceProtocolGuid, NULL, (VOID **)&gTPS65950); ASSERT_EFI_ERROR (Status); OldTpl = gBS->RaiseTPL(TPL_NOTIFY); Data = VAUX_DEV_GRP_P1; Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VPLL2_DEV_GRP), 1, &Data); ASSERT_EFI_ERROR(Status); Data = VAUX_DEDICATED_18V; Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VPLL2_DEDICATED), 1, &Data); ASSERT_EFI_ERROR (Status); // Power up TFP410 (set GPIO2 on TPS - for BeagleBoard-xM) Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, GPIODATADIR1), 1, &Data); ASSERT_EFI_ERROR (Status); Data |= BIT2; Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, GPIODATADIR1), 1, &Data); ASSERT_EFI_ERROR (Status); Data = BIT2; Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, SETGPIODATAOUT1), 1, &Data); ASSERT_EFI_ERROR (Status); gBS->RestoreTPL(OldTpl); // Power up TFP410 (set GPIO 170 - for older BeagleBoards) MmioAnd32 (GPIO6_BASE + GPIO_OE, ~BIT10); MmioOr32 (GPIO6_BASE + GPIO_SETDATAOUT, BIT10); return EFI_SUCCESS; } EFI_STATUS InitializeDisplay ( IN LCD_INSTANCE* Instance ) { EFI_STATUS Status; UINTN VramSize; EFI_PHYSICAL_ADDRESS VramBaseAddress; Status = LcdPlatformGetVram (&VramBaseAddress, &VramSize); if (EFI_ERROR (Status)) { return Status; } Instance->Mode.FrameBufferBase = VramBaseAddress; Instance->Mode.FrameBufferSize = VramSize; Status = HwInitializeDisplay((UINTN)VramBaseAddress, VramSize); if (!EFI_ERROR (Status)) { mDisplayInitialized = TRUE; } return Status; } EFI_STATUS EFIAPI LcdGraphicsQueryMode ( IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, IN UINT32 ModeNumber, OUT UINTN *SizeOfInfo, OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info ) { LCD_INSTANCE *Instance; Instance = LCD_INSTANCE_FROM_GOP_THIS(This); if (!mDisplayInitialized) { InitializeDisplay (Instance); } // 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 )); return EFI_INVALID_PARAMETER; } *Info = AllocateCopyPool(sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION), &Instance->ModeInfo); if (*Info == NULL) { return EFI_OUT_OF_RESOURCES; } *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); (*Info)->Version = 0; (*Info)->HorizontalResolution = LcdModes[ModeNumber].HorizontalResolution; (*Info)->VerticalResolution = LcdModes[ModeNumber].VerticalResolution; (*Info)->PixelFormat = PixelBltOnly; return EFI_SUCCESS; } EFI_STATUS EFIAPI LcdGraphicsSetMode ( IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, IN UINT32 ModeNumber ) { LCD_INSTANCE *Instance; Instance = LCD_INSTANCE_FROM_GOP_THIS(This); if (ModeNumber >= Instance->Mode.MaxMode) { return EFI_UNSUPPORTED; } if (!mDisplayInitialized) { InitializeDisplay (Instance); } DssSetMode((UINT32)Instance->Mode.FrameBufferBase, ModeNumber); Instance->Mode.Mode = ModeNumber; Instance->ModeInfo.HorizontalResolution = LcdModes[ModeNumber].HorizontalResolution; Instance->ModeInfo.VerticalResolution = LcdModes[ModeNumber].VerticalResolution; return EFI_SUCCESS; } EFI_STATUS EFIAPI LcdGraphicsOutputDxeInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status = EFI_SUCCESS; LCD_INSTANCE* Instance; 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; }