Trusted Firmware-A Tests, version 2.0
This is the first public version of the tests for the Trusted
Firmware-A project. Please see the documentation provided in the
source tree for more details.
Change-Id: I6f3452046a1351ac94a71b3525c30a4ca8db7867
Signed-off-by: Sandrine Bailleux <sandrine.bailleux@arm.com>
Co-authored-by: amobal01 <amol.balasokamble@arm.com>
Co-authored-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
Co-authored-by: Asha R <asha.r@arm.com>
Co-authored-by: Chandni Cherukuri <chandni.cherukuri@arm.com>
Co-authored-by: David Cunado <david.cunado@arm.com>
Co-authored-by: Dimitris Papastamos <dimitris.papastamos@arm.com>
Co-authored-by: Douglas Raillard <douglas.raillard@arm.com>
Co-authored-by: dp-arm <dimitris.papastamos@arm.com>
Co-authored-by: Jeenu Viswambharan <jeenu.viswambharan@arm.com>
Co-authored-by: Jonathan Wright <jonathan.wright@arm.com>
Co-authored-by: Kévin Petit <kevin.petit@arm.com>
Co-authored-by: Roberto Vargas <roberto.vargas@arm.com>
Co-authored-by: Sathees Balya <sathees.balya@arm.com>
Co-authored-by: Shawon Roy <Shawon.Roy@arm.com>
Co-authored-by: Soby Mathew <soby.mathew@arm.com>
Co-authored-by: Thomas Abraham <thomas.abraham@arm.com>
Co-authored-by: Vikram Kanigiri <vikram.kanigiri@arm.com>
Co-authored-by: Yatharth Kochar <yatharth.kochar@arm.com>
diff --git a/drivers/arm/gic/arm_gic_v2.c b/drivers/arm/gic/arm_gic_v2.c
new file mode 100644
index 0000000..025d48d
--- /dev/null
+++ b/drivers/arm/gic/arm_gic_v2.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <debug.h>
+#include <gic_v2.h>
+
+void arm_gic_enable_interrupts_local(void)
+{
+ gicv2_enable_cpuif();
+}
+
+void arm_gic_setup_local(void)
+{
+ gicv2_probe_gic_cpu_id();
+ gicv2_setup_cpuif();
+}
+
+void arm_gic_disable_interrupts_local(void)
+{
+ gicv2_disable_cpuif();
+}
+
+void arm_gic_save_context_local(void)
+{
+ gicv2_save_cpuif_context();
+}
+
+void arm_gic_restore_context_local(void)
+{
+ gicv2_restore_cpuif_context();
+}
+
+void arm_gic_save_context_global(void)
+{
+ gicv2_save_sgi_ppi_context();
+}
+
+void arm_gic_restore_context_global(void)
+{
+ gicv2_setup_distif();
+ gicv2_restore_sgi_ppi_context();
+}
+
+void arm_gic_setup_global(void)
+{
+ gicv2_setup_distif();
+}
+
+unsigned int arm_gic_get_intr_priority(unsigned int num)
+{
+ return gicv2_gicd_get_ipriorityr(num);
+}
+
+void arm_gic_set_intr_priority(unsigned int num,
+ unsigned int priority)
+{
+ gicv2_gicd_set_ipriorityr(num, priority);
+}
+
+void arm_gic_send_sgi(unsigned int sgi_id, unsigned int core_pos)
+{
+ gicv2_send_sgi(sgi_id, core_pos);
+}
+
+void arm_gic_set_intr_target(unsigned int num, unsigned int core_pos)
+{
+ gicv2_set_itargetsr(num, core_pos);
+}
+
+unsigned int arm_gic_intr_enabled(unsigned int num)
+{
+ return gicv2_gicd_get_isenabler(num) != 0;
+}
+
+void arm_gic_intr_enable(unsigned int num)
+{
+ gicv2_gicd_set_isenabler(num);
+}
+
+void arm_gic_intr_disable(unsigned int num)
+{
+ gicv2_gicd_set_icenabler(num);
+}
+
+unsigned int arm_gic_intr_ack(unsigned int *raw_iar)
+{
+ assert(raw_iar);
+
+ *raw_iar = gicv2_gicc_read_iar();
+ return get_gicc_iar_intid(*raw_iar);
+}
+
+unsigned int arm_gic_is_intr_pending(unsigned int num)
+{
+ return gicv2_gicd_get_ispendr(num);
+}
+
+void arm_gic_intr_clear(unsigned int num)
+{
+ gicv2_gicd_set_icpendr(num);
+}
+
+void arm_gic_end_of_intr(unsigned int raw_iar)
+{
+ gicv2_gicc_write_eoir(raw_iar);
+}
+
+void arm_gic_init(uintptr_t gicc_base,
+ uintptr_t gicd_base,
+ uintptr_t gicr_base)
+{
+ gicv2_init(gicc_base, gicd_base);
+ INFO("ARM GIC v2 driver initialized\n");
+}
+
diff --git a/drivers/arm/gic/arm_gic_v2v3.c b/drivers/arm/gic/arm_gic_v2v3.c
new file mode 100644
index 0000000..576c611
--- /dev/null
+++ b/drivers/arm/gic/arm_gic_v2v3.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <debug.h>
+#include <gic_common.h>
+#include <gic_v2.h>
+#include <gic_v3.h>
+
+/* Record whether a GICv3 was detected on the system */
+static unsigned int gicv3_detected;
+
+void arm_gic_enable_interrupts_local(void)
+{
+ if (gicv3_detected)
+ gicv3_enable_cpuif();
+ else
+ gicv2_enable_cpuif();
+}
+
+void arm_gic_setup_local(void)
+{
+ if (gicv3_detected) {
+ gicv3_probe_redistif_addr();
+ gicv3_setup_cpuif();
+ } else {
+ gicv2_probe_gic_cpu_id();
+ gicv2_setup_cpuif();
+ }
+}
+
+void arm_gic_disable_interrupts_local(void)
+{
+ if (gicv3_detected)
+ gicv3_disable_cpuif();
+ else
+ gicv2_disable_cpuif();
+}
+
+void arm_gic_save_context_local(void)
+{
+ if (gicv3_detected)
+ gicv3_save_cpuif_context();
+ else
+ gicv2_save_cpuif_context();
+}
+
+void arm_gic_restore_context_local(void)
+{
+ if (gicv3_detected)
+ gicv3_restore_cpuif_context();
+ else
+ gicv2_restore_cpuif_context();
+}
+
+void arm_gic_save_context_global(void)
+{
+ if (gicv3_detected)
+ gicv3_save_sgi_ppi_context();
+ else
+ gicv2_save_sgi_ppi_context();
+}
+
+void arm_gic_restore_context_global(void)
+{
+ if (gicv3_detected) {
+ gicv3_setup_distif();
+ gicv3_restore_sgi_ppi_context();
+ } else {
+ gicv2_setup_distif();
+ gicv2_restore_sgi_ppi_context();
+ }
+}
+
+void arm_gic_setup_global(void)
+{
+ if (gicv3_detected)
+ gicv3_setup_distif();
+ else
+ gicv2_setup_distif();
+}
+
+unsigned int arm_gic_get_intr_priority(unsigned int num)
+{
+ if (gicv3_detected)
+ return gicv3_get_ipriorityr(num);
+ else
+ return gicv2_gicd_get_ipriorityr(num);
+}
+
+void arm_gic_set_intr_priority(unsigned int num,
+ unsigned int priority)
+{
+ if (gicv3_detected)
+ gicv3_set_ipriorityr(num, priority);
+ else
+ gicv2_gicd_set_ipriorityr(num, priority);
+}
+
+void arm_gic_send_sgi(unsigned int sgi_id, unsigned int core_pos)
+{
+ if (gicv3_detected)
+ gicv3_send_sgi(sgi_id, core_pos);
+ else
+ gicv2_send_sgi(sgi_id, core_pos);
+}
+
+void arm_gic_set_intr_target(unsigned int num, unsigned int core_pos)
+{
+ if (gicv3_detected)
+ gicv3_set_intr_route(num, core_pos);
+ else
+ gicv2_set_itargetsr(num, core_pos);
+}
+
+unsigned int arm_gic_intr_enabled(unsigned int num)
+{
+ if (gicv3_detected)
+ return gicv3_get_isenabler(num) != 0;
+ else
+ return gicv2_gicd_get_isenabler(num) != 0;
+}
+
+void arm_gic_intr_enable(unsigned int num)
+{
+ if (gicv3_detected)
+ gicv3_set_isenabler(num);
+ else
+ gicv2_gicd_set_isenabler(num);
+}
+
+void arm_gic_intr_disable(unsigned int num)
+{
+ if (gicv3_detected)
+ gicv3_set_icenabler(num);
+ else
+ gicv2_gicd_set_icenabler(num);
+}
+
+unsigned int arm_gic_intr_ack(unsigned int *raw_iar)
+{
+ assert(raw_iar);
+
+ if (gicv3_detected) {
+ *raw_iar = gicv3_acknowledge_interrupt();
+ return *raw_iar;
+ } else {
+ *raw_iar = gicv2_gicc_read_iar();
+ return get_gicc_iar_intid(*raw_iar);
+ }
+}
+
+unsigned int arm_gic_is_intr_pending(unsigned int num)
+{
+ if (gicv3_detected)
+ return gicv3_get_ispendr(num);
+ else
+ return gicv2_gicd_get_ispendr(num);
+}
+
+void arm_gic_intr_clear(unsigned int num)
+{
+ if (gicv3_detected)
+ gicv3_set_icpendr(num);
+ else
+ gicv2_gicd_set_icpendr(num);
+}
+
+void arm_gic_end_of_intr(unsigned int raw_iar)
+{
+ if (gicv3_detected)
+ gicv3_end_of_interrupt(raw_iar);
+ else
+ gicv2_gicc_write_eoir(raw_iar);
+}
+
+void arm_gic_init(uintptr_t gicc_base,
+ uintptr_t gicd_base,
+ uintptr_t gicr_base)
+{
+
+ if (is_gicv3_mode()) {
+ gicv3_detected = 1;
+ gicv3_init(gicr_base, gicd_base);
+ } else {
+ gicv2_init(gicc_base, gicd_base);
+ }
+
+ INFO("%s mode detected\n", (gicv3_detected) ?
+ "GICv3" : "GICv2");
+}
diff --git a/drivers/arm/gic/gic_common.c b/drivers/arm/gic/gic_common.c
new file mode 100644
index 0000000..207ee15
--- /dev/null
+++ b/drivers/arm/gic/gic_common.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <gic_common.h>
+#include <gic_v3.h>
+#include <mmio.h>
+
+/*******************************************************************************
+ * GIC Distributor interface accessors for reading entire registers
+ ******************************************************************************/
+
+unsigned int gicd_read_isenabler(unsigned int base, unsigned int interrupt_id)
+{
+ unsigned int n = interrupt_id >> ISENABLER_SHIFT;
+ return mmio_read_32(base + GICD_ISENABLER + (n << 2));
+}
+
+unsigned int gicd_read_icenabler(unsigned int base, unsigned int interrupt_id)
+{
+ unsigned int n = interrupt_id >> ICENABLER_SHIFT;
+ return mmio_read_32(base + GICD_ICENABLER + (n << 2));
+}
+
+unsigned int gicd_read_ispendr(unsigned int base, unsigned int interrupt_id)
+{
+ unsigned int n = interrupt_id >> ISPENDR_SHIFT;
+ return mmio_read_32(base + GICD_ISPENDR + (n << 2));
+}
+
+unsigned int gicd_read_icpendr(unsigned int base, unsigned int interrupt_id)
+{
+ unsigned int n = interrupt_id >> ICPENDR_SHIFT;
+ return mmio_read_32(base + GICD_ICPENDR + (n << 2));
+}
+
+unsigned int gicd_read_isactiver(unsigned int base, unsigned int interrupt_id)
+{
+ unsigned int n = interrupt_id >> ISACTIVER_SHIFT;
+ return mmio_read_32(base + GICD_ISACTIVER + (n << 2));
+}
+
+unsigned int gicd_read_icactiver(unsigned int base, unsigned int interrupt_id)
+{
+ unsigned int n = interrupt_id >> ICACTIVER_SHIFT;
+ return mmio_read_32(base + GICD_ICACTIVER + (n << 2));
+}
+
+unsigned int gicd_read_ipriorityr(unsigned int base, unsigned int interrupt_id)
+{
+ unsigned int n = interrupt_id >> IPRIORITYR_SHIFT;
+ return mmio_read_32(base + GICD_IPRIORITYR + (n << 2));
+}
+
+unsigned int gicd_read_icfgr(unsigned int base, unsigned int interrupt_id)
+{
+ unsigned int n = interrupt_id >> ICFGR_SHIFT;
+ return mmio_read_32(base + GICD_ICFGR + (n << 2));
+}
+
+/*******************************************************************************
+ * GIC Distributor interface accessors for writing entire registers
+ ******************************************************************************/
+
+void gicd_write_isenabler(unsigned int base,
+ unsigned int interrupt_id, unsigned int val)
+{
+ unsigned int n = interrupt_id >> ISENABLER_SHIFT;
+ mmio_write_32(base + GICD_ISENABLER + (n << 2), val);
+}
+
+void gicd_write_icenabler(unsigned int base,
+ unsigned int interrupt_id, unsigned int val)
+{
+ unsigned int n = interrupt_id >> ICENABLER_SHIFT;
+ mmio_write_32(base + GICD_ICENABLER + (n << 2), val);
+}
+
+void gicd_write_ispendr(unsigned int base,
+ unsigned int interrupt_id, unsigned int val)
+{
+ unsigned int n = interrupt_id >> ISPENDR_SHIFT;
+ mmio_write_32(base + GICD_ISPENDR + (n << 2), val);
+}
+
+void gicd_write_icpendr(unsigned int base,
+ unsigned int interrupt_id, unsigned int val)
+{
+ unsigned int n = interrupt_id >> ICPENDR_SHIFT;
+ mmio_write_32(base + GICD_ICPENDR + (n << 2), val);
+}
+
+void gicd_write_isactiver(unsigned int base,
+ unsigned int interrupt_id, unsigned int val)
+{
+ unsigned int n = interrupt_id >> ISACTIVER_SHIFT;
+ mmio_write_32(base + GICD_ISACTIVER + (n << 2), val);
+}
+
+void gicd_write_icactiver(unsigned int base,
+ unsigned int interrupt_id, unsigned int val)
+{
+ unsigned int n = interrupt_id >> ICACTIVER_SHIFT;
+ mmio_write_32(base + GICD_ICACTIVER + (n << 2), val);
+}
+
+void gicd_write_ipriorityr(unsigned int base,
+ unsigned int interrupt_id, unsigned int val)
+{
+ unsigned int n = interrupt_id >> IPRIORITYR_SHIFT;
+ mmio_write_32(base + GICD_IPRIORITYR + (n << 2), val);
+}
+
+void gicd_write_icfgr(unsigned int base,
+ unsigned int interrupt_id, unsigned int val)
+{
+ unsigned int n = interrupt_id >> ICFGR_SHIFT;
+ mmio_write_32(base + GICD_ICFGR + (n << 2), val);
+}
+
+/*******************************************************************************
+ * GIC Distributor interface accessors for individual interrupt manipulation
+ ******************************************************************************/
+unsigned int gicd_get_isenabler(unsigned int base, unsigned int interrupt_id)
+{
+ unsigned int bit_num = interrupt_id & ((1 << ISENABLER_SHIFT) - 1);
+
+ return gicd_read_isenabler(base, interrupt_id) & (1 << bit_num);
+}
+
+void gicd_set_isenabler(unsigned int base, unsigned int interrupt_id)
+{
+ unsigned int bit_num = interrupt_id & ((1 << ISENABLER_SHIFT) - 1);
+
+ gicd_write_isenabler(base, interrupt_id, (1 << bit_num));
+}
+
+void gicd_set_icenabler(unsigned int base, unsigned int interrupt_id)
+{
+ unsigned int bit_num = interrupt_id & ((1 << ICENABLER_SHIFT) - 1);
+
+ gicd_write_icenabler(base, interrupt_id, (1 << bit_num));
+}
+
+void gicd_set_ispendr(unsigned int base, unsigned int interrupt_id)
+{
+ unsigned int bit_num = interrupt_id & ((1 << ISPENDR_SHIFT) - 1);
+
+ gicd_write_ispendr(base, interrupt_id, (1 << bit_num));
+}
+
+void gicd_set_icpendr(unsigned int base, unsigned int interrupt_id)
+{
+ unsigned int bit_num = interrupt_id & ((1 << ICPENDR_SHIFT) - 1);
+
+ gicd_write_icpendr(base, interrupt_id, (1 << bit_num));
+}
+
+void gicd_set_isactiver(unsigned int base, unsigned int interrupt_id)
+{
+ unsigned int bit_num = interrupt_id & ((1 << ISACTIVER_SHIFT) - 1);
+
+ gicd_write_isactiver(base, interrupt_id, (1 << bit_num));
+}
+
+void gicd_set_icactiver(unsigned int base, unsigned int interrupt_id)
+{
+ unsigned int bit_num = interrupt_id & ((1 << ICACTIVER_SHIFT) - 1);
+
+ gicd_write_icactiver(base, interrupt_id, (1 << bit_num));
+}
+
+unsigned int gicd_get_ipriorityr(unsigned int base, unsigned int interrupt_id)
+{
+ return gicd_read_ipriorityr(base, interrupt_id) & GIC_PRI_MASK;
+}
+
+void gicd_set_ipriorityr(unsigned int base, unsigned int interrupt_id,
+ unsigned int priority)
+{
+ mmio_write_8(base + GICD_IPRIORITYR + interrupt_id,
+ priority & GIC_PRI_MASK);
+}
+
+unsigned int is_gicv3_mode(void)
+{
+ /* Check if GICv3 system register available */
+#ifndef AARCH32
+ if (!(read_id_aa64pfr0_el1() & (ID_AA64PFR0_GIC_MASK << ID_AA64PFR0_GIC_SHIFT)))
+ return 0;
+#else
+ if (!(read_id_pfr1() & (ID_PFR1_GIC_MASK << ID_PFR1_GIC_SHIFT)))
+ return 0;
+#endif
+
+ /* Check whether the system register interface is enabled */
+ return !!is_sre_enabled();
+}
diff --git a/drivers/arm/gic/gic_v2.c b/drivers/arm/gic/gic_v2.c
new file mode 100644
index 0000000..48ee29e
--- /dev/null
+++ b/drivers/arm/gic/gic_v2.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <arm_gic.h>
+#include <assert.h>
+#include <gic_common.h>
+#include <gic_v2.h>
+#include <mmio.h>
+#include <platform.h>
+
+/*
+ * Data structure to store the GIC per CPU context before entering
+ * system suspend. Only the GIC context of first 32 interrupts (SGIs and PPIs)
+ * will be saved. The GIC SPI context needs to be restored by the respective
+ * drivers. The GICC_PMR is not saved here as it will be reinitialized during
+ * GIC restore.
+ */
+struct gicv2_pcpu_ctx {
+ unsigned int gicc_ctlr;
+ unsigned int gicd_isenabler0;
+ unsigned int gicd_ipriorityr[NUM_PCPU_INTR >> IPRIORITYR_SHIFT];
+ unsigned int gicd_icfgr;
+};
+
+static struct gicv2_pcpu_ctx pcpu_gic_ctx[PLATFORM_CORE_COUNT];
+
+static uintptr_t gicc_base_addr;
+static uintptr_t gicd_base_addr;
+
+static unsigned int gic_cpu_id[PLATFORM_CORE_COUNT] = {UINT32_MAX};
+
+/* Helper function to convert core pos to gic id */
+static unsigned int core_pos_to_gic_id(unsigned int core_pos)
+{
+ assert(gic_cpu_id[core_pos] != UINT32_MAX);
+ return gic_cpu_id[core_pos];
+}
+
+/*******************************************************************************
+ * GIC Distributor interface accessors for reading entire registers
+ ******************************************************************************/
+unsigned int gicd_read_itargetsr(unsigned int base, unsigned int interrupt_id)
+{
+ unsigned n = interrupt_id >> ITARGETSR_SHIFT;
+ return mmio_read_32(base + GICD_ITARGETSR + (n << 2));
+}
+
+unsigned int gicd_read_cpendsgir(unsigned int base, unsigned int interrupt_id)
+{
+ unsigned n = interrupt_id >> CPENDSGIR_SHIFT;
+ return mmio_read_32(base + GICD_CPENDSGIR + (n << 2));
+}
+
+unsigned int gicd_read_spendsgir(unsigned int base, unsigned int interrupt_id)
+{
+ unsigned n = interrupt_id >> SPENDSGIR_SHIFT;
+ return mmio_read_32(base + GICD_SPENDSGIR + (n << 2));
+}
+
+/*******************************************************************************
+ * GIC Distributor interface accessors for writing entire registers
+ ******************************************************************************/
+void gicd_write_itargetsr(unsigned int base,
+ unsigned int interrupt_id, unsigned int val)
+{
+ unsigned n = interrupt_id >> ITARGETSR_SHIFT;
+ mmio_write_32(base + GICD_ITARGETSR + (n << 2), val);
+}
+
+void gicd_write_itargetsr_byte(unsigned int base,
+ unsigned int interrupt_id, unsigned int val)
+{
+ mmio_write_8(base + GICD_ITARGETSR + interrupt_id, val);
+}
+
+void gicd_write_cpendsgir(unsigned int base,
+ unsigned int interrupt_id, unsigned int val)
+{
+ unsigned n = interrupt_id >> CPENDSGIR_SHIFT;
+ mmio_write_32(base + GICD_CPENDSGIR + (n << 2), val);
+}
+
+void gicd_write_spendsgir(unsigned int base,
+ unsigned int interrupt_id, unsigned int val)
+{
+ unsigned n = interrupt_id >> SPENDSGIR_SHIFT;
+ mmio_write_32(base + GICD_SPENDSGIR + (n << 2), val);
+}
+
+/*******************************************************************************
+ * GIC Distributor interface accessors for individual interrupt manipulation
+ ******************************************************************************/
+void gicd_set_itargetsr(unsigned int base,
+ unsigned int interrupt_id, unsigned int iface)
+{
+ mmio_write_8(base + GICD_ITARGETSR + interrupt_id, (1 << iface));
+}
+
+/******************************************************************************
+ * GICv2 public driver API
+ *****************************************************************************/
+
+void gicv2_enable_cpuif(void)
+{
+ unsigned int gicc_ctlr;
+
+ assert(gicc_base_addr);
+
+ /* Enable the GICC and disable bypass */
+ gicc_ctlr = GICC_CTLR_ENABLE | FIQ_BYP_DIS_GRP1
+ | IRQ_BYP_DIS_GRP1;
+ gicc_write_ctlr(gicc_base_addr, gicc_ctlr);
+}
+
+void gicv2_probe_gic_cpu_id(void)
+{
+ unsigned int gicd_itargets_val, core_pos;
+
+ assert(gicd_base_addr);
+ core_pos = platform_get_core_pos(read_mpidr_el1());
+ gicd_itargets_val = gicd_read_itargetsr(gicd_base_addr, 0);
+
+ assert(gicd_itargets_val);
+
+ /* Convert the bit pos returned by read of ITARGETSR0 to GIC CPU ID */
+ gic_cpu_id[core_pos] = __builtin_ctz(gicd_itargets_val);
+}
+
+void gicv2_setup_cpuif(void)
+{
+ assert(gicc_base_addr);
+
+ /* Set the priority mask register to allow all interrupts to trickle in */
+ gicc_write_pmr(gicc_base_addr, GIC_PRI_MASK);
+ gicv2_enable_cpuif();
+}
+
+void gicv2_disable_cpuif(void)
+{
+ unsigned int gicc_ctlr;
+
+ assert(gicc_base_addr);
+
+ /* Disable non-secure interrupts and disable their bypass */
+ gicc_ctlr = gicc_read_ctlr(gicc_base_addr);
+ gicc_ctlr &= ~GICC_CTLR_ENABLE;
+ gicc_ctlr |= FIQ_BYP_DIS_GRP1 | IRQ_BYP_DIS_GRP1;
+ gicc_write_ctlr(gicc_base_addr, gicc_ctlr);
+}
+
+void gicv2_save_cpuif_context(void)
+{
+ unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
+
+ assert(gicc_base_addr);
+ pcpu_gic_ctx[core_pos].gicc_ctlr =
+ gicc_read_ctlr(gicc_base_addr);
+}
+
+void gicv2_restore_cpuif_context(void)
+{
+ unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
+
+ assert(gicc_base_addr);
+
+ /* The GICC_PMR is never modified, hence we initialize this register */
+ gicc_write_pmr(gicc_base_addr, GIC_PRI_MASK);
+
+ gicc_write_ctlr(gicc_base_addr,
+ pcpu_gic_ctx[core_pos].gicc_ctlr);
+}
+
+void gicv2_setup_distif(void)
+{
+ unsigned int gicd_ctlr;
+
+ assert(gicd_base_addr);
+
+ /* Enable the forwarding of interrupts to CPU interface */
+ gicd_ctlr = gicd_read_ctlr(gicd_base_addr);
+ gicd_ctlr |= GICD_CTLR_ENABLE;
+ gicd_write_ctlr(gicd_base_addr, gicd_ctlr);
+}
+
+/* Save the per-cpu GICD ISENABLER, IPRIORITYR and ICFGR registers */
+void gicv2_save_sgi_ppi_context(void)
+{
+ unsigned int i;
+ unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
+
+ assert(gicd_base_addr);
+ pcpu_gic_ctx[core_pos].gicd_isenabler0 =
+ gicd_read_isenabler(gicd_base_addr, 0);
+
+ /* Read the ipriority registers, 4 at a time */
+ for (i = 0; i < (NUM_PCPU_INTR >> IPRIORITYR_SHIFT); i++)
+ pcpu_gic_ctx[core_pos].gicd_ipriorityr[i] =
+ gicd_read_ipriorityr(gicd_base_addr, i << IPRIORITYR_SHIFT);
+
+ pcpu_gic_ctx[core_pos].gicd_icfgr =
+ gicd_read_icfgr(gicd_base_addr, MIN_PPI_ID);
+}
+
+/* Restore the per-cpu GICD ISENABLER, IPRIORITYR and ICFGR registers */
+void gicv2_restore_sgi_ppi_context(void)
+{
+ unsigned int i;
+ unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
+
+ assert(gicd_base_addr);
+
+ /* Write the ipriority registers, 4 at a time */
+ for (i = 0; i < (NUM_PCPU_INTR >> IPRIORITYR_SHIFT); i++)
+ gicd_write_ipriorityr(gicd_base_addr, i << IPRIORITYR_SHIFT,
+ pcpu_gic_ctx[core_pos].gicd_ipriorityr[i]);
+
+ gicd_write_icfgr(gicd_base_addr, MIN_PPI_ID,
+ pcpu_gic_ctx[core_pos].gicd_icfgr);
+
+ gicd_write_isenabler(gicd_base_addr, 0,
+ pcpu_gic_ctx[core_pos].gicd_isenabler0);
+}
+
+unsigned int gicv2_gicd_get_ipriorityr(unsigned int interrupt_id)
+{
+ assert(gicd_base_addr);
+ assert(IS_VALID_INTR_ID(interrupt_id));
+
+ return gicd_get_ipriorityr(gicd_base_addr, interrupt_id);
+}
+
+void gicv2_gicd_set_ipriorityr(unsigned int interrupt_id,
+ unsigned int priority)
+{
+ assert(gicd_base_addr);
+ assert(IS_VALID_INTR_ID(interrupt_id));
+
+ gicd_set_ipriorityr(gicd_base_addr, interrupt_id, priority);
+}
+
+void gicv2_send_sgi(unsigned int sgi_id, unsigned int core_pos)
+{
+ unsigned int sgir_val;
+
+ assert(gicd_base_addr);
+ assert(IS_SGI(sgi_id));
+
+ sgir_val = sgi_id << GICD_SGIR_INTID_SHIFT;
+ sgir_val |= (1 << core_pos_to_gic_id(core_pos)) << GICD_SGIR_CPUTL_SHIFT;
+
+ gicd_write_sgir(gicd_base_addr, sgir_val);
+}
+
+void gicv2_set_itargetsr(unsigned int num, unsigned int core_pos)
+{
+ unsigned int gic_cpu_id;
+ assert(gicd_base_addr);
+ assert(IS_SPI(num));
+
+ gic_cpu_id = core_pos_to_gic_id(core_pos);
+ gicd_set_itargetsr(gicd_base_addr, num, gic_cpu_id);
+}
+
+void gicv2_set_itargetsr_value(unsigned int num, unsigned int val)
+{
+ assert(gicd_base_addr);
+ assert(IS_SPI(num));
+
+ gicd_write_itargetsr_byte(gicd_base_addr, num, val);
+}
+
+unsigned int gicv2_gicd_get_isenabler(unsigned int num)
+{
+ assert(gicd_base_addr);
+ assert(IS_VALID_INTR_ID(num));
+
+ return gicd_get_isenabler(gicd_base_addr, num);
+}
+
+void gicv2_gicd_set_isenabler(unsigned int num)
+{
+ assert(gicd_base_addr);
+ assert(IS_VALID_INTR_ID(num));
+
+ gicd_set_isenabler(gicd_base_addr, num);
+}
+
+void gicv2_gicd_set_icenabler(unsigned int num)
+{
+ assert(gicd_base_addr);
+ assert(IS_VALID_INTR_ID(num));
+
+ gicd_set_icenabler(gicd_base_addr, num);
+}
+
+unsigned int gicv2_gicc_read_iar(void)
+{
+ assert(gicc_base_addr);
+ return gicc_read_iar(gicc_base_addr);
+}
+
+unsigned int gicv2_gicd_get_ispendr(unsigned int interrupt_id)
+{
+ unsigned int ispendr;
+ unsigned int bit_pos;
+
+ assert(gicd_base_addr);
+ assert(IS_VALID_INTR_ID(interrupt_id));
+
+ ispendr = gicd_read_ispendr(gicd_base_addr, interrupt_id);
+ bit_pos = interrupt_id % (1 << ISPENDR_SHIFT);
+
+ return !!(ispendr & (1 << bit_pos));
+}
+
+void gicv2_gicd_set_ispendr(unsigned int interrupt_id)
+{
+ assert(gicd_base_addr);
+ assert(IS_PPI(interrupt_id) || IS_SPI(interrupt_id));
+ gicd_set_ispendr(gicd_base_addr, interrupt_id);
+}
+
+void gicv2_gicd_set_icpendr(unsigned int interrupt_id)
+{
+ assert(gicd_base_addr);
+ assert(IS_PPI(interrupt_id) || IS_SPI(interrupt_id));
+
+ gicd_set_icpendr(gicd_base_addr, interrupt_id);
+}
+
+void gicv2_gicc_write_eoir(unsigned int val)
+{
+ assert(gicc_base_addr);
+
+ gicc_write_eoir(gicc_base_addr, val);
+}
+
+void gicv2_init(uintptr_t gicc_base,
+ uintptr_t gicd_base)
+{
+ assert(gicc_base);
+ assert(gicd_base);
+
+ /* Assert that this is a GICv2 system */
+ assert(!is_gicv3_mode());
+ gicc_base_addr = gicc_base;
+ gicd_base_addr = gicd_base;
+}
diff --git a/drivers/arm/gic/gic_v3.c b/drivers/arm/gic/gic_v3.c
new file mode 100644
index 0000000..76b0863
--- /dev/null
+++ b/drivers/arm/gic/gic_v3.c
@@ -0,0 +1,507 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <arm_gic.h>
+#include <assert.h>
+#include <debug.h>
+#include <gic_common.h>
+#include <gic_v3.h>
+#include <mmio.h>
+#include <platform.h>
+
+/* Global variables to store the GIC base addresses */
+static uintptr_t gicr_base_addr;
+static uintptr_t gicd_base_addr;
+
+#ifndef AARCH32
+#define MPIDR_AFFLVL3_MASK ((unsigned long long)MPIDR_AFFLVL_MASK << MPIDR_AFF3_SHIFT)
+#define gic_typer_affinity_from_mpidr(mpidr) \
+ (((mpidr) & (~MPIDR_AFFLVL3_MASK)) | (((mpidr) & MPIDR_AFFLVL3_MASK) >> 8))
+#else
+#define gic_typer_affinity_from_mpidr(mpidr) \
+ ((mpidr) & ((MPIDR_AFFLVL_MASK << MPIDR_AFF2_SHIFT) | MPID_MASK))
+#endif
+
+/*
+ * Data structure to store the GIC per CPU context before entering
+ * system suspend. Only the GIC context of first 32 interrupts (SGIs and PPIs)
+ * will be saved. The GIC SPI context needs to be restored by the respective
+ * drivers.
+ */
+struct gicv3_pcpu_ctx {
+ /* Flag to indicate whether the CPU is suspended */
+ unsigned int is_suspended;
+ unsigned int icc_igrpen1;
+ unsigned int gicr_isenabler;
+ unsigned int gicr_ipriorityr[NUM_PCPU_INTR >> IPRIORITYR_SHIFT];
+ unsigned int gicr_icfgr;
+};
+
+/* Array to store the per-cpu GICv3 context when being suspended.*/
+static struct gicv3_pcpu_ctx pcpu_ctx[PLATFORM_CORE_COUNT];
+
+/* Array to store the per-cpu redistributor frame addresses */
+static uintptr_t rdist_pcpu_base[PLATFORM_CORE_COUNT];
+
+/*
+ * Array to store the mpidr corresponding to each initialized per-CPU
+ * redistributor interface.
+ */
+static unsigned long long mpidr_list[PLATFORM_CORE_COUNT] = {UINT64_MAX};
+
+/******************************************************************************
+ * GIC Distributor interface accessors for writing entire registers
+ *****************************************************************************/
+static void gicd_write_irouter(unsigned int base,
+ unsigned int interrupt_id,
+ unsigned long long route)
+{
+ assert(interrupt_id >= MIN_SPI_ID);
+ mmio_write_64(base + GICD_IROUTER + (interrupt_id << 3), route);
+}
+
+/******************************************************************************
+ * GIC Re-distributor interface accessors for writing entire registers
+ *****************************************************************************/
+static void gicr_write_isenabler0(unsigned int base, unsigned int val)
+{
+ mmio_write_32(base + GICR_ISENABLER0, val);
+}
+
+static void gicr_write_icenabler0(unsigned int base, unsigned int val)
+{
+ mmio_write_32(base + GICR_ICENABLER0, val);
+}
+
+static void gicr_write_icpendr0(unsigned int base, unsigned int val)
+{
+ mmio_write_32(base + GICR_ICPENDR0, val);
+}
+
+static 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);
+}
+
+static void gicr_write_icfgr1(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICR_ICFGR1, val);
+}
+
+/******************************************************************************
+ * GIC Re-distributor interface accessors for reading entire registers
+ *****************************************************************************/
+static unsigned long long gicr_read_typer(uintptr_t base)
+{
+ return mmio_read_64(base + GICR_TYPER);
+}
+
+static unsigned int gicr_read_icfgr1(uintptr_t base)
+{
+ return mmio_read_32(base + GICR_ICFGR1);
+}
+
+static unsigned int gicr_read_isenabler0(unsigned int base)
+{
+ return mmio_read_32(base + GICR_ISENABLER0);
+}
+
+static 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));
+}
+
+static unsigned int gicr_read_ispendr0(unsigned int base)
+{
+ return mmio_read_32(base + GICR_ISPENDR0);
+}
+
+/******************************************************************************
+ * GIC Re-distributor interface accessors for individual interrupt
+ * manipulation
+ *****************************************************************************/
+static unsigned int gicr_get_isenabler0(unsigned int base,
+ unsigned int interrupt_id)
+{
+ unsigned bit_num = interrupt_id & ((1 << ISENABLER_SHIFT) - 1);
+ return gicr_read_isenabler0(base) & (1 << bit_num);
+}
+
+static void gicr_set_isenabler0(unsigned int base, unsigned int interrupt_id)
+{
+ unsigned bit_num = interrupt_id & ((1 << ISENABLER_SHIFT) - 1);
+ gicr_write_isenabler0(base, (1 << bit_num));
+}
+
+static void gicr_set_icenabler0(unsigned int base, unsigned int interrupt_id)
+{
+ unsigned bit_num = interrupt_id & ((1 << ISENABLER_SHIFT) - 1);
+ gicr_write_icenabler0(base, (1 << bit_num));
+}
+
+static void gicr_set_icpendr0(unsigned int base, unsigned int interrupt_id)
+{
+ unsigned bit_num = interrupt_id & ((1 << ICPENDR_SHIFT) - 1);
+ gicr_write_icpendr0(base, (1 << bit_num));
+}
+
+/******************************************************************************
+ * GICv3 public driver API
+ *****************************************************************************/
+void gicv3_enable_cpuif(void)
+{
+ /* Assert that system register access is enabled */
+ assert(IS_IN_EL2() ? (read_icc_sre_el2() & ICC_SRE_SRE_BIT) :
+ (read_icc_sre_el1() & ICC_SRE_SRE_BIT));
+
+ /* Enable Group1 non secure interrupts */
+ write_icc_igrpen1_el1(read_icc_igrpen1_el1() | IGRPEN1_EL1_ENABLE_BIT);
+ isb();
+}
+
+void gicv3_setup_cpuif(void)
+{
+ /* Set the priority mask register to allow all interrupts to trickle in */
+ write_icc_pmr_el1(GIC_PRI_MASK);
+ isb();
+ gicv3_enable_cpuif();
+}
+
+void gicv3_disable_cpuif(void)
+{
+ /* Disable Group1 non secure interrupts */
+ write_icc_igrpen1_el1(read_icc_igrpen1_el1() &
+ ~IGRPEN1_EL1_ENABLE_BIT);
+ isb();
+}
+
+void gicv3_save_cpuif_context(void)
+{
+ unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
+
+ /* Set the `is_suspended` flag as this core is being suspended. */
+ pcpu_ctx[core_pos].is_suspended = 1;
+ pcpu_ctx[core_pos].icc_igrpen1 = read_icc_igrpen1_el1();
+}
+
+void gicv3_restore_cpuif_context(void)
+{
+ unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
+
+ /* Reset the `is_suspended` flag as this core has resumed from suspend. */
+ pcpu_ctx[core_pos].is_suspended = 0;
+ write_icc_pmr_el1(GIC_PRI_MASK);
+ write_icc_igrpen1_el1(pcpu_ctx[core_pos].icc_igrpen1);
+ isb();
+}
+
+void gicv3_save_sgi_ppi_context(void)
+{
+ unsigned int i, core_pos;
+ unsigned int my_core_pos = platform_get_core_pos(read_mpidr_el1());
+
+ /* Save the context for all the suspended cores */
+ for (core_pos = 0; core_pos < PLATFORM_CORE_COUNT; core_pos++) {
+ /*
+ * Continue if the core pos is not the current core
+ * and has not suspended
+ */
+ if ((core_pos != my_core_pos) &&
+ (!pcpu_ctx[core_pos].is_suspended))
+ continue;
+
+ assert(rdist_pcpu_base[core_pos]);
+
+ pcpu_ctx[core_pos].gicr_isenabler =
+ gicr_read_isenabler0(rdist_pcpu_base[core_pos]);
+
+ /* Read the ipriority registers, 4 at a time */
+ for (i = 0; i < (NUM_PCPU_INTR >> IPRIORITYR_SHIFT); i++)
+ pcpu_ctx[core_pos].gicr_ipriorityr[i] =
+ gicr_read_ipriorityr(rdist_pcpu_base[core_pos],
+ i << IPRIORITYR_SHIFT);
+
+ pcpu_ctx[core_pos].gicr_icfgr =
+ gicr_read_icfgr1(rdist_pcpu_base[core_pos]);
+ }
+}
+
+void gicv3_restore_sgi_ppi_context(void)
+{
+ unsigned int i, core_pos;
+ unsigned int my_core_pos = platform_get_core_pos(read_mpidr_el1());
+
+ /* Restore the context for all the suspended cores */
+ for (core_pos = 0; core_pos < PLATFORM_CORE_COUNT; core_pos++) {
+ /*
+ * Continue if the core pos is not the current core
+ * and has not suspended
+ */
+ if ((core_pos != my_core_pos) &&
+ (!pcpu_ctx[core_pos].is_suspended))
+ continue;
+
+ assert(rdist_pcpu_base[core_pos]);
+
+ /* Read the ipriority registers, 4 at a time */
+ for (i = 0; i < (NUM_PCPU_INTR >> IPRIORITYR_SHIFT); i++)
+ gicr_write_ipriorityr(rdist_pcpu_base[core_pos],
+ i << IPRIORITYR_SHIFT,
+ pcpu_ctx[core_pos].gicr_ipriorityr[i]);
+
+ gicr_write_icfgr1(rdist_pcpu_base[core_pos],
+ pcpu_ctx[core_pos].gicr_icfgr);
+ gicr_write_isenabler0(rdist_pcpu_base[core_pos],
+ pcpu_ctx[core_pos].gicr_isenabler);
+ }
+}
+
+unsigned int gicv3_get_ipriorityr(unsigned int interrupt_id)
+{
+ unsigned int core_pos;
+ assert(gicd_base_addr);
+ assert(IS_VALID_INTR_ID(interrupt_id));
+
+ if (interrupt_id < MIN_SPI_ID) {
+ core_pos = platform_get_core_pos(read_mpidr_el1());
+ assert(rdist_pcpu_base[core_pos]);
+ return mmio_read_8(rdist_pcpu_base[core_pos] + GICR_IPRIORITYR
+ + interrupt_id);
+ } else {
+ return mmio_read_8(gicd_base_addr +
+ GICD_IPRIORITYR + interrupt_id);
+ }
+}
+
+void gicv3_set_ipriorityr(unsigned int interrupt_id,
+ unsigned int priority)
+{
+ unsigned int core_pos;
+ assert(gicd_base_addr);
+ assert(IS_VALID_INTR_ID(interrupt_id));
+
+ if (interrupt_id < MIN_SPI_ID) {
+ core_pos = platform_get_core_pos(read_mpidr_el1());
+ assert(rdist_pcpu_base[core_pos]);
+ mmio_write_8(rdist_pcpu_base[core_pos] + GICR_IPRIORITYR
+ + interrupt_id, priority & GIC_PRI_MASK);
+ } else {
+ mmio_write_8(gicd_base_addr + GICD_IPRIORITYR + interrupt_id,
+ priority & GIC_PRI_MASK);
+ }
+}
+
+void gicv3_send_sgi(unsigned int sgi_id, unsigned int core_pos)
+{
+ unsigned long long aff0, aff1, aff2;
+ unsigned long long sgir, target_list;
+
+ assert(IS_SGI(sgi_id));
+ assert(core_pos < PLATFORM_CORE_COUNT);
+
+ assert(mpidr_list[core_pos] != UINT64_MAX);
+
+ /* Extract the affinity information */
+ aff0 = MPIDR_AFF_ID(mpidr_list[core_pos], 0);
+ aff1 = MPIDR_AFF_ID(mpidr_list[core_pos], 1);
+ aff2 = MPIDR_AFF_ID(mpidr_list[core_pos], 2);
+#ifndef AARCH32
+ unsigned long long aff3;
+ aff3 = MPIDR_AFF_ID(mpidr_list[core_pos], 3);
+#endif
+
+ /* Construct the SGI target list using Affinity 0 */
+ assert(aff0 < SGI_TARGET_MAX_AFF0);
+ target_list = 1 << aff0;
+
+ /* Construct the SGI target affinity */
+ sgir =
+#ifndef AARCH32
+ ((aff3 & SGI1R_AFF_MASK) << SGI1R_AFF3_SHIFT) |
+#endif
+ ((aff2 & SGI1R_AFF_MASK) << SGI1R_AFF2_SHIFT) |
+ ((aff1 & SGI1R_AFF_MASK) << SGI1R_AFF1_SHIFT) |
+ ((target_list & SGI1R_TARGET_LIST_MASK)
+ << SGI1R_TARGET_LIST_SHIFT);
+
+ /* Combine SGI target affinity with the SGI ID */
+ sgir |= ((sgi_id & SGI1R_INTID_MASK) << SGI1R_INTID_SHIFT);
+#ifndef AARCH32
+ write_icc_sgi1r(sgir);
+#else
+ write64_icc_sgi1r(sgir);
+#endif
+ isb();
+}
+
+void gicv3_set_intr_route(unsigned int interrupt_id,
+ unsigned int core_pos)
+{
+ unsigned long long route_affinity;
+
+ assert(gicd_base_addr);
+ assert(core_pos < PLATFORM_CORE_COUNT);
+ assert(mpidr_list[core_pos] != UINT64_MAX);
+
+ /* Routing information can be set only for SPIs */
+ assert(IS_SPI(interrupt_id));
+ route_affinity = mpidr_list[core_pos];
+
+ gicd_write_irouter(gicd_base_addr, interrupt_id, route_affinity);
+}
+
+unsigned int gicv3_get_isenabler(unsigned int interrupt_id)
+{
+ unsigned int core_pos;
+
+ assert(gicd_base_addr);
+ assert(IS_VALID_INTR_ID(interrupt_id));
+
+ if (interrupt_id < MIN_SPI_ID) {
+ core_pos = platform_get_core_pos(read_mpidr_el1());
+ assert(rdist_pcpu_base[core_pos]);
+ return gicr_get_isenabler0(rdist_pcpu_base[core_pos], interrupt_id);
+ } else
+ return gicd_get_isenabler(gicd_base_addr, interrupt_id);
+}
+
+void gicv3_set_isenabler(unsigned int interrupt_id)
+{
+ unsigned int core_pos;
+
+ assert(gicd_base_addr);
+ assert(IS_VALID_INTR_ID(interrupt_id));
+
+ if (interrupt_id < MIN_SPI_ID) {
+ core_pos = platform_get_core_pos(read_mpidr_el1());
+ assert(rdist_pcpu_base[core_pos]);
+ gicr_set_isenabler0(rdist_pcpu_base[core_pos], interrupt_id);
+ } else
+ gicd_set_isenabler(gicd_base_addr, interrupt_id);
+}
+
+void gicv3_set_icenabler(unsigned int interrupt_id)
+{
+ unsigned int core_pos;
+
+ assert(gicd_base_addr);
+ assert(IS_VALID_INTR_ID(interrupt_id));
+
+ if (interrupt_id < MIN_SPI_ID) {
+ core_pos = platform_get_core_pos(read_mpidr_el1());
+ assert(rdist_pcpu_base[core_pos]);
+ gicr_set_icenabler0(rdist_pcpu_base[core_pos], interrupt_id);
+ } else
+ gicd_set_icenabler(gicd_base_addr, interrupt_id);
+}
+
+unsigned int gicv3_get_ispendr(unsigned int interrupt_id)
+{
+ unsigned int ispendr;
+ unsigned int bit_pos, core_pos;
+
+ assert(gicd_base_addr);
+ assert(IS_VALID_INTR_ID(interrupt_id));
+
+ if (interrupt_id < MIN_SPI_ID) {
+ core_pos = platform_get_core_pos(read_mpidr_el1());
+ assert(rdist_pcpu_base[core_pos]);
+ ispendr = gicr_read_ispendr0(rdist_pcpu_base[core_pos]);
+ } else
+ ispendr = gicd_read_ispendr(gicd_base_addr, interrupt_id);
+
+ bit_pos = interrupt_id % (1 << ISPENDR_SHIFT);
+ return !!(ispendr & (1 << bit_pos));
+}
+
+void gicv3_set_icpendr(unsigned int interrupt_id)
+{
+ unsigned int core_pos;
+
+ assert(gicd_base_addr);
+ assert(IS_SPI(interrupt_id) || IS_PPI(interrupt_id));
+
+ if (interrupt_id < MIN_SPI_ID) {
+ core_pos = platform_get_core_pos(read_mpidr_el1());
+ assert(rdist_pcpu_base[core_pos]);
+ gicr_set_icpendr0(rdist_pcpu_base[core_pos], interrupt_id);
+
+ } else
+ gicd_set_icpendr(gicd_base_addr, interrupt_id);
+}
+
+void gicv3_probe_redistif_addr(void)
+{
+ unsigned long long typer_val;
+ uintptr_t rdistif_base;
+ unsigned long long affinity;
+ unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
+
+ assert(gicr_base_addr);
+
+ /*
+ * Return if the re-distributor base address is already populated
+ * for this core.
+ */
+ if (rdist_pcpu_base[core_pos])
+ return;
+
+ /* Iterate over the GICR frames and find the matching frame*/
+ rdistif_base = gicr_base_addr;
+ affinity = gic_typer_affinity_from_mpidr(read_mpidr_el1() & MPIDR_AFFINITY_MASK);
+ do {
+ typer_val = gicr_read_typer(rdistif_base);
+ if (affinity == ((typer_val >> TYPER_AFF_VAL_SHIFT) & TYPER_AFF_VAL_MASK)) {
+ rdist_pcpu_base[core_pos] = rdistif_base;
+ mpidr_list[core_pos] = read_mpidr_el1() & MPIDR_AFFINITY_MASK;
+ return;
+ }
+ rdistif_base += (1 << GICR_PCPUBASE_SHIFT);
+ } while (!(typer_val & TYPER_LAST_BIT));
+
+ ERROR("Re-distributor address not found for core %d\n", core_pos);
+ panic();
+}
+
+void gicv3_setup_distif(void)
+{
+ unsigned int gicd_ctlr;
+
+ assert(gicd_base_addr);
+
+ /* Check for system register support */
+#ifndef AARCH32
+ assert(read_id_aa64pfr0_el1() &
+ (ID_AA64PFR0_GIC_MASK << ID_AA64PFR0_GIC_SHIFT));
+#else
+ assert(read_id_pfr1() & (ID_PFR1_GIC_MASK << ID_PFR1_GIC_SHIFT));
+#endif
+
+ /* Assert that system register access is enabled */
+ assert(is_sre_enabled());
+
+ /* Enable the forwarding of interrupts to CPU interface */
+ gicd_ctlr = gicd_read_ctlr(gicd_base_addr);
+
+ /* Assert ARE_NS bit in GICD */
+ assert(gicd_ctlr & (GICD_CTLR_ARE_NS_MASK << GICD_CTLR_ARE_NS_SHIFT));
+
+ gicd_ctlr |= GICD_CTLR_ENABLE_GRP1A;
+ gicd_write_ctlr(gicd_base_addr, gicd_ctlr);
+}
+
+void gicv3_init(uintptr_t gicr_base, uintptr_t gicd_base)
+{
+ assert(gicr_base);
+ assert(gicd_base);
+
+ gicr_base_addr = gicr_base;
+ gicd_base_addr = gicd_base;
+}
diff --git a/drivers/arm/pl011/aarch32/pl011_console.S b/drivers/arm/pl011/aarch32/pl011_console.S
new file mode 100644
index 0000000..96da6f9
--- /dev/null
+++ b/drivers/arm/pl011/aarch32/pl011_console.S
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <console.h>
+#include <pl011.h>
+
+ .globl console_init
+ .globl console_putc
+ .globl console_getc
+ .globl console_try_getc
+ .globl console_flush
+ .globl console_core_init
+ .globl console_core_putc
+ .globl console_core_getc
+ .globl console_core_flush
+
+ /*
+ * The console base is in the data section and not in .bss
+ * even though it is zero-init. In particular, this allows
+ * the console functions to start using this variable before
+ * the runtime memory is initialized for images which do not
+ * need to copy the .data section from ROM to RAM.
+ */
+ .section .data.console_base
+ .align 2
+console_base: .word 0x0
+
+ /* -----------------------------------------------
+ * int console_init(uintptr_t base_addr,
+ * unsigned int uart_clk, unsigned int baud_rate)
+ * Function to initialize the console without a
+ * C Runtime to print debug information. It saves
+ * the console base to the data section.
+ * In: r0 - Console base address
+ * r1 - Uart clock in Hz
+ * r2 - Baud rate
+ * Out: r0 - Return 1 on success, 0 on error.
+ * Clobber list : r1 - r3
+ * -----------------------------------------------
+ */
+func console_init
+ ldr r3, =console_base
+ str r0, [r3]
+ b console_core_init
+endfunc console_init
+
+ /* -----------------------------------------------
+ * int console_core_init(uintptr_t base_addr,
+ * unsigned int uart_clk, unsigned int baud_rate)
+ * Function to initialize the console without a
+ * C Runtime to print debug information. This
+ * function will be accessed by console_init and
+ * crash reporting.
+ * In: r0 - Console base address
+ * r1 - Uart clock in Hz
+ * r2 - Baud rate
+ * Out: r0 - Return 1 on success, 0 on error.
+ * Clobber list : r1 - r3
+ * -----------------------------------------------
+ */
+func console_core_init
+ /* Check the input base address */
+ cmp r0, #0
+ beq core_init_fail
+ /* Check baud rate and uart clock for sanity */
+ cmp r1, #0
+ beq core_init_fail
+ cmp r2, #0
+ beq core_init_fail
+ /* Disable the UART before initialization */
+ ldr r3, [r0, #UARTCR]
+ bic r3, r3, #PL011_UARTCR_UARTEN
+ str r3, [r0, #UARTCR]
+ /* Program the baudrate */
+ /* Divisor = (Uart clock * 4) / baudrate */
+ lsl r1, r1, #2
+ udiv r2, r1, r2
+ /* IBRD = Divisor >> 6 */
+ lsr r1, r2, #6
+ /* Write the IBRD */
+ str r1, [r0, #UARTIBRD]
+ /* FBRD = Divisor & 0x3F */
+ and r1, r2, #0x3f
+ /* Write the FBRD */
+ str r1, [r0, #UARTFBRD]
+ mov r1, #PL011_LINE_CONTROL
+ str r1, [r0, #UARTLCR_H]
+ /* Clear any pending errors */
+ mov r1, #0
+ str r1, [r0, #UARTECR]
+ /* Enable tx, rx, and uart overall */
+ ldr r1, =(PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN)
+ str r1, [r0, #UARTCR]
+ mov r0, #1
+ bx lr
+core_init_fail:
+ mov r0, #0
+ bx lr
+endfunc console_core_init
+
+ /* ---------------------------------------------
+ * int console_putc(int c)
+ * Function to output a character over the
+ * console. It returns the character printed on
+ * success or an error code.
+ * In : r0 - Character to be printed
+ * Out : r0 - Input character or error code.
+ * Clobber list : r1, r2
+ * ---------------------------------------------
+ */
+func console_putc
+ ldr r1, =console_base
+ ldr r1, [r1]
+ b console_core_putc
+endfunc console_putc
+
+ /* --------------------------------------------------------
+ * int console_core_putc(int c, uintptr_t base_addr)
+ * Function to output a character over the console. It
+ * returns the character printed on success or an error
+ * code.
+ * In : r0 - Character to be printed
+ * r1 - Console base address
+ * Out : r0 - Input character or error code.
+ * Clobber list : r2
+ * --------------------------------------------------------
+ */
+func console_core_putc
+ /* Check the input parameter */
+ cmp r1, #0
+ beq putc_error
+ /* Prepend '\r' to '\n' */
+ cmp r0, #0xA
+ bne 2f
+1:
+ /* Check if the transmit FIFO is full */
+ ldr r2, [r1, #UARTFR]
+ tst r2, #PL011_UARTFR_TXFF
+ bne 1b
+ mov r2, #0xD
+ str r2, [r1, #UARTDR]
+2:
+ /* Check if the transmit FIFO is full */
+ ldr r2, [r1, #UARTFR]
+ tst r2, #PL011_UARTFR_TXFF
+ bne 2b
+
+ /* Only write 8 bits */
+ and r0, r0, #0xFF
+ str r0, [r1, #UARTDR]
+ bx lr
+putc_error:
+ mov r0, #ERROR_NO_VALID_CONSOLE
+ bx lr
+endfunc console_core_putc
+
+ /* ---------------------------------------------
+ * int console_getc(void)
+ * Function to get a character from the console.
+ * It returns the character grabbed on success
+ * or an error code on error. This function is
+ * blocking, it waits until there is an
+ * available character to return.
+ * Out : r0 - Return character or error code.
+ * Clobber list : r0 - r3
+ * ---------------------------------------------
+ */
+func console_getc
+ ldr r2, =console_base
+ ldr r2, [r2]
+ mov r3, lr
+
+ /* Loop until it returns a character or an error. */
+1: mov r0, r2
+ bl console_core_getc
+ cmp r0, #ERROR_NO_PENDING_CHAR
+ beq 1b
+
+ bx r3
+endfunc console_getc
+
+ /* ---------------------------------------------
+ * int console_try_getc(void)
+ * Function to get a character from the console.
+ * It returns the character grabbed on success
+ * or an error code on error. This function is
+ * non-blocking, it returns immediately.
+ * Out : r0 - Return character or error code.
+ * Clobber list : r0, r1
+ * ---------------------------------------------
+ */
+func console_try_getc
+ ldr r0, =console_base
+ ldr r0, [r0]
+ b console_core_getc
+endfunc console_try_getc
+
+ /* ---------------------------------------------
+ * int console_core_getc(uintptr_t base_addr)
+ * Function to get a character from the console.
+ * It returns the character grabbed on success
+ * or an error code.
+ * In : r0 - Console base address
+ * Out : r0 - Return character or error code.
+ * Clobber list : r0, r1
+ * ---------------------------------------------
+ */
+func console_core_getc
+ cmp r0, #0
+ beq getc_error
+
+ /* Check if the receive FIFO is empty */
+ ldr r1, [r0, #UARTFR]
+ tst r1, #PL011_UARTFR_RXFE
+ bne getc_empty
+
+ /* Read a character from the FIFO */
+ ldr r1, [r0, #UARTDR]
+ /* Mask out error flags */
+ and r0, r1, #0xFF
+ bx lr
+
+getc_empty:
+ mov r0, #ERROR_NO_PENDING_CHAR
+ bx lr
+getc_error:
+ mov r0, #ERROR_NO_VALID_CONSOLE
+ bx lr
+endfunc console_core_getc
+
+ /* ---------------------------------------------
+ * int console_flush(void)
+ * Function to force a write of all buffered
+ * data that hasn't been output. It returns 0
+ * upon successful completion, otherwise it
+ * returns an error code.
+ * Out: r0 - Error code or 0.
+ * Clobber list : r0, r1
+ * ---------------------------------------------
+ */
+func console_flush
+ ldr r0, =console_base
+ ldr r0, [r0]
+ b console_core_flush
+endfunc console_flush
+
+ /* ---------------------------------------------
+ * int console_core_flush(uintptr_t base_addr)
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * In : r0 - Console base address
+ * Out : r0 - Error code or 0.
+ * Clobber list : r0, r1
+ * ---------------------------------------------
+ */
+func console_core_flush
+ cmp r0, #0
+ beq flush_error
+
+1:
+ /* Loop while the transmit FIFO is busy */
+ ldr r1, [r0, #UARTFR]
+ tst r1, #PL011_UARTFR_BUSY
+ bne 1b
+
+ mov r0, #0
+ bx lr
+flush_error:
+ mov r0, #ERROR_NO_VALID_CONSOLE
+ bx lr
+endfunc console_core_flush
diff --git a/drivers/arm/pl011/aarch64/pl011_console.S b/drivers/arm/pl011/aarch64/pl011_console.S
new file mode 100644
index 0000000..d87982a
--- /dev/null
+++ b/drivers/arm/pl011/aarch64/pl011_console.S
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <console.h>
+#include <pl011.h>
+
+ .globl console_init
+ .globl console_putc
+ .globl console_getc
+ .globl console_try_getc
+ .globl console_flush
+ .globl console_core_init
+ .globl console_core_putc
+ .globl console_core_getc
+ .globl console_core_flush
+
+ /*
+ * The console base is in the data section and not in .bss
+ * even though it is zero-init. In particular, this allows
+ * the console functions to start using this variable before
+ * the runtime memory is initialized for images which do not
+ * need to copy the .data section from ROM to RAM.
+ */
+ .section .data.console_base
+ .align 3
+console_base: .quad 0x0
+
+ /* -----------------------------------------------
+ * int console_init(uintptr_t base_addr,
+ * unsigned int uart_clk, unsigned int baud_rate)
+ * Function to initialize the console without a
+ * C Runtime to print debug information. It saves
+ * the console base to the data section.
+ * In: x0 - Console base address
+ * w1 - Uart clock in Hz
+ * w2 - Baud rate
+ * Out: w0 - Return 1 on success, 0 on error.
+ * Clobber list : x1 - x3
+ * -----------------------------------------------
+ */
+func console_init
+ adrp x3, console_base
+ str x0, [x3, :lo12:console_base]
+ b console_core_init
+endfunc console_init
+
+ /* -----------------------------------------------
+ * int console_core_init(uintptr_t base_addr,
+ * unsigned int uart_clk, unsigned int baud_rate)
+ * Function to initialize the console without a
+ * C Runtime to print debug information. This
+ * function will be accessed by console_init and
+ * crash reporting.
+ * In: x0 - Console base address
+ * w1 - Uart clock in Hz
+ * w2 - Baud rate
+ * Out: w0 - Return 1 on success, 0 on error.
+ * Clobber list : x1 - x3
+ * -----------------------------------------------
+ */
+func console_core_init
+ /* Check the input base address */
+ cbz x0, init_fail
+ /* Check baud rate and uart clock for sanity */
+ cbz w1, init_fail
+ cbz w2, init_fail
+ /* Disable uart before programming */
+ ldr w3, [x0, #UARTCR]
+ bic w3, w3, #PL011_UARTCR_UARTEN
+ str w3, [x0, #UARTCR]
+ /* Program the baudrate */
+ /* Divisor = (Uart clock * 4) / baudrate */
+ lsl w1, w1, #2
+ udiv w2, w1, w2
+ /* IBRD = Divisor >> 6 */
+ lsr w1, w2, #6
+ /* Write the IBRD */
+ str w1, [x0, #UARTIBRD]
+ /* FBRD = Divisor & 0x3F */
+ and w1, w2, #0x3f
+ /* Write the FBRD */
+ str w1, [x0, #UARTFBRD]
+ mov w1, #PL011_LINE_CONTROL
+ str w1, [x0, #UARTLCR_H]
+ /* Clear any pending errors */
+ str wzr, [x0, #UARTECR]
+ /* Enable tx, rx, and uart overall */
+ mov w1, #(PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN)
+ str w1, [x0, #UARTCR]
+ mov w0, #1
+ ret
+init_fail:
+ mov w0, wzr
+ ret
+endfunc console_core_init
+
+ /* ---------------------------------------------
+ * int console_putc(int c)
+ * Function to output a character over the
+ * console. It returns the character printed on
+ * success or an error code.
+ * In : x0 - Character to be printed
+ * Out : w0 - Input character or error code.
+ * Clobber list : x1, x2
+ * ---------------------------------------------
+ */
+func console_putc
+ adrp x1, console_base
+ ldr x1, [x1, :lo12:console_base]
+ b console_core_putc
+endfunc console_putc
+
+ /* ---------------------------------------------
+ * int console_core_putc(int c, uintptr_t base_addr)
+ * Function to output a character over the console. It
+ * returns the character printed on success or an error
+ * code.
+ * In : w0 - Character to be printed
+ * x1 - Console base address
+ * Out : w0 - Input character or error code.
+ * Clobber list : x2
+ * ---------------------------------------------
+ */
+func console_core_putc
+ /* Check the input parameter */
+ cbz x1, putc_error
+ /* Prepend '\r' to '\n' */
+ cmp w0, #0xA
+ b.ne 2f
+1:
+ /* Check if the transmit FIFO is full */
+ ldr w2, [x1, #UARTFR]
+ tbnz w2, #PL011_UARTFR_TXFF_BIT, 1b
+ mov w2, #0xD
+ str w2, [x1, #UARTDR]
+2:
+ /* Check if the transmit FIFO is full */
+ ldr w2, [x1, #UARTFR]
+ tbnz w2, #PL011_UARTFR_TXFF_BIT, 2b
+
+ /* Only write 8 bits */
+ and w0, w0, #0xFF
+ str w0, [x1, #UARTDR]
+ ret
+putc_error:
+ mov w0, #ERROR_NO_VALID_CONSOLE
+ ret
+endfunc console_core_putc
+
+ /* ---------------------------------------------
+ * int console_getc(void)
+ * Function to get a character from the console.
+ * It returns the character grabbed on success
+ * or an error code on error. This function is
+ * blocking, it waits until there is an
+ * available character to return.
+ * Out : w0 - Return character or error code.
+ * Clobber list : x0 - x3
+ * ---------------------------------------------
+ */
+func console_getc
+ adrp x2, console_base
+ ldr x2, [x2, :lo12:console_base]
+ mov x3, x30
+
+ /* Loop until it returns a character or an error. */
+1: mov x0, x2
+ bl console_core_getc
+ cmp w0, #ERROR_NO_PENDING_CHAR
+ b.eq 1b
+
+ ret x3
+endfunc console_getc
+
+ /* ---------------------------------------------
+ * int console_try_getc(void)
+ * Function to get a character from the console.
+ * It returns the character grabbed on success
+ * or an error code on error. This function is
+ * non-blocking, it returns immediately.
+ * Out : w0 - Return character or error code.
+ * Clobber list : x0, x1
+ * ---------------------------------------------
+ */
+func console_try_getc
+ adrp x0, console_base
+ ldr x0, [x0, :lo12:console_base]
+ b console_core_getc
+endfunc console_try_getc
+
+ /* ---------------------------------------------
+ * int console_core_getc(uintptr_t base_addr)
+ * Function to get a character from the console.
+ * It returns the character grabbed on success
+ * or an error code.
+ * In : x0 - Console base address
+ * Out : w0 - Return character or error code.
+ * Clobber list : x0, x1
+ * ---------------------------------------------
+ */
+func console_core_getc
+ cbz x0, getc_error
+
+ /* Check if the receive FIFO is empty */
+ ldr w1, [x0, #UARTFR]
+ tbnz w1, #PL011_UARTFR_RXFE_BIT, getc_empty
+
+ /* Read a character from the FIFO */
+ ldr w0, [x0, #UARTDR]
+ /* Mask out error flags */
+ and w0, w0, #0xFF
+ ret
+
+getc_empty:
+ mov w0, #ERROR_NO_PENDING_CHAR
+ ret
+getc_error:
+ mov w0, #ERROR_NO_VALID_CONSOLE
+ ret
+endfunc console_core_getc
+
+ /* ---------------------------------------------
+ * int console_flush(void)
+ * Function to force a write of all buffered
+ * data that hasn't been output. It returns 0
+ * upon successful completion, otherwise it
+ * returns an error code.
+ * Out: w0 - Error code or 0.
+ * Clobber list : x0, x1
+ * ---------------------------------------------
+ */
+func console_flush
+ adrp x0, console_base
+ ldr x0, [x0, :lo12:console_base]
+ b console_core_flush
+endfunc console_flush
+
+ /* ---------------------------------------------
+ * int console_core_flush(uintptr_t base_addr)
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * In : x0 - Console base address
+ * Out : w0 - Error code or 0.
+ * Clobber list : x0, x1
+ * ---------------------------------------------
+ */
+func console_core_flush
+ cbz x0, flush_error
+
+1:
+ /* Loop until the transmit FIFO is empty */
+ ldr w1, [x0, #UARTFR]
+ tbnz w1, #PL011_UARTFR_BUSY_BIT, 1b
+
+ mov w0, wzr
+ ret
+flush_error:
+ mov w0, #ERROR_NO_VALID_CONSOLE
+ ret
+endfunc console_core_flush
diff --git a/drivers/arm/sp805/sp805.c b/drivers/arm/sp805/sp805.c
new file mode 100644
index 0000000..72a668d
--- /dev/null
+++ b/drivers/arm/sp805/sp805.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <debug.h>
+#include <mmio.h>
+#include <platform_def.h>
+#include <sp805.h>
+#include <stdint.h>
+
+static inline uint32_t sp805_read_wdog_load(unsigned long base)
+{
+ assert(base);
+ return mmio_read_32(base + SP805_WDOG_LOAD_OFF);
+}
+
+static inline void sp805_write_wdog_load(unsigned long base, uint32_t value)
+{
+ assert(base);
+ mmio_write_32(base + SP805_WDOG_LOAD_OFF, value);
+}
+
+static inline uint32_t sp805_read_wdog_value(unsigned long base)
+{
+ assert(base);
+ return mmio_read_32(base + SP805_WDOG_VALUE_0FF);
+}
+
+static inline uint32_t sp805_read_wdog_ctrl(unsigned long base)
+{
+ assert(base);
+ return mmio_read_32(base + SP805_WDOG_CTRL_OFF) & SP805_WDOG_CTRL_MASK;
+}
+
+static inline void sp805_write_wdog_ctrl(unsigned long base, uint32_t value)
+{
+ assert(base);
+ /* Not setting reserved bits */
+ assert(!(value & ~SP805_WDOG_CTRL_MASK));
+ mmio_write_32(base + SP805_WDOG_CTRL_OFF, value);
+}
+
+static inline void sp805_write_wdog_int_clr(unsigned long base, uint32_t value)
+{
+ assert(base);
+ mmio_write_32(base + SP805_WDOG_INT_CLR_OFF, value);
+}
+
+static inline uint32_t sp805_read_wdog_ris(unsigned long base)
+{
+ assert(base);
+ return mmio_read_32(base + SP805_WDOG_RIS_OFF) & SP805_WDOG_RIS_MASK;
+}
+
+static inline uint32_t sp805_read_wdog_mis(unsigned long base)
+{
+ assert(base);
+ return mmio_read_32(base + SP805_WDOG_MIS_OFF) & SP805_WDOG_MIS_MASK;
+}
+
+static inline uint32_t sp805_read_wdog_lock(unsigned long base)
+{
+ assert(base);
+ return mmio_read_32(base + SP805_WDOG_LOCK_OFF);
+}
+
+static inline void sp805_write_wdog_lock(unsigned long base, uint32_t value)
+{
+ assert(base);
+ mmio_write_32(base + SP805_WDOG_LOCK_OFF, value);
+}
+
+static inline uint32_t sp805_read_wdog_itcr(unsigned long base)
+{
+ assert(base);
+ return mmio_read_32(base + SP805_WDOG_ITCR_OFF) & SP805_WDOG_ITCR_MASK;
+}
+
+static inline void sp805_write_wdog_itcr(unsigned long base, uint32_t value)
+{
+ assert(base);
+ /* Not setting reserved bits */
+ assert(!(value & ~SP805_WDOG_ITCR_MASK));
+ mmio_write_32(base + SP805_WDOG_ITCR_OFF, value);
+}
+
+static inline void sp805_write_wdog_itop(unsigned long base, uint32_t value)
+{
+ assert(base);
+ /* Not setting reserved bits */
+ assert(!(value & ~SP805_WDOG_ITOP_MASK));
+ mmio_write_32(base + SP805_WDOG_ITOP_OFF, value);
+}
+
+static inline uint32_t sp805_read_wdog_periph_id(unsigned long base, unsigned int id)
+{
+ assert(base);
+ assert(id < 4);
+ return mmio_read_32(base + SP805_WDOG_PERIPH_ID_OFF + (id << 2));
+}
+
+static inline uint32_t sp805_read_wdog_pcell_id(unsigned long base, unsigned int id)
+{
+ assert(base);
+ assert(id < 4);
+ return mmio_read_32(base + SP805_WDOG_PCELL_ID_OFF + (id << 2));
+}
+
+void sp805_wdog_start(uint32_t wdog_cycles)
+{
+ /* Unlock to access the watchdog registers */
+ sp805_write_wdog_lock(SP805_WDOG_BASE, SP805_WDOG_UNLOCK_ACCESS);
+
+ /* Write the number of cycles needed */
+ sp805_write_wdog_load(SP805_WDOG_BASE, wdog_cycles);
+
+ /* Enable reset interrupt and watchdog interrupt on expiry */
+ sp805_write_wdog_ctrl(SP805_WDOG_BASE,
+ SP805_WDOG_CTRL_RESEN | SP805_WDOG_CTRL_INTEN);
+
+ /* Lock registers so that they can't be accidently overwritten */
+ sp805_write_wdog_lock(SP805_WDOG_BASE, 0x0);
+}
+
+void sp805_wdog_stop(void)
+{
+ /* Unlock to access the watchdog registers */
+ sp805_write_wdog_lock(SP805_WDOG_BASE, SP805_WDOG_UNLOCK_ACCESS);
+
+ /* Clearing INTEN bit stops the counter */
+ sp805_write_wdog_ctrl(SP805_WDOG_BASE, 0x00);
+
+ /* Lock registers so that they can't be accidently overwritten */
+ sp805_write_wdog_lock(SP805_WDOG_BASE, 0x0);
+}
+
+void sp805_wdog_refresh(void)
+{
+ /* Unlock to access the watchdog registers */
+ sp805_write_wdog_lock(SP805_WDOG_BASE, SP805_WDOG_UNLOCK_ACCESS);
+
+ /*
+ * Write of any value to WdogIntClr clears interrupt and reloads
+ * the counter from the value in WdogLoad Register.
+ */
+ sp805_write_wdog_int_clr(SP805_WDOG_BASE, 1);
+
+ /* Lock registers so that they can't be accidently overwritten */
+ sp805_write_wdog_lock(SP805_WDOG_BASE, 0x0);
+}
diff --git a/drivers/arm/timer/private_timer.c b/drivers/arm/timer/private_timer.c
new file mode 100644
index 0000000..c629448
--- /dev/null
+++ b/drivers/arm/timer/private_timer.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <platform.h>
+
+/*******************************************************************************
+ * Data structure to keep track of per-cpu secure generic timer context across
+ * power management operations.
+ ******************************************************************************/
+typedef struct timer_context {
+ uint64_t cval;
+ uint32_t ctl;
+} timer_context_t;
+
+static timer_context_t pcpu_timer_context[PLATFORM_CORE_COUNT];
+
+/*******************************************************************************
+ * This function initializes the generic timer to fire every `timeo` ms.
+ ******************************************************************************/
+void private_timer_start(unsigned long timeo)
+{
+ uint64_t cval, freq;
+ uint32_t ctl = 0;
+
+ /* Any previous pending timer activation will be disabled. */
+ cval = read_cntpct_el0();
+ freq = read_cntfrq_el0();
+ cval += (freq * timeo) / 1000;
+ write_cnthp_cval_el2(cval);
+
+ /* Enable the secure physical timer */
+ set_cntp_ctl_enable(ctl);
+ write_cnthp_ctl_el2(ctl);
+}
+
+/*******************************************************************************
+ * This function deasserts the timer interrupt prior to cpu power down
+ ******************************************************************************/
+void private_timer_stop(void)
+{
+ /* Disable the timer */
+ write_cnthp_ctl_el2(0);
+}
+
+/*******************************************************************************
+ * This function saves the timer context prior to cpu suspension
+ ******************************************************************************/
+void private_timer_save(void)
+{
+ uint32_t linear_id = platform_get_core_pos(read_mpidr_el1());
+
+ pcpu_timer_context[linear_id].cval = read_cnthp_cval_el2();
+ pcpu_timer_context[linear_id].ctl = read_cnthp_ctl_el2();
+ flush_dcache_range((uintptr_t) &pcpu_timer_context[linear_id],
+ sizeof(pcpu_timer_context[linear_id]));
+}
+
+/*******************************************************************************
+ * This function restores the timer context post cpu resummption
+ ******************************************************************************/
+void private_timer_restore(void)
+{
+ uint32_t linear_id = platform_get_core_pos(read_mpidr_el1());
+
+ write_cnthp_cval_el2(pcpu_timer_context[linear_id].cval);
+ write_cnthp_ctl_el2(pcpu_timer_context[linear_id].ctl);
+}
diff --git a/drivers/arm/timer/sp804.c b/drivers/arm/timer/sp804.c
new file mode 100644
index 0000000..de88cda
--- /dev/null
+++ b/drivers/arm/timer/sp804.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <arm_gic.h>
+#include <assert.h>
+#include <gic_v2.h>
+#include <mmio.h>
+#include <sp804.h>
+
+static unsigned int sp804_freq;
+static uintptr_t sp804_base;
+
+int sp804_timer_program(unsigned long time_out_ms)
+{
+ unsigned int load_val;
+ unsigned char ctrl_reg;
+
+ assert(sp804_base);
+ assert(time_out_ms);
+
+ /* Disable the timer */
+ ctrl_reg = mmio_read_8(sp804_base + SP804_CTRL_OFFSET);
+ ctrl_reg &= ~(TIMER_EN | INT_ENABLE);
+ mmio_write_8(sp804_base + SP804_CTRL_OFFSET, ctrl_reg);
+
+ /* Calculate the load value */
+ load_val = (sp804_freq * time_out_ms) / 1000;
+
+ /* Write the load value to sp804 timer */
+ mmio_write_32(sp804_base + SP804_LOAD_OFFSET, load_val);
+
+ /* Enable the timer */
+ ctrl_reg |= (TIMER_EN | INT_ENABLE);
+ mmio_write_8(sp804_base + SP804_CTRL_OFFSET, ctrl_reg);
+
+ return 0;
+}
+
+static void sp804_timer_disable(void)
+{
+ unsigned char ctrl_reg;
+
+ /*
+ * The interrupt line should be cleared prior to timer disable.
+ * Otherwise the interrupt line level decay from high to quiescent
+ * level is not quick enough which may trigger spurious interrupt.
+ * Write a dummy load value to sp804 timer to clear the interrupt.
+ */
+ mmio_write_32(sp804_base + SP804_LOAD_OFFSET, 0xffff);
+
+ /* De-assert the timer interrupt */
+ mmio_write_8(sp804_base + SP804_INT_CLR_OFFSET, 0x0);
+
+ /* Disable the timer */
+ ctrl_reg = mmio_read_8(sp804_base + SP804_CTRL_OFFSET);
+ ctrl_reg &= ~(TIMER_EN | INT_ENABLE);
+ mmio_write_8(sp804_base + SP804_CTRL_OFFSET, ctrl_reg);
+}
+
+int sp804_timer_cancel(void)
+{
+ assert(sp804_base);
+ sp804_timer_disable();
+ return 0;
+}
+
+int sp804_timer_handler(void)
+{
+ assert(sp804_base);
+ sp804_timer_disable();
+ return 0;
+}
+
+int sp804_timer_init(uintptr_t base_addr, unsigned int timer_freq)
+{
+ unsigned char ctrl_reg;
+
+ /* Check input parameters */
+ assert(base_addr && timer_freq);
+
+ /* Check for duplicate initialization */
+ assert(sp804_base == 0);
+
+ sp804_base = base_addr;
+ sp804_freq = timer_freq;
+
+ /*
+ * Configure the timer in one shot mode, pre-scalar divider to 1,
+ * timer counter width to 32 bits and un-mask the interrupt.
+ */
+ ctrl_reg = ONESHOT_MODE | TIMER_PRE_DIV1 | TIMER_SIZE;
+ mmio_write_8(sp804_base + SP804_CTRL_OFFSET, ctrl_reg);
+
+ return 0;
+}
diff --git a/drivers/arm/timer/system_timer.c b/drivers/arm/timer/system_timer.c
new file mode 100644
index 0000000..3415e41
--- /dev/null
+++ b/drivers/arm/timer/system_timer.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <arm_gic.h>
+#include <assert.h>
+#include <debug.h>
+#include <gic_v2.h>
+#include <irq.h>
+#include <mmio.h>
+#include <system_timer.h>
+
+static uintptr_t g_systimer_base;
+
+int program_systimer(unsigned long time_out_ms)
+{
+ unsigned int cntp_ctl;
+ unsigned long long count_val;
+ unsigned int freq;
+
+ /* Check timer base is initialised */
+ assert(g_systimer_base);
+
+ count_val = mmio_read_64(g_systimer_base + CNTPCT_LO);
+ freq = read_cntfrq_el0();
+ count_val += (freq * time_out_ms) / 1000;
+ mmio_write_64(g_systimer_base + CNTP_CVAL_LO, count_val);
+
+ /* Enable the timer */
+ cntp_ctl = mmio_read_32(g_systimer_base + CNTP_CTL);
+ set_cntp_ctl_enable(cntp_ctl);
+ clr_cntp_ctl_imask(cntp_ctl);
+ mmio_write_32(g_systimer_base + CNTP_CTL, cntp_ctl);
+
+ /*
+ * Ensure that we have programmed a timer interrupt for a time in
+ * future. Else we will have to wait for the systimer to rollover
+ * for the interrupt to fire (which is 64 years).
+ */
+ if (count_val < mmio_read_64(g_systimer_base + CNTPCT_LO))
+ panic();
+
+ VERBOSE("%s : interrupt requested at sys_counter: %lld "
+ "time_out_ms: %ld\n", __func__, count_val, time_out_ms);
+
+ return 0;
+}
+
+static void disable_systimer(void)
+{
+ uint32_t val;
+
+ /* Check timer base is initialised */
+ assert(g_systimer_base);
+
+ /* Deassert and disable the timer interrupt */
+ val = 0;
+ set_cntp_ctl_imask(val);
+ mmio_write_32(g_systimer_base + CNTP_CTL, val);
+}
+
+int cancel_systimer(void)
+{
+ disable_systimer();
+ return 0;
+}
+
+int handler_systimer(void)
+{
+ disable_systimer();
+ return 0;
+}
+
+int init_systimer(uintptr_t systimer_base)
+{
+ /* Check timer base is not initialised */
+ assert(!g_systimer_base);
+
+ g_systimer_base = systimer_base;
+
+ /* Disable the timer as the reset value is unknown */
+ disable_systimer();
+
+ /* Initialise CVAL to zero */
+ mmio_write_64(g_systimer_base + CNTP_CVAL_LO, 0);
+
+ return 0;
+}