fbdev: sh_mobile_hdmi: add command line option to use the preferred EDID mode

Currently, if no command-line option is specified, the sh_mobile_hdmi
will use the default 720p video mode. If a command line option of the
form "video=sh_mobile_lcdc:<width>x<height>@<refresh>" is provided,
the driver will look for that mode among those, available in the
monitor EDID. This patch adds the ability to request the driver to
use monitor's preferred mode by specifying 0 as width and hight in
the above string. If that mode is not supported by the system, the
driver will continue scanning through EDID modes, until it finds a
suitable one.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
This commit is contained in:
Guennadi Liakhovetski 2011-01-07 11:57:55 +00:00 committed by Paul Mundt
parent e9ab320731
commit c7321d6f88

View File

@ -737,7 +737,7 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
struct fb_modelist *modelist = NULL;
unsigned int f_width = 0, f_height = 0, f_refresh = 0;
unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */
bool exact_match = false;
bool scanning = false, preferred_bad = false;
u8 edid[128];
char *forced;
int i;
@ -800,6 +800,9 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
if (i < 2) {
f_width = 0;
f_height = 0;
} else {
/* The user wants us to use the EDID data */
scanning = true;
}
dev_dbg(hdmi->dev, "Forced mode %ux%u@%uHz\n",
f_width, f_height, f_refresh);
@ -807,37 +810,56 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
/* Walk monitor modes to find the best or the exact match */
for (i = 0, mode = hdmi->monspec.modedb;
f_width && f_height && i < hdmi->monspec.modedb_len && !exact_match;
i < hdmi->monspec.modedb_len && scanning;
i++, mode++) {
unsigned long rate_error;
/* No interest in unmatching modes */
if (f_width != mode->xres || f_height != mode->yres)
if (!f_width && !f_height) {
/*
* A parameter string "video=sh_mobile_lcdc:0x0" means
* use the preferred EDID mode. If it is rejected by
* .fb_check_var(), keep looking, until an acceptable
* one is found.
*/
if ((mode->flag & FB_MODE_IS_FIRST) || preferred_bad)
scanning = false;
else
continue;
} else if (f_width != mode->xres || f_height != mode->yres) {
/* No interest in unmatching modes */
continue;
}
rate_error = sh_hdmi_rate_error(hdmi, mode, hdmi_rate, parent_rate);
if (f_refresh == mode->refresh || (!f_refresh && !rate_error))
/*
* Exact match if either the refresh rate matches or it
* hasn't been specified and we've found a mode, for
* which we can configure the clock precisely
*/
exact_match = true;
else if (found && found_rate_error <= rate_error)
/*
* We otherwise search for the closest matching clock
* rate - either if no refresh rate has been specified
* or we cannot find an exactly matching one
*/
continue;
if (scanning) {
if (f_refresh == mode->refresh || (!f_refresh && !rate_error))
/*
* Exact match if either the refresh rate
* matches or it hasn't been specified and we've
* found a mode, for which we can configure the
* clock precisely
*/
scanning = false;
else if (found && found_rate_error <= rate_error)
/*
* We otherwise search for the closest matching
* clock rate - either if no refresh rate has
* been specified or we cannot find an exactly
* matching one
*/
continue;
}
/* Check if supported: sufficient fb memory, supported clock-rate */
fb_videomode_to_var(var, mode);
var->bits_per_pixel = info->var.bits_per_pixel;
if (info && info->fbops->fb_check_var &&
info->fbops->fb_check_var(var, info)) {
exact_match = false;
scanning = true;
preferred_bad = true;
continue;
}