From cf4877c2c3585e1a11417e41237f8ee77fcb1791 Mon Sep 17 00:00:00 2001 From: Sudarsan Ramesh Date: Tue, 20 Oct 2020 16:01:00 -0400 Subject: [PATCH] disp: msm: dp: cache edid data for mst Currently, in SST mode, sink edid is read once after hpd and reused on subsequent mode enumeration calls. But in MST mode, there is no caching and the driver re-reads the edid from the sink on every get_modes call for each monitor. Each read takes more than 500ms causing unnecessary delays during MST enumeration. This change reads the edid once per hpd and uses the cached data on subsequent calls. Change-Id: I27545a44b9f9bd40000dde60735815f9c47fa54c Signed-off-by: Sudarsan Ramesh --- msm/dp/dp_mst_drm.c | 73 ++++++++++++++++++++++++++++++++++++----- msm/sde/sde_connector.h | 3 ++ 2 files changed, 67 insertions(+), 9 deletions(-) diff --git a/msm/dp/dp_mst_drm.c b/msm/dp/dp_mst_drm.c index dd212114964a..13c660146dfb 100644 --- a/msm/dp/dp_mst_drm.c +++ b/msm/dp/dp_mst_drm.c @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include "msm_drv.h" #include "msm_kms.h" @@ -151,6 +153,7 @@ struct dp_mst_private { const struct dp_drm_mst_fw_helper_ops *mst_fw_cbs; struct dp_mst_sim_mode simulator; struct mutex mst_lock; + struct mutex edid_lock; enum dp_drv_state state; bool mst_session_state; }; @@ -1379,23 +1382,50 @@ static int dp_mst_connector_get_modes(struct drm_connector *connector, struct sde_connector *c_conn = to_sde_connector(connector); struct dp_display *dp_display = display; struct dp_mst_private *mst = dp_display->dp_mst_prv_info; - struct edid *edid; int rc = 0; + struct edid *edid = NULL; DP_MST_DEBUG("enter:\n"); SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, connector->base.id); - edid = mst->mst_fw_cbs->get_edid(connector, &mst->mst_mgr, - c_conn->mst_port); + mutex_lock(&mst->edid_lock); - if (edid) - rc = dp_display->mst_connector_update_edid(dp_display, - connector, edid); + if (c_conn->cached_edid) + goto duplicate_edid; - DP_MST_DEBUG("mst connector get modes. id: %d\n", connector->base.id); + mutex_unlock(&mst->edid_lock); - DP_MST_DEBUG("exit:\n"); - SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, connector->base.id); + edid = mst->mst_fw_cbs->get_edid(connector, + &mst->mst_mgr, c_conn->mst_port); + + if (!edid) { + DP_MST_DEBUG("get edid failed. id: %d\n", + connector->base.id); + goto end; + } + + mutex_lock(&mst->edid_lock); + c_conn->cached_edid = edid; + +duplicate_edid: + + edid = drm_edid_duplicate(c_conn->cached_edid); + + mutex_unlock(&mst->edid_lock); + + if (IS_ERR(edid)) { + rc = PTR_ERR(edid); + DP_MST_DEBUG("edid duplication failed. id: %d\n", + connector->base.id); + goto end; + } + + rc = dp_display->mst_connector_update_edid(dp_display, + connector, edid); + +end: + DP_MST_DEBUG("exit: id: %d rc: %d\n", connector->base.id, rc); + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, connector->base.id, rc); return rc; } @@ -1728,6 +1758,9 @@ static void dp_mst_connector_pre_destroy(struct drm_connector *connector, DP_MST_DEBUG("enter:\n"); SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, conn_id); + kfree(c_conn->cached_edid); + c_conn->cached_edid = NULL; + drm_dp_mst_put_port_malloc(c_conn->mst_port); dp_display->mst_connector_uninstall(dp_display, connector); @@ -2227,6 +2260,9 @@ static void dp_mst_display_hpd_irq(void *dp_display, u8 esi[14]; unsigned int esi_res = DP_SINK_COUNT_ESI + 1; bool handled; + struct drm_connector_list_iter conn_iter; + struct drm_connector *conn; + struct sde_connector *c_conn; if (info->mst_hpd_sim) { if (mst->simulator.mst_state && (info->mst_sim_add_con || @@ -2269,6 +2305,22 @@ static void dp_mst_display_hpd_irq(void *dp_display, if (handled) { rc = drm_dp_dpcd_write(mst->caps.drm_aux, esi_res, &esi[1], 3); + if (esi[1] & DP_UP_REQ_MSG_RDY) { + drm_connector_list_iter_begin(dp->drm_dev, &conn_iter); + drm_for_each_connector_iter(conn, &conn_iter) { + + c_conn = to_sde_connector(conn); + if (!c_conn->mst_port) + continue; + + mutex_lock(&mst->edid_lock); + kfree(c_conn->cached_edid); + c_conn->cached_edid = NULL; + mutex_unlock(&mst->edid_lock); + } + drm_connector_list_iter_end(&conn_iter); + } + if (rc != 3) DP_ERR("dpcd esi_res failed. rlen=%d\n", rc); } @@ -2354,6 +2406,7 @@ int dp_mst_init(struct dp_display *dp_display) dp_mst.dp_display = dp_display; mutex_init(&dp_mst.mst_lock); + mutex_init(&dp_mst.edid_lock); ret = drm_dp_mst_topology_mgr_init(&dp_mst.mst_mgr, dev, dp_mst.caps.drm_aux, @@ -2386,6 +2439,7 @@ int dp_mst_init(struct dp_display *dp_display) error: mutex_destroy(&dp_mst.mst_lock); + mutex_destroy(&dp_mst.edid_lock); return ret; } @@ -2410,6 +2464,7 @@ void dp_mst_deinit(struct dp_display *dp_display) dp_mst.mst_initialized = false; mutex_destroy(&mst->mst_lock); + mutex_destroy(&mst->edid_lock); DP_MST_INFO("dp drm mst topology manager deinit completed\n"); } diff --git a/msm/sde/sde_connector.h b/msm/sde/sde_connector.h index 109906599822..aad04d29f2f4 100644 --- a/msm/sde/sde_connector.h +++ b/msm/sde/sde_connector.h @@ -481,6 +481,7 @@ struct sde_connector_dyn_hdr_metadata { * @hdr_capable: external hdr support present * @cmd_rx_buf: the return buffer of response of command transfer * @rx_len: the length of dcs command received buffer + * @cached_edid: cached edid data for the connector */ struct sde_connector { struct drm_connector base; @@ -550,6 +551,8 @@ struct sde_connector { u8 cmd_rx_buf[MAX_CMD_RECEIVE_SIZE]; int rx_len; + + struct edid *cached_edid; }; /**