| From c4867936474183332db4c19791a65fdad6474fd5 Mon Sep 17 00:00:00 2001 |
| From: Daniel Vetter <daniel.vetter@ffwll.ch> |
| Date: Tue, 10 Apr 2012 10:42:36 +0200 |
| Subject: drm/i915: properly compute dp dithering for user-created modes |
| |
| From: Daniel Vetter <daniel.vetter@ffwll.ch> |
| |
| commit c4867936474183332db4c19791a65fdad6474fd5 upstream. |
| |
| We've only computed whether we need to fall back to 6bpc due to dp |
| link bandwidth constrains in mode_valid, but not mode_fixup. Under |
| various circumstances X likes to create new modes which then lack |
| proper 6bpc flags (if required), resulting in mode_fixup failures and |
| ultimately black screens. |
| |
| Chris Wilson pointed out that we still get things wrong for bpp > 24, |
| but that should be fixed in another patch (and it'll be easier because |
| this patch consolidates the logic). |
| |
| The likely culprit for this regression is |
| |
| commit 3d794f87238f74d80e78a7611c7fbde8a54c85c2 |
| Author: Keith Packard <keithp@keithp.com> |
| Date: Wed Jan 25 08:16:25 2012 -0800 |
| |
| drm/i915: Force explicit bpp selection for intel_dp_link_required |
| |
| v2: Fix indentation and tune down the too bold claim that this should |
| fix the world. Both noticed by Chris Wilson. |
| |
| v3: Try to really git add things. |
| |
| Reported-and-tested-by: Brice Goglin <Brice.Goglin@ens-lyon.org> |
| Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=48170 |
| Cc: stable@kernel.org |
| Reviewed-by: Adam Jackson <ajax@redhat.com> |
| Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/gpu/drm/i915/intel_dp.c | 49 ++++++++++++++++++++++++++++------------ |
| 1 file changed, 35 insertions(+), 14 deletions(-) |
| |
| --- a/drivers/gpu/drm/i915/intel_dp.c |
| +++ b/drivers/gpu/drm/i915/intel_dp.c |
| @@ -219,14 +219,38 @@ intel_dp_max_data_rate(int max_link_cloc |
| return (max_link_clock * max_lanes * 8) / 10; |
| } |
| |
| +static bool |
| +intel_dp_adjust_dithering(struct intel_dp *intel_dp, |
| + struct drm_display_mode *mode, |
| + struct drm_display_mode *adjusted_mode) |
| +{ |
| + int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp)); |
| + int max_lanes = intel_dp_max_lane_count(intel_dp); |
| + int max_rate, mode_rate; |
| + |
| + mode_rate = intel_dp_link_required(mode->clock, 24); |
| + max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes); |
| + |
| + if (mode_rate > max_rate) { |
| + mode_rate = intel_dp_link_required(mode->clock, 18); |
| + if (mode_rate > max_rate) |
| + return false; |
| + |
| + if (adjusted_mode) |
| + adjusted_mode->private_flags |
| + |= INTEL_MODE_DP_FORCE_6BPC; |
| + |
| + return true; |
| + } |
| + |
| + return true; |
| +} |
| + |
| static int |
| intel_dp_mode_valid(struct drm_connector *connector, |
| struct drm_display_mode *mode) |
| { |
| struct intel_dp *intel_dp = intel_attached_dp(connector); |
| - int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp)); |
| - int max_lanes = intel_dp_max_lane_count(intel_dp); |
| - int max_rate, mode_rate; |
| |
| if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) { |
| if (mode->hdisplay > intel_dp->panel_fixed_mode->hdisplay) |
| @@ -236,16 +260,8 @@ intel_dp_mode_valid(struct drm_connector |
| return MODE_PANEL; |
| } |
| |
| - mode_rate = intel_dp_link_required(mode->clock, 24); |
| - max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes); |
| - |
| - if (mode_rate > max_rate) { |
| - mode_rate = intel_dp_link_required(mode->clock, 18); |
| - if (mode_rate > max_rate) |
| - return MODE_CLOCK_HIGH; |
| - else |
| - mode->private_flags |= INTEL_MODE_DP_FORCE_6BPC; |
| - } |
| + if (!intel_dp_adjust_dithering(intel_dp, mode, NULL)) |
| + return MODE_CLOCK_HIGH; |
| |
| if (mode->clock < 10000) |
| return MODE_CLOCK_LOW; |
| @@ -673,7 +689,7 @@ intel_dp_mode_fixup(struct drm_encoder * |
| int lane_count, clock; |
| int max_lane_count = intel_dp_max_lane_count(intel_dp); |
| int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0; |
| - int bpp = mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 24; |
| + int bpp; |
| static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 }; |
| |
| if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) { |
| @@ -687,6 +703,11 @@ intel_dp_mode_fixup(struct drm_encoder * |
| mode->clock = intel_dp->panel_fixed_mode->clock; |
| } |
| |
| + if (!intel_dp_adjust_dithering(intel_dp, mode, adjusted_mode)) |
| + return false; |
| + |
| + bpp = adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 24; |
| + |
| for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) { |
| for (clock = 0; clock <= max_clock; clock++) { |
| int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count); |