aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/intelfb/intelfbhw.c
diff options
context:
space:
mode:
authorEric Hustvedt <ehustvedt@cecropia.com>2006-06-20 14:36:41 -0400
committerDave Airlie <airlied@linux.ie>2006-07-03 04:59:46 -0400
commit7649757bd900bc900adcd95ab08903cdc28342fa (patch)
tree4c710d9e458ff3c6731180aca738123886f7adec /drivers/video/intelfb/intelfbhw.c
parent9a5f019b1a9ea6a75ba36d7c312ff069006ed479 (diff)
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 <ehustvedt@cecropia.com>
Diffstat (limited to 'drivers/video/intelfb/intelfbhw.c')
-rw-r--r--drivers/video/intelfb/intelfbhw.c76
1 files changed, 76 insertions, 0 deletions
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 05aded669cdb..1a698a7230e0 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -34,6 +34,7 @@
34#include <linux/pci.h> 34#include <linux/pci.h>
35#include <linux/vmalloc.h> 35#include <linux/vmalloc.h>
36#include <linux/pagemap.h> 36#include <linux/pagemap.h>
37#include <linux/interrupt.h>
37 38
38#include <asm/io.h> 39#include <asm/io.h>
39 40
@@ -1943,3 +1944,78 @@ intelfbhw_cursor_reset(struct intelfb_info *dinfo) {
1943 addr += 16; 1944 addr += 16;
1944 } 1945 }
1945} 1946}
1947
1948static irqreturn_t
1949intelfbhw_irq(int irq, void *dev_id, struct pt_regs *fp) {
1950 int handled = 0;
1951 u16 tmp;
1952 struct intelfb_info *dinfo = (struct intelfb_info *)dev_id;
1953
1954 spin_lock(&dinfo->int_lock);
1955
1956 tmp = INREG16(IIR);
1957 tmp &= VSYNC_PIPE_A_INTERRUPT;
1958
1959 if (tmp == 0) {
1960 spin_unlock(&dinfo->int_lock);
1961 return IRQ_RETVAL(handled);
1962 }
1963
1964 OUTREG16(IIR, tmp);
1965
1966 if (tmp & VSYNC_PIPE_A_INTERRUPT) {
1967 dinfo->vsync.count++;
1968 wake_up_interruptible(&dinfo->vsync.wait);
1969 handled = 1;
1970 }
1971
1972 spin_unlock(&dinfo->int_lock);
1973
1974 return IRQ_RETVAL(handled);
1975}
1976
1977int
1978intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable) {
1979
1980 if (!test_and_set_bit(0, &dinfo->irq_flags)) {
1981 if (request_irq(dinfo->pdev->irq, intelfbhw_irq, SA_SHIRQ, "intelfb", dinfo)) {
1982 clear_bit(0, &dinfo->irq_flags);
1983 return -EINVAL;
1984 }
1985
1986 spin_lock_irq(&dinfo->int_lock);
1987 OUTREG16(HWSTAM, 0xfffe);
1988 OUTREG16(IMR, 0x0);
1989 OUTREG16(IER, VSYNC_PIPE_A_INTERRUPT);
1990 spin_unlock_irq(&dinfo->int_lock);
1991 } else if (reenable) {
1992 u16 ier;
1993
1994 spin_lock_irq(&dinfo->int_lock);
1995 ier = INREG16(IER);
1996 if ((ier & VSYNC_PIPE_A_INTERRUPT)) {
1997 DBG_MSG("someone disabled the IRQ [%08X]\n", ier);
1998 OUTREG(IER, VSYNC_PIPE_A_INTERRUPT);
1999 }
2000 spin_unlock_irq(&dinfo->int_lock);
2001 }
2002 return 0;
2003}
2004
2005void
2006intelfbhw_disable_irq(struct intelfb_info *dinfo) {
2007 u16 tmp;
2008
2009 if (test_and_clear_bit(0, &dinfo->irq_flags)) {
2010 spin_lock_irq(&dinfo->int_lock);
2011 OUTREG16(HWSTAM, 0xffff);
2012 OUTREG16(IMR, 0xffff);
2013 OUTREG16(IER, 0x0);
2014
2015 tmp = INREG16(IIR);
2016 OUTREG16(IIR, tmp);
2017 spin_unlock_irq(&dinfo->int_lock);
2018
2019 free_irq(dinfo->pdev->irq, dinfo);
2020 }
2021}