From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wr1-f50.google.com (mail-wr1-f50.google.com [209.85.221.50]) by mx.groups.io with SMTP id smtpd.web11.6749.1622851530098810349 for ; Fri, 04 Jun 2021 17:05:30 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@nuviainc-com.20150623.gappssmtp.com header.s=20150623 header.b=yzt5bOBu; spf=pass (domain: nuviainc.com, ip: 209.85.221.50, mailfrom: leif@nuviainc.com) Received: by mail-wr1-f50.google.com with SMTP id a11so8970087wrt.13 for ; Fri, 04 Jun 2021 17:05:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nuviainc-com.20150623.gappssmtp.com; s=20150623; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to; bh=5dI/ZjyEep0W6lZWpShDqvufdlVXrN3xbrBHIwF+Y4k=; b=yzt5bOBuBVKb6uXCJG5QJcVxFH0muKGBYG5t+toJHXFXCDCvH+UHRVTj4tLf5oZqOS WNn3XWuAs7qvlmfFthudHvdtQn3KBMZN58cZaefhyp5Htd/YC2FWFmqv1fi2GprSPpHK OtzLdzlmJhGRNsctNqZLTEUf/JNAdEcCge3SHAn1x8mK7b3x2keR4OPDD+iuIgaapdhC hk8rY2+V+QwtW+9pCiLsNOTJylBGATAb73rnMXFGjfbBpZdRDEs3Xwn9/hYqZwFEPlTW l5sIdpmj7pV0LO3L9THOx7QFB8FNwL2FhcXlSGxciDfUlQ2va71IHqm9h4y+M8Z1tCRm AlXA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to; bh=5dI/ZjyEep0W6lZWpShDqvufdlVXrN3xbrBHIwF+Y4k=; b=BBSefXKB+tKbTo4ee0bwjgUQe/R15Hh4ZnirL121bAANzmGK8EFnPamtK3XAO2WieL 85cMelEvyy16nXgDGKqULHWGl+mLvy3A8HFvH5550n/U2RiKpaBZq8/3Yo5blJL+AxeF +tpqaghoGtCRn4tlkNX07MmWxtiNANt9N+dg6cO39eVDUpWA7SPyAFPpWqCpciWm42+w xKTAHyHHkYe5XLSVCzE/IDOudIeLOo1BcYixsW4e79MFJMdYnn7reBWNRWkJjB7/t3II /XxuxZmH9Fh0Y4A1+qIRdZRdIPuBE9IckgKgLC1JMNu2+08Kn1l0iDGkFOCa/EQtLs/C kOow== X-Gm-Message-State: AOAM533JTUMUW85G49NqkJYOK78k9P56MFMxaiAQZuxCYqJcodGpbSWh zxKyaRDrm9t1oLZninKecP1UWA== X-Google-Smtp-Source: ABdhPJz9JvE02orRsp2tm0lBmFX6jJRLmZmcXuf0lAOj8J7hlGJfX82lhNJXHFMRtKmS2IP4BqKPTg== X-Received: by 2002:adf:e4cf:: with SMTP id v15mr6246995wrm.162.1622851528157; Fri, 04 Jun 2021 17:05:28 -0700 (PDT) Return-Path: Received: from leviathan (cpc1-cmbg19-2-0-cust915.5-4.cable.virginm.net. [82.27.183.148]) by smtp.gmail.com with ESMTPSA id a4sm6945467wme.45.2021.06.04.17.05.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 04 Jun 2021 17:05:27 -0700 (PDT) Date: Sat, 5 Jun 2021 01:05:25 +0100 From: "Leif Lindholm" To: Nhi Pham Cc: devel@edk2.groups.io, Vu Nguyen , Thang Nguyen , Chuong Tran , Phong Vo , Michael D Kinney , Ard Biesheuvel , Nate DeSimone Subject: Re: [edk2-platforms][PATCH v2 14/32] AmpereAltraPkg: Add PcieCoreLib library instance Message-ID: <20210605000525.zqbwom75qpcp4di4@leviathan> References: <20210526100724.5359-1-nhi@os.amperecomputing.com> <20210526100724.5359-16-nhi@os.amperecomputing.com> MIME-Version: 1.0 In-Reply-To: <20210526100724.5359-16-nhi@os.amperecomputing.com> Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Wed, May 26, 2021 at 17:07:06 +0700, Nhi Pham wrote: > From: Vu Nguyen > > Provides essential functions to initialize the PCIe Root Complex of > Ampere Altra processor. > > Cc: Thang Nguyen > Cc: Chuong Tran > Cc: Phong Vo > Cc: Leif Lindholm > Cc: Michael D Kinney > Cc: Ard Biesheuvel > Cc: Nate DeSimone > > Signed-off-by: Vu Nguyen > --- > Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec | 3 + > Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc | 1 + > Silicon/Ampere/AmpereAltraPkg/Library/PcieCoreLib/PcieCoreLib.inf | 68 ++ > Silicon/Ampere/AmpereAltraPkg/Include/Library/PcieCoreLib.h | 164 +++ > Silicon/Ampere/AmpereAltraPkg/Include/Pcie.h | 203 ++++ > Silicon/Ampere/AmpereAltraPkg/Library/PcieCoreLib/PcieCore.h | 582 +++++++++ > Silicon/Ampere/AmpereAltraPkg/Library/PcieCoreLib/PcieCoreCapCfg.h | 64 + > Silicon/Ampere/AmpereAltraPkg/Library/PcieCoreLib/PciePatchAcpi.h | 30 + > Silicon/Ampere/AmpereAltraPkg/Library/PcieCoreLib/PcieCore.c | 1266 ++++++++++++++++++++ > Silicon/Ampere/AmpereAltraPkg/Library/PcieCoreLib/PcieCoreLib.c | 536 +++++++++ > Silicon/Ampere/AmpereAltraPkg/Library/PcieCoreLib/PciePatchAcpi.c | 610 ++++++++++ > 11 files changed, 3527 insertions(+) > > diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec > index d5b12a81e9bf..0d79673ce50a 100644 > --- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec > +++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec > @@ -37,6 +37,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 methods to initialize Pcie > + PcieCoreLib|Silicon/Ampere/AmpereAltraP/Include/Library/PcieCoreLib.h > + > ## @libraryclass Defines a set of methods to access flash memory. > FlashLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h > > diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc > index 11f50f2f09cd..fc8e0b40ee19 100755 > --- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc > +++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc > @@ -83,6 +83,7 @@ [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 > + PcieCoreLib|Silicon/Ampere/AmpereAltraPkg/Library/PcieCoreLib/PcieCoreLib.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/Silicon/Ampere/AmpereAltraPkg/Library/PcieCoreLib/PcieCoreLib.inf b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCoreLib/PcieCoreLib.inf > new file mode 100755 > index 000000000000..fe20d4675518 > --- /dev/null > +++ b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCoreLib/PcieCoreLib.inf > @@ -0,0 +1,68 @@ > +## @file > +# > +# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.
> +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + INF_VERSION = 0x0001001B > + BASE_NAME = PcieCoreLib > + FILE_GUID = 8ABFA0FC-313E-11E8-B467-0ED5F89F718B > + MODULE_TYPE = DXE_DRIVER > + VERSION_STRING = 1.0 > + LIBRARY_CLASS = PcieCoreLib > + > +[Sources] > + PcieCore.c > + PcieCore.h > + PcieCoreCapCfg.h > + PcieCoreLib.c > + PciePatchAcpi.c > + PciePatchAcpi.h > + > +[Packages] > + ArmPkg/ArmPkg.dec > + ArmPlatformPkg/ArmPlatformPkg.dec > + MdeModulePkg/MdeModulePkg.dec > + MdePkg/MdePkg.dec > + Silicon/Ampere/AmpereAltraBinPkg/AmpereAltraBinPkg.dec > + Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec > + Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec > + > +[BuildOptions] > + *_*_*_CC_FLAGS = -Wno-error=switch -Wno-missing-braces No. Actually add the braces. > + > +[LibraryClasses] > + AmpereCpuLib > + ArmLib > + BaseLib > + BaseMemoryLib > + DebugLib > + GpioLib > + IoLib > + MemoryAllocationLib > + PcdLib > + PcieBoardLib > + PciePhyLib > + SerialPortLib > + SystemFirmwareInterfaceLib > + TimerLib > + UefiBootServicesTableLib > + UefiLib > + UefiRuntimeServicesTableLib > + > +[Pcd] > + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision > + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision > + > +[Protocols] > + gEfiAcpiTableProtocolGuid # PROTOCOL ALWAYS_CONSUMED > + gEfiAcpiSdtProtocolGuid # PROTOCOL ALWAYS_CONSUMED > + > +[Guids] > + gPlatformHobGuid > + > +[Depex] > + gEfiAcpiTableProtocolGuid AND gEfiAcpiSdtProtocolGuid > diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Library/PcieCoreLib.h b/Silicon/Ampere/AmpereAltraPkg/Include/Library/PcieCoreLib.h > new file mode 100644 > index 000000000000..99038454f534 > --- /dev/null > +++ b/Silicon/Ampere/AmpereAltraPkg/Include/Library/PcieCoreLib.h > @@ -0,0 +1,164 @@ > +/** @file > + > + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef PCI_CORE_LIB_H_ > +#define PCI_CORE_LIB_H_ > + > +#include > +#include > + > +/** > + Get RootBridge disable status. > + > + @param HBIndex[In] Index to identify of PCIE Host bridge. > + @param RBIndex[In] Index to identify of underneath PCIE Root bridge. > + > + @retval BOOLEAN Return RootBridge disable status. > +**/ > +BOOLEAN > +Ac01PcieCheckRootBridgeDisabled ( > + IN UINTN HBIndex, > + IN UINTN RBIndex > + ); > + > +/** > + Prepare to start PCIE core BSP driver > + > + @param ImageHandle[in] Handle for the image. > + @param SystemTable[in] Address of the system table. > + > + @retval EFI_SUCCESS Initialize successfully. > +**/ > +EFI_STATUS > +Ac01PcieSetup ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ); > + > +/** > + Prepare to end PCIE core BSP driver. > +**/ > +VOID > +Ac01PcieEnd ( > + VOID > + ); > + > +/** > + Get Total HostBridge. > + > + @retval UINTN Return Total HostBridge. > +**/ > +UINT8 > +Ac01PcieGetTotalHBs ( > + VOID > + ); > + > +/** > + Get Total RootBridge per HostBridge. > + > + @param RCIndex[in] Index to identify of Root Complex. > + > + @retval UINTN Return Total RootBridge per HostBridge. > +**/ > +UINT8 > +Ac01PcieGetTotalRBsPerHB ( > + IN UINTN RCIndex > + ); > + > +/** > + Get RootBridge Attribute. > + > + @param HBIndex[in] Index to identify of PCIE Host bridge. > + @param RBIndex[in] Index to identify of underneath PCIE Root bridge. > + > + @retval UINTN Return RootBridge Attribute. > +**/ > +UINTN > +Ac01PcieGetRootBridgeAttribute ( > + IN UINTN HBIndex, > + IN UINTN RBIndex > + ); > + > +/** > + Get RootBridge Segment number > + > + @param HBIndex[in] Index to identify of PCIE Host bridge. > + @param RBIndex[in] Index to identify of underneath PCIE Root bridge. > + > + @retval UINTN Return RootBridge Segment number. > +**/ > +UINTN > +Ac01PcieGetRootBridgeSegmentNumber ( > + IN UINTN HBIndex, > + IN UINTN RBIndex > + ); > + > +/** > + Initialize Host bridge > + > + @param HBIndex[in] Index to identify of PCIE Host bridge. > + > + @retval EFI_SUCCESS Initialize successfully. > +**/ > +EFI_STATUS > +Ac01PcieSetupHostBridge ( > + IN UINTN HBIndex > + ); > + > +/** > + Initialize Root bridge > + > + @param HBIndex[in] Index to identify of PCIE Host bridge. > + @param RBIndex[in] Index to identify of underneath PCIE Root bridge. > + @param RootBridgeInstance[in] The pointer of instance of the Root bridge IO. > + > + @retval EFI_SUCCESS Initialize successfully. > + @retval EFI_DEVICE_ERROR Error when initializing. > +**/ > +EFI_STATUS > +Ac01PcieSetupRootBridge ( > + IN UINTN HBIndex, > + IN UINTN RBIndex, > + IN PCI_ROOT_BRIDGE *RootBridge > + ); > + > +/** > + Reads/Writes an PCI configuration register. > + > + @param RootInstance[in] Pointer to RootInstance structure. > + @param Address[in] Address which want to read or write to. > + @param Write[in] Indicate that this is a read or write command. > + @param Width[in] Specify the width of the data. > + @param Data[in, out] The buffer to hold the data. > + > + @retval EFI_SUCCESS Read/Write successfully. > +**/ > +EFI_STATUS > +Ac01PcieConfigRW ( > + IN VOID *RootInstance, > + IN UINT64 Address, > + IN BOOLEAN Write, > + IN UINTN Width, > + IN OUT VOID *Data > + ); > + > +/** > + Callback funciton for EndEnumeration notification from PCI stack. > + > + @param HBIndex[in] Index to identify of PCIE Host bridge. > + @param RBIndex[in] Index to identify of underneath PCIE Root bridge. > + @param Phase[in] 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 > + ); > + > +#endif /* PCI_CORE_LIB_H_ */ > diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Pcie.h b/Silicon/Ampere/AmpereAltraPkg/Include/Pcie.h > new file mode 100644 > index 000000000000..fb4c8bbbe994 > --- /dev/null > +++ b/Silicon/Ampere/AmpereAltraPkg/Include/Pcie.h Again, namespaces. > @@ -0,0 +1,203 @@ > +/** @file > + > + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef PCIE_H_ > +#define PCIE_H_ And here. > + > +#define PCIE_CORE_DEBUG > +#define PCIE_CORE_CFG_DEBUG > +#undef PCIE_CORE_MMIO_DEBUG And here. Etc. Please add some vendor prefix to all of these. > + > +#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_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, 0x000001000000, 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, 0x000001000000, 0x000010000000, 0x000020000000, 0x000030000000, 0, 0, 0, 0, 0, 0, 0, 0 > + > +/* 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, 0x0000000001000000, 0x000000000FFFFFFF, 0x0000000000000000, 0x000000000F000000 > + > +/* 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 > + > +/* 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 > + > +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 { > + 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 { > + 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/PcieCoreLib/PcieCore.h b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCoreLib/PcieCore.h > new file mode 100644 > index 000000000000..9dd1627a85d0 > --- /dev/null > +++ b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCoreLib/PcieCore.h > @@ -0,0 +1,582 @@ > +/** @file > + > + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef PCIECORE_H_ > +#define PCIECORE_H_ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "Pcie.h" > +#include "PcieCoreCapCfg.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)) > + > +// SLOTCAP > +#define SLOT_HPC_SET(dst, src) (((dst) & ~0x40) | (((UINT32) (src) << 6) & 0x40)) > + > +// 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 SLOT_CAPABILITIES_REG (PCIE_CAP + 0x14) > +#define DEVICE_CONTROL2_DEVICE_STATUS2_REG (PCIE_CAP + 0x28) > +#define LINK_CAPABILITIES2_REG (PCIE_CAP + 0x2c) > +#define LINK_CONTROL2_LINK_STATUS2_REG (PCIE_CAP + 0x30) > +#define UNCORR_ERR_STATUS_OFF (AER_CAP + 0x4) > +#define UNCORR_ERR_MASK_OFF (AER_CAP + 0x8) > +#define RESOURCE_CON_REG_VC0 (VC_CAP + 0x14) > +#define RESOURCE_CON_REG_VC1 (VC_CAP + 0x20) > +#define RESOURCE_STATUS_REG_VC1 (VC_CAP + 0x24) > +#define SD_CONTROL1_REG (RAS_DES_CAP+0xA0) > +#define CCIX_TP_CAP_TP_HDR2_OFF (CCIX_TP_CAP + 0x8) > +#define ESM_MNDTRY_RATE_CAP_OFF (CCIX_TP_CAP + 0xc) > +#define ESM_STAT_OFF (CCIX_TP_CAP + 0x14) > +#define ESM_CNTL_OFF (CCIX_TP_CAP + 0x18) > +#define ESM_LN_EQ_CNTL_25G_0_OFF (CCIX_TP_CAP + 0x2c) > +#define PORT_LINK_CTRL_OFF 0x710 > +#define FILTER_MASK_2_OFF 0x720 > +#define GEN2_CTRL_OFF 0x80c > +#define GEN3_RELATED_OFF 0x890 > +#define GEN3_EQ_CONTROL_OFF 0x8A8 > +#define MISC_CONTROL_1_OFF 0x8bc > +#define AMBA_ERROR_RESPONSE_DEFAULT_OFF 0x8d0 > +#define AMBA_LINK_TIMEOUT_OFF 0x8d4 > +#define AMBA_ORDERING_CTRL_OFF 0x8d8 > +#define DTIM_CTRL0_OFF 0xab0 > +#define AUX_CLK_FREQ_OFF 0xb40 > +#define CCIX_CTRL_OFF 0xc20 > + > +#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) Vendor prefix. / Leif > + > +// 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)) > +#define SDES_ERR_MASK_SET(dst, src) (((dst) & ~0x20) | (((UINT32)(src) << 5) & 0x20)) > + > +// 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/PcieCoreLib/PcieCoreCapCfg.h b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCoreLib/PcieCoreCapCfg.h > new file mode 100755 > index 000000000000..0da47cb4e9d3 > --- /dev/null > +++ b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCoreLib/PcieCoreCapCfg.h > @@ -0,0 +1,64 @@ > +/** @file > + > + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.
> + > + 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/PcieCoreLib/PciePatchAcpi.h b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCoreLib/PciePatchAcpi.h > new file mode 100755 > index 000000000000..c9356f658778 > --- /dev/null > +++ b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCoreLib/PciePatchAcpi.h > @@ -0,0 +1,30 @@ > +/** @file > + > + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.
> + > + 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/PcieCoreLib/PcieCore.c b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCoreLib/PcieCore.c > new file mode 100644 > index 000000000000..a798d995ba9d > --- /dev/null > +++ b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCoreLib/PcieCore.c > @@ -0,0 +1,1266 @@ > +/** @file > + > + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "Pcie.h" > +#include "PcieCore.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 > + ) > +{ > + PLATFORM_INFO_HOB *PlatformHob; > + VOID *Hob; > + > + Hob = GetFirstGuidHob (&gPlatformHobGuid); > + PlatformHob = (PLATFORM_INFO_HOB *)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); > + > + // In order to detect the NVMe disk for booting without disk, > + // need to set Hot-Plug Slot Capable during port initialization. > + // It will help PCI Linux driver to initialize its slot iomem resource, > + // the one is used for detecting the disk when it is inserted. > + Ac01PcieCsrIn32 (CfgAddr + SLOT_CAPABILITIES_REG, &Val); > + Val = SLOT_HPC_SET (Val, 1); > + Ac01PcieCsrOut32 (CfgAddr + SLOT_CAPABILITIES_REG, 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); > + // AER surprise link down error should be masked due to hotplug is enabled > + // This event must be handled by Hotplug handler, instead of error handler > + Val = SDES_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 (MailboxMsgRegisterRead (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); > + } > + MailboxMsgRegisterWrite (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/PcieCoreLib/PcieCoreLib.c b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCoreLib/PcieCoreLib.c > new file mode 100644 > index 000000000000..5beb59689254 > --- /dev/null > +++ b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCoreLib/PcieCoreLib.c > @@ -0,0 +1,536 @@ > +/** @file > + > + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "PcieCore.h" > +#include "PciePatchAcpi.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. > + > + @param ImageHandle[in] Handle for the image. > + @param SystemTable[in] Address of the system table. > + > + @retval EFI_SUCCESS Initialize successfully. > +**/ > +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 (!IsSlaveSocketPresent ()) { > + 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; > +} > + > +/** > + Get Total HostBridge > + > + @retval UINTN Return Total HostBridge. > +**/ > +UINT8 > +Ac01PcieGetTotalHBs ( > + VOID > + ) > +{ > + return MAX_AC01_PCIE_ROOT_COMPLEX; > +} > + > +/** > + Get Total RootBridge per HostBridge. > + > + @param RCIndex[in] Index to identify of Root Complex. > + > + @retval UINTN Return Total RootBridge per HostBridge. > +**/ > +UINT8 > +Ac01PcieGetTotalRBsPerHB ( > + IN UINTN RCIndex > + ) > +{ > + return MAX_AC01_PCIE_ROOT_BRIDGE; > +} > + > +/** > + Get RootBridge Attribute. > + > + @param HBIndex[in] Index to identify of PCIE Host bridge. > + @param RBIndex[in] Index to identify of underneath PCIE Root bridge. > + > + @retval UINTN Return RootBridge Attribute. > +**/ > +UINTN > +Ac01PcieGetRootBridgeAttribute ( > + IN UINTN HBIndex, > + IN UINTN RBIndex > + ) > +{ > + return EFI_PCI_HOST_BRIDGE_MEM64_DECODE; > +} > + > +/** > + Get RootBridge Segment number. > + > + @param HBIndex[in] Index to identify of PCIE Host bridge. > + @param RBIndex[in] Index to identify of underneath PCIE Root bridge. > + > + @retval UINTN Return RootBridge Segment number. > +**/ > +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 > + ); > + } > +} > + > +/** > + Get RootBridge disable status > + > + @param HBIndex[In] Index to identify of PCIE Host bridge. > + @param RBIndex[In] Index to identify of underneath PCIE Root bridge. > + > + @retval BOOLEAN Return RootBridge disable status. > +**/ > +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 (!IsSlaveSocketPresent ()) { > + AcpiPatchPciMem32 (PciList); > + } > + AcpiInstallMcfg (PciList); > + AcpiInstallIort (PciList); > + } > + return Ret; > +} > + > +/** > + Initialize Host bridge. > + > + @param HBIndex[in] Index to identify of PCIE Host bridge. > + > + @retval EFI_SUCCESS Initialize successfully. > +**/ > +EFI_STATUS > +Ac01PcieSetupHostBridge ( > + IN UINTN HBIndex > + ) > +{ > + return EFI_SUCCESS; > +} > + > +/** > + Initialize Root bridge. > + > + @param HBIndex[in] Index to identify of PCIE Host bridge. > + @param RBIndex[in] Index to identify of underneath PCIE Root bridge. > + @param RootBridgeInstance[in] The pointer of instance of the Root bridge IO. > + > + @retval EFI_SUCCESS Initialize successfully. > + @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. > + > + @param RootInstance[in] Pointer to RootInstance structure. > + @param Address[in] Address which want to read or write to. > + @param Write[in] Indicate that this is a read or write command. > + @param Width[in] Specify the width of the data. > + @param Data[in, out] The buffer to hold the data. > + > + @retval EFI_SUCCESS Read/Write successfully. > +**/ > +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 HBIndex Index to identify of PCIE Host bridge. > + @param RBIndex Index to identify of underneath PCIE Root bridge. > + @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/PcieCoreLib/PciePatchAcpi.c b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCoreLib/PciePatchAcpi.c > new file mode 100644 > index 000000000000..dae7ee4fced1 > --- /dev/null > +++ b/Silicon/Ampere/AmpereAltraPkg/Library/PcieCoreLib/PciePatchAcpi.c > @@ -0,0 +1,610 @@ > +/** @file > + > + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#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.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; > + > + 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, > + .MemoryAddressSize = 64, > + }, > + __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; > + > + 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 >