/** @file This file implements the Graphics Output protocol for Arm platforms Copyright (c) 2011 - 2020, Arm Limited. All rights reserved.
Copyright (c) 2022 Rockchip Electronics Co. Ltd. SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include #include #include "LcdGraphicsOutputDxe.h" //to delete #include // // Global variables // STATIC LIST_ENTRY mDisplayStateList; //STATIC DISPLAY_PROTOCOL mDisplayProtocol; typedef enum { ROCKCHIP_VOP2_CLUSTER0 = 0, ROCKCHIP_VOP2_CLUSTER1, ROCKCHIP_VOP2_ESMART0, ROCKCHIP_VOP2_ESMART1, ROCKCHIP_VOP2_SMART0, ROCKCHIP_VOP2_SMART1, ROCKCHIP_VOP2_CLUSTER2, ROCKCHIP_VOP2_CLUSTER3, ROCKCHIP_VOP2_ESMART2, ROCKCHIP_VOP2_ESMART3, ROCKCHIP_VOP2_LAYER_MAX, } VOP2_LAYER_PHY_ID; STATIC OVER_SCAN mDefaultOverScanParas = { .LeftMargin = 100, .RightMargin = 100, .TopMargin = 100, .BottomMargin = 100 }; typedef struct { UINT32 Resolution; UINT32 Sync; UINT32 BackPorch; UINT32 FrontPorch; } SCAN_TIMINGS; typedef struct { UINT32 CrtcId; UINT32 OscFreq; SCAN_TIMINGS Horizontal; SCAN_TIMINGS Vertical; UINT32 HsyncActive; UINT32 VsyncActive; UINT32 DenActive; UINT32 ClkActive; UINT32 VpsConfigModeID; } DISPLAY_MODE; STATIC DISPLAY_MODE mDisplayModes[] = { { // eDP : 1536 x 2048 2, 200000000, {1536, 16, 12, 48}, {2048, 4, 8, 8}, 0, 0, 0, 0, 1 }, { // eDP : 1920 x 1080 2, 148500000, {1920, 32, 200, 48}, {1080, 5, 37, 3}, 0, 0, 0, 0, 1 }, }; BOOLEAN mDisplayInitialized = FALSE; STATIC CONST UINT32 mMaxMode = ARRAY_SIZE (mDisplayModes); 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 = mMaxMode; Instance->Mode.Info = &Instance->ModeInfo; *NewInstance = Instance; return EFI_SUCCESS; } // // Function Definitions // EFIAPI EFI_STATUS DisplayGetTiming ( OUT DISPLAY_STATE *DisplayState ) { DRM_DISPLAY_MODE *Mode = &DisplayState->ConnectorState.DisplayMode; UINT32 ModeNumber = DisplayState->ModeNumber; UINT32 HActive, VActive, PixelClock; UINT32 HFrontPorch, HBackPorch, HSyncLen; UINT32 VFrontPorch, VBackPorch, VSyncLen; UINT32 Flags = 0; UINT32 Val = 0; HActive = mDisplayModes[ModeNumber].Horizontal.Resolution; VActive = mDisplayModes[ModeNumber].Vertical.Resolution; PixelClock = mDisplayModes[ModeNumber].OscFreq; HSyncLen = mDisplayModes[ModeNumber].Horizontal.Sync; HFrontPorch = mDisplayModes[ModeNumber].Horizontal.FrontPorch; HBackPorch = mDisplayModes[ModeNumber].Horizontal.BackPorch; VSyncLen = mDisplayModes[ModeNumber].Vertical.Sync; VFrontPorch = mDisplayModes[ModeNumber].Vertical.FrontPorch; VBackPorch = mDisplayModes[ModeNumber].Vertical.BackPorch; Val = mDisplayModes[ModeNumber].HsyncActive ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC; Flags |= Val; Val = mDisplayModes[ModeNumber].VsyncActive ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC; Flags |= Val; Val = mDisplayModes[ModeNumber].ClkActive ? DRM_MODE_FLAG_PPIXDATA : 0; Flags |= Val; Mode->HDisplay = HActive; Mode->HSyncStart = Mode->HDisplay + HFrontPorch; Mode->HSyncEnd = Mode->HSyncStart + HSyncLen; Mode->HTotal = Mode->HSyncEnd + HBackPorch; Mode->VDisplay = VActive; Mode->VSyncStart = Mode->VDisplay + VFrontPorch; Mode->VSyncEnd = Mode->VSyncStart + VSyncLen; Mode->VTotal = Mode->VSyncEnd + VBackPorch; Mode->Clock = PixelClock / 1000; Mode->Flags = Flags; /* not to set fix --- todo */ Mode->VScan = 0; return EFI_SUCCESS; } STATIC UINT32 DisplayBppConvert ( IN LCD_BPP LcdBpp ) { UINT32 DisplayBpp; switch (LcdBpp) { case LcdBitsPerPixel_24: DisplayBpp = 32; break; default: DisplayBpp = 32; break; } return DisplayBpp; } EFI_STATUS InitializeDisplay ( IN LCD_INSTANCE* Instance ) { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS VramBaseAddress; UINTN VramSize; DISPLAY_STATE *StateInterate; CRTC_STATE *CrtcState; CONNECTOR_STATE *ConnectorState; DRM_DISPLAY_MODE *Mode; ROCKCHIP_CRTC_PROTOCOL *Crtc; LCD_BPP LcdBpp; ROCKCHIP_CONNECTOR_PROTOCOL *Connector; Status = DisplaySetFramebuffer (&VramBaseAddress, &VramSize); if (EFI_ERROR (Status)) { goto EXIT; } // Setup all the relevant mode information Instance->Gop.Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); Instance->Gop.Mode->FrameBufferBase = VramBaseAddress; LIST_FOR_EACH_ENTRY(StateInterate, &mDisplayStateList, ListHead) { if (StateInterate->IsEnable) { Crtc = (ROCKCHIP_CRTC_PROTOCOL *)StateInterate->CrtcState.Crtc; Connector = (ROCKCHIP_CONNECTOR_PROTOCOL *)StateInterate->ConnectorState.Connector; CrtcState = &StateInterate->CrtcState; ConnectorState = &StateInterate->ConnectorState; Mode = &StateInterate->ConnectorState.DisplayMode; //to delete AnalogixDpConnectorInit (StateInterate); if (Connector && Connector->Init) Status = Connector->Init(Connector, StateInterate); /* move to panel protocol --- todo */ DisplayGetTiming (StateInterate); DEBUG ((DEBUG_INIT, "[INIT]detailed mode clock %u kHz, flags[%x]\n" " H: %04d %04d %04d %04d\n" " V: %04d %04d %04d %04d\n" " bus_format: %x\n", Mode->Clock, Mode->Flags, Mode->HDisplay, Mode->HSyncStart, Mode->HSyncEnd, Mode->HTotal, Mode->VDisplay, Mode->VSyncStart, Mode->VSyncEnd, Mode->VTotal, ConnectorState->BusFormat)); Status = DisplaySetCrtcInfo(Mode, CRTC_INTERLACE_HALVE_V); if (EFI_ERROR (Status)) { goto EXIT; } if (Crtc && Crtc->Init) { Status = Crtc->Init (Crtc, StateInterate); if (EFI_ERROR (Status)) { goto EXIT; } } /* adapt to uefi display architecture */ CrtcState->Format = ROCKCHIP_FMT_ARGB8888; CrtcState->SrcW = ConnectorState->DisplayMode.HDisplay; CrtcState->SrcH = ConnectorState->DisplayMode.VDisplay; CrtcState->SrcX = 0; CrtcState->SrcY = 0; CrtcState->CrtcW = ConnectorState->DisplayMode.HDisplay; CrtcState->CrtcH = ConnectorState->DisplayMode.VDisplay; CrtcState->CrtcX = 0; CrtcState->CrtcY = 0; CrtcState->YMirror = 0; CrtcState->RBSwap = 0; LcdGraphicsGetBpp (StateInterate->ModeNumber, &LcdBpp); CrtcState->XVirtual = ALIGN(CrtcState->SrcW * DisplayBppConvert (LcdBpp), 32) >> 5; CrtcState->DMAAddress = (UINT32)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: return Status; } STATIC EFI_STATUS DisplayPreInit ( IN LCD_INSTANCE* Instance ) { EFI_STATUS Status; DISPLAY_STATE *StateInterate; ROCKCHIP_CRTC_PROTOCOL *Crtc; ROCKCHIP_CONNECTOR_PROTOCOL *Connector; LIST_FOR_EACH_ENTRY(StateInterate, &mDisplayStateList, ListHead) { if (StateInterate->IsEnable) { Crtc = (ROCKCHIP_CRTC_PROTOCOL*)StateInterate->CrtcState.Crtc; Connector = (ROCKCHIP_CONNECTOR_PROTOCOL *)StateInterate->ConnectorState.Connector; //to delete AnalogixDpConnectorPreInit(StateInterate); if (Connector && Connector->Preinit) Status = Connector->Preinit(Connector, StateInterate); if (Crtc && Crtc->Preinit) { Status = Crtc->Preinit(Crtc, StateInterate); if (EFI_ERROR (Status)) { goto EXIT; } } } } EXIT: return Status; } EFI_STATUS EFIAPI LcdGraphicsOutputDxeInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; LCD_INSTANCE* Instance; DISPLAY_STATE *DisplayState; DISPLAY_MODE *Mode; ROCKCHIP_CRTC_PROTOCOL *Crtc; INT32 i = 0; UINT32 HorizontalResolution = PcdGet32 (PcdVideoHorizontalResolution); UINT32 VerticalResolution = PcdGet32 (PcdVideoVerticalResolution); 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; } InitializeListHead (&mDisplayStateList); for (i = 0; i < mMaxMode; i++) { Mode = &mDisplayModes[i]; DisplayState = AllocatePool (sizeof(DISPLAY_STATE)); InitializeListHead (&DisplayState->ListHead); /* adapt to UEFI architecture */ DisplayState->ModeNumber = i; Status = gBS->LocateProtocol (&gRockchipCrtcProtocolGuid, NULL, (VOID **) &DisplayState->CrtcState.Crtc); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Can not locate the RockchipCrtcProtocol. Exit Status=%r\n", Status)); return EFI_INVALID_PARAMETER; } Crtc = (ROCKCHIP_CRTC_PROTOCOL*)DisplayState->CrtcState.Crtc; Crtc->Vps = Crtc->GetVps (Crtc, Mode->VpsConfigModeID); if (!Crtc->Vps) { DEBUG ((DEBUG_ERROR, "Can not get vps config. Exit Status=%r\n", EFI_INVALID_PARAMETER)); return EFI_INVALID_PARAMETER; } DisplayState->CrtcState.CrtcID = Mode->CrtcId; Status = gBS->LocateProtocol (&gRockchipConnectorProtocolGuid, NULL, (VOID **) &DisplayState->ConnectorState.Connector); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Can not locate the RockchipConnectorProtocol. Exit Status=%r\n", Status)); //to delete //return EFI_INVALID_PARAMETER; } DisplayState->ConnectorState.OverScan.LeftMargin = mDefaultOverScanParas.LeftMargin; DisplayState->ConnectorState.OverScan.RightMargin = mDefaultOverScanParas.RightMargin; DisplayState->ConnectorState.OverScan.TopMargin = mDefaultOverScanParas.TopMargin; DisplayState->ConnectorState.OverScan.BottomMargin = mDefaultOverScanParas.BottomMargin; /* set MEDIA_BUS_FMT_RBG888_1X24 by default when using panel */ /* move to panel driver later -- todo*/ DisplayState->ConnectorState.BusFormat = MEDIA_BUS_FMT_RBG888_1X24; /* add BCSH data if needed --- todo */ DisplayState->ConnectorState.DispInfo = NULL; if (Mode->Horizontal.Resolution == HorizontalResolution && Mode->Vertical.Resolution == VerticalResolution) DisplayState->IsEnable = TRUE; else DisplayState->IsEnable = FALSE; InsertTailList (&mDisplayStateList, &DisplayState->ListHead); } Status = DisplayPreInit (Instance); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "LcdGraphicsOutputDxeInitialize: DisplayPreInit fail. Exit Status=%r\n", Status)); goto EXIT_ERROR_UNINSTALL_PROTOCOL; } // 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 } } /** 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); (*Info)->Version = 0; (*Info)->HorizontalResolution = mDisplayModes[ModeNumber].Horizontal.Resolution; (*Info)->VerticalResolution = mDisplayModes[ModeNumber].Vertical.Resolution; (*Info)->PixelsPerScanLine = mDisplayModes[ModeNumber].Horizontal.Resolution; (*Info)->PixelFormat = FixedPcdGet32 (PcdLcdPixelFormat); return EFI_SUCCESS; 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; DISPLAY_STATE *StateInterate; ROCKCHIP_CRTC_PROTOCOL *Crtc; ROCKCHIP_CONNECTOR_PROTOCOL *Connector; //to delete struct AnalogixDpDevice *Dp; 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; } // Update the UEFI mode information This->Mode->Mode = ModeNumber; Instance->ModeInfo.Version = 0; Instance->ModeInfo.HorizontalResolution = mDisplayModes[ModeNumber].Horizontal.Resolution; Instance->ModeInfo.VerticalResolution = mDisplayModes[ModeNumber].Vertical.Resolution; Instance->ModeInfo.PixelsPerScanLine = mDisplayModes[ModeNumber].Horizontal.Resolution; Instance->ModeInfo.PixelFormat = FixedPcdGet32 (PcdLcdPixelFormat); Status = LcdGraphicsGetBpp (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); LIST_FOR_EACH_ENTRY(StateInterate, &mDisplayStateList, ListHead) { if (StateInterate->ModeNumber == ModeNumber && StateInterate->IsEnable) { Crtc = (ROCKCHIP_CRTC_PROTOCOL*)StateInterate->CrtcState.Crtc; Connector = (ROCKCHIP_CONNECTOR_PROTOCOL *)StateInterate->ConnectorState.Connector; if (Crtc && Crtc->SetPlane) Crtc->SetPlane (Crtc, StateInterate); if (Crtc && Crtc->Enable) Crtc->Enable (Crtc, StateInterate); if (Connector && Connector->Enable) Connector->Enable (Connector, StateInterate); //to delete Dp = AllocatePool(sizeof(*Dp)); AnalogixDpConnectorEnable(StateInterate, Dp); } } // 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; } EFI_STATUS EFIAPI LcdGraphicsGetBpp ( IN UINT32 ModeNumber, OUT LCD_BPP* Bpp ) { if (ModeNumber >= mMaxMode) { return EFI_INVALID_PARAMETER; } *Bpp = LcdBitsPerPixel_24; return EFI_SUCCESS; } 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; } }