diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index 8ac7f46c..5b9b3921 100644 --- a/msm/dp/dp_display.c +++ b/msm/dp/dp_display.c @@ -97,6 +97,8 @@ struct dp_display_private { struct work_struct connect_work; struct work_struct attention_work; struct mutex session_lock; + bool suspended; + bool hdcp_delayed_off; u32 active_stream_cnt; struct dp_mst mst; @@ -307,6 +309,19 @@ static void dp_display_hdcp_cb_work(struct work_struct *work) if (!dp->power_on || !dp->is_connected || atomic_read(&dp->aborted)) return; + if (dp->suspended) { + pr_debug("System suspending. Delay HDCP operations\n"); + queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ); + return; + } + + if (dp->hdcp_delayed_off) { + if (dp->hdcp.ops && dp->hdcp.ops->off) + dp->hdcp.ops->off(dp->hdcp.data); + dp_display_update_hdcp_status(dp, true); + dp->hdcp_delayed_off = false; + } + drm_dp_dpcd_readb(dp->aux->drm_aux, DP_SINK_STATUS, &sink_status); sink_status &= (DP_RECEIVE_PORT_0_STATUS | DP_RECEIVE_PORT_1_STATUS); if (sink_status < 1) { @@ -890,9 +905,7 @@ static void dp_display_clean(struct dp_display_private *dp) dp->power_on = false; - mutex_lock(&dp->session_lock); dp->ctrl->off(dp->ctrl); - mutex_unlock(&dp->session_lock); } static int dp_display_handle_disconnect(struct dp_display_private *dp) @@ -1649,6 +1662,13 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel) if (dp_display_is_hdcp_enabled(dp) && status->hdcp_state != HDCP_STATE_INACTIVE) { + + if (dp->suspended) { + pr_debug("Can't perform HDCP cleanup while suspended. Defer\n"); + dp->hdcp_delayed_off = true; + goto stream; + } + flush_delayed_work(&dp->hdcp_cb_work); if (dp->mst.mst_active) { dp_display_hdcp_deregister_stream(dp, @@ -2588,14 +2608,24 @@ static int dp_display_remove(struct platform_device *pdev) static int dp_pm_prepare(struct device *dev) { + struct dp_display_private *dp = container_of(g_dp_display, + struct dp_display_private, dp_display); + dp_display_set_mst_state(g_dp_display, PM_SUSPEND); + dp->suspended = true; + return 0; } static void dp_pm_complete(struct device *dev) { + struct dp_display_private *dp = container_of(g_dp_display, + struct dp_display_private, dp_display); + dp_display_set_mst_state(g_dp_display, PM_DEFAULT); + + dp->suspended = false; } static const struct dev_pm_ops dp_pm_ops = {