* [PATCH v2 0/3] drm/msm/dp, phy: qcom: improve DP Type-C reconnect handli
@ 2026-11-11 10:43 naidu nama
2026-11-11 10:43 ` [PATCH v2 1/3] phy: qcom: qmp-combo: delay Type-C mux switch while DP PHY is initializing naidu nama
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: naidu nama @ 2026-11-11 10:43 UTC (permalink / raw)
To: vkoul, neil.armstrong, mani, robin.clark, lumag, abhinav.kumar,
jesszhan0024, sean, marijn.suijten, irlied, simona
Cc: naidu nama, linux-arm-msm, linux-phy, linux-kernel, dri-devel,
quic_riteshk, quic_vproddut, quic_mkuntuma, mahadevan.p,
saurabh.anand
This series improves the Qualcomm DP Type-C bring-up and reconnect paths
by handling PHY initialization races and link-training corner cases more
consistently.
The fixes cover races and link-training corner cases in the Qualcomm DP
Type-C path. They prevent Type-C mux switching while the DP PHY is still
initializing, avoid unnecessary retraining after a successful link train,
and keep the downgrade retry path running across transient AUX disconnects
when the cable is still plugged.
Together these changes make DP reconnect and orientation-switch
handling more robust.
---
[v2]
- Updated the commit message [Konrad, Dmitry]
- Handled the force_link_train varibale usage [Konrad]
- Handled the plugged field from struct msm_dp_ctrl,
by passing the current dp->plugged value as a function argument [Dmitry]
- Dropped the drm/msm/dp: skip LTTPR init when no LTTPRs are present[Konrad, Dmitry]
---
Saurabh Anand (3):
phy: qcom: qmp-combo: delay Type-C mux switch while DP PHY is
initializing
drm/msm/dp: Remove redundant force_link_train flag
drm/msm/dp: continue link training downgrade when cable is still
plugged
drivers/gpu/drm/msm/dp/dp_ctrl.c | 20 ++++++++++----------
drivers/gpu/drm/msm/dp/dp_ctrl.h | 7 +++----
drivers/gpu/drm/msm/dp/dp_display.c | 11 ++++-------
drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 3 ++-
4 files changed, 19 insertions(+), 22 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 1/3] phy: qcom: qmp-combo: delay Type-C mux switch while DP PHY is initializing
2026-11-11 10:43 [PATCH v2 0/3] drm/msm/dp, phy: qcom: improve DP Type-C reconnect handli naidu nama
@ 2026-11-11 10:43 ` naidu nama
2026-11-11 14:06 ` Dmitry Baryshkov
2026-11-11 10:43 ` [PATCH v2 2/3] drm/msm/dp: Remove redundant force_link_train flag naidu nama
2026-11-11 10:43 ` [PATCH v2 3/3] drm/msm/dp: continue link training downgrade when cable is still plugged naidu nama
2 siblings, 1 reply; 7+ messages in thread
From: naidu nama @ 2026-11-11 10:43 UTC (permalink / raw)
To: vkoul, neil.armstrong, mani, robin.clark, lumag, abhinav.kumar,
jesszhan0024, sean, marijn.suijten, irlied, simona
Cc: Saurabh Anand, linux-arm-msm, linux-phy, linux-kernel, dri-devel,
quic_riteshk, quic_vproddut, quic_mkuntuma, mahadevan.p,
naidu.nama
From: Saurabh Anand <saurabh.anand@oss.qualcomm.com>
The Type-C mux switch guard only checked dp_powered_on, which is set in
qmp_combo_dp_power_on(). However there is a race window between
qmp_combo_dp_init() and qmp_combo_dp_power_on() during which dp_init_count
is non-zero but dp_powered_on is still false. A Type-C orientation change
arriving in this window would proceed with the mux switch while the DP PHY
is mid-initialization, corrupting the PHY state.
Extend the guard to also block the mux switch when dp_init_count is
non-zero, covering the full period from dp_init through dp_power_on.
Signed-off-by: Saurabh Anand <saurabh.anand@oss.qualcomm.com>
---
drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
index 61d8b7a5ce8f..3f93043f94e5 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
@@ -5163,7 +5163,8 @@ static int qmp_combo_typec_mux_set(struct typec_mux_dev *mux, struct typec_mux_s
return 0;
}
- if (qmp->qmpphy_mode != QMPPHY_MODE_USB3_ONLY && qmp->dp_powered_on) {
+ if (qmp->qmpphy_mode != QMPPHY_MODE_USB3_ONLY &&
+ (qmp->dp_powered_on || qmp->dp_init_count)) {
dev_dbg(qmp->dev, "typec_mux_set: DP PHY is still in use, delaying switch\n");
return 0;
}
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 2/3] drm/msm/dp: Remove redundant force_link_train flag
2026-11-11 10:43 [PATCH v2 0/3] drm/msm/dp, phy: qcom: improve DP Type-C reconnect handli naidu nama
2026-11-11 10:43 ` [PATCH v2 1/3] phy: qcom: qmp-combo: delay Type-C mux switch while DP PHY is initializing naidu nama
@ 2026-11-11 10:43 ` naidu nama
2026-11-11 14:06 ` Dmitry Baryshkov
2026-11-11 10:43 ` [PATCH v2 3/3] drm/msm/dp: continue link training downgrade when cable is still plugged naidu nama
2 siblings, 1 reply; 7+ messages in thread
From: naidu nama @ 2026-11-11 10:43 UTC (permalink / raw)
To: vkoul, neil.armstrong, mani, robin.clark, lumag, abhinav.kumar,
jesszhan0024, sean, marijn.suijten, irlied, simona
Cc: Saurabh Anand, linux-arm-msm, linux-phy, linux-kernel, dri-devel,
quic_riteshk, quic_vproddut, quic_mkuntuma, mahadevan.p,
naidu.nama
From: Saurabh Anand <saurabh.anand@oss.qualcomm.com>
force_link_train is always false when passed to
msm_dp_ctrl_prepare_stream_on(): the initial link is trained by
msm_dp_ctrl_on_link(), and the flag is cleared before stream preparation.
For active streams, it is never set.
Remove the dead flag and parameter. Stream preparation still retrains
when channel equalization is incomplete.
Signed-off-by: Saurabh Anand <saurabh.anand@oss.qualcomm.com>
---
drivers/gpu/drm/msm/dp/dp_ctrl.c | 5 ++---
drivers/gpu/drm/msm/dp/dp_ctrl.h | 3 +--
drivers/gpu/drm/msm/dp/dp_display.c | 4 +---
3 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 47647fdec9de..6b9d9a76ba05 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -2582,8 +2582,7 @@ static void msm_dp_ctrl_config_msa(struct msm_dp_ctrl_private *ctrl,
}
int msm_dp_ctrl_prepare_stream_on(struct msm_dp_ctrl *msm_dp_ctrl,
- struct msm_dp_panel *panel,
- bool force_link_train)
+ struct msm_dp_panel *panel)
{
int ret = 0;
struct msm_dp_ctrl_private *ctrl;
@@ -2608,7 +2607,7 @@ int msm_dp_ctrl_prepare_stream_on(struct msm_dp_ctrl *msm_dp_ctrl,
}
}
- if (force_link_train || !msm_dp_ctrl_channel_eq_ok(ctrl))
+ if (!msm_dp_ctrl_channel_eq_ok(ctrl))
msm_dp_ctrl_link_retrain(ctrl, panel);
/* stop txing train pattern to end link training */
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h b/drivers/gpu/drm/msm/dp/dp_ctrl.h
index 80d9258501b4..fc884038182f 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.h
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h
@@ -20,8 +20,7 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl,
struct msm_dp_panel *panel);
int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, struct msm_dp_panel *panel);
int msm_dp_ctrl_prepare_stream_on(struct msm_dp_ctrl *msm_dp_ctrl,
- struct msm_dp_panel *panel,
- bool force_link_train);
+ struct msm_dp_panel *panel);
void msm_dp_ctrl_off_link(struct msm_dp_ctrl *msm_dp_ctrl,
struct msm_dp_panel *panel);
void msm_dp_ctrl_off_pixel_clk(struct msm_dp_ctrl *msm_dp_ctrl, enum msm_dp_stream_id stream_id);
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index c0c150e2c575..169938ba515e 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -633,7 +633,6 @@ static int msm_dp_display_prepare_link(struct msm_dp_display_private *dp)
{
struct msm_dp *msm_dp_display = &dp->msm_dp_display;
int rc = 0;
- bool force_link_train = false;
drm_dbg_dp(dp->drm_dev, "sink_count=%d\n", dp->link->sink_count);
@@ -651,7 +650,6 @@ 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;
}
rc = msm_dp_ctrl_on_link(dp->ctrl, dp->panel);
@@ -661,7 +659,7 @@ static int msm_dp_display_prepare_link(struct msm_dp_display_private *dp)
return rc;
}
- return msm_dp_ctrl_prepare_stream_on(dp->ctrl, dp->panel, force_link_train);
+ return msm_dp_ctrl_prepare_stream_on(dp->ctrl, dp->panel);
}
static int msm_dp_display_enable(struct msm_dp_display_private *dp,
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 3/3] drm/msm/dp: continue link training downgrade when cable is still plugged
2026-11-11 10:43 [PATCH v2 0/3] drm/msm/dp, phy: qcom: improve DP Type-C reconnect handli naidu nama
2026-11-11 10:43 ` [PATCH v2 1/3] phy: qcom: qmp-combo: delay Type-C mux switch while DP PHY is initializing naidu nama
2026-11-11 10:43 ` [PATCH v2 2/3] drm/msm/dp: Remove redundant force_link_train flag naidu nama
@ 2026-11-11 10:43 ` naidu nama
2026-11-11 14:08 ` Dmitry Baryshkov
2 siblings, 1 reply; 7+ messages in thread
From: naidu nama @ 2026-11-11 10:43 UTC (permalink / raw)
To: vkoul, neil.armstrong, mani, robin.clark, lumag, abhinav.kumar,
jesszhan0024, sean, marijn.suijten, irlied, simona
Cc: Saurabh Anand, linux-arm-msm, linux-phy, linux-kernel, dri-devel,
quic_riteshk, quic_vproddut, quic_mkuntuma, mahadevan.p,
naidu.nama
From: Saurabh Anand <saurabh.anand@oss.qualcomm.com>
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.
Signed-off-by: Saurabh Anand <saurabh.anand@oss.qualcomm.com>
---
drivers/gpu/drm/msm/dp/dp_ctrl.c | 15 ++++++++-------
drivers/gpu/drm/msm/dp/dp_ctrl.h | 4 ++--
drivers/gpu/drm/msm/dp/dp_display.c | 7 +++----
3 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 6b9d9a76ba05..f8a6bd7b0d10 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -2274,7 +2274,8 @@ void msm_dp_ctrl_off_pixel_clk(struct msm_dp_ctrl *msm_dp_ctrl, enum msm_dp_stre
}
static int msm_dp_ctrl_process_phy_test_request(struct msm_dp_ctrl_private *ctrl,
- struct msm_dp_panel *panel)
+ struct msm_dp_panel *panel,
+ bool plugged)
{
int ret;
unsigned long pixel_rate;
@@ -2293,7 +2294,7 @@ static int msm_dp_ctrl_process_phy_test_request(struct msm_dp_ctrl_private *ctrl
msm_dp_ctrl_off_pixel_clk(&ctrl->msm_dp_ctrl, panel->stream_id);
msm_dp_ctrl_off_link(&ctrl->msm_dp_ctrl, panel);
- ret = msm_dp_ctrl_on_link(&ctrl->msm_dp_ctrl, panel);
+ ret = msm_dp_ctrl_on_link(&ctrl->msm_dp_ctrl, panel, plugged);
if (ret) {
DRM_ERROR("failed to enable DP link controller\n");
return ret;
@@ -2310,7 +2311,7 @@ static int msm_dp_ctrl_process_phy_test_request(struct msm_dp_ctrl_private *ctrl
}
void msm_dp_ctrl_handle_sink_request(struct msm_dp_ctrl *msm_dp_ctrl,
- struct msm_dp_panel *panel)
+ struct msm_dp_panel *panel, bool plugged)
{
struct msm_dp_ctrl_private *ctrl;
u32 sink_request = 0x0;
@@ -2325,7 +2326,7 @@ void msm_dp_ctrl_handle_sink_request(struct msm_dp_ctrl *msm_dp_ctrl,
if (sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
drm_dbg_dp(ctrl->drm_dev, "PHY_TEST_PATTERN request\n");
- if (msm_dp_ctrl_process_phy_test_request(ctrl, panel)) {
+ if (msm_dp_ctrl_process_phy_test_request(ctrl, panel, plugged)) {
DRM_ERROR("process phy_test_req failed\n");
return;
}
@@ -2377,7 +2378,7 @@ static bool msm_dp_ctrl_channel_eq_ok(struct msm_dp_ctrl_private *ctrl)
}
int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl,
- struct msm_dp_panel *panel)
+ struct msm_dp_panel *panel, bool plugged)
{
int rc = 0;
struct msm_dp_ctrl_private *ctrl;
@@ -2427,7 +2428,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) && !plugged)
break;
drm_dp_dpcd_read_link_status(ctrl->aux, link_status);
@@ -2452,7 +2453,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) && !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 fc884038182f..3edf954cc805 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.h
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h
@@ -17,7 +17,7 @@ struct msm_dp_ctrl {
struct phy;
int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl,
- struct msm_dp_panel *panel);
+ struct msm_dp_panel *panel, bool plugged);
int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, struct msm_dp_panel *panel);
int msm_dp_ctrl_prepare_stream_on(struct msm_dp_ctrl *msm_dp_ctrl,
struct msm_dp_panel *panel);
@@ -28,7 +28,7 @@ void msm_dp_ctrl_push_idle(struct msm_dp_ctrl *msm_dp_ctrl);
irqreturn_t msm_dp_ctrl_isr(struct msm_dp_ctrl *msm_dp_ctrl,
struct msm_dp_panel *panel);
void msm_dp_ctrl_handle_sink_request(struct msm_dp_ctrl *msm_dp_ctrl,
- struct msm_dp_panel *panel);
+ struct msm_dp_panel *panel, bool plugged);
struct msm_dp_ctrl *msm_dp_ctrl_get(struct device *dev,
struct msm_dp_link *link,
struct drm_dp_aux *aux,
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 169938ba515e..551d2c63ef8e 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -399,7 +399,7 @@ static int msm_dp_display_handle_irq_hpd(struct msm_dp_display_private *dp)
drm_dbg_dp(dp->drm_dev, "%d\n", sink_request);
- msm_dp_ctrl_handle_sink_request(dp->ctrl, dp->panel);
+ msm_dp_ctrl_handle_sink_request(dp->ctrl, dp->panel, dp->plugged);
if (sink_request & DP_TEST_LINK_VIDEO_PATTERN)
msm_dp_display_handle_video_request(dp);
@@ -648,11 +648,10 @@ static int msm_dp_display_prepare_link(struct msm_dp_display_private *dp)
if (dp->link->sink_count == 0)
return -ENOTCONN;
- if (!msm_dp_display->power_on) {
+ if (!msm_dp_display->power_on)
msm_dp_display_host_phy_init(dp);
- }
- rc = msm_dp_ctrl_on_link(dp->ctrl, dp->panel);
+ rc = msm_dp_ctrl_on_link(dp->ctrl, dp->panel, dp->plugged);
if (rc) {
DRM_ERROR("Failed link training (rc=%d)\n", rc);
// TODO: schedule drm_connector_set_link_status_property()
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/3] phy: qcom: qmp-combo: delay Type-C mux switch while DP PHY is initializing
2026-11-11 10:43 ` [PATCH v2 1/3] phy: qcom: qmp-combo: delay Type-C mux switch while DP PHY is initializing naidu nama
@ 2026-11-11 14:06 ` Dmitry Baryshkov
0 siblings, 0 replies; 7+ messages in thread
From: Dmitry Baryshkov @ 2026-11-11 14:06 UTC (permalink / raw)
To: naidu nama
Cc: vkoul, neil.armstrong, mani, robin.clark, lumag, abhinav.kumar,
jesszhan0024, sean, marijn.suijten, irlied, simona,
Saurabh Anand, linux-arm-msm, linux-phy, linux-kernel, dri-devel,
quic_riteshk, quic_vproddut, quic_mkuntuma, mahadevan.p
On Wed, Nov 11, 2026 at 04:13:53PM +0530, naidu nama wrote:
> From: Saurabh Anand <saurabh.anand@oss.qualcomm.com>
>
> The Type-C mux switch guard only checked dp_powered_on, which is set in
> qmp_combo_dp_power_on(). However there is a race window between
> qmp_combo_dp_init() and qmp_combo_dp_power_on() during which dp_init_count
> is non-zero but dp_powered_on is still false. A Type-C orientation change
> arriving in this window would proceed with the mux switch while the DP PHY
> is mid-initialization, corrupting the PHY state.
How is going to be handled then?
>
> Extend the guard to also block the mux switch when dp_init_count is
> non-zero, covering the full period from dp_init through dp_power_on.
>
> Signed-off-by: Saurabh Anand <saurabh.anand@oss.qualcomm.com>
Naidu, you are resending the other people patches, but the SoB is
missing.
> ---
> drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
> index 61d8b7a5ce8f..3f93043f94e5 100644
> --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
> @@ -5163,7 +5163,8 @@ static int qmp_combo_typec_mux_set(struct typec_mux_dev *mux, struct typec_mux_s
> return 0;
> }
>
> - if (qmp->qmpphy_mode != QMPPHY_MODE_USB3_ONLY && qmp->dp_powered_on) {
> + if (qmp->qmpphy_mode != QMPPHY_MODE_USB3_ONLY &&
> + (qmp->dp_powered_on || qmp->dp_init_count)) {
Can dp_powered_on be dropped then?
> dev_dbg(qmp->dev, "typec_mux_set: DP PHY is still in use, delaying switch\n");
> return 0;
> }
> --
> 2.43.0
>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 2/3] drm/msm/dp: Remove redundant force_link_train flag
2026-11-11 10:43 ` [PATCH v2 2/3] drm/msm/dp: Remove redundant force_link_train flag naidu nama
@ 2026-11-11 14:06 ` Dmitry Baryshkov
0 siblings, 0 replies; 7+ messages in thread
From: Dmitry Baryshkov @ 2026-11-11 14:06 UTC (permalink / raw)
To: naidu nama
Cc: vkoul, neil.armstrong, mani, robin.clark, lumag, abhinav.kumar,
jesszhan0024, sean, marijn.suijten, irlied, simona,
Saurabh Anand, linux-arm-msm, linux-phy, linux-kernel, dri-devel,
quic_riteshk, quic_vproddut, quic_mkuntuma, mahadevan.p
On Wed, Nov 11, 2026 at 04:13:54PM +0530, naidu nama wrote:
> From: Saurabh Anand <saurabh.anand@oss.qualcomm.com>
>
> force_link_train is always false when passed to
> msm_dp_ctrl_prepare_stream_on(): the initial link is trained by
> msm_dp_ctrl_on_link(), and the flag is cleared before stream preparation.
> For active streams, it is never set.
>
> Remove the dead flag and parameter. Stream preparation still retrains
> when channel equalization is incomplete.
>
> Signed-off-by: Saurabh Anand <saurabh.anand@oss.qualcomm.com>
> ---
> drivers/gpu/drm/msm/dp/dp_ctrl.c | 5 ++---
> drivers/gpu/drm/msm/dp/dp_ctrl.h | 3 +--
> drivers/gpu/drm/msm/dp/dp_display.c | 4 +---
> 3 files changed, 4 insertions(+), 8 deletions(-)
The same SoB comment.
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 3/3] drm/msm/dp: continue link training downgrade when cable is still plugged
2026-11-11 10:43 ` [PATCH v2 3/3] drm/msm/dp: continue link training downgrade when cable is still plugged naidu nama
@ 2026-11-11 14:08 ` Dmitry Baryshkov
0 siblings, 0 replies; 7+ messages in thread
From: Dmitry Baryshkov @ 2026-11-11 14:08 UTC (permalink / raw)
To: naidu nama
Cc: vkoul, neil.armstrong, mani, robin.clark, lumag, abhinav.kumar,
jesszhan0024, sean, marijn.suijten, irlied, simona,
Saurabh Anand, linux-arm-msm, linux-phy, linux-kernel, dri-devel,
quic_riteshk, quic_vproddut, quic_mkuntuma, mahadevan.p
On Wed, Nov 11, 2026 at 04:13:55PM +0530, naidu nama wrote:
> From: Saurabh Anand <saurabh.anand@oss.qualcomm.com>
>
> 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.
Is there a reason to assume that DP is not plugged at this point? I
guess not. But the other issue is: what if the DP gets unplugged in the
middle of link training.
>
> Signed-off-by: Saurabh Anand <saurabh.anand@oss.qualcomm.com>
SoB
> ---
> drivers/gpu/drm/msm/dp/dp_ctrl.c | 15 ++++++++-------
> drivers/gpu/drm/msm/dp/dp_ctrl.h | 4 ++--
> drivers/gpu/drm/msm/dp/dp_display.c | 7 +++----
> 3 files changed, 13 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
> index 6b9d9a76ba05..f8a6bd7b0d10 100644
> --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
> +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
> @@ -2274,7 +2274,8 @@ void msm_dp_ctrl_off_pixel_clk(struct msm_dp_ctrl *msm_dp_ctrl, enum msm_dp_stre
> }
>
> static int msm_dp_ctrl_process_phy_test_request(struct msm_dp_ctrl_private *ctrl,
> - struct msm_dp_panel *panel)
> + struct msm_dp_panel *panel,
> + bool plugged)
Can it ever be false here with your patch in place?
> {
> int ret;
> unsigned long pixel_rate;
> @@ -2293,7 +2294,7 @@ static int msm_dp_ctrl_process_phy_test_request(struct msm_dp_ctrl_private *ctrl
> msm_dp_ctrl_off_pixel_clk(&ctrl->msm_dp_ctrl, panel->stream_id);
> msm_dp_ctrl_off_link(&ctrl->msm_dp_ctrl, panel);
>
> - ret = msm_dp_ctrl_on_link(&ctrl->msm_dp_ctrl, panel);
> + ret = msm_dp_ctrl_on_link(&ctrl->msm_dp_ctrl, panel, plugged);
> if (ret) {
> DRM_ERROR("failed to enable DP link controller\n");
> return ret;
> @@ -2310,7 +2311,7 @@ static int msm_dp_ctrl_process_phy_test_request(struct msm_dp_ctrl_private *ctrl
> }
>
> void msm_dp_ctrl_handle_sink_request(struct msm_dp_ctrl *msm_dp_ctrl,
> - struct msm_dp_panel *panel)
> + struct msm_dp_panel *panel, bool plugged)
> {
> struct msm_dp_ctrl_private *ctrl;
> u32 sink_request = 0x0;
> @@ -2325,7 +2326,7 @@ void msm_dp_ctrl_handle_sink_request(struct msm_dp_ctrl *msm_dp_ctrl,
>
> if (sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
> drm_dbg_dp(ctrl->drm_dev, "PHY_TEST_PATTERN request\n");
> - if (msm_dp_ctrl_process_phy_test_request(ctrl, panel)) {
> + if (msm_dp_ctrl_process_phy_test_request(ctrl, panel, plugged)) {
> DRM_ERROR("process phy_test_req failed\n");
> return;
> }
> @@ -2377,7 +2378,7 @@ static bool msm_dp_ctrl_channel_eq_ok(struct msm_dp_ctrl_private *ctrl)
> }
>
> int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl,
> - struct msm_dp_panel *panel)
> + struct msm_dp_panel *panel, bool plugged)
> {
> int rc = 0;
> struct msm_dp_ctrl_private *ctrl;
> @@ -2427,7 +2428,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) && !plugged)
> break;
>
> drm_dp_dpcd_read_link_status(ctrl->aux, link_status);
> @@ -2452,7 +2453,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) && !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 fc884038182f..3edf954cc805 100644
> --- a/drivers/gpu/drm/msm/dp/dp_ctrl.h
> +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h
> @@ -17,7 +17,7 @@ struct msm_dp_ctrl {
> struct phy;
>
> int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl,
> - struct msm_dp_panel *panel);
> + struct msm_dp_panel *panel, bool plugged);
> int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, struct msm_dp_panel *panel);
> int msm_dp_ctrl_prepare_stream_on(struct msm_dp_ctrl *msm_dp_ctrl,
> struct msm_dp_panel *panel);
> @@ -28,7 +28,7 @@ void msm_dp_ctrl_push_idle(struct msm_dp_ctrl *msm_dp_ctrl);
> irqreturn_t msm_dp_ctrl_isr(struct msm_dp_ctrl *msm_dp_ctrl,
> struct msm_dp_panel *panel);
> void msm_dp_ctrl_handle_sink_request(struct msm_dp_ctrl *msm_dp_ctrl,
> - struct msm_dp_panel *panel);
> + struct msm_dp_panel *panel, bool plugged);
> struct msm_dp_ctrl *msm_dp_ctrl_get(struct device *dev,
> struct msm_dp_link *link,
> struct drm_dp_aux *aux,
> diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
> index 169938ba515e..551d2c63ef8e 100644
> --- a/drivers/gpu/drm/msm/dp/dp_display.c
> +++ b/drivers/gpu/drm/msm/dp/dp_display.c
> @@ -399,7 +399,7 @@ static int msm_dp_display_handle_irq_hpd(struct msm_dp_display_private *dp)
>
> drm_dbg_dp(dp->drm_dev, "%d\n", sink_request);
>
> - msm_dp_ctrl_handle_sink_request(dp->ctrl, dp->panel);
> + msm_dp_ctrl_handle_sink_request(dp->ctrl, dp->panel, dp->plugged);
>
> if (sink_request & DP_TEST_LINK_VIDEO_PATTERN)
> msm_dp_display_handle_video_request(dp);
> @@ -648,11 +648,10 @@ static int msm_dp_display_prepare_link(struct msm_dp_display_private *dp)
> if (dp->link->sink_count == 0)
> return -ENOTCONN;
>
> - if (!msm_dp_display->power_on) {
> + if (!msm_dp_display->power_on)
> msm_dp_display_host_phy_init(dp);
> - }
>
> - rc = msm_dp_ctrl_on_link(dp->ctrl, dp->panel);
> + rc = msm_dp_ctrl_on_link(dp->ctrl, dp->panel, dp->plugged);
> if (rc) {
> DRM_ERROR("Failed link training (rc=%d)\n", rc);
> // TODO: schedule drm_connector_set_link_status_property()
> --
> 2.43.0
>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-11-11 14:09 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-11 10:43 [PATCH v2 0/3] drm/msm/dp, phy: qcom: improve DP Type-C reconnect handli naidu nama
2026-11-11 10:43 ` [PATCH v2 1/3] phy: qcom: qmp-combo: delay Type-C mux switch while DP PHY is initializing naidu nama
2026-11-11 14:06 ` Dmitry Baryshkov
2026-11-11 10:43 ` [PATCH v2 2/3] drm/msm/dp: Remove redundant force_link_train flag naidu nama
2026-11-11 14:06 ` Dmitry Baryshkov
2026-11-11 10:43 ` [PATCH v2 3/3] drm/msm/dp: continue link training downgrade when cable is still plugged naidu nama
2026-11-11 14:08 ` Dmitry Baryshkov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®