[PATCH 4/4] 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 <[EMAIL PROTECTED]> --- 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) 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, 0x | PIPESTAT_FLD_EVT_ODD_EN); + break; + case FB_VMODE_INTERLACED: /* even lines first */ + OUTREG(pipe_stat_reg, 0x | PIPESTAT_FLD_EVT_EVEN_EN); + break; + default:/* non-interlaced */ + OUTREG(pipe_stat_reg, 0x); /* 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(>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(>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) { - dinfo->vsync.count++; - if (dinfo->vsync.pan_display) { - dinfo->vsync.pan_display = 0; - OUTREG(DSPABASE, dinfo->vsync.pan_offset); - } - wake_up_interruptible(>vsync.wait); - handled = 1; + OUTREG16(IIR, tmp); + if (dinfo->vsync.pan_display) { + dinfo->vsync.pan_display = 0; + OUTREG(DSPABASE, dinfo->vsync.pan_offset); } + dinfo->vsync.count++; + wake_up_interruptible(>vsync.wait); + spin_unlock(>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, >irq_flags)) { if (request_irq(dinfo->pdev->irq, intelfbhw_irq, IRQF_SHARED, -"intelfb", dinfo)) { + "intelfb", dinfo)) { clear_bit(0, >irq_flags); return -EINVAL; } spin_lock_irq(>int_lock); - OUTREG16(HWSTAM, 0xfffe); - OUTREG16(IMR, 0x0); - OUTREG16(IER, VSYNC_PIPE_A_INTERRUPT); - spin_unlock_irq(>int_lock); - } else if (reenable) { - u16 ier; - +
[PATCH 4/4] 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 [EMAIL PROTECTED] --- 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) 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, 0x | PIPESTAT_FLD_EVT_ODD_EN); + break; + case FB_VMODE_INTERLACED: /* even lines first */ + OUTREG(pipe_stat_reg, 0x | PIPESTAT_FLD_EVT_EVEN_EN); + break; + default:/* non-interlaced */ + OUTREG(pipe_stat_reg, 0x); /* 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 */ } - 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) { - 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; + OUTREG16(IIR, tmp); + 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; - +