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
dc22ee6fc1
.
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>
This commit is contained in:
parent
f45b55575c
commit
3b5c78a35c
3 changed files with 39 additions and 8 deletions
|
@ -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)
|
||||||
* 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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
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,
|
||||||
/* 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)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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 @@
|
||||||
/* 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,
|
||||||
|
|
Loading…
Reference in a new issue