Merge pull request #1130 from jeenu-arm/gic-patches

New GIC APIs and specifying interrupt propertes
diff --git a/Makefile b/Makefile
index a7d3a87..b32b417 100644
--- a/Makefile
+++ b/Makefile
@@ -449,6 +449,7 @@
 $(eval $(call assert_boolean,ENABLE_SPE_FOR_LOWER_ELS))
 $(eval $(call assert_boolean,ERROR_DEPRECATED))
 $(eval $(call assert_boolean,GENERATE_COT))
+$(eval $(call assert_boolean,GICV2_G0_FOR_EL3))
 $(eval $(call assert_boolean,HW_ASSISTED_COHERENCY))
 $(eval $(call assert_boolean,LOAD_IMAGE_V2))
 $(eval $(call assert_boolean,NS_TIMER_SWITCH))
@@ -486,6 +487,7 @@
 $(eval $(call add_define,ENABLE_RUNTIME_INSTRUMENTATION))
 $(eval $(call add_define,ENABLE_SPE_FOR_LOWER_ELS))
 $(eval $(call add_define,ERROR_DEPRECATED))
+$(eval $(call add_define,GICV2_G0_FOR_EL3))
 $(eval $(call add_define,HW_ASSISTED_COHERENCY))
 $(eval $(call add_define,LOAD_IMAGE_V2))
 $(eval $(call add_define,LOG_LEVEL))
diff --git a/docs/firmware-design.rst b/docs/firmware-design.rst
index e16e9b8..0790597 100644
--- a/docs/firmware-design.rst
+++ b/docs/firmware-design.rst
@@ -1167,6 +1167,56 @@
 already been performed and act as appropriate. Possible courses of actions are,
 e.g. skip the action the second time, or undo/redo it.
 
+Configuring secure interrupts
+-----------------------------
+
+The GIC driver is responsible for performing initial configuration of secure
+interrupts on the platform. To this end, the platform is expected to provide the
+GIC driver (either GICv2 or GICv3, as selected by the platform) with the
+interrupt configuration during the driver initialisation.
+
+There are two ways to specify secure interrupt configuration:
+
+#. Array of secure interrupt properties: In this scheme, in both GICv2 and GICv3
+   driver data structures, the ``interrupt_props`` member points to an array of
+   interrupt properties. Each element of the array specifies the interrupt
+   number and its configuration, viz. priority, group, configuration. Each
+   element of the array shall be populated by the macro ``INTR_PROP_DESC()``.
+   The macro takes the following arguments:
+
+   -  10-bit interrupt number,
+
+   -  8-bit interrupt priority,
+
+   -  Interrupt type (one of ``INTR_TYPE_EL3``, ``INTR_TYPE_S_EL1``,
+      ``INTR_TYPE_NS``),
+
+   -  Interrupt configuration (either ``GIC_INTR_CFG_LEVEL`` or
+      ``GIC_INTR_CFG_EDGE``).
+
+#. Array of secure interrupts: In this scheme, the GIC driver is provided an
+   array of secure interrupt numbers. The GIC driver, at the time of
+   initialisation, iterates through the array and assigns each interrupt
+   the appropriate group.
+
+   -  For the GICv2 driver, in ``gicv2_driver_data`` structure, the
+      ``g0_interrupt_array`` member of the should point to the array of
+      interrupts to be assigned to *Group 0*, and the ``g0_interrupt_num``
+      member of the should be set to the number of interrupts in the array.
+
+   -  For the GICv3 driver, in ``gicv3_driver_data`` structure:
+
+      -  The ``g0_interrupt_array`` member of the should point to the array of
+         interrupts to be assigned to *Group 0*, and the ``g0_interrupt_num``
+         member of the should be set to the number of interrupts in the array.
+
+      -  The ``g1s_interrupt_array`` member of the should point to the array of
+         interrupts to be assigned to *Group 1 Secure*, and the
+         ``g1s_interrupt_num`` member of the should be set to the number of
+         interrupts in the array.
+
+   **Note that this scheme is deprecated.**
+
 CPU specific operations framework
 ---------------------------------
 
