From 9ec9267905e8e712eba27c106c96e78c6da3e56f Mon Sep 17 00:00:00 2001
From: Chandan Uddaraju <chandanu@codeaurora.org>
Date: Wed, 17 Aug 2016 11:52:41 -0700
Subject: [PATCH] mdss: display-port: fix Display-port disable sequence

Fix the OFF path for display-port driver when cable is
disconnected. Check for link clock status before accessing
any of the mainlink registers. Use common mutex for
DP_ON and DP_OFF sequence. Remove the resource vote
when PLL is diabled.

Change-Id: I9b81f79043b4ea7355b99ba9d8347d79bed10153
Signed-off-by: Chandan Uddaraju <chandanu@codeaurora.org>
---
 .../clk/msm/mdss/mdss-dp-pll-cobalt-util.c    |  2 +
 drivers/video/fbdev/msm/mdss_dp.c             | 49 +++++++++----------
 drivers/video/fbdev/msm/mdss_dp.h             |  2 +-
 drivers/video/fbdev/msm/mdss_dp_aux.c         | 12 +----
 4 files changed, 28 insertions(+), 37 deletions(-)

diff --git a/drivers/clk/msm/mdss/mdss-dp-pll-cobalt-util.c b/drivers/clk/msm/mdss/mdss-dp-pll-cobalt-util.c
index 74032aba22bc..123a5ae09fa8 100644
--- a/drivers/clk/msm/mdss/mdss-dp-pll-cobalt-util.c
+++ b/drivers/clk/msm/mdss/mdss-dp-pll-cobalt-util.c
@@ -583,8 +583,10 @@ int dp_vco_prepare(struct clk *c)
 		mdss_pll_resource_enable(dp_pll_res, false);
 		pr_err("ndx=%d failed to enable dsi pll\n",
 					dp_pll_res->index);
+		goto error;
 	}
 
+	mdss_pll_resource_enable(dp_pll_res, false);
 error:
 	return rc;
 }
diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c
index f7261d4e3fa4..140836f9e89e 100644
--- a/drivers/video/fbdev/msm/mdss_dp.c
+++ b/drivers/video/fbdev/msm/mdss_dp.c
@@ -895,7 +895,7 @@ int mdss_dp_on(struct mdss_panel_data *pdata)
 			panel_data);
 
 	/* wait until link training is completed */
-	mutex_lock(&dp_drv->host_mutex);
+	mutex_lock(&dp_drv->train_mutex);
 
 	pr_debug("Enter++ cont_splash=%d\n", dp_drv->cont_splash);
 	/* Default lane mapping */
@@ -908,7 +908,7 @@ int mdss_dp_on(struct mdss_panel_data *pdata)
 		ret = mdss_dp_clk_ctrl(dp_drv, DP_CORE_PM, true);
 		if (ret) {
 			pr_err("Unabled to start core clocks\n");
-			return ret;
+			goto exit;
 		}
 		mdss_dp_hpd_configure(&dp_drv->ctrl_io, true);
 
@@ -941,7 +941,8 @@ int mdss_dp_on(struct mdss_panel_data *pdata)
 			       dp_drv->link_rate, dp_drv->dpcd.max_link_rate);
 		if (!dp_drv->link_rate) {
 			pr_err("Unable to configure required link rate\n");
-			return -EINVAL;
+			ret = -EINVAL;
+			goto exit;
 		}
 
 		pr_debug("link_rate = 0x%x\n", dp_drv->link_rate);
@@ -955,9 +956,8 @@ int mdss_dp_on(struct mdss_panel_data *pdata)
 
 		ret = mdss_dp_clk_ctrl(dp_drv, DP_CTRL_PM, true);
 		if (ret) {
-			mdss_dp_clk_ctrl(dp_drv, DP_CORE_PM, false);
 			pr_err("Unabled to start link clocks\n");
-			return ret;
+			goto exit;
 		}
 
 		mdss_dp_mainlink_reset(&dp_drv->ctrl_io);
@@ -985,17 +985,16 @@ int mdss_dp_on(struct mdss_panel_data *pdata)
 		pr_debug("mainlink ready\n");
 
 	dp_drv->power_on = true;
-
-	mutex_unlock(&dp_drv->host_mutex);
 	pr_debug("End-\n");
 
