Merge pull request #1117 from antonio-nino-diaz-arm/an/xlat-improvements

Improvements to the translation tables library v2
diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst
index 9798566..6c07b2e 100644
--- a/docs/porting-guide.rst
+++ b/docs/porting-guide.rst
@@ -2107,13 +2107,32 @@
 corresponding to the local state at each power level. The generic code
 expects the handler to succeed.
 
-The difference between turning a power domain off versus suspending it
-is that in the former case, the power domain is expected to re-initialize
-its state when it is next powered on (see ``pwr_domain_on_finish()``). In the
-latter case, the power domain is expected to save enough state so that it can
-resume execution by restoring this state when its powered on (see
+The difference between turning a power domain off versus suspending it is that
+in the former case, the power domain is expected to re-initialize its state
+when it is next powered on (see ``pwr_domain_on_finish()``). In the latter
+case, the power domain is expected to save enough state so that it can resume
+execution by restoring this state when its powered on (see
 ``pwr_domain_suspend_finish()``).
 
+When suspending a core, the platform can also choose to power off the GICv3
+Redistributor and ITS through an implementation-defined sequence. To achieve
+this safely, the ITS context must be saved first. The architectural part is
+implemented by the ``gicv3_its_save_disable()`` helper, but most of the needed
+sequence is implementation defined and it is therefore the responsibility of
+the platform code to implement the necessary sequence. Then the GIC
+Redistributor context can be saved using the ``gicv3_rdistif_save()`` helper.
+Powering off the Redistributor requires the implementation to support it and it
+is the responsibility of the platform code to execute the right implementation
+defined sequence.
+
+When a system suspend is requested, the platform can also make use of the
+``gicv3_distif_save()`` helper to save the context of the GIC Distributor after
+it has saved the context of the Redistributors and ITS of all the cores in the
+system. The context of the Distributor can be large and may require it to be
+allocated in a special area if it cannot fit in the platform's global static
+data, for example in DRAM. The Distributor can then be powered down using an
+implementation-defined sequence.
+
 plat\_psci\_ops.pwr\_domain\_pwr\_down\_wfi()
 .............................................
 
@@ -2159,6 +2178,10 @@
 the ``pwr_domain_on_finish()`` operation. The generic code expects the platform
 to succeed.
 
+If the Distributor, Redistributors or ITS have been powered off as part of a
+suspend, their context must be restored in this function in the reverse order
+to how they were saved during suspend sequence.
+
 plat\_psci\_ops.system\_off()
 .............................
 
diff --git a/drivers/arm/gic/v3/arm_gicv3_common.c b/drivers/arm/gic/v3/arm_gicv3_common.c
new file mode 100644
index 0000000..8d552ca
--- /dev/null
+++ b/drivers/arm/gic/v3/arm_gicv3_common.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Driver for implementation defined features that are identical in ARM GICv3
+* implementations (GIC-500 and GIC-600 for now). This driver only overrides
+* APIs that are different to those generic ones in GICv3 driver.
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <gicv3.h>
+
+#include "gicv3_private.h"
+#include "arm_gicv3_common.h"
+
+/*
+ * Flush the internal GIC cache of the LPIs pending tables to memory before
+ * saving the state of the Redistributor. This is required before powering off
+ * the GIC when the pending status must be preserved.
+ * `rdist_proc_num` is the processor number corresponding to the Redistributor of the
+ * current CPU.
+ */
+void arm_gicv3_distif_pre_save(unsigned int rdist_proc_num)
+{
+	uintptr_t gicr_base = 0;
+
+	assert(gicv3_driver_data);
+	assert(gicv3_driver_data->rdistif_base_addrs);
+
+	/*
+	 * The GICR_WAKER.Sleep bit should be set only when both
+	 * GICR_WAKER.ChildrenAsleep and GICR_WAKER.ProcessorSleep are set on
+	 * all the Redistributors.
+	 */
+	for (unsigned int i = 0; i < gicv3_driver_data->rdistif_num; i++) {
+		gicr_base = gicv3_driver_data->rdistif_base_addrs[i];
+		assert(gicr_base);
+		assert(gicr_read_waker(gicr_base) & WAKER_CA_BIT);
+		assert(gicr_read_waker(gicr_base) & WAKER_PS_BIT);
+	}
+
+	gicr_base = gicv3_driver_data->rdistif_base_addrs[rdist_proc_num];
+	/*
+	 * According to the TRM, there is only one instance of the
+	 * GICR_WAKER.Sleep and GICR_WAKER.Quiescent bits that can be accessed
+	 * through any of the Redistributor.
+	 */
+
+	/*
+	 * Set GICR_WAKER.Sleep
+	 * After this point, the system must be configured so that the
+	 * wake_request signals for the right cores are asserted when a wakeup
+	 * interrupt is detected. The GIC will not be able to do that anymore
+	 * when the GICR_WAKER.Sleep bit is set to 1.
+	 */
+	gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) | WAKER_SL_BIT);
+
+	/* Wait until the GICR_WAKER.Quiescent bit is set */
+	while (!(gicr_read_waker(gicr_base) & WAKER_QSC_BIT))
+		;
+}
+
+/*
+ * Allow the LPIs pending state to be read back from the tables in memory after
+ * having restored the state of the GIC Redistributor.
+ */
+void arm_gicv3_distif_post_restore(unsigned int rdist_proc_num)
+{
+	uintptr_t gicr_base;
+
+	assert(gicv3_driver_data);
+	assert(gicv3_driver_data->rdistif_base_addrs);
+
+	/*
+	 * According to the TRM, there is only one instance of the
+	 * GICR_WAKER.Sleep and GICR_WAKER.Quiescent bits that can be accessed
+	 * through any of the Redistributor.
+	 */
+	gicr_base = gicv3_driver_data->rdistif_base_addrs[rdist_proc_num];
+	assert(gicr_base);
+
+	/*
+	 * Writes to GICR_WAKER.Sleep bit are ignored if GICR_WAKER.Quiescent
+	 * bit is not set. We should be alright on power on path, therefore
+	 * coming out of sleep and Quiescent should be set, but we assert in
+	 * case.
+	 */
+	assert(gicr_read_waker(gicr_base) & WAKER_QSC_BIT);
+
+	/* Clear GICR_WAKER.Sleep */
+	gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) & ~WAKER_SL_BIT);
+
+	/*
+	 * We don't know if the effects of setting GICR_WAKER.Sleep bit is
+	 * instantaneous, so we wait until the interface is not Quiescent
+	 * anymore.
+	 */
+	while (gicr_read_waker(gicr_base) & WAKER_QSC_BIT)
+		;
+}
+
diff --git a/drivers/arm/gic/v3/gic500.c b/drivers/arm/gic/v3/gic500.c
new file mode 100644
index 0000000..f03e33f
--- /dev/null
+++ b/drivers/arm/gic/v3/gic500.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Driver for GIC500-specific features. This driver only overrides APIs that are
+ * different to those generic ones in GICv3 driver.
+ */
+#include "gicv3_private.h"
+
+void gicv3_distif_pre_save(unsigned int proc_num)
+{
+	arm_gicv3_distif_pre_save(proc_num);
+}
+
+void gicv3_distif_post_restore(unsigned int proc_num)
+{
+	arm_gicv3_distif_post_restore(proc_num);
+}
+
diff --git a/drivers/arm/gic/v3/gic600.c b/drivers/arm/gic/v3/gic600.c
index 4ea31ab..eb4fc54 100644
--- a/drivers/arm/gic/v3/gic600.c
+++ b/drivers/arm/gic/v3/gic600.c
@@ -18,32 +18,29 @@
 #include "gicv3_private.h"
 
 /* GIC600-specific register offsets */
-#define GICR_PWRR		0x24
+#define GICR_PWRR	0x24
 
 /* GICR_PWRR fields */
 #define PWRR_RDPD_SHIFT		0
 #define PWRR_RDGPD_SHIFT	2
 #define PWRR_RDGPO_SHIFT	3
 
-#define PWRR_RDGPD		(1 << PWRR_RDGPD_SHIFT)
-#define PWRR_RDGPO		(1 << PWRR_RDGPO_SHIFT)
+#define PWRR_RDGPD	(1 << PWRR_RDGPD_SHIFT)
+#define PWRR_RDGPO	(1 << PWRR_RDGPO_SHIFT)
 
 /* Values to write to GICR_PWRR register to power redistributor */
-#define PWRR_ON			(0 << PWRR_RDPD_SHIFT)
-#define PWRR_OFF		(1 << PWRR_RDPD_SHIFT)
-
-/* Generic GICv3 resources */
-extern const gicv3_driver_data_t *gicv3_driver_data;
+#define PWRR_ON		(0 << PWRR_RDPD_SHIFT)
+#define PWRR_OFF	(1 << PWRR_RDPD_SHIFT)
 
 /* GIC600-specific accessor functions */
 static void gicr_write_pwrr(uintptr_t base, unsigned int val)
 {
-       mmio_write_32(base + GICR_PWRR, val);
+	mmio_write_32(base + GICR_PWRR, val);
 }
 
 static uint32_t gicr_read_pwrr(uintptr_t base)
 {
-       return mmio_read_32(base + GICR_PWRR);
+	return mmio_read_32(base + GICR_PWRR);
 }
 
 static int gicr_group_powering_down(uint32_t pwrr)
@@ -82,6 +79,16 @@
 	}
 }
 
