summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/arm/gic/v2/gicv2_main.c33
-rw-r--r--drivers/arm/gic/v3/gicv3_main.c68
2 files changed, 101 insertions, 0 deletions
diff --git a/drivers/arm/gic/v2/gicv2_main.c b/drivers/arm/gic/v2/gicv2_main.c
index 4861e02d..8048c6a7 100644
--- a/drivers/arm/gic/v2/gicv2_main.c
+++ b/drivers/arm/gic/v2/gicv2_main.c
@@ -10,11 +10,19 @@
#include <debug.h>
#include <gic_common.h>
#include <gicv2.h>
+#include <spinlock.h>
#include "../common/gic_common_private.h"
#include "gicv2_private.h"
static const gicv2_driver_data_t *driver_data;
+/*
+ * Spinlock to guard registers needing read-modify-write. APIs protected by this
+ * spinlock are used either at boot time (when only a single CPU is active), or
+ * when the system is fully coherent.
+ */
+spinlock_t gic_lock;
+
/*******************************************************************************
* Enable secure interrupts and use FIQs to route them. Disable legacy bypass
* and set the priority mask register to allow all interrupts to trickle in.
@@ -335,3 +343,28 @@ void gicv2_set_interrupt_priority(unsigned int id, unsigned int priority)
gicd_set_ipriorityr(driver_data->gicd_base, id, priority);
}
+
+/*******************************************************************************
+ * This function assigns group for the interrupt identified by id. The group can
+ * be any of GICV2_INTR_GROUP*
+ ******************************************************************************/
+void gicv2_set_interrupt_type(unsigned int id, unsigned int type)
+{
+ assert(driver_data);
+ assert(driver_data->gicd_base);
+ assert(id <= MAX_SPI_ID);
+
+ /* Serialize read-modify-write to Distributor registers */
+ spin_lock(&gic_lock);
+ switch (type) {
+ case GICV2_INTR_GROUP1:
+ gicd_set_igroupr(driver_data->gicd_base, id);
+ break;
+ case GICV2_INTR_GROUP0:
+ gicd_clr_igroupr(driver_data->gicd_base, id);
+ break;
+ default:
+ assert(0);
+ }
+ spin_unlock(&gic_lock);
+}
diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c
index d0ecab61..04b47129 100644
--- a/drivers/arm/gic/v3/gicv3_main.c
+++ b/drivers/arm/gic/v3/gicv3_main.c
@@ -9,12 +9,20 @@
#include <assert.h>
#include <debug.h>
#include <gicv3.h>
+#include <spinlock.h>
#include "gicv3_private.h"
const gicv3_driver_data_t *gicv3_driver_data;
static unsigned int gicv2_compat;
/*
+ * Spinlock to guard registers needing read-modify-write. APIs protected by this
+ * spinlock are used either at boot time (when only a single CPU is active), or
+ * when the system is fully coherent.
+ */
+spinlock_t gic_lock;
+
+/*
* Redistributor power operations are weakly bound so that they can be
* overridden
*/
@@ -892,3 +900,63 @@ void gicv3_set_interrupt_priority(unsigned int id, unsigned int proc_num,
gicd_set_ipriorityr(gicv3_driver_data->gicd_base, id, priority);
}
}
+
+/*******************************************************************************
+ * This function assigns group for the interrupt identified by id. The proc_num
+ * is used if the interrupt is SGI or PPI, and programs the corresponding
+ * Redistributor interface. The group can be any of GICV3_INTR_GROUP*
+ ******************************************************************************/
+void gicv3_set_interrupt_type(unsigned int id, unsigned int proc_num,
+ unsigned int type)
+{
+ unsigned int igroup = 0, grpmod = 0;
+ uintptr_t gicr_base;
+
+ assert(gicv3_driver_data);
+ assert(gicv3_driver_data->gicd_base);
+ assert(proc_num < gicv3_driver_data->rdistif_num);
+ assert(gicv3_driver_data->rdistif_base_addrs);
+
+ switch (type) {
+ case INTR_GROUP1S:
+ igroup = 0;
+ grpmod = 1;
+ break;
+ case INTR_GROUP0:
+ igroup = 0;
+ grpmod = 0;
+ break;
+ case INTR_GROUP1NS:
+ igroup = 1;
+ grpmod = 0;
+ break;
+ default:
+ assert(0);
+ }
+
+ if (id < MIN_SPI_ID) {
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+ if (igroup)
+ gicr_set_igroupr0(gicr_base, id);
+ else
+ gicr_clr_igroupr0(gicr_base, id);
+
+ if (grpmod)
+ gicr_set_igrpmodr0(gicr_base, id);
+ else
+ gicr_clr_igrpmodr0(gicr_base, id);
+ } else {
+ /* Serialize read-modify-write to Distributor registers */
+ spin_lock(&gic_lock);
+ if (igroup)
+ gicd_set_igroupr(gicv3_driver_data->gicd_base, id);
+ else
+ gicd_clr_igroupr(gicv3_driver_data->gicd_base, id);
+
+ if (grpmod)
+ gicd_set_igrpmodr(gicv3_driver_data->gicd_base, id);
+ else
+ gicd_clr_igrpmodr(gicv3_driver_data->gicd_base, id);
+ spin_unlock(&gic_lock);
+ }
+}