aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/intelfb/intelfbhw.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/intelfb/intelfbhw.c')
-rw-r--r--drivers/video/intelfb/intelfbhw.c136
1 files changed, 135 insertions, 1 deletions
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 2a9322f9cfdc..f887f1efd3fe 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -32,6 +32,7 @@
32#include <linux/pci.h> 32#include <linux/pci.h>
33#include <linux/vmalloc.h> 33#include <linux/vmalloc.h>
34#include <linux/pagemap.h> 34#include <linux/pagemap.h>
35#include <linux/interrupt.h>
35 36
36#include <asm/io.h> 37#include <asm/io.h>
37 38
@@ -368,7 +369,13 @@ intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
368 369
369 offset += dinfo->fb.offset << 12; 370 offset += dinfo->fb.offset << 12;
370 371
371 OUTREG(DSPABASE, offset); 372 dinfo->vsync.pan_offset = offset;
373 if ((var->activate & FB_ACTIVATE_VBL) && !intelfbhw_enable_irq(dinfo, 0)) {
374 dinfo->vsync.pan_display = 1;
375 } else {
376 dinfo->vsync.pan_display = 0;
377 OUTREG(DSPABASE, offset);
378 }
372 379
373 return 0; 380 return 0;
374} 381}
@@ -585,6 +592,11 @@ intelfbhw_read_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
585 hw->fw_blc_0 = INREG(FW_BLC_0); 592 hw->fw_blc_0 = INREG(FW_BLC_0);
586 hw->fw_blc_1 = INREG(FW_BLC_1); 593 hw->fw_blc_1 = INREG(FW_BLC_1);
587 594
595 hw->hwstam = INREG16(HWSTAM);
596 hw->ier = INREG16(IER);
597 hw->iir = INREG16(IIR);
598 hw->imr = INREG16(IMR);
599
588 return 0; 600 return 0;
589} 601}
590 602
@@ -613,6 +625,7 @@ static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2, int lvd
613 return vco / p; 625 return vco / p;
614} 626}
615 627
628#if REGDUMP
616static void 629static void
617intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2) 630intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2)
618{ 631{
@@ -638,6 +651,7 @@ intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2)
638 *o_p1 = p1; 651 *o_p1 = p1;
639 *o_p2 = p2; 652 *o_p2 = p2;
640} 653}
654#endif
641 655
642 656
643void 657void
@@ -794,6 +808,10 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
794 printk(" FW_BLC_0 0x%08x\n", hw->fw_blc_0); 808 printk(" FW_BLC_0 0x%08x\n", hw->fw_blc_0);
795 printk(" FW_BLC_1 0x%08x\n", hw->fw_blc_1); 809 printk(" FW_BLC_1 0x%08x\n", hw->fw_blc_1);
796 810
811 printk(" HWSTAM 0x%04x\n", hw->hwstam);
812 printk(" IER 0x%04x\n", hw->ier);
813 printk(" IIR 0x%04x\n", hw->iir);
814 printk(" IMR 0x%04x\n", hw->imr);
797 printk("hw state dump end\n"); 815 printk("hw state dump end\n");
798#endif 816#endif
799} 817}
@@ -1932,3 +1950,119 @@ intelfbhw_cursor_reset(struct intelfb_info *dinfo) {
1932 addr += 16; 1950 addr += 16;
1933 } 1951 }
1934} 1952}
1953
1954static irqreturn_t
1955intelfbhw_irq(int irq, void *dev_id, struct pt_regs *fp) {
1956 int handled = 0;
1957 u16 tmp;
1958 struct intelfb_info *dinfo = (struct intelfb_info *)dev_id;
1959
1960 spin_lock(&dinfo->int_lock);
1961
1962 tmp = INREG16(IIR);
1963 tmp &= VSYNC_PIPE_A_INTERRUPT;
1964
1965 if (tmp == 0) {
1966 spin_unlock(&dinfo->int_lock);
1967 return IRQ_RETVAL(handled);
1968 }
1969
1970 OUTREG16(IIR, tmp);
1971
1972 if (tmp & VSYNC_PIPE_A_INTERRUPT) {
1973 dinfo->vsync.count++;
1974 if (dinfo->vsync.pan_display) {
1975 dinfo->vsync.pan_display = 0;
1976 OUTREG(DSPABASE, dinfo->vsync.pan_offset);
1977 }
1978 wake_up_interruptible(&dinfo->vsync.wait);
1979 handled = 1;
1980 }
1981
1982 spin_unlock(&dinfo->int_lock);
1983
1984 return IRQ_RETVAL(handled);
1985}
1986
1987int
1988intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable) {
1989
1990 if (!test_and_set_bit(0, &dinfo->irq_flags)) {
1991 if (request_irq(dinfo->pdev->irq, intelfbhw_irq, SA_SHIRQ, "intelfb", dinfo)) {
1992 clear_bit(0, &dinfo->irq_flags);
1993 return -EINVAL;
1994 }
1995
1996 spin_lock_irq(&dinfo->int_lock);
1997 OUTREG16(HWSTAM, 0xfffe);
1998 OUTREG16(IMR, 0x0);
1999 OUTREG16(IER, VSYNC_PIPE_A_INTERRUPT);
2000 spin_unlock_irq(&dinfo->int_lock);
2001 } else if (reenable) {
2002 u16 ier;
2003
2004 spin_lock_irq(&dinfo->int_lock);
2005 ier = INREG16(IER);
2006 if ((ier & VSYNC_PIPE_A_INTERRUPT)) {
2007 DBG_MSG("someone disabled the IRQ [%08X]\n", ier);
2008 OUTREG(IER, VSYNC_PIPE_A_INTERRUPT);
2009 }
2010 spin_unlock_irq(&dinfo->int_lock);
2011 }
2012 return 0;
2013}
2014
2015void
2016intelfbhw_disable_irq(struct intelfb_info *dinfo) {
2017 u16 tmp;
2018
2019 if (test_and_clear_bit(0, &dinfo->irq_flags)) {
2020 if (dinfo->vsync.pan_display) {
2021 dinfo->vsync.pan_display = 0;
2022 OUTREG(DSPABASE, dinfo->vsync.pan_offset);
2023 }
2024 spin_lock_irq(&dinfo->int_lock);
2025 OUTREG16(HWSTAM, 0xffff);
2026 OUTREG16(IMR, 0xffff);
2027 OUTREG16(IER, 0x0);
2028
2029 tmp = INREG16(IIR);
2030 OUTREG16(IIR, tmp);
2031 spin_unlock_irq(&dinfo->int_lock);
2032
2033 free_irq(dinfo->pdev->irq, dinfo);
2034 }
2035}
2036
2037int
2038intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe) {
2039 struct intelfb_vsync *vsync;
2040 unsigned int count;
2041 int ret;
2042
2043 switch (pipe) {
2044 case 0:
2045 vsync = &dinfo->vsync;
2046 break;
2047 default:
2048 return -ENODEV;
2049 }
2050
2051 ret = intelfbhw_enable_irq(dinfo, 0);
2052 if (ret) {
2053 return ret;
2054 }
2055
2056 count = vsync->count;
2057 ret = wait_event_interruptible_timeout(vsync->wait, count != vsync->count, HZ/10);
2058 if (ret < 0) {
2059 return ret;
2060 }
2061 if (ret == 0) {
2062 intelfbhw_enable_irq(dinfo, 1);
2063 DBG_MSG("wait_for_vsync timed out!\n");
2064 return -ETIMEDOUT;
2065 }
2066
2067 return 0;
2068}