diff options
Diffstat (limited to 'plat/arm/css/common/css_pm.c')
-rw-r--r-- | plat/arm/css/common/css_pm.c | 192 |
1 files changed, 94 insertions, 98 deletions
diff --git a/plat/arm/css/common/css_pm.c b/plat/arm/css/common/css_pm.c index 7b0282ee..cc64bf8b 100644 --- a/plat/arm/css/common/css_pm.c +++ b/plat/arm/css/common/css_pm.c @@ -41,42 +41,49 @@ #include <psci.h> #include "css_scpi.h" + +#if ARM_RECOM_STATE_ID_ENC +/* + * The table storing the valid idle power states. Ensure that the + * array entries are populated in ascending order of state-id to + * enable us to use binary search during power state validation. + * 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), + 0, +}; +#endif + /******************************************************************************* * Private function to program the mailbox for a cpu before it is released * from reset. ******************************************************************************/ -static void css_program_mailbox(uint64_t mpidr, uint64_t address) +static void css_program_mailbox(uintptr_t address) { - uint64_t linear_id; - uint64_t mbox; - - linear_id = platform_get_core_pos(mpidr); - mbox = TRUSTED_MAILBOXES_BASE + (linear_id << TRUSTED_MAILBOX_SHIFT); - *((uint64_t *) mbox) = address; - flush_dcache_range(mbox, sizeof(mbox)); + uintptr_t *mailbox = (void *) TRUSTED_MAILBOX_BASE; + *mailbox = address; + flush_dcache_range((uintptr_t) mailbox, sizeof(*mailbox)); } /******************************************************************************* - * Handler called when an affinity instance is about to be turned on. The + * Handler called when a power domain is about to be turned on. The * level and mpidr determine the affinity instance. ******************************************************************************/ -int32_t css_affinst_on(uint64_t mpidr, - uint64_t sec_entrypoint, - uint32_t afflvl, - uint32_t state) +int css_pwr_domain_on(u_register_t mpidr) { /* - * SCP takes care of powering up higher affinity levels so we + * SCP takes care of powering up parent power domains so we * only need to care about level 0 */ - if (afflvl != MPIDR_AFFLVL0) - return PSCI_E_SUCCESS; - - /* - * Setup mailbox with address for CPU entrypoint when it next powers up - */ - css_program_mailbox(mpidr, sec_entrypoint); - scpi_set_css_power_state(mpidr, scpi_power_on, scpi_power_on, scpi_power_on); @@ -84,47 +91,37 @@ int32_t css_affinst_on(uint64_t mpidr, } /******************************************************************************* - * Handler called when an affinity instance has just been powered on after - * being turned off earlier. The level and mpidr determine the affinity - * instance. The 'state' arg. allows the platform to decide whether the cluster - * was turned off prior to wakeup and do what's necessary to setup it up - * correctly. + * Handler called when a power level has just been powered on after + * being turned off earlier. The target_state encodes the low power state that + * each level has woken up from. ******************************************************************************/ -void css_affinst_on_finish(uint32_t afflvl, uint32_t state) +void css_pwr_domain_on_finish(const psci_power_state_t *target_state) { - unsigned long mpidr; - - /* Determine if any platform actions need to be executed. */ - if (arm_do_affinst_actions(afflvl, state) == -EAGAIN) - return; - - /* Get the mpidr for this cpu */ - mpidr = read_mpidr_el1(); + assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == + ARM_LOCAL_STATE_OFF); /* * Perform the common cluster specific operations i.e enable coherency * if this cluster was off. */ - if (afflvl != MPIDR_AFFLVL0) - cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); + if (target_state->pwr_domain_state[ARM_PWR_LVL1] == + ARM_LOCAL_STATE_OFF) + cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1())); /* Enable the gic cpu interface */ arm_gic_cpuif_setup(); /* todo: Is this setup only needed after a cold boot? */ arm_gic_pcpu_distif_setup(); - - /* Clear the mailbox for this cpu. */ - css_program_mailbox(mpidr, 0); } /******************************************************************************* * Common function called while turning a cpu off or suspending it. It is called * from css_off() or css_suspend() when these functions in turn are called for - * the highest affinity level which will be powered down. It performs the - * actions common to the OFF and SUSPEND calls. + * power domain at the highest power level which will be powered down. It + * performs the actions common to the OFF and SUSPEND calls. ******************************************************************************/ -static void css_power_down_common(uint32_t afflvl) +static void css_power_down_common(const psci_power_state_t *target_state) { uint32_t cluster_state = scpi_power_on; @@ -132,7 +129,8 @@ static void css_power_down_common(uint32_t afflvl) arm_gic_cpuif_deactivate(); /* Cluster is to be turned off, so disable coherency */ - if (afflvl > MPIDR_AFFLVL0) { + if (target_state->pwr_domain_state[ARM_PWR_LVL1] == + ARM_LOCAL_STATE_OFF) { cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr())); cluster_state = scpi_power_off; } @@ -148,64 +146,55 @@ static void css_power_down_common(uint32_t afflvl) } /******************************************************************************* - * Handler called when an affinity instance is about to be turned off. The - * level and mpidr determine the affinity instance. The 'state' arg. allows the - * platform to decide whether the cluster is being turned off and take - * appropriate actions. - * - * CAUTION: There is no guarantee that caches will remain turned on across calls - * to this function as each affinity level is dealt with. So do not write & read - * global variables across calls. It will be wise to do flush a write to the - * global to prevent unpredictable results. + * Handler called when a power domain is about to be turned off. The + * target_state encodes the power state that each level should transition to. ******************************************************************************/ -static void css_affinst_off(uint32_t afflvl, uint32_t state) +static void css_pwr_domain_off(const psci_power_state_t *target_state) { - /* Determine if any platform actions need to be executed */ - if (arm_do_affinst_actions(afflvl, state) == -EAGAIN) - return; + assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == + ARM_LOCAL_STATE_OFF); - css_power_down_common(afflvl); + css_power_down_common(target_state); } /******************************************************************************* - * Handler called when an affinity instance is about to be suspended. The - * level and mpidr determine the affinity instance. The 'state' arg. allows the - * platform to decide whether the cluster is being turned off and take apt - * actions. The 'sec_entrypoint' determines the address in BL3-1 from where - * execution should resume. - * - * CAUTION: There is no guarantee that caches will remain turned on across calls - * to this function as each affinity level is dealt with. So do not write & read - * global variables across calls. It will be wise to do flush a write to the - * global to prevent unpredictable results. + * Handler called when a power domain is about to be suspended. The + * target_state encodes the power state that each level should transition to. ******************************************************************************/ -static void css_affinst_suspend(uint64_t sec_entrypoint, - uint32_t afflvl, - uint32_t state) +static void css_pwr_domain_suspend(const psci_power_state_t *target_state) { - /* Determine if any platform actions need to be executed */ - if (arm_do_affinst_actions(afflvl, state) == -EAGAIN) - return; - /* - * Setup mailbox with address for CPU entrypoint when it next powers up. + * Juno has retention only at cpu level. Just return + * as nothing is to be done for retention. */ - css_program_mailbox(read_mpidr_el1(), sec_entrypoint); + if (target_state->pwr_domain_state[ARM_PWR_LVL0] == + ARM_LOCAL_STATE_RET) + return; + + assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == + ARM_LOCAL_STATE_OFF); - css_power_down_common(afflvl); + css_power_down_common(target_state); } /******************************************************************************* - * Handler called when an affinity instance has just been powered on after - * having been suspended earlier. The level and mpidr determine the affinity - * instance. + * Handler called when a power domain has just been powered on after + * having been suspended earlier. The target_state encodes the low power state + * that each level has woken up from. * TODO: At the moment we reuse the on finisher and reinitialize the secure * context. Need to implement a separate suspend finisher. ******************************************************************************/ -static void css_affinst_suspend_finish(uint32_t afflvl, - uint32_t state) +static void css_pwr_domain_suspend_finish( + const psci_power_state_t *target_state) { - css_affinst_on_finish(afflvl, state); + /* + * Return as nothing is to be done on waking up from retention. + */ + if (target_state->pwr_domain_state[ARM_PWR_LVL0] == + ARM_LOCAL_STATE_RET) + return; + + css_pwr_domain_on_finish(target_state); } /******************************************************************************* @@ -244,12 +233,14 @@ static void __dead2 css_system_reset(void) } /******************************************************************************* - * Handler called when an affinity instance is about to enter standby. + * Handler called when the CPU power domain is about to enter standby. ******************************************************************************/ -void css_affinst_standby(unsigned int power_state) +void css_cpu_standby(plat_local_state_t cpu_state) { unsigned int scr; + assert(cpu_state == ARM_LOCAL_STATE_RET); + scr = read_scr_el3(); /* Enable PhysicalIRQ bit for NS world to wake the CPU */ write_scr_el3(scr | SCR_IRQ_BIT); @@ -267,23 +258,28 @@ void css_affinst_standby(unsigned int power_state) /******************************************************************************* * Export the platform handlers to enable psci to invoke them ******************************************************************************/ -static const plat_pm_ops_t css_ops = { - .affinst_on = css_affinst_on, - .affinst_on_finish = css_affinst_on_finish, - .affinst_off = css_affinst_off, - .affinst_standby = css_affinst_standby, - .affinst_suspend = css_affinst_suspend, - .affinst_suspend_finish = css_affinst_suspend_finish, +static const plat_psci_ops_t css_ops = { + .pwr_domain_on = css_pwr_domain_on, + .pwr_domain_on_finish = css_pwr_domain_on_finish, + .pwr_domain_off = css_pwr_domain_off, + .cpu_standby = css_cpu_standby, + .pwr_domain_suspend = css_pwr_domain_suspend, + .pwr_domain_suspend_finish = css_pwr_domain_suspend_finish, .system_off = css_system_off, .system_reset = css_system_reset, - .validate_power_state = arm_validate_power_state + .validate_power_state = arm_validate_power_state, + .validate_ns_entrypoint = arm_validate_ns_entrypoint }; /******************************************************************************* - * Export the platform specific power ops. + * Export the platform specific psci ops. ******************************************************************************/ -int32_t platform_setup_pm(const plat_pm_ops_t **plat_ops) +int plat_setup_psci_ops(uintptr_t sec_entrypoint, + const plat_psci_ops_t **psci_ops) { - *plat_ops = &css_ops; + *psci_ops = &css_ops; + + /* Setup mailbox with entry point. */ + css_program_mailbox(sec_entrypoint); return 0; } |