[PATCH 5/5] drm/i2c: tda998x: improve correctness of quantisation range

Russell King rmk+kernel at armlinux.org.uk
Fri Jan 25 09:43:29 UTC 2019


CEA-861 says: "A Source shall not send a non-zero Q value that does
not correspond to the default RGB Quantization Range for the
transmitted Picture unless the Sink indicates support for the Q bit
in a Video Capabilities Data Block."

Make TDA998x compliant by using the helper to set the quantisation
range in the infoframe, and using the TDA998x's colour scaling to
appropriately adjust the RGB values sent to the monitor.

This ensures that monitors that do not support the Q bit are sent
RGB values that are within the expected range.  Monitors with
support for the Q bit will be sent full-range RGB.

Signed-off-by: Russell King <rmk+kernel at armlinux.org.uk>
---
 drivers/gpu/drm/i2c/tda998x_drv.c | 39 ++++++++++++++++++++++++++++++++++-----
 1 file changed, 34 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index b0ed2ef49c62..7d9aea79aff2 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -50,6 +50,8 @@ struct tda998x_priv {
 	bool is_on;
 	bool supports_infoframes;
 	bool sink_has_audio;
+	bool has_rgb_quant;
+	enum hdmi_quantization_range rgb_quant_range;
 	u8 vip_cntrl_0;
 	u8 vip_cntrl_1;
 	u8 vip_cntrl_2;
@@ -869,7 +871,9 @@ tda998x_write_avi(struct tda998x_priv *priv, const struct drm_display_mode *mode
 
 	drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
 						 &priv->connector, mode);
-	frame.avi.quantization_range = HDMI_QUANTIZATION_RANGE_FULL;
+	drm_hdmi_avi_infoframe_quant_range(&frame.avi, mode,
+					   priv->rgb_quant_range,
+					   priv->has_rgb_quant, false);
 
 	tda998x_write_if(priv, DIP_IF_FLAGS_IF2, REG_IF2_HB0, &frame);
 }
@@ -1259,6 +1263,7 @@ static int tda998x_connector_get_modes(struct drm_connector *connector)
 	mutex_lock(&priv->audio_mutex);
 	n = drm_add_edid_modes(connector, edid);
 	priv->sink_has_audio = drm_detect_monitor_audio(edid);
+	priv->has_rgb_quant = drm_rgb_quant_range_selectable(edid);
 	mutex_unlock(&priv->audio_mutex);
 
 	kfree(edid);
@@ -1385,6 +1390,15 @@ static void tda998x_bridge_mode_set(struct drm_bridge *bridge,
 	u8 reg, div, rep, sel_clk;
 
 	/*
+	 * Since we are "computer" like, our source invariably produces
+	 * full-range RGB.  If the monitor supports full-range, then use
+	 * it, otherwise reduce to limited-range.
+	 */
+	priv->rgb_quant_range = priv->has_rgb_quant ?
+		HDMI_QUANTIZATION_RANGE_FULL :
+		drm_default_rgb_quant_range(adjusted_mode);
+
+	/*
 	 * Internally TDA998x is using ITU-R BT.656 style sync but
 	 * we get VESA style sync. TDA998x is using a reference pixel
 	 * relative to ITU to sync to the input frame and for output
@@ -1499,10 +1513,25 @@ static void tda998x_bridge_mode_set(struct drm_bridge *bridge,
 	reg_write(priv, REG_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(div) |
 			PLL_SERIAL_2_SRL_PR(rep));
 
-	/* set color matrix bypass flag: */
-	reg_write(priv, REG_MAT_CONTRL, MAT_CONTRL_MAT_BP |
-				MAT_CONTRL_MAT_SC(1));
-	reg_set(priv, REG_FEAT_POWERDOWN, FEAT_POWERDOWN_CSC);
+	/* set color matrix according to output rgb quant range */
+	if (priv->rgb_quant_range == HDMI_QUANTIZATION_RANGE_LIMITED) {
+		static u8 tda998x_full_to_limited_range[] = {
+			MAT_CONTRL_MAT_SC(2),
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x03, 0x6f, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x03, 0x6f, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x03, 0x6f,
+			0x00, 0x40, 0x00, 0x40, 0x00, 0x40
+		};
+		reg_clear(priv, REG_FEAT_POWERDOWN, FEAT_POWERDOWN_CSC);
+		reg_write_range(priv, REG_MAT_CONTRL,
+				tda998x_full_to_limited_range,
+				sizeof(tda998x_full_to_limited_range));
+	} else {
+		reg_write(priv, REG_MAT_CONTRL, MAT_CONTRL_MAT_BP |
+					MAT_CONTRL_MAT_SC(1));
+		reg_set(priv, REG_FEAT_POWERDOWN, FEAT_POWERDOWN_CSC);
+	}
 
 	/* set BIAS tmds value: */
 	reg_write(priv, REG_ANA_GENERAL, 0x09);
-- 
2.7.4



More information about the dri-devel mailing list