Tegra: GIC: enable FIQ interrupt handling

Tegra chips support multiple FIQ interrupt sources. These interrupts
are enabled in the GICD/GICC interfaces by the tegra_gic driver. A
new FIQ handler would be added in a subsequent change which can be
registered by the platform code.

This patch adds the GIC programming as part of the tegra_gic_setup()
which now takes an array of all the FIQ interrupts to be enabled for
the platform. The Tegra132 and Tegra210 platforms right now do not
register for any FIQ interrupts themselves, but will definitely use
this support in the future.

Change-Id: I0ea164be901cd6681167028fea0567399f18d4b8
Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
diff --git a/plat/nvidia/tegra/common/tegra_gic.c b/plat/nvidia/tegra/common/tegra_gic.c
index ee12975..786eefc 100644
--- a/plat/nvidia/tegra/common/tegra_gic.c
+++ b/plat/nvidia/tegra/common/tegra_gic.c
@@ -47,6 +47,9 @@
 	(GIC_HIGHEST_NS_PRIORITY << 16) | \
 	(GIC_HIGHEST_NS_PRIORITY << 24))
 
+static const unsigned int *g_irq_sec_ptr;
+static unsigned int g_num_irqs;
+
 /*******************************************************************************
  * Place the cpu interface in a state where it can never make a cpu exit wfi as
  * as result of an asserted interrupt. This is critical for powering down a cpu
@@ -110,7 +113,9 @@
  ******************************************************************************/
 static void tegra_gic_distif_setup(unsigned int gicd_base)
 {
-	unsigned int index, num_ints;
+	unsigned int index, num_ints, irq_num;
+	uint8_t target_cpus;
+	uint32_t val;
 
 	/*
 	 * Mark out non-secure interrupts. Calculate number of
@@ -128,6 +133,41 @@
 				GICD_IPRIORITYR_DEF_VAL);
 	}
 
+	/* Configure SPI secure interrupts now */
+	if (g_irq_sec_ptr) {
+
+		/* Read the target CPU mask */
+		target_cpus = TEGRA_SEC_IRQ_TARGET_MASK & GIC_TARGET_CPU_MASK;
+
+		for (index = 0; index < g_num_irqs; index++) {
+			irq_num = g_irq_sec_ptr[index];
+
+			if (irq_num >= MIN_SPI_ID) {
+
+				/* Configure as a secure interrupt */
+				gicd_clr_igroupr(gicd_base, irq_num);
+
+				/* Configure SPI priority */
+				mmio_write_8(gicd_base + GICD_IPRIORITYR +
+					irq_num,
+					GIC_HIGHEST_SEC_PRIORITY &
+					GIC_PRI_MASK);
+
+				/* Configure as level triggered */
+				val = gicd_read_icfgr(gicd_base, irq_num);
+				val |= (3 << ((irq_num & 0xF) << 1));
+				gicd_write_icfgr(gicd_base, irq_num, val);
+
+				/* Route SPI to the target CPUs */
+				gicd_set_itargetsr(gicd_base, irq_num,
+					target_cpus);
+
+				/* Enable this interrupt */
+				gicd_set_isenabler(gicd_base, irq_num);
+			}
+		}
+	}
+
 	/*
 	 * Configure the SGI and PPI. This is done in a separated function
 	 * because each CPU is responsible for initializing its own private
@@ -139,8 +179,11 @@
 	gicd_write_ctlr(gicd_base, ENABLE_GRP0 | ENABLE_GRP1);
 }
 
-void tegra_gic_setup(void)
+void tegra_gic_setup(const unsigned int *irq_sec_ptr, unsigned int num_irqs)
 {
+	g_irq_sec_ptr = irq_sec_ptr;
+	g_num_irqs = num_irqs;
+
 	tegra_gic_cpuif_setup(TEGRA_GICC_BASE);
 	tegra_gic_distif_setup(TEGRA_GICD_BASE);
 }