[PATCH 13/17] drm/i915: Clear PPS port select when giving up the power sequencer

ville.syrjala
2014-10-16T18:29:56Z

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

VLV gets confused if two power sequencers have the same port selected.
It would seem the port doesn't start up properly in the is case and
vlv_wait_port_ready() will fail as will the link training. Clearing the
port select in the PP_ON_DELAYS register fixes this problem.

CHV doesn't seem to need this, but it doesn't seem to hurt either so
let's just do it for both to keep the code between the platforms as
uniform as possible.

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

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index c9a1600..103468c 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -2694,6 +2694,32 @@ static void g4x_pre_enable_dp(struct intel_encoder *encoder)
}
}

+static void vlv_detach_power_sequencer(struct intel_dp *intel_dp)
+{
+ struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+ struct drm_i915_private *dev_priv = intel_dig_port->base.base.dev->dev_private;
+ enum pipe pipe = intel_dp->pps_pipe;
+ int pp_on_reg = VLV_PIPE_PP_ON_DELAYS(pipe);
+
+ edp_panel_vdd_off_sync(intel_dp);
+
+ /*
+ * VLV seems to get confused when multiple power seqeuencers
+ * have the same port selected (even if only one has power/vdd
+ * enabled). The failure manifests as vlv_wait_port_ready() failing
+ * CHV on the other hand doesn't seem to mind having the same port
+ * selected in multiple power seqeuencers, but let's clear the
+ * port select always when logically disconnecting a power sequencer
+ * from a port.
+ */
+ DRM_DEBUG_KMS("detaching pipe %c power sequencer from port %c\n",
+ pipe_name(pipe), port_name(intel_dig_port->port));
+ I915_WRITE(pp_on_reg, 0);
+ POSTING_READ(pp_on_reg);
+
+ intel_dp->pps_pipe = INVALID_PIPE;
+}
+
static void vlv_steal_power_sequencer(struct drm_device *dev,
enum pipe pipe)
{
@@ -2724,9 +2750,7 @@ static void vlv_steal_power_sequencer(struct drm_device *dev,
pipe_name(pipe), port_name(port));

/* make sure vdd is off before we steal it */
- edp_panel_vdd_off_sync(intel_dp);
-
- intel_dp->pps_pipe = INVALID_PIPE;
+ vlv_detach_power_sequencer(intel_dp);
}
}

@@ -2752,7 +2776,7 @@ static void vlv_init_panel_power_sequencer(struct intel_dp *intel_dp)
* we still have control of it.
*/
if (intel_dp->pps_pipe != INVALID_PIPE)
- edp_panel_vdd_off_sync(intel_dp);
+ vlv_detach_power_sequencer(intel_dp);

/*
* We may be stealing the power
--
2.0.4