1968 lines
67 KiB
C
1968 lines
67 KiB
C
/** @file
|
|
This driver is for Hybrid Graphics Feature DXE initialize.
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2018 - 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.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
|
|
#include <HybridGraphicsDxe.h>
|
|
#include <CommonDefinitions.h>
|
|
#include <SetupConfig.h>
|
|
|
|
GLOBAL_REMOVE_IF_UNREFERENCED PLATFORM_NVS_AREA_PROTOCOL *mPlatformNvsAreaProtocol;
|
|
|
|
//
|
|
// Function Prototypes
|
|
//
|
|
VOID
|
|
EFIAPI
|
|
HybridGraphicsBdsCallback (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
);
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
HybridGraphicsDxeInitialize (
|
|
IN OUT HG_DXE_INFORMATION_DATA **HgDxeInfoData,
|
|
IN OUT HG_INFORMATION_DATA_HOB **HgInfoDataHob
|
|
);
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
NvidiaOptimusDxeInitialize (
|
|
IN HG_DXE_INFORMATION_DATA *HgDxeInfoData,
|
|
IN HG_INFORMATION_DATA_HOB *HgInfoDataHob
|
|
);
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
InitMXMSupport (
|
|
IN EFI_GUID *MxmBinaryGuid,
|
|
IN OUT UINTN *Address,
|
|
IN OUT UINTN *Size,
|
|
IN UINT8 BootType
|
|
);
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ControlNvidiaDgpuHdAudio (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
);
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
SearchDiscreteGraphicsVbios (
|
|
IN OUT HG_DXE_INFORMATION_DATA *HgDxeInfoData
|
|
);
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
ExecuteDiscreteGraphicsVbios (
|
|
IN OUT HG_DXE_INFORMATION_DATA *HgDxeInfoData,
|
|
IN HG_INFORMATION_DATA_HOB *HgInfoDataHob
|
|
);
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
SetHybridGraphicsSsdt (
|
|
IN HG_DXE_INFORMATION_DATA *HgDxeInfoData,
|
|
IN HG_INFORMATION_DATA_HOB *HgInfoDataHob
|
|
);
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
InitializeOpRegion (
|
|
IN EFI_ACPI_DESCRIPTION_HEADER *NvStoreTable,
|
|
IN HG_DXE_INFORMATION_DATA *HgDxeInfoData,
|
|
IN HG_INFORMATION_DATA_HOB *HgInfoDataHob
|
|
);
|
|
|
|
STATIC
|
|
VOID
|
|
UpdateHgOpRegion (
|
|
IN OUT EFI_HG_NVS_AREA_PROTOCOL *HgOpRegion,
|
|
IN HG_DXE_INFORMATION_DATA *HgDxeInfoData,
|
|
IN HG_INFORMATION_DATA_HOB *HgInfoDataHob
|
|
);
|
|
|
|
STATIC
|
|
VOID
|
|
UpdateAmdOpRegion (
|
|
IN OUT OPERATION_REGION_AMD *AmdOpRegion,
|
|
IN HG_DXE_INFORMATION_DATA *HgDxeInfoData,
|
|
IN HG_INFORMATION_DATA_HOB *HgInfoDataHob
|
|
);
|
|
|
|
STATIC
|
|
VOID
|
|
UpdateNvidiaOpRegion (
|
|
IN OUT OPERATION_REGION_NVIDIA *NvidiaOpRegion,
|
|
IN HG_DXE_INFORMATION_DATA *HgDxeInfoData,
|
|
IN HG_INFORMATION_DATA_HOB *HgInfoDataHob
|
|
);
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
HgInformationUpdate (
|
|
IN HG_DXE_INFORMATION_DATA *HgDxeInfoData,
|
|
IN HG_INFORMATION_DATA_HOB *HgInfoDataHob
|
|
);
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SetSecondaryGrcphicsCommandRegister (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
);
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CloseDiscreteSecondaryHdAudio (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
);
|
|
|
|
VOID
|
|
EFIAPI
|
|
FreeHgDxeInfoData (
|
|
IN OUT HG_DXE_INFORMATION_DATA **HgDxeInfoData
|
|
);
|
|
|
|
STATIC
|
|
VOID
|
|
DisableDgpuBridgeHotplugSmi (
|
|
IN HG_DXE_INFORMATION_DATA *HgDxeInfoData
|
|
);
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
CloseAmdSecondaryAudioDevice (
|
|
IN HG_DXE_INFORMATION_DATA *HgDxeInfoData,
|
|
IN HG_INFORMATION_DATA_HOB *HgInfoDataHob
|
|
);
|
|
|
|
/**
|
|
This function calculates and updates an UINT8 checksum.
|
|
|
|
@param[in] Buffer Pointer to buffer to checksum
|
|
@param[in] Size Number of bytes to checksum
|
|
@param[in] ChecksumOffset Offset to place the checksum result in
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
**/
|
|
EFI_STATUS
|
|
AcpiChecksum (
|
|
IN VOID *Buffer,
|
|
IN UINTN Size,
|
|
IN UINTN ChecksumOffset
|
|
)
|
|
{
|
|
UINT8 Sum;
|
|
UINT8 *Ptr;
|
|
|
|
Sum = 0;
|
|
///
|
|
/// Initialize pointer
|
|
///
|
|
Ptr = Buffer;
|
|
|
|
///
|
|
/// set checksum to 0 first
|
|
///
|
|
Ptr[ChecksumOffset] = 0;
|
|
|
|
///
|
|
/// add all content of buffer
|
|
///
|
|
while (Size--) {
|
|
Sum = (UINT8) (Sum + (*Ptr++));
|
|
}
|
|
///
|
|
/// set checksum
|
|
///
|
|
Ptr = Buffer;
|
|
Ptr[ChecksumOffset] = (UINT8) (0xff - Sum + 1);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
Hybrid Graphics feature driver entry point.
|
|
This driver will handle secondary VBIOS and create feature own SSDT.
|
|
|
|
@param[in] ImageHandle Image handle of this driver.
|
|
@param[in] SystemTable Pointer to standard EFI system table.
|
|
|
|
@retval EFI_SUCCESS Hybrid Graphics feature DXE initialized successfully.
|
|
@retval !EFI_SUCCESS Hybrid Graphics feature doesn't be supported.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
HybridGraphicsDxeInitEntry (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
H2O_HG_INFO_PROTOCOL *HgInfoProtocol;
|
|
VOID *Registration;
|
|
EFI_HG_NVS_AREA_PROTOCOL *HGNvsArea;
|
|
|
|
HGNvsArea = AllocateReservedZeroPool (sizeof (EFI_HG_NVS_AREA_PROTOCOL));
|
|
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&ImageHandle,
|
|
&gEfiHgNvsAreaProtocolGuid,
|
|
HGNvsArea,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
if (FeaturePcdGet (PcdHybridGraphicsSupported)) {
|
|
EfiCreateProtocolNotifyEvent (
|
|
&gH2OHybridGraphicsEventProtocolGuid,
|
|
TPL_CALLBACK,
|
|
HybridGraphicsBdsCallback,
|
|
NULL,
|
|
&Registration
|
|
);
|
|
|
|
//
|
|
// Allocate and install Hybrid Graphics information Protocol.
|
|
//
|
|
HgInfoProtocol = AllocateReservedZeroPool (sizeof (H2O_HG_INFO_PROTOCOL));
|
|
if (HgInfoProtocol == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&ImageHandle,
|
|
&gH2OHybridGraphicsInfoProtocolGuid,
|
|
HgInfoProtocol,
|
|
NULL
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
After BDS platform driver connect Root Bridge will install HG protocol
|
|
to trigger event to run this Hybrid Graphics feature callback,
|
|
this specific timing discrete graphics already exist then we can
|
|
handle and initialize it.
|
|
|
|
@param[in] Event Event whose notification function is being invoked.
|
|
@param[in] Context Pointer to the notification function's context.
|
|
|
|
@retval None.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
HybridGraphicsBdsCallback (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
HG_DXE_INFORMATION_DATA *HgDxeInfoData;
|
|
HG_INFORMATION_DATA_HOB *HgInfoDataHob;
|
|
UINT8 *Instance;
|
|
|
|
//
|
|
// Make sure the time to execute this callback is BDS phase (After PCI enumeration).
|
|
//
|
|
Status = gBS->LocateProtocol (
|
|
&gH2OHybridGraphicsEventProtocolGuid,
|
|
NULL,
|
|
(VOID **)&Instance
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
|
|
Status = gBS->LocateProtocol (
|
|
&gPlatformNvsAreaProtocolGuid,
|
|
NULL,
|
|
(VOID **)&mPlatformNvsAreaProtocol
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Get HG information data HOB, and create HG DXE infromation Data.
|
|
//
|
|
Status = HybridGraphicsDxeInitialize (&HgDxeInfoData, &HgInfoDataHob);
|
|
if (EFI_ERROR (Status) || HgDxeInfoData == NULL || HgInfoDataHob == NULL) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Close Hybrid Graphics BDS event.
|
|
//
|
|
gBS->CloseEvent (Event);
|
|
|
|
if (FeaturePcdGet (PcdNvidiaOptimusSupported)) {
|
|
//
|
|
// Get MXM SIS, Update global NVS area variable and set HG variable for nVIDIA Optimus.
|
|
//
|
|
Status = NvidiaOptimusDxeInitialize (HgDxeInfoData, HgInfoDataHob);
|
|
if (EFI_ERROR (Status)) {
|
|
FreeHgDxeInfoData (&HgDxeInfoData);
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Search discrete graphics VBIOS location, and initialize secondary ATI graphics VBIOS.
|
|
//
|
|
Status = SearchDiscreteGraphicsVbios (HgDxeInfoData);
|
|
if (!EFI_ERROR (Status)) {
|
|
if (FeaturePcdGet (PcdAmdPowerXpressSupported)) {
|
|
if ((HgInfoDataHob->HgMode == HgModeMuxless) &&
|
|
(HgDxeInfoData->DgpuVendorId == AMD_VID) &&
|
|
(HgInfoDataHob->BootType != EfiBootType)) {
|
|
ExecuteDiscreteGraphicsVbios (HgDxeInfoData, HgInfoDataHob);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set HG SSDT and initialize HG own operation region.
|
|
//
|
|
Status = SetHybridGraphicsSsdt (HgDxeInfoData, HgInfoDataHob);
|
|
if (EFI_ERROR (Status)) {
|
|
FreeHgDxeInfoData (&HgDxeInfoData);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Update Hybrid Graphics infromation protocol,
|
|
// and create event to set the Secondary Grcphics Command Register.
|
|
//
|
|
Status = HgInformationUpdate (HgDxeInfoData, HgInfoDataHob);
|
|
if (EFI_ERROR (Status)) {
|
|
FreeHgDxeInfoData (&HgDxeInfoData);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Clear secondary audio device.
|
|
//
|
|
if (HgDxeInfoData->DgpuVendorId == AMD_VID) {
|
|
Status = CloseAmdSecondaryAudioDevice (HgDxeInfoData, HgInfoDataHob);
|
|
}
|
|
}
|
|
|
|
/**
|
|
|
|
Hybrid Graphics feature DXE driver initialize function.
|
|
This function will get HG information data HOB, and create HG DXE infromation Data.
|
|
|
|
@param[in, out] HgDxeInfoData A double pointer of HG DXE information data structure,
|
|
this driver or HG Operation Region will use these data.
|
|
@param[in, out] HgInfoDataHob A double pointer of HG information data HOB,
|
|
HG PEI Module created this HOB, and passes the data from PEI phase.
|
|
|
|
@retval EFI_SUCCESS This path initialized data successfully, and need handle HG SSDT and VBIOS.
|
|
@retval !EFI_SUCCESS This path initialized data failed and doesn't handle HG SSDT and VBIOS.
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
HybridGraphicsDxeInitialize (
|
|
IN OUT HG_DXE_INFORMATION_DATA **HgDxeInfoData,
|
|
IN OUT HG_INFORMATION_DATA_HOB **HgInfoDataHob
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 DgpuBridgeBus;
|
|
UINT8 DgpuBus;
|
|
UINT16 DgpuVendorId;
|
|
//[-start-211206-JEPLIUT205-add]//
|
|
#if defined(S570_SUPPORT)
|
|
UINT32 DATA32;
|
|
UINT8 DWlanBus;
|
|
#endif
|
|
//[-end-211206-JEPLIUT205-add]//
|
|
UINTN DgpuBridgeDevice;
|
|
UINTN DgpuBridgeFunction;
|
|
UINTN PciAddress;
|
|
HG_INFO_HOB *HgInfoHob;
|
|
UINT16 DgpuDeviceId;
|
|
CHIPSET_CONFIGURATION ChipsetConfiguration;
|
|
UINTN Size;
|
|
UINT8 BaseClassCode;
|
|
|
|
(*HgDxeInfoData) = NULL;
|
|
HgInfoHob = NULL;
|
|
|
|
//
|
|
// Get HG related information data HOB and SA config data HOB.
|
|
//
|
|
Status = EfiGetSystemConfigurationTable (&gEfiHobListGuid, HgInfoDataHob);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
HgInfoHob = GetNextGuidHob (&gHybridGraphicsInfoHobGuid, (*HgInfoDataHob));
|
|
if (HgInfoHob == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
(*HgInfoDataHob) = GetNextGuidHob (&gH2OHgInformationDataHobGuid, (*HgInfoDataHob));
|
|
if ((*HgInfoDataHob) == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
Size = sizeof (CHIPSET_CONFIGURATION);
|
|
Status = gRT->GetVariable (
|
|
SETUP_VARIABLE_NAME,
|
|
&gSystemConfigurationGuid,
|
|
NULL,
|
|
&Size,
|
|
&ChipsetConfiguration
|
|
);
|
|
|
|
if (ChipsetConfiguration.HgSlot == PCH) {
|
|
DgpuBridgeBus = PcdGet8 (PcdHgPcieBridgeBus);
|
|
// DgpuBridgeDevice = PcdGet8 (PcdHgPcieBridgeDevice);
|
|
// DgpuBridgeFunction = PcdGet8 (PcdHgPcieBridgeFunction);
|
|
if (PcdGetBool (PcdUseCrbHgDefaultSettings)) {
|
|
Status = GetPchPcieRpDevFun ((UINTN)HgInfoHob->HgInfo.RootPortIndex, &DgpuBridgeDevice, &DgpuBridgeFunction);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
} else {
|
|
//
|
|
// Project needs to set correct physical root port number (0-based),
|
|
// otherwise Device/Function number will not correct.
|
|
//
|
|
Status = GetPchPcieRpDevFun ((UINTN)PcdGet8 (PcdHgPcieRootPortIndex), &DgpuBridgeDevice, &DgpuBridgeFunction);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
} else {
|
|
DgpuBridgeBus = PcdGet8 (PcdHgPegBridgeBus);
|
|
DgpuBridgeDevice = PcdGet8 (PcdHgPegBridgeDevice);
|
|
DgpuBridgeFunction = PcdGet8 (PcdHgPegBridgeFunction);
|
|
}
|
|
|
|
//
|
|
// Read discrete GPU Bus and Venodr ID.
|
|
//
|
|
PciAddress = PCI_EXPRESS_LIB_ADDRESS (
|
|
(UINTN)DgpuBridgeBus,
|
|
(UINTN)DgpuBridgeDevice,
|
|
(UINTN)DgpuBridgeFunction,
|
|
PCI_SBUS
|
|
);
|
|
DgpuBus = PciExpressRead8 (PciAddress);
|
|
PciAddress = PCI_EXPRESS_LIB_ADDRESS (
|
|
DgpuBus,
|
|
DGPU_DEVICE_NUM,
|
|
DGPU_FUNCTION_NUM,
|
|
PCI_VID
|
|
);
|
|
DgpuVendorId = PciExpressRead16 (PciAddress);
|
|
PciAddress = PCI_EXPRESS_LIB_ADDRESS (
|
|
DgpuBus,
|
|
DGPU_DEVICE_NUM,
|
|
DGPU_FUNCTION_NUM,
|
|
PCI_DID
|
|
);
|
|
DgpuDeviceId = PciExpressRead16 (PciAddress);
|
|
|
|
PciAddress = PCI_EXPRESS_LIB_ADDRESS (
|
|
DgpuBus,
|
|
DGPU_DEVICE_NUM,
|
|
DGPU_FUNCTION_NUM,
|
|
PCI_BCC
|
|
);
|
|
BaseClassCode = PciExpressRead8 (PciAddress);
|
|
|
|
if ((DgpuBus == 0x00) || (DgpuBus == 0xFF) || (DgpuVendorId == 0xFFFF) ||
|
|
((**HgInfoDataHob).HgMode == HgModeDisabled) || (BaseClassCode != PCI_CLASS_DISPLAY)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Allocate and initialize Hybrid Graphics DXE driver information data.
|
|
//
|
|
(*HgDxeInfoData) = AllocateZeroPool (sizeof (HG_DXE_INFORMATION_DATA));
|
|
if ((*HgDxeInfoData) == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
(**HgDxeInfoData).DgpuBridgeBus = DgpuBridgeBus;
|
|
(**HgDxeInfoData).DgpuBridgeDevice = DgpuBridgeDevice;
|
|
(**HgDxeInfoData).DgpuBridgeFunction = DgpuBridgeFunction;
|
|
(**HgDxeInfoData).Dgpu2BridgeBus = PcdGet8 (PcdHgDgpu2BridgeBus);
|
|
(**HgDxeInfoData).Dgpu2BridgeDevice = PcdGet8 (PcdHgDgpu2BridgeDevice);
|
|
(**HgDxeInfoData).Dgpu2BridgeFunction = PcdGet8 (PcdHgDgpu2BridgeFunction);
|
|
|
|
//
|
|
// Bus 0 Device 0 Function 0 Offset 54 is DEVEN - Device Enable register (decide iGPU exist or not).
|
|
//
|
|
PciAddress = PCI_EXPRESS_LIB_ADDRESS (SA_MC_BUS, SA_MC_DEV, SA_MC_FUN, R_SA_DEVEN);
|
|
(**HgDxeInfoData).SaDeven = PciExpressRead8 (PciAddress);
|
|
(**HgDxeInfoData).Dgpu2GpioSupport = (**HgInfoDataHob).Dgpu2GpioSupport;
|
|
(**HgDxeInfoData).AmdSecondaryGrcphicsCommandRegister = PcdGet8 (PcdAmdSecondaryGrcphicsCommandRegister);
|
|
(**HgDxeInfoData).NvidiaSecondaryGrcphicsCommandRegister = PcdGet8 (PcdNvidiaSecondaryGrcphicsCommandRegister);
|
|
(**HgDxeInfoData).DgpuBus = DgpuBus;
|
|
(**HgDxeInfoData).DgpuVendorId = DgpuVendorId;
|
|
(**HgDxeInfoData).DgpuDeviceId = DgpuDeviceId;
|
|
mPlatformNvsAreaProtocol->Area->DgpuVendorID = DgpuVendorId;
|
|
|
|
//[-start-211206-JEPLIUT205-add]//
|
|
#if defined(S570_SUPPORT)
|
|
PciAddress = PCI_EXPRESS_LIB_ADDRESS (
|
|
0,
|
|
0x1d,
|
|
0,
|
|
0x19
|
|
);
|
|
DWlanBus = PciExpressRead8 (PciAddress);
|
|
PciAddress = PCI_EXPRESS_LIB_ADDRESS (
|
|
DWlanBus,
|
|
0x00,
|
|
0x00,
|
|
0
|
|
);
|
|
DATA32 = PciExpressRead32 (PciAddress);
|
|
|
|
if (DATA32 == 0xC82210EC) {
|
|
mPlatformNvsAreaProtocol->Area->WwanRtd3Option = 1;
|
|
}
|
|
else {
|
|
mPlatformNvsAreaProtocol->Area->WwanRtd3Option = 2;
|
|
}
|
|
#endif
|
|
//[-end-211206-JEPLIUT205-add]//
|
|
|
|
//
|
|
// Read Slave discrete GPU Bus and Venodr ID.
|
|
//
|
|
if ((**HgDxeInfoData).Dgpu2GpioSupport) {
|
|
PciAddress = PCI_EXPRESS_LIB_ADDRESS (
|
|
(**HgDxeInfoData).Dgpu2BridgeBus,
|
|
(**HgDxeInfoData).Dgpu2BridgeDevice,
|
|
(**HgDxeInfoData).Dgpu2BridgeFunction,
|
|
PCI_SBUS
|
|
);
|
|
(**HgDxeInfoData).Dgpu2Bus = PciExpressRead8 (PciAddress);
|
|
PciAddress = PCI_EXPRESS_LIB_ADDRESS (
|
|
(**HgDxeInfoData).Dgpu2Bus,
|
|
DGPU_DEVICE_NUM,
|
|
DGPU_FUNCTION_NUM,
|
|
PCI_VID
|
|
);
|
|
(**HgDxeInfoData).Dgpu2VendorId = PciExpressRead16 (PciAddress);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
nVIDIA Optimus DXE driver initialize function.
|
|
This function will update global NVS area variable, set HG variable and load MXM SIS binary.
|
|
|
|
@param[in, out] HgDxeInfoData A pointer of HG DXE information data structure,
|
|
this driver or HG Operation Region will use these data.
|
|
@param[in] HgInfoDataHob A pointer of HG information data HOB,
|
|
HG PEI Module created this HOB, and passes the data from PEI phase.
|
|
|
|
@retval EFI_SUCCESS Update global NVS area variable and set HG variable both successfully.
|
|
@retval !EFI_SUCCESS Update global NVS area variable or set HG variable failed.
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
NvidiaOptimusDxeInitialize (
|
|
IN OUT HG_DXE_INFORMATION_DATA *HgDxeInfoData,
|
|
IN HG_INFORMATION_DATA_HOB *HgInfoDataHob
|
|
)
|
|
{
|
|
EFI_EVENT ReadyToBootEvent;
|
|
EFI_STATUS Status;
|
|
HG_VARIABLE_CONFIGURATION *HgVariableData;
|
|
EFI_HG_NVS_AREA_PROTOCOL *HGNvsArea;
|
|
UINT16 *HgNvidiaDgpuCheckTable;
|
|
UINTN Index;
|
|
UINTN Size;
|
|
NV_DGPU_INFO *HgNvidiaDgpuInfo;
|
|
|
|
//
|
|
// Base on different mode to load different MXM binary.
|
|
//
|
|
if (HgDxeInfoData->DgpuVendorId == NVIDIA_VID) {
|
|
if (((HgDxeInfoData->SaDeven) & B_SA_DEVEN_D2EN_MASK) == Inactive) {
|
|
InitMXMSupport (
|
|
PcdGetPtr (PcdPegModeMasterMxmBinaryGuid),
|
|
&(HgDxeInfoData->DgpuMxmBinFile.Address),
|
|
&(HgDxeInfoData->DgpuMxmBinFile.Size),
|
|
HgInfoDataHob->BootType
|
|
);
|
|
} else {
|
|
InitMXMSupport (
|
|
PcdGetPtr (PcdHgModeMxmBinaryGuid),
|
|
&(HgDxeInfoData->DgpuMxmBinFile.Address),
|
|
&(HgDxeInfoData->DgpuMxmBinFile.Size),
|
|
HgInfoDataHob->BootType
|
|
);
|
|
}
|
|
}
|
|
if ((HgDxeInfoData->Dgpu2GpioSupport) && (HgDxeInfoData->Dgpu2VendorId == NVIDIA_VID)) {
|
|
InitMXMSupport (
|
|
PcdGetPtr (PcdPegModeSlaveMxmBinaryGuid),
|
|
&(HgDxeInfoData->Dgpu2MxmBinFile.Address),
|
|
&(HgDxeInfoData->Dgpu2MxmBinFile.Size),
|
|
HgInfoDataHob->BootType
|
|
);
|
|
}
|
|
//
|
|
// Locate HG NVS Protocol and update PEG Vendor ID.
|
|
//
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiHgNvsAreaProtocolGuid,
|
|
NULL,
|
|
(VOID **)&HGNvsArea
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
if (HgInfoDataHob->HgMode == HgModeMuxless || HgInfoDataHob->HgMode == HgModeDgpu) {
|
|
if (HgDxeInfoData->DgpuVendorId == NVIDIA_VID) {
|
|
//
|
|
// Decide Nvidia dGPU generation dynamically.
|
|
// CRB will adopt NV_GEN_18 as default.
|
|
// Project should fill PcdHgNvidiaDgpuCheckTable to decide Nvidia dGPU generation.
|
|
//
|
|
if (PcdGetBool (PcdCrbBoard)) {
|
|
HgDxeInfoData->NvDgpuGen = NV_GEN_18;
|
|
HGNvsArea->NvDgpuGen = NV_GEN_18;
|
|
} else {
|
|
HgDxeInfoData->NvDgpuGen = NV_GEN_17;
|
|
HGNvsArea->NvDgpuGen = NV_GEN_17;
|
|
HgNvidiaDgpuCheckTable = (UINT16 *)PcdGetPtr (PcdHgNvidiaDgpuCheckTable);
|
|
Size = PcdGetSize (PcdHgNvidiaDgpuCheckTable) / sizeof (UINT16);
|
|
for (Index = 0; Index < Size; Index++) {
|
|
if (HgNvidiaDgpuCheckTable[Index] == HgDxeInfoData->DgpuDeviceId) {
|
|
HgDxeInfoData->NvDgpuGen = NV_GEN_18;
|
|
HGNvsArea->NvDgpuGen = NV_GEN_18;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// New PCD to decide Nvidia dGPU generation dynamically.
|
|
// Please set corresponding dGPU DID and generation info in PcdHgNvidiaDgpuCheckTable2.
|
|
//
|
|
HgNvidiaDgpuInfo = (NV_DGPU_INFO *)PcdGetPtr (PcdHgNvidiaDgpuCheckTable2);
|
|
Size = PcdGetSize (PcdHgNvidiaDgpuCheckTable2) / sizeof (NV_DGPU_INFO);
|
|
for (Index = 0; Index < Size; Index++) {
|
|
if (HgNvidiaDgpuInfo[Index].NvGen == NV_GEN_20) {
|
|
if (HgNvidiaDgpuInfo[Index].NvDid == HgDxeInfoData->DgpuDeviceId) {
|
|
HgDxeInfoData->NvDgpuGen = NV_GEN_20;
|
|
HGNvsArea->NvDgpuGen = NV_GEN_20;
|
|
break;
|
|
}
|
|
} else if (HgNvidiaDgpuInfo[Index].NvGen == NV_GEN_18) {
|
|
if (HgNvidiaDgpuInfo[Index].NvDid == HgDxeInfoData->DgpuDeviceId) {
|
|
HgDxeInfoData->NvDgpuGen = NV_GEN_18;
|
|
HGNvsArea->NvDgpuGen = NV_GEN_18;
|
|
break;
|
|
}
|
|
} else if (HgNvidiaDgpuInfo[Index].NvGen == NV_GEN_17) {
|
|
if (HgNvidiaDgpuInfo[Index].NvDid == HgDxeInfoData->DgpuDeviceId) {
|
|
HgDxeInfoData->NvDgpuGen = NV_GEN_17;
|
|
HGNvsArea->NvDgpuGen = NV_GEN_17;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (FeaturePcdGet (PcdHgNvidiaDdsFeatureSupport)) {
|
|
CHIPSET_CONFIGURATION ChipsetConfiguration;
|
|
//
|
|
// Update DisplayMode setting into Global NVS.
|
|
//
|
|
Size = sizeof (CHIPSET_CONFIGURATION);
|
|
Status = gRT->GetVariable (
|
|
SETUP_VARIABLE_NAME,
|
|
&gSystemConfigurationGuid,
|
|
NULL,
|
|
&Size,
|
|
&ChipsetConfiguration
|
|
);
|
|
HGNvsArea->DisplayMode = ChipsetConfiguration.DisplayMode;
|
|
}
|
|
|
|
//
|
|
// If NVIDIA HG variable doesn't exist, set the default value.
|
|
//
|
|
GetVariable2 (L"HybridGraphicsVariable", &gH2OHybridGraphicsVariableGuid, &HgVariableData, NULL);
|
|
if (HgVariableData == NULL) {
|
|
HgVariableData = AllocateZeroPool (sizeof (HG_VARIABLE_CONFIGURATION));
|
|
if (HgVariableData == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
HgVariableData->OptimusVariable.OptimusFlag = Inactive;
|
|
HgVariableData->OptimusVariable.DgpuBus = HgDxeInfoData->DgpuBus;
|
|
HgVariableData->OptimusVariable.Dgpu2Bus = HgDxeInfoData->Dgpu2Bus;
|
|
HgVariableData->OptimusVariable.NvDgpuGen = HgDxeInfoData->NvDgpuGen;
|
|
Status = gRT->SetVariable (
|
|
L"HybridGraphicsVariable",
|
|
&gH2OHybridGraphicsVariableGuid,
|
|
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
sizeof (HG_VARIABLE_CONFIGURATION),
|
|
HgVariableData
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
FreePool (HgVariableData);
|
|
return Status;
|
|
}
|
|
}
|
|
HgDxeInfoData->OptimusFlag = HgVariableData->OptimusVariable.OptimusFlag;
|
|
Status = EfiCreateEventReadyToBootEx (
|
|
TPL_CALLBACK,
|
|
ControlNvidiaDgpuHdAudio,
|
|
HgDxeInfoData,
|
|
&ReadyToBootEvent
|
|
);
|
|
FreePool (HgVariableData);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
Get MXM (Mobile PCI Express Module) SIS (System Information Structure) binary from firmware volume,
|
|
legacy boot allocate 0xE0000 legacy memory region and copy MXM SIS binary into this region
|
|
for MXM INT 15 callback function to get this binary,
|
|
EFI boot just get the MXM SIS binary firmware volume address.
|
|
|
|
@param[in] MxmBinaryGuid MXM SIS binary GUID for search MXM SIS binary from irmware volume.
|
|
@param[in, out] Address EFI boot firmware volume MXM SIS binary address
|
|
or legacy boot allocated 0xE0000 legacy region MXM SIS binary address.
|
|
@param[in, out] Size MXM SIS binary size.
|
|
@param[in] BootType SCU Boot Type setting.
|
|
|
|
@retval EFI_SUCCESS Get MXM SIS binary successfully.
|
|
@retval !EFI_SUCCESS Get MXM SIS binary failed.
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
InitMXMSupport (
|
|
IN EFI_GUID *MxmBinaryGuid,
|
|
IN OUT UINTN *Address,
|
|
IN OUT UINTN *Size,
|
|
IN UINT8 BootType
|
|
)
|
|
{
|
|
EFI_COMPATIBILITY16_TABLE *EfiTable;
|
|
EFI_IA32_REGISTER_SET Regs;
|
|
EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
|
|
EFI_LEGACY_REGION2_PROTOCOL *LegacyRegion;
|
|
EFI_STATUS Status;
|
|
UINT8 *Ptr;
|
|
UINTN *BuffPtr;
|
|
UINTN BufferSize;
|
|
UINTN TablePtr;
|
|
|
|
EfiTable = NULL;
|
|
BuffPtr = NULL;
|
|
(*Address) = 0;
|
|
(*Size) = 0;
|
|
|
|
//
|
|
// Locate MXM Binary
|
|
//
|
|
Status = GetSectionFromAnyFv (MxmBinaryGuid, EFI_SECTION_RAW, 0, &BuffPtr, &BufferSize);
|
|
if (EFI_ERROR (Status) || BufferSize == 0) {
|
|
return Status;
|
|
}
|
|
if (BootType == EfiBootType) {
|
|
(*Address) = (UINTN)(VOID *)BuffPtr;
|
|
(*Size) = BufferSize;
|
|
}
|
|
|
|
//
|
|
// Locate Legacy Bios and Legacy Region Protocol.
|
|
//
|
|
Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **)&LegacyBios);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
Status = gBS->LocateProtocol (&gEfiLegacyRegion2ProtocolGuid, NULL, (VOID **)&LegacyRegion);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Get EFI table from F segment.
|
|
//
|
|
for (Ptr = (UINT8 *)((UINTN)0xFE000); Ptr < (UINT8 *) ((UINTN) 0x100000); Ptr = (UINT8 *) ((UINTN) Ptr + 0x10)) {
|
|
if (*(UINT32 *) Ptr == SIGNATURE_32 ('I', 'F', 'E', '$')) {
|
|
EfiTable = (EFI_COMPATIBILITY16_TABLE *)Ptr;
|
|
break;
|
|
}
|
|
}
|
|
if (EfiTable == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
Status = LegacyRegion->UnLock (LegacyRegion, 0xE0000, 0x20000, NULL);
|
|
//
|
|
// To find the required size of availabe free memory
|
|
//
|
|
ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
|
|
Regs.X.AX = Legacy16GetTableAddress;
|
|
Regs.X.BX = 0x02; // E0000Region
|
|
Regs.X.CX = (UINT16)BufferSize;
|
|
Regs.X.DX = 1;
|
|
Status = LegacyBios->FarCall86 (
|
|
LegacyBios,
|
|
EfiTable->Compatibility16CallSegment,
|
|
EfiTable->Compatibility16CallOffset,
|
|
&Regs,
|
|
NULL,
|
|
0
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// To copy the image to legacy memory
|
|
//
|
|
TablePtr = (UINT32) ((Regs.X.DS << 4) + Regs.X.BX);
|
|
CopyMem ((VOID *)TablePtr, (VOID *)BuffPtr, BufferSize);
|
|
(*Address) = TablePtr;
|
|
(*Size) = BufferSize;
|
|
Status = LegacyRegion->Lock (LegacyRegion, 0xE0000, 0x20000, NULL);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
Enable or disable dGPU HD Audio device during normal boot or S4 resume.
|
|
|
|
@param[in] Event The Event this notify function registered to.
|
|
@param[in] Context Pointer to the context data registerd to the Event.
|
|
|
|
@retval EFI_SUCCESS Set secondary Graphics command register successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ControlNvidiaDgpuHdAudio (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_BOOT_MODE BootMode;
|
|
EFI_PEI_HOB_POINTERS Hob;
|
|
EFI_STATUS Status;
|
|
HG_DXE_INFORMATION_DATA *HgDxeInfoData;
|
|
UINTN PciAddress;
|
|
VOID *HobList;
|
|
|
|
HgDxeInfoData = (HG_DXE_INFORMATION_DATA *)Context;
|
|
if (HgDxeInfoData == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Status = EfiGetSystemConfigurationTable (&gEfiHobListGuid, &HobList);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
Hob.Raw = HobList;
|
|
if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_HANDOFF) {
|
|
return Status;
|
|
}
|
|
BootMode = Hob.HandoffInformationTable->BootMode;
|
|
|
|
PciAddress = PCI_EXPRESS_LIB_ADDRESS (
|
|
HgDxeInfoData->DgpuBus,
|
|
DGPU_DEVICE_NUM,
|
|
DGPU_FUNCTION_NUM,
|
|
NVIDIA_DGPU_HDA_REGISTER
|
|
);
|
|
|
|
if ((BootMode != BOOT_ON_S3_RESUME) && (BootMode != BOOT_ON_S4_RESUME)) {
|
|
if (HgDxeInfoData->NvDgpuGen == NV_GEN_17) {
|
|
//
|
|
// N17: Disable dGPU HDA during normal boot.
|
|
//
|
|
PciExpressAnd32 (PciAddress, (UINT32)~(BIT25));
|
|
} else {
|
|
//
|
|
// N18: Enable dGPU HDA during normal boot.
|
|
//
|
|
PciExpressOr32 (PciAddress, (UINT32)BIT25);
|
|
}
|
|
}
|
|
|
|
if (BootMode == BOOT_ON_S4_RESUME) {
|
|
if (HgDxeInfoData->NvDgpuGen == NV_GEN_17) {
|
|
//
|
|
// Sync the value of OptimusFlag to global NVS during S4 resume.
|
|
//
|
|
((EFI_HG_NVS_AREA_PROTOCOL *)(HgDxeInfoData->HgOpRegionAddress))->OptimusFlag = HgDxeInfoData->OptimusFlag;
|
|
|
|
//
|
|
// N17: Based on the value of OptimusFlag to enable or disable dGPU HDA during S4 resume.
|
|
//
|
|
if (((HgDxeInfoData->OptimusFlag) & BIT0) == Inactive) {
|
|
PciExpressAnd32 (PciAddress, (UINT32)~(BIT25));
|
|
} else {
|
|
PciExpressOr32 (PciAddress, (UINT32)BIT25);
|
|
}
|
|
} else {
|
|
//
|
|
// N18: Enable dGPU HDA during S4 resume.
|
|
//
|
|
PciExpressOr32 (PciAddress, (UINT32)BIT25);
|
|
}
|
|
}
|
|
|
|
gBS->CloseEvent (Event);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
Search discrete graphics VBIOS location and save into HG information data.
|
|
|
|
@param[in, out] HgDxeInfoData A pointer of HG DXE information data structure,
|
|
this driver or HG Operation Region will use these data.
|
|
|
|
@retval EFI_SUCCESS Search discrete graphics VBIOS successfully.
|
|
@retval !EFI_SUCCESS Search discrete graphics VBIOS failed.
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
SearchDiscreteGraphicsVbios (
|
|
IN OUT HG_DXE_INFORMATION_DATA *HgDxeInfoData
|
|
)
|
|
{
|
|
EFI_HANDLE *HandleBuffer;
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
EFI_STATUS Status;
|
|
PCI_3_0_DATA_STRUCTURE *PcirBlockPtr;
|
|
PCI_EXPANSION_ROM_HEADER *VBiosRomImage;
|
|
UINTN HandleCount;
|
|
UINTN Index;
|
|
|
|
//
|
|
// Get all PCI IO protocols
|
|
//
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiPciIoProtocolGuid,
|
|
NULL,
|
|
&HandleCount,
|
|
&HandleBuffer
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Find the video BIOS by checking each PCI IO handle for DGPU video
|
|
// BIOS OPROM.
|
|
//
|
|
for (Index = 0; Index < HandleCount; Index++) {
|
|
Status = gBS->HandleProtocol (
|
|
HandleBuffer[Index],
|
|
&gEfiPciIoProtocolGuid,
|
|
(VOID**)&PciIo
|
|
);
|
|
if (EFI_ERROR (Status) || (PciIo->RomImage == NULL)) {
|
|
//
|
|
// If this PCI device doesn't have a ROM image, skip to the next device.
|
|
//
|
|
continue;
|
|
}
|
|
VBiosRomImage = PciIo->RomImage;
|
|
|
|
//
|
|
// Get pointer to PCIR structure
|
|
//
|
|
PcirBlockPtr = (PCI_3_0_DATA_STRUCTURE *)((UINTN)VBiosRomImage + VBiosRomImage->PcirOffset);
|
|
|
|
//
|
|
// Check if we have an video BIOS OPROM for DGPU.
|
|
//
|
|
if ((VBiosRomImage->Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE) &&
|
|
(HgDxeInfoData->DgpuVendorId == PcirBlockPtr->VendorId) &&
|
|
(PcirBlockPtr->ClassCode[2] == PCI_CLASS_DISPLAY)) {
|
|
HgDxeInfoData->Vbios.Address = (UINTN)PciIo->RomImage;
|
|
HgDxeInfoData->Vbios.Size = (UINT32)PciIo->RomSize;
|
|
if (HgDxeInfoData->Vbios.Size > sizeof (OPERATION_REGION_VBIOS)) {
|
|
DEBUG((DEBUG_ERROR, "\nASSERT! Size too small:"));
|
|
ASSERT(FALSE);
|
|
}
|
|
FreePool (HandleBuffer);
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
FreePool (HandleBuffer);
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
|
|
Execute discrete graphics VBIOS for ATI graphics initialize.
|
|
|
|
@param[in, out] HgDxeInfoData A pointer of HG DXE information data structure,
|
|
this driver or HG Operation Region will use these data.
|
|
@param[in] HgInfoDataHob A pointer of HG information data HOB,
|
|
HG PEI Module created this HOB, and passes the data from PEI phase.
|
|
|
|
@retval EFI_SUCCESS Execute discrete graphics VBIOS successfully.
|
|
@retval !EFI_SUCCESS Execute discrete graphics VBIOS failed.
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
ExecuteDiscreteGraphicsVbios (
|
|
IN OUT HG_DXE_INFORMATION_DATA *HgDxeInfoData,
|
|
IN HG_INFORMATION_DATA_HOB *HgInfoDataHob
|
|
)
|
|
{
|
|
EFI_IA32_REGISTER_SET RegSet;
|
|
EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
|
|
EFI_PHYSICAL_ADDRESS ImageLocation;
|
|
EFI_STATUS Status;
|
|
UINTN Offset;
|
|
UINTN PegBridgeCmdRegAddr;
|
|
UINTN PegDeviceCmdRegAddr;
|
|
UINTN VbiosPages;
|
|
VOID *VbiosAddress;
|
|
|
|
//
|
|
// Memory IO Bus Master needs to be enabled when we execute the VBIOS.
|
|
//
|
|
PegBridgeCmdRegAddr = PCI_EXPRESS_LIB_ADDRESS (
|
|
(UINTN)HgDxeInfoData->DgpuBridgeBus,
|
|
(UINTN)HgDxeInfoData->DgpuBridgeDevice,
|
|
(UINTN)HgDxeInfoData->DgpuBridgeFunction,
|
|
PCI_CMD
|
|
);
|
|
PegDeviceCmdRegAddr = PCI_EXPRESS_LIB_ADDRESS (
|
|
HgDxeInfoData->DgpuBus,
|
|
DGPU_DEVICE_NUM,
|
|
DGPU_FUNCTION_NUM,
|
|
PCI_CMD
|
|
);
|
|
//
|
|
// Enable Memory Access, IO Access Bus Master enable on PEG root port and PEG device.
|
|
//
|
|
PciExpressOr16 (PegBridgeCmdRegAddr, BIT0 + BIT1 + BIT2);
|
|
PciExpressOr16 (PegDeviceCmdRegAddr, BIT0 + BIT1 + BIT2);
|
|
//
|
|
// Allocate under 1MB memory region (less than 640 KB).
|
|
//
|
|
VbiosPages = ((HgDxeInfoData->Vbios.Size) / 0x1000) + 1;
|
|
ImageLocation = (EFI_PHYSICAL_ADDRESS)(UINTN)0xA0000;
|
|
Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesCode, VbiosPages, &ImageLocation);
|
|
if (!EFI_ERROR (Status)) {
|
|
ZeroMem ((VOID *)(UINTN)ImageLocation, (VbiosPages * 4096));
|
|
//
|
|
// After allocation copy VBIOS to buffer
|
|
//
|
|
CopyMem ((VOID *)(UINTN)ImageLocation, (VOID *)HgDxeInfoData->Vbios.Address, HgDxeInfoData->Vbios.Size);
|
|
Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **)&LegacyBios);
|
|
if (!EFI_ERROR (Status)) {
|
|
ZeroMem (&RegSet, sizeof (EFI_IA32_REGISTER_SET));
|
|
RegSet.H.AH = HgDxeInfoData->DgpuBus;
|
|
Offset = MemoryRead16 ((UINTN)ImageLocation + 0x40);
|
|
LegacyBios->FarCall86 (
|
|
LegacyBios,
|
|
((UINT16)(RShiftU64 ((ImageLocation & 0x000FFFF0), 4))),
|
|
((UINT16)Offset),
|
|
&RegSet,
|
|
NULL,
|
|
0
|
|
);
|
|
Offset = (MemoryRead16 ((UINTN)ImageLocation + 0x42)) + (UINTN)ImageLocation;
|
|
if (MemoryRead16 ((UINTN)ImageLocation + 0x44) == 0x0) {
|
|
HgDxeInfoData->Vbios.Size = (MemoryRead8 ((UINTN)ImageLocation + 0x2)) * 512;
|
|
} else {
|
|
HgDxeInfoData->Vbios.Size = (MemoryRead16 ((UINTN)ImageLocation + 0x44)) * 512;
|
|
}
|
|
//
|
|
// Copy Oprom to allocated space
|
|
//
|
|
VbiosAddress = AllocateZeroPool (HgDxeInfoData->Vbios.Size);
|
|
if (VbiosAddress == NULL) {
|
|
FreePages ((VOID *)(UINTN)ImageLocation, VbiosPages);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
CopyMem (VbiosAddress, (VOID *)Offset, HgDxeInfoData->Vbios.Size);
|
|
HgDxeInfoData->Vbios.Address = (UINTN)VbiosAddress;
|
|
ZeroMem ((VOID *)(UINTN)ImageLocation, HgDxeInfoData->Vbios.Size);
|
|
}
|
|
FreePages ((VOID *)(UINTN)ImageLocation, VbiosPages);
|
|
}
|
|
//
|
|
// Disable Memory Access, IO Access Bus Master enable on PEG device and PEG root port.
|
|
//
|
|
PciExpressAnd16 (PegDeviceCmdRegAddr, BIT0 + BIT1 + BIT2);
|
|
PciExpressAnd16 (PegBridgeCmdRegAddr, BIT0 + BIT1 + BIT2);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
Load Hybrid Graphics own SSDT (Secondary System Description Table) and initialize
|
|
Hybrid Graphics own operation region for ASL (ACPI Source Language) code usage.
|
|
|
|
@param[in] HgDxeInfoData A pointer of HG DXE information data structure,
|
|
this driver or HG Operation Region will use these data.
|
|
@param[in] HgInfoDataHob A pointer of HG information data HOB,
|
|
HG PEI Module created this HOB, and passes the data from PEI phase.
|
|
|
|
@retval EFI_SUCCESS Load and set Hybrid Graphics SSDT successfully.
|
|
@retval !EFI_SUCCESS Load or set Hybrid Graphics SSDT failed.
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
SetHybridGraphicsSsdt (
|
|
IN HG_DXE_INFORMATION_DATA *HgDxeInfoData,
|
|
IN HG_INFORMATION_DATA_HOB *HgInfoDataHob
|
|
)
|
|
{
|
|
EFI_ACPI_COMMON_HEADER *CurrentTable;
|
|
EFI_ACPI_DESCRIPTION_HEADER *TempTable;
|
|
EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
|
|
EFI_FIRMWARE_VOLUME2_PROTOCOL *FirmwareVolume;
|
|
EFI_FV_FILE_ATTRIBUTES Attributes;
|
|
EFI_FV_FILETYPE FileType;
|
|
EFI_GUID *SsdtFileGuid;
|
|
EFI_HANDLE *HandleBuffer;
|
|
EFI_STATUS Status;
|
|
UINT32 FvStatus;
|
|
UINTN TableKey;
|
|
UINTN Index;
|
|
UINTN NumberOfHandles;
|
|
UINTN Size;
|
|
CHIPSET_CONFIGURATION ChipsetConfiguration;
|
|
|
|
CurrentTable = NULL;
|
|
FirmwareVolume = NULL;
|
|
SsdtFileGuid = NULL;
|
|
TempTable = NULL;
|
|
|
|
|
|
Size = sizeof (CHIPSET_CONFIGURATION);
|
|
Status = gRT->GetVariable (
|
|
SETUP_VARIABLE_NAME,
|
|
&gSystemConfigurationGuid,
|
|
NULL,
|
|
&Size,
|
|
&ChipsetConfiguration
|
|
);
|
|
|
|
//
|
|
// Choose SSDT table:
|
|
// Nvidia -> Based on HgMode (HgModeDgpu or HgModeMuxless), PCH type (H/S or U/Y) and dGPU generation (N17/N18/...).
|
|
// AMD -> Based on HgMode (HgModeDgpu or HgModeMuxless) and PCH type (H/S or U/Y).
|
|
//
|
|
if ((FeaturePcdGet (PcdNvidiaOptimusSupported)) && (HgDxeInfoData->DgpuVendorId == NVIDIA_VID)) {
|
|
if (HgInfoDataHob->HgMode == HgModeDgpu) {
|
|
if (ChipsetConfiguration.HgSlot == PCH) {
|
|
switch (HgDxeInfoData->NvDgpuGen) {
|
|
case NV_GEN_17:
|
|
SsdtFileGuid = PcdGetPtr (PcdNvidiaUltDiscreteSsdtN17Guid);
|
|
break;
|
|
case NV_GEN_18:
|
|
SsdtFileGuid = PcdGetPtr (PcdNvidiaUltDiscreteSsdtN18Guid);
|
|
break;
|
|
case NV_GEN_20:
|
|
SsdtFileGuid = PcdGetPtr (PcdNvidiaUltDiscreteSsdtN20Guid);
|
|
break;
|
|
}
|
|
} else {
|
|
switch (HgDxeInfoData->NvDgpuGen) {
|
|
case NV_GEN_17:
|
|
SsdtFileGuid = PcdGetPtr (PcdNvidiaDiscreteSsdtN17Guid);
|
|
break;
|
|
case NV_GEN_18:
|
|
SsdtFileGuid = PcdGetPtr (PcdNvidiaDiscreteSsdtN18Guid);
|
|
break;
|
|
case NV_GEN_20:
|
|
SsdtFileGuid = PcdGetPtr (PcdNvidiaDiscreteSsdtN20Guid);
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
if (ChipsetConfiguration.HgSlot == PCH) {
|
|
switch (HgDxeInfoData->NvDgpuGen) {
|
|
case NV_GEN_17:
|
|
SsdtFileGuid = PcdGetPtr (PcdNvidiaUltOptimusSsdtN17Guid);
|
|
break;
|
|
case NV_GEN_18:
|
|
SsdtFileGuid = PcdGetPtr (PcdNvidiaUltOptimusSsdtN18Guid);
|
|
break;
|
|
case NV_GEN_20:
|
|
SsdtFileGuid = PcdGetPtr (PcdNvidiaUltOptimusSsdtN20Guid);
|
|
break;
|
|
}
|
|
} else {
|
|
switch (HgDxeInfoData->NvDgpuGen) {
|
|
case NV_GEN_17:
|
|
SsdtFileGuid = PcdGetPtr (PcdNvidiaOptimusSsdtN17Guid);
|
|
break;
|
|
case NV_GEN_18:
|
|
SsdtFileGuid = PcdGetPtr (PcdNvidiaOptimusSsdtN18Guid);
|
|
break;
|
|
case NV_GEN_20:
|
|
SsdtFileGuid = PcdGetPtr (PcdNvidiaOptimusSsdtN20Guid);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ((FeaturePcdGet (PcdAmdPowerXpressSupported)) && (HgDxeInfoData->DgpuVendorId == AMD_VID)) {
|
|
if (HgInfoDataHob->HgMode == HgModeDgpu) {
|
|
SsdtFileGuid = PcdGetPtr (PcdAmdDiscreteSsdtGuid);
|
|
} else {
|
|
if (ChipsetConfiguration.HgSlot == PCH) {
|
|
SsdtFileGuid = PcdGetPtr (PcdAmdUltPowerXpressSsdtGuid);
|
|
} else {
|
|
SsdtFileGuid = PcdGetPtr (PcdAmdPowerXpressSsdtGuid);
|
|
}
|
|
}
|
|
}
|
|
if (SsdtFileGuid == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **)&AcpiTable);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiFirmwareVolume2ProtocolGuid,
|
|
NULL,
|
|
&NumberOfHandles,
|
|
&HandleBuffer
|
|
);
|
|
if (EFI_ERROR (Status) || (NumberOfHandles == 0)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Looking for FV with ACPI storage file
|
|
//
|
|
for (Index = 0; Index < NumberOfHandles; Index++) {
|
|
Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiFirmwareVolume2ProtocolGuid, (VOID**)&FirmwareVolume);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
FvStatus = 0;
|
|
Size = 0;
|
|
Status = FirmwareVolume->ReadFile (
|
|
FirmwareVolume,
|
|
SsdtFileGuid,
|
|
NULL,
|
|
&Size,
|
|
&FileType,
|
|
&Attributes,
|
|
&FvStatus
|
|
);
|
|
if (Status == EFI_SUCCESS) {
|
|
break;
|
|
}
|
|
}
|
|
FreePool (HandleBuffer);
|
|
ASSERT (FirmwareVolume != NULL);
|
|
if (EFI_ERROR (Status) || FirmwareVolume == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Read tables from the storage file.
|
|
//
|
|
TableKey = 0;
|
|
Status = FirmwareVolume->ReadSection (
|
|
FirmwareVolume,
|
|
SsdtFileGuid,
|
|
EFI_SECTION_RAW,
|
|
0,
|
|
(VOID**)&CurrentTable,
|
|
&Size,
|
|
&FvStatus
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
TempTable = AllocateZeroPool (CurrentTable->Length);
|
|
ASSERT (TempTable != NULL);
|
|
if (TempTable != NULL) {
|
|
CopyMem (TempTable, CurrentTable, CurrentTable->Length);
|
|
Status = InitializeOpRegion ((EFI_ACPI_DESCRIPTION_HEADER*)TempTable, HgDxeInfoData, HgInfoDataHob);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = AcpiTable->InstallAcpiTable (AcpiTable, TempTable, CurrentTable->Length, &TableKey);
|
|
}
|
|
FreePool (CurrentTable);
|
|
FreePool (TempTable);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
Initialize Hybrid Graphics own operation region for ASL (ACPI Source Language) code usage.
|
|
|
|
@param[in] NvStoreTable A pointer of temporary HG SSDT that prepares modified and installed.
|
|
@param[in] HgDxeInfoData A pointer of HG DXE information data structure,
|
|
this driver or HG Operation Region will use these data.
|
|
@param[in] HgInfoDataHob A pointer of HG information data HOB,
|
|
HG PEI Module created this HOB, and passes the data from PEI phase.
|
|
|
|
@retval EFI_SUCCESS Load Hybrid Graphics SSDT successfully.
|
|
@retval !EFI_SUCCESS Load Hybrid Graphics SSDT failed.
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
InitializeOpRegion (
|
|
IN EFI_ACPI_DESCRIPTION_HEADER *NvStoreTable,
|
|
IN HG_DXE_INFORMATION_DATA *HgDxeInfoData,
|
|
IN HG_INFORMATION_DATA_HOB *HgInfoDataHob
|
|
)
|
|
{
|
|
EFI_ACPI_DESCRIPTION_HEADER *Table;
|
|
EFI_STATUS Status;
|
|
OPERATION_REGION_AMD *AmdOpRegion;
|
|
OPERATION_REGION_NVIDIA *NvidiaOpRegion;
|
|
EFI_HG_NVS_AREA_PROTOCOL *HGNvsArea;
|
|
OPERATION_REGION_VBIOS *VbiosOpRegion;
|
|
UINT8 *SsdtPointer;
|
|
UINT32 *Signature;
|
|
|
|
Table = NvStoreTable;
|
|
for (SsdtPointer = (UINT8 *)((UINTN)Table + sizeof (EFI_ACPI_DESCRIPTION_HEADER)); \
|
|
SsdtPointer <= (UINT8 *)((UINTN)Table + (UINTN)(Table->Length)); SsdtPointer++) {
|
|
Signature = (UINT32*)SsdtPointer;
|
|
switch (*Signature) {
|
|
case (SIGNATURE_32 ('H', 'G', 'O', 'P')): // HG operation region initialize
|
|
if (IsAmlOpRegionObject (SsdtPointer)) {
|
|
Status = gBS->LocateProtocol(&gEfiHgNvsAreaProtocolGuid, NULL, (VOID **)&HGNvsArea);
|
|
if (!EFI_ERROR (Status)) {
|
|
UpdateHgOpRegion (HGNvsArea, HgDxeInfoData, HgInfoDataHob);
|
|
SetOpRegion (SsdtPointer, HGNvsArea, sizeof (EFI_HG_NVS_AREA_PROTOCOL));
|
|
}
|
|
}
|
|
break;
|
|
case (SIGNATURE_32 ('V', 'B', 'O', 'R')): // VBIOS operation region initialize
|
|
if (IsAmlOpRegionObject (SsdtPointer)) {
|
|
Status = gBS->AllocatePool (EfiACPIMemoryNVS, sizeof (OPERATION_REGION_VBIOS), (VOID **)&VbiosOpRegion);
|
|
if (!EFI_ERROR (Status)) {
|
|
ZeroMem (VbiosOpRegion, sizeof (OPERATION_REGION_VBIOS));
|
|
VbiosOpRegion->RVBS = (UINT32)HgDxeInfoData->Vbios.Size;
|
|
CopyMem (
|
|
(VOID *)(VbiosOpRegion->VBOIS),
|
|
(VOID *)(HgDxeInfoData->Vbios.Address),
|
|
HgDxeInfoData->Vbios.Size
|
|
);
|
|
HgDxeInfoData->Vbios.Address = (UINTN)(VbiosOpRegion->VBOIS);
|
|
SetOpRegion (SsdtPointer, VbiosOpRegion, sizeof (OPERATION_REGION_VBIOS));
|
|
}
|
|
}
|
|
break;
|
|
case (SIGNATURE_32 ('A', 'O', 'P', 'R')): // AMD operation region initialize
|
|
if ((FeaturePcdGet (PcdAmdPowerXpressSupported)) && IsAmlOpRegionObject (SsdtPointer)) {
|
|
Status = gBS->AllocatePool (EfiACPIMemoryNVS, sizeof (OPERATION_REGION_AMD), (VOID **)&AmdOpRegion);
|
|
if (!EFI_ERROR (Status)) {
|
|
ZeroMem (AmdOpRegion, sizeof (OPERATION_REGION_AMD));
|
|
UpdateAmdOpRegion (AmdOpRegion, HgDxeInfoData, HgInfoDataHob);
|
|
SetOpRegion (SsdtPointer, AmdOpRegion, sizeof (OPERATION_REGION_AMD));
|
|
}
|
|
}
|
|
SsdtPointer = (UINT8 *)((UINTN)Table + (UINTN)(Table->Length));
|
|
break;
|
|
case (SIGNATURE_32 ('N', 'O', 'P', 'R')): // nVIDIA operation region initialize
|
|
if ((FeaturePcdGet (PcdNvidiaOptimusSupported)) && IsAmlOpRegionObject (SsdtPointer)) {
|
|
Status = gBS->AllocatePool (EfiACPIMemoryNVS, sizeof (OPERATION_REGION_NVIDIA), (VOID **)&NvidiaOpRegion);
|
|
if (!EFI_ERROR (Status)) {
|
|
ZeroMem (NvidiaOpRegion, sizeof (OPERATION_REGION_NVIDIA));
|
|
UpdateNvidiaOpRegion (NvidiaOpRegion, HgDxeInfoData, HgInfoDataHob);
|
|
SetOpRegion (SsdtPointer, NvidiaOpRegion, sizeof (OPERATION_REGION_NVIDIA));
|
|
}
|
|
}
|
|
SsdtPointer = (UINT8 *)((UINTN)Table + (UINTN)(Table->Length));
|
|
break;
|
|
}
|
|
Status = AcpiChecksum (Table, Table->Length, ((UINTN)(&(((EFI_ACPI_DESCRIPTION_HEADER *)0)->Checksum))));
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
Update Hybrid Graphics own operation region for ASL (ACPI Source Language) code usage.
|
|
|
|
@param[in] HgOpRegion A pointer of HG own operation region.
|
|
@param[in] HgDxeInfoData A pointer of HG DXE information data structure,
|
|
this driver or HG Operation Region will use these data.
|
|
@param[in] HgInfoDataHob A pointer of HG information data HOB,
|
|
HG PEI Module created this HOB, and passes the data from PEI phase.
|
|
|
|
@retval None.
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
UpdateHgOpRegion (
|
|
IN OUT EFI_HG_NVS_AREA_PROTOCOL *HgOpRegion,
|
|
IN HG_DXE_INFORMATION_DATA *HgDxeInfoData,
|
|
IN HG_INFORMATION_DATA_HOB *HgInfoDataHob
|
|
)
|
|
{
|
|
UINTN PciAddress;
|
|
UINTN Size;
|
|
CHIPSET_CONFIGURATION ChipsetConfiguration;
|
|
EFI_STATUS Status;
|
|
|
|
PciAddress = PCI_EXPRESS_LIB_ADDRESS (
|
|
(UINTN)HgDxeInfoData->DgpuBridgeBus,
|
|
(UINTN)HgDxeInfoData->DgpuBridgeDevice,
|
|
(UINTN)HgDxeInfoData->DgpuBridgeFunction,
|
|
0x0
|
|
);
|
|
|
|
Size = sizeof (CHIPSET_CONFIGURATION);
|
|
Status = gRT->GetVariable (
|
|
SETUP_VARIABLE_NAME,
|
|
&gSystemConfigurationGuid,
|
|
NULL,
|
|
&Size,
|
|
&ChipsetConfiguration
|
|
);
|
|
|
|
HgOpRegion->DgpuPcieCfgBaseAddress = (UINT32)(PcdGet64 (PcdPciExpressBaseAddress) + PciAddress);
|
|
HgDxeInfoData->HgOpRegionAddress = HgOpRegion;
|
|
HgOpRegion->HgSlot = ChipsetConfiguration.HgSlot;
|
|
|
|
if (HgInfoDataHob->HgMode == HgModeMuxless || HgInfoDataHob->HgMode == HgModeDgpu) {
|
|
//
|
|
// PEG Endpoint Base Addresses and Capability Structure Offsets for ASL usage
|
|
//
|
|
PciAddress = PCI_EXPRESS_LIB_ADDRESS (
|
|
HgDxeInfoData->DgpuBus,
|
|
DGPU_DEVICE_NUM,
|
|
DGPU_FUNCTION_NUM,
|
|
0x0
|
|
);
|
|
HgOpRegion->EndpointBaseAddress = (UINT32)(PcdGet64 (PcdPciExpressBaseAddress) + PciAddress);
|
|
}
|
|
}
|
|
|
|
/**
|
|
|
|
Update AMD own operation region for ASL (ACPI Source Language) code usage.
|
|
|
|
@param[in] AmdOpRegion A pointer of AMD own operation region.
|
|
@param[in] HgDxeInfoData A pointer of HG DXE information data structure,
|
|
this driver or HG Operation Region will use these data.
|
|
@param[in] HgInfoDataHob A pointer of HG information data HOB,
|
|
HG PEI Module created this HOB, and passes the data from PEI phase.
|
|
|
|
@retval None.
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
UpdateAmdOpRegion (
|
|
IN OUT OPERATION_REGION_AMD *AmdOpRegion,
|
|
IN HG_DXE_INFORMATION_DATA *HgDxeInfoData,
|
|
IN HG_INFORMATION_DATA_HOB *HgInfoDataHob
|
|
)
|
|
{
|
|
if ((HgInfoDataHob->HgMode == HgModeMuxless) || (HgInfoDataHob->HgMode == HgModeDgpu)) {
|
|
AmdOpRegion->ExpansionMode = HgInfoDataHob->PannelScaling; // Expansion Mode
|
|
}
|
|
if (HgInfoDataHob->HgMode == HgModeDgpu) {
|
|
AmdOpRegion->SlaveDgpuSupport = Inactive;
|
|
if (HgInfoDataHob->Dgpu2GpioSupport) {
|
|
AmdOpRegion->SlaveDgpuSupport = Active;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
|
|
Update nVIDIA own operation region for ASL (ACPI Source Language) code usage.
|
|
|
|
@param[in] NvidiaOpRegion A pointer of nVIDIA own operation region.
|
|
@param[in] HgDxeInfoData A pointer of HG DXE information data structure,
|
|
this driver or HG Operation Region will use these data.
|
|
@param[in] HgInfoDataHob A pointer of HG information data HOB,
|
|
HG PEI Module created this HOB, and passes the data from PEI phase.
|
|
|
|
@retval None.
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
UpdateNvidiaOpRegion (
|
|
IN OUT OPERATION_REGION_NVIDIA *NvidiaOpRegion,
|
|
IN HG_DXE_INFORMATION_DATA *HgDxeInfoData,
|
|
IN HG_INFORMATION_DATA_HOB *HgInfoDataHob
|
|
)
|
|
{
|
|
if (HgInfoDataHob->HgMode == HgModeMuxless) {
|
|
NvidiaOpRegion->DgpuHotPlugSupport = PcdGetBool (PcdHgNvidiaOptimusDgpuHotPlugSupport);
|
|
NvidiaOpRegion->DgpuPowerControlSupport = PcdGetBool (PcdHgNvidiaOptimusDgpuPowerControlSupport);
|
|
NvidiaOpRegion->GpsFeatureSupport = PcdGetBool (PcdHgNvidiaGpsFeatureSupport);
|
|
NvidiaOpRegion->VenturaFeatureSupport = PcdGetBool (PcdHgNvidiaVenturaFeatureSupport);
|
|
NvidiaOpRegion->NbciFeatureSupport = PcdGetBool (PcdHgNvidiaNbciFeatureSupport);
|
|
NvidiaOpRegion->OptimusGc6Support = PcdGetBool (PcdHgNvidiaOptimusGc6FeatureSupport);
|
|
NvidiaOpRegion->OptimusGc6NvsrSupport = PcdGetBool (PcdHgNvidiaOptimusGc6NvsrFeatureSupport);
|
|
NvidiaOpRegion->NpcfFeatureSupport = PcdGetBool (PcdHgNvidiaNpcfFeatureSupport);
|
|
NvidiaOpRegion->SpbConfig = Active; // SpbConfig bit0: SPB 1: enable, 0: disable
|
|
NvidiaOpRegion->ExpansionMode = HgInfoDataHob->PannelScaling; // Expansion Mode
|
|
NvidiaOpRegion->MxmBinarySize = (UINT32)HgDxeInfoData->DgpuMxmBinFile.Size; // MXM bin file size (bits)
|
|
NvidiaOpRegion->Gc6FbEn = FixedPcdGet32 (PcdNvidiaGC6FBEN);
|
|
NvidiaOpRegion->Gc6Event = FixedPcdGet32 (PcdNvidiaGPUEvent);
|
|
NvidiaOpRegion->PowerGood = HgInfoDataHob->DgpuPwrOkGpioNo;
|
|
NvidiaOpRegion->DdsMuxModePin = FixedPcdGet32 (PcdNvidiaDDSMuxModePin);
|
|
NvidiaOpRegion->DdsLcdForceResetPin = FixedPcdGet32 (PcdNvidiaDDSLcdForceResetPin);
|
|
//
|
|
// Copy MXM bin file to OpRegion
|
|
//
|
|
CopyMem (
|
|
(VOID *)(NvidiaOpRegion->MxmBinaryBuffer),
|
|
(VOID *)(HgDxeInfoData->DgpuMxmBinFile.Address),
|
|
HgDxeInfoData->DgpuMxmBinFile.Size
|
|
);
|
|
}
|
|
if (HgInfoDataHob->HgMode == HgModeDgpu) {
|
|
NvidiaOpRegion->DgpuHotPlugSupport = PcdGetBool (PcdHgNvidiaOptimusDgpuHotPlugSupport);
|
|
NvidiaOpRegion->DgpuPowerControlSupport = PcdGetBool (PcdHgNvidiaOptimusDgpuPowerControlSupport);
|
|
NvidiaOpRegion->DgpuHotPlugSupport = PcdGetBool (PcdHgNvidiaOptimusDgpuHotPlugSupport);
|
|
NvidiaOpRegion->DgpuPowerControlSupport = PcdGetBool (PcdHgNvidiaOptimusDgpuPowerControlSupport);
|
|
NvidiaOpRegion->GpsFeatureSupport = PcdGetBool (PcdHgNvidiaGpsFeatureSupport);
|
|
NvidiaOpRegion->VenturaFeatureSupport = PcdGetBool (PcdHgNvidiaVenturaFeatureSupport);
|
|
NvidiaOpRegion->NbciFeatureSupport = PcdGetBool (PcdHgNvidiaNbciFeatureSupport);
|
|
NvidiaOpRegion->OptimusGc6Support = PcdGetBool (PcdHgNvidiaOptimusGc6FeatureSupport);
|
|
NvidiaOpRegion->OptimusGc6NvsrSupport = PcdGetBool (PcdHgNvidiaOptimusGc6NvsrFeatureSupport);
|
|
NvidiaOpRegion->NpcfFeatureSupport = PcdGetBool (PcdHgNvidiaNpcfFeatureSupport);
|
|
NvidiaOpRegion->SpbConfig = Active; // SpbConfig bit0: SPB 1: enable, 0: disable
|
|
NvidiaOpRegion->ExpansionMode = HgInfoDataHob->PannelScaling; // Expansion Mode
|
|
NvidiaOpRegion->SlaveDgpuSupport = Inactive;
|
|
if (HgInfoDataHob->Dgpu2GpioSupport) {
|
|
NvidiaOpRegion->SlaveDgpuSupport = Active;
|
|
}
|
|
NvidiaOpRegion->MxmBinarySize = (UINT32)HgDxeInfoData->DgpuMxmBinFile.Size; // MXM bin file size (bits)
|
|
NvidiaOpRegion->Gc6FbEn = FixedPcdGet32 (PcdNvidiaGC6FBEN);
|
|
NvidiaOpRegion->Gc6Event = FixedPcdGet32 (PcdNvidiaGPUEvent);
|
|
NvidiaOpRegion->PowerGood = HgInfoDataHob->DgpuPwrOkGpioNo;
|
|
NvidiaOpRegion->DdsMuxModePin = FixedPcdGet32 (PcdNvidiaDDSMuxModePin);
|
|
NvidiaOpRegion->DdsLcdForceResetPin = FixedPcdGet32 (PcdNvidiaDDSLcdForceResetPin);
|
|
//
|
|
// Copy MXM bin file to OpRegion
|
|
//
|
|
CopyMem (
|
|
(VOID *)(NvidiaOpRegion->MxmBinaryBuffer),
|
|
(VOID *)(HgDxeInfoData->DgpuMxmBinFile.Address),
|
|
HgDxeInfoData->DgpuMxmBinFile.Size
|
|
);
|
|
NvidiaOpRegion->SlaveMxmBinarySize = (UINT32)HgDxeInfoData->Dgpu2MxmBinFile.Size;
|
|
//
|
|
// Copy Slave MXM bin file to OpRegion
|
|
//
|
|
CopyMem (
|
|
(VOID *)(NvidiaOpRegion->SlaveMxmBinaryBuffer),
|
|
(VOID *)(HgDxeInfoData->Dgpu2MxmBinFile.Address),
|
|
HgDxeInfoData->Dgpu2MxmBinFile.Size
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
|
|
Update Hybrid Graphics information protocol related data for nVIDIA INT 15 callback usage.
|
|
Create Exit Boot Service event and Legacy Boot event to set the Secondary Grcphics Command Register.
|
|
|
|
@param[in] HgDxeInfoData A pointer of HG DXE information data structure,
|
|
this driver or HG Operation Region will use these data.
|
|
@param[in] HgInfoDataHob A pointer of HG information data HOB,
|
|
HG PEI Module created this HOB, and passes the data from PEI phase.
|
|
|
|
@retval EFI_SUCCESS Update Hybrid Graphics information protocol successfully.
|
|
@retval !EFI_SUCCESS Locate Hybrid Graphics information protocol failed.
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
HgInformationUpdate (
|
|
IN HG_DXE_INFORMATION_DATA *HgDxeInfoData,
|
|
IN HG_INFORMATION_DATA_HOB *HgInfoDataHob
|
|
)
|
|
{
|
|
EFI_EVENT ExitBootServicesEvent;
|
|
EFI_EVENT LegacyBootEvent;
|
|
EFI_EVENT ReadyToBootEvent;
|
|
EFI_STATUS Status;
|
|
H2O_HG_INFO_PROTOCOL *HgInfoProtocol;
|
|
|
|
Status = gBS->LocateProtocol (&gH2OHybridGraphicsInfoProtocolGuid, NULL, (VOID **)&HgInfoProtocol);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
HgInfoProtocol->HgMode = HgInfoDataHob->HgMode;
|
|
if (FeaturePcdGet (PcdNvidiaOptimusSupported)) {
|
|
HgInfoProtocol->Vbios.Address = HgDxeInfoData->Vbios.Address;
|
|
HgInfoProtocol->Vbios.Size = HgDxeInfoData->Vbios.Size;
|
|
HgInfoProtocol->DgpuMxmBinFile.Address = HgDxeInfoData->DgpuMxmBinFile.Address;
|
|
HgInfoProtocol->DgpuMxmBinFile.Size = HgDxeInfoData->DgpuMxmBinFile.Size;
|
|
HgInfoProtocol->Dgpu2MxmBinFile.Address = HgDxeInfoData->Dgpu2MxmBinFile.Address;
|
|
HgInfoProtocol->Dgpu2MxmBinFile.Size = HgDxeInfoData->Dgpu2MxmBinFile.Size;
|
|
}
|
|
|
|
if ((HgDxeInfoData->Dgpu2GpioSupport) && ((HgDxeInfoData->Dgpu2VendorId) != 0xFFFF) &&
|
|
(HgInfoDataHob->HgMode == HgModeDgpu)) {
|
|
Status = EfiCreateEventReadyToBootEx (
|
|
TPL_CALLBACK,
|
|
CloseDiscreteSecondaryHdAudio,
|
|
HgDxeInfoData,
|
|
&ReadyToBootEvent
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
if (HgInfoDataHob->BootType == EfiBootType) {
|
|
Status = gBS->CreateEvent (
|
|
EVT_SIGNAL_EXIT_BOOT_SERVICES,
|
|
TPL_NOTIFY,
|
|
SetSecondaryGrcphicsCommandRegister,
|
|
HgDxeInfoData,
|
|
&ExitBootServicesEvent
|
|
);
|
|
} else {
|
|
Status = EfiCreateEventLegacyBootEx (
|
|
TPL_NOTIFY,
|
|
SetSecondaryGrcphicsCommandRegister,
|
|
HgDxeInfoData,
|
|
&LegacyBootEvent
|
|
);
|
|
}
|
|
|
|
//
|
|
// Diable dGPU Hotplug SCI/SMI and set SSID/SVID.
|
|
//
|
|
DisableDgpuBridgeHotplugSmi (HgDxeInfoData);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
Set Secondary Graphics Command Register for avoid I/O resource crash.
|
|
|
|
@param[in] Event The Event this notify function registered to.
|
|
@param[in] Context Pointer to the context data registerd to the Event.
|
|
|
|
@retval EFI_SUCCESS Set secondary Graphics command register successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SetSecondaryGrcphicsCommandRegister (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
HG_DXE_INFORMATION_DATA *HgDxeInfoData;
|
|
UINT8 Data;
|
|
UINTN PciAddress;
|
|
|
|
HgDxeInfoData = (HG_DXE_INFORMATION_DATA *)Context;
|
|
if (HgDxeInfoData == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
Data = 0x07;
|
|
//
|
|
// DEVEN register bit 4 is Internal Graphics Engine (D2EN).
|
|
//
|
|
if (((HgDxeInfoData->SaDeven) & B_SA_DEVEN_D2EN_MASK) != Inactive) {
|
|
//
|
|
// If dGPU and iGPU exist at the same time, close dGPU IO port.
|
|
// Different vendor requests to write command register with different value.
|
|
//
|
|
if ((HgDxeInfoData->DgpuVendorId) != 0xFFFF) {
|
|
PciAddress = PCI_EXPRESS_LIB_ADDRESS (
|
|
HgDxeInfoData->DgpuBus,
|
|
DGPU_DEVICE_NUM,
|
|
DGPU_FUNCTION_NUM,
|
|
PCI_CMD
|
|
);
|
|
if (HgDxeInfoData->DgpuVendorId == NVIDIA_VID) {
|
|
Data = HgDxeInfoData->NvidiaSecondaryGrcphicsCommandRegister;
|
|
}
|
|
if (HgDxeInfoData->DgpuVendorId == AMD_VID) {
|
|
Data = HgDxeInfoData->AmdSecondaryGrcphicsCommandRegister;
|
|
}
|
|
PciExpressAndThenOr8 (PciAddress, Data, Data);
|
|
}
|
|
}
|
|
if ((HgDxeInfoData->Dgpu2GpioSupport) && ((HgDxeInfoData->Dgpu2VendorId) != 0xFFFF)) {
|
|
PciAddress = PCI_EXPRESS_LIB_ADDRESS (
|
|
HgDxeInfoData->Dgpu2Bus,
|
|
DGPU_DEVICE_NUM,
|
|
DGPU_FUNCTION_NUM,
|
|
PCI_CMD
|
|
);
|
|
if (HgDxeInfoData->Dgpu2VendorId == NVIDIA_VID) {
|
|
Data = HgDxeInfoData->AmdSecondaryGrcphicsCommandRegister;
|
|
}
|
|
if (HgDxeInfoData->Dgpu2VendorId == AMD_VID) {
|
|
Data = HgDxeInfoData->NvidiaSecondaryGrcphicsCommandRegister;
|
|
}
|
|
PciExpressAndThenOr8 (PciAddress, Data, Data);
|
|
}
|
|
|
|
//
|
|
// Assign the value of dGPU SSID/SVID to global NVS.
|
|
//
|
|
PciAddress = PCI_EXPRESS_LIB_ADDRESS (
|
|
HgDxeInfoData->DgpuBus,
|
|
DGPU_DEVICE_NUM,
|
|
DGPU_FUNCTION_NUM,
|
|
PCI_SVID
|
|
);
|
|
((EFI_HG_NVS_AREA_PROTOCOL *)(HgDxeInfoData->HgOpRegionAddress))->DgpuSsidSvid = PciExpressRead32 (PciAddress);
|
|
|
|
FreeHgDxeInfoData (&HgDxeInfoData);
|
|
gBS->CloseEvent (Event);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
Discrete GPU only mode Close secondary HD Audio device.
|
|
Close nVIDIA slave HD Audio device.
|
|
Discrete GPU memory mapping register 0x488 Bit 25 is HD audio device power enable bit.
|
|
Close AMD slave HD Audio device.
|
|
1. io_wr offset=0x0, data=0x541C
|
|
2. rd_data = io_rd offset=0x4
|
|
3. io_wr offset=0x4, data=rd_data & ~0x80 (for masking off STRAP_BIF_AUDIO_EN)
|
|
For reference, here's the register composition:
|
|
BIF_PINSTRAP0 <BIFDEC:0x541C> 32
|
|
{
|
|
STRAP_BIF_GEN2_EN_A 0 NUM DEF=1;
|
|
STRAP_BIF_CLK_PM_EN 1 NUM DEF=0;
|
|
STRAP_BIF_BIOS_ROM_EN 2 NUM DEF=0;
|
|
STRAP_BIF_RX_PLL_CALIB_BYPASS 3 NUM DEF=0;
|
|
STRAP_BIF_MEM_AP_SIZE_PIN 6:4 NUM DEF=0;
|
|
STRAP_BIF_AUDIO_EN_PIN 7 NUM DEF=0;
|
|
STRAP_BIF_VGA_DIS_PIN 8 NUM DEF=0;
|
|
STRAP_TX_DEEMPH_EN 9 NUM DEF=1;
|
|
STRAP_TX_PWRS_ENB 10 NUM DEF=1;
|
|
}
|
|
|
|
@param[in] Event The Event this notify function registered to.
|
|
@param[in] Context Pointer to the context data registerd to the Event.
|
|
|
|
@retval EFI_SUCCESS Set secondary Graphics command register successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CloseDiscreteSecondaryHdAudio (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
HG_DXE_INFORMATION_DATA *HgDxeInfoData;
|
|
UINT16 SlavePegIoAddress;
|
|
UINTN PciAddress;
|
|
|
|
HgDxeInfoData = (HG_DXE_INFORMATION_DATA *)Context;
|
|
if (HgDxeInfoData == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if (HgDxeInfoData->Dgpu2VendorId == NVIDIA_VID) {
|
|
PciAddress = PCI_EXPRESS_LIB_ADDRESS (
|
|
HgDxeInfoData->Dgpu2Bus,
|
|
DGPU_DEVICE_NUM,
|
|
DGPU_FUNCTION_NUM,
|
|
NVIDIA_DGPU_HDA_REGISTER
|
|
);
|
|
PciExpressAnd32 (PciAddress, (UINT32)~(BIT25));
|
|
} else if (HgDxeInfoData->Dgpu2VendorId == AMD_VID) {
|
|
PciAddress = PCI_EXPRESS_LIB_ADDRESS (
|
|
HgDxeInfoData->Dgpu2Bus,
|
|
DGPU_DEVICE_NUM,
|
|
DGPU_FUNCTION_NUM,
|
|
PCI_BAR4
|
|
);
|
|
SlavePegIoAddress = PciExpressRead16 (PciAddress);
|
|
SlavePegIoAddress &= ~(BIT0);
|
|
IoWrite32 (SlavePegIoAddress, 0x541C);
|
|
IoWrite32 ((SlavePegIoAddress + 4), (IoRead32 (SlavePegIoAddress + 4) & ~(BIT7)));
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
The function is for free HgDxeInfoData pointer.
|
|
|
|
@param[in, out] HgDxeInfoData A double pointer of HG DXE information data structure.
|
|
|
|
@retval None.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
FreeHgDxeInfoData (
|
|
IN OUT HG_DXE_INFORMATION_DATA **HgDxeInfoData
|
|
)
|
|
{
|
|
if ((*HgDxeInfoData) != NULL) {
|
|
FreePool (*HgDxeInfoData);
|
|
(*HgDxeInfoData) = NULL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
|
|
The function is for disable dGPU bridge hot plug SMI/SCI.
|
|
|
|
@param[in] HgInfoDataHob A pointer of HG information data HOB,
|
|
HG PEI Module created this HOB, and passes the data from PEI phase.
|
|
|
|
@retval None.
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
DisableDgpuBridgeHotplugSmi (
|
|
IN HG_DXE_INFORMATION_DATA *HgDxeInfoData
|
|
)
|
|
{
|
|
UINT32 Data32;
|
|
UINTN PciAddress;
|
|
|
|
//
|
|
// Program Misc Port Config (MPC) register at PCI config space offset
|
|
// D8h as follows:
|
|
// Hot Plug SMI Enable (HPME, bit1) = 0b : Disable
|
|
// Hot Plug SMI Enable (HPME, bit1) = 1b : Enable
|
|
//
|
|
PciAddress = PCI_EXPRESS_LIB_ADDRESS (
|
|
(UINTN)HgDxeInfoData->DgpuBridgeBus,
|
|
(UINTN)HgDxeInfoData->DgpuBridgeDevice,
|
|
(UINTN)HgDxeInfoData->DgpuBridgeFunction,
|
|
R_PCH_PCIE_CFG_MPC
|
|
);
|
|
|
|
Data32 = PciExpressRead32 (PciAddress);
|
|
if (Data32 != 0xFFFFFFFF) {
|
|
Data32 &= (~(B_PCH_PCIE_CFG_MPC_PMCE | B_PCH_PCIE_CFG_MPC_HPCE | B_PCH_PCIE_CFG_MPC_HPME)); // Disable Hotplug SCI/SMI
|
|
PciExpressWrite32(PciAddress, Data32);
|
|
}
|
|
|
|
PciAddress = PCI_EXPRESS_LIB_ADDRESS (
|
|
(UINTN)HgDxeInfoData->DgpuBridgeBus,
|
|
(UINTN)HgDxeInfoData->DgpuBridgeDevice,
|
|
(UINTN)(HgDxeInfoData->DgpuBridgeFunction + 1),
|
|
R_PCH_PCIE_CFG_MPC
|
|
);
|
|
|
|
Data32 = PciExpressRead32 (PciAddress);
|
|
|
|
if (Data32 != 0xFFFFFFFF) {
|
|
Data32 &= (~(B_PCH_PCIE_CFG_MPC_PMCE | B_PCH_PCIE_CFG_MPC_HPCE | B_PCH_PCIE_CFG_MPC_HPME)); // Disable Hotplug SCI/SMI
|
|
PciExpressWrite32 (PciAddress, Data32);
|
|
}
|
|
}
|
|
|
|
/**
|
|
|
|
This function will disable the secondary audio device.
|
|
|
|
@param[in, out] HgDxeInfoData A double pointer of HG DXE information data structure,
|
|
this driver or HG Operation Region will use these data.
|
|
@param[in, out] HgInfoDataHob A double pointer of HG information data HOB,
|
|
HG PEI Module created this HOB, and passes the data from PEI phase.
|
|
|
|
@retval EFI_SUCCESS Disable the secondary audio device pass.
|
|
@retval !EFI_SUCCESS It is someting worng to disable secondary audio device.
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
CloseAmdSecondaryAudioDevice (
|
|
IN HG_DXE_INFORMATION_DATA *HgDxeInfoData,
|
|
IN HG_INFORMATION_DATA_HOB *HgInfoDataHob
|
|
)
|
|
{
|
|
UINT16 PegIoAddress;
|
|
UINTN PciAddress;
|
|
|
|
if (HgDxeInfoData == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Disable the secondary audio device with ATI display card.
|
|
//
|
|
if (HgDxeInfoData->DgpuVendorId == AMD_VID && HgInfoDataHob->HgMode == HgModeMuxless) {
|
|
PciAddress = PCI_EXPRESS_LIB_ADDRESS (
|
|
HgDxeInfoData->DgpuBus,
|
|
DGPU_DEVICE_NUM,
|
|
DGPU_FUNCTION_NUM,
|
|
PCI_BAR4
|
|
);
|
|
PegIoAddress = PciExpressRead16 (PciAddress);
|
|
if (PegIoAddress != 0xFFFF) {
|
|
PegIoAddress &= ~(BIT0);
|
|
IoWrite32 (PegIoAddress, 0x541C);
|
|
IoWrite32 ((PegIoAddress + 4), (IoRead32 (PegIoAddress + 4) & ~(BIT7)));
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|