summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/arm/gic/common/gic_common.c308
-rw-r--r--drivers/arm/gic/v2/gicv2_helpers.c230
-rw-r--r--drivers/arm/gic/v2/gicv2_main.c254
-rw-r--r--drivers/arm/gic/v2/gicv2_private.h147
-rw-r--r--drivers/arm/gic/v3/gicv3_helpers.c415
-rw-r--r--drivers/arm/gic/v3/gicv3_main.c381
-rw-r--r--drivers/arm/gic/v3/gicv3_private.h232
-rw-r--r--drivers/arm/sp805/sp805.c74
-rw-r--r--drivers/arm/tzc400/tzc400.c25
9 files changed, 2055 insertions, 11 deletions
diff --git a/drivers/arm/gic/common/gic_common.c b/drivers/arm/gic/common/gic_common.c
new file mode 100644
index 00000000..17be61d5
--- /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 00000000..1f904c51
--- /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 00000000..cf939261
--- /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 00000000..6a1ec82b
--- /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 00000000..6e8251d5
--- /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 00000000..06311e3a
--- /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 00000000..c8b311a1
--- /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/drivers/arm/sp805/sp805.c b/drivers/arm/sp805/sp805.c
new file mode 100644
index 00000000..4886e01f
--- /dev/null
+++ b/drivers/arm/sp805/sp805.c
@@ -0,0 +1,74 @@
+/*
+ * 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 <mmio.h>
+#include <sp805.h>
+#include <stdint.h>
+
+/* Inline register access functions */
+
+static inline void sp805_write_wdog_load(uintptr_t base, unsigned long value)
+{
+ mmio_write_32(base + SP805_WDOG_LOAD_OFF, value);
+}
+
+static inline void sp805_write_wdog_ctrl(uintptr_t base, unsigned long value)
+{
+ mmio_write_32(base + SP805_WDOG_CTR_OFF, value);
+}
+
+static inline void sp805_write_wdog_lock(uintptr_t base, unsigned long value)
+{
+ mmio_write_32(base + SP805_WDOG_LOCK_OFF, value);
+}
+
+
+/* Public API implementation */
+
+void sp805_start(uintptr_t base, unsigned long ticks)
+{
+ sp805_write_wdog_load(base, ticks);
+ sp805_write_wdog_ctrl(base, SP805_CTR_RESEN | SP805_CTR_INTEN);
+ /* Lock registers access */
+ sp805_write_wdog_lock(base, 0);
+}
+
+void sp805_stop(uintptr_t base)
+{
+ sp805_write_wdog_lock(base, WDOG_UNLOCK_KEY);
+ sp805_write_wdog_ctrl(base, 0);
+}
+
+void sp805_refresh(uintptr_t base, unsigned long ticks)
+{
+ sp805_write_wdog_lock(base, WDOG_UNLOCK_KEY);
+ sp805_write_wdog_load(base, ticks);
+ sp805_write_wdog_lock(base, 0);
+}
diff --git a/drivers/arm/tzc400/tzc400.c b/drivers/arm/tzc400/tzc400.c
index 4b72a2bb..940e00e0 100644
--- a/drivers/arm/tzc400/tzc400.c
+++ b/drivers/arm/tzc400/tzc400.c
@@ -118,14 +118,13 @@ static inline void tzc_write_region_id_access(uintptr_t base,
REGION_NUM_OFF(region), val);
}
-static uint32_t tzc_read_component_id(uintptr_t base)
+static unsigned int tzc_read_peripheral_id(uintptr_t base)
{
- uint32_t id;
+ unsigned int id;
- id = mmio_read_8(base + CID0_OFF);
- id |= (mmio_read_8(base + CID1_OFF) << 8);
- id |= (mmio_read_8(base + CID2_OFF) << 16);
- id |= (mmio_read_8(base + CID3_OFF) << 24);
+ id = mmio_read_8(base + PID0_OFF);
+ /* Masks jep106_id_3_0 part in PID1 */
+ id |= ((mmio_read_8(base + PID1_OFF) & 0xF) << 8);
return id;
}
@@ -166,17 +165,21 @@ static void tzc_set_gate_keeper(uintptr_t base, uint8_t filter, uint32_t val)
void tzc_init(uintptr_t base)
{
- uint32_t tzc_id, tzc_build;
+ unsigned int tzc_id;
+ unsigned int tzc_build;
assert(base);
+
+ /* Assert if already initialised */
+ assert(!tzc.base);
+
tzc.base = base;
/*
- * We expect to see a tzc400. Check component ID. The TZC-400 TRM shows
- * component ID is expected to be "0xB105F00D".
+ * We expect to see a tzc400. Check peripheral ID.
*/
- tzc_id = tzc_read_component_id(tzc.base);
- if (tzc_id != TZC400_COMPONENT_ID) {
+ tzc_id = tzc_read_peripheral_id(tzc.base);
+ if (tzc_id != TZC400_PERIPHERAL_ID) {
ERROR("TZC : Wrong device ID (0x%x).\n", tzc_id);
panic();
}