From 75ddf133e308f7ce15af9ecd899079a22c59dcfc Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Thu, 18 Mar 2021 23:15:28 -0500 Subject: [PATCH] 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. Since SCPI provides no way to handshake an exit from a standby state, the only possible standby state is the architectural WFI state. Since WFI can be used without PSCI, we do not allow passing in standby states. Signed-off-by: Samuel Holland Change-Id: I4b3b84e5c255ee58a25255a0cab5d7623425086e --- plat/allwinner/common/sunxi_scpi_pm.c | 36 ++++++++++++--------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/plat/allwinner/common/sunxi_scpi_pm.c b/plat/allwinner/common/sunxi_scpi_pm.c index 89c834aa9..8dcc54b16 100644 --- a/plat/allwinner/common/sunxi_scpi_pm.c +++ b/plat/allwinner/common/sunxi_scpi_pm.c @@ -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; } -- 2.33.1