diff options
Diffstat (limited to 'plat/arm/css/common/css_pm.c')
-rw-r--r-- | plat/arm/css/common/css_pm.c | 60 |
1 files changed, 59 insertions, 1 deletions
diff --git a/plat/arm/css/common/css_pm.c b/plat/arm/css/common/css_pm.c index 2d0e9019..3f468570 100644 --- a/plat/arm/css/common/css_pm.c +++ b/plat/arm/css/common/css_pm.c @@ -31,6 +31,7 @@ #include <arch_helpers.h> #include <assert.h> #include <arm_gic.h> +#include <cassert.h> #include <cci.h> #include <css_pm.h> #include <debug.h> @@ -69,6 +70,13 @@ const unsigned int arm_pm_idle_states[] = { }; #endif /* __ARM_RECOM_STATE_ID_ENC__ */ +/* + * All the power management helpers in this file assume at least cluster power + * level is supported. + */ +CASSERT(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL1, + assert_max_pwr_lvl_supported_mismatch); + /******************************************************************************* * Handler called when a power domain is about to be turned on. The * level and mpidr determine the affinity instance. @@ -95,6 +103,16 @@ void css_pwr_domain_on_finish(const psci_power_state_t *target_state) assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == ARM_LOCAL_STATE_OFF); + if (PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) { + /* + * Perform system initialization if woken up from system + * suspend. + */ + if (target_state->pwr_domain_state[ARM_PWR_LVL2] == + ARM_LOCAL_STATE_OFF) + arm_system_pwr_domain_resume(); + } + /* * Perform the common cluster specific operations i.e enable coherency * if this cluster was off. @@ -103,6 +121,18 @@ void css_pwr_domain_on_finish(const psci_power_state_t *target_state) ARM_LOCAL_STATE_OFF) cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1())); + + if (PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) { + /* + * Skip GIC CPU interface and per-CPU Distributor interface + * setups if woken up from system suspend as it is done as + * part of css_system_pwr_domain_resume(). + */ + if (target_state->pwr_domain_state[ARM_PWR_LVL2] == + ARM_LOCAL_STATE_OFF) + return; + } + /* Enable the gic cpu interface */ arm_gic_cpuif_setup(); @@ -119,10 +149,21 @@ void css_pwr_domain_on_finish(const psci_power_state_t *target_state) static void css_power_down_common(const psci_power_state_t *target_state) { uint32_t cluster_state = scpi_power_on; + uint32_t system_state = scpi_power_on; /* Prevent interrupts from spuriously waking up this cpu */ arm_gic_cpuif_deactivate(); + if (PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) { + /* + * Check if power down at system power domain level is + * requested. + */ + if (target_state->pwr_domain_state[ARM_PWR_LVL2] == + ARM_LOCAL_STATE_OFF) + system_state = scpi_power_retention; + } + /* Cluster is to be turned off, so disable coherency */ if (target_state->pwr_domain_state[ARM_PWR_LVL1] == ARM_LOCAL_STATE_OFF) { @@ -137,7 +178,7 @@ static void css_power_down_common(const psci_power_state_t *target_state) scpi_set_css_power_state(read_mpidr_el1(), scpi_power_off, cluster_state, - scpi_power_on); + system_state); } /******************************************************************************* @@ -251,6 +292,23 @@ void css_cpu_standby(plat_local_state_t cpu_state) } /******************************************************************************* + * Handler called to return the 'req_state' for system suspend. + ******************************************************************************/ +void css_get_sys_suspend_power_state(psci_power_state_t *req_state) +{ + unsigned int i; + + /* + * System Suspend is supported only if the system power domain node + * is implemented. + */ + assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2); + + for (i = ARM_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++) + req_state->pwr_domain_state[i] = ARM_LOCAL_STATE_OFF; +} + +/******************************************************************************* * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard * platform will take care of registering the handlers with PSCI. ******************************************************************************/ |