Commit 3b5c78a3 authored by Adam Jackson's avatar Adam Jackson Committed by Keith Packard

drm/i915/dp: Dither down to 6bpc if it makes the mode fit

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
dc22ee6f.

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: default avatarAdam Jackson <ajax@redhat.com>
Signed-off-by: default avatarEric Anholt <eric@anholt.net>
Tested-by: default avatarEric Anholt <eric@anholt.net>
Tested-by: default avatarDirk Hohndel <hohndel@infradead.org>
Signed-off-by: default avatarKeith Packard <keithp@keithp.com>
parent f45b5557
...@@ -4670,6 +4670,7 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) ...@@ -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 * intel_choose_pipe_bpp_dither - figure out what color depth the pipe should send
* @crtc: CRTC structure * @crtc: CRTC structure
* @mode: requested mode
* *
* A pipe may be connected to one or more outputs. Based on the depth of the * 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. * attached framebuffer, choose a good color depth to use on the pipe.
...@@ -4681,13 +4682,15 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) ...@@ -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 * 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 * Displays may support a restricted set as well, check EDID and clamp as
* appropriate. * appropriate.
* DP may want to dither down to 6bpc to fit larger modes
* *
* RETURNS: * RETURNS:
* Dithering requirement (i.e. false if display bpc and pipe bpc match, * Dithering requirement (i.e. false if display bpc and pipe bpc match,
* true if they don't match). * true if they don't match).
*/ */
static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, 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_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
...@@ -4758,6 +4761,11 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, ...@@ -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 * We could just drive the pipe at the highest bpc all the time and
* enable dithering as needed, but that costs bandwidth. So choose * enable dithering as needed, but that costs bandwidth. So choose
...@@ -5019,6 +5027,16 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, ...@@ -5019,6 +5027,16 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
pipeconf &= ~PIPECONF_DOUBLE_WIDE; 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; dpll |= DPLL_VCO_ENABLE;
DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
...@@ -5480,7 +5498,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, ...@@ -5480,7 +5498,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
/* determine panel color depth */ /* determine panel color depth */
temp = I915_READ(PIPECONF(pipe)); temp = I915_READ(PIPECONF(pipe));
temp &= ~PIPE_BPC_MASK; 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) { switch (pipe_bpp) {
case 18: case 18:
temp |= PIPE_6BPC; temp |= PIPE_6BPC;
......
...@@ -208,13 +208,15 @@ intel_dp_link_clock(uint8_t link_bw) ...@@ -208,13 +208,15 @@ intel_dp_link_clock(uint8_t link_bw)
*/ */
static int 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 drm_crtc *crtc = intel_dp->base.base.crtc;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int bpp = 24; int bpp = 24;
if (intel_crtc) if (check_bpp)
bpp = check_bpp;
else if (intel_crtc)
bpp = intel_crtc->bpp; bpp = intel_crtc->bpp;
return (pixel_clock * bpp + 9) / 10; return (pixel_clock * bpp + 9) / 10;
...@@ -233,6 +235,7 @@ intel_dp_mode_valid(struct drm_connector *connector, ...@@ -233,6 +235,7 @@ intel_dp_mode_valid(struct drm_connector *connector,
struct intel_dp *intel_dp = intel_attached_dp(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_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_lanes = intel_dp_max_lane_count(intel_dp);
int max_rate, mode_rate;
if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) { if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) {
if (mode->hdisplay > intel_dp->panel_fixed_mode->hdisplay) if (mode->hdisplay > intel_dp->panel_fixed_mode->hdisplay)
...@@ -242,9 +245,17 @@ intel_dp_mode_valid(struct drm_connector *connector, ...@@ -242,9 +245,17 @@ intel_dp_mode_valid(struct drm_connector *connector,
return MODE_PANEL; return MODE_PANEL;
} }
if (intel_dp_link_required(intel_dp, mode->clock) mode_rate = intel_dp_link_required(intel_dp, mode->clock, 0);
> intel_dp_max_data_rate(max_link_clock, max_lanes)) max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes);
return MODE_CLOCK_HIGH;
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) if (mode->clock < 10000)
return MODE_CLOCK_LOW; return MODE_CLOCK_LOW;
...@@ -672,6 +683,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, ...@@ -672,6 +683,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
int lane_count, clock; int lane_count, clock;
int max_lane_count = intel_dp_max_lane_count(intel_dp); 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 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 }; static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) { if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) {
...@@ -689,7 +701,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, ...@@ -689,7 +701,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
for (clock = 0; clock <= max_clock; clock++) { for (clock = 0; clock <= max_clock; clock++) {
int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count); 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) { <= link_avail) {
intel_dp->link_bw = bws[clock]; intel_dp->link_bw = bws[clock];
intel_dp->lane_count = lane_count; intel_dp->lane_count = lane_count;
......
...@@ -110,6 +110,7 @@ ...@@ -110,6 +110,7 @@
/* drm_display_mode->private_flags */ /* drm_display_mode->private_flags */
#define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0) #define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0)
#define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT) #define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT)
#define INTEL_MODE_DP_FORCE_6BPC (0x10)
static inline void static inline void
intel_mode_set_pixel_multiplier(struct drm_display_mode *mode, intel_mode_set_pixel_multiplier(struct drm_display_mode *mode,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment