diff mbox

i915: enable AVI infoframe for intel_hdmi.c [v2]

Message ID 20100909210001.11985.1244.stgit@localhost.localdomain (mailing list archive)
State New, archived
Headers show

Commit Message

David Härdeman Sept. 9, 2010, 9 p.m. UTC
None
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 67e3ec1..6c2d9a6 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1330,6 +1330,22 @@ 
 #define   LVDS_B0B3_POWER_DOWN		(0 << 2)
 #define   LVDS_B0B3_POWER_UP		(3 << 2)
 
+/* Video Data Island Packet control */
+#define VIDEO_DIP_DATA		0x61178
+#define VIDEO_DIP_CTL		0x61170
+#define   VIDEO_DIP_ENABLE		(1 << 31)
+#define   VIDEO_DIP_PORT_B		(1 << 29)
+#define   VIDEO_DIP_PORT_C		(2 << 29)
+#define   VIDEO_DIP_ENABLE_AVI		(1 << 21)
+#define   VIDEO_DIP_ENABLE_VENDOR	(2 << 21)
+#define   VIDEO_DIP_ENABLE_SPD		(8 << 21)
+#define   VIDEO_DIP_SELECT_AVI		(0 << 19)
+#define   VIDEO_DIP_SELECT_VENDOR	(1 << 19)
+#define   VIDEO_DIP_SELECT_SPD		(3 << 19)
+#define   VIDEO_DIP_FREQ_ONCE		(0 << 16)
+#define   VIDEO_DIP_FREQ_VSYNC		(1 << 16)
+#define   VIDEO_DIP_FREQ_2VSYNC		(2 << 16)
+
 /* Panel power sequencing */
 #define PP_STATUS	0x61200
 #define   PP_ON		(1 << 31)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 0e92aa0..f5808e7 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -176,6 +176,30 @@  struct intel_crtc {
 #define enc_to_intel_encoder(x) container_of(x, struct intel_encoder, enc)
 #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
 
+#define DIP_TYPE_AVI    0x82
+#define DIP_VERSION_AVI 0x2
+#define DIP_LEN_AVI     13
+
+struct dip_infoframe {
+	uint8_t type;		/* HB0 */
+	uint8_t ver;		/* HB1 */
+	uint8_t len;		/* HB2 - body len, not including checksum */
+	uint8_t ecc;		/* HW specific, not part of the infoframe */
+	uint8_t checksum;	/* PB0 */
+	uint8_t Y_A_B_S;	/* PB1 - Y 6:5, A 4:4, B 3:2, S 1:0 */
+	uint8_t C_M_R;		/* PB2 - C 7:6, M 5:4, R 3:0 */
+	uint8_t ITC_EC_Q_SC;	/* PB3 - ITC 7:7, EC 6:4, Q 3:2, SC 1:0 */
+	uint8_t VIC;		/* PB4 - VIC 6:0 */
+	uint8_t PR;		/* PB5 - PR 3:0 */
+	/* PB6 - PB13 */
+	uint16_t top_bar_end;
+	uint16_t bottom_bar_start;
+	uint16_t left_bar_end;
+	uint16_t right_bar_start;
+	/* Pad to 32-bit */
+	uint16_t padding;
+} __attribute__((packed));
+
 struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg,
 				     const char *name);
 void intel_i2c_destroy(struct i2c_adapter *adapter);
@@ -186,6 +210,9 @@  void intel_i2c_reset_gmbus(struct drm_device *dev);
 
 extern void intel_crt_init(struct drm_device *dev);
 extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg);
+extern bool intel_hdmi_proc_infoframe(struct drm_encoder *encoder,
+				      struct dip_infoframe *avi_if,
+				      bool (*write_func)(struct drm_encoder *, uint8_t *)); 
 extern bool intel_sdvo_init(struct drm_device *dev, int output_device);
 extern void intel_dvo_init(struct drm_device *dev);
 extern void intel_tv_init(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index ccd4c97..4fc323c 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -48,6 +48,79 @@  static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
 	return container_of(enc_to_intel_encoder(encoder), struct intel_hdmi, base);
 }
 
