Merge "disp: msm: dp: resend hpd notification to usermode"
This commit is contained in:

committed by
Gerrit - the friendly Code Review server

commit
df56ac358f
@@ -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 (!skip_wait) {
|
||||||
if (rc)
|
rc = dp_audio_notify(audio, EXT_DISPLAY_CABLE_DISCONNECT);
|
||||||
goto end;
|
if (rc)
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
DP_DEBUG("success\n");
|
DP_DEBUG("success\n");
|
||||||
end:
|
end:
|
||||||
|
@@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
@@ -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,
|
// wait 2 seconds
|
||||||
HZ * 5)) {
|
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);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user