+exit:
+	mutex_unlock(&dp_drv->train_mutex);
 	return ret;
 }
 
 int mdss_dp_off(struct mdss_panel_data *pdata)
 {
 	struct mdss_dp_drv_pdata *dp_drv = NULL;
-	int ret = 0;
 
 	dp_drv = container_of(pdata, struct mdss_dp_drv_pdata,
 				panel_data);
@@ -1009,34 +1008,31 @@ int mdss_dp_off(struct mdss_panel_data *pdata)
 	mutex_lock(&dp_drv->train_mutex);
 
 	reinit_completion(&dp_drv->idle_comp);
-	mdss_dp_state_ctrl(&dp_drv->ctrl_io, ST_PUSH_IDLE);
-
-	ret = wait_for_completion_timeout(&dp_drv->idle_comp,
-						msecs_to_jiffies(100));
-	if (ret == 0)
-		pr_err("idle pattern timedout\n");
 
 	mdss_dp_state_ctrl(&dp_drv->ctrl_io, 0);
 
-	mdss_dp_irq_disable(dp_drv);
+	if (dp_drv->link_clks_on)
+		mdss_dp_mainlink_ctrl(&dp_drv->ctrl_io, false);
 
-	mdss_dp_mainlink_reset(&dp_drv->ctrl_io);
-	mdss_dp_mainlink_ctrl(&dp_drv->ctrl_io, false);
+	mdss_dp_aux_ctrl(&dp_drv->ctrl_io, false);
+
+	mdss_dp_irq_disable(dp_drv);
 
 	mdss_dp_config_gpios(dp_drv, false);
 	mdss_dp_pinctrl_set_state(dp_drv, false);
 
-	mdss_dp_aux_ctrl(&dp_drv->ctrl_io, false);
+	/* Make sure DP is disabled before clk disable */
+	wmb();
 	mdss_dp_clk_ctrl(dp_drv, DP_CTRL_PM, false);
 	mdss_dp_clk_ctrl(dp_drv, DP_CORE_PM, false);
 
 	mdss_dp_regulator_ctrl(dp_drv, false);
-
-	pr_debug("End--: state_ctrl=%x\n",
-				dp_read(dp_drv->base + DP_STATE_CTRL));
+	dp_drv->dp_initialized = false;
 
 	dp_drv->power_on = false;
 	mutex_unlock(&dp_drv->train_mutex);
+	pr_debug("DP off done\n");
+
 	return 0;
 }
 
@@ -1124,6 +1120,10 @@ static int mdss_dp_host_init(struct mdss_panel_data *pdata)
 	dp_drv = container_of(pdata, struct mdss_dp_drv_pdata,
 			panel_data);
 
+	if (dp_drv->dp_initialized) {
+		pr_err("%s: host init done already\n", __func__);
+		return 0;
+	}
 	ret = mdss_dp_regulator_ctrl(dp_drv, true);
 	if (ret) {
 		pr_err("failed to enable regulators\n");
@@ -1170,7 +1170,7 @@ static int mdss_dp_host_init(struct mdss_panel_data *pdata)
 	}
 
 	mdss_dp_send_cable_notification(dp_drv, true);
-
+	dp_drv->dp_initialized = true;
 	return ret;
 
 edid_error:
@@ -1781,8 +1781,8 @@ static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd,
 		if (cmd_type == SVDM_CMD_TYPE_INITIATOR) {
 			pr_debug("Attention. cmd_type=%d\n",
 			       cmd_type);
-			if (!dp_drv->alt_mode.current_state
-						== ENTER_MODE_DONE) {
+			if (!(dp_drv->alt_mode.current_state
+					== ENTER_MODE_DONE)) {
 				pr_debug("sending discover_mode\n");
 				dp_send_events(dp_drv, EV_USBPD_DISCOVER_MODES);
 				break;
@@ -1909,7 +1909,6 @@ static int mdss_dp_probe(struct platform_device *pdev)
 	dp_drv->mask1 = EDP_INTR_MASK1;
 	dp_drv->mask2 = EDP_INTR_MASK2;
 	mutex_init(&dp_drv->emutex);
-	mutex_init(&dp_drv->host_mutex);
 	mutex_init(&dp_drv->pd_msg_mutex);
 	mutex_init(&dp_drv->hdcp_mutex);
 	spin_lock_init(&dp_drv->lock);
diff --git a/drivers/video/fbdev/msm/mdss_dp.h b/drivers/video/fbdev/msm/mdss_dp.h
index d36c1e4ffce5..e29440746478 100644
--- a/drivers/video/fbdev/msm/mdss_dp.h
+++ b/drivers/video/fbdev/msm/mdss_dp.h
@@ -337,6 +337,7 @@ struct mdss_dp_drv_pdata {
 	struct usbpd *pd;
 	struct usbpd_svid_handler svid_handler;
 	struct dp_alt_mode alt_mode;
+	bool dp_initialized;
 
 	struct mutex emutex;
 	int clk_cnt;
@@ -398,7 +399,6 @@ struct mdss_dp_drv_pdata {
 	struct completion video_comp;
 	struct mutex aux_mutex;
 	struct mutex train_mutex;
-	struct mutex host_mutex;
 	struct mutex pd_msg_mutex;
 	struct mutex hdcp_mutex;
 	bool cable_connected;
diff --git a/drivers/video/fbdev/msm/mdss_dp_aux.c b/drivers/video/fbdev/msm/mdss_dp_aux.c
index aea342ac90db..fc24bb53a61c 100644
--- a/drivers/video/fbdev/msm/mdss_dp_aux.c
+++ b/drivers/video/fbdev/msm/mdss_dp_aux.c
@@ -1312,7 +1312,7 @@ static void dp_clear_training_pattern(struct mdss_dp_drv_pdata *ep)
 	usleep_range(usleep_time, usleep_time);
 }
 
-static int dp_aux_link_train(struct mdss_dp_drv_pdata *dp)
+int mdss_dp_link_train(struct mdss_dp_drv_pdata *dp)
 {
 	int ret = 0;
 	int usleep_time;
@@ -1412,16 +1412,6 @@ void mdss_dp_fill_link_cfg(struct mdss_dp_drv_pdata *ep)
 
 }
 
-int mdss_dp_link_train(struct mdss_dp_drv_pdata *ep)
-{
-	int ret;
-
-	mutex_lock(&ep->train_mutex);
-	ret = dp_aux_link_train(ep);
-	mutex_unlock(&ep->train_mutex);
-	return ret;
-}
-
 void mdss_dp_aux_init(struct mdss_dp_drv_pdata *ep)
 {
 	mutex_init(&ep->aux_mutex);