feat(interrupts): add support for GICv3 controller

Most of the source code is taken from trustedfirmware-a project and
put in gicv3_helpers.h; We made some changes to fit to hafnium project

Moreover, TF-A(BL31) also configures GIC Distributor, Redistributor and
GIC CPU interfaces while booting CPUs. Hence, many of the configuration
steps are skipped in the current GICv3 driver implementation.

Change-Id: Ie17ab7c65578866a56fa054cd1fea9cd6a0f32a4
Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
diff --git a/src/arch/aarch64/plat/interrupts/gicv3.c b/src/arch/aarch64/plat/interrupts/gicv3.c
index e53ba6c..d48dd2b 100644
--- a/src/arch/aarch64/plat/interrupts/gicv3.c
+++ b/src/arch/aarch64/plat/interrupts/gicv3.c
@@ -6,24 +6,480 @@
  * https://opensource.org/licenses/BSD-3-Clause.
  */
 
+#include "hf/cpu.h"
+#include "hf/dlog.h"
+#include "hf/interrupt_desc.h"
+#include "hf/io.h"
+#include "hf/panic.h"
 #include "hf/plat/interrupts.h"
+#include "hf/static_assert.h"
 #include "hf/types.h"
 
+#include "gicv3_helpers.h"
 #include "msr.h"
 
