[PATCH v4 33/39] drm/msm/dp: initialize dp_mst module for each DP MST controller

From: Yongxing Mou

Date: Fri Apr 10 2026 - 05:46:07 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 | 73 +++++++++++++++++++++++++++++++++
drivers/gpu/drm/msm/dp/dp_mst_drm.h | 13 ++++++
drivers/gpu/drm/msm/msm_drv.h | 6 +++
7 files changed, 120 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 8b94c5f1cb68..1d8426876aa1 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -144,7 +144,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 090e7d790593..d7ce13a4586d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -680,6 +680,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 9eaf6994a350..919767945ba5 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);
@@ -360,6 +361,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:
@@ -527,6 +531,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);

@@ -1556,6 +1565,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_state *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 bda76319c459..55874daf41c4 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 prepared;

+ 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..b6c7b8211025
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_mst_drm.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <drm/drm_edid.h>
+#include <drm/drm_managed.h>
+#include <drm/drm_bridge.h>
+#include <drm/display/drm_dp_mst_helper.h>
+
+#include "dp_mst_drm.h"
+#include "dp_panel.h"
+
+#define MAX_DPCD_TRANSACTION_BYTES 16
+
+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;
+ /* Protects MST bridge enable/disable handling. */
+ struct mutex mst_lock;
+};
+
+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_ERROR("failed to set topology mgr state to %d. rc %d\n",
+ state, rc);
+ }
+
+ drm_dbg_dp(dp_display->drm_dev, "dp_mst_display_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;
+ int conn_base_id = 0;
+ int ret;
+ struct msm_dp_mst *msm_dp_mst;
+
+ msm_dp_mst = devm_kzalloc(dev->dev, sizeof(*msm_dp_mst), GFP_KERNEL);
+ if (!msm_dp_mst)
+ return -ENOMEM;
+
+ memset(&msm_dp_mst->mst_mgr, 0, sizeof(msm_dp_mst->mst_mgr));
+
+ conn_base_id = dp_display->connector->base.id;
+ msm_dp_mst->msm_dp = dp_display;
+ msm_dp_mst->max_streams = max_streams;
+
+ msm_dp_mst->dp_aux = drm_aux;
+
+ ret = drm_dp_mst_topology_mgr_init(&msm_dp_mst->mst_mgr, dev,
+ drm_aux,
+ MAX_DPCD_TRANSACTION_BYTES,
+ max_streams,
+ conn_base_id);
+ if (ret) {
+ DRM_ERROR("DP DRM MST topology manager init failed\n");
+ return ret;
+ }
+
+ dp_display->msm_dp_mst = msm_dp_mst;
+
+ mutex_init(&msm_dp_mst->mst_lock);
+ return ret;
+}
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 3061eca49cb2..5f73e0aa1c2f 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -363,6 +363,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)
{
@@ -384,6 +385,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