Skip to content

Commit

Permalink
fbdev: Distinguish between interlaced and progressive modes
Browse files Browse the repository at this point in the history
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: Fredrik Noring <noring@nocrew.org>
Cc: "Maciej W. Rozycki" <macro@linux-mips.org>
[b.zolnierkie: updated patch description]
Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
  • Loading branch information
Fredrik Noring authored and Bartlomiej Zolnierkiewicz committed Jul 24, 2018
1 parent 34db50e commit 1ba0a59
Showing 1 changed file with 30 additions and 11 deletions.
41 changes: 30 additions & 11 deletions drivers/video/fbdev/core/modedb.c
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,7 @@ static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info,
*
* 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>]
*
* with <xres>, <yres>, <bpp> and <refresh> decimal numbers and
Expand All @@ -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),
* the function will compute the timings using VESA(tm) Coordinated
* Video Timings (CVT). If 'R' is present after 'M', will compute with
* reduced blanking (for flatpanels). If 'i' is present, compute
* interlaced mode. If 'm' is present, add margins equal to 1.8%
* of xres rounded down to 8 pixels, and 1.8% of yres. The char
* 'i' and 'm' must be after 'M' and 'R'. Example:
* reduced blanking (for flatpanels). If 'i' or 'p' are present, compute
* interlaced or progressive mode. If 'm' is present, add margins equal
* to 1.8% of xres rounded down to 8 pixels, and 1.8% of yres. The chars
* 'i', 'p' and 'm' must be after 'M' and 'R'. Example:
*
* 1024x768MR-8@60m - Reduced blank with margins at 60Hz.
*
Expand Down Expand Up @@ -697,7 +697,8 @@ int fb_find_mode(struct fb_var_screeninfo *var,
unsigned int namelen = strlen(name);
int res_specified = 0, bpp_specified = 0, refresh_specified = 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;
u32 best, diff, tdiff;

Expand Down Expand Up @@ -748,9 +749,17 @@ int fb_find_mode(struct fb_var_screeninfo *var,
if (!cvt)
margins = 1;
break;
case 'p':
if (!cvt) {
interlace = 0;
interlace_specified = 1;
}
break;
case 'i':
if (!cvt)
if (!cvt) {
interlace = 1;
interlace_specified = 1;
}
break;
default:
goto done;
Expand Down Expand Up @@ -819,11 +828,21 @@ int fb_find_mode(struct fb_var_screeninfo *var,
if ((name_matches(db[i], name, namelen) ||
(res_specified && res_matches(db[i], xres, yres))) &&
!fb_try_mode(var, info, &db[i], bpp)) {
if (refresh_specified && db[i].refresh == refresh)
return 1;
const int db_interlace = (db[i].vmode &
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) {
diff = abs(db[i].refresh - refresh);
if (score < diff) {
diff = score;
best = i;
}
}
Expand Down

0 comments on commit 1ba0a59

Please sign in to comment.