Merge pull request #1154 from soby-mathew/sm/fix_psci_stat

Fix PSCI STAT time stamp collection
diff --git a/Makefile b/Makefile
index b32b417..a648d8c 100644
--- a/Makefile
+++ b/Makefile
@@ -260,6 +260,8 @@
 
 include ${PLAT_MAKEFILE_FULL}
 
+$(eval $(call MAKE_PREREQ_DIR,${BUILD_PLAT}))
+
 # Platform compatibility is not supported in AArch32
 ifneq (${ARCH},aarch32)
 # If the platform has not defined ENABLE_PLAT_COMPAT, then enable it by default
diff --git a/common/aarch64/debug.S b/common/aarch64/debug.S
index d794d12..4478d0d 100644
--- a/common/aarch64/debug.S
+++ b/common/aarch64/debug.S
@@ -6,6 +6,7 @@
 
 #include <arch.h>
 #include <asm_macros.S>
+#include <debug.h>
 
 	.globl	asm_print_str
 	.globl	asm_print_hex
diff --git a/include/lib/el3_runtime/cpu_data.h b/include/lib/el3_runtime/cpu_data.h
index c0c3a19..bd787ce 100644
--- a/include/lib/el3_runtime/cpu_data.h
+++ b/include/lib/el3_runtime/cpu_data.h
@@ -141,17 +141,17 @@
 #define set_cpu_data(_m, _v)		   _cpu_data()->_m = _v
 #define get_cpu_data_by_index(_ix, _m)	   _cpu_data_by_index(_ix)->_m
 #define set_cpu_data_by_index(_ix, _m, _v) _cpu_data_by_index(_ix)->_m = _v
-
+/* ((cpu_data_t *)0)->_m is a dummy to get the sizeof the struct member _m */
 #define flush_cpu_data(_m)	   flush_dcache_range((uintptr_t)	  \
-						      &(_cpu_data()->_m), \
-						      sizeof(_cpu_data()->_m))
+						&(_cpu_data()->_m), \
+						sizeof(((cpu_data_t *)0)->_m))
 #define inv_cpu_data(_m)	   inv_dcache_range((uintptr_t)	  	  \
-						      &(_cpu_data()->_m), \
-						      sizeof(_cpu_data()->_m))
+						&(_cpu_data()->_m), \
+						sizeof(((cpu_data_t *)0)->_m))
 #define flush_cpu_data_by_index(_ix, _m)	\
 				   flush_dcache_range((uintptr_t)	  \
 					 &(_cpu_data_by_index(_ix)->_m),  \
-					 sizeof(_cpu_data_by_index(_ix)->_m))
+						sizeof(((cpu_data_t *)0)->_m))
 
 
 #endif /* __ASSEMBLY__ */
diff --git a/include/lib/xlat_tables/xlat_tables_v2_helpers.h b/include/lib/xlat_tables/xlat_tables_v2_helpers.h
index 28228c4..96dee1a 100644
--- a/include/lib/xlat_tables/xlat_tables_v2_helpers.h
+++ b/include/lib/xlat_tables/xlat_tables_v2_helpers.h
@@ -168,7 +168,7 @@
  * This IMAGE_EL macro must not to be used outside the library, and it is only
  * used in AArch64.
  */
-#if IMAGE_BL1 || IMAGE_BL31
+#if defined(IMAGE_BL1) || defined(IMAGE_BL31)
 # define IMAGE_EL	3
 # define IMAGE_XLAT_DEFAULT_REGIME EL3_REGIME
 #else
diff --git a/include/plat/arm/board/common/board_arm_def.h b/include/plat/arm/board/common/board_arm_def.h
index 93828c9..7a4594c 100644
--- a/include/plat/arm/board/common/board_arm_def.h
+++ b/include/plat/arm/board/common/board_arm_def.h
@@ -53,7 +53,7 @@
  * enable dynamic memory mapping.
  */
 #if defined(IMAGE_BL31) || defined(IMAGE_BL32)
-# define PLAT_ARM_MMAP_ENTRIES		6
+# define PLAT_ARM_MMAP_ENTRIES		7
 # define MAX_XLAT_TABLES		5
 #else
 # define PLAT_ARM_MMAP_ENTRIES		11
diff --git a/include/plat/arm/common/arm_common.ld.S b/include/plat/arm/common/arm_common.ld.S
new file mode 100644
index 0000000..478b08c
--- /dev/null
+++ b/include/plat/arm/common/arm_common.ld.S
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __ARM_COMMON_LD_S__
+#define __ARM_COMMON_LD_S__
+
+MEMORY {
+    EL3_SEC_DRAM (rw): ORIGIN = ARM_EL3_TZC_DRAM1_BASE, LENGTH = ARM_EL3_TZC_DRAM1_SIZE
+}
+
+SECTIONS
+{
+	. = ARM_EL3_TZC_DRAM1_BASE;
+	ASSERT(. == ALIGN(4096),
+	"ARM_EL3_TZC_DRAM_BASE address is not aligned on a page boundary.")
+	el3_tzc_dram (NOLOAD) : ALIGN(4096) {
+	__EL3_SEC_DRAM_START__ = .;
+	*(arm_el3_tzc_dram)
+	__EL3_SEC_DRAM_UNALIGNED_END__ = .;
+
+	. = NEXT(4096);
+	__EL3_SEC_DRAM_END__ = .;
+	} >EL3_SEC_DRAM
+}
+
+#endif /* __ARM_COMMON_LD_S__ */
diff --git a/include/plat/arm/common/arm_def.h b/include/plat/arm/common/arm_def.h
index c84fabd..6cab91f 100644
--- a/include/plat/arm/common/arm_def.h
+++ b/include/plat/arm/common/arm_def.h
@@ -77,11 +77,23 @@
 #define ARM_SCP_TZC_DRAM1_END		(ARM_SCP_TZC_DRAM1_BASE +	\
 					 ARM_SCP_TZC_DRAM1_SIZE - 1)
 
