drm/i915/dp: Add 'force_audio' property
authorChris Wilson <chris@chris-wilson.co.uk>
Sun, 19 Sep 2010 08:29:33 +0000 (09:29 +0100)
committerChris Wilson <chris@chris-wilson.co.uk>
Tue, 19 Oct 2010 08:17:58 +0000 (09:17 +0100)
Allow the user to override the detection of the sink's audio capabilities
from EDID. Not all sinks support the required EDID level to specify
whether they handle audio over the display connection, so allow the user
to enable it manually.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
drivers/gpu/drm/i915/intel_dp.c

index 42cd528286a528cd5022df2c10351d30b80e3bcb..891f4f1d63b11570b7ede1c4e5e49814f2dcb5d0 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;
 };
 
 /**
@@ -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.