+#define GICD_SIZE (0x10000)
+#define GICV3_REDIST_SIZE_PER_PE (0x20000) /* 128 KB */
+
+#define REDIST_LAST_FRAME_MASK (1 << 4)
+#define GICV3_REDIST_FRAMES_OFFSET GICV3_REDIST_SIZE_PER_PE
+
+struct gicv3_driver {
+	uintptr_t dist_base;
+	uintptr_t base_redist_frame;
+	uintptr_t all_redist_frames[MAX_CPUS];
+	struct spinlock lock;
+};
+
+static struct gicv3_driver plat_gicv3_driver;
+
+static uint32_t affinity_to_core_id(uint64_t reg)
+{
+	struct cpu *this_cpu;
+
+	this_cpu = cpu_find(reg & MPIDR_AFFINITY_MASK);
+
+	CHECK(this_cpu != NULL);
+
+	return cpu_index(this_cpu);
+}
+
+/**
+ * This function checks the interrupt ID and returns true for SGIs and (E)PPIs
+ * and false for (E)SPIs IDs.
+ */
+static bool is_sgi_ppi(uint32_t id)
+{
+	/* SGIs: 0-15, PPIs: 16-31, EPPIs: 1056-1119. */
+	if (IS_SGI_PPI(id)) {
+		return true;
+	}
+
+	/* SPIs: 32-1019, ESPIs: 4096-5119. */
+	if (IS_SPI(id)) {
+		return false;
+	}
+
+	CHECK(false);
+	return false;
+}
+
+/**
+ * This function returns the id of the highest priority pending interrupt at
+ * the GIC cpu interface.
+ */
+uint32_t gicv3_get_pending_interrupt_id(void)
+{
+	return (uint32_t)read_msr(ICC_IAR1_EL1) & IAR1_EL1_INTID_MASK;
+}
+
+/**
+ * This function returns the type of the interrupt id depending on the group
+ * this interrupt has been configured under by the interrupt controller i.e.
+ * group1 Secure / group1 Non Secure. The return value can be one of the
+ * following :
+ *    INTR_GROUP1S : The interrupt type is a Secure Group 1 secure interrupt.
+ *    INTR_GROUP1NS: The interrupt type is a Secure Group 1 non secure
+ *                   interrupt.
+ */
+uint32_t gicv3_get_interrupt_type(uint32_t id, uint32_t proc_num)
+{
+	uint32_t igroup;
+	uint32_t grpmodr;
+	uintptr_t gicr_base;
+
+	/* Ensure the parameters are valid. */
+	CHECK((id < PENDING_G1S_INTID) || (id >= MIN_LPI_ID));
+	CHECK(proc_num < MAX_CPUS);
+
+	/* All LPI interrupts are Group 1 non secure. */
+	if (id >= MIN_LPI_ID) {
+		return INTR_GROUP1NS;
+	}
+
+	/* Check interrupt ID. */
+	if (is_sgi_ppi(id)) {
+		/* SGIs: 0-15, PPIs: 16-31, EPPIs: 1056-1119. */
+		gicr_base = plat_gicv3_driver.all_redist_frames[proc_num];
+		igroup = gicr_get_igroupr(gicr_base, id);
+		grpmodr = gicr_get_igrpmodr(gicr_base, id);
+	} else {
+		/* SPIs: 32-1019, ESPIs: 4096-5119. */
+		igroup = gicd_get_igroupr(plat_gicv3_driver.dist_base, id);
+		grpmodr = gicd_get_igrpmodr(plat_gicv3_driver.dist_base, id);
+	}
+
+	/*
+	 * If the IGROUP bit is set, then it is a Group 1 Non secure
+	 * interrupt.
+	 */
+	if (igroup != 0U) {
+		return INTR_GROUP1NS;
+	}
+
+	/* If the GRPMOD bit is set, then it is a Group 1 Secure interrupt. */
+	if (grpmodr != 0U) {
+		return INTR_GROUP1S;
+	}
+
+	CHECK(false);
+}
+
+/**
+ * This function enables the interrupt identified by id. The proc_num
+ * is used if the interrupt is SGI or PPI, and programs the corresponding
+ * Redistributor interface.
+ */
+void gicv3_enable_interrupt(uint32_t id, uint32_t proc_num)
+{
+	CHECK(plat_gicv3_driver.dist_base != 0U);
+	CHECK(plat_gicv3_driver.base_redist_frame != 0U);
+	CHECK(proc_num < MAX_CPUS);
+
+	/*
+	 * Ensure that any shared variable updates depending on out of band
+	 * interrupt trigger are observed before enabling interrupt.
+	 */
+	dsb(ish);
+
+	/* Check interrupt ID. */
+	if (is_sgi_ppi(id)) {
+		/* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119. */
+		gicr_set_isenabler(
+			plat_gicv3_driver.all_redist_frames[proc_num], id);
+	} else {
+		/* For SPIs: 32-1019 and ESPIs: 4096-5119. */
+		gicd_set_isenabler(plat_gicv3_driver.dist_base, id);
+	}
+}
+
+/**
+ * This function disables the interrupt identified by id. The proc_num
+ * is used if the interrupt is SGI or PPI, and programs the corresponding
+ * Redistributor interface.
+ */
+void gicv3_disable_interrupt(uint32_t id, uint32_t proc_num)
+{
+	CHECK(plat_gicv3_driver.dist_base != 0U);
+	CHECK(plat_gicv3_driver.base_redist_frame != 0U);
+	CHECK(proc_num < MAX_CPUS);
+
+	/*
+	 * Disable interrupt, and ensure that any shared variable updates
+	 * depending on out of band interrupt trigger are observed afterwards.
+	 */
+
+	/* Check interrupt ID. */
+	if (is_sgi_ppi(id)) {
+		/* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119. */
+		gicr_set_icenabler(
+			plat_gicv3_driver.all_redist_frames[proc_num], id);
+
+		/* Write to clear enable requires waiting for pending writes. */
+		gicr_wait_for_pending_write(
+			plat_gicv3_driver.all_redist_frames[proc_num]);
+	} else {
+		/* For SPIs: 32-1019 and ESPIs: 4096-5119. */
+		gicd_set_icenabler(plat_gicv3_driver.dist_base, id);
+
+		/* Write to clear enable requires waiting for pending writes. */
+		gicd_wait_for_pending_write(plat_gicv3_driver.dist_base);
+	}
+
+	dsb(ish);
+}
+
+/**
+ * This function sets the interrupt priority as supplied for the given interrupt
+ * id.
+ */
+void gicv3_set_interrupt_priority(uint32_t id, uint32_t core_pos,
+				  uint32_t priority)
+{
+	uintptr_t gicr_base;
+
+	/* Core index cannot exceed maximum core count. */
+	CHECK(core_pos < MAX_CPUS);
+
+	/* Check interrupt ID. */
+	if (is_sgi_ppi(id)) {
+		/* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119. */
+		gicr_base = plat_gicv3_driver.all_redist_frames[core_pos];
+		gicr_set_ipriorityr(gicr_base, id, priority);
+	} else {
+		/* For SPIs: 32-1019 and ESPIs: 4096-5119. */
+		gicd_set_ipriorityr(plat_gicv3_driver.dist_base, id, priority);
+	}
+}
+
+/**
+ * This function assigns group for the interrupt identified by id. The proc_num
+ * is used if the interrupt is SGI or (E)PPI, and programs the corresponding
+ * Redistributor interface. The group can be any of GICV3_INTR_GROUP*.
+ */
+void gicv3_set_interrupt_type(uint32_t id, uint32_t proc_num, uint32_t type)
+{
+	bool igroup = false;
+	bool grpmod = false;
+	uintptr_t gicr_base;
+
+	CHECK(plat_gicv3_driver.dist_base != 0U);
+	CHECK(proc_num < MAX_CPUS);
+
+	switch (type) {
+	case INTR_GROUP1S:
+		igroup = false;
+		grpmod = true;
+		break;
+	case INTR_GROUP1NS:
+		igroup = true;
+		grpmod = false;
+		break;
+	default:
+		CHECK(false);
+		break;
+	}
+
+	/* Check interrupt ID. */
+	if (is_sgi_ppi(id)) {
+		/* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119. */
+		gicr_base = plat_gicv3_driver.all_redist_frames[proc_num];
+
+		igroup ? gicr_set_igroupr(gicr_base, id)
+		       : gicr_clr_igroupr(gicr_base, id);
+		grpmod ? gicr_set_igrpmodr(gicr_base, id)
+		       : gicr_clr_igrpmodr(gicr_base, id);
+	} else {
+		/* For SPIs: 32-1019 and ESPIs: 4096-5119. */
+
+		/* Serialize read-modify-write to Distributor registers. */
+		sl_lock(&plat_gicv3_driver.lock);
+
+		igroup ? gicd_set_igroupr(plat_gicv3_driver.dist_base, id)
+		       : gicd_clr_igroupr(plat_gicv3_driver.dist_base, id);
+		grpmod ? gicd_set_igrpmodr(plat_gicv3_driver.dist_base, id)
+		       : gicd_clr_igrpmodr(plat_gicv3_driver.dist_base, id);
+
+		sl_unlock(&plat_gicv3_driver.lock);
+	}
+}
+
+void gicv3_end_of_interrupt(uint32_t id)
+{
+	/*
+	 * Interrupt request deassertion from peripheral to GIC happens
+	 * by clearing interrupt condition by a write to the peripheral
+	 * register. It is desired that the write transfer is complete
+	 * before the core tries to change GIC state from 'AP/Active' to
+	 * a new state on seeing 'EOI write'.
+	 * Since ICC interface writes are not ordered against Device
+	 * memory writes, a barrier is required to ensure the ordering.
+	 * The dsb will also ensure *completion* of previous writes with
+	 * DEVICE nGnRnE attribute.
+	 */
+	dsb(ish);
+	write_msr(ICC_EOIR1_EL1, id);
+}
+
+uint64_t read_gicr_typer_reg(uintptr_t gicr_frame_addr)
+{
+	return io_read64(IO64_C(gicr_frame_addr + GICR_TYPER));
+}
+
+static inline uint32_t gicr_affinity_to_core_pos(uint64_t typer_reg)
+{
+	uint64_t aff3;
+	uint64_t aff2;
+	uint64_t aff1;
+	uint64_t aff0;
+	uint64_t reg;
+
+	aff3 = (typer_reg >> RDIST_AFF3_SHIFT) & (0xff);
+	aff2 = (typer_reg >> RDIST_AFF2_SHIFT) & (0xff);
+	aff1 = (typer_reg >> RDIST_AFF1_SHIFT) & (0xff);
+	aff0 = (typer_reg >> RDIST_AFF0_SHIFT) & (0xff);
+
+	/* Construct mpidr based on above affinities. */
+	reg = (aff3 << MPIDR_AFF3_SHIFT) | (aff2 << MPIDR_AFF2_SHIFT) |
+	      (aff1 << MPIDR_AFF1_SHIFT) | (aff0 << MPIDR_AFF0_SHIFT);
+
+	return affinity_to_core_id(reg);
+}
+
+static inline void populate_redist_base_addrs(void)
+{
+	uintptr_t current_rdist_frame;
+	uint64_t typer_reg;
+	uint32_t core_idx;
+
+	current_rdist_frame = plat_gicv3_driver.base_redist_frame;
+
+	while (true) {
+		typer_reg = read_gicr_typer_reg(current_rdist_frame);
+		core_idx = gicr_affinity_to_core_pos(typer_reg);
+
+		CHECK(core_idx < MAX_CPUS);
+		plat_gicv3_driver.all_redist_frames[core_idx] =
+			current_rdist_frame;
+
+		/* Check if this is the last frame. */
+		if (typer_reg & REDIST_LAST_FRAME_MASK) {
+			return;
+		}
+
+		current_rdist_frame += GICV3_REDIST_FRAMES_OFFSET;
+	}
+}
+
+static uint32_t find_core_pos(void)
+{
+	uint64_t mpidr_reg;
+
+	mpidr_reg = read_msr(MPIDR_EL1);
+
+	return affinity_to_core_id(mpidr_reg);
+}
+
+/**
+ * Currently, TF-A has complete access to GIC driver and configures
+ * GIC Distributor, GIC Re-distributor and CPU interfaces as needed.
+ */
+void gicv3_distif_init(void)
+{
+	/* TODO: Currently, we skip this. */
+	return;
+
+	/* Enable G1S and G1NS interrupts. */
+	gicd_write_ctlr(
+		plat_gicv3_driver.dist_base,
+		CTLR_ENABLE_G1NS_BIT | CTLR_ENABLE_G1S_BIT | CTLR_ARE_S_BIT);
+}
+
+void gicv3_rdistif_init(uint32_t core_pos)
+{
+	/* TODO: Currently, we skip this. */
+	(void)core_pos;
+}
+
+void gicv3_cpuif_enable(uint32_t core_pos)
+{
+	/* TODO: Currently, we skip this. */
+	(void)core_pos;
+}
+
+void gicv3_send_sgi(uint32_t sgi_id, bool send_to_all, uint32_t target_list,
+		    bool to_this_security_state)
+{
+	uint64_t sgir;
+	uint64_t irm;
+	uint64_t mpidr_reg;
+
+	CHECK(is_sgi_ppi(sgi_id));
+
+	mpidr_reg = read_msr(MPIDR_EL1);
+	sgir = (sgi_id & SGIR_INTID_MASK) << SGIR_INTID_SHIFT;
+
+	/* Check the interrupt routing mode. */
+	if (send_to_all) {
+		irm = 1;
+	} else {
+		irm = 0;
+
+		/*
+		 * Find the affinity path of the PE for which SGI will be
+		 * generated.
+		 */
+
+		uint64_t aff1;
+		uint64_t aff2;
+		uint64_t aff3;
+
+		/*
+		 * Target List is a one hot encoding representing which cores
+		 * will be delivered the interrupt. At least one has to be
+		 * enabled.
+		 */
+
+		CHECK(target_list != 0U);
+
+		aff3 = (mpidr_reg >> MPIDR_AFF3_SHIFT) & (0xff);
+		aff2 = (mpidr_reg >> MPIDR_AFF2_SHIFT) & (0xff);
+		aff1 = (mpidr_reg >> MPIDR_AFF1_SHIFT) & (0xff);
+
+		/* Populate the various affinity fields. */
+		sgir |= ((aff3 & SGIR_AFF_MASK) << SGIR_AFF3_SHIFT) |
+			((aff2 & SGIR_AFF_MASK) << SGIR_AFF2_SHIFT) |
+			((aff1 & SGIR_AFF_MASK) << SGIR_AFF1_SHIFT);
+
+		/* Construct the SGI target affinity. */
+		sgir |= (target_list & SGIR_TGT_MASK) << SGIR_TGT_SHIFT;
+	}
+
+	/* Populate the Interrupt Routing Mode field. */
+	sgir |= (irm & SGIR_IRM_MASK) << SGIR_IRM_SHIFT;
+
+	if (to_this_security_state) {
+		write_msr(ICC_SGI1R_EL1, sgir);
+	} else {
+		write_msr(ICC_ASGI1R_EL1, sgir);
+	}
+
+	isb();
+}
+
+bool gicv3_driver_init(struct mm_stage1_locked stage1_locked,
+		       struct mpool *ppool)
+{
+	void *base_addr;
+
+	base_addr = mm_identity_map(stage1_locked, pa_init(GICD_BASE),
+				    pa_init(GICD_BASE + GICD_SIZE),
+				    MM_MODE_R | MM_MODE_W | MM_MODE_D, ppool);
+	if (base_addr == NULL) {
+		dlog_error("Could not map GICv3 into Hafnium memory map\n");
+		return false;
+	}
+
+	plat_gicv3_driver.dist_base = (uintptr_t)base_addr;
+
+	base_addr = mm_identity_map(
+		stage1_locked, pa_init(GICR_BASE),
+		pa_init(GICR_BASE + MAX_CPUS * GICV3_REDIST_SIZE_PER_PE),
+		MM_MODE_R | MM_MODE_W | MM_MODE_D, ppool);
+
+	if (base_addr == NULL) {
+		dlog_error("Could not map GICv3 into Hafnium memory map\n");
+		return false;
+	}
+
+	plat_gicv3_driver.base_redist_frame = (uintptr_t)base_addr;
+
+	populate_redist_base_addrs();
+
+	return true;
+}
+
 bool plat_interrupts_controller_driver_init(
 	const struct fdt *fdt, struct mm_stage1_locked stage1_locked,
 	struct mpool *ppool)
 {
 	(void)fdt;
-	(void)stage1_locked;
-	(void)ppool;
+
+	if (!gicv3_driver_init(stage1_locked, ppool)) {
+		dlog_error("Failed to initialize GICv3 driver\n");
+		return false;
+	}
+
+	gicv3_distif_init();
+	gicv3_rdistif_init(find_core_pos());
+
 	return true;
 }
 
 void plat_interrupts_controller_hw_init(struct cpu *c)
 {
 	(void)c;
+	gicv3_cpuif_enable(find_core_pos());
 }
 
 void plat_interrupts_set_priority_mask(uint8_t min_priority)
@@ -31,7 +487,100 @@
 	write_msr(ICC_PMR_EL1, min_priority);
 }
 
+uint8_t plat_interrupts_get_priority_mask(void)
+{
+	return read_msr(ICC_PMR_EL1);
+}
+
+void plat_interrupts_set_priority(uint32_t id, uint32_t core_pos,
+				  uint32_t priority)
+{
+	gicv3_set_interrupt_priority(id, core_pos, priority);
+}
+
+void plat_interrupts_enable(uint32_t id, uint32_t core_pos)
+{
+	gicv3_enable_interrupt(id, core_pos);
+}
+
+void plat_interrupts_disable(uint32_t id, uint32_t core_pos)
+{
+	gicv3_disable_interrupt(id, core_pos);
+}
+
+void plat_interrupts_set_type(uint32_t id, uint32_t type)
+{
+	gicv3_set_interrupt_type(id, find_core_pos(), type);
+}
+
+uint32_t plat_interrupts_get_type(uint32_t id)
+{
+	return gicv3_get_interrupt_type(id, find_core_pos());
+}
+
+uint32_t plat_interrupts_get_pending_interrupt_id(void)
+{
+	return gicv3_get_pending_interrupt_id();
+}
+
+void plat_interrupts_end_of_interrupt(uint32_t id)
+{
+	gicv3_end_of_interrupt(id);
+}
+
+/**
+ * Configure Group, priority, edge/level of the interrupt and enable it.
+ */
 void plat_interrupts_configure_interrupt(struct interrupt_descriptor int_desc)
 {
-	(void)int_desc;
+	uint32_t core_idx = find_core_pos();
+	uint32_t level_cfg = 0U;
+	uint32_t intr_num = interrupt_desc_get_id(int_desc);
+
+	CHECK(core_idx < MAX_CPUS);
+
+	/* Configure the interrupt as either G1S or G1NS. */
+	if (interrupt_desc_get_sec_state(int_desc) != 0) {
+		gicv3_set_interrupt_type(intr_num, core_idx, INTR_GROUP1S);
+	} else {
+		gicv3_set_interrupt_type(intr_num, core_idx, INTR_GROUP1NS);
+	}
+
+	/* Program the interrupt priority. */
+	gicv3_set_interrupt_priority(intr_num, core_idx,
+				     interrupt_desc_get_priority(int_desc));
+
+	if (interrupt_desc_get_config(int_desc) != 0) {
+		level_cfg = 1U;
+	}
+
+	/* Set interrupt configuration. */
+	if (is_sgi_ppi(intr_num)) {
+		/* GICR interface. */
+		gicr_set_icfgr(plat_gicv3_driver.all_redist_frames[core_idx],
+			       intr_num, level_cfg);
+	} else {
+		/* GICD interface. */
+		gicd_set_icfgr(plat_gicv3_driver.dist_base, intr_num,
+			       level_cfg);
+	}
+
+	/* Target SPI to primary CPU using affinity routing. */
+	if (IS_SPI(intr_num)) {
+		uint64_t gic_affinity_val;
+
+		gic_affinity_val =
+			gicd_irouter_val_from_mpidr(read_msr(MPIDR_EL1), 0U);
+		gicd_write_irouter(plat_gicv3_driver.dist_base, intr_num,
+				   gic_affinity_val);
+	}
+
+	/* Enable the interrupt now. */
+	gicv3_enable_interrupt(intr_num, core_idx);
+}
+
+void plat_interrupts_send_sgi(uint32_t id, bool send_to_all,
+			      uint32_t target_list, bool to_this_security_state)
+{
+	gicv3_send_sgi(id, send_to_all, target_list, to_this_security_state);
 }
