Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

intelfb: fix setting of active pipe with LVDS displays

The intelfb driver sets color map depending on currently active pipe.
However, if an LVDS display is attached (like in laptop) the active pipe
variable is never set. The default value is PIPE_A and can be wrong. Set
up the pipe variable during driver initialization after hardware state was
read.

Also, the detection of the active display (and hence the pipe) is wrong.
The pipes are assigned to so called planes. Both pipes are always enabled
on my laptop but only one plane is enabled (the plane A for the CRT or the
plane B for the LVDS). Change active pipe detection code to take into
account a status of the plane assigned to each pipe.

The problem is visible in the 8 bpp mode if colors above 15 are used. The
first 16 color entries are displayed correctly.

The graphics chip description is here (G45 vol. 3):
http://intellinuxgraphics.org/documentation.html

Addresses http://bugzilla.kernel.org/show_bug.cgi?id=13285

Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl>
Cc: Michal Suchanek <hramrach@centrum.cz>
Cc: Dean Menezes <samanddeanus@yahoo.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Krzysztof Helt and committed by
Linus Torvalds
cfbd646f e6bf0d2c

+34 -17
+3
drivers/video/intelfb/intelfbdrv.c
··· 874 874 if (bailearly == 18) 875 875 bailout(dinfo); 876 876 877 + /* read active pipe */ 878 + dinfo->pipe = intelfbhw_active_pipe(&dinfo->save_state); 879 + 877 880 /* Cursor initialisation */ 878 881 if (dinfo->hwcursor) { 879 882 intelfbhw_cursor_init(dinfo);
+30 -17
drivers/video/intelfb/intelfbhw.c
··· 469 469 } 470 470 471 471 472 + /* Check which pipe is connected to an active display plane. */ 473 + int intelfbhw_active_pipe(const struct intelfb_hwstate *hw) 474 + { 475 + int pipe = -1; 476 + 477 + /* keep old default behaviour - prefer PIPE_A */ 478 + if (hw->disp_b_ctrl & DISPPLANE_PLANE_ENABLE) { 479 + pipe = (hw->disp_b_ctrl >> DISPPLANE_SEL_PIPE_SHIFT); 480 + pipe &= PIPE_MASK; 481 + if (unlikely(pipe == PIPE_A)) 482 + return PIPE_A; 483 + } 484 + if (hw->disp_a_ctrl & DISPPLANE_PLANE_ENABLE) { 485 + pipe = (hw->disp_a_ctrl >> DISPPLANE_SEL_PIPE_SHIFT); 486 + pipe &= PIPE_MASK; 487 + if (likely(pipe == PIPE_A)) 488 + return PIPE_A; 489 + } 490 + /* Impossible that no pipe is selected - return PIPE_A */ 491 + WARN_ON(pipe == -1); 492 + if (unlikely(pipe == -1)) 493 + pipe = PIPE_A; 494 + 495 + return pipe; 496 + } 497 + 472 498 void intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno, 473 499 unsigned red, unsigned green, unsigned blue, 474 500 unsigned transp) ··· 1045 1019 struct intelfb_hwstate *hw, 1046 1020 struct fb_var_screeninfo *var) 1047 1021 { 1048 - int pipe = PIPE_A; 1022 + int pipe = intelfbhw_active_pipe(hw); 1049 1023 u32 *dpll, *fp0, *fp1; 1050 1024 u32 m1, m2, n, p1, p2, clock_target, clock; 1051 1025 u32 hsync_start, hsync_end, hblank_start, hblank_end, htotal, hactive; ··· 1058 1032 1059 1033 /* Disable VGA */ 1060 1034 hw->vgacntrl |= VGA_DISABLE; 1061 - 1062 - /* Check whether pipe A or pipe B is enabled. */ 1063 - if (hw->pipe_a_conf & PIPECONF_ENABLE) 1064 - pipe = PIPE_A; 1065 - else if (hw->pipe_b_conf & PIPECONF_ENABLE) 1066 - pipe = PIPE_B; 1067 1035 1068 1036 /* Set which pipe's registers will be set. */ 1069 1037 if (pipe == PIPE_B) { ··· 1282 1262 int intelfbhw_program_mode(struct intelfb_info *dinfo, 1283 1263 const struct intelfb_hwstate *hw, int blank) 1284 1264 { 1285 - int pipe = PIPE_A; 1286 1265 u32 tmp; 1287 1266 const u32 *dpll, *fp0, *fp1, *pipe_conf; 1288 1267 const u32 *hs, *ht, *hb, *vs, *vt, *vb, *ss; ··· 1291 1272 u32 src_size_reg; 1292 1273 u32 count, tmp_val[3]; 1293 1274 1294 - /* Assume single pipe, display plane A, analog CRT. */ 1275 + /* Assume single pipe */ 1295 1276 1296 1277 #if VERBOSE > 0 1297 1278 DBG_MSG("intelfbhw_program_mode\n"); ··· 1302 1283 tmp |= VGA_DISABLE; 1303 1284 OUTREG(VGACNTRL, tmp); 1304 1285 1305 - /* Check whether pipe A or pipe B is enabled. */ 1306 - if (hw->pipe_a_conf & PIPECONF_ENABLE) 1307 - pipe = PIPE_A; 1308 - else if (hw->pipe_b_conf & PIPECONF_ENABLE) 1309 - pipe = PIPE_B; 1286 + dinfo->pipe = intelfbhw_active_pipe(hw); 1310 1287 1311 - dinfo->pipe = pipe; 1312 - 1313 - if (pipe == PIPE_B) { 1288 + if (dinfo->pipe == PIPE_B) { 1314 1289 dpll = &hw->dpll_b; 1315 1290 fp0 = &hw->fpb0; 1316 1291 fp1 = &hw->fpb1;
+1
drivers/video/intelfb/intelfbhw.h
··· 604 604 extern int intelfbhw_enable_irq(struct intelfb_info *dinfo); 605 605 extern void intelfbhw_disable_irq(struct intelfb_info *dinfo); 606 606 extern int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe); 607 + extern int intelfbhw_active_pipe(const struct intelfb_hwstate *hw); 607 608 608 609 #endif /* _INTELFBHW_H */