OSDN Git Service

drm/i915/dp: Fix MST disable sequence
authorJosé Roberto de Souza <jose.souza@intel.com>
Mon, 23 Dec 2019 01:06:51 +0000 (17:06 -0800)
committerJosé Roberto de Souza <jose.souza@intel.com>
Mon, 23 Dec 2019 17:26:43 +0000 (09:26 -0800)
The disable sequence after wait for transcoder off was not correctly
implemented.
The MST disable sequence is basically the same for HSW, SKL, ICL and
TGL, with just minor changes for TGL.

With this last patch we finally fixed the hotplugs triggered by MST
sinks during the disable/enable sequence, those were causing source
to try to do a link training while it was not ready causing CPU pipe
FIFO underrrus on TGL.

v2: Only unsetting TGL_TRANS_DDI_PORT_MASK for TGL on the post
disable sequence

v4: Rebased, moved MST sequences to intel_mst_post_disable_dp()

BSpec: 4231
BSpec: 4163
BSpec: 22243
BSpec: 49190
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Lucas De Marchi <lucas.demarchi@intel.com>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191223010654.67037-4-jose.souza@intel.com
drivers/gpu/drm/i915/display/intel_ddi.c
drivers/gpu/drm/i915/display/intel_dp_mst.c

index c3ac950..3a53878 100644 (file)
@@ -34,6 +34,7 @@
 #include "intel_ddi.h"
 #include "intel_display_types.h"
 #include "intel_dp.h"
+#include "intel_dp_mst.h"
 #include "intel_dp_link_training.h"
 #include "intel_dpio_phy.h"
 #include "intel_dsi.h"
@@ -1949,17 +1950,18 @@ void intel_ddi_disable_transcoder_func(const struct intel_crtc_state *crtc_state
        struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
-       i915_reg_t reg = TRANS_DDI_FUNC_CTL(cpu_transcoder);
-       u32 val = I915_READ(reg);
+       u32 val;
+
+       val = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
+       val &= ~TRANS_DDI_FUNC_ENABLE;
 
        if (INTEL_GEN(dev_priv) >= 12) {
-               val &= ~(TRANS_DDI_FUNC_ENABLE | TGL_TRANS_DDI_PORT_MASK |
-                        TRANS_DDI_DP_VC_PAYLOAD_ALLOC);
+               if (!intel_dp_mst_is_master_trans(crtc_state))
+                       val &= ~TGL_TRANS_DDI_PORT_MASK;
        } else {
-               val &= ~(TRANS_DDI_FUNC_ENABLE | TRANS_DDI_PORT_MASK |
-                        TRANS_DDI_DP_VC_PAYLOAD_ALLOC);
+               val &= ~TRANS_DDI_PORT_MASK;
        }
-       I915_WRITE(reg, val);
+       I915_WRITE(TRANS_DDI_FUNC_CTL(cpu_transcoder), val);
 
        if (dev_priv->quirks & QUIRK_INCREASE_DDI_DISABLED_TIME &&
            intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) {
@@ -3813,8 +3815,19 @@ static void intel_ddi_post_disable_dp(struct intel_encoder *encoder,
         */
        intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
 
-       if (INTEL_GEN(dev_priv) < 12 && !is_mst)
-               intel_ddi_disable_pipe_clock(old_crtc_state);
+       if (INTEL_GEN(dev_priv) >= 12) {
+               if (is_mst) {
+                       enum transcoder cpu_transcoder = old_crtc_state->cpu_transcoder;
+                       u32 val;
+
+                       val = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
+                       val &= ~TGL_TRANS_DDI_PORT_MASK;
+                       I915_WRITE(TRANS_DDI_FUNC_CTL(cpu_transcoder), val);
+               }
+       } else {
+               if (!is_mst)
+                       intel_ddi_disable_pipe_clock(old_crtc_state);
+       }
 
        intel_disable_ddi_buf(encoder, old_crtc_state);
 
index 8cfff07..9251d47 100644 (file)
@@ -347,6 +347,7 @@ static void intel_mst_post_disable_dp(struct intel_encoder *encoder,
                to_intel_connector(old_conn_state->connector);
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
        bool last_mst_stream;
+       u32 val;
 
        intel_dp->active_mst_links--;
        last_mst_stream = intel_dp->active_mst_links == 0;
@@ -357,6 +358,19 @@ static void intel_mst_post_disable_dp(struct intel_encoder *encoder,
 
        intel_disable_pipe(old_crtc_state);
 
+       drm_dp_update_payload_part2(&intel_dp->mst_mgr);
+
+       val = I915_READ(TRANS_DDI_FUNC_CTL(old_crtc_state->cpu_transcoder));
+       val &= ~TRANS_DDI_DP_VC_PAYLOAD_ALLOC;
+       I915_WRITE(TRANS_DDI_FUNC_CTL(old_crtc_state->cpu_transcoder), val);
+
+       if (intel_de_wait_for_set(dev_priv, intel_dp->regs.dp_tp_status,
+                                 DP_TP_STATUS_ACT_SENT, 1))
+               DRM_ERROR("Timed out waiting for ACT sent when disabling\n");
+       drm_dp_check_act_status(&intel_dp->mst_mgr);
+
+       drm_dp_mst_deallocate_vcpi(&intel_dp->mst_mgr, connector->port);
+
        intel_ddi_disable_transcoder_func(old_crtc_state);
 
        if (INTEL_GEN(dev_priv) >= 9)
@@ -365,6 +379,12 @@ static void intel_mst_post_disable_dp(struct intel_encoder *encoder,
                ironlake_pfit_disable(old_crtc_state);
 
        /*
+        * Power down mst path before disabling the port, otherwise we end
+        * up getting interrupts from the sink upon detecting link loss.
+        */
+       drm_dp_send_power_updown_phy(&intel_dp->mst_mgr, connector->port,
+                                    false);
+       /*
         * From TGL spec: "If multi-stream slave transcoder: Configure
         * Transcoder Clock Select to direct no clock to the transcoder"
         *
@@ -374,19 +394,6 @@ static void intel_mst_post_disable_dp(struct intel_encoder *encoder,
        if (INTEL_GEN(dev_priv) < 12 || !last_mst_stream)
                intel_ddi_disable_pipe_clock(old_crtc_state);
 
-       /* this can fail */
-       drm_dp_check_act_status(&intel_dp->mst_mgr);
-       /* and this can also fail */
-       drm_dp_update_payload_part2(&intel_dp->mst_mgr);
-
-       drm_dp_mst_deallocate_vcpi(&intel_dp->mst_mgr, connector->port);
-
-       /*
-        * Power down mst path before disabling the port, otherwise we end
-        * up getting interrupts from the sink upon detecting link loss.
-        */
-       drm_dp_send_power_updown_phy(&intel_dp->mst_mgr, connector->port,
-                                    false);
 
        intel_mst->connector = NULL;
        if (last_mst_stream)