Jelajahi Sumber

Merge "disp: msm: dp: cache edid data for mst"

qctecmdr 4 tahun lalu
induk
melakukan
746f5eb68a
2 mengubah file dengan 67 tambahan dan 9 penghapusan
  1. 64 9
      msm/dp/dp_mst_drm.c
  2. 3 0
      msm/sde/sde_connector.h

+ 64 - 9
msm/dp/dp_mst_drm.c

@@ -34,6 +34,8 @@
 #include <drm/drm_crtc.h>
 #include <drm/drm_dp_mst_helper.h>
 #include <drm/drm_fixed.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_dp_helper.h>
 
 #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");
 }

+ 3 - 0
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;
 };
 
 /**