+/*
+ * Define a 2MB region within the TZC secured DRAM for use by EL3 runtime
+ * firmware. This region is meant to be NOLOAD and will not be zero
+ * initialized. Data sections with the attribute `arm_el3_tzc_dram` will be
+ * placed here.
+ */
+#define ARM_EL3_TZC_DRAM1_BASE		(ARM_SCP_TZC_DRAM1_BASE - ARM_EL3_TZC_DRAM1_SIZE)
+#define ARM_EL3_TZC_DRAM1_SIZE		ULL(0x00200000) /* 2 MB */
+#define ARM_EL3_TZC_DRAM1_END		(ARM_EL3_TZC_DRAM1_BASE +	\
+					ARM_EL3_TZC_DRAM1_SIZE - 1)
+
 #define ARM_AP_TZC_DRAM1_BASE		(ARM_DRAM1_BASE +		\
 					 ARM_DRAM1_SIZE -		\
 					 ARM_TZC_DRAM1_SIZE)
 #define ARM_AP_TZC_DRAM1_SIZE		(ARM_TZC_DRAM1_SIZE -		\
-					 ARM_SCP_TZC_DRAM1_SIZE)
+					 (ARM_SCP_TZC_DRAM1_SIZE +	\
+					 ARM_EL3_TZC_DRAM1_SIZE))
 #define ARM_AP_TZC_DRAM1_END		(ARM_AP_TZC_DRAM1_BASE +	\
 					 ARM_AP_TZC_DRAM1_SIZE - 1)
 
@@ -224,6 +236,11 @@
 						MT_MEMORY | MT_RW | MT_SECURE)
 #endif
 
+#define ARM_MAP_EL3_TZC_DRAM		MAP_REGION_FLAT(			\
+						ARM_EL3_TZC_DRAM1_BASE,	\
+						ARM_EL3_TZC_DRAM1_SIZE,	\
+						MT_MEMORY | MT_RW | MT_SECURE)
+
 /*
  * The number of regions like RO(code), coherent and data required by
  * different BL stages which need to be mapped in the MMU.
diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h
index 4e589c0..33d951c 100644
--- a/include/plat/arm/common/plat_arm.h
+++ b/include/plat/arm/common/plat_arm.h
@@ -120,6 +120,7 @@
 int arm_validate_power_state(unsigned int power_state,
 			    psci_power_state_t *req_state);
 int arm_validate_ns_entrypoint(uintptr_t entrypoint);
+void arm_system_pwr_domain_save(void);
 void arm_system_pwr_domain_resume(void);
 void arm_program_trusted_mailbox(uintptr_t address);
 int arm_psci_read_mem_protect(int *val);
@@ -183,6 +184,8 @@
 void plat_arm_gic_redistif_on(void);
 void plat_arm_gic_redistif_off(void);
 void plat_arm_gic_pcpu_init(void);
+void plat_arm_gic_save(void);
+void plat_arm_gic_resume(void);
 void plat_arm_security_setup(void);
 void plat_arm_pwrc_setup(void);
 void plat_arm_interconnect_init(void);
diff --git a/make_helpers/build_macros.mk b/make_helpers/build_macros.mk
index e59a64b..7531f6d 100644
--- a/make_helpers/build_macros.mk
+++ b/make_helpers/build_macros.mk
@@ -291,7 +291,7 @@
 
 # Create generators for object directory structure
 
-$(eval $(call MAKE_PREREQ_DIR,${BUILD_DIR},))
+$(eval $(call MAKE_PREREQ_DIR,${BUILD_DIR},${BUILD_PLAT}))
 
 $(eval $(foreach objd,${OBJ_DIRS},$(call MAKE_PREREQ_DIR,${objd},${BUILD_DIR})))
 
diff --git a/plat/arm/board/fvp/fvp_common.c b/plat/arm/board/fvp/fvp_common.c
index 7015ac0..57cc3d5 100644
--- a/plat/arm/board/fvp/fvp_common.c
+++ b/plat/arm/board/fvp/fvp_common.c
@@ -109,6 +109,7 @@
 #ifdef IMAGE_BL31
 const mmap_region_t plat_arm_mmap[] = {
 	ARM_MAP_SHARED_RAM,
+	ARM_MAP_EL3_TZC_DRAM,
 	V2M_MAP_IOFPGA,
 	MAP_DEVICE0,
 	MAP_DEVICE1,
diff --git a/plat/arm/board/fvp/fvp_pm.c b/plat/arm/board/fvp/fvp_pm.c
index dad3a79..faeb1b7 100644
--- a/plat/arm/board/fvp/fvp_pm.c
+++ b/plat/arm/board/fvp/fvp_pm.c
@@ -9,6 +9,7 @@
 #include <assert.h>
 #include <debug.h>
 #include <errno.h>
+#include <gicv3.h>
 #include <mmio.h>
 #include <plat_arm.h>
 #include <platform.h>
@@ -36,6 +37,9 @@
 	/* State-id - 0x22 */
 	arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF,
 			ARM_PWR_LVL1, PSTATE_TYPE_POWERDOWN),
+	/* State-id - 0x222 */
+	arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF,
+		ARM_LOCAL_STATE_OFF, ARM_PWR_LVL2, PSTATE_TYPE_POWERDOWN),
 	0,
 };
 #endif
@@ -63,6 +67,18 @@
 	fvp_pwrc_write_pcoffr(mpidr);
 }
 
+/*
+ * Empty implementation of these hooks avoid setting the GICR_WAKER.Sleep bit
+ * on ARM GICv3 implementations on FVP. This is required, because FVP does not
+ * support SYSTEM_SUSPEND and it is `faked` in firmware. Hence, for wake up
+ * from `fake` system suspend the GIC must not be powered off.
+ */
+void arm_gicv3_distif_pre_save(unsigned int proc_num)
+{}
+
+void arm_gicv3_distif_post_restore(unsigned int proc_num)
+{}
+
 static void fvp_power_domain_on_finish_common(const psci_power_state_t *target_state)
 {
 	unsigned long mpidr;
@@ -90,6 +106,10 @@
 		/* Enable coherency if this cluster was off */
 		fvp_interconnect_enable();
 	}
+	/* Perform the common system specific operations */
+	if (target_state->pwr_domain_state[ARM_PWR_LVL2] ==
+						ARM_LOCAL_STATE_OFF)
+		arm_system_pwr_domain_resume();
 
 	/*
 	 * Clear PWKUPR.WEN bit to ensure interrupts do not interfere
@@ -201,13 +221,18 @@
 	 * register context.
 	 */
 
-	/* Program the power controller to power off this cpu. */
-	fvp_pwrc_write_ppoffr(read_mpidr_el1());
-
 	/* Perform the common cluster specific operations */
 	if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
 					ARM_LOCAL_STATE_OFF)
 		fvp_cluster_pwrdwn_common();
+
+	/* Perform the common system specific operations */
+	if (target_state->pwr_domain_state[ARM_PWR_LVL2] ==
+						ARM_LOCAL_STATE_OFF)
+		arm_system_pwr_domain_save();
+
+	/* Program the power controller to power off this cpu. */
+	fvp_pwrc_write_ppoffr(read_mpidr_el1());
 }
 
 /*******************************************************************************
@@ -309,7 +334,57 @@
 	return ret;
 }
 
+/*
+ * The FVP doesn't truly support power management at SYSTEM power domain. The
+ * SYSTEM_SUSPEND will be down-graded to the cluster level within the platform
+ * layer. The `fake` SYSTEM_SUSPEND allows us to validate some of the driver
+ * save and restore sequences on FVP.
+ */
+void fvp_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	unsigned int i;
+
+	for (i = ARM_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++)
+		req_state->pwr_domain_state[i] = ARM_LOCAL_STATE_OFF;
+}
+
 /*******************************************************************************
+ * Handler to filter PSCI requests.
+ ******************************************************************************/
+/*
+ * The system power domain suspend is only supported only via
+ * PSCI SYSTEM_SUSPEND API. PSCI CPU_SUSPEND request to system power domain
+ * will be downgraded to the lower level.
+ */
+static int fvp_validate_power_state(unsigned int power_state,
+			    psci_power_state_t *req_state)
+{
+	int rc;
+	rc = arm_validate_power_state(power_state, req_state);
+
+	/*
+	 * Ensure that the system power domain level is never suspended
+	 * via PSCI CPU SUSPEND API. Currently system suspend is only
+	 * supported via PSCI SYSTEM SUSPEND API.
+	 */
+	req_state->pwr_domain_state[ARM_PWR_LVL2] = ARM_LOCAL_STATE_RUN;
+	return rc;
+}
+
+/*
+ * Custom `translate_power_state_by_mpidr` handler for FVP. Unlike in the
+ * `fvp_validate_power_state`, we do not downgrade the system power
+ * domain level request in `power_state` as it will be used to query the
+ * PSCI_STAT_COUNT/RESIDENCY at the system power domain level.
+ */
+static int fvp_translate_power_state_by_mpidr(u_register_t mpidr,
+		unsigned int power_state,
+		psci_power_state_t *output_state)
+{
+	return arm_validate_power_state(power_state, output_state);
+}
+
+/*******************************************************************************
  * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
  * platform layer will take care of registering the handlers with PSCI.
  ******************************************************************************/
@@ -322,9 +397,11 @@
 	.pwr_domain_suspend_finish = fvp_pwr_domain_suspend_finish,
 	.system_off = fvp_system_off,
 	.system_reset = fvp_system_reset,
-	.validate_power_state = arm_validate_power_state,
+	.validate_power_state = fvp_validate_power_state,
 	.validate_ns_entrypoint = arm_validate_ns_entrypoint,
+	.translate_power_state_by_mpidr = fvp_translate_power_state_by_mpidr,
 	.get_node_hw_state = fvp_node_hw_state,
+	.get_sys_suspend_power_state = fvp_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.
diff --git a/plat/arm/board/fvp/fvp_topology.c b/plat/arm/board/fvp/fvp_topology.c
index cf1492b..4a007f4 100644
--- a/plat/arm/board/fvp/fvp_topology.c
+++ b/plat/arm/board/fvp/fvp_topology.c
@@ -12,7 +12,7 @@
 #include "drivers/pwrc/fvp_pwrc.h"
 
 /* The FVP power domain tree descriptor */
-unsigned char fvp_power_domain_tree_desc[FVP_CLUSTER_COUNT + 1];
+unsigned char fvp_power_domain_tree_desc[FVP_CLUSTER_COUNT + 2];
 
 
 CASSERT(FVP_CLUSTER_COUNT && FVP_CLUSTER_COUNT <= 256, assert_invalid_fvp_cluster_count);
@@ -23,18 +23,18 @@
  ******************************************************************************/
 const unsigned char *plat_get_power_domain_tree_desc(void)
 {
-	int i;
+	unsigned int i;
 
 	/*
-	 * The FVP power domain tree does not have a single system level power domain
-	 * i.e. a single root node. The first entry in the power domain descriptor
-	 * specifies the number of power domains at the highest power level. For the FVP
-	 * this is the number of cluster power domains.
+	 * The highest level is the system level. The next level is constituted
+	 * by clusters and then cores in clusters.
 	 */
-	fvp_power_domain_tree_desc[0] = FVP_CLUSTER_COUNT;
+	fvp_power_domain_tree_desc[0] = 1;
+	fvp_power_domain_tree_desc[1] = FVP_CLUSTER_COUNT;
 
 	for (i = 0; i < FVP_CLUSTER_COUNT; i++)
-		fvp_power_domain_tree_desc[i + 1] = FVP_MAX_CPUS_PER_CLUSTER;
+		fvp_power_domain_tree_desc[i + 2] = FVP_MAX_CPUS_PER_CLUSTER;
+
 
 	return fvp_power_domain_tree_desc;
 }
diff --git a/plat/arm/board/fvp/include/plat.ld.S b/plat/arm/board/fvp/include/plat.ld.S
new file mode 100644
index 0000000..24c3deb
--- /dev/null
+++ b/plat/arm/board/fvp/include/plat.ld.S
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __PLAT_LD_S__
+#define __PLAT_LD_S__
+
+#include <arm_common.ld.S>
+
+#endif /* __PLAT_LD_S__ */
diff --git a/plat/arm/board/fvp/include/platform_def.h b/plat/arm/board/fvp/include/platform_def.h
index e953580..310db7b 100644
--- a/plat/arm/board/fvp/include/platform_def.h
+++ b/plat/arm/board/fvp/include/platform_def.h
@@ -20,9 +20,9 @@
 	(FVP_CLUSTER_COUNT * FVP_MAX_CPUS_PER_CLUSTER * FVP_MAX_PE_PER_CPU)
 
 #define PLAT_NUM_PWR_DOMAINS		(FVP_CLUSTER_COUNT + \
-					PLATFORM_CORE_COUNT)
+					PLATFORM_CORE_COUNT) + 1
 
-#define PLAT_MAX_PWR_LVL		ARM_PWR_LVL1
+#define PLAT_MAX_PWR_LVL		ARM_PWR_LVL2
 
 /*
  * Other platform porting definitions are provided by included headers
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index 29da12e..1b50296 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -155,5 +155,8 @@
     NEED_BL32 := yes
 endif
 
+# Add support for platform supplied linker script for BL31 build
+$(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
+
 include plat/arm/board/common/board_common.mk
 include plat/arm/common/arm_common.mk
diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk
index e1484d7..44eb43f 100644
--- a/plat/arm/common/arm_common.mk
+++ b/plat/arm/common/arm_common.mk
@@ -26,14 +26,17 @@
   endif
 
   # Process flags
-  $(eval $(call add_define,ARM_TSP_RAM_LOCATION_ID))
-
   # Process ARM_BL31_IN_DRAM flag
   ARM_BL31_IN_DRAM		:=	0
   $(eval $(call assert_boolean,ARM_BL31_IN_DRAM))
   $(eval $(call add_define,ARM_BL31_IN_DRAM))
+else
+  ARM_TSP_RAM_LOCATION_ID = ARM_TRUSTED_SRAM_ID
 endif
 
+$(eval $(call add_define,ARM_TSP_RAM_LOCATION_ID))
+
+
 # For the original power-state parameter format, the State-ID can be encoded
 # according to the recommended encoding or zero. This flag determines which
 # State-ID encoding to be parsed.
diff --git a/plat/arm/common/arm_gicv2.c b/plat/arm/common/arm_gicv2.c
index aac0248..b081fa8 100644
--- a/plat/arm/common/arm_gicv2.c
+++ b/plat/arm/common/arm_gicv2.c
@@ -92,3 +92,21 @@
 {
 	return;
 }
+
+
+/******************************************************************************
+ * ARM common helper to save & restore the GICv3 on resume from system suspend.
+ * The normal world currently takes care of saving and restoring the GICv2
+ * registers due to legacy reasons. Hence we just initialize the Distributor
+ * on resume from system suspend.
+ *****************************************************************************/
+void plat_arm_gic_save(void)
+{
+	return;
+}
+
+void plat_arm_gic_resume(void)
+{
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+}
diff --git a/plat/arm/common/arm_gicv3.c b/plat/arm/common/arm_gicv3.c
index cec6a9d..e273b77 100644
--- a/plat/arm/common/arm_gicv3.c
+++ b/plat/arm/common/arm_gicv3.c
@@ -32,6 +32,13 @@
 };
 
 /*
+ * We save and restore the GICv3 context on system suspend. Allocate the
+ * data in the designated EL3 Secure carve-out memory
+ */
+gicv3_redist_ctx_t rdist_ctx __section("arm_el3_tzc_dram");
+gicv3_dist_ctx_t dist_ctx __section("arm_el3_tzc_dram");
+
+/*
  * MPIDR hashing function for translating MPIDRs read from GICR_TYPER register
  * to core position.
  *
@@ -121,3 +128,58 @@
 {
 	gicv3_rdistif_off(plat_my_core_pos());
 }
+
+/******************************************************************************
+ * ARM common helper to save & restore the GICv3 on resume from system suspend
+ *****************************************************************************/
+void plat_arm_gic_save(void)
+{
+
+	/*
+	 * If an ITS is available, save its context before
+	 * the Redistributor using:
+	 * gicv3_its_save_disable(gits_base, &its_ctx[i])
+	 * Additionnaly, an implementation-defined sequence may
+	 * be required to save the whole ITS state.
+	 */
+
+	/*
+	 * Save the GIC Redistributors and ITS contexts before the
+	 * Distributor context. As we only handle SYSTEM SUSPEND API,
+	 * we only need to save the context of the CPU that is issuing
+	 * the SYSTEM SUSPEND call, i.e. the current CPU.
+	 */
+	gicv3_rdistif_save(plat_my_core_pos(), &rdist_ctx);
+
+	/* Save the GIC Distributor context */
+	gicv3_distif_save(&dist_ctx);
+
+	/*
+	 * From here, all the components of the GIC can be safely powered down
+	 * as long as there is an alternate way to handle wakeup interrupt
+	 * sources.
+	 */
+}
+
+void plat_arm_gic_resume(void)
+{
+	/* Restore the GIC Distributor context */
+	gicv3_distif_init_restore(&dist_ctx);
+
+	/*
+	 * Restore the GIC Redistributor and ITS contexts after the
+	 * Distributor context. As we only handle SYSTEM SUSPEND API,
+	 * we only need to restore the context of the CPU that issued
+	 * the SYSTEM SUSPEND call.
+	 */
+	gicv3_rdistif_init_restore(plat_my_core_pos(), &rdist_ctx);
+
+	/*
+	 * If an ITS is available, restore its context after
+	 * the Redistributor using:
+	 * gicv3_its_restore(gits_base, &its_ctx[i])
+	 * An implementation-defined sequence may be required to
+	 * restore the whole ITS state. The ITS must also be
+	 * re-enabled after this sequence has been executed.
+	 */
+}
diff --git a/plat/arm/common/arm_gicv3_legacy.c b/plat/arm/common/arm_gicv3_legacy.c
index a014a8e..e19799a 100644
--- a/plat/arm/common/arm_gicv3_legacy.c
+++ b/plat/arm/common/arm_gicv3_legacy.c
@@ -84,3 +84,16 @@
 {
 	return;
 }
+
+/******************************************************************************
+ * ARM common helper to save & restore the GICv3 on resume from system suspend.
+ *****************************************************************************/
+void plat_arm_gic_save(void)
+{
+	return;
+}
+
+void plat_arm_gic_resume(void)
+{
+	arm_gic_setup();
+}
diff --git a/plat/arm/common/arm_pm.c b/plat/arm/common/arm_pm.c
index cc131a9..5e7e047 100644
--- a/plat/arm/common/arm_pm.c
+++ b/plat/arm/common/arm_pm.c
@@ -11,6 +11,7 @@
 #include <console.h>
 #include <errno.h>
 #include <plat_arm.h>
+#include <platform.h>
 #include <platform_def.h>
 #include <psci.h>
 
