Skip to content

Commit

Permalink
drm/i915: properly compute dp dithering for user-created modes
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Daniel Vetter committed Apr 10, 2012
1 parent 14667a4 commit c486793
Showing 1 changed file with 35 additions and 14 deletions.
49 changes: 35 additions & 14 deletions drivers/gpu/drm/i915/intel_dp.c
Original file line number Diff line number Diff line change
Expand Up @@ -219,14 +219,38 @@ intel_dp_max_data_rate(int max_link_clock, int max_lanes)
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)
Expand All @@ -236,16 +260,8 @@ intel_dp_mode_valid(struct drm_connector *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;
Expand Down Expand Up @@ -672,7 +688,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
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) {
Expand All @@ -686,6 +702,11 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
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);
Expand Down

0 comments on commit c486793

Please sign in to comment.