From: "Nhi Pham" <nhi@os.amperecomputing.com>
To: devel@edk2.groups.io
Cc: patches@amperecomputing.com, nhi@os.amperecomputing.com,
vunguyen@os.amperecomputing.com,
Thang Nguyen <thang@os.amperecomputing.com>,
Chuong Tran <chuong@os.amperecomputing.com>,
Phong Vo <phong@os.amperecomputing.com>,
Leif Lindholm <leif@nuviainc.com>,
Michael D Kinney <michael.d.kinney@intel.com>,
Ard Biesheuvel <ardb+tianocore@kernel.org>,
Nate DeSimone <nathaniel.l.desimone@intel.com>
Subject: [edk2-platforms][PATCH v4 12/31] AmpereAltraPkg: Add Ac01PcieLib library instance
Date: Fri, 22 Oct 2021 13:17:50 +0700 [thread overview]
Message-ID: <20211022061809.31087-13-nhi@os.amperecomputing.com> (raw)
In-Reply-To: <20211022061809.31087-1-nhi@os.amperecomputing.com>
From: Vu Nguyen <vunguyen@os.amperecomputing.com>
Provides essential functions to initialize the PCIe Root Complex on
Ampere Altra processor.
Cc: Thang Nguyen <thang@os.amperecomputing.com>
Cc: Chuong Tran <chuong@os.amperecomputing.com>
Cc: Phong Vo <phong@os.amperecomputing.com>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
Signed-off-by: Nhi Pham <nhi@os.amperecomputing.com>
---
Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec | 6 +
Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc | 2 +
Platform/Ampere/JadePkg/Jade.dsc | 5 +
Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/Ac01PcieLib.inf | 42 +
Silicon/Ampere/AmpereAltraPkg/Library/BoardPcieLibNull/BoardPcieLibNull.inf | 25 +
Silicon/Ampere/AmpereAltraPkg/Include/Library/Ac01PcieLib.h | 49 +
Silicon/Ampere/AmpereAltraPkg/Include/Library/BoardPcieLib.h | 45 +
Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.h | 451 +++++++
Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.c | 1391 ++++++++++++++++++++
Silicon/Ampere/AmpereAltraPkg/Library/BoardPcieLibNull/BoardPcieLibNull.c | 47 +
10 files changed, 2063 insertions(+)
diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
index e19925c68a0e..7bd4d3ac9462 100644
--- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
@@ -43,6 +43,12 @@ [LibraryClasses]
## @libraryclass Defines a set of methods to access flash memory.
FlashLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h
+ ## @libraryclass Defines a set of platform dependent functions
+ BoardPcieLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/BoardPcieLib.h
+
+ ## @libraryclass Defines a set of methods to initialize Pcie
+ Ac01PcieLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/Ac01PcieLib.h
+
[Guids]
## NVParam MM GUID
gNVParamMmGuid = { 0xE4AC5024, 0x29BE, 0x4ADC, { 0x93, 0x36, 0x87, 0xB5, 0xA0, 0x76, 0x23, 0x2D } }
diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
index c01a8be3c607..a6f7d87769fe 100644
--- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
+++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
@@ -81,6 +81,8 @@ [LibraryClasses.common]
NVParamLib|Silicon/Ampere/AmpereAltraPkg/Library/NVParamLib/NVParamLib.inf
MailboxInterfaceLib|Silicon/Ampere/AmpereAltraPkg/Library/MailboxInterfaceLib/MailboxInterfaceLib.inf
SystemFirmwareInterfaceLib|Silicon/Ampere/AmpereAltraPkg/Library/SystemFirmwareInterfaceLib/SystemFirmwareInterfaceLib.inf
+ PciePhyLib|Silicon/Ampere/AmpereAltraBinPkg/Library/PciePhyLib/PciePhyLib.inf
+ Ac01PcieLib|Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/Ac01PcieLib.inf
AmpereCpuLib|Silicon/Ampere/AmpereAltraPkg/Library/AmpereCpuLib/AmpereCpuLib.inf
TimeBaseLib|EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.inf
I2cLib|Silicon/Ampere/AmpereAltraPkg/Library/DwI2cLib/DwI2cLib.inf
diff --git a/Platform/Ampere/JadePkg/Jade.dsc b/Platform/Ampere/JadePkg/Jade.dsc
index e4b29e36fc8d..23a297d0dbeb 100644
--- a/Platform/Ampere/JadePkg/Jade.dsc
+++ b/Platform/Ampere/JadePkg/Jade.dsc
@@ -82,6 +82,11 @@ [LibraryClasses]
#
AcpiLib|EmbeddedPkg/Library/AcpiLib/AcpiLib.inf
+ #
+ # Pcie Board
+ #
+ BoardPcieLib|Silicon/Ampere/AmpereAltraPkg/Library/BoardPcieLibNull/BoardPcieLibNull.inf
+
################################################################################
#
# Specific Platform Pcds
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/Ac01PcieLib.inf b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/Ac01PcieLib.inf
new file mode 100644
index 000000000000..8c8661265cd5
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/Ac01PcieLib.inf
@@ -0,0 +1,42 @@
+## @file
+#
+# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = Ac01PcieLib
+ FILE_GUID = 8ABFA0FC-313E-11E8-B467-0ED5F89F718B
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = Ac01PcieLib
+
+[Sources]
+ PcieCore.c
+ PcieCore.h
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/Ampere/AmpereAltraBinPkg/AmpereAltraBinPkg.dec
+ Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+
+[LibraryClasses]
+ ArmGenericTimerCounterLib
+ BaseLib
+ BoardPcieLib
+ DebugLib
+ HobLib
+ IoLib
+ PciePhyLib
+ SystemFirmwareInterfaceLib
+ TimerLib
+
+[Guids]
+ gPlatformInfoHobGuid
+
+[Depex]
+ TRUE
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/BoardPcieLibNull/BoardPcieLibNull.inf b/Silicon/Ampere/AmpereAltraPkg/Library/BoardPcieLibNull/BoardPcieLibNull.inf
new file mode 100644
index 000000000000..435092b864ec
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/BoardPcieLibNull/BoardPcieLibNull.inf
@@ -0,0 +1,25 @@
+## @file
+#
+# Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = BoardPcieLibNull
+ FILE_GUID = 7820C925-F525-4101-8E64-87838356B7A6
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = BoardPcieLib
+
+[Sources.common]
+ BoardPcieLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+
+[LibraryClasses]
+ BaseLib
diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Library/Ac01PcieLib.h b/Silicon/Ampere/AmpereAltraPkg/Include/Library/Ac01PcieLib.h
new file mode 100644
index 000000000000..53d3739af713
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Include/Library/Ac01PcieLib.h
@@ -0,0 +1,49 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef AC01_PCIE_LIB_H_
+#define AC01_PCIE_LIB_H_
+
+/**
+ Setup and initialize the AC01 PCIe Root Complex and underneath PCIe controllers
+
+ @param RootComplex Pointer to Root Complex structure
+ @param ReInit Re-init status
+ @param ReInitPcieIndex PCIe index
+
+ @retval RETURN_SUCCESS The Root Complex has been initialized successfully.
+ @retval RETURN_DEVICE_ERROR PHY, Memory or PIPE is not ready.
+**/
+RETURN_STATUS
+Ac01PcieCoreSetupRC (
+ IN AC01_ROOT_COMPLEX *RootComplex,
+ IN BOOLEAN ReInit,
+ IN UINT8 ReInitPcieIndex
+ );
+
+/**
+ Verify the link status and retry to initialize the Root Complex if there's any issue.
+
+ @param RootComplexList Pointer to the Root Complex list
+**/
+VOID
+Ac01PcieCorePostSetupRC (
+ IN AC01_ROOT_COMPLEX *RootComplexList
+ );
+
+/**
+ Callback function when the Host Bridge enumeration end.
+
+ @param RootComplex Pointer to the Root Complex structure
+**/
+VOID
+Ac01PcieCoreEndEnumeration (
+ IN AC01_ROOT_COMPLEX *RootComplex
+ );
+
+#endif /* AC01_PCIE_LIB_H_ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Library/BoardPcieLib.h b/Silicon/Ampere/AmpereAltraPkg/Include/Library/BoardPcieLib.h
new file mode 100644
index 000000000000..34e7dee702ec
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Include/Library/BoardPcieLib.h
@@ -0,0 +1,45 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef BOARD_PCIE_LIB_H_
+#define BOARD_PCIE_LIB_H_
+
+#include <Guid/RootComplexInfoHob.h>
+
+/**
+ Assert PERST of the PCIe controller
+
+ @param[in] RootComplex Root Complex instance.
+ @param[in] PcieIndex PCIe controller index of input Root Complex.
+ @param[in] IsPullToHigh Target status for the PERST.
+
+ @retval RETURN_SUCCESS The operation is successful.
+ @retval Others An error occurred.
+**/
+RETURN_STATUS
+EFIAPI
+BoardPcieAssertPerst (
+ IN AC01_ROOT_COMPLEX *RootComplex,
+ IN UINT8 PcieIndex,
+ IN BOOLEAN IsPullToHigh
+ );
+
+/**
+ Override the segment number for a root complex with a board specific number.
+
+ @param[in] RootComplex Root Complex instance with properties.
+
+ @retval Segment number corresponding to the input root complex.
+ Default segment number is 0x0F.
+**/
+UINT16
+BoardPcieGetSegmentNumber (
+ IN AC01_ROOT_COMPLEX *RootComplex
+ );
+
+#endif /* BOARD_PCIE_LIB_H_ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.h b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.h
new file mode 100644
index 000000000000..f3f15c4c74df
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.h
@@ -0,0 +1,451 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef AC01_PCIE_CORE_H_
+#define AC01_PCIE_CORE_H_
+
+//
+// PCIe config space capabilities offset
+//
+#define PM_CAP 0x40
+#define MSI_CAP 0x50
+#define PCIE_CAP 0x70
+#define MSIX_CAP 0xB0
+#define SLOT_CAP 0xC0
+#define VPD_CAP 0xD0
+#define SATA_CAP 0xE0
+#define CFG_NEXT_CAP 0x40
+#define PM_NEXT_CAP 0x70
+#define MSI_NEXT_CAP 0x00
+#define PCIE_NEXT_CAP 0x00
+#define MSIX_NEXT_CAP 0x00
+#define SLOT_NEXT_CAP 0x00
+#define VPD_NEXT_CAP 0x00
+#define SATA_NEXT_CAP 0x00
+#define BASE_CAP 0x100
+#define AER_CAP 0x100
+#define VC_CAP 0x148
+#define SN_CAP 0x178
+#define PB_CAP 0x178
+#define ARI_CAP 0x178
+#define SPCIE_CAP_x8 0x148
+#define SPCIE_CAP 0x178
+#define PL16G_CAP 0x1A8
+#define MARGIN_CAP 0x1D8
+#define PL32G_CAP 0x220
+#define SRIOV_CAP 0x220
+#define TPH_CAP 0x220
+#define ATS_CAP 0x220
+#define ACS_CAP 0x230
+#define PRS_CAP 0x238
+#define LTR_CAP 0x248
+#define L1SUB_CAP 0x248
+#define PASID_CAP 0x248
+#define DPA_CAP 0x248
+#define DPC_CAP 0x248
+#define MPCIE_CAP 0x248
+#define FRSQ_CAP 0x248
+#define RTR_CAP 0x248
+#define LN_CAP 0x248
+#define RAS_DES_CAP 0x248
+#define VSECRAS_CAP 0x348
+#define DLINK_CAP 0x380
+#define PTM_CAP 0x38C
+#define PTM_VSEC_CAP 0x38C
+#define CCIX_TP_CAP 0x38C
+#define CXS_CAP 0x3D0
+#define RBAR_CAP 0x3E8
+#define VF_RBAR_CAP 0x3E8
+
+#define MAX_REINIT 3
+
+#define SLOT_POWER_LIMIT 75 // Watt
+
+#define LINK_CHECK_SUCCESS 0
+#define LINK_CHECK_FAILED -1
+#define LINK_CHECK_WRONG_PARAMETER 1
+
+#define PFA_REG_ENABLE 0
+#define PFA_REG_READ 1
+#define PFA_REG_CLEAR 2
+
+#define AMPERE_PCIE_VENDORID 0x1DEF
+#define AC01_HOST_BRIDGE_DEVICEID_RCA 0xE100
+#define AC01_HOST_BRIDGE_DEVICEID_RCB 0xE110
+#define AC01_PCIE_BRIDGE_DEVICEID_RCA 0xE101
+#define AC01_PCIE_BRIDGE_DEVICEID_RCB 0xE111
+
+#define MEMRDY_TIMEOUT 10 // 10 us
+#define PIPE_CLOCK_TIMEOUT 20000 // 20,000 us
+#define LTSSM_TRANSITION_TIMEOUT 100000 // 100 ms in total
+#define EP_LINKUP_TIMEOUT (10 * 1000) // 10ms
+#define LINK_WAIT_INTERVAL_US 50
+
+//
+// DATA LINK registers
+//
+#define DLINK_VENDOR_CAP_ID 0x25
+#define DLINK_VSEC 0x80000001
+#define DATA_LINK_FEATURE_CAP_OFF 0x04
+
+//
+// PL16 CAP registers
+//
+#define PL16_CAP_ID 0x26
+#define PL16G_CAP_OFF_20H_REG_OFF 0x20
+#define PL16G_STATUS_REG_OFF 0x0C
+#define PL16G_STATUS_EQ_CPL_GET(val) (val & 0x1)
+#define PL16G_STATUS_EQ_CPL_P1_GET(val) ((val & 0x2) >> 1)
+#define PL16G_STATUS_EQ_CPL_P2_GET(val) ((val & 0x4) >> 2)
+#define PL16G_STATUS_EQ_CPL_P3_GET(val) ((val & 0x8) >> 3)
+#define DSP_16G_TX_PRESET0_SET(dst,src) (((dst) & ~0xF) | (((UINT32) (src)) & 0xF))
+#define DSP_16G_TX_PRESET1_SET(dst,src) (((dst) & ~0xF00) | (((UINT32) (src) << 8) & 0xF00))
+#define DSP_16G_TX_PRESET2_SET(dst,src) (((dst) & ~0xF0000) | (((UINT32) (src) << 16) & 0xF0000))
+#define DSP_16G_TX_PRESET3_SET(dst,src) (((dst) & ~0xF000000) | (((UINT32) (src) << 24) & 0xF000000))
+#define DSP_16G_RXTX_PRESET0_SET(dst,src) (((dst) & ~0xFF) | (((UINT32) (src)) & 0xFF))
+#define DSP_16G_RXTX_PRESET1_SET(dst,src) (((dst) & ~0xFF00) | (((UINT32) (src) << 8) & 0xFF00))
+#define DSP_16G_RXTX_PRESET2_SET(dst,src) (((dst) & ~0xFF0000) | (((UINT32) (src) << 16) & 0xFF0000))
+#define DSP_16G_RXTX_PRESET3_SET(dst,src) (((dst) & ~0xFF000000) | (((UINT32) (src) << 24) & 0xFF000000))
+
+//
+// PCIe PF0_PORT_LOGIC registers
+//
+#define PORT_LOCIG_VC0_P_RX_Q_CTRL_OFF 0x748
+#define PORT_LOCIG_VC0_NP_RX_Q_CTRL_OFF 0x74C
+
+//
+// SNPSRAM Synopsys Memory Read/Write Margin registers
+//
+#define SPRF_RMR 0x0
+#define SPSRAM_RMR 0x4
+#define TPRF_RMR 0x8
+#define TPSRAM_RMR 0xC
+
+//
+// Host bridge registers
+//
+#define HBRCAPDMR 0x0
+#define HBRCBPDMR 0x4
+#define HBPDVIDR 0x10
+#define HBPRBNR 0x14
+#define HBPREVIDR 0x18
+#define HBPSIDR 0x1C
+#define HBPCLSSR 0x20
+
+// HBRCAPDMR
+#define RCAPCIDEVMAP_SET(dst, src) (((dst) & ~0x7) | (((UINT32) (src)) & 0x7))
+#define RCAPCIDEVMAP_GET(val) ((val) & 0x7)
+
+// HBRCBPDMR
+#define RCBPCIDEVMAPLO_SET(dst, src) (((dst) & ~0x7) | (((UINT32) (src)) & 0x7))
+#define RCBPCIDEVMAPLO_GET(val) ((val) & 0x7)
+
+#define RCBPCIDEVMAPHI_SET(dst, src) (((dst) & ~0x70) | (((UINT32) (src) << 4) & 0x70))
+#define RCBPCIDEVMAPHI_GET(val) (((val) & 0x7) >> 4)
+
+// HBPDVIDR
+#define PCIVENDID_SET(dst, src) (((dst) & ~0xFFFF) | (((UINT32) (src)) & 0xFFFF))
+#define PCIVENDID_GET(val) ((val) & 0xFFFF)
+
+#define PCIDEVID_SET(dst, src) (((dst) & ~0xFFFF0000) | (((UINT32) (src) << 16) & 0xFFFF0000))
+#define PCIDEVID_GET(val) (((val) & 0xFFFF0000) >> 16)
+
+// HBPRBNR
+#define PCIRBNUM_SET(dst, src) (((dst) & ~0x1F) | (((UINT32) (src)) & 0x1F))
+
+// HBPREVIDR
+#define PCIREVID_SET(dst, src) (((dst) & ~0xFF) | (((UINT32) (src)) & 0xFF))
+
+// HBPSIDR
+#define PCISUBSYSVENDID_SET(dst, src) (((dst) & ~0xFFFF) | (((UINT32) (src)) & 0xFFFF))
+
+#define PCISUBSYSID_SET(dst, src) (((dst) & ~0xFFFF0000) | (((UINT32) (src) << 16) & 0xFFFF0000))
+
+// HBPCLSSR
+#define CACHELINESIZE_SET(dst, src) (((dst) & ~0xFF) | (((UINT32) (src)) & 0xFF))
+
+//
+// PCIE core register
+//
+#define LINKCTRL 0x0
+#define LINKSTAT 0x4
+#define IRQSEL 0xC
+#define HOTPLUGSTAT 0x28
+#define IRQENABLE 0x30
+#define IRQEVENTSTAT 0x38
+#define BLOCKEVENTSTAT 0x3c
+#define RESET 0xC000
+#define CLOCK 0xC004
+#define MEMRDYR 0xC104
+#define RAMSDR 0xC10C
+
+// LINKCTRL
+#define LTSSMENB_SET(dst, src) (((dst) & ~0x1) | (((UINT32) (src)) & 0x1))
+#define DEVICETYPE_SET(dst, src) (((dst) & ~0xF0) | (((UINT32) (src) << 4) & 0xF0))
+#define DEVICETYPE_GET(val) (((val) & 0xF0) >> 4)
+
+// LINKSTAT
+#define PHY_STATUS_MASK (1 << 2)
+#define SMLH_LTSSM_STATE_MASK 0x3f00
+#define SMLH_LTSSM_STATE_GET(val) ((val & 0x3F00) >> 8)
+#define RDLH_SMLH_LINKUP_STATUS_GET(val) (val & 0x3)
+#define PHY_STATUS_MASK_BIT 0x04
+#define SMLH_LINK_UP_MASK_BIT 0x02
+#define RDLH_LINK_UP_MASK_BIT 0x01
+
+#define LTSSM_STATE_L0 0x11
+
+// IRQSEL
+#define AER_SET(dst, src) (((dst) & ~0x1) | (((UINT32) (src)) & 0x1))
+#define PME_SET(dst, src) (((dst) & ~0x2) | (((UINT32) (src) << 1) & 0x2))
+#define LINKAUTOBW_SET(dst, src) (((dst) & ~0x4) | (((UINT32) (src) << 2) & 0x4))
+#define BWMGMT_SET(dst, src) (((dst) & ~0x8) | (((UINT32) (src) << 3) & 0x8))
+#define EQRQST_SET(dst, src) (((dst) & ~0x10) | (((UINT32) (src) << 4) & 0x10))
+#define INTPIN_SET(dst, src) (((dst) & ~0xFF00) | (((UINT32) (src) << 8) & 0xFF00))
+
+// SLOTCAP
+#define SLOT_HPC_SET(dst, src) (((dst) & ~0x40) | (((UINT32) (src) << 6) & 0x40))
+
+// SLOT_CAPABILITIES_REG, PCIE_CAP_SLOT_POWER_LIMIT_VALUE bits[14:7]
+#define SLOT_CAP_SLOT_POWER_LIMIT_VALUE_SET(dst, src) \
+ (((dst) & ~0x7F80) | (((UINT32)(src) << 7) & 0x7F80))
+
+// HOTPLUGSTAT
+#define PWR_IND_SET(dst, src) (((dst) & ~0x1) | (((UINT32) (src)) & 0x1))
+#define ATTEN_IND_SET(dst, src) (((dst) & ~0x2) | (((UINT32) (src) << 1) & 0x2))
+#define PWR_CTRL_SET(dst, src) (((dst) & ~0x4) | (((UINT32) (src) << 2) & 0x4))
+#define EML_CTRL_SET(dst, src) (((dst) & ~0x8) | (((UINT32) (src) << 3) & 0x8))
+
+// IRQENABLE
+#define LINKUP_SET(dst, src) (((dst) & ~0x40) | (((UINT32) (src) << 6) & 0x40))
+
+// IRQEVENTSTAT
+#define BLOCK_INT_MASK BIT4
+#define INT_MASK BIT3
+
+// BLOCKEVENTSTAT
+#define LINKUP_MASK BIT0
+
+// RESET
+#define DWCPCIE_SET(dst, src) (((dst) & ~0x1) | (((UINT32) (src)) & 0x1))
+#define RESET_MASK 0x1
+
+// CLOCK
+#define AXIPIPE_SET(dst, src) (((dst) & ~0x1) | (((UINT32) (src)) & 0x1))
+
+// RAMSDR
+#define SD_SET(dst, src) (((dst) & ~0x1) | (((UINT32) (src)) & 0x1))
+
+//
+// PHY registers
+//
+#define RSTCTRL 0x0
+#define PHYCTRL 0x4
+#define RAMCTRL 0x8
+#define RAMSTAT 0xC
+#define PLLCTRL 0x10
+#define PHYLPKCTRL 0x14
+#define PHYTERMOFFSET0 0x18
+#define PHYTERMOFFSET1 0x1C
+#define PHYTERMOFFSET2 0x20
+#define PHYTERMOFFSET3 0x24
+#define RXTERM 0x28
+#define PHYDIAGCTRL 0x2C
+
+// RSTCTRL
+#define PHY_RESET_SET(dst, src) (((dst) & ~0x1) | (((UINT32) (src)) & 0x1))
+
+// PHYCTRL
+#define PWR_STABLE_SET(dst, src) (((dst) & ~0x1) | (((UINT32) (src)) & 0x1))
+
+//
+// PCIe config space registers
+//
+#define TYPE1_DEV_ID_VEND_ID_REG 0
+#define TYPE1_CLASS_CODE_REV_ID_REG 0x8
+#define TYPE1_CAP_PTR_REG 0x34
+#define SEC_LAT_TIMER_SUB_BUS_SEC_BUS_PRI_BUS_REG 0x18
+#define BRIDGE_CTRL_INT_PIN_INT_LINE_REG 0x3c
+#define CON_STATUS_REG (PM_CAP + 0x4)
+#define LINK_CAPABILITIES_REG (PCIE_CAP + 0xc)
+#define LINK_CONTROL_LINK_STATUS_REG (PCIE_CAP + 0x10)
+#define SLOT_CAPABILITIES_REG (PCIE_CAP + 0x14)
+#define DEVICE_CONTROL2_DEVICE_STATUS2_REG (PCIE_CAP + 0x28)
+#define LINK_CAPABILITIES2_REG (PCIE_CAP + 0x2c)
+#define LINK_CONTROL2_LINK_STATUS2_REG (PCIE_CAP + 0x30)
+#define UNCORR_ERR_STATUS_OFF (AER_CAP + 0x4)
+#define UNCORR_ERR_MASK_OFF (AER_CAP + 0x8)
+#define RESOURCE_CON_REG_VC0 (VC_CAP + 0x14)
+#define RESOURCE_CON_REG_VC1 (VC_CAP + 0x20)
+#define RESOURCE_STATUS_REG_VC1 (VC_CAP + 0x24)
+#define SD_CONTROL1_REG (RAS_DES_CAP+0xA0)
+#define CCIX_TP_CAP_TP_HDR2_OFF (CCIX_TP_CAP + 0x8)
+#define ESM_MNDTRY_RATE_CAP_OFF (CCIX_TP_CAP + 0xc)
+#define ESM_STAT_OFF (CCIX_TP_CAP + 0x14)
+#define ESM_CNTL_OFF (CCIX_TP_CAP + 0x18)
+#define ESM_LN_EQ_CNTL_25G_0_OFF (CCIX_TP_CAP + 0x2c)
+#define PORT_LINK_CTRL_OFF 0x710
+#define FILTER_MASK_2_OFF 0x720
+#define GEN2_CTRL_OFF 0x80c
+#define GEN3_RELATED_OFF 0x890
+#define GEN3_EQ_CONTROL_OFF 0x8A8
+#define MISC_CONTROL_1_OFF 0x8bc
+#define AMBA_ERROR_RESPONSE_DEFAULT_OFF 0x8d0
+#define AMBA_LINK_TIMEOUT_OFF 0x8d4
+#define AMBA_ORDERING_CTRL_OFF 0x8d8
+#define DTIM_CTRL0_OFF 0xab0
+#define AUX_CLK_FREQ_OFF 0xb40
+#define CCIX_CTRL_OFF 0xc20
+
+// TYPE1_DEV_ID_VEND_ID_REG
+#define VENDOR_ID_SET(dst, src) (((dst) & ~0xFFFF) | (((UINT32) (src)) & 0xFFFF))
+#define DEVICE_ID_SET(dst, src) (((dst) & ~0xFFFF0000) | (((UINT32) (src) << 16) & 0xFFFF0000))
+
+// TYPE1_CLASS_CODE_REV_ID_REG
+#define BASE_CLASS_CODE_SET(dst, src) (((dst) & ~0xFF000000) | (((UINT32) (src) << 24) & 0xFF000000))
+#define SUBCLASS_CODE_SET(dst, src) (((dst) & ~0xFF0000) | (((UINT32) (src) << 16) & 0xFF0000))
+#define PROGRAM_INTERFACE_SET(dst, src) (((dst) & ~0xFF00) | (((UINT32) (src) << 8) & 0xFF00))
+#define REVISION_ID_SET(dst, src) (((dst) & ~0xFF) | (((UINT32) (src)) & 0xFF))
+
+// SEC_LAT_TIMER_SUB_BUS_SEC_BUS_PRI_BUS_REG
+#define DEFAULT_SUB_BUS 0xFF
+#define SUB_BUS_SET(dst, src) (((dst) & ~0xFF0000) | (((UINT32) (src) << 16) & 0xFF0000))
+#define SEC_BUS_SET(dst, src) (((dst) & ~0xFF00) | (((UINT32) (src) << 8) & 0xFF00))
+#define PRIM_BUS_SET(dst, src) (((dst) & ~0xFF) | (((UINT32) (src)) & 0xFF))
+
+// BRIDGE_CTRL_INT_PIN_INT_LINE_REG
+#define INT_PIN_SET(dst, src) (((dst) & ~0xFF00) | (((UINT32) (src) << 8) & 0xFF00))
+
+// CON_STATUS_REG
+#define POWER_STATE_SET(dst, src) (((dst) & ~0x3) | (((UINT32) (src)) & 0x3))
+
+// DEVICE_CONTROL2_DEVICE_STATUS2_REG
+#define CAP_CPL_TIMEOUT_VALUE_SET(dst, src) (((dst) & ~0xF) | (((UINT32) (src)) & 0xF))
+
+// LINK_CAPABILITIES_REG
+#define CAP_ID 0x10
+#define LINK_CAPABILITIES_REG_OFF 0xC
+#define LINK_CONTROL_LINK_STATUS_OFF 0x10
+#define CAP_MAX_LINK_WIDTH_X1 0x1
+#define CAP_MAX_LINK_WIDTH_X2 0x2
+#define CAP_MAX_LINK_WIDTH_X4 0x4
+#define CAP_MAX_LINK_WIDTH_X8 0x8
+#define CAP_MAX_LINK_WIDTH_X16 0x10
+#define CAP_MAX_LINK_WIDTH_GET(val) ((val & 0x3F0) >> 4)
+#define CAP_MAX_LINK_WIDTH_SET(dst, src) (((dst) & ~0x3F0) | (((UINT32) (src) << 4) & 0x3F0))
+#define MAX_LINK_SPEED_25 0x1
+#define MAX_LINK_SPEED_50 0x2
+#define MAX_LINK_SPEED_80 0x3
+#define MAX_LINK_SPEED_160 0x4
+#define MAX_LINK_SPEED_320 0x5
+#define CAP_MAX_LINK_SPEED_GET(val) ((val & 0xF))
+#define CAP_MAX_LINK_SPEED_SET(dst, src) (((dst) & ~0xF) | (((UINT32) (src)) & 0xF))
+#define CAP_SLOT_CLK_CONFIG_SET(dst, src) (((dst) & ~0x10000000) | (((UINT32) (src) << 28) & 0x10000000))
+#define NO_ASPM_SUPPORTED 0x0
+#define L0S_SUPPORTED 0x1
+#define L1_SUPPORTED 0x2
+#define L0S_L1_SUPPORTED 0x3
+#define CAP_ACTIVE_STATE_LINK_PM_SUPPORT_SET(dst, src) (((dst) & ~0xC00) | (((UINT32)(src) << 10) & 0xC00))
+
+// LINK_CONTROL_LINK_STATUS_REG
+#define CAP_DLL_ACTIVE_GET(val) ((val & 0x20000000) >> 29)
+#define CAP_NEGO_LINK_WIDTH_GET(val) ((val & 0x3F00000) >> 20)
+#define CAP_LINK_SPEED_GET(val) ((val & 0xF0000) >> 16)
+#define CAP_LINK_SPEED_SET(dst, src) (((dst) & ~0xF0000) | (((UINT32) (src) << 16) & 0xF0000))
+#define CAP_LINK_SPEED_TO_VECTOR(val) (1 << ((val)-1))
+#define CAP_EN_CLK_POWER_MAN_GET(val) ((val & 0x100) >> 8)
+#define CAP_EN_CLK_POWER_MAN_SET(dst, src) (((dst) & ~0x100) | (((UINT32) (src) << 8) & 0x100))
+#define CAP_RETRAIN_LINK_SET(dst, src) (((dst) & ~0x20) | (((UINT32) (src) << 5) & 0x20))
+#define CAP_COMMON_CLK_SET(dst, src) (((dst) & ~0x40) | (((UINT32) (src) << 6) & 0x40))
+#define CAP_LINK_TRAINING_GET(val) ((val & 0x8000000) >> 27)
+#define CAP_LINK_DISABLE_SET(dst, src) (((dst) & ~0x10) | (((UINT32)(src) << 4) & 0x10))
+
+// LINK_CONTROL2_LINK_STATUS2_REG
+#define CAP_TARGET_LINK_SPEED_SET(dst, src) (((dst) & ~0xF) | (((UINT32) (src)) & 0xF))
+
+// Secondary Capability
+#define SPCIE_CAP_ID 0x19
+#define CAP_OFF_0C 0x0C
+#define LINK_CONTROL3_REG_OFF 0x4
+#define DSP_TX_PRESET0_SET(dst,src) (((dst) & ~0xF) | (((UINT32) (src)) & 0xF))
+#define DSP_TX_PRESET1_SET(dst,src) (((dst) & ~0xF0000) | (((UINT32) (src) << 16) & 0xF0000))
+
+// UNCORR_ERR_MASK_OFF
+#define CMPLT_TIMEOUT_ERR_MASK_SET(dst, src) (((dst) & ~0x4000) | (((UINT32) (src) << 14) & 0x4000))
+#define SDES_ERR_MASK_SET(dst, src) (((dst) & ~0x20) | (((UINT32)(src) << 5) & 0x20))
+
+// PORT_LINK_CTRL_OFF
+#define LINK_CAPABLE_X1 0x1
+#define LINK_CAPABLE_X2 0x3
+#define LINK_CAPABLE_X4 0x7
+#define LINK_CAPABLE_X8 0xF
+#define LINK_CAPABLE_X16 0x1F
+#define LINK_CAPABLE_X32 0x3F
+#define LINK_CAPABLE_SET(dst, src) (((dst) & ~0x3F0000) | (((UINT32) (src) << 16) & 0x3F0000))
+#define FAST_LINK_MODE_SET(dst, src) (((dst) & ~0x80) | (((UINT32) (src) << 7) & 0x80))
+
+// FILTER_MASK_2_OFF
+#define CX_FLT_MASK_VENMSG0_DROP_SET(dst, src) (((dst) & ~0x1) | (((UINT32) (src)) & 0x1))
+#define CX_FLT_MASK_VENMSG1_DROP_SET(dst, src) (((dst) & ~0x2) | (((UINT32) (src) << 1) & 0x2))
+#define CX_FLT_MASK_DABORT_4UCPL_SET(dst, src) (((dst) & ~0x4) | (((UINT32) (src) << 2) & 0x4))
+
+// GEN2_CTRL_OFF
+#define NUM_OF_LANES_X2 0x2
+#define NUM_OF_LANES_X4 0x4
+#define NUM_OF_LANES_X8 0x8
+#define NUM_OF_LANES_X16 0x10
+#define NUM_OF_LANES_SET(dst, src) (((dst) & ~0x1F00) | (((UINT32) (src) << 8) & 0x1F00))
+
+// GEN3_RELATED_OFF
+#define RATE_SHADOW_SEL_SET(dst, src) (((dst) & ~0x3000000) | (((UINT32) (src) << 24) & 0x3000000))
+#define EQ_PHASE_2_3_SET(dst, src) (((dst) & ~0x200) | (((UINT32) (src) << 9) & 0x200))
+#define RXEQ_REGRDLESS_SET(dst, src) (((dst) & ~0x2000) | (((UINT32) (src) << 13) & 0x2000))
+
+// GEN3_EQ_CONTROL_OFF
+#define GEN3_EQ_FB_MODE(dst, src) (((dst) & ~0xF) | ((UINT32) (src) & 0xF))
+#define GEN3_EQ_PRESET_VEC(dst, src) (((dst) & 0xFF0000FF) | (((UINT32) (src) << 8) & 0xFFFF00))
+#define GEN3_EQ_INIT_EVAL(dst,src) (((dst) & ~0x1000000) | (((UINT32) (src) << 24) & 0x1000000))
+
+// MISC_CONTROL_1_OFF
+#define DBI_RO_WR_EN_SET(dst, src) (((dst) & ~0x1) | (((UINT32) (src)) & 0x1))
+
+// AMBA_ERROR_RESPONSE_DEFAULT_OFF
+#define AMBA_ERROR_RESPONSE_CRS_SET(dst, src) (((dst) & ~0x18) | (((UINT32) (src) << 3) & 0x18))
+#define AMBA_ERROR_RESPONSE_GLOBAL_SET(dst, src) (((dst) & ~0x1) | (((UINT32) (src)) & 0x1))
+
+// AMBA_LINK_TIMEOUT_OFF
+#define LINK_TIMEOUT_PERIOD_DEFAULT_SET(dst, src) (((dst) & ~0xFF) | (((UINT32) (src)) & 0xFF))
+
+// AMBA_ORDERING_CTRL_OFF
+#define AX_MSTR_ZEROLREAD_FW_SET(dst, src) (((dst) & ~0x80) | (((UINT32) (src) << 7) & 0x80))
+
+// DTIM_CTRL0_OFF
+#define DTIM_CTRL0_ROOT_PORT_ID_SET(dst, src) (((dst) & ~0xFFFF) | (((UINT32) (src)) & 0xFFFF))
+
+// AUX_CLK_FREQ_OFF
+#define AUX_CLK_500MHZ 500
+#define AUX_CLK_FREQ_SET(dst, src) (((dst) & ~0x1FF) | (((UINT32) (src)) & 0x1FF))
+
+#define EXT_CAP_OFFSET_START 0x100
+
+// EVENT_COUNTER_CONTROL_REG
+#define ECCR_GROUP_EVENT_SEL_SET(dst, src) (((dst) & ~0xFFF0000) | (((UINT32)(src) << 16) & 0xFFF0000))
+#define ECCR_GROUP_SEL_SET(dst, src) (((dst) & ~0xF000000) | (((UINT32)(src) << 24) & 0xF000000))
+#define ECCR_EVENT_SEL_SET(dst, src) (((dst) & ~0xFF0000) | (((UINT32)(src) << 16) & 0xFF0000))
+#define ECCR_LANE_SEL_SET(dst, src) (((dst) & ~0xF00) | (((UINT32)(src) << 8) & 0xF00))
+#define ECCR_EVENT_COUNTER_ENABLE_SET(dst, src) (((dst) & ~0x1C) | (((UINT32)(src) << 2) & 0x1C))
+#define ECCR_EVENT_COUNTER_CLEAR_SET(dst, src) (((dst) & ~0x3) | (((UINT32)(src)) & 0x3))
+
+// PFA Registers offests
+#define RAS_DES_CAP_ID 0xB
+#define EVENT_COUNTER_CONTROL_REG_OFF 0x8
+#define EVENT_COUNTER_DATA_REG_OFF 0xC
+
+#define MAX_NUM_ERROR_CODE 47
+
+#endif /* AC01_PCIE_CORE_H_ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.c b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.c
new file mode 100644
index 000000000000..c546ee8330b9
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.c
@@ -0,0 +1,1391 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Guid/PlatformInfoHob.h>
+#include <Guid/RootComplexInfoHob.h>
+#include <Library/ArmGenericTimerCounterLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BoardPcieLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciePhyLib.h>
+#include <Library/SystemFirmwareInterfaceLib.h>
+#include <Library/TimerLib.h>
+
+#include "PcieCore.h"
+
+/**
+ Return the next extended capability address
+
+ @param RootComplex Pointer to AC01_ROOT_COMPLEX structure
+ @param PcieIndex PCIe index
+ @param IsRC TRUE: Checking RootComplex configuration space
+ FALSE: Checking EP configuration space
+ @param ExtendedCapId
+**/
+UINT64
+PcieCheckCap (
+ IN AC01_ROOT_COMPLEX *RootComplex,
+ IN UINT8 PcieIndex,
+ IN BOOLEAN IsRC,
+ IN UINT16 ExtendedCapId
+ )
+{
+ PHYSICAL_ADDRESS CfgAddr;
+ UINT32 Val = 0, NextCap = 0, CapId = 0, ExCap = 0;
+
+ if (IsRC) {
+ CfgAddr = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << 15);
+ } else {
+ CfgAddr = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << 20);
+ }
+
+ Val = MmioRead32 (CfgAddr + TYPE1_CAP_PTR_REG);
+ NextCap = Val & 0xFF;
+
+ // Loop untill desired capability is found else return 0
+ while (1) {
+ if ((NextCap & 0x3) != 0) {
+ // Not alignment, just return
+ return 0;
+ }
+ Val = MmioRead32 (CfgAddr + NextCap);
+ if (NextCap < EXT_CAP_OFFSET_START) {
+ CapId = Val & 0xFF;
+ } else {
+ CapId = Val & 0xFFFF;
+ }
+
+ if (CapId == ExtendedCapId) {
+ return (UINT64)(CfgAddr + NextCap);
+ }
+
+ if (NextCap < EXT_CAP_OFFSET_START) {
+ NextCap = (Val & 0xFFFF) >> 8;
+ } else {
+ NextCap = (Val & 0xFFFF0000) >> 20;
+ }
+
+ if ((NextCap == 0) && (ExCap == 0)) {
+ ExCap = 1;
+ NextCap = EXT_CAP_OFFSET_START;
+ }
+
+ if ((NextCap == 0) && (ExCap == 1)) {
+ return (UINT64)0;
+ }
+ }
+}
+
+/**
+ Configure equalization settings
+
+ @param RootComplex Pointer to AC01_ROOT_COMPLEX structure
+ @param PcieIndex PCIe index
+**/
+STATIC
+VOID
+ConfigureEqualization (
+ IN AC01_ROOT_COMPLEX *RootComplex,
+ IN UINT8 PcieIndex
+ )
+{
+ PHYSICAL_ADDRESS CfgAddr;
+ UINT32 Val;
+
+ CfgAddr = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << 15);
+
+ // Select the FoM method, need double-write to convey settings
+ Val = MmioRead32 (CfgAddr + GEN3_EQ_CONTROL_OFF);
+ Val = GEN3_EQ_FB_MODE (Val, 0x1);
+ Val = GEN3_EQ_PRESET_VEC (Val, 0x3FF);
+ Val = GEN3_EQ_INIT_EVAL (Val, 0x1);
+ MmioWrite32 (CfgAddr + GEN3_EQ_CONTROL_OFF, Val);
+ MmioWrite32 (CfgAddr + GEN3_EQ_CONTROL_OFF, Val);
+ Val = MmioRead32 (CfgAddr + GEN3_EQ_CONTROL_OFF);
+}
+
+/**
+ Configure presets for GEN3 equalization
+
+ @param RootComplex Pointer to AC01_ROOT_COMPLEX structure
+ @param PcieIndex PCIe index
+**/
+STATIC
+VOID
+ConfigurePresetGen3 (
+ IN AC01_ROOT_COMPLEX *RootComplex,
+ IN UINT8 PcieIndex
+ )
+{
+ PHYSICAL_ADDRESS CfgAddr, SpcieBaseAddr;
+ UINT32 Val, Idx;
+
+ CfgAddr = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << 15);
+
+ // Bring to legacy mode
+ Val = MmioRead32 (CfgAddr + GEN3_RELATED_OFF);
+ Val = RATE_SHADOW_SEL_SET (Val, 0);
+ MmioWrite32 (CfgAddr + GEN3_RELATED_OFF, Val);
+ Val = EQ_PHASE_2_3_SET (Val, 0);
+ Val = RXEQ_REGRDLESS_SET (Val, 1);
+ MmioWrite32 (CfgAddr + GEN3_RELATED_OFF, Val);
+
+ // Generate SPCIE capability address
+ SpcieBaseAddr = PcieCheckCap (RootComplex, PcieIndex, TRUE, SPCIE_CAP_ID);
+ if (SpcieBaseAddr == 0) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "PCIE%d.%d: Cannot get SPCIE capability address\n",
+ RootComplex->ID,
+ PcieIndex
+ ));
+ return;
+ }
+
+ for (Idx=0; Idx < RootComplex->Pcie[PcieIndex].MaxWidth/2; Idx++) {
+ // Program Preset to Gen3 EQ Lane Control
+ Val = MmioRead32 (SpcieBaseAddr + CAP_OFF_0C + Idx*4);
+ Val = DSP_TX_PRESET0_SET (Val, 0x7);
+ Val = DSP_TX_PRESET1_SET (Val, 0x7);
+ MmioWrite32 (SpcieBaseAddr + CAP_OFF_0C + Idx*4, Val);
+ }
+}
+
+/**
+ Configure presets for GEN4 equalization
+
+ @param RootComplex Pointer to AC01_ROOT_COMPLEX structure
+ @param PcieIndex PCIe controller index
+**/
+STATIC
+VOID
+ConfigurePresetGen4 (
+ IN AC01_ROOT_COMPLEX *RootComplex,
+ IN UINT8 PcieIndex
+ )
+{
+ PHYSICAL_ADDRESS CfgAddr, SpcieBaseAddr, Pl16BaseAddr;
+ UINT32 LinkWidth, Idx;
+ UINT32 Val;
+ UINT8 Preset;
+
+ CfgAddr = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << 15);
+
+ // Bring to legacy mode
+ Val = MmioRead32 (CfgAddr + GEN3_RELATED_OFF);
+ Val = RATE_SHADOW_SEL_SET (Val, 1);
+ MmioWrite32 (CfgAddr + GEN3_RELATED_OFF, Val);
+ Val = EQ_PHASE_2_3_SET (Val, 0);
+ Val = RXEQ_REGRDLESS_SET (Val, 1);
+ MmioWrite32 (CfgAddr + GEN3_RELATED_OFF, Val);
+
+ // Generate the PL16 capability address
+ Pl16BaseAddr = PcieCheckCap (RootComplex, PcieIndex, TRUE, PL16_CAP_ID);
+ if (Pl16BaseAddr == 0) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "PCIE%d.%d: Cannot get PL16 capability address\n",
+ RootComplex->ID,
+ PcieIndex
+ ));
+ return;
+ }
+
+ // Generate the SPCIE capability address
+ SpcieBaseAddr = PcieCheckCap (RootComplex, PcieIndex, TRUE, SPCIE_CAP_ID);
+ if (SpcieBaseAddr == 0) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "PCIE%d.%d: Cannot get SPICE capability address\n",
+ RootComplex->ID,
+ PcieIndex
+ ));
+ return;
+ }
+
+ // Configure downstream Gen4 Tx preset
+ if (RootComplex->PresetGen4[PcieIndex] == PRESET_INVALID) {
+ Preset = 0x57; // Default Gen4 preset
+ } else {
+ Preset = RootComplex->PresetGen4[PcieIndex];
+ }
+
+ LinkWidth = RootComplex->Pcie[PcieIndex].MaxWidth;
+ if (LinkWidth == 0x2) {
+ Val = MmioRead32 (Pl16BaseAddr + PL16G_CAP_OFF_20H_REG_OFF);
+ Val = DSP_16G_RXTX_PRESET0_SET (Val, Preset);
+ Val = DSP_16G_RXTX_PRESET1_SET (Val, Preset);
+ MmioWrite32 (Pl16BaseAddr + PL16G_CAP_OFF_20H_REG_OFF, Val);
+ } else {
+ for (Idx = 0; Idx < LinkWidth/4; Idx++) {
+ Val = MmioRead32 (Pl16BaseAddr + PL16G_CAP_OFF_20H_REG_OFF + Idx*4);
+ Val = DSP_16G_RXTX_PRESET0_SET (Val, Preset);
+ Val = DSP_16G_RXTX_PRESET1_SET (Val, Preset);
+ Val = DSP_16G_RXTX_PRESET2_SET (Val, Preset);
+ Val = DSP_16G_RXTX_PRESET3_SET (Val, Preset);
+ MmioWrite32 (Pl16BaseAddr + PL16G_CAP_OFF_20H_REG_OFF + Idx*4, Val);
+ }
+ }
+
+ // Configure Gen3 preset
+ for (Idx = 0; Idx < LinkWidth/2; Idx++) {
+ Val = MmioRead32 (SpcieBaseAddr + CAP_OFF_0C + Idx*4);
+ Val = DSP_TX_PRESET0_SET (Val, 0x7);
+ Val = DSP_TX_PRESET1_SET (Val, 0x7);
+ MmioWrite32 (SpcieBaseAddr + CAP_OFF_0C + Idx*4, Val);
+ }
+}
+
+INT8
+RasdpMitigation (
+ IN AC01_ROOT_COMPLEX *RootComplex,
+ IN UINT8 PcieIndex
+ )
+{
+ PHYSICAL_ADDRESS CfgAddr, DlinkBaseAddr, SnpsRamBase;
+ PLATFORM_INFO_HOB *PlatformHob;
+ UINT16 NextExtendedCapabilityOff;
+ UINT32 Val;
+ UINT32 VsecVal;
+ VOID *Hob;
+
+ SnpsRamBase = RootComplex->Pcie[PcieIndex].SnpsRamBase;
+ CfgAddr = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << 15);
+
+ Hob = GetFirstGuidHob (&gPlatformInfoHobGuid);
+ PlatformHob = (PLATFORM_INFO_HOB *)GET_GUID_HOB_DATA (Hob);
+ if ((PlatformHob->ScuProductId[0] & 0xff) == 0x01
+ && AsciiStrCmp ((CONST CHAR8 *)PlatformHob->CpuVer, "A0") == 0
+ && (RootComplex->Type == RootComplexTypeB || PcieIndex > 0)) {
+ // Change the Read Margin dual ported RAMs
+ Val = 0x10; // Margin to 0x0 (most conservative setting)
+ MmioWrite32 (SnpsRamBase + TPSRAM_RMR, Val);
+
+ // Generate the DLINK capability address
+ DlinkBaseAddr = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << 15);
+ NextExtendedCapabilityOff = 0x100; // This is the 1st extended capability offset
+ do {
+ Val = MmioRead32 (DlinkBaseAddr + NextExtendedCapabilityOff);
+ if (Val == 0xFFFFFFFF) {
+ DlinkBaseAddr = 0x0;
+ break;
+ }
+ if ((Val & 0xFFFF) == DLINK_VENDOR_CAP_ID) {
+ VsecVal = MmioRead32 (DlinkBaseAddr + NextExtendedCapabilityOff + 0x4);
+ if (VsecVal == DLINK_VSEC) {
+ DlinkBaseAddr = DlinkBaseAddr + NextExtendedCapabilityOff;
+ break;
+ }
+ }
+ NextExtendedCapabilityOff = (Val >> 20);
+ } while (NextExtendedCapabilityOff != 0);
+
+ // Disable the scaled credit mode
+ if (DlinkBaseAddr != 0x0) {
+ Val = 1;
+ MmioWrite32 (DlinkBaseAddr + DATA_LINK_FEATURE_CAP_OFF, Val);
+ Val = MmioRead32 (DlinkBaseAddr + DATA_LINK_FEATURE_CAP_OFF);
+ if (Val != 1) {
+ DEBUG ((DEBUG_ERROR, "- Pcie[%d] - Unable to disable scaled credit\n", PcieIndex));
+ return -1;
+ }
+ } else {
+ DEBUG ((DEBUG_ERROR, "- Pcie[%d] - Unable to locate data link feature cap offset\n", PcieIndex));
+ return -1;
+ }
+
+ // Reduce Posted Credits to 1 packet header and data credit for all
+ // impacted controllers. Also zero credit scale values for both
+ // data and packet headers.
+ Val=0x40201020;
+ MmioWrite32 (CfgAddr + PORT_LOCIG_VC0_P_RX_Q_CTRL_OFF, Val);
+ }
+
+ return 0;
+}
+
+VOID
+ProgramHostBridge (
+ AC01_ROOT_COMPLEX *RootComplex
+ )
+{
+ UINT32 Val;
+
+ // Program Root Complex Bifurcation
+ if (RootComplex->Active) {
+ if (RootComplex->Type == RootComplexTypeA) {
+ if (!EFI_ERROR (MailboxMsgRegisterRead (RootComplex->Socket, RootComplex->HostBridgeBase + HBRCAPDMR, &Val))) {
+ Val = RCAPCIDEVMAP_SET (Val, RootComplex->DevMapLow);
+ MailboxMsgRegisterWrite (RootComplex->Socket, RootComplex->HostBridgeBase + HBRCAPDMR, Val);
+ }
+ } else {
+ if (!EFI_ERROR (MailboxMsgRegisterRead (RootComplex->Socket, RootComplex->HostBridgeBase + HBRCBPDMR, &Val))) {
+ Val = RCBPCIDEVMAPLO_SET (Val, RootComplex->DevMapLow);
+ Val = RCBPCIDEVMAPHI_SET (Val, RootComplex->DevMapHigh);
+ MailboxMsgRegisterWrite (RootComplex->Socket, RootComplex->HostBridgeBase + HBRCBPDMR, Val);
+ }
+ }
+ }
+
+ // Program VendorID and DeviceId
+ if (!EFI_ERROR (MailboxMsgRegisterRead (RootComplex->Socket, RootComplex->HostBridgeBase + HBPDVIDR, &Val))) {
+ Val = PCIVENDID_SET (Val, AMPERE_PCIE_VENDORID);
+ if (RootComplexTypeA == RootComplex->Type) {
+ Val = PCIDEVID_SET (Val, AC01_HOST_BRIDGE_DEVICEID_RCA);
+ } else {
+ Val = PCIDEVID_SET (Val, AC01_HOST_BRIDGE_DEVICEID_RCB);
+ }
+ MailboxMsgRegisterWrite (RootComplex->Socket, RootComplex->HostBridgeBase + HBPDVIDR, Val);
+ }
+}
+
+VOID
+ProgramLinkCapabilities (
+ IN AC01_ROOT_COMPLEX *RootComplex,
+ IN UINT8 PcieIndex
+ )
+{
+ PHYSICAL_ADDRESS CfgAddr;
+ UINT32 Val;
+
+ CfgAddr = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << 15);
+
+ Val = MmioRead32 (CfgAddr + PORT_LINK_CTRL_OFF);
+ switch (RootComplex->Pcie[PcieIndex].MaxWidth) {
+ case LINK_WIDTH_X2:
+ Val = LINK_CAPABLE_SET (Val, LINK_CAPABLE_X2);
+ break;
+
+ case LINK_WIDTH_X4:
+ Val = LINK_CAPABLE_SET (Val, LINK_CAPABLE_X4);
+ break;
+
+ case LINK_WIDTH_X8:
+ Val = LINK_CAPABLE_SET (Val, LINK_CAPABLE_X8);
+ break;
+
+ case LINK_WIDTH_X16:
+ default:
+ Val = LINK_CAPABLE_SET (Val, LINK_CAPABLE_X16);
+ break;
+ }
+ MmioWrite32 (CfgAddr + PORT_LINK_CTRL_OFF, Val);
+ Val = MmioRead32 (CfgAddr + GEN2_CTRL_OFF);
+ switch (RootComplex->Pcie[PcieIndex].MaxWidth) {
+ case LINK_WIDTH_X2:
+ Val = NUM_OF_LANES_SET (Val, NUM_OF_LANES_X2);
+ break;
+
+ case LINK_WIDTH_X4:
+ Val = NUM_OF_LANES_SET (Val, NUM_OF_LANES_X4);
+ break;
+
+ case LINK_WIDTH_X8:
+ Val = NUM_OF_LANES_SET (Val, NUM_OF_LANES_X8);
+ break;
+
+ case LINK_WIDTH_X16:
+ default:
+ Val = NUM_OF_LANES_SET (Val, NUM_OF_LANES_X16);
+ break;
+ }
+ MmioWrite32 (CfgAddr + GEN2_CTRL_OFF, Val);
+ Val = MmioRead32 (CfgAddr + LINK_CAPABILITIES_REG);
+ switch (RootComplex->Pcie[PcieIndex].MaxWidth) {
+ case LINK_WIDTH_X2:
+ Val = CAP_MAX_LINK_WIDTH_SET (Val, CAP_MAX_LINK_WIDTH_X2);
+ break;
+
+ case LINK_WIDTH_X4:
+ Val = CAP_MAX_LINK_WIDTH_SET (Val, CAP_MAX_LINK_WIDTH_X4);
+ break;
+
+ case LINK_WIDTH_X8:
+ Val = CAP_MAX_LINK_WIDTH_SET (Val, CAP_MAX_LINK_WIDTH_X8);
+ break;
+
+ case LINK_WIDTH_X16:
+ default:
+ Val = CAP_MAX_LINK_WIDTH_SET (Val, CAP_MAX_LINK_WIDTH_X16);
+ break;
+ }
+
+ switch (RootComplex->Pcie[PcieIndex].MaxGen) {
+ case LINK_SPEED_GEN1:
+ Val = CAP_MAX_LINK_SPEED_SET (Val, MAX_LINK_SPEED_25);
+ break;
+
+ case LINK_SPEED_GEN2:
+ Val = CAP_MAX_LINK_SPEED_SET (Val, MAX_LINK_SPEED_50);
+ break;
+
+ case LINK_SPEED_GEN3:
+ Val = CAP_MAX_LINK_SPEED_SET (Val, MAX_LINK_SPEED_80);
+ break;
+
+ default:
+ Val = CAP_MAX_LINK_SPEED_SET (Val, MAX_LINK_SPEED_160);
+ break;
+ }
+ /* Enable ASPM Capability */
+ Val = CAP_ACTIVE_STATE_LINK_PM_SUPPORT_SET (Val, L0S_L1_SUPPORTED);
+ MmioWrite32 (CfgAddr + LINK_CAPABILITIES_REG, Val);
+
+ Val = MmioRead32 (CfgAddr + LINK_CONTROL2_LINK_STATUS2_REG);
+ switch (RootComplex->Pcie[PcieIndex].MaxGen) {
+ case LINK_SPEED_GEN1:
+ Val = CAP_TARGET_LINK_SPEED_SET (Val, MAX_LINK_SPEED_25);
+ break;
+
+ case LINK_SPEED_GEN2:
+ Val = CAP_TARGET_LINK_SPEED_SET (Val, MAX_LINK_SPEED_50);
+ break;
+
+ case LINK_SPEED_GEN3:
+ Val = CAP_TARGET_LINK_SPEED_SET (Val, MAX_LINK_SPEED_80);
+ break;
+
+ default:
+ Val = CAP_TARGET_LINK_SPEED_SET (Val, MAX_LINK_SPEED_160);
+ break;
+ }
+ MmioWrite32 (CfgAddr + LINK_CONTROL2_LINK_STATUS2_REG, Val);
+}
+
+VOID
+MaskCompletionTimeOut (
+ IN AC01_ROOT_COMPLEX *RootComplex,
+ IN UINT8 PcieIndex,
+ IN UINT32 TimeOut,
+ IN BOOLEAN IsMask
+ )
+{
+ PHYSICAL_ADDRESS CfgAddr;
+ UINT32 Val;
+
+ CfgAddr = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << 15);
+
+ Val = MmioRead32 (CfgAddr + AMBA_LINK_TIMEOUT_OFF);
+ Val = LINK_TIMEOUT_PERIOD_DEFAULT_SET (Val, TimeOut);
+ MmioWrite32 (CfgAddr + AMBA_LINK_TIMEOUT_OFF, Val);
+ Val = MmioRead32 (CfgAddr + UNCORR_ERR_MASK_OFF);
+ Val = CMPLT_TIMEOUT_ERR_MASK_SET (Val, IsMask ? 1 : 0);
+ MmioWrite32 (CfgAddr + UNCORR_ERR_MASK_OFF, Val);
+}
+
+BOOLEAN
+PollMemReady (
+ PHYSICAL_ADDRESS CsrBase
+ )
+{
+ UINT32 TimeOut;
+ UINT32 Val;
+
+ // Poll till mem is ready
+ TimeOut = MEMRDY_TIMEOUT;
+ do {
+ Val = MmioRead32 (CsrBase + MEMRDYR);
+ if (Val & 1) {
+ break;
+ }
+
+ TimeOut--;
+ MicroSecondDelay (1);
+ } while (TimeOut > 0);
+
+ if (TimeOut <= 0) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+PollPipeReady (
+ PHYSICAL_ADDRESS CsrBase
+ )
+{
+ UINT32 TimeOut;
+ UINT32 Val;
+
+ // Poll till PIPE clock is stable
+ TimeOut = PIPE_CLOCK_TIMEOUT;
+ do {
+ Val = MmioRead32 (CsrBase + LINKSTAT);
+ if (!(Val & PHY_STATUS_MASK)) {
+ break;
+ }
+
+ TimeOut--;
+ MicroSecondDelay (1);
+ } while (TimeOut > 0);
+
+ if (TimeOut <= 0) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Setup and initialize the AC01 PCIe Root Complex and underneath PCIe controllers
+
+ @param RootComplex Pointer to Root Complex structure
+ @param ReInit Re-init status
+ @param ReInitPcieIndex PCIe index
+
+ @retval RETURN_SUCCESS The Root Complex has been initialized successfully.
+ @retval RETURN_DEVICE_ERROR PHY, Memory or PIPE is not ready.
+**/
+RETURN_STATUS
+Ac01PcieCoreSetupRC (
+ IN AC01_ROOT_COMPLEX *RootComplex,
+ IN BOOLEAN ReInit,
+ IN UINT8 ReInitPcieIndex
+ )
+{
+ PHYSICAL_ADDRESS CsrBase, CfgAddr;
+ RETURN_STATUS Status;
+ UINT32 Val;
+ UINT8 PcieIndex;
+
+ DEBUG ((DEBUG_INFO, "Initializing Socket%d RootComplex%d\n", RootComplex->Socket, RootComplex->ID));
+
+ ProgramHostBridge (RootComplex);
+
+ if (!ReInit) {
+ // Initialize PHY
+ Status = PciePhyInit (RootComplex->SerdesBase);
+ if (RETURN_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to initialize the PCIe PHY\n", __FUNCTION__));
+ return RETURN_DEVICE_ERROR;
+ }
+ }
+
+ // Setup each controller
+ for (PcieIndex = 0; PcieIndex < RootComplex->MaxPcieController; PcieIndex++) {
+
+ if (ReInit) {
+ PcieIndex = ReInitPcieIndex;
+ }
+
+ if (!RootComplex->Pcie[PcieIndex].Active) {
+ continue;
+ }
+
+ DEBUG ((DEBUG_INFO, "Initializing Controller %d\n", PcieIndex));
+
+ CsrBase = RootComplex->Pcie[PcieIndex].CsrBase;
+ CfgAddr = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << 15);
+
+ // Put Controller into reset if not in reset already
+ Val = MmioRead32 (CsrBase + RESET);
+ if (!(Val & RESET_MASK)) {
+ Val = DWCPCIE_SET (Val, 1);
+ MmioWrite32 (CsrBase + RESET, Val);
+
+ // Delay 50ms to ensure controller finish its reset
+ MicroSecondDelay (50000);
+ }
+
+ // Clear memory shutdown
+ Val = MmioRead32 (CsrBase + RAMSDR);
+ Val = SD_SET (Val, 0);
+ MmioWrite32 (CsrBase + RAMSDR, Val);
+
+ if (!PollMemReady (CsrBase)) {
+ DEBUG ((DEBUG_ERROR, "- Pcie[%d] - Mem not ready\n", PcieIndex));
+ return RETURN_DEVICE_ERROR;
+ }
+
+ // Hold link training
+ Val = MmioRead32 (CsrBase + LINKCTRL);
+ Val = LTSSMENB_SET (Val, 0);
+ MmioWrite32 (CsrBase + LINKCTRL, Val);
+
+ // Enable subsystem clock and release reset
+ Val = MmioRead32 (CsrBase + CLOCK);
+ Val = AXIPIPE_SET (Val, 1);
+ MmioWrite32 (CsrBase + CLOCK, Val);
+ Val = MmioRead32 (CsrBase + RESET);
+ Val = DWCPCIE_SET (Val, 0);
+ MmioWrite32 (CsrBase + RESET, Val);
+
+ //
+ // Controller does not provide any indicator for reset released.
+ // Must wait at least 1us as per EAS.
+ //
+ MicroSecondDelay (1);
+
+ if (!PollPipeReady (CsrBase)) {
+ DEBUG ((DEBUG_ERROR, "- Pcie[%d] - PIPE clock is not stable\n", PcieIndex));
+ return RETURN_DEVICE_ERROR;
+ }
+
+ // Start PERST pulse
+ BoardPcieAssertPerst (RootComplex, PcieIndex, TRUE);
+
+ // Allow programming to config space
+ Val = MmioRead32 (CfgAddr + MISC_CONTROL_1_OFF);
+ Val = DBI_RO_WR_EN_SET (Val, 1);
+ MmioWrite32 (CfgAddr + MISC_CONTROL_1_OFF, Val);
+
+ // In order to detect the NVMe disk for booting without disk,
+ // need to set Hot-Plug Slot Capable during port initialization.
+ // It will help PCI Linux driver to initialize its slot iomem resource,
+ // the one is used for detecting the disk when it is inserted.
+ Val = MmioRead32 (CfgAddr + SLOT_CAPABILITIES_REG);
+ Val = SLOT_HPC_SET (Val, 1);
+ // Program the power limit
+ Val = SLOT_CAP_SLOT_POWER_LIMIT_VALUE_SET (Val, SLOT_POWER_LIMIT);
+ MmioWrite32 (CfgAddr + SLOT_CAPABILITIES_REG, Val);
+
+ // Apply RASDP error mitigation for all x8, x4, and x2 controllers
+ // This includes all RootComplexTypeB root ports, and every RootComplexTypeA root port controller
+ // except for index 0 (i.e. x16 controllers are exempted from this WA)
+ RasdpMitigation (RootComplex, PcieIndex);
+
+ // Program DTI for ATS support
+ Val = MmioRead32 (CfgAddr + DTIM_CTRL0_OFF);
+ Val = DTIM_CTRL0_ROOT_PORT_ID_SET (Val, 0);
+ MmioWrite32 (CfgAddr + DTIM_CTRL0_OFF, Val);
+
+ //
+ // Program number of lanes used
+ // - Reprogram LINK_CAPABLE of PORT_LINK_CTRL_OFF
+ // - Reprogram NUM_OF_LANES of GEN2_CTRL_OFF
+ // - Reprogram CAP_MAX_LINK_WIDTH of LINK_CAPABILITIES_REG
+ //
+ ProgramLinkCapabilities (RootComplex, PcieIndex);
+
+ // Set Zero byte request handling
+ Val = MmioRead32 (CfgAddr + FILTER_MASK_2_OFF);
+ Val = CX_FLT_MASK_VENMSG0_DROP_SET (Val, 0);
+ Val = CX_FLT_MASK_VENMSG1_DROP_SET (Val, 0);
+ Val = CX_FLT_MASK_DABORT_4UCPL_SET (Val, 0);
+ MmioWrite32 (CfgAddr + FILTER_MASK_2_OFF, Val);
+ Val = MmioRead32 (CfgAddr + AMBA_ORDERING_CTRL_OFF);
+ Val = AX_MSTR_ZEROLREAD_FW_SET (Val, 0);
+ MmioWrite32 (CfgAddr + AMBA_ORDERING_CTRL_OFF, Val);
+
+ //
+ // Set Completion with CRS handling for CFG Request
+ // Set Completion with CA/UR handling non-CFG Request
+ //
+ Val = MmioRead32 (CfgAddr + AMBA_ERROR_RESPONSE_DEFAULT_OFF);
+ Val = AMBA_ERROR_RESPONSE_CRS_SET (Val, 0x2);
+ MmioWrite32 (CfgAddr + AMBA_ERROR_RESPONSE_DEFAULT_OFF, Val);
+
+ // Set Legacy PCIE interrupt map to INTA
+ Val = MmioRead32 (CfgAddr + BRIDGE_CTRL_INT_PIN_INT_LINE_REG);
+ Val = INT_PIN_SET (Val, 1);
+ MmioWrite32 (CfgAddr + BRIDGE_CTRL_INT_PIN_INT_LINE_REG, Val);
+ Val = MmioRead32 (CsrBase + IRQSEL);
+ Val = INTPIN_SET (Val, 1);
+ MmioWrite32 (CsrBase + IRQSEL, Val);
+
+ if (RootComplex->Pcie[PcieIndex].MaxGen != LINK_SPEED_GEN1) {
+ ConfigureEqualization (RootComplex, PcieIndex);
+ if (RootComplex->Pcie[PcieIndex].MaxGen == LINK_SPEED_GEN3) {
+ ConfigurePresetGen3 (RootComplex, PcieIndex);
+ } else if (RootComplex->Pcie[PcieIndex].MaxGen == LINK_SPEED_GEN4) {
+ ConfigurePresetGen4 (RootComplex, PcieIndex);
+ }
+ }
+
+ // Mask Completion Timeout
+ MaskCompletionTimeOut (RootComplex, PcieIndex, 1, TRUE);
+
+ // AER surprise link down error should be masked due to hotplug is enabled
+ // This event must be handled by Hotplug handler, instead of error handler
+ Val = MmioRead32 (CfgAddr + UNCORR_ERR_MASK_OFF);
+ Val = SDES_ERR_MASK_SET (Val, 1);
+ MmioWrite32 (CfgAddr + UNCORR_ERR_MASK_OFF, Val);
+
+ // Program Class Code
+ Val = MmioRead32 (CfgAddr + TYPE1_CLASS_CODE_REV_ID_REG);
+ Val = REVISION_ID_SET (Val, 4);
+ Val = SUBCLASS_CODE_SET (Val, 4);
+ Val = BASE_CLASS_CODE_SET (Val, 6);
+ MmioWrite32 (CfgAddr + TYPE1_CLASS_CODE_REV_ID_REG, Val);
+
+ // Program VendorID and DeviceID
+ Val = MmioRead32 (CfgAddr + TYPE1_DEV_ID_VEND_ID_REG);
+ Val = VENDOR_ID_SET (Val, AMPERE_PCIE_VENDORID);
+ if (RootComplexTypeA == RootComplex->Type) {
+ Val = DEVICE_ID_SET (Val, AC01_PCIE_BRIDGE_DEVICEID_RCA + PcieIndex);
+ } else {
+ Val = DEVICE_ID_SET (Val, AC01_PCIE_BRIDGE_DEVICEID_RCB + PcieIndex);
+ }
+ MmioWrite32 (CfgAddr + TYPE1_DEV_ID_VEND_ID_REG, Val);
+
+ // Enable common clock for downstream
+ Val = MmioRead32 (CfgAddr + LINK_CONTROL_LINK_STATUS_REG);
+ Val = CAP_SLOT_CLK_CONFIG_SET (Val, 1);
+ Val = CAP_COMMON_CLK_SET (Val, 1);
+ MmioWrite32 (CfgAddr + LINK_CONTROL_LINK_STATUS_REG, Val);
+
+ // Match aux_clk to system
+ Val = MmioRead32 (CfgAddr + AUX_CLK_FREQ_OFF);
+ Val = AUX_CLK_FREQ_SET (Val, AUX_CLK_500MHZ);
+ MmioWrite32 (CfgAddr + AUX_CLK_FREQ_OFF, Val);
+
+ // Assert PERST low to reset endpoint
+ BoardPcieAssertPerst (RootComplex, PcieIndex, FALSE);
+
+ // Start link training
+ Val = MmioRead32 (CsrBase + LINKCTRL);
+ Val = LTSSMENB_SET (Val, 1);
+ MmioWrite32 (CsrBase + LINKCTRL, Val);
+
+ // Complete the PERST pulse
+ BoardPcieAssertPerst (RootComplex, PcieIndex, TRUE);
+
+ // Lock programming of config space
+ Val = MmioRead32 (CfgAddr + MISC_CONTROL_1_OFF);
+ Val = DBI_RO_WR_EN_SET (Val, 0);
+ MmioWrite32 (CfgAddr + MISC_CONTROL_1_OFF, Val);
+
+ if (ReInit) {
+ return RETURN_SUCCESS;
+ }
+ }
+
+ return RETURN_SUCCESS;
+}
+
+BOOLEAN
+PcieLinkUpCheck (
+ IN AC01_PCIE_CONTROLLER *Pcie
+ )
+{
+ PHYSICAL_ADDRESS CsrBase;
+ UINT32 BlockEvent;
+ UINT32 LinkStat;
+
+ CsrBase = Pcie->CsrBase;
+
+ // Check if card present
+ // smlh_ltssm_state[13:8] = 0
+ // phy_status[2] = 0
+ // smlh_link_up[1] = 0
+ // rdlh_link_up[0] = 0
+ LinkStat = MmioRead32 (CsrBase + LINKSTAT);
+ LinkStat = LinkStat & (SMLH_LTSSM_STATE_MASK | PHY_STATUS_MASK_BIT |
+ SMLH_LINK_UP_MASK_BIT | RDLH_LINK_UP_MASK_BIT);
+ if (LinkStat == 0x0000) {
+ return FALSE;
+ }
+
+ BlockEvent = MmioRead32 (CsrBase + BLOCKEVENTSTAT);
+ LinkStat = MmioRead32 (CsrBase + LINKSTAT);
+
+ if (((BlockEvent & LINKUP_MASK) != 0)
+ && (SMLH_LTSSM_STATE_GET(LinkStat) == LTSSM_STATE_L0))
+ {
+ DEBUG ((DEBUG_INFO, "%a Linkup\n", __FUNCTION__));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Callback function when the Host Bridge enumeration end.
+
+ @param RootComplex Pointer to the Root Complex structure
+**/
+VOID
+Ac01PcieCoreEndEnumeration (
+ IN AC01_ROOT_COMPLEX *RootComplex
+ )
+{
+ PHYSICAL_ADDRESS CfgAddr;
+ PHYSICAL_ADDRESS Reg;
+ UINT32 Val;
+ UINTN Index;
+
+ if (RootComplex == NULL || !RootComplex->Active) {
+ return;
+ }
+
+ // Clear uncorrectable error during enumuration phase. Mainly completion timeout.
+ for (Index = 0; Index < RootComplex->MaxPcieController; Index++) {
+ if (!RootComplex->Pcie[Index].Active) {
+ continue;
+ }
+ if (!PcieLinkUpCheck(&RootComplex->Pcie[Index])) {
+ // If link down/disabled after enumeration, disable completed time out
+ CfgAddr = RootComplex->MmcfgBase + (RootComplex->Pcie[Index].DevNum << 15);
+ Val = MmioRead32 (CfgAddr + UNCORR_ERR_MASK_OFF);
+ Val = CMPLT_TIMEOUT_ERR_MASK_SET (Val, 1);
+ MmioWrite32 (CfgAddr + UNCORR_ERR_MASK_OFF, Val);
+ }
+ // Clear all errors
+ Reg = RootComplex->MmcfgBase + ((Index + 1) << 15) + UNCORR_ERR_STATUS_OFF;
+ Val = MmioRead32 (Reg);
+ if (Val != 0) {
+ // Clear error by writting
+ MmioWrite32 (Reg, Val);
+ }
+ }
+}
+
+/**
+ Comparing current link status with the max capabilities of the link
+
+ @param RootComplex Pointer to AC01_ROOT_COMPLEX structure
+ @param PcieIndex PCIe index
+ @param EpMaxWidth EP max link width
+ @param EpMaxGen EP max link speed
+
+ @retval -1: Link status do not match with link max capabilities
+ 1: Link capabilites are invalid
+ 0: Link status are correct
+**/
+INT32
+Ac01PcieCoreLinkCheck (
+ IN AC01_ROOT_COMPLEX *RootComplex,
+ IN UINT8 PcieIndex,
+ IN UINT8 EpMaxWidth,
+ IN UINT8 EpMaxGen
+ )
+{
+ PHYSICAL_ADDRESS CsrBase, CfgAddr;
+ UINT32 Val, LinkStat;
+ UINT32 MaxWidth, MaxGen;
+
+ CsrBase = RootComplex->Pcie[PcieIndex].CsrBase;
+ CfgAddr = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << 15);
+
+ Val = MmioRead32 (CfgAddr + LINK_CAPABILITIES_REG);
+ if ((CAP_MAX_LINK_WIDTH_GET (Val) == 0) ||
+ (CAP_MAX_LINK_SPEED_GET (Val) == 0)) {
+ DEBUG ((DEBUG_INFO, "\tPCIE%d.%d: Wrong RootComplex capabilities\n", RootComplex->ID, PcieIndex));
+ return LINK_CHECK_WRONG_PARAMETER;
+ }
+
+ if ((EpMaxWidth == 0) || (EpMaxGen == 0)) {
+ DEBUG ((DEBUG_INFO, "\tPCIE%d.%d: Wrong EP capabilities\n", RootComplex->ID, PcieIndex));
+ return LINK_CHECK_FAILED;
+ }
+
+ // Compare RootComplex and EP capabilities
+ if (CAP_MAX_LINK_WIDTH_GET (Val) > EpMaxWidth) {
+ MaxWidth = EpMaxWidth;
+ } else {
+ MaxWidth = CAP_MAX_LINK_WIDTH_GET (Val);
+ }
+
+ // Compare RootComplex and EP capabilities
+ if (CAP_MAX_LINK_SPEED_GET (Val) > EpMaxGen) {
+ MaxGen = EpMaxGen;
+ } else {
+ MaxGen = CAP_MAX_LINK_SPEED_GET (Val);
+ }
+
+ LinkStat = MmioRead32 (CsrBase + LINKSTAT);
+ Val = MmioRead32 (CfgAddr + LINK_CONTROL_LINK_STATUS_REG);
+ DEBUG ((
+ DEBUG_INFO,
+ "PCIE%d.%d: Link MaxWidth %d MaxGen %d, LINKSTAT 0x%x",
+ RootComplex->ID,
+ PcieIndex,
+ MaxWidth,
+ MaxGen,
+ LinkStat
+ ));
+
+ // Checking all conditions of the link
+ // If one of them is not sastified, return link up fail
+ if ((CAP_NEGO_LINK_WIDTH_GET (Val) != MaxWidth) ||
+ (CAP_LINK_SPEED_GET (Val) != MaxGen) ||
+ (RDLH_SMLH_LINKUP_STATUS_GET (LinkStat) != (SMLH_LINK_UP_MASK_BIT | RDLH_LINK_UP_MASK_BIT)))
+ {
+ DEBUG ((DEBUG_INFO, "\tLinkCheck FAILED\n"));
+ return LINK_CHECK_FAILED;
+ }
+
+ DEBUG ((DEBUG_INFO, "\tLinkCheck SUCCESS\n"));
+ return LINK_CHECK_SUCCESS;
+}
+
+INT32
+PFACounterRead (
+ IN AC01_ROOT_COMPLEX *RootComplex,
+ IN UINT8 PcieIndex,
+ IN UINT64 RasDesVSecBase
+ )
+{
+ INT32 Ret = LINK_CHECK_SUCCESS;
+ UINT32 Val;
+ UINT8 ErrCode, ErrGrpNum;
+
+ UINT32 ErrCtrlCfg[MAX_NUM_ERROR_CODE] = {
+ 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, 0x008, 0x009, 0x00A, // Per Lane
+ 0x105, 0x106, 0x107, 0x108, 0x109, 0x10A,
+ 0x200, 0x201, 0x202, 0x203, 0x204, 0x205, 0x206, 0x207,
+ 0x300, 0x301, 0x302, 0x303, 0x304, 0x305,
+ 0x400, 0x401, // Per Lane
+ 0x500, 0x501, 0x502, 0x503, 0x504, 0x505, 0x506, 0x507, 0x508, 0x509, 0x50A, 0x50B, 0x50C, 0x50D
+ };
+
+ for (ErrCode = 0; ErrCode < MAX_NUM_ERROR_CODE; ErrCode++) {
+ ErrGrpNum = (ErrCtrlCfg[ErrCode] & 0xF00) >> 8;
+ // Skipping per lane group
+ // Checking common lane group because AER error are included in common group only
+ if ((ErrGrpNum != 0) && (ErrGrpNum != 4)) {
+ Val = MmioRead32 (RasDesVSecBase + EVENT_COUNTER_CONTROL_REG_OFF);
+ if (RootComplex->Type == RootComplexTypeA) {
+ // RootComplexTypeA - 4 PCIe controller per port, 1 controller in charge of 4 lanes
+ Val = ECCR_LANE_SEL_SET (Val, PcieIndex*4);
+ } else {
+ // RootComplexTypeB - 8 PCIe controller per port, 1 controller in charge of 2 lanes
+ Val = ECCR_LANE_SEL_SET (Val, PcieIndex*2);
+ }
+ Val = ECCR_GROUP_EVENT_SEL_SET (Val, ErrCtrlCfg[ErrCode]);
+ MmioWrite32 (RasDesVSecBase + EVENT_COUNTER_CONTROL_REG_OFF, Val);
+
+ // After setting Counter Control reg
+ // This delay just to make sure Counter Data reg is update with new value
+ MicroSecondDelay (1);
+ Val = MmioRead32 (RasDesVSecBase + EVENT_COUNTER_DATA_REG_OFF);
+ if (Val != 0) {
+ Ret = LINK_CHECK_FAILED;
+ DEBUG ((
+ DEBUG_ERROR,
+ "\tSocket%d RootComplex%d RP%d \t%s: %d \tGROUP:%d-EVENT:%d\n",
+ RootComplex->Socket,
+ RootComplex->ID,
+ PcieIndex,
+ Val,
+ ((ErrCtrlCfg[ErrCode] & 0xF00) >> 8), // Group
+ (ErrCtrlCfg[ErrCode] & 0x0FF) // Event
+ ));
+ }
+ }
+ }
+
+ return Ret;
+}
+
+INT32
+Ac01PFAEnableAll (
+ IN AC01_ROOT_COMPLEX *RootComplex,
+ IN UINT8 PcieIndex,
+ IN INTN PFAMode
+ )
+{
+ PHYSICAL_ADDRESS CfgAddr;
+ PHYSICAL_ADDRESS RasDesVSecBase;
+ INT32 Ret = LINK_CHECK_SUCCESS;
+ UINT32 Val;
+
+ CfgAddr = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << 15);
+
+ // Allow programming to config space
+ Val = MmioRead32 (CfgAddr + MISC_CONTROL_1_OFF);
+ Val = DBI_RO_WR_EN_SET (Val, 1);
+ MmioWrite32 (CfgAddr + MISC_CONTROL_1_OFF, Val);
+
+ // Generate the RAS DES capability address
+ // RAS_DES_CAP_ID = 0xB
+ RasDesVSecBase = PcieCheckCap (RootComplex, PcieIndex, TRUE, RAS_DES_CAP_ID);
+ if (RasDesVSecBase == 0) {
+ DEBUG ((DEBUG_INFO, "PCIE%d.%d: Cannot get RAS DES capability address\n", RootComplex->ID, PcieIndex));
+ return LINK_CHECK_WRONG_PARAMETER;
+ }
+
+ if (PFAMode == PFA_REG_ENABLE) {
+ // PFA Counters Enable
+ Val = MmioRead32 (RasDesVSecBase + EVENT_COUNTER_CONTROL_REG_OFF);
+ Val = ECCR_EVENT_COUNTER_ENABLE_SET (Val, 0x7);
+ Val = ECCR_EVENT_COUNTER_CLEAR_SET (Val, 0);
+ MmioWrite32 (RasDesVSecBase + EVENT_COUNTER_CONTROL_REG_OFF, Val);
+ } else if (PFAMode == PFA_REG_CLEAR) {
+ // PFA Counters Clear
+ Val = MmioRead32 (RasDesVSecBase + EVENT_COUNTER_CONTROL_REG_OFF);
+ Val = ECCR_EVENT_COUNTER_ENABLE_SET (Val, 0);
+ Val = ECCR_EVENT_COUNTER_CLEAR_SET (Val, 0x3);
+ MmioWrite32 (RasDesVSecBase + EVENT_COUNTER_CONTROL_REG_OFF, Val);
+ } else {
+ // PFA Counters Read
+ Ret = PFACounterRead (RootComplex, PcieIndex, RasDesVSecBase);
+ }
+
+ // Disable programming to config space
+ Val = MmioRead32 (CfgAddr + MISC_CONTROL_1_OFF);
+ Val = DBI_RO_WR_EN_SET (Val, 0);
+ MmioWrite32 (CfgAddr + MISC_CONTROL_1_OFF, Val);
+
+ return Ret;
+}
+
+UINT32
+CheckEndpointCfg (
+ IN AC01_ROOT_COMPLEX *RootComplex,
+ IN UINT8 PcieIndex
+ )
+{
+ PHYSICAL_ADDRESS EpCfgAddr;
+ UINT32 TimeOut;
+ UINT32 Val;
+
+ EpCfgAddr = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << 20); /* Bus 1, dev 0, func 0 */
+
+ // Loop read EpCfgAddr value until got valid value or
+ // reach to timeout EP_LINKUP_TIMEOUT (or more depend on card)
+ TimeOut = EP_LINKUP_TIMEOUT;
+ do {
+ Val = MmioRead32 (EpCfgAddr);
+ if (Val != 0xFFFF0001 && Val != 0xFFFFFFFF) {
+ break;
+ }
+ MicroSecondDelay (LINK_WAIT_INTERVAL_US);
+ TimeOut -= LINK_WAIT_INTERVAL_US;
+ } while (TimeOut > 0);
+
+ return MmioRead32 (EpCfgAddr);
+}
+
+VOID
+GetEndpointInfo (
+ IN AC01_ROOT_COMPLEX *RootComplex,
+ IN UINT8 PcieIndex,
+ OUT UINT8 *EpMaxWidth,
+ OUT UINT8 *EpMaxGen
+ )
+{
+ PHYSICAL_ADDRESS PcieCapBaseAddr;
+ UINT32 Val;
+
+ Val = CheckEndpointCfg (RootComplex, PcieIndex);
+ if (Val == 0xFFFFFFFF) {
+ *EpMaxWidth = 0; // Invalid Width
+ *EpMaxGen = 0; // Invalid Speed
+ DEBUG ((DEBUG_ERROR, "PCIE%d.%d Cannot access EP config space!\n", RootComplex->ID, PcieIndex));
+ } else {
+ PcieCapBaseAddr = PcieCheckCap (RootComplex, PcieIndex, FALSE, CAP_ID);
+ if (PcieCapBaseAddr == 0) {
+ *EpMaxWidth = 0; // Invalid Width
+ *EpMaxGen = 0; // Invalid Speed
+ DEBUG ((
+ DEBUG_ERROR,
+ "PCIE%d.%d Cannot get PCIe capability extended address!\n",
+ RootComplex->ID,
+ PcieIndex
+ ));
+ } else {
+ Val = MmioRead32 (PcieCapBaseAddr + LINK_CAPABILITIES_REG_OFF);
+ *EpMaxWidth = (Val >> 4) & 0x3F;
+ *EpMaxGen = Val & 0xF;
+ DEBUG ((
+ DEBUG_INFO,
+ "PCIE%d.%d EP MaxWidth %d EP MaxGen %d \n", RootComplex->ID,
+ PcieIndex,
+ *EpMaxWidth,
+ *EpMaxGen
+ ));
+
+ // From EP, enabling common clock for upstream
+ Val = MmioRead32 (PcieCapBaseAddr + LINK_CONTROL_LINK_STATUS_OFF);
+ Val = CAP_SLOT_CLK_CONFIG_SET (Val, 1);
+ Val = CAP_COMMON_CLK_SET (Val, 1);
+ MmioWrite32 (PcieCapBaseAddr + LINK_CONTROL_LINK_STATUS_OFF, Val);
+ }
+ }
+}
+
+/**
+ Get link capabilities link width and speed of endpoint
+
+ @param RootComplex[in] Pointer to AC01_ROOT_COMPLEX structure
+ @param PcieIndex[in] PCIe controller index
+ @param EpMaxWidth[out] EP max link width
+ @param EpMaxGen[out] EP max link speed
+**/
+VOID
+Ac01PcieCoreGetEndpointInfo (
+ IN AC01_ROOT_COMPLEX *RootComplex,
+ IN UINT8 PcieIndex,
+ OUT UINT8 *EpMaxWidth,
+ OUT UINT8 *EpMaxGen
+ )
+{
+ PHYSICAL_ADDRESS RcCfgAddr;
+ UINT32 Val, RestoreVal;
+
+ RcCfgAddr = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << 15);
+
+ // Allow programming to config space
+ Val = MmioRead32 (RcCfgAddr + MISC_CONTROL_1_OFF);
+ Val = DBI_RO_WR_EN_SET (Val, 1);
+ MmioWrite32 (RcCfgAddr + MISC_CONTROL_1_OFF, Val);
+
+ Val = MmioRead32 (RcCfgAddr + SEC_LAT_TIMER_SUB_BUS_SEC_BUS_PRI_BUS_REG);
+ RestoreVal = Val;
+ Val = SUB_BUS_SET (Val, DEFAULT_SUB_BUS); /* Set DEFAULT_SUB_BUS to Subordinate bus */
+ Val = SEC_BUS_SET (Val, RootComplex->Pcie[PcieIndex].DevNum); /* Set RootComplex->Pcie[PcieIndex].DevNum to Secondary bus */
+ Val = PRIM_BUS_SET (Val, 0x0); /* Set 0x0 to Primary bus */
+ MmioWrite32 (RcCfgAddr + SEC_LAT_TIMER_SUB_BUS_SEC_BUS_PRI_BUS_REG, Val);
+
+ GetEndpointInfo (RootComplex, PcieIndex, EpMaxWidth, EpMaxGen);
+
+ // Restore value in order to not affect enumeration process
+ MmioWrite32 (RcCfgAddr + SEC_LAT_TIMER_SUB_BUS_SEC_BUS_PRI_BUS_REG, RestoreVal);
+
+ // Disable programming to config space
+ Val = MmioRead32 (RcCfgAddr + MISC_CONTROL_1_OFF);
+ Val = DBI_RO_WR_EN_SET (Val, 0);
+ MmioWrite32 (RcCfgAddr + MISC_CONTROL_1_OFF, Val);
+}
+
+VOID
+PollLinkUp (
+ IN AC01_ROOT_COMPLEX *RootComplex,
+ IN UINT8 PcieIndex
+ )
+{
+ UINT32 TimeOut;
+
+ // Poll until link up
+ // This checking for linkup status and
+ // give LTSSM state the time to transit from DECTECT state to L0 state
+ // Total delay are 100ms, smaller number of delay cannot always make sure
+ // the state transition is completed
+ TimeOut = LTSSM_TRANSITION_TIMEOUT;
+ do {
+ if (PcieLinkUpCheck (&RootComplex->Pcie[PcieIndex])) {
+ DEBUG ((
+ DEBUG_INFO,
+ "\tPCIE%d.%d LinkStat is correct after soft reset, transition time: %d\n",
+ RootComplex->ID,
+ PcieIndex,
+ TimeOut
+ ));
+ RootComplex->Pcie[PcieIndex].LinkUp = TRUE;
+ break;
+ }
+
+ MicroSecondDelay (100);
+ TimeOut -= 100;
+ } while (TimeOut > 0);
+
+ if (TimeOut <= 0) {
+ DEBUG ((DEBUG_ERROR, "\tPCIE%d.%d LinkStat TIMEOUT after re-init\n", RootComplex->ID, PcieIndex));
+ } else {
+ DEBUG ((DEBUG_INFO, "PCIE%d.%d Link re-initialization passed!\n", RootComplex->ID, PcieIndex));
+ }
+}
+
+/**
+ Check active PCIe controllers of RootComplex, retrain or soft reset if needed
+
+ @param RootComplex[in] Pointer to AC01_ROOT_COMPLEX structure
+ @param PcieIndex[in] PCIe controller index
+
+ @retval -1: Link recovery had failed
+ 1: Link width and speed are not correct
+ 0: Link recovery succeed
+**/
+INT32
+Ac01PcieCoreQoSLinkCheckRecovery (
+ IN AC01_ROOT_COMPLEX *RootComplex,
+ IN UINT8 PcieIndex
+ )
+{
+ INT32 NumberOfReset = MAX_REINIT; // Number of soft reset retry
+ UINT8 EpMaxWidth, EpMaxGen;
+ INT32 LinkStatusCheck, RasdesChecking;
+
+ // PCIe controller is not active or Link is not up
+ // Nothing to be done
+ if ((!RootComplex->Pcie[PcieIndex].Active) || (!RootComplex->Pcie[PcieIndex].LinkUp)) {
+ return LINK_CHECK_WRONG_PARAMETER;
+ }
+
+ do {
+
+ if (RootComplex->Pcie[PcieIndex].LinkUp) {
+ // Enable all of RASDES register to detect any training error
+ Ac01PFAEnableAll (RootComplex, PcieIndex, PFA_REG_ENABLE);
+
+ // Accessing Endpoint and checking current link capabilities
+ Ac01PcieCoreGetEndpointInfo (RootComplex, PcieIndex, &EpMaxWidth, &EpMaxGen);
+ LinkStatusCheck = Ac01PcieCoreLinkCheck (RootComplex, PcieIndex, EpMaxWidth, EpMaxGen);
+
+ // Delay to allow the link to perform internal operation and generate
+ // any error status update. This allows detection of any error observed
+ // during initial link training. Possible evaluation time can be
+ // between 100ms to 200ms.
+ MicroSecondDelay (100000);
+
+ // Check for error
+ RasdesChecking = Ac01PFAEnableAll (RootComplex, PcieIndex, PFA_REG_READ);
+
+ // Clear error counter
+ Ac01PFAEnableAll (RootComplex, PcieIndex, PFA_REG_CLEAR);
+
+ // If link check functions return passed, then breaking out
+ // else go to soft reset
+ if (LinkStatusCheck != LINK_CHECK_FAILED &&
+ RasdesChecking != LINK_CHECK_FAILED &&
+ PcieLinkUpCheck (&RootComplex->Pcie[PcieIndex]))
+ {
+ return LINK_CHECK_SUCCESS;
+ }
+
+ RootComplex->Pcie[PcieIndex].LinkUp = FALSE;
+ }
+
+ // Trigger controller soft reset
+ DEBUG ((DEBUG_INFO, "PCIE%d.%d Start link re-initialization..\n", RootComplex->ID, PcieIndex));
+ Ac01PcieCoreSetupRC (RootComplex, TRUE, PcieIndex);
+
+ PollLinkUp (RootComplex, PcieIndex);
+
+ NumberOfReset--;
+ } while (NumberOfReset > 0);
+
+ return LINK_CHECK_SUCCESS;
+}
+
+VOID
+Ac01PcieCoreUpdateLink (
+ IN AC01_ROOT_COMPLEX *RootComplex,
+ OUT BOOLEAN *IsNextRoundNeeded,
+ OUT INT8 *FailedPciePtr,
+ OUT INT8 *FailedPcieCount
+ )
+{
+ AC01_PCIE_CONTROLLER *Pcie;
+ PHYSICAL_ADDRESS CfgAddr;
+ UINT8 PcieIndex;
+ UINT32 Index;
+ UINT32 Val;
+
+ *IsNextRoundNeeded = FALSE;
+ *FailedPcieCount = 0;
+ for (Index = 0; Index < MaxPcieControllerB; Index++) {
+ FailedPciePtr[Index] = -1;
+ }
+
+ if (!RootComplex->Active) {
+ return;
+ }
+
+ // Loop for all controllers
+ for (PcieIndex = 0; PcieIndex < RootComplex->MaxPcieController; PcieIndex++) {
+ Pcie = &RootComplex->Pcie[PcieIndex];
+ CfgAddr = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << 15);
+
+ if (Pcie->Active && !Pcie->LinkUp) {
+ if (PcieLinkUpCheck (Pcie)) {
+ Pcie->LinkUp = TRUE;
+ Val = MmioRead32 (CfgAddr + LINK_CONTROL_LINK_STATUS_REG);
+ DEBUG ((
+ DEBUG_INFO,
+ "%a Socket%d RootComplex%d RP%d NEGO_LINK_WIDTH: 0x%x LINK_SPEED: 0x%x\n",
+ __FUNCTION__,
+ RootComplex->Socket,
+ RootComplex->ID,
+ PcieIndex,
+ CAP_NEGO_LINK_WIDTH_GET (Val),
+ CAP_LINK_SPEED_GET (Val)
+ ));
+
+ // Doing link checking and recovery if needed
+ Ac01PcieCoreQoSLinkCheckRecovery (RootComplex, PcieIndex);
+
+ // Un-mask Completion Timeout
+ MaskCompletionTimeOut (RootComplex, PcieIndex, 32, FALSE);
+
+ } else {
+ *IsNextRoundNeeded = FALSE;
+ FailedPciePtr[*FailedPcieCount] = PcieIndex;
+ *FailedPcieCount += 1;
+ }
+ }
+ }
+}
+
+/**
+ Verify the link status and retry to initialize the Root Complex if there's any issue.
+
+ @param RootComplexList Pointer to the Root Complex list
+**/
+VOID
+Ac01PcieCorePostSetupRC (
+ IN AC01_ROOT_COMPLEX *RootComplexList
+ )
+{
+ UINT8 RCIndex, Idx;
+ BOOLEAN IsNextRoundNeeded = FALSE, NextRoundNeeded;
+ UINT64 PrevTick, CurrTick, ElapsedCycle;
+ UINT64 TimerTicks64;
+ UINT8 ReInit;
+ INT8 FailedPciePtr[MaxPcieControllerB];
+ INT8 FailedPcieCount;
+
+ ReInit = 0;
+
+_link_polling:
+ NextRoundNeeded = 0;
+ //
+ // It is not guaranteed the timer service is ready prior to PCI Dxe.
+ // Calculate system ticks for link training.
+ //
+ TimerTicks64 = ArmGenericTimerGetTimerFreq (); /* 1 Second */
+ PrevTick = ArmGenericTimerGetSystemCount ();
+ ElapsedCycle = 0;
+
+ do {
+ CurrTick = ArmGenericTimerGetSystemCount ();
+ if (CurrTick < PrevTick) {
+ ElapsedCycle += (UINT64)(~0x0ULL) - PrevTick;
+ PrevTick = 0;
+ }
+ ElapsedCycle += (CurrTick - PrevTick);
+ PrevTick = CurrTick;
+ } while (ElapsedCycle < TimerTicks64);
+
+ for (RCIndex = 0; RCIndex < AC01_PCIE_MAX_ROOT_COMPLEX; RCIndex++) {
+ Ac01PcieCoreUpdateLink (&RootComplexList[RCIndex], &IsNextRoundNeeded, FailedPciePtr, &FailedPcieCount);
+ if (IsNextRoundNeeded) {
+ NextRoundNeeded = 1;
+ }
+ }
+
+ if (NextRoundNeeded && ReInit < MAX_REINIT) {
+ //
+ // Timer is up. Give another chance to re-program controller
+ //
+ ReInit++;
+ for (RCIndex = 0; RCIndex < AC01_PCIE_MAX_ROOT_COMPLEX; RCIndex++) {
+ Ac01PcieCoreUpdateLink (&RootComplexList[RCIndex], &IsNextRoundNeeded, FailedPciePtr, &FailedPcieCount);
+ if (IsNextRoundNeeded) {
+ for (Idx = 0; Idx < FailedPcieCount; Idx++) {
+ if (FailedPciePtr[Idx] == -1) {
+ continue;
+ }
+
+ //
+ // Some controller still observes link-down. Re-init controller
+ //
+ Ac01PcieCoreSetupRC (&RootComplexList[RCIndex], TRUE, FailedPciePtr[Idx]);
+ }
+ }
+ }
+
+ goto _link_polling;
+ }
+}
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/BoardPcieLibNull/BoardPcieLibNull.c b/Silicon/Ampere/AmpereAltraPkg/Library/BoardPcieLibNull/BoardPcieLibNull.c
new file mode 100644
index 000000000000..0916adb77539
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/BoardPcieLibNull/BoardPcieLibNull.c
@@ -0,0 +1,47 @@
+/** @file
+
+ Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BoardPcieLib.h>
+
+/**
+ Assert PERST of input PCIe controller
+
+ @param[in] RootComplex RootComplex instance.
+ @param[in] PcieIndex PCIe controller index of input Root Complex.
+ @param[in] Bifurcation Bifurcation mode of input Root Complex.
+ @param[in] IsPullToHigh Target status for the PERST.
+
+ @retval RETURN_SUCCESS The operation is successful.
+ @retval Others An error occurred.
+**/
+RETURN_STATUS
+EFIAPI
+BoardPcieAssertPerst (
+ IN AC01_ROOT_COMPLEX *RootComplex,
+ IN UINT8 PcieIndex,
+ IN BOOLEAN IsPullToHigh
+ )
+{
+ return RETURN_SUCCESS;
+}
+
+/**
+ Override the segment number for a root complex with a board specific number.
+
+ @param[in] RootComplex Root Complex instance with properties.
+
+ @retval Segment number corresponding to the input root complex.
+ Default segment number is 0x0F.
+**/
+UINT16
+BoardPcieGetSegmentNumber (
+ IN AC01_ROOT_COMPLEX *RootComplex
+ )
+{
+ return 0x0F;
+}
--
2.17.1
next prev parent reply other threads:[~2021-10-22 6:20 UTC|newest]
Thread overview: 56+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-10-22 6:17 [edk2-platforms][PATCH v4 00/31] Add new Ampere Mt. Jade platform Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 01/31] Ampere: Initial support for Ampere Altra processor and " Nhi Pham
2021-10-26 11:14 ` Leif Lindholm
2021-11-03 9:31 ` Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 02/31] AmpereAltraPkg: Add FlashLib library instance Nhi Pham
2021-10-26 11:25 ` Leif Lindholm
2021-11-03 9:32 ` Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 03/31] AmpereAltraPkg: Add FailSafe and WDT support Nhi Pham
2021-10-26 12:15 ` Leif Lindholm
2021-11-03 9:35 ` Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 04/31] AmpereAltraPkg: Add DwI2cLib library instance Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 05/31] AmpereAltraPkg: Add DwGpioLib " Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 06/31] JadePkg: Implement RealTimeClockLib for PCF85063 Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 07/31] AmpereAltraPkg: Add BootProgress support Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 08/31] AmpereAltraPkg: Support UEFI non-volatile variable Nhi Pham
2021-10-26 12:21 ` Leif Lindholm
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 09/31] AmpereSiliconPkg: Add PlatformManagerUiLib library instance Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 10/31] AmpereAltraPkg, JadePkg: Add ACPI support Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 11/31] AmpereAltraPkg: Add Root Complex HOB data structures Nhi Pham
2021-10-26 12:23 ` Leif Lindholm
2021-10-22 6:17 ` Nhi Pham [this message]
2021-10-26 12:45 ` [edk2-platforms][PATCH v4 12/31] AmpereAltraPkg: Add Ac01PcieLib library instance Leif Lindholm
2021-11-03 9:33 ` Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 13/31] JadePkg: Add BoardPcieLib " Nhi Pham
2021-10-26 12:46 ` Leif Lindholm
2021-11-03 9:33 ` Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 14/31] AmpereAltraPkg: Add driver to initialize PCIe Root Complex Nhi Pham
2021-10-26 12:49 ` Leif Lindholm
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 15/31] AmpereAltraPkg: Add PciHostBridgeLib library instance Nhi Pham
2021-10-26 12:49 ` Leif Lindholm
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 16/31] AmpereAltraPkg: Add PciSegmentLib " Nhi Pham
2021-10-26 12:53 ` Leif Lindholm
2021-11-03 9:35 ` Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 17/31] JadePkg: Enable PciHostBridgeDxe driver Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 18/31] JadePkg: Add PciPlatformDxe driver Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 19/31] JadePkg: Add ACPI tables to support PCIe Nhi Pham
2021-10-26 12:54 ` Leif Lindholm
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 20/31] JadePkg: Add ASpeed GOP driver Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 21/31] AmpereAltraPkg: Add Random Number Generator Support Nhi Pham
2021-10-22 6:18 ` [edk2-platforms][PATCH v4 22/31] JadePkg: Add SMBIOS tables support Nhi Pham
2021-10-22 6:18 ` [edk2-platforms][PATCH v4 23/31] AmpereAltraPkg: Add DebugInfoPei module Nhi Pham
2021-10-22 6:18 ` [edk2-platforms][PATCH v4 24/31] AmpereAltraPkg: Add configuration screen for PCIe Nhi Pham
2021-10-26 12:56 ` Leif Lindholm
2021-10-22 6:18 ` [edk2-platforms][PATCH v4 25/31] Ampere: Utilize the PCIe User setting Nhi Pham
2021-10-26 12:57 ` Leif Lindholm
2021-10-22 6:18 ` [edk2-platforms][PATCH v4 26/31] AmpereAltraPkg: Add platform info screen Nhi Pham
2021-10-22 6:18 ` [edk2-platforms][PATCH v4 27/31] AmpereAltraPkg: Add configuration screen for Memory Nhi Pham
2021-10-26 12:58 ` Leif Lindholm
2021-10-22 6:18 ` [edk2-platforms][PATCH v4 28/31] AmpereAltraPkg: Add configuration screen for CPU Nhi Pham
2021-10-22 6:18 ` [edk2-platforms][PATCH v4 29/31] AmpereAltraPkg: Add configuration screen for ACPI Nhi Pham
2021-10-22 6:18 ` [edk2-platforms][PATCH v4 30/31] AmpereAltraPkg: Add configuration screen for RAS Nhi Pham
2021-10-22 6:18 ` [edk2-platforms][PATCH v4 31/31] AmpereAltraPkg: Add configuration screen for Watchdog timer Nhi Pham
2021-10-26 13:03 ` Leif Lindholm
2021-11-03 9:36 ` Nhi Pham
2021-10-26 13:08 ` [edk2-platforms][PATCH v4 00/31] Add new Ampere Mt. Jade platform Leif Lindholm
2021-11-03 9:37 ` Nhi Pham
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20211022061809.31087-13-nhi@os.amperecomputing.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox