|
@@ -97,6 +97,8 @@ struct dp_display_private {
|
|
struct work_struct connect_work;
|
|
struct work_struct connect_work;
|
|
struct work_struct attention_work;
|
|
struct work_struct attention_work;
|
|
struct mutex session_lock;
|
|
struct mutex session_lock;
|
|
|
|
+ bool suspended;
|
|
|
|
+ bool hdcp_delayed_off;
|
|
|
|
|
|
u32 active_stream_cnt;
|
|
u32 active_stream_cnt;
|
|
struct dp_mst mst;
|
|
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))
|
|
if (!dp->power_on || !dp->is_connected || atomic_read(&dp->aborted))
|
|
return;
|
|
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);
|
|
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);
|
|
sink_status &= (DP_RECEIVE_PORT_0_STATUS | DP_RECEIVE_PORT_1_STATUS);
|
|
if (sink_status < 1) {
|
|
if (sink_status < 1) {
|
|
@@ -890,9 +905,7 @@ static void dp_display_clean(struct dp_display_private *dp)
|
|
|
|
|
|
dp->power_on = false;
|
|
dp->power_on = false;
|
|
|
|
|
|
- mutex_lock(&dp->session_lock);
|
|
|
|
dp->ctrl->off(dp->ctrl);
|
|
dp->ctrl->off(dp->ctrl);
|
|
- mutex_unlock(&dp->session_lock);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
static int dp_display_handle_disconnect(struct dp_display_private *dp)
|
|
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) &&
|
|
if (dp_display_is_hdcp_enabled(dp) &&
|
|
status->hdcp_state != HDCP_STATE_INACTIVE) {
|
|
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);
|
|
flush_delayed_work(&dp->hdcp_cb_work);
|
|
if (dp->mst.mst_active) {
|
|
if (dp->mst.mst_active) {
|
|
dp_display_hdcp_deregister_stream(dp,
|
|
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)
|
|
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_display_set_mst_state(g_dp_display, PM_SUSPEND);
|
|
|
|
|
|
|
|
+ dp->suspended = true;
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
static void dp_pm_complete(struct device *dev)
|
|
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_display_set_mst_state(g_dp_display, PM_DEFAULT);
|
|
|
|
+
|
|
|
|
+ dp->suspended = false;
|
|
}
|
|
}
|
|
|
|
|
|
static const struct dev_pm_ops dp_pm_ops = {
|
|
static const struct dev_pm_ops dp_pm_ops = {
|