summaryrefslogtreecommitdiff
path: root/plat/arm/css/common/css_pm.c
diff options
context:
space:
mode:
Diffstat (limited to 'plat/arm/css/common/css_pm.c')
-rw-r--r--plat/arm/css/common/css_pm.c192
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;
}