Arm reference design platforms have multiple IO virtualization blocks
that allow connecting PCIe root bus or non-PCIe SoC peripherals to the
system. Each of these IO virtualization blocks consists of an instance
of SMMUv3, a GIC-ITS and a NCI (network chip interconnect) to support
traffic flow and address mapping, as required.
The SoC expansion blocks that connect to the IO virtualization block
include devices such as UARTs, DMAs and few additional memory nodes. For
platforms having SoC expansion block connected to the IO virtualization
block add a SSDT table to describe devices included in the SoC expansion
block. Preprocessor macros are also added in this change to allow
scalability for platforms that implement multiple instances of these SoC
expansion blocks.
Signed-off-by: Vivek Gautam <vivek.gau...@arm.com>
---
Platform/ARM/SgiPkg/SgiPlatform.dec | 4 +
Platform/ARM/SgiPkg/SgiMemoryMap2.dsc.inc | 3 +
Platform/ARM/SgiPkg/Include/IoVirtSoCExp.h | 188 ++++++++++++++++++++
Platform/ARM/SgiPkg/AcpiTables/SsdtIoVirtSocExp.asl | 96 ++++++++++
4 files changed, 291 insertions(+)
diff --git a/Platform/ARM/SgiPkg/SgiPlatform.dec
b/Platform/ARM/SgiPkg/SgiPlatform.dec
index e878af24d56b..1613cc01981e 100644
--- a/Platform/ARM/SgiPkg/SgiPlatform.dec
+++ b/Platform/ARM/SgiPkg/SgiPlatform.dec
@@ -98,5 +98,9 @@
# Address bus width
gArmSgiTokenSpaceGuid.PcdMaxAddressBitsPerChip|0x0|UINT64|0x00000027
+ # IO virtualization block
+ gArmSgiTokenSpaceGuid.PcdIoVirtSocExpBlk0Base|0|UINT64|0x0000002B
+ gArmSgiTokenSpaceGuid.PcdIoVirtSocExpBlkUartEnable|0|UINT32|0x0000002C
+
[Ppis]
gNtFwConfigDtInfoPpiGuid = { 0x6f606eb3, 0x9123, 0x4e15, { 0xa8, 0x9b,
0x0f, 0xac, 0x66, 0xef, 0xd0, 0x17 } }
diff --git a/Platform/ARM/SgiPkg/SgiMemoryMap2.dsc.inc
b/Platform/ARM/SgiPkg/SgiMemoryMap2.dsc.inc
index 12dcd82eb132..de1d8ea24b89 100644
--- a/Platform/ARM/SgiPkg/SgiMemoryMap2.dsc.inc
+++ b/Platform/ARM/SgiPkg/SgiMemoryMap2.dsc.inc
@@ -72,3 +72,6 @@
gArmSgiTokenSpaceGuid.PcdGpioController0BaseAddress|0x0C1D0000
gArmSgiTokenSpaceGuid.PcdGpioController0Size|0x00010000
gArmSgiTokenSpaceGuid.PcdGpioController0Interrupt|392
+
+ # IO virtualization block
+ gArmSgiTokenSpaceGuid.PcdIoVirtSocExpBlk0Base|0x1080000000
diff --git a/Platform/ARM/SgiPkg/Include/IoVirtSoCExp.h
b/Platform/ARM/SgiPkg/Include/IoVirtSoCExp.h
new file mode 100644
index 000000000000..ab20f7b1413b
--- /dev/null
+++ b/Platform/ARM/SgiPkg/Include/IoVirtSoCExp.h
@@ -0,0 +1,188 @@
+/** @file
+*
+* Copyright (c) 2023, Arm Limited. All rights reserved.
+*
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#include "SgiPlatform.h"
+
+#define IO_VIRT_BLK_BASE FixedPcdGet64 (PcdIoVirtSocExpBlk0Base)
+#define DEV_OFFSET 0x10000000
+#define RESOURCE_SIZE 0x10000
+
+/** Macros to calculate base addresses of UART and DMA devices within IO
+ virtualization SoC expansion block address space.
+
+ @param [in] n Index of UART or DMA device within SoC expansion block.
+ Should be either 0 or 1.
+
+ The base address offsets of UART and DMA devices within a SoC expansion block
+ are shown below. The UARTs are at offset (2 * index * offset), while the DMAs
+ are at offsets ((2 * index + 1) * offset).
+ +----------------------------------------------+
+ | Port # | Peripheral | Base address offset |
+ |--------|---------------|---------------------|
+ | x4_0 | PL011_UART0 | 0x0000_0000 |
+ |--------|---------------|---------------------|
+ | x4_1 | PL011_DMA0_NS | 0x1000_0000 |
+ |--------|---------------|---------------------|
+ | x8 | PL011_UART1 | 0x2000_0000 |
+ |--------|---------------|---------------------|
+ | x16 | PL011_DMA1_NS | 0x3000_0000 |
+ +----------------------------------------------+
+**/
+#define UART_START(n) IO_VIRT_BLK_BASE + (2 * n * DEV_OFFSET)
+#define DMA_START(n) IO_VIRT_BLK_BASE + (((2 * n) + 1) * DEV_OFFSET)
+
+// Interrupt numbers of PL330 DMA-0 and DMA-1 devices in the SoC expansion
+// connected to the IO Virtualization block. Each DMA PL330 controller uses
+// eight data channel interrupts and one instruction channel interrupt to
+// notify aborts.
+#define RD_IOVIRT_SOC_EXP_DMA0_INTERRUPTS_INIT
\
+ Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) {
\
+ 493, 494, 495, 496, 497, 498, 499, 500, 501
\
+ }
+#define RD_IOVIRT_SOC_EXP_DMA1_INTERRUPTS_INIT
\
+ Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) {
\
+ 503, 504, 505, 506, 507, 508, 509, 510, 511
\
+ }
+
+#define RD_IOVIRT_SOC_EXP_DMA2_INTERRUPTS_INIT
\
+ Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) {
\
+ 973, 974, 975, 976, 977, 978, 979, 980, 981
\
+ }
+
+#define RD_IOVIRT_SOC_EXP_DMA3_INTERRUPTS_INIT
\
+ Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) {
\
+ 983, 984, 985, 986, 987, 988, 989, 990, 991
\
+ }
+
+#define RD_IOVIRT_SOC_EXP_DMA4_INTERRUPTS_INIT
\
+ Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) {
\
+ 4557, 4558, 4559, 4560, 4561, 4562, 4563, 4564, 4565
\
+ }
+
+#define RD_IOVIRT_SOC_EXP_DMA5_INTERRUPTS_INIT
\
+ Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) {
\
+ 4567, 4568, 4569, 4570, 4571, 4572, 4573, 4574, 4575
\
+ }
+
+#define RD_IOVIRT_SOC_EXP_DMA6_INTERRUPTS_INIT
\
+ Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) {
\
+ 5037, 5038, 5039, 5040, 5041, 5042, 5043, 5044, 5045
\
+ }
+
+#define RD_IOVIRT_SOC_EXP_DMA7_INTERRUPTS_INIT
\
+ Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) {
\
+ 5047, 5048, 5049, 5050, 5051, 5052, 5053, 5054, 5055
\
+ }
+
+/** Macro for PL011 UART controller node instantiation in SSDT table.
+
+ See section 5.2.11.2 of ACPI specification v6.4 for the definition of SSDT
+ table.
+
+ @param [in] ComIdx Index of Com device to be initializaed;
+ to be passed as 2-digit index, such as 01 to
+ support multichip platforms as well.
+ @param [in] ChipIdx Index of chip to which this DMA device belongs
+ @param [in] StartOff Starting offset of this device within IO
+ virtualization block memory map
+ @param [in] IrqNum Interrupt ID used for the device
+**/
+#define RD_IOVIRT_SOC_EXP_COM_INIT(ComIdx, ChipIdx, StartOff, IrqNum)
\
+ Device (COM ##ComIdx) {
\
+ Name (_HID, "ARMH0011")
\
+ Name (_UID, ComIdx)
\
+ Name (_STA, 0xF)
\
+
\
+ Method (_CRS, 0, Serialized) {
\
+ Name (RBUF, ResourceTemplate () {
\
+ QWordMemory (
\
+ ResourceProducer,
\
+ PosDecode,
\
+ MinFixed,
\
+ MaxFixed,
\
+ NonCacheable,
\
+ ReadWrite,
\
+ 0x0,
\
+ 0,
\
+ 1,
\
+ 0x0,
\
+ 2,
\
+ ,
\
+ ,
\
+ MMI1,
\
+ AddressRangeMemory,
\
+ TypeStatic
\
+ )
\
+
\
+ Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) {
\
+ IrqNum
\
+ }
\
+ }) /* end Name(RBUF) */
\
+ /* Work around ASL's inability to add in a resource definition */
\
+ CreateQwordField (RBUF, MMI1._MIN, MIN1)
\
+ CreateQwordField (RBUF, MMI1._MAX, MAX1)
\
+ CreateQwordField (RBUF, MMI1._LEN, LEN1)
\
+ Add (SGI_REMOTE_CHIP_MEM_OFFSET(ChipIdx), StartOff, MIN1)
\
+ Add (MIN1, RESOURCE_SIZE - 1, MAX1)
\
+ Add (RESOURCE_SIZE, 0, LEN1)
\
+
\
+ Return (RBUF)
\
+ } /* end Method(_CRS) */
\
+ }
+
+/** Macro for PL330 DMA controller node instantiation in SSDT table.
+
+ See section 5.2.11.2 of ACPI specification v6.4 for the definition of SSDT
+ table.
+
+ @param [in] DmaIdx Index of DMA device to be initializaed
+ @param [in] ChipIdx Index of chip to which this DMA device belongs
+ @param [in] StartOff Starting offset of this device within IO
+ virtualization block memory map
+**/
+#define RD_IOVIRT_SOC_EXP_DMA_INIT(DmaIdx, ChipIdx, StartOff)
\
+ Device (\_SB.DMA ##DmaIdx) {
\
+ Name (_HID, "ARMH0330")
\
+ Name (_UID, DmaIdx)
\
+ Name (_CCA, 1)
\
+ Name (_STA, 0xF)
\
+
\
+ Method (_CRS, 0, Serialized) {
\
+ Name (RBUF, ResourceTemplate () {
\
+ QWordMemory (
\
+ ResourceProducer,
\
+ PosDecode,
\
+ MinFixed,
\
+ MaxFixed,
\
+ NonCacheable,
\
+ ReadWrite,
\
+ 0x0,
\
+ 0,
\
+ 1,
\
+ 0x0,
\
+ 2,
\
+ ,
\
+ ,
\
+ MMI2,
\
+ AddressRangeMemory,
\
+ TypeStatic
\
+ )
\
+
\
+ RD_IOVIRT_SOC_EXP_DMA ##DmaIdx## _INTERRUPTS_INIT
\
+ }) /* end Name(RBUF) */
\
+ /* Work around ASL's inability to add in a resource definition */
\
+ CreateQwordField (RBUF, MMI2._MIN, MIN2)
\
+ CreateQwordField (RBUF, MMI2._MAX, MAX2)
\
+ CreateQwordField (RBUF, MMI2._LEN, LEN2)
\
+ Add (SGI_REMOTE_CHIP_MEM_OFFSET(ChipIdx), StartOff, MIN2)
\
+ Add (MIN2, RESOURCE_SIZE - 1, MAX2)
\
+ Add (RESOURCE_SIZE, 0, LEN2)
\
+
\
+ Return (RBUF)
\
+ } /* end Method(_CRS) */
\
+ }
diff --git a/Platform/ARM/SgiPkg/AcpiTables/SsdtIoVirtSocExp.asl
b/Platform/ARM/SgiPkg/AcpiTables/SsdtIoVirtSocExp.asl
new file mode 100644
index 000000000000..d852cf4ffeaa
--- /dev/null
+++ b/Platform/ARM/SgiPkg/AcpiTables/SsdtIoVirtSocExp.asl
@@ -0,0 +1,96 @@
+/** @file
+ Secondary System Description Table (SSDT) for IO Virtualization SoC Expansion
+
+ The IO virtualization blocks on Arm Reference Design (RD) platforms allow
+ connecting PCIe root bus as well as other non-PCIe SoC peripherals. Each of
+ these IO virtualization blocks consists of an instance of SMMUv3, a GIC-ITS
+ and a NCI (network chip interconnect) to support traffic flow and address
+ mapping, as required. The PCIe root bus or the SoC peripherals connect to the
+ IO virtualization block over ports namely x4_0, x4_1, x8 and x16.
+
+ Some of the RD platforms utilize one or more IO virtualization blocks to
+ connect non-PCIe devices mapped in the SoC expansion address space. One
+ such instance of SoC expansion block consists of a set of non-PCIe devices
+ that includes two PL011 UART controllers, two PL330 DMA controllers and
+ few additional memory nodes. The devices in this SoC expansion block are
+ placed at fixed offsets from a base address in the SoC expansion address
+ space and the read/write accesses to these devices are routed by the IO
+ virtualization block.
+
+ The table below lists the address offset, address space size and interrupts
+ used for the devices present in each instance of this SoC expansion block
+ that is connected to the IO Virtualization block.
+
+-------------------------------------------------------------------------------+
+ | Port | Peripheral | Memory map | Size |
Interrupt |
+ | # | |-------------------------------------| | ID
|
+ | | | Start Addr Offset | End Addr Offset | |
|
+
+-------------------------------------------------------------------------------+
+ | x4_0 | PL011_UART0 | 0x0000_0000 | 0x0000_FFFF | 64KB | 492
|
+
|-------------------------------------------------------------------------------|
+ | x4_1 | PL011_DMA0_NS | 0x1000_0000 | 0x1000_FFFF | 64KB |
493-501 |
+
|-------------------------------------------------------------------------------|
+ | x8 | PL011_UART1 | 0x2000_0000 | 0x2000_FFFF | 64KB | 502
|
+
|-------------------------------------------------------------------------------|
+ | x16 | PL011_DMA1_NS | 0x3000_0000 | 0x3000_FFFF | 64KB |
503-511 |
+
+-------------------------------------------------------------------------------+
+
+ This SSDT ACPI table lists the SoC expansion block devices connected via the
+ IO Virtualization block on RD-N2 platform variants and mapped to SoC
expansion
+ address at an offset of 0x10_8000_0000 from each chip's base address.
+
+ Copyright (c) 2023, Arm Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Specification Reference:
+ - ACPI 6.4, Chapter 5, Section 5.2.11.2, Secondary System Description Table
+**/
+
+#include "IoVirtSoCExp.h"
+#include "SgiAcpiHeader.h"
+
+DefinitionBlock ("SsdtIoVirtSocExp.aml", "SSDT", 2, "ARMLTD", "ARMSGI",
+ EFI_ACPI_ARM_OEM_REVISION) {
+ Scope (_SB)
+ {
+
+ // IO Virtualization SoC Expansion - PL011 UART
+#if (FixedPcdGet32 (PcdIoVirtSocExpBlkUartEnable) == 1)
+ RD_IOVIRT_SOC_EXP_COM_INIT(2, 0, UART_START(0), 492)
+ RD_IOVIRT_SOC_EXP_COM_INIT(3, 0, UART_START(1), 502)
+
+#if (FixedPcdGet32 (PcdChipCount) > 1)
+ RD_IOVIRT_SOC_EXP_COM_INIT(4, 1, UART_START(0), 972)
+ RD_IOVIRT_SOC_EXP_COM_INIT(5, 1, UART_START(1), 982)
+#endif
+
+#if (FixedPcdGet32 (PcdChipCount) > 2)
+ RD_IOVIRT_SOC_EXP_COM_INIT(6, 2, UART_START(0), 4556)
+ RD_IOVIRT_SOC_EXP_COM_INIT(7, 2, UART_START(1), 4566)
+#endif
+
+#if (FixedPcdGet32 (PcdChipCount) > 3)
+ RD_IOVIRT_SOC_EXP_COM_INIT(8, 3, UART_START(0), 5036)
+ RD_IOVIRT_SOC_EXP_COM_INIT(9, 3, UART_START(1), 5046)
+#endif
+#endif
+
+ // IO Virtualization SoC Expansion - PL330 DMA
+ RD_IOVIRT_SOC_EXP_DMA_INIT(0, 0, DMA_START(0))
+ RD_IOVIRT_SOC_EXP_DMA_INIT(1, 0, DMA_START(1))
+
+#if (FixedPcdGet32 (PcdChipCount) > 1)
+ RD_IOVIRT_SOC_EXP_DMA_INIT(2, 1, DMA_START(0))
+ RD_IOVIRT_SOC_EXP_DMA_INIT(3, 1, DMA_START(1))
+#endif
+
+#if (FixedPcdGet32 (PcdChipCount) > 2)
+ RD_IOVIRT_SOC_EXP_DMA_INIT(4, 2, DMA_START(0))
+ RD_IOVIRT_SOC_EXP_DMA_INIT(5, 2, DMA_START(1))
+#endif
+
+#if (FixedPcdGet32 (PcdChipCount) > 3)
+ RD_IOVIRT_SOC_EXP_DMA_INIT(6, 3, DMA_START(0))
+ RD_IOVIRT_SOC_EXP_DMA_INIT(7, 3, DMA_START(1))
+#endif
+ } // Scope(_SB)
+}