diff --git a/docs/platform-interrupt-controller-API.rst b/docs/platform-interrupt-controller-API.rst
new file mode 100644
index 0000000..795c085
--- /dev/null
+++ b/docs/platform-interrupt-controller-API.rst
@@ -0,0 +1,297 @@
+Platform Interrupt Controller API documentation
+===============================================
+
+.. section-numbering::
+    :suffix: .
+
+.. contents::
+
+This document lists the optional platform interrupt controller API that
+abstracts the runtime configuration and control of interrupt controller from the
+generic code. The mandatory APIs are described in the `porting guide`__.
+
+.. __: porting-guide.rst#interrupt-management-framework-in-bl31
+
+Function: unsigned int plat_ic_get_running_priority(void); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : unsigned int
+
+This API should return the priority of the interrupt the PE is currently
+servicing. This must be be called only after an interrupt has already been
+acknowledged via. ``plat_ic_acknowledge_interrupt``.
+
+In the case of ARM standard platforms using GIC, the *Running Priority Register*
+is read to determine the priority of the interrupt.
+
+Function: int plat_ic_is_spi(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : int
+
+The API should return whether the interrupt ID (first parameter) is categorized
+as a Shared Peripheral Interrupt. Shared Peripheral Interrupts are typically
+associated to system-wide peripherals, and these interrupts can target any PE in
+the system.
+
+Function: int plat_ic_is_ppi(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : int
+
+The API should return whether the interrupt ID (first parameter) is categorized
+as a Private Peripheral Interrupt. Private Peripheral Interrupts are typically
+associated with peripherals that are private to each PE. Interrupts from private
+peripherals target to that PE only.
+
+Function: int plat_ic_is_sgi(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : int
+
+The API should return whether the interrupt ID (first parameter) is categorized
+as a Software Generated Interrupt. Software Generated Interrupts are raised by
+explicit programming by software, and are typically used in inter-PE
+communication. Secure SGIs are reserved for use by Secure world software.
+
+Function: unsigned int plat_ic_get_interrupt_active(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : int
+
+This API should return the *active* status of the interrupt ID specified by the
+first parameter, ``id``.
+
+In case of ARM standard platforms using GIC, the implementation of the API reads
+the GIC *Set Active Register* to read and return the active status of the
+interrupt.
+
+Function: void plat_ic_enable_interrupt(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : void
+
+This API should enable the interrupt ID specified by the first parameter,
+``id``. PEs in the system are expected to receive only enabled interrupts.
+
+In case of ARM standard platforms using GIC, the implementation of the API
+inserts barrier to make memory updates visible before enabling interrupt, and
+then writes to GIC *Set Enable Register* to enable the interrupt.
+
+Function: void plat_ic_disable_interrupt(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : void
+
+This API should disable the interrupt ID specified by the first parameter,
+``id``. PEs in the system are not expected to receive disabled interrupts.
+
+In case of ARM standard platforms using GIC, the implementation of the API
+writes to GIC *Clear Enable Register* to disable the interrupt, and inserts
+barrier to make memory updates visible afterwards.
+
+Function: void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Argument : unsigned int
+    Return   : void
+
+This API should set the priority of the interrupt specified by first parameter
+``id`` to the value set by the second parameter ``priority``.
+
+In case of ARM standard platforms using GIC, the implementation of the API
+writes to GIC *Priority Register* set interrupt priority.
+
+Function: int plat_ic_has_interrupt_type(unsigned int type); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : int
+
+This API should return whether the platform supports a given interrupt type. The
+parameter ``type`` shall be one of ``INTR_TYPE_EL3``, ``INTR_TYPE_S_EL1``, or
+``INTR_TYPE_NS``.
+
+In case of ARM standard platforms using GICv3, the implementation of the API
+returns ``1`` for all interrupt types.
+
+In case of ARM standard platforms using GICv2, the API always return ``1`` for
+``INTR_TYPE_NS``. Return value for other types depends on the value of build
+option ``GICV2_G0_FOR_EL3``:
+
+- For interrupt type ``INTR_TYPE_EL3``:
+
+  - When ``GICV2_G0_FOR_EL3`` is ``0``, it returns ``0``, indicating no support
+    for EL3 interrupts.
+
+  - When ``GICV2_G0_FOR_EL3`` is ``1``, it returns ``1``, indicating support for
+    EL3 interrupts.
+
+- For interrupt type ``INTR_TYPE_S_EL1``:
+
+  - When ``GICV2_G0_FOR_EL3`` is ``0``, it returns ``1``, indicating support for
+    Secure EL1 interrupts.
+
+  - When ``GICV2_G0_FOR_EL3`` is ``1``, it returns ``0``, indicating no support
+    for Secure EL1 interrupts.
+
+Function: void plat_ic_set_interrupt_type(unsigned int id, unsigned int type); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Argument : unsigned int
+    Return   : void
+
+This API should set the interrupt specified by first parameter ``id`` to the
+type specified by second parameter ``type``. The ``type`` parameter can be
+one of:
+
+- ``INTR_TYPE_NS``: interrupt is meant to be consumed by the Non-secure world.
+
+- ``INTR_TYPE_S_EL1``: interrupt is meant to be consumed by Secure EL1.
+
+- ``INTR_TYPE_EL3``: interrupt is meant to be consumed by EL3.
+
+In case of ARM standard platforms using GIC, the implementation of the API
+writes to the GIC *Group Register* and *Group Modifier Register* (only GICv3) to
+assign the interrupt to the right group.
+
+For GICv3:
+
+- ``INTR_TYPE_NS`` maps to Group 1 interrupt.
+
+- ``INTR_TYPE_S_EL1`` maps to Secure Group 1 interrupt.
+
+- ``INTR_TYPE_EL3`` maps to Secure Group 0 interrupt.
+
+For GICv2:
+
+- ``INTR_TYPE_NS`` maps to Group 1 interrupt.
+
+- When the build option ``GICV2_G0_FOR_EL3`` is set to ``0`` (the default),
+  ``INTR_TYPE_S_EL1`` maps to Group 0. Otherwise, ``INTR_TYPE_EL3`` maps to
+  Group 0 interrupt.
+
+Function: void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : int
+    Argument : u_register_t
+    Return   : void
+
+This API should raise an EL3 SGI. The first parameter, ``sgi_num``, specifies
+the ID of the SGI. The second parameter, ``target``, must be the MPIDR of the
+target PE.
+
+In case of ARM standard platforms using GIC, the implementation of the API
+inserts barrier to make memory updates visible before raising SGI, then writes
+to appropriate *SGI Register* in order to raise the EL3 SGI.
+
+Function: void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode, u_register_t mpidr); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Argument : unsigned int
+    Argument : u_register_t
+    Return   : void
+
+This API should set the routing mode of Share Peripheral Interrupt (SPI)
+specified by first parameter ``id`` to that specified by the second parameter
+``routing_mode``.
+
+The ``routing_mode`` parameter can be one of:
+
+- ``INTR_ROUTING_MODE_ANY`` means the interrupt can be routed to any PE in the
+  system. The ``mpidr`` parameter is ignored in this case.
+
+- ``INTR_ROUTING_MODE_PE`` means the interrupt is routed to the PE whose MPIDR
+  value is specified by the parameter ``mpidr``.
+
+In case of ARM standard platforms using GIC, the implementation of the API
+writes to the GIC *Target Register* (GICv2) or *Route Register* (GICv3) to set
+the routing.
+
+Function: void plat_ic_set_interrupt_pending(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : void
+
+This API should set the interrupt specified by first parameter ``id`` to
+*Pending*.
+
+In case of ARM standard platforms using GIC, the implementation of the API
+inserts barrier to make memory updates visible before setting interrupt pending,
+and writes to the GIC *Set Pending Register* to set the interrupt pending
+status.
+
+Function: void plat_ic_clear_interrupt_pending(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : void
+
+This API should clear the *Pending* status of the interrupt specified by first
+parameter ``id``.
+
+In case of ARM standard platforms using GIC, the implementation of the API
+writes to the GIC *Clear Pending Register* to clear the interrupt pending
+status, and inserts barrier to make memory updates visible afterwards.
+
+Function: unsigned int plat_ic_set_priority_mask(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : int
+
+This API should set the priority mask (first parameter) in the interrupt
+controller such that only interrupts of higher priority than the supplied one
+may be signalled to the PE. The API should return the current priority value
+that it's overwriting.
+
+In case of ARM standard platforms using GIC, the implementation of the API
+inserts to order memory updates before updating mask, then writes to the GIC
+*Priority Mask Register*, and make sure memory updates are visible before
+potential trigger due to mask update.
+
+----
+
+*Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.*
diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst
index cd3bcda..6352bb9 100644
--- a/docs/porting-guide.rst
+++ b/docs/porting-guide.rst
@@ -2327,6 +2327,10 @@
 GICv3 depending on the build flag ``FVP_USE_GIC_DRIVER`` (See FVP platform
 specific build options in `User Guide`_ for more details).
 
+See also: `Interrupt Controller Abstraction APIs`__.
+
+.. __: platform-interrupt-controller-API.rst
+
 Function : plat\_interrupt\_type\_to\_line() [mandatory]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -2674,7 +2678,7 @@
 
 --------------
 
-*Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.*
+*Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.*
 
 .. _Migration Guide: platform-migration-guide.rst
 .. _include/plat/common/platform.h: ../include/plat/common/platform.h
diff --git a/docs/user-guide.rst b/docs/user-guide.rst
index 7c0a980..28483f2 100644
--- a/docs/user-guide.rst
+++ b/docs/user-guide.rst
@@ -386,6 +386,19 @@
    images will include support for Trusted Board Boot, but the FIP and FWU\_FIP
    will not include the corresponding certificates, causing a boot failure.
 
+-  ``GICV2_G0_FOR_EL3``: Unlike GICv3, the GICv2 architecture doesn't have
+   inherent support for specific EL3 type interrupts. Setting this build option
+   to ``1`` assumes GICv2 *Group 0* interrupts are expected to target EL3, both
+   by `platform abstraction layer`__ and `Interrupt Management Framework`__.
+   This allows GICv2 platforms to enable features requiring EL3 interrupt type.
+   This also means that all GICv2 Group 0 interrupts are delivered to EL3, and
+   the Secure Payload interrupts needs to be synchronously handed over to Secure
+   EL1 for handling. The default value of this option is ``0``, which means the
+   Group 0 interrupts are assumed to be handled by Secure EL1.
+
+   .. __: `platform-interrupt-controller-API.rst`
+   .. __: `interrupt-framework-design.rst`
+
 -  ``HANDLE_EA_EL3_FIRST``: When defined External Aborts and SError Interrupts
    will be always trapped in EL3 i.e. in BL31 at runtime.
 
diff --git a/drivers/arm/gic/common/gic_common.c b/drivers/arm/gic/common/gic_common.c
index 6535813..d523772 100644
--- a/drivers/arm/gic/common/gic_common.c
+++ b/drivers/arm/gic/common/gic_common.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -273,6 +273,14 @@
 	gicd_write_icpendr(base, id, (1 << bit_num));
 }
 
+unsigned int gicd_get_isactiver(uintptr_t base, unsigned int id)
+{
+	unsigned int bit_num = id & ((1 << ISACTIVER_SHIFT) - 1);
+	unsigned int reg_val = gicd_read_isactiver(base, id);
+
+	return (reg_val >> bit_num) & 0x1;
+}
+
 void gicd_set_isactiver(uintptr_t base, unsigned int id)
 {
 	unsigned bit_num = id & ((1 << ISACTIVER_SHIFT) - 1);
@@ -291,3 +299,15 @@
 {
 	mmio_write_8(base + GICD_IPRIORITYR + id, pri & GIC_PRI_MASK);
 }
+
+void gicd_set_icfgr(uintptr_t base, unsigned int id, unsigned int cfg)
+{
+	unsigned bit_num = id & ((1 << ICFGR_SHIFT) - 1);
+	uint32_t reg_val = gicd_read_icfgr(base, id);
+
+	/* Clear the field, and insert required configuration */
+	reg_val &= ~(GIC_CFG_MASK << bit_num);
+	reg_val |= ((cfg & GIC_CFG_MASK) << bit_num);
+
+	gicd_write_icfgr(base, id, reg_val);
+}
diff --git a/drivers/arm/gic/common/gic_common_private.h b/drivers/arm/gic/common/gic_common_private.h
index 2077cc4..2021f9a 100644
--- a/drivers/arm/gic/common/gic_common_private.h
+++ b/drivers/arm/gic/common/gic_common_private.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -73,8 +73,10 @@
 void gicd_set_icenabler(uintptr_t base, unsigned int id);
 void gicd_set_ispendr(uintptr_t base, unsigned int id);
 void gicd_set_icpendr(uintptr_t base, unsigned int id);
+unsigned int gicd_get_isactiver(uintptr_t base, unsigned int id);
 void gicd_set_isactiver(uintptr_t base, unsigned int id);
 void gicd_set_icactiver(uintptr_t base, unsigned int id);
 void gicd_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri);
+void gicd_set_icfgr(uintptr_t base, unsigned int id, unsigned int cfg);
 
 #endif /* GIC_COMMON_PRIVATE_H_ */
diff --git a/drivers/arm/gic/v2/gicv2_helpers.c b/drivers/arm/gic/v2/gicv2_helpers.c
index 7cdbc27..0df50fb 100644
--- a/drivers/arm/gic/v2/gicv2_helpers.c
+++ b/drivers/arm/gic/v2/gicv2_helpers.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -9,6 +9,7 @@
 #include <assert.h>
 #include <debug.h>
 #include <gic_common.h>
+#include <interrupt_props.h>
 #include "../common/gic_common_private.h"
 #include "gicv2_private.h"
 
@@ -72,15 +73,6 @@
 	mmio_write_32(base + GICD_SPENDSGIR + (n << 2), val);
 }
 
-/*
- * Accessor to write the GIC Distributor ITARGETSR corresponding to the
- * interrupt `id`.
- */
-void gicd_set_itargetsr(uintptr_t base, unsigned int id, unsigned int target)
-{
-	mmio_write_8(base + GICD_ITARGETSR + id, target & GIC_TARGET_CPU_MASK);
-}
-
 /*******************************************************************************
  * Get the current CPU bit mask from GICD_ITARGETSR0
  ******************************************************************************/
@@ -121,6 +113,7 @@
 		gicd_write_icfgr(gicd_base, index, 0);
 }
 
+#if !ERROR_DEPRECATED
 /*******************************************************************************
  * Helper function to configure secure G0 SPIs.
  ******************************************************************************/
@@ -154,8 +147,50 @@
 	}
 
 }
+#endif
 
 /*******************************************************************************
+ * Helper function to configure properties of secure G0 SPIs.
+ ******************************************************************************/
+void gicv2_secure_spis_configure_props(uintptr_t gicd_base,
+		const interrupt_prop_t *interrupt_props,
+		unsigned int interrupt_props_num)
+{
+	unsigned int i;
+	const interrupt_prop_t *prop_desc;
+
+	/* Make sure there's a valid property array */
+	assert(interrupt_props_num != 0 ? (uintptr_t) interrupt_props : 1);
+
+	for (i = 0; i < interrupt_props_num; i++) {
+		prop_desc = &interrupt_props[i];
+
+		if (prop_desc->intr_num < MIN_SPI_ID)
+			continue;
+
+		/* Configure this interrupt as a secure interrupt */
+		assert(prop_desc->intr_grp == GICV2_INTR_GROUP0);
+		gicd_clr_igroupr(gicd_base, prop_desc->intr_num);
+
+		/* Set the priority of this interrupt */
+		gicd_set_ipriorityr(gicd_base, prop_desc->intr_num,
+				prop_desc->intr_pri);
+
+		/* Target the secure interrupts to primary CPU */
+		gicd_set_itargetsr(gicd_base, prop_desc->intr_num,
+				gicv2_get_cpuif_id(gicd_base));
+
+		/* Set interrupt configuration */
+		gicd_set_icfgr(gicd_base, prop_desc->intr_num,
+				prop_desc->intr_cfg);
+
+		/* Enable this interrupt */
+		gicd_set_isenabler(gicd_base, prop_desc->intr_num);
+	}
+}
+
+#if !ERROR_DEPRECATED
+/*******************************************************************************
  * Helper function to configure secure G0 SGIs and PPIs.
  ******************************************************************************/
 void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base,
@@ -202,3 +237,66 @@
 	/* Enable the Group 0 SGIs and PPIs */
 	gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask);
 }
+#endif
+
+/*******************************************************************************
+ * Helper function to configure properties of secure G0 SGIs and PPIs.
+ ******************************************************************************/
+void gicv2_secure_ppi_sgi_setup_props(uintptr_t gicd_base,
+		const interrupt_prop_t *interrupt_props,
+		unsigned int interrupt_props_num)
+{
+	unsigned int i;
+	uint32_t sec_ppi_sgi_mask = 0;
+	const interrupt_prop_t *prop_desc;
+
+	/* Make sure there's a valid property array */
+	assert(interrupt_props_num != 0 ? (uintptr_t) interrupt_props : 1);
+
+	/*
+	 * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a
+	 * more scalable approach as it avoids clearing the enable bits in the
+	 * GICD_CTLR.
+	 */
+	gicd_write_icenabler(gicd_base, 0, ~0);
+
+	/* Setup the default PPI/SGI priorities doing four at a time */
+	for (i = 0; i < MIN_SPI_ID; i += 4)
+		gicd_write_ipriorityr(gicd_base, i, GICD_IPRIORITYR_DEF_VAL);
+
+	for (i = 0; i < interrupt_props_num; i++) {
+		prop_desc = &interrupt_props[i];
+
+		if (prop_desc->intr_num >= MIN_SPI_ID)
+			continue;
+
+		/* Configure this interrupt as a secure interrupt */
+		assert(prop_desc->intr_grp == GICV2_INTR_GROUP0);
+
+		/*
+		 * Set interrupt configuration for PPIs. Configuration for SGIs
+		 * are ignored.
+		 */
+		if ((prop_desc->intr_num >= MIN_PPI_ID) &&
+				(prop_desc->intr_num < MIN_SPI_ID)) {
+			gicd_set_icfgr(gicd_base, prop_desc->intr_num,
+					prop_desc->intr_cfg);
+		}
+
+		/* We have an SGI or a PPI. They are Group0 at reset */
+		sec_ppi_sgi_mask |= (1u << prop_desc->intr_num);
+
+		/* Set the priority of this interrupt */
+		gicd_set_ipriorityr(gicd_base, prop_desc->intr_num,
+				prop_desc->intr_pri);
+	}
+
+	/*
+	 * Invert the bitmask to create a mask for non-secure PPIs and SGIs.
+	 * Program the GICD_IGROUPR0 with this bit mask.
+	 */
+	gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask);
+
+	/* Enable the Group 0 SGIs and PPIs */
+	gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask);
+}
diff --git a/drivers/arm/gic/v2/gicv2_main.c b/drivers/arm/gic/v2/gicv2_main.c
index deac927..25296a6 100644
--- a/drivers/arm/gic/v2/gicv2_main.c
+++ b/drivers/arm/gic/v2/gicv2_main.c
@@ -10,11 +10,20 @@
 #include <debug.h>
 #include <gic_common.h>
 #include <gicv2.h>
+#include <interrupt_props.h>
+#include <spinlock.h>
 #include "../common/gic_common_private.h"
 #include "gicv2_private.h"
 
 static const gicv2_driver_data_t *driver_data;
 
+/*
+ * Spinlock to guard registers needing read-modify-write. APIs protected by this
+ * spinlock are used either at boot time (when only a single CPU is active), or
+ * when the system is fully coherent.
+ */
+spinlock_t gic_lock;
+
 /*******************************************************************************
  * Enable secure interrupts and use FIQs to route them. Disable legacy bypass
  * and set the priority mask register to allow all interrupts to trickle in.
@@ -65,11 +74,21 @@
 {
 	assert(driver_data);
 	assert(driver_data->gicd_base);
-	assert(driver_data->g0_interrupt_array);
 
-	gicv2_secure_ppi_sgi_setup(driver_data->gicd_base,
-					driver_data->g0_interrupt_num,
-					driver_data->g0_interrupt_array);
+#if !ERROR_DEPRECATED
+	if (driver_data->interrupt_props != NULL) {
+#endif
+		gicv2_secure_ppi_sgi_setup_props(driver_data->gicd_base,
+				driver_data->interrupt_props,
+				driver_data->interrupt_props_num);
+#if !ERROR_DEPRECATED
+	} else {
+		assert(driver_data->g0_interrupt_array);
+		gicv2_secure_ppi_sgi_setup(driver_data->gicd_base,
+				driver_data->g0_interrupt_num,
+				driver_data->g0_interrupt_array);
+	}
+#endif
 }
 
 /*******************************************************************************
@@ -83,7 +102,6 @@
 
 	assert(driver_data);
 	assert(driver_data->gicd_base);
-	assert(driver_data->g0_interrupt_array);
 
 	/* Disable the distributor before going further */
 	ctlr = gicd_read_ctlr(driver_data->gicd_base);
@@ -93,10 +111,22 @@
 	/* Set the default attribute of all SPIs */
 	gicv2_spis_configure_defaults(driver_data->gicd_base);
 
-	/* Configure the G0 SPIs */
-	gicv2_secure_spis_configure(driver_data->gicd_base,
-					driver_data->g0_interrupt_num,
-					driver_data->g0_interrupt_array);
+#if !ERROR_DEPRECATED
+	if (driver_data->interrupt_props != NULL) {
+#endif
+		gicv2_secure_spis_configure_props(driver_data->gicd_base,
+				driver_data->interrupt_props,
+				driver_data->interrupt_props_num);
+#if !ERROR_DEPRECATED
+	} else {
+		assert(driver_data->g0_interrupt_array);
+
+		/* Configure the G0 SPIs */
+		gicv2_secure_spis_configure(driver_data->gicd_base,
+				driver_data->g0_interrupt_num,
+				driver_data->g0_interrupt_array);
+	}
+#endif
 
 	/* Re-enable the secure SPIs now that they have been configured */
 	gicd_write_ctlr(driver_data->gicd_base, ctlr | CTLR_ENABLE_G0_BIT);
@@ -112,19 +142,26 @@
 	assert(plat_driver_data->gicd_base);
 	assert(plat_driver_data->gicc_base);
 
