feat(lib/pcie): add dvsec helpers
Add DVSEC RME DA support and helpers based on RME System
Architecture [1].
[1] https://developer.arm.com/documentation/den0129/latest
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: I29c2dc3c94fa295c9948f63f57f88e2763326291
diff --git a/include/lib/pcie/pcie_dvsec_rmeda.h b/include/lib/pcie/pcie_dvsec_rmeda.h
new file mode 100644
index 0000000..b693f2a
--- /dev/null
+++ b/include/lib/pcie/pcie_dvsec_rmeda.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PCIE_DVSEC_RME_DA_H
+#define PCIE_DVSEC_RME_DA_H
+
+/* PCI RootPort Extended Capability RMEDA registers offset */
+
+/*
+ * Extended Capability Header
+ * DVSEC Headers
+ * RME-DA Control registers
+ */
+#define PCIE_ECAP_ECH_OFFSET U(0)
+#define PCIE_ECAP_DVSEC_HDR1_OFFSET U(4)
+#define PCIE_ECAP_DVSEC_HDR2_OFFSET U(8)
+#define PCIE_ECAP_DVSEC_RME_DA_CTL_REG1_OFFSET U(12)
+#define PCIE_ECAP_DVSEC_RME_DA_CTL_REG2_OFFSET U(16)
+
+/* RME-DA DVSEC Header1 */
+#define DVSEC_HDR1_VENDOR_ID_SHIFT U(0)
+#define DVSEC_HDR1_VENDOR_ID_WIDTH U(16)
+#define DVSEC_HDR1_REVISION_SHIFT U(16)
+#define DVSEC_HDR1_REVISION_WIDTH U(4)
+#define DVSEC_HDR1_LENGTH_SHIFT U(20)
+#define DVSEC_HDR1_LENGTH_WIDTH U(12)
+
+/* RME-DA DVSEC Header1 - Values */
+#define DVSEC_VENDOR_ID_ARM U(0x13b5)
+#define DVSEC_REVISION_0 U(0x0)
+
+/* RME-DA DVSEC Header2 */
+#define DVSEC_HDR2_DVSEC_ID_SHIFT U(0)
+#define DVSEC_HDR2_DVSEC_ID_WIDTH U(16)
+
+/* RME-DA DVSEC Header2 - Values */
+#define DVSEC_ID_RME_DA U(0xFF01)
+
+/* RME-DA Control register 1 */
+#define DVSEC_RMEDA_CTL_REG1_TDISP_EN_SHIFT U(0)
+#define DVSEC_RMEDA_CTL_REG1_TDISP_EN_WIDTH U(1)
+
+/* RME-DA Control register 1 - Values */
+#define RME_DA_TDISP_DISABLE U(0)
+#define RME_DA_TDISP_ENABLE U(1)
+
+/* RME-DA Control register 2. 32 IDE Selective Stream Lock bits */
+#define DVSEC_RME_DA_CTL_REG2_SEL_STR_LOCK_SHIFT U(0)
+#define DVSEC_RME_DA_CTL_REG2_SEL_STR_LOCK_WIDTH U(32)
+
+uint32_t pcie_find_rmeda_capability(uint32_t bdf, uint32_t *cid_offset);
+
+#endif /* PCIE_DVSEC_RME_DA_H */
diff --git a/include/lib/pcie/pcie_spec.h b/include/lib/pcie/pcie_spec.h
index 31fd98b..cd851ee 100644
--- a/include/lib/pcie/pcie_spec.h
+++ b/include/lib/pcie/pcie_spec.h
@@ -87,6 +87,14 @@
#define PCIE_ECAP_CIDR_MASK 0xffff
#define PCIE_ECAP_NCPR_MASK 0xfff
+/* PCIe Extended Capability Header */
+#define PCIE_ECH_ID_SHIFT U(0)
+#define PCIE_ECH_ID_WIDTH U(16)
+#define PCIE_ECH_CAP_VER_SHIFT U(16)
+#define PCIE_ECH_CAP_VER_WIDTH U(4)
+#define PCIE_ECH_NEXT_CAP_OFFSET_SHIFT U(20)
+#define PCIE_ECH_NEXT_CAP_OFFSET_WIDTH U(12)
+
#define PCIE_CAP_START 0x40
#define PCIE_CAP_END 0xFC
#define PCIE_ECAP_START 0x100
@@ -107,6 +115,8 @@
#define ECID_PASID 0x001B
#define ECID_DPC 0x001D
#define ECID_DVSEC 0x0023
+#define ECID_DOE 0x002E
+#define ECID_IDE 0x0030
/* PCI Express capability struct offsets */
#define CIDR_OFFSET 0x0
diff --git a/lib/pcie/pcie_dvsec_rmeda.c b/lib/pcie/pcie_dvsec_rmeda.c
new file mode 100644
index 0000000..c1da99a
--- /dev/null
+++ b/lib/pcie/pcie_dvsec_rmeda.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common_def.h>
+#include <errno.h>
+#include <stddef.h>
+#include <debug.h>
+#include <mmio.h>
+#include <pcie.h>
+#include <pcie_spec.h>
+#include <pcie_dvsec_rmeda.h>
+#include <platform.h>
+#include <tftf_lib.h>
+
+/*
+ * Check if the DVSEC header matches RME Sys Arch spec
+ *
+ * DVSEC_REVISION must be 0
+ * DVSEC_VENDOR_ID must be Arm
+ * DVSEC_ID must be RME_DA
+ */
+static bool is_dvsec_arm_rmeda(uint32_t rp_bdf, uint32_t dvsec_base)
+{
+ uint32_t hdr1 = 0U;
+ uint32_t hdr2 = 0U;
+
+ hdr1 = pcie_read_cfg(rp_bdf, dvsec_base + PCIE_ECAP_DVSEC_HDR1_OFFSET);
+ hdr2 = pcie_read_cfg(rp_bdf, dvsec_base + PCIE_ECAP_DVSEC_HDR2_OFFSET);
+
+ if ((EXTRACT(DVSEC_HDR1_VENDOR_ID, hdr1) == DVSEC_VENDOR_ID_ARM) &&
+ (EXTRACT(DVSEC_HDR1_REVISION, hdr1) == DVSEC_REVISION_0) &&
+ (EXTRACT(DVSEC_HDR2_DVSEC_ID, hdr2) == DVSEC_ID_RME_DA)) {
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Traverse all DVSEC extended capability and return the first RMEDA DVSEC if the
+ * header, revision are expected as mentioned in RME System Architecture.
+ */
+uint32_t pcie_find_rmeda_capability(uint32_t rp_bdf, uint32_t *cid_offset)
+{
+ uint32_t ech;
+ unsigned int dvsec_offset;
+ uint16_t next_cap_offset;
+
+ dvsec_offset = PCIE_ECAP_START;
+ do {
+ assert((dvsec_offset + sizeof(ech)) < SZ_4K);
+
+ ech = pcie_read_cfg(rp_bdf, dvsec_offset);
+
+ /* Check for PCIE_ECH_CAP_VER_1 as well? */
+ if ((EXTRACT(PCIE_ECH_ID, ech) == ECID_DVSEC) &&
+ is_dvsec_arm_rmeda(rp_bdf, dvsec_offset)) {
+ *cid_offset = dvsec_offset;
+ return PCIE_SUCCESS;
+ }
+
+ next_cap_offset = EXTRACT(PCIE_ECH_NEXT_CAP_OFFSET, ech);
+ dvsec_offset += next_cap_offset;
+ } while ((next_cap_offset != 0U) && (dvsec_offset < PCIE_ECAP_END));
+
+ return PCIE_CAP_NOT_FOUND;
+}
diff --git a/tftf/tests/tests-realm-payload.mk b/tftf/tests/tests-realm-payload.mk
index add6a7f..5859d31 100644
--- a/tftf/tests/tests-realm-payload.mk
+++ b/tftf/tests/tests-realm-payload.mk
@@ -62,6 +62,7 @@
$(addprefix lib/pcie/, \
pcie.c \
pcie_doe.c \
+ pcie_dvsec_rmeda.c \
)
ifeq (${ENABLE_REALM_PAYLOAD_TESTS},1)