From 9cfbd570efaed48bd9bcce3de757f84186d419d6 Mon Sep 17 00:00:00 2001 From: Padmanabhan Komanduru Date: Fri, 9 Jun 2017 16:29:25 +0530 Subject: [PATCH] mdss: dp: check if sink device is connected before DP ON sequence During cases where device coming out of pm suspend and disconnecting the DP cable happens around the same time, it is possible that the DP ON sequence is triggered from userspace before the disconnect event is notified to the userspace. Add a check to make sure DP ON sequence is executed only when the sink is connected. Change-Id: I61d06e007358df75c5cedc26552422c7a8c8aa0b Signed-off-by: Padmanabhan Komanduru --- drivers/video/fbdev/msm/mdss_dp.c | 33 ++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c index a74bf6f60774..3758c4bdac7f 100644 --- a/drivers/video/fbdev/msm/mdss_dp.c +++ b/drivers/video/fbdev/msm/mdss_dp.c @@ -1674,6 +1674,8 @@ exit: int mdss_dp_on(struct mdss_panel_data *pdata) { struct mdss_dp_drv_pdata *dp_drv = NULL; + bool hpd; + int rc = 0; if (!pdata) { pr_err("Invalid input data\n"); @@ -1683,6 +1685,22 @@ int mdss_dp_on(struct mdss_panel_data *pdata) dp_drv = container_of(pdata, struct mdss_dp_drv_pdata, panel_data); + mutex_lock(&dp_drv->attention_lock); + hpd = dp_drv->cable_connected; + mutex_unlock(&dp_drv->attention_lock); + + /* In case of device coming out of PM_SUSPEND, there can be + * a corner case where the sink is turned off or the DP cable + * is disconnected almost at the same time as userspace triggering + * unblank. This can cause the UNBLANK call to be still triggered + * before the disconnect event is notified to the userspace. + * Avoid turning ON DP path in such cases. + */ + if (!hpd || !dp_drv->alt_mode.dp_status.hpd_high) { + pr_err("DP sink not connected\n"); + return -EINVAL; + } + /* * If the link already active, then nothing needs to be done here. * However, it is possible that the the power_on flag could be @@ -1707,8 +1725,11 @@ int mdss_dp_on(struct mdss_panel_data *pdata) * init/deinit during unrelated resume/suspend events, * add host initialization call before DP power-on. */ - if (!dp_drv->dp_initialized) - mdss_dp_host_init(pdata); + if (!dp_drv->dp_initialized) { + rc = mdss_dp_host_init(pdata); + if (rc < 0) + return rc; + } return mdss_dp_on_hpd(dp_drv); } @@ -1941,6 +1962,11 @@ static int mdss_dp_host_init(struct mdss_panel_data *pdata) } dp_drv->orientation = usbpd_get_plug_orientation(dp_drv->pd); + if (dp_drv->orientation == ORIENTATION_NONE) { + pr_err("DP cable might be disconnected\n"); + ret = -EINVAL; + goto orientation_error; + } dp_drv->aux_sel_gpio_output = 0; if (dp_drv->orientation == ORIENTATION_CC2) @@ -1981,8 +2007,9 @@ static int mdss_dp_host_init(struct mdss_panel_data *pdata) return 0; clk_error: - mdss_dp_regulator_ctrl(dp_drv, false); mdss_dp_config_gpios(dp_drv, false); +orientation_error: + mdss_dp_regulator_ctrl(dp_drv, false); vreg_error: return ret; }