-	/*
-	 * The platform should provide a list of atleast one type of
-	 * interrupts
-	 */
-	assert(plat_driver_data->g0_interrupt_array);
+#if !ERROR_DEPRECATED
+	if (plat_driver_data->interrupt_props == NULL) {
+		/* Interrupt properties array size must be 0 */
+		assert(plat_driver_data->interrupt_props_num == 0);
 
-	/*
-	 * If there are no interrupts of a particular type, then the number of
-	 * interrupts of that type should be 0 and vice-versa.
-	 */
-	assert(plat_driver_data->g0_interrupt_array ?
-	       plat_driver_data->g0_interrupt_num :
-	       plat_driver_data->g0_interrupt_num == 0);
+		/* The platform should provide a list of secure interrupts */
+		assert(plat_driver_data->g0_interrupt_array);
+
+		/*
+		 * If there are no interrupts of a particular type, then the
+		 * number of interrupts of that type should be 0 and vice-versa.
+		 */
+		assert(plat_driver_data->g0_interrupt_array ?
+				plat_driver_data->g0_interrupt_num :
+				plat_driver_data->g0_interrupt_num == 0);
+	}
+#else
+	assert(plat_driver_data->interrupt_props != NULL);
+	assert(plat_driver_data->interrupt_props_num > 0);
+#endif
 
 	/* Ensure that this is a GICv2 system */
 	gic_version = gicd_read_pidr2(plat_driver_data->gicd_base);
@@ -240,3 +277,255 @@
 
 	return gicd_get_igroupr(driver_data->gicd_base, id);
 }
+
+/*******************************************************************************
+ * This function returns the priority of the interrupt the processor is
+ * currently servicing.
+ ******************************************************************************/
+unsigned int gicv2_get_running_priority(void)
+{
+	assert(driver_data);
+	assert(driver_data->gicc_base);
+
+	return gicc_read_rpr(driver_data->gicc_base);
+}
+
+/*******************************************************************************
+ * This function sets the GICv2 target mask pattern for the current PE. The PE
+ * target mask is used to translate linear PE index (returned by platform core
+ * position) to a bit mask used when targeting interrupts to a PE, viz. when
+ * raising SGIs and routing SPIs.
+ ******************************************************************************/
+void gicv2_set_pe_target_mask(unsigned int proc_num)
+{
+	assert(driver_data);
+	assert(driver_data->gicd_base);
+	assert(driver_data->target_masks);
+	assert(proc_num < GICV2_MAX_TARGET_PE);
+	assert(proc_num < driver_data->target_masks_num);
+
+	/* Return if the target mask is already populated */
+	if (driver_data->target_masks[proc_num])
+		return;
+
+	/* Read target register corresponding to this CPU */
+	driver_data->target_masks[proc_num] =
+		gicv2_get_cpuif_id(driver_data->gicd_base);
+}
+
+/*******************************************************************************
+ * This function returns the active status of the interrupt (either because the
+ * state is active, or active and pending).
+ ******************************************************************************/
+unsigned int gicv2_get_interrupt_active(unsigned int id)
+{
+	assert(driver_data);
+	assert(driver_data->gicd_base);
+	assert(id <= MAX_SPI_ID);
+
+	return gicd_get_isactiver(driver_data->gicd_base, id);
+}
+
+/*******************************************************************************
+ * This function enables the interrupt identified by id.
+ ******************************************************************************/
+void gicv2_enable_interrupt(unsigned int id)
+{
+	assert(driver_data);
+	assert(driver_data->gicd_base);
+	assert(id <= MAX_SPI_ID);
+
+	/*
+	 * Ensure that any shared variable updates depending on out of band
+	 * interrupt trigger are observed before enabling interrupt.
+	 */
+	dsbishst();
+	gicd_set_isenabler(driver_data->gicd_base, id);
+}
+
+/*******************************************************************************
+ * This function disables the interrupt identified by id.
+ ******************************************************************************/
+void gicv2_disable_interrupt(unsigned int id)
+{
+	assert(driver_data);
+	assert(driver_data->gicd_base);
+	assert(id <= MAX_SPI_ID);
+
+	/*
+	 * Disable interrupt, and ensure that any shared variable updates
+	 * depending on out of band interrupt trigger are observed afterwards.
+	 */
+	gicd_set_icenabler(driver_data->gicd_base, id);
+	dsbishst();
+}
+
+/*******************************************************************************
+ * This function sets the interrupt priority as supplied for the given interrupt
+ * id.
+ ******************************************************************************/
+void gicv2_set_interrupt_priority(unsigned int id, unsigned int priority)
+{
+	assert(driver_data);
+	assert(driver_data->gicd_base);
+	assert(id <= MAX_SPI_ID);
+
+	gicd_set_ipriorityr(driver_data->gicd_base, id, priority);
+}
+
+/*******************************************************************************
+ * This function assigns group for the interrupt identified by id. The group can
+ * be any of GICV2_INTR_GROUP*
+ ******************************************************************************/
+void gicv2_set_interrupt_type(unsigned int id, unsigned int type)
+{
+	assert(driver_data);
+	assert(driver_data->gicd_base);
+	assert(id <= MAX_SPI_ID);
+
+	/* Serialize read-modify-write to Distributor registers */
+	spin_lock(&gic_lock);
+	switch (type) {
+	case GICV2_INTR_GROUP1:
+		gicd_set_igroupr(driver_data->gicd_base, id);
+		break;
+	case GICV2_INTR_GROUP0:
+		gicd_clr_igroupr(driver_data->gicd_base, id);
+		break;
+	default:
+		assert(0);
+	}
+	spin_unlock(&gic_lock);
+}
+
+/*******************************************************************************
+ * This function raises the specified SGI to requested targets.
+ *
+ * The proc_num parameter must be the linear index of the target PE in the
+ * system.
+ ******************************************************************************/
+void gicv2_raise_sgi(int sgi_num, int proc_num)
+{
+	unsigned int sgir_val, target;
+
+	assert(driver_data);
+	assert(proc_num < GICV2_MAX_TARGET_PE);
+	assert(driver_data->gicd_base);
+
+	/*
+	 * Target masks array must have been supplied, and the core position
+	 * should be valid.
+	 */
+	assert(driver_data->target_masks);
+	assert(proc_num < driver_data->target_masks_num);
+
+	/* Don't raise SGI if the mask hasn't been populated */
+	target = driver_data->target_masks[proc_num];
+	assert(target != 0);
+
+	sgir_val = GICV2_SGIR_VALUE(SGIR_TGT_SPECIFIC, target, sgi_num);
+
+	/*
+	 * Ensure that any shared variable updates depending on out of band
+	 * interrupt trigger are observed before raising SGI.
+	 */
+	dsbishst();
+	gicd_write_sgir(driver_data->gicd_base, sgir_val);
+}
+
+/*******************************************************************************
+ * This function sets the interrupt routing for the given SPI interrupt id.
+ * The interrupt routing is specified in routing mode. The proc_num parameter is
+ * linear index of the PE to target SPI. When proc_num < 0, the SPI may target
+ * all PEs.
+ ******************************************************************************/
+void gicv2_set_spi_routing(unsigned int id, int proc_num)
+{
+	int target;
+
+	assert(driver_data);
+	assert(driver_data->gicd_base);
+
+	assert(id >= MIN_SPI_ID && id <= MAX_SPI_ID);
+
+	/*
+	 * Target masks array must have been supplied, and the core position
+	 * should be valid.
+	 */
+	assert(driver_data->target_masks);
+	assert(proc_num < GICV2_MAX_TARGET_PE);
+	assert(proc_num < driver_data->target_masks_num);
+
+	if (proc_num < 0) {
+		/* Target all PEs */
+		target = GIC_TARGET_CPU_MASK;
+	} else {
+		/* Don't route interrupt if the mask hasn't been populated */
+		target = driver_data->target_masks[proc_num];
+		assert(target != 0);
+	}
+
+	gicd_set_itargetsr(driver_data->gicd_base, id, target);
+}
+
+/*******************************************************************************
+ * This function clears the pending status of an interrupt identified by id.
+ ******************************************************************************/
+void gicv2_clear_interrupt_pending(unsigned int id)
+{
+	assert(driver_data);
+	assert(driver_data->gicd_base);
+
+	/* SGIs can't be cleared pending */
+	assert(id >= MIN_PPI_ID);
+
+	/*
+	 * Clear pending interrupt, and ensure that any shared variable updates
+	 * depending on out of band interrupt trigger are observed afterwards.
+	 */
+	gicd_set_icpendr(driver_data->gicd_base, id);
+	dsbishst();
+}
+
+/*******************************************************************************
+ * This function sets the pending status of an interrupt identified by id.
+ ******************************************************************************/
+void gicv2_set_interrupt_pending(unsigned int id)
+{
+	assert(driver_data);
+	assert(driver_data->gicd_base);
+
+	/* SGIs can't be cleared pending */
+	assert(id >= MIN_PPI_ID);
+
+	/*
+	 * Ensure that any shared variable updates depending on out of band
+	 * interrupt trigger are observed before setting interrupt pending.
+	 */
+	dsbishst();
+	gicd_set_ispendr(driver_data->gicd_base, id);
+}
+
+/*******************************************************************************
+ * This function sets the PMR register with the supplied value. Returns the
+ * original PMR.
+ ******************************************************************************/
+unsigned int gicv2_set_pmr(unsigned int mask)
+{
+	unsigned int old_mask;
+
+	assert(driver_data);
+	assert(driver_data->gicc_base);
+
+	old_mask = gicc_read_pmr(driver_data->gicc_base);
+
+	/*
+	 * Order memory updates w.r.t. PMR write, and ensure they're visible
+	 * before potential out of band interrupt trigger because of PMR update.
+	 */
+	dmbishst();
+	gicc_write_pmr(driver_data->gicc_base, mask);
+	dsbishst();
+
+	return old_mask;
+}
diff --git a/drivers/arm/gic/v2/gicv2_private.h b/drivers/arm/gic/v2/gicv2_private.h
index 91ab43a..25600de 100644
--- a/drivers/arm/gic/v2/gicv2_private.h
+++ b/drivers/arm/gic/v2/gicv2_private.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -15,12 +15,20 @@
  * Private function prototypes
  ******************************************************************************/
 void gicv2_spis_configure_defaults(uintptr_t gicd_base);
+#if !ERROR_DEPRECATED
 void gicv2_secure_spis_configure(uintptr_t gicd_base,
 				     unsigned int num_ints,
 				     const unsigned int *sec_intr_list);
 void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base,
 					unsigned int num_ints,
 					const unsigned int *sec_intr_list);
+#endif
+void gicv2_secure_spis_configure_props(uintptr_t gicd_base,
+		const interrupt_prop_t *interrupt_props,
+		unsigned int interrupt_props_num);
+void gicv2_secure_ppi_sgi_setup_props(uintptr_t gicd_base,
+		const interrupt_prop_t *interrupt_props,
+		unsigned int interrupt_props_num);
 unsigned int gicv2_get_cpuif_id(uintptr_t base);
 
 /*******************************************************************************
@@ -32,6 +40,25 @@
 }
 
 /*******************************************************************************
+ * GIC Distributor interface accessors for writing entire registers
+ ******************************************************************************/
+static inline unsigned int gicd_get_itargetsr(uintptr_t base, unsigned int id)
+{
+	return mmio_read_8(base + GICD_ITARGETSR + id);
+}
+
+static inline void gicd_set_itargetsr(uintptr_t base, unsigned int id,
+		unsigned int target)
+{
+	mmio_write_8(base + GICD_ITARGETSR + id, target & GIC_TARGET_CPU_MASK);
+}
+
+static inline void gicd_write_sgir(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICD_SGIR, val);
+}
+
+/*******************************************************************************
  * GIC CPU interface accessors for reading entire registers
  ******************************************************************************/
 
@@ -80,6 +107,11 @@
 	return mmio_read_32(base + GICC_IIDR);
 }
 
+static inline unsigned int gicc_read_rpr(uintptr_t base)
+{
+	return mmio_read_32(base + GICC_RPR);
+}
+
 /*******************************************************************************
  * GIC CPU interface accessors for writing entire registers
  ******************************************************************************/
diff --git a/drivers/arm/gic/v3/gicv3_helpers.c b/drivers/arm/gic/v3/gicv3_helpers.c
index 73ad060..2522695 100644
--- a/drivers/arm/gic/v3/gicv3_helpers.c
+++ b/drivers/arm/gic/v3/gicv3_helpers.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -9,6 +9,7 @@
 #include <assert.h>
 #include <debug.h>
 #include <gic_common.h>
+#include <interrupt_props.h>
 #include "../common/gic_common_private.h"
 #include "gicv3_private.h"
 
@@ -172,6 +173,51 @@
 }
 
 /*
+ * Accessor to set the bit corresponding to interrupt ID in GIC Re-distributor
+ * ICENABLER0.
+ */
+void gicr_set_icenabler0(uintptr_t base, unsigned int id)
+{
+	unsigned bit_num = id & ((1 << ICENABLER_SHIFT) - 1);
+
+	gicr_write_icenabler0(base, (1 << bit_num));
+}
+
+/*
+ * Accessor to set the bit corresponding to interrupt ID in GIC Re-distributor
+ * ISACTIVER0.
+ */
+unsigned int gicr_get_isactiver0(uintptr_t base, unsigned int id)
+{
+	unsigned bit_num = id & ((1 << ISACTIVER_SHIFT) - 1);
+	unsigned int reg_val = gicr_read_isactiver0(base);
+
+	return (reg_val >> bit_num) & 0x1;
+}
+
+/*
+ * Accessor to clear the bit corresponding to interrupt ID in GIC Re-distributor
+ * ICPENDRR0.
+ */
+void gicr_set_icpendr0(uintptr_t base, unsigned int id)
+{
+	unsigned bit_num = id & ((1 << ICPENDR_SHIFT) - 1);
+
+	gicr_write_icpendr0(base, (1 << bit_num));
+}
+
+/*
+ * Accessor to set the bit corresponding to interrupt ID in GIC Re-distributor
+ * ISPENDR0.
+ */
+void gicr_set_ispendr0(uintptr_t base, unsigned int id)
+{
+	unsigned bit_num = id & ((1 << ISPENDR_SHIFT) - 1);
+
+	gicr_write_ispendr0(base, (1 << bit_num));
+}
+
+/*
  * Accessor to set the byte corresponding to interrupt ID
  * in GIC Re-distributor IPRIORITYR.
  */
