aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-omap2/pm34xx.c115
-rw-r--r--arch/arm/mach-omap2/prm2xxx_3xxx.c26
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 */
197static int prcm_clear_mod_irqs(s16 module, u8 regs) 197static 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
233static int _prcm_int_handle_wakeup(void) 235static 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/* 245static 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 */
265static 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
305static void omap34xx_save_context(u32 *save) 266static 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
556static void omap3_pm_finish(void)
557{
558 omap_prcm_irq_complete();
559}
560
594static const struct platform_suspend_ops omap_pm_ops = { 561static 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
30static const struct omap_prcm_irq omap3_prcm_irqs[] = {
31 OMAP_PRCM_IRQ("wkup", 0, 0),
32 OMAP_PRCM_IRQ("io", 9, 1),
33};
34
35static 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
30u32 omap2_prm_read_mod_reg(s16 module, u16 idx) 48u32 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
303static 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}
309subsys_initcall(omap3xxx_prcm_init);