feat(fvp): add GICv5 support
Factors out GICv3 specific code and replace it with GICv5. This can be
selected with FVP_USE_GIC_DRIVER=FVP_GICV5. Specifically, the FCONF
logic does not apply to GICv5 as the bindings are completely different.
This patch does not include a device tree. This will be added at a later
date.
Change-Id: Ifd0c7b4e0bc2ea1e53a6779ab4c50c4aec39dafb
Signed-off-by: Boyan Karatotev <boyan.karatotev@arm.com>
diff --git a/plat/arm/board/fvp/fconf/fconf_gicv3_config_getter.c b/plat/arm/board/fvp/fconf/fconf_gicv3_config_getter.c
new file mode 100644
index 0000000..7cb88ed
--- /dev/null
+++ b/plat/arm/board/fvp/fconf/fconf_gicv3_config_getter.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2025, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/arm/gicv3.h>
+
+#include <fconf_hw_config_getter.h>
+
+struct gicv3_config_t gicv3_config;
+
+int fconf_populate_gicv3_config(uintptr_t config)
+{
+ int err;
+ int node;
+ uintptr_t addr;
+
+ /* Necessary to work with libfdt APIs */
+ const void *hw_config_dtb = (const void *)config;
+
+ /*
+ * Find the offset of the node containing "arm,gic-v3" compatible property.
+ * Populating fconf strucutures dynamically is not supported for legacy
+ * systems which use GICv2 IP. Simply skip extracting GIC properties.
+ */
+ node = fdt_node_offset_by_compatible(hw_config_dtb, -1, "arm,gic-v3");
+ if (node < 0) {
+ WARN("FCONF: Unable to locate node with arm,gic-v3 compatible property\n");
+ return 0;
+ }
+ /* The GICv3 DT binding holds at least two address/size pairs,
+ * the first describing the distributor, the second the redistributors.
+ * See: bindings/interrupt-controller/arm,gic-v3.yaml
+ */
+ err = fdt_get_reg_props_by_index(hw_config_dtb, node, 0, &addr, NULL);
+ if (err < 0) {
+ ERROR("FCONF: Failed to read GICD reg property of GIC node\n");
+ return err;
+ }
+ gicv3_config.gicd_base = addr;
+
+ err = fdt_get_reg_props_by_index(hw_config_dtb, node, 1, &addr, NULL);
+ if (err < 0) {
+ ERROR("FCONF: Failed to read GICR reg property of GIC node\n");
+ } else {
+ gicv3_config.gicr_base = addr;
+ }
+
+ return err;
+}
+FCONF_REGISTER_POPULATOR(HW_CONFIG, gicv3_config, fconf_populate_gicv3_config);
diff --git a/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c b/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c
index fb7f48e..abc78ce 100644
--- a/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c
+++ b/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c
@@ -14,7 +14,6 @@
#include <libfdt.h>
#include <plat/common/platform.h>
-struct gicv3_config_t gicv3_config;
struct hw_topology_t soc_topology;
struct uart_serial_config_t uart_serial_config;
struct cpu_timer_t cpu_timer;
@@ -32,45 +31,6 @@
#define ILLEGAL_ADDR ULL(~0)
-int fconf_populate_gicv3_config(uintptr_t config)
-{
- int err;
- int node;
- uintptr_t addr;
-
- /* Necessary to work with libfdt APIs */
- const void *hw_config_dtb = (const void *)config;
-
- /*
- * Find the offset of the node containing "arm,gic-v3" compatible property.
- * Populating fconf strucutures dynamically is not supported for legacy
- * systems which use GICv2 IP. Simply skip extracting GIC properties.
- */
- node = fdt_node_offset_by_compatible(hw_config_dtb, -1, "arm,gic-v3");
- if (node < 0) {
- WARN("FCONF: Unable to locate node with arm,gic-v3 compatible property\n");
- return 0;
- }
- /* The GICv3 DT binding holds at least two address/size pairs,
- * the first describing the distributor, the second the redistributors.
- * See: bindings/interrupt-controller/arm,gic-v3.yaml
- */
- err = fdt_get_reg_props_by_index(hw_config_dtb, node, 0, &addr, NULL);
- if (err < 0) {
- ERROR("FCONF: Failed to read GICD reg property of GIC node\n");
- return err;
- }
- gicv3_config.gicd_base = addr;
-
- err = fdt_get_reg_props_by_index(hw_config_dtb, node, 1, &addr, NULL);
- if (err < 0) {
- ERROR("FCONF: Failed to read GICR reg property of GIC node\n");
- } else {
- gicv3_config.gicr_base = addr;
- }
-
- return err;
-}
int fconf_populate_topology(uintptr_t config)
{
@@ -447,7 +407,6 @@
return 0;
}
-FCONF_REGISTER_POPULATOR(HW_CONFIG, gicv3_config, fconf_populate_gicv3_config);
FCONF_REGISTER_POPULATOR(HW_CONFIG, topology, fconf_populate_topology);
FCONF_REGISTER_POPULATOR(HW_CONFIG, uart_config, fconf_populate_uart_config);
FCONF_REGISTER_POPULATOR(HW_CONFIG, cpu_timer, fconf_populate_cpu_timer);
diff --git a/plat/arm/board/fvp/fvp_common.c b/plat/arm/board/fvp/fvp_common.c
index 9d0463d..95dff53 100644
--- a/plat/arm/board/fvp/fvp_common.c
+++ b/plat/arm/board/fvp/fvp_common.c
@@ -68,6 +68,10 @@
#define MAP_DEVICE1 MAP_REGION_FLAT(DEVICE1_BASE, \
DEVICE1_SIZE, \
+ MT_DEVICE | MT_RW | EL3_PAS)
+
+#define MAP_CCN MAP_REGION_FLAT(CCN_BASE, \
+ CCN_SIZE, \
MT_DEVICE | MT_RW | MT_SECURE)
#if FVP_GICR_REGION_PROTECTION
@@ -115,7 +119,7 @@
V2M_MAP_IOFPGA,
MAP_DEVICE0,
#if FVP_INTERCONNECT_DRIVER == FVP_CCN
- MAP_DEVICE1,
+ MAP_CCN,
#endif
#if TRUSTED_BOARD_BOOT
/* To access the Root of Trust Public Key registers. */
@@ -133,7 +137,7 @@
V2M_MAP_IOFPGA,
MAP_DEVICE0,
#if FVP_INTERCONNECT_DRIVER == FVP_CCN
- MAP_DEVICE1,
+ MAP_CCN,
#endif
ARM_MAP_NS_DRAM1,
#ifdef __aarch64__
@@ -208,6 +212,9 @@
MAP_GICD_MEM,
MAP_GICR_MEM,
#else
+#if FVP_INTERCONNECT_DRIVER == FVP_CCN
+ MAP_CCN,
+#endif
MAP_DEVICE1,
#endif /* FVP_GICR_REGION_PROTECTION */
ARM_V2M_MAP_MEM_PROTECT,
@@ -254,6 +261,9 @@
#endif
V2M_MAP_IOFPGA,
MAP_DEVICE0,
+#if FVP_INTERCONNECT_DRIVER == FVP_CCN
+ MAP_CCN,
+#endif
MAP_DEVICE1,
{0}
};
diff --git a/plat/arm/board/fvp/fvp_def.h b/plat/arm/board/fvp/fvp_def.h
index 831eb35..d87be31 100644
--- a/plat/arm/board/fvp/fvp_def.h
+++ b/plat/arm/board/fvp/fvp_def.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2025, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -53,12 +53,12 @@
* In case of FVP models with CCN, the CCN register space overlaps into
* the NSRAM area.
*/
-#if FVP_INTERCONNECT_DRIVER == FVP_CCN
-#define DEVICE1_BASE UL(0x2e000000)
-#define DEVICE1_SIZE UL(0x1A00000)
-#else
-#define DEVICE1_BASE BASE_GICD_BASE
+#define CCN_BASE UL(0x2e000000)
+#define CCN_SIZE UL(0x1000000)
+/* TODO: this covers gicv5, but macros should be adjusted */
+#if USE_GIC_DRIVER != 5
+#define DEVICE1_BASE BASE_GICD_BASE
#if GIC_ENABLE_V4_EXTN
/* GICv4 mapping: GICD + CORE_COUNT * 256KB */
#define DEVICE1_SIZE ((BASE_GICR_BASE - BASE_GICD_BASE) + \
@@ -68,10 +68,11 @@
#define DEVICE1_SIZE ((BASE_GICR_BASE - BASE_GICD_BASE) + \
(PLATFORM_CORE_COUNT * 0x20000))
#endif /* GIC_ENABLE_V4_EXTN */
-
-#define NSRAM_BASE UL(0x2e000000)
-#define NSRAM_SIZE UL(0x10000)
+#else
+#define DEVICE1_BASE BASE_IWB_BASE
+#define DEVICE1_SIZE ((BASE_IRS_BASE - BASE_IWB_BASE) + SZ_64K)
#endif
+
/* Devices in the second GB */
#define DEVICE2_BASE UL(0x7fe00000)
#define DEVICE2_SIZE UL(0x00200000)
@@ -124,6 +125,15 @@
#define FVP_SP810_CTRL_TIM2_OV BIT_32(20)
#define FVP_SP810_CTRL_TIM3_OV BIT_32(22)
+
+#define NSRAM_BASE UL(0x2e000000)
+#define NSRAM_SIZE UL(0x10000)
+/*
+ * In case of FVP models with CCN, the CCN register space overlaps into
+ * the NSRAM area.
+ */
+#define CCN_BASE UL(0x2e000000)
+#define CCN_SIZE UL(0x1000000)
/*******************************************************************************
* GIC & interrupt handling related constants
******************************************************************************/
@@ -138,6 +148,9 @@
#define BASE_GICD_SIZE UL(0x10000)
#define BASE_GICR_BASE UL(0x2f100000)
+#define BASE_IWB_BASE UL(0x2f000000)
+#define BASE_IRS_BASE UL(0x2f1c0000)
+
#if GIC_ENABLE_V4_EXTN
/* GICv4 redistributor size: 256KB */
#define BASE_GICR_SIZE UL(0x40000)
diff --git a/plat/arm/board/fvp/fvp_gicv5.c b/plat/arm/board/fvp/fvp_gicv5.c
new file mode 100644
index 0000000..73bd9c5
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_gicv5.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2025, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/gicv5.h>
+#include <platform_def.h>
+
+/* wire 26 is the timer interrupt. Will be assigned NS by default */
+struct gicv5_wire_props irs0_spis[] = {
+};
+
+struct gicv5_wire_props iwb0_wires[] = {
+};
+
+struct gicv5_irs irss[] = {{
+ .el3_config_frame = BASE_IRS_BASE,
+ .spis = irs0_spis,
+ .num_spis = ARRAY_SIZE(irs0_spis),
+}};
+
+struct gicv5_iwb iwbs[] = {{
+ .config_frame = BASE_IWB_BASE,
+ .wires = iwb0_wires,
+ .num_wires = ARRAY_SIZE(iwb0_wires)
+}};
+
+const struct gicv5_driver_data plat_gicv5_driver_data = {
+ .irss = irss,
+ .iwbs = iwbs,
+ .num_irss = ARRAY_SIZE(irss),
+ .num_iwbs = ARRAY_SIZE(iwbs)
+};
+
+void fvp_gic_driver_pre_init(void)
+{
+}
+
+void fvp_pcpu_init(void)
+{
+}
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index 26ea58d..bf4aaf8 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -22,13 +22,6 @@
# only; enable redistributor frames of all CPU cores by default.
FVP_GICR_REGION_PROTECTION := 0
-ifeq (${HW_ASSISTED_COHERENCY}, 0)
-FVP_DT_PREFIX := fvp-base-gicv3-psci
-else
-FVP_DT_PREFIX := fvp-base-gicv3-psci-dynamiq
-endif
-# fdts is wrong otherwise
-
# Size (in kilobytes) of the Trusted SRAM region to utilize when building for
# the FVP platform.
ifeq (${ENABLE_RME},1)
@@ -137,7 +130,20 @@
GICV3_OVERRIDE_DISTIF_PWR_OPS := 1
FVP_SECURITY_SOURCES += plat/arm/board/fvp/fvp_gicv3.c
+ifeq ($(filter 1,${RESET_TO_BL2} ${RESET_TO_BL31}),)
+BL31_SOURCES += plat/arm/board/fvp/fconf/fconf_gicv3_config_getter.c
+endif
+ifeq (${HW_ASSISTED_COHERENCY}, 0)
+FVP_DT_PREFIX := fvp-base-gicv3-psci
+else
+FVP_DT_PREFIX := fvp-base-gicv3-psci-dynamiq
+endif
+else ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV5)
+USE_GIC_DRIVER := 5
+ENABLE_FEAT_GCIE := 1
+BL31_SOURCES += plat/arm/board/fvp/fvp_gicv5.c
+FVP_DT_PREFIX := "FVP does not provide a GICv5 dts yet"
else ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV2)
USE_GIC_DRIVER := 2