+void gicv3_distif_pre_save(unsigned int proc_num)
+{
+	arm_gicv3_distif_pre_save(proc_num);
+}
+
+void gicv3_distif_post_restore(unsigned int proc_num)
+{
+	arm_gicv3_distif_post_restore(proc_num);
+}
+
 /*
  * Power off GIC600 redistributor
  */
diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c
index b68d998..1a018d8 100644
--- a/drivers/arm/gic/v3/gicv3_main.c
+++ b/drivers/arm/gic/v3/gicv3_main.c
@@ -21,6 +21,27 @@
 #pragma weak gicv3_rdistif_off
 #pragma weak gicv3_rdistif_on
 
+
+/* Helper macros to save and restore GICD registers to and from the context */
+#define RESTORE_GICD_REGS(base, ctx, intr_num, reg, REG)		\
+	do {								\
+		for (unsigned int int_id = MIN_SPI_ID; int_id < intr_num; \
+				int_id += (1 << REG##_SHIFT)) {		\
+			gicd_write_##reg(base, int_id,			\
+				ctx->gicd_##reg[(int_id - MIN_SPI_ID) >> REG##_SHIFT]); \
+		}							\
+	} while (0)
+
+#define SAVE_GICD_REGS(base, ctx, intr_num, reg, REG)			\
+	do {								\
+		for (unsigned int int_id = MIN_SPI_ID; int_id < intr_num; \
+				int_id += (1 << REG##_SHIFT)) {		\
+			ctx->gicd_##reg[(int_id - MIN_SPI_ID) >> REG##_SHIFT] =\
+					gicd_read_##reg(base, int_id);	\
+		}							\
+	} while (0)
+
+
 /*******************************************************************************
  * This function initialises the ARM GICv3 driver in EL3 with provided platform
  * inputs.
@@ -406,3 +427,345 @@
 	/* Else it is a Group 0 Secure interrupt */
 	return INTR_GROUP0;
 }
+
+/*****************************************************************************
+ * Function to save and disable the GIC ITS register context. The power
+ * management of GIC ITS is implementation-defined and this function doesn't
+ * save any memory structures required to support ITS. As the sequence to save
+ * this state is implementation defined, it should be executed in platform
+ * specific code. Calling this function alone and then powering down the GIC and
+ * ITS without implementing the aforementioned platform specific code will
+ * corrupt the ITS state.
+ *
+ * This function must be invoked after the GIC CPU interface is disabled.
+ *****************************************************************************/
+void gicv3_its_save_disable(uintptr_t gits_base, gicv3_its_ctx_t * const its_ctx)
+{
+	int i;
+
+	assert(gicv3_driver_data);
+	assert(IS_IN_EL3());
+	assert(its_ctx);
+	assert(gits_base);
+
+	its_ctx->gits_ctlr = gits_read_ctlr(gits_base);
+
+	/* Disable the ITS */
+	gits_write_ctlr(gits_base, its_ctx->gits_ctlr &
+					(~GITS_CTLR_ENABLED_BIT));
+
+	/* Wait for quiescent state */
+	gits_wait_for_quiescent_bit(gits_base);
+
+	its_ctx->gits_cbaser = gits_read_cbaser(gits_base);
+	its_ctx->gits_cwriter = gits_read_cwriter(gits_base);
+
+	for (i = 0; i < ARRAY_SIZE(its_ctx->gits_baser); i++)
+		its_ctx->gits_baser[i] = gits_read_baser(gits_base, i);
+}
+
+/*****************************************************************************
+ * Function to restore the GIC ITS register context. The power
+ * management of GIC ITS is implementation defined and this function doesn't
+ * restore any memory structures required to support ITS. The assumption is
+ * that these structures are in memory and are retained during system suspend.
+ *
+ * This must be invoked before the GIC CPU interface is enabled.
+ *****************************************************************************/
+void gicv3_its_restore(uintptr_t gits_base, const gicv3_its_ctx_t * const its_ctx)
+{
+	int i;
+
+	assert(gicv3_driver_data);
+	assert(IS_IN_EL3());
+	assert(its_ctx);
+	assert(gits_base);
+
+	/* Assert that the GITS is disabled and quiescent */
+	assert((gits_read_ctlr(gits_base) & GITS_CTLR_ENABLED_BIT) == 0);
+	assert((gits_read_ctlr(gits_base) & GITS_CTLR_QUIESCENT_BIT) != 0);
+
+	gits_write_cbaser(gits_base, its_ctx->gits_cbaser);
+	gits_write_cwriter(gits_base, its_ctx->gits_cwriter);
+
+	for (i = 0; i < ARRAY_SIZE(its_ctx->gits_baser); i++)
+		gits_write_baser(gits_base, i, its_ctx->gits_baser[i]);
+
+	/* Restore the ITS CTLR but leave the ITS disabled */
+	gits_write_ctlr(gits_base, its_ctx->gits_ctlr &
+			(~GITS_CTLR_ENABLED_BIT));
+}
+
+/*****************************************************************************
+ * Function to save the GIC Redistributor register context. This function
+ * must be invoked after CPU interface disable and prior to Distributor save.
+ *****************************************************************************/
+void gicv3_rdistif_save(unsigned int proc_num, gicv3_redist_ctx_t * const rdist_ctx)
+{
+	uintptr_t gicr_base;
+	unsigned int int_id;
+
+	assert(gicv3_driver_data);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs);
+	assert(IS_IN_EL3());
+	assert(rdist_ctx);
+
+	gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+
+	/*
+	 * Wait for any write to GICR_CTLR to complete before trying to save any
+	 * state.
+	 */
+	gicr_wait_for_pending_write(gicr_base);
+
+	rdist_ctx->gicr_ctlr = gicr_read_ctlr(gicr_base);
+
+	rdist_ctx->gicr_propbaser = gicr_read_propbaser(gicr_base);
+	rdist_ctx->gicr_pendbaser = gicr_read_pendbaser(gicr_base);
+
+	rdist_ctx->gicr_igroupr0 = gicr_read_igroupr0(gicr_base);
+	rdist_ctx->gicr_isenabler0 = gicr_read_isenabler0(gicr_base);
+	rdist_ctx->gicr_ispendr0 = gicr_read_ispendr0(gicr_base);
+	rdist_ctx->gicr_isactiver0 = gicr_read_isactiver0(gicr_base);
+	rdist_ctx->gicr_icfgr0 = gicr_read_icfgr0(gicr_base);
+	rdist_ctx->gicr_icfgr1 = gicr_read_icfgr1(gicr_base);
+	rdist_ctx->gicr_igrpmodr0 = gicr_read_igrpmodr0(gicr_base);
+	rdist_ctx->gicr_nsacr = gicr_read_nsacr(gicr_base);
+	for (int_id = MIN_SGI_ID; int_id < TOTAL_PCPU_INTR_NUM;
+			int_id += (1 << IPRIORITYR_SHIFT)) {
+		rdist_ctx->gicr_ipriorityr[(int_id - MIN_SGI_ID) >> IPRIORITYR_SHIFT] =
+				gicr_read_ipriorityr(gicr_base, int_id);
+	}
+
+
+	/*
+	 * Call the pre-save hook that implements the IMP DEF sequence that may
+	 * be required on some GIC implementations. As this may need to access
+	 * the Redistributor registers, we pass it proc_num.
+	 */
+	gicv3_distif_pre_save(proc_num);
+}
+
+/*****************************************************************************
+ * Function to restore the GIC Redistributor register context. We disable
+ * LPI and per-cpu interrupts before we start restore of the Redistributor.
+ * This function must be invoked after Distributor restore but prior to
+ * CPU interface enable. The pending and active interrupts are restored
+ * after the interrupts are fully configured and enabled.
+ *****************************************************************************/
+void gicv3_rdistif_init_restore(unsigned int proc_num,
+				const gicv3_redist_ctx_t * const rdist_ctx)
+{
+	uintptr_t gicr_base;
+	unsigned int int_id;
+
+	assert(gicv3_driver_data);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs);
+	assert(IS_IN_EL3());
+	assert(rdist_ctx);
+
+	gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+
+	/* Power on redistributor */
+	gicv3_rdistif_on(proc_num);
+
+	/*
+	 * Call the post-restore hook that implements the IMP DEF sequence that
+	 * may be required on some GIC implementations. As this may need to
+	 * access the Redistributor registers, we pass it proc_num.
+	 */
+	gicv3_distif_post_restore(proc_num);
+
+	/*
+	 * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a
+	 * more scalable approach as it avoids clearing the enable bits in the
+	 * GICD_CTLR
+	 */
+	gicr_write_icenabler0(gicr_base, ~0);
+	/* Wait for pending writes to GICR_ICENABLER */
+	gicr_wait_for_pending_write(gicr_base);
+
+	/*
+	 * Disable the LPIs to avoid unpredictable behavior when writing to
+	 * GICR_PROPBASER and GICR_PENDBASER.
+	 */
+	gicr_write_ctlr(gicr_base,
+			rdist_ctx->gicr_ctlr & ~(GICR_CTLR_EN_LPIS_BIT));
+
+	/* Restore registers' content */
+	gicr_write_propbaser(gicr_base, rdist_ctx->gicr_propbaser);
+	gicr_write_pendbaser(gicr_base, rdist_ctx->gicr_pendbaser);
+
+	gicr_write_igroupr0(gicr_base, rdist_ctx->gicr_igroupr0);
+
+	for (int_id = MIN_SGI_ID; int_id < TOTAL_PCPU_INTR_NUM;
+			int_id += (1 << IPRIORITYR_SHIFT)) {
+		gicr_write_ipriorityr(gicr_base, int_id,
+		rdist_ctx->gicr_ipriorityr[
+				(int_id - MIN_SGI_ID) >> IPRIORITYR_SHIFT]);
+	}
+
+	gicr_write_icfgr0(gicr_base, rdist_ctx->gicr_icfgr0);
+	gicr_write_icfgr1(gicr_base, rdist_ctx->gicr_icfgr1);
+	gicr_write_igrpmodr0(gicr_base, rdist_ctx->gicr_igrpmodr0);
+	gicr_write_nsacr(gicr_base, rdist_ctx->gicr_nsacr);
+
+	/* Restore after group and priorities are set */
+	gicr_write_ispendr0(gicr_base, rdist_ctx->gicr_ispendr0);
+	gicr_write_isactiver0(gicr_base, rdist_ctx->gicr_isactiver0);
+
+	/*
+	 * Wait for all writes to the Distributor to complete before enabling
+	 * the SGI and PPIs.
+	 */
+	gicr_wait_for_upstream_pending_write(gicr_base);
+	gicr_write_isenabler0(gicr_base, rdist_ctx->gicr_isenabler0);
+
+	/*
+	 * Restore GICR_CTLR.Enable_LPIs bit and wait for pending writes in case
+	 * the first write to GICR_CTLR was still in flight (this write only
+	 * restores GICR_CTLR.Enable_LPIs and no waiting is required for this
+	 * bit).
+	 */
+	gicr_write_ctlr(gicr_base, rdist_ctx->gicr_ctlr);
+	gicr_wait_for_pending_write(gicr_base);
+}
+
+/*****************************************************************************
+ * Function to save the GIC Distributor register context. This function
+ * must be invoked after CPU interface disable and Redistributor save.
+ *****************************************************************************/
+void gicv3_distif_save(gicv3_dist_ctx_t * const dist_ctx)
+{
+	unsigned int num_ints;
+
+	assert(gicv3_driver_data);
+	assert(gicv3_driver_data->gicd_base);
+	assert(IS_IN_EL3());
+	assert(dist_ctx);
+
+	uintptr_t gicd_base = gicv3_driver_data->gicd_base;
+
+	num_ints = gicd_read_typer(gicd_base);
+	num_ints &= TYPER_IT_LINES_NO_MASK;
+	num_ints = (num_ints + 1) << 5;
+
+	assert(num_ints <= MAX_SPI_ID + 1);
+
+	/* Wait for pending write to complete */
+	gicd_wait_for_pending_write(gicd_base);
+
+	/* Save the GICD_CTLR */
+	dist_ctx->gicd_ctlr = gicd_read_ctlr(gicd_base);
+
+	/* Save GICD_IGROUPR for INTIDs 32 - 1020 */
+	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUPR);
+
+	/* Save GICD_ISENABLER for INT_IDs 32 - 1020 */
+	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLER);
+
+	/* Save GICD_ISPENDR for INTIDs 32 - 1020 */
+	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPENDR);
+
+	/* Save GICD_ISACTIVER for INTIDs 32 - 1020 */
+	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVER);
+
+	/* Save GICD_IPRIORITYR for INTIDs 32 - 1020 */
+	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITYR);
+
+	/* Save GICD_ICFGR for INTIDs 32 - 1020 */
+	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFGR);
+
+	/* Save GICD_IGRPMODR for INTIDs 32 - 1020 */
+	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMODR);
+
+	/* Save GICD_NSACR for INTIDs 32 - 1020 */
+	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSACR);
+
+	/* Save GICD_IROUTER for INTIDs 32 - 1024 */
+	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTER);
+
+	/*
+	 * GICD_ITARGETSR<n> and GICD_SPENDSGIR<n> are RAZ/WI when
+	 * GICD_CTLR.ARE_(S|NS) bits are set which is the case for our GICv3
+	 * driver.
+	 */
+}
+
+/*****************************************************************************
+ * Function to restore the GIC Distributor register context. We disable G0, G1S
+ * and G1NS interrupt groups before we start restore of the Distributor. This
+ * function must be invoked prior to Redistributor restore and CPU interface
+ * enable. The pending and active interrupts are restored after the interrupts
+ * are fully configured and enabled.
+ *****************************************************************************/
+void gicv3_distif_init_restore(const gicv3_dist_ctx_t * const dist_ctx)
+{
+	unsigned int num_ints = 0;
+
+	assert(gicv3_driver_data);
+	assert(gicv3_driver_data->gicd_base);
+	assert(IS_IN_EL3());
+	assert(dist_ctx);
+
+	uintptr_t gicd_base = gicv3_driver_data->gicd_base;
+
+	/*
+	 * Clear the "enable" bits for G0/G1S/G1NS interrupts before configuring
+	 * the ARE_S bit. The Distributor might generate a system error
+	 * otherwise.
+	 */
+	gicd_clr_ctlr(gicd_base,
+		      CTLR_ENABLE_G0_BIT |
+		      CTLR_ENABLE_G1S_BIT |
+		      CTLR_ENABLE_G1NS_BIT,
+		      RWP_TRUE);
+
+	/* Set the ARE_S and ARE_NS bit now that interrupts have been disabled */
+	gicd_set_ctlr(gicd_base, CTLR_ARE_S_BIT | CTLR_ARE_NS_BIT, RWP_TRUE);
+
+	num_ints = gicd_read_typer(gicd_base);
+	num_ints &= TYPER_IT_LINES_NO_MASK;
+	num_ints = (num_ints + 1) << 5;
+
+	assert(num_ints <= MAX_SPI_ID + 1);
+
+	/* Restore GICD_IGROUPR for INTIDs 32 - 1020 */
+	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUPR);
+
+	/* Restore GICD_IPRIORITYR for INTIDs 32 - 1020 */
+	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITYR);
+
+	/* Restore GICD_ICFGR for INTIDs 32 - 1020 */
+	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFGR);
+
+	/* Restore GICD_IGRPMODR for INTIDs 32 - 1020 */
+	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMODR);
+
+	/* Restore GICD_NSACR for INTIDs 32 - 1020 */
+	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSACR);
+
+	/* Restore GICD_IROUTER for INTIDs 32 - 1020 */
+	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTER);
+
+	/*
+	 * Restore ISENABLER, ISPENDR and ISACTIVER after the interrupts are
+	 * configured.
+	 */
+
+	/* Restore GICD_ISENABLER for INT_IDs 32 - 1020 */
+	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLER);
+
+	/* Restore GICD_ISPENDR for INTIDs 32 - 1020 */
+	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPENDR);
+
+	/* Restore GICD_ISACTIVER for INTIDs 32 - 1020 */
+	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVER);
+
+	/* Restore the GICD_CTLR */
+	gicd_write_ctlr(gicd_base, dist_ctx->gicd_ctlr);
+	gicd_wait_for_pending_write(gicd_base);
+
+}
diff --git a/drivers/arm/gic/v3/gicv3_private.h b/drivers/arm/gic/v3/gicv3_private.h
index f95cfab..59298ed 100644
--- a/drivers/arm/gic/v3/gicv3_private.h
+++ b/drivers/arm/gic/v3/gicv3_private.h
@@ -7,6 +7,7 @@
 #ifndef __GICV3_PRIVATE_H__
 #define __GICV3_PRIVATE_H__
 
+#include <assert.h>
 #include <gic_common.h>
 #include <gicv3.h>
 #include <mmio.h>
@@ -22,17 +23,6 @@
 #define RWP_FALSE		0
 
 /*
- * Macro to wait for updates to :
- * GICD_CTLR[2:0] - the Group Enables
- * GICD_CTLR[5:4] - the ARE bits
- * GICD_ICENABLERn - the clearing of enable state for SPIs
- */
-#define gicd_wait_for_pending_write(gicd_base)			\
-	do {							\
-		;						\
-	} while (gicd_read_ctlr(gicd_base) & GICD_CTLR_RWP_BIT)
-
-/*
  * Macro to convert an mpidr to a value suitable for programming into a
  * GICD_IROUTER. Bits[31:24] in the MPIDR are cleared as they are not relevant
  * to GICv3.
@@ -42,18 +32,6 @@
 	 (irm & IROUTER_IRM_MASK) << IROUTER_IRM_SHIFT)
 
 /*
- * Macro to wait for updates to :
- * GICR_ICENABLER0
- * GICR_CTLR.DPG1S
- * GICR_CTLR.DPG1NS
- * GICR_CTLR.DPG0
- */
-#define gicr_wait_for_pending_write(gicr_base)			\
-	do {							\
-		;						\
-	} while (gicr_read_ctlr(gicr_base) & GICR_CTLR_RWP_BIT)
-
-/*
  * Macro to convert a GICR_TYPER affinity value into a MPIDR value. Bits[31:24]
  * are zeroes.
  */
@@ -66,6 +44,11 @@
 #endif
 
 /*******************************************************************************
+ * GICv3 private global variables declarations
+ ******************************************************************************/
+extern const gicv3_driver_data_t *gicv3_driver_data;
+
+/*******************************************************************************
  * Private GICv3 function prototypes for accessing entire registers.
  * Note: The raw register values correspond to multiple interrupt IDs and
  * the number of interrupt IDs involved depends on the register accessed.
@@ -116,6 +99,18 @@
 /*******************************************************************************
  * GIC Distributor interface accessors
  ******************************************************************************/
+/*
+ * Wait for updates to :
+ * GICD_CTLR[2:0] - the Group Enables
+ * GICD_CTLR[5:4] - the ARE bits
+ * GICD_ICENABLERn - the clearing of enable state for SPIs
+ */
+static inline void gicd_wait_for_pending_write(uintptr_t gicd_base)
+{
+	while (gicd_read_ctlr(gicd_base) & GICD_CTLR_RWP_BIT)
+		;
+}
+
 static inline unsigned int gicd_read_pidr2(uintptr_t base)
 {
 	return mmio_read_32(base + GICD_PIDR2_GICV3);
@@ -161,6 +156,11 @@
 	return mmio_read_64(base + GICR_CTLR);
 }
 
+static inline void gicr_write_ctlr(uintptr_t base, uint64_t val)
+{
+	mmio_write_64(base + GICR_CTLR, val);
+}
+
 static inline unsigned long long gicr_read_typer(uintptr_t base)
 {
 	return mmio_read_64(base + GICR_TYPER);
@@ -176,6 +176,29 @@
 	mmio_write_32(base + GICR_WAKER, val);
 }
 
+/*
+ * Wait for updates to :
+ * GICR_ICENABLER0
+ * GICR_CTLR.DPG1S
+ * GICR_CTLR.DPG1NS
+ * GICR_CTLR.DPG0
+ */
+static inline void gicr_wait_for_pending_write(uintptr_t gicr_base)
+{
+	while (gicr_read_ctlr(gicr_base) & GICR_CTLR_RWP_BIT)
+		;
+}
+
+static inline void gicr_wait_for_upstream_pending_write(uintptr_t gicr_base)
+{
+	while (gicr_read_ctlr(gicr_base) & GICR_CTLR_UWP_BIT)
+		;
+}
+
+/* Private implementation of Distributor power control hooks */
+void arm_gicv3_distif_pre_save(unsigned int rdist_proc_num);
+void arm_gicv3_distif_post_restore(unsigned int rdist_proc_num);
+
 /*******************************************************************************
  * GIC Re-distributor functions for accessing entire registers.
  * Note: The raw register values correspond to multiple interrupt IDs and
@@ -206,6 +229,16 @@
 	return mmio_read_32(base + GICR_IGROUPR0);
 }
 
+static inline unsigned int gicr_read_ispendr0(uintptr_t base)
+{
+	return mmio_read_32(base + GICR_ISPENDR0);
+}
+
+static inline void gicr_write_ispendr0(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICR_ISPENDR0, val);
+}
+
 static inline void gicr_write_igroupr0(uintptr_t base, unsigned int val)
 {
 	mmio_write_32(base + GICR_IGROUPR0, val);
@@ -221,14 +254,120 @@
 	mmio_write_32(base + GICR_IGRPMODR0, val);
 }
 
+static inline unsigned int gicr_read_nsacr(uintptr_t base)
+{
+	return mmio_read_32(base + GICR_NSACR);
+}
+
+static inline void gicr_write_nsacr(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICR_NSACR, val);
+}
+
+static inline unsigned int gicr_read_isactiver0(uintptr_t base)
+{
+	return mmio_read_32(base + GICR_ISACTIVER0);
+}
+
+static inline void gicr_write_isactiver0(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICR_ISACTIVER0, val);
+}
+
+static inline unsigned int gicr_read_icfgr0(uintptr_t base)
+{
+	return mmio_read_32(base + GICR_ICFGR0);
+}
+
 static inline unsigned int gicr_read_icfgr1(uintptr_t base)
 {
 	return mmio_read_32(base + GICR_ICFGR1);
 }
 
+static inline void gicr_write_icfgr0(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICR_ICFGR0, val);
+}
+
 static inline void gicr_write_icfgr1(uintptr_t base, unsigned int val)
 {
 	mmio_write_32(base + GICR_ICFGR1, val);
 }
 
+static inline unsigned int gicr_read_propbaser(uintptr_t base)
+{
+	return mmio_read_32(base + GICR_PROPBASER);
+}
+
+static inline void gicr_write_propbaser(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICR_PROPBASER, val);
+}
+
+static inline unsigned int gicr_read_pendbaser(uintptr_t base)
+{
+	return mmio_read_32(base + GICR_PENDBASER);
+}
+
+static inline void gicr_write_pendbaser(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICR_PENDBASER, val);
+}
+
+/*******************************************************************************
+ * GIC ITS functions to read and write entire ITS registers.
+ ******************************************************************************/
+static inline uint32_t gits_read_ctlr(uintptr_t base)
+{
+	return mmio_read_32(base + GITS_CTLR);
+}
+
+static inline void gits_write_ctlr(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GITS_CTLR, val);
+}
+
+static inline uint64_t gits_read_cbaser(uintptr_t base)
+{
+	return mmio_read_64(base + GITS_CBASER);
+}
+
+static inline void gits_write_cbaser(uintptr_t base, uint64_t val)
+{
+	mmio_write_32(base + GITS_CBASER, val);
+}
+
+static inline uint64_t gits_read_cwriter(uintptr_t base)
+{
+	return mmio_read_64(base + GITS_CWRITER);
+}
+
+static inline void gits_write_cwriter(uintptr_t base, uint64_t val)
+{
+	mmio_write_32(base + GITS_CWRITER, val);
+}
+
+static inline uint64_t gits_read_baser(uintptr_t base, unsigned int its_table_id)
+{
+	assert(its_table_id < 8);
+	return mmio_read_64(base + GITS_BASER + (8 * its_table_id));
+}
+
+static inline void gits_write_baser(uintptr_t base, unsigned int its_table_id, uint64_t val)
+{
+	assert(its_table_id < 8);
+	mmio_write_64(base + GITS_BASER + (8 * its_table_id), val);
+}
+
+/*
+ * Wait for Quiescent bit when GIC ITS is disabled
+ */
+static inline void gits_wait_for_quiescent_bit(uintptr_t gits_base)
+{
+	assert(!(gits_read_ctlr(gits_base) & GITS_CTLR_ENABLED_BIT));
+	while ((gits_read_ctlr(gits_base) & GITS_CTLR_QUIESCENT_BIT) == 0)
+		;
+}
+
+
 #endif /* __GICV3_PRIVATE_H__ */
diff --git a/include/drivers/arm/arm_gicv3_common.h b/include/drivers/arm/arm_gicv3_common.h
new file mode 100644
index 0000000..8970e3f
--- /dev/null
+++ b/include/drivers/arm/arm_gicv3_common.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __ARM_GICV3_COMMON_H__
+#define __ARM_GICV3_COMMON_H__
+
+/*******************************************************************************
+ * GIC500/GIC600 Re-distributor interface registers & constants
+ ******************************************************************************/
+
+/* GICR_WAKER implementation-defined bit definitions */
+#define	WAKER_SL_SHIFT		0
+#define	WAKER_QSC_SHIFT		31
+
+#define WAKER_SL_BIT		(1U << WAKER_SL_SHIFT)
+#define WAKER_QSC_BIT		(1U << WAKER_QSC_SHIFT)
+
+#endif /* __ARM_GICV3_COMMON_H__ */
diff --git a/include/drivers/arm/gic_common.h b/include/drivers/arm/gic_common.h
index 7e097ad..b9cae80 100644
--- a/include/drivers/arm/gic_common.h
+++ b/include/drivers/arm/gic_common.h
@@ -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
  */
@@ -14,6 +14,10 @@
 #define MIN_SGI_ID		0
 #define MIN_PPI_ID		16
 #define MIN_SPI_ID		32
+#define MAX_SPI_ID		1019
+
+#define TOTAL_SPI_INTR_NUM	(MAX_SPI_ID - MIN_SPI_ID + 1)
+#define TOTAL_PCPU_INTR_NUM	(MIN_SPI_ID - MIN_SGI_ID)
 
 /* Mask for the priority field common to all GIC interfaces */
 #define GIC_PRI_MASK			0xff
diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h
index 8d9981a..c52fe48 100644
--- a/include/drivers/arm/gicv3.h
+++ b/include/drivers/arm/gicv3.h
@@ -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
  */
@@ -7,6 +7,8 @@
 #ifndef __GICV3_H__
 #define __GICV3_H__
 
+#include "utils_def.h"
+
 /*******************************************************************************
  * GICv3 miscellaneous definitions
  ******************************************************************************/
@@ -66,9 +68,12 @@
 #define GICD_CTLR_RWP_BIT		(1 << GICD_CTLR_RWP_SHIFT)
 
 /* GICD_IROUTER shifts and masks */
+#define IROUTER_SHIFT		0
 #define IROUTER_IRM_SHIFT	31
 #define IROUTER_IRM_MASK	0x1
 
+#define NUM_OF_DIST_REGS	30
+
 /*******************************************************************************
  * GICv3 Re-distributor interface registers & constants
  ******************************************************************************/
@@ -77,18 +82,29 @@
 #define GICR_CTLR		0x0
 #define GICR_TYPER		0x08
 #define GICR_WAKER		0x14
+#define GICR_PROPBASER		0x70
+#define GICR_PENDBASER		0x78
 #define GICR_IGROUPR0		(GICR_SGIBASE_OFFSET + 0x80)
 #define GICR_ISENABLER0		(GICR_SGIBASE_OFFSET + 0x100)
 #define GICR_ICENABLER0		(GICR_SGIBASE_OFFSET + 0x180)
+#define GICR_ISPENDR0		(GICR_SGIBASE_OFFSET + 0x200)
+#define GICR_ICPENDR0		(GICR_SGIBASE_OFFSET + 0x280)
+#define GICR_ISACTIVER0		(GICR_SGIBASE_OFFSET + 0x300)
+#define GICR_ICACTIVER0		(GICR_SGIBASE_OFFSET + 0x380)
 #define GICR_IPRIORITYR		(GICR_SGIBASE_OFFSET + 0x400)
 #define GICR_ICFGR0		(GICR_SGIBASE_OFFSET + 0xc00)
 #define GICR_ICFGR1		(GICR_SGIBASE_OFFSET + 0xc04)
 #define GICR_IGRPMODR0		(GICR_SGIBASE_OFFSET + 0xd00)
+#define GICR_NSACR		(GICR_SGIBASE_OFFSET + 0xe00)
 
 /* GICR_CTLR bit definitions */
+#define GICR_CTLR_UWP_SHIFT	31
+#define GICR_CTLR_UWP_MASK	0x1
+#define GICR_CTLR_UWP_BIT	(1U << GICR_CTLR_UWP_SHIFT)
 #define GICR_CTLR_RWP_SHIFT	3
 #define GICR_CTLR_RWP_MASK	0x1
-#define GICR_CTLR_RWP_BIT	(1 << GICR_CTLR_RWP_SHIFT)
+#define GICR_CTLR_RWP_BIT	(1U << GICR_CTLR_RWP_SHIFT)
+#define GICR_CTLR_EN_LPIS_BIT	(1U << 0)
 
 /* GICR_WAKER bit definitions */
 #define WAKER_CA_SHIFT		2
@@ -111,6 +127,8 @@
 
 #define TYPER_LAST_BIT		(1 << TYPER_LAST_SHIFT)
 
+#define NUM_OF_REDIST_REGS	30
+
 /*******************************************************************************
  * GICv3 CPU interface registers & constants
  ******************************************************************************/
@@ -147,10 +165,29 @@
 #define IAR1_EL1_INTID_SHIFT		0
 #define IAR1_EL1_INTID_MASK		0xffffff
 
+/*****************************************************************************
+ * GICv3 ITS registers and constants
+ *****************************************************************************/
+
+#define GITS_CTLR			0x0
+#define GITS_IIDR			0x4
+#define GITS_TYPER			0x8
+#define GITS_CBASER			0x80
+#define GITS_CWRITER			0x88
+#define GITS_CREADR			0x90
+#define GITS_BASER			0x100
+
+/* GITS_CTLR bit definitions */
+#define GITS_CTLR_ENABLED_BIT		1
+#define GITS_CTLR_QUIESCENT_SHIFT	31
+#define GITS_CTLR_QUIESCENT_BIT		(1U << GITS_CTLR_QUIESCENT_SHIFT)
+
 #ifndef __ASSEMBLY__
 
+#include <gic_common.h>
 #include <stdint.h>
 #include <types.h>
+#include <utils_def.h>
 
 #define gicv3_is_intr_id_special_identifier(id)	\
 	(((id) >= PENDING_G1S_INTID) && ((id) <= GIC_SPURIOUS_INTERRUPT))
@@ -172,6 +209,16 @@
 							IAR0_EL1_INTID_MASK
 #define gicv3_end_of_interrupt(id)		write_icc_eoir0_el1(id)
 
+/*
+ * This macro returns the total number of GICD registers corresponding to
+ * the name.
+ */
+#define GICD_NUM_REGS(reg_name)	\
+	DIV_ROUND_UP_2EVAL(TOTAL_SPI_INTR_NUM, (1 << reg_name ## _SHIFT))
+
+#define GICR_NUM_REGS(reg_name)	\
+	DIV_ROUND_UP_2EVAL(TOTAL_PCPU_INTR_NUM, (1 << reg_name ## _SHIFT))
+
 /*******************************************************************************
  * This structure describes some of the implementation defined attributes of the
  * GICv3 IP. It is used by the platform port to specify these attributes in order
@@ -229,6 +276,50 @@
 	mpidr_hash_fn mpidr_to_core_pos;
 } gicv3_driver_data_t;
 
+typedef struct gicv3_redist_ctx {
+	/* 64 bits registers */
+	uint64_t gicr_propbaser;
+	uint64_t gicr_pendbaser;
+
+	/* 32 bits registers */
+	uint32_t gicr_ctlr;
+	uint32_t gicr_igroupr0;
+	uint32_t gicr_isenabler0;
+	uint32_t gicr_ispendr0;
+	uint32_t gicr_isactiver0;
+	uint32_t gicr_ipriorityr[GICR_NUM_REGS(IPRIORITYR)];
+	uint32_t gicr_icfgr0;
+	uint32_t gicr_icfgr1;
+	uint32_t gicr_igrpmodr0;
+	uint32_t gicr_nsacr;
+} gicv3_redist_ctx_t;
+
+typedef struct gicv3_dist_ctx {
+	/* 64 bits registers */
+	uint64_t gicd_irouter[TOTAL_SPI_INTR_NUM];
+
+	/* 32 bits registers */
+	uint32_t gicd_ctlr;
+	uint32_t gicd_igroupr[GICD_NUM_REGS(IGROUPR)];
+	uint32_t gicd_isenabler[GICD_NUM_REGS(ISENABLER)];
+	uint32_t gicd_ispendr[GICD_NUM_REGS(ISPENDR)];
+	uint32_t gicd_isactiver[GICD_NUM_REGS(ISACTIVER)];
+	uint32_t gicd_ipriorityr[GICD_NUM_REGS(IPRIORITYR)];
+	uint32_t gicd_icfgr[GICD_NUM_REGS(ICFGR)];
+	uint32_t gicd_igrpmodr[GICD_NUM_REGS(IGRPMODR)];
+	uint32_t gicd_nsacr[GICD_NUM_REGS(NSACR)];
+} gicv3_dist_ctx_t;
+
+typedef struct gicv3_its_ctx {
+	/* 64 bits registers */
+	uint64_t gits_cbaser;
+	uint64_t gits_cwriter;
+	uint64_t gits_baser[8];
+
+	/* 32 bits registers */
+	uint32_t gits_ctlr;
+} gicv3_its_ctx_t;
+
 /*******************************************************************************
  * GICv3 EL3 driver API
  ******************************************************************************/
@@ -243,7 +334,20 @@
 unsigned int gicv3_get_pending_interrupt_id(void);
 unsigned int gicv3_get_interrupt_type(unsigned int id,
 					  unsigned int proc_num);
-
+void gicv3_distif_init_restore(const gicv3_dist_ctx_t * const dist_ctx);
+void gicv3_distif_save(gicv3_dist_ctx_t * const dist_ctx);
+/*
+ * gicv3_distif_post_restore and gicv3_distif_pre_save must be implemented if
+ * gicv3_distif_save and gicv3_rdistif_init_restore are used. If no
+ * implementation-defined sequence is needed at these steps, an empty function
+ * can be provided.
+ */
+void gicv3_distif_post_restore(unsigned int proc_num);
+void gicv3_distif_pre_save(unsigned int proc_num);
+void gicv3_rdistif_init_restore(unsigned int proc_num, const gicv3_redist_ctx_t * const rdist_ctx);
+void gicv3_rdistif_save(unsigned int proc_num, gicv3_redist_ctx_t * const rdist_ctx);
+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);
 
 #endif /* __ASSEMBLY__ */
 #endif /* __GICV3_H__ */
diff --git a/include/lib/psci/psci.h b/include/lib/psci/psci.h
index 0ed39c9..0b44ab2 100644
--- a/include/lib/psci/psci.h
+++ b/include/lib/psci/psci.h
@@ -65,6 +65,9 @@
 #define PSCI_STAT_RESIDENCY_AARCH64	U(0xc4000010)
 #define PSCI_STAT_COUNT_AARCH32		U(0x84000011)
 #define PSCI_STAT_COUNT_AARCH64		U(0xc4000011)
+#define PSCI_MEM_PROTECT		U(0x84000013)
+#define PSCI_MEM_CHK_RANGE_AARCH32	U(0x84000014)
+#define PSCI_MEM_CHK_RANGE_AARCH64	U(0xc4000014)
 
 /* Macro to help build the psci capabilities bitfield */
 #define define_psci_cap(x)		(U(1) << (x & U(0x1f)))
@@ -288,6 +291,9 @@
 				    unsigned int power_state,
 				    psci_power_state_t *output_state);
 	int (*get_node_hw_state)(u_register_t mpidr, unsigned int power_level);
+	int (*mem_protect_chk)(uintptr_t base, u_register_t length);
+	int (*read_mem_protect)(int *val);
+	int (*write_mem_protect)(int val);
 } plat_psci_ops_t;
 
 /*******************************************************************************
diff --git a/include/lib/utils.h b/include/lib/utils.h
index b75813f..cfc8302 100644
--- a/include/lib/utils.h
+++ b/include/lib/utils.h
@@ -19,6 +19,25 @@
 
 #include <types.h>
 
+typedef struct mem_region_t {
+	uintptr_t base;
+	size_t nbytes;
+} mem_region_t;
+
+/*
+ * zero_normalmem all the regions defined in tbl.
+ */
+void clear_mem_regions(mem_region_t *tbl, size_t nregions);
+
+
+/*
+ * checks that a region (addr + nbytes-1) of memory is totally covered by
+ * one of the regions defined in tbl. Caller must ensure that (addr+nbytes-1)
+ * doesn't overflow.
+ */
+int mem_region_in_array_chk(mem_region_t *tbl, size_t nregions,
+			    uintptr_t addr, size_t nbytes);
+
 /*
  * Fill a region of normal memory of size "length" in bytes with zero bytes.
  *
diff --git a/include/lib/utils_def.h b/include/lib/utils_def.h
index b397e30..185a1c1 100644
--- a/include/lib/utils_def.h
+++ b/include/lib/utils_def.h
@@ -18,6 +18,12 @@
 
 #define BIT(nr)				(1ULL << (nr))
 
+/*
+ * This variant of div_round_up can be used in macro definition but should not
+ * be used in C code as the `div` parameter is evaluated twice.
+ */
+#define DIV_ROUND_UP_2EVAL(n, d)	(((n) + (d) - 1) / (d))
+
 #define MIN(x, y) __extension__ ({	\
 	__typeof__(x) _x = (x);		\
 	__typeof__(y) _y = (y);		\
@@ -49,6 +55,11 @@
 #define round_down(value, boundary)		\
 	((value) & ~round_boundary(value, boundary))
 
+#define div_round_up(val, div) __extension__ ({	\
+	__typeof__(div) _div = (div);		\
+	round_up((val), _div)/_div;		\
+})
+
 /*
  * Evaluates to 1 if (ptr + inc) overflows, 0 otherwise.
  * Both arguments must be unsigned pointer values (i.e. uintptr_t).
diff --git a/include/plat/arm/board/common/board_arm_def.h b/include/plat/arm/board/common/board_arm_def.h
index 4d14500..49ab601 100644
--- a/include/plat/arm/board/common/board_arm_def.h
+++ b/include/plat/arm/board/common/board_arm_def.h
@@ -54,9 +54,9 @@
  */
 #if defined(IMAGE_BL31) || defined(IMAGE_BL32)
 # define PLAT_ARM_MMAP_ENTRIES		6
-# define MAX_XLAT_TABLES		4
+# define MAX_XLAT_TABLES		5
 #else
-# define PLAT_ARM_MMAP_ENTRIES		10
+# define PLAT_ARM_MMAP_ENTRIES		11
 # define MAX_XLAT_TABLES		5
 #endif
 
@@ -89,11 +89,26 @@
 
 #define PLAT_ARM_TRUSTED_SRAM_SIZE	0x00040000	/* 256 KB */
 
+/* Reserve the last block of flash for PSCI MEM PROTECT flag */
 #define PLAT_ARM_FIP_BASE		V2M_FLASH0_BASE
-#define PLAT_ARM_FIP_MAX_SIZE		V2M_FLASH0_SIZE
+#define PLAT_ARM_FIP_MAX_SIZE		(V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
 
 #define PLAT_ARM_NVM_BASE		V2M_FLASH0_BASE
-#define PLAT_ARM_NVM_SIZE		V2M_FLASH0_SIZE
+#define PLAT_ARM_NVM_SIZE		(V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+/* PSCI memory protect definitions:
+ * This variable is stored in a non-secure flash because some ARM reference
+ * platforms do not have secure NVRAM. Real systems that provided MEM_PROTECT
+ * support must use a secure NVRAM to store the PSCI MEM_PROTECT definitions.
+ */
+#define PLAT_ARM_MEM_PROT_ADDR		(V2M_FLASH0_BASE + \
+					 V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
 
+/*
+ * Map mem_protect flash region with read and write permissions
+ */
+#define ARM_V2M_MAP_MEM_PROTECT		MAP_REGION_FLAT(PLAT_ARM_MEM_PROT_ADDR,	\
+						V2M_FLASH_BLOCK_SIZE,		\
+						MT_DEVICE | MT_RW | MT_SECURE)
 
 #endif /* __BOARD_ARM_DEF_H__ */
diff --git a/include/plat/arm/board/common/v2m_def.h b/include/plat/arm/board/common/v2m_def.h
index 2ad513a..364b780 100644
--- a/include/plat/arm/board/common/v2m_def.h
+++ b/include/plat/arm/board/common/v2m_def.h
@@ -69,6 +69,7 @@
 /* NOR Flash */
 #define V2M_FLASH0_BASE			0x08000000
 #define V2M_FLASH0_SIZE			0x04000000
+#define V2M_FLASH_BLOCK_SIZE		0x00040000	/* 256 KB */
 
 #define V2M_IOFPGA_BASE			0x1c000000
 #define V2M_IOFPGA_SIZE			0x03000000
diff --git a/include/plat/arm/common/arm_def.h b/include/plat/arm/common/arm_def.h
index 787ccb0..dbf102b 100644
--- a/include/plat/arm/common/arm_def.h
+++ b/include/plat/arm/common/arm_def.h
@@ -177,7 +177,12 @@
 						ARM_NS_DRAM1_SIZE,	\
 						MT_MEMORY | MT_RW | MT_NS)
 
+#define ARM_MAP_DRAM2			MAP_REGION_FLAT(		\
+						ARM_DRAM2_BASE,		\
+						ARM_DRAM2_SIZE,		\
+						MT_MEMORY | MT_RW | MT_NS)
 #ifdef SPD_tspd
+
 #define ARM_MAP_TSP_SEC_MEM		MAP_REGION_FLAT(		\
 						TSP_SEC_MEM_BASE,	\
 						TSP_SEC_MEM_SIZE,	\
@@ -224,8 +229,18 @@
  * Required platform porting definitions common to all ARM standard platforms
  *****************************************************************************/
 
+/*
+ * We need to access DRAM2 from BL2 for PSCI_MEM_PROTECT for
+ * AArch64 builds
+ */
+#ifdef AARCH64
+#define PLAT_PHY_ADDR_SPACE_SIZE			(1ull << 36)
+#define PLAT_VIRT_ADDR_SPACE_SIZE			(1ull << 36)
+#else
 #define PLAT_PHY_ADDR_SPACE_SIZE			(1ull << 32)
 #define PLAT_VIRT_ADDR_SPACE_SIZE			(1ull << 32)
+#endif
+
 
 /*
  * This macro defines the deepest retention state possible. A higher state
diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h
index f0e9767..4e589c0 100644
--- a/include/plat/arm/common/plat_arm.h
+++ b/include/plat/arm/common/plat_arm.h
@@ -122,6 +122,10 @@
 int arm_validate_ns_entrypoint(uintptr_t entrypoint);
 void arm_system_pwr_domain_resume(void);
 void arm_program_trusted_mailbox(uintptr_t address);
+int arm_psci_read_mem_protect(int *val);
+int arm_nor_psci_write_mem_protect(int val);
+void arm_nor_psci_do_mem_protect(void);
+int arm_psci_mem_protect_chk(uintptr_t base, u_register_t length);
 
 /* Topology utility function */
 int arm_check_mpidr(u_register_t mpidr);
diff --git a/lib/psci/psci_lib.mk b/lib/psci/psci_lib.mk
index 29080db..1d4aac4 100644
--- a/lib/psci/psci_lib.mk
+++ b/lib/psci/psci_lib.mk
@@ -17,6 +17,7 @@
 				lib/psci/psci_main.c			\
 				lib/psci/psci_setup.c			\
 				lib/psci/psci_system_off.c		\
+				lib/psci/psci_mem_protect.c		\
 				lib/psci/${ARCH}/psci_helpers.S
 
 ifeq (${ARCH}, aarch64)
diff --git a/lib/psci/psci_main.c b/lib/psci/psci_main.c
index 257479a..a5d707e 100644
--- a/lib/psci/psci_main.c
+++ b/lib/psci/psci_main.c
@@ -408,6 +408,11 @@
 		case PSCI_STAT_COUNT_AARCH32:
 			return psci_stat_count(x1, x2);
 #endif
+		case PSCI_MEM_PROTECT:
+			return psci_mem_protect(x1);
+
+		case PSCI_MEM_CHK_RANGE_AARCH32:
+			return psci_mem_chk_range(x1, x2);
 
 		default:
 			break;
@@ -445,6 +450,10 @@
 			return psci_stat_count(x1, x2);
 #endif
 
+		case PSCI_MEM_CHK_RANGE_AARCH64:
+			return psci_mem_chk_range(x1, x2);
+
+
 		default:
 			break;
 		}
diff --git a/lib/psci/psci_mem_protect.c b/lib/psci/psci_mem_protect.c
new file mode 100644
index 0000000..fca84e9
--- /dev/null
+++ b/lib/psci/psci_mem_protect.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <limits.h>
+#include <utils.h>
+#include "psci_private.h"
+
+int psci_mem_protect(unsigned int enable)
+{
+	int val;
+
+	assert(psci_plat_pm_ops->read_mem_protect);
+	assert(psci_plat_pm_ops->write_mem_protect);
+
+	if (psci_plat_pm_ops->read_mem_protect(&val) < 0)
+		return PSCI_E_NOT_SUPPORTED;
+	if (psci_plat_pm_ops->write_mem_protect(enable) < 0)
+		return PSCI_E_NOT_SUPPORTED;
+
+	return val != 0;
+}
+
+int psci_mem_chk_range(uintptr_t base, u_register_t length)
+{
+	int ret;
+
+	assert(psci_plat_pm_ops->mem_protect_chk);
+
+	if (length == 0 || check_uptr_overflow(base, length-1))
+		return PSCI_E_DENIED;
+
+	ret = psci_plat_pm_ops->mem_protect_chk(base, length);
+	return (ret < 0) ? PSCI_E_DENIED : PSCI_E_SUCCESS;
+}
diff --git a/lib/psci/psci_private.h b/lib/psci/psci_private.h
index da6a20f..facfacb 100644
--- a/lib/psci/psci_private.h
+++ b/lib/psci/psci_private.h
@@ -269,4 +269,8 @@
 u_register_t psci_stat_count(u_register_t target_cpu,
 			unsigned int power_state);
 
