From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=104.47.40.58; helo=nam03-co1-obe.outbound.protection.outlook.com; envelope-from=vabhav.sharma@nxp.com; receiver=edk2-devel@lists.01.org Received: from NAM03-CO1-obe.outbound.protection.outlook.com (mail-co1nam03on0058.outbound.protection.outlook.com [104.47.40.58]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 16A17222CB309 for ; Thu, 21 Dec 2017 22:45:41 -0800 (PST) Received: from BN3PR03CA0084.namprd03.prod.outlook.com (10.167.1.172) by CY4PR03MB2694.namprd03.prod.outlook.com (10.173.43.137) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.323.15; Fri, 22 Dec 2017 06:50:29 +0000 Received: from BN1AFFO11FD029.protection.gbl (2a01:111:f400:7c10::143) by BN3PR03CA0084.outlook.office365.com (2a01:111:e400:7a4d::44) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.20.345.14 via Frontend Transport; Fri, 22 Dec 2017 06:50:28 +0000 Authentication-Results: spf=fail (sender IP is 192.88.168.50) smtp.mailfrom=nxp.com; nxp.com; dkim=none (message not signed) header.d=none;nxp.com; dmarc=fail action=none header.from=nxp.com; Received-SPF: Fail (protection.outlook.com: domain of nxp.com does not designate 192.88.168.50 as permitted sender) receiver=protection.outlook.com; client-ip=192.88.168.50; helo=tx30smr01.am.freescale.net; Received: from tx30smr01.am.freescale.net (192.88.168.50) by BN1AFFO11FD029.mail.protection.outlook.com (10.58.52.184) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.20.302.6 via Frontend Transport; Fri, 22 Dec 2017 06:50:13 +0000 Received: from uefi-OptiPlex-790.ap.freescale.net ([10.232.132.56]) by tx30smr01.am.freescale.net (8.14.3/8.14.0) with ESMTP id vBM6oHF3022495; Thu, 21 Dec 2017 23:50:25 -0700 From: Vabhav To: , , , Date: Fri, 22 Dec 2017 00:18:28 +0530 Message-ID: <1513882109-14295-3-git-send-email-vabhav.sharma@nxp.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1513882109-14295-1-git-send-email-vabhav.sharma@nxp.com> References: <1513882109-14295-1-git-send-email-vabhav.sharma@nxp.com> X-EOPAttributedMessage: 0 X-Matching-Connectors: 131583990141151628; (91ab9b29-cfa4-454e-5278-08d120cd25b8); () X-Forefront-Antispam-Report: CIP:192.88.168.50; IPV:NLI; CTRY:US; EFV:NLI; SFV:NSPM; SFS:(10009020)(336005)(7966004)(396003)(376002)(346002)(39380400002)(39860400002)(2980300002)(1110001)(1109001)(339900001)(199004)(189003)(68736007)(966005)(8936002)(5660300001)(6306002)(356003)(77096006)(59450400001)(104016004)(47776003)(4326008)(53376002)(53946003)(305945005)(15188155005)(8676002)(2906002)(36756003)(498600001)(5890100001)(53936002)(85426001)(2201001)(316002)(16799955002)(97736004)(106466001)(51416003)(81166006)(2950100002)(50466002)(50226002)(105606002)(48376002)(551934003)(16200700003)(110136005)(76176011)(86362001)(81156014)(575784001)(16586007)(54906003)(8656006)(559001)(579004)(569006); DIR:OUT; SFP:1101; SCL:1; SRVR:CY4PR03MB2694; H:tx30smr01.am.freescale.net; FPR:; SPF:Fail; PTR:InfoDomainNonexistent; A:1; MX:1; LANG:en; X-Microsoft-Exchange-Diagnostics: 1; BN1AFFO11FD029; 1:b0RempyeWoHRYFazewSQ6zrysdMOk0/NIipOrfQfySVAzQ8lS31nZ65YMnSGhLSEUtxis4k4hq3AXfcXsdDNYTbqZ1cfDisf+69r+aVTK7jeEAOxPyf1oxNhzNRJOC4y MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: ea8767b5-9edf-4a46-e98c-08d5490840f4 X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(5600026)(4604075)(4534020)(4628075)(201703131517081)(2017052603307); SRVR:CY4PR03MB2694; X-Microsoft-Exchange-Diagnostics: 1; CY4PR03MB2694; 3:q64CZz0C1gRKaZ4N4vx/huuFxrU2MpMDEHrrXVRdeM6Eov5nsQiuxUnuJc1AOTav5NWvwK84vP1bDazE1+7NM/iSeEkax8oyJTVFG8qG/6vRlKLNS4AfNoNbijomCs+Sum+1W0QGdseHv+tSKm9iyo3TD5qjwtT6dfNkkfD5f8c6act6fm33jSuj7pTAYr7q9JbjeNFiNmveFLMpa5kXY70wPxkpyptVyO2XdGFZSx8o1fzDKj3N2497m8p84rROR9a52pMVbpIpjOJKYIZrYs1WajslyMxqS4Ef9H7V1KKixfhnUHZGveQqOBxDmKKmCJw38/EtUIoRATUrJJ4QSKZXCmAdZaGwyAzQ9SSnARo=; 25:jajnetQGT+2yeDg7M8s650b7XNYPtZs3k9WhpoRAiePq06Ex/M1fYJyAZUOJdkZpBPVSvNWHGiUKAIUKzrk5esZ80BJy3Sr0MK5e6lvf9BDmXDKk3hVickU3fCktpLGOXdnPuxJHMp6hzm4OHnxtQfd7wVIm5mQzB31518RPh+NSHqCb/cyOweYq/RxhND6y3vJY4mco1o2CQJ6noHbeXPGQPuB8DETQPTIOi4sQYXHjvHNajyR4HQox0YRS8cf4FMrPCL1HVRhzwIrrAT4I/MunoLqyVWPHTieZKKZU6cqSgTSvocaHXPivbywgzdq7ZEUdXfPKUicSkqH9BS4Oig== X-MS-TrafficTypeDiagnostic: CY4PR03MB2694: X-Microsoft-Exchange-Diagnostics: 1; CY4PR03MB2694; 31:+CCHsQNnmAuI9AGWz0PUHIe1dnUnJvwYkgz/mjnJ1YaHyBbJjNbnoljvJdvWcdXfo1orUOTAH453p3MjoWVGsIDl2v0sC2+1ncr+QG4bCWa/Fn4xcXsm0O78ob7ogwux0JxFfdiOPD5tRw6SwqjZQSvfd649ZK4HzKrn1Kpcb/uwNkFgC8K/6iyEyknluTmgSgA/YQlunLZFzH6g437RolDhGvuzWwZPs/J2e0xKsJA=; 4:grb9E19B/49mB5V7+XIcTZokUgywB4X8b+8TisSZqtD+uz2lI3sDrtTYfBox1RkqP3b1J9/6GePsIOyC9r8pRbkskXTcNuE2nJ9wOPw3oF/40ra0rj1rHD25kZ5HH+C5kTHdNngfv72jzoK628EnPykkN98bWu814Y2Sj24fjr2XSfdNGPzJnBjoH426ONq3uXvQ+c52pbanoNa82WevngTpyeqlVL48QRIQbdNAxD+wX118jNIQ7S/msTdgDPGrqEUeGP+Ry8Qqu+yWGXRLgvU7Q1kpfgrpS1x/FhCB5zBwWcyJaBST76EitsOkZWZXATF2fL546xemndW/guxuF64341hNWBhH0NU2TBc4KGM= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(185117386973197)(211171220733660); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(6095135)(2401047)(8121501046)(5005006)(3231023)(93006095)(93001095)(10201501046)(3002001)(6055026)(6096035)(20161123563025)(201703131430075)(201703131433075)(201703131441075)(201703131448075)(201703161259150)(20161123559100)(20161123556025)(20161123561025)(20161123565025)(201708071742011); SRVR:CY4PR03MB2694; BCL:0; PCL:0; RULEID:(100000803101)(100110400095)(400006); SRVR:CY4PR03MB2694; X-Forefront-PRVS: 05299D545B X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; CY4PR03MB2694; 23:awWRUih+v3e2aASsuZKePgF4JvtqII8X2xPRTTjoc?= =?us-ascii?Q?3JAwyDbc8xXgjJISr1GIS3e/H5ujrY4+VowqwZkwphIemw8brm1AGAb3TAOJ?= =?us-ascii?Q?LcgGXuMZXWy8WKKk8Eyb2Q1ppwy8C0klkAco8gUmruoNFKYdu5UzXuVH4Pmy?= =?us-ascii?Q?R6kGwx58R2QxwlTVhcaJqHN4qlI+SiLqL5HSIwpG2Mjsw8axB7d/rtjLnFUN?= =?us-ascii?Q?HKeTj3Tg8jTx6UJdswJRi+ik32KCEaOGFOo6xTTy4E09ULulC4A57NjZbChp?= =?us-ascii?Q?pVrqbOzMQUUDkfls+snSDSJ27Lb5pGd+EqqIt/ZRRfZy1qtmbj2stJyERFe2?= =?us-ascii?Q?nnzMRHxqxt3rMSmHlebYdnWcjaqSE2Bv25iVCbjITWP6Mt+Nl1iUugj/amIW?= =?us-ascii?Q?GjkyrtrKzCS8KnnArHuQD5BVZJjBH3kbrT1GC/AHBH5UQCbzwcBuWYMluwSX?= =?us-ascii?Q?f3sMyWTJ+rfelm8+oMtSPGBfJIQDAHnGV9t3CF5KhThNGytFOhRLKytp9iyW?= =?us-ascii?Q?3YZ2LKCKOuHxmH12eI5ye2SwdOl+FBr5pvKHB7tisVPHuGyn2/148gW6B3vJ?= =?us-ascii?Q?XjfAlgYZFy9ascYsHjncFOK+Mx/wY8kGRj3g20WSHt6x6DrvVMIhsCLvaLgJ?= =?us-ascii?Q?nenpMTcwmtjfYBHzzTa+yWopUbSYagjRR9Dv0qe39n2hNetLuPupUiUmeog+?= =?us-ascii?Q?llZplXYEG8N6DJaaSmRNSL8uKMFt1bPfML4ROg6d1vAfgCKzMmPqJcPc49/5?= =?us-ascii?Q?8XULVSGEy5AR9k2RITONmgKd12pSp3bjvk86hUIvQzPPxqmjGYgOP3DjabWq?= =?us-ascii?Q?vHMjMRBHXEd6BVVkGelV6+0kC+Bwz3K9MT3jEUhhCjX4KBfb9kkZ8/ogxy+L?= =?us-ascii?Q?2qx8i2Y2UU1eG8ILSzIIY/MVNWlLWG3Ro8K1N7Cjo1u7V8AuxH347jKyi3+i?= =?us-ascii?Q?ADavuasOK86bbefsndWyWrKyy8k+P7ORj+3I8VHnyGUTIxtTndL6Kt1phdH8?= =?us-ascii?Q?tJxxYRztY0veguGJdXy2w31Xiv4vWF+oUnNiTXxed8ssJWz6wtVEeznIKRlH?= =?us-ascii?Q?J4ScQ4HzJD/jmu2zEyX/UAOA/PHgCW8/bAIzttgcQFuRclcBiKw/C5/CYs93?= =?us-ascii?Q?VAGANmn72EcrE4t6v5dTGfYSbjaCp61KAPABcpEAx6l3NasU+wnKvBQDc/sj?= =?us-ascii?Q?7LBVNUs77ChV2JbmMdDyJSkmqlRzhSTu/JcMHEqpPIlUpK0c2xQG3eTWYCP1?= =?us-ascii?Q?xsOtv8ViIuMxGfiqdkGI6GjSFTaURKklWt1GQD3wSVpIJjuJePd4skkSzXYC?= =?us-ascii?Q?O0Sm0hz58YDGdbOLft8rPHJH6I/PknT2errsgKUFH/F/8BlH9ZHKr3Mq8joW?= =?us-ascii?Q?jRyPEWP2z6hdQvTUXvyp09mqxetsoiSdRak1WUPrW35oOep?= X-Microsoft-Exchange-Diagnostics: 1; CY4PR03MB2694; 6:P9GoRqmreM0DzR99ETyql79Pb9Kczxt98wjcWpgtOj7CLfZdsgJoHPLM7HE82qC4A+iXaaTSpNjNLvtdmZ9nEDADPKYFzQDEbf04442eZEwxksMCTauY9yFQvIdm+izabUN/D7PBLBR6f7gs3pI0ujQ3cjt+wFetgQcVSbqp9P/pJj9vHA3vdEhMe3ByD+tYNcFDSLcjGt3N/r6s9aepLP5cadaLXmc9YjzZrjXMNoj9MX4VQhCQcqORXcDxc1lTB1nVIha09H5LGjGdDOXojyvohM5LrTqjySV1C3x2a6AIh4+hTsLUQVX4WCZijM7JLyJtW81+D3NGTWl5oIyL0llfOx/f3aj6NRoFvhfGCWA=; 5:2pnf1F5rAlk7H4VG8cw3jjt49uxPX0oGBg+ymVqG7alDCBjJBmBmeefOwi8jeK0rs3CsWaCodsZhSjSph1tCxehOfJS8gKxsEWGY75idVcVdkmH7YAG7utAdz2ZbLcZP1YIBWlhsgJsfvlRcDNQY5BPh+7I4SyqM7iQqRWtTfiI=; 24:McQNdVoTvllyYzLK8YvnNrFeCEEAKbQ1mn9Qo/Z5QggSJr/wdgOT71UE0BS9D6oT9QjCuLn/aOAXEQoLTnYsSB+gMMSnkS38RpibJLVaewQ=; 7:fBFK6z6WWRdKh80q2qBmYIH4h/2sJ2hHwkdQueXARV9aq5CeSi1WTnPp32Coj6TsL0dgVcdenPAdrZinaEFSX9qwBgz5zRnTz6bDf7TXhAI63YbLrzjTto4boyP5fozKzW3ZXE11f/5maiZAwdeQouSR9o+LjX4lResFuJQgttOlB1OZyDyTox4U8MgPz02WJvi6A1O7/jNVjh1numlARcp+ycpN+hOAtejMR87GXVawQlqG0YqnhYboVFtPPyZb SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-MS-Exchange-CrossTenant-OriginalArrivalTime: 22 Dec 2017 06:50:13.9435 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: ea8767b5-9edf-4a46-e98c-08d5490840f4 X-MS-Exchange-CrossTenant-Id: 5afe0b00-7697-4969-b663-5eab37d5f47e X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=5afe0b00-7697-4969-b663-5eab37d5f47e; Ip=[192.88.168.50]; Helo=[tx30smr01.am.freescale.net] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY4PR03MB2694 Subject: [PATCH edk2-platforms 2/3] Platform/NXP : Add PCI Host Bridge Driver X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 22 Dec 2017 06:45:42 -0000 Content-Type: text/plain Added NXP PCI host bridge Dxe driver which install host bridge resource allocation protocol,root bridge IO protocol,Device path protocol and consumes MetronomeArch Protocol. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Vabhav --- .../Drivers/PciHostBridgeDxe/PciHostBridgeDxe.c | 967 ++++++++++++++++ .../Drivers/PciHostBridgeDxe/PciHostBridgeDxe.inf | 61 + .../NXP/Drivers/PciHostBridgeDxe/PciRootBridgeIo.c | 1193 ++++++++++++++++++++ Platform/NXP/Include/PciHostBridge.h | 466 ++++++++ Platform/NXP/Include/PciRootBridge.h | 674 +++++++++++ 5 files changed, 3361 insertions(+) create mode 100644 Platform/NXP/Drivers/PciHostBridgeDxe/PciHostBridgeDxe.c create mode 100644 Platform/NXP/Drivers/PciHostBridgeDxe/PciHostBridgeDxe.inf create mode 100644 Platform/NXP/Drivers/PciHostBridgeDxe/PciRootBridgeIo.c create mode 100644 Platform/NXP/Include/PciHostBridge.h create mode 100644 Platform/NXP/Include/PciRootBridge.h diff --git a/Platform/NXP/Drivers/PciHostBridgeDxe/PciHostBridgeDxe.c b/Platform/NXP/Drivers/PciHostBridgeDxe/PciHostBridgeDxe.c new file mode 100644 index 0000000..e9e43bc --- /dev/null +++ b/Platform/NXP/Drivers/PciHostBridgeDxe/PciHostBridgeDxe.c @@ -0,0 +1,967 @@ +/** PciHostBridgeDxe.c + Provides all functions of PCI Host Bridge Resource Allocation Protocol + + Based on PCI HosttBridge implementation in + ArmPlatformPkg/ArmJunoPkg/Drivers/PciHostBridgeDxe/PciHostBridgeResourceAllocation.c + + Copyright (c) 2011-2015, ARM Ltd. All rights reserved. + Copyright 2017 NXP + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +/** + Hard code: Root Bridge Number within the host bridge + Root Bridge's attribute + Root Bridge's device path + Root Bridge's resource aperture +**/ + +UINT64 PciMemBase[NUM_PCIE_CONTROLLER]; +UINT64 PciBaseAddr[NUM_PCIE_CONTROLLER]; + +PCI_HOST_BRIDGE_INSTANCE *HostBridge[NUM_PCIE_CONTROLLER]; +PCI_ROOT_BRIDGE_INSTANCE *PrivateData[NUM_PCIE_CONTROLLER]; + + +UINT64 RootBridgeAttribute[1][1] = { {EFI_PCI_HOST_BRIDGE_MEM64_DECODE | EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM} }; + +EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mEfiPciRootBridgeDevicePath = { + { + { ACPI_DEVICE_PATH, + ACPI_DP, + { + (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)), + (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8) + } + }, + EISA_PNP_ID (0x0A03), + 0 + }, + + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + END_DEVICE_PATH_LENGTH, + 0 + } + } +}; + +EFI_HANDLE mPciDriverImageHandle; + +PCI_HOST_BRIDGE_INSTANCE gPciHostBridgeInstanceTemplate = { + PCI_HOST_BRIDGE_SIGNATURE, // Signature + NULL, // HostBridgeHandle + NULL, // ImageHandle + {0, 0, 0, 0}, // RootBridgeNumber + NULL, // RootBridgeInstance + {NULL, NULL}, // Head + FALSE, // ResourceSubiteed + TRUE, // CanRestarted + { // ResAlloc + PciNotifyPhase, + PciGetNextRootBridge, + PciGetAllocAttributes, + PciStartBusEnumeration, + PciSetBusNumbers, + PciSubmitResources, + PciGetProposedResources, + PciPreprocessController + } +}; + +/** + This function checks whether PCIe is enabled or not + depending upon board serdes protocol map + + @param PcieNum PCIe number + + @return The PCIe number enabled in map + @return FALSE PCIe number is disabled in map +**/ +STATIC +BOOLEAN +IsPcieNumEnabled( + IN UINTN PcieNum + ) +{ + UINT64 SerDes1ProtocolMap; + + SerDes1ProtocolMap = 0x0; + + GetSerdesProtocolMaps (&SerDes1ProtocolMap); + + if (PcieNum < NUM_PCIE_CONTROLLER) { + return IsSerDesLaneProtocolConfigured (SerDes1ProtocolMap, (PcieNum+1)); + } + else { + DEBUG ((DEBUG_ERROR, "Device not supported\n")); + } + + return FALSE; +} + +STATIC +EFI_STATUS +AddMemorySpace ( + IN UINT64 BaseAddress, + IN UINTN Size + ) +{ + EFI_STATUS Status; + Status = gDS->AddMemorySpace ( + EfiGcdMemoryTypeMemoryMappedIo, + BaseAddress, + Size, + 0 + ); + + return Status; +} + +/** + Entry point of this driver + + @param ImageHandle Handle of driver image + @param SystemTable Point to EFI_SYSTEM_TABLE + + @retval EFI_ABORTED PCI host bridge not present + @retval EFI_OUT_OF_RESOURCES Can not allocate memory resource + @retval EFI_DEVICE_ERROR Can not install the protocol instance + @retval EFI_SUCCESS Success to initialize the Pci host bridge. +**/ +EFI_STATUS +EFIAPI +PciHostBridgeEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + UINTN Loop1; + + Status = EFI_OUT_OF_RESOURCES; // error + + for (Loop1 = 0; Loop1 < NUM_PCIE_CONTROLLER; Loop1++) { + PciMemBase[Loop1] = PcdGet64 (PcdPci1Mmio64Base) + + (PCI_MMIO64_BASE_DIFFERENCE * Loop1); + PciBaseAddr[Loop1] = PcdGet64 (PcdPciExp1BaseAddr) + + (PcdGet64 (PcdPciExp1BaseSize) * Loop1); + + DEBUG ((DEBUG_INFO, "PciMemBase %d : 0x%p\n", Loop1, PciMemBase[Loop1])); + DEBUG ((DEBUG_INFO, "PciBaseAddr %d : 0x%p\n", Loop1, PciBaseAddr[Loop1])); + } + + // + // Create Host Bridge Device Handle + // + for (Loop1 = 0; Loop1 < NUM_PCIE_CONTROLLER; Loop1++) { + if (!IsPcieNumEnabled (Loop1)) { + DEBUG ((DEBUG_ERROR, "PCIE%d is disabled\n", (Loop1 + 1))); + continue; + } + + DEBUG ((DEBUG_INFO, "PCIE%d is Enabled\n", (Loop1 + 1))); + + HostBridge[Loop1] = AllocateCopyPool (sizeof (PCI_HOST_BRIDGE_INSTANCE), &gPciHostBridgeInstanceTemplate); + if (HostBridge[Loop1] == NULL) { + DEBUG ((DEBUG_ERROR, "%a: Fail to Allocate HostBridge: %d\n", Loop1)); + continue; // Continue with other controllers + } + + HostBridge[Loop1]->RootBridgeNumber[Loop1] = TRUE; + InitializeListHead (&HostBridge[Loop1]->Head); + DEBUG ((DEBUG_INFO, "PCI : Install Protocol for HostBridge: %d\n", Loop1)); + + Status = gBS->InstallMultipleProtocolInterfaces ( + &HostBridge[Loop1]->HostBridgeHandle, + &gEfiPciHostBridgeResourceAllocationProtocolGuid, &HostBridge[Loop1]->ResAlloc, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Fail to install resource alloc\n", __FUNCTION__)); + FreePool (HostBridge[Loop1]); + continue; // Continue with other controllers + } else { + DEBUG ((DEBUG_INFO, "%a: Succeed to install resource allocation protocol\n", __FUNCTION__)); + } + + HostBridge[Loop1]->ImageHandle = ImageHandle; + // + // Create Root Bridge Device Handle in this Host Bridge + // + PrivateData[Loop1] = AllocateZeroPool (sizeof (PCI_ROOT_BRIDGE_INSTANCE)); + if (PrivateData[Loop1] == NULL) { + gBS->UninstallMultipleProtocolInterfaces ( + HostBridge[Loop1]->HostBridgeHandle, + &gEfiPciHostBridgeResourceAllocationProtocolGuid, &HostBridge[Loop1]->ResAlloc, + NULL + ); // Uninstall Resource Allocation protocol + FreePool (HostBridge[Loop1]); // Unallocate previous memory, + continue; // Continue with other controllers + } + + PrivateData[Loop1]->Signature = PCI_ROOT_BRIDGE_SIGNATURE; + CopyMem (&(PrivateData[Loop1]->DevicePath), &mEfiPciRootBridgeDevicePath, sizeof (EFI_PCI_ROOT_BRIDGE_DEVICE_PATH)); + // Set Device Path for this Root Bridge + + PrivateData[Loop1]->DevicePath.AcpiDevicePath.UID = Loop1; + PrivateData[Loop1]->PciMemBase64 = PciMemBase[Loop1]; + + PrivateData[Loop1]->Info = AllocateZeroPool (sizeof (LsPcieInfo)); + PrivateData[Loop1]->Pcie = AllocateZeroPool (sizeof (LsPcie)); + + SetLSPcieInfo(PrivateData[Loop1]->Info, (Loop1+1)); + + HostBridge[Loop1]->RootBridge = PrivateData[Loop1]; + + if (FeaturePcdGet (PcdPciDebug) == TRUE) { + DEBUG ((DEBUG_INFO, "Installed Host Bridges successfully\n")); + } + + Status = PciRbInitialize ( + PrivateData[Loop1], + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *)&PrivateData[Loop1]->Io, + PrivateData[Loop1]->Info, + HostBridge[Loop1]->HostBridgeHandle, + RootBridgeAttribute[0][0], + (Loop1+1), + 0, + PciBaseAddr + ); + + if (EFI_ERROR (Status)) { + Status = gBS->UninstallMultipleProtocolInterfaces ( + HostBridge[Loop1]->HostBridgeHandle, + &gEfiPciHostBridgeResourceAllocationProtocolGuid, &HostBridge[Loop1]->ResAlloc, + NULL + ); + + FreePool (PrivateData[Loop1]->Info); + FreePool (PrivateData[Loop1]->Pcie); + FreePool (PrivateData[Loop1]); + FreePool (HostBridge[Loop1]); + DEBUG ((DEBUG_INFO, "UNInstalled HostBridge ResAlloc protocol and Freed memory\n")); + continue; // Continue with other controllers + } + + Status = gBS->InstallMultipleProtocolInterfaces ( + &PrivateData[Loop1]->Handle, + &gEfiDevicePathProtocolGuid, &PrivateData[Loop1]->DevicePath, + &gEfiPciRootBridgeIoProtocolGuid, &PrivateData[Loop1]->Io, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to install RootBridgeIo and DevicePath protocols\n")); + FreePool (PrivateData[Loop1]); + return EFI_DEVICE_ERROR; + } + + DEBUG ((DEBUG_INFO, "Successfully Installed RootBridgeIo and DevicePath protocols\n")); + InsertTailList (&HostBridge[Loop1]->Head, &PrivateData[Loop1]->Link); + Status = AddMemorySpace (PciMemBase[Loop1], PCI_MEM64_SIZE); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Memory Resource couldn't be added for PCI%d_MEM64\n",Loop1)); + return EFI_DEVICE_ERROR; + } + + } + + return EFI_SUCCESS; +} + +/** + Functions declarations for Host Bridge Resource allocation protocol + + @param ImageHandle Handle of driver image + @param SystemTable Point to EFI_SYSTEM_TABLE + + @retval EFI_ABORTED PCI host bridge not present + @retval EFI_OUT_OF_RESOURCES Can not allocate memory resource + @retval EFI_DEVICE_ERROR Can not install the protocol instance + @retval EFI_SUCCESS Success to initialize the Pci host bridge. +**/ +EFI_STATUS +PciNotifyPhase ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase + ) +{ + PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance; + PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance; + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS BaseAddress; + UINT64 AddrLen; + UINTN BitsOfAlignment; + + BaseAddress = 0x0; + + HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This); + RootBridgeInstance = HostBridgeInstance->RootBridge; + + // Check RootBridge Signature + ASSERT (HostBridgeInstance->RootBridge->Signature == PCI_ROOT_BRIDGE_SIGNATURE); + + // The enumeration cannot be restarted after the process has been further than the first phase + if (Phase == EfiPciHostBridgeBeginEnumeration) { + if (!HostBridgeInstance->CanRestarted) { + return EFI_NOT_READY; + } + } else { + HostBridgeInstance->CanRestarted = FALSE; + } + + switch (Phase) { + case EfiPciHostBridgeBeginEnumeration: + RootBridgeInstance = HostBridgeInstance->RootBridge; + break; + + case EfiPciHostBridgeBeginBusAllocation: + // The bus allocation phase is about to begin + break; + + case EfiPciHostBridgeEndBusAllocation: + // The bus allocation and bus programming phase is complete. All the PCI-to-PCI bridges have been given and written back + // a bus number range into their configuration + break; + + case EfiPciHostBridgeBeginResourceAllocation: + // The resource allocation phase is about to begin. + break; + + case EfiPciHostBridgeAllocateResources: + // Allocates resources per previously submitted requests for all the PCI root bridges. The resources have been submitted to + // PciHbRaSubmitResources() before. + + RootBridgeInstance = HostBridgeInstance->RootBridge; + if (RootBridgeInstance->ResAlloc[ResTypeIo].Length != 0) { + BitsOfAlignment = HighBitSet64 (RootBridgeInstance->ResAlloc[ResTypeIo].Alignment) + 1; // Get the number of '1' in Alignment + AddrLen = RootBridgeInstance->ResAlloc[ResTypeIo].Length; + + Status = gDS->AllocateIoSpace ( + EfiGcdAllocateAnySearchBottomUp, + EfiGcdIoTypeIo, + BitsOfAlignment, + AddrLen, + &BaseAddress, + HostBridgeInstance->ImageHandle, + NULL + ); + // If error then ResAlloc[n].Base ==0 + if (!EFI_ERROR (Status)) { + RootBridgeInstance->ResAlloc[ResTypeIo].Base = (UINTN)BaseAddress; + } + } + + if (RootBridgeInstance->ResAlloc[ResTypeMem32].Length != 0) { + BitsOfAlignment = HighBitSet64 (RootBridgeInstance->ResAlloc[ResTypeMem32].Alignment) + 1; // Get the number of '1' in Alignment + AddrLen = RootBridgeInstance->ResAlloc[ResTypeMem32].Length; + + // Top of the 64bit PCI Memory space + BaseAddress = RootBridgeInstance->PciMemBase64 + PCI_MEM64_SIZE; + + Status = gDS->AllocateMemorySpace ( + EfiGcdAllocateMaxAddressSearchTopDown, + EfiGcdMemoryTypeMemoryMappedIo, + BitsOfAlignment, + AddrLen, + &BaseAddress, + HostBridgeInstance->ImageHandle, + NULL + ); + + // Ensure the allocation is in the 64bit PCI memory space + if (!EFI_ERROR (Status) && (BaseAddress >= RootBridgeInstance->PciMemBase64)) { + RootBridgeInstance->ResAlloc[ResTypeMem32].Base = (UINTN)(BaseAddress - RootBridgeInstance->PciBaseAddress64); + } + } + + if (RootBridgeInstance->ResAlloc[ResTypePMem32].Length != 0) { + BitsOfAlignment = HighBitSet64 (RootBridgeInstance->ResAlloc[ResTypePMem32].Alignment) + 1; // Get the number of '1' in Alignment + AddrLen = RootBridgeInstance->ResAlloc[ResTypePMem32].Length; + + // Top of the 64bit PCI Memory space + BaseAddress = RootBridgeInstance->PciMemBase64 + PCI_MEM64_SIZE; + + Status = gDS->AllocateMemorySpace ( + EfiGcdAllocateMaxAddressSearchTopDown, + EfiGcdMemoryTypeMemoryMappedIo, + BitsOfAlignment, + AddrLen, + &BaseAddress, + HostBridgeInstance->ImageHandle, + NULL + ); + + // Ensure the allocation is in the 64bit PCI memory space + if (!EFI_ERROR (Status) && (BaseAddress >= RootBridgeInstance->PciMemBase64)) { + RootBridgeInstance->ResAlloc[ResTypePMem32].Base = (UINTN)(BaseAddress - RootBridgeInstance->PciBaseAddress64); + } + } + + if (RootBridgeInstance->ResAlloc[ResTypeMem64].Length != 0) { + BitsOfAlignment = HighBitSet64 (RootBridgeInstance->ResAlloc[ResTypeMem64].Alignment) + 1; // Get the number of '1' in Alignment + AddrLen = RootBridgeInstance->ResAlloc[ResTypeMem64].Length; + // Top of the 64bit PCI Memory space + BaseAddress = RootBridgeInstance->PciMemBase64 + PCI_MEM64_SIZE; + + Status = gDS->AllocateMemorySpace ( + EfiGcdAllocateMaxAddressSearchTopDown, + EfiGcdMemoryTypeMemoryMappedIo, + BitsOfAlignment, + AddrLen, + &BaseAddress, + HostBridgeInstance->ImageHandle, + NULL + ); + + // Ensure the allocation is in the 64bit PCI memory space + if (!EFI_ERROR (Status) && (BaseAddress >= RootBridgeInstance->PciMemBase64)) { + RootBridgeInstance->ResAlloc[ResTypeMem64].Base = (UINTN)(BaseAddress - RootBridgeInstance->PciBaseAddress64); + } + } + if (RootBridgeInstance->ResAlloc[ResTypePMem64].Length != 0) { + BitsOfAlignment = HighBitSet64 (RootBridgeInstance->ResAlloc[ResTypePMem64].Alignment) + 1; //Get the number of '1' in Alignment + AddrLen = RootBridgeInstance->ResAlloc[ResTypePMem64].Length; + // Top of the 64bit PCI Memory space + BaseAddress = RootBridgeInstance->PciMemBase64 + PCI_MEM64_SIZE; + + Status = gDS->AllocateMemorySpace ( + EfiGcdAllocateMaxAddressSearchTopDown, + EfiGcdMemoryTypeMemoryMappedIo, + BitsOfAlignment, + AddrLen, + &BaseAddress, + HostBridgeInstance->ImageHandle, + NULL + ); + + // Ensure the allocation is in the 64bit PCI memory space + if (!EFI_ERROR (Status) && (BaseAddress >= RootBridgeInstance->PciMemBase64)) { + RootBridgeInstance->ResAlloc[ResTypePMem64].Base = (UINTN)(BaseAddress - RootBridgeInstance->PciBaseAddress64); + } + } + + break; + + case EfiPciHostBridgeSetResources: + // Programs the host bridge hardware to decode previously allocated resources (proposed resources) + // for all the PCI root bridges. The PCI bus driver will now program the resources + break; + + case EfiPciHostBridgeFreeResources: + // Deallocates resources that were previously allocated for all the PCI root bridges and resets the + // I/O and memory apertures to their initial state.*/ + break; + + case EfiPciHostBridgeEndResourceAllocation: + break; + + case EfiPciHostBridgeEndEnumeration: + break; + + default: + DEBUG ((DEBUG_INFO, "PciHbRaNotifyPhase (Phase:%d)\n", Phase)); + ASSERT (0); + } + + return EFI_SUCCESS; + +} + +/** + This function returns the next root bridge attached to the + 'This' PCI Host Bridge. + There is only one PCI Root Bridge in this PCI interface, we + return either this root bridge if it the first time we call + this function (*RootBridgeHandle == NULL) or return EFI_NOT_FOUND + **/ +EFI_STATUS +PciGetNextRootBridge ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN OUT EFI_HANDLE *RootBridgeHandle + ) +{ + PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance; + + HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This); + ASSERT (HostBridgeInstance->RootBridge != NULL); + + //Check RootBridge Signature + ASSERT (HostBridgeInstance->RootBridge->Signature == PCI_ROOT_BRIDGE_SIGNATURE); + + if (*RootBridgeHandle == NULL) { + *RootBridgeHandle = HostBridgeInstance->RootBridge->Handle; + return EFI_SUCCESS; + } else if (*RootBridgeHandle == HostBridgeInstance->RootBridge->Handle) { + return EFI_NOT_FOUND; + } else { + return EFI_INVALID_PARAMETER; + } +} + +/** + This function returns the resource allocation attributes supported + by this PCI Root Bridge. + A PCI Root bridge could support these types : + - EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM : does not support separate + windows for nonprefetchable and prefetchable memory. + - EFI_PCI_HOST_BRIDGE_MEM64_DECODE : supports 64-bit memory windows + + @param This Pointer to host bridge resource allocation protocol + + @return Attributes Attribues supported by the PCI root bridge + **/ +EFI_STATUS +PciGetAllocAttributes ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_HANDLE RootBridgeHandle, + OUT UINT64 *Attributes + ) +{ + PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance; + + HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This); + + // Check if the RootBridgeHandle is the one managed by this PCI Host Bridge + ASSERT (HostBridgeInstance->RootBridge != NULL); + if (HostBridgeInstance->RootBridge->Handle != RootBridgeHandle) { + return EFI_INVALID_PARAMETER; + } + + *Attributes = HostBridgeInstance->RootBridge->RootBridgeAttrib; + return EFI_SUCCESS; +} + +/** + + This function sets up the specified PCI root bridge for the + bus enumeration process + + @param This pointer to host bridge resource allocation protocol +**/ +EFI_STATUS +PciStartBusEnumeration ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_HANDLE RootBridgeHandle, + OUT VOID **Configuration + ) +{ + VOID *Buffer; + UINT8 *Ptr; + PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance; + + HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This); + + Buffer = AllocateZeroPool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Ptr = (UINT8 *)Buffer; + + // Fill an ACPI descriptor table with the Bus Number Range. This information will be used by the PCI Bus driver + // to set bus numbers to PCI-to-PCI bridge. + + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Ptr)->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; // QWORD Address space Descriptor + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Ptr)->Len = 0x2B; // Length of this descriptor in bytes not including the first two fields + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Ptr)->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS; // Resource Type Bus Number Range + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Ptr)->GenFlag = 0; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Ptr)->SpecificFlag = 0; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Ptr)->AddrSpaceGranularity = 0; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Ptr)->AddrRangeMin = HostBridgeInstance->RootBridge->BusStart; // Bus Start + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Ptr)->AddrRangeMax = 0; // Bus Max + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Ptr)->AddrTranslationOffset = 0; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Ptr)->AddrLen = FixedPcdGet32 (PcdPciBusMax) - FixedPcdGet32 (PcdPciBusMin) + 1; + + Ptr = Ptr + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); + ((EFI_ACPI_END_TAG_DESCRIPTOR *)Ptr)->Desc = ACPI_END_TAG_DESCRIPTOR; + ((EFI_ACPI_END_TAG_DESCRIPTOR *)Ptr)->Checksum = 0x0; + + *Configuration = Buffer; + return EFI_SUCCESS; +} + +/** + This function set PCI bus number(start,end for this root bridge instance + -Checks if ACPI descriptor is passed for supported bus range +**/ +EFI_STATUS +PciSetBusNumbers ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_HANDLE RootBridgeHandle, + IN VOID *Configuration + ) +{ + PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance; + UINT8 *Ptr; + UINTN BusStart; + UINTN BusEnd; + UINTN BusLen; + + Ptr = Configuration; + if (*Ptr != ACPI_ADDRESS_SPACE_DESCRIPTOR) { + return EFI_INVALID_PARAMETER; + } + + // Check if the passed ACPI descriptor table define a Bus Number Range + if (((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Ptr)->ResType != ACPI_ADDRESS_SPACE_TYPE_BUS) { + return EFI_INVALID_PARAMETER; + } + + // Check if the Configuration only passed one ACPI Descriptor (+ End Descriptor) + if (*((UINT8*)(Ptr + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR))) != ACPI_END_TAG_DESCRIPTOR) { + return EFI_INVALID_PARAMETER; + } + + HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This); + ASSERT (HostBridgeInstance->RootBridge != NULL); + if (HostBridgeInstance->RootBridge->Handle != RootBridgeHandle) { + return EFI_INVALID_PARAMETER; + } + + BusStart = (UINTN)((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Ptr)->AddrRangeMin; + BusLen = (UINTN)((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Ptr)->AddrLen; + BusEnd = BusStart + BusLen - 1; + + ASSERT (BusStart <= BusEnd); // We should at least have PCI_BUS_ROOT and PCI_SWITCH_BUS + ASSERT ((BusStart >= HostBridgeInstance->RootBridge->BusStart) && (BusLen <= HostBridgeInstance->RootBridge->BusLength)); + + HostBridgeInstance->RootBridge->BusStart = BusStart; + HostBridgeInstance->RootBridge->BusLength = BusLen; + + return EFI_SUCCESS; +} + +/** + This function is used to submit all the I/O and memory resources + that are required by the specified PCI root bridge. + **/ +EFI_STATUS +PciSubmitResources ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_HANDLE RootBridgeHandle, + IN VOID *Configuration + ) +{ + PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance; + PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance; + UINT8 *Ptr; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc; + PCI_RESOURCE_TYPE ResType; + + HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This); + + if (Configuration == NULL) { + DEBUG((DEBUG_ERROR, "PciHbRaSubmitResources(): NULL COnf\n")); + return EFI_INVALID_PARAMETER; + } + + // Check if the ACPI Descriptor tables is conformed + Ptr = (UINT8 *)Configuration; + while (*Ptr == ACPI_ADDRESS_SPACE_DESCRIPTOR) { // QWORD Address Space descriptor + Ptr += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) ; + } + if (*Ptr != ACPI_END_TAG_DESCRIPTOR) { // End tag + DEBUG ((DEBUG_ERROR, "PciHbRaSubmitResources(): END tag issue\n")); + return EFI_INVALID_PARAMETER; + } + + // Check the RootBridgeHandle + RootBridgeInstance = HostBridgeInstance->RootBridge; + ASSERT (RootBridgeInstance != NULL); + if (RootBridgeHandle != HostBridgeInstance->RootBridge->Handle) { + DEBUG ((DEBUG_ERROR, "PciHbRaSubmitResources(): HB/RB dont match\n")); + return EFI_INVALID_PARAMETER; + } + + Ptr = (UINT8 *)Configuration; + while ( *Ptr == ACPI_ADDRESS_SPACE_DESCRIPTOR) { // While the entry is an ACPI Descriptor Table + Desc = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Ptr; + + // Check if the description is valid + if (Desc->AddrLen > 0xffffffff) { + DEBUG ((DEBUG_ERROR, "PciHbRaSubmitResources(): Invalid addr length\n")); + return EFI_INVALID_PARAMETER; + } + + if ((Desc->AddrRangeMax >= 0xffffffff) || (Desc->AddrRangeMax != (GetPowerOfTwo64 (Desc->AddrRangeMax + 1) - 1))) { + DEBUG ((DEBUG_ERROR, "PciHbRaSubmitResources(): Invalid addr range\n")); + return EFI_INVALID_PARAMETER; + } + + switch (Desc->ResType) { + case ACPI_ADDRESS_SPACE_TYPE_MEM: + // Check invalid Address Space Granularity + if ((Desc->AddrSpaceGranularity != 32) && (Desc->AddrSpaceGranularity != 64)) { + DEBUG ((DEBUG_ERROR, "PciHbRaSubmitResources(): Invalid addr space granul\n")); + return EFI_INVALID_PARAMETER; + } + + // check the memory resource request is supported by PCI root bridge + if (RootBridgeInstance->MemAllocAttributes == EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM && Desc->SpecificFlag == 0x06) { + DEBUG ((DEBUG_ERROR, "PciHbRaSubmitResources(): Invalid memalloc attri \n")); + return EFI_INVALID_PARAMETER; + } + + if (Desc->AddrSpaceGranularity == 32) { + if (Desc->SpecificFlag == ACPI_SPECFLAG_PREFETCHABLE) { + ResType = ResTypePMem32; + } else { + ResType = ResTypeMem32; + } + } else { + if (Desc->SpecificFlag == ACPI_SPECFLAG_PREFETCHABLE) { + ResType = ResTypePMem64; + } else { + ResType = ResTypeMem64; + } + } + RootBridgeInstance->ResAlloc[ResType].Length = Desc->AddrLen; + RootBridgeInstance->ResAlloc[ResType].Alignment = Desc->AddrRangeMax; + RootBridgeInstance->ResAlloc[ResType].Base = Desc->AddrRangeMin; + break; + case ACPI_ADDRESS_SPACE_TYPE_IO: + RootBridgeInstance->ResAlloc[ResTypeIo].Length = Desc->AddrLen; + RootBridgeInstance->ResAlloc[ResTypeIo].Alignment = Desc->AddrRangeMax; + RootBridgeInstance->ResAlloc[ResTypeIo].Base = 0; + break; + default: + ASSERT (0); // Could be the case Desc->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS + break; + } + Ptr += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); + } + + return EFI_SUCCESS; +} + +/** + This function Returns the proposed resource settings for the specified + PCI root bridge. The resources have been submitted by + PciHbRaSubmitResources() + + @param This Pointer to host bridge resource allocation + instance + @param RootBridgeHandle Pointer to this root bridge instance + + @return Configuration Pointer to resource settings + @return EFI_SUCCESS Successful returned requested resource + settings + @return EFI_INVALID_PARAMETER Invalid parameter for root bridge + @return EFI_OUT_OF_RESOURCES Resources can not be allocated + **/ +EFI_STATUS +PciGetProposedResources ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_HANDLE RootBridgeHandle, + OUT VOID **Configuration + ) +{ + PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance; + PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance; + UINT32 i; + UINT32 ResAllocCount; + VOID *Buffer; + UINT8 *Ptr; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc; + + HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This); + + // Check the RootBridgeHandle + RootBridgeInstance = HostBridgeInstance->RootBridge; + ASSERT (RootBridgeInstance != NULL); + if (RootBridgeHandle != HostBridgeInstance->RootBridge->Handle) { + return EFI_INVALID_PARAMETER; + } + + // Count the number of Resource Allocated for this Root Bridge + ResAllocCount = 0; + for (i = 0; i < ResTypeMax; i++) { + if (RootBridgeInstance->ResAlloc[i].Length != 0) ResAllocCount++; + } + + if (ResAllocCount == 0) { + return EFI_INVALID_PARAMETER; + } + + Buffer = AllocateZeroPool (ResAllocCount * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Ptr = Buffer; + for (i = 0; i < ResTypeMax; i++) { + // Base != 0 if the resource has been allocated + if (RootBridgeInstance->ResAlloc[i].Length != 0) { + Desc = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Ptr; + + Desc->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; + Desc->Len = 0x2B; + Desc->GenFlag = 0; + Desc->AddrRangeMax = 0; + + switch (i) { + case ResTypeIo: + Desc->Desc = 0x8A; + Desc->Len = 0x2B; + Desc->ResType = 1; + Desc->GenFlag = 0; + Desc->SpecificFlag = 0; + Desc->AddrSpaceGranularity = 0; + Desc->AddrRangeMin = RootBridgeInstance->ResAlloc[i].Base; + Desc->AddrLen = RootBridgeInstance->ResAlloc[i].Length; + break; + case ResTypeMem32: + Desc->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; + Desc->Desc = 0x8A; + Desc->Len = 0x2B; + Desc->ResType = 0; + Desc->GenFlag = 0; + Desc->SpecificFlag = 0; + Desc->AddrSpaceGranularity = 32; + Desc->AddrRangeMin = RootBridgeInstance->ResAlloc[i].Base; + Desc->AddrLen = RootBridgeInstance->ResAlloc[i].Length; + break; + case ResTypePMem32: + Desc->Desc = 0x8A; + Desc->Len = 0x2B; + Desc->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; + Desc->GenFlag = 0; + Desc->SpecificFlag = 6; + Desc->AddrSpaceGranularity = 32; + Desc->AddrRangeMin = 0; + Desc->AddrTranslationOffset = EFI_RESOURCE_NONEXISTENT; + Desc->AddrLen = 0; + break; + case ResTypeMem64: + Desc->Desc = 0x8A; + Desc->Len = 0x2B; + Desc->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; + Desc->GenFlag = 0; + Desc->SpecificFlag = 0; + Desc->AddrSpaceGranularity = 64; + Desc->AddrRangeMin = RootBridgeInstance->ResAlloc[i].Base; + Desc->AddrLen = RootBridgeInstance->ResAlloc[i].Length; + break; + case ResTypePMem64: + Desc->Desc = 0x8A; + Desc->Len = 0x2B; + Desc->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; + Desc->GenFlag = 0; + Desc->SpecificFlag = 6; + Desc->AddrSpaceGranularity = 64; + Desc->AddrRangeMin = 0; + Desc->AddrTranslationOffset = EFI_RESOURCE_NONEXISTENT; + Desc->AddrLen = 0; + break; + } + Desc->AddrRangeMin = RootBridgeInstance->ResAlloc[i].Base; + Desc->AddrTranslationOffset = EFI_RESOURCE_SATISFIED; + Desc->AddrLen = RootBridgeInstance->ResAlloc[i].Length; + Ptr += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); + } + } + + ((EFI_ACPI_END_TAG_DESCRIPTOR *)Ptr)->Desc = ACPI_END_TAG_DESCRIPTOR; + ((EFI_ACPI_END_TAG_DESCRIPTOR *)Ptr)->Checksum = 0x0; + + *Configuration = Buffer; + return EFI_SUCCESS; +} + +/** + This function allow the host bridge driver to preinitialize individual + PCI controllers before enumeration +**/ +EFI_STATUS +PciPreprocessController ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_HANDLE RootBridgeHandle, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress, + IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase + ) +{ + PCI_HOST_BRIDGE_INSTANCE* HostBridge; + PCI_ROOT_BRIDGE_INSTANCE* RootBridge; + UINT32 CapabilityPtr; + UINT32 CapabilityEntry; + UINT16 CapabilityID; + UINT32 DeviceCapability; + + if (FeaturePcdGet (PcdPciMaxPayloadFixup)) { + // Do Max payload fixup for every devices + if (Phase == EfiPciBeforeResourceCollection) { + // Get RootBridge Instance from Host Bridge Instance + HostBridge = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This); + RootBridge = HostBridge->RootBridge; + + // Get the first PCI Capability + CapabilityPtr = PCI_CAPBILITY_POINTER_OFFSET; + RootBridge->Io.Pci.Read ( + &RootBridge->Io, + EfiPciWidthUint8, + EFI_PCI_ADDRESS (PciAddress.Bus, PciAddress.Device, PciAddress.Function, CapabilityPtr), + 1, + &CapabilityPtr + ); + CapabilityPtr &= 0x1FF; + + // Get Pci Express Capability + while (CapabilityPtr != 0) { + RootBridge->Io.Pci.Read ( + &RootBridge->Io, + EfiPciWidthUint16, + EFI_PCI_ADDRESS (PciAddress.Bus, PciAddress.Device, PciAddress.Function, CapabilityPtr), + 1, + &CapabilityEntry + ); + + CapabilityID = (UINT8)CapabilityEntry; + + // Is PCIe capability ? + if (CapabilityID == EFI_PCI_CAPABILITY_ID_PCIEXP) { + // Get PCIe Device Capabilities + RootBridge->Io.Pci.Read ( + &RootBridge->Io, + EfiPciWidthUint32, + EFI_PCI_ADDRESS (PciAddress.Bus, PciAddress.Device, PciAddress.Function, CapabilityPtr + 0x8), + 1, + &DeviceCapability + ); + + // Force the Max Payload to 128 Bytes (128 Bytes Max Payload Size = 0) + DeviceCapability &= ~ ((UINT32)(0x7 << 5 )); + // Max Read Request Size to 128 Bytes (128 Bytes Max Read Request Size = 0) + DeviceCapability &= ~ ((UINT32)(0x7 << 12)); + // Enable all error reporting + DeviceCapability |= 0xF; + + RootBridge->Io.Pci.Write ( + &RootBridge->Io, + EfiPciWidthUint32, + EFI_PCI_ADDRESS (PciAddress.Bus, PciAddress.Device, PciAddress.Function, CapabilityPtr + 0x8), + 1, + &DeviceCapability + ); + + return EFI_SUCCESS; + } + CapabilityPtr = (CapabilityEntry >> 8) & 0xFF; + } + } + } + + return EFI_SUCCESS; +} diff --git a/Platform/NXP/Drivers/PciHostBridgeDxe/PciHostBridgeDxe.inf b/Platform/NXP/Drivers/PciHostBridgeDxe/PciHostBridgeDxe.inf new file mode 100644 index 0000000..019cc63 --- /dev/null +++ b/Platform/NXP/Drivers/PciHostBridgeDxe/PciHostBridgeDxe.inf @@ -0,0 +1,61 @@ +/* PciHostBridgeDxe.inf +# +# Component description file for PCI Host Bridge driver +# +# Copyright (c) 2015, Freescale Semiconductor, Inc. All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +*/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = PciHostBridge + FILE_GUID = C62F4B20-681E-11DF-8F0D-0002A5D5C51B + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = PciHostBridgeEntryPoint + +[Packages] + MdePkg/MdePkg.dec + Platform/NXP/NxpQoriqLs.dec + Silicon/NXP/Chassis/Chassis2/Chassis2.dec + +[LibraryClasses] + DxeServicesTableLib + PciHostBridgeLib + SocLib + UefiDriverEntryPoint + +[Sources] + PciHostBridgeDxe.c + PciRootBridgeIo.c + +[FixedPcd] + gNxpQoriqLsTokenSpaceGuid.PcdPciBusMin + gNxpQoriqLsTokenSpaceGuid.PcdPciBusMax + gNxpQoriqLsTokenSpaceGuid.PcdPci1Mmio64Base + gNxpQoriqLsTokenSpaceGuid.PcdPciMmio64Size + gNxpQoriqLsTokenSpaceGuid.PcdPciExp1BaseAddr + gNxpQoriqLsTokenSpaceGuid.PcdKludgeMapPciMmioAsCached + gNxpQoriqLsTokenSpaceGuid.PcdPciMaxPayloadFixup + gNxpQoriqLsTokenSpaceGuid.PcdPciDebug + gNxpQoriqLsTokenSpaceGuid.PcdNumPciController + gNxpQoriqLsTokenSpaceGuid.PcdPciMemOneTransaction + gNxpQoriqLsTokenSpaceGuid.PcdPciExp1BaseSize + +[Protocols] + gEfiPciHostBridgeResourceAllocationProtocolGuid ## PRODUCES + gEfiPciRootBridgeIoProtocolGuid ## PRODUCES + gEfiMetronomeArchProtocolGuid ## CONSUMES + gEfiDevicePathProtocolGuid ## PRODUCES + +[Depex] + TRUE diff --git a/Platform/NXP/Drivers/PciHostBridgeDxe/PciRootBridgeIo.c b/Platform/NXP/Drivers/PciHostBridgeDxe/PciRootBridgeIo.c new file mode 100644 index 0000000..9a5c238 --- /dev/null +++ b/Platform/NXP/Drivers/PciHostBridgeDxe/PciRootBridgeIo.c @@ -0,0 +1,1193 @@ +/** PciRootBridgeIo.c + PCI Root Bridge Io Protocol implementation + + Based on PCI RootBridge implementation in + ArmPlatformPkg/ArmJunoPkg/Drivers/PciHostBridgeDxe/PciRootBridge.c + + Copyright (c) 2011-2015, ARM Ltd. All rights reserved. + Copyright 2017 NXP + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +typedef struct { + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR SpaceDesp[ResTypeMax+1]; + EFI_ACPI_END_TAG_DESCRIPTOR EndDesp; +} RESOURCE_CONFIGURATION; + +RESOURCE_CONFIGURATION Configuration = { + {{ACPI_ADDRESS_SPACE_DESCRIPTOR, 0x2B, ACPI_ADDRESS_SPACE_TYPE_IO , 0, 0, 0, 0, 0, 0, 0}, + {ACPI_ADDRESS_SPACE_DESCRIPTOR, 0x2B, ACPI_ADDRESS_SPACE_TYPE_MEM, 0, 0, 32, 0, 0, 0, 0}, + {ACPI_ADDRESS_SPACE_DESCRIPTOR, 0x2B, ACPI_ADDRESS_SPACE_TYPE_MEM, 0, 6, 32, 0, 0, 0, 0}, + {ACPI_ADDRESS_SPACE_DESCRIPTOR, 0x2B, ACPI_ADDRESS_SPACE_TYPE_MEM, 0, 0, 64, 0, 0, 0, 0}, + {ACPI_ADDRESS_SPACE_DESCRIPTOR, 0x2B, ACPI_ADDRESS_SPACE_TYPE_MEM, 0, 6, 64, 0, 0, 0, 0}, + {ACPI_ADDRESS_SPACE_DESCRIPTOR, 0x2B, ACPI_ADDRESS_SPACE_TYPE_BUS, 0, 0, 0, 0, 255, 0, 255}}, + {ACPI_END_TAG_DESCRIPTOR, 0} +}; + +// +// Memory Controller Pci Root Bridge Io Module Variables +// +EFI_METRONOME_ARCH_PROTOCOL *mMetronome; + +/** + + Initialize and create Pci Root Bridges for Board + + @param PrvateData Driver instance of this Root Bridge IO protocol + @param Protocol Point to protocol instance + @param Info Point to Info field of this driver instance + @param HostBridgeHandle Handle of host bridge + @param Attri Attribute of host bridge + @param HostNo HostNo for this Host Bridge + @param Busno Bus Number for the Host Bridge + + @retval EFI_SUCCESS Success to initialize the Pci Root Bridge. + +**/ +EFI_STATUS +PciRbInitialize ( + IN PCI_ROOT_BRIDGE_INSTANCE *PrivateData, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *Protocol, + IN LsPcieInfo *Info, + IN EFI_HANDLE HostBridgeHandle, + IN UINT64 Attri, + IN INTN HostNo, + IN INTN Busno, + IN UINT64 *PciBaseAddr + ) +{ + EFI_STATUS Status; + LsPcie *Pcie; + PciDevT Pdev; + INTN LinkUp, EpMode; + UINT8 HeaderType; + UINT16 Temp16; + UINT16 VendorID16; + UINT16 DeviceID16; + UINT16 Cntr; + + Pdev = ((Busno) << 16 | (0) << 11 | (0) << 8); + Pcie = PrivateData->Pcie; + + PrivateData->FirstBusno = Busno; + PrivateData->Pcie->Dbi = (VOID *)Info->Regs; + PrivateData->Pcie->VaCfg0 = (VOID *)Info->Cfg0Phys; + PrivateData->Pcie->VaCfg1 = (VOID *)Info->Cfg1Phys; + + LinkUp = PcieLinkUp(Pcie); + + if (!LinkUp) { + // Let the user know there's no PCIe link + DEBUG ((DEBUG_INFO,"no link, regs @ 0x%lx\n", Info->Regs)); + PrivateData->LastBusno = PrivateData->FirstBusno; + return EFI_ABORTED; + } + DEBUG ((DEBUG_INFO, "Passed Linkup Phase\n")); + + // outbound memory + PciSetRegion (&PrivateData->Regions[0], + (PciSizeT)Info->MemBus, + (PhysSizeT)Info->MemPhys, + (PciSizeT)Info->MemSize, + LS_PCI_REGION_MEM); + + // outbound io + PciSetRegion (&PrivateData->Regions[1], + (PciSizeT)Info->IoBus, + (PhysSizeT)Info->IoPhys, + (PciSizeT)Info->IoSize, + LS_PCI_REGION_IO); + + // System memory space + PciSetRegion (&PrivateData->Regions[2], + LS_PCI_MEMORY_BUS, + LS_PCI_MEMORY_PHYS, + LS_PCI_MEMORY_SIZE, + LS_PCI_REGION_SYS_MEMORY); + + PrivateData->RegionCnt = 3; + + if (FeaturePcdGet (PcdPciDebug) == TRUE) { + for (Cntr = 0; Cntr < PrivateData->RegionCnt; Cntr++) { + DEBUG ((DEBUG_INFO, "PCI reg:%d %016llx:%016llx %016llx %08lx\n", + Cntr, + (UINT64)PrivateData->Regions[Cntr].PhysStart, + (UINT64)PrivateData->Regions[Cntr].BusStart, + (UINT64)PrivateData->Regions[Cntr].Size, + PrivateData->Regions[Cntr].Flags)); + } + } + + PcieReadConfigWord (PrivateData, Pdev, LS_PCI_VENDOR_ID, (UINT16 *)&VendorID16); + DEBUG ((DEBUG_INFO,"PCIe:VendorID: %04lx\n", VendorID16)); + PcieReadConfigWord (PrivateData, Pdev, LS_PCI_DEVICE_ID, (UINT16 *)&DeviceID16); + DEBUG ((DEBUG_INFO,"PCIe Device ID: %04lx\n", DeviceID16)); + PcieReadConfigByte (PrivateData, Pdev, LS_PCI_HEADER_TYPE, (UINT8 *)&HeaderType); + DEBUG ((DEBUG_INFO,"PCIe Header Type: %02lx\n", HeaderType)); + EpMode = (HeaderType & 0x7f) == LS_PCI_HEADER_TYPE_NORMAL; + DEBUG ((DEBUG_INFO,"EpMode: %d\n", EpMode)); + DEBUG ((DEBUG_INFO,"PCIe%d: %a\n", (UINT64)Info->PciNum, EpMode ? "Endpoint" : "Root Complex")); + + // Print the negotiated PCIe link width + PcieReadConfigWord (PrivateData, Pdev, LS_PCIE_LINK_STA, (UINT16 *)&Temp16); + DEBUG ((DEBUG_INFO,"PCIe Link Status: %04lx\n", Temp16)); + DEBUG ((DEBUG_INFO,"x%d gen%d, regs @ 0x%lx\n", (Temp16 & 0x3f0) >> 4, + (Temp16 & 0xf), Info->Regs)); + + if (EpMode) { + DEBUG ((DEBUG_INFO, "EpMode: %d\n", Busno)); + return Busno; + } + + PrivateData->PciBaseAddress64 = PciBaseAddr[HostNo - 1]; + if (!PrivateData->PciBaseAddress64) { + DEBUG ((DEBUG_ERROR, "%a: PCI %d host bridge not present\n", __FUNCTION__, HostNo)); + return EFI_ABORTED; + } + + PcieSetupCntrl (PrivateData, PrivateData->Pcie, PrivateData->Info); + + PrivateData->BusStart = FixedPcdGet32 (PcdPciBusMin); + PrivateData->BusLength = FixedPcdGet32 (PcdPciBusMax) - FixedPcdGet32 (PcdPciBusMin) + 1; + + PrivateData->RootBridgeAttrib = Attri; + + PrivateData->Supports = EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO | \ + EFI_PCI_ATTRIBUTE_ISA_IO_16 | EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO | \ + EFI_PCI_ATTRIBUTE_VGA_MEMORY | \ + EFI_PCI_ATTRIBUTE_VGA_IO_16 | EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16; + PrivateData->Attributes = PrivateData->Supports; + + Protocol->ParentHandle = HostBridgeHandle; + + Protocol->PollMem = RootBridgeIoPollMem; + Protocol->PollIo = RootBridgeIoPollIo; + + Protocol->Mem.Read = RootBridgeIoMemRead; + Protocol->Mem.Write = RootBridgeIoMemWrite; + + Protocol->Io.Read = RootBridgeIoIoRead; + Protocol->Io.Write = RootBridgeIoIoWrite; + + Protocol->CopyMem = RootBridgeIoCopyMem; + + Protocol->Pci.Read = RootBridgeIoPciRead; + Protocol->Pci.Write = RootBridgeIoPciWrite; + + Protocol->Map = RootBridgeIoMap; + Protocol->Unmap = RootBridgeIoUnmap; + + Protocol->AllocateBuffer = RootBridgeIoAllocateBuffer; + Protocol->FreeBuffer = RootBridgeIoFreeBuffer; + + Protocol->Flush = RootBridgeIoFlush; + + Protocol->GetAttributes = RootBridgeIoGetAttributes; + Protocol->SetAttributes = RootBridgeIoSetAttributes; + + Protocol->Configuration = RootBridgeIoConfiguration; + + Protocol->SegmentNumber = HostNo; + + Status = gBS->LocateProtocol (&gEfiMetronomeArchProtocolGuid, NULL, (VOID **)&mMetronome); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + +/** + Polls an address in memory mapped I/O space until an exit condition is met, or + a timeout occurs. + + This function provides a standard way to poll a PCI memory location. A PCI memory read + operation is performed at the PCI memory address specified by Address for the width specified + by Width. The result of this PCI memory read operation is stored in Result. This PCI memory + read operation is repeated until either a timeout of Delay 100 ns units has expired, or (Result & + Mask) is equal to Value. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width Signifies the width of the memory operations. + @param[in] Address The base address of the memory operations. The caller is + responsible for aligning Address if required. + @param[in] Mask Mask used for the polling criteria. Bytes above Width in Mask + are ignored. The bits in the bytes below Width which are zero in + Mask are ignored when polling the memory address. + @param[in] Value The comparison value used for the polling exit criteria. + @param[in] Delay The number of 100 ns units to poll. Note that timer available may + be of poorer granularity. + @param[out] Result Pointer to the last value read from the memory location. + + @retval EFI_SUCCESS The last data returned from the access matched the poll exit criteria. + @retval EFI_INVALID_PARAMETER Width is invalid. + @retval EFI_INVALID_PARAMETER Result is NULL. + @retval EFI_TIMEOUT Delay expired before a match occurred. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoPollMem ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ) +{ + EFI_STATUS Status; + UINT64 NumberOfTicks; + UINT32 Remainder; + + if (Result == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width > EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + // No matter what, always do a single poll. + Status = This->Mem.Read (This, Width, Address, 1, Result); + if (EFI_ERROR (Status)) { + return Status; + } + if ((*Result & Mask) == Value) { + return EFI_SUCCESS; + } + + if (Delay == 0) { + return EFI_SUCCESS; + } + + NumberOfTicks = DivU64x32Remainder (Delay, (UINT32) mMetronome->TickPeriod, &Remainder); + if (Remainder != 0) { + NumberOfTicks += 1; + } + NumberOfTicks += 1; + + while (NumberOfTicks) { + mMetronome->WaitForTick (mMetronome, 1); + + Status = This->Mem.Read (This, Width, Address, 1, Result); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((*Result & Mask) == Value) { + return EFI_SUCCESS; + } + + NumberOfTicks -= 1; + } + + return EFI_TIMEOUT; +} + +/** + Reads from the I/O space of a PCI Root Bridge. Returns when either the polling exit criteria is + satisfied or after a defined duration. + + This function provides a standard way to poll a PCI I/O location. A PCI I/O read operation is + performed at the PCI I/O address specified by Address for the width specified by Width. + The result of this PCI I/O read operation is stored in Result. This PCI I/O read operation is + repeated until either a timeout of Delay 100 ns units has expired, or (Result & Mask) is equal + to Value. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width Signifies the width of the I/O operations. + @param[in] Address The base address of the I/O operations. The caller is responsible + for aligning Address if required. + @param[in] Mask Mask used for the polling criteria. Bytes above Width in Mask + are ignored. The bits in the bytes below Width which are zero in + Mask are ignored when polling the I/O address. + @param[in] Value The comparison value used for the polling exit criteria. + @param[in] Delay The number of 100 ns units to poll. Note that timer available may + be of poorer granularity. + @param[out] Result Pointer to the last value read from the memory location. + + @retval EFI_SUCCESS The last data returned from the access matched the poll exit criteria. + @retval EFI_INVALID_PARAMETER Width is invalid. + @retval EFI_INVALID_PARAMETER Result is NULL. + @retval EFI_TIMEOUT Delay expired before a match occurred. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoPollIo ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ) +{ + EFI_STATUS Status; + UINT64 NumberOfTicks; + UINT32 Remainder; + + if (Result == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width > EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + // No matter what, always do a single poll. + Status = This->Io.Read (This, Width, Address, 1, Result); + if (EFI_ERROR (Status)) { + return Status; + } + if ((*Result & Mask) == Value) { + return EFI_SUCCESS; + } + + if (Delay == 0) { + return EFI_SUCCESS; + } + + NumberOfTicks = DivU64x32Remainder (Delay, (UINT32) mMetronome->TickPeriod, &Remainder); + if (Remainder != 0) { + NumberOfTicks += 1; + } + NumberOfTicks += 1; + + while (NumberOfTicks) { + mMetronome->WaitForTick (mMetronome, 1); + + Status = This->Io.Read (This, Width, Address, 1, Result); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((*Result & Mask) == Value) { + return EFI_SUCCESS; + } + + NumberOfTicks -= 1; + } + + return EFI_TIMEOUT; +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space. + + The Mem.Read(), and Mem.Write() functions enable a driver to access PCI controller + registers in the PCI root bridge memory space. + The memory operations are carried out exactly as requested. The caller is responsible for satisfying + any alignment and memory width restrictions that a PCI Root Bridge on a platform might require. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width Signifies the width of the memory operation. + @param[in] Address The base address of the memory operation. The caller is + responsible for aligning the Address if required. + @param[in] Count The number of memory operations to perform. Bytes moved is + Width size * Count, starting at Address. + @param[out] Buffer For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoMemRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + OUT VOID *Buffer + ) +{ + return RootBridgeIoMemRW (This, FALSE, Width, Address, Count, Buffer); +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space. + + The Mem.Read(), and Mem.Write() functions enable a driver to access PCI controller + registers in the PCI root bridge memory space. + The memory operations are carried out exactly as requested. The caller is responsible for satisfying + any alignment and memory width restrictions that a PCI Root Bridge on a platform might require. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width Signifies the width of the memory operation. + @param[in] Address The base address of the memory operation. The caller is + responsible for aligning the Address if required. + @param[in] Count The number of memory operations to perform. Bytes moved is + Width size * Count, starting at Address. + @param[in] Buffer For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoMemWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ) +{ + return RootBridgeIoMemRW (This, TRUE, Width, Address, Count, Buffer); +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge I/O space. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width Signifies the width of the memory operations. + @param[in] Address The base address of the I/O operation. The caller is responsible for + aligning the Address if required. + @param[in] Count The number of I/O operations to perform. Bytes moved is Width + size * Count, starting at Address. + @param[out] Buffer For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoIoRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + OUT VOID *Buffer + ) +{ + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + return RootBridgeIoIoRW (This, FALSE, Width, Address, Count, Buffer); +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge I/O space. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width Signifies the width of the memory operations. + @param[in] Address The base address of the I/O operation. The caller is responsible for + aligning the Address if required. + @param[in] Count The number of I/O operations to perform. Bytes moved is Width + size * Count, starting at Address. + @param[in] Buffer For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoIoWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ) +{ + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + return RootBridgeIoIoRW (This, TRUE, Width, Address, Count, Buffer); +} + +/** + Enables a PCI driver to copy one region of PCI root bridge memory space to another region of PCI + root bridge memory space. + + The CopyMem() function enables a PCI driver to copy one region of PCI root bridge memory + space to another region of PCI root bridge memory space. This is especially useful for video scroll + operation on a memory mapped video buffer. + The memory operations are carried out exactly as requested. The caller is responsible for satisfying + any alignment and memory width restrictions that a PCI root bridge on a platform might require. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance. + @param[in] Width Signifies the width of the memory operations. + @param[in] DestAddress The destination address of the memory operation. The caller is + responsible for aligning the DestAddress if required. + @param[in] SrcAddress The source address of the memory operation. The caller is + responsible for aligning the SrcAddress if required. + @param[in] Count The number of memory operations to perform. Bytes moved is + Width size * Count, starting at DestAddress and SrcAddress. + + @retval EFI_SUCCESS The data was copied from one memory region to another memory region. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoCopyMem ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 DestAddress, + IN UINT64 SrcAddress, + IN UINTN Count + ) +{ + EFI_STATUS Status; + BOOLEAN Direction; + UINTN Stride; + UINTN Index; + UINT64 Result; + + if (Width > EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + if (DestAddress == SrcAddress) { + return EFI_SUCCESS; + } + + Stride = (UINTN)(1 << Width); + + Direction = TRUE; + if ((DestAddress > SrcAddress) && (DestAddress < (SrcAddress + Count * Stride))) { + Direction = FALSE; + SrcAddress = SrcAddress + (Count-1) * Stride; + DestAddress = DestAddress + (Count-1) * Stride; + } + + for (Index = 0; Index < Count; Index++) { + Status = RootBridgeIoMemRead ( + This, + Width, + SrcAddress, + 1, + &Result + ); + if (EFI_ERROR (Status)) { + return Status; + } + Status = RootBridgeIoMemWrite ( + This, + Width, + DestAddress, + 1, + &Result + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Direction) { + SrcAddress += Stride; + DestAddress += Stride; + } else { + SrcAddress -= Stride; + DestAddress -= Stride; + } + } + return EFI_SUCCESS; +} + +/** + Enables a PCI driver to access PCI controller registers in a PCI root bridge's configuration space. + + The Pci.Read() and Pci.Write() functions enable a driver to access PCI configuration + registers for a PCI controller. + The PCI Configuration operations are carried out exactly as requested. The caller is responsible for + any alignment and PCI configuration width issues that a PCI Root Bridge on a platform might + require. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width Signifies the width of the memory operations. + @param[in] Address The address within the PCI configuration space for the PCI controller. + @param[in] Count The number of PCI configuration operations to perform. Bytes + moved is Width size * Count, starting at Address. + @param[out] Buffer For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoPciRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + OUT VOID *Buffer + ) +{ + return RootBridgeIoPciRW (This, FALSE, Width, Address, Count, Buffer); +} + +/** + Enables a PCI driver to access PCI controller registers in a PCI root bridge's configuration space. + + The Pci.Read() and Pci.Write() functions enable a driver to access PCI configuration + registers for a PCI controller. + The PCI Configuration operations are carried out exactly as requested. The caller is responsible for + any alignment and PCI configuration width issues that a PCI Root Bridge on a platform might + require. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width Signifies the width of the memory operations. + @param[in] Address The address within the PCI configuration space for the PCI controller. + @param[in] Count The number of PCI configuration operations to perform. Bytes + moved is Width size * Count, starting at Address. + @param[in] Buffer For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoPciWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ) +{ + return RootBridgeIoPciRW (This, TRUE, Width, Address, Count, Buffer); +} + +/** + Provides the PCI controller-specific addresses required to access system memory from a + DMA bus master. + + The Map() function provides the PCI controller specific addresses needed to access system + memory. This function is used to map system memory for PCI bus master DMA accesses. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Operation Indicates if the bus master is going to read or write to system memory. + @param[in] HostAddress The system memory address to map to the PCI controller. + @param[in, out] NumberOfBytes On input the number of bytes to map. On output the number of bytes that were mapped. + @param[out] DeviceAddress The resulting map address for the bus master PCI controller to use + to access the system memory's HostAddress. + @param[out] Mapping The value to pass to Unmap() when the bus master DMA operation is complete. + + @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes. + @retval EFI_INVALID_PARAMETER Operation is invalid. + @retval EFI_INVALID_PARAMETER HostAddress is NULL. + @retval EFI_INVALID_PARAMETER NumberOfBytes is NULL. + @retval EFI_INVALID_PARAMETER DeviceAddress is NULL. + @retval EFI_INVALID_PARAMETER Mapping is NULL. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer. + @retval EFI_DEVICE_ERROR The system hardware could not map the requested address. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoMap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS PhysicalAddress; + MAP_INFO *MapInfo; + + if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL || Mapping == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Initialize the return values to their defaults + // + *Mapping = NULL; + + // + // Make sure that Operation is valid + // + if ((UINT32)Operation >= EfiPciOperationMaximum) { + return EFI_INVALID_PARAMETER; + } + + if ((*NumberOfBytes) > PcdGet64 (PcdPciMemOneTransaction)) { + DEBUG((DEBUG_INFO, "Cannot map more than 0x%x at one transaction\n", + PcdGet64 (PcdPciMemOneTransaction))); + return EFI_INVALID_PARAMETER; + } + + // + // If any part of the DMA transfer being mapped is above 4GB, then + // map the DMA transfer to a buffer below 4GB + // + PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress; + if ((PhysicalAddress + *NumberOfBytes) > 0x100000000ULL) { + + // + // Common Buffer operations can not be remapped. If the common buffer + // if above 4GB, then it is not possible to generate a mapping, so return + // an error. + // + if (Operation == EfiPciOperationBusMasterCommonBuffer || Operation == EfiPciOperationBusMasterCommonBuffer64) { + return EFI_UNSUPPORTED; + } + + // + // Allocate a MAP_INFO structure to remember the mapping when Unmap() is + // called later. + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (MAP_INFO), + (VOID **)&MapInfo + ); + if (EFI_ERROR (Status)) { + *NumberOfBytes = 0; + return Status; + } + + // + // Return a pointer to the MAP_INFO structure in Mapping + // + *Mapping = MapInfo; + + // + // Initialize the MAP_INFO structure + // + MapInfo->Operation = Operation; + MapInfo->NumberOfBytes = *NumberOfBytes; + MapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (*NumberOfBytes); + MapInfo->HostAddress = PhysicalAddress; + MapInfo->MappedHostAddress = GetPciAddressSpaceMask (); + + // + // Allocate a buffer below 4GB to map the transfer to. + // + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiBootServicesData, + MapInfo->NumberOfPages, + &MapInfo->MappedHostAddress + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (MapInfo); + *NumberOfBytes = 0; + return Status; + } + + // + // If this is a read operation from the Bus Master's point of view, + // then copy the contents of the real buffer into the mapped buffer + // so the Bus Master can read the contents of the real buffer. + // + if (Operation == EfiPciOperationBusMasterRead || Operation == EfiPciOperationBusMasterRead64) { + CopyMem ( + (VOID *)(UINTN)MapInfo->MappedHostAddress, + (VOID *)(UINTN)MapInfo->HostAddress, + MapInfo->NumberOfBytes + ); + } + + // + // The DeviceAddress is the address of the maped buffer below 4GB + // + *DeviceAddress = MapInfo->MappedHostAddress; + } else { + // + // The transfer is below 4GB, so the DeviceAddress is simply the HostAddress + // + *DeviceAddress = PhysicalAddress; + } + + return EFI_SUCCESS; +} + +/** + Completes the Map() operation and releases any corresponding resources. + + The Unmap() function completes the Map() operation and releases any corresponding resources. + If the operation was an EfiPciOperationBusMasterWrite or + EfiPciOperationBusMasterWrite64, the data is committed to the target system memory. + Any resources used for the mapping are freed. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Mapping The mapping value returned from Map(). + + @retval EFI_SUCCESS The range was unmapped. + @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map(). + @retval EFI_DEVICE_ERROR The data was not committed to the target system memory. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoUnmap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN VOID *Mapping + ) +{ + MAP_INFO *MapInfo; + + // + // See if the Map() operation associated with this Unmap() required a mapping buffer. + // If a mapping buffer was not required, then this function simply returns EFI_SUCCESS. + // + if (Mapping != NULL) { + // + // Get the MAP_INFO structure from Mapping + // + MapInfo = (MAP_INFO *)Mapping; + + // + // If this is a write operation from the Bus Master's point of view, + // then copy the contents of the mapped buffer into the real buffer + // so the processor can read the contents of the real buffer. + // + if (MapInfo->Operation == EfiPciOperationBusMasterWrite || MapInfo->Operation == EfiPciOperationBusMasterWrite64) { + CopyMem ( + (VOID *)(UINTN)MapInfo->HostAddress, + (VOID *)(UINTN)MapInfo->MappedHostAddress, + MapInfo->NumberOfBytes + ); + } + + // + // Free the mapped buffer and the MAP_INFO structure. + // + gBS->FreePages (MapInfo->MappedHostAddress, MapInfo->NumberOfPages); + gBS->FreePool (Mapping); + } + return EFI_SUCCESS; +} + +/** + Allocates pages that are suitable for an EfiPciOperationBusMasterCommonBuffer or + EfiPciOperationBusMasterCommonBuffer64 mapping. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Type This parameter is not used and must be ignored. + @param MemoryType The type of memory to allocate, EfiBootServicesData or EfiRuntimeServicesData. + @param Pages The number of pages to allocate. + @param HostAddress A pointer to store the base system memory address of the allocated range. + @param Attributes The requested bit mask of attributes for the allocated range. Only + the attributes EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE, EFI_PCI_ATTRIBUTE_MEMORY_CAC HED,and EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE may be used with this function. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_INVALID_PARAMETER MemoryType is invalid. + @retval EFI_INVALID_PARAMETER HostAddress is NULL. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE, MEMORY_CACHED, and DUAL_ADDRESS_CYCLE. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoAllocateBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS PhysicalAddress; + + // + // Validate Attributes + // + if ((Attributes & EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) != 0) { + return EFI_UNSUPPORTED; + } + + // + // Check for invalid inputs + // + if (HostAddress == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData + // + if (MemoryType != EfiBootServicesData && MemoryType != EfiRuntimeServicesData) { + return EFI_INVALID_PARAMETER; + } + + // + // Limit allocations to memory below 4GB + // + PhysicalAddress = (EFI_PHYSICAL_ADDRESS)(GetPciAddressSpaceMask ()); + + Status = gBS->AllocatePages (AllocateMaxAddress, MemoryType, Pages, &PhysicalAddress); + if (EFI_ERROR (Status)) { + return Status; + } + + *HostAddress = (VOID *)(UINTN)PhysicalAddress; + + return EFI_SUCCESS; +} + +/** + Frees memory that was allocated with AllocateBuffer(). + + The FreeBuffer() function frees memory that was allocated with AllocateBuffer(). + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Pages The number of pages to free. + @param HostAddress The base system memory address of the allocated range. + + @retval EFI_SUCCESS The requested memory pages were freed. + @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages + was not allocated with AllocateBuffer(). + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoFreeBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINTN Pages, + OUT VOID *HostAddress + ) +{ + + return gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress, Pages); +} + +/** + Flushes all PCI posted write transactions from a PCI host bridge to system memory. + + The Flush() function flushes any PCI posted write transactions from a PCI host bridge to system + memory. Posted write transactions are generated by PCI bus masters when they perform write + transactions to target addresses in system memory. + This function does not flush posted write transactions from any PCI bridges. A PCI controller + specific action must be taken to guarantee that the posted write transactions have been flushed from + the PCI controller and from all the PCI bridges into the PCI host bridge. This is typically done with + a PCI read transaction from the PCI controller prior to calling Flush(). + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + + @retval EFI_SUCCESS The PCI posted write transactions were flushed from the PCI host + bridge to system memory. + @retval EFI_DEVICE_ERROR The PCI posted write transactions were not flushed from the PCI + host bridge due to a hardware error. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoFlush ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This + ) +{ + // + // not supported yet + // + return EFI_SUCCESS; +} + +/** + Gets the attributes that a PCI root bridge supports setting with SetAttributes(), and the + attributes that a PCI root bridge is currently using. + + The GetAttributes() function returns the mask of attributes that this PCI root bridge supports + and the mask of attributes that the PCI root bridge is currently using + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Supported A pointer to the mask of attributes that this PCI root bridge + supports setting with SetAttributes(). + @param Attributes A pointer to the mask of attributes that this PCI root bridge is + currently using. + + @retval EFI_SUCCESS If Supports is not NULL, then the attributes that the PCI root + bridge supports is returned in Supports. If Attributes is + not NULL, then the attributes that the PCI root bridge is currently + using is returned in Attributes. + @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoGetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT UINT64 *Supported, + OUT UINT64 *Attributes + ) +{ + PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This); + + if (Attributes == NULL && Supported == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Set the return value for Supported and Attributes + // + if (Supported != NULL) { + *Supported = PrivateData->Supports; + } + + if (Attributes != NULL) { + *Attributes = PrivateData->Attributes; + } + + return EFI_SUCCESS; +} + +/** + Sets attributes for a resource range on a PCI root bridge. + + The SetAttributes() function sets the attributes specified in Attributes for the PCI root + bridge on the resource range specified by ResourceBase and ResourceLength. Since the + granularity of setting these attributes may vary from resource type to resource type, and from + platform to platform, the actual resource range and the one passed in by the caller may differ. As a + result, this function may set the attributes specified by Attributes on a larger resource range + than the caller requested. The actual range is returned in ResourceBase and + ResourceLength. The caller is responsible for verifying that the actual range for which the + attributes were set is acceptable. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Attributes The mask of attributes to set. If the attribute bit + MEMORY_WRITE_COMBINE, MEMORY_CACHED, or + MEMORY_DISABLE is set, then the resource range is specified by + ResourceBase and ResourceLength. If + MEMORY_WRITE_COMBINE, MEMORY_CACHED, and + MEMORY_DISABLE are not set, then ResourceBase and + ResourceLength are ignored, and may be NULL. + @param[in, out] ResourceBase A pointer to the base address of the resource range to be modified + by the attributes specified by Attributes. + @param[in, out] ResourceLength A pointer to the length of the resource range to be modified by the + attributes specified by Attributes. + + @retval EFI_SUCCESS The current configuration of this PCI root bridge was returned in Resources. + @retval EFI_UNSUPPORTED The current configuration of this PCI root bridge could not be retrieved. + @retval EFI_INVALID_PARAMETER Invalid pointer of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoSetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN OUT UINT64 *ResourceBase, + IN OUT UINT64 *ResourceLength + ) +{ + PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This); + + if (Attributes != 0) { + if ((Attributes & (~(PrivateData->Supports))) != 0) { + return EFI_UNSUPPORTED; + } + } + + // + // This is a generic driver for a PC-AT class system. It does not have any + // chipset specific knowlegde, so none of the attributes can be set or + // cleared. Any attempt to set attribute that are already set will succeed, + // and any attempt to set an attribute that is not supported will fail. + // + if (Attributes & (~PrivateData->Attributes)) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +/** + Retrieves the current resource settings of this PCI root bridge in the form of a set of ACPI 2.0 + resource descriptors. + + There are only two resource descriptor types from the ACPI Specification that may be used to + describe the current resources allocated to a PCI root bridge. These are the QWORD Address + Space Descriptor (ACPI 2.0 Section 6.4.3.5.1), and the End Tag (ACPI 2.0 Section 6.4.2.8). The + QWORD Address Space Descriptor can describe memory, I/O, and bus number ranges for dynamic + or fixed resources. The configuration of a PCI root bridge is described with one or more QWORD + Address Space Descriptors followed by an End Tag. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[out] Resources A pointer to the ACPI 2.0 resource descriptors that describe the + current configuration of this PCI root bridge. The storage for the + ACPI 2.0 resource descriptors is allocated by this function. The + caller must treat the return buffer as read-only data, and the buffer + must not be freed by the caller. + + @retval EFI_SUCCESS The current configuration of this PCI root bridge was returned in Resources. + @retval EFI_UNSUPPORTED The current configuration of this PCI root bridge could not be retrieved. + @retval EFI_INVALID_PARAMETER Invalid pointer of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoConfiguration ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT VOID **Resources +) +{ + PCI_ROOT_BRIDGE_INSTANCE *RootBridge; + UINTN Index; + + RootBridge = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This); + + for (Index = 0; Index < ResTypeMax; Index++) { + if (RootBridge->ResAlloc[Index].Length != 0) { + Configuration.SpaceDesp[Index].AddrRangeMin = RootBridge->ResAlloc[Index].Base; + Configuration.SpaceDesp[Index].AddrRangeMax = RootBridge->ResAlloc[Index].Base + RootBridge->ResAlloc[Index].Length - 1; + Configuration.SpaceDesp[Index].AddrLen = RootBridge->ResAlloc[Index].Length; + } + } + + // Set up Configuration for the bus + Configuration.SpaceDesp[Index].AddrRangeMin = RootBridge->BusStart; + Configuration.SpaceDesp[Index].AddrLen = RootBridge->BusLength; + + *Resources = &Configuration; + return EFI_SUCCESS; +} diff --git a/Platform/NXP/Include/PciHostBridge.h b/Platform/NXP/Include/PciHostBridge.h new file mode 100644 index 0000000..cfca971 --- /dev/null +++ b/Platform/NXP/Include/PciHostBridge.h @@ -0,0 +1,466 @@ +/** PciHostBridge.h + The Header file of the Pci Host Bridge Driver + + Some part of code is inspired from EDK II, File: + PcAtChipsetPkg/PciHostBridgeDxe/PciHostBridge.h + + Copyright (c) 2008 - 2010, Intel Corporation. All rights reserved.
+ Copyright 2017 NXP + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _PCI_HOST_BRIDGE_H_ +#define _PCI_HOST_BRIDGE_H_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "PciCntrlLib.h" + +#define MAX_PCI_DEVICE_NUMBER 31 +#define MAX_PCI_FUNCTION_NUMBER 7 +#define MAX_PCI_REG_ADDRESS (SIZE_4KB - 1) + +#define LS_PCIE_CFG0_PHYS_OFF 0x00000000 +#define LS_PCIE_CFG0_SIZE 0x00001000 /* 4k */ +#define LS_PCIE_CFG1_PHYS_OFF 0x00001000 +#define LS_PCIE_CFG1_SIZE 0x00001000 /* 4k */ + +#define LS_PCIE_IO_BUS 0x00000000 +#define LS_PCIE_IO_PHYS_OFF 0x00010000 +#define LS_PCIE_IO_SIZE 0x00010000 /* 64k */ + +#define LS_PCIE_MEM_BUS 0x40000000 +#define LS_PCIE_MEM_PHYS_OFF 0x40000000 +#define LS_PCIE_MEM_SIZE 0x40000000 /* 1 GB */ + +#define PCI_MEM64_SIZE FixedPcdGet64 (PcdPciMmio64Size) + +#define NUM_PCIE_CONTROLLER FixedPcdGet32 (PcdNumPciController) + +#define PCI_MMIO64_BASE_DIFFERENCE 0x800000000 + +typedef enum { + IoOperation, + MemOperation, + PciOperation +} OPERATION_TYPE; + +#define PCI_HOST_BRIDGE_SIGNATURE SIGNATURE_32('p', 'c', 'i', 'h') +typedef struct PCI_HOST_BRIDGE_INSTANCE_ST { + UINTN Signature; + EFI_HANDLE HostBridgeHandle; + EFI_HANDLE ImageHandle; + UINTN RootBridgeNumber[4]; + PCI_ROOT_BRIDGE_INSTANCE *RootBridge; + LIST_ENTRY Head; + BOOLEAN ResourceSubmited; + BOOLEAN CanRestarted; + EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL ResAlloc; +} PCI_HOST_BRIDGE_INSTANCE; + +#define INSTANCE_FROM_RESOURCE_ALLOCATION_THIS(a) \ + CR(a, PCI_HOST_BRIDGE_INSTANCE, ResAlloc, PCI_HOST_BRIDGE_SIGNATURE) + +// +// HostBridge Resource Allocation interface +// +/** + These are the notifications from the PCI bus driver that it is about to enter a certain + phase of the PCI enumeration process. + + This member function can be used to notify the host bridge driver to perform specific actions, + including any chipset-specific initialization, so that the chipset is ready to enter the next phase. + Eight notification points are defined at this time. See belows: + EfiPciHostBridgeBeginEnumeration Resets the host bridge PCI apertures and internal data + structures. The PCI enumerator should issue this notification + before starting a fresh enumeration process. Enumeration cannot + be restarted after sending any other notification such as + EfiPciHostBridgeBeginBusAllocation. + EfiPciHostBridgeBeginBusAllocation The bus allocation phase is about to begin. No specific action is + required here. This notification can be used to perform any + chipset-specific programming. + EfiPciHostBridgeEndBusAllocation The bus allocation and bus programming phase is complete. No + specific action is required here. This notification can be used to + perform any chipset-specific programming. + EfiPciHostBridgeBeginResourceAllocation + The resource allocation phase is about to begin. No specific + action is required here. This notification can be used to perform + any chipset-specific programming. + EfiPciHostBridgeAllocateResources Allocates resources per previously submitted requests for all the PCI + root bridges. These resource settings are returned on the next call to + GetProposedResources(). Before calling NotifyPhase() with a Phase of + EfiPciHostBridgeAllocateResource, the PCI bus enumerator is responsible + for gathering I/O and memory requests for + all the PCI root bridges and submitting these requests using + SubmitResources(). This function pads the resource amount + to suit the root bridge hardware, takes care of dependencies between + the PCI root bridges, and calls the Global Coherency Domain (GCD) + with the allocation request. In the case of padding, the allocated range + could be bigger than what was requested. + EfiPciHostBridgeSetResources Programs the host bridge hardware to decode previously allocated + resources (proposed resources) for all the PCI root bridges. After the + hardware is programmed, reassigning resources will not be supported. + The bus settings are not affected. + EfiPciHostBridgeFreeResources Deallocates resources that were previously allocated for all the PCI + root bridges and resets the I/O and memory apertures to their initial + state. The bus settings are not affected. If the request to allocate + resources fails, the PCI enumerator can use this notification to + deallocate previous resources, adjust the requests, and retry + allocation. + EfiPciHostBridgeEndResourceAllocation The resource allocation phase is completed. No specific action is + required here. This notification can be used to perform any chipsetspecific + programming. + + @param[in] This The instance pointer of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL + @param[in] Phase The phase during enumeration + + @retval EFI_NOT_READY This phase cannot be entered at this time. For example, this error + is valid for a Phase of EfiPciHostBridgeAllocateResources if + SubmitResources() has not been called for one or more + PCI root bridges before this call + @retval EFI_DEVICE_ERROR Programming failed due to a hardware error. This error is valid + for a Phase of EfiPciHostBridgeSetResources. + @retval EFI_INVALID_PARAMETER Invalid phase parameter + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + This error is valid for a Phase of EfiPciHostBridgeAllocateResources if the + previously submitted resource requests cannot be fulfilled or + were only partially fulfilled. + @retval EFI_SUCCESS The notification was accepted without any errors. + +**/ +EFI_STATUS +EFIAPI +PciNotifyPhase( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase + ); + +/** + Return the device handle of the next PCI root bridge that is associated with this Host Bridge. + + This function is called multiple times to retrieve the device handles of all the PCI root bridges that + are associated with this PCI host bridge. Each PCI host bridge is associated with one or more PCI + root bridges. On each call, the handle that was returned by the previous call is passed into the + interface, and on output the interface returns the device handle of the next PCI root bridge. The + caller can use the handle to obtain the instance of the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL + for that root bridge. When there are no more PCI root bridges to report, the interface returns + EFI_NOT_FOUND. A PCI enumerator must enumerate the PCI root bridges in the order that they + are returned by this function. + For D945 implementation, there is only one root bridge in PCI host bridge. + + @param[in] This The instance pointer of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL + @param[in, out] RootBridgeHandle Returns the device handle of the next PCI root bridge. + + @retval EFI_SUCCESS If parameter RootBridgeHandle = NULL, then return the first Rootbridge handle of the + specific Host bridge and return EFI_SUCCESS. + @retval EFI_NOT_FOUND Can not find the any more root bridge in specific host bridge. + @retval EFI_INVALID_PARAMETER RootBridgeHandle is not an EFI_HANDLE that was + returned on a previous call to GetNextRootBridge(). +**/ +EFI_STATUS +EFIAPI +PciGetNextRootBridge( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN OUT EFI_HANDLE *RootBridgeHandle + ); + +/** + Returns the allocation attributes of a PCI root bridge. + + The function returns the allocation attributes of a specific PCI root bridge. The attributes can vary + from one PCI root bridge to another. These attributes are different from the decode-related + attributes that are returned by the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.GetAttributes() member function. The + RootBridgeHandle parameter is used to specify the instance of the PCI root bridge. The device + handles of all the root bridges that are associated with this host bridge must be obtained by calling + GetNextRootBridge(). The attributes are static in the sense that they do not change during or + after the enumeration process. The hardware may provide mechanisms to change the attributes on + the fly, but such changes must be completed before EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL is + installed. The permitted values of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ATTRIBUTES are defined in + "Related Definitions" below. The caller uses these attributes to combine multiple resource requests. + For example, if the flag EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM is set, the PCI bus enumerator needs to + include requests for the prefetchable memory in the nonprefetchable memory pool and not request any + prefetchable memory. + Attribute Description + ------------------------------------ ---------------------------------------------------------------------- + EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM If this bit is set, then the PCI root bridge does not support separate + windows for nonprefetchable and prefetchable memory. A PCI bus + driver needs to include requests for prefetchable memory in the + nonprefetchable memory pool. + + EFI_PCI_HOST_BRIDGE_MEM64_DECODE If this bit is set, then the PCI root bridge supports 64-bit memory + windows. If this bit is not set, the PCI bus driver needs to include + requests for a 64-bit memory address in the corresponding 32-bit + memory pool. + + @param[in] This The instance pointer of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL + @param[in] RootBridgeHandle The device handle of the PCI root bridge in which the caller is interested. Type + EFI_HANDLE is defined in InstallProtocolInterface() in the UEFI 2.0 Specification. + @param[out] Attributes The pointer to attribte of root bridge, it is output parameter + + @retval EFI_INVALID_PARAMETER Attribute pointer is NULL + @retval EFI_INVALID_PARAMETER RootBridgehandle is invalid. + @retval EFI_SUCCESS Success to get attribute of interested root bridge. + +**/ +EFI_STATUS +EFIAPI +PciGetAllocAttributes( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_HANDLE RootBridgeHandle, + OUT UINT64 *Attributes + ); + +/** + Sets up the specified PCI root bridge for the bus enumeration process. + + This member function sets up the root bridge for bus enumeration and returns the PCI bus range + over which the search should be performed in ACPI 2.0 resource descriptor format. + + @param[in] This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance. + @param[in] RootBridgeHandle The PCI Root Bridge to be set up. + @param[out] Configuration Pointer to the pointer to the PCI bus resource descriptor. + + @retval EFI_INVALID_PARAMETER Invalid Root bridge's handle + @retval EFI_OUT_OF_RESOURCES Fail to allocate ACPI resource descriptor tag. + @retval EFI_SUCCESS Sucess to allocate ACPI resource descriptor. + +**/ +EFI_STATUS +EFIAPI +PciStartBusEnumeration( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_HANDLE RootBridgeHandle, + OUT VOID **Configuration + ); + +/** + Programs the PCI root bridge hardware so that it decodes the specified PCI bus range. + + This member function programs the specified PCI root bridge to decode the bus range that is + specified by the input parameter Configuration. + The bus range information is specified in terms of the ACPI 2.0 resource descriptor format. + + @param[in] This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance + @param[in] RootBridgeHandle The PCI Root Bridge whose bus range is to be programmed + @param[in] Configuration The pointer to the PCI bus resource descriptor + + @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid root bridge handle. + @retval EFI_INVALID_PARAMETER Configuration is NULL. + @retval EFI_INVALID_PARAMETER Configuration does not point to a valid ACPI 2.0 resource descriptor. + @retval EFI_INVALID_PARAMETER Configuration does not include a valid ACPI 2.0 bus resource descriptor. + @retval EFI_INVALID_PARAMETER Configuration includes valid ACPI 2.0 resource descriptors other than + bus descriptors. + @retval EFI_INVALID_PARAMETER Configuration contains one or more invalid ACPI resource descriptors. + @retval EFI_INVALID_PARAMETER "Address Range Minimum" is invalid for this root bridge. + @retval EFI_INVALID_PARAMETER "Address Range Length" is invalid for this root bridge. + @retval EFI_DEVICE_ERROR Programming failed due to a hardware error. + @retval EFI_SUCCESS The bus range for the PCI root bridge was programmed. + +**/ +EFI_STATUS +EFIAPI +PciSetBusNumbers( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_HANDLE RootBridgeHandle, + IN VOID *Configuration + ); + +/** + Submits the I/O and memory resource requirements for the specified PCI root bridge. + + This function is used to submit all the I/O and memory resources that are required by the specified + PCI root bridge. The input parameter Configuration is used to specify the following: + - The various types of resources that are required + - The associated lengths in terms of ACPI 2.0 resource descriptor format + + @param[in] This Pointer to the EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance. + @param[in] RootBridgeHandle The PCI root bridge whose I/O and memory resource requirements are being submitted. + @param[in] Configuration The pointer to the PCI I/O and PCI memory resource descriptor. + + @retval EFI_SUCCESS The I/O and memory resource requests for a PCI root bridge were accepted. + @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid root bridge handle. + @retval EFI_INVALID_PARAMETER Configuration is NULL. + @retval EFI_INVALID_PARAMETER Configuration does not point to a valid ACPI 2.0 resource descriptor. + @retval EFI_INVALID_PARAMETER Configuration includes requests for one or more resource types that are + not supported by this PCI root bridge. This error will happen if the caller + did not combine resources according to Attributes that were returned by + GetAllocAttributes(). + @retval EFI_INVALID_PARAMETER Address Range Maximum" is invalid. + @retval EFI_INVALID_PARAMETER "Address Range Length" is invalid for this PCI root bridge. + @retval EFI_INVALID_PARAMETER "Address Space Granularity" is invalid for this PCI root bridge. + +**/ +EFI_STATUS +EFIAPI +PciSubmitResources( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_HANDLE RootBridgeHandle, + IN VOID *Configuration + ); + +/** + Returns the proposed resource settings for the specified PCI root bridge. + + This member function returns the proposed resource settings for the specified PCI root bridge. The + proposed resource settings are prepared when NotifyPhase() is called with a Phase of + EfiPciHostBridgeAllocateResources. The output parameter Configuration + specifies the following: + - The various types of resources, excluding bus resources, that are allocated + - The associated lengths in terms of ACPI 2.0 resource descriptor format + + @param[in] This Pointer to the EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance. + @param[in] RootBridgeHandle The PCI root bridge handle. Type EFI_HANDLE is defined in InstallProtocolInterface() in the UEFI 2.0 Specification. + @param[out] Configuration The pointer to the pointer to the PCI I/O and memory resource descriptor. + + @retval EFI_SUCCESS The requested parameters were returned. + @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid root bridge handle. + @retval EFI_DEVICE_ERROR Programming failed due to a hardware error. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +PciGetProposedResources( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_HANDLE RootBridgeHandle, + OUT VOID **Configuration + ); + +/** + Provides the hooks from the PCI bus driver to every PCI controller (device/function) at various + stages of the PCI enumeration process that allow the host bridge driver to preinitialize individual + PCI controllers before enumeration. + + This function is called during the PCI enumeration process. No specific action is expected from this + member function. It allows the host bridge driver to preinitialize individual PCI controllers before + enumeration. + + @param This Pointer to the EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance. + @param RootBridgeHandle The associated PCI root bridge handle. Type EFI_HANDLE is defined in + InstallProtocolInterface() in the UEFI 2.0 Specification. + @param PciAddress The address of the PCI device on the PCI bus. This address can be passed to the + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL member functions to access the PCI + configuration space of the device. See Table 12-1 in the UEFI 2.0 Specification for + the definition of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS. + @param Phase The phase of the PCI device enumeration. + + @retval EFI_SUCCESS The requested parameters were returned. + @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid root bridge handle. + @retval EFI_INVALID_PARAMETER Phase is not a valid phase that is defined in + EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE. + @retval EFI_DEVICE_ERROR Programming failed due to a hardware error. The PCI enumerator should + not enumerate this device, including its child devices if it is a PCI-to-PCI + bridge. + +**/ +EFI_STATUS +EFIAPI +PciPreprocessController ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This, + IN EFI_HANDLE RootBridgeHandle, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress, + IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase + ); + + +// +// Define resource status constant +// +#define EFI_RESOURCE_NONEXISTENT 0xFFFFFFFFFFFFFFFFULL +#define EFI_RESOURCE_LESS 0xFFFFFFFFFFFFFFFEULL + +// +// Driver Instance Data Prototypes +// + +typedef struct { + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation; + UINTN NumberOfBytes; + UINTN NumberOfPages; + EFI_PHYSICAL_ADDRESS HostAddress; + EFI_PHYSICAL_ADDRESS MappedHostAddress; +} MAP_INFO; + +typedef enum { + ResNone = 0, + ResSubmitted, + ResRequested, + ResAllocated, + ResStatusMax +} RES_STATUS; + +typedef struct { + PCI_RESOURCE_TYPE Type; + UINT64 Base; + UINT64 Length; + UINT64 Alignment; + RES_STATUS Status; +} PCI_RES_NODE; + +#define PCI_ROOT_BRIDGE_SIGNATURE SIGNATURE_32('P', 'C', 'I', '3') + +// +// Driver Instance Data Macros +// +#define DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(a) \ + CR(a, PCI_ROOT_BRIDGE_INSTANCE, Io, PCI_ROOT_BRIDGE_SIGNATURE) + + +#define DRIVER_INSTANCE_FROM_LIST_ENTRY(a) \ + CR(a, PCI_ROOT_BRIDGE_INSTANCE, Link, PCI_ROOT_BRIDGE_SIGNATURE) + +/** + Initialize and create Pci Root Bridges for Board + + @param PrvateData Driver instance of this Root Bridge IO protocol + @param Protocol Point to protocol instance + @param Info Point to Info field of this driver instance + @param HostBridgeHandle Handle of host bridge + @param Attri Attribute of host bridge + @param HostNo HostNo for this Host Bridge + @param Busno Bus Number for the Host Bridge + + @retval EFI_SUCCESS Success to initialize the Pci Root Bridge. + +**/ + +EFI_STATUS +PciRbInitialize ( + IN PCI_ROOT_BRIDGE_INSTANCE *PrivateData, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *Protocol, + IN LsPcieInfo *Info, + IN EFI_HANDLE HostBridgeHandle, + IN UINT64 Attri, + IN INTN HostNo, + IN INTN Busno, + IN UINT64 *PciBaseAddr +); + +/** + Function to return PCI addess space mask +**/ +UINT64 +GetPciAddressSpaceMask ( + IN VOID + ); + +#endif diff --git a/Platform/NXP/Include/PciRootBridge.h b/Platform/NXP/Include/PciRootBridge.h new file mode 100644 index 0000000..cd22e48 --- /dev/null +++ b/Platform/NXP/Include/PciRootBridge.h @@ -0,0 +1,674 @@ +/** PciRootBridge.h + The Header file of the Pci Root Bridge driver + + Copyright 2017 NXP + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _PCI_LS_H_ +#define _PCI_LS_H_ + +#include + +#define MAX_PCI_REGIONS 7 + +typedef UINT64 PciAddrT; +typedef UINT64 PciSizeT; +typedef UINT64 PhysAddrT; +typedef UINT64 PhysSizeT; +typedef INTN PciDevT; + +// +// Protocol Member Function Prototypes +// + +/** + Polls an address in memory mapped I/O space until an exit condition is met, or + a timeout occurs. + + This function provides a standard way to poll a PCI memory location. A PCI memory read + operation is performed at the PCI memory address specified by Address for the width specified + by Width. The result of this PCI memory read operation is stored in Result. This PCI memory + read operation is repeated until either a timeout of Delay 100 ns units has expired, or (Result & + Mask) is equal to Value. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width Signifies the width of the memory operations. + @param[in] Address The base address of the memory operations. The caller is + responsible for aligning Address if required. + @param[in] Mask Mask used for the polling criteria. Bytes above Width in Mask + are ignored. The bits in the bytes below Width which are zero in + Mask are ignored when polling the memory address. + @param[in] Value The comparison value used for the polling exit criteria. + @param[in] Delay The number of 100 ns units to poll. Note that timer available may + be of poorer granularity. + @param[out] Result Pointer to the last value read from the memory location. + + @retval EFI_SUCCESS The last data returned from the access matched the poll exit criteria. + @retval EFI_INVALID_PARAMETER Width is invalid. + @retval EFI_INVALID_PARAMETER Result is NULL. + @retval EFI_TIMEOUT Delay expired before a match occurred. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoPollMem ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ); + +/** + Reads from the I/O space of a PCI Root Bridge. Returns when either the polling exit criteria is + satisfied or after a defined duration. + + This function provides a standard way to poll a PCI I/O location. A PCI I/O read operation is + performed at the PCI I/O address specified by Address for the width specified by Width. + The result of this PCI I/O read operation is stored in Result. This PCI I/O read operation is + repeated until either a timeout of Delay 100 ns units has expired, or (Result & Mask) is equal + to Value. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width Signifies the width of the I/O operations. + @param[in] Address The base address of the I/O operations. The caller is responsible + for aligning Address if required. + @param[in] Mask Mask used for the polling criteria. Bytes above Width in Mask + are ignored. The bits in the bytes below Width which are zero in + Mask are ignored when polling the I/O address. + @param[in] Value The comparison value used for the polling exit criteria. + @param[in] Delay The number of 100 ns units to poll. Note that timer available may + be of poorer granularity. + @param[out] Result Pointer to the last value read from the memory location. + + @retval EFI_SUCCESS The last data returned from the access matched the poll exit criteria. + @retval EFI_INVALID_PARAMETER Width is invalid. + @retval EFI_INVALID_PARAMETER Result is NULL. + @retval EFI_TIMEOUT Delay expired before a match occurred. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoPollIo ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ); + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space. + + The Mem.Read(), and Mem.Write() functions enable a driver to access PCI controller + registers in the PCI root bridge memory space. + The memory operations are carried out exactly as requested. The caller is responsible for satisfying + any alignment and memory width restrictions that a PCI Root Bridge on a platform might require. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width Signifies the width of the memory operation. + @param[in] Address The base address of the memory operation. The caller is + responsible for aligning the Address if required. + @param[in] Count The number of memory operations to perform. Bytes moved is + Width size * Count, starting at Address. + @param[out] Buffer For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoMemRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + OUT VOID *Buffer + ); + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space. + + The Mem.Read(), and Mem.Write() functions enable a driver to access PCI controller + registers in the PCI root bridge memory space. + The memory operations are carried out exactly as requested. The caller is responsible for satisfying + any alignment and memory width restrictions that a PCI Root Bridge on a platform might require. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width Signifies the width of the memory operation. + @param[in] Address The base address of the memory operation. The caller is + responsible for aligning the Address if required. + @param[in] Count The number of memory operations to perform. Bytes moved is + Width size * Count, starting at Address. + @param[in] Buffer For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoMemWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ); + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge I/O space. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width Signifies the width of the memory operations. + @param[in] UserAddress The base address of the I/O operation. The caller is responsible for + aligning the Address if required. + @param[in] Count The number of I/O operations to perform. Bytes moved is Width + size * Count, starting at Address. + @param[out] UserBuffer For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoIoRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + OUT VOID *UserBuffer + ); + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge I/O space. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width Signifies the width of the memory operations. + @param[in] UserAddress The base address of the I/O operation. The caller is responsible for + aligning the Address if required. + @param[in] Count The number of I/O operations to perform. Bytes moved is Width + size * Count, starting at Address. + @param[in] UserBuffer For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoIoWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN VOID *UserBuffer + ); + +/** + Enables a PCI driver to copy one region of PCI root bridge memory space to another region of PCI + root bridge memory space. + + The CopyMem() function enables a PCI driver to copy one region of PCI root bridge memory + space to another region of PCI root bridge memory space. This is especially useful for video scroll + operation on a memory mapped video buffer. + The memory operations are carried out exactly as requested. The caller is responsible for satisfying + any alignment and memory width restrictions that a PCI root bridge on a platform might require. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance. + @param[in] Width Signifies the width of the memory operations. + @param[in] DestAddress The destination address of the memory operation. The caller is + responsible for aligning the DestAddress if required. + @param[in] SrcAddress The source address of the memory operation. The caller is + responsible for aligning the SrcAddress if required. + @param[in] Count The number of memory operations to perform. Bytes moved is + Width size * Count, starting at DestAddress and SrcAddress. + + @retval EFI_SUCCESS The data was copied from one memory region to another memory region. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoCopyMem ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 DestAddress, + IN UINT64 SrcAddress, + IN UINTN Count + ); + +/** + Enables a PCI driver to access PCI controller registers in a PCI root bridge's configuration space. + + The Pci.Read() and Pci.Write() functions enable a driver to access PCI configuration + registers for a PCI controller. + The PCI Configuration operations are carried out exactly as requested. The caller is responsible for + any alignment and PCI configuration width issues that a PCI Root Bridge on a platform might + require. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width Signifies the width of the memory operations. + @param[in] Address The address within the PCI configuration space for the PCI controller. + @param[in] Count The number of PCI configuration operations to perform. Bytes + moved is Width size * Count, starting at Address. + @param[out] Buffer For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoPciRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + OUT VOID *Buffer + ); + +/** + Enables a PCI driver to access PCI controller registers in a PCI root bridge's configuration space. + + The Pci.Read() and Pci.Write() functions enable a driver to access PCI configuration + registers for a PCI controller. + The PCI Configuration operations are carried out exactly as requested. The caller is responsible for + any alignment and PCI configuration width issues that a PCI Root Bridge on a platform might + require. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width Signifies the width of the memory operations. + @param[in] Address The address within the PCI configuration space for the PCI controller. + @param[in] Count The number of PCI configuration operations to perform. Bytes + moved is Width size * Count, starting at Address. + @param[in] Buffer For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoPciWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ); + +/** + Provides the PCI controller-specific addresses required to access system memory from a + DMA bus master. + + The Map() function provides the PCI controller specific addresses needed to access system + memory. This function is used to map system memory for PCI bus master DMA accesses. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Operation Indicates if the bus master is going to read or write to system memory. + @param[in] HostAddress The system memory address to map to the PCI controller. + @param[in, out] NumberOfBytes On input the number of bytes to map. On output the number of bytes that were mapped. + @param[out] DeviceAddress The resulting map address for the bus master PCI controller to use + to access the system memory's HostAddress. + @param[out] Mapping The value to pass to Unmap() when the bus master DMA operation is complete. + + @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes. + @retval EFI_INVALID_PARAMETER Operation is invalid. + @retval EFI_INVALID_PARAMETER HostAddress is NULL. + @retval EFI_INVALID_PARAMETER NumberOfBytes is NULL. + @retval EFI_INVALID_PARAMETER DeviceAddress is NULL. + @retval EFI_INVALID_PARAMETER Mapping is NULL. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer. + @retval EFI_DEVICE_ERROR The system hardware could not map the requested address. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoMap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +/** + Completes the Map() operation and releases any corresponding resources. + + The Unmap() function completes the Map() operation and releases any corresponding resources. + If the operation was an EfiPciOperationBusMasterWrite or + EfiPciOperationBusMasterWrite64, the data is committed to the target system memory. + Any resources used for the mapping are freed. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Mapping The mapping value returned from Map(). + + @retval EFI_SUCCESS The range was unmapped. + @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map(). + @retval EFI_DEVICE_ERROR The data was not committed to the target system memory. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoUnmap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN VOID *Mapping + ); + +/** + Allocates pages that are suitable for an EfiPciOperationBusMasterCommonBuffer or + EfiPciOperationBusMasterCommonBuffer64 mapping. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Type This parameter is not used and must be ignored. + @param MemoryType The type of memory to allocate, EfiBootServicesData or EfiRuntimeServicesData. + @param Pages The number of pages to allocate. + @param HostAddress A pointer to store the base system memory address of the allocated range. + @param Attributes The requested bit mask of attributes for the allocated range. Only + the attributes EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE, EFI_PCI_ATTRIBUTE_MEMORY_CACHED, + and EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE may be used with this function. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_INVALID_PARAMETER MemoryType is invalid. + @retval EFI_INVALID_PARAMETER HostAddress is NULL. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE, MEMORY_CACHED, and DUAL_ADDRESS_CYCLE. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoAllocateBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes + ); + +/** + Frees memory that was allocated with AllocateBuffer(). + + The FreeBuffer() function frees memory that was allocated with AllocateBuffer(). + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Pages The number of pages to free. + @param HostAddress The base system memory address of the allocated range. + + @retval EFI_SUCCESS The requested memory pages were freed. + @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages + was not allocated with AllocateBuffer(). + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoFreeBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINTN Pages, + OUT VOID *HostAddress + ); + +/** + Flushes all PCI posted write transactions from a PCI host bridge to system memory. + + The Flush() function flushes any PCI posted write transactions from a PCI host bridge to system + memory. Posted write transactions are generated by PCI bus masters when they perform write + transactions to target addresses in system memory. + This function does not flush posted write transactions from any PCI bridges. A PCI controller + specific action must be taken to guarantee that the posted write transactions have been flushed from + the PCI controller and from all the PCI bridges into the PCI host bridge. This is typically done with + a PCI read transaction from the PCI controller prior to calling Flush(). + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + + @retval EFI_SUCCESS The PCI posted write transactions were flushed from the PCI host + bridge to system memory. + @retval EFI_DEVICE_ERROR The PCI posted write transactions were not flushed from the PCI + host bridge due to a hardware error. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoFlush ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This + ); + +/** + Gets the attributes that a PCI root bridge supports setting with SetAttributes(), and the + attributes that a PCI root bridge is currently using. + + The GetAttributes() function returns the mask of attributes that this PCI root bridge supports + and the mask of attributes that the PCI root bridge is currently using. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Supported A pointer to the mask of attributes that this PCI root bridge + supports setting with SetAttributes(). + @param Attributes A pointer to the mask of attributes that this PCI root bridge is + currently using. + + @retval EFI_SUCCESS If Supports is not NULL, then the attributes that the PCI root + bridge supports is returned in Supports. If Attributes is + not NULL, then the attributes that the PCI root bridge is currently + using is returned in Attributes. + @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL. + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoGetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT UINT64 *Supported, + OUT UINT64 *Attributes + ); + +/** + Sets attributes for a resource range on a PCI root bridge. + + The SetAttributes() function sets the attributes specified in Attributes for the PCI root + bridge on the resource range specified by ResourceBase and ResourceLength. Since the + granularity of setting these attributes may vary from resource type to resource type, and from + platform to platform, the actual resource range and the one passed in by the caller may differ. As a + result, this function may set the attributes specified by Attributes on a larger resource range + than the caller requested. The actual range is returned in ResourceBase and + ResourceLength. The caller is responsible for verifying that the actual range for which the + attributes were set is acceptable. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Attributes The mask of attributes to set. If the attribute bit + MEMORY_WRITE_COMBINE, MEMORY_CACHED, or + MEMORY_DISABLE is set, then the resource range is specified by + ResourceBase and ResourceLength. If + MEMORY_WRITE_COMBINE, MEMORY_CACHED, and + MEMORY_DISABLE are not set, then ResourceBase and + ResourceLength are ignored, and may be NULL. + @param[in, out] ResourceBase A pointer to the base address of the resource range to be modified + by the attributes specified by Attributes. + @param[in, out] ResourceLength A pointer to the length of the resource range to be modified by the + attributes specified by Attributes. + + @retval EFI_SUCCESS The current configuration of this PCI root bridge was returned in Resources. + @retval EFI_UNSUPPORTED The current configuration of this PCI root bridge could not be retrieved. + @retval EFI_INVALID_PARAMETER Invalid pointer of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoSetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN OUT UINT64 *ResourceBase, + IN OUT UINT64 *ResourceLength + ); + +/** + Retrieves the current resource settings of this PCI root bridge in the form of a set of ACPI 2.0 + resource descriptors. + + There are only two resource descriptor types from the ACPI Specification that may be used to + describe the current resources allocated to a PCI root bridge. These are the QWORD Address + Space Descriptor (ACPI 2.0 Section 6.4.3.5.1), and the End Tag (ACPI 2.0 Section 6.4.2.8). The + QWORD Address Space Descriptor can describe memory, I/O, and bus number ranges for dynamic + or fixed resources. The configuration of a PCI root bridge is described with one or more QWORD + Address Space Descriptors followed by an End Tag. + + @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[out] Resources A pointer to the ACPI 2.0 resource descriptors that describe the + current configuration of this PCI root bridge. The storage for the + ACPI 2.0 resource descriptors is allocated by this function. The + caller must treat the return buffer as read-only data, and the buffer + must not be freed by the caller. + + @retval EFI_SUCCESS The current configuration of this PCI root bridge was returned in Resources. + @retval EFI_UNSUPPORTED The current configuration of this PCI root bridge could not be retrieved. + @retval EFI_INVALID_PARAMETER Invalid pointer of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL + +**/ +EFI_STATUS +EFIAPI +RootBridgeIoConfiguration ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT VOID **Resources + ); + +// Structure for PCI region +typedef struct { + PciAddrT BusStart; // Start on the bus + PhysAddrT PhysStart; // Start in physical address space + PciSizeT Size; // Size + UINT64 Flags; // Resource flags + PciAddrT BusLower; +} PciRegion; + +// Structure for PCI space(I/O,Mem,Configuration) +typedef struct { + UINT64 Regs; + INT32 PciNum; + UINT64 Cfg0Phys; + UINT64 Cfg0Size; + UINT64 Cfg1Phys; + UINT64 Cfg1Size; + UINT64 MemBus; + UINT64 MemPhys; + UINT64 MemSize; + UINT64 IoBus; + UINT64 IoPhys; + UINT64 IoSize; +} LsPcieInfo; + +typedef struct { + INTN Idx; + VOID *Dbi; + UINT32 *VaCfg0; + UINT32 *VaCfg1; +} LsPcie; + +typedef struct { + UINTN Vendor, Device; // Vendor and device ID or PCI_ANY_ID +} PciDeviceId; + +typedef struct { + UINTN Vendor, Device; // Vendor and device ID or PCI_ANY_ID + UINTN Class; // Class ID, or PCI_ANY_ID + UINTN Bus; // Bus number, or PCI_ANY_ID + UINTN Dev; // Device number, or PCI_ANY_ID + UINTN Func; // Function number, or PCI_ANY_ID + UINTN Priv[3]; +} PciConfigTable; + +#define ACPI_SPECFLAG_PREFETCHABLE 0x06 +#define EFI_RESOURCE_NONEXISTENT 0xFFFFFFFFFFFFFFFFULL +#define EFI_RESOURCE_LESS 0xFFFFFFFFFFFFFFFEULL + +typedef struct { + ACPI_HID_DEVICE_PATH AcpiDevicePath; + EFI_DEVICE_PATH_PROTOCOL End; +} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH; + +typedef enum { + ResTypeIo = 0, + ResTypeMem32, + ResTypePMem32, + ResTypeMem64, + ResTypePMem64, + ResTypeMax +} PCI_RESOURCE_TYPE; + +typedef struct { + UINT64 Base; + UINT64 Length; + UINT64 Alignment; +} PCI_RESOURCE_ALLOC; + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + EFI_HANDLE Handle; + UINT64 RootBridgeAttrib; + UINT64 Attributes; + UINT64 Supports; + UINTN BusStart; + UINTN BusLength; + UINT64 MemAllocAttributes; + PCI_RESOURCE_ALLOC ResAlloc[ResTypeMax]; + UINT64 PciBaseAddress64; + UINT64 PciMemBase64; + LsPcieInfo *Info; + LsPcie *Pcie; + struct PCI_ROOT_BRIDGE_INSTANCE *Next; + INTN FirstBusno; + INTN LastBusno; + INTN CurrentBusno; + UINTN *CfgAddr; + CHAR8 *CfgData; + INTN IndirectType; + PciRegion Regions[MAX_PCI_REGIONS]; + INTN RegionCnt; + PciConfigTable *ConfigTable; + + PciRegion *PciMem, *PciIo, *PciPrefetch; + + EFI_PCI_ROOT_BRIDGE_DEVICE_PATH DevicePath; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL Io; + +} PCI_ROOT_BRIDGE_INSTANCE; + +#endif -- 1.9.1