summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChandan Uddaraju <chandanu@codeaurora.org>2016-10-09 17:18:28 -0700
committerChandan Uddaraju <chandanu@codeaurora.org>2016-10-12 12:32:32 -0700
commita9494a84ac704327ea77576869b7bc2f4de69629 (patch)
tree6e8e60c34f06fcf76e9168f9b354feecf2f06f12
parent0410649f01f5725380f8f5ac601440810c051680 (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.c37
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;