Re: [PATCH RESEND v5 15/25] drm/msm/dp: add an API to initialize MST on sink side

From: Yongxing Mou

Date: Wed Aug 26 2026 - 03:49:57 EST




On 7/13/2026 5:35 AM, Dmitry Baryshkov wrote:
On Mon, Jun 29, 2026 at 10:14:36PM +0800, Yongxing Mou wrote:
From: Abhinav Kumar <quic_abhinavk@xxxxxxxxxxx>

If the DP controller is capable of supporting multiple streams
then initialize the DP sink in MST mode by programming the DP_MSTM_CTRL
DPCD register to enable MST mode.

Signed-off-by: Abhinav Kumar <quic_abhinavk@xxxxxxxxxxx>
Signed-off-by: Yongxing Mou <yongxing.mou@xxxxxxxxxxxxxxxx>
---
drivers/gpu/drm/msm/dp/dp_display.c | 48 +++++++++++++++++++++++++++++++------
1 file changed, 41 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 5786e598a406..c3be656f10ee 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -14,6 +14,7 @@
#include <linux/string_choices.h>
#include <drm/display/drm_dp_aux_bus.h>
#include <drm/display/drm_hdmi_audio_helper.h>
+#include <drm/display/drm_dp_mst_helper.h>
#include <drm/drm_edid.h>
#include "msm_drv.h"
@@ -270,6 +271,31 @@ static int msm_dp_display_lttpr_init(struct msm_dp_display_private *dp, u8 *dpcd
return lttpr_count;
}
+static void msm_dp_display_mst_init(struct msm_dp_display_private *dp)
+{
+ u8 old_mstm_ctrl;
+ struct msm_dp *msm_dp = &dp->msm_dp_display;
+ int ret;
+
+ /* clear sink MST state */
+ drm_dp_dpcd_read_byte(dp->aux, DP_MSTM_CTRL, &old_mstm_ctrl);
+
+ ret = drm_dp_dpcd_write_byte(dp->aux, DP_MSTM_CTRL, 0);
+ if (ret < 0) {
+ DRM_ERROR("failed to clear DP_MSTM_CTRL, ret=%d\n", ret);
+ return;
+ }

Is it not enough to write the new value? Please add a small comment,
why (reference DP standard in the commit message, please).

Got it.
+
+ ret = drm_dp_dpcd_write_byte(dp->aux, DP_MSTM_CTRL,
+ DP_MST_EN | DP_UP_REQ_EN | DP_UPSTREAM_IS_SRC);
+ if (ret < 0) {
+ DRM_ERROR("sink MST enablement failed\n");
+ return;
+ }
+
+ msm_dp->mst_active = true;
+}
+
static int msm_dp_display_process_hpd_high(struct msm_dp_display_private *dp)
{
struct drm_connector *connector = dp->msm_dp_display.connector;
@@ -288,14 +314,19 @@ static int msm_dp_display_process_hpd_high(struct msm_dp_display_private *dp)
if (rc)
goto end;
- drm_edid = drm_edid_read_ddc(connector, &dp->aux->ddc);
- drm_edid_connector_update(connector, drm_edid);
+ if (!(dp->max_stream > 1) || !drm_dp_read_mst_cap(dp->aux, dp->panel->dpcd)) {
+ drm_edid = drm_edid_read_ddc(connector, &dp->aux->ddc);
+ drm_edid_connector_update(connector, drm_edid);
- if (!drm_edid) {
- DRM_ERROR("panel edid read failed\n");
- /* check edid read fail is due to unplug */
- if (!msm_dp_aux_is_link_connected(dp->aux))
- return -ETIMEDOUT;
+ if (!drm_edid) {
+ DRM_ERROR("panel edid read failed\n");
+ /* check edid read fail is due to unplug */
+ if (!msm_dp_aux_is_link_connected(dp->aux))
+ return -ETIMEDOUT;
+ }
+
+ if (rc)
+ goto end;

This also is going to break DP. If you are using dp->max_streams as a
determining factor, rearrange commits so that max_streams are parseed
and set only after the rest of the commits are in place (and the driver
is ready for DP MST).

Sorry, that was an oversight. Those two lines shouldn't be there. The patch wasn't clean enough, and I'll remove them in the next revision.
}
msm_dp_link_process_request(dp->link);
@@ -317,6 +348,9 @@ static int msm_dp_display_process_hpd_high(struct msm_dp_display_private *dp)
*/
msm_dp_link_psm_config(dp->link, &dp->panel->link_info, false);
+ if (dp->max_stream > 1 && drm_dp_read_mst_cap(dp->aux, dp->panel->dpcd))
+ msm_dp_display_mst_init(dp);
+
msm_dp_link_reset_phy_params_vx_px(dp->link);
end:

--
2.43.0