Provide a hint to power controller for DSU cluster power down

By writing 0 to CLUSTERPWRDN DSU register bit 0, we send an
advisory to the power controller that cluster power is not required
when all cores are powered down.

The AArch32 CLUSTERPWRDN register is architecturally mapped to the
AArch64 CLUSTERPWRDN_EL1 register

Change-Id: Ie6e67c1c7d811fa25c51e2e405ca7f59bd20c81b
Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
diff --git a/include/arch/aarch32/arch.h b/include/arch/aarch32/arch.h
index 8492b3e..a11d55e 100644
--- a/include/arch/aarch32/arch.h
+++ b/include/arch/aarch32/arch.h
@@ -701,4 +701,14 @@
 #define AMEVTYPER1E	p15, 0, c13, c15, 6
 #define AMEVTYPER1F	p15, 0, c13, c15, 7
 
+/*******************************************************************************
+ * Definitions for DynamicIQ Shared Unit registers
+ ******************************************************************************/
+#define CLUSTERPWRDN	p15, 0, c15, c3, 6
+
+/* CLUSTERPWRDN register definitions */
+#define DSU_CLUSTER_PWR_OFF	0
+#define DSU_CLUSTER_PWR_ON	1
+#define DSU_CLUSTER_PWR_MASK	U(1)
+
 #endif /* ARCH_H */
diff --git a/include/arch/aarch32/arch_helpers.h b/include/arch/aarch32/arch_helpers.h
index a90b2a5..eed56e2 100644
--- a/include/arch/aarch32/arch_helpers.h
+++ b/include/arch/aarch32/arch_helpers.h
@@ -336,6 +336,11 @@
 DEFINE_DCOP_PARAM_FUNC(cvac, DCCMVAC)
 #endif
 
+/*
+ * DynamIQ Shared Unit power management
+ */
+DEFINE_COPROCR_RW_FUNCS(clusterpwrdn, CLUSTERPWRDN)
+
 /* Previously defined accessor functions with incomplete register names  */
 #define dsb()			dsbsy()
 #define dmb()			dmbsy()
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index 19dd8c5..e45a594 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -947,4 +947,14 @@
 #define RGSR_EL1		S3_0_C1_C0_5
 #define GCR_EL1			S3_0_C1_C0_6
 
+/*******************************************************************************
+ * Definitions for DynamicIQ Shared Unit registers
+ ******************************************************************************/
+#define CLUSTERPWRDN_EL1	S3_0_c15_c3_6
+
+/* CLUSTERPWRDN_EL1 register definitions */
+#define DSU_CLUSTER_PWR_OFF	0
+#define DSU_CLUSTER_PWR_ON	1
+#define DSU_CLUSTER_PWR_MASK	U(1)
+
 #endif /* ARCH_H */
diff --git a/include/arch/aarch64/arch_helpers.h b/include/arch/aarch64/arch_helpers.h
index 669a140..9cd1ae5 100644
--- a/include/arch/aarch64/arch_helpers.h
+++ b/include/arch/aarch64/arch_helpers.h
@@ -520,6 +520,9 @@
 DEFINE_RENAME_SYSREG_RW_FUNCS(rgsr_el1, RGSR_EL1)
 DEFINE_RENAME_SYSREG_RW_FUNCS(gcr_el1, GCR_EL1)
 
+/* DynamIQ Shared Unit power management */
+DEFINE_RENAME_SYSREG_RW_FUNCS(clusterpwrdn_el1, CLUSTERPWRDN_EL1)
+
 #define IS_IN_EL(x) \
 	(GET_EL(read_CurrentEl()) == MODE_EL##x)
 
@@ -582,4 +585,7 @@
 #define read_cpacr()		read_cpacr_el1()
 #define write_cpacr(_v)		write_cpacr_el1(_v)
 
+#define read_clusterpwrdn()	read_clusterpwrdn_el1()
+#define write_clusterpwrdn(_v)	write_clusterpwrdn_el1(_v)
+
 #endif /* ARCH_HELPERS_H */
diff --git a/plat/arm/board/fvp/fvp_pm.c b/plat/arm/board/fvp/fvp_pm.c
index c47d837..333d892 100644
--- a/plat/arm/board/fvp/fvp_pm.c
+++ b/plat/arm/board/fvp/fvp_pm.c
@@ -64,6 +64,25 @@
 	/* Disable coherency if this cluster is to be turned off */
 	fvp_interconnect_disable();
 
+#if HW_ASSISTED_COHERENCY
+	uint32_t reg;
+
+	/*
+	 * If we have determined this core to be the last man standing and we
+	 * intend to power down the cluster proactively, we provide a hint to
+	 * the power controller that cluster power is not required when all
+	 * cores are powered down.
+	 * Note that this is only an advisory to power controller and is supported
+	 * by SoCs with DynamIQ Shared Units only.
+	 */
+	reg = read_clusterpwrdn();
+
+	/* Clear and set bit 0 : Cluster power not required */
+	reg &= ~DSU_CLUSTER_PWR_MASK;
+	reg |= DSU_CLUSTER_PWR_OFF;
+	write_clusterpwrdn(reg);
+#endif
+
 	/* Program the power controller to turn the cluster off */
 	fvp_pwrc_write_pcoffr(mpidr);
 }
diff --git a/plat/arm/css/common/css_pm.c b/plat/arm/css/common/css_pm.c
index af69c6f..8e74526 100644
--- a/plat/arm/css/common/css_pm.c
+++ b/plat/arm/css/common/css_pm.c
@@ -124,8 +124,28 @@
 	plat_arm_gic_cpuif_disable();
 
 	/* Cluster is to be turned off, so disable coherency */
-	if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF)
+	if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) {
 		plat_arm_interconnect_exit_coherency();
+
+#if HW_ASSISTED_COHERENCY
+		uint32_t reg;
+
+		/*
+		 * If we have determined this core to be the last man standing and we
+		 * intend to power down the cluster proactively, we provide a hint to
+		 * the power controller that cluster power is not required when all
+		 * cores are powered down.
+		 * Note that this is only an advisory to power controller and is supported
+		 * by SoCs with DynamIQ Shared Units only.
+		 */
+		reg = read_clusterpwrdn();
+
+		/* Clear and set bit 0 : Cluster power not required */
+		reg &= ~DSU_CLUSTER_PWR_MASK;
+		reg |= DSU_CLUSTER_PWR_OFF;
+		write_clusterpwrdn(reg);
+#endif
+	}
 }
 
 /*******************************************************************************