| From 97cd0f178e80376d1a83ee986b41454a2a461907 Mon Sep 17 00:00:00 2001 |
| From: Daniel Vetter <daniel.vetter@ffwll.ch> |
| Date: Thu, 21 Feb 2013 00:00:16 +0100 |
| Subject: drm/i915: implement fdi auto-dithering |
| |
| So on a bunch of setups we only have 2 fdi lanes available, e.g. hsw |
| VGA or 3 pipes on ivb. And seemingly a lot of modes don't quite fit |
| into this, among them the default 1080p mode. |
| |
| The solution is to dither down the pipe a bit so that everything fits, |
| which this patch implements. |
| |
| But ports compute their state under the assumption that the bpp they |
| pick will be the one selected, e.g. the display port bw computations |
| won't work otherwise. Now we could adjust our code to again up-dither |
| to the computed DP link parameters, but that's pointless. |
| |
| So instead when the pipe needs to adjust parameters we need to retry |
| the pipe_config computation at the encoder stage. Furthermore we need |
| to inform encoders that they should not increase bandwidth |
| requirements if possible. This is required for the hdmi code, which |
| prefers the pipe to up-dither to either of the two possible hdmi bpc |
| values. |
| |
| LVDS has a similar requirement, although that's probably only |
| theoretical in nature: It's unlikely that we'll ever see an 8bpc |
| high-res lvds panel (which is required to hit the 2 fdi lane limit). |
| |
| eDP is the only thing which could increase the pipe_bpp setting again, |
| even when in the retry-loop. This could hit the WARN. Two reasons for |
| not bothering: |
| - On many eDP panels we'll get a black screen if the bpp settings |
| don't match vbt. So failing the modeset is the right thing to do. |
| But since that also means it's the only way to light up the panel, |
| it should work. So we shouldn't be able to hit this WARN. |
| - There are still opens around the eDP panel handling, and maybe we |
| need additional tricks. Before that happens it's imo no use trying |
| to be too clever. |
| Worst case we just need to kill that WARN or maybe fail the compute |
| config stage if the eDP connector can't get the bpp setting it wants. |
| And since this can only happen with an fdi link in between and so for |
| pch eDP panels it's rather unlikely to blow up, if ever. |
| |
| v2: Rebased on top of a bikeshed from Paulo. |
| |
| v3: Improve commit message around eDP handling with the stuff |
| things with Imre. |
| |
| Reviewed-by: Imre Deak <imre.deak@intel.com> |
| Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> |
| (cherry picked from commit e29c22c0c4fefeb48a0157811930f7e9df0bb3f3) |
| Signed-off-by: Darren Hart <dvhart@linux.intel.com> |
| --- |
| drivers/gpu/drm/i915/intel_display.c | 56 ++++++++++++++++++++++++++++-------- |
| drivers/gpu/drm/i915/intel_drv.h | 7 +++++ |
| drivers/gpu/drm/i915/intel_hdmi.c | 14 ++++++--- |
| drivers/gpu/drm/i915/intel_lvds.c | 2 +- |
| 4 files changed, 62 insertions(+), 17 deletions(-) |
| |
| diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c |
| index 4fd41ecc063a..dc9d2753d756 100644 |
| --- a/drivers/gpu/drm/i915/intel_display.c |
| +++ b/drivers/gpu/drm/i915/intel_display.c |
| @@ -4036,13 +4036,16 @@ static bool ironlake_check_fdi_lanes(struct drm_device *dev, enum pipe pipe, |
| } |
| } |
| |
| -static bool ironlake_fdi_compute_config(struct intel_crtc *intel_crtc, |
| - struct intel_crtc_config *pipe_config) |
| +#define RETRY 1 |
| +static int ironlake_fdi_compute_config(struct intel_crtc *intel_crtc, |
| + struct intel_crtc_config *pipe_config) |
| { |
| struct drm_device *dev = intel_crtc->base.dev; |
| struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; |
| int target_clock, lane, link_bw; |
| + bool setup_ok, needs_recompute = false; |
| |
| +retry: |
| /* FDI is a binary signal running at ~2.7GHz, encoding |
| * each output octet as 10 bits. The actual frequency |
| * is stored as a divider into a 100MHz clock, and the |
| @@ -4067,12 +4070,26 @@ static bool ironlake_fdi_compute_config(struct intel_crtc *intel_crtc, |
| intel_link_compute_m_n(pipe_config->pipe_bpp, lane, target_clock, |
| link_bw, &pipe_config->fdi_m_n); |
| |
| - return ironlake_check_fdi_lanes(intel_crtc->base.dev, |
| - intel_crtc->pipe, pipe_config); |
| + setup_ok = ironlake_check_fdi_lanes(intel_crtc->base.dev, |
| + intel_crtc->pipe, pipe_config); |
| + if (!setup_ok && pipe_config->pipe_bpp > 6*3) { |
| + pipe_config->pipe_bpp -= 2*3; |
| + DRM_DEBUG_KMS("fdi link bw constraint, reducing pipe bpp to %i\n", |
| + pipe_config->pipe_bpp); |
| + needs_recompute = true; |
| + pipe_config->bw_constrained = true; |
| + |
| + goto retry; |
| + } |
| + |
| + if (needs_recompute) |
| + return RETRY; |
| + |
| + return setup_ok ? 0 : -EINVAL; |
| } |
| |
| -static bool intel_crtc_compute_config(struct drm_crtc *crtc, |
| - struct intel_crtc_config *pipe_config) |
| +static int intel_crtc_compute_config(struct drm_crtc *crtc, |
| + struct intel_crtc_config *pipe_config) |
| { |
| struct drm_device *dev = crtc->dev; |
| struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; |
| @@ -4081,7 +4098,7 @@ static bool intel_crtc_compute_config(struct drm_crtc *crtc, |
| /* FDI link clock is fixed at 2.7G */ |
| if (pipe_config->requested_mode.clock * 3 |
| > IRONLAKE_FDI_FREQ * 4) |
| - return false; |
| + return -EINVAL; |
| } |
| |
| /* All interlaced capable intel hw wants timings in frames. Note though |
| @@ -4095,7 +4112,7 @@ static bool intel_crtc_compute_config(struct drm_crtc *crtc, |
| */ |
| if ((INTEL_INFO(dev)->gen > 4 || IS_G4X(dev)) && |
| adjusted_mode->hsync_start == adjusted_mode->hdisplay) |
| - return false; |
| + return -EINVAL; |
| |
| if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)) && pipe_config->pipe_bpp > 10*3) { |
| pipe_config->pipe_bpp = 10*3; /* 12bpc is gen5+ */ |
| @@ -4108,7 +4125,7 @@ static bool intel_crtc_compute_config(struct drm_crtc *crtc, |
| if (pipe_config->has_pch_encoder) |
| return ironlake_fdi_compute_config(to_intel_crtc(crtc), pipe_config); |
| |
| - return true; |
| + return 0; |
| } |
| |
| static int valleyview_get_display_clock_speed(struct drm_device *dev) |
| @@ -7708,7 +7725,8 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, |
| struct drm_encoder_helper_funcs *encoder_funcs; |
| struct intel_encoder *encoder; |
| struct intel_crtc_config *pipe_config; |
| - int plane_bpp; |
| + int plane_bpp, ret = -EINVAL; |
| + bool retry = true; |
| |
| pipe_config = kzalloc(sizeof(*pipe_config), GFP_KERNEL); |
| if (!pipe_config) |
| @@ -7721,6 +7739,7 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, |
| if (plane_bpp < 0) |
| goto fail; |
| |
| +encoder_retry: |
| /* Pass our mode to the connectors and the CRTC to give them a chance to |
| * adjust it according to limitations or connector properties, and also |
| * a chance to reject the mode entirely. |
| @@ -7749,10 +7768,23 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, |
| } |
| } |
| |
| - if (!(intel_crtc_compute_config(crtc, pipe_config))) { |
| + ret = intel_crtc_compute_config(crtc, pipe_config); |
| + if (ret < 0) { |
| DRM_DEBUG_KMS("CRTC fixup failed\n"); |
| goto fail; |
| } |
| + |
| + if (ret == RETRY) { |
| + if (WARN(!retry, "loop in pipe configuration computation\n")) { |
| + ret = -EINVAL; |
| + goto fail; |
| + } |
| + |
| + DRM_DEBUG_KMS("CRTC bw constrained, retrying\n"); |
| + retry = false; |
| + goto encoder_retry; |
| + } |
| + |
| DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); |
| |
| pipe_config->dither = pipe_config->pipe_bpp != plane_bpp; |
| @@ -7762,7 +7794,7 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, |
| return pipe_config; |
| fail: |
| kfree(pipe_config); |
| - return ERR_PTR(-EINVAL); |
| + return ERR_PTR(ret); |
| } |
| |
| /* Computes which crtcs are affected and sets the relevant bits in the mask. For |
| diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h |
| index cee65ee5745c..174ba4e6a105 100644 |
| --- a/drivers/gpu/drm/i915/intel_drv.h |
| +++ b/drivers/gpu/drm/i915/intel_drv.h |
| @@ -223,6 +223,13 @@ struct intel_crtc_config { |
| /* Controls for the clock computation, to override various stages. */ |
| bool clock_set; |
| |
| + /* |
| + * crtc bandwidth limit, don't increase pipe bpp or clock if not really |
| + * required. This is set in the 2nd loop of calling encoder's |
| + * ->compute_config if the first pick doesn't work out. |
| + */ |
| + bool bw_constrained; |
| + |
| /* Settings for the intel dpll used on pretty much everything but |
| * haswell. */ |
| struct dpll dpll; |
| diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c |
| index 17e76478a8f5..2b727f0d201f 100644 |
| --- a/drivers/gpu/drm/i915/intel_hdmi.c |
| +++ b/drivers/gpu/drm/i915/intel_hdmi.c |
| @@ -784,6 +784,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, |
| struct drm_device *dev = encoder->base.dev; |
| struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; |
| int clock_12bpc = pipe_config->requested_mode.clock * 3 / 2; |
| + int desired_bpp; |
| |
| if (intel_hdmi->color_range_auto) { |
| /* See CEA-861-E - 5.1 Default Encoding Parameters */ |
| @@ -808,16 +809,21 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, |
| */ |
| if (pipe_config->pipe_bpp > 8*3 && clock_12bpc <= 225000 |
| && HAS_PCH_SPLIT(dev)) { |
| - DRM_DEBUG_KMS("forcing bpc to 12 for HDMI\n"); |
| - pipe_config->pipe_bpp = 12*3; |
| + DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n"); |
| + desired_bpp = 12*3; |
| |
| /* Need to adjust the port link by 1.5x for 12bpc. */ |
| adjusted_mode->clock = clock_12bpc; |
| pipe_config->pixel_target_clock = |
| pipe_config->requested_mode.clock; |
| } else { |
| - DRM_DEBUG_KMS("forcing bpc to 8 for HDMI\n"); |
| - pipe_config->pipe_bpp = 8*3; |
| + DRM_DEBUG_KMS("picking bpc to 8 for HDMI output\n"); |
| + desired_bpp = 8*3; |
| + } |
| + |
| + if (!pipe_config->bw_constrained) { |
| + DRM_DEBUG_KMS("forcing pipe bpc to %i for HDMI\n", desired_bpp); |
| + pipe_config->pipe_bpp = desired_bpp; |
| } |
| |
| if (adjusted_mode->clock > 225000) { |
| diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c |
| index d125756a2665..ab04cb9d0725 100644 |
| --- a/drivers/gpu/drm/i915/intel_lvds.c |
| +++ b/drivers/gpu/drm/i915/intel_lvds.c |
| @@ -248,7 +248,7 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, |
| else |
| lvds_bpp = 6*3; |
| |
| - if (lvds_bpp != pipe_config->pipe_bpp) { |
| + if (lvds_bpp != pipe_config->pipe_bpp && !pipe_config->bw_constrained) { |
| DRM_DEBUG_KMS("forcing display bpp (was %d) to LVDS (%d)\n", |
| pipe_config->pipe_bpp, lvds_bpp); |
| pipe_config->pipe_bpp = lvds_bpp; |
| -- |
| 1.8.5.rc3 |
| |