Merge pull request #456 from soby-mathew/sm/gicv3-tsp-plat-changes-v2

Modify TSP and ARM standard platforms for new GIC drivers v2
diff --git a/bl31/interrupt_mgmt.c b/bl31/interrupt_mgmt.c
index 206578b..e991851 100644
--- a/bl31/interrupt_mgmt.c
+++ b/bl31/interrupt_mgmt.c
@@ -67,18 +67,15 @@
 static intr_type_desc_t intr_type_descs[MAX_INTR_TYPES];
 
 /*******************************************************************************
- * This function validates the interrupt type. EL3 interrupts are currently not
- * supported.
+ * This function validates the interrupt type.
  ******************************************************************************/
 static int32_t validate_interrupt_type(uint32_t type)
 {
-	if (type == INTR_TYPE_EL3)
-		return -ENOTSUP;
-
-	if (type != INTR_TYPE_S_EL1 && type != INTR_TYPE_NS)
-		return -EINVAL;
+	if (type == INTR_TYPE_S_EL1 || type == INTR_TYPE_NS ||
+			type == INTR_TYPE_EL3)
+		return 0;
 
-	return 0;
+	return -EINVAL;
 }
 
 /*******************************************************************************
@@ -95,6 +92,9 @@
 	if (type == INTR_TYPE_NS)
 		return validate_ns_interrupt_rm(flags);
 
+	if (type == INTR_TYPE_EL3)
+		return validate_el3_interrupt_rm(flags);
+
 	return -EINVAL;
 }
 
diff --git a/bl32/tsp/aarch64/tsp_entrypoint.S b/bl32/tsp/aarch64/tsp_entrypoint.S
index 9732ff2..531ab9b 100644
--- a/bl32/tsp/aarch64/tsp_entrypoint.S
+++ b/bl32/tsp/aarch64/tsp_entrypoint.S
@@ -177,7 +177,7 @@
 	b	tsp_cpu_off_entry
 	b	tsp_cpu_resume_entry
 	b	tsp_cpu_suspend_entry
-	b	tsp_fiq_entry
+	b	tsp_sel1_intr_entry
 	b	tsp_system_off_entry
 	b	tsp_system_reset_entry
 endfunc tsp_vector_table
@@ -325,13 +325,15 @@
 	restore_args_call_smc
 endfunc tsp_cpu_suspend_entry
 
-	/*---------------------------------------------
+	/*-------------------------------------------------
 	 * This entrypoint is used by the TSPD to pass
-	 * control for handling a pending S-EL1 FIQ.
-	 * 'x0' contains a magic number which indicates
-	 * this. TSPD expects control to be handed back
-	 * at the end of FIQ processing. This is done
-	 * through an SMC. The handover agreement is:
+	 * control for `synchronously` handling a S-EL1
+	 * Interrupt which was triggered while executing
+	 * in normal world. 'x0' contains a magic number
+	 * which indicates this. TSPD expects control to
+	 * be handed back at the end of interrupt
+	 * processing. This is done through an SMC.
+	 * The handover agreement is:
 	 *
 	 * 1. PSTATE.DAIF are set upon entry. 'x1' has
 	 *    the ELR_EL3 from the non-secure state.
@@ -343,40 +345,54 @@
 	 * 4. TSP can use 'x0-x18' to enable its C
 	 *    runtime.
 	 * 5. TSP returns to TSPD using an SMC with
-	 *    'x0' = TSP_HANDLED_S_EL1_FIQ
-	 * ---------------------------------------------
+	 *    'x0' = TSP_HANDLED_S_EL1_INTR
+	 * ------------------------------------------------
 	 */
-func	tsp_fiq_entry
+func	tsp_sel1_intr_entry
 #if DEBUG
-	mov	x2, #(TSP_HANDLE_FIQ_AND_RETURN & ~0xffff)
-	movk	x2, #(TSP_HANDLE_FIQ_AND_RETURN &  0xffff)
+	mov_imm	x2, TSP_HANDLE_SEL1_INTR_AND_RETURN
 	cmp	x0, x2
-	b.ne	tsp_fiq_entry_panic
+	b.ne	tsp_sel1_int_entry_panic
 #endif
-	/*---------------------------------------------
+	/*-------------------------------------------------
 	 * Save any previous context needed to perform
 	 * an exception return from S-EL1 e.g. context
-	 * from a previous IRQ. Update statistics and
-	 * handle the FIQ before returning to the TSPD.
+	 * from a previous Non secure Interrupt.
+	 * Update statistics and handle the S-EL1
+	 * interrupt before returning to the TSPD.
 	 * IRQ/FIQs are not enabled since that will
 	 * complicate the implementation. Execution
 	 * will be transferred back to the normal world
-	 * in any case. A non-zero return value from the
-	 * fiq handler is an error.
-	 * ---------------------------------------------
+	 * in any case. The handler can return 0
+	 * if the interrupt was handled or TSP_PREEMPTED
+	 * if the expected interrupt was preempted
+	 * by an interrupt that should be handled in EL3
+	 * e.g. Group 0 interrupt in GICv3. In both
+	 * the cases switch to EL3 using SMC with id
+	 * TSP_HANDLED_S_EL1_INTR. Any other return value
+	 * from the handler will result in panic.
+	 * ------------------------------------------------
 	 */
 	save_eret_context x2 x3
-	bl	tsp_update_sync_fiq_stats
-	bl	tsp_fiq_handler
-	cbnz	x0, tsp_fiq_entry_panic
+	bl	tsp_update_sync_sel1_intr_stats
+	bl	tsp_common_int_handler
+	/* Check if the S-EL1 interrupt has been handled */
+	cbnz	x0, tsp_sel1_intr_check_preemption
+	b	tsp_sel1_intr_return
+tsp_sel1_intr_check_preemption:
+	/* Check if the S-EL1 interrupt has been preempted */
+	mov_imm	x1, TSP_PREEMPTED
+	cmp	x0, x1
+	b.ne	tsp_sel1_int_entry_panic
+tsp_sel1_intr_return:
+	mov_imm	x0, TSP_HANDLED_S_EL1_INTR
 	restore_eret_context x2 x3
-	mov	x0, #(TSP_HANDLED_S_EL1_FIQ & ~0xffff)
-	movk	x0, #(TSP_HANDLED_S_EL1_FIQ &  0xffff)
 	smc	#0
 
-tsp_fiq_entry_panic:
-	b	tsp_fiq_entry_panic
-endfunc tsp_fiq_entry
+	/* Should never reach here */
+tsp_sel1_int_entry_panic:
+	b	tsp_sel1_int_entry_panic
+endfunc tsp_sel1_intr_entry
 
 	/*---------------------------------------------
 	 * This entrypoint is used by the TSPD when this
diff --git a/bl32/tsp/aarch64/tsp_exceptions.S b/bl32/tsp/aarch64/tsp_exceptions.S
index 4c0d436..d5e089f 100644
--- a/bl32/tsp/aarch64/tsp_exceptions.S
+++ b/bl32/tsp/aarch64/tsp_exceptions.S
@@ -70,6 +70,28 @@
 	add	sp, sp, SCRATCH_REG_SIZE
 	.endm
 
+	/* ----------------------------------------------------
+	 * Common TSP interrupt handling routine
+	 * ----------------------------------------------------
+	 */
+	.macro	handle_tsp_interrupt label
+	/* Enable the SError interrupt */
+	msr	daifclr, #DAIF_ABT_BIT
+
+	save_caller_regs_and_lr
+	bl	tsp_common_int_handler
+	cbz	x0, interrupt_exit_\label
+
+	/*
+	 * This interrupt was not targetted to S-EL1 so send it to
+	 * the monitor and wait for execution to resume.
+	 */
+	smc	#0
+interrupt_exit_\label:
+	restore_caller_regs_and_lr
+	eret
+	.endm
+
 	.globl	tsp_exceptions
 
 	/* -----------------------------------------------------
@@ -120,36 +142,12 @@
 
 	.align	7
 irq_sp_elx:
-	/* Enable the SError interrupt */
-	msr	daifclr, #DAIF_ABT_BIT
-
-	save_caller_regs_and_lr
-	/* We just update some statistics in the handler */
-	bl	tsp_irq_received
-	/* Hand over control to the normal world to handle the IRQ */
-	smc	#0
-	/* The resume std smc starts from here */
-	restore_caller_regs_and_lr
-	eret
+	handle_tsp_interrupt irq_sp_elx
 	check_vector_size irq_sp_elx
 
 	.align	7
 fiq_sp_elx:
-	/* Enable the SError interrupt */
-	msr	daifclr, #DAIF_ABT_BIT
-
-	save_caller_regs_and_lr
-	bl	tsp_fiq_handler
-	cbz	x0, fiq_sp_elx_done
-
-	/*
-	 * This FIQ was not targetted to S-EL1 so send it to
-	 * the monitor and wait for execution to resume.
-	 */
-	smc	#0
-fiq_sp_elx_done:
-	restore_caller_regs_and_lr
-	eret
+	handle_tsp_interrupt fiq_sp_elx
 	check_vector_size fiq_sp_elx
 
 	.align	7
diff --git a/bl32/tsp/tsp_interrupt.c b/bl32/tsp/tsp_interrupt.c
index 139642d..7654d2e 100644
--- a/bl32/tsp/tsp_interrupt.c
+++ b/bl32/tsp/tsp_interrupt.c
@@ -31,50 +31,70 @@
 #include <arch_helpers.h>
 #include <assert.h>
 #include <debug.h>
-#include <gic_v2.h>
 #include <platform.h>
 #include <platform_def.h>
 #include <tsp.h>
 #include "tsp_private.h"
 
 /*******************************************************************************
- * This function updates the TSP statistics for FIQs handled synchronously i.e
- * the ones that have been handed over by the TSPD. It also keeps count of the
- * number of times control was passed back to the TSPD after handling an FIQ.
- * In the future it will be possible that the TSPD hands over an FIQ to the TSP
- * but does not expect it to return execution. This statistic will be useful to
- * distinguish between these two models of synchronous FIQ handling.
- * The 'elr_el3' parameter contains the address of the instruction in normal
- * world where this FIQ was generated.
+ * This function updates the TSP statistics for S-EL1 interrupts handled
+ * synchronously i.e the ones that have been handed over by the TSPD. It also
+ * keeps count of the number of times control was passed back to the TSPD
+ * after handling the interrupt. In the future it will be possible that the
+ * TSPD hands over an S-EL1 interrupt to the TSP but does not expect it to
+ * return execution. This statistic will be useful to distinguish between these
+ * two models of synchronous S-EL1 interrupt handling. The 'elr_el3' parameter
+ * contains the address of the instruction in normal world where this S-EL1
+ * interrupt was generated.
  ******************************************************************************/
-void tsp_update_sync_fiq_stats(uint32_t type, uint64_t elr_el3)
+void tsp_update_sync_sel1_intr_stats(uint32_t type, uint64_t elr_el3)
 {
 	uint32_t linear_id = plat_my_core_pos();
 
-	tsp_stats[linear_id].sync_fiq_count++;
-	if (type == TSP_HANDLE_FIQ_AND_RETURN)
-		tsp_stats[linear_id].sync_fiq_ret_count++;
+	tsp_stats[linear_id].sync_sel1_intr_count++;
+	if (type == TSP_HANDLE_SEL1_INTR_AND_RETURN)
+		tsp_stats[linear_id].sync_sel1_intr_ret_count++;
 
 #if LOG_LEVEL >= LOG_LEVEL_VERBOSE
 	spin_lock(&console_lock);
-	VERBOSE("TSP: cpu 0x%lx sync fiq request from 0x%lx\n",
+	VERBOSE("TSP: cpu 0x%lx sync s-el1 interrupt request from 0x%lx\n",
 		read_mpidr(), elr_el3);
-	VERBOSE("TSP: cpu 0x%lx: %d sync fiq requests, %d sync fiq returns\n",
+	VERBOSE("TSP: cpu 0x%lx: %d sync s-el1 interrupt requests,"
+		" %d sync s-el1 interrupt returns\n",
 		read_mpidr(),
-		tsp_stats[linear_id].sync_fiq_count,
-		tsp_stats[linear_id].sync_fiq_ret_count);
+		tsp_stats[linear_id].sync_sel1_intr_count,
+		tsp_stats[linear_id].sync_sel1_intr_ret_count);
 	spin_unlock(&console_lock);
 #endif
 }
 
+/******************************************************************************
+ * This function is invoked when a non S-EL1 interrupt is received and causes
+ * the preemption of TSP. This function returns TSP_PREEMPTED and results
+ * in the control being handed over to EL3 for handling the interrupt.
+ *****************************************************************************/
+int32_t tsp_handle_preemption(void)
+{
+	uint32_t linear_id = plat_my_core_pos();
+
+	tsp_stats[linear_id].preempt_intr_count++;
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+	spin_lock(&console_lock);
+	VERBOSE("TSP: cpu 0x%lx: %d preempt interrupt requests\n",
+		read_mpidr(), tsp_stats[linear_id].preempt_intr_count);
+	spin_unlock(&console_lock);
+#endif
+	return TSP_PREEMPTED;
+}
+
 /*******************************************************************************
- * TSP FIQ handler called as a part of both synchronous and asynchronous
- * handling of FIQ interrupts. It returns 0 upon successfully handling a S-EL1
- * FIQ and treats all other FIQs as EL3 interrupts. It assumes that the GIC
- * architecture version in v2.0 and the secure physical timer interrupt is the
- * only S-EL1 interrupt that it needs to handle.
+ * TSP interrupt handler is called as a part of both synchronous and
+ * asynchronous handling of TSP interrupts. Currently the physical timer
+ * interrupt is the only S-EL1 interrupt that this handler expects. It returns
+ * 0 upon successfully handling the expected interrupt and all other
+ * interrupts are treated as normal world or EL3 interrupts.
  ******************************************************************************/
-int32_t tsp_fiq_handler(void)
+int32_t tsp_common_int_handler(void)
 {
 	uint32_t linear_id = plat_my_core_pos(), id;
 
@@ -82,16 +102,21 @@
 	 * Get the highest priority pending interrupt id and see if it is the
 	 * secure physical generic timer interrupt in which case, handle it.
 	 * Otherwise throw this interrupt at the EL3 firmware.
+	 *
+	 * There is a small time window between reading the highest priority
+	 * pending interrupt and acknowledging it during which another
+	 * interrupt of higher priority could become the highest pending
+	 * interrupt. This is not expected to happen currently for TSP.
 	 */
 	id = plat_ic_get_pending_interrupt_id();
 
 	/* TSP can only handle the secure physical timer interrupt */
 	if (id != TSP_IRQ_SEC_PHY_TIMER)
-		return TSP_EL3_FIQ;
+		return tsp_handle_preemption();
 
 	/*
-	 * Handle the interrupt. Also sanity check if it has been preempted by
-	 * another secure interrupt through an assertion.
+	 * Acknowledge and handle the secure timer interrupt. Also sanity check
+	 * if it has been preempted by another interrupt through an assertion.
 	 */
 	id = plat_ic_acknowledge_interrupt();
 	assert(id == TSP_IRQ_SEC_PHY_TIMER);
@@ -99,29 +124,14 @@
 	plat_ic_end_of_interrupt(id);
 
 	/* Update the statistics and print some messages */
-	tsp_stats[linear_id].fiq_count++;
+	tsp_stats[linear_id].sel1_intr_count++;
 #if LOG_LEVEL >= LOG_LEVEL_VERBOSE
 	spin_lock(&console_lock);
-	VERBOSE("TSP: cpu 0x%lx handled fiq %d\n",
+	VERBOSE("TSP: cpu 0x%lx handled S-EL1 interrupt %d\n",
 	       read_mpidr(), id);
-	VERBOSE("TSP: cpu 0x%lx: %d fiq requests\n",
-	     read_mpidr(), tsp_stats[linear_id].fiq_count);
+	VERBOSE("TSP: cpu 0x%lx: %d S-EL1 requests\n",
+	     read_mpidr(), tsp_stats[linear_id].sel1_intr_count);
 	spin_unlock(&console_lock);
 #endif
 	return 0;
 }
-
-int32_t tsp_irq_received(void)
-{
-	uint32_t linear_id = plat_my_core_pos();
-
-	tsp_stats[linear_id].irq_count++;
-#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
-	spin_lock(&console_lock);
-	VERBOSE("TSP: cpu 0x%lx received irq\n", read_mpidr());
-	VERBOSE("TSP: cpu 0x%lx: %d irq requests\n",
-		read_mpidr(), tsp_stats[linear_id].irq_count);
-	spin_unlock(&console_lock);
-#endif
-	return TSP_PREEMPTED;
-}
diff --git a/bl32/tsp/tsp_private.h b/bl32/tsp/tsp_private.h
index 39fb5f6..e341cfd 100644
--- a/bl32/tsp/tsp_private.h
+++ b/bl32/tsp/tsp_private.h
@@ -54,10 +54,14 @@
 
 
 typedef struct work_statistics {
-	uint32_t fiq_count;		/* Number of FIQs on this cpu */
-	uint32_t irq_count;		/* Number of IRQs on this cpu */
-	uint32_t sync_fiq_count;	/* Number of sync. fiqs on this cpu */
-	uint32_t sync_fiq_ret_count;	/* Number of fiq returns on this cpu */
+	/* Number of s-el1 interrupts on this cpu */
+	uint32_t sel1_intr_count;
+	/* Number of non s-el1 interrupts on this cpu which preempted TSP */
+	uint32_t preempt_intr_count;
+	/* Number of sync s-el1 interrupts on this cpu */
+	uint32_t sync_sel1_intr_count;
+	/* Number of s-el1 interrupts returns on this cpu */
+	uint32_t sync_sel1_intr_ret_count;
 	uint32_t smc_count;		/* Number of returns on this cpu */
 	uint32_t eret_count;		/* Number of entries on this cpu */
 	uint32_t cpu_on_count;		/* Number of cpu on requests */
@@ -115,8 +119,8 @@
 void tsp_generic_timer_save(void);
 void tsp_generic_timer_restore(void);
 
-/* FIQ management functions */
-void tsp_update_sync_fiq_stats(uint32_t type, uint64_t elr_el3);
+/* S-EL1 interrupt management functions */
+void tsp_update_sync_sel1_intr_stats(uint32_t type, uint64_t elr_el3);
 
 
 /* Data structure to keep track of TSP statistics */
diff --git a/docs/interrupt-framework-design.md b/docs/interrupt-framework-design.md
index 53707ae..271cd92 100644
--- a/docs/interrupt-framework-design.md
+++ b/docs/interrupt-framework-design.md
@@ -399,12 +399,12 @@
 1.  It passes control to the Test Secure Payload to perform its
     initialisation. The TSP provides the address of the vector table
     `tsp_vectors` in the SP which also includes the handler for Secure-EL1
-    interrupts in the `fiq_entry` field. The TSPD passes control to the TSP at
+    interrupts in the `sel1_intr_entry` field. The TSPD passes control to the TSP at
     this address when it receives a Secure-EL1 interrupt.
 
     The handover agreement between the TSP and the TSPD requires that the TSPD
     masks all interrupts (`PSTATE.DAIF` bits) when it calls
-    `tsp_fiq_entry()`. The TSP has to preserve the callee saved general
+    `tsp_sel1_intr_entry()`. The TSP has to preserve the callee saved general
     purpose, SP_EL1/Secure-EL0, LR, VFP and system registers. It can use
     `x0-x18` to enable its C runtime.
 
@@ -514,7 +514,7 @@
 The routing model for Secure-EL1 and non-secure interrupts chosen by the TSP is
 described in Section 2.2.2. It is known to the TSPD service at build time.
 
-The TSP implements an entrypoint (`tsp_fiq_entry()`) for handling Secure-EL1
+The TSP implements an entrypoint (`tsp_sel1_intr_entry()`) for handling Secure-EL1
 interrupts taken in non-secure state and routed through the TSPD service
 (synchronous handling model). It passes the reference to this entrypoint via
 `tsp_vectors` to the TSPD service.
@@ -700,9 +700,9 @@
 3.  It saves the system register context for the non-secure state by calling
     `cm_el1_sysregs_context_save(NON_SECURE);`.
 
-4.  It sets the `ELR_EL3` system register to `tsp_fiq_entry` and sets the
+4.  It sets the `ELR_EL3` system register to `tsp_sel1_intr_entry` and sets the
     `SPSR_EL3.DAIF` bits in the secure CPU context. It sets `x0` to
-    `TSP_HANDLE_FIQ_AND_RETURN`. If the TSP was in the middle of handling a
+    `TSP_HANDLE_SEL1_INTR_AND_RETURN`. If the TSP was in the middle of handling a
     standard SMC, then the `ELR_EL3` and `SPSR_EL3` registers in the secure CPU
     context are saved first.
 
@@ -723,20 +723,20 @@
 
 ![Image 1](diagrams/sec-int-handling.png?raw=true)
 
-The TSP issues an SMC with `TSP_HANDLED_S_EL1_FIQ` as the function identifier to
+The TSP issues an SMC with `TSP_HANDLED_S_EL1_INTR` as the function identifier to
 signal completion of interrupt handling.
 
 The TSP issues an SMC with `TSP_PREEMPTED` as the function identifier to signal
 generation of a non-secure interrupt in Secure-EL1.
 
 The TSPD service takes the following actions in `tspd_smc_handler()` function
-upon receiving an SMC with `TSP_HANDLED_S_EL1_FIQ` and `TSP_PREEMPTED` as the
+upon receiving an SMC with `TSP_HANDLED_S_EL1_INTR` and `TSP_PREEMPTED` as the
 function identifiers:
 
 1.  It ensures that the call originated from the secure state otherwise
     execution returns to the non-secure state with `SMC_UNK` in `x0`.
 
-2.  If the function identifier is `TSP_HANDLED_S_EL1_FIQ`, it restores the
+2.  If the function identifier is `TSP_HANDLED_S_EL1_INTR`, it restores the
     saved `ELR_EL3` and `SPSR_EL3` system registers back to the secure CPU
     context (see step 4 above) in case the TSP had been preempted by a non
     secure interrupt earlier.  It does not save the secure context since the
@@ -811,7 +811,7 @@
 
 ##### 2.3.3.1 Test secure payload behavior
 The TSPD hands control of a Secure-EL1 interrupt to the TSP at the
-`tsp_fiq_entry()`.  The TSP handles the interrupt while ensuring that the
+`tsp_sel1_intr_entry()`.  The TSP handles the interrupt while ensuring that the
 handover agreement described in Section 2.2.2.1 is maintained. It updates some
 statistics by calling `tsp_update_sync_fiq_stats()`. It then calls
 `tsp_fiq_handler()` which.
@@ -827,7 +827,7 @@
     end of interrupt processing.
 
 The TSP passes control back to the TSPD by issuing an SMC64 with
-`TSP_HANDLED_S_EL1_FIQ` as the function identifier.
+`TSP_HANDLED_S_EL1_INTR` as the function identifier.
 
 The TSP handles interrupts under the asynchronous model as follows.
 
diff --git a/docs/user-guide.md b/docs/user-guide.md
index bcdc645..716ed7d 100644
--- a/docs/user-guide.md
+++ b/docs/user-guide.md
@@ -278,10 +278,13 @@
     (Coherent memory region is included) or 0 (Coherent memory region is
     excluded). Default is 1.
 
-*   `TSPD_ROUTE_IRQ_TO_EL3`: A non zero value enables the routing model
-    for non-secure interrupts in which they are routed to EL3 (TSPD). The
-    default model (when the value is 0) is to route non-secure interrupts
-    to S-EL1 (TSP).
+*   `TSP_NS_INTR_ASYNC_PREEMPT`: A non zero value enables the interrupt
+    routing model which routes non-secure interrupts asynchronously from TSP
+    to EL3 causing immediate preemption of TSP. The EL3 is responsible
+    for saving and restoring the TSP context in this routing model. The
+    default routing model (when the value is 0) is to route non-secure
+    interrupts to TSP allowing it to save its context and hand over
+    synchronously to EL3 via an SMC.
 
 *   `TRUSTED_BOARD_BOOT`: Boolean flag to include support for the Trusted Board
     Boot feature. When set to '1', BL1 and BL2 images include support to load
diff --git a/drivers/arm/gic/v3/gicv3_helpers.c b/drivers/arm/gic/v3/gicv3_helpers.c
index 6e8251d..2fb98cb 100644
--- a/drivers/arm/gic/v3/gicv3_helpers.c
+++ b/drivers/arm/gic/v3/gicv3_helpers.c
@@ -312,7 +312,7 @@
 	unsigned int index, irq_num;
 	uint64_t gic_affinity_val;
 
-	assert((int_grp == INT_TYPE_G1S) || (int_grp == INT_TYPE_G0));
+	assert((int_grp == INTR_GROUP1S) || (int_grp == INTR_GROUP0));
 	/* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */
 	assert(num_ints ? (uintptr_t)sec_intr_list : 1);
 
@@ -324,7 +324,7 @@
 			gicd_clr_igroupr(gicd_base, irq_num);
 
 			/* Configure this interrupt as G0 or a G1S interrupt */
-			if (int_grp == INT_TYPE_G1S)
+			if (int_grp == INTR_GROUP1S)
 				gicd_set_igrpmodr(gicd_base, irq_num);
 			else
 				gicd_clr_igrpmodr(gicd_base, irq_num);
@@ -386,7 +386,7 @@
 {
 	unsigned int index, irq_num;
 
-	assert((int_grp == INT_TYPE_G1S) || (int_grp == INT_TYPE_G0));
+	assert((int_grp == INTR_GROUP1S) || (int_grp == INTR_GROUP0));
 	/* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */
 	assert(num_ints ? (uintptr_t)sec_intr_list : 1);
 
@@ -398,7 +398,7 @@
 			gicr_clr_igroupr0(gicr_base, irq_num);
 
 			/* Configure this interrupt as G0 or a G1S interrupt */
-			if (int_grp == INT_TYPE_G1S)
+			if (int_grp == INTR_GROUP1S)
 				gicr_set_igrpmodr0(gicr_base, irq_num);
 			else
 				gicr_clr_igrpmodr0(gicr_base, irq_num);
diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c
index 06311e3..d5cd0ed 100644
--- a/drivers/arm/gic/v3/gicv3_main.c
+++ b/drivers/arm/gic/v3/gicv3_main.c
@@ -144,13 +144,13 @@
 	gicv3_secure_spis_configure(driver_data->gicd_base,
 					driver_data->g1s_interrupt_num,
 					driver_data->g1s_interrupt_array,
-					INT_TYPE_G1S);
+					INTR_GROUP1S);
 
 	/* Configure the G0 SPIs */
 	gicv3_secure_spis_configure(driver_data->gicd_base,
 					driver_data->g0_interrupt_num,
 					driver_data->g0_interrupt_array,
-					INT_TYPE_G0);
+					INTR_GROUP0);
 
 	/* Enable the secure SPIs now that they have been configured */
 	gicd_set_ctlr(driver_data->gicd_base,
@@ -186,13 +186,13 @@
 	gicv3_secure_ppi_sgi_configure(gicr_base,
 					   driver_data->g1s_interrupt_num,
 					   driver_data->g1s_interrupt_array,
-					   INT_TYPE_G1S);
+					   INTR_GROUP1S);
 
 	/* Configure the G0 SGIs/PPIs */
 	gicv3_secure_ppi_sgi_configure(gicr_base,
 					   driver_data->g0_interrupt_num,
 					   driver_data->g0_interrupt_array,
-					   INT_TYPE_G0);
+					   INTR_GROUP0);
 }
 
 /*******************************************************************************
@@ -332,9 +332,9 @@
  * this interrupt has been configured under by the interrupt controller i.e.
  * group0 or group1 Secure / Non Secure. The return value can be one of the
  * following :
- *    INT_TYPE_G0  : The interrupt type is a Secure Group 0 interrupt
- *    INT_TYPE_G1S : The interrupt type is a Secure Group 1 secure interrupt
- *    INT_TYPE_G1NS: The interrupt type is a Secure Group 1 non secure
+ *    INTR_GROUP0  : The interrupt type is a Secure Group 0 interrupt
+ *    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.
  ******************************************************************************/
 unsigned int gicv3_get_interrupt_type(unsigned int id,
@@ -352,7 +352,7 @@
 
 	/* All LPI interrupts are Group 1 non secure */
 	if (id >= MIN_LPI_ID)
-		return INT_TYPE_G1NS;
+		return INTR_GROUP1NS;
 
 	if (id < MIN_SPI_ID) {
 		assert(driver_data->rdistif_base_addrs);
@@ -370,12 +370,12 @@
 	 * interrupt
 	 */
 	if (igroup)
-		return INT_TYPE_G1NS;
+		return INTR_GROUP1NS;
 
 	/* If the GRPMOD bit is set, then it is a Group 1 Secure interrupt */
 	if (grpmodr)
-		return INT_TYPE_G1S;
+		return INTR_GROUP1S;
 
 	/* Else it is a Group 0 Secure interrupt */
-	return INT_TYPE_G0;
+	return INTR_GROUP0;
 }
diff --git a/include/bl31/interrupt_mgmt.h b/include/bl31/interrupt_mgmt.h
index e07ddf8..0172b60 100644
--- a/include/bl31/interrupt_mgmt.h
+++ b/include/bl31/interrupt_mgmt.h
@@ -63,6 +63,10 @@
 #define INTR_NS_VALID_RM0		0x0
 /* Routed to EL1/EL2 from NS and to EL3 from Secure */
 #define INTR_NS_VALID_RM1		0x1
+/* Routed to EL3 from NS. Taken to S-EL1 from Secure and handed over to EL3 */
+#define INTR_EL3_VALID_RM0		0x2
+/* Routed to EL3 from NS and Secure */
+#define INTR_EL3_VALID_RM1		0x3
 /* This is the default routing model */
 #define INTR_DEFAULT_RM		0x0
 
@@ -87,12 +91,16 @@
  * of interrupt. If the model does not match one of the valid masks
  * -EINVAL is returned.
  ******************************************************************************/
-#define validate_sel1_interrupt_rm(x)	(x == INTR_SEL1_VALID_RM0 ? 0 : \
-					 (x == INTR_SEL1_VALID_RM1 ? 0 :\
+#define validate_sel1_interrupt_rm(x)	((x) == INTR_SEL1_VALID_RM0 ? 0 : \
+					 ((x) == INTR_SEL1_VALID_RM1 ? 0 :\
 					  -EINVAL))
 
-#define validate_ns_interrupt_rm(x)	(x == INTR_NS_VALID_RM0 ? 0 : \
-					 (x == INTR_NS_VALID_RM1 ? 0 :\
+#define validate_ns_interrupt_rm(x)	((x) == INTR_NS_VALID_RM0 ? 0 : \
+					 ((x) == INTR_NS_VALID_RM1 ? 0 :\
+					  -EINVAL))
+
+#define validate_el3_interrupt_rm(x)	((x) == INTR_EL3_VALID_RM0 ? 0 : \
+					 ((x) == INTR_EL3_VALID_RM1 ? 0 :\
 					  -EINVAL))
 
 /*******************************************************************************
diff --git a/include/bl32/tsp/tsp.h b/include/bl32/tsp/tsp.h
index c6578b7..fd43fd3 100644
--- a/include/bl32/tsp/tsp.h
+++ b/include/bl32/tsp/tsp.h
@@ -45,12 +45,12 @@
 #define TSP_SYSTEM_RESET_DONE	0xf2000009
 
 /*
- * Function identifiers to handle FIQs through the synchronous handling model.
- * If the TSP was previously interrupted then control has to be returned to
- * the TSPD after handling the interrupt else execution can remain in the TSP.
+ * Function identifiers to handle S-El1 interrupt through the synchronous
+ * handling model. If the TSP was previously interrupted then control has to
+ * be returned to the TSPD after handling the interrupt else execution can
+ * remain in the TSP.
  */
-#define TSP_HANDLED_S_EL1_FIQ		0xf2000006
-#define TSP_EL3_FIQ			0xf2000007
+#define TSP_HANDLED_S_EL1_INTR		0xf2000006
 
 /* SMC function ID that TSP uses to request service from secure monitor */
 #define TSP_GET_ARGS		0xf2001000
@@ -63,7 +63,7 @@
 #define TSP_SUB		0x2001
 #define TSP_MUL		0x2002
 #define TSP_DIV		0x2003
-#define TSP_HANDLE_FIQ_AND_RETURN	0x2004
+#define TSP_HANDLE_SEL1_INTR_AND_RETURN	0x2004
 
 /*
  * Generate function IDs for TSP services to be used in SMC calls, by
@@ -115,7 +115,7 @@
 	tsp_vector_isn_t cpu_off_entry;
 	tsp_vector_isn_t cpu_resume_entry;
 	tsp_vector_isn_t cpu_suspend_entry;
-	tsp_vector_isn_t fiq_entry;
+	tsp_vector_isn_t sel1_intr_entry;
 	tsp_vector_isn_t system_off_entry;
 	tsp_vector_isn_t system_reset_entry;
 } tsp_vectors_t;
diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h
index e874f5c..ae6fd91 100644
--- a/include/drivers/arm/gicv3.h
+++ b/include/drivers/arm/gicv3.h
@@ -35,9 +35,9 @@
  * GICv3 miscellaneous definitions
  ******************************************************************************/
 /* Interrupt group definitions */
-#define INT_TYPE_G1S		0
-#define INT_TYPE_G0		1
-#define INT_TYPE_G1NS		2
+#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
diff --git a/include/plat/arm/common/aarch64/arm_macros.S b/include/plat/arm/common/aarch64/arm_macros.S
index 594b096..eaaa62f 100644
--- a/include/plat/arm/common/aarch64/arm_macros.S
+++ b/include/plat/arm/common/aarch64/arm_macros.S
@@ -31,12 +31,21 @@
 #define __ARM_MACROS_S__
 
 #include <cci.h>
-#include <gic_v2.h>
+#include <gic_common.h>
+#include <gicv2.h>
+#include <gicv3.h>
 #include <platform_def.h>
 
 .section .rodata.gic_reg_name, "aS"
+/* Applicable only to GICv2 and GICv3 with SRE disabled (legacy mode) */
 gicc_regs:
 	.asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
+
+/* Applicable only to GICv3 with SRE enabled */
+icc_regs:
+	.asciz "icc_hppir0_el1", "icc_hppir1_el1", "icc_ctlr_el3", ""
+
+/* Registers common to both GICv2 and GICv3 */
 gicd_pend_reg:
 	.asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n"	\
 		" Offset:\t\t\tvalue\n"
@@ -54,6 +63,28 @@
 	 * ---------------------------------------------
 	 */
 	.macro arm_print_gic_regs
+	/* Check for GICv3 system register access */
+	mrs	x7, id_aa64pfr0_el1
+	ubfx	x7, x7, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH
+	cmp	x7, #1
+	b.ne	print_gicv2
+
+	/* Check for SRE enable */
+	mrs	x8, ICC_SRE_EL3
+	tst	x8, #ICC_SRE_SRE_BIT
+	b.eq	print_gicv2
+
+	/* Load the icc reg list to x6 */
+	adr	x6, icc_regs
+	/* Load the icc regs to gp regs used by str_in_crash_buf_print */
+	mrs	x8, ICC_HPPIR0_EL1
+	mrs	x9, ICC_HPPIR1_EL1
+	mrs	x10, ICC_CTLR_EL3
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+	b	print_gic_common
+
+print_gicv2:
 	/* Load the gicc reg list to x6 */
 	adr	x6, gicc_regs
 	/* Load the gicc regs to gp regs used by str_in_crash_buf_print */
@@ -63,6 +94,7 @@
 	/* Store to the crash buf and print to console */
 	bl	str_in_crash_buf_print
 
+print_gic_common:
 	/* Print the GICD_ISPENDR regs */
 	add	x7, x16, #GICD_ISPENDR
 	adr	x4, gicd_pend_reg
diff --git a/include/plat/arm/common/arm_config.h b/include/plat/arm/common/arm_config.h
index 0b16127..24c1f0a 100644
--- a/include/plat/arm/common/arm_config.h
+++ b/include/plat/arm/common/arm_config.h
@@ -42,12 +42,6 @@
 };
 
 typedef struct arm_config {
-	uintptr_t gicd_base;
-	uintptr_t gicc_base;
-	uintptr_t gich_base;
-	uintptr_t gicv_base;
-	unsigned int max_aff0;
-	unsigned int max_aff1;
 	unsigned long flags;
 } arm_config_t;
 
diff --git a/include/plat/arm/common/arm_def.h b/include/plat/arm/common/arm_def.h
index 4726d5e..5c03feb 100644
--- a/include/plat/arm/common/arm_def.h
+++ b/include/plat/arm/common/arm_def.h
@@ -135,6 +135,22 @@
 #define ARM_IRQ_SEC_SGI_6		14
 #define ARM_IRQ_SEC_SGI_7		15
 
+/*
+ * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
+ * terminology. On a GICv2 system or mode, the lists will be merged and treated
+ * as Group 0 interrupts.
+ */
+#define ARM_G1S_IRQS			ARM_IRQ_SEC_PHY_TIMER,		\
+					ARM_IRQ_SEC_SGI_1,		\
+					ARM_IRQ_SEC_SGI_2,		\
+					ARM_IRQ_SEC_SGI_3,		\
+					ARM_IRQ_SEC_SGI_4,		\
+					ARM_IRQ_SEC_SGI_5,		\
+					ARM_IRQ_SEC_SGI_7
+
+#define ARM_G0_IRQS			ARM_IRQ_SEC_SGI_0,		\
+					ARM_IRQ_SEC_SGI_6
+
 #define ARM_SHARED_RAM_ATTR		((PLAT_ARM_SHARED_RAM_CACHED ?	\
 						MT_MEMORY : MT_DEVICE)	\
 						| MT_RW | MT_SECURE)
diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h
index aadf58d..f0b3ff6 100644
--- a/include/plat/arm/common/plat_arm.h
+++ b/include/plat/arm/common/plat_arm.h
@@ -37,7 +37,6 @@
 #include <stdint.h>
 #include <xlat_tables.h>
 
-
 /*
  * Extern declarations common to ARM standard platforms
  */
@@ -179,7 +178,11 @@
 /*
  * Mandatory functions required in ARM standard platforms
  */
+void plat_arm_gic_driver_init(void);
 void plat_arm_gic_init(void);
+void plat_arm_gic_cpuif_enable(void);
+void plat_arm_gic_cpuif_disable(void);
+void plat_arm_gic_pcpu_init(void);
 void plat_arm_security_setup(void);
 void plat_arm_pwrc_setup(void);
 
diff --git a/include/plat/arm/css/common/aarch64/css_macros.S b/include/plat/arm/css/common/aarch64/css_macros.S
index 2a26eb7..9f18e09 100644
--- a/include/plat/arm/css/common/aarch64/css_macros.S
+++ b/include/plat/arm/css/common/aarch64/css_macros.S
@@ -41,8 +41,8 @@
 	 * ---------------------------------------------
 	 */
 	.macro plat_print_gic_regs
-	mov_imm	x16, PLAT_CSS_GICD_BASE
-	mov_imm	x17, PLAT_CSS_GICC_BASE
+	mov_imm	x16, PLAT_ARM_GICD_BASE
+	mov_imm	x17, PLAT_ARM_GICC_BASE
 	arm_print_gic_regs
 	.endm
 
diff --git a/include/plat/arm/css/common/css_def.h b/include/plat/arm/css/common/css_def.h
index 98b69cb..99491f8 100644
--- a/include/plat/arm/css/common/css_def.h
+++ b/include/plat/arm/css/common/css_def.h
@@ -61,6 +61,16 @@
 #define CSS_IRQ_SEC_SYS_TIMER		91
 
 /*
+ * Define a list of Group 1 Secure interrupts as per GICv3 terminology. On a
+ * GICv2 system or mode, the interrupts will be treated as Group 0 interrupts.
+ */
+#define CSS_G1S_IRQS			CSS_IRQ_MHU,		\
+					CSS_IRQ_GPU_SMMU_0,	\
+					CSS_IRQ_TZC,		\
+					CSS_IRQ_TZ_WDOG,	\
+					CSS_IRQ_SEC_SYS_TIMER
+
+/*
  * SCP <=> AP boot configuration
  *
  * The SCP/AP boot configuration is a 32-bit word located at a known offset from
diff --git a/plat/arm/board/fvp/aarch64/fvp_common.c b/plat/arm/board/fvp/aarch64/fvp_common.c
index 8771e5b..e089405 100644
--- a/plat/arm/board/fvp/aarch64/fvp_common.c
+++ b/plat/arm/board/fvp/aarch64/fvp_common.c
@@ -30,14 +30,23 @@
 
 #include <arm_config.h>
 #include <arm_def.h>
-#include <arm_gic.h>
 #include <cci.h>
 #include <debug.h>
+#include <gicv2.h>
 #include <mmio.h>
 #include <plat_arm.h>
 #include <v2m_def.h>
 #include "../fvp_def.h"
 
+#if (FVP_USE_GIC_DRIVER == FVP_GICV2)
+extern gicv2_driver_data_t arm_gic_data;
+#endif
+
+/* Defines for GIC Driver build time selection */
+#define FVP_GICV2		1
+#define FVP_GICV3		2
+#define FVP_GICV3_LEGACY	3
+
 /*******************************************************************************
  * arm_config holds the characteristics of the differences between the three FVP
  * platforms (Base, A53_A57 & Foundation). It will be populated during cold boot
@@ -109,33 +118,6 @@
 
 ARM_CASSERT_MMAP
 
-
-#if IMAGE_BL31 || IMAGE_BL32
-/* Array of secure interrupts to be configured by the gic driver */
-const unsigned int irq_sec_array[] = {
-	ARM_IRQ_SEC_PHY_TIMER,
-	ARM_IRQ_SEC_SGI_0,
-	ARM_IRQ_SEC_SGI_1,
-	ARM_IRQ_SEC_SGI_2,
-	ARM_IRQ_SEC_SGI_3,
-	ARM_IRQ_SEC_SGI_4,
-	ARM_IRQ_SEC_SGI_5,
-	ARM_IRQ_SEC_SGI_6,
-	ARM_IRQ_SEC_SGI_7,
-	FVP_IRQ_TZ_WDOG,
-	FVP_IRQ_SEC_SYS_TIMER
-};
-
-void plat_arm_gic_init(void)
-{
-	arm_gic_init(arm_config.gicc_base,
-		arm_config.gicd_base,
-		BASE_GICR_BASE,
-		irq_sec_array,
-		ARRAY_SIZE(irq_sec_array));
-}
-
-#endif
 
 /*******************************************************************************
  * A single boot loader stack is expected to work on both the Foundation FVP
@@ -165,16 +147,28 @@
 	 */
 	switch (bld) {
 	case BLD_GIC_VE_MMAP:
-		arm_config.gicd_base = VE_GICD_BASE;
-		arm_config.gicc_base = VE_GICC_BASE;
-		arm_config.gich_base = VE_GICH_BASE;
-		arm_config.gicv_base = VE_GICV_BASE;
+#if IMAGE_BL31 || IMAGE_BL32
+#if FVP_USE_GIC_DRIVER == FVP_GICV2
+		/*
+		 * If the FVP implements the VE compatible memory map, then the
+		 * GICv2 driver must be included in the build. Update the platform
+		 * data with the correct GICv2 base addresses before it is used
+		 * to initialise the driver.
+		 *
+		 * This update of platform data is temporary and will be removed
+		 * once VE memory map for FVP is no longer supported by Trusted
+		 * Firmware.
+		 */
+		arm_gic_data.gicd_base = VE_GICD_BASE;
+		arm_gic_data.gicc_base = VE_GICC_BASE;
+
+#else
+		ERROR("Only GICv2 driver supported for VE memory map\n");
+		panic();
+#endif /* __FVP_USE_GIC_DRIVER == FVP_GICV2__ */
+#endif /* __IMAGE_BL31 || IMAGE_BL32__ */
 		break;
 	case BLD_GIC_A53A57_MMAP:
-		arm_config.gicd_base = BASE_GICD_BASE;
-		arm_config.gicc_base = BASE_GICC_BASE;
-		arm_config.gich_base = BASE_GICH_BASE;
-		arm_config.gicv_base = BASE_GICV_BASE;
 		break;
 	default:
 		ERROR("Unsupported board build %x\n", bld);
@@ -187,8 +181,6 @@
 	 */
 	switch (hbi) {
 	case HBI_FOUNDATION_FVP:
-		arm_config.max_aff0 = 4;
-		arm_config.max_aff1 = 1;
 		arm_config.flags = 0;
 
 		/*
@@ -206,8 +198,6 @@
 		}
 		break;
 	case HBI_BASE_FVP:
-		arm_config.max_aff0 = 4;
-		arm_config.max_aff1 = 2;
 		arm_config.flags |= ARM_CONFIG_BASE_MMAP |
 			ARM_CONFIG_HAS_CCI | ARM_CONFIG_HAS_TZC;
 
diff --git a/plat/arm/board/fvp/aarch64/fvp_helpers.S b/plat/arm/board/fvp/aarch64/fvp_helpers.S
index 2c24e61..338d158 100644
--- a/plat/arm/board/fvp/aarch64/fvp_helpers.S
+++ b/plat/arm/board/fvp/aarch64/fvp_helpers.S
@@ -30,7 +30,8 @@
 
 #include <arch.h>
 #include <asm_macros.S>
-#include <gic_v2.h>
+#include <gicv2.h>
+#include <gicv3.h>
 #include <platform_def.h>
 #include <v2m_def.h>
 #include "../drivers/pwrc/fvp_pwrc.h"
@@ -74,9 +75,26 @@
 	str	w0, [x1, #PPOFFR_OFF]
 
 	/* ---------------------------------------------
-	 * Deactivate the gic cpu interface as well
+	 * Disable GIC bypass as well
 	 * ---------------------------------------------
 	 */
+	/* Check for GICv3 system register access */
+	mrs	x0, id_aa64pfr0_el1
+	ubfx	x0, x0, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH
+	cmp	x0, #1
+	b.ne	gicv2_bypass_disable
+
+	/* Check for SRE enable */
+	mrs	x1, ICC_SRE_EL3
+	tst	x1, #ICC_SRE_SRE_BIT
+	b.eq	gicv2_bypass_disable
+
+	mrs	x2, ICC_SRE_EL3
+	orr	x2, x2, #(ICC_SRE_DIB_BIT | ICC_SRE_DFB_BIT)
+	msr	ICC_SRE_EL3, x2
+	b	secondary_cold_boot_wait
+
+gicv2_bypass_disable:
 	ldr	x0, =VE_GICC_BASE
 	ldr	x1, =BASE_GICC_BASE
 	fvp_choose_gicmmap	x0, x1, x2, w2, x1
@@ -84,6 +102,7 @@
 	orr	w0, w0, #(IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP0)
 	str	w0, [x1, #GICC_CTLR]
 
+secondary_cold_boot_wait:
 	/* ---------------------------------------------
 	 * There is no sane reason to come out of this
 	 * wfi so panic if we do. This cpu will be pow-
diff --git a/plat/arm/board/fvp/fvp_pm.c b/plat/arm/board/fvp/fvp_pm.c
index 21ad14f..c5129a6 100644
--- a/plat/arm/board/fvp/fvp_pm.c
+++ b/plat/arm/board/fvp/fvp_pm.c
@@ -30,7 +30,6 @@
 
 #include <arch_helpers.h>
 #include <arm_config.h>
-#include <arm_gic.h>
 #include <assert.h>
 #include <debug.h>
 #include <errno.h>
@@ -72,7 +71,7 @@
 static void fvp_cpu_pwrdwn_common(void)
 {
 	/* Prevent interrupts from spuriously waking up this cpu */
-	arm_gic_cpuif_deactivate();
+	plat_arm_gic_cpuif_disable();
 
 	/* Program the power controller to power off this cpu. */
 	fvp_pwrc_write_ppoffr(read_mpidr_el1());
@@ -93,6 +92,42 @@
 	fvp_pwrc_write_pcoffr(mpidr);
 }
 
+static void fvp_power_domain_on_finish_common(const psci_power_state_t *target_state)
+{
+	unsigned long mpidr;
+
+	assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
+					ARM_LOCAL_STATE_OFF);
+
+	/* Get the mpidr for this cpu */
+	mpidr = read_mpidr_el1();
+
+	/* Perform the common cluster specific operations */
+	if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
+					ARM_LOCAL_STATE_OFF) {
+		/*
+		 * This CPU might have woken up whilst the cluster was
+		 * attempting to power down. In this case the FVP power
+		 * controller will have a pending cluster power off request
+		 * which needs to be cleared by writing to the PPONR register.
+		 * This prevents the power controller from interpreting a
+		 * subsequent entry of this cpu into a simple wfi as a power
+		 * down request.
+		 */
+		fvp_pwrc_write_pponr(mpidr);
+
+		/* Enable coherency if this cluster was off */
+		fvp_cci_enable();
+	}
+
+	/*
+	 * Clear PWKUPR.WEN bit to ensure interrupts do not interfere
+	 * with a cpu power down unless the bit is set again
+	 */
+	fvp_pwrc_clr_wen(mpidr);
+}
+
+
 /*******************************************************************************
  * FVP handler called when a CPU is about to enter standby.
  ******************************************************************************/
@@ -196,43 +231,13 @@
  ******************************************************************************/
 void fvp_pwr_domain_on_finish(const psci_power_state_t *target_state)
 {
-	unsigned long mpidr;
-
-	assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
-					ARM_LOCAL_STATE_OFF);
-
-	/* Get the mpidr for this cpu */
-	mpidr = read_mpidr_el1();
-
-	/* Perform the common cluster specific operations */
-	if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
-					ARM_LOCAL_STATE_OFF) {
-		/*
-		 * This CPU might have woken up whilst the cluster was
-		 * attempting to power down. In this case the FVP power
-		 * controller will have a pending cluster power off request
-		 * which needs to be cleared by writing to the PPONR register.
-		 * This prevents the power controller from interpreting a
-		 * subsequent entry of this cpu into a simple wfi as a power
-		 * down request.
-		 */
-		fvp_pwrc_write_pponr(mpidr);
-
-		/* Enable coherency if this cluster was off */
-		fvp_cci_enable();
-	}
-
-	/*
-	 * Clear PWKUPR.WEN bit to ensure interrupts do not interfere
-	 * with a cpu power down unless the bit is set again
-	 */
-	fvp_pwrc_clr_wen(mpidr);
+	fvp_power_domain_on_finish_common(target_state);
 
 	/* Enable the gic cpu interface */
-	arm_gic_cpuif_setup();
+	plat_arm_gic_pcpu_init();
 
-	/* TODO: This setup is needed only after a cold boot */
-	arm_gic_pcpu_distif_setup();
+	/* Program the gic per-cpu distributor or re-distributor interface */
+	plat_arm_gic_cpuif_enable();
 }
 
 /*******************************************************************************
@@ -251,7 +256,10 @@
 					ARM_LOCAL_STATE_RET)
 		return;
 
-	fvp_pwr_domain_on_finish(target_state);
+	fvp_power_domain_on_finish_common(target_state);
+
+	/* Enable the gic cpu interface */
+	plat_arm_gic_cpuif_enable();
 }
 
 /*******************************************************************************
diff --git a/plat/arm/board/fvp/include/plat_macros.S b/plat/arm/board/fvp/include/plat_macros.S
index 2feffbe..2ed0d85 100644
--- a/plat/arm/board/fvp/include/plat_macros.S
+++ b/plat/arm/board/fvp/include/plat_macros.S
@@ -53,16 +53,14 @@
 	/* Check if VE mmap */
 	cmp	w16, #BLD_GIC_VE_MMAP
 	b.eq	use_ve_mmap
-	/* Check if Cortex-A53/A57 mmap */
-	cmp	w16, #BLD_GIC_A53A57_MMAP
-	b.ne	exit_print_gic_regs
+	/* Assume Base Cortex mmap */
 	mov_imm	x17, BASE_GICC_BASE
 	mov_imm	x16, BASE_GICD_BASE
-	b	print_gicc_regs
+	b	print_gic_regs
 use_ve_mmap:
 	mov_imm	x17, VE_GICC_BASE
 	mov_imm	x16, VE_GICD_BASE
-print_gicc_regs:
+print_gic_regs:
 	arm_print_gic_regs
 	.endm
 
diff --git a/plat/arm/board/fvp/include/platform_def.h b/plat/arm/board/fvp/include/platform_def.h
index 9ada6b2..9cb88de 100644
--- a/plat/arm/board/fvp/include/platform_def.h
+++ b/plat/arm/board/fvp/include/platform_def.h
@@ -121,5 +121,24 @@
 		TZC_REGION_ACCESS_RDWR(FVP_NSAID_VIRTIO)	|	\
 		TZC_REGION_ACCESS_RDWR(FVP_NSAID_VIRTIO_OLD))
 
