[Intel-gfx] [PATCH 3/3] drm/i915: Make infoframe trnsmission more reliable on g4x

ville.syrjala at linux.intel.com ville.syrjala at linux.intel.com
Thu Jan 23 22:15:35 CET 2014


From: Ville Syrjälä <ville.syrjala at linux.intel.com>

On g4x there's just one video DIP, but there can be two HDMI/DVI
ports. Currently even a DVI monitor on another port can clobber
the infoframes meant for a real HDMI monitor on the other port.

Make sure we only ever send DIPs to one port. The first port with a
HDMI sink to get there gets to own the DIP until such time that the
port is completely turned off (ie. not just DPMS off). If there are
two HDMI sinks attached, the one to arrive second doesn't get any
infoframes. And if there's a DVI sink on the other port, it will
no longer disable DIP transmission for the other port.

Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
---
 drivers/gpu/drm/i915/intel_hdmi.c | 32 +++++++++++++++++++++++++++++++-
 1 file changed, 31 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 9a8c7f8..673e371 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -427,6 +427,15 @@ static void g4x_set_infoframes(struct drm_encoder *encoder,
 
 	assert_hdmi_port_disabled(intel_hdmi);
 
+	/* Is DIP already being transmitted on another port? */
+	if ((val & VIDEO_DIP_ENABLE) != 0 &&
+	    (val & VIDEO_DIP_PORT_MASK) != port) {
+		if (intel_hdmi->has_hdmi_sink)
+			DRM_DEBUG_KMS("Video DIP busy. Can't transmit on port %c\n",
+				      port_name(intel_dig_port->port));
+		return;
+	}
+
 	/* If the registers were not initialized yet, they might be zeroes,
 	 * which means we're selecting the AVI DIP and we're setting its
 	 * frequency to once. This seems to really confuse the HW and make
@@ -439,7 +448,8 @@ static void g4x_set_infoframes(struct drm_encoder *encoder,
 	val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
 
 	if (!intel_hdmi->has_hdmi_sink) {
-		if (!(val & VIDEO_DIP_ENABLE))
+		if ((val & VIDEO_DIP_ENABLE) == 0 ||
+		    (val & VIDEO_DIP_PORT_MASK) != port)
 			return;
 		val &= ~VIDEO_DIP_ENABLE;
 		I915_WRITE(reg, val);
@@ -1143,6 +1153,23 @@ static void vlv_hdmi_post_disable(struct intel_encoder *encoder)
 	mutex_unlock(&dev_priv->dpio_lock);
 }
 
+static void g4x_hdmi_off(struct intel_encoder *encoder)
+{
+	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+	struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
+	u32 port = VIDEO_DIP_PORT(intel_dig_port->port);
+	u32 reg = VIDEO_DIP_CTL;
+	u32 val = I915_READ(reg);
+
+	if ((val & VIDEO_DIP_ENABLE) == 0 ||
+	    (val & VIDEO_DIP_PORT_MASK) != port)
+		return;
+
+	val &= ~VIDEO_DIP_ENABLE;
+	I915_WRITE(reg, val);
+	POSTING_READ(reg);
+}
+
 static void intel_hdmi_destroy(struct drm_connector *connector)
 {
 	drm_connector_cleanup(connector);
@@ -1285,6 +1312,9 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port)
 		intel_encoder->enable = intel_enable_hdmi;
 	}
 
+	if (IS_G4X(dev))
+		intel_encoder->off = g4x_hdmi_off;
+
 	intel_encoder->type = INTEL_OUTPUT_HDMI;
 	intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
 	intel_encoder->cloneable = false;
-- 
1.8.3.2




More information about the Intel-gfx mailing list