Commit 394d3af7ba9e67d630c1c6d2ac1d9c11b318b73e

Authored by Krzysztof Halasa
Committed by Linus Torvalds
1 parent 28ebe4f66b

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>

Showing 3 changed files with 82 additions and 40 deletions Side-by-side Diff

drivers/video/intelfb/intelfbhw.c
... ... @@ -376,7 +376,7 @@
376 376  
377 377 dinfo->vsync.pan_offset = offset;
378 378 if ((var->activate & FB_ACTIVATE_VBL) &&
379   - !intelfbhw_enable_irq(dinfo, 0))
  379 + !intelfbhw_enable_irq(dinfo))
380 380 dinfo->vsync.pan_display = 1;
381 381 else {
382 382 dinfo->vsync.pan_display = 0;
... ... @@ -1240,7 +1240,7 @@
1240 1240 u32 tmp;
1241 1241 const u32 *dpll, *fp0, *fp1, *pipe_conf;
1242 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 1244 u32 hsync_reg, htotal_reg, hblank_reg;
1245 1245 u32 vsync_reg, vtotal_reg, vblank_reg;
1246 1246 u32 src_size_reg;
... ... @@ -1281,6 +1281,7 @@
1281 1281 fp0_reg = FPB0;
1282 1282 fp1_reg = FPB1;
1283 1283 pipe_conf_reg = PIPEBCONF;
  1284 + pipe_stat_reg = PIPEBSTAT;
1284 1285 hsync_reg = HSYNC_B;
1285 1286 htotal_reg = HTOTAL_B;
1286 1287 hblank_reg = HBLANK_B;
... ... @@ -1304,6 +1305,7 @@
1304 1305 fp0_reg = FPA0;
1305 1306 fp1_reg = FPA1;
1306 1307 pipe_conf_reg = PIPEACONF;
  1308 + pipe_stat_reg = PIPEASTAT;
1307 1309 hsync_reg = HSYNC_A;
1308 1310 htotal_reg = HTOTAL_A;
1309 1311 hblank_reg = HBLANK_A;
... ... @@ -1390,6 +1392,17 @@
1390 1392 OUTREG(vtotal_reg, *vt);
1391 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 1406 /* Enable pipe */
1394 1407 OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE);
1395 1408  
1396 1409  
1397 1410  
1398 1411  
1399 1412  
1400 1413  
1401 1414  
1402 1415  
1403 1416  
1404 1417  
1405 1418  
1406 1419  
1407 1420  
... ... @@ -1955,71 +1968,72 @@
1955 1968 }
1956 1969 }
1957 1970  
1958   -static irqreturn_t
1959   -intelfbhw_irq(int irq, void *dev_id) {
1960   - int handled = 0;
  1971 +static irqreturn_t intelfbhw_irq(int irq, void *dev_id)
  1972 +{
1961 1973 u16 tmp;
1962 1974 struct intelfb_info *dinfo = (struct intelfb_info *)dev_id;
1963 1975  
1964 1976 spin_lock(&dinfo->int_lock);
1965 1977  
1966 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 1984 if (tmp == 0) {
1970 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) {
1977   - dinfo->vsync.count++;
1978   - if (dinfo->vsync.pan_display) {
1979   - dinfo->vsync.pan_display = 0;
1980   - OUTREG(DSPABASE, dinfo->vsync.pan_offset);
1981   - }
1982   - wake_up_interruptible(&dinfo->vsync.wait);
1983   - handled = 1;
  1992 + OUTREG16(IIR, tmp);
  1993 + if (dinfo->vsync.pan_display) {
  1994 + dinfo->vsync.pan_display = 0;
  1995 + OUTREG(DSPABASE, dinfo->vsync.pan_offset);
1984 1996 }
1985 1997  
  1998 + dinfo->vsync.count++;
  1999 + wake_up_interruptible(&dinfo->vsync.wait);
  2000 +
1986 2001 spin_unlock(&dinfo->int_lock);
1987 2002  
1988   - return IRQ_RETVAL(handled);
  2003 + return IRQ_RETVAL(1);
1989 2004 }
1990 2005  
1991   -int
1992   -intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable) {
1993   -
  2006 +int intelfbhw_enable_irq(struct intelfb_info *dinfo)
  2007 +{
  2008 + u16 tmp;
1994 2009 if (!test_and_set_bit(0, &dinfo->irq_flags)) {
1995 2010 if (request_irq(dinfo->pdev->irq, intelfbhw_irq, IRQF_SHARED,
1996   - "intelfb", dinfo)) {
  2011 + "intelfb", dinfo)) {
1997 2012 clear_bit(0, &dinfo->irq_flags);
1998 2013 return -EINVAL;
1999 2014 }
2000 2015  
2001 2016 spin_lock_irq(&dinfo->int_lock);
2002   - OUTREG16(HWSTAM, 0xfffe);
2003   - OUTREG16(IMR, 0x0);
2004   - OUTREG16(IER, VSYNC_PIPE_A_INTERRUPT);
2005   - spin_unlock_irq(&dinfo->int_lock);
2006   - } else if (reenable) {
2007   - u16 ier;
2008   -
  2017 + OUTREG16(HWSTAM, 0xfffe); /* i830 DRM uses ffff */
  2018 + OUTREG16(IMR, 0);
  2019 + } else
2009 2020 spin_lock_irq(&dinfo->int_lock);
2010   - ier = INREG16(IER);
2011   - if ((ier & VSYNC_PIPE_A_INTERRUPT)) {
2012   - DBG_MSG("someone disabled the IRQ [%08X]\n", ier);
2013   - OUTREG(IER, VSYNC_PIPE_A_INTERRUPT);
2014   - }
2015   - spin_unlock_irq(&dinfo->int_lock);
  2021 +
  2022 + if (dinfo->info->var.vmode & FB_VMODE_INTERLACED)
  2023 + tmp = PIPE_A_EVENT_INTERRUPT;
  2024 + else
  2025 + tmp = VSYNC_PIPE_A_INTERRUPT; /* non-interlaced */
  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 2032 return 0;
2018 2033 }
2019 2034  
2020   -void
2021   -intelfbhw_disable_irq(struct intelfb_info *dinfo) {
2022   -
  2035 +void intelfbhw_disable_irq(struct intelfb_info *dinfo)
  2036 +{
2023 2037 if (test_and_clear_bit(0, &dinfo->irq_flags)) {
2024 2038 if (dinfo->vsync.pan_display) {
2025 2039 dinfo->vsync.pan_display = 0;
... ... @@ -2051,7 +2065,7 @@
2051 2065 return -ENODEV;
2052 2066 }
2053 2067  
2054   - ret = intelfbhw_enable_irq(dinfo, 0);
  2068 + ret = intelfbhw_enable_irq(dinfo);
2055 2069 if (ret)
2056 2070 return ret;
2057 2071  
... ... @@ -2061,7 +2075,6 @@
2061 2075 if (ret < 0)
2062 2076 return ret;
2063 2077 if (ret == 0) {
2064   - intelfbhw_enable_irq(dinfo, 1);
2065 2078 DBG_MSG("wait_for_vsync timed out!\n");
2066 2079 return -ETIMEDOUT;
2067 2080 }
drivers/video/intelfb/intelfbhw.h
... ... @@ -280,6 +280,9 @@
280 280 #define PIPEB_DSL 0x71000
281 281 #define PIPEACONF 0x70008
282 282 #define PIPEBCONF 0x71008
  283 +#define PIPEASTAT 0x70024 /* bits 0-15 are "write 1 to clear" */
  284 +#define PIPEBSTAT 0x71024
  285 +
283 286 #define PIPECONF_ENABLE (1 << 31)
284 287 #define PIPECONF_DISABLE 0
285 288 #define PIPECONF_DOUBLE_WIDE (1 << 30)
... ... @@ -293,6 +296,31 @@
293 296 #define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21)
294 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 324 #define DISPARB 0x70030
297 325 #define DISPARB_AEND_MASK 0x1ff
298 326 #define DISPARB_AEND_SHIFT 0
... ... @@ -573,7 +601,7 @@
573 601 extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width,
574 602 int height, u8 *data);
575 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 605 extern void intelfbhw_disable_irq(struct intelfb_info *dinfo);
578 606 extern int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe);
579 607  
... ... @@ -207,6 +207,7 @@
207 207 #define FB_VMODE_NONINTERLACED 0 /* non interlaced */
208 208 #define FB_VMODE_INTERLACED 1 /* interlaced */
209 209 #define FB_VMODE_DOUBLE 2 /* double scan */
  210 +#define FB_VMODE_ODD_FLD_FIRST 4 /* interlaced: top line first */
210 211 #define FB_VMODE_MASK 255
211 212  
212 213 #define FB_VMODE_YWRAP 256 /* ywrap instead of panning */