diff options
author | danh-arm <dan.handley@arm.com> | 2015-10-30 16:57:32 +0000 |
---|---|---|
committer | danh-arm <dan.handley@arm.com> | 2015-10-30 16:57:32 +0000 |
commit | f4c012537d02be82b550b0d977a9b28b72c2637c (patch) | |
tree | cfbaabb67ef5c1197db4d167163bc5d6b14791f4 /plat/arm/css/common/css_pm.c | |
parent | c909c636c3ffe13360a342e3d69f2f5cb6bdae9c (diff) | |
parent | 6971c6274432f74c73ca952617e38d191c94794d (diff) |
Merge pull request #418 from soby-mathew/sm/sys_suspend
Support SYSTEM SUSPEND on Juno
Diffstat (limited to 'plat/arm/css/common/css_pm.c')
-rw-r--r-- | plat/arm/css/common/css_pm.c | 85 |
1 files changed, 74 insertions, 11 deletions
diff --git a/plat/arm/css/common/css_pm.c b/plat/arm/css/common/css_pm.c index c0c615b9..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> @@ -51,18 +52,30 @@ * The table must be terminated by a NULL entry. */ const unsigned int arm_pm_idle_states[] = { - /* State-id - 0x01 */ - arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RET, - ARM_PWR_LVL0, PSTATE_TYPE_STANDBY), - /* State-id - 0x02 */ - arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_OFF, - ARM_PWR_LVL0, PSTATE_TYPE_POWERDOWN), - /* State-id - 0x22 */ - arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF, - ARM_PWR_LVL1, PSTATE_TYPE_POWERDOWN), + /* State-id - 0x001 */ + arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RUN, + ARM_LOCAL_STATE_RET, ARM_PWR_LVL0, PSTATE_TYPE_STANDBY), + /* State-id - 0x002 */ + arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RUN, + ARM_LOCAL_STATE_OFF, ARM_PWR_LVL0, PSTATE_TYPE_POWERDOWN), + /* State-id - 0x022 */ + arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_OFF, + ARM_LOCAL_STATE_OFF, ARM_PWR_LVL1, PSTATE_TYPE_POWERDOWN), +#if PLAT_MAX_PWR_LVL > ARM_PWR_LVL1 + /* 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), +#endif 0, }; -#endif +#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 @@ -90,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. @@ -98,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(); @@ -114,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) { @@ -132,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); } /******************************************************************************* @@ -246,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. ******************************************************************************/ |