@@ -140,6 +141,24 @@
 }
 
 /******************************************************************************
+ * Helper function to save the platform state before a system suspend. Save the
+ * state of the system components which are not in the Always ON power domain.
+ *****************************************************************************/
+void arm_system_pwr_domain_save(void)
+{
+	/* Assert system power domain is available on the platform */
+	assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2);
+
+	plat_arm_gic_save();
+
+	/*
+	 * All the other peripheral which are configured by ARM TF are
+	 * re-initialized on resume from system suspend. Hence we
+	 * don't save their state here.
+	 */
+}
+
+/******************************************************************************
  * Helper function to resume the platform from system suspend. Reinitialize
  * the system components which are not in the Always ON power domain.
  * TODO: Unify the platform setup when waking up from cold boot and system
@@ -153,12 +172,8 @@
 	/* Assert system power domain is available on the platform */
 	assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2);
 
-	/*
-	 * TODO: On GICv3 systems, figure out whether the core that wakes up
-	 * first from system suspend need to initialize the re-distributor
-	 * interface of all the other suspended cores.
-	 */
-	plat_arm_gic_init();
+	plat_arm_gic_resume();
+
 	plat_arm_security_setup();
 	arm_configure_sys_timer();
 }
diff --git a/plat/arm/common/arm_tzc400.c b/plat/arm/common/arm_tzc400.c
index 1d61c57..e19ca67 100644
--- a/plat/arm/common/arm_tzc400.c
+++ b/plat/arm/common/arm_tzc400.c
@@ -40,7 +40,7 @@
 
 	/* Region 1 set to cover Secure part of DRAM */
 	tzc400_configure_region(PLAT_ARM_TZC_FILTERS, 1,
-			ARM_AP_TZC_DRAM1_BASE, ARM_AP_TZC_DRAM1_END,
+			ARM_AP_TZC_DRAM1_BASE, ARM_EL3_TZC_DRAM1_END,
 			TZC_REGION_S_RDWR,
 			0);
 
diff --git a/plat/arm/common/arm_tzc_dmc500.c b/plat/arm/common/arm_tzc_dmc500.c
index 21ca4e8..8e41391 100644
--- a/plat/arm/common/arm_tzc_dmc500.c
+++ b/plat/arm/common/arm_tzc_dmc500.c
@@ -33,7 +33,7 @@
 
 	/* Region 1 set to cover Secure part of DRAM */
 	tzc_dmc500_configure_region(1, ARM_AP_TZC_DRAM1_BASE,
-		ARM_AP_TZC_DRAM1_END,
+		ARM_EL3_TZC_DRAM1_END,
 		TZC_REGION_S_RDWR,
 		0);
 
diff --git a/plat/arm/css/common/css_pm.c b/plat/arm/css/common/css_pm.c
index 39c02af..4104dd7 100644
--- a/plat/arm/css/common/css_pm.c
+++ b/plat/arm/css/common/css_pm.c
@@ -74,6 +74,9 @@
 {
 	assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF);
 
+	/* Enable the gic cpu interface */
+	plat_arm_gic_cpuif_enable();
+
 	/*
 	 * Perform the common cluster specific operations i.e enable coherency
 	 * if this cluster was off.
@@ -95,13 +98,10 @@
 	/* Assert that the system power domain need not be initialized */
 	assert(CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_RUN);
 
-	css_pwr_domain_on_finisher_common(target_state);
-
 	/* Program the gic per-cpu distributor or re-distributor interface */
 	plat_arm_gic_pcpu_init();
 
-	/* Enable the gic cpu interface */
-	plat_arm_gic_cpuif_enable();
+	css_pwr_domain_on_finisher_common(target_state);
 }
 
 /*******************************************************************************
@@ -144,8 +144,18 @@
 	if (CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_RET)
 		return;
 
+
 	assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF);
 	css_power_down_common(target_state);
+
+	/* Perform system domain state saving if issuing system suspend */
+	if (CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) {
+		arm_system_pwr_domain_save();
+
+		/* Power off the Redistributor after having saved its context */
+		plat_arm_gic_redistif_off();
+	}
+
 	css_scp_suspend(target_state);
 }
 
@@ -165,10 +175,12 @@
 
 	/* Perform system domain restore if woken up from system suspend */
 	if (CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF)
+		/*
+		 * At this point, the Distributor must be powered on to be ready
+		 * to have its state restored. The Redistributor will be powered
+		 * on as part of gicv3_rdistif_init_restore.
+		 */
 		arm_system_pwr_domain_resume();
-	else
-		/* Enable the gic cpu interface */
-		plat_arm_gic_cpuif_enable();
 
 	css_pwr_domain_on_finisher_common(target_state);
 }
diff --git a/plat/hisilicon/hikey/aarch64/hikey_common.c b/plat/hisilicon/hikey/aarch64/hikey_common.c
index 02a00ac..d5b63cc 100644
--- a/plat/hisilicon/hikey/aarch64/hikey_common.c
+++ b/plat/hisilicon/hikey/aarch64/hikey_common.c
@@ -59,7 +59,7 @@
  * This doesn't include Trusted RAM as the 'mem_layout' argument passed to
  * hikey_init_mmu_elx() will give the available subset of that,
  */
-#if IMAGE_BL1
+#ifdef IMAGE_BL1
 static const mmap_region_t hikey_mmap[] = {
 	MAP_DEVICE,
 	MAP_ROM_PARAM,
@@ -68,7 +68,7 @@
 };
 #endif
 