@@ -180,6 +226,38 @@
 	mmio_write_8(base + GICR_IPRIORITYR + id, pri & GIC_PRI_MASK);
 }
 
+/*
+ * Accessor to set the bit fields corresponding to interrupt ID
+ * in GIC Re-distributor ICFGR0.
+ */
+void gicr_set_icfgr0(uintptr_t base, unsigned int id, unsigned int cfg)
+{
+	unsigned bit_num = id & ((1 << ICFGR_SHIFT) - 1);
+	uint32_t reg_val = gicr_read_icfgr0(base);
+
+	/* Clear the field, and insert required configuration */
+	reg_val &= ~(GIC_CFG_MASK << bit_num);
+	reg_val |= ((cfg & GIC_CFG_MASK) << bit_num);
+
+	gicr_write_icfgr0(base, reg_val);
+}
+
+/*
+ * Accessor to set the bit fields corresponding to interrupt ID
+ * in GIC Re-distributor ICFGR1.
+ */
+void gicr_set_icfgr1(uintptr_t base, unsigned int id, unsigned int cfg)
+{
+	unsigned bit_num = id & ((1 << ICFGR_SHIFT) - 1);
+	uint32_t reg_val = gicr_read_icfgr1(base);
+
+	/* Clear the field, and insert required configuration */
+	reg_val &= ~(GIC_CFG_MASK << bit_num);
+	reg_val |= ((cfg & GIC_CFG_MASK) << bit_num);
+
+	gicr_write_icfgr1(base, reg_val);
+}
+
 /******************************************************************************
  * This function marks the core as awake in the re-distributor and
  * ensures that the interface is active.
@@ -287,6 +365,7 @@
 		gicd_write_icfgr(gicd_base, index, 0);
 }
 
+#if !ERROR_DEPRECATED
 /*******************************************************************************
  * Helper function to configure secure G0 and G1S SPIs.
  ******************************************************************************/
@@ -333,6 +412,63 @@
 	}
 
 }
+#endif
+
+/*******************************************************************************
+ * Helper function to configure properties of secure SPIs
+ ******************************************************************************/
+unsigned int gicv3_secure_spis_configure_props(uintptr_t gicd_base,
+		const interrupt_prop_t *interrupt_props,
+		unsigned int interrupt_props_num)
+{
+	unsigned int i;
+	const interrupt_prop_t *current_prop;
+	unsigned long long gic_affinity_val;
+	unsigned int ctlr_enable = 0;
+
+	/* Make sure there's a valid property array */
+	assert(interrupt_props != NULL);
+	assert(interrupt_props_num > 0);
+
+	for (i = 0; i < interrupt_props_num; i++) {
+		current_prop = &interrupt_props[i];
+
+		if (current_prop->intr_num < MIN_SPI_ID)
+			continue;
+
+		/* Configure this interrupt as a secure interrupt */
+		gicd_clr_igroupr(gicd_base, current_prop->intr_num);
+
+		/* Configure this interrupt as G0 or a G1S interrupt */
+		assert((current_prop->intr_grp == INTR_GROUP0) ||
+				(current_prop->intr_grp == INTR_GROUP1S));
+		if (current_prop->intr_grp == INTR_GROUP1S) {
+			gicd_set_igrpmodr(gicd_base, current_prop->intr_num);
+			ctlr_enable |= CTLR_ENABLE_G1S_BIT;
+		} else {
+			gicd_clr_igrpmodr(gicd_base, current_prop->intr_num);
+			ctlr_enable |= CTLR_ENABLE_G0_BIT;
+		}
+
+		/* Set interrupt configuration */
+		gicd_set_icfgr(gicd_base, current_prop->intr_num,
+				current_prop->intr_cfg);
+
+		/* Set the priority of this interrupt */
+		gicd_set_ipriorityr(gicd_base, current_prop->intr_num,
+				current_prop->intr_pri);
+
+		/* Target SPIs to the primary CPU */
+		gic_affinity_val = gicd_irouter_val_from_mpidr(read_mpidr(), 0);
+		gicd_write_irouter(gicd_base, current_prop->intr_num,
+				gic_affinity_val);
+
+		/* Enable this interrupt */
+		gicd_set_isenabler(gicd_base, current_prop->intr_num);
+	}
+
+	return ctlr_enable;
+}
 
 /*******************************************************************************
  * Helper function to configure the default attributes of SPIs.
@@ -362,6 +498,7 @@
 	gicr_write_icfgr1(gicr_base, 0);
 }
 
+#if !ERROR_DEPRECATED
 /*******************************************************************************
  * Helper function to configure secure G0 and G1S SPIs.
  ******************************************************************************/
@@ -399,3 +536,54 @@
 		}
 	}
 }
+#endif
+
+/*******************************************************************************
+ * Helper function to configure properties of secure G0 and G1S PPIs and SGIs.
+ ******************************************************************************/
+void gicv3_secure_ppi_sgi_configure_props(uintptr_t gicr_base,
+		const interrupt_prop_t *interrupt_props,
+		unsigned int interrupt_props_num)
+{
+	unsigned int i;
+	const interrupt_prop_t *current_prop;
+
+	/* Make sure there's a valid property array */
+	assert(interrupt_props != NULL);
+	assert(interrupt_props_num > 0);
+
+	for (i = 0; i < interrupt_props_num; i++) {
+		current_prop = &interrupt_props[i];
+
+		if (current_prop->intr_num >= MIN_SPI_ID)
+			continue;
+
+		/* Configure this interrupt as a secure interrupt */
+		gicr_clr_igroupr0(gicr_base, current_prop->intr_num);
+
+		/* Configure this interrupt as G0 or a G1S interrupt */
+		assert((current_prop->intr_grp == INTR_GROUP0) ||
+				(current_prop->intr_grp == INTR_GROUP1S));
+		if (current_prop->intr_grp == INTR_GROUP1S)
+			gicr_set_igrpmodr0(gicr_base, current_prop->intr_num);
+		else
+			gicr_clr_igrpmodr0(gicr_base, current_prop->intr_num);
+
+		/* Set the priority of this interrupt */
+		gicr_set_ipriorityr(gicr_base, current_prop->intr_num,
+				current_prop->intr_pri);
+
+		/*
+		 * Set interrupt configuration for PPIs. Configuration for SGIs
+		 * are ignored.
+		 */
+		if ((current_prop->intr_num >= MIN_PPI_ID) &&
+				(current_prop->intr_num < MIN_SPI_ID)) {
+			gicr_set_icfgr1(gicr_base, current_prop->intr_num,
+					current_prop->intr_cfg);
+		}
+
+		/* Enable this interrupt */
+		gicr_set_isenabler0(gicr_base, current_prop->intr_num);
+	}
+}
diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c
index 1a018d8..8c4f508 100644
--- a/drivers/arm/gic/v3/gicv3_main.c
+++ b/drivers/arm/gic/v3/gicv3_main.c
@@ -9,12 +9,21 @@
 #include <assert.h>
 #include <debug.h>
 #include <gicv3.h>
+#include <interrupt_props.h>
+#include <spinlock.h>
 #include "gicv3_private.h"
 
 const gicv3_driver_data_t *gicv3_driver_data;
 static unsigned int gicv2_compat;
 
 /*
+ * Spinlock to guard registers needing read-modify-write. APIs protected by this
+ * spinlock are used either at boot time (when only a single CPU is active), or
+ * when the system is fully coherent.
+ */
+spinlock_t gic_lock;
+
+/*
  * Redistributor power operations are weakly bound so that they can be
  * overridden
  */
@@ -58,23 +67,33 @@
 
 	assert(IS_IN_EL3());
 
-	/*
-	 * The platform should provide a list of at least one type of
-	 * interrupts
-	 */
-	assert(plat_driver_data->g0_interrupt_array ||
-	       plat_driver_data->g1s_interrupt_array);
+#if !ERROR_DEPRECATED
+	if (plat_driver_data->interrupt_props == NULL) {
+		/* Interrupt properties array size must be 0 */
+		assert(plat_driver_data->interrupt_props_num == 0);
 
-	/*
-	 * If there are no interrupts of a particular type, then the number of
-	 * interrupts of that type should be 0 and vice-versa.
-	 */
-	assert(plat_driver_data->g0_interrupt_array ?
-	       plat_driver_data->g0_interrupt_num :
-	       plat_driver_data->g0_interrupt_num == 0);
-	assert(plat_driver_data->g1s_interrupt_array ?
-	       plat_driver_data->g1s_interrupt_num :
-	       plat_driver_data->g1s_interrupt_num == 0);
+		/*
+		 * The platform should provide a list of at least one type of
+		 * interrupt.
+		 */
+		assert(plat_driver_data->g0_interrupt_array ||
+				plat_driver_data->g1s_interrupt_array);
+
+		/*
+		 * If there are no interrupts of a particular type, then the
+		 * number of interrupts of that type should be 0 and vice-versa.
+		 */
+		assert(plat_driver_data->g0_interrupt_array ?
+				plat_driver_data->g0_interrupt_num :
+				plat_driver_data->g0_interrupt_num == 0);
+		assert(plat_driver_data->g1s_interrupt_array ?
+				plat_driver_data->g1s_interrupt_num :
+				plat_driver_data->g1s_interrupt_num == 0);
+	}
+#else
+	assert(plat_driver_data->interrupt_props != NULL);
+	assert(plat_driver_data->interrupt_props_num > 0);
+#endif
 
 	/* Check for system register support */
 #ifdef AARCH32
@@ -140,8 +159,6 @@
 
 	assert(gicv3_driver_data);
 	assert(gicv3_driver_data->gicd_base);
-	assert(gicv3_driver_data->g1s_interrupt_array ||
-	       gicv3_driver_data->g0_interrupt_array);
 
 	assert(IS_IN_EL3());
 
@@ -163,23 +180,37 @@
 	/* Set the default attribute of all SPIs */
 	gicv3_spis_configure_defaults(gicv3_driver_data->gicd_base);
 
