diff options
author | Tony Lindgren <tony@atomide.com> | 2012-02-17 18:12:36 -0500 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2012-02-17 18:12:36 -0500 |
commit | 4d68c05ce11f4cdf6a6392f3a18dc6a985b4d0c4 (patch) | |
tree | 72e500b97c4bdcb9631209f3121f42b05ae30fea /arch/arm/mach-omap2/pm34xx.c | |
parent | 40c0591f0a349ec074357e05c6ab1a3bc951807c (diff) | |
parent | 19bfb76ca32f8e4fa80746608ff4a77707f40520 (diff) |
Merge branch 'for_3.4/dt_base' of git://git.kernel.org/pub/scm/linux/kernel/git/bcousson/linux-omap-dt into dt
Diffstat (limited to 'arch/arm/mach-omap2/pm34xx.c')
-rw-r--r-- | arch/arm/mach-omap2/pm34xx.c | 158 |
1 files changed, 44 insertions, 114 deletions
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index fa637dfdda53..fc6987578920 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c | |||
@@ -28,7 +28,6 @@ | |||
28 | #include <linux/clk.h> | 28 | #include <linux/clk.h> |
29 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | #include <linux/console.h> | ||
32 | #include <trace/events/power.h> | 31 | #include <trace/events/power.h> |
33 | 32 | ||
34 | #include <asm/suspend.h> | 33 | #include <asm/suspend.h> |
@@ -36,7 +35,6 @@ | |||
36 | #include <plat/sram.h> | 35 | #include <plat/sram.h> |
37 | #include "clockdomain.h" | 36 | #include "clockdomain.h" |
38 | #include "powerdomain.h" | 37 | #include "powerdomain.h" |
39 | #include <plat/serial.h> | ||
40 | #include <plat/sdrc.h> | 38 | #include <plat/sdrc.h> |
41 | #include <plat/prcm.h> | 39 | #include <plat/prcm.h> |
42 | #include <plat/gpmc.h> | 40 | #include <plat/gpmc.h> |
@@ -54,15 +52,6 @@ | |||
54 | 52 | ||
55 | #ifdef CONFIG_SUSPEND | 53 | #ifdef CONFIG_SUSPEND |
56 | static suspend_state_t suspend_state = PM_SUSPEND_ON; | 54 | static suspend_state_t suspend_state = PM_SUSPEND_ON; |
57 | static inline bool is_suspending(void) | ||
58 | { | ||
59 | return (suspend_state != PM_SUSPEND_ON) && console_suspend_enabled; | ||
60 | } | ||
61 | #else | ||
62 | static inline bool is_suspending(void) | ||
63 | { | ||
64 | return false; | ||
65 | } | ||
66 | #endif | 55 | #endif |
67 | 56 | ||
68 | /* pm34xx errata defined in pm.h */ | 57 | /* pm34xx errata defined in pm.h */ |
@@ -195,7 +184,7 @@ static void omap3_save_secure_ram_context(void) | |||
195 | * that any peripheral wake-up events occurring while attempting to | 184 | * that any peripheral wake-up events occurring while attempting to |
196 | * clear the PM_WKST_x are detected and cleared. | 185 | * clear the PM_WKST_x are detected and cleared. |
197 | */ | 186 | */ |
198 | static int prcm_clear_mod_irqs(s16 module, u8 regs) | 187 | static int prcm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits) |
199 | { | 188 | { |
200 | u32 wkst, fclk, iclk, clken; | 189 | u32 wkst, fclk, iclk, clken; |
201 | u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1; | 190 | u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1; |
@@ -207,6 +196,7 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs) | |||
207 | 196 | ||
208 | wkst = omap2_prm_read_mod_reg(module, wkst_off); | 197 | wkst = omap2_prm_read_mod_reg(module, wkst_off); |
209 | wkst &= omap2_prm_read_mod_reg(module, grpsel_off); | 198 | wkst &= omap2_prm_read_mod_reg(module, grpsel_off); |
199 | wkst &= ~ignore_bits; | ||
210 | if (wkst) { | 200 | if (wkst) { |
211 | iclk = omap2_cm_read_mod_reg(module, iclk_off); | 201 | iclk = omap2_cm_read_mod_reg(module, iclk_off); |
212 | fclk = omap2_cm_read_mod_reg(module, fclk_off); | 202 | fclk = omap2_cm_read_mod_reg(module, fclk_off); |
@@ -222,6 +212,7 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs) | |||
222 | omap2_cm_set_mod_reg_bits(clken, module, fclk_off); | 212 | omap2_cm_set_mod_reg_bits(clken, module, fclk_off); |
223 | omap2_prm_write_mod_reg(wkst, module, wkst_off); | 213 | omap2_prm_write_mod_reg(wkst, module, wkst_off); |
224 | wkst = omap2_prm_read_mod_reg(module, wkst_off); | 214 | wkst = omap2_prm_read_mod_reg(module, wkst_off); |
215 | wkst &= ~ignore_bits; | ||
225 | c++; | 216 | c++; |
226 | } | 217 | } |
227 | omap2_cm_write_mod_reg(iclk, module, iclk_off); | 218 | omap2_cm_write_mod_reg(iclk, module, iclk_off); |
@@ -231,76 +222,35 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs) | |||
231 | return c; | 222 | return c; |
232 | } | 223 | } |
233 | 224 | ||
234 | static int _prcm_int_handle_wakeup(void) | 225 | static irqreturn_t _prcm_int_handle_io(int irq, void *unused) |
235 | { | 226 | { |
236 | int c; | 227 | int c; |
237 | 228 | ||
238 | c = prcm_clear_mod_irqs(WKUP_MOD, 1); | 229 | c = prcm_clear_mod_irqs(WKUP_MOD, 1, |
239 | c += prcm_clear_mod_irqs(CORE_MOD, 1); | 230 | ~(OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK)); |
240 | c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1); | ||
241 | if (omap_rev() > OMAP3430_REV_ES1_0) { | ||
242 | c += prcm_clear_mod_irqs(CORE_MOD, 3); | ||
243 | c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1); | ||
244 | } | ||
245 | 231 | ||
246 | return c; | 232 | return c ? IRQ_HANDLED : IRQ_NONE; |
247 | } | 233 | } |
248 | 234 | ||
249 | /* | 235 | static irqreturn_t _prcm_int_handle_wakeup(int irq, void *unused) |
250 | * PRCM Interrupt Handler | ||
251 | * | ||
252 | * The PRM_IRQSTATUS_MPU register indicates if there are any pending | ||
253 | * interrupts from the PRCM for the MPU. These bits must be cleared in | ||
254 | * order to clear the PRCM interrupt. The PRCM interrupt handler is | ||
255 | * implemented to simply clear the PRM_IRQSTATUS_MPU in order to clear | ||
256 | * the PRCM interrupt. Please note that bit 0 of the PRM_IRQSTATUS_MPU | ||
257 | * register indicates that a wake-up event is pending for the MPU and | ||
258 | * this bit can only be cleared if the all the wake-up events latched | ||
259 | * in the various PM_WKST_x registers have been cleared. The interrupt | ||
260 | * handler is implemented using a do-while loop so that if a wake-up | ||
261 | * event occurred during the processing of the prcm interrupt handler | ||
262 | * (setting a bit in the corresponding PM_WKST_x register and thus | ||
263 | * preventing us from clearing bit 0 of the PRM_IRQSTATUS_MPU register) | ||
264 | * this would be handled. | ||
265 | */ | ||
266 | static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id) | ||
267 | { | 236 | { |
268 | u32 irqenable_mpu, irqstatus_mpu; | 237 | int c; |
269 | int c = 0; | ||
270 | |||
271 | irqenable_mpu = omap2_prm_read_mod_reg(OCP_MOD, | ||
272 | OMAP3_PRM_IRQENABLE_MPU_OFFSET); | ||
273 | irqstatus_mpu = omap2_prm_read_mod_reg(OCP_MOD, | ||
274 | OMAP3_PRM_IRQSTATUS_MPU_OFFSET); | ||
275 | irqstatus_mpu &= irqenable_mpu; | ||
276 | |||
277 | do { | ||
278 | if (irqstatus_mpu & (OMAP3430_WKUP_ST_MASK | | ||
279 | OMAP3430_IO_ST_MASK)) { | ||
280 | c = _prcm_int_handle_wakeup(); | ||
281 | |||
282 | /* | ||
283 | * Is the MPU PRCM interrupt handler racing with the | ||
284 | * IVA2 PRCM interrupt handler ? | ||
285 | */ | ||
286 | WARN(c == 0, "prcm: WARNING: PRCM indicated MPU wakeup " | ||
287 | "but no wakeup sources are marked\n"); | ||
288 | } else { | ||
289 | /* XXX we need to expand our PRCM interrupt handler */ | ||
290 | WARN(1, "prcm: WARNING: PRCM interrupt received, but " | ||
291 | "no code to handle it (%08x)\n", irqstatus_mpu); | ||
292 | } | ||
293 | |||
294 | omap2_prm_write_mod_reg(irqstatus_mpu, OCP_MOD, | ||
295 | OMAP3_PRM_IRQSTATUS_MPU_OFFSET); | ||
296 | |||
297 | irqstatus_mpu = omap2_prm_read_mod_reg(OCP_MOD, | ||
298 | OMAP3_PRM_IRQSTATUS_MPU_OFFSET); | ||
299 | irqstatus_mpu &= irqenable_mpu; | ||
300 | 238 | ||
301 | } while (irqstatus_mpu); | 239 | /* |
240 | * Clear all except ST_IO and ST_IO_CHAIN for wkup module, | ||
241 | * these are handled in a separate handler to avoid acking | ||
242 | * IO events before parsing in mux code | ||
243 | */ | ||
244 | c = prcm_clear_mod_irqs(WKUP_MOD, 1, | ||
245 | OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK); | ||
246 | c += prcm_clear_mod_irqs(CORE_MOD, 1, 0); | ||
247 | c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1, 0); | ||
248 | if (omap_rev() > OMAP3430_REV_ES1_0) { | ||
249 | c += prcm_clear_mod_irqs(CORE_MOD, 3, 0); | ||
250 | c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1, 0); | ||
251 | } | ||
302 | 252 | ||
303 | return IRQ_HANDLED; | 253 | return c ? IRQ_HANDLED : IRQ_NONE; |
304 | } | 254 | } |
305 | 255 | ||
306 | static void omap34xx_save_context(u32 *save) | 256 | static void omap34xx_save_context(u32 *save) |
@@ -376,20 +326,11 @@ void omap_sram_idle(void) | |||
376 | omap3_enable_io_chain(); | 326 | omap3_enable_io_chain(); |
377 | } | 327 | } |
378 | 328 | ||
379 | /* Block console output in case it is on one of the OMAP UARTs */ | ||
380 | if (!is_suspending()) | ||
381 | if (per_next_state < PWRDM_POWER_ON || | ||
382 | core_next_state < PWRDM_POWER_ON) | ||
383 | if (!console_trylock()) | ||
384 | goto console_still_active; | ||
385 | |||
386 | pwrdm_pre_transition(); | 329 | pwrdm_pre_transition(); |
387 | 330 | ||
388 | /* PER */ | 331 | /* PER */ |
389 | if (per_next_state < PWRDM_POWER_ON) { | 332 | if (per_next_state < PWRDM_POWER_ON) { |
390 | per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0; | 333 | per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0; |
391 | omap_uart_prepare_idle(2); | ||
392 | omap_uart_prepare_idle(3); | ||
393 | omap2_gpio_prepare_for_idle(per_going_off); | 334 | omap2_gpio_prepare_for_idle(per_going_off); |
394 | if (per_next_state == PWRDM_POWER_OFF) | 335 | if (per_next_state == PWRDM_POWER_OFF) |
395 | omap3_per_save_context(); | 336 | omap3_per_save_context(); |
@@ -397,8 +338,6 @@ void omap_sram_idle(void) | |||
397 | 338 | ||
398 | /* CORE */ | 339 | /* CORE */ |
399 | if (core_next_state < PWRDM_POWER_ON) { | 340 | if (core_next_state < PWRDM_POWER_ON) { |
400 | omap_uart_prepare_idle(0); | ||
401 | omap_uart_prepare_idle(1); | ||
402 | if (core_next_state == PWRDM_POWER_OFF) { | 341 | if (core_next_state == PWRDM_POWER_OFF) { |
403 | omap3_core_save_context(); | 342 | omap3_core_save_context(); |
404 | omap3_cm_save_context(); | 343 | omap3_cm_save_context(); |
@@ -447,8 +386,6 @@ void omap_sram_idle(void) | |||
447 | omap3_sram_restore_context(); | 386 | omap3_sram_restore_context(); |
448 | omap2_sms_restore_context(); | 387 | omap2_sms_restore_context(); |
449 | } | 388 | } |
450 | omap_uart_resume_idle(0); | ||
451 | omap_uart_resume_idle(1); | ||
452 | if (core_next_state == PWRDM_POWER_OFF) | 389 | if (core_next_state == PWRDM_POWER_OFF) |
453 | omap2_prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF_MASK, | 390 | omap2_prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF_MASK, |
454 | OMAP3430_GR_MOD, | 391 | OMAP3430_GR_MOD, |
@@ -464,14 +401,8 @@ void omap_sram_idle(void) | |||
464 | omap2_gpio_resume_after_idle(); | 401 | omap2_gpio_resume_after_idle(); |
465 | if (per_prev_state == PWRDM_POWER_OFF) | 402 | if (per_prev_state == PWRDM_POWER_OFF) |
466 | omap3_per_restore_context(); | 403 | omap3_per_restore_context(); |
467 | omap_uart_resume_idle(2); | ||
468 | omap_uart_resume_idle(3); | ||
469 | } | 404 | } |
470 | 405 | ||
471 | if (!is_suspending()) | ||
472 | console_unlock(); | ||
473 | |||
474 | console_still_active: | ||
475 | /* Disable IO-PAD and IO-CHAIN wakeup */ | 406 | /* Disable IO-PAD and IO-CHAIN wakeup */ |
476 | if (omap3_has_io_wakeup() && | 407 | if (omap3_has_io_wakeup() && |
477 | (per_next_state < PWRDM_POWER_ON || | 408 | (per_next_state < PWRDM_POWER_ON || |
@@ -485,21 +416,11 @@ console_still_active: | |||
485 | clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]); | 416 | clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]); |
486 | } | 417 | } |
487 | 418 | ||
488 | int omap3_can_sleep(void) | ||
489 | { | ||
490 | if (!omap_uart_can_sleep()) | ||
491 | return 0; | ||
492 | return 1; | ||
493 | } | ||
494 | |||
495 | static void omap3_pm_idle(void) | 419 | static void omap3_pm_idle(void) |
496 | { | 420 | { |
497 | local_irq_disable(); | 421 | local_irq_disable(); |
498 | local_fiq_disable(); | 422 | local_fiq_disable(); |
499 | 423 | ||
500 | if (!omap3_can_sleep()) | ||
501 | goto out; | ||
502 | |||
503 | if (omap_irq_pending() || need_resched()) | 424 | if (omap_irq_pending() || need_resched()) |
504 | goto out; | 425 | goto out; |
505 | 426 | ||
@@ -533,7 +454,6 @@ static int omap3_pm_suspend(void) | |||
533 | goto restore; | 454 | goto restore; |
534 | } | 455 | } |
535 | 456 | ||
536 | omap_uart_prepare_suspend(); | ||
537 | omap3_intc_suspend(); | 457 | omap3_intc_suspend(); |
538 | 458 | ||
539 | omap_sram_idle(); | 459 | omap_sram_idle(); |
@@ -580,22 +500,27 @@ static int omap3_pm_begin(suspend_state_t state) | |||
580 | { | 500 | { |
581 | disable_hlt(); | 501 | disable_hlt(); |
582 | suspend_state = state; | 502 | suspend_state = state; |
583 | omap_uart_enable_irqs(0); | 503 | omap_prcm_irq_prepare(); |
584 | return 0; | 504 | return 0; |
585 | } | 505 | } |
586 | 506 | ||
587 | static void omap3_pm_end(void) | 507 | static void omap3_pm_end(void) |
588 | { | 508 | { |
589 | suspend_state = PM_SUSPEND_ON; | 509 | suspend_state = PM_SUSPEND_ON; |
590 | omap_uart_enable_irqs(1); | ||
591 | enable_hlt(); | 510 | enable_hlt(); |
592 | return; | 511 | return; |
593 | } | 512 | } |
594 | 513 | ||
514 | static void omap3_pm_finish(void) | ||
515 | { | ||
516 | omap_prcm_irq_complete(); | ||
517 | } | ||
518 | |||
595 | static const struct platform_suspend_ops omap_pm_ops = { | 519 | static const struct platform_suspend_ops omap_pm_ops = { |
596 | .begin = omap3_pm_begin, | 520 | .begin = omap3_pm_begin, |
597 | .end = omap3_pm_end, | 521 | .end = omap3_pm_end, |
598 | .enter = omap3_pm_enter, | 522 | .enter = omap3_pm_enter, |
523 | .finish = omap3_pm_finish, | ||
599 | .valid = suspend_valid_only_mem, | 524 | .valid = suspend_valid_only_mem, |
600 | }; | 525 | }; |
601 | #endif /* CONFIG_SUSPEND */ | 526 | #endif /* CONFIG_SUSPEND */ |
@@ -701,10 +626,6 @@ static void __init prcm_setup_regs(void) | |||
701 | OMAP3430_GRPSEL_GPT1_MASK | | 626 | OMAP3430_GRPSEL_GPT1_MASK | |
702 | OMAP3430_GRPSEL_GPT12_MASK, | 627 | OMAP3430_GRPSEL_GPT12_MASK, |
703 | WKUP_MOD, OMAP3430_PM_MPUGRPSEL); | 628 | WKUP_MOD, OMAP3430_PM_MPUGRPSEL); |
704 | /* For some reason IO doesn't generate wakeup event even if | ||
705 | * it is selected to mpu wakeup goup */ | ||
706 | omap2_prm_write_mod_reg(OMAP3430_IO_EN_MASK | OMAP3430_WKUP_EN_MASK, | ||
707 | OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET); | ||
708 | 629 | ||
709 | /* Enable PM_WKEN to support DSS LPR */ | 630 | /* Enable PM_WKEN to support DSS LPR */ |
710 | omap2_prm_write_mod_reg(OMAP3430_PM_WKEN_DSS_EN_DSS_MASK, | 631 | omap2_prm_write_mod_reg(OMAP3430_PM_WKEN_DSS_EN_DSS_MASK, |
@@ -881,12 +802,21 @@ static int __init omap3_pm_init(void) | |||
881 | * supervised mode for powerdomains */ | 802 | * supervised mode for powerdomains */ |
882 | prcm_setup_regs(); | 803 | prcm_setup_regs(); |
883 | 804 | ||
884 | ret = request_irq(INT_34XX_PRCM_MPU_IRQ, | 805 | ret = request_irq(omap_prcm_event_to_irq("wkup"), |
885 | (irq_handler_t)prcm_interrupt_handler, | 806 | _prcm_int_handle_wakeup, IRQF_NO_SUSPEND, "pm_wkup", NULL); |
886 | IRQF_DISABLED, "prcm", NULL); | 807 | |
808 | if (ret) { | ||
809 | pr_err("pm: Failed to request pm_wkup irq\n"); | ||
810 | goto err1; | ||
811 | } | ||
812 | |||
813 | /* IO interrupt is shared with mux code */ | ||
814 | ret = request_irq(omap_prcm_event_to_irq("io"), | ||
815 | _prcm_int_handle_io, IRQF_SHARED | IRQF_NO_SUSPEND, "pm_io", | ||
816 | omap3_pm_init); | ||
817 | |||
887 | if (ret) { | 818 | if (ret) { |
888 | printk(KERN_ERR "request_irq failed to register for 0x%x\n", | 819 | pr_err("pm: Failed to request pm_io irq\n"); |
889 | INT_34XX_PRCM_MPU_IRQ); | ||
890 | goto err1; | 820 | goto err1; |
891 | } | 821 | } |
892 | 822 | ||