aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSantosh Shilimkar <santosh.shilimkar@ti.com>2016-11-07 18:50:11 -0500
committerTony Lindgren <tony@atomide.com>2016-11-07 18:52:14 -0500
commit7abdb0e23e7bc8da685da5a54eb9f2f67f922ef2 (patch)
tree6f647531e06874a5ff99054f4c96ff638cbf5076
parentcbf2642872333547b56b8c4d943f5ed04ac9a4ee (diff)
ARM: OMAP5: Add basic cpuidle MPU CSWR support
Add OMAP5 CPUIDLE support. This patch adds MPUSS low power states in cpuidle. C1 - CPU0 WFI + CPU1 WFI + MPU ON C2 - CPU0 RET + CPU1 RET + MPU CSWR Modified from TI kernel tree commit 605967fd2205 ("ARM: DRA7: PM: cpuidle MPU CSWR support") except enable cpuidle for omap5 instead of dra7. According to Nishanth Menon <nm@ti.com>, cpuidle on dra7 is not supported properly in the hardware so we don't want to enable it. However, for omap5 this adds some nice power savings. Note that the TI 3.8 based tree has other cpuidle states that we may be able to enable later on. On omap5-uevm, the power consumption eventually settles down to about 920mW with ehci-omap and ohci-omap3 unloaded compared to about 1.7W without these patches. Note that it seems to take few minutes after booting for the idle power to go down to 920mW from 1.3W, no idea so far what might be causing that. Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com> [ j-keerthy@ti.com rework on 3.14] Signed-off-by: Keerthy <j-keerthy@ti.com> [nm@ti.com: updates based on profiling] [tony@atomide.com: dropped CPUIDLE_FLAG_TIME_VALID no longer used, changed for omap5 only as requested by Nishanth, updated comments] Signed-off-by: Nishanth Menon <nm@ti.com> Signed-off-by: Tony Lindgren <tony@atomide.com>
-rw-r--r--arch/arm/mach-omap2/cpuidle44xx.c80
-rw-r--r--arch/arm/mach-omap2/pm44xx.c2
2 files changed, 80 insertions, 2 deletions
diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c
index fa138d4032b6..a8b291f00109 100644
--- a/arch/arm/mach-omap2/cpuidle44xx.c
+++ b/arch/arm/mach-omap2/cpuidle44xx.c
@@ -21,6 +21,7 @@
21#include "common.h" 21#include "common.h"
22#include "pm.h" 22#include "pm.h"
23#include "prm.h" 23#include "prm.h"
24#include "soc.h"
24#include "clockdomain.h" 25#include "clockdomain.h"
25 26
26#define MAX_CPUS 2 27#define MAX_CPUS 2
@@ -30,6 +31,7 @@ struct idle_statedata {
30 u32 cpu_state; 31 u32 cpu_state;
31 u32 mpu_logic_state; 32 u32 mpu_logic_state;
32 u32 mpu_state; 33 u32 mpu_state;
34 u32 mpu_state_vote;
33}; 35};
34 36
35static struct idle_statedata omap4_idle_data[] = { 37static struct idle_statedata omap4_idle_data[] = {
@@ -50,12 +52,26 @@ static struct idle_statedata omap4_idle_data[] = {
50 }, 52 },
51}; 53};
52 54
55static struct idle_statedata omap5_idle_data[] = {
56 {
57 .cpu_state = PWRDM_POWER_ON,
58 .mpu_state = PWRDM_POWER_ON,
59 .mpu_logic_state = PWRDM_POWER_ON,
60 },
61 {
62 .cpu_state = PWRDM_POWER_RET,
63 .mpu_state = PWRDM_POWER_RET,
64 .mpu_logic_state = PWRDM_POWER_RET,
65 },
66};
67
53static struct powerdomain *mpu_pd, *cpu_pd[MAX_CPUS]; 68static struct powerdomain *mpu_pd, *cpu_pd[MAX_CPUS];
54static struct clockdomain *cpu_clkdm[MAX_CPUS]; 69static struct clockdomain *cpu_clkdm[MAX_CPUS];
55 70
56static atomic_t abort_barrier; 71static atomic_t abort_barrier;
57static bool cpu_done[MAX_CPUS]; 72static bool cpu_done[MAX_CPUS];
58static struct idle_statedata *state_ptr = &omap4_idle_data[0]; 73static struct idle_statedata *state_ptr = &omap4_idle_data[0];
74static DEFINE_RAW_SPINLOCK(mpu_lock);
59 75
60/* Private functions */ 76/* Private functions */
61 77
@@ -77,6 +93,32 @@ static int omap_enter_idle_simple(struct cpuidle_device *dev,
77 return index; 93 return index;
78} 94}
79 95
96static int omap_enter_idle_smp(struct cpuidle_device *dev,
97 struct cpuidle_driver *drv,
98 int index)
99{
100 struct idle_statedata *cx = state_ptr + index;
101 unsigned long flag;
102
103 raw_spin_lock_irqsave(&mpu_lock, flag);
104 cx->mpu_state_vote++;
105 if (cx->mpu_state_vote == num_online_cpus()) {
106 pwrdm_set_logic_retst(mpu_pd, cx->mpu_logic_state);
107 omap_set_pwrdm_state(mpu_pd, cx->mpu_state);
108 }
109 raw_spin_unlock_irqrestore(&mpu_lock, flag);
110
111 omap4_enter_lowpower(dev->cpu, cx->cpu_state);
112
113 raw_spin_lock_irqsave(&mpu_lock, flag);
114 if (cx->mpu_state_vote == num_online_cpus())
115 omap_set_pwrdm_state(mpu_pd, PWRDM_POWER_ON);
116 cx->mpu_state_vote--;
117 raw_spin_unlock_irqrestore(&mpu_lock, flag);
118
119 return index;
120}
121
80static int omap_enter_idle_coupled(struct cpuidle_device *dev, 122static int omap_enter_idle_coupled(struct cpuidle_device *dev,
81 struct cpuidle_driver *drv, 123 struct cpuidle_driver *drv,
82 int index) 124 int index)
@@ -220,6 +262,32 @@ static struct cpuidle_driver omap4_idle_driver = {
220 .safe_state_index = 0, 262 .safe_state_index = 0,
221}; 263};
222 264
265static struct cpuidle_driver omap5_idle_driver = {
266 .name = "omap5_idle",
267 .owner = THIS_MODULE,
268 .states = {
269 {
270 /* C1 - CPU0 ON + CPU1 ON + MPU ON */
271 .exit_latency = 2 + 2,
272 .target_residency = 5,
273 .enter = omap_enter_idle_simple,
274 .name = "C1",
275 .desc = "CPUx WFI, MPUSS ON"
276 },
277 {
278 /* C2 - CPU0 RET + CPU1 RET + MPU CSWR */
279 .exit_latency = 48 + 60,
280 .target_residency = 100,
281 .flags = CPUIDLE_FLAG_TIMER_STOP,
282 .enter = omap_enter_idle_smp,
283 .name = "C2",
284 .desc = "CPUx CSWR, MPUSS CSWR",
285 },
286 },
287 .state_count = ARRAY_SIZE(omap5_idle_data),
288 .safe_state_index = 0,
289};
290
223/* Public functions */ 291/* Public functions */
224 292
225/** 293/**
@@ -230,6 +298,16 @@ static struct cpuidle_driver omap4_idle_driver = {
230 */ 298 */
231int __init omap4_idle_init(void) 299int __init omap4_idle_init(void)
232{ 300{
301 struct cpuidle_driver *idle_driver;
302
303 if (soc_is_omap54xx()) {
304 state_ptr = &omap5_idle_data[0];
305 idle_driver = &omap5_idle_driver;
306 } else {
307 state_ptr = &omap4_idle_data[0];
308 idle_driver = &omap4_idle_driver;
309 }
310
233 mpu_pd = pwrdm_lookup("mpu_pwrdm"); 311 mpu_pd = pwrdm_lookup("mpu_pwrdm");
234 cpu_pd[0] = pwrdm_lookup("cpu0_pwrdm"); 312 cpu_pd[0] = pwrdm_lookup("cpu0_pwrdm");
235 cpu_pd[1] = pwrdm_lookup("cpu1_pwrdm"); 313 cpu_pd[1] = pwrdm_lookup("cpu1_pwrdm");
@@ -244,5 +322,5 @@ int __init omap4_idle_init(void)
244 /* Configure the broadcast timer on each cpu */ 322 /* Configure the broadcast timer on each cpu */
245 on_each_cpu(omap_setup_broadcast_timer, NULL, 1); 323 on_each_cpu(omap_setup_broadcast_timer, NULL, 1);
246 324
247 return cpuidle_register(&omap4_idle_driver, cpu_online_mask); 325 return cpuidle_register(idle_driver, cpu_online_mask);
248} 326}
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index 178e22c146b7..b3870220612e 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -287,7 +287,7 @@ int __init omap4_pm_init(void)
287 /* Overwrite the default cpu_do_idle() */ 287 /* Overwrite the default cpu_do_idle() */
288 arm_pm_idle = omap_default_idle; 288 arm_pm_idle = omap_default_idle;
289 289
290 if (cpu_is_omap44xx()) 290 if (cpu_is_omap44xx() || soc_is_omap54xx())
291 omap4_idle_init(); 291 omap4_idle_init();
292 292
293err2: 293err2: