summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2014-10-16 21:29:51 +0300
committerDaniel Vetter <daniel.vetter@ffwll.ch>2014-11-04 23:22:03 +0100
commit83b8459756659ce55446e3eb97d64b966c60bfb9 (patch)
treefbc8bedb4e000743f5835c55897fe4c697180664 /drivers
parent9a42356b964dee6418d8b812109298658cc8dc38 (diff)
drm/i915: Clear PPS port select when giving up the power sequencer
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> Reviewed-by: Imre Deak <imre.deak@intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c32
1 files changed, 28 insertions, 4 deletions
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 451dd253b5d..04d7bc73099 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -2657,6 +2657,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)
{
@@ -2683,9 +2709,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);
}
}
@@ -2711,7 +2735,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