+/*
+ * GIC related constants to cater for both GICv2 and GICv3 instances of an
+ * FVP. They could be overriden at runtime in case the FVP implements the legacy
+ * VE memory map.
+ */
+#define PLAT_ARM_GICD_BASE		BASE_GICD_BASE
+#define PLAT_ARM_GICR_BASE		BASE_GICR_BASE
+#define PLAT_ARM_GICC_BASE		BASE_GICC_BASE
+
+/*
+ * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
+ * terminology. On a GICv2 system or mode, the lists will be merged and treated
+ * as Group 0 interrupts.
+ */
+#define PLAT_ARM_G1S_IRQS		ARM_G1S_IRQS,			\
+					FVP_IRQ_TZ_WDOG,		\
+					FVP_IRQ_SEC_SYS_TIMER
+
+#define PLAT_ARM_G0_IRQS		ARM_G0_IRQS
 
 #endif /* __PLATFORM_DEF_H__ */
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index c46d3b7..b6f0739 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -28,6 +28,35 @@
 # POSSIBILITY OF SUCH DAMAGE.
 #
 
+# Use the Legacy GICv3 driver on the FVP by default to maintain compatibility.
+FVP_USE_GIC_DRIVER	:= FVP_GICV3_LEGACY
+
+# The FVP platform depends on this macro to build with correct GIC driver.
+$(eval $(call add_define,FVP_USE_GIC_DRIVER))
+
+# Choose the GIC sources depending upon the how the FVP will be invoked
+ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV3)
+FVP_GIC_SOURCES		:=	drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v3/gicv3_main.c		\
+				drivers/arm/gic/v3/gicv3_helpers.c	\
+				plat/common/plat_gicv3.c		\
+				plat/arm/common/arm_gicv3.c
+else ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV2)
+FVP_GIC_SOURCES		:=	drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v2/gicv2_main.c		\
+				drivers/arm/gic/v2/gicv2_helpers.c	\
+				plat/common/plat_gicv2.c		\
+				plat/arm/common/arm_gicv2.c
+else ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV3_LEGACY)
+FVP_GIC_SOURCES		:=	drivers/arm/gic/arm_gic.c		\
+				drivers/arm/gic/gic_v2.c		\
+				drivers/arm/gic/gic_v3.c		\
+				plat/common/plat_gic.c			\
+				plat/arm/common/arm_gicv3_legacy.c
+else
+$(error "Incorrect GIC driver chosen on FVP port")
+endif
+
 PLAT_INCLUDES		:=	-Iplat/arm/board/fvp/include
 
 
@@ -62,7 +91,8 @@
 				plat/arm/board/fvp/fvp_security.c		\
 				plat/arm/board/fvp/fvp_topology.c		\
 				plat/arm/board/fvp/aarch64/fvp_helpers.S	\
-				plat/arm/board/fvp/drivers/pwrc/fvp_pwrc.c
+				plat/arm/board/fvp/drivers/pwrc/fvp_pwrc.c	\
+				${FVP_GIC_SOURCES}
 
 # Disable the PSCI platform compatibility layer
 ENABLE_PLAT_COMPAT	:= 	0
diff --git a/plat/arm/board/fvp/tsp/tsp-fvp.mk b/plat/arm/board/fvp/tsp/tsp-fvp.mk
index 99db2f4..54a76fd 100644
--- a/plat/arm/board/fvp/tsp/tsp-fvp.mk
+++ b/plat/arm/board/fvp/tsp/tsp-fvp.mk
@@ -31,6 +31,7 @@
 # TSP source files specific to FVP platform
 BL32_SOURCES		+=	plat/arm/board/fvp/fvp_topology.c		\
 				plat/arm/board/fvp/drivers/pwrc/fvp_pwrc.c	\
-				plat/arm/board/fvp/tsp/fvp_tsp_setup.c
+				plat/arm/board/fvp/tsp/fvp_tsp_setup.c		\
+				${FVP_GIC_SOURCES}
 
 include plat/arm/common/tsp/arm_tsp.mk
diff --git a/plat/arm/board/juno/include/platform_def.h b/plat/arm/board/juno/include/platform_def.h
index 39283c5..924eb0a 100644
--- a/plat/arm/board/juno/include/platform_def.h
+++ b/plat/arm/board/juno/include/platform_def.h
@@ -94,17 +94,18 @@
  */
 
 /* GIC related constants (no GICR in GIC-400) */
-#define PLAT_CSS_GICD_BASE		0x2c010000
-#define PLAT_CSS_GICR_BASE		0x0
-#define PLAT_CSS_GICC_BASE		0x2c02f000
-#define PLAT_CSS_GICH_BASE		0x2c04f000
-#define PLAT_CSS_GICV_BASE		0x2c06f000
+#define PLAT_ARM_GICD_BASE		0x2c010000
+#define PLAT_ARM_GICC_BASE		0x2c02f000
+#define PLAT_ARM_GICH_BASE		0x2c04f000
+#define PLAT_ARM_GICV_BASE		0x2c06f000
 
-#define PLAT_CSS_IRQ_SEC_LIST		CSS_IRQ_MHU,			\
-					CSS_IRQ_GPU_SMMU_0,		\
-					CSS_IRQ_TZC,			\
-					CSS_IRQ_TZ_WDOG,		\
-					CSS_IRQ_SEC_SYS_TIMER,		\
+/*
+ * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
+ * terminology. On a GICv2 system or mode, the lists will be merged and treated
+ * as Group 0 interrupts.
+ */
+#define PLAT_ARM_G1S_IRQS		CSS_G1S_IRQS,			\
+					ARM_G1S_IRQS,			\
 					JUNO_IRQ_DMA_SMMU,		\
 					JUNO_IRQ_HDLCD0_SMMU,		\
 					JUNO_IRQ_HDLCD1_SMMU,		\
@@ -114,6 +115,8 @@
 					JUNO_IRQ_GPU_SMMU_1,		\
 					JUNO_IRQ_ETR_SMMU
 
+#define PLAT_ARM_G0_IRQS		ARM_G0_IRQS
+
 /*
  * Required ARM CSS SoC based platform porting definitions
  */
diff --git a/plat/arm/board/juno/platform.mk b/plat/arm/board/juno/platform.mk
index 127dcbe..0212fdd 100644
--- a/plat/arm/board/juno/platform.mk
+++ b/plat/arm/board/juno/platform.mk
@@ -28,6 +28,12 @@
 # POSSIBILITY OF SUCH DAMAGE.
 #
 
+JUNO_GIC_SOURCES	:=	drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v2/gicv2_main.c		\
+				drivers/arm/gic/v2/gicv2_helpers.c	\
+				plat/common/plat_gicv2.c		\
+				plat/arm/common/arm_gicv2.c
+
 PLAT_INCLUDES		:=	-Iplat/arm/board/juno/include
 
 PLAT_BL_COMMON_SOURCES	:=	plat/arm/board/juno/aarch64/juno_helpers.S
@@ -44,7 +50,8 @@
 				lib/cpus/aarch64/cortex_a57.S		\
 				lib/cpus/aarch64/cortex_a72.S		\
 				plat/arm/board/juno/juno_pm.c		\
-				plat/arm/board/juno/juno_security.c
+				plat/arm/board/juno/juno_security.c	\
+				${JUNO_GIC_SOURCES}
 
 # Enable workarounds for selected Cortex-A57 erratas.
 ERRATA_A57_806969	:=	0
diff --git a/plat/arm/board/juno/tsp/tsp-juno.mk b/plat/arm/board/juno/tsp/tsp-juno.mk
index bb67012..2ef964e 100644
--- a/plat/arm/board/juno/tsp/tsp-juno.mk
+++ b/plat/arm/board/juno/tsp/tsp-juno.mk
@@ -28,6 +28,7 @@
 # POSSIBILITY OF SUCH DAMAGE.
 #
 
-BL32_SOURCES		+=	plat/arm/css/common/css_topology.c
+BL32_SOURCES		+=	plat/arm/css/common/css_topology.c	\
+				${JUNO_GIC_SOURCES}
 
 include plat/arm/common/tsp/arm_tsp.mk
diff --git a/plat/arm/common/arm_bl31_setup.c b/plat/arm/common/arm_bl31_setup.c
index 8682fd1..50b98c7 100644
--- a/plat/arm/common/arm_bl31_setup.c
+++ b/plat/arm/common/arm_bl31_setup.c
@@ -31,7 +31,6 @@
 #include <arch.h>
 #include <arch_helpers.h>
 #include <arm_def.h>
-#include <arm_gic.h>
 #include <assert.h>
 #include <bl_common.h>
 #include <cci.h>
