/** @file Copyright (c) 2011-2014, ARM Ltd. All rights reserved.
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 "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; }