summaryrefslogtreecommitdiff
path: root/drivers/arm/gic/v3/gicv3_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/arm/gic/v3/gicv3_main.c')
-rw-r--r--drivers/arm/gic/v3/gicv3_main.c38
1 files changed, 38 insertions, 0 deletions
diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c
index a5067322..c81ba950 100644
--- a/drivers/arm/gic/v3/gicv3_main.c
+++ b/drivers/arm/gic/v3/gicv3_main.c
@@ -999,3 +999,41 @@ void gicv3_raise_secure_g0_sgi(int sgi_num, u_register_t target)
write_icc_sgi0r_el1(sgi_val);
isb();
}
+
+/*******************************************************************************
+ * This function sets the interrupt routing for the given SPI interrupt id.
+ * The interrupt routing is specified in routing mode and mpidr.
+ *
+ * The routing mode can be either of:
+ * - GICV3_IRM_ANY
+ * - GICV3_IRM_PE
+ *
+ * The mpidr is the affinity of the PE to which the interrupt will be routed,
+ * and is ignored for routing mode GICV3_IRM_ANY.
+ ******************************************************************************/
+void gicv3_set_spi_routing(unsigned int id, unsigned int irm, u_register_t mpidr)
+{
+ unsigned long long aff;
+ uint64_t router;
+
+ assert(gicv3_driver_data);
+ assert(gicv3_driver_data->gicd_base);
+
+ assert((irm == GICV3_IRM_ANY) || (irm == GICV3_IRM_PE));
+ assert(id >= MIN_SPI_ID && id <= MAX_SPI_ID);
+
+ aff = gicd_irouter_val_from_mpidr(mpidr, irm);
+ gicd_write_irouter(gicv3_driver_data->gicd_base, id, aff);
+
+ /*
+ * In implementations that do not require 1 of N distribution of SPIs,
+ * IRM might be RAZ/WI. Read back and verify IRM bit.
+ */
+ if (irm == GICV3_IRM_ANY) {
+ router = gicd_read_irouter(gicv3_driver_data->gicd_base, id);
+ if (!((router >> IROUTER_IRM_SHIFT) & IROUTER_IRM_MASK)) {
+ ERROR("GICv3 implementation doesn't support routing ANY\n");
+ panic();
+ }
+ }
+}