[Intel-gfx] [PATCH 3/4] drm/i915/hdmi: split infoframe setting from infoframe type code

Jesse Barnes jbarnes at virtuousgeek.org
Wed Aug 3 18:22:55 CEST 2011


This makes it easier to add support for other infoframes (e.g. SPD,
vendor specific).

Signed-off-by: Jesse Barnes <jbarnes at virtuousgeek.org>
---
 drivers/gpu/drm/i915/i915_reg.h   |    1 +
 drivers/gpu/drm/i915/intel_drv.h  |    2 +
 drivers/gpu/drm/i915/intel_hdmi.c |  149 +++++++++++++++++++++++++-----------
 3 files changed, 106 insertions(+), 46 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index a7f7a34..b630816 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1505,6 +1505,7 @@
 #define   VIDEO_DIP_SELECT_AVI		(0 << 19)
 #define   VIDEO_DIP_SELECT_VENDOR	(1 << 19)
 #define   VIDEO_DIP_SELECT_SPD		(3 << 19)
+#define   VIDEO_DIP_SELECT_MASK		(3 << 19)
 #define   VIDEO_DIP_FREQ_ONCE		(0 << 16)
 #define   VIDEO_DIP_FREQ_VSYNC		(1 << 16)
 #define   VIDEO_DIP_FREQ_2VSYNC		(2 << 16)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 9ffa61e..45c403b 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -177,6 +177,8 @@ struct intel_crtc {
 #define to_intel_encoder(x) container_of(x, struct intel_encoder, base)
 #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
 
+#define DIP_HEADER_SIZE	5
+
 #define DIP_TYPE_AVI    0x82
 #define DIP_VERSION_AVI 0x2
 #define DIP_LEN_AVI     13
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index c220255..fe3469b 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -45,6 +45,8 @@ struct intel_hdmi {
 	bool has_hdmi_sink;
 	bool has_audio;
 	int force_audio;
+	void (*write_infoframe)(struct drm_encoder *encoder,
+				struct dip_infoframe *frame);
 };
 
 static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
@@ -58,37 +60,70 @@ static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector)
 			    struct intel_hdmi, base);
 }
 
-void intel_dip_infoframe_csum(struct dip_infoframe *avi_if)
+void intel_dip_infoframe_csum(struct dip_infoframe *frame)
 {
-	uint8_t *data = (uint8_t *)avi_if;
+	uint8_t *data = (uint8_t *)frame;
 	uint8_t sum = 0;
 	unsigned i;
 
-	avi_if->checksum = 0;
-	avi_if->ecc = 0;
+	frame->checksum = 0;
+	frame->ecc = 0;
 
-	for (i = 0; i < sizeof(*avi_if); i++)
+	/* Header isn't part of the checksum */
+	for (i = 5; i < frame->len; i++)
 		sum += data[i];
 
-	avi_if->checksum = 0x100 - sum;
+	frame->checksum = 0x100 - sum;
 }
 
-static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
+static u32 intel_infoframe_index(struct dip_infoframe *frame)
 {
-	struct dip_infoframe avi_if = {
-		.type = DIP_TYPE_AVI,
-		.ver = DIP_VERSION_AVI,
-		.len = DIP_LEN_AVI,
-	};
-	uint32_t *data = (uint32_t *)&avi_if;
+	u32 flags = 0;
+
+	switch (frame->type) {
+	case DIP_TYPE_AVI:
+		flags |= VIDEO_DIP_SELECT_AVI;
+		break;
+	case DIP_TYPE_SPD:
+		flags |= VIDEO_DIP_SELECT_SPD;
+		break;
+	default:
+		DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
+		break;
+	}
+
+	return flags;
+}
+
+static u32 intel_infoframe_flags(struct dip_infoframe *frame)
+{
+	u32 flags = 0;
+
+	switch (frame->type) {
+	case DIP_TYPE_AVI:
+		flags |= VIDEO_DIP_ENABLE_AVI | VIDEO_DIP_FREQ_VSYNC;
+		break;
+	case DIP_TYPE_SPD:
+		flags |= VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_FREQ_2VSYNC;
+		break;
+	default:
+		DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
+		break;
+	}
+
+	return flags;
+}
+
+static void i9xx_write_infoframe(struct drm_encoder *encoder,
+				 struct dip_infoframe *frame)
+{
+	uint32_t *data = (uint32_t *)frame;
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
-	u32 port;
-	unsigned i;
+	u32 port, flags, val = I915_READ(VIDEO_DIP_CTL);
+	unsigned i, len = DIP_HEADER_SIZE + frame->len;
 
-	if (!intel_hdmi->has_hdmi_sink)
-		return;
 
 	/* XXX first guess at handling video port, is this corrent? */
 	if (intel_hdmi->sdvox_reg == SDVOB)
@@ -98,52 +133,72 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
 	else
 		return;
 
-	I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port |
-		   VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC);
+	flags = intel_infoframe_index(frame);
+
+	val &= ~VIDEO_DIP_SELECT_MASK;
+
+	I915_WRITE(VIDEO_DIP_CTL, val | port | flags);
 
