Connection state is set incorrectly happen at either failure of link train or cable plugged in while suspended. This patch fixes these problems. This patch also replace ST_SUSPEND_PENDING with ST_DISPLAY_OFF. Signed-off-by: Kuogee Hsieh <khsieh@xxxxxxxxxxxxxx> --- drivers/gpu/drm/msm/dp/dp_display.c | 52 ++++++++++++++--------------- drivers/gpu/drm/msm/dp/dp_panel.c | 5 +++ 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 431dff9de797..898c6cc1643a 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -45,7 +45,7 @@ enum { ST_CONNECT_PENDING, ST_CONNECTED, ST_DISCONNECT_PENDING, - ST_SUSPEND_PENDING, + ST_DISPLAY_OFF, ST_SUSPENDED, }; @@ -340,8 +340,6 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) } dp_add_event(dp, EV_USER_NOTIFICATION, true, 0); - - end: return rc; } @@ -489,7 +487,7 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) mutex_lock(&dp->event_mutex); state = atomic_read(&dp->hpd_state); - if (state == ST_SUSPEND_PENDING) { + if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) { mutex_unlock(&dp->event_mutex); return 0; } @@ -511,14 +509,14 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) hpd->hpd_high = 1; ret = dp_display_usbpd_configure_cb(&dp->pdev->dev); - if (ret) { /* failed */ + if (ret) { /* link train failed */ hpd->hpd_high = 0; atomic_set(&dp->hpd_state, ST_DISCONNECTED); + } else { + /* start sentinel checking in case of missing uevent */ + dp_add_event(dp, EV_CONNECT_PENDING_TIMEOUT, 0, tout); } - /* start sanity checking */ - dp_add_event(dp, EV_CONNECT_PENDING_TIMEOUT, 0, tout); - mutex_unlock(&dp->event_mutex); /* uevent will complete connection part */ @@ -563,10 +561,6 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) mutex_lock(&dp->event_mutex); state = atomic_read(&dp->hpd_state); - if (state == ST_SUSPEND_PENDING) { - mutex_unlock(&dp->event_mutex); - return 0; - } if (state == ST_DISCONNECT_PENDING || state == ST_DISCONNECTED) { mutex_unlock(&dp->event_mutex); @@ -594,7 +588,7 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) */ dp_display_usbpd_disconnect_cb(&dp->pdev->dev); - /* start sanity checking */ + /* start sentinel checking in case of missing uevent */ dp_add_event(dp, EV_DISCONNECT_PENDING_TIMEOUT, 0, DP_TIMEOUT_5_SECOND); /* signal the disconnect event early to ensure proper teardown */ @@ -634,7 +628,7 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data) /* irq_hpd can happen at either connected or disconnected state */ state = atomic_read(&dp->hpd_state); - if (state == ST_SUSPEND_PENDING) { + if (state == ST_DISPLAY_OFF) { mutex_unlock(&dp->event_mutex); return 0; } @@ -1067,7 +1061,7 @@ static irqreturn_t dp_display_irq_handler(int irq, void *dev_id) } if (hpd_isr_status & DP_DP_IRQ_HPD_INT_MASK) { - /* delete connect pending event first */ + /* delete sentinel connect pending checking */ dp_del_event(dp, EV_CONNECT_PENDING_TIMEOUT); dp_add_event(dp, EV_IRQ_HPD_INT, 0, 0); } @@ -1186,19 +1180,19 @@ static int dp_pm_resume(struct device *dev) dp = container_of(dp_display, struct dp_display_private, dp_display); + /* start from dis connection state */ + atomic_set(&dp->hpd_state, ST_DISCONNECTED); + dp_display_host_init(dp); dp_catalog_ctrl_hpd_config(dp->catalog); status = dp_catalog_hpd_get_state_status(dp->catalog); - if (status) { + if (status) dp->dp_display.is_connected = true; - } else { + else dp->dp_display.is_connected = false; - /* make sure next resume host_init be called */ - dp->core_initialized = false; - } return 0; } @@ -1214,6 +1208,9 @@ static int dp_pm_suspend(struct device *dev) if (dp_display->power_on == true) dp_display_disable(dp, 0); + /* host_init will be called at pm_resume */ + dp->core_initialized = false; + atomic_set(&dp->hpd_state, ST_SUSPENDED); return 0; @@ -1343,6 +1340,9 @@ int msm_dp_display_enable(struct msm_dp *dp, struct drm_encoder *encoder) mutex_lock(&dp_display->event_mutex); + /* delete sentinel checking */ + dp_del_event(dp_display, EV_CONNECT_PENDING_TIMEOUT); + rc = dp_display_set_mode(dp, &dp_display->dp_mode); if (rc) { DRM_ERROR("Failed to perform a mode set, rc=%d\n", rc); @@ -1368,9 +1368,8 @@ int msm_dp_display_enable(struct msm_dp *dp, struct drm_encoder *encoder) dp_display_unprepare(dp); } - dp_del_event(dp_display, EV_CONNECT_PENDING_TIMEOUT); - - if (state == ST_SUSPEND_PENDING) + /* manual kick off plug event to train link */ + if (state == ST_DISPLAY_OFF) dp_add_event(dp_display, EV_IRQ_HPD_INT, 0, 0); /* completed connection */ @@ -1402,20 +1401,21 @@ int msm_dp_display_disable(struct msm_dp *dp, struct drm_encoder *encoder) mutex_lock(&dp_display->event_mutex); + /* delete sentinel checking */ + dp_del_event(dp_display, EV_DISCONNECT_PENDING_TIMEOUT); + dp_display_disable(dp_display, 0); rc = dp_display_unprepare(dp); if (rc) DRM_ERROR("DP display unprepare failed, rc=%d\n", rc); - dp_del_event(dp_display, EV_DISCONNECT_PENDING_TIMEOUT); - state = atomic_read(&dp_display->hpd_state); if (state == ST_DISCONNECT_PENDING) { /* completed disconnection */ atomic_set(&dp_display->hpd_state, ST_DISCONNECTED); } else { - atomic_set(&dp_display->hpd_state, ST_SUSPEND_PENDING); + atomic_set(&dp_display->hpd_state, ST_DISPLAY_OFF); } mutex_unlock(&dp_display->event_mutex); diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c index 18cec4fc5e0b..1b7a20dc2d8e 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.c +++ b/drivers/gpu/drm/msm/dp/dp_panel.c @@ -196,6 +196,11 @@ int dp_panel_read_sink_caps(struct dp_panel *dp_panel, &panel->aux->ddc); if (!dp_panel->edid) { DRM_ERROR("panel edid read failed\n"); + /* check edid read fail is due to unplug */ + if (!dp_catalog_hpd_get_state_status(panel->catalog)) { + rc = -ETIMEDOUT; + goto end; + } /* fail safe edid */ mutex_lock(&connector->dev->mode_config.mutex); base-commit: 6fa6fd6a3e2cb76f7d54220daa1266a94c13bc4d -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project