drm/i915: Fix LVDS fixed-mode regression from 219adae1
[pandora-kernel.git] / drivers / gpu / drm / i915 / intel_dp.c
index 42cd528..c8e0055 100644 (file)
@@ -48,6 +48,7 @@ struct intel_dp {
        uint32_t DP;
        uint8_t  link_configuration[DP_LINK_CONFIGURATION_SIZE];
        bool has_audio;
+       int force_audio;
        int dpms_mode;
        uint8_t link_bw;
        uint8_t lane_count;
@@ -57,6 +58,8 @@ struct intel_dp {
        bool is_pch_edp;
        uint8_t train_set[4];
        uint8_t link_status[DP_LINK_STATUS_SIZE];
+
+       struct drm_property *force_audio_property;
 };
 
 /**
@@ -1514,7 +1517,7 @@ g4x_dp_detect(struct intel_dp *intel_dp)
                        status = connector_status_connected;
        }
 
-       return bit;
+       return status;
 }
 
 /**
@@ -1540,11 +1543,15 @@ intel_dp_detect(struct drm_connector *connector, bool force)
        if (status != connector_status_connected)
                return status;
 
-       edid = drm_get_edid(connector, &intel_dp->adapter);
-       if (edid) {
-               intel_dp->has_audio = drm_detect_monitor_audio(edid);
-               connector->display_info.raw_edid = NULL;
-               kfree(edid);
+       if (intel_dp->force_audio) {
+               intel_dp->has_audio = intel_dp->force_audio > 0;
+       } else {
+               edid = drm_get_edid(connector, &intel_dp->adapter);
+               if (edid) {
+                       intel_dp->has_audio = drm_detect_monitor_audio(edid);
+                       connector->display_info.raw_edid = NULL;
+                       kfree(edid);
+               }
        }
 
        return connector_status_connected;
@@ -1589,6 +1596,46 @@ static int intel_dp_get_modes(struct drm_connector *connector)
        return 0;
 }
 
+static int
+intel_dp_set_property(struct drm_connector *connector,
+                     struct drm_property *property,
+                     uint64_t val)
+{
+       struct intel_dp *intel_dp = intel_attached_dp(connector);
+       int ret;
+
+       ret = drm_connector_property_set_value(connector, property, val);
+       if (ret)
+               return ret;
+
+       if (property == intel_dp->force_audio_property) {
+               if (val == intel_dp->force_audio)
+                       return 0;
+
+               intel_dp->force_audio = val;
+
+               if (val > 0 && intel_dp->has_audio)
+                       return 0;
+               if (val < 0 && !intel_dp->has_audio)
+                       return 0;
+
+               intel_dp->has_audio = val > 0;
+               goto done;
+       }
+
+       return -EINVAL;
+
+done:
+       if (intel_dp->base.base.crtc) {
+               struct drm_crtc *crtc = intel_dp->base.base.crtc;
+               drm_crtc_helper_set_mode(crtc, &crtc->mode,
+                                        crtc->x, crtc->y,
+                                        crtc->fb);
+       }
+
+       return 0;
+}
+
 static void
 intel_dp_destroy (struct drm_connector *connector)
 {
@@ -1618,6 +1665,7 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = {
        .dpms = drm_helper_connector_dpms,
        .detect = intel_dp_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
+       .set_property = intel_dp_set_property,
        .destroy = intel_dp_destroy,
 };
 
@@ -1682,6 +1730,20 @@ bool intel_dpd_is_edp(struct drm_device *dev)
        return false;
 }
 
+static void
+intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+
+       intel_dp->force_audio_property =
+               drm_property_create(dev, DRM_MODE_PROP_RANGE, "force_audio", 2);
+       if (intel_dp->force_audio_property) {
+               intel_dp->force_audio_property->values[0] = -1;
+               intel_dp->force_audio_property->values[1] = 1;
+               drm_connector_attach_property(connector, intel_dp->force_audio_property, 0);
+       }
+}
+
 void
 intel_dp_init(struct drm_device *dev, int output_reg)
 {
@@ -1808,6 +1870,8 @@ intel_dp_init(struct drm_device *dev, int output_reg)
                }
        }
 
+       intel_dp_add_properties(intel_dp, connector);
+
        /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
         * 0xd.  Failure to do so will result in spurious interrupts being
         * generated on the port when a cable is not attached.