-	intel_dip_infoframe_csum(&avi_if);
-	for (i = 0; i < sizeof(avi_if); i += 4) {
+	for (i = 0; i < len; i += 4) {
 		I915_WRITE(VIDEO_DIP_DATA, *data);
 		data++;
 	}
 
-	I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port |
-		   VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC |
-		   VIDEO_DIP_ENABLE_AVI);
+	flags |= intel_infoframe_flags(frame);
+
+	I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | val | port | flags);
 }
 
-static void intel_ironlake_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
+static void ironlake_write_infoframe(struct drm_encoder *encoder,
+				     struct dip_infoframe *frame)
 {
-	struct dip_infoframe avi_if = {
-		.type = DIP_TYPE_AVI,
-		.ver = DIP_VERSION_AVI,
-		.len = DIP_LEN_AVI,
-	};
-	uint32_t *data = (uint32_t *)&avi_if;
+	uint32_t *data = (uint32_t *)frame;
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
 	struct drm_crtc *crtc = encoder->crtc;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
-	unsigned i;
-
-	if (!intel_hdmi->has_hdmi_sink)
-		return;
+	unsigned i, len = DIP_HEADER_SIZE + frame->len;
+	u32 flags, val = I915_READ(reg);
 
 	intel_wait_for_vblank(dev, intel_crtc->pipe);
 
-	I915_WRITE(reg, VIDEO_DIP_SELECT_AVI);
+	flags = intel_infoframe_index(frame);
 
-	intel_dip_infoframe_csum(&avi_if);
-	for (i = 0; i < sizeof(avi_if); i += 4) {
+	val &= ~VIDEO_DIP_SELECT_MASK;
+
+	I915_WRITE(reg, val | flags);
+
+	for (i = 0; i < len; i += 4) {
 		I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
 		data++;
 	}
 
-	I915_WRITE(reg, VIDEO_DIP_ENABLE | VIDEO_DIP_SELECT_AVI |
-		   VIDEO_DIP_FREQ_VSYNC | (DIP_LEN_AVI << 8) |
-		   VIDEO_DIP_ENABLE_AVI);
+	flags |= intel_infoframe_flags(frame);
+
+	I915_WRITE(reg, VIDEO_DIP_ENABLE | val | flags);
+}
+static void intel_set_infoframe(struct drm_encoder *encoder,
+				struct dip_infoframe *frame)
+{
+	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+
+	if (!intel_hdmi->has_hdmi_sink)
+		return;
+
+	intel_dip_infoframe_csum(frame);
+	intel_hdmi->write_infoframe(encoder, frame);
+}
+
+static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
+{
+	struct dip_infoframe avi_if = {
+		.type = DIP_TYPE_AVI,
+		.ver = DIP_VERSION_AVI,
+		.len = DIP_LEN_AVI,
+	};
+
+	intel_set_infoframe(encoder, &avi_if);
 }
 
 static void intel_hdmi_mode_set(struct drm_encoder *encoder,
@@ -183,10 +238,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
 	I915_WRITE(intel_hdmi->sdvox_reg, sdvox);
 	POSTING_READ(intel_hdmi->sdvox_reg);
 
-	if (HAS_PCH_SPLIT(dev))
-		intel_ironlake_hdmi_set_avi_infoframe(encoder);
-	else
-		intel_hdmi_set_avi_infoframe(encoder);
+	intel_hdmi_set_avi_infoframe(encoder);
 }
 
 static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
@@ -464,6 +516,11 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
 
 	intel_hdmi->sdvox_reg = sdvox_reg;
 
+	if (!HAS_PCH_SPLIT(dev))
+		intel_hdmi->write_infoframe = i9xx_write_infoframe;
+	else
+		intel_hdmi->write_infoframe = ironlake_write_infoframe;
+
 	drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs);
 
 	intel_hdmi_add_properties(intel_hdmi, connector);
-- 
1.7.4.1




More information about the Intel-gfx mailing list