plat/fvp: Add support for dynamic description of secure interrupts
Using the fconf framework, the Group 0 and Group 1 secure interrupt
descriptors are moved to device tree and retrieved in runtime. This
feature is enabled by the build flag SEC_INT_DESC_IN_FCONF.
Change-Id: I360c63a83286c7ecc2426cd1ff1b4746d61e633c
Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
diff --git a/plat/arm/board/fvp/fvp_gicv3.c b/plat/arm/board/fvp/fvp_gicv3.c
index a3ee8ef..3e04d6b 100644
--- a/plat/arm/board/fvp/fvp_gicv3.c
+++ b/plat/arm/board/fvp/fvp_gicv3.c
@@ -12,6 +12,7 @@
#include <fconf_hw_config_getter.h>
#include <lib/utils.h>
#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/common/fconf_sec_intr_config.h>
#include <plat/common/platform.h>
/* The GICv3 driver only needs to be initialized in EL3 */
@@ -23,10 +24,13 @@
/* List of zero terminated GICR frame addresses which CPUs will probe */
static uint64_t *fvp_gicr_frames = fvp_gicr_base_addrs;
+#if !(SEC_INT_DESC_IN_FCONF && ((!defined(__aarch64__) && defined(IMAGE_BL32)) || \
+ (defined(__aarch64__) && defined(IMAGE_BL31))))
static const interrupt_prop_t fvp_interrupt_props[] = {
PLAT_ARM_G1S_IRQ_PROPS(INTR_GROUP1S),
PLAT_ARM_G0_IRQ_PROPS(INTR_GROUP0)
};
+#endif
/*
* MPIDR hashing function for translating MPIDRs read from GICR_TYPER register
@@ -52,8 +56,6 @@
static gicv3_driver_data_t fvp_gic_data = {
- .interrupt_props = fvp_interrupt_props,
- .interrupt_props_num = ARRAY_SIZE(fvp_interrupt_props),
.rdistif_num = PLATFORM_CORE_COUNT,
.rdistif_base_addrs = fvp_rdistif_base_addrs,
.mpidr_to_core_pos = fvp_gicv3_mpidr_hash
@@ -61,7 +63,10 @@
void plat_arm_gic_driver_init(void)
{
- /* Get GICD and GICR base addressed through FCONF APIs */
+ /*
+ * Get GICD and GICR base addressed through FCONF APIs.
+ * FCONF is not supported in BL32 for FVP.
+ */
#if (!defined(__aarch64__) && defined(IMAGE_BL32)) || \
(defined(__aarch64__) && defined(IMAGE_BL31))
fvp_gic_data.gicd_base = (uintptr_t)FCONF_GET_PROPERTY(hw_config,
@@ -69,9 +74,20 @@
gicd_base);
fvp_gicr_base_addrs[0] = FCONF_GET_PROPERTY(hw_config, gicv3_config,
gicr_base);
+#if SEC_INT_DESC_IN_FCONF
+ fvp_gic_data.interrupt_props = FCONF_GET_PROPERTY(hw_config,
+ sec_intr_prop, descriptor);
+ fvp_gic_data.interrupt_props_num = FCONF_GET_PROPERTY(hw_config,
+ sec_intr_prop, count);
+#else
+ fvp_gic_data.interrupt_props = fvp_interrupt_props;
+ fvp_gic_data.interrupt_props_num = ARRAY_SIZE(fvp_interrupt_props);
+#endif
#else
fvp_gic_data.gicd_base = PLAT_ARM_GICD_BASE;
fvp_gicr_base_addrs[0] = PLAT_ARM_GICR_BASE;
+ fvp_gic_data.interrupt_props = fvp_interrupt_props;
+ fvp_gic_data.interrupt_props_num = ARRAY_SIZE(fvp_interrupt_props);
#endif
/*
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index 024e682..e605608 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -221,6 +221,11 @@
BL31_SOURCES += common/fdt_wrappers.c \
lib/fconf/fconf.c \
plat/arm/board/fvp/fconf/fconf_hw_config_getter.c
+
+ifeq (${SEC_INT_DESC_IN_FCONF},1)
+BL31_SOURCES += plat/arm/common/fconf/fconf_sec_intr_config.c
+endif
+
endif
ifeq (${FVP_USE_SP804_TIMER},1)
diff --git a/plat/arm/board/fvp/sp_min/sp_min-fvp.mk b/plat/arm/board/fvp/sp_min/sp_min-fvp.mk
index ba6ceec..64cb7ad 100644
--- a/plat/arm/board/fvp/sp_min/sp_min-fvp.mk
+++ b/plat/arm/board/fvp/sp_min/sp_min-fvp.mk
@@ -25,6 +25,11 @@
BL32_SOURCES += common/fdt_wrappers.c \
lib/fconf/fconf.c \
plat/arm/board/fvp/fconf/fconf_hw_config_getter.c
+
+ifeq (${SEC_INT_DESC_IN_FCONF},1)
+BL32_SOURCES += plat/arm/common/fconf/fconf_sec_intr_config.c
+endif
+
endif
include plat/arm/common/sp_min/arm_sp_min.mk
diff --git a/plat/arm/common/fconf/fconf_sec_intr_config.c b/plat/arm/common/fconf/fconf_sec_intr_config.c
new file mode 100644
index 0000000..f28be24
--- /dev/null
+++ b/plat/arm/common/fconf/fconf_sec_intr_config.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <libfdt.h>
+#include <plat/arm/common/fconf_sec_intr_config.h>
+
+#define G0_INTR_NUM(i) g0_intr_prop[3U * (i)]
+#define G0_INTR_PRIORITY(i) g0_intr_prop[3U * (i) + 1]
+#define G0_INTR_CONFIG(i) g0_intr_prop[3U * (i) + 2]
+
+#define G1S_INTR_NUM(i) g1s_intr_prop[3U * (i)]
+#define G1S_INTR_PRIORITY(i) g1s_intr_prop[3U * (i) + 1]
+#define G1S_INTR_CONFIG(i) g1s_intr_prop[3U * (i) + 2]
+
+struct sec_intr_prop_t sec_intr_prop;
+
+static void print_intr_prop(interrupt_prop_t prop)
+{
+ VERBOSE("FCONF: Secure Interrupt NUM: %d, PRI: %d, TYPE: %d\n",
+ prop.intr_num, prop.intr_pri, prop.intr_cfg);
+}
+
+int fconf_populate_sec_intr_config(uintptr_t config)
+{
+ int node, err;
+ uint32_t g0_intr_count, g1s_intr_count;
+ uint32_t g0_intr_prop[SEC_INT_COUNT_MAX * 3];
+ uint32_t g1s_intr_prop[SEC_INT_COUNT_MAX * 3];
+
+ /* Necessary to work with libfdt APIs */
+ const void *hw_config_dtb = (const void *)config;
+
+ node = fdt_node_offset_by_compatible(hw_config_dtb, -1,
+ "arm,secure_interrupt_desc");
+ if (node < 0) {
+ ERROR("FCONF: Unable to locate node with %s compatible property\n",
+ "arm,secure_interrupt_desc");
+ return node;
+ }
+
+ /* Read number of Group 0 interrupts specified by platform */
+ err = fdt_read_uint32(hw_config_dtb, node, "g0_intr_cnt", &g0_intr_count);
+ if (err < 0) {
+ ERROR("FCONF: Could not locate g0s_intr_cnt property\n");
+ return err;
+ }
+
+ /* At least 1 Group 0 interrupt description has to be provided*/
+ if (g0_intr_count < 1U) {
+ ERROR("FCONF: Invalid number of Group 0 interrupts count specified\n");
+ return -1;
+ }
+
+ /* Read number of Group 1 secure interrupts specified by platform */
+ err = fdt_read_uint32(hw_config_dtb, node, "g1s_intr_cnt",
+ &g1s_intr_count);
+ if (err < 0) {
+ ERROR("FCONF: Could not locate g1s_intr_cnt property\n");
+ return err;
+ }
+
+ /* At least one Group 1 interrupt description has to be provided*/
+ if (g1s_intr_count < 1U) {
+ ERROR("FCONF: Invalid number of Group 1 secure interrupts count specified\n");
+ return -1;
+ }
+
+ /*
+ * Check if the total number of secure interrupts described are within
+ * the limit defined statically by the platform.
+ */
+ if ((g0_intr_count + g1s_intr_count) > SEC_INT_COUNT_MAX) {
+ ERROR("FCONF: Total number of secure interrupts exceed limit the of %d\n",
+ SEC_INT_COUNT_MAX);
+ return -1;
+ }
+
+ sec_intr_prop.count = g0_intr_count + g1s_intr_count;
+
+ /* Read the Group 0 interrupt descriptors */
+ err = fdt_read_uint32_array(hw_config_dtb, node, "g0_intr_desc",
+ g0_intr_count * 3, g0_intr_prop);
+ if (err < 0) {
+ ERROR("FCONF: Read cell failed for 'g0s_intr_desc': %d\n", err);
+ return err;
+ }
+
+ /* Read the Group 1 secure interrupt descriptors */
+ err = fdt_read_uint32_array(hw_config_dtb, node, "g1s_intr_desc",
+ g1s_intr_count * 3, g1s_intr_prop);
+ if (err < 0) {
+ ERROR("FCONF: Read cell failed for 'g1s_intr_desc': %d\n", err);
+ return err;
+ }
+
+ /* Populate Group 0 interrupt descriptors into fconf based C struct */
+ for (uint32_t i = 0; i < g0_intr_count; i++) {
+ interrupt_prop_t sec_intr_property;
+
+ /* Secure Interrupt Group: INTR_GROUP0 i.e., 0x1 */
+ sec_intr_property.intr_grp = 1;
+ sec_intr_property.intr_num = G0_INTR_NUM(i);
+ sec_intr_property.intr_pri = G0_INTR_PRIORITY(i);
+ sec_intr_property.intr_cfg = G0_INTR_CONFIG(i);
+ sec_intr_prop.descriptor[i] = sec_intr_property;
+ print_intr_prop(sec_intr_property);
+ }
+
+ /* Populate G1 secure interrupt descriptors into fconf based C struct */
+ for (uint32_t i = 0; i < g1s_intr_count; i++) {
+ interrupt_prop_t sec_intr_property;
+
+ /* Secure Interrupt Group: INTR_GROUP1S i.e., 0x0 */
+ sec_intr_property.intr_grp = 0;
+ sec_intr_property.intr_num = G1S_INTR_NUM(i);
+ sec_intr_property.intr_pri = G1S_INTR_PRIORITY(i);
+ sec_intr_property.intr_cfg = G1S_INTR_CONFIG(i);
+ sec_intr_prop.descriptor[i + g0_intr_count] = sec_intr_property;
+ print_intr_prop(sec_intr_property);
+ }
+
+ return 0;
+}
+
+FCONF_REGISTER_POPULATOR(HW_CONFIG, sec_intr_prop, fconf_populate_sec_intr_config);