[PATCH 4/4] drm/msm/dp: continue link training downgrade when cable is still plugged

From: Saurabh Anand

Date: Mon Aug 24 2026 - 07:34:25 EST


During a Type-C reconnect the AUX channel may report link-disconnected
transiently while the physical cable is still present. The link training
retry loop in msm_dp_ctrl_on_link() was aborting immediately on any
msm_dp_aux_is_link_connected() failure, preventing the rate/lane downgrade
path from running.

When the display is known to be plugged (msm_dp_ctrl->plugged), an AUX
link-disconnected status is likely a transient glitch rather than a true
unplug. Allow the downgrade loop to continue in that case by requiring both
conditions before breaking out of the retry loop: AUX reports disconnected
and the display is not plugged.

The plugged state is snapshotted from dp_display into msm_dp_ctrl just
before msm_dp_ctrl_on_link() is called, so the retry loop has an accurate
view of cable presence at the time link training started.

Signed-off-by: Saurabh Anand <saurabh.anand@xxxxxxxxxxxxxxxx>
---
drivers/gpu/drm/msm/dp/dp_ctrl.c | 4 ++--
drivers/gpu/drm/msm/dp/dp_ctrl.h | 1 +
drivers/gpu/drm/msm/dp/dp_display.c | 1 +
3 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 59070f399e2d..e8fd8f4c75fe 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -2379,7 +2379,7 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl,
break;
} else if (training_step == DP_TRAINING_1) {
/* link train_1 failed */
- if (!msm_dp_aux_is_link_connected(ctrl->aux))
+ if (!msm_dp_aux_is_link_connected(ctrl->aux) && !msm_dp_ctrl->plugged)
break;

drm_dp_dpcd_read_link_status(ctrl->aux, link_status);
@@ -2404,7 +2404,7 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl,
}
} else if (training_step == DP_TRAINING_2) {
/* link train_2 failed */
- if (!msm_dp_aux_is_link_connected(ctrl->aux))
+ if (!msm_dp_aux_is_link_connected(ctrl->aux) && !msm_dp_ctrl->plugged)
break;

drm_dp_dpcd_read_link_status(ctrl->aux, link_status);
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h b/drivers/gpu/drm/msm/dp/dp_ctrl.h
index 5902cf7e746a..95533b0b6297 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.h
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h
@@ -12,6 +12,7 @@

struct msm_dp_ctrl {
bool wide_bus_en;
+ bool plugged;
};

struct phy;
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 1f60c78a463d..93a37a44273f 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -644,6 +644,7 @@ static int msm_dp_display_prepare_link(struct msm_dp_display_private *dp)
if (!msm_dp_display->power_on) {
msm_dp_display_host_phy_init(dp);
force_link_train = true;
+ dp->ctrl->plugged = dp->plugged;
}

rc = msm_dp_ctrl_on_link(dp->ctrl, dp->panel);

--
2.34.1