-	/* Configure the G1S SPIs */
-	if (gicv3_driver_data->g1s_interrupt_array) {
-		gicv3_secure_spis_configure(gicv3_driver_data->gicd_base,
+#if !ERROR_DEPRECATED
+	if (gicv3_driver_data->interrupt_props != NULL) {
+#endif
+		bitmap = gicv3_secure_spis_configure_props(
+				gicv3_driver_data->gicd_base,
+				gicv3_driver_data->interrupt_props,
+				gicv3_driver_data->interrupt_props_num);
+#if !ERROR_DEPRECATED
+	} else {
+		assert(gicv3_driver_data->g1s_interrupt_array ||
+				gicv3_driver_data->g0_interrupt_array);
+
+		/* Configure the G1S SPIs */
+		if (gicv3_driver_data->g1s_interrupt_array) {
+			gicv3_secure_spis_configure(gicv3_driver_data->gicd_base,
 					gicv3_driver_data->g1s_interrupt_num,
 					gicv3_driver_data->g1s_interrupt_array,
 					INTR_GROUP1S);
-		bitmap |= CTLR_ENABLE_G1S_BIT;
-	}
+			bitmap |= CTLR_ENABLE_G1S_BIT;
+		}
 
-	/* Configure the G0 SPIs */
-	if (gicv3_driver_data->g0_interrupt_array) {
-		gicv3_secure_spis_configure(gicv3_driver_data->gicd_base,
+		/* Configure the G0 SPIs */
+		if (gicv3_driver_data->g0_interrupt_array) {
+			gicv3_secure_spis_configure(gicv3_driver_data->gicd_base,
 					gicv3_driver_data->g0_interrupt_num,
 					gicv3_driver_data->g0_interrupt_array,
 					INTR_GROUP0);
-		bitmap |= CTLR_ENABLE_G0_BIT;
+			bitmap |= CTLR_ENABLE_G0_BIT;
+		}
 	}
+#endif
 
 	/* Enable the secure SPIs now that they have been configured */
 	gicd_set_ctlr(gicv3_driver_data->gicd_base, bitmap, RWP_TRUE);
@@ -199,8 +230,6 @@
 	assert(gicv3_driver_data->rdistif_base_addrs);
 	assert(gicv3_driver_data->gicd_base);
 	assert(gicd_read_ctlr(gicv3_driver_data->gicd_base) & CTLR_ARE_S_BIT);
-	assert(gicv3_driver_data->g1s_interrupt_array ||
-	       gicv3_driver_data->g0_interrupt_array);
 
 	assert(IS_IN_EL3());
 
@@ -212,21 +241,34 @@
 	/* Set the default attribute of all SGIs and PPIs */
 	gicv3_ppi_sgi_configure_defaults(gicr_base);
 
-	/* Configure the G1S SGIs/PPIs */
-	if (gicv3_driver_data->g1s_interrupt_array) {
-		gicv3_secure_ppi_sgi_configure(gicr_base,
+#if !ERROR_DEPRECATED
+	if (gicv3_driver_data->interrupt_props != NULL) {
+#endif
+		gicv3_secure_ppi_sgi_configure_props(gicr_base,
+				gicv3_driver_data->interrupt_props,
+				gicv3_driver_data->interrupt_props_num);
+#if !ERROR_DEPRECATED
+	} else {
+		assert(gicv3_driver_data->g1s_interrupt_array ||
+		       gicv3_driver_data->g0_interrupt_array);
+
+		/* Configure the G1S SGIs/PPIs */
+		if (gicv3_driver_data->g1s_interrupt_array) {
+			gicv3_secure_ppi_sgi_configure(gicr_base,
 					gicv3_driver_data->g1s_interrupt_num,
 					gicv3_driver_data->g1s_interrupt_array,
 					INTR_GROUP1S);
-	}
+		}
 
-	/* Configure the G0 SGIs/PPIs */
-	if (gicv3_driver_data->g0_interrupt_array) {
-		gicv3_secure_ppi_sgi_configure(gicr_base,
+		/* Configure the G0 SGIs/PPIs */
+		if (gicv3_driver_data->g0_interrupt_array) {
+			gicv3_secure_ppi_sgi_configure(gicr_base,
 					gicv3_driver_data->g0_interrupt_num,
 					gicv3_driver_data->g0_interrupt_array,
 					INTR_GROUP0);
+		}
 	}
+#endif
 }
 
 /*******************************************************************************
@@ -769,3 +811,337 @@
 	gicd_wait_for_pending_write(gicd_base);
 
 }
+
+/*******************************************************************************
+ * This function gets the priority of the interrupt the processor is currently
+ * servicing.
+ ******************************************************************************/
+unsigned int gicv3_get_running_priority(void)
+{
+	return read_icc_rpr_el1();
+}
+
+/*******************************************************************************
+ * This function checks if the interrupt identified by id is active (whether the
+ * state is either active, or active and pending). The proc_num is used if the
+ * interrupt is SGI or PPI and programs the corresponding Redistributor
+ * interface.
+ ******************************************************************************/
+unsigned int gicv3_get_interrupt_active(unsigned int id, unsigned int proc_num)
+{
+	unsigned int value;
+
+	assert(gicv3_driver_data);
+	assert(gicv3_driver_data->gicd_base);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs);
+	assert(id <= MAX_SPI_ID);
+
+	if (id < MIN_SPI_ID) {
+		/* For SGIs and PPIs */
+		value = gicr_get_isactiver0(
+				gicv3_driver_data->rdistif_base_addrs[proc_num], id);
+	} else {
+		value = gicd_get_isactiver(gicv3_driver_data->gicd_base, id);
+	}
+
+	return value;
+}
+
+/*******************************************************************************
+ * This function enables the interrupt identified by id. The proc_num
+ * is used if the interrupt is SGI or PPI, and programs the corresponding
+ * Redistributor interface.
+ ******************************************************************************/
+void gicv3_enable_interrupt(unsigned int id, unsigned int proc_num)
+{
+	assert(gicv3_driver_data);
+	assert(gicv3_driver_data->gicd_base);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs);
+	assert(id <= MAX_SPI_ID);
+
+	/*
+	 * Ensure that any shared variable updates depending on out of band
+	 * interrupt trigger are observed before enabling interrupt.
+	 */
+	dsbishst();
+	if (id < MIN_SPI_ID) {
+		/* For SGIs and PPIs */
+		gicr_set_isenabler0(
+				gicv3_driver_data->rdistif_base_addrs[proc_num],
+				id);
+	} else {
+		gicd_set_isenabler(gicv3_driver_data->gicd_base, id);
+	}
+}
+
+/*******************************************************************************
+ * This function disables the interrupt identified by id. The proc_num
+ * is used if the interrupt is SGI or PPI, and programs the corresponding
+ * Redistributor interface.
+ ******************************************************************************/
+void gicv3_disable_interrupt(unsigned int id, unsigned int proc_num)
+{
+	assert(gicv3_driver_data);
+	assert(gicv3_driver_data->gicd_base);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs);
+	assert(id <= MAX_SPI_ID);
+
+	/*
+	 * Disable interrupt, and ensure that any shared variable updates
+	 * depending on out of band interrupt trigger are observed afterwards.
+	 */
+	if (id < MIN_SPI_ID) {
+		/* For SGIs and PPIs */
+		gicr_set_icenabler0(
+				gicv3_driver_data->rdistif_base_addrs[proc_num],
+				id);
+
+		/* Write to clear enable requires waiting for pending writes */
+		gicr_wait_for_pending_write(
+				gicv3_driver_data->rdistif_base_addrs[proc_num]);
+	} else {
+		gicd_set_icenabler(gicv3_driver_data->gicd_base, id);
+
+		/* Write to clear enable requires waiting for pending writes */
+		gicd_wait_for_pending_write(gicv3_driver_data->gicd_base);
+	}
+
+	dsbishst();
+}
+
+/*******************************************************************************
+ * This function sets the interrupt priority as supplied for the given interrupt
+ * id.
+ ******************************************************************************/
+void gicv3_set_interrupt_priority(unsigned int id, unsigned int proc_num,
+		unsigned int priority)
+{
+	uintptr_t gicr_base;
+
+	assert(gicv3_driver_data);
+	assert(gicv3_driver_data->gicd_base);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs);
+	assert(id <= MAX_SPI_ID);
+
+	if (id < MIN_SPI_ID) {
+		gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+		gicr_set_ipriorityr(gicr_base, id, priority);
+	} else {
+		gicd_set_ipriorityr(gicv3_driver_data->gicd_base, id, priority);
+	}
+}
+
+/*******************************************************************************
+ * This function assigns group for the interrupt identified by id. The proc_num
+ * is used if the interrupt is SGI or PPI, and programs the corresponding
+ * Redistributor interface. The group can be any of GICV3_INTR_GROUP*
+ ******************************************************************************/
+void gicv3_set_interrupt_type(unsigned int id, unsigned int proc_num,
+		unsigned int type)
+{
+	unsigned int igroup = 0, grpmod = 0;
+	uintptr_t gicr_base;
+
+	assert(gicv3_driver_data);
+	assert(gicv3_driver_data->gicd_base);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs);
+
+	switch (type) {
+	case INTR_GROUP1S:
+		igroup = 0;
+		grpmod = 1;
+		break;
+	case INTR_GROUP0:
+		igroup = 0;
+		grpmod = 0;
+		break;
+	case INTR_GROUP1NS:
+		igroup = 1;
+		grpmod = 0;
+		break;
+	default:
+		assert(0);
+	}
+
+	if (id < MIN_SPI_ID) {
+		gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+		if (igroup)
+			gicr_set_igroupr0(gicr_base, id);
+		else
+			gicr_clr_igroupr0(gicr_base, id);
+
+		if (grpmod)
+			gicr_set_igrpmodr0(gicr_base, id);
+		else
+			gicr_clr_igrpmodr0(gicr_base, id);
+	} else {
+		/* Serialize read-modify-write to Distributor registers */
+		spin_lock(&gic_lock);
+		if (igroup)
+			gicd_set_igroupr(gicv3_driver_data->gicd_base, id);
+		else
+			gicd_clr_igroupr(gicv3_driver_data->gicd_base, id);
+
+		if (grpmod)
+			gicd_set_igrpmodr(gicv3_driver_data->gicd_base, id);
+		else
+			gicd_clr_igrpmodr(gicv3_driver_data->gicd_base, id);
+		spin_unlock(&gic_lock);
+	}
+}
+
+/*******************************************************************************
+ * This function raises the specified Secure Group 0 SGI.
+ *
+ * The target parameter must be a valid MPIDR in the system.
+ ******************************************************************************/
+void gicv3_raise_secure_g0_sgi(int sgi_num, u_register_t target)
+{
+	unsigned int tgt, aff3, aff2, aff1, aff0;
+	uint64_t sgi_val;
+
+	/* Verify interrupt number is in the SGI range */
+	assert((sgi_num >= MIN_SGI_ID) && (sgi_num < MIN_PPI_ID));
+
+	/* Extract affinity fields from target */
+	aff0 = MPIDR_AFFLVL0_VAL(target);
+	aff1 = MPIDR_AFFLVL1_VAL(target);
+	aff2 = MPIDR_AFFLVL2_VAL(target);
+	aff3 = MPIDR_AFFLVL3_VAL(target);
+
+	/*
+	 * Make target list from affinity 0, and ensure GICv3 SGI can target
+	 * this PE.
+	 */
+	assert(aff0 < GICV3_MAX_SGI_TARGETS);
+	tgt = BIT(aff0);
+
+	/* Raise SGI to PE specified by its affinity */
+	sgi_val = GICV3_SGIR_VALUE(aff3, aff2, aff1, sgi_num, SGIR_IRM_TO_AFF,
+			tgt);
+
+	/*
+	 * Ensure that any shared variable updates depending on out of band
+	 * interrupt trigger are observed before raising SGI.
+	 */
+	dsbishst();
+	write_icc_sgi0r_el1(sgi_val);
+	isb();
+}
+
+/*******************************************************************************
+ * This function sets the interrupt routing for the given SPI interrupt id.
+ * The interrupt routing is specified in routing mode and mpidr.
+ *
+ * The routing mode can be either of:
+ *  - GICV3_IRM_ANY
+ *  - GICV3_IRM_PE
+ *
+ * The mpidr is the affinity of the PE to which the interrupt will be routed,
+ * and is ignored for routing mode GICV3_IRM_ANY.
+ ******************************************************************************/
+void gicv3_set_spi_routing(unsigned int id, unsigned int irm, u_register_t mpidr)
+{
+	unsigned long long aff;
+	uint64_t router;
+
+	assert(gicv3_driver_data);
+	assert(gicv3_driver_data->gicd_base);
+
+	assert((irm == GICV3_IRM_ANY) || (irm == GICV3_IRM_PE));
+	assert(id >= MIN_SPI_ID && id <= MAX_SPI_ID);
+
+	aff = gicd_irouter_val_from_mpidr(mpidr, irm);
+	gicd_write_irouter(gicv3_driver_data->gicd_base, id, aff);
+
+	/*
+	 * In implementations that do not require 1 of N distribution of SPIs,
+	 * IRM might be RAZ/WI. Read back and verify IRM bit.
+	 */
+	if (irm == GICV3_IRM_ANY) {
+		router = gicd_read_irouter(gicv3_driver_data->gicd_base, id);
+		if (!((router >> IROUTER_IRM_SHIFT) & IROUTER_IRM_MASK)) {
+			ERROR("GICv3 implementation doesn't support routing ANY\n");
+			panic();
+		}
+	}
+}
+
+/*******************************************************************************
+ * This function clears the pending status of an interrupt identified by id.
+ * The proc_num is used if the interrupt is SGI or PPI, and programs the
+ * corresponding Redistributor interface.
+ ******************************************************************************/
+void gicv3_clear_interrupt_pending(unsigned int id, unsigned int proc_num)
+{
+	assert(gicv3_driver_data);
+	assert(gicv3_driver_data->gicd_base);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs);
+
+	/*
+	 * Clear pending interrupt, and ensure that any shared variable updates
+	 * depending on out of band interrupt trigger are observed afterwards.
+	 */
+	if (id < MIN_SPI_ID) {
+		/* For SGIs and PPIs */
+		gicr_set_icpendr0(gicv3_driver_data->rdistif_base_addrs[proc_num],
+				id);
+	} else {
+		gicd_set_icpendr(gicv3_driver_data->gicd_base, id);
+	}
+	dsbishst();
+}
+
+/*******************************************************************************
+ * This function sets the pending status of an interrupt identified by id.
+ * The proc_num is used if the interrupt is SGI or PPI and programs the
+ * corresponding Redistributor interface.
+ ******************************************************************************/
+void gicv3_set_interrupt_pending(unsigned int id, unsigned int proc_num)
+{
+	assert(gicv3_driver_data);
+	assert(gicv3_driver_data->gicd_base);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs);
+
+	/*
+	 * Ensure that any shared variable updates depending on out of band
+	 * interrupt trigger are observed before setting interrupt pending.
+	 */
+	dsbishst();
+	if (id < MIN_SPI_ID) {
+		/* For SGIs and PPIs */
+		gicr_set_ispendr0(gicv3_driver_data->rdistif_base_addrs[proc_num],
+				id);
+	} else {
+		gicd_set_ispendr(gicv3_driver_data->gicd_base, id);
+	}
+}
+
+/*******************************************************************************
+ * This function sets the PMR register with the supplied value. Returns the
+ * original PMR.
+ ******************************************************************************/
+unsigned int gicv3_set_pmr(unsigned int mask)
+{
+	unsigned int old_mask;
+
+	old_mask = read_icc_pmr_el1();
+
+	/*
+	 * Order memory updates w.r.t. PMR write, and ensure they're visible
+	 * before potential out of band interrupt trigger because of PMR update.
+	 * PMR system register writes are self-synchronizing, so no ISB required
+	 * thereafter.
+	 */
+	dsbishst();
+	write_icc_pmr_el1(mask);
+
+	return old_mask;
+}
diff --git a/drivers/arm/gic/v3/gicv3_private.h b/drivers/arm/gic/v3/gicv3_private.h
index 59298ed..a5093d0 100644
--- a/drivers/arm/gic/v3/gicv3_private.h
+++ b/drivers/arm/gic/v3/gicv3_private.h
@@ -67,9 +67,13 @@
 unsigned int gicd_get_igrpmodr(uintptr_t base, unsigned int id);
 unsigned int gicr_get_igrpmodr0(uintptr_t base, unsigned int id);
 unsigned int gicr_get_igroupr0(uintptr_t base, unsigned int id);
+unsigned int gicr_get_isactiver0(uintptr_t base, unsigned int id);
 void gicd_set_igrpmodr(uintptr_t base, unsigned int id);
 void gicr_set_igrpmodr0(uintptr_t base, unsigned int id);
 void gicr_set_isenabler0(uintptr_t base, unsigned int id);
+void gicr_set_icenabler0(uintptr_t base, unsigned int id);
+void gicr_set_ispendr0(uintptr_t base, unsigned int id);
+void gicr_set_icpendr0(uintptr_t base, unsigned int id);
 void gicr_set_igroupr0(uintptr_t base, unsigned int id);
 void gicd_clr_igrpmodr(uintptr_t base, unsigned int id);
 void gicr_clr_igrpmodr0(uintptr_t base, unsigned int id);
@@ -81,6 +85,7 @@
  ******************************************************************************/
 void gicv3_spis_configure_defaults(uintptr_t gicd_base);
 void gicv3_ppi_sgi_configure_defaults(uintptr_t gicr_base);
+#if !ERROR_DEPRECATED
 void gicv3_secure_spis_configure(uintptr_t gicd_base,
 				     unsigned int num_ints,
 				     const unsigned int *sec_intr_list,
@@ -89,6 +94,13 @@
 					unsigned int num_ints,
 					const unsigned int *sec_intr_list,
 					unsigned int int_grp);
+#endif
+void gicv3_secure_ppi_sgi_configure_props(uintptr_t gicr_base,
+		const interrupt_prop_t *interrupt_props,
+		unsigned int interrupt_props_num);
+unsigned int gicv3_secure_spis_configure_props(uintptr_t gicd_base,
+		const interrupt_prop_t *interrupt_props,
+		unsigned int interrupt_props_num);
 void gicv3_rdistif_base_addrs_probe(uintptr_t *rdistif_base_addrs,
 					unsigned int rdistif_num,
 					uintptr_t gicr_base,
@@ -219,6 +231,11 @@
 	return mmio_read_32(base + GICR_ISENABLER0);
 }
 
