When the last MST stream is disabled, i915 sends SET_POWER D3 to the
MST trunk while MSTM_CTRL (DPCD 0x111) still has MST mode enabled.
On re-enable, POWER_UP_PHY is sent before MSTM_CTRL is restored, so
the hub may process the PHY power-up in an inconsistent state and
fail to retrain its downstream links.

Fix this by clearing MSTM_CTRL before sending D3 on the last stream
disable, mirroring what drm_dp_mst_topology_mgr_set_mst() does on
MST disconnect. On re-enable, restore MSTM_CTRL after writing D0 and
before sending POWER_UP_PHY, so the hub is back in MST mode when it
processes the PHY power-up and retrains its downstream links.

Signed-off-by: Xiao Lu <[email protected]>
---
 drivers/gpu/drm/i915/display/intel_ddi.c    | 2 ++
 drivers/gpu/drm/i915/display/intel_dp_mst.c | 6 +++++-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c 
b/drivers/gpu/drm/i915/display/intel_ddi.c
index a46ab5d3d..7e4e18345 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -3163,6 +3163,8 @@ static void intel_ddi_post_disable_dp(struct 
intel_atomic_state *state,
         * Power down sink before disabling the port, otherwise we end
         * up getting interrupts from the sink on detecting link loss.
         */
+       if (is_mst)
+               drm_dp_dpcd_write_byte(&intel_dp->aux, DP_MSTM_CTRL, 0);
        intel_dp_set_power(intel_dp, DP_SET_POWER_D3);
 
        if (DISPLAY_VER(display) >= 12) {
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c 
b/drivers/gpu/drm/i915/display/intel_dp_mst.c
index 7023619aa..4109bb928 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -1270,8 +1270,12 @@ static void mst_stream_pre_enable(struct 
intel_atomic_state *state,
        drm_WARN_ON(display->drm, DISPLAY_VER(display) >= 12 && 
first_mst_stream &&
                    !intel_dp_mst_is_master_trans(pipe_config));
 
-       if (first_mst_stream)
+       if (first_mst_stream) {
                intel_dp_set_power(intel_dp, DP_SET_POWER_D0);
+               drm_dp_dpcd_write_byte(&intel_dp->aux, DP_MSTM_CTRL,
+                                      DP_MST_EN | DP_UP_REQ_EN |
+                                      DP_UPSTREAM_IS_SRC);
+       }
 
        drm_dp_send_power_updown_phy(&intel_dp->mst.mgr, connector->mst.port, 
true);
 
-- 
2.43.0

Reply via email to