From 9a5f019b1a9ea6a75ba36d7c312ff069006ed479 Mon Sep 17 00:00:00 2001 From: Eric Hustvedt Date: Tue, 20 Jun 2006 14:36:41 -0400 Subject: intelfb: add vsync interrupt support [02/05] intelfb: Add interrupt related register definitions Add constants for accessing HWSTAM, IER, IIR, and IMR registers. Add constants for interrupt types supported by the 8xx and 9xx chipsets. The registers are also stored in the hwstate struct and dumped in the debug routine. Signed-off-by: Eric Hustvedt --- drivers/video/intelfb/intelfbhw.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/video/intelfb/intelfbhw.c') diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index 7533b3dd08a..05aded669cd 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -587,6 +587,11 @@ intelfbhw_read_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, hw->fw_blc_0 = INREG(FW_BLC_0); hw->fw_blc_1 = INREG(FW_BLC_1); + hw->hwstam = INREG16(HWSTAM); + hw->ier = INREG16(IER); + hw->iir = INREG16(IIR); + hw->imr = INREG16(IMR); + return 0; } @@ -796,6 +801,10 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw) printk(" FW_BLC_0 0x%08x\n", hw->fw_blc_0); printk(" FW_BLC_1 0x%08x\n", hw->fw_blc_1); + printk(" HWSTAM 0x%04x\n", hw->hwstam); + printk(" IER 0x%04x\n", hw->ier); + printk(" IIR 0x%04x\n", hw->iir); + printk(" IMR 0x%04x\n", hw->imr); printk("hw state dump end\n"); #endif } -- cgit v1.2.3 From 7649757bd900bc900adcd95ab08903cdc28342fa Mon Sep 17 00:00:00 2001 From: Eric Hustvedt Date: Tue, 20 Jun 2006 14:36:41 -0400 Subject: intelfb: add vsync interrupt support [03/05] intelfb: Implement basic interrupt handling Functions have been added to enable and disable interrupts using the MMIO registers. Currently only pipe A vsync interrupts are enabled. A generalized vsync accounting struct is defined, with the intent that it can encapsulate per-pipe vsync related info in the future. Currently a single instance is hard-coded. The interrupt service routine currently only looks for vsync interrupts on pipe A, and increments a counter and wakes up anyone waiting on it. This implementation is heavily influenced by similar implementations in the atyfb and matroxfb drivers. Signed-off-by: Eric Hustvedt --- drivers/video/intelfb/intelfbhw.c | 76 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) (limited to 'drivers/video/intelfb/intelfbhw.c') diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index 05aded669cd..1a698a7230e 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -1943,3 +1944,78 @@ intelfbhw_cursor_reset(struct intelfb_info *dinfo) { addr += 16; } } + +static irqreturn_t +intelfbhw_irq(int irq, void *dev_id, struct pt_regs *fp) { + int handled = 0; + u16 tmp; + struct intelfb_info *dinfo = (struct intelfb_info *)dev_id; + + spin_lock(&dinfo->int_lock); + + tmp = INREG16(IIR); + tmp &= VSYNC_PIPE_A_INTERRUPT; + + if (tmp == 0) { + spin_unlock(&dinfo->int_lock); + return IRQ_RETVAL(handled); + } + + OUTREG16(IIR, tmp); + + if (tmp & VSYNC_PIPE_A_INTERRUPT) { + dinfo->vsync.count++; + wake_up_interruptible(&dinfo->vsync.wait); + handled = 1; + } + + spin_unlock(&dinfo->int_lock); + + return IRQ_RETVAL(handled); +} + +int +intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable) { + + if (!test_and_set_bit(0, &dinfo->irq_flags)) { + if (request_irq(dinfo->pdev->irq, intelfbhw_irq, SA_SHIRQ, "intelfb", dinfo)) { + clear_bit(0, &dinfo->irq_flags); + return -EINVAL; + } + + spin_lock_irq(&dinfo->int_lock); + OUTREG16(HWSTAM, 0xfffe); + OUTREG16(IMR, 0x0); + OUTREG16(IER, VSYNC_PIPE_A_INTERRUPT); + spin_unlock_irq(&dinfo->int_lock); + } else if (reenable) { + u16 ier; + + spin_lock_irq(&dinfo->int_lock); + ier = INREG16(IER); + if ((ier & VSYNC_PIPE_A_INTERRUPT)) { + DBG_MSG("someone disabled the IRQ [%08X]\n", ier); + OUTREG(IER, VSYNC_PIPE_A_INTERRUPT); + } + spin_unlock_irq(&dinfo->int_lock); + } + return 0; +} + +void +intelfbhw_disable_irq(struct intelfb_info *dinfo) { + u16 tmp; + + if (test_and_clear_bit(0, &dinfo->irq_flags)) { + spin_lock_irq(&dinfo->int_lock); + OUTREG16(HWSTAM, 0xffff); + OUTREG16(IMR, 0xffff); + OUTREG16(IER, 0x0); + + tmp = INREG16(IIR); + OUTREG16(IIR, tmp); + spin_unlock_irq(&dinfo->int_lock); + + free_irq(dinfo->pdev->irq, dinfo); + } +} -- cgit v1.2.3 From 37bced38b3d09c3de7c871790eddde81a3ce57cb Mon Sep 17 00:00:00 2001 From: Eric Hustvedt Date: Tue, 20 Jun 2006 14:36:42 -0400 Subject: intelfb: add vsync interrupt support [04/05] intelfb: implement FBIO_WAITFORVSYNC ioctl The (unofficial) FBIO_WAITFORVSYNC ioctl is implemented by sleeping on the appropriate waitqueue, as defined in my earlier patch. Currently, only display 0 (aka pipe A) is supported. Signed-off-by: Eric Hustvedt --- drivers/video/intelfb/intelfbhw.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'drivers/video/intelfb/intelfbhw.c') diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index 1a698a7230e..0f9631c2ad3 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -2019,3 +2019,36 @@ intelfbhw_disable_irq(struct intelfb_info *dinfo) { free_irq(dinfo->pdev->irq, dinfo); } } + +int +intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe) { + struct intelfb_vsync *vsync; + unsigned int count; + int ret; + + switch (pipe) { + case 0: + vsync = &dinfo->vsync; + break; + default: + return -ENODEV; + } + + ret = intelfbhw_enable_irq(dinfo, 0); + if (ret) { + return ret; + } + + count = vsync->count; + ret = wait_event_interruptible_timeout(vsync->wait, count != vsync->count, HZ/10); + if (ret < 0) { + return ret; + } + if (ret == 0) { + intelfbhw_enable_irq(dinfo, 1); + DBG_MSG("wait_for_vsync timed out!\n"); + return -ETIMEDOUT; + } + + return 0; +} -- cgit v1.2.3 From f80d0d23f2010b7682e06449345e8199a2b2619c Mon Sep 17 00:00:00 2001 From: Eric Hustvedt Date: Tue, 20 Jun 2006 14:36:42 -0400 Subject: intelfb: add vsync interrupt support [05/05] intelfb: Honor FB_ACTIVATE_VBL for display panning Extends the intelfb_vsync struct to store panning offset. The interrupt service routine uses the stored panning offset if a pan is requested for the vsync. intelfbhw_disable_irq also pans the display if there is a pending request. Signed-off-by: Eric Hustvedt --- drivers/video/intelfb/intelfbhw.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers/video/intelfb/intelfbhw.c') diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index 0f9631c2ad3..8038f558611 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -371,7 +371,13 @@ intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) offset += dinfo->fb.offset << 12; - OUTREG(DSPABASE, offset); + dinfo->vsync.pan_offset = offset; + if ((var->activate & FB_ACTIVATE_VBL) && !intelfbhw_enable_irq(dinfo, 0)) { + dinfo->vsync.pan_display = 1; + } else { + dinfo->vsync.pan_display = 0; + OUTREG(DSPABASE, offset); + } return 0; } @@ -1965,6 +1971,10 @@ intelfbhw_irq(int irq, void *dev_id, struct pt_regs *fp) { if (tmp & VSYNC_PIPE_A_INTERRUPT) { dinfo->vsync.count++; + if (dinfo->vsync.pan_display) { + dinfo->vsync.pan_display = 0; + OUTREG(DSPABASE, dinfo->vsync.pan_offset); + } wake_up_interruptible(&dinfo->vsync.wait); handled = 1; } @@ -2007,6 +2017,10 @@ intelfbhw_disable_irq(struct intelfb_info *dinfo) { u16 tmp; if (test_and_clear_bit(0, &dinfo->irq_flags)) { + if (dinfo->vsync.pan_display) { + dinfo->vsync.pan_display = 0; + OUTREG(DSPABASE, dinfo->vsync.pan_offset); + } spin_lock_irq(&dinfo->int_lock); OUTREG16(HWSTAM, 0xffff); OUTREG16(IMR, 0xffff); -- cgit v1.2.3 From 4dc3595f5c569021b1bd0109502acfca82036902 Mon Sep 17 00:00:00 2001 From: Parag Warudkar Date: Tue, 22 Aug 2006 10:12:58 +1000 Subject: intelfbhw.c: intelfbhw_get_p1p2 defined but not used intelfbhw_get_p1p2 is used only if REGDUMP is defined - compile it in only if REGDUMP is defined - one less compiler warning. Signed-off-by: Dave Airlie --- drivers/video/intelfb/intelfbhw.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/video/intelfb/intelfbhw.c') diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index 8038f558611..bbd82fffc3f 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -627,6 +627,7 @@ static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2, int lvd return vco / p; } +#if REGDUMP static void intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2) { @@ -652,6 +653,7 @@ intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2) *o_p1 = p1; *o_p2 = p2; } +#endif void -- cgit v1.2.3