drm/edid: Fix up clock for CEA/HDMI modes specified via detailed timings
EDID detailed timings have a resolution of 10kHz for the pixel clock, so they can't represent certain CEA/HDMI modes accurately. If we see a mode coming in via detailed timings which otherwise matches one of the CEA/HDMI modes except the clock is just a bit off, let's assume that the intention was for that mode to be one of the CEA/HDMI modes and go ahead and fix up the clock to match the CEA/HDMI spec exactly (well, as close as we can get with the 1 kHz resolution we use). This should help code that's looking for an exact clock match (eg. i915 audio N/CTS setup). Cc: Adam Jackson <ajax@redhat.com> Cc: Clint Taylor <clinton.a.taylor@intel.com> Cc: Libin Yang <libin.yang@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
parent
affa0e033b
commit
fa3a7340ea
|
@ -2418,6 +2418,8 @@ add_cvt_modes(struct drm_connector *connector, struct edid *edid)
|
|||
return closure.modes;
|
||||
}
|
||||
|
||||
static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode);
|
||||
|
||||
static void
|
||||
do_detailed_mode(struct detailed_timing *timing, void *c)
|
||||
{
|
||||
|
@ -2434,6 +2436,13 @@ do_detailed_mode(struct detailed_timing *timing, void *c)
|
|||
if (closure->preferred)
|
||||
newmode->type |= DRM_MODE_TYPE_PREFERRED;
|
||||
|
||||
/*
|
||||
* Detailed modes are limited to 10kHz pixel clock resolution,
|
||||
* so fix up anything that looks like CEA/HDMI mode, but the clock
|
||||
* is just slightly off.
|
||||
*/
|
||||
fixup_detailed_cea_mode_clock(newmode);
|
||||
|
||||
drm_mode_probed_add(closure->connector, newmode);
|
||||
closure->modes++;
|
||||
closure->preferred = 0;
|
||||
|
@ -3103,6 +3112,45 @@ add_cea_modes(struct drm_connector *connector, struct edid *edid)
|
|||
return modes;
|
||||
}
|
||||
|
||||
static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode)
|
||||
{
|
||||
const struct drm_display_mode *cea_mode;
|
||||
int clock1, clock2, clock;
|
||||
u8 mode_idx;
|
||||
const char *type;
|
||||
|
||||
mode_idx = drm_match_cea_mode(mode) - 1;
|
||||
if (mode_idx < ARRAY_SIZE(edid_cea_modes)) {
|
||||
type = "CEA";
|
||||
cea_mode = &edid_cea_modes[mode_idx];
|
||||
clock1 = cea_mode->clock;
|
||||
clock2 = cea_mode_alternate_clock(cea_mode);
|
||||
} else {
|
||||
mode_idx = drm_match_hdmi_mode(mode) - 1;
|
||||
if (mode_idx < ARRAY_SIZE(edid_4k_modes)) {
|
||||
type = "HDMI";
|
||||
cea_mode = &edid_4k_modes[mode_idx];
|
||||
clock1 = cea_mode->clock;
|
||||
clock2 = hdmi_mode_alternate_clock(cea_mode);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* pick whichever is closest */
|
||||
if (abs(mode->clock - clock1) < abs(mode->clock - clock2))
|
||||
clock = clock1;
|
||||
else
|
||||
clock = clock2;
|
||||
|
||||
if (mode->clock == clock)
|
||||
return;
|
||||
|
||||
DRM_DEBUG("detailed mode matches %s VIC %d, adjusting clock %d -> %d\n",
|
||||
type, mode_idx + 1, mode->clock, clock);
|
||||
mode->clock = clock;
|
||||
}
|
||||
|
||||
static void
|
||||
parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue