diff options
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_ctrl.c | 29 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_ctrl.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_display.c | 113 |
3 files changed, 63 insertions, 80 deletions
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index 89ab74efbe92..7b18f331829c 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -1925,6 +1925,35 @@ int dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl) return ret; } +int dp_ctrl_off_link(struct dp_ctrl *dp_ctrl) +{ + struct dp_ctrl_private *ctrl; + struct dp_io *dp_io; + struct phy *phy; + int ret; + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + dp_io = &ctrl->parser->io; + phy = dp_io->phy; + + dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false); + + ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, false); + if (ret) { + DRM_ERROR("Failed to disable link clocks. ret=%d\n", ret); + } + + DRM_DEBUG_DP("Before, phy=%p init_count=%d power_on=%d\n", + phy, phy->init_count, phy->power_count); + + phy_power_off(phy); + + DRM_DEBUG_DP("After, phy=%p init_count=%d power_on=%d\n", + phy, phy->init_count, phy->power_count); + + return ret; +} + int dp_ctrl_off(struct dp_ctrl *dp_ctrl) { struct dp_ctrl_private *ctrl; diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h b/drivers/gpu/drm/msm/dp/dp_ctrl.h index 4dff44dfa9bd..0745fde01b45 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.h +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h @@ -23,6 +23,7 @@ struct dp_ctrl { int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl); int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl); int dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl); +int dp_ctrl_off_link(struct dp_ctrl *dp_ctrl); int dp_ctrl_off(struct dp_ctrl *dp_ctrl); void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl); void dp_ctrl_isr(struct dp_ctrl *dp_ctrl); diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 2119d708eb9f..b37bc1c74d88 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -41,7 +41,7 @@ enum { /* event thread connection state */ enum { ST_DISCONNECTED, - ST_CONNECT_PENDING, + ST_MAINLINK_READY, ST_CONNECTED, ST_DISCONNECT_PENDING, ST_DISPLAY_OFF, @@ -56,14 +56,11 @@ enum { EV_IRQ_HPD_INT, EV_HPD_UNPLUG_INT, EV_USER_NOTIFICATION, - EV_CONNECT_PENDING_TIMEOUT, - EV_DISCONNECT_PENDING_TIMEOUT, }; #define EVENT_TIMEOUT (HZ/10) /* 100ms */ #define DP_EVENT_Q_MAX 8 -#define DP_TIMEOUT_5_SECOND (5000/EVENT_TIMEOUT) #define DP_TIMEOUT_NONE 0 #define WAIT_FOR_RESUME_TIMEOUT_JIFFIES (HZ / 2) @@ -474,6 +471,11 @@ static int dp_display_usbpd_configure_cb(struct device *dev) static int dp_display_usbpd_disconnect_cb(struct device *dev) { + return 0; +} + +static int dp_display_notify_disconnect(struct device *dev) +{ struct dp_display_private *dp = dev_get_dp_display_private(dev); dp_add_event(dp, EV_USER_NOTIFICATION, false, 0); @@ -501,7 +503,7 @@ static int dp_display_handle_port_ststus_changed(struct dp_display_private *dp) } } else { if (dp->hpd_state == ST_DISCONNECTED) { - dp->hpd_state = ST_CONNECT_PENDING; + dp->hpd_state = ST_MAINLINK_READY; rc = dp_display_process_hpd_high(dp); if (rc) dp->hpd_state = ST_DISCONNECTED; @@ -558,7 +560,6 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) { struct dp_usbpd *hpd = dp->usbpd; u32 state; - u32 tout = DP_TIMEOUT_5_SECOND; int ret; if (!hpd) @@ -575,7 +576,7 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) return 0; } - if (state == ST_CONNECT_PENDING || state == ST_CONNECTED) { + if (state == ST_MAINLINK_READY || state == ST_CONNECTED) { mutex_unlock(&dp->event_mutex); return 0; } @@ -587,14 +588,11 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) return 0; } - dp->hpd_state = ST_CONNECT_PENDING; - ret = dp_display_usbpd_configure_cb(&dp->pdev->dev); if (ret) { /* link train failed */ dp->hpd_state = ST_DISCONNECTED; } else { - /* start sentinel checking in case of missing uevent */ - dp_add_event(dp, EV_CONNECT_PENDING_TIMEOUT, 0, tout); + dp->hpd_state = ST_MAINLINK_READY; } /* enable HDP irq_hpd/replug interrupt */ @@ -612,23 +610,6 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) static int dp_display_enable(struct dp_display_private *dp, u32 data); static int dp_display_disable(struct dp_display_private *dp, u32 data); -static int dp_connect_pending_timeout(struct dp_display_private *dp, u32 data) -{ - u32 state; - - mutex_lock(&dp->event_mutex); - - state = dp->hpd_state; - if (state == ST_CONNECT_PENDING) { - dp->hpd_state = ST_CONNECTED; - drm_dbg_dp(dp->drm_dev, "type=%d\n", dp->dp_display.connector_type); - } - - mutex_unlock(&dp->event_mutex); - - return 0; -} - static void dp_display_handle_plugged_change(struct msm_dp *dp_display, bool plugged) { @@ -670,24 +651,21 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) if (dp->link->sink_count == 0) { dp_display_host_phy_exit(dp); } + dp_display_notify_disconnect(&dp->pdev->dev); mutex_unlock(&dp->event_mutex); return 0; - } - - if (state == ST_DISCONNECT_PENDING) { + } else if (state == ST_DISCONNECT_PENDING) { mutex_unlock(&dp->event_mutex); return 0; - } - - if (state == ST_CONNECT_PENDING) { - /* wait until CONNECTED */ - dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 1); /* delay = 1 */ + } else if (state == ST_MAINLINK_READY) { + dp_ctrl_off_link(dp->ctrl); + dp_display_host_phy_exit(dp); + dp->hpd_state = ST_DISCONNECTED; + dp_display_notify_disconnect(&dp->pdev->dev); mutex_unlock(&dp->event_mutex); return 0; } - dp->hpd_state = ST_DISCONNECT_PENDING; - /* disable HPD plug interrupts */ dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, false); @@ -695,10 +673,13 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) * We don't need separate work for disconnect as * connect/attention interrupts are disabled */ - dp_display_usbpd_disconnect_cb(&dp->pdev->dev); + dp_display_notify_disconnect(&dp->pdev->dev); - /* start sentinel checking in case of missing uevent */ - dp_add_event(dp, EV_DISCONNECT_PENDING_TIMEOUT, 0, DP_TIMEOUT_5_SECOND); + if (state == ST_DISPLAY_OFF) { + dp->hpd_state = ST_DISCONNECTED; + } else { + dp->hpd_state = ST_DISCONNECT_PENDING; + } /* signal the disconnect event early to ensure proper teardown */ dp_display_handle_plugged_change(&dp->dp_display, false); @@ -714,23 +695,6 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) return 0; } -static int dp_disconnect_pending_timeout(struct dp_display_private *dp, u32 data) -{ - u32 state; - - mutex_lock(&dp->event_mutex); - - state = dp->hpd_state; - if (state == ST_DISCONNECT_PENDING) { - dp->hpd_state = ST_DISCONNECTED; - drm_dbg_dp(dp->drm_dev, "type=%d\n", dp->dp_display.connector_type); - } - - mutex_unlock(&dp->event_mutex); - - return 0; -} - static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data) { u32 state; @@ -747,14 +711,7 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data) return 0; } - if (state == ST_CONNECT_PENDING) { - /* wait until ST_CONNECTED */ - dp_add_event(dp, EV_IRQ_HPD_INT, 0, 1); /* delay = 1 */ - mutex_unlock(&dp->event_mutex); - return 0; - } - - if (state == ST_CONNECT_PENDING || state == ST_DISCONNECT_PENDING) { + if (state == ST_MAINLINK_READY || state == ST_DISCONNECT_PENDING) { /* wait until ST_CONNECTED */ dp_add_event(dp, EV_IRQ_HPD_INT, 0, 1); /* delay = 1 */ mutex_unlock(&dp->event_mutex); @@ -1192,14 +1149,6 @@ static int hpd_event_thread(void *data) dp_display_send_hpd_notification(dp_priv, todo->data); break; - case EV_CONNECT_PENDING_TIMEOUT: - dp_connect_pending_timeout(dp_priv, - todo->data); - break; - case EV_DISCONNECT_PENDING_TIMEOUT: - dp_disconnect_pending_timeout(dp_priv, - todo->data); - break; default: break; } @@ -1242,8 +1191,6 @@ static irqreturn_t dp_display_irq_handler(int irq, void *dev_id) dp_add_event(dp, EV_HPD_PLUG_INT, 0, 0); if (hpd_isr_status & DP_DP_IRQ_HPD_INT_MASK) { - /* stop sentinel connect pending checking */ - dp_del_event(dp, EV_CONNECT_PENDING_TIMEOUT); dp_add_event(dp, EV_IRQ_HPD_INT, 0, 0); } @@ -1629,8 +1576,11 @@ void dp_bridge_enable(struct drm_bridge *drm_bridge) mutex_lock(&dp_display->event_mutex); - /* stop sentinel checking */ - dp_del_event(dp_display, EV_CONNECT_PENDING_TIMEOUT); + state = dp_display->hpd_state; + if (state != ST_DISPLAY_OFF && state != ST_MAINLINK_READY) { + mutex_unlock(&dp_display->event_mutex); + return; + } rc = dp_display_set_mode(dp, &dp_display->dp_mode); if (rc) { @@ -1694,8 +1644,11 @@ void dp_bridge_post_disable(struct drm_bridge *drm_bridge) mutex_lock(&dp_display->event_mutex); - /* stop sentinel checking */ - dp_del_event(dp_display, EV_DISCONNECT_PENDING_TIMEOUT); + state = dp_display->hpd_state; + if (state != ST_DISCONNECT_PENDING && state != ST_CONNECTED) { + mutex_unlock(&dp_display->event_mutex); + return; + } dp_display_disable(dp_display, 0); |