Commit e953fd7bb32f55309a96abd5ceba9cf68d221434
1 parent
ce453d81cb
Exists in
master
and in
20 other branches
drm/i915: Add support for limited color range of broadcast outputs
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>
Showing 7 changed files with 82 additions and 2 deletions Side-by-side Diff
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_reg.h
... | ... | @@ -1387,6 +1387,7 @@ |
1387 | 1387 | #define SDVO_ENCODING_HDMI (0x2 << 10) |
1388 | 1388 | /** Requird for HDMI operation */ |
1389 | 1389 | #define SDVO_NULL_PACKETS_DURING_VSYNC (1 << 9) |
1390 | +#define SDVO_COLOR_RANGE_16_235 (1 << 8) | |
1390 | 1391 | #define SDVO_BORDER_ENABLE (1 << 7) |
1391 | 1392 | #define SDVO_AUDIO_ENABLE (1 << 6) |
1392 | 1393 | /** New with 965, default is to be set */ |
drivers/gpu/drm/i915/intel_dp.c
... | ... | @@ -49,6 +49,7 @@ |
49 | 49 | uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE]; |
50 | 50 | bool has_audio; |
51 | 51 | int force_audio; |
52 | + uint32_t color_range; | |
52 | 53 | int dpms_mode; |
53 | 54 | uint8_t link_bw; |
54 | 55 | uint8_t lane_count; |
... | ... | @@ -741,8 +742,8 @@ |
741 | 742 | struct drm_crtc *crtc = intel_dp->base.base.crtc; |
742 | 743 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
743 | 744 | |
744 | - intel_dp->DP = (DP_VOLTAGE_0_4 | | |
745 | - DP_PRE_EMPHASIS_0); | |
745 | + intel_dp->DP = DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0; | |
746 | + intel_dp->DP |= intel_dp->color_range; | |
746 | 747 | |
747 | 748 | if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) |
748 | 749 | intel_dp->DP |= DP_SYNC_HS_HIGH; |
... | ... | @@ -1680,6 +1681,7 @@ |
1680 | 1681 | struct drm_property *property, |
1681 | 1682 | uint64_t val) |
1682 | 1683 | { |
1684 | + struct drm_i915_private *dev_priv = connector->dev->dev_private; | |
1683 | 1685 | struct intel_dp *intel_dp = intel_attached_dp(connector); |
1684 | 1686 | int ret; |
1685 | 1687 | |
... | ... | @@ -1708,6 +1710,14 @@ |
1708 | 1710 | goto done; |
1709 | 1711 | } |
1710 | 1712 | |
1713 | + if (property == dev_priv->broadcast_rgb_property) { | |
1714 | + if (val == !!intel_dp->color_range) | |
1715 | + return 0; | |
1716 | + | |
1717 | + intel_dp->color_range = val ? DP_COLOR_RANGE_16_235 : 0; | |
1718 | + goto done; | |
1719 | + } | |
1720 | + | |
1711 | 1721 | return -EINVAL; |
1712 | 1722 | |
1713 | 1723 | done: |
... | ... | @@ -1827,6 +1837,8 @@ |
1827 | 1837 | intel_dp->force_audio_property->values[1] = 1; |
1828 | 1838 | drm_connector_attach_property(connector, intel_dp->force_audio_property, 0); |
1829 | 1839 | } |
1840 | + | |
1841 | + intel_attach_broadcast_rgb_property(connector); | |
1830 | 1842 | } |
1831 | 1843 | |
1832 | 1844 | void |
drivers/gpu/drm/i915/intel_drv.h
... | ... | @@ -237,6 +237,8 @@ |
237 | 237 | int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter); |
238 | 238 | extern bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus); |
239 | 239 | |
240 | +extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector); | |
241 | + | |
240 | 242 | extern void intel_crt_init(struct drm_device *dev); |
241 | 243 | extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg); |
242 | 244 | void intel_dip_infoframe_csum(struct dip_infoframe *avi_if); |
drivers/gpu/drm/i915/intel_hdmi.c
... | ... | @@ -41,6 +41,7 @@ |
41 | 41 | struct intel_encoder base; |
42 | 42 | u32 sdvox_reg; |
43 | 43 | int ddc_bus; |
44 | + uint32_t color_range; | |
44 | 45 | bool has_hdmi_sink; |
45 | 46 | bool has_audio; |
46 | 47 | int force_audio; |
... | ... | @@ -124,6 +125,7 @@ |
124 | 125 | u32 sdvox; |
125 | 126 | |
126 | 127 | sdvox = SDVO_ENCODING_HDMI | SDVO_BORDER_ENABLE; |
128 | + sdvox |= intel_hdmi->color_range; | |
127 | 129 | if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) |
128 | 130 | sdvox |= SDVO_VSYNC_ACTIVE_HIGH; |
129 | 131 | if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) |
... | ... | @@ -278,6 +280,7 @@ |
278 | 280 | uint64_t val) |
279 | 281 | { |
280 | 282 | struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); |
283 | + struct drm_i915_private *dev_priv = connector->dev->dev_private; | |
281 | 284 | int ret; |
282 | 285 | |
283 | 286 | ret = drm_connector_property_set_value(connector, property, val); |
... | ... | @@ -305,6 +308,14 @@ |
305 | 308 | goto done; |
306 | 309 | } |
307 | 310 | |
311 | + if (property == dev_priv->broadcast_rgb_property) { | |
312 | + if (val == !!intel_hdmi->color_range) | |
313 | + return 0; | |
314 | + | |
315 | + intel_hdmi->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0; | |
316 | + goto done; | |
317 | + } | |
318 | + | |
308 | 319 | return -EINVAL; |
309 | 320 | |
310 | 321 | done: |
... | ... | @@ -363,6 +374,8 @@ |
363 | 374 | intel_hdmi->force_audio_property->values[1] = 1; |
364 | 375 | drm_connector_attach_property(connector, intel_hdmi->force_audio_property, 0); |
365 | 376 | } |
377 | + | |
378 | + intel_attach_broadcast_rgb_property(connector); | |
366 | 379 | } |
367 | 380 | |
368 | 381 | void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) |
drivers/gpu/drm/i915/intel_modes.c
... | ... | @@ -80,4 +80,34 @@ |
80 | 80 | |
81 | 81 | return ret; |
82 | 82 | } |
83 | + | |
84 | +static const char *broadcast_rgb_names[] = { | |
85 | + "Full", | |
86 | + "Limited 16:235", | |
87 | +}; | |
88 | + | |
89 | +void | |
90 | +intel_attach_broadcast_rgb_property(struct drm_connector *connector) | |
91 | +{ | |
92 | + struct drm_device *dev = connector->dev; | |
93 | + struct drm_i915_private *dev_priv = dev->dev_private; | |
94 | + struct drm_property *prop; | |
95 | + int i; | |
96 | + | |
97 | + prop = dev_priv->broadcast_rgb_property; | |
98 | + if (prop == NULL) { | |
99 | + prop = drm_property_create(dev, DRM_MODE_PROP_ENUM, | |
100 | + "Broadcast RGB", | |
101 | + ARRAY_SIZE(broadcast_rgb_names)); | |
102 | + if (prop == NULL) | |
103 | + return; | |
104 | + | |
105 | + for (i = 0; i < ARRAY_SIZE(broadcast_rgb_names); i++) | |
106 | + drm_property_add_enum(prop, i, i, broadcast_rgb_names[i]); | |
107 | + | |
108 | + dev_priv->broadcast_rgb_property = prop; | |
109 | + } | |
110 | + | |
111 | + drm_connector_attach_property(connector, prop, 0); | |
112 | +} |
drivers/gpu/drm/i915/intel_sdvo.c
... | ... | @@ -93,6 +93,12 @@ |
93 | 93 | uint16_t attached_output; |
94 | 94 | |
95 | 95 | /** |
96 | + * This is used to select the color range of RBG outputs in HDMI mode. | |
97 | + * It is only valid when using TMDS encoding and 8 bit per color mode. | |
98 | + */ | |
99 | + uint32_t color_range; | |
100 | + | |
101 | + /** | |
96 | 102 | * This is set if we're going to treat the device as TV-out. |
97 | 103 | * |
98 | 104 | * While we have these nice friendly flags for output types that ought |
... | ... | @@ -1056,6 +1062,8 @@ |
1056 | 1062 | /* Set the SDVO control regs. */ |
1057 | 1063 | if (INTEL_INFO(dev)->gen >= 4) { |
1058 | 1064 | sdvox = 0; |
1065 | + if (intel_sdvo->is_hdmi) | |
1066 | + sdvox |= intel_sdvo->color_range; | |
1059 | 1067 | if (INTEL_INFO(dev)->gen < 5) |
1060 | 1068 | sdvox |= SDVO_BORDER_ENABLE; |
1061 | 1069 | if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) |
... | ... | @@ -1695,6 +1703,7 @@ |
1695 | 1703 | { |
1696 | 1704 | struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); |
1697 | 1705 | struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); |
1706 | + struct drm_i915_private *dev_priv = connector->dev->dev_private; | |
1698 | 1707 | uint16_t temp_value; |
1699 | 1708 | uint8_t cmd; |
1700 | 1709 | int ret; |
... | ... | @@ -1724,6 +1733,14 @@ |
1724 | 1733 | goto done; |
1725 | 1734 | } |
1726 | 1735 | |
1736 | + if (property == dev_priv->broadcast_rgb_property) { | |
1737 | + if (val == !!intel_sdvo->color_range) | |
1738 | + return 0; | |
1739 | + | |
1740 | + intel_sdvo->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0; | |
1741 | + goto done; | |
1742 | + } | |
1743 | + | |
1727 | 1744 | #define CHECK_PROPERTY(name, NAME) \ |
1728 | 1745 | if (intel_sdvo_connector->name == property) { \ |
1729 | 1746 | if (intel_sdvo_connector->cur_##name == temp_value) return 0; \ |
... | ... | @@ -2028,6 +2045,9 @@ |
2028 | 2045 | drm_connector_attach_property(&connector->base.base, |
2029 | 2046 | connector->force_audio_property, 0); |
2030 | 2047 | } |
2048 | + | |
2049 | + if (INTEL_INFO(dev)->gen >= 4 && IS_MOBILE(dev)) | |
2050 | + intel_attach_broadcast_rgb_property(&connector->base.base); | |
2031 | 2051 | } |
2032 | 2052 | |
2033 | 2053 | static bool |