[PATCH 37/40] drm/i915: Fix eDP link training when switching pipes

ville.syrjala
2014-06-27T23:06:40Z

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

When switching from one pipe to another, the power sequencer of the new
pipe seems to need a bit of kicking to lock into the port. Even the vdd
force bit doesn't work before the power sequencer has been sufficiently
kicked, so this must be done even before any AUX transactions.

This sequence has been found to do the trick:
1) enable port with idle pattern
2) enable the power sequencer
3) proceed with link training

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
drivers/gpu/drm/i915/intel_dp.c | 34 ++++++++++++++++++++++++++++++++--
1 file changed, 32 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 65ab54c..07b0320 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -2010,6 +2010,37 @@ static void chv_post_disable_dp(struct intel_encoder *encoder)
mutex_unlock(&dev_priv->dpio_lock);
}

+static void intel_edp_init_train(struct intel_dp *intel_dp)
+{
+ struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+ struct drm_device *dev = intel_dig_port->base.base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (!is_edp(intel_dp))
+ return;
+
+ /*
+ * Need to enable the port with idle pattern to allow the power
+ * sequencer to lock into the port. Otherwise the power sequencer
+ * (including vdd force bit!) doesn't work on this port.
+ */
+ if (IS_VALLEYVIEW(dev)) {
+ intel_dp->DP |= DP_PORT_EN;
+
+ if (IS_CHERRYVIEW(dev))
+ intel_dp->DP &= ~DP_LINK_TRAIN_MASK_CHV;
+ else
+ intel_dp->DP &= ~DP_LINK_TRAIN_MASK;
+ intel_dp->DP |= DP_LINK_TRAIN_PAT_IDLE;
+
+ I915_WRITE(intel_dp->output_reg, intel_dp->DP);
+ POSTING_READ(intel_dp->output_reg);
+ }
+
+ intel_edp_panel_on(intel_dp);
+ edp_panel_vdd_off(intel_dp, true);
+}
+
static void intel_enable_dp(struct intel_encoder *encoder)
{
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
@@ -2021,10 +2052,9 @@ static void intel_enable_dp(struct intel_encoder *encoder)
return;

intel_edp_panel_vdd_on(intel_dp);
+ intel_edp_init_train(intel_dp);
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
intel_dp_start_link_train(intel_dp);
- intel_edp_panel_on(intel_dp);
- edp_panel_vdd_off(intel_dp, true);
intel_dp_complete_link_train(intel_dp);
intel_dp_stop_link_train(intel_dp);
}
--
1.8.5.5