1129 lines
41 KiB
C
1129 lines
41 KiB
C
/** @file
|
|
The PEIM implements the SA PEI Initialization.
|
|
|
|
@copyright
|
|
INTEL CONFIDENTIAL
|
|
Copyright 1999 - 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:
|
|
**/
|
|
#include <Library/PeiServicesLib.h>
|
|
#include <Library/IoLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/HobLib.h>
|
|
#include <Library/PciSegmentLib.h>
|
|
#include <Uefi/UefiBaseType.h>
|
|
#include <PcieRegs.h>
|
|
#include <CpuRegs.h>
|
|
#include <Ppi/SiPolicy.h>
|
|
#include <SaDataHob.h>
|
|
#include <CpuPcieHobGen3.h>
|
|
#include <CpuPcieHob.h>
|
|
#include <SaConfigHob.h>
|
|
#include <Library/CpuDmiInfoLib.h>
|
|
#include <Library/CpuPlatformLib.h>
|
|
#include <Library/PchPcieRpLib.h>
|
|
#include <Library/PchInfoLib.h>
|
|
#include <Library/SaInitLib.h>
|
|
#include <Library/PcdLib.h>
|
|
#include <Library/PeiServicesTablePointerLib.h>
|
|
#include <Library/ConfigBlockLib.h>
|
|
#include <Register/PchRegs.h>
|
|
#include <Register/IgdRegs.h>
|
|
#include <CpuSbInfo.h>
|
|
#include <Library/PchPciBdfLib.h>
|
|
#include <Register/SaRegsHostBridge.h>
|
|
#include <GraphicsDataHob.h>
|
|
#include <Library/MsrFruLib.h>
|
|
|
|
/**
|
|
Enable VLW's
|
|
|
|
@param[in] HostBridgePreMemConfig Instance of HOST_BRIDGE_PREMEM_CONFIG
|
|
|
|
**/
|
|
VOID
|
|
VlwEnable (
|
|
IN HOST_BRIDGE_PREMEM_CONFIG *HostBridgePreMemConfig
|
|
)
|
|
{
|
|
//
|
|
// Enable VLW's by clearing bit0 DROP_VLW_CTL
|
|
//
|
|
DEBUG ((DEBUG_INFO, "Enable VLW \n"));
|
|
MmioAnd32 (HostBridgePreMemConfig->MchBar + R_SA_MCHBAR_VLWCTL, (UINT32) ~(B_SA_MCHBAR_VLWCTL_DROP_VLW_CTL));
|
|
}
|
|
|
|
/**
|
|
Check some SA policies are valid for debugging unexpected problem if these
|
|
values are not initialized or assigned incorrect resource.
|
|
|
|
@param[in] SiPreMemPolicyPpi The SI PreMem Policy instance
|
|
|
|
**/
|
|
VOID
|
|
SaValidatePolicy (
|
|
IN SI_PREMEM_POLICY_PPI *SiPreMemPolicyPpi
|
|
)
|
|
{
|
|
ASSERT (SiPreMemPolicyPpi->TableHeader.Header.Revision == SI_PREMEM_POLICY_REVISION);
|
|
}
|
|
|
|
/**
|
|
This function enumerate all downstream bridge.
|
|
|
|
@param[in] BusNum - Primary bus number of current bridge.
|
|
|
|
@retval BusNum: return current bus number if current bus is an enpoint device.
|
|
@retval SubBus: return subordinate bus number if current bus is a bridge.
|
|
**/
|
|
UINT8
|
|
EnumerateDownstream (
|
|
IN UINT8 BusNum
|
|
)
|
|
{
|
|
UINT64 DeviceBaseAddress;
|
|
UINT8 DevNum;
|
|
UINT16 Buffer16;
|
|
UINT8 SubBus;
|
|
UINT8 SecBus;
|
|
|
|
SubBus = 0;
|
|
|
|
SecBus = BusNum;
|
|
|
|
for (DevNum = 0; DevNum < 32; DevNum++) {
|
|
///
|
|
/// Read Vendor ID to check if device exists
|
|
/// if no device exists, then check next device
|
|
///
|
|
DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, BusNum, DevNum, 0, 0);
|
|
if (PciSegmentRead16 (DeviceBaseAddress + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
|
|
continue;
|
|
}
|
|
|
|
Buffer16 = PciSegmentRead16 (DeviceBaseAddress + R_PCI_SCC_OFFSET);
|
|
///
|
|
/// Check for PCI/PCI Bridge Device Base Class 6 with subclass 4
|
|
///
|
|
if (Buffer16 == 0x0604) {
|
|
SecBus++;
|
|
PciSegmentWrite8 (DeviceBaseAddress + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, BusNum);
|
|
PciSegmentWrite8 (DeviceBaseAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET, SecBus);
|
|
///
|
|
/// Assign temporary subordinate bus number so that device behind this bridge can be seen
|
|
///
|
|
PciSegmentWrite8 (DeviceBaseAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET, 0xFF);
|
|
|
|
///
|
|
/// A config write is required in order for the device to re-capture the Bus number,
|
|
/// according to PCI Express Base Specification, 2.2.6.2
|
|
/// Write to a read-only register VendorID to not cause any side effects.
|
|
///
|
|
PciSegmentWrite16 (PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, SecBus, 0, 0, PCI_VENDOR_ID_OFFSET), 0);
|
|
|
|
///
|
|
/// Enumerate bus behind this bridge by calling this function recursively
|
|
///
|
|
SubBus = EnumerateDownstream (SecBus);
|
|
///
|
|
/// Update the correct subordinate bus number
|
|
///
|
|
PciSegmentWrite8 (DeviceBaseAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET, SubBus);
|
|
SecBus = SubBus;
|
|
}
|
|
}
|
|
|
|
if (SubBus == 0) {
|
|
return BusNum;
|
|
} else {
|
|
return SubBus;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Find the MMIO size that a given PCI device requires
|
|
|
|
@param[in] BusNum - Bus number of the device
|
|
@param[in] DevNum - device Number of the device
|
|
@param[in] FunNum - Function number of the device
|
|
@param[out] MmioLength - MMIO Length in bytes
|
|
**/
|
|
VOID
|
|
FindPciDeviceMmioLength (
|
|
IN UINT32 BusNum,
|
|
IN UINT32 DevNum,
|
|
IN UINT32 FunNum,
|
|
OUT UINT32 *MmioLength
|
|
)
|
|
{
|
|
UINT32 CurrentMmioLength;
|
|
UINT32 SavedBAR;
|
|
UINT16 SavedCmd;
|
|
UINT32 i;
|
|
UINT8 ClassCode;
|
|
UINT64 DeviceBaseAddress;
|
|
SI_PREMEM_POLICY_PPI *SiPreMemPolicyPpi;
|
|
HOST_BRIDGE_PREMEM_CONFIG *HostBridgePreMemConfig;
|
|
EFI_STATUS Status;
|
|
|
|
*MmioLength = 0;
|
|
|
|
SiPreMemPolicyPpi = NULL;
|
|
Status = PeiServicesLocatePpi (&gSiPreMemPolicyPpiGuid, 0, NULL, (VOID **) &SiPreMemPolicyPpi);
|
|
ASSERT_EFI_ERROR(Status);
|
|
|
|
HostBridgePreMemConfig = NULL;
|
|
Status = GetConfigBlock ((VOID *) SiPreMemPolicyPpi, &gHostBridgePeiPreMemConfigGuid, (VOID *) &HostBridgePreMemConfig);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, BusNum, DevNum, FunNum, 0);
|
|
ClassCode = PciSegmentRead8 (DeviceBaseAddress + R_PCI_BCC_OFFSET);
|
|
if (ClassCode == PCI_CLASS_BRIDGE) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Save and disable PCI command before change BAR
|
|
//
|
|
SavedCmd = PciSegmentRead16 (DeviceBaseAddress + PCI_COMMAND_OFFSET);
|
|
PciSegmentWrite16 (DeviceBaseAddress + PCI_COMMAND_OFFSET, 0);
|
|
|
|
for (i = R_BASE_ADDRESS_OFFSET_0; i <= R_BASE_ADDRESS_OFFSET_5; i += 4) {
|
|
SavedBAR = PciSegmentRead32 (DeviceBaseAddress + i);
|
|
///
|
|
/// Skip next index if BAR is 64bit address when enable above 4G support.
|
|
///
|
|
if ((HostBridgePreMemConfig != NULL) && (HostBridgePreMemConfig->EnableAbove4GBMmio == 1)) {
|
|
if ((SavedBAR & (BIT1 + BIT2)) == 0x4) {
|
|
i += 4;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
///
|
|
/// Check BAR is read-only or not
|
|
///
|
|
PciSegmentAnd32 (DeviceBaseAddress + i, (UINT32) 0);
|
|
PciSegmentOr32 (DeviceBaseAddress + i, (UINT32) MAX_UINT32);
|
|
if (SavedBAR == PciSegmentRead32 (DeviceBaseAddress + i)) {
|
|
///
|
|
/// Restore BAR as original value
|
|
///
|
|
PciSegmentWrite32 (DeviceBaseAddress + i, SavedBAR);
|
|
continue;
|
|
}
|
|
///
|
|
/// If BAR is not memory map, skip it
|
|
///
|
|
if ((SavedBAR & BIT0) != 0) {
|
|
///
|
|
/// Restore BAR as original value
|
|
///
|
|
PciSegmentWrite32 (DeviceBaseAddress + i, SavedBAR);
|
|
continue;
|
|
}
|
|
///
|
|
/// Calculate the MMIO length through BAR
|
|
///
|
|
CurrentMmioLength = ~(PciSegmentRead32 (DeviceBaseAddress + i) &~0xF) + 1;
|
|
*MmioLength += CurrentMmioLength;
|
|
|
|
///
|
|
/// Restore BAR as original value
|
|
///
|
|
PciSegmentWrite32 (DeviceBaseAddress + i, SavedBAR);
|
|
}
|
|
//
|
|
// Restore Command as original value
|
|
//
|
|
PciSegmentWrite16 (DeviceBaseAddress + PCI_COMMAND_OFFSET, SavedCmd);
|
|
}
|
|
|
|
/**
|
|
Read OpROM Headers and determine if the OpROM only provides legacy VBIOS
|
|
|
|
@param[in] RomSize - Size of the OpROM memory mapped area
|
|
@param[in] OpRomScanTempMmioBar - Temporary BAR to MMIO map OpROMs during VGA scanning
|
|
@param[in] OpRomScanTempMmioLimit - Limit address for OpROM MMIO range
|
|
|
|
@retval TRUE if end point has a legacy only OpROM
|
|
@retval FALSE if end point has a UEFI OpROM, Hybrid OpROM, or no OpROM
|
|
**/
|
|
BOOLEAN
|
|
ParseOpRomHeadersForLegacyOnly (
|
|
IN UINT32 RomSize,
|
|
IN UINT32 OpRomScanTempMmioBar,
|
|
IN UINT32 OpRomScanTempMmioLimit
|
|
)
|
|
{
|
|
PCI_EXPANSION_ROM_HEADER *RomHeader;
|
|
PCI_DATA_STRUCTURE *RomPcir;
|
|
UINT32 CurrentImageOffset;
|
|
UINT32 RomImageSize;
|
|
UINT16 OffsetPcir;
|
|
UINT16 EfiMachineType;
|
|
BOOLEAN FirstImage;
|
|
BOOLEAN FoundEfiImage;
|
|
BOOLEAN FoundLegacyImage;
|
|
UINT8 Indicator;
|
|
|
|
FirstImage = TRUE;
|
|
FoundEfiImage = FALSE;
|
|
FoundLegacyImage = FALSE;
|
|
Indicator = 0;
|
|
CurrentImageOffset = 0;
|
|
RomImageSize = 0;
|
|
do {
|
|
RomHeader = (PCI_EXPANSION_ROM_HEADER*) (UINTN) (OpRomScanTempMmioBar + CurrentImageOffset);
|
|
if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
|
|
if (FirstImage) {
|
|
DEBUG ((DEBUG_INFO, "Invalid OpROM\n"));
|
|
return FALSE;
|
|
} else {
|
|
CurrentImageOffset += 512;
|
|
RomImageSize += 512;
|
|
continue;
|
|
}
|
|
}
|
|
FirstImage = FALSE;
|
|
OffsetPcir = RomHeader->PcirOffset;
|
|
if ((OffsetPcir == 0) || ((OffsetPcir & 3) != 0) ||
|
|
((RomImageSize + OffsetPcir + sizeof (PCI_DATA_STRUCTURE)) > RomSize)) {
|
|
DEBUG ((DEBUG_INFO, "PCIR offset invalid\n"));
|
|
break;
|
|
}
|
|
RomPcir = (PCI_DATA_STRUCTURE*) (UINTN) (OpRomScanTempMmioBar + CurrentImageOffset + OffsetPcir);
|
|
if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
|
|
DEBUG ((DEBUG_INFO, "Invalid PCIR signature\n"));
|
|
break;
|
|
}
|
|
if ((RomImageSize + (RomPcir->ImageLength * 512)) > RomSize) {
|
|
DEBUG ((DEBUG_INFO, "Image size exceeds total ROM size\n"));
|
|
break;
|
|
}
|
|
if (RomPcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
|
|
DEBUG ((DEBUG_INFO, "Legacy OpROM Found: Offset[0x%x]\n", CurrentImageOffset));
|
|
FoundLegacyImage = TRUE;
|
|
} else if (RomPcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) {
|
|
EfiMachineType = ((EFI_PCI_EXPANSION_ROM_HEADER*) RomHeader)->EfiMachineType;
|
|
switch (EfiMachineType) {
|
|
case EFI_IMAGE_MACHINE_IA32:
|
|
DEBUG ((DEBUG_INFO, "UEFI OpROM Found: Type[IA32] Offset[0x%x]\n", CurrentImageOffset));
|
|
break;
|
|
case EFI_IMAGE_MACHINE_IA64:
|
|
DEBUG ((DEBUG_INFO, "UEFI OpROM Found: Type[IPF] Offset[0x%x]\n", CurrentImageOffset));
|
|
break;
|
|
case EFI_IMAGE_MACHINE_EBC:
|
|
DEBUG ((DEBUG_INFO, "UEFI OpROM Found: Type[EBC] Offset[0x%x]\n", CurrentImageOffset));
|
|
break;
|
|
case EFI_IMAGE_MACHINE_X64:
|
|
DEBUG ((DEBUG_INFO, "UEFI OpROM Found: Type[X64] Offset[0x%x]\n", CurrentImageOffset));
|
|
break;
|
|
case EFI_IMAGE_MACHINE_ARMTHUMB_MIXED:
|
|
DEBUG ((DEBUG_INFO, "UEFI OpROM Found: Type[ARM] Offset[0x%x]\n", CurrentImageOffset));
|
|
break;
|
|
case EFI_IMAGE_MACHINE_AARCH64:
|
|
DEBUG ((DEBUG_INFO, "UEFI OpROM Found: Type[ARM64] Offset[0x%x]\n", CurrentImageOffset));
|
|
break;
|
|
default:
|
|
DEBUG ((DEBUG_INFO, "UEFI OpROM Found: Type[Unknown] Offset[0x%x]\n", CurrentImageOffset));
|
|
break;
|
|
}
|
|
///
|
|
/// GOP Image Machine Type must be X64 or EBC to work on this platform
|
|
///
|
|
if ((EfiMachineType == EFI_IMAGE_MACHINE_X64) || (EfiMachineType == EFI_IMAGE_MACHINE_EBC)) {
|
|
FoundEfiImage = TRUE;
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "UEFI OpROM Machine Type not supported on this platform\n"));
|
|
}
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "Unknown OpROM Found: Type = %d Offset[%x]\n", (UINTN) RomPcir->CodeType, CurrentImageOffset));
|
|
}
|
|
if ((RomPcir->ImageLength % 2) == 1) {
|
|
DEBUG ((DEBUG_INFO, "OpROM Size: %d.5KB\n", RomPcir->ImageLength / 2));
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "OpROM Size: %dKB\n", RomPcir->ImageLength / 2));
|
|
}
|
|
|
|
Indicator = RomPcir->Indicator;
|
|
RomImageSize += RomPcir->ImageLength * 512;
|
|
CurrentImageOffset += RomPcir->ImageLength * 512;
|
|
} while (((Indicator & BIT7) == 0x0) && (CurrentImageOffset < RomSize));
|
|
|
|
if (!FoundEfiImage && FoundLegacyImage) {
|
|
return TRUE;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Traverse depth first to find end point in the PCI topology and determine its OpROM
|
|
|
|
@param[in] ParentSegment - Segment number for parent device
|
|
@param[in] ParentBus - Bus number for parent device
|
|
@param[in] ParentDev - Device number for parent device
|
|
@param[in] ParentFunc - Function number for parent device
|
|
@param[in] OpRomScanTempMmioBar - Temporary BAR to MMIO map OpROMs during VGA scanning
|
|
@param[in] OpRomScanTempMmioLimit - Limit address for OpROM MMIO range
|
|
@param[in] ParentSecondary - Secondary Bus number for the parent PCI/PCI bridge
|
|
@param[in] ParentSubordinate - Subordinate Bus number for the parent PCI/PCI bridge
|
|
@param[in] EpSegment - Segment number for end point to check
|
|
@param[in] EpBus - Bus number for end point to check
|
|
@param[in] EpDev - Device number for end point to check
|
|
@param[in] EpFunc - Function number for end point to check
|
|
|
|
@retval TRUE if end point has a legacy only OpROM
|
|
@retval FALSE if end point has a UEFI OpROM, Hybrid OpROM, or no OpROM
|
|
**/
|
|
BOOLEAN
|
|
ScanDownstreamForLegacyOpRom (
|
|
IN UINT8 ParentSegment,
|
|
IN UINT8 ParentBus,
|
|
IN UINTN ParentDev,
|
|
IN UINTN ParentFunc,
|
|
IN UINT32 OpRomScanTempMmioBar,
|
|
IN UINT32 OpRomScanTempMmioLimit,
|
|
IN UINT8 ParentSecondary,
|
|
IN UINT8 ParentSubordinate,
|
|
IN UINT8 EpSegment,
|
|
IN UINT8 EpBus,
|
|
IN UINT8 EpDev,
|
|
IN UINT8 EpFunc,
|
|
IN OUT BOOLEAN *FoundEp
|
|
)
|
|
{
|
|
UINT64 ParentBaseAddress;
|
|
UINT64 DeviceBaseAddress;
|
|
UINT32 RomSize;
|
|
UINT16 ClassCode;
|
|
UINT8 Dev;
|
|
UINT8 Func;
|
|
UINT8 MaxFunc;
|
|
UINT8 ChildSecondary;
|
|
UINT8 ChildSubordinate;
|
|
UINT8 HeaderType;
|
|
BOOLEAN FoundLegacyOpRom;
|
|
BOOLEAN TraversedBridge;
|
|
|
|
FoundLegacyOpRom = FALSE;
|
|
TraversedBridge = FALSE;
|
|
ParentBaseAddress = PCI_SEGMENT_LIB_ADDRESS (ParentSegment, (UINT32) ParentBus, (UINT32) ParentDev, (UINT32) ParentFunc, 0);
|
|
|
|
///
|
|
/// Forward MMIO access from the primary interface to the secondary interface
|
|
///
|
|
PciSegmentWrite32 (ParentBaseAddress + R_PCI_BRIDGE_MBL, ((OpRomScanTempMmioLimit & 0xFFFF0000) | (OpRomScanTempMmioBar >> 16)));
|
|
PciSegmentOr8 (ParentBaseAddress + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE);
|
|
|
|
///
|
|
/// If we have reached the correct bus, there are no more bridges to traverse
|
|
///
|
|
if (ParentSecondary == EpBus) {
|
|
DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (EpSegment, (UINT32) EpBus, (UINT32) EpDev, (UINT32) EpFunc, 0);
|
|
if (PciSegmentRead16 (DeviceBaseAddress + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
|
|
(*FoundEp) = FALSE;
|
|
} else {
|
|
///
|
|
/// Found the Primary Display device
|
|
///
|
|
(*FoundEp) = TRUE;
|
|
///
|
|
/// Determine if an OpROM is present and its size
|
|
///
|
|
PciSegmentWrite32 (DeviceBaseAddress + PCI_EXPANSION_ROM_BASE, 0xFFFFFFFE);
|
|
RomSize = PciSegmentRead32 (DeviceBaseAddress + PCI_EXPANSION_ROM_BASE);
|
|
RomSize &= 0xFFFFF800; ///< Bits[10:1] are reserved
|
|
if ((RomSize == 0) || (RomSize == 0xFFFFF800)) {
|
|
///
|
|
/// Device doesn't have an OpROM, hence it doesn't have a legacy OpROM
|
|
///
|
|
FoundLegacyOpRom = FALSE;
|
|
} else {
|
|
RomSize = ((~RomSize) + 1);
|
|
DEBUG ((DEBUG_INFO, "Found %dKB OpROM\n", (UINTN) (RomSize / 1024)));
|
|
///
|
|
/// Enable MMIO to the OpROM
|
|
///
|
|
PciSegmentWrite32 (DeviceBaseAddress + PCI_EXPANSION_ROM_BASE, (OpRomScanTempMmioBar | BIT0));
|
|
PciSegmentOr8 (DeviceBaseAddress + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE);
|
|
///
|
|
/// Parse the OpROM headers to determine if it is legacy only
|
|
///
|
|
FoundLegacyOpRom = ParseOpRomHeadersForLegacyOnly (RomSize, OpRomScanTempMmioBar, OpRomScanTempMmioLimit);
|
|
///
|
|
/// Disable MMIO to the OpROM
|
|
///
|
|
PciSegmentAnd8 (DeviceBaseAddress + PCI_COMMAND_OFFSET, (UINT8) ~(EFI_PCI_COMMAND_MEMORY_SPACE));
|
|
PciSegmentWrite32 (DeviceBaseAddress + PCI_EXPANSION_ROM_BASE, 0);
|
|
}
|
|
}
|
|
} else {
|
|
///
|
|
/// Scan Parent Secondary Bus for more bridges
|
|
///
|
|
for (Dev = 0; Dev < 32; Dev++) {
|
|
DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (ParentSegment, (UINT32) ParentSecondary, (UINT32) Dev, 0, 0);
|
|
if (PciSegmentRead16 (DeviceBaseAddress + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
|
|
continue;
|
|
}
|
|
HeaderType = PciSegmentRead8 (DeviceBaseAddress + PCI_HEADER_TYPE_OFFSET);
|
|
if ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) != 0) {
|
|
MaxFunc = 7;
|
|
} else {
|
|
MaxFunc = 0;
|
|
}
|
|
for (Func = 0; Func <= MaxFunc; Func++) {
|
|
if (Func != 0) {
|
|
DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (ParentSegment, (UINT32) ParentSecondary, (UINT32) Dev, (UINT32) Func, 0);
|
|
if (PciSegmentRead16 (DeviceBaseAddress + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
|
|
continue;
|
|
}
|
|
}
|
|
///
|
|
/// Search for the next PCI/PCI Bridge
|
|
///
|
|
ClassCode = PciSegmentRead16 (DeviceBaseAddress + R_PCI_SCC_OFFSET);
|
|
if (ClassCode == 0x0604) {
|
|
ChildSecondary = PciSegmentRead8 (DeviceBaseAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
|
|
ChildSubordinate = PciSegmentRead8 (DeviceBaseAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
|
|
if ((EpBus >= ChildSecondary) && (EpBus <= ChildSubordinate)) {
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"Traversing PCI/PCI Bridge at (%x:%x:%x) Sec[%d], Sub[%d]\n",
|
|
(UINTN) ParentSecondary,
|
|
(UINTN) Dev,
|
|
(UINTN) Func,
|
|
(UINTN) ChildSecondary,
|
|
(UINTN) ChildSubordinate
|
|
));
|
|
TraversedBridge = TRUE;
|
|
FoundLegacyOpRom = ScanDownstreamForLegacyOpRom (
|
|
ParentSegment,
|
|
ParentSecondary,
|
|
Dev,
|
|
Func,
|
|
OpRomScanTempMmioBar,
|
|
OpRomScanTempMmioLimit,
|
|
ChildSecondary,
|
|
ChildSubordinate,
|
|
EpSegment,
|
|
EpBus,
|
|
EpDev,
|
|
EpFunc,
|
|
FoundEp
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (TraversedBridge) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
///
|
|
/// Disable MMIO access now that we are done
|
|
///
|
|
PciSegmentAnd8 (ParentBaseAddress + PCI_COMMAND_OFFSET, (UINT8) ~(EFI_PCI_COMMAND_MEMORY_SPACE));
|
|
PciSegmentWrite32 (ParentBaseAddress + R_PCI_BRIDGE_MBL, 0);
|
|
return FoundLegacyOpRom;
|
|
}
|
|
|
|
/**
|
|
Check if device has a legacy only OpROM (CSM required to dispatch device's OpROM)
|
|
|
|
@param[in] OpRomScanTempMmioBar - Temporary BAR to MMIO map OpROMs during VGA scanning
|
|
@param[in] OpRomScanTempMmioLimit - Limit address for OpROM MMIO range
|
|
@param[in] EpSegment - Segment number for end point to check
|
|
@param[in] EpBus - Bus number for end point to check
|
|
@param[in] EpDev - Device number for end point to check
|
|
@param[in] EpFunc - Function number for end point to check
|
|
|
|
@retval TRUE if end point has a legacy only OpROM
|
|
@retval FALSE if end point has a UEFI OpROM, Hybrid OpROM, or no OpROM
|
|
**/
|
|
BOOLEAN
|
|
CheckForLegacyOnlyOpRom (
|
|
IN UINT32 OpRomScanTempMmioBar,
|
|
IN UINT32 OpRomScanTempMmioLimit,
|
|
IN UINT8 EpSegment,
|
|
IN UINT8 EpBus,
|
|
IN UINT8 EpDev,
|
|
IN UINT8 EpFunc
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN RpDev;
|
|
UINTN RpFunc;
|
|
UINTN RpIndex;
|
|
UINT64 RpBaseAddress;
|
|
BOOLEAN FoundEp;
|
|
BOOLEAN FoundLegacyOpRom;
|
|
UINT8 SecondaryBus;
|
|
UINT8 SubordinateBus;
|
|
UINT8 PegMaxFuncNum;
|
|
|
|
RpDev = SA_PEG_DEV_NUM;
|
|
PegMaxFuncNum = SA_PEG_MAX_FUN;
|
|
|
|
///
|
|
/// Check that correct alignment and range is provided
|
|
///
|
|
ASSERT ((OpRomScanTempMmioBar % 0x1000000) == 0);
|
|
ASSERT ((OpRomScanTempMmioLimit - OpRomScanTempMmioBar) >= 0x1000000);
|
|
///
|
|
/// First determine the root port the device is connected to, check PEG first
|
|
///
|
|
DEBUG ((DEBUG_INFO, "Detecting OpROM for (%x:%x:%x)\n", (UINTN) EpBus, (UINTN) EpDev, (UINTN) EpFunc));
|
|
if (IsPchLinkDmi ()) {
|
|
for (RpFunc = 0; RpFunc < PegMaxFuncNum; RpFunc++) {
|
|
RpBaseAddress = PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, SA_PEG_BUS_NUM, (UINT32) RpDev, (UINT32) RpFunc, 0);
|
|
if (PciSegmentRead16 (RpBaseAddress + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
|
|
continue;
|
|
}
|
|
SecondaryBus = PciSegmentRead8 (RpBaseAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
|
|
SubordinateBus = PciSegmentRead8 (RpBaseAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"PCIe RP (%x:%x:%x) Sec[%d], Sub[%d]\n",
|
|
SA_PEG_BUS_NUM,
|
|
RpDev,
|
|
RpFunc,
|
|
(UINTN) SecondaryBus,
|
|
(UINTN) SubordinateBus
|
|
));
|
|
if ((EpBus >= SecondaryBus) && (EpBus <= SubordinateBus)) {
|
|
DEBUG ((DEBUG_INFO, "Found correct RP, traversing downstream...\n"));
|
|
FoundEp = FALSE;
|
|
FoundLegacyOpRom = ScanDownstreamForLegacyOpRom (
|
|
SA_SEG_NUM,
|
|
SA_PEG_BUS_NUM,
|
|
RpDev,
|
|
RpFunc,
|
|
OpRomScanTempMmioBar,
|
|
OpRomScanTempMmioLimit,
|
|
SecondaryBus,
|
|
SubordinateBus,
|
|
EpSegment,
|
|
EpBus,
|
|
EpDev,
|
|
EpFunc,
|
|
&FoundEp
|
|
);
|
|
if (FoundEp) {
|
|
DEBUG ((DEBUG_INFO, "Legacy Only VBIOS: %d\n", (UINTN) FoundLegacyOpRom));
|
|
return FoundLegacyOpRom;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (RpIndex = 0; RpIndex < GetPchMaxPciePortNum (); RpIndex++) {
|
|
///
|
|
/// Check if root port exists
|
|
///
|
|
Status = GetPchPcieRpDevFun (RpIndex, &RpDev, &RpFunc);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
RpBaseAddress = PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMBER_PCH, DEFAULT_PCI_BUS_NUMBER_PCH, (UINT32) RpDev, (UINT32) RpFunc, 0);
|
|
if (PciSegmentRead16 (RpBaseAddress + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
|
|
continue;
|
|
}
|
|
SecondaryBus = PciSegmentRead8 (RpBaseAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
|
|
SubordinateBus = PciSegmentRead8 (RpBaseAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"PCIe RP (%x:%x:%x) Sec[%d], Sub[%d]\n",
|
|
DEFAULT_PCI_BUS_NUMBER_PCH,
|
|
RpDev,
|
|
RpFunc,
|
|
(UINTN) SecondaryBus,
|
|
(UINTN) SubordinateBus
|
|
));
|
|
if ((EpBus >= SecondaryBus) && (EpBus <= SubordinateBus)) {
|
|
DEBUG ((DEBUG_INFO, "Found correct RP, traversing downstream...\n"));
|
|
FoundEp = FALSE;
|
|
FoundLegacyOpRom = ScanDownstreamForLegacyOpRom (
|
|
DEFAULT_PCI_SEGMENT_NUMBER_PCH,
|
|
DEFAULT_PCI_BUS_NUMBER_PCH,
|
|
RpDev,
|
|
RpFunc,
|
|
OpRomScanTempMmioBar,
|
|
OpRomScanTempMmioLimit,
|
|
SecondaryBus,
|
|
SubordinateBus,
|
|
EpSegment,
|
|
EpBus,
|
|
EpDev,
|
|
EpFunc,
|
|
&FoundEp
|
|
);
|
|
if (FoundEp) {
|
|
DEBUG ((DEBUG_INFO, "Legacy Only VBIOS: %d\n", (UINTN) FoundLegacyOpRom));
|
|
return FoundLegacyOpRom;
|
|
}
|
|
}
|
|
}
|
|
DEBUG ((DEBUG_WARN, "Primary Graphics device not found!\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// This macro does not track the maximun PCIE RP number. This MACRO counts for
|
|
// BIT Size of ExtGfxCardPresentOnPcieRpBitMap variable in GFX_DATA_HOB Structure.
|
|
// The data type of ExtGfxCardPresentOnPcieRpBitMap is UINT32 currently.
|
|
//
|
|
#define MAX_BIT_SIZE_OF_PCIE_BIT_MAP_VAR 32
|
|
typedef struct {
|
|
UINT8 RpIndex;
|
|
UINT8 SecBusNum;
|
|
UINT8 SubBusNum;
|
|
UINT8 GfxCardFound;
|
|
} PRIVATE_PCIE_RP_GFX_SCAN_DATA;
|
|
|
|
/**
|
|
CheckOffboardPcieVga: Check if off board PCIe graphics Card is present
|
|
|
|
@param[in, out] PchPcieMmioLength - Total PCIe MMIO length on all PCH root ports
|
|
@param[in, out] PrimaryDisplay - Primary Display - default is IGD
|
|
@param[in] OpRomScanTempMmioBar - Temporary BAR to MMIO map OpROMs during VGA scanning
|
|
@param[in] OpRomScanTempMmioLimit - Limit address for OpROM MMIO range
|
|
@param[in] ScanForLegacyOpRom - TRUE to scan for legacy only VBIOS, FALSE otherwise
|
|
@param[out] FoundLegacyOpRom - If legacy only VBIOS found, returns TRUE
|
|
@param[in] ResizableBarSupport - Resizable BAR is support
|
|
**/
|
|
VOID
|
|
CheckOffboardPcieVga (
|
|
IN OUT UINT32 *PchPcieMmioLength,
|
|
IN OUT DISPLAY_DEVICE *PrimaryDisplay,
|
|
IN UINT32 OpRomScanTempMmioBar,
|
|
IN UINT32 OpRomScanTempMmioLimit,
|
|
IN BOOLEAN ScanForLegacyOpRom,
|
|
OUT BOOLEAN *FoundLegacyOpRom,
|
|
IN UINT8 ResizableBarSupport
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN RpDev;
|
|
UINTN RpFunc;
|
|
UINTN RpIndex;
|
|
UINT64 DeviceBaseAddress;
|
|
UINT32 PcieBusNum;
|
|
UINT8 Bus;
|
|
UINT8 Dev;
|
|
UINT8 Func;
|
|
UINT8 MaxFunction;
|
|
UINT8 SubBusNum;
|
|
UINT8 HeaderType;
|
|
UINT16 Buffer16;
|
|
BOOLEAN CardDetect;
|
|
UINT32 MmioLength;
|
|
UINT8 RpGfxScanIndex;
|
|
UINT8 MaxPcieRpDeviceFound;
|
|
PRIVATE_PCIE_RP_GFX_SCAN_DATA RpGfxScan[MAX_BIT_SIZE_OF_PCIE_BIT_MAP_VAR];
|
|
GFX_DATA_HOB *GfxDataHob;
|
|
SA_DATA_HOB *SaDataHob;
|
|
|
|
MmioLength = 0;
|
|
GfxDataHob = NULL;
|
|
SaDataHob = NULL;
|
|
|
|
//
|
|
// Get the HOB for Gfx Data
|
|
//
|
|
GfxDataHob = (GFX_DATA_HOB *) GetFirstGuidHob (&gGraphicsDataHobGuid);
|
|
if (GfxDataHob == NULL) {
|
|
DEBUG ((EFI_D_ERROR, "Gfx Data Hob not found\n"));
|
|
return;
|
|
}
|
|
//
|
|
// Get the HOB for SA Data
|
|
//
|
|
SaDataHob = (SA_DATA_HOB *)GetFirstGuidHob (&gSaDataHobGuid);
|
|
if (SaDataHob == NULL) {
|
|
DEBUG ((EFI_D_ERROR, "SA Data Hob not found\n"));
|
|
return;
|
|
}
|
|
|
|
///
|
|
/// Initialize Secondary and Subordinate bus number for first Pcie root port
|
|
///
|
|
PcieBusNum = 0x00010100;
|
|
|
|
SubBusNum = 0;
|
|
|
|
CardDetect = FALSE;
|
|
SaDataHob->ResizableBarSupport = ResizableBarSupport;
|
|
|
|
for (RpIndex = 0, RpGfxScanIndex =0; RpIndex < GetPchMaxPciePortNum (); RpIndex++) {
|
|
///
|
|
/// Check if root port exists
|
|
///
|
|
Status = GetPchPcieRpDevFun (RpIndex, &RpDev, &RpFunc);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMBER_PCH, DEFAULT_PCI_BUS_NUMBER_PCH, (UINT32) RpDev, (UINT32) RpFunc, 0);
|
|
if (PciSegmentRead16 (DeviceBaseAddress + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
|
|
continue;
|
|
}
|
|
|
|
PciSegmentWrite32 (DeviceBaseAddress + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, PcieBusNum);
|
|
Bus = PciSegmentRead8 (DeviceBaseAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
|
|
|
|
///
|
|
/// Assign temporary subordinate bus number so that device this bridge can be seen
|
|
///
|
|
PciSegmentWrite8 (DeviceBaseAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET, 0xFF);
|
|
|
|
///
|
|
/// A config write is required in order for the device to re-capture the Bus number,
|
|
/// according to PCI Express Base Specification, 2.2.6.2
|
|
/// Write to a read-only register VendorID to not cause any side effects.
|
|
///
|
|
PciSegmentWrite16 (PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMBER_PCH, Bus, 0, 0, PCI_VENDOR_ID_OFFSET), 0);
|
|
|
|
SubBusNum = EnumerateDownstream (Bus);
|
|
|
|
RpGfxScan[RpGfxScanIndex].RpIndex = (UINT8) RpIndex;
|
|
RpGfxScan[RpGfxScanIndex].SecBusNum = (UINT8) (PcieBusNum >> 8) & 0xFF;
|
|
RpGfxScan[RpGfxScanIndex].SubBusNum = (UINT8) SubBusNum;
|
|
RpGfxScanIndex++;
|
|
|
|
///
|
|
/// Update the actual subordinate bus number
|
|
///
|
|
PciSegmentWrite8 (DeviceBaseAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET, SubBusNum);
|
|
PcieBusNum = (SubBusNum + 1) << 8;
|
|
}
|
|
|
|
MaxPcieRpDeviceFound = RpGfxScanIndex;
|
|
|
|
for (Bus = 1; Bus <= SubBusNum; Bus++) {
|
|
for (Dev = 0; Dev < 32; Dev++) {
|
|
///
|
|
/// Read Vendor ID to check if device exists
|
|
/// if no device exists, then check next device
|
|
///
|
|
DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMBER_PCH, Bus, Dev, 0, 0);
|
|
if (PciSegmentRead16 (DeviceBaseAddress + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
|
|
continue;
|
|
}
|
|
///
|
|
/// Check for a multifunction device
|
|
///
|
|
HeaderType = PciSegmentRead8 (DeviceBaseAddress + PCI_HEADER_TYPE_OFFSET);
|
|
if ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) != 0) {
|
|
MaxFunction = 7;
|
|
} else {
|
|
MaxFunction = 0;
|
|
}
|
|
|
|
for (Func = 0; Func <= MaxFunction; Func++) {
|
|
if (PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMBER_PCH, Bus, Dev, Func, PCI_VENDOR_ID_OFFSET)) == 0xFFFF) {
|
|
continue;
|
|
}
|
|
|
|
FindPciDeviceMmioLength (Bus, Dev, Func, &MmioLength);
|
|
*PchPcieMmioLength += MmioLength;
|
|
|
|
///
|
|
/// Video cards can have Base Class 0 with Sub-class 1
|
|
/// or Base Class 3.
|
|
///
|
|
if (PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMBER_PCH, Bus, Dev, Func, R_PCI_SCC_OFFSET)) == 0x0300) {
|
|
if (((PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(DEFAULT_PCI_SEGMENT_NUMBER_PCH, Bus, Dev, Func, PCI_VENDOR_ID_OFFSET)) == 0x8086) || (PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(DEFAULT_PCI_SEGMENT_NUMBER_PCH, Bus, Dev, Func, PCI_VENDOR_ID_OFFSET)) == 0x1002)) && (ResizableBarSupport != 0)){
|
|
SaDataHob->ResizableBarSupport = 1;
|
|
}
|
|
for (RpGfxScanIndex = 0; RpGfxScanIndex < MaxPcieRpDeviceFound; RpGfxScanIndex++) {
|
|
if ((RpGfxScan[RpGfxScanIndex].SecBusNum <= Bus) && (RpGfxScan[RpGfxScanIndex].SubBusNum >= Bus)) {
|
|
GfxDataHob->ExtGfxCardPresentOnPcieRpBitMap |= (UINT32) (BIT0 << RpGfxScan[RpGfxScanIndex].RpIndex);
|
|
GfxDataHob->NumberOfGfxControllerFound ++;
|
|
if (RpGfxScan[RpGfxScanIndex].SecBusNum == Bus) {
|
|
GfxDataHob->ExtGfxCardOnPcieRpAsImmediateChildBitMap |= (UINT32) (BIT0 << RpGfxScan[RpGfxScanIndex].RpIndex);
|
|
}
|
|
}
|
|
}
|
|
if (CardDetect != TRUE) {
|
|
*PrimaryDisplay = PCI;
|
|
GfxDataHob->PrimaryDisplayDetection = PCI;
|
|
DEBUG ((DEBUG_INFO, "PCH PCIe Graphics Card enabled.\n"));
|
|
CardDetect = TRUE;
|
|
if (ScanForLegacyOpRom) {
|
|
(*FoundLegacyOpRom) = CheckForLegacyOnlyOpRom (OpRomScanTempMmioBar, OpRomScanTempMmioLimit, DEFAULT_PCI_SEGMENT_NUMBER_PCH, Bus, Dev, Func);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
///
|
|
/// Clear bus number on all the bridges that we have opened so far.
|
|
/// We have to do it in the reverse Bus number order.
|
|
///
|
|
for (Bus = SubBusNum; Bus >= 1; Bus--) {
|
|
for (Dev = 0; Dev < 32; Dev++) {
|
|
///
|
|
/// Read Vendor ID to check if device exists
|
|
/// if no device exists, then check next device
|
|
///
|
|
DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMBER_PCH, Bus, Dev, 0, 0);
|
|
if (PciSegmentRead16 (DeviceBaseAddress + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
|
|
continue;
|
|
}
|
|
|
|
Buffer16 = PciSegmentRead16 (DeviceBaseAddress + R_PCI_SCC_OFFSET);
|
|
///
|
|
/// Clear Bus Number for PCI/PCI Bridge Device
|
|
///
|
|
if (Buffer16 == 0x0604) {
|
|
PciSegmentWrite32 (DeviceBaseAddress + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (RpIndex = 0; RpIndex < GetPchMaxPciePortNum (); RpIndex++) {
|
|
///
|
|
/// Clear bus numbers so that PCIe slots are hidden
|
|
///
|
|
Status = GetPchPcieRpDevFun (RpIndex, &RpDev, &RpFunc);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMBER_PCH, DEFAULT_PCI_BUS_NUMBER_PCH, (UINT32) RpDev, (UINT32) RpFunc, 0);
|
|
PciSegmentWrite32 (DeviceBaseAddress + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, 0);
|
|
}
|
|
}
|
|
|
|
///
|
|
/// Functions
|
|
///
|
|
typedef union {
|
|
struct {
|
|
UINT32 Low;
|
|
UINT32 High;
|
|
} Data32;
|
|
UINT64 Data;
|
|
} UINT64_STRUCT;
|
|
|
|
/**
|
|
Disable IGD VGA Decode Bits
|
|
**/
|
|
VOID
|
|
DisableIgdVgaDecodeBits (
|
|
VOID
|
|
)
|
|
{
|
|
UINT64 McD0BaseAddress;
|
|
UINT64 McD2BaseAddress;
|
|
|
|
///
|
|
/// Disable VGA Decode bits for IGD
|
|
///
|
|
McD2BaseAddress = PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, IGD_BUS_NUM, IGD_DEV_NUM, IGD_FUN_NUM, 0);
|
|
McD0BaseAddress = PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, SA_MC_BUS, SA_MC_DEV, SA_MC_FUN, 0);
|
|
|
|
if (PciSegmentRead16 (McD2BaseAddress + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
|
|
PciSegmentOr16 (McD0BaseAddress + R_SA_GGC, (UINT16) (B_SA_GGC_IVD_MASK | B_SA_GGC_VAMEN_MASK));
|
|
}
|
|
}
|
|
|
|
/**
|
|
Init and Install SA Hob
|
|
|
|
@param[in] MiscPeiPreMemConfig - Instance of SA_MISC_PEI_PREMEM_CONFIG
|
|
@param[out] SaDataHob - SA_DATA_HOB instance installed by this function
|
|
@param[out] SaConfigHob - SA_CONFIG_HOB instance installed by this function
|
|
@retval EFI_SUCCESS
|
|
**/
|
|
EFI_STATUS
|
|
InstallSaHob (
|
|
IN SA_MISC_PEI_PREMEM_CONFIG *MiscPeiPreMemConfig,
|
|
OUT SA_DATA_HOB **SaDataHobOut,
|
|
OUT SA_CONFIG_HOB **SaConfigHobOut
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
SA_DATA_HOB *SaDataHob;
|
|
SA_CONFIG_HOB *SaConfigHob;
|
|
SI_PREMEM_POLICY_PPI *SiPreMemPolicy;
|
|
CPU_SECURITY_PREMEM_CONFIG *CpuSecurityPreMemConfig;
|
|
CPU_TXT_PREMEM_CONFIG *CpuTxtPreMemConfig;
|
|
|
|
///
|
|
/// Create HOB for SA Data
|
|
///
|
|
Status = PeiServicesCreateHob (
|
|
EFI_HOB_TYPE_GUID_EXTENSION,
|
|
sizeof (SA_DATA_HOB),
|
|
(VOID **) &SaDataHob
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
///
|
|
/// Create HOB for SA Config
|
|
///
|
|
Status = PeiServicesCreateHob (
|
|
EFI_HOB_TYPE_GUID_EXTENSION,
|
|
sizeof (SA_CONFIG_HOB),
|
|
(VOID **) &SaConfigHob
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
///
|
|
/// Initialize default HOB data
|
|
///
|
|
SaDataHob->EfiHobGuidType.Name = gSaDataHobGuid;
|
|
DEBUG ((DEBUG_INFO, "SaDataHob->EfiHobGuidType.Name: %g\n", &SaDataHob->EfiHobGuidType.Name));
|
|
ZeroMem (&(SaDataHob->PrimaryDisplay), sizeof (SA_DATA_HOB) - sizeof (EFI_HOB_GUID_TYPE));
|
|
|
|
SaConfigHob->EfiHobGuidType.Name = gSaConfigHobGuid;
|
|
DEBUG ((DEBUG_INFO, "SaConfigHob->EfiHobGuidType.Name: %g\n", &SaConfigHob->EfiHobGuidType.Name));
|
|
ZeroMem (&(SaConfigHob->DprDirectory[0]), sizeof (SA_CONFIG_HOB) - sizeof (EFI_HOB_GUID_TYPE));
|
|
|
|
DEBUG ((DEBUG_INFO, "SaDataHob @ %X\n", SaDataHob));
|
|
DEBUG ((DEBUG_INFO, "SaDataHobSize - HobHeader: %X\n", sizeof (SA_DATA_HOB) - sizeof (EFI_HOB_GUID_TYPE)));
|
|
DEBUG ((DEBUG_INFO, "SaDataHobSize: %X\n", sizeof (SA_DATA_HOB)));
|
|
|
|
///
|
|
/// Update SA Config HOB
|
|
///
|
|
Status = PeiServicesLocatePpi(
|
|
&gSiPreMemPolicyPpiGuid,
|
|
0,
|
|
NULL,
|
|
(VOID **) &SiPreMemPolicy
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
Status = GetConfigBlock ((VOID *) SiPreMemPolicy, &gCpuSecurityPreMemConfigGuid, (VOID *) &CpuSecurityPreMemConfig);
|
|
ASSERT_EFI_ERROR (Status);
|
|
Status = GetConfigBlock ((VOID *) SiPreMemPolicy, &gCpuTxtPreMemConfigGuid, (VOID *) &CpuTxtPreMemConfig);
|
|
///
|
|
/// TXT DPR Directory Entry
|
|
///
|
|
SaConfigHob->DprDirectory[EnumDprDirectoryTxt].Type = DPR_DIRECTORY_TYPE_TXT;
|
|
if (CpuSecurityPreMemConfig->Txt) {
|
|
SaConfigHob->DprDirectory[EnumDprDirectoryTxt].Size = (UINT8) RShiftU64 ((UINT64) CpuTxtPreMemConfig->TxtDprMemorySize, 20);
|
|
}
|
|
|
|
SaConfigHob->CridEnable = (BOOLEAN) (UINTN) MiscPeiPreMemConfig->CridEnable;
|
|
|
|
(*SaDataHobOut) = SaDataHob;
|
|
(*SaConfigHobOut) = SaConfigHob;
|
|
DEBUG ((DEBUG_INFO, "SA HOBs installed\n"));
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Report the SA PCIe initialization code version.
|
|
|
|
@param[in] MiscPeiPreMemConfig - Instance of SA_MISC_PEI_PREMEM_CONFIG
|
|
|
|
@retval EFI_SUCCESS
|
|
**/
|
|
EFI_STATUS
|
|
ReportPcieVersion (
|
|
IN HOST_BRIDGE_PREMEM_CONFIG *HostBridgePreMemConfig
|
|
)
|
|
{
|
|
UINT32 Version;
|
|
|
|
DEBUG ((DEBUG_INFO, "***************** System Agent PCIe code version *****************\n"));
|
|
DEBUG ((DEBUG_INFO, "** Major version number is: %3d **\n", PcdGet8 (PcdSiliconInitVersionMajor)));
|
|
DEBUG ((DEBUG_INFO, "** Minor version number is: %3d **\n", PcdGet8 (PcdSiliconInitVersionMinor)));
|
|
DEBUG ((DEBUG_INFO, "** Rev version number is: %3d **\n", PcdGet8 (PcdSiliconInitVersionRevision)));
|
|
DEBUG ((DEBUG_INFO, "** Build number is: %3d **\n", PcdGet8 (PcdSiliconInitVersionBuild)));
|
|
DEBUG ((DEBUG_INFO, "******************************************************************\n"));
|
|
|
|
Version = (((UINT32) PcdGet8 (PcdSiliconInitVersionMajor)) << 24) |
|
|
(((UINT32) PcdGet8 (PcdSiliconInitVersionMinor)) << 16) |
|
|
(((UINT32) PcdGet8 (PcdSiliconInitVersionRevision)) << 8) |
|
|
(((UINT32) PcdGet8 (PcdSiliconInitVersionBuild)));
|
|
|
|
///
|
|
/// Store SA Reference Code version and SA PCIe code version in scrachpad registers
|
|
///
|
|
MmioWrite32 ((UINTN) (HostBridgePreMemConfig->DmiBar) + R_SA_DMIBAR_SCRATCHPAD0_OFFSET, Version);
|
|
MmioWrite32 ((UINTN) (HostBridgePreMemConfig->DmiBar) + R_SA_DMIBAR_SCRATCHPAD1_OFFSET, Version);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Create and Init Graphics Data Hob
|
|
|
|
@param[in] MiscPeiPreMemConfig - Instance of SA_MISC_PEI_PREMEM_CONFIG
|
|
@retval EFI_SUCCESS
|
|
**/
|
|
EFI_STATUS
|
|
CreateGfxDataHob (
|
|
IN SA_MISC_PEI_PREMEM_CONFIG *MiscPeiPreMemConfig
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
GFX_DATA_HOB *GfxDataHob;
|
|
|
|
GfxDataHob = NULL;
|
|
///
|
|
/// Create HOB for Graphics Data
|
|
///
|
|
Status = PeiServicesCreateHob (
|
|
EFI_HOB_TYPE_GUID_EXTENSION,
|
|
sizeof (GFX_DATA_HOB),
|
|
(VOID **) &GfxDataHob
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
if (GfxDataHob == NULL) {
|
|
DEBUG ((EFI_D_INFO, "Gfx Data Hob not Created\n"));
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
///
|
|
/// Initialize default HOB data
|
|
///
|
|
GfxDataHob->EfiHobGuidType.Name = gGraphicsDataHobGuid;
|
|
DEBUG ((DEBUG_INFO, "GfxDataHob->EfiHobGuidType.Name: %g\n", &GfxDataHob->EfiHobGuidType.Name));
|
|
ZeroMem (&(GfxDataHob->PrimaryDisplayDetection), sizeof (GFX_DATA_HOB) - sizeof (EFI_HOB_GUID_TYPE));
|
|
|
|
GfxDataHob->PrimaryDisplayDetection = IGD;
|
|
GfxDataHob->ExternalGfxScanEnable = (MiscPeiPreMemConfig->SkipExtGfxScan == DISABLED);
|
|
|
|
DEBUG ((DEBUG_INFO, "GfxDataHob @ %X\n", GfxDataHob));
|
|
DEBUG ((DEBUG_INFO, "GfxDataHobSize - HobHeader: %X\n", sizeof (GFX_DATA_HOB) - sizeof (EFI_HOB_GUID_TYPE)));
|
|
DEBUG ((DEBUG_INFO, "GfxDataHobSize: %X\n", sizeof (GFX_DATA_HOB)));
|
|
DEBUG ((DEBUG_INFO, "GfxDataHob->PrimaryDisplayDetection: %X\n", GfxDataHob->PrimaryDisplayDetection));
|
|
DEBUG ((DEBUG_INFO, "GfxDataHob->ExternalGfxScanEnable: %X\n", GfxDataHob->ExternalGfxScanEnable));
|
|
|
|
DEBUG ((DEBUG_INFO, "Gfx HOBs installed\n"));
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|