Loading msm/dp/dp_debug.h +27 −7 Original line number Diff line number Diff line Loading @@ -13,13 +13,33 @@ #include "dp_aux.h" #include "dp_display.h" #define DP_WARN(fmt, ...) DRM_WARN("[msm-dp-warn] "fmt, ##__VA_ARGS__) #define DP_ERR(fmt, ...) DRM_DEV_ERROR(NULL, "[msm-dp-error]" fmt, \ ##__VA_ARGS__) #define DP_INFO(fmt, ...) DRM_DEV_INFO(NULL, "[msm-dp-info] "fmt, \ ##__VA_ARGS__) #define DP_DEBUG(fmt, ...) DRM_DEV_DEBUG_DP(NULL, "[msm-dp-debug] "fmt, \ ##__VA_ARGS__) #define DP_DEBUG(fmt, ...) \ do { \ if (unlikely(drm_debug & DRM_UT_KMS)) \ DRM_DEBUG("[msm-dp-debug][%-4d]"fmt, current->pid, \ ##__VA_ARGS__); \ else \ pr_debug("[drm:%s][msm-dp-debug][%-4d]"fmt, __func__,\ current->pid, ##__VA_ARGS__); \ } while (0) #define DP_INFO(fmt, ...) \ do { \ if (unlikely(drm_debug & DRM_UT_KMS)) \ DRM_INFO("[msm-dp-info][%-4d]"fmt, current->pid, \ ##__VA_ARGS__); \ else \ pr_info("[drm:%s][msm-dp-info][%-4d]"fmt, __func__, \ current->pid, ##__VA_ARGS__); \ } while (0) #define DP_WARN(fmt, ...) \ pr_warn("[drm:%s][msm-dp-warn][%-4d]"fmt, __func__, \ current->pid, ##__VA_ARGS__) #define DP_ERR(fmt, ...) \ pr_err("[drm:%s][msm-dp-err][%-4d]"fmt, __func__, \ current->pid, ##__VA_ARGS__) /** * struct dp_debug Loading msm/dp/dp_display.c +127 −12 Original line number Diff line number Diff line Loading @@ -690,6 +690,24 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp) bool hpd = !!dp_display_state_is(DP_STATE_CONNECTED); SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state, hpd); /* * Send the notification only if there is any change. This check is * necessary since it is possible that the connect_work may or may not * skip sending the notification in order to respond to a pending * attention message. Attention work thread will always attempt to * send the notification after successfully handling the attention * message. This check here will avoid any unintended duplicate * notifications. */ if (dp_display_state_is(DP_STATE_CONNECT_NOTIFIED) && hpd) { DP_DEBUG("connection notified already, skip notification\n"); goto skip_wait; } else if (dp_display_state_is(DP_STATE_DISCONNECT_NOTIFIED) && !hpd) { DP_DEBUG("disonnect notified already, skip notification\n"); goto skip_wait; } dp->aux->state |= DP_STATE_NOTIFICATION_SENT; if (!dp->mst.mst_active) Loading Loading @@ -823,6 +841,25 @@ static void dp_display_host_ready(struct dp_display_private *dp) return; } /* * Reset the aborted state for AUX and CTRL modules. This will * allow these modules to execute normally in response to the * cable connection event. * * One corner case still exists. While the execution flow ensures * that cable disconnection flushes all pending work items on the DP * workqueue, and waits for the user module to clean up the DP * connection session, it is possible that the system delays can * lead to timeouts in the connect path. As a result, the actual * connection callback from user modules can come in late and can * race against a subsequent connection event here which would have * reset the aborted flags. There is no clear solution for this since * the connect/disconnect notifications do not currently have any * sessions IDs. */ dp->aux->abort(dp->aux, false); dp->ctrl->abort(dp->ctrl, false); dp->aux->init(dp->aux, dp->parser->aux_cfg); dp->panel->init(dp->panel); Loading Loading @@ -891,7 +928,6 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) dp->dp_display.max_pclk_khz = min(dp->parser->max_pclk_khz, dp->debug->max_pclk_khz); dp_display_host_init(dp); dp_display_host_ready(dp); dp->link->psm_config(dp->link, &dp->panel->link_info, false); Loading Loading @@ -929,9 +965,36 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) end: mutex_unlock(&dp->session_lock); /* * Delay the HPD connect notification to see if sink generates any * IRQ HPDs immediately after the HPD high. */ usleep_range(10000, 10100); /* * If an IRQ HPD is pending, then do not send a connect notification. * Once this work returns, the IRQ HPD would be processed and any * required actions (such as link maintenance) would be done which * will subsequently send the HPD notification. To keep things simple, * do this only for SST use-cases. MST use cases require additional * care in order to handle the side-band communications as well. * * One of the main motivations for this is DP LL 1.4 CTS use case * where it is possible that we could get a test request right after * a connection, and the strict timing requriements of the test can * only be met if we do not wait for the e2e connection to be set up. */ if (!dp->mst.mst_active && (work_busy(&dp->attention_work) == WORK_BUSY_PENDING)) { SDE_EVT32_EXTERNAL(dp->state, 99); DP_DEBUG("Attention pending, skip HPD notification\n"); goto skip_notify; } if (!rc && !dp_display_state_is(DP_STATE_ABORTED)) dp_display_send_hpd_notification(dp); skip_notify: SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state, rc); return rc; } Loading Loading @@ -1121,7 +1184,6 @@ static int dp_display_handle_disconnect(struct dp_display_private *dp) dp_display_clean(dp); dp_display_host_unready(dp); dp_display_host_deinit(dp); mutex_unlock(&dp->session_lock); Loading Loading @@ -1172,6 +1234,10 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev) dp_display_disconnect_sync(dp); mutex_lock(&dp->session_lock); dp_display_host_deinit(dp); mutex_unlock(&dp->session_lock); if (!dp->debug->sim_mode && !dp->parser->no_aux_switch && !dp->parser->gpio_aux_switch) dp->aux->aux_switch(dp->aux, false, ORIENTATION_NONE); Loading Loading @@ -1246,6 +1312,10 @@ static void dp_display_attention_work(struct work_struct *work) if (dp_display_is_sink_count_zero(dp)) { dp_display_handle_disconnect(dp); } else { /* * connect work should take care of sending * the HPD notification. */ if (!dp->mst.mst_active) queue_work(dp->wq, &dp->connect_work); } Loading @@ -1258,6 +1328,10 @@ static void dp_display_attention_work(struct work_struct *work) dp_display_handle_disconnect(dp); dp->panel->video_test = true; /* * connect work should take care of sending * the HPD notification. */ queue_work(dp->wq, &dp->connect_work); goto mst_attention; Loading @@ -1268,7 +1342,6 @@ static void dp_display_attention_work(struct work_struct *work) mutex_lock(&dp->session_lock); dp_audio_enable(dp, false); mutex_unlock(&dp->session_lock); if (dp->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) { SDE_EVT32_EXTERNAL(dp->state, Loading @@ -1287,13 +1360,22 @@ static void dp_display_attention_work(struct work_struct *work) dp->ctrl->link_maintenance(dp->ctrl); } mutex_lock(&dp->session_lock); dp_audio_enable(dp, true); mutex_unlock(&dp->session_lock); if (dp->link->sink_request & (DP_TEST_LINK_PHY_TEST_PATTERN | DP_TEST_LINK_TRAINING)) DP_TEST_LINK_TRAINING)) { goto mst_attention; } else { /* * It is possible that the connect_work skipped sending * the HPD notification if the attention message was * already pending. Send the notification here to * account for that. This is not needed if this * attention work was handling a test request */ dp_display_send_hpd_notification(dp); } } cp_irq: Loading Loading @@ -1698,8 +1780,22 @@ static int dp_display_prepare(struct dp_display *dp_display, void *panel) SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state); mutex_lock(&dp->session_lock); if (dp_display_state_is(DP_STATE_ABORTED | DP_STATE_ENABLED)) { dp_display_state_show("[not initialized]"); /* * If the physical connection to the sink is already lost by the time * we try to set up the connection, we can just skip all the steps * here safely. */ if (dp_display_state_is(DP_STATE_ABORTED)) { dp_display_state_log("[aborted]"); goto end; } /* * If DP_STATE_ENABLED, there is nothing left to do. * However, this should not happen ideally. So, log this. */ if (dp_display_state_is(DP_STATE_ENABLED)) { dp_display_state_show("[already enabled]"); goto end; } Loading Loading @@ -1820,15 +1916,25 @@ static int dp_display_enable(struct dp_display *dp_display, void *panel) SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state); mutex_lock(&dp->session_lock); /* * If DP_STATE_READY is not set, we should not do any HW * programming. */ if (!dp_display_state_is(DP_STATE_READY)) { dp_display_state_show("[host not ready]"); goto end; } if (dp_display_state_is(DP_STATE_ABORTED)) { dp_display_state_show("[aborted]"); goto end; } /* * It is possible that by the time we get call back to establish * the DP pipeline e2e, the physical DP connection to the sink is * already lost. In such cases, the DP_STATE_ABORTED would be set. * However, it is necessary to NOT abort the display setup here so as * to ensure that the rest of the system is in a stable state prior to * handling the disconnect notification. */ if (dp_display_state_is(DP_STATE_ABORTED)) dp_display_state_log("[aborted, but continue on]"); rc = dp_display_stream_enable(dp, panel); if (rc) Loading Loading @@ -1865,13 +1971,22 @@ static int dp_display_post_enable(struct dp_display *dp_display, void *panel) SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state); mutex_lock(&dp->session_lock); /* * If DP_STATE_READY is not set, we should not do any HW * programming. */ if (!dp_display_state_is(DP_STATE_ENABLED)) { dp_display_state_show("[not enabled]"); goto end; } /* * If the physical connection to the sink is already lost by the time * we try to set up the connection, we can just skip all the steps * here safely. */ if (dp_display_state_is(DP_STATE_ABORTED)) { dp_display_state_show("[aborted]"); dp_display_state_log("[aborted]"); goto end; } Loading Loading
msm/dp/dp_debug.h +27 −7 Original line number Diff line number Diff line Loading @@ -13,13 +13,33 @@ #include "dp_aux.h" #include "dp_display.h" #define DP_WARN(fmt, ...) DRM_WARN("[msm-dp-warn] "fmt, ##__VA_ARGS__) #define DP_ERR(fmt, ...) DRM_DEV_ERROR(NULL, "[msm-dp-error]" fmt, \ ##__VA_ARGS__) #define DP_INFO(fmt, ...) DRM_DEV_INFO(NULL, "[msm-dp-info] "fmt, \ ##__VA_ARGS__) #define DP_DEBUG(fmt, ...) DRM_DEV_DEBUG_DP(NULL, "[msm-dp-debug] "fmt, \ ##__VA_ARGS__) #define DP_DEBUG(fmt, ...) \ do { \ if (unlikely(drm_debug & DRM_UT_KMS)) \ DRM_DEBUG("[msm-dp-debug][%-4d]"fmt, current->pid, \ ##__VA_ARGS__); \ else \ pr_debug("[drm:%s][msm-dp-debug][%-4d]"fmt, __func__,\ current->pid, ##__VA_ARGS__); \ } while (0) #define DP_INFO(fmt, ...) \ do { \ if (unlikely(drm_debug & DRM_UT_KMS)) \ DRM_INFO("[msm-dp-info][%-4d]"fmt, current->pid, \ ##__VA_ARGS__); \ else \ pr_info("[drm:%s][msm-dp-info][%-4d]"fmt, __func__, \ current->pid, ##__VA_ARGS__); \ } while (0) #define DP_WARN(fmt, ...) \ pr_warn("[drm:%s][msm-dp-warn][%-4d]"fmt, __func__, \ current->pid, ##__VA_ARGS__) #define DP_ERR(fmt, ...) \ pr_err("[drm:%s][msm-dp-err][%-4d]"fmt, __func__, \ current->pid, ##__VA_ARGS__) /** * struct dp_debug Loading
msm/dp/dp_display.c +127 −12 Original line number Diff line number Diff line Loading @@ -690,6 +690,24 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp) bool hpd = !!dp_display_state_is(DP_STATE_CONNECTED); SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state, hpd); /* * Send the notification only if there is any change. This check is * necessary since it is possible that the connect_work may or may not * skip sending the notification in order to respond to a pending * attention message. Attention work thread will always attempt to * send the notification after successfully handling the attention * message. This check here will avoid any unintended duplicate * notifications. */ if (dp_display_state_is(DP_STATE_CONNECT_NOTIFIED) && hpd) { DP_DEBUG("connection notified already, skip notification\n"); goto skip_wait; } else if (dp_display_state_is(DP_STATE_DISCONNECT_NOTIFIED) && !hpd) { DP_DEBUG("disonnect notified already, skip notification\n"); goto skip_wait; } dp->aux->state |= DP_STATE_NOTIFICATION_SENT; if (!dp->mst.mst_active) Loading Loading @@ -823,6 +841,25 @@ static void dp_display_host_ready(struct dp_display_private *dp) return; } /* * Reset the aborted state for AUX and CTRL modules. This will * allow these modules to execute normally in response to the * cable connection event. * * One corner case still exists. While the execution flow ensures * that cable disconnection flushes all pending work items on the DP * workqueue, and waits for the user module to clean up the DP * connection session, it is possible that the system delays can * lead to timeouts in the connect path. As a result, the actual * connection callback from user modules can come in late and can * race against a subsequent connection event here which would have * reset the aborted flags. There is no clear solution for this since * the connect/disconnect notifications do not currently have any * sessions IDs. */ dp->aux->abort(dp->aux, false); dp->ctrl->abort(dp->ctrl, false); dp->aux->init(dp->aux, dp->parser->aux_cfg); dp->panel->init(dp->panel); Loading Loading @@ -891,7 +928,6 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) dp->dp_display.max_pclk_khz = min(dp->parser->max_pclk_khz, dp->debug->max_pclk_khz); dp_display_host_init(dp); dp_display_host_ready(dp); dp->link->psm_config(dp->link, &dp->panel->link_info, false); Loading Loading @@ -929,9 +965,36 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) end: mutex_unlock(&dp->session_lock); /* * Delay the HPD connect notification to see if sink generates any * IRQ HPDs immediately after the HPD high. */ usleep_range(10000, 10100); /* * If an IRQ HPD is pending, then do not send a connect notification. * Once this work returns, the IRQ HPD would be processed and any * required actions (such as link maintenance) would be done which * will subsequently send the HPD notification. To keep things simple, * do this only for SST use-cases. MST use cases require additional * care in order to handle the side-band communications as well. * * One of the main motivations for this is DP LL 1.4 CTS use case * where it is possible that we could get a test request right after * a connection, and the strict timing requriements of the test can * only be met if we do not wait for the e2e connection to be set up. */ if (!dp->mst.mst_active && (work_busy(&dp->attention_work) == WORK_BUSY_PENDING)) { SDE_EVT32_EXTERNAL(dp->state, 99); DP_DEBUG("Attention pending, skip HPD notification\n"); goto skip_notify; } if (!rc && !dp_display_state_is(DP_STATE_ABORTED)) dp_display_send_hpd_notification(dp); skip_notify: SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state, rc); return rc; } Loading Loading @@ -1121,7 +1184,6 @@ static int dp_display_handle_disconnect(struct dp_display_private *dp) dp_display_clean(dp); dp_display_host_unready(dp); dp_display_host_deinit(dp); mutex_unlock(&dp->session_lock); Loading Loading @@ -1172,6 +1234,10 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev) dp_display_disconnect_sync(dp); mutex_lock(&dp->session_lock); dp_display_host_deinit(dp); mutex_unlock(&dp->session_lock); if (!dp->debug->sim_mode && !dp->parser->no_aux_switch && !dp->parser->gpio_aux_switch) dp->aux->aux_switch(dp->aux, false, ORIENTATION_NONE); Loading Loading @@ -1246,6 +1312,10 @@ static void dp_display_attention_work(struct work_struct *work) if (dp_display_is_sink_count_zero(dp)) { dp_display_handle_disconnect(dp); } else { /* * connect work should take care of sending * the HPD notification. */ if (!dp->mst.mst_active) queue_work(dp->wq, &dp->connect_work); } Loading @@ -1258,6 +1328,10 @@ static void dp_display_attention_work(struct work_struct *work) dp_display_handle_disconnect(dp); dp->panel->video_test = true; /* * connect work should take care of sending * the HPD notification. */ queue_work(dp->wq, &dp->connect_work); goto mst_attention; Loading @@ -1268,7 +1342,6 @@ static void dp_display_attention_work(struct work_struct *work) mutex_lock(&dp->session_lock); dp_audio_enable(dp, false); mutex_unlock(&dp->session_lock); if (dp->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) { SDE_EVT32_EXTERNAL(dp->state, Loading @@ -1287,13 +1360,22 @@ static void dp_display_attention_work(struct work_struct *work) dp->ctrl->link_maintenance(dp->ctrl); } mutex_lock(&dp->session_lock); dp_audio_enable(dp, true); mutex_unlock(&dp->session_lock); if (dp->link->sink_request & (DP_TEST_LINK_PHY_TEST_PATTERN | DP_TEST_LINK_TRAINING)) DP_TEST_LINK_TRAINING)) { goto mst_attention; } else { /* * It is possible that the connect_work skipped sending * the HPD notification if the attention message was * already pending. Send the notification here to * account for that. This is not needed if this * attention work was handling a test request */ dp_display_send_hpd_notification(dp); } } cp_irq: Loading Loading @@ -1698,8 +1780,22 @@ static int dp_display_prepare(struct dp_display *dp_display, void *panel) SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state); mutex_lock(&dp->session_lock); if (dp_display_state_is(DP_STATE_ABORTED | DP_STATE_ENABLED)) { dp_display_state_show("[not initialized]"); /* * If the physical connection to the sink is already lost by the time * we try to set up the connection, we can just skip all the steps * here safely. */ if (dp_display_state_is(DP_STATE_ABORTED)) { dp_display_state_log("[aborted]"); goto end; } /* * If DP_STATE_ENABLED, there is nothing left to do. * However, this should not happen ideally. So, log this. */ if (dp_display_state_is(DP_STATE_ENABLED)) { dp_display_state_show("[already enabled]"); goto end; } Loading Loading @@ -1820,15 +1916,25 @@ static int dp_display_enable(struct dp_display *dp_display, void *panel) SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state); mutex_lock(&dp->session_lock); /* * If DP_STATE_READY is not set, we should not do any HW * programming. */ if (!dp_display_state_is(DP_STATE_READY)) { dp_display_state_show("[host not ready]"); goto end; } if (dp_display_state_is(DP_STATE_ABORTED)) { dp_display_state_show("[aborted]"); goto end; } /* * It is possible that by the time we get call back to establish * the DP pipeline e2e, the physical DP connection to the sink is * already lost. In such cases, the DP_STATE_ABORTED would be set. * However, it is necessary to NOT abort the display setup here so as * to ensure that the rest of the system is in a stable state prior to * handling the disconnect notification. */ if (dp_display_state_is(DP_STATE_ABORTED)) dp_display_state_log("[aborted, but continue on]"); rc = dp_display_stream_enable(dp, panel); if (rc) Loading Loading @@ -1865,13 +1971,22 @@ static int dp_display_post_enable(struct dp_display *dp_display, void *panel) SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state); mutex_lock(&dp->session_lock); /* * If DP_STATE_READY is not set, we should not do any HW * programming. */ if (!dp_display_state_is(DP_STATE_ENABLED)) { dp_display_state_show("[not enabled]"); goto end; } /* * If the physical connection to the sink is already lost by the time * we try to set up the connection, we can just skip all the steps * here safely. */ if (dp_display_state_is(DP_STATE_ABORTED)) { dp_display_state_show("[aborted]"); dp_display_state_log("[aborted]"); goto end; } Loading