From 9cf7f355ce8984a4cde970d5f57c913d5247ca6d Mon Sep 17 00:00:00 2001 From: Madhukar Pappireddy Date: Wed, 30 Oct 2019 14:24:39 -0500 Subject: [PATCH] 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 --- include/arch/aarch32/arch.h | 10 ++++++++++ include/arch/aarch32/arch_helpers.h | 5 +++++ include/arch/aarch64/arch.h | 10 ++++++++++ include/arch/aarch64/arch_helpers.h | 6 ++++++ plat/arm/board/fvp/fvp_pm.c | 19 +++++++++++++++++++ plat/arm/css/common/css_pm.c | 22 +++++++++++++++++++++- 6 files changed, 71 insertions(+), 1 deletion(-) diff --git a/include/arch/aarch32/arch.h b/include/arch/aarch32/arch.h index 8492b3ea4..a11d55e08 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 a90b2a54c..eed56e219 100644 --- a/include/arch/aarch32/arch_helpers.h +++ b/include/arch/aarch32/arch_helpers.h @@ -336,6 +336,11 @@ DEFINE_DCOP_PARAM_FUNC(cvac, DCCIMVAC) 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 19dd8c5e3..e45a594c5 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 669a1403c..9cd1ae515 100644 --- a/include/arch/aarch64/arch_helpers.h +++ b/include/arch/aarch64/arch_helpers.h @@ -520,6 +520,9 @@ DEFINE_RENAME_SYSREG_RW_FUNCS(tfsr_el1, TFSR_EL1) 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 @@ static inline uint64_t el_implemented(unsigned int el) #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 c47d83779..333d89288 100644 --- a/plat/arm/board/fvp/fvp_pm.c +++ b/plat/arm/board/fvp/fvp_pm.c @@ -64,6 +64,25 @@ static void fvp_cluster_pwrdwn_common(void) /* 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 af69c6fb4..8e7452634 100644 --- a/plat/arm/css/common/css_pm.c +++ b/plat/arm/css/common/css_pm.c @@ -124,8 +124,28 @@ static void css_power_down_common(const psci_power_state_t *target_state) 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 + } } /*******************************************************************************