Merge pull request #439 from soby-mathew/sm/new-gic-driver
Introduce new GICv3 and GICv2 drivers
diff --git a/drivers/arm/gic/common/gic_common.c b/drivers/arm/gic/common/gic_common.c
new file mode 100644
index 0000000..17be61d
--- /dev/null
+++ b/drivers/arm/gic/common/gic_common.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <gic_common.h>
+#include <mmio.h>
+
+/*******************************************************************************
+ * GIC Distributor interface accessors for reading entire registers
+ ******************************************************************************/
+/*
+ * Accessor to read the GIC Distributor IGROUPR corresponding to the interrupt
+ * `id`, 32 interrupt ids at a time.
+ */
+unsigned int gicd_read_igroupr(uintptr_t base, unsigned int id)
+{
+ unsigned n = id >> IGROUPR_SHIFT;
+ return mmio_read_32(base + GICD_IGROUPR + (n << 2));
+}
+
+/*
+ * Accessor to read the GIC Distributor ISENABLER corresponding to the
+ * interrupt `id`, 32 interrupt ids at a time.
+ */
+unsigned int gicd_read_isenabler(uintptr_t base, unsigned int id)
+{
+ unsigned n = id >> ISENABLER_SHIFT;
+ return mmio_read_32(base + GICD_ISENABLER + (n << 2));
+}
+
+/*
+ * Accessor to read the GIC Distributor ICENABLER corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+unsigned int gicd_read_icenabler(uintptr_t base, unsigned int id)
+{
+ unsigned n = id >> ICENABLER_SHIFT;
+ return mmio_read_32(base + GICD_ICENABLER + (n << 2));
+}
+
+/*
+ * Accessor to read the GIC Distributor ISPENDR corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+unsigned int gicd_read_ispendr(uintptr_t base, unsigned int id)
+{
+ unsigned n = id >> ISPENDR_SHIFT;
+ return mmio_read_32(base + GICD_ISPENDR + (n << 2));
+}
+
+/*
+ * Accessor to read the GIC Distributor ICPENDR corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+unsigned int gicd_read_icpendr(uintptr_t base, unsigned int id)
+{
+ unsigned n = id >> ICPENDR_SHIFT;
+ return mmio_read_32(base + GICD_ICPENDR + (n << 2));
+}
+
+/*
+ * Accessor to read the GIC Distributor ISACTIVER corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+unsigned int gicd_read_isactiver(uintptr_t base, unsigned int id)
+{
+ unsigned n = id >> ISACTIVER_SHIFT;
+ return mmio_read_32(base + GICD_ISACTIVER + (n << 2));
+}
+
+/*
+ * Accessor to read the GIC Distributor ICACTIVER corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+unsigned int gicd_read_icactiver(uintptr_t base, unsigned int id)
+{
+ unsigned n = id >> ICACTIVER_SHIFT;
+ return mmio_read_32(base + GICD_ICACTIVER + (n << 2));
+}
+
+/*
+ * Accessor to read the GIC Distributor IPRIORITYR corresponding to the
+ * interrupt `id`, 4 interrupt IDs at a time.
+ */
+unsigned int gicd_read_ipriorityr(uintptr_t base, unsigned int id)
+{
+ unsigned n = id >> IPRIORITYR_SHIFT;
+ return mmio_read_32(base + GICD_IPRIORITYR + (n << 2));
+}
+
+/*
+ * Accessor to read the GIC Distributor ICGFR corresponding to the
+ * interrupt `id`, 16 interrupt IDs at a time.
+ */
+unsigned int gicd_read_icfgr(uintptr_t base, unsigned int id)
+{
+ unsigned n = id >> ICFGR_SHIFT;
+ return mmio_read_32(base + GICD_ICFGR + (n << 2));
+}
+
+/*
+ * Accessor to read the GIC Distributor NSACR corresponding to the
+ * interrupt `id`, 16 interrupt IDs at a time.
+ */
+unsigned int gicd_read_nsacr(uintptr_t base, unsigned int id)
+{
+ unsigned n = id >> NSACR_SHIFT;
+ return mmio_read_32(base + GICD_NSACR + (n << 2));
+}
+
+/*******************************************************************************
+ * GIC Distributor interface accessors for writing entire registers
+ ******************************************************************************/
+/*
+ * Accessor to write the GIC Distributor IGROUPR corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+void gicd_write_igroupr(uintptr_t base, unsigned int id, unsigned int val)
+{
+ unsigned n = id >> IGROUPR_SHIFT;
+ mmio_write_32(base + GICD_IGROUPR + (n << 2), val);
+}
+
+/*
+ * Accessor to write the GIC Distributor ISENABLER corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+void gicd_write_isenabler(uintptr_t base, unsigned int id, unsigned int val)
+{
+ unsigned n = id >> ISENABLER_SHIFT;
+ mmio_write_32(base + GICD_ISENABLER + (n << 2), val);
+}
+
+/*
+ * Accessor to write the GIC Distributor ICENABLER corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+void gicd_write_icenabler(uintptr_t base, unsigned int id, unsigned int val)
+{
+ unsigned n = id >> ICENABLER_SHIFT;
+ mmio_write_32(base + GICD_ICENABLER + (n << 2), val);
+}
+
+/*
+ * Accessor to write the GIC Distributor ISPENDR corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+void gicd_write_ispendr(uintptr_t base, unsigned int id, unsigned int val)
+{
+ unsigned n = id >> ISPENDR_SHIFT;
+ mmio_write_32(base + GICD_ISPENDR + (n << 2), val);
+}
+
+/*
+ * Accessor to write the GIC Distributor ICPENDR corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+void gicd_write_icpendr(uintptr_t base, unsigned int id, unsigned int val)
+{
+ unsigned n = id >> ICPENDR_SHIFT;
+ mmio_write_32(base + GICD_ICPENDR + (n << 2), val);
+}
+
+/*
+ * Accessor to write the GIC Distributor ISACTIVER corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+void gicd_write_isactiver(uintptr_t base, unsigned int id, unsigned int val)
+{
+ unsigned n = id >> ISACTIVER_SHIFT;
+ mmio_write_32(base + GICD_ISACTIVER + (n << 2), val);
+}
+
+/*
+ * Accessor to write the GIC Distributor ICACTIVER corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+void gicd_write_icactiver(uintptr_t base, unsigned int id, unsigned int val)
+{
+ unsigned n = id >> ICACTIVER_SHIFT;
+ mmio_write_32(base + GICD_ICACTIVER + (n << 2), val);
+}
+
+/*
+ * Accessor to write the GIC Distributor IPRIORITYR corresponding to the
+ * interrupt `id`, 4 interrupt IDs at a time.
+ */
+void gicd_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val)
+{
+ unsigned n = id >> IPRIORITYR_SHIFT;
+ mmio_write_32(base + GICD_IPRIORITYR + (n << 2), val);
+}
+
+/*
+ * Accessor to write the GIC Distributor ICFGR corresponding to the
+ * interrupt `id`, 16 interrupt IDs at a time.
+ */
+void gicd_write_icfgr(uintptr_t base, unsigned int id, unsigned int val)
+{
+ unsigned n = id >> ICFGR_SHIFT;
+ mmio_write_32(base + GICD_ICFGR + (n << 2), val);
+}
+
+/*
+ * Accessor to write the GIC Distributor NSACR corresponding to the
+ * interrupt `id`, 16 interrupt IDs at a time.
+ */
+void gicd_write_nsacr(uintptr_t base, unsigned int id, unsigned int val)
+{
+ unsigned n = id >> NSACR_SHIFT;
+ mmio_write_32(base + GICD_NSACR + (n << 2), val);
+}
+
+/*******************************************************************************
+ * GIC Distributor interface accessors for individual interrupt manipulation
+ ******************************************************************************/
+unsigned int gicd_get_igroupr(uintptr_t base, unsigned int id)
+{
+ unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1);
+ unsigned int reg_val = gicd_read_igroupr(base, id);
+
+ return (reg_val >> bit_num) & 0x1;
+}
+
+void gicd_set_igroupr(uintptr_t base, unsigned int id)
+{
+ unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1);
+ unsigned int reg_val = gicd_read_igroupr(base, id);
+
+ gicd_write_igroupr(base, id, reg_val | (1 << bit_num));
+}
+
+void gicd_clr_igroupr(uintptr_t base, unsigned int id)
+{
+ unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1);
+ unsigned int reg_val = gicd_read_igroupr(base, id);
+
+ gicd_write_igroupr(base, id, reg_val & ~(1 << bit_num));
+}
+
+void gicd_set_isenabler(uintptr_t base, unsigned int id)
+{
+ unsigned bit_num = id & ((1 << ISENABLER_SHIFT) - 1);
+
+ gicd_write_isenabler(base, id, (1 << bit_num));
+}
+
+void gicd_set_icenabler(uintptr_t base, unsigned int id)
+{
+ unsigned bit_num = id & ((1 << ICENABLER_SHIFT) - 1);
+
+ gicd_write_icenabler(base, id, (1 << bit_num));
+}
+
+void gicd_set_ispendr(uintptr_t base, unsigned int id)
+{
+ unsigned bit_num = id & ((1 << ISPENDR_SHIFT) - 1);
+
+ gicd_write_ispendr(base, id, (1 << bit_num));
+}
+
+void gicd_set_icpendr(uintptr_t base, unsigned int id)
+{
+ unsigned bit_num = id & ((1 << ICPENDR_SHIFT) - 1);
+
+ gicd_write_icpendr(base, id, (1 << bit_num));
+}
+
+void gicd_set_isactiver(uintptr_t base, unsigned int id)
+{
+ unsigned bit_num = id & ((1 << ISACTIVER_SHIFT) - 1);
+
+ gicd_write_isactiver(base, id, (1 << bit_num));
+}
+
+void gicd_set_icactiver(uintptr_t base, unsigned int id)
+{
+ unsigned bit_num = id & ((1 << ICACTIVER_SHIFT) - 1);
+
+ gicd_write_icactiver(base, id, (1 << bit_num));
+}
diff --git a/drivers/arm/gic/v2/gicv2_helpers.c b/drivers/arm/gic/v2/gicv2_helpers.c
new file mode 100644
index 0000000..1f904c5
--- /dev/null
+++ b/drivers/arm/gic/v2/gicv2_helpers.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <debug.h>
+#include <gic_common.h>
+#include "gicv2_private.h"
+
+/*
+ * Accessor to read the GIC Distributor ITARGETSR corresponding to the
+ * interrupt `id`, 4 interrupt IDs at a time.
+ */
+unsigned int gicd_read_itargetsr(uintptr_t base, unsigned int id)
+{
+ unsigned n = id >> ITARGETSR_SHIFT;
+ return mmio_read_32(base + GICD_ITARGETSR + (n << 2));
+}
+
+/*
+ * Accessor to read the GIC Distributor CPENDSGIR corresponding to the
+ * interrupt `id`, 4 interrupt IDs at a time.
+ */
+unsigned int gicd_read_cpendsgir(uintptr_t base, unsigned int id)
+{
+ unsigned n = id >> CPENDSGIR_SHIFT;
+ return mmio_read_32(base + GICD_CPENDSGIR + (n << 2));
+}
+
+/*
+ * Accessor to read the GIC Distributor SPENDSGIR corresponding to the
+ * interrupt `id`, 4 interrupt IDs at a time.
+ */
+unsigned int gicd_read_spendsgir(uintptr_t base, unsigned int id)
+{
+ unsigned n = id >> SPENDSGIR_SHIFT;
+ return mmio_read_32(base + GICD_SPENDSGIR + (n << 2));
+}
+
+/*
+ * Accessor to write the GIC Distributor ITARGETSR corresponding to the
+ * interrupt `id`, 4 interrupt IDs at a time.
+ */
+void gicd_write_itargetsr(uintptr_t base, unsigned int id, unsigned int val)
+{
+ unsigned n = id >> ITARGETSR_SHIFT;
+ mmio_write_32(base + GICD_ITARGETSR + (n << 2), val);
+}
+
+/*
+ * Accessor to write the GIC Distributor CPENDSGIR corresponding to the
+ * interrupt `id`, 4 interrupt IDs at a time.
+ */
+void gicd_write_cpendsgir(uintptr_t base, unsigned int id, unsigned int val)
+{
+ unsigned n = id >> CPENDSGIR_SHIFT;
+ mmio_write_32(base + GICD_CPENDSGIR + (n << 2), val);
+}
+
+/*
+ * Accessor to write the GIC Distributor SPENDSGIR corresponding to the
+ * interrupt `id`, 4 interrupt IDs at a time.
+ */
+void gicd_write_spendsgir(uintptr_t base, unsigned int id, unsigned int val)
+{
+ unsigned n = id >> SPENDSGIR_SHIFT;
+ mmio_write_32(base + GICD_SPENDSGIR + (n << 2), val);
+}
+
+/*
+ * Accessor to write the GIC Distributor ITARGETSR corresponding to the
+ * interrupt `id`.
+ */
+void gicd_set_itargetsr(uintptr_t base, unsigned int id, unsigned int target)
+{
+ unsigned byte_off = id & ((1 << ITARGETSR_SHIFT) - 1);
+ unsigned int reg_val = gicd_read_itargetsr(base, id);
+
+ gicd_write_itargetsr(base, id, reg_val | (target << (byte_off << 3)));
+}
+
+/*******************************************************************************
+ * Get the current CPU bit mask from GICD_ITARGETSR0
+ ******************************************************************************/
+unsigned int gicv2_get_cpuif_id(uintptr_t base)
+{
+ unsigned int val;
+
+ val = gicd_read_itargetsr(base, 0);
+ return val & GIC_TARGET_CPU_MASK;
+}
+
+/*******************************************************************************
+ * Helper function to configure the default attributes of SPIs.
+ ******************************************************************************/
+void gicv2_spis_configure_defaults(uintptr_t gicd_base)
+{
+ unsigned int index, num_ints;
+
+ num_ints = gicd_read_typer(gicd_base);
+ num_ints &= TYPER_IT_LINES_NO_MASK;
+ num_ints = (num_ints + 1) << 5;
+
+ /*
+ * Treat all SPIs as G1NS by default. The number of interrupts is
+ * calculated as 32 * (IT_LINES + 1). We do 32 at a time.
+ */
+ for (index = MIN_SPI_ID; index < num_ints; index += 32)
+ gicd_write_igroupr(gicd_base, index, ~0U);
+
+ /* Setup the default SPI priorities doing four at a time */
+ for (index = MIN_SPI_ID; index < num_ints; index += 4)
+ gicd_write_ipriorityr(gicd_base,
+ index,
+ GICD_IPRIORITYR_DEF_VAL);
+
+ /* Treat all SPIs as level triggered by default, 16 at a time */
+ for (index = MIN_SPI_ID; index < num_ints; index += 16)
+ gicd_write_icfgr(gicd_base, index, 0);
+}
+
+/*******************************************************************************
+ * Helper function to configure secure G0 SPIs.
+ ******************************************************************************/
+void gicv2_secure_spis_configure(uintptr_t gicd_base,
+ unsigned int num_ints,
+ const unsigned int *sec_intr_list)
+{
+ unsigned int index, irq_num;
+
+ /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */
+ assert(num_ints ? (uintptr_t)sec_intr_list : 1);
+
+ for (index = 0; index < num_ints; index++) {
+ irq_num = sec_intr_list[index];
+ if (irq_num >= MIN_SPI_ID) {
+ /* Configure this interrupt as a secure interrupt */
+ gicd_clr_igroupr(gicd_base, irq_num);
+
+ /* Set the priority of this interrupt */
+ gicd_write_ipriorityr(gicd_base,
+ irq_num,
+ GIC_HIGHEST_SEC_PRIORITY);
+
+ /* Target the secure interrupts to primary CPU */
+ gicd_set_itargetsr(gicd_base, irq_num,
+ gicv2_get_cpuif_id(gicd_base));
+
+ /* Enable this interrupt */
+ gicd_set_isenabler(gicd_base, irq_num);
+ }
+ }
+
+}
+
+/*******************************************************************************
+ * Helper function to configure secure G0 SGIs and PPIs.
+ ******************************************************************************/
+void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base,
+ unsigned int num_ints,
+ const unsigned int *sec_intr_list)
+{
+ unsigned int index, irq_num, sec_ppi_sgi_mask = 0;
+
+ /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */
+ assert(num_ints ? (uintptr_t)sec_intr_list : 1);
+
+ /*
+ * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a
+ * more scalable approach as it avoids clearing the enable bits in the
+ * GICD_CTLR.
+ */
+ gicd_write_icenabler(gicd_base, 0, ~0);
+
+ /* Setup the default PPI/SGI priorities doing four at a time */
+ for (index = 0; index < MIN_SPI_ID; index += 4)
+ gicd_write_ipriorityr(gicd_base,
+ index,
+ GICD_IPRIORITYR_DEF_VAL);
+
+ for (index = 0; index < num_ints; index++) {
+ irq_num = sec_intr_list[index];
+ if (irq_num < MIN_SPI_ID) {
+ /* We have an SGI or a PPI. They are Group0 at reset */
+ sec_ppi_sgi_mask |= 1U << irq_num;
+
+ /* Set the priority of this interrupt */
+ gicd_write_ipriorityr(gicd_base,
+ irq_num,
+ GIC_HIGHEST_SEC_PRIORITY);
+ }
+ }
+
+ /*
+ * Invert the bitmask to create a mask for non-secure PPIs and
+ * SGIs. Program the GICD_IGROUPR0 with this bit mask.
+ */
+ gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask);
+
+ /* Enable the Group 0 SGIs and PPIs */
+ gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask);
+}
diff --git a/drivers/arm/gic/v2/gicv2_main.c b/drivers/arm/gic/v2/gicv2_main.c
new file mode 100644
index 0000000..cf93926
--- /dev/null
+++ b/drivers/arm/gic/v2/gicv2_main.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <debug.h>
+#include <gic_common.h>
+#include <gicv2.h>
+#include "gicv2_private.h"
+
+static const gicv2_driver_data_t *driver_data;
+
+/*******************************************************************************
+ * 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.
+ ******************************************************************************/
+void gicv2_cpuif_enable(void)
+{
+ unsigned int val;
+
+ assert(driver_data);
+ assert(driver_data->gicc_base);
+
+ /*
+ * Enable the Group 0 interrupts, FIQEn and disable Group 0/1
+ * bypass.
+ */
+ val = CTLR_ENABLE_G0_BIT | FIQ_EN_BIT | FIQ_BYP_DIS_GRP0;
+ val |= IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP1 | IRQ_BYP_DIS_GRP1;
+
+ /* Program the idle priority in the PMR */
+ gicc_write_pmr(driver_data->gicc_base, GIC_PRI_MASK);
+ gicc_write_ctlr(driver_data->gicc_base, val);
+}
+
+/*******************************************************************************
+ * 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
+ ******************************************************************************/
+void gicv2_cpuif_disable(void)
+{
+ unsigned int val;
+
+ assert(driver_data);
+ assert(driver_data->gicc_base);
+
+ /* Disable secure, non-secure interrupts and disable their bypass */
+ val = gicc_read_ctlr(driver_data->gicc_base);
+ val &= ~(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1_BIT);
+ val |= FIQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP0;
+ val |= IRQ_BYP_DIS_GRP0 | IRQ_BYP_DIS_GRP1;
+ gicc_write_ctlr(driver_data->gicc_base, val);
+}
+
+/*******************************************************************************
+ * Per cpu gic distributor setup which will be done by all cpus after a cold
+ * boot/hotplug. This marks out the secure SPIs and PPIs & enables them.
+ ******************************************************************************/
+void gicv2_pcpu_distif_init(void)
+{
+ assert(driver_data);
+ assert(driver_data->gicd_base);
+ assert(driver_data->g0_interrupt_array);
+
+ gicv2_secure_ppi_sgi_setup(driver_data->gicd_base,
+ driver_data->g0_interrupt_num,
+ driver_data->g0_interrupt_array);
+}
+
+/*******************************************************************************
+ * Global gic distributor init which will be done by the primary cpu after a
+ * cold boot. It marks out the secure SPIs, PPIs & SGIs and enables them. It
+ * then enables the secure GIC distributor interface.
+ ******************************************************************************/
+void gicv2_distif_init(void)
+{
+ unsigned int ctlr;
+
+ assert(driver_data);
+ assert(driver_data->gicd_base);
+ assert(driver_data->g0_interrupt_array);
+
+ /* Disable the distributor before going further */
+ ctlr = gicd_read_ctlr(driver_data->gicd_base);
+ gicd_write_ctlr(driver_data->gicd_base,
+ ctlr & ~(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1_BIT));
+
+ /* Set the default attribute of all SPIs */
+ gicv2_spis_configure_defaults(driver_data->gicd_base);
+
+ /* Configure the G0 SPIs */
+ gicv2_secure_spis_configure(driver_data->gicd_base,
+ driver_data->g0_interrupt_num,
+ driver_data->g0_interrupt_array);
+
+ /* Re-enable the secure SPIs now that they have been configured */
+ gicd_write_ctlr(driver_data->gicd_base, ctlr | CTLR_ENABLE_G0_BIT);
+}
+
+/*******************************************************************************
+ * Initialize the ARM GICv2 driver with the provided platform inputs
+ ******************************************************************************/
+void gicv2_driver_init(const gicv2_driver_data_t *plat_driver_data)
+{
+ unsigned int gic_version;
+ assert(plat_driver_data);
+ assert(plat_driver_data->gicd_base);
+ assert(plat_driver_data->gicc_base);
+
+ /*
+ * The platform should provide a list of atleast one type of
+ * interrupts
+ */
+ assert(plat_driver_data->g0_interrupt_array);
+
+ /*
+ * If there are no interrupts of a particular type, then the number of
+ * interrupts of that type should be 0 and vice-versa.
+ */
+ assert(plat_driver_data->g0_interrupt_array ?
+ plat_driver_data->g0_interrupt_num :
+ plat_driver_data->g0_interrupt_num == 0);
+
+ /* Ensure that this is a GICv2 system */
+ gic_version = gicd_read_pidr2(plat_driver_data->gicd_base);
+ gic_version = (gic_version >> PIDR2_ARCH_REV_SHIFT)
+ & PIDR2_ARCH_REV_MASK;
+ assert(gic_version == ARCH_REV_GICV2);
+
+ driver_data = plat_driver_data;
+
+ INFO("ARM GICv2 driver initialized\n");
+}
+
+/******************************************************************************
+ * This function returns whether FIQ is enabled in the GIC CPU interface.
+ *****************************************************************************/
+unsigned int gicv2_is_fiq_enabled(void)
+{
+ unsigned int gicc_ctlr;
+
+ assert(driver_data);
+ assert(driver_data->gicc_base);
+
+ gicc_ctlr = gicc_read_ctlr(driver_data->gicc_base);
+ return (gicc_ctlr >> FIQ_EN_SHIFT) & 0x1;
+}
+
+/*******************************************************************************
+ * This function returns the type of the highest priority pending interrupt at
+ * the GIC cpu interface. The return values can be one of the following :
+ * PENDING_G1_INTID : The interrupt type is non secure Group 1.
+ * 0 - 1019 : The interrupt type is secure Group 0.
+ * GIC_SPURIOUS_INTERRUPT : there is no pending interrupt with
+ * sufficient priority to be signaled
+ ******************************************************************************/
+unsigned int gicv2_get_pending_interrupt_type(void)
+{
+ assert(driver_data);
+ assert(driver_data->gicc_base);
+
+ return gicc_read_hppir(driver_data->gicc_base) & INT_ID_MASK;
+}
+
+/*******************************************************************************
+ * This function returns the id of the highest priority pending interrupt at
+ * the GIC cpu interface. GIC_SPURIOUS_INTERRUPT is returned when there is no
+ * interrupt pending.
+ ******************************************************************************/
+unsigned int gicv2_get_pending_interrupt_id(void)
+{
+ unsigned int id;
+
+ assert(driver_data);
+ assert(driver_data->gicc_base);
+
+ id = gicc_read_hppir(driver_data->gicc_base) & INT_ID_MASK;
+
+ /*
+ * Find out which non-secure interrupt it is under the assumption that
+ * the GICC_CTLR.AckCtl bit is 0.
+ */
+ if (id == PENDING_G1_INTID)
+ id = gicc_read_ahppir(driver_data->gicc_base) & INT_ID_MASK;
+
+ return id;
+}
+
+/*******************************************************************************
+ * This functions reads the GIC cpu interface Interrupt Acknowledge register
+ * to start handling the pending secure 0 interrupt. It returns the
+ * contents of the IAR.
+ ******************************************************************************/
+unsigned int gicv2_acknowledge_interrupt(void)
+{
+ assert(driver_data);
+ assert(driver_data->gicc_base);
+
+ return gicc_read_IAR(driver_data->gicc_base);
+}
+
+/*******************************************************************************
+ * This functions writes the GIC cpu interface End Of Interrupt register with
+ * the passed value to finish handling the active secure group 0 interrupt.
+ ******************************************************************************/
+void gicv2_end_of_interrupt(unsigned int id)
+{
+ assert(driver_data);
+ assert(driver_data->gicc_base);
+
+ gicc_write_EOIR(driver_data->gicc_base, id);
+}
+
+/*******************************************************************************
+ * This function returns the type of the interrupt id depending upon the group
+ * this interrupt has been configured under by the interrupt controller i.e.
+ * group0 secure or group1 non secure. It returns zero for Group 0 secure and
+ * one for Group 1 non secure interrupt.
+ ******************************************************************************/
+unsigned int gicv2_get_interrupt_group(unsigned int id)
+{
+ assert(driver_data);
+ assert(driver_data->gicd_base);
+
+ return gicd_get_igroupr(driver_data->gicd_base, id);
+}
diff --git a/drivers/arm/gic/v2/gicv2_private.h b/drivers/arm/gic/v2/gicv2_private.h
new file mode 100644
index 0000000..6a1ec82
--- /dev/null
+++ b/drivers/arm/gic/v2/gicv2_private.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __GICV2_PRIVATE_H__
+#define __GICV2_PRIVATE_H__
+
+#include <gicv2.h>
+#include <mmio.h>
+#include <stdint.h>
+
+/*******************************************************************************
+ * Private function prototypes
+ ******************************************************************************/
+void gicv2_spis_configure_defaults(uintptr_t gicd_base);
+void gicv2_secure_spis_configure(uintptr_t gicd_base,
+ unsigned int num_ints,
+ const unsigned int *sec_intr_list);
+void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base,
+ unsigned int num_ints,
+ const unsigned int *sec_intr_list);
+unsigned int gicv2_get_cpuif_id(uintptr_t base);
+
+/*******************************************************************************
+ * GIC Distributor interface accessors for reading entire registers
+ ******************************************************************************/
+static inline unsigned int gicd_read_pidr2(uintptr_t base)
+{
+ return mmio_read_32(base + GICD_PIDR2_GICV2);
+}
+
+/*******************************************************************************
+ * GIC CPU interface accessors for reading entire registers
+ ******************************************************************************/
+
+static inline unsigned int gicc_read_ctlr(uintptr_t base)
+{
+ return mmio_read_32(base + GICC_CTLR);
+}
+
+static inline unsigned int gicc_read_pmr(uintptr_t base)
+{
+ return mmio_read_32(base + GICC_PMR);
+}
+
+static inline unsigned int gicc_read_BPR(uintptr_t base)
+{
+ return mmio_read_32(base + GICC_BPR);
+}
+
+static inline unsigned int gicc_read_IAR(uintptr_t base)
+{
+ return mmio_read_32(base + GICC_IAR);
+}
+
+static inline unsigned int gicc_read_EOIR(uintptr_t base)
+{
+ return mmio_read_32(base + GICC_EOIR);
+}
+
+static inline unsigned int gicc_read_hppir(uintptr_t base)
+{
+ return mmio_read_32(base + GICC_HPPIR);
+}
+
+static inline unsigned int gicc_read_ahppir(uintptr_t base)
+{
+ return mmio_read_32(base + GICC_AHPPIR);
+}
+
+static inline unsigned int gicc_read_dir(uintptr_t base)
+{
+ return mmio_read_32(base + GICC_DIR);
+}
+
+static inline unsigned int gicc_read_iidr(uintptr_t base)
+{
+ return mmio_read_32(base + GICC_IIDR);
+}
+
+/*******************************************************************************
+ * GIC CPU interface accessors for writing entire registers
+ ******************************************************************************/
+
+static inline void gicc_write_ctlr(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICC_CTLR, val);
+}
+
+static inline void gicc_write_pmr(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICC_PMR, val);
+}
+
+static inline void gicc_write_BPR(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICC_BPR, val);
+}
+
+
+static inline void gicc_write_IAR(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICC_IAR, val);
+}
+
+static inline void gicc_write_EOIR(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICC_EOIR, val);
+}
+
+static inline void gicc_write_hppir(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICC_HPPIR, val);
+}
+
+static inline void gicc_write_dir(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICC_DIR, val);
+}
+
+#endif /* __GICV2_PRIVATE_H__ */
diff --git a/drivers/arm/gic/v3/gicv3_helpers.c b/drivers/arm/gic/v3/gicv3_helpers.c
new file mode 100644
index 0000000..6e8251d
--- /dev/null
+++ b/drivers/arm/gic/v3/gicv3_helpers.c
@@ -0,0 +1,415 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <debug.h>
+#include <gic_common.h>
+#include "gicv3_private.h"
+
+/*
+ * Accessor to read the GIC Distributor IGRPMODR corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+unsigned int gicd_read_igrpmodr(uintptr_t base, unsigned int id)
+{
+ unsigned n = id >> IGRPMODR_SHIFT;
+ return mmio_read_32(base + GICD_IGRPMODR + (n << 2));
+}
+
+/*
+ * Accessor to write the GIC Distributor IGRPMODR corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+void gicd_write_igrpmodr(uintptr_t base, unsigned int id, unsigned int val)
+{
+ unsigned n = id >> IGRPMODR_SHIFT;
+ mmio_write_32(base + GICD_IGRPMODR + (n << 2), val);
+}
+
+/*
+ * Accessor to get the bit corresponding to interrupt ID
+ * in GIC Distributor IGRPMODR.
+ */
+unsigned int gicd_get_igrpmodr(uintptr_t base, unsigned int id)
+{
+ unsigned bit_num = id & ((1 << IGRPMODR_SHIFT) - 1);
+ unsigned int reg_val = gicd_read_igrpmodr(base, id);
+
+ return (reg_val >> bit_num) & 0x1;
+}
+
+/*
+ * Accessor to set the bit corresponding to interrupt ID
+ * in GIC Distributor IGRPMODR.
+ */
+void gicd_set_igrpmodr(uintptr_t base, unsigned int id)
+{
+ unsigned bit_num = id & ((1 << IGRPMODR_SHIFT) - 1);
+ unsigned int reg_val = gicd_read_igrpmodr(base, id);
+
+ gicd_write_igrpmodr(base, id, reg_val | (1 << bit_num));
+}
+
+/*
+ * Accessor to clear the bit corresponding to interrupt ID
+ * in GIC Distributor IGRPMODR.
+ */
+void gicd_clr_igrpmodr(uintptr_t base, unsigned int id)
+{
+ unsigned bit_num = id & ((1 << IGRPMODR_SHIFT) - 1);
+ unsigned int reg_val = gicd_read_igrpmodr(base, id);
+
+ gicd_write_igrpmodr(base, id, reg_val & ~(1 << bit_num));
+}
+
+/*
+ * Accessor to read the GIC Re-distributor IPRIORITYR corresponding to the
+ * interrupt `id`, 4 interrupts IDs at a time.
+ */
+unsigned int gicr_read_ipriorityr(uintptr_t base, unsigned int id)
+{
+ unsigned n = id >> IPRIORITYR_SHIFT;
+ return mmio_read_32(base + GICR_IPRIORITYR + (n << 2));
+}
+
+/*
+ * Accessor to write the GIC Re-distributor IPRIORITYR corresponding to the
+ * interrupt `id`, 4 interrupts IDs at a time.
+ */
+void gicr_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val)
+{
+ unsigned n = id >> IPRIORITYR_SHIFT;
+ mmio_write_32(base + GICR_IPRIORITYR + (n << 2), val);
+}
+
+/*
+ * Accessor to get the bit corresponding to interrupt ID
+ * from GIC Re-distributor IGROUPR0.
+ */
+unsigned int gicr_get_igroupr0(uintptr_t base, unsigned int id)
+{
+ unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1);
+ unsigned int reg_val = gicr_read_igroupr0(base);
+
+ return (reg_val >> bit_num) & 0x1;
+}
+
+/*
+ * Accessor to set the bit corresponding to interrupt ID
+ * in GIC Re-distributor IGROUPR0.
+ */
+void gicr_set_igroupr0(uintptr_t base, unsigned int id)
+{
+ unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1);
+ unsigned int reg_val = gicr_read_igroupr0(base);
+
+ gicr_write_igroupr0(base, reg_val | (1 << bit_num));
+}
+
+/*
+ * Accessor to clear the bit corresponding to interrupt ID
+ * in GIC Re-distributor IGROUPR0.
+ */
+void gicr_clr_igroupr0(uintptr_t base, unsigned int id)
+{
+ unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1);
+ unsigned int reg_val = gicr_read_igroupr0(base);
+
+ gicr_write_igroupr0(base, reg_val & ~(1 << bit_num));
+}
+
+/*
+ * Accessor to get the bit corresponding to interrupt ID
+ * from GIC Re-distributor IGRPMODR0.
+ */
+unsigned int gicr_get_igrpmodr0(uintptr_t base, unsigned int id)
+{
+ unsigned bit_num = id & ((1 << IGRPMODR_SHIFT) - 1);
+ unsigned int reg_val = gicr_read_igrpmodr0(base);
+
+ return (reg_val >> bit_num) & 0x1;
+}
+
+/*
+ * Accessor to set the bit corresponding to interrupt ID
+ * in GIC Re-distributor IGRPMODR0.
+ */
+void gicr_set_igrpmodr0(uintptr_t base, unsigned int id)
+{
+ unsigned bit_num = id & ((1 << IGRPMODR_SHIFT) - 1);
+ unsigned int reg_val = gicr_read_igrpmodr0(base);
+
+ gicr_write_igrpmodr0(base, reg_val | (1 << bit_num));
+}
+
+/*
+ * Accessor to clear the bit corresponding to interrupt ID
+ * in GIC Re-distributor IGRPMODR0.
+ */
+void gicr_clr_igrpmodr0(uintptr_t base, unsigned int id)
+{
+ unsigned bit_num = id & ((1 << IGRPMODR_SHIFT) - 1);
+ unsigned int reg_val = gicr_read_igrpmodr0(base);
+
+ gicr_write_igrpmodr0(base, reg_val & ~(1 << bit_num));
+}
+
+/*
+ * Accessor to set the bit corresponding to interrupt ID
+ * in GIC Re-distributor ISENABLER0.
+ */
+void gicr_set_isenabler0(uintptr_t base, unsigned int id)
+{
+ unsigned bit_num = id & ((1 << ISENABLER_SHIFT) - 1);
+
+ gicr_write_isenabler0(base, (1 << bit_num));
+}
+
+/******************************************************************************
+ * This function marks the core as awake in the re-distributor and
+ * ensures that the interface is active.
+ *****************************************************************************/
+void gicv3_rdistif_mark_core_awake(uintptr_t gicr_base)
+{
+ /*
+ * The WAKER_PS_BIT should be changed to 0
+ * only when WAKER_CA_BIT is 1.
+ */
+ assert(gicr_read_waker(gicr_base) & WAKER_CA_BIT);
+
+ /* Mark the connected core as awake */
+ gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) & ~WAKER_PS_BIT);
+
+ /* Wait till the WAKER_CA_BIT changes to 0 */
+ while (gicr_read_waker(gicr_base) & WAKER_CA_BIT)
+ ;
+}
+
+
+/******************************************************************************
+ * This function marks the core as asleep in the re-distributor and ensures
+ * that the interface is quiescent.
+ *****************************************************************************/
+void gicv3_rdistif_mark_core_asleep(uintptr_t gicr_base)
+{
+ /* Mark the connected core as asleep */
+ gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) | WAKER_PS_BIT);
+
+ /* Wait till the WAKER_CA_BIT changes to 1 */
+ while (!(gicr_read_waker(gicr_base) & WAKER_CA_BIT))
+ ;
+}
+
+
+/*******************************************************************************
+ * This function probes the Redistributor frames when the driver is initialised
+ * and saves their base addresses. These base addresses are used later to
+ * initialise each Redistributor interface.
+ ******************************************************************************/
+void gicv3_rdistif_base_addrs_probe(uintptr_t *rdistif_base_addrs,
+ unsigned int rdistif_num,
+ uintptr_t gicr_base,
+ mpidr_hash_fn mpidr_to_core_pos)
+{
+ unsigned long mpidr;
+ unsigned int proc_num;
+ unsigned long long typer_val;
+ uintptr_t rdistif_base = gicr_base;
+
+ assert(rdistif_base_addrs);
+
+ /*
+ * Iterate over the Redistributor frames. Store the base address of each
+ * frame in the platform provided array. Use the "Processor Number"
+ * field to index into the array if the platform has not provided a hash
+ * function to convert an MPIDR (obtained from the "Affinity Value"
+ * field into a linear index.
+ */
+ do {
+ typer_val = gicr_read_typer(rdistif_base);
+ if (mpidr_to_core_pos) {
+ mpidr = mpidr_from_gicr_typer(typer_val);
+ proc_num = mpidr_to_core_pos(mpidr);
+ } else {
+ proc_num = (typer_val >> TYPER_PROC_NUM_SHIFT) &
+ TYPER_PROC_NUM_MASK;
+ }
+ assert(proc_num < rdistif_num);
+ rdistif_base_addrs[proc_num] = rdistif_base;
+ rdistif_base += (1 << GICR_PCPUBASE_SHIFT);
+ } while (!(typer_val & TYPER_LAST_BIT));
+}
+
+/*******************************************************************************
+ * Helper function to configure the default attributes of SPIs.
+ ******************************************************************************/
+void gicv3_spis_configure_defaults(uintptr_t gicd_base)
+{
+ unsigned int index, num_ints;
+
+ num_ints = gicd_read_typer(gicd_base);
+ num_ints &= TYPER_IT_LINES_NO_MASK;
+ num_ints = (num_ints + 1) << 5;
+
+ /*
+ * Treat all SPIs as G1NS by default. The number of interrupts is
+ * calculated as 32 * (IT_LINES + 1). We do 32 at a time.
+ */
+ for (index = MIN_SPI_ID; index < num_ints; index += 32)
+ gicd_write_igroupr(gicd_base, index, ~0U);
+
+ /* Setup the default SPI priorities doing four at a time */
+ for (index = MIN_SPI_ID; index < num_ints; index += 4)
+ gicd_write_ipriorityr(gicd_base,
+ index,
+ GICD_IPRIORITYR_DEF_VAL);
+
+ /*
+ * Treat all SPIs as level triggered by default, write 16 at
+ * a time
+ */
+ for (index = MIN_SPI_ID; index < num_ints; index += 16)
+ gicd_write_icfgr(gicd_base, index, 0);
+}
+
+/*******************************************************************************
+ * Helper function to configure secure G0 and G1S SPIs.
+ ******************************************************************************/
+void gicv3_secure_spis_configure(uintptr_t gicd_base,
+ unsigned int num_ints,
+ const unsigned int *sec_intr_list,
+ unsigned int int_grp)
+{
+ unsigned int index, irq_num;
+ uint64_t gic_affinity_val;
+
+ assert((int_grp == INT_TYPE_G1S) || (int_grp == INT_TYPE_G0));
+ /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */
+ assert(num_ints ? (uintptr_t)sec_intr_list : 1);
+
+ for (index = 0; index < num_ints; index++) {
+ irq_num = sec_intr_list[index];
+ if (irq_num >= MIN_SPI_ID) {
+
+ /* Configure this interrupt as a secure interrupt */
+ gicd_clr_igroupr(gicd_base, irq_num);
+
+ /* Configure this interrupt as G0 or a G1S interrupt */
+ if (int_grp == INT_TYPE_G1S)
+ gicd_set_igrpmodr(gicd_base, irq_num);
+ else
+ gicd_clr_igrpmodr(gicd_base, irq_num);
+
+ /* Set the priority of this interrupt */
+ gicd_write_ipriorityr(gicd_base,
+ irq_num,
+ GIC_HIGHEST_SEC_PRIORITY);
+
+ /* Target SPIs to the primary CPU */
+ gic_affinity_val =
+ gicd_irouter_val_from_mpidr(read_mpidr(), 0);
+ gicd_write_irouter(gicd_base,
+ irq_num,
+ gic_affinity_val);
+
+ /* Enable this interrupt */
+ gicd_set_isenabler(gicd_base, irq_num);
+ }
+ }
+
+}
+
+/*******************************************************************************
+ * Helper function to configure the default attributes of SPIs.
+ ******************************************************************************/
+void gicv3_ppi_sgi_configure_defaults(uintptr_t gicr_base)
+{
+ unsigned int index;
+
+ /*
+ * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a
+ * more scalable approach as it avoids clearing the enable bits in the
+ * GICD_CTLR
+ */
+ gicr_write_icenabler0(gicr_base, ~0);
+ gicr_wait_for_pending_write(gicr_base);
+
+ /* Treat all SGIs/PPIs as G1NS by default. */
+ gicr_write_igroupr0(gicr_base, ~0U);
+
+ /* Setup the default PPI/SGI priorities doing four at a time */
+ for (index = 0; index < MIN_SPI_ID; index += 4)
+ gicr_write_ipriorityr(gicr_base,
+ index,
+ GICD_IPRIORITYR_DEF_VAL);
+
+ /* Configure all PPIs as level triggered by default */
+ gicr_write_icfgr1(gicr_base, 0);
+}
+
+/*******************************************************************************
+ * Helper function to configure secure G0 and G1S SPIs.
+ ******************************************************************************/
+void gicv3_secure_ppi_sgi_configure(uintptr_t gicr_base,
+ unsigned int num_ints,
+ const unsigned int *sec_intr_list,
+ unsigned int int_grp)
+{
+ unsigned int index, irq_num;
+
+ assert((int_grp == INT_TYPE_G1S) || (int_grp == INT_TYPE_G0));
+ /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */
+ assert(num_ints ? (uintptr_t)sec_intr_list : 1);
+
+ for (index = 0; index < num_ints; index++) {
+ irq_num = sec_intr_list[index];
+ if (irq_num < MIN_SPI_ID) {
+
+ /* Configure this interrupt as a secure interrupt */
+ gicr_clr_igroupr0(gicr_base, irq_num);
+
+ /* Configure this interrupt as G0 or a G1S interrupt */
+ if (int_grp == INT_TYPE_G1S)
+ gicr_set_igrpmodr0(gicr_base, irq_num);
+ else
+ gicr_clr_igrpmodr0(gicr_base, irq_num);
+
+ /* Set the priority of this interrupt */
+ gicr_write_ipriorityr(gicr_base,
+ irq_num,
+ GIC_HIGHEST_SEC_PRIORITY);
+
+ /* Enable this interrupt */
+ gicr_set_isenabler0(gicr_base, irq_num);
+ }
+ }
+}
diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c
new file mode 100644
index 0000000..06311e3
--- /dev/null
+++ b/drivers/arm/gic/v3/gicv3_main.c
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <debug.h>
+#include <gic_common.h>
+#include <gicv3.h>
+#include "gicv3_private.h"
+
+static const gicv3_driver_data_t *driver_data;
+static unsigned int gicv2_compat;
+
+/*******************************************************************************
+ * This function initialises the ARM GICv3 driver in EL3 with provided platform
+ * inputs.
+ ******************************************************************************/
+void gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data)
+{
+ unsigned int gic_version;
+
+ assert(plat_driver_data);
+ assert(plat_driver_data->gicd_base);
+ assert(plat_driver_data->gicr_base);
+ assert(plat_driver_data->rdistif_num);
+ assert(plat_driver_data->rdistif_base_addrs);
+
+ assert(IS_IN_EL3());
+
+ /*
+ * The platform should provide a list of at least one type of
+ * interrupts
+ */
+ assert(plat_driver_data->g0_interrupt_array ||
+ plat_driver_data->g1s_interrupt_array);
+
+ /*
+ * If there are no interrupts of a particular type, then the number of
+ * interrupts of that type should be 0 and vice-versa.
+ */
+ assert(plat_driver_data->g0_interrupt_array ?
+ plat_driver_data->g0_interrupt_num :
+ plat_driver_data->g0_interrupt_num == 0);
+ assert(plat_driver_data->g1s_interrupt_array ?
+ plat_driver_data->g1s_interrupt_num :
+ plat_driver_data->g1s_interrupt_num == 0);
+
+ /* Check for system register support */
+ assert(read_id_aa64pfr0_el1() &
+ (ID_AA64PFR0_GIC_MASK << ID_AA64PFR0_GIC_SHIFT));
+
+ /* The GIC version should be 3.0 */
+ gic_version = gicd_read_pidr2(plat_driver_data->gicd_base);
+ gic_version >>= PIDR2_ARCH_REV_SHIFT;
+ gic_version &= PIDR2_ARCH_REV_MASK;
+ assert(gic_version == ARCH_REV_GICV3);
+
+ /*
+ * Find out whether the GIC supports the GICv2 compatibility mode. The
+ * ARE_S bit resets to 0 if supported
+ */
+ gicv2_compat = gicd_read_ctlr(plat_driver_data->gicd_base);
+ gicv2_compat >>= CTLR_ARE_S_SHIFT;
+ gicv2_compat = !(gicv2_compat & CTLR_ARE_S_MASK);
+
+ /*
+ * Find the base address of each implemented Redistributor interface.
+ * The number of interfaces should be equal to the number of CPUs in the
+ * system. The memory for saving these addresses has to be allocated by
+ * the platform port
+ */
+ gicv3_rdistif_base_addrs_probe(plat_driver_data->rdistif_base_addrs,
+ plat_driver_data->rdistif_num,
+ plat_driver_data->gicr_base,
+ plat_driver_data->mpidr_to_core_pos);
+
+ driver_data = plat_driver_data;
+
+ INFO("GICv3 %s legacy support detected."
+ " ARM GICV3 driver initialized in EL3\n",
+ gicv2_compat ? "with" : "without");
+}
+
+/*******************************************************************************
+ * This function initialises the GIC distributor interface based upon the data
+ * provided by the platform while initialising the driver.
+ ******************************************************************************/
+void gicv3_distif_init(void)
+{
+ assert(driver_data);
+ assert(driver_data->gicd_base);
+ assert(driver_data->g1s_interrupt_array);
+ assert(driver_data->g0_interrupt_array);
+
+ assert(IS_IN_EL3());
+
+ /*
+ * Clear the "enable" bits for G0/G1S/G1NS interrupts before configuring
+ * the ARE_S bit. The Distributor might generate a system error
+ * otherwise.
+ */
+ gicd_clr_ctlr(driver_data->gicd_base,
+ CTLR_ENABLE_G0_BIT |
+ CTLR_ENABLE_G1S_BIT |
+ CTLR_ENABLE_G1NS_BIT,
+ RWP_TRUE);
+
+ /* Set the ARE_S and ARE_NS bit now that interrupts have been disabled */
+ gicd_set_ctlr(driver_data->gicd_base,
+ CTLR_ARE_S_BIT | CTLR_ARE_NS_BIT, RWP_TRUE);
+
+ /* Set the default attribute of all SPIs */
+ gicv3_spis_configure_defaults(driver_data->gicd_base);
+
+ /* Configure the G1S SPIs */
+ gicv3_secure_spis_configure(driver_data->gicd_base,
+ driver_data->g1s_interrupt_num,
+ driver_data->g1s_interrupt_array,
+ INT_TYPE_G1S);
+
+ /* Configure the G0 SPIs */
+ gicv3_secure_spis_configure(driver_data->gicd_base,
+ driver_data->g0_interrupt_num,
+ driver_data->g0_interrupt_array,
+ INT_TYPE_G0);
+
+ /* Enable the secure SPIs now that they have been configured */
+ gicd_set_ctlr(driver_data->gicd_base,
+ CTLR_ENABLE_G1S_BIT | CTLR_ENABLE_G0_BIT,
+ RWP_TRUE);
+}
+
+/*******************************************************************************
+ * This function initialises the GIC Redistributor interface of the calling CPU
+ * (identified by the 'proc_num' parameter) based upon the data provided by the
+ * platform while initialising the driver.
+ ******************************************************************************/
+void gicv3_rdistif_init(unsigned int proc_num)
+{
+ uintptr_t gicr_base;
+
+ assert(driver_data);
+ assert(proc_num < driver_data->rdistif_num);
+ assert(driver_data->rdistif_base_addrs);
+ assert(driver_data->gicd_base);
+ assert(gicd_read_ctlr(driver_data->gicd_base) & CTLR_ARE_S_BIT);
+ assert(driver_data->g1s_interrupt_array);
+ assert(driver_data->g0_interrupt_array);
+
+ assert(IS_IN_EL3());
+
+ gicr_base = driver_data->rdistif_base_addrs[proc_num];
+
+ /* Set the default attribute of all SGIs and PPIs */
+ gicv3_ppi_sgi_configure_defaults(gicr_base);
+
+ /* Configure the G1S SGIs/PPIs */
+ gicv3_secure_ppi_sgi_configure(gicr_base,
+ driver_data->g1s_interrupt_num,
+ driver_data->g1s_interrupt_array,
+ INT_TYPE_G1S);
+
+ /* Configure the G0 SGIs/PPIs */
+ gicv3_secure_ppi_sgi_configure(gicr_base,
+ driver_data->g0_interrupt_num,
+ driver_data->g0_interrupt_array,
+ INT_TYPE_G0);
+}
+
+/*******************************************************************************
+ * This function enables the GIC CPU interface of the calling CPU using only
+ * system register accesses.
+ ******************************************************************************/
+void gicv3_cpuif_enable(unsigned int proc_num)
+{
+ uintptr_t gicr_base;
+ unsigned int scr_el3;
+ unsigned int icc_sre_el3;
+
+ assert(driver_data);
+ assert(proc_num < driver_data->rdistif_num);
+ assert(driver_data->rdistif_base_addrs);
+ assert(IS_IN_EL3());
+
+ /* Mark the connected core as awake */
+ gicr_base = driver_data->rdistif_base_addrs[proc_num];
+ gicv3_rdistif_mark_core_awake(gicr_base);
+
+ /* Disable the legacy interrupt bypass */
+ icc_sre_el3 = ICC_SRE_DIB_BIT | ICC_SRE_DFB_BIT;
+
+ /*
+ * Enable system register access for EL3 and allow lower exception
+ * levels to configure the same for themselves. If the legacy mode is
+ * not supported, the SRE bit is RAO/WI
+ */
+ icc_sre_el3 |= (ICC_SRE_EN_BIT | ICC_SRE_SRE_BIT);
+ write_icc_sre_el3(read_icc_sre_el3() | icc_sre_el3);
+
+ scr_el3 = read_scr_el3();
+
+ /*
+ * Switch to NS state to write Non secure ICC_SRE_EL1 and
+ * ICC_SRE_EL2 registers.
+ */
+ write_scr_el3(scr_el3 | SCR_NS_BIT);
+ isb();
+
+ write_icc_sre_el2(read_icc_sre_el2() | icc_sre_el3);
+ write_icc_sre_el1(ICC_SRE_SRE_BIT);
+ isb();
+
+ /* Switch to secure state. */
+ write_scr_el3(scr_el3 & (~SCR_NS_BIT));
+ isb();
+
+ /* Program the idle priority in the PMR */
+ write_icc_pmr_el1(GIC_PRI_MASK);
+
+ /* Enable Group0 interrupts */
+ write_icc_igrpen0_el1(IGRPEN1_EL1_ENABLE_G0_BIT);
+
+ /* Enable Group1 Secure interrupts */
+ write_icc_igrpen1_el3(read_icc_igrpen1_el3() |
+ IGRPEN1_EL3_ENABLE_G1S_BIT);
+
+ /* Write the secure ICC_SRE_EL1 register */
+ write_icc_sre_el1(ICC_SRE_SRE_BIT);
+ isb();
+}
+
+/*******************************************************************************
+ * This function disables the GIC CPU interface of the calling CPU using
+ * only system register accesses.
+ ******************************************************************************/
+void gicv3_cpuif_disable(unsigned int proc_num)
+{
+ uintptr_t gicr_base;
+
+ assert(driver_data);
+ assert(proc_num < driver_data->rdistif_num);
+ assert(driver_data->rdistif_base_addrs);
+
+ assert(IS_IN_EL3());
+
+ /* Disable legacy interrupt bypass */
+ write_icc_sre_el3(read_icc_sre_el3() |
+ (ICC_SRE_DIB_BIT | ICC_SRE_DFB_BIT));
+
+ /* Disable Group0 interrupts */
+ write_icc_igrpen0_el1(read_icc_igrpen0_el1() &
+ ~IGRPEN1_EL1_ENABLE_G0_BIT);
+
+ /* Disable Group1 Secure interrupts */
+ write_icc_igrpen1_el3(read_icc_igrpen1_el3() &
+ ~IGRPEN1_EL3_ENABLE_G1S_BIT);
+
+ /* Synchronise accesses to group enable registers */
+ isb();
+
+ /* Mark the connected core as asleep */
+ gicr_base = driver_data->rdistif_base_addrs[proc_num];
+ gicv3_rdistif_mark_core_asleep(gicr_base);
+}
+
+/*******************************************************************************
+ * This function returns the id of the highest priority pending interrupt at
+ * the GIC cpu interface.
+ ******************************************************************************/
+unsigned int gicv3_get_pending_interrupt_id(void)
+{
+ unsigned int id;
+
+ assert(IS_IN_EL3());
+ id = read_icc_hppir0_el1() & HPPIR0_EL1_INTID_MASK;
+
+ /*
+ * If the ID is special identifier corresponding to G1S or G1NS
+ * interrupt, then read the highest pending group 1 interrupt.
+ */
+ if ((id == PENDING_G1S_INTID) || (id == PENDING_G1NS_INTID))
+ return read_icc_hppir1_el1() & HPPIR1_EL1_INTID_MASK;
+
+ return id;
+}
+
+/*******************************************************************************
+ * This function returns the type of the highest priority pending interrupt at
+ * the GIC cpu interface. The return values can be one of the following :
+ * PENDING_G1S_INTID : The interrupt type is secure Group 1.
+ * PENDING_G1NS_INTID : The interrupt type is non secure Group 1.
+ * 0 - 1019 : The interrupt type is secure Group 0.
+ * GIC_SPURIOUS_INTERRUPT : there is no pending interrupt with
+ * sufficient priority to be signaled
+ ******************************************************************************/
+unsigned int gicv3_get_pending_interrupt_type(void)
+{
+ assert(IS_IN_EL3());
+ return read_icc_hppir0_el1() & HPPIR0_EL1_INTID_MASK;
+}
+
+/*******************************************************************************
+ * This function returns the type of the interrupt id depending upon the group
+ * this interrupt has been configured under by the interrupt controller i.e.
+ * group0 or group1 Secure / Non Secure. The return value can be one of the
+ * following :
+ * INT_TYPE_G0 : The interrupt type is a Secure Group 0 interrupt
+ * INT_TYPE_G1S : The interrupt type is a Secure Group 1 secure interrupt
+ * INT_TYPE_G1NS: The interrupt type is a Secure Group 1 non secure
+ * interrupt.
+ ******************************************************************************/
+unsigned int gicv3_get_interrupt_type(unsigned int id,
+ unsigned int proc_num)
+{
+ unsigned int igroup, grpmodr;
+ uintptr_t gicr_base;
+
+ assert(IS_IN_EL3());
+ assert(driver_data);
+
+ /* Ensure the parameters are valid */
+ assert(id < PENDING_G1S_INTID || id >= MIN_LPI_ID);
+ assert(proc_num < driver_data->rdistif_num);
+
+ /* All LPI interrupts are Group 1 non secure */
+ if (id >= MIN_LPI_ID)
+ return INT_TYPE_G1NS;
+
+ if (id < MIN_SPI_ID) {
+ assert(driver_data->rdistif_base_addrs);
+ gicr_base = driver_data->rdistif_base_addrs[proc_num];
+ igroup = gicr_get_igroupr0(gicr_base, id);
+ grpmodr = gicr_get_igrpmodr0(gicr_base, id);
+ } else {
+ assert(driver_data->gicd_base);
+ igroup = gicd_get_igroupr(driver_data->gicd_base, id);
+ grpmodr = gicd_get_igrpmodr(driver_data->gicd_base, id);
+ }
+
+ /*
+ * If the IGROUP bit is set, then it is a Group 1 Non secure
+ * interrupt
+ */
+ if (igroup)
+ return INT_TYPE_G1NS;
+
+ /* If the GRPMOD bit is set, then it is a Group 1 Secure interrupt */
+ if (grpmodr)
+ return INT_TYPE_G1S;
+
+ /* Else it is a Group 0 Secure interrupt */
+ return INT_TYPE_G0;
+}
diff --git a/drivers/arm/gic/v3/gicv3_private.h b/drivers/arm/gic/v3/gicv3_private.h
new file mode 100644
index 0000000..c8b311a
--- /dev/null
+++ b/drivers/arm/gic/v3/gicv3_private.h
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __GICV3_PRIVATE_H__
+#define __GICV3_PRIVATE_H__
+
+#include <gicv3.h>
+#include <mmio.h>
+#include <stdint.h>
+
+/*******************************************************************************
+ * GICv3 private macro definitions
+ ******************************************************************************/
+
+/* Constants to indicate the status of the RWP bit */
+#define RWP_TRUE 1
+#define RWP_FALSE 0
+
+/*
+ * Macro to wait for updates to :
+ * GICD_CTLR[2:0] - the Group Enables
+ * GICD_CTLR[5:4] - the ARE bits
+ * GICD_ICENABLERn - the clearing of enable state for SPIs
+ */
+#define gicd_wait_for_pending_write(gicd_base) \
+ do { \
+ ; \
+ } while (gicd_read_ctlr(gicd_base) & GICD_CTLR_RWP_BIT)
+
+/*
+ * Macro to convert an mpidr to a value suitable for programming into a
+ * GICD_IROUTER. Bits[31:24] in the MPIDR are cleared as they are not relevant
+ * to GICv3.
+ */
+#define gicd_irouter_val_from_mpidr(mpidr, irm) \
+ ((mpidr & ~(0xff << 24)) | \
+ (irm & IROUTER_IRM_MASK) << IROUTER_IRM_SHIFT)
+
+/*
+ * Macro to wait for updates to :
+ * GICR_ICENABLER0
+ * GICR_CTLR.DPG1S
+ * GICR_CTLR.DPG1NS
+ * GICR_CTLR.DPG0
+ */
+#define gicr_wait_for_pending_write(gicr_base) \
+ do { \
+ ; \
+ } while (gicr_read_ctlr(gicr_base) & GICR_CTLR_RWP_BIT)
+
+/*
+ * Macro to convert a GICR_TYPER affinity value into a MPIDR value. Bits[31:24]
+ * are zeroes.
+ */
+#define mpidr_from_gicr_typer(typer_val) \
+ ((((typer_val >> 56) & MPIDR_AFFLVL_MASK) << MPIDR_AFF3_SHIFT) | \
+ ((typer_val >> 32) & 0xffffff))
+
+/*******************************************************************************
+ * Private function prototypes
+ ******************************************************************************/
+unsigned int gicd_read_igrpmodr(uintptr_t base, unsigned int id);
+unsigned int gicr_read_ipriorityr(uintptr_t base, unsigned int id);
+unsigned int gicd_get_igrpmodr(uintptr_t base, unsigned int id);
+unsigned int gicr_get_igrpmodr0(uintptr_t base, unsigned int id);
+unsigned int gicr_get_igroupr0(uintptr_t base, unsigned int id);
+unsigned int gicv3_get_pending_grp1_interrupt_id(unsigned int pending_grp);
+void gicd_write_igrpmodr(uintptr_t base, unsigned int id, unsigned int val);
+void gicr_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val);
+void gicd_set_igrpmodr(uintptr_t base, unsigned int id);
+void gicr_set_igrpmodr0(uintptr_t base, unsigned int id);
+void gicr_set_isenabler0(uintptr_t base, unsigned int id);
+void gicr_set_igroupr0(uintptr_t base, unsigned int id);
+void gicd_clr_igrpmodr(uintptr_t base, unsigned int id);
+void gicr_clr_igrpmodr0(uintptr_t base, unsigned int id);
+void gicr_clr_igroupr0(uintptr_t base, unsigned int id);
+void gicv3_spis_configure_defaults(uintptr_t gicd_base);
+void gicv3_ppi_sgi_configure_defaults(uintptr_t gicr_base);
+void gicv3_secure_spis_configure(uintptr_t gicd_base,
+ unsigned int num_ints,
+ const unsigned int *sec_intr_list,
+ unsigned int int_grp);
+void gicv3_secure_ppi_sgi_configure(uintptr_t gicr_base,
+ unsigned int num_ints,
+ const unsigned int *sec_intr_list,
+ unsigned int int_grp);
+void gicv3_rdistif_base_addrs_probe(uintptr_t *rdistif_base_addrs,
+ unsigned int rdistif_num,
+ uintptr_t gicr_base,
+ mpidr_hash_fn mpidr_to_core_pos);
+void gicv3_rdistif_mark_core_awake(uintptr_t gicr_base);
+void gicv3_rdistif_mark_core_asleep(uintptr_t gicr_base);
+
+/*******************************************************************************
+ * GIC Distributor interface accessors
+ ******************************************************************************/
+static inline unsigned int gicd_read_pidr2(uintptr_t base)
+{
+ return mmio_read_32(base + GICD_PIDR2_GICV3);
+}
+
+static inline unsigned long long gicd_read_irouter(uintptr_t base, unsigned int id)
+{
+ return mmio_read_64(base + GICD_IROUTER + (id << 3));
+}
+
+static inline void gicd_write_irouter(uintptr_t base,
+ unsigned int id,
+ unsigned long long affinity)
+{
+ mmio_write_64(base + GICD_IROUTER + (id << 3), affinity);
+}
+
+static inline void gicd_clr_ctlr(uintptr_t base,
+ unsigned int bitmap,
+ unsigned int rwp)
+{
+ gicd_write_ctlr(base, gicd_read_ctlr(base) & ~bitmap);
+ if (rwp)
+ gicd_wait_for_pending_write(base);
+}
+
+static inline void gicd_set_ctlr(uintptr_t base,
+ unsigned int bitmap,
+ unsigned int rwp)
+{
+ gicd_write_ctlr(base, gicd_read_ctlr(base) | bitmap);
+ if (rwp)
+ gicd_wait_for_pending_write(base);
+}
+
+/*******************************************************************************
+ * GIC Redistributor interface accessors
+ ******************************************************************************/
+static inline unsigned long long gicr_read_ctlr(uintptr_t base)
+{
+ return mmio_read_64(base + GICR_CTLR);
+}
+
+static inline unsigned long long gicr_read_typer(uintptr_t base)
+{
+ return mmio_read_64(base + GICR_TYPER);
+}
+
+static inline unsigned int gicr_read_waker(uintptr_t base)
+{
+ return mmio_read_32(base + GICR_WAKER);
+}
+
+static inline void gicr_write_waker(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICR_WAKER, val);
+}
+
+static inline unsigned int gicr_read_icenabler0(uintptr_t base)
+{
+ return mmio_read_32(base + GICR_ICENABLER0);
+}
+
+static inline void gicr_write_icenabler0(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICR_ICENABLER0, val);
+}
+
+static inline unsigned int gicr_read_isenabler0(uintptr_t base)
+{
+ return mmio_read_32(base + GICR_ISENABLER0);
+}
+
+static inline void gicr_write_isenabler0(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICR_ISENABLER0, val);
+}
+
+static inline unsigned int gicr_read_igroupr0(uintptr_t base)
+{
+ return mmio_read_32(base + GICR_IGROUPR0);
+}
+
+static inline void gicr_write_igroupr0(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICR_IGROUPR0, val);
+}
+
+static inline unsigned int gicr_read_igrpmodr0(uintptr_t base)
+{
+ return mmio_read_32(base + GICR_IGRPMODR0);
+}
+
+static inline void gicr_write_igrpmodr0(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICR_IGRPMODR0, val);
+}
+
+static inline unsigned int gicr_read_icfgr1(uintptr_t base)
+{
+ return mmio_read_32(base + GICR_ICFGR1);
+}
+
+static inline void gicr_write_icfgr1(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICR_ICFGR1, val);
+}
+
+#endif /* __GICV3_PRIVATE_H__ */
diff --git a/include/drivers/arm/arm_gic.h b/include/drivers/arm/arm_gic.h
index 5752d8f..8c1f03f 100644
--- a/include/drivers/arm/arm_gic.h
+++ b/include/drivers/arm/arm_gic.h
@@ -31,6 +31,7 @@
#ifndef __ARM_GIC_H__
#define __ARM_GIC_H__
+#include <common_def.h>
#include <stdint.h>
/*******************************************************************************
@@ -40,18 +41,18 @@
uintptr_t gicd_base,
uintptr_t gicr_base,
const unsigned int *irq_sec_ptr,
- unsigned int num_irqs);
-void arm_gic_setup(void);
-void arm_gic_cpuif_deactivate(void);
-void arm_gic_cpuif_setup(void);
-void arm_gic_pcpu_distif_setup(void);
+ unsigned int num_irqs) __warn_deprecated;
+void arm_gic_setup(void) __warn_deprecated;
+void arm_gic_cpuif_deactivate(void) __warn_deprecated;
+void arm_gic_cpuif_setup(void) __warn_deprecated;
+void arm_gic_pcpu_distif_setup(void) __warn_deprecated;
uint32_t arm_gic_interrupt_type_to_line(uint32_t type,
- uint32_t security_state);
-uint32_t arm_gic_get_pending_interrupt_type(void);
-uint32_t arm_gic_get_pending_interrupt_id(void);
-uint32_t arm_gic_acknowledge_interrupt(void);
-void arm_gic_end_of_interrupt(uint32_t id);
-uint32_t arm_gic_get_interrupt_type(uint32_t id);
+ uint32_t security_state) __warn_deprecated;
+uint32_t arm_gic_get_pending_interrupt_type(void) __warn_deprecated;
+uint32_t arm_gic_get_pending_interrupt_id(void) __warn_deprecated;
+uint32_t arm_gic_acknowledge_interrupt(void) __warn_deprecated;
+void arm_gic_end_of_interrupt(uint32_t id) __warn_deprecated;
+uint32_t arm_gic_get_interrupt_type(uint32_t id) __warn_deprecated;
#endif /* __GIC_H__ */
diff --git a/include/drivers/arm/gic_common.h b/include/drivers/arm/gic_common.h
new file mode 100644
index 0000000..6a322a2
--- /dev/null
+++ b/include/drivers/arm/gic_common.h
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __GIC_COMMON_H__
+#define __GIC_COMMON_H__
+
+/*******************************************************************************
+ * GIC Distributor interface general definitions
+ ******************************************************************************/
+/* Constants to categorise interrupts */
+#define MIN_SGI_ID 0
+#define MIN_PPI_ID 16
+#define MIN_SPI_ID 32
+
+/* Mask for the priority field common to all GIC interfaces */
+#define GIC_PRI_MASK 0xff
+
+/* Constant to indicate a spurious interrupt in all GIC versions */
+#define GIC_SPURIOUS_INTERRUPT 1023
+
+/* Constants to categorise priorities */
+#define GIC_HIGHEST_SEC_PRIORITY 0
+#define GIC_LOWEST_SEC_PRIORITY 127
+#define GIC_HIGHEST_NS_PRIORITY 128
+#define GIC_LOWEST_NS_PRIORITY 254 /* 255 would disable an interrupt */
+
+/*******************************************************************************
+ * GIC Distributor interface register offsets that are common to GICv3 & GICv2
+ ******************************************************************************/
+#define GICD_CTLR 0x0
+#define GICD_TYPER 0x4
+#define GICD_IIDR 0x8
+#define GICD_IGROUPR 0x80
+#define GICD_ISENABLER 0x100
+#define GICD_ICENABLER 0x180
+#define GICD_ISPENDR 0x200
+#define GICD_ICPENDR 0x280
+#define GICD_ISACTIVER 0x300
+#define GICD_ICACTIVER 0x380
+#define GICD_IPRIORITYR 0x400
+#define GICD_ICFGR 0xc00
+#define GICD_NSACR 0xe00
+
+/* GICD_CTLR bit definitions */
+#define CTLR_ENABLE_G0_SHIFT 0
+#define CTLR_ENABLE_G0_MASK 0x1
+#define CTLR_ENABLE_G0_BIT (1 << CTLR_ENABLE_G0_SHIFT)
+
+
+/*******************************************************************************
+ * GIC Distributor interface register constants that are common to GICv3 & GICv2
+ ******************************************************************************/
+#define PIDR2_ARCH_REV_SHIFT 4
+#define PIDR2_ARCH_REV_MASK 0xf
+
+/* GICv3 revision as reported by the PIDR2 register */
+#define ARCH_REV_GICV3 0x3
+/* GICv2 revision as reported by the PIDR2 register */
+#define ARCH_REV_GICV2 0x2
+
+#define IGROUPR_SHIFT 5
+#define ISENABLER_SHIFT 5
+#define ICENABLER_SHIFT ISENABLER_SHIFT
+#define ISPENDR_SHIFT 5
+#define ICPENDR_SHIFT ISPENDR_SHIFT
+#define ISACTIVER_SHIFT 5
+#define ICACTIVER_SHIFT ISACTIVER_SHIFT
+#define IPRIORITYR_SHIFT 2
+#define ICFGR_SHIFT 4
+#define NSACR_SHIFT 4
+
+/* GICD_TYPER shifts and masks */
+#define TYPER_IT_LINES_NO_SHIFT 0
+#define TYPER_IT_LINES_NO_MASK 0x1f
+
+/* Value used to initialize Normal world interrupt priorities four at a time */
+#define GICD_IPRIORITYR_DEF_VAL \
+ (GIC_HIGHEST_NS_PRIORITY | \
+ (GIC_HIGHEST_NS_PRIORITY << 8) | \
+ (GIC_HIGHEST_NS_PRIORITY << 16) | \
+ (GIC_HIGHEST_NS_PRIORITY << 24))
+
+#ifndef __ASSEMBLY__
+
+#include <mmio.h>
+#include <stdint.h>
+
+/*******************************************************************************
+ * GIC Distributor interface register accessors that are common to GICv3 & GICv2
+ ******************************************************************************/
+static inline unsigned int gicd_read_ctlr(uintptr_t base)
+{
+ return mmio_read_32(base + GICD_CTLR);
+}
+
+static inline unsigned int gicd_read_typer(uintptr_t base)
+{
+ return mmio_read_32(base + GICD_TYPER);
+}
+
+static inline unsigned int gicd_read_iidr(uintptr_t base)
+{
+ return mmio_read_32(base + GICD_IIDR);
+}
+
+static inline void gicd_write_ctlr(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICD_CTLR, val);
+}
+
+/*******************************************************************************
+ * GIC Distributor function prototypes
+ ******************************************************************************/
+unsigned int gicd_read_igroupr(uintptr_t base, unsigned int id);
+unsigned int gicd_read_isenabler(uintptr_t base, unsigned int id);
+unsigned int gicd_read_icenabler(uintptr_t base, unsigned int id);
+unsigned int gicd_read_ispendr(uintptr_t base, unsigned int id);
+unsigned int gicd_read_icpendr(uintptr_t base, unsigned int id);
+unsigned int gicd_read_isactiver(uintptr_t base, unsigned int id);
+unsigned int gicd_read_icactiver(uintptr_t base, unsigned int id);
+unsigned int gicd_read_ipriorityr(uintptr_t base, unsigned int id);
+unsigned int gicd_read_icfgr(uintptr_t base, unsigned int id);
+unsigned int gicd_read_nsacr(uintptr_t base, unsigned int id);
+void gicd_write_igroupr(uintptr_t base, unsigned int id, unsigned int val);
+void gicd_write_isenabler(uintptr_t base, unsigned int id, unsigned int val);
+void gicd_write_icenabler(uintptr_t base, unsigned int id, unsigned int val);
+void gicd_write_ispendr(uintptr_t base, unsigned int id, unsigned int val);
+void gicd_write_icpendr(uintptr_t base, unsigned int id, unsigned int val);
+void gicd_write_isactiver(uintptr_t base, unsigned int id, unsigned int val);
+void gicd_write_icactiver(uintptr_t base, unsigned int id, unsigned int val);
+void gicd_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val);
+void gicd_write_icfgr(uintptr_t base, unsigned int id, unsigned int val);
+void gicd_write_nsacr(uintptr_t base, unsigned int id, unsigned int val);
+unsigned int gicd_get_igroupr(uintptr_t base, unsigned int id);
+void gicd_set_igroupr(uintptr_t base, unsigned int id);
+void gicd_clr_igroupr(uintptr_t base, unsigned int id);
+void gicd_set_isenabler(uintptr_t base, unsigned int id);
+void gicd_set_icenabler(uintptr_t base, unsigned int id);
+void gicd_set_ispendr(uintptr_t base, unsigned int id);
+void gicd_set_icpendr(uintptr_t base, unsigned int id);
+void gicd_set_isactiver(uintptr_t base, unsigned int id);
+void gicd_set_icactiver(uintptr_t base, unsigned int id);
+
+
+#endif /* __ASSEMBLY__ */
+#endif /* __GIC_COMMON_H__ */
diff --git a/include/drivers/arm/gic_v2.h b/include/drivers/arm/gic_v2.h
index ce9311e..594ce49 100644
--- a/include/drivers/arm/gic_v2.h
+++ b/include/drivers/arm/gic_v2.h
@@ -31,6 +31,13 @@
#ifndef __GIC_V2_H__
#define __GIC_V2_H__
+/******************************************************************************
+ * THIS DRIVER IS DEPRECATED. For GICv2 systems, use the driver in gicv2.h
+ * and for GICv3 systems, use the driver in gicv3.h.
+ *****************************************************************************/
+#if ERROR_DEPRECATED
+#error " The legacy ARM GIC driver is deprecated."
+#endif
#define GIC400_NUM_SPIS 480
#define MAX_PPIS 14
diff --git a/include/drivers/arm/gic_v3.h b/include/drivers/arm/gic_v3.h
index c410626..a1b6f1b 100644
--- a/include/drivers/arm/gic_v3.h
+++ b/include/drivers/arm/gic_v3.h
@@ -31,6 +31,14 @@
#ifndef __GIC_V3_H__
#define __GIC_V3_H__
+/******************************************************************************
+ * THIS DRIVER IS DEPRECATED. For GICv2 systems, use the driver in gicv2.h
+ * and for GICv3 systems, use the driver in gicv3.h.
+ *****************************************************************************/
+#if ERROR_DEPRECATED
+#error " The legacy ARM GIC driver is deprecated."
+#endif
+
#include <mmio.h>
#include <stdint.h>
diff --git a/include/drivers/arm/gicv2.h b/include/drivers/arm/gicv2.h
new file mode 100644
index 0000000..88dc015
--- /dev/null
+++ b/include/drivers/arm/gicv2.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __GICV2_H__
+#define __GICV2_H__
+
+/*******************************************************************************
+ * GICv2 miscellaneous definitions
+ ******************************************************************************/
+/* Interrupt IDs reported by the HPPIR and IAR registers */
+#define PENDING_G1_INTID 1022
+
+/*******************************************************************************
+ * GICv2 specific Distributor interface register offsets and constants.
+ ******************************************************************************/
+#define GICD_ITARGETSR 0x800
+#define GICD_SGIR 0xF00
+#define GICD_CPENDSGIR 0xF10
+#define GICD_SPENDSGIR 0xF20
+#define GICD_PIDR2_GICV2 0xFE8
+
+#define ITARGETSR_SHIFT 2
+#define GIC_TARGET_CPU_MASK 0xff
+
+#define CPENDSGIR_SHIFT 2
+#define SPENDSGIR_SHIFT CPENDSGIR_SHIFT
+
+/*******************************************************************************
+ * GICv2 specific CPU interface register offsets and constants.
+ ******************************************************************************/
+/* Physical CPU Interface registers */
+#define GICC_CTLR 0x0
+#define GICC_PMR 0x4
+#define GICC_BPR 0x8
+#define GICC_IAR 0xC
+#define GICC_EOIR 0x10
+#define GICC_RPR 0x14
+#define GICC_HPPIR 0x18
+#define GICC_AHPPIR 0x28
+#define GICC_IIDR 0xFC
+#define GICC_DIR 0x1000
+#define GICC_PRIODROP GICC_EOIR
+
+/* GICC_CTLR bit definitions */
+#define EOI_MODE_NS (1 << 10)
+#define EOI_MODE_S (1 << 9)
+#define IRQ_BYP_DIS_GRP1 (1 << 8)
+#define FIQ_BYP_DIS_GRP1 (1 << 7)
+#define IRQ_BYP_DIS_GRP0 (1 << 6)
+#define FIQ_BYP_DIS_GRP0 (1 << 5)
+#define CBPR (1 << 4)
+#define FIQ_EN_SHIFT 3
+#define FIQ_EN_BIT (1 << FIQ_EN_SHIFT)
+#define ACK_CTL (1 << 2)
+
+/* GICC_IIDR bit masks and shifts */
+#define GICC_IIDR_PID_SHIFT 20
+#define GICC_IIDR_ARCH_SHIFT 16
+#define GICC_IIDR_REV_SHIFT 12
+#define GICC_IIDR_IMP_SHIFT 0
+
+#define GICC_IIDR_PID_MASK 0xfff
+#define GICC_IIDR_ARCH_MASK 0xf
+#define GICC_IIDR_REV_MASK 0xf
+#define GICC_IIDR_IMP_MASK 0xfff
+
+/* HYP view virtual CPU Interface registers */
+#define GICH_CTL 0x0
+#define GICH_VTR 0x4
+#define GICH_ELRSR0 0x30
+#define GICH_ELRSR1 0x34
+#define GICH_APR0 0xF0
+#define GICH_LR_BASE 0x100
+
+/* Virtual CPU Interface registers */
+#define GICV_CTL 0x0
+#define GICV_PRIMASK 0x4
+#define GICV_BP 0x8
+#define GICV_INTACK 0xC
+#define GICV_EOI 0x10
+#define GICV_RUNNINGPRI 0x14
+#define GICV_HIGHESTPEND 0x18
+#define GICV_DEACTIVATE 0x1000
+
+/* GICD_CTLR bit definitions */
+#define CTLR_ENABLE_G1_SHIFT 1
+#define CTLR_ENABLE_G1_MASK 0x1
+#define CTLR_ENABLE_G1_BIT (1 << CTLR_ENABLE_G1_SHIFT)
+
+/* Interrupt ID mask for HPPIR, AHPPIR, IAR and AIAR CPU Interface registers */
+#define INT_ID_MASK 0x3ff
+
+#ifndef __ASSEMBLY__
+
+#include <stdint.h>
+
+/*******************************************************************************
+ * This structure describes some of the implementation defined attributes of
+ * the GICv2 IP. It is used by the platform port to specify these attributes
+ * in order to initialize the GICv2 driver. The attributes are described
+ * below.
+ *
+ * 1. The 'gicd_base' field contains the base address of the Distributor
+ * interface programmer's view.
+ *
+ * 2. The 'gicc_base' field contains the base address of the CPU Interface
+ * programmer's view.
+ *
+ * 3. The 'g0_interrupt_array' field is a pointer to an array in which each
+ * entry corresponds to an ID of a Group 0 interrupt.
+ *
+ * 4. The 'g0_interrupt_num' field contains the number of entries in the
+ * 'g0_interrupt_array'.
+ ******************************************************************************/
+typedef struct gicv2_driver_data {
+ uintptr_t gicd_base;
+ uintptr_t gicc_base;
+ unsigned int g0_interrupt_num;
+ const unsigned int *g0_interrupt_array;
+} gicv2_driver_data_t;
+
+/*******************************************************************************
+ * Function prototypes
+ ******************************************************************************/
+void gicv2_driver_init(const gicv2_driver_data_t *plat_driver_data);
+void gicv2_distif_init(void);
+void gicv2_pcpu_distif_init(void);
+void gicv2_cpuif_enable(void);
+void gicv2_cpuif_disable(void);
+unsigned int gicv2_is_fiq_enabled(void);
+unsigned int gicv2_get_pending_interrupt_type(void);
+unsigned int gicv2_get_pending_interrupt_id(void);
+unsigned int gicv2_acknowledge_interrupt(void);
+void gicv2_end_of_interrupt(unsigned int id);
+unsigned int gicv2_get_interrupt_group(unsigned int id);
+
+#endif /* __ASSEMBLY__ */
+#endif /* __GICV2_H__ */
diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h
new file mode 100644
index 0000000..e874f5c
--- /dev/null
+++ b/include/drivers/arm/gicv3.h
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __GICV3_H__
+#define __GICV3_H__
+
+/*******************************************************************************
+ * GICv3 miscellaneous definitions
+ ******************************************************************************/
+/* Interrupt group definitions */
+#define INT_TYPE_G1S 0
+#define INT_TYPE_G0 1
+#define INT_TYPE_G1NS 2
+
+/* Interrupt IDs reported by the HPPIR and IAR registers */
+#define PENDING_G1S_INTID 1020
+#define PENDING_G1NS_INTID 1021
+
+/* Constant to categorize LPI interrupt */
+#define MIN_LPI_ID 8192
+
+/*******************************************************************************
+ * GICv3 specific Distributor interface register offsets and constants.
+ ******************************************************************************/
+#define GICD_STATUSR 0x10
+#define GICD_SETSPI_NSR 0x40
+#define GICD_CLRSPI_NSR 0x48
+#define GICD_SETSPI_SR 0x50
+#define GICD_CLRSPI_SR 0x50
+#define GICD_IGRPMODR 0xd00
+#define GICD_IROUTER 0x6100
+#define GICD_PIDR2_GICV3 0xffe8
+
+#define IGRPMODR_SHIFT 5
+
+/* GICD_CTLR bit definitions */
+#define CTLR_ENABLE_G1NS_SHIFT 1
+#define CTLR_ENABLE_G1S_SHIFT 2
+#define CTLR_ARE_S_SHIFT 4
+#define CTLR_ARE_NS_SHIFT 5
+#define CTLR_DS_SHIFT 6
+#define CTLR_E1NWF_SHIFT 7
+#define GICD_CTLR_RWP_SHIFT 31
+
+#define CTLR_ENABLE_G1NS_MASK 0x1
+#define CTLR_ENABLE_G1S_MASK 0x1
+#define CTLR_ARE_S_MASK 0x1
+#define CTLR_ARE_NS_MASK 0x1
+#define CTLR_DS_MASK 0x1
+#define CTLR_E1NWF_MASK 0x1
+#define GICD_CTLR_RWP_MASK 0x1
+
+#define CTLR_ENABLE_G1NS_BIT (1 << CTLR_ENABLE_G1NS_SHIFT)
+#define CTLR_ENABLE_G1S_BIT (1 << CTLR_ENABLE_G1S_SHIFT)
+#define CTLR_ARE_S_BIT (1 << CTLR_ARE_S_SHIFT)
+#define CTLR_ARE_NS_BIT (1 << CTLR_ARE_NS_SHIFT)
+#define CTLR_DS_BIT (1 << CTLR_DS_SHIFT)
+#define CTLR_E1NWF_BIT (1 << CTLR_E1NWF_SHIFT)
+#define GICD_CTLR_RWP_BIT (1 << GICD_CTLR_RWP_SHIFT)
+
+/* GICD_IROUTER shifts and masks */
+#define IROUTER_IRM_SHIFT 31
+#define IROUTER_IRM_MASK 0x1
+
+/*******************************************************************************
+ * GICv3 Re-distributor interface registers & constants
+ ******************************************************************************/
+#define GICR_PCPUBASE_SHIFT 0x11
+#define GICR_SGIBASE_OFFSET (1 << 0x10) /* 64 KB */
+#define GICR_CTLR 0x0
+#define GICR_TYPER 0x08
+#define GICR_WAKER 0x14
+#define GICR_IGROUPR0 (GICR_SGIBASE_OFFSET + 0x80)
+#define GICR_ISENABLER0 (GICR_SGIBASE_OFFSET + 0x100)
+#define GICR_ICENABLER0 (GICR_SGIBASE_OFFSET + 0x180)
+#define GICR_IPRIORITYR (GICR_SGIBASE_OFFSET + 0x400)
+#define GICR_ICFGR0 (GICR_SGIBASE_OFFSET + 0xc00)
+#define GICR_ICFGR1 (GICR_SGIBASE_OFFSET + 0xc04)
+#define GICR_IGRPMODR0 (GICR_SGIBASE_OFFSET + 0xd00)
+
+/* GICR_CTLR bit definitions */
+#define GICR_CTLR_RWP_SHIFT 3
+#define GICR_CTLR_RWP_MASK 0x1
+#define GICR_CTLR_RWP_BIT (1 << GICR_CTLR_RWP_SHIFT)
+
+/* GICR_WAKER bit definitions */
+#define WAKER_CA_SHIFT 2
+#define WAKER_PS_SHIFT 1
+
+#define WAKER_CA_MASK 0x1
+#define WAKER_PS_MASK 0x1
+
+#define WAKER_CA_BIT (1 << WAKER_CA_SHIFT)
+#define WAKER_PS_BIT (1 << WAKER_PS_SHIFT)
+
+/* GICR_TYPER bit definitions */
+#define TYPER_AFF_VAL_SHIFT 32
+#define TYPER_PROC_NUM_SHIFT 8
+#define TYPER_LAST_SHIFT 4
+
+#define TYPER_AFF_VAL_MASK 0xffffffff
+#define TYPER_PROC_NUM_MASK 0xffff
+#define TYPER_LAST_MASK 0x1
+
+#define TYPER_LAST_BIT (1 << TYPER_LAST_SHIFT)
+
+/*******************************************************************************
+ * GICv3 CPU interface registers & constants
+ ******************************************************************************/
+/* ICC_SRE bit definitions*/
+#define ICC_SRE_EN_BIT (1 << 3)
+#define ICC_SRE_DIB_BIT (1 << 2)
+#define ICC_SRE_DFB_BIT (1 << 1)
+#define ICC_SRE_SRE_BIT (1 << 0)
+
+/* ICC_IGRPEN1_EL3 bit definitions */
+#define IGRPEN1_EL3_ENABLE_G1NS_SHIFT 0
+#define IGRPEN1_EL3_ENABLE_G1S_SHIFT 1
+
+#define IGRPEN1_EL3_ENABLE_G1NS_BIT (1 << IGRPEN1_EL3_ENABLE_G1NS_SHIFT)
+#define IGRPEN1_EL3_ENABLE_G1S_BIT (1 << IGRPEN1_EL3_ENABLE_G1S_SHIFT)
+
+/* ICC_IGRPEN0_EL1 bit definitions */
+#define IGRPEN1_EL1_ENABLE_G0_SHIFT 0
+#define IGRPEN1_EL1_ENABLE_G0_BIT (1 << IGRPEN1_EL1_ENABLE_G0_SHIFT)
+
+/* ICC_HPPIR0_EL1 bit definitions */
+#define HPPIR0_EL1_INTID_SHIFT 0
+#define HPPIR0_EL1_INTID_MASK 0xffffff
+
+/* ICC_HPPIR1_EL1 bit definitions */
+#define HPPIR1_EL1_INTID_SHIFT 0
+#define HPPIR1_EL1_INTID_MASK 0xffffff
+
+/* ICC_IAR0_EL1 bit definitions */
+#define IAR0_EL1_INTID_SHIFT 0
+#define IAR0_EL1_INTID_MASK 0xffffff
+
+/* ICC_IAR1_EL1 bit definitions */
+#define IAR1_EL1_INTID_SHIFT 0
+#define IAR1_EL1_INTID_MASK 0xffffff
+
+#ifndef __ASSEMBLY__
+
+#include <stdint.h>
+
+#define gicv3_is_intr_id_special_identifier(id) \
+ (((id) >= PENDING_G1S_INTID) && ((id) <= GIC_SPURIOUS_INTERRUPT))
+
+/*******************************************************************************
+ * Helper GICv3 macros for SEL1
+ ******************************************************************************/
+#define gicv3_acknowledge_interrupt_sel1() read_icc_iar1_el1() &\
+ IAR1_EL1_INTID_MASK
+#define gicv3_get_pending_interrupt_id_sel1() read_icc_hppir1_el1() &\
+ HPPIR1_EL1_INTID_MASK
+#define gicv3_end_of_interrupt_sel1(id) write_icc_eoir1_el1(id)
+
+
+/*******************************************************************************
+ * Helper GICv3 macros for EL3
+ ******************************************************************************/
+#define gicv3_acknowledge_interrupt() read_icc_iar0_el1() &\
+ IAR0_EL1_INTID_MASK
+#define gicv3_end_of_interrupt(id) write_icc_eoir0_el1(id)
+
+/*******************************************************************************
+ * This structure describes some of the implementation defined attributes of the
+ * GICv3 IP. It is used by the platform port to specify these attributes in order
+ * to initialise the GICV3 driver. The attributes are described below.
+ *
+ * 1. The 'gicd_base' field contains the base address of the Distributor
+ * interface programmer's view.
+ *
+ * 2. The 'gicr_base' field contains the base address of the Re-distributor
+ * interface programmer's view.
+ *
+ * 3. The 'g0_interrupt_array' field is a ponter to an array in which each
+ * entry corresponds to an ID of a Group 0 interrupt.
+ *
+ * 4. The 'g0_interrupt_num' field contains the number of entries in the
+ * 'g0_interrupt_array'.
+ *
+ * 5. The 'g1s_interrupt_array' field is a ponter to an array in which each
+ * entry corresponds to an ID of a Group 1 interrupt.
+ *
+ * 6. The 'g1s_interrupt_num' field contains the number of entries in the
+ * 'g1s_interrupt_array'.
+ *
+ * 7. The 'rdistif_num' field contains the number of Redistributor interfaces
+ * the GIC implements. This is equal to the number of CPUs or CPU interfaces
+ * instantiated in the GIC.
+ *
+ * 8. The 'rdistif_base_addrs' field is a pointer to an array that has an entry
+ * for storing the base address of the Redistributor interface frame of each
+ * CPU in the system. The size of the array = 'rdistif_num'. The base
+ * addresses are detected during driver initialisation.
+ *
+ * 9. The 'mpidr_to_core_pos' field is a pointer to a hash function which the
+ * driver will use to convert an MPIDR value to a linear core index. This
+ * index will be used for accessing the 'rdistif_base_addrs' array. This is
+ * an optional field. A GICv3 implementation maps each MPIDR to a linear core
+ * index as well. This mapping can be found by reading the "Affinity Value"
+ * and "Processor Number" fields in the GICR_TYPER. It is IMP. DEF. if the
+ * "Processor Numbers" are suitable to index into an array to access core
+ * specific information. If this not the case, the platform port must provide
+ * a hash function. Otherwise, the "Processor Number" field will be used to
+ * access the array elements.
+ ******************************************************************************/
+typedef unsigned int (*mpidr_hash_fn)(unsigned long mpidr);
+
+typedef struct gicv3_driver_data {
+ uintptr_t gicd_base;
+ uintptr_t gicr_base;
+ unsigned int g0_interrupt_num;
+ unsigned int g1s_interrupt_num;
+ const unsigned int *g0_interrupt_array;
+ const unsigned int *g1s_interrupt_array;
+ unsigned int rdistif_num;
+ uintptr_t *rdistif_base_addrs;
+ mpidr_hash_fn mpidr_to_core_pos;
+} gicv3_driver_data_t;
+
+/*******************************************************************************
+ * GICv3 EL3 driver API
+ ******************************************************************************/
+void gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data);
+void gicv3_distif_init(void);
+void gicv3_rdistif_init(unsigned int proc_num);
+void gicv3_cpuif_enable(unsigned int proc_num);
+void gicv3_cpuif_disable(unsigned int proc_num);
+unsigned int gicv3_get_pending_interrupt_type(void);
+unsigned int gicv3_get_pending_interrupt_id(void);
+unsigned int gicv3_get_interrupt_type(unsigned int id,
+ unsigned int proc_num);
+
+
+#endif /* __ASSEMBLY__ */
+#endif /* __GICV3_H__ */
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index 9aea2c9..49efafc 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -88,6 +88,14 @@
#define ICC_CTLR_EL1 S3_0_C12_C12_4
#define ICC_CTLR_EL3 S3_6_C12_C12_4
#define ICC_PMR_EL1 S3_0_C4_C6_0
+#define ICC_IGRPEN1_EL3 S3_6_c12_c12_7
+#define ICC_IGRPEN0_EL1 S3_0_c12_c12_6
+#define ICC_HPPIR0_EL1 S3_0_c12_c8_2
+#define ICC_HPPIR1_EL1 S3_0_c12_c12_2
+#define ICC_IAR0_EL1 S3_0_c12_c8_0
+#define ICC_IAR1_EL1 S3_0_c12_c12_0
+#define ICC_EOIR0_EL1 S3_0_c12_c8_1
+#define ICC_EOIR1_EL1 S3_0_c12_c12_1
/*******************************************************************************
* Generic timer memory mapped registers & offsets
@@ -122,6 +130,10 @@
#define ID_AA64PFR0_EL3_SHIFT 12
#define ID_AA64PFR0_ELX_MASK 0xf
+#define ID_AA64PFR0_GIC_SHIFT 24
+#define ID_AA64PFR0_GIC_WIDTH 4
+#define ID_AA64PFR0_GIC_MASK ((1 << ID_AA64PFR0_GIC_WIDTH) - 1)
+
/* ID_PFR1_EL1 definitions */
#define ID_PFR1_VIRTEXT_SHIFT 12
#define ID_PFR1_VIRTEXT_MASK 0xf
diff --git a/include/lib/aarch64/arch_helpers.h b/include/lib/aarch64/arch_helpers.h
index d01ea31..43c6917 100644
--- a/include/lib/aarch64/arch_helpers.h
+++ b/include/lib/aarch64/arch_helpers.h
@@ -74,6 +74,14 @@
_DEFINE_SYSREG_READ_FUNC(_name, _reg_name) \
_DEFINE_SYSREG_WRITE_FUNC(_name, _reg_name)
+/* Define read function for renamed system register */
+#define DEFINE_RENAME_SYSREG_READ_FUNC(_name, _reg_name) \
+ _DEFINE_SYSREG_READ_FUNC(_name, _reg_name)
+
+/* Define write function for renamed system register */
+#define DEFINE_RENAME_SYSREG_WRITE_FUNC(_name, _reg_name) \
+ _DEFINE_SYSREG_WRITE_FUNC(_name, _reg_name)
+
/* Define write function for special system registers */
#define DEFINE_SYSREG_WRITE_CONST_FUNC(_name) \
_DEFINE_SYSREG_WRITE_CONST_FUNC(_name, _name)
@@ -284,12 +292,18 @@
DEFINE_SYSREG_READ_FUNC(ctr_el0)
-/* GICv3 System Registers */
-
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el1, ICC_SRE_EL1)
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el2, ICC_SRE_EL2)
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el3, ICC_SRE_EL3)
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_pmr_el1, ICC_PMR_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(icc_igrpen1_el3, ICC_IGRPEN1_EL3)
+DEFINE_RENAME_SYSREG_RW_FUNCS(icc_igrpen0_el1, ICC_IGRPEN0_EL1)
+DEFINE_RENAME_SYSREG_READ_FUNC(icc_hppir0_el1, ICC_HPPIR0_EL1)
+DEFINE_RENAME_SYSREG_READ_FUNC(icc_hppir1_el1, ICC_HPPIR1_EL1)
+DEFINE_RENAME_SYSREG_READ_FUNC(icc_iar0_el1, ICC_IAR0_EL1)
+DEFINE_RENAME_SYSREG_READ_FUNC(icc_iar1_el1, ICC_IAR1_EL1)
+DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_eoir0_el1, ICC_EOIR0_EL1)
+DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_eoir1_el1, ICC_EOIR1_EL1)
#define IS_IN_EL(x) \