+static inline void gicr_write_icpendr0(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICR_ICPENDR0, val);
+}
+
 static inline void gicr_write_isenabler0(uintptr_t base, unsigned int val)
 {
 	mmio_write_32(base + GICR_ISENABLER0, val);
diff --git a/include/bl31/interrupt_mgmt.h b/include/bl31/interrupt_mgmt.h
index 9a6a7fa..cccad3a 100644
--- a/include/bl31/interrupt_mgmt.h
+++ b/include/bl31/interrupt_mgmt.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -17,6 +17,11 @@
 #define INTR_TYPE_NS			U(2)
 #define MAX_INTR_TYPES			U(3)
 #define INTR_TYPE_INVAL			MAX_INTR_TYPES
+
+/* Interrupt routing modes */
+#define INTR_ROUTING_MODE_PE		0
+#define INTR_ROUTING_MODE_ANY		1
+
 /*
  * Constant passed to the interrupt handler in the 'id' field when the
  * framework does not read the gic registers to determine the interrupt id.
@@ -93,6 +98,8 @@
 
 #ifndef __ASSEMBLY__
 
+#include <stdint.h>
+
 /* Prototype for defining a handler for an interrupt type */
 typedef uint64_t (*interrupt_type_handler_t)(uint32_t id,
 					     uint32_t flags,
diff --git a/include/common/interrupt_props.h b/include/common/interrupt_props.h
new file mode 100644
index 0000000..9786b40
--- /dev/null
+++ b/include/common/interrupt_props.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __INTERRUPT_PROPS_H__
+#define __INTERRUPT_PROPS_H__
+
+#ifndef __ASSEMBLY__
+
+/* Create an interrupt property descriptor from various interrupt properties */
+#define INTR_PROP_DESC(num, pri, grp, cfg) \
+	{ \
+		.intr_num = num, \
+		.intr_pri = pri, \
+		.intr_grp = grp, \
+		.intr_cfg = cfg, \
+	}
+
+typedef struct interrupt_prop {
+	unsigned int intr_num:10;
+	unsigned int intr_pri:8;
+	unsigned int intr_grp:2;
+	unsigned int intr_cfg:2;
+} interrupt_prop_t;
+
+#endif /* __ASSEMBLY__ */
+#endif /* __INTERRUPT_PROPS_H__ */
diff --git a/include/drivers/arm/gic_common.h b/include/drivers/arm/gic_common.h
index b9cae80..9e126a8 100644
--- a/include/drivers/arm/gic_common.h
+++ b/include/drivers/arm/gic_common.h
@@ -12,6 +12,7 @@
  ******************************************************************************/
 /* Constants to categorise interrupts */
 #define MIN_SGI_ID		0
+#define MIN_SEC_SGI_ID		8
 #define MIN_PPI_ID		16
 #define MIN_SPI_ID		32
 #define MAX_SPI_ID		1019
@@ -22,9 +23,16 @@
 /* Mask for the priority field common to all GIC interfaces */
 #define GIC_PRI_MASK			0xff
 
+/* Mask for the configuration field common to all GIC interfaces */
+#define GIC_CFG_MASK			0x3
+
 /* Constant to indicate a spurious interrupt in all GIC versions */
 #define GIC_SPURIOUS_INTERRUPT		1023
 
+/* Interrupt configurations */
+#define GIC_INTR_CFG_LEVEL		0
+#define GIC_INTR_CFG_EDGE		1
+
 /* Constants to categorise priorities */
 #define GIC_HIGHEST_SEC_PRIORITY	0
 #define GIC_LOWEST_SEC_PRIORITY		127
@@ -73,6 +81,7 @@
 #define ISACTIVER_SHIFT		5
 #define ICACTIVER_SHIFT		ISACTIVER_SHIFT
 #define IPRIORITYR_SHIFT	2
+#define ITARGETSR_SHIFT		2
 #define ICFGR_SHIFT		4
 #define NSACR_SHIFT		4
 
diff --git a/include/drivers/arm/gicv2.h b/include/drivers/arm/gicv2.h
index a788025..6e8322e 100644
--- a/include/drivers/arm/gicv2.h
+++ b/include/drivers/arm/gicv2.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -10,9 +10,17 @@
 /*******************************************************************************
  * GICv2 miscellaneous definitions
  ******************************************************************************/
+
+/* Interrupt group definitions */
+#define GICV2_INTR_GROUP0	0
+#define GICV2_INTR_GROUP1	1
+
 /* Interrupt IDs reported by the HPPIR and IAR registers */
 #define PENDING_G1_INTID	1022
 
+/* GICv2 can only target up to 8 PEs */
+#define GICV2_MAX_TARGET_PE	8
+
 /*******************************************************************************
  * GICv2 specific Distributor interface register offsets and constants.
  ******************************************************************************/
@@ -28,6 +36,19 @@
 #define CPENDSGIR_SHIFT		2
 #define SPENDSGIR_SHIFT		CPENDSGIR_SHIFT
 
+#define SGIR_TGTLSTFLT_SHIFT	24
+#define SGIR_TGTLSTFLT_MASK	0x3
+#define SGIR_TGTLST_SHIFT	16
+#define SGIR_TGTLST_MASK	0xff
+#define SGIR_INTID_MASK		0xf
+
+#define SGIR_TGT_SPECIFIC	0
+
+#define GICV2_SGIR_VALUE(tgt_lst_flt, tgt, intid) \
+	((((tgt_lst_flt) & SGIR_TGTLSTFLT_MASK) << SGIR_TGTLSTFLT_SHIFT) | \
+	 (((tgt) & SGIR_TGTLST_MASK) << SGIR_TGTLST_SHIFT) | \
+	 ((intid) & SGIR_INTID_MASK))
+
 /*******************************************************************************
  * GICv2 specific CPU interface register offsets and constants.
  ******************************************************************************/
@@ -95,6 +116,7 @@
 
 #ifndef __ASSEMBLY__
 
+#include <interrupt_props.h>
 #include <stdint.h>
 
 /*******************************************************************************
@@ -103,23 +125,43 @@
  * in order to initialize the GICv2 driver. The attributes are described
  * below.
  *
- * 1. The 'gicd_base' field contains the base address of the Distributor
- *    interface programmer's view.
+ * The 'gicd_base' field contains the base address of the Distributor interface
+ * programmer's view.
  *
- * 2. The 'gicc_base' field contains the base address of the CPU Interface
- *    programmer's view.
+ * The 'gicc_base' field contains the base address of the CPU Interface
+ * programmer's view.
  *
- * 3. The 'g0_interrupt_array' field is a pointer to an array in which each
- *    entry corresponds to an ID of a Group 0 interrupt.
+ * The 'g0_interrupt_array' field is a pointer to an array in which each entry
+ * corresponds to an ID of a Group 0 interrupt. This field is ignored when
+ * 'interrupt_props' field is used. This field is deprecated.
  *
- * 4. The 'g0_interrupt_num' field contains the number of entries in the
- *    'g0_interrupt_array'.
+ * The 'g0_interrupt_num' field contains the number of entries in the
+ * 'g0_interrupt_array'. This field is ignored when 'interrupt_props' field is
+ * used. This field is deprecated.
+ *
+ * The 'target_masks' is a pointer to an array containing 'target_masks_num'
+ * elements. The GIC driver will populate the array with per-PE target mask to
+ * use to when targeting interrupts.
+ *
+ * The 'interrupt_props' field is a pointer to an array that enumerates secure
+ * interrupts and their properties. If this field is not NULL, both
+ * 'g0_interrupt_array' and 'g1s_interrupt_array' fields are ignored.
+ *
+ * The 'interrupt_props_num' field contains the number of entries in the
+ * 'interrupt_props' array. If this field is non-zero, 'g0_interrupt_num' is
+ * ignored.
  ******************************************************************************/
 typedef struct gicv2_driver_data {
 	uintptr_t gicd_base;
 	uintptr_t gicc_base;
+#if !ERROR_DEPRECATED
 	unsigned int g0_interrupt_num;
 	const unsigned int *g0_interrupt_array;
+#endif
+	unsigned int *target_masks;
+	unsigned int target_masks_num;
+	const interrupt_prop_t *interrupt_props;
+	unsigned int interrupt_props_num;
 } gicv2_driver_data_t;
 
 /*******************************************************************************
@@ -136,6 +178,18 @@
 unsigned int gicv2_acknowledge_interrupt(void);
 void gicv2_end_of_interrupt(unsigned int id);
 unsigned int gicv2_get_interrupt_group(unsigned int id);
+unsigned int gicv2_get_running_priority(void);
+void gicv2_set_pe_target_mask(unsigned int proc_num);
+unsigned int gicv2_get_interrupt_active(unsigned int id);
+void gicv2_enable_interrupt(unsigned int id);
+void gicv2_disable_interrupt(unsigned int id);
+void gicv2_set_interrupt_priority(unsigned int id, unsigned int priority);
+void gicv2_set_interrupt_type(unsigned int id, unsigned int type);
+void gicv2_raise_sgi(int sgi_num, int proc_num);
+void gicv2_set_spi_routing(unsigned int id, int proc_num);
+void gicv2_set_interrupt_pending(unsigned int id);
+void gicv2_clear_interrupt_pending(unsigned int id);
+unsigned int gicv2_set_pmr(unsigned int mask);
 
 #endif /* __ASSEMBLY__ */
 #endif /* __GICV2_H__ */
diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h
index c52fe48..b2e4d4c 100644
--- a/include/drivers/arm/gicv3.h
+++ b/include/drivers/arm/gicv3.h
@@ -7,8 +7,6 @@
 #ifndef __GICV3_H__
 #define __GICV3_H__
 
-#include "utils_def.h"
-
 /*******************************************************************************
  * GICv3 miscellaneous definitions
  ******************************************************************************/
@@ -24,6 +22,9 @@
 /* Constant to categorize LPI interrupt */
 #define MIN_LPI_ID		8192
 
+/* GICv3 can only target up to 16 PEs with SGI */
+#define GICV3_MAX_SGI_TARGETS	16
+
 /*******************************************************************************
  * GICv3 specific Distributor interface register offsets and constants.
  ******************************************************************************/
@@ -72,6 +73,9 @@
 #define IROUTER_IRM_SHIFT	31
 #define IROUTER_IRM_MASK	0x1
 
+#define GICV3_IRM_PE		0
+#define GICV3_IRM_ANY		1
+
 #define NUM_OF_DIST_REGS	30
 
 /*******************************************************************************
@@ -165,6 +169,27 @@
 #define IAR1_EL1_INTID_SHIFT		0
 #define IAR1_EL1_INTID_MASK		0xffffff
 
+/* ICC SGI macros */
+#define SGIR_TGT_MASK			0xffff
+#define SGIR_AFF1_SHIFT			16
+#define SGIR_INTID_SHIFT		24
+#define SGIR_INTID_MASK			0xf
+#define SGIR_AFF2_SHIFT			32
+#define SGIR_IRM_SHIFT			40
+#define SGIR_IRM_MASK			0x1
+#define SGIR_AFF3_SHIFT			48
+#define SGIR_AFF_MASK			0xf
+
+#define SGIR_IRM_TO_AFF			0
+
+#define GICV3_SGIR_VALUE(aff3, aff2, aff1, intid, irm, tgt) \
+	((((uint64_t) (aff3) & SGIR_AFF_MASK) << SGIR_AFF3_SHIFT) | \
+	 (((uint64_t) (irm) & SGIR_IRM_MASK) << SGIR_IRM_SHIFT) | \
+	 (((uint64_t) (aff2) & SGIR_AFF_MASK) << SGIR_AFF2_SHIFT) | \
+	 (((intid) & SGIR_INTID_MASK) << SGIR_INTID_SHIFT) | \
+	 (((aff1) & SGIR_AFF_MASK) << SGIR_AFF1_SHIFT) | \
+	 ((tgt) & SGIR_TGT_MASK))
+
 /*****************************************************************************
  * GICv3 ITS registers and constants
  *****************************************************************************/
@@ -185,6 +210,7 @@
 #ifndef __ASSEMBLY__
 
 #include <gic_common.h>
+#include <interrupt_props.h>
 #include <stdint.h>
 #include <types.h>
 #include <utils_def.h>
@@ -224,53 +250,70 @@
  * GICv3 IP. It is used by the platform port to specify these attributes in order
  * to initialise the GICV3 driver. The attributes are described below.
  *
- * 1. The 'gicd_base' field contains the base address of the Distributor
- *    interface programmer's view.
+ * The 'gicd_base' field contains the base address of the Distributor interface
+ * programmer's view.
  *
- * 2. The 'gicr_base' field contains the base address of the Re-distributor
- *    interface programmer's view.
+ * The 'gicr_base' field contains the base address of the Re-distributor
+ * interface programmer's view.
  *
- * 3. The 'g0_interrupt_array' field is a ponter to an array in which each
- *    entry corresponds to an ID of a Group 0 interrupt.
+ * The 'g0_interrupt_array' field is a pointer to an array in which each entry
+ * corresponds to an ID of a Group 0 interrupt. This field is ignored when
+ * 'interrupt_props' field is used. This field is deprecated.
  *
- * 4. The 'g0_interrupt_num' field contains the number of entries in the
- *    'g0_interrupt_array'.
+ * The 'g0_interrupt_num' field contains the number of entries in the
+ * 'g0_interrupt_array'. This field is ignored when 'interrupt_props' field is
+ * used. This field is deprecated.
  *
- * 5. The 'g1s_interrupt_array' field is a ponter to an array in which each
- *    entry corresponds to an ID of a Group 1 interrupt.
+ * The 'g1s_interrupt_array' field is a pointer to an array in which each entry
+ * corresponds to an ID of a Group 1 interrupt. This field is ignored when
+ * 'interrupt_props' field is used. This field is deprecated.
  *
- * 6. The 'g1s_interrupt_num' field contains the number of entries in the
- *    'g1s_interrupt_array'.
+ * The 'g1s_interrupt_num' field contains the number of entries in the
+ * 'g1s_interrupt_array'. This field must be 0 if 'interrupt_props' field is
+ * used. This field is ignored when 'interrupt_props' field is used. This field
+ * is deprecated.
  *
- * 7. The 'rdistif_num' field contains the number of Redistributor interfaces
- *    the GIC implements. This is equal to the number of CPUs or CPU interfaces
- *    instantiated in the GIC.
+ * The 'interrupt_props' field is a pointer to an array that enumerates secure
+ * interrupts and their properties. If this field is not NULL, both
+ * 'g0_interrupt_array' and 'g1s_interrupt_array' fields are ignored.
  *
- * 8. The 'rdistif_base_addrs' field is a pointer to an array that has an entry
- *    for storing the base address of the Redistributor interface frame of each
- *    CPU in the system. The size of the array = 'rdistif_num'. The base
- *    addresses are detected during driver initialisation.
+ * The 'interrupt_props_num' field contains the number of entries in the
+ * 'interrupt_props' array. If this field is non-zero, both 'g0_interrupt_num'
+ * and 'g1s_interrupt_num' are ignored.
  *
- * 9. The 'mpidr_to_core_pos' field is a pointer to a hash function which the
- *    driver will use to convert an MPIDR value to a linear core index. This
- *    index will be used for accessing the 'rdistif_base_addrs' array. This is
- *    an optional field. A GICv3 implementation maps each MPIDR to a linear core
- *    index as well. This mapping can be found by reading the "Affinity Value"
- *    and "Processor Number" fields in the GICR_TYPER. It is IMP. DEF. if the
- *    "Processor Numbers" are suitable to index into an array to access core
- *    specific information. If this not the case, the platform port must provide
- *    a hash function. Otherwise, the "Processor Number" field will be used to
- *    access the array elements.
+ * The 'rdistif_num' field contains the number of Redistributor interfaces the
+ * GIC implements. This is equal to the number of CPUs or CPU interfaces
+ * instantiated in the GIC.
+ *
+ * The 'rdistif_base_addrs' field is a pointer to an array that has an entry for
+ * storing the base address of the Redistributor interface frame of each CPU in
+ * the system. The size of the array = 'rdistif_num'. The base addresses are
+ * detected during driver initialisation.
+ *
+ * The 'mpidr_to_core_pos' field is a pointer to a hash function which the
+ * driver will use to convert an MPIDR value to a linear core index. This index
+ * will be used for accessing the 'rdistif_base_addrs' array. This is an
+ * optional field. A GICv3 implementation maps each MPIDR to a linear core index
+ * as well. This mapping can be found by reading the "Affinity Value" and
+ * "Processor Number" fields in the GICR_TYPER. It is IMP. DEF. if the
+ * "Processor Numbers" are suitable to index into an array to access core
+ * specific information. If this not the case, the platform port must provide a
+ * hash function. Otherwise, the "Processor Number" field will be used to access
+ * the array elements.
  ******************************************************************************/
 typedef unsigned int (*mpidr_hash_fn)(u_register_t mpidr);
 
 typedef struct gicv3_driver_data {
 	uintptr_t gicd_base;
 	uintptr_t gicr_base;
+#if !ERROR_DEPRECATED
 	unsigned int g0_interrupt_num;
 	unsigned int g1s_interrupt_num;
 	const unsigned int *g0_interrupt_array;
 	const unsigned int *g1s_interrupt_array;
+#endif
+	const interrupt_prop_t *interrupt_props;
+	unsigned int interrupt_props_num;
 	unsigned int rdistif_num;
 	uintptr_t *rdistif_base_addrs;
 	mpidr_hash_fn mpidr_to_core_pos;
@@ -349,5 +392,20 @@
 void gicv3_its_save_disable(uintptr_t gits_base, gicv3_its_ctx_t * const its_ctx);
 void gicv3_its_restore(uintptr_t gits_base, const gicv3_its_ctx_t * const its_ctx);
 
+unsigned int gicv3_get_running_priority(void);
+unsigned int gicv3_get_interrupt_active(unsigned int id, unsigned int proc_num);
+void gicv3_enable_interrupt(unsigned int id, unsigned int proc_num);
+void gicv3_disable_interrupt(unsigned int id, unsigned int proc_num);
+void gicv3_set_interrupt_priority(unsigned int id, unsigned int proc_num,
+		unsigned int priority);
+void gicv3_set_interrupt_type(unsigned int id, unsigned int proc_num,
+		unsigned int group);
+void gicv3_raise_secure_g0_sgi(int sgi_num, u_register_t target);
+void gicv3_set_spi_routing(unsigned int id, unsigned int irm,
+		u_register_t mpidr);
+void gicv3_set_interrupt_pending(unsigned int id, unsigned int proc_num);
+void gicv3_clear_interrupt_pending(unsigned int id, unsigned int proc_num);
+unsigned int gicv3_set_pmr(unsigned int mask);
+
 #endif /* __ASSEMBLY__ */
 #endif /* __GICV3_H__ */
diff --git a/include/lib/aarch32/arch.h b/include/lib/aarch32/arch.h
index 6c6d6a1..3846bec 100644
--- a/include/lib/aarch32/arch.h
+++ b/include/lib/aarch32/arch.h
@@ -44,6 +44,7 @@
 		(((mpidr) >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK)
 #define MPIDR_AFFLVL2_VAL(mpidr) \
 		(((mpidr) >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK)
+#define MPIDR_AFFLVL3_VAL(mpidr)	0
 
 /*
  * The MPIDR_MAX_AFFLVL count starts from 0. Take care to
diff --git a/include/lib/aarch32/arch_helpers.h b/include/lib/aarch32/arch_helpers.h
index 5d31836..469e9b0 100644
--- a/include/lib/aarch32/arch_helpers.h
+++ b/include/lib/aarch32/arch_helpers.h
@@ -213,6 +213,7 @@
 DEFINE_SYSOP_TYPE_FUNC(dsb, ish)
 DEFINE_SYSOP_TYPE_FUNC(dsb, ishst)
 DEFINE_SYSOP_TYPE_FUNC(dmb, ish)
+DEFINE_SYSOP_TYPE_FUNC(dmb, ishst)
 DEFINE_SYSOP_FUNC(isb)
 
 void __dead2 smc(uint32_t r0, uint32_t r1, uint32_t r2, uint32_t r3,
@@ -257,6 +258,7 @@
 DEFINE_COPROCR_RW_FUNCS(icc_sre_el2, ICC_HSRE)
 DEFINE_COPROCR_RW_FUNCS(icc_sre_el3, ICC_MSRE)
 DEFINE_COPROCR_RW_FUNCS(icc_pmr_el1, ICC_PMR)
+DEFINE_COPROCR_RW_FUNCS(icc_rpr_el1, ICC_RPR)
 DEFINE_COPROCR_RW_FUNCS(icc_igrpen1_el3, ICC_MGRPEN1)
 DEFINE_COPROCR_RW_FUNCS(icc_igrpen0_el1, ICC_IGRPEN0)
 DEFINE_COPROCR_RW_FUNCS(icc_hppir0_el1, ICC_HPPIR0)
@@ -265,6 +267,7 @@
 DEFINE_COPROCR_RW_FUNCS(icc_iar1_el1, ICC_IAR1)
 DEFINE_COPROCR_RW_FUNCS(icc_eoir0_el1, ICC_EOIR0)
 DEFINE_COPROCR_RW_FUNCS(icc_eoir1_el1, ICC_EOIR1)
+DEFINE_COPROCR_RW_FUNCS_64(icc_sgi0r_el1, ICC_SGI0R_EL1_64)
 
 DEFINE_COPROCR_RW_FUNCS(hdcr, HDCR)
 DEFINE_COPROCR_RW_FUNCS(cnthp_ctl, CNTHP_CTL)
@@ -324,4 +327,7 @@
 
 #define read_ctr_el0()		read_ctr()
 
+#define write_icc_sgi0r_el1(_v) \
+		write64_icc_sgi0r_el1(_v)
+
 #endif /* __ARCH_HELPERS_H__ */
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index 9cbe405..997e3a2 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -68,6 +68,7 @@
 #define ICC_CTLR_EL1    S3_0_C12_C12_4
 #define ICC_CTLR_EL3    S3_6_C12_C12_4
 #define ICC_PMR_EL1     S3_0_C4_C6_0
+#define ICC_RPR_EL1     S3_0_C12_C11_3
 #define ICC_IGRPEN1_EL3 S3_6_c12_c12_7
 #define ICC_IGRPEN0_EL1 S3_0_c12_c12_6
 #define ICC_HPPIR0_EL1  S3_0_c12_c8_2
@@ -76,6 +77,7 @@
 #define ICC_IAR1_EL1    S3_0_c12_c12_0
 #define ICC_EOIR0_EL1   S3_0_c12_c8_1
 #define ICC_EOIR1_EL1   S3_0_c12_c12_1
+#define ICC_SGI0R_EL1	S3_0_c12_c11_7
 
 /*******************************************************************************
  * Generic timer memory mapped registers & offsets
diff --git a/include/lib/aarch64/arch_helpers.h b/include/lib/aarch64/arch_helpers.h
index 04b2e03..9c022ab 100644
--- a/include/lib/aarch64/arch_helpers.h
+++ b/include/lib/aarch64/arch_helpers.h
@@ -198,6 +198,7 @@
 DEFINE_SYSOP_TYPE_FUNC(dsb, ish)
 DEFINE_SYSOP_TYPE_FUNC(dsb, ishst)
 DEFINE_SYSOP_TYPE_FUNC(dmb, ish)
+DEFINE_SYSOP_TYPE_FUNC(dmb, ishst)
 DEFINE_SYSOP_FUNC(isb)
 
 uint32_t get_afflvl_shift(uint32_t);
@@ -307,6 +308,7 @@
 DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el2, ICC_SRE_EL2)
 DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el3, ICC_SRE_EL3)
 DEFINE_RENAME_SYSREG_RW_FUNCS(icc_pmr_el1, ICC_PMR_EL1)
+DEFINE_RENAME_SYSREG_READ_FUNC(icc_rpr_el1, ICC_RPR_EL1)
 DEFINE_RENAME_SYSREG_RW_FUNCS(icc_igrpen1_el3, ICC_IGRPEN1_EL3)
 DEFINE_RENAME_SYSREG_RW_FUNCS(icc_igrpen0_el1, ICC_IGRPEN0_EL1)
 DEFINE_RENAME_SYSREG_READ_FUNC(icc_hppir0_el1, ICC_HPPIR0_EL1)
@@ -315,6 +317,7 @@
 DEFINE_RENAME_SYSREG_READ_FUNC(icc_iar1_el1, ICC_IAR1_EL1)
 DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_eoir0_el1, ICC_EOIR0_EL1)
 DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_eoir1_el1, ICC_EOIR1_EL1)
+DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_sgi0r_el1, ICC_SGI0R_EL1)
 
 
 #define IS_IN_EL(x) \
diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h
index e189f64..f03a399 100644
--- a/include/plat/common/platform.h
+++ b/include/plat/common/platform.h
@@ -70,6 +70,26 @@
 				     uint32_t security_state);
 
 /*******************************************************************************
+ * Optional interrupt management functions, depending on chosen EL3 components.
+ ******************************************************************************/
+unsigned int plat_ic_get_running_priority(void);
+int plat_ic_is_spi(unsigned int id);
+int plat_ic_is_ppi(unsigned int id);
+int plat_ic_is_sgi(unsigned int id);
+unsigned int plat_ic_get_interrupt_active(unsigned int id);
+void plat_ic_disable_interrupt(unsigned int id);
+void plat_ic_enable_interrupt(unsigned int id);
+int plat_ic_has_interrupt_type(unsigned int type);
+void plat_ic_set_interrupt_type(unsigned int id, unsigned int type);
+void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority);
+void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target);
+void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode,
+		u_register_t mpidr);
+void plat_ic_set_interrupt_pending(unsigned int id);
+void plat_ic_clear_interrupt_pending(unsigned int id);
+unsigned int plat_ic_set_priority_mask(unsigned int mask);
+
+/*******************************************************************************
  * Optional common functions (may be overridden)
  ******************************************************************************/
 uintptr_t plat_get_my_stack(void);
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index 8601046..412c3b7 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -77,6 +77,10 @@
 # For Chain of Trust
 GENERATE_COT			:= 0
 
+# Hint platform interrupt control layer that Group 0 interrupts are for EL3. By
+# default, they are for Secure EL1.
+GICV2_G0_FOR_EL3		:= 0
+
 # Whether system coherency is managed in hardware, without explicit software
 # operations.
 HW_ASSISTED_COHERENCY		:= 0
diff --git a/plat/arm/common/arm_gicv2.c b/plat/arm/common/arm_gicv2.c
index 521fa8c..6dd847b 100644
--- a/plat/arm/common/arm_gicv2.c
+++ b/plat/arm/common/arm_gicv2.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -28,11 +28,15 @@
 	PLAT_ARM_G0_IRQS
 };
 
+static unsigned int target_mask_array[PLATFORM_CORE_COUNT];
+
 static const 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,
+	.target_masks = target_mask_array,
+	.target_masks_num = ARRAY_SIZE(target_mask_array),
 };
 
 /******************************************************************************
@@ -72,6 +76,7 @@
 void plat_arm_gic_pcpu_init(void)
 {
 	gicv2_pcpu_distif_init();
+	gicv2_set_pe_target_mask(plat_my_core_pos());
 }
 
 /******************************************************************************
diff --git a/plat/common/plat_gicv2.c b/plat/common/plat_gicv2.c
index 50a8181..05fabca 100644
--- a/plat/common/plat_gicv2.c
+++ b/plat/common/plat_gicv2.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,6 +7,7 @@
 #include <gic_common.h>
 #include <gicv2.h>
 #include <interrupt_mgmt.h>
+#include <platform.h>
 
 /*
  * The following platform GIC functions are weakly defined. They
@@ -20,6 +21,18 @@
 #pragma weak plat_ic_end_of_interrupt
 #pragma weak plat_interrupt_type_to_line
 
+#pragma weak plat_ic_get_running_priority
+#pragma weak plat_ic_is_spi
+#pragma weak plat_ic_is_ppi
+#pragma weak plat_ic_is_sgi
+#pragma weak plat_ic_get_interrupt_active
+#pragma weak plat_ic_enable_interrupt
+#pragma weak plat_ic_disable_interrupt
+#pragma weak plat_ic_set_interrupt_priority
+#pragma weak plat_ic_set_interrupt_type
+#pragma weak plat_ic_raise_el3_sgi
+#pragma weak plat_ic_set_spi_routing
+
 /*
  * This function returns the highest priority pending interrupt at
  * the Interrupt controller
@@ -53,8 +66,13 @@
 	id = gicv2_get_pending_interrupt_type();
 
 	/* Assume that all secure interrupts are S-EL1 interrupts */
-	if (id < PENDING_G1_INTID)
+	if (id < PENDING_G1_INTID) {
+#if GICV2_G0_FOR_EL3
+		return INTR_TYPE_EL3;
+#else
 		return INTR_TYPE_S_EL1;
+#endif
+	}
 
 	if (id == GIC_SPURIOUS_INTERRUPT)
 		return INTR_TYPE_INVAL;
@@ -83,7 +101,12 @@
 	type = gicv2_get_interrupt_group(id);
 
 	/* Assume that all secure interrupts are S-EL1 interrupts */
-	return (type) ? INTR_TYPE_NS : INTR_TYPE_S_EL1;
+	return type == GICV2_INTR_GROUP1 ? INTR_TYPE_NS :
+#if GICV2_G0_FOR_EL3
+		INTR_TYPE_EL3;
+#else
+		INTR_TYPE_S_EL1;
+#endif
 }
 
 /*
@@ -122,3 +145,135 @@
 	return ((gicv2_is_fiq_enabled()) ? __builtin_ctz(SCR_FIQ_BIT) :
 						__builtin_ctz(SCR_IRQ_BIT));
 }
+
+unsigned int plat_ic_get_running_priority(void)
+{
+	return gicv2_get_running_priority();
+}
+
+int plat_ic_is_spi(unsigned int id)
+{
+	return (id >= MIN_SPI_ID) && (id <= MAX_SPI_ID);
+}
+
+int plat_ic_is_ppi(unsigned int id)
+{
+	return (id >= MIN_PPI_ID) && (id < MIN_SPI_ID);
+}
+
+int plat_ic_is_sgi(unsigned int id)
+{
+	return (id >= MIN_SGI_ID) && (id < MIN_PPI_ID);
+}
+
+unsigned int plat_ic_get_interrupt_active(unsigned int id)
+{
+	return gicv2_get_interrupt_active(id);
+}
+
+void plat_ic_enable_interrupt(unsigned int id)
+{
+	gicv2_enable_interrupt(id);
+}
+
+void plat_ic_disable_interrupt(unsigned int id)
+{
+	gicv2_disable_interrupt(id);
+}
+
+void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority)
+{
+	gicv2_set_interrupt_priority(id, priority);
+}
+
+int plat_ic_has_interrupt_type(unsigned int type)
+{
+	switch (type) {
+#if GICV2_G0_FOR_EL3
+	case INTR_TYPE_EL3:
+#else
+	case INTR_TYPE_S_EL1:
+#endif
+	case INTR_TYPE_NS:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+void plat_ic_set_interrupt_type(unsigned int id, unsigned int type)
+{
+	int gicv2_type = 0;
+
+	/* Map canonical interrupt type to GICv2 type */
+	switch (type) {
+#if GICV2_G0_FOR_EL3
+	case INTR_TYPE_EL3:
+#else
+	case INTR_TYPE_S_EL1:
+#endif
+		gicv2_type = GICV2_INTR_GROUP0;
+		break;
+	case INTR_TYPE_NS:
+		gicv2_type = GICV2_INTR_GROUP1;
+		break;
+	default:
+		assert(0);
+	}
+
+	gicv2_set_interrupt_type(id, gicv2_type);
+}
+
+void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target)
+{
+#if GICV2_G0_FOR_EL3
+	int id;
+
+	/* Target must be a valid MPIDR in the system */
+	id = plat_core_pos_by_mpidr(target);
+	assert(id >= 0);
+
+	/* Verify that this is a secure SGI */
+	assert(plat_ic_get_interrupt_type(sgi_num) == INTR_TYPE_EL3);
+
+	gicv2_raise_sgi(sgi_num, id);
+#else
+	assert(0);
+#endif
+}
+
+void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode,
+		u_register_t mpidr)
+{
+	int proc_num = 0;
+
+	switch (routing_mode) {
+	case INTR_ROUTING_MODE_PE:
+		proc_num = plat_core_pos_by_mpidr(mpidr);
+		assert(proc_num >= 0);
+		break;
+	case INTR_ROUTING_MODE_ANY:
+		/* Bit mask selecting all 8 CPUs as candidates */
+		proc_num = -1;
+		break;
+	default:
+		assert(0);
+	}
+
+	gicv2_set_spi_routing(id, proc_num);
+}
+
+void plat_ic_set_interrupt_pending(unsigned int id)
+{
+	gicv2_set_interrupt_pending(id);
+}
+
+void plat_ic_clear_interrupt_pending(unsigned int id)
+{
+	gicv2_clear_interrupt_pending(id);
+}
+
+unsigned int plat_ic_set_priority_mask(unsigned int mask)
+{
+	return gicv2_set_pmr(mask);
+}
diff --git a/plat/common/plat_gicv3.c b/plat/common/plat_gicv3.c
index 030a1d9..52ceb6a 100644
--- a/plat/common/plat_gicv3.c
+++ b/plat/common/plat_gicv3.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -26,6 +26,20 @@
 #pragma weak plat_ic_end_of_interrupt
 #pragma weak plat_interrupt_type_to_line
 
+#pragma weak plat_ic_get_running_priority
+#pragma weak plat_ic_is_spi
+#pragma weak plat_ic_is_ppi
+#pragma weak plat_ic_is_sgi
+#pragma weak plat_ic_get_interrupt_active
+#pragma weak plat_ic_enable_interrupt
+#pragma weak plat_ic_disable_interrupt
+#pragma weak plat_ic_set_interrupt_priority
+#pragma weak plat_ic_set_interrupt_type
+#pragma weak plat_ic_raise_el3_sgi
+#pragma weak plat_ic_set_spi_routing
+#pragma weak plat_ic_set_interrupt_pending
+#pragma weak plat_ic_clear_interrupt_pending
+
 CASSERT((INTR_TYPE_S_EL1 == INTR_GROUP1S) &&
 	(INTR_TYPE_NS == INTR_GROUP1NS) &&
 	(INTR_TYPE_EL3 == INTR_GROUP0), assert_interrupt_type_mismatch);
@@ -155,6 +169,108 @@
 		return __builtin_ctz(SCR_FIQ_BIT);
 	}
 }
+
+unsigned int plat_ic_get_running_priority(void)
+{
+	return gicv3_get_running_priority();
+}
+
+int plat_ic_is_spi(unsigned int id)
+{
+	return (id >= MIN_SPI_ID) && (id <= MAX_SPI_ID);
+}
+
+int plat_ic_is_ppi(unsigned int id)
+{
+	return (id >= MIN_PPI_ID) && (id < MIN_SPI_ID);
+}
+
+int plat_ic_is_sgi(unsigned int id)
+{
+	return (id >= MIN_SGI_ID) && (id < MIN_PPI_ID);
+}
+
+unsigned int plat_ic_get_interrupt_active(unsigned int id)
+{
+	return gicv3_get_interrupt_active(id, plat_my_core_pos());
+}
+
+void plat_ic_enable_interrupt(unsigned int id)
+{
+	gicv3_enable_interrupt(id, plat_my_core_pos());
+}
+
+void plat_ic_disable_interrupt(unsigned int id)
+{
+	gicv3_disable_interrupt(id, plat_my_core_pos());
+}
+
+void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority)
+{
+	gicv3_set_interrupt_priority(id, plat_my_core_pos(), priority);
+}
+
+int plat_ic_has_interrupt_type(unsigned int type)
+{
+	assert((type == INTR_TYPE_EL3) || (type == INTR_TYPE_S_EL1) ||
+			(type == INTR_TYPE_NS));
+	return 1;
+}
+
+void plat_ic_set_interrupt_type(unsigned int id, unsigned int type)
+{
+	gicv3_set_interrupt_type(id, plat_my_core_pos(), type);
+}
+
+void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target)
+{
+	/* Target must be a valid MPIDR in the system */
+	assert(plat_core_pos_by_mpidr(target) >= 0);
+
+	/* Verify that this is a secure EL3 SGI */
+	assert(plat_ic_get_interrupt_type(sgi_num) == INTR_TYPE_EL3);
+
+	gicv3_raise_secure_g0_sgi(sgi_num, target);
+}
+
+void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode,
+		u_register_t mpidr)
+{
+	unsigned int irm = 0;
+
+	switch (routing_mode) {
+	case INTR_ROUTING_MODE_PE:
+		assert(plat_core_pos_by_mpidr(mpidr) >= 0);
+		irm = GICV3_IRM_PE;
+		break;
+	case INTR_ROUTING_MODE_ANY:
+		irm = GICV3_IRM_ANY;
+		break;
+	default:
+		assert(0);
+	}
+
+	gicv3_set_spi_routing(id, irm, mpidr);
+}
+
+void plat_ic_set_interrupt_pending(unsigned int id)
+{
+	/* Disallow setting SGIs pending */
+	assert(id >= MIN_PPI_ID);
+	gicv3_set_interrupt_pending(id, plat_my_core_pos());
+}
+
+void plat_ic_clear_interrupt_pending(unsigned int id)
+{
+	/* Disallow setting SGIs pending */
+	assert(id >= MIN_PPI_ID);
+	gicv3_clear_interrupt_pending(id, plat_my_core_pos());
+}
+
+unsigned int plat_ic_set_priority_mask(unsigned int mask)
+{
+	return gicv3_set_pmr(mask);
+}
 #endif
 #ifdef IMAGE_BL32