[PATCH RESEND v5 19/25] drm/msm/dp: initialize dp_mst module for each DP MST controller

From: Yongxing Mou

Date: Mon Jun 29 2026 - 10:30:18 EST


From: Abhinav Kumar <quic_abhinavk@xxxxxxxxxxx>

For each MST capable DP controller, initialize a dp_mst module to
manage its DP MST operations. The DP MST module for each controller
is the central entity to manage its topology related operations as
well as interfacing with the rest of the DP driver.

Signed-off-by: Abhinav Kumar <quic_abhinavk@xxxxxxxxxxx>
Signed-off-by: Yongxing Mou <yongxing.mou@xxxxxxxxxxxxxxxx>
---
drivers/gpu/drm/msm/Makefile | 3 +-
drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 6 ++++
drivers/gpu/drm/msm/dp/dp_display.c | 18 ++++++++++
drivers/gpu/drm/msm/dp/dp_display.h | 2 ++
drivers/gpu/drm/msm/dp/dp_mst_drm.c | 60 +++++++++++++++++++++++++++++++++
drivers/gpu/drm/msm/dp/dp_mst_drm.h | 13 +++++++
drivers/gpu/drm/msm/msm_drv.h | 6 ++++
7 files changed, 107 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index ba45e99be05b..d510be1c173f 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -145,7 +145,8 @@ msm-display-$(CONFIG_DRM_MSM_DP)+= dp/dp_aux.o \
dp/dp_link.o \
dp/dp_panel.o \
dp/dp_audio.o \
- dp/dp_utils.o
+ dp/dp_utils.o \
+ dp/dp_mst_drm.o

msm-display-$(CONFIG_DRM_MSM_HDMI_HDCP) += hdmi/hdmi_hdcp.o

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 7a00c4094d5c..91d33b432427 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -682,6 +682,12 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev,
stream_cnt = msm_dp_get_mst_max_stream(priv->kms->dp[i]);

