/** @file This is part of the implementation of DG OpRegion initialization. Software SCI interface between system BIOS, ASL code, and Graphics drivers. The code in this file will load the driver and initialize the interface ;****************************************************************************** ;* Copyright (c) 2021, Insyde Software Corp. All Rights Reserved. ;* ;* You may not reproduce, distribute, publish, display, perform, modify, adapt, ;* transmit, broadcast, present, recite, release, license or otherwise exploit ;* any part of this publication in any form, by any means, without the prior ;* written permission of Insyde Software Corporation. ;* ;****************************************************************************** @copyright INTEL CONFIDENTIAL Copyright 2020 - 2021 Intel Corporation. The source code contained or described herein and all documents related to the source code ("Material") are owned by Intel Corporation or its suppliers or licensors. Title to the Material remains with Intel Corporation or its suppliers and licensors. The Material may contain trade secrets and proprietary and confidential information of Intel Corporation and its suppliers and licensors, and is protected by worldwide copyright and trade secret laws and treaty provisions. No part of the Material may be used, copied, reproduced, modified, published, uploaded, posted, transmitted, distributed, or disclosed in any way without Intel's prior express written permission. No license under any patent, copyright, trade secret or other intellectual property right is granted to or conferred upon you by disclosure or delivery of the Materials, either expressly, by implication, inducement, estoppel or otherwise. Any license under such intellectual property rights must be express and approved by Intel in writing. Unless otherwise agreed by Intel in writing, you may not remove or alter this notice or any other notice embedded in Materials by Intel or Intel's suppliers or licensors in any way. This file contains an 'Intel Peripheral Driver' and is uniquely identified as "Intel Reference Module" and is licensed for Intel CPUs and chipsets under the terms of your license agreement with Intel or your vendor. This file may be modified by the user, subject to additional terms of the license agreement. @par Specification Reference: - OpRegion / Software SCI SPEC **/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "DgOpRegion.h" #include "HybridGraphicsInfo.h" #include #include GLOBAL_REMOVE_IF_UNREFERENCED DG_OPREGION_PROTOCOL DgOpRegion; /** Check if the device id is DG @param[in] UINT16 DeviceId @retval BOOLEAN TRUE if DG DeviceId , FALSE otherwise. **/ BOOLEAN IsDgDevice ( IN UINT16 DeviceId ) { switch (DeviceId) { case DG2_DEVICE_ID_1: case DG2_DEVICE_ID_2: case DG2_DEVICE_ID_3: case DG2_DEVICE_ID_4: case DG2_DEVICE_ID_5: case DG2_DEVICE_ID_6: case DG2_DEVICE_ID_7: case DG2_DEVICE_ID_8: case DG2_DEVICE_ID_9: //[-start-210831-IB05660175-add]// case DG2_DEVICE_ID_10: //[-end-210831-IB05660175-add]// return TRUE; default: return FALSE; } } /** This function gets registered as a callback to Update DG Graphics OpRegion after PCI enumeration for VRAMSR support @param[in] Event - A pointer to the Event that triggered the callback. @param[in] Context - A pointer to private data registered with the callback function. **/ VOID EFIAPI UpdateDgOnPciEnumComplete ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_STATUS Status; UINTN HandleCount; PCI_TYPE00 Pci; UINTN Index; UINTN Segment; UINTN Bus; UINTN Device; UINTN Function; EFI_HANDLE *HandleBuffer; EFI_PCI_IO_PROTOCOL *PciIo; PCI_DATA_STRUCTURE *PcirBlockPtr; PCI_EXPANSION_ROM_HEADER *LocalRomImage; PLATFORM_NVS_AREA_PROTOCOL *PlatformNvsAreaProtocol; UINT64 DgBaseAddress; UINT64 ConfigDataSize; UINTN VariableSize; SETUP_DATA SetupVariables; BOOLEAN DgDeviceFound; VOID *ProtocolPointer; Bus = 0; Device = 0; Function = 0; DgDeviceFound = FALSE; DEBUG ((DEBUG_INFO, "UpdateDgOnPciEnumComplete Start\n")); Status = gBS->LocateProtocol (&gEfiPciEnumerationCompleteProtocolGuid, NULL, (VOID **) &ProtocolPointer); if (EFI_ERROR (Status)) { return; } /// /// Get the SA policy and the required Dg config block. /// VariableSize = sizeof (SETUP_DATA); ZeroMem (&SetupVariables, VariableSize); Status = gRT->GetVariable ( L"Setup", &gSetupVariableGuid, NULL, &VariableSize, &SetupVariables ); ASSERT_EFI_ERROR (Status); /// /// Locate the SA Global NVS Protocol. /// Status = gBS->LocateProtocol (&gPlatformNvsAreaProtocolGuid, NULL, (VOID **) &PlatformNvsAreaProtocol); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO, "UpdateDgOnPciEnumComplete - Not able to locate NVS protocol 0x%x \n", Status)); return; } /// /// Get all PCI IO protocols handles /// Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiPciIoProtocolGuid, NULL, &HandleCount, &HandleBuffer ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO, "UpdateDgOnPciEnumComplete -Not able to get PCI IO handles 0x%x \n", Status)); return; } for (Index = 0; Index < HandleCount; Index++) { /// /// Get the PCI IO Protocol Interface corresponding to each handle /// PciIo = NULL; Status = gBS->HandleProtocol ( HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID **) &PciIo ); if (EFI_ERROR (Status)) { /// /// Not able to locate the pci io protocol, skip to the next device, /// continue; } Status = PciIo->Pci.Read ( PciIo, EfiPciIoWidthUint32, 0, sizeof (Pci) / sizeof (UINT32), &Pci ); if (EFI_ERROR (Status) || (NULL == PciIo->RomImage)) { /// /// If this PCI device doesn't have a ROM image, skip to the next device, /// continue; } LocalRomImage = PciIo->RomImage; PcirBlockPtr = (PCI_DATA_STRUCTURE *) ((UINTN) LocalRomImage + LocalRomImage->PcirOffset); if ((OPTION_ROM_SIGNATURE != LocalRomImage->Signature) || (NULL == PcirBlockPtr)) { /// /// If this PCI device doesn't have a valid Option rom image or pcir block, /// skip to the next device, /// continue; } /// /// If DG device is found then get the OpRegion start address, OpRegion offset and size /// if ((Pci.Hdr.VendorId == 0x8086) && (IsDgDevice (Pci.Hdr.DeviceId))) { DgDeviceFound = TRUE; break; } } if (DgDeviceFound == FALSE) { DEBUG ((DEBUG_INFO, "UpdateDgOnPciEnumComplete -DG Device not found\n")); return; } /// /// Find the b.d.f of the DG device /// Status = PciIo->GetLocation ( PciIo, &Segment, &Bus, &Device, &Function ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO, "UpdateDgOnPciEnumComplete - Not able to locate the b.d.f of DG device 0x%x \n", Status)); return; } DEBUG ((DEBUG_INFO, "UpdateDgOnPciEnumComplete - DG device b.d.f 0x%x : 0x%x : 0x%x \n", Bus, Device, Function)); DgBaseAddress = PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, Bus, Device, Function, 0); DEBUG ((DEBUG_INFO, "UpdateDgOnPciEnumComplete - DgBaseAddress : 0x%x \n", DgBaseAddress)); PlatformNvsAreaProtocol->Area->DgBaseAddress = DgBaseAddress; PlatformNvsAreaProtocol->Area->DgBrightnessPercentage = 100; /// /// Allocate NVS memory of OpRegion Size + 16KB of buffer for VBT which Gfx driver will copy into. /// ConfigDataSize = sizeof (DG_OPREGION_STRUCTURE) + SIZE_16KB; /// /// Allocate an ACPI NVS memory buffer as the DG NVS OpRegion. /// Status = (gBS->AllocatePool) (EfiACPIMemoryNVS, ConfigDataSize, (VOID **) &DgOpRegion.OpRegion); ASSERT_EFI_ERROR (Status); DEBUG ((DEBUG_INFO, "UpdateDgOnPciEnumComplete allocated Nvs OpRegion 0x%x \n", (UINT32) (UINTN) (DgOpRegion.OpRegion))); SetMem (DgOpRegion.OpRegion, ConfigDataSize, 0); PlatformNvsAreaProtocol->Area->DgOpRegionAddress = (UINT32) (UINTN) (DgOpRegion.OpRegion); /// /// Initialize OpRegion Header /// CopyMem (DgOpRegion.OpRegion->Header.SIGN, DG_HEADER_SIGNATURE, sizeof (DG_HEADER_SIGNATURE)); /// /// Set OpRegion Size in KBs /// DgOpRegion.OpRegion->Header.SIZE = HEADER_SIZE / 1024; DgOpRegion.OpRegion->Header.OVER = (UINT32) (LShiftU64 (HEADER_OPREGION_VER, 16) + LShiftU64 (HEADER_OPREGION_REV, 8)); /// /// All Mailboxes are supported. /// DgOpRegion.OpRegion->Header.MBOX = HEADER_MBOX_SUPPORT; /// /// Update DG Opregion fields /// if (SetupVariables.DgPlatformSupport == 1) { // // Set PCON BIT9 & BIT10 if External Gfx adapter is in MB-down config // DgOpRegion.OpRegion->Header.PCON |= (BIT9 | BIT10); } // For DG MBD RVP, BIT 12 & BIT 11 of PCON variable in DG Op-region are required to be set to support VRAM Self Refresh feature // By default enabling VRAM SR, oem can override this DgOpRegion.OpRegion->Header.PCON |= (BIT12 | BIT11); // // Set BIT0 & BIT1 if Platform is Connected Standby capable & it's capability field is valid respectively. // if (SetupVariables.LowPowerS0Idle == 0) { DgOpRegion.OpRegion->Header.PCON |= (BIT1 | BIT0); } else { DgOpRegion.OpRegion->Header.PCON &= (UINT32)(~BIT0); //[-start-211215-QINGLIN0129-add]// #ifdef LCFC_SUPPORT DgOpRegion.OpRegion->Header.PCON |= BIT1; #endif //[-end-211215-QINGLIN0129-add]// } //[-start-211123-QINGLIN0117-add]// #ifdef LCFC_SUPPORT // Set PCON BIT13 for headless profile. dGFX driver will identify this bit. OPREGION version higher than 0x0203 has this bit13 setting definition. DgOpRegion.OpRegion->Header.PCON |= BIT13; #endif //[-end-211123-QINGLIN0117-add]// DgOpRegion.OpRegion->MBox3.BCLP = BACKLIGHT_BRIGHTNESS; DgOpRegion.OpRegion->MBox3.CBLV = (INIT_BRIGHT_LEVEL | FIELD_VALID_BIT); DgOpRegion.OpRegion->MBox3.BCLM[0] = (0x0000 + WORD_FIELD_VALID_BIT); ///< 0% DgOpRegion.OpRegion->MBox3.BCLM[1] = (0x0A19 + WORD_FIELD_VALID_BIT); ///< 10% DgOpRegion.OpRegion->MBox3.BCLM[2] = (0x1433 + WORD_FIELD_VALID_BIT); ///< 20% DgOpRegion.OpRegion->MBox3.BCLM[3] = (0x1E4C + WORD_FIELD_VALID_BIT); ///< 30% DgOpRegion.OpRegion->MBox3.BCLM[4] = (0x2866 + WORD_FIELD_VALID_BIT); ///< 40% DgOpRegion.OpRegion->MBox3.BCLM[5] = (0x327F + WORD_FIELD_VALID_BIT); ///< 50% DgOpRegion.OpRegion->MBox3.BCLM[6] = (0x3C99 + WORD_FIELD_VALID_BIT); ///< 60% DgOpRegion.OpRegion->MBox3.BCLM[7] = (0x46B2 + WORD_FIELD_VALID_BIT); ///< 70% DgOpRegion.OpRegion->MBox3.BCLM[8] = (0x50CC + WORD_FIELD_VALID_BIT); ///< 80% DgOpRegion.OpRegion->MBox3.BCLM[9] = (0x5AE5 + WORD_FIELD_VALID_BIT); ///< 90% DgOpRegion.OpRegion->MBox3.BCLM[10] = (0x64FF + WORD_FIELD_VALID_BIT); ///< 100% DEBUG ((DEBUG_INFO, "UpdateDgOnPciEnumComplete - PCON 0x%x Nvs OpRegion 0x%x \n", DgOpRegion.OpRegion->Header.PCON, PlatformNvsAreaProtocol->Area->DgOpRegionAddress)); /// /// Set ASLS Register to the OpRegion physical memory address.. /// PciSegmentWrite32 (DgBaseAddress + R_SA_DG_ASLS_OFFSET, (UINT32) (UINTN) (DgOpRegion.OpRegion)); DEBUG ((DEBUG_INFO, "UpdateDgOnPciEnumComplete - Value at R_SA_DG_ASLS_OFFSET 0x%x \n", (PciSegmentRead32 (DgBaseAddress + R_SA_DG_ASLS_OFFSET)))); } /** DG Op-Region Initialization for VRAM SR support @param[in] ImageHandle Handle for the image of this driver @param[in] SystemTable Pointer to the EFI System Table @retval EFI_SUCCESS The function completed successfully **/ EFI_STATUS EFIAPI DxeDgOpregionInit ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { VOID *Registration; if (PcdGetBool (PcdDashGEnable) == FALSE) { DEBUG ((DEBUG_INFO, "DxeDgOpregionInit - DashG is not enabled\n")); return EFI_UNSUPPORTED; } /// /// Create PCI Enumeration Completed callback for DG /// EfiCreateProtocolNotifyEvent ( &gEfiPciEnumerationCompleteProtocolGuid, TPL_CALLBACK, UpdateDgOnPciEnumComplete, NULL, &Registration ); return EFI_SUCCESS; }