diff options
Diffstat (limited to 'arch/arm/mach-omap2/cpuidle34xx.c')
-rw-r--r-- | arch/arm/mach-omap2/cpuidle34xx.c | 58 |
1 files changed, 54 insertions, 4 deletions
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 3d3d035db9af..0d50b45d041c 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c | |||
@@ -29,10 +29,10 @@ | |||
29 | #include <plat/irqs.h> | 29 | #include <plat/irqs.h> |
30 | #include <plat/powerdomain.h> | 30 | #include <plat/powerdomain.h> |
31 | #include <plat/clockdomain.h> | 31 | #include <plat/clockdomain.h> |
32 | #include <plat/control.h> | ||
33 | #include <plat/serial.h> | 32 | #include <plat/serial.h> |
34 | 33 | ||
35 | #include "pm.h" | 34 | #include "pm.h" |
35 | #include "control.h" | ||
36 | 36 | ||
37 | #ifdef CONFIG_CPU_IDLE | 37 | #ifdef CONFIG_CPU_IDLE |
38 | 38 | ||
@@ -60,7 +60,8 @@ struct omap3_processor_cx { | |||
60 | 60 | ||
61 | struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES]; | 61 | struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES]; |
62 | struct omap3_processor_cx current_cx_state; | 62 | struct omap3_processor_cx current_cx_state; |
63 | struct powerdomain *mpu_pd, *core_pd; | 63 | struct powerdomain *mpu_pd, *core_pd, *per_pd; |
64 | struct powerdomain *cam_pd; | ||
64 | 65 | ||
65 | /* | 66 | /* |
66 | * The latencies/thresholds for various C states have | 67 | * The latencies/thresholds for various C states have |
@@ -233,14 +234,60 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, | |||
233 | struct cpuidle_state *state) | 234 | struct cpuidle_state *state) |
234 | { | 235 | { |
235 | struct cpuidle_state *new_state = next_valid_state(dev, state); | 236 | struct cpuidle_state *new_state = next_valid_state(dev, state); |
237 | u32 core_next_state, per_next_state = 0, per_saved_state = 0; | ||
238 | u32 cam_state; | ||
239 | struct omap3_processor_cx *cx; | ||
240 | int ret; | ||
236 | 241 | ||
237 | if ((state->flags & CPUIDLE_FLAG_CHECK_BM) && omap3_idle_bm_check()) { | 242 | if ((state->flags & CPUIDLE_FLAG_CHECK_BM) && omap3_idle_bm_check()) { |
238 | BUG_ON(!dev->safe_state); | 243 | BUG_ON(!dev->safe_state); |
239 | new_state = dev->safe_state; | 244 | new_state = dev->safe_state; |
245 | goto select_state; | ||
240 | } | 246 | } |
241 | 247 | ||
248 | cx = cpuidle_get_statedata(state); | ||
249 | core_next_state = cx->core_state; | ||
250 | |||
251 | /* | ||
252 | * FIXME: we currently manage device-specific idle states | ||
253 | * for PER and CORE in combination with CPU-specific | ||
254 | * idle states. This is wrong, and device-specific | ||
255 | * idle managment needs to be separated out into | ||
256 | * its own code. | ||
257 | */ | ||
258 | |||
259 | /* | ||
260 | * Prevent idle completely if CAM is active. | ||
261 | * CAM does not have wakeup capability in OMAP3. | ||
262 | */ | ||
263 | cam_state = pwrdm_read_pwrst(cam_pd); | ||
264 | if (cam_state == PWRDM_POWER_ON) { | ||
265 | new_state = dev->safe_state; | ||
266 | goto select_state; | ||
267 | } | ||
268 | |||
269 | /* | ||
270 | * Prevent PER off if CORE is not in retention or off as this | ||
271 | * would disable PER wakeups completely. | ||
272 | */ | ||
273 | per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd); | ||
274 | if ((per_next_state == PWRDM_POWER_OFF) && | ||
275 | (core_next_state > PWRDM_POWER_RET)) | ||
276 | per_next_state = PWRDM_POWER_RET; | ||
277 | |||
278 | /* Are we changing PER target state? */ | ||
279 | if (per_next_state != per_saved_state) | ||
280 | pwrdm_set_next_pwrst(per_pd, per_next_state); | ||
281 | |||
282 | select_state: | ||
242 | dev->last_state = new_state; | 283 | dev->last_state = new_state; |
243 | return omap3_enter_idle(dev, new_state); | 284 | ret = omap3_enter_idle(dev, new_state); |
285 | |||
286 | /* Restore original PER state if it was modified */ | ||
287 | if (per_next_state != per_saved_state) | ||
288 | pwrdm_set_next_pwrst(per_pd, per_saved_state); | ||
289 | |||
290 | return ret; | ||
244 | } | 291 | } |
245 | 292 | ||
246 | DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev); | 293 | DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev); |
@@ -328,7 +375,8 @@ void omap_init_power_states(void) | |||
328 | cpuidle_params_table[OMAP3_STATE_C2].threshold; | 375 | cpuidle_params_table[OMAP3_STATE_C2].threshold; |
329 | omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_ON; | 376 | omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_ON; |
330 | omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_ON; | 377 | omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_ON; |
331 | omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID; | 378 | omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID | |
379 | CPUIDLE_FLAG_CHECK_BM; | ||
332 | 380 | ||
333 | /* C3 . MPU CSWR + Core inactive */ | 381 | /* C3 . MPU CSWR + Core inactive */ |
334 | omap3_power_states[OMAP3_STATE_C3].valid = | 382 | omap3_power_states[OMAP3_STATE_C3].valid = |
@@ -426,6 +474,8 @@ int __init omap3_idle_init(void) | |||
426 | 474 | ||
427 | mpu_pd = pwrdm_lookup("mpu_pwrdm"); | 475 | mpu_pd = pwrdm_lookup("mpu_pwrdm"); |
428 | core_pd = pwrdm_lookup("core_pwrdm"); | 476 | core_pd = pwrdm_lookup("core_pwrdm"); |
477 | per_pd = pwrdm_lookup("per_pwrdm"); | ||
478 | cam_pd = pwrdm_lookup("cam_pwrdm"); | ||
429 | 479 | ||
430 | omap_init_power_states(); | 480 | omap_init_power_states(); |
431 | cpuidle_register_driver(&omap3_idle_driver); | 481 | cpuidle_register_driver(&omap3_idle_driver); |