]> Pileus Git - ~andy/linux/blobdiff - drivers/gpu/drm/i915/intel_dp.c
drm/i915: propagate errors from intel_dp_init_connector
[~andy/linux] / drivers / gpu / drm / i915 / intel_dp.c
index 98686005dcf64f98edb9bd1b27537764180ef833..1a429cf55291a21257366b1b963bb4cbfbb9a8bb 100644 (file)
@@ -2683,13 +2683,14 @@ done:
 static void
 intel_dp_destroy(struct drm_connector *connector)
 {
-       struct intel_dp *intel_dp = intel_attached_dp(connector);
        struct intel_connector *intel_connector = to_intel_connector(connector);
 
        if (!IS_ERR_OR_NULL(intel_connector->edid))
                kfree(intel_connector->edid);
 
-       if (is_edp(intel_dp))
+       /* Can't call is_edp() since the encoder may have been destroyed
+        * already. */
+       if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
                intel_panel_fini(&intel_connector->panel);
 
        drm_sysfs_connector_remove(connector);
@@ -2954,7 +2955,87 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
                      I915_READ(pp_div_reg));
 }
 
-void
+static bool intel_edp_init_connector(struct intel_dp *intel_dp,
+                                    struct intel_connector *intel_connector)
+{
+       struct drm_connector *connector = &intel_connector->base;
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct drm_device *dev = intel_dig_port->base.base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_display_mode *fixed_mode = NULL;
+       struct edp_power_seq power_seq = { 0 };
+       bool has_dpcd;
+       struct drm_display_mode *scan;
+       struct edid *edid;
+
+       if (!is_edp(intel_dp))
+               return true;
+
+       intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
+
+       /* Cache DPCD and EDID for edp. */
+       ironlake_edp_panel_vdd_on(intel_dp);
+       has_dpcd = intel_dp_get_dpcd(intel_dp);
+       ironlake_edp_panel_vdd_off(intel_dp, false);
+
+       if (has_dpcd) {
+               if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11)
+                       dev_priv->no_aux_handshake =
+                               intel_dp->dpcd[DP_MAX_DOWNSPREAD] &
+                               DP_NO_AUX_HANDSHAKE_LINK_TRAINING;
+       } 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;
+       }
+
+       /* We now know it's not a ghost, init power sequence regs. */
+       intel_dp_init_panel_power_sequencer_registers(dev, intel_dp,
+                                                     &power_seq);
+
+       ironlake_edp_panel_vdd_on(intel_dp);
+       edid = drm_get_edid(connector, &intel_dp->adapter);
+       if (edid) {
+               if (drm_add_edid_modes(connector, edid)) {
+                       drm_mode_connector_update_edid_property(connector,
+                                                               edid);
+                       drm_edid_to_eld(connector, edid);
+               } else {
+                       kfree(edid);
+                       edid = ERR_PTR(-EINVAL);
+               }
+       } else {
+               edid = ERR_PTR(-ENOENT);
+       }
+       intel_connector->edid = edid;
+
+       /* prefer fixed mode from EDID if available */
+       list_for_each_entry(scan, &connector->probed_modes, head) {
+               if ((scan->type & DRM_MODE_TYPE_PREFERRED)) {
+                       fixed_mode = drm_mode_duplicate(dev, scan);
+                       break;
+               }
+       }
+
+       /* fallback to VBT if available for eDP */
+       if (!fixed_mode && dev_priv->vbt.lfp_lvds_vbt_mode) {
+               fixed_mode = drm_mode_duplicate(dev,
+                                       dev_priv->vbt.lfp_lvds_vbt_mode);
+               if (fixed_mode)
+                       fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
+       }
+
+       ironlake_edp_panel_vdd_off(intel_dp, false);
+
+       intel_panel_init(&intel_connector->panel, fixed_mode);
+       intel_panel_setup_backlight(connector);
+
+       return true;
+}
+
+bool
 intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
                        struct intel_connector *intel_connector)
 {
@@ -2963,8 +3044,6 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
        struct intel_encoder *intel_encoder = &intel_dig_port->base;
        struct drm_device *dev = intel_encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_display_mode *fixed_mode = NULL;
-       struct edp_power_seq power_seq = { 0 };
        enum port port = intel_dig_port->port;
        const char *name = NULL;
        int type;
@@ -3065,75 +3144,10 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
                BUG();
        }
 
-       if (is_edp(intel_dp))
-               intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
-
        intel_dp_i2c_init(intel_dp, intel_connector, name);
 
-       /* Cache DPCD and EDID for edp. */
-       if (is_edp(intel_dp)) {
-               bool ret;
-               struct drm_display_mode *scan;
-               struct edid *edid;
-
-               ironlake_edp_panel_vdd_on(intel_dp);
-               ret = intel_dp_get_dpcd(intel_dp);
-               ironlake_edp_panel_vdd_off(intel_dp, false);
-
-               if (ret) {
-                       if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11)
-                               dev_priv->no_aux_handshake =
-                                       intel_dp->dpcd[DP_MAX_DOWNSPREAD] &
-                                       DP_NO_AUX_HANDSHAKE_LINK_TRAINING;
-               } 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_encoder->base);
-                       intel_dp_destroy(connector);
-                       return;
-               }
-
-               /* We now know it's not a ghost, init power sequence regs. */
-               intel_dp_init_panel_power_sequencer_registers(dev, intel_dp,
-                                                             &power_seq);
-
-               ironlake_edp_panel_vdd_on(intel_dp);
-               edid = drm_get_edid(connector, &intel_dp->adapter);
-               if (edid) {
-                       if (drm_add_edid_modes(connector, edid)) {
-                               drm_mode_connector_update_edid_property(connector, edid);
-                               drm_edid_to_eld(connector, edid);
-                       } else {
-                               kfree(edid);
-                               edid = ERR_PTR(-EINVAL);
-                       }
-               } else {
-                       edid = ERR_PTR(-ENOENT);
-               }
-               intel_connector->edid = edid;
-
-               /* prefer fixed mode from EDID if available */
-               list_for_each_entry(scan, &connector->probed_modes, head) {
-                       if ((scan->type & DRM_MODE_TYPE_PREFERRED)) {
-                               fixed_mode = drm_mode_duplicate(dev, scan);
-                               break;
-                       }
-               }
-
-               /* fallback to VBT if available for eDP */
-               if (!fixed_mode && dev_priv->vbt.lfp_lvds_vbt_mode) {
-                       fixed_mode = drm_mode_duplicate(dev, dev_priv->vbt.lfp_lvds_vbt_mode);
-                       if (fixed_mode)
-                               fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
-               }
-
-               ironlake_edp_panel_vdd_off(intel_dp, false);
-       }
-
-       if (is_edp(intel_dp)) {
-               intel_panel_init(&intel_connector->panel, fixed_mode);
-               intel_panel_setup_backlight(connector);
-       }
+       if (!intel_edp_init_connector(intel_dp, intel_connector))
+               return false;
 
        intel_dp_add_properties(intel_dp, connector);
 
@@ -3145,6 +3159,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
                u32 temp = I915_READ(PEG_BAND_GAP_DATA);
                I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
        }
+
+       return true;
 }
 
 void