-#if IMAGE_BL2
+#ifdef IMAGE_BL2
 static const mmap_region_t hikey_mmap[] = {
 	MAP_DDR,
 	MAP_DEVICE,
@@ -82,7 +82,7 @@
 };
 #endif
 
-#if IMAGE_BL31
+#ifdef IMAGE_BL31
 static const mmap_region_t hikey_mmap[] = {
 	MAP_DEVICE,
 	MAP_SRAM,
@@ -91,7 +91,7 @@
 };
 #endif
 
-#if IMAGE_BL32
+#ifdef IMAGE_BL32
 static const mmap_region_t hikey_mmap[] = {
 	MAP_DEVICE,
 	MAP_DDR,
diff --git a/plat/hisilicon/hikey/hikey_io_storage.c b/plat/hisilicon/hikey/hikey_io_storage.c
index 60ec42b..57c66d5 100644
--- a/plat/hisilicon/hikey/hikey_io_storage.c
+++ b/plat/hisilicon/hikey/hikey_io_storage.c
@@ -47,7 +47,7 @@
 
 static const io_block_dev_spec_t emmc_dev_spec = {
 	/* It's used as temp buffer in block driver. */
-#if IMAGE_BL1
+#ifdef IMAGE_BL1
 	.buffer		= {
 		.offset	= HIKEY_BL1_MMC_DATA_BASE,
 		.length	= HIKEY_BL1_MMC_DATA_SIZE,
diff --git a/plat/hisilicon/hikey/include/platform_def.h b/plat/hisilicon/hikey/include/platform_def.h
index 0180654..f4a3fd4 100644
--- a/plat/hisilicon/hikey/include/platform_def.h
+++ b/plat/hisilicon/hikey/include/platform_def.h
@@ -151,15 +151,15 @@
  */
 #define ADDR_SPACE_SIZE			(1ull << 32)
 
-#if IMAGE_BL1 || IMAGE_BL32
+#if defined(IMAGE_BL1) || defined(IMAGE_BL32)
 #define MAX_XLAT_TABLES			3
 #endif
 
-#if IMAGE_BL31
+#ifdef IMAGE_BL31
 #define MAX_XLAT_TABLES			4
 #endif
 
-#if IMAGE_BL2
+#ifdef IMAGE_BL2
 #if LOAD_IMAGE_V2
 #ifdef SPD_opteed
 #define MAX_XLAT_TABLES			4
diff --git a/plat/hisilicon/hikey960/aarch64/hikey960_common.c b/plat/hisilicon/hikey960/aarch64/hikey960_common.c
index bce0c96..b1020a6 100644
--- a/plat/hisilicon/hikey960/aarch64/hikey960_common.c
+++ b/plat/hisilicon/hikey960/aarch64/hikey960_common.c
@@ -55,7 +55,7 @@
  * This doesn't include Trusted RAM as the 'mem_layout' argument passed to
  * hikey960_init_mmu_elx() will give the available subset of that,
  */
-#if IMAGE_BL1
+#ifdef IMAGE_BL1
 static const mmap_region_t hikey960_mmap[] = {
 	MAP_UFS_DATA,
 	MAP_BL1_RW,
@@ -65,7 +65,7 @@
 };
 #endif
 
-#if IMAGE_BL2
+#ifdef IMAGE_BL2
 static const mmap_region_t hikey960_mmap[] = {
 	MAP_DDR,
 	MAP_DEVICE,
@@ -79,7 +79,7 @@
 };
 #endif
 
-#if IMAGE_BL31
+#ifdef IMAGE_BL31
 static const mmap_region_t hikey960_mmap[] = {
 	MAP_DEVICE,
 	MAP_TSP_MEM,
@@ -87,7 +87,7 @@
 };
 #endif
 
-#if IMAGE_BL32
+#ifdef IMAGE_BL32
 static const mmap_region_t hikey960_mmap[] = {
 	MAP_DEVICE,
 	MAP_DDR,
diff --git a/plat/hisilicon/hikey960/include/platform_def.h b/plat/hisilicon/hikey960/include/platform_def.h
index 202952c..cb76090 100644
--- a/plat/hisilicon/hikey960/include/platform_def.h
+++ b/plat/hisilicon/hikey960/include/platform_def.h
@@ -116,11 +116,11 @@
  */
 #define ADDR_SPACE_SIZE			(1ull << 32)
 
-#if IMAGE_BL1 || IMAGE_BL31 || IMAGE_BL32
+#if defined(IMAGE_BL1) || defined(IMAGE_BL31) || defined(IMAGE_BL32)
 #define MAX_XLAT_TABLES			3
 #endif
 
-#if IMAGE_BL2
+#ifdef IMAGE_BL2
 #if LOAD_IMAGE_V2
 #ifdef SPD_opteed
 #define MAX_XLAT_TABLES			4
diff --git a/plat/qemu/qemu_bl31_setup.c b/plat/qemu/qemu_bl31_setup.c
index 5bf4589..f79a885 100644
--- a/plat/qemu/qemu_bl31_setup.c
+++ b/plat/qemu/qemu_bl31_setup.c
@@ -7,6 +7,7 @@
 #include <assert.h>
 #include <bl_common.h>
 #include <console.h>
+#include <gic_common.h>
 #include <gicv2.h>
 #include <platform_def.h>
 #include "qemu_private.h"
@@ -112,22 +113,40 @@
 			      BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END);
 }
 
-static const unsigned int irq_sec_array[] = {
-	QEMU_IRQ_SEC_SGI_0,
-	QEMU_IRQ_SEC_SGI_1,
-	QEMU_IRQ_SEC_SGI_2,
-	QEMU_IRQ_SEC_SGI_3,
-	QEMU_IRQ_SEC_SGI_4,
-	QEMU_IRQ_SEC_SGI_5,
-	QEMU_IRQ_SEC_SGI_6,
-	QEMU_IRQ_SEC_SGI_7,
+/******************************************************************************
+ * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
+ * interrupts.
+ *****************************************************************************/
+#define PLATFORM_G1S_PROPS(grp)						\
+	INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY,	\
+					   grp, GIC_INTR_CFG_EDGE),	\
+	INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY,	\
+					   grp, GIC_INTR_CFG_EDGE),	\
+	INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY,	\
+					   grp, GIC_INTR_CFG_EDGE),	\
+	INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY,	\
+					   grp, GIC_INTR_CFG_EDGE),	\
+	INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY,	\
+					   grp, GIC_INTR_CFG_EDGE),	\
+	INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY,	\
+					   grp, GIC_INTR_CFG_EDGE),	\
+	INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY,	\
+					   grp, GIC_INTR_CFG_EDGE),	\
+	INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY,	\
+					   grp, GIC_INTR_CFG_EDGE)
+
+#define PLATFORM_G0_PROPS(grp)
+
+static const interrupt_prop_t qemu_interrupt_props[] = {
+	PLATFORM_G1S_PROPS(GICV2_INTR_GROUP0),
+	PLATFORM_G0_PROPS(GICV2_INTR_GROUP0)
 };
 
 static const struct gicv2_driver_data plat_gicv2_driver_data = {
 	.gicd_base = GICD_BASE,
 	.gicc_base = GICC_BASE,
-	.g0_interrupt_num = ARRAY_SIZE(irq_sec_array),
-	.g0_interrupt_array = irq_sec_array,
+	.interrupt_props = qemu_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(qemu_interrupt_props),
 };
 
 void bl31_platform_setup(void)
