summaryrefslogtreecommitdiff
path: root/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/GraphicsInit.c
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Chipset/SystemAgent/SaInit/Pei/GraphicsInit.c')
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/GraphicsInit.c929
1 files changed, 929 insertions, 0 deletions
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/GraphicsInit.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/GraphicsInit.c
new file mode 100644
index 0000000..ab08eb3
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/GraphicsInit.c
@@ -0,0 +1,929 @@
+/** @file
+ PEIM to initialize both IGD, PEG and PCI graphics card.
+
+@copyright
+ Copyright (c) 1999 - 2013 Intel Corporation. All rights reserved
+ This software and associated documentation (if any) is furnished
+ under a license and may only be used or copied in accordance
+ with the terms of the license. Except as permitted by such
+ license, no part of this software or documentation may be
+ reproduced, stored in a retrieval system, or transmitted in any
+ form or by any means without the express written consent of
+ Intel Corporation.
+
+ This file contains an 'Intel Peripheral Driver' and 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
+
+**/
+#include "GraphicsInit.h"
+#include "CpuIA32.h"
+#include <Token.h>
+#define IGD_ENABLE 1
+#define IGD_DISABLE 0
+
+/**
+ GraphicsInit: Initialize the IGD if no other external graphics is present
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] SaPlatformPolicyPpi - SaPlatformPolicyPpi to access the GtConfig related information
+**/
+VOID
+GraphicsInit (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+{
+ DISPLAY_DEVICE PrimaryDisplay;
+ UINT8 GMSData;
+ UINT32 PciMmioLength;
+ UINT32 PchPcieMmioLength;
+ UINT32 PegMmioLength;
+ UINT32 IGfxMmioLength;
+ UINT32 TotalMmioLength;
+ BOOLEAN IGfxSupported;
+ UINT32 LoGTBaseAddress;
+ UINT32 HiGTBaseAddress;
+ UINT32 RegOffset;
+ UINT32 Data32And;
+ UINT32 Data32Or;
+ UINT32 Data32Mask;
+ UINT32 Result;
+ PEI_STALL_PPI *StallPpi;
+ EFI_STATUS Status;
+ UINT64 GttMmAdr;
+ UINTN MchBarBase;
+ CPU_FAMILY CpuFamilyId;
+
+ PciMmioLength = 0;
+ PchPcieMmioLength = 0;
+ PegMmioLength = 0;
+ IGfxMmioLength = 0;
+ GttMmAdr = 0;
+ MchBarBase = McD0PciCfg32 (0x48) &~BIT0;
+ CpuFamilyId = GetCpuFamily();
+
+ ///
+ /// Set the VGA Decode bits to a good known starting point where both PEG and
+ /// IGD VGA Decode Bits are both disabled.
+ ///
+ McD0PciCfg16Or (R_SA_GGC, B_SA_GGC_IVD_MASK);
+ PrimaryDisplay = IGD;
+
+ ///
+ /// Check if IGfx is supported
+ ///
+ IGfxSupported = (BOOLEAN) (McD2PciCfg16 (R_SA_IGD_VID) != 0xFFFF);
+
+ ///
+ /// Check external VGA devices
+ ///
+ CheckOffboardPcieVga (PeiServices, &PchPcieMmioLength, &PrimaryDisplay);
+ CheckAndInitializePegVga (
+ PeiServices,
+ SaPlatformPolicyPpi->PcieConfig->AlwaysEnablePeg,
+ &PrimaryDisplay,
+ SaPlatformPolicyPpi->GtConfig->PrimaryDisplay,
+ &PegMmioLength
+ );
+
+ ///
+ /// Temporarily program GttMmAdr
+ ///
+ GttMmAdr = SaPlatformPolicyPpi->GtConfig->GttMmAdr;
+
+ ///
+ /// Program GttMmAdr
+ ///
+ LoGTBaseAddress = (UINT32) (GttMmAdr & 0xFFFFFFFF);
+ HiGTBaseAddress = (UINT32) RShiftU64 ((GttMmAdr & 0xFFFFFFFF00000000), 32);
+ McD2PciCfg32 (R_SA_IGD_GTTMMADR) = LoGTBaseAddress | BIT2;
+ McD2PciCfg32 (R_SA_IGD_GTTMMADR + 4) = HiGTBaseAddress;
+
+ ///
+ /// Enable Bus Master and Memory access on 0:2:0
+ ///
+ McD2PciCfg16Or (R_SA_IGD_CMD, (BIT2 | BIT1));
+
+ ///
+ /// If primary display device is IGD or no other display detected then enable IGD
+ ///
+ if (IGfxSupported &&
+ (
+ (
+ ((PrimaryDisplay == IGD) || (SaPlatformPolicyPpi->GtConfig->PrimaryDisplay == IGD)) &&
+ (SaPlatformPolicyPpi->GtConfig->InternalGraphics != IGD_DISABLE)
+ ) || (SaPlatformPolicyPpi->GtConfig->InternalGraphics == IGD_ENABLE)
+ )
+ ) {
+
+ DEBUG ((EFI_D_INFO, "IGD enabled.\n"));
+
+ ///
+ /// Program GFX Memory by setting D0.F0.R 050h [7:3]
+ ///
+ McD0PciCfg16And (R_SA_GGC, ~(B_SA_GGC_GMS_MASK));
+
+ GMSData = SaPlatformPolicyPpi->GtConfig->IgdDvmt50PreAlloc;
+
+ McD0PciCfg8Or (R_SA_GGC, (GMSData << N_SA_GGC_GMS_OFFSET));
+
+ ///
+ /// Program Graphics GTT Memory D0:F0:R50h[9:8] = 10b => 2MB of GTT
+ ///
+ McD0PciCfg16AndThenOr (R_SA_GGC, ~(B_SA_GGC_GGMS_MASK), 1 << (N_SA_GGC_GGMS_OFFSET + 1));
+
+ ///
+ /// Set register D2.F0.R 062h [2:1] = `01b' to set a 256MByte aperture.
+ /// This must be done before Device 2 registers are enumerated.
+ ///
+ if (SaPlatformPolicyPpi->GtConfig->ApertureSize == APERTURE_SIZE_128MB) {
+ McD2PciCfg8And (R_SA_IGD_MSAC_OFFSET, ~(BIT2 + BIT1));
+ } else if (SaPlatformPolicyPpi->GtConfig->ApertureSize == APERTURE_SIZE_256MB) {
+ McD2PciCfg8AndThenOr (R_SA_IGD_MSAC_OFFSET, ~(BIT2 + BIT1), BIT1);
+ } else {
+ McD2PciCfg8Or (R_SA_IGD_MSAC_OFFSET, (BIT2 + BIT1));
+ }
+ ///
+ /// Enable IGD VGA Decode. This is needed so the Class Code will
+ /// be correct for the IGD Device when determining which device
+ /// should be primary. If disabled, IGD will show up as a non VGA device.
+ ///
+ if ((SaPlatformPolicyPpi->GtConfig->PrimaryDisplay != IGD) && (PrimaryDisplay != IGD)) {
+ ///
+ /// If IGD is forced to be enabled, but is a secondary display, disable IGD VGA Decode
+ ///
+ McD0PciCfg16Or (R_SA_GGC, B_SA_GGC_IVD_MASK);
+ DEBUG ((EFI_D_INFO, "IGD VGA Decode is disabled because it's not a primary display.\n"));
+ } else {
+ McD0PciCfg16And (R_SA_GGC, ~(B_SA_GGC_IVD_MASK));
+ }
+
+ FindPciDeviceMmioLength (0, 2, 0, &IGfxMmioLength);
+
+ if ((SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_12) && (SaPlatformPolicyPpi->GtConfig->PanelPowerEnable == 1)) {
+ ///
+ /// Panel Enable VDD bit
+ ///
+ Mmio32Or (GttMmAdr, 0xc7204, 0x8);
+ }
+ } else {
+
+ Status = (*PeiServices)->LocatePpi (PeiServices, &gPeiStallPpiGuid, 0, NULL, &StallPpi);
+ ASSERT_PEI_ERROR (PeiServices, Status);
+
+ if (CpuFamilyId == EnumCpuHswUlt) {
+ ///
+ /// For HSW ULT, Disable LCPLL
+ /// Set LCPLL_CTL (GTTMMADR Offset 0x130040) PLL_disable (Bit 31) to 1b to disable LCPLL.
+ /// Poll for LCPLL_CTL PLL_lock (Bit 30) = 0b to indicate LCPLL lost lock.Timeout and continue after 1 ms.
+ /// Set D_COMP COMP_DISABLE (MCHBAR offset 0x5F0C Bit 0)to 1b.
+ /// Wait > 100 ns for write to complete.
+ /// Poll for D_COMP RCOMP_IN_PROGRESS Bit 9 = 0b.Timeout and continue after 1 ms.
+ ///
+
+ RegOffset = 0x130040;
+ Data32And = 0xFFFFFFFF;
+ Data32Or = BIT31;
+ Mmio32AndThenOr (GttMmAdr, RegOffset, Data32And, Data32Or);
+
+ if (IGfxSupported) {
+ Data32Mask = BIT30;
+ Result = 0;
+ PollGtReady (PeiServices, StallPpi, GttMmAdr, RegOffset, Data32Mask, Result);
+ }
+
+ RegOffset = 0x5F0C;
+ Data32And = 0xFFFFFFFF;
+ Data32Or = BIT0;
+ Mmio32AndThenOr (MchBarBase, RegOffset, Data32And, Data32Or);
+
+ ///
+ /// 1uSec wait
+ ///
+ StallPpi->Stall (PeiServices, StallPpi, 1);
+
+ if (IGfxSupported) {
+ Data32Mask = BIT9;
+ Result = 0;
+ PollGtReady (PeiServices, StallPpi, MchBarBase, RegOffset, Data32Mask, Result);
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "Disable IGD Device.\n"));
+ ///
+ /// Disable IGD device
+ ///
+ /// Register D0:F0 Offset 50h [7:3] = '00000b'.
+ /// This prevents UMA memory from being pre-allocated to IGD.
+ /// Set D0:F0 Offset 50h [9:8] = '00b'.
+ /// GTT Graphics Memory Size to 0
+ /// Set VGA Disable (IVD) in D0:F0 Offset 50h [1] = '1b'.
+ ///
+ McD0PciCfg16AndThenOr (R_SA_GGC, ~(B_SA_GGC_GGMS_MASK | B_SA_GGC_GMS_MASK), B_SA_GGC_IVD_MASK);
+ SaPlatformPolicyPpi->GtConfig->GttSize = 0;
+ SaPlatformPolicyPpi->GtConfig->IgdDvmt50PreAlloc = 0;
+
+ ///
+ /// Disable IGD. D0.F0.R 054h [4] = '0b'.
+ ///
+ McD0PciCfg8And (R_SA_DEVEN, ~(B_SA_DEVEN_D2EN_MASK));
+ }
+
+ TotalMmioLength = PciMmioLength + PchPcieMmioLength + PegMmioLength + IGfxMmioLength;
+ DEBUG ((EFI_D_INFO, "TotalMmioLength: 0x%08X bytes\n", TotalMmioLength));
+
+ ///
+ /// Disable Bus Master and Memory access on 0:2:0 and clear GTTMMADR
+ ///
+ McD2PciCfg16And (R_SA_IGD_CMD, ~(BIT2 | BIT1));
+ McD2PciCfg32And (R_SA_IGD_GTTMMADR, 0x0);
+ McD2PciCfg32And (R_SA_IGD_GTTMMADR + 0x4, 0x0);
+
+ ///
+ /// Determine MMIO Size for Dynamic Tolud
+ ///
+ if (SaPlatformPolicyPpi->MemConfig->MaxTolud == 0x00) {
+ ///
+ /// if total MMIO need 1GB or over
+ ///
+ if (TotalMmioLength >= 0x40000000) {
+ SaPlatformPolicyPpi->GtConfig->MmioSize = 0x800;
+ }
+ ///
+ /// if total MMIO need 728MB~1GB
+ ///
+ else if (TotalMmioLength >= 0x30000000) {
+ SaPlatformPolicyPpi->GtConfig->MmioSize = 0x700;
+ }
+ ///
+ /// if total MMIO need 512MB~728MB
+ ///
+ else if (TotalMmioLength >= 0x20000000) {
+ SaPlatformPolicyPpi->GtConfig->MmioSize = 0x600;
+ }
+ ///
+ /// if total MMIO need 256MB~512MB
+ ///
+ else if (TotalMmioLength >= 0x10000000) {
+ SaPlatformPolicyPpi->GtConfig->MmioSize = 0x500;
+ }
+ ///
+ /// if total MMIO need less than 256MB
+ ///
+ else {
+ SaPlatformPolicyPpi->GtConfig->MmioSize = 0x400;
+ }
+ }
+}
+
+/**
+ CheckAndInitializePegVga: Check if PEG card is present and configure accordingly
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] AlwaysEnablePeg - 0 - Peg is not always enabled.
+ @param[in, out] PrimaryDisplay - Primary Display - default is IGD
+ @param[in] PrimaryDisplaySelection - Primary display selection from BIOS Setup
+ @param[in, out] PegMmioLength - Total PEG MMIO length on all PEG ports
+**/
+VOID
+CheckAndInitializePegVga (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN UINT8 AlwaysEnablePeg,
+ IN OUT DISPLAY_DEVICE *PrimaryDisplay,
+ IN UINT8 PrimaryDisplaySelection,
+ IN OUT UINT32 *PegMmioLength
+ )
+{
+ UINT8 ClassCode;
+ BOOLEAN IgdPresent;
+ UINT8 PegBus;
+ UINT8 PegDev;
+ UINT8 PegFunc;
+ UINT16 PegDevenReg;
+ UINT8 PegComplete;
+ UINT16 PegEnable;
+ BOOLEAN CardDetect;
+ UINT32 MmioLength;
+ UINT8 Func;
+ UINT8 MaxFunction;
+ UINT8 HeaderType;
+ UINT8 PegVgaFunc;
+
+ PEG_DEVEN PegDevenTable[] = {
+ ///
+ /// Bus, Device, Function, DevenMask
+ ///
+ {
+ SA_PEG_BUS_NUM,
+ SA_PEG10_DEV_NUM,
+ SA_PEG10_FUN_NUM,
+ BIT3
+ }
+// AMI_OVERRID >>
+#if RC_PEG_1 == 1
+,
+ {
+ SA_PEG_BUS_NUM,
+ SA_PEG11_DEV_NUM,
+ SA_PEG11_FUN_NUM,
+ BIT2
+ }
+#endif
+#if RC_PEG_2 == 1
+,
+ {
+ SA_PEG_BUS_NUM,
+ SA_PEG12_DEV_NUM,
+ SA_PEG12_FUN_NUM,
+ BIT1
+ }
+#endif
+// AMI_OVERRID <<
+ };
+
+ MmioLength = 0;
+ CardDetect = FALSE;
+ PegVgaFunc = 0xFF;
+
+ ///
+ /// Read the DEVEN register for PEG0/1/2 controllers configuration
+ ///
+ PegDevenReg = MmPci16 (0, SA_MC_BUS, 0, 0, R_SA_DEVEN) & (BIT3 + BIT2 + BIT1);
+
+ ///
+ /// If IGD is disabled
+ /// or not present IgdPresent is set to false
+ ///
+ if (McD2PciCfg16 (PCI_VID) == 0xFFFF) {
+ IgdPresent = FALSE;
+ } else {
+ IgdPresent = TRUE;
+ }
+ ///
+ /// Scan PEG device vs DEVEN register for PEG controllers configuration
+ ///
+ for (PegComplete = 0; PegComplete < ((sizeof (PegDevenTable)) / (sizeof (PEG_DEVEN))); PegComplete++) {
+
+ PegBus = PegDevenTable[PegComplete].Bus;
+ PegDev = PegDevenTable[PegComplete].Device;
+ PegFunc = PegDevenTable[PegComplete].Function;
+ PegEnable = PegDevenTable[PegComplete].DevenMask;
+
+ if ((PegDevenReg & PegEnable) == 0) {
+ continue;
+ }
+ ///
+ /// Check for a card presence in the PEG slot.
+ /// We don't know if it's a graphics card yet.
+ ///
+ if ((MmPci8 (0, PegBus, PegDev, PegFunc, R_SA_PEG_SLOTSTS_OFFSET) & BIT6) == 0) {
+ continue;
+ }
+ ///
+ /// Set PEG PortBus = 1 to Read Endpoint.
+ ///
+ MmPci32AndThenOr (0, PegBus, PegDev, PegFunc, PCI_PBUS, 0xFF0000FF, 0x00010100);
+
+ ///
+ /// 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.
+ ///
+ MmPci16 (0, 1, 0, 0, PCI_VID) = 0;
+
+ ///
+ /// Read Vendor ID to check if endpoint exists
+ /// if no device exists, then check next device
+ ///
+ if (MmPci16 (0, 1, 0, 0, PCI_VID) == 0xFFFF) {
+ continue;
+ }
+ ///
+ /// Check for a multifunction device
+ ///
+ HeaderType = MmPci8 (0, 1, 0, 0, PCI_HEADER_TYPE_OFFSET);
+ if ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) != 0) {
+ MaxFunction = 7;
+ } else {
+ MaxFunction = 0;
+ }
+ ///
+ /// Calculate total PEG MMIO length on all functions of the endpoint
+ ///
+ for (Func = 0; Func <= MaxFunction; Func++) {
+ if (MmPci16 (0, 1, 0, Func, PCI_VID) == 0xFFFF) {
+ continue;
+ }
+
+ FindPciDeviceMmioLength (1, 0, Func, &MmioLength);
+ *PegMmioLength += MmioLength;
+ }
+ ///
+ /// Perform PEG Endpoint Class Code Check. If the Endpoint Class Code is
+ /// not GFX, then the Port is being used as a standard PCI Express Port.
+ ///
+ ClassCode = MmPci8 (0, 1, 0, 0, PCI_BCC);
+ if (ClassCode == 0x03) {
+ ///
+ /// Disable PEG if IGD or PCI VGA take precedence.
+ ///
+ if (AlwaysEnablePeg == 0) {
+ ///
+ /// If IGD is present and selected as primary, skip the PEG VGA enabling
+ ///
+ if (IgdPresent && (PrimaryDisplaySelection == IGD)) {
+ MmPci32And (0, PegBus, PegDev, PegFunc, PCI_PBUS, 0xFF0000FF);
+ continue;
+ }
+ ///
+ /// If PCI video card was detected, skip the PEG VGA enabling
+ ///
+ if (*PrimaryDisplay == PCI) {
+ MmPci32And (0, PegBus, PegDev, PegFunc, PCI_PBUS, 0xFF0000FF);
+ continue;
+ }
+ }
+ ///
+ /// Enable PEG video and Execute 16-bit address decodes on VGA I/O accesses
+ ///
+ /// Check if PEG VGA already detected
+ ///
+ if (*PrimaryDisplay != PEG) {
+ MmPci16Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_BCTRL_OFFSET, (BIT3 + BIT4));
+ *PrimaryDisplay = PEG;
+ PegVgaFunc = PegFunc;
+ DEBUG ((EFI_D_INFO, "PCIe card on PEG%x%x (%x:%x:%x) enabled as VGA.\n", PegDev, PegFunc, PegBus, PegDev, PegFunc));
+ }
+ }
+
+ if (ClassCode == 0x06) {
+ CardDetect = EnumerateBridgeDevice (PegBus, PegDev, PegFunc, PegMmioLength);
+ if (CardDetect == TRUE) {
+ ///
+ /// Check if PEG VGA already detected
+ ///
+ if (*PrimaryDisplay != PEG) {
+ MmPci16Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_BCTRL_OFFSET, (BIT3 + BIT4));
+ *PrimaryDisplay = PEG;
+ PegVgaFunc = PegFunc;
+ DEBUG ((EFI_D_INFO, "PCIe card on PEG%x%x (%x:%x:%x) enabled as VGA.\n", PegDev, PegFunc, PegBus, PegDev, PegFunc));
+ }
+ }
+ }
+ ///
+ /// Restore bus numbers on the PEG bridge.
+ ///
+ MmPci32And (0, PegBus, PegDev, PegFunc, PCI_PBUS, 0xFF0000FF);
+ } // End of the for Loop
+
+ ///
+ /// If a PEG device is used for primary graphics, set the ISAEN bit on all other PEG ports.
+ ///
+ if (PegVgaFunc != 0xFF) {
+ for (PegComplete = 0; PegComplete < ((sizeof (PegDevenTable)) / (sizeof (PEG_DEVEN))); PegComplete++) {
+ if (PegVgaFunc == PegComplete) {
+ continue;
+ }
+ PegBus = PegDevenTable[PegComplete].Bus;
+ PegDev = PegDevenTable[PegComplete].Device;
+ PegFunc = PegDevenTable[PegComplete].Function;
+ MmPci16Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_BCTRL_OFFSET, BIT2);
+ DEBUG ((EFI_D_INFO, "PEG%x%x (%x:%x:%x) ISAEN has been set.\n", PegDev, PegFunc, PegBus, PegDev, PegFunc));
+ }
+ }
+}
+
+/**
+ 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;
+ UINT32 i;
+ UINT64 BarAlign;
+ UINT8 ClassCode;
+
+ *MmioLength = 0;
+ BarAlign = PCI_BAR_OLD_ALIGN;
+
+ ClassCode = MmPci8 (0, BusNum, DevNum, FunNum, PCI_BCC);
+ if (ClassCode == PCI_CLASS_BRIDGE) {
+ return ;
+ }
+
+ for (i = PCI_BAR0; i <= PCI_BAR5; i += 4) {
+ SavedBAR = MmPci32 (0, BusNum, DevNum, FunNum, i);
+ ///
+ /// Check BAR is read-only or not
+ ///
+ MmPci32And (0, BusNum, DevNum, FunNum, i, (UINT32) PCI_BAR_NOCHANGE);
+ MmPci32Or (0, BusNum, DevNum, FunNum, i, BarAlign);
+ if (SavedBAR == MmPci32 (0, BusNum, DevNum, FunNum, i)) {
+ ///
+ /// Restore BAR as original value
+ ///
+ MmPci32 (0, BusNum, DevNum, FunNum, i) = SavedBAR;
+ continue;
+ }
+ ///
+ /// If BAR is not memory map, skip it
+ ///
+ if ((SavedBAR & BIT0) != 0) {
+ ///
+ /// Restore BAR as original value
+ ///
+ MmPci32 (0, BusNum, DevNum, FunNum, i) = SavedBAR;
+ continue;
+ }
+ ///
+ /// Calculate the MMIO length through BAR
+ ///
+ CurrentMmioLength = ~(MmPci32 (0, BusNum, DevNum, FunNum, i) &~0xF) + 1;
+ *MmioLength += CurrentMmioLength;
+
+ ///
+ /// Restore BAR as original value
+ ///
+ MmPci32 (0, BusNum, DevNum, FunNum, i) = SavedBAR;
+ ///
+ /// Skip next index if BAR is 64bit address
+ ///
+ if ((SavedBAR & (BIT1 + BIT2)) == 0x4) {
+ i += 4;
+ }
+ }
+}
+
+/**
+ CheckOffboardPcieVga: Check if off board PCIe graphics Card is present
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in, out] PchPcieMmioLength - Total PCIe MMIO length on all PCH root ports
+ @param[in, out] PrimaryDisplay - Primary Display - default is IGD
+**/
+VOID
+CheckOffboardPcieVga (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN OUT UINT32 *PchPcieMmioLength,
+ IN OUT DISPLAY_DEVICE *PrimaryDisplay
+ )
+{
+ UINT8 PortNo;
+ UINT32 PcieBusNum;
+ UINT8 Bus;
+ UINT8 Dev;
+ UINT8 Func;
+ UINT8 MaxFunction;
+ UINT8 SubBusNum;
+ UINT8 HeaderType;
+ UINT16 Buffer16;
+ BOOLEAN CardDetect;
+ UINT32 MmioLength;
+
+ MmioLength = 0;
+
+ ///
+ /// Initialize Secondary and Subordinate bus number for first Pcie root port
+ ///
+ PcieBusNum = 0x00010100;
+
+ SubBusNum = 0;
+
+ CardDetect = FALSE;
+
+ for (PortNo = 0; PortNo < GetPchMaxPciePortNum (); PortNo++) {
+ ///
+ /// Check if root port exists
+ ///
+ if (MmPci16 (0, 0, 0x1C, PortNo, PCI_VID) == 0xFFFF) {
+ continue;
+ }
+
+ MmPci32 (0, 0, 0x1c, PortNo, PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET) = PcieBusNum;
+ Bus = MmPci8 (0, 0, 0x1c, PortNo, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
+
+ ///
+ /// Assign temporary subordinate bus number so that device this bridge can be seen
+ ///
+ MmPci8 (0, 0, 0x1c, PortNo, 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.
+ ///
+ MmPci16 (0, Bus, 0, 0, PCI_VID) = 0;
+
+ SubBusNum = EnumerateDownstream (Bus);
+ ///
+ /// Update the actual subordinate bus number
+ ///
+ MmPci8 (0, 0, 0x1c, PortNo, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET) = SubBusNum;
+ PcieBusNum = (SubBusNum + 1) << 8;
+ }
+
+ 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
+ ///
+ if (MmPci16 (0, Bus, Dev, 0, PCI_VID) == 0xFFFF) {
+ continue;
+ }
+ ///
+ /// Check for a multifunction device
+ ///
+ HeaderType = MmPci8 (0, Bus, Dev, 0, PCI_HDR);
+ if ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) != 0) {
+ MaxFunction = 7;
+ } else {
+ MaxFunction = 0;
+ }
+
+ for (Func = 0; Func <= MaxFunction; Func++) {
+ if (MmPci16 (0, Bus, Dev, Func, PCI_VID) == 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 (MmPci16 (0, Bus, Dev, Func, PCI_SCC) == 0x0300) {
+ if (CardDetect != TRUE) {
+ *PrimaryDisplay = PCI;
+ DEBUG ((EFI_D_INFO, "PCH PCIe Graphics Card enabled.\n"));
+ CardDetect = TRUE;
+ }
+ }
+ }
+ }
+ }
+ ///
+ /// 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
+ ///
+ if (MmPci16 (0, Bus, Dev, 0, PCI_VID) == 0xFFFF) {
+ continue;
+ }
+
+ Buffer16 = MmPci16 (0, Bus, Dev, 0, PCI_SCC);
+ ///
+ /// Clear Bus Number for PCI/PCI Bridge Device
+ ///
+ if (Buffer16 == 0x0604) {
+ MmPci32 (0, Bus, Dev, 0, PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET) = 0;
+ }
+ }
+ }
+
+ for (PortNo = 0; PortNo < GetPchMaxPciePortNum (); PortNo++) {
+ ///
+ /// Clear bus numbers so that PCIe slots are hidden
+ ///
+ MmPci32 (0, 0, 0x1c, PortNo, PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET) = 0;
+ }
+}
+
+/**
+ 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
+ )
+{
+ 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
+ ///
+ if (MmPci16 (0, BusNum, DevNum, 0, PCI_VID) == 0xFFFF) {
+ continue;
+ }
+
+ Buffer16 = MmPci16 (0, BusNum, DevNum, 0, PCI_SCC);
+ ///
+ /// Check for PCI/PCI Bridge Device Base Class 6 with subclass 4
+ ///
+ if (Buffer16 == 0x0604) {
+ SecBus++;
+ MmPci8 (0, BusNum, DevNum, 0, PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET) = BusNum;
+ MmPci8 (0, BusNum, DevNum, 0, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET) = SecBus;
+ ///
+ /// Assign temporary subordinate bus number so that device behind this bridge can be seen
+ ///
+ MmPci8 (0, BusNum, DevNum, 0, 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.
+ ///
+ MmPci16 (0, SecBus, 0, 0, PCI_VID) = 0;
+
+ ///
+ /// Enumerate bus behind this bridge by calling this funstion recursively
+ ///
+ SubBus = EnumerateDownstream (SecBus);
+ ///
+ /// Update the correct subordinate bus number
+ ///
+ MmPci8 (0, BusNum, DevNum, 0, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET) = SubBus;
+ SecBus = SubBus;
+ }
+ }
+
+ if (SubBus == 0) {
+ return BusNum;
+ } else {
+ return SubBus;
+ }
+}
+
+/**
+ This function enumerate the bridge on the device
+
+ @param[in] PegBus - Particular Bus number
+ @param[in] PegDev - Particular Device number
+ @param[in] PegFunc - Particular Func number
+ @param[in, out] PegMmioLength - PEG MMIO length
+
+ @retval CardDetect : TRUE if current bridge device has a Graphics card.
+ @retval CardDetect : FALSE if current bridge device has no Graphics card.
+**/
+BOOLEAN
+EnumerateBridgeDevice (
+ IN UINT8 PegBus,
+ IN UINT8 PegDev,
+ IN UINT8 PegFunc,
+ IN OUT UINT32 *PegMmioLength
+ )
+{
+
+ UINT8 Bus;
+ UINT8 Dev;
+ UINT8 SubBusNum;
+ UINT16 Buffer16;
+ BOOLEAN CardDetect;
+
+ CardDetect = FALSE;
+
+ ///
+ /// Temporarily program the secondary and subordinate bus numbers
+ /// of PEG bridge to (1, 0xFF) so that devices behind the bridge can be seen
+ ///
+ Bus = 1;
+ MmPci8 (0, PegBus, PegDev, PegFunc, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET) = Bus;
+ MmPci8 (0, PegBus, PegDev, PegFunc, 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.
+ ///
+ MmPci16 (0, Bus, 0, 0, PCI_VID) = 0;
+
+ SubBusNum = EnumerateDownstream (Bus);
+
+ 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
+ ///
+ if (MmPci16 (0, Bus, Dev, 0, PCI_VID) == 0xFFFF) {
+ continue;
+
+ }
+ ///
+ /// Video cards can have Base Class 0 with Sub-class 1
+ /// or Base Class 3.
+ ///
+ if (MmPci16 (0, Bus, Dev, 0, PCI_SCC) == 0x0300) {
+ FindPciDeviceMmioLength (Bus, Dev, 0, PegMmioLength);
+ CardDetect = TRUE;
+ break;
+ }
+ }
+
+ if (CardDetect == TRUE) {
+ break;
+ }
+ }
+ ///
+ /// 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
+ ///
+ if (MmPci16 (0, Bus, Dev, 0, PCI_VID) == 0xFFFF) {
+ continue;
+ }
+
+ Buffer16 = MmPci16 (0, Bus, Dev, 0, PCI_SCC);
+ ///
+ /// Clear Bus Number for PCI/PCI Bridge Device
+ ///
+ if (Buffer16 == 0x0604) {
+ MmPci32 (0, Bus, Dev, 0, PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET) = 0;
+ }
+ }
+ }
+ ///
+ /// Clear the bus numbers on the PEG bridge
+ ///
+ MmPci32 (0, PegBus, PegDev, PegFunc, PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET) = 0;
+
+ return CardDetect;
+}
+
+/**
+
+ "Poll Status" for GT Readiness
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] StallPpi - Pointer to Stall PPI
+ @param[in] Base - Base address of MMIO
+ @param[in] Offset - MMIO Offset
+ @param[in] Mask - Mask
+ @param[in] Result - Value to wait for
+
+
+**/
+VOID
+PollGtReady (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi,
+ UINT64 Base,
+ UINT32 Offset,
+ UINT32 Mask,
+ UINT32 Result
+ )
+{
+ UINT32 GtStatus;
+ UINT16 StallCount;
+
+ StallCount = 0;
+
+ ///
+ /// Register read
+ ///
+ GtStatus = Mmio32 (Base, Offset);
+
+ while (((GtStatus & Mask) != Result) && (StallCount < GT_WAIT_TIMEOUT)) {
+
+ GtStatus = Mmio32 (Base, Offset);
+ ///
+ /// 1mSec wait
+ ///
+ StallPpi->Stall (PeiServices, StallPpi, 1000);
+ StallCount = StallCount + 1;
+ }
+
+ ASSERT ((StallCount != GT_WAIT_TIMEOUT));
+}