aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/pm34xx.c
diff options
context:
space:
mode:
authorTero Kristo <t-kristo@ti.com>2011-12-16 16:36:59 -0500
committerPaul Walmsley <paul@pwsan.com>2011-12-16 16:36:59 -0500
commit22f51371f8c35869ed850f46aa76b6cc2b502110 (patch)
tree4987812d4953514e710b7a2ab7711bf338c8eaee /arch/arm/mach-omap2/pm34xx.c
parentabc2d5456334d548328978d0b0d22c0e5d44cdcd (diff)
ARM: OMAP3: pm: use prcm chain handler
PM interrupt handling is now done through the PRCM chain handler. The interrupt handling logic is also split in two parts, to serve IO and WKUP events separately. This allows us to handle IO chain events in a clean way. Core event code is also changed in accordance to this, as PRCM interrupt handling is done by independent handlers, and the core handler should not clear the IO events anymore. Signed-off-by: Tero Kristo <t-kristo@ti.com> Tested-by: Kevin Hilman <khilman@ti.com> Reviewed-by: Kevin Hilman <khilman@ti.com> [paul@pwsan.com: use pr_err(); combined with portions of earlier patches and the "do not enable PRCM MPU interrupts manually" patch] Signed-off-by: Paul Walmsley <paul@pwsan.com>
Diffstat (limited to 'arch/arm/mach-omap2/pm34xx.c')
-rw-r--r--arch/arm/mach-omap2/pm34xx.c115
1 files changed, 44 insertions, 71 deletions
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index efa66494c1e..ba1692e0a5f 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