summaryrefslogtreecommitdiff
path: root/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PciExpressInit.c
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PciExpressInit.c')
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PciExpressInit.c2987
1 files changed, 2987 insertions, 0 deletions
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