[Intel-gfx] [PATCH] i915: enable AVI infoframe for intel_hdmi.c
David Härdeman
david at hardeman.nu
Thu Sep 9 00:52:17 CEST 2010
This patch enables the sending of AVI infoframes in
drivers/gpu/drm/i915/intel_hdmi.c.
My receiver currently loses sync when the HDMI output on my computer
(DG45FC motherboard) is switched from 800x600 (the BIOS resolution) to
1920x1080 as part of the boot. Fixable by switching inputs on the receiver
a couple of times.
With this patch, my receiver has not lost sync yet (> 40 tries).
I'm not sure that the general approach is sound, which is why I'm sending
this out for some feedback and review (in particular, is the SDVOB and SDVOC
handling in intel_hdmi_set_avi_infoframe() correct?).
Regards,
David Härdeman
---
drivers/gpu/drm/i915/i915_reg.h | 16 +++++++
drivers/gpu/drm/i915/intel_hdmi.c | 90 +++++++++++++++++++++++++++++++++++++
2 files changed, 106 insertions(+), 0 deletions(-)
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_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index ccd4c97..e3a92c2 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -48,6 +48,93 @@ static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
return container_of(enc_to_intel_encoder(encoder), struct intel_hdmi, base);
}
+#define DIP_TYPE_AVI 0x82
+#define DIP_VERSION_AVI 0x2
+#define DIP_LEN_AVI 13
+
+struct dip_avi_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));
+
+static void intel_hdmi_calc_csum(struct dip_avi_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 void intel_hdmi_write_avi_infoframe(struct drm_encoder *encoder,
+ struct dip_avi_infoframe *avi_if)
+{
+ struct drm_device *dev = encoder->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 *data = (u32 *)avi_if;
+ unsigned i;
+
+ for (i = 0; i < sizeof(*avi_if); i += 4) {
+ I915_WRITE(VIDEO_DIP_DATA, *data);
+ data++;
+ }
+
+}
+
+static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
+{
+ struct dip_avi_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;
+
+ intel_hdmi_calc_csum(&avi_if);
+ I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port | VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC);
+ POSTING_READ(VIDEO_DIP_ENABLE);
+ intel_hdmi_write_avi_infoframe(encoder, &avi_if);
+ 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 +154,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 +168,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)
More information about the Intel-gfx
mailing list