From: "Leif Lindholm" <leif@nuviainc.com>
To: devel@edk2.groups.io, nhi@os.amperecomputing.com
Cc: patches@amperecomputing.com, vunguyen@os.amperecomputing.com,
Thang Nguyen <thang@os.amperecomputing.com>,
Chuong Tran <chuong@os.amperecomputing.com>,
Phong Vo <phong@os.amperecomputing.com>,
Michael D Kinney <michael.d.kinney@intel.com>,
Ard Biesheuvel <ardb+tianocore@kernel.org>,
Nate DeSimone <nathaniel.l.desimone@intel.com>
Subject: Re: [edk2-devel] [edk2-platforms][PATCH v6 11/30] AmpereAltraPkg: Add Ac01PcieLib library instance
Date: Thu, 18 Nov 2021 15:58:35 +0000 [thread overview]
Message-ID: <YZZ4K+6opH8hvv17@leviathan> (raw)
In-Reply-To: <20211118134115.29199-1-nhi@os.amperecomputing.com>
On Thu, Nov 18, 2021 at 20:41:15 +0700, Nhi Pham via groups.io wrote:
> From: Vu Nguyen <vunguyen@os.amperecomputing.com>
>
> Provides essential functions to initialize the PCIe Root Complex on
> Ampere Altra processor.
>
> Cc: Thang Nguyen <thang@os.amperecomputing.com>
> Cc: Chuong Tran <chuong@os.amperecomputing.com>
> Cc: Phong Vo <phong@os.amperecomputing.com>
> Cc: Leif Lindholm <leif@nuviainc.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
>
> Signed-off-by: Nhi Pham <nhi@os.amperecomputing.com>
Reviewed-by: Leif Lindholm <leif@nuviainc.com>
> ---
> Changes since v5:
> * Fixed an error with the NOOPT build.
> https://edk2.groups.io/g/devel/message/83855
>
> Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec | 6 +
> Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc | 2 +
> Platform/Ampere/JadePkg/Jade.dsc | 5 +
> Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/Ac01PcieLib.inf | 42 +
> Silicon/Ampere/AmpereAltraPkg/Library/BoardPcieLibNull/BoardPcieLibNull.inf | 25 +
> Silicon/Ampere/AmpereAltraPkg/Include/Library/Ac01PcieLib.h | 49 +
> Silicon/Ampere/AmpereAltraPkg/Include/Library/BoardPcieLib.h | 45 +
> Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.h | 372 +++++
> Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.c | 1416 ++++++++++++++++++++
> Silicon/Ampere/AmpereAltraPkg/Library/BoardPcieLibNull/BoardPcieLibNull.c | 47 +
> 10 files changed, 2009 insertions(+)
>
> diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
> index e19925c68a0e..7bd4d3ac9462 100644
> --- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
> +++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
> @@ -43,6 +43,12 @@ [LibraryClasses]
> ## @libraryclass Defines a set of methods to access flash memory.
> FlashLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h
>
> + ## @libraryclass Defines a set of platform dependent functions
> + BoardPcieLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/BoardPcieLib.h
> +
> + ## @libraryclass Defines a set of methods to initialize Pcie
> + Ac01PcieLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/Ac01PcieLib.h
> +
> [Guids]
> ## NVParam MM GUID
> gNVParamMmGuid = { 0xE4AC5024, 0x29BE, 0x4ADC, { 0x93, 0x36, 0x87, 0xB5, 0xA0, 0x76, 0x23, 0x2D } }
> diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
> index fa9b120b2c2b..5b767ecb024f 100644
> --- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
> +++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
> @@ -81,6 +81,8 @@ [LibraryClasses.common]
> NVParamLib|Silicon/Ampere/AmpereAltraPkg/Library/NVParamLib/NVParamLib.inf
> MailboxInterfaceLib|Silicon/Ampere/AmpereAltraPkg/Library/MailboxInterfaceLib/MailboxInterfaceLib.inf
> SystemFirmwareInterfaceLib|Silicon/Ampere/AmpereAltraPkg/Library/SystemFirmwareInterfaceLib/SystemFirmwareInterfaceLib.inf
> + PciePhyLib|Silicon/Ampere/AmpereAltraBinPkg/Library/PciePhyLib/PciePhyLib.inf
> + Ac01PcieLib|Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/Ac01PcieLib.inf
> AmpereCpuLib|Silicon/Ampere/AmpereAltraPkg/Library/AmpereCpuLib/AmpereCpuLib.inf
> TimeBaseLib|EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.inf
> I2cLib|Silicon/Ampere/AmpereAltraPkg/Library/DwI2cLib/DwI2cLib.inf
> diff --git a/Platform/Ampere/JadePkg/Jade.dsc b/Platform/Ampere/JadePkg/Jade.dsc
> index e4b29e36fc8d..23a297d0dbeb 100644
> --- a/Platform/Ampere/JadePkg/Jade.dsc
> +++ b/Platform/Ampere/JadePkg/Jade.dsc
> @@ -82,6 +82,11 @@ [LibraryClasses]
> #
> AcpiLib|EmbeddedPkg/Library/AcpiLib/AcpiLib.inf
>
> + #
> + # Pcie Board
> + #
> + BoardPcieLib|Silicon/Ampere/AmpereAltraPkg/Library/BoardPcieLibNull/BoardPcieLibNull.inf
> +
> ################################################################################
> #
> # Specific Platform Pcds
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/Ac01PcieLib.inf b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/Ac01PcieLib.inf
> new file mode 100644
> index 000000000000..8c8661265cd5
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/Ac01PcieLib.inf
> @@ -0,0 +1,42 @@
> +## @file
> +#
> +# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> + INF_VERSION = 0x0001001B
> + BASE_NAME = Ac01PcieLib
> + FILE_GUID = 8ABFA0FC-313E-11E8-B467-0ED5F89F718B
> + MODULE_TYPE = BASE
> + VERSION_STRING = 1.0
> + LIBRARY_CLASS = Ac01PcieLib
> +
> +[Sources]
> + PcieCore.c
> + PcieCore.h
> +
> +[Packages]
> + ArmPkg/ArmPkg.dec
> + MdePkg/MdePkg.dec
> + Silicon/Ampere/AmpereAltraBinPkg/AmpereAltraBinPkg.dec
> + Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
> +
> +[LibraryClasses]
> + ArmGenericTimerCounterLib
> + BaseLib
> + BoardPcieLib
> + DebugLib
> + HobLib
> + IoLib
> + PciePhyLib
> + SystemFirmwareInterfaceLib
> + TimerLib
> +
> +[Guids]
> + gPlatformInfoHobGuid
> +
> +[Depex]
> + TRUE
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/BoardPcieLibNull/BoardPcieLibNull.inf b/Silicon/Ampere/AmpereAltraPkg/Library/BoardPcieLibNull/BoardPcieLibNull.inf
> new file mode 100644
> index 000000000000..435092b864ec
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Library/BoardPcieLibNull/BoardPcieLibNull.inf
> @@ -0,0 +1,25 @@
> +## @file
> +#
> +# Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> + INF_VERSION = 0x0001001B
> + BASE_NAME = BoardPcieLibNull
> + FILE_GUID = 7820C925-F525-4101-8E64-87838356B7A6
> + MODULE_TYPE = BASE
> + VERSION_STRING = 1.0
> + LIBRARY_CLASS = BoardPcieLib
> +
> +[Sources.common]
> + BoardPcieLibNull.c
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> + Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
> +
> +[LibraryClasses]
> + BaseLib
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Library/Ac01PcieLib.h b/Silicon/Ampere/AmpereAltraPkg/Include/Library/Ac01PcieLib.h
> new file mode 100644
> index 000000000000..692bc2669915
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Include/Library/Ac01PcieLib.h
> @@ -0,0 +1,49 @@
> +/** @file
> +
> + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef AC01_PCIE_LIB_H_
> +#define AC01_PCIE_LIB_H_
> +
> +/**
> + Setup and initialize the AC01 PCIe Root Complex and underneath PCIe controllers
> +
> + @param RootComplex Pointer to Root Complex structure
> + @param ReInit Re-init status
> + @param ReInitPcieIndex PCIe controller index
> +
> + @retval RETURN_SUCCESS The Root Complex has been initialized successfully.
> + @retval RETURN_DEVICE_ERROR PHY, Memory or PIPE is not ready.
> +**/
> +RETURN_STATUS
> +Ac01PcieCoreSetupRC (
> + IN AC01_ROOT_COMPLEX *RootComplex,
> + IN BOOLEAN ReInit,
> + IN UINT8 ReInitPcieIndex
> + );
> +
> +/**
> + Verify the link status and retry to initialize the Root Complex if there's any issue.
> +
> + @param RootComplexList Pointer to the Root Complex list
> +**/
> +VOID
> +Ac01PcieCorePostSetupRC (
> + IN AC01_ROOT_COMPLEX *RootComplexList
> + );
> +
> +/**
> + Callback function when the Host Bridge enumeration end.
> +
> + @param RootComplex Pointer to the Root Complex structure
> +**/
> +VOID
> +Ac01PcieCoreEndEnumeration (
> + IN AC01_ROOT_COMPLEX *RootComplex
> + );
> +
> +#endif /* AC01_PCIE_LIB_H_ */
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Library/BoardPcieLib.h b/Silicon/Ampere/AmpereAltraPkg/Include/Library/BoardPcieLib.h
> new file mode 100644
> index 000000000000..34e7dee702ec
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Include/Library/BoardPcieLib.h
> @@ -0,0 +1,45 @@
> +/** @file
> +
> + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef BOARD_PCIE_LIB_H_
> +#define BOARD_PCIE_LIB_H_
> +
> +#include <Guid/RootComplexInfoHob.h>
> +
> +/**
> + Assert PERST of the PCIe controller
> +
> + @param[in] RootComplex Root Complex instance.
> + @param[in] PcieIndex PCIe controller index of input Root Complex.
> + @param[in] IsPullToHigh Target status for the PERST.
> +
> + @retval RETURN_SUCCESS The operation is successful.
> + @retval Others An error occurred.
> +**/
> +RETURN_STATUS
> +EFIAPI
> +BoardPcieAssertPerst (
> + IN AC01_ROOT_COMPLEX *RootComplex,
> + IN UINT8 PcieIndex,
> + IN BOOLEAN IsPullToHigh
> + );
> +
> +/**
> + Override the segment number for a root complex with a board specific number.
> +
> + @param[in] RootComplex Root Complex instance with properties.
> +
> + @retval Segment number corresponding to the input root complex.
> + Default segment number is 0x0F.
> +**/
> +UINT16
> +BoardPcieGetSegmentNumber (
> + IN AC01_ROOT_COMPLEX *RootComplex
> + );
> +
> +#endif /* BOARD_PCIE_LIB_H_ */
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.h b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.h
> new file mode 100644
> index 000000000000..1db8a68b3df4
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.h
> @@ -0,0 +1,372 @@
> +/** @file
> +
> + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef AC01_PCIE_CORE_H_
> +#define AC01_PCIE_CORE_H_
> +
> +#define BUS_SHIFT 20
> +#define DEV_SHIFT 15
> +
> +#define GET_LOW_8_BITS(x) ((x) & 0xFF)
> +#define GET_HIGH_8_BITS(x) (((x) >> 8) & 0xFF)
> +#define GET_LOW_16_BITS(x) ((x) & 0xFFFF)
> +#define GET_HIGH_16_BITS(x) (((x) >> 16) & 0xFFFF)
> +#define GET_CAPABILITY_PTR(x) (GET_LOW_16_BITS (x) >> 8)
> +#define GET_EXT_CAPABILITY_PTR(x) (GET_HIGH_16_BITS (x) >> 4)
> +
> +#define WORD_ALIGN_MASK 0x3
> +
> +#define MAX_REINIT 3 // Number of soft reset retry
> +
> +#define SLOT_POWER_LIMIT_75W 75 // Watt
> +
> +#define LINK_CHECK_SUCCESS 0
> +#define LINK_CHECK_FAILED -1
> +#define LINK_CHECK_WRONG_PARAMETER 1
> +
> +#define AMPERE_PCIE_VENDOR_ID 0x1DEF
> +#define AC01_HOST_BRIDGE_DEVICE_ID_RCA 0xE100
> +#define AC01_HOST_BRIDGE_DEVICE_ID_RCB 0xE110
> +#define AC01_PCIE_BRIDGE_DEVICE_ID_RCA 0xE101
> +#define AC01_PCIE_BRIDGE_DEVICE_ID_RCB 0xE111
> +
> +#define MEMRDY_TIMEOUT 10 // 10 us
> +#define PIPE_CLOCK_TIMEOUT 20000 // 20,000 us
> +#define LTSSM_TRANSITION_TIMEOUT 100000 // 100 ms in total
> +#define EP_LINKUP_TIMEOUT (10 * 1000) // 10ms
> +#define LINK_WAIT_INTERVAL_US 50
> +
> +#define PFA_MODE_ENABLE 0
> +#define PFA_MODE_CLEAR 1
> +#define PFA_MODE_READ 2
> +
> +//
> +// Host Bridge registers
> +//
> +#define AC01_HOST_BRIDGE_RCA_DEV_MAP_REG 0x0
> +#define AC01_HOST_BRIDGE_RCB_DEV_MAP_REG 0x4
> +#define AC01_HOST_BRIDGE_VENDOR_DEVICE_ID_REG 0x10
> +
> +// AC01_HOST_BRIDGE_RCA_DEV_MAP_REG
> +#define RCA_DEV_MAP_SET(dst, src) (((dst) & ~0x7) | (((UINT32) (src)) & 0x7))
> +#define RCA_DEV_MAP_GET(val) ((val) & 0x7)
> +
> +// AC01_HOST_BRIDGE_RCB_DEV_MAP_REG
> +#define RCB_DEV_MAP_LOW_SET(dst, src) (((dst) & ~0x7) | (((UINT32) (src)) & 0x7))
> +#define RCB_DEV_MAP_LOW_GET(val) ((val) & 0x7)
> +
> +#define RCB_DEV_MAP_HIGH_SET(dst, src) (((dst) & ~0x70) | (((UINT32) (src) << 4) & 0x70))
> +#define RCB_DEV_MAP_HIGH_GET(val) (((val) & 0x7) >> 4)
> +
> +// AC01_HOST_BRIDGE_VENDOR_DEVICE_ID_REG
> +#define VENDOR_ID_SET(dst, src) (((dst) & ~0xFFFF) | (((UINT32) (src)) & 0xFFFF))
> +#define VENDOR_ID_GET(val) ((val) & 0xFFFF)
> +
> +#define DEVICE_ID_SET(dst, src) (((dst) & ~0xFFFF0000) | (((UINT32) (src) << 16) & 0xFFFF0000))
> +#define DEVICE_ID_GET(val) (((val) & 0xFFFF0000) >> 16)
> +
> +//
> +// PCIe core registers
> +//
> +#define AC01_PCIE_CORE_LINK_CTRL_REG 0x0
> +#define AC01_PCIE_CORE_LINK_STAT_REG 0x4
> +#define AC01_PCIE_CORE_IRQ_SEL_REG 0xC
> +#define AC01_PCIE_CORE_HOT_PLUG_STAT_REG 0x28
> +#define AC01_PCIE_CORE_IRQ_ENABLE_REG 0x30
> +#define AC01_PCIE_CORE_IRQ_EVENT_STAT_REG 0x38
> +#define AC01_PCIE_CORE_BLOCK_EVENT_STAT_REG 0x3C
> +#define AC01_PCIE_CORE_RESET_REG 0xC000
> +#define AC01_PCIE_CORE_CLOCK_REG 0xC004
> +#define AC01_PCIE_CORE_MEM_READY_REG 0xC104
> +#define AC01_PCIE_CORE_RAM_SHUTDOWN_REG 0xC10C
> +
> +// AC01_PCIE_CORE_LINK_CTRL_REG
> +#define LTSSMENB_SET(dst, src) (((dst) & ~0x1) | (((UINT32) (src)) & 0x1))
> +#define HOLD_LINK_TRAINING 0
> +#define START_LINK_TRAINING 1
> +#define DEVICETYPE_SET(dst, src) (((dst) & ~0xF0) | (((UINT32) (src) << 4) & 0xF0))
> +#define DEVICETYPE_GET(val) (((val) & 0xF0) >> 4)
> +
> +// AC01_PCIE_CORE_LINK_STAT_REG
> +#define PHY_STATUS_MASK (1 << 2)
> +#define SMLH_LTSSM_STATE_MASK 0x3F00
> +#define SMLH_LTSSM_STATE_GET(val) ((val & SMLH_LTSSM_STATE_MASK) >> 8)
> +#define LTSSM_STATE_L0 0x11
> +#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
> +
> +// AC01_PCIE_CORE_IRQ_SEL_REG
> +#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))
> +#define IRQ_INT_A 0x01
> +
> +// AC01_PCIE_CORE_HOT_PLUG_STAT_REG
> +#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))
> +
> +// AC01_PCIE_CORE_BLOCK_EVENT_STAT_REG
> +#define LINKUP_MASK 0x1
> +
> +// AC01_PCIE_CORE_RESET_REG
> +#define DWC_PCIE_SET(dst, src) (((dst) & ~0x1) | (((UINT32) (src)) & 0x1))
> +#define RESET_MASK 0x1
> +#define ASSERT_RESET 0x1
> +
> +// AC01_PCIE_CORE_CLOCK_REG
> +#define AXIPIPE_SET(dst, src) (((dst) & ~0x1) | (((UINT32) (src)) & 0x1))
> +
> +// AC01_PCIE_CORE_MEM_READY_REG
> +#define MEMORY_READY 0x1
> +
> +// AC01_PCIE_CORE_RAM_SHUTDOWN_REG
> +#define SD_SET(dst, src) (((dst) & ~0x1) | (((UINT32) (src)) & 0x1))
> +
> +//
> +// AC01 PCIe Type 1 configuration 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 PCIE_CAPABILITY_BASE 0x70
> +#define EXT_CAPABILITY_START_BASE 0x100
> +#define AER_CAPABILITY_BASE 0x100
> +
> +// 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 DEFAULT_BASE_CLASS_CODE 6
> +#define SUB_CLASS_CODE_SET(dst, src) (((dst) & ~0xFF0000) | (((UINT32) (src) << 16) & 0xFF0000))
> +#define DEFAULT_SUB_CLASS_CODE 4
> +#define PROGRAM_INTERFACE_SET(dst, src) (((dst) & ~0xFF00) | (((UINT32) (src) << 8) & 0xFF00))
> +#define REVISION_ID_SET(dst, src) (((dst) & ~0xFF) | (((UINT32) (src)) & 0xFF))
> +#define DEFAULT_REVISION_ID 4
> +
> +// SEC_LAT_TIMER_SUB_BUS_SEC_BUS_PRI_BUS_REG
> +#define SUB_BUS_SET(dst, src) (((dst) & ~0xFF0000) | (((UINT32) (src) << 16) & 0xFF0000))
> +#define DEFAULT_SUB_BUS 0xFF
> +#define SEC_BUS_SET(dst, src) (((dst) & ~0xFF00) | (((UINT32) (src) << 8) & 0xFF00))
> +#define PRIM_BUS_SET(dst, src) (((dst) & ~0xFF) | (((UINT32) (src)) & 0xFF))
> +#define DEFAULT_PRIM_BUS 0x00
> +
> +// BRIDGE_CTRL_INT_PIN_INT_LINE_REG
> +#define INT_PIN_SET(dst, src) (((dst) & ~0xFF00) | (((UINT32) (src) << 8) & 0xFF00))
> +
> +//
> +// PCI Express Capability
> +//
> +#define PCIE_CAPABILITY_ID 0x10
> +#define LINK_CAPABILITIES_REG 0xC
> +#define LINK_CONTROL_LINK_STATUS_REG 0x10
> +#define SLOT_CAPABILITIES_REG 0x14
> +#define DEVICE_CONTROL2_DEVICE_STATUS2_REG 0x28
> +#define LINK_CAPABILITIES2_REG 0x2C
> +#define LINK_CONTROL2_LINK_STATUS2_REG 0x30
> +
> +// LINK_CAPABILITIES_REG
> +#define CAP_ACTIVE_STATE_LINK_PM_SUPPORT_SET(dst, src) (((dst) & ~0xC00) | (((UINT32)(src) << 10) & 0xC00))
> +#define NO_ASPM_SUPPORTED 0x0
> +#define L0S_SUPPORTED 0x1
> +#define L1_SUPPORTED 0x2
> +#define L0S_L1_SUPPORTED 0x3
> +#define CAP_MAX_LINK_WIDTH_GET(val) ((val & 0x3F0) >> 4)
> +#define CAP_MAX_LINK_WIDTH_SET(dst, src) (((dst) & ~0x3F0) | (((UINT32) (src) << 4) & 0x3F0))
> +#define CAP_MAX_LINK_WIDTH_X1 0x1
> +#define CAP_MAX_LINK_WIDTH_X2 0x2
> +#define CAP_MAX_LINK_WIDTH_X4 0x4
> +#define CAP_MAX_LINK_WIDTH_X8 0x8
> +#define CAP_MAX_LINK_WIDTH_X16 0x10
> +#define CAP_MAX_LINK_SPEED_GET(val) ((val & 0xF))
> +#define CAP_MAX_LINK_SPEED_SET(dst, src) (((dst) & ~0xF) | (((UINT32) (src)) & 0xF))
> +#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
> +
> +// LINK_CONTROL_LINK_STATUS_REG
> +#define CAP_DLL_ACTIVE_GET(val) ((val & 0x20000000) >> 29)
> +#define CAP_SLOT_CLK_CONFIG_SET(dst, src) (((dst) & ~0x10000000) | (((UINT32) (src) << 28) & 0x10000000))
> +#define CAP_NEGO_LINK_WIDTH_GET(val) ((val & 0x3F00000) >> 20)
> +#define CAP_LINK_SPEED_GET(val) ((val & 0xF0000) >> 16)
> +#define CAP_LINK_SPEED_SET(dst, src) (((dst) & ~0xF0000) | (((UINT32) (src) << 16) & 0xF0000))
> +#define CAP_LINK_SPEED_TO_VECTOR(val) (1 << ((val) - 1))
> +#define CAP_EN_CLK_POWER_MAN_GET(val) ((val & 0x100) >> 8)
> +#define CAP_EN_CLK_POWER_MAN_SET(dst, src) (((dst) & ~0x100) | (((UINT32) (src) << 8) & 0x100))
> +#define CAP_COMMON_CLK_SET(dst, src) (((dst) & ~0x40) | (((UINT32) (src) << 6) & 0x40))
> +#define CAP_RETRAIN_LINK_SET(dst, src) (((dst) & ~0x20) | (((UINT32) (src) << 5) & 0x20))
> +#define CAP_LINK_TRAINING_GET(val) ((val & 0x8000000) >> 27)
> +#define CAP_LINK_DISABLE_SET(dst, src) (((dst) & ~0x10) | (((UINT32)(src) << 4) & 0x10))
> +
> +// SLOT_CAPABILITIES_REG
> +#define SLOT_HPC_SET(dst, src) (((dst) & ~0x40) | (((UINT32) (src) << 6) & 0x40))
> +#define SLOT_CAP_SLOT_POWER_LIMIT_VALUE_SET(dst, src) \
> + (((dst) & ~0x7F80) | (((UINT32)(src) << 7) & 0x7F80))
> +
> +// DEVICE_CONTROL2_DEVICE_STATUS2_REG
> +#define CAP_CPL_TIMEOUT_VALUE_SET(dst, src) (((dst) & ~0xF) | (((UINT32) (src)) & 0xF))
> +
> +// LINK_CONTROL2_LINK_STATUS2_REG
> +#define CAP_TARGET_LINK_SPEED_SET(dst, src) (((dst) & ~0xF) | (((UINT32) (src)) & 0xF))
> +
> +//
> +// Advanced Error Reporting Capability
> +//
> +#define AER_CAPABILITY_ID 0x0001
> +#define UNCORR_ERR_STATUS_OFF 0x04
> +#define UNCORR_ERR_MASK_OFF 0x08
> +
> +// UNCORR_ERR_MASK_OFF
> +#define CMPLT_TIMEOUT_ERR_MASK_SET(dst, src) (((dst) & ~0x4000) | (((UINT32) (src) << 14) & 0x4000))
> +#define SDES_ERR_MASK_SET(dst, src) (((dst) & ~0x20) | (((UINT32)(src) << 5) & 0x20))
> +
> +//
> +// Vendor specific RAS D.E.S Capability
> +//
> +#define RAS_DES_CAPABILITY_ID 0x000B
> +#define EVENT_COUNTER_CONTROL_REG 0x08
> +#define EVENT_COUNTER_DATA_REG 0x0C
> +
> +// EVENT_COUNTER_CONTROL_REG
> +#define ECCR_GROUP_EVENT_SEL_SET(dst, src) (((dst) & ~0xFFF0000) | (((UINT32)(src) << 16) & 0xFFF0000))
> +#define ECCR_GROUP_SEL_SET(dst, src) (((dst) & ~0xF000000) | (((UINT32)(src) << 24) & 0xF000000))
> +#define ECCR_EVENT_SEL_SET(dst, src) (((dst) & ~0xFF0000) | (((UINT32)(src) << 16) & 0xFF0000))
> +#define ECCR_LANE_SEL_SET(dst, src) (((dst) & ~0xF00) | (((UINT32)(src) << 8) & 0xF00))
> +#define ECCR_EVENT_COUNTER_ENABLE_SET(dst, src) (((dst) & ~0x1C) | (((UINT32)(src) << 2) & 0x1C))
> +#define EVENT_COUNTER_ENABLE_NO_CHANGE 0x00
> +#define EVENT_COUNTER_ENABLE_ALL_ON 0x07
> +#define ECCR_EVENT_COUNTER_CLEAR_SET(dst, src) (((dst) & ~0x3) | (((UINT32)(src)) & 0x3))
> +#define EVENT_COUNTER_CLEAR_NO_CHANGE 0x00
> +#define EVENT_COUNTER_CLEAR_ALL_CLEAR 0x03
> +
> +//
> +// Secondary PCI Express Capability
> +//
> +#define SPCIE_CAPABILITY_ID 0x0019
> +#define SPCIE_CAP_OFF_0C_REG 0x0C
> +
> +// SPCIE_CAP_OFF_0C_REG
> +#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))
> +#define DEFAULT_GEN3_PRESET 0x05
> +
> +//
> +// Physical Layer 16.0 GT/s Extended Capability
> +//
> +#define PL16G_CAPABILITY_ID 0x0026
> +#define PL16G_STATUS_REG 0x0C
> +#define PL16G_CAP_OFF_20H_REG 0x20
> +
> +// PL16G_STATUS_REG
> +#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)
> +
> +// PL16G_CAP_OFF_20H_REG
> +#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))
> +#define DEFAULT_GEN4_PRESET 0x57
> +
> +//
> +// Port Logic
> +//
> +#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
> +
> +// PORT_LINK_CTRL_OFF
> +#define LINK_CAPABLE_SET(dst, src) (((dst) & ~0x3F0000) | (((UINT32) (src) << 16) & 0x3F0000))
> +#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 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_SET(dst, src) (((dst) & ~0x1F00) | (((UINT32) (src) << 8) & 0x1F00))
> +#define NUM_OF_LANES_X2 0x2
> +#define NUM_OF_LANES_X4 0x4
> +#define NUM_OF_LANES_X8 0x8
> +#define NUM_OF_LANES_X16 0x10
> +
> +// GEN3_RELATED_OFF
> +#define RATE_SHADOW_SEL_SET(dst, src) (((dst) & ~0x3000000) | (((UINT32) (src) << 24) & 0x3000000))
> +#define GEN3_DATA_RATE 0x00
> +#define GEN4_DATA_RATE 0x01
> +#define EQ_PHASE_2_3_SET(dst, src) (((dst) & ~0x200) | (((UINT32) (src) << 9) & 0x200))
> +#define ENABLE_EQ_PHASE_2_3 0x00
> +#define DISABLE_EQ_PHASE_2_3 0x01
> +#define RXEQ_REGRDLESS_SET(dst, src) (((dst) & ~0x2000) | (((UINT32) (src) << 13) & 0x2000))
> +#define ASSERT_RXEQ 0x01
> +
> +// GEN3_EQ_CONTROL_OFF
> +#define GEN3_EQ_FB_MODE(dst, src) (((dst) & ~0xF) | ((UINT32) (src) & 0xF))
> +#define FOM_METHOD 0x01
> +#define GEN3_EQ_PRESET_VEC(dst, src) (((dst) & 0xFF0000FF) | (((UINT32) (src) << 8) & 0xFFFF00))
> +#define EQ_DEFAULT_PRESET_VECTOR 0x370
> +#define GEN3_EQ_INIT_EVAL(dst,src) (((dst) & ~0x1000000) | (((UINT32) (src) << 24) & 0x1000000))
> +#define INCLUDE_INIT_FOM 0x01
> +
> +// MISC_CONTROL_1_OFF
> +#define DBI_RO_WR_EN_SET(dst, src) (((dst) & ~0x1) | (((UINT32) (src)) & 0x1))
> +#define ENABLE_WR 0x01
> +#define DISABLE_WR 0x00
> +
> +// 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_FREQ_SET(dst, src) (((dst) & ~0x1FF) | (((UINT32) (src)) & 0x1FF))
> +#define AUX_CLK_500MHZ 500
> +
> +#endif /* AC01_PCIE_CORE_H_ */
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.c b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.c
> new file mode 100644
> index 000000000000..ad648b1b9efd
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.c
> @@ -0,0 +1,1416 @@
> +/** @file
> +
> + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <PiDxe.h>
> +
> +#include <Guid/PlatformInfoHob.h>
> +#include <Guid/RootComplexInfoHob.h>
> +#include <Library/ArmGenericTimerCounterLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BoardPcieLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/HobLib.h>
> +#include <Library/IoLib.h>
> +#include <Library/PciePhyLib.h>
> +#include <Library/SystemFirmwareInterfaceLib.h>
> +#include <Library/TimerLib.h>
> +
> +#include "PcieCore.h"
> +
> +/**
> + Return the next extended capability base address
> +
> + @param RootComplex Pointer to AC01_ROOT_COMPLEX structure
> + @param PcieIndex PCIe controller index
> + @param IsRootComplex TRUE: Checking RootComplex configuration space
> + FALSE: Checking EP configuration space
> + @param ExtCapabilityId
> +**/
> +PHYSICAL_ADDRESS
> +GetCapabilityBase (
> + IN AC01_ROOT_COMPLEX *RootComplex,
> + IN UINT8 PcieIndex,
> + IN BOOLEAN IsRootComplex,
> + IN UINT16 ExtCapabilityId
> + )
> +{
> + BOOLEAN IsExtCapability = FALSE;
> + PHYSICAL_ADDRESS CfgBase;
> + UINT32 CapabilityId;
> + UINT32 NextCapabilityPtr;
> + UINT32 Val;
> +
> + if (IsRootComplex) {
> + CfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << DEV_SHIFT);
> + } else {
> + CfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << BUS_SHIFT);
> + }
> +
> + Val = MmioRead32 (CfgBase + TYPE1_CAP_PTR_REG);
> + NextCapabilityPtr = GET_LOW_8_BITS (Val);
> +
> + // Loop untill desired capability is found else return 0
> + while (1) {
> + if ((NextCapabilityPtr & WORD_ALIGN_MASK) != 0) {
> + // Not alignment, just return
> + return 0;
> + }
> +
> + Val = MmioRead32 (CfgBase + NextCapabilityPtr);
> + if (NextCapabilityPtr < EXT_CAPABILITY_START_BASE) {
> + CapabilityId = GET_LOW_8_BITS (Val);
> + } else {
> + CapabilityId = GET_LOW_16_BITS (Val);
> + }
> +
> + if (CapabilityId == ExtCapabilityId) {
> + return (CfgBase + NextCapabilityPtr);
> + }
> +
> + if (NextCapabilityPtr < EXT_CAPABILITY_START_BASE) {
> + NextCapabilityPtr = GET_CAPABILITY_PTR (Val);
> + } else {
> + NextCapabilityPtr = GET_EXT_CAPABILITY_PTR (Val);
> + }
> +
> + if ((NextCapabilityPtr == 0) && !IsExtCapability) {
> + IsExtCapability = TRUE;
> + NextCapabilityPtr = EXT_CAPABILITY_START_BASE;
> + }
> +
> + if ((NextCapabilityPtr == 0) && IsExtCapability) {
> + return 0;
> + }
> + }
> +}
> +
> +/**
> + Configure equalization settings for Gen3 and Gen4
> +
> + @param RootComplex Pointer to AC01_ROOT_COMPLEX structure
> + @param PcieIndex PCIe controller index
> +**/
> +STATIC
> +VOID
> +ConfigureEqualization (
> + IN AC01_ROOT_COMPLEX *RootComplex,
> + IN UINT8 PcieIndex
> + )
> +{
> + PHYSICAL_ADDRESS CfgBase;
> + PHYSICAL_ADDRESS Gen3RelatedAddr;
> + PHYSICAL_ADDRESS Gen3EqControlAddr;
> + UINT32 Val;
> +
> + CfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << DEV_SHIFT);
> +
> + //
> + // Gen3 and Gen4 EQ process use the same setting registers which are
> + // GEN3_RELATED_OFF and GEN3_EQ_CONTROL_OFF. Both are shadow registers
> + // and controlled by GEN3_RELATED_OFF[25:24].
> + //
> + Gen3RelatedAddr = CfgBase + GEN3_RELATED_OFF;
> + Gen3EqControlAddr = CfgBase + GEN3_EQ_CONTROL_OFF;
> +
> + //
> + // Equalization setting for Gen3
> + //
> + Val = MmioRead32 (Gen3RelatedAddr);
> + Val = RATE_SHADOW_SEL_SET (Val, GEN3_DATA_RATE);
> + MmioWrite32 (Gen3RelatedAddr, Val);
> +
> + Val = EQ_PHASE_2_3_SET (Val, ENABLE_EQ_PHASE_2_3);
> + Val = RXEQ_REGRDLESS_SET (Val, ASSERT_RXEQ);
> + MmioWrite32 (Gen3RelatedAddr, Val);
> +
> + Val = MmioRead32 (Gen3EqControlAddr);
> + Val = GEN3_EQ_FB_MODE (Val, FOM_METHOD);
> + Val = GEN3_EQ_PRESET_VEC (Val, EQ_DEFAULT_PRESET_VECTOR);
> + Val = GEN3_EQ_INIT_EVAL (Val, INCLUDE_INIT_FOM);
> + MmioWrite32 (Gen3EqControlAddr, Val);
> +
> + //
> + // Equalization setting for Gen4
> + //
> + Val = MmioRead32 (Gen3RelatedAddr);
> + Val = RATE_SHADOW_SEL_SET (Val, GEN4_DATA_RATE);
> + MmioWrite32 (Gen3RelatedAddr, Val);
> +
> + Val = EQ_PHASE_2_3_SET (Val, ENABLE_EQ_PHASE_2_3);
> + Val = RXEQ_REGRDLESS_SET (Val, ASSERT_RXEQ);
> + MmioWrite32 (Gen3RelatedAddr, Val);
> +
> + Val = MmioRead32 (Gen3EqControlAddr);
> + Val = GEN3_EQ_FB_MODE (Val, FOM_METHOD);
> + Val = GEN3_EQ_PRESET_VEC (Val, EQ_DEFAULT_PRESET_VECTOR);
> + Val = GEN3_EQ_INIT_EVAL (Val, INCLUDE_INIT_FOM);
> + MmioWrite32 (Gen3EqControlAddr, Val);
> +}
> +
> +/**
> + Configure presets for Gen3 equalization
> +
> + @param RootComplex Pointer to AC01_ROOT_COMPLEX structure
> + @param PcieIndex PCIe controller index
> +**/
> +STATIC
> +VOID
> +ConfigurePresetGen3 (
> + IN AC01_ROOT_COMPLEX *RootComplex,
> + IN UINT8 PcieIndex
> + )
> +{
> + PHYSICAL_ADDRESS LaneEqControlAddr;
> + PHYSICAL_ADDRESS SpcieCapabilityBase;
> + UINT32 Idx;
> + UINT32 LinkWidth;
> + UINT32 Val;
> +
> + // Get the Secondary PCI Express Extended capability base address
> + SpcieCapabilityBase = GetCapabilityBase (RootComplex, PcieIndex, TRUE, SPCIE_CAPABILITY_ID);
> + if (SpcieCapabilityBase == 0) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "PCIE%d.%d: Cannot get SPCIE capability address\n",
> + RootComplex->ID,
> + PcieIndex
> + ));
> + return;
> + }
> +
> + LinkWidth = RootComplex->Pcie[PcieIndex].MaxWidth;
> +
> + // Each register holds the Preset for 2 lanes
> + for (Idx = 0; Idx < (LinkWidth / 2); Idx++) {
> + LaneEqControlAddr = SpcieCapabilityBase + SPCIE_CAP_OFF_0C_REG + Idx * sizeof (UINT32);
> + Val = MmioRead32 (LaneEqControlAddr);
> + Val = DSP_TX_PRESET0_SET (Val, DEFAULT_GEN3_PRESET);
> + Val = DSP_TX_PRESET1_SET (Val, DEFAULT_GEN3_PRESET);
> + MmioWrite32 (LaneEqControlAddr, Val);
> + }
> +}
> +
> +/**
> + Configure presets for Gen4 equalization
> +
> + @param RootComplex Pointer to AC01_ROOT_COMPLEX structure
> + @param PcieIndex PCIe controller index
> +**/
> +STATIC
> +VOID
> +ConfigurePresetGen4 (
> + IN AC01_ROOT_COMPLEX *RootComplex,
> + IN UINT8 PcieIndex
> + )
> +{
> + PHYSICAL_ADDRESS LaneEqControlAddr;
> + PHYSICAL_ADDRESS Pl16gCapabilityBase;
> + UINT32 Idx;
> + UINT32 LinkWidth;
> + UINT32 Val;
> + UINT8 Preset;
> +
> + // Get the Physical Layer 16.0 GT/s Extended capability base address
> + Pl16gCapabilityBase = GetCapabilityBase (RootComplex, PcieIndex, TRUE, PL16G_CAPABILITY_ID);
> + if (Pl16gCapabilityBase == 0) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "PCIE%d.%d: Cannot get PL16G capability address\n",
> + RootComplex->ID,
> + PcieIndex
> + ));
> + return;
> + }
> +
> + if (RootComplex->PresetGen4[PcieIndex] == PRESET_INVALID) {
> + Preset = DEFAULT_GEN4_PRESET;
> + } else {
> + Preset = RootComplex->PresetGen4[PcieIndex];
> + }
> +
> + LinkWidth = RootComplex->Pcie[PcieIndex].MaxWidth;
> +
> + if (LinkWidth == CAP_MAX_LINK_WIDTH_X2) {
> + LaneEqControlAddr = Pl16gCapabilityBase + PL16G_CAP_OFF_20H_REG;
> + Val = MmioRead32 (LaneEqControlAddr);
> + Val = DSP_16G_RXTX_PRESET0_SET (Val, Preset);
> + Val = DSP_16G_RXTX_PRESET1_SET (Val, Preset);
> + MmioWrite32 (LaneEqControlAddr, Val);
> + } else {
> + // Each register holds the Preset for 4 lanes
> + for (Idx = 0; Idx < (LinkWidth / 4); Idx++) {
> + LaneEqControlAddr = Pl16gCapabilityBase + PL16G_CAP_OFF_20H_REG + Idx * sizeof (UINT32);
> + Val = MmioRead32 (LaneEqControlAddr);
> + Val = DSP_16G_RXTX_PRESET0_SET (Val, Preset);
> + Val = DSP_16G_RXTX_PRESET1_SET (Val, Preset);
> + Val = DSP_16G_RXTX_PRESET2_SET (Val, Preset);
> + Val = DSP_16G_RXTX_PRESET3_SET (Val, Preset);
> + MmioWrite32 (LaneEqControlAddr, Val);
> + }
> + }
> +}
> +
> +VOID
> +ProgramHostBridgeInfo (
> + AC01_ROOT_COMPLEX *RootComplex
> + )
> +{
> + EFI_STATUS Status;
> + PHYSICAL_ADDRESS TargetAddress;
> + UINT32 Val;
> +
> + // Program Root Complex Bifurcation
> + if (RootComplex->Active) {
> + if (RootComplex->Type == RootComplexTypeA) {
> + TargetAddress = RootComplex->HostBridgeBase + AC01_HOST_BRIDGE_RCA_DEV_MAP_REG;
> + Status = MailboxMsgRegisterRead (RootComplex->Socket, TargetAddress, &Val);
> + if (!RETURN_ERROR (Status)) {
> + Val = RCA_DEV_MAP_SET (Val, RootComplex->DevMapLow);
> + MailboxMsgRegisterWrite (RootComplex->Socket, TargetAddress, Val);
> + }
> + } else {
> + TargetAddress = RootComplex->HostBridgeBase + AC01_HOST_BRIDGE_RCB_DEV_MAP_REG;
> + Status = MailboxMsgRegisterRead (RootComplex->Socket, TargetAddress, &Val);
> + if (!RETURN_ERROR (Status)) {
> + Val = RCB_DEV_MAP_LOW_SET (Val, RootComplex->DevMapLow);
> + Val = RCB_DEV_MAP_HIGH_SET (Val, RootComplex->DevMapHigh);
> + MailboxMsgRegisterWrite (RootComplex->Socket, TargetAddress, Val);
> + }
> + }
> + }
> +
> + // Program Vendor ID and Device ID
> + TargetAddress = RootComplex->HostBridgeBase + AC01_HOST_BRIDGE_VENDOR_DEVICE_ID_REG;
> + Status = MailboxMsgRegisterRead (RootComplex->Socket, TargetAddress, &Val);
> + if (!RETURN_ERROR (Status)) {
> + Val = VENDOR_ID_SET (Val, AMPERE_PCIE_VENDOR_ID);
> + if (RootComplexTypeA == RootComplex->Type) {
> + Val = DEVICE_ID_SET (Val, AC01_HOST_BRIDGE_DEVICE_ID_RCA);
> + } else {
> + Val = DEVICE_ID_SET (Val, AC01_HOST_BRIDGE_DEVICE_ID_RCB);
> + }
> + MailboxMsgRegisterWrite (RootComplex->Socket, TargetAddress, Val);
> + }
> +}
> +
> +VOID
> +ProgramRootPortInfo (
> + AC01_ROOT_COMPLEX *RootComplex,
> + UINT32 PcieIndex
> + )
> +{
> + PHYSICAL_ADDRESS CfgBase;
> + PHYSICAL_ADDRESS TargetAddress;
> + UINT32 Val;
> +
> + CfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << DEV_SHIFT);
> +
> + // Program Class Code
> + TargetAddress = CfgBase + TYPE1_CLASS_CODE_REV_ID_REG;
> + Val = MmioRead32 (TargetAddress);
> + Val = REVISION_ID_SET (Val, DEFAULT_REVISION_ID);
> + Val = SUB_CLASS_CODE_SET (Val, DEFAULT_SUB_CLASS_CODE);
> + Val = BASE_CLASS_CODE_SET (Val, DEFAULT_BASE_CLASS_CODE);
> + MmioWrite32 (TargetAddress, Val);
> +
> + // Program Vendor ID and Device ID
> + TargetAddress = CfgBase + TYPE1_DEV_ID_VEND_ID_REG;
> + Val = MmioRead32 (TargetAddress);
> + Val = VENDOR_ID_SET (Val, AMPERE_PCIE_VENDOR_ID);
> + if (RootComplexTypeA == RootComplex->Type) {
> + Val = DEVICE_ID_SET (Val, AC01_PCIE_BRIDGE_DEVICE_ID_RCA + PcieIndex);
> + } else {
> + Val = DEVICE_ID_SET (Val, AC01_PCIE_BRIDGE_DEVICE_ID_RCB + PcieIndex);
> + }
> + MmioWrite32 (TargetAddress, Val);
> +}
> +
> +VOID
> +ProgramLinkCapabilities (
> + IN AC01_ROOT_COMPLEX *RootComplex,
> + IN UINT8 PcieIndex
> + )
> +{
> + PHYSICAL_ADDRESS CfgBase;
> + PHYSICAL_ADDRESS TargetAddress;
> + UINT32 Val;
> + UINT8 MaxWidth;
> + UINT8 MaxGen;
> +
> + CfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << DEV_SHIFT);
> +
> + MaxWidth = RootComplex->Pcie[PcieIndex].MaxWidth;
> + MaxGen = RootComplex->Pcie[PcieIndex].MaxGen;
> +
> + TargetAddress = CfgBase + PORT_LINK_CTRL_OFF;
> + Val = MmioRead32 (TargetAddress);
> + switch (MaxWidth) {
> + case LINK_WIDTH_X2:
> + Val = LINK_CAPABLE_SET (Val, LINK_CAPABLE_X2);
> + break;
> +
> + case LINK_WIDTH_X4:
> + Val = LINK_CAPABLE_SET (Val, LINK_CAPABLE_X4);
> + break;
> +
> + case LINK_WIDTH_X8:
> + Val = LINK_CAPABLE_SET (Val, LINK_CAPABLE_X8);
> + break;
> +
> + case LINK_WIDTH_X16:
> + default:
> + Val = LINK_CAPABLE_SET (Val, LINK_CAPABLE_X16);
> + break;
> + }
> + MmioWrite32 (TargetAddress, Val);
> +
> + TargetAddress = CfgBase + GEN2_CTRL_OFF;
> + Val = MmioRead32 (TargetAddress);
> + switch (MaxWidth) {
> + case LINK_WIDTH_X2:
> + Val = NUM_OF_LANES_SET (Val, NUM_OF_LANES_X2);
> + break;
> +
> + case LINK_WIDTH_X4:
> + Val = NUM_OF_LANES_SET (Val, NUM_OF_LANES_X4);
> + break;
> +
> + case LINK_WIDTH_X8:
> + Val = NUM_OF_LANES_SET (Val, NUM_OF_LANES_X8);
> + break;
> +
> + case LINK_WIDTH_X16:
> + default:
> + Val = NUM_OF_LANES_SET (Val, NUM_OF_LANES_X16);
> + break;
> + }
> + MmioWrite32 (TargetAddress, Val);
> +
> + TargetAddress = CfgBase + PCIE_CAPABILITY_BASE + LINK_CAPABILITIES_REG;
> + Val = MmioRead32 (TargetAddress);
> + switch (MaxWidth) {
> + case LINK_WIDTH_X2:
> + Val = CAP_MAX_LINK_WIDTH_SET (Val, CAP_MAX_LINK_WIDTH_X2);
> + break;
> +
> + case LINK_WIDTH_X4:
> + Val = CAP_MAX_LINK_WIDTH_SET (Val, CAP_MAX_LINK_WIDTH_X4);
> + break;
> +
> + case LINK_WIDTH_X8:
> + Val = CAP_MAX_LINK_WIDTH_SET (Val, CAP_MAX_LINK_WIDTH_X8);
> + break;
> +
> + case LINK_WIDTH_X16:
> + default:
> + Val = CAP_MAX_LINK_WIDTH_SET (Val, CAP_MAX_LINK_WIDTH_X16);
> + break;
> + }
> +
> + switch (MaxGen) {
> + case LINK_SPEED_GEN1:
> + Val = CAP_MAX_LINK_SPEED_SET (Val, MAX_LINK_SPEED_25);
> + break;
> +
> + case LINK_SPEED_GEN2:
> + Val = CAP_MAX_LINK_SPEED_SET (Val, MAX_LINK_SPEED_50);
> + break;
> +
> + case LINK_SPEED_GEN3:
> + Val = CAP_MAX_LINK_SPEED_SET (Val, MAX_LINK_SPEED_80);
> + break;
> +
> + default:
> + Val = CAP_MAX_LINK_SPEED_SET (Val, MAX_LINK_SPEED_160);
> + break;
> + }
> + // Enable ASPM Capability
> + Val = CAP_ACTIVE_STATE_LINK_PM_SUPPORT_SET (Val, L0S_L1_SUPPORTED);
> + MmioWrite32 (TargetAddress, Val);
> +
> + TargetAddress = CfgBase + PCIE_CAPABILITY_BASE + LINK_CONTROL2_LINK_STATUS2_REG;
> + Val = MmioRead32 (TargetAddress);
> + switch (MaxGen) {
> + case LINK_SPEED_GEN1:
> + Val = CAP_TARGET_LINK_SPEED_SET (Val, MAX_LINK_SPEED_25);
> + break;
> +
> + case LINK_SPEED_GEN2:
> + Val = CAP_TARGET_LINK_SPEED_SET (Val, MAX_LINK_SPEED_50);
> + break;
> +
> + case LINK_SPEED_GEN3:
> + Val = CAP_TARGET_LINK_SPEED_SET (Val, MAX_LINK_SPEED_80);
> + break;
> +
> + default:
> + Val = CAP_TARGET_LINK_SPEED_SET (Val, MAX_LINK_SPEED_160);
> + break;
> + }
> + MmioWrite32 (TargetAddress, Val);
> +}
> +
> +VOID
> +DisableCompletionTimeOut (
> + IN AC01_ROOT_COMPLEX *RootComplex,
> + IN UINT8 PcieIndex,
> + IN BOOLEAN IsMask
> + )
> +{
> + PHYSICAL_ADDRESS CfgBase;
> + PHYSICAL_ADDRESS TargetAddress;
> + UINT32 Val;
> +
> + CfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << DEV_SHIFT);
> +
> + TargetAddress = CfgBase + AER_CAPABILITY_BASE + UNCORR_ERR_MASK_OFF;
> + Val = MmioRead32 (TargetAddress);
> + Val = CMPLT_TIMEOUT_ERR_MASK_SET (Val, IsMask ? 1 : 0);
> + MmioWrite32 (TargetAddress, Val);
> +}
> +
> +BOOLEAN
> +EnableItsMemory (
> + AC01_ROOT_COMPLEX *RootComplex,
> + UINT32 PcieIndex
> + )
> +{
> + PHYSICAL_ADDRESS CsrBase;
> + PHYSICAL_ADDRESS TargetAddress;
> + UINT32 TimeOut;
> + UINT32 Val;
> +
> + CsrBase = RootComplex->Pcie[PcieIndex].CsrBase;
> +
> + // Clear memory shutdown
> + TargetAddress = CsrBase + AC01_PCIE_CORE_RAM_SHUTDOWN_REG;
> + Val = MmioRead32 (TargetAddress);
> + Val = SD_SET (Val, 0);
> + MmioWrite32 (TargetAddress, Val);
> +
> + // Poll till ITS Memory is ready
> + TimeOut = MEMRDY_TIMEOUT;
> + do {
> + Val = MmioRead32 (CsrBase + AC01_PCIE_CORE_MEM_READY_REG);
> + if (Val & MEMORY_READY) {
> + return TRUE;
> + }
> +
> + TimeOut--;
> + MicroSecondDelay (1);
> + } while (TimeOut > 0);
> +
> + return FALSE;
> +}
> +
> +BOOLEAN
> +EnableAxiPipeClock (
> + AC01_ROOT_COMPLEX *RootComplex,
> + UINT32 PcieIndex
> + )
> +{
> + PHYSICAL_ADDRESS CsrBase;
> + PHYSICAL_ADDRESS TargetAddress;
> + UINT32 TimeOut;
> + UINT32 Val;
> +
> + CsrBase = RootComplex->Pcie[PcieIndex].CsrBase;
> +
> + // Enable subsystem clock and release reset
> + TargetAddress = CsrBase + AC01_PCIE_CORE_CLOCK_REG;
> + Val = MmioRead32 (TargetAddress);
> + Val = AXIPIPE_SET (Val, 1);
> + MmioWrite32 (TargetAddress, Val);
> +
> + TargetAddress = CsrBase + AC01_PCIE_CORE_RESET_REG;
> + Val = MmioRead32 (TargetAddress);
> + Val = DWC_PCIE_SET (Val, 0);
> + MmioWrite32 (TargetAddress, 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 = PIPE_CLOCK_TIMEOUT;
> + do {
> + Val = MmioRead32 (CsrBase + AC01_PCIE_CORE_LINK_STAT_REG);
> + if (!(Val & PHY_STATUS_MASK)) {
> + return TRUE;
> + }
> +
> + TimeOut--;
> + MicroSecondDelay (1);
> + } while (TimeOut > 0);
> +
> + return FALSE;
> +}
> +
> +VOID
> +SetLinkTimeout (
> + AC01_ROOT_COMPLEX *RootComplex,
> + UINT32 PcieIndex,
> + UINTN Timeout
> + )
> +{
> + PHYSICAL_ADDRESS TargetAddress;
> + UINT32 Val;
> +
> + TargetAddress = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << DEV_SHIFT)
> + + AMBA_LINK_TIMEOUT_OFF;
> +
> + Val = MmioRead32 (TargetAddress);
> + Val = LINK_TIMEOUT_PERIOD_DEFAULT_SET (Val, Timeout);
> + MmioWrite32 (TargetAddress, Val);
> +}
> +
> +VOID
> +StartLinkTraining (
> + AC01_ROOT_COMPLEX *RootComplex,
> + UINT32 PcieIndex,
> + BOOLEAN StartLink
> + )
> +{
> + PHYSICAL_ADDRESS TargetAddress;
> + UINT32 Val;
> +
> + TargetAddress = RootComplex->Pcie[PcieIndex].CsrBase + AC01_PCIE_CORE_LINK_CTRL_REG;
> +
> + Val = MmioRead32 (TargetAddress);
> + Val = LTSSMENB_SET (Val, StartLink ? START_LINK_TRAINING : HOLD_LINK_TRAINING);
> + MmioWrite32 (TargetAddress, Val);
> +}
> +
> +VOID
> +EnableDbiAccess (
> + AC01_ROOT_COMPLEX *RootComplex,
> + UINT32 PcieIndex,
> + BOOLEAN EnableDbi
> + )
> +{
> + PHYSICAL_ADDRESS TargetAddress;
> + UINT32 Val;
> +
> + TargetAddress = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << DEV_SHIFT)
> + + MISC_CONTROL_1_OFF;
> +
> + Val = MmioRead32 (TargetAddress);
> + Val = DBI_RO_WR_EN_SET (Val, EnableDbi ? ENABLE_WR : DISABLE_WR);
> + MmioWrite32 (TargetAddress, Val);
> +}
> +
> +/**
> + Setup and initialize the AC01 PCIe Root Complex and underneath PCIe controllers
> +
> + @param RootComplex Pointer to Root Complex structure
> + @param ReInit Re-init status
> + @param ReInitPcieIndex PCIe controller index
> +
> + @retval RETURN_SUCCESS The Root Complex has been initialized successfully.
> + @retval RETURN_DEVICE_ERROR PHY, Memory or PIPE is not ready.
> +**/
> +RETURN_STATUS
> +Ac01PcieCoreSetupRC (
> + IN AC01_ROOT_COMPLEX *RootComplex,
> + IN BOOLEAN ReInit,
> + IN UINT8 ReInitPcieIndex
> + )
> +{
> + PHYSICAL_ADDRESS CfgBase;
> + PHYSICAL_ADDRESS CsrBase;
> + PHYSICAL_ADDRESS TargetAddress;
> + RETURN_STATUS Status;
> + UINT32 Val;
> + UINT8 PcieIndex;
> +
> + DEBUG ((DEBUG_INFO, "Initializing Socket%d RootComplex%d\n", RootComplex->Socket, RootComplex->ID));
> +
> + ProgramHostBridgeInfo (RootComplex);
> +
> + if (!ReInit) {
> + Status = PciePhyInit (RootComplex->SerdesBase);
> + if (RETURN_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a: Failed to initialize the PCIe PHY\n", __FUNCTION__));
> + return RETURN_DEVICE_ERROR;
> + }
> + }
> +
> + // Setup each controller
> + for (PcieIndex = 0; PcieIndex < RootComplex->MaxPcieController; PcieIndex++) {
> +
> + if (ReInit) {
> + PcieIndex = ReInitPcieIndex;
> + }
> +
> + if (!RootComplex->Pcie[PcieIndex].Active) {
> + continue;
> + }
> +
> + DEBUG ((DEBUG_INFO, "Initializing Controller %d\n", PcieIndex));
> +
> + CsrBase = RootComplex->Pcie[PcieIndex].CsrBase;
> + CfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << DEV_SHIFT);
> +
> + // Put Controller into reset if not in reset already
> + TargetAddress = CsrBase + AC01_PCIE_CORE_RESET_REG;
> + Val = MmioRead32 (TargetAddress);
> + if (!(Val & RESET_MASK)) {
> + Val = DWC_PCIE_SET (Val, ASSERT_RESET);
> + MmioWrite32 (TargetAddress, Val);
> +
> + // Delay 50ms to ensure controller finish its reset
> + MicroSecondDelay (50000);
> + }
> +
> + if (!EnableItsMemory (RootComplex, PcieIndex)) {
> + DEBUG ((DEBUG_ERROR, "- Pcie[%d] - ITS Memory is not ready\n", PcieIndex));
> + return RETURN_DEVICE_ERROR;
> + }
> +
> + // Hold link training
> + StartLinkTraining (RootComplex, PcieIndex, FALSE);
> +
> + if (!EnableAxiPipeClock (RootComplex, PcieIndex)) {
> + DEBUG ((DEBUG_ERROR, "- Pcie[%d] - PIPE clock is not stable\n", PcieIndex));
> + return RETURN_DEVICE_ERROR;
> + }
> +
> + // Start PERST pulse
> + BoardPcieAssertPerst (RootComplex, PcieIndex, TRUE);
> +
> + // Allow programming to config space
> + EnableDbiAccess (RootComplex, PcieIndex, TRUE);
> +
> + // Program the power limit
> + TargetAddress = CfgBase + PCIE_CAPABILITY_BASE + SLOT_CAPABILITIES_REG;
> + Val = MmioRead32 (TargetAddress);
> + Val = SLOT_CAP_SLOT_POWER_LIMIT_VALUE_SET (Val, SLOT_POWER_LIMIT_75W);
> + MmioWrite32 (TargetAddress, Val);
> +
> + // Program DTI for ATS support
> + TargetAddress = CfgBase + DTIM_CTRL0_OFF;
> + Val = MmioRead32 (TargetAddress);
> + Val = DTIM_CTRL0_ROOT_PORT_ID_SET (Val, 0);
> + MmioWrite32 (TargetAddress, Val);
> +
> + //
> + // Program number of lanes used
> + // - Reprogram LINK_CAPABLE of PORT_LINK_CTRL_OFF
> + // - Reprogram NUM_OF_LANES of GEN2_CTRL_OFF
> + // - Reprogram CAP_MAX_LINK_WIDTH of LINK_CAPABILITIES_REG
> + //
> + ProgramLinkCapabilities (RootComplex, PcieIndex);
> +
> + // Set Zero byte request handling
> + TargetAddress = CfgBase + FILTER_MASK_2_OFF;
> + Val = MmioRead32 (TargetAddress);
> + Val = CX_FLT_MASK_VENMSG0_DROP_SET (Val, 0);
> + Val = CX_FLT_MASK_VENMSG1_DROP_SET (Val, 0);
> + Val = CX_FLT_MASK_DABORT_4UCPL_SET (Val, 0);
> + MmioWrite32 (TargetAddress, Val);
> +
> + TargetAddress = CfgBase + AMBA_ORDERING_CTRL_OFF;
> + Val = MmioRead32 (TargetAddress);
> + Val = AX_MSTR_ZEROLREAD_FW_SET (Val, 0);
> + MmioWrite32 (TargetAddress, Val);
> +
> + //
> + // Set Completion with CRS handling for CFG Request
> + // Set Completion with CA/UR handling non-CFG Request
> + //
> + TargetAddress = CfgBase + AMBA_ERROR_RESPONSE_DEFAULT_OFF;
> + Val = MmioRead32 (TargetAddress);
> + // 0x2: OKAY with FFFF_0001 and FFFF_FFFF
> + Val = AMBA_ERROR_RESPONSE_CRS_SET (Val, 0x2);
> + MmioWrite32 (TargetAddress, Val);
> +
> + // Set Legacy PCIE interrupt map to INTA
> + TargetAddress = CfgBase + BRIDGE_CTRL_INT_PIN_INT_LINE_REG;
> + Val = MmioRead32 (TargetAddress);
> + Val = INT_PIN_SET (Val, IRQ_INT_A);
> + MmioWrite32 (TargetAddress, Val);
> +
> + TargetAddress = CsrBase + AC01_PCIE_CORE_IRQ_SEL_REG;
> + Val = MmioRead32 (TargetAddress);
> + Val = INTPIN_SET (Val, IRQ_INT_A);
> + MmioWrite32 (TargetAddress, Val);
> +
> + if (RootComplex->Pcie[PcieIndex].MaxGen >= LINK_SPEED_GEN2) {
> + ConfigureEqualization (RootComplex, PcieIndex);
> + if (RootComplex->Pcie[PcieIndex].MaxGen >= LINK_SPEED_GEN3) {
> + ConfigurePresetGen3 (RootComplex, PcieIndex);
> + if (RootComplex->Pcie[PcieIndex].MaxGen >= LINK_SPEED_GEN4) {
> + ConfigurePresetGen4 (RootComplex, PcieIndex);
> + }
> + }
> + }
> +
> + // Link timeout after 1ms
> + SetLinkTimeout (RootComplex, PcieIndex, 1);
> +
> + DisableCompletionTimeOut (RootComplex, PcieIndex, TRUE);
> +
> + ProgramRootPortInfo (RootComplex, PcieIndex);
> +
> + // Enable common clock for downstream
> + TargetAddress = CfgBase + PCIE_CAPABILITY_BASE + LINK_CONTROL_LINK_STATUS_REG;
> + Val = MmioRead32 (TargetAddress);
> + Val = CAP_SLOT_CLK_CONFIG_SET (Val, 1);
> + Val = CAP_COMMON_CLK_SET (Val, 1);
> + MmioWrite32 (TargetAddress, Val);
> +
> + // Match aux_clk to system
> + TargetAddress = CfgBase + AUX_CLK_FREQ_OFF;
> + Val = MmioRead32 (TargetAddress);
> + Val = AUX_CLK_FREQ_SET (Val, AUX_CLK_500MHZ);
> + MmioWrite32 (TargetAddress, Val);
> +
> + // Assert PERST low to reset endpoint
> + BoardPcieAssertPerst (RootComplex, PcieIndex, FALSE);
> +
> + // Start link training
> + StartLinkTraining (RootComplex, PcieIndex, TRUE);
> +
> + // Complete the PERST pulse
> + BoardPcieAssertPerst (RootComplex, PcieIndex, TRUE);
> +
> + // Lock programming of config space
> + EnableDbiAccess (RootComplex, PcieIndex, FALSE);
> +
> + if (ReInit) {
> + return RETURN_SUCCESS;
> + }
> + }
> +
> + return RETURN_SUCCESS;
> +}
> +
> +BOOLEAN
> +PcieLinkUpCheck (
> + IN AC01_PCIE_CONTROLLER *Pcie
> + )
> +{
> + PHYSICAL_ADDRESS CsrBase;
> + UINT32 BlockEvent;
> + UINT32 LinkStat;
> +
> + CsrBase = Pcie->CsrBase;
> +
> + // Check if card present
> + // smlh_ltssm_state[13:8] = 0
> + // phy_status[2] = 0
> + // smlh_link_up[1] = 0
> + // rdlh_link_up[0] = 0
> + LinkStat = MmioRead32 (CsrBase + AC01_PCIE_CORE_LINK_STAT_REG);
> + LinkStat = LinkStat & (SMLH_LTSSM_STATE_MASK | PHY_STATUS_MASK_BIT |
> + SMLH_LINK_UP_MASK_BIT | RDLH_LINK_UP_MASK_BIT);
> + if (LinkStat == 0) {
> + return FALSE;
> + }
> +
> + BlockEvent = MmioRead32 (CsrBase + AC01_PCIE_CORE_BLOCK_EVENT_STAT_REG);
> + LinkStat = MmioRead32 (CsrBase + AC01_PCIE_CORE_LINK_STAT_REG);
> +
> + if (((BlockEvent & LINKUP_MASK) != 0)
> + && (SMLH_LTSSM_STATE_GET(LinkStat) == LTSSM_STATE_L0)) {
> + return TRUE;
> + }
> +
> + return FALSE;
> +}
> +
> +/**
> + Callback function when the Host Bridge enumeration end.
> +
> + @param RootComplex Pointer to the Root Complex structure
> +**/
> +VOID
> +Ac01PcieCoreEndEnumeration (
> + IN AC01_ROOT_COMPLEX *RootComplex
> + )
> +{
> +
> + PHYSICAL_ADDRESS TargetAddress;
> + UINT32 PcieIndex;
> + UINT32 Val;
> +
> + if (RootComplex == NULL || !RootComplex->Active) {
> + return;
> + }
> +
> + // Clear uncorrectable error during enumuration phase. Mainly completion timeout.
> + for (PcieIndex = 0; PcieIndex < RootComplex->MaxPcieController; PcieIndex++) {
> + if (!RootComplex->Pcie[PcieIndex].Active) {
> + continue;
> + }
> +
> + if (!PcieLinkUpCheck(&RootComplex->Pcie[PcieIndex])) {
> + // If link down/disabled after enumeration, disable completed time out
> + DisableCompletionTimeOut (RootComplex, PcieIndex, TRUE);
> + }
> +
> + // Clear all errors
> + TargetAddress = RootComplex->MmcfgBase + ((PcieIndex + 1) << DEV_SHIFT) \
> + + AER_CAPABILITY_BASE + UNCORR_ERR_STATUS_OFF;
> + Val = MmioRead32 (TargetAddress);
> + if (Val != 0) {
> + // Clear error by writting
> + MmioWrite32 (TargetAddress, Val);
> + }
> + }
> +}
> +
> +/**
> + Comparing current link status with the max capabilities of the link
> +
> + @param RootComplex Pointer to AC01_ROOT_COMPLEX structure
> + @param PcieIndex PCIe controller index
> + @param EpMaxWidth EP max link width
> + @param EpMaxGen EP max link speed
> +
> + @retval -1: Link status do not match with link max capabilities
> + 1: Link capabilites are invalid
> + 0: Link status are correct
> +**/
> +INT32
> +Ac01PcieCoreLinkCheck (
> + IN AC01_ROOT_COMPLEX *RootComplex,
> + IN UINT8 PcieIndex,
> + IN UINT8 EpMaxWidth,
> + IN UINT8 EpMaxGen
> + )
> +{
> + PHYSICAL_ADDRESS CsrBase, CfgBase;
> + UINT32 Val, LinkStat;
> + UINT32 MaxWidth, MaxGen;
> +
> + CsrBase = RootComplex->Pcie[PcieIndex].CsrBase;
> + CfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << DEV_SHIFT);
> +
> + Val = MmioRead32 (CfgBase + PCIE_CAPABILITY_BASE + LINK_CAPABILITIES_REG);
> + if ((CAP_MAX_LINK_WIDTH_GET (Val) == 0) ||
> + (CAP_MAX_LINK_SPEED_GET (Val) == 0)) {
> + DEBUG ((DEBUG_INFO, "\tPCIE%d.%d: Wrong RootComplex capabilities\n", RootComplex->ID, PcieIndex));
> + return LINK_CHECK_WRONG_PARAMETER;
> + }
> +
> + if ((EpMaxWidth == 0) || (EpMaxGen == 0)) {
> + DEBUG ((DEBUG_INFO, "\tPCIE%d.%d: Wrong EP capabilities\n", RootComplex->ID, PcieIndex));
> + return LINK_CHECK_FAILED;
> + }
> +
> + // Compare RootComplex and EP capabilities
> + if (CAP_MAX_LINK_WIDTH_GET (Val) > EpMaxWidth) {
> + MaxWidth = EpMaxWidth;
> + } else {
> + MaxWidth = CAP_MAX_LINK_WIDTH_GET (Val);
> + }
> +
> + // Compare RootComplex and EP capabilities
> + if (CAP_MAX_LINK_SPEED_GET (Val) > EpMaxGen) {
> + MaxGen = EpMaxGen;
> + } else {
> + MaxGen = CAP_MAX_LINK_SPEED_GET (Val);
> + }
> +
> + LinkStat = MmioRead32 (CsrBase + AC01_PCIE_CORE_LINK_STAT_REG);
> + Val = MmioRead32 (CfgBase + PCIE_CAPABILITY_BASE + LINK_CONTROL_LINK_STATUS_REG);
> + DEBUG ((
> + DEBUG_INFO,
> + "PCIE%d.%d: Link MaxWidth %d MaxGen %d, AC01_PCIE_CORE_LINK_STAT_REG 0x%x",
> + RootComplex->ID,
> + PcieIndex,
> + MaxWidth,
> + MaxGen,
> + LinkStat
> + ));
> +
> + // Checking all conditions of the link
> + // If one of them is not sastified, return link up fail
> + if ((CAP_NEGO_LINK_WIDTH_GET (Val) != MaxWidth) ||
> + (CAP_LINK_SPEED_GET (Val) != MaxGen) ||
> + (RDLH_SMLH_LINKUP_STATUS_GET (LinkStat) != (SMLH_LINK_UP_MASK_BIT | RDLH_LINK_UP_MASK_BIT)))
> + {
> + DEBUG ((DEBUG_INFO, "\tLinkCheck FAILED\n"));
> + return LINK_CHECK_FAILED;
> + }
> +
> + DEBUG ((DEBUG_INFO, "\tLinkCheck SUCCESS\n"));
> + return LINK_CHECK_SUCCESS;
> +}
> +
> +INT32
> +PFACounterRead (
> + IN AC01_ROOT_COMPLEX *RootComplex,
> + IN UINT8 PcieIndex,
> + IN UINT64 RasDesCapabilityBase
> + )
> +{
> + INT32 Ret = LINK_CHECK_SUCCESS;
> + UINT32 Val;
> + UINT8 ErrCode, ErrGrpNum;
> +
> + UINT32 ErrCtrlCfg[] = {
> + 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, 0x008, 0x009, 0x00A, // Per Lane
> + 0x105, 0x106, 0x107, 0x108, 0x109, 0x10A,
> + 0x200, 0x201, 0x202, 0x203, 0x204, 0x205, 0x206, 0x207,
> + 0x300, 0x301, 0x302, 0x303, 0x304, 0x305,
> + 0x400, 0x401, // Per Lane
> + 0x500, 0x501, 0x502, 0x503, 0x504, 0x505, 0x506, 0x507, 0x508, 0x509, 0x50A, 0x50B, 0x50C, 0x50D
> + };
> +
> + for (ErrCode = 0; ErrCode < ARRAY_SIZE (ErrCtrlCfg); ErrCode++) {
> + ErrGrpNum = GET_HIGH_8_BITS (ErrCtrlCfg[ErrCode]);
> + // Skipping per lane group
> + // Checking common lane group because AER error are included in common group only
> + if ((ErrGrpNum != 0) && (ErrGrpNum != 4)) {
> + Val = MmioRead32 (RasDesCapabilityBase + EVENT_COUNTER_CONTROL_REG);
> + if (RootComplex->Type == RootComplexTypeA) {
> + // RootComplexTypeA - 4 PCIe controller per port, 1 controller in charge of 4 lanes
> + Val = ECCR_LANE_SEL_SET (Val, PcieIndex * 4);
> + } else {
> + // RootComplexTypeB - 8 PCIe controller per port, 1 controller in charge of 2 lanes
> + Val = ECCR_LANE_SEL_SET (Val, PcieIndex * 2);
> + }
> + Val = ECCR_GROUP_EVENT_SEL_SET (Val, ErrCtrlCfg[ErrCode]);
> + MmioWrite32 (RasDesCapabilityBase + EVENT_COUNTER_CONTROL_REG, Val);
> +
> + // After setting Counter Control reg
> + // This delay just to make sure Counter Data reg is update with new value
> + MicroSecondDelay (1);
> + Val = MmioRead32 (RasDesCapabilityBase + EVENT_COUNTER_DATA_REG);
> + if (Val != 0) {
> + Ret = LINK_CHECK_FAILED;
> + DEBUG ((
> + DEBUG_ERROR,
> + "\tSocket%d RootComplex%d RP%d \t%s: %d \tGROUP:%d-EVENT:%d\n",
> + RootComplex->Socket,
> + RootComplex->ID,
> + PcieIndex,
> + Val,
> + ErrGrpNum,
> + GET_LOW_8_BITS (ErrCtrlCfg[ErrCode])
> + ));
> + }
> + }
> + }
> +
> + return Ret;
> +}
> +
> +/**
> + Handle Predictive Failure Analysis command
> +
> + @param RootComplex Pointer to Root Complex structure
> + @param PcieIndex PCIe controller index
> + @param PFAMode The PFA mode
> +
> + @retval The link status
> +**/
> +INT32
> +Ac01PFACommand (
> + IN AC01_ROOT_COMPLEX *RootComplex,
> + IN UINT8 PcieIndex,
> + IN UINT8 PFAMode
> + )
> +{
> + PHYSICAL_ADDRESS RasDesCapabilityBase;
> + PHYSICAL_ADDRESS TargetAddress;
> + INT32 Ret = LINK_CHECK_SUCCESS;
> + UINT32 Val;
> +
> + // Allow programming to config space
> + EnableDbiAccess (RootComplex, PcieIndex, TRUE);
> +
> + // Get the RAS D.E.S. capability base address
> + RasDesCapabilityBase = GetCapabilityBase (RootComplex, PcieIndex, TRUE, RAS_DES_CAPABILITY_ID);
> + if (RasDesCapabilityBase == 0) {
> + DEBUG ((DEBUG_INFO, "PCIE%d.%d: Cannot get RAS DES capability address\n", RootComplex->ID, PcieIndex));
> + return LINK_CHECK_WRONG_PARAMETER;
> + }
> +
> + TargetAddress = RasDesCapabilityBase + EVENT_COUNTER_CONTROL_REG;
> +
> + switch (PFAMode) {
> + case PFA_MODE_ENABLE:
> + Val = MmioRead32 (TargetAddress);
> + Val = ECCR_EVENT_COUNTER_ENABLE_SET (Val, EVENT_COUNTER_ENABLE_ALL_ON);
> + Val = ECCR_EVENT_COUNTER_CLEAR_SET (Val, EVENT_COUNTER_CLEAR_NO_CHANGE);
> + MmioWrite32 (TargetAddress, Val);
> + break;
> +
> + case PFA_MODE_CLEAR:
> + Val = MmioRead32 (TargetAddress);
> + Val = ECCR_EVENT_COUNTER_ENABLE_SET (Val, EVENT_COUNTER_ENABLE_NO_CHANGE);
> + Val = ECCR_EVENT_COUNTER_CLEAR_SET (Val, EVENT_COUNTER_CLEAR_ALL_CLEAR);
> + MmioWrite32 (TargetAddress, Val);
> + break;
> +
> + case PFA_MODE_READ:
> + Ret = PFACounterRead (RootComplex, PcieIndex, RasDesCapabilityBase);
> + break;
> +
> + default:
> + DEBUG ((DEBUG_ERROR, "%a: Invalid PFA mode\n"));
> + }
> +
> + // Disable programming to config space
> + EnableDbiAccess (RootComplex, PcieIndex, FALSE);
> +
> + return Ret;
> +}
> +
> +UINT32
> +EndpointCfgReady (
> + IN AC01_ROOT_COMPLEX *RootComplex,
> + IN UINT8 PcieIndex
> + )
> +{
> + PHYSICAL_ADDRESS CfgBase;
> + UINT32 TimeOut;
> + UINT32 Val;
> +
> + CfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << BUS_SHIFT);
> +
> + // Loop read CfgBase value until got valid value or
> + // reach to timeout EP_LINKUP_TIMEOUT (or more depend on card)
> + TimeOut = EP_LINKUP_TIMEOUT;
> + do {
> + Val = MmioRead32 (CfgBase);
> + if (Val != 0xFFFF0001 && Val != 0xFFFFFFFF) {
> + return TRUE;
> + }
> +
> + TimeOut -= LINK_WAIT_INTERVAL_US;
> + MicroSecondDelay (LINK_WAIT_INTERVAL_US);
> + } while (TimeOut > 0);
> +
> + return FALSE;
> +}
> +
> +/**
> + Get link capabilities link width and speed of endpoint
> +
> + @param RootComplex[in] Pointer to AC01_ROOT_COMPLEX structure
> + @param PcieIndex[in] PCIe controller index
> + @param EpMaxWidth[out] EP max link width
> + @param EpMaxGen[out] EP max link speed
> +**/
> +VOID
> +Ac01PcieCoreGetEndpointInfo (
> + IN AC01_ROOT_COMPLEX *RootComplex,
> + IN UINT8 PcieIndex,
> + OUT UINT8 *EpMaxWidth,
> + OUT UINT8 *EpMaxGen
> + )
> +{
> + PHYSICAL_ADDRESS CfgBase;
> + PHYSICAL_ADDRESS PcieCapBase;
> + PHYSICAL_ADDRESS SecLatTimerAddr;
> + PHYSICAL_ADDRESS TargetAddress;
> + UINT32 RestoreVal;
> + UINT32 Val;
> +
> + CfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << DEV_SHIFT);
> + SecLatTimerAddr = CfgBase + SEC_LAT_TIMER_SUB_BUS_SEC_BUS_PRI_BUS_REG;
> +
> + *EpMaxWidth = 0;
> + *EpMaxGen = 0;
> +
> + // Allow programming to config space
> + EnableDbiAccess (RootComplex, PcieIndex, TRUE);
> +
> + Val = MmioRead32 (SecLatTimerAddr);
> + RestoreVal = Val;
> + Val = SUB_BUS_SET (Val, DEFAULT_SUB_BUS);
> + Val = SEC_BUS_SET (Val, RootComplex->Pcie[PcieIndex].DevNum);
> + Val = PRIM_BUS_SET (Val, DEFAULT_PRIM_BUS);
> + MmioWrite32 (SecLatTimerAddr, Val);
> +
> + if (EndpointCfgReady (RootComplex, PcieIndex)) {
> + PcieCapBase = GetCapabilityBase (RootComplex, PcieIndex, FALSE, PCIE_CAPABILITY_ID);
> + if (PcieCapBase == 0) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "PCIE%d.%d Cannot get PCIe capability base address!\n",
> + RootComplex->ID,
> + PcieIndex
> + ));
> + } else {
> + Val = MmioRead32 (PcieCapBase + LINK_CAPABILITIES_REG);
> + *EpMaxWidth = CAP_MAX_LINK_WIDTH_GET (Val);
> + *EpMaxGen = CAP_MAX_LINK_SPEED_GET (Val);
> + DEBUG ((
> + DEBUG_INFO,
> + "PCIE%d.%d EP MaxWidth %d EP MaxGen %d \n", RootComplex->ID,
> + PcieIndex,
> + *EpMaxWidth,
> + *EpMaxGen
> + ));
> +
> + // From EP, enabling common clock for upstream
> + TargetAddress = PcieCapBase + LINK_CONTROL_LINK_STATUS_REG;
> + Val = MmioRead32 (TargetAddress);
> + Val = CAP_SLOT_CLK_CONFIG_SET (Val, 1);
> + Val = CAP_COMMON_CLK_SET (Val, 1);
> + MmioWrite32 (TargetAddress, Val);
> + }
> + }
> +
> + // Restore value in order to not affect enumeration process
> + MmioWrite32 (SecLatTimerAddr, RestoreVal);
> +
> + // Disable programming to config space
> + EnableDbiAccess (RootComplex, PcieIndex, FALSE);
> +}
> +
> +VOID
> +PollLinkUp (
> + IN AC01_ROOT_COMPLEX *RootComplex,
> + IN UINT8 PcieIndex
> + )
> +{
> + UINT32 TimeOut;
> +
> + // Poll until link up
> + // This checking for linkup status and
> + // give LTSSM state the time to transit from DECTECT state to L0 state
> + // Total delay are 100ms, smaller number of delay cannot always make sure
> + // the state transition is completed
> + TimeOut = LTSSM_TRANSITION_TIMEOUT;
> + do {
> + if (PcieLinkUpCheck (&RootComplex->Pcie[PcieIndex])) {
> + DEBUG ((
> + DEBUG_INFO,
> + "\tPCIE%d.%d LinkStat is correct after soft reset, transition time: %d\n",
> + RootComplex->ID,
> + PcieIndex,
> + TimeOut
> + ));
> + RootComplex->Pcie[PcieIndex].LinkUp = TRUE;
> + break;
> + }
> +
> + MicroSecondDelay (100);
> + TimeOut -= 100;
> + } while (TimeOut > 0);
> +
> + if (TimeOut <= 0) {
> + DEBUG ((DEBUG_ERROR, "\tPCIE%d.%d LinkStat TIMEOUT after re-init\n", RootComplex->ID, PcieIndex));
> + } else {
> + DEBUG ((DEBUG_INFO, "PCIE%d.%d Link re-initialization passed!\n", RootComplex->ID, PcieIndex));
> + }
> +}
> +
> +/**
> + Check active PCIe controllers of RootComplex, retrain or soft reset if needed
> +
> + @param RootComplex[in] Pointer to AC01_ROOT_COMPLEX structure
> + @param PcieIndex[in] PCIe controller index
> +
> + @retval -1: Link recovery had failed
> + 1: Link width and speed are not correct
> + 0: Link recovery succeed
> +**/
> +INT32
> +Ac01PcieCoreQoSLinkCheckRecovery (
> + IN AC01_ROOT_COMPLEX *RootComplex,
> + IN UINT8 PcieIndex
> + )
> +{
> + INT32 LinkStatusCheck, RasdesChecking;
> + INT32 NumberOfReset = MAX_REINIT;
> + UINT8 EpMaxWidth, EpMaxGen;
> +
> + // PCIe controller is not active or Link is not up
> + // Nothing to be done
> + if ((!RootComplex->Pcie[PcieIndex].Active) || (!RootComplex->Pcie[PcieIndex].LinkUp)) {
> + return LINK_CHECK_WRONG_PARAMETER;
> + }
> +
> + do {
> + if (RootComplex->Pcie[PcieIndex].LinkUp) {
> + // Enable all of RASDES register to detect any training error
> + Ac01PFACommand (RootComplex, PcieIndex, PFA_MODE_ENABLE);
> +
> + // Accessing Endpoint and checking current link capabilities
> + Ac01PcieCoreGetEndpointInfo (RootComplex, PcieIndex, &EpMaxWidth, &EpMaxGen);
> + LinkStatusCheck = Ac01PcieCoreLinkCheck (RootComplex, PcieIndex, EpMaxWidth, EpMaxGen);
> +
> + // Delay to allow the link to perform internal operation and generate
> + // any error status update. This allows detection of any error observed
> + // during initial link training. Possible evaluation time can be
> + // between 100ms to 200ms.
> + MicroSecondDelay (100000);
> +
> + // Check for error
> + RasdesChecking = Ac01PFACommand (RootComplex, PcieIndex, PFA_MODE_READ);
> +
> + // Clear error counter
> + Ac01PFACommand (RootComplex, PcieIndex, PFA_MODE_CLEAR);
> +
> + // If link check functions return passed, then breaking out
> + // else go to soft reset
> + if (LinkStatusCheck != LINK_CHECK_FAILED &&
> + RasdesChecking != LINK_CHECK_FAILED &&
> + PcieLinkUpCheck (&RootComplex->Pcie[PcieIndex]))
> + {
> + return LINK_CHECK_SUCCESS;
> + }
> +
> + RootComplex->Pcie[PcieIndex].LinkUp = FALSE;
> + }
> +
> + // Trigger controller soft reset
> + DEBUG ((DEBUG_INFO, "PCIE%d.%d Start link re-initialization..\n", RootComplex->ID, PcieIndex));
> + Ac01PcieCoreSetupRC (RootComplex, TRUE, PcieIndex);
> +
> + PollLinkUp (RootComplex, PcieIndex);
> +
> + NumberOfReset--;
> + } while (NumberOfReset > 0);
> +
> + return LINK_CHECK_SUCCESS;
> +}
> +
> +VOID
> +Ac01PcieCoreUpdateLink (
> + IN AC01_ROOT_COMPLEX *RootComplex,
> + OUT BOOLEAN *IsNextRoundNeeded,
> + OUT INT8 *FailedPciePtr,
> + OUT INT8 *FailedPcieCount
> + )
> +{
> + AC01_PCIE_CONTROLLER *Pcie;
> + PHYSICAL_ADDRESS CfgBase;
> + UINT8 PcieIndex;
> + UINT32 Index;
> + UINT32 Val;
> +
> + *IsNextRoundNeeded = FALSE;
> + *FailedPcieCount = 0;
> + for (Index = 0; Index < MaxPcieControllerOfRootComplexB; Index++) {
> + FailedPciePtr[Index] = -1;
> + }
> +
> + if (!RootComplex->Active) {
> + return;
> + }
> +
> + // Loop for all controllers
> + for (PcieIndex = 0; PcieIndex < RootComplex->MaxPcieController; PcieIndex++) {
> + Pcie = &RootComplex->Pcie[PcieIndex];
> + CfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << DEV_SHIFT);
> +
> + if (Pcie->Active && !Pcie->LinkUp) {
> + if (PcieLinkUpCheck (Pcie)) {
> + Pcie->LinkUp = TRUE;
> + Val = MmioRead32 (CfgBase + PCIE_CAPABILITY_BASE + LINK_CONTROL_LINK_STATUS_REG);
> +
> + DEBUG ((
> + DEBUG_INFO,
> + "%a Socket%d RootComplex%d RP%d NEGO_LINK_WIDTH: 0x%x LINK_SPEED: 0x%x\n",
> + __FUNCTION__,
> + RootComplex->Socket,
> + RootComplex->ID,
> + PcieIndex,
> + CAP_NEGO_LINK_WIDTH_GET (Val),
> + CAP_LINK_SPEED_GET (Val)
> + ));
> +
> + // Doing link checking and recovery if needed
> + Ac01PcieCoreQoSLinkCheckRecovery (RootComplex, PcieIndex);
> +
> + // Link timeout after 32ms
> + SetLinkTimeout (RootComplex, PcieIndex, 32);
> +
> + // Un-mask Completion Timeout
> + DisableCompletionTimeOut (RootComplex, PcieIndex, FALSE);
> +
> + } else {
> + *IsNextRoundNeeded = FALSE;
> + FailedPciePtr[*FailedPcieCount] = PcieIndex;
> + *FailedPcieCount += 1;
> + }
> + }
> + }
> +}
> +
> +/**
> + Verify the link status and retry to initialize the Root Complex if there's any issue.
> +
> + @param RootComplexList Pointer to the Root Complex list
> +**/
> +VOID
> +Ac01PcieCorePostSetupRC (
> + IN AC01_ROOT_COMPLEX *RootComplexList
> + )
> +{
> + UINT8 RCIndex, Idx;
> + BOOLEAN IsNextRoundNeeded, NextRoundNeeded;
> + UINT64 PrevTick, CurrTick, ElapsedCycle;
> + UINT64 TimerTicks64;
> + UINT8 ReInit;
> + INT8 FailedPciePtr[MaxPcieControllerOfRootComplexB];
> + INT8 FailedPcieCount;
> +
> + ReInit = 0;
> +
> +_link_polling:
> + NextRoundNeeded = FALSE;
> + //
> + // It is not guaranteed the timer service is ready prior to PCI Dxe.
> + // Calculate system ticks for link training.
> + //
> + TimerTicks64 = ArmGenericTimerGetTimerFreq (); /* 1 Second */
> + PrevTick = ArmGenericTimerGetSystemCount ();
> + ElapsedCycle = 0;
> +
> + do {
> + CurrTick = ArmGenericTimerGetSystemCount ();
> + if (CurrTick < PrevTick) {
> + ElapsedCycle += MAX_UINT64 - PrevTick;
> + PrevTick = 0;
> + }
> + ElapsedCycle += (CurrTick - PrevTick);
> + PrevTick = CurrTick;
> + } while (ElapsedCycle < TimerTicks64);
> +
> + for (RCIndex = 0; RCIndex < AC01_PCIE_MAX_ROOT_COMPLEX; RCIndex++) {
> + Ac01PcieCoreUpdateLink (&RootComplexList[RCIndex], &IsNextRoundNeeded, FailedPciePtr, &FailedPcieCount);
> + if (IsNextRoundNeeded) {
> + NextRoundNeeded = TRUE;
> + }
> + }
> +
> + if (NextRoundNeeded && ReInit < MAX_REINIT) {
> + //
> + // Timer is up. Give another chance to re-program controller
> + //
> + ReInit++;
> + for (RCIndex = 0; RCIndex < AC01_PCIE_MAX_ROOT_COMPLEX; RCIndex++) {
> + Ac01PcieCoreUpdateLink (&RootComplexList[RCIndex], &IsNextRoundNeeded, FailedPciePtr, &FailedPcieCount);
> + if (IsNextRoundNeeded) {
> + for (Idx = 0; Idx < FailedPcieCount; Idx++) {
> + if (FailedPciePtr[Idx] == -1) {
> + continue;
> + }
> +
> + //
> + // Some controller still observes link-down. Re-init controller
> + //
> + Ac01PcieCoreSetupRC (&RootComplexList[RCIndex], TRUE, FailedPciePtr[Idx]);
> + }
> + }
> + }
> +
> + goto _link_polling;
> + }
> +}
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/BoardPcieLibNull/BoardPcieLibNull.c b/Silicon/Ampere/AmpereAltraPkg/Library/BoardPcieLibNull/BoardPcieLibNull.c
> new file mode 100644
> index 000000000000..0916adb77539
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Library/BoardPcieLibNull/BoardPcieLibNull.c
> @@ -0,0 +1,47 @@
> +/** @file
> +
> + Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Library/BoardPcieLib.h>
> +
> +/**
> + Assert PERST of input PCIe controller
> +
> + @param[in] RootComplex RootComplex instance.
> + @param[in] PcieIndex PCIe controller index of input Root Complex.
> + @param[in] Bifurcation Bifurcation mode of input Root Complex.
> + @param[in] IsPullToHigh Target status for the PERST.
> +
> + @retval RETURN_SUCCESS The operation is successful.
> + @retval Others An error occurred.
> +**/
> +RETURN_STATUS
> +EFIAPI
> +BoardPcieAssertPerst (
> + IN AC01_ROOT_COMPLEX *RootComplex,
> + IN UINT8 PcieIndex,
> + IN BOOLEAN IsPullToHigh
> + )
> +{
> + return RETURN_SUCCESS;
> +}
> +
> +/**
> + Override the segment number for a root complex with a board specific number.
> +
> + @param[in] RootComplex Root Complex instance with properties.
> +
> + @retval Segment number corresponding to the input root complex.
> + Default segment number is 0x0F.
> +**/
> +UINT16
> +BoardPcieGetSegmentNumber (
> + IN AC01_ROOT_COMPLEX *RootComplex
> + )
> +{
> + return 0x0F;
> +}
> --
> 2.17.1
>
>
>
>
>
>
prev parent reply other threads:[~2021-11-18 15:58 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-11-18 13:41 [edk2-platforms][PATCH v6 11/30] AmpereAltraPkg: Add Ac01PcieLib library instance Nhi Pham
2021-11-18 15:58 ` Leif Lindholm [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=YZZ4K+6opH8hvv17@leviathan \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox