aboutsummaryrefslogtreecommitdiff
path: root/drivers/video/intelfb/intelfbhw.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/intelfb/intelfbhw.c')
-rw-r--r--drivers/video/intelfb/intelfbhw.c318
1 files changed, 161 insertions, 157 deletions
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 6a47682d861..2a0e32074f7 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -56,17 +56,16 @@ static struct pll_min_max plls[PLLS_MAX] = {
6, 16, 3, 16,
4, 128, 0, 31,
930000, 1400000, 165000, 48000,
- 4, 2 }, //I8xx
+ 4, 2 }, /* I8xx */
{ 75, 120, 10, 20,
5, 9, 4, 7,
5, 80, 1, 8,
1400000, 2800000, 200000, 96000,
- 10, 5 } //I9xx
+ 10, 5 } /* I9xx */
};
-int
-intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo)
+int intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo)
{
u32 tmp;
if (!pdev || !dinfo)
@@ -149,9 +148,8 @@ intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo)
}
}
-int
-intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
- int *stolen_size)
+int intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
+ int *stolen_size)
{
struct pci_dev *bridge_dev;
u16 tmp;
@@ -254,8 +252,7 @@ intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
}
}
-int
-intelfbhw_check_non_crt(struct intelfb_info *dinfo)
+int intelfbhw_check_non_crt(struct intelfb_info *dinfo)
{
int dvo = 0;
@@ -271,8 +268,7 @@ intelfbhw_check_non_crt(struct intelfb_info *dinfo)
return dvo;
}
-const char *
-intelfbhw_dvo_to_string(int dvo)
+const char * intelfbhw_dvo_to_string(int dvo)
{
if (dvo & DVOA_PORT)
return "DVO port A";
@@ -287,9 +283,8 @@ intelfbhw_dvo_to_string(int dvo)
}
-int
-intelfbhw_validate_mode(struct intelfb_info *dinfo,
- struct fb_var_screeninfo *var)
+int intelfbhw_validate_mode(struct intelfb_info *dinfo,
+ struct fb_var_screeninfo *var)
{
int bytes_per_pixel;
int tmp;
@@ -322,17 +317,26 @@ intelfbhw_validate_mode(struct intelfb_info *dinfo,
var->yres, VACTIVE_MASK + 1);
return 1;
}
-
- /* Check for interlaced/doublescan modes. */
- if (var->vmode & FB_VMODE_INTERLACED) {
- WRN_MSG("Mode is interlaced.\n");
+ if (var->xres < 4) {
+ WRN_MSG("X resolution too small (%d vs 4).\n", var->xres);
+ return 1;
+ }
+ if (var->yres < 4) {
+ WRN_MSG("Y resolution too small (%d vs 4).\n", var->yres);
return 1;
}
+
+ /* Check for doublescan modes. */
if (var->vmode & FB_VMODE_DOUBLE) {
WRN_MSG("Mode is double-scan.\n");
return 1;
}
+ if ((var->vmode & FB_VMODE_INTERLACED) && (var->yres & 1)) {
+ WRN_MSG("Odd number of lines in interlaced mode\n");
+ return 1;
+ }
+
/* Check if clock is OK. */
tmp = 1000000000 / var->pixclock;
if (tmp < MIN_CLOCK) {
@@ -349,8 +353,7 @@ intelfbhw_validate_mode(struct intelfb_info *dinfo,
return 0;
}
-int
-intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+int intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
{
struct intelfb_info *dinfo = GET_DINFO(info);
u32 offset, xoffset, yoffset;
@@ -372,9 +375,10 @@ intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
offset += dinfo->fb.offset << 12;
dinfo->vsync.pan_offset = offset;
- if ((var->activate & FB_ACTIVATE_VBL) && !intelfbhw_enable_irq(dinfo, 0)) {
+ if ((var->activate & FB_ACTIVATE_VBL) &&
+ !intelfbhw_enable_irq(dinfo))
dinfo->vsync.pan_display = 1;
- } else {
+ else {
dinfo->vsync.pan_display = 0;
OUTREG(DSPABASE, offset);
}
@@ -383,8 +387,7 @@ intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
}
/* Blank the screen. */
-void
-intelfbhw_do_blank(int blank, struct fb_info *info)
+void intelfbhw_do_blank(int blank, struct fb_info *info)
{
struct intelfb_info *dinfo = GET_DINFO(info);
u32 tmp;
@@ -409,11 +412,10 @@ intelfbhw_do_blank(int blank, struct fb_info *info)
DBG_MSG("cursor_on is %d\n", dinfo->cursor_on);
#endif
if (dinfo->cursor_on) {
- if (blank) {
+ if (blank)
intelfbhw_cursor_hide(dinfo);
- } else {
+ else
intelfbhw_cursor_show(dinfo);
- }
dinfo->cursor_on = 1;
}
dinfo->cursor_blanked = blank;
@@ -441,19 +443,18 @@ intelfbhw_do_blank(int blank, struct fb_info *info)
}
-void
-intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno,
- unsigned red, unsigned green, unsigned blue,
- unsigned transp)
+void intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno,
+ unsigned red, unsigned green, unsigned blue,
+ unsigned transp)
{
+ u32 palette_reg = (dinfo->pipe == PIPE_A) ?
+ PALETTE_A : PALETTE_B;
+
#if VERBOSE > 0
DBG_MSG("intelfbhw_setcolreg: %d: (%d, %d, %d)\n",
regno, red, green, blue);
#endif
- u32 palette_reg = (dinfo->pipe == PIPE_A) ?
- PALETTE_A : PALETTE_B;
-
OUTREG(palette_reg + (regno << 2),
(red << PALETTE_8_RED_SHIFT) |
(green << PALETTE_8_GREEN_SHIFT) |
@@ -461,9 +462,8 @@ intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno,
}
-int
-intelfbhw_read_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
- int flag)
+int intelfbhw_read_hw_state(struct intelfb_info *dinfo,
+ struct intelfb_hwstate *hw, int flag)
{
int i;
@@ -610,7 +610,8 @@ static int calc_vclock3(int index, int m, int n, int p)
return plls[index].ref_clk * m / n / p;
}
-static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2, int lvds)
+static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2,
+ int lvds)
{
struct pll_min_max *pll = &plls[index];
u32 m, vco, p;
@@ -619,17 +620,16 @@ static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2, int lvd
n += 2;
vco = pll->ref_clk * m / n;
- if (index == PLLS_I8xx) {
+ if (index == PLLS_I8xx)
p = ((p1 + 2) * (1 << (p2 + 1)));
- } else {
+ else
p = ((p1) * (p2 ? 5 : 10));
- }
return vco / p;
}
#if REGDUMP
-static void
-intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2)
+static void intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll,
+ int *o_p1, int *o_p2)
{
int p1, p2;
@@ -638,7 +638,7 @@ intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2)
p1 = 1;
else
p1 = (dpll >> DPLL_P1_SHIFT) & 0xff;
-
+
p1 = ffs(p1);
p2 = (dpll >> DPLL_I9XX_P2_SHIFT) & DPLL_P2_MASK;
@@ -656,8 +656,8 @@ intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2)
#endif
-void
-intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
+void intelfbhw_print_hw_state(struct intelfb_info *dinfo,
+ struct intelfb_hwstate *hw)
{
#if REGDUMP
int i, m1, m2, n, p1, p2;
@@ -670,7 +670,7 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
printk("hw state dump start\n");
printk(" VGA0_DIVISOR: 0x%08x\n", hw->vga0_divisor);
printk(" VGA1_DIVISOR: 0x%08x\n", hw->vga1_divisor);
- printk(" VGAPD: 0x%08x\n", hw->vga_pd);
+ printk(" VGAPD: 0x%08x\n", hw->vga_pd);
n = (hw->vga0_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
m1 = (hw->vga0_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
m2 = (hw->vga0_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
@@ -689,7 +689,8 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
intelfbhw_get_p1p2(dinfo, hw->vga_pd, &p1, &p2);
printk(" VGA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
m1, m2, n, p1, p2);
- printk(" VGA1: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2, 0));
+ printk(" VGA1: clock is %d\n",
+ calc_vclock(index, m1, m2, n, p1, p2, 0));
printk(" DPLL_A: 0x%08x\n", hw->dpll_a);
printk(" DPLL_B: 0x%08x\n", hw->dpll_b);
@@ -706,7 +707,8 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
printk(" PLLA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
m1, m2, n, p1, p2);
- printk(" PLLA0: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2, 0));
+ printk(" PLLA0: clock is %d\n",
+ calc_vclock(index, m1, m2, n, p1, p2, 0));
n = (hw->fpa1 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
m1 = (hw->fpa1 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
@@ -716,7 +718,8 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
printk(" PLLA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
m1, m2, n, p1, p2);
- printk(" PLLA1: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2, 0));
+ printk(" PLLA1: clock is %d\n",
+ calc_vclock(index, m1, m2, n, p1, p2, 0));
#if 0
printk(" PALETTE_A:\n");
@@ -821,8 +824,8 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
/* Split the M parameter into M1 and M2. */
-static int
-splitm(int index, unsigned int m, unsigned int *retm1, unsigned int *retm2)
+static int splitm(int index, unsigned int m, unsigned int *retm1,
+ unsigned int *retm2)
{
int m1, m2;
int testm;
@@ -843,8 +846,8 @@ splitm(int index, unsigned int m, unsigned int *retm1, unsigned int *retm2)
}
/* Split the P parameter into P1 and P2. */
-static int
-splitp(int index, unsigned int p, unsigned int *retp1, unsigned int *retp2)
+static int splitp(int index, unsigned int p, unsigned int *retp1,
+ unsigned int *retp2)
{
int p1, p2;
struct pll_min_max *pll = &plls[index];
@@ -878,9 +881,8 @@ splitp(int index, unsigned int p, unsigned int *retp1, unsigned int *retp2)
}
}
-static int
-calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1,
- u32 *retp2, u32 *retclock)
+static int calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2,
+ u32 *retn, u32 *retp1, u32 *retp2, u32 *retclock)
{
u32 m1, m2, n, p1, p2, n1, testm;
u32 f_vco, p, p_best = 0, m, f_out = 0;
@@ -975,8 +977,8 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re
return 0;
}
-static __inline__ int
-check_overflow(u32 value, u32 limit, const char *description)
+static __inline__ int check_overflow(u32 value, u32 limit,
+ const char *description)
{
if (value > limit) {
WRN_MSG("%s value %d exceeds limit %d\n",
@@ -987,9 +989,9 @@ check_overflow(u32 value, u32 limit, const char *description)
}
/* It is assumed that hw is filled in with the initial state information. */
-int
-intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
- struct fb_var_screeninfo *var)
+int intelfbhw_mode_to_hw(struct intelfb_info *dinfo,
+ struct intelfb_hwstate *hw,
+ struct fb_var_screeninfo *var)
{
int pipe = PIPE_A;
u32 *dpll, *fp0, *fp1;
@@ -1093,9 +1095,8 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
if (IS_I9XX(dinfo)) {
*dpll |= (p2 << DPLL_I9XX_P2_SHIFT);
*dpll |= (1 << (p1 - 1)) << DPLL_P1_SHIFT;
- } else {
+ } else
*dpll |= (p2 << DPLL_P2_SHIFT) | (p1 << DPLL_P1_SHIFT);
- }
*fp0 = (n << FP_N_DIVISOR_SHIFT) |
(m1 << FP_M1_DIVISOR_SHIFT) |
@@ -1139,6 +1140,8 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
hblank_end);
vactive = var->yres;
+ if (var->vmode & FB_VMODE_INTERLACED)
+ vactive--; /* the chip adds 2 halflines automatically */
vsync_start = vactive + var->lower_margin;
vsync_end = vsync_start + var->vsync_len;
vtotal = vsync_end + var->upper_margin;
@@ -1220,19 +1223,24 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
/* Set the palette to 8-bit mode. */
*pipe_conf &= ~PIPECONF_GAMMA;
+
+ if (var->vmode & FB_VMODE_INTERLACED)
+ *pipe_conf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
+ else
+ *pipe_conf &= ~PIPECONF_INTERLACE_MASK;
+
return 0;
}
/* Program a (non-VGA) video mode. */
-int
-intelfbhw_program_mode(struct intelfb_info *dinfo,
- const struct intelfb_hwstate *hw, int blank)
+int intelfbhw_program_mode(struct intelfb_info *dinfo,
+ const struct intelfb_hwstate *hw, int blank)
{
int pipe = PIPE_A;
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;
@@ -1273,6 +1281,7 @@ 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;
@@ -1296,6 +1305,7 @@ 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;
@@ -1312,8 +1322,8 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
count = 0;
do {
- tmp_val[count%3] = INREG(0x70000);
- if ((tmp_val[0] == tmp_val[1]) && (tmp_val[1]==tmp_val[2]))
+ tmp_val[count % 3] = INREG(PIPEA_DSL);
+ if ((tmp_val[0] == tmp_val[1]) && (tmp_val[1] == tmp_val[2]))
break;
count++;
udelay(1);
@@ -1322,7 +1332,7 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
tmp &= ~PIPECONF_ENABLE;
OUTREG(pipe_conf_reg, tmp);
}
- } while(count < 2000);
+ } while (count < 2000);
OUTREG(ADPA, INREG(ADPA) & ~ADPA_DAC_ENABLE);
@@ -1382,6 +1392,17 @@ 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);
@@ -1446,8 +1467,7 @@ static u32 get_ring_space(struct intelfb_info *dinfo)
return ring_space;
}
-static int
-wait_ring(struct intelfb_info *dinfo, int n)
+static int wait_ring(struct intelfb_info *dinfo, int n)
{
int i = 0;
unsigned long end;
@@ -1489,16 +1509,15 @@ wait_ring(struct intelfb_info *dinfo, int n)
return i;
}
-static void
-do_flush(struct intelfb_info *dinfo) {
+static void do_flush(struct intelfb_info *dinfo)
+{
START_RING(2);
OUT_RING(MI_FLUSH | MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE);
OUT_RING(MI_NOOP);
ADVANCE_RING();
}
-void
-intelfbhw_do_sync(struct intelfb_info *dinfo)
+void intelfbhw_do_sync(struct intelfb_info *dinfo)
{
#if VERBOSE > 0
DBG_MSG("intelfbhw_do_sync\n");
@@ -1517,8 +1536,7 @@ intelfbhw_do_sync(struct intelfb_info *dinfo)
dinfo->ring_space = dinfo->ring.size - RING_MIN_FREE;
}
-static void
-refresh_ring(struct intelfb_info *dinfo)
+static void refresh_ring(struct intelfb_info *dinfo)
{
#if VERBOSE > 0
DBG_MSG("refresh_ring\n");
@@ -1529,8 +1547,7 @@ refresh_ring(struct intelfb_info *dinfo)
dinfo->ring_space = get_ring_space(dinfo);
}
-static void
-reset_state(struct intelfb_info *dinfo)
+static void reset_state(struct intelfb_info *dinfo)
{
int i;
u32 tmp;
@@ -1560,12 +1577,11 @@ reset_state(struct intelfb_info *dinfo)
}
/* Stop the 2D engine, and turn off the ring buffer. */
-void
-intelfbhw_2d_stop(struct intelfb_info *dinfo)
+void intelfbhw_2d_stop(struct intelfb_info *dinfo)
{
#if VERBOSE > 0
- DBG_MSG("intelfbhw_2d_stop: accel: %d, ring_active: %d\n", dinfo->accel,
- dinfo->ring_active);
+ DBG_MSG("intelfbhw_2d_stop: accel: %d, ring_active: %d\n",
+ dinfo->accel, dinfo->ring_active);
#endif
if (!dinfo->accel)
@@ -1580,8 +1596,7 @@ intelfbhw_2d_stop(struct intelfb_info *dinfo)
* It is assumed that the graphics engine has been stopped by previously
* calling intelfb_2d_stop().
*/
-void
-intelfbhw_2d_start(struct intelfb_info *dinfo)
+void intelfbhw_2d_start(struct intelfb_info *dinfo)
{
#if VERBOSE > 0
DBG_MSG("intelfbhw_2d_start: accel: %d, ring_active: %d\n",
@@ -1605,9 +1620,8 @@ intelfbhw_2d_start(struct intelfb_info *dinfo)
}
/* 2D fillrect (solid fill or invert) */
-void
-intelfbhw_do_fillrect(struct intelfb_info *dinfo, u32 x, u32 y, u32 w, u32 h,
- u32 color, u32 pitch, u32 bpp, u32 rop)
+void intelfbhw_do_fillrect(struct intelfb_info *dinfo, u32 x, u32 y, u32 w,
+ u32 h, u32 color, u32 pitch, u32 bpp, u32 rop)
{
u32 br00, br09, br13, br14, br16;
@@ -1696,9 +1710,9 @@ intelfbhw_do_bitblt(struct intelfb_info *dinfo, u32 curx, u32 cury,
ADVANCE_RING();
}
-int
-intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg, u32 w,
- u32 h, const u8* cdat, u32 x, u32 y, u32 pitch, u32 bpp)
+int intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg, u32 w,
+ u32 h, const u8* cdat, u32 x, u32 y, u32 pitch,
+ u32 bpp)
{
int nbytes, ndwords, pad, tmp;
u32 br00, br09, br13, br18, br19, br22, br23;
@@ -1785,8 +1799,7 @@ intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg, u32 w,
}
/* HW cursor functions. */
-void
-intelfbhw_cursor_init(struct intelfb_info *dinfo)
+void intelfbhw_cursor_init(struct intelfb_info *dinfo)
{
u32 tmp;
@@ -1817,8 +1830,7 @@ intelfbhw_cursor_init(struct intelfb_info *dinfo)
}
}
-void
-intelfbhw_cursor_hide(struct intelfb_info *dinfo)
+void intelfbhw_cursor_hide(struct intelfb_info *dinfo)
{
u32 tmp;
@@ -1843,8 +1855,7 @@ intelfbhw_cursor_hide(struct intelfb_info *dinfo)
}
}
-void
-intelfbhw_cursor_show(struct intelfb_info *dinfo)
+void intelfbhw_cursor_show(struct intelfb_info *dinfo)
{
u32 tmp;
@@ -1873,8 +1884,7 @@ intelfbhw_cursor_show(struct intelfb_info *dinfo)
}
}
-void
-intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y)
+void intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y)
{
u32 tmp;
@@ -1892,13 +1902,11 @@ intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y)
((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
OUTREG(CURSOR_A_POSITION, tmp);
- if (IS_I9XX(dinfo)) {
+ if (IS_I9XX(dinfo))
OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical);
- }
}
-void
-intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, u32 fg)
+void intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, u32 fg)
{
#if VERBOSE > 0
DBG_MSG("intelfbhw_cursor_setcolor\n");
@@ -1910,9 +1918,8 @@ intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, u32 fg)
OUTREG(CURSOR_A_PALETTE3, bg & CURSOR_PALETTE_MASK);
}
-void
-intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, int height,
- u8 *data)
+void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, int height,
+ u8 *data)
{
u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual;
int i, j, w = width / 8;
@@ -1940,8 +1947,8 @@ intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, int height,
}
}
-void
-intelfbhw_cursor_reset(struct intelfb_info *dinfo) {
+void intelfbhw_cursor_reset(struct intelfb_info *dinfo)
+{
u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual;
int i, j;
@@ -1961,72 +1968,72 @@ 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;
-
+ 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) {
- u16 tmp;
-
+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;
@@ -2037,16 +2044,15 @@ intelfbhw_disable_irq(struct intelfb_info *dinfo) {
OUTREG16(IMR, 0xffff);
OUTREG16(IER, 0x0);
- tmp = INREG16(IIR);
- OUTREG16(IIR, tmp);
+ OUTREG16(IIR, INREG16(IIR)); /* clear IRQ requests */
spin_unlock_irq(&dinfo->int_lock);
free_irq(dinfo->pdev->irq, dinfo);
}
}
-int
-intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe) {
+int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe)
+{
struct intelfb_vsync *vsync;
unsigned int count;
int ret;
@@ -2059,18 +2065,16 @@ intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe) {
return -ENODEV;
}
- ret = intelfbhw_enable_irq(dinfo, 0);
- if (ret) {
+ ret = intelfbhw_enable_irq(dinfo);
+ if (ret)
return ret;
- }
count = vsync->count;
- ret = wait_event_interruptible_timeout(vsync->wait, count != vsync->count, HZ/10);
- if (ret < 0) {
+ ret = wait_event_interruptible_timeout(vsync->wait,
+ count != vsync->count, HZ / 10);
+ if (ret < 0)
return ret;
- }
if (ret == 0) {
- intelfbhw_enable_irq(dinfo, 1);
DBG_MSG("wait_for_vsync timed out!\n");
return -ETIMEDOUT;
}