feat(allwinner): simplify CPU_SUSPEND power state encoding

Use the encoding recommended by the PSCI specification: four bits for
the power state at each power level.

SCPI provides no way to handshake an exit from a standby state, so the
only possible standby state is the architectural WFI state. Since WFI
can be used outside of PSCI, we do not allow passing in standby states.

Change-Id: I4b3b84e5c255ee58a25255a0cab5d7623425086e
Signed-off-by: Samuel Holland <samuel@sholland.org>
This commit is contained in:
Samuel Holland 2021-03-18 23:15:28 -05:00 committed by Joanna Farley
parent 159c36fd2f
commit 52466ec38e
1 changed files with 16 additions and 20 deletions

View File

@ -33,6 +33,9 @@
*/
#define SCP_FIRMWARE_MAGIC 0xb4400012
#define PLAT_LOCAL_PSTATE_WIDTH U(4)
#define PLAT_LOCAL_PSTATE_MASK ((U(1) << PLAT_LOCAL_PSTATE_WIDTH) - 1)
#define CPU_PWR_LVL MPIDR_AFFLVL0
#define CLUSTER_PWR_LVL MPIDR_AFFLVL1
#define SYSTEM_PWR_LVL MPIDR_AFFLVL2
@ -126,7 +129,9 @@ static int sunxi_validate_power_state(unsigned int power_state,
psci_power_state_t *req_state)
{
unsigned int power_level = psci_get_pstate_pwrlvl(power_state);
unsigned int state_id = psci_get_pstate_id(power_state);
unsigned int type = psci_get_pstate_type(power_state);
unsigned int i;
assert(req_state != NULL);
@ -135,28 +140,19 @@ static int sunxi_validate_power_state(unsigned int power_state,
}
if (type == PSTATE_TYPE_STANDBY) {
/* Only one retention power state is supported. */
if (psci_get_pstate_id(power_state) > 0) {
return PSCI_E_INVALID_PARAMS;
}
/* The SoC cannot be suspended without losing state */
if (power_level == SYSTEM_PWR_LVL) {
return PSCI_E_INVALID_PARAMS;
}
for (unsigned int i = 0; i <= power_level; ++i) {
req_state->pwr_domain_state[i] = PLAT_MAX_RET_STATE;
}
} else {
/* Only one off power state is supported. */
if (psci_get_pstate_id(power_state) > 0) {
return PSCI_E_INVALID_PARAMS;
}
for (unsigned int i = 0; i <= power_level; ++i) {
req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
}
return PSCI_E_INVALID_PARAMS;
}
/* Pass through the requested PSCI state as-is. */
for (i = 0; i <= power_level; ++i) {
unsigned int local_pstate = state_id & PLAT_LOCAL_PSTATE_MASK;
req_state->pwr_domain_state[i] = local_pstate;
state_id >>= PLAT_LOCAL_PSTATE_WIDTH;
}
/* Higher power domain levels should all remain running */
for (unsigned int i = power_level + 1; i <= PLAT_MAX_PWR_LVL; ++i) {
for (; i <= PLAT_MAX_PWR_LVL; ++i) {
req_state->pwr_domain_state[i] = PSCI_LOCAL_STATE_RUN;
}