diff options
Diffstat (limited to 'plat/allwinner/common/sunxi_scpi_pm.c')
-rw-r--r-- | plat/allwinner/common/sunxi_scpi_pm.c | 81 |
1 files changed, 46 insertions, 35 deletions
diff --git a/plat/allwinner/common/sunxi_scpi_pm.c b/plat/allwinner/common/sunxi_scpi_pm.c index 74763ef7ed..6a0e967015 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 @@ -44,17 +47,6 @@ #define SYSTEM_PWR_STATE(state) \ ((state)->pwr_domain_state[SYSTEM_PWR_LVL]) -static inline scpi_power_state_t scpi_map_state(plat_local_state_t psci_state) -{ - if (is_local_state_run(psci_state)) { - return scpi_power_on; - } - if (is_local_state_retn(psci_state)) { - return scpi_power_retention; - } - return scpi_power_off; -} - static void sunxi_cpu_standby(plat_local_state_t cpu_state) { u_register_t scr = read_scr_el3(); @@ -87,9 +79,9 @@ static void sunxi_pwr_domain_off(const psci_power_state_t *target_state) } scpi_set_css_power_state(read_mpidr(), - scpi_map_state(cpu_pwr_state), - scpi_map_state(cluster_pwr_state), - scpi_map_state(system_pwr_state)); + cpu_pwr_state, + cluster_pwr_state, + system_pwr_state); } static void sunxi_pwr_domain_on_finish(const psci_power_state_t *target_state) @@ -133,11 +125,39 @@ static void __dead2 sunxi_system_reset(void) psci_power_down_wfi(); } +static int sunxi_system_reset2(int is_vendor, int reset_type, u_register_t cookie) +{ + uint32_t ret; + + if (is_vendor || (reset_type != PSCI_RESET2_SYSTEM_WARM_RESET)) + return PSCI_E_NOT_SUPPORTED; + + gicv2_cpuif_disable(); + + /* Send the system reset request to the SCP. */ + ret = scpi_sys_power_state(scpi_system_reset); + if (ret != SCP_OK) { + ERROR("PSCI: SCPI %s failed: %d\n", "reset", ret); + return PSCI_E_INVALID_PARAMS; + } + + psci_power_down_wfi(); + + /* + * Should not reach here. + * However sunxi_system_reset2 has to return some value + * according to PSCI v1.1 spec. + */ + return PSCI_E_SUCCESS; +} + 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); @@ -146,28 +166,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; } @@ -192,6 +203,7 @@ static const plat_psci_ops_t sunxi_scpi_psci_ops = { .pwr_domain_suspend_finish = sunxi_pwr_domain_on_finish, .system_off = sunxi_system_off, .system_reset = sunxi_system_reset, + .system_reset2 = sunxi_system_reset2, .validate_power_state = sunxi_validate_power_state, .validate_ns_entrypoint = sunxi_validate_ns_entrypoint, .get_sys_suspend_power_state = sunxi_get_sys_suspend_power_state, @@ -212,7 +224,6 @@ int sunxi_set_scpi_psci_ops(const plat_psci_ops_t **psci_ops) uint32_t offset = SUNXI_SCP_BASE - vector; mmio_write_32(vector, offset >> 2); - clean_dcache_range(vector, sizeof(uint32_t)); } /* Take the SCP out of reset. */ |