aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/pm34xx.c
diff options
context:
space:
mode:
authorTony Lindgren <tony@atomide.com>2012-02-17 18:12:36 -0500
committerTony Lindgren <tony@atomide.com>2012-02-17 18:12:36 -0500
commit4d68c05ce11f4cdf6a6392f3a18dc6a985b4d0c4 (patch)
tree72e500b97c4bdcb9631209f3121f42b05ae30fea /arch/arm/mach-omap2/pm34xx.c
parent40c0591f0a349ec074357e05c6ab1a3bc951807c (diff)
parent19bfb76ca32f8e4fa80746608ff4a77707f40520 (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.c158
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
56static suspend_state_t suspend_state = PM_SUSPEND_ON; 54static suspend_state_t suspend_state = PM_SUSPEND_ON;
57static inline bool is_suspending(void)
58{
59 return (suspend_state != PM_SUSPEND_ON) && console_suspend_enabled;
60}
61#else
62static 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 */
198static int prcm_clear_mod_irqs(s16 module, u8 regs) 187static 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
234static int _prcm_int_handle_wakeup(void) 225static 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/* 235static 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 */
266static 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
306static void omap34xx_save_context(u32 *save) 256static 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
474console_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
488int omap3_can_sleep(void)
489{
490 if (!omap_uart_can_sleep())
491 return 0;
492 return 1;
493}
494
495static void omap3_pm_idle(void) 419static 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
587static void omap3_pm_end(void) 507static 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
514static void omap3_pm_finish(void)
515{
516 omap_prcm_irq_complete();
517}
518
595static const struct platform_suspend_ops omap_pm_ops = { 519static 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