Commit 394d3af7ba9e67d630c1c6d2ac1d9c11b318b73e
Committed by
Linus Torvalds
1 parent
28ebe4f66b
Exists in
master
and in
7 other branches
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 |
include/linux/fb.h
... | ... | @@ -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 */ |