+static void intel_hdmi_calc_infoframe_csum(struct dip_infoframe *avi_if)
+{
+	uint8_t *data = (uint8_t *)avi_if;
+	uint8_t sum = 0;
+	unsigned i;
+
+	avi_if->checksum = 0;
+	avi_if->ecc = 0;
+	avi_if->padding = 0;
+
+	for (i = 0; i < sizeof(*avi_if); i++)
+		sum += data[i];
+
+	avi_if->checksum = 0x100 - sum;
+}
+
+static bool intel_hdmi_write_avi_infoframe(struct drm_encoder *encoder,
+					   uint8_t *data)
+{
+	struct drm_device *dev = encoder->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	I915_WRITE(VIDEO_DIP_DATA, *((u32 *)data));
+	return true;
+}
+
+bool intel_hdmi_proc_infoframe(struct drm_encoder *encoder,
+			    struct dip_infoframe *avi_if,
+			    bool (*write_func)(struct drm_encoder *, uint8_t *))
+{
+	unsigned size;
+	uint8_t *data = (uint8_t *)avi_if;
+
+	intel_hdmi_calc_infoframe_csum(avi_if);
+	for (size = sizeof(*avi_if); size > 0; size -= 4) {
+		if (!write_func(encoder, data))
+			return false;
+		data += 4;
+	}
+	return true;
+}
+
+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,
+		.Y_A_B_S = 0x02,
+		.C_M_R = 0x28,
+	};
+	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;
+
+	if (!intel_hdmi->has_hdmi_sink)
+		return;
+
+	if (intel_hdmi->sdvox_reg == SDVOB)
+		port = VIDEO_DIP_PORT_B;
+	else if (intel_hdmi->sdvox_reg == SDVOC)
+		port = VIDEO_DIP_PORT_C;
+	else
+		return;
+
+	I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port | VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC);
+	POSTING_READ(VIDEO_DIP_ENABLE);
+	intel_hdmi_proc_infoframe(encoder, &avi_if, intel_hdmi_write_avi_infoframe);
+	I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port | VIDEO_DIP_ENABLE_AVI | VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC);
+	POSTING_READ(VIDEO_DIP_ENABLE);
+}
+
 static void intel_hdmi_mode_set(struct drm_encoder *encoder,
 				struct drm_display_mode *mode,
 				struct drm_display_mode *adjusted_mode)
@@ -67,6 +140,7 @@  static void intel_hdmi_mode_set(struct drm_encoder *encoder,
 
 	if (intel_hdmi->has_hdmi_sink) {
 		sdvox |= SDVO_AUDIO_ENABLE;
+		sdvox |= SDVO_NULL_PACKETS_DURING_VSYNC;
 		if (HAS_PCH_CPT(dev))
 			sdvox |= HDMI_MODE_SELECT;
 	}
@@ -80,6 +154,8 @@  static void intel_hdmi_mode_set(struct drm_encoder *encoder,
 
 	I915_WRITE(intel_hdmi->sdvox_reg, sdvox);
 	POSTING_READ(intel_hdmi->sdvox_reg);
+
+	intel_hdmi_set_avi_infoframe(encoder);
 }
 
 static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 093e914..b99ec72 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -874,115 +874,32 @@  static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo)
 }
 #endif
 
-static bool intel_sdvo_set_hdmi_buf(struct intel_sdvo *intel_sdvo,
-				    int index,
-				    uint8_t *data, int8_t size, uint8_t tx_rate)
+static bool intel_sdvo_write_avi_infoframe(struct drm_encoder *encoder,
+					   uint8_t *data)
 {
-    uint8_t set_buf_index[2];
-
-    set_buf_index[0] = index;
-    set_buf_index[1] = 0;
-
-    if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX,
-			      set_buf_index, 2))
-	    return false;
-
-    for (; size > 0; size -= 8) {
-	if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_DATA, data, 8))
-		return false;
-
-	data += 8;
-    }
-
-    return intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_TXRATE, &tx_rate, 1);
-}
-
-static uint8_t intel_sdvo_calc_hbuf_csum(uint8_t *data, uint8_t size)
-{
-	uint8_t csum = 0;
-	int i;
-
-	for (i = 0; i < size; i++)
-		csum += data[i];
+	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
 
-	return 0x100 - csum;
+	return intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_DATA, data, 4);
 }
 
