[PATCH v6 22/29] drm/msm/dpu: add per-stream MST encoders
From: Yongxing Mou
Date: Mon Aug 31 2026 - 04:36:00 EST
Unlike SST, where a DP controller is represented by a single encoder,
MST requires an encoder instance for each stream.
Create one DRM encoder per MST stream, associate it with a stream ID,
and initialize it with MST-specific encoder helper callbacks.
This establishes the per-stream encoder infrastructure required for DP
MST support.
Signed-off-by: Abhinav Kumar <quic_abhinavk@xxxxxxxxxxx>
Signed-off-by: Yongxing Mou <yongxing.mou@xxxxxxxxxxxxxxxx>
---
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 23 ++++++++++++++++++++++-
drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 15 +++++++++++++++
drivers/gpu/drm/msm/dp/dp_mst_drm.c | 20 ++++++++++++++++++++
drivers/gpu/drm/msm/dp/dp_mst_drm.h | 2 ++
drivers/gpu/drm/msm/msm_drv.h | 9 +++++++++
5 files changed, 68 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 004d5fc460a8..533109b4365c 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -2744,6 +2744,24 @@ static const struct drm_encoder_helper_funcs dpu_encoder_helper_funcs = {
.atomic_enable = dpu_encoder_virt_atomic_enable,
};
+static void dpu_encoder_mst_atomic_enable(struct drm_encoder *enc,
+ struct drm_atomic_commit *state)
+{
+ dpu_encoder_virt_atomic_enable(enc, state);
+}
+
+static void dpu_encoder_mst_atomic_disable(struct drm_encoder *enc,
+ struct drm_atomic_commit *state)
+{
+ dpu_encoder_virt_atomic_disable(enc, state);
+}
+
+static const struct drm_encoder_helper_funcs dpu_mst_encoder_helper_funcs = {
+ .atomic_mode_set = dpu_encoder_virt_atomic_mode_set,
+ .atomic_enable = dpu_encoder_mst_atomic_enable,
+ .atomic_disable = dpu_encoder_mst_atomic_disable,
+};
+
static const struct drm_encoder_funcs dpu_encoder_funcs = {
.debugfs_init = dpu_encoder_debugfs_init,
};
@@ -2769,7 +2787,10 @@ struct drm_encoder *dpu_encoder_init(struct drm_device *dev,
if (IS_ERR(dpu_enc))
return ERR_CAST(dpu_enc);
- drm_encoder_helper_add(&dpu_enc->base, &dpu_encoder_helper_funcs);
+ if (drm_enc_mode == DRM_MODE_ENCODER_DPMST)
+ drm_encoder_helper_add(&dpu_enc->base, &dpu_mst_encoder_helper_funcs);
+ else
+ drm_encoder_helper_add(&dpu_enc->base, &dpu_encoder_helper_funcs);
spin_lock_init(&dpu_enc->enc_spinlock);
dpu_enc->enabled = false;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 66cabac0a726..d6182cec06d5 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -688,6 +688,21 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev,
return rc;
}
}
+
+ for (int stream_id = 0; stream_cnt > 1 && stream_id < stream_cnt; stream_id++) {
+ info.stream_id = stream_id;
+ encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_DPMST, &info);
+ if (IS_ERR(encoder)) {
+ DPU_ERROR("encoder init failed for dp mst display\n");
+ return PTR_ERR(encoder);
+ }
+
+ rc = msm_dp_mst_attach_encoder(priv->kms->dp[i], stream_id, encoder);
+ if (rc) {
+ DPU_ERROR("dp_mst attach_encoder failed, rc = %d\n", rc);
+ return rc;
+ }
+ }
}
return 0;
diff --git a/drivers/gpu/drm/msm/dp/dp_mst_drm.c b/drivers/gpu/drm/msm/dp/dp_mst_drm.c
index 94a717ba7c82..93536b6936cb 100644
--- a/drivers/gpu/drm/msm/dp/dp_mst_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_mst_drm.c
@@ -145,6 +145,26 @@ static int msm_dp_mst_encoder_stream_id(struct msm_dp_mst *mst,
return -1;
}
+int msm_dp_mst_attach_encoder(struct msm_dp *dp_display, unsigned int stream_id,
+ struct drm_encoder *encoder)
+{
+ struct msm_dp_mst *mst = dp_display->msm_dp_mst;
+ struct msm_dp_panel *dp_panel;
+
+ dp_panel = msm_dp_display_get_panel(dp_display, stream_id);
+ if (!dp_panel) {
+ drm_err(dp_display->drm_dev,
+ "[MST] failed to allocate panel for stream %d\n", stream_id);
+ return -ENOMEM;
+ }
+
+ mst->mst_encoders[stream_id].enc = encoder;
+ mst->mst_encoders[stream_id].stream_id = stream_id;
+ mst->mst_encoders[stream_id].dp_panel = dp_panel;
+
+ return 0;
+}
+
static struct drm_encoder *
msm_dp_mst_atomic_best_encoder(struct drm_connector *connector, struct drm_atomic_commit *state)
{
diff --git a/drivers/gpu/drm/msm/dp/dp_mst_drm.h b/drivers/gpu/drm/msm/dp/dp_mst_drm.h
index e54d49cf3499..89f73b1db2e7 100644
--- a/drivers/gpu/drm/msm/dp/dp_mst_drm.h
+++ b/drivers/gpu/drm/msm/dp/dp_mst_drm.h
@@ -8,5 +8,7 @@
#include "dp_display.h"
int msm_dp_mst_mgr_init(struct msm_dp *dp_display, u32 max_streams, struct drm_dp_aux *drm_aux);
+int msm_dp_mst_attach_encoder(struct msm_dp *dp_display, unsigned int stream_id,
+ struct drm_encoder *encoder);
#endif /* _DP_MST_DRM_H_ */
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 8e98f7eb8724..6c6a1546478d 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -359,6 +359,8 @@ bool msm_dp_needs_periph_flush(const struct msm_dp *dp_display,
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);
+int msm_dp_mst_attach_encoder(struct msm_dp *dp_display, unsigned int stream_id,
+ struct drm_encoder *encoder);
#else
static inline int __init msm_dp_register(void)
@@ -401,6 +403,13 @@ static inline int msm_dp_mst_register(struct msm_dp *dp_display)
return -EINVAL;
}
+static inline int msm_dp_mst_attach_encoder(struct msm_dp *dp_display,
+ unsigned int stream_id,
+ struct drm_encoder *encoder)
+{
+ return -EINVAL;
+}
+
#endif
#ifdef CONFIG_DRM_MSM_MDP4
--
2.43.0