From 04e88e68eedf67f5a6e4554f717917605121bf48 Mon Sep 17 00:00:00 2001 From: Aravind Venkateswaran Date: Thu, 4 May 2017 14:23:50 -0700 Subject: [PATCH] msm: mdss: dp: fix handling of device shutdown with cable connected When the source is powered off with an external sink connected, it will result in a call to blank and power off the source. In the current implementation, sink is not transitioned to D3 power mode prior to turning off the source. This can result in the sink reporting signal lock failures as the source if powered off, resulting in an HPD IRQ interrupt. If this interrupt is handled after the DP controller is powered off, it can lead to unclocked register accesses. Fix this by ensuring that sink is powered off prior to powering off the source. In addition, ensure that no more attention events are handled once the DP controller is powered off. Change-Id: I08558229f7c3e603904527de58a39039b3d7615e Signed-off-by: Aravind Venkateswaran Signed-off-by: Padmanabhan Komanduru --- drivers/video/fbdev/msm/mdss_dp.c | 48 +++++++++++++++------------ drivers/video/fbdev/msm/mdss_dp.h | 6 ---- drivers/video/fbdev/msm/mdss_dp_aux.c | 9 ----- 3 files changed, 27 insertions(+), 36 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c index 4c6a5e73406b..bc325a91a9bf 100644 --- a/drivers/video/fbdev/msm/mdss_dp.c +++ b/drivers/video/fbdev/msm/mdss_dp.c @@ -68,6 +68,7 @@ static int mdss_dp_process_phy_test_pattern_request( struct mdss_dp_drv_pdata *dp); static int mdss_dp_send_audio_notification( struct mdss_dp_drv_pdata *dp, int val); +static void mdss_dp_reset_sw_state(struct mdss_dp_drv_pdata *dp); static inline void mdss_dp_reset_sink_count(struct mdss_dp_drv_pdata *dp) { @@ -1489,7 +1490,12 @@ static int mdss_dp_setup_main_link(struct mdss_dp_drv_pdata *dp, bool train) pr_debug("enter\n"); mdss_dp_mainlink_ctrl(&dp->ctrl_io, true); - mdss_dp_aux_set_sink_power_state(dp, SINK_POWER_ON); + ret = mdss_dp_aux_send_psm_request(dp, false); + if (ret) { + pr_err("Failed to exit low power mode, rc=%d\n", ret); + goto end; + } + reinit_completion(&dp->video_comp); if (mdss_dp_is_phy_test_pattern_requested(dp)) @@ -1576,15 +1582,6 @@ static int mdss_dp_on_irq(struct mdss_dp_drv_pdata *dp_drv, bool lt_needed) dp_drv->power_on = true; - if (dp_drv->psm_enabled) { - ret = mdss_dp_aux_send_psm_request(dp_drv, false); - if (ret) { - pr_err("Failed to exit low power mode, rc=%d\n", - ret); - goto exit_loop; - } - } - ret = mdss_dp_setup_main_link(dp_drv, lt_needed); exit_loop: @@ -1653,15 +1650,6 @@ int mdss_dp_on_hpd(struct mdss_dp_drv_pdata *dp_drv) mdss_dp_configure_source_params(dp_drv, ln_map); - if (dp_drv->psm_enabled) { - ret = mdss_dp_aux_send_psm_request(dp_drv, false); - if (ret) { - pr_err("Failed to exit low power mode, rc=%d\n", ret); - goto exit; - } - } - - link_training: dp_drv->power_on = true; @@ -2989,6 +2977,7 @@ static int mdss_dp_sysfs_create(struct mdss_dp_drv_pdata *dp, static void mdss_dp_mainlink_push_idle(struct mdss_panel_data *pdata) { + bool cable_connected; struct mdss_dp_drv_pdata *dp_drv = NULL; const int idle_pattern_completion_timeout_ms = 3 * HZ / 100; @@ -3009,6 +2998,14 @@ static void mdss_dp_mainlink_push_idle(struct mdss_panel_data *pdata) return; } + /* power down the sink if cable is still connected */ + mutex_lock(&dp_drv->attention_lock); + cable_connected = dp_drv->cable_connected; + mutex_unlock(&dp_drv->attention_lock); + if (cable_connected && dp_drv->alt_mode.dp_status.hpd_high) { + if (mdss_dp_aux_send_psm_request(dp_drv, true)) + pr_err("Failed to enter low power mode\n"); + } 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, @@ -3129,6 +3126,10 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata, pr_err("DP Controller not powered on\n"); break; } + if (!atomic_read(&dp->notification_pending)) { + pr_debug("blank when cable is connected\n"); + kthread_park(dp->ev_thread); + } if (dp_is_hdcp_enabled(dp)) { dp->hdcp_status = HDCP_STATE_INACTIVE; @@ -3168,8 +3169,10 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata, * when you connect DP sink while the * device is in suspend state. */ - if ((!dp->power_on) && (dp->dp_initialized)) + if ((!dp->power_on) && (dp->dp_initialized)) { rc = mdss_dp_host_deinit(dp); + kthread_park(dp->ev_thread); + } /* * For DP suspend/resume use case, CHECK_PARAMS is @@ -3181,8 +3184,11 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata, dp->suspend_vic = dp->vic; break; case MDSS_EVENT_RESUME: - if (dp->suspend_vic != HDMI_VFRMT_UNKNOWN) + if (dp->suspend_vic != HDMI_VFRMT_UNKNOWN) { dp_init_panel_info(dp, dp->suspend_vic); + mdss_dp_reset_sw_state(dp); + kthread_unpark(dp->ev_thread); + } break; default: pr_debug("unhandled event=%d\n", event); diff --git a/drivers/video/fbdev/msm/mdss_dp.h b/drivers/video/fbdev/msm/mdss_dp.h index afa8e3db590f..983f5e34a515 100644 --- a/drivers/video/fbdev/msm/mdss_dp.h +++ b/drivers/video/fbdev/msm/mdss_dp.h @@ -218,10 +218,6 @@ struct dp_alt_mode { #define ST_SEND_VIDEO BIT(7) #define ST_PUSH_IDLE BIT(8) -/* sink power state */ -#define SINK_POWER_ON 1 -#define SINK_POWER_OFF 2 - #define DP_LINK_RATE_162 6 /* 1.62G = 270M * 6 */ #define DP_LINK_RATE_270 10 /* 2.70G = 270M * 10 */ #define DP_LINK_RATE_540 20 /* 5.40G = 270M * 20 */ @@ -1181,11 +1177,9 @@ void dp_aux_native_handler(struct mdss_dp_drv_pdata *dp, u32 isr); void mdss_dp_aux_init(struct mdss_dp_drv_pdata *ep); void mdss_dp_fill_link_cfg(struct mdss_dp_drv_pdata *ep); -void mdss_dp_sink_power_down(struct mdss_dp_drv_pdata *ep); void mdss_dp_lane_power_ctrl(struct mdss_dp_drv_pdata *ep, int up); void mdss_dp_config_ctrl(struct mdss_dp_drv_pdata *ep); char mdss_dp_gen_link_clk(struct mdss_dp_drv_pdata *dp); -int mdss_dp_aux_set_sink_power_state(struct mdss_dp_drv_pdata *ep, char state); int mdss_dp_aux_send_psm_request(struct mdss_dp_drv_pdata *dp, bool enable); void mdss_dp_aux_send_test_response(struct mdss_dp_drv_pdata *ep); void *mdss_dp_get_hdcp_data(struct device *dev); diff --git a/drivers/video/fbdev/msm/mdss_dp_aux.c b/drivers/video/fbdev/msm/mdss_dp_aux.c index c0632e8241a0..86946adfeeb0 100644 --- a/drivers/video/fbdev/msm/mdss_dp_aux.c +++ b/drivers/video/fbdev/msm/mdss_dp_aux.c @@ -2556,15 +2556,6 @@ static int dp_link_rate_down_shift(struct mdss_dp_drv_pdata *ep) return ret; } -int mdss_dp_aux_set_sink_power_state(struct mdss_dp_drv_pdata *ep, char state) -{ - int ret; - - ret = dp_aux_write_buf(ep, 0x600, &state, 1, 0); - pr_debug("state=%d ret=%d\n", state, ret); - return ret; -} - static void dp_clear_training_pattern(struct mdss_dp_drv_pdata *ep) { int usleep_time;