X-Git-Url: http://git.monstr.eu/?a=blobdiff_plain;f=drivers%2Fgpu%2Fdrm%2Fmsm%2Fdp%2Fdp_display.c;h=051c1be1de7ec9fda0451fba8d86e8aff6666834;hb=f591dbb5fb8c;hp=5a39da6e1eaf2779a2944a81490e22f8bc0374d2;hpb=81aa0968b7ea6dbabcdcda37dc8434dca6e1565b;p=linux-2.6-microblaze.git diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 5a39da6e1eaf..051c1be1de7e 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -178,6 +178,15 @@ static int dp_del_event(struct dp_display_private *dp_priv, u32 event) return 0; } +void dp_display_signal_audio_start(struct msm_dp *dp_display) +{ + struct dp_display_private *dp; + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + reinit_completion(&dp->audio_comp); +} + void dp_display_signal_audio_complete(struct msm_dp *dp_display) { struct dp_display_private *dp; @@ -199,10 +208,6 @@ static int dp_display_bind(struct device *dev, struct device *master, dp = container_of(g_dp_display, struct dp_display_private, dp_display); - if (!dp) { - DRM_ERROR("DP driver bind failed. Invalid driver data\n"); - return -EINVAL; - } dp->dp_display.drm_dev = drm; priv = drm->dev_private; @@ -243,10 +248,6 @@ static void dp_display_unbind(struct device *dev, struct device *master, dp = container_of(g_dp_display, struct dp_display_private, dp_display); - if (!dp) { - DRM_ERROR("Invalid DP driver data\n"); - return; - } dp_power_client_deinit(dp->power); dp_aux_unregister(dp->aux); @@ -337,6 +338,12 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) dp->dp_display.max_pclk_khz = DP_MAX_PIXEL_CLK_KHZ; dp->dp_display.max_dp_lanes = dp->parser->max_dp_lanes; + /* + * set sink to normal operation mode -- D0 + * before dpcd read + */ + dp_link_psm_config(dp->link, &dp->panel->link_info, false); + dp_link_reset_phy_params_vx_px(dp->link); rc = dp_ctrl_on_link(dp->ctrl); if (rc) { @@ -397,19 +404,9 @@ static int dp_display_usbpd_configure_cb(struct device *dev) dp = container_of(g_dp_display, struct dp_display_private, dp_display); - if (!dp) { - DRM_ERROR("no driver data found\n"); - rc = -ENODEV; - goto end; - } dp_display_host_init(dp, false); - /* - * set sink to normal operation mode -- D0 - * before dpcd read - */ - dp_link_psm_config(dp->link, &dp->panel->link_info, false); rc = dp_display_process_hpd_high(dp); end: return rc; @@ -428,11 +425,6 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev) dp = container_of(g_dp_display, struct dp_display_private, dp_display); - if (!dp) { - DRM_ERROR("no driver data found\n"); - rc = -ENODEV; - return rc; - } dp_add_event(dp, EV_USER_NOTIFICATION, false, 0); @@ -493,7 +485,6 @@ static int dp_display_usbpd_attention_cb(struct device *dev) int rc = 0; u32 sink_request; struct dp_display_private *dp; - struct dp_usbpd *hpd; if (!dev) { DRM_ERROR("invalid dev\n"); @@ -502,12 +493,6 @@ static int dp_display_usbpd_attention_cb(struct device *dev) dp = container_of(g_dp_display, struct dp_display_private, dp_display); - if (!dp) { - DRM_ERROR("no driver data found\n"); - return -ENODEV; - } - - hpd = dp->usbpd; /* check for any test request issued by sink */ rc = dp_link_process_request(dp->link); @@ -570,6 +555,10 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) dp_add_event(dp, EV_CONNECT_PENDING_TIMEOUT, 0, tout); } + /* enable HDP irq_hpd/replug interrupt */ + dp_catalog_hpd_config_intr(dp->catalog, + DP_DP_IRQ_HPD_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK, true); + mutex_unlock(&dp->event_mutex); /* uevent will complete connection part */ @@ -586,10 +575,8 @@ static int dp_connect_pending_timeout(struct dp_display_private *dp, u32 data) mutex_lock(&dp->event_mutex); state = dp->hpd_state; - if (state == ST_CONNECT_PENDING) { - dp_display_enable(dp, 0); + if (state == ST_CONNECT_PENDING) dp->hpd_state = ST_CONNECTED; - } mutex_unlock(&dp->event_mutex); @@ -621,7 +608,26 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) mutex_lock(&dp->event_mutex); state = dp->hpd_state; - if (state == ST_DISCONNECT_PENDING || state == ST_DISCONNECTED) { + + /* disable irq_hpd/replug interrupts */ + dp_catalog_hpd_config_intr(dp->catalog, + DP_DP_IRQ_HPD_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK, false); + + /* unplugged, no more irq_hpd handle */ + dp_del_event(dp, EV_IRQ_HPD_INT); + + if (state == ST_DISCONNECTED) { + /* triggered by irq_hdp with sink_count = 0 */ + if (dp->link->sink_count == 0) { + dp_ctrl_off_phy(dp->ctrl); + hpd->hpd_high = 0; + dp->core_initialized = false; + } + mutex_unlock(&dp->event_mutex); + return 0; + } + + if (state == ST_DISCONNECT_PENDING) { mutex_unlock(&dp->event_mutex); return 0; } @@ -635,9 +641,8 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) dp->hpd_state = ST_DISCONNECT_PENDING; - /* disable HPD plug interrupt until disconnect is done */ - dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK - | DP_DP_IRQ_HPD_INT_MASK, false); + /* disable HPD plug interrupts */ + dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, false); hpd->hpd_high = 0; @@ -651,11 +656,10 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) dp_add_event(dp, EV_DISCONNECT_PENDING_TIMEOUT, 0, DP_TIMEOUT_5_SECOND); /* signal the disconnect event early to ensure proper teardown */ - reinit_completion(&dp->audio_comp); dp_display_handle_plugged_change(g_dp_display, false); - dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK | - DP_DP_IRQ_HPD_INT_MASK, true); + /* enable HDP plug interrupt to prepare for next plugin */ + dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, true); /* uevent will complete disconnection part */ mutex_unlock(&dp->event_mutex); @@ -669,10 +673,8 @@ static int dp_disconnect_pending_timeout(struct dp_display_private *dp, u32 data mutex_lock(&dp->event_mutex); state = dp->hpd_state; - if (state == ST_DISCONNECT_PENDING) { - dp_display_disable(dp, 0); + if (state == ST_DISCONNECT_PENDING) dp->hpd_state = ST_DISCONNECTED; - } mutex_unlock(&dp->event_mutex); @@ -688,7 +690,7 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data) /* irq_hpd can happen at either connected or disconnected state */ state = dp->hpd_state; - if (state == ST_DISPLAY_OFF) { + if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) { mutex_unlock(&dp->event_mutex); return 0; } @@ -720,7 +722,6 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data) static void dp_display_deinit_sub_modules(struct dp_display_private *dp) { dp_debug_put(dp->debug); - dp_ctrl_put(dp->ctrl); dp_panel_put(dp->panel); dp_aux_put(dp->aux); dp_audio_put(dp->audio); @@ -814,13 +815,11 @@ static int dp_init_sub_modules(struct dp_display_private *dp) rc = PTR_ERR(dp->audio); pr_err("failed to initialize audio, rc = %d\n", rc); dp->audio = NULL; - goto error_audio; + goto error_ctrl; } return rc; -error_audio: - dp_ctrl_put(dp->ctrl); error_ctrl: dp_panel_put(dp->panel); error_link: @@ -898,7 +897,6 @@ static int dp_display_disable(struct dp_display_private *dp, u32 data) /* wait only if audio was enabled */ if (dp_display->audio_enabled) { /* signal the disconnect event */ - reinit_completion(&dp->audio_comp); dp_display_handle_plugged_change(dp_display, false); if (!wait_for_completion_timeout(&dp->audio_comp, HZ * 5)) @@ -907,9 +905,13 @@ static int dp_display_disable(struct dp_display_private *dp, u32 data) dp_display->audio_enabled = false; - dp_ctrl_off(dp->ctrl); - - dp->core_initialized = false; + /* triggered by irq_hpd with sink_count = 0 */ + if (dp->link->sink_count == 0) { + dp_ctrl_off_link_stream(dp->ctrl); + } else { + dp_ctrl_off(dp->ctrl); + dp->core_initialized = false; + } dp_display->power_on = false; @@ -1009,6 +1011,33 @@ int dp_display_get_test_bpp(struct msm_dp *dp) dp_display->link->test_video.test_bit_depth); } +void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp) +{ + struct dp_display_private *dp_display; + struct drm_device *drm; + + dp_display = container_of(dp, struct dp_display_private, dp_display); + drm = dp->drm_dev; + + /* + * if we are reading registers we need the link clocks to be on + * however till DP cable is connected this will not happen as we + * do not know the resolution to power up with. Hence check the + * power_on status before dumping DP registers to avoid crash due + * to unclocked access + */ + mutex_lock(&dp_display->event_mutex); + + if (!dp->power_on) { + mutex_unlock(&dp_display->event_mutex); + return; + } + + dp_catalog_snapshot(dp_display->catalog, disp_state); + + mutex_unlock(&dp_display->event_mutex); +} + static void dp_display_config_hpd(struct dp_display_private *dp) { @@ -1272,7 +1301,12 @@ static int dp_pm_resume(struct device *dev) status = dp_catalog_link_is_connected(dp->catalog); - if (status) + /* + * can not declared display is connected unless + * HDMI cable is plugged in and sink_count of + * dongle become 1 + */ + if (status && dp->link->sink_count) dp->dp_display.is_connected = true; else dp->dp_display.is_connected = false; @@ -1292,8 +1326,13 @@ static int dp_pm_suspend(struct device *dev) mutex_lock(&dp->event_mutex); - if (dp->core_initialized == true) + if (dp->core_initialized == true) { + /* mainlink enabled */ + if (dp_power_clk_status(dp->power, DP_CTRL_PM)) + dp_ctrl_off_link_stream(dp->ctrl); + dp_display_host_deinit(dp); + } dp->hpd_state = ST_SUSPENDED;