|
@@ -21,6 +21,7 @@
|
|
|
#include "common.h"
|
|
|
#include "pm.h"
|
|
|
#include "prm.h"
|
|
|
+#include "soc.h"
|
|
|
#include "clockdomain.h"
|
|
|
|
|
|
#define MAX_CPUS 2
|
|
@@ -30,6 +31,7 @@ struct idle_statedata {
|
|
|
u32 cpu_state;
|
|
|
u32 mpu_logic_state;
|
|
|
u32 mpu_state;
|
|
|
+ u32 mpu_state_vote;
|
|
|
};
|
|
|
|
|
|
static struct idle_statedata omap4_idle_data[] = {
|
|
@@ -50,12 +52,26 @@ static struct idle_statedata omap4_idle_data[] = {
|
|
|
},
|
|
|
};
|
|
|
|
|
|
+static struct idle_statedata omap5_idle_data[] = {
|
|
|
+ {
|
|
|
+ .cpu_state = PWRDM_POWER_ON,
|
|
|
+ .mpu_state = PWRDM_POWER_ON,
|
|
|
+ .mpu_logic_state = PWRDM_POWER_ON,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .cpu_state = PWRDM_POWER_RET,
|
|
|
+ .mpu_state = PWRDM_POWER_RET,
|
|
|
+ .mpu_logic_state = PWRDM_POWER_RET,
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
static struct powerdomain *mpu_pd, *cpu_pd[MAX_CPUS];
|
|
|
static struct clockdomain *cpu_clkdm[MAX_CPUS];
|
|
|
|
|
|
static atomic_t abort_barrier;
|
|
|
static bool cpu_done[MAX_CPUS];
|
|
|
static struct idle_statedata *state_ptr = &omap4_idle_data[0];
|
|
|
+static DEFINE_RAW_SPINLOCK(mpu_lock);
|
|
|
|
|
|
/* Private functions */
|
|
|
|
|
@@ -77,6 +93,32 @@ static int omap_enter_idle_simple(struct cpuidle_device *dev,
|
|
|
return index;
|
|
|
}
|
|
|
|
|
|
+static int omap_enter_idle_smp(struct cpuidle_device *dev,
|
|
|
+ struct cpuidle_driver *drv,
|
|
|
+ int index)
|
|
|
+{
|
|
|
+ struct idle_statedata *cx = state_ptr + index;
|
|
|
+ unsigned long flag;
|
|
|
+
|
|
|
+ raw_spin_lock_irqsave(&mpu_lock, flag);
|
|
|
+ cx->mpu_state_vote++;
|
|
|
+ if (cx->mpu_state_vote == num_online_cpus()) {
|
|
|
+ pwrdm_set_logic_retst(mpu_pd, cx->mpu_logic_state);
|
|
|
+ omap_set_pwrdm_state(mpu_pd, cx->mpu_state);
|
|
|
+ }
|
|
|
+ raw_spin_unlock_irqrestore(&mpu_lock, flag);
|
|
|
+
|
|
|
+ omap4_enter_lowpower(dev->cpu, cx->cpu_state);
|
|
|
+
|
|
|
+ raw_spin_lock_irqsave(&mpu_lock, flag);
|
|
|
+ if (cx->mpu_state_vote == num_online_cpus())
|
|
|
+ omap_set_pwrdm_state(mpu_pd, PWRDM_POWER_ON);
|
|
|
+ cx->mpu_state_vote--;
|
|
|
+ raw_spin_unlock_irqrestore(&mpu_lock, flag);
|
|
|
+
|
|
|
+ return index;
|
|
|
+}
|
|
|
+
|
|
|
static int omap_enter_idle_coupled(struct cpuidle_device *dev,
|
|
|
struct cpuidle_driver *drv,
|
|
|
int index)
|
|
@@ -220,6 +262,32 @@ static struct cpuidle_driver omap4_idle_driver = {
|
|
|
.safe_state_index = 0,
|
|
|
};
|
|
|
|
|
|
+static struct cpuidle_driver omap5_idle_driver = {
|
|
|
+ .name = "omap5_idle",
|
|
|
+ .owner = THIS_MODULE,
|
|
|
+ .states = {
|
|
|
+ {
|
|
|
+ /* C1 - CPU0 ON + CPU1 ON + MPU ON */
|
|
|
+ .exit_latency = 2 + 2,
|
|
|
+ .target_residency = 5,
|
|
|
+ .enter = omap_enter_idle_simple,
|
|
|
+ .name = "C1",
|
|
|
+ .desc = "CPUx WFI, MPUSS ON"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ /* C2 - CPU0 RET + CPU1 RET + MPU CSWR */
|
|
|
+ .exit_latency = 48 + 60,
|
|
|
+ .target_residency = 100,
|
|
|
+ .flags = CPUIDLE_FLAG_TIMER_STOP,
|
|
|
+ .enter = omap_enter_idle_smp,
|
|
|
+ .name = "C2",
|
|
|
+ .desc = "CPUx CSWR, MPUSS CSWR",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ .state_count = ARRAY_SIZE(omap5_idle_data),
|
|
|
+ .safe_state_index = 0,
|
|
|
+};
|
|
|
+
|
|
|
/* Public functions */
|
|
|
|
|
|
/**
|
|
@@ -230,6 +298,16 @@ static struct cpuidle_driver omap4_idle_driver = {
|
|
|
*/
|
|
|
int __init omap4_idle_init(void)
|
|
|
{
|
|
|
+ struct cpuidle_driver *idle_driver;
|
|
|
+
|
|
|
+ if (soc_is_omap54xx()) {
|
|
|
+ state_ptr = &omap5_idle_data[0];
|
|
|
+ idle_driver = &omap5_idle_driver;
|
|
|
+ } else {
|
|
|
+ state_ptr = &omap4_idle_data[0];
|
|
|
+ idle_driver = &omap4_idle_driver;
|
|
|
+ }
|
|
|
+
|
|
|
mpu_pd = pwrdm_lookup("mpu_pwrdm");
|
|
|
cpu_pd[0] = pwrdm_lookup("cpu0_pwrdm");
|
|
|
cpu_pd[1] = pwrdm_lookup("cpu1_pwrdm");
|
|
@@ -244,5 +322,5 @@ int __init omap4_idle_init(void)
|
|
|
/* Configure the broadcast timer on each cpu */
|
|
|
on_each_cpu(omap_setup_broadcast_timer, NULL, 1);
|
|
|
|
|
|
- return cpuidle_register(&omap4_idle_driver, cpu_online_mask);
|
|
|
+ return cpuidle_register(idle_driver, cpu_online_mask);
|
|
|
}
|