diff options
Diffstat (limited to 'ReferenceCode/Chipset/SystemAgent/SaInit/Pei')
24 files changed, 10043 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)); +} diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/GraphicsInit.h b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/GraphicsInit.h new file mode 100644 index 0000000..6d060cb --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/GraphicsInit.h @@ -0,0 +1,219 @@ +/** @file + Graphics header file + +@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 +**/ +#ifndef _GRAPHICS_INIT_H_ +#define _GRAPHICS_INIT_H_ + +#include "EdkIIGluePeim.h" +#include "SaAccess.h" +#include "PchAccess.h" +#include "EdkIIGluePcdPciExpressLib.h" +#include "EdkIIGlueConfig.h" +#include "Pci22.h" +#include "PchPlatformLib.h" +#include "CpuRegs.h" +#include "CpuPlatformLib.h" + +/// +/// Driver Consumed PPI Prototypes +/// +#include EFI_PPI_DEPENDENCY (SaPlatformPolicy) + +typedef struct { + UINT8 Bus; + UINT8 Device; + UINT8 Function; + UINT16 DevenMask; +} PEG_DEVEN; + +typedef enum { + IGD = 0, + PEG, + PCI, + DISPLAY_DEVICE_MAX +} DISPLAY_DEVICE; + +typedef enum { + VBIOS_DEFAULT = 0, + CRT, + LFP, + CRT_LFP, + TV, + LFPSDVO, + EFP, + TVSDVO, + CRT_LFPSDVO, + CRT_EFP, + IGD_BOOT_TYPE_MAX +} IGD_BOOT_TYPE; + +typedef enum { + GMS_FIXED = 0, + GMS_DVMT, + GMS_FIXED_DVMT, + GMS_MAX +} GRAPHICS_MEMORY_SELECTION; + +typedef enum { + GM_32M = 1, + GM_64M = 2, + GM_128M = 4, + GM_MAX +} STOLEN_MEMORY; + +typedef enum { + PAVP_DISABLED = 0, + PAVP_LITE, + PAVP_HIGH +} PAVP_MODE; + +#define GTTMMADR_SIZE_4MB 0x400000 +#define GTT_SIZE_2MB 2 +#define GT_WAIT_TIMEOUT 3000 ///< ~3 seconds + +#define APERTURE_SIZE_128MB 1 +#define APERTURE_SIZE_256MB 2 +#define APERTURE_SIZE_512MB 3 + +/** + 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 + ) +; + +/** + CheckOffboardPciVga: Check if off board PCI graphics Card is present + + @param[in] PeiServices - Pointer to the PEI services table + @param[in, out] PciMmioLength - PCI MMIO length + @param[in, out] PrimaryDisplay - Primary Display - default is IGD +**/ +VOID +CheckOffboardPciVga ( + IN EFI_PEI_SERVICES **PeiServices, + IN OUT UINT32 *PciMmioLength, + IN OUT DISPLAY_DEVICE *PrimaryDisplay + ) +; + +/** + 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 + ) +; + +/** + 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 + ) +; + +/** + This function enumerate all downstream bridge. + + @param[in] BusNum - Primary bus number of current bridge + + @retval Current bus number: if current bus is an enpoint device + @retval subordinate bus number: if current bus is a bridge +**/ +UINT8 +EnumerateDownstream ( + IN UINT8 BusNum + ) +; + +/** + 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 + ) +; + +/** + + "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 + ) +; + +#endif diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PciExpressInit.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PciExpressInit.c new file mode 100644 index 0000000..bead6ce --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PciExpressInit.c @@ -0,0 +1,2987 @@ +/** @file + PEI Function to initialize SA PciExpress. + +@copyright + Copyright (c) 1999 - 2014 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 "PciExpressInit.h" +#include "PcieTraining.h" +#include "PchPlatformLib.h" + +#include <Token.h> //AMI_OVERRIDE + +#ifdef PEG_FLAG +#include EFI_GUID_DEFINITION (SaDataHob) + +#define SA_PEG_VMARGIN_UP 0 +#define SA_PEG_VMARGIN_DOWN 1 + +#define SA_PEG_LINK_DISABLE_MAXWAIT 100*10 + +VOID +ReportPcieLinkStatus ( + IN UINT8 PegBus, + IN UINT8 PegDev, + IN UINT8 PegFunc +) +/** + This function reports a PEG controller's link status + + @param[in] PegBus - Peg Bus + @param[in] PegDev - Peg Device + @param[in] PegFunc - Peg Function + + @retval None +**/ +{ + UINT32 Deven; + UINT16 LinkStatus; + UINT8 LinkWidth; + UINT8 LinkSpeed; + UINT16 Vc0Pending; + + Deven = MmPci32 (0, SA_MC_BUS, SA_MC_DEV, SA_MC_FUN, R_SA_DEVEN); + Deven = (Deven >> 1) & 0x7; + DEBUG ((EFI_D_INFO, "PEG%x%x (%x:%x:%x) - ", PegDev, PegFunc, PegBus, PegDev, PegFunc)); + if (((Deven >> (SA_PEG_MAX_FUN - 1 - PegFunc)) & 0x1) == 0x1) { + LinkStatus = MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_LSTS_OFFSET); + LinkWidth = (LinkStatus >> 4) & 0x3F; + LinkSpeed = LinkStatus & 0xF; + Vc0Pending = ((MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC0RSTS_OFFSET)) >> 1) & 0x1; + DEBUG ((EFI_D_INFO, "Trained to x%d at Gen%d.", LinkWidth, LinkSpeed)); + DEBUG ((EFI_D_INFO, " VC0 Negotiation Pending = %d.", Vc0Pending)); + DEBUG ((EFI_D_INFO, "\n")); + } else { + DEBUG ((EFI_D_INFO, "Disabled.\n")); + } +} + +VOID +WaitForVc0Negotiation ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_STALL_PPI *StallPpi, + IN UINT8 PegBus, + IN UINT8 PegDev, + IN UINT8 PegFunc +) +/** + This function prints the time required for VC0 Negotiation Pending to be cleared. Quits after 100 msec. + + @param[in] PeiServices - Pointer to the PEI services table + @param[in] StallPpi - Pointer to PEI_STALL_PPI + @param[in] PegBus - Peg Bus + @param[in] PegDev - Peg Device + @param[in] PegFunc - Peg Function + + @retval None +**/ +{ + UINT32 Deven; + UINT32 MsecWait; + UINT16 Vc0Pending; + + Deven = MmPci32 (0, SA_MC_BUS, SA_MC_DEV, SA_MC_FUN, R_SA_DEVEN); + Deven = (Deven >> 1) & 0x7; + if (((Deven >> (SA_PEG_MAX_FUN - 1 - PegFunc)) & 0x1) == 0x1) { + MsecWait = 0; + Vc0Pending = ((MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC0RSTS_OFFSET)) >> 1) & 0x1; + + while (Vc0Pending && (MsecWait < 100)) { + MsecWait++; + StallPpi->Stall (PeiServices, StallPpi, STALL_ONE_MILLI_SECOND); + Vc0Pending = ((MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC0RSTS_OFFSET)) >> 1) & 0x1; + } + DEBUG ((EFI_D_INFO, "PEG%x%x (%x:%x:%x) - VC0 Negotiation Pending = %x after %d msec.\n", + PegDev, PegFunc, PegBus, PegDev, PegFunc, Vc0Pending, MsecWait)); + } +} + +VOID +GracefulLinkStatusStall ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_STALL_PPI *StallPpi, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN SA_DATA_HOB *SaDataHob, + IN UINT8 HwStrap + ) +/** + If we have a record of links that did not train from last boot, then do not stall for them + For links that did train last boot, stall until they train or 100ms pass + + @param[in] PeiServices - Pointer to the PEI services table + @param[in] StallPpi - Pointer to PEI_STALL_PPI + @param[in] SaPlatformPolicyPpi - Pointer to SA_PLATFORM_POLICY_PPI + @param[in] SaDataHob - Pointer to SA_DATA_HOB + @param[in] HwStrap - HwStrap configuration from FUSESCMN + + @retval None +**/ +{ + UINT8 LinkStatusGood; + UINT8 PegLinkFailMask; + UINT8 i; + UINT8 PegDev; + UINT8 PegFunc; + UINT8 CurrentPegFuncBit; + UINT8 SkipFuncMask; + EFI_STATUS Status; + EFI_BOOT_MODE BootMode; + + PegLinkFailMask = 0; + /// + /// If this is S3 Resume or Warm Boot, check if PEG delay can be skipped when no PEG devices populated. + /// + Status = (*PeiServices)->GetBootMode (PeiServices, &BootMode); + ASSERT_EFI_ERROR (Status); + if ((BootMode == BOOT_ON_S3_RESUME) || (GetPchPmStatus (WarmBoot) == TRUE)) { + if ((SaDataHob != NULL) && (SaDataHob->PegDataValid)) { + if (SaDataHob->PegData.PegLinkFailMask != 0) { + PegLinkFailMask = SaDataHob->PegData.PegLinkFailMask; + DEBUG ((EFI_D_INFO, "Previous Link Training Fail Mask 0x%2.2X\n", SaDataHob->PegData.PegLinkFailMask)); + } else { + PegLinkFailMask = 0xFF; + for (i = 0; i < SA_PEG_MAX_FUN; i++) { + PegLinkFailMask &= (UINT8) ~(0x1 << i); + } + } + } + } + DEBUG ((EFI_D_INFO, "New Link Training Fail Mask 0x%2.2X\n", PegLinkFailMask)); + + switch (HwStrap) { + case SA_PEG_x16_x0_x0: + SkipFuncMask = BIT2 | BIT1; + break; + + case SA_PEG_x8_x8_x0: + SkipFuncMask = BIT2; + break; + + default: + case SA_PEG_x8_x4_x4: + SkipFuncMask = 0; + break; + } + + LinkStatusGood = 0; + PegDev = 1; + for (i = 0; i < 100; i++) { + /// + /// Poll endpoints + /// Skip endpoints that failed last boot + /// Skip endpoints that trained good this boot + /// Loop in 1-ms increments until all endpoints are: + /// reported bad from last boot, or + /// have trained good on this boot + /// + for (PegFunc = 0, CurrentPegFuncBit = 1; PegFunc < SA_PEG_MAX_FUN; PegFunc++, CurrentPegFuncBit <<= 1) { + if (CurrentPegFuncBit == (CurrentPegFuncBit & SkipFuncMask)) { + if (i == 0) { + DEBUG ((EFI_D_INFO, " PEG%x%x (%x:%x:%x) - skipping due to furcation\n", PegDev, PegFunc, SA_PEG_BUS_NUM, PegDev, PegFunc)); + } + continue; + } + /// + /// If configuration change, then break out of loop. + /// Test if current PEG is neither in fail mask nor previously tested good. + /// + if (CurrentPegFuncBit != (CurrentPegFuncBit & (UINT8) (PegLinkFailMask | LinkStatusGood))) { + DEBUG ((EFI_D_INFO, " PEG%x%x (%x:%x:%x) - checking\n", PegDev, PegFunc, SA_PEG_BUS_NUM, PegDev, PegFunc)); + /// + /// VC negotiation is complete + /// + if ((BIT1 & MmPci16(0, SA_PEG_BUS_NUM, PegDev, PegFunc, R_SA_PEG_VC0RSTS_OFFSET)) != BIT1) { + DEBUG ((EFI_D_INFO, " VC negotiation is complete\n")); + /// + /// Record as a good link + /// + LinkStatusGood |= CurrentPegFuncBit; + } + } + } + /// + /// If all links accounted for, then exit. + /// + if (((UINT8) (LinkStatusGood | PegLinkFailMask | SkipFuncMask)) == 0xFF) { + break; + } + StallPpi->Stall (PeiServices, StallPpi, STALL_ONE_MILLI_SECOND); + } ///< End of stall loop + + DEBUG ((EFI_D_INFO, "Total Stall: %d msec\n", i)); + if (SaDataHob != NULL) { + SaDataHob->PegData.PegLinkFailMask = (UINT8) ~LinkStatusGood; + DEBUG ((EFI_D_INFO, "Returned PegLinkFailMask 0x%2.2X\n", SaDataHob->PegData.PegLinkFailMask)); + } + +} + +UINT32 +PcieFindCapId ( + IN UINT8 Bus, + IN UINT8 Device, + IN UINT8 PegFunc, + IN UINT8 CapId + ) +/** + Find the Offset to a given Capabilities ID + CAPID list: + 0x01 = PCI Power Management Interface + 0x04 = Slot Identification + 0x05 = MSI Capability + 0x10 = PCI Express Capability + + @param[in] Bus - Pci Bus Number + @param[in] Device - Pci Device Number + @param[in] PegFunc - Pci Function Number + @param[in] CapId - CAPID to search for + + @retval 0 - CAPID not found + @retval Other - CAPID found, Offset of desired CAPID +**/ +{ + UINT8 CapHeader; + + /// + /// Always start at Offset 0x34 + /// + CapHeader = MmPci8 (0, Bus, Device, PegFunc, PCI_CAPBILITY_POINTER_OFFSET); + if (CapHeader == 0xFF) { + return 0; + } + + while (CapHeader != 0) { + /// + /// Bottom 2 bits of the pointers are reserved per PCI Local Bus Spec 2.2 + /// + CapHeader &= ~(BIT1 | BIT0); + /// + /// Search for desired CapID + /// + if (MmPci8 (0, Bus, Device, PegFunc, CapHeader) == CapId) { + return CapHeader; + } + + CapHeader = MmPci8 (0, Bus, Device, PegFunc, CapHeader + 1); + } + + return 0; +} + + +VOID +SetLoadBus ( + IN UINT32 DmiBar, + IN UINTN Dev, + IN UINTN Lane, + IN UINT32 LoadSel, + IN UINT32 LoadData, + IN UINT8 CpuSteppingId + ) +/** + Set Load Bus + + @param[in] DmiBar - DMIBAR address + @param[in] Dev - Device Number + @param[in] Lane - Number of Lane + @param[in] LoadSel - Load selection value + @param[in] LoadData - Load Data + @param[in] CpuSteppingId - CPUID.1.EAX[3:0], CPU stepping ID + + @retval None +**/ +{ + UINT32 lbcvalue; + UINT32 lbcdata; + UINT32 lbclnsel; + UINT32 lbcldsel; + UINT32 lbcaddr; + + lbcaddr = R_SA_PEG_LOADBUSCTL0_OFFSET + BUNDLE_STEP * (Lane >> 1); + lbcvalue = 0x70000000; + + lbclnsel = ((Lane & 1) == 0) ? 0x80000 : 0x100000; + lbcldsel = (LoadSel & 0x3f) << 21; + lbcdata = (LoadData << 1) & 0x7FFF; + + lbcvalue = lbcvalue | lbclnsel | lbcldsel | lbcdata; + + if (Dev == 0) { + Mmio32 (DmiBar, lbcaddr) = lbcvalue; + } else { + MmPci32 (0, SA_PEG_BUS_NUM, Dev, SA_PEG10_FUN_NUM, lbcaddr) = lbcvalue; + } + + return; +} + +UINT32 +GetMonBus ( + IN UINT32 DmiBar, + IN UINTN Dev, + IN UINTN Lane, + IN UINT32 LoadSel, + IN UINT8 CpuSteppingId + ) +/** + Get monitor bus from the lane selected + + @param[in] DmiBar - DMIBAR address + @param[in] Dev - Device number + @param[in] Lane - Number of Lane + @param[in] LoadSel - Load selection value + @param[in] LoadData - Load selecttion data + @param[in] CpuSteppingId - CPUID.1.EAX[3:0], CPU stepping ID + + @retval UINT32 - Load bus address +**/ +{ + UINT32 monvalue; + UINT32 prevalue; + UINT32 lbclnsel; + UINT32 lbcldsel; + UINT32 lbcaddr; + UINT32 Result; + + lbcaddr = R_SA_PEG_LOADBUSCTL0_OFFSET + BUNDLE_STEP * (Lane >> 1); + monvalue = 0x068008000; + + if (Dev == 0) { + prevalue = Mmio32 (DmiBar, lbcaddr); + } else { + prevalue = MmPci32 (0, SA_PEG_BUS_NUM, Dev, SA_PEG10_FUN_NUM, lbcaddr); + } + monvalue = monvalue | (prevalue & 0x7FFE); + + lbclnsel = ((Lane & 1) == 0) ? 0x80000 : 0x100000; + lbcldsel = (LoadSel & 0x3f) << 21; + monvalue = monvalue | lbclnsel | lbcldsel; + + if (Dev == 0) { + Mmio32 (DmiBar, lbcaddr) = monvalue; + Result = Mmio32 (DmiBar, lbcaddr); + } else { + MmPci32 (0, SA_PEG_BUS_NUM, Dev, SA_PEG10_FUN_NUM, lbcaddr) = monvalue; + Result = MmPci32 (0, SA_PEG_BUS_NUM, Dev, SA_PEG10_FUN_NUM, lbcaddr); + } + + return (Result >> 1) & 0x3FFF; +} + +VOID +ProgramPreset ( + IN UINT8 Direction, + IN UINT8 PresetValue, + IN UINT8 PegFunc, + IN UINT8 Lane + ) +/** + Program PEG Gen3 preset value + + @param[in] Direction - 0 = Root Port, 1 = End Point + @param[in] PresetValue - Preset value to program + @param[in] PegFunc - Peg function number to be configured + @param[in] Lane - Lane to be configured + + @retval None +**/ +{ + UINT32 Data32Or; + UINT32 Data32And; + UINT8 OriginalLane; + + OriginalLane = Lane; + switch (PegFunc) { + case 1: + if (Lane < 8) { + DEBUG ((EFI_D_WARN, "Invalid input to ProgramPreset() function! PegFunc=%d, Lane=%d\n", PegFunc, Lane)); + return; + } else { + Lane -= 8; + } + break; + case 2: + if (Lane < 12) { + DEBUG ((EFI_D_WARN, "Invalid input to ProgramPreset() function! PegFunc=%d, Lane=%d\n", PegFunc, Lane)); + return; + } else { + Lane -= 12; + } + break; + default: + break; + } + /// + /// RP preset goes to bits [3:0] for even lane and [19:16] for odd lane + /// EP preset goes to bits [11:8] for even lane and [27:24] for odd lane + /// + if (Direction != 0) { + if ((Lane % 2) == 0) { + Data32And = 0xFFFFF0FF; + Data32Or = PresetValue << 8; + } else { + Data32And = 0xF0FFFFFF; + Data32Or = PresetValue << 24; + } + } else { + if (OriginalLane >= 8) { + if ((Lane % 2) == 0) { + Data32And = 0xFFF0FFFF; + Data32Or = PresetValue << 16; + } else { + Data32And = 0xFFFFFFF0; + Data32Or = PresetValue; + } + } else { + if ((Lane % 2) == 0) { + Data32And = 0xFFFFFFF0; + Data32Or = PresetValue; + } else { + Data32And = 0xFFF0FFFF; + Data32Or = PresetValue << 16; + } + } + } + + MmPci32AndThenOr (0, SA_PEG_BUS_NUM, SA_PEG_DEV_NUM, PegFunc, R_SA_PEG_EQCTL0_1_OFFSET + (Lane / 2) * 4, Data32And, Data32Or); + + return; +} + +VOID +ProgramPresetPerLane ( + IN UINT8 *RootPortPreset, + IN UINT8 *EndPointPreset, + IN UINT8 *EndPointHint, + IN UINTN HwStrap + ) +/** + Program PEG Gen3 preset values per lane + + @param[in] RootPortPreset - Array of root port preset values to program + @param[in] EndPointPreset - Array of end point preset values to program + @param[in] EndPointHint - Array of end point hint value to program + @param[in] HwStrap - HwStrap configuration from FUSESCMN + + @retval None +**/ +{ + UINTN i; + + for (i = 0; i < SA_PEG_MAX_LANE; i++) { + if (RootPortPreset[i] > 9) { + RootPortPreset[i] = 8; + } + if (EndPointPreset[i] > 9) { + EndPointPreset[i] = 7; + } + if (EndPointHint[i] > 6) { + EndPointHint[i] = 2; + } + } + + /// + /// RP preset goes to bits [3:0] and [19:16] + /// EP preset goes to bits [11:8] and [27:24] + /// EP hint goes to bits [14:12] and [30:28] + /// + switch (HwStrap) { + case SA_PEG_x16_x0_x0: + /// + /// PEG10 x16 + /// + + for (i = 0; i < 4; ++i) { + McD1PciCfg32AndThenOr (R_SA_PEG_EQCTL0_1_OFFSET + i * 4, 0x80F080F0, + RootPortPreset[2 * i] | (EndPointPreset[2 * i] << 8) | (EndPointHint[2 * i] << 12) | (RootPortPreset[2 * i + 1] << 16) | (EndPointPreset[2 * i + 1] << 24) | (EndPointHint[2 * i + 1] << 28)); + } + for (i = 4; i < 8; ++i) { + McD1PciCfg32AndThenOr (R_SA_PEG_EQCTL0_1_OFFSET + i * 4, 0x80F080F0, + RootPortPreset[2 * i + 1] | (EndPointPreset[2 * i] << 8) | (EndPointHint[2 * i] << 12) | (RootPortPreset[2 * i] << 16) | (EndPointPreset[2 * i + 1] << 24) | (EndPointHint[2 * i + 1] << 28)); + } + break; + + case SA_PEG_x8_x8_x0: + /// + /// PEG10 x8 / PEG11 x8 + /// + for (i = 0; i < 4; ++i) { + McD1PciCfg32AndThenOr (R_SA_PEG_EQCTL0_1_OFFSET + i * 4, 0x80F080F0, + RootPortPreset[2 * i] | (EndPointPreset[2 * i] << 8) | (EndPointHint[2 * i] << 12) | (RootPortPreset[2 * i + 1] << 16) | (EndPointPreset[2 * i + 1] << 24) | (EndPointHint[2 * i + 1] << 28)); + McD1F1PciCfg32AndThenOr (R_SA_PEG_EQCTL0_1_OFFSET + i * 4, 0x80F080F0, + RootPortPreset[8 + 2 * i + 1] | (EndPointPreset[8 + 2 * i] << 8) | (EndPointHint[8 + 2 * i] << 12) | (RootPortPreset[8 + 2 * i] << 16) | (EndPointPreset[8 + 2 * i + 1] << 24) | (EndPointHint[8 + 2 * i + 1] << 28)); + } + break; + + case SA_PEG_x8_x4_x4: + /// + /// PEG10 x8 / PEG11 x4 / PEG12 x4 + /// + for (i = 0; i < 4; ++i) { + McD1PciCfg32AndThenOr (R_SA_PEG_EQCTL0_1_OFFSET + i * 4, 0x80F080F0, + RootPortPreset[2 * i] | (EndPointPreset[2 * i] << 8) | (EndPointHint[2 * i] << 12) | (RootPortPreset[2 * i + 1] << 16) | (EndPointPreset[2 * i + 1] << 24) | (EndPointHint[2 * i + 1] << 28)); + } + for (i = 0; i < 2; ++i) { + McD1F1PciCfg32AndThenOr (R_SA_PEG_EQCTL0_1_OFFSET + i * 4, 0x80F080F0, + RootPortPreset[8 + 2 * i + 1] | (EndPointPreset[8 + 2 * i] << 8) | (EndPointHint[8 + 2 * i] << 12) | (RootPortPreset[8 + 2 * i] << 16) | (EndPointPreset[8 + 2 * i + 1] << 24) | (EndPointHint[8 + 2 * i + 1] << 28)); + McD1F2PciCfg32AndThenOr (R_SA_PEG_EQCTL0_1_OFFSET + i * 4, 0x80F080F0, + RootPortPreset[12 + 2 * i + 1] | (EndPointPreset[12 + 2 * i] << 8) | (EndPointHint[12 + 2 * i] << 12) | (RootPortPreset[12 + 2 * i] << 16) | (EndPointPreset[12 + 2 * i + 1] << 24) | (EndPointHint[12 + 2 * i + 1] << 28)); + } + break; + + default: + break; + } + + return; +} + +VOID +PegGen3Equalization ( + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN UINT8 CpuSteppingId, + IN UINTN HwStrap + ) +/** + Perform PEG Gen3 Equalization steps + + @param[in] SaPlatformPolicyPpi - pointer to SA_PLATFORM_POLICY_PPI + @param[in] CpuSteppingId - CPUID.1.EAX[3:0], CPU stepping ID + @param[in] HwStrap - HwStrap configuration from FUSESCMN + + @retval None +**/ +{ + UINT8 *RootPortPreset; + UINT8 *EndPointPreset; + UINT8 *EndPointHint; + + /// + /// Apply static presets for root port and endpoint + /// + RootPortPreset = SaPlatformPolicyPpi->PcieConfig->Gen3RootPortPreset; + EndPointPreset = SaPlatformPolicyPpi->PcieConfig->Gen3EndPointPreset; + EndPointHint = SaPlatformPolicyPpi->PcieConfig->Gen3EndPointHint; + + ProgramPresetPerLane (RootPortPreset, EndPointPreset, EndPointHint, HwStrap); + + return; +} + +#endif // PEG_FLAG + +#if defined(DMI_FLAG) || defined(PEG_FLAG) +VOID +PegDmiRecipe ( + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN UINT32 MchBar, + IN UINT32 DmiBar, + IN UINTN Dev, + IN UINT8 SwingControl + ) +/** + Perform PEG/DMI PCIe Recipe steps + + @param[in] SaPlatformPolicyPpi - Pointer to SA_PLATFORM_POLICY_PPI + @param[in] MchBar - MCHBAR or zero if called for PEG + @param[in] DmiBar - DMIBAR or zero if called for PEG + @param[in] Dev - PEG device number: 1 for PEG10, 0 if called for DMI. + @param[in] SwingControl - 1 = Half, 2 = Full + + @retval None +**/ +{ + UINTN i; + UINTN BundlesCount; + UINTN LanesCount; + UINT32 Data32; + UINT32 Data32And; + UINT32 Data32Or; + UINT32 VcuAddress; + UINT8 VcuReadOp; + UINT8 VcuWriteOp; + CPU_FAMILY CpuFamilyId; + CPU_STEPPING CpuSteppingId; + BOOLEAN IsSingleCall; + + CpuFamilyId = GetCpuFamily(); + CpuSteppingId = GetCpuStepping(); + + /// + /// With both DMI_FLAG and PEG_FLAG defined, this function is called twice: once for DMI and once for PEG. + /// Some registers are shared between DMI and PEG, so they are only programmed during one of the calls. + /// If only one flag is defined, this function will only be called once, so the shared registers need to be + /// programmed during the first/only call. + /// + IsSingleCall = TRUE; +#if defined(DMI_FLAG) && defined(PEG_FLAG) + IsSingleCall = FALSE; +#endif + + if (Dev == SA_PEG_DEV_NUM) { + /// + /// PEG10 + /// + LanesCount = SA_PEG_MAX_LANE; + } else { + /// + /// DMI + /// + LanesCount = SA_DMI_MAX_LANE; + } + + BundlesCount = LanesCount >> 1; + + /// + /// g23rxvref = 0xC (DMI & PEG) + /// + Data32And = (UINT32) ~(BIT4 | BIT3 | BIT2 | BIT1 | BIT0); + Data32Or = 0xC; + for (i = 0; i < LanesCount; i++) { + SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFELN0CFG0_OFFSET + i * LANE_STEP, Data32And, Data32Or); + } + /// + /// CDRPDDATMODE = 0x1 (DMI & PEG) + /// + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + for (i = 0; i < LanesCount; i++) { + SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFELN0CFG1_OFFSET + i * LANE_STEP, 0xFFFFFFFF, BIT11); + } + } + /// + /// irefctl = 0x2 (PEG only) + /// + if (DmiBar == 0) { + /// + /// Switch on + /// SwingControl 1 == Half + /// 2 == Full (Default) + /// + switch (SwingControl) { + case SA_SWING_HALF: + Data32Or = 0x0C; + break; + + default: + case SA_SWING_FULL: + Data32Or = 0x02; + break; + } + + for (i = 0; i < BundlesCount; i++) { + SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG1_OFFSET + i * BUNDLE_STEP, (UINT32) ~(0x1F), Data32Or); + } + } + /// + /// txvrefsel = 0x3 (PEG only) + /// + if (DmiBar == 0) { + /// + /// Switch on + /// SwingControl 1 == Half + /// 2 == Full (Default) + /// + switch (SwingControl) { + case SA_SWING_HALF: + Data32Or = 0x0E; + break; + + default: + case SA_SWING_FULL: + Data32Or = 0x03; + break; + } + + for (i = 0; i < BundlesCount; i++) { + SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG1_OFFSET + i * BUNDLE_STEP, (UINT32) ~(0x1F << 5), Data32Or << 5); + } + } + /// + /// igacq = 0x0 (HSW A0: DMI & PEG) + /// + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + for (i = 0; i < BundlesCount; i++) { + SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG1_OFFSET + i * BUNDLE_STEP, (UINT32) ~(7 << 22), 0); + } + } + /// + /// dfegainacq = 0x1 (HSW A0: DMI & PEG) + /// + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + for (i = 0; i < BundlesCount; i++) { + SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG1_OFFSET + i * BUNDLE_STEP, (UINT32) ~(3 << 29), 1 << 29); + } + } + /// + /// PGTRK = 0x9 (DMI & PEG) + /// + Data32And = (UINT32) ~(BIT10 | BIT9 | BIT8 | BIT7 | BIT6 | BIT5); + Data32Or = 0x9 << 5; + for (i = 0; i < BundlesCount; i++) { + SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG3_OFFSET + i * BUNDLE_STEP, Data32And, Data32Or); + } + /// + /// igtrk = 0x0 (HSW A0: DMI & PEG) + /// + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + for (i = 0; i < BundlesCount; i++) { + SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG3_OFFSET + i * BUNDLE_STEP, (UINT32) ~(7 << 17), 0); + } + } + /// + /// RXRTBIN = 0x5 (PEG only) + /// + if (DmiBar == 0) { + Data32And = (UINT32) ~(BIT24 | BIT23 | BIT22 | BIT21); + Data32Or = 0x5 << 21; + for (i = 0; i < BundlesCount; i++) { + SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG3_OFFSET + i * BUNDLE_STEP, Data32And, Data32Or); + } + } + /// + /// G3RXCTLEPEAK = 0x8 (PEG only) + /// + if (DmiBar == 0) { + Data32And = (UINT32) ~(BIT9 | BIT8 | BIT7 | BIT6); + for (i = 0; i < BundlesCount; i++) { + if (SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_3) { + Data32Or = SaPlatformPolicyPpi->PcieConfig->Gen3RxCtleP[i] << 6; + } else { + Data32Or = 8 << 6; + } + SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG4_OFFSET + i * BUNDLE_STEP, Data32And, Data32Or); + } + } + /// + /// g2rxctlepeak = 0x0 (DMI & PEG) + /// + for (i = 0; i < BundlesCount; i++) { + SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG4_OFFSET + i * BUNDLE_STEP, (UINT32) ~(0xF << 10), 0); + } + /// + /// AFEBNDSPARE[uneqmm] = 0x4 (HSW == A0: DMI & PEG) + /// + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + for (i = 0; i < BundlesCount; i++) { + SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG4_OFFSET + i * BUNDLE_STEP, (UINT32) ~(7 << 29), 4 << 29); + } + } + /// + /// AGCACQLEN = 0x2 (HSW == A0: DMI & PEG) + /// + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + for (i = 0; i < BundlesCount; i++) { + SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG5_OFFSET + i * BUNDLE_STEP, (UINT32) ~(3 << 7), 2 << 7); + } + } + /// + /// G2DFEC1CTL = 0x0 (HSW == A0: DMI & PEG) + /// + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + for (i = 0; i < BundlesCount; i++) { + SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG5_OFFSET + i * BUNDLE_STEP, (UINT32) ~(3 << 12), 0); + } + } + /// + /// RXSQEXCTL = 0x0 (DMI & PEG) + /// + Data32And = (UINT32) ~(BIT20 | BIT19 | BIT18); + Data32Or = 0; + for (i = 0; i < BundlesCount; i++) { + SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG5_OFFSET + i * BUNDLE_STEP, Data32And, Data32Or); + } + /// + /// dfemfc = 0x3 (HSW == A0: DMI & PEG) + /// + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + for (i = 0; i < BundlesCount; i++) { + SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG5_OFFSET + i * BUNDLE_STEP, (UINT32) ~(3 << 21), 3 << 21); + } + } + + /// + /// ICOMPGAIN = 0x6 (HSW == A0: DMI & PEG) + /// + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + VcuAddress = R_SA_VCU_AFECMNCFG0_ADDRESS_REV1; + VcuReadOp = V_SA_VCU_OPCODE_READ_MMIO_REV1; + VcuWriteOp = V_SA_VCU_OPCODE_WRITE_MMIO_REV1; + } else { + VcuAddress = R_SA_VCU_AFECMNCFG0_ADDRESS_REV2; + VcuReadOp = V_SA_VCU_OPCODE_READ_MMIO_REV2; + VcuWriteOp = V_SA_VCU_OPCODE_WRITE_MMIO_REV2; + } + + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + if ((DmiBar != 0) || (IsSingleCall)) { + Data32 = SendVcuApiSequence (MchBar, VcuAddress, VcuReadOp, 0); + Data32 &= (UINT32) ~(BIT12 | BIT11 | BIT10 | BIT9); + Data32 |= 0x6 << 9; + SendVcuApiSequence (MchBar, VcuAddress, VcuWriteOp, Data32); + } + } + + /// + /// PEGVCMSEL = 0x3 (PEG only) + /// + if (DmiBar == 0) { + Data32 = SendVcuApiSequence (MchBar, VcuAddress, VcuReadOp, 0); + Data32 &= (UINT32) ~(BIT29 | BIT28 | BIT27 | BIT26 | BIT25); + /// + /// Switch on + /// SwingControl 1 == Half + /// 2 == Full (Default) + /// + switch (SwingControl) { + case SA_SWING_HALF: + Data32 |= (UINT32) (0x0E << 25); + break; + + default: + case SA_SWING_FULL: + Data32 |= (UINT32) (0x03 << 25); + break; + } + SendVcuApiSequence (MchBar, VcuAddress, VcuWriteOp, Data32); + } + + /// + /// PH3EQFFEKNOBS = 0x8 (DMI & PEG) + /// + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + VcuAddress = R_SA_VCU_AFECMNCFG2_ADDRESS_REV1; + } else { + VcuAddress = R_SA_VCU_AFECMNCFG2_ADDRESS_REV2; + } + + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + if ((DmiBar != 0) || (IsSingleCall)) { + Data32 = SendVcuApiSequence (MchBar, VcuAddress, VcuReadOp, 0); + Data32 &= (UINT32) ~(BIT30 | BIT29 | BIT28 | BIT27 | BIT26 | BIT25); + Data32 |= 0x8 << 25; + SendVcuApiSequence (MchBar, VcuAddress, VcuWriteOp, Data32); + } + } + + /// + /// FIXUNCORRDATA = 0x0 (DMI & PEG) + /// + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + VcuAddress = R_SA_VCU_AFECMNCFG3_ADDRESS_REV1; + } else { + VcuAddress = R_SA_VCU_AFECMNCFG3_ADDRESS_REV2; + } + + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + if ((DmiBar != 0) || (IsSingleCall)) { + Data32 = SendVcuApiSequence (MchBar, VcuAddress, VcuReadOp, 0); + Data32 &= (UINT32) ~(BIT20); + Data32 |= 0; + SendVcuApiSequence (MchBar, VcuAddress, VcuWriteOp, Data32); + } + } + /// + /// BLEGCTL = 0x0 (DMI & PEG) + /// + if ((DmiBar != 0) || (IsSingleCall)) { + Data32 = SendVcuApiSequence (MchBar, VcuAddress, VcuReadOp, 0); + Data32 &= (UINT32) ~(BIT28 | BIT27 | BIT26 | BIT25 | BIT24 | BIT23); + Data32 |= 0; + SendVcuApiSequence (MchBar, VcuAddress, VcuWriteOp, Data32); + } + if (((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) && + ((DmiBar != 0) || (IsSingleCall) )) { + VcuAddress = R_SA_VCU_AFECMNCFG7_ADDRESS_REV1; + VcuReadOp = V_SA_VCU_OPCODE_READ_CSR_REV1; + VcuWriteOp = V_SA_VCU_OPCODE_WRITE_CSR_REV1; + + Data32 = SendVcuApiSequence (MchBar, VcuAddress, VcuReadOp, 0); + /// + /// VREFRXDET = 0x19 (PEG only) + /// + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + Data32 &= (UINT32) ~(BIT18 | BIT17 | BIT16 | BIT15 | BIT14); + Data32 |= 0x19 << 14; + } + /// + /// DFEFIX = 0x4 (PEG only) + /// + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + Data32 &= (UINT32) ~(BIT30 | BIT29 | BIT28); + Data32 |= 0x4 << 28; + } + SendVcuApiSequence (MchBar, VcuAddress, VcuWriteOp, Data32); + } + + + /// + /// RXDETECT_SAMPLE_TIME = 0x4 (PEG only) + /// + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + if (DmiBar == 0) { + Data32And = (UINT32) ~(BIT14 | BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8 | BIT7); + Data32Or = 0x4 << 7; + SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFE_PWRON_OFFSET, Data32And, Data32Or); + } + } + + /// + /// RXL0S_ENTRY_EXIT_TIMER = 0x00 (HSW == A0: DMI & PEG) + /// = 0x13 (HSW >= B0: DMI & PEG) + /// + Data32And = (UINT32) ~(BIT4 | BIT3 | BIT2 | BIT1 | BIT0); + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + Data32Or = 0x00; + } else { + Data32Or = 0x13; + } + SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFE_PM_TMR_OFFSET, Data32And, Data32Or); + + /// + /// Set 0xC38[6] = 0x1 (HSW == A0), 0x0 (HSW >= B0) (DMI & PEG) + /// + Data32And = (UINT32) ~(BIT6); + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + Data32Or = 0x1 << 6; + } else { + Data32Or = 0x0 << 6; + } + if (DmiBar == 0) { + McD1PciCfg16AndThenOr (R_SA_PEG_CMNSPARE_OFFSET, Data32And, Data32Or); + McD1F1PciCfg16AndThenOr (R_SA_PEG_CMNSPARE_OFFSET, Data32And, Data32Or); + McD1F2PciCfg16AndThenOr (R_SA_PEG_CMNSPARE_OFFSET, Data32And, Data32Or); + } else { + Mmio32AndThenOr (DmiBar, R_SA_DMIBAR_CMNSPARE_OFFSET, Data32And, Data32Or); + } + + /// + /// Set 0x260[1:0] = '10b' (DMI & PEG) + /// + Data32And = (UINT32) ~(BIT1 | BIT0); + Data32Or = 0x2; + if (DmiBar == 0) { + McD1PciCfg16AndThenOr (R_SA_PEG_CFG6_OFFSET, Data32And, Data32Or); + McD1F1PciCfg16AndThenOr (R_SA_PEG_CFG6_OFFSET, Data32And, Data32Or); + McD1F2PciCfg16AndThenOr (R_SA_PEG_CFG6_OFFSET, Data32And, Data32Or); + } else { + Mmio32AndThenOr (DmiBar, R_SA_DMIBAR_CFG6_OFFSET, Data32And, Data32Or); + } + + /// + /// setdfelsbsel = 0 + /// + for (i = 0; i < BundlesCount; i++) { + SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG0_OFFSET + i * BUNDLE_STEP, (UINT32) ~(3 << 26), 0); + } + /// + /// OFFCORGAIN = 0x3 (HSW >= A0) + /// + for (i = 0; i < BundlesCount; i++) { + SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG1_OFFSET + i * BUNDLE_STEP, (UINT32) ~(3 << 10), 3 << 10); + } + + /// + /// fixtxrtermoffset = -3; (PEG only) + /// + if (DmiBar == 0) { + for (i = 0; i < BundlesCount; i++) { + SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG3_OFFSET + i * BUNDLE_STEP, (UINT32) ~(0x1F << 25), ((0x03 << 1) | 0x01) << 25); + } + } + + /// + /// Set BND0SPARE[29:27] = '101b' (PEG) + /// + Data32And = (UINT32) ~(BIT29 | BIT28 | BIT27); + Data32Or = (UINT32) 0x28000000; + for (i = 0; i < BundlesCount; i++) { + MmPci32AndThenOr ( + 0, + SA_PEG_BUS_NUM, + SA_PEG10_DEV_NUM, + SA_PEG10_FUN_NUM, + R_SA_PEG_BND0SPARE_OFFSET + (i * BUNDLE_STEP), + Data32And, + Data32Or + ); + } + return; +} +#endif // DMI_FLAG || PEG_FLAG + +#ifdef PEG_FLAG +VOID +BubbleSort ( + IN OUT DATA_SAMPLE Array[] + ) +/** + Bubble sort from DATA_SAMPLE + + @param[in, out] - Array[]: array of DATA_SAMPLE + + @retval None +**/ +{ + UINTN n; + UINTN i; + UINTN j; + DATA_SAMPLE Temp; + + n = (UINTN) Array[0].Count; + + for (i = 1; i <= n; i++) { + for (j = n; j > i; j--) { + if (Array[j - 1].Data > Array[j].Data) { + Temp = Array[j - 1]; + Array[j - 1] = Array[j]; + Array[j] = Temp; + } + } + } + + return; +} + +UINT32 +GetMiddleValue ( + IN OUT DATA_SAMPLE Array[] + ) +/** + Get Middle Value from DATA_SAMPLE + + @param[in, out] - Array[]: array of DATA_SAMPLE + + @retval UINT32 : Middle Value of DATA_SAMPLE +**/ +{ + UINT32 n; + + n = Array[0].Count; + + return Array[n / 2 + 1].Data; +} + +#ifdef EFI_DEBUG +VOID +DumpSamplerValues ( + IN UINT32 DmiBar, + IN UINT8 CpuSteppingId, + IN UINTN Dev, + IN UINTN LanesCount + ) +/** + Dump Sampler Values + + @param[in] DmiBar - DMIBAR address + @param[in] CpuSteppingId - CPUID.1.EAX[3:0], CPU stepping ID + @param[in] Dev - Device number + @param[in] LanesCount - Value of Lanes + + @retval None +**/ +{ + UINTN Lane; + UINT32 Sampler; + UINT8 SampleData; + + DEBUG ((EFI_D_INFO, "Lane DS0 DS1 ESP0 ESP1 ESM0 ESM1\n")); + for (Lane = 0; Lane < LanesCount; Lane++) { + DEBUG ((EFI_D_INFO, "%2d: ", Lane)); + for (Sampler = 0; Sampler < 6; Sampler++) { + SampleData = GetMonBus (DmiBar, Dev, Lane, 0x31 + Sampler, CpuSteppingId) & 0x3F; + DEBUG ((EFI_D_INFO, "%02X ", SampleData)); + } + + DEBUG ((EFI_D_INFO, "\n")); + } + + return; +} +#endif // EFI_DEBUG + +VOID +SamplerCalibratePegPort ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_STALL_PPI *StallPpi, + IN UINT8 CpuSteppingId, + IN UINTN Dev, + IN UINTN LanesCount, + IN UINTN HwStrap + ) +/** + This function performs the PEG Sampler Calibration for HSW on a given PEG controller + It also calls the Step 2 of PEG Recipe routine. + + @param[in] PeiServices - Pointer to the PEI services table + @param[in] StallPpi - pointer to PEI_STALL_PPI + @param[in] CpuSteppingId - CPUID.1.EAX[3:0], CPU stepping ID + @param[in] Dev - Device number + @param[in] LanesCount - Value of Lanes + @param[in] HwStrap - HwStrap configuration from FUSESCMN + + @retval None +**/ +{ + UINTN Iteration; + UINTN PegSamplerIterations; + UINTN Lane; + UINTN i; + BOOLEAN Peg11Present; + BOOLEAN Peg12Present; + BOOLEAN EarlyExit; + BOOLEAN CodeFound; + UINT8 SampleData; + UINT32 Sampler; + UINT16 CodesFound; + UINT32 MiddleCode; + UINTN OcDelay; + + /// + /// Array of sampling data - 16 lanes max, 6 samplers per lane, up to MAX_CODES per sampler + /// Size is 3 * 16 * 6 * 11 = 3168 bytes + /// + DATA_SAMPLE SampleArray[16][6][MAX_CODES + 1]; + + PegSamplerIterations = SA_PEG_SAMPLER_ITERATIONS; + Peg11Present = FALSE; + Peg12Present = FALSE; + + if (LanesCount == 16) { + OcDelay = 10; + } else { + OcDelay = 20; + } + + ZeroMem (&SampleArray, sizeof (SampleArray)); + + if (HwStrap == SA_PEG_x8_x8_x0) { + Peg11Present = TRUE; + } + + + if (HwStrap == SA_PEG_x8_x4_x4) { + Peg11Present = TRUE; + Peg12Present = TRUE; + } + /// + /// Dump the Sampler values before calibration + /// + DEBUG ((EFI_D_INFO, "--- Sampler values before calibration ---\n")); +#ifdef EFI_DEBUG + DumpSamplerValues (0, CpuSteppingId, Dev, LanesCount); +#endif // EFI_DEBUG + /// + /// Disable the link + /// + MmPci16Or (0, SA_PEG_BUS_NUM, Dev, 0, R_SA_PEG_LCTL_OFFSET, BIT4); + if (Peg11Present) { + MmPci16Or (0, SA_PEG_BUS_NUM, Dev, 1, R_SA_PEG_LCTL_OFFSET, BIT4); + } + if (Peg12Present) { + MmPci16Or (0, SA_PEG_BUS_NUM, Dev, 2, R_SA_PEG_LCTL_OFFSET, BIT4); + } + + /// + /// Delay 10 ms after link disable + /// + StallPpi->Stall (PeiServices, StallPpi, 10 * STALL_ONE_MILLI_SECOND); + + /// + /// Override L0s and L1 - set bits 11, 13 & 15 of AFEOVR + /// + MmPci32Or (0, SA_PEG_BUS_NUM, Dev, 0, R_SA_PEG_AFEOVR_OFFSET, 0xA800); + if (Peg11Present) { + MmPci32Or (0, SA_PEG_BUS_NUM, Dev, 1, R_SA_PEG_AFEOVR_OFFSET, 0xA800); + } + if (Peg12Present) { + MmPci32Or (0, SA_PEG_BUS_NUM, Dev, 2, R_SA_PEG_AFEOVR_OFFSET, 0xA800); + } + + for (Iteration = 0; Iteration < PegSamplerIterations; Iteration++) { + PostCode ((UINT8) (Iteration / 100)); + /// + /// First trigger OC on each lane + /// + for (Lane = 0; Lane < LanesCount; Lane++) { + SetLoadBus (0, Dev, Lane, 0x39, 0x1, CpuSteppingId); + SetLoadBus (0, Dev, Lane, 0x3A, 0xC, CpuSteppingId); + } + /// + /// Delay to give the OC time to complete + /// + StallPpi->Stall (PeiServices, StallPpi, OcDelay * STALL_ONE_MICRO_SECOND); + + for (Lane = 0; Lane < LanesCount; Lane++) { + for (Sampler = 0; Sampler < 6; Sampler++) { + SampleData = GetMonBus (0, Dev, Lane, 0x31 + Sampler, CpuSteppingId) & 0x3F; + + /// + /// SampleArray[Lane][Sampler][0].Count holds the number of distinct codes found so far + /// + CodeFound = FALSE; + for (i = 1; i <= SampleArray[Lane][Sampler][0].Count; ++i) { + if (SampleArray[Lane][Sampler][i].Data == SampleData) { + CodeFound = TRUE; + SampleArray[Lane][Sampler][i].Count++; + break; + } + } + + if (!CodeFound) { + if (i > MAX_CODES) { + DEBUG ((EFI_D_ERROR, "ERROR: PEG dev=%d, lane=%d, sampler=%d, iteration=%d, found more than %d distinct codes!!!\n", Dev, Lane, Sampler, Iteration, MAX_CODES)); + if (LanesCount == 16) { + PostCode ((UINT8) (ERROR_BY_16 >> 8)); + } else { + PostCode ((UINT8) (ERROR_NOT_BY_16 >> 8)); + } + + EFI_DEADLOOP (); + } + /// + /// Increment the number of distinct codes found for this sampler + /// + SampleArray[Lane][Sampler][0].Count++; + + /// + /// Save the new code + /// + SampleArray[Lane][Sampler][i].Data = SampleData; + SampleArray[Lane][Sampler][i].Count = 1; + } + } + } + /// + /// Exit early if all the sampled lanes have more than 5 codes, + /// and we covered at least 20% of iterations. + /// Ignore the inactive lanes, these will only show one code. + /// + if (Iteration > PegSamplerIterations / 5) { + EarlyExit = TRUE; + for (Lane = 0; Lane < LanesCount; Lane++) { + for (Sampler = 0; Sampler < 6; Sampler++) { + CodesFound = SampleArray[Lane][Sampler][0].Count; + if ((CodesFound > 1) && (CodesFound < 5)) { + EarlyExit = FALSE; + break; + } + } + + if (!EarlyExit) { + break; + } + } + + if (EarlyExit) { + break; + } + } + } + /// + /// Iteration + /// + for (Lane = 0; Lane < LanesCount; Lane++) { + for (Sampler = 0; Sampler < 6; Sampler++) { + /// + /// Sort the codes for this Lane / Sampler + /// + BubbleSort (SampleArray[Lane][Sampler]); + /// + /// Find the middle value + /// + MiddleCode = GetMiddleValue (SampleArray[Lane][Sampler]); + /// + /// Set the middle calibration code + /// + SetLoadBus (0, Dev, Lane, 0x31 + Sampler, MiddleCode, CpuSteppingId); + } + } + /// + /// Restore AFEOVR + /// + MmPci32 (0, SA_PEG_BUS_NUM, Dev, 0, R_SA_PEG_AFEOVR_OFFSET) = 0; + if (Peg11Present) { + MmPci32 (0, SA_PEG_BUS_NUM, Dev, 1, R_SA_PEG_AFEOVR_OFFSET) = 0; + } + if (Peg12Present) { + MmPci32 (0, SA_PEG_BUS_NUM, Dev, 2, R_SA_PEG_AFEOVR_OFFSET) = 0; + } + /// + /// Delay 1 ms before link enable + /// + StallPpi->Stall (PeiServices, StallPpi, STALL_ONE_MILLI_SECOND); + + /// + /// Enable the link + /// + MmPci16And (0, SA_PEG_BUS_NUM, Dev, 0, R_SA_PEG_LCTL_OFFSET, ~BIT4); + if (Peg11Present) { + MmPci16And (0, SA_PEG_BUS_NUM, Dev, 1, R_SA_PEG_LCTL_OFFSET, ~BIT4); + } + if (Peg12Present) { + MmPci16And (0, SA_PEG_BUS_NUM, Dev, 2, R_SA_PEG_LCTL_OFFSET, ~BIT4); + } + /// + /// Dump the Sampler values after calibration + /// + DEBUG ((EFI_D_INFO, "--- Sampler values after calibration ---\n")); +#ifdef EFI_DEBUG + DumpSamplerValues (0, CpuSteppingId, Dev, LanesCount); +#endif // EFI_DEBUG + return; +} + +VOID +PegSamplerCalibration ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN PEI_STALL_PPI *StallPpi, + IN UINT8 CpuSteppingId, + IN UINT8 HwStrap + ) +/** + This function performs the PEG Sampler Calibration + + @param[in] PeiServices - Pointer to the PEI services table + @param[in] SaPlatformPolicyPpi - pointer to SA_PLATFORM_POLICY_PPI + @param[in] StallPpi - pointer to PEI_STALL_PPI + @param[in] CpuSteppingId - CPUID.1.EAX[3:0], CPU stepping ID + @param[in] HwStrap - HwStrap configuration from FUSESCMN + + @retval None +**/ +{ + UINT32 Data32; + + /// + /// Calibrate PEG10/PEG11/PEG12 - 16 lanes total + /// + if (MmPci16 (0, 0, 1, 0, PCI_VID) != 0xFFFF) { + Data32 = MmPci32 (0, 0, 1, 0, R_SA_PEG_PEGSTS_OFFSET); + if (((Data32 & 0xFFFF) != 0) && (((Data32 >> 16) & 0x0F) >= 7)) { + SamplerCalibratePegPort (PeiServices, StallPpi, CpuSteppingId, SA_PEG10_DEV_NUM, 16, HwStrap); + } + } + + return; +} + +VOID +PegGen2AutoSpeedDisable ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN PEI_STALL_PPI *StallPpi, + IN SA_DATA_HOB *SaDataHob, + IN PEG_PORT *PegPortTable, + IN UINTN PegPortTableSize, + IN UINT8 HwStrap + ) +/** + This function performs the PEG GEN2 Auto Speed Disable + + @param[in] PeiServices - Pointer to the PEI services table + @param[in] SaPlatformPolicyPpi - Pointer to SA_PLATFORM_POLICY_PPI + @param[in] StallPpi - Pointer to PEI_STALL_PPI + @param[in] SaDataHob - Pointer to SA_DATA_HOB + @param[in] PegPortTable - Pointer to PEG Port Table + @param[in] PegPortTableSize - Size of PEG Port Table + @param[in] HwStrap - Furcation HW Strap Value + + @retval None +**/ +{ + UINTN PortIndex; + EFI_STATUS Status; + EFI_BOOT_MODE BootMode; + UINT8 DisableAutoSpeedUp; + UINT8 PegBus; + UINT8 PegDev; + UINT8 PegFunc; + + DisableAutoSpeedUp = 0; + Status = (*PeiServices)->GetBootMode (PeiServices, &BootMode); + ASSERT_EFI_ERROR (Status); + + for (PortIndex = 0; PortIndex < PegPortTableSize; PortIndex++) { + PegBus = PegPortTable[PortIndex].Bus; + PegDev = PegPortTable[PortIndex].Device; + PegFunc = PegPortTable[PortIndex].Function; + + /// + /// If VC0 is still pending + /// And presence of an endpoint was detected, enable GEN2 auto speed disable + /// + if ((MmPci16 (0, PegBus, PegDev, PegFunc, PCI_VID ) != 0xFFFF) && + ((MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC0RSTS_OFFSET) & BIT1) != 0) && + ((MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_SLOTSTS_OFFSET) & BIT6) != 0)) { + DisableAutoSpeedUp |= 1 << PegFunc; + MmPci16Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCTL_OFFSET, BIT4); + MmPci32Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_CFG5_OFFSET, BIT9); + MmPci16And (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCTL_OFFSET, (UINT16)~(BIT4)); + } + } + /// + /// If needed, reinitialize link after disable + /// + if (DisableAutoSpeedUp != 0) { + if ((BootMode == BOOT_ON_S3_RESUME) || (GetPchPmStatus (WarmBoot) == TRUE)) { + if ((SaDataHob != NULL) && (SaDataHob->PegDataValid)) { + if (SaDataHob->PegData.PegLinkFailMask != 0) { + /// + /// Even on warm boot/S3 resume, we still want to force checking of VC0 status + /// + SaDataHob->PegData.PegLinkFailMask = 0; + } + } + } + GracefulLinkStatusStall (PeiServices, StallPpi, SaPlatformPolicyPpi, SaDataHob, HwStrap); + for (PortIndex = 0; PortIndex < PegPortTableSize; PortIndex++) { + PegBus = PegPortTable[PortIndex].Bus; + PegDev = PegPortTable[PortIndex].Device; + PegFunc = PegPortTable[PortIndex].Function; + if (((DisableAutoSpeedUp >> PegFunc) & 1) == 1) { + /// + /// Retrain to allow link to reach GEN2 + /// + MmPci16Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCTL_OFFSET, BIT5); + } + } + /// + /// Ensure all links are now ready + /// + if ((BootMode == BOOT_ON_S3_RESUME) || (GetPchPmStatus (WarmBoot) == TRUE)) { + if ((SaDataHob != NULL) && (SaDataHob->PegDataValid)) { + if (SaDataHob->PegData.PegLinkFailMask != 0) { + /// + /// Even on warm boot/S3 resume, we still want to force checking of VC0 status + /// + SaDataHob->PegData.PegLinkFailMask = 0; + } + } + } + GracefulLinkStatusStall (PeiServices, StallPpi, SaPlatformPolicyPpi, SaDataHob, HwStrap); + DEBUG ((EFI_D_INFO, "PEG Link Status after auto speed disable:\n")); + for (PortIndex = 0; PortIndex < PegPortTableSize; PortIndex++) { + PegBus = PegPortTable[PortIndex].Bus; + PegDev = PegPortTable[PortIndex].Device; + PegFunc = PegPortTable[PortIndex].Function; + ReportPcieLinkStatus (PegBus, PegDev, PegFunc); + } + } +} + +VOID +PciExpressInit ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +/** + Initialize the SA PciExpress in PEI + + @param[in] PeiServices - Pointer to the PEI services table + @param[in] SaPlatformPolicyPpi - SaPlatformPolicyPpi to access the GtConfig related information +**/ +{ + UINT8 PegBus; + UINT8 PegDev; + UINT8 PegFunc; + UINT8 PegIndex; + UINT8 HwStrap; + UINT64 MchBar; + UINT64 DmiBar; + BOOLEAN DisableFun0; + BOOLEAN DisableFun1; + BOOLEAN DisableFun2; + BOOLEAN DisableLinkFunc0; + EFI_STATUS Status; + CPU_FAMILY CpuFamilyId; + CPU_STEPPING CpuSteppingId; + UINTN PegComplete; + UINT16 Peg10Speed; + UINT16 Peg11Speed; + UINT16 Peg12Speed; + UINT8 SwingControl; + UINT8 Gen3Capable; + UINT8 i; + PEI_STALL_PPI *StallPpi; + UINT32 Data32; + UINT32 CapOffset; + BOOLEAN AnyGen3Endpoint; + UINT8 FullSwing; + UINT8 PreCursor; + UINT8 Cursor; + UINT8 PostCursor; + + PEG_PORT PegPortTable[] = { + /// + /// Bus, Device, Function, Index, PresenceDetect, MaxLinkWidth, EndpointMaxLinkSpeed + /// + { SA_PEG_BUS_NUM, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, 0, FALSE, 16, 0} +//AMI_OVERRIDE>> +#if RC_PEG_1 == 1 + ,{ SA_PEG_BUS_NUM, SA_PEG11_DEV_NUM, SA_PEG11_FUN_NUM, 1, FALSE, 8, 0} +#endif +#if RC_PEG_2 == 1 + ,{ SA_PEG_BUS_NUM, SA_PEG12_DEV_NUM, SA_PEG12_FUN_NUM, 2, FALSE, 4, 0} +#endif +//AMI_OVERRIDE<< + }; + SA_DATA_HOB *SaDataHob; + BOOLEAN S3Flow; + UINT8 LinkStatusGood; + BOOLEAN FunctionExists; + UINT8 UnusedLanes; + UINT8 CtrlMaxLinkWidth; + UINT8 EpMaxLinkWidth; + UINT16 LoopCount; + UINT8 MaxBndlPwrdnCount; + UINT8 BndlPwrdnCount; + UINT8 PwrDnUnusedBundlesSetupData; + + HwStrap = SA_PEG_x16_x0_x0; + DisableFun0 = FALSE; + DisableFun1 = FALSE; + DisableFun2 = FALSE; + DisableLinkFunc0 = FALSE; + MchBar = McD0PciCfg64 (R_SA_MCHBAR) &~BIT0; + DmiBar = McD0PciCfg64 (R_SA_DMIBAR) &~BIT0; + PegDev = 0x1; + + Peg10Speed = 0; + Peg11Speed = 0; + Peg12Speed = 0; + SwingControl = SaPlatformPolicyPpi->PcieConfig->PegSwingControl; + SaDataHob = NULL; + S3Flow = FALSE; + Gen3Capable = TRUE; + AnyGen3Endpoint = FALSE; + FullSwing = 0; + CtrlMaxLinkWidth = 0; + EpMaxLinkWidth = 0; + UnusedLanes = 0; + LoopCount = 0; + MaxBndlPwrdnCount = 0; + BndlPwrdnCount = 0; + PwrDnUnusedBundlesSetupData = 0xFF; + + /// + /// Check to see if PEG exists and leave initialization function if non-existant + /// + if (McD1PciCfg16 (PCI_VID) == 0xFFFF) { + DEBUG ((EFI_D_INFO, "PEG controller not detected\n")); + return; + } + + /// + /// Read the HW straps - Bus 0, Device 1, Fun 0, Reg 0x504 BIT17,16 + /// Fun 1 & 2 disabled = Pcie 1x16, Fun 2 disabled = Pcie 2x8 + /// Fun 1 & 2 enabled = Pcie 1x8 + (2+4) + /// + HwStrap = (UINT8) ((MmPci32 (0, SA_MC_BUS, PegDev, 0, R_SA_PEG_FUSESCMN_OFFSET) >> 16) & 0x03); + DEBUG ((EFI_D_INFO, "PEG HW Strap value %x\n", HwStrap)); + + Status = (*PeiServices)->LocatePpi (PeiServices, &gPeiStallPpiGuid, 0, NULL, &StallPpi); + ASSERT_EFI_ERROR (Status); + + /// + /// Update PEG LCAP.MLW based on PEG port Split configuration. + /// This is Write-Once field, so keep the values in the structure, + /// and write later together with LCAP.MLS. + /// + switch (HwStrap) { + case SA_PEG_x8_x4_x4: + /// + /// 0x0: Device 1 functions 1 and 2 enabled + /// PEG10: x16->x8, PEG11: x8->x4, PEG12: x4 + /// + PegPortTable[0].MaxLinkWidth = 8; +//AMI_OVERRIDE >> +#if RC_PEG_1 == 1 + PegPortTable[1].MaxLinkWidth = 4; +#endif +//AMI_OVERRIDE << + break; + + + case SA_PEG_x8_x8_x0: + /// + /// 0x2: Device 1 function 1 enabled; function 2 disabled + /// PEG10: x16->x8, PEG11: x8, PEG12: N/A + /// + PegPortTable[0].MaxLinkWidth = 8; + break; + + default: + case SA_PEG_x16_x0_x0: + break; + } + + CpuFamilyId = GetCpuFamily(); + CpuSteppingId = GetCpuStepping(); + + /// + /// Read PEG Gen3 Fuse to see if it should override programming + /// + if (MmPci32 (0, SA_MC_BUS, SA_MC_DEV, SA_MC_FUN, R_SA_MC_CAPID0_B) & BIT20) { + Gen3Capable = FALSE; + DEBUG ((EFI_D_INFO, "PEG Gen3 Fused off\n")); + } + + /// + /// Gen3 Preset Search: 0 = Disabled, 1 = Enabled (default) + /// + if (SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearch == 2) { + SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearch = 1; + } + + /// + /// Restore SA Data HOB's PEG data + /// + if (SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_2) { + SaDataHob = (SA_DATA_HOB *) GetFirstGuidHob (&gSaDataHobGuid); + + if (SaDataHob != NULL) { + if (SaPlatformPolicyPpi->PcieConfig->PegDataPtr != NULL) { + DEBUG ((EFI_D_INFO, "\nRestore SA PEG DATA from previous boot: Size=%X\n", sizeof (SA_PEG_DATA))); + CopyMem (&(SaDataHob->PegData), SaPlatformPolicyPpi->PcieConfig->PegDataPtr, sizeof (SA_PEG_DATA)); + SaDataHob->PegDataValid = TRUE; + if ((SaDataHob->PegData.PegGen3PresetSearch != SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearch) && (SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearch != 1)) { + /// + /// Zero out previous boot GEN3 Preset data so old data won't be re-used when PegGen3PresetSearch re-enabled later + /// + DEBUG ((EFI_D_INFO, "\nPegGen3PresetSearch is disabled, Clear old Preset data\n")); + for (PegIndex = 0; PegIndex < SA_PEG_MAX_FUN; PegIndex++) { + SaDataHob->PegData.EndPointVendorIdDeviceId[PegIndex] = 0; + for (i = 0; i < SA_PEG_MAX_LANE; i++) { + SaDataHob->PegData.BestPreset[i] = 0; + } + } + } + } + SaDataHob->PegData.PegGen3PresetSearch = SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearch; + } + } + + /// + /// Perform PEG Pre-Detection steps + /// + for (PegComplete = 0; PegComplete < ((sizeof (PegPortTable)) / (sizeof (PEG_PORT))); PegComplete++) { + PegBus = PegPortTable[PegComplete].Bus; + PegDev = PegPortTable[PegComplete].Device; + PegFunc = PegPortTable[PegComplete].Function; + PegPreDetectionSteps (PegBus, PegDev, PegFunc, SaPlatformPolicyPpi); + } + + /// + /// Perform PEG Recipe steps + /// + DEBUG ((EFI_D_INFO, "PEG Recipe...\n")); + PegDmiRecipe (SaPlatformPolicyPpi, (UINT32) MchBar, 0, SA_PEG10_DEV_NUM, SwingControl); + + /// + /// Perform PEG Gen3 Equalization steps and load preset values + /// + if (Gen3Capable == TRUE) { + if (SaPlatformPolicyPpi->PcieConfig->PegGen3Equalization != 0) { + DEBUG ((EFI_D_INFO, "PEG Gen3 Equalization...\n")); + PegGen3Equalization (SaPlatformPolicyPpi, CpuSteppingId, HwStrap); + } + } + + /// + /// PEG Sampler Calibration: 0 = Disabled (default), 1 = Enabled + /// + if (SaPlatformPolicyPpi->PcieConfig->PegSamplerCalibrate == 2) { + SaPlatformPolicyPpi->PcieConfig->PegSamplerCalibrate = 0; + } + + if (SaPlatformPolicyPpi->PcieConfig->PegSamplerCalibrate == 1) { + /// + /// Back up the current PEG speed in LCTL2.TLS[3:0] + /// + Peg10Speed = McD1PciCfg16 (R_SA_PEG_LCTL2_OFFSET) & 0x0F; + Peg11Speed = McD1F1PciCfg16 (R_SA_PEG_LCTL2_OFFSET) & 0x0F; + Peg12Speed = McD1F2PciCfg16 (R_SA_PEG_LCTL2_OFFSET) & 0x0F; + /// + /// Set the PEG speed in LCTL2.TLS[3:0] to Gen1 before clearing DEFER_OC, + /// in order to run Sampler Calibration at Gen1. + /// + McD1PciCfg16AndThenOr (R_SA_PEG_LCTL2_OFFSET, 0xFFF0, 1); + McD1F1PciCfg16AndThenOr (R_SA_PEG_LCTL2_OFFSET, 0xFFF0, 1); + McD1F2PciCfg16AndThenOr (R_SA_PEG_LCTL2_OFFSET, 0xFFF0, 1); + } + + for (PegComplete = 0; PegComplete < ((sizeof (PegPortTable)) / (sizeof (PEG_PORT))); PegComplete++) { + /// + /// Program the PEG speed according to Setup options: Auto/Gen1/2/3 + /// We have to do it before endpoint enumeration, so that uncompliant card + /// can train at a lower speed. + /// + ConfigurePegGenX ( + PeiServices, + StallPpi, + SaPlatformPolicyPpi, + PegPortTable, + PegComplete, + CpuSteppingId, + Gen3Capable + ); + } + + /// + /// RxCEM Loopback (LPBK) Mode + /// + if ((SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_3) && (SaPlatformPolicyPpi->PcieConfig->RxCEMLoopback == 1)) { + McD1PciCfg32AndThenOr (R_SA_PEG_PEGTST_OFFSET, ~(BIT19|BIT18|BIT17|BIT16), (SaPlatformPolicyPpi->PcieConfig->RxCEMLoopbackLane & 0xF) << 16); + for (i = 0; i < SA_PEG_MAX_LANE; i++) { + if (i == SaPlatformPolicyPpi->PcieConfig->RxCEMLoopbackLane) { + McD1PciCfg32And (R_SA_PEG_AFELN0CFG0_OFFSET + LANE_STEP * i, ~BIT9); + } else { + McD1PciCfg32Or (R_SA_PEG_AFELN0CFG0_OFFSET + LANE_STEP * i, BIT9); + } + } + } + + /// + /// Enable 3-OC retry for PEG(0/1/2). HSW/CRW earlier than C0. + /// + if (((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId < EnumHswC0)) || + ((CpuFamilyId == EnumCpuCrw) && (CpuSteppingId < EnumCrwC0))) { + McD1PciCfg32Or (R_SA_PEG_AFE_PWRON_OFFSET, BIT5); + McD1F1PciCfg32Or (R_SA_PEG_AFE_PWRON_OFFSET, BIT5); + McD1F2PciCfg32Or (R_SA_PEG_AFE_PWRON_OFFSET, BIT5); + } + + /// + /// Bypass phase2 + /// + Data32 = McD1PciCfg32 (R_SA_PEG_EQCFG_OFFSET); + Data32 |= BIT15 | BIT1; + McD1PciCfg32 (R_SA_PEG_EQCFG_OFFSET) = Data32; + + /// + /// Clear DEFER_OC in offset 0xC24[16] on all PEG controllers to start the PEG training + /// + McD1PciCfg32And (R_SA_PEG_AFE_PWRON_OFFSET, ~BIT16); + McD1F1PciCfg32And (R_SA_PEG_AFE_PWRON_OFFSET, ~BIT16); + McD1F2PciCfg32And (R_SA_PEG_AFE_PWRON_OFFSET, ~BIT16); + + /// + /// Delay for 100ms to meet the timing requirements of the PCI Express Base + /// Specification, Revision 1.0A, Section 6.6 ("...software must wait at least + /// 100 ms from the end of reset of one or more device before it is permitted + /// to issue Configuration Requests to those devices"). + /// + GracefulLinkStatusStall (PeiServices, StallPpi, SaPlatformPolicyPpi, SaDataHob, HwStrap); + + PegGen2AutoSpeedDisable (PeiServices, + SaPlatformPolicyPpi, + StallPpi, + SaDataHob, + &(PegPortTable[0]), + ((sizeof (PegPortTable)) / (sizeof (PEG_PORT))), + HwStrap); + + /// + /// Read the presence detect bit for each PEG port - must be done before sampler calibration + /// + for (PegComplete = 0; PegComplete < ((sizeof (PegPortTable)) / (sizeof (PEG_PORT))); PegComplete++) { + PegBus = PegPortTable[PegComplete].Bus; + PegDev = PegPortTable[PegComplete].Device; + PegFunc = PegPortTable[PegComplete].Function; + if (( MmPci16 (0, PegBus, PegDev, PegFunc, PCI_VID ) != 0xFFFF) && + ((MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_SLOTSTS_OFFSET) & BIT6) != 0)) { + PegPortTable[PegComplete].PresenceDetect = TRUE; + + /// + /// Read the endpoint's Max Link Speed + /// + MmPci32AndThenOr (0, PegBus, PegDev, PegFunc, PCI_PBUS, 0xFF0000FF, 0x00010100); + MmPci16 (0, 1, 0, 0, PCI_VID) = 0; + CapOffset = PcieFindCapId (1, 0, 0, EFI_PCI_CAPABILITY_ID_PCIEXP); + if (CapOffset != 0) { + Data32 = MmPci32 (0, 1, 0, 0, CapOffset + 0xC); + PegPortTable[PegComplete].EndpointMaxLinkSpeed = Data32 & 0xF; + if (PegPortTable[PegComplete].EndpointMaxLinkSpeed >= 0x3) { + AnyGen3Endpoint = TRUE; + } + } + MmPci32And (0, PegBus, PegDev, PegFunc, PCI_PBUS, 0xFF0000FF); + } + } + DEBUG ((EFI_D_INFO, "Presence detect table...\n")); + for (PegComplete = 0; PegComplete < ((sizeof (PegPortTable)) / (sizeof (PEG_PORT))); PegComplete++) { + DEBUG ((EFI_D_INFO, " PEG%d%d PresenceDetect: %x. EndpointMaxLinkSpeed: %x.\n", + PegPortTable[PegComplete].Device, + PegPortTable[PegComplete].Function, + PegPortTable[PegComplete].PresenceDetect, + PegPortTable[PegComplete].EndpointMaxLinkSpeed)); + } + + /// + /// If any Gen3 device, setup equalization values and retrain link + /// + if (AnyGen3Endpoint && + (((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId >= EnumHswB0)) || + ((CpuFamilyId == EnumCpuCrw) && (CpuSteppingId >= EnumCrwB0)))) { + /// + /// Program presets based upon endpoint fullswing value + /// + for (i = 0; i < SA_PEG_MAX_LANE; i++) { + switch (i) { + case 0: + GetLinkPartnerFullSwing (i, &FullSwing); + break; + case 8: + if (PegPortTable[1].PresenceDetect) { + GetLinkPartnerFullSwing (i, &FullSwing); + } + break; + case 12: + if (PegPortTable[2].PresenceDetect) { + GetLinkPartnerFullSwing (i, &FullSwing); + } + break; + default: + break; + } + GetCoefficientsFromPreset (SaPlatformPolicyPpi->PcieConfig->Gen3EndPointPreset[i], FullSwing, &PreCursor, &Cursor, &PostCursor); + SetPartnerTxCoefficients (i, &PreCursor, &Cursor, &PostCursor); + } + + /// + /// Redo EQ + /// + for (PegComplete = 0; PegComplete < ((sizeof (PegPortTable)) / (sizeof (PEG_PORT))); PegComplete++) { + if (PegPortTable[PegComplete].PresenceDetect) { + PegBus = PegPortTable[PegComplete].Bus; + PegDev = PegPortTable[PegComplete].Device; + PegFunc = PegPortTable[PegComplete].Function; + MmPci32Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCTL3_OFFSET, BIT0); ///< DOEQ + MmPci16Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCTL_OFFSET, BIT5); ///< Retrain link + } + } + for (PegComplete = 0; PegComplete < ((sizeof (PegPortTable)) / (sizeof (PEG_PORT))); PegComplete++) { + if (PegPortTable[PegComplete].PresenceDetect) { + WaitForL0 (PeiServices, StallPpi, &(PegPortTable[PegComplete]), FALSE); + } + } + } + + /// + /// Sampler Calibration + /// + if (SaPlatformPolicyPpi->PcieConfig->PegSamplerCalibrate == 1) { + DEBUG ((EFI_D_INFO, "PEG SamplerCalibration...\n")); + PegSamplerCalibration (PeiServices, SaPlatformPolicyPpi, StallPpi, CpuSteppingId, HwStrap); + + /// + /// Restore the PEG speed + /// + McD1PciCfg16AndThenOr (R_SA_PEG_LCTL2_OFFSET, 0xFFF0, Peg10Speed); + McD1F1PciCfg16AndThenOr (R_SA_PEG_LCTL2_OFFSET, 0xFFF0, Peg11Speed); + McD1F2PciCfg16AndThenOr (R_SA_PEG_LCTL2_OFFSET, 0xFFF0, Peg12Speed); + + /// + /// Delay 100ms to let endpoint train properly + /// + StallPpi->Stall (PeiServices, StallPpi, 100 * STALL_ONE_MILLI_SECOND); + } + /// + /// Gen3 Preset Search: 0 = Disabled, 1 = Enabled (default) + /// + if (SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearch == 2) { + SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearch = 1; + } + + if (SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearch == 1) { + PegGen3PresetSearch (PeiServices, SaPlatformPolicyPpi, StallPpi, SaDataHob); + } + + /// + /// After last equalization, set PH3 bypass + /// + McD1PciCfg32Or (R_SA_PEG_EQCFG_OFFSET, BIT15 | BIT14); + + /// + /// Scan PEG Ports for device population + /// + DEBUG ((EFI_D_INFO, "PEG Ports Scanning starts.\n")); + for (PegComplete = 0; PegComplete < ((sizeof (PegPortTable)) / (sizeof (PEG_PORT))); PegComplete++) { + + PegBus = PegPortTable[PegComplete].Bus; + PegDev = PegPortTable[PegComplete].Device; + PegFunc = PegPortTable[PegComplete].Function; + PegIndex = PegPortTable[PegComplete].Index; + + /// + /// Check for a card presence in the PEG slot, or if the PEG port exists. + /// + if ((MmPci16 (0, PegBus, PegDev, PegFunc, PCI_VID) == 0xFFFF) || + (PegPortTable[PegComplete].PresenceDetect == FALSE)) { + if (SaPlatformPolicyPpi->PcieConfig->AlwaysEnablePeg == 0) { + goto PegDisable; + } + } else { + if (SaPlatformPolicyPpi->PcieConfig->AlwaysEnablePeg == 0) { + /// + /// 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; + + /// + /// Negotiation Done? + /// + if ((MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC0RSTS_OFFSET) & BIT1) != 0) { + goto PegDisable; + } + + /// + /// Restore bus numbers on the PEG bridge. + /// + MmPci32And (0, PegBus, PegDev, PegFunc, PCI_PBUS, 0xFF0000FF); + } + + if (SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_8) { + PwrDnUnusedBundlesSetupData = SaPlatformPolicyPpi->PcieConfig->PowerDownUnusedBundles[PegIndex]; + } else { + PwrDnUnusedBundlesSetupData = 0xFF; ///< Forced to AUTO mode for calculating unused bundles to powerdown + } + + if (PwrDnUnusedBundlesSetupData == 0xff) { ///< AUTO mode for calculating unused bundles to powerdown + /// + /// Read the controller's Max Link Width + /// + CtrlMaxLinkWidth = (UINT8) ((MmPci32 (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCAP_OFFSET) >> 4) & 0x3F); + + /// + /// Read the endpoint's Max Link Width + /// + + /// + /// 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; + + /// + /// Check if the device actually got mapped into config space, + /// if the device wasn't able to be mapped into config space then + /// it's possible that it's a test card or some other device that + /// does not support config space. In that case our only option is + /// to assume that the link trains to its max width and use that to + /// determine which bundles to power down + /// + if (MmPci32 (0, 1, 0, 0, PCI_VID) == 0xFFFFFFFF) { + EpMaxLinkWidth = (UINT8) ((MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_LSTS_OFFSET) & 0x3f0) >> 4); + DEBUG ((EFI_D_INFO, + "PEG%d%d - Endpoint not responding to PCI config space access, assuming negotiated width (X%d) is max width\n", + PegDev, + PegFunc, + EpMaxLinkWidth + )); + } else { + CapOffset = PcieFindCapId (1, 0, 0, EFI_PCI_CAPABILITY_ID_PCIEXP); + if (CapOffset != 0) { + EpMaxLinkWidth = (UINT8) ((MmPci32 (0, 1, 0, 0, CapOffset + 0xC) >> 4) & 0x3F); + } + } + + /// + /// Restore bus numbers on the PEG bridge. + /// + MmPci32And (0, PegBus, PegDev, PegFunc, PCI_PBUS, 0xFF0000FF); + + if (CtrlMaxLinkWidth > EpMaxLinkWidth) { + UnusedLanes = CtrlMaxLinkWidth - EpMaxLinkWidth; + } else { + UnusedLanes = 0; + } + + BndlPwrdnCount = (UnusedLanes / 2); + + DEBUG ((EFI_D_INFO, "CtrlMLW[%d]. EpMLW[%d]. UnusedLanes[%d]. BndlPwrdnCount[%d].\n", CtrlMaxLinkWidth, EpMaxLinkWidth, UnusedLanes, BndlPwrdnCount)); + } else if (PwrDnUnusedBundlesSetupData != 0) { ///< User selection mode: 1...8 unused bundles + BndlPwrdnCount = PwrDnUnusedBundlesSetupData; + DEBUG ((EFI_D_INFO, "BndlPwrdnCount[%d].\n", BndlPwrdnCount)); + } + + /// + /// PowerOff unused lanes for PEGs + /// + if (((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId >= EnumHswC0)) || + ((CpuFamilyId == EnumCpuCrw) && (CpuSteppingId >= EnumCrwC0))) { + if (PwrDnUnusedBundlesSetupData != 0) { + MaxBndlPwrdnCount = GetMaxBundles(PeiServices, PegFunc, HwStrap); + if (BndlPwrdnCount > MaxBndlPwrdnCount) { + BndlPwrdnCount = MaxBndlPwrdnCount; + DEBUG ((EFI_D_INFO+EFI_D_ERROR, "BndlPwrdnCount violation! Overriding BndlPwrdnCount! BndlPwrdnCount[%d].\n", BndlPwrdnCount)); + } + PowerDownUnusedBundles(PeiServices, PegFunc, HwStrap, BndlPwrdnCount); + } + } + + /// + /// Additional Programming Steps for PEGs + /// + DEBUG ((EFI_D_INFO, "Run AdditionalPegProgramSteps on PEG%x%x!\n", PegDev, PegFunc)); + AdditionalPegProgramSteps (SaPlatformPolicyPpi, PegBus, PegDev, PegFunc); + } + + if ((HwStrap == SA_PEG_x16_x0_x0) && (PegIndex == 0)) { + DisableFun1 = TRUE; + DisableFun2 = TRUE; + break; + } + if ((HwStrap == SA_PEG_x8_x8_x0) && (PegIndex == 1)) { + DisableFun2 = TRUE; + break; + } + if ((HwStrap == SA_PEG_x8_x4_x4) && (PegIndex == 2)) { + break; + } + + continue; + +PegDisable: + /// + /// SA_PEG_x16_x0_x0 Mode: in this mode, PEG11 and PEG12 need to be Disabled by BIOS in this driver. + /// Only PEG10 needs to be checked (whether has a VGA device on it) and disabled if not. + /// + /// SA_PEG_x8_x8_x0 Mode: in this mode, PEG12 needs to be disabled, PEG10 and PEG11 + /// need to be checked and disabled if no device installed. + /// + /// + /// SA_PEG_x8_x4_x4 Mode: in this mode, all PEG10, PEG11 and PEG12 devices + /// need to be checked and disabled if no device installed. + /// + if (HwStrap == SA_PEG_x16_x0_x0) { + DisableFun0 = TRUE; + DisableFun1 = TRUE; + DisableFun2 = TRUE; + break; + } else if (HwStrap == SA_PEG_x8_x8_x0) { + DisableFun2 = TRUE; + if (PegIndex == 0) { + DisableFun0 = TRUE; + } else { + DisableFun1 = TRUE; + break; + } + } else if (HwStrap == SA_PEG_x8_x4_x4) { + if (PegIndex == 0) { + DisableFun0 = TRUE; + } else if (PegIndex == 1) { + DisableFun1 = TRUE; + } else { + DisableFun2 = TRUE; + break; + } + } + } ///< End of the for Loop + + if (!DisableFun1 || !DisableFun2) { + /// + /// PEG10 must be enabled if PEG11 and/or PEG12 are enabled + /// + if (DisableFun0) { + DisableLinkFunc0 = TRUE; + } + + DisableFun0 = FALSE; + } + + if (MmPci16 (0, SA_PEG_BUS_NUM, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, R_SA_PEG_VID_OFFSET) != 0xFFFF) { + FunctionExists = TRUE; + } else { + FunctionExists = FALSE; + DEBUG ((EFI_D_WARN, "PEG10 Disabled.\n")); + } + if ((DisableFun0 || DisableLinkFunc0) && FunctionExists) { + /// + /// Set D1.F0.R 224h [8] = 1 + /// + MmPci32Or (0, SA_PEG_BUS_NUM, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, R_SA_PEG_LTSSMC_OFFSET, BIT8); + + /// + /// DisableLink. Set D1.F0.R 0B0h [4] (LD (Link Disable) bit in Link Control Register + /// Set D1.F0.R D10h [0]. + /// + MmPci8Or (0, SA_PEG_BUS_NUM, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, R_SA_PEG_LCTL_OFFSET, BIT4); + + /// + /// Poll until D1.F0.R 464h [5:0] = 2 + /// + LoopCount = 0; + while( ((MmPci32 (0, SA_PEG_BUS_NUM, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, R_SA_PEG_REUT_PH1_PIS_OFFSET) & 0x3F) != 2) + && (LoopCount < SA_PEG_LINK_DISABLE_MAXWAIT)) { + StallPpi->Stall (PeiServices, StallPpi, STALL_ONE_MICRO_SECOND*100); //100usec + LoopCount++; + } + + /// + /// Program AFEOVR.RXSQDETOVR + /// PCIe link disable for Switchable GFx + /// Additional Power savings: Set 0:1:0 0xC20 BIT4 = 0 & BIT5 = 1 + /// + MmPci8AndThenOr (0, SA_PEG_BUS_NUM, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, R_SA_PEG_AFEOVR_OFFSET, ~(BIT5 | BIT4), BIT5); + + if (((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId >= EnumHswC0)) || + ((CpuFamilyId == EnumCpuCrw) && (CpuSteppingId >= EnumCrwC0))) { + MaxBndlPwrdnCount = GetMaxBundles(PeiServices, 0, HwStrap); + PowerDownUnusedBundles(PeiServices, 0, HwStrap, MaxBndlPwrdnCount); + } + + if (DisableFun0) { + /// + /// Set D1.F0.R D20h [30] to power off PEG lanes when no device is attached (prvtexdetq=1). + /// Clear D0.F0.R 054h (DEVEN) enable bit. + /// + MmPci32Or (0, SA_PEG_BUS_NUM, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, R_SA_PEG_PEGCOMLCGCTRL_OFFSET, BIT30); + MmPci8And (0, SA_MC_BUS, 0, 0, R_SA_DEVEN, ~B_SA_DEVEN_D1F0EN_MASK); + DEBUG ((EFI_D_WARN, "PEG10 Disabled.\n")); + } + } + + if (MmPci16 (0, SA_PEG_BUS_NUM, SA_PEG11_DEV_NUM, SA_PEG11_FUN_NUM, R_SA_PEG_VID_OFFSET) != 0xFFFF) { + FunctionExists = TRUE; + } else { + FunctionExists = FALSE; + DEBUG ((EFI_D_WARN, "PEG11 Disabled.\n")); + } + if (DisableFun1 && FunctionExists) { + /// + /// Set D1.F1.R 224h [8] = 1 + /// + MmPci32Or (0, SA_PEG_BUS_NUM, SA_PEG11_DEV_NUM, SA_PEG11_FUN_NUM, R_SA_PEG_LTSSMC_OFFSET, BIT8); + + /// + /// DisableLink. Set D1.F1.R 0B0h [4] (LD (Link Disable) bit in Link Control Register. + /// Set D1.F1.R D10h [0]. + /// Set D1.F1.R D20h [30] to power off PEG lanes when no device is attached (prvtexdetq=1). + /// Clear B0,D0,F0 054h (DEVEN) enable bit. + /// + MmPci8Or (0, SA_PEG_BUS_NUM, SA_PEG11_DEV_NUM, SA_PEG11_FUN_NUM, R_SA_PEG_LCTL_OFFSET, BIT4); + + /// + /// Poll until D1.F0.R 464h [13:8] = 2 + /// + LoopCount = 0; + while( (((MmPci32 (0, SA_PEG_BUS_NUM, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, R_SA_PEG_REUT_PH1_PIS_OFFSET) >> 8) & 0x3F) != 2) + && (LoopCount < SA_PEG_LINK_DISABLE_MAXWAIT)) { + StallPpi->Stall (PeiServices, StallPpi, STALL_ONE_MICRO_SECOND*100); //100usec + LoopCount++; + } + + /// + /// Program AFEOVR.RXSQDETOVR + /// PCIe link disable for Switchable GFx + /// Additional Power savings: Set 0:1:1 0xC20 BIT4 = 0 & BIT5 = 1 + /// + MmPci8AndThenOr (0, SA_PEG_BUS_NUM, SA_PEG11_DEV_NUM, SA_PEG11_FUN_NUM, R_SA_PEG_AFEOVR_OFFSET, ~(BIT5 | BIT4), BIT5); + + if (((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId >= EnumHswC0)) || + ((CpuFamilyId == EnumCpuCrw) && (CpuSteppingId >= EnumCrwC0))) { + MaxBndlPwrdnCount = GetMaxBundles(PeiServices, 1, HwStrap); + PowerDownUnusedBundles(PeiServices, 1, HwStrap, MaxBndlPwrdnCount); + } + + MmPci32Or (0, SA_PEG_BUS_NUM, SA_PEG11_DEV_NUM, SA_PEG11_FUN_NUM, R_SA_PEG_PEGCOMLCGCTRL_OFFSET, BIT30); + MmPci8And (0, SA_MC_BUS, 0, 0, R_SA_DEVEN, ~B_SA_DEVEN_D1F1EN_MASK); + DEBUG ((EFI_D_WARN, "PEG11 Disabled.\n")); + } + + if (MmPci16 (0, SA_PEG_BUS_NUM, SA_PEG12_DEV_NUM, SA_PEG12_FUN_NUM, R_SA_PEG_VID_OFFSET) != 0xFFFF) { + FunctionExists = TRUE; + } else { + FunctionExists = FALSE; + DEBUG ((EFI_D_WARN, "PEG12 Disabled.\n")); + } + if (DisableFun2 && FunctionExists) { + /// + /// Set D1.F2.R 224h [8] = 1 + /// + MmPci32Or (0, SA_PEG_BUS_NUM, SA_PEG12_DEV_NUM, SA_PEG12_FUN_NUM, R_SA_PEG_LTSSMC_OFFSET, BIT8); + + /// + /// DisableLink. Set D1.F2.R 0B0h [4] (LD (Link Disable) bit in Link Control Register. + /// Set D1.F2.R D10h [0]. + /// Set D1.F2.R D20h [30] to power off PEG lanes when no device is attached (prvtexdetq=1). + /// Clear B0,D0,F0 054h (DEVEN) enable bit. + /// + MmPci8Or (0, SA_PEG_BUS_NUM, SA_PEG12_DEV_NUM, SA_PEG12_FUN_NUM, R_SA_PEG_LCTL_OFFSET, BIT4); + + /// + /// Poll until D1.F0.R 464h [21:16] = 2 + /// + LoopCount = 0; + while( (((MmPci32 (0, SA_PEG_BUS_NUM, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, R_SA_PEG_REUT_PH1_PIS_OFFSET) >> 16) & 0x3F) != 2) + && (LoopCount < SA_PEG_LINK_DISABLE_MAXWAIT)) { + StallPpi->Stall (PeiServices, StallPpi, STALL_ONE_MICRO_SECOND*100); //100usec + LoopCount++; + } + + /// + /// Program AFEOVR.RXSQDETOVR + /// PCIe link disable for Switchable GFx + /// Additional Power savings: Set 0:1:2 0xC20 BIT4 = 0 & BIT5 = 1 + /// + MmPci8AndThenOr (0, SA_PEG_BUS_NUM, SA_PEG12_DEV_NUM, SA_PEG12_FUN_NUM, R_SA_PEG_AFEOVR_OFFSET, ~(BIT5 | BIT4), BIT5); + + if (((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId >= EnumHswC0)) || + ((CpuFamilyId == EnumCpuCrw) && (CpuSteppingId >= EnumCrwC0))) { + MaxBndlPwrdnCount = GetMaxBundles(PeiServices, 2, HwStrap); + PowerDownUnusedBundles(PeiServices, 2, HwStrap, MaxBndlPwrdnCount); + } + + MmPci32Or (0, SA_PEG_BUS_NUM, SA_PEG12_DEV_NUM, SA_PEG12_FUN_NUM, R_SA_PEG_PEGCOMLCGCTRL_OFFSET, BIT30); + MmPci8And (0, SA_MC_BUS, 0, 0, R_SA_DEVEN, ~B_SA_DEVEN_D1F2EN_MASK); + DEBUG ((EFI_D_WARN, "PEG12 Disabled.\n")); + } + + for (PegComplete = 0; PegComplete < ((sizeof (PegPortTable)) / (sizeof (PEG_PORT))); PegComplete++) { + PegBus = PegPortTable[PegComplete].Bus; + PegDev = PegPortTable[PegComplete].Device; + PegFunc = PegPortTable[PegComplete].Function; + WaitForVc0Negotiation(PeiServices, StallPpi, PegBus, PegDev, PegFunc); + ReportPcieLinkStatus(PegBus, PegDev, PegFunc); + } + + /// + /// Re-check Link again and see if PegLinkFailMask in SaDataHob needed update + /// + if (SaDataHob != NULL) { + LinkStatusGood = 0; + if ((BIT1 & MmPci16(0, 0, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, R_SA_PEG_VC0RSTS_OFFSET)) != BIT1) { + LinkStatusGood |= BIT0; + } + if ((BIT1 & MmPci16(0, 0, SA_PEG10_DEV_NUM, SA_PEG11_FUN_NUM, R_SA_PEG_VC0RSTS_OFFSET)) != BIT1) { + LinkStatusGood |= BIT1; + } + if ((BIT1 & MmPci16(0, 0, SA_PEG10_DEV_NUM, SA_PEG12_FUN_NUM, R_SA_PEG_VC0RSTS_OFFSET)) != BIT1) { + LinkStatusGood |= BIT2; + } + if (SaDataHob->PegData.PegLinkFailMask != (UINT8) (~LinkStatusGood)) { + DEBUG ((EFI_D_INFO, "Original PegLinkFailMask=%X, Final PegLinkFailMask=%X\n", SaDataHob->PegData.PegLinkFailMask, (UINT8) (~LinkStatusGood))); + SaDataHob->PegData.PegLinkFailMask = (UINT8) (~LinkStatusGood); + } + } + + if ((SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_11) && + (SaPlatformPolicyPpi->PcieConfig->PegComplianceTestingMode == 1)) { + for (PegComplete = 0; PegComplete < ((sizeof (PegPortTable)) / (sizeof (PEG_PORT))); PegComplete++) { + PegBus = PegPortTable[PegComplete].Bus; + PegDev = PegPortTable[PegComplete].Device; + PegFunc = PegPortTable[PegComplete].Function; + MmPci32Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_CFG5_OFFSET, BIT0); + } + } + + /// + /// Maximize the dedicated credits for the PEG controllers + /// + MaximizeSharedCredits(); + RebalancePegPerformanceCredits (DisableFun0, DisableFun1, DisableFun2); + return; +} + +VOID +ConfigurePegGenX ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_STALL_PPI *StallPpi, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN PEG_PORT *PegPortTable, + IN UINTN TableIndex, + IN UINT8 CpuSteppingId, + IN UINT8 Gen3Capable + ) +/** + Configure PEG GenX mode + + @param[in] PeiServices - Pointer to the PEI services table + @param[in] StallPpi - Pointer to PEI_STALL_PPI + @param[in] SaPlatformPolicyPpi - Pointer to SA_PLATFORM_POLICY_PPI + @param[in] PegPortTable - Pointer to PEG_PORT array + @param[in] TableIndex - Index in PEG_PORT array + @param[in] CpuSteppingId - CPU stepping + @param[in] Gen3Capable - Selected PEG_PORT is Gen3 capable + + @retval None +**/ +{ + UINT8 PegPortGenx; + UINT8 PegBus; + UINT8 PegDev; + UINT8 PegFunc; + UINT8 PegIndex; + UINT8 MaxLinkWidth; + UINT16 LinkSpeed; + + PegBus = PegPortTable[TableIndex].Bus; + PegDev = PegPortTable[TableIndex].Device; + PegFunc = PegPortTable[TableIndex].Function; + PegIndex = PegPortTable[TableIndex].Index; + MaxLinkWidth = PegPortTable[TableIndex].MaxLinkWidth; + + /// + /// Check if this port exists + /// + if (MmPci16 (0, PegBus, PegDev, PegFunc, PCI_VID) == 0xFFFF) { + return; + } + + /// + /// PegPortGenx: 0 = Auto, 1 = Gen1, 2 = Gen2, 3 = Gen3 + /// + PegPortGenx = SaPlatformPolicyPpi->PcieConfig->PegGenx[PegIndex]; + + if (PegPortGenx == PEG_AUTO) { + DEBUG ((EFI_D_ERROR, "Auto\n")); + LinkSpeed = (UINT16)(MmPci32(0, PegBus, PegDev, PegFunc, R_SA_PEG_LCAP_OFFSET) & 0x0F); + } else { + LinkSpeed = SaPlatformPolicyPpi->PcieConfig->PegGenx[PegIndex]; + DEBUG ((EFI_D_ERROR, "Speed From Setup %x\n", LinkSpeed)); + } + /// + /// If Gen3 is fused off, limit is Gen2 + /// + if (Gen3Capable == FALSE) { + if (LinkSpeed > 2) { + LinkSpeed = 2; + } + } + /// + /// Set the requested speed in Max Link Speed in LCAP[3:0] and Target Link Speed in LCTL2[3:0]. + /// Update LCAP.MLW in the same write as it's a Write-Once field + /// + DEBUG ((EFI_D_INFO, "PEG%x%x (%x:%x:%x) - Max Link Speed = Gen%d\n", PegDev, PegFunc, PegBus, PegDev, PegFunc, LinkSpeed)); + MmPci32AndThenOr (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCAP_OFFSET, 0xFFFFFC00, ((UINT32) MaxLinkWidth << 4) | LinkSpeed); + MmPci16AndThenOr (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCTL2_OFFSET, ~(0x0F), LinkSpeed); + + return; +} + +VOID +AdditionalPegProgramSteps ( + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN UINT8 PegBus, + IN UINT8 PegDev, + IN UINT8 PegFunc + ) +/** + Additional PEG Programming Steps at PEI + + @param[in] SaPlatformPolicyPpi - pointer to SA_PLATFORM_POLICY_PPI + @param[in] PegBus - Pci Bus Number + @param[in] PegDev - Pci Device Number + @param[in] PegFunc - Pci Func Number + + @retval None +**/ +{ + UINT32 Data32And; + UINT32 Data32Or; + + + /// + /// Set L0SLAT[15:0] to 0x2020 + /// + Data32And = (UINT32) ~(0xFFFF); + Data32Or = 0x00002020; + MmPci32AndThenOr (0, PegBus, PegDev, PegFunc, R_SA_PEG_L0SLAT_OFFSET, Data32And, Data32Or); + + /// + /// Disable PEG Debug Align Message - set 258[29] = '1b' + /// + Data32And = (UINT32) ~BIT29; + Data32Or = BIT29; + MmPci32AndThenOr (0, PegBus, PegDev, PegFunc, R_SA_PEG_CFG4_OFFSET, Data32And, Data32Or); + + /// + /// Retrain the link only if VC0 negotiation is complete at this point. + /// This is to support CLB card together with "Aways Enable PEG" option + /// + if ((MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC0RSTS_OFFSET) & BIT1) == 0) { + /// + /// Set LCTL.RL (0xb0 bit 5) to initiate link retrain + /// + MmPci8Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCTL_OFFSET, BIT5); + /// + /// Wait for Link training complete + /// + while (MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_LSTS_OFFSET) & BIT11) { + }; + } + + return; +} + +VOID +MaximizeSharedCredits ( + ) +/** + Maximize the dedicated credits for the PEG controllers +**/ +{ + + UINT64 MchBar; + UINT32 Crdtctl0; + UINT32 Crdtctl1; + UINT32 Crdtctl2; + UINT32 Crdtctl3; + UINT8 Data8; + UINT8 Iotrk; + UINT8 Rrtrk; + BOOL CommitUpdates; + UINT8 i; + + Iotrk = 40; + Rrtrk = 71; + CommitUpdates = FALSE; + + MchBar = McD0PciCfg64 (R_SA_MCHBAR) & ~BIT0; + Crdtctl0 = Mmio32 (MchBar, R_SA_MCHBAR_CRDTCTL0_OFFSET); + Crdtctl1 = Mmio32 (MchBar, R_SA_MCHBAR_CRDTCTL1_OFFSET); + Crdtctl2 = Mmio32 (MchBar, R_SA_MCHBAR_CRDTCTL2_OFFSET); + Crdtctl3 = Mmio32 (MchBar, R_SA_MCHBAR_CRDTCTL3_OFFSET); + + Data8 = 0; + for (i = 0; i < 24; i += 3) { + Data8 += (Crdtctl0 >> i) & 0x7; + Data8 += (Crdtctl1 >> i) & 0x7; + } + if (Data8 > Iotrk) { + DEBUG ((EFI_D_ERROR, "ERROR: Attempted to reserve > %d IOTRK (Attempt = %d)! Skipping programming.\n", Iotrk, Data8)); + CommitUpdates = FALSE; + } else { + Iotrk -= Data8; + DEBUG ((EFI_D_INFO, "IOTRK: Reserved = %d. Shared = %d. Total = %d.\n", Data8, Iotrk, Data8 + Iotrk)); + } + + Data8 = 0; + for (i = 0; i < 24; i += 3) { + Data8 += (Crdtctl2 >> i) & 0x7; + } + Data8 += (Crdtctl2 >> 24) & 0x3F; + if (Data8 > Rrtrk) { + DEBUG ((EFI_D_ERROR, "ERROR: Attempted to reserve > %d RRTRK (Attempt = %d)! Skipping programming.\n", Rrtrk, Data8)); + CommitUpdates = FALSE; + } else { + Rrtrk -= Data8; + DEBUG ((EFI_D_INFO, "RRTRK: Reserved = %d. Shared = %d. Total = %d.\n", Data8, Rrtrk, Data8 + Rrtrk)); + } + + if (CommitUpdates) { + Crdtctl3 = ((Rrtrk & 0x7F) << 6) | (Iotrk & 0x3F); + Mmio32AndThenOr (MchBar, R_SA_MCHBAR_CRDTCTL3_OFFSET, (UINT32) ~(0x00001FFF), Crdtctl3); + } + + return; +} + +VOID +RebalancePegPerformanceCredits ( + IN BOOLEAN DisablePeg10, + IN BOOLEAN DisablePeg11, + IN BOOLEAN DisablePeg12 + ) +/** + Rebalance Credits when PEG controllers so that no starvation occurs + + @param[in] DisablePeg10 - Peg10 disable/enable status + @param[in] DisablePeg11 - Peg11 disable/enable status + @param[in] DisablePeg12 - Peg12 disable/enable status + + @retval None +**/ +{ + UINT64 MchBar; + UINT32 Crdtctl4; + UINT32 Crdtctl6; + UINT32 Crdtctl8; + UINT16 PegLinkWidth10; + UINT16 PegLinkWidth11; + UINT16 PegLinkWidth12; + + MchBar = McD0PciCfg64 (R_SA_MCHBAR) & ~BIT0; + Crdtctl4 = Mmio32 (MchBar, R_SA_MCHBAR_CRDTCTL4_OFFSET); + Crdtctl6 = Mmio32 (MchBar, R_SA_MCHBAR_CRDTCTL6_OFFSET); + Crdtctl8 = Mmio32 (MchBar, R_SA_MCHBAR_CRDTCTL8_OFFSET); + + DEBUG ((EFI_D_INFO, "Crdtctl4 Crdtctl6 Crdtctl8 Before = %x %x %x\n", Crdtctl4, Crdtctl6, Crdtctl8)); + + PegLinkWidth10 = 0; + PegLinkWidth11 = 0; + PegLinkWidth12 = 0; + + if (!DisablePeg10) { + PegLinkWidth10 = (MmPci16 (0, SA_PEG_BUS_NUM, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, R_SA_PEG_LSTS_OFFSET) & 0x3F0) >> 4; + } + if (!DisablePeg11) { + PegLinkWidth11 = (MmPci16 (0, SA_PEG_BUS_NUM, SA_PEG11_DEV_NUM, SA_PEG11_FUN_NUM, R_SA_PEG_LSTS_OFFSET) & 0x3F0) >> 4; + } + if (!DisablePeg12) { + PegLinkWidth12 = (MmPci16 (0, SA_PEG_BUS_NUM, SA_PEG12_DEV_NUM, SA_PEG12_FUN_NUM, R_SA_PEG_LSTS_OFFSET) & 0x3F0) >> 4; + } + + DEBUG ((EFI_D_INFO, "PEG10: LinkDisabled = %x. Width = %x\n", DisablePeg10, PegLinkWidth10)); + DEBUG ((EFI_D_INFO, "PEG11: LinkDisabled = %x. Width = %x\n", DisablePeg11, PegLinkWidth11)); + DEBUG ((EFI_D_INFO, "PEG12: LinkDisabled = %x. Width = %x\n", DisablePeg12, PegLinkWidth12)); + + /// + /// PEG10 = x8 and PEG11 = x8 + /// + if (!DisablePeg10 && !DisablePeg11 && (PegLinkWidth10 == 8) && (PegLinkWidth11 == 8)) { + Crdtctl4 &= ~0x3E0; + Crdtctl4 |= (Crdtctl4 & 0x7C00) >> 5; + Crdtctl6 &= ~0x3E0; + Crdtctl6 |= (Crdtctl6 & 0x7C00) >> 5; + Crdtctl8 &= ~0xFC0; + Crdtctl8 |= (Crdtctl8 & 0x3F000) >> 6; + } + + /// + /// PEG12 = x4 + /// + if (!DisablePeg12 && (PegLinkWidth12 == 4)) { + /// + /// PEG10 = x4 + /// + if (!DisablePeg10 && (PegLinkWidth10 == 4)) { + Crdtctl4 &= ~0x3E0; + Crdtctl4 |= (Crdtctl4 & 0xF8000) >> 10; + Crdtctl6 &= ~0x3E0; + Crdtctl6 |= (Crdtctl6 & 0xF8000) >> 10; + Crdtctl8 &= ~0xFC0; + Crdtctl8 |= (Crdtctl8 & 0xFC0000) >> 12; + } + /// + /// PEG11 = x4 + /// + if (!DisablePeg11 && (PegLinkWidth11 == 4)) { + Crdtctl4 &= ~0x7C00; + Crdtctl4 |= (Crdtctl4 & 0xF8000) >> 5; + Crdtctl6 &= ~0x7C00; + Crdtctl6 |= (Crdtctl6 & 0xF8000) >> 5; + Crdtctl8 &= ~0x3F000; + Crdtctl8 |= (Crdtctl8 & 0xFC0000) >> 6; + } + } + + DEBUG ((EFI_D_INFO, "Crdtctl4 Crdtctl6 Crdtctl8 After = %x %x %x\n", Crdtctl4, Crdtctl6, Crdtctl8)); + + Mmio32AndThenOr (MchBar, R_SA_MCHBAR_CRDTCTL4_OFFSET, (UINT32) ~0x01FFFFFF, Crdtctl4); + Mmio32AndThenOr (MchBar, R_SA_MCHBAR_CRDTCTL6_OFFSET, (UINT32) ~0x01FFFFFF, Crdtctl6); + Mmio32AndThenOr (MchBar, R_SA_MCHBAR_CRDTCTL8_OFFSET, (UINT32) ~0x3FFFFFFF, Crdtctl8); + + return; +} + +VOID +PegPreDetectionSteps ( + IN UINT8 PegBus, + IN UINT8 PegDev, + IN UINT8 PegFunc, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +/** + Additional PEG Programming Steps before PEG detection at PEI + + @param[in] PegBus - Pci Bus Number + @param[in] PegDev - Pci Device Number + @param[in] PegFunc - Pci Func Number + @param[in] SaPlatformPolicyPpi - Pointer to SA_PLATFORM_POLICY_PPI +**/ +{ + UINT32 Data32; + UINT32 Data32And; + UINT32 Data32Or; + UINT32 i; + CPU_STEPPING CpuSteppingId; + CPU_FAMILY CpuFamilyId; + + CpuSteppingId = GetCpuStepping(); + CpuFamilyId = GetCpuFamily(); + + + Data32Or = (UINT32) (BIT4 | BIT3 | BIT2 | BIT1 | BIT0); + Data32And = (UINT32) ~(BIT8); + MmPci32AndThenOr (0, PegBus, PegDev, PegFunc, R_SA_PEG_LTSSMC_OFFSET, Data32And, Data32Or); + + /// + /// Set PPCIE_CR_REUT_OVR_CTL_0_1_0_MMR.GRCLKGTDIS [28] to 1 (for PCIE Margin Test, Default is kept 0) + /// + if ((PegDev == 1) && (PegFunc == 0)) { + Data32And = (UINT32) ~BIT28; + Data32Or = 0; + MmPci32AndThenOr (0, PegBus, PegDev, PegFunc, R_SA_PEG_REUT_OVR_CTL_OFFSET, Data32And, Data32Or); + } + + if ((PegDev == 1) && (PegFunc == 0)) { + /// + /// DCBLNC = 0 + /// + Data32And = (UINT32) ~(BIT3 | BIT2); + Data32Or = 0; + for (i = 0; i < SA_PEG_MAX_BUNDLE; i++) { + MmPci32AndThenOr (0, PegBus, PegDev, PegFunc, R_SA_PEG_G3CTL0_OFFSET + i * BUNDLE_STEP, Data32And, Data32Or); + } + } + + /// + /// DEBUP3[4] = 1 + /// + if ((CpuFamilyId == EnumCpuHsw) || (CpuFamilyId == EnumCpuCrw)) { + Data32And = (UINT32) ~(BIT4); + Data32Or = BIT4; + MmPci32AndThenOr (0, PegBus, PegDev, PegFunc, R_SA_PEG_DEBUP3_OFFSET, Data32And, Data32Or); + } + + /// + /// FCLKGTTLLL[2] = 1 + /// + if (((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId < EnumHswC0)) || + ((CpuFamilyId == EnumCpuCrw) && (CpuSteppingId < EnumCrwC0))) { + Data32And = (UINT32) ~(BIT2); + Data32Or = BIT2; + MmPci32AndThenOr (0, PegBus, PegDev, PegFunc, R_SA_PEG_FCLKGTTLLL_OFFSET, Data32And, Data32Or); + } + + /// + /// Program Read-Only Write-Once Registers + /// R 308h [31:0] + /// R 314h [31:0] + /// R 32Ch [31:0] + /// R 330h [31:0] + /// + Data32 = MmPci32 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC0PRCA_OFFSET); + MmPci32 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC0PRCA_OFFSET) = Data32; + Data32 = MmPci32 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC0NPRCA_OFFSET); + MmPci32 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC0NPRCA_OFFSET) = Data32; + Data32 = MmPci32 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC1PRCA_OFFSET); + MmPci32 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC1PRCA_OFFSET) = Data32; + Data32 = MmPci32 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC1NPRCA_OFFSET); + MmPci32 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC1NPRCA_OFFSET) = Data32; + + return; +} +#endif // PEG_FLAG + +#if defined(DMI_FLAG) || defined(PEG_FLAG) +UINT32 +SendVcuApiSequence ( + IN UINT32 MchBar, + IN UINT32 Address, + IN UINT16 OpCode, + IN UINT32 WriteData + ) +/** + Send one sequence to VCU MailBox + + @param[in] MchBar - MCHBAR value + @param[in] Address - Target address + @param[in] OpCode - OpCode number + @param[in] WriteData - Data value (only used if OpCode is a write) +**/ +{ + BOOL IsWrite; + BOOL IsCsr; + UINT32 DataOpCode; + UINT32 SequenceId; + UINT32 VcuData; + CPU_FAMILY CpuFamilyId; + CPU_STEPPING CpuSteppingId; + + CpuFamilyId = GetCpuFamily(); + CpuSteppingId = GetCpuStepping(); + + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + if ((OpCode == V_SA_VCU_OPCODE_WRITE_CSR_REV1) || (OpCode == V_SA_VCU_OPCODE_WRITE_MMIO_REV1)) { + IsWrite = TRUE; + } else { + IsWrite = FALSE; + } + + if ((OpCode == V_SA_VCU_OPCODE_READ_CSR_REV1) || (OpCode == V_SA_VCU_OPCODE_WRITE_CSR_REV1)) { + IsCsr = TRUE; + } else { + IsCsr = FALSE; + } + } else { + if ((OpCode == V_SA_VCU_OPCODE_WRITE_CSR_REV2) || (OpCode == V_SA_VCU_OPCODE_WRITE_MMIO_REV2)) { + IsWrite = TRUE; + } else { + IsWrite = FALSE; + } + + if ((OpCode == V_SA_VCU_OPCODE_READ_CSR_REV2) || (OpCode == V_SA_VCU_OPCODE_WRITE_CSR_REV2)) { + IsCsr = TRUE; + } else { + IsCsr = FALSE; + } + } + + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + if (IsWrite) { + DataOpCode = V_SA_VCU_OPCODE_WRITE_DATA_REV1; + if (IsCsr) { + SequenceId = V_SA_VCU_SEQID_WRITE_CSR_REV1; + } else { + SequenceId = V_SA_VCU_SEQID_WRITE_MMIO_REV1; + } + } else { + DataOpCode = V_SA_VCU_OPCODE_READ_DATA_REV1; + if (IsCsr) { + SequenceId = V_SA_VCU_SEQID_READ_CSR_REV1; + } else { + SequenceId = V_SA_VCU_SEQID_READ_MMIO_REV1; + } + } + } else { + if (IsWrite) { + DataOpCode = V_SA_VCU_OPCODE_WRITE_DATA_REV2; + if (IsCsr) { + SequenceId = V_SA_VCU_SEQID_WRITE_CSR_REV2; + } else { + SequenceId = V_SA_VCU_SEQID_WRITE_MMIO_REV2; + } + } else { + DataOpCode = V_SA_VCU_OPCODE_READ_DATA_REV2; + if (IsCsr) { + SequenceId = V_SA_VCU_SEQID_READ_CSR_REV2; + } else { + SequenceId = V_SA_VCU_SEQID_READ_MMIO_REV2; + } + } + } + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + SendVcuApiCmd (MchBar, V_SA_VCU_OPCODE_OPEN_SEQ_REV1, SequenceId); + } else { + SendVcuApiCmd (MchBar, V_SA_VCU_OPCODE_OPEN_SEQ_REV2, SequenceId); + } + SendVcuApiCmd (MchBar, OpCode, Address); + SendVcuApiCmd (MchBar, DataOpCode, WriteData); + VcuData = Mmio32 (MchBar, R_SA_MCHBAR_VCU_MAILBOX_DATA_OFFSET); + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + SendVcuApiCmd (MchBar, V_SA_VCU_OPCODE_CLOSE_SEQ_REV1, SequenceId); + } else { + SendVcuApiCmd (MchBar, V_SA_VCU_OPCODE_CLOSE_SEQ_REV2, SequenceId); + } + + return VcuData; +} + +VOID +SendVcuApiCmd ( + IN UINT32 MchBar, + IN UINT32 Interface, + IN UINT32 Data + ) +/** + Send one command to VCU MailBox + + @param[in] MchBar - MCHBAR value + @param[in] Interface - Interface number + @param[in] Data - Data value +**/ +{ + UINT32 ResponseCounter; + UINT16 ResponseCode; + UINT32 BusyCounter; + UINT32 RunBusy; + BOOL BusyStatus; + + ResponseCode = V_SA_VCU_RESPONSE_SUCCESS; + for (ResponseCounter = 0; ResponseCounter < V_SA_VCU_RESPONSE_RETRY_LIMIT; ResponseCounter++) { + Mmio32 (MchBar, R_SA_MCHBAR_VCU_MAILBOX_DATA_OFFSET) = Data; + Mmio32 (MchBar, R_SA_MCHBAR_VCU_MAILBOX_INTERFACE_OFFSET) = (Interface | B_SA_MCHBAR_VCU_STATUS_RUN_BUSY); + BusyStatus = FALSE; + for (BusyCounter = 0; BusyCounter < V_SA_VCU_STATUS_BUSY_LIMIT; BusyCounter++) { + RunBusy = Mmio32 (MchBar, R_SA_MCHBAR_VCU_MAILBOX_INTERFACE_OFFSET); + BusyStatus = (RunBusy & B_SA_MCHBAR_VCU_STATUS_RUN_BUSY) ? TRUE : FALSE; + if (BusyStatus == FALSE) { + break; + } + } + + if (BusyStatus) { + DEBUG ((EFI_D_INFO, "VCU Busy Timeout after %d tries: MCHBAR=%8.8X. Interface=%8.8X. Data=%4.4X.\n", BusyCounter, MchBar, Interface, Data)); + } + ResponseCode = Mmio16 (MchBar, R_SA_MCHBAR_VCU_MAILBOX_INTERFACE_OFFSET); + if (ResponseCode == V_SA_VCU_RESPONSE_SUCCESS) { + break; + } + } + + if (ResponseCode != V_SA_VCU_RESPONSE_SUCCESS) { + DEBUG ((EFI_D_ERROR, "ERROR: VCU Response Error after %d tries: MCHBAR=%8.8X. Interface=%4.4X. Data=%8.8X. ResponseCode=%4.4X\n", ResponseCounter, MchBar, Interface, Data, ResponseCode)); + } + + return; +} +#endif // DMI_FLAG || PEG_FLAG + +#ifdef PEG_FLAG + +UINT8 +GetMaxBundles ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINT8 PegFunc, + IN UINT8 HwStrap + ) +/** + GetMaxBundles: Get the maximum bundle numbers for the corresponding PEG + + @param[in] PeiServices - Pointer to the PEI services table + @param[in] PegFunc - Points to PEG0/PEG1/PEG2/... + @param[in] HwStrap - Points to PEG configuration information [x16_x0_x0/x8_x8_x0/x8_x4_x4/...] + + @retval - MaxBndlPwrdnCount [Maximun number of bundles for this HW configuration] +**/ +{ + UINT8 MaxBndlPwrdnCount; + + MaxBndlPwrdnCount = 0; + + DEBUG ((EFI_D_INFO, "In GetMaxBundles procedure\n")); + + if (PegFunc == 0) { // PEG10 + if (HwStrap == SA_PEG_x16_x0_x0) { + MaxBndlPwrdnCount = 8; + } else { + MaxBndlPwrdnCount = 4; + } + } else if (PegFunc == 1) { // PEG11 + if (HwStrap == SA_PEG_x8_x8_x0) { + MaxBndlPwrdnCount = 4; + } else if (HwStrap == SA_PEG_x8_x4_x4) { + MaxBndlPwrdnCount = 2; + } + } else if (PegFunc == 2) { // PEG12 + if (HwStrap == SA_PEG_x8_x4_x4) { + MaxBndlPwrdnCount = 2; + } + } + + DEBUG ((EFI_D_INFO, "MaxBndlPwrdnCount = %d\n", MaxBndlPwrdnCount)); + return MaxBndlPwrdnCount; +} + +VOID +PowerDownUnusedBundles ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINT8 PegFunc, + IN UINT8 HwStrap, + IN UINT8 BndlPwrdnCount + ) +/** + PowerDownUnusedBundles: Program the PEG BundleSpare registers for power on sequence [PowerOff unused bundles for PEGs] + + @param[in] PeiServices - Pointer to the PEI services table + @param[in] PegFunc - Points to PEG0/PEG1/PEG2/... + @param[in] HwStrap - Points to PEG configuration information [x16_x0_x0/x8_x8_x0/x8_x4_x4/...] + @param[in] BndlPwrdnCount - Points to how many bundles are unused and should be powered down +**/ +{ + BOOLEAN PegLaneReversal; + UINT8 BndlPwrdnFirst; + + UINT8 i; + UINT8 j; + + PegLaneReversal = FALSE; + BndlPwrdnFirst = 0; + + DEBUG ((EFI_D_INFO, "In PowerDownUnusedBundles sequence\n")); + + if (BndlPwrdnCount == 0) { + /// + /// If all lanes are used. Do nothing + /// + DEBUG ((EFI_D_INFO, "All lanes are used. Do nothing.\n")); + return; + } + + if ((MmPci32 (0, SA_PEG_BUS_NUM, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, R_SA_PEG_PEGTST_OFFSET) & BIT20) != 0) { + DEBUG ((EFI_D_INFO, "PegLaneReversal is true\n")); + PegLaneReversal = TRUE; + } + + if (PegFunc == 0) { // PEG10 + if (HwStrap == SA_PEG_x16_x0_x0) { + if (!PegLaneReversal) { + BndlPwrdnFirst = 8 - BndlPwrdnCount; + } else { + BndlPwrdnFirst = 0; + } + } else { + if (!PegLaneReversal) { + BndlPwrdnFirst = 4 - BndlPwrdnCount; + } else { + BndlPwrdnFirst = 4; + } + } + } else if (PegFunc == 1) { // PEG11 + if (HwStrap == SA_PEG_x8_x8_x0) { + if (!PegLaneReversal) { + BndlPwrdnFirst = 8 - BndlPwrdnCount; + } else { + BndlPwrdnFirst = 0; + } + } else if (HwStrap == SA_PEG_x8_x4_x4) { + if (!PegLaneReversal) { + BndlPwrdnFirst = 6 - BndlPwrdnCount; + } else { + BndlPwrdnFirst = 2; + } + } + } else if (PegFunc == 2) { // PEG12 + if (HwStrap == SA_PEG_x8_x4_x4) { + if (!PegLaneReversal) { + BndlPwrdnFirst = 8 - BndlPwrdnCount; + } else { + BndlPwrdnFirst = 0; + } + } + } + + /// + /// Power down unused lanes per request + /// + DEBUG ((EFI_D_INFO, "BNDL_PWRDN PEG%d%d[%d:%d]\n", 0, PegFunc, BndlPwrdnFirst, (BndlPwrdnFirst+BndlPwrdnCount-1))); + for (i = BndlPwrdnFirst, j=1; j <= BndlPwrdnCount; i++, j++) { + MmPci32Or (0, SA_PEG_BUS_NUM, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, R_SA_PEG_BND0SPARE_OFFSET + (i * BUNDLE_STEP), BIT31); + } + + return; +} +#endif // PEG_FLAG diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PciExpressInit.h b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PciExpressInit.h new file mode 100644 index 0000000..2ca1bbe --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PciExpressInit.h @@ -0,0 +1,452 @@ +/** @file + PciExpressInit header file + +@copyright + Copyright (c) 1999 - 2012 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 + +**/ +#ifndef _PCIEXPRESS_INIT_H_ +#define _PCIEXPRESS_INIT_H_ + +#include "EdkIIGluePeim.h" +#include "SaAccess.h" +#include "PchAccess.h" +#include "EdkIIGluePcdPciExpressLib.h" +#include "EdkIIGlueConfig.h" +#include "Pci30.h" +#include "CpuRegs.h" +#include "CpuPlatformLib.h" + +/// +/// Driver Consumed PPI Prototypes +/// +#include EFI_PPI_DEPENDENCY (Stall) +#include EFI_PPI_DEPENDENCY (SaPlatformPolicy) + +#define PEG_AUTO 0 +#define PEG_GEN1 1 +#define PEG_GEN2 2 +#define PEG_GEN3 3 + +#define DMI_GEN1 1 +#define DMI_GEN2 2 + +#define LANE_STEP 0x10 +#define BUNDLE_STEP 0x20 + +typedef struct { + UINT8 Bus; + UINT8 Device; + UINT8 Function; + UINT8 Index; + BOOLEAN PresenceDetect; + UINT8 MaxLinkWidth; + UINT8 EndpointMaxLinkSpeed; +} PEG_PORT; + +/// +/// Data structure used in Sampler Calibration +/// +#pragma pack(1) +typedef struct _SAMPLE { + UINT8 Data; + UINT16 Count; +} DATA_SAMPLE; +#pragma pack() + +#define MAX_CODES 10 + +/// +/// Data structure used in Preset Search +/// +typedef struct _PRESET_DATA { + UINT8 Preset; + UINTN TimingMargin[SA_PEG_MAX_BUNDLE]; + UINTN VoltageUpMargin[SA_PEG_MAX_BUNDLE]; + UINTN VoltageDownMargin[SA_PEG_MAX_BUNDLE]; +} PRESET_DATA; + +#define MAX_PRESETS 3 + +#define SA_PEG_SAMPLER_ITERATIONS 500 +/// +/// Common register access macros - use either DMIBAR or PEG10 +/// +#define SaMmio32AndThenOr(BaseAddr, Device, Register, AndData, OrData) \ + if (BaseAddr != 0) { \ + Mmio32AndThenOr (BaseAddr, Register, AndData, OrData); \ + } else { \ + MmPci32AndThenOr (0, 0, Device, 0, Register, AndData, OrData); \ + } + +#ifdef PEG_FLAG +VOID +BubbleSort ( + IN OUT DATA_SAMPLE Array[] + ) +/** + Bubble sort from DATA_SAMPLE + + @param[in, out] - Array[]: array of DATA_SAMPLE + + @retval None +**/ +; + +UINT32 +GetMiddleValue ( + IN OUT DATA_SAMPLE Array[] + ) +/** + Get Middle Value from DATA_SAMPLE + + @param[in, out] - Array[]: array of DATA_SAMPLE + + @retval UINT32 : Middle Value of DATA_SAMPLE +**/ +; + +VOID +SetLoadBus ( + IN UINT32 DmiBar, + IN UINTN Dev, + IN UINTN Lane, + IN UINT32 LoadSel, + IN UINT32 LoadData, + IN UINT8 CpuSteppingId + ) +/** + Set Load Bus + + @param[in] DmiBar - DMIBAR address + @param[in] Dev - Device Number + @param[in] Lane - Number of Lane + @param[in] LoadSel - Load selection value + @param[in] LoadData - Load Data + @param[in] CpuSteppingId - CPUID.1.EAX[3:0], CPU stepping ID + + @retval None +**/ +; + +UINT32 +GetMonBus ( + IN UINT32 DmiBar, + IN UINTN Dev, + IN UINTN Lane, + IN UINT32 LoadSel, + IN UINT8 CpuSteppingId + ) +/** + Get monitor bus from the lane selected + + @param[in] DmiBar - DMIBAR address + @param[in] Dev - Device number + @param[in] Lane - Number of Lane + @param[in] LoadSel - Load selection value + @param[in] LoadData - Load selecttion data + @param[in] CpuSteppingId - CPUID.1.EAX[3:0], CPU stepping ID + + @retval UINT32 - Load bus address +**/ +; + +VOID +DumpSamplerValues ( + IN UINT32 DmiBar, + IN UINT8 CpuSteppingId, + IN UINTN Dev, + IN UINTN LanesCount + ) +/** + Dump Sampler Values + + @param[in] DmiBar - DMIBAR address + @param[in] CpuSteppingId - CPUID.1.EAX[3:0], CPU stepping ID + @param[in] Dev - Device number + @param[in] LanesCount - Value of Lanes + + @retval None +**/ +; +#endif // PEG_FLAG + +#if defined(DMI_FLAG) || defined(PEG_FLAG) +VOID +PegDmiRecipe ( + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN UINT32 MchBar, + IN UINT32 DmiBar, + IN UINTN Dev, + IN UINT8 SwingControl + ) +/** + Perform PEG/DMI PCIe Recipe steps + + @param[in] SaPlatformPolicyPpi - Pointer to SA_PLATFORM_POLICY_PPI + @param[in] MchBar - MCHBAR or zero if called for PEG + @param[in] DmiBar - DMIBAR or zero if called for PEG + @param[in] Dev - PEG device number: 1 for PEG10, 0 if called for DMI. + @param[in] SwingControl - 1 = Half, 2 = Full + + @retval None +**/ +; +#endif // DMI_FLAG || PEG_FLAG + +#ifdef PEG_FLAG +VOID +ConfigurePegGenX ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_STALL_PPI *StallPpi, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN PEG_PORT *PegPortTable, + IN UINTN TableIndex, + IN UINT8 CpuSteppingId, + IN UINT8 Gen3Capable + ) +/** + Configure PEG GenX mode + + @param[in] PeiServices - Pointer to the PEI services table + @param[in] StallPpi - Pointer to PEI_STALL_PPI + @param[in] SaPlatformPolicyPpi - Pointer to SA_PLATFORM_POLICY_PPI + @param[in] PegPortTable - Pointer to PEG_PORT array + @param[in] TableIndex - Index in PEG_PORT array + @param[in] CpuSteppingId - CPU stepping + @param[in] Gen3Capable - Selected PEG_PORT is Gen3 capable + + @retval None +**/ +; + +VOID +AdditionalPegProgramSteps ( + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN UINT8 PegBus, + IN UINT8 PegDev, + IN UINT8 PegFunc + ) +/** + Additional PEG Programming Steps at PEI + + @param[in] SaPlatformPolicyPpi - SaPlatformPolicyPpi to access the GtConfig related information + @param[in] PegBus - Pci Bus Number + @param[in] PegDev - Pci Device Number + @param[in] PegFunc - Pci Func Number +**/ +; + +VOID +MaximizeSharedCredits ( + ) +/** + Maximize the dedicated credits for the PEG controllers +**/ +; + +VOID +RebalancePegPerformanceCredits ( + IN BOOLEAN DisablePeg10, + IN BOOLEAN DisablePeg11, + IN BOOLEAN DisablePeg12 + ) +/** + Rebalance Credits when PEG controllers so that no stavation occurs + + @param[in] DisablePeg10 - Peg10 disable/enable status + @param[in] DisablePeg11 - Peg11 disable/enable status + @param[in] DisablePeg12 - Peg12 disable/enable status + + @retval None +**/ +; + +VOID +PegPreDetectionSteps ( + IN UINT8 PegBus, + IN UINT8 PegDev, + IN UINT8 PegFunc, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +/** + Additional PEG Programming Steps before PEG detection at PEI + + @param[in] PegBus - Pci Bus Number + @param[in] PegDev - Pci Device Number + @param[in] PegFunc - Pci Func Number + @param[in] SaPlatformPolicyPpi - Pointer to SA_PLATFORM_POLICY_PPI +**/ +; +#endif // PEG_FLAG + +#if defined(DMI_FLAG) || defined(PEG_FLAG) +UINT32 +SendVcuApiSequence ( + IN UINT32 MchBar, + IN UINT32 Address, + IN UINT16 OpCode, + IN UINT32 WriteData + ) +/** + Send one sequence to VCU MailBox + + @param[in] MchBar - MCHBAR value + @param[in] Address - Target address + @param[in] OpCode - OpCode number + @param[in] WriteData - Data value (only used if OpCode is a write) +**/ +; + +VOID +SendVcuApiCmd ( + IN UINT32 MchBar, + IN UINT32 Interface, + IN UINT32 Data + ) +/** + Send one command to VCU MailBox + + @param[in] MchBar - MCHBAR value + @param[in] Interface - Interface number + @param[in] Data - Data value +**/ +; + +VOID +ReportPcieLinkStatus ( + IN UINT8 PegBus, + IN UINT8 PegDev, + IN UINT8 PegFunc +) +/** + This function reports a PEG controller's link status + + @param[in] PegBus - Peg Bus + @param[in] PegDev - Peg Device + @param[in] PegFunc - Peg Function + + @retval None +**/ +; + +VOID +WaitForVc0Negotiation ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_STALL_PPI *StallPpi, + IN UINT8 PegBus, + IN UINT8 PegDev, + IN UINT8 PegFunc +) +/** + This function prints the time required for VC0 Negotiation Pending to be cleared. Quits after 100 msec. + + @param[in] PeiServices - Pointer to the PEI services table + @param[in] StallPpi - Pointer to PEI_STALL_PPI + @param[in] PegBus - Peg Bus + @param[in] PegDev - Peg Device + @param[in] PegFunc - Peg Function + + @retval None +**/ +; + +UINT32 +PcieFindCapId ( + IN UINT8 Bus, + IN UINT8 Device, + IN UINT8 PegFunc, + IN UINT8 CapId + ) +/** + Find the Offset to a given Capabilities ID + CAPID list: + 0x01 = PCI Power Management Interface + 0x04 = Slot Identification + 0x05 = MSI Capability + 0x10 = PCI Express Capability + + @param[in] Bus - Pci Bus Number + @param[in] Device - Pci Device Number + @param[in] PegFunc - Pci Function Number + @param[in] CapId - CAPID to search for + + @retval 0 - CAPID not found + @retval Other - CAPID found, Offset of desired CAPID +**/ +; + +VOID +ProgramPreset ( + IN UINT8 Direction, + IN UINT8 PresetValue, + IN UINT8 PegFunc, + IN UINT8 Lane + ) +/** + Program PEG Gen3 preset value + + @param[in] Direction - 0 = Root Port, 1 = End Point + @param[in] PresetValue - Preset value to program + @param[in] PegFunc - Peg function number to be configured + @param[in] Lane - Lane to be configured + + @retval None +**/ +; + +#endif // DMI_FLAG || PEG_FLAG + +#ifdef PEG_FLAG +UINT8 +GetMaxBundles ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINT8 PegFunc, + IN UINT8 HwStrap + ) +/** + GetMaxBundles: Get the maximum bundle numbers for the corresponding PEG + + @param[in] PeiServices - Pointer to the PEI services table + @param[in] PegFunc - Points to PEG0/PEG1/PEG2/... + @param[in] HwStrap - Points to PEG configuration information [x16_x0_x0/x8_x8_x0/x8_x4_x4/...] + + @retval - MaxBndlPwrdnCount [Maximun number of bundles for this HW configuration] +**/ +; + +VOID +PowerDownUnusedBundles ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINT8 PegFunc, + IN UINT8 HwStrap, + IN UINT8 BndlPwrdnCount + ) +/** + PowerDownUnusedBundles: Program the PEG BundleSpare registers for power on sequence [PowerOff unused bundles for PEGs] + + @param[in] PeiServices - Pointer to the PEI services table + @param[in] PegFunc - Points to PEG0/PEG1/PEG2/... + @param[in] HwStrap - Points to PEG configuration information [x16_x0_x0/x8_x8_x0/x8_x4_x4/...] + @param[in] BndlPwrdnCount - Points to how many bundles are unused and should be powered down + + @retval - None +**/ +; +#endif // PEG_FLAG + +#endif diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTraining.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTraining.c new file mode 100644 index 0000000..26f16be --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTraining.c @@ -0,0 +1,628 @@ +/** @file + This driver trains the PEG interface. + +@copyright + Copyright (c) 2012 - 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 "PcieTraining.h" + +#ifdef PEG_FLAG + +UINT16 +GetErrorTarget ( + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +{ + UINT16 ErrorTarget; + + if ((SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_3) && + (SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearchErrorTarget >= 1)) { + ErrorTarget = SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearchErrorTarget; + } else { + ErrorTarget = 4; + } + + return ErrorTarget; +} + +VOID +GetPortInfo ( + OUT PORT_INFO *PortInfoList, + OUT UINT8 *PortInfoListLength, + OUT BOOLEAN *SkipBundle0 + ) +{ + UINT32 HwStrap; + UINT8 PegBus; + UINT8 PegDev; + UINT8 PcieController; + UINT8 Index; + UINT8 Lane; + UINT8 LaneIndex; + UINT8 FurcationSetup[SA_PEG_MAX_FUN]; + UINT8 PcieControllerList[SA_PEG_MAX_FUN]; + UINT8 NumberToCheck; + UINT8 StartLane; + UINT8 Width; + UINT32 Lcap; + UINT32 CapOffset; + CPU_FAMILY CpuFamilyId; + CPU_STEPPING CpuSteppingId; + + PegBus = SA_MC_BUS; + PegDev = 1; + HwStrap = (McD1PciCfg32(R_SA_PEG_FUSESCMN_OFFSET) >> 16) & 0x3; + CpuFamilyId = GetCpuFamily(); + CpuSteppingId = GetCpuStepping(); + + switch(HwStrap) { + case SA_PEG_x8_x4_x4: + FurcationSetup[0] = 8; + FurcationSetup[1] = 4; + FurcationSetup[2] = 4; + NumberToCheck = 3; + break; + case SA_PEG_x8_x8_x0: + FurcationSetup[0] = 8; + FurcationSetup[1] = 8; + NumberToCheck = 2; + break; + default: + case SA_PEG_x16_x0_x0: + FurcationSetup[0] = 16; + NumberToCheck = 1; + break; + } + + /// + /// Figure out which PcieControllers are enabled + /// + (*PortInfoListLength) = 0; + for (PcieController = 0; PcieController < NumberToCheck; PcieController++) { + /// + /// Sanity check to make sure width > 0 + /// + if (FurcationSetup[PcieController] == 0) { + continue; + } + + /// + /// Check to make sure the Root Port Exists + /// + if (MmPci16 (0, PegBus, PegDev, PcieController, PCI_VID) == 0xFFFF) { + continue; + } + + /// + /// Add the PcieController to the list of enabled controllers + /// + PcieControllerList[(*PortInfoListLength)] = PcieController; + (*PortInfoListLength)++; + } + + /// + /// If needed, skip Bundle 0's preset search and use Bundle 1's preset instead. + /// + (*SkipBundle0) = FALSE; + if (((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId < EnumHswC0)) || + ((CpuFamilyId == EnumCpuCrw) && (CpuSteppingId < EnumCrwC0))) { + (*SkipBundle0) = TRUE; + } + if ((*SkipBundle0)) { + DEBUG ((EFI_D_INFO, "Skipping each controller's Lane 0-1 preset searches; using their Lane 2 preset instead.\n")); + } + + StartLane = 0; + for (Index = 0; Index < (*PortInfoListLength); Index++) { + PcieController = PcieControllerList[Index]; + + /// + /// Get information for the current port + /// + (PortInfoList[Index]).EnableMargin = TRUE; + (PortInfoList[Index]).FoundUsablePreset = FALSE; + (PortInfoList[Index]).PegPort.Bus = PegBus; + (PortInfoList[Index]).PegPort.Device = PegDev; + (PortInfoList[Index]).PegPort.Function = PcieController; + (PortInfoList[Index]).PegPort.Index = PcieController; + (PortInfoList[Index]).PegPort.EndpointMaxLinkSpeed = 0; + ReportPcieLinkStatus (PegBus, PegDev, PcieController); + Width = GetNegotiatedWidth(&((PortInfoList[Index]).PegPort)); + (PortInfoList[Index]).LaneListLength = Width; + for (Lane = 0, LaneIndex = 0; Lane < Width; Lane++) { + if ((*SkipBundle0)) { + if ((Lane == 0) || (Lane == 1)) { + (PortInfoList[Index]).LaneListLength--; + continue; + } + } + if (LaneIndex < SA_PEG_MAX_LANE) { + (PortInfoList[Index]).LaneList[LaneIndex] = (Lane + StartLane); + } + LaneIndex++; + } + + /// + /// Check that both root port and endpoint support Gen3 + /// + Lcap = MmPci32 (0, PegBus, PegDev, PcieController, R_SA_PEG_LCAP_OFFSET); + if ((Lcap & 0x0F) != 3) { + DEBUG ((EFI_D_INFO, " PEG%x%x (%x:%x:%x) - Root Port is not Gen3-capable. Max Link Speed = %d.\n", + PegDev, PcieController, PegBus, PegDev, PcieController, Lcap & 0x0F)); + (PortInfoList[Index]).LinkIsGen3Capable = FALSE; + } else { + + DEBUG ((EFI_D_INFO, " PEG%x%x (%x:%x:%x) - Root Port is Gen3-capable.\n", + PegDev, PcieController, PegBus, PegDev, PcieController)); + + /// + /// Set PEG PortBus = 1 to Read Endpoint. + /// + MmPci32AndThenOr (0, PegBus, PegDev, PcieController, 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; + + /// + /// Save end point vendor id and device id + /// + (PortInfoList[Index]).EndPointVendorIdDeviceId = MmPci32 (0, 1, 0, 0, 0); + + /// + /// Negotiation Done? + /// + if ((MmPci16 (0, PegBus, PegDev, PcieController, R_SA_PEG_VC0RSTS_OFFSET) & BIT1) != 0) { + (PortInfoList[Index]).LinkIsGen3Capable = FALSE; + DEBUG ((EFI_D_INFO, " PEG%x%x (%x:%x:%x) - VC0 negotiation is pending! Skipping endpoint.\n", + PegDev, PcieController, PegBus, PegDev, PcieController, Lcap & 0x0F)); + ReportPcieLinkStatus (PegBus, PegDev, PcieController); + } else { + /// + /// Get the pointer to the Port PCI Express Capability Structure. + /// + CapOffset = PcieFindCapId (1, 0, 0, EFI_PCI_CAPABILITY_ID_PCIEXP); + if (CapOffset == 0) { + (PortInfoList[Index]).LinkIsGen3Capable = FALSE; + DEBUG ((EFI_D_INFO, " PEG%x%x (%x:%x:%x) - Endpoint is not Gen3-capable. No PCIe Capability found.\n", + PegDev, PcieController, PegBus, PegDev, PcieController, Lcap & 0x0F)); + } else { + Lcap = MmPci32 (0, 1, 0, 0, CapOffset + 0x0C); + (PortInfoList[Index]).PegPort.EndpointMaxLinkSpeed = Lcap & 0x0F; + if ((Lcap & 0x0F) < 3) { + (PortInfoList[Index]).LinkIsGen3Capable = FALSE; + DEBUG ((EFI_D_INFO, " PEG%x%x (%x:%x:%x) - Endpoint is not Gen3-capable. Max Link Speed = %d.\n", + PegDev, PcieController, PegBus, PegDev, PcieController, Lcap & 0x0F)); + } else { + (PortInfoList[Index]).LinkIsGen3Capable = TRUE; + DEBUG ((EFI_D_INFO, " PEG%x%x (%x:%x:%x) - Endpoint is Gen3-capable\n", + PegDev, PcieController, PegBus, PegDev, PcieController, Lcap & 0x0F)); + } + } + } + /// + /// Restore bus numbers on the PEG bridge. + /// + MmPci32And (0, PegBus, PegDev, PcieController, PCI_PBUS, 0xFF0000FF); + } + + StartLane += FurcationSetup[PcieController]; + } ///< End of for each port + + return; +} + +EFI_STATUS +RunMarginTest ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN SA_DATA_HOB *SaDataHob, + IN PEI_STALL_PPI *StallPpi, + IN UINT32 MonitorPort, + IN PORT_INFO *PortInfoList, + IN UINT8 PortInfoListLength, + IN MARGIN_TEST_TYPE MarginTest, + OUT INT32 *Margins + ) +{ + EFI_STATUS Status; + UINT8 *LaneList; + UINT8 Lane; + UINT8 PortListIndex; + UINT8 OriginalSpeed; + UINT8 OriginalWidth; + UINT8 LaneListLength; + PEG_PORT *PegPort; + + Status = EFI_SUCCESS; + + /// + /// Initialize Margins to -1. Since -1 is an invalid value, we know that lane wasn't tested if its margin == -1 + /// + for (Lane = 0; Lane < SA_PEG_MAX_LANE; Lane++) { + Margins[Lane] = -1; + } + + for (PortListIndex = 0; PortListIndex < PortInfoListLength; PortListIndex++) { + /// + /// Test all lanes associated with this the current port + /// + LaneList = &((PortInfoList[PortListIndex]).LaneList[0]); + LaneListLength = (PortInfoList[PortListIndex]).LaneListLength; + PegPort = &((PortInfoList[PortListIndex]).PegPort); + if ((PortInfoList[PortListIndex]).EnableMargin == FALSE || + (PortInfoList[PortListIndex]).SkipMargin == TRUE) { + continue; + } + + if ((PortInfoList[PortListIndex]).LinkIsGen3Capable) { + OriginalSpeed = 3; + } else { + OriginalSpeed = GetLinkSpeed (PegPort); + } + OriginalWidth = GetNegotiatedWidth (PegPort); + + switch (MarginTest) { + case LaneLevelRxJitter: + Status = LaneLevelJitterTest ( + PeiServices, + SaPlatformPolicyPpi, + SaDataHob, + StallPpi, + MonitorPort, + LaneList, + LaneListLength, + PegPort, + OriginalSpeed, + OriginalWidth, + FALSE, + Margins + ); + break; + default: + DEBUG ((EFI_D_WARN, "Invalid Margin Test Requested.\n")); + break; + } + } + + return Status; +} + +EFI_STATUS +LaneLevelJitterTest ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN SA_DATA_HOB *SaDataHob, + IN PEI_STALL_PPI *StallPpi, + IN UINT32 MonitorPort, + IN UINT8 *LaneList, + IN UINT8 LaneListLength, + IN PEG_PORT *PegPort, + IN UINT8 OriginalLinkSpeed, + IN UINT8 OriginalLinkWidth, + IN BOOLEAN TxJitterTest, + OUT INT32 *Margins + ) +{ + EFI_STATUS Status; + UINT8 LaneListIndex; + INT8 Jitter; + UINT32 Errors; + UINT32 PreviousErrors; + UINT8 Lane; + UINT32 RecoveryCount; + BOOLEAN AbortMargin; + UINT16 ErrorTarget; + UINT8 ConvergenceCounter; + INT32 LastMargin; + INT32 MarginDifference; + INT32 StartJitter; + INT8 MarginDirection; + UINT8 RepeatCount; + + ErrorTarget = GetErrorTarget (SaPlatformPolicyPpi); + + for (LaneListIndex = 0; LaneListIndex < LaneListLength; LaneListIndex++) { + Lane = LaneList[LaneListIndex]; + Errors = 0; + AbortMargin = FALSE; + Margins[Lane] = 0; + MarginDirection = 1; + + if (TxJitterTest) { + ConfigureTxJitterMux (Lane, SaPlatformPolicyPpi->PlatformData->MchBar); + EnableTxJitterInjection (Lane, TRUE); + } + + /// + /// Determine value to start at + /// + if (LaneListIndex == 0) { + StartJitter = 0; + } else { + StartJitter = (Margins[LaneList[LaneListIndex - 1]] / 100) - JITTER_MARGIN_INITIAL_OFFSET; + if (StartJitter < 0) { + StartJitter = 0; + } + } + + ConvergenceCounter = 0; + LastMargin = -1; + RepeatCount = 0; + while (ConvergenceCounter < MARGIN_CONVERGANCE_MIN_MATCHES && RepeatCount < MARGIN_CONVERGANCE_MAX_REPEATS) { + RepeatCount++; + /// + /// Determine whether to go up or down from starting point + /// + AbortMargin = FALSE; + RecoveryCount = SaPcieGetErrorCount (MonitorPort, PegPort->Function); + Status = SetJitterTolerance (&Lane, 1, (UINT8) StartJitter); + ASSERT_EFI_ERROR (Status); + + Errors = SaPciePointTest (PeiServices, SaPlatformPolicyPpi, StallPpi, MonitorPort, PegPort, RecoveryCount); + if (Errors >= ErrorTarget) { + if (StartJitter == 0) { + Margins[Lane] = 0; + AbortMargin = TRUE; + } else { + MarginDirection = -1; + } + } else { + MarginDirection = 1; + } + for (Jitter = (INT8) (StartJitter + MarginDirection); + Jitter < JITTER_LENGTH && + Jitter >= 0 && + (!AbortMargin); + Jitter = (INT8) (Jitter + MarginDirection)) { + /// + /// Check for a link downgrade + /// + AbortMargin = LinkIsDowngraded (PegPort, OriginalLinkSpeed, OriginalLinkWidth); + if (AbortMargin) { + if (MarginDirection < 0) { + LastMargin = -1; + ConvergenceCounter = 0; + StartJitter = 0; + MarginDirection = 1; + } else { + if (Jitter == 0) { + Margins[Lane] = 0; + } else { + Margins[Lane] = (Jitter - 1) * 100; + } + } + break; + } + + /// + /// Get initial recovery count + /// + RecoveryCount = SaPcieGetErrorCount (MonitorPort, PegPort->Function); + Status = SetJitterTolerance (&Lane, 1, Jitter); + ASSERT_EFI_ERROR (Status); + + PreviousErrors = Errors; + Errors = SaPciePointTest (PeiServices, SaPlatformPolicyPpi, StallPpi, MonitorPort, PegPort, RecoveryCount); + if (MarginDirection < 0) { + if (Errors < ErrorTarget) { ///< Downward direction has started passing + Margins[Lane] = InterpolateMargin (ErrorTarget, PreviousErrors, Errors, (INT32) Jitter); + break; + } + } else { + if (Errors >= ErrorTarget) { ///< Upward direction has started failing + Margins[Lane] = InterpolateMargin (ErrorTarget, Errors, PreviousErrors, (INT32) Jitter); + break; + } + } + } ///< End of for loop + + /// + /// Check if we never reached the error target + /// + if (MarginDirection < 0) { + if ((Errors >= ErrorTarget) && (!AbortMargin)) { + Margins[Lane] = 0; + } + } else { + if ((Errors < ErrorTarget) && (!AbortMargin)) { + Margins[Lane] = JITTER_LENGTH * 100; + } + } + + /// + /// Compute the next margin point to start at + /// + StartJitter = (Margins[Lane] / 100) - JITTER_MARGIN_INITIAL_OFFSET; + if (StartJitter < 0) { + StartJitter = 0; + } + + /// + /// Check for convergance + /// + if (LastMargin == -1) { + LastMargin = Margins[Lane]; + } else { + MarginDifference = CalculateMarginDifference (LastMargin, Margins[Lane]); + if (MarginDifference <= MARGIN_CONVERGANCE_ALLOWED_DELTA) { + ConvergenceCounter++; + } else { + ConvergenceCounter = 0; + } + LastMargin = Margins[Lane]; + } + + if (LinkIsDowngraded (PegPort, OriginalLinkSpeed, OriginalLinkWidth)) { + Status = SetJitterTolerance (&Lane, 1, 0); + ASSERT_EFI_ERROR (Status); + } + + /// + /// If the link degraded in any way, bring it back to functional state + /// + Status = EnsureLinkIsHealthy (PeiServices, SaPlatformPolicyPpi, SaDataHob, StallPpi, PegPort, OriginalLinkSpeed, OriginalLinkWidth); + if (EFI_ERROR (Status)) { + return Status; + } + } ///< End of repeat while loop + + /// + /// Remove Jitter in preparation for testing the next lane + /// + Status = SetJitterTolerance (&Lane, 1, 0); + ASSERT_EFI_ERROR (Status); + if (TxJitterTest) { + EnableTxJitterInjection (Lane, FALSE); + } + } ///< End of for each lane loop + + return EFI_SUCCESS; +} + +UINT32 +SaPciePointTest ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN PEI_STALL_PPI *StallPpi, + IN UINT32 MonitorPort, + IN PEG_PORT *PegPort, + IN UINT32 InitialRecoveryCount + ) +{ + UINT32 Data32; + + StallPpi->Stall (PeiServices, StallPpi, SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearchDwellTime); + Data32 = SaPcieGetErrorCount (MonitorPort, PegPort->Function) - InitialRecoveryCount; + + return Data32; +} + +INT32 +CalculateMarginDifference ( + IN INT32 Margin1, + IN INT32 Margin2 + ) +{ + if (Margin1 < Margin2) { + return Margin2 - Margin1; + } else { + return Margin1 - Margin2; + } +} + +INT32 +InterpolateMargin ( + IN UINT32 ErrorTarget, + IN UINT32 CurrentErrorCount, + IN UINT32 PreviousErrorCount, + IN INT32 FailingPoint + ) +{ + UINT32 LnErrorTarget; + UINT32 LnCurrentErrorCount; + UINT32 LnPreviousErrorCount; + INT32 Margin; + + if (ErrorTarget > 40000) { + ErrorTarget = 40000; + } + if (CurrentErrorCount > 40000) { + CurrentErrorCount = 40000; + } + if (PreviousErrorCount > 40000) { + PreviousErrorCount = 40000; + } + + LnErrorTarget = NaturalLog (ErrorTarget * 100); + LnCurrentErrorCount = NaturalLog (CurrentErrorCount * 100); + LnPreviousErrorCount = NaturalLog (PreviousErrorCount * 100); + + if (FailingPoint >= 0) { + if ((LnCurrentErrorCount - LnPreviousErrorCount) == 0) { + Margin = (FailingPoint - 1) * 100; + } else { + Margin = ((LnErrorTarget - LnPreviousErrorCount) * 100) / + (LnCurrentErrorCount - LnPreviousErrorCount) + + ((FailingPoint - 1) * 100); + } + if (Margin < 0) { + Margin = 0; + } + } else { + if ((LnCurrentErrorCount - LnPreviousErrorCount) == 0) { + Margin = (FailingPoint + 1) * 100; + } else { + Margin = ((FailingPoint + 1) * 100) - + ((LnErrorTarget - LnPreviousErrorCount) * 100) / + (LnCurrentErrorCount - LnPreviousErrorCount); + } + if (Margin > 0) { + Margin = 0; + } + } + + return Margin; +} + + +UINT32 +NaturalLog ( + IN UINT32 Input + ) + /*++ + + Routine Description: + + This function calculates the Natural Log of the Input parameter using integers + + Arguments: + + Input - 100 times a number to get the Natural log from. + - Max Input Number is 40,000 (without 100x) + + Returns: + + Output - 100 times the actual result. Accurate within +/- 2 + + --*/ +{ + UINT32 Output; + + /// + ///Special case - treat 0 recoveries as 1 recovery for interpolation purposes + /// + if (Input == 0) { + return 0; + } + + Output = 0; + while (Input > 271) { + Input = (Input * 1000) / 2718; + Output += 100; + } + + Output += ((-16 * Input * Input + 11578 * Input - 978860) / 10000); + + return Output; +} + +#endif // PEG_FLAG diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTraining.h b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTraining.h new file mode 100644 index 0000000..5c7ee57 --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTraining.h @@ -0,0 +1,425 @@ +/** @file + Header file for PcieTraining Initialization Driver. + +@copyright + Copyright (c) 2012 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 +**/ + +#ifndef _PCIETRAINING_H_ +#define _PCIETRAINING_H_ + +#include "EdkIIGluePeim.h" +#include "SaAccess.h" +#include "PciExpressInit.h" + +#include EFI_PPI_DEPENDENCY (SaPlatformPolicy) +#include EFI_GUID_DEFINITION (SaDataHob) + +/// +/// Data structures +/// + +typedef struct { + PEG_PORT PegPort; + UINT32 EndPointVendorIdDeviceId; + BOOLEAN LinkIsGen3Capable; + UINT8 LaneList[SA_PEG_MAX_LANE]; + UINT8 LaneListLength; + BOOLEAN EnableMargin; + BOOLEAN SkipMargin; + BOOLEAN FoundUsablePreset; +} PORT_INFO; + +typedef struct { + INT8 Depth; + UINT8 Step; + UINT8 ReportedMargin; + UINT8 DoubleMargin; +} JITTER_SETTING; + +typedef struct { + UINT8 Lane; + UINT32 InitialDs0Dac; + UINT32 InitialDs0Value; + INT32 Ds0MarginOffset; + UINT32 InitialDs1Dac; + UINT32 InitialDs1Value; + INT32 Ds1MarginOffset; + INT32 MaxUpMargin; + INT32 MaxDownMargin; +} VOC_STATE; + +typedef enum { + LaneLevelRxJitter, + VocUp, + VocDown +} MARGIN_TEST_TYPE; + +#define JITTER_LENGTH 25 +#define JITTER_MARGIN_INITIAL_OFFSET 1 +#define MARGIN_CONVERGANCE_ALLOWED_DELTA 100 +#define MARGIN_CONVERGANCE_MIN_MATCHES 2 +#define MARGIN_CONVERGANCE_MAX_REPEATS 30 + +#define SA_PEI_MONITOR_OFFSET 0xFED85000 + +/// +/// Register Definitions +/// +#define B_SA_PEG_LTSSMC_WIDTH_MASK 0xFFFFFFE0 + +#define R_SA_PEG_REUT_PH_CTR_OFFSET 0x444 +#define B_SA_PEG_REUT_PH_CTR_PHYRESET_MASK 0x1 +#define B_SA_PEG_REUT_PH_CTR_RESETMOD_MASK 0x2 +#define B_SA_PEG_REUT_PH_CTR_AUTOCOMP_MASK 0x2000 + +#define R_SA_PEG_REUT_PH1_PIS_OFFSET 0x464 +#define B_SA_PEG_REUT_PH1_PIS_ST_MASK 0x3F +#define B_SA_PEG_REUT_PH1_PIS_ST_STEP 0x8 + +#define B_SA_PEG_BCTRL_SRESET_MASK BIT6 + +#define V_SA_VCU_OPCODE_SET_TXJITTER_MUX 0x3002 +#define V_SA_VCU_SEQID_SET_TXJITTER_MUX 0x00030003 + +#define R_SA_VCU_REUT_PH_CTR_ADDRESS_REV1 0x04448808 +#define R_SA_VCU_REUT_PH_CTR_ADDRESS_REV2 0x04448080 + +#define R_SA_VCU_REUT_PH1_PIS_ADDRESS_REV1 0x04648808 +#define R_SA_VCU_REUT_PH1_PIS_ADDRESS_REV2 0x04648080 + +/// +/// Function Prototypes +/// + + + +UINT16 +GetErrorTarget ( + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ); + +VOID GetPortInfo ( + OUT PORT_INFO *PortInfoList, + OUT UINT8 *PortInfoListLength, + OUT BOOLEAN *SkipBundle0 + ); + +EFI_STATUS +RunMarginTest ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN SA_DATA_HOB *SaDataHob, + IN PEI_STALL_PPI *StallPpi, + IN UINT32 MonitorPort, + IN PORT_INFO *PortInfoList, + IN UINT8 PortInfoListLength, + IN MARGIN_TEST_TYPE MarginTest, + OUT INT32 *Margins + ); + +EFI_STATUS +LaneLevelJitterTest ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN SA_DATA_HOB *SaDataHob, + IN PEI_STALL_PPI *StallPpi, + IN UINT32 MonitorPort, + IN UINT8 *LaneList, + IN UINT8 LaneListLength, + IN PEG_PORT *PegPort, + IN UINT8 OriginalLinkSpeed, + IN UINT8 OriginalLinkWidth, + IN BOOLEAN TxJitterTest, + OUT INT32 *Margins + ); + +UINT32 +SaPciePointTest ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN PEI_STALL_PPI *StallPpi, + IN UINT32 MonitorPort, + IN PEG_PORT *PegPort, + IN UINT32 InitialRecoveryCount + ); + +INT32 +CalculateMarginDifference ( + IN INT32 Margin1, + IN INT32 Margin2 + ); + +INT32 +InterpolateMargin ( + IN UINT32 ErrorTarget, + IN UINT32 CurrentErrorCount, + IN UINT32 PreviousErrorCount, + IN INT32 FailingPoint + ); + + +UINT32 +NaturalLog ( + IN UINT32 Input + ); + + +VOID +PegGen3PresetSearch ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN PEI_STALL_PPI *StallPpi, + SA_DATA_HOB *SaDataHob + ); + +BOOLEAN +SaPolicyEnablesGen3 ( + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ); + + +EFI_STATUS +EnsureLinkIsHealthy ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN SA_DATA_HOB *SaDataHob, + IN PEI_STALL_PPI *StallPpi, + IN PEG_PORT *PegPort, + IN UINT8 OriginalLinkSpeed, + IN UINT8 OriginalLinkWidth + ); + +EFI_STATUS +WaitForL0 ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_STALL_PPI *StallPpi, + IN PEG_PORT *PegPort, + IN BOOLEAN UseVcu + ); + +EFI_STATUS +TogglePegSlotReset ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_STALL_PPI *StallPpi, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ); + +EFI_STATUS +AssertPegSlotReset ( + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ); + +EFI_STATUS +DeassertPegSlotReset ( + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ); + +EFI_STATUS +RecoverLinkFailure ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN SA_DATA_HOB *SaDataHob, + IN PEI_STALL_PPI *StallPpi, + IN PEG_PORT *PegPort, + IN UINT8 OriginalLinkSpeed, + IN UINT8 OriginalLinkWidth + ); + +BOOLEAN +LinkIsDowngraded ( + IN PEG_PORT *PegPort, + IN UINT8 OriginalLinkSpeed, + IN UINT8 OriginalLinkWidth + ); + +EFI_STATUS +SecondaryBusReset ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_STALL_PPI *StallPpi, + IN PEG_PORT *PegPort + ); + +EFI_STATUS +ResetPhyLayer ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_STALL_PPI *StallPpi, + IN PEG_PORT *PegPort + ); + +EFI_STATUS +RetrainLink ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_STALL_PPI *StallPpi, + IN PEG_PORT *PegPort + ); + +UINT8 +GetNegotiatedWidth ( + IN PEG_PORT *PegPort + ); + +EFI_STATUS +RecoverLinkWidth ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_STALL_PPI *StallPpi, + IN PEG_PORT *PegPort, + IN UINT8 OriginalLinkWidth + ); + +UINT8 +GetLinkSpeed ( + IN PEG_PORT *PegPort + ); + +EFI_STATUS +RecoverLinkSpeed ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_STALL_PPI *StallPpi, + IN PEG_PORT *PegPort, + IN UINT8 OriginalLinkSpeed + ); + +VOID +PcieTrainingWarmReset ( + IN EFI_PEI_SERVICES **PeiServices + ); + + +EFI_STATUS +SetJitterTolerance ( + IN UINT8 *LaneList, + IN UINT8 LaneListLength, + IN UINT8 ReportedMargin + ); + +EFI_STATUS +SetRawJitterTolerance ( + IN UINT8 *LaneList, + IN UINT8 LaneListLength, + IN UINT8 Step, + IN UINT8 Depth, + IN UINT8 DoubleMargin, + IN BOOLEAN EnableJitter + ); + +VOID +EnableTxJitterInjection ( + IN UINT8 Lane, + IN BOOLEAN EnableTxJitter + ); + +VOID +ConfigureTxJitterMux ( + IN UINT8 Lane, + IN UINT32 MchBar + ); + +EFI_STATUS +GetBundleList ( + IN UINT8 *LaneList, + IN UINT8 LaneListLength, + OUT UINT8 *BundleList, + OUT UINT8 *BundleListLength + ); + + +UINT32 +OpenMonitor ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN PEI_STALL_PPI *StallPpi + ); + +VOID +CloseMonitor ( + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN UINT32 MonitorPort + ); + +UINT32 +SaPcieGetErrorCount ( + IN UINT32 MonitorPort, + IN UINT8 PcieController + ); + +VOID +SaPcieClearErrorCount ( + IN UINT32 MonitorPort, + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_STALL_PPI *StallPpi + ); + +VOID +InitMonitor ( + IN UINT32 MchBar, + IN UINT32 GdxcBar + ); + +VOID +TearDownMonitor ( + IN UINT32 MchBar, + IN UINT32 GdxcBar + ); + +UINT32 +EnableMonitor ( + VOID + ); + +VOID +DisableMonitor ( + VOID + ); + +VOID +FullMonitorReset ( + IN UINT32 MonitorPort + ); + +VOID +ProgramMonitor ( + IN UINT32 MonitorPort, + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_STALL_PPI *StallPpi + ); + + +VOID +GetLinkPartnerFullSwing ( + IN UINT8 Lane, + OUT UINT8 *FullSwing + ); + +VOID +GetCoefficientsFromPreset ( + IN UINT8 Preset, + IN UINT8 FullSwing, + OUT UINT8 *PreCursor, + OUT UINT8 *Cursor, + OUT UINT8 *PostCursor + ); + +VOID +SetPartnerTxCoefficients ( + IN UINT8 Lane, + IN UINT8 *PreCursor, + IN UINT8 *Cursor, + IN UINT8 *PostCursor + ); + +#endif diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingEqSettings.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingEqSettings.c new file mode 100644 index 0000000..dc4515e --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingEqSettings.c @@ -0,0 +1,166 @@ +/*++ @file + This file adds equalization setting support. + +@copyright + Copyright (c) 2012 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 "PcieTraining.h" +#include "PciExpressInit.h" + +#ifdef PEG_FLAG + +VOID +GetLinkPartnerFullSwing ( + IN UINT8 Lane, + OUT UINT8 *FullSwing + ) +{ + UINT32 Data32; + + Data32 = BIT25 | BIT23 | (Lane << 19) | BIT18; + McD1PciCfg32(R_SA_PEG_EQPH3_OFFSET) = Data32; + Data32 = McD1PciCfg32(R_SA_PEG_EQPH3_OFFSET); + McD1PciCfg32(R_SA_PEG_EQPH3_OFFSET) = 0; + + *FullSwing = (Data32 >> 6) & 0x3F; + + return; +} + +VOID +GetCoefficientsFromPreset ( + IN UINT8 Preset, + IN UINT8 FullSwing, + OUT UINT8 *PreCursor, + OUT UINT8 *Cursor, + OUT UINT8 *PostCursor + ) +{ + INT32 PreCursorMilli; + INT32 PostCursorMilli; + + PreCursorMilli = 0; + PostCursorMilli = 0; + + /// + /// Get starting values from Table 4-16 of the PCIe Base Spec v3.0 + /// + switch (Preset) { + case 0: + PreCursorMilli = 0; + PostCursorMilli = -250; + break; + + case 1: + PreCursorMilli = 0; + PostCursorMilli = -167; + break; + + case 2: + PreCursorMilli = 0; + PostCursorMilli = -200; + break; + + case 3: + PreCursorMilli = 0; + PostCursorMilli = -125; + break; + + case 4: + PreCursorMilli = 0; + PostCursorMilli = 0; + break; + + case 5: + PreCursorMilli = -100; + PostCursorMilli = 0; + break; + + case 6: + PreCursorMilli = -125; + PostCursorMilli = 0; + break; + + case 7: + PreCursorMilli = -100; + PostCursorMilli = -200; + break; + + case 8: + PreCursorMilli = -125; + PostCursorMilli = -125; + break; + + case 9: + PreCursorMilli = -166; + PostCursorMilli = 0; + break; + + case 10: ///< P10 is unsupported + default: + PreCursorMilli = -100; + PostCursorMilli = -200; + DEBUG ((EFI_D_WARN, "GetCoefficientsFromPreset(): Unsupported Preset Requested: P%d. Using P7.\n", Preset)); + break; + } + + /// + /// Convert to absolute values + /// + if (PreCursorMilli < 0) { + PreCursorMilli *= -1; + } + if (PostCursorMilli < 0) { + PostCursorMilli *= -1; + } + + /// + /// Apply FullSwing + /// + PreCursorMilli *= FullSwing; + PostCursorMilli *= FullSwing; + + /// + /// Convert to integers + /// + *PreCursor = (( PreCursorMilli % 1000) >= 500) ? (UINT8) (( PreCursorMilli / 1000) + 1) : (UINT8) ( PreCursorMilli / 1000); + *PostCursor = ((PostCursorMilli % 1000) >= 500) ? (UINT8) ((PostCursorMilli / 1000) + 1) : (UINT8) (PostCursorMilli / 1000); + *Cursor = FullSwing - (*PreCursor) - (*PostCursor); + + return; +} + +VOID +SetPartnerTxCoefficients ( + IN UINT8 Lane, + IN UINT8 *PreCursor, + IN UINT8 *Cursor, + IN UINT8 *PostCursor + ) +{ + UINT32 Data32; + + Data32 = (Lane << 19) | BIT18 | (*Cursor << 12) | (*PreCursor << 6) | (*PostCursor); + McD1PciCfg32(R_SA_PEG_EQPH3_OFFSET) = Data32; + McD1PciCfg32(R_SA_PEG_EQPH3_OFFSET) = 0; + + return; +} + +#endif // PEG_FLAG diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingErrorCount.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingErrorCount.c new file mode 100644 index 0000000..d1fb107 --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingErrorCount.c @@ -0,0 +1,195 @@ +/** @file + Error Counting for PEG training. + +@copyright + Copyright (c) 2012 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 "PcieTraining.h" + +#ifdef PEG_FLAG + +UINT32 +OpenMonitor ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN PEI_STALL_PPI *StallPpi + ) +{ + UINT32 MonitorPort; + + InitMonitor (SaPlatformPolicyPpi->PlatformData->MchBar, SaPlatformPolicyPpi->PlatformData->GdxcBar); + MonitorPort = EnableMonitor (); + FullMonitorReset (MonitorPort); + ProgramMonitor (MonitorPort, PeiServices, StallPpi); + + return MonitorPort; +} + +VOID +CloseMonitor ( + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN UINT32 MonitorPort + ) +{ + FullMonitorReset (MonitorPort); + DisableMonitor (); + TearDownMonitor (SaPlatformPolicyPpi->PlatformData->MchBar, SaPlatformPolicyPpi->PlatformData->GdxcBar); + + return; +} + +UINT32 +SaPcieGetErrorCount ( + IN UINT32 MonitorPort, + IN UINT8 PcieController + ) +{ + UINT32 Data32; + + Data32 = Mmio32 (MonitorPort, (0xC + (PcieController * 0x10))); + + return Data32; +} + +VOID +SaPcieClearErrorCount ( + IN UINT32 MonitorPort, + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_STALL_PPI *StallPpi + ) +{ + FullMonitorReset (MonitorPort); + ProgramMonitor (MonitorPort, PeiServices, StallPpi); + + return; +} + +VOID +InitMonitor ( + IN UINT32 MchBar, + IN UINT32 GdxcBar + ) +{ + Mmio32 (MchBar, 0x6430) = 0x3; + Mmio32 (MchBar, 0x6434) = 0x76543210; + McD1PciCfg32 (0x630) = 0xB; + McD1PciCfg32 (0x600) = 0x60B; + McD1PciCfg32 (0x604) = 0x76543980; + McD1F1PciCfg32 (0x600) = 0x60B; + McD1F1PciCfg32 (0x604) = 0x76543280; + McD1F2PciCfg32 (0x600) = 0xB; + McD1F2PciCfg32 (0x604) = 0x76543210; + Mmio32 (MchBar, 0x6438) = 0x680000; + Mmio32 (GdxcBar, 0xA04) = 0xA; + + return; +} + +VOID +TearDownMonitor ( + IN UINT32 MchBar, + IN UINT32 GdxcBar + ) +{ + Mmio32 (MchBar, 0x6430) = 0x0; + Mmio32 (MchBar, 0x6434) = 0x0; + McD1PciCfg32 (0x630) = 0x0; + McD1PciCfg32 (0x600) = 0x0; + McD1PciCfg32 (0x604) = 0x0; + McD1F1PciCfg32 (0x600) = 0x0; + McD1F1PciCfg32 (0x604) = 0x0; + McD1F2PciCfg32 (0x600) = 0x0; + McD1F2PciCfg32 (0x604) = 0x0; + Mmio32 (MchBar, 0x6438) = 0x0; + Mmio32 (GdxcBar, 0xA04) = 0x0; + + return; +} + +UINT32 +EnableMonitor ( + VOID + ) +{ + UINT32 Data32; + + Data32 = (McD0PciCfg32 (0140) & ~(07)); + Mmio32Or (Data32, 0124, 040000); + Mmio64 (Data32, 0700020) = (UINT64) SA_PEI_MONITOR_OFFSET; + Mmio16Or (Data32, 0700004, 02); + + return SA_PEI_MONITOR_OFFSET; +} + +VOID +DisableMonitor ( + VOID + ) +{ + UINT32 Data32; + + Data32 = (McD0PciCfg32 (0140) & ~(07)); + Mmio16And (Data32, 0700004, 0177775); + Mmio64And (Data32, 0700020, 07777); + Mmio32And (Data32, 0124, 037777737777); + + return; +} + +VOID +FullMonitorReset ( + IN UINT32 MonitorPort + ) +{ + Mmio32 (MonitorPort, 0x0) = 0x40000; + Mmio32 (MonitorPort, 0x4) = 0x0; + Mmio32 (MonitorPort, 0x10) = 0x40000; + Mmio32 (MonitorPort, 0x14) = 0x0; + Mmio32 (MonitorPort, 0x20) = 0x40000; + Mmio32 (MonitorPort, 0x24) = 0x0; + Mmio32 (MonitorPort, 0x8) = 0xFF000000; + Mmio32 (MonitorPort, 0x18) = 0xFF000000; + Mmio32 (MonitorPort, 0x28) = 0xFF000000; + Mmio32 (MonitorPort, 0xC) = 0x0; + Mmio32 (MonitorPort, 0x1C) = 0x0; + Mmio32 (MonitorPort, 0x2C) = 0x0; + + return; +} + +VOID +ProgramMonitor ( + IN UINT32 MonitorPort, + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_STALL_PPI *StallPpi + ) +{ + Mmio32 (MonitorPort, 0x4) = 0xA100; + Mmio32 (MonitorPort, 0x14) = 0xA101; + Mmio32 (MonitorPort, 0x24) = 0xA102; + Mmio32 (MonitorPort, 0x0) = 0x110000; + StallPpi->Stall (PeiServices, StallPpi, 1 * STALL_ONE_MILLI_SECOND); + + Mmio32 (MonitorPort, 0x0) = 0x22100; + Mmio32 (MonitorPort, 0x10) = 0x22101; + Mmio32 (MonitorPort, 0x20) = 0x22102; + + return; +} + +#endif // PEG_FLAG diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingLinkRecovery.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingLinkRecovery.c new file mode 100644 index 0000000..1480bc7 --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingLinkRecovery.c @@ -0,0 +1,721 @@ +/*++ @file + This driver recovers the PEG link. + +@copyright + Copyright (c) 2012 - 2014 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 "PcieTraining.h" +#include "PciExpressInit.h" +#include EFI_PPI_CONSUMER (PchReset) + +#ifdef PEG_FLAG + +EFI_STATUS +EnsureLinkIsHealthy ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN SA_DATA_HOB *SaDataHob, + IN PEI_STALL_PPI *StallPpi, + IN PEG_PORT *PegPort, + IN UINT8 OriginalLinkSpeed, + IN UINT8 OriginalLinkWidth + ) +{ + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + /// + /// Check Link Status and Recover the Link if needed + /// + Status = RecoverLinkWidth (PeiServices, StallPpi, PegPort, OriginalLinkWidth); + if (EFI_ERROR (Status)) { + Status = RecoverLinkFailure (PeiServices, SaPlatformPolicyPpi, SaDataHob, StallPpi, PegPort, OriginalLinkSpeed, OriginalLinkWidth); + if (EFI_ERROR (Status)) { + return Status; + } + } + Status = RecoverLinkSpeed (PeiServices, StallPpi, PegPort, OriginalLinkSpeed); + if (EFI_ERROR (Status)) { + Status = RecoverLinkFailure (PeiServices, SaPlatformPolicyPpi, SaDataHob, StallPpi, PegPort, OriginalLinkSpeed, OriginalLinkWidth); + if (EFI_ERROR (Status)) { + return Status; + } + } + Status = WaitForL0 (PeiServices, StallPpi, PegPort, FALSE); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, "DOWNGRADE, Link is not in L0\n")); + Status = RetrainLink (PeiServices, StallPpi, PegPort); + if (EFI_ERROR (Status)) { + Status = RecoverLinkFailure (PeiServices, SaPlatformPolicyPpi, SaDataHob, StallPpi, PegPort, OriginalLinkSpeed, OriginalLinkWidth); + if (EFI_ERROR (Status)) { + return Status; + } + } + } + + return Status; +} + +/** + Wait until link is up. + + @param[in] PeiServices - Pointer to the PEI services table + @param[in] StallPpi - Pointer to PEI_STALL_PPI + @param[in] PegPort - Pointer PEG Port + @param[in] UseVcu - If TRUE, use VCU to determine link state. If FALSE, use MMIO CFG to determine link state. + + @retval EFI_SUCCESS - Completed successfully before timeout + @retval EFI_TIMEOUT - Timed out +**/ +EFI_STATUS +WaitForL0 ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_STALL_PPI *StallPpi, + IN PEG_PORT *PegPort, + IN BOOLEAN UseVcu + ) +{ + UINT32 MchBar; + UINT32 i; + EFI_STATUS Status; + UINT32 VcuAddress; + UINT8 VcuReadOp; + UINT8 VcuWriteOp; + CPU_FAMILY CpuFamilyId; + CPU_STEPPING CpuSteppingId; + BOOLEAN CheckEq; + BOOLEAN CompletedEq; + UINT32 EqStatus; + UINT32 LinkStatus; + + Status = EFI_TIMEOUT; + CheckEq = (PegPort->EndpointMaxLinkSpeed >= 0x3) ? TRUE : FALSE; + CompletedEq = FALSE; + i = 0; + MchBar = McD0PciCfg64 (R_SA_MCHBAR) & ~BIT0; + CpuFamilyId = GetCpuFamily(); + CpuSteppingId = GetCpuStepping(); + +#ifndef AMI_OVERRIDE_FOR_ULT_FASTBOOT + if (CpuFamilyId == EnumCpuHswUlt) return EFI_UNSUPPORTED; +#endif // AMI_OVERRIDE_FOR_ULT_FASTBOOT + + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + VcuAddress = R_SA_VCU_REUT_PH1_PIS_ADDRESS_REV1; + VcuReadOp = V_SA_VCU_OPCODE_READ_CSR_REV1; + VcuWriteOp = V_SA_VCU_OPCODE_WRITE_CSR_REV1; + } else { + VcuAddress = R_SA_VCU_REUT_PH1_PIS_ADDRESS_REV2; + VcuReadOp = V_SA_VCU_OPCODE_READ_CSR_REV2; + VcuWriteOp = V_SA_VCU_OPCODE_WRITE_CSR_REV2; + } + + /// + /// If endpoint's LCAP.MLS (Spec section 7.8.6) indicated Gen3 capability, first wait for equalization to complete. + /// Check equalization status LSTS2.EC (Spec section 7.8.20) until Gen3 equalization successfully completed. + /// + if (CheckEq && !UseVcu) { + for (; i < 100; i++) { + EqStatus = MmPci16 (0, PegPort->Bus, PegPort->Device, PegPort->Function, R_SA_PEG_LSTS2_OFFSET); + EqStatus = (EqStatus >> 1) & 0x1; + if (EqStatus == 0x1) { + CompletedEq = TRUE; + break; + } + StallPpi->Stall (PeiServices, StallPpi, STALL_ONE_MILLI_SECOND); + } + } + + /// + /// Check for L0 status. If !UseVcu, check PEGSTS. + /// Continue up to 100 msec of combined delay. + /// Skip if equalization was needed but didn't successfully complete. + /// + if ((CheckEq && CompletedEq) || !CheckEq || UseVcu) { + for (; i < 100; i++) { + if (UseVcu) { + LinkStatus = SendVcuApiSequence (MchBar, VcuAddress, VcuReadOp, 0); + LinkStatus = (LinkStatus >> (PegPort->Function * B_SA_PEG_REUT_PH1_PIS_ST_STEP)) & B_SA_PEG_REUT_PH1_PIS_ST_MASK; + if (LinkStatus == 0x10) { + Status = EFI_SUCCESS; + break; + } + } else { + LinkStatus = MmPci32 (0, PegPort->Bus, PegPort->Device, PegPort->Function, R_SA_PEG_PEGSTS_OFFSET); + LinkStatus = (LinkStatus >> 16) & 0xF; + if (LinkStatus == 0x7) { + Status = EFI_SUCCESS; + break; + } + } + StallPpi->Stall (PeiServices, StallPpi, STALL_ONE_MILLI_SECOND); + } + } + + return Status; +} + +EFI_STATUS +SetPchGpio ( + IN UINT8 GpioNumber, + IN UINT8 Level + ) +/** + This function sets a GPIO to a particular level. + + @param[in] GpioNumber - PCH GPIO number + @param[in] Level - 0 = Low, 1 = High + + @retval EFI_SUCCESS - Did toggle GPIO + @retval EFI_UNSUPPORTED - Didn't toggle GPIO + @retval EFI_INVALID_PARAMETER - Didn't toggle GPIO +**/ +{ + UINT32 Data32; + UINT16 LpcDeviceId; + UINT16 GpioBase; + UINT16 UseSelOffset; + UINT16 IoSelOffset; + UINT16 LvlOffset; + UINT8 GpioBit; + EFI_STATUS Status; + + Level &= 0x1; + Status = EFI_SUCCESS; + GpioBase = 0; + UseSelOffset = 0; + IoSelOffset = 0; + LvlOffset = 0; + GpioBit = 0; + + LpcDeviceId = McDevFunPciCfg16 ( + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_LPC, + PCI_FUNCTION_NUMBER_PCH_LPC, + R_PCH_LPC_DEVICE_ID + ); + if (!IS_PCH_LPT_LPC_DEVICE_ID (LpcDeviceId)) { + Status = EFI_UNSUPPORTED; + return Status; + } + + GpioBase = McDevFunPciCfg16 ( + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_LPC, + PCI_FUNCTION_NUMBER_PCH_LPC, + R_PCH_LPC_GPIO_BASE + ) & B_PCH_LPC_GPIO_BASE_BAR; + if (GpioBase == 0) { + Status = EFI_UNSUPPORTED; + return Status; + } + + if (GpioNumber < 0x20) { + UseSelOffset = R_PCH_GPIO_USE_SEL; + IoSelOffset = R_PCH_GPIO_IO_SEL; + LvlOffset = R_PCH_GPIO_LVL; + GpioBit = GpioNumber; + } else if (GpioNumber < 0x40) { + UseSelOffset = R_PCH_GPIO_USE_SEL2; + IoSelOffset = R_PCH_GPIO_IO_SEL2; + LvlOffset = R_PCH_GPIO_LVL2; + GpioBit = GpioNumber - 0x20; + } else if (GpioNumber < 0x60) { + UseSelOffset = R_PCH_GPIO_USE_SEL3; + IoSelOffset = R_PCH_GPIO_IO_SEL3; + LvlOffset = R_PCH_GPIO_LVL3; + GpioBit = GpioNumber - 0x40; + } else { + Status = EFI_INVALID_PARAMETER; + return Status; + } + + if (!EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, "Setting GPIO%d to %x\n", GpioNumber, Level)); + IoOr32 ((UINTN) (GpioBase + UseSelOffset), (UINT32) (1 << GpioBit)); + IoAnd32 ((UINTN) (GpioBase + IoSelOffset), (UINT32) ~(1 << GpioBit)); + Data32 = IoRead32 ((UINTN) (GpioBase + LvlOffset)); + Data32 &= (UINT32) ~(1 << GpioBit); + Data32 |= (UINT32) (Level << GpioBit); + IoWrite32 ((UINTN) (GpioBase + LvlOffset), Data32); + } + + return Status; +} + +EFI_STATUS +TogglePegSlotReset ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_STALL_PPI *StallPpi, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +/** + This function asserts and deasserts a GPIO that controls PERST#. + The specific GPIO and its active level is provided by a policy. + The GPIO minimum assertion time, T_PERST (100 usec), is defined in the PCIe CEM Specification. + + @param[in] PeiServices - Pointer to the PEI services table + @param[in] StallPpi - Pointer to PEI_STALL_PPI + @param[in] SaPlatformPolicyPpi - Pointer to SA_PLATFORM_POLICY_PPI + + @retval EFI_SUCCESS - Did toggle GPIO + @retval EFI_UNSUPPORTED - Didn't toggle GPIO + @retval EFI_INVALID_PARAMETER - Didn't toggle GPIO +**/ +{ + EFI_STATUS Status; + UINT8 i; + + DEBUG ((EFI_D_INFO, "Toggling PEG slot reset.\n")); + for (i = 0; i < SA_PEG_MAX_FUN; i++) { + MmPci16Or (0, SA_PEG_BUS_NUM, SA_PEG_DEV_NUM, i, R_SA_PEG_LCTL_OFFSET, BIT4); + } + Status = AssertPegSlotReset (SaPlatformPolicyPpi); + if (!EFI_ERROR (Status)) { + StallPpi->Stall (PeiServices, StallPpi, 100 * STALL_ONE_MICRO_SECOND); + for (i = 0; i < SA_PEG_MAX_FUN; i++) { + MmPci16And (0, SA_PEG_BUS_NUM, SA_PEG_DEV_NUM, i, R_SA_PEG_LCTL_OFFSET, (UINT16) ~(BIT4)); + } + Status = DeassertPegSlotReset (SaPlatformPolicyPpi); + } else { + for (i = 0; i < SA_PEG_MAX_FUN; i++) { + MmPci16And (0, SA_PEG_BUS_NUM, SA_PEG_DEV_NUM, i, R_SA_PEG_LCTL_OFFSET, (UINT16) ~(BIT4)); + } + } + + return Status; +} + +EFI_STATUS +AssertPegSlotReset ( + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +/** + This function asserts a GPIO that controls PERST#. + The specific GPIO and its active level is provided by a policy. + The GPIO minimum assertion time, T_PERST (100 usec), is defined in the PCIe CEM Specification. + + @param[in] SaPlatformPolicyPpi - Pointer to SA_PLATFORM_POLICY_PPI + + @retval EFI_SUCCESS - Did assert GPIO + @retval EFI_UNSUPPORTED - Didn't assert GPIO + @retval EFI_INVALID_PARAMETER - Didn't assert GPIO +**/ +{ + EFI_STATUS Status; + UINT8 GpioNumber; + UINT8 AssertLevel; + + Status = EFI_SUCCESS; + + DEBUG ((EFI_D_INFO, "Asserting PEG slot reset.\n")); + + if (!((SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_3) && + (SaPlatformPolicyPpi->PcieConfig->PegGpioData->GpioSupport == TRUE))) { + Status = EFI_UNSUPPORTED; + } + + if (!EFI_ERROR (Status)) { + GpioNumber = (UINT8) (SaPlatformPolicyPpi->PcieConfig->PegGpioData->SaPegReset->Value); + AssertLevel = (UINT8) (SaPlatformPolicyPpi->PcieConfig->PegGpioData->SaPegReset->Active & 0x1); + Status = SetPchGpio (GpioNumber, AssertLevel); + } + + return Status; +} + +EFI_STATUS +DeassertPegSlotReset ( + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +/** + This function deasserts a GPIO that controls PERST#. + The specific GPIO and its active level is provided by a policy. + The GPIO minimum assertion time, T_PERST (100 usec), is defined in the PCIe CEM Specification. + + @param[in] SaPlatformPolicyPpi - Pointer to SA_PLATFORM_POLICY_PPI + + @retval EFI_SUCCESS - Did deassert GPIO + @retval EFI_UNSUPPORTED - Didn't deassert GPIO + @retval EFI_INVALID_PARAMETER - Didn't deassert GPIO +**/ +{ + EFI_STATUS Status; + UINT8 GpioNumber; + UINT8 DeassertLevel; + + Status = EFI_SUCCESS; + + DEBUG ((EFI_D_INFO, "Deasserting PEG slot reset.\n")); + + if (!((SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_3) && + (SaPlatformPolicyPpi->PcieConfig->PegGpioData->GpioSupport == TRUE))) { + Status = EFI_UNSUPPORTED; + } + + if (!EFI_ERROR (Status)) { + GpioNumber = (UINT8) (SaPlatformPolicyPpi->PcieConfig->PegGpioData->SaPegReset->Value); + DeassertLevel = (UINT8) ((SaPlatformPolicyPpi->PcieConfig->PegGpioData->SaPegReset->Active & 0x1) ^ 0x1); + SetPchGpio (GpioNumber, DeassertLevel); + } + + return Status; +} + +EFI_STATUS +RecoverLinkFailure ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN SA_DATA_HOB *SaDataHob, + IN PEI_STALL_PPI *StallPpi, + IN PEG_PORT *PegPort, + IN UINT8 OriginalLinkSpeed, + IN UINT8 OriginalLinkWidth + ) +{ + EFI_STATUS Status; + UINT8 CurrentLinkWidth; + UINT8 CurrentLinkSpeed; + UINT8 PegBus; + UINT8 PegDev; + UINT8 PegFunc; + + /// + /// A platform reset should be done after presets are saved in NVRAM + /// + if (SaDataHob != NULL) { + if ((SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_2) && + (SaPlatformPolicyPpi->PcieConfig->PegGen3ForcePresetSearch == 0)) { + SaDataHob->PegPlatformResetRequired = TRUE; + } else if (SaPlatformPolicyPpi->Revision < SA_PLATFORM_POLICY_PPI_REVISION_2) { + SaDataHob->PegPlatformResetRequired = TRUE; + } + } + + /// + /// Bypass phase2 and assert slot reset + /// + McD1PciCfg32Or (R_SA_PEG_EQCFG_OFFSET, BIT15); + Status = TogglePegSlotReset (PeiServices, StallPpi, SaPlatformPolicyPpi); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, "Error 0x%x.\n", Status)); + } else { + DEBUG ((EFI_D_INFO, "Success.\n")); + } + PegBus = PegPort->Bus; + PegDev = PegPort->Device; + PegFunc = PegPort->Function; + /// + /// Wait for Equalization Done + /// + while (((MmPci32 (0, PegBus, PegDev, PegFunc, R_SA_PEG_LSTS2_OFFSET) >> 1) & 0x1) != 0x1); + /// + /// Wait for flow control credits exchange + /// + WaitForVc0Negotiation (PeiServices, StallPpi, PegBus, PegDev, PegFunc); + + CurrentLinkWidth = GetNegotiatedWidth (PegPort); + if (CurrentLinkWidth < OriginalLinkWidth) { + DEBUG ((EFI_D_ERROR, "Link Width DOWNGRADED!\n")); + Status = EFI_TIMEOUT; + } + CurrentLinkSpeed = GetLinkSpeed (PegPort); + if (CurrentLinkSpeed < OriginalLinkSpeed) { + DEBUG ((EFI_D_ERROR, "Link Speed DOWNGRADED!\n")); + Status = EFI_TIMEOUT; + } + + return Status; +} + +BOOLEAN +LinkIsDowngraded ( + IN PEG_PORT *PegPort, + IN UINT8 OriginalLinkSpeed, + IN UINT8 OriginalLinkWidth + ) +{ + BOOLEAN IsDowngraded; + + IsDowngraded = FALSE; + + if (OriginalLinkSpeed != GetLinkSpeed (PegPort)) { + DEBUG ((EFI_D_INFO, "Link speed downgrade detected\n")); + IsDowngraded = TRUE; + } + if (OriginalLinkWidth != GetNegotiatedWidth (PegPort)) { + DEBUG ((EFI_D_INFO, "Link width downgrade detected\n")); + IsDowngraded = TRUE; + } + return IsDowngraded; +} + +EFI_STATUS +SecondaryBusReset ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_STALL_PPI *StallPpi, + IN PEG_PORT *PegPort + ) +{ + EFI_STATUS Status; + + Status = EFI_SUCCESS; + DEBUG ((EFI_D_INFO, "SECONDARY BUS RESET!\n")); + MmPci16Or (0, PegPort->Bus, PegPort->Device, PegPort->Function, R_SA_PEG_BCTRL_OFFSET, B_SA_PEG_BCTRL_SRESET_MASK); + MmPci16And (0, PegPort->Bus, PegPort->Device, PegPort->Function, R_SA_PEG_BCTRL_OFFSET,~(B_SA_PEG_BCTRL_SRESET_MASK)); + Status = WaitForL0 (PeiServices, StallPpi, PegPort, FALSE); + DEBUG ((EFI_D_INFO, "Reset Complete\n")); + + return Status; +} + +EFI_STATUS +ResetPhyLayer ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_STALL_PPI *StallPpi, + IN PEG_PORT *PegPort + ) +{ + EFI_STATUS Status; + UINT32 MchBar; + UINT32 Data32; + UINT32 VcuAddress; + UINT8 VcuReadOp; + UINT8 VcuWriteOp; + BOOLEAN UseVcu; + CPU_FAMILY CpuFamilyId; + CPU_STEPPING CpuSteppingId; + + UseVcu = TRUE; + Status = EFI_SUCCESS; + MchBar = McD0PciCfg64 (R_SA_MCHBAR) &~BIT0; + CpuFamilyId = GetCpuFamily(); + CpuSteppingId = GetCpuStepping(); + +#ifndef AMI_OVERRIDE_FOR_ULT_FASTBOOT + if (CpuFamilyId == EnumCpuHswUlt) return EFI_UNSUPPORTED; +#endif // AMI_OVERRIDE_FOR_ULT_FASTBOOT + + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + VcuAddress = R_SA_VCU_REUT_PH_CTR_ADDRESS_REV1; + VcuReadOp = V_SA_VCU_OPCODE_READ_CSR_REV1; + VcuWriteOp = V_SA_VCU_OPCODE_WRITE_CSR_REV1; + } else { + VcuAddress = R_SA_VCU_REUT_PH_CTR_ADDRESS_REV2; + VcuReadOp = V_SA_VCU_OPCODE_READ_CSR_REV2; + VcuWriteOp = V_SA_VCU_OPCODE_WRITE_CSR_REV2; + } + + DEBUG ((EFI_D_INFO, "PHY LAYER RESET!\n")); + if (UseVcu) { + Data32 = SendVcuApiSequence (MchBar, VcuAddress, VcuReadOp, 0); + Data32 &= (UINT32) ~(BIT1); + SendVcuApiSequence (MchBar, VcuAddress, VcuWriteOp, Data32); + } else { + McD1PciCfg32And (R_SA_PEG_REUT_PH_CTR_OFFSET, ~(B_SA_PEG_REUT_PH_CTR_RESETMOD_MASK)); + } + + if (UseVcu) { + Data32 = SendVcuApiSequence (MchBar, VcuAddress, VcuReadOp, 0); + Data32 |= (UINT32) BIT0; + SendVcuApiSequence (MchBar, VcuAddress, VcuWriteOp, Data32); + } else { + McD1PciCfg32Or (R_SA_PEG_REUT_PH_CTR_OFFSET, B_SA_PEG_REUT_PH_CTR_PHYRESET_MASK); + } + + if (UseVcu) { + Data32 = SendVcuApiSequence (MchBar, VcuAddress, VcuReadOp, 0); + Data32 |= (UINT32) BIT13; + SendVcuApiSequence (MchBar, VcuAddress, VcuWriteOp, Data32); + } else { + McD1PciCfg32Or (R_SA_PEG_REUT_PH_CTR_OFFSET, B_SA_PEG_REUT_PH_CTR_AUTOCOMP_MASK); + } + + if (UseVcu) { + Data32 = SendVcuApiSequence (MchBar, VcuAddress, VcuReadOp, 0); + Data32 &= (UINT32) ~(BIT0); + SendVcuApiSequence (MchBar, VcuAddress, VcuWriteOp, Data32); + } else { + McD1PciCfg32And (R_SA_PEG_REUT_PH_CTR_OFFSET, ~(B_SA_PEG_REUT_PH_CTR_PHYRESET_MASK)); + } + + Status = WaitForL0 (PeiServices, StallPpi, PegPort, TRUE); + DEBUG ((EFI_D_INFO, "Reset Complete\n")); + + return Status; +} + +EFI_STATUS +RetrainLink ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_STALL_PPI *StallPpi, + IN PEG_PORT *PegPort + ) +{ + EFI_STATUS Status; + + /// + /// Initiate Link Retrain + /// + MmPci16Or (0, PegPort->Bus, PegPort->Device, PegPort->Function, R_SA_PEG_LCTL_OFFSET, 0x20); + + Status = WaitForL0 (PeiServices, StallPpi, PegPort, FALSE); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, "Link retrain FAILED!!!\n")); + } + + return Status; +} + +UINT8 +GetNegotiatedWidth ( + IN PEG_PORT *PegPort + ) +{ + UINT16 Lsts; + + Lsts = MmPci16 (0, PegPort->Bus, PegPort->Device, PegPort->Function, R_SA_PEG_LSTS_OFFSET); + + return (UINT8)((Lsts >> 4) & 0x3F); +} + +EFI_STATUS +RecoverLinkWidth ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_STALL_PPI *StallPpi, + IN PEG_PORT *PegPort, + IN UINT8 OriginalLinkWidth + ) +{ + EFI_STATUS Status; + UINT8 CurrentLinkWidth; + + Status = EFI_SUCCESS; + + CurrentLinkWidth = GetNegotiatedWidth (PegPort); + if (CurrentLinkWidth < OriginalLinkWidth) { + DEBUG ((EFI_D_INFO, "DOWNGRADE from x%d to x%d detected\n", OriginalLinkWidth, CurrentLinkWidth)); + MmPci32AndThenOr ( + 0, + PegPort->Bus, + PegPort->Device, + PegPort->Function, + R_SA_PEG_LTSSMC_OFFSET, + B_SA_PEG_LTSSMC_WIDTH_MASK, + OriginalLinkWidth + ); + MmPci16Or (0, PegPort->Bus, PegPort->Device, PegPort->Function, R_SA_PEG_LCTL_OFFSET, 0x10); + StallPpi->Stall (PeiServices, StallPpi, STALL_ONE_MICRO_SECOND); + MmPci16And (0, PegPort->Bus, PegPort->Device, PegPort->Function, R_SA_PEG_LCTL_OFFSET, 0xFFEF); + Status = WaitForL0 (PeiServices, StallPpi, PegPort, FALSE); + MmPci32Or ( + 0, + PegPort->Bus, + PegPort->Device, + PegPort->Function, + R_SA_PEG_LTSSMC_OFFSET, + 0x1F + ); + if (EFI_ERROR (Status)) { + return Status; + } + + CurrentLinkWidth = GetNegotiatedWidth (PegPort); + if (CurrentLinkWidth == OriginalLinkWidth) { + DEBUG ((EFI_D_INFO, "Width Recovery Successful\n")); + Status = EFI_SUCCESS; + } else { + DEBUG ((EFI_D_INFO, "Width Recovery FAILED!\n")); + Status = EFI_DEVICE_ERROR; + } + } + + return Status; +} + +UINT8 +GetLinkSpeed ( + IN PEG_PORT *PegPort + ) +{ + UINT16 Lsts; + + Lsts = MmPci16 (0, PegPort->Bus, PegPort->Device, PegPort->Function, R_SA_PEG_LSTS_OFFSET); + + return (UINT8)(Lsts & 0xF); +} + +EFI_STATUS +RecoverLinkSpeed ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_STALL_PPI *StallPpi, + IN PEG_PORT *PegPort, + IN UINT8 OriginalLinkSpeed + ) +{ + EFI_STATUS Status; + UINT8 CurrentLinkSpeed; + + Status = EFI_SUCCESS; + + CurrentLinkSpeed = GetLinkSpeed (PegPort); + if (CurrentLinkSpeed < OriginalLinkSpeed) { + DEBUG ((EFI_D_INFO, "DOWNGRADE from Gen %d to Gen %d detected\n", OriginalLinkSpeed, CurrentLinkSpeed)); + + Status = RetrainLink (PeiServices, StallPpi, PegPort); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, "Link Speed Recovery FAILED!\n")); + return Status; + } + + CurrentLinkSpeed = GetLinkSpeed (PegPort); + if (CurrentLinkSpeed < OriginalLinkSpeed) { + DEBUG ((EFI_D_INFO, "Link Speed Recovery FAILED!\n")); + Status = EFI_DEVICE_ERROR; + } else { + DEBUG ((EFI_D_INFO, "Link Speed Recovery Successful\n")); + } + } + + return Status; +} + +VOID +PcieTrainingWarmReset ( + IN EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + PCH_RESET_PPI *PchResetPpi; + + Status = (*PeiServices)->LocatePpi ( + PeiServices, + &gPchResetPpiGuid, + 0, + NULL, + &PchResetPpi + ); + ASSERT_EFI_ERROR (Status); + PchResetPpi->Reset (PchResetPpi, WarmReset); + + return; +} + +#endif // PEG_FLAG diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingMargining.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingMargining.c new file mode 100644 index 0000000..7d2f63d --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingMargining.c @@ -0,0 +1,223 @@ +/** @file + Margining for PEG Training + +@copyright + Copyright (c) 2012 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 "PcieTraining.h" + +#ifdef PEG_FLAG + +/// +/// Jitter Calculations +/// +JITTER_SETTING Jitter_Gen3[/* 083.333 */] = {{1, 64, 1, 0}, {1, 33, 2, 0}, {3, 64, 3, 0}, {4, 80, 4, 0}, {5, 97, 5, 0}, {6, 128, 6, 0}, {7, 129, 7, 0}, {8, 161, 8, 0}, {9, 192, 9, 0}, {10, 193, 10, 0}, {11, 225, 11, 0}, {12, 128, 12, 1}, {13, 129, 13, 1}, {14, 145, 14, 1}, {15, 160, 15, 1}, {16, 161, 16, 1}, {17, 177, 17, 1}, {18, 192, 18, 1}, {19, 193, 19, 1}, {20, 209, 20, 1}, {21, 224, 21, 1}, {22, 225, 22, 1}, {23, 241, 23, 1}, {24, 246, 24, 1}}; + +EFI_STATUS +SetJitterTolerance ( + IN UINT8 *LaneList, + IN UINT8 LaneListLength, + IN UINT8 ReportedMargin + ) +{ + JITTER_SETTING Settings = {0, 0, 0, 0}; + UINT8 i; + BOOLEAN Found; + + if (ReportedMargin > 0) { + Found = FALSE; + for (i = 0; i < (JITTER_LENGTH - 1); ++i) { + Settings = Jitter_Gen3[i]; + if (Settings.ReportedMargin == ReportedMargin) { + Found = TRUE; + break; + } + } + + if (Found) { + return SetRawJitterTolerance ( + LaneList, + LaneListLength, + Settings.Step, + Settings.Depth, + Settings.DoubleMargin, + TRUE + ); + } else { + return EFI_INVALID_PARAMETER; + } + } else { + return SetRawJitterTolerance ( + LaneList, + LaneListLength, + Settings.Step, + Settings.Depth, + Settings.DoubleMargin, + FALSE + ); + } +} + +EFI_STATUS +SetRawJitterTolerance ( + IN UINT8 *LaneList, + IN UINT8 LaneListLength, + IN UINT8 Step, + IN UINT8 Depth, + IN UINT8 DoubleMargin, + IN BOOLEAN EnableJitter + ) +{ + UINT8 BundleList[8]; + UINT8 BundleListLength; + UINT8 i; + UINT8 Lane; + UINT8 Bundle; + + BundleListLength = 0; + + GetBundleList (LaneList, LaneListLength, &BundleList[0], &BundleListLength); + + for (i = 0; i < LaneListLength; ++i) { + Lane = LaneList[i]; + + McD1PciCfg32And (R_SA_PEG_AFELN0CFG0_OFFSET + (Lane * LANE_STEP), 0xFFFFFBFF); + } + + for (i = 0; i < BundleListLength; ++i) { + Bundle = BundleList[i]; + + McD1PciCfg32AndThenOr ( + R_SA_PEG_AFEBND0CFG0_OFFSET + (Bundle * BUNDLE_STEP), + (UINT32) ~(BIT28 | BIT17 | BIT16 | BIT15 | BIT14 | BIT13 | BIT12 | BIT11 | BIT10), + (UINT32) ((DoubleMargin << 28) | (Step << 10)) + ); + + McD1PciCfg32AndThenOr ( + R_SA_PEG_AFEBND0CFG3_OFFSET + (Bundle * BUNDLE_STEP), + (UINT32) ~(BIT16 | BIT15 | BIT14 | BIT13 | BIT12 | BIT11), + (UINT32) (Depth << 11) + ); + } + + if (EnableJitter) { + for (i = 0; i < LaneListLength; ++i) { + Lane = LaneList[i]; + McD1PciCfg32Or (R_SA_PEG_AFELN0CFG0_OFFSET + (Lane * LANE_STEP), BIT10); + } + } + + return EFI_SUCCESS; +} + +VOID +EnableTxJitterInjection ( + IN UINT8 Lane, + IN BOOLEAN EnableTxJitter + ) +{ + UINT8 Bundle; + + Bundle = Lane / 2; + + if (EnableTxJitter) { + McD1PciCfg32AndThenOr ( + R_SA_PEG_AFEBND0CFG0_OFFSET + (Bundle * BUNDLE_STEP), + ~(BIT1 | BIT2), + 0x6 + ); + } else { + McD1PciCfg32And ( + R_SA_PEG_AFEBND0CFG0_OFFSET + (Bundle * BUNDLE_STEP), + ~(BIT1 | BIT2) + ); + } +} + + +VOID +ConfigureTxJitterMux ( + IN UINT8 Lane, + IN UINT32 MchBar + ) +{ + CPU_FAMILY CpuFamilyId; + CPU_STEPPING CpuSteppingId; + UINT32 SequenceId; + + CpuFamilyId = GetCpuFamily (); + CpuSteppingId = GetCpuStepping (); + SequenceId = V_SA_VCU_SEQID_SET_TXJITTER_MUX; + +#ifndef AMI_OVERRIDE_FOR_ULT_FASTBOOT + if (CpuFamilyId == EnumCpuHswUlt) return; +#endif // AMI_OVERRIDE_FOR_ULT_FASTBOOT + + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + SendVcuApiCmd (MchBar, V_SA_VCU_OPCODE_OPEN_SEQ_REV1, SequenceId); + } else { + SendVcuApiCmd (MchBar, V_SA_VCU_OPCODE_OPEN_SEQ_REV2, SequenceId); + } + + SendVcuApiCmd (MchBar, V_SA_VCU_OPCODE_SET_TXJITTER_MUX, Lane); + + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + SendVcuApiCmd (MchBar, V_SA_VCU_OPCODE_CLOSE_SEQ_REV1, 0); + } else { + SendVcuApiCmd (MchBar, V_SA_VCU_OPCODE_CLOSE_SEQ_REV2, 0); + } + + return; +} + +EFI_STATUS +GetBundleList ( + IN UINT8 *LaneList, + IN UINT8 LaneListLength, + OUT UINT8 *BundleList, + OUT UINT8 *BundleListLength + ) +{ + UINT8 Bundle; + BOOLEAN HasBundle; + UINT8 i; + UINT8 j; + + (*BundleListLength) = 0; + + for (i = 0; i < LaneListLength; ++i) { + Bundle = LaneList[i] / 2; + + HasBundle = FALSE; + for (j = 0; j < (*BundleListLength); ++j) { + if (BundleList[j] == Bundle) { + HasBundle = TRUE; + break; + } + } + + if (!HasBundle) { + BundleList[*BundleListLength] = Bundle; + ++(*BundleListLength); + } + } + + return EFI_SUCCESS; +} + +#endif // PEG_FLAG diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingPhase3.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingPhase3.c new file mode 100644 index 0000000..6123968 --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingPhase3.c @@ -0,0 +1,657 @@ +/** @file + This driver trains the PEG interface. + +@copyright + Copyright (c) 2012 - 2014 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 "PcieTraining.h" + +#ifdef PEG_FLAG + +#include EFI_PPI_DEFINITION (PchMeUma) +#include "PchMeUma.h" + +typedef struct _MARGIN_DATA { + UINT8 Preset; + INT32 TimingMargin[SA_PEG_MAX_LANE]; +} MARGIN_DATA; + +UINT8 +SelectBestPresetForLane ( + IN PORT_INFO *PortInfo, + IN UINT8 Lane, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN SA_DATA_HOB *SaDataHob, + IN UINT8 TrainingPreset + ) +{ + UINT8 BestPreset; + + /// + /// Init to EV default + /// + BestPreset = 7; + + /// + /// EnableMargin FoundUsablePreset SaDataHob + /// Y Y !NULL -> Use training results; update SaDataHob + /// Y Y NULL -> Use training results + /// Y N !NULL -> Use Policy value; update SaDataHob + /// X N NULL -> Use Policy value + /// N X !NULL -> Restore from SaDataHob + /// + if (Lane < SA_PEG_MAX_LANE) { + DEBUG ((EFI_D_INFO, "Preset for Lane %2d: ", Lane)); + if ((PortInfo->EnableMargin) && (PortInfo->FoundUsablePreset)) { + /// + /// Use the best preset found during training + /// + BestPreset = TrainingPreset; + DEBUG ((EFI_D_INFO, "Search Result: P%d", BestPreset)); + if (SaDataHob != NULL) { + DEBUG ((EFI_D_INFO, ". Saving value for next boot.")); + SaDataHob->PegData.BestPreset[Lane] = BestPreset; + } + } else if ((PortInfo->EnableMargin) && (!PortInfo->FoundUsablePreset) && (SaDataHob != NULL)) { + /// + /// Use the policy value; update SaDataHob + /// + BestPreset = (UINT8) SaPlatformPolicyPpi->PcieConfig->Gen3EndPointPreset[Lane]; + DEBUG ((EFI_D_INFO, "Applying Policy value: P%d. Saving value for next boot.", BestPreset)); + SaDataHob->PegData.BestPreset[Lane] = BestPreset; + } else if ((!PortInfo->FoundUsablePreset) && (SaDataHob == NULL)) { + /// + /// Use the policy value + /// + BestPreset = (UINT8) SaPlatformPolicyPpi->PcieConfig->Gen3EndPointPreset[Lane]; + DEBUG ((EFI_D_INFO, "Applying Policy value: P%d", BestPreset)); + } else if ((!PortInfo->EnableMargin) && (SaDataHob != NULL)) { + /// + /// Use the preset found on a previous boot + /// + BestPreset = (UINT8) SaDataHob->PegData.BestPreset[Lane]; + DEBUG ((EFI_D_INFO, "Restoring previous value: P%d", BestPreset)); + } + DEBUG ((EFI_D_INFO, "\n")); + } else { + /// + /// Error: Non-existent lane + /// + DEBUG ((EFI_D_ERROR, "Illegal Lane: %d", Lane)); + } + + return BestPreset; +} + +VOID +PegGen3PresetSearch ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN PEI_STALL_PPI *StallPpi, + SA_DATA_HOB *SaDataHob + ) +{ + UINT8 Index; + INT32 MarginScore; + UINT8 PegBus; + UINT8 PegDev; + UINT8 PegFunc; + UINT16 LinkStatus; + BOOLEAN LoadedSavedPreset; + BOOLEAN EndpointDeviceChanged; + UINT8 TempIndex; + BOOLEAN SkipBundle0; + CPU_FAMILY CpuFamilyId; + CPU_STEPPING CpuSteppingId; + MARGIN_DATA MarginData[MAX_PRESETS]; + PORT_INFO PortInfoList[SA_PEG_MAX_FUN]; + INT32 LaneScores[SA_PEG_MAX_LANE]; + INT32 BestScores[SA_PEG_MAX_LANE]; + UINT8 BestPresets[SA_PEG_MAX_LANE]; + EFI_STATUS Status; + UINT32 MonitorPort; + UINT8 PortInfoListLength; + UINT8 PortIndex; + UINT8 Lane; + BOOLEAN AnyGen3CapableLinks; + BOOLEAN AnyMarginingNeeded; + UINT8 PreCursor; + UINT8 Cursor; + UINT8 PostCursor; + UINT8 FullSwing; + UINT32 NominalRecoveryCount; + UINT8 FirstSkippedLane; + UINT8 LastSkippedLane; + UINT32 Data32; + BOOLEAN SlotResetNeeded; + PCH_ME_UMA_PPI *PchMeUmaPpi; + UINT8 DetectedReplacedCpu; + + AnyMarginingNeeded = FALSE; + CpuFamilyId = GetCpuFamily(); + CpuSteppingId = GetCpuStepping(); + + /// + /// Setup default presets to search + /// + MarginData[0].Preset = 7; + MarginData[1].Preset = 3; + MarginData[2].Preset = 5; + + /// + /// Initialize Arrays + /// + for (Lane = 0; Lane < SA_PEG_MAX_LANE; Lane++) { + LaneScores[Lane] = -1; + BestScores[Lane] = -1; + BestPresets[Lane] = MarginData[0].Preset; + } + + DEBUG ((EFI_D_INFO, "PEG Gen3 Preset Search\n")); + + if (!SaPolicyEnablesGen3 (SaPlatformPolicyPpi)) { + DEBUG ((EFI_D_INFO, " Gen3 is disabled by policy\n")); + return; + } + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId < EnumHswB0)) { + DEBUG ((EFI_D_WARN, " Gen3 preset search is not supported on this stepping\n")); + return; + } + Data32 = (McD1PciCfg32 (R_SA_PEG_PEGTST_OFFSET) & BIT20) >> 20; + if (Data32 != 0) { + DEBUG ((EFI_D_WARN, " Gen3 preset search does not support lane reversal\n")); + return; + } + + /// + /// If ME is supported and the CPU has been replaced, redo the Preset Search. + /// Note that calling CpuReplacementCheck() can induce an ME-required warm reset. + /// + DetectedReplacedCpu = 0; + Status = EFI_SUCCESS; + + if ((SaDataHob != NULL) && (SaDataHob->PegDataValid)) { + Status = (*PeiServices)->LocatePpi (PeiServices, &gPchMeUmaPpiGuid, 0, NULL, &PchMeUmaPpi); + ASSERT_EFI_ERROR (Status); + DEBUG ((EFI_D_INFO, "Calling CpuReplacementCheck\n")); + Status = PchMeUmaPpi->CpuReplacementCheck (PeiServices, NULL, &DetectedReplacedCpu); + ASSERT_EFI_ERROR (Status); + DEBUG ((EFI_D_INFO, " ME reported CPU Replacement value: %x\n", DetectedReplacedCpu)); + } + + /// + /// Get the furcation setup and port information + /// + GetPortInfo (&(PortInfoList[0]), &PortInfoListLength, &SkipBundle0); + + /// + /// Make sure we at Gen3 before starting, if not attempt reset and see if that helps + /// + SlotResetNeeded = FALSE; + for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) { + PegBus = (PortInfoList[PortIndex]).PegPort.Bus; + PegDev = (PortInfoList[PortIndex]).PegPort.Device; + PegFunc = (PortInfoList[PortIndex]).PegPort.Function; + LinkStatus = MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_LSTS_OFFSET); + if (((LinkStatus & 0x0F) != 3) && ((PortInfoList[PortIndex]).LinkIsGen3Capable)) { + SlotResetNeeded = TRUE; + break; + } + } + if (SlotResetNeeded) { + /// + /// Bypass phase2 and assert slot reset + /// + McD1PciCfg32Or (R_SA_PEG_EQCFG_OFFSET, BIT15); + Status = TogglePegSlotReset (PeiServices, StallPpi, SaPlatformPolicyPpi); + if (!EFI_ERROR (Status)) { + for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) { + PegBus = (PortInfoList[PortIndex]).PegPort.Bus; + PegDev = (PortInfoList[PortIndex]).PegPort.Device; + PegFunc = (PortInfoList[PortIndex]).PegPort.Function; + /// + /// Wait for Equalization Done + /// + while (((MmPci32 (0, PegBus, PegDev, PegFunc, R_SA_PEG_LSTS2_OFFSET) >> 1) & 0x1) != 0x1); + /// + /// Wait for flow control credits exchange + /// + WaitForVc0Negotiation (PeiServices, StallPpi, PegBus, PegDev, PegFunc); + } + } + } + + /// + /// Determine which PEG ports require testing + /// + AnyGen3CapableLinks = FALSE; + for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) { + PegBus = (PortInfoList[PortIndex]).PegPort.Bus; + PegDev = (PortInfoList[PortIndex]).PegPort.Device; + PegFunc = (PortInfoList[PortIndex]).PegPort.Function; + + /// + /// If we already have Best Preset value from previous boot, use it and skip PresetSearch when end point device no change + /// + LoadedSavedPreset = FALSE; + EndpointDeviceChanged = TRUE; + if (SaDataHob != NULL) { + if (SaDataHob->PegDataValid) { + LoadedSavedPreset = TRUE; + if (SaDataHob->PegData.EndPointVendorIdDeviceId[PegFunc] == (PortInfoList[PortIndex]).EndPointVendorIdDeviceId) { + EndpointDeviceChanged = FALSE; + } + } + if (EndpointDeviceChanged) { + /// + /// Save new device ID vendor ID + /// + SaDataHob->PegData.EndPointVendorIdDeviceId[PegFunc] = (PortInfoList[PortIndex]).EndPointVendorIdDeviceId; + } + } + DEBUG ((EFI_D_INFO, " PEG%x%x (%x:%x:%x) - LoadedSavedPreset = %d. EndpointDeviceChanged = %d.\n", + PegDev, PegFunc, PegBus, PegDev, PegFunc, LoadedSavedPreset, EndpointDeviceChanged)); + + ReportPcieLinkStatus (PegBus, PegDev, PegFunc); + + if ( (!LoadedSavedPreset) || + (EndpointDeviceChanged) || + (DetectedReplacedCpu != 0) || + ((SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_2) && + (SaPlatformPolicyPpi->PcieConfig->PegGen3ForcePresetSearch == 1 ))) { + (PortInfoList[PortIndex]).EnableMargin = TRUE; + } else { + (PortInfoList[PortIndex]).EnableMargin = FALSE; + } + + if (!(PortInfoList[PortIndex]).LinkIsGen3Capable) { + (PortInfoList[PortIndex]).EnableMargin = FALSE; + } else { + AnyGen3CapableLinks = TRUE; + } + } ///< PegFunc Loop end + + if (!AnyGen3CapableLinks) { + DEBUG ((EFI_D_INFO, "Skipping Preset Search - No Gen3 capable links\n")); + return; + } + + /// + /// Determine if any ports need to be trained. + /// If any ports are trained, the corresponding endpoint should also be reset with PERST#. + /// + for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) { + if ((PortInfoList[PortIndex]).EnableMargin == TRUE) { + AnyMarginingNeeded = TRUE; + break; + } + } + + if (AnyMarginingNeeded) { + MonitorPort = OpenMonitor (PeiServices, SaPlatformPolicyPpi, StallPpi); + + McD1PciCfg32Or (R_SA_PEG_REUT_PH_CTR_OFFSET, B_SA_PEG_REUT_PH_CTR_AUTOCOMP_MASK); + + /// + /// Presets Loop start + /// + for (Index = 0; Index < MAX_PRESETS; Index++) { + /// + /// Clear out old values + /// + for (TempIndex = 0; TempIndex < SA_PEG_MAX_LANE; TempIndex++) { + MarginData[Index].TimingMargin[TempIndex] = 0; + } ///< End of for each Lane + + + for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) { + (PortInfoList[PortIndex]).SkipMargin = FALSE; + PegBus = (PortInfoList[PortIndex]).PegPort.Bus; + PegDev = (PortInfoList[PortIndex]).PegPort.Device; + PegFunc = (PortInfoList[PortIndex]).PegPort.Function; + + if (!(PortInfoList[PortIndex]).LinkIsGen3Capable) { + DEBUG ((EFI_D_INFO, "Skipping PEG%d%d - Not Gen3 capable\n", PegDev, PegFunc)); + continue; + } + + /// + /// Find first lane of the port for coefficient programming + /// + switch (PegFunc) { + default: + case 0: + Lane = 0; + FirstSkippedLane = 0; + LastSkippedLane = 1; + break; + case 1: + Lane = 8; + FirstSkippedLane = 8; + LastSkippedLane = 9; + break; + case 2: + Lane = 12; + FirstSkippedLane = 12; + LastSkippedLane = 13; + break; + } + + /// + /// Get FullSwing + /// + GetLinkPartnerFullSwing (Lane, &FullSwing); + + /// + /// Get Coefficients + /// + GetCoefficientsFromPreset (MarginData[Index].Preset, FullSwing, &PreCursor, &Cursor, &PostCursor); + + /// + /// Set Lane's Coefficients + /// + if (SkipBundle0) { + for (TempIndex = FirstSkippedLane; TempIndex <= LastSkippedLane; TempIndex++) { + SetPartnerTxCoefficients (TempIndex, &PreCursor, &Cursor, &PostCursor); + ProgramPreset (1, MarginData[Index].Preset, PegFunc, TempIndex); + } + } + for (TempIndex = 0; TempIndex < (PortInfoList[PortIndex]).LaneListLength; TempIndex++) { + SetPartnerTxCoefficients ((PortInfoList[PortIndex]).LaneList[TempIndex], &PreCursor, &Cursor, &PostCursor); + ProgramPreset (1, MarginData[Index].Preset, PegFunc, (PortInfoList[PortIndex]).LaneList[TempIndex]); + } + + /// + /// Set DOEQ bit + /// + MmPci32Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCTL3_OFFSET, BIT0); + RetrainLink (PeiServices, StallPpi, &((PortInfoList[PortIndex]).PegPort)); + + /// + /// Get the current link status + /// + LinkStatus = MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_LSTS_OFFSET); + /// + /// No need to margin if couldn't get to Gen3 with this preset + /// + if ((LinkStatus & 0x0F) != 3) { + RecoverLinkFailure (PeiServices, SaPlatformPolicyPpi, SaDataHob, StallPpi, + &((PortInfoList[PortIndex]).PegPort), 3, + GetNegotiatedWidth (&((PortInfoList[PortIndex]).PegPort))); + LinkStatus = MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_LSTS_OFFSET); + if ((LinkStatus & 0x0F) != 3) { + (PortInfoList[PortIndex]).SkipMargin = TRUE; + continue; + } + } + + NominalRecoveryCount = SaPcieGetErrorCount (MonitorPort, PegFunc); + StallPpi->Stall (PeiServices, StallPpi, SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearchDwellTime * STALL_ONE_MICRO_SECOND); + NominalRecoveryCount = SaPcieGetErrorCount (MonitorPort, PegFunc) - NominalRecoveryCount; + if (NominalRecoveryCount > 0) { + (PortInfoList[PortIndex]).SkipMargin = TRUE; + continue; + } + (PortInfoList[PortIndex]).FoundUsablePreset = TRUE; + } ///< End of for each Port + + Status = RunMarginTest ( + PeiServices, + SaPlatformPolicyPpi, + SaDataHob, + StallPpi, + MonitorPort, + &(PortInfoList[0]), + PortInfoListLength, + LaneLevelRxJitter, + MarginData[Index].TimingMargin + ); + + if (EFI_ERROR (Status)) { + for (TempIndex = 0; TempIndex < SA_PEG_MAX_LANE; TempIndex++) { + MarginData[Index].TimingMargin[TempIndex] = 0; + } + } + } ///< Presets Loop end + + McD1PciCfg32And (R_SA_PEG_REUT_PH_CTR_OFFSET, ~B_SA_PEG_REUT_PH_CTR_AUTOCOMP_MASK); + CloseMonitor (SaPlatformPolicyPpi, MonitorPort); + + /// + /// Find the preset with the maximum margin (largest of all margin values) + /// + for (Index = 0; Index < sizeof (MarginData) / sizeof (MarginData[0]); Index++) { + for (Lane = 0; Lane < SA_PEG_MAX_LANE; Lane++) { + LaneScores[Lane] = -1; + } + for (Lane = 0; Lane < SA_PEG_MAX_LANE; Lane++) { + if (MarginData[Index].TimingMargin[Lane] != -1) { + MarginScore = MarginData[Index].TimingMargin[Lane]; + LaneScores[Lane] = MarginScore; + } + if (LaneScores[Lane] > BestScores[Lane]) { + BestScores[Lane] = LaneScores[Lane]; + BestPresets[Lane] = MarginData[Index].Preset; + } + } ///< End of for each Lane + } ///< End of for each Preset + + /// + /// If Lanes 0-1 were skipped, copy the values from Lane 2 + /// + if (SkipBundle0) { + for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) { + PegFunc = (PortInfoList[PortIndex]).PegPort.Function; + switch (PegFunc) { + default: + case 0: + Lane = 2; + FirstSkippedLane = 0; + LastSkippedLane = 1; + break; + case 1: + Lane = 10; + FirstSkippedLane = 8; + LastSkippedLane = 9; + break; + case 2: + Lane = 14; + FirstSkippedLane = 12; + LastSkippedLane = 13; + break; + } + if (BestScores[Lane] != -1) { + DEBUG ((EFI_D_INFO, "Using Lane %2d's Best Preset for Lanes %2d-%2d.\n", Lane, FirstSkippedLane, LastSkippedLane)); + for (TempIndex = FirstSkippedLane; TempIndex <= LastSkippedLane; TempIndex++) { + BestScores[TempIndex] = BestScores[Lane]; + BestPresets[TempIndex] = BestPresets[Lane]; + } + } + } ///< End of for each port + } ///< End of SkipBundle0 + } ///< End of AnyMarginingNeeded + + for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) { + PegBus = (PortInfoList[PortIndex]).PegPort.Bus; + PegDev = (PortInfoList[PortIndex]).PegPort.Device; + PegFunc = (PortInfoList[PortIndex]).PegPort.Function; + if (!(PortInfoList[PortIndex]).LinkIsGen3Capable) { + continue; + } + if (SkipBundle0) { + switch (PegFunc) { + default: + case 0: + FirstSkippedLane = 0; + LastSkippedLane = 1; + break; + case 1: + FirstSkippedLane = 8; + LastSkippedLane = 9; + break; + case 2: + FirstSkippedLane = 12; + LastSkippedLane = 13; + break; + } + for (TempIndex = FirstSkippedLane; TempIndex <= LastSkippedLane; TempIndex++) { + BestPresets[TempIndex] = SelectBestPresetForLane ( + &(PortInfoList[PortIndex]), + TempIndex, + SaPlatformPolicyPpi, + SaDataHob, + BestPresets[TempIndex] + ); + } + } + for (TempIndex = 0; TempIndex < (PortInfoList[PortIndex]).LaneListLength; TempIndex++) { + BestPresets[(PortInfoList[PortIndex]).LaneList[TempIndex]] = SelectBestPresetForLane ( + &(PortInfoList[PortIndex]), + (PortInfoList[PortIndex]).LaneList[TempIndex], + SaPlatformPolicyPpi, + SaDataHob, + BestPresets[(PortInfoList[PortIndex]).LaneList[TempIndex]] + ); + } + } + + /// + /// Program the presets. If any link was margined, also reset the + /// endpoints in order to return the endpoints to a known-good state. + /// + if (AnyMarginingNeeded) { + for (TempIndex = 0; TempIndex < SA_PEG_MAX_FUN; TempIndex++) { + MmPci16Or (0, SA_PEG_BUS_NUM, SA_PEG_DEV_NUM, TempIndex, R_SA_PEG_LCTL_OFFSET, BIT4); + } + AssertPegSlotReset (SaPlatformPolicyPpi); + } + for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) { + PegBus = (PortInfoList[PortIndex]).PegPort.Bus; + PegDev = (PortInfoList[PortIndex]).PegPort.Device; + PegFunc = (PortInfoList[PortIndex]).PegPort.Function; + if (!(PortInfoList[PortIndex]).LinkIsGen3Capable) { + DEBUG ((EFI_D_INFO, "PEG%d%d - Not Gen3 capable, skip coefficient programming.\n", PegDev, PegFunc)); + continue; + } + /// + /// Find first lane of the port for coefficient programming + /// + switch (PegFunc) { + default: + case 0: + Lane = 0; + FirstSkippedLane = 0; + LastSkippedLane = 1; + break; + case 1: + Lane = 8; + FirstSkippedLane = 8; + LastSkippedLane = 9; + break; + case 2: + Lane = 12; + FirstSkippedLane = 12; + LastSkippedLane = 13; + break; + } + /// + /// Get FullSwing + /// + GetLinkPartnerFullSwing (Lane, &FullSwing); + + if (SkipBundle0) { + for (TempIndex = FirstSkippedLane; TempIndex <= LastSkippedLane; TempIndex++) { + GetCoefficientsFromPreset (BestPresets[TempIndex], FullSwing, &PreCursor, &Cursor, &PostCursor); + SetPartnerTxCoefficients (TempIndex, &PreCursor, &Cursor, &PostCursor); + ProgramPreset (1, BestPresets[TempIndex], PegFunc, TempIndex); + } + } + for (TempIndex = 0; TempIndex < (PortInfoList[PortIndex]).LaneListLength; TempIndex++) { + /// + /// Get Coefficients + /// + GetCoefficientsFromPreset (BestPresets[((PortInfoList[PortIndex]).LaneList[TempIndex])], FullSwing, &PreCursor, &Cursor, &PostCursor); + + /// + /// Set Lane's Coefficients + /// + SetPartnerTxCoefficients ((PortInfoList[PortIndex]).LaneList[TempIndex], &PreCursor, &Cursor, &PostCursor); + + /// + /// Set Phase 1 Presets + /// + ProgramPreset (1, BestPresets[((PortInfoList[PortIndex]).LaneList[TempIndex])], PegFunc, (PortInfoList[PortIndex]).LaneList[TempIndex]); + } + + MmPci32Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCTL3_OFFSET, BIT0); ///< DOEQ + MmPci16Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCTL_OFFSET, BIT5); ///< Retrain link + } + + if (AnyMarginingNeeded) { + StallPpi->Stall (PeiServices, StallPpi, 100 * STALL_ONE_MICRO_SECOND); + for (TempIndex = 0; TempIndex < SA_PEG_MAX_FUN; TempIndex++) { + MmPci16And (0, SA_PEG_BUS_NUM, SA_PEG_DEV_NUM, TempIndex, R_SA_PEG_LCTL_OFFSET, (UINT16) ~(BIT4)); + } + DeassertPegSlotReset (SaPlatformPolicyPpi); + } + + for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) { + PegBus = (PortInfoList[PortIndex]).PegPort.Bus; + PegDev = (PortInfoList[PortIndex]).PegPort.Device; + PegFunc = (PortInfoList[PortIndex]).PegPort.Function; + WaitForL0 (PeiServices, StallPpi, &(PortInfoList[PortIndex].PegPort), FALSE); + ReportPcieLinkStatus (PegBus, PegDev, PegFunc); + } + + DEBUG ((EFI_D_INFO, "PEG Gen3 Preset Search done\n\n")); + + return; +} + +BOOLEAN +SaPolicyEnablesGen3 ( + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +{ + UINTN PegPortGenx; + BOOLEAN Gen3Enabled; + UINT8 Index; + + Gen3Enabled = FALSE; + + /// + /// Check if Gen3 is enabled on PEG10/11/12 + /// + for (Index = 0; Index < SA_PEG_MAX_FUN; Index++) { + /// + /// PegPortGenx: 0 = Auto, 1 = Gen1, 2 = Gen2, 3 = Gen3 + /// + PegPortGenx = SaPlatformPolicyPpi->PcieConfig->PegGenx[Index]; + + /// + /// Check if the root port is present and the speed is not limited to Gen1/Gen2 + /// + if ((PegPortGenx == PEG_AUTO) || (PegPortGenx == PEG_GEN3)) { + Gen3Enabled = TRUE; + break; + } + } + return Gen3Enabled; +} + +#endif // PEG_FLAG diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaDmiPeim.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaDmiPeim.c new file mode 100644 index 0000000..ea817d8 --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaDmiPeim.c @@ -0,0 +1,450 @@ +/** @file + SA Dmi PEI Initialization library + +@copyright + Copyright (c) 1999 - 2012 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 "SaDmiPeim.h" +#include "PciExpressInit.h" + +/// +/// Functions +/// +/** + Initialize DMI Tc/Vc mapping through SA-PCH. + + @param[in] PeiServices - General purpose services available to every PEIM. + @param[in] SaPlatformPolicyPpi - Instance of SA_PLATFORM_POLICY_PPI + + @retval EFI_SUCCESS +**/ +EFI_STATUS +SaDmiTcVcInit ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +{ + EFI_STATUS Status; + UINT64 MchBar; + UINT64 DmiBar; + PCH_INIT_PPI *PchInitPpi; + PCH_DMI_TC_VC_PPI *PchDmiTcVcMapPpi; + CPU_FAMILY CpuFamilyId; + UINT8 i; + + MchBar = McD0PciCfg64 (R_SA_MCHBAR) &~BIT0; + DmiBar = McD0PciCfg64 (R_SA_DMIBAR) &~BIT0; + CpuFamilyId = GetCpuFamily(); + + /// + /// Locate PchInitPpi and PchDmiTcVcMapPpi + /// + Status = (*PeiServices)->LocatePpi (PeiServices, &gPchInitPpiGuid, 0, NULL, (VOID **) &PchInitPpi); + ASSERT_EFI_ERROR (Status); + + Status = (*PeiServices)->LocatePpi (PeiServices, &gPchDmiTcVcMapPpiGuid, 0, NULL, (VOID **) &PchDmiTcVcMapPpi); + ASSERT_EFI_ERROR (Status); + + /// + /// SA OPI Initialization + /// + if (CpuFamilyId == EnumCpuHswUlt) { + MmioOr8 ((UINTN) (DmiBar + 0xA78), BIT1); + } + + /// + /// Update DmiTcVcMapping based on Policy + /// + PchDmiTcVcMapPpi->DmiVc[DmiVcTypeVc1].Enable = (BOOLEAN) SaPlatformPolicyPpi->PcieConfig->DmiVc1; + PchDmiTcVcMapPpi->DmiVc[DmiVcTypeVcp].Enable = (BOOLEAN) SaPlatformPolicyPpi->PcieConfig->DmiVcp; + PchDmiTcVcMapPpi->DmiVc[DmiVcTypeVcm].Enable = (BOOLEAN) SaPlatformPolicyPpi->PcieConfig->DmiVcm; + + for (i = 0; i < DmiTcTypeMax; i++) { + if (((PchDmiTcVcMapPpi->DmiTc[i].Vc == DmiVcTypeVc1) && (PchDmiTcVcMapPpi->DmiVc[DmiVcTypeVc1].Enable == FALSE)) || + ((PchDmiTcVcMapPpi->DmiTc[i].Vc == DmiVcTypeVcp) && (PchDmiTcVcMapPpi->DmiVc[DmiVcTypeVcp].Enable == FALSE)) || + ((PchDmiTcVcMapPpi->DmiTc[i].Vc == DmiVcTypeVcm) && (PchDmiTcVcMapPpi->DmiVc[DmiVcTypeVcm].Enable == FALSE)) + ) { + PchDmiTcVcMapPpi->DmiTc[i].Vc = DmiVcTypeVc0; + } + } + /// + /// Program NB TC/VC mapping + /// + SaSetDmiTcVcMapping (PchDmiTcVcMapPpi, DmiBar); + + /// + /// Call PchDmiTcVcProgPoll + /// + Status = PchInitPpi->DmiTcVcProgPoll (PeiServices); + ASSERT_EFI_ERROR (Status); + + /// + /// Poll NB negotiation completion + /// + SaPollDmiVcStatus (PchDmiTcVcMapPpi, DmiBar); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; + +} + +/** + Map SA DMI TCs to VC + + @param[in] PchDmiTcVcMapPpi - Instance of PCH_DMI_TC_VC_PPI + @param[in] DmiBar - DMIBAR address + + @retval EFI_SUCCESS - Succeed. + @retval EFI_INVALID_PARAMETER - Wrong phase parameter passed in. +**/ +EFI_STATUS +SaSetDmiTcVcMapping ( + IN PCH_DMI_TC_VC_PPI *PchDmiTcVcMapPpi, + IN UINT64 DmiBar + ) +{ + UINT32 Data32And; + UINT32 Data32Or; + UINT8 Data8And; + UINT8 Data8Or; + UINT8 Index; + UINT16 Register; + UINT8 VcId; + UINT8 VcMap[DmiVcTypeMax] = { 0 }; + + /// + /// Set the TC/VC mappings + /// + for (Index = 0; Index < DmiTcTypeMax; Index++) { + VcMap[PchDmiTcVcMapPpi->DmiTc[Index].Vc] |= (BIT0 << Index); + } + /// + /// System BIOS must perform the following steps for VC0 configuration. + /// Program the TCs/VC0 map by setting DMIBAR offset 014h [7:1] = '0111 101b'. + /// + /// Private Virtual Channel Configuration + /// Step1. Assign Virtual Channel ID 2 to VCp: + /// Programming the DMIVCPRCTL DMI Port Register DMIBAR Offset 02Ch[26:24] = '010b'. + /// + /// Step2. Set TC2 to VCp: + /// Program the DMIVCPRCTL DMI Port Register DMIBAR offset 02Ch [7:1] = '0000 010b'. + /// + /// Step3. Enable VCp by programming the DMIVCPRCTL DMI Port Register DMIBAR Offset 02Ch[31] = '1b'. + /// + /// Virtual Channel for ME (VCm) Configuration + /// This is configured by ConfigMemMe + /// + /// Step1. Assign Virtual Channel ID 7 to VCm: + /// Programming the DMIVCMRCTL DMI Port Register DMIBAR Offset 038h[26:24] = '111b'. + /// + /// Step2. Enable VCm: + /// Programming the DMIVMPRCTL DMI Port Register DMIBAR Offset 038h[31] = '1b'. + /// + /// Step3. Enable VCm by programming the DMIVCMRCTL DMI Port Register DMIBAR Offset 038h[31] = '1b'. + /// + for (Index = 0; Index < DmiVcTypeMax; Index++) { + if (PchDmiTcVcMapPpi->DmiVc[Index].Enable == PCH_DEVICE_ENABLE) { + /// + /// Map TCs to VC, Set the VC ID, Enable VC + /// + VcId = PchDmiTcVcMapPpi->DmiVc[Index].VcId, + + Data32And = (UINT32) (~(V_SA_DMIBAR_DMIVCCTL_ID | B_SA_DMIBAR_DMIVCCTL_TVM_MASK)); + Data32Or = VcId << N_SA_DMIBAR_DMIVCCTL_ID; + Data32Or |= VcMap[Index]; + Data32Or |= N_SA_DMIBAR_DMIVCCTL_EN; + + switch (Index) { + case DmiVcTypeVc0: + Register = R_SA_DMIBAR_DMIVC0RCTL_OFFSET; + break; + + case DmiVcTypeVc1: + Register = R_SA_DMIBAR_DMIVC1RCTL_OFFSET; + break; + + case DmiVcTypeVcp: + Register = R_SA_DMIBAR_DMIVCPRCTL_OFFSET; + break; + + case DmiVcTypeVcm: + Register = R_SA_DMIBAR_DMIVCMRCTL_OFFSET; + break; + + default: + return EFI_INVALID_PARAMETER; + } + + MmioAndThenOr32 ((UINTN) (DmiBar + Register), Data32And, Data32Or); + } + } + /// + /// System BIOS must program the extended VC Count: + /// Set the DMI Port Register DMIBAR Offset 004h[2:0]=001b + /// + Data8And = (UINT8) (~0x07); + if (PchDmiTcVcMapPpi->DmiVc[DmiVcTypeVc1].Enable == TRUE) { + Data8Or = 1; + } else { + Data8Or = 0; + } + + MmioAndThenOr8 ((UINTN) (DmiBar + R_SA_DMIBAR_DMIPVCCAP1_OFFSET), Data8And, Data8Or); + + return EFI_SUCCESS; +} + +/** + Poll SA DMI negotiation completion + + @param[in] PchDmiTcVcMapPpi - Instance of PCH_DMI_TC_VC_PPI + @param[in] DmiBar - DMIBAR address + + @retval EFI_SUCCESS - Succeed. + @retval EFI_INVALID_PARAMETER - Wrong phase parameter passed in. +**/ +EFI_STATUS +SaPollDmiVcStatus ( + IN PCH_DMI_TC_VC_PPI *PchDmiTcVcMapPpi, + IN UINT64 DmiBar + ) +{ + UINT8 Index; + UINT16 Register; + + /// + /// 6.2.3.2 - Step 4, Poll until VC1 has been negotiated + /// Read the DMIVC1RSTS DMI Port Register Offset 026h until [1]==0 + /// + /// 6.2.3.3 - Step4. Poll the VCp Negotiation Pending bit until it reads 0: + /// Read the DMIVCPRSTS DMI Port Register Offset 032h until [1]==0 + /// + /// 6.2.3.4 - Step4. Poll the VCm Negotiation Pending bit until it reads 0: + /// Read the DMIVCMRSTS DMI Port Register Offset 03Eh until [1]==0 + /// + for (Index = 0; Index < DmiVcTypeMax; Index++) { + if (PchDmiTcVcMapPpi->DmiVc[Index].Enable == PCH_DEVICE_ENABLE) { + switch (Index) { + case DmiVcTypeVc0: + Register = R_SA_DMIBAR_DMIVC0RSTS_OFFSET; + break; + + case DmiVcTypeVc1: + Register = R_SA_DMIBAR_DMIVC1RSTS_OFFSET; + break; + + case DmiVcTypeVcp: + Register = R_SA_DMIBAR_DMIVCPRSTS_OFFSET; + break; + + case DmiVcTypeVcm: + Register = R_SA_DMIBAR_DMIVCMRSTS_OFFSET; + break; + + default: + return EFI_INVALID_PARAMETER; + } + /// + /// Wait for negotiation to complete + /// + while ((MmioRead16 ((UINTN) (DmiBar + Register)) & B_SA_DMIBAR_DMISTS_NP) != 0); + } + } + + return EFI_SUCCESS; +} + +#ifdef DMI_FLAG +/** + Initialize DMI. + + @param[in] PeiServices - General purpose services available to every PEIM. + @param[in] SaPlatformPolicyPpi - Instance of SA_PLATFORM_POLICY_PPI + + @retval EFI_SUCCESS +**/ +EFI_STATUS +DmiInit ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +{ + EFI_STATUS Status; + UINT64 MchBar; + UINT64 DmiBar; + PCH_INIT_PPI *PchInitPpi; + PCH_PLATFORM_POLICY_PPI *PchPlatformPolicyPpi; + UINT8 CpuSteppingId; + BOOLEAN DmiGen2Enable; + UINT16 LinkStatus; + UINT32 Data32Or; + + /// + /// Read the CPU stepping + /// + CpuSteppingId = GetCpuStepping(); + + /// + /// BridgeId = (UINT8) (McD0PciCfg16 (R_MC_DEVICE_ID) & 0xF0); + /// BridgeSteppingId = BridgeId + CpuSteppingId; + /// + MchBar = McD0PciCfg64 (R_SA_MCHBAR) &~BIT0; + DmiBar = McD0PciCfg64 (R_SA_DMIBAR) &~BIT0; + + /// + /// Get RCBA through the PchPlatformPolicy PPI + /// + Status = (**PeiServices).LocatePpi ( + PeiServices, + &gPchPlatformPolicyPpiGuid, + 0, + NULL, + &PchPlatformPolicyPpi + ); + ASSERT_EFI_ERROR (Status); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Can't locate PchPlatformPolicy PPI - exiting.\n")); + return Status; + } + /// + /// Perform DMI Recipe steps + /// + DEBUG ((EFI_D_INFO, "DMI Recipe...\n")); + PegDmiRecipe (SaPlatformPolicyPpi, (UINT32) MchBar, (UINT32) DmiBar, 0, 0); + + /// + /// Additional DMI steps. See SA BIOS Spec. + /// + DEBUG ((EFI_D_INFO, "Run AdditionalDmiProgramSteps!\n")); + AdditionalDmiProgramSteps (SaPlatformPolicyPpi, (UINT32) MchBar, (UINT32) DmiBar); + + DmiGen2Enable = TRUE; + if ((SaPlatformPolicyPpi->PcieConfig->DmiGen2 == 0) || + ((MmioRead8 ((UINTN) PchPlatformPolicyPpi->Rcba + R_PCH_RCRB_LCAP) & (BIT0 | BIT1 | BIT2 | BIT3)) == 0x1) || + (McDevFunPciCfg32 (0, 0, 0, R_SA_MC_CAPID0_A_OFFSET) & BIT22) + ) { + DEBUG ((EFI_D_WARN, "DMI Gen2 is Disabled or not capable, staying at Gen1 !\n")); + DmiGen2Enable = FALSE; + } + + if (DmiGen2Enable) { + /// + /// Locate PchInitPpi + /// + Status = (*PeiServices)->LocatePpi (PeiServices, &gPchInitPpiGuid, 0, NULL, &PchInitPpi); + ASSERT_EFI_ERROR (Status); + + /// + /// Program PCH TLS to Gen 2 + /// + PchInitPpi->DmiGen2Prog (PeiServices); + + /// + /// Program CPU Max Link Speed to Gen 2 + /// + MmioAndThenOr32 ((UINTN) (DmiBar + R_SA_DMIBAR_LCAP_OFFSET), (UINT32)~0xF, 2); + } + Data32Or = (MmioRead32 ((UINTN) (DmiBar + R_SA_DMIBAR_LCAP_OFFSET)) & (BIT3 | BIT2 | BIT1 | BIT0)); + MmioAndThenOr32 ((UINTN) (DmiBar + R_SA_DMIBAR_LCTL2_OFFSET), (UINT32)~(BIT3 | BIT2 | BIT1 | BIT0), Data32Or); + + /// + /// Retrain link + /// + DmiLinkTrain (DmiBar); + + /// + /// Retrain link if it is GEN2 Capable and it is not yet set to GEN2 + /// + if (DmiGen2Enable && + ((((MmioRead16 ((UINTN) (DmiBar + R_SA_DMIBAR_LSTS_OFFSET))) & 0x0F) != DMI_GEN2) || + (((MmioRead16 ((UINTN) PchPlatformPolicyPpi->Rcba + R_PCH_RCRB_LSTS)) & 0x0F) != DMI_GEN2)) + ) { + DEBUG ((EFI_D_INFO, "DMI Link re-train to set GEN2\n")); + DmiLinkTrain (DmiBar); + } + /// + /// Get the current link status + /// + LinkStatus = MmioRead16 ((UINTN) (DmiBar + R_SA_DMIBAR_LSTS_OFFSET)); + DEBUG ((EFI_D_INFO, "DMI trained to x%d at Gen%d\n", (LinkStatus >> 4) & 0x3F, LinkStatus & 0x0F)); + + return EFI_SUCCESS; +} + +/** + DMI link training + + @param[in] DmiBar - DMIBAR address +**/ +VOID +DmiLinkTrain ( + IN UINT64 DmiBar + ) +{ + /// + /// Retrain link + /// + MmioOr8 ((UINTN) (DmiBar + R_SA_DMIBAR_LCTL_OFFSET), BIT5); + + /// + /// Wait for link training complete + /// + while ((MmioRead16 ((UINTN) (DmiBar + R_SA_DMIBAR_LSTS_OFFSET)) & BIT11) != 0) + ; +} + +/** + Additional DMI Programming Steps at PEI + + @param[in] SaPlatformPolicyPpi - pointer to SA_PLATFORM_POLICY_PPI + @param[in] MchBar - MCHBAR address + @param[in] DmiBar - DMIBAR address +**/ +VOID +AdditionalDmiProgramSteps ( + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN UINT32 MchBar, + IN UINT32 DmiBar + ) +{ + UINT32 Data32And; + UINT32 Data32Or; + + /// + /// Disable DMI and PEG Debug Align Message - set 0x258[29] = '1b' + /// + Data32And = (UINT32) ~BIT29; + Data32Or = BIT29; + Mmio32AndThenOr (DmiBar, R_SA_DMIBAR_CFG4_OFFSET, Data32And, Data32Or); + + /// + /// Overwrite DMICC (DMIBAR offset 0x208) to 0x6B5 + /// + Data32And = (UINT32)~(BIT10 | BIT9 | BIT8 | BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0); + Data32Or = 0x6B5; + Mmio32AndThenOr (DmiBar, R_SA_DMIBAR_DMICC_OFFSET, Data32And, Data32Or); + + /// + /// Set L0SLAT[15:0] to 0x2020 + /// + Data32And = (UINT32) ~(0xFFFF); + Data32Or = 0x00002020; + Mmio32AndThenOr (DmiBar, R_SA_DMIBAR_L0SLAT_OFFSET, Data32And, Data32Or); +} +#endif // DMI_FLAG diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaDmiPeim.h b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaDmiPeim.h new file mode 100644 index 0000000..799eb13 --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaDmiPeim.h @@ -0,0 +1,94 @@ +/** @file + Header file for the SA Dmi Init library. + +@copyright + Copyright (c) 1999 - 2012 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 +**/ +#ifndef _SA_DMI_PEIM_H_ +#define _SA_DMI_PEIM_H_ + +#include "EdkIIGluePeim.h" +#include "SaAccess.h" +#include "CpuRegs.h" +#include "CpuPlatformLib.h" + +/// +/// Driver Consumed PPI Prototypes +/// +#include EFI_PPI_DEPENDENCY (SaPlatformPolicy) +#include EFI_PPI_DEPENDENCY (PchPlatformPolicy) +#include EFI_PPI_DEPENDENCY (PchInit) +#include EFI_PPI_DEPENDENCY (PchDmiTcVcMap) + +/** + Map SA DMI TCs to VC + + @param[in] PchDmiTcVcMapPpi - Instance of PCH_DMI_TC_VC_PPI + @param[in] DmiBar - DMIBAR address + + @retval EFI_SUCCESS +**/ +EFI_STATUS +SaSetDmiTcVcMapping ( + IN PCH_DMI_TC_VC_PPI *PchDmiTcVcMapPpi, + IN UINT64 DmiBar + ) +; + +/** + Poll SA DMI negotiation completion + + @param[in] PchDmiTcVcMapPpi - Instance of PCH_DMI_TC_VC_PPI + @param[in] DmiBar - DMIBAR address + + @retval EFI_SUCCESS +**/ +EFI_STATUS +SaPollDmiVcStatus ( + IN PCH_DMI_TC_VC_PPI *PchDmiTcVcMapPpi, + IN UINT64 DmiBar + ) +; + +#ifdef DMI_FLAG +/** + DMI link training + + @param[in] DmiBar - DMIBAR address +**/ +VOID +DmiLinkTrain ( + IN UINT64 DmiBar + ) +; + +/** + Additional DMI Programming Steps at PEI + + @param[in] SaPlatformPolicyPpi - pointer to SA_PLATFORM_POLICY_PPI + @param[in] MchBar - MCHBAR address + @param[in] DmiBar - DMIBAR address +**/ +VOID +AdditionalDmiProgramSteps ( + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi, + IN UINT32 MchBar, + IN UINT32 DmiBar + ) +; +#endif // DMI_FLAG +#endif diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.c new file mode 100644 index 0000000..28fc22e --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.c @@ -0,0 +1,689 @@ +/** @file + The PEIM implements the SA PEI Initialization. + +@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 "SaInitPeim.h" +#ifdef RAPID_START_FLAG +#include EFI_PPI_CONSUMER (RapidStart) +#endif + +static EFI_PEI_PPI_DESCRIPTOR mSaPeiInitPpi[] = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gSaPeiInitPpiGuid, + NULL +}; + +STATIC EFI_PEI_NOTIFY_DESCRIPTOR mSaResetCompleteNotifyDesc = { + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gMemoryInitHobGuid, + SaResetComplete +}; + +EFI_GUID gEfiPeiEndOfPeiPhasePpiGuid = EFI_PEI_END_OF_PEI_PHASE_PPI_GUID; +STATIC EFI_PEI_NOTIFY_DESCRIPTOR mSaS3ResumeNotifyDesc = { + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiEndOfPeiPhasePpiGuid, + SaS3ResumeAtEndOfPei +}; + +#ifdef RAPID_START_FLAG +STATIC EFI_PEI_NOTIFY_DESCRIPTOR mSaOnRapidStartPpiNotifyDesc = { + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gRapidStartPpiGuid, + SaCheckRapidStartMode +}; +#endif + +/// +/// Functions +/// +static +EFI_STATUS +SaS3ResumeAtEndOfPei ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc, + IN VOID *Ppi + ) +/** + This function handles SA S3 resume task + + @param[in] PeiServices - Pointer to PEI Services Table. + @param[in] NotifyDesc - Pointer to the descriptor for the Notification event that + caused this function to execute. + @param[in] Ppi - Pointer to the PPI data associated with this function. + + @retval EFI_STATUS - Always return EFI_SUCCESS +**/ +{ + SA_DATA_HOB *SaDataHob; + CPU_STEPPING CpuSteppingId; + CPU_FAMILY CpuFamilyId; + + CpuSteppingId = GetCpuStepping(); + CpuFamilyId = GetCpuFamily(); + /// + /// Get SaPegDataHob HOB + /// + SaDataHob = NULL; + SaDataHob = (SA_DATA_HOB *)GetFirstGuidHob (&gSaDataHobGuid); + if (SaDataHob != NULL) { + /// + /// If there was no DXE mode supported, always enable SMM mode + /// +#if SA_PCIE_ASPM_IN_DXE == 0 + SaDataHob->InitPcieAspmAfterOprom = 1; +#endif + /// + /// If there was no SMM mode supported, always enable DXE mode + /// +#if SA_PCIE_ASPM_IN_SMM == 0 + SaDataHob->InitPcieAspmAfterOprom = 0; +#endif + + if ((SaDataHob->SaIotrapSmiAddress != 0) && (SaDataHob->InitPcieAspmAfterOprom == 1)) { +#if SA_PCIE_ASPM_IN_SMM == 1 + /// + /// Always generate SA IO TRAP SMI when supported + /// The SMI handler will directly return if not PCIe ASPM init after Oprom was enabled + /// + DEBUG ((EFI_D_INFO, "Generate SA IOTRAP SMI port=%X\n", SaDataHob->SaIotrapSmiAddress)); + IoWrite8 (SaDataHob->SaIotrapSmiAddress, 0); +#endif + } + } +#if SA_PCIE_ASPM_IN_DXE == 1 + if ((SaDataHob == NULL) || (SaDataHob->InitPcieAspmAfterOprom == 0)) { + /// + /// When SaDataHob not preset/corrupted or InitPcieAspmAfterOprom set to 0, + /// try to do DXE mode S3 resume task. + /// + /// + /// Lock processor/chipset BAR registers + /// Other save/restore were done by S3 Save script table + /// + if (!(((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId <= EnumHswB0) ) || + ((CpuFamilyId == EnumCpuHswUlt) && (CpuSteppingId <= EnumHswUltB0)) || + ((CpuFamilyId == EnumCpuCrw) && (CpuSteppingId <= EnumCrwB0) ) )) { + AsmMsrOr64 (0x2e7, 1); + } + } +#endif + return EFI_SUCCESS; +} + +#ifdef RAPID_START_FLAG +static +EFI_STATUS +SaCheckRapidStartMode ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc, + IN VOID *Ppi + ) +/** + This function will check Rapid Start mode and install SaS3Resume callback notify if it was Rapid Start Resume + + @param[in] PeiServices - Pointer to PEI Services Table. + @param[in] NotifyDesc - Pointer to the descriptor for the Notification event that + caused this function to execute. + @param[in] Ppi - Pointer to the PPI data associated with this function. + + @retval EFI_STATUS - Always return EFI_SUCCESS +**/ +{ + RAPID_START_PPI *RapidStartPpi; + EFI_STATUS Status; + + /// + /// When Rapid Start implemented and in the Rapid Start Resume transition, this SA S3 resume Notify should happen early than Rapid Start End-Of-Pei callback + /// This is because Rapid Start End-Of-Pei callback will generate ACPI_ENABLE SMI which should be after SA S3 resume completed. + /// + Status = PeiServicesLocatePpi (&gRapidStartPpiGuid, 0, NULL, &RapidStartPpi); + ASSERT_EFI_ERROR (Status); + if (RapidStartPpi->GetMode (RapidStartPpi) == RapidStartExit) { + DEBUG ((EFI_D_INFO, "[SA] Install Notify callback for Rapid Start Resume\n")); + Status = PeiServicesNotifyPpi (&mSaS3ResumeNotifyDesc); + ASSERT_EFI_ERROR (Status); + } + return EFI_SUCCESS; +} +#endif + +EFI_STATUS +EFIAPI +SaInitPeiEntryPoint ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +/** + SA PEI Initialization. + + @param[in] FfsHeader - Pointer to Firmware File System file header. + @param[in] PeiServices - General purpose services available to every PEIM. + + @retval EFI_SUCCESS +**/ +{ + EFI_STATUS Status; + SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi; + EFI_BOOT_MODE BootMode; +#ifdef RAPID_START_FLAG + RAPID_START_PPI *RapidStartPpi; +#endif +#if defined(DMI_FLAG) || defined(PEG_FLAG) + CPU_FAMILY CpuFamilyId; + + CpuFamilyId = GetCpuFamily(); +#endif // DMI_FLAG || PEG_FLAG + + /// + /// Get platform policy settings through the SaPlatformPolicy PPI + /// + Status = (**PeiServices).LocatePpi ( + PeiServices, + &gSaPlatformPolicyPpiGuid, + 0, + NULL, + (VOID **) &SaPlatformPolicyPpi + ); + ASSERT_EFI_ERROR (Status); + + /// + /// Dump SA Platform Policy + /// + SaPeiPolicyDump (SaPlatformPolicyPpi); + + /// + /// Program SA Bar Registers + /// + DEBUG ((EFI_D_INFO, "Programming SA Bars\n")); + ProgramSaBars (SaPlatformPolicyPpi); + + /// + /// Install SA HOBs + /// + InstallSaHob (PeiServices, SaPlatformPolicyPpi); + + /// + /// Report SA PCIe code version + /// + DEBUG ((EFI_D_INFO, "Reporting SA PCIe code version\n")); + ReportPcieVersion (SaPlatformPolicyPpi); + +#ifdef DMI_FLAG + if ((CpuFamilyId == EnumCpuHsw) || (CpuFamilyId == EnumCpuCrw)) { + /// + /// Initialize DMI + /// + DEBUG ((EFI_D_INFO, "Initializing DMI\n")); + DmiInit (PeiServices, SaPlatformPolicyPpi); + } +#endif // DMI_FLAG + +#ifdef SG_SUPPORT + /// + /// Initialize SwitchableGraphics + /// + DEBUG ((EFI_D_INFO, "Initializing SwitchableGraphics\n")); + SwitchableGraphicsInit (PeiServices, SaPlatformPolicyPpi); +#endif + +#ifdef PEG_FLAG + if ((CpuFamilyId == EnumCpuHsw) || (CpuFamilyId == EnumCpuCrw)) { + /// + /// Initialize SA PCIe + /// + DEBUG ((EFI_D_INFO, "Initializing SA PCIe\n")); + PciExpressInit (PeiServices, SaPlatformPolicyPpi); + } +#endif // PEG_FLAG + + /// + /// Initialize Graphics (IGD/External) + /// + DEBUG ((EFI_D_INFO, "Initializing Graphics\n")); + GraphicsInit (PeiServices, SaPlatformPolicyPpi); + + /// + /// Initialize Overclocking + /// + DEBUG ((EFI_D_INFO, "Initializing System Agent Overclocking\n")); + SaOcInit(PeiServices, SaPlatformPolicyPpi); + + /// + /// Initialize DMI Tc/Vc mapping setting + /// + DEBUG ((EFI_D_INFO, "Initializing DMI Tc/Vc mapping\n")); + SaDmiTcVcInit (PeiServices, SaPlatformPolicyPpi); + + /// + /// Early BIOS POST Programming + /// + DEBUG ((EFI_D_INFO, "Early BIOS POST Programming\n")); + EarlyBiosPostProgramming(SaPlatformPolicyPpi); + + /// + /// Install Notify + /// + Status = PeiServicesNotifyPpi (&mSaResetCompleteNotifyDesc); + ASSERT_EFI_ERROR (Status); + + /// + /// Install SA S3 resume Notify only when booting from S3 resume + /// + Status = PeiServicesGetBootMode (&BootMode); + DEBUG ((EFI_D_INFO, "[SA] BootMode = %X\n", BootMode)); + if ((Status == EFI_SUCCESS) && (BootMode == BOOT_ON_S3_RESUME)) { + DEBUG ((EFI_D_INFO, "[SA] Install SA S3 Notify callback\n")); + Status = PeiServicesNotifyPpi (&mSaS3ResumeNotifyDesc); + ASSERT_EFI_ERROR (Status); + } +#ifdef RAPID_START_FLAG + else { + /// + /// When Rapid Start implemented and in the Rapid Start Resume transition, this SA S3 resume Notify should happen early than Rapid Start End-Of-Pei callback + /// This is because Rapid Start End-Of-Pei callback will generate ACPI_ENABLE SMI which should be after SA S3 resume completed. + /// + Status = PeiServicesLocatePpi (&gRapidStartPpiGuid, 0, NULL, &RapidStartPpi); + if (Status == EFI_SUCCESS) { + DEBUG ((EFI_D_INFO, "[SA] Check Rapid Start transition mode\n")); + if (RapidStartPpi->GetMode (RapidStartPpi) == RapidStartExit) { + DEBUG ((EFI_D_INFO, "[SA] Install Notify callback for Rapid Start Resume\n")); + Status = PeiServicesNotifyPpi (&mSaS3ResumeNotifyDesc); + ASSERT_EFI_ERROR (Status); + } + } else { + DEBUG ((EFI_D_INFO, "[SA] Postpone Rapid Start mode checking after RapidStartPpi installed\n")); + Status = PeiServicesNotifyPpi (&mSaOnRapidStartPpiNotifyDesc); + } + } +#endif + + /// + /// Install Ppi with SaInitPeim complete + /// + Status = (**PeiServices).InstallPpi (PeiServices, mSaPeiInitPpi); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +SaResetComplete ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc, + IN VOID *Ppi + ) +/** + BIOS_RESET_CPL bit is set for processor to activate the power and thermal management + features on the platform. + + @param[in] PeiServices - Pointer to PEI Services Table. + @param[in] NotifyDesc - Pointer to the descriptor for the Notification event that + caused this function to execute. + @param[in] Ppi - Pointer to the PPI data associated with this function. + + @retval EFI_SUCCESS +**/ +{ + EFI_STATUS Status; + UINT64 MchBar; + UINT32 Data32And; + UINT32 Data32Or; + SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi; + + MchBar = McD0PciCfg64 (R_SA_MCHBAR) &~BIT0; + + /// + /// Get platform policy settings through the SaPlatformPolicy PPI + /// + Status = PeiServicesLocatePpi (&gSaPlatformPolicyPpiGuid, 0, NULL, (VOID **) &SaPlatformPolicyPpi); + ASSERT_EFI_ERROR (Status); + + /// + /// Set MCHBAR Offset 5F00h [10:9] = 11b + /// + Data32And = (UINT32)~(BIT10 | BIT9); + Data32Or = 0x3 << 9; + Mmio32AndThenOr (MchBar, R_SA_MCHBAR_SAPMCTL_OFFSET, Data32And, Data32Or); + + /// + /// Set BIOS_RESET_CPL + /// + DEBUG ((EFI_D_INFO, "Set BIOS_RESET_CPL to indicate all configurations complete\n")); + Mmio8Or ((UINTN) MchBar, R_SA_MCHBAR_BIOS_RESET_CPL_OFFSET, BIT0 | BIT1); + + return EFI_SUCCESS; +} + +VOID +ProgramSaBars ( + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +/** + Programs SA Bars + + @param[in] SaPlatformPolicyPpi - Instance of SA_PLATFORM_POLICY_PPI +**/ +{ + CPU_FAMILY CpuFamilyId; + + CpuFamilyId = GetCpuFamily(); + + /// + /// Program SA MchBar, DmiBar and EpBar + /// + McD0PciCfg64 (R_SA_MCHBAR) = (UINT64) (SaPlatformPolicyPpi->PlatformData->MchBar | BIT0); + McD0PciCfg64 (R_SA_DMIBAR) = (UINT64) (SaPlatformPolicyPpi->PlatformData->DmiBar | BIT0); + McD0PciCfg64 (R_SA_PXPEPBAR) = (UINT64) (SaPlatformPolicyPpi->PlatformData->EpBar | BIT0); + + /// + /// Program SA GdxcBar + /// + Mmio64 ((UINTN) (SaPlatformPolicyPpi->PlatformData->MchBar), R_SA_MCHBAR_GDXCBAR_OFFSET) = (UINT64) + (SaPlatformPolicyPpi->PlatformData->GdxcBar | BIT0); + + if (CpuFamilyId == EnumCpuCrw) { + /// + /// Program SA EdramBar + /// + Mmio64 ((UINTN) (SaPlatformPolicyPpi->PlatformData->MchBar), R_SA_MCHBAR_EDRAMBAR_OFFSET) = (UINT64) + (SaPlatformPolicyPpi->PlatformData->EdramBar | BIT0); + } +} + +VOID +EarlyBiosPostProgramming ( + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +/** + Do Early BIOS POST Programming + + @param[in] SaPlatformPolicyPpi - Instance of SA_PLATFORM_POLICY_PPI +**/ +{ + /// SA BS 11.1 Early BIOS POST Programming + /// 1. Enable System Agent Clock Gating by setting the MCHBAR offset 5F00h [0] = '1b'. + MmioOr32 ((UINTN) (SaPlatformPolicyPpi->PlatformData->MchBar + 0x5F00), BIT0); +} + +EFI_STATUS +InstallSaHob ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +/** + Init and Install SA Hob + + @param[in] PeiServices - General purpose services available to every PEIM. + @param[in] SaPlatformPolicyPpi - SaPlatformPolicyPpi to access the GtConfig related information + + @retval EFI_SUCCESS +**/ +{ + EFI_STATUS Status; + SA_DATA_HOB *SaDataHob; + PEI_CPU_PLATFORM_POLICY_PPI *CpuPlatformPolicy; + + /// + /// Create HOB for SA Data + /// + Status = (**PeiServices).CreateHob ( + PeiServices, + EFI_HOB_TYPE_GUID_EXTENSION, + sizeof (SA_DATA_HOB), + (VOID **) &SaDataHob + ); + ASSERT_EFI_ERROR (Status); + + /// + /// Initialize default HOB data + /// + SaDataHob->EfiHobGuidType.Name = gSaDataHobGuid; + ZeroMem (&(SaDataHob->DprDirectory[EnumDprDirectoryTxt]), sizeof (DPR_DIRECTORY_ENTRY)); + ZeroMem (&(SaDataHob->DprDirectory[EnumDprDirectoryPfat]), sizeof (DPR_DIRECTORY_ENTRY)); + ZeroMem (&(SaDataHob->PegData), sizeof (SA_PEG_DATA)); + SaDataHob->PegDataValid = FALSE; + SaDataHob->PegPlatformResetRequired = FALSE; + if (SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_2) { + SaDataHob->SaIotrapSmiAddress = SaPlatformPolicyPpi->PcieConfig->SaIotrapSmiAddress; + SaDataHob->InitPcieAspmAfterOprom = SaPlatformPolicyPpi->PcieConfig->InitPcieAspmAfterOprom; + } else { + SaDataHob->SaIotrapSmiAddress = 0; + SaDataHob->InitPcieAspmAfterOprom = 0; + } + + /// + /// Get platform policy settings through the SaPlatformPolicy PPI + /// + Status = (**PeiServices).LocatePpi ( + PeiServices, + &gPeiCpuPlatformPolicyPpiGuid, + 0, + NULL, + (VOID **) &CpuPlatformPolicy + ); + ASSERT_EFI_ERROR (Status); + + /// + /// TXT DPR Directory Entry + /// +#if defined(TXT_SUPPORT_FLAG) && (TXT_SUPPORT_FLAG == 1) + SaDataHob->DprDirectory[EnumDprDirectoryTxt].Type = DPR_DIRECTORY_TYPE_TXT; + if (CpuPlatformPolicy->CpuConfig->Txt) { + SaDataHob->DprDirectory[EnumDprDirectoryTxt].Size = (UINT8) RShiftU64 (CpuPlatformPolicy->SecurityConfig->TxtConfig->TxtDprMemorySize, 20); + } +#endif + + /// + /// PFAT Directory Entry + /// + SaDataHob->DprDirectory[EnumDprDirectoryPfat].Type = DPR_DIRECTORY_TYPE_PFAT; + if (CpuPlatformPolicy->CpuConfig->Pfat) { + SaDataHob->DprDirectory[EnumDprDirectoryPfat].Size = CpuPlatformPolicy->SecurityConfig->PfatConfig->PfatMemSize; + } + + DEBUG ((EFI_D_INFO, "SA Data HOB installed\n")); + + return EFI_SUCCESS; +} + +EFI_STATUS +ReportPcieVersion ( + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +/** + Report the SA PCIe initialization code version. + + @param[in] SaPlatformPolicyPpi - Instance of SA_PLATFORM_POLICY_PPI + + @retval EFI_SUCCESS +**/ +{ + UINT32 Version; + CPU_FAMILY CpuFamilyId; + CPU_STEPPING CpuSteppingId; + const CodeVersion SaPcieCodeVersion = { +#include "SaPcieVersion.h" + }; + + DEBUG ((EFI_D_INFO, "***************** System Agent PCIe code version *****************\n")); + DEBUG ((EFI_D_INFO, "** Major version number is: %3d **\n", SaPcieCodeVersion.Major)); + DEBUG ((EFI_D_INFO, "** Minor version number is: %3d **\n", SaPcieCodeVersion.Minor)); + DEBUG ((EFI_D_INFO, "** Rev version number is: %3d **\n", SaPcieCodeVersion.Rev)); + DEBUG ((EFI_D_INFO, "** Build number is: %3d **\n", SaPcieCodeVersion.Build)); + DEBUG ((EFI_D_INFO, "******************************************************************\n")); + + Version = (((UINT32) SaPcieCodeVersion.Major) << 24) | (((UINT32) SaPcieCodeVersion.Minor) << 16) | (((UINT32) SaPcieCodeVersion.Rev) << 8) | (((UINT32) SaPcieCodeVersion.Build)); + + CpuFamilyId = GetCpuFamily(); + CpuSteppingId = GetCpuStepping(); + + /// + /// Store SA Reference Code version and SA PCIe code version in scrachpad registers + /// + if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) { + Mmio32 ((UINTN) (SaPlatformPolicyPpi->PlatformData->MchBar), R_SA_MCHBAR_PCIE_CODE_VERSION_OFFSET_HSW) = Version; + } else { + Mmio32 ((UINTN) (SaPlatformPolicyPpi->PlatformData->DmiBar), R_SA_DMIBAR_SCRATCHPAD0_OFFSET) = SaPlatformPolicyPpi->Revision; + Mmio32 ((UINTN) (SaPlatformPolicyPpi->PlatformData->DmiBar), R_SA_DMIBAR_SCRATCHPAD1_OFFSET) = Version; + } + return EFI_SUCCESS; +} + +VOID +SaPeiPolicyDump ( + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +/** + This function prints the PEI phase platform policy. + + @param[in] SaPlatformPolicyPpi - Instance of SA_PLATFORM_POLICY_PPI +**/ +{ +#ifdef EFI_DEBUG + INTN i; + + DEBUG ((EFI_D_INFO, "\n------------------------ SA Platform Policy (PEI) dump BEGIN -----------------\n")); + DEBUG ((EFI_D_INFO, "Revision : %x\n", SaPlatformPolicyPpi->Revision)); + + DEBUG ((EFI_D_INFO, "------------------------ SA_PLATFORM_DATA -----------------\n")); + + DEBUG ((EFI_D_INFO, " SpdAddressTable[%d] :", SA_MC_MAX_SOCKETS)); + for (i = 0; i < SA_MC_MAX_SOCKETS; i++) { + DEBUG ((EFI_D_INFO, " %x", SaPlatformPolicyPpi->PlatformData->SpdAddressTable[i])); + } + DEBUG ((EFI_D_INFO, "\n")); + + DEBUG ((EFI_D_INFO, " MchBar : %x\n", SaPlatformPolicyPpi->PlatformData->MchBar)); + DEBUG ((EFI_D_INFO, " DmiBar : %x\n", SaPlatformPolicyPpi->PlatformData->DmiBar)); + DEBUG ((EFI_D_INFO, " EpBar : %x\n", SaPlatformPolicyPpi->PlatformData->EpBar)); + DEBUG ((EFI_D_INFO, " PciExpressBar : %x\n", SaPlatformPolicyPpi->PlatformData->PciExpressBar)); + DEBUG ((EFI_D_INFO, " SmbusBar : %x\n", SaPlatformPolicyPpi->PlatformData->SmbusBar)); + DEBUG ((EFI_D_INFO, " GdxcBar : %x\n", SaPlatformPolicyPpi->PlatformData->GdxcBar)); + DEBUG ((EFI_D_INFO, " TsegSize : %x\n", SaPlatformPolicyPpi->PlatformData->TsegSize)); + DEBUG ((EFI_D_INFO, " UserBd : %x\n", SaPlatformPolicyPpi->PlatformData->UserBd)); + DEBUG ((EFI_D_INFO, " FastBoot : %x\n", SaPlatformPolicyPpi->PlatformData->FastBoot)); + DEBUG ((EFI_D_INFO, " EdramBar : %x\n", SaPlatformPolicyPpi->PlatformData->EdramBar)); + + DEBUG ((EFI_D_INFO, "------------------------ GT_CONFIGURATION -----------------\n")); + DEBUG ((EFI_D_INFO, " MmioSize : %x MB\n", SaPlatformPolicyPpi->GtConfig->MmioSize)); + DEBUG ((EFI_D_INFO, " GttSize : %x MB\n", SaPlatformPolicyPpi->GtConfig->GttSize)); + DEBUG ((EFI_D_INFO, " IgdDvmt50PreAlloc : %x\n", SaPlatformPolicyPpi->GtConfig->IgdDvmt50PreAlloc)); + DEBUG ((EFI_D_INFO, " InternalGraphics : %x\n", SaPlatformPolicyPpi->GtConfig->InternalGraphics)); + DEBUG ((EFI_D_INFO, " PrimaryDisplay : %x\n", SaPlatformPolicyPpi->GtConfig->PrimaryDisplay)); + DEBUG ((EFI_D_INFO, " ApertureSize : %x\n", SaPlatformPolicyPpi->GtConfig->ApertureSize)); + DEBUG ((EFI_D_INFO, " GttMmAdr : %x\n", SaPlatformPolicyPpi->GtConfig->GttMmAdr)); + + DEBUG ((EFI_D_INFO, "------------------------ PCIE_CONFIGURATION -----------------\n")); + DEBUG ((EFI_D_INFO, " DmiVc1 : %x\n", SaPlatformPolicyPpi->PcieConfig->DmiVc1)); + DEBUG ((EFI_D_INFO, " DmiVcp : %x\n", SaPlatformPolicyPpi->PcieConfig->DmiVcp)); + DEBUG ((EFI_D_INFO, " DmiVcm : %x\n", SaPlatformPolicyPpi->PcieConfig->DmiVcm)); + DEBUG ((EFI_D_INFO, " DmiGen2 : %x\n", SaPlatformPolicyPpi->PcieConfig->DmiGen2)); + DEBUG ((EFI_D_INFO, " AlwaysEnablePeg : %x\n", SaPlatformPolicyPpi->PcieConfig->AlwaysEnablePeg)); + + DEBUG ((EFI_D_INFO, " PegGenx[%d] :", SA_PEG_MAX_FUN)); + for (i = 0; i < SA_PEG_MAX_FUN; i++) { + DEBUG ((EFI_D_INFO, " %x", SaPlatformPolicyPpi->PcieConfig->PegGenx[i])); + } + DEBUG ((EFI_D_INFO, "\n")); + + DEBUG ((EFI_D_INFO, " PegGen3Equalization : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGen3Equalization)); + + DEBUG ((EFI_D_INFO, " Gen3RootPortPreset[%d] :", SA_PEG_MAX_LANE)); + for (i = 0; i < SA_PEG_MAX_LANE; i++) { + DEBUG ((EFI_D_INFO, " %x", SaPlatformPolicyPpi->PcieConfig->Gen3RootPortPreset[i])); + } + DEBUG ((EFI_D_INFO, "\n")); + + DEBUG ((EFI_D_INFO, " Gen3EndPointPreset[%d] :", SA_PEG_MAX_LANE)); + for (i = 0; i < SA_PEG_MAX_LANE; i++) { + DEBUG ((EFI_D_INFO, " %x", SaPlatformPolicyPpi->PcieConfig->Gen3EndPointPreset[i])); + } + DEBUG ((EFI_D_INFO, "\n")); + + DEBUG ((EFI_D_INFO, " Gen3EndPointHint[%d] :", SA_PEG_MAX_LANE)); + for (i = 0; i < SA_PEG_MAX_LANE; i++) { + DEBUG ((EFI_D_INFO, " %x", SaPlatformPolicyPpi->PcieConfig->Gen3EndPointHint[i])); + } + DEBUG ((EFI_D_INFO, "\n")); + + DEBUG ((EFI_D_INFO, " PegSamplerCalibrate : %x\n", SaPlatformPolicyPpi->PcieConfig->PegSamplerCalibrate)); + DEBUG ((EFI_D_INFO, " PegGen3EqualizationPhase2 : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGen3EqualizationPhase2)); + DEBUG ((EFI_D_INFO, " PegGen3PresetSearch : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearch)); + DEBUG ((EFI_D_INFO, " PegGen3PresetSearchDwellTime : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearchDwellTime)); + DEBUG ((EFI_D_INFO, " PegGen3PresetSearchMarginSteps : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearchMarginSteps)); + DEBUG ((EFI_D_INFO, " PegGen3PresetSearchStartMargin : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearchStartMargin)); + DEBUG ((EFI_D_INFO, " PegSwingControl : %x\n", SaPlatformPolicyPpi->PcieConfig->PegSwingControl)); + if (SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_2) { + DEBUG ((EFI_D_INFO, " PegGen3PresetSearchVoltageMarginSteps : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearchVoltageMarginSteps)); + DEBUG ((EFI_D_INFO, " PegGen3PresetSearchVoltageStartMargin : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearchVoltageStartMargin)); + DEBUG ((EFI_D_INFO, " PegGen3PresetSearchFavorTiming : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearchFavorTiming)); + DEBUG ((EFI_D_INFO, " PegDataPtr : %p\n", SaPlatformPolicyPpi->PcieConfig->PegDataPtr)); + DEBUG ((EFI_D_INFO, " PegGen3ForcePresetSearch : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGen3ForcePresetSearch)); + DEBUG ((EFI_D_INFO, " InitPcieAspmAfterOprom : %x\n", SaPlatformPolicyPpi->PcieConfig->InitPcieAspmAfterOprom)); + DEBUG ((EFI_D_INFO, " SaIotrapSmiAddress : %x\n", SaPlatformPolicyPpi->PcieConfig->SaIotrapSmiAddress)); + } + if (SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_3) { + DEBUG ((EFI_D_INFO, " PegGpioData : %p\n", SaPlatformPolicyPpi->PcieConfig->PegGpioData)); + if (SaPlatformPolicyPpi->PcieConfig->PegGpioData != NULL) { + DEBUG ((EFI_D_INFO, " PegGpioData->GpioSupport : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGpioData->GpioSupport)); + if (SaPlatformPolicyPpi->PcieConfig->PegGpioData->SaPegReset != NULL) { + DEBUG ((EFI_D_INFO, " PegGpioData->SaPegReset->Value : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGpioData->SaPegReset->Value)); + DEBUG ((EFI_D_INFO, " PegGpioData->SaPegReset->Active : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGpioData->SaPegReset->Active)); + } + } + DEBUG ((EFI_D_INFO, " PegGen3PresetSearchErrorTarget : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearchErrorTarget)); + DEBUG ((EFI_D_INFO, " RxCEMLoopback : %x\n", SaPlatformPolicyPpi->PcieConfig->RxCEMLoopback)); + DEBUG ((EFI_D_INFO, " RxCEMLoopbackLane : %x\n", SaPlatformPolicyPpi->PcieConfig->RxCEMLoopbackLane)); + + DEBUG ((EFI_D_INFO, " Gen3RxCtleP[%d] :", SA_PEG_MAX_BUNDLE)); + for (i = 0; i < SA_PEG_MAX_BUNDLE; i++) { + DEBUG ((EFI_D_INFO, " %x", SaPlatformPolicyPpi->PcieConfig->Gen3RxCtleP[i])); + } + DEBUG ((EFI_D_INFO, "\n")); + } + + DEBUG ((EFI_D_INFO, "------------------------ OVERCLOCKING_CONFIGURATION -----------------\n")); + DEBUG ((EFI_D_INFO, " GtVoltageOffset : %x\n", SaPlatformPolicyPpi->OcConfig->GtVoltageOffset)); + DEBUG ((EFI_D_INFO, " GtVoltageOverride : %x\n", SaPlatformPolicyPpi->OcConfig->GtVoltageOverride)); + DEBUG ((EFI_D_INFO, " GtExtraTurboVoltage : %x\n", SaPlatformPolicyPpi->OcConfig->GtExtraTurboVoltage)); + DEBUG ((EFI_D_INFO, " GtMaxOcTurboRatio : %x\n", SaPlatformPolicyPpi->OcConfig->GtMaxOcTurboRatio)); + DEBUG ((EFI_D_INFO, " SaVoltageOffset : %x\n", SaPlatformPolicyPpi->OcConfig->SaVoltageOffset)); + DEBUG ((EFI_D_INFO, " GtVoltageMode : %x\n", SaPlatformPolicyPpi->OcConfig->GtVoltageMode)); + DEBUG ((EFI_D_INFO, " OcSupport : %x\n", SaPlatformPolicyPpi->OcConfig->OcSupport)); + DEBUG ((EFI_D_INFO, " IoaVoltageOffset : %x\n", SaPlatformPolicyPpi->OcConfig->IoaVoltageOffset)); + DEBUG ((EFI_D_INFO, " IodVoltageOffset : %x\n", SaPlatformPolicyPpi->OcConfig->IodVoltageOffset)); + + DEBUG ((EFI_D_INFO, "------------------------ Misc -----------------\n")); + DEBUG ((EFI_D_INFO, " S3DataPtr : %x\n", SaPlatformPolicyPpi->S3DataPtr)); + + if (SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_3) { + DEBUG ((EFI_D_INFO, "------------------------ SG_GPIO_DATA -----------------\n")); + DEBUG ((EFI_D_INFO, " SgGpioData : %x\n", SaPlatformPolicyPpi->SgGpioData)); + if (SaPlatformPolicyPpi->SgGpioData != NULL) { + DEBUG ((EFI_D_INFO, " SgGpioData->GpioSupport : %x\n", SaPlatformPolicyPpi->SgGpioData->GpioSupport)); + } + } + + DEBUG ((EFI_D_INFO, "\n------------------------ SA Platform Policy (PEI) dump END -----------------\n")); +#endif + return; +} diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.cif b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.cif new file mode 100644 index 0000000..c60de34 --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.cif @@ -0,0 +1,30 @@ +<component> + name = "SaInitPeim" + category = ModulePart + LocalRoot = "ReferenceCode\Chipset\SystemAgent\SaInit\Pei" + RefName = "SaInitPeim" +[files] +"SaInitPeim.sdl" +"SaInitPeim.mak" +"SaInitPeim.h" +"SaInitPeim.c" +"SaInitPeim.dxs" +"SaInitPeim.inf" +"GraphicsInit.h" +"GraphicsInit.c" +"SaDmiPeim.h" +"SaDmiPeim.c" +"PciExpressInit.h" +"PciExpressInit.c" +"PcieTraining.c" +"PcieTraining.h" +"PcieTrainingEqSettings.c" +"PcieTrainingErrorCount.c" +"PcieTrainingLinkRecovery.c" +"PcieTrainingMargining.c" +"PcieTrainingPhase3.c" +"SaOcInit.c" +"SaOcInit.h" +"SwitchableGraphicsInit.c" +"SwitchableGraphicsInit.h" +<endComponent> diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.dxs b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.dxs new file mode 100644 index 0000000..4eedf37 --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.dxs @@ -0,0 +1,49 @@ +/** @file + Dependency expression source file. + +@copyright + Copyright (c) 2009 - 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 a 'Sample Driver' and is licensed as such + under the terms of your license agreement with Intel or your + vendor. This file may be modified by the user, subject to + the additional terms of the license agreement + +**/ + + +// +// Common for R8 and R9 codebase +// +#include "AutoGen.h" +#include "PeimDepex.h" + +// +// BUILD_WITH_GLUELIB and BUILD_WITH_EDKII_GLUE_LIB are both "defined" in R8 codebase; +// BUILD_WITH_EDKII_GLUE_LIB is defined in Edk-Dev-Snapshot-20070228 and later version +// BUILD_WITH_GLUELIB and BUILD_WITH_EDKII_GLUE_LIB are "not defined" in R9 codebase. +// +#if defined (BUILD_WITH_GLUELIB) || defined (BUILD_WITH_EDKII_GLUE_LIB) +#include "EfiDepex.h" +#endif + +#include EFI_PPI_DEPENDENCY (SaPlatformPolicy) +#include EFI_PPI_DEPENDENCY (CpuPlatformPolicy) +#include EFI_PPI_DEPENDENCY (PchInit) +#include EFI_PPI_DEPENDENCY (Stall) +#include EFI_PPI_DEPENDENCY (PchMeUma) + +DEPENDENCY_START + SA_PLATFORM_POLICY_PPI_GUID AND + PCH_INIT_PPI_GUID AND + PEI_STALL_PPI_GUID AND + PEI_CPU_PLATFORM_POLICY_PPI_GUID + AND PCH_ME_UMA_PPI_GUID +DEPENDENCY_END diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.h b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.h new file mode 100644 index 0000000..2f3263c --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.h @@ -0,0 +1,260 @@ +/** @file + Header file for the SA Init PEIM + +@copyright + Copyright (c) 1999 - 2012 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 +**/ +#ifndef _SA_INIT_PEIM_H_ +#define _SA_INIT_PEIM_H_ + +/// +/// External include files do NOT need to be explicitly specified in real EDKII +/// environment +/// +#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000) +#include "EdkIIGluePeim.h" +#include "SaAccess.h" +#include "MemInfoHob.h" +#include "CpuRegs.h" +#include "CpuPlatformLib.h" +#include "SaOcInit.h" + +#include EFI_PPI_DEPENDENCY (SaPlatformPolicy) +#include EFI_PPI_DEPENDENCY (CpuPlatformPolicy) +#include EFI_PPI_PRODUCER (SaPeiInit) +#include EFI_GUID_DEFINITION (SaDataHob) +#endif +/// +/// Data definitions & structures +/// + +EFI_GUID gMemoryInitHobGuid = EFI_PEI_PERMANENT_MEMORY_INSTALLED_PPI_GUID; + +/// +/// Functions +/// +EFI_STATUS +EFIAPI +SaInitPeiEntryPoint ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +/** + SA PEI Initialization. + + @param[in] FfsHeader - Pointer to Firmware File System file header. + @param[in] PeiServices - General purpose services available to every PEIM. + + @retval EFI_SUCCESS +**/ +; + +VOID +ProgramSaBars ( + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +/** + Programs Sa Bars + + @param[in] SaPlatformPolicyPpi - Instance of SA_PLATFORM_POLICY_PPI +**/ +; + +VOID +SwitchableGraphicsInit ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +/** + SwitchableGraphicsInit: Initialize the Switchable Graphics if enabled + + @param[in] PeiServices - Pointer to the PEI services table + @param[in] SaPlatformPolicyPpi - SaPlatformPolicyPpi to access the SgConfig related information +**/ +; + +VOID +EarlyBiosPostProgramming ( + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +/** + Do Early BIOS POST Programming + + @param[in] SaPlatformPolicyPpi - Instance of SA_PLATFORM_POLICY_PPI +**/ +; + +VOID +GraphicsInit ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +/** + 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 +**/ +; + +EFI_STATUS +SaDmiTcVcInit ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +/** + Initialize DMI Tc/Vc mapping through SA-PCH. + + @param[in] PeiServices - General purpose services available to every PEIM. + @param[in] SaPlatformPolicyPpi - SaPlatformPolicyPpi to access the GtConfig related information + + @retval EFI_SUCCESS +**/ +; + +#ifdef DMI_FLAG +EFI_STATUS +DmiInit ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +/** + Initialize DMI. + + @param[in] PeiServices - General purpose services available to every PEIM. + @param[in] SaPlatformPolicyPpi - SaPlatformPolicyPpi to access the GtConfig related information + + @retval EFI_SUCCESS +**/ +; +#endif // DMI_FLAG + +#ifdef PEG_FLAG +VOID +PciExpressInit ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +/** + 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 +**/ +; +#endif // PEG_FLAG + +EFI_STATUS +InstallSaHob ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +/** + Init and Install SA Hob + + @param[in] PeiServices - General purpose services available to every PEIM. + @param[in] SaPlatformPolicyPpi - SaPlatformPolicyPpi to access the GtConfig related information + + @retval EFI_SUCCESS +**/ +; + +EFI_STATUS +ReportPcieVersion ( + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +/** + Report the SA PCIe initialization code version. + + @param[in] SaPlatformPolicyPpi - Instance of SA_PLATFORM_POLICY_PPI + + @retval EFI_SUCCESS +**/ +; + +STATIC +EFI_STATUS +SaResetComplete ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc, + IN VOID *Ppi + ) +/** + BIOS_CPL_BIT is set for processor to activate the power and thermal management + features on the platform. + + @param[in] PeiServices - Pointer to PEI Services Table. + @param[in] NotifyDesc - Pointer to the descriptor for the Notification event that + caused this function to execute. + @param[in] Ppi - Pointer to the PPI data associated with this function. + + @retval EFI_SUCCESS +**/ +; + +VOID +SaPeiPolicyDump ( + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +/** + This function prints the PEI phase platform policy. + + @param[in] SaPlatformPolicyPpi - Instance of SA_PLATFORM_POLICY_PPI +**/ +; + +static +EFI_STATUS +SaS3ResumeAtEndOfPei ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc, + IN VOID *Ppi + ) +/** + This function handles SA S3 resume task + + @param[in] PeiServices - Pointer to PEI Services Table. + @param[in] NotifyDesc - Pointer to the descriptor for the Notification event that + caused this function to execute. + @param[in] Ppi - Pointer to the PPI data associated with this function. + + @retval EFI_STATUS - Always return EFI_SUCCESS +**/ +; + +#ifdef RAPID_START_FLAG +static +EFI_STATUS +SaCheckRapidStartMode ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc, + IN VOID *Ppi + ) +/** + This function will check Rapid Start mode and install SaS3Resume callback notify if it was Rapid Start Resume + + @param[in] PeiServices - Pointer to PEI Services Table. + @param[in] NotifyDesc - Pointer to the descriptor for the Notification event that + caused this function to execute. + @param[in] Ppi - Pointer to the PPI data associated with this function. + + @retval EFI_STATUS - Always return EFI_SUCCESS +**/ +; +#endif // RAPID_START_FLAG + +#endif diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.inf b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.inf new file mode 100644 index 0000000..8ca75a4 --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.inf @@ -0,0 +1,132 @@ +## @file +# Component description file for the SA Init PEIM. +# +#@copyright +# Copyright (c) 2010 - 2014 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 a 'Sample Driver' and is licensed as such +# under the terms of your license agreement with Intel or your +# vendor. This file may be modified by the user, subject to +# the additional terms of the license agreement +# + +[defines] +BASE_NAME = SaInitPeim +FILE_GUID = FD236AE7-0791-48c4-B29E-29BDEEE1A811 +COMPONENT_TYPE = PE32_PEIM + +[sources.common] + SaInitPeim.h + SaInitPeim.c + GraphicsInit.h + GraphicsInit.c + SaDmiPeim.h + SaDmiPeim.c + PciExpressInit.h + PciExpressInit.c + SwitchableGraphicsInit.c + SwitchableGraphicsInit.h + PcieTraining.h + PcieTraining.c + PcieTrainingEqSettings.c + PcieTrainingErrorCount.c + PcieTrainingMargining.c + PcieTrainingLinkRecovery.c + PcieTrainingPhase3.c + SaOcInit.h + SaOcInit.c +# +# Edk II Glue Driver Entry Point +# + EdkIIGluePeimEntryPoint.c + + +[includes.common] + . + ../Common + $(EDK_SOURCE)/Foundation/Efi + $(EDK_SOURCE)/Foundation/Include + $(EDK_SOURCE)/Foundation/Efi/Include + $(EDK_SOURCE)/Foundation/Framework/Include + $(EFI_SOURCE)/$(PROJECT_SA_ROOT) + $(EFI_SOURCE)/$(PROJECT_SA_ROOT)/Include + $(EFI_SOURCE)/$(PROJECT_RAPID_START_ROOT) + $(EFI_SOURCE)/$(PROJECT_CPU_ROOT)/Library + $(EFI_SOURCE)/$(PROJECT_CPU_ROOT)/Library/OverclockingLib + +# +# EDK II Glue Library utilizes some standard headers from EDK +# + $(EFI_SOURCE) + $(EFI_SOURCE)/$(PROJECT_PCH_ROOT) + $(EDK_SOURCE)/Foundation + $(EDK_SOURCE)/Foundation/Framework + $(EDK_SOURCE)/Foundation/Include/IndustryStandard + $(EDK_SOURCE)/Foundation/Core/Dxe + $(EDK_SOURCE)/Foundation/Include/Pei + $(EDK_SOURCE)/Foundation/Library/Pei/Include + $(EDK_SOURCE)/Foundation/Library/Dxe/Include + $(EDK_SOURCE)/Foundation/Library/EdkIIGlueLib/Include + $(EDK_SOURCE)/Foundation/Library/EdkIIGlueLib/Include/Library + $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)/Include + $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)/Include/Library + $(EDK_SOURCE)/Foundation/Library/EdkIIGlueLib/Include/Pcd + $(EDK_SOURCE)/Foundation/Cpu/Pentium/Include + $(EFI_SOURCE)/$(PROJECT_SA_ROOT)/$(PROJECT_SA_MRC)/Pei/Source/Api + $(EFI_SOURCE)/$(PROJECT_SA_ROOT)/$(PROJECT_SA_MRC)/Pei/Source/Include + $(EFI_SOURCE)/$(PROJECT_SA_ROOT)/$(PROJECT_SA_MRC)/Pei/Source/Include/MrcRegisters + $(EFI_SOURCE)/$(PROJECT_SA_ROOT)/$(PROJECT_SA_MRC)/Pei + $(EFI_SOURCE)/$(PROJECT_CPU_ROOT) + $(EFI_SOURCE)/$(PROJECT_CPU_ROOT)/Include + $(EFI_SOURCE)/$(PROJECT_CPU_ROOT)/Include/Library + $(EFI_SOURCE)/$(PROJECT_ME_ROOT) + $(EFI_SOURCE)/$(PROJECT_ME_ROOT)/PchMeUma + +[libraries.common] + $(PROJECT_PCH_FAMILY)PpiLib + EdkFrameworkPpiLib + EdkIIGlueBaseIoLibIntrinsic + EdkIIGlueBaseMemoryLib + EdkIIGluePeiDebugLibReportStatusCode + EdkIIGluePeiReportStatusCodeLib + EdkIIGluePeiServicesLib + EdkIIGluePeiMemoryAllocationLib + EdkIIGlueBasePciExpressLib + EdkIIGlueBasePostCodeLibPort80 + PeiLib + $(PROJECT_SA_FAMILY)PpiLib + SAGuidLib + EdkPpiLib + CpuPpiLib + CpuPlatformLib + EdkIIGluePeiHobLib + PchPlatformLib + OverclockingLib + MeLibPpi +# +# Uncomment all the RapidStart include directories and library if RapidStart is supported +# +# RapidStartPpiLib + + +[nmake.common] + IMAGE_ENTRY_POINT = _ModuleEntryPoint + DPX_SOURCE = SaInitPeim.dxs +# +# Module Entry Point +# + C_FLAGS = $(C_FLAGS) -D __EDKII_GLUE_MODULE_ENTRY_POINT__=SaInitPeiEntryPoint + C_FLAGS = $(C_FLAGS) -D __EDKII_GLUE_BASE_IO_LIB_INTRINSIC__ \ + -D __EDKII_GLUE_BASE_MEMORY_LIB__ \ + -D __EDKII_GLUE_PEI_DEBUG_LIB_REPORT_STATUS_CODE__ \ + -D __EDKII_GLUE_PEI_REPORT_STATUS_CODE_LIB__ \ + -D __EDKII_GLUE_PEI_SERVICES_LIB__ \ + -D __EDKII_GLUE_PEI_MEMORY_ALLOCATION_LIB__ \ + -D __EDKII_GLUE_BASE_PCI_LIB_PCI_EXPRESS__ diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.mak b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.mak new file mode 100644 index 0000000..935d761 --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.mak @@ -0,0 +1,72 @@ +#--------------------------------------------------------------------------- +# Create SaInitPeim module +#--------------------------------------------------------------------------- +all : SaInitPeim +SaInitPeim : $(BUILD_DIR)\SaInitPeim.mak SaInitPeimBin + +$(BUILD_DIR)\SaInitPeim.mak : $(SaInitPeim_DIR)\$(@B).cif $(SaInitPeim_DIR)\$(@B).mak $(BUILD_RULES) + $(CIF2MAK) $(SaInitPeim_DIR)\$(@B).cif $(CIF2MAK_DEFAULTS) + +SaInitPeim_INCLUDES=\ + $(INTEL_MCH_INCLUDES)\ + $(INTEL_PCH_INCLUDES)\ + $(EdkIIGlueLib_INCLUDES)\ + $(PROJECT_CPU_INCLUDES)\ + $(RAPIDSTART_INCLUDES)\ + $(PchMeUma_INCLUDES)\ + /I$(PROJECT_CPU_ROOT)\Library\OverclockingLib \ + +SaInitPeim_DEFINES = $(MY_DEFINES)\ + /D"__EDKII_GLUE_MODULE_ENTRY_POINT__=SaInitPeiEntryPoint"\ + /D __EDKII_GLUE_BASE_LIB__ \ + /D __EDKII_GLUE_BASE_MEMORY_LIB__ \ + /D __EDKII_GLUE_BASE_IO_LIB_INTRINSIC__ \ + /D __EDKII_GLUE_PEI_DEBUG_LIB_REPORT_STATUS_CODE__ \ + /D __EDKII_GLUE_PEI_REPORT_STATUS_CODE_LIB__ \ + /D __EDKII_GLUE_PEI_SERVICES_LIB__ \ + /D __EDKII_GLUE_PEI_MEMORY_ALLOCATION_LIB__ \ + /D __EDKII_GLUE_BASE_PCI_LIB_PCI_EXPRESS__ \ + +SaInitPeim_LIB_LINKS =\ + $(INTEL_SA_PPI_LIB) \ + $(IntelPchPpiLib_LIB)\ + $(EDKFRAMEWORKPPILIB) \ + $(EdkIIGlueBaseLib_LIB)\ + $(EdkIIGlueBaseLibIA32_LIB)\ + $(EdkIIGlueBaseIoLibIntrinsic_LIB) \ + $(EdkIIGluePeiDebugLibReportStatusCode_LIB) \ + $(EdkIIGluePeiReportStatusCodeLib_LIB) \ + $(EdkIIGluePeiServicesLib_LIB) \ + $(EdkIIGluePeiMemoryAllocationLib_LIB) \ + $(EdkIIGlueBasePciLibPciExpress_LIB) \ + $(EdkIIGlueBasePciExpressLib_LIB)\ + $(PEILIB)\ + $(SaGuidLib_LIB)\ + $(EdkIIGlueBasePciExpressLib_LIB)\ + $(EdkIIGlueBasePostCodeLibPort80_LIB)\ + $(CPU_PPI_LIB)\ + $(CpuPlatformLib_LIB)\ + $(PchPlatformPeiLib_LIB)\ + $(EdkIIGluePeiHobLib_LIB)\ + $(OcPlatformLib_LIB)\ +# +# Uncomment all the RapidStart include directories and library if RapidStart is supported +# +# RapidStartPpiLib + $(RapidStartPpiLib_LIB)\ + $(MeLibPpi_LIB) + +SaInitPeimBin: $(SaInitPeim_LIB_LINKS) + $(MAKE) /$(MAKEFLAGS) $(EDKIIGLUE_DEFAULTS)\ + /f $(BUILD_DIR)\SaInitPeim.mak all \ + "MY_INCLUDES=$(SaInitPeim_INCLUDES)"\ + "MY_DEFINES=$(SaInitPeim_DEFINES)"\ + NAME=SaInitPeim\ + MAKEFILE=$(BUILD_DIR)\SaInitPeim.mak \ + GUID=FD236AE7-0791-48c4-B29E-29BDEEE1A811\ + ENTRY_POINT=_ModuleEntryPoint \ + TYPE=PEIM \ + EDKIIModule=PEIM\ + DEPEX1=$(SaInitPeim_DIR)\SaInitPeim.dxs\ + DEPEX1_TYPE=EFI_SECTION_PEI_DEPEX\ + COMPRESS=0 diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.sdl b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.sdl new file mode 100644 index 0000000..38ceadb --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.sdl @@ -0,0 +1,39 @@ +TOKEN + Name = "SaInitPeim_SUPPORT" + Value = "1" + Help = "Main switch to enable SaInitPeim support in Project" + TokenType = Boolean + TargetEQU = Yes + TargetMAK = Yes + Master = Yes +End + +TOKEN + Name = "SA_DEBUG_INFO" + Value = "1" + TokenType = Boolean + Range = "0-1 " + TargetMAK = Yes +End + +ELINK + Name = "/D SA_DEBUG_FLAG" + Parent = "INTEL_SA_RC_FLAGS" + Token = "SA_DEBUG_INFO" "=" "1" + InvokeOrder = AfterParent +End + +PATH + Name = "SaInitPeim_DIR" +End + +MODULE + File = "SaInitPeim.mak" + Help = "Includes SaInitPeim.mak to Project" +End + +ELINK + Name = "$(BUILD_DIR)\SaInitPeim.ffs" + Parent = "FV_BB" + InvokeOrder = AfterParent +End diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaOcInit.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaOcInit.c new file mode 100644 index 0000000..80a1ffb --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaOcInit.c @@ -0,0 +1,189 @@ +/** @file + OC System Agent Early Post initializations. + +@copyright + Copyright (c) 2011 - 2012 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 +**/ + +/// +/// External include files do NOT need to be explicitly specified in real EDKII +/// environment +/// +#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000) +#include "EdkIIGluePeim.h" +#include "SaOcInit.h" +#endif + +EFI_STATUS +SaOcInit ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +/** + Initializes Overclocking settings in the processor. + + @param[in] PeiServices - General purpose services available to every PEIM. + @param[in] OverclockingtConfig Pointer to Policy protocol instance + + @retval EFI_SUCCESS +**/ +{ + EFI_STATUS Status; + OC_CAPABILITIES_ITEM OcCaps; + VOLTAGE_FREQUENCY_ITEM CurrentVfItem; + VOLTAGE_FREQUENCY_ITEM RequestedVfItem; + UINT32 LibStatus; + UINT8 DomainId; + BOOLEAN VfUpdateNeeded; + WDT_PPI *gWdtPei; + + LibStatus = 0; + VfUpdateNeeded = FALSE; + + if (SaPlatformPolicyPpi->OcConfig->OcSupport == 0){ + /// + /// Overclocking is disabled + /// + DEBUG ((EFI_D_ERROR, "(OC) Overclocking is disabled. Bypassing SA overclocking flow.\n")); + return EFI_SUCCESS; + } + + Status = EFI_SUCCESS; + ZeroMem(&CurrentVfItem,sizeof(CurrentVfItem)); + ZeroMem(&RequestedVfItem,sizeof(RequestedVfItem)); + + // + // Locate WDT_PPI (ICC WDT PPI) + // + Status = PeiServicesLocatePpi ( + &gWdtPpiGuid, + 0, + NULL, + (VOID **) &gWdtPei + ); + ASSERT_EFI_ERROR (Status); + + /// + /// We will loop on the CPU domains to manage the voltage/frequency settings + /// + for (DomainId = OC_LIB_DOMAIN_ID_GT; DomainId <= OC_LIB_DOMAIN_ID_IOD; DomainId++) { + /// + /// Only GT, Uncore, IOA, and IOD are valid for System Agent + /// + if ((DomainId == OC_LIB_DOMAIN_ID_GT) ||(DomainId == OC_LIB_DOMAIN_ID_UNCORE) || + (DomainId == OC_LIB_DOMAIN_ID_IOA) || (DomainId == OC_LIB_DOMAIN_ID_IOD)){ + /// + /// Get OC Capabilities of the domain + /// + ZeroMem(&OcCaps,sizeof(OcCaps)); + OcCaps.DomainId = DomainId; + Status = GetOcCapabilities(&OcCaps,&LibStatus); + + if (LibStatus == OC_LIB_COMPLETION_CODE_SUCCESS){ + /// + /// If any OC is supported on this domain, then proceed + /// + if (OcCaps.RatioOcSupported || OcCaps.VoltageOverridesSupported || OcCaps.VoltageOffsetSupported){ + /// + /// Need to populate the user requested settings from the platform policy + /// to determine if OC changes are desired. + /// + ZeroMem(&CurrentVfItem,sizeof(CurrentVfItem)); + CurrentVfItem.DomainId = DomainId; + + /// + /// Get a copy of the current domain VfSettings from the Mailbox Library + /// + Status = GetVoltageFrequencyItem(&CurrentVfItem,&LibStatus); + if ((Status != EFI_SUCCESS) || (LibStatus != OC_LIB_COMPLETION_CODE_SUCCESS)){ + continue; + } + + /// + /// Populate the user requested VfSettings struct + /// + ZeroMem(&RequestedVfItem,sizeof(RequestedVfItem)); + RequestedVfItem.DomainId = DomainId; + if (DomainId == OC_LIB_DOMAIN_ID_GT){ + RequestedVfItem.VfSettings.MaxOcRatio = (UINT8) SaPlatformPolicyPpi->OcConfig->GtMaxOcTurboRatio; + + /// + /// VoltageTarget has 2 uses and we need to update the target based + /// on the voltagemode requested + /// + RequestedVfItem.VfSettings.VoltageTargetMode = SaPlatformPolicyPpi->OcConfig->GtVoltageMode; + if (RequestedVfItem.VfSettings.VoltageTargetMode == OC_LIB_OFFSET_ADAPTIVE){ + RequestedVfItem.VfSettings.VoltageTarget = SaPlatformPolicyPpi->OcConfig->GtExtraTurboVoltage; + } + else { + RequestedVfItem.VfSettings.VoltageTarget = SaPlatformPolicyPpi->OcConfig->GtVoltageOverride; + } + RequestedVfItem.VfSettings.VoltageOffset = SaPlatformPolicyPpi->OcConfig->GtVoltageOffset; + + VfUpdateNeeded = (BOOLEAN)CompareMem((VOID*)&RequestedVfItem,(VOID*)&CurrentVfItem,sizeof(VOLTAGE_FREQUENCY_ITEM)); + } + else if ((DomainId == OC_LIB_DOMAIN_ID_UNCORE) || (DomainId == OC_LIB_DOMAIN_ID_IOA) || (DomainId == OC_LIB_DOMAIN_ID_IOD)){ + /// + /// Uncore,IOA, and IOD domains only supports voltage offset, other settings are ignored + /// + switch (DomainId) { + case OC_LIB_DOMAIN_ID_UNCORE: + RequestedVfItem.VfSettings.VoltageOffset = SaPlatformPolicyPpi->OcConfig->SaVoltageOffset; + break; + + case OC_LIB_DOMAIN_ID_IOA: + RequestedVfItem.VfSettings.VoltageOffset = SaPlatformPolicyPpi->OcConfig->IoaVoltageOffset; + break; + + case OC_LIB_DOMAIN_ID_IOD: + RequestedVfItem.VfSettings.VoltageOffset = SaPlatformPolicyPpi->OcConfig->IodVoltageOffset; + break; + } + + if (RequestedVfItem.VfSettings.VoltageOffset != CurrentVfItem.VfSettings.VoltageOffset) + VfUpdateNeeded = TRUE; + } + + if (VfUpdateNeeded){ + VfUpdateNeeded = FALSE; + + /// + /// Arm watchdog timer for OC changes + /// + Status = gWdtPei->ReloadAndStart (WDT_TIMEOUT_BETWEEN_PEI_DXE); + + /// + /// Need to update the requested voltage/frequency values + /// + Status = SetVoltageFrequencyItem(RequestedVfItem,&LibStatus); + if ((Status != EFI_SUCCESS) || (LibStatus != OC_LIB_COMPLETION_CODE_SUCCESS)){ + DEBUG ((EFI_D_ERROR, "(OC) Set Voltage Frequency failed. EFI Status = %X, Library Status = %X\n", Status, LibStatus)); + } + } + } + else { + DEBUG ((EFI_D_INFO, "(OC) No OC support for this Domain = %X\n", DomainId)); + } + } + else { + DEBUG ((EFI_D_ERROR, "(OC) GetOcCapabilities message failed. Library Status = %X, Domain = %X\n", LibStatus, DomainId)); + } + } + } + + return Status; +} diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaOcInit.h b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaOcInit.h new file mode 100644 index 0000000..0ebff94 --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaOcInit.h @@ -0,0 +1,56 @@ +/** @file + Describes the functions visible to the rest of the OcInit. + +@copyright + Copyright (c) 2011 - 2012 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 +**/ +#ifndef _SA_INIT_H_ +#define _SA_INIT_H_ + +#include "OverclockingLibrary.h" +#include EFI_PPI_DEPENDENCY (CpuPlatformPolicy) +#include EFI_PPI_DEPENDENCY (SaPlatformPolicy) +#include EFI_PPI_CONSUMER (Wdt) + +#ifdef USE_WDT_IN_DEBUG_BIOS +// +// MRC takes a lot of time to execute in debug mode +// +#define WDT_TIMEOUT_BETWEEN_PEI_DXE 120 +#else +#define WDT_TIMEOUT_BETWEEN_PEI_DXE 60 +#endif + +/// +/// Function Prototypes +/// +EFI_STATUS +SaOcInit ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +/** + Initializes Overclocking settings in the processor. + + @param[in] PeiServices - General purpose services available to every PEIM. + @param[in] OverclockingtConfig Pointer to Policy protocol instance + + @retval EFI_SUCCESS +**/ +; + +#endif diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SwitchableGraphicsInit.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SwitchableGraphicsInit.c new file mode 100644 index 0000000..cbb8748 --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SwitchableGraphicsInit.c @@ -0,0 +1,288 @@ +/** @file + SwitchableGraphics Pei driver. + This Pei driver initialize GPIO programming + for the platform. + +@copyright + Copyright (c) 2010 - 2012 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 "SwitchableGraphicsInit.h" +#include EFI_GUID_DEFINITION (SaDataHob) + +#ifdef SG_SUPPORT + +/** + Initialize the SwitchableGraphics support (PEI). + + @param[in] PeiServices - Pointer to the PEI services table + @param[in] SaPlatformPolicyPpi - SaPlatformPolicyPpi to access the GtConfig related information +**/ +VOID +SwitchableGraphicsInit ( + IN EFI_PEI_SERVICES **PeiServices, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +{ + EFI_STATUS Status; + PEI_STALL_PPI *StallPpi; + EFI_GUID StallPpiGuid = PEI_STALL_PPI_GUID; + UINT16 GpioAddress; + SA_DATA_HOB *SaDataHob; + BOOLEAN SgDgpuPrsntGpioIsValid = TRUE; + CPU_FAMILY CpuFamilyId; + + CpuFamilyId = GetCpuFamily(); + + /// + /// Get SaDataHob HOB + /// + SaDataHob = NULL; + SaDataHob = (SA_DATA_HOB *) GetFirstGuidHob (&gSaDataHobGuid); + + if (SaDataHob != NULL) { + SaDataHob->SgInfo.SgMode = SaPlatformPolicyPpi->PlatformData->SgMode; + SaDataHob->SgInfo.PXFixedDynamicMode = SaPlatformPolicyPpi->PlatformData->PXFixedDynamicMode; // AMI_OVERRIDE_FOR ATI 5.0 Fixed/Dynamic + + /// + /// GPIO Assigned from policy + /// + SaDataHob->SgInfo.SgGpioSupport = SaPlatformPolicyPpi->SgGpioData->GpioSupport; + + if (SaPlatformPolicyPpi->SgGpioData->GpioSupport == 1) { + /// + /// Get GPIO Base Address + /// + GpioAddress = MmPci16 (0, 0, PCI_DEVICE_NUMBER_PCH_LPC, 0, R_PCH_LPC_GPIO_BASE) &~BIT0; + + SaDataHob->SgInfo.SgDgpuPwrOK = SaPlatformPolicyPpi->SgGpioData->SgDgpuPwrOK->Value; + SaDataHob->SgInfo.SgDgpuHoldRst = SaPlatformPolicyPpi->SgGpioData->SgDgpuHoldRst->Value; + SaDataHob->SgInfo.SgDgpuPwrEnable = SaPlatformPolicyPpi->SgGpioData->SgDgpuPwrEnable->Value; + SaDataHob->SgInfo.SgDgpuPrsnt = SaPlatformPolicyPpi->SgGpioData->SgDgpuPrsnt->Value; + + /// + /// Set Bit7 as indicator for GPIO Active Low/High + /// + SaDataHob->SgInfo.SgDgpuPwrOK |= (SaPlatformPolicyPpi->SgGpioData->SgDgpuPwrOK->Active << 7); + SaDataHob->SgInfo.SgDgpuHoldRst |= (SaPlatformPolicyPpi->SgGpioData->SgDgpuHoldRst->Active << 7); + SaDataHob->SgInfo.SgDgpuPwrEnable |= (SaPlatformPolicyPpi->SgGpioData->SgDgpuPwrEnable->Active << 7); + SaDataHob->SgInfo.SgDgpuPrsnt |= (SaPlatformPolicyPpi->SgGpioData->SgDgpuPrsnt->Active << 7); + + if (CpuFamilyId == EnumCpuHswUlt) { + PEI_DEBUG ((PeiServices, EFI_D_INFO, "SgDgpuPrsntGpioIsValid = FALSE\n")); + SgDgpuPrsntGpioIsValid = FALSE; + } + + /// + /// Locate PPI stall service + /// + Status = (**PeiServices).LocatePpi ( + PeiServices, + &StallPpiGuid, + 0, + NULL, + &StallPpi + ); + if (!EFI_ERROR (Status)) { + /// + /// if DGPU PRSNT is Disabled, it means that MXM card was not detected, and + /// DGPU HOLD RST must be driven high to allow the board to support a normal PEG card + /// + if ( (SgDgpuPrsntGpioIsValid) + && (GpioRead (PeiServices, CpuFamilyId, GpioAddress, SaDataHob->SgInfo.SgDgpuPrsnt) == GP_DISABLE)) { + GpioWrite (PeiServices, CpuFamilyId, GpioAddress, SaDataHob->SgInfo.SgDgpuHoldRst, GP_DISABLE); + /// + /// Set SG mode as disabled + /// + SaDataHob->SgInfo.SgMode = SgModeDisabled; + } else { + /// + /// DGPU PRSNT Enabled. MXM is present. + /// If PEG Mode or SG Muxless + /// Power on MXM + /// Configure GPIOs to drive MXM in PEG mode or SG Muxless + /// else + /// Do Nothing + /// + if ((SaPlatformPolicyPpi->PlatformData->SgMode == SgModeMuxless) || + (SaPlatformPolicyPpi->PlatformData->SgMode == SgModeDgpu)) { + PEI_DEBUG ((PeiServices, EFI_D_INFO, "Configure GPIOs for driving the dGPU.\n")); + /// + /// Drive DGPU HOLD RST Enable to make sure we hold reset + /// + GpioWrite (PeiServices, CpuFamilyId, GpioAddress, SaDataHob->SgInfo.SgDgpuHoldRst, GP_ENABLE); + /// + /// wait 100ms + /// + StallPpi->Stall ( + PeiServices, + StallPpi, + SG_DELAY_HOLD_RST + ); + + /// + /// Drive DGPU PWR EN to Power On MXM + /// + GpioWrite (PeiServices, CpuFamilyId, GpioAddress, SaDataHob->SgInfo.SgDgpuPwrEnable, GP_ENABLE); + + /// + /// wait 300ms + /// + StallPpi->Stall ( + PeiServices, + StallPpi, + SG_DELAY_PWR_ENABLE + ); + + /// + /// Drive DGPU HOLD RST Disabled to remove reset + /// + GpioWrite (PeiServices, CpuFamilyId, GpioAddress, SaDataHob->SgInfo.SgDgpuHoldRst, GP_DISABLE); + + /// + /// wait 100ms + /// + StallPpi->Stall ( + PeiServices, + StallPpi, + SG_DELAY_HOLD_RST + ); + } + } + } + } + } + /// + /// Program SubsystemID for IGFX + /// + PEI_DEBUG ((PeiServices, EFI_D_INFO, "Program SDID [Subsystem ID] for IGFX: 0x%x\n", SaPlatformPolicyPpi->PlatformData->SgSubSystemId)); + McD2PciCfg16Or (PCI_SID, SaPlatformPolicyPpi->PlatformData->SgSubSystemId); + +} + +/** + SG GPIO Read + + @param[in] PeiServices - General purpose services available to every PEIM + @param[in] CpuFamilyId - Specifies the CPU family + @param[in] GpioAddress - GPIO base address + @param[in] Value - PCH GPIO number + + @retval GPIO read value (0/1) +**/ +BOOLEAN +GpioRead ( + EFI_PEI_SERVICES **PeiServices, + CPU_FAMILY CpuFamilyId, + IN UINT16 GpioAddress, + IN UINT8 Value + ) +{ + BOOLEAN Active; + UINT16 BitOffset=0; + UINT32 Data; + + Active = (BOOLEAN) (Value >> 7); + Value &= 0x7F; + + ASSERT (GpioAddress != 0); + + if (CpuFamilyId == EnumCpuHswUlt) { + GpioAddress += R_PCH_GP_N_CONFIG0 + (Value * 0x08); + BitOffset = 30; //GPI_LVL + } else { + if (Value < 0x20) { + GpioAddress += R_PCH_GPIO_LVL; + BitOffset = Value; + } else if (Value < 0x40) { + GpioAddress += R_PCH_GPIO_LVL2; + BitOffset = Value - 0x20; + } else { + GpioAddress += R_PCH_GPIO_LVL3; + BitOffset = Value - 0x40; + } + } + + Data = IoRead32 (GpioAddress); + Data >>= BitOffset; + + if (Active == 0) { + Data = ~Data; + } + + return (BOOLEAN) (Data & 0x1); +} + +/** + SG GPIO Write + + @param[in] PeiServices - General purpose services available to every PEIM + @param[in] CpuFamilyId - Specifies the CPU family + @param[in] GpioAddress - GPIO base address + @param[in] Value - PCH GPIO number + @param[in] Level - Write SG GPIO value (0/1) + + @retval none +**/ +VOID +GpioWrite ( + EFI_PEI_SERVICES **PeiServices, + CPU_FAMILY CpuFamilyId, + IN UINT16 GpioAddress, + IN UINT8 Value, + IN BOOLEAN Level + ) +{ + BOOLEAN Active; + UINT32 Data; + UINT16 BitOffset=0; + + Active = (BOOLEAN) (Value >> 7); + Value &= 0x7F; + + if (Active == 0) { + Level = (~Level) & 0x1; + } + + ASSERT (GpioAddress != 0); + + if (CpuFamilyId == EnumCpuHswUlt) { + GpioAddress += R_PCH_GP_N_CONFIG0 + (Value * 0x08); + BitOffset = 31; //GPO_LVL + } else { + if (Value < 0x20) { + GpioAddress += R_PCH_GPIO_LVL; + BitOffset = Value; + } else if (Value < 0x40) { + GpioAddress += R_PCH_GPIO_LVL2; + BitOffset = Value - 0x20; + } else { + GpioAddress += R_PCH_GPIO_LVL3; + BitOffset = Value - 0x40; + } + } + + Data = IoRead32 (GpioAddress); + Data &= ~(0x1 << BitOffset); + Data |= (Level << BitOffset); + + IoWrite32 (GpioAddress, Data); + return ; +} + +#endif //SG_SUPPORT
\ No newline at end of file diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SwitchableGraphicsInit.h b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SwitchableGraphicsInit.h new file mode 100644 index 0000000..7126b19 --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SwitchableGraphicsInit.h @@ -0,0 +1,93 @@ +/** @file + Header file for the SwitchableGraphics Pei driver. + +@copyright + Copyright (c) 2010 - 2012 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 +**/ + +#ifndef _SWITCHABLE_GRAPHICS_PEI_H_ +#define _SWITCHABLE_GRAPHICS_PEI_H_ + +#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000) +#include "EdkIIGluePeim.h" +#include "EdkIIGlueIoLib.h" +#endif + +#include "CpuRegs.h" +#include "CpuPlatformLib.h" + +#include "PchAccess.h" +#include "SaAccess.h" + +#include EFI_PPI_DEPENDENCY (SaPlatformPolicy) +#include EFI_PPI_DEPENDENCY (Stall) + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef HIGH +#define HIGH 1 +#endif + +#ifndef LOW +#define LOW 0 +#endif + +#define SG_DELAY_HOLD_RST 100 * STALL_ONE_MILLI_SECOND +#define SG_DELAY_PWR_ENABLE 300 * STALL_ONE_MILLI_SECOND + +/** + SG GPIO Write + + @param[in] PeiServices - General purpose services available to every PEIM + @param[in] CpuFamilyId - Specifies the CPU family + @param[in] GpioAddress - GPIO base address + @param[in] Value - PCH GPIO number + @param[in] Level - Write SG GPIO value (0/1) + + @retval none +**/ +VOID +GpioWrite ( + EFI_PEI_SERVICES **PeiServices, + CPU_FAMILY CpuFamilyId, + IN UINT16 GpioAddress, + IN UINT8 Value, + IN BOOLEAN Level + ) +; + +/** + SG GPIO Read + + @param[in] PeiServices - General purpose services available to every PEIM + @param[in] CpuFamilyId - Specifies the CPU family + @param[in] GpioAddress - GPIO base address + @param[in] Value - PCH GPIO number + + @retval GPIO read value (0/1) +**/ +BOOLEAN +GpioRead ( + EFI_PEI_SERVICES **PeiServices, + CPU_FAMILY CpuFamilyId, + IN UINT16 GpioAddress, + IN UINT8 Value + ) +; +#endif |