浏览代码

disp: msm: dp: Prevent disconnect from stopping HDCP

If a DP stream is disconnected when HDCP is not fully authenticated,
authentication may not continue for remaining streams. This occurs
due to the worker thread rescheduling itself on auth fail while
disconnect cancels any pending work.

Update disconnect logic to wait for HDCP authentication to complete
before stream de-registration, and reschedule the HDCP worker if HDCP
did not fully authenticate prior to disconnect.

Change-Id: I0f8934e4f34e4f5a8015587e852131795a3dad21
Signed-off-by: Christopher Braga <[email protected]>
Christopher Braga 6 年之前
父节点
当前提交
9b4453096a
共有 1 个文件被更改,包括 27 次插入8 次删除
  1. 27 8
      msm/dp/dp_display.c

+ 27 - 8
msm/dp/dp_display.c

@@ -99,6 +99,7 @@ struct dp_display_private {
 	struct mutex session_lock;
 	struct mutex session_lock;
 	bool suspended;
 	bool suspended;
 	bool hdcp_delayed_off;
 	bool hdcp_delayed_off;
+	bool hdcp_abort;
 
 
 	u32 active_stream_cnt;
 	u32 active_stream_cnt;
 	struct dp_mst mst;
 	struct dp_mst mst;
@@ -306,7 +307,8 @@ static void dp_display_hdcp_cb_work(struct work_struct *work)
 
 
 	dp = container_of(dw, struct dp_display_private, hdcp_cb_work);
 	dp = container_of(dw, struct dp_display_private, hdcp_cb_work);
 
 
-	if (!dp->power_on || !dp->is_connected || atomic_read(&dp->aborted))
+	if (!dp->power_on || !dp->is_connected || atomic_read(&dp->aborted) ||
+			dp->hdcp_abort)
 		return;
 		return;
 
 
 	if (dp->suspended) {
 	if (dp->suspended) {
@@ -1660,13 +1662,16 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel)
 		goto end;
 		goto end;
 	}
 	}
 
 
+	dp->hdcp_abort = true;
+	cancel_delayed_work_sync(&dp->hdcp_cb_work);
 	if (dp_display_is_hdcp_enabled(dp) &&
 	if (dp_display_is_hdcp_enabled(dp) &&
 			status->hdcp_state != HDCP_STATE_INACTIVE) {
 			status->hdcp_state != HDCP_STATE_INACTIVE) {
+		bool off = true;
 
 
 		if (dp->suspended) {
 		if (dp->suspended) {
 			pr_debug("Can't perform HDCP cleanup while suspended. Defer\n");
 			pr_debug("Can't perform HDCP cleanup while suspended. Defer\n");
 			dp->hdcp_delayed_off = true;
 			dp->hdcp_delayed_off = true;
-			goto stream;
+			goto clean;
 		}
 		}
 
 
 		flush_delayed_work(&dp->hdcp_cb_work);
 		flush_delayed_work(&dp->hdcp_cb_work);
@@ -1677,18 +1682,19 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel)
 				if (i != dp_panel->stream_id &&
 				if (i != dp_panel->stream_id &&
 						dp->active_panels[i]) {
 						dp->active_panels[i]) {
 					pr_debug("Streams are still active. Skip disabling HDCP\n");
 					pr_debug("Streams are still active. Skip disabling HDCP\n");
-					goto stream;
+					off = false;
 				}
 				}
 			}
 			}
 		}
 		}
 
 
-		if (dp->hdcp.ops->off)
-			dp->hdcp.ops->off(dp->hdcp.data);
-
-		dp_display_update_hdcp_status(dp, true);
+		if (off) {
+			if (dp->hdcp.ops->off)
+				dp->hdcp.ops->off(dp->hdcp.data);
+			dp_display_update_hdcp_status(dp, true);
+		}
 	}
 	}
 
 
-stream:
+clean:
 	if (dp_panel->audio_supported)
 	if (dp_panel->audio_supported)
 		dp_panel->audio->off(dp_panel->audio);
 		dp_panel->audio->off(dp_panel->audio);
 
 
@@ -1701,8 +1707,10 @@ end:
 
 
 static int dp_display_disable(struct dp_display *dp_display, void *panel)
 static int dp_display_disable(struct dp_display *dp_display, void *panel)
 {
 {
+	int i;
 	struct dp_display_private *dp = NULL;
 	struct dp_display_private *dp = NULL;
 	struct dp_panel *dp_panel = NULL;
 	struct dp_panel *dp_panel = NULL;
+	struct dp_link_hdcp_status *status;
 
 
 	if (!dp_display || !panel) {
 	if (!dp_display || !panel) {
 		pr_err("invalid input\n");
 		pr_err("invalid input\n");
@@ -1711,6 +1719,7 @@ static int dp_display_disable(struct dp_display *dp_display, void *panel)
 
 
 	dp = container_of(dp_display, struct dp_display_private, dp_display);
 	dp = container_of(dp_display, struct dp_display_private, dp_display);
 	dp_panel = panel;
 	dp_panel = panel;
+	status = &dp->link->hdcp_status;
 
 
 	mutex_lock(&dp->session_lock);
 	mutex_lock(&dp->session_lock);
 
 
@@ -1721,6 +1730,16 @@ static int dp_display_disable(struct dp_display *dp_display, void *panel)
 
 
 	dp_display_stream_disable(dp, dp_panel);
 	dp_display_stream_disable(dp, dp_panel);
 	dp_display_update_dsc_resources(dp, dp_panel, false);
 	dp_display_update_dsc_resources(dp, dp_panel, false);
+
+	dp->hdcp_abort = false;
+	for (i = DP_STREAM_0; i < DP_STREAM_MAX; i++) {
+		if (dp->active_panels[i]) {
+			if (status->hdcp_state != HDCP_STATE_AUTHENTICATED)
+				queue_delayed_work(dp->wq, &dp->hdcp_cb_work,
+						HZ/4);
+			break;
+		}
+	}
 end:
 end:
 	mutex_unlock(&dp->session_lock);
 	mutex_unlock(&dp->session_lock);
 	return 0;
 	return 0;