aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKrzysztof Halasa <khc@pm.waw.pl>2007-10-16 04:29:34 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-16 12:43:20 -0400
commit394d3af7ba9e67d630c1c6d2ac1d9c11b318b73e (patch)
tree7057c8c671e7bc33753830928c82c9c5378cd496
parent28ebe4f66beda8f142569d24fe3b168f8a08a6a6 (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.c91
-rw-r--r--drivers/video/intelfb/intelfbhw.h30
-rw-r--r--include/linux/fb.h1
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
1958static irqreturn_t 1971static irqreturn_t intelfbhw_irq(int irq, void *dev_id)
1959intelfbhw_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
1991int 2006int intelfbhw_enable_irq(struct intelfb_info *dinfo)
1992intelfbhw_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
2020void 2035void intelfbhw_disable_irq(struct intelfb_info *dinfo)
2021intelfbhw_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,
573extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, 601extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width,
574 int height, u8 *data); 602 int height, u8 *data);
575extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo); 603extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo);
576extern int intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable); 604extern int intelfbhw_enable_irq(struct intelfb_info *dinfo);
577extern void intelfbhw_disable_irq(struct intelfb_info *dinfo); 605extern void intelfbhw_disable_irq(struct intelfb_info *dinfo);
578extern int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe); 606extern 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 */