浏览代码

Merge "disp: msm: dp: resend hpd notification to usermode"

qctecmdr 2 年之前
父节点
当前提交
df56ac358f
共有 4 个文件被更改,包括 50 次插入29 次删除
  1. 7 4
      msm/dp/dp_audio.c
  2. 3 1
      msm/dp/dp_audio.h
  3. 2 0
      msm/dp/dp_debug.c
  4. 38 24
      msm/dp/dp_display.c

+ 7 - 4
msm/dp/dp_audio.c

@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 // SPDX-License-Identifier: GPL-2.0-only
 /*
 /*
+ * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
  * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
  */
  */
 
 
@@ -769,7 +770,7 @@ end:
 	return rc;
 	return rc;
 }
 }
 
 
-static int dp_audio_off(struct dp_audio *dp_audio)
+static int dp_audio_off(struct dp_audio *dp_audio, bool skip_wait)
 {
 {
 	int rc = 0;
 	int rc = 0;
 	struct dp_audio_private *audio;
 	struct dp_audio_private *audio;
@@ -794,9 +795,11 @@ static int dp_audio_off(struct dp_audio *dp_audio)
 	if (work_pending)
 	if (work_pending)
 		DP_DEBUG("pending notification work completed\n");
 		DP_DEBUG("pending notification work completed\n");
 
 
-	rc = dp_audio_notify(audio, EXT_DISPLAY_CABLE_DISCONNECT);
-	if (rc)
-		goto end;
+	if (!skip_wait) {
+		rc = dp_audio_notify(audio, EXT_DISPLAY_CABLE_DISCONNECT);
+		if (rc)
+			goto end;
+	}
 
 
 	DP_DEBUG("success\n");
 	DP_DEBUG("success\n");
 end:
 end:

+ 3 - 1
msm/dp/dp_audio.h

@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
 /*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
  * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
  */
  */
 
 
@@ -41,10 +42,11 @@ struct dp_audio {
 	 * playback should be stopped on the external display.
 	 * playback should be stopped on the external display.
 	 *
 	 *
 	 * @dp_audio: an instance of struct dp_audio.
 	 * @dp_audio: an instance of struct dp_audio.
+	 * @skip_wait: flag to skip any waits
 	 *
 	 *
 	 * Returns the error code in case of failure, 0 in success case.
 	 * Returns the error code in case of failure, 0 in success case.
 	 */
 	 */
-	int (*off)(struct dp_audio *dp_audio);
+	int (*off)(struct dp_audio *dp_audio, bool skip_wait);
 };
 };
 
 
 /**
 /**

+ 2 - 0
msm/dp/dp_debug.c

@@ -2468,6 +2468,8 @@ static void dp_debug_abort(struct dp_debug *dp_debug)
 	debug = container_of(dp_debug, struct dp_debug_private, dp_debug);
 	debug = container_of(dp_debug, struct dp_debug_private, dp_debug);
 
 
 	mutex_lock(&debug->lock);
 	mutex_lock(&debug->lock);
+	// disconnect has already been handled. so clear hotplug
+	debug->hotplug = false;
 	dp_debug_set_sim_mode(debug, false);
 	dp_debug_set_sim_mode(debug, false);
 	mutex_unlock(&debug->lock);
 	mutex_unlock(&debug->lock);
 }
 }

+ 38 - 24
msm/dp/dp_display.c

@@ -293,7 +293,7 @@ static void dp_audio_enable(struct dp_display_private *dp, bool enable)
 					dp->link->link_params.lane_count;
 					dp->link->link_params.lane_count;
 				dp_panel->audio->on(dp_panel->audio);
 				dp_panel->audio->on(dp_panel->audio);
 			} else {
 			} else {
-				dp_panel->audio->off(dp_panel->audio);
+				dp_panel->audio->off(dp_panel->audio, false);
 			}
 			}
 		}
 		}
 	}
 	}
@@ -917,7 +917,7 @@ static bool dp_display_send_hpd_event(struct dp_display_private *dp)
 	return true;
 	return true;
 }
 }
 
 
-static int dp_display_send_hpd_notification(struct dp_display_private *dp)
+static int dp_display_send_hpd_notification(struct dp_display_private *dp, bool skip_wait)
 {
 {
 	int ret = 0;
 	int ret = 0;
 	bool hpd = !!dp_display_state_is(DP_STATE_CONNECTED);
 	bool hpd = !!dp_display_state_is(DP_STATE_CONNECTED);
@@ -976,15 +976,25 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp)
 		goto skip_wait;
 		goto skip_wait;
 	}
 	}
 
 
-	if (hpd && dp->mst.mst_active)
+	if (skip_wait || (hpd && dp->mst.mst_active))
 		goto skip_wait;
 		goto skip_wait;
 
 
 	if (!dp->mst.mst_active &&
 	if (!dp->mst.mst_active &&
 			(!!dp_display_state_is(DP_STATE_ENABLED) == hpd))
 			(!!dp_display_state_is(DP_STATE_ENABLED) == hpd))
 		goto skip_wait;
 		goto skip_wait;
 
 
-	if (!wait_for_completion_timeout(&dp->notification_comp,
-						HZ * 5)) {
+	// wait 2 seconds
+	if (wait_for_completion_timeout(&dp->notification_comp, HZ * 2))
+		goto skip_wait;
+
+	//resend notification
+	if (dp->mst.mst_active)
+		dp->mst.cbs.hpd(&dp->dp_display, hpd);
+	else
+		dp_display_send_hpd_event(dp);
+
+	// wait another 3 seconds
+	if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 3)) {
 		DP_WARN("%s timeout\n", hpd ? "connect" : "disconnect");
 		DP_WARN("%s timeout\n", hpd ? "connect" : "disconnect");
 		ret = -EINVAL;
 		ret = -EINVAL;
 	}
 	}
@@ -1321,7 +1331,7 @@ end:
 	}
 	}
 
 
 	if (!rc && !dp_display_state_is(DP_STATE_ABORTED))
 	if (!rc && !dp_display_state_is(DP_STATE_ABORTED))
-		dp_display_send_hpd_notification(dp);
+		dp_display_send_hpd_notification(dp, false);
 
 
 skip_notify:
 skip_notify:
 	SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state,
 	SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state,
@@ -1329,7 +1339,7 @@ skip_notify:
 	return rc;
 	return rc;
 }
 }
 
 
-static void dp_display_process_mst_hpd_low(struct dp_display_private *dp)
+static void dp_display_process_mst_hpd_low(struct dp_display_private *dp, bool skip_wait)
 {
 {
 	int rc = 0;
 	int rc = 0;
 
 
@@ -1346,7 +1356,7 @@ static void dp_display_process_mst_hpd_low(struct dp_display_private *dp)
 
 
 		if ((dp_display_state_is(DP_STATE_CONNECT_NOTIFIED) ||
 		if ((dp_display_state_is(DP_STATE_CONNECT_NOTIFIED) ||
 				dp_display_state_is(DP_STATE_ENABLED)))
 				dp_display_state_is(DP_STATE_ENABLED)))
-			rc = dp_display_send_hpd_notification(dp);
+			rc = dp_display_send_hpd_notification(dp, skip_wait);
 
 
 		dp_display_set_mst_mgr_state(dp, false);
 		dp_display_set_mst_mgr_state(dp, false);
 		dp_display_update_mst_state(dp, false);
 		dp_display_update_mst_state(dp, false);
@@ -1355,7 +1365,7 @@ static void dp_display_process_mst_hpd_low(struct dp_display_private *dp)
 	DP_MST_DEBUG("mst_hpd_low. mst_active:%d\n", dp->mst.mst_active);
 	DP_MST_DEBUG("mst_hpd_low. mst_active:%d\n", dp->mst.mst_active);
 }
 }
 
 
-static int dp_display_process_hpd_low(struct dp_display_private *dp)
+static int dp_display_process_hpd_low(struct dp_display_private *dp, bool skip_wait)
 {
 {
 	int rc = 0;
 	int rc = 0;
 
 
@@ -1364,11 +1374,11 @@ static int dp_display_process_hpd_low(struct dp_display_private *dp)
 	dp_audio_enable(dp, false);
 	dp_audio_enable(dp, false);
 
 
 	if (dp->mst.mst_active) {
 	if (dp->mst.mst_active) {
-		dp_display_process_mst_hpd_low(dp);
+		dp_display_process_mst_hpd_low(dp, skip_wait);
 	} else {
 	} else {
 		if ((dp_display_state_is(DP_STATE_CONNECT_NOTIFIED) ||
 		if ((dp_display_state_is(DP_STATE_CONNECT_NOTIFIED) ||
 				dp_display_state_is(DP_STATE_ENABLED)))
 				dp_display_state_is(DP_STATE_ENABLED)))
-			rc = dp_display_send_hpd_notification(dp);
+			rc = dp_display_send_hpd_notification(dp, skip_wait);
 	}
 	}
 
 
 	mutex_lock(&dp->session_lock);
 	mutex_lock(&dp->session_lock);
@@ -1551,7 +1561,7 @@ static void dp_display_stream_disable(struct dp_display_private *dp,
 	dp->active_stream_cnt--;
 	dp->active_stream_cnt--;
 }
 }
 
 
-static void dp_display_clean(struct dp_display_private *dp)
+static void dp_display_clean(struct dp_display_private *dp, bool skip_wait)
 {
 {
 	int idx;
 	int idx;
 	struct dp_panel *dp_panel;
 	struct dp_panel *dp_panel;
@@ -1579,9 +1589,10 @@ static void dp_display_clean(struct dp_display_private *dp)
 
 
 		dp_panel = dp->active_panels[idx];
 		dp_panel = dp->active_panels[idx];
 		if (dp_panel->audio_supported)
 		if (dp_panel->audio_supported)
-			dp_panel->audio->off(dp_panel->audio);
+			dp_panel->audio->off(dp_panel->audio, skip_wait);
 
 
-		dp_display_stream_pre_disable(dp, dp_panel);
+		if (!skip_wait)
+			dp_display_stream_pre_disable(dp, dp_panel);
 		dp_display_stream_disable(dp, dp_panel);
 		dp_display_stream_disable(dp, dp_panel);
 		dp_display_clear_reservation(&dp->dp_display, dp_panel);
 		dp_display_clear_reservation(&dp->dp_display, dp_panel);
 		dp_panel->deinit(dp_panel, 0);
 		dp_panel->deinit(dp_panel, 0);
@@ -1593,12 +1604,12 @@ static void dp_display_clean(struct dp_display_private *dp)
 	SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state);
 	SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state);
 }
 }
 
 
-static int dp_display_handle_disconnect(struct dp_display_private *dp)
+static int dp_display_handle_disconnect(struct dp_display_private *dp, bool skip_wait)
 {
 {
 	int rc;
 	int rc;
 
 
 	SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state);
 	SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state);
-	rc = dp_display_process_hpd_low(dp);
+	rc = dp_display_process_hpd_low(dp, skip_wait);
 	if (rc) {
 	if (rc) {
 		/* cancel any pending request */
 		/* cancel any pending request */
 		dp->ctrl->abort(dp->ctrl, true);
 		dp->ctrl->abort(dp->ctrl, true);
@@ -1607,7 +1618,7 @@ static int dp_display_handle_disconnect(struct dp_display_private *dp)
 
 
 	mutex_lock(&dp->session_lock);
 	mutex_lock(&dp->session_lock);
 	if (dp_display_state_is(DP_STATE_ENABLED))
 	if (dp_display_state_is(DP_STATE_ENABLED))
-		dp_display_clean(dp);
+		dp_display_clean(dp, skip_wait);
 
 
 	dp_display_host_unready(dp);
 	dp_display_host_unready(dp);
 
 
@@ -1648,7 +1659,7 @@ static void dp_display_disconnect_sync(struct dp_display_private *dp)
 	DP_DEBUG("disconnect delay = %d ms\n", disconnect_delay_ms);
 	DP_DEBUG("disconnect delay = %d ms\n", disconnect_delay_ms);
 	msleep(disconnect_delay_ms);
 	msleep(disconnect_delay_ms);
 
 
-	dp_display_handle_disconnect(dp);
+	dp_display_handle_disconnect(dp, false);
 	SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state,
 	SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state,
 		disconnect_delay_ms);
 		disconnect_delay_ms);
 }
 }
