diff options
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_catalog.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_ctrl.c | 55 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_ctrl.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_display.c | 57 |
4 files changed, 101 insertions, 18 deletions
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c index b1a9b1b98f5f..f4f53f23e331 100644 --- a/drivers/gpu/drm/msm/dp/dp_catalog.c +++ b/drivers/gpu/drm/msm/dp/dp_catalog.c @@ -582,10 +582,9 @@ void dp_catalog_ctrl_hpd_config(struct dp_catalog *dp_catalog) u32 reftimer = dp_read_aux(catalog, REG_DP_DP_HPD_REFTIMER); - /* enable HPD interrupts */ + /* enable HPD plug and unplug interrupts */ dp_catalog_hpd_config_intr(dp_catalog, - DP_DP_HPD_PLUG_INT_MASK | DP_DP_IRQ_HPD_INT_MASK - | DP_DP_HPD_UNPLUG_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK, true); + DP_DP_HPD_PLUG_INT_MASK | DP_DP_HPD_UNPLUG_INT_MASK, true); /* Configure REFTIMER and enable it */ reftimer |= DP_DP_HPD_REFTIMER_ENABLE; diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index 1390f3547fde..2a8955ca70d1 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -1809,6 +1809,61 @@ end: return ret; } +int dp_ctrl_off_link_stream(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; + + /* set dongle to D3 (power off) mode */ + dp_link_psm_config(ctrl->link, &ctrl->panel->link_info, true); + + dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false); + + ret = dp_power_clk_enable(ctrl->power, DP_STREAM_PM, false); + if (ret) { + DRM_ERROR("Failed to disable pixel clocks. ret=%d\n", ret); + return ret; + } + + ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, false); + if (ret) { + DRM_ERROR("Failed to disable link clocks. ret=%d\n", ret); + return ret; + } + + phy_power_off(phy); + + /* aux channel down, reinit phy */ + phy_exit(phy); + phy_init(phy); + + DRM_DEBUG_DP("DP off link/stream done\n"); + return ret; +} + +void dp_ctrl_off_phy(struct dp_ctrl *dp_ctrl) +{ + struct dp_ctrl_private *ctrl; + struct dp_io *dp_io; + struct phy *phy; + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + dp_io = &ctrl->parser->io; + phy = dp_io->phy; + + dp_catalog_ctrl_reset(ctrl->catalog); + + phy_exit(phy); + + DRM_DEBUG_DP("DP off phy done\n"); +} + 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 a836bd358447..25e4f7512252 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.h +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h @@ -23,6 +23,8 @@ int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip, bool reset); void dp_ctrl_host_deinit(struct dp_ctrl *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); +void dp_ctrl_off_phy(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 1784e119269b..cdec0a367a2c 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -346,6 +346,12 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) dp->dp_display.max_pclk_khz = DP_MAX_PIXEL_CLK_KHZ; dp->dp_display.max_dp_lanes = dp->parser->max_dp_lanes; + /* + * set sink to normal operation mode -- D0 + * before dpcd read + */ + dp_link_psm_config(dp->link, &dp->panel->link_info, false); + dp_link_reset_phy_params_vx_px(dp->link); rc = dp_ctrl_on_link(dp->ctrl); if (rc) { @@ -414,11 +420,6 @@ static int dp_display_usbpd_configure_cb(struct device *dev) dp_display_host_init(dp, false); - /* - * set sink to normal operation mode -- D0 - * before dpcd read - */ - dp_link_psm_config(dp->link, &dp->panel->link_info, false); rc = dp_display_process_hpd_high(dp); end: return rc; @@ -579,6 +580,10 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) dp_add_event(dp, EV_CONNECT_PENDING_TIMEOUT, 0, tout); } + /* enable HDP irq_hpd/replug interrupt */ + dp_catalog_hpd_config_intr(dp->catalog, + DP_DP_IRQ_HPD_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK, true); + mutex_unlock(&dp->event_mutex); /* uevent will complete connection part */ @@ -628,7 +633,26 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) mutex_lock(&dp->event_mutex); state = dp->hpd_state; - if (state == ST_DISCONNECT_PENDING || state == ST_DISCONNECTED) { + + /* disable irq_hpd/replug interrupts */ + dp_catalog_hpd_config_intr(dp->catalog, + DP_DP_IRQ_HPD_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK, false); + + /* unplugged, no more irq_hpd handle */ + dp_del_event(dp, EV_IRQ_HPD_INT); + + if (state == ST_DISCONNECTED) { + /* triggered by irq_hdp with sink_count = 0 */ + if (dp->link->sink_count == 0) { + dp_ctrl_off_phy(dp->ctrl); + hpd->hpd_high = 0; + dp->core_initialized = false; + } + mutex_unlock(&dp->event_mutex); + return 0; + } + + if (state == ST_DISCONNECT_PENDING) { mutex_unlock(&dp->event_mutex); return 0; } @@ -642,9 +666,8 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) dp->hpd_state = ST_DISCONNECT_PENDING; - /* disable HPD plug interrupt until disconnect is done */ - dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK - | DP_DP_IRQ_HPD_INT_MASK, false); + /* disable HPD plug interrupts */ + dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, false); hpd->hpd_high = 0; @@ -660,8 +683,8 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) /* signal the disconnect event early to ensure proper teardown */ dp_display_handle_plugged_change(g_dp_display, false); - dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK | - DP_DP_IRQ_HPD_INT_MASK, true); + /* enable HDP plug interrupt to prepare for next plugin */ + dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, true); /* uevent will complete disconnection part */ mutex_unlock(&dp->event_mutex); @@ -692,7 +715,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 = dp->hpd_state; - if (state == ST_DISPLAY_OFF) { + if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) { mutex_unlock(&dp->event_mutex); return 0; } @@ -910,9 +933,13 @@ static int dp_display_disable(struct dp_display_private *dp, u32 data) dp_display->audio_enabled = false; - dp_ctrl_off(dp->ctrl); - - dp->core_initialized = false; + /* triggered by irq_hpd with sink_count = 0 */ + if (dp->link->sink_count == 0) { + dp_ctrl_off_link_stream(dp->ctrl); + } else { + dp_ctrl_off(dp->ctrl); + dp->core_initialized = false; + } dp_display->power_on = false; |