Files
nix-config/packages/edk2/patches/platforms/0014-Platform-RPi5-Add-PCIe-support.patch
2026-01-07 21:28:20 -06:00

5826 lines
193 KiB
Diff

From 6e7fd9d3093cc6bf927058315adf0f1ae1a55c22 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mario=20B=C4=83l=C4=83nic=C4=83?=
<mariobalanica02@gmail.com>
Date: Fri, 15 Mar 2024 02:57:08 +0200
Subject: [PATCH 14/16] Platform/RPi5: Add PCIe support
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This introduces PCIe support to both UEFI and ACPI.
Moreover, it also fixes RP1 USB corruption issues, caused by the
bridge's non-prefetchable memory aperture essentially creating a hole in
the PCIe's view of system RAM (mapped 1:1), through which inbound (DMA)
traffic could not pass anymore.
Therefore, we now reserve up to 1 GB of RAM for 32-bit BARs, which is
automatically reclaimed depending on how much space the connected
devices actually consume. A minimum of 5 MBs are reserved by RP1.
This is only done when ACPI is enabled; FDT uses DMA translation and can
map the entire RAM.
ECAM is still a small 4 KB window, so only a single device function can
be exposed to Windows and Linux. This is possible thanks to a few OS
workarounds:
- for Windows: "NXPMX6" OEM ID in FADT, bus 0 in MCFG is limited to
devfn 0.
- for Linux: "AMAZON" OEM ID + "GRAVITON" OEM Table ID in MCFG. An
"AMZN0001" device with _UID matching the RC segment number returns the
ECAM window in _CRS.
TF-A implements the DEN0115 spec, enabling FreeBSD, NetBSD and ESXi to
scan the entire config space.
The compatibility mode used can be configured in the setup menu. Default
is "Auto (NXPMX6 / Arm DEN0115)", which selects the NXPMX6 mode when
Windows is booted and DEN0115 for other OSes.
Tested with NVME and SATA boot + some Wi-Fi cards.
Signed-off-by: Mario Bălănică <mariobalanica02@gmail.com>
---
.../RaspberryPi/RPi5/AcpiTables/AcpiTables.h | 55 +-
.../RPi5/AcpiTables/AcpiTables.inf | 4 +-
Platform/RaspberryPi/RPi5/AcpiTables/Dsdt.asl | 93 +-
.../RaspberryPi/RPi5/AcpiTables/Mcfg.aslc | 51 +
.../RPi5/AcpiTables/PcieCommon.asi | 107 ++
.../RPi5/Drivers/RpiPlatformDxe/ConfigTable.c | 754 ++++++++-
.../RPi5/Drivers/RpiPlatformDxe/ConfigTable.h | 14 +-
.../RPi5/Drivers/RpiPlatformDxe/Peripherals.c | 78 +-
.../RPi5/Drivers/RpiPlatformDxe/Peripherals.h | 25 +-
.../Drivers/RpiPlatformDxe/RpiPlatformDxe.c | 18 +-
.../Drivers/RpiPlatformDxe/RpiPlatformDxe.h | 15 +
.../Drivers/RpiPlatformDxe/RpiPlatformDxe.inf | 16 +-
.../RpiPlatformDxe/RpiPlatformDxeHii.uni | 40 +-
.../RpiPlatformDxe/RpiPlatformDxeHii.vfr | 70 +-
.../RaspberryPi/RPi5/Include/Rpi5McfgTable.h | 23 +
.../RPi5/Include/RpiPlatformVarStoreData.h | 15 +-
.../RPi5/Library/PlatformLib/RaspberryPiMem.c | 35 +-
Platform/RaspberryPi/RPi5/RPi5.dsc | 20 +-
Platform/RaspberryPi/RPi5/RPi5.fdf | 4 +-
Silicon/Broadcom/Bcm27xx/Bcm27xx.dec | 4 +
.../Include/Bcm2712PcieControllerSettings.h | 27 +
.../Include/IndustryStandard/Bcm2712.h | 16 +-
.../Include/IndustryStandard/Bcm2712Pcie.h | 206 +++
.../Include/Protocol/Bcm2712PciePlatform.h | 28 +
.../Bcm2712PciHostBridge.c | 478 ++++++
.../Bcm2712PciHostBridge.h | 33 +
.../Bcm2712PciHostBridgeLib.c | 326 ++++
.../Bcm2712PciHostBridgeLib.inf | 38 +
.../Bcm2712PciSegmentLib/PciSegmentLib.c | 1456 +++++++++++++++++
.../Bcm2712PciSegmentLib/PciSegmentLib.inf | 31 +
.../Drivers/Rp1BusDxe/ComponentName.c | 323 ++++
.../Drivers/Rp1BusDxe/Rp1BusDxe.c | 463 +++++-
.../Drivers/Rp1BusDxe/Rp1BusDxe.h | 34 +
.../Drivers/Rp1BusDxe/Rp1BusDxe.inf | 11 +-
.../RpiSiliconPkg/Include/Protocol/Rp1Bus.h | 29 +
.../RaspberryPi/RpiSiliconPkg/Include/Rp1.h | 7 +-
.../RpiSiliconPkg/RpiSiliconPkg.dec | 6 +-
37 files changed, 4831 insertions(+), 122 deletions(-)
create mode 100644 Platform/RaspberryPi/RPi5/AcpiTables/Mcfg.aslc
create mode 100644 Platform/RaspberryPi/RPi5/AcpiTables/PcieCommon.asi
create mode 100644 Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/RpiPlatformDxe.h
create mode 100644 Platform/RaspberryPi/RPi5/Include/Rpi5McfgTable.h
create mode 100644 Silicon/Broadcom/Bcm27xx/Include/Bcm2712PcieControllerSettings.h
create mode 100644 Silicon/Broadcom/Bcm27xx/Include/IndustryStandard/Bcm2712Pcie.h
create mode 100644 Silicon/Broadcom/Bcm27xx/Include/Protocol/Bcm2712PciePlatform.h
create mode 100644 Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciHostBridgeLib/Bcm2712PciHostBridge.c
create mode 100644 Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciHostBridgeLib/Bcm2712PciHostBridge.h
create mode 100644 Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciHostBridgeLib/Bcm2712PciHostBridgeLib.c
create mode 100644 Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciHostBridgeLib/Bcm2712PciHostBridgeLib.inf
create mode 100644 Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciSegmentLib/PciSegmentLib.c
create mode 100644 Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciSegmentLib/PciSegmentLib.inf
create mode 100644 Silicon/RaspberryPi/RpiSiliconPkg/Drivers/Rp1BusDxe/ComponentName.c
create mode 100644 Silicon/RaspberryPi/RpiSiliconPkg/Drivers/Rp1BusDxe/Rp1BusDxe.h
create mode 100644 Silicon/RaspberryPi/RpiSiliconPkg/Include/Protocol/Rp1Bus.h
diff --git a/Platform/RaspberryPi/RPi5/AcpiTables/AcpiTables.h b/Platform/RaspberryPi/RPi5/AcpiTables/AcpiTables.h
index 0b965d39..2035a3d3 100644
--- a/Platform/RaspberryPi/RPi5/AcpiTables/AcpiTables.h
+++ b/Platform/RaspberryPi/RPi5/AcpiTables/AcpiTables.h
@@ -1,6 +1,6 @@
/** @file
*
- * Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
+ * Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
@@ -35,6 +35,14 @@
EFI_ACPI_CREATOR_REVISION /* UINT32 CreatorRevision */ \
}
+//
+// Default values for patching, to avoid compiler optimizations.
+//
+#define ACPI_PATCH_QWORD_VALUE 0xABCDEF0123456789
+#define ACPI_PATCH_DWORD_VALUE 0xABCDEF01
+#define ACPI_PATCH_WORD_VALUE 0xABCD
+#define ACPI_PATCH_BYTE_VALUE 0xAB
+
//
// Device resource helpers
//
@@ -43,12 +51,49 @@
MinFixed, MaxFixed, NonCacheable, ReadWrite, \
0x0, 0x0, 0x0, 0x0, 0x1,,, RB ## Index)
-#define QWORDMEMORY_SET(Index, Minimum, Length) \
- CreateQwordField (RBUF, RB ## Index._MIN, MI ## Index) \
- CreateQwordField (RBUF, RB ## Index._MAX, MA ## Index) \
- CreateQwordField (RBUF, RB ## Index._LEN, LE ## Index) \
+#define QWORDIO_BUF(Index, ResourceType) \
+ QWordIO (ResourceType, \
+ MinFixed, MaxFixed, PosDecode, EntireRange, \
+ 0x0, 0x0, 0x0, 0x0, 0x1,,, RB ## Index)
+
+#define DWORDMEMORY_BUF(Index, ResourceType) \
+ DWordMemory (ResourceType,, \
+ MinFixed, MaxFixed, NonCacheable, ReadWrite, \
+ 0x0, 0x0, 0x0, 0x0, 0x1,,, RB ## Index)
+
+#define WORDBUSNUMBER_BUF(Index, ResourceType) \
+ WordBusNumber (ResourceType, \
+ MinFixed, MaxFixed, PosDecode, \
+ 0x0, 0x0, 0x0, 0x0, 0x1,,, RB ## Index)
+
+#define QWORD_SET(Index, Minimum, Length, Translation) \
+ CreateQWordField (RBUF, RB ## Index._MIN, MI ## Index) \
+ CreateQWordField (RBUF, RB ## Index._MAX, MA ## Index) \
+ CreateQWordField (RBUF, RB ## Index._TRA, TR ## Index) \
+ CreateQWordField (RBUF, RB ## Index._LEN, LE ## Index) \
+ LE ## Index = Length \
+ MI ## Index = Minimum \
+ TR ## Index = Translation \
+ MA ## Index = MI ## Index + LE ## Index - 1
+
+#define DWORD_SET(Index, Minimum, Length, Translation) \
+ CreateDWordField (RBUF, RB ## Index._MIN, MI ## Index) \
+ CreateDWordField (RBUF, RB ## Index._MAX, MA ## Index) \
+ CreateDWordField (RBUF, RB ## Index._TRA, TR ## Index) \
+ CreateDWordField (RBUF, RB ## Index._LEN, LE ## Index) \
+ LE ## Index = Length \
+ MI ## Index = Minimum \
+ TR ## Index = Translation \
+ MA ## Index = MI ## Index + LE ## Index - 1
+
+#define WORD_SET(Index, Minimum, Length, Translation) \
+ CreateWordField (RBUF, RB ## Index._MIN, MI ## Index) \
+ CreateWordField (RBUF, RB ## Index._MAX, MA ## Index) \
+ CreateWordField (RBUF, RB ## Index._TRA, TR ## Index) \
+ CreateWordField (RBUF, RB ## Index._LEN, LE ## Index) \
LE ## Index = Length \
MI ## Index = Minimum \
+ TR ## Index = Translation \
MA ## Index = MI ## Index + LE ## Index - 1
//
diff --git a/Platform/RaspberryPi/RPi5/AcpiTables/AcpiTables.inf b/Platform/RaspberryPi/RPi5/AcpiTables/AcpiTables.inf
index 8eef5805..b3ad9787 100644
--- a/Platform/RaspberryPi/RPi5/AcpiTables/AcpiTables.inf
+++ b/Platform/RaspberryPi/RPi5/AcpiTables/AcpiTables.inf
@@ -2,7 +2,7 @@
#
# ACPI table data and ASL sources required to boot the platform.
#
-# Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
+# Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -23,6 +23,7 @@
Madt.aslc
Pptt.aslc
Spcr.aslc
+ Mcfg.aslc
[Packages]
ArmPkg/ArmPkg.dec
@@ -52,4 +53,3 @@
gRaspberryPiTokenSpaceGuid.PcdGicPmuIrq1
gRaspberryPiTokenSpaceGuid.PcdGicPmuIrq2
gRaspberryPiTokenSpaceGuid.PcdGicPmuIrq3
- gRpiSiliconTokenSpaceGuid.Rp1PciPeripheralsBar
diff --git a/Platform/RaspberryPi/RPi5/AcpiTables/Dsdt.asl b/Platform/RaspberryPi/RPi5/AcpiTables/Dsdt.asl
index 62cacf7c..77d41efe 100644
--- a/Platform/RaspberryPi/RPi5/AcpiTables/Dsdt.asl
+++ b/Platform/RaspberryPi/RPi5/AcpiTables/Dsdt.asl
@@ -2,7 +2,7 @@
*
* Differentiated System Definition Table (DSDT)
*
- * Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
+ * Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
@@ -59,7 +59,7 @@ DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RPIFDN", "RPI5 ", 2)
Name (RBUF, ResourceTemplate () {
QWORDMEMORY_BUF (00, ResourceProducer)
})
- QWORDMEMORY_SET (00, BCM2712_LEGACY_BUS_BASE, BCM2712_LEGACY_BUS_LENGTH)
+ QWORD_SET (00, BCM2712_LEGACY_BUS_BASE, BCM2712_LEGACY_BUS_LENGTH, 0)
Return (RBUF)
}
@@ -97,7 +97,7 @@ DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RPIFDN", "RPI5 ", 2)
QWORDMEMORY_BUF (00, ResourceConsumer)
Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { PL011_DEBUG_INTERRUPT }
})
- QWORDMEMORY_SET (00, PL011_DEBUG_BASE_ADDRESS, PL011_DEBUG_LENGTH)
+ QWORD_SET (00, PL011_DEBUG_BASE_ADDRESS, PL011_DEBUG_LENGTH, 0)
Return (RBUF)
}
@@ -110,6 +110,78 @@ DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RPIFDN", "RPI5 ", 2)
}
} // Device (SOCB)
+ //
+ // PCIe Root Complexes
+ //
+ // These (and _STA) are patched by the platform driver:
+ //
+ Name (PBMA, ACPI_PATCH_BYTE_VALUE)
+ Name (BB32, ACPI_PATCH_QWORD_VALUE)
+ Name (MS32, ACPI_PATCH_QWORD_VALUE)
+
+ Device (PCI0) {
+ Name (_SEG, 0)
+ Name (_STA, 0xF)
+
+ Name (CFGB, BCM2712_BRCMSTB_PCIE0_BASE)
+ Name (CFGS, BCM2712_BRCMSTB_PCIE_LENGTH)
+ Name (MB32, BCM2712_BRCMSTB_PCIE0_CPU_MEM_BASE)
+ Name (MB64, BCM2712_BRCMSTB_PCIE0_CPU_MEM64_BASE)
+ Name (MS64, BCM2712_BRCMSTB_PCIE_MEM64_SIZE)
+
+ Name (_PRT, Package () {
+ Package (4) { 0x0FFFF, 0, 0, 241 },
+ Package (4) { 0x0FFFF, 1, 0, 242 },
+ Package (4) { 0x0FFFF, 2, 0, 243 },
+ Package (4) { 0x0FFFF, 3, 0, 244 }
+ })
+
+ Include ("PcieCommon.asi")
+ }
+
+ Device (PCI1) {
+ Name (_SEG, 1)
+ Name (_STA, 0xF)
+
+ Name (CFGB, BCM2712_BRCMSTB_PCIE1_BASE)
+ Name (CFGS, BCM2712_BRCMSTB_PCIE_LENGTH)
+ Name (MB32, BCM2712_BRCMSTB_PCIE1_CPU_MEM_BASE)
+ Name (MB64, BCM2712_BRCMSTB_PCIE1_CPU_MEM64_BASE)
+ Name (MS64, BCM2712_BRCMSTB_PCIE_MEM64_SIZE)
+
+ Name (_PRT, Package () {
+ Package (4) { 0x0FFFF, 0, 0, 251 },
+ Package (4) { 0x0FFFF, 1, 0, 252 },
+ Package (4) { 0x0FFFF, 2, 0, 253 },
+ Package (4) { 0x0FFFF, 3, 0, 254 }
+ })
+
+ Include ("PcieCommon.asi")
+ }
+
+ Device (PCI2) {
+ Name (_SEG, 2)
+ Name (_STA, 0xF)
+
+ Name (CFGB, BCM2712_BRCMSTB_PCIE2_BASE)
+ Name (CFGS, BCM2712_BRCMSTB_PCIE_LENGTH)
+ Name (MB32, BCM2712_BRCMSTB_PCIE2_CPU_MEM_BASE)
+ Name (MB64, BCM2712_BRCMSTB_PCIE2_CPU_MEM64_BASE)
+ Name (MS64, BCM2712_BRCMSTB_PCIE_MEM64_SIZE)
+
+ Name (_PRT, Package () {
+ Package (4) { 0x0FFFF, 0, 0, 261 },
+ Package (4) { 0x0FFFF, 1, 0, 262 },
+ Package (4) { 0x0FFFF, 2, 0, 263 },
+ Package (4) { 0x0FFFF, 3, 0, 264 }
+ })
+
+ Include ("PcieCommon.asi")
+ }
+
+ //
+ // RP1 I/O Bridge
+ //
Device (RP1B) {
Name (_HID, "ACPI0004")
Name (_UID, 0x1)
@@ -117,12 +189,19 @@ DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RPIFDN", "RPI5 ", 2)
// Parent bus is non-coherent
Name (_CCA, 0x0)
- // Firmware mapped BAR
- Name (PBAR, FixedPcdGet64 (Rp1PciPeripheralsBar))
+ // Firmware mapped BAR - patched by platform driver
+ Name (PBAR, ACPI_PATCH_QWORD_VALUE)
// Shared level interrupt - PCIE2 INTA# SPI
Name (PINT, 261)
+ Method (_STA) {
+ If (PBAR == ACPI_PATCH_QWORD_VALUE) {
+ Return (0x0)
+ }
+ Return (0xF)
+ }
+
Include ("Rp1.asi")
}
@@ -183,7 +262,7 @@ DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RPIFDN", "RPI5 ", 2)
QWORDMEMORY_BUF (00, ResourceConsumer)
Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 305 }
})
- QWORDMEMORY_SET (00, BCM2712_BRCMSTB_SDIO1_HOST_BASE, BCM2712_BRCMSTB_SDIO_HOST_LENGTH)
+ QWORD_SET (00, BCM2712_BRCMSTB_SDIO1_HOST_BASE, BCM2712_BRCMSTB_SDIO_HOST_LENGTH, 0)
Return (RBUF)
}
@@ -303,7 +382,7 @@ DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RPIFDN", "RPI5 ", 2)
QWORDMEMORY_BUF (00, ResourceConsumer)
Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 306 }
})
- QWORDMEMORY_SET (00, BCM2712_BRCMSTB_SDIO2_HOST_BASE, BCM2712_BRCMSTB_SDIO_HOST_LENGTH)
+ QWORD_SET (00, BCM2712_BRCMSTB_SDIO2_HOST_BASE, BCM2712_BRCMSTB_SDIO_HOST_LENGTH, 0)
Return (RBUF)
}
diff --git a/Platform/RaspberryPi/RPi5/AcpiTables/Mcfg.aslc b/Platform/RaspberryPi/RPi5/AcpiTables/Mcfg.aslc
new file mode 100644
index 00000000..ed0fb512
--- /dev/null
+++ b/Platform/RaspberryPi/RPi5/AcpiTables/Mcfg.aslc
@@ -0,0 +1,51 @@
+/** @file
+ *
+ * PCI Express Memory-mapped Configuration Space base address description table (MCFG)
+ *
+ * Copyright (c) 2024, Mario Bălănică <mariobalanica02@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#include <Rpi5McfgTable.h>
+
+#include "AcpiTables.h"
+
+//
+// MCFG is patched by RpiPlatformDxe.
+//
+RPI5_MCFG_TABLE Mcfg = {
+ {
+ ACPI_HEADER (
+ EFI_ACPI_6_4_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE,
+ RPI5_MCFG_TABLE,
+ EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_TABLE_REVISION
+ ),
+ },
+ {
+ {
+ BCM2712_BRCMSTB_PCIE0_BASE + PCIE_EXT_CFG_DATA,
+ 0, // PciSegmentNumber
+ 0, // PciBusMin
+ 0, // PciBusMax
+ 0 // Reserved
+ },
+ {
+ BCM2712_BRCMSTB_PCIE1_BASE + PCIE_EXT_CFG_DATA,
+ 1, // PciSegmentNumber
+ 0, // PciBusMin
+ 0, // PciBusMax
+ 0 // Reserved
+ },
+ {
+ BCM2712_BRCMSTB_PCIE2_BASE + PCIE_EXT_CFG_DATA,
+ 2, // PciSegmentNumber
+ 0, // PciBusMin
+ 0, // PciBusMax
+ 0 // Reserved
+ }
+ }
+};
+
+VOID* CONST ReferenceAcpiTable = &Mcfg;
diff --git a/Platform/RaspberryPi/RPi5/AcpiTables/PcieCommon.asi b/Platform/RaspberryPi/RPi5/AcpiTables/PcieCommon.asi
new file mode 100644
index 00000000..630e94ab
--- /dev/null
+++ b/Platform/RaspberryPi/RPi5/AcpiTables/PcieCommon.asi
@@ -0,0 +1,107 @@
+/* @file
+ *
+ * Copyright (c) 2024, Mario Bălănică <mariobalanica02@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ */
+
+#include <IndustryStandard/Bcm2712Pcie.h>
+
+//
+// PBMA - Max Bus Number
+// CFGB - RC Base
+// CFGS - RC Size
+// MB32 - 32-bit memory base
+// BB32 - 32-bit memory bus base
+// MS32 - 32-bit memory size
+// MB64 - 64-bit memory base
+// MS64 - 64-bit memory size
+//
+Name (_HID, "PNP0A08")
+Name (_CID, "PNP0A03")
+Name (_CCA, 0)
+Name (_BBN, 0)
+Method (_UID) {
+ Return (_SEG)
+}
+
+Method (_INI, 0, Serialized) {
+ OperationRegion (OCFG, SystemMemory, CFGB + PCIE_EXT_CFG_INDEX, 0x4)
+ Field (OCFG, DWordAcc, NoLock, Preserve) {
+ CFGI, 32
+ }
+ //
+ // Ensure the small ECAM window is pointing at BDF 01:00.0,
+ // for OSes that can only consume a single-function device.
+ //
+ CFGI = 0x00100000
+}
+
+Method (_CRS, 0, Serialized) {
+ Name (RBUF, ResourceTemplate () {
+ WORDBUSNUMBER_BUF (00, ResourceProducer)
+ QWORDMEMORY_BUF (01, ResourceProducer)
+ QWORDMEMORY_BUF (02, ResourceProducer)
+ })
+ WORD_SET (00, _BBN, (PBMA - _BBN) + 1, 0)
+ QWORD_SET (01, BB32, MS32, MB32 - BB32)
+ QWORD_SET (02, MB64, MS64, 0)
+ Return (RBUF)
+}
+
+Device (RES0) {
+ Name (_HID, "AMZN0001")
+ Name (_CID, "PNP0C02")
+ Method (_UID) {
+ Return (_SEG)
+ }
+ Method (_CRS, 0, Serialized) {
+ Name (RBUF, ResourceTemplate () {
+ QWORDMEMORY_BUF (00, ResourceConsumer)
+ })
+ QWORD_SET (00, CFGB + PCIE_EXT_CFG_DATA, 0x1000, 0)
+ Return (RBUF)
+ }
+}
+
+Name (SUPP, Zero) // PCI _OSC Support Field value
+Name (CTRL, Zero) // PCI _OSC Control Field value
+
+Method (_OSC, 4) {
+ If (Arg0 == ToUUID ("33DB4D5B-1FF7-401C-9657-7441C03DD766")) {
+ // Create DWord-adressable fields from the Capabilities Buffer
+ CreateDWordField (Arg3, 0, CDW1)
+ CreateDWordField (Arg3, 4, CDW2)
+ CreateDWordField (Arg3, 8, CDW3)
+
+ // Save Capabilities DWord2 & 3
+ SUPP = CDW2
+ CTRL = CDW3
+
+ // Mask out native hot plug control
+ CTRL &= 0x1E
+
+ // Always allow native PME, AER and Capability Structure control
+ // Never allow SHPC and LTR control
+ CTRL &= 0x1D
+
+ // Unknown revision
+ If (Arg1 != 1) {
+ Cdw1 |= 0x08
+ }
+
+ // Capabilities bits were masked
+ If (CDW3 != CTRL) {
+ CDW1 |= 0x10
+ }
+
+ // Update DWORD3 in the buffer
+ CDW3 = CTRL
+ Return (Arg3)
+ } Else {
+ // Unrecognized UUID
+ CDW1 |= 4
+ Return (Arg3)
+ }
+}
diff --git a/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/ConfigTable.c b/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/ConfigTable.c
index 9aadb325..bc61e804 100644
--- a/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/ConfigTable.c
+++ b/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/ConfigTable.c
@@ -1,6 +1,6 @@
/** @file
*
- * Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
+ * Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
@@ -8,15 +8,27 @@
#include <Guid/RpiPlatformFormSetGuid.h>
#include <IndustryStandard/Acpi.h>
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/PeImage.h>
#include <Library/AcpiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Protocol/AcpiSystemDescriptionTable.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/Rp1Bus.h>
#include <RpiPlatformVarStoreData.h>
+#include <Rpi5McfgTable.h>
#include <ConfigVars.h>
#include "ConfigTable.h"
+#include "RpiPlatformDxe.h"
+#include "Peripherals.h"
//
// AcpiTables.inf
@@ -28,6 +40,122 @@ STATIC CONST EFI_GUID mAcpiTableFile = {
STATIC ACPI_SD_COMPAT_MODE_VARSTORE_DATA AcpiSdCompatMode;
STATIC ACPI_SD_LIMIT_UHS_VARSTORE_DATA AcpiSdLimitUhs;
+STATIC ACPI_PCIE_ECAM_COMPAT_MODE_VARSTORE_DATA AcpiPcieEcamCompatMode;
+STATIC ACPI_PCIE_32_BIT_BAR_SPACE_SIZE_MB_VARSTORE_DATA AcpiPcie32BitBarSpaceSizeMB;
+
+STATIC BOOLEAN mIsAcpiEnabled;
+STATIC EFI_ACPI_SDT_PROTOCOL *mAcpiSdtProtocol;
+STATIC EFI_ACPI_DESCRIPTION_HEADER *mDsdtTable;
+
+STATIC UINT64 mAcpiPciMem32Base;
+STATIC UINT64 mAcpiPciMem32Size;
+
+STATIC EFI_EXIT_BOOT_SERVICES mOriginalExitBootServices;
+
+typedef enum {
+ AcpiOsUnknown = 0,
+ AcpiOsWindows,
+} ACPI_OS_BOOT_TYPE;
+
+#define SDT_PATTERN_LEN (AML_NAME_SEG_SIZE + 1)
+
+//
+// Simple NameOp integer patcher.
+// Does not allocate memory and can be safely used at ExitBootServices.
+//
+STATIC
+EFI_STATUS
+EFIAPI
+AcpiUpdateSdtNameInteger (
+ IN EFI_ACPI_DESCRIPTION_HEADER *AcpiTable,
+ IN CHAR8 Name[AML_NAME_SEG_SIZE],
+ IN UINTN Value
+ )
+{
+ UINTN Index;
+ CHAR8 Pattern[SDT_PATTERN_LEN];
+ UINT8 *SdtPtr;
+ UINT32 DataSize;
+ UINT32 ValueOffset;
+
+ if (AcpiTable->Length <= SDT_PATTERN_LEN) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SdtPtr = (UINT8 *)AcpiTable;
+ //
+ // Do a single NameOp variable replacement. These are of the
+ // form "08 XXXX SIZE VAL", where SIZE is: 0A=byte, 0B=word, 0C=dword,
+ // XXXX is the name and VAL is the value.
+ //
+ Pattern[0] = AML_NAME_OP;
+ CopyMem (Pattern + 1, Name, AML_NAME_SEG_SIZE);
+
+ ValueOffset = SDT_PATTERN_LEN + 1;
+
+ for (Index = 0; Index < (AcpiTable->Length - SDT_PATTERN_LEN); Index++) {
+ if (CompareMem (SdtPtr + Index, Pattern, SDT_PATTERN_LEN) == 0) {
+ switch (SdtPtr[Index + SDT_PATTERN_LEN]) {
+ case AML_QWORD_PREFIX:
+ DataSize = sizeof (UINT64);
+ break;
+ case AML_DWORD_PREFIX:
+ DataSize = sizeof (UINT32);
+ break;
+ case AML_WORD_PREFIX:
+ DataSize = sizeof (UINT16);
+ break;
+ case AML_ONE_OP:
+ case AML_ZERO_OP:
+ ValueOffset--;
+ // Fallthrough
+ case AML_BYTE_PREFIX:
+ DataSize = sizeof (UINT8);
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ CopyMem (SdtPtr + Index + ValueOffset, &Value, DataSize);
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+STATIC
+VOID
+EFIAPI
+DsdtFixupStatus (
+ IN EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol,
+ IN EFI_ACPI_HANDLE TableHandle
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+
+ struct {
+ CHAR8 *ObjectPath;
+ BOOLEAN Enabled;
+ } DevStatus[] = {
+ { "\\_SB.PCI0._STA", FALSE }, // Not exposed
+ { "\\_SB.PCI1._STA", mPciePlatform.Settings[1].Enabled }, // Configurable
+ { "\\_SB.PCI2._STA", FALSE }, // Reserved by RP1
+ };
+
+ for (Index = 0; Index < ARRAY_SIZE (DevStatus); Index++) {
+ if (DevStatus[Index].Enabled == FALSE) {
+ Status = AcpiAmlObjectUpdateInteger (AcpiSdtProtocol, TableHandle,
+ DevStatus[Index].ObjectPath, 0x0);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to patch %a. Status=%r\n",
+ __func__, DevStatus[Index].ObjectPath, Status));
+ }
+ }
+ }
+}
+
STATIC
VOID
EFIAPI
@@ -51,79 +179,613 @@ DsdtFixupSd (
}
}
+STATIC
+VOID
+EFIAPI
+DsdtFixupRp1 (
+ IN EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol,
+ IN EFI_ACPI_HANDLE TableHandle
+ )
+{
+ EFI_STATUS Status;
+ RP1_BUS_PROTOCOL *Rp1Bus;
+ UINTN HandleCount;
+ EFI_HANDLE *Handles;
+
+ HandleCount = 0;
+ Handles = NULL;
+ Rp1Bus = NULL;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gRp1BusProtocolGuid,
+ NULL,
+ &HandleCount,
+ &Handles
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_WARN,
+ "%a: Failed to locate RP1 instance! Status=%r\n",
+ __func__,
+ Status
+ ));
+ return;
+ }
+
+ if (HandleCount > 1) {
+ DEBUG ((DEBUG_WARN, "%a: Only one RP1 instance is supported!\n", __func__));
+ }
+
+ Status = gBS->HandleProtocol (
+ Handles[0],
+ &gRp1BusProtocolGuid,
+ (VOID **)&Rp1Bus
+ );
+ FreePool (Handles);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_WARN,
+ "%a: Failed to get RP1 bus protocol! Status=%r\n",
+ __func__,
+ Status
+ ));
+ return;
+ }
+
+ Status = AcpiAmlObjectUpdateInteger (
+ AcpiSdtProtocol,
+ TableHandle,
+ "\\_SB.RP1B.PBAR",
+ Rp1Bus->GetPeripheralBase (Rp1Bus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to patch PBAR. Status=%r\n", __func__, Status));
+ }
+}
+
+STATIC
+VOID
+EFIAPI
+DsdtFixupPcie (
+ IN EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol,
+ IN EFI_ACPI_HANDLE TableHandle
+ )
+{
+ EFI_STATUS Status;
+
+ Status = AcpiAmlObjectUpdateInteger (AcpiSdtProtocol, TableHandle,
+ "\\_SB.BB32", mAcpiPciMem32Base);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to patch BB32.\n", __func__));
+ }
+
+ Status = AcpiAmlObjectUpdateInteger (AcpiSdtProtocol, TableHandle,
+ "\\_SB.MS32", mAcpiPciMem32Size);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to patch MS32.\n", __func__));
+ }
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+AcpiFixupPcieEcam (
+ IN ACPI_OS_BOOT_TYPE OsType
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ RPI5_MCFG_TABLE *McfgTable;
+ EFI_ACPI_DESCRIPTION_HEADER *FadtTable;
+ UINTN TableKey;
+ UINT32 PcieEcamMode;
+ UINT8 PcieBusMax;
+
+ Index = 0;
+ Status = AcpiLocateTableBySignature (
+ mAcpiSdtProtocol,
+ EFI_ACPI_6_4_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE,
+ &Index,
+ (EFI_ACPI_DESCRIPTION_HEADER **)&McfgTable,
+ &TableKey);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Couldn't locate ACPI MCFG table! Status=%r\n",
+ __func__, Status));
+ return Status;
+ }
+
+ PcieEcamMode = AcpiPcieEcamCompatMode.Value;
+
+ if (PcieEcamMode == ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6_DEN0115 ||
+ PcieEcamMode == ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6_GRAVITON) {
+ if (OsType == AcpiOsWindows) {
+ PcieEcamMode = ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6;
+ } else {
+ PcieEcamMode &= ~ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6;
+ }
+ }
+
+ switch (PcieEcamMode) {
+ case ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6:
+ PcieBusMax = 0;
+
+ Index = 0;
+ Status = AcpiLocateTableBySignature (
+ mAcpiSdtProtocol,
+ EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE,
+ &Index,
+ &FadtTable,
+ &TableKey);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Couldn't locate ACPI FADT table! Status=%r\n",
+ __func__, Status));
+ return Status;
+ }
+
+ CopyMem (FadtTable->OemId, "NXPMX6", sizeof (FadtTable->OemId));
+ AcpiUpdateChecksum ((UINT8 *)FadtTable, FadtTable->Length);
+ break;
+
+ case ACPI_PCIE_ECAM_COMPAT_MODE_GRAVITON:
+ PcieBusMax = 0;
+
+ CopyMem (McfgTable->Header.Header.OemId, "AMAZON", sizeof (McfgTable->Header.Header.OemId));
+ McfgTable->Header.Header.OemTableId = SIGNATURE_64 ('G','R','A','V','I','T','O','N');
+ McfgTable->Header.Header.OemRevision = 0;
+
+ //
+ // The ECAM window of the single function exposed on bus 0 is obtained
+ // from the "AMZN0001" device in DSDT.
+ // This causes a conflict with the region described in MCFG, but since
+ // the latter is superfluous, we can simply point it to a bogus region
+ // way above the register space.
+ //
+ for (Index = 0; Index < ARRAY_SIZE (McfgTable->Entries); Index++) {
+ McfgTable->Entries[Index].BaseAddress = BASE_1TB + (Index * SIZE_1MB);
+ }
+ break;
+
+ default: // ACPI_PCIE_ECAM_COMPAT_MODE_DEN0115
+ PcieBusMax = PCI_MAX_BUS;
+
+ // MCFG must be hidden.
+ McfgTable->Header.Header.Signature = 0;
+ break;
+ }
+
+ AcpiUpdateChecksum ((UINT8 *)McfgTable, McfgTable->Header.Header.Length);
+
+ AcpiUpdateSdtNameInteger (mDsdtTable, "PBMA", PcieBusMax);
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+VOID
+EFIAPI
+AcpiOsBootHandler (
+ IN ACPI_OS_BOOT_TYPE OsType
+ )
+{
+ if ((mAcpiSdtProtocol == NULL) || (mDsdtTable == NULL)) {
+ ASSERT (FALSE);
+ return;
+ }
+
+ AcpiFixupPcieEcam (OsType);
+
+ AcpiUpdateChecksum ((UINT8 *)mDsdtTable, mDsdtTable->Length);
+}
+
+STATIC
+UINTN
+EFIAPI
+FindPeImageBase (
+ EFI_PHYSICAL_ADDRESS Base
+ )
+{
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+
+ Base &= ~(EFI_PAGE_SIZE - 1);
+
+ while (Base != 0) {
+ DosHdr = (EFI_IMAGE_DOS_HEADER *)Base;
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(Base + DosHdr->e_lfanew);
+ if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
+ break;
+ }
+ }
+
+ Base -= EFI_PAGE_SIZE;
+ }
+
+ return Base;
+}
+
+STATIC CHAR8 mWinLoadNameStr[] = "winload";
+#define PDB_NAME_MAX_LENGTH 256
+
+STATIC
+BOOLEAN
+EFIAPI
+IsPeImageWinLoader (
+ IN VOID *PeImage
+ )
+{
+ CHAR8 *PdbStr;
+ UINTN WinLoadNameStrLen;
+ UINTN Index;
+
+ PdbStr = (CHAR8 *)PeCoffLoaderGetPdbPointer (PeImage);
+ if (PdbStr == NULL) {
+ return FALSE;
+ }
+
+ WinLoadNameStrLen = sizeof (mWinLoadNameStr) - sizeof (CHAR8);
+
+ for (Index = 0; Index < PDB_NAME_MAX_LENGTH && PdbStr[Index] != '\0'; Index++) {
+ if (AsciiStrnCmp (PdbStr + Index, mWinLoadNameStr, WinLoadNameStrLen) == 0) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+AcpiExitBootServicesHook (
+ IN EFI_HANDLE ImageHandle,
+ IN UINTN MapKey
+ )
+{
+ UINTN ReturnAddress;
+ UINTN OsLoaderAddress;
+ ACPI_OS_BOOT_TYPE OsType;
+
+ ReturnAddress = (UINTN)RETURN_ADDRESS (0);
+
+ gBS->ExitBootServices = mOriginalExitBootServices;
+
+ OsType = AcpiOsUnknown;
+
+ OsLoaderAddress = FindPeImageBase (ReturnAddress);
+ if (OsLoaderAddress > 0) {
+ if (IsPeImageWinLoader ((VOID *)OsLoaderAddress)) {
+ OsType = AcpiOsWindows;
+ }
+ }
+
+ AcpiOsBootHandler (OsType);
+
+ return gBS->ExitBootServices (ImageHandle, MapKey);
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+GetPciMem32TotalRange (
+ OUT UINT64 *Base,
+ OUT UINT64 *Size
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_HANDLE *Handles;
+ UINTN HandleCount;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE01 PciConfigHeader;
+ UINT32 MemoryBase;
+ UINT32 MinimumMemoryBase;
+ UINT32 MemoryLimit;
+ UINT32 MaximumMemoryLimit;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &Handles
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ MinimumMemoryBase = MAX_UINT32;
+ MaximumMemoryLimit = 0;
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ Handles[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **)&PciIo
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (PciConfigHeader) / sizeof (UINT32),
+ &PciConfigHeader
+ );
+ if (EFI_ERROR (Status) ||
+ (!IS_PCI_P2P (&PciConfigHeader) &&
+ !IS_PCI_P2P_SUB (&PciConfigHeader)))
+ {
+ continue;
+ }
+
+ MemoryBase = 0;
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ OFFSET_OF (PCI_TYPE01, Bridge.MemoryBase),
+ 1,
+ &MemoryBase
+ );
+ MemoryBase <<= 16;
+
+ if (MinimumMemoryBase > MemoryBase) {
+ MinimumMemoryBase = MemoryBase;
+ }
+
+ MemoryLimit = 0;
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ OFFSET_OF (PCI_TYPE01, Bridge.MemoryLimit),
+ 1,
+ &MemoryLimit
+ );
+ MemoryLimit <<= 16;
+
+ if (MaximumMemoryLimit < MemoryLimit) {
+ MaximumMemoryLimit = MemoryLimit;
+ }
+ }
+
+ FreePool (Handles);
+
+ if (MaximumMemoryLimit == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ *Base = MinimumMemoryBase;
+ *Size = (MaximumMemoryLimit + SIZE_1MB) - MinimumMemoryBase;
+
+ return EFI_SUCCESS;
+}
+
+//
+// See Bcm2712PciHostBridgeLib.c for more details.
+//
+STATIC
+VOID
+EFIAPI
+AdjustPciReservedMemory (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT64 MemoryToReclaimBase;
+ UINT64 MemoryToReclaimSize;
+ UINT64 PciMem32Base;
+ UINT64 PciMem32Size;
+ UINT64 PciMem32PreferredSize;
+
+ //
+ // Initially, we wish to reclaim all system RAM and disable
+ // PCI 32-bit memory if possible.
+ //
+ MemoryToReclaimBase = PCI_RESERVED_MEM32_BASE;
+ MemoryToReclaimSize = PCI_RESERVED_MEM32_SIZE;
+
+ mAcpiPciMem32Base = MemoryToReclaimBase;
+ mAcpiPciMem32Size = 0;
+
+ //
+ // Compute the reserved memory size for ACPI boot.
+ // FDT uses DMA translation and does not need any reserved RAM.
+ //
+ if (mIsAcpiEnabled) {
+ Status = GetPciMem32TotalRange (&PciMem32Base, &PciMem32Size);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Failed to get Mem32 region. Status=%r\n",
+ __func__,
+ Status
+ ));
+
+ PciMem32Base = mAcpiPciMem32Base;
+ PciMem32Size = mAcpiPciMem32Size;
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: Mem32 Base: 0x%lx, Size: 0x%lx\n",
+ __func__,
+ PciMem32Base,
+ PciMem32Size
+ ));
+
+ if ((PciMem32Base < MemoryToReclaimBase) || (PciMem32Size > MemoryToReclaimSize)) {
+ ASSERT (FALSE);
+ DEBUG ((DEBUG_ERROR, "%a: Mem32 region out of reserved bounds!", __func__));
+ goto ReclaimMemoryExit;
+ }
+
+ PciMem32PreferredSize = AcpiPcie32BitBarSpaceSizeMB.Value * 1024 * 1024;
+ if (PciMem32PreferredSize <= MemoryToReclaimSize) {
+ if (PciMem32Size < PciMem32PreferredSize) {
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: Mem32 Preferred Size: 0x%lx\n",
+ __func__,
+ PciMem32PreferredSize
+ ));
+
+ PciMem32Size = PciMem32PreferredSize;
+ }
+ } else {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Mem32 Preferred Size too large: 0x%lx\n",
+ __func__,
+ PciMem32PreferredSize
+ ));
+ }
+
+ mAcpiPciMem32Base = PciMem32Base;
+ mAcpiPciMem32Size = PciMem32Size;
+
+ if (PciMem32Size > 0) {
+ MemoryToReclaimBase = PciMem32Base + PciMem32Size;
+ MemoryToReclaimSize = SIZE_4GB - MemoryToReclaimBase;
+ }
+ }
+
+ReclaimMemoryExit:
+ if ((mSystemMemorySize > PCI_RESERVED_MEM32_BASE) && (MemoryToReclaimSize > 0)) {
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: Reclaiming system RAM - Base: 0x%lx, Size: 0x%lx\n",
+ __func__,
+ MemoryToReclaimBase,
+ MemoryToReclaimSize
+ ));
+
+ Status = gDS->AddMemorySpace (
+ EfiGcdMemoryTypeSystemMemory,
+ MemoryToReclaimBase,
+ MemoryToReclaimSize,
+ EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ Status = gDS->SetMemorySpaceAttributes (
+ MemoryToReclaimBase,
+ MemoryToReclaimSize,
+ EFI_MEMORY_WB
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+}
+
STATIC
EFI_STATUS
EFIAPI
-ApplyDsdtFixups (
+InstallAcpiTables (
VOID
)
{
- EFI_STATUS Status;
- EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol;
- EFI_ACPI_DESCRIPTION_HEADER *Table;
- UINTN TableKey;
- UINTN TableIndex;
- EFI_ACPI_HANDLE TableHandle;
+ EFI_STATUS Status;
+ UINTN TableKey;
+ UINTN TableIndex;
+ EFI_ACPI_HANDLE TableHandle;
Status = gBS->LocateProtocol (
&gEfiAcpiSdtProtocolGuid,
NULL,
- (VOID **)&AcpiSdtProtocol);
+ (VOID **)&mAcpiSdtProtocol
+ );
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Couldn't locate gEfiAcpiSdtProtocolGuid!\n", __func__));
return Status;
}
+ Status = LocateAndInstallAcpiFromFvConditional (&mAcpiTableFile, NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to install ACPI tables!\n"));
+ return Status;
+ }
+
TableIndex = 0;
Status = AcpiLocateTableBySignature (
- AcpiSdtProtocol,
+ mAcpiSdtProtocol,
EFI_ACPI_6_3_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE,
&TableIndex,
- &Table,
- &TableKey);
+ &mDsdtTable,
+ &TableKey
+ );
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Couldn't locate ACPI DSDT table!\n", __func__));
return Status;
}
- Status = AcpiSdtProtocol->OpenSdt (TableKey, &TableHandle);
+ Status = mAcpiSdtProtocol->OpenSdt (TableKey, &TableHandle);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Couldn't open ACPI DSDT table!\n", __func__));
- AcpiSdtProtocol->Close (TableHandle);
+ mAcpiSdtProtocol->Close (TableHandle);
return Status;
}
- DsdtFixupSd (AcpiSdtProtocol, TableHandle);
+ DsdtFixupStatus (mAcpiSdtProtocol, TableHandle);
+ DsdtFixupSd (mAcpiSdtProtocol, TableHandle);
+ DsdtFixupRp1 (mAcpiSdtProtocol, TableHandle);
+ DsdtFixupPcie (mAcpiSdtProtocol, TableHandle);
- AcpiSdtProtocol->Close (TableHandle);
- AcpiUpdateChecksum ((UINT8 *)Table, Table->Length);
+ mAcpiSdtProtocol->Close (TableHandle);
return EFI_SUCCESS;
}
+STATIC
+VOID
+EFIAPI
+OnReadyToBoot (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ gBS->CloseEvent (Event);
+
+ AdjustPciReservedMemory ();
+
+ if (mIsAcpiEnabled) {
+ InstallAcpiTables ();
+ } else {
+ // FDT installation is done by FdtDxe.
+ }
+}
+
VOID
EFIAPI
ApplyConfigTableVariables (
VOID
)
{
- EFI_STATUS Status;
+ EFI_STATUS Status;
+ EFI_EVENT Event;
- if (PcdGet32 (PcdSystemTableMode) != SYSTEM_TABLE_MODE_ACPI
- && PcdGet32 (PcdSystemTableMode) != SYSTEM_TABLE_MODE_BOTH) {
- // FDT is taken care of by FdtDxe.
- return;
- }
+ mIsAcpiEnabled = PcdGet32 (PcdSystemTableMode) == SYSTEM_TABLE_MODE_ACPI ||
+ PcdGet32 (PcdSystemTableMode) == SYSTEM_TABLE_MODE_BOTH;
- Status = LocateAndInstallAcpiFromFvConditional (&mAcpiTableFile, NULL);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "%a: Failed to install ACPI tables!\n"));
- return;
- }
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ OnReadyToBoot,
+ NULL,
+ &gEfiEventReadyToBootGuid,
+ &Event
+ );
+ ASSERT_EFI_ERROR (Status);
- Status = ApplyDsdtFixups ();
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "%a: Failed to apply ACPI DSDT fixups!\n"));
+ if (mIsAcpiEnabled) {
+ mOriginalExitBootServices = gBS->ExitBootServices;
+ gBS->ExitBootServices = AcpiExitBootServicesHook;
}
}
@@ -139,6 +801,8 @@ SetupConfigTableVariables (
AcpiSdCompatMode.Value = ACPI_SD_COMPAT_MODE_DEFAULT;
AcpiSdLimitUhs.Value = ACPI_SD_LIMIT_UHS_DEFAULT;
+ AcpiPcieEcamCompatMode.Value = ACPI_PCIE_ECAM_COMPAT_MODE_DEFAULT;
+ AcpiPcie32BitBarSpaceSizeMB.Value = ACPI_PCIE_32_BIT_BAR_SPACE_SIZE_MB_DEFAULT;
Size = sizeof (ACPI_SD_COMPAT_MODE_VARSTORE_DATA);
Status = gRT->GetVariable (L"AcpiSdCompatMode",
@@ -168,6 +832,34 @@ SetupConfigTableVariables (
ASSERT_EFI_ERROR (Status);
}
+ Size = sizeof (ACPI_PCIE_ECAM_COMPAT_MODE_VARSTORE_DATA);
+ Status = gRT->GetVariable (L"AcpiPcieEcamCompatMode",
+ &gRpiPlatformFormSetGuid,
+ NULL, &Size, &AcpiPcieEcamCompatMode);
+ if (EFI_ERROR (Status)) {
+ Status = gRT->SetVariable (
+ L"AcpiPcieEcamCompatMode",
+ &gRpiPlatformFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ Size,
+ &AcpiPcieEcamCompatMode);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ Size = sizeof (ACPI_PCIE_32_BIT_BAR_SPACE_SIZE_MB_VARSTORE_DATA);
+ Status = gRT->GetVariable (L"AcpiPcie32BitBarSpaceSizeMB",
+ &gRpiPlatformFormSetGuid,
+ NULL, &Size, &AcpiPcie32BitBarSpaceSizeMB);
+ if (EFI_ERROR (Status)) {
+ Status = gRT->SetVariable (
+ L"AcpiPcie32BitBarSpaceSizeMB",
+ &gRpiPlatformFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ Size,
+ &AcpiPcie32BitBarSpaceSizeMB);
+ ASSERT_EFI_ERROR (Status);
+ }
+
Size = sizeof (UINT32);
Status = gRT->GetVariable (L"SystemTableMode",
&gRpiPlatformFormSetGuid,
diff --git a/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/ConfigTable.h b/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/ConfigTable.h
index 8dadc409..5aab3689 100644
--- a/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/ConfigTable.h
+++ b/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/ConfigTable.h
@@ -1,6 +1,6 @@
/** @file
*
- * Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
+ * Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
@@ -11,9 +11,21 @@
#include <RpiPlatformVarStoreData.h>
+//
+// Must match the reserved memory in PlatformLib/RaspberryPiMem.c
+//
+#define PCI_RESERVED_MEM32_BASE 0xC0000000 // 3 GB
+#define PCI_RESERVED_MEM32_SIZE 0x40000000 // 1 GB
+
#define ACPI_SD_COMPAT_MODE_DEFAULT ACPI_SD_COMPAT_MODE_BRCMSTB_BAYTRAIL
#define ACPI_SD_LIMIT_UHS_DEFAULT TRUE
+#define ACPI_PCIE_ECAM_COMPAT_MODE_DEFAULT ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6_DEN0115
+#define ACPI_PCIE_32_BIT_BAR_SPACE_SIZE_MB_MINIMUM 0
+#define ACPI_PCIE_32_BIT_BAR_SPACE_SIZE_MB_MAXIMUM 1024 // (PCI_RESERVED_MEM32_SIZE / 1024 / 1024)
+#define ACPI_PCIE_32_BIT_BAR_SPACE_SIZE_MB_STEP 1
+#define ACPI_PCIE_32_BIT_BAR_SPACE_SIZE_MB_DEFAULT ACPI_PCIE_32_BIT_BAR_SPACE_SIZE_MB_MINIMUM
+
#ifndef VFRCOMPILE
VOID
EFIAPI
diff --git a/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/Peripherals.c b/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/Peripherals.c
index 7cb08635..994485f7 100644
--- a/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/Peripherals.c
+++ b/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/Peripherals.c
@@ -1,6 +1,6 @@
/** @file
*
- * Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
+ * Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
@@ -12,9 +12,12 @@
#include <Library/Bcm2712GpioLib.h>
#include <Library/DebugLib.h>
#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
#include <Protocol/BrcmStbSdhciDevice.h>
#include "Peripherals.h"
+#include "ConfigTable.h"
+#include "RpiPlatformDxe.h"
STATIC
EFI_STATUS
@@ -90,6 +93,46 @@ InitGpioPinctrls (
return EFI_SUCCESS;
}
+BCM2712_PCIE_PLATFORM_PROTOCOL mPciePlatform = {
+ .Mem32BusBase = PCI_RESERVED_MEM32_BASE,
+ .Mem32Size = PCI_RESERVED_MEM32_SIZE,
+
+ .Settings = {
+ [1] = { // Connector (configurable)
+ .Enabled = PCIE1_SETTINGS_ENABLED_DEFAULT,
+ .MaxLinkSpeed = PCIE1_SETTINGS_MAX_LINK_SPEED_DEFAULT
+ },
+ [2] = { // RP1 (fixed)
+ .Enabled = TRUE,
+ .MaxLinkSpeed = 2,
+ .RcbMatchMps = TRUE,
+ .VdmToQosMap = 0xbbaa9888
+ }
+ }
+};
+
+STATIC
+EFI_STATUS
+EFIAPI
+RegisterPciePlatform (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle = NULL;
+
+ ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gBcm2712PciePlatformProtocolGuid);
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gBcm2712PciePlatformProtocolGuid,
+ &mPciePlatform,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
EFI_STATUS
EFIAPI
SetupPeripherals (
@@ -99,6 +142,39 @@ SetupPeripherals (
InitGpioPinctrls ();
RegisterSdControllers ();
+ RegisterPciePlatform ();
return EFI_SUCCESS;
}
+
+VOID
+EFIAPI
+ApplyPeripheralVariables (
+ VOID
+ )
+{
+}
+
+VOID
+EFIAPI
+SetupPeripheralVariables (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+
+ Size = sizeof (BCM2712_PCIE_CONTROLLER_SETTINGS);
+ Status = gRT->GetVariable (L"Pcie1Settings",
+ &gRpiPlatformFormSetGuid,
+ NULL, &Size, &mPciePlatform.Settings[1]);
+ if (EFI_ERROR (Status)) {
+ Status = gRT->SetVariable (
+ L"Pcie1Settings",
+ &gRpiPlatformFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ Size,
+ &mPciePlatform.Settings[1]);
+ ASSERT_EFI_ERROR (Status);
+ }
+}
diff --git a/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/Peripherals.h b/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/Peripherals.h
index ef74a44d..3ef14ebc 100644
--- a/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/Peripherals.h
+++ b/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/Peripherals.h
@@ -1,6 +1,6 @@
/** @file
*
- * Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
+ * Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
@@ -9,10 +9,33 @@
#ifndef __RPI_PLATFORM_PERIPHERALS_H__
#define __RPI_PLATFORM_PERIPHERALS_H__
+#include <Bcm2712PcieControllerSettings.h>
+
+#define PCIE1_SETTINGS_ENABLED_DEFAULT TRUE
+#define PCIE1_SETTINGS_MAX_LINK_SPEED_DEFAULT 2
+
+#ifndef VFRCOMPILE
+ #include <Protocol/Bcm2712PciePlatform.h>
+
EFI_STATUS
EFIAPI
SetupPeripherals (
VOID
);
+VOID
+EFIAPI
+ApplyPeripheralVariables (
+ VOID
+ );
+
+VOID
+EFIAPI
+SetupPeripheralVariables (
+ VOID
+ );
+
+extern BCM2712_PCIE_PLATFORM_PROTOCOL mPciePlatform;
+#endif // VFRCOMPILE
+
#endif // __RPI_PLATFORM_PERIPHERALS_H__
diff --git a/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/RpiPlatformDxe.c b/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/RpiPlatformDxe.c
index c0601b39..dab20b8e 100644
--- a/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/RpiPlatformDxe.c
+++ b/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/RpiPlatformDxe.c
@@ -1,6 +1,6 @@
/** @file
*
- * Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
+ * Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
@@ -8,6 +8,8 @@
#include <Uefi.h>
#include <Guid/RpiPlatformFormSetGuid.h>
+#include <Library/BoardInfoLib.h>
+#include <Library/BoardRevisionHelperLib.h>
#include <Library/DebugLib.h>
#include <Library/DevicePathLib.h>
#include <Library/HiiLib.h>
@@ -16,6 +18,9 @@
#include "ConfigTable.h"
#include "Peripherals.h"
+UINT32 mBoardRevisionCode;
+UINT64 mSystemMemorySize;
+
extern UINT8 RpiPlatformDxeHiiBin[];
extern UINT8 RpiPlatformDxeStrings[];
@@ -90,6 +95,7 @@ SetupVariables (
)
{
SetupConfigTableVariables ();
+ SetupPeripheralVariables ();
}
STATIC
@@ -100,6 +106,7 @@ ApplyVariables (
)
{
ApplyConfigTableVariables ();
+ ApplyPeripheralVariables ();
}
EFI_STATUS
@@ -111,6 +118,15 @@ RpiPlatformDxeEntryPoint (
{
EFI_STATUS Status;
+ Status = BoardInfoGetRevisionCode (&mBoardRevisionCode);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to get board revision. Status=%r\n",
+ __func__, Status));
+ ASSERT (FALSE);
+ }
+
+ mSystemMemorySize = BoardRevisionGetMemorySize (mBoardRevisionCode);
+
SetupVariables ();
ApplyVariables ();
diff --git a/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/RpiPlatformDxe.h b/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/RpiPlatformDxe.h
new file mode 100644
index 00000000..448f7a31
--- /dev/null
+++ b/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/RpiPlatformDxe.h
@@ -0,0 +1,15 @@
+/** @file
+ *
+ * Copyright (c) 2024, Mario Bălănică <mariobalanica02@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#ifndef __RPI_PLATFORM_DXE_H__
+#define __RPI_PLATFORM_DXE_H__
+
+extern UINT32 mBoardRevisionCode;
+extern UINT64 mSystemMemorySize;
+
+#endif // __RPI_PLATFORM_DXE_H__
diff --git a/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/RpiPlatformDxe.inf b/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/RpiPlatformDxe.inf
index 6bb48c3f..ca2f12d8 100644
--- a/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/RpiPlatformDxe.inf
+++ b/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/RpiPlatformDxe.inf
@@ -1,6 +1,6 @@
#/** @file
#
-# Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
+# Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -29,24 +29,36 @@
Platform/RaspberryPi/RPi5/RPi5.dec
Silicon/Broadcom/BroadcomPkg.dec
Silicon/Broadcom/Bcm27xx/Bcm27xx.dec
+ Silicon/RaspberryPi/RpiSiliconPkg/RpiSiliconPkg.dec
[LibraryClasses]
AcpiLib
+ BaseLib
+ BaseMemoryLib
+ Bcm2712GpioLib
+ BoardInfoLib
+ BoardRevisionHelperLib
DebugLib
DevicePathLib
+ DxeServicesTableLib
HiiLib
+ MemoryAllocationLib
+ PeCoffGetEntryPointLib
UefiLib
UefiBootServicesTableLib
UefiRuntimeServicesTableLib
UefiDriverEntryPoint
- Bcm2712GpioLib
[Guids]
gRpiPlatformFormSetGuid
+ gEfiEventReadyToBootGuid
[Protocols]
gEfiAcpiSdtProtocolGuid ## CONSUMES
gBrcmStbSdhciDeviceProtocolGuid ## PRODUCES
+ gRp1BusProtocolGuid ## CONSUMES
+ gEfiPciIoProtocolGuid ## CONSUMES
+ gBcm2712PciePlatformProtocolGuid ## PRODUCES
[Pcd]
gRaspberryPiTokenSpaceGuid.PcdSystemTableMode
diff --git a/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/RpiPlatformDxeHii.uni b/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/RpiPlatformDxeHii.uni
index 5cb460f6..0d29271c 100644
--- a/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/RpiPlatformDxeHii.uni
+++ b/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/RpiPlatformDxeHii.uni
@@ -1,6 +1,6 @@
/** @file
*
- * Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
+ * Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
@@ -9,6 +9,9 @@
#langdef en-US "English"
#string STR_NULL_STRING #language en-US ""
+#string STR_AUTO #language en-US "Auto"
+#string STR_ENABLED #language en-US "Enabled"
+#string STR_DISABLED #language en-US "Disabled"
#string STR_FORM_SET_TITLE #language en-US "Raspberry Pi Configuration"
#string STR_FORM_SET_TITLE_HELP #language en-US "Configure various platform settings."
@@ -48,3 +51,38 @@
"- in 'BRCMSTB + Bay Trail' mode, speed is limited to HS. Disabling this limit is not possible.\n"
"- in 'Full Bay Trail' mode, speed is increased to DDR50. It also becomes possible to disable all other UHS-I limitations.\n\n"
"For FreeBSD: speed falls back to HS. This option has no effect."
+
+#string STR_ACPI_PCIE_SUBTITLE #language en-US "PCI Express"
+
+#string STR_ACPI_PCIE_ECAM_COMPAT_MODE_PROMPT #language en-US "ECAM Compatibility Mode"
+#string STR_ACPI_PCIE_ECAM_COMPAT_MODE_HELP #language en-US "Choose how to expose the non-standard PCIe configuration space to the OS.\n\n"
+ "Arm DEN0115 - compatible with FreeBSD, NetBSD and ESXi Arm Fling. Exposes the full bus hierarchy.\n\n"
+ "NXPMX6 - compatible with Windows. Exposes a single device function at most.\n\n"
+ "AMAZON GRAVITON - compatible with Linux. Exposes a single device function at most.\n\n"
+ "The Auto modes select NXPMX6 for Windows and fall back to the second option when booting other OSes."
+#string STR_ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6_DEN0115 #language en-US "Auto (NXPMX6 / Arm DEN0115)"
+#string STR_ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6_GRAVITON #language en-US "Auto (NXPMX6 / AMAZON GRAVITON)"
+#string STR_ACPI_PCIE_ECAM_COMPAT_MODE_DEN0115 #language en-US "Arm DEN0115"
+#string STR_ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6 #language en-US "NXPMX6"
+#string STR_ACPI_PCIE_ECAM_COMPAT_MODE_GRAVITON #language en-US "AMAZON GRAVITON"
+
+#string STR_ACPI_PCIE_32_BIT_BAR_SPACE_SIZE_MB_PROMPT #language en-US "32-bit BAR Space Preferred Size"
+#string STR_ACPI_PCIE_32_BIT_BAR_SPACE_SIZE_MB_HELP #language en-US "Choose the preferred size (in megabytes) for the non-prefetchable 32-bit BAR space.\n\n"
+ "By default, the firmware automatically reserves the minimum amount required by all devices connected at boot. If you intend to connect devices after the OS has booted, increasing this size might be necessary.\n\n"
+ "Note: reserved space is deducted from system RAM below 4 GB."
+
+/*
+ * PCI Express configuration
+ */
+#string STR_PCIE_FORM_TITLE #language en-US "PCI Express"
+#string STR_PCIE_FORM_HELP #language en-US "Configure the PCIe support."
+
+#string STR_PCIE0_SUBTITLE #language en-US "PCIe Controller #0"
+#string STR_PCIE1_SUBTITLE #language en-US "PCIe Controller #1"
+#string STR_PCIE2_SUBTITLE #language en-US "PCIe Controller #2"
+
+#string STR_PCIE_LINK_SPEED_PROMPT #language en-US "Link Speed"
+#string STR_PCIE_LINK_SPEED_HELP #language en-US "Choose the maximum supported link speed."
+#string STR_PCIE_LINK_SPEED_GEN1 #language en-US "Gen 1 (2.5 GT/s)"
+#string STR_PCIE_LINK_SPEED_GEN2 #language en-US "Gen 2 (5 GT/s)"
+#string STR_PCIE_LINK_SPEED_GEN3 #language en-US "Gen 3 (8 GT/s)"
diff --git a/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/RpiPlatformDxeHii.vfr b/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/RpiPlatformDxeHii.vfr
index e5ee4b3e..71b43219 100644
--- a/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/RpiPlatformDxeHii.vfr
+++ b/Platform/RaspberryPi/RPi5/Drivers/RpiPlatformDxe/RpiPlatformDxeHii.vfr
@@ -1,6 +1,6 @@
/** @file
*
- * Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
+ * Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
@@ -13,6 +13,7 @@
#include <ConfigVars.h>
#include "ConfigTable.h"
+#include "Peripherals.h"
formset
guid = RPI_PLATFORM_FORMSET_GUID,
@@ -35,6 +36,21 @@ formset
name = AcpiSdLimitUhs,
guid = RPI_PLATFORM_FORMSET_GUID;
+ efivarstore ACPI_PCIE_ECAM_COMPAT_MODE_VARSTORE_DATA,
+ attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ name = AcpiPcieEcamCompatMode,
+ guid = RPI_PLATFORM_FORMSET_GUID;
+
+ efivarstore ACPI_PCIE_32_BIT_BAR_SPACE_SIZE_MB_VARSTORE_DATA,
+ attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ name = AcpiPcie32BitBarSpaceSizeMB,
+ guid = RPI_PLATFORM_FORMSET_GUID;
+
+ efivarstore BCM2712_PCIE_CONTROLLER_SETTINGS,
+ attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ name = Pcie1Settings,
+ guid = RPI_PLATFORM_FORMSET_GUID;
+
form formid = 1,
title = STRING_TOKEN(STR_FORM_SET_TITLE);
@@ -44,6 +60,10 @@ formset
goto 0x1000,
prompt = STRING_TOKEN(STR_SYSTEM_TABLE_FORM_TITLE),
help = STRING_TOKEN(STR_SYSTEM_TABLE_FORM_HELP);
+
+ goto 0x1001,
+ prompt = STRING_TOKEN(STR_PCIE_FORM_TITLE),
+ help = STRING_TOKEN(STR_PCIE_FORM_HELP);
endform;
form formid = 0x1000,
@@ -81,6 +101,54 @@ formset
flags = CHECKBOX_DEFAULT | CHECKBOX_DEFAULT_MFG | RESET_REQUIRED,
default = ACPI_SD_LIMIT_UHS_DEFAULT,
endcheckbox;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+ subtitle text = STRING_TOKEN(STR_ACPI_PCIE_SUBTITLE);
+
+ oneof varid = AcpiPcieEcamCompatMode.Value,
+ prompt = STRING_TOKEN(STR_ACPI_PCIE_ECAM_COMPAT_MODE_PROMPT),
+ help = STRING_TOKEN(STR_ACPI_PCIE_ECAM_COMPAT_MODE_HELP),
+ flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED,
+ default = ACPI_PCIE_ECAM_COMPAT_MODE_DEFAULT,
+ option text = STRING_TOKEN(STR_ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6_DEN0115), value = ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6_DEN0115, flags = 0;
+ option text = STRING_TOKEN(STR_ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6_GRAVITON), value = ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6_GRAVITON, flags = 0;
+ option text = STRING_TOKEN(STR_ACPI_PCIE_ECAM_COMPAT_MODE_DEN0115), value = ACPI_PCIE_ECAM_COMPAT_MODE_DEN0115, flags = 0;
+ option text = STRING_TOKEN(STR_ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6), value = ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6, flags = 0;
+ option text = STRING_TOKEN(STR_ACPI_PCIE_ECAM_COMPAT_MODE_GRAVITON), value = ACPI_PCIE_ECAM_COMPAT_MODE_GRAVITON, flags = 0;
+ endoneof;
+
+ numeric varid = AcpiPcie32BitBarSpaceSizeMB.Value,
+ prompt = STRING_TOKEN(STR_ACPI_PCIE_32_BIT_BAR_SPACE_SIZE_MB_PROMPT),
+ help = STRING_TOKEN(STR_ACPI_PCIE_32_BIT_BAR_SPACE_SIZE_MB_HELP),
+ flags = DISPLAY_UINT_DEC | NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED,
+ minimum = ACPI_PCIE_32_BIT_BAR_SPACE_SIZE_MB_MINIMUM,
+ maximum = ACPI_PCIE_32_BIT_BAR_SPACE_SIZE_MB_MAXIMUM,
+ step = ACPI_PCIE_32_BIT_BAR_SPACE_SIZE_MB_STEP,
+ default = ACPI_PCIE_32_BIT_BAR_SPACE_SIZE_MB_DEFAULT,
+ endnumeric;
endif;
endform;
+
+ form formid = 0x1001,
+ title = STRING_TOKEN(STR_PCIE_FORM_TITLE);
+
+ subtitle text = STRING_TOKEN(STR_PCIE1_SUBTITLE);
+
+ checkbox varid = Pcie1Settings.Enabled,
+ prompt = STRING_TOKEN(STR_ENABLED),
+ help = STRING_TOKEN(STR_NULL_STRING),
+ flags = CHECKBOX_DEFAULT | CHECKBOX_DEFAULT_MFG | RESET_REQUIRED,
+ default = PCIE1_SETTINGS_ENABLED_DEFAULT,
+ endcheckbox;
+
+ oneof varid = Pcie1Settings.MaxLinkSpeed,
+ prompt = STRING_TOKEN(STR_PCIE_LINK_SPEED_PROMPT),
+ help = STRING_TOKEN(STR_PCIE_LINK_SPEED_HELP),
+ flags = NUMERIC_SIZE_1 | INTERACTIVE | RESET_REQUIRED,
+ default = PCIE1_SETTINGS_MAX_LINK_SPEED_DEFAULT,
+ option text = STRING_TOKEN(STR_PCIE_LINK_SPEED_GEN1), value = 1, flags = 0;
+ option text = STRING_TOKEN(STR_PCIE_LINK_SPEED_GEN2), value = 2, flags = 0;
+ option text = STRING_TOKEN(STR_PCIE_LINK_SPEED_GEN3), value = 3, flags = 0;
+ endoneof;
+ endform;
endformset;
diff --git a/Platform/RaspberryPi/RPi5/Include/Rpi5McfgTable.h b/Platform/RaspberryPi/RPi5/Include/Rpi5McfgTable.h
new file mode 100644
index 00000000..ea2b4825
--- /dev/null
+++ b/Platform/RaspberryPi/RPi5/Include/Rpi5McfgTable.h
@@ -0,0 +1,23 @@
+/** @file
+ *
+ * Copyright (c) 2024, Mario Bălănică <mariobalanica02@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#ifndef __RPI5_MCFG_TABLE_H__
+#define __RPI5_MCFG_TABLE_H__
+
+#include <IndustryStandard/Bcm2712.h>
+#include <IndustryStandard/Bcm2712Pcie.h>
+#include <IndustryStandard/MemoryMappedConfigurationSpaceAccessTable.h>
+
+#pragma pack(push, 1)
+typedef struct {
+ EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_HEADER Header;
+ EFI_ACPI_MEMORY_MAPPED_ENHANCED_CONFIGURATION_SPACE_BASE_ADDRESS_ALLOCATION_STRUCTURE Entries[BCM2712_BRCMSTB_PCIE_COUNT];
+} RPI5_MCFG_TABLE;
+#pragma pack(pop)
+
+#endif // __RPI5_MCFG_TABLE_H__
diff --git a/Platform/RaspberryPi/RPi5/Include/RpiPlatformVarStoreData.h b/Platform/RaspberryPi/RPi5/Include/RpiPlatformVarStoreData.h
index 374ecb09..5b9bad5c 100644
--- a/Platform/RaspberryPi/RPi5/Include/RpiPlatformVarStoreData.h
+++ b/Platform/RaspberryPi/RPi5/Include/RpiPlatformVarStoreData.h
@@ -1,6 +1,6 @@
/** @file
*
- * Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
+ * Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
@@ -19,4 +19,17 @@ typedef struct {
BOOLEAN Value;
} ACPI_SD_LIMIT_UHS_VARSTORE_DATA;
+#define ACPI_PCIE_ECAM_COMPAT_MODE_DEN0115 0x00000001
+#define ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6 0x00000002
+#define ACPI_PCIE_ECAM_COMPAT_MODE_GRAVITON 0x00000004
+#define ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6_DEN0115 0x00000003
+#define ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6_GRAVITON 0x00000006
+typedef struct {
+ UINT32 Value;
+} ACPI_PCIE_ECAM_COMPAT_MODE_VARSTORE_DATA;
+
+typedef struct {
+ UINT32 Value;
+} ACPI_PCIE_32_BIT_BAR_SPACE_SIZE_MB_VARSTORE_DATA;
+
#endif // __RPI_PLATFORM_VARSTORE_DATA_H__
diff --git a/Platform/RaspberryPi/RPi5/Library/PlatformLib/RaspberryPiMem.c b/Platform/RaspberryPi/RPi5/Library/PlatformLib/RaspberryPiMem.c
index a31085d9..98575625 100644
--- a/Platform/RaspberryPi/RPi5/Library/PlatformLib/RaspberryPiMem.c
+++ b/Platform/RaspberryPi/RPi5/Library/PlatformLib/RaspberryPiMem.c
@@ -1,6 +1,6 @@
/** @file
*
- * Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
+ * Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
* Copyright (c) 2019, Pete Batard <pete@akeo.ie>
* Copyright (c) 2017-2018, Andrey Warkentin <andrey.warkentin@gmail.com>
* Copyright (c) 2014, Linaro Limited. All rights reserved.
@@ -56,6 +56,8 @@ ArmPlatformGetVirtualMemoryMap (
EFI_STATUS Status;
UINT32 RevisionCode = 0;
UINT64 TotalMemorySize;
+ UINT64 MemorySizeBelow3GB;
+ UINT64 MemorySizeBelow4GB;
UINTN Index = 0;
ARM_MEMORY_REGION_DESCRIPTOR *VirtualMemoryTable;
@@ -78,6 +80,9 @@ ArmPlatformGetVirtualMemoryMap (
TotalMemorySize = BoardRevisionGetMemorySize (RevisionCode);
DEBUG ((DEBUG_INFO, "Total RAM: 0x%ll08X\n", TotalMemorySize));
+ MemorySizeBelow3GB = MIN(TotalMemorySize, 3UL * SIZE_1GB);
+ MemorySizeBelow4GB = MIN(TotalMemorySize, 4UL * SIZE_1GB);
+
VirtualMemoryTable = (ARM_MEMORY_REGION_DESCRIPTOR*)AllocatePages
(EFI_SIZE_TO_PAGES (sizeof (ARM_MEMORY_REGION_DESCRIPTOR) *
MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS));
@@ -125,14 +130,36 @@ ArmPlatformGetVirtualMemoryMap (
VirtualMemoryInfo[Index].Type = RPI_MEM_UNMAPPED_REGION;
VirtualMemoryInfo[Index++].Name = L"GPU Reserved";
- // System RAM >= 1 GB
- if (TotalMemorySize > SIZE_1GB) {
+ // Memory in the 1GB - 3GB range is always available.
+ if (MemorySizeBelow3GB > SIZE_1GB) {
VirtualMemoryTable[Index].PhysicalBase = SIZE_1GB;
VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase;
+ VirtualMemoryTable[Index].Length = MemorySizeBelow3GB - VirtualMemoryTable[Index].PhysicalBase;
+ VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK;
+ VirtualMemoryInfo[Index].Type = RPI_MEM_BASIC_REGION;
+ VirtualMemoryInfo[Index++].Name = L"Extended System RAM < 3GB";
+ }
+
+ //
+ // Memory in the 3GB - 4GB range may be reserved for 32-bit PCIe BAR space.
+ // RpiPlatformDxe can reclaim part of it as system RAM depending on the needs.
+ //
+ if (MemorySizeBelow4GB > 3UL * SIZE_1GB) {
+ VirtualMemoryTable[Index].PhysicalBase = 3UL * SIZE_1GB;
+ VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase;
+ VirtualMemoryTable[Index].Length = MemorySizeBelow4GB - VirtualMemoryTable[Index].PhysicalBase;
+ VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK;
+ VirtualMemoryInfo[Index].Type = RPI_MEM_UNMAPPED_REGION;
+ VirtualMemoryInfo[Index++].Name = L"Extended System RAM < 4GB";
+ }
+
+ if (TotalMemorySize > 4UL * SIZE_1GB) {
+ VirtualMemoryTable[Index].PhysicalBase = 4UL * SIZE_1GB;
+ VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase;
VirtualMemoryTable[Index].Length = TotalMemorySize - VirtualMemoryTable[Index].PhysicalBase;
VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK;
VirtualMemoryInfo[Index].Type = RPI_MEM_BASIC_REGION;
- VirtualMemoryInfo[Index++].Name = L"System RAM >= 1GB";
+ VirtualMemoryInfo[Index++].Name = L"Extended System RAM >= 4GB";
}
// SoC device registers
diff --git a/Platform/RaspberryPi/RPi5/RPi5.dsc b/Platform/RaspberryPi/RPi5/RPi5.dsc
index 63e86be3..58eb5dfd 100644
--- a/Platform/RaspberryPi/RPi5/RPi5.dsc
+++ b/Platform/RaspberryPi/RPi5/RPi5.dsc
@@ -1,6 +1,6 @@
# @file
#
-# Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
+# Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
# Copyright (c) 2011 - 2020, ARM Limited. All rights reserved.
# Copyright (c) 2017 - 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
# Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.
@@ -189,6 +189,9 @@
Bcm2712GpioLib|Silicon/Broadcom/Bcm27xx/Library/Bcm2712GpioLib/Bcm2712GpioLib.inf
+ PciHostBridgeLib|Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciHostBridgeLib/Bcm2712PciHostBridgeLib.inf
+ PciSegmentLib|Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciSegmentLib/PciSegmentLib.inf
+
[LibraryClasses.common.SEC]
PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
@@ -414,6 +417,8 @@
gRaspberryPiTokenSpaceGuid.PcdFdtSize|0x20000
+ gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|40
+
# UARTs
gArmPlatformTokenSpaceGuid.PL011UartClkInHz|44000000
gArmPlatformTokenSpaceGuid.PL011UartInterrupt|153
@@ -443,11 +448,6 @@
#
gBcm283xTokenSpaceGuid.PcdBcm2838RngBaseAddress|0x107d208000
- #
- # RP1 BAR1 preconfigured by the VPU
- #
- gRpiSiliconTokenSpaceGuid.Rp1PciPeripheralsBar|0x1f00000000
-
## Default Terminal Type
## 0-PCANSI, 1-VT100, 2-VT00+, 3-UTF8, 4-TTYTERM
gEfiMdePkgTokenSpaceGuid.PcdDefaultTerminalType|4
@@ -663,11 +663,17 @@
# PCI Support
#
ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
- # MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
+ MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf
EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.inf {
<PcdsFixedAtBuild>
+ #
+ # Limit DMA to bottom 3 GB to account for 32-bit BAR space.
+ # We may attempt to reclaim the memory already reserved for this,
+ # so without a hard limit here, devices in UEFI would start running
+ # into corruption issues.
+ #
gEmbeddedTokenSpaceGuid.PcdDmaDeviceOffset|0x00000000
gEmbeddedTokenSpaceGuid.PcdDmaDeviceLimit|0xbfffffff
}
diff --git a/Platform/RaspberryPi/RPi5/RPi5.fdf b/Platform/RaspberryPi/RPi5/RPi5.fdf
index a00b3d98..552160a0 100644
--- a/Platform/RaspberryPi/RPi5/RPi5.fdf
+++ b/Platform/RaspberryPi/RPi5/RPi5.fdf
@@ -1,6 +1,6 @@
## @file
#
-# Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
+# Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
# Copyright (c) 2011 - 2019, ARM Limited. All rights reserved.
# Copyright (c) 2017 - 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
# Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.
@@ -284,7 +284,7 @@ READ_LOCK_STATUS = TRUE
# PCI Support
#
INF ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
- # INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
+ INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
INF MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
INF MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf
INF EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.inf
diff --git a/Silicon/Broadcom/Bcm27xx/Bcm27xx.dec b/Silicon/Broadcom/Bcm27xx/Bcm27xx.dec
index 2ace631f..6e36f6e3 100644
--- a/Silicon/Broadcom/Bcm27xx/Bcm27xx.dec
+++ b/Silicon/Broadcom/Bcm27xx/Bcm27xx.dec
@@ -1,5 +1,6 @@
## @file
#
+# Copyright (c) 2024, Mario Bălănică <mariobalanica02@gmail.com>
# Copyright (c) 2019, Pete Batard <pete@akeo.ie>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -18,6 +19,9 @@
[Guids]
gBcm27xxTokenSpaceGuid = {0x44045e56, 0x7056, 0x4be6, {0x88, 0xc0, 0x49, 0x0c, 0x67, 0x90, 0x2f, 0xba}}
+[Protocols]
+ gBcm2712PciePlatformProtocolGuid = { 0xf411a098, 0xc82b, 0x4920, { 0x90, 0x07, 0xca, 0x70, 0xb3, 0x65, 0x33, 0x89 } }
+
[PcdsFixedAtBuild.common]
gBcm27xxTokenSpaceGuid.PcdBcm27xxRegistersAddress|0x0|UINT32|0x00000001
gBcm27xxTokenSpaceGuid.PcdBcm27xxPciRegBase|0x0|UINT32|0x00000002
diff --git a/Silicon/Broadcom/Bcm27xx/Include/Bcm2712PcieControllerSettings.h b/Silicon/Broadcom/Bcm27xx/Include/Bcm2712PcieControllerSettings.h
new file mode 100644
index 00000000..da5048e7
--- /dev/null
+++ b/Silicon/Broadcom/Bcm27xx/Include/Bcm2712PcieControllerSettings.h
@@ -0,0 +1,27 @@
+/** @file
+ *
+ * Copyright (c) 2024, Mario Bălănică <mariobalanica02@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#ifndef __BCM2712_PCIE_CONTROLLER_SETTINGS_H__
+#define __BCM2712_PCIE_CONTROLLER_SETTINGS_H__
+
+//
+// This may be used in VFR forms and variable store.
+//
+
+#pragma pack (1)
+typedef struct {
+ BOOLEAN Enabled;
+ UINT8 MaxLinkSpeed;
+ BOOLEAN AspmSupportL0s;
+ BOOLEAN AspmSupportL1;
+ BOOLEAN RcbMatchMps;
+ UINT32 VdmToQosMap;
+} BCM2712_PCIE_CONTROLLER_SETTINGS;
+#pragma pack()
+
+#endif // __BCM2712_PCIE_CONTROLLER_SETTINGS_H__
diff --git a/Silicon/Broadcom/Bcm27xx/Include/IndustryStandard/Bcm2712.h b/Silicon/Broadcom/Bcm27xx/Include/IndustryStandard/Bcm2712.h
index c1d1f22f..f2daa41a 100644
--- a/Silicon/Broadcom/Bcm27xx/Include/IndustryStandard/Bcm2712.h
+++ b/Silicon/Broadcom/Bcm27xx/Include/IndustryStandard/Bcm2712.h
@@ -1,6 +1,6 @@
/** @file
*
- * Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
+ * Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
@@ -35,4 +35,18 @@
#define BCM2712_BRCMSTB_SDIO_HOST_LENGTH 0x260
#define BCM2712_BRCMSTB_SDIO_CFG_LENGTH 0x200
+#define BCM2712_BRCMSTB_PCIE0_BASE 0x1000100000
+#define BCM2712_BRCMSTB_PCIE0_CPU_MEM_BASE 0x1700000000
+#define BCM2712_BRCMSTB_PCIE0_CPU_MEM64_BASE 0x1400000000
+#define BCM2712_BRCMSTB_PCIE1_BASE 0x1000110000
+#define BCM2712_BRCMSTB_PCIE1_CPU_MEM_BASE 0x1b00000000
+#define BCM2712_BRCMSTB_PCIE1_CPU_MEM64_BASE 0x1800000000
+#define BCM2712_BRCMSTB_PCIE2_BASE 0x1000120000
+#define BCM2712_BRCMSTB_PCIE2_CPU_MEM_BASE 0x1f00000000
+#define BCM2712_BRCMSTB_PCIE2_CPU_MEM64_BASE 0x1c00000000
+#define BCM2712_BRCMSTB_PCIE_LENGTH 0x9310
+#define BCM2712_BRCMSTB_PCIE_MEM_SIZE 0xfffffffc
+#define BCM2712_BRCMSTB_PCIE_MEM64_SIZE 0x300000000
+#define BCM2712_BRCMSTB_PCIE_COUNT 3
+
#endif // __BCM2712_H__
diff --git a/Silicon/Broadcom/Bcm27xx/Include/IndustryStandard/Bcm2712Pcie.h b/Silicon/Broadcom/Bcm27xx/Include/IndustryStandard/Bcm2712Pcie.h
new file mode 100644
index 00000000..d751bddd
--- /dev/null
+++ b/Silicon/Broadcom/Bcm27xx/Include/IndustryStandard/Bcm2712Pcie.h
@@ -0,0 +1,206 @@
+/** @file
+ *
+ * Copyright (c) 2024, Mario Bălănică <mariobalanica02@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#ifndef __BCM2712_PCIE_H__
+#define __BCM2712_PCIE_H__
+
+#define BRCM_PCIE_CAP_REGS 0x00ac
+#define PCIE_LINK_CAPABILITIES 0xc
+#define PCIE_LINK_CAPABILITIES_SUPPORTED_LINK_SPEED_MASK 0xf
+#define PCIE_LINK_STATUS 0x12
+#define PCIE_LINK_STATUS_LINK_SPEED_MASK 0xf
+#define PCIE_LINK_STATUS_LINK_WIDTH_SHIFT 4
+#define PCIE_LINK_STATUS_LINK_WIDTH_MASK (0x3f << 4)
+#define PCIE_LINK_CONTROL_2 0x30
+#define PCIE_LINK_CONTROL_2_TARGET_LINK_SPEED_MASK 0xf
+
+#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1 0x0188
+#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_SHIFT 2
+#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK (0x3 << 2)
+#define PCIE_RC_CFG_VENDOR_SPCIFIC_REG1_LITTLE_ENDIAN 0x0
+
+#define PCIE_RC_CFG_PRIV1_ID_VAL3 0x043c
+#define PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK 0xffffff
+
+#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY 0x04dc
+#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_SHIFT 10
+#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK (0x3 << 10)
+#define PCIE_LINK_STATE_L0S BIT0
+#define PCIE_LINK_STATE_L1 BIT1
+#define PCIE_LINK_STATE_CLKPM BIT2
+#define PCIE_LINK_STATE_L1_1 BIT3
+#define PCIE_LINK_STATE_L1_2 BIT4
+#define PCIE_LINK_STATE_L1_1_PCIPM BIT5
+#define PCIE_LINK_STATE_L1_2_PCIPM BIT6
+
+#define PCIE_RC_TL_VDM_CTL0 0x0a20
+#define PCIE_RC_TL_VDM_CTL0_VDM_ENABLED_MASK 0x10000
+#define PCIE_RC_TL_VDM_CTL0_VDM_IGNORETAG_MASK 0x20000
+#define PCIE_RC_TL_VDM_CTL0_VDM_IGNOREVNDRID_MASK 0x40000
+
+#define PCIE_RC_TL_VDM_CTL1 0x0a0c
+#define PCIE_RC_TL_VDM_CTL1_VDM_VNDRID0_MASK 0x0000ffff
+#define PCIE_RC_TL_VDM_CTL1_VDM_VNDRID1_MASK 0xffff0000
+
+#define PCIE_RC_DL_MDIO_ADDR 0x1100
+#define PCIE_RC_DL_MDIO_CMD_SHIFT 20
+#define PCIE_RC_DL_MDIO_CMD_MASK (0xfff << 20)
+#define PCIE_RC_DL_MDIO_CMD_READ 0x1
+#define PCIE_RC_DL_MDIO_CMD_WRITE 0x0
+#define PCIE_RC_DL_MDIO_PORT_SHIFT 16
+#define PCIE_RC_DL_MDIO_PORT_MASK (0xf << 16)
+#define PCIE_RC_DL_MDIO_REGAD_SHIFT 0
+#define PCIE_RC_DL_MDIO_REGAD_MASK (0xffff << 0)
+
+#define PCIE_RC_DL_MDIO_PACKET(_Port, _Reg, _Cmd) \
+ (_Port << PCIE_RC_DL_MDIO_PORT_SHIFT | \
+ _Reg << PCIE_RC_DL_MDIO_REGAD_SHIFT | \
+ _Cmd << PCIE_RC_DL_MDIO_CMD_SHIFT)
+
+#define PCIE_RC_DL_MDIO_WR_DATA 0x1104
+#define PCIE_RC_DL_MDIO_RD_DATA 0x1108
+#define PCIE_RC_DL_MDIO_DATA_SHIFT 0
+#define PCIE_RC_DL_MDIO_DATA_MASK (0x7fffffff << 0)
+#define PCIE_RC_DL_MDIO_DATA_DONE_MASK 0x80000000
+
+#define PCIE_RC_PL_PHY_CTL_15 0x184c
+#define PCIE_RC_PL_PHY_CTL_15_PM_CLK_PERIOD_MASK 0xff
+
+#define PCIE_MISC_MISC_CTRL 0x4008
+#define PCIE_MISC_MISC_CTRL_PCIE_RCB_64B_MODE_MASK 0x80
+#define PCIE_MISC_MISC_CTRL_PCIE_RCB_MPS_MODE_MASK 0x400
+#define PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK 0x1000
+#define PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK 0x2000
+#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_SHIFT 20
+#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK (0x3 << 20)
+#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_128 1
+#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_256 2
+#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_512 3
+#define PCIE_MISC_MISC_CTRL_SCB0_SIZE_SHIFT 27
+#define PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK (0x1f << 27)
+#define PCIE_MISC_MISC_CTRL_SCB1_SIZE_SHIFT 22
+#define PCIE_MISC_MISC_CTRL_SCB1_SIZE_MASK (0x1f << 22)
+#define PCIE_MISC_MISC_CTRL_SCB2_SIZE_SHIFT 0
+#define PCIE_MISC_MISC_CTRL_SCB2_SIZE_MASK (0x1f << 0)
+
+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO 0x400c
+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI 0x4010
+
+#define PCIE_MEM_WIN_LO(_Idx) PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO + ((_Idx) * 8)
+#define PCIE_MEM_WIN_HI(_Idx) PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI + ((_Idx) * 8)
+
+#define PCIE_MISC_RC_BAR1_CONFIG_LO 0x402c
+#define PCIE_MISC_RC_BAR1_CONFIG_HI 0x4030
+
+#define PCIE_MISC_RC_BAR2_CONFIG_LO 0x4034
+#define PCIE_MISC_RC_BAR2_CONFIG_HI 0x4038
+
+#define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c
+#define PCIE_MISC_RC_BAR3_CONFIG_HI 0x4040
+
+#define PCIE_MISC_RC_CONFIG_RETRY_TIMEOUT 0x405c
+
+#define PCIE_MISC_PCIE_CTRL 0x4064
+#define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK 0x1
+#define PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_MASK 0x4
+
+#define PCIE_MISC_PCIE_STATUS 0x4068
+#define PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_MASK 0x20
+#define PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK 0x10
+#define PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK 0x40
+
+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT 0x4070
+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN_BASE_LIMIT_MASK_BITS 12
+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN_BASE_LIMIT_LIMIT_SHIFT 20
+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN_BASE_LIMIT_LIMIT_MASK (0xfff << 20)
+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN_BASE_LIMIT_BASE_SHIFT 4
+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN_BASE_LIMIT_BASE_MASK (0xfff << 4)
+
+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI 0x4080
+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN_BASE_HI_BASE_MASK 0xff
+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI 0x4084
+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN_LIMIT_HI_LIMIT_MASK 0xff
+
+#define PCIE_MEM_WIN_BASE_LIMIT(_Idx) (PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT + ((_Idx) * 4))
+#define PCIE_MEM_WIN_BASE_HI(_Idx) (PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI + ((_Idx) * 8))
+#define PCIE_MEM_WIN_LIMIT_HI(_Idx) (PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI + ((_Idx) * 8))
+
+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG 0x4304
+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK 0x2
+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_PERST_ASSERT_MASK 0x8
+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000
+#define PCIE_BMIPS_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x00800000
+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_L1SS_ENABLE_MASK 0x00200000
+
+#define PCIE_MISC_CTRL_1 0x40A0
+#define PCIE_MISC_CTRL_1_OUTBOUND_TC_MASK 0xf
+#define PCIE_MISC_CTRL_1_OUTBOUND_NO_SNOOP_MASK BIT3
+#define PCIE_MISC_CTRL_1_OUTBOUND_RO_MASK BIT4
+#define PCIE_MISC_CTRL_1_EN_VDM_QOS_CONTROL_MASK BIT5
+
+#define PCIE_MISC_UBUS_CTRL 0x40a4
+#define PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_ERR_DIS_MASK BIT13
+#define PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_DECERR_DIS_MASK BIT19
+
+#define PCIE_MISC_UBUS_TIMEOUT 0x40A8
+
+#define PCIE_MISC_UBUS_BAR1_CONFIG_REMAP_LO 0x40ac
+#define PCIE_MISC_UBUS_BAR1_CONFIG_REMAP_HI 0x40b0
+
+#define PCIE_MISC_UBUS_BAR2_CONFIG_REMAP_LO 0x40b4
+#define PCIE_MISC_UBUS_BAR2_CONFIG_REMAP_HI 0x40b8
+
+#define PCIE_MISC_RC_BAR4_CONFIG_LO 0x40d4
+#define PCIE_MISC_RC_BAR4_CONFIG_HI 0x40d8
+#define PCIE_MISC_RC_BAR_CONFIG_LO_SIZE_MASK 0x1f
+
+#define PCIE_IB_WIN_LO(_Idx) \
+ ((_Idx == 0) ? PCIE_MISC_RC_BAR2_CONFIG_LO \
+ : PCIE_MISC_RC_BAR4_CONFIG_LO + ((_Idx - 1) * 8))
+
+#define PCIE_IB_WIN_HI(_Idx) \
+ ((_Idx == 0) ? PCIE_MISC_RC_BAR2_CONFIG_HI \
+ : PCIE_MISC_RC_BAR4_CONFIG_HI + ((_Idx - 1) * 8))
+
+#define PCIE_MISC_UBUS_BAR_CONFIG_REMAP_ENABLE BIT0
+#define PCIE_MISC_UBUS_BAR_CONFIG_REMAP_LO_MASK 0xfffff000
+#define PCIE_MISC_UBUS_BAR_CONFIG_REMAP_HI_MASK 0xff
+#define PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_LO 0x410c
+#define PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_HI 0x4110
+
+#define PCIE_IB_WIN_REMAP_LO(_Idx) \
+ ((_Idx == 0) ? PCIE_MISC_UBUS_BAR2_CONFIG_REMAP_LO \
+ : PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_LO + ((_Idx - 1) * 8))
+
+#define PCIE_IB_WIN_REMAP_HI(_Idx) \
+ ((_Idx == 0) ? PCIE_MISC_UBUS_BAR2_CONFIG_REMAP_HI \
+ : PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_HI + ((_Idx - 1) * 8))
+
+#define PCIE_MISC_VDM_PRIORITY_TO_QOS_MAP_HI 0x4164
+#define PCIE_MISC_VDM_PRIORITY_TO_QOS_MAP_LO 0x4168
+
+#define PCIE_MISC_AXI_INTF_CTRL 0x416C
+#define AXI_REQFIFO_EN_QOS_PROPAGATION BIT7
+
+#define PCIE_MISC_AXI_READ_ERROR_DATA 0x4170
+
+#define PCIE_INTR2_CPU_BASE 0x4400
+#define PCIE_INTR2_CPU_MASK_SET 0x10
+#define PCIE_INTR2_CPU_MASK_CLR 0x14
+
+#define PCIE_EXT_CFG_DATA 0x8000
+#define PCIE_EXT_CFG_INDEX 0x9000
+
+#define MDIO_PHY_SET_ADDR_OFFSET 0x1f
+
+#define PCIE_NUM_INBOUND_WINDOWS 8
+#define PCIE_NUM_OUTBOUND_WINDOWS 4
+
+#define PCI_INVALID_ADDRESS 0xffffffff
+
+#endif // __BCM2712_PCIE_H__
diff --git a/Silicon/Broadcom/Bcm27xx/Include/Protocol/Bcm2712PciePlatform.h b/Silicon/Broadcom/Bcm27xx/Include/Protocol/Bcm2712PciePlatform.h
new file mode 100644
index 00000000..467b2d62
--- /dev/null
+++ b/Silicon/Broadcom/Bcm27xx/Include/Protocol/Bcm2712PciePlatform.h
@@ -0,0 +1,28 @@
+/** @file
+ *
+ * Copyright (c) 2024, Mario Bălănică <mariobalanica02@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#ifndef __BCM2712_PCIE_PLATFORM_H__
+#define __BCM2712_PCIE_PLATFORM_H__
+
+#include <IndustryStandard/Bcm2712.h>
+#include <Bcm2712PcieControllerSettings.h>
+
+#define BCM2712_PCIE_PLATFORM_PROTOCOL_GUID \
+ { 0xf411a098, 0xc82b, 0x4920, { 0x90, 0x07, 0xca, 0x70, 0xb3, 0x65, 0x33, 0x89 } }
+
+typedef struct _BCM2712_PCIE_PLATFORM_PROTOCOL BCM2712_PCIE_PLATFORM_PROTOCOL;
+
+struct _BCM2712_PCIE_PLATFORM_PROTOCOL {
+ EFI_PHYSICAL_ADDRESS Mem32BusBase;
+ UINTN Mem32Size;
+ BCM2712_PCIE_CONTROLLER_SETTINGS Settings[BCM2712_BRCMSTB_PCIE_COUNT];
+};
+
+extern EFI_GUID gBcm2712PciePlatformProtocolGuid;
+
+#endif // __BCM2712_PCIE_PLATFORM_H__
diff --git a/Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciHostBridgeLib/Bcm2712PciHostBridge.c b/Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciHostBridgeLib/Bcm2712PciHostBridge.c
new file mode 100644
index 00000000..b2bfabd4
--- /dev/null
+++ b/Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciHostBridgeLib/Bcm2712PciHostBridge.c
@@ -0,0 +1,478 @@
+/** @file
+ *
+ * Copyright (c) 2024, Mario Bălănică <mariobalanica02@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#include <Uefi.h>
+#include <IndustryStandard/Bcm2712.h>
+#include <IndustryStandard/Bcm2712Pcie.h>
+#include <IndustryStandard/Pci.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "Bcm2712PciHostBridge.h"
+
+EFI_STATUS
+PciePhyRead (
+ IN BCM2712_PCIE_RC *Pcie,
+ IN UINT8 Register,
+ OUT UINT16 *Value
+ )
+{
+ UINT32 Retry;
+ UINT32 Data;
+
+ MmioWrite32 (
+ Pcie->Base + PCIE_RC_DL_MDIO_ADDR,
+ PCIE_RC_DL_MDIO_PACKET (0, Register, PCIE_RC_DL_MDIO_CMD_READ)
+ );
+ MmioRead32 (Pcie->Base + PCIE_RC_DL_MDIO_ADDR);
+
+ for (Retry = 10; Retry > 0; Retry--) {
+ Data = MmioRead32 (Pcie->Base + PCIE_RC_DL_MDIO_RD_DATA);
+ if ((Data & PCIE_RC_DL_MDIO_DATA_DONE_MASK) != 0) {
+ *Value = (Data & PCIE_RC_DL_MDIO_DATA_MASK) >> PCIE_RC_DL_MDIO_DATA_SHIFT;
+ return EFI_SUCCESS;
+ }
+
+ gBS->Stall (10);
+ }
+
+ return EFI_TIMEOUT;
+}
+
+STATIC
+EFI_STATUS
+PciePhyWrite (
+ IN BCM2712_PCIE_RC *Pcie,
+ IN UINT8 Register,
+ IN UINT16 Value
+ )
+{
+ UINT32 Retry;
+ UINT32 Data;
+
+ MmioWrite32 (
+ Pcie->Base + PCIE_RC_DL_MDIO_ADDR,
+ PCIE_RC_DL_MDIO_PACKET (0, Register, PCIE_RC_DL_MDIO_CMD_WRITE)
+ );
+ MmioRead32 (Pcie->Base + PCIE_RC_DL_MDIO_ADDR);
+ MmioWrite32 (Pcie->Base + PCIE_RC_DL_MDIO_WR_DATA, PCIE_RC_DL_MDIO_DATA_DONE_MASK | Value);
+
+ for (Retry = 10; Retry > 0; Retry--) {
+ Data = MmioRead32 (Pcie->Base + PCIE_RC_DL_MDIO_WR_DATA);
+ if ((Data & PCIE_RC_DL_MDIO_DATA_DONE_MASK) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ gBS->Stall (10);
+ }
+
+ return EFI_TIMEOUT;
+}
+
+STATIC
+VOID
+PcieSetupPhy (
+ IN BCM2712_PCIE_RC *Pcie
+ )
+{
+ // Enable PHY SerDes
+ MmioAnd32 (
+ Pcie->Base + PCIE_MISC_HARD_PCIE_HARD_DEBUG,
+ ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK
+ );
+ gBS->Stall (100);
+
+ // Allow a 54 MHz reference clock
+ PciePhyWrite (Pcie, MDIO_PHY_SET_ADDR_OFFSET, 0x1600);
+ PciePhyWrite (Pcie, 0x16, 0x50b9);
+ PciePhyWrite (Pcie, 0x17, 0xbda1);
+ PciePhyWrite (Pcie, 0x18, 0x0094);
+ PciePhyWrite (Pcie, 0x19, 0x97b4);
+ PciePhyWrite (Pcie, 0x1b, 0x5030);
+ PciePhyWrite (Pcie, 0x1c, 0x5030);
+ PciePhyWrite (Pcie, 0x1e, 0x0007);
+ gBS->Stall (100);
+
+ // Tweak PM period for 54 MHz clock
+ MmioAndThenOr32 (
+ Pcie->Base + PCIE_RC_PL_PHY_CTL_15,
+ ~PCIE_RC_PL_PHY_CTL_15_PM_CLK_PERIOD_MASK,
+ 18 // ns
+ );
+}
+
+STATIC
+UINTN
+PcieEncodeInboundSize (
+ IN UINT64 Size
+ )
+{
+ UINTN Log2Size;
+
+ Log2Size = HighBitSet64 (Size);
+
+ if ((Log2Size >= 12) && (Log2Size <= 15)) {
+ // 4KB - 32KB
+ return (Log2Size - 12) + 0x1c;
+ } else if ((Log2Size >= 16) && (Log2Size <= 36)) {
+ // 64KB - 64GB
+ return Log2Size - 15;
+ }
+
+ return 0;
+}
+
+STATIC
+VOID
+PcieSetupInboundWindow (
+ IN BCM2712_PCIE_RC *Pcie,
+ IN UINT32 Index,
+ IN EFI_PHYSICAL_ADDRESS CpuBase,
+ IN EFI_PHYSICAL_ADDRESS BusBase,
+ IN UINTN Size
+ )
+{
+ UINT32 InboundSize;
+
+ InboundSize = PcieEncodeInboundSize (Size);
+
+ MmioWrite32 (
+ Pcie->Base + PCIE_IB_WIN_LO (Index),
+ ((UINT32)BusBase & ~PCIE_MISC_RC_BAR_CONFIG_LO_SIZE_MASK) | InboundSize
+ );
+ MmioWrite32 (Pcie->Base + PCIE_IB_WIN_HI (Index), BusBase >> 32);
+
+ MmioWrite32 (
+ Pcie->Base + PCIE_IB_WIN_REMAP_LO (Index),
+ ((UINT32)CpuBase & PCIE_MISC_UBUS_BAR_CONFIG_REMAP_LO_MASK) |
+ PCIE_MISC_UBUS_BAR_CONFIG_REMAP_ENABLE
+ );
+ MmioWrite32 (
+ Pcie->Base + PCIE_IB_WIN_REMAP_HI (Index),
+ (CpuBase >> 32) & PCIE_MISC_UBUS_BAR_CONFIG_REMAP_HI_MASK
+ );
+
+ if (Index == 0) {
+ // Set memory controller size based on the primary window.
+ MmioAndThenOr32 (
+ Pcie->Base + PCIE_MISC_MISC_CTRL,
+ ~PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK,
+ InboundSize << PCIE_MISC_MISC_CTRL_SCB0_SIZE_SHIFT
+ );
+ }
+}
+
+STATIC
+VOID
+PcieSetupOutboundWindow (
+ IN BCM2712_PCIE_RC *Pcie,
+ IN UINT32 Index,
+ IN EFI_PHYSICAL_ADDRESS CpuBase,
+ IN EFI_PHYSICAL_ADDRESS BusBase,
+ IN UINTN Size
+ )
+{
+ EFI_PHYSICAL_ADDRESS CpuBaseMB;
+ EFI_PHYSICAL_ADDRESS CpuLimitMB;
+
+ CpuBaseMB = CpuBase / SIZE_1MB;
+ CpuLimitMB = (CpuBase + Size - 1) / SIZE_1MB;
+
+ MmioAndThenOr32 (
+ Pcie->Base + PCIE_MEM_WIN_BASE_LIMIT (Index),
+ ~(PCIE_MISC_CPU_2_PCIE_MEM_WIN_BASE_LIMIT_BASE_MASK |
+ PCIE_MISC_CPU_2_PCIE_MEM_WIN_BASE_LIMIT_LIMIT_MASK),
+ CpuBaseMB << PCIE_MISC_CPU_2_PCIE_MEM_WIN_BASE_LIMIT_BASE_SHIFT |
+ CpuLimitMB << PCIE_MISC_CPU_2_PCIE_MEM_WIN_BASE_LIMIT_LIMIT_SHIFT
+ );
+
+ MmioAndThenOr32 (
+ Pcie->Base + PCIE_MEM_WIN_BASE_HI (Index),
+ ~PCIE_MISC_CPU_2_PCIE_MEM_WIN_BASE_HI_BASE_MASK,
+ CpuBaseMB >> PCIE_MISC_CPU_2_PCIE_MEM_WIN_BASE_LIMIT_MASK_BITS
+ );
+
+ MmioAndThenOr32 (
+ Pcie->Base + PCIE_MEM_WIN_LIMIT_HI (Index),
+ ~PCIE_MISC_CPU_2_PCIE_MEM_WIN_LIMIT_HI_LIMIT_MASK,
+ CpuLimitMB >> PCIE_MISC_CPU_2_PCIE_MEM_WIN_BASE_LIMIT_MASK_BITS
+ );
+
+ MmioWrite32 (Pcie->Base + PCIE_MEM_WIN_LO (Index), (UINT32)BusBase);
+ MmioWrite32 (Pcie->Base + PCIE_MEM_WIN_HI (Index), BusBase >> 32);
+}
+
+STATIC
+VOID
+PcieSetupAxiQosPriority (
+ IN BCM2712_PCIE_RC *Pcie
+ )
+{
+ MmioAnd32 (Pcie->Base + PCIE_MISC_AXI_INTF_CTRL, ~AXI_REQFIFO_EN_QOS_PROPAGATION);
+
+ if (Pcie->Settings->VdmToQosMap == 0) {
+ MmioAnd32 (Pcie->Base + PCIE_MISC_CTRL_1, ~PCIE_MISC_CTRL_1_EN_VDM_QOS_CONTROL_MASK);
+ return;
+ }
+
+ MmioOr32 (Pcie->Base + PCIE_MISC_CTRL_1, PCIE_MISC_CTRL_1_EN_VDM_QOS_CONTROL_MASK);
+
+ MmioWrite32 (Pcie->Base + PCIE_MISC_VDM_PRIORITY_TO_QOS_MAP_LO, Pcie->Settings->VdmToQosMap);
+ MmioWrite32 (Pcie->Base + PCIE_MISC_VDM_PRIORITY_TO_QOS_MAP_HI, Pcie->Settings->VdmToQosMap);
+
+ MmioWrite32 (Pcie->Base + PCIE_RC_TL_VDM_CTL1, 0);
+
+ MmioOr32 (
+ Pcie->Base + PCIE_RC_TL_VDM_CTL0,
+ PCIE_RC_TL_VDM_CTL0_VDM_ENABLED_MASK |
+ PCIE_RC_TL_VDM_CTL0_VDM_IGNORETAG_MASK |
+ PCIE_RC_TL_VDM_CTL0_VDM_IGNOREVNDRID_MASK
+ );
+}
+
+STATIC
+VOID
+PcieSetupAspm (
+ IN BCM2712_PCIE_RC *Pcie
+ )
+{
+ UINT32 Data;
+ UINT32 AspmCaps;
+
+ Data = MmioRead32 (Pcie->Base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
+ Data &= ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK;
+ Data &= ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_L1SS_ENABLE_MASK;
+ //
+ // TODO: BCM2712 cannot support both L1 and L1SS at the same time.
+ // Only allow L1 for now, but we should read the capabilities of
+ // the endpoint and pick L1SS if possible.
+ //
+ Data |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK;
+ MmioWrite32 (Pcie->Base + PCIE_MISC_HARD_PCIE_HARD_DEBUG, Data);
+
+ AspmCaps = 0;
+
+ if (Pcie->Settings->AspmSupportL0s) {
+ AspmCaps |= PCIE_LINK_STATE_L0S;
+ }
+
+ if (Pcie->Settings->AspmSupportL1) {
+ AspmCaps |= PCIE_LINK_STATE_L1;
+ }
+
+ MmioAndThenOr32 (
+ Pcie->Base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY,
+ ~PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK,
+ AspmCaps << PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_SHIFT
+ );
+}
+
+STATIC
+VOID
+PcieSetupLinkSpeed (
+ IN BCM2712_PCIE_RC *Pcie,
+ IN UINT8 Speed
+ )
+{
+ if (Speed == 0) {
+ return;
+ }
+
+ MmioAndThenOr16 (
+ Pcie->Base + BRCM_PCIE_CAP_REGS + PCIE_LINK_CONTROL_2,
+ ~PCIE_LINK_CONTROL_2_TARGET_LINK_SPEED_MASK,
+ Speed
+ );
+
+ MmioAndThenOr32 (
+ Pcie->Base + BRCM_PCIE_CAP_REGS + PCIE_LINK_CAPABILITIES,
+ ~PCIE_LINK_CAPABILITIES_SUPPORTED_LINK_SPEED_MASK,
+ Speed
+ );
+}
+
+STATIC
+VOID
+PcieAssertPerst (
+ IN BCM2712_PCIE_RC *Pcie,
+ IN BOOLEAN Value
+ )
+{
+ MmioAndThenOr32 (
+ Pcie->Base + PCIE_MISC_PCIE_CTRL,
+ ~PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_MASK,
+ Value ? 0 : PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_MASK
+ );
+}
+
+STATIC
+BOOLEAN
+PcieIsLinkUp (
+ IN BCM2712_PCIE_RC *Pcie
+ )
+{
+ UINT32 Status;
+
+ Status = MmioRead32 (Pcie->Base + PCIE_MISC_PCIE_STATUS);
+
+ return (Status & (PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_MASK |
+ PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK)) != 0;
+}
+
+STATIC
+EFI_STATUS
+PcieWaitForLinkUp (
+ IN BCM2712_PCIE_RC *Pcie
+ )
+{
+ UINT32 Retry;
+ UINT16 LinkStatus;
+ UINT8 LinkSpeed;
+ UINT8 LinkWidth;
+
+ // Wait up to 100 ms
+ for (Retry = 20; Retry > 0; Retry--) {
+ if (PcieIsLinkUp (Pcie)) {
+ break;
+ }
+
+ gBS->Stall (5000);
+ }
+
+ if (Retry == 0) {
+ DEBUG ((DEBUG_ERROR, "PCIe: Link down (timeout)\n"));
+ return EFI_TIMEOUT;
+ }
+
+ LinkStatus = MmioRead16 (Pcie->Base + BRCM_PCIE_CAP_REGS + PCIE_LINK_STATUS);
+ LinkSpeed = LinkStatus & PCIE_LINK_STATUS_LINK_SPEED_MASK;
+ LinkWidth = (LinkStatus & PCIE_LINK_STATUS_LINK_WIDTH_MASK) >> PCIE_LINK_STATUS_LINK_WIDTH_SHIFT;
+
+ DEBUG ((DEBUG_INFO, "PCIe: Link up (Gen %d x%d)\n", LinkSpeed, LinkWidth));
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+PcieInitRc (
+ IN BCM2712_PCIE_RC *Pcie
+ )
+{
+ DEBUG ((DEBUG_INIT, "PCIe: Base: 0x%lx\n", Pcie->Base));
+ DEBUG ((DEBUG_INIT, "PCIe: Settings->MaxLinkSpeed: %d\n", Pcie->Settings->MaxLinkSpeed));
+ DEBUG ((DEBUG_INIT, "PCIe: Settings->AspmSupportL0s: %d\n", Pcie->Settings->AspmSupportL0s));
+ DEBUG ((DEBUG_INIT, "PCIe: Settings->AspmSupportL1: %d\n", Pcie->Settings->AspmSupportL1));
+ DEBUG ((DEBUG_INIT, "PCIe: Settings->RcbMatchMps: %d\n", Pcie->Settings->RcbMatchMps));
+ DEBUG ((DEBUG_INIT, "PCIe: Settings->VdmToQosMap: %x\n", Pcie->Settings->VdmToQosMap));
+
+ //
+ // The VPU firmware has already deasserted the bridge resets.
+ // Only touch PERST.
+ //
+ PcieAssertPerst (Pcie, TRUE);
+ gBS->Stall (100);
+
+ PcieSetupPhy (Pcie);
+
+ MmioAndThenOr32 (
+ Pcie->Base + PCIE_MISC_MISC_CTRL,
+ ~PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK,
+ PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_128 << PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_SHIFT |
+ PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK |
+ PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK |
+ Pcie->Settings->RcbMatchMps ? PCIE_MISC_MISC_CTRL_PCIE_RCB_MPS_MODE_MASK : 0
+ );
+
+ //
+ // Disable AXI bus errors to avoid Arm SError exceptions
+ // when the link is down.
+ //
+ MmioOr32 (
+ Pcie->Base + PCIE_MISC_UBUS_CTRL,
+ PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_ERR_DIS_MASK |
+ PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_DECERR_DIS_MASK
+ );
+ MmioWrite32 (Pcie->Base + PCIE_MISC_AXI_READ_ERROR_DATA, PCI_INVALID_ADDRESS);
+
+ //
+ // Set UBUS timeout to ~250ms and CRS timeout to ~240ms.
+ //
+ MmioWrite32 (Pcie->Base + PCIE_MISC_UBUS_TIMEOUT, 0xb2d0000);
+ MmioWrite32 (Pcie->Base + PCIE_MISC_RC_CONFIG_RETRY_TIMEOUT, 0xaba0000);
+
+ PcieSetupAxiQosPriority (Pcie);
+
+ //
+ // Disable GISB & SCB windows
+ //
+ MmioAnd32 (Pcie->Base + PCIE_MISC_RC_BAR1_CONFIG_LO, ~PCIE_MISC_RC_BAR_CONFIG_LO_SIZE_MASK);
+ MmioAnd32 (Pcie->Base + PCIE_MISC_RC_BAR3_CONFIG_LO, ~PCIE_MISC_RC_BAR_CONFIG_LO_SIZE_MASK);
+
+ //
+ // Map inbound windows
+ //
+ PcieSetupInboundWindow (
+ Pcie,
+ 0,
+ Pcie->Inbound.CpuBase,
+ Pcie->Inbound.BusBase,
+ Pcie->Inbound.Size
+ );
+
+ //
+ // Map outbound windows
+ //
+ PcieSetupOutboundWindow (
+ Pcie,
+ 0,
+ Pcie->Mem32.CpuBase,
+ Pcie->Mem32.BusBase,
+ Pcie->Mem32.Size
+ );
+
+ PcieSetupOutboundWindow (
+ Pcie,
+ 1,
+ Pcie->Mem64.CpuBase,
+ Pcie->Mem64.BusBase,
+ Pcie->Mem64.Size
+ );
+
+ // Clear and mask interrupts
+ MmioWrite32 (Pcie->Base + PCIE_INTR2_CPU_BASE + PCIE_INTR2_CPU_MASK_CLR, 0xffffffff);
+ MmioWrite32 (Pcie->Base + PCIE_INTR2_CPU_BASE + PCIE_INTR2_CPU_MASK_SET, 0xffffffff);
+
+ // Program PCI to PCI bridge class into the root port
+ MmioAndThenOr32 (
+ Pcie->Base + PCIE_RC_CFG_PRIV1_ID_VAL3,
+ ~PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK,
+ ((PCI_CLASS_BRIDGE << 8) | PCI_CLASS_BRIDGE_P2P) << 8
+ );
+
+ // PCIe->SCB little-endian mode for BAR
+ MmioAndThenOr32 (
+ Pcie->Base + PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1,
+ ~PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK,
+ PCIE_RC_CFG_VENDOR_SPCIFIC_REG1_LITTLE_ENDIAN
+ << PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_SHIFT
+ );
+
+ PcieSetupLinkSpeed (Pcie, Pcie->Settings->MaxLinkSpeed);
+
+ PcieSetupAspm (Pcie);
+
+ // Start link-up
+ PcieAssertPerst (Pcie, FALSE);
+ gBS->Stall (100000);
+
+ PcieWaitForLinkUp (Pcie);
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciHostBridgeLib/Bcm2712PciHostBridge.h b/Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciHostBridgeLib/Bcm2712PciHostBridge.h
new file mode 100644
index 00000000..6e6723a8
--- /dev/null
+++ b/Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciHostBridgeLib/Bcm2712PciHostBridge.h
@@ -0,0 +1,33 @@
+/** @file
+ *
+ * Copyright (c) 2024, Mario Bălănică <mariobalanica02@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#ifndef __BCM2712_PCI_HOST_BRIDGE_H__
+#define __BCM2712_PCI_HOST_BRIDGE_H__
+
+#include <Protocol/Bcm2712PciePlatform.h>
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS CpuBase;
+ EFI_PHYSICAL_ADDRESS BusBase;
+ UINTN Size;
+} BCM_PCIE_RC_WINDOW;
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS Base;
+ BCM_PCIE_RC_WINDOW Inbound;
+ BCM_PCIE_RC_WINDOW Mem32;
+ BCM_PCIE_RC_WINDOW Mem64;
+ BCM2712_PCIE_CONTROLLER_SETTINGS *Settings;
+} BCM2712_PCIE_RC;
+
+EFI_STATUS
+PcieInitRc (
+ IN BCM2712_PCIE_RC *Pcie
+ );
+
+#endif // __BCM2712_PCI_HOST_BRIDGE_H__
diff --git a/Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciHostBridgeLib/Bcm2712PciHostBridgeLib.c b/Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciHostBridgeLib/Bcm2712PciHostBridgeLib.c
new file mode 100644
index 00000000..a655f57e
--- /dev/null
+++ b/Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciHostBridgeLib/Bcm2712PciHostBridgeLib.c
@@ -0,0 +1,326 @@
+/** @file
+ *
+ * Broadcom BCM2712 PCI Host Bridge Library
+ *
+ * This implementation configures the PCIe RCs as close to standard as
+ * possible, to accomodate ACPI OS usage.
+ *
+ * The inbound and 64-bit outbound windows are identity mapped, while the
+ * 32-bit non-prefetchable one is translated. Since this window must be
+ * located below 4 GB, it inevitably overlaps a part of the inbound window.
+ * This alone is not an issue; however, once the bridge's aperture is
+ * programmed, inbound (DMA) traffic cannot pass through it anymore.
+ *
+ * In order to avoid DMA corruption, the platform must ensure that the decoded
+ * aperture (Memory Base - Limit in the root port configuration) is not used
+ * for DMA, either by reserving system RAM or by imposing a limit.
+ *
+ * Copyright (c) 2024, Mario Bălănică <mariobalanica02@gmail.com>
+ * Copyright (c) 2017, Linaro Ltd. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#include <Uefi.h>
+#include <IndustryStandard/Bcm2712.h>
+#include <IndustryStandard/Pci.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PciHostBridgeLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/PciHostBridgeResourceAllocation.h>
+
+#include "Bcm2712PciHostBridge.h"
+
+#pragma pack(1)
+typedef struct {
+ ACPI_HID_DEVICE_PATH AcpiDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
+} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH;
+#pragma pack ()
+
+STATIC CONST EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mPciDevicePathTemplate[] = {
+ {
+ {
+ {
+ ACPI_DEVICE_PATH,
+ ACPI_DP,
+ {
+ (UINT8)(sizeof (ACPI_HID_DEVICE_PATH)),
+ (UINT8)(sizeof (ACPI_HID_DEVICE_PATH) >> 8)
+ }
+ },
+ EISA_PNP_ID (0x0A08), // PCI Express
+ 0
+ },
+
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ END_DEVICE_PATH_LENGTH,
+ 0
+ }
+ }
+ },
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+CHAR16 *mPciHostBridgeLibAcpiAddressSpaceTypeStr[] = {
+ L"Mem", L"I/O", L"Bus"
+};
+
+STATIC BCM2712_PCIE_RC mPcieRcs[BCM2712_BRCMSTB_PCIE_COUNT] = {
+ {
+ .Base = BCM2712_BRCMSTB_PCIE0_BASE,
+ .Mem32 ={
+ .CpuBase = BCM2712_BRCMSTB_PCIE0_CPU_MEM_BASE
+ },
+ .Mem64 ={
+ .CpuBase = BCM2712_BRCMSTB_PCIE0_CPU_MEM64_BASE,
+ .BusBase = BCM2712_BRCMSTB_PCIE0_CPU_MEM64_BASE,
+ .Size = BCM2712_BRCMSTB_PCIE_MEM64_SIZE
+ }
+ },
+ {
+ .Base = BCM2712_BRCMSTB_PCIE1_BASE,
+ .Mem32 ={
+ .CpuBase = BCM2712_BRCMSTB_PCIE1_CPU_MEM_BASE
+ },
+ .Mem64 ={
+ .CpuBase = BCM2712_BRCMSTB_PCIE1_CPU_MEM64_BASE,
+ .BusBase = BCM2712_BRCMSTB_PCIE1_CPU_MEM64_BASE,
+ .Size = BCM2712_BRCMSTB_PCIE_MEM64_SIZE
+ }
+ },
+ {
+ .Base = BCM2712_BRCMSTB_PCIE2_BASE,
+ .Mem32 ={
+ .CpuBase = BCM2712_BRCMSTB_PCIE2_CPU_MEM_BASE
+ },
+ .Mem64 ={
+ .CpuBase = BCM2712_BRCMSTB_PCIE2_CPU_MEM64_BASE,
+ .BusBase = BCM2712_BRCMSTB_PCIE2_CPU_MEM64_BASE,
+ .Size = BCM2712_BRCMSTB_PCIE_MEM64_SIZE
+ }
+ }
+};
+
+/**
+ Return all the root bridge instances in an array.
+
+ @param Count Return the count of root bridge instances.
+
+ @return All the root bridge instances in an array.
+ The array should be passed into PciHostBridgeFreeRootBridges()
+ when it's not used.
+**/
+PCI_ROOT_BRIDGE *
+EFIAPI
+PciHostBridgeGetRootBridges (
+ OUT UINTN *Count
+ )
+{
+ EFI_STATUS Status;
+ UINTN Seg;
+ UINTN Index;
+ UINTN SegCount;
+ BCM2712_PCIE_PLATFORM_PROTOCOL *PciePlatform;
+ PCI_ROOT_BRIDGE *RootBridges;
+
+ Status = gBS->LocateProtocol (
+ &gBcm2712PciePlatformProtocolGuid,
+ NULL,
+ (VOID **)&PciePlatform
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ goto Fail;
+ }
+
+ SegCount = ARRAY_SIZE (mPcieRcs);
+
+ RootBridges = AllocateZeroPool (SegCount * sizeof (PCI_ROOT_BRIDGE));
+ if (RootBridges == NULL) {
+ ASSERT (FALSE);
+ goto Fail;
+ }
+
+ for (Seg = 0, Index = 0; Seg < SegCount; Seg++) {
+ if (PciePlatform->Settings[Seg].Enabled == FALSE) {
+ continue;
+ }
+
+ mPcieRcs[Seg].Inbound.CpuBase = 0;
+ mPcieRcs[Seg].Inbound.BusBase = 0;
+ mPcieRcs[Seg].Inbound.Size = SIZE_64GB;
+
+ mPcieRcs[Seg].Mem32.BusBase = PciePlatform->Mem32BusBase;
+ mPcieRcs[Seg].Mem32.Size = PciePlatform->Mem32Size;
+
+ mPcieRcs[Seg].Settings = &PciePlatform->Settings[Seg];
+
+ Status = PcieInitRc (&mPcieRcs[Seg]);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "PCIe: Failed to init segment %d. Status=%r\n", Seg, Status));
+ continue;
+ }
+
+ RootBridges[Index].Segment = Seg;
+ RootBridges[Index].Supports = 0;
+ RootBridges[Index].Attributes = RootBridges[Index].Supports;
+ RootBridges[Index].DmaAbove4G = FALSE;
+ RootBridges[Index].NoExtendedConfigSpace = FALSE;
+ RootBridges[Index].ResourceAssigned = FALSE;
+ RootBridges[Index].AllocationAttributes = EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM |
+ EFI_PCI_HOST_BRIDGE_MEM64_DECODE;
+ RootBridges[Index].Bus.Base = 0;
+ RootBridges[Index].Bus.Limit = PCI_MAX_BUS;
+
+ //
+ // Workaround: pretend to support I/O space even though we don't,
+ // because otherwise PciHostBridgeDxe would report a resource conflict
+ // on devices with I/O BARs and end up destroying all root bridges.
+ // Many such devices don't actually need those BARs to work (e.g. ASM1061,
+ // RTL NICs), so ideally, PciBusDxe should skip allocating them when there's
+ // no space and leave it up to the device drivers to decide if that's a problem.
+ //
+ RootBridges[Index].Io.Base = 0;
+ RootBridges[Index].Io.Limit = RootBridges[Index].Io.Base + SIZE_64KB - 1;
+ RootBridges[Index].Io.Translation = MAX_UINT64 - (mPcieRcs[Seg].Mem32.CpuBase + mPcieRcs[Seg].Mem32.Size) + 1;
+
+ RootBridges[Index].Mem.Base = mPcieRcs[Seg].Mem32.BusBase;
+ RootBridges[Index].Mem.Limit = RootBridges[Index].Mem.Base + mPcieRcs[Seg].Mem32.Size - 1;
+ RootBridges[Index].Mem.Translation = MAX_UINT64 - (mPcieRcs[Seg].Mem32.CpuBase - mPcieRcs[Seg].Mem32.BusBase) + 1;
+
+ RootBridges[Index].MemAbove4G.Base = mPcieRcs[Seg].Mem64.BusBase;
+ RootBridges[Index].MemAbove4G.Limit = RootBridges[Index].MemAbove4G.Base + mPcieRcs[Seg].Mem64.Size - 1;
+ RootBridges[Index].MemAbove4G.Translation = MAX_UINT64 - (mPcieRcs[Seg].Mem64.CpuBase - mPcieRcs[Seg].Mem64.BusBase) + 1;
+
+ RootBridges[Index].PMem.Base = MAX_UINT64;
+ RootBridges[Index].PMem.Limit = 0;
+
+ RootBridges[Index].PMemAbove4G.Base = MAX_UINT64;
+ RootBridges[Index].PMemAbove4G.Limit = 0;
+
+ RootBridges[Index].DevicePath = AllocateCopyPool (
+ sizeof (EFI_PCI_ROOT_BRIDGE_DEVICE_PATH),
+ &mPciDevicePathTemplate
+ );
+ if (RootBridges[Index].DevicePath == NULL) {
+ ASSERT (FALSE);
+ PciHostBridgeFreeRootBridges (RootBridges, Index);
+ goto Fail;
+ }
+
+ ((EFI_PCI_ROOT_BRIDGE_DEVICE_PATH *)RootBridges[Index].DevicePath)->AcpiDevicePath.UID = Seg;
+
+ Index++;
+ }
+
+ if (Index == 0) {
+ FreePool (RootBridges);
+ goto Fail;
+ }
+
+ *Count = Index;
+ return RootBridges;
+
+Fail:
+ *Count = 0;
+ return NULL;
+}
+
+/**
+ Free the root bridge instances array returned from PciHostBridgeGetRootBridges().
+
+ @param Bridges The root bridge instances array.
+ @param Count The count of the array.
+**/
+VOID
+EFIAPI
+PciHostBridgeFreeRootBridges (
+ PCI_ROOT_BRIDGE *Bridges,
+ UINTN Count
+ )
+{
+ UINTN Index;
+
+ if (Bridges == NULL) {
+ return;
+ }
+
+ for (Index = 0; Index < Count; Index++) {
+ FreePool (Bridges[Index].DevicePath);
+ }
+
+ FreePool (Bridges);
+}
+
+/**
+ Inform the platform that the resource conflict happens.
+
+ @param HostBridgeHandle Handle of the Host Bridge.
+ @param Configuration Pointer to PCI I/O and PCI memory resource
+ descriptors. The Configuration contains the resources
+ for all the root bridges. The resource for each root
+ bridge is terminated with END descriptor and an
+ additional END is appended indicating the end of the
+ entire resources. The resource descriptor field
+ values follow the description in
+ EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
+ .SubmitResources().
+**/
+VOID
+EFIAPI
+PciHostBridgeResourceConflict (
+ EFI_HANDLE HostBridgeHandle,
+ VOID *Configuration
+ )
+{
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+ UINTN RootBridgeIndex;
+
+ DEBUG ((DEBUG_ERROR, "PciHostBridge: Resource conflict happens!\n"));
+
+ RootBridgeIndex = 0;
+ Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Configuration;
+ while (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
+ DEBUG ((DEBUG_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++));
+ for ( ; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {
+ ASSERT (
+ Descriptor->ResType <
+ ARRAY_SIZE (mPciHostBridgeLibAcpiAddressSpaceTypeStr)
+ );
+ DEBUG ((
+ DEBUG_ERROR,
+ " %s: Length/Alignment = 0x%lx / 0x%lx\n",
+ mPciHostBridgeLibAcpiAddressSpaceTypeStr[Descriptor->ResType],
+ Descriptor->AddrLen,
+ Descriptor->AddrRangeMax
+ ));
+ if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
+ DEBUG ((
+ DEBUG_ERROR,
+ " Granularity/SpecificFlag = %ld / %02x%s\n",
+ Descriptor->AddrSpaceGranularity,
+ Descriptor->SpecificFlag,
+ ((Descriptor->SpecificFlag &
+ EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
+ ) != 0) ? L" (Prefetchable)" : L""
+ ));
+ }
+ }
+
+ //
+ // Skip the END descriptor for root bridge
+ //
+ ASSERT (Descriptor->Desc == ACPI_END_TAG_DESCRIPTOR);
+ Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(
+ (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor + 1
+ );
+ }
+}
diff --git a/Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciHostBridgeLib/Bcm2712PciHostBridgeLib.inf b/Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciHostBridgeLib/Bcm2712PciHostBridgeLib.inf
new file mode 100644
index 00000000..f83f21ca
--- /dev/null
+++ b/Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciHostBridgeLib/Bcm2712PciHostBridgeLib.inf
@@ -0,0 +1,38 @@
+#/** @file
+#
+# Copyright (c) 2024, Mario Bălănică <mariobalanica02@gmail.com>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = Bcm2712PciHostBridgeLib
+ FILE_GUID = 04d39ac0-9ca7-4653-8fdd-4e5436e0791c
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PciHostBridgeLib|DXE_DRIVER
+
+[Sources]
+ Bcm2712PciHostBridge.c
+ Bcm2712PciHostBridgeLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ Silicon/Broadcom/Bcm27xx/Bcm27xx.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ DevicePathLib
+ IoLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+
+[Protocols]
+ gBcm2712PciePlatformProtocolGuid ## CONSUMES
+
+[Depex]
+ gBcm2712PciePlatformProtocolGuid
diff --git a/Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciSegmentLib/PciSegmentLib.c b/Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciSegmentLib/PciSegmentLib.c
new file mode 100644
index 00000000..ef7ff2f2
--- /dev/null
+++ b/Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciSegmentLib/PciSegmentLib.c
@@ -0,0 +1,1456 @@
+/** @file
+ *
+ * Copyright (c) 2024, Mario Bălănică <mariobalanica02@gmail.com>
+ * Copyright (c) 2019, Jeremy Linton
+ * Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>
+ * Copyright (c) 2007 - 2012, Intel Corporation. All rights reserved.<BR>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#include <Base.h>
+#include <Uefi.h>
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/Bcm2712.h>
+#include <IndustryStandard/Bcm2712Pcie.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciSegmentLib.h>
+#include <Library/UefiLib.h>
+
+typedef enum {
+ PciCfgWidthUint8 = 0,
+ PciCfgWidthUint16,
+ PciCfgWidthUint32,
+ PciCfgWidthMax
+} PCI_CFG_WIDTH;
+
+/**
+ Assert the validity of a PCI Segment address.
+ A valid PCI Segment address should not contain 1's in bits 28..31 and 48..63
+
+ @param A The address to validate.
+ @param M Additional bits to assert to be zero.
+
+**/
+#define ASSERT_INVALID_PCI_SEGMENT_ADDRESS(A, M) \
+ ASSERT (((A) & (0xffff0000f0000000ULL | (M))) == 0)
+
+#define GET_SEG_NUM(Address) ((Address >> 32) & 0xFFFF)
+#define GET_BUS_NUM(Address) ((Address >> 20) & 0xFF)
+#define GET_DEV_NUM(Address) ((Address >> 15) & 0x1F)
+#define GET_FUN_NUM(Address) ((Address >> 12) & 0x07)
+#define GET_REG_NUM(Address) ((Address) & 0xFFF)
+#define GET_BUS_DEV_FUN(Address) ((Address) & 0xFFFFF000)
+
+/**
+ Given the nature of how we access PCI devices, we ensure that
+ read/write accesses are serialized through the use of a lock.
+**/
+STATIC
+EFI_LOCK mPciSegmentReadWriteLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);
+
+STATIC EFI_PHYSICAL_ADDRESS mPcieRcBaseAddresses[] = {
+ BCM2712_BRCMSTB_PCIE0_BASE,
+ BCM2712_BRCMSTB_PCIE1_BASE,
+ BCM2712_BRCMSTB_PCIE2_BASE
+};
+
+/**
+ Internal worker function to obtain config space base address.
+
+ @param Address The address that encodes the PCI Bus, Device, Function and
+ Register.
+
+ @return The value read from the PCI configuration register.
+
+**/
+STATIC
+UINT64
+PciSegmentLibGetConfigBase (
+ IN UINT64 Address
+ )
+{
+ EFI_PHYSICAL_ADDRESS Base;
+ UINT16 Segment;
+ UINT8 Bus;
+ UINT8 Device;
+ UINT8 Function;
+
+ Segment = GET_SEG_NUM (Address);
+
+ if (Segment >= ARRAY_SIZE (mPcieRcBaseAddresses)) {
+ ASSERT (FALSE);
+ return PCI_INVALID_ADDRESS;
+ }
+
+ // The root port is at the base of the PCIe register space
+ Base = mPcieRcBaseAddresses[Segment];
+
+ Bus = GET_BUS_NUM (Address);
+ Device = GET_DEV_NUM (Address);
+ Function = GET_FUN_NUM (Address);
+
+ // There can only be the root port on bus 0
+ if ((Bus == 0) && ((Device > 0) || (Function > 0))) {
+ return PCI_INVALID_ADDRESS;
+ }
+
+ // There can only be one device on bus 1
+ if ((Bus == 1) && (Device > 0)) {
+ return PCI_INVALID_ADDRESS;
+ }
+
+ if (Bus > 0) {
+ //
+ // Device function is mapped at CFG_DATA, a 4 KB window
+ // movable by writing its B/D/F location to CFG_INDEX.
+ //
+ MmioWrite32 (Base + PCIE_EXT_CFG_INDEX, GET_BUS_DEV_FUN (Address));
+ Base += PCIE_EXT_CFG_DATA;
+ }
+
+ return Base + GET_REG_NUM (Address);
+}
+
+/**
+ Internal worker function to read a PCI configuration register.
+
+ @param Address The address that encodes the PCI Bus, Device, Function and
+ Register.
+ @param Width The width of data to read
+
+ @return The value read from the PCI configuration register.
+
+**/
+STATIC
+UINT32
+PciSegmentLibReadWorker (
+ IN UINT64 Address,
+ IN PCI_CFG_WIDTH Width
+ )
+{
+ UINT64 Base;
+ UINT64 Ret;
+
+ EfiAcquireLock (&mPciSegmentReadWriteLock);
+ Base = PciSegmentLibGetConfigBase (Address);
+
+ if (Base == PCI_INVALID_ADDRESS) {
+ EfiReleaseLock (&mPciSegmentReadWriteLock);
+ return Base;
+ }
+
+ switch (Width) {
+ case PciCfgWidthUint8:
+ Ret = MmioRead8 (Base);
+ break;
+ case PciCfgWidthUint16:
+ Ret = MmioRead16 (Base);
+ break;
+ case PciCfgWidthUint32:
+ Ret = MmioRead32 (Base);
+ break;
+ default:
+ ASSERT (FALSE);
+ Ret = 0;
+ }
+
+ EfiReleaseLock (&mPciSegmentReadWriteLock);
+ return Ret;
+}
+
+/**
+ Internal worker function to writes a PCI configuration register.
+
+ @param Address The address that encodes the PCI Bus, Device, Function and
+ Register.
+ @param Width The width of data to write
+ @param Data The value to write.
+
+ @return The value written to the PCI configuration register.
+
+**/
+STATIC
+UINT32
+PciSegmentLibWriteWorker (
+ IN UINT64 Address,
+ IN PCI_CFG_WIDTH Width,
+ IN UINT32 Data
+ )
+{
+ UINT64 Base;
+
+ EfiAcquireLock (&mPciSegmentReadWriteLock);
+ Base = PciSegmentLibGetConfigBase (Address);
+
+ switch (Width) {
+ case PciCfgWidthUint8:
+ MmioWrite8 (Base, Data);
+ break;
+ case PciCfgWidthUint16:
+ MmioWrite16 (Base, Data);
+ break;
+ case PciCfgWidthUint32:
+ MmioWrite32 (Base, Data);
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+
+ EfiReleaseLock (&mPciSegmentReadWriteLock);
+ return Data;
+}
+
+/**
+ Register a PCI device so PCI configuration registers may be accessed after
+ SetVirtualAddressMap().
+
+ If any reserved bits in Address are set, then ASSERT().
+
+ @param Address The address that encodes the PCI Bus, Device, Function and
+ Register.
+
+ @retval RETURN_SUCCESS The PCI device was registered for runtime access.
+ @retval RETURN_UNSUPPORTED An attempt was made to call this function
+ after ExitBootServices().
+ @retval RETURN_UNSUPPORTED The resources required to access the PCI device
+ at runtime could not be mapped.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to
+ complete the registration.
+
+**/
+RETURN_STATUS
+EFIAPI
+PciSegmentRegisterForRuntimeAccess (
+ IN UINTN Address
+ )
+{
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0);
+ return RETURN_UNSUPPORTED;
+}
+
+/**
+ Reads an 8-bit PCI configuration register.
+
+ Reads and returns the 8-bit PCI configuration register specified by Address.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function,
+ and Register.
+
+ @return The 8-bit PCI configuration register specified by Address.
+
+**/
+UINT8
+EFIAPI
+PciSegmentRead8 (
+ IN UINT64 Address
+ )
+{
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0);
+
+ return (UINT8)PciSegmentLibReadWorker (Address, PciCfgWidthUint8);
+}
+
+/**
+ Writes an 8-bit PCI configuration register.
+
+ Writes the 8-bit PCI configuration register specified by Address with the value specified by Value.
+ Value is returned. This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param Value The value to write.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentWrite8 (
+ IN UINT64 Address,
+ IN UINT8 Value
+ )
+{
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0);
+
+ return (UINT8)PciSegmentLibWriteWorker (Address, PciCfgWidthUint8, Value);
+}
+
+/**
+ Performs a bitwise OR of an 8-bit PCI configuration register with an 8-bit value.
+
+ Reads the 8-bit PCI configuration register specified by Address,
+ performs a bitwise OR between the read result and the value specified by OrData,
+ and writes the result to the 8-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentOr8 (
+ IN UINT64 Address,
+ IN UINT8 OrData
+ )
+{
+ return PciSegmentWrite8 (Address, (UINT8)(PciSegmentRead8 (Address) | OrData));
+}
+
+/**
+ Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit value.
+
+ Reads the 8-bit PCI configuration register specified by Address,
+ performs a bitwise AND between the read result and the value specified by AndData,
+ and writes the result to the 8-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+ If any reserved bits in Address are set, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param AndData The value to AND with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentAnd8 (
+ IN UINT64 Address,
+ IN UINT8 AndData
+ )
+{
+ return PciSegmentWrite8 (Address, (UINT8)(PciSegmentRead8 (Address) & AndData));
+}
+
+/**
+ Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit value,
+ followed a bitwise OR with another 8-bit value.
+
+ Reads the 8-bit PCI configuration register specified by Address,
+ performs a bitwise AND between the read result and the value specified by AndData,
+ performs a bitwise OR between the result of the AND operation and the value specified by OrData,
+ and writes the result to the 8-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param AndData The value to AND with the PCI configuration register.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentAndThenOr8 (
+ IN UINT64 Address,
+ IN UINT8 AndData,
+ IN UINT8 OrData
+ )
+{
+ return PciSegmentWrite8 (Address, (UINT8)((PciSegmentRead8 (Address) & AndData) | OrData));
+}
+
+/**
+ Reads a bit field of a PCI configuration register.
+
+ Reads the bit field in an 8-bit PCI configuration register. The bit field is
+ specified by the StartBit and the EndBit. The value of the bit field is
+ returned.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 7, then ASSERT().
+ If EndBit is greater than 7, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+
+ @param Address The PCI configuration register to read.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..7.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..7.
+
+ @return The value of the bit field read from the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldRead8 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit
+ )
+{
+ return BitFieldRead8 (PciSegmentRead8 (Address), StartBit, EndBit);
+}
+
+/**
+ Writes a bit field to a PCI configuration register.
+
+ Writes Value to the bit field of the PCI configuration register. The bit
+ field is specified by the StartBit and the EndBit. All other bits in the
+ destination PCI configuration register are preserved. The new value of the
+ 8-bit register is returned.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 7, then ASSERT().
+ If EndBit is greater than 7, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address The PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..7.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..7.
+ @param Value The new value of the bit field.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldWrite8 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT8 Value
+ )
+{
+ return PciSegmentWrite8 (
+ Address,
+ BitFieldWrite8 (PciSegmentRead8 (Address), StartBit, EndBit, Value)
+ );
+}
+
+/**
+ Reads a bit field in an 8-bit PCI configuration, performs a bitwise OR, and
+ writes the result back to the bit field in the 8-bit port.
+
+ Reads the 8-bit PCI configuration register specified by Address, performs a
+ bitwise OR between the read result and the value specified by
+ OrData, and writes the result to the 8-bit PCI configuration register
+ specified by Address. The value written to the PCI configuration register is
+ returned. This function must guarantee that all PCI read and write operations
+ are serialized. Extra left bits in OrData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 7, then ASSERT().
+ If EndBit is greater than 7, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address The PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..7.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..7.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldOr8 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT8 OrData
+ )
+{
+ return PciSegmentWrite8 (
+ Address,
+ BitFieldOr8 (PciSegmentRead8 (Address), StartBit, EndBit, OrData)
+ );
+}
+
+/**
+ Reads a bit field in an 8-bit PCI configuration register, performs a bitwise
+ AND, and writes the result back to the bit field in the 8-bit register.
+
+ Reads the 8-bit PCI configuration register specified by Address, performs a
+ bitwise AND between the read result and the value specified by AndData, and
+ writes the result to the 8-bit PCI configuration register specified by
+ Address. The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are
+ serialized. Extra left bits in AndData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 7, then ASSERT().
+ If EndBit is greater than 7, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address The PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..7.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..7.
+ @param AndData The value to AND with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldAnd8 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT8 AndData
+ )
+{
+ return PciSegmentWrite8 (
+ Address,
+ BitFieldAnd8 (PciSegmentRead8 (Address), StartBit, EndBit, AndData)
+ );
+}
+
+/**
+ Reads a bit field in an 8-bit port, performs a bitwise AND followed by a
+ bitwise OR, and writes the result back to the bit field in the
+ 8-bit port.
+
+ Reads the 8-bit PCI configuration register specified by Address, performs a
+ bitwise AND followed by a bitwise OR between the read result and
+ the value specified by AndData, and writes the result to the 8-bit PCI
+ configuration register specified by Address. The value written to the PCI
+ configuration register is returned. This function must guarantee that all PCI
+ read and write operations are serialized. Extra left bits in both AndData and
+ OrData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 7, then ASSERT().
+ If EndBit is greater than 7, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address The PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..7.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..7.
+ @param AndData The value to AND with the PCI configuration register.
+ @param OrData The value to OR with the result of the AND operation.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldAndThenOr8 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT8 AndData,
+ IN UINT8 OrData
+ )
+{
+ return PciSegmentWrite8 (
+ Address,
+ BitFieldAndThenOr8 (PciSegmentRead8 (Address), StartBit, EndBit, AndData, OrData)
+ );
+}
+
+/**
+ Reads a 16-bit PCI configuration register.
+
+ Reads and returns the 16-bit PCI configuration register specified by Address.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+
+ @return The 16-bit PCI configuration register specified by Address.
+
+**/
+UINT16
+EFIAPI
+PciSegmentRead16 (
+ IN UINT64 Address
+ )
+{
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1);
+
+ return (UINT16)PciSegmentLibReadWorker (Address, PciCfgWidthUint16);
+}
+
+/**
+ Writes a 16-bit PCI configuration register.
+
+ Writes the 16-bit PCI configuration register specified by Address with the value specified by Value.
+ Value is returned. This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param Value The value to write.
+
+ @return The parameter of Value.
+
+**/
+UINT16
+EFIAPI
+PciSegmentWrite16 (
+ IN UINT64 Address,
+ IN UINT16 Value
+ )
+{
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1);
+
+ return (UINT16)PciSegmentLibWriteWorker (Address, PciCfgWidthUint16, Value);
+}
+
+/**
+ Performs a bitwise OR of a 16-bit PCI configuration register with
+ a 16-bit value.
+
+ Reads the 16-bit PCI configuration register specified by Address, performs a
+ bitwise OR between the read result and the value specified by
+ OrData, and writes the result to the 16-bit PCI configuration register
+ specified by Address. The value written to the PCI configuration register is
+ returned. This function must guarantee that all PCI read and write operations
+ are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function and
+ Register.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentOr16 (
+ IN UINT64 Address,
+ IN UINT16 OrData
+ )
+{
+ return PciSegmentWrite16 (Address, (UINT16)(PciSegmentRead16 (Address) | OrData));
+}
+
+/**
+ Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit value.
+
+ Reads the 16-bit PCI configuration register specified by Address,
+ performs a bitwise AND between the read result and the value specified by AndData,
+ and writes the result to the 16-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param AndData The value to AND with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentAnd16 (
+ IN UINT64 Address,
+ IN UINT16 AndData
+ )
+{
+ return PciSegmentWrite16 (Address, (UINT16)(PciSegmentRead16 (Address) & AndData));
+}
+
+/**
+ Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit value,
+ followed a bitwise OR with another 16-bit value.
+
+ Reads the 16-bit PCI configuration register specified by Address,
+ performs a bitwise AND between the read result and the value specified by AndData,
+ performs a bitwise OR between the result of the AND operation and the value specified by OrData,
+ and writes the result to the 16-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param AndData The value to AND with the PCI configuration register.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentAndThenOr16 (
+ IN UINT64 Address,
+ IN UINT16 AndData,
+ IN UINT16 OrData
+ )
+{
+ return PciSegmentWrite16 (Address, (UINT16)((PciSegmentRead16 (Address) & AndData) | OrData));
+}
+
+/**
+ Reads a bit field of a PCI configuration register.
+
+ Reads the bit field in a 16-bit PCI configuration register. The bit field is
+ specified by the StartBit and the EndBit. The value of the bit field is
+ returned.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+ If StartBit is greater than 15, then ASSERT().
+ If EndBit is greater than 15, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+
+ @param Address The PCI configuration register to read.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..15.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..15.
+
+ @return The value of the bit field read from the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldRead16 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit
+ )
+{
+ return BitFieldRead16 (PciSegmentRead16 (Address), StartBit, EndBit);
+}
+
+/**
+ Writes a bit field to a PCI configuration register.
+
+ Writes Value to the bit field of the PCI configuration register. The bit
+ field is specified by the StartBit and the EndBit. All other bits in the
+ destination PCI configuration register are preserved. The new value of the
+ 16-bit register is returned.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+ If StartBit is greater than 15, then ASSERT().
+ If EndBit is greater than 15, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address The PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..15.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..15.
+ @param Value The new value of the bit field.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldWrite16 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT16 Value
+ )
+{
+ return PciSegmentWrite16 (
+ Address,
+ BitFieldWrite16 (PciSegmentRead16 (Address), StartBit, EndBit, Value)
+ );
+}
+
+/**
+ Reads the 16-bit PCI configuration register specified by Address,
+ performs a bitwise OR between the read result and the value specified by OrData,
+ and writes the result to the 16-bit PCI configuration register specified by Address.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+ If StartBit is greater than 15, then ASSERT().
+ If EndBit is greater than 15, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address The PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..15.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..15.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldOr16 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT16 OrData
+ )
+{
+ return PciSegmentWrite16 (
+ Address,
+ BitFieldOr16 (PciSegmentRead16 (Address), StartBit, EndBit, OrData)
+ );
+}
+
+/**
+ Reads a bit field in a 16-bit PCI configuration, performs a bitwise OR,
+ and writes the result back to the bit field in the 16-bit port.
+
+ Reads the 16-bit PCI configuration register specified by Address,
+ performs a bitwise OR between the read result and the value specified by OrData,
+ and writes the result to the 16-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+ Extra left bits in OrData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+ If StartBit is greater than 7, then ASSERT().
+ If EndBit is greater than 7, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ The ordinal of the least significant bit in a byte is bit 0.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ The ordinal of the most significant bit in a byte is bit 7.
+ @param AndData The value to AND with the read value from the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldAnd16 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT16 AndData
+ )
+{
+ return PciSegmentWrite16 (
+ Address,
+ BitFieldAnd16 (PciSegmentRead16 (Address), StartBit, EndBit, AndData)
+ );
+}
+
+/**
+ Reads a bit field in a 16-bit port, performs a bitwise AND followed by a
+ bitwise OR, and writes the result back to the bit field in the
+ 16-bit port.
+
+ Reads the 16-bit PCI configuration register specified by Address, performs a
+ bitwise AND followed by a bitwise OR between the read result and
+ the value specified by AndData, and writes the result to the 16-bit PCI
+ configuration register specified by Address. The value written to the PCI
+ configuration register is returned. This function must guarantee that all PCI
+ read and write operations are serialized. Extra left bits in both AndData and
+ OrData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 15, then ASSERT().
+ If EndBit is greater than 15, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address The PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..15.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..15.
+ @param AndData The value to AND with the PCI configuration register.
+ @param OrData The value to OR with the result of the AND operation.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldAndThenOr16 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT16 AndData,
+ IN UINT16 OrData
+ )
+{
+ return PciSegmentWrite16 (
+ Address,
+ BitFieldAndThenOr16 (PciSegmentRead16 (Address), StartBit, EndBit, AndData, OrData)
+ );
+}
+
+/**
+ Reads a 32-bit PCI configuration register.
+
+ Reads and returns the 32-bit PCI configuration register specified by Address.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function,
+ and Register.
+
+ @return The 32-bit PCI configuration register specified by Address.
+
+**/
+UINT32
+EFIAPI
+PciSegmentRead32 (
+ IN UINT64 Address
+ )
+{
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3);
+
+ return PciSegmentLibReadWorker (Address, PciCfgWidthUint32);
+}
+
+/**
+ Writes a 32-bit PCI configuration register.
+
+ Writes the 32-bit PCI configuration register specified by Address with the value specified by Value.
+ Value is returned. This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device,
+ Function, and Register.
+ @param Value The value to write.
+
+ @return The parameter of Value.
+
+**/
+UINT32
+EFIAPI
+PciSegmentWrite32 (
+ IN UINT64 Address,
+ IN UINT32 Value
+ )
+{
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3);
+
+ return PciSegmentLibWriteWorker (Address, PciCfgWidthUint32, Value);
+}
+
+/**
+ Performs a bitwise OR of a 32-bit PCI configuration register with a 32-bit value.
+
+ Reads the 32-bit PCI configuration register specified by Address,
+ performs a bitwise OR between the read result and the value specified by OrData,
+ and writes the result to the 32-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentOr32 (
+ IN UINT64 Address,
+ IN UINT32 OrData
+ )
+{
+ return PciSegmentWrite32 (Address, PciSegmentRead32 (Address) | OrData);
+}
+
+/**
+ Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit value.
+
+ Reads the 32-bit PCI configuration register specified by Address,
+ performs a bitwise AND between the read result and the value specified by AndData,
+ and writes the result to the 32-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function,
+ and Register.
+ @param AndData The value to AND with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentAnd32 (
+ IN UINT64 Address,
+ IN UINT32 AndData
+ )
+{
+ return PciSegmentWrite32 (Address, PciSegmentRead32 (Address) & AndData);
+}
+
+/**
+ Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit value,
+ followed a bitwise OR with another 32-bit value.
+
+ Reads the 32-bit PCI configuration register specified by Address,
+ performs a bitwise AND between the read result and the value specified by AndData,
+ performs a bitwise OR between the result of the AND operation and the value specified by OrData,
+ and writes the result to the 32-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function,
+ and Register.
+ @param AndData The value to AND with the PCI configuration register.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentAndThenOr32 (
+ IN UINT64 Address,
+ IN UINT32 AndData,
+ IN UINT32 OrData
+ )
+{
+ return PciSegmentWrite32 (Address, (PciSegmentRead32 (Address) & AndData) | OrData);
+}
+
+/**
+ Reads a bit field of a PCI configuration register.
+
+ Reads the bit field in a 32-bit PCI configuration register. The bit field is
+ specified by the StartBit and the EndBit. The value of the bit field is
+ returned.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+ If StartBit is greater than 31, then ASSERT().
+ If EndBit is greater than 31, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+
+ @param Address The PCI configuration register to read.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..31.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..31.
+
+ @return The value of the bit field read from the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldRead32 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit
+ )
+{
+ return BitFieldRead32 (PciSegmentRead32 (Address), StartBit, EndBit);
+}
+
+/**
+ Writes a bit field to a PCI configuration register.
+
+ Writes Value to the bit field of the PCI configuration register. The bit
+ field is specified by the StartBit and the EndBit. All other bits in the
+ destination PCI configuration register are preserved. The new value of the
+ 32-bit register is returned.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+ If StartBit is greater than 31, then ASSERT().
+ If EndBit is greater than 31, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address The PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..31.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..31.
+ @param Value The new value of the bit field.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldWrite32 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT32 Value
+ )
+{
+ return PciSegmentWrite32 (
+ Address,
+ BitFieldWrite32 (PciSegmentRead32 (Address), StartBit, EndBit, Value)
+ );
+}
+
+/**
+ Reads a bit field in a 32-bit PCI configuration, performs a bitwise OR, and
+ writes the result back to the bit field in the 32-bit port.
+
+ Reads the 32-bit PCI configuration register specified by Address, performs a
+ bitwise OR between the read result and the value specified by
+ OrData, and writes the result to the 32-bit PCI configuration register
+ specified by Address. The value written to the PCI configuration register is
+ returned. This function must guarantee that all PCI read and write operations
+ are serialized. Extra left bits in OrData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 31, then ASSERT().
+ If EndBit is greater than 31, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address The PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..31.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..31.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldOr32 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT32 OrData
+ )
+{
+ return PciSegmentWrite32 (
+ Address,
+ BitFieldOr32 (PciSegmentRead32 (Address), StartBit, EndBit, OrData)
+ );
+}
+
+/**
+ Reads a bit field in a 32-bit PCI configuration register, performs a bitwise
+ AND, and writes the result back to the bit field in the 32-bit register.
+
+
+ Reads the 32-bit PCI configuration register specified by Address, performs a bitwise
+ AND between the read result and the value specified by AndData, and writes the result
+ to the 32-bit PCI configuration register specified by Address. The value written to
+ the PCI configuration register is returned. This function must guarantee that all PCI
+ read and write operations are serialized. Extra left bits in AndData are stripped.
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+ If StartBit is greater than 31, then ASSERT().
+ If EndBit is greater than 31, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address The PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..31.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..31.
+ @param AndData The value to AND with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldAnd32 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT32 AndData
+ )
+{
+ return PciSegmentWrite32 (
+ Address,
+ BitFieldAnd32 (PciSegmentRead32 (Address), StartBit, EndBit, AndData)
+ );
+}
+
+/**
+ Reads a bit field in a 32-bit port, performs a bitwise AND followed by a
+ bitwise OR, and writes the result back to the bit field in the
+ 32-bit port.
+
+ Reads the 32-bit PCI configuration register specified by Address, performs a
+ bitwise AND followed by a bitwise OR between the read result and
+ the value specified by AndData, and writes the result to the 32-bit PCI
+ configuration register specified by Address. The value written to the PCI
+ configuration register is returned. This function must guarantee that all PCI
+ read and write operations are serialized. Extra left bits in both AndData and
+ OrData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 31, then ASSERT().
+ If EndBit is greater than 31, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address The PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..31.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..31.
+ @param AndData The value to AND with the PCI configuration register.
+ @param OrData The value to OR with the result of the AND operation.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldAndThenOr32 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT32 AndData,
+ IN UINT32 OrData
+ )
+{
+ return PciSegmentWrite32 (
+ Address,
+ BitFieldAndThenOr32 (PciSegmentRead32 (Address), StartBit, EndBit, AndData, OrData)
+ );
+}
+
+/**
+ Reads a range of PCI configuration registers into a caller supplied buffer.
+
+ Reads the range of PCI configuration registers specified by StartAddress and
+ Size into the buffer specified by Buffer. This function only allows the PCI
+ configuration registers from a single PCI function to be read. Size is
+ returned. When possible 32-bit PCI configuration read cycles are used to read
+ from StartAdress to StartAddress + Size. Due to alignment restrictions, 8-bit
+ and 16-bit PCI configuration read cycles may be used at the beginning and the
+ end of the range.
+
+ If any reserved bits in StartAddress are set, then ASSERT().
+ If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT().
+ If Size > 0 and Buffer is NULL, then ASSERT().
+
+ @param StartAddress The starting address that encodes the PCI Segment, Bus,
+ Device, Function and Register.
+ @param Size The size in bytes of the transfer.
+ @param Buffer The pointer to a buffer receiving the data read.
+
+ @return Size
+
+**/
+UINTN
+EFIAPI
+PciSegmentReadBuffer (
+ IN UINT64 StartAddress,
+ IN UINTN Size,
+ OUT VOID *Buffer
+ )
+{
+ UINTN ReturnValue;
+
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (StartAddress, 0);
+ ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000);
+
+ if (Size == 0) {
+ return Size;
+ }
+
+ ASSERT (Buffer != NULL);
+
+ //
+ // Save Size for return
+ //
+ ReturnValue = Size;
+
+ if ((StartAddress & BIT0) != 0) {
+ //
+ // Read a byte if StartAddress is byte aligned
+ //
+ *(volatile UINT8 *)Buffer = PciSegmentRead8 (StartAddress);
+ StartAddress += sizeof (UINT8);
+ Size -= sizeof (UINT8);
+ Buffer = (UINT8 *)Buffer + 1;
+ }
+
+ if ((Size >= sizeof (UINT16)) && ((StartAddress & BIT1) != 0)) {
+ //
+ // Read a word if StartAddress is word aligned
+ //
+ WriteUnaligned16 (Buffer, PciSegmentRead16 (StartAddress));
+ StartAddress += sizeof (UINT16);
+ Size -= sizeof (UINT16);
+ Buffer = (UINT16 *)Buffer + 1;
+ }
+
+ while (Size >= sizeof (UINT32)) {
+ //
+ // Read as many double words as possible
+ //
+ WriteUnaligned32 (Buffer, PciSegmentRead32 (StartAddress));
+ StartAddress += sizeof (UINT32);
+ Size -= sizeof (UINT32);
+ Buffer = (UINT32 *)Buffer + 1;
+ }
+
+ if (Size >= sizeof (UINT16)) {
+ //
+ // Read the last remaining word if exist
+ //
+ WriteUnaligned16 (Buffer, PciSegmentRead16 (StartAddress));
+ StartAddress += sizeof (UINT16);
+ Size -= sizeof (UINT16);
+ Buffer = (UINT16 *)Buffer + 1;
+ }
+
+ if (Size >= sizeof (UINT8)) {
+ //
+ // Read the last remaining byte if exist
+ //
+ *(volatile UINT8 *)Buffer = PciSegmentRead8 (StartAddress);
+ }
+
+ return ReturnValue;
+}
+
+/**
+ Copies the data in a caller supplied buffer to a specified range of PCI
+ configuration space.
+
+ Writes the range of PCI configuration registers specified by StartAddress and
+ Size from the buffer specified by Buffer. This function only allows the PCI
+ configuration registers from a single PCI function to be written. Size is
+ returned. When possible 32-bit PCI configuration write cycles are used to
+ write from StartAdress to StartAddress + Size. Due to alignment restrictions,
+ 8-bit and 16-bit PCI configuration write cycles may be used at the beginning
+ and the end of the range.
+
+ If any reserved bits in StartAddress are set, then ASSERT().
+ If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT().
+ If Size > 0 and Buffer is NULL, then ASSERT().
+
+ @param StartAddress The starting address that encodes the PCI Segment, Bus,
+ Device, Function and Register.
+ @param Size The size in bytes of the transfer.
+ @param Buffer The pointer to a buffer containing the data to write.
+
+ @return The parameter of Size.
+
+**/
+UINTN
+EFIAPI
+PciSegmentWriteBuffer (
+ IN UINT64 StartAddress,
+ IN UINTN Size,
+ IN VOID *Buffer
+ )
+{
+ UINTN ReturnValue;
+
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (StartAddress, 0);
+ ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000);
+
+ if (Size == 0) {
+ return 0;
+ }
+
+ ASSERT (Buffer != NULL);
+
+ //
+ // Save Size for return
+ //
+ ReturnValue = Size;
+
+ if ((StartAddress & BIT0) != 0) {
+ //
+ // Write a byte if StartAddress is byte aligned
+ //
+ PciSegmentWrite8 (StartAddress, *(UINT8 *)Buffer);
+ StartAddress += sizeof (UINT8);
+ Size -= sizeof (UINT8);
+ Buffer = (UINT8 *)Buffer + 1;
+ }
+
+ if ((Size >= sizeof (UINT16)) && ((StartAddress & BIT1) != 0)) {
+ //
+ // Write a word if StartAddress is word aligned
+ //
+ PciSegmentWrite16 (StartAddress, ReadUnaligned16 (Buffer));
+ StartAddress += sizeof (UINT16);
+ Size -= sizeof (UINT16);
+ Buffer = (UINT16 *)Buffer + 1;
+ }
+
+ while (Size >= sizeof (UINT32)) {
+ //
+ // Write as many double words as possible
+ //
+ PciSegmentWrite32 (StartAddress, ReadUnaligned32 (Buffer));
+ StartAddress += sizeof (UINT32);
+ Size -= sizeof (UINT32);
+ Buffer = (UINT32 *)Buffer + 1;
+ }
+
+ if (Size >= sizeof (UINT16)) {
+ //
+ // Write the last remaining word if exist
+ //
+ PciSegmentWrite16 (StartAddress, ReadUnaligned16 (Buffer));
+ StartAddress += sizeof (UINT16);
+ Size -= sizeof (UINT16);
+ Buffer = (UINT16 *)Buffer + 1;
+ }
+
+ if (Size >= sizeof (UINT8)) {
+ //
+ // Write the last remaining byte if exist
+ //
+ PciSegmentWrite8 (StartAddress, *(UINT8 *)Buffer);
+ }
+
+ return ReturnValue;
+}
diff --git a/Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciSegmentLib/PciSegmentLib.inf b/Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciSegmentLib/PciSegmentLib.inf
new file mode 100644
index 00000000..63408865
--- /dev/null
+++ b/Silicon/Broadcom/Bcm27xx/Library/Bcm2712PciSegmentLib/PciSegmentLib.inf
@@ -0,0 +1,31 @@
+#/** @file
+#
+# Copyright (c) 2024, Mario Bălănică <mariobalanica02@gmail.com>
+# Copyright (c) 2019, Jeremy Linton
+# Copyright (c) 2017, Linaro Ltd. All rights reserved.<BR>
+# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = PciSegmentLib
+ FILE_GUID = 644017d3-258f-4e31-8f2f-842506bb8097
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PciSegmentLib
+
+[Sources]
+ PciSegmentLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ Silicon/Broadcom/Bcm27xx/Bcm27xx.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ IoLib
+ UefiLib
diff --git a/Silicon/RaspberryPi/RpiSiliconPkg/Drivers/Rp1BusDxe/ComponentName.c b/Silicon/RaspberryPi/RpiSiliconPkg/Drivers/Rp1BusDxe/ComponentName.c
new file mode 100644
index 00000000..656049dc
--- /dev/null
+++ b/Silicon/RaspberryPi/RpiSiliconPkg/Drivers/Rp1BusDxe/ComponentName.c
@@ -0,0 +1,323 @@
+/** @file
+ *
+ * Copyright (c) 2024, Mario Bălănică <mariobalanica02@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#include <Uefi.h>
+#include <Library/UefiLib.h>
+
+#include "Rp1BusDxe.h"
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+Rp1BusComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+Rp1BusComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL mRp1BusComponentName = {
+ Rp1BusComponentNameGetDriverName,
+ Rp1BusComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL mRp1BusComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)Rp1BusComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)Rp1BusComponentNameGetControllerName,
+ "en"
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mRp1BusDriverNameTable[] = {
+ { "eng;en", L"Raspberry Pi RP1 I/O Bridge Driver" },
+ { NULL, NULL }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mRp1BusControllerNameTable[] = {
+ { "eng;en", L"Raspberry Pi RP1 I/O Bridge" },
+ { NULL, NULL }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+Rp1BusComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mRp1BusDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &mRp1BusComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+Rp1BusComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ mRp1BusDriverBinding.DriverBindingHandle,
+ &gEfiPciIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mRp1BusControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &mRp1BusComponentName)
+ );
+}
diff --git a/Silicon/RaspberryPi/RpiSiliconPkg/Drivers/Rp1BusDxe/Rp1BusDxe.c b/Silicon/RaspberryPi/RpiSiliconPkg/Drivers/Rp1BusDxe/Rp1BusDxe.c
index 7d7012b5..aed8ae81 100644
--- a/Silicon/RaspberryPi/RpiSiliconPkg/Drivers/Rp1BusDxe/Rp1BusDxe.c
+++ b/Silicon/RaspberryPi/RpiSiliconPkg/Drivers/Rp1BusDxe/Rp1BusDxe.c
@@ -1,98 +1,469 @@
/** @file
*
- * Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
+ * Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
**/
#include <Uefi.h>
+#include <IndustryStandard/Pci.h>
#include <Library/DebugLib.h>
#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
#include <Library/NonDiscoverableDeviceRegistrationLib.h>
-
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
#include <Rp1.h>
-typedef struct {
- EFI_PHYSICAL_ADDRESS Bar;
- UINT32 ChipId;
-} RP1_DEVICE;
+#include "Rp1BusDxe.h"
STATIC
-EFI_STATUS
+VOID
EFIAPI
-Rp1RegisterDwc3Controllers (
- IN RP1_DEVICE *This
+Rp1BusRegisterDwc3Controllers (
+ IN RP1_BUS_DATA *Rp1Data
)
{
- EFI_STATUS Status;
- UINTN Index;
- EFI_PHYSICAL_ADDRESS FullBase;
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_PHYSICAL_ADDRESS FullBase;
+ EFI_HANDLE DeviceHandle;
+ RP1_BUS_PROTOCOL *Rp1Bus;
- EFI_PHYSICAL_ADDRESS Dwc3Addresses[] = {
+ EFI_PHYSICAL_ADDRESS Dwc3Addresses[] = {
RP1_USBHOST0_BASE, RP1_USBHOST1_BASE
};
for (Index = 0; Index < ARRAY_SIZE (Dwc3Addresses); Index++) {
- FullBase = This->Bar + Dwc3Addresses[Index];
+ DeviceHandle = NULL;
+ FullBase = Rp1Data->PeripheralBase + Dwc3Addresses[Index];
+
Status = RegisterNonDiscoverableMmioDevice (
- NonDiscoverableDeviceTypeXhci,
- NonDiscoverableDeviceDmaTypeNonCoherent,
- NULL,
- NULL,
- 1,
- FullBase,
- RP1_USBHOST_SIZE
- );
+ NonDiscoverableDeviceTypeXhci,
+ NonDiscoverableDeviceDmaTypeNonCoherent,
+ NULL,
+ &DeviceHandle,
+ 1,
+ FullBase,
+ RP1_USBHOST_SIZE
+ );
if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR,
- "%a: Failed to register DWC3 controller at 0x%lx. Status=%r\n",
- __func__, FullBase, Status));
- return Status;
+ DEBUG ((
+ DEBUG_ERROR,
+ "RP1: Failed to register DWC3 controller at 0x%lx. Status=%r\n",
+ FullBase,
+ Status
+ ));
+ continue;
+ }
+
+ Status = gBS->OpenProtocol (
+ Rp1Data->ControllerHandle,
+ &gRp1BusProtocolGuid,
+ (VOID **)&Rp1Bus,
+ Rp1Data->DriverBinding->DriverBindingHandle,
+ DeviceHandle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "RP1: Failed to open DWC3 by controller. Status=%r\n",
+ Status
+ ));
+ continue;
}
}
- return EFI_SUCCESS;
}
STATIC
VOID
EFIAPI
-Rp1RegisterDevices (
- IN RP1_DEVICE *This
+Rp1BusRegisterDevices (
+ IN RP1_BUS_DATA *Rp1Data
)
{
- Rp1RegisterDwc3Controllers (This);
+ Rp1BusRegisterDwc3Controllers (Rp1Data);
}
STATIC
VOID
EFIAPI
-Rp1EnableInterrupts (
- IN RP1_DEVICE *This
+Rp1BusEnableInterrupts (
+ IN RP1_BUS_DATA *Rp1Data
+ )
+{
+ MmioWrite32 (
+ Rp1Data->PeripheralBase + RP1_PCIE_REG_SET + RP1_PCIE_MSIX_CFG (RP1_INT_USBHOST0_0),
+ RP1_PCIE_MSIX_CFG_ENABLE
+ );
+ MmioWrite32 (
+ Rp1Data->PeripheralBase + RP1_PCIE_REG_SET + RP1_PCIE_MSIX_CFG (RP1_INT_USBHOST1_0),
+ RP1_PCIE_MSIX_CFG_ENABLE
+ );
+}
+
+STATIC
+EFI_PHYSICAL_ADDRESS
+EFIAPI
+Rp1BusGetPeripheralBase (
+ IN RP1_BUS_PROTOCOL *This
)
{
- MmioWrite32 (This->Bar + RP1_PCIE_REG_SET + RP1_PCIE_MSIX_CFG (RP1_INT_USBHOST0_0),
- RP1_PCIE_MSIX_CFG_ENABLE);
- MmioWrite32 (This->Bar + RP1_PCIE_REG_SET + RP1_PCIE_MSIX_CFG (RP1_INT_USBHOST1_0),
- RP1_PCIE_MSIX_CFG_ENABLE);
+ ASSERT (This != NULL);
+
+ return (RP1_BUS_DATA_FROM_THIS (This))->PeripheralBase;
}
EFI_STATUS
EFIAPI
-Rp1BusDxeEntryPoint (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
+Rp1BusDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT32 PciId;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **)&PciIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ PCI_VENDOR_ID_OFFSET,
+ 1,
+ &PciId
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_UNSUPPORTED;
+ goto Exit;
+ }
+
+ if (((PciId & 0xffff) != PCI_VENDOR_ID_RPILTD) ||
+ ((PciId >> 16) != PCI_DEVICE_ID_RP1))
+ {
+ Status = EFI_UNSUPPORTED;
+ }
+
+Exit:
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+Rp1BusDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT64 Supports;
+ RP1_BUS_DATA *Rp1Data;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *PeripheralDesc;
+
+ Rp1Data = NULL;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **)&PciIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ if (!EFI_ERROR (Status)) {
+ Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ Supports,
+ NULL
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "RP1: Failed to enable PCI device. Status=%r\n", Status));
+ goto Fail;
+ }
+
+ Rp1Data = AllocateZeroPool (sizeof (RP1_BUS_DATA));
+ if (Rp1Data == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((DEBUG_ERROR, "RP1: Failed to allocate device context. Status=%r\n", Status));
+ goto Fail;
+ }
+
+ Rp1Data->Signature = RP1_BUS_DATA_SIGNATURE;
+ Rp1Data->ControllerHandle = ControllerHandle;
+ Rp1Data->DriverBinding = This;
+ Rp1Data->PciIo = PciIo;
+ Rp1Data->Rp1Bus.GetPeripheralBase = Rp1BusGetPeripheralBase;
+
+ Status = PciIo->GetBarAttributes (
+ PciIo,
+ RP1_PERIPHERAL_BAR_INDEX,
+ NULL,
+ (VOID **)&PeripheralDesc
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "RP1: Failed to get BAR attributes. Status=%r\n", Status));
+ goto Fail;
+ }
+
+ Rp1Data->PeripheralBase = PeripheralDesc->AddrRangeMin;
+ FreePool (PeripheralDesc);
+
+ Rp1Data->ChipId = MmioRead32 (Rp1Data->PeripheralBase + RP1_SYSINFO_BASE);
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ControllerHandle,
+ &gRp1BusProtocolGuid,
+ &Rp1Data->Rp1Bus,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "RP1: Failed to install bus protocol. Status=%r\n", Status));
+ goto Fail;
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "RP1: chip id %x, peripheral base at CPU address 0x%lx\n",
+ Rp1Data->ChipId,
+ Rp1Data->PeripheralBase
+ ));
+
+ Rp1BusRegisterDevices (Rp1Data);
+ Rp1BusEnableInterrupts (Rp1Data);
+
+ return EFI_SUCCESS;
+
+Fail:
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ gBS->UninstallMultipleProtocolInterfaces (
+ ControllerHandle,
+ &gRp1BusProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ if (Rp1Data != NULL) {
+ FreePool (Rp1Data);
+ }
+
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+Rp1BusUnregisterNonDiscoverableDevice (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE DeviceHandle
+ )
+{
+ EFI_STATUS Status;
+ NON_DISCOVERABLE_DEVICE *NonDiscoverableDevice;
+ EFI_DEVICE_PATH_PROTOCOL *NonDiscoverableDevicePath;
+ RP1_BUS_PROTOCOL *Rp1Bus;
+
+ Status = gBS->OpenProtocol (
+ DeviceHandle,
+ &gEdkiiNonDiscoverableDeviceProtocolGuid,
+ (VOID **)&NonDiscoverableDevice,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ DeviceHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **)&NonDiscoverableDevicePath,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ Status = gBS->CloseProtocol (
+ ControllerHandle,
+ &gRp1BusProtocolGuid,
+ This->DriverBindingHandle,
+ DeviceHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ DeviceHandle,
+ &gEdkiiNonDiscoverableDeviceProtocolGuid,
+ NonDiscoverableDevice,
+ &gEfiDevicePathProtocolGuid,
+ NonDiscoverableDevicePath,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->OpenProtocol (
+ ControllerHandle,
+ &gRp1BusProtocolGuid,
+ (VOID **)&Rp1Bus,
+ This->DriverBindingHandle,
+ DeviceHandle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ return Status;
+ }
+
+ FreePool (NonDiscoverableDevice);
+ FreePool (NonDiscoverableDevicePath);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+Rp1BusDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *DeviceHandleBuffer
)
{
- RP1_DEVICE Dev;
- Dev.Bar = PcdGet64 (Rp1PciPeripheralsBar);
- Dev.ChipId = MmioRead32 (Dev.Bar + RP1_SYSINFO_BASE);
+ EFI_STATUS Status;
+ UINTN Index;
+ RP1_BUS_PROTOCOL *Rp1Bus;
+ BOOLEAN AllChildrenStopped;
+
+ if (NumberOfChildren == 0) {
+ DEBUG ((DEBUG_INFO, "RP1: Stop bus at %p\n", ControllerHandle));
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gRp1BusProtocolGuid,
+ (VOID **)&Rp1Bus,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ControllerHandle,
+ &gRp1BusProtocolGuid,
+ Rp1Bus,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (RP1_BUS_DATA_FROM_THIS (Rp1Bus));
+
+ Status = gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+ }
- DEBUG ((DEBUG_INFO, "RP1 chip id: %x, peripheral BAR at CPU address 0x%lx\n",
- Dev.ChipId, Dev.Bar));
+ AllChildrenStopped = TRUE;
- Rp1RegisterDevices (&Dev);
- Rp1EnableInterrupts (&Dev);
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+ //
+ // We only register non-discoverable PCI devices so far.
+ //
+ Status = Rp1BusUnregisterNonDiscoverableDevice (
+ This,
+ ControllerHandle,
+ DeviceHandleBuffer[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ continue;
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
return EFI_SUCCESS;
}
+
+EFI_DRIVER_BINDING_PROTOCOL mRp1BusDriverBinding = {
+ Rp1BusDriverBindingSupported,
+ Rp1BusDriverBindingStart,
+ Rp1BusDriverBindingStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+EFI_STATUS
+EFIAPI
+Rp1BusDxeEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &mRp1BusDriverBinding,
+ ImageHandle,
+ &mRp1BusComponentName,
+ &mRp1BusComponentName2
+ );
+}
diff --git a/Silicon/RaspberryPi/RpiSiliconPkg/Drivers/Rp1BusDxe/Rp1BusDxe.h b/Silicon/RaspberryPi/RpiSiliconPkg/Drivers/Rp1BusDxe/Rp1BusDxe.h
new file mode 100644
index 00000000..f75389a6
--- /dev/null
+++ b/Silicon/RaspberryPi/RpiSiliconPkg/Drivers/Rp1BusDxe/Rp1BusDxe.h
@@ -0,0 +1,34 @@
+/** @file
+ *
+ * Copyright (c) 2024, Mario Bălănică <mariobalanica02@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#ifndef __RP1_BUS_DXE_H__
+#define __RP1_BUS_DXE_H__
+
+#include <Protocol/DriverBinding.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/Rp1Bus.h>
+
+#define RP1_BUS_DATA_SIGNATURE SIGNATURE_32 ('R','P','1','b')
+
+typedef struct {
+ UINT32 Signature;
+ EFI_HANDLE ControllerHandle;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ RP1_BUS_PROTOCOL Rp1Bus;
+ EFI_PHYSICAL_ADDRESS PeripheralBase;
+ UINT32 ChipId;
+} RP1_BUS_DATA;
+
+#define RP1_BUS_DATA_FROM_THIS(a) CR (a, RP1_BUS_DATA, Rp1Bus, RP1_BUS_DATA_SIGNATURE)
+
+extern EFI_DRIVER_BINDING_PROTOCOL mRp1BusDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL mRp1BusComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL mRp1BusComponentName2;
+
+#endif // __RP1_BUS_DXE_H__
diff --git a/Silicon/RaspberryPi/RpiSiliconPkg/Drivers/Rp1BusDxe/Rp1BusDxe.inf b/Silicon/RaspberryPi/RpiSiliconPkg/Drivers/Rp1BusDxe/Rp1BusDxe.inf
index ffc8c143..671ec77f 100644
--- a/Silicon/RaspberryPi/RpiSiliconPkg/Drivers/Rp1BusDxe/Rp1BusDxe.inf
+++ b/Silicon/RaspberryPi/RpiSiliconPkg/Drivers/Rp1BusDxe/Rp1BusDxe.inf
@@ -1,6 +1,6 @@
#/** @file
#
-# Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
+# Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -16,6 +16,7 @@
[Sources]
Rp1BusDxe.c
+ ComponentName.c
[Packages]
MdePkg/MdePkg.dec
@@ -25,15 +26,17 @@
[LibraryClasses]
DebugLib
IoLib
+ MemoryAllocationLib
NonDiscoverableDeviceRegistrationLib
UefiBootServicesTableLib
UefiDriverEntryPoint
UefiLib
[Protocols]
-
-[Pcd]
- gRpiSiliconTokenSpaceGuid.Rp1PciPeripheralsBar
+ gEfiPciIoProtocolGuid ## TO_START
+ gRp1BusProtocolGuid ## BY_START
+ gEdkiiNonDiscoverableDeviceProtocolGuid ## BY_START
+ gEfiDevicePathProtocolGuid ## BY_START
[Depex]
TRUE
diff --git a/Silicon/RaspberryPi/RpiSiliconPkg/Include/Protocol/Rp1Bus.h b/Silicon/RaspberryPi/RpiSiliconPkg/Include/Protocol/Rp1Bus.h
new file mode 100644
index 00000000..4ae879b8
--- /dev/null
+++ b/Silicon/RaspberryPi/RpiSiliconPkg/Include/Protocol/Rp1Bus.h
@@ -0,0 +1,29 @@
+/** @file
+ *
+ * Copyright (c) 2024, Mario Bălănică <mariobalanica02@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#ifndef __RP1_BUS_H__
+#define __RP1_BUS_H__
+
+#define RP1_BUS_PROTOCOL_GUID \
+ { 0xf1417a30, 0x5418, 0x4cd5, { 0x8e, 0x65, 0xf9, 0x02, 0x51, 0x21, 0xb5, 0x7f } }
+
+typedef struct _RP1_BUS_PROTOCOL RP1_BUS_PROTOCOL;
+
+typedef
+EFI_PHYSICAL_ADDRESS
+(EFIAPI *RP1_BUS_GET_PERIPHERAL_BASE)(
+ IN RP1_BUS_PROTOCOL *This
+ );
+
+struct _RP1_BUS_PROTOCOL {
+ RP1_BUS_GET_PERIPHERAL_BASE GetPeripheralBase;
+};
+
+extern EFI_GUID gRp1BusProtocolGuid;
+
+#endif // __RP1_BUS_H__
diff --git a/Silicon/RaspberryPi/RpiSiliconPkg/Include/Rp1.h b/Silicon/RaspberryPi/RpiSiliconPkg/Include/Rp1.h
index 13a33fc6..d136c518 100644
--- a/Silicon/RaspberryPi/RpiSiliconPkg/Include/Rp1.h
+++ b/Silicon/RaspberryPi/RpiSiliconPkg/Include/Rp1.h
@@ -1,6 +1,6 @@
/** @file
*
- * Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
+ * Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
@@ -9,6 +9,11 @@
#ifndef __RP1_H__
#define __RP1_H__
+#define PCI_VENDOR_ID_RPILTD 0x1de4
+#define PCI_DEVICE_ID_RP1 0x0001
+
+#define RP1_PERIPHERAL_BAR_INDEX 1
+
//
// BAR1 Peripherals
//
diff --git a/Silicon/RaspberryPi/RpiSiliconPkg/RpiSiliconPkg.dec b/Silicon/RaspberryPi/RpiSiliconPkg/RpiSiliconPkg.dec
index d66041e0..ce74ec7b 100644
--- a/Silicon/RaspberryPi/RpiSiliconPkg/RpiSiliconPkg.dec
+++ b/Silicon/RaspberryPi/RpiSiliconPkg/RpiSiliconPkg.dec
@@ -1,6 +1,6 @@
#/** @file
#
-# Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
+# Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -18,5 +18,5 @@
[Guids]
gRpiSiliconTokenSpaceGuid = { 0x0b3ce57a, 0xa82b, 0x4ada, { 0x8f, 0xb5, 0x52, 0xc8, 0x72, 0x30, 0x1f, 0xdb } }
-[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
- gRpiSiliconTokenSpaceGuid.Rp1PciPeripheralsBar|0x0|UINT64|0x00000001
+[Protocols]
+ gRp1BusProtocolGuid = { 0xf1417a30, 0x5418, 0x4cd5, { 0x8e, 0x65, 0xf9, 0x02, 0x51, 0x21, 0xb5, 0x7f } }
--
2.51.2