diff mbox

[3/4] drm/i915: Implement limited color range for SDVO properly

Message ID 1439477755-24811-4-git-send-email-ville.syrjala@linux.intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Ville Syrjälä Aug. 13, 2015, 2:55 p.m. UTC
From: Ville Syrjälä <ville.syrjala@linux.intel.com>

The SDVO/HDMI port register limited color range bit can only be used
with TMDS encoding and not SDVO encoding, ie. to be used only when
using the port as a HDMI port as opposed to a SDVO port.

To implement limited color range support for SDVO->HDMI we need to ask
the SDVO device to do the range compression. Do so, but first check if
the device even supports the colorimetry selection.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_sdvo.c | 63 +++++++++++++++++++++++++++------------
 1 file changed, 44 insertions(+), 19 deletions(-)
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 33e58c1..0d1fed4 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -85,6 +85,8 @@  struct intel_sdvo {
 	 */
 	struct intel_sdvo_caps caps;
 
+	uint8_t colorimetry_cap;
+
 	/* Pixel clock limitations reported by the SDVO device, in kHz */
 	int pixel_clock_min, pixel_clock_max;
 
@@ -1164,14 +1166,16 @@  static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
 
 	pipe_config->has_hdmi_sink = intel_sdvo->has_hdmi_monitor;
 
-	if (intel_sdvo->color_range_auto) {
-		/* See CEA-861-E - 5.1 Default Encoding Parameters */
-		pipe_config->limited_color_range =
-			pipe_config->has_hdmi_sink &&
-			drm_match_cea_mode(adjusted_mode) > 1;
-	} else {
-		pipe_config->limited_color_range =
-			intel_sdvo->limited_color_range;
+	if (intel_sdvo->colorimetry_cap & SDVO_COLORIMETRY_RGB220) {
+		if (intel_sdvo->color_range_auto) {
+			/* See CEA-861-E - 5.1 Default Encoding Parameters */
+			pipe_config->limited_color_range =
+				pipe_config->has_hdmi_sink &&
+				drm_match_cea_mode(adjusted_mode) > 1;
+		} else {
+			pipe_config->limited_color_range =
+				intel_sdvo->limited_color_range;
+		}
 	}
 
 	/* Clock computation needs to happen after pixel multiplier. */
@@ -1232,8 +1236,12 @@  static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder)
 
 	if (crtc->config->has_hdmi_sink) {
 		intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI);
-		intel_sdvo_set_colorimetry(intel_sdvo,
-					   SDVO_COLORIMETRY_RGB256);
+		if (crtc->config->limited_color_range)
+			intel_sdvo_set_colorimetry(intel_sdvo,
+						   SDVO_COLORIMETRY_RGB220);
+		else
+			intel_sdvo_set_colorimetry(intel_sdvo,
+						   SDVO_COLORIMETRY_RGB256);
 		intel_sdvo_set_avi_infoframe(intel_sdvo, adjusted_mode);
 	} else
 		intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI);
@@ -1265,10 +1273,6 @@  static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder)
 		/* The real mode polarity is set by the SDVO commands, using
 		 * struct intel_sdvo_dtd. */
 		sdvox = SDVO_VSYNC_ACTIVE_HIGH | SDVO_HSYNC_ACTIVE_HIGH;
-		/* FIXME: this bit is only valid when using TMDS
-		 * encoding and 8 bit per color mode. */
-		if (!HAS_PCH_SPLIT(dev) && crtc->config->limited_color_range)
-			sdvox |= HDMI_COLOR_RANGE_16_235;
 		if (INTEL_INFO(dev)->gen < 5)
 			sdvox |= SDVO_BORDER_ENABLE;
 	} else {
@@ -1418,8 +1422,16 @@  static void intel_sdvo_get_config(struct intel_encoder *encoder,
 		}
 	}
 
-	if (sdvox & HDMI_COLOR_RANGE_16_235)
-		pipe_config->limited_color_range = true;
+	if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_COLORIMETRY,
+				 &val, 1)) {
+		switch (val) {
+		case SDVO_COLORIMETRY_RGB220:
+			pipe_config->limited_color_range = true;
+			break;
+		default:
+			break;
+		}
+	}
 
 	if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ENCODE,
 				 &val, 1)) {
@@ -1570,6 +1582,17 @@  static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct in
 	return true;
 }
 
+static uint8_t intel_sdvo_get_colorimetry_cap(struct intel_sdvo *intel_sdvo)
+{
+	uint8_t cap;
+
+	if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_COLORIMETRY_CAP,
+				  &cap, sizeof(cap)))
+		return SDVO_COLORIMETRY_RGB256;
+
+	return cap;
+}
+
 static uint16_t intel_sdvo_get_hotplug_support(struct intel_sdvo *intel_sdvo)
 {
 	struct drm_device *dev = intel_sdvo->base.base.dev;
@@ -2373,10 +2396,9 @@  static void
 intel_sdvo_add_hdmi_properties(struct intel_sdvo *intel_sdvo,
 			       struct intel_sdvo_connector *connector)
 {
-	struct drm_device *dev = connector->base.base.dev;
-
 	intel_attach_force_audio_property(&connector->base.base);
-	if (INTEL_INFO(dev)->gen >= 4 && IS_MOBILE(dev)) {
+
+	if (intel_sdvo->colorimetry_cap & SDVO_COLORIMETRY_RGB220) {
 		intel_attach_broadcast_rgb_property(&connector->base.base);
 		intel_sdvo->color_range_auto = true;
 	}
@@ -2958,6 +2980,9 @@  bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
 	if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
 		goto err;
 
+	intel_sdvo->colorimetry_cap =
+		intel_sdvo_get_colorimetry_cap(intel_sdvo);
+
 	if (intel_sdvo_output_setup(intel_sdvo,
 				    intel_sdvo->caps.output_flags) != true) {
 		DRM_DEBUG_KMS("SDVO output failed to setup on %s\n",