diff --git a/src/arch/aarch64/plat/interrupts/gicv3_helpers.h b/src/arch/aarch64/plat/interrupts/gicv3_helpers.h
new file mode 100644
index 0000000..562e3a6
--- /dev/null
+++ b/src/arch/aarch64/plat/interrupts/gicv3_helpers.h
@@ -0,0 +1,609 @@
+/*
+ * Copyright 2021 The Hafnium Authors.
+ *
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/BSD-3-Clause.
+ */
+
+#include "hf/cpu.h"
+#include "hf/dlog.h"
+#include "hf/io.h"
+#include "hf/panic.h"
+#include "hf/plat/interrupts.h"
+#include "hf/static_assert.h"
+#include "hf/types.h"
+
+#include "msr.h"
+
+#define BIT_32(nr) (UINT32_C(1) << (nr))
+
+#define MPIDR_AFFINITY_MASK (0xff00ffffff)
+#define MPIDR_AFFLVL_MASK (0xff)
+#define MPIDR_AFF0_SHIFT (0)
+#define MPIDR_AFF1_SHIFT (8)
+#define MPIDR_AFF2_SHIFT (16)
+#define MPIDR_AFF3_SHIFT (32)
+#define RDIST_AFF3_SHIFT (56)
+#define RDIST_AFF2_SHIFT (48)
+#define RDIST_AFF1_SHIFT (40)
+#define RDIST_AFF0_SHIFT (32)
+
+/* Mask for the configuration field common to all GIC interfaces */
+#define GIC_CFG_MASK (0x3)
+
+/**
+ * Common GIC Distributor interface register offsets
+ */
+#define GICD_CTLR (0x0)
+#define GICD_TYPER (0x4)
+#define GICD_IIDR (0x8)
+#define GICD_IGROUPR (0x80)
+#define GICD_ISENABLER (0x100)
+#define GICD_ICENABLER (0x180)
+#define GICD_ISPENDR (0x200)
+#define GICD_ICPENDR (0x280)
+#define GICD_ISACTIVER (0x300)
+#define GICD_ICACTIVER (0x380)
+#define GICD_IPRIORITYR (0x400)
+#define GICD_ICFGR (0xc00)
+#define GICD_NSACR (0xe00)
+
+/* GICD_CTLR bit definitions */
+#define CTLR_ENABLE_G0_SHIFT 0
+#define CTLR_ENABLE_G0_MASK (0x1)
+#define CTLR_ENABLE_G0_BIT BIT_32(CTLR_ENABLE_G0_SHIFT)
+
+#define IGROUPR_SHIFT 5
+#define ISENABLER_SHIFT 5
+#define ICENABLER_SHIFT ISENABLER_SHIFT
+#define ISPENDR_SHIFT 5
+#define ICPENDR_SHIFT ISPENDR_SHIFT
+#define ISACTIVER_SHIFT 5
+#define ICACTIVER_SHIFT ISACTIVER_SHIFT
+#define IPRIORITYR_SHIFT 2
+#define ITARGETSR_SHIFT 2
+#define ICFGR_SHIFT 4
+#define NSACR_SHIFT 4
+
+#define GIC_PRI_MASK (0xff)
+
+/**
+ * GICv3 and 3.1 specific Distributor interface register offsets and constants
+ */
+#define GICD_TYPER2 (0x0c)
+#define GICD_STATUSR (0x10)
+#define GICD_SETSPI_NSR (0x40)
+#define GICD_CLRSPI_NSR (0x48)
+#define GICD_SETSPI_SR (0x50)
+#define GICD_CLRSPI_SR (0x58)
+#define GICD_IGRPMODR (0xd00)
+#define GICD_IGROUPRE (0x1000)
+#define GICD_ISENABLERE (0x1200)
+#define GICD_ICENABLERE (0x1400)
+#define GICD_ISPENDRE (0x1600)
+#define GICD_ICPENDRE (0x1800)
+#define GICD_ISACTIVERE (0x1a00)
+#define GICD_ICACTIVERE (0x1c00)
+#define GICD_IPRIORITYRE (0x2000)
+#define GICD_ICFGRE (0x3000)
+#define GICD_IGRPMODRE (0x3400)
+#define GICD_NSACRE (0x3600)
+
+/**
+ * GICD_IROUTER<n> register is at 0x6000 + 8n, where n is the interrupt ID
+ * and n >= 32, making the effective offset as 0x6100
+ */
+#define GICD_IROUTER (0x6000)
+#define GICD_IROUTERE (0x8000)
+
+#define GICD_PIDR2_GICV3 (0xffe8)
+
+#define IGRPMODR_SHIFT 5
+
+/* GICD_CTLR bit definitions */
+#define CTLR_ENABLE_G1NS_SHIFT 1
+#define CTLR_ENABLE_G1S_SHIFT 2
+#define CTLR_ARE_S_SHIFT 4
+#define CTLR_ARE_NS_SHIFT 5
+#define CTLR_DS_SHIFT 6
+#define CTLR_E1NWF_SHIFT 7
+#define GICD_CTLR_RWP_SHIFT 31
+
+#define CTLR_ENABLE_G1NS_MASK (0x1)
+#define CTLR_ENABLE_G1S_MASK (0x1)
+#define CTLR_ARE_S_MASK (0x1)
+#define CTLR_ARE_NS_MASK (0x1)
+#define CTLR_DS_MASK (0x1)
+#define CTLR_E1NWF_MASK (0x1)
+#define GICD_CTLR_RWP_MASK (0x1)
+
+#define CTLR_ENABLE_G1NS_BIT BIT_32(CTLR_ENABLE_G1NS_SHIFT)
+#define CTLR_ENABLE_G1S_BIT BIT_32(CTLR_ENABLE_G1S_SHIFT)
+#define CTLR_ARE_S_BIT BIT_32(CTLR_ARE_S_SHIFT)
+#define CTLR_ARE_NS_BIT BIT_32(CTLR_ARE_NS_SHIFT)
+#define CTLR_DS_BIT BIT_32(CTLR_DS_SHIFT)
+#define CTLR_E1NWF_BIT BIT_32(CTLR_E1NWF_SHIFT)
+#define GICD_CTLR_RWP_BIT BIT_32(GICD_CTLR_RWP_SHIFT)
+
+/* GICD_IROUTER shifts and masks */
+#define IROUTER_SHIFT 0
+#define IROUTER_IRM_SHIFT 31
+#define IROUTER_IRM_MASK (0x1)
+
+#define GICV3_IRM_PE (0)
+#define GICV3_IRM_ANY (1)
+
+#define NUM_OF_DIST_REGS 30
+
+/* GICD_TYPER shifts and masks */
+#define TYPER_ESPI (1 << 8)
+#define TYPER_DVIS (1 << 18)
+#define TYPER_ESPI_RANGE_MASK (0x1f)
+#define TYPER_ESPI_RANGE_SHIFT (27)
+#define TYPER_ESPI_RANGE (TYPER_ESPI_MASK << TYPER_ESPI_SHIFT)
+
+/**
+ * Common GIC Redistributor interface registers & constants
+ */
+#define GICR_SGIBASE_OFFSET (65536) /* 64 KB */
+#define GICR_CTLR (0x0)
+#define GICR_IIDR (0x04)
+#define GICR_TYPER (0x08)
+#define GICR_STATUSR (0x10)
+#define GICR_WAKER (0x14)
+#define GICR_PROPBASER (0x70)
+#define GICR_PENDBASER (0x78)
+#define GICR_IGROUPR0 (GICR_SGIBASE_OFFSET + (0x80))
+#define GICR_ISENABLER0 (GICR_SGIBASE_OFFSET + (0x100))
+#define GICR_ICENABLER0 (GICR_SGIBASE_OFFSET + (0x180))
+#define GICR_ISPENDR0 (GICR_SGIBASE_OFFSET + (0x200))
+#define GICR_ICPENDR0 (GICR_SGIBASE_OFFSET + (0x280))
+#define GICR_ISACTIVER0 (GICR_SGIBASE_OFFSET + (0x300))
+#define GICR_ICACTIVER0 (GICR_SGIBASE_OFFSET + (0x380))
+#define GICR_IPRIORITYR (GICR_SGIBASE_OFFSET + (0x400))
+#define GICR_ICFGR0 (GICR_SGIBASE_OFFSET + (0xc00))
+#define GICR_ICFGR1 (GICR_SGIBASE_OFFSET + (0xc04))
+#define GICR_IGRPMODR0 (GICR_SGIBASE_OFFSET + (0xd00))
+#define GICR_NSACR (GICR_SGIBASE_OFFSET + (0xe00))
+
+#define GICR_IGROUPR GICR_IGROUPR0
+#define GICR_ISENABLER GICR_ISENABLER0
+#define GICR_ICENABLER GICR_ICENABLER0
+#define GICR_ISPENDR GICR_ISPENDR0
+#define GICR_ICPENDR GICR_ICPENDR0
+#define GICR_ISACTIVER GICR_ISACTIVER0
+#define GICR_ICACTIVER GICR_ICACTIVER0
+#define GICR_ICFGR GICR_ICFGR0
+#define GICR_IGRPMODR GICR_IGRPMODR0
+
+/* GICR_CTLR bit definitions */
+#define GICR_CTLR_UWP_SHIFT 31
+#define GICR_CTLR_UWP_MASK (0x1)
+#define GICR_CTLR_UWP_BIT BIT_32(GICR_CTLR_UWP_SHIFT)
+#define GICR_CTLR_RWP_SHIFT 3
+#define GICR_CTLR_RWP_MASK (0x1)
+#define GICR_CTLR_RWP_BIT BIT_32(GICR_CTLR_RWP_SHIFT)
+#define GICR_CTLR_EN_LPIS_BIT BIT_32(0)
+
+/**
+ * GICv3 and 3.1 CPU interface registers & constants
+ */
+/* ICC_SRE bit definitions */
+#define ICC_SRE_EN_BIT BIT_32(3)
+#define ICC_SRE_DIB_BIT BIT_32(2)
+#define ICC_SRE_DFB_BIT BIT_32(1)
+#define ICC_SRE_SRE_BIT BIT_32(0)
+
+/* ICC_IGRPEN1_EL3 bit definitions */
+#define IGRPEN1_EL3_ENABLE_G1NS_SHIFT 0
+#define IGRPEN1_EL3_ENABLE_G1S_SHIFT 1
+
+#define IGRPEN1_EL3_ENABLE_G1NS_BIT BIT_32(IGRPEN1_EL3_ENABLE_G1NS_SHIFT)
+#define IGRPEN1_EL3_ENABLE_G1S_BIT BIT_32(IGRPEN1_EL3_ENABLE_G1S_SHIFT)
+
+/* ICC_IGRPEN0_EL1 bit definitions */
+#define IGRPEN1_EL1_ENABLE_G0_SHIFT 0
+#define IGRPEN1_EL1_ENABLE_G0_BIT BIT_32(IGRPEN1_EL1_ENABLE_G0_SHIFT)
+
+/* ICC_HPPIR0_EL1 bit definitions */
+#define HPPIR0_EL1_INTID_SHIFT 0
+#define HPPIR0_EL1_INTID_MASK (0xffffff)
+
+/* ICC_HPPIR1_EL1 bit definitions */
+#define HPPIR1_EL1_INTID_SHIFT 0
+#define HPPIR1_EL1_INTID_MASK (0xffffff)
+
+/* ICC_IAR0_EL1 bit definitions */
+#define IAR0_EL1_INTID_SHIFT 0
+#define IAR0_EL1_INTID_MASK (0xffffff)
+
+/* ICC_IAR1_EL1 bit definitions */
+#define IAR1_EL1_INTID_SHIFT 0
+#define IAR1_EL1_INTID_MASK (0xffffff)
+
+/* ICC SGI macros */
+#define SGIR_TGT_SHIFT 0
+#define SGIR_TGT_MASK 0xffff
+#define SGIR_AFF1_SHIFT 16
+#define SGIR_INTID_SHIFT 24
+#define SGIR_INTID_MASK 0xf
+#define SGIR_AFF2_SHIFT 32
+#define SGIR_IRM_SHIFT 40
+#define SGIR_IRM_MASK 0x1
+#define SGIR_AFF3_SHIFT 48
+#define SGIR_AFF_MASK 0xf
+
+#define SGIR_IRM_TO_AFF (0)
+
+/**
+ * GICv3 and 3.1 miscellaneous definitions
+ */
+/* Interrupt group definitions */
+#define INTR_GROUP1S (0)
+#define INTR_GROUP0 (1)
+#define INTR_GROUP1NS (2)
+
+/* Interrupt IDs reported by the HPPIR and IAR registers */
+#define PENDING_G1S_INTID (1020)
+#define PENDING_G1NS_INTID (8192)
+
+/* Constant to categorize LPI interrupt */
+#define MIN_LPI_ID (8192)
+
+/* GICv3 can only target up to 16 PEs with SGI */
+#define GICV3_MAX_SGI_TARGETS (16)
+
+/* PPIs INTIDs 16-31 */
+#define MAX_PPI_ID (31)
+#define MIN_SPI_ID (32)
+#define MAX_SPI_ID (1019)
+
+/* SGIs: 0-15, PPIs: 16-31 */
+#define IS_SGI_PPI(id) ((id) <= MAX_PPI_ID)
+
+/* SPIs: 32-1019 */
+#define IS_SPI(id) (((id) >= MIN_SPI_ID) && ((id) <= MAX_SPI_ID))
+
+/**
+ * GICv3 private macro definitions
+ */
+
+/* Constants to indicate the status of the RWP bit */
+#define RWP_TRUE (1)
+#define RWP_FALSE (0)
+
+/* Calculate GIC register bit number corresponding to its interrupt ID */
+#define BIT_NUM(REG, id) ((id) & ((1U << REG##R_SHIFT) - 1U))
+
+/*
+ * Calculate 8, 32 and 64-bit GICD register offset
+ * corresponding to its interrupt ID
+ */
+#define GICD_OFFSET_8(REG, id) (GICD_##REG##R + (uintptr_t)(id))
+
+#define GICD_OFFSET(REG, id) \
+	(GICD_##REG##R + (((uintptr_t)(id) >> REG##R_SHIFT) << 2))
+
+#define GICD_OFFSET_64(REG, id) \
+	(GICD_##REG##R + (((uintptr_t)(id) >> REG##R_SHIFT) << 3))
+
+/*
+ * Read/Write 8, 32 and 64-bit GIC Distributor register
+ * corresponding to its interrupt ID
+ */
+#define GICD_READ(REG, base, id) \
+	io_read32(IO32_C((base) + GICD_OFFSET(REG, (id))))
+
+#define GICD_READ_64(REG, base, id) \
+	io_read64(IO64_C((base) + GICD_OFFSET_64(REG, (id))))
+
+#define GICD_WRITE_8(REG, base, id, val) \
+	io_write8(IO8_C((base) + GICD_OFFSET_8(REG, (id))), (val))
+
+#define GICD_WRITE(REG, base, id, val) \
+	io_write32(IO32_C((base) + GICD_OFFSET(REG, (id)), (val)))
+
+#define GICD_WRITE_64(REG, base, id, val) \
+	io_write64(IO64_C((base) + GICD_OFFSET_64(REG, (id))), (val))
+
+/*
+ * Bit operations on GIC Distributor register corresponding
+ * to its interrupt ID
+ */
+/* Get bit in GIC Distributor register */
+#define GICD_GET_BIT(REG, base, id)                             \
+	((io_read32(IO32_C((base) + GICD_OFFSET(REG, (id)))) >> \
+	  BIT_NUM(REG, (id))) &                                 \
+	 1U)
+
+/* Set bit in GIC Distributor register */
+#define GICD_SET_BIT(REG, base, id)                           \
+	io_setbits32(IO32_C((base) + GICD_OFFSET(REG, (id))), \
+		     ((uint32_t)1 << BIT_NUM(REG, (id))))
+
+/* Clear bit in GIC Distributor register */
+#define GICD_CLR_BIT(REG, base, id)                           \
+	io_clrbits32(IO32_C((base) + GICD_OFFSET(REG, (id))), \
+		     ((uint32_t)1 << BIT_NUM(REG, (id))))
+
+/* Write bit in GIC Distributor register */
+#define GICD_WRITE_BIT(REG, base, id)                       \
+	io_write32(IO32_C((base) + GICD_OFFSET(REG, (id))), \
+		   ((uint32_t)1 << BIT_NUM(REG, (id))))
+
+/**
+ * Calculate 8 and 32-bit GICR register offset
+ * corresponding to its interrupt ID
+ */
+#define GICR_OFFSET_8(REG, id) (GICR_##REG##R + (uintptr_t)(id))
+
+#define GICR_OFFSET(REG, id) \
+	(GICR_##REG##R + (((uintptr_t)(id) >> REG##R_SHIFT) << 2))
+
+/* Read/Write GIC Redistributor register corresponding to its interrupt ID */
+#define GICR_READ(REG, base, id) \
+	io_read32(IO32_C((base) + GICR_OFFSET(REG, (id))))
+
+#define GICR_WRITE_8(REG, base, id, val) \
+	io_write8(IO8_C((base) + GICR_OFFSET_8(REG, (id))), (val))
+
+#define GICR_WRITE(REG, base, id, val) \
+	io_write32(IO32_C((base) + GICR_OFFSET(REG, (id))), (val))
+
+/*
+ * Bit operations on GIC Redistributor register
+ * corresponding to its interrupt ID
+ */
+
+/* Get bit in GIC Redistributor register */
+#define GICR_GET_BIT(REG, base, id)                             \
+	((io_read32(IO32_C((base) + GICR_OFFSET(REG, (id)))) >> \
+	  BIT_NUM(REG, (id))) &                                 \
+	 1U)
+
+/* Write bit in GIC Redistributor register */
+#define GICR_WRITE_BIT(REG, base, id)                       \
+	io_write32(IO32_C((base) + GICR_OFFSET(REG, (id))), \
+		   ((uint32_t)1 << BIT_NUM(REG, (id))))
+
+/* Set bit in GIC Redistributor register */
+#define GICR_SET_BIT(REG, base, id)                           \
+	io_setbits32(IO32_C((base) + GICR_OFFSET(REG, (id))), \
+		     ((uint32_t)1 << BIT_NUM(REG, (id))))
+
+/* Clear bit in GIC Redistributor register */
+#define GICR_CLR_BIT(REG, base, id)                           \
+	io_clrbits32(IO32_C((base) + GICR_OFFSET(REG, (id))), \
+		     ((uint32_t)1 << BIT_NUM(REG, (id))))
+
+static inline uint64_t gicd_irouter_val_from_mpidr(uint64_t mpidr,
+						   unsigned int irm)
+{
+	return (mpidr & ~(UINT32_C(0xff) << 24)) |
+	       ((irm & IROUTER_IRM_MASK) << IROUTER_IRM_SHIFT);
+}
+
+/**
+ * GIC Distributor interface register accessors that are common to GICv3 & GICv2
+ */
+static inline unsigned int gicd_read_ctlr(uintptr_t base)
+{
+	return io_read32(IO32_C(base + GICD_CTLR));
+}
+
+static inline void gicd_write_ctlr(uintptr_t base, unsigned int val)
+{
+	io_write32(IO32_C(base + GICD_CTLR), val);
+}
+
+/**
+ * GIC Distributor interface accessors
+ */
+/*
+ * Wait for updates to:
+ * GICD_CTLR[2:0] - the Group Enables
+ * GICD_CTLR[7:4] - the ARE bits, E1NWF bit and DS bit
+ * GICD_ICENABLER<n> - the clearing of enable state for SPIs
+ */
+static inline void gicd_wait_for_pending_write(uintptr_t gicd_base)
+{
+	while ((gicd_read_ctlr(gicd_base) & GICD_CTLR_RWP_BIT) != 0U) {
+	}
+}
+
+static inline void gicd_write_irouter(uintptr_t base, unsigned int id,
+				      uint64_t affinity)
+{
+	CHECK(id >= MIN_SPI_ID);
+	GICD_WRITE_64(IROUTE, base, id, affinity);
+}
+
+/**
+ * GIC Redistributor interface accessors
+ */
+static inline uint32_t gicr_read_ctlr(uintptr_t base)
+{
+	return io_read32(IO32_C(base + GICR_CTLR));
+}
+
+/*
+ * Wait for updates to:
+ * GICR_ICENABLER0
+ * GICR_CTLR.DPG1S
+ * GICR_CTLR.DPG1NS
+ * GICR_CTLR.DPG0
+ * GICR_CTLR, which clears EnableLPIs from 1 to 0
+ */
+static inline void gicr_wait_for_pending_write(uintptr_t gicr_base)
+{
+	while ((gicr_read_ctlr(gicr_base) & GICR_CTLR_RWP_BIT) != 0U) {
+	}
+}
+
+/**
+ * GIC Distributor functions for accessing the GIC registers
+ * corresponding to a single interrupt ID. These functions use bitwise
+ * operations or appropriate register accesses to modify or return
+ * the bit-field corresponding the single interrupt ID.
+ */
+
+/**
+ * Accessors to set the bits corresponding to interrupt ID
+ * in GIC Distributor ICFGR and ICFGRE.
+ */
+void gicd_set_icfgr(uintptr_t base, unsigned int id, unsigned int cfg)
+{
+	/* Interrupt configuration is a 2-bit field */
+	unsigned int bit_shift = BIT_NUM(ICFG, id) << 1U;
+
+	/* Clear the field, and insert required configuration */
+	io_clrsetbits32(IO32_C(base + GICD_OFFSET(ICFG, id)),
+			(uint32_t)GIC_CFG_MASK << bit_shift,
+			(cfg & GIC_CFG_MASK) << bit_shift);
+}
+
+/**
+ * Accessors to get/set/clear the bit corresponding to interrupt ID
+ * in GIC Distributor IGROUPR and IGROUPRE.
+ */
+unsigned int gicd_get_igroupr(uintptr_t base, unsigned int id)
+{
+	return GICD_GET_BIT(IGROUP, base, id);
+}
+
+void gicd_set_igroupr(uintptr_t base, unsigned int id)
+{
+	GICD_SET_BIT(IGROUP, base, id);
+}
+
+void gicd_clr_igroupr(uintptr_t base, unsigned int id)
+{
+	GICD_CLR_BIT(IGROUP, base, id);
+}
+
+/**
+ * Accessors to get/set/clear the bit corresponding to interrupt ID
+ * in GIC Distributor IGRPMODR and IGRPMODRE.
+ */
+unsigned int gicd_get_igrpmodr(uintptr_t base, unsigned int id)
+{
+	return GICD_GET_BIT(IGRPMOD, base, id);
+}
+
+void gicd_set_igrpmodr(uintptr_t base, unsigned int id)
+{
+	GICD_SET_BIT(IGRPMOD, base, id);
+}
+
+void gicd_clr_igrpmodr(uintptr_t base, unsigned int id)
+{
+	GICD_CLR_BIT(IGRPMOD, base, id);
+}
+
+/**
+ * Accessors to set the bit corresponding to interrupt ID
+ * in GIC Distributor ICENABLER and ICENABLERE.
+ */
+void gicd_set_icenabler(uintptr_t base, unsigned int id)
+{
+	GICD_WRITE_BIT(ICENABLE, base, id);
+}
+
+/**
+ * Accessors to set the bit corresponding to interrupt ID
+ * in GIC Distributor ISENABLER and ISENABLERE.
+ */
+void gicd_set_isenabler(uintptr_t base, unsigned int id)
+{
+	GICD_WRITE_BIT(ISENABLE, base, id);
+}
+
+/**
+ * Accessors to set the bit corresponding to interrupt ID
+ * in GIC Distributor IPRIORITYR and IPRIORITYRE.
+ */
+void gicd_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri)
+{
+	GICD_WRITE_8(IPRIORITY, base, id, (uint8_t)(pri & GIC_PRI_MASK));
+}
+
+/**
+ * Accessor to set the byte corresponding to interrupt `id`
+ * in GIC Redistributor IPRIORITYR and IPRIORITYRE.
+ */
+void gicr_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri)
+{
+	GICR_WRITE_8(IPRIORITY, base, id, (uint8_t)(pri & GIC_PRI_MASK));
+}
+
+/**
+ * Accessors to get/set/clear the bit corresponding to interrupt `id`
+ * from GIC Redistributor IGROUPR0 and IGROUPRE
+ */
+unsigned int gicr_get_igroupr(uintptr_t base, unsigned int id)
+{
+	return GICR_GET_BIT(IGROUP, base, id);
+}
+
+void gicr_set_igroupr(uintptr_t base, unsigned int id)
+{
+	GICR_SET_BIT(IGROUP, base, id);
+}
+
+void gicr_clr_igroupr(uintptr_t base, unsigned int id)
+{
+	GICR_CLR_BIT(IGROUP, base, id);
+}
+
+/**
+ * Accessors to get/set/clear the bit corresponding to interrupt `id`
+ * from GIC Redistributor IGRPMODR0 and IGRPMODRE
+ */
+unsigned int gicr_get_igrpmodr(uintptr_t base, unsigned int id)
+{
+	return GICR_GET_BIT(IGRPMOD, base, id);
+}
+
+void gicr_set_igrpmodr(uintptr_t base, unsigned int id)
+{
+	GICR_SET_BIT(IGRPMOD, base, id);
+}
+
+void gicr_clr_igrpmodr(uintptr_t base, unsigned int id)
+{
+	GICR_CLR_BIT(IGRPMOD, base, id);
+}
+
+/**
+ * Accessor to write the bit corresponding to interrupt `id`
+ * in GIC Redistributor ISENABLER0 and ISENABLERE
+ */
+void gicr_set_isenabler(uintptr_t base, unsigned int id)
+{
+	GICR_WRITE_BIT(ISENABLE, base, id);
+}
+
+/**
+ * Accessor to write the bit corresponding to interrupt `id`
+ * in GIC Redistributor ICENABLER0 and ICENABLERE
+ */
+void gicr_set_icenabler(uintptr_t base, unsigned int id)
+{
+	GICR_WRITE_BIT(ICENABLE, base, id);
+}
+
+/**
+ * Accessor to set the bit fields corresponding to interrupt `id`
+ * in GIC Redistributor ICFGR0, ICFGR1 and ICFGRE
+ */
+void gicr_set_icfgr(uintptr_t base, unsigned int id, unsigned int cfg)
+{
+	/* Interrupt configuration is a 2-bit field */
+	unsigned int bit_shift = BIT_NUM(ICFG, id) << 1U;
+
+	/* Clear the field, and insert required configuration */
+	io_clrsetbits32(IO32_C(base + GICR_OFFSET(ICFG, id)),
+			(uint32_t)GIC_CFG_MASK << bit_shift,
+			(cfg & GIC_CFG_MASK) << bit_shift);
+}