if (stream_cnt > 1) {
+ rc = msm_dp_mst_register(priv->kms->dp[i]);
+ if (rc) {
+ DPU_ERROR("dp_mst_init failed for DP, rc = %d\n", rc);
+ return rc;
+ }
+
for (stream_id = 0; stream_id < stream_cnt; stream_id++) {
encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_DPMST, &info);
if (IS_ERR(encoder)) {
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index d56ee10ee065..fc9c1e3e57ab 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -28,6 +28,7 @@
#include "dp_drm.h"
#include "dp_audio.h"
#include "dp_debug.h"
+#include "dp_mst_drm.h"

static bool psr_enabled = false;
module_param(psr_enabled, bool, 0);
@@ -351,6 +352,9 @@ static int msm_dp_display_process_hpd_high(struct msm_dp_display_private *dp)
if (dp->max_stream > 1 && drm_dp_read_mst_cap(dp->aux, dp->panel->dpcd))
msm_dp_display_mst_init(dp);

+ if (dp->msm_dp_display.mst_active)
+ msm_dp_mst_display_set_mgr_state(&dp->msm_dp_display, true);
+
msm_dp_link_reset_phy_params_vx_px(dp->link);

end:
@@ -522,6 +526,11 @@ static int msm_dp_hpd_unplug_handle(struct msm_dp_display_private *dp)
dp->panel->dpcd,
dp->panel->downstream_ports);

+ if (dp->msm_dp_display.mst_active) {
+ msm_dp_mst_display_set_mgr_state(&dp->msm_dp_display, false);
+ dp->msm_dp_display.mst_active = false;
+ }
+
/* signal the disconnect event early to ensure proper teardown */
msm_dp_display_handle_plugged_change(&dp->msm_dp_display, false);

@@ -1530,6 +1539,15 @@ int msm_dp_modeset_init(struct msm_dp *msm_dp_display, struct drm_device *dev,
return 0;
}

+int msm_dp_mst_register(struct msm_dp *msm_dp_display)
+{
+ struct msm_dp_display_private *dp;
+
+ dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display);
+
+ return msm_dp_mst_init(msm_dp_display, dp->max_stream, dp->aux);
+}
+
int msm_dp_display_set_mode_helper(struct msm_dp *msm_dp_display,
struct drm_atomic_commit *state,
struct drm_encoder *drm_encoder,
diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h
index 0464f8941e8d..a185819ec57e 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.h
+++ b/drivers/gpu/drm/msm/dp/dp_display.h
@@ -24,6 +24,8 @@ struct msm_dp {
bool is_edp;
bool link_ready;

+ void *msm_dp_mst;
+
struct msm_dp_audio *msm_dp_audio;
bool psr_supported;
};
diff --git a/drivers/gpu/drm/msm/dp/dp_mst_drm.c b/drivers/gpu/drm/msm/dp/dp_mst_drm.c
new file mode 100644
index 000000000000..78b8dffe111b
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_mst_drm.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <drm/drm_edid.h>
+#include <drm/display/drm_dp_mst_helper.h>
+
+#include "dp_mst_drm.h"
+#include "dp_panel.h"
+
+struct msm_dp_mst {
+ struct drm_dp_mst_topology_mgr mst_mgr;
+ struct msm_dp *msm_dp;
+ struct drm_dp_aux *dp_aux;
+ u32 max_streams;
+};
+
+int msm_dp_mst_display_set_mgr_state(struct msm_dp *dp_display, bool state)
+{
+ struct msm_dp_mst *mst = dp_display->msm_dp_mst;
+ int rc;
+
+ rc = drm_dp_mst_topology_mgr_set_mst(&mst->mst_mgr, state);
+ if (rc < 0) {
+ drm_err(dp_display->drm_dev,
+ "[MST] failed to set topology mgr state to %d rc:%d\n", state, rc);
+ }
+
+ drm_dbg_kms(dp_display->drm_dev, "[MST] set_mgr_state state:%d\n", state);
+ return rc;
+}
+
+int msm_dp_mst_init(struct msm_dp *dp_display, u32 max_streams, struct drm_dp_aux *drm_aux)
+{
+ struct drm_device *dev = dp_display->drm_dev;
+ struct msm_dp_mst *mst;
+ int ret;
+
+ mst = devm_kzalloc(dev->dev, sizeof(*mst), GFP_KERNEL);
+ if (!mst)
+ return -ENOMEM;
+
+ mst->msm_dp = dp_display;
+ mst->max_streams = max_streams;
+ mst->dp_aux = drm_aux;
+
+ ret = drm_dp_mst_topology_mgr_init(&mst->mst_mgr, dev,
+ drm_aux,
+ 16,
+ max_streams,
+ dp_display->connector->base.id);
+ if (ret) {
+ drm_err(dev, "[MST] topology manager init failed\n");
+ return ret;
+ }
+
+ dp_display->msm_dp_mst = mst;
+ return 0;
+}
diff --git a/drivers/gpu/drm/msm/dp/dp_mst_drm.h b/drivers/gpu/drm/msm/dp/dp_mst_drm.h
new file mode 100644
index 000000000000..5d411529f681
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_mst_drm.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _DP_MST_DRM_H_
+#define _DP_MST_DRM_H_
+
+#include "dp_display.h"
+
+int msm_dp_mst_init(struct msm_dp *dp_display, u32 max_streams, struct drm_dp_aux *drm_aux);
+int msm_dp_mst_display_set_mgr_state(struct msm_dp *dp_display, bool state);
+
+#endif /* _DP_MST_DRM_H_ */
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 5fee0b291059..963303079220 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -356,6 +356,7 @@ bool msm_dp_needs_periph_flush(const struct msm_dp *dp_display,
const struct drm_display_mode *mode);
bool msm_dp_wide_bus_available(const struct msm_dp *dp_display);
int msm_dp_get_mst_max_stream(struct msm_dp *dp_display);
+int msm_dp_mst_register(struct msm_dp *dp_display);
#else
static inline int __init msm_dp_register(void)
{
@@ -377,6 +378,11 @@ static inline int msm_dp_get_mst_max_stream(struct msm_dp *dp_display)
return -EINVAL;
}

+static inline int msm_dp_mst_register(struct msm_dp *dp_display)
+{
+ return -EINVAL;
+}
+
static inline void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp_display)
{
}

--
2.43.0