GIC: Allow specifying interrupt properties

The GIC driver initialization currently allows an array of interrupts to
be configured as secure. Future use cases would require more interrupt
configuration other than just security, such as priority.

This patch introduces a new interrupt property array as part of both
GICv2 and GICv3 driver data. The platform can populate the array with
interrupt numbers and respective properties. The corresponding driver
initialization iterates through the array, and applies interrupt
configuration as required.

This capability, and the current way of supplying array (or arrays, in
case of GICv3) of secure interrupts, are however mutually exclusive.
Henceforth, the platform should supply either:

  - A list of interrupts to be mapped as secure (the current way).
    Platforms that do this will continue working as they were. With this
    patch, this scheme is deprecated.

  - A list of interrupt properties (properties include interrupt group).
    Individual interrupt properties are specified via. descriptors of
    type 'interrupt_prop_desc_t', which can be populated with the macro
    INTR_PROP_DESC().

A run time assert checks that the platform doesn't specify both.

Henceforth the old scheme of providing list of secure interrupts is
deprecated. When built with ERROR_DEPRECATED=1, GIC drivers will require
that the interrupt properties are supplied instead of an array of secure
interrupts.

Add a section to firmware design about configuring secure interrupts.

Fixes ARM-software/tf-issues#262

Change-Id: I8eec29e72eb69dbb6bce77879febf32c95376942
Signed-off-by: Jeenu Viswambharan <jeenu.viswambharan@arm.com>
diff --git a/drivers/arm/gic/v3/gicv3_helpers.c b/drivers/arm/gic/v3/gicv3_helpers.c
index 33dbe2c..2522695 100644
--- a/drivers/arm/gic/v3/gicv3_helpers.c
+++ b/drivers/arm/gic/v3/gicv3_helpers.c
@@ -9,6 +9,7 @@
 #include <assert.h>
 #include <debug.h>
 #include <gic_common.h>
+#include <interrupt_props.h>
 #include "../common/gic_common_private.h"
 #include "gicv3_private.h"
 
@@ -364,6 +365,7 @@
 		gicd_write_icfgr(gicd_base, index, 0);
 }
 
+#if !ERROR_DEPRECATED
 /*******************************************************************************
  * Helper function to configure secure G0 and G1S SPIs.
  ******************************************************************************/
@@ -410,8 +412,65 @@
 	}
 
 }
+#endif
 
 /*******************************************************************************
+ * Helper function to configure properties of secure SPIs
+ ******************************************************************************/
+unsigned int gicv3_secure_spis_configure_props(uintptr_t gicd_base,
+		const interrupt_prop_t *interrupt_props,
+		unsigned int interrupt_props_num)
+{
+	unsigned int i;
+	const interrupt_prop_t *current_prop;
+	unsigned long long gic_affinity_val;
+	unsigned int ctlr_enable = 0;
+
+	/* Make sure there's a valid property array */
+	assert(interrupt_props != NULL);
+	assert(interrupt_props_num > 0);
+
+	for (i = 0; i < interrupt_props_num; i++) {
+		current_prop = &interrupt_props[i];
+
+		if (current_prop->intr_num < MIN_SPI_ID)
+			continue;
+
+		/* Configure this interrupt as a secure interrupt */
+		gicd_clr_igroupr(gicd_base, current_prop->intr_num);
+
+		/* Configure this interrupt as G0 or a G1S interrupt */
+		assert((current_prop->intr_grp == INTR_GROUP0) ||
+				(current_prop->intr_grp == INTR_GROUP1S));
+		if (current_prop->intr_grp == INTR_GROUP1S) {
+			gicd_set_igrpmodr(gicd_base, current_prop->intr_num);
+			ctlr_enable |= CTLR_ENABLE_G1S_BIT;
+		} else {
+			gicd_clr_igrpmodr(gicd_base, current_prop->intr_num);
+			ctlr_enable |= CTLR_ENABLE_G0_BIT;
+		}
+
+		/* Set interrupt configuration */
+		gicd_set_icfgr(gicd_base, current_prop->intr_num,
+				current_prop->intr_cfg);
+
+		/* Set the priority of this interrupt */
+		gicd_set_ipriorityr(gicd_base, current_prop->intr_num,
+				current_prop->intr_pri);
+
+		/* Target SPIs to the primary CPU */
+		gic_affinity_val = gicd_irouter_val_from_mpidr(read_mpidr(), 0);
+		gicd_write_irouter(gicd_base, current_prop->intr_num,
+				gic_affinity_val);
+
+		/* Enable this interrupt */
+		gicd_set_isenabler(gicd_base, current_prop->intr_num);
+	}
+
+	return ctlr_enable;
+}
+
+/*******************************************************************************
  * Helper function to configure the default attributes of SPIs.
  ******************************************************************************/
 void gicv3_ppi_sgi_configure_defaults(uintptr_t gicr_base)
@@ -439,6 +498,7 @@
 	gicr_write_icfgr1(gicr_base, 0);
 }
 
+#if !ERROR_DEPRECATED
 /*******************************************************************************
  * Helper function to configure secure G0 and G1S SPIs.
  ******************************************************************************/
@@ -476,3 +536,54 @@
 		}
 	}
 }
+#endif
+
+/*******************************************************************************
+ * Helper function to configure properties of secure G0 and G1S PPIs and SGIs.
+ ******************************************************************************/
+void gicv3_secure_ppi_sgi_configure_props(uintptr_t gicr_base,
+		const interrupt_prop_t *interrupt_props,
+		unsigned int interrupt_props_num)
+{
+	unsigned int i;
+	const interrupt_prop_t *current_prop;
+
+	/* Make sure there's a valid property array */
+	assert(interrupt_props != NULL);
+	assert(interrupt_props_num > 0);
+
+	for (i = 0; i < interrupt_props_num; i++) {
+		current_prop = &interrupt_props[i];
+
+		if (current_prop->intr_num >= MIN_SPI_ID)
+			continue;
+
+		/* Configure this interrupt as a secure interrupt */
+		gicr_clr_igroupr0(gicr_base, current_prop->intr_num);
+
+		/* Configure this interrupt as G0 or a G1S interrupt */
+		assert((current_prop->intr_grp == INTR_GROUP0) ||
+				(current_prop->intr_grp == INTR_GROUP1S));
+		if (current_prop->intr_grp == INTR_GROUP1S)
+			gicr_set_igrpmodr0(gicr_base, current_prop->intr_num);
+		else
+			gicr_clr_igrpmodr0(gicr_base, current_prop->intr_num);
+
+		/* Set the priority of this interrupt */
+		gicr_set_ipriorityr(gicr_base, current_prop->intr_num,
+				current_prop->intr_pri);
+
+		/*
+		 * Set interrupt configuration for PPIs. Configuration for SGIs
+		 * are ignored.
+		 */
+		if ((current_prop->intr_num >= MIN_PPI_ID) &&
+				(current_prop->intr_num < MIN_SPI_ID)) {
+			gicr_set_icfgr1(gicr_base, current_prop->intr_num,
+					current_prop->intr_cfg);
+		}
+
+		/* Enable this interrupt */
+		gicr_set_isenabler0(gicr_base, current_prop->intr_num);
+	}
+}