[PATCH v6 18/29] drm/msm/dp: introduce dp_mst_drm module
From: Yongxing Mou
Date: Mon Aug 31 2026 - 04:24:24 EST
Add the dp_mst_drm module and the core MST manager data structures.
Introduce the MST manager object, per-stream encoder state and the
initialization path for creating a DRM MST topology manager associated
with a DP controller.
Also add the registration hooks used to initialize the MST manager
during DP device setup.
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 | 12 +++++++-
drivers/gpu/drm/msm/dp/dp_display.c | 19 ++++++++++++
drivers/gpu/drm/msm/dp/dp_display.h | 4 +++
drivers/gpu/drm/msm/dp/dp_mst_drm.c | 54 +++++++++++++++++++++++++++++++++
drivers/gpu/drm/msm/dp/dp_mst_drm.h | 12 ++++++++
drivers/gpu/drm/msm/msm_drv.h | 12 ++++++++
7 files changed, 114 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index d0c3a4c6703b..31a15636958c 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 da3556eb6ecc..66cabac0a726 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -655,7 +655,7 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev,
struct msm_display_info info;
bool yuv_supported;
int rc;
- int i;
+ int i, stream_cnt;
for (i = 0; i < ARRAY_SIZE(priv->kms->dp); i++) {
if (!priv->kms->dp[i])
@@ -678,6 +678,16 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev,
DPU_ERROR("modeset_init failed for DP, rc = %d\n", rc);
return rc;
}
+
+ 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;
+ }
+ }
}
return 0;
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 6952f83db006..c015af868801 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -27,6 +27,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);
@@ -1270,6 +1271,24 @@ static int msm_dp_display_get_io(struct msm_dp_display_private *display)
return 0;
}
+int msm_dp_get_mst_max_stream(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_ctrl_get_stream_cnt(dp->ctrl);
+}
+
+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_mgr_init(msm_dp_display, msm_dp_ctrl_get_stream_cnt(dp->ctrl), dp->aux);
+}
+
static int msm_dp_display_probe(struct platform_device *pdev)
{
int rc = 0;
diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h
index 4d4349068c2f..ca2faf478c95 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 {
unsigned int connector_type;
bool is_edp;
+ void *msm_dp_mst;
+
struct msm_dp_audio *msm_dp_audio;
bool psr_supported;
};
@@ -59,6 +61,8 @@ int msm_dp_display_set_mode_helper(struct msm_dp *msm_dp_display,
int msm_dp_display_prepare_link(struct msm_dp *msm_dp_display);
void msm_dp_display_unprepare(struct msm_dp *dp);
+int msm_dp_get_mst_max_stream(struct msm_dp *msm_dp_display);
+int msm_dp_mst_register(struct msm_dp *msm_dp_display);
struct msm_dp_panel *msm_dp_display_get_panel(struct msm_dp *msm_dp_display,
enum msm_dp_stream_id stream_id);
#endif /* _DP_DISPLAY_H_ */
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..648d3ec72a1d
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_mst_drm.c
@@ -0,0 +1,54 @@
+// 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_fixed.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/display/drm_dp_mst_helper.h>
+
+#include "dp_mst_drm.h"
+#include "dp_panel.h"
+
+struct msm_dp_mst_encoder {
+ struct drm_encoder *enc;
+ int stream_id;
+ struct msm_dp_panel *dp_panel;
+};
+
+struct msm_dp_mst {
+ struct drm_dp_mst_topology_mgr mst_mgr;
+ struct msm_dp_mst_encoder mst_encoders[DP_STREAM_MAX];
+ struct msm_dp *msm_dp;
+ struct drm_dp_aux *dp_aux;
+ u32 max_streams;
+};
+
+int msm_dp_mst_mgr_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..e54d49cf3499
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_mst_drm.h
@@ -0,0 +1,12 @@
+/* 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_mgr_init(struct msm_dp *dp_display, u32 max_streams, struct drm_dp_aux *drm_aux);
+
+#endif /* _DP_MST_DRM_H_ */
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index eb4bbae8557b..8e98f7eb8724 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -357,6 +357,8 @@ void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp_displa
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)
@@ -389,6 +391,16 @@ static inline bool msm_dp_wide_bus_available(const struct msm_dp *dp_display)
return false;
}
+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;
+}
+
#endif
#ifdef CONFIG_DRM_MSM_MDP4
--
2.43.0