@@ -1764,7 +1775,7 @@ static void dp_display_attention_work(struct work_struct *work)
 		SDE_EVT32_EXTERNAL(dp->state, DS_PORT_STATUS_CHANGED);
 		SDE_EVT32_EXTERNAL(dp->state, DS_PORT_STATUS_CHANGED);
 		if (!dp->mst.mst_active) {
 		if (!dp->mst.mst_active) {
 			if (dp_display_is_sink_count_zero(dp)) {
 			if (dp_display_is_sink_count_zero(dp)) {
-				dp_display_handle_disconnect(dp);
+				dp_display_handle_disconnect(dp, false);
 			} else {
 			} else {
 				/*
 				/*
 				 * connect work should take care of sending
 				 * connect work should take care of sending
@@ -1779,7 +1790,7 @@ static void dp_display_attention_work(struct work_struct *work)
 
 
 	if (dp->link->sink_request & DP_TEST_LINK_VIDEO_PATTERN) {
 	if (dp->link->sink_request & DP_TEST_LINK_VIDEO_PATTERN) {
 		SDE_EVT32_EXTERNAL(dp->state, DP_TEST_LINK_VIDEO_PATTERN);
 		SDE_EVT32_EXTERNAL(dp->state, DP_TEST_LINK_VIDEO_PATTERN);
-		dp_display_handle_disconnect(dp);
+		dp_display_handle_disconnect(dp, false);
 
 
 		dp->panel->video_test = true;
 		dp->panel->video_test = true;
 		/*
 		/*
@@ -1838,7 +1849,7 @@ cp_irq:
 		 * account for that. This is not needed if this
 		 * account for that. This is not needed if this
 		 * attention work was handling a test request
 		 * attention work was handling a test request
 		 */
 		 */
-		dp_display_send_hpd_notification(dp);
+		dp_display_send_hpd_notification(dp, false);
 	}
 	}
 
 
 mst_attention:
 mst_attention:
@@ -1939,7 +1950,10 @@ static int dp_display_usb_notifier(struct notifier_block *nb,
 	SDE_EVT32_EXTERNAL(dp->state, dp->debug->sim_mode, action);
 	SDE_EVT32_EXTERNAL(dp->state, dp->debug->sim_mode, action);
 	if (!action && dp->debug->sim_mode) {
 	if (!action && dp->debug->sim_mode) {
 		DP_WARN("usb disconnected during simulation\n");
 		DP_WARN("usb disconnected during simulation\n");
-		dp_display_disconnect_sync(dp);
+		dp_display_state_add(DP_STATE_ABORTED);
+		dp->ctrl->abort(dp->ctrl, true);
+		dp->aux->abort(dp->aux, true);
+		dp_display_handle_disconnect(dp, true);
 		dp->debug->abort(dp->debug);
 		dp->debug->abort(dp->debug);
 	}
 	}
 
 
@@ -1978,7 +1992,7 @@ int dp_display_mmrm_callback(struct mmrm_client_notifier_data *notifier_data)
 	if (notifier_data->cb_type == MMRM_CLIENT_RESOURCE_VALUE_CHANGE
 	if (notifier_data->cb_type == MMRM_CLIENT_RESOURCE_VALUE_CHANGE
 				&& dp_display_state_is(DP_STATE_ENABLED)
 				&& dp_display_state_is(DP_STATE_ENABLED)
 				&& !dp_display_state_is(DP_STATE_ABORTED)) {
 				&& !dp_display_state_is(DP_STATE_ABORTED)) {
-		ret = dp_display_handle_disconnect(dp);
+		ret = dp_display_handle_disconnect(dp, false);
 		if (ret)
 		if (ret)
 			DP_ERR("mmrm callback error reducing clk, ret:%d\n", ret);
 			DP_ERR("mmrm callback error reducing clk, ret:%d\n", ret);
 	}
 	}
@@ -2650,7 +2664,7 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel)
 
 
 clean:
 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, false);
 
 
 	rc = dp_display_stream_pre_disable(dp, dp_panel);
 	rc = dp_display_stream_pre_disable(dp, dp_panel);