aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_edid.c
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2015-11-16 14:05:12 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2015-12-01 01:57:14 -0500
commit4c6bcf44549907cb50b67f98eb13717a4adc6b33 (patch)
tree1b2d0b895c0c6a2891359526455637eba1a5649f /drivers/gpu/drm/drm_edid.c
parent6753ba97e78bb0ed5c0ed35c21c1e2a31f7299a0 (diff)
drm/edid: Make the detailed timing CEA/HDMI mode fixup accept up to 5kHz clock difference
Rather than using drm_match_cea_mode() to see if the EDID detailed timings are supposed to represent one of the CEA/HDMI modes, add a special version of that function that takes in an explicit clock tolerance value (in kHz). When looking at the detailed timings specify the tolerance as 5kHz due to the 10kHz clock resolution limit inherent in detailed timings. drm_match_cea_mode() uses the normal KHZ2PICOS() matching of clocks, which only allows smaller errors for lower clocks (eg. for 25200 it won't allow any error) and a bigger error for higher clocks (eg. for 297000 it actually matches 296913-297000). So it doesn't really match what we want for the fixup. Using the explicit +-5kHz is much better for this use case. Not sure if we should change the normal mode matching to also use something else besides KHZ2PICOS() since it allows a different proportion of error depending on the clock. I believe VESA CVT allows a maximum deviation of .5%, so using that for normal mode matching might be a good idea? Cc: Adam Jackson <ajax@redhat.com> Tested-by: nathan.d.ciobanu@linux.intel.com Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=92217 Fixes: fa3a7340eaa1 ("drm/edid: Fix up clock for CEA/HDMI modes specified via detailed timings") 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>
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
-rw-r--r--drivers/gpu/drm/drm_edid.c62
1 files changed, 60 insertions, 2 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index d5d2c03fd136..c214f1246cb4 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -2545,6 +2545,33 @@ cea_mode_alternate_clock(const struct drm_display_mode *cea_mode)
2545 return clock; 2545 return clock;
2546} 2546}
2547 2547
2548static u8 drm_match_cea_mode_clock_tolerance(const struct drm_display_mode *to_match,
2549 unsigned int clock_tolerance)
2550{
2551 u8 mode;
2552
2553 if (!to_match->clock)
2554 return 0;
2555
2556 for (mode = 0; mode < ARRAY_SIZE(edid_cea_modes); mode++) {
2557 const struct drm_display_mode *cea_mode = &edid_cea_modes[mode];
2558 unsigned int clock1, clock2;
2559
2560 /* Check both 60Hz and 59.94Hz */
2561 clock1 = cea_mode->clock;
2562 clock2 = cea_mode_alternate_clock(cea_mode);
2563
2564 if (abs(to_match->clock - clock1) > clock_tolerance &&
2565 abs(to_match->clock - clock2) > clock_tolerance)
2566 continue;
2567
2568 if (drm_mode_equal_no_clocks(to_match, cea_mode))
2569 return mode + 1;
2570 }
2571
2572 return 0;
2573}
2574
2548/** 2575/**
2549 * drm_match_cea_mode - look for a CEA mode matching given mode 2576 * drm_match_cea_mode - look for a CEA mode matching given mode
2550 * @to_match: display mode 2577 * @to_match: display mode
@@ -2609,6 +2636,33 @@ hdmi_mode_alternate_clock(const struct drm_display_mode *hdmi_mode)
2609 return cea_mode_alternate_clock(hdmi_mode); 2636 return cea_mode_alternate_clock(hdmi_mode);
2610} 2637}
2611 2638
2639static u8 drm_match_hdmi_mode_clock_tolerance(const struct drm_display_mode *to_match,
2640 unsigned int clock_tolerance)
2641{
2642 u8 mode;
2643
2644 if (!to_match->clock)
2645 return 0;
2646
2647 for (mode = 0; mode < ARRAY_SIZE(edid_4k_modes); mode++) {
2648 const struct drm_display_mode *hdmi_mode = &edid_4k_modes[mode];
2649 unsigned int clock1, clock2;
2650
2651 /* Make sure to also match alternate clocks */
2652 clock1 = hdmi_mode->clock;
2653 clock2 = hdmi_mode_alternate_clock(hdmi_mode);
2654
2655 if (abs(to_match->clock - clock1) > clock_tolerance &&
2656 abs(to_match->clock - clock2) > clock_tolerance)
2657 continue;
2658
2659 if (drm_mode_equal_no_clocks(to_match, hdmi_mode))
2660 return mode + 1;
2661 }
2662
2663 return 0;
2664}
2665
2612/* 2666/*
2613 * drm_match_hdmi_mode - look for a HDMI mode matching given mode 2667 * drm_match_hdmi_mode - look for a HDMI mode matching given mode
2614 * @to_match: display mode 2668 * @to_match: display mode
@@ -3119,14 +3173,18 @@ static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode)
3119 u8 mode_idx; 3173 u8 mode_idx;
3120 const char *type; 3174 const char *type;
3121 3175
3122 mode_idx = drm_match_cea_mode(mode) - 1; 3176 /*
3177 * allow 5kHz clock difference either way to account for
3178 * the 10kHz clock resolution limit of detailed timings.
3179 */
3180 mode_idx = drm_match_cea_mode_clock_tolerance(mode, 5) - 1;
3123 if (mode_idx < ARRAY_SIZE(edid_cea_modes)) { 3181 if (mode_idx < ARRAY_SIZE(edid_cea_modes)) {
3124 type = "CEA"; 3182 type = "CEA";
3125 cea_mode = &edid_cea_modes[mode_idx]; 3183 cea_mode = &edid_cea_modes[mode_idx];
3126 clock1 = cea_mode->clock; 3184 clock1 = cea_mode->clock;
3127 clock2 = cea_mode_alternate_clock(cea_mode); 3185 clock2 = cea_mode_alternate_clock(cea_mode);
3128 } else { 3186 } else {
3129 mode_idx = drm_match_hdmi_mode(mode) - 1; 3187 mode_idx = drm_match_hdmi_mode_clock_tolerance(mode, 5) - 1;
3130 if (mode_idx < ARRAY_SIZE(edid_4k_modes)) { 3188 if (mode_idx < ARRAY_SIZE(edid_4k_modes)) {
3131 type = "HDMI"; 3189 type = "HDMI";
3132 cea_mode = &edid_4k_modes[mode_idx]; 3190 cea_mode = &edid_4k_modes[mode_idx];