]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
drm/i915: Add support for limited color range of broadcast outputs
authorChris Wilson <chris@chris-wilson.co.uk>
Mon, 21 Feb 2011 22:23:52 +0000 (22:23 +0000)
committerChris Wilson <chris@chris-wilson.co.uk>
Tue, 22 Feb 2011 15:56:56 +0000 (15:56 +0000)
In order to prevent "crushed blacks" on TVs, the range of the RGB output
may be limited to 16-235. This used to be available through Xorg under
the "Broadcast RGB" option, so reintroduce support for KMS.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=34543
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_modes.c
drivers/gpu/drm/i915/intel_sdvo.c

index 6b86e83ae1281af198aea0f144c6d273e68aa2f4..3d4fd0181f657df3ca06d092d575c433323ef81a 100644 (file)
@@ -707,6 +707,8 @@ typedef struct drm_i915_private {
 
        /* list of fbdev register on this device */
        struct intel_fbdev *fbdev;
+
+       struct drm_property *broadcast_rgb_property;
 } drm_i915_private_t;
 
 struct drm_i915_gem_object {
index 139d15234ffb7074682e78c7b9af27e0d14c9ead..63ed072e5fe3c246a5a1cbd274542179ce062040 100644 (file)
 #define   SDVO_ENCODING_HDMI           (0x2 << 10)
 /** Requird for HDMI operation */
 #define   SDVO_NULL_PACKETS_DURING_VSYNC (1 << 9)
+#define   SDVO_COLOR_RANGE_16_235      (1 << 8)
 #define   SDVO_BORDER_ENABLE           (1 << 7)
 #define   SDVO_AUDIO_ENABLE            (1 << 6)
 /** New with 965, default is to be set */
index 7ffb324b6a7df8855cc2f6a96816d48a491ba45e..3216adcf54d246aba616a2f2d56761fd2c50e43f 100644 (file)
@@ -49,6 +49,7 @@ struct intel_dp {
        uint8_t  link_configuration[DP_LINK_CONFIGURATION_SIZE];
        bool has_audio;
        int force_audio;
+       uint32_t color_range;
        int dpms_mode;
        uint8_t link_bw;
        uint8_t lane_count;
@@ -741,8 +742,8 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
        struct drm_crtc *crtc = intel_dp->base.base.crtc;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-       intel_dp->DP = (DP_VOLTAGE_0_4 |
-                      DP_PRE_EMPHASIS_0);
+       intel_dp->DP = DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
+       intel_dp->DP |= intel_dp->color_range;
 
        if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
                intel_dp->DP |= DP_SYNC_HS_HIGH;
@@ -1680,6 +1681,7 @@ intel_dp_set_property(struct drm_connector *connector,
                      struct drm_property *property,
                      uint64_t val)
 {
+       struct drm_i915_private *dev_priv = connector->dev->dev_private;
        struct intel_dp *intel_dp = intel_attached_dp(connector);
        int ret;
 
@@ -1708,6 +1710,14 @@ intel_dp_set_property(struct drm_connector *connector,
                goto done;
        }
 
+       if (property == dev_priv->broadcast_rgb_property) {
+               if (val == !!intel_dp->color_range)
+                       return 0;
+
+               intel_dp->color_range = val ? DP_COLOR_RANGE_16_235 : 0;
+               goto done;
+       }
+
        return -EINVAL;
 
 done:
@@ -1827,6 +1837,8 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
                intel_dp->force_audio_property->values[1] = 1;
                drm_connector_attach_property(connector, intel_dp->force_audio_property, 0);
        }
+
+       intel_attach_broadcast_rgb_property(connector);
 }
 
 void
index 08cd27d2c13261ea42a676fc0825d340731ba6ff..5daa991cb28733149da4402b51ff01964731bc46 100644 (file)
@@ -237,6 +237,8 @@ struct intel_unpin_work {
 int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter);
 extern bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus);
 
+extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector);
+
 extern void intel_crt_init(struct drm_device *dev);
 extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg);
 void intel_dip_infoframe_csum(struct dip_infoframe *avi_if);
index c635c9e357b9124e3617188cd9c249f2bde1e144..f289b86429762e7b644e3b454c7f8b1a0d345987 100644 (file)
@@ -41,6 +41,7 @@ struct intel_hdmi {
        struct intel_encoder base;
        u32 sdvox_reg;
        int ddc_bus;
+       uint32_t color_range;
        bool has_hdmi_sink;
        bool has_audio;
        int force_audio;
@@ -124,6 +125,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
        u32 sdvox;
 
        sdvox = SDVO_ENCODING_HDMI | SDVO_BORDER_ENABLE;
+       sdvox |= intel_hdmi->color_range;
        if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
                sdvox |= SDVO_VSYNC_ACTIVE_HIGH;
        if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
@@ -278,6 +280,7 @@ intel_hdmi_set_property(struct drm_connector *connector,
                      uint64_t val)
 {
        struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+       struct drm_i915_private *dev_priv = connector->dev->dev_private;
        int ret;
 
        ret = drm_connector_property_set_value(connector, property, val);
@@ -305,6 +308,14 @@ intel_hdmi_set_property(struct drm_connector *connector,
                goto done;
        }
 
+       if (property == dev_priv->broadcast_rgb_property) {
+               if (val == !!intel_hdmi->color_range)
+                       return 0;
+
+               intel_hdmi->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0;
+               goto done;
+       }
+
        return -EINVAL;
 
 done:
@@ -363,6 +374,8 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c
                intel_hdmi->force_audio_property->values[1] = 1;
                drm_connector_attach_property(connector, intel_hdmi->force_audio_property, 0);
        }
+
+       intel_attach_broadcast_rgb_property(connector);
 }
 
 void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
index f70b7cf32bffc43a4325233e0ba11ab5726ce64f..9034dd8f33c75646eedceeba9d010e26f198ae5c 100644 (file)
@@ -80,3 +80,33 @@ int intel_ddc_get_modes(struct drm_connector *connector,
 
        return ret;
 }
+
+static const char *broadcast_rgb_names[] = {
+       "Full",
+       "Limited 16:235",
+};
+
+void
+intel_attach_broadcast_rgb_property(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_property *prop;
+       int i;
+
+       prop = dev_priv->broadcast_rgb_property;
+       if (prop == NULL) {
+               prop = drm_property_create(dev, DRM_MODE_PROP_ENUM,
+                                          "Broadcast RGB",
+                                          ARRAY_SIZE(broadcast_rgb_names));
+               if (prop == NULL)
+                       return;
+
+               for (i = 0; i < ARRAY_SIZE(broadcast_rgb_names); i++)
+                       drm_property_add_enum(prop, i, i, broadcast_rgb_names[i]);
+
+               dev_priv->broadcast_rgb_property = prop;
+       }
+
+       drm_connector_attach_property(connector, prop, 0);
+}
index 19c817a2df0cb44da2eba9b8d781179fb643d743..9698e91f6a37e23984d771bbdf8fff228aa8048e 100644 (file)
@@ -92,6 +92,12 @@ struct intel_sdvo {
        */
        uint16_t attached_output;
 
+       /**
+        * This is used to select the color range of RBG outputs in HDMI mode.
+        * It is only valid when using TMDS encoding and 8 bit per color mode.
+        */
+       uint32_t color_range;
+
        /**
         * This is set if we're going to treat the device as TV-out.
         *
@@ -1056,6 +1062,8 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
        /* Set the SDVO control regs. */
        if (INTEL_INFO(dev)->gen >= 4) {
                sdvox = 0;
+               if (intel_sdvo->is_hdmi)
+                       sdvox |= intel_sdvo->color_range;
                if (INTEL_INFO(dev)->gen < 5)
                        sdvox |= SDVO_BORDER_ENABLE;
                if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
@@ -1695,6 +1703,7 @@ intel_sdvo_set_property(struct drm_connector *connector,
 {
        struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
        struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
+       struct drm_i915_private *dev_priv = connector->dev->dev_private;
        uint16_t temp_value;
        uint8_t cmd;
        int ret;
@@ -1724,6 +1733,14 @@ intel_sdvo_set_property(struct drm_connector *connector,
                goto done;
        }
 
+       if (property == dev_priv->broadcast_rgb_property) {
+               if (val == !!intel_sdvo->color_range)
+                       return 0;
+
+               intel_sdvo->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0;
+               goto done;
+       }
+
 #define CHECK_PROPERTY(name, NAME) \
        if (intel_sdvo_connector->name == property) { \
                if (intel_sdvo_connector->cur_##name == temp_value) return 0; \
@@ -2028,6 +2045,9 @@ intel_sdvo_add_hdmi_properties(struct intel_sdvo_connector *connector)
                drm_connector_attach_property(&connector->base.base,
                                              connector->force_audio_property, 0);
        }
+
+       if (INTEL_INFO(dev)->gen >= 4 && IS_MOBILE(dev))
+               intel_attach_broadcast_rgb_property(&connector->base.base);
 }
 
 static bool