[PATCH 3/5 2.6.17-rc6-mm2] add vsync interrupt support to intelfb driver
From: Dennis Munsie <hidden>
Date: 2006-06-14 13:07:50
From: Eric Hustvedt <redacted> [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 <redacted> Signed-off-by: Dennis Munsie <redacted> --- drivers/video/intelfb/intelfb.h | 11 +++ drivers/video/intelfb/intelfbdrv.c | 39 +++++++++++++ drivers/video/intelfb/intelfbhw.c | 77 +++++++++++++++++++++++++++ drivers/video/intelfb/intelfbhw.h | 2 4 files changed, 129 insertions(+) diff -X linux-2.6.17-rc4-hwstam/Documentation/dontdiff -Naurp linux-2.6.17-rc4-hwstam/drivers/video/intelfb/intelfb.h linux-2.6.17- rc4-interrupt/drivers/video/intelfb/intelfb.h
--- linux-2.6.17-rc4-hwstam/drivers/video/intelfb/intelfb.h 2006-06-09 09:43:18.000000000 -0600
+++ linux-2.6.17-rc4-interrupt/drivers/video/intelfb/intelfb.h 2006-06-09 10:10:15.000000000 -0600
@@ -208,6 +208,11 @@ struct intelfb_heap_data { u32 size; // in bytes
};
+struct intelfb_vsync {
+ wait_queue_head_t wait;
+ unsigned int count;
+};
+
struct intelfb_info {
struct fb_info *info;
struct fb_ops *fbops;@@ -271,7 +276,13 @@ struct intelfb_info {int fixed_mode; int ring_active; int flag; + unsigned long irq_flags; + int open; + /* vsync */ + struct intelfb_vsync vsync; + spinlock_t int_lock; + /* hw cursor */ int cursor_on; int cursor_blanked; diff -X linux-2.6.17-rc4-hwstam/Documentation/dontdiff -Naurp linux-2.6.17-rc4-hwstam/drivers/video/intelfb/intelfbdrv.c linux-2.6.17-rc4-interrupt/drivers/video/intelfb/intelfbdrv.c
--- linux-2.6.17-rc4-hwstam/drivers/video/intelfb/intelfbdrv.c 2006-06-09 09:41:10.000000000 -0600
+++ linux-2.6.17-rc4-interrupt/drivers/video/intelfb/intelfbdrv.c 2006-06-09 10:11:11.000000000 -0600
@@ -137,6 +137,8 @@static void __devinit get_initial_mode(struct intelfb_info *dinfo); static void update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var); +static int intelfb_open(struct fb_info *info, int user); +static int intelfb_release(struct fb_info *info, int user); static int intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info); static int intelfb_set_par(struct fb_info *info);
@@ -195,6 +197,8 @@ static int num_registered = 0;/* fb ops */
static struct fb_ops intel_fb_ops = {
.owner = THIS_MODULE,
+ .fb_open = intelfb_open,
+ .fb_release = intelfb_release,
.fb_check_var = intelfb_check_var,
.fb_set_par = intelfb_set_par,
.fb_setcolreg = intelfb_setcolreg,@@ -447,6 +451,8 @@ cleanup(struct intelfb_info *dinfo)if (!dinfo) return; + intelfbhw_disable_irq(dinfo); + fb_dealloc_cmap(&dinfo->info->cmap); kfree(dinfo->info->pixmap.addr);
@@ -889,6 +895,11 @@ intelfb_pci_register(struct pci_dev *pde} dinfo->registered = 1; + dinfo->open = 0; + + init_waitqueue_head(&dinfo->vsync.wait); + spin_lock_init(&dinfo->int_lock); + dinfo->irq_flags = 0; return 0;
@@ -1189,6 +1200,34 @@ update_dinfo(struct intelfb_info *dinfo, ***************************************************************/
static int
+intelfb_open(struct fb_info *info, int user)
+{
+ struct intelfb_info *dinfo = GET_DINFO(info);
+
+ if (user) {
+ dinfo->open++;
+ }
+
+ return 0;
+}
+
+static int
+intelfb_release(struct fb_info *info, int user)
+{
+ struct intelfb_info *dinfo = GET_DINFO(info);
+
+ if (user) {
+ dinfo->open--;
+ msleep(1);
+ if (!dinfo->open) {
+ intelfbhw_disable_irq(dinfo);
+ }
+ }
+
+ return 0;
+}
+
+static int
intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
int change_var = 0;
diff -X linux-2.6.17-rc4-hwstam/Documentation/dontdiff -Naurp
linux-2.6.17-rc4-hwstam/drivers/video/intelfb/intelfbhw.c
linux-2.6.17-rc4-interrupt/drivers/video/intelfb/intelfbhw.c--- linux-2.6.17-rc4-hwstam/drivers/video/intelfb/intelfbhw.c 2006-06-09 09:43:18.000000000 -0600
+++ linux-2.6.17-rc4-interrupt/drivers/video/intelfb/intelfbhw.c 2006-06-13 12:15:13.000000000 -0600
@@ -34,6 +34,7 @@#include <linux/pci.h> #include <linux/vmalloc.h> #include <linux/pagemap.h> +#include <linux/interrupt.h> #include <asm/io.h>
@@ -1991,3 +1992,79 @@ intelfbhw_cursor_reset(struct intelfb_in 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);
+ }
+}
diff -X linux-2.6.17-rc4-hwstam/Documentation/dontdiff -Naurp
linux-2.6.17-rc4-hwstam/drivers/video/intelfb/intelfbhw.h
linux-2.6.17-rc4-interrupt/drivers/video/intelfb/intelfbhw.h--- linux-2.6.17-rc4-hwstam/drivers/video/intelfb/intelfbhw.h 2006-06-09 10:04:37.000000000 -0600
+++ linux-2.6.17-rc4-interrupt/drivers/video/intelfb/intelfbhw.h 2006-06-09 10:17:51.000000000 -0600
@@ -561,5 +561,7 @@ extern void intelfbhw_cursor_setcolor(stextern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, int height, u8 *data); extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo); +extern int intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable); +extern void intelfbhw_disable_irq(struct intelfb_info *dinfo); #endif /* _INTELFBHW_H */