aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFinn Thain <fthain@telegraphics.com.au>2009-11-03 08:43:16 -0500
committerGeert Uytterhoeven <geert@linux-m68k.org>2010-02-27 12:31:12 -0500
commitd876c11a0fd40993136f5cc1e81371ccc6c21a63 (patch)
treed2f09796146f4d8a61499759191e4cb832b1984c
parenteeb9c182a6ad8bc130377adb0a4cd7b95dd15f49 (diff)
fbdev: mac_var_to_mode() fix
The valkyriefb driver assumes that this logic holds: mac_vmode_to_var(X, cmode, &var); mac_var_to_vmode(&var, &vmode, &cmode); assert(vmode == X); But it doesn't hold because mac_var_to_vmode() can return a mode with a slower pixel clock, even when a match is available. So we end up with this failure: using video mode 11 and color mode 0. valkyriefb: vmode 12 not valid. valkyriefb: can't set default video mode valkyriefb: vmode 12 not valid. Rather than have mac_var_to_mode() return the first reasonable mode it finds, have it return the mode that is closest to the requested one (or the mode with the closest longer pixel clock period if there is no exact match). Signed-off-by: Finn Thain <fthain@telegraphics.com.au> Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
-rw-r--r--drivers/video/macmodes.c40
1 files changed, 31 insertions, 9 deletions
diff --git a/drivers/video/macmodes.c b/drivers/video/macmodes.c
index 083f60321ed8..3e11f7425aef 100644
--- a/drivers/video/macmodes.c
+++ b/drivers/video/macmodes.c
@@ -134,7 +134,7 @@ static const struct fb_videomode mac_modedb[] = {
134 * 134 *
135 * These MUST be ordered in 135 * These MUST be ordered in
136 * - increasing resolution 136 * - increasing resolution
137 * - decreasing refresh rate 137 * - decreasing pixel clock period
138 */ 138 */
139 139
140static const struct mode_map { 140static const struct mode_map {
@@ -142,20 +142,20 @@ static const struct mode_map {
142 const struct fb_videomode *mode; 142 const struct fb_videomode *mode;
143} mac_modes[] = { 143} mac_modes[] = {
144 /* 640x480 */ 144 /* 640x480 */
145 { VMODE_640_480_67, &mac_modedb[1] },
146 { VMODE_640_480_60, &mac_modedb[0] }, 145 { VMODE_640_480_60, &mac_modedb[0] },
146 { VMODE_640_480_67, &mac_modedb[1] },
147 /* 800x600 */ 147 /* 800x600 */
148 { VMODE_800_600_56, &mac_modedb[2] },
149 { VMODE_800_600_60, &mac_modedb[3] },
148 { VMODE_800_600_75, &mac_modedb[5] }, 150 { VMODE_800_600_75, &mac_modedb[5] },
149 { VMODE_800_600_72, &mac_modedb[4] }, 151 { VMODE_800_600_72, &mac_modedb[4] },
150 { VMODE_800_600_60, &mac_modedb[3] },
151 { VMODE_800_600_56, &mac_modedb[2] },
152 /* 832x624 */ 152 /* 832x624 */
153 { VMODE_832_624_75, &mac_modedb[6] }, 153 { VMODE_832_624_75, &mac_modedb[6] },
154 /* 1024x768 */ 154 /* 1024x768 */
155 { VMODE_1024_768_75, &mac_modedb[10] },
156 { VMODE_1024_768_75V, &mac_modedb[9] },
157 { VMODE_1024_768_70, &mac_modedb[8] },
158 { VMODE_1024_768_60, &mac_modedb[7] }, 155 { VMODE_1024_768_60, &mac_modedb[7] },
156 { VMODE_1024_768_70, &mac_modedb[8] },
157 { VMODE_1024_768_75V, &mac_modedb[9] },
158 { VMODE_1024_768_75, &mac_modedb[10] },
159 /* 1152x768 */ 159 /* 1152x768 */
160 { VMODE_1152_768_60, &mac_modedb[14] }, 160 { VMODE_1152_768_60, &mac_modedb[14] },
161 /* 1152x870 */ 161 /* 1152x870 */
@@ -299,7 +299,6 @@ EXPORT_SYMBOL(mac_vmode_to_var);
299int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode, 299int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode,
300 int *cmode) 300 int *cmode)
301{ 301{
302 const struct fb_videomode *mode = NULL;
303 const struct mode_map *map; 302 const struct mode_map *map;
304 303
305 if (var->bits_per_pixel <= 8) 304 if (var->bits_per_pixel <= 8)
@@ -311,8 +310,13 @@ int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode,
311 else 310 else
312 return -EINVAL; 311 return -EINVAL;
313 312
313 /*
314 * Find the mac_mode with a matching resolution or failing that, the
315 * closest larger resolution. Skip modes with a shorter pixel clock period.
316 */
314 for (map = mac_modes; map->vmode != -1; map++) { 317 for (map = mac_modes; map->vmode != -1; map++) {
315 mode = map->mode; 318 const struct fb_videomode *mode = map->mode;
319
316 if (var->xres > mode->xres || var->yres > mode->yres) 320 if (var->xres > mode->xres || var->yres > mode->yres)
317 continue; 321 continue;
318 if (var->xres_virtual > mode->xres || var->yres_virtual > mode->yres) 322 if (var->xres_virtual > mode->xres || var->yres_virtual > mode->yres)
@@ -322,6 +326,24 @@ int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode,
322 if ((var->vmode & FB_VMODE_MASK) != mode->vmode) 326 if ((var->vmode & FB_VMODE_MASK) != mode->vmode)
323 continue; 327 continue;
324 *vmode = map->vmode; 328 *vmode = map->vmode;
329
330 /*
331 * Having found a good resolution, find the matching pixel clock
332 * or failing that, the closest longer pixel clock period.
333 */
334 map++;
335 while (map->vmode != -1) {
336 const struct fb_videomode *clk_mode = map->mode;
337
338 if (mode->xres != clk_mode->xres || mode->yres != clk_mode->yres)
339 break;
340 if (var->pixclock > mode->pixclock)
341 break;
342 if (mode->vmode != clk_mode->vmode)
343 continue;
344 *vmode = map->vmode;
345 map++;
346 }
325 return 0; 347 return 0;
326 } 348 }
327 return -EINVAL; 349 return -EINVAL;