-#define DIP_TYPE_AVI	0x82
-#define DIP_VERSION_AVI	0x2
-#define DIP_LEN_AVI	13
-
-struct dip_infoframe {
-	uint8_t type;
-	uint8_t version;
-	uint8_t len;
-	uint8_t checksum;
-	union {
-		struct {
-			/* Packet Byte #1 */
-			uint8_t S:2;
-			uint8_t B:2;
-			uint8_t A:1;
-			uint8_t Y:2;
-			uint8_t rsvd1:1;
-			/* Packet Byte #2 */
-			uint8_t R:4;
-			uint8_t M:2;
-			uint8_t C:2;
-			/* Packet Byte #3 */
-			uint8_t SC:2;
-			uint8_t Q:2;
-			uint8_t EC:3;
-			uint8_t ITC:1;
-			/* Packet Byte #4 */
-			uint8_t VIC:7;
-			uint8_t rsvd2:1;
-			/* Packet Byte #5 */
-			uint8_t PR:4;
-			uint8_t rsvd3:4;
-			/* Packet Byte #6~13 */
-			uint16_t top_bar_end;
-			uint16_t bottom_bar_start;
-			uint16_t left_bar_end;
-			uint16_t right_bar_start;
-		} avi;
-		struct {
-			/* Packet Byte #1 */
-			uint8_t channel_count:3;
-			uint8_t rsvd1:1;
-			uint8_t coding_type:4;
-			/* Packet Byte #2 */
-			uint8_t sample_size:2; /* SS0, SS1 */
-			uint8_t sample_frequency:3;
-			uint8_t rsvd2:3;
-			/* Packet Byte #3 */
-			uint8_t coding_type_private:5;
-			uint8_t rsvd3:3;
-			/* Packet Byte #4 */
-			uint8_t channel_allocation;
-			/* Packet Byte #5 */
-			uint8_t rsvd4:3;
-			uint8_t level_shift:4;
-			uint8_t downmix_inhibit:1;
-		} audio;
-		uint8_t payload[28];
-	} __attribute__ ((packed)) u;
-} __attribute__((packed));
-
-static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo,
-					 struct drm_display_mode * mode)
+static bool intel_sdvo_set_avi_infoframe(struct drm_encoder *encoder)
 {
+	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
 	struct dip_infoframe avi_if = {
 		.type = DIP_TYPE_AVI,
-		.version = DIP_VERSION_AVI,
+		.ver = DIP_VERSION_AVI,
 		.len = DIP_LEN_AVI,
 	};
+	uint8_t buf[2] = { 1, 0 };
+
+	if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX, buf, 2))
+		return false;
+
+	if (!intel_hdmi_proc_infoframe(encoder, &avi_if, intel_sdvo_write_avi_infoframe))
+		return false;
 
-	avi_if.checksum = intel_sdvo_calc_hbuf_csum((uint8_t *)&avi_if,
-						    4 + avi_if.len);
-	return intel_sdvo_set_hdmi_buf(intel_sdvo, 1, (uint8_t *)&avi_if,
-				       4 + avi_if.len,
-				       SDVO_HBUF_TX_VSYNC);
+	buf[0] = SDVO_HBUF_TX_VSYNC;
+	return intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_TXRATE, buf, 1);
 }
 
 static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo)
@@ -1114,7 +1031,7 @@  static void intel_sdvo_mode_set(struct drm_encoder *encoder,
 		return;
 
 	if (intel_sdvo->is_hdmi) {
-		if (!intel_sdvo_set_avi_infoframe(intel_sdvo, mode))
+		if (!intel_sdvo_set_avi_infoframe(encoder))
 			return;
 
 		sdvox |= SDVO_AUDIO_ENABLE;