From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from NAM10-MW2-obe.outbound.protection.outlook.com (NAM10-MW2-obe.outbound.protection.outlook.com [40.107.94.101]) by mx.groups.io with SMTP id smtpd.web08.10078.1631721601274623016 for ; Wed, 15 Sep 2021 09:00:01 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="body hash did not verify" header.i=@os.amperecomputing.com header.s=selector2 header.b=Fz70PyAw; spf=pass (domain: os.amperecomputing.com, ip: 40.107.94.101, mailfrom: nhi@os.amperecomputing.com) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=CVbfoKodWFRTLGXENkurIS8VSxLfk7UjI0h6eEUB1pIQ2BfKM29vHGcQW3TNJrpdAPTOgTFj8xNOKEaoFeWu2uNyPC60rUQiSa7C5hN68Pi/jaYiibpxjObc6nydrxB52fIMXIVIpRt7YSc+ilvaF2MvZwbTl1TQHvc/YAW8xFRLe5JDNMJ+4wrcFWq+pJk7zlKKVAmkobomDLEU1QE16WtorkamUMykVBoZQAjg6HdBe6VKX/wmXF+Z9+ECoRaZB7pu4SFqlF75Cy911HhgrIzG2QYoexkOydbAE9ubzhl9gcRNeQXTr1J9VbS8czTI5fOVDaSYU0SHHsYJ53hGXg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=0sdNAVCuDwWq4iKSq1qjf4ckq/HHPrZOz0efQQ8F5ak=; b=WMzHV+IDq0bX8S/cNQQyV+ziCho0RdSMVyQyNA20WmDBTJfK304r6OopfEcWa6hrts9+HGN0bCf9CRBC4jWUXsdWqFEULc8758ltKG9a1odsZ0Xv+qZRXXuhWd94uo79HEtc5oYcaOX67rjlbwQp4jWohAliWqWc/ew9CQXWT8LgWlk5zi0v630DcX6XyTh7GYO1QNsN1eYV1b5iDaO+iK67slrfhAEvYccHMqt+tyn9qTjiZZMrGAZoBSOkfsQbx/1o4Jjt1s52hkHzuy7ctjOMnPMTW4Ox3F14ETjOzKP/Eq2th21tC4ucmNB7SN+PpCa0N5K+CZTG7Kflorq9AA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=os.amperecomputing.com; dmarc=pass action=none header.from=os.amperecomputing.com; dkim=pass header.d=os.amperecomputing.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=os.amperecomputing.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=0sdNAVCuDwWq4iKSq1qjf4ckq/HHPrZOz0efQQ8F5ak=; b=Fz70PyAwDbNfu9ICZfmvGtz61+IZYozitHZdVqxErPcOkOfYoQcPfNAMCZDVbpDC19AgX0nczD+wkZeaIAAISInUH1Q6mnpzH2NYDL0kgIFK5dYL8bXeilYjY1I1gP9vRlIYsBU23onbzDraSlBdfjD1kHQvD1VxZh/YkLXfjBA= Authentication-Results: edk2.groups.io; dkim=none (message not signed) header.d=none;edk2.groups.io; dmarc=none action=none header.from=os.amperecomputing.com; Received: from DM6PR01MB5849.prod.exchangelabs.com (2603:10b6:5:205::20) by DM5PR0101MB3065.prod.exchangelabs.com (2603:10b6:4:33::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4500.15; Wed, 15 Sep 2021 15:59:56 +0000 Received: from DM6PR01MB5849.prod.exchangelabs.com ([fe80::8eb:704f:2ba7:9bc3]) by DM6PR01MB5849.prod.exchangelabs.com ([fe80::8eb:704f:2ba7:9bc3%4]) with mapi id 15.20.4523.014; Wed, 15 Sep 2021 15:59:56 +0000 From: "Nhi Pham" To: devel@edk2.groups.io CC: patches@amperecomputing.com, nhi@os.amperecomputing.com, vunguyen@os.amperecomputing.com, Thang Nguyen , Chuong Tran , Phong Vo , Leif Lindholm , Michael D Kinney , Ard Biesheuvel , Nate DeSimone Subject: [PATCH v3 12/28] AmpereAltraPkg: Add Ac01PcieLib library instance Date: Wed, 15 Sep 2021 22:55:11 +0700 Message-ID: <20210915155527.8176-13-nhi@os.amperecomputing.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210915155527.8176-1-nhi@os.amperecomputing.com> References: <20210915155527.8176-1-nhi@os.amperecomputing.com> X-ClientProxiedBy: HK2PR0302CA0012.apcprd03.prod.outlook.com (2603:1096:202::22) To DM6PR01MB5849.prod.exchangelabs.com (2603:10b6:5:205::20) Return-Path: nhi@os.amperecomputing.com MIME-Version: 1.0 Received: from sw004.amperecomputing.com (118.69.219.201) by HK2PR0302CA0012.apcprd03.prod.outlook.com (2603:1096:202::22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4544.5 via Frontend Transport; Wed, 15 Sep 2021 15:59:52 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 761bf82d-c998-4b87-dc94-08d97861dcac X-MS-TrafficTypeDiagnostic: DM5PR0101MB3065: X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:2000; X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: lItzW4GXkVYcmdmOTmcds3bUwESdctw5YCMrfA4aIKNuqemupz4NENw+FYm2BGhLOFDKd3DEElOBgswbgxT4jhR8A6rhj3eKkI3ZDzn8A86hRmXMWOO4uEV7COyjnfSdpRkSDuOhxsDv+X7/iw+adku5V727rDvkCgU4PYbSh5G0NCuEe8NoULWed1N+0m+YW7fit/7MukzEz32FIhWbHy1KYIL4scnICWHvfJcnJgCNsWREbqxeG911l4svpZaRuWzoiurNZCK9TYXeQN0HZhdl/YJpy+Y2iQ0XvP/vGHJygeItHNZgCJk7EpXMd1bj9VTUApsNZh2jfqQJPW5TS82ivq+LjBmVOj4Y1SDEgn5vJhCc0Lxd2achPNsnislDQEfg80E5oaiWLGutpR/1ew62VN+EhzFdz446bhUcjvUK2w/1wMPPj9bqoEiJPx5N+XQwhDRogtkohQNwh5Y682aOLzBnPsXP9rb+gtvMkk5lM/WsN0vxv96Dtm7hM6T3RJOhBFXWAb7rSuovHCNQCKMBdG2YQkN4aVxVTehFromcAHmoJc0HsCGMDurteIbivGqOdawQhMc6Hv7gjYTSNO9J0CjTPefD+tNFLQpHwbrfxkochzHxvSwW+UivyzeDk0Ooifj8l2oas3FkyYBbpmOFkNQHXn2ORKkfOvwk4vLLJLqOCPJgI3SkMcwRzFuVbuLKWBMwaxrnLsNJnWPsyg== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DM6PR01MB5849.prod.exchangelabs.com;PTR:;CAT:NONE;SFS:(4636009)(136003)(346002)(396003)(366004)(376002)(39850400004)(2616005)(38100700002)(38350700002)(2906002)(6666004)(6916009)(83380400001)(30864003)(6512007)(26005)(8676002)(4326008)(186003)(19627235002)(8936002)(478600001)(6506007)(5660300002)(52116002)(1076003)(86362001)(316002)(66556008)(54906003)(956004)(6486002)(66476007)(66946007)(559001)(579004);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?CN76TF5SRs3pV8WNPKJXRGW0SGu0fF9C8WNbehCk+3r3t8RI52/T4AP8i7b9?= =?us-ascii?Q?aubr0B+qG+5CkRQ6uPDBQqLCMcs03VqI8FDv4Zy02EPLEWf/D/IAcGUGmmV/?= =?us-ascii?Q?iQ5RzsJZgMC3dCk6K5cq4FVnUNvnLzHIiJTKE1HPia9Ds+GnHFvWdjsW4KJC?= =?us-ascii?Q?afSKz1WEwV2xCUUnM4qKL46S6nZk1Bq/qhMV7HCcVaVg27RVS96oAyjo+cSh?= =?us-ascii?Q?Jb1s//w5fE2VlTkJa+ZEQw6V2PZHAGt1VpplB0shJVJaYHh1TUQ0R0Uvxk5s?= =?us-ascii?Q?sUsf4tbnFEG/4yOQWUNxRe7NG+IKpEjjl5D3MIRQDmlTYKBtaY+G7ae7eI7i?= =?us-ascii?Q?2VandXzznvuLfWB1kSmQ/yapOffCfgVa+uHPe7Ld5FneGcoEqi6CvVuBcYQu?= =?us-ascii?Q?7B5NNZRMbGOzqGSad6wtme/QEDdvs+YoHQKZ8zscwuL8eiXNRqE/8gzjZf0F?= =?us-ascii?Q?x/0ADmF0fAZXLyCCmU8UVrgJCZa2Kw79zGQZQ3Q2o0xMTdXER8W1Fa5h/X2z?= =?us-ascii?Q?55rAIf1cUHu04KGBxGfWD0wA8bu0C2bs+IEpl3QGaGxa6BX/c2Sthkz3QgzS?= =?us-ascii?Q?xLdf1gawBG+aHCc7UFJYN0dlWTFlN4ixEs6W8SANge5viKN2U5264u8uougD?= =?us-ascii?Q?TxQAcEwQvBveXMtFG4zhcCEURQ6m2HXKdUmbvcSaemQ7WguvIdPuTiKJh41W?= =?us-ascii?Q?wgX9DZ0ZC1h2UfheBrOb/D9oKPrsQFDud9RhS2/vWDGpDEMSFMJrBmDMk8gq?= =?us-ascii?Q?WIaQNGJbgrts7OMGRl8j1oDZY6byCM7eoBoHmRawVqroWVIARIypSFIs6ks6?= =?us-ascii?Q?lOneLG5gOgdQTqmA/xIS6F3+cificOQqg+PeE7LFybrt6ro0jhaRyC/KKwQ9?= =?us-ascii?Q?lVNw0g9rzmU0wUPr7Gpjf39bh9EsRAg3Jrzi4IFe9EsEgvYKjMoIeHSzZQRE?= =?us-ascii?Q?emRHfO2DkMIEG4+Vv7lvAt41SDx9kMFwOdlRP0bePIbwWmFG4bnh2ExVqBfP?= =?us-ascii?Q?w4G4IZlSws2bMU4HfLEsaKJH+kAJvvPrylYmN9nYoNMKAudoC9vJ7quXlMab?= =?us-ascii?Q?m9c7KFv58d9bicwrjSGHtxRSm5yC+8p3PUgm6Bbp9MRr85O9WXmaQl8gZFEq?= =?us-ascii?Q?KrOLUXMs6P6JicLpr4mRkX3DOXaMMr9vEBNfPEENS2B+266Gc9wJpXI+Rrub?= =?us-ascii?Q?fr5JbZmvsZA008GnSiWnsLdZsO+6oUsPUmOn+JjXZ14N5AKZHwZzYpDIp3t8?= =?us-ascii?Q?lD65vwsLVhOIunf5mbkvziICSZgnrq0/HcFwgbkaryDI44qSof/T0kn5bScc?= =?us-ascii?Q?0TLy1DgefViTlXpi5tEq0EFk?= X-OriginatorOrg: os.amperecomputing.com X-MS-Exchange-CrossTenant-Network-Message-Id: 761bf82d-c998-4b87-dc94-08d97861dcac X-MS-Exchange-CrossTenant-AuthSource: DM6PR01MB5849.prod.exchangelabs.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 15 Sep 2021 15:59:56.3770 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 3bc2b170-fd94-476d-b0ce-4229bdc904a7 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: 2q5PlOj+1ltueNeGyGXyxKK1p+jFvTZGutWHnOKDzuTinCyGrebD1tJaL1xpU3llDldOdasB2x5aqATzTHL+gPHOZEv2RmU1803/L8okhz8= X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM5PR0101MB3065 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain 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 | 6 = + Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc | 1 = + Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/Ac01PcieLib.inf | 67 = + Silicon/Ampere/AmpereAltraPkg/Include/Ac01PcieCommon.h | 128 = ++ Silicon/Ampere/AmpereAltraPkg/Include/Library/Ac01PcieLib.h | 163 = ++ Silicon/Ampere/AmpereAltraPkg/Include/Library/BoardPcieLib.h | 92 = ++ Silicon/Ampere/AmpereAltraPkg/Include/Platform/Ac01.h | 19 = +- Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.h | 649 = ++++++++ Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCoreCapCfg.h | 63 = + Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PciePatchAcpi.h | 30 = + Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.c | 1659 = ++++++++++++++++++++ Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCoreLib.c | 556 = +++++++ Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PciePatchAcpi.c | 646 = ++++++++ 13 files changed, 4077 insertions(+), 2 deletions(-) diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec b/Silicon/Amp= ere/AmpereAltraPkg/AmpereAltraPkg.dec index d5b12a81e9bf..93da9b38def5 100644 --- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec +++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec @@ -37,6 +37,12 @@ [LibraryClasses] ## @libraryclass Defines a set of methods to communicate with secure p= arition over MM interface. MmCommunicationLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/MmCommu= nicationLib.h =20 + ## @libraryclass Defines a set of methods to initialize Pcie + Ac01PcieLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/Ac01PcieLib.h + + ## @libraryclass Defines a set of platform PCIe functions + BoardPcieLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/BoardPcieLib.= h + ## @libraryclass Defines a set of methods to access flash memory. FlashLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h =20 diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc b/Silicon= /Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc index 4af85f721cb3..d4e1b84c0276 100644 --- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc +++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc @@ -82,6 +82,7 @@ [LibraryClasses.common] NVParamLib|Silicon/Ampere/AmpereAltraPkg/Library/NVParamLib/NVParamLib.i= nf MailboxInterfaceLib|Silicon/Ampere/AmpereAltraPkg/Library/MailboxInterfa= ceLib/MailboxInterfaceLib.inf SystemFirmwareInterfaceLib|Silicon/Ampere/AmpereAltraPkg/Library/SystemF= irmwareInterfaceLib/SystemFirmwareInterfaceLib.inf + Ac01PcieLib|Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/Ac01PcieLi= b.inf AmpereCpuLib|Silicon/Ampere/AmpereAltraPkg/Library/AmpereCpuLib/AmpereCp= uLib.inf TimeBaseLib|EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.inf I2cLib|Silicon/Ampere/AmpereAltraPkg/Library/DwI2cLib/DwI2cLib.inf diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/Ac01PcieLib.= inf b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/Ac01PcieLib.inf new file mode 100644 index 000000000000..e2b0f293eb24 --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/Ac01PcieLib.inf @@ -0,0 +1,67 @@ +## @file +# +# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x0001001B + BASE_NAME =3D Ac01PcieLib + FILE_GUID =3D 8ABFA0FC-313E-11E8-B467-0ED5F89F718B + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D Ac01PcieLib + +[Sources] + PcieCore.c + PcieCore.h + PcieCoreCapCfg.h + PcieCoreLib.c + PciePatchAcpi.c + PciePatchAcpi.h + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + 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 + +[LibraryClasses] + AcpiLib + AmpereCpuLib + ArmLib + BaseLib + BaseMemoryLib + BoardPcieLib + DebugLib + GpioLib + IoLib + MemoryAllocationLib + PcdLib + 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/Ac01PcieCommon.h b/Silic= on/Ampere/AmpereAltraPkg/Include/Ac01PcieCommon.h new file mode 100644 index 000000000000..b72c305f4637 --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Include/Ac01PcieCommon.h @@ -0,0 +1,128 @@ +/** @file + + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef AC01_PCIE_COMMON_H_ +#define AC01_PCIE_COMMON_H_ + +#define PRESET_INVALID 0xFF + +// +// PCIe link width +// +enum { + LNKW_NONE =3D 0, + LNKW_X1 =3D 0x1, + LNKW_X2 =3D 0x2, + LNKW_X4 =3D 0x4, + LNKW_X8 =3D 0x8, + LNKW_X16 =3D 0x10, +}; + +// +// PCIe link speed +// +enum { + SPEED_NONE =3D 0, + SPEED_GEN1 =3D 0x1, + SPEED_GEN2 =3D 0x2, + SPEED_GEN3 =3D 0x4, + SPEED_GEN4 =3D 0x8, +}; + +// +// PCIe controller number +// +enum { + PCIE_0 =3D 0, + PCIE_1, + PCIE_2, + PCIE_3, + PCIE_4, + MAX_PCIE_A =3D PCIE_4, + PCIE_5, + PCIE_6, + PCIE_7, + MAX_PCIE, + MAX_PCIE_B =3D MAX_PCIE +}; + +// +// Root Complex type +// +enum { + RCA, + RCB +}; + +// +// Root Complex number +// +enum { + RCA0 =3D 0, + RCA1, + RCA2, + RCA3, + MAX_RCA, + RCB0 =3D MAX_RCA, + RCB1, + RCB2, + RCB3, + MAX_RCB, + MAX_RC =3D MAX_RCB +}; + +// +// Data structure to store the PCIe controller information +// +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 Compl= ex + 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; + +// +// Data structure to store the Root Complex information +// +typedef struct { + UINT64 BaseAddr; + UINT64 TcuAddr; + UINT64 HBAddr; + UINT64 MsgAddr; + UINT64 SerdesAddr; + UINT64 MmcfgAddr; + UINT64 MmioAddr; + UINT64 MmioSize; + UINT64 Mmio32Addr; + UINT64 Mmio32Size; + UINT64 IoAddr; + AC01_PCIE Pcie[MAX_PCIE_B]; + UINT8 MaxPcieController; + UINT8 Type; + UINT8 ID; + UINT8 DevMapHigh:3; // Copy of High Devmap programmed to H= ost bridge + UINT8 DevMapLow:3; // Copy of Low Devmap programmed to Ho= st bridge + UINT8 DefaultDevMapHigh:3; // Default of High devmap based on boa= rd settings + UINT8 DefaultDevMapLow:3; // Default of Low devmap based on boar= d 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/Include/Library/Ac01PcieLib.h b/= Silicon/Ampere/AmpereAltraPkg/Include/Library/Ac01PcieLib.h new file mode 100644 index 000000000000..47c6452a0499 --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Include/Library/Ac01PcieLib.h @@ -0,0 +1,163 @@ +/** @file + + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef AC01_PCIE_LIB_H_ +#define AC01_PCIE_LIB_H_ + +#include +#include + +/** + Get RootBridge disable status. + + @param[in] HBIndex Index to identify of PCIE Host bridge. + @param[in] RBIndex Index to identify of underneath PCIE R= oot bridge. + + @retval BOOLEAN Return RootBridge disable status. +**/ +BOOLEAN +Ac01PcieCheckRootBridgeDisabled ( + IN UINTN HBIndex, + IN UINTN RBIndex + ); + +/** + Prepare to start PCIE core BSP driver + + @retval EFI_SUCCESS The operation is successful. + @retval Others An error occurred. +**/ +EFI_STATUS +Ac01PcieSetup ( + VOID + ); + +/** + 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[in] RCIndex Index to identify of Root Complex. + + @retval UINTN Return Total RootBridge per HostBridge= . +**/ +UINT8 +Ac01PcieGetTotalRBsPerHB ( + IN UINTN RCIndex + ); + +/** + Get RootBridge Attribute. + + @param[in] HBIndex Index to identify of PCIE Host bridge. + @param[in] RBIndex Index to identify of underneath PCIE R= oot bridge. + + @retval UINTN Return RootBridge Attribute. +**/ +UINTN +Ac01PcieGetRootBridgeAttribute ( + IN UINTN HBIndex, + IN UINTN RBIndex + ); + +/** + Get RootBridge Segment number + + @param[in] HBIndex Index to identify of PCIE Host bridge. + @param[in] RBIndex Index to identify of underneath PCIE R= oot bridge. + + @retval UINTN Return RootBridge Segment number. +**/ +UINTN +Ac01PcieGetRootBridgeSegmentNumber ( + IN UINTN HBIndex, + IN UINTN RBIndex + ); + +/** + Initialize Host bridge + + @param[in] HBIndex Index to identify of PCIE Host bridge. + + @retval EFI_SUCCESS The operation is successful. + @retval Others An error occurred. +**/ +EFI_STATUS +Ac01PcieSetupHostBridge ( + IN UINTN HBIndex + ); + +/** + Initialize Root bridge + + @param[in] HBIndex Index to identify of PCIE Host bridge. + @param[in] RBIndex Index to identify of underneath PCIE R= oot bridge. + @param[in] RootBridgeInstance The pointer of instance of the Root br= idge IO. + + @retval EFI_SUCCESS The operation is successful. + @retval Others An error occurred. +**/ +EFI_STATUS +Ac01PcieSetupRootBridge ( + IN UINTN HBIndex, + IN UINTN RBIndex, + IN PCI_ROOT_BRIDGE *RootBridge + ); + +/** + Reads/Writes an PCI configuration register. + + @param[in] RootInstance Pointer to RootInstance structure. + @param[in] Address Address which want to read or write to= . + @param[in] Write Indicate that this is a read or write = command. + @param[in] Width Specify the width of the data. + @param[in, out] Data The buffer to hold the data. + + @retval EFI_SUCCESS The operation is successful. + @retval Others An error occurred. +**/ +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[in] HBIndex Index to identify of PCIE Host bridge. + @param[in] RBIndex Index to identify of underneath PCIE R= oot bridge. + @param[in] Phase The phase of enumeration as informed f= rom PCI stack. +**/ +VOID +Ac01PcieHostBridgeNotifyPhase ( + IN UINTN HBIndex, + IN UINTN RBIndex, + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase + ); + +#endif /* AC01_PCIE_LIB_H_ */ diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Library/BoardPcieLib.h b= /Silicon/Ampere/AmpereAltraPkg/Include/Library/BoardPcieLib.h new file mode 100644 index 000000000000..772a85dd5677 --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Include/Library/BoardPcieLib.h @@ -0,0 +1,92 @@ +/** @file + + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef BOARD_PCIE_LIB_H_ +#define BOARD_PCIE_LIB_H_ + +#include + +/** + Override the segment number for a root complex with a board specific num= ber. + + @param[in] RC Root Complex instance with properties. + @param[out] SegmentNumber Return segment number. + + @retval EFI_SUCCESS The operation is successful. + @retval Others An error occurred. +**/ +EFI_STATUS +EFIAPI +BoardPcieGetRCSegmentNumber ( + IN AC01_RC *RC, + OUT UINTN *SegmentNumber + ); + +/** + Check if SMM PMU enabled in board screen. + + @param[out] IsSmmuPmuEnabled TRUE if the SMMU PMU enabled, otherwis= e FALSE. + + @retval EFI_SUCCESS The operation is successful. + @retval Others An error occurred. +**/ +EFI_STATUS +EFIAPI +BoardPcieCheckSmmuPmuEnabled ( + OUT BOOLEAN *IsSmmuPmuEnabled + ); + +/** + Build PCIe menu screen. + + @param[in] RCList List of Root Complex with properties. + + @retval EFI_SUCCESS The operation is successful. + @retval Others An error occurred. +**/ +EFI_STATUS +EFIAPI +BoardPcieScreenInitialize ( + IN AC01_RC *RCList + ); + +/** + Parse platform Root Complex information. + + @param[out] RC Root Complex instance to store the pla= tform information. + + @retval EFI_SUCCESS The operation is successful. + @retval Others An error occurred. +**/ +EFI_STATUS +EFIAPI +BoardPcieParseRCParams ( + OUT AC01_RC *RC + ); + +/** + Assert PERST of input PCIe controller + + @param[in] RC Root Complex instance. + @param[in] PcieIndex PCIe controller index of input Root Co= mplex. + @param[in] Bifurcation Bifurcation mode of input Root Complex= . + @param[in] IsPullToHigh Target status for the PERST. + + @retval EFI_SUCCESS The operation is successful. + @retval Others An error occurred. +**/ +EFI_STATUS +EFIAPI +BoardPcieAssertPerst ( + IN AC01_RC *RC, + IN UINT32 PcieIndex, + IN UINT8 Bifurcation, + IN BOOLEAN IsPullToHigh + ); + +#endif /* BOARD_PCIE_LIB_H_ */ diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Platform/Ac01.h b/Silico= n/Ampere/AmpereAltraPkg/Include/Platform/Ac01.h index 66286bfff145..ed25c6eaa3b8 100644 --- a/Silicon/Ampere/AmpereAltraPkg/Include/Platform/Ac01.h +++ b/Silicon/Ampere/AmpereAltraPkg/Include/Platform/Ac01.h @@ -264,15 +264,30 @@ // #define AC01_PCIE_MMIO_BASE 0x300000000000, 0x340000000000, 0x3800= 00000000, 0x3C0000000000, 0x200000000000, 0x240000000000, 0x280000000000, 0= x2C0000000000, 0x700000000000, 0x740000000000, 0x780000000000, 0x7C00000000= 00, 0x600000000000, 0x640000000000, 0x680000000000, 0x6C0000000000 =20 +// +// The size of MMIO space +// +#define AC01_PCIE_MMIO_SIZE 0x3FFE0000000, 0x3FFE0000000, 0x3FFE00= 00000, 0x3FFE0000000, 0x3FFE0000000, 0x3FFE0000000, 0x3FFE0000000, 0x3FFE00= 00000, 0x3FFE0000000, 0x3FFE0000000, 0x3FFE0000000, 0x3FFE0000000, 0x3FFE00= 00000, 0x3FFE0000000, 0x3FFE0000000, 0x3FFE0000000 + // // The base address of MMIO32 Registers // -#define AC01_PCIE_MMIO32_BASE 0x000020000000, 0x000028000000, 0x0000= 30000000, 0x000038000000, 0x000001000000, 0x000008000000, 0x000010000000, 0= x000018000000, 0x000060000000, 0x000068000000, 0x000070000000, 0x0000780000= 00, 0x000040000000, 0x000048000000, 0x000050000000, 0x000058000000 +#define AC01_PCIE_MMIO32_BASE 0x000020000000, 0x000028000000, 0x0000= 30000000, 0x000038000000, 0x000004000000, 0x000008000000, 0x000010000000, 0= x000018000000, 0x000060000000, 0x000068000000, 0x000070000000, 0x0000780000= 00, 0x000040000000, 0x000048000000, 0x000050000000, 0x000058000000 + +// +// The size of MMIO32 space +// +#define AC01_PCIE_MMIO32_SIZE 0x8000000, 0x8000000, 0x8000000, 0x800= 0000, 0x4000000, 0x8000000, 0x8000000, 0x8000000, 0x8000000, 0x8000000, 0x8= 000000, 0x8000000, 0x8000000, 0x8000000, 0x8000000, 0x8000000 =20 // // The base address of MMIO32 Registers // -#define AC01_PCIE_MMIO32_BASE_1P 0x000040000000, 0x000050000000, 0x0000= 60000000, 0x000070000000, 0x000001000000, 0x000010000000, 0x000020000000, 0= x000030000000, 0, 0, 0, 0, 0, 0, 0, 0 +#define AC01_PCIE_MMIO32_BASE_1P 0x000040000000, 0x000050000000, 0x0000= 60000000, 0x000070000000, 0x000008000000, 0x000010000000, 0x000020000000, 0= x000030000000, 0, 0, 0, 0, 0, 0, 0, 0 + +// +// The size of MMIO32 1P space +// +#define AC01_PCIE_MMIO32_SIZE_1P 0x10000000, 0x10000000, 0x10000000, 0x= 10000000, 0x8000000, 0x10000000, 0x10000000, 0x10000000, 0, 0, 0, 0, 0, 0, = 0, 0 =20 // // DSDT RCA2 PCIe Meme32 Attribute diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.h b= /Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.h new file mode 100644 index 000000000000..f84f7cec9fae --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.h @@ -0,0 +1,649 @@ +/** @file + + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef AC01_PCIE_CORE_H_ +#define AC01_PCIE_CORE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "PcieCoreCapCfg.h" + +#ifdef ENABLE_DEBUG_CFG +#define DEBUG_PCIE_CFG(arg...) \ + if (DebugCodeEnabled()) { \ + DEBUG ((DEBUG_INFO,"PCICore (CFG): ")); \ + DEBUG ((DEBUG_INFO,## arg)); \ + } +#else +#define DEBUG_PCIE_CFG(arg...) +#endif + +#ifdef ENABLE_DEBUG_CSR +#define DEBUG_PCIE_CSR(arg...) \ + if (DebugCodeEnabled()) { \ + DEBUG ((DEBUG_INFO,"PCICore (CSR): ")); \ + DEBUG ((DEBUG_INFO,## arg)); \ + } +#else +#define DEBUG_PCIE_CSR(arg...) +#endif + +#ifdef ENABLE_DEBUG_PHY +#define DEBUG_PCIE_PHY(arg...) \ + if (DebugCodeEnabled()) { \ + DEBUG ((DEBUG_INFO,"PCICore (PHY): ")); \ + DEBUG ((DEBUG_INFO,## arg)); \ + } +#else +#define DEBUG_PCIE_PHY(arg...) +#endif + +#ifdef ENABLE_DEBUG_INFO +#define DEBUG_PCIE_INFO(arg...) \ + if (DebugCodeEnabled()) { \ + DEBUG ((DEBUG_INFO,"PCICore (DBG): ")); \ + DEBUG ((DEBUG_INFO,## arg)); \ + } +#else +#define DEBUG_PCIE_INFO(arg...) +#endif + +#define DEBUG_PCIE_ERR(arg...) \ + DEBUG ((DEBUG_ERROR,"PCICore (ERROR): ")); \ + DEBUG ((DEBUG_ERROR,## arg)); + +#ifndef BIT +#define BIT(nr) (1 << (nr)) +#endif + + +#define SLOT_POWER_LIMIT 75 // Watt + +#define MAX_REINIT 3 + +#define LINK_CHECK_SUCCESS 0 +#define LINK_CHECK_FAILED -1 +#define LINK_CHECK_WRONG_PARAMETER 1 + +#define PFA_REG_ENABLE 0 +#define PFA_REG_READ 1 +#define PFA_REG_CLEAR 2 + +#define AMPERE_PCIE_VENDORID 0x1DEF +#define AC01_HOST_BRIDGE_DEVICEID_RCA 0xE100 +#define AC01_HOST_BRIDGE_DEVICEID_RCB 0xE110 +#define AC01_PCIE_BRIDGE_DEVICEID_RCA 0xE101 +#define AC01_PCIE_BRIDGE_DEVICEID_RCB 0xE111 + +#define MEMRDY_TIMEOUT 10 // 10 us +#define PIPE_CLOCK_TIMEOUT 20000 // 20,000 us +#define LTSSM_TRANSITION_TIMEOUT 100000 // 100 ms in total +#define EP_LINKUP_TIMEOUT (10 * 1000) // 10ms +#define LINK_WAIT_INTERVAL_US 50 + +#define LINK_POLL_US_TIMER 1 +#define IO_SPACE 0x2000 + +#define TCU_OFFSET 0 +#define HB_CSR_OFFSET 0x01000000 +#define PCIE0_CSR_OFFSET 0x01010000 +#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) (sr= c) << 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) (s= rc)) & 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) | (((UINT= 32) (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)) & 0= x7)) +#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) & 0x= 8)) +#define EQRQST_SET(dst, src) (((dst) & ~0x10) | (((UINT32) (src) << 4) & 0= x10)) +#define INTPIN_SET(dst, src) (((dst) & ~0xFF00) | (((UINT32) (src) << 8) &= 0xFF00)) + +// SLOTCAP +#define SLOT_HPC_SET(dst, src) (((dst) & ~0x40) | (((UINT32) (src) << 6) &= 0x40)) + +// SLOT_CAPABILITIES_REG, PCIE_CAP_SLOT_POWER_LIMIT_VALUE bits[14:7] +#define SLOT_CAP_SLOT_POWER_LIMIT_VALUE_SET(dst, src) \ + (((dst) & ~0x7F80) | (((UINT32)(src) << 7) & 0= x7F80)) + +// 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) & 0= x40)) + +// IRQEVENTSTAT +#define BLOCK_INT_MASK (1 << 4) +#define 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)) & 0= xFFFF)) +#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) (s= rc) << 8) & 0xFF00)) +#define REVISION_ID_SET(dst, src) (((dst) & ~0xFF) | (((UINT32) (src)) & 0= xFF)) + +// SEC_LAT_TIMER_SUB_BUS_SEC_BUS_PRI_BUS_REG +#define DEFAULT_SUB_BUS 0xFF +#define SUB_BUS_SET(dst, src) (((dst) & ~0xFF0000) | (((UINT32) (src) << 1= 6) & 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)) & 0x= 3)) + +// DEVICE_CONTROL2_DEVICE_STATUS2_REG +#define CAP_CPL_TIMEOUT_VALUE_SET(dst, src) (((dst) & ~0xF) | (((UINT32) (= src)) & 0xF)) + +// LINK_CAPABILITIES_REG +#define CAP_ID 0x10 +#define LINK_CAPABILITIES_REG_OFF 0xC +#define LINK_CONTROL_LINK_STATUS_OFF 0x10 +#define CAP_MAX_LINK_WIDTH_X1 0x1 +#define CAP_MAX_LINK_WIDTH_X2 0x2 +#define CAP_MAX_LINK_WIDTH_X4 0x4 +#define CAP_MAX_LINK_WIDTH_X8 0x8 +#define CAP_MAX_LINK_WIDTH_X16 0x10 +#define CAP_MAX_LINK_WIDTH_GET(val) ((val & 0x3F0) >> 4) +#define CAP_MAX_LINK_WIDTH_SET(dst, src) (((dst) & ~0x3F0) | (((UIN= T32) (src) << 4) & 0x3F0)) +#define MAX_LINK_SPEED_25 0x1 +#define MAX_LINK_SPEED_50 0x2 +#define MAX_LINK_SPEED_80 0x3 +#define MAX_LINK_SPEED_160 0x4 +#define MAX_LINK_SPEED_320 0x5 +#define CAP_MAX_LINK_SPEED_GET(val) ((val & 0xF)) +#define CAP_MAX_LINK_SPEED_SET(dst, src) (((dst) & ~0xF) | (((UINT3= 2) (src)) & 0xF)) +#define CAP_SLOT_CLK_CONFIG_SET(dst, src) (((dst) & ~0x10000000) | (= ((UINT32) (src) << 28) & 0x10000000)) +#define NO_ASPM_SUPPORTED 0x0 +#define L0S_SUPPORTED 0x1 +#define L1_SUPPORTED 0x2 +#define L0S_L1_SUPPORTED 0x3 +#define CAP_ACTIVE_STATE_LINK_PM_SUPPORT_SET(dst, src) (((dst) & ~0xC00) |= (((UINT32)(src) << 10) & 0xC00)) + +// LINK_CONTROL_LINK_STATUS_REG +#define CAP_DLL_ACTIVE_GET(val) ((val & 0x20000000) >> 29) +#define CAP_NEGO_LINK_WIDTH_GET(val) ((val & 0x3F00000) >> 20) +#define CAP_LINK_SPEED_GET(val) ((val & 0xF0000) >> 16) +#define CAP_LINK_SPEED_SET(dst, src) (((dst) & ~0xF0000) | (((U= INT32) (src) << 16) & 0xF0000)) +#define CAP_LINK_SPEED_TO_VECTOR(val) BIT((val)-1) +#define CAP_EN_CLK_POWER_MAN_GET(val) ((val & 0x100) >> 8) +#define CAP_EN_CLK_POWER_MAN_SET(dst, src) (((dst) & ~0x100) | (((UIN= T32) (src) << 8) & 0x100)) +#define CAP_RETRAIN_LINK_SET(dst, src) (((dst) & ~0x20) | (((UINT= 32) (src) << 5) & 0x20)) +#define CAP_COMMON_CLK_SET(dst, src) (((dst) & ~0x40) | (((UINT= 32) (src) << 6) & 0x40)) +#define CAP_LINK_TRAINING_GET(val) ((val & 0x8000000) >> 27) +#define CAP_LINK_DISABLE_SET(dst, src) (((dst) & ~0x10) | (((UINT= 32)(src) << 4) & 0x10)) + +// 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 CAP_SUPPORT_LINK_SPEED_VECTOR_GET(val) ((val & 0xFE) >> 1) +#define CAP_SUPPORT_LINK_SPEED_VECTOR_SET(dst, src) (((dst) & ~0xFE) | (((= UINT32) (src) << 1) & 0xFE)) +#define CAP_EQ_CPL_GET(val) ((val & 0x20000) >> 17) +#define CAP_EQ_CPL_P1_GET(val) ((val & 0x40000) >> 18) +#define CAP_EQ_CPL_P2_GET(val) ((val & 0x80000) >> 19) +#define CAP_EQ_CPL_P3_GET(val) ((val & 0x100000) >> 20) + +// LINK_CONTROL2_LINK_STATUS2_REG +#define CAP_TARGET_LINK_SPEED_SET(dst, src) (((dst) & ~0xF) | (((UINT3= 2) (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) | (((UIN= T32) (src) << 14) & 0x4000)) + +// UNCORR_ERR_MASK_OFF +#define CMPLT_TIMEOUT_ERR_MASK_SET(dst, src) (((dst) & ~0x4000) | (((UINT3= 2) (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) | (((UINT3= 2) (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) | (((UI= NT32) (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) | (((UIN= T32) (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) (s= rc) << 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)) & 0= x1)) + +// 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) | (((UINT= 32) (src)) & 0x1)) + +// AMBA_LINK_TIMEOUT_OFF +#define LINK_TIMEOUT_PERIOD_DEFAULT_SET(dst, src) (((dst) & ~0xFF) | (((UI= NT32) (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) | (((UINT= 32) (src)) & 0xFFFF)) + +// AUX_CLK_FREQ_OFF +#define AUX_CLK_500MHZ 500 +#define AUX_CLK_FREQ_SET(dst, src) (((dst) & ~0x1FF) | (((UINT32) (src)) &= 0x1FF)) + +#define EXT_CAP_OFFSET_START 0x100 + +// EVENT_COUNTER_CONTROL_REG +#define ECCR_GROUP_EVENT_SEL_SET(dst, src) (((dst) & ~0xFFF0000) = | (((UINT32)(src) << 16) & 0xFFF0000)) +#define ECCR_GROUP_SEL_SET(dst, src) (((dst) & ~0xF000000) = | (((UINT32)(src) << 24) & 0xF000000)) +#define ECCR_EVENT_SEL_SET(dst, src) (((dst) & ~0xFF0000) |= (((UINT32)(src) << 16) & 0xFF0000)) +#define ECCR_LANE_SEL_SET(dst, src) (((dst) & ~0xF00) | ((= (UINT32)(src) << 8) & 0xF00)) +#define ECCR_EVENT_COUNTER_ENABLE_SET(dst, src) (((dst) & ~0x1C) | (((= UINT32)(src) << 2) & 0x1C)) +#define ECCR_EVENT_COUNTER_CLEAR_SET(dst, src) (((dst) & ~0x3) | (((U= INT32)(src)) & 0x3)) + +// PFA Registers offests +#define RAS_DES_CAP_ID 0xB +#define EVENT_COUNTER_CONTROL_REG_OFF 0x8 +#define EVENT_COUNTER_DATA_REG_OFF 0xC + +#define MAX_NUM_ERROR_CODE 47 +#define DEFAULT_COMMON_LANE_NUM 15 + +enum LTSSM_STATE { + S_DETECT_QUIET =3D 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 MmioSize, + UINT64 Mmio32Base, + UINT64 Mmio32Size + ); + +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 /* AC01_PCIE_CORE_H_ */ diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCoreCapC= fg.h b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCoreCapCfg.h new file mode 100644 index 000000000000..c3914673b852 --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCoreCapCfg.h @@ -0,0 +1,63 @@ +/** @file + + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef AC01_PCIE_CAP_CFG_H_ +#define AC01_PCIE_CAP_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 /* AC01_PCIE_CAP_CFG_H_ */ diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PciePatchAcp= i.h b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PciePatchAcpi.h new file mode 100644 index 000000000000..2dfefdf97159 --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/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 AC01_PCIE_PATCH_ACPI_H_ +#define AC01_PCIE_PATCH_ACPI_H_ + +EFI_STATUS +EFIAPI +AcpiPatchPciMem32 ( + INT8 *PciSegEnabled + ); + +EFI_STATUS +EFIAPI +AcpiInstallMcfg ( + INT8 *PciSegEnabled + ); + +EFI_STATUS +EFIAPI +AcpiInstallIort ( + INT8 *PciSegEnabled + ); + +#endif /* AC01_PCIE_PATCH_ACPI_H_ */ diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.c b= /Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.c new file mode 100644 index 000000000000..684dd808a96a --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.c @@ -0,0 +1,1659 @@ +/** @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 "PcieCore.h" + +STATIC INT32 +Ac01PcieCsrOut32 ( + VOID *Addr, + UINT32 Val + ) +{ + MmioWrite32 ((UINT64)Addr, Val); + DEBUG_PCIE_CSR ( + "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); + DEBUG_PCIE_CSR ( + "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 =3D MmioRead32 ((UINT64)Addr); + DEBUG_PCIE_CSR ("PCIE CSR RD: 0x%p value: 0x%08X\n", Addr, *Val); + + return 0; +} + +STATIC INT32 +Ac01PcieCsrIn32Serdes ( + VOID *Addr, + UINT32 *Val + ) +{ + *Val =3D MmioRead32 ((UINT64)Addr); + DEBUG_PCIE_CSR ("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 + ) +{ + DEBUG_PCIE_PHY ("%a\n", __FUNCTION__); +} + +VOID +Ac01PciePutInt ( + UINT32 val + ) +{ + DEBUG_PCIE_PHY ("%a\n", __FUNCTION__); +} + +VOID +Ac01PciePutHex ( + UINT64 val + ) +{ + DEBUG_PCIE_PHY ("%a\n", __FUNCTION__); +} + +INT32 +Ac01PcieDebugPrint ( + CONST CHAR8 *fmt, + ... + ) +{ + DEBUG_PCIE_PHY ("%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); + DEBUG_PCIE_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 =3D (UINT64)Addr & ~0x3; + UINT32 Val32 =3D MmioRead32 (AlignedAddr); + + switch ((UINT64)Addr & 0x3) { + case 2: + Val32 &=3D ~0xFFFF0000; + Val32 |=3D (UINT32)Val << 16; + break; + + case 0: + default: + Val32 &=3D ~0xFFFF; + Val32 |=3D Val; + break; + } + MmioWrite32 (AlignedAddr, Val32); + DEBUG_PCIE_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 =3D (UINT64)Addr & ~0x3; + UINT32 Val32 =3D MmioRead32 (AlignedAddr); + + switch ((UINT64)Addr & 0x3) { + case 0: + Val32 &=3D ~0xFF; + Val32 |=3D Val; + break; + + case 1: + Val32 &=3D ~0xFF00; + Val32 |=3D (UINT32)Val << 8; + break; + + case 2: + Val32 &=3D ~0xFF0000; + Val32 |=3D (UINT32)Val << 16; + break; + + case 3: + default: + Val32 &=3D ~0xFF000000; + Val32 |=3D (UINT32)Val << 24; + break; + } + MmioWrite32 (AlignedAddr, Val32); + DEBUG_PCIE_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, Ht, Primary =3D 0, Sec =3D 0, Sub =3D 0; + + if ((BUS_NUM (Addr) > 0) && (DEV_NUM (Addr) > 0) && (CFG_REG (Addr) =3D= =3D 0)) { + *Val =3D MmioRead32 ((UINT64)Addr); + DEBUG_PCIE_CFG ( + "PCIE CFG RD: B%X|D%X 0x%p value: 0x%08X\n", + BUS_NUM (Addr), + DEV_NUM (Addr), + Addr, + *Val + ); + + if (*Val !=3D 0xffffffff) { + RegC =3D MmioRead32 ((UINT64)Addr + 0xC); + DEBUG_PCIE_CFG ("Peek PCIE MfHt RD32: 0x%p value: 0x%08X\n", Addr + = 0xc, RegC); + MfHt =3D RegC >> 16; + DEBUG_PCIE_CFG (" Peek RD8 MfHt=3D0x%02X\n", MfHt); + + Ht =3D MfHt & 0x7F; + if (Ht !=3D 0) { /* Type 1 header */ + Reg18 =3D MmioRead32 ((UINT64)Addr + 0x18); + Primary =3D Reg18; Sec =3D Reg18 >> 8; Sub =3D Reg18 >> 16; + DEBUG_PCIE_CFG ( + " Bus Peek PCIE Sub:%01X Sec:%01X Primary:%01X RD: 0x%p value:= 0x%08X\n", + Sub, + Sec, + Primary, + Addr + 0x18, + Reg18 + ); + } + if ((Ht =3D=3D 0) || (Primary !=3D 0)) { /* Ampere Altra RPs Primary= Bus is 0b */ + *Val =3D 0xffffffff; + DEBUG_PCIE_CFG ( + " Skip RD32 B%X|D%X PCIE CFG RD: 0x%p return 0xffffffff\n", + BUS_NUM (Addr), + DEV_NUM (Addr), + Addr + ); + } + } + } else { + *Val =3D MmioRead32 ((UINT64)Addr); + } + DEBUG_PCIE_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 =3D (UINT64)Addr & ~0x3; + UINT32 RegC, Reg18; + UINT8 MfHt, Primary =3D 0, Sec =3D 0, Sub =3D 0; + UINT32 Val32; + + if ((BUS_NUM (Addr) > 0) && (DEV_NUM (Addr) > 0) && (CFG_REG (Addr) =3D= =3D 0)) { + *Val =3D MmioRead32 ((UINT64)Addr); + DEBUG_PCIE_CFG ( + "PCIE CFG16 RD: B%X|D%X 0x%p value: 0x%08X\n", + BUS_NUM (Addr), + DEV_NUM (Addr), + Addr, + *Val + ); + + if (*Val !=3D 0xffff) { + RegC =3D MmioRead32 ((UINT64)Addr + 0xC); + DEBUG_PCIE_CFG (" Peek PCIE MfHt RD: 0x%p value: 0x%08X\n", Addr + = 0xc, RegC); + MfHt =3D RegC >> 16; + DEBUG_PCIE_CFG (" Peek RD8 MfHt=3D0x%02X\n", MfHt); + + + if ((MfHt & 0x7F)!=3D 0) { /* Type 1 header */ + Reg18 =3D MmioRead32 ((UINT64)Addr + 0x18); + Primary =3D Reg18; Sec =3D Reg18 >> 8; Sub =3D Reg18 >> 16; + DEBUG_PCIE_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 =3D=3D 0) || (Primary !=3D 0)) { /* QS RPs Primary Bus is = 0b */ + *Val =3D 0xffff; + DEBUG_PCIE_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 =3D MmioRead32 (AlignedAddr); + switch ((UINT64)Addr & 0x3) { + case 2: + *Val =3D Val32 >> 16; + break; + + case 0: + default: + *Val =3D Val32; + break; + } + DEBUG_PCIE_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 =3D (UINT64)Addr & ~0x3; + UINT32 Val32 =3D MmioRead32 (AlignedAddr); + switch ((UINT64)Addr & 0x3) { + case 3: + *Val =3D Val32 >> 24; + break; + + case 2: + *Val =3D Val32 >> 16; + break; + + case 1: + *Val =3D Val32 >> 8; + break; + + case 0: + default: + *Val =3D Val32; + break; + } + DEBUG_PCIE_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 =3D 0, NextCap =3D 0, CapId =3D 0, ExCap =3D 0; + + if (IsRC) { + CfgAddr =3D (VOID *)(RC->MmcfgAddr + (RC->Pcie[PcieIndex].DevNum << 15= )); + } else { + CfgAddr =3D (VOID *)(RC->MmcfgAddr + (RC->Pcie[PcieIndex].DevNum << 20= )); + } + + Ac01PcieCsrIn32 (CfgAddr + TYPE1_CAP_PTR_REG, &Val); + NextCap =3D Val & 0xFF; + + // Loop untill desired capability is found else return 0 + while (1) { + if ((NextCap & 0x3) !=3D 0) { + /* Not alignment, just return */ + return 0; + } + Ac01PcieCsrIn32 (CfgAddr + NextCap, &Val); + if (NextCap < EXT_CAP_OFFSET_START) { + CapId =3D Val & 0xFF; + } else { + CapId =3D Val & 0xFFFF; + } + + if (CapId =3D=3D ExtendedCapId) { + return (UINT64)(CfgAddr + NextCap); + } + + if (NextCap < EXT_CAP_OFFSET_START) { + NextCap =3D (Val & 0xFFFF) >> 8; + } else { + NextCap =3D (Val & 0xFFFF0000) >> 20; + } + + if ((NextCap =3D=3D 0) && (ExCap =3D=3D 0)) { + ExCap =3D 1; + NextCap =3D EXT_CAP_OFFSET_START; + } + + if ((NextCap =3D=3D 0) && (ExCap =3D=3D 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, a= nd MMCFG register + @param MmioBase Base address of 64-bit MMIO + @param MmioSize Size of 64-bit MMIO space + @param Mmio32Base Base address of 32-bit MMIO + @param Mmio32Size Size of 32-bit MMIO space +**/ +VOID +Ac01PcieCoreBuildRCStruct ( + AC01_RC *RC, + UINT64 RegBase, + UINT64 MmioBase, + UINT64 MmioSize, + UINT64 Mmio32Base, + UINT64 Mmio32Size + ) +{ + INTN PcieIndex; + + RC->BaseAddr =3D RegBase; + RC->TcuAddr =3D RegBase + TCU_OFFSET; + RC->HBAddr =3D RegBase + HB_CSR_OFFSET; + RC->SerdesAddr =3D RegBase + SERDES_CSR_OFFSET; + RC->MmcfgAddr =3D RegBase + MMCONFIG_OFFSET; + RC->MmioAddr =3D MmioBase; + RC->MmioSize =3D MmioSize; + RC->Mmio32Addr =3D Mmio32Base; + RC->Mmio32Size =3D Mmio32Size; + RC->IoAddr =3D Mmio32Base + Mmio32Size - IO_SPACE; + + RC->Type =3D (RC->ID < MAX_RCA) ? RCA : RCB; + RC->MaxPcieController =3D (RC->Type =3D=3D RCB) ? MAX_PCIE_B : MAX_PCIE_= A; + + BoardPcieParseRCParams (RC); + + for (PcieIndex =3D 0; PcieIndex < RC->MaxPcieController; PcieIndex++) { + RC->Pcie[PcieIndex].ID =3D PcieIndex; + RC->Pcie[PcieIndex].CsrAddr =3D RC->BaseAddr + PCIE0_CSR_OFFSET + Pcie= Index*0x10000; + RC->Pcie[PcieIndex].SnpsRamAddr =3D RC->Pcie[PcieIndex].CsrAddr + SNPS= RAM_OFFSET; + RC->Pcie[PcieIndex].DevNum =3D PcieIndex + 1; + } + + DEBUG_PCIE_INFO ( + " + S%d - RC%a%d, MMCfgAddr:0x%lx, MmioAddr:0x%lx, MmioSize:0x%lx, Mmi= o32Addr:0x%lx, Mmio32Size:0x%lx, Enabled:%a\n", + RC->Socket, + (RC->Type =3D=3D RCA) ? "A" : "B", + RC->ID, + RC->MmcfgAddr, + RC->MmioAddr, + RC->MmioSize, + RC->Mmio32Addr, + RC->Mmio32Size, + (RC->Active) ? "Y" : "N" + ); + DEBUG_PCIE_INFO (" + DevMapLow/High: 0x%x/0x%x\n", RC->DevMapLow, RC->= DevMapHigh); + for (PcieIndex =3D 0; PcieIndex < RC->MaxPcieController; PcieIndex++) { + DEBUG_PCIE_INFO ( + " + 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 =3D (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 =3D GEN3_EQ_FB_MODE (Val, 0x1); + Val =3D GEN3_EQ_PRESET_VEC (Val, 0x3FF); + Val =3D 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 =3D (VOID *)(RC->MmcfgAddr + (RC->Pcie[PcieIndex].DevNum << 15))= ; + + // Bring to legacy mode + Ac01PcieCfgIn32 (CfgAddr + GEN3_RELATED_OFF, &Val); + Val =3D RATE_SHADOW_SEL_SET (Val, 0); + Ac01PcieCfgOut32 (CfgAddr + GEN3_RELATED_OFF, Val); + Val =3D EQ_PHASE_2_3_SET (Val, 0); + Val =3D RXEQ_REGRDLESS_SET (Val, 1); + Ac01PcieCfgOut32 (CfgAddr + GEN3_RELATED_OFF, Val); + + // Generate SPCIE capability address + SpcieBaseAddr =3D (VOID *)PcieCheckCap (RC, PcieIndex, 0x1, SPCIE_CAP_ID= ); + if (SpcieBaseAddr =3D=3D 0) { + DEBUG_PCIE_ERR ( + "PCIE%d.%d: Cannot get SPCIE capability address\n", + RC->ID, + PcieIndex + ); + return; + } + + for (Idx=3D0; Idx < RC->Pcie[PcieIndex].MaxWidth/2; Idx++) { + // Program Preset to Gen3 EQ Lane Control + Ac01PcieCfgIn32 (SpcieBaseAddr + CAP_OFF_0C + Idx*4, &Val); + Val =3D DSP_TX_PRESET0_SET (Val, 0x7); + Val =3D 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 =3D (VOID *)(RC->MmcfgAddr + (RC->Pcie[PcieIndex].DevNum << 15))= ; + + // Bring to legacy mode + Ac01PcieCfgIn32 (CfgAddr + GEN3_RELATED_OFF, &Val); + Val =3D RATE_SHADOW_SEL_SET (Val, 1); + Ac01PcieCfgOut32 (CfgAddr + GEN3_RELATED_OFF, Val); + Val =3D EQ_PHASE_2_3_SET (Val, 0); + Val =3D RXEQ_REGRDLESS_SET (Val, 1); + Ac01PcieCfgOut32 (CfgAddr + GEN3_RELATED_OFF, Val); + + // Generate the PL16 capability address + Pl16BaseAddr =3D (VOID *)PcieCheckCap (RC, PcieIndex, 0x1, PL16_CAP_ID); + if (Pl16BaseAddr =3D=3D 0) { + DEBUG_PCIE_ERR ( + "PCIE%d.%d: Cannot get PL16 capability address\n", + RC->ID, + PcieIndex + ); + return; + } + + // Generate the SPCIE capability address + SpcieBaseAddr =3D (VOID *)PcieCheckCap (RC, PcieIndex, 0x1, SPCIE_CAP_ID= ); + if (SpcieBaseAddr =3D=3D 0) { + DEBUG_PCIE_ERR ( + "PCIE%d.%d: Cannot get SPICE capability address\n", + RC->ID, + PcieIndex + ); + return; + } + + // Configure downstream Gen4 Tx preset + if (RC->PresetGen4[PcieIndex] =3D=3D PRESET_INVALID) { + Preset =3D 0x57; // Default Gen4 preset + } else { + Preset =3D RC->PresetGen4[PcieIndex]; + } + + LinkWidth =3D RC->Pcie[PcieIndex].MaxWidth; + if (LinkWidth =3D=3D 0x2) { + Ac01PcieCfgIn32 (Pl16BaseAddr + PL16G_CAP_OFF_20H_REG_OFF, &Val); + Val =3D DSP_16G_RXTX_PRESET0_SET (Val, Preset); + Val =3D DSP_16G_RXTX_PRESET1_SET (Val, Preset); + Ac01PcieCfgOut32 (Pl16BaseAddr + PL16G_CAP_OFF_20H_REG_OFF, Val); + } else { + for (i =3D 0; i < LinkWidth/4; i++) { + Ac01PcieCfgIn32 (Pl16BaseAddr + PL16G_CAP_OFF_20H_REG_OFF + i*4, &Va= l); + Val =3D DSP_16G_RXTX_PRESET0_SET (Val, Preset); + Val =3D DSP_16G_RXTX_PRESET1_SET (Val, Preset); + Val =3D DSP_16G_RXTX_PRESET2_SET (Val, Preset); + Val =3D DSP_16G_RXTX_PRESET3_SET (Val, Preset); + Ac01PcieCfgOut32 (Pl16BaseAddr + PL16G_CAP_OFF_20H_REG_OFF + i*4, Va= l); + } + } + + // Configure Gen3 preset + for (i =3D 0; i < LinkWidth/2; i++) { + Ac01PcieCfgIn32 (SpcieBaseAddr + CAP_OFF_0C + i*4, &Val); + Val =3D DSP_TX_PRESET0_SET (Val, 0x7); + Val =3D 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 =3D GetFirstGuidHob (&gPlatformHobGuid); + PlatformHob =3D (PLATFORM_INFO_HOB *)GET_GUID_HOB_DATA (Hob); + if ((PlatformHob->ScuProductId[0] & 0xff) =3D=3D 0x01) { + if (AsciiStrCmp ((CONST CHAR8 *)PlatformHob->CpuVer, "A0") =3D=3D 0) { + return ((RC->Type =3D=3D RCB)||(PcieIndex > 0)) ? TRUE : FALSE; + } + } + + return FALSE; +} + +/** + Setup and initialize the AC01 PCIe Root Complex and underneath PCIe con= trollers + + @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 =3D { 0 }; + PHY_PLAT_RESOURCE PhyPlatResource =3D { 0 }; + INTN Ret; + UINT16 NextExtendedCapabilityOff; + UINT32 VsecVal; + + DEBUG_PCIE_INFO ("Initializing Socket%d RC%d\n", RC->Socket, RC->ID); + + if (ReInit =3D=3D 0) { + // Initialize SERDES + ZeroMem (&PhyCtx, sizeof (PhyCtx)); + PhyCtx.SdsAddr =3D RC->SerdesAddr; + PhyCtx.PcieCtrlInfo |=3D ((RC->Socket & 0x1) << 2); + PhyCtx.PcieCtrlInfo |=3D ((RC->ID & 0x7) << 4); + PhyCtx.PcieCtrlInfo |=3D 0xF << 8; + PhyPlatResource.MmioRd =3D Ac01PcieMmioRd; + PhyPlatResource.MmioWr =3D Ac01PcieMmioWr; + PhyPlatResource.UsDelay =3D Ac01PcieDelay; + PhyPlatResource.Puts =3D Ac01PciePuts; + PhyPlatResource.PutInt =3D Ac01PciePutInt; + PhyPlatResource.PutHex =3D Ac01PciePutInt; + PhyPlatResource.PutHex64 =3D Ac01PciePutHex; + PhyPlatResource.DebugPrint =3D Ac01PcieDebugPrint; + PhyCtx.PhyPlatResource =3D &PhyPlatResource; + + Ret =3D SerdesInitClkrst (&PhyCtx); + if (Ret !=3D PHY_INIT_PASS) { + return -1; + } + } + + // Setup each controller + for (PcieIndex =3D 0; PcieIndex < RC->MaxPcieController; PcieIndex++) { + + if (ReInit =3D=3D 1) { + PcieIndex =3D ReInitPcieIndex; + } + + if (!RC->Pcie[PcieIndex].Active) { + continue; + } + + DEBUG_PCIE_INFO ("Initializing Controller %d\n", PcieIndex); + + CsrAddr =3D (VOID *)RC->Pcie[PcieIndex].CsrAddr; + SnpsRamAddr =3D (VOID *)RC->Pcie[PcieIndex].SnpsRamAddr; + CfgAddr =3D (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 =3D DWCPCIE_SET (Val, 1); + Ac01PcieCsrOut32 (CsrAddr + RESET, Val); + + // Delay 50ms to ensure controller finish its reset + MicroSecondDelay (50000); + } + + // Clear memory shutdown + Ac01PcieCsrIn32 (CsrAddr + RAMSDR, &Val); + Val =3D SD_SET (Val, 0); + Ac01PcieCsrOut32 (CsrAddr + RAMSDR, Val); + + // Poll till mem is ready + TimeOut =3D MEMRDY_TIMEOUT; + do { + Ac01PcieCsrIn32 (CsrAddr + MEMRDYR, &Val); + if (Val & 1) { + break; + } + + TimeOut--; + MicroSecondDelay (1); + } while (TimeOut > 0); + + if (TimeOut <=3D 0) { + DEBUG_PCIE_ERR ("- Pcie[%d] - Mem not ready\n", PcieIndex); + return -1; + } + + // Hold link training + Ac01PcieCsrIn32 (CsrAddr + LINKCTRL, &Val); + Val =3D LTSSMENB_SET (Val, 0); + Ac01PcieCsrOut32 (CsrAddr + LINKCTRL, Val); + + // Enable subsystem clock and release reset + Ac01PcieCsrIn32 (CsrAddr + CLOCK, &Val); + Val =3D AXIPIPE_SET (Val, 1); + Ac01PcieCsrOut32 (CsrAddr + CLOCK, Val); + Ac01PcieCsrIn32 (CsrAddr + RESET, &Val); + Val =3D 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 =3D PIPE_CLOCK_TIMEOUT; + do { + Ac01PcieCsrIn32 (CsrAddr + LINKSTAT, &Val); + if (!(Val & PHY_STATUS_MASK)) { + break; + } + + TimeOut--; + MicroSecondDelay (1); + } while (TimeOut > 0); + + if (TimeOut <=3D 0) { + DEBUG_PCIE_ERR ("- Pcie[%d] - PIPE clock is not stable\n", PcieIndex= ); + return -1; + } + + // Start PERST pulse + BoardPcieAssertPerst (RC, PcieIndex, 0, TRUE); + + // Allow programming to config space + Ac01PcieCsrIn32 (CfgAddr + MISC_CONTROL_1_OFF, &Val); + Val =3D 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 =3D SLOT_HPC_SET (Val, 1); + // Program the power limit + Val =3D SLOT_CAP_SLOT_POWER_LIMIT_VALUE_SET (Val, SLOT_POWER_LIMIT); + 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 controlle= r + // 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 =3D 0x10; // Margin to 0x0 (most conservative setting) + Ac01PcieCsrOut32 (SnpsRamAddr + TPSRAM_RMR, Val); + + // Generate the DLINK capability address + DlinkBaseAddr =3D (VOID *)(RC->MmcfgAddr + (RC->Pcie[PcieIndex].DevN= um << 15)); + NextExtendedCapabilityOff =3D 0x100; // This is the 1st extended cap= ability offset + do { + Ac01PcieCsrIn32 (DlinkBaseAddr + NextExtendedCapabilityOff, &Val); + if (Val =3D=3D 0xFFFFFFFF) { + DlinkBaseAddr =3D 0x0; + break; + } + if ((Val & 0xFFFF) =3D=3D DLINK_VENDOR_CAP_ID) { + Ac01PcieCsrIn32 (DlinkBaseAddr + NextExtendedCapabilityOff + 0x4= , &VsecVal); + if (VsecVal =3D=3D DLINK_VSEC) { + DlinkBaseAddr =3D DlinkBaseAddr + NextExtendedCapabilityOff; + break; + } + } + NextExtendedCapabilityOff =3D (Val >> 20); + } while (NextExtendedCapabilityOff !=3D 0); + + // Disable the scaled credit mode + if (DlinkBaseAddr !=3D 0x0) { + Val =3D 1; + Ac01PcieCsrOut32 (DlinkBaseAddr + DATA_LINK_FEATURE_CAP_OFF, Val); + Ac01PcieCsrIn32 (DlinkBaseAddr + DATA_LINK_FEATURE_CAP_OFF, &Val); + if (Val !=3D 1) { + DEBUG_PCIE_ERR ("- Pcie[%d] - Unable to disable scaled credit\n"= , PcieIndex); + return -1; + } + } else { + DEBUG_PCIE_ERR ("- Pcie[%d] - Unable to locate data link feature c= ap 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=3D0x40201020; + Ac01PcieCsrOut32 (CfgAddr + PORT_LOCIG_VC0_P_RX_Q_CTRL_OFF, Val); + } + + // Program DTI for ATS support + Ac01PcieCsrIn32 (CfgAddr + DTIM_CTRL0_OFF, &Val); + Val =3D 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 CAP_MAX_LINK_WIDTH of LINK_CAPABILITIES_REG + // + Ac01PcieCsrIn32 (CfgAddr + PORT_LINK_CTRL_OFF, &Val); + switch (RC->Pcie[PcieIndex].MaxWidth) { + case LNKW_X2: + Val =3D LINK_CAPABLE_SET (Val, LINK_CAPABLE_X2); + break; + + case LNKW_X4: + Val =3D LINK_CAPABLE_SET (Val, LINK_CAPABLE_X4); + break; + + case LNKW_X8: + Val =3D LINK_CAPABLE_SET (Val, LINK_CAPABLE_X8); + break; + + case LNKW_X16: + default: + Val =3D 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 =3D NUM_OF_LANES_SET (Val, NUM_OF_LANES_X2); + break; + + case LNKW_X4: + Val =3D NUM_OF_LANES_SET (Val, NUM_OF_LANES_X4); + break; + + case LNKW_X8: + Val =3D NUM_OF_LANES_SET (Val, NUM_OF_LANES_X8); + break; + + case LNKW_X16: + default: + Val =3D 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 =3D CAP_MAX_LINK_WIDTH_SET (Val, CAP_MAX_LINK_WIDTH_X2); + break; + + case LNKW_X4: + Val =3D CAP_MAX_LINK_WIDTH_SET (Val, CAP_MAX_LINK_WIDTH_X4); + break; + + case LNKW_X8: + Val =3D CAP_MAX_LINK_WIDTH_SET (Val, CAP_MAX_LINK_WIDTH_X8); + break; + + case LNKW_X16: + default: + Val =3D CAP_MAX_LINK_WIDTH_SET (Val, CAP_MAX_LINK_WIDTH_X16); + break; + } + + switch (RC->Pcie[PcieIndex].MaxGen) { + case SPEED_GEN1: + Val =3D CAP_MAX_LINK_SPEED_SET (Val, MAX_LINK_SPEED_25); + break; + + case SPEED_GEN2: + Val =3D CAP_MAX_LINK_SPEED_SET (Val, MAX_LINK_SPEED_50); + break; + + case SPEED_GEN3: + Val =3D CAP_MAX_LINK_SPEED_SET (Val, MAX_LINK_SPEED_80); + break; + + default: + Val =3D CAP_MAX_LINK_SPEED_SET (Val, MAX_LINK_SPEED_160); + break; + } + /* Enable ASPM Capability */ + Val =3D 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 =3D CAP_TARGET_LINK_SPEED_SET (Val, MAX_LINK_SPEED_25); + break; + + case SPEED_GEN2: + Val =3D CAP_TARGET_LINK_SPEED_SET (Val, MAX_LINK_SPEED_50); + break; + + case SPEED_GEN3: + Val =3D CAP_TARGET_LINK_SPEED_SET (Val, MAX_LINK_SPEED_80); + break; + + default: + Val =3D 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 =3D CX_FLT_MASK_VENMSG0_DROP_SET (Val, 0); + Val =3D CX_FLT_MASK_VENMSG1_DROP_SET (Val, 0); + Val =3D CX_FLT_MASK_DABORT_4UCPL_SET (Val, 0); + Ac01PcieCsrOut32 (CfgAddr + FILTER_MASK_2_OFF, Val); + Ac01PcieCsrIn32 (CfgAddr + AMBA_ORDERING_CTRL_OFF, &Val); + Val =3D 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 =3D 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 =3D INT_PIN_SET (Val, 1); + Ac01PcieCsrOut32 (CfgAddr + BRIDGE_CTRL_INT_PIN_INT_LINE_REG, Val); + Ac01PcieCsrIn32 (CsrAddr + IRQSEL, &Val); + Val =3D INTPIN_SET (Val, 1); + Ac01PcieCsrOut32 (CsrAddr + IRQSEL, Val); + + if (RC->Pcie[PcieIndex].MaxGen !=3D SPEED_GEN1) { + Ac01PcieConfigureEqualization (RC, PcieIndex); + if (RC->Pcie[PcieIndex].MaxGen =3D=3D SPEED_GEN3) { + Ac01PcieConfigurePresetGen3 (RC, PcieIndex); + } else if (RC->Pcie[PcieIndex].MaxGen =3D=3D SPEED_GEN4) { + Ac01PcieConfigurePresetGen4 (RC, PcieIndex); + } + } + + // Mask Completion Timeout + Ac01PcieCsrIn32 (CfgAddr + AMBA_LINK_TIMEOUT_OFF, &Val); + Val =3D LINK_TIMEOUT_PERIOD_DEFAULT_SET (Val, 1); + Ac01PcieCsrOut32 (CfgAddr + AMBA_LINK_TIMEOUT_OFF, Val); + Ac01PcieCsrIn32 (CfgAddr + UNCORR_ERR_MASK_OFF, &Val); + Val =3D CMPLT_TIMEOUT_ERR_MASK_SET (Val, 1); + // AER surprise link down error should be masked due to hotplug is ena= bled + // This event must be handled by Hotplug handler, instead of error han= dler + Val =3D 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 =3D REVISION_ID_SET (Val, 4); + Val =3D SUBCLASS_CODE_SET (Val, 4); + Val =3D 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 =3D VENDOR_ID_SET (Val, AMPERE_PCIE_VENDORID); + if (RCA =3D=3D RC->Type) { + Val =3D DEVICE_ID_SET (Val, AC01_PCIE_BRIDGE_DEVICEID_RCA + PcieInde= x); + } else { + Val =3D DEVICE_ID_SET (Val, AC01_PCIE_BRIDGE_DEVICEID_RCB + PcieInde= x); + } + Ac01PcieCsrOut32 (CfgAddr + TYPE1_DEV_ID_VEND_ID_REG, Val); + + // Enable common clock for downstream + Ac01PcieCsrIn32 (CfgAddr + LINK_CONTROL_LINK_STATUS_REG, &Val); + Val =3D CAP_SLOT_CLK_CONFIG_SET (Val, 1); + Val =3D CAP_COMMON_CLK_SET (Val, 1); + Ac01PcieCsrOut32 (CfgAddr + LINK_CONTROL_LINK_STATUS_REG, Val); + + // Match aux_clk to system + Ac01PcieCsrIn32 (CfgAddr + AUX_CLK_FREQ_OFF, &Val); + Val =3D AUX_CLK_FREQ_SET (Val, AUX_CLK_500MHZ); + Ac01PcieCsrOut32 (CfgAddr + AUX_CLK_FREQ_OFF, Val); + + // Assert PERST low to reset endpoint + BoardPcieAssertPerst (RC, PcieIndex, 0, FALSE); + + // Start link training + Ac01PcieCsrIn32 (CsrAddr + LINKCTRL, &Val); + Val =3D LTSSMENB_SET (Val, 1); + Ac01PcieCsrOut32 (CsrAddr + LINKCTRL, Val); + + // Complete the PERST pulse + BoardPcieAssertPerst (RC, PcieIndex, 0, TRUE); + + // Lock programming of config space + Ac01PcieCsrIn32 (CfgAddr + MISC_CONTROL_1_OFF, &Val); + Val =3D DBI_RO_WR_EN_SET (Val, 0); + Ac01PcieCsrOut32 (CfgAddr + MISC_CONTROL_1_OFF, Val); + + if (ReInit =3D=3D 1) { + return 0; + } + } + + // Program VendorID and DeviceId + if (!EFI_ERROR (MailboxMsgRegisterRead (RC->Socket, RC->HBAddr + HBPDVI= DR, &Val))) { + Val =3D PCIVENDID_SET (Val, AMPERE_PCIE_VENDORID); + if (RCA =3D=3D RC->Type) { + Val =3D PCIDEVID_SET (Val, AC01_HOST_BRIDGE_DEVICEID_RCA); + } else { + Val =3D PCIDEVID_SET (Val, AC01_HOST_BRIDGE_DEVICEID_RCB); + } + MailboxMsgRegisterWrite (RC->Socket, RC->HBAddr + HBPDVIDR, Val); + } + + return 0; +} + +BOOLEAN +PcieLinkUpCheck ( + IN AC01_PCIE *Pcie + ) +{ + VOID *CsrAddr; + UINT32 BlockEvent, LinkStat; + + CsrAddr =3D (VOID *)Pcie->CsrAddr; + + // Check if card present + // smlh_ltssm_state[13:8] =3D 0 + // phy_status[2] =3D 0 + // smlh_link_up[1] =3D 0 + // rdlh_link_up[0] =3D 0 + Ac01PcieCsrIn32 (CsrAddr + LINKSTAT, &LinkStat); + LinkStat =3D LinkStat & (SMLH_LTSSM_STATE_MASK | PHY_STATUS_MASK_BIT | + SMLH_LINK_UP_MASK_BIT | RDLH_LINK_UP_MASK_BIT); + if (LinkStat =3D=3D 0x0000) { + return FALSE; + } + + Ac01PcieCsrIn32 (CsrAddr + BLOCKEVENTSTAT, &BlockEvent); + Ac01PcieCsrIn32 (CsrAddr + LINKSTAT, &LinkStat); + + if (((BlockEvent & LINKUP_MASK) !=3D 0) + && (SMLH_LTSSM_STATE_GET(LinkStat) =3D=3D S_L0)) + { + DEBUG_PCIE_INFO ("%a Linkup\n", __FUNCTION__); + return TRUE; + } + + return FALSE; +} + +VOID +Ac01PcieCoreEndEnumeration ( + AC01_RC *RC + ) +{ + VOID *Reg; + UINTN Index; + UINT32 Val; + VOID *CfgAddr; + + if (RC =3D=3D NULL || !RC->Active) { + return; + } + + // Clear uncorrectable error during enumuration phase. Mainly completion= timeout. + for (Index =3D 0; Index < RC->MaxPcieController; Index++) { + if (!RC->Pcie[Index].Active) { + continue; + } + if (!PcieLinkUpCheck(&RC->Pcie[Index])) { + // If link down/disabled after enumeration, disable completed time o= ut + CfgAddr =3D (VOID *)(RC->MmcfgAddr + (RC->Pcie[Index].DevNum << 15))= ; + Ac01PcieCsrIn32 (CfgAddr + UNCORR_ERR_MASK_OFF, &Val); + Val =3D CMPLT_TIMEOUT_ERR_MASK_SET (Val, 1); + Ac01PcieCsrOut32 (CfgAddr + UNCORR_ERR_MASK_OFF, Val); + } + // Clear all errors + Reg =3D (VOID *)((UINT64)RC->MmcfgAddr + ((Index + 1) << 15) + UNCORR_= ERR_STATUS_OFF); + Ac01PcieCfgIn32 (Reg, &Val); + if (Val !=3D 0) { + // Clear error by writting + Ac01PcieCfgOut32 (Reg, Val); + } + } +} + +/** + Comparing current link status with the max capabilities of the link + + @param RC Pointer to AC01_RC structure + @param PcieIndex PCIe index + @param EpMaxWidth EP max link width + @param EpMaxGen EP max link speed + @retval -1: Link status do not match with link max capabil= ities + 1: Link capabilites are invalid + 0: Link status are correct +**/ +INT32 +Ac01PcieCoreLinkCheck ( + IN AC01_RC *RC, + IN INTN PcieIndex, + IN UINT8 EpMaxWidth, + IN UINT8 EpMaxGen + ) +{ + VOID *CsrAddr, *CfgAddr; + UINT32 Val, LinkStat; + UINT32 MaxWidth, MaxGen; + + CsrAddr =3D (VOID *)RC->Pcie[PcieIndex].CsrAddr; + CfgAddr =3D (VOID *)(RC->MmcfgAddr + (RC->Pcie[PcieIndex].DevNum << 15))= ; + + Ac01PcieCsrIn32 (CfgAddr + LINK_CAPABILITIES_REG, &Val); + if ((CAP_MAX_LINK_WIDTH_GET (Val) =3D=3D 0) || + (CAP_MAX_LINK_SPEED_GET (Val) =3D=3D 0)) { + DEBUG_PCIE_INFO ("\tPCIE%d.%d: Wrong RC capabilities\n", RC->ID, PcieI= ndex); + return LINK_CHECK_WRONG_PARAMETER; + } + + if ((EpMaxWidth =3D=3D 0) || (EpMaxGen =3D=3D 0)) { + DEBUG_PCIE_INFO ("\tPCIE%d.%d: Wrong EP capabilities\n", RC->ID, PcieI= ndex); + return LINK_CHECK_FAILED; + } + + // Compare RC and EP capabilities + if (CAP_MAX_LINK_WIDTH_GET (Val) > EpMaxWidth) { + MaxWidth =3D EpMaxWidth; + } else { + MaxWidth =3D CAP_MAX_LINK_WIDTH_GET (Val); + } + + // Compare RC and EP capabilities + if (CAP_MAX_LINK_SPEED_GET (Val) > EpMaxGen) { + MaxGen =3D EpMaxGen; + } else { + MaxGen =3D CAP_MAX_LINK_SPEED_GET (Val); + } + + Ac01PcieCsrIn32 (CsrAddr + LINKSTAT, &LinkStat); + Ac01PcieCsrIn32 (CfgAddr + LINK_CONTROL_LINK_STATUS_REG, &Val); + DEBUG_PCIE_INFO ( + "PCIE%d.%d: Link MaxWidth %d MaxGen %d, LINKSTAT 0x%x", + RC->ID, + PcieIndex, + MaxWidth, + MaxGen, + LinkStat + ); + + // Checking all conditions of the link + // If one of them is not sastified, return link up fail + if ((CAP_NEGO_LINK_WIDTH_GET (Val) !=3D MaxWidth) || + (CAP_LINK_SPEED_GET (Val) !=3D MaxGen) || + (RDLH_SMLH_LINKUP_STATUS_GET (LinkStat) !=3D (SMLH_LINK_UP_MASK_BIT = | RDLH_LINK_UP_MASK_BIT))) + { + DEBUG_PCIE_INFO ("\tLinkCheck FAILED\n"); + return LINK_CHECK_FAILED; + } + + DEBUG_PCIE_INFO ("\tLinkCheck SUCCESS\n"); + return LINK_CHECK_SUCCESS; +} + +INT32 +Ac01PFAEnableAll ( + IN AC01_RC *RC, + IN INTN PcieIndex, + IN INTN PFAMode + ) +{ + VOID *RasDesVSecBase; + VOID *CfgAddr; + UINT8 ErrCode, ErrGrpNum; + UINT32 Val; + INT32 Ret =3D LINK_CHECK_SUCCESS; + + UINT32 ErrCtrlCfg[MAX_NUM_ERROR_CODE] =3D { + 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, 0x008, 0x009, = 0x00A, // Per Lane + 0x105, 0x106, 0x107, 0x108, 0x109, 0x10A, + 0x200, 0x201, 0x202, 0x203, 0x204, 0x205, 0x206, 0x207, + 0x300, 0x301, 0x302, 0x303, 0x304, 0x305, + 0x400, 0x401, = // Per Lane + 0x500, 0x501, 0x502, 0x503, 0x504, 0x505, 0x506, 0x507, 0x508, 0x509, = 0x50A, 0x50B, 0x50C, 0x50D + }; + + CfgAddr =3D (VOID *)(RC->MmcfgAddr + (RC->Pcie[PcieIndex].DevNum << 15))= ; + + // Allow programming to config space + Ac01PcieCsrIn32 (CfgAddr + MISC_CONTROL_1_OFF, &Val); + Val =3D DBI_RO_WR_EN_SET (Val, 1); + Ac01PcieCsrOut32 (CfgAddr + MISC_CONTROL_1_OFF, Val); + + // Generate the RAS DES capability address + // RAS_DES_CAP_ID =3D 0xB + RasDesVSecBase =3D (VOID *)PcieCheckCap (RC, PcieIndex, 0x1, RAS_DES_CAP= _ID); + if (RasDesVSecBase =3D=3D 0) { + DEBUG_PCIE_INFO ("PCIE%d.%d: Cannot get RAS DES capability address\n",= RC->ID, PcieIndex); + return LINK_CHECK_WRONG_PARAMETER; + } + + if (PFAMode =3D=3D PFA_REG_ENABLE) { + // PFA Counters Enable + Ac01PcieCsrIn32 (RasDesVSecBase + EVENT_COUNTER_CONTROL_REG_OFF, &Val)= ; + Val =3D ECCR_EVENT_COUNTER_ENABLE_SET (Val, 0x7); + Val =3D ECCR_EVENT_COUNTER_CLEAR_SET (Val, 0); + Ac01PcieCsrOut32 (RasDesVSecBase + EVENT_COUNTER_CONTROL_REG_OFF, Val)= ; + } else if (PFAMode =3D=3D PFA_REG_CLEAR) { + // PFA Counters Clear + Ac01PcieCsrIn32 (RasDesVSecBase + EVENT_COUNTER_CONTROL_REG_OFF, &Val)= ; + Val =3D ECCR_EVENT_COUNTER_ENABLE_SET (Val, 0); + Val =3D ECCR_EVENT_COUNTER_CLEAR_SET (Val, 0x3); + Ac01PcieCsrOut32 (RasDesVSecBase + EVENT_COUNTER_CONTROL_REG_OFF, Val)= ; + } else { + // PFA Counters Read + for (ErrCode =3D 0; ErrCode < MAX_NUM_ERROR_CODE; ErrCode++) { + ErrGrpNum =3D (ErrCtrlCfg[ErrCode] & 0xF00) >> 8; + // Skipping per lane group + // Checking common lane group because AER error are included in comm= on group only + if ((ErrGrpNum !=3D 0) && (ErrGrpNum !=3D 4)) { + Ac01PcieCsrIn32 (RasDesVSecBase + EVENT_COUNTER_CONTROL_REG_OFF, &= Val); + if (RC->Type =3D=3D RCA) { // RCA - 4 PCIe controller per port, 1 = controller in charge of 4 lanes + Val =3D ECCR_LANE_SEL_SET (Val, PcieIndex*4); + } else { // RCB - 8 PCIe controller per port, 1 controller in char= ge of 2 lanes + Val =3D ECCR_LANE_SEL_SET (Val, PcieIndex*2); + } + Val =3D ECCR_GROUP_EVENT_SEL_SET (Val, ErrCtrlCfg[ErrCode]); + Ac01PcieCsrOut32 (RasDesVSecBase + EVENT_COUNTER_CONTROL_REG_OFF, = Val); + + // After setting Counter Control reg + // This delay just to make sure Counter Data reg is update with ne= w value + MicroSecondDelay (1); + Ac01PcieCsrIn32 (RasDesVSecBase + EVENT_COUNTER_DATA_REG_OFF, &Val= ); + if (Val !=3D 0) { + Ret =3D LINK_CHECK_FAILED; + DEBUG_PCIE_INFO ( + "\tS%d RC%d RP%d \t%s: %d \tGROUP:%d-EVENT:%d\n", + RC->Socket, + RC->ID, + PcieIndex, + Val, + ((ErrCtrlCfg[ErrCode] & 0xF00) >> 8), // Group + (ErrCtrlCfg[ErrCode] & 0x0FF) // Event + ); + } + } + } + } + + // Disable programming to config space + Ac01PcieCsrIn32 (CfgAddr + MISC_CONTROL_1_OFF, &Val); + Val =3D DBI_RO_WR_EN_SET (Val, 0); + Ac01PcieCsrOut32 (CfgAddr + MISC_CONTROL_1_OFF, Val); + + return Ret; +} + +/** + Get link capabilities link width and speed of endpoint + + @param RC[in] Pointer to AC01_RC structure + @param PcieIndex[in] PCIe controller index + @param EpMaxWidth[out] EP max link width + @param EpMaxGen[out] EP max link speed +**/ +VOID +Ac01PcieCoreGetEndpointInfo ( + IN AC01_RC *RC, + IN INTN PcieIndex, + OUT UINT8 *EpMaxWidth, + OUT UINT8 *EpMaxGen + ) +{ + VOID *PcieCapBaseAddr, *EpCfgAddr; + VOID *RcCfgAddr; + UINT32 Val, RestoreVal; + UINTN TimeOut; + + RcCfgAddr =3D (VOID *)(RC->MmcfgAddr + (RC->Pcie[PcieIndex].DevNum << 15= )); + + // Allow programming to config space + Ac01PcieCsrIn32 (RcCfgAddr + MISC_CONTROL_1_OFF, &Val); + Val =3D DBI_RO_WR_EN_SET (Val, 1); + Ac01PcieCsrOut32 (RcCfgAddr + MISC_CONTROL_1_OFF, Val); + + Ac01PcieCsrIn32 (RcCfgAddr + SEC_LAT_TIMER_SUB_BUS_SEC_BUS_PRI_BUS_REG, = &Val); + RestoreVal =3D Val; + Val =3D SUB_BUS_SET (Val, DEFAULT_SUB_BUS); /* Set DEFAULT_S= UB_BUS to Subordinate bus */ + Val =3D SEC_BUS_SET (Val, RC->Pcie[PcieIndex].DevNum); /* Set RC->Pcie[= PcieIndex].DevNum to Secondary bus */ + Val =3D PRIM_BUS_SET (Val, 0x0); /* Set 0x0 to Pr= imary bus */ + Ac01PcieCsrOut32 (RcCfgAddr + SEC_LAT_TIMER_SUB_BUS_SEC_BUS_PRI_BUS_REG,= Val); + EpCfgAddr =3D (VOID *)(RC->MmcfgAddr + (RC->Pcie[PcieIndex].DevNum << 20= )); /* Bus 1, dev 0, func 0 */ + + // Loop read EpCfgAddr value until got valid value or + // reach to timeout EP_LINKUP_TIMEOUT (or more depend on card) + TimeOut =3D EP_LINKUP_TIMEOUT; + do { + Ac01PcieCsrIn32 (EpCfgAddr, &Val); + if (Val !=3D 0xFFFF0001 && Val !=3D 0xFFFFFFFF) { + break; + } + MicroSecondDelay (LINK_WAIT_INTERVAL_US); + TimeOut -=3D LINK_WAIT_INTERVAL_US; + } while (TimeOut > 0); + + Ac01PcieCsrIn32 (EpCfgAddr, &Val); + + // Check whether EP config space is accessible or not + if (Val =3D=3D 0xFFFFFFFF) { + *EpMaxWidth =3D 0; // Invalid Width + *EpMaxGen =3D 0; // Invalid Speed + DEBUG_PCIE_INFO ("PCIE%d.%d Cannot access EP config space!\n", RC->ID,= PcieIndex); + } else { + PcieCapBaseAddr =3D (VOID *)PcieCheckCap (RC, PcieIndex, 0x0, CAP_ID); + if (PcieCapBaseAddr =3D=3D 0) { + *EpMaxWidth =3D 0; // Invalid Width + *EpMaxGen =3D 0; // Invalid Speed + DEBUG_PCIE_INFO ( + "PCIE%d.%d Cannot get PCIe capability extended address!\n", + RC->ID, + PcieIndex + ); + } else { + Ac01PcieCsrIn32 (PcieCapBaseAddr + LINK_CAPABILITIES_REG_OFF, &Val); + *EpMaxWidth =3D (Val >> 4) & 0x3F; + *EpMaxGen =3D Val & 0xF; + DEBUG_PCIE_INFO ( + "PCIE%d.%d EP MaxWidth %d EP MaxGen %d \n", RC->ID, + PcieIndex, + *EpMaxWidth, + *EpMaxGen + ); + + // From EP, enabling common clock for upstream + Ac01PcieCsrIn32 (PcieCapBaseAddr + LINK_CONTROL_LINK_STATUS_OFF, &Va= l); + Val =3D CAP_SLOT_CLK_CONFIG_SET (Val, 1); + Val =3D CAP_COMMON_CLK_SET (Val, 1); + Ac01PcieCsrOut32 (PcieCapBaseAddr + LINK_CONTROL_LINK_STATUS_OFF, Va= l); + } + } + + // Restore value in order to not affect enumeration process + Ac01PcieCsrOut32 (RcCfgAddr + SEC_LAT_TIMER_SUB_BUS_SEC_BUS_PRI_BUS_REG,= RestoreVal); + + // Disable programming to config space + Ac01PcieCsrIn32 (RcCfgAddr + MISC_CONTROL_1_OFF, &Val); + Val =3D DBI_RO_WR_EN_SET (Val, 0); + Ac01PcieCsrOut32 (RcCfgAddr + MISC_CONTROL_1_OFF, Val); +} + +/** + Check active PCIe controllers of RC, retrain or soft reset if needed + + @param RC[in] Pointer to AC01_RC structure + @param PcieIndex[in] PCIe controller index + + @retval -1: Link recovery had failed + 1: Link width and speed are not correct + 0: Link recovery succeed +**/ +INT32 +Ac01PcieCoreQoSLinkCheckRecovery ( + IN AC01_RC *RC, + IN INTN PcieIndex + ) +{ + VOID *CsrAddr; + INTN TimeOut; + INT32 NumberOfReset =3D MAX_REINIT; // Number of soft reset retry + UINT8 EpMaxWidth, EpMaxGen; + INT32 LinkStatusCheck, RasdesChecking; + + // PCIe controller is not active or Link is not up + // Nothing to be done + if ((!RC->Pcie[PcieIndex].Active) || (!RC->Pcie[PcieIndex].LinkUp)) { + return LINK_CHECK_WRONG_PARAMETER; + } + + do { + + if (RC->Pcie[PcieIndex].LinkUp) { + // Enable all of RASDES register to detect any training error + Ac01PFAEnableAll (RC, PcieIndex, PFA_REG_ENABLE); + + // Accessing Endpoint and checking current link capabilities + Ac01PcieCoreGetEndpointInfo (RC, PcieIndex, &EpMaxWidth, &EpMaxGen); + LinkStatusCheck =3D Ac01PcieCoreLinkCheck (RC, PcieIndex, EpMaxWidth= , EpMaxGen); + + // Delay to allow the link to perform internal operation and generat= e + // any error status update. This allows detection of any error obser= ved + // during initial link training. Possible evaluation time can be + // between 100ms to 200ms. + MicroSecondDelay (100000); + + // Check for error + RasdesChecking =3D Ac01PFAEnableAll (RC, PcieIndex, PFA_REG_READ); + + // Clear error counter + Ac01PFAEnableAll (RC, PcieIndex, PFA_REG_CLEAR); + + // If link check functions return passed, then breaking out + // else go to soft reset + if (LinkStatusCheck !=3D LINK_CHECK_FAILED && + RasdesChecking !=3D LINK_CHECK_FAILED && + PcieLinkUpCheck (&RC->Pcie[PcieIndex])) + { + return LINK_CHECK_SUCCESS; + } + + RC->Pcie[PcieIndex].LinkUp =3D FALSE; + } + + // Trigger controller soft reset + DEBUG_PCIE_INFO ("PCIE%d.%d Start link re-initialization..\n", RC->ID,= PcieIndex); + Ac01PcieCoreSetupRC (RC, 1, PcieIndex); + + // Poll until link up + // This checking for linkup status and + // give LTSSM state the time to transit from DECTECT state to L0 state + // Total delay are 100ms, smaller number of delay cannot always make s= ure + // the state transition is completed + TimeOut =3D LTSSM_TRANSITION_TIMEOUT; + CsrAddr =3D (VOID *)RC->Pcie[PcieIndex].CsrAddr; + do { + if (PcieLinkUpCheck (&RC->Pcie[PcieIndex])) { + DEBUG_PCIE_INFO ( + "\tPCIE%d.%d LinkStat is correct after soft reset, transition ti= me: %d\n", + RC->ID, + PcieIndex, + TimeOut + ); + RC->Pcie[PcieIndex].LinkUp =3D TRUE; + break; + } + + MicroSecondDelay (100); + TimeOut -=3D 100; + } while (TimeOut > 0); + + if (TimeOut <=3D 0) { + DEBUG_PCIE_INFO ("\tPCIE%d.%d LinkStat TIMEOUT after re-init\n", RC-= >ID, PcieIndex); + } else { + DEBUG_PCIE_INFO ("PCIE%d.%d Link re-initialization passed!\n", RC->I= D, PcieIndex); + } + + NumberOfReset--; + } while (NumberOfReset > 0); + + return LINK_CHECK_SUCCESS; +} + +VOID +Ac01PcieCoreUpdateLink ( + IN AC01_RC *RC, + OUT BOOLEAN *IsNextRoundNeeded, + OUT INT8 *FailedPciePtr, + OUT INT8 *FailedPcieCount + ) +{ + INTN PcieIndex; + AC01_PCIE *Pcie; + UINT32 i; + UINT32 Val; + VOID *CfgAddr; + + *IsNextRoundNeeded =3D FALSE; + *FailedPcieCount =3D 0; + for (i =3D 0; i < MAX_PCIE_B; i++) { + FailedPciePtr[i] =3D -1; + } + + if (!RC->Active) { + return; + } + + // Loop for all controllers + for (PcieIndex =3D 0; PcieIndex < RC->MaxPcieController; PcieIndex++) { + Pcie =3D &RC->Pcie[PcieIndex]; + CfgAddr =3D (VOID *)(RC->MmcfgAddr + (RC->Pcie[PcieIndex].DevNum << 15= )); + + if (Pcie->Active && !Pcie->LinkUp) { + if (PcieLinkUpCheck (Pcie)) { + Pcie->LinkUp =3D TRUE; + Ac01PcieCsrIn32 (CfgAddr + LINK_CONTROL_LINK_STATUS_REG, &Val); + DEBUG_PCIE_INFO ( + "%a S%d RC%d RP%d NEGO_LINK_WIDTH: 0x%x LINK_SPEED: 0x%x\n", + __FUNCTION__, + RC->Socket, + RC->ID, + PcieIndex, + CAP_NEGO_LINK_WIDTH_GET (Val), + CAP_LINK_SPEED_GET (Val) + ); + + // Doing link checking and recovery if needed + Ac01PcieCoreQoSLinkCheckRecovery (RC, PcieIndex); + + // Un-mask Completion Timeout + Ac01PcieCsrIn32 (CfgAddr + AMBA_LINK_TIMEOUT_OFF, &Val); + Val =3D LINK_TIMEOUT_PERIOD_DEFAULT_SET (Val, 32); + Ac01PcieCsrOut32 (CfgAddr + AMBA_LINK_TIMEOUT_OFF, Val); + Ac01PcieCsrIn32 (CfgAddr + UNCORR_ERR_MASK_OFF, &Val); + Val =3D CMPLT_TIMEOUT_ERR_MASK_SET (Val, 0); + Ac01PcieCsrOut32 (CfgAddr + UNCORR_ERR_MASK_OFF, Val); + } else { + *IsNextRoundNeeded =3D FALSE; + FailedPciePtr[*FailedPcieCount] =3D PcieIndex; + *FailedPcieCount +=3D 1; + } + } + } +} diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCoreLib.= c b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCoreLib.c new file mode 100644 index 000000000000..42a0f240763c --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCoreLib.c @@ -0,0 +1,556 @@ +/** @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 + +#include "PcieCore.h" +#include "PciePatchAcpi.h" + +STATIC UINT64 RCRegBase[AC01_MAX_PCIE_ROOT_COMPLEX] =3D { AC01_PCIE_REGIS= TER_BASE }; +STATIC UINT64 RCMmioBase[AC01_MAX_PCIE_ROOT_COMPLEX] =3D { AC01_PCIE_MMIO= _BASE }; +STATIC UINT64 RCMmioSize[AC01_MAX_PCIE_ROOT_COMPLEX] =3D {AC01_PCIE_MMIO_= SIZE}; +STATIC UINT64 RCMmio32Base[AC01_MAX_PCIE_ROOT_COMPLEX] =3D { AC01_PCIE_MM= IO32_BASE }; +STATIC UINT64 RCMmio32Base1P[AC01_MAX_PCIE_ROOT_COMPLEX] =3D { AC01_PCIE_= MMIO32_BASE_1P }; +STATIC UINT64 RCMmio32Size[AC01_MAX_PCIE_ROOT_COMPLEX] =3D {AC01_PCIE_MMI= O32_SIZE}; +STATIC UINT64 RCMmio32Size1P[AC01_MAX_PCIE_ROOT_COMPLEX] =3D {AC01_PCIE_M= MIO32_SIZE_1P}; +STATIC AC01_RC RCList[AC01_MAX_PCIE_ROOT_COMPLEX]; +STATIC INT8 PciList[AC01_MAX_PCIE_ROOT_COMPLEX]; + +STATIC +VOID +SerialPrint ( + IN CONST CHAR8 *FormatString, + ... + ) +{ + UINT8 Buf[64]; + VA_LIST Marker; + UINTN NumberOfPrinted; + + VA_START (Marker, FormatString); + NumberOfPrinted =3D AsciiVSPrint ((CHAR8 *)Buf, sizeof (Buf), FormatStri= ng, 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 f= rom 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 driv= er + // + return HBIndex * AC01_MAX_PCIE_ROOT_BRIDGE + RBIndex; +} + +/** + Prepare to start PCIE core BSP driver + + @retval EFI_SUCCESS The operation is successful. + @retval Others An error occurred. +**/ +EFI_STATUS +Ac01PcieSetup ( + VOID + ) +{ + AC01_RC *RC; + INTN RCIndex; + + ZeroMem (&RCList, sizeof (AC01_RC) * AC01_MAX_PCIE_ROOT_COMPLEX); + + // Adjust MMIO32 base address 1P vs 2P + if (!IsSlaveSocketPresent ()) { + CopyMem ((VOID *)&RCMmio32Base, (VOID *)&RCMmio32Base1P, sizeof (RCMmi= o32Base1P)); + CopyMem ((VOID *)&RCMmio32Size, (VOID *)&RCMmio32Size1P, sizeof (RCMmi= o32Size1P)); + } + + for (RCIndex =3D 0; RCIndex < AC01_MAX_PCIE_ROOT_COMPLEX; RCIndex++) { + RC =3D &RCList[RCIndex]; + RC->Socket =3D RCIndex / AC01_MAX_RCS_PER_SOCKET; + RC->ID =3D RCIndex % AC01_MAX_RCS_PER_SOCKET; + + Ac01PcieCoreBuildRCStruct ( + RC, + RCRegBase[RCIndex], + RCMmioBase[RCIndex], + RCMmioSize[RCIndex], + RCMmio32Base[RCIndex], + RCMmio32Size[RCIndex] + ); + } + + // Build the UEFI menu + BoardPcieScreenInitialize (RCList); + + return EFI_SUCCESS; +} + +/** + Get Total HostBridge. + + @retval UINTN Return Total HostBridge. +**/ +UINT8 +Ac01PcieGetTotalHBs ( + VOID + ) +{ + return AC01_MAX_PCIE_ROOT_COMPLEX; +} + +/** + Get Total RootBridge per HostBridge. + + @param[in] RCIndex Index to identify of Root Complex. + + @retval UINTN Return Total RootBridge per HostBridge= . +**/ +UINT8 +Ac01PcieGetTotalRBsPerHB ( + IN UINTN RCIndex + ) +{ + return AC01_MAX_PCIE_ROOT_BRIDGE; +} + +/** + Get RootBridge Attribute. + + @param[in] HBIndex Index to identify of PCIE Host bridge. + @param[in] RBIndex Index to identify of underneath PCIE R= oot 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[in] HBIndex Index to identify of PCIE Host bridge. + @param[in] RBIndex Index to identify of underneath PCIE R= oot bridge. + + @retval UINTN Return RootBridge Segment number. +**/ +UINTN +Ac01PcieGetRootBridgeSegmentNumber ( + IN UINTN HBIndex, + IN UINTN RBIndex + ) +{ + UINTN RCIndex; + AC01_RC *RC; + UINTN SegmentNumber; + + RCIndex =3D GetRCIndex (HBIndex, RBIndex); + RC =3D &RCList[RCIndex]; + SegmentNumber =3D RCIndex; + + // Get board specific overrides + BoardPcieGetRCSegmentNumber (RC, &SegmentNumber); + RC->Logical =3D SegmentNumber; + + return SegmentNumber; +} + +STATIC +VOID +SortPciList ( + INT8 *PciList + ) +{ + INT8 Idx1, Idx2; + + for (Idx2 =3D 0, Idx1 =3D 0; Idx2 < AC01_MAX_PCIE_ROOT_COMPLEX; Idx2++) = { + if (PciList[Idx2] < 0) { + continue; + } + PciList[Idx1] =3D PciList[Idx2]; + if (Idx1 !=3D Idx2) { + PciList[Idx2] =3D -1; + } + Idx1++; + } + + for (Idx2 =3D 0; Idx2 < Idx1; Idx2++) { + DEBUG_PCIE_INFO ( + " %a: PciList[%d]=3D%d TcuAddr=3D0x%llx\n", + __FUNCTION__, + Idx2, + PciList[Idx2], + RCList[PciList[Idx2]].TcuAddr + ); + } +} + +/** + Get RootBridge disable status. + + @param[in] HBIndex Index to identify of PCIE Host bridge. + @param[in] RBIndex Index to identify of underneath PCIE R= oot bridge. + + @retval BOOLEAN Return RootBridge disable status. +**/ +BOOLEAN +Ac01PcieCheckRootBridgeDisabled ( + IN UINTN HBIndex, + IN UINTN RBIndex + ) +{ + UINTN RCIndex; + INT8 Ret; + + RCIndex =3D HBIndex; + Ret =3D !RCList[RCIndex].Active; + if (Ret) { + PciList[HBIndex] =3D -1; + } else { + PciList[HBIndex] =3D HBIndex; + } + if (HBIndex =3D=3D (AC01_MAX_PCIE_ROOT_COMPLEX -1)) { + SortPciList (PciList); + if (!IsSlaveSocketPresent ()) { + AcpiPatchPciMem32 (PciList); + } + AcpiInstallMcfg (PciList); + AcpiInstallIort (PciList); + } + return Ret; +} + +/** + Initialize Host bridge + + @param[in] HBIndex Index to identify of PCIE Host bridge. + + @retval EFI_SUCCESS The operation is successful. + @retval Others An error occurred. +**/ +EFI_STATUS +Ac01PcieSetupHostBridge ( + IN UINTN HBIndex + ) +{ + return EFI_SUCCESS; +} + +/** + Initialize Root bridge + + @param[in] HBIndex Index to identify of PCIE Host bridge. + @param[in] RBIndex Index to identify of underneath PCIE R= oot bridge. + @param[in] RootBridgeInstance The pointer of instance of the Root br= idge IO. + + @retval EFI_SUCCESS The operation is successful. + @retval Others An error occurred. +**/ +EFI_STATUS +Ac01PcieSetupRootBridge ( + IN UINTN HBIndex, + IN UINTN RBIndex, + IN PCI_ROOT_BRIDGE *RootBridge + ) +{ + UINTN RCIndex; + AC01_RC *RC; + UINT32 Result; + + RCIndex =3D GetRCIndex (HBIndex, RBIndex); + RC =3D &RCList[RCIndex]; + if (!RC->Active) { + return EFI_DEVICE_ERROR; + } + + RC->RootBridge =3D (VOID *)RootBridge; + + // Initialize Root Complex and underneath controllers + Result =3D Ac01PcieCoreSetupRC (RC, 0, 0); + if (Result) { + DEBUG_PCIE_ERR ("RootComplex[%d]: Init Failed\n", RCIndex); + + goto Error; + } + + // Populate resource aperture + RootBridge->Bus.Base =3D 0x0; + RootBridge->Bus.Limit =3D 0xFF; + RootBridge->Io.Base =3D RC->IoAddr; + RootBridge->Io.Limit =3D RC->IoAddr + IO_SPACE - 1; + RootBridge->Mem.Base =3D RC->Mmio32Addr; + RootBridge->Mem.Limit =3D (RootBridge->Mem.Base) ? (RootBridge->Mem.Base= + RC->Mmio32Size - 1) : 0; + RootBridge->PMem.Base =3D RootBridge->Mem.Base; + RootBridge->PMem.Limit =3D RootBridge->Mem.Limit; + RootBridge->MemAbove4G.Base =3D MAX_UINT64; + RootBridge->MemAbove4G.Limit =3D 0x0; + RootBridge->PMemAbove4G.Base =3D RC->MmioAddr; + RootBridge->PMemAbove4G.Limit =3D (RootBridge->PMemAbove4G.Base) ? (Root= Bridge->PMemAbove4G.Base + RC->MmioSize - 1) : 0; + + DEBUG_PCIE_INFO (" + Bus: 0x%lx - 0x%lx\n", RootBridge->Bus.Base, Roo= tBridge->Bus.Limit); + DEBUG_PCIE_INFO (" + Io: 0x%lx - 0x%lx\n", RootBridge->Io.Base, Root= Bridge->Io.Limit); + DEBUG_PCIE_INFO (" + Mem: 0x%lx - 0x%lx\n", RootBridge->Mem.Base, Roo= tBridge->Mem.Limit); + DEBUG_PCIE_INFO (" + PMem: 0x%lx - 0x%lx\n", RootBridge->PMem.Base, Ro= otBridge->PMem.Limit); + DEBUG_PCIE_INFO (" + 4GMem: 0x%lx - 0x%lx\n", RootBridge->MemAbove4G.Ba= se, RootBridge->MemAbove4G.Limit); + DEBUG_PCIE_INFO (" + 4GPMem: 0x%lx - 0x%lx\n", RootBridge->PMemAbove4G.B= ase, RootBridge->PMemAbove4G.Limit); + + return EFI_SUCCESS; + +Error: + RC->Active =3D FALSE; + return EFI_DEVICE_ERROR; +} + +/** + Reads/Writes an PCI configuration register. + + @param[in] RootInstance Pointer to RootInstance structure. + @param[in] Address Address which want to read or write to= . + @param[in] Write Indicate that this is a read or write = command. + @param[in] Width Specify the width of the data. + @param[in, out] Data The buffer to hold the data. + + @retval EFI_SUCCESS The operation is successful. + @retval Others An error occurred. +**/ +EFI_STATUS +Ac01PcieConfigRW ( + IN VOID *RootInstance, + IN UINT64 Address, + IN BOOLEAN Write, + IN UINTN Width, + IN OUT VOID *Data + ) +{ + AC01_RC *RC =3D NULL; + VOID *CfgBase =3D NULL; + UINTN RCIndex; + UINT32 Reg; + UINT32 Segment; + + Segment =3D RShiftU64 (Address, 32) & 0xFFFF; + + for (RCIndex =3D 0; RCIndex < AC01_MAX_PCIE_ROOT_COMPLEX; RCIndex++) { + RC =3D &RCList[RCIndex]; + if (RC->RootBridge !=3D NULL) { + if (RC->RootBridge =3D=3D RootInstance + || (RootInstance =3D=3D NULL + && ((PCI_ROOT_BRIDGE *)RC->RootBridge)->Segment =3D=3D Segment= )) { + break; + } + } + } + + if ((RCIndex =3D=3D AC01_MAX_PCIE_ROOT_COMPLEX) || (RC =3D=3D NULL)) { + DEBUG_PCIE_ERR ("Can't find Root Bridge instance:%p\n", RootInstance); + return EFI_INVALID_PARAMETER; + } + + Reg =3D Address & 0xFFF; + + CfgBase =3D (VOID *)((UINT64)RC->MmcfgAddr + (Address & 0x0FFFF000)); + if (Write) { + switch (Width) { + case 1: + Ac01PcieCfgOut8 ((VOID *)(CfgBase + (Reg & (~(Width - 1)))), *((UINT= 8 *)Data)); + break; + + case 2: + Ac01PcieCfgOut16 ((VOID *)(CfgBase + (Reg & (~(Width - 1)))), *((UIN= T16 *)Data)); + break; + + case 4: + Ac01PcieCfgOut32 ((VOID *)(CfgBase + (Reg & (~(Width - 1)))), *((UIN= T32 *)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 =3D=3D 0xAE && (*((UINT16 *)Data)) =3D=3D 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 =3D FALSE, NextRoundNeeded; + UINT64 PrevTick, CurrTick, ElapsedCycle; + UINT64 TimerTicks64; + UINT8 ReInit; + INT8 FailedPciePtr[MAX_PCIE_B]; + INT8 FailedPcieCount; + + ReInit =3D 0; + +_link_polling: + NextRoundNeeded =3D 0; + // + // It is not guaranteed the timer service is ready prior to PCI Dxe. + // Calculate system ticks for link training. + // + TimerTicks64 =3D ArmGenericTimerGetTimerFreq (); /* 1 Second */ + PrevTick =3D ArmGenericTimerGetSystemCount (); + ElapsedCycle =3D 0; + + do { + // Update timer + CurrTick =3D ArmGenericTimerGetSystemCount (); + if (CurrTick < PrevTick) { + ElapsedCycle +=3D (UINT64)(~0x0ULL) - PrevTick; + PrevTick =3D 0; + } + ElapsedCycle +=3D (CurrTick - PrevTick); + PrevTick =3D CurrTick; + } while (ElapsedCycle < TimerTicks64); + + for (RCIndex =3D 0; RCIndex < AC01_MAX_PCIE_ROOT_COMPLEX; RCIndex++) { + Ac01PcieCoreUpdateLink (&RCList[RCIndex], &IsNextRoundNeeded, FailedPc= iePtr, &FailedPcieCount); + if (IsNextRoundNeeded) { + NextRoundNeeded =3D 1; + } + } + + if (NextRoundNeeded && ReInit < MAX_REINIT) { + // Timer is up. Give another chance to re-program controller + ReInit++; + for (RCIndex =3D 0; RCIndex < AC01_MAX_PCIE_ROOT_COMPLEX; RCIndex++) { + Ac01PcieCoreUpdateLink (&RCList[RCIndex], &IsNextRoundNeeded, Failed= PciePtr, &FailedPcieCount); + if (IsNextRoundNeeded) { + for (i =3D 0; i < FailedPcieCount; i++) { + PcieIndex =3D FailedPciePtr[i]; + if (PcieIndex =3D=3D -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[in] HBIndex Index to identify of PCIE Host bridge. + @param[in] RBIndex Index to identify of underneath PCIE R= oot bridge. + @param[in] Phase The phase of enumeration as informed f= rom 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 =3D GetRCIndex (HBIndex, RBIndex); + RC =3D &RCList[RCIndex]; + + switch (Phase) { + case EfiPciHostBridgeEndEnumeration: + Ac01PcieCoreEndEnumeration (RC); + break; + + case EfiPciHostBridgeBeginEnumeration: + /* 100ms that help fixing completion timeout issue */ + MicroSecondDelay (100000); + break; + + case EfiPciHostBridgeBeginBusAllocation: + case EfiPciHostBridgeEndBusAllocation: + case EfiPciHostBridgeBeginResourceAllocation: + case EfiPciHostBridgeAllocateResources: + case EfiPciHostBridgeSetResources: + case EfiPciHostBridgeFreeResources: + case EfiPciHostBridgeEndResourceAllocation: + case EfiMaxPciHostBridgeEnumerationPhase: + break; + } +} diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PciePatchAcp= i.c b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PciePatchAcpi.c new file mode 100644 index 000000000000..b15dea459a07 --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PciePatchAcpi.c @@ -0,0 +1,646 @@ +/** @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" + +#define ACPI_RESOURCE_NAME_ADDRESS16 0x88 +#define ACPI_RESOURCE_NAME_ADDRESS64 0x8A + +#define RCA_NUM_TBU_PMU 6 +#define RCB_NUM_TBU_PMU 10 + +// Required to be 1 to match the kernel quirk for ECAM +#define EFI_ACPI_MCFG_OEM_REVISION 1 + +STATIC UINT32 gTbuPmuIrqArray[] =3D { AC01_SMMU_TBU_PMU_IRQS }; +STATIC UINT32 gTcuPmuIrqArray[] =3D { AC01_SMMU_TCU_PMU_IRQS }; + +#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[] =3D { + { 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 *AcpiSdtProtocol; + EFI_STATUS Status; + UINTN Idx, Ix; + EFI_ACPI_DESCRIPTION_HEADER *Table; + UINTN TableKey; + UINTN TableIndex; + EFI_ACPI_HANDLE TableHandle, SegHandle; + CHAR8 Buffer[256]; + CHAR8 *KB, *B; + EFI_ACPI_DATA_TYPE DataType; + UINTN DataSize, Mem32; + RESOURCE *Rs; + QWordMemory *Qm; + UINT8 Segment; + + Status =3D gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (VOID **= )&AcpiSdtProtocol); + if (EFI_ERROR (Status)) { + DEBUG_PCIE_ERR ("Unable to locate ACPI table protocol Guid\n"); + return Status; + } + + TableIndex =3D 0; + Status =3D AcpiLocateTableBySignature ( + AcpiSdtProtocol, + EFI_ACPI_6_3_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATUR= E, + &TableIndex, + &Table, + &TableKey + ); + Status =3D AcpiSdtProtocol->OpenSdt (TableKey, &TableHandle); + if (EFI_ERROR (Status)) { + DEBUG_PCIE_ERR ("Unable to open DSDT table\n"); + return Status; + } + + for (Idx =3D 0; PciSegEnabled[Idx] !=3D -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", PciSegEnable= d[Idx]); + Status =3D AcpiSdtProtocol->FindPath (TableHandle, (VOID *)Buffer, &Se= gHandle); + if (EFI_ERROR (Status)) { + continue; + } + + for (Ix =3D 0; Ix < 3; Ix++) { + Status =3D AcpiSdtProtocol->GetOption ( + SegHandle, + Ix, + &DataType, + (VOID *)&B, + &DataSize + ); + KB =3D B; + if (EFI_ERROR (Status)) { + continue; + } + + if (Ix =3D=3D 0) { /* B[0] =3D=3D AML_NAME_OP */ + if (!((DataSize =3D=3D 1) && (DataType =3D=3D EFI_ACPI_DATA_TYPE_O= PCODE))) { + break; + } + } else if (Ix =3D=3D 1) { /* *B =3D=3D "RBUF" */ + if (!((DataSize =3D=3D 4) && (DataType =3D=3D EFI_ACPI_DATA_TYPE_N= AME_STRING))) { + break; + } + } else { /* Ix:2 11 42 07 0A 6E 88 ... */ + if (DataType !=3D EFI_ACPI_DATA_TYPE_CHILD) { + break; + } + + KB +=3D 5; /* Point to Resource type */ + Rs =3D (RESOURCE *)KB; + Mem32 =3D 0; + while ((Mem32 =3D=3D 0) && ((KB - B) < DataSize)) { + if (Rs->ResourceType =3D=3D ACPI_RESOURCE_NAME_ADDRESS16) { + KB +=3D (Rs->ResourceSize + 3); /* Type + Size */ + Rs =3D (RESOURCE *)KB; + } else if (Rs->ResourceType =3D=3D ACPI_RESOURCE_NAME_ADDRESS64)= { + + if (Rs->Attribute =3D=3D 0x00) { /* The first QWordMemory */ + Mem32 =3D 1; + Segment =3D PciSegEnabled[Idx] - 2; + Qm =3D (QWordMemory *)&(Rs->ResourcePtr); + *Qm =3D Qmem[Segment]; /* Physical segment */ + } + KB +=3D (Rs->ResourceSize + 3); /* Type + Size */ + Rs =3D (RESOURCE *)KB; + } + } + if (Mem32 !=3D 0) { + Status =3D AcpiSdtProtocol->SetOption ( + SegHandle, + Ix, + (VOID *)B, + DataSize + ); + } + } + } + + AcpiSdtProtocol->Close (SegHandle); + } + + AcpiSdtProtocol->Close (TableHandle); + AcpiUpdateChecksum ((UINT8 *)Table, Table->Length); + + return Status; +} + +VOID +ConstructMcfg ( + VOID *McfgPtr, + INT8 *PciSegEnabled, + UINT32 McfgCount + ) +{ + EFI_MCFG_TABLE_CONFIG McfgHeader =3D { + { + EFI_ACPI_6_1_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDR= ESS_DESCRIPTION_TABLE_SIGNATURE, + McfgCount, + 1, + 0x00, // Checksum will be updated at runtime + EFI_ACPI_OEM_ID, + EFI_ACPI_OEM_TABLE_ID, + EFI_ACPI_MCFG_OEM_REVISION, + EFI_ACPI_CREATOR_ID, + EFI_ACPI_CREATOR_REVISION + }, + 0x0000000000000000, // Reserved + }; + EFI_MCFG_CONFIG_STRUCTURE TMcfg =3D { + .ullBaseAddress =3D 0, + .usSegGroupNum =3D 0, + .ucStartBusNum =3D 0, + .ucEndBusNum =3D 255, + .Reserved2 =3D 0, + }; + UINT32 Idx; + VOID *TMcfgPtr =3D McfgPtr; + AC01_RC *Rc; + + CopyMem (TMcfgPtr, &McfgHeader, sizeof (EFI_MCFG_TABLE_CONFIG)); + TMcfgPtr +=3D sizeof (EFI_MCFG_TABLE_CONFIG); + for (Idx =3D 0; PciSegEnabled[Idx] !=3D -1; Idx++) { + Rc =3D GetRCList (PciSegEnabled[Idx]); /* Logical */ + TMcfg.ullBaseAddress =3D Rc->MmcfgAddr; + TMcfg.usSegGroupNum =3D Rc->Logical; + CopyMem (TMcfgPtr, &TMcfg, sizeof (EFI_MCFG_CONFIG_STRUCTURE)); + TMcfgPtr +=3D sizeof (EFI_MCFG_CONFIG_STRUCTURE); + } +} + +EFI_STATUS +EFIAPI +AcpiInstallMcfg ( + INT8 *PciSegEnabled + ) +{ + UINT32 RcCount, McfgCount; + EFI_ACPI_TABLE_PROTOCOL *AcpiSdtProtocol; + UINTN TableKey; + EFI_STATUS Status; + VOID *McfgPtr; + + Status =3D gBS->LocateProtocol ( + &gEfiAcpiTableProtocolGuid, + NULL, + (VOID **)&AcpiSdtProtocol + ); + if (EFI_ERROR (Status)) { + DEBUG_PCIE_ERR ("MCFG: Unable to locate ACPI table entry\n"); + return Status; + } + for (RcCount =3D 0; PciSegEnabled[RcCount] !=3D -1; RcCount++) { + } + McfgCount =3D sizeof (EFI_MCFG_TABLE_CONFIG) + sizeof (EFI_MCFG_CONFIG_S= TRUCTURE) * RcCount; + McfgPtr =3D AllocateZeroPool (McfgCount); + if (McfgPtr =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + ConstructMcfg (McfgPtr, PciSegEnabled, McfgCount); + Status =3D AcpiSdtProtocol->InstallAcpiTable ( + AcpiSdtProtocol, + McfgPtr, + McfgCount, + &TableKey + ); + if (EFI_ERROR (Status)) { + DEBUG_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 =3D { + .Header =3D __ACPI_HEADER ( + EFI_ACPI_6_0_IO_REMAPPING_TABLE_SIGNATURE, + AC01_IO_REMAPPING_STRUCTURE, + EFI_ACPI_IO_REMAPPING_TABLE_REVISION + ), + .NumNodes =3D (3 * RcCount) + SmmuPmuAgentCount, + .NodeOffset =3D sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE), + 0 + }; + + AC01_ITS_NODE TItsNode =3D { + .Node =3D { + { + EFI_ACPI_IORT_TYPE_ITS_GROUP, + sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE) + 4, + 0x0, + 0x0, + 0x0, + 0x0, + }, + .NumItsIdentifiers =3D 1, + }, + .ItsIdentifier =3D 1, + }; + + AC01_RC_NODE TRcNode =3D { + { + { + 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 =3D 0, + .MemoryAddressSize =3D 64, + }, + __AC01_ID_MAPPING (0x0, 0xffff, 0x0, SmmuNode, 0), + }; + + AC01_SMMU_NODE TSmmuNode =3D { + { + { + EFI_ACPI_IORT_TYPE_SMMUv3, + sizeof (AC01_SMMU_NODE), + 0x2, /* Revision */ + 0x0, + 0x2, /* Mapping Count */ + FIELD_OFFSET (AC01_SMMU_NODE, InterruptMsiMapping), + }, + .Base =3D 0, + EFI_ACPI_IORT_SMMUv3_FLAG_COHAC_OVERRIDE, + 0, + 0, + 0, + 0, + 0, + 0x0, + 0x0, + 0, // Proximity domain - need fill in + .DeviceIdMapping =3D 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 =3D { + { + 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[AC01_MAX_PCIE_ROOT_COMPLEX]; + VOID *TIortPtr =3D IortPtr, *SmmuPtr, *PmcgPtr; + UINT32 ItsOffset[AC01_MAX_PCIE_ROOT_COMPLEX]; + AC01_RC *Rc; + UINTN NumTbuPmu; + + TIort.Header.Length =3D HeaderCount; + CopyMem (TIortPtr, &TIort, sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE)); + TIortPtr +=3D sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE); + for (Idx =3D 0; Idx < RcCount; Idx++) { + ItsOffset[Idx] =3D TIortPtr - IortPtr; + TItsNode.ItsIdentifier =3D PciSegEnabled[Idx]; /* Physical */ + CopyMem (TIortPtr, &TItsNode, sizeof (AC01_ITS_NODE)); + TIortPtr +=3D sizeof (AC01_ITS_NODE); + } + + SmmuPtr =3D TIortPtr + RcCount * sizeof (AC01_RC_NODE); + PmcgPtr =3D SmmuPtr + RcCount * sizeof (AC01_SMMU_NODE); + for (Idx =3D 0; Idx < RcCount; Idx++) { + SmmuNodeOffset[Idx] =3D SmmuPtr - IortPtr; + Rc =3D GetRCList (PciSegEnabled[Idx]); /* Physical RC */ + TSmmuNode.Node.Base =3D Rc->TcuAddr; + TSmmuNode.InterruptMsiMapping.OutputBase =3D PciSegEnabled[Idx] << 16; + TSmmuNode.InterruptMsiMapping.OutputReference =3D ItsOffset[Idx]; + TSmmuNode.InterruptMsiMappingSingle.OutputBase =3D PciSegEnabled[Idx] = << 16; + TSmmuNode.InterruptMsiMappingSingle.OutputReference =3D ItsOffset[Idx]= ; + /* All RCs on master be assigned to node 0, while remote RCs be assign= ed to first remote node */ + TSmmuNode.Node.Flags =3D EFI_ACPI_IORT_SMMUv3_FLAG_PROXIMITY_DOMAIN; + TSmmuNode.Node.ProximityDomain =3D 0; + if ((Rc->TcuAddr & SLAVE_SOCKET_BASE_ADDRESS_OFFSET) !=3D 0) { + /* RC on remote socket */ + TSmmuNode.Node.Flags =3D EFI_ACPI_IORT_SMMUv3_FLAG_PROXIMITY_DOMAIN; + switch (CpuGetSubNumaMode ()) { + case SUBNUMA_MODE_MONOLITHIC: + TSmmuNode.Node.ProximityDomain +=3D MONOLITIC_NUM_OF_REGION; + break; + case SUBNUMA_MODE_HEMISPHERE: + TSmmuNode.Node.ProximityDomain +=3D HEMISPHERE_NUM_OF_REGION; + break; + case SUBNUMA_MODE_QUADRANT: + TSmmuNode.Node.ProximityDomain +=3D QUADRANT_NUM_OF_REGION; + break; + } + } + CopyMem (SmmuPtr, &TSmmuNode, sizeof (AC01_SMMU_NODE)); + SmmuPtr +=3D sizeof (AC01_SMMU_NODE); + + if (!SmmuPmuAgentCount) { + continue; + } + + /* Add PMCG nodes */ + if (Rc->Type =3D=3D RCA) { + NumTbuPmu =3D RCA_NUM_TBU_PMU; + } else { + NumTbuPmu =3D RCB_NUM_TBU_PMU; + } + for (Idx1 =3D 0; Idx1 < NumTbuPmu; Idx1++) { + TPmcgNode.Base =3D Rc->TcuAddr; + if (NumTbuPmu =3D=3D RCA_NUM_TBU_PMU) { + switch (Idx1) { + case 0: + TPmcgNode.Base +=3D 0x40000; + break; + + case 1: + TPmcgNode.Base +=3D 0x60000; + break; + + case 2: + TPmcgNode.Base +=3D 0xA0000; + break; + + case 3: + TPmcgNode.Base +=3D 0xE0000; + break; + + case 4: + TPmcgNode.Base +=3D 0x100000; + break; + + case 5: + TPmcgNode.Base +=3D 0x140000; + break; + } + } else { + switch (Idx1) { + case 0: + TPmcgNode.Base +=3D 0x40000; + break; + + case 1: + TPmcgNode.Base +=3D 0x60000; + break; + + case 2: + TPmcgNode.Base +=3D 0xA0000; + break; + + case 3: + TPmcgNode.Base +=3D 0xE0000; + break; + + case 4: + TPmcgNode.Base +=3D 0x120000; + break; + + case 5: + TPmcgNode.Base +=3D 0x160000; + break; + + case 6: + TPmcgNode.Base +=3D 0x180000; + break; + + case 7: + TPmcgNode.Base +=3D 0x1C0000; + break; + + case 8: + TPmcgNode.Base +=3D 0x200000; + break; + + case 9: + TPmcgNode.Base +=3D 0x240000; + break; + } + } + TPmcgNode.Page1Base =3D TPmcgNode.Base + 0x12000; + TPmcgNode.Base +=3D 0x2000; + TPmcgNode.NodeReference =3D SmmuNodeOffset[Idx]; + TPmcgNode.OverflowInterruptGsiv =3D gTbuPmuIrqArray[PciSegEnabled[Id= x]] + Idx1; + CopyMem (PmcgPtr, &TPmcgNode, sizeof (TPmcgNode)); + PmcgPtr +=3D sizeof (TPmcgNode); + } + + /* TCU PMCG */ + TPmcgNode.Base =3D Rc->TcuAddr; + TPmcgNode.Base +=3D 0x2000; + TPmcgNode.Page1Base =3D Rc->TcuAddr + 0x12000; + TPmcgNode.NodeReference =3D SmmuNodeOffset[Idx]; + TPmcgNode.OverflowInterruptGsiv =3D gTcuPmuIrqArray[PciSegEnabled[Idx]= ]; + CopyMem (PmcgPtr, &TPmcgNode, sizeof (TPmcgNode)); + PmcgPtr +=3D sizeof (TPmcgNode); + } + + for (Idx =3D 0; Idx < RcCount; Idx++) { + TRcNode.Node.PciSegmentNumber =3D GetRCList (PciSegEnabled[Idx])->Logi= cal; /* Logical */ + TRcNode.RcIdMapping.OutputReference =3D SmmuNodeOffset[Idx]; + CopyMem (TIortPtr, &TRcNode, sizeof (AC01_RC_NODE)); + TIortPtr +=3D sizeof (AC01_RC_NODE); + } +} + +EFI_STATUS +EFIAPI +AcpiInstallIort ( + INT8 *PciSegEnabled + ) +{ + EFI_STATUS Status; + EFI_ACPI_TABLE_PROTOCOL *AcpiSdtProtocol; + UINTN TableKey; + VOID *IortPtr; + BOOLEAN IsSmmuPmuEnabled; + UINT32 RcCount, SmmuPmuAgentCount, TotalCount; + + Status =3D gBS->LocateProtocol ( + &gEfiAcpiTableProtocolGuid, + NULL, + (VOID **)&AcpiSdtProtocol + ); + if (EFI_ERROR (Status)) { + DEBUG_PCIE_ERR ("IORT: Unable to locate ACPI table entry\n"); + return Status; + } + + for (RcCount =3D 0, SmmuPmuAgentCount =3D 0; PciSegEnabled[RcCount] !=3D= -1; RcCount++) { + if ((GetRCList (PciSegEnabled[RcCount]))->Type =3D=3D RCA) { + SmmuPmuAgentCount +=3D RCA_NUM_TBU_PMU; + } else { + SmmuPmuAgentCount +=3D RCB_NUM_TBU_PMU; + } + SmmuPmuAgentCount +=3D 1; /* Only 1 TCU */ + } + + BoardPcieCheckSmmuPmuEnabled (&IsSmmuPmuEnabled); + if (!IsSmmuPmuEnabled) { + SmmuPmuAgentCount =3D 0; + } + + TotalCount =3D 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 =3D AllocateZeroPool (TotalCount); + if (IortPtr =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + ConstructIort (IortPtr, RcCount, SmmuPmuAgentCount, TotalCount, PciSegEn= abled); + + Status =3D AcpiSdtProtocol->InstallAcpiTable ( + AcpiSdtProtocol, + IortPtr, + TotalCount, + &TableKey + ); + if (EFI_ERROR (Status)) { + DEBUG_PCIE_ERR ("IORT: Unable to install IORT table entry\n"); + } + FreePool (IortPtr); + return Status; +} --=20 2.17.1