summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/msm/dp/dp_display.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/msm/dp/dp_display.c')
-rw-r--r--drivers/gpu/drm/msm/dp/dp_display.c121
1 files changed, 76 insertions, 45 deletions
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 1784e119269b..051c1be1de7e 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -208,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;
@@ -252,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);
@@ -346,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) {
@@ -406,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;
@@ -437,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);
@@ -502,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");
@@ -511,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);
@@ -579,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 */
@@ -628,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;
}
@@ -642,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;
@@ -660,8 +658,8 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)
/* signal the disconnect event early to ensure proper teardown */
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);
@@ -692,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;
}
@@ -724,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);
@@ -818,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:
@@ -910,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;
@@ -1012,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)
{
@@ -1300,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;