@@ -200,9 +199,9 @@
  ******************************************************************************/
 void arm_bl31_platform_setup(void)
 {
-	/* Initialize the gic cpu and distributor interfaces */
+	/* Initialize the GIC driver, cpu and distributor interfaces */
+	plat_arm_gic_driver_init();
 	plat_arm_gic_init();
-	arm_gic_setup();
 
 #if RESET_TO_BL31
 	/*
diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk
index 1290cef..1336e23 100644
--- a/plat/arm/common/arm_common.mk
+++ b/plat/arm/common/arm_common.mk
@@ -108,15 +108,11 @@
 
 BL31_SOURCES		+=	drivers/arm/cci/cci.c				\
 				drivers/arm/ccn/ccn.c				\
-				drivers/arm/gic/arm_gic.c			\
-				drivers/arm/gic/gic_v2.c			\
-				drivers/arm/gic/gic_v3.c			\
 				drivers/arm/tzc400/tzc400.c			\
 				plat/arm/common/arm_bl31_setup.c		\
 				plat/arm/common/arm_pm.c			\
 				plat/arm/common/arm_security.c			\
 				plat/arm/common/arm_topology.c			\
-				plat/common/plat_gic.c				\
 				plat/common/aarch64/platform_mp_stack.S		\
 				plat/common/aarch64/plat_psci_common.c
 
@@ -127,9 +123,9 @@
 
     # Include common TBB sources
     AUTH_SOURCES	:=	drivers/auth/auth_mod.c				\
-    				drivers/auth/crypto_mod.c			\
-    				drivers/auth/img_parser_mod.c			\
-    				drivers/auth/tbbr/tbbr_cot.c			\
+				drivers/auth/crypto_mod.c			\
+				drivers/auth/img_parser_mod.c			\
+				drivers/auth/tbbr/tbbr_cot.c			\
 
     BL1_SOURCES		+=	${AUTH_SOURCES}
     BL2_SOURCES		+=	${AUTH_SOURCES}
diff --git a/plat/arm/common/arm_gicv2.c b/plat/arm/common/arm_gicv2.c
new file mode 100644
index 0000000..76f04cd
--- /dev/null
+++ b/plat/arm/common/arm_gicv2.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <gicv2.h>
+#include <plat_arm.h>
+#include <platform.h>
+#include <platform_def.h>
+
+/******************************************************************************
+ * The following functions are defined as weak to allow a platform to override
+ * the way the GICv2 driver is initialised and used.
+ *****************************************************************************/
+#pragma weak plat_arm_gic_driver_init
+#pragma weak plat_arm_gic_init
+#pragma weak plat_arm_gic_cpuif_enable
+#pragma weak plat_arm_gic_cpuif_disable
+#pragma weak plat_arm_gic_pcpu_init
+
+/******************************************************************************
+ * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
+ * interrupts.
+ *****************************************************************************/
+const unsigned int g0_interrupt_array[] = {
+	PLAT_ARM_G1S_IRQS,
+	PLAT_ARM_G0_IRQS
+};
+
+/*
+ * Ideally `arm_gic_data` structure definition should be a `const` but it is
+ * kept as modifiable for overwriting with different GICD and GICC base when
+ * running on FVP with VE memory map.
+ */
+gicv2_driver_data_t arm_gic_data = {
+	.gicd_base = PLAT_ARM_GICD_BASE,
+	.gicc_base = PLAT_ARM_GICC_BASE,
+	.g0_interrupt_num = ARRAY_SIZE(g0_interrupt_array),
+	.g0_interrupt_array = g0_interrupt_array,
+};
+
+/******************************************************************************
+ * ARM common helper to initialize the GICv2 only driver.
+ *****************************************************************************/
+void plat_arm_gic_driver_init(void)
+{
+	gicv2_driver_init(&arm_gic_data);
+}
+
+void plat_arm_gic_init(void)
+{
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+}
+
+/******************************************************************************
+ * ARM common helper to enable the GICv2 CPU interface
+ *****************************************************************************/
+void plat_arm_gic_cpuif_enable(void)
+{
+	gicv2_cpuif_enable();
+}
+
+/******************************************************************************
+ * ARM common helper to disable the GICv2 CPU interface
+ *****************************************************************************/
+void plat_arm_gic_cpuif_disable(void)
+{
+	gicv2_cpuif_disable();
+}
+
+/******************************************************************************
+ * ARM common helper to initialize the per cpu distributor interface in GICv2
+ *****************************************************************************/
+void plat_arm_gic_pcpu_init(void)
+{
+	gicv2_pcpu_distif_init();
+}
diff --git a/plat/arm/common/arm_gicv3.c b/plat/arm/common/arm_gicv3.c
new file mode 100644
index 0000000..33f8018
--- /dev/null
+++ b/plat/arm/common/arm_gicv3.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <arm_def.h>
+#include <gicv3.h>
+#include <plat_arm.h>
+#include <platform.h>
+#include <platform_def.h>
+
+/******************************************************************************
+ * The following functions are defined as weak to allow a platform to override
+ * the way the GICv3 driver is initialised and used.
+ *****************************************************************************/
+#pragma weak plat_arm_gic_driver_init
+#pragma weak plat_arm_gic_init
+#pragma weak plat_arm_gic_cpuif_enable
+#pragma weak plat_arm_gic_cpuif_disable
+#pragma weak plat_arm_gic_pcpu_init
+
+/* The GICv3 driver only needs to be initialized in EL3 */
+uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+/* Array of Group1 secure interrupts to be configured by the gic driver */
+const unsigned int g1s_interrupt_array[] = {
+	PLAT_ARM_G1S_IRQS
+};
+
+/* Array of Group0 interrupts to be configured by the gic driver */
+const unsigned int g0_interrupt_array[] = {
+	PLAT_ARM_G0_IRQS
+};
+
+const gicv3_driver_data_t arm_gic_data = {
+	.gicd_base = PLAT_ARM_GICD_BASE,
+	.gicr_base = PLAT_ARM_GICR_BASE,
+	.g0_interrupt_num = ARRAY_SIZE(g0_interrupt_array),
+	.g1s_interrupt_num = ARRAY_SIZE(g1s_interrupt_array),
+	.g0_interrupt_array = g0_interrupt_array,
+	.g1s_interrupt_array = g1s_interrupt_array,
+	.rdistif_num = PLATFORM_CORE_COUNT,
+	.rdistif_base_addrs = rdistif_base_addrs,
+	.mpidr_to_core_pos = plat_arm_calc_core_pos
+};
+
+void plat_arm_gic_driver_init(void)
+{
+	/*
+	 * The GICv3 driver is initialized in EL3 and does not need
+	 * to be initialized again in SEL1. This is because the S-EL1
+	 * can use GIC system registers to manage interrupts and does
+	 * not need GIC interface base addresses to be configured.
+	 */
+#if IMAGE_BL31
+	gicv3_driver_init(&arm_gic_data);
+#endif
+}
+
+/******************************************************************************
+ * ARM common helper to initialize the GIC. Only invoked by BL31
+ *****************************************************************************/
+void plat_arm_gic_init(void)
+{
+	gicv3_distif_init();
+	gicv3_rdistif_init(plat_my_core_pos());
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * ARM common helper to enable the GIC CPU interface
+ *****************************************************************************/
+void plat_arm_gic_cpuif_enable(void)
+{
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * ARM common helper to disable the GIC CPU interface
+ *****************************************************************************/
+void plat_arm_gic_cpuif_disable(void)
+{
+	gicv3_cpuif_disable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * ARM common helper to initialize the per-cpu redistributor interface in GICv3
+ *****************************************************************************/
+void plat_arm_gic_pcpu_init(void)
+{
+	gicv3_rdistif_init(plat_my_core_pos());
+}
diff --git a/plat/arm/common/arm_gicv3_legacy.c b/plat/arm/common/arm_gicv3_legacy.c
new file mode 100644
index 0000000..6170933
--- /dev/null
+++ b/plat/arm/common/arm_gicv3_legacy.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <arm_def.h>
+#include <arm_gic.h>
+#include <plat_arm.h>
+#include <platform.h>
+#include <platform_def.h>
+
+/******************************************************************************
+ * The following function is defined as weak to allow a platform to override
+ * the way the Legacy GICv3 driver is initialised and used.
+ *****************************************************************************/
+#pragma weak plat_arm_gic_driver_init
+#pragma weak plat_arm_gic_init
+#pragma weak plat_arm_gic_cpuif_enable
+#pragma weak plat_arm_gic_cpuif_disable
+#pragma weak plat_arm_gic_pcpu_init
+
+/*
+ * In the GICv3 Legacy mode, the Group 1 secure interrupts are treated as Group
+ * 0 interrupts.
+ */
+const unsigned int irq_sec_array[] = {
+	PLAT_ARM_G0_IRQS,
+	PLAT_ARM_G1S_IRQS
+};
+
+void plat_arm_gic_driver_init(void)
+{
+	arm_gic_init(PLAT_ARM_GICC_BASE,
+		     PLAT_ARM_GICD_BASE,
+		     PLAT_ARM_GICR_BASE,
+		     irq_sec_array,
+		     ARRAY_SIZE(irq_sec_array));
+}
+
+/******************************************************************************
+ * ARM common helper to initialize the GIC.
+ *****************************************************************************/
+void plat_arm_gic_init(void)
+{
+	arm_gic_setup();
+}
+
+/******************************************************************************
+ * ARM common helper to enable the GIC CPU interface
+ *****************************************************************************/
+void plat_arm_gic_cpuif_enable(void)
+{
+	arm_gic_cpuif_setup();
+}
+
+/******************************************************************************
+ * ARM common helper to disable the GIC CPU interface
+ *****************************************************************************/
+void plat_arm_gic_cpuif_disable(void)
+{
+	arm_gic_cpuif_deactivate();
+}
+
+/******************************************************************************
+ * ARM common helper to initialize the per-cpu distributor in GICv2 or
+ * redistributor interface in GICv3.
+ *****************************************************************************/
+void plat_arm_gic_pcpu_init(void)
+{
+	arm_gic_pcpu_distif_setup();
+}
diff --git a/plat/arm/common/arm_pm.c b/plat/arm/common/arm_pm.c
index cae6597..bd5820b 100644
--- a/plat/arm/common/arm_pm.c
+++ b/plat/arm/common/arm_pm.c
@@ -164,9 +164,13 @@
 	/* Assert system power domain is available on the platform */
 	assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2);
 
-	arm_gic_setup();
+	/*
+	 * TODO: On GICv3 systems, figure out whether the core that wakes up
+	 * first from system suspend need to initialize the re-distributor
+	 * interface of all the other suspended cores.
+	 */
+	plat_arm_gic_init();
 	plat_arm_security_setup();
-
 	arm_configure_sys_timer();
 }
 
diff --git a/plat/arm/common/tsp/arm_tsp.mk b/plat/arm/common/tsp/arm_tsp.mk
index f285f58..691a2ab 100644
--- a/plat/arm/common/tsp/arm_tsp.mk
+++ b/plat/arm/common/tsp/arm_tsp.mk
@@ -29,9 +29,6 @@
 #
 
 # TSP source files common to ARM standard platforms
-BL32_SOURCES		+=	drivers/arm/gic/arm_gic.c			\
-				drivers/arm/gic/gic_v2.c			\
-				plat/arm/common/arm_topology.c			\
+BL32_SOURCES		+=	plat/arm/common/arm_topology.c			\
 				plat/arm/common/tsp/arm_tsp_setup.c		\
-				plat/common/aarch64/platform_mp_stack.S		\
-				plat/common/plat_gic.c
+				plat/common/aarch64/platform_mp_stack.S
diff --git a/plat/arm/common/tsp/arm_tsp_setup.c b/plat/arm/common/tsp/arm_tsp_setup.c
index 78db160..3631c03 100644
--- a/plat/arm/common/tsp/arm_tsp_setup.c
+++ b/plat/arm/common/tsp/arm_tsp_setup.c
@@ -89,7 +89,7 @@
  ******************************************************************************/
 void tsp_platform_setup(void)
 {
-	plat_arm_gic_init();
+	plat_arm_gic_driver_init();
 }
 
 /*******************************************************************************
diff --git a/plat/arm/css/common/css_common.c b/plat/arm/css/common/css_common.c
deleted file mode 100644
index 91813f2..0000000
--- a/plat/arm/css/common/css_common.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of ARM nor the names of its contributors may be used
- * to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <arm_gic.h>
-#include <bl_common.h>
-#include <platform_def.h>
-
-
-#if IMAGE_BL31 || IMAGE_BL32
-
-const unsigned int irq_sec_array[] = {
-	PLAT_CSS_IRQ_SEC_LIST,
-	ARM_IRQ_SEC_PHY_TIMER,
-	ARM_IRQ_SEC_SGI_0,
-	ARM_IRQ_SEC_SGI_1,
-	ARM_IRQ_SEC_SGI_2,
-	ARM_IRQ_SEC_SGI_3,
-	ARM_IRQ_SEC_SGI_4,
-	ARM_IRQ_SEC_SGI_5,
-	ARM_IRQ_SEC_SGI_6,
-	ARM_IRQ_SEC_SGI_7
-};
-
-
-/* Weak definitions may be overridden in specific CSS based platform */
-#pragma weak plat_arm_gic_init
-
-void plat_arm_gic_init(void)
-{
-	arm_gic_init(PLAT_CSS_GICC_BASE,
-		PLAT_CSS_GICD_BASE,
-		PLAT_CSS_GICR_BASE,
-		irq_sec_array,
-		ARRAY_SIZE(irq_sec_array));
-}
-
-#endif /* IMAGE_BL31 || IMAGE_BL32 */
diff --git a/plat/arm/css/common/css_common.mk b/plat/arm/css/common/css_common.mk
index 6b05869..6394197 100644
--- a/plat/arm/css/common/css_common.mk
+++ b/plat/arm/css/common/css_common.mk
@@ -32,8 +32,7 @@
 				-Iinclude/plat/arm/css/common/aarch64
 
 
-PLAT_BL_COMMON_SOURCES	+=	plat/arm/css/common/aarch64/css_helpers.S	\
-				plat/arm/css/common/css_common.c
+PLAT_BL_COMMON_SOURCES	+=	plat/arm/css/common/aarch64/css_helpers.S
 
 #BL1_SOURCES		+=
 
diff --git a/plat/arm/css/common/css_pm.c b/plat/arm/css/common/css_pm.c
index 3f46857..6d6646e 100644
--- a/plat/arm/css/common/css_pm.c
+++ b/plat/arm/css/common/css_pm.c
@@ -30,7 +30,6 @@
 
 #include <arch_helpers.h>
 #include <assert.h>
-#include <arm_gic.h>
 #include <cassert.h>
 #include <cci.h>
 #include <css_pm.h>
@@ -41,6 +40,12 @@
 #include <platform_def.h>
 #include "css_scpi.h"
 
+/* Macros to read the CSS power domain state */
+#define CSS_CORE_PWR_STATE(state)	(state)->pwr_domain_state[ARM_PWR_LVL0]
+#define CSS_CLUSTER_PWR_STATE(state)	(state)->pwr_domain_state[ARM_PWR_LVL1]
+#define CSS_SYSTEM_PWR_STATE(state)	((PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) ?\
+				(state)->pwr_domain_state[ARM_PWR_LVL2] : 0)
+
 /* Allow CSS platforms to override `plat_arm_psci_pm_ops` */
 #pragma weak plat_arm_psci_pm_ops
 
@@ -93,51 +98,39 @@
 	return PSCI_E_SUCCESS;
 }
 
-/*******************************************************************************
- * Handler called when a power level has just been powered on after
- * being turned off earlier. The target_state encodes the low power state that
- * each level has woken up from.
- ******************************************************************************/
-void css_pwr_domain_on_finish(const psci_power_state_t *target_state)
+static void css_pwr_domain_on_finisher_common(
+		const psci_power_state_t *target_state)
 {
-	assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
-						ARM_LOCAL_STATE_OFF);
-
-	if (PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) {
-		/*
-		 * Perform system initialization if woken up from system
-		 * suspend.
-		 */
-		if (target_state->pwr_domain_state[ARM_PWR_LVL2] ==
-							ARM_LOCAL_STATE_OFF)
-			arm_system_pwr_domain_resume();
-	}
+	assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF);
 
 	/*
 	 * Perform the common cluster specific operations i.e enable coherency
 	 * if this cluster was off.
 	 */
-	if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
-						ARM_LOCAL_STATE_OFF)
+	if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF)
 		cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+}
+
+/*******************************************************************************
+ * Handler called when a power level has just been powered on after
+ * being turned off earlier. The target_state encodes the low power state that
+ * each level has woken up from. This handler would never be invoked with
+ * the system power domain uninitialized as either the primary would have taken
+ * care of it as part of cold boot or the first core awakened from system
+ * suspend would have already initialized it.
+ ******************************************************************************/
+void css_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	/* Assert that the system power domain need not be initialized */
+	assert(CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_RUN);
 
+	css_pwr_domain_on_finisher_common(target_state);
 
-	if (PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) {
-		/*
-		 * Skip GIC CPU interface and per-CPU Distributor interface
-		 * setups if woken up from system suspend as it is done as
-		 * part of css_system_pwr_domain_resume().
-		 */
-		if (target_state->pwr_domain_state[ARM_PWR_LVL2] ==
-							ARM_LOCAL_STATE_OFF)
-			return;
-	}
+	/* Program the gic per-cpu distributor or re-distributor interface */
+	plat_arm_gic_pcpu_init();
 
 	/* Enable the gic cpu interface */
-	arm_gic_cpuif_setup();
-
-	/* todo: Is this setup only needed after a cold boot? */
-	arm_gic_pcpu_distif_setup();
+	plat_arm_gic_cpuif_enable();
 }
 
 /*******************************************************************************
@@ -152,21 +145,14 @@
 	uint32_t system_state = scpi_power_on;
 
 	/* Prevent interrupts from spuriously waking up this cpu */
-	arm_gic_cpuif_deactivate();
+	plat_arm_gic_cpuif_disable();
 
-	if (PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) {
-		/*
-		 * Check if power down at system power domain level is
-		 * requested.
-		 */
-		if (target_state->pwr_domain_state[ARM_PWR_LVL2] ==
-							ARM_LOCAL_STATE_OFF)
+	/* Check if power down at system power domain level is requested */
+	if (CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF)
 			system_state = scpi_power_retention;
-	}
 
 	/* Cluster is to be turned off, so disable coherency */
-	if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
-						ARM_LOCAL_STATE_OFF) {
+	if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) {
 		cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr()));
 		cluster_state = scpi_power_off;
 	}
@@ -187,9 +173,7 @@
  ******************************************************************************/
 void css_pwr_domain_off(const psci_power_state_t *target_state)
 {
-	assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
-						ARM_LOCAL_STATE_OFF);
-
+	assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF);
 	css_power_down_common(target_state);
 }
 
@@ -200,16 +184,13 @@
 void css_pwr_domain_suspend(const psci_power_state_t *target_state)
 {
 	/*
-	 * Juno has retention only at cpu level. Just return
+	 * CSS currently supports retention only at cpu level. Just return
 	 * as nothing is to be done for retention.
 	 */
-	if (target_state->pwr_domain_state[ARM_PWR_LVL0] ==
-						ARM_LOCAL_STATE_RET)
+	if (CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_RET)
 		return;
 
-	assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
-						ARM_LOCAL_STATE_OFF);
-
+	assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF);
 	css_power_down_common(target_state);
 }
 
@@ -223,14 +204,18 @@
 void css_pwr_domain_suspend_finish(
 				const psci_power_state_t *target_state)
 {
-	/*
-	 * Return as nothing is to be done on waking up from retention.
-	 */
-	if (target_state->pwr_domain_state[ARM_PWR_LVL0] ==
-						ARM_LOCAL_STATE_RET)
+	/* Return as nothing is to be done on waking up from retention. */
+	if (CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_RET)
 		return;
 
-	css_pwr_domain_on_finish(target_state);
+	/* Perform system domain restore if woken up from system suspend */
+	if (CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF)
+		arm_system_pwr_domain_resume();
+	else
+		/* Enable the gic cpu interface */
+		plat_arm_gic_cpuif_enable();
+
+	css_pwr_domain_on_finisher_common(target_state);
 }
 
 /*******************************************************************************
diff --git a/plat/common/plat_gicv2.c b/plat/common/plat_gicv2.c
new file mode 100644
index 0000000..65f89dc
--- /dev/null
+++ b/plat/common/plat_gicv2.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <assert.h>
+#include <gic_common.h>
+#include <gicv2.h>
+#include <interrupt_mgmt.h>
+
+/*
+ * The following platform GIC functions are weakly defined. They
+ * provide typical implementations that may be re-used by multiple
+ * platforms but may also be overridden by a platform if required.
+ */
+#pragma weak plat_ic_get_pending_interrupt_id
+#pragma weak plat_ic_get_pending_interrupt_type
+#pragma weak plat_ic_acknowledge_interrupt
+#pragma weak plat_ic_get_interrupt_type
+#pragma weak plat_ic_end_of_interrupt
+#pragma weak plat_interrupt_type_to_line
+
+/*
+ * This function returns the highest priority pending interrupt at
+ * the Interrupt controller
+ */
+uint32_t plat_ic_get_pending_interrupt_id(void)
+{
+	unsigned int id;
+
+	id = gicv2_get_pending_interrupt_id();
+	if (id == GIC_SPURIOUS_INTERRUPT)
+		return INTR_ID_UNAVAILABLE;
+
+	return id;
+}
+
+/*
+ * This function returns the type of the highest priority pending interrupt
+ * at the Interrupt controller. In the case of GICv2, the Highest Priority
+ * Pending interrupt register (`GICC_HPPIR`) is read to determine the id of
+ * the pending interrupt. The type of interrupt depends upon the id value
+ * as follows.
+ *   1. id < PENDING_G1_INTID (1022) is reported as a S-EL1 interrupt
+ *   2. id = PENDING_G1_INTID (1022) is reported as a Non-secure interrupt.
+ *   3. id = GIC_SPURIOUS_INTERRUPT (1023) is reported as an invalid interrupt
+ *           type.
+ */
+uint32_t plat_ic_get_pending_interrupt_type(void)
+{
+	unsigned int id;
+
+	id = gicv2_get_pending_interrupt_type();
+
+	/* Assume that all secure interrupts are S-EL1 interrupts */
+	if (id < PENDING_G1_INTID)
+		return INTR_TYPE_S_EL1;
+
+	if (id == GIC_SPURIOUS_INTERRUPT)
+		return INTR_TYPE_INVAL;
+
+	return INTR_TYPE_NS;
+}
+
+/*
+ * This function returns the highest priority pending interrupt at
+ * the Interrupt controller and indicates to the Interrupt controller
+ * that the interrupt processing has started.
+ */
+uint32_t plat_ic_acknowledge_interrupt(void)
+{
+	return gicv2_acknowledge_interrupt();
+}
+
+/*
+ * This function returns the type of the interrupt `id`, depending on how
+ * the interrupt has been configured in the interrupt controller
+ */
+uint32_t plat_ic_get_interrupt_type(uint32_t id)
+{
+	unsigned int type;
+
+	type = gicv2_get_interrupt_group(id);
+
+	/* Assume that all secure interrupts are S-EL1 interrupts */
+	return (type) ? INTR_TYPE_NS : INTR_TYPE_S_EL1;
+}
+
+/*
+ * This functions is used to indicate to the interrupt controller that
+ * the processing of the interrupt corresponding to the `id` has
+ * finished.
+ */
+void plat_ic_end_of_interrupt(uint32_t id)
+{
+	gicv2_end_of_interrupt(id);
+}
+
+/*
+ * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins.
+ * The interrupt controller knows which pin/line it uses to signal a type of
+ * interrupt. It lets the interrupt management framework determine
+ * for a type of interrupt and security state, which line should be used in the
+ * SCR_EL3 to control its routing to EL3. The interrupt line is represented
+ * as the bit position of the IRQ or FIQ bit in the SCR_EL3.
+ */
+uint32_t plat_interrupt_type_to_line(uint32_t type,
+				uint32_t security_state)
+{
+	assert(type == INTR_TYPE_S_EL1 ||
+		       type == INTR_TYPE_EL3 ||
+		       type == INTR_TYPE_NS);
+
+	/* Non-secure interrupts are signaled on the IRQ line always */
+	if (type == INTR_TYPE_NS)
+		return __builtin_ctz(SCR_IRQ_BIT);
+
+	/*
+	 * Secure interrupts are signaled using the IRQ line if the FIQ is
+	 * not enabled else they are signaled using the FIQ line.
+	 */
+	return ((gicv2_is_fiq_enabled()) ? __builtin_ctz(SCR_FIQ_BIT) :
+						__builtin_ctz(SCR_IRQ_BIT));
+}
diff --git a/plat/common/plat_gicv3.c b/plat/common/plat_gicv3.c
new file mode 100644
index 0000000..249caf8
--- /dev/null
+++ b/plat/common/plat_gicv3.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <arch_helpers.h>
+#include <assert.h>
+#include <bl_common.h>
+#include <cassert.h>
+#include <gic_common.h>
+#include <gicv3.h>
+#include <interrupt_mgmt.h>
+#include <platform.h>
+
+#if IMAGE_BL31
+
+/*
+ * The following platform GIC functions are weakly defined. They
+ * provide typical implementations that may be re-used by multiple
+ * platforms but may also be overridden by a platform if required.
+ */
+#pragma weak plat_ic_get_pending_interrupt_id
+#pragma weak plat_ic_get_pending_interrupt_type
+#pragma weak plat_ic_acknowledge_interrupt
+#pragma weak plat_ic_get_interrupt_type
+#pragma weak plat_ic_end_of_interrupt
+#pragma weak plat_interrupt_type_to_line
+
+CASSERT((INTR_TYPE_S_EL1 == INTR_GROUP1S) &&
+	(INTR_TYPE_NS == INTR_GROUP1NS) &&
+	(INTR_TYPE_EL3 == INTR_GROUP0), assert_interrupt_type_mismatch);
+
+/*
+ * This function returns the highest priority pending interrupt at
+ * the Interrupt controller
+ */
+uint32_t plat_ic_get_pending_interrupt_id(void)
+{
+	unsigned int irqnr;
+
+	assert(IS_IN_EL3());
+	irqnr = gicv3_get_pending_interrupt_id();
+	return (gicv3_is_intr_id_special_identifier(irqnr)) ?
+				INTR_ID_UNAVAILABLE : irqnr;
+}
+
+/*
+ * This function returns the type of the highest priority pending interrupt
+ * at the Interrupt controller. In the case of GICv3, the Highest Priority
+ * Pending interrupt system register (`ICC_HPPIR0_EL1`) is read to determine
+ * the id of the pending interrupt. The type of interrupt depends upon the
+ * id value as follows.
+ *   1. id = PENDING_G1S_INTID (1020) is reported as a S-EL1 interrupt
+ *   2. id = PENDING_G1NS_INTID (1021) is reported as a Non-secure interrupt.
+ *   3. id = GIC_SPURIOUS_INTERRUPT (1023) is reported as an invalid interrupt
+ *           type.
+ *   4. All other interrupt id's are reported as EL3 interrupt.
+ */
+uint32_t plat_ic_get_pending_interrupt_type(void)
+{
+	unsigned int irqnr;
+
+	assert(IS_IN_EL3());
+	irqnr = gicv3_get_pending_interrupt_type();
+
+	switch (irqnr) {
+	case PENDING_G1S_INTID:
+		return INTR_TYPE_S_EL1;
+	case PENDING_G1NS_INTID:
+		return INTR_TYPE_NS;
+	case GIC_SPURIOUS_INTERRUPT:
+		return INTR_TYPE_INVAL;
+	default:
+		return INTR_TYPE_EL3;
+	}
+}
+
+/*
+ * This function returns the highest priority pending interrupt at
+ * the Interrupt controller and indicates to the Interrupt controller
+ * that the interrupt processing has started.
+ */
+uint32_t plat_ic_acknowledge_interrupt(void)
+{
+	assert(IS_IN_EL3());
+	return gicv3_acknowledge_interrupt();
+}
+
+/*
+ * This function returns the type of the interrupt `id`, depending on how
+ * the interrupt has been configured in the interrupt controller
+ */
+uint32_t plat_ic_get_interrupt_type(uint32_t id)
+{
+	assert(IS_IN_EL3());
+	return gicv3_get_interrupt_type(id, plat_my_core_pos());
+}
+
+/*
+ * This functions is used to indicate to the interrupt controller that
+ * the processing of the interrupt corresponding to the `id` has
+ * finished.
+ */
+void plat_ic_end_of_interrupt(uint32_t id)
+{
+	assert(IS_IN_EL3());
+	gicv3_end_of_interrupt(id);
+}
+
+/*
+ * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins.
+ * The interrupt controller knows which pin/line it uses to signal a type of
+ * interrupt. It lets the interrupt management framework determine for a type of
+ * interrupt and security state, which line should be used in the SCR_EL3 to
+ * control its routing to EL3. The interrupt line is represented as the bit
+ * position of the IRQ or FIQ bit in the SCR_EL3.
+ */
+uint32_t plat_interrupt_type_to_line(uint32_t type,
+				uint32_t security_state)
+{
+	assert(type == INTR_TYPE_S_EL1 ||
+	       type == INTR_TYPE_EL3 ||
+	       type == INTR_TYPE_NS);
+
+	assert(sec_state_is_valid(security_state));
+	assert(IS_IN_EL3());
+
+	switch (type) {
+	case INTR_TYPE_S_EL1:
+		/*
+		 * The S-EL1 interrupts are signaled as IRQ in S-EL0/1 contexts
+		 * and as FIQ in the NS-EL0/1/2 contexts
+		 */
+		if (security_state == SECURE)
+			return __builtin_ctz(SCR_IRQ_BIT);
+		else
+			return __builtin_ctz(SCR_FIQ_BIT);
+	case INTR_TYPE_NS:
+		/*
+		 * The Non secure interrupts will be signaled as FIQ in S-EL0/1
+		 * contexts and as IRQ in the NS-EL0/1/2 contexts.
+		 */
+		if (security_state == SECURE)
+			return __builtin_ctz(SCR_FIQ_BIT);
+		else
+			return __builtin_ctz(SCR_IRQ_BIT);
+	default:
+		assert(0);
+		/* Fall through in the release build */
+	case INTR_TYPE_EL3:
+		/*
+		 * The EL3 interrupts are signaled as FIQ in both S-EL0/1 and
+		 * NS-EL0/1/2 contexts
+		 */
+		return __builtin_ctz(SCR_FIQ_BIT);
+	}
+}
+#endif
+#if IMAGE_BL32
+
+#pragma weak plat_ic_get_pending_interrupt_id
+#pragma weak plat_ic_acknowledge_interrupt
+#pragma weak plat_ic_end_of_interrupt
+
+/*
+ * This function returns the highest priority pending interrupt at
+ * the Interrupt controller
+ */
+uint32_t plat_ic_get_pending_interrupt_id(void)
+{
+	unsigned int irqnr;
+
+	assert(IS_IN_EL1());
+	irqnr = gicv3_get_pending_interrupt_id_sel1();
+	return (irqnr == GIC_SPURIOUS_INTERRUPT) ?
+				INTR_ID_UNAVAILABLE : irqnr;
+}
+
+/*
+ * This function returns the highest priority pending interrupt at
+ * the Interrupt controller and indicates to the Interrupt controller
+ * that the interrupt processing has started.
+ */
+uint32_t plat_ic_acknowledge_interrupt(void)
+{
+	assert(IS_IN_EL1());
+	return gicv3_acknowledge_interrupt_sel1();
+}
+
+/*
+ * This functions is used to indicate to the interrupt controller that
+ * the processing of the interrupt corresponding to the `id` has
+ * finished.
+ */
+void plat_ic_end_of_interrupt(uint32_t id)
+{
+	assert(IS_IN_EL1());
+	gicv3_end_of_interrupt_sel1(id);
+}
+#endif
diff --git a/services/spd/tspd/tspd.mk b/services/spd/tspd/tspd.mk
index 139c7d7..ede2504 100644
--- a/services/spd/tspd/tspd.mk
+++ b/services/spd/tspd/tspd.mk
@@ -55,7 +55,17 @@
 
 # Flag used to enable routing of non-secure interrupts to EL3 when they are
 # generated while the code is executing in S-EL1/0.
-TSPD_ROUTE_IRQ_TO_EL3	:=	0
+TSP_NS_INTR_ASYNC_PREEMPT	:=	0
+
+# If TSPD_ROUTE_IRQ_TO_EL3 build flag is defined, use it to define value for
+# TSP_NS_INTR_ASYNC_PREEMPT for backward compatibility.
+ifdef TSPD_ROUTE_IRQ_TO_EL3
+ifeq (${ERROR_DEPRECATED},1)
+$(error "TSPD_ROUTE_IRQ_TO_EL3 is deprecated. Please use the new build flag TSP_NS_INTR_ASYNC_PREEMPT")
+endif
+$(warning "TSPD_ROUTE_IRQ_TO_EL3 is deprecated. Please use the new build flag TSP_NS_INTR_ASYNC_PREEMPT")
+TSP_NS_INTR_ASYNC_PREEMPT	:= ${TSPD_ROUTE_IRQ_TO_EL3}
+endif
 
-$(eval $(call assert_boolean,TSPD_ROUTE_IRQ_TO_EL3))
-$(eval $(call add_define,TSPD_ROUTE_IRQ_TO_EL3))
+$(eval $(call assert_boolean,TSP_NS_INTR_ASYNC_PREEMPT))
+$(eval $(call add_define,TSP_NS_INTR_ASYNC_PREEMPT))
diff --git a/services/spd/tspd/tspd_main.c b/services/spd/tspd/tspd_main.c
index 6223160..4b89425 100644
--- a/services/spd/tspd/tspd_main.c
+++ b/services/spd/tspd/tspd_main.c
@@ -72,9 +72,16 @@
 
 int32_t tspd_init(void);
 
+/*
+ * This helper function handles Secure EL1 preemption. The preemption could be
+ * due Non Secure interrupts or EL3 interrupts. In both the cases we context
+ * switch to the normal world and in case of EL3 interrupts, it will again be
+ * routed to EL3 which will get handled at the exception vectors.
+ */
 uint64_t tspd_handle_sp_preemption(void *handle)
 {
 	cpu_context_t *ns_cpu_context;
+
 	assert(handle == cm_get_context(SECURE));
 	cm_el1_sysregs_context_save(SECURE);
 	/* Get a reference to the non-secure context */
@@ -82,18 +89,30 @@
 	assert(ns_cpu_context);
 
 	/*
+	 * To allow Secure EL1 interrupt handler to re-enter TSP while TSP
+	 * is preempted, the secure system register context which will get
+	 * overwritten must be additionally saved. This is currently done
+	 * by the TSPD S-EL1 interrupt handler.
+	 */
+
+	/*
-	 * Restore non-secure state. The secure system
-	 * register context will be saved when required.
+	 * Restore non-secure state.
 	 */
 	cm_el1_sysregs_context_restore(NON_SECURE);
 	cm_set_next_eret_context(NON_SECURE);
 
+	/*
+	 * The TSP was preempted during STD SMC execution.
+	 * Return back to the normal world with SMC_PREEMPTED as error
+	 * code in x0.
+	 */
 	SMC_RET1(ns_cpu_context, SMC_PREEMPTED);
 }
+
 /*******************************************************************************
  * This function is the handler registered for S-EL1 interrupts by the TSPD. It
  * validates the interrupt and upon success arranges entry into the TSP at
- * 'tsp_fiq_entry()' for handling the interrupt.
+ * 'tsp_sel1_intr_entry()' for handling the interrupt.
  ******************************************************************************/
 static uint64_t tspd_sel1_interrupt_handler(uint32_t id,
 					    uint32_t flags,
@@ -121,44 +140,44 @@
 	 * Determine if the TSP was previously preempted. Its last known
 	 * context has to be preserved in this case.
 	 * The TSP should return control to the TSPD after handling this
-	 * FIQ. Preserve essential EL3 context to allow entry into the
-	 * TSP at the FIQ entry point using the 'cpu_context' structure.
-	 * There is no need to save the secure system register context
-	 * since the TSP is supposed to preserve it during S-EL1 interrupt
-	 * handling.
+	 * S-EL1 interrupt. Preserve essential EL3 context to allow entry into
+	 * the TSP at the S-EL1 interrupt entry point using the 'cpu_context'
+	 * structure. There is no need to save the secure system register
+	 * context since the TSP is supposed to preserve it during S-EL1
+	 * interrupt handling.
 	 */
 	if (get_std_smc_active_flag(tsp_ctx->state)) {
 		tsp_ctx->saved_spsr_el3 = SMC_GET_EL3(&tsp_ctx->cpu_ctx,
 						      CTX_SPSR_EL3);
 		tsp_ctx->saved_elr_el3 = SMC_GET_EL3(&tsp_ctx->cpu_ctx,
 						     CTX_ELR_EL3);
-#if TSPD_ROUTE_IRQ_TO_EL3
+#if TSP_NS_INTR_ASYNC_PREEMPT
 		/*Need to save the previously interrupted secure context */
 		memcpy(&tsp_ctx->sp_ctx, &tsp_ctx->cpu_ctx, TSPD_SP_CTX_SIZE);
 #endif
 	}
 
 	cm_el1_sysregs_context_restore(SECURE);
-	cm_set_elr_spsr_el3(SECURE, (uint64_t) &tsp_vectors->fiq_entry,
+	cm_set_elr_spsr_el3(SECURE, (uint64_t) &tsp_vectors->sel1_intr_entry,
 		    SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS));
 
 	cm_set_next_eret_context(SECURE);
 
 	/*
-	 * Tell the TSP that it has to handle an FIQ synchronously. Also the
-	 * instruction in normal world where the interrupt was generated is
-	 * passed for debugging purposes. It is safe to retrieve this address
-	 * from ELR_EL3 as the secure context will not take effect until
-	 * el3_exit().
+	 * Tell the TSP that it has to handle a S-EL1 interrupt synchronously.
+	 * Also the instruction in normal world where the interrupt was
+	 * generated is passed for debugging purposes. It is safe to retrieve
+	 * this address from ELR_EL3 as the secure context will not take effect
+	 * until el3_exit().
 	 */
-	SMC_RET2(&tsp_ctx->cpu_ctx, TSP_HANDLE_FIQ_AND_RETURN, read_elr_el3());
+	SMC_RET2(&tsp_ctx->cpu_ctx, TSP_HANDLE_SEL1_INTR_AND_RETURN, read_elr_el3());
 }
 
-#if TSPD_ROUTE_IRQ_TO_EL3
+#if TSP_NS_INTR_ASYNC_PREEMPT
 /*******************************************************************************
- * This function is the handler registered for S-EL1 interrupts by the TSPD. It
- * validates the interrupt and upon success arranges entry into the TSP at
- * 'tsp_fiq_entry()' for handling the interrupt.
+ * This function is the handler registered for Non secure interrupts by the
+ * TSPD. It validates the interrupt and upon success arranges entry into the
+ * normal world for handling the interrupt.
  ******************************************************************************/
 static uint64_t tspd_ns_interrupt_handler(uint32_t id,
 					    uint32_t flags,
@@ -312,10 +331,11 @@
 
 	/*
 	 * This function ID is used only by the TSP to indicate that it has
-	 * finished handling a S-EL1 FIQ interrupt. Execution should resume
+	 * finished handling a S-EL1 interrupt or was preempted by a higher
+	 * priority pending EL3 interrupt. Execution should resume
 	 * in the normal world.
 	 */
-	case TSP_HANDLED_S_EL1_FIQ:
+	case TSP_HANDLED_S_EL1_INTR:
 		if (ns)
 			SMC_RET1(handle, SMC_UNK);
 
@@ -332,7 +352,7 @@
 			SMC_SET_EL3(&tsp_ctx->cpu_ctx,
 				    CTX_ELR_EL3,
 				    tsp_ctx->saved_elr_el3);
-#if TSPD_ROUTE_IRQ_TO_EL3
+#if TSP_NS_INTR_ASYNC_PREEMPT
 			/*
 			 * Need to restore the previously interrupted
 			 * secure context.
@@ -356,35 +376,6 @@
 
 		SMC_RET0((uint64_t) ns_cpu_context);
 
-
-	/*
-	 * This function ID is used only by the TSP to indicate that it was
-	 * interrupted due to a EL3 FIQ interrupt. Execution should resume
-	 * in the normal world.
-	 */
-	case TSP_EL3_FIQ:
-		if (ns)
-			SMC_RET1(handle, SMC_UNK);
-
-		assert(handle == cm_get_context(SECURE));
-
-		/* Assert that standard SMC execution has been preempted */
-		assert(get_std_smc_active_flag(tsp_ctx->state));
-
-		/* Save the secure system register state */
-		cm_el1_sysregs_context_save(SECURE);
-
-		/* Get a reference to the non-secure context */
-		ns_cpu_context = cm_get_context(NON_SECURE);
-		assert(ns_cpu_context);
-
-		/* Restore non-secure state */
-		cm_el1_sysregs_context_restore(NON_SECURE);
-		cm_set_next_eret_context(NON_SECURE);
-
-		SMC_RET1(ns_cpu_context, TSP_EL3_FIQ);
-
-
 	/*
 	 * This function ID is used only by the SP to indicate it has
 	 * finished initialising itself after a cold boot
@@ -422,7 +413,7 @@
 			if (rc)
 				panic();
 
-#if TSPD_ROUTE_IRQ_TO_EL3
+#if TSP_NS_INTR_ASYNC_PREEMPT
 			/*
 			 * Register an interrupt handler for NS interrupts when
 			 * generated during code executing in secure state are
@@ -438,8 +429,7 @@
 				panic();
 
 			/*
-			 * Disable the interrupt NS locally since it will be enabled globally
-			 * within cm_init_my_context.
+			 * Disable the NS interrupt locally.
 			 */
 			disable_intr_rm_local(INTR_TYPE_NS, SECURE);
 #endif
@@ -561,7 +551,7 @@
 				set_std_smc_active_flag(tsp_ctx->state);
 				cm_set_elr_el3(SECURE, (uint64_t)
 						&tsp_vectors->std_smc_entry);
-#if TSPD_ROUTE_IRQ_TO_EL3
+#if TSP_NS_INTR_ASYNC_PREEMPT
 				/*
 				 * Enable the routing of NS interrupts to EL3
 				 * during STD SMC processing on this core.
@@ -592,7 +582,7 @@
 			cm_set_next_eret_context(NON_SECURE);
 			if (GET_SMC_TYPE(smc_fid) == SMC_TYPE_STD) {
 				clr_std_smc_active_flag(tsp_ctx->state);
-#if TSPD_ROUTE_IRQ_TO_EL3
+#if TSP_NS_INTR_ASYNC_PREEMPT
 				/*
 				 * Disable the routing of NS interrupts to EL3
 				 * after STD SMC processing is finished on this
@@ -635,7 +625,7 @@
 		 * We are done stashing the non-secure context. Ask the
 		 * secure payload to do the work now.
 		 */
-#if TSPD_ROUTE_IRQ_TO_EL3
+#if TSP_NS_INTR_ASYNC_PREEMPT
 		/*
 		 * Enable the routing of NS interrupts to EL3 during resumption
 		 * of STD SMC call on this core.
diff --git a/services/spd/tspd/tspd_pm.c b/services/spd/tspd/tspd_pm.c
index 5089420..55562ba 100644
--- a/services/spd/tspd/tspd_pm.c
+++ b/services/spd/tspd/tspd_pm.c
@@ -130,7 +130,7 @@
 	/* Initialise this cpu's secure context */
 	cm_init_my_context(&tsp_on_entrypoint);
 
-#if TSPD_ROUTE_IRQ_TO_EL3
+#if TSP_NS_INTR_ASYNC_PREEMPT
 	/*
 	 * Disable the NS interrupt locally since it will be enabled globally
 	 * within cm_init_my_context.
diff --git a/services/spd/tspd/tspd_private.h b/services/spd/tspd/tspd_private.h
index 5f6fb2b..cadc6aa 100644
--- a/services/spd/tspd/tspd_private.h
+++ b/services/spd/tspd/tspd_private.h
@@ -183,10 +183,10 @@
 
 /*******************************************************************************
  * Structure which helps the SPD to maintain the per-cpu state of the SP.
- * 'saved_spsr_el3' - temporary copy to allow FIQ handling when the TSP has been
- *                    preempted.
- * 'saved_elr_el3'  - temporary copy to allow FIQ handling when the TSP has been
- *                    preempted.
+ * 'saved_spsr_el3' - temporary copy to allow S-EL1 interrupt handling when
+ *                    the TSP has been preempted.
+ * 'saved_elr_el3'  - temporary copy to allow S-EL1 interrupt handling when
+ *                    the TSP has been preempted.
  * 'state'          - collection of flags to track SP state e.g. on/off
  * 'mpidr'          - mpidr to associate a context with a cpu
  * 'c_rt_ctx'       - stack address to restore C runtime context from after
@@ -207,7 +207,7 @@
 	uint64_t c_rt_ctx;
 	cpu_context_t cpu_ctx;
 	uint64_t saved_tsp_args[TSP_NUM_ARGS];
-#if TSPD_ROUTE_IRQ_TO_EL3
+#if TSP_NS_INTR_ASYNC_PREEMPT
 	sp_ctx_regs_t sp_ctx;
 #endif
 } tsp_context_t;