From: Abhinav Kumar <[email protected]> MST topology discovery requires the sink to operate in MST mode. Enable MST on sinks that advertise MST capability and are connected to a multi-stream capable DP controller.
Once MST is enabled, downstream sink discovery and EDID retrieval are handled through the MST topology rather than the primary DP connector. Activate the MST topology manager on connect and disable it on disconnect to track the sink topology lifecycle. Signed-off-by: Abhinav Kumar <[email protected]> Signed-off-by: Yongxing Mou <[email protected]> --- drivers/gpu/drm/msm/dp/dp_display.c | 52 ++++++++++++++++++++++++++++++++----- drivers/gpu/drm/msm/dp/dp_mst_drm.c | 15 +++++++++++ drivers/gpu/drm/msm/dp/dp_mst_drm.h | 1 + 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 21dadc2e6cdc..e913ed91bbfd 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" @@ -269,10 +270,34 @@ static int msm_dp_display_lttpr_init(struct msm_dp_display_private *dp, u8 *dpcd return lttpr_count; } +static void msm_dp_display_mst_enable(struct msm_dp_display_private *dp) +{ + struct msm_dp *msm_dp = &dp->msm_dp_display; + int ret; + + /* Clear any pre-existing MST state before enabling MST. */ + 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; + } + + 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; + msm_dp_mst_display_set_mgr_state(msm_dp, true); +} + static int msm_dp_display_process_hpd_high(struct msm_dp_display_private *dp) { struct drm_connector *connector = dp->msm_dp_display.connector; const struct drm_display_info *info = &connector->display_info; + enum drm_dp_mst_mode mst_mode = DRM_DP_SST; int rc = 0; u8 dpcd[DP_RECEIVER_CAP_SIZE]; const struct drm_edid *drm_edid = NULL; @@ -287,14 +312,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 (msm_dp_ctrl_get_stream_cnt(dp->ctrl) > 1) + mst_mode = drm_dp_read_mst_cap(dp->aux, dp->panel->dpcd); + + if (mst_mode != DRM_DP_MST) { + 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; + } } msm_dp_link_process_request(dp->link); @@ -316,6 +346,9 @@ static int msm_dp_display_process_hpd_high(struct msm_dp_display_private *dp) */ msm_dp_link_psm_config(dp->link, &dp->link->link_caps, false); + if (mst_mode == DRM_DP_MST) + msm_dp_display_mst_enable(dp); + msm_dp_link_reset_phy_params_vx_px(dp->link); end: @@ -499,6 +532,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); diff --git a/drivers/gpu/drm/msm/dp/dp_mst_drm.c b/drivers/gpu/drm/msm/dp/dp_mst_drm.c index 4c0ad3dc5793..35193cf45a6f 100644 --- a/drivers/gpu/drm/msm/dp/dp_mst_drm.c +++ b/drivers/gpu/drm/msm/dp/dp_mst_drm.c @@ -361,6 +361,21 @@ int msm_dp_mst_attach_encoder(struct msm_dp *dp_display, unsigned int stream_id, return 0; } +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; +} + void msm_dp_mst_display_hpd_irq(struct msm_dp *dp_display) { int rc; diff --git a/drivers/gpu/drm/msm/dp/dp_mst_drm.h b/drivers/gpu/drm/msm/dp/dp_mst_drm.h index 3bd3e66b4eac..84de7ca0c689 100644 --- a/drivers/gpu/drm/msm/dp/dp_mst_drm.h +++ b/drivers/gpu/drm/msm/dp/dp_mst_drm.h @@ -12,6 +12,7 @@ int msm_dp_mst_mgr_init(struct msm_dp *dp_display, struct msm_dp_link *link, void msm_dp_mst_mgr_destroy(struct msm_dp *dp_display); int msm_dp_mst_attach_encoder(struct msm_dp *dp_display, unsigned int stream_id, struct drm_encoder *encoder); +int msm_dp_mst_display_set_mgr_state(struct msm_dp *dp_display, bool state); void msm_dp_mst_display_hpd_irq(struct msm_dp *dp_display); #endif /* _DP_MST_DRM_H_ */ -- 2.43.0
