diff --git a/msm/dp/dp_audio.c b/msm/dp/dp_audio.c index 680f6d6747..cd665aa44e 100644 --- a/msm/dp/dp_audio.c +++ b/msm/dp/dp_audio.c @@ -1,5 +1,6 @@ // 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. */ @@ -769,7 +770,7 @@ end: 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; struct dp_audio_private *audio; @@ -794,9 +795,11 @@ static int dp_audio_off(struct dp_audio *dp_audio) if (work_pending) 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"); end: diff --git a/msm/dp/dp_audio.h b/msm/dp/dp_audio.h index 19e207e0e5..f81f0079e4 100644 --- a/msm/dp/dp_audio.h +++ b/msm/dp/dp_audio.h @@ -1,5 +1,6 @@ /* 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. */ @@ -41,10 +42,11 @@ struct dp_audio { * playback should be stopped on the external display. * * @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. */ - int (*off)(struct dp_audio *dp_audio); + int (*off)(struct dp_audio *dp_audio, bool skip_wait); }; /** diff --git a/msm/dp/dp_debug.c b/msm/dp/dp_debug.c index c5cfb46e52..2897d96ecd 100644 --- a/msm/dp/dp_debug.c +++ b/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); mutex_lock(&debug->lock); + // disconnect has already been handled. so clear hotplug + debug->hotplug = false; dp_debug_set_sim_mode(debug, false); mutex_unlock(&debug->lock); } diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index dad28ce86c..fe073d4bed 100644 --- a/msm/dp/dp_display.c +++ b/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_panel->audio->on(dp_panel->audio); } 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; } -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; 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; } - if (hpd && dp->mst.mst_active) + if (skip_wait || (hpd && dp->mst.mst_active)) goto skip_wait; if (!dp->mst.mst_active && (!!dp_display_state_is(DP_STATE_ENABLED) == hpd)) 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"); ret = -EINVAL; } @@ -1321,7 +1331,7 @@ end: } if (!rc && !dp_display_state_is(DP_STATE_ABORTED)) - dp_display_send_hpd_notification(dp); + dp_display_send_hpd_notification(dp, false); skip_notify: SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state, @@ -1329,7 +1339,7 @@ skip_notify: 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; @@ -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) || 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_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); } -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; @@ -1364,11 +1374,11 @@ static int dp_display_process_hpd_low(struct dp_display_private *dp) dp_audio_enable(dp, false); if (dp->mst.mst_active) { - dp_display_process_mst_hpd_low(dp); + dp_display_process_mst_hpd_low(dp, skip_wait); } else { if ((dp_display_state_is(DP_STATE_CONNECT_NOTIFIED) || 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); @@ -1551,7 +1561,7 @@ static void dp_display_stream_disable(struct dp_display_private *dp, 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; 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]; 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_clear_reservation(&dp->dp_display, dp_panel); 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); } -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; 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) { /* cancel any pending request */ 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); if (dp_display_state_is(DP_STATE_ENABLED)) - dp_display_clean(dp); + dp_display_clean(dp, skip_wait); 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); msleep(disconnect_delay_ms); - dp_display_handle_disconnect(dp); + dp_display_handle_disconnect(dp, false); SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state, 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); if (!dp->mst.mst_active) { if (dp_display_is_sink_count_zero(dp)) { - dp_display_handle_disconnect(dp); + dp_display_handle_disconnect(dp, false); } else { /* * 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) { 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; /* @@ -1838,7 +1849,7 @@ cp_irq: * account for that. This is not needed if this * attention work was handling a test request */ - dp_display_send_hpd_notification(dp); + dp_display_send_hpd_notification(dp, false); } 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); if (!action && dp->debug->sim_mode) { 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); } @@ -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 && dp_display_state_is(DP_STATE_ENABLED) && !dp_display_state_is(DP_STATE_ABORTED)) { - ret = dp_display_handle_disconnect(dp); + ret = dp_display_handle_disconnect(dp, false); if (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: 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);