Commit 394d3af7 authored by Krzysztof Halasa's avatar Krzysztof Halasa Committed by Linus Torvalds

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: default avatarKrzysztof Halasa <khc@pm.waw.pl>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Cc: <sylvain.meyer@worldonline.fr>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 28ebe4f6
...@@ -376,7 +376,7 @@ int intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) ...@@ -376,7 +376,7 @@ int intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
dinfo->vsync.pan_offset = offset; dinfo->vsync.pan_offset = offset;
if ((var->activate & FB_ACTIVATE_VBL) && if ((var->activate & FB_ACTIVATE_VBL) &&
!intelfbhw_enable_irq(dinfo, 0)) !intelfbhw_enable_irq(dinfo))
dinfo->vsync.pan_display = 1; dinfo->vsync.pan_display = 1;
else { else {
dinfo->vsync.pan_display = 0; dinfo->vsync.pan_display = 0;
...@@ -1240,7 +1240,7 @@ int intelfbhw_program_mode(struct intelfb_info *dinfo, ...@@ -1240,7 +1240,7 @@ int intelfbhw_program_mode(struct intelfb_info *dinfo,
u32 tmp; u32 tmp;
const u32 *dpll, *fp0, *fp1, *pipe_conf; const u32 *dpll, *fp0, *fp1, *pipe_conf;
const u32 *hs, *ht, *hb, *vs, *vt, *vb, *ss; const u32 *hs, *ht, *hb, *vs, *vt, *vb, *ss;
u32 dpll_reg, fp0_reg, fp1_reg, pipe_conf_reg; u32 dpll_reg, fp0_reg, fp1_reg, pipe_conf_reg, pipe_stat_reg;
u32 hsync_reg, htotal_reg, hblank_reg; u32 hsync_reg, htotal_reg, hblank_reg;
u32 vsync_reg, vtotal_reg, vblank_reg; u32 vsync_reg, vtotal_reg, vblank_reg;
u32 src_size_reg; u32 src_size_reg;
...@@ -1281,6 +1281,7 @@ int intelfbhw_program_mode(struct intelfb_info *dinfo, ...@@ -1281,6 +1281,7 @@ int intelfbhw_program_mode(struct intelfb_info *dinfo,
fp0_reg = FPB0; fp0_reg = FPB0;
fp1_reg = FPB1; fp1_reg = FPB1;
pipe_conf_reg = PIPEBCONF; pipe_conf_reg = PIPEBCONF;
pipe_stat_reg = PIPEBSTAT;
hsync_reg = HSYNC_B; hsync_reg = HSYNC_B;
htotal_reg = HTOTAL_B; htotal_reg = HTOTAL_B;
hblank_reg = HBLANK_B; hblank_reg = HBLANK_B;
...@@ -1304,6 +1305,7 @@ int intelfbhw_program_mode(struct intelfb_info *dinfo, ...@@ -1304,6 +1305,7 @@ int intelfbhw_program_mode(struct intelfb_info *dinfo,
fp0_reg = FPA0; fp0_reg = FPA0;
fp1_reg = FPA1; fp1_reg = FPA1;
pipe_conf_reg = PIPEACONF; pipe_conf_reg = PIPEACONF;
pipe_stat_reg = PIPEASTAT;
hsync_reg = HSYNC_A; hsync_reg = HSYNC_A;
htotal_reg = HTOTAL_A; htotal_reg = HTOTAL_A;
hblank_reg = HBLANK_A; hblank_reg = HBLANK_A;
...@@ -1390,6 +1392,17 @@ int intelfbhw_program_mode(struct intelfb_info *dinfo, ...@@ -1390,6 +1392,17 @@ int intelfbhw_program_mode(struct intelfb_info *dinfo,
OUTREG(vtotal_reg, *vt); OUTREG(vtotal_reg, *vt);
OUTREG(src_size_reg, *ss); OUTREG(src_size_reg, *ss);
switch (dinfo->info->var.vmode & (FB_VMODE_INTERLACED |
FB_VMODE_ODD_FLD_FIRST)) {
case FB_VMODE_INTERLACED | FB_VMODE_ODD_FLD_FIRST:
OUTREG(pipe_stat_reg, 0xFFFF | PIPESTAT_FLD_EVT_ODD_EN);
break;
case FB_VMODE_INTERLACED: /* even lines first */
OUTREG(pipe_stat_reg, 0xFFFF | PIPESTAT_FLD_EVT_EVEN_EN);
break;
default: /* non-interlaced */
OUTREG(pipe_stat_reg, 0xFFFF); /* clear all status bits only */
}
/* Enable pipe */ /* Enable pipe */
OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE); OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE);
...@@ -1955,71 +1968,72 @@ void intelfbhw_cursor_reset(struct intelfb_info *dinfo) ...@@ -1955,71 +1968,72 @@ void intelfbhw_cursor_reset(struct intelfb_info *dinfo)
} }
} }
static irqreturn_t static irqreturn_t intelfbhw_irq(int irq, void *dev_id)
intelfbhw_irq(int irq, void *dev_id) { {
int handled = 0;
u16 tmp; u16 tmp;
struct intelfb_info *dinfo = (struct intelfb_info *)dev_id; struct intelfb_info *dinfo = (struct intelfb_info *)dev_id;
spin_lock(&dinfo->int_lock); spin_lock(&dinfo->int_lock);
tmp = INREG16(IIR); tmp = INREG16(IIR);
tmp &= VSYNC_PIPE_A_INTERRUPT; if (dinfo->info->var.vmode & FB_VMODE_INTERLACED)
tmp &= PIPE_A_EVENT_INTERRUPT;
else
tmp &= VSYNC_PIPE_A_INTERRUPT; /* non-interlaced */
if (tmp == 0) { if (tmp == 0) {
spin_unlock(&dinfo->int_lock); spin_unlock(&dinfo->int_lock);
return IRQ_RETVAL(handled); return IRQ_RETVAL(0); /* not us */
} }
OUTREG16(IIR, tmp); /* clear status bits 0-15 ASAP and don't touch bits 16-31 */
OUTREG(PIPEASTAT, INREG(PIPEASTAT));
if (tmp & VSYNC_PIPE_A_INTERRUPT) { OUTREG16(IIR, tmp);
dinfo->vsync.count++; if (dinfo->vsync.pan_display) {
if (dinfo->vsync.pan_display) { dinfo->vsync.pan_display = 0;
dinfo->vsync.pan_display = 0; OUTREG(DSPABASE, dinfo->vsync.pan_offset);
OUTREG(DSPABASE, dinfo->vsync.pan_offset);
}
wake_up_interruptible(&dinfo->vsync.wait);
handled = 1;
} }
dinfo->vsync.count++;
wake_up_interruptible(&dinfo->vsync.wait);
spin_unlock(&dinfo->int_lock); spin_unlock(&dinfo->int_lock);
return IRQ_RETVAL(handled); return IRQ_RETVAL(1);
} }
int int intelfbhw_enable_irq(struct intelfb_info *dinfo)
intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable) { {
u16 tmp;
if (!test_and_set_bit(0, &dinfo->irq_flags)) { if (!test_and_set_bit(0, &dinfo->irq_flags)) {
if (request_irq(dinfo->pdev->irq, intelfbhw_irq, IRQF_SHARED, if (request_irq(dinfo->pdev->irq, intelfbhw_irq, IRQF_SHARED,
"intelfb", dinfo)) { "intelfb", dinfo)) {
clear_bit(0, &dinfo->irq_flags); clear_bit(0, &dinfo->irq_flags);
return -EINVAL; return -EINVAL;
} }
spin_lock_irq(&dinfo->int_lock); spin_lock_irq(&dinfo->int_lock);
OUTREG16(HWSTAM, 0xfffe); OUTREG16(HWSTAM, 0xfffe); /* i830 DRM uses ffff */
OUTREG16(IMR, 0x0); OUTREG16(IMR, 0);
OUTREG16(IER, VSYNC_PIPE_A_INTERRUPT); } else
spin_unlock_irq(&dinfo->int_lock);
} else if (reenable) {
u16 ier;
spin_lock_irq(&dinfo->int_lock); spin_lock_irq(&dinfo->int_lock);
ier = INREG16(IER);
if ((ier & VSYNC_PIPE_A_INTERRUPT)) { if (dinfo->info->var.vmode & FB_VMODE_INTERLACED)
DBG_MSG("someone disabled the IRQ [%08X]\n", ier); tmp = PIPE_A_EVENT_INTERRUPT;
OUTREG(IER, VSYNC_PIPE_A_INTERRUPT); else
} tmp = VSYNC_PIPE_A_INTERRUPT; /* non-interlaced */
spin_unlock_irq(&dinfo->int_lock); if (tmp != INREG16(IER)) {
DBG_MSG("changing IER to 0x%X\n", tmp);
OUTREG16(IER, tmp);
} }
spin_unlock_irq(&dinfo->int_lock);
return 0; return 0;
} }
void void intelfbhw_disable_irq(struct intelfb_info *dinfo)
intelfbhw_disable_irq(struct intelfb_info *dinfo) { {
if (test_and_clear_bit(0, &dinfo->irq_flags)) { if (test_and_clear_bit(0, &dinfo->irq_flags)) {
if (dinfo->vsync.pan_display) { if (dinfo->vsync.pan_display) {
dinfo->vsync.pan_display = 0; dinfo->vsync.pan_display = 0;
...@@ -2051,7 +2065,7 @@ int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe) ...@@ -2051,7 +2065,7 @@ int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe)
return -ENODEV; return -ENODEV;
} }
ret = intelfbhw_enable_irq(dinfo, 0); ret = intelfbhw_enable_irq(dinfo);
if (ret) if (ret)
return ret; return ret;
...@@ -2061,7 +2075,6 @@ int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe) ...@@ -2061,7 +2075,6 @@ int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe)
if (ret < 0) if (ret < 0)
return ret; return ret;
if (ret == 0) { if (ret == 0) {
intelfbhw_enable_irq(dinfo, 1);
DBG_MSG("wait_for_vsync timed out!\n"); DBG_MSG("wait_for_vsync timed out!\n");
return -ETIMEDOUT; return -ETIMEDOUT;
} }
......
...@@ -280,6 +280,9 @@ ...@@ -280,6 +280,9 @@
#define PIPEB_DSL 0x71000 #define PIPEB_DSL 0x71000
#define PIPEACONF 0x70008 #define PIPEACONF 0x70008
#define PIPEBCONF 0x71008 #define PIPEBCONF 0x71008
#define PIPEASTAT 0x70024 /* bits 0-15 are "write 1 to clear" */
#define PIPEBSTAT 0x71024
#define PIPECONF_ENABLE (1 << 31) #define PIPECONF_ENABLE (1 << 31)
#define PIPECONF_DISABLE 0 #define PIPECONF_DISABLE 0
#define PIPECONF_DOUBLE_WIDE (1 << 30) #define PIPECONF_DOUBLE_WIDE (1 << 30)
...@@ -293,6 +296,31 @@ ...@@ -293,6 +296,31 @@
#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21) #define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21)
#define PIPECONF_INTERLACE_MASK (7 << 21) #define PIPECONF_INTERLACE_MASK (7 << 21)
/* enable bits, write 1 to enable */
#define PIPESTAT_FIFO_UNDERRUN (1 << 31)
#define PIPESTAT_CRC_ERROR_EN (1 << 29)
#define PIPESTAT_CRC_DONE_EN (1 << 28)
#define PIPESTAT_HOTPLUG_EN (1 << 26)
#define PIPESTAT_VERTICAL_SYNC_EN (1 << 25)
#define PIPESTAT_DISPLINE_COMP_EN (1 << 24)
#define PIPESTAT_FLD_EVT_ODD_EN (1 << 21)
#define PIPESTAT_FLD_EVT_EVEN_EN (1 << 20)
#define PIPESTAT_TV_HOTPLUG_EN (1 << 18)
#define PIPESTAT_VBLANK_EN (1 << 17)
#define PIPESTAT_OVL_UPDATE_EN (1 << 16)
/* status bits, write 1 to clear */
#define PIPESTAT_HOTPLUG_STATE (1 << 15)
#define PIPESTAT_CRC_ERROR (1 << 13)
#define PIPESTAT_CRC_DONE (1 << 12)
#define PIPESTAT_HOTPLUG (1 << 10)
#define PIPESTAT_VSYNC (1 << 9)
#define PIPESTAT_DISPLINE_COMP (1 << 8)
#define PIPESTAT_FLD_EVT_ODD (1 << 5)
#define PIPESTAT_FLD_EVT_EVEN (1 << 4)
#define PIPESTAT_TV_HOTPLUG (1 << 2)
#define PIPESTAT_VBLANK (1 << 1)
#define PIPESTAT_OVL_UPDATE (1 << 0)
#define DISPARB 0x70030 #define DISPARB 0x70030
#define DISPARB_AEND_MASK 0x1ff #define DISPARB_AEND_MASK 0x1ff
#define DISPARB_AEND_SHIFT 0 #define DISPARB_AEND_SHIFT 0
...@@ -573,7 +601,7 @@ extern void intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, ...@@ -573,7 +601,7 @@ extern void intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg,
extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width,
int height, u8 *data); int height, u8 *data);
extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo); extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo);
extern int intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable); extern int intelfbhw_enable_irq(struct intelfb_info *dinfo);
extern void intelfbhw_disable_irq(struct intelfb_info *dinfo); extern void intelfbhw_disable_irq(struct intelfb_info *dinfo);
extern int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe); extern int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe);
......
...@@ -207,6 +207,7 @@ struct fb_bitfield { ...@@ -207,6 +207,7 @@ struct fb_bitfield {
#define FB_VMODE_NONINTERLACED 0 /* non interlaced */ #define FB_VMODE_NONINTERLACED 0 /* non interlaced */
#define FB_VMODE_INTERLACED 1 /* interlaced */ #define FB_VMODE_INTERLACED 1 /* interlaced */
#define FB_VMODE_DOUBLE 2 /* double scan */ #define FB_VMODE_DOUBLE 2 /* double scan */
#define FB_VMODE_ODD_FLD_FIRST 4 /* interlaced: top line first */
#define FB_VMODE_MASK 255 #define FB_VMODE_MASK 255
#define FB_VMODE_YWRAP 256 /* ywrap instead of panning */ #define FB_VMODE_YWRAP 256 /* ywrap instead of panning */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment