diff options
-rw-r--r-- | arch/arm/mach-omap2/pm34xx.c | 115 | ||||
-rw-r--r-- | arch/arm/mach-omap2/prm2xxx_3xxx.c | 26 |
2 files changed, 70 insertions, 71 deletions
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index efa66494c1e3..ba1692e0a5f4 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c | |||
@@ -194,7 +194,7 @@ static void omap3_save_secure_ram_context(void) | |||
194 | * that any peripheral wake-up events occurring while attempting to | 194 | * that any peripheral wake-up events occurring while attempting to |
195 | * clear the PM_WKST_x are detected and cleared. | 195 | * clear the PM_WKST_x are detected and cleared. |
196 | */ | 196 | */ |
197 | static int prcm_clear_mod_irqs(s16 module, u8 regs) | 197 | static int prcm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits) |
198 | { | 198 | { |
199 | u32 wkst, fclk, iclk, clken; | 199 | u32 wkst, fclk, iclk, clken; |
200 | u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1; | 200 | u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1; |
@@ -206,6 +206,7 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs) | |||
206 | 206 | ||
207 | wkst = omap2_prm_read_mod_reg(module, wkst_off); | 207 | wkst = omap2_prm_read_mod_reg(module, wkst_off); |
208 | wkst &= omap2_prm_read_mod_reg(module, grpsel_off); | 208 | wkst &= omap2_prm_read_mod_reg(module, grpsel_off); |
209 | wkst &= ~ignore_bits; | ||
209 | if (wkst) { | 210 | if (wkst) { |
210 | iclk = omap2_cm_read_mod_reg(module, iclk_off); | 211 | iclk = omap2_cm_read_mod_reg(module, iclk_off); |
211 | fclk = omap2_cm_read_mod_reg(module, fclk_off); | 212 | fclk = omap2_cm_read_mod_reg(module, fclk_off); |
@@ -221,6 +222,7 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs) | |||
221 | omap2_cm_set_mod_reg_bits(clken, module, fclk_off); | 222 | omap2_cm_set_mod_reg_bits(clken, module, fclk_off); |
222 | omap2_prm_write_mod_reg(wkst, module, wkst_off); | 223 | omap2_prm_write_mod_reg(wkst, module, wkst_off); |
223 | wkst = omap2_prm_read_mod_reg(module, wkst_off); | 224 | wkst = omap2_prm_read_mod_reg(module, wkst_off); |
225 | wkst &= ~ignore_bits; | ||
224 | c++; | 226 | c++; |
225 | } | 227 | } |
226 | omap2_cm_write_mod_reg(iclk, module, iclk_off); | 228 | omap2_cm_write_mod_reg(iclk, module, iclk_off); |
@@ -230,76 +232,35 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs) | |||
230 | return c; | 232 | return c; |
231 | } | 233 | } |
232 | 234 | ||
233 | static int _prcm_int_handle_wakeup(void) | 235 | static irqreturn_t _prcm_int_handle_io(int irq, void *unused) |
234 | { | 236 | { |
235 | int c; | 237 | int c; |
236 | 238 | ||
237 | c = prcm_clear_mod_irqs(WKUP_MOD, 1); | 239 | c = prcm_clear_mod_irqs(WKUP_MOD, 1, |
238 | c += prcm_clear_mod_irqs(CORE_MOD, 1); | 240 | ~(OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK)); |
239 | c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1); | ||
240 | if (omap_rev() > OMAP3430_REV_ES1_0) { | ||
241 | c += prcm_clear_mod_irqs(CORE_MOD, 3); | ||
242 | c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1); | ||
243 | } | ||
244 | 241 | ||
245 | return c; | 242 | return c ? IRQ_HANDLED : IRQ_NONE; |
246 | } | 243 | } |
247 | 244 | ||
248 | /* | 245 | static irqreturn_t _prcm_int_handle_wakeup(int irq, void *unused) |
249 | * PRCM Interrupt Handler | ||
250 | * | ||
251 | * The PRM_IRQSTATUS_MPU register indicates if there are any pending | ||
252 | * interrupts from the PRCM for the MPU. These bits must be cleared in | ||
253 | * order to clear the PRCM interrupt. The PRCM interrupt handler is | ||
254 | * implemented to simply clear the PRM_IRQSTATUS_MPU in order to clear | ||
255 | * the PRCM interrupt. Please note that bit 0 of the PRM_IRQSTATUS_MPU | ||
256 | * register indicates that a wake-up event is pending for the MPU and | ||
257 | * this bit can only be cleared if the all the wake-up events latched | ||
258 | * in the various PM_WKST_x registers have been cleared. The interrupt | ||
259 | * handler is implemented using a do-while loop so that if a wake-up | ||
260 | * event occurred during the processing of the prcm interrupt handler | ||
261 | * (setting a bit in the corresponding PM_WKST_x register and thus | ||
262 | * preventing us from clearing bit 0 of the PRM_IRQSTATUS_MPU register) | ||
263 | * this would be handled. | ||
264 | */ | ||
265 | static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id) | ||
266 | { | 246 | { |
267 | u32 irqenable_mpu, irqstatus_mpu; | 247 | int c; |
268 | int c = 0; | ||
269 | |||
270 | irqenable_mpu = omap2_prm_read_mod_reg(OCP_MOD, | ||
271 | OMAP3_PRM_IRQENABLE_MPU_OFFSET); | ||
272 | irqstatus_mpu = omap2_prm_read_mod_reg(OCP_MOD, | ||
273 | OMAP3_PRM_IRQSTATUS_MPU_OFFSET); | ||
274 | irqstatus_mpu &= irqenable_mpu; | ||
275 | |||
276 | do { | ||
277 | if (irqstatus_mpu & (OMAP3430_WKUP_ST_MASK | | ||
278 | OMAP3430_IO_ST_MASK)) { | ||
279 | c = _prcm_int_handle_wakeup(); | ||
280 | |||
281 | /* | ||
282 | * Is the MPU PRCM interrupt handler racing with the | ||
283 | * IVA2 PRCM interrupt handler ? | ||
284 | */ | ||
285 | WARN(c == 0, "prcm: WARNING: PRCM indicated MPU wakeup " | ||
286 | "but no wakeup sources are marked\n"); | ||
287 | } else { | ||
288 | /* XXX we need to expand our PRCM interrupt handler */ | ||
289 | WARN(1, "prcm: WARNING: PRCM interrupt received, but " | ||
290 | "no code to handle it (%08x)\n", irqstatus_mpu); | ||
291 | } | ||
292 | |||
293 | omap2_prm_write_mod_reg(irqstatus_mpu, OCP_MOD, | ||
294 | OMAP3_PRM_IRQSTATUS_MPU_OFFSET); | ||
295 | |||
296 | irqstatus_mpu = omap2_prm_read_mod_reg(OCP_MOD, | ||
297 | OMAP3_PRM_IRQSTATUS_MPU_OFFSET); | ||
298 | irqstatus_mpu &= irqenable_mpu; | ||
299 | 248 | ||
300 | } while (irqstatus_mpu); | 249 | /* |
250 | * Clear all except ST_IO and ST_IO_CHAIN for wkup module, | ||
251 | * these are handled in a separate handler to avoid acking | ||
252 | * IO events before parsing in mux code | ||
253 | */ | ||
254 | c = prcm_clear_mod_irqs(WKUP_MOD, 1, | ||
255 | OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK); | ||
256 | c += prcm_clear_mod_irqs(CORE_MOD, 1, 0); | ||
257 | c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1, 0); | ||
258 | if (omap_rev() > OMAP3430_REV_ES1_0) { | ||
259 | c += prcm_clear_mod_irqs(CORE_MOD, 3, 0); | ||
260 | c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1, 0); | ||
261 | } | ||
301 | 262 | ||
302 | return IRQ_HANDLED; | 263 | return c ? IRQ_HANDLED : IRQ_NONE; |
303 | } | 264 | } |
304 | 265 | ||
305 | static void omap34xx_save_context(u32 *save) | 266 | static void omap34xx_save_context(u32 *save) |
@@ -580,6 +541,7 @@ static int omap3_pm_begin(suspend_state_t state) | |||
580 | disable_hlt(); | 541 | disable_hlt(); |
581 | suspend_state = state; | 542 | suspend_state = state; |
582 | omap_uart_enable_irqs(0); | 543 | omap_uart_enable_irqs(0); |
544 | omap_prcm_irq_prepare(); | ||
583 | return 0; | 545 | return 0; |
584 | } | 546 | } |
585 | 547 | ||
@@ -591,10 +553,16 @@ static void omap3_pm_end(void) | |||
591 | return; | 553 | return; |
592 | } | 554 | } |
593 | 555 | ||
556 | static void omap3_pm_finish(void) | ||
557 | { | ||
558 | omap_prcm_irq_complete(); | ||
559 | } | ||
560 | |||
594 | static const struct platform_suspend_ops omap_pm_ops = { | 561 | static const struct platform_suspend_ops omap_pm_ops = { |
595 | .begin = omap3_pm_begin, | 562 | .begin = omap3_pm_begin, |
596 | .end = omap3_pm_end, | 563 | .end = omap3_pm_end, |
597 | .enter = omap3_pm_enter, | 564 | .enter = omap3_pm_enter, |
565 | .finish = omap3_pm_finish, | ||
598 | .valid = suspend_valid_only_mem, | 566 | .valid = suspend_valid_only_mem, |
599 | }; | 567 | }; |
600 | #endif /* CONFIG_SUSPEND */ | 568 | #endif /* CONFIG_SUSPEND */ |
@@ -700,10 +668,6 @@ static void __init prcm_setup_regs(void) | |||
700 | OMAP3430_GRPSEL_GPT1_MASK | | 668 | OMAP3430_GRPSEL_GPT1_MASK | |
701 | OMAP3430_GRPSEL_GPT12_MASK, | 669 | OMAP3430_GRPSEL_GPT12_MASK, |
702 | WKUP_MOD, OMAP3430_PM_MPUGRPSEL); | 670 | WKUP_MOD, OMAP3430_PM_MPUGRPSEL); |
703 | /* For some reason IO doesn't generate wakeup event even if | ||
704 | * it is selected to mpu wakeup goup */ | ||
705 | omap2_prm_write_mod_reg(OMAP3430_IO_EN_MASK | OMAP3430_WKUP_EN_MASK, | ||
706 | OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET); | ||
707 | 671 | ||
708 | /* Enable PM_WKEN to support DSS LPR */ | 672 | /* Enable PM_WKEN to support DSS LPR */ |
709 | omap2_prm_write_mod_reg(OMAP3430_PM_WKEN_DSS_EN_DSS_MASK, | 673 | omap2_prm_write_mod_reg(OMAP3430_PM_WKEN_DSS_EN_DSS_MASK, |
@@ -880,12 +844,21 @@ static int __init omap3_pm_init(void) | |||
880 | * supervised mode for powerdomains */ | 844 | * supervised mode for powerdomains */ |
881 | prcm_setup_regs(); | 845 | prcm_setup_regs(); |
882 | 846 | ||
883 | ret = request_irq(INT_34XX_PRCM_MPU_IRQ, | 847 | ret = request_irq(omap_prcm_event_to_irq("wkup"), |
884 | (irq_handler_t)prcm_interrupt_handler, | 848 | _prcm_int_handle_wakeup, IRQF_NO_SUSPEND, "pm_wkup", NULL); |
885 | IRQF_DISABLED, "prcm", NULL); | 849 | |
850 | if (ret) { | ||
851 | pr_err("pm: Failed to request pm_wkup irq\n"); | ||
852 | goto err1; | ||
853 | } | ||
854 | |||
855 | /* IO interrupt is shared with mux code */ | ||
856 | ret = request_irq(omap_prcm_event_to_irq("io"), | ||
857 | _prcm_int_handle_io, IRQF_SHARED | IRQF_NO_SUSPEND, "pm_io", | ||
858 | omap3_pm_init); | ||
859 | |||
886 | if (ret) { | 860 | if (ret) { |
887 | printk(KERN_ERR "request_irq failed to register for 0x%x\n", | 861 | pr_err("pm: Failed to request pm_io irq\n"); |
888 | INT_34XX_PRCM_MPU_IRQ); | ||
889 | goto err1; | 862 | goto err1; |
890 | } | 863 | } |
891 | 864 | ||
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c index 58d9ce70e792..3545c9a6056f 100644 --- a/arch/arm/mach-omap2/prm2xxx_3xxx.c +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c | |||
@@ -27,6 +27,24 @@ | |||
27 | #include "prm-regbits-24xx.h" | 27 | #include "prm-regbits-24xx.h" |
28 | #include "prm-regbits-34xx.h" | 28 | #include "prm-regbits-34xx.h" |
29 | 29 | ||
30 | static const struct omap_prcm_irq omap3_prcm_irqs[] = { | ||
31 | OMAP_PRCM_IRQ("wkup", 0, 0), | ||
32 | OMAP_PRCM_IRQ("io", 9, 1), | ||
33 | }; | ||
34 | |||
35 | static struct omap_prcm_irq_setup omap3_prcm_irq_setup = { | ||
36 | .ack = OMAP3_PRM_IRQSTATUS_MPU_OFFSET, | ||
37 | .mask = OMAP3_PRM_IRQENABLE_MPU_OFFSET, | ||
38 | .nr_regs = 1, | ||
39 | .irqs = omap3_prcm_irqs, | ||
40 | .nr_irqs = ARRAY_SIZE(omap3_prcm_irqs), | ||
41 | .irq = INT_34XX_PRCM_MPU_IRQ, | ||
42 | .read_pending_irqs = &omap3xxx_prm_read_pending_irqs, | ||
43 | .ocp_barrier = &omap3xxx_prm_ocp_barrier, | ||
44 | .save_and_clear_irqen = &omap3xxx_prm_save_and_clear_irqen, | ||
45 | .restore_irqen = &omap3xxx_prm_restore_irqen, | ||
46 | }; | ||
47 | |||
30 | u32 omap2_prm_read_mod_reg(s16 module, u16 idx) | 48 | u32 omap2_prm_read_mod_reg(s16 module, u16 idx) |
31 | { | 49 | { |
32 | return __raw_readl(prm_base + module + idx); | 50 | return __raw_readl(prm_base + module + idx); |
@@ -281,3 +299,11 @@ void omap3xxx_prm_restore_irqen(u32 *saved_mask) | |||
281 | omap2_prm_write_mod_reg(saved_mask[0], OCP_MOD, | 299 | omap2_prm_write_mod_reg(saved_mask[0], OCP_MOD, |
282 | OMAP3_PRM_IRQENABLE_MPU_OFFSET); | 300 | OMAP3_PRM_IRQENABLE_MPU_OFFSET); |
283 | } | 301 | } |
302 | |||
303 | static int __init omap3xxx_prcm_init(void) | ||
304 | { | ||
305 | if (cpu_is_omap34xx()) | ||
306 | return omap_prcm_register_chain_handler(&omap3_prcm_irq_setup); | ||
307 | return 0; | ||
308 | } | ||
309 | subsys_initcall(omap3xxx_prcm_init); | ||