diff options
| author | Chandan Uddaraju <chandanu@codeaurora.org> | 2016-10-09 17:18:28 -0700 |
|---|---|---|
| committer | Chandan Uddaraju <chandanu@codeaurora.org> | 2016-10-12 12:32:32 -0700 |
| commit | a9494a84ac704327ea77576869b7bc2f4de69629 (patch) | |
| tree | 6e8e60c34f06fcf76e9168f9b354feecf2f06f12 | |
| parent | 0410649f01f5725380f8f5ac601440810c051680 (diff) | |
mdss: displayport: fix shutdown sequence
It is recommended to ensure that the interface timing engine is on
when configuring the hardware to switch to "IDLE pattern" state
as part of the shutdown sequence. In addition, it is also preferred
to issue a global software reset of the controller to ensure that
it's state machine is reset for any subsequent connections.
This updated sequence fixes link training failures seen during
multiple connect/disconnect use-cases.
Change-Id: I1984c1fc8c3e4a5f9c818240ec7e0323a68bfe3b
Signed-off-by: Chandan Uddaraju <chandanu@codeaurora.org>
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_dp.c | 37 |
1 files changed, 34 insertions, 3 deletions
diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c index e8e9da0e928f..b4a96b211801 100644 --- a/drivers/video/fbdev/msm/mdss_dp.c +++ b/drivers/video/fbdev/msm/mdss_dp.c @@ -1157,23 +1157,46 @@ exit: return ret; } -int mdss_dp_off(struct mdss_panel_data *pdata) +static void mdss_dp_mainlink_off(struct mdss_panel_data *pdata) { struct mdss_dp_drv_pdata *dp_drv = NULL; + const int idle_pattern_completion_timeout_ms = 3 * HZ / 100; dp_drv = container_of(pdata, struct mdss_dp_drv_pdata, panel_data); if (!dp_drv) { pr_err("Invalid input data\n"); - return -EINVAL; + return; } - pr_debug("Entered++, cont_splash=%d\n", dp_drv->cont_splash); + pr_debug("Entered++\n"); /* wait until link training is completed */ mutex_lock(&dp_drv->train_mutex); reinit_completion(&dp_drv->idle_comp); mdss_dp_state_ctrl(&dp_drv->ctrl_io, ST_PUSH_IDLE); + if (!wait_for_completion_timeout(&dp_drv->idle_comp, + idle_pattern_completion_timeout_ms)) + pr_warn("PUSH_IDLE pattern timedout\n"); + + mutex_unlock(&dp_drv->train_mutex); + pr_debug("mainlink off done\n"); +} + +int mdss_dp_off(struct mdss_panel_data *pdata) +{ + struct mdss_dp_drv_pdata *dp_drv = NULL; + + dp_drv = container_of(pdata, struct mdss_dp_drv_pdata, + panel_data); + if (!dp_drv) { + pr_err("Invalid input data\n"); + return -EINVAL; + } + pr_debug("Entered++, cont_splash=%d\n", dp_drv->cont_splash); + + /* wait until link training is completed */ + mutex_lock(&dp_drv->train_mutex); if (dp_drv->link_clks_on) mdss_dp_mainlink_ctrl(&dp_drv->ctrl_io, false); @@ -1187,6 +1210,13 @@ int mdss_dp_off(struct mdss_panel_data *pdata) mdss_dp_config_gpios(dp_drv, false); mdss_dp_pinctrl_set_state(dp_drv, false); + /* + * The global reset will need DP link ralated clocks to be + * running. Add the global reset just before disabling the + * link clocks and core clocks. + */ + mdss_dp_ctrl_reset(&dp_drv->ctrl_io); + /* Make sure DP is disabled before clk disable */ wmb(); mdss_dp_clk_ctrl(dp_drv, DP_CTRL_PM, false); @@ -1640,6 +1670,7 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata, case MDSS_EVENT_BLANK: if (ops && ops->off) ops->off(dp->hdcp_data); + mdss_dp_mainlink_off(pdata); break; case MDSS_EVENT_FB_REGISTERED: fbi = (struct fb_info *)arg; |