diff --git a/plat/rockchip/rk3328/include/platform_def.h b/plat/rockchip/rk3328/include/platform_def.h
index 7304dcf..39d3c21 100644
--- a/plat/rockchip/rk3328/include/platform_def.h
+++ b/plat/rockchip/rk3328/include/platform_def.h
@@ -26,13 +26,13 @@
 /* Size of cacheable stacks */
 #if DEBUG_XLAT_TABLE
 #define PLATFORM_STACK_SIZE 0x800
-#elif IMAGE_BL1
+#elif defined(IMAGE_BL1)
 #define PLATFORM_STACK_SIZE 0x440
-#elif IMAGE_BL2
+#elif defined(IMAGE_BL2)
 #define PLATFORM_STACK_SIZE 0x400
-#elif IMAGE_BL31
+#elif defined(IMAGE_BL31)
 #define PLATFORM_STACK_SIZE 0x800
-#elif IMAGE_BL32
+#elif defined(IMAGE_BL32)
 #define PLATFORM_STACK_SIZE 0x440
 #endif
 
diff --git a/plat/rockchip/rk3399/platform.mk b/plat/rockchip/rk3399/platform.mk
index 85cca1b..6cd5b24 100644
--- a/plat/rockchip/rk3399/platform.mk
+++ b/plat/rockchip/rk3399/platform.mk
@@ -88,7 +88,7 @@
 ${BUILD_PLAT}/bl31/cdn_dp.o: CCACHE_EXTRAFILES=$(HDCPFW)
 ${RK_PLAT_SOC}/drivers/dp/cdn_dp.c: $(HDCPFW)
 
-$(eval $(call MAKE_PREREQ_DIR,${BUILD_M0},))
+$(eval $(call MAKE_PREREQ_DIR,${BUILD_M0},${BUILD_PLAT}))
 .PHONY: $(RK3399M0FW)
 $(RK3399M0FW): | ${BUILD_M0}
 	$(MAKE) -C ${RK_PLAT_SOC}/drivers/m0 BUILD=$(abspath ${BUILD_PLAT}/m0)
diff --git a/plat/socionext/uniphier/platform.mk b/plat/socionext/uniphier/platform.mk
index e6f510e..c91abb6 100644
--- a/plat/socionext/uniphier/platform.mk
+++ b/plat/socionext/uniphier/platform.mk
@@ -101,7 +101,7 @@
 $(BUILD_PLAT)/bl2/uniphier_rotpk.o: $(ROTPK_HASH)
 
 certificates: $(ROT_KEY)
-$(ROT_KEY):
+$(ROT_KEY): | $(BUILD_PLAT)
 	@echo "  OPENSSL $@"
 	$(Q)openssl genrsa 2048 > $@ 2>/dev/null