Loading msm/dp/dp_display.c +156 −65 Original line number Original line Diff line number Diff line Loading @@ -31,6 +31,71 @@ #define DP_MST_DEBUG(fmt, ...) DP_DEBUG(fmt, ##__VA_ARGS__) #define DP_MST_DEBUG(fmt, ...) DP_DEBUG(fmt, ##__VA_ARGS__) #define dp_display_state_show(x) { \ DP_ERR("%s: state (0x%x): %s\n", x, dp->state, \ dp_display_state_name(dp->state)); } #define dp_display_state_is(x) (dp->state & (x)) #define dp_display_state_add(x) (dp->state |= (x)) #define dp_display_state_remove(x) (dp->state &= ~(x)) enum dp_display_states { DP_STATE_DISCONNECTED = 0, DP_STATE_CONFIGURED = BIT(0), DP_STATE_INITIALIZED = BIT(1), DP_STATE_READY = BIT(2), DP_STATE_CONNECTED = BIT(3), DP_STATE_ENABLED = BIT(4), DP_STATE_SUSPENDED = BIT(5), DP_STATE_ABORTED = BIT(6), DP_STATE_HDCP_ABORTED = BIT(7), }; static char *dp_display_state_name(enum dp_display_states state) { static char buf[SZ_1K]; u32 len = 0; memset(buf, 0, SZ_1K); if (state & DP_STATE_CONFIGURED) len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", "CONFIGURED"); if (state & DP_STATE_INITIALIZED) len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", "INITIALIZED"); if (state & DP_STATE_READY) len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", "READY"); if (state & DP_STATE_CONNECTED) len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", "CONNECTED"); if (state & DP_STATE_ENABLED) len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", "ENABLED"); if (state & DP_STATE_SUSPENDED) len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", "SUSPENDED"); if (state & DP_STATE_ABORTED) len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", "ABORTED"); if (state & DP_STATE_HDCP_ABORTED) len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", "HDCP_ABORTED"); if (!strlen(buf)) return "DISCONNECTED"; return buf; } static struct dp_display *g_dp_display; static struct dp_display *g_dp_display; #define HPD_STRING_SIZE 30 #define HPD_STRING_SIZE 30 Loading Loading @@ -60,13 +125,8 @@ struct dp_display_private { char *name; char *name; int irq; int irq; /* state variables */ bool core_initialized; bool power_on; bool is_connected; enum drm_connector_status cached_connector_status; enum drm_connector_status cached_connector_status; enum dp_display_states state; atomic_t aborted; struct platform_device *pdev; struct platform_device *pdev; struct device_node *aux_switch_node; struct device_node *aux_switch_node; Loading Loading @@ -96,9 +156,7 @@ 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; bool hdcp_delayed_off; bool hdcp_abort; u32 active_stream_cnt; u32 active_stream_cnt; struct dp_mst mst; struct dp_mst mst; Loading Loading @@ -161,7 +219,7 @@ static bool dp_display_is_sink_count_zero(struct dp_display_private *dp) static bool dp_display_is_ready(struct dp_display_private *dp) static bool dp_display_is_ready(struct dp_display_private *dp) { { return dp->hpd->hpd_high && dp->is_connected && return dp->hpd->hpd_high && dp_display_state_is(DP_STATE_CONNECTED) && !dp_display_is_sink_count_zero(dp) && !dp_display_is_sink_count_zero(dp) && dp->hpd->alt_mode_cfg_done; dp->hpd->alt_mode_cfg_done; } } Loading Loading @@ -306,11 +364,11 @@ static void dp_display_hdcp_cb_work(struct work_struct *work) dp = container_of(dw, struct dp_display_private, hdcp_cb_work); dp = container_of(dw, struct dp_display_private, hdcp_cb_work); if (!dp->power_on || !dp->is_connected || atomic_read(&dp->aborted) || if (!dp_display_state_is(DP_STATE_ENABLED | DP_STATE_CONNECTED) || dp->hdcp_abort) dp_display_state_is(DP_STATE_ABORTED | DP_STATE_HDCP_ABORTED)) return; return; if (dp->suspended) { if (dp_display_state_is(DP_STATE_SUSPENDED)) { DP_DEBUG("System suspending. Delay HDCP operations\n"); DP_DEBUG("System suspending. Delay HDCP operations\n"); queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ); queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ); return; return; Loading Loading @@ -380,7 +438,8 @@ static void dp_display_hdcp_cb_work(struct work_struct *work) status->hdcp_state = HDCP_STATE_AUTHENTICATING; status->hdcp_state = HDCP_STATE_AUTHENTICATING; break; break; case HDCP_STATE_AUTH_FAIL: case HDCP_STATE_AUTH_FAIL: if (dp_display_is_ready(dp) && dp->power_on) { if (dp_display_is_ready(dp) && dp_display_state_is(DP_STATE_ENABLED)) { if (ops && ops->on && ops->on(data)) { if (ops && ops->on && ops->on(data)) { dp_display_update_hdcp_status(dp, true); dp_display_update_hdcp_status(dp, true); return; return; Loading Loading @@ -599,7 +658,7 @@ static void dp_display_send_hpd_event(struct dp_display_private *dp) static int dp_display_send_hpd_notification(struct dp_display_private *dp) static int dp_display_send_hpd_notification(struct dp_display_private *dp) { { int ret = 0; int ret = 0; bool hpd = dp->is_connected; bool hpd = !!dp_display_state_is(DP_STATE_CONNECTED); dp->aux->state |= DP_STATE_NOTIFICATION_SENT; dp->aux->state |= DP_STATE_NOTIFICATION_SENT; Loading @@ -614,7 +673,8 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp) if (hpd && dp->mst.mst_active) if (hpd && dp->mst.mst_active) goto skip_wait; goto skip_wait; if (!dp->mst.mst_active && (dp->power_on == hpd)) if (!dp->mst.mst_active && (!!dp_display_state_is(DP_STATE_ENABLED) == hpd)) goto skip_wait; goto skip_wait; if (!wait_for_completion_timeout(&dp->notification_comp, if (!wait_for_completion_timeout(&dp->notification_comp, Loading Loading @@ -697,7 +757,7 @@ static void dp_display_host_init(struct dp_display_private *dp) bool flip = false; bool flip = false; bool reset; bool reset; if (dp->core_initialized) if (dp_display_state_is(DP_STATE_INITIALIZED)) return; return; if (dp->hpd->orientation == ORIENTATION_CC2) if (dp->hpd->orientation == ORIENTATION_CC2) Loading @@ -710,20 +770,35 @@ static void dp_display_host_init(struct dp_display_private *dp) dp->ctrl->init(dp->ctrl, flip, reset); dp->ctrl->init(dp->ctrl, flip, reset); enable_irq(dp->irq); enable_irq(dp->irq); dp_display_state_add(DP_STATE_INITIALIZED); /* log this as it results from user action of cable connection */ /* log this as it results from user action of cable connection */ DP_INFO("[OK]\n"); DP_INFO("[OK]\n"); } } static void dp_display_host_late_init(struct dp_display_private *dp) static void dp_display_host_ready(struct dp_display_private *dp) { { if (!dp_display_state_is(DP_STATE_INITIALIZED)) return; if (dp_display_state_is(DP_STATE_READY)) return; dp->aux->init(dp->aux, dp->parser->aux_cfg); dp->aux->init(dp->aux, dp->parser->aux_cfg); dp->panel->init(dp->panel); dp->panel->init(dp->panel); dp->core_initialized = true; dp_display_state_add(DP_STATE_READY); } } static void dp_display_host_early_deinit(struct dp_display_private *dp) static void dp_display_host_unready(struct dp_display_private *dp) { { dp->core_initialized = false; if (!dp_display_state_is(DP_STATE_INITIALIZED)) return; if (!dp_display_state_is(DP_STATE_READY)) return; dp_display_state_remove(DP_STATE_READY); dp->aux->deinit(dp->aux); dp->aux->deinit(dp->aux); } } Loading @@ -734,12 +809,17 @@ static void dp_display_host_deinit(struct dp_display_private *dp) return; return; } } if (!dp_display_state_is(DP_STATE_INITIALIZED)) return; dp->ctrl->deinit(dp->ctrl); dp->ctrl->deinit(dp->ctrl); dp->hpd->host_deinit(dp->hpd, &dp->catalog->hpd); dp->hpd->host_deinit(dp->hpd, &dp->catalog->hpd); dp->power->deinit(dp->power); dp->power->deinit(dp->power); disable_irq(dp->irq); disable_irq(dp->irq); dp->aux->state = 0; dp->aux->state = 0; dp_display_state_remove(DP_STATE_INITIALIZED); /* log this as it results from user action of cable dis-connection */ /* log this as it results from user action of cable dis-connection */ DP_INFO("[OK]\n"); DP_INFO("[OK]\n"); } } Loading @@ -750,19 +830,19 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) mutex_lock(&dp->session_lock); mutex_lock(&dp->session_lock); if (dp->is_connected) { if (dp_display_state_is(DP_STATE_CONNECTED)) { DP_DEBUG("dp already connected, skipping hpd high\n"); DP_DEBUG("dp already connected, skipping hpd high\n"); mutex_unlock(&dp->session_lock); mutex_unlock(&dp->session_lock); rc = -EISCONN; rc = -EISCONN; goto end; goto end; } } dp->is_connected = true; dp_display_state_add(DP_STATE_CONNECTED); dp->dp_display.max_pclk_khz = min(dp->parser->max_pclk_khz, dp->dp_display.max_pclk_khz = min(dp->parser->max_pclk_khz, dp->debug->max_pclk_khz); dp->debug->max_pclk_khz); dp_display_host_late_init(dp); dp_display_host_ready(dp); dp->link->psm_config(dp->link, &dp->panel->link_info, false); dp->link->psm_config(dp->link, &dp->panel->link_info, false); dp->debug->psm_enabled = false; dp->debug->psm_enabled = false; Loading @@ -777,7 +857,7 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) * ENOTCONN --> no downstream device connected * ENOTCONN --> no downstream device connected */ */ if (rc == -ETIMEDOUT || rc == -ENOTCONN) { if (rc == -ETIMEDOUT || rc == -ENOTCONN) { dp->is_connected = false; dp_display_state_remove(DP_STATE_CONNECTED); goto end; goto end; } } Loading @@ -789,7 +869,7 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) rc = dp->ctrl->on(dp->ctrl, dp->mst.mst_active, rc = dp->ctrl->on(dp->ctrl, dp->mst.mst_active, dp->panel->fec_en, false); dp->panel->fec_en, false); if (rc) { if (rc) { dp->is_connected = false; dp_display_state_remove(DP_STATE_CONNECTED); goto end; goto end; } } Loading @@ -799,7 +879,7 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) end: end: mutex_unlock(&dp->session_lock); mutex_unlock(&dp->session_lock); if (!rc && !atomic_read(&dp->aborted)) if (!rc && !dp_display_state_is(DP_STATE_ABORTED)) dp_display_send_hpd_notification(dp); dp_display_send_hpd_notification(dp); return rc; return rc; Loading @@ -826,12 +906,12 @@ static int dp_display_process_hpd_low(struct dp_display_private *dp) { { int rc = 0; int rc = 0; dp->is_connected = false; dp_display_state_remove(DP_STATE_CONNECTED); dp->process_hpd_connect = false; dp->process_hpd_connect = false; dp_display_process_mst_hpd_low(dp); dp_display_process_mst_hpd_low(dp); if (dp->power_on && !dp->mst.mst_active) if (dp_display_state_is(DP_STATE_ENABLED) && !dp->mst.mst_active) rc = dp_display_send_hpd_notification(dp); rc = dp_display_send_hpd_notification(dp); mutex_lock(&dp->session_lock); mutex_lock(&dp->session_lock); Loading Loading @@ -871,7 +951,8 @@ static int dp_display_usbpd_configure_cb(struct device *dev) mutex_lock(&dp->session_lock); mutex_lock(&dp->session_lock); atomic_set(&dp->aborted, 0); dp_display_state_remove(DP_STATE_ABORTED); dp_display_state_add(DP_STATE_CONFIGURED); dp_display_host_init(dp); dp_display_host_init(dp); Loading Loading @@ -938,8 +1019,7 @@ static void dp_display_clean(struct dp_display_private *dp) dp_panel->deinit(dp_panel, 0); dp_panel->deinit(dp_panel, 0); } } dp->power_on = false; dp_display_state_remove(DP_STATE_ENABLED | DP_STATE_CONNECTED); dp->is_connected = false; dp->ctrl->off(dp->ctrl); dp->ctrl->off(dp->ctrl); } } Loading @@ -956,10 +1036,10 @@ static int dp_display_handle_disconnect(struct dp_display_private *dp) } } mutex_lock(&dp->session_lock); mutex_lock(&dp->session_lock); if (rc && dp->power_on) if (rc && dp_display_state_is(DP_STATE_ENABLED)) dp_display_clean(dp); dp_display_clean(dp); dp_display_host_early_deinit(dp); dp_display_host_unready(dp); mutex_unlock(&dp->session_lock); mutex_unlock(&dp->session_lock); Loading @@ -969,7 +1049,8 @@ static int dp_display_handle_disconnect(struct dp_display_private *dp) static void dp_display_disconnect_sync(struct dp_display_private *dp) static void dp_display_disconnect_sync(struct dp_display_private *dp) { { /* cancel any pending request */ /* cancel any pending request */ atomic_set(&dp->aborted, 1); dp_display_state_add(DP_STATE_ABORTED); dp->ctrl->abort(dp->ctrl); dp->ctrl->abort(dp->ctrl); dp->aux->abort(dp->aux); dp->aux->abort(dp->aux); Loading Loading @@ -999,8 +1080,10 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev) goto end; goto end; } } dp_display_state_remove(DP_STATE_CONFIGURED); mutex_lock(&dp->session_lock); mutex_lock(&dp->session_lock); if (dp->debug->psm_enabled && dp->core_initialized) if (dp->debug->psm_enabled && dp_display_state_is(DP_STATE_READY)) dp->link->psm_config(dp->link, &dp->panel->link_info, true); dp->link->psm_config(dp->link, &dp->panel->link_info, true); mutex_unlock(&dp->session_lock); mutex_unlock(&dp->session_lock); Loading Loading @@ -1063,7 +1146,7 @@ static void dp_display_attention_work(struct work_struct *work) mutex_lock(&dp->session_lock); mutex_lock(&dp->session_lock); if (dp->debug->mst_hpd_sim || !dp->core_initialized) { if (dp->debug->mst_hpd_sim || !dp_display_state_is(DP_STATE_READY)) { mutex_unlock(&dp->session_lock); mutex_unlock(&dp->session_lock); goto mst_attention; goto mst_attention; } } Loading Loading @@ -1132,15 +1215,17 @@ static int dp_display_usbpd_attention_cb(struct device *dev) DP_DEBUG("hpd_irq:%d, hpd_high:%d, power_on:%d, is_connected:%d\n", DP_DEBUG("hpd_irq:%d, hpd_high:%d, power_on:%d, is_connected:%d\n", dp->hpd->hpd_irq, dp->hpd->hpd_high, dp->hpd->hpd_irq, dp->hpd->hpd_high, dp->power_on, dp->is_connected); !!dp_display_state_is(DP_STATE_ENABLED), !!dp_display_state_is(DP_STATE_CONNECTED)); if (!dp->hpd->hpd_high) { if (!dp->hpd->hpd_high) { dp_display_disconnect_sync(dp); dp_display_disconnect_sync(dp); } else if ((dp->hpd->hpd_irq && dp->core_initialized) || } else if ((dp->hpd->hpd_irq && dp_display_state_is(DP_STATE_READY)) || dp->debug->mst_hpd_sim) { dp->debug->mst_hpd_sim) { queue_work(dp->wq, &dp->attention_work); queue_work(dp->wq, &dp->attention_work); } else if (dp->process_hpd_connect || !dp->is_connected) { } else if (dp->process_hpd_connect || atomic_set(&dp->aborted, 0); !dp_display_state_is(DP_STATE_CONNECTED)) { dp_display_state_remove(DP_STATE_ABORTED); queue_work(dp->wq, &dp->connect_work); queue_work(dp->wq, &dp->connect_work); } else { } else { DP_DEBUG("ignored\n"); DP_DEBUG("ignored\n"); Loading @@ -1155,7 +1240,7 @@ static void dp_display_connect_work(struct work_struct *work) struct dp_display_private *dp = container_of(work, struct dp_display_private *dp = container_of(work, struct dp_display_private, connect_work); struct dp_display_private, connect_work); if (atomic_read(&dp->aborted)) { if (dp_display_state_is(DP_STATE_ABORTED)) { DP_WARN("HPD off requested\n"); DP_WARN("HPD off requested\n"); return; return; } } Loading Loading @@ -1498,16 +1583,15 @@ static int dp_display_prepare(struct dp_display *dp_display, void *panel) mutex_lock(&dp->session_lock); mutex_lock(&dp->session_lock); if (atomic_read(&dp->aborted)) if (dp_display_state_is(DP_STATE_ABORTED | DP_STATE_ENABLED)) goto end; if (dp->power_on) goto end; goto end; if (!dp_display_is_ready(dp)) if (!dp_display_is_ready(dp)) goto end; goto end; /* For supporting DP_PANEL_SRC_INITIATED_POWER_DOWN case */ dp_display_host_init(dp); dp_display_host_init(dp); dp_display_host_ready(dp); if (dp->debug->psm_enabled) { if (dp->debug->psm_enabled) { dp->link->psm_config(dp->link, &dp->panel->link_info, false); dp->link->psm_config(dp->link, &dp->panel->link_info, false); Loading Loading @@ -1614,17 +1698,20 @@ static int dp_display_enable(struct dp_display *dp_display, void *panel) mutex_lock(&dp->session_lock); mutex_lock(&dp->session_lock); if (!dp->core_initialized || atomic_read(&dp->aborted)) { if (!dp_display_state_is(DP_STATE_READY)) { DP_ERR("host not initialized\n"); dp_display_state_show("[host not ready]"); goto end; goto end; } } if (dp_display_state_is(DP_STATE_ABORTED)) goto end; rc = dp_display_stream_enable(dp, panel); rc = dp_display_stream_enable(dp, panel); if (rc) if (rc) goto end; goto end; dp_display_update_dsc_resources(dp, panel, true); dp_display_update_dsc_resources(dp, panel, true); dp->power_on = true; dp_display_state_add(DP_STATE_ENABLED); end: end: mutex_unlock(&dp->session_lock); mutex_unlock(&dp->session_lock); return rc; return rc; Loading Loading @@ -1652,16 +1739,16 @@ static int dp_display_post_enable(struct dp_display *dp_display, void *panel) mutex_lock(&dp->session_lock); mutex_lock(&dp->session_lock); if (!dp->power_on) { if (!dp_display_state_is(DP_STATE_ENABLED)) { DP_DEBUG("stream not setup, return\n"); dp_display_state_show("[not enabled]"); goto end; goto end; } } if (atomic_read(&dp->aborted)) if (dp_display_state_is(DP_STATE_ABORTED)) goto end; goto end; if (!dp_display_is_ready(dp) || !dp->core_initialized) { if (!dp_display_is_ready(dp) || !dp_display_state_is(DP_STATE_READY)) { DP_ERR("display not ready\n"); dp_display_state_show("[not ready]"); goto end; goto end; } } Loading Loading @@ -1710,18 +1797,18 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel) status = &dp->link->hdcp_status; status = &dp->link->hdcp_status; if (!dp->power_on) { if (!dp_display_state_is(DP_STATE_ENABLED)) { DP_DEBUG("stream already powered off, return\n"); dp_display_state_show("[not enabled]"); goto end; goto end; } } dp->hdcp_abort = true; dp_display_state_add(DP_STATE_HDCP_ABORTED); cancel_delayed_work_sync(&dp->hdcp_cb_work); cancel_delayed_work_sync(&dp->hdcp_cb_work); 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) { bool off = true; bool off = true; if (dp->suspended) { if (dp_display_state_is(DP_STATE_SUSPENDED)) { DP_DEBUG("Can't perform HDCP cleanup while suspended. Defer\n"); DP_DEBUG("Can't perform HDCP cleanup while suspended. Defer\n"); dp->hdcp_delayed_off = true; dp->hdcp_delayed_off = true; goto clean; goto clean; Loading Loading @@ -1778,15 +1865,20 @@ static int dp_display_disable(struct dp_display *dp_display, void *panel) mutex_lock(&dp->session_lock); mutex_lock(&dp->session_lock); if (!dp->power_on || !dp->core_initialized) { if (!dp_display_state_is(DP_STATE_ENABLED)) { DP_DEBUG("Link already powered off, return\n"); dp_display_state_show("[not enabled]"); goto end; } if (!dp_display_state_is(DP_STATE_READY)) { dp_display_state_show("[not ready]"); goto end; goto end; } } dp_display_stream_disable(dp, dp_panel); dp_display_stream_disable(dp, dp_panel); dp_display_update_dsc_resources(dp, dp_panel, false); dp_display_update_dsc_resources(dp, dp_panel, false); dp->hdcp_abort = false; dp_display_state_remove(DP_STATE_HDCP_ABORTED); for (i = DP_STREAM_0; i < DP_STREAM_MAX; i++) { for (i = DP_STREAM_0; i < DP_STREAM_MAX; i++) { if (dp->active_panels[i]) { if (dp->active_panels[i]) { if (status->hdcp_state != HDCP_STATE_AUTHENTICATED) if (status->hdcp_state != HDCP_STATE_AUTHENTICATED) Loading Loading @@ -1877,11 +1969,11 @@ static int dp_display_unprepare(struct dp_display *dp_display, void *panel) dp->debug->psm_enabled = true; dp->debug->psm_enabled = true; dp->ctrl->off(dp->ctrl); dp->ctrl->off(dp->ctrl); dp_display_host_early_deinit(dp); dp_display_host_unready(dp); dp_display_host_deinit(dp); dp_display_host_deinit(dp); } } dp->power_on = false; dp_display_state_remove(DP_STATE_ENABLED); dp->aux->state = DP_STATE_CTRL_POWERED_OFF; dp->aux->state = DP_STATE_CTRL_POWERED_OFF; complete_all(&dp->notification_comp); complete_all(&dp->notification_comp); Loading Loading @@ -2621,7 +2713,6 @@ static int dp_display_probe(struct platform_device *pdev) dp->name = "drm_dp"; dp->name = "drm_dp"; memset(&dp->mst, 0, sizeof(dp->mst)); memset(&dp->mst, 0, sizeof(dp->mst)); atomic_set(&dp->aborted, 0); rc = dp_display_init_aux_switch(dp); rc = dp_display_init_aux_switch(dp); if (rc) { if (rc) { Loading Loading @@ -2758,7 +2849,7 @@ static int dp_pm_prepare(struct device *dev) dp_display_set_mst_state(g_dp_display, PM_SUSPEND); dp_display_set_mst_state(g_dp_display, PM_SUSPEND); dp->suspended = true; dp_display_state_add(DP_STATE_SUSPENDED); return 0; return 0; } } Loading @@ -2770,7 +2861,7 @@ static void dp_pm_complete(struct device *dev) dp_display_set_mst_state(g_dp_display, PM_DEFAULT); dp_display_set_mst_state(g_dp_display, PM_DEFAULT); dp->suspended = false; dp_display_state_remove(DP_STATE_SUSPENDED); } } static const struct dev_pm_ops dp_pm_ops = { static const struct dev_pm_ops dp_pm_ops = { Loading Loading
msm/dp/dp_display.c +156 −65 Original line number Original line Diff line number Diff line Loading @@ -31,6 +31,71 @@ #define DP_MST_DEBUG(fmt, ...) DP_DEBUG(fmt, ##__VA_ARGS__) #define DP_MST_DEBUG(fmt, ...) DP_DEBUG(fmt, ##__VA_ARGS__) #define dp_display_state_show(x) { \ DP_ERR("%s: state (0x%x): %s\n", x, dp->state, \ dp_display_state_name(dp->state)); } #define dp_display_state_is(x) (dp->state & (x)) #define dp_display_state_add(x) (dp->state |= (x)) #define dp_display_state_remove(x) (dp->state &= ~(x)) enum dp_display_states { DP_STATE_DISCONNECTED = 0, DP_STATE_CONFIGURED = BIT(0), DP_STATE_INITIALIZED = BIT(1), DP_STATE_READY = BIT(2), DP_STATE_CONNECTED = BIT(3), DP_STATE_ENABLED = BIT(4), DP_STATE_SUSPENDED = BIT(5), DP_STATE_ABORTED = BIT(6), DP_STATE_HDCP_ABORTED = BIT(7), }; static char *dp_display_state_name(enum dp_display_states state) { static char buf[SZ_1K]; u32 len = 0; memset(buf, 0, SZ_1K); if (state & DP_STATE_CONFIGURED) len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", "CONFIGURED"); if (state & DP_STATE_INITIALIZED) len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", "INITIALIZED"); if (state & DP_STATE_READY) len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", "READY"); if (state & DP_STATE_CONNECTED) len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", "CONNECTED"); if (state & DP_STATE_ENABLED) len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", "ENABLED"); if (state & DP_STATE_SUSPENDED) len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", "SUSPENDED"); if (state & DP_STATE_ABORTED) len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", "ABORTED"); if (state & DP_STATE_HDCP_ABORTED) len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", "HDCP_ABORTED"); if (!strlen(buf)) return "DISCONNECTED"; return buf; } static struct dp_display *g_dp_display; static struct dp_display *g_dp_display; #define HPD_STRING_SIZE 30 #define HPD_STRING_SIZE 30 Loading Loading @@ -60,13 +125,8 @@ struct dp_display_private { char *name; char *name; int irq; int irq; /* state variables */ bool core_initialized; bool power_on; bool is_connected; enum drm_connector_status cached_connector_status; enum drm_connector_status cached_connector_status; enum dp_display_states state; atomic_t aborted; struct platform_device *pdev; struct platform_device *pdev; struct device_node *aux_switch_node; struct device_node *aux_switch_node; Loading Loading @@ -96,9 +156,7 @@ 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; bool hdcp_delayed_off; bool hdcp_abort; u32 active_stream_cnt; u32 active_stream_cnt; struct dp_mst mst; struct dp_mst mst; Loading Loading @@ -161,7 +219,7 @@ static bool dp_display_is_sink_count_zero(struct dp_display_private *dp) static bool dp_display_is_ready(struct dp_display_private *dp) static bool dp_display_is_ready(struct dp_display_private *dp) { { return dp->hpd->hpd_high && dp->is_connected && return dp->hpd->hpd_high && dp_display_state_is(DP_STATE_CONNECTED) && !dp_display_is_sink_count_zero(dp) && !dp_display_is_sink_count_zero(dp) && dp->hpd->alt_mode_cfg_done; dp->hpd->alt_mode_cfg_done; } } Loading Loading @@ -306,11 +364,11 @@ static void dp_display_hdcp_cb_work(struct work_struct *work) dp = container_of(dw, struct dp_display_private, hdcp_cb_work); dp = container_of(dw, struct dp_display_private, hdcp_cb_work); if (!dp->power_on || !dp->is_connected || atomic_read(&dp->aborted) || if (!dp_display_state_is(DP_STATE_ENABLED | DP_STATE_CONNECTED) || dp->hdcp_abort) dp_display_state_is(DP_STATE_ABORTED | DP_STATE_HDCP_ABORTED)) return; return; if (dp->suspended) { if (dp_display_state_is(DP_STATE_SUSPENDED)) { DP_DEBUG("System suspending. Delay HDCP operations\n"); DP_DEBUG("System suspending. Delay HDCP operations\n"); queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ); queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ); return; return; Loading Loading @@ -380,7 +438,8 @@ static void dp_display_hdcp_cb_work(struct work_struct *work) status->hdcp_state = HDCP_STATE_AUTHENTICATING; status->hdcp_state = HDCP_STATE_AUTHENTICATING; break; break; case HDCP_STATE_AUTH_FAIL: case HDCP_STATE_AUTH_FAIL: if (dp_display_is_ready(dp) && dp->power_on) { if (dp_display_is_ready(dp) && dp_display_state_is(DP_STATE_ENABLED)) { if (ops && ops->on && ops->on(data)) { if (ops && ops->on && ops->on(data)) { dp_display_update_hdcp_status(dp, true); dp_display_update_hdcp_status(dp, true); return; return; Loading Loading @@ -599,7 +658,7 @@ static void dp_display_send_hpd_event(struct dp_display_private *dp) static int dp_display_send_hpd_notification(struct dp_display_private *dp) static int dp_display_send_hpd_notification(struct dp_display_private *dp) { { int ret = 0; int ret = 0; bool hpd = dp->is_connected; bool hpd = !!dp_display_state_is(DP_STATE_CONNECTED); dp->aux->state |= DP_STATE_NOTIFICATION_SENT; dp->aux->state |= DP_STATE_NOTIFICATION_SENT; Loading @@ -614,7 +673,8 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp) if (hpd && dp->mst.mst_active) if (hpd && dp->mst.mst_active) goto skip_wait; goto skip_wait; if (!dp->mst.mst_active && (dp->power_on == hpd)) if (!dp->mst.mst_active && (!!dp_display_state_is(DP_STATE_ENABLED) == hpd)) goto skip_wait; goto skip_wait; if (!wait_for_completion_timeout(&dp->notification_comp, if (!wait_for_completion_timeout(&dp->notification_comp, Loading Loading @@ -697,7 +757,7 @@ static void dp_display_host_init(struct dp_display_private *dp) bool flip = false; bool flip = false; bool reset; bool reset; if (dp->core_initialized) if (dp_display_state_is(DP_STATE_INITIALIZED)) return; return; if (dp->hpd->orientation == ORIENTATION_CC2) if (dp->hpd->orientation == ORIENTATION_CC2) Loading @@ -710,20 +770,35 @@ static void dp_display_host_init(struct dp_display_private *dp) dp->ctrl->init(dp->ctrl, flip, reset); dp->ctrl->init(dp->ctrl, flip, reset); enable_irq(dp->irq); enable_irq(dp->irq); dp_display_state_add(DP_STATE_INITIALIZED); /* log this as it results from user action of cable connection */ /* log this as it results from user action of cable connection */ DP_INFO("[OK]\n"); DP_INFO("[OK]\n"); } } static void dp_display_host_late_init(struct dp_display_private *dp) static void dp_display_host_ready(struct dp_display_private *dp) { { if (!dp_display_state_is(DP_STATE_INITIALIZED)) return; if (dp_display_state_is(DP_STATE_READY)) return; dp->aux->init(dp->aux, dp->parser->aux_cfg); dp->aux->init(dp->aux, dp->parser->aux_cfg); dp->panel->init(dp->panel); dp->panel->init(dp->panel); dp->core_initialized = true; dp_display_state_add(DP_STATE_READY); } } static void dp_display_host_early_deinit(struct dp_display_private *dp) static void dp_display_host_unready(struct dp_display_private *dp) { { dp->core_initialized = false; if (!dp_display_state_is(DP_STATE_INITIALIZED)) return; if (!dp_display_state_is(DP_STATE_READY)) return; dp_display_state_remove(DP_STATE_READY); dp->aux->deinit(dp->aux); dp->aux->deinit(dp->aux); } } Loading @@ -734,12 +809,17 @@ static void dp_display_host_deinit(struct dp_display_private *dp) return; return; } } if (!dp_display_state_is(DP_STATE_INITIALIZED)) return; dp->ctrl->deinit(dp->ctrl); dp->ctrl->deinit(dp->ctrl); dp->hpd->host_deinit(dp->hpd, &dp->catalog->hpd); dp->hpd->host_deinit(dp->hpd, &dp->catalog->hpd); dp->power->deinit(dp->power); dp->power->deinit(dp->power); disable_irq(dp->irq); disable_irq(dp->irq); dp->aux->state = 0; dp->aux->state = 0; dp_display_state_remove(DP_STATE_INITIALIZED); /* log this as it results from user action of cable dis-connection */ /* log this as it results from user action of cable dis-connection */ DP_INFO("[OK]\n"); DP_INFO("[OK]\n"); } } Loading @@ -750,19 +830,19 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) mutex_lock(&dp->session_lock); mutex_lock(&dp->session_lock); if (dp->is_connected) { if (dp_display_state_is(DP_STATE_CONNECTED)) { DP_DEBUG("dp already connected, skipping hpd high\n"); DP_DEBUG("dp already connected, skipping hpd high\n"); mutex_unlock(&dp->session_lock); mutex_unlock(&dp->session_lock); rc = -EISCONN; rc = -EISCONN; goto end; goto end; } } dp->is_connected = true; dp_display_state_add(DP_STATE_CONNECTED); dp->dp_display.max_pclk_khz = min(dp->parser->max_pclk_khz, dp->dp_display.max_pclk_khz = min(dp->parser->max_pclk_khz, dp->debug->max_pclk_khz); dp->debug->max_pclk_khz); dp_display_host_late_init(dp); dp_display_host_ready(dp); dp->link->psm_config(dp->link, &dp->panel->link_info, false); dp->link->psm_config(dp->link, &dp->panel->link_info, false); dp->debug->psm_enabled = false; dp->debug->psm_enabled = false; Loading @@ -777,7 +857,7 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) * ENOTCONN --> no downstream device connected * ENOTCONN --> no downstream device connected */ */ if (rc == -ETIMEDOUT || rc == -ENOTCONN) { if (rc == -ETIMEDOUT || rc == -ENOTCONN) { dp->is_connected = false; dp_display_state_remove(DP_STATE_CONNECTED); goto end; goto end; } } Loading @@ -789,7 +869,7 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) rc = dp->ctrl->on(dp->ctrl, dp->mst.mst_active, rc = dp->ctrl->on(dp->ctrl, dp->mst.mst_active, dp->panel->fec_en, false); dp->panel->fec_en, false); if (rc) { if (rc) { dp->is_connected = false; dp_display_state_remove(DP_STATE_CONNECTED); goto end; goto end; } } Loading @@ -799,7 +879,7 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) end: end: mutex_unlock(&dp->session_lock); mutex_unlock(&dp->session_lock); if (!rc && !atomic_read(&dp->aborted)) if (!rc && !dp_display_state_is(DP_STATE_ABORTED)) dp_display_send_hpd_notification(dp); dp_display_send_hpd_notification(dp); return rc; return rc; Loading @@ -826,12 +906,12 @@ static int dp_display_process_hpd_low(struct dp_display_private *dp) { { int rc = 0; int rc = 0; dp->is_connected = false; dp_display_state_remove(DP_STATE_CONNECTED); dp->process_hpd_connect = false; dp->process_hpd_connect = false; dp_display_process_mst_hpd_low(dp); dp_display_process_mst_hpd_low(dp); if (dp->power_on && !dp->mst.mst_active) if (dp_display_state_is(DP_STATE_ENABLED) && !dp->mst.mst_active) rc = dp_display_send_hpd_notification(dp); rc = dp_display_send_hpd_notification(dp); mutex_lock(&dp->session_lock); mutex_lock(&dp->session_lock); Loading Loading @@ -871,7 +951,8 @@ static int dp_display_usbpd_configure_cb(struct device *dev) mutex_lock(&dp->session_lock); mutex_lock(&dp->session_lock); atomic_set(&dp->aborted, 0); dp_display_state_remove(DP_STATE_ABORTED); dp_display_state_add(DP_STATE_CONFIGURED); dp_display_host_init(dp); dp_display_host_init(dp); Loading Loading @@ -938,8 +1019,7 @@ static void dp_display_clean(struct dp_display_private *dp) dp_panel->deinit(dp_panel, 0); dp_panel->deinit(dp_panel, 0); } } dp->power_on = false; dp_display_state_remove(DP_STATE_ENABLED | DP_STATE_CONNECTED); dp->is_connected = false; dp->ctrl->off(dp->ctrl); dp->ctrl->off(dp->ctrl); } } Loading @@ -956,10 +1036,10 @@ static int dp_display_handle_disconnect(struct dp_display_private *dp) } } mutex_lock(&dp->session_lock); mutex_lock(&dp->session_lock); if (rc && dp->power_on) if (rc && dp_display_state_is(DP_STATE_ENABLED)) dp_display_clean(dp); dp_display_clean(dp); dp_display_host_early_deinit(dp); dp_display_host_unready(dp); mutex_unlock(&dp->session_lock); mutex_unlock(&dp->session_lock); Loading @@ -969,7 +1049,8 @@ static int dp_display_handle_disconnect(struct dp_display_private *dp) static void dp_display_disconnect_sync(struct dp_display_private *dp) static void dp_display_disconnect_sync(struct dp_display_private *dp) { { /* cancel any pending request */ /* cancel any pending request */ atomic_set(&dp->aborted, 1); dp_display_state_add(DP_STATE_ABORTED); dp->ctrl->abort(dp->ctrl); dp->ctrl->abort(dp->ctrl); dp->aux->abort(dp->aux); dp->aux->abort(dp->aux); Loading Loading @@ -999,8 +1080,10 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev) goto end; goto end; } } dp_display_state_remove(DP_STATE_CONFIGURED); mutex_lock(&dp->session_lock); mutex_lock(&dp->session_lock); if (dp->debug->psm_enabled && dp->core_initialized) if (dp->debug->psm_enabled && dp_display_state_is(DP_STATE_READY)) dp->link->psm_config(dp->link, &dp->panel->link_info, true); dp->link->psm_config(dp->link, &dp->panel->link_info, true); mutex_unlock(&dp->session_lock); mutex_unlock(&dp->session_lock); Loading Loading @@ -1063,7 +1146,7 @@ static void dp_display_attention_work(struct work_struct *work) mutex_lock(&dp->session_lock); mutex_lock(&dp->session_lock); if (dp->debug->mst_hpd_sim || !dp->core_initialized) { if (dp->debug->mst_hpd_sim || !dp_display_state_is(DP_STATE_READY)) { mutex_unlock(&dp->session_lock); mutex_unlock(&dp->session_lock); goto mst_attention; goto mst_attention; } } Loading Loading @@ -1132,15 +1215,17 @@ static int dp_display_usbpd_attention_cb(struct device *dev) DP_DEBUG("hpd_irq:%d, hpd_high:%d, power_on:%d, is_connected:%d\n", DP_DEBUG("hpd_irq:%d, hpd_high:%d, power_on:%d, is_connected:%d\n", dp->hpd->hpd_irq, dp->hpd->hpd_high, dp->hpd->hpd_irq, dp->hpd->hpd_high, dp->power_on, dp->is_connected); !!dp_display_state_is(DP_STATE_ENABLED), !!dp_display_state_is(DP_STATE_CONNECTED)); if (!dp->hpd->hpd_high) { if (!dp->hpd->hpd_high) { dp_display_disconnect_sync(dp); dp_display_disconnect_sync(dp); } else if ((dp->hpd->hpd_irq && dp->core_initialized) || } else if ((dp->hpd->hpd_irq && dp_display_state_is(DP_STATE_READY)) || dp->debug->mst_hpd_sim) { dp->debug->mst_hpd_sim) { queue_work(dp->wq, &dp->attention_work); queue_work(dp->wq, &dp->attention_work); } else if (dp->process_hpd_connect || !dp->is_connected) { } else if (dp->process_hpd_connect || atomic_set(&dp->aborted, 0); !dp_display_state_is(DP_STATE_CONNECTED)) { dp_display_state_remove(DP_STATE_ABORTED); queue_work(dp->wq, &dp->connect_work); queue_work(dp->wq, &dp->connect_work); } else { } else { DP_DEBUG("ignored\n"); DP_DEBUG("ignored\n"); Loading @@ -1155,7 +1240,7 @@ static void dp_display_connect_work(struct work_struct *work) struct dp_display_private *dp = container_of(work, struct dp_display_private *dp = container_of(work, struct dp_display_private, connect_work); struct dp_display_private, connect_work); if (atomic_read(&dp->aborted)) { if (dp_display_state_is(DP_STATE_ABORTED)) { DP_WARN("HPD off requested\n"); DP_WARN("HPD off requested\n"); return; return; } } Loading Loading @@ -1498,16 +1583,15 @@ static int dp_display_prepare(struct dp_display *dp_display, void *panel) mutex_lock(&dp->session_lock); mutex_lock(&dp->session_lock); if (atomic_read(&dp->aborted)) if (dp_display_state_is(DP_STATE_ABORTED | DP_STATE_ENABLED)) goto end; if (dp->power_on) goto end; goto end; if (!dp_display_is_ready(dp)) if (!dp_display_is_ready(dp)) goto end; goto end; /* For supporting DP_PANEL_SRC_INITIATED_POWER_DOWN case */ dp_display_host_init(dp); dp_display_host_init(dp); dp_display_host_ready(dp); if (dp->debug->psm_enabled) { if (dp->debug->psm_enabled) { dp->link->psm_config(dp->link, &dp->panel->link_info, false); dp->link->psm_config(dp->link, &dp->panel->link_info, false); Loading Loading @@ -1614,17 +1698,20 @@ static int dp_display_enable(struct dp_display *dp_display, void *panel) mutex_lock(&dp->session_lock); mutex_lock(&dp->session_lock); if (!dp->core_initialized || atomic_read(&dp->aborted)) { if (!dp_display_state_is(DP_STATE_READY)) { DP_ERR("host not initialized\n"); dp_display_state_show("[host not ready]"); goto end; goto end; } } if (dp_display_state_is(DP_STATE_ABORTED)) goto end; rc = dp_display_stream_enable(dp, panel); rc = dp_display_stream_enable(dp, panel); if (rc) if (rc) goto end; goto end; dp_display_update_dsc_resources(dp, panel, true); dp_display_update_dsc_resources(dp, panel, true); dp->power_on = true; dp_display_state_add(DP_STATE_ENABLED); end: end: mutex_unlock(&dp->session_lock); mutex_unlock(&dp->session_lock); return rc; return rc; Loading Loading @@ -1652,16 +1739,16 @@ static int dp_display_post_enable(struct dp_display *dp_display, void *panel) mutex_lock(&dp->session_lock); mutex_lock(&dp->session_lock); if (!dp->power_on) { if (!dp_display_state_is(DP_STATE_ENABLED)) { DP_DEBUG("stream not setup, return\n"); dp_display_state_show("[not enabled]"); goto end; goto end; } } if (atomic_read(&dp->aborted)) if (dp_display_state_is(DP_STATE_ABORTED)) goto end; goto end; if (!dp_display_is_ready(dp) || !dp->core_initialized) { if (!dp_display_is_ready(dp) || !dp_display_state_is(DP_STATE_READY)) { DP_ERR("display not ready\n"); dp_display_state_show("[not ready]"); goto end; goto end; } } Loading Loading @@ -1710,18 +1797,18 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel) status = &dp->link->hdcp_status; status = &dp->link->hdcp_status; if (!dp->power_on) { if (!dp_display_state_is(DP_STATE_ENABLED)) { DP_DEBUG("stream already powered off, return\n"); dp_display_state_show("[not enabled]"); goto end; goto end; } } dp->hdcp_abort = true; dp_display_state_add(DP_STATE_HDCP_ABORTED); cancel_delayed_work_sync(&dp->hdcp_cb_work); cancel_delayed_work_sync(&dp->hdcp_cb_work); 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) { bool off = true; bool off = true; if (dp->suspended) { if (dp_display_state_is(DP_STATE_SUSPENDED)) { DP_DEBUG("Can't perform HDCP cleanup while suspended. Defer\n"); DP_DEBUG("Can't perform HDCP cleanup while suspended. Defer\n"); dp->hdcp_delayed_off = true; dp->hdcp_delayed_off = true; goto clean; goto clean; Loading Loading @@ -1778,15 +1865,20 @@ static int dp_display_disable(struct dp_display *dp_display, void *panel) mutex_lock(&dp->session_lock); mutex_lock(&dp->session_lock); if (!dp->power_on || !dp->core_initialized) { if (!dp_display_state_is(DP_STATE_ENABLED)) { DP_DEBUG("Link already powered off, return\n"); dp_display_state_show("[not enabled]"); goto end; } if (!dp_display_state_is(DP_STATE_READY)) { dp_display_state_show("[not ready]"); goto end; goto end; } } dp_display_stream_disable(dp, dp_panel); dp_display_stream_disable(dp, dp_panel); dp_display_update_dsc_resources(dp, dp_panel, false); dp_display_update_dsc_resources(dp, dp_panel, false); dp->hdcp_abort = false; dp_display_state_remove(DP_STATE_HDCP_ABORTED); for (i = DP_STREAM_0; i < DP_STREAM_MAX; i++) { for (i = DP_STREAM_0; i < DP_STREAM_MAX; i++) { if (dp->active_panels[i]) { if (dp->active_panels[i]) { if (status->hdcp_state != HDCP_STATE_AUTHENTICATED) if (status->hdcp_state != HDCP_STATE_AUTHENTICATED) Loading Loading @@ -1877,11 +1969,11 @@ static int dp_display_unprepare(struct dp_display *dp_display, void *panel) dp->debug->psm_enabled = true; dp->debug->psm_enabled = true; dp->ctrl->off(dp->ctrl); dp->ctrl->off(dp->ctrl); dp_display_host_early_deinit(dp); dp_display_host_unready(dp); dp_display_host_deinit(dp); dp_display_host_deinit(dp); } } dp->power_on = false; dp_display_state_remove(DP_STATE_ENABLED); dp->aux->state = DP_STATE_CTRL_POWERED_OFF; dp->aux->state = DP_STATE_CTRL_POWERED_OFF; complete_all(&dp->notification_comp); complete_all(&dp->notification_comp); Loading Loading @@ -2621,7 +2713,6 @@ static int dp_display_probe(struct platform_device *pdev) dp->name = "drm_dp"; dp->name = "drm_dp"; memset(&dp->mst, 0, sizeof(dp->mst)); memset(&dp->mst, 0, sizeof(dp->mst)); atomic_set(&dp->aborted, 0); rc = dp_display_init_aux_switch(dp); rc = dp_display_init_aux_switch(dp); if (rc) { if (rc) { Loading Loading @@ -2758,7 +2849,7 @@ static int dp_pm_prepare(struct device *dev) dp_display_set_mst_state(g_dp_display, PM_SUSPEND); dp_display_set_mst_state(g_dp_display, PM_SUSPEND); dp->suspended = true; dp_display_state_add(DP_STATE_SUSPENDED); return 0; return 0; } } Loading @@ -2770,7 +2861,7 @@ static void dp_pm_complete(struct device *dev) dp_display_set_mst_state(g_dp_display, PM_DEFAULT); dp_display_set_mst_state(g_dp_display, PM_DEFAULT); dp->suspended = false; dp_display_state_remove(DP_STATE_SUSPENDED); } } static const struct dev_pm_ops dp_pm_ops = { static const struct dev_pm_ops dp_pm_ops = { Loading