+/* Private exported functions from psci_mem_protect.c */
+int psci_mem_protect(unsigned int enable);
+int psci_mem_chk_range(uintptr_t base, u_register_t length);
+
 #endif /* __PSCI_PRIVATE_H__ */
diff --git a/lib/psci/psci_setup.c b/lib/psci/psci_setup.c
index f70e34d..5ef49ac 100644
--- a/lib/psci/psci_setup.c
+++ b/lib/psci/psci_setup.c
@@ -243,6 +243,11 @@
 		psci_caps |=  define_psci_cap(PSCI_SYSTEM_RESET);
 	if (psci_plat_pm_ops->get_node_hw_state)
 		psci_caps |= define_psci_cap(PSCI_NODE_HW_STATE_AARCH64);
+	if (psci_plat_pm_ops->read_mem_protect &&
+			psci_plat_pm_ops->write_mem_protect)
+		psci_caps |= define_psci_cap(PSCI_MEM_PROTECT);
+	if (psci_plat_pm_ops->mem_protect_chk)
+		psci_caps |= define_psci_cap(PSCI_MEM_CHK_RANGE_AARCH64);
 
 #if ENABLE_PSCI_STAT
 	psci_caps |=  define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64);
diff --git a/lib/utils/mem_region.c b/lib/utils/mem_region.c
new file mode 100644
index 0000000..31c6231
--- /dev/null
+++ b/lib/utils/mem_region.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <utils.h>
+
+/*
+ * All the regions defined in mem_region_t must have the following properties
+ *
+ * - Any contiguous regions must be merged into a single entry.
+ * - The number of bytes of each region must be greater than zero.
+ * - The calculation of the highest address within the region (base + nbytes-1)
+ *   doesn't produce an overflow.
+ *
+ * These conditions must be fulfilled by the caller and they aren't checked
+ * at runtime.
+ */
+
+/*
+ * zero_normalmem all the regions defined in tbl.
+ * It assumes that MMU is enabled and the memory is Normal memory.
+ * tbl must be a valid pointer to a memory mem_region_t array,
+ * nregions is the size of the array.
+ */
+void clear_mem_regions(mem_region_t *tbl, size_t nregions)
+{
+	size_t i;
+
+	assert(tbl);
+	assert(nregions > 0);
+
+	for (i = 0; i < nregions; i++) {
+		assert(tbl->nbytes > 0);
+		assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1));
+		zero_normalmem((void *) (tbl->base), tbl->nbytes);
+		tbl++;
+	}
+}
+
+/*
+ * This function checks that a region (addr + nbytes-1) of memory is totally
+ * covered by one of the regions defined in tbl.
+ * tbl must be a valid pointer to a memory mem_region_t array, nregions
+ * is the size of the array and the region described by addr and nbytes must
+ * not generate an overflow.
+ * Returns:
+ *  -1 means that the region is not covered by any of the regions
+ *     described in tbl.
+ *   0 the region (addr + nbytes-1) is covered by one of the regions described
+ *     in tbl
+ */
+int mem_region_in_array_chk(mem_region_t *tbl, size_t nregions,
+			    uintptr_t addr, size_t nbytes)
+{
+	uintptr_t region_start, region_end, start, end;
+	size_t i;
+
+	assert(tbl);
+	assert(nbytes > 0);
+	assert(!check_uptr_overflow(addr, nbytes-1));
+
+	region_start = addr;
+	region_end = addr + (nbytes - 1);
+	for (i = 0; i < nregions; i++) {
+		assert(tbl->nbytes > 0);
+		assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1));
+		start = tbl->base;
+		end = start + (tbl->nbytes - 1);
+		if (region_start >= start && region_end <= end)
+			return 0;
+		tbl++;
+	}
+
+	return -1;
+}
diff --git a/plat/arm/board/common/board_common.mk b/plat/arm/board/common/board_common.mk
index 643047c..d63ae9a 100644
--- a/plat/arm/board/common/board_common.mk
+++ b/plat/arm/board/common/board_common.mk
@@ -12,9 +12,13 @@
 
 BL1_SOURCES		+=	plat/arm/board/common/drivers/norflash/norflash.c
 
-BL2_SOURCES		+=	plat/arm/board/common/drivers/norflash/norflash.c
+BL2_SOURCES		+=	lib/utils/mem_region.c					\
+				plat/arm/common/arm_nor_psci_mem_protect.c		\
+				plat/arm/board/common/drivers/norflash/norflash.c
 
-#BL31_SOURCES		+=
+BL31_SOURCES		+=	lib/utils/mem_region.c					\
+				plat/arm/board/common/drivers/norflash/norflash.c	\
+				plat/arm/common/arm_nor_psci_mem_protect.c
 
 ifneq (${TRUSTED_BOARD_BOOT},0)
   ifneq (${ARM_CRYPTOCELL_INTEG}, 1)
diff --git a/plat/arm/board/common/board_css_common.c b/plat/arm/board/common/board_css_common.c
index 159bf86..032ebdf 100644
--- a/plat/arm/board/common/board_css_common.c
+++ b/plat/arm/board/common/board_css_common.c
@@ -29,10 +29,16 @@
 const mmap_region_t plat_arm_mmap[] = {
 	ARM_MAP_SHARED_RAM,
 	V2M_MAP_FLASH0_RO,
+#ifdef PLAT_ARM_MEM_PROT_ADDR
+	ARM_V2M_MAP_MEM_PROTECT,
+#endif
 	V2M_MAP_IOFPGA,
 	CSS_MAP_DEVICE,
 	SOC_CSS_MAP_DEVICE,
 	ARM_MAP_NS_DRAM1,
+#ifdef AARCH64
+	ARM_MAP_DRAM2,
+#endif
 #ifdef SPD_tspd
 	ARM_MAP_TSP_SEC_MEM,
 #endif
@@ -56,6 +62,9 @@
 	ARM_MAP_SHARED_RAM,
 	V2M_MAP_IOFPGA,
 	CSS_MAP_DEVICE,
+#ifdef PLAT_ARM_MEM_PROT_ADDR
+	ARM_V2M_MAP_MEM_PROTECT,
+#endif
 	SOC_CSS_MAP_DEVICE,
 	{0}
 };
diff --git a/plat/arm/board/fvp/fvp_common.c b/plat/arm/board/fvp/fvp_common.c
index e869f5b..7015ac0 100644
--- a/plat/arm/board/fvp/fvp_common.c
+++ b/plat/arm/board/fvp/fvp_common.c
@@ -79,6 +79,9 @@
 	MAP_DEVICE0,
 	MAP_DEVICE1,
 	ARM_MAP_NS_DRAM1,
+#ifdef AARCH64
+	ARM_MAP_DRAM2,
+#endif
 #ifdef SPD_tspd
 	ARM_MAP_TSP_SEC_MEM,
 #endif
@@ -109,6 +112,7 @@
 	V2M_MAP_IOFPGA,
 	MAP_DEVICE0,
 	MAP_DEVICE1,
+	ARM_V2M_MAP_MEM_PROTECT,
 	{0}
 };
 #endif
diff --git a/plat/arm/board/fvp/fvp_pm.c b/plat/arm/board/fvp/fvp_pm.c
index 9a02089..dad3a79 100644
--- a/plat/arm/board/fvp/fvp_pm.c
+++ b/plat/arm/board/fvp/fvp_pm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -324,5 +324,14 @@
 	.system_reset = fvp_system_reset,
 	.validate_power_state = arm_validate_power_state,
 	.validate_ns_entrypoint = arm_validate_ns_entrypoint,
-	.get_node_hw_state = fvp_node_hw_state
+	.get_node_hw_state = fvp_node_hw_state,
+/*
+ * mem_protect is not supported in RESET_TO_BL31 and RESET_TO_SP_MIN,
+ * as that would require mapping in all of NS DRAM into BL31 or BL32.
+ */
+#if !RESET_TO_BL31 && !RESET_TO_SP_MIN
+	.mem_protect_chk	= arm_psci_mem_protect_chk,
+	.read_mem_protect	= arm_psci_read_mem_protect,
+	.write_mem_protect	= arm_nor_psci_write_mem_protect,
+#endif
 };
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index 6d8aa5f..29da12e 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -48,7 +48,8 @@
 
 # Choose the GIC sources depending upon the how the FVP will be invoked
 ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV3)
-FVP_GIC_SOURCES		:=	${FVP_GICV3_SOURCES}
+FVP_GIC_SOURCES		:=	${FVP_GICV3_SOURCES}			\
+				drivers/arm/gic/v3/gic500.c
 else ifeq (${FVP_USE_GIC_DRIVER},FVP_GIC600)
 FVP_GIC_SOURCES		:=	${FVP_GICV3_SOURCES}			\
 				drivers/arm/gic/v3/gic600.c
