Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/i915: Add "Automatic" mode for the "Broadcast RGB" property

Add a new "Automatic" mode to the "Broadcast RGB" range property.
When selected the driver automagically selects between full range and
limited range output.

Based on CEA-861 [1] guidelines, limited range output is selected if the
mode is a CEA mode, except 640x480. Otherwise full range output is used.
Additionally DVI monitors should most likely default to full range
always.

As per DP1.2a [2] DisplayPort should always use full range for 18bpp, and
otherwise will follow CEA-861 rules.

NOTE: The default value for the property will now be "Automatic"
so some people may be affected in case they're relying on the
current full range default.

[1] CEA-861-E - 5.1 Default Encoding Parameters
[2] VESA DisplayPort Ver.1.2a - 5.1.1.1 Video Colorimetry

v2: Use has_hdmi_sink to check if a HDMI monitor is present
v3: Add information about relevant spec chapters

Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>

authored by

Ville Syrjälä and committed by
Daniel Vetter
55bc60db 3685a8f3

+93 -17
+4
drivers/gpu/drm/i915/i915_drv.h
··· 1811 1811 #define POSTING_READ(reg) (void)I915_READ_NOTRACE(reg) 1812 1812 #define POSTING_READ16(reg) (void)I915_READ16_NOTRACE(reg) 1813 1813 1814 + /* "Broadcast RGB" property */ 1815 + #define INTEL_BROADCAST_RGB_AUTO 0 1816 + #define INTEL_BROADCAST_RGB_FULL 1 1817 + #define INTEL_BROADCAST_RGB_LIMITED 2 1814 1818 1815 1819 #endif
+28 -4
drivers/gpu/drm/i915/intel_dp.c
··· 764 764 765 765 bpp = adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 24; 766 766 767 + if (intel_dp->color_range_auto) { 768 + /* 769 + * See: 770 + * CEA-861-E - 5.1 Default Encoding Parameters 771 + * VESA DisplayPort Ver.1.2a - 5.1.1.1 Video Colorimetry 772 + */ 773 + if (bpp != 18 && drm_mode_cea_vic(adjusted_mode) > 1) 774 + intel_dp->color_range = DP_COLOR_RANGE_16_235; 775 + else 776 + intel_dp->color_range = 0; 777 + } 778 + 767 779 if (intel_dp->color_range) 768 780 adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE; 769 781 ··· 2474 2462 } 2475 2463 2476 2464 if (property == dev_priv->broadcast_rgb_property) { 2477 - if (val == !!intel_dp->color_range) 2478 - return 0; 2479 - 2480 - intel_dp->color_range = val ? DP_COLOR_RANGE_16_235 : 0; 2465 + switch (val) { 2466 + case INTEL_BROADCAST_RGB_AUTO: 2467 + intel_dp->color_range_auto = true; 2468 + break; 2469 + case INTEL_BROADCAST_RGB_FULL: 2470 + intel_dp->color_range_auto = false; 2471 + intel_dp->color_range = 0; 2472 + break; 2473 + case INTEL_BROADCAST_RGB_LIMITED: 2474 + intel_dp->color_range_auto = false; 2475 + intel_dp->color_range = DP_COLOR_RANGE_16_235; 2476 + break; 2477 + default: 2478 + return -EINVAL; 2479 + } 2481 2480 goto done; 2482 2481 } 2483 2482 ··· 2629 2606 2630 2607 intel_attach_force_audio_property(connector); 2631 2608 intel_attach_broadcast_rgb_property(connector); 2609 + intel_dp->color_range_auto = true; 2632 2610 2633 2611 if (is_edp(intel_dp)) { 2634 2612 drm_mode_create_scaling_mode_property(connector->dev);
+2
drivers/gpu/drm/i915/intel_drv.h
··· 343 343 u32 sdvox_reg; 344 344 int ddc_bus; 345 345 uint32_t color_range; 346 + bool color_range_auto; 346 347 bool has_hdmi_sink; 347 348 bool has_audio; 348 349 enum hdmi_force_audio force_audio; ··· 363 362 bool has_audio; 364 363 enum hdmi_force_audio force_audio; 365 364 uint32_t color_range; 365 + bool color_range_auto; 366 366 uint8_t link_bw; 367 367 uint8_t lane_count; 368 368 uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
+25 -4
drivers/gpu/drm/i915/intel_hdmi.c
··· 768 768 { 769 769 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 770 770 771 + if (intel_hdmi->color_range_auto) { 772 + /* See CEA-861-E - 5.1 Default Encoding Parameters */ 773 + if (intel_hdmi->has_hdmi_sink && 774 + drm_mode_cea_vic(adjusted_mode) > 1) 775 + intel_hdmi->color_range = SDVO_COLOR_RANGE_16_235; 776 + else 777 + intel_hdmi->color_range = 0; 778 + } 779 + 771 780 if (intel_hdmi->color_range) 772 781 adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE; 773 782 ··· 921 912 } 922 913 923 914 if (property == dev_priv->broadcast_rgb_property) { 924 - if (val == !!intel_hdmi->color_range) 925 - return 0; 926 - 927 - intel_hdmi->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0; 915 + switch (val) { 916 + case INTEL_BROADCAST_RGB_AUTO: 917 + intel_hdmi->color_range_auto = true; 918 + break; 919 + case INTEL_BROADCAST_RGB_FULL: 920 + intel_hdmi->color_range_auto = false; 921 + intel_hdmi->color_range = 0; 922 + break; 923 + case INTEL_BROADCAST_RGB_LIMITED: 924 + intel_hdmi->color_range_auto = false; 925 + intel_hdmi->color_range = SDVO_COLOR_RANGE_16_235; 926 + break; 927 + default: 928 + return -EINVAL; 929 + } 928 930 goto done; 929 931 } 930 932 ··· 984 964 { 985 965 intel_attach_force_audio_property(connector); 986 966 intel_attach_broadcast_rgb_property(connector); 967 + intel_hdmi->color_range_auto = true; 987 968 } 988 969 989 970 void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
+3 -2
drivers/gpu/drm/i915/intel_modes.c
··· 100 100 } 101 101 102 102 static const struct drm_prop_enum_list broadcast_rgb_names[] = { 103 - { 0, "Full" }, 104 - { 1, "Limited 16:235" }, 103 + { INTEL_BROADCAST_RGB_AUTO, "Automatic" }, 104 + { INTEL_BROADCAST_RGB_FULL, "Full" }, 105 + { INTEL_BROADCAST_RGB_LIMITED, "Limited 16:235" }, 105 106 }; 106 107 107 108 void
+31 -7
drivers/gpu/drm/i915/intel_sdvo.c
··· 103 103 * It is only valid when using TMDS encoding and 8 bit per color mode. 104 104 */ 105 105 uint32_t color_range; 106 + bool color_range_auto; 106 107 107 108 /** 108 109 * This is set if we're going to treat the device as TV-out. ··· 1065 1064 multiplier = intel_sdvo_get_pixel_multiplier(adjusted_mode); 1066 1065 intel_mode_set_pixel_multiplier(adjusted_mode, multiplier); 1067 1066 1067 + if (intel_sdvo->color_range_auto) { 1068 + /* See CEA-861-E - 5.1 Default Encoding Parameters */ 1069 + if (intel_sdvo->has_hdmi_monitor && 1070 + drm_mode_cea_vic(adjusted_mode) > 1) 1071 + intel_sdvo->color_range = SDVO_COLOR_RANGE_16_235; 1072 + else 1073 + intel_sdvo->color_range = 0; 1074 + } 1075 + 1068 1076 if (intel_sdvo->color_range) 1069 1077 adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE; 1070 1078 ··· 1910 1900 } 1911 1901 1912 1902 if (property == dev_priv->broadcast_rgb_property) { 1913 - if (val == !!intel_sdvo->color_range) 1914 - return 0; 1915 - 1916 - intel_sdvo->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0; 1903 + switch (val) { 1904 + case INTEL_BROADCAST_RGB_AUTO: 1905 + intel_sdvo->color_range_auto = true; 1906 + break; 1907 + case INTEL_BROADCAST_RGB_FULL: 1908 + intel_sdvo->color_range_auto = false; 1909 + intel_sdvo->color_range = 0; 1910 + break; 1911 + case INTEL_BROADCAST_RGB_LIMITED: 1912 + intel_sdvo->color_range_auto = false; 1913 + intel_sdvo->color_range = SDVO_COLOR_RANGE_16_235; 1914 + break; 1915 + default: 1916 + return -EINVAL; 1917 + } 1917 1918 goto done; 1918 1919 } 1919 1920 ··· 2221 2200 } 2222 2201 2223 2202 static void 2224 - intel_sdvo_add_hdmi_properties(struct intel_sdvo_connector *connector) 2203 + intel_sdvo_add_hdmi_properties(struct intel_sdvo *intel_sdvo, 2204 + struct intel_sdvo_connector *connector) 2225 2205 { 2226 2206 struct drm_device *dev = connector->base.base.dev; 2227 2207 2228 2208 intel_attach_force_audio_property(&connector->base.base); 2229 - if (INTEL_INFO(dev)->gen >= 4 && IS_MOBILE(dev)) 2209 + if (INTEL_INFO(dev)->gen >= 4 && IS_MOBILE(dev)) { 2230 2210 intel_attach_broadcast_rgb_property(&connector->base.base); 2211 + intel_sdvo->color_range_auto = true; 2212 + } 2231 2213 } 2232 2214 2233 2215 static bool ··· 2278 2254 2279 2255 intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); 2280 2256 if (intel_sdvo->is_hdmi) 2281 - intel_sdvo_add_hdmi_properties(intel_sdvo_connector); 2257 + intel_sdvo_add_hdmi_properties(intel_sdvo, intel_sdvo_connector); 2282 2258 2283 2259 return true; 2284 2260 }