Commit c7c53dc8 authored by Fredrik Noring's avatar Fredrik Noring Committed by Greg Kroah-Hartman

fbdev: Distinguish between interlaced and progressive modes

[ Upstream commit 1ba0a59c ]

I discovered the problem when developing a frame buffer driver for the
PlayStation 2 (not yet merged), using the following video modes for the
PlayStation 3 in drivers/video/fbdev/ps3fb.c:

    }, {
        /* 1080if */
        "1080if", 50, 1920, 1080, 13468, 148, 484, 36, 4, 88, 5,
        FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
    }, {
        /* 1080pf */
        "1080pf", 50, 1920, 1080, 6734, 148, 484, 36, 4, 88, 5,
        FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
    },

In ps3fb_probe, the mode_option module parameter is used with fb_find_mode
but it can only select the interlaced variant of 1920x1080 since the loop
matching the modes does not take the difference between interlaced and
progressive modes into account.

In short, without the patch, progressive 1920x1080 cannot be chosen as a
mode_option parameter since fb_find_mode (falsely) thinks interlace is a
perfect match.
Signed-off-by: default avatarFredrik Noring <noring@nocrew.org>
Cc: "Maciej W. Rozycki" <macro@linux-mips.org>
[b.zolnierkie: updated patch description]
Signed-off-by: default avatarBartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
Signed-off-by: default avatarSasha Levin <alexander.levin@microsoft.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 0b339773
...@@ -644,7 +644,7 @@ static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info, ...@@ -644,7 +644,7 @@ static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info,
* *
* Valid mode specifiers for @mode_option: * Valid mode specifiers for @mode_option:
* *
* <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m] or * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][p][m] or
* <name>[-<bpp>][@<refresh>] * <name>[-<bpp>][@<refresh>]
* *
* with <xres>, <yres>, <bpp> and <refresh> decimal numbers and * with <xres>, <yres>, <bpp> and <refresh> decimal numbers and
...@@ -653,10 +653,10 @@ static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info, ...@@ -653,10 +653,10 @@ static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info,
* If 'M' is present after yres (and before refresh/bpp if present), * If 'M' is present after yres (and before refresh/bpp if present),
* the function will compute the timings using VESA(tm) Coordinated * the function will compute the timings using VESA(tm) Coordinated
* Video Timings (CVT). If 'R' is present after 'M', will compute with * Video Timings (CVT). If 'R' is present after 'M', will compute with
* reduced blanking (for flatpanels). If 'i' is present, compute * reduced blanking (for flatpanels). If 'i' or 'p' are present, compute
* interlaced mode. If 'm' is present, add margins equal to 1.8% * interlaced or progressive mode. If 'm' is present, add margins equal
* of xres rounded down to 8 pixels, and 1.8% of yres. The char * to 1.8% of xres rounded down to 8 pixels, and 1.8% of yres. The chars
* 'i' and 'm' must be after 'M' and 'R'. Example: * 'i', 'p' and 'm' must be after 'M' and 'R'. Example:
* *
* 1024x768MR-8@60m - Reduced blank with margins at 60Hz. * 1024x768MR-8@60m - Reduced blank with margins at 60Hz.
* *
...@@ -697,7 +697,8 @@ int fb_find_mode(struct fb_var_screeninfo *var, ...@@ -697,7 +697,8 @@ int fb_find_mode(struct fb_var_screeninfo *var,
unsigned int namelen = strlen(name); unsigned int namelen = strlen(name);
int res_specified = 0, bpp_specified = 0, refresh_specified = 0; int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0; unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0;
int yres_specified = 0, cvt = 0, rb = 0, interlace = 0; int yres_specified = 0, cvt = 0, rb = 0;
int interlace_specified = 0, interlace = 0;
int margins = 0; int margins = 0;
u32 best, diff, tdiff; u32 best, diff, tdiff;
...@@ -748,9 +749,17 @@ int fb_find_mode(struct fb_var_screeninfo *var, ...@@ -748,9 +749,17 @@ int fb_find_mode(struct fb_var_screeninfo *var,
if (!cvt) if (!cvt)
margins = 1; margins = 1;
break; break;
case 'p':
if (!cvt) {
interlace = 0;
interlace_specified = 1;
}
break;
case 'i': case 'i':
if (!cvt) if (!cvt) {
interlace = 1; interlace = 1;
interlace_specified = 1;
}
break; break;
default: default:
goto done; goto done;
...@@ -819,11 +828,21 @@ int fb_find_mode(struct fb_var_screeninfo *var, ...@@ -819,11 +828,21 @@ int fb_find_mode(struct fb_var_screeninfo *var,
if ((name_matches(db[i], name, namelen) || if ((name_matches(db[i], name, namelen) ||
(res_specified && res_matches(db[i], xres, yres))) && (res_specified && res_matches(db[i], xres, yres))) &&
!fb_try_mode(var, info, &db[i], bpp)) { !fb_try_mode(var, info, &db[i], bpp)) {
if (refresh_specified && db[i].refresh == refresh) const int db_interlace = (db[i].vmode &
return 1; FB_VMODE_INTERLACED ? 1 : 0);
int score = abs(db[i].refresh - refresh);
if (interlace_specified)
score += abs(db_interlace - interlace);
if (!interlace_specified ||
db_interlace == interlace)
if (refresh_specified &&
db[i].refresh == refresh)
return 1;
if (abs(db[i].refresh - refresh) < diff) { if (score < diff) {
diff = abs(db[i].refresh - refresh); diff = score;
best = i; best = i;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment