diff options
author | Krzysztof Halasa <khc@pm.waw.pl> | 2007-10-16 04:29:34 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-16 12:43:20 -0400 |
commit | 394d3af7ba9e67d630c1c6d2ac1d9c11b318b73e (patch) | |
tree | 7057c8c671e7bc33753830928c82c9c5378cd496 | |
parent | 28ebe4f66beda8f142569d24fe3b168f8a08a6a6 (diff) |
Intel FB: more interlaced mode support
Intel FB: allow odd- and even-field-first in interlaced modes, and
proper sync to vertical retrace
Signed-off-by: Krzysztof Halasa <khc@pm.waw.pl>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Cc: <sylvain.meyer@worldonline.fr>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/video/intelfb/intelfbhw.c | 91 | ||||
-rw-r--r-- | drivers/video/intelfb/intelfbhw.h | 30 | ||||
-rw-r--r-- | include/linux/fb.h | 1 |
3 files changed, 82 insertions, 40 deletions
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index a02ee24f3668..2a0e32074f7d 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c | |||
@@ -376,7 +376,7 @@ int intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) | |||
376 | 376 | ||
377 | dinfo->vsync.pan_offset = offset; | 377 | dinfo->vsync.pan_offset = offset; |
378 | if ((var->activate & FB_ACTIVATE_VBL) && | 378 | if ((var->activate & FB_ACTIVATE_VBL) && |
379 | !intelfbhw_enable_irq(dinfo, 0)) | 379 | !intelfbhw_enable_irq(dinfo)) |
380 | dinfo->vsync.pan_display = 1; | 380 | dinfo->vsync.pan_display = 1; |
381 | else { | 381 | else { |
382 | dinfo->vsync.pan_display = 0; | 382 | dinfo->vsync.pan_display = 0; |
@@ -1240,7 +1240,7 @@ int intelfbhw_program_mode(struct intelfb_info *dinfo, | |||
1240 | u32 tmp; | 1240 | u32 tmp; |
1241 | const u32 *dpll, *fp0, *fp1, *pipe_conf; | 1241 | const u32 *dpll, *fp0, *fp1, *pipe_conf; |
1242 | const u32 *hs, *ht, *hb, *vs, *vt, *vb, *ss; | 1242 | const u32 *hs, *ht, *hb, *vs, *vt, *vb, *ss; |
1243 | u32 dpll_reg, fp0_reg, fp1_reg, pipe_conf_reg; | 1243 | u32 dpll_reg, fp0_reg, fp1_reg, pipe_conf_reg, pipe_stat_reg; |
1244 | u32 hsync_reg, htotal_reg, hblank_reg; | 1244 | u32 hsync_reg, htotal_reg, hblank_reg; |
1245 | u32 vsync_reg, vtotal_reg, vblank_reg; | 1245 | u32 vsync_reg, vtotal_reg, vblank_reg; |
1246 | u32 src_size_reg; | 1246 | u32 src_size_reg; |
@@ -1281,6 +1281,7 @@ int intelfbhw_program_mode(struct intelfb_info *dinfo, | |||
1281 | fp0_reg = FPB0; | 1281 | fp0_reg = FPB0; |
1282 | fp1_reg = FPB1; | 1282 | fp1_reg = FPB1; |
1283 | pipe_conf_reg = PIPEBCONF; | 1283 | pipe_conf_reg = PIPEBCONF; |
1284 | pipe_stat_reg = PIPEBSTAT; | ||
1284 | hsync_reg = HSYNC_B; | 1285 | hsync_reg = HSYNC_B; |
1285 | htotal_reg = HTOTAL_B; | 1286 | htotal_reg = HTOTAL_B; |
1286 | hblank_reg = HBLANK_B; | 1287 | hblank_reg = HBLANK_B; |
@@ -1304,6 +1305,7 @@ int intelfbhw_program_mode(struct intelfb_info *dinfo, | |||
1304 | fp0_reg = FPA0; | 1305 | fp0_reg = FPA0; |
1305 | fp1_reg = FPA1; | 1306 | fp1_reg = FPA1; |
1306 | pipe_conf_reg = PIPEACONF; | 1307 | pipe_conf_reg = PIPEACONF; |
1308 | pipe_stat_reg = PIPEASTAT; | ||
1307 | hsync_reg = HSYNC_A; | 1309 | hsync_reg = HSYNC_A; |
1308 | htotal_reg = HTOTAL_A; | 1310 | htotal_reg = HTOTAL_A; |
1309 | hblank_reg = HBLANK_A; | 1311 | hblank_reg = HBLANK_A; |
@@ -1390,6 +1392,17 @@ int intelfbhw_program_mode(struct intelfb_info *dinfo, | |||
1390 | OUTREG(vtotal_reg, *vt); | 1392 | OUTREG(vtotal_reg, *vt); |
1391 | OUTREG(src_size_reg, *ss); | 1393 | OUTREG(src_size_reg, *ss); |
1392 | 1394 | ||
1395 | switch (dinfo->info->var.vmode & (FB_VMODE_INTERLACED | | ||
1396 | FB_VMODE_ODD_FLD_FIRST)) { | ||
1397 | case FB_VMODE_INTERLACED | FB_VMODE_ODD_FLD_FIRST: | ||
1398 | OUTREG(pipe_stat_reg, 0xFFFF | PIPESTAT_FLD_EVT_ODD_EN); | ||
1399 | break; | ||
1400 | case FB_VMODE_INTERLACED: /* even lines first */ | ||
1401 | OUTREG(pipe_stat_reg, 0xFFFF | PIPESTAT_FLD_EVT_EVEN_EN); | ||
1402 | break; | ||
1403 | default: /* non-interlaced */ | ||
1404 | OUTREG(pipe_stat_reg, 0xFFFF); /* clear all status bits only */ | ||
1405 | } | ||
1393 | /* Enable pipe */ | 1406 | /* Enable pipe */ |
1394 | OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE); | 1407 | OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE); |
1395 | 1408 | ||
@@ -1955,71 +1968,72 @@ void intelfbhw_cursor_reset(struct intelfb_info *dinfo) | |||
1955 | } | 1968 | } |
1956 | } | 1969 | } |
1957 | 1970 | ||
1958 | static irqreturn_t | 1971 | static irqreturn_t intelfbhw_irq(int irq, void *dev_id) |
1959 | intelfbhw_irq(int irq, void *dev_id) { | 1972 | { |
1960 | int handled = 0; | ||
1961 | u16 tmp; | 1973 | u16 tmp; |
1962 | struct intelfb_info *dinfo = (struct intelfb_info *)dev_id; | 1974 | struct intelfb_info *dinfo = (struct intelfb_info *)dev_id; |
1963 | 1975 | ||
1964 | spin_lock(&dinfo->int_lock); | 1976 | spin_lock(&dinfo->int_lock); |
1965 | 1977 | ||
1966 | tmp = INREG16(IIR); | 1978 | tmp = INREG16(IIR); |
1967 | tmp &= VSYNC_PIPE_A_INTERRUPT; | 1979 | if (dinfo->info->var.vmode & FB_VMODE_INTERLACED) |
1980 | tmp &= PIPE_A_EVENT_INTERRUPT; | ||
1981 | else | ||
1982 | tmp &= VSYNC_PIPE_A_INTERRUPT; /* non-interlaced */ | ||
1968 | 1983 | ||
1969 | if (tmp == 0) { | 1984 | if (tmp == 0) { |
1970 | spin_unlock(&dinfo->int_lock); | 1985 | spin_unlock(&dinfo->int_lock); |
1971 | return IRQ_RETVAL(handled); | 1986 | return IRQ_RETVAL(0); /* not us */ |
1972 | } | 1987 | } |
1973 | 1988 | ||
1974 | OUTREG16(IIR, tmp); | 1989 | /* clear status bits 0-15 ASAP and don't touch bits 16-31 */ |
1990 | OUTREG(PIPEASTAT, INREG(PIPEASTAT)); | ||
1975 | 1991 | ||
1976 | if (tmp & VSYNC_PIPE_A_INTERRUPT) { | 1992 | OUTREG16(IIR, tmp); |
1977 | dinfo->vsync.count++; | 1993 | if (dinfo->vsync.pan_display) { |
1978 | if (dinfo->vsync.pan_display) { | 1994 | dinfo->vsync.pan_display = 0; |
1979 | dinfo->vsync.pan_display = 0; | 1995 | OUTREG(DSPABASE, dinfo->vsync.pan_offset); |
1980 | OUTREG(DSPABASE, dinfo->vsync.pan_offset); | ||
1981 | } | ||
1982 | wake_up_interruptible(&dinfo->vsync.wait); | ||
1983 | handled = 1; | ||
1984 | } | 1996 | } |
1985 | 1997 | ||
1998 | dinfo->vsync.count++; | ||
1999 | wake_up_interruptible(&dinfo->vsync.wait); | ||
2000 | |||
1986 | spin_unlock(&dinfo->int_lock); | 2001 | spin_unlock(&dinfo->int_lock); |
1987 | 2002 | ||
1988 | return IRQ_RETVAL(handled); | 2003 | return IRQ_RETVAL(1); |
1989 | } | 2004 | } |
1990 | 2005 | ||
1991 | int | 2006 | int intelfbhw_enable_irq(struct intelfb_info *dinfo) |
1992 | intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable) { | 2007 | { |
1993 | 2008 | u16 tmp; | |
1994 | if (!test_and_set_bit(0, &dinfo->irq_flags)) { | 2009 | if (!test_and_set_bit(0, &dinfo->irq_flags)) { |
1995 | if (request_irq(dinfo->pdev->irq, intelfbhw_irq, IRQF_SHARED, | 2010 | if (request_irq(dinfo->pdev->irq, intelfbhw_irq, IRQF_SHARED, |
1996 | "intelfb", dinfo)) { | 2011 | "intelfb", dinfo)) { |
1997 | clear_bit(0, &dinfo->irq_flags); | 2012 | clear_bit(0, &dinfo->irq_flags); |
1998 | return -EINVAL; | 2013 | return -EINVAL; |
1999 | } | 2014 | } |
2000 | 2015 | ||
2001 | spin_lock_irq(&dinfo->int_lock); | 2016 | spin_lock_irq(&dinfo->int_lock); |
2002 | OUTREG16(HWSTAM, 0xfffe); | 2017 | OUTREG16(HWSTAM, 0xfffe); /* i830 DRM uses ffff */ |
2003 | OUTREG16(IMR, 0x0); | 2018 | OUTREG16(IMR, 0); |
2004 | OUTREG16(IER, VSYNC_PIPE_A_INTERRUPT); | 2019 | } else |
2005 | spin_unlock_irq(&dinfo->int_lock); | ||
2006 | } else if (reenable) { | ||
2007 | u16 ier; | ||
2008 | |||
2009 | spin_lock_irq(&dinfo->int_lock); | 2020 | spin_lock_irq(&dinfo->int_lock); |
2010 | ier = INREG16(IER); | 2021 | |
2011 | if ((ier & VSYNC_PIPE_A_INTERRUPT)) { | 2022 | if (dinfo->info->var.vmode & FB_VMODE_INTERLACED) |
2012 | DBG_MSG("someone disabled the IRQ [%08X]\n", ier); | 2023 | tmp = PIPE_A_EVENT_INTERRUPT; |
2013 | OUTREG(IER, VSYNC_PIPE_A_INTERRUPT); | 2024 | else |
2014 | } | 2025 | tmp = VSYNC_PIPE_A_INTERRUPT; /* non-interlaced */ |
2015 | spin_unlock_irq(&dinfo->int_lock); | 2026 | if (tmp != INREG16(IER)) { |
2027 | DBG_MSG("changing IER to 0x%X\n", tmp); | ||
2028 | OUTREG16(IER, tmp); | ||
2016 | } | 2029 | } |
2030 | |||
2031 | spin_unlock_irq(&dinfo->int_lock); | ||
2017 | return 0; | 2032 | return 0; |
2018 | } | 2033 | } |
2019 | 2034 | ||
2020 | void | 2035 | void intelfbhw_disable_irq(struct intelfb_info *dinfo) |
2021 | intelfbhw_disable_irq(struct intelfb_info *dinfo) { | 2036 | { |
2022 | |||
2023 | if (test_and_clear_bit(0, &dinfo->irq_flags)) { | 2037 | if (test_and_clear_bit(0, &dinfo->irq_flags)) { |
2024 | if (dinfo->vsync.pan_display) { | 2038 | if (dinfo->vsync.pan_display) { |
2025 | dinfo->vsync.pan_display = 0; | 2039 | dinfo->vsync.pan_display = 0; |
@@ -2051,7 +2065,7 @@ int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe) | |||
2051 | return -ENODEV; | 2065 | return -ENODEV; |
2052 | } | 2066 | } |
2053 | 2067 | ||
2054 | ret = intelfbhw_enable_irq(dinfo, 0); | 2068 | ret = intelfbhw_enable_irq(dinfo); |
2055 | if (ret) | 2069 | if (ret) |
2056 | return ret; | 2070 | return ret; |
2057 | 2071 | ||
@@ -2061,7 +2075,6 @@ int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe) | |||
2061 | if (ret < 0) | 2075 | if (ret < 0) |
2062 | return ret; | 2076 | return ret; |
2063 | if (ret == 0) { | 2077 | if (ret == 0) { |
2064 | intelfbhw_enable_irq(dinfo, 1); | ||
2065 | DBG_MSG("wait_for_vsync timed out!\n"); | 2078 | DBG_MSG("wait_for_vsync timed out!\n"); |
2066 | return -ETIMEDOUT; | 2079 | return -ETIMEDOUT; |
2067 | } | 2080 | } |
diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h index 3cbfcef83361..0b076bac321b 100644 --- a/drivers/video/intelfb/intelfbhw.h +++ b/drivers/video/intelfb/intelfbhw.h | |||
@@ -280,6 +280,9 @@ | |||
280 | #define PIPEB_DSL 0x71000 | 280 | #define PIPEB_DSL 0x71000 |
281 | #define PIPEACONF 0x70008 | 281 | #define PIPEACONF 0x70008 |
282 | #define PIPEBCONF 0x71008 | 282 | #define PIPEBCONF 0x71008 |
283 | #define PIPEASTAT 0x70024 /* bits 0-15 are "write 1 to clear" */ | ||
284 | #define PIPEBSTAT 0x71024 | ||
285 | |||
283 | #define PIPECONF_ENABLE (1 << 31) | 286 | #define PIPECONF_ENABLE (1 << 31) |
284 | #define PIPECONF_DISABLE 0 | 287 | #define PIPECONF_DISABLE 0 |
285 | #define PIPECONF_DOUBLE_WIDE (1 << 30) | 288 | #define PIPECONF_DOUBLE_WIDE (1 << 30) |
@@ -293,6 +296,31 @@ | |||
293 | #define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21) | 296 | #define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21) |
294 | #define PIPECONF_INTERLACE_MASK (7 << 21) | 297 | #define PIPECONF_INTERLACE_MASK (7 << 21) |
295 | 298 | ||
299 | /* enable bits, write 1 to enable */ | ||
300 | #define PIPESTAT_FIFO_UNDERRUN (1 << 31) | ||
301 | #define PIPESTAT_CRC_ERROR_EN (1 << 29) | ||
302 | #define PIPESTAT_CRC_DONE_EN (1 << 28) | ||
303 | #define PIPESTAT_HOTPLUG_EN (1 << 26) | ||
304 | #define PIPESTAT_VERTICAL_SYNC_EN (1 << 25) | ||
305 | #define PIPESTAT_DISPLINE_COMP_EN (1 << 24) | ||
306 | #define PIPESTAT_FLD_EVT_ODD_EN (1 << 21) | ||
307 | #define PIPESTAT_FLD_EVT_EVEN_EN (1 << 20) | ||
308 | #define PIPESTAT_TV_HOTPLUG_EN (1 << 18) | ||
309 | #define PIPESTAT_VBLANK_EN (1 << 17) | ||
310 | #define PIPESTAT_OVL_UPDATE_EN (1 << 16) | ||
311 | /* status bits, write 1 to clear */ | ||
312 | #define PIPESTAT_HOTPLUG_STATE (1 << 15) | ||
313 | #define PIPESTAT_CRC_ERROR (1 << 13) | ||
314 | #define PIPESTAT_CRC_DONE (1 << 12) | ||
315 | #define PIPESTAT_HOTPLUG (1 << 10) | ||
316 | #define PIPESTAT_VSYNC (1 << 9) | ||
317 | #define PIPESTAT_DISPLINE_COMP (1 << 8) | ||
318 | #define PIPESTAT_FLD_EVT_ODD (1 << 5) | ||
319 | #define PIPESTAT_FLD_EVT_EVEN (1 << 4) | ||
320 | #define PIPESTAT_TV_HOTPLUG (1 << 2) | ||
321 | #define PIPESTAT_VBLANK (1 << 1) | ||
322 | #define PIPESTAT_OVL_UPDATE (1 << 0) | ||
323 | |||
296 | #define DISPARB 0x70030 | 324 | #define DISPARB 0x70030 |
297 | #define DISPARB_AEND_MASK 0x1ff | 325 | #define DISPARB_AEND_MASK 0x1ff |
298 | #define DISPARB_AEND_SHIFT 0 | 326 | #define DISPARB_AEND_SHIFT 0 |
@@ -573,7 +601,7 @@ extern void intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, | |||
573 | extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, | 601 | extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, |
574 | int height, u8 *data); | 602 | int height, u8 *data); |
575 | extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo); | 603 | extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo); |
576 | extern int intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable); | 604 | extern int intelfbhw_enable_irq(struct intelfb_info *dinfo); |
577 | extern void intelfbhw_disable_irq(struct intelfb_info *dinfo); | 605 | extern void intelfbhw_disable_irq(struct intelfb_info *dinfo); |
578 | extern int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe); | 606 | extern int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe); |
579 | 607 | ||
diff --git a/include/linux/fb.h b/include/linux/fb.h index b39395caa460..672927209255 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h | |||
@@ -207,6 +207,7 @@ struct fb_bitfield { | |||
207 | #define FB_VMODE_NONINTERLACED 0 /* non interlaced */ | 207 | #define FB_VMODE_NONINTERLACED 0 /* non interlaced */ |
208 | #define FB_VMODE_INTERLACED 1 /* interlaced */ | 208 | #define FB_VMODE_INTERLACED 1 /* interlaced */ |
209 | #define FB_VMODE_DOUBLE 2 /* double scan */ | 209 | #define FB_VMODE_DOUBLE 2 /* double scan */ |
210 | #define FB_VMODE_ODD_FLD_FIRST 4 /* interlaced: top line first */ | ||
210 | #define FB_VMODE_MASK 255 | 211 | #define FB_VMODE_MASK 255 |
211 | 212 | ||
212 | #define FB_VMODE_YWRAP 256 /* ywrap instead of panning */ | 213 | #define FB_VMODE_YWRAP 256 /* ywrap instead of panning */ |