drm/i915: Turn off g4x DP port in .post_disable()
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Wed, 13 Jun 2018 16:05:53 +0000 (19:05 +0300)
committerVille Syrjälä <ville.syrjala@linux.intel.com>
Thu, 14 Jun 2018 18:13:14 +0000 (21:13 +0300)
While Bspec doesn't list a specific sequence for turning off the DP port
on g4x we are getting an underrun if the port is disabled in the
.disable() hook. Looks like the pipe stops when the port stops, and by
that time the plane disable may not have completed yet. Also the plane(s)
seem to end up in some wonky state when this happens as they also signal
another underrun immediately after we turn them back on during the next
enable sequence.

We could add a vblank wait in .disable() to avoid wedging the planes,
but I assume we're still tripping up the pipe in some way. So it seems
better to me to just follow the ILK+ sequence and turn off the DP port
in .post_disable() instead. This sequence doesn't seem to suffer from
this problem. Could be it was always the intended sequence for DP and
the gen4 bspec was just never updated to include it.

Originally we used the bad sequence even on ilk+, but I changed that
in commit 08aff3fe26ae ("drm/i915: Move DP port disable to post_disable
for pch platforms") as it was causing issues on those platforms as well.
I left out g4x then only because I didn't have the hardware to test it.
Now that I do it's fairly clear that the ilk+ sequence is also the
right choice for g4x.

v2: Fix whitespace fail (Jani)
    Mention the ilk+ commit (Jani)

Cc: stable@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180613160553.11664-2-ville.syrjala@linux.intel.com
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
drivers/gpu/drm/i915/intel_dp.c

index 2fe85c63d5ceb62d5ab058e7db4a8804beae7f39..67875b00c8df799048cd4d5eccac2e5df2879fbf 100644 (file)
@@ -2809,16 +2809,6 @@ static void intel_disable_dp(struct intel_encoder *encoder,
 static void g4x_disable_dp(struct intel_encoder *encoder,
                           const struct intel_crtc_state *old_crtc_state,
                           const struct drm_connector_state *old_conn_state)
-{
-       intel_disable_dp(encoder, old_crtc_state, old_conn_state);
-
-       /* disable the port before the pipe on g4x */
-       intel_dp_link_down(encoder, old_crtc_state);
-}
-
-static void ilk_disable_dp(struct intel_encoder *encoder,
-                          const struct intel_crtc_state *old_crtc_state,
-                          const struct drm_connector_state *old_conn_state)
 {
        intel_disable_dp(encoder, old_crtc_state, old_conn_state);
 }
@@ -2834,13 +2824,19 @@ static void vlv_disable_dp(struct intel_encoder *encoder,
        intel_disable_dp(encoder, old_crtc_state, old_conn_state);
 }
 
-static void ilk_post_disable_dp(struct intel_encoder *encoder,
+static void g4x_post_disable_dp(struct intel_encoder *encoder,
                                const struct intel_crtc_state *old_crtc_state,
                                const struct drm_connector_state *old_conn_state)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
        enum port port = encoder->port;
 
+       /*
+        * Bspec does not list a specific disable sequence for g4x DP.
+        * Follow the ilk+ sequence (disable pipe before the port) for
+        * g4x DP as it does not suffer from underruns like the normal
+        * g4x modeset sequence (disable pipe after the port).
+        */
        intel_dp_link_down(encoder, old_crtc_state);
 
        /* Only ilk+ has port A */
@@ -6456,15 +6452,11 @@ bool intel_dp_init(struct drm_i915_private *dev_priv,
                intel_encoder->enable = vlv_enable_dp;
                intel_encoder->disable = vlv_disable_dp;
                intel_encoder->post_disable = vlv_post_disable_dp;
-       } else if (INTEL_GEN(dev_priv) >= 5) {
-               intel_encoder->pre_enable = g4x_pre_enable_dp;
-               intel_encoder->enable = g4x_enable_dp;
-               intel_encoder->disable = ilk_disable_dp;
-               intel_encoder->post_disable = ilk_post_disable_dp;
        } else {
                intel_encoder->pre_enable = g4x_pre_enable_dp;
                intel_encoder->enable = g4x_enable_dp;
                intel_encoder->disable = g4x_disable_dp;
+               intel_encoder->post_disable = g4x_post_disable_dp;
        }
 
        intel_dig_port->dp.output_reg = output_reg;