aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/intelfb
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
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')
-rw-r--r--drivers/video/intelfb/intelfb.h11
-rw-r--r--drivers/video/intelfb/intelfbdrv.c39
-rw-r--r--drivers/video/intelfb/intelfbhw.c76
-rw-r--r--drivers/video/intelfb/intelfbhw.h2
4 files changed, 128 insertions, 0 deletions
diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h
index cb016fe4d488..dab1f2d764d2 100644
--- a/drivers/video/intelfb/intelfb.h
+++ b/drivers/video/intelfb/intelfb.h
@@ -208,6 +208,11 @@ struct intelfb_heap_data {
208 u32 size; // in bytes 208 u32 size; // in bytes
209}; 209};
210 210
211struct intelfb_vsync {
212 wait_queue_head_t wait;
213 unsigned int count;
214};
215
211struct intelfb_info { 216struct intelfb_info {
212 struct fb_info *info; 217 struct fb_info *info;
213 struct fb_ops *fbops; 218 struct fb_ops *fbops;
@@ -271,6 +276,12 @@ struct intelfb_info {
271 int fixed_mode; 276 int fixed_mode;
272 int ring_active; 277 int ring_active;
273 int flag; 278 int flag;
279 unsigned long irq_flags;
280 int open;
281
282 /* vsync */
283 struct intelfb_vsync vsync;
284 spinlock_t int_lock;
274 285
275 /* hw cursor */ 286 /* hw cursor */
276 int cursor_on; 287 int cursor_on;
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index 0a0a8b199ecc..068c56d4e652 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -137,6 +137,8 @@
137static void __devinit get_initial_mode(struct intelfb_info *dinfo); 137static void __devinit get_initial_mode(struct intelfb_info *dinfo);
138static void update_dinfo(struct intelfb_info *dinfo, 138static void update_dinfo(struct intelfb_info *dinfo,
139 struct fb_var_screeninfo *var); 139 struct fb_var_screeninfo *var);
140static int intelfb_open(struct fb_info *info, int user);
141static int intelfb_release(struct fb_info *info, int user);
140static int intelfb_check_var(struct fb_var_screeninfo *var, 142static int intelfb_check_var(struct fb_var_screeninfo *var,
141 struct fb_info *info); 143 struct fb_info *info);
142static int intelfb_set_par(struct fb_info *info); 144static int intelfb_set_par(struct fb_info *info);
@@ -195,6 +197,8 @@ static int num_registered = 0;
195/* fb ops */ 197/* fb ops */
196static struct fb_ops intel_fb_ops = { 198static struct fb_ops intel_fb_ops = {
197 .owner = THIS_MODULE, 199 .owner = THIS_MODULE,
200 .fb_open = intelfb_open,
201 .fb_release = intelfb_release,
198 .fb_check_var = intelfb_check_var, 202 .fb_check_var = intelfb_check_var,
199 .fb_set_par = intelfb_set_par, 203 .fb_set_par = intelfb_set_par,
200 .fb_setcolreg = intelfb_setcolreg, 204 .fb_setcolreg = intelfb_setcolreg,
@@ -447,6 +451,8 @@ cleanup(struct intelfb_info *dinfo)
447 if (!dinfo) 451 if (!dinfo)
448 return; 452 return;
449 453
454 intelfbhw_disable_irq(dinfo);
455
450 fb_dealloc_cmap(&dinfo->info->cmap); 456 fb_dealloc_cmap(&dinfo->info->cmap);
451 kfree(dinfo->info->pixmap.addr); 457 kfree(dinfo->info->pixmap.addr);
452 458
@@ -889,6 +895,11 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
889 } 895 }
890 896
891 dinfo->registered = 1; 897 dinfo->registered = 1;
898 dinfo->open = 0;
899
900 init_waitqueue_head(&dinfo->vsync.wait);
901 spin_lock_init(&dinfo->int_lock);
902 dinfo->irq_flags = 0;
892 903
893 return 0; 904 return 0;
894 905
@@ -1189,6 +1200,34 @@ update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var)
1189 ***************************************************************/ 1200 ***************************************************************/
1190 1201
1191static int 1202static int
1203intelfb_open(struct fb_info *info, int user)
1204{
1205 struct intelfb_info *dinfo = GET_DINFO(info);
1206
1207 if (user) {
1208 dinfo->open++;
1209 }
1210
1211 return 0;
1212}
1213
1214static int
1215intelfb_release(struct fb_info *info, int user)
1216{
1217 struct intelfb_info *dinfo = GET_DINFO(info);
1218
1219 if (user) {
1220 dinfo->open--;
1221 msleep(1);
1222 if (!dinfo->open) {
1223 intelfbhw_disable_irq(dinfo);
1224 }
1225 }
1226
1227 return 0;
1228}
1229
1230static int
1192intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 1231intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1193{ 1232{
1194 int change_var = 0; 1233 int change_var = 0;
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}
diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h
index 8d2e36972fc8..aa0c139a2301 100644
--- a/drivers/video/intelfb/intelfbhw.h
+++ b/drivers/video/intelfb/intelfbhw.h
@@ -561,5 +561,7 @@ extern void intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg,
561extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, 561extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width,
562 int height, u8 *data); 562 int height, u8 *data);
563extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo); 563extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo);
564extern int intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable);
565extern void intelfbhw_disable_irq(struct intelfb_info *dinfo);
564 566
565#endif /* _INTELFBHW_H */ 567#endif /* _INTELFBHW_H */