diff --git a/plat/arm/board/fvp/sp_min/sp_min-fvp.mk b/plat/arm/board/fvp/sp_min/sp_min-fvp.mk
index 864df1b..b370fd5 100644
--- a/plat/arm/board/fvp/sp_min/sp_min-fvp.mk
+++ b/plat/arm/board/fvp/sp_min/sp_min-fvp.mk
@@ -5,11 +5,14 @@
 #
 
 # SP_MIN source files specific to FVP platform
-BL32_SOURCES		+=	plat/arm/board/fvp/aarch32/fvp_helpers.S	\
+BL32_SOURCES		+=	lib/utils/mem_region.c				\
+				plat/arm/board/fvp/aarch32/fvp_helpers.S	\
 				plat/arm/board/fvp/drivers/pwrc/fvp_pwrc.c	\
 				plat/arm/board/fvp/fvp_pm.c			\
 				plat/arm/board/fvp/fvp_topology.c		\
 				plat/arm/board/fvp/sp_min/fvp_sp_min_setup.c	\
+				plat/arm/board/common/drivers/norflash/norflash.c	\
+				plat/arm/common/arm_nor_psci_mem_protect.c	\
 				${FVP_CPU_LIBS}					\
 				${FVP_GIC_SOURCES}				\
 				${FVP_INTERCONNECT_SOURCES}			\
diff --git a/plat/arm/board/juno/include/platform_def.h b/plat/arm/board/juno/include/platform_def.h
index 7794af5..3c44a1e 100644
--- a/plat/arm/board/juno/include/platform_def.h
+++ b/plat/arm/board/juno/include/platform_def.h
@@ -68,11 +68,11 @@
 
 #ifdef IMAGE_BL2
 #ifdef SPD_opteed
-# define PLAT_ARM_MMAP_ENTRIES		9
-# define MAX_XLAT_TABLES		4
+# define PLAT_ARM_MMAP_ENTRIES		11
+# define MAX_XLAT_TABLES		5
 #else
-# define PLAT_ARM_MMAP_ENTRIES		8
-# define MAX_XLAT_TABLES		3
+# define PLAT_ARM_MMAP_ENTRIES		10
+# define MAX_XLAT_TABLES		4
 #endif
 #endif
 
@@ -82,8 +82,8 @@
 #endif
 
 #ifdef IMAGE_BL31
-#  define PLAT_ARM_MMAP_ENTRIES		5
-#  define MAX_XLAT_TABLES		2
+#  define PLAT_ARM_MMAP_ENTRIES		7
+#  define MAX_XLAT_TABLES		3
 #endif
 
 #ifdef IMAGE_BL32
diff --git a/plat/arm/board/juno/sp_min/sp_min-juno.mk b/plat/arm/board/juno/sp_min/sp_min-juno.mk
index 336c4e7..cd1f497 100644
--- a/plat/arm/board/juno/sp_min/sp_min-juno.mk
+++ b/plat/arm/board/juno/sp_min/sp_min-juno.mk
@@ -8,7 +8,10 @@
 BL32_SOURCES	+=	lib/cpus/aarch32/cortex_a53.S		\
 			lib/cpus/aarch32/cortex_a57.S		\
 			lib/cpus/aarch32/cortex_a72.S		\
+			lib/utils/mem_region.c			\
+			plat/arm/board/common/drivers/norflash/norflash.c	\
 			plat/arm/board/juno/juno_topology.c	\
+			plat/arm/common/arm_nor_psci_mem_protect.c	\
 			plat/arm/soc/common/soc_css_security.c	\
 			${JUNO_GIC_SOURCES}			\
 			${JUNO_INTERCONNECT_SOURCES}		\
diff --git a/plat/arm/common/arm_bl2_setup.c b/plat/arm/common/arm_bl2_setup.c
index cab6113..5d83118 100644
--- a/plat/arm/common/arm_bl2_setup.c
+++ b/plat/arm/common/arm_bl2_setup.c
@@ -193,6 +193,10 @@
 {
 	/* Initialize the secure environment */
 	plat_arm_security_setup();
+
+#if defined(PLAT_ARM_MEM_PROT_ADDR)
+	arm_nor_psci_do_mem_protect();
+#endif
 }
 
 void bl2_platform_setup(void)
diff --git a/plat/arm/common/arm_nor_psci_mem_protect.c b/plat/arm/common/arm_nor_psci_mem_protect.c
new file mode 100644
index 0000000..c5263fd
--- /dev/null
+++ b/plat/arm/common/arm_nor_psci_mem_protect.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <debug.h>
+#include <mmio.h>
+#include <norflash.h>
+#include <plat_arm.h>
+#include <platform_def.h>
+#include <psci.h>
+#include <utils.h>
+
+mem_region_t arm_ram_ranges[] = {
+	{ARM_NS_DRAM1_BASE, ARM_NS_DRAM1_SIZE},
+#ifdef AARCH64
+	{ARM_DRAM2_BASE, ARM_DRAM2_SIZE},
+#endif
+};
+
+/*******************************************************************************
+ * Function that reads the content of the memory protect variable that
+ * enables clearing of non secure memory when system boots. This variable
+ * should be stored in a secure NVRAM.
+ ******************************************************************************/
+int arm_psci_read_mem_protect(int *enabled)
+{
+	int tmp;
+
+	tmp = *(int *) PLAT_ARM_MEM_PROT_ADDR;
+	*enabled = (tmp == 1);
+	return 0;
+}
+
+/*******************************************************************************
+ * Function that writes the content of the memory protect variable that
+ * enables overwritten of non secure memory when system boots.
+ ******************************************************************************/
+int arm_nor_psci_write_mem_protect(int val)
+{
+	int enable = (val != 0);
+
+	if (nor_unlock(PLAT_ARM_MEM_PROT_ADDR) != 0) {
+		ERROR("unlocking memory protect variable\n");
+		return -1;
+	}
+
+	if (enable) {
+		/*
+		 * If we want to write a value different than 0
+		 * then we have to erase the full block because
+		 * otherwise we cannot ensure that the value programmed
+		 * into the flash is going to be the same than the value
+		 * requested by the caller
+		 */
+		if (nor_erase(PLAT_ARM_MEM_PROT_ADDR) != 0) {
+			ERROR("erasing block containing memory protect variable\n");
+			return -1;
+		}
+	}
+
+	if (nor_word_program(PLAT_ARM_MEM_PROT_ADDR, enable) != 0) {
+		ERROR("programming memory protection variable\n");
+		return -1;
+	}
+	return 0;
+}
+
+/*******************************************************************************
+ * Function used for required psci operations performed when
+ * system boots
+ ******************************************************************************/
+void arm_nor_psci_do_mem_protect(void)
+{
+	int enable;
+
+	arm_psci_read_mem_protect(&enable);
+	if (!enable)
+		return;
+	INFO("PSCI: Overwritting non secure memory\n");
+	clear_mem_regions(arm_ram_ranges, ARRAY_SIZE(arm_ram_ranges));
+	arm_nor_psci_write_mem_protect(0);
+}
+
+/*******************************************************************************
+ * Function that checks if a region is protected by the memory protect
+ * mechanism
+ ******************************************************************************/
+int arm_psci_mem_protect_chk(uintptr_t base, u_register_t length)
+{
+	return mem_region_in_array_chk(arm_ram_ranges,
+				       ARRAY_SIZE(arm_ram_ranges),
+				       base, length);
+}
diff --git a/plat/arm/css/common/css_pm.c b/plat/arm/css/common/css_pm.c
index e0e5200..93d51fe 100644
--- a/plat/arm/css/common/css_pm.c
+++ b/plat/arm/css/common/css_pm.c
@@ -290,5 +290,14 @@
 	.validate_ns_entrypoint = arm_validate_ns_entrypoint,
 	.translate_power_state_by_mpidr = css_translate_power_state_by_mpidr,
 	.get_node_hw_state	= css_node_hw_state,
-	.get_sys_suspend_power_state = css_get_sys_suspend_power_state
+	.get_sys_suspend_power_state = css_get_sys_suspend_power_state,
+/*
+ * mem_protect is not supported in RESET_TO_BL31 and RESET_TO_SP_MIN,
+ * as that would require mapping in all of NS DRAM into BL31 or BL32.
+ */
+#if defined(PLAT_ARM_MEM_PROT_ADDR) && !RESET_TO_BL31 && !RESET_TO_SP_MIN
+	.mem_protect_chk	= arm_psci_mem_protect_chk,
+	.read_mem_protect	= arm_psci_read_mem_protect,
+	.write_mem_protect	= arm_nor_psci_write_mem_protect,
+#endif
 };
diff --git a/tools/cert_create/src/key.c b/tools/cert_create/src/key.c
index c1bde5d..e8257e9 100644
--- a/tools/cert_create/src/key.c
+++ b/tools/cert_create/src/key.c
@@ -91,9 +91,10 @@
 
 typedef int (*key_create_fn_t)(key_t *key);
 static const key_create_fn_t key_create_fn[KEY_ALG_MAX_NUM] = {
-	key_create_rsa,
+	key_create_rsa, 	/* KEY_ALG_RSA */
+	key_create_rsa, 	/* KEY_ALG_RSA_1_5 */
 #ifndef OPENSSL_NO_EC
-	key_create_ecdsa,
+	key_create_ecdsa, 	/* KEY_ALG_ECDSA */
 #endif /* OPENSSL_NO_EC */
 };