Skip to content

Commit

Permalink
drm/i915/dp: Dither down to 6bpc if it makes the mode fit
Browse files Browse the repository at this point in the history
Some active adaptors (VGA usually) only have two lanes at 2.7GHz.
That's a maximum pixel clock of 144MHz at 8bpc, but 192MHz at 6bpc.

Fixes Asus UX31 panel being black at startup due to no valid modes since
dc22ee6.

v2: Rebased to current code, resulting in the fix applying to EDP panels as
    well.  Also changed from spatio-temporal to just spatial dithering on
    pre-ironlake, to be conssitent (and less visual flicker)

Signed-off-by: Adam Jackson <ajax@redhat.com>
Signed-off-by: Eric Anholt <eric@anholt.net>
Tested-by: Eric Anholt <eric@anholt.net>
Tested-by: Dirk Hohndel <hohndel@infradead.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
  • Loading branch information
Adam Jackson authored and Keith Packard committed Dec 16, 2011
1 parent f45b555 commit 3b5c78a
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 8 deletions.
22 changes: 20 additions & 2 deletions drivers/gpu/drm/i915/intel_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -4670,6 +4670,7 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
/**
* intel_choose_pipe_bpp_dither - figure out what color depth the pipe should send
* @crtc: CRTC structure
* @mode: requested mode
*
* A pipe may be connected to one or more outputs. Based on the depth of the
* attached framebuffer, choose a good color depth to use on the pipe.
Expand All @@ -4681,13 +4682,15 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
* HDMI supports only 8bpc or 12bpc, so clamp to 8bpc with dither for 10bpc
* Displays may support a restricted set as well, check EDID and clamp as
* appropriate.
* DP may want to dither down to 6bpc to fit larger modes
*
* RETURNS:
* Dithering requirement (i.e. false if display bpc and pipe bpc match,
* true if they don't match).
*/
static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
unsigned int *pipe_bpp)
unsigned int *pipe_bpp,
struct drm_display_mode *mode)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
Expand Down Expand Up @@ -4758,6 +4761,11 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
}
}

if (mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) {
DRM_DEBUG_KMS("Dithering DP to 6bpc\n");
display_bpc = 6;
}

/*
* We could just drive the pipe at the highest bpc all the time and
* enable dithering as needed, but that costs bandwidth. So choose
Expand Down Expand Up @@ -5019,6 +5027,16 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
pipeconf &= ~PIPECONF_DOUBLE_WIDE;
}

/* default to 8bpc */
pipeconf &= ~(PIPECONF_BPP_MASK | PIPECONF_DITHER_EN);
if (is_dp) {
if (mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) {
pipeconf |= PIPECONF_BPP_6 |
PIPECONF_DITHER_EN |
PIPECONF_DITHER_TYPE_SP;
}
}

dpll |= DPLL_VCO_ENABLE;

DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
Expand Down Expand Up @@ -5480,7 +5498,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
/* determine panel color depth */
temp = I915_READ(PIPECONF(pipe));
temp &= ~PIPE_BPC_MASK;
dither = intel_choose_pipe_bpp_dither(crtc, &pipe_bpp);
dither = intel_choose_pipe_bpp_dither(crtc, &pipe_bpp, mode);
switch (pipe_bpp) {
case 18:
temp |= PIPE_6BPC;
Expand Down
24 changes: 18 additions & 6 deletions drivers/gpu/drm/i915/intel_dp.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,13 +208,15 @@ intel_dp_link_clock(uint8_t link_bw)
*/

static int
intel_dp_link_required(struct intel_dp *intel_dp, int pixel_clock)
intel_dp_link_required(struct intel_dp *intel_dp, int pixel_clock, int check_bpp)
{
struct drm_crtc *crtc = intel_dp->base.base.crtc;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int bpp = 24;

if (intel_crtc)
if (check_bpp)
bpp = check_bpp;
else if (intel_crtc)
bpp = intel_crtc->bpp;

return (pixel_clock * bpp + 9) / 10;
Expand All @@ -233,6 +235,7 @@ intel_dp_mode_valid(struct drm_connector *connector,
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 @@ -242,9 +245,17 @@ intel_dp_mode_valid(struct drm_connector *connector,
return MODE_PANEL;
}

if (intel_dp_link_required(intel_dp, mode->clock)
> intel_dp_max_data_rate(max_link_clock, max_lanes))
return MODE_CLOCK_HIGH;
mode_rate = intel_dp_link_required(intel_dp, mode->clock, 0);
max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes);

if (mode_rate > max_rate) {
mode_rate = intel_dp_link_required(intel_dp,
mode->clock, 18);
if (mode_rate > max_rate)
return MODE_CLOCK_HIGH;
else
mode->private_flags |= INTEL_MODE_DP_FORCE_6BPC;
}

if (mode->clock < 10000)
return MODE_CLOCK_LOW;
Expand Down Expand Up @@ -672,6 +683,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 : 0;
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 @@ -689,7 +701,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
for (clock = 0; clock <= max_clock; clock++) {
int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count);

if (intel_dp_link_required(intel_dp, mode->clock)
if (intel_dp_link_required(intel_dp, mode->clock, bpp)
<= link_avail) {
intel_dp->link_bw = bws[clock];
intel_dp->lane_count = lane_count;
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/intel_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
/* drm_display_mode->private_flags */
#define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0)
#define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT)
#define INTEL_MODE_DP_FORCE_6BPC (0x10)

static inline void
intel_mode_set_pixel_multiplier(struct drm_display_mode *mode,
Expand Down

0 comments on commit 3b5c78a

Please sign in to comment.