PSCI: Migrate ARM reference platforms to new platform API
This patch migrates ARM reference platforms, Juno and FVP, to the new platform
API mandated by the new PSCI power domain topology and composite power state
frameworks. The platform specific makefiles now exports the build flag
ENABLE_PLAT_COMPAT=0 to disable the platform compatibility layer.
Change-Id: I3040ed7cce446fc66facaee9c67cb54a8cd7ca29
diff --git a/plat/arm/css/common/css_pm.c b/plat/arm/css/common/css_pm.c
index 7b0282e..55b1703 100644
--- a/plat/arm/css/common/css_pm.c
+++ b/plat/arm/css/common/css_pm.c
@@ -41,6 +41,8 @@
#include <psci.h>
#include "css_scpi.h"
+unsigned long wakeup_address;
+
/*******************************************************************************
* Private function to program the mailbox for a cpu before it is released
* from reset.
@@ -50,32 +52,27 @@
uint64_t linear_id;
uint64_t mbox;
- linear_id = platform_get_core_pos(mpidr);
+ linear_id = plat_arm_calc_core_pos(mpidr);
mbox = TRUSTED_MAILBOXES_BASE + (linear_id << TRUSTED_MAILBOX_SHIFT);
*((uint64_t *) mbox) = address;
flush_dcache_range(mbox, sizeof(mbox));
}
/*******************************************************************************
- * 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);
+ css_program_mailbox(mpidr, wakeup_address);
scpi_set_css_power_state(mpidr, scpi_power_on, scpi_power_on,
scpi_power_on);
@@ -84,29 +81,22 @@
}
/*******************************************************************************
- * 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();
@@ -115,16 +105,16 @@
arm_gic_pcpu_distif_setup();
/* Clear the mailbox for this cpu. */
- css_program_mailbox(mpidr, 0);
+ css_program_mailbox(read_mpidr_el1(), 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 +122,8 @@
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 +139,60 @@
}
/*******************************************************************************
- * 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)
+ /*
+ * Juno has retention only at cpu level. Just return
+ * as nothing is to be done for retention.
+ */
+ 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);
+
/*
* Setup mailbox with address for CPU entrypoint when it next powers up.
*/
- css_program_mailbox(read_mpidr_el1(), sec_entrypoint);
+ css_program_mailbox(read_mpidr_el1(), wakeup_address);
- 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 +231,14 @@
}
/*******************************************************************************
- * 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 +256,28 @@
/*******************************************************************************
* 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
};
/*******************************************************************************
- * 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;
+
+ wakeup_address = sec_entrypoint;
+ flush_dcache_range((unsigned long)&wakeup_address,
+ sizeof(wakeup_address));
return 0;
}