drm/i915: export error state ref handling
[deliverable/linux.git] / drivers / gpu / drm / i915 / intel_dp.c
index 1a429cf55291a21257366b1b963bb4cbfbb9a8bb..11eb697dec0114f50b8c29e51e149f220be6b674 100644 (file)
@@ -1324,22 +1324,44 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
                                struct intel_crtc_config *pipe_config)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-       struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
        u32 tmp, flags = 0;
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum port port = dp_to_dig_port(intel_dp)->port;
+       struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
 
-       tmp = I915_READ(intel_dp->output_reg);
+       if ((port == PORT_A) || !HAS_PCH_CPT(dev)) {
+               tmp = I915_READ(intel_dp->output_reg);
+               if (tmp & DP_SYNC_HS_HIGH)
+                       flags |= DRM_MODE_FLAG_PHSYNC;
+               else
+                       flags |= DRM_MODE_FLAG_NHSYNC;
 
-       if (tmp & DP_SYNC_HS_HIGH)
-               flags |= DRM_MODE_FLAG_PHSYNC;
-       else
-               flags |= DRM_MODE_FLAG_NHSYNC;
+               if (tmp & DP_SYNC_VS_HIGH)
+                       flags |= DRM_MODE_FLAG_PVSYNC;
+               else
+                       flags |= DRM_MODE_FLAG_NVSYNC;
+       } else {
+               tmp = I915_READ(TRANS_DP_CTL(crtc->pipe));
+               if (tmp & TRANS_DP_HSYNC_ACTIVE_HIGH)
+                       flags |= DRM_MODE_FLAG_PHSYNC;
+               else
+                       flags |= DRM_MODE_FLAG_NHSYNC;
 
-       if (tmp & DP_SYNC_VS_HIGH)
-               flags |= DRM_MODE_FLAG_PVSYNC;
-       else
-               flags |= DRM_MODE_FLAG_NVSYNC;
+               if (tmp & TRANS_DP_VSYNC_ACTIVE_HIGH)
+                       flags |= DRM_MODE_FLAG_PVSYNC;
+               else
+                       flags |= DRM_MODE_FLAG_NVSYNC;
+       }
 
        pipe_config->adjusted_mode.flags |= flags;
+
+       if (dp_to_dig_port(intel_dp)->port == PORT_A) {
+               if ((I915_READ(DP_A) & DP_PLL_FREQ_MASK) == DP_PLL_FREQ_160MHZ)
+                       pipe_config->port_clock = 162000;
+               else
+                       pipe_config->port_clock = 270000;
+       }
 }
 
 static void intel_disable_dp(struct intel_encoder *encoder)
@@ -2681,7 +2703,7 @@ done:
 }
 
 static void
-intel_dp_destroy(struct drm_connector *connector)
+intel_dp_connector_destroy(struct drm_connector *connector)
 {
        struct intel_connector *intel_connector = to_intel_connector(connector);
 
@@ -2724,7 +2746,7 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = {
        .detect = intel_dp_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .set_property = intel_dp_set_property,
-       .destroy = intel_dp_destroy,
+       .destroy = intel_dp_connector_destroy,
 };
 
 static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = {
@@ -2986,8 +3008,6 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
        } else {
                /* if this fails, presume the device is a ghost */
                DRM_INFO("failed to retrieve link info, disabling eDP\n");
-               intel_dp_encoder_destroy(&intel_dig_port->base.base);
-               intel_dp_destroy(connector);
                return false;
        }
 
@@ -3046,7 +3066,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
        struct drm_i915_private *dev_priv = dev->dev_private;
        enum port port = intel_dig_port->port;
        const char *name = NULL;
-       int type;
+       int type, error;
 
        /* Preserve the current hw state. */
        intel_dp->DP = I915_READ(intel_dp->output_reg);
@@ -3144,10 +3164,22 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
                BUG();
        }
 
-       intel_dp_i2c_init(intel_dp, intel_connector, name);
+       error = intel_dp_i2c_init(intel_dp, intel_connector, name);
+       WARN(error, "intel_dp_i2c_init failed with error %d for port %c\n",
+            error, port_name(port));
 
-       if (!intel_edp_init_connector(intel_dp, intel_connector))
+       if (!intel_edp_init_connector(intel_dp, intel_connector)) {
+               i2c_del_adapter(&intel_dp->adapter);
+               if (is_edp(intel_dp)) {
+                       cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
+                       mutex_lock(&dev->mode_config.mutex);
+                       ironlake_panel_vdd_off_sync(intel_dp);
+                       mutex_unlock(&dev->mode_config.mutex);
+               }
+               drm_sysfs_connector_remove(connector);
+               drm_connector_cleanup(connector);
                return false;
+       }
 
        intel_dp_add_properties(intel_dp, connector);
 
@@ -3206,5 +3238,9 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
        intel_encoder->cloneable = false;
        intel_encoder->hot_plug = intel_dp_hot_plug;
 
-       intel_dp_init_connector(intel_dig_port, intel_connector);
+       if (!intel_dp_init_connector(intel_dig_port, intel_connector)) {
+               drm_encoder_cleanup(encoder);
+               kfree(intel_dig_port);
+               kfree(intel_connector);
+       }
 }
This page took 0.025785 seconds and 5 git commands to generate.