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>
This commit is contained in:
parent
28ebe4f66b
commit
394d3af7ba
|
@ -376,7 +376,7 @@ int intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
|
|||
|
||||
dinfo->vsync.pan_offset = offset;
|
||||
if ((var->activate & FB_ACTIVATE_VBL) &&
|
||||
!intelfbhw_enable_irq(dinfo, 0))
|
||||
!intelfbhw_enable_irq(dinfo))
|
||||
dinfo->vsync.pan_display = 1;
|
||||
else {
|
||||
dinfo->vsync.pan_display = 0;
|
||||
|
@ -1240,7 +1240,7 @@ int intelfbhw_program_mode(struct intelfb_info *dinfo,
|
|||
u32 tmp;
|
||||
const u32 *dpll, *fp0, *fp1, *pipe_conf;
|
||||
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 vsync_reg, vtotal_reg, vblank_reg;
|
||||
u32 src_size_reg;
|
||||
|
@ -1281,6 +1281,7 @@ int intelfbhw_program_mode(struct intelfb_info *dinfo,
|
|||
fp0_reg = FPB0;
|
||||
fp1_reg = FPB1;
|
||||
pipe_conf_reg = PIPEBCONF;
|
||||
pipe_stat_reg = PIPEBSTAT;
|
||||
hsync_reg = HSYNC_B;
|
||||
htotal_reg = HTOTAL_B;
|
||||
hblank_reg = HBLANK_B;
|
||||
|
@ -1304,6 +1305,7 @@ int intelfbhw_program_mode(struct intelfb_info *dinfo,
|
|||
fp0_reg = FPA0;
|
||||
fp1_reg = FPA1;
|
||||
pipe_conf_reg = PIPEACONF;
|
||||
pipe_stat_reg = PIPEASTAT;
|
||||
hsync_reg = HSYNC_A;
|
||||
htotal_reg = HTOTAL_A;
|
||||
hblank_reg = HBLANK_A;
|
||||
|
@ -1390,6 +1392,17 @@ int intelfbhw_program_mode(struct intelfb_info *dinfo,
|
|||
OUTREG(vtotal_reg, *vt);
|
||||
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 */
|
||||
OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE);
|
||||
|
||||
|
@ -1955,71 +1968,72 @@ void intelfbhw_cursor_reset(struct intelfb_info *dinfo)
|
|||
}
|
||||
}
|
||||
|
||||
static irqreturn_t
|
||||
intelfbhw_irq(int irq, void *dev_id) {
|
||||
int handled = 0;
|
||||
static irqreturn_t intelfbhw_irq(int irq, void *dev_id)
|
||||
{
|
||||
u16 tmp;
|
||||
struct intelfb_info *dinfo = (struct intelfb_info *)dev_id;
|
||||
|
||||
spin_lock(&dinfo->int_lock);
|
||||
|
||||
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) {
|
||||
spin_unlock(&dinfo->int_lock);
|
||||
return IRQ_RETVAL(handled);
|
||||
return IRQ_RETVAL(0); /* not us */
|
||||
}
|
||||
|
||||
/* clear status bits 0-15 ASAP and don't touch bits 16-31 */
|
||||
OUTREG(PIPEASTAT, INREG(PIPEASTAT));
|
||||
|
||||
OUTREG16(IIR, tmp);
|
||||
|
||||
if (tmp & VSYNC_PIPE_A_INTERRUPT) {
|
||||
dinfo->vsync.count++;
|
||||
if (dinfo->vsync.pan_display) {
|
||||
dinfo->vsync.pan_display = 0;
|
||||
OUTREG(DSPABASE, dinfo->vsync.pan_offset);
|
||||
}
|
||||
wake_up_interruptible(&dinfo->vsync.wait);
|
||||
handled = 1;
|
||||
if (dinfo->vsync.pan_display) {
|
||||
dinfo->vsync.pan_display = 0;
|
||||
OUTREG(DSPABASE, dinfo->vsync.pan_offset);
|
||||
}
|
||||
|
||||
dinfo->vsync.count++;
|
||||
wake_up_interruptible(&dinfo->vsync.wait);
|
||||
|
||||
spin_unlock(&dinfo->int_lock);
|
||||
|
||||
return IRQ_RETVAL(handled);
|
||||
return IRQ_RETVAL(1);
|
||||
}
|
||||
|
||||
int
|
||||
intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable) {
|
||||
|
||||
int intelfbhw_enable_irq(struct intelfb_info *dinfo)
|
||||
{
|
||||
u16 tmp;
|
||||
if (!test_and_set_bit(0, &dinfo->irq_flags)) {
|
||||
if (request_irq(dinfo->pdev->irq, intelfbhw_irq, IRQF_SHARED,
|
||||
"intelfb", dinfo)) {
|
||||
"intelfb", dinfo)) {
|
||||
clear_bit(0, &dinfo->irq_flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irq(&dinfo->int_lock);
|
||||
OUTREG16(HWSTAM, 0xfffe);
|
||||
OUTREG16(IMR, 0x0);
|
||||
OUTREG16(IER, VSYNC_PIPE_A_INTERRUPT);
|
||||
spin_unlock_irq(&dinfo->int_lock);
|
||||
} else if (reenable) {
|
||||
u16 ier;
|
||||
|
||||
OUTREG16(HWSTAM, 0xfffe); /* i830 DRM uses ffff */
|
||||
OUTREG16(IMR, 0);
|
||||
} else
|
||||
spin_lock_irq(&dinfo->int_lock);
|
||||
ier = INREG16(IER);
|
||||
if ((ier & VSYNC_PIPE_A_INTERRUPT)) {
|
||||
DBG_MSG("someone disabled the IRQ [%08X]\n", ier);
|
||||
OUTREG(IER, VSYNC_PIPE_A_INTERRUPT);
|
||||
}
|
||||
spin_unlock_irq(&dinfo->int_lock);
|
||||
|
||||
if (dinfo->info->var.vmode & FB_VMODE_INTERLACED)
|
||||
tmp = PIPE_A_EVENT_INTERRUPT;
|
||||
else
|
||||
tmp = VSYNC_PIPE_A_INTERRUPT; /* non-interlaced */
|
||||
if (tmp != INREG16(IER)) {
|
||||
DBG_MSG("changing IER to 0x%X\n", tmp);
|
||||
OUTREG16(IER, tmp);
|
||||
}
|
||||
|
||||
spin_unlock_irq(&dinfo->int_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
intelfbhw_disable_irq(struct intelfb_info *dinfo) {
|
||||
|
||||
void intelfbhw_disable_irq(struct intelfb_info *dinfo)
|
||||
{
|
||||
if (test_and_clear_bit(0, &dinfo->irq_flags)) {
|
||||
if (dinfo->vsync.pan_display) {
|
||||
dinfo->vsync.pan_display = 0;
|
||||
|
@ -2051,7 +2065,7 @@ int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = intelfbhw_enable_irq(dinfo, 0);
|
||||
ret = intelfbhw_enable_irq(dinfo);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -2061,7 +2075,6 @@ int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret == 0) {
|
||||
intelfbhw_enable_irq(dinfo, 1);
|
||||
DBG_MSG("wait_for_vsync timed out!\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
|
|
@ -280,6 +280,9 @@
|
|||
#define PIPEB_DSL 0x71000
|
||||
#define PIPEACONF 0x70008
|
||||
#define PIPEBCONF 0x71008
|
||||
#define PIPEASTAT 0x70024 /* bits 0-15 are "write 1 to clear" */
|
||||
#define PIPEBSTAT 0x71024
|
||||
|
||||
#define PIPECONF_ENABLE (1 << 31)
|
||||
#define PIPECONF_DISABLE 0
|
||||
#define PIPECONF_DOUBLE_WIDE (1 << 30)
|
||||
|
@ -293,6 +296,31 @@
|
|||
#define PIPECONF_INTERLACE_FIELD_0_ONLY (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_AEND_MASK 0x1ff
|
||||
#define DISPARB_AEND_SHIFT 0
|
||||
|
@ -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,
|
||||
int height, u8 *data);
|
||||
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 int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe);
|
||||
|
||||
|
|
|
@ -207,6 +207,7 @@ struct fb_bitfield {
|
|||
#define FB_VMODE_NONINTERLACED 0 /* non interlaced */
|
||||
#define FB_VMODE_INTERLACED 1 /* interlaced */
|
||||
#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_YWRAP 256 /* ywrap instead of panning */
|
||||
|
|
Loading…
Reference in a new issue