[edk2-devel] [edk2-platforms][PATCH 12/34] AmpereAltraPkg: Add PcieCore Library

Nhi Pham via groups.io nhi=os.amperecomputing.com at groups.io
Wed Dec 9 09:25:09 UTC 2020


From: Vu Nguyen <vunguyen at os.amperecomputing.com>

Support low level hardware functions for both PCIe RCA and RCB
controllers on Ampere Altra. These will be used by PcieHostBridge
driver to complete hardware initialize and link equalize as well.

Signed-off-by: Vu Nguyen <vunguyen at os.amperecomputing.com>
---
 Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec                          |    3 +
 Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dsc.inc                      |    1 +
 Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PcieCoreLib.inf     |   63 +
 Silicon/Ampere/AmpereAltraPkg/Include/Library/PciHostBridgeElink.h |   58 +
 Silicon/Ampere/AmpereAltraPkg/Include/Library/PcieBoardLib.h       |   99 ++
 Silicon/Ampere/AmpereAltraPkg/Include/PciBus.h                     |   38 +
 Silicon/Ampere/AmpereAltraPkg/Include/Pcie.h                       |  232 ++++
 Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PcieCore.h          |  576 +++++++++
 Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PcieCoreCapCfg.h    |   64 +
 Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PciePatchAcpi.h     |   30 +
 Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PcieCore.c          | 1246 ++++++++++++++++++++
 Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PcieCoreLib.c       |  492 ++++++++
 Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PciePatchAcpi.c     |  607 ++++++++++
 13 files changed, 3509 insertions(+)

diff --git a/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec b/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec
index cc513d8ac69f..267d6cc74e0b 100644
--- a/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec
+++ b/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec
@@ -34,6 +34,9 @@ [LibraryClasses]
   ##  @libraryclass  Defines a set of methods to communicate with secure parition over MM interface.
   MmCommunicationLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/MmCommunicationLib.h
 
+  ##  @libraryclass  Defines a set of miscellaneous PCIe functions
+  PcieBoardLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/PcieBoardLib.h
+
   ##  @libraryclass  Defines a set of methods to communicate with PMPro.
   PMProLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/PMProLib.h
 
diff --git a/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dsc.inc b/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dsc.inc
index bb583d6f75ef..bb0e5edc3dd7 100755
--- a/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dsc.inc
+++ b/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dsc.inc
@@ -87,6 +87,7 @@ [LibraryClasses.common]
   NVParamLib|Silicon/Ampere/AmpereAltraPkg/Library/NVParamLib/NVParamLib.inf
   SMProLib|Silicon/Ampere/AmpereAltraPkg/Library/SMProLib/SMProLib.inf
   PMProLib|Silicon/Ampere/AmpereAltraPkg/Library/PMProLib/PMProLib.inf
+  PciePhyLib|Silicon/Ampere/AmpereAltraBinPkg/Library/PciePhyLib/PciePhyLib.inf
   AmpereCpuLib|Silicon/Ampere/AmpereAltraPkg/Library/AmpereCpuLib/AmpereCpuLib.inf
   TimeBaseLib|EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.inf
   I2CLib|Silicon/Ampere/AmpereAltraPkg/Library/DWI2CLib/I2CLib.inf
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PcieCoreLib.inf b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PcieCoreLib.inf
new file mode 100755
index 000000000000..17ceb12778dc
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PcieCoreLib.inf
@@ -0,0 +1,63 @@
+## @file
+#
+# Copyright (c) 2020, Ampere Computing LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x0001001B
+  BASE_NAME                      = PcieCore
+  FILE_GUID                      = 8ABFA0FC-313E-11E8-B467-0ED5F89F718B
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = PcieCoreLib
+
+[Sources]
+  PcieCore.c
+  PcieCoreLib.c
+  PciePatchAcpi.c
+  PciePatchAcpi.h
+  PcieCore.h
+  PcieCoreCapCfg.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  ArmPkg/ArmPkg.dec
+  ArmPlatformPkg/ArmPlatformPkg.dec
+  Silicon/Ampere/AmperePkg.dec
+  Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec
+  Silicon/Ampere/AmpereAltraBinPkg/Ac01BinPkg.dec
+
+[BuildOptions]
+  *_*_*_CC_FLAGS = -Wno-error=switch -Wno-missing-braces
+
+[LibraryClasses]
+  UefiLib
+  MemoryAllocationLib
+  BaseMemoryLib
+  BaseLib
+  DebugLib
+  DwapbGpioLib
+  TimerLib
+  ArmLib
+  IoLib
+  PcdLib
+  PcieBoardLib
+  UefiBootServicesTableLib
+  UefiRuntimeServicesTableLib
+  PciePhyLib
+  SMProLib
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision
+
+[Protocols]
+  gEfiAcpiTableProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+  gEfiAcpiSdtProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+
+[Depex]
+    gEfiAcpiTableProtocolGuid AND gEfiAcpiSdtProtocolGuid
diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Library/PciHostBridgeElink.h b/Silicon/Ampere/AmpereAltraPkg/Include/Library/PciHostBridgeElink.h
new file mode 100644
index 000000000000..14f975158640
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Include/Library/PciHostBridgeElink.h
@@ -0,0 +1,58 @@
+/** @file
+
+  Copyright (c) 2020, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PCI_HOST_BRIDGE_ELINK_H_
+#define _PCI_HOST_BRIDGE_ELINK_H_
+
+#include <Protocol/PciHostBridgeResourceAllocation.h>
+
+typedef BOOLEAN (PCI_CHECK_ROOT_BRIDGE_DISABLED_FUNC)(IN UINTN, IN UINTN);
+#define PCI_CHECK_ROOT_BRIDGE_DISABLED Ac01PcieCheckRootBridgeDisabled
+extern PCI_CHECK_ROOT_BRIDGE_DISABLED_FUNC PCI_CHECK_ROOT_BRIDGE_DISABLED;
+
+typedef EFI_STATUS (PCI_CORE_SETUP_FUNC)(EFI_HANDLE, EFI_SYSTEM_TABLE*);
+#define PCI_CORE_SETUP Ac01PcieSetup
+extern PCI_CORE_SETUP_FUNC PCI_CORE_SETUP;
+
+typedef EFI_STATUS (PCI_CORE_END_FUNC)(VOID);
+#define PCI_CORE_END Ac01PcieEnd
+extern PCI_CORE_END_FUNC PCI_CORE_END;
+
+typedef UINTN (PCI_GET_NUMBER_HOSTBRIDGE_FUNC)(VOID);
+#define PCI_GET_NUMBER_HOSTBRIDGE Ac01PcieGetTotalHBs
+extern PCI_GET_NUMBER_HOSTBRIDGE_FUNC PCI_GET_NUMBER_HOSTBRIDGE;
+
+typedef UINTN (PCI_GET_NUMBER_ROOTBRIDGE_FUNC)(UINTN);
+#define PCI_GET_NUMBER_ROOTBRIDGE Ac01PcieGetTotalRBsPerHB
+extern PCI_GET_NUMBER_ROOTBRIDGE_FUNC PCI_GET_NUMBER_ROOTBRIDGE;
+
+typedef UINTN (PCI_GET_ROOTBRIDGE_ATTR_FUNC)(UINTN);
+#define PCI_GET_ROOTBRIDGE_ATTR Ac01PcieGetRootBridgeAttribute
+extern PCI_GET_ROOTBRIDGE_ATTR_FUNC PCI_GET_ROOTBRIDGE_ATTR;
+
+typedef UINTN (PCI_GET_ROOTBRIDGE_SEGMENTNUMBER_FUNC)(UINTN, UINTN);
+#define PCI_GET_ROOTBRIDGE_SEGMENTNUMBER Ac01PcieGetRootBridgeSegmentNumber
+extern PCI_GET_ROOTBRIDGE_SEGMENTNUMBER_FUNC PCI_GET_ROOTBRIDGE_SEGMENTNUMBER;
+
+typedef EFI_STATUS (PCI_CORE_SETUP_HOST_BRIDGE_FUNC)(IN UINTN);
+#define PCI_CORE_SETUP_HOST_BRIDGE Ac01PcieSetupHostBridge
+extern PCI_CORE_SETUP_HOST_BRIDGE_FUNC PCI_CORE_SETUP_HOST_BRIDGE;
+
+typedef EFI_STATUS (PCI_CORE_SETUP_ROOT_BRIDGE_FUNC)(IN UINTN, IN UINTN, IN PCI_ROOT_BRIDGE *);
+#define PCI_CORE_SETUP_ROOT_BRIDGE Ac01PcieSetupRootBridge
+extern PCI_CORE_SETUP_ROOT_BRIDGE_FUNC PCI_CORE_SETUP_ROOT_BRIDGE;
+
+typedef EFI_STATUS (PCI_CORE_IO_PCI_RW_FUNC)(IN VOID *, IN UINT64, IN BOOLEAN, IN UINTN, IN OUT VOID *);
+#define PCI_CORE_IO_PCI_RW Ac01PcieConfigRW
+extern  PCI_CORE_IO_PCI_RW_FUNC PCI_CORE_IO_PCI_RW;
+
+typedef VOID (PCI_CORE_HOST_BRIDGE_NOTIFY_PHASE_FUNC)(IN UINTN, IN UINTN, IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE);
+#define PCI_CORE_HOST_BRIDGE_NOTIFY_PHASE Ac01PcieHostBridgeNotifyPhase
+extern PCI_CORE_HOST_BRIDGE_NOTIFY_PHASE_FUNC PCI_CORE_HOST_BRIDGE_NOTIFY_PHASE;
+
+#endif /* _PCI_HOST_BRIDGE_ELINK_H_ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Library/PcieBoardLib.h b/Silicon/Ampere/AmpereAltraPkg/Include/Library/PcieBoardLib.h
new file mode 100755
index 000000000000..e8461aa16591
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Include/Library/PcieBoardLib.h
@@ -0,0 +1,99 @@
+/** @file
+
+  Copyright (c) 2020, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PCIE_BOARD_LIB_H_
+#define _PCIE_BOARD_LIB_H_
+
+#include "Pcie.h"
+
+/**
+
+  Check if a PCIE port enabled in the board configuration.
+
+  @param  Index                     The port index.
+
+  @retval                           TRUE if the port enabled, otherwise FALSE.
+
+**/
+BOOLEAN
+PcieBoardCheckSysSlotEnabled (
+  IN UINTN Index
+  );
+
+VOID
+PcieBoardGetRCSegmentNumber (
+  IN  AC01_RC *RC,
+  OUT UINTN   *SegmentNumber
+  );
+
+/**
+
+  Check if SMM PMU enabled in board screen
+
+  @retval                           TRUE if the SMMU PMU enabled, otherwise FALSE.
+
+**/
+BOOLEAN
+PcieBoardCheckSmmuPmuEnabled (VOID);
+
+/**
+
+  Build UEFI menu.
+
+  @param  ImageHandle               Handle.
+  @param  SystemTable               Pointer to System Table.
+  @param  RCList                    List of Root Complex with properties.
+
+  @retval                           EFI_SUCCESS if successful, otherwise EFI_ERROR.
+
+**/
+EFI_STATUS
+PcieBoardScreenInitialize (
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_SYSTEM_TABLE   *SystemTable,
+  IN AC01_RC            *RCList
+  );
+
+BOOLEAN IsEmptyRC (
+  IN   AC01_RC *RC
+  );
+
+VOID
+PcieBoardSetupDevmap (
+  IN   AC01_RC *RC
+  );
+
+VOID
+PcieBoardGetLaneAllocation (
+  IN   AC01_RC *RC
+  );
+
+VOID
+PcieBoardGetSpeed (
+  IN   AC01_RC *RC
+  );
+
+VOID
+PcieBoardParseRCParams (
+  IN   AC01_RC *RC
+  );
+
+VOID
+PcieBoardAssertPerst (
+  AC01_RC *RC,
+  UINT32 PcieIndex,
+  UINT8 Bifurcation,
+  BOOLEAN isPullToHigh
+  );
+
+BOOLEAN
+PcieBoardCheckSmmuPmuEnabled (
+  VOID
+  );
+
+#endif /* _PCIE_BOARD_LIB_H_ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/PciBus.h b/Silicon/Ampere/AmpereAltraPkg/Include/PciBus.h
new file mode 100755
index 000000000000..6b7fc83e8ca9
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Include/PciBus.h
@@ -0,0 +1,38 @@
+/** @file
+
+  Copyright (c) 2020, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __PCI_BUS_H_
+#define __PCI_BUS_H_
+
+/**
+ * This ENUM value definitions used to identify PCI Device different Resource types.
+ *
+ * Fields:
+ *  Name            Type                    Description
+ *  ------------------------------------------------------------------
+ *  rtBus           ENUM                Bus resources
+ *  rtIo16          ENUM                I/O 16bit Resources
+ *  rtIo32          ENUM                I/O 32bit Resources
+ *  rtMmio32        ENUM                MMIO 32bit Resources
+ *  rtMmio32p       ENUM                Prefetchable MMIO 32bit
+ *  rtMmio64        ENUM                MMIO 64bit Resources
+ *  rtMmio64p       ENUM                Prefetchable MMIO 64bit
+ *  rtMaxRes        ENUM                Last valid value of this ENUM
+ **/
+typedef enum {
+    rtBus=0,
+    rtIo16,        //1
+    rtIo32,        //2
+    rtMmio32,      //3
+    rtMmio32p,     //4
+    rtMmio64,      //5
+    rtMmio64p,     //6
+    rtMaxRes
+} MRES_TYPE;
+
+#endif /* __PCI_BUS_H_ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Pcie.h b/Silicon/Ampere/AmpereAltraPkg/Include/Pcie.h
new file mode 100755
index 000000000000..37880f5f56bd
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Include/Pcie.h
@@ -0,0 +1,232 @@
+/** @file
+
+  Copyright (c) 2020, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __PCIE_H__
+#define __PCIE_H__
+
+#define PCIE_CORE_DEBUG
+#define PCIE_CORE_CFG_DEBUG
+#undef PCIE_CORE_MMIO_DEBUG
+
+#ifdef PCIE_CORE_CFG_DEBUG
+#define PCIE_DEBUG_CFG(arg...)               \
+  if (DebugCodeEnabled()) {                  \
+    DEBUG ((DEBUG_INFO,"PCICore (DBG): "));  \
+    DEBUG ((DEBUG_INFO,## arg));             \
+  }
+#else
+#define PCIE_DEBUG_CFG(arg...)
+#endif
+
+#ifdef PCIE_CORE_CSR_DEBUG
+#define PCIE_CSR_DEBUG(arg...)               \
+  if (DebugCodeEnabled()) {                  \
+    DEBUG ((DEBUG_INFO,"PCICore (DBG): "));  \
+    DEBUG((DEBUG_INFO,## arg))               \
+  }
+#else
+#define PCIE_CSR_DEBUG(arg...)
+#endif
+
+#ifdef PCIE_CORE_PHY_DEBUG
+#define PCIE_PHY_DEBUG(arg...)               \
+  if (DebugCodeEnabled()) {                  \
+    DEBUG ((DEBUG_INFO,"PCICore (DBG): "));  \
+    DEBUG ((DEBUG_INFO,## arg))              \
+  }
+#else
+#define PCIE_PHY_DEBUG(arg...)
+#endif
+
+#ifdef PCIE_CORE_MMIO_DEBUG
+#define PCIE_DEBUG_MMIO(arg...)            \
+  DEBUG ((DEBUG_INFO,"PCICore (DBG): "));  \
+  DEBUG ((DEBUG_INFO,## arg))
+#else
+#define PCIE_DEBUG_MMIO(arg...)
+#endif
+
+#ifdef PCIE_CORE_DEBUG
+#define PCIE_DEBUG(arg...)                   \
+  if (DebugCodeEnabled()) {                  \
+    DEBUG ((DEBUG_INFO,"PCICore (DBG): "));  \
+    DEBUG ((DEBUG_INFO,## arg));             \
+  }
+#else
+#define PCIE_DEBUG(arg...)
+#endif
+
+#define PCIE_WARN(arg...)                   \
+  DEBUG ((DEBUG_WARN,"PCICore (WARN): "));  \
+  DEBUG ((DEBUG_WARN,## arg))
+
+#define PCIE_ERR(arg...)                      \
+  DEBUG ((DEBUG_ERROR,"PCICore (ERROR): "));  \
+  DEBUG ((DEBUG_ERROR,## arg))
+
+#define RCS_PER_SOCKET          8
+
+#define PCIE_ERRATA_SPEED1      0x0001 // Limited speed errata
+
+#define PRESET_INVALID          0xFF
+
+/* Max number for AC01 PCIE Root Complexes */
+#define MAX_AC01_PCIE_ROOT_COMPLEX   16
+
+/* Max number for AC01 PCIE Root Bridge under each Root Complex */
+#define MAX_AC01_PCIE_ROOT_BRIDGE    1
+
+/* The base address of {TCU, CSR, MMCONFIG} Registers */
+#define AC01_PCIE_REGISTER_BASE    0x33FFE0000000, 0x37FFE0000000, 0x3BFFE0000000, 0x3FFFE0000000, 0x23FFE0000000, 0x27FFE0000000, 0x2BFFE0000000, 0x2FFFE0000000, 0x73FFE0000000, 0x77FFE0000000, 0x7BFFE0000000, 0x7FFFE0000000, 0x63FFE0000000, 0x67FFE0000000, 0x6BFFE0000000, 0x6FFFE0000000
+
+/* The base address of MMIO Registers */
+#define AC01_PCIE_MMIO_BASE        0x300000000000, 0x340000000000, 0x380000000000, 0x3C0000000000, 0x200000000000, 0x240000000000, 0x280000000000, 0x2C0000000000, 0x700000000000, 0x740000000000, 0x780000000000, 0x7C0000000000, 0x600000000000, 0x640000000000, 0x680000000000, 0x6C0000000000
+
+/* The base address of MMIO32 Registers*/
+#define AC01_PCIE_MMIO32_BASE      0x000020000000, 0x000028000000, 0x000030000000, 0x000038000000, 0x000000800000, 0x000008000000, 0x000010000000, 0x000018000000, 0x000060000000, 0x000068000000, 0x000070000000, 0x000078000000, 0x000040000000, 0x000048000000, 0x000050000000, 0x000058000000
+
+/* The base address of MMIO32 Registers */
+#define AC01_PCIE_MMIO32_BASE_1P   0x000040000000, 0x000050000000, 0x000060000000, 0x000070000000, 0x000000800000, 0x000010000000, 0x000020000000, 0x000030000000, 0, 0, 0, 0, 0, 0, 0, 0
+
+/* A switch to enable PciBus Driver Debug messages over Serial Port. */
+#define PCI_BUS_DEBUG_MESSAGES    1
+
+/* DSDT RCA2 PCIe Meme32 Attribute */
+#define AC01_PCIE_RCA2_QMEM    0x0000000000000000, 0x0000000060000000, 0x000000006FFFFFFF, 0x0000000000000000, 0x0000000010000000
+
+/* DSDT RCA3 PCIe Meme32 Attribute */
+#define AC01_PCIE_RCA3_QMEM    0x0000000000000000, 0x0000000070000000, 0x000000007FFFFFFF, 0x0000000000000000, 0x0000000010000000
+
+/* DSDT RCB0 PCIe Meme32 Attribute */
+#define AC01_PCIE_RCB0_QMEM    0x0000000000000000, 0x0000000000800000, 0x000000000FFFFFFF, 0x0000000000000000, 0x000000000F800000
+
+/* DSDT RCB1 PCIe Meme32 Attribute */
+#define AC01_PCIE_RCB1_QMEM    0x0000000000000000, 0x0000000010000000, 0x000000001FFFFFFF, 0x0000000000000000, 0x0000000010000000
+
+/* DSDT RCB2 PCIe Meme32 Attribute*/
+#define AC01_PCIE_RCB2_QMEM    0x0000000000000000, 0x0000000020000000, 0x000000002FFFFFFF, 0x0000000000000000, 0x0000000010000000
+
+/* DSDT RCB3 PCIe Meme32 Attribute */
+#define AC01_PCIE_RCB3_QMEM    0x0000000000000000, 0x0000000030000000, 0x000000003FFFFFFF, 0x0000000000000000, 0x0000000010000000
+
+/* Ampere Pcie vendor ID */
+#define AMPERE_PCIE_VENDORID  0x1DEF
+
+/* Ampere Pcie device ID */
+#define AMPERE_PCIE_DEVICEID  0xE00D
+
+/* The start of TBU PMU IRQ array. */
+#define SMMU_TBU_PMU_IRQ_START_ARRAY  224, 230, 236, 242, 160, 170, 180, 190, 544, 550, 556, 562, 480, 490, 500, 510
+
+/* The start of TCU PMU IRQ array */
+#define SMMU_TCU_PMU_IRQ_START_ARRAY  256, 257, 258, 259, 260, 261, 262, 263, 576, 577, 578, 579, 580, 581, 582, 583
+
+/* Token Enabled to use PCIIO Mapped address for either DMA or PIO Data Transfer*/
+#define USE_PCIIO_MAP_ADDRESS_FOR_DATA_TRANSFER   1
+
+/* Pci Express Base Addrerss should come from CSP module */
+#define PCIEX_BASE_ADDRESS    0x00000000
+
+#define PCIEX_LENGTH          0x10000000
+/* Pci Express Extended Config Space length should come from CSP module */
+
+#define ISA_IRQ_MASK          0
+
+
+enum PCIE_LINK_WIDTH{
+  LNKW_NONE = 0,
+  LNKW_X1 = 0x1,
+  LNKW_X2 = 0x2,
+  LNKW_X4 = 0x4,
+  LNKW_X8 = 0x8,
+  LNKW_X16 = 0x10,
+};
+
+enum PCIE_LINK_SPEED {
+  SPEED_NONE = 0,
+  SPEED_GEN1 = 0x1,
+  SPEED_GEN2 = 0x2,
+  SPEED_GEN3 = 0x4,
+  SPEED_GEN4 = 0x8,
+};
+
+enum PCIE_CONTROLLER {
+  PCIE_0 = 0,
+  PCIE_1,
+  PCIE_2,
+  PCIE_3,
+  PCIE_4,
+  MAX_PCIE_A = PCIE_4,
+  PCIE_5,
+  PCIE_6,
+  PCIE_7,
+  MAX_PCIE,
+  MAX_PCIE_B = MAX_PCIE
+};
+
+enum RC_TYPE {
+  RCA,
+  RCB
+};
+
+enum RC_BLOCK {
+  RCA0 = 0,
+  RCA1,
+  RCA2,
+  RCA3,
+  MAX_RCA,
+  RCB0 = MAX_RCA,
+  RCB1,
+  RCB2,
+  RCB3,
+  MAX_RCB,
+  MAX_RC = MAX_RCB
+};
+
+typedef struct _AC01_PCIE {
+  UINT64        CsrAddr;                // Pointer to CSR Address
+  UINT64        SnpsRamAddr;            // Pointer to Synopsys SRAM address
+  UINT8         MaxGen;                 // Max speed Gen-1/-2/-3/-4
+  UINT8         CurGen;                 // Current speed Gen-1/-2/-3/-4
+  UINT8         MaxWidth;               // Max lanes x2/x4/x8/x16
+  UINT8         CurWidth;               // Current lanes x2/x4/x8/x16
+  UINT8         ID;                     // ID of the controller within Root Complex
+  UINT8         DevNum;                 // Device number as part of Bus:Dev:Func
+  BOOLEAN       Active;                 // Active? Used in bi-furcation mode
+  BOOLEAN       LinkUp;                 // PHY and PCIE linkup
+  BOOLEAN       HotPlug;                // Hotplug support
+} AC01_PCIE;
+
+typedef struct _AC01_RC {
+  UINT64        BaseAddr;
+  UINT64        TcuAddr;
+  UINT64        HBAddr;
+  UINT64        MsgAddr;
+  UINT64        SerdesAddr;
+  UINT64        MmcfgAddr;
+  UINT64        MmioAddr;
+  UINT64        Mmio32Addr;
+  UINT64        IoAddr;
+  AC01_PCIE     Pcie[MAX_PCIE_B];
+  UINT8         MaxPcieController;
+  UINT8         Type;
+  UINT8         ID;
+  UINT8         DevMapHi;               // Copy of High Devmap programmed to Host bridge
+  UINT8         DevMapLo;               // Copy of Low Devmap programmed to Host bridge
+  UINT8         DefaultDevMapHi;        // Default of High devmap based on board settings
+  UINT8         DefaultDevMapLo;        // Default of Low devmap based on board settings
+  UINT8         Socket;
+  BOOLEAN       Active;
+  UINT8         Logical;
+  VOID          *RootBridge;            // Pointer to Stack PCI_ROOT_BRIDGE
+  UINT32        Flags;                  // Flags
+  UINT8         PresetGen3[MAX_PCIE_B]; // Preset for Gen3
+  UINT8         PresetGen4[MAX_PCIE_B]; // Preset for Gen4
+} AC01_RC;
+
+#endif
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PcieCore.h b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PcieCore.h
new file mode 100755
index 000000000000..1add9edac6b3
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PcieCore.h
@@ -0,0 +1,576 @@
+/** @file
+
+  Copyright (c) 2020, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __PCIECORE_H__
+#define __PCIECORE_H__
+
+#include <Library/ArmLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciLib.h>
+#include <Library/PcdLib.h>
+#include <Library/TimerLib.h>
+#include <Library/UefiLib.h>
+#include <IndustryStandard/Pci22.h>
+#include <Library/PciHostBridgeLib.h>
+#include "PcieCoreCapCfg.h"
+#include "Pcie.h"
+
+#ifndef BIT
+#define BIT(nr)                         (1 << (nr))
+#endif
+
+#define MAX_REINIT                       3
+#define MAX_RETRAIN                      10
+
+#define LINK_RETRAIN_SUCCESS             0
+#define LINK_RETRAIN_FAILED              -1
+#define LINK_RETRAIN_WRONG_PARAMETER     1
+
+#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 PCIE_MEMRDY_TIMEOUT     10       // 10 us
+#define PCIE_PIPE_CLOCK_TIMEOUT 20000    // 20,000 us
+#define PCIE_RETRAIN_TRANSITION_TIMEOUT 20000 // 20,000 us
+
+#define LINK_POLL_US_TIMER      1
+#define IO_SPACE                0x2000
+#define MMIO32_SPACE            0x8000000ULL
+#define MMIO_SPACE              0x3FFE0000000ULL
+
+#define TCU_OFFSET              0
+#define HB_CSR_OFFSET           0x01000000
+#define PCIE0_CSR_OFFSET        0x01010000
+#define PCIE1_CSR_OFFSET        0x01020000
+#define PCIE2_CSR_OFFSET        0x01030000
+#define PCIE3_CSR_OFFSET        0x01040000
+#define PCIE4_CSR_OFFSET        0x01010000
+#define PCIE5_CSR_OFFSET        0x01020000
+#define PCIE6_CSR_OFFSET        0x01030000
+#define PCIE7_CSR_OFFSET        0x01040000
+#define SNPSRAM_OFFSET          0x9000
+#define SERDES_CSR_OFFSET       0x01200000
+#define MMCONFIG_OFFSET         0x10000000
+
+
+/* DATA LINK registers */
+#define DLINK_VENDOR_CAP_ID       0x25
+#define DLINK_VSEC                0x80000001
+#define DATA_LINK_FEATURE_CAP_OFF 0X4
+
+/* 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
+
+/* TCU registers */
+#define SMMU_GBPA    0x044
+
+/* 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
+
+// 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))
+
+// 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          (1 << 4)
+#define PCIE_INT_MASK           (1 << 3)
+
+// BLOCKEVENTSTAT
+#define LINKUP_MASK             (1 << 0)
+
+// 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 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
+
+#define DEV_MASK 0x00F8000
+#define BUS_MASK 0xFF00000
+#define BUS_NUM(Addr) ((((UINT64)(Addr)) & BUS_MASK) >> 20)
+#define DEV_NUM(Addr) ((((UINT64)(Addr)) & DEV_MASK) >> 15)
+#define CFG_REG(Addr) (((UINT64)Addr) & 0x7FFF)
+
+// 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 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 PCIE_CAP_CPL_TIMEOUT_VALUE_SET(dst, src) (((dst) & ~0xF) | (((UINT32) (src)) & 0xF))
+
+// LINK_CAPABILITIES_REG
+#define PCIE_CAP_ID                             0x10
+#define LINK_CAPABILITIES_REG_OFF               0xC
+#define LINK_CONTROL_LINK_STATUS_OFF            0x10
+#define PCIE_CAP_MAX_LINK_WIDTH_X1              0x1
+#define PCIE_CAP_MAX_LINK_WIDTH_X2              0x2
+#define PCIE_CAP_MAX_LINK_WIDTH_X4              0x4
+#define PCIE_CAP_MAX_LINK_WIDTH_X8              0x8
+#define PCIE_CAP_MAX_LINK_WIDTH_X16             0x10
+#define PCIE_CAP_MAX_LINK_WIDTH_GET(val) ((val & 0x3F0) >> 4)
+#define PCIE_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 PCIE_CAP_MAX_LINK_SPEED_GET(val) ((val & 0xF))
+#define PCIE_CAP_MAX_LINK_SPEED_SET(dst, src) (((dst) & ~0xF) | (((UINT32) (src)) & 0xF))
+#define PCIE_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 PCIE_CAP_ACTIVE_STATE_LINK_PM_SUPPORT_SET(dst, src) (((dst) & ~0xC00) | (((UINT32)(src) << 10) & 0xC00))
+
+// LINK_CONTROL_LINK_STATUS_REG
+#define PCIE_CAP_DLL_ACTIVE_GET(val) ((val & 0x20000000) >> 29)
+#define PCIE_CAP_NEGO_LINK_WIDTH_GET(val) ((val & 0x3F00000) >> 20)
+#define PCIE_CAP_LINK_SPEED_GET(val) ((val & 0xF0000) >> 16)
+#define PCIE_CAP_LINK_SPEED_SET(dst, src) (((dst) & ~0xF0000) | (((UINT32) (src) << 16) & 0xF0000))
+#define CAP_LINK_SPEED_TO_VECTOR(val)          BIT((val)-1)
+#define PCIE_CAP_EN_CLK_POWER_MAN_GET(val) ((val & 0x100) >> 8)
+#define PCIE_CAP_EN_CLK_POWER_MAN_SET(dst, src) (((dst) & ~0x100) | (((UINT32) (src) << 8) & 0x100))
+#define PCIE_CAP_RETRAIN_LINK_SET(dst, src) (((dst) & ~0x20) | (((UINT32) (src) << 5) & 0x20))
+#define PCIE_CAP_COMMON_CLK_SET(dst, src) (((dst) & ~0x40) | (((UINT32) (src) << 6) & 0x40))
+#define PCIE_CAP_LINK_TRAINING_GET(val)     ((val & 0x8000000) >> 27)
+
+// LINK_CAPABILITIES2_REG
+#define LINK_SPEED_VECTOR_25                    BIT(0)
+#define LINK_SPEED_VECTOR_50                    BIT(1)
+#define LINK_SPEED_VECTOR_80                    BIT(2)
+#define LINK_SPEED_VECTOR_160                   BIT(3)
+#define LINK_SPEED_VECTOR_320                   BIT(4)
+#define PCIE_CAP_SUPPORT_LINK_SPEED_VECTOR_GET(val) ((val & 0xFE) >> 1)
+#define PCIE_CAP_SUPPORT_LINK_SPEED_VECTOR_SET(dst, src) (((dst) & ~0xFE) | (((UINT32) (src) << 1) & 0xFE))
+#define PCIE_CAP_EQ_CPL_GET(val)        ((val & 0x20000) >> 17)
+#define PCIE_CAP_EQ_CPL_P1_GET(val)     ((val & 0x40000) >> 18)
+#define PCIE_CAP_EQ_CPL_P2_GET(val)     ((val & 0x80000) >> 19)
+#define PCIE_CAP_EQ_CPL_P3_GET(val)     ((val & 0x100000) >> 20)
+
+// LINK_CONTROL2_LINK_STATUS2_REG
+#define PCIE_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_STATUS_OFF
+#define CMPLT_TIMEOUT_ERR_STATUS_GET(val) ((val & 0x4000) >> 14)
+#define CMPLT_TIMEOUT_ERR_STATUS_SET(dst, src) (((dst) & ~0x4000) | (((UINT32) (src) << 14) & 0x4000))
+
+// UNCORR_ERR_MASK_OFF
+#define CMPLT_TIMEOUT_ERR_MASK_SET(dst, src) (((dst) & ~0x4000) | (((UINT32) (src) << 14) & 0x4000))
+
+// RESOURCE_STATUS_REG_VC1
+#define VC_NEGO_PENDING_VC1_GET(val) ((val & 0x20000) >> 17)
+
+// SD_CONTROL1_REG
+#define FORCE_DETECT_LANE_EN_SET(dst, src) (((dst) & ~0x10000) | (((UINT32) (src) << 16) & 0x10000))
+
+// CCIX_TP_CAP_TP_HDR2_OFF
+#define ESM_REACH_LENGTH_GET(val) ((val & 0x60000) >> 17)
+#define ESM_CALIBRATION_TIME_GET(val) ((val & 0x700000) >> 20)
+#define ESM_CALIBRATION_TIME_SET(dst, src) (((dst) & ~0x700000) | (((UINT32) (src) << 20) & 0x700000))
+
+// ESM_STAT_OFF
+#define ESM_CALIB_CMPLT_GET(val) ((val & 0x80) >> 7)
+#define ESM_CURNT_DATA_RATE_GET(val) ((val & 0x7F) >> 0)
+
+// ESM_CNTL_OFF
+#define QUICK_EQ_TIMEOUT_SET(dst, src) (((dst) & ~0x1C000000) | (((UINT32) (src) << 26) & 0x1C000000))
+#define LINK_REACH_TARGET_GET(val) ((val & 0x1000000) >> 24)
+#define LINK_REACH_TARGET_SET(dst, src) (((dst) & ~0x1000000) | (((UINT32) (src) << 24) & 0x1000000))
+#define ESM_EXT_EQ3_DSP_TIMEOUT_GET(val) ((val & 0x700000) >> 20)
+#define ESM_EXT_EQ3_DSP_TIMEOUT_SET(dst, src) (((dst) & ~0x700000) | (((UINT32) (src) << 20) & 0x700000))
+#define ESM_EXT_EQ2_USP_TIMEOUT_GET(val) ((val & 0x70000) >> 16)
+#define ESM_EXT_EQ2_USP_TIMEOUT_SET(dst, src) (((dst) & ~0x70000) | (((UINT32) (src) << 16) & 0x70000))
+#define ESM_ENABLE_SET(dst, src) (((dst) & ~0x8000) | (((UINT32) (src) << 15) & 0x8000))
+#define ESM_DATA_RATE1_SET(dst, src) (((dst) & ~0x7F00) | (((UINT32) (src) << 8) & 0x7F00))
+#define ESM_PERFORM_CAL_SET(dst, src) (((dst) & ~0x80) | (((UINT32) (src) << 7) & 0x80))
+#define ESM_DATA_RATE0_SET(dst, src) (((dst) & ~0x7F) | (((UINT32) (src)) & 0x7F))
+
+// 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
+
+enum LTSSM_STATE {
+  S_DETECT_QUIET = 0,
+  S_DETECT_ACT,
+  S_POLL_ACTIVE,
+  S_POLL_COMPLIANCE,
+  S_POLL_CONFIG,
+  S_PRE_DETECT_QUIET,
+  S_DETECT_WAIT,
+  S_CFG_LINKWD_START,
+  S_CFG_LINKWD_ACEPT,
+  S_CFG_LANENUM_WAI,
+  S_CFG_LANENUM_ACEPT,
+  S_CFG_COMPLETE,
+  S_CFG_IDLE,
+  S_RCVRY_LOCK,
+  S_RCVRY_SPEED,
+  S_RCVRY_RCVRCFG,
+  S_RCVRY_IDLE,
+  S_L0,
+  S_L0S,
+  S_L123_SEND_EIDLE,
+  S_L1_IDLE,
+  S_L2_IDLE,
+  S_L2_WAKE,
+  S_DISABLED_ENTRY,
+  S_DISABLED_IDLE,
+  S_DISABLED,
+  S_LPBK_ENTRY,
+  S_LPBK_ACTIVE,
+  S_LPBK_EXIT,
+  S_LPBK_EXIT_TIMEOUT,
+  S_HOT_RESET_ENTRY,
+  S_HOT_RESET,
+  S_RCVRY_EQ0,
+  S_RCVRY_EQ1,
+  S_RCVRY_EQ2,
+  S_RCVRY_EQ3,
+  MAX_LTSSM_STATE
+};
+
+INT32
+Ac01PcieCfgOut32 (
+  VOID   *Addr,
+  UINT32 Val
+  );
+
+INT32
+Ac01PcieCfgOut16 (
+  VOID   *Addr,
+  UINT16 Val
+  );
+
+INT32
+Ac01PcieCfgOut8 (
+  VOID  *Addr,
+  UINT8 Val
+  );
+
+INT32
+Ac01PcieCfgIn32 (
+  VOID   *Addr,
+  UINT32 *Val
+  );
+
+INT32
+Ac01PcieCfgIn16 (
+  VOID   *Addr,
+  UINT16 *Val
+  );
+
+INT32
+Ac01PcieCfgIn8 (
+  VOID  *Addr,
+  UINT8 *Val
+  );
+
+INT32
+Ac01PcieCoreSetup (
+  AC01_RC *RC
+  );
+
+VOID
+Ac01PcieCoreResetPort (
+  AC01_RC *RC
+  );
+
+VOID
+Ac01PcieClearConfigPort (
+  AC01_RC *RC
+  );
+
+AC01_RC
+*GetRCList (
+  UINT8 Idx
+);
+
+VOID
+Ac01PcieCoreBuildRCStruct (
+  AC01_RC *RC,
+  UINT64  RegBase,
+  UINT64  MmioBase,
+  UINT64  Mmio32Base
+);
+
+INT32
+Ac01PcieCoreSetupRC (
+  IN AC01_RC *RC,
+  IN UINT8   ReInit,
+  IN UINT8   ReInitPcieIndex
+);
+
+VOID
+Ac01PcieCoreUpdateLink (
+  IN AC01_RC  *RC,
+  OUT BOOLEAN *IsNextRoundNeeded,
+  OUT INT8    *FailedPciePtr,
+  OUT INT8    *FailedPcieCount
+);
+
+VOID
+Ac01PcieCoreEndEnumeration (
+  AC01_RC *RC
+);
+
+INT32
+Ac01PcieCoreQoSLinkCheckRecovery (
+  IN AC01_RC   *RC,
+  IN INTN      PcieIndex
+);
+
+#endif /* __PCIECORE_H__ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PcieCoreCapCfg.h b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PcieCoreCapCfg.h
new file mode 100755
index 000000000000..78aab032b93d
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PcieCoreCapCfg.h
@@ -0,0 +1,64 @@
+/** @file
+
+  Copyright (c) 2020, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __X16_CAP_PORT_CFG_H__
+#define __X16_CAP_PORT_CFG_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
+
+#endif /* __X16_CAP_PORT_CFG_H__ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PciePatchAcpi.h b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PciePatchAcpi.h
new file mode 100755
index 000000000000..7b02fb17cba9
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PciePatchAcpi.h
@@ -0,0 +1,30 @@
+/** @file
+
+  Copyright (c) 2020, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __PCIEPATCHACPI_H__
+#define __PCIEPATCHACPI_H__
+
+EFI_STATUS
+EFIAPI
+AcpiPatchPciMem32 (
+  INT8 *PciSegEnabled
+  );
+
+EFI_STATUS
+EFIAPI
+AcpiInstallMcfg (
+  INT8 *PciSegEnabled
+  );
+
+EFI_STATUS
+EFIAPI
+AcpiInstallIort (
+  INT8 *PciSegEnabled
+  );
+
+#endif /* __PCIEPATCHACPI_H__ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PcieCore.c b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PcieCore.c
new file mode 100755
index 000000000000..35979a638e7e
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PcieCore.c
@@ -0,0 +1,1246 @@
+/** @file
+
+  Copyright (c) 2020, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <string.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/HobLib.h>
+#include <Library/PciePhyLib.h>
+#include <Library/PcieBoardLib.h>
+#include <Library/SMProLib.h>
+#include <PlatformInfoHob.h>
+#include "PcieCore.h"
+#include "Pcie.h"
+
+#define DEV_MASK 0x00F8000
+#define BUS_MASK 0xFF00000
+
+STATIC INT32
+Ac01PcieCsrOut32 (
+  VOID   *Addr,
+  UINT32 Val
+  )
+{
+  MmioWrite32 ((UINT64) Addr, Val);
+  PCIE_CSR_DEBUG (
+    "PCIE CSR WR: 0x%p value: 0x%08X (0x%08X)\n",
+    Addr,
+    Val,
+    MmioRead32 ((UINT64) Addr)
+    );
+
+  return 0;
+}
+
+STATIC INT32
+Ac01PcieCsrOut32Serdes (
+  VOID   *Addr,
+  UINT32 Val
+  )
+{
+  MmioWrite32 ((UINT64) Addr, Val);
+  PCIE_CSR_DEBUG (
+    "PCIE CSR WR: 0x%p value: 0x%08X (0x%08X)\n",
+    Addr,
+    Val,
+    MmioRead32 ((UINT64) Addr)
+    );
+
+  return 0;
+}
+
+STATIC INT32
+Ac01PcieCsrIn32 (
+  VOID   *Addr,
+  UINT32 *Val
+  )
+{
+  *Val = MmioRead32 ((UINT64) Addr);
+  PCIE_CSR_DEBUG ("PCIE CSR RD: 0x%p value: 0x%08X\n", Addr, *Val);
+
+  return 0;
+}
+
+STATIC INT32
+Ac01PcieCsrIn32Serdes (
+  VOID   *Addr,
+  UINT32 *Val
+  )
+{
+  *Val = MmioRead32 ((UINT64) Addr);
+  PCIE_CSR_DEBUG ("PCIE CSR RD: 0x%p value: 0x%08X\n", Addr, *Val);
+
+  return 0;
+}
+
+VOID
+Ac01PcieMmioRd (
+  UINT64 Addr,
+  UINT32 *Val
+  )
+{
+  Ac01PcieCsrIn32Serdes ((VOID *) Addr, (UINT32 *) Val);
+}
+
+VOID
+Ac01PcieMmioWr (
+  UINT64 Addr,
+  UINT32 Val
+  )
+{
+  Ac01PcieCsrOut32Serdes ((VOID *) Addr, (UINT32) Val);
+}
+
+VOID
+Ac01PciePuts(
+  CONST CHAR8 *Msg
+  )
+{
+  PCIE_PHY_DEBUG ("%a\n", __FUNCTION__);
+}
+
+VOID
+Ac01PciePutInt (
+  UINT32 val
+  )
+{
+  PCIE_PHY_DEBUG ("%a\n", __FUNCTION__);
+}
+
+VOID
+Ac01PciePutHex (
+  UINT64 val
+  )
+{
+  PCIE_PHY_DEBUG ("%a\n", __FUNCTION__);
+}
+
+INT32
+Ac01PcieDebugPrint (
+  CONST CHAR8 *fmt,
+  ...
+  )
+{
+  PCIE_PHY_DEBUG ("%a\n", __FUNCTION__);
+  return 0;
+}
+
+VOID
+Ac01PcieDelay (
+  UINT32 Val
+  )
+{
+  MicroSecondDelay (Val);
+}
+
+/**
+   Write 32-bit value to config space address
+
+   @param Addr          Address within config space
+   @param Val           32-bit value to write
+**/
+INT32
+Ac01PcieCfgOut32 (
+  IN VOID *Addr,
+  IN UINT32 Val
+  )
+{
+  MmioWrite32 ((UINT64) Addr, Val);
+  PCIE_DEBUG_CFG (
+    "PCIE CFG WR: 0x%p value: 0x%08X (0x%08X)\n",
+    Addr,
+    Val,
+    MmioRead32 ((UINT64) Addr)
+    );
+
+  return 0;
+}
+
+/**
+   Write 16-bit value to config space address
+
+   @param Addr          Address within config space
+   @param Val           16-bit value to write
+**/
+INT32 Ac01PcieCfgOut16 (
+  IN VOID *Addr,
+  IN UINT16 Val
+  )
+{
+  UINT64 AlignedAddr = (UINT64) Addr & ~0x3;
+  UINT32 Val32  = MmioRead32 (AlignedAddr);
+
+  switch ((UINT64) Addr & 0x3) {
+  case 2:
+    Val32 &= ~0xFFFF0000;
+    Val32 |= (UINT32) Val << 16;
+    break;
+
+  case 0:
+  default:
+    Val32 &= ~0xFFFF;
+    Val32 |= Val;
+    break;
+  }
+  MmioWrite32 (AlignedAddr, Val32);
+  PCIE_DEBUG_CFG (
+    "PCIE CFG WR16: 0x%p value: 0x%04X (0x%08llX 0x%08X)\n",
+    Addr,
+    Val,
+    AlignedAddr,
+    MmioRead32 ((UINT64) AlignedAddr)
+    );
+
+  return 0;
+}
+
+/**
+   Write 8-bit value to config space address
+
+   @param Addr          Address within config space
+   @param Val           8-bit value to write
+**/
+INT32
+Ac01PcieCfgOut8 (
+  IN VOID *Addr,
+  IN UINT8 Val
+  )
+{
+  UINT64 AlignedAddr = (UINT64) Addr & ~0x3;
+  UINT32 Val32  = MmioRead32 (AlignedAddr);
+
+  switch ((UINT64) Addr & 0x3) {
+  case 0:
+    Val32 &= ~0xFF;
+    Val32 |= Val;
+    break;
+
+  case 1:
+    Val32 &= ~0xFF00;
+    Val32 |= (UINT32) Val << 8;
+    break;
+
+  case 2:
+    Val32 &= ~0xFF0000;
+    Val32 |= (UINT32) Val << 16;
+    break;
+
+  case 3:
+  default:
+    Val32 &= ~0xFF000000;
+    Val32 |= (UINT32) Val << 24;
+    break;
+  }
+  MmioWrite32 (AlignedAddr, Val32);
+  PCIE_DEBUG_CFG (
+    "PCIE CFG WR8: 0x%p value: 0x%04X (0x%08llX 0x%08X)\n",
+    Addr,
+    Val,
+    AlignedAddr,
+    MmioRead32 ((UINT64) AlignedAddr)
+    );
+
+  return 0;
+}
+
+/**
+   Read 32-bit value from config space address
+
+   @param Addr          Address within config space
+   @param Val           Point to address for read value
+**/
+INT32
+Ac01PcieCfgIn32 (
+  IN VOID *Addr,
+  OUT UINT32 *Val
+  )
+{
+  UINT32 RegC, Reg18;
+  UINT8  MfHt, Primary = 0, Sec = 0, Sub = 0;
+
+  if ((BUS_NUM (Addr) > 0) && (DEV_NUM (Addr) > 0) && (CFG_REG (Addr) == 0)) {
+    *Val = MmioRead32 ((UINT64) Addr);
+    PCIE_DEBUG_CFG (
+      "PCIE CFG RD: B%X|D%X 0x%p value: 0x%08X\n",
+      BUS_NUM (Addr),
+      DEV_NUM (Addr),
+      Addr, *Val
+      );
+
+    if (*Val != 0xffffffff) {
+      RegC = MmioRead32 ((UINT64) Addr + 0xC);
+      PCIE_DEBUG_CFG ("Peek PCIE MfHt RD32: 0x%p value: 0x%08X\n", Addr + 0xc, RegC);
+      MfHt = RegC >> 16;
+      PCIE_DEBUG_CFG ("  Peek RD8 MfHt=0x%02X\n", MfHt);
+
+      if ((MfHt & 0x7F)!= 0) { /* Type 1 header */
+        Reg18 = MmioRead32 ((UINT64) Addr + 0x18);
+        Primary = Reg18; Sec = Reg18 >> 8; Sub = Reg18 >> 16;
+        PCIE_DEBUG_CFG (
+          "  Bus Peek PCIE Sub:%01X Sec:%01X Primary:%01X  RD: 0x%p value: 0x%08X\n",
+          Sub,
+          Sec,
+          Primary,
+          Addr + 0x18,
+          Reg18
+          );
+      }
+      if ((MfHt == 0) || (Primary != 0)) { /* QS RPs Primary Bus is 0b */
+        *Val = 0xffffffff;
+        PCIE_DEBUG_CFG (
+          "  Skip RD32 B%X|D%X PCIE CFG RD: 0x%p return 0xffffffff\n",
+          BUS_NUM (Addr),
+          DEV_NUM (Addr),
+          Addr
+          );
+      }
+    }
+  } else {
+    *Val = MmioRead32 ((UINT64) Addr);
+  }
+  PCIE_DEBUG_CFG ("PCIE CFG RD: 0x%p value: 0x%08X\n", Addr, *Val);
+
+  return 0;
+}
+
+/**
+   Read 16-bit value from config space address
+
+   @param Addr          Address within config space
+   @param Val           Point to address for read value
+**/
+INT32
+Ac01PcieCfgIn16 (
+  IN VOID *Addr,
+  OUT UINT16 *Val)
+{
+  UINT64 AlignedAddr = (UINT64) Addr & ~0x3;
+  UINT32 RegC, Reg18;
+  UINT8  MfHt, Primary = 0, Sec = 0, Sub = 0;
+  UINT32 Val32;
+
+  if ((BUS_NUM (Addr) > 0) && (DEV_NUM (Addr) > 0) && (CFG_REG (Addr) == 0)) {
+    *Val = MmioRead32 ((UINT64) Addr);
+    PCIE_DEBUG_CFG (
+      "PCIE CFG16 RD: B%X|D%X 0x%p value: 0x%08X\n",
+      BUS_NUM (Addr),
+      DEV_NUM (Addr),
+      Addr,
+      *Val
+      );
+
+    if (*Val != 0xffff) {
+      RegC = MmioRead32 ((UINT64) Addr + 0xC);
+      PCIE_DEBUG_CFG ("  Peek PCIE MfHt RD: 0x%p value: 0x%08X\n", Addr + 0xc, RegC);
+      MfHt = RegC >> 16;
+      PCIE_DEBUG_CFG ("  Peek RD8 MfHt=0x%02X\n", MfHt);
+
+
+      if ((MfHt & 0x7F)!= 0) { /* Type 1 header */
+        Reg18 = MmioRead32 ((UINT64) Addr + 0x18);
+        Primary = Reg18; Sec = Reg18 >> 8; Sub = Reg18 >> 16;
+        PCIE_DEBUG_CFG (
+          "  Bus Peek PCIE Sub:%01X Sec:%01X Primary:%01X  RD: 0x%p value: 0x%08X\n",
+          Sub,
+          Sec,
+          Primary,
+          Addr + 0x18, Reg18
+          );
+      }
+      if ((MfHt == 0) || (Primary != 0)) { /* QS RPs Primary Bus is 0b */
+        *Val = 0xffff;
+        PCIE_DEBUG_CFG (
+          "  Skip RD16 B%X|D%X PCIE CFG RD: 0x%p return 0xffff\n",
+          BUS_NUM (Addr),
+          DEV_NUM (Addr),
+          Addr
+          );
+        return 0;
+      }
+    }
+  }
+
+  Val32 = MmioRead32 (AlignedAddr);
+  switch ((UINT64) Addr & 0x3) {
+  case 2:
+    *Val = Val32 >> 16;
+    break;
+
+  case 0:
+  default:
+    *Val = Val32;
+    break;
+  }
+  PCIE_DEBUG_CFG (
+    "PCIE CFG RD16: 0x%p value: 0x%04X (0x%08llX 0x%08X)\n",
+    Addr,
+    *Val,
+    AlignedAddr,
+    Val32
+    );
+
+  return 0;
+}
+
+/**
+   Read 8-bit value from config space address
+
+   @param Addr          Address within config space
+   @param Val           Point to address for read value
+**/
+INT32
+Ac01PcieCfgIn8 (
+  IN VOID *Addr,
+  OUT UINT8 *Val
+  )
+{
+  UINT64 AlignedAddr = (UINT64) Addr & ~0x3;
+  if ((((UINT64) Addr & DEV_MASK) >> 15 )> 0 && (((UINT64) Addr & BUS_MASK)  >> 20)> 0) {
+    *Val = 0xff;
+   return 0;
+  }
+
+  UINT32 Val32 = MmioRead32 (AlignedAddr);
+  switch ((UINT64) Addr & 0x3) {
+  case 3:
+    *Val = Val32 >> 24;
+    break;
+
+  case 2:
+    *Val = Val32 >> 16;
+    break;
+
+  case 1:
+    *Val = Val32 >> 8;
+    break;
+
+  case 0:
+  default:
+    *Val = Val32;
+    break;
+  }
+  PCIE_DEBUG_CFG (
+    "PCIE CFG RD8: 0x%p value: 0x%02X (0x%08llX 0x%08X)\n",
+    Addr,
+    *Val,
+    AlignedAddr,
+    Val32
+    );
+
+  return 0;
+}
+
+/**
+   Return the next extended capability address
+
+   @param RC              Pointer to AC01_RC structure
+   @param PcieIndex       PCIe index
+   @param IsRC            0x1: Checking RC configuration space
+                          0x0: Checking EP configuration space
+   @param ExtendedCapId
+**/
+UINT64
+PcieCheckCap (
+  IN AC01_RC  *RC,
+  IN INTN      PcieIndex,
+  IN BOOLEAN   IsRC,
+  IN UINT16    ExtendedCapId
+  )
+{
+  VOID         *CfgAddr;
+  UINT32        Val = 0, NextCap = 0, CapId = 0, ExCap = 0;
+
+  if (IsRC) {
+    CfgAddr = (VOID *) (RC->MmcfgAddr + (RC->Pcie[PcieIndex].DevNum << 15));
+  } else {
+    CfgAddr = (VOID *) (RC->MmcfgAddr + (RC->Pcie[PcieIndex].DevNum << 20));
+  }
+
+  Ac01PcieCsrIn32 (CfgAddr + TYPE1_CAP_PTR_REG, &Val);
+  NextCap = Val & 0xFF;
+
+  // Loop untill desired capability is found else return 0
+  while (1) {
+    if ((NextCap & 0x3) != 0) {
+     /* Not alignment, just return */
+      return 0;
+    }
+    Ac01PcieCsrIn32 (CfgAddr + NextCap, &Val);
+    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;
+    }
+  }
+}
+
+/**
+   Read 8-bit value from config space address
+
+   @param RC          Pointer to AC01_RC strucutre
+   @param RegBase     Base address of CSR, TCU, Hostbridge, Msg, Serdes, and MMCFG register
+   @param MmioBase    Base address of 32-bit MMIO
+   @param Mmio32Base  Base address of 64-bit MMIO
+**/
+VOID
+Ac01PcieCoreBuildRCStruct (
+  AC01_RC *RC,
+  UINT64 RegBase,
+  UINT64 MmioBase,
+  UINT64 Mmio32Base
+  )
+{
+  INTN          PcieIndex;
+
+  RC->BaseAddr = RegBase;
+  RC->TcuAddr = RegBase + TCU_OFFSET;
+  RC->HBAddr = RegBase + HB_CSR_OFFSET;
+  RC->SerdesAddr = RegBase + SERDES_CSR_OFFSET;
+  RC->MmcfgAddr = RegBase + MMCONFIG_OFFSET;
+  RC->MmioAddr = MmioBase;
+  RC->Mmio32Addr = Mmio32Base;
+  RC->IoAddr = Mmio32Base + MMIO32_SPACE - IO_SPACE;
+
+  RC->Type = (RC->ID < MAX_RCA) ? RCA : RCB;
+  RC->MaxPcieController = (RC->Type == RCB) ? MAX_PCIE_B : MAX_PCIE_A;
+
+  PcieBoardParseRCParams (RC);
+
+  for (PcieIndex = 0; PcieIndex < RC->MaxPcieController; PcieIndex++) {
+    RC->Pcie[PcieIndex].ID = PcieIndex;
+    RC->Pcie[PcieIndex].CsrAddr = RC->BaseAddr + PCIE0_CSR_OFFSET + PcieIndex*0x10000;
+    RC->Pcie[PcieIndex].SnpsRamAddr = RC->Pcie[PcieIndex].CsrAddr + SNPSRAM_OFFSET;
+    RC->Pcie[PcieIndex].DevNum = PcieIndex + 1;
+  }
+
+  PCIE_DEBUG (
+    " + S%d - RC%a%d, MMCfgAddr:0x%lx, MmioAddr:0x%lx, Mmio32Addr:0x%lx, Enabled:%a\n",
+    RC->Socket,
+    (RC->Type == RCA) ? "A" : "B",
+    RC->ID,
+    RC->MmcfgAddr,
+    RC->MmioAddr,
+    RC->Mmio32Addr,
+    (RC->Active) ? "Y" : "N"
+    );
+  PCIE_DEBUG (" +   DevMapLo/Hi: 0x%x/0x%x\n", RC->DevMapLo, RC->DevMapHi);
+  for (PcieIndex = 0; PcieIndex < RC->MaxPcieController; PcieIndex++) {
+    PCIE_DEBUG (
+      " +     PCIE%d:0x%lx - Enabled:%a - DevNum:0x%x\n", PcieIndex,
+      RC->Pcie[PcieIndex].CsrAddr,
+      (RC->Pcie[PcieIndex].Active) ? "Y" : "N",
+      RC->Pcie[PcieIndex].DevNum
+      );
+  }
+}
+
+/**
+   Configure equalization settings
+
+   @param RC              Pointer to AC01_RC structure
+   @param PcieIndex       PCIe index
+**/
+STATIC
+VOID
+Ac01PcieConfigureEqualization (
+  IN AC01_RC   *RC,
+  IN INTN      PcieIndex
+  )
+{
+  VOID *CfgAddr;
+  UINT32 Val;
+
+  CfgAddr = (VOID *) (RC->MmcfgAddr + (RC->Pcie[PcieIndex].DevNum << 15));
+
+  // Select the FoM method, need double-write to convey settings
+  Ac01PcieCfgIn32 (CfgAddr + GEN3_EQ_CONTROL_OFF, &Val);
+  Val = GEN3_EQ_FB_MODE (Val, 0x1);
+  Val = GEN3_EQ_PRESET_VEC (Val, 0x3FF);
+  Val = GEN3_EQ_INIT_EVAL (Val, 0x1);
+  Ac01PcieCfgOut32 (CfgAddr + GEN3_EQ_CONTROL_OFF, Val);
+  Ac01PcieCfgOut32 (CfgAddr + GEN3_EQ_CONTROL_OFF, Val);
+  Ac01PcieCfgIn32 (CfgAddr + GEN3_EQ_CONTROL_OFF, &Val);
+}
+
+/**
+   Configure presets for GEN3 equalization
+
+   @param RC              Pointer to AC01_RC structure
+   @param PcieIndex       PCIe index
+**/
+STATIC
+VOID
+Ac01PcieConfigurePresetGen3 (
+  IN AC01_RC   *RC,
+  IN INTN      PcieIndex
+  )
+{
+  VOID *CfgAddr, *SpcieBaseAddr;
+  UINT32 Val, Idx;
+  CfgAddr = (VOID *) (RC->MmcfgAddr + (RC->Pcie[PcieIndex].DevNum << 15));
+
+  // Bring to legacy mode
+  Ac01PcieCfgIn32 (CfgAddr + GEN3_RELATED_OFF, &Val);
+  Val = RATE_SHADOW_SEL_SET (Val, 0);
+  Ac01PcieCfgOut32 (CfgAddr + GEN3_RELATED_OFF, Val);
+  Val = EQ_PHASE_2_3_SET (Val, 0);
+  Val = RXEQ_REGRDLESS_SET (Val, 1);
+  Ac01PcieCfgOut32 (CfgAddr + GEN3_RELATED_OFF, Val);
+
+  // Generate SPCIE capability address
+  SpcieBaseAddr = (VOID *) PcieCheckCap (RC, PcieIndex, 0x1, SPCIE_CAP_ID);
+  if (SpcieBaseAddr == 0) {
+    PCIE_ERR (
+      "PCIE%d.%d: Cannot get SPCIE capability address\n",
+      RC->ID,
+      PcieIndex
+      );
+    return;
+  }
+
+  for (Idx=0; Idx < RC->Pcie[PcieIndex].MaxWidth/2; Idx++) {
+    // Program Preset to Gen3 EQ Lane Control
+    Ac01PcieCfgIn32 (SpcieBaseAddr + CAP_OFF_0C + Idx*4, &Val);
+    Val = DSP_TX_PRESET0_SET (Val, 0x7);
+    Val = DSP_TX_PRESET1_SET (Val, 0x7);
+    Ac01PcieCfgOut32 (SpcieBaseAddr + CAP_OFF_0C + Idx*4, Val);
+  }
+}
+
+/**
+   Configure presets for GEN4 equalization
+
+   @param RC              Pointer to AC01_RC structure
+   @param PcieIndex       PCIe index
+**/
+STATIC
+VOID
+Ac01PcieConfigurePresetGen4 (
+  IN AC01_RC   *RC,
+  IN INTN      PcieIndex
+  )
+{
+  UINT32    Val;
+  VOID      *CfgAddr, *SpcieBaseAddr, *Pl16BaseAddr;
+  UINT32    LinkWidth, i;
+  UINT8     Preset;
+
+  CfgAddr = (VOID *) (RC->MmcfgAddr + (RC->Pcie[PcieIndex].DevNum << 15));
+
+  // Bring to legacy mode
+  Ac01PcieCfgIn32 (CfgAddr + GEN3_RELATED_OFF, &Val);
+  Val = RATE_SHADOW_SEL_SET (Val, 1);
+  Ac01PcieCfgOut32 (CfgAddr + GEN3_RELATED_OFF, Val);
+  Val = EQ_PHASE_2_3_SET (Val, 0);
+  Val = RXEQ_REGRDLESS_SET (Val, 1);
+  Ac01PcieCfgOut32 (CfgAddr + GEN3_RELATED_OFF, Val);
+
+  // Generate the PL16 capability address
+  Pl16BaseAddr = (VOID *) PcieCheckCap (RC, PcieIndex, 0x1, PL16_CAP_ID);
+  if (Pl16BaseAddr == 0) {
+    PCIE_ERR (
+      "PCIE%d.%d: Cannot get PL16 capability address\n",
+      RC->ID,
+      PcieIndex
+      );
+    return;
+  }
+
+  // Generate the SPCIE capability address
+  SpcieBaseAddr = (VOID *) PcieCheckCap (RC, PcieIndex, 0x1, SPCIE_CAP_ID);
+  if (SpcieBaseAddr == 0) {
+    PCIE_ERR (
+      "PCIE%d.%d: Cannot get SPICE capability address\n",
+      RC->ID,
+      PcieIndex
+      );
+    return;
+  }
+
+  // Configure downstream Gen4 Tx preset
+  if (RC->PresetGen4[PcieIndex] == PRESET_INVALID) {
+    Preset = 0x57; // Default Gen4 preset
+  } else {
+    Preset = RC->PresetGen4[PcieIndex];
+  }
+
+  LinkWidth = RC->Pcie[PcieIndex].MaxWidth;
+  if (LinkWidth == 0x2) {
+    Ac01PcieCfgIn32 (Pl16BaseAddr + PL16G_CAP_OFF_20H_REG_OFF, &Val);
+    Val = DSP_16G_RXTX_PRESET0_SET (Val, Preset);
+    Val = DSP_16G_RXTX_PRESET1_SET (Val, Preset);
+    Ac01PcieCfgOut32 (Pl16BaseAddr + PL16G_CAP_OFF_20H_REG_OFF, Val);
+  } else {
+    for (i = 0 ; i < LinkWidth/4; i++) {
+      Ac01PcieCfgIn32 (Pl16BaseAddr + PL16G_CAP_OFF_20H_REG_OFF + i*4, &Val);
+      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);
+      Ac01PcieCfgOut32 (Pl16BaseAddr + PL16G_CAP_OFF_20H_REG_OFF + i*4, Val);
+    }
+  }
+
+  // Configure Gen3 preset
+  for (i = 0; i < LinkWidth/2; i++) {
+    Ac01PcieCfgIn32 (SpcieBaseAddr + CAP_OFF_0C + i*4, &Val);
+    Val = DSP_TX_PRESET0_SET (Val, 0x7);
+    Val = DSP_TX_PRESET1_SET (Val, 0x7);
+    Ac01PcieCfgOut32 (SpcieBaseAddr + CAP_OFF_0C + i*4, Val);
+  }
+}
+
+STATIC BOOLEAN
+RasdpMitigationCheck (
+  AC01_RC *RC,
+  INTN    PcieIndex
+  )
+{
+  EFI_GUID           PlatformHobGuid = PLATFORM_INFO_HOB_GUID_V2;
+  PlatformInfoHob_V2 *PlatformHob;
+  VOID               *Hob;
+
+  Hob = GetFirstGuidHob (&PlatformHobGuid);
+  PlatformHob = (PlatformInfoHob_V2 *) GET_GUID_HOB_DATA (Hob);
+  if ((PlatformHob->ScuProductId[0] & 0xff) == 0x01) {
+    if (AsciiStrCmp ((CONST CHAR8 *) PlatformHob->CpuVer, "A0") == 0) {
+      return ((RC->Type == RCB)||(PcieIndex > 0)) ? TRUE : FALSE;
+    }
+  }
+
+  return FALSE;
+}
+
+/**
+   Setup and initialize the AC01 PCIe Root Complex and underneath PCIe controllers
+
+   @param RC                    Pointer to Root Complex structure
+   @param ReInit                Re-init status
+   @param ReInitPcieIndex       PCIe index
+**/
+INT32
+Ac01PcieCoreSetupRC (
+  IN AC01_RC    *RC,
+  IN UINT8      ReInit,
+  IN UINT8      ReInitPcieIndex
+  )
+{
+  VOID          *CsrAddr, *CfgAddr, *SnpsRamAddr, *DlinkBaseAddr;
+  INTN          PcieIndex;
+  INTN          TimeOut;
+  UINT32        Val;
+  PHY_CONTEXT   PhyCtx = { 0 };
+  PHY_PLAT_RESOURCE PhyPlatResource = { 0 };
+  INTN          Ret;
+  UINT16        NextExtendedCapabilityOff;
+  UINT32        VsecVal;
+
+  PCIE_DEBUG ("Initializing Socket%d RC%d\n", RC->Socket, RC->ID);
+
+  if (ReInit == 0) {
+    // Initialize SERDES
+    ZeroMem (&PhyCtx, sizeof(PhyCtx));
+    PhyCtx.SdsAddr = RC->SerdesAddr;
+    PhyCtx.PcieCtrlInfo |= ((RC->Socket & 0x1) << 2);
+    PhyCtx.PcieCtrlInfo |= ((RC->ID & 0x7) << 4);
+    PhyCtx.PcieCtrlInfo |= 0xF << 8;
+    PhyPlatResource.MmioRd = Ac01PcieMmioRd;
+    PhyPlatResource.MmioWr = Ac01PcieMmioWr;
+    PhyPlatResource.UsDelay = Ac01PcieDelay;
+    PhyPlatResource.Puts = Ac01PciePuts;
+    PhyPlatResource.PutInt = Ac01PciePutInt;
+    PhyPlatResource.PutHex = Ac01PciePutInt;
+    PhyPlatResource.PutHex64 = Ac01PciePutHex;
+    PhyPlatResource.DebugPrint = Ac01PcieDebugPrint;
+    PhyCtx.PhyPlatResource = &PhyPlatResource;
+
+    Ret = SerdesInitClkrst (&PhyCtx);
+    if (Ret != PHY_INIT_PASS)
+      return -1;
+  }
+
+  // Setup each controller
+  for (PcieIndex = 0; PcieIndex < RC->MaxPcieController; PcieIndex ++) {
+
+    if (ReInit == 1) {
+      PcieIndex = ReInitPcieIndex;
+    }
+
+    if (!RC->Pcie[PcieIndex].Active) {
+      continue;
+    }
+
+    PCIE_DEBUG ("Initializing Controller %d\n", PcieIndex);
+
+    CsrAddr = (VOID *) RC->Pcie[PcieIndex].CsrAddr;
+    SnpsRamAddr = (VOID *) RC->Pcie[PcieIndex].SnpsRamAddr;
+    CfgAddr = (VOID *) (RC->MmcfgAddr + (RC->Pcie[PcieIndex].DevNum << 15));
+
+    // Put Controller into reset if not in reset already
+    Ac01PcieCsrIn32 (CsrAddr +  RESET, &Val);
+    if (!(Val & RESET_MASK)) {
+      Val = DWCPCIE_SET (Val, 1);
+      Ac01PcieCsrOut32 (CsrAddr + RESET, Val);
+
+      // Delay 50ms to ensure controller finish its reset
+      // FIXME: Is this necessary?
+      MicroSecondDelay (50000);
+    }
+
+    // Clear memory shutdown
+    Ac01PcieCsrIn32 (CsrAddr + RAMSDR, &Val);
+    Val = SD_SET (Val, 0);
+    Ac01PcieCsrOut32 (CsrAddr + RAMSDR, Val);
+
+    // Poll till mem is ready
+    TimeOut = PCIE_MEMRDY_TIMEOUT;
+    do {
+      Ac01PcieCsrIn32 (CsrAddr + MEMRDYR, &Val);
+      if (Val & 1)
+        break;
+
+      TimeOut--;
+      MicroSecondDelay (1);
+    } while (TimeOut > 0);
+
+    if (TimeOut <= 0) {
+      PCIE_ERR ("- Pcie[%d] - Mem not ready\n", PcieIndex);
+      return -1;
+    }
+
+    // Hold link training
+    Ac01PcieCsrIn32 (CsrAddr + LINKCTRL, &Val);
+    Val = LTSSMENB_SET (Val, 0);
+    Ac01PcieCsrOut32 (CsrAddr + LINKCTRL, Val);
+
+    // Enable subsystem clock and release reset
+    Ac01PcieCsrIn32 (CsrAddr + CLOCK, &Val);
+    Val = AXIPIPE_SET (Val, 1);
+    Ac01PcieCsrOut32 (CsrAddr + CLOCK, Val);
+    Ac01PcieCsrIn32 (CsrAddr +  RESET, &Val);
+    Val = DWCPCIE_SET (Val, 0);
+    Ac01PcieCsrOut32 (CsrAddr + RESET, Val);
+
+    //
+    // Controller does not provide any indicator for reset released.
+    // Must wait at least 1us as per EAS.
+    //
+    MicroSecondDelay (1);
+
+    // Poll till PIPE clock is stable
+    TimeOut = PCIE_PIPE_CLOCK_TIMEOUT;
+    do {
+      Ac01PcieCsrIn32 (CsrAddr + LINKSTAT, &Val);
+      if (!(Val & PHY_STATUS_MASK))
+        break;
+
+      TimeOut--;
+      MicroSecondDelay (1);
+    } while (TimeOut > 0);
+
+    if (TimeOut <= 0) {
+      PCIE_ERR ("- Pcie[%d] - PIPE clock is not stable\n", PcieIndex);
+      return -1;
+    }
+
+    // Start PERST pulse
+    PcieBoardAssertPerst (RC, PcieIndex, 0, TRUE);
+
+    // Allow programming to config space
+    Ac01PcieCsrIn32 (CfgAddr + MISC_CONTROL_1_OFF, &Val);
+    Val = DBI_RO_WR_EN_SET (Val, 1);
+    Ac01PcieCsrOut32 (CfgAddr + MISC_CONTROL_1_OFF, Val);
+
+    // Apply RASDP error mitigation for all x8, x4, and x2 controllers
+    // This includes all RCB root ports, and every RCA root port controller
+    // except for index 0 (i.e. x16 controllers are exempted from this WA)
+    if (RasdpMitigationCheck (RC, PcieIndex)) {
+      // Change the Read Margin dual ported RAMs
+      Val = 0x10; // Margin to 0x0 (most conservative setting)
+      Ac01PcieCsrOut32 (SnpsRamAddr + TPSRAM_RMR, Val);
+
+      //Generate the DLINK capability address
+      DlinkBaseAddr = (VOID *) (RC->MmcfgAddr + (RC->Pcie[PcieIndex].DevNum << 15));
+      NextExtendedCapabilityOff = 0x100; // This is the 1st extended capability offset
+      do {
+        Ac01PcieCsrIn32 (DlinkBaseAddr + NextExtendedCapabilityOff, &Val);
+        if (Val == 0xFFFFFFFF) {
+          DlinkBaseAddr = 0x0;
+          break;
+        }
+        if ((Val & 0xFFFF) == DLINK_VENDOR_CAP_ID) {
+          Ac01PcieCsrIn32 (DlinkBaseAddr + NextExtendedCapabilityOff + 0x4, &VsecVal);
+            if (VsecVal == DLINK_VSEC) {
+              DlinkBaseAddr = DlinkBaseAddr + NextExtendedCapabilityOff;
+              break;
+            }
+        }
+        NextExtendedCapabilityOff = (Val >> 20);
+      } while (NextExtendedCapabilityOff != 0);
+
+      // Disable the scaled credit mode
+      if (DlinkBaseAddr != 0x0) {
+        Val = 1;
+        Ac01PcieCsrOut32 (DlinkBaseAddr + DATA_LINK_FEATURE_CAP_OFF, Val);
+        Ac01PcieCsrIn32 (DlinkBaseAddr + DATA_LINK_FEATURE_CAP_OFF, &Val);
+        if (Val != 1) {
+          PCIE_ERR ("- Pcie[%d] - Unable to disable scaled credit\n", PcieIndex);
+          return -1;
+        }
+      }
+      else {
+        PCIE_ERR ("- 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;
+      Ac01PcieCsrOut32 (CfgAddr + PORT_LOCIG_VC0_P_RX_Q_CTRL_OFF, Val);
+    }
+
+    // Program DTI for ATS support
+    Ac01PcieCsrIn32 (CfgAddr + DTIM_CTRL0_OFF, &Val);
+    Val = DTIM_CTRL0_ROOT_PORT_ID_SET (Val, 0);
+    Ac01PcieCsrOut32 (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 PCIE_CAP_MAX_LINK_WIDTH of LINK_CAPABILITIES_REG
+    //
+    Ac01PcieCsrIn32 (CfgAddr + PORT_LINK_CTRL_OFF, &Val);
+    switch (RC->Pcie[PcieIndex].MaxWidth) {
+    case LNKW_X2:
+      Val = LINK_CAPABLE_SET (Val, LINK_CAPABLE_X2);
+      break;
+
+    case LNKW_X4:
+      Val = LINK_CAPABLE_SET (Val, LINK_CAPABLE_X4);
+      break;
+
+    case LNKW_X8:
+      Val = LINK_CAPABLE_SET (Val, LINK_CAPABLE_X8);
+      break;
+
+    case LNKW_X16:
+    default:
+      Val = LINK_CAPABLE_SET (Val, LINK_CAPABLE_X16);
+      break;
+    };
+    Ac01PcieCsrOut32 (CfgAddr + PORT_LINK_CTRL_OFF, Val);
+    Ac01PcieCsrIn32 (CfgAddr + GEN2_CTRL_OFF, &Val);
+    switch (RC->Pcie[PcieIndex].MaxWidth) {
+    case LNKW_X2:
+      Val = NUM_OF_LANES_SET (Val, NUM_OF_LANES_X2);
+      break;
+
+    case LNKW_X4:
+      Val = NUM_OF_LANES_SET (Val, NUM_OF_LANES_X4);
+      break;
+
+    case LNKW_X8:
+      Val = NUM_OF_LANES_SET (Val, NUM_OF_LANES_X8);
+      break;
+
+    case LNKW_X16:
+    default:
+      Val = NUM_OF_LANES_SET (Val, NUM_OF_LANES_X16);
+      break;
+    };
+    Ac01PcieCsrOut32 (CfgAddr + GEN2_CTRL_OFF, Val);
+    Ac01PcieCsrIn32 (CfgAddr + LINK_CAPABILITIES_REG, &Val);
+    switch (RC->Pcie[PcieIndex].MaxWidth) {
+    case LNKW_X2:
+      Val = PCIE_CAP_MAX_LINK_WIDTH_SET (Val, PCIE_CAP_MAX_LINK_WIDTH_X2);
+      break;
+
+    case LNKW_X4:
+      Val = PCIE_CAP_MAX_LINK_WIDTH_SET (Val, PCIE_CAP_MAX_LINK_WIDTH_X4);
+      break;
+
+    case LNKW_X8:
+      Val = PCIE_CAP_MAX_LINK_WIDTH_SET (Val, PCIE_CAP_MAX_LINK_WIDTH_X8);
+      break;
+
+    case LNKW_X16:
+    default:
+      Val = PCIE_CAP_MAX_LINK_WIDTH_SET (Val, PCIE_CAP_MAX_LINK_WIDTH_X16);
+      break;
+    };
+
+    switch (RC->Pcie[PcieIndex].MaxGen) {
+    case SPEED_GEN1:
+      Val = PCIE_CAP_MAX_LINK_SPEED_SET (Val, MAX_LINK_SPEED_25);
+      break;
+
+    case SPEED_GEN2:
+      Val = PCIE_CAP_MAX_LINK_SPEED_SET (Val, MAX_LINK_SPEED_50);
+      break;
+
+    case SPEED_GEN3:
+      Val = PCIE_CAP_MAX_LINK_SPEED_SET (Val, MAX_LINK_SPEED_80);
+      break;
+
+    default:
+      Val = PCIE_CAP_MAX_LINK_SPEED_SET (Val, MAX_LINK_SPEED_160);
+      break;
+    };
+    /* Enable ASPM Capability */
+    Val = PCIE_CAP_ACTIVE_STATE_LINK_PM_SUPPORT_SET(Val, L0S_L1_SUPPORTED);
+    Ac01PcieCsrOut32 (CfgAddr + LINK_CAPABILITIES_REG, Val);
+
+    Ac01PcieCsrIn32 (CfgAddr + LINK_CONTROL2_LINK_STATUS2_REG, &Val);
+    switch (RC->Pcie[PcieIndex].MaxGen) {
+    case SPEED_GEN1:
+      Val = PCIE_CAP_TARGET_LINK_SPEED_SET (Val, MAX_LINK_SPEED_25);
+      break;
+
+    case SPEED_GEN2:
+      Val = PCIE_CAP_TARGET_LINK_SPEED_SET (Val, MAX_LINK_SPEED_50);
+      break;
+
+    case SPEED_GEN3:
+      Val = PCIE_CAP_TARGET_LINK_SPEED_SET (Val, MAX_LINK_SPEED_80);
+      break;
+
+    default:
+      Val = PCIE_CAP_TARGET_LINK_SPEED_SET (Val, MAX_LINK_SPEED_160);
+      break;
+    };
+    Ac01PcieCsrOut32 (CfgAddr + LINK_CONTROL2_LINK_STATUS2_REG, Val);
+
+    // Set Zero byte request handling
+    Ac01PcieCsrIn32 (CfgAddr + FILTER_MASK_2_OFF, &Val);
+    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);
+    Ac01PcieCsrOut32 (CfgAddr + FILTER_MASK_2_OFF, Val);
+    Ac01PcieCsrIn32 (CfgAddr + AMBA_ORDERING_CTRL_OFF, &Val);
+    Val = AX_MSTR_ZEROLREAD_FW_SET (Val, 0);
+    Ac01PcieCsrOut32 (CfgAddr + AMBA_ORDERING_CTRL_OFF, Val);
+
+    //
+    // Set Completion with CRS handling for CFG Request
+    // Set Completion with CA/UR handling non-CFG Request
+    //
+    Ac01PcieCsrIn32 (CfgAddr + AMBA_ERROR_RESPONSE_DEFAULT_OFF, &Val);
+    Val = AMBA_ERROR_RESPONSE_CRS_SET (Val, 0x2);
+    Ac01PcieCsrOut32 (CfgAddr + AMBA_ERROR_RESPONSE_DEFAULT_OFF, Val);
+
+    // Set Legacy PCIE interrupt map to INTA
+    Ac01PcieCsrIn32 (CfgAddr + BRIDGE_CTRL_INT_PIN_INT_LINE_REG, &Val);
+    Val = INT_PIN_SET (Val, 1);
+    Ac01PcieCsrOut32 (CfgAddr + BRIDGE_CTRL_INT_PIN_INT_LINE_REG, Val);
+    Ac01PcieCsrIn32 (CsrAddr + IRQSEL, &Val);
+    Val = INTPIN_SET (Val, 1);
+    Ac01PcieCsrOut32 (CsrAddr + IRQSEL, Val);
+
+    if (RC->Pcie[PcieIndex].MaxGen != SPEED_GEN1) {
+      Ac01PcieConfigureEqualization (RC, PcieIndex);
+      if (RC->Pcie[PcieIndex].MaxGen == SPEED_GEN3) {
+        Ac01PcieConfigurePresetGen3 (RC, PcieIndex);
+      } else if (RC->Pcie[PcieIndex].MaxGen == SPEED_GEN4) {
+        Ac01PcieConfigurePresetGen4 (RC, PcieIndex);
+      }
+    }
+
+    // Mask Completion Timeout
+    Ac01PcieCsrIn32 (CfgAddr + AMBA_LINK_TIMEOUT_OFF, &Val);
+    Val = LINK_TIMEOUT_PERIOD_DEFAULT_SET (Val, 1);
+    Ac01PcieCsrOut32 (CfgAddr + AMBA_LINK_TIMEOUT_OFF, Val);
+    Ac01PcieCsrIn32 (CfgAddr + UNCORR_ERR_MASK_OFF, &Val);
+    Val = CMPLT_TIMEOUT_ERR_MASK_SET (Val, 1);
+    Ac01PcieCsrOut32 (CfgAddr + UNCORR_ERR_MASK_OFF, Val);
+
+    // Program Class Code
+    Ac01PcieCsrIn32 (CfgAddr + TYPE1_CLASS_CODE_REV_ID_REG, &Val);
+    Val = REVISION_ID_SET (Val, 4);
+    Val = SUBCLASS_CODE_SET (Val, 4);
+    Val = BASE_CLASS_CODE_SET (Val, 6);
+    Ac01PcieCsrOut32 (CfgAddr + TYPE1_CLASS_CODE_REV_ID_REG, Val);
+
+    // Program VendorID and DeviceID
+    Ac01PcieCsrIn32 (CfgAddr + TYPE1_DEV_ID_VEND_ID_REG, &Val);
+    Val = VENDOR_ID_SET (Val, AMPERE_PCIE_VENDORID);
+    if (RCA == RC->Type) {
+      Val = DEVICE_ID_SET (Val, AC01_PCIE_BRIDGE_DEVICEID_RCA + PcieIndex);
+    } else {
+      Val = DEVICE_ID_SET (Val, AC01_PCIE_BRIDGE_DEVICEID_RCB + PcieIndex);
+    }
+    Ac01PcieCsrOut32 (CfgAddr + TYPE1_DEV_ID_VEND_ID_REG, Val);
+
+    // Enable common clock for downstream
+    Ac01PcieCsrIn32 (CfgAddr + LINK_CONTROL_LINK_STATUS_REG, &Val);
+    Val = PCIE_CAP_SLOT_CLK_CONFIG_SET (Val, 1);
+    Val = PCIE_CAP_COMMON_CLK_SET (Val, 1);
+    Ac01PcieCsrOut32 (CfgAddr + LINK_CONTROL_LINK_STATUS_REG, Val);
+
+    // Assert PERST low to reset endpoint
+    PcieBoardAssertPerst (RC, PcieIndex, 0, FALSE);
+
+    // Start link training
+    Ac01PcieCsrIn32 (CsrAddr + LINKCTRL, &Val);
+    Val = LTSSMENB_SET (Val, 1);
+    Ac01PcieCsrOut32 (CsrAddr + LINKCTRL, Val);
+
+    // Complete the PERST pulse
+    PcieBoardAssertPerst (RC, PcieIndex, 0, TRUE);
+
+    // Match aux_clk to system
+    Ac01PcieCsrIn32 (CfgAddr + AUX_CLK_FREQ_OFF, &Val);
+    Val = AUX_CLK_FREQ_SET (Val, AUX_CLK_500MHZ);
+    Ac01PcieCsrOut32 (CfgAddr + AUX_CLK_FREQ_OFF, Val);
+
+    // Lock programming of config space
+    Ac01PcieCsrIn32 (CfgAddr + MISC_CONTROL_1_OFF, &Val);
+    Val = DBI_RO_WR_EN_SET (Val, 0);
+    Ac01PcieCsrOut32 (CfgAddr + MISC_CONTROL_1_OFF, Val);
+
+    if (ReInit == 1) {
+      break;
+    }
+  }
+
+  // Program VendorID and DeviceId
+  if (!EFI_ERROR (SMProRegRd (RC->Socket, RC->HBAddr  + HBPDVIDR, &Val))) {
+    Val = PCIVENDID_SET (Val, AMPERE_PCIE_VENDORID);
+    if (RCA == RC->Type) {
+      Val = PCIDEVID_SET (Val, AC01_HOST_BRIDGE_DEVICEID_RCA);
+    } else {
+      Val = PCIDEVID_SET (Val, AC01_HOST_BRIDGE_DEVICEID_RCB);
+    }
+    SMProRegWr (RC->Socket, RC->HBAddr  + HBPDVIDR, Val);
+  }
+
+  return 0;
+}
+
+STATIC BOOLEAN
+PcieLinkUpCheck (
+  IN AC01_PCIE  *Pcie,
+  OUT UINT32    *LtssmState
+  )
+{
+  VOID *        CsrAddr;
+  UINT32        BlockEvent, LinkStat;
+
+  CsrAddr = (VOID *) Pcie->CsrAddr;
+
+  // Check if card present
+  // smlh_ltssm_state[13:8] = 0
+  // phy_status[2] = 0
+  // smlh_link_up[1] = 0
+  // rdlh_link_up[0] = 0
+  Ac01PcieCsrIn32 (CsrAddr + LINKSTAT, &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 0;
+  }
+
+   Ac01PcieCsrIn32 (CsrAddr +  BLOCKEVENTSTAT, &BlockEvent);
+   Ac01PcieCsrIn32 (CsrAddr +  LINKSTAT, &LinkStat);
+
+   if ((BlockEvent & LINKUP_MASK) != 0) {
+     *LtssmState = SMLH_LTSSM_STATE_GET (LinkStat);
+     PCIE_DEBUG ("%a *LtssmState=%lx Linkup\n", __func__, *LtssmState);
+     return 1;
+   }
+
+   return 0;
+}
+
+VOID
+Ac01PcieCoreUpdateLink (
+  IN AC01_RC  *RC,
+  OUT BOOLEAN *IsNextRoundNeeded,
+  OUT INT8    *FailedPciePtr,
+  OUT INT8    *FailedPcieCount
+  )
+{
+  INTN                      PcieIndex;
+  AC01_PCIE                *Pcie;
+  UINT32                    Ltssm, i;
+  UINT32                    Val;
+  VOID                     *CfgAddr;
+
+  *IsNextRoundNeeded = FALSE;
+  *FailedPcieCount   = 0;
+  for (i = 0; i < MAX_PCIE_B; i++) {
+    FailedPciePtr[i] = -1;
+  }
+
+  if (!RC->Active) {
+    return;
+  }
+
+  // Loop for all controllers
+  for (PcieIndex = 0; PcieIndex < RC->MaxPcieController; PcieIndex++) {
+    Pcie = &RC->Pcie[PcieIndex];
+    CfgAddr = (VOID *) (RC->MmcfgAddr + (RC->Pcie[PcieIndex].DevNum << 15));
+
+    if (Pcie->Active && !Pcie->LinkUp) {
+      if (PcieLinkUpCheck (Pcie, &Ltssm)) {
+        Pcie->LinkUp = 1;
+        Ac01PcieCsrIn32 (CfgAddr + LINK_CONTROL_LINK_STATUS_REG, &Val);
+        PCIE_DEBUG (
+          "%a S%d RC%d RP%d NEGO_LINK_WIDTH: 0x%x LINK_SPEED: 0x%x\n",
+          __FUNCTION__,
+          RC->Socket, RC->ID,
+          PcieIndex,
+          PCIE_CAP_NEGO_LINK_WIDTH_GET (Val),
+          PCIE_CAP_LINK_SPEED_GET (Val)
+          );
+
+        // Un-mask Completion Timeout
+        Ac01PcieCsrIn32 (CfgAddr + AMBA_LINK_TIMEOUT_OFF, &Val);
+        Val = LINK_TIMEOUT_PERIOD_DEFAULT_SET (Val, 32);
+        Ac01PcieCsrOut32 (CfgAddr + AMBA_LINK_TIMEOUT_OFF, Val);
+        Ac01PcieCsrIn32 (CfgAddr + UNCORR_ERR_MASK_OFF, &Val);
+        Val = CMPLT_TIMEOUT_ERR_MASK_SET (Val, 0);
+        Ac01PcieCsrOut32 (CfgAddr + UNCORR_ERR_MASK_OFF, Val);
+      } else {
+        *IsNextRoundNeeded = TRUE;
+        FailedPciePtr[*FailedPcieCount] = PcieIndex;
+        *FailedPcieCount += 1;
+      }
+    }
+  }
+}
+
+VOID
+Ac01PcieCoreEndEnumeration (
+  AC01_RC *RC
+  )
+{
+  //
+  // Reserved for hook from stack ending of enumeration phase processing.
+  // Emptry for now.
+  //
+}
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PcieCoreLib.c b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PcieCoreLib.c
new file mode 100755
index 000000000000..41976a919354
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PcieCoreLib.c
@@ -0,0 +1,492 @@
+/** @file
+
+  Copyright (c) 2020, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <string.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/ArmGenericTimerCounterLib.h>
+#include <Library/PciHostBridgeLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/PciHostBridgeResourceAllocation.h>
+#include <Library/PrintLib.h>
+#include <Library/SerialPortLib.h>
+#include <Library/PcieBoardLib.h>
+#include <Library/AmpereCpuLib.h>
+#include <PciePatchAcpi.h>
+#include <PcieCore.h>
+
+STATIC UINT64 RCRegBase[MAX_AC01_PCIE_ROOT_COMPLEX] = { AC01_PCIE_REGISTER_BASE };
+STATIC UINT64 RCMmioBase[MAX_AC01_PCIE_ROOT_COMPLEX] = { AC01_PCIE_MMIO_BASE };
+STATIC UINT64 RCMmio32Base[MAX_AC01_PCIE_ROOT_COMPLEX] = { AC01_PCIE_MMIO32_BASE };
+STATIC UINT64 RCMmio32Base1P[MAX_AC01_PCIE_ROOT_COMPLEX] = { AC01_PCIE_MMIO32_BASE_1P };
+STATIC AC01_RC RCList[MAX_AC01_PCIE_ROOT_COMPLEX];
+STATIC INT8 PciList[MAX_AC01_PCIE_ROOT_COMPLEX];
+
+STATIC
+VOID
+SerialPrint (
+  IN  CONST CHAR8  *FormatString,
+  ...
+  )
+{
+  UINT8     Buf[64];
+  VA_LIST   Marker;
+  UINTN     NumberOfPrinted;
+
+  VA_START (Marker, FormatString);
+  NumberOfPrinted = AsciiVSPrint ((CHAR8 *) Buf, sizeof (Buf), FormatString, Marker);
+  SerialPortWrite (Buf, NumberOfPrinted);
+  VA_END (Marker);
+}
+
+AC01_RC *
+GetRCList (
+  UINT8 Idx
+  )
+{
+  return &RCList[Idx];
+}
+
+/**
+   Map BusDxe Host bridge and Root bridge Indexes to PCIE core BSP driver Root Complex Index.
+
+   @param  HBIndex               Index to identify of PCIE Host bridge.
+   @param  RBIndex               Index to identify of PCIE Root bridge.
+   @retval UINT8                 Index to identify Root Complex instance from global RCList.
+**/
+STATIC
+UINT8
+GetRCIndex (
+  IN UINT8 HBIndex,
+  IN UINT8 RBIndex
+  )
+{
+  //
+  // BusDxe addresses resources based on Host bridge and Root bridge.
+  // Map those to Root Complex index/instance known for Pcie Core BSP driver
+  //
+  return HBIndex * MAX_AC01_PCIE_ROOT_BRIDGE + RBIndex;
+}
+
+/**
+   Prepare to start PCIE core BSP driver
+
+   @retval EFI_SUCCESS           Success to initialize.
+**/
+EFI_STATUS
+Ac01PcieSetup (
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_SYSTEM_TABLE   *SystemTable
+  )
+{
+  AC01_RC       *RC;
+  INTN          RCIndex;
+
+  ZeroMem (&RCList, sizeof (AC01_RC) * MAX_AC01_PCIE_ROOT_COMPLEX);
+
+  // Adjust MMIO32 base address 1P vs 2P
+  if (!PlatSlaveSocketPresent ()) {
+    CopyMem ((VOID *) &RCMmio32Base, (VOID *) &RCMmio32Base1P, sizeof (UINT64) * MAX_AC01_PCIE_ROOT_COMPLEX);
+  }
+
+  for (RCIndex = 0; RCIndex < MAX_AC01_PCIE_ROOT_COMPLEX; RCIndex++) {
+    RC = &RCList[RCIndex];
+    RC->Socket = RCIndex / RCS_PER_SOCKET;
+    RC->ID = RCIndex % RCS_PER_SOCKET;
+
+    Ac01PcieCoreBuildRCStruct (RC, RCRegBase[RCIndex], RCMmioBase[RCIndex], RCMmio32Base[RCIndex]);
+  }
+
+  // Build the UEFI menu
+  PcieBoardScreenInitialize (ImageHandle, SystemTable, RCList);
+
+  return EFI_SUCCESS;
+}
+
+UINT8
+Ac01PcieGetTotalHBs (VOID)
+{
+  return 16;
+}
+
+UINT8
+Ac01PcieGetTotalRBsPerHB (
+  UINTN RCIndex
+  )
+{
+  return 1;
+}
+
+UINTN
+Ac01PcieGetRootBridgeAttribute (
+  IN UINTN HBIndex,
+  IN UINTN RBIndex
+  )
+{
+  return 2;
+}
+
+UINTN
+Ac01PcieGetRootBridgeSegmentNumber (
+  IN UINTN HBIndex,
+  IN UINTN RBIndex
+  )
+{
+  UINTN RCIndex;
+  AC01_RC *RC;
+  UINTN SegmentNumber;
+
+  RCIndex = GetRCIndex (HBIndex, RBIndex);
+  RC = &RCList[RCIndex];
+  SegmentNumber = RCIndex;
+
+  // Get board specific overrides
+  PcieBoardGetRCSegmentNumber (RC, &SegmentNumber);
+  RC->Logical = SegmentNumber;
+
+  return SegmentNumber;
+}
+
+STATIC
+VOID
+SortPciList (
+  INT8 *PciList
+  )
+{
+  INT8     Idx1, Idx2;
+
+  for (Idx2 = 0, Idx1 = 0; Idx2 < MAX_AC01_PCIE_ROOT_COMPLEX; Idx2++) {
+    if (PciList[Idx2] < 0) {
+      continue;
+    }
+    PciList[Idx1] = PciList[Idx2];
+    if (Idx1 != Idx2) {
+      PciList[Idx2] = -1;
+    }
+    Idx1++;
+  }
+
+  for (Idx2 = 0; Idx2 < Idx1; Idx2++) {
+    PCIE_DEBUG (
+      " %a: PciList[%d]=%d TcuAddr=0x%llx\n",
+      __FUNCTION__,
+      Idx2,
+      PciList[Idx2],
+      RCList[PciList[Idx2]].TcuAddr
+      );
+  }
+}
+
+BOOLEAN
+Ac01PcieCheckRootBridgeDisabled (
+  IN UINTN HBIndex,
+  IN UINTN RBIndex
+  )
+{
+  UINTN         RCIndex;
+  INT8          Ret;
+
+  RCIndex = HBIndex;
+  Ret = !RCList[RCIndex].Active;
+  if (Ret) {
+    PciList[HBIndex] = -1;
+  } else {
+    PciList[HBIndex] = HBIndex;
+  }
+  if (HBIndex == (MAX_AC01_PCIE_ROOT_COMPLEX -1)) {
+    SortPciList (PciList);
+    if (!PlatSlaveSocketPresent ()) {
+      AcpiPatchPciMem32 (PciList);
+    }
+    AcpiInstallMcfg (PciList);
+    AcpiInstallIort (PciList);
+  }
+  return Ret;
+}
+
+/**
+   Initialize Host bridge
+
+   @param  HBIndex               Index to identify of PCIE Host bridge.
+   @retval EFI_SUCCESS           Success to initialize.
+**/
+EFI_STATUS
+Ac01PcieSetupHostBridge (
+  IN UINTN HBIndex
+  )
+{
+  return EFI_SUCCESS;
+}
+
+/**
+   Initialize Root bridge
+
+   @param  HBIndex               Index to identify of PCIE Host bridge.
+   @param  RBIndex               Index to identify of underneath PCIE Root bridge.
+   @param  RootBridgeInstance    The pointer of instance of the Root bridge IO.
+   @retval EFI_SUCCESS           Success to initialize.
+   @retval EFI_DEVICE_ERROR      Error when initializing.
+**/
+EFI_STATUS
+Ac01PcieSetupRootBridge (
+  IN UINTN HBIndex,
+  IN UINTN RBIndex,
+  IN PCI_ROOT_BRIDGE *RootBridge
+  )
+{
+  UINTN                     RCIndex;
+  AC01_RC                   *RC;
+  UINT32                    Result;
+
+  RCIndex = GetRCIndex (HBIndex, RBIndex);
+  RC = &RCList[RCIndex];
+  if (!RC->Active) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  RC->RootBridge = (VOID *) RootBridge;
+
+  // Initialize Root Complex and underneath controllers
+  Result = Ac01PcieCoreSetupRC (RC, 0, 0);
+  if (Result) {
+    PCIE_ERR ("RootComplex[%d]: Init Failed\n", RCIndex);
+
+    goto Error;
+  }
+
+  // Populate resource aperture
+  RootBridge->Bus.Base = 0x0;
+  RootBridge->Bus.Limit = 0xFF;
+  RootBridge->Io.Base = RC->IoAddr;
+  RootBridge->Io.Limit = RC->IoAddr + IO_SPACE - 1;
+  RootBridge->Mem.Base = RC->Mmio32Addr;
+  RootBridge->Mem.Limit = RootBridge->Mem.Base + MMIO32_SPACE - 1;
+  RootBridge->PMem.Base = RootBridge->Mem.Base;
+  RootBridge->PMem.Limit = RootBridge->Mem.Limit;
+  RootBridge->MemAbove4G.Base = 0x0;
+  RootBridge->MemAbove4G.Limit = 0x0;
+  RootBridge->PMemAbove4G.Base = RC->MmioAddr;
+  RootBridge->PMemAbove4G.Limit = RootBridge->PMemAbove4G.Base + MMIO_SPACE - 1;
+
+  PCIE_DEBUG (" +    Bus: 0x%x - 0x%lx\n", RootBridge->Bus.Base, RootBridge->Bus.Limit);
+  PCIE_DEBUG (" +     Io: 0x%x - 0x%lx\n", RootBridge->Io.Base, RootBridge->Io.Limit);
+  PCIE_DEBUG (" +    Mem: 0x%x - 0x%lx\n", RootBridge->Mem.Base, RootBridge->Mem.Limit);
+  PCIE_DEBUG (" +   PMem: 0x%x - 0x%lx\n", RootBridge->PMem.Base, RootBridge->PMem.Limit);
+  PCIE_DEBUG (" +  4GMem: 0x%x - 0x%lx\n", RootBridge->MemAbove4G.Base, RootBridge->MemAbove4G.Limit);
+  PCIE_DEBUG (" + 4GPMem: 0x%x - 0x%lx\n", RootBridge->PMemAbove4G.Base, RootBridge->PMemAbove4G.Limit);
+
+  return EFI_SUCCESS;
+
+Error:
+  RC->Active = FALSE;
+  return EFI_DEVICE_ERROR;
+}
+
+/**
+   Reads/Writes an PCI configuration register.
+
+   Reads/Writes from/to register specified by Address.
+   This function must guarantee that all PCI read and write operations are
+   serialized.
+
+   If Address > 0x0FFFFFFF, then ASSERT().
+
+   Address de-couple to format of Bus:Dev:Fn
+   Bus = (Address >> 20) & 0xFF;
+   Dev = (Address >> 15) & 0x1F;
+   Func = (Address >> 12) & 0x07;
+   Reg = (Address) & 0xFFF;
+**/
+
+EFI_STATUS
+Ac01PcieConfigRW (
+  IN      VOID      *RootInstance,
+  IN      UINT64    Address,
+  IN      BOOLEAN   Write,
+  IN      UINTN     Width,
+  IN OUT  VOID      *Data)
+{
+  AC01_RC           *RC = NULL;
+  VOID              *CfgBase = NULL;
+  UINTN             RCIndex;
+  UINT32            Reg;
+
+  ASSERT (Address <= 0x0FFFFFFF);
+
+  for (RCIndex = 0; RCIndex < MAX_AC01_PCIE_ROOT_COMPLEX; RCIndex++) {
+    RC = &RCList[RCIndex];
+    if (RC->RootBridge == RootInstance) {
+      break;
+    }
+  }
+
+  if ((RCIndex == MAX_AC01_PCIE_ROOT_COMPLEX) || (RC == NULL)) {
+    PCIE_ERR("Can't find Root Bridge instance:%p\n", RootInstance);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Reg = Address & 0xFFF;
+
+  CfgBase = (VOID *) ((UINT64) RC->MmcfgAddr + (Address & 0x0FFFF000));
+  if (Write) {
+    switch (Width) {
+    case 1:
+      Ac01PcieCfgOut8 ((VOID *) (CfgBase + (Reg & (~(Width - 1)))), *((UINT8 *) Data));
+      break;
+
+    case 2:
+      Ac01PcieCfgOut16 ((VOID *) (CfgBase + (Reg & (~(Width - 1)))), *((UINT16 *) Data));
+      break;
+
+    case 4:
+      Ac01PcieCfgOut32 ((VOID *) (CfgBase + (Reg & (~(Width - 1)))), *((UINT32 *) Data));
+      break;
+
+    default:
+      return EFI_INVALID_PARAMETER;
+    }
+  } else {
+    switch (Width) {
+    case 1:
+      Ac01PcieCfgIn8 ((VOID *) (CfgBase + (Reg & (~(Width - 1)))), (UINT8 *) Data);
+      break;
+
+    case 2:
+      Ac01PcieCfgIn16 ((VOID *) (CfgBase + (Reg & (~(Width - 1)))), (UINT16 *) Data);
+      if (Reg == 0xAE && (*((UINT16 *) Data)) == 0xFFFF) {
+        SerialPrint ("PANIC due to PCIE RC:%d link issue\n", RC->ID);
+        // Loop forever waiting for failsafe/watch dog time out
+        do {} while (1);
+      }
+      break;
+
+    case 4:
+      Ac01PcieCfgIn32 ((VOID *) (CfgBase + (Reg & (~(Width - 1)))), (UINT32 *) Data);
+      break;
+
+    default:
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+VOID
+Ac01PcieCorePollLinkUp (VOID)
+{
+  INTN          RCIndex, PcieIndex, i;
+  BOOLEAN       IsNextRoundNeeded = FALSE, NextRoundNeeded;
+  UINT64        PrevTick, CurrTick, ElapsedCycle;
+  UINT64        TimerTicks64;
+  UINT8         ReInit;
+  INT8          FailedPciePtr[MAX_PCIE_B];
+  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 {
+    // Update timer
+    CurrTick = ArmGenericTimerGetSystemCount ();
+    if (CurrTick < PrevTick) {
+      ElapsedCycle += (UINT64)(~0x0ULL) - PrevTick;
+      PrevTick = 0;
+    }
+    ElapsedCycle += (CurrTick - PrevTick);
+    PrevTick = CurrTick;
+  } while (ElapsedCycle < TimerTicks64);
+
+  for (RCIndex = 0; RCIndex < MAX_AC01_PCIE_ROOT_COMPLEX; RCIndex++) {
+    Ac01PcieCoreUpdateLink (&RCList[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 < MAX_AC01_PCIE_ROOT_COMPLEX; RCIndex++) {
+      Ac01PcieCoreUpdateLink (&RCList[RCIndex], &IsNextRoundNeeded, FailedPciePtr, &FailedPcieCount);
+      if (IsNextRoundNeeded) {
+        for (i = 0; i < FailedPcieCount; i++) {
+          PcieIndex = FailedPciePtr[i];
+          if (PcieIndex == -1) {
+            continue;
+          }
+
+          // Some controller still observes link-down. Re-init controller
+          Ac01PcieCoreSetupRC (&RCList[RCIndex], 1, PcieIndex);
+        }
+      }
+    }
+
+    goto _link_polling;
+  }
+}
+
+/**
+   Prepare to end PCIE core BSP driver
+**/
+VOID
+Ac01PcieEnd (VOID)
+{
+  Ac01PcieCorePollLinkUp ();
+}
+
+/**
+   Callback funciton for EndEnumeration notification from PCI stack
+
+   @param  RCIndex               Index to identify of PCIE root complex.
+   @param  PortIndex             Index to identify of PCIE root port.
+   @param  Phase                 The phase of enumeration as informed from PCI stack.
+**/
+VOID
+Ac01PcieHostBridgeNotifyPhase (
+  IN UINTN HBIndex,
+  IN UINTN RBIndex,
+  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE    Phase
+  )
+{
+  AC01_RC *RC;
+  UINTN RCIndex;
+
+  RCIndex = GetRCIndex (HBIndex, RBIndex);
+  RC = &RCList[RCIndex];
+
+  switch (Phase) {
+  case EfiPciHostBridgeEndEnumeration:
+    Ac01PcieCoreEndEnumeration (RC);
+    break;
+
+  case EfiPciHostBridgeBeginEnumeration:
+  case EfiPciHostBridgeBeginBusAllocation:
+  case EfiPciHostBridgeEndBusAllocation:
+  case EfiPciHostBridgeBeginResourceAllocation:
+  case EfiPciHostBridgeAllocateResources:
+  case EfiPciHostBridgeSetResources:
+  case EfiPciHostBridgeFreeResources:
+  case EfiPciHostBridgeEndResourceAllocation:
+  case EfiMaxPciHostBridgeEnumerationPhase:
+    break;
+  }
+}
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PciePatchAcpi.c b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PciePatchAcpi.c
new file mode 100755
index 000000000000..ea19f5074288
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCore/PciePatchAcpi.c
@@ -0,0 +1,607 @@
+/** @file
+
+  Copyright (c) 2020, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <string.h>
+#include <IndustryStandard/Acpi30.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/AcpiHelperLib.h>
+#include <Protocol/AcpiTable.h>
+#include <IndustryStandard/IoRemappingTable.h>
+#include <Library/PrintLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PcieBoardLib.h>
+#include <AcpiHeader.h>
+#include <Platform/Ac01.h>
+#include "Pcie.h"
+#include "PcieCore.h"
+
+#define ACPI_RESOURCE_NAME_ADDRESS16            0x88
+#define ACPI_RESOURCE_NAME_ADDRESS64            0x8A
+
+#define RCA_NUM_TBU_PMU         6
+#define RCB_NUM_TBU_PMU         10
+
+STATIC  UINT32  gTbuPmuIrqArray[] = { SMMU_TBU_PMU_IRQ_START_ARRAY };
+STATIC  UINT32  gTcuPmuIrqArray[] = { SMMU_TCU_PMU_IRQ_START_ARRAY };
+
+#pragma pack(1)
+typedef struct
+{
+  UINT64 ullBaseAddress;
+  UINT16 usSegGroupNum;
+  UINT8  ucStartBusNum;
+  UINT8  ucEndBusNum;
+  UINT32 Reserved2;
+} EFI_MCFG_CONFIG_STRUCTURE;
+
+typedef struct
+{
+  EFI_ACPI_DESCRIPTION_HEADER Header;
+  UINT64 Reserved1;
+} EFI_MCFG_TABLE_CONFIG;
+
+typedef struct {
+  UINT64 AddressGranularity;
+  UINT64 AddressMin;
+  UINT64 AddressMax;
+  UINT64 AddressTranslation;
+  UINT64 RangeLength;
+} QWordMemory;
+
+typedef struct ResourceEntry {
+  UINT8   ResourceType;
+  UINT16  ResourceSize;
+  UINT8   Attribute;
+  UINT8   Byte0;
+  UINT8   Byte1;
+  VOID    *ResourcePtr;
+} RESOURCE;
+
+STATIC QWordMemory Qmem[] = {
+  { AC01_PCIE_RCA2_QMEM },
+  { AC01_PCIE_RCA3_QMEM },
+  { AC01_PCIE_RCB0_QMEM },
+  { AC01_PCIE_RCB1_QMEM },
+  { AC01_PCIE_RCB2_QMEM },
+  { AC01_PCIE_RCB3_QMEM }
+};
+
+typedef struct {
+  EFI_ACPI_6_0_IO_REMAPPING_NODE          Node;
+  UINT64                                  Base;
+  UINT32                                  Flags;
+  UINT32                                  Reserved;
+  UINT64                                  VatosAddress;
+  UINT32                                  Model;
+  UINT32                                  Event;
+  UINT32                                  Pri;
+  UINT32                                  Gerr;
+  UINT32                                  Sync;
+  UINT32                                  ProximityDomain;
+  UINT32                                  DeviceIdMapping;
+} EFI_ACPI_6_2_IO_REMAPPING_SMMU3_NODE;
+
+typedef struct {
+  EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE        Node;
+  UINT32                                    ItsIdentifier;
+} AC01_ITS_NODE;
+
+
+typedef struct {
+  EFI_ACPI_6_0_IO_REMAPPING_RC_NODE         Node;
+  EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE        RcIdMapping;
+} AC01_RC_NODE;
+
+typedef struct {
+  EFI_ACPI_6_2_IO_REMAPPING_SMMU3_NODE      Node;
+  EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE        InterruptMsiMapping;
+  EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE        InterruptMsiMappingSingle;
+} AC01_SMMU_NODE;
+
+typedef struct {
+  EFI_ACPI_6_0_IO_REMAPPING_TABLE           Iort;
+  AC01_ITS_NODE                             ItsNode[2];
+  AC01_RC_NODE                              RcNode[2];
+  AC01_SMMU_NODE                            SmmuNode[2];
+} AC01_IO_REMAPPING_STRUCTURE;
+
+#define FIELD_OFFSET(type, name)            __builtin_offsetof (type, name)
+#define __AC01_ID_MAPPING(In, Num, Out, Ref, Flags)    \
+  {                                                    \
+    In,                                                \
+    Num,                                               \
+    Out,                                               \
+    FIELD_OFFSET (AC01_IO_REMAPPING_STRUCTURE, Ref),   \
+    Flags                                              \
+  }
+
+EFI_STATUS
+EFIAPI
+AcpiPatchPciMem32 (
+  INT8 *PciSegEnabled
+  )
+{
+  EFI_ACPI_SDT_PROTOCOL             *AcpiTableProtocol;
+  EFI_STATUS                        Status;
+  UINTN                             Idx, Ix;
+  EFI_ACPI_HANDLE                   TableHandle, SegHandle;
+  CHAR8                             Buffer[MAX_ACPI_NODE_PATH];
+  CHAR8                             *KB, *B;
+  EFI_ACPI_DATA_TYPE                DataType;
+  UINTN                             DataSize, Mem32;
+  RESOURCE                          *Rs;
+  QWordMemory                       *Qm;
+  UINT8                             Segment;
+
+  Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (VOID**) &AcpiTableProtocol);
+  if (EFI_ERROR(Status)) {
+    PCIE_ERR ("Unable to locate ACPI table protocol Guid\n");
+    return Status;
+  }
+
+  /* Open DSDT Table */
+  Status = AcpiOpenDSDT (AcpiTableProtocol, &TableHandle);
+  if (EFI_ERROR (Status)) {
+    PCIE_ERR ("Unable to open DSDT table\n");
+    return Status;
+  }
+
+  for (Idx = 0; PciSegEnabled[Idx] != -1; Idx++) {
+    if (PciSegEnabled[Idx] > SOCKET0_LAST_RC) { /* Physical segment */
+      break;
+    }
+    if (PciSegEnabled[Idx] < SOCKET0_FIRST_RC) {
+      continue;
+    }
+
+    /* DSDT PCI devices to use Physical segment */
+    AsciiSPrint (Buffer, sizeof (Buffer), "\\_SB.PCI%x._CRS.RBUF", PciSegEnabled[Idx]);
+    Status = AcpiTableProtocol->FindPath (TableHandle, (VOID *) Buffer, &SegHandle);
+    if (EFI_ERROR (Status)) {
+      continue;
+    }
+
+    for (Ix = 0; Ix < 3; Ix++) {
+      Status = AcpiTableProtocol->GetOption (SegHandle,
+                                Ix, &DataType, (VOID *) &B, &DataSize);
+      KB = B;
+      if (EFI_ERROR (Status)) {
+        continue;
+      }
+
+      if (Ix == 0) { /* B[0] == AML_NAME_OP */
+        if (!((DataSize == 1) && (DataType == EFI_ACPI_DATA_TYPE_OPCODE))) {
+          break;
+        }
+      } else if (Ix == 1) { /* *B == "RBUF"  */
+        if (!((DataSize == 4) && (DataType == EFI_ACPI_DATA_TYPE_NAME_STRING))) {
+          break;
+        }
+      } else { /* Ix:2 11 42 07 0A 6E 88 ... */
+        if (DataType != EFI_ACPI_DATA_TYPE_CHILD) {
+          break;
+        }
+
+        KB += 5; /* Point to Resource type */
+        Rs = (RESOURCE *) KB;
+        Mem32 = 0;
+        while ((Mem32 == 0) && ((KB - B) < DataSize)) {
+          if (Rs->ResourceType == ACPI_RESOURCE_NAME_ADDRESS16) {
+            KB += (Rs->ResourceSize + 3); /* Type + Size */
+            Rs = (RESOURCE *) KB;
+          } else if (Rs->ResourceType == ACPI_RESOURCE_NAME_ADDRESS64) {
+
+            if (Rs->Attribute == 0x00) { /* The first QWordMemory */
+              Mem32 = 1;
+              Segment = PciSegEnabled[Idx] - 2;
+              Qm = (QWordMemory *)&(Rs->ResourcePtr);
+              *Qm = Qmem[Segment]; /* Physical segment */
+            }
+            KB += (Rs->ResourceSize + 3); /* Type + Size */
+            Rs = (RESOURCE *) KB;
+          }
+        }
+        if (Mem32 != 0) {
+          Status = AcpiTableProtocol->SetOption (SegHandle,
+                                Ix, (VOID *) B, DataSize);
+        }
+      }
+    }
+  }
+  AcpiTableProtocol->Close (TableHandle);
+  /* Update DSDT Checksum */
+  AcpiDSDTUpdateChecksum (AcpiTableProtocol);
+
+  return Status;
+}
+
+VOID
+ConstructMcfg (
+  VOID *McfgPtr,
+  INT8 *PciSegEnabled,
+  UINT32 McfgCount
+  )
+{
+  EFI_MCFG_TABLE_CONFIG            McfgHeader = {
+    {
+      EFI_ACPI_6_1_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE,
+      McfgCount,
+      1,
+      0x00,                        // Checksum will be updated at runtime
+      EFI_ACPI_OEM_ID,
+      EFI_ACPI_OEM_TABLE_ID,
+      EFI_ACPI_OEM_REVISION,
+      EFI_ACPI_CREATOR_ID,
+      EFI_ACPI_CREATOR_REVISION
+    },
+    0x0000000000000000,            // Reserved
+  };
+  EFI_MCFG_CONFIG_STRUCTURE        TMcfg = {
+    .ullBaseAddress = 0,
+    .usSegGroupNum = 0,
+    .ucStartBusNum = 0,
+    .ucEndBusNum = 255,
+    .Reserved2 = 0,
+  };
+  UINT32                           Idx;
+  VOID                             *TMcfgPtr = McfgPtr;
+  AC01_RC                          *Rc;
+
+  CopyMem (TMcfgPtr, &McfgHeader, sizeof (EFI_MCFG_TABLE_CONFIG));
+  TMcfgPtr += sizeof (EFI_MCFG_TABLE_CONFIG);
+  for (Idx = 0; PciSegEnabled[Idx] != -1; Idx++) {
+    Rc = GetRCList (PciSegEnabled[Idx]); /* Logical */
+    TMcfg.ullBaseAddress = Rc->MmcfgAddr;
+    TMcfg.usSegGroupNum = Rc->Logical;
+    CopyMem (TMcfgPtr, &TMcfg, sizeof (EFI_MCFG_CONFIG_STRUCTURE));
+    TMcfgPtr += sizeof (EFI_MCFG_CONFIG_STRUCTURE);
+  }
+}
+
+EFI_STATUS
+EFIAPI
+AcpiInstallMcfg (
+  INT8 *PciSegEnabled
+  )
+{
+  UINT32                            RcCount, McfgCount;
+  EFI_ACPI_TABLE_PROTOCOL           *AcpiTableProtocol;
+  UINTN                             TableKey;
+  EFI_STATUS                        Status;
+  VOID                              *McfgPtr;
+
+  if (IsAcpiInstalled (EFI_ACPI_6_1_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE)) {
+    DEBUG ((DEBUG_INFO, "MCFG table is already installed.  Skipping...\n"));
+    return EFI_ABORTED;
+  }
+
+  Status = gBS->LocateProtocol (
+                  &gEfiAcpiTableProtocolGuid,
+                  NULL,
+                  (VOID **) &AcpiTableProtocol
+                  );
+  if (EFI_ERROR (Status)) {
+    PCIE_ERR ("MCFG: Unable to locate ACPI table entry\n");
+    return Status;
+  }
+  for (RcCount = 0; PciSegEnabled[RcCount] != -1; RcCount++)
+    ;
+  McfgCount = sizeof (EFI_MCFG_TABLE_CONFIG) + sizeof (EFI_MCFG_CONFIG_STRUCTURE) * RcCount;
+  McfgPtr = AllocateZeroPool (McfgCount);
+  if (McfgPtr == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  ConstructMcfg (McfgPtr, PciSegEnabled, McfgCount);
+  Status = AcpiTableProtocol->InstallAcpiTable (
+                                AcpiTableProtocol,
+                                McfgPtr,
+                                McfgCount,
+                                &TableKey
+                                );
+  if (EFI_ERROR (Status)) {
+    PCIE_ERR ("MCFG: Unable to install MCFG table entry\n");
+  }
+  FreePool (McfgPtr);
+  return Status;
+}
+
+STATIC
+VOID
+ConstructIort (
+  VOID *IortPtr,
+  UINT32 RcCount,
+  UINT32 SmmuPmuAgentCount,
+  UINT32 HeaderCount,
+  INT8 *PciSegEnabled
+  )
+{
+  EFI_ACPI_6_0_IO_REMAPPING_TABLE   TIort = {
+    .Header = __ACPI_HEADER (EFI_ACPI_6_0_IO_REMAPPING_TABLE_SIGNATURE,
+               AC01_IO_REMAPPING_STRUCTURE,
+               EFI_ACPI_IO_REMAPPING_TABLE_REVISION),
+    .NumNodes = (3 * RcCount) + SmmuPmuAgentCount,
+    .NodeOffset = sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE),
+    0
+  };
+
+  AC01_ITS_NODE                    TItsNode = {
+    .Node = {
+          EFI_ACPI_IORT_TYPE_ITS_GROUP,
+          sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE) + 4,
+          0x0,
+          0x0,
+          0x0,
+          0x0,
+    .NumItsIdentifiers = 1,
+    },
+    .ItsIdentifier = 1,
+  };
+
+  AC01_RC_NODE                     TRcNode = {
+    {
+      {
+        EFI_ACPI_IORT_TYPE_ROOT_COMPLEX,
+        sizeof (AC01_RC_NODE),
+        0x1,
+        0x0,
+        0x1,
+        FIELD_OFFSET (AC01_RC_NODE, RcIdMapping),
+      },
+      EFI_ACPI_IORT_MEM_ACCESS_PROP_CCA,
+      0x0,
+      0x0,
+      EFI_ACPI_IORT_MEM_ACCESS_FLAGS_CPM |
+      EFI_ACPI_IORT_MEM_ACCESS_FLAGS_DACS,
+      EFI_ACPI_IORT_ROOT_COMPLEX_ATS_UNSUPPORTED,
+      .PciSegmentNumber = 0,
+    },
+    __AC01_ID_MAPPING (0x0, 0xffff, 0x0, SmmuNode, 0),
+  };
+
+  AC01_SMMU_NODE                   TSmmuNode = {
+    {
+       {
+          EFI_ACPI_IORT_TYPE_SMMUv3,
+          sizeof (AC01_SMMU_NODE),
+          0x2,  /* Revision */
+          0x0,
+          0x2,  /* Mapping Count */
+          FIELD_OFFSET (AC01_SMMU_NODE, InterruptMsiMapping),
+       },
+       .Base = 0,
+       EFI_ACPI_IORT_SMMUv3_FLAG_COHAC_OVERRIDE,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0x0,
+       0x0,
+       0,
+       .DeviceIdMapping = 1,
+    },
+    __AC01_ID_MAPPING (0x0, 0xffff, 0, SmmuNode, 0),
+    __AC01_ID_MAPPING (0x0, 0x1, 0, SmmuNode, 1),
+  };
+
+  EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE   TPmcgNode = {
+    {
+      EFI_ACPI_IORT_TYPE_PMCG,
+      sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE),
+      0x1,
+      0x0,
+      0x0,
+      0x0,
+    },
+    0, /* Page 0 Base. Need to be filled */
+    0, /* GSIV. Need to be filled */
+    0, /* Node reference. Need to be filled */
+    0, /* Page 1 Base. Need to be filled. */
+  };
+
+  UINT32                            Idx, Idx1, SmmuNodeOffset[MAX_AC01_PCIE_ROOT_COMPLEX];
+  VOID                              *TIortPtr = IortPtr, *SmmuPtr, *PmcgPtr;
+  UINT32                            ItsOffset[MAX_AC01_PCIE_ROOT_COMPLEX];
+  AC01_RC                           *Rc;
+  UINTN                             NumTbuPmu;
+
+  TIort.Header.Length = HeaderCount;
+  CopyMem (TIortPtr, &TIort, sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE));
+  TIortPtr += sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE);
+  for (Idx = 0; Idx < RcCount; Idx++) {
+    ItsOffset[Idx] = TIortPtr - IortPtr;
+    TItsNode.ItsIdentifier = PciSegEnabled[Idx]; /* Physical */
+    CopyMem (TIortPtr, &TItsNode, sizeof (AC01_ITS_NODE));
+    TIortPtr += sizeof (AC01_ITS_NODE);
+  }
+
+  SmmuPtr = TIortPtr + RcCount * sizeof (AC01_RC_NODE);
+  PmcgPtr = SmmuPtr + RcCount * sizeof (AC01_SMMU_NODE);
+  for (Idx = 0; Idx < RcCount; Idx++) {
+    SmmuNodeOffset[Idx] = SmmuPtr - IortPtr;
+    Rc = GetRCList (PciSegEnabled[Idx]); /* Physical RC */
+    TSmmuNode.Node.Base = Rc->TcuAddr;
+    TSmmuNode.InterruptMsiMapping.OutputBase = PciSegEnabled[Idx] << 16;
+    TSmmuNode.InterruptMsiMapping.OutputReference = ItsOffset[Idx];
+    TSmmuNode.InterruptMsiMappingSingle.OutputBase = PciSegEnabled[Idx] << 16;
+    TSmmuNode.InterruptMsiMappingSingle.OutputReference = ItsOffset[Idx];
+    CopyMem (SmmuPtr, &TSmmuNode, sizeof (AC01_SMMU_NODE));
+    SmmuPtr += sizeof (AC01_SMMU_NODE);
+
+    if (!SmmuPmuAgentCount) {
+      continue;
+    }
+
+    /* Add PMCG nodes */
+    if (Rc->Type == RCA) {
+      NumTbuPmu = RCA_NUM_TBU_PMU;
+    } else {
+      NumTbuPmu = RCB_NUM_TBU_PMU;
+    }
+    for (Idx1 = 0; Idx1 < NumTbuPmu; Idx1 ++) {
+      TPmcgNode.Base = Rc->TcuAddr;
+      if (NumTbuPmu == RCA_NUM_TBU_PMU) {
+        switch (Idx1) {
+        case 0:
+          TPmcgNode.Base += 0x40000;
+          break;
+
+        case 1:
+          TPmcgNode.Base += 0x60000;
+          break;
+
+        case 2:
+          TPmcgNode.Base += 0xA0000;
+          break;
+
+        case 3:
+          TPmcgNode.Base += 0xE0000;
+          break;
+
+        case 4:
+          TPmcgNode.Base += 0x100000;
+          break;
+
+        case 5:
+          TPmcgNode.Base += 0x140000;
+          break;
+        }
+      } else {
+       switch (Idx1) {
+        case 0:
+          TPmcgNode.Base += 0x40000;
+          break;
+
+        case 1:
+          TPmcgNode.Base += 0x60000;
+          break;
+
+        case 2:
+          TPmcgNode.Base += 0xA0000;
+          break;
+
+        case 3:
+          TPmcgNode.Base += 0xE0000;
+          break;
+
+        case 4:
+          TPmcgNode.Base += 0x120000;
+          break;
+
+        case 5:
+          TPmcgNode.Base += 0x160000;
+          break;
+
+        case 6:
+          TPmcgNode.Base += 0x180000;
+          break;
+
+        case 7:
+          TPmcgNode.Base += 0x1C0000;
+          break;
+
+        case 8:
+          TPmcgNode.Base += 0x200000;
+          break;
+
+        case 9:
+          TPmcgNode.Base += 0x240000;
+          break;
+        }
+      }
+      TPmcgNode.Page1Base = TPmcgNode.Base + 0x12000;
+      TPmcgNode.Base += 0x2000;
+      TPmcgNode.NodeReference = SmmuNodeOffset[Idx];
+      TPmcgNode.OverflowInterruptGsiv = gTbuPmuIrqArray[PciSegEnabled[Idx]] + Idx1;
+      CopyMem (PmcgPtr, &TPmcgNode, sizeof (TPmcgNode));
+      PmcgPtr += sizeof (TPmcgNode);
+    }
+
+    /* TCU PMCG */
+    TPmcgNode.Base = Rc->TcuAddr;
+    TPmcgNode.Base += 0x2000;
+    TPmcgNode.Page1Base = Rc->TcuAddr + 0x12000;
+    TPmcgNode.NodeReference = SmmuNodeOffset[Idx];
+    TPmcgNode.OverflowInterruptGsiv = gTcuPmuIrqArray[PciSegEnabled[Idx]];
+    CopyMem (PmcgPtr, &TPmcgNode, sizeof (TPmcgNode));
+    PmcgPtr += sizeof (TPmcgNode);
+  }
+
+  for (Idx = 0; Idx < RcCount; Idx++) {
+    TRcNode.Node.PciSegmentNumber = GetRCList (PciSegEnabled[Idx])->Logical; /* Logical */
+    TRcNode.RcIdMapping.OutputReference = SmmuNodeOffset[Idx];
+    CopyMem (TIortPtr, &TRcNode, sizeof (AC01_RC_NODE));
+    TIortPtr += sizeof (AC01_RC_NODE);
+  }
+}
+
+EFI_STATUS
+EFIAPI
+AcpiInstallIort (
+  INT8 *PciSegEnabled
+  )
+{
+  UINT32                            RcCount, SmmuPmuAgentCount, TotalCount;
+  VOID                              *IortPtr;
+  UINTN                             TableKey;
+  EFI_STATUS                        Status;
+  EFI_ACPI_TABLE_PROTOCOL           *AcpiTableProtocol;
+
+  if (IsAcpiInstalled (EFI_ACPI_6_0_IO_REMAPPING_TABLE_SIGNATURE)) {
+    DEBUG ((DEBUG_INFO, "IORT table is already installed.  Skipping...\n"));
+    return EFI_ABORTED;
+  }
+
+  Status = gBS->LocateProtocol (
+                  &gEfiAcpiTableProtocolGuid,
+                  NULL,
+                  (VOID **) &AcpiTableProtocol
+                  );
+  if (EFI_ERROR (Status)) {
+    PCIE_ERR ("IORT: Unable to locate ACPI table entry\n");
+    return Status;
+  }
+
+  for (RcCount = 0, SmmuPmuAgentCount = 0; PciSegEnabled[RcCount] != -1; RcCount++) {
+    if ((GetRCList (PciSegEnabled[RcCount]))->Type == RCA) {
+      SmmuPmuAgentCount += RCA_NUM_TBU_PMU;
+    } else {
+      SmmuPmuAgentCount += RCB_NUM_TBU_PMU;
+    }
+    SmmuPmuAgentCount += 1; /* Only 1 TCU */
+  }
+
+  if (!PcieBoardCheckSmmuPmuEnabled ()) {
+    SmmuPmuAgentCount = 0;
+  }
+
+  TotalCount = sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE) +
+        RcCount * (sizeof (AC01_ITS_NODE) + sizeof (AC01_RC_NODE) + sizeof (AC01_SMMU_NODE)) +
+        SmmuPmuAgentCount * sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE);
+
+  IortPtr = AllocateZeroPool (TotalCount);
+  if (IortPtr == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  ConstructIort (IortPtr, RcCount, SmmuPmuAgentCount, TotalCount, PciSegEnabled);
+
+  Status = AcpiTableProtocol->InstallAcpiTable (
+                                AcpiTableProtocol,
+                                IortPtr,
+                                TotalCount,
+                                &TableKey
+                                );
+  if (EFI_ERROR (Status)) {
+    PCIE_ERR ("IORT: Unable to install IORT table entry\n");
+  }
+  FreePool (IortPtr);
+  return Status;
+}
-- 
2.17.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#68511): https://edk2.groups.io/g/devel/message/68511
Mute This Topic: https://groups.io/mt/78825495/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-





More information about the edk2-devel-archive mailing list