|
@@ -14,6 +14,7 @@
|
|
#include <linux/cpuidle.h>
|
|
#include <linux/cpuidle.h>
|
|
#include <linux/cpu_pm.h>
|
|
#include <linux/cpu_pm.h>
|
|
#include <linux/export.h>
|
|
#include <linux/export.h>
|
|
|
|
+#include <linux/clockchips.h>
|
|
|
|
|
|
#include <asm/cpuidle.h>
|
|
#include <asm/cpuidle.h>
|
|
#include <asm/proc-fns.h>
|
|
#include <asm/proc-fns.h>
|
|
@@ -83,6 +84,7 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
|
|
{
|
|
{
|
|
struct idle_statedata *cx = state_ptr + index;
|
|
struct idle_statedata *cx = state_ptr + index;
|
|
u32 mpuss_can_lose_context = 0;
|
|
u32 mpuss_can_lose_context = 0;
|
|
|
|
+ int cpu_id = smp_processor_id();
|
|
|
|
|
|
/*
|
|
/*
|
|
* CPU0 has to wait and stay ON until CPU1 is OFF state.
|
|
* CPU0 has to wait and stay ON until CPU1 is OFF state.
|
|
@@ -110,6 +112,8 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
|
|
mpuss_can_lose_context = (cx->mpu_state == PWRDM_POWER_RET) &&
|
|
mpuss_can_lose_context = (cx->mpu_state == PWRDM_POWER_RET) &&
|
|
(cx->mpu_logic_state == PWRDM_POWER_OFF);
|
|
(cx->mpu_logic_state == PWRDM_POWER_OFF);
|
|
|
|
|
|
|
|
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu_id);
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Call idle CPU PM enter notifier chain so that
|
|
* Call idle CPU PM enter notifier chain so that
|
|
* VFP and per CPU interrupt context is saved.
|
|
* VFP and per CPU interrupt context is saved.
|
|
@@ -165,6 +169,8 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
|
|
if (dev->cpu == 0 && mpuss_can_lose_context)
|
|
if (dev->cpu == 0 && mpuss_can_lose_context)
|
|
cpu_cluster_pm_exit();
|
|
cpu_cluster_pm_exit();
|
|
|
|
|
|
|
|
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu_id);
|
|
|
|
+
|
|
fail:
|
|
fail:
|
|
cpuidle_coupled_parallel_barrier(dev, &abort_barrier);
|
|
cpuidle_coupled_parallel_barrier(dev, &abort_barrier);
|
|
cpu_done[dev->cpu] = false;
|
|
cpu_done[dev->cpu] = false;
|
|
@@ -172,6 +178,16 @@ fail:
|
|
return index;
|
|
return index;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * For each cpu, setup the broadcast timer because local timers
|
|
|
|
+ * stops for the states above C1.
|
|
|
|
+ */
|
|
|
|
+static void omap_setup_broadcast_timer(void *arg)
|
|
|
|
+{
|
|
|
|
+ int cpu = smp_processor_id();
|
|
|
|
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu);
|
|
|
|
+}
|
|
|
|
+
|
|
static struct cpuidle_driver omap4_idle_driver = {
|
|
static struct cpuidle_driver omap4_idle_driver = {
|
|
.name = "omap4_idle",
|
|
.name = "omap4_idle",
|
|
.owner = THIS_MODULE,
|
|
.owner = THIS_MODULE,
|
|
@@ -189,8 +205,7 @@ static struct cpuidle_driver omap4_idle_driver = {
|
|
/* C2 - CPU0 OFF + CPU1 OFF + MPU CSWR */
|
|
/* C2 - CPU0 OFF + CPU1 OFF + MPU CSWR */
|
|
.exit_latency = 328 + 440,
|
|
.exit_latency = 328 + 440,
|
|
.target_residency = 960,
|
|
.target_residency = 960,
|
|
- .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED |
|
|
|
|
- CPUIDLE_FLAG_TIMER_STOP,
|
|
|
|
|
|
+ .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED,
|
|
.enter = omap_enter_idle_coupled,
|
|
.enter = omap_enter_idle_coupled,
|
|
.name = "C2",
|
|
.name = "C2",
|
|
.desc = "CPUx OFF, MPUSS CSWR",
|
|
.desc = "CPUx OFF, MPUSS CSWR",
|
|
@@ -199,8 +214,7 @@ static struct cpuidle_driver omap4_idle_driver = {
|
|
/* C3 - CPU0 OFF + CPU1 OFF + MPU OSWR */
|
|
/* C3 - CPU0 OFF + CPU1 OFF + MPU OSWR */
|
|
.exit_latency = 460 + 518,
|
|
.exit_latency = 460 + 518,
|
|
.target_residency = 1100,
|
|
.target_residency = 1100,
|
|
- .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED |
|
|
|
|
- CPUIDLE_FLAG_TIMER_STOP,
|
|
|
|
|
|
+ .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED,
|
|
.enter = omap_enter_idle_coupled,
|
|
.enter = omap_enter_idle_coupled,
|
|
.name = "C3",
|
|
.name = "C3",
|
|
.desc = "CPUx OFF, MPUSS OSWR",
|
|
.desc = "CPUx OFF, MPUSS OSWR",
|
|
@@ -231,5 +245,8 @@ int __init omap4_idle_init(void)
|
|
if (!cpu_clkdm[0] || !cpu_clkdm[1])
|
|
if (!cpu_clkdm[0] || !cpu_clkdm[1])
|
|
return -ENODEV;
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
+ /* 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(&omap4_idle_driver, cpu_online_mask);
|
|
}
|
|
}
|