diff options
Diffstat (limited to 'drivers/video/intelfb/intelfbhw.c')
-rw-r--r-- | drivers/video/intelfb/intelfbhw.c | 136 |
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 | ||
616 | static void | 629 | static void |
617 | intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2) | 630 | intelfbhw_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 | ||
643 | void | 657 | void |
@@ -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 | |||
1954 | static irqreturn_t | ||
1955 | intelfbhw_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 | |||
1987 | int | ||
1988 | intelfbhw_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 | |||
2015 | void | ||
2016 | intelfbhw_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 | |||
2037 | int | ||
2038 | intelfbhw_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 | } | ||