[patch 2/2] intel: enable SDVO-HDMI output

Hong Liu hong.liu at intel.com
Tue Jun 3 00:45:57 PDT 2008


This patch enables the SDVO-HDMI output on my ASUS P5E-VM
motherboard(G35 platform). I can have display on our SONY TV
with 1920x1080 resolution.

You may need patch 1 (DSPARB fix 2nd) to get correct display.
VT switch is not working on HDMI output currently.

Thanks,
Hong

diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c
index 2379127..3360af5 100644
--- a/src/i830_sdvo.c
+++ b/src/i830_sdvo.c
@@ -92,6 +92,9 @@ struct i830_sdvo_priv {
      */
     struct i830_sdvo_tv_format tv_format;
 
+    /** supported encoding mode, used to determine whether HDMI is supported */
+    struct i830_sdvo_encode encode;
+
     /** DDC bus used by this SDVO output */
     uint8_t ddc_bus;
 
@@ -225,10 +228,23 @@ const static struct _sdvo_cmd_name {
     SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_POWER_STATES),
     SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ENCODER_POWER_STATE),
     SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ENCODER_POWER_STATE),
-    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_RESOLUTION_SUPPORT),
+    //SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_RESOLUTION_SUPPORT),
     SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CONTROL_BUS_SWITCH),
     SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT),
     SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS),
+    /* HDMI op code */
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPP_ENCODE),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ENCODE),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PIXEL_REPLI),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_COLORIMETRY_CAP),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_COLORIMETRY),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_AUDIO_ENCRYPT_PREFER),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_AUDIO_STAT),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_INDEX),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HBUF_INDEX),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_INFO),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_AV_SPLIT),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_TXRATE),
 };
 
 static I2CSlaveAddr slaveAddr;
@@ -741,6 +757,190 @@ i830_sdvo_get_mode_from_dtd(DisplayModePtr mode, struct i830_sdvo_dtd *dtd)
 }
 
 static Bool
+i830_sdvo_get_supp_encode(xf86OutputPtr output, struct i830_sdvo_encode *encode)
+{
+    uint8_t status;
+
+    i830_sdvo_write_cmd(output, SDVO_CMD_GET_SUPP_ENCODE, NULL, 0);
+    status = i830_sdvo_read_response(output, encode, sizeof(*encode));
+    if (status != SDVO_CMD_STATUS_SUCCESS) {
+	memset(encode, 0, sizeof(*encode));
+	return FALSE;
+    }
+
+    return TRUE;
+}
+
+static Bool
+i830_sdvo_set_encode(xf86OutputPtr output, uint8_t mode)
+{
+    uint8_t status;
+
+    i830_sdvo_write_cmd(output, SDVO_CMD_SET_ENCODE, &mode, 1);
+    status = i830_sdvo_read_response(output, NULL, 0);
+
+    return (status == SDVO_CMD_STATUS_SUCCESS);
+}
+
+static Bool
+i830_sdvo_set_colorimetry(xf86OutputPtr output, uint8_t mode)
+{
+    uint8_t status;
+
+    i830_sdvo_write_cmd(output, SDVO_CMD_SET_COLORIMETRY, &mode, 1);
+    status = i830_sdvo_read_response(output, NULL, 0);
+
+    return (status == SDVO_CMD_STATUS_SUCCESS);
+}
+
+static Bool
+i830_sdvo_set_pixel_repli(xf86OutputPtr output, uint8_t repli)
+{
+    uint8_t status;
+
+    i830_sdvo_write_cmd(output, SDVO_CMD_SET_PIXEL_REPLI, &repli, 1);
+    status = i830_sdvo_read_response(output, NULL, 0);
+
+    return (status == SDVO_CMD_STATUS_SUCCESS);
+}
+
+static void i830_sdvo_dump_hdmi_buf(xf86OutputPtr output)
+{
+    int i, j;
+    uint8_t set_buf_index[2];
+    uint8_t av_split;
+    uint8_t buf_size;
+    uint8_t buf[48];
+    uint8_t *pos;
+
+    
+    i830_sdvo_write_cmd(output, SDVO_CMD_GET_HBUF_AV_SPLIT, NULL, 0);
+    i830_sdvo_read_response(output, &av_split, 1);
+
+    for (i = 0; i <= av_split; i++) {
+	set_buf_index[0] = i; set_buf_index[1] = 0;
+	i830_sdvo_write_cmd(output, SDVO_CMD_SET_HBUF_INDEX,
+				set_buf_index, 2);
+	i830_sdvo_write_cmd(output, SDVO_CMD_GET_HBUF_INFO, NULL, 0);
+	i830_sdvo_read_response(output, &buf_size, 1);
+
+	pos = buf;
+	for (j = 0; j <= buf_size; j += 8) {
+	    i830_sdvo_write_cmd(output, SDVO_CMD_GET_HBUF_DATA, NULL, 0);
+	    i830_sdvo_read_response(output, pos, 8);
+	    pos += 8;
+    	}
+    }
+}
+
+static void i830_sdvo_set_hdmi_buf(xf86OutputPtr output, int index,
+				uint8_t *data, int8_t size, uint8_t tx_rate)
+{
+    uint8_t set_buf_index[2];
+
+    set_buf_index[0] = index;
+    set_buf_index[1] = 0;
+
+    i830_sdvo_write_cmd(output, SDVO_CMD_SET_HBUF_INDEX, set_buf_index, 2);
+
+    for (; size > 0; size -= 8) {
+	i830_sdvo_write_cmd(output, SDVO_CMD_SET_HBUF_DATA, data, 8);
+	data += 8;
+    }
+
+    i830_sdvo_write_cmd(output, SDVO_CMD_SET_HBUF_TXRATE, &tx_rate, 1);
+}
+
+static uint8_t i830_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];
+
+    return 0x100 - csum;
+}
+
+#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 CC:3;
+	    uint8_t rsvd1:1;
+	    uint8_t CT:4;
+	    /* Packet Byte #2 */
+	    uint8_t SS:2;
+	    uint8_t SF:3;
+	    uint8_t rsvd2:3;
+	    /* Packet Byte #3 */
+	    uint8_t CXT:5;
+	    uint8_t rsvd3:3;
+	    /* Packet Byte #4 */
+	    uint8_t CA;
+	    /* Packet Byte #5 */
+	    uint8_t rsvd4:3;
+	    uint8_t LSV:4;
+	    uint8_t DM_INH:1;
+	} audio;
+	uint8_t payload[28];
+    } __attribute__ ((packed)) u;
+} __attribute__((packed));
+
+static void i830_sdvo_set_avi_infoframe(xf86OutputPtr output,
+					DisplayModePtr mode)
+{
+    I830OutputPrivatePtr    intel_output = output->driver_private;
+    struct dip_infoframe avi_if = {
+	.type = DIP_TYPE_AVI,
+	.version = DIP_VERSION_AVI,
+	.len = DIP_LEN_AVI,
+    };
+
+    avi_if.u.avi.PR = i830_sdvo_get_pixel_multiplier(mode) - 1;
+    avi_if.checksum = i830_sdvo_calc_hbuf_csum((uint8_t *)&avi_if,
+	    				4 + avi_if.len);
+    i830_sdvo_set_hdmi_buf(output, 1, (uint8_t *)&avi_if, 4 + avi_if.len,
+	    		SDVO_HBUF_TX_VSYNC);
+}
+
+static Bool
 i830_sdvo_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
 		     DisplayModePtr adjusted_mode)
 {
@@ -827,6 +1027,9 @@ i830_sdvo_mode_set(xf86OutputPtr output, DisplayModePtr mode,
 			&in_out, sizeof(in_out));
     status = i830_sdvo_read_response(output, NULL, 0);
 
+    if (dev_priv->encode.hdmi_rev)
+	i830_sdvo_set_avi_infoframe(output, mode);
+
     i830_sdvo_get_dtd_from_mode(&input_dtd, mode);
 
     /* If it's a TV, we already set the output timing in mode_fixup.
@@ -1201,6 +1404,15 @@ i830_sdvo_dump_device(xf86OutputPtr output)
     i830_sdvo_dump_cmd(output, SDVO_CMD_GET_TV_FORMAT);
     i830_sdvo_dump_cmd(output, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT);
     i830_sdvo_dump_cmd(output, SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS);
+
+    i830_sdvo_dump_cmd(output, SDVO_CMD_GET_SUPP_ENCODE);
+    i830_sdvo_dump_cmd(output, SDVO_CMD_GET_ENCODE);
+    i830_sdvo_dump_cmd(output, SDVO_CMD_GET_PIXEL_REPLI);
+    i830_sdvo_dump_cmd(output, SDVO_CMD_GET_COLORIMETRY_CAP);
+    i830_sdvo_dump_cmd(output, SDVO_CMD_GET_COLORIMETRY);
+    i830_sdvo_dump_cmd(output, SDVO_CMD_GET_AUDIO_ENCRYPT_PREFER);
+    i830_sdvo_dump_cmd(output, SDVO_CMD_GET_AUDIO_STAT);
+    i830_sdvo_dump_hdmi_buf(output);
 }
 
 void
@@ -1618,17 +1830,22 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
 
     i830_sdvo_get_capabilities(output, &dev_priv->caps);
 
-    if (dev_priv->caps.output_flags & SDVO_OUTPUT_TMDS0)
-    {
-	dev_priv->controlled_output = SDVO_OUTPUT_TMDS0;
-        output->subpixel_order = SubPixelHorizontalRGB;
-	name_prefix="TMDS";
-    }
-    else if (dev_priv->caps.output_flags & SDVO_OUTPUT_TMDS1)
+    if (dev_priv->caps.output_flags & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1))
     {
-	dev_priv->controlled_output = SDVO_OUTPUT_TMDS1;
+	if (dev_priv->caps.output_flags & SDVO_OUTPUT_TMDS0)
+	    dev_priv->controlled_output = SDVO_OUTPUT_TMDS0;
+	else
+	    dev_priv->controlled_output = SDVO_OUTPUT_TMDS1;
         output->subpixel_order = SubPixelHorizontalRGB;
 	name_prefix="TMDS";
+
+	i830_sdvo_get_supp_encode(output, &dev_priv->encode);
+	if (dev_priv->encode.hdmi_rev != 0) {
+	    /* enable hdmi encoding mode if supported */
+	    i830_sdvo_set_encode(output, SDVO_ENCODE_HDMI);
+	    i830_sdvo_set_colorimetry(output, SDVO_COLORIMETRY_RGB256);
+	    name_prefix = "HDMI";
+	}
     }
     else if (dev_priv->caps.output_flags & SDVO_OUTPUT_SVID0)
     {
diff --git a/src/i830_sdvo_regs.h b/src/i830_sdvo_regs.h
index dc2522a..cdf3e27 100644
--- a/src/i830_sdvo_regs.h
+++ b/src/i830_sdvo_regs.h
@@ -503,7 +503,7 @@ struct i830_sdvo_enhancements_arg {
 # define SDVO_DITHER_ON						(1 << 0)
 # define SDVO_DITHER_DEFAULT_ON					(1 << 1)
 
-#define SDVO_CMD_SET_TV_RESOLUTION_SUPPORT		0x93
+//#define SDVO_CMD_SET_TV_RESOLUTION_SUPPORT		0x93
 
 #define SDVO_CMD_SET_CONTROL_BUS_SWITCH			0x7a
 # define SDVO_CONTROL_BUS_PROM				(1 << 0)
@@ -511,3 +511,39 @@ struct i830_sdvo_enhancements_arg {
 # define SDVO_CONTROL_BUS_DDC2				(1 << 2)
 # define SDVO_CONTROL_BUS_DDC3				(1 << 3)
 
+/* HDMI op codes */
+#define SDVO_CMD_GET_SUPP_ENCODE	0x9d
+#define SDVO_CMD_GET_ENCODE		0x9e
+#define SDVO_CMD_SET_ENCODE		0x9f
+  #define SDVO_ENCODE_DVI	0x0
+  #define SDVO_ENCODE_HDMI	0x1
+#define SDVO_CMD_SET_PIXEL_REPLI	0x8b
+#define SDVO_CMD_GET_PIXEL_REPLI	0x8c
+#define SDVO_CMD_GET_COLORIMETRY_CAP	0x8d
+#define SDVO_CMD_SET_COLORIMETRY	0x8e
+  #define SDVO_COLORIMETRY_RGB256   0x0
+  #define SDVO_COLORIMETRY_RGB220   0x1
+  #define SDVO_COLORIMETRY_YCrCb422 0x3
+  #define SDVO_COLORIMETRY_YCrCb444 0x4
+#define SDVO_CMD_GET_COLORIMETRY	0x8f
+#define SDVO_CMD_GET_AUDIO_ENCRYPT_PREFER 0x90
+#define SDVO_CMD_SET_AUDIO_STAT		0x91
+#define SDVO_CMD_GET_AUDIO_STAT		0x92
+#define SDVO_CMD_SET_HBUF_INDEX		0x93
+#define SDVO_CMD_GET_HBUF_INDEX		0x94
+#define SDVO_CMD_GET_HBUF_INFO		0x95
+#define SDVO_CMD_SET_HBUF_AV_SPLIT	0x96
+#define SDVO_CMD_GET_HBUF_AV_SPLIT	0x97
+#define SDVO_CMD_SET_HBUF_DATA		0x98
+#define SDVO_CMD_GET_HBUF_DATA		0x99
+#define SDVO_CMD_SET_HBUF_TXRATE	0x9a
+#define SDVO_CMD_GET_HBUF_TXRATE	0x9b
+  #define SDVO_HBUF_TX_DISABLED	(0 << 6)
+  #define SDVO_HBUF_TX_ONCE	(2 << 6)
+  #define SDVO_HBUF_TX_VSYNC	(3 << 6)
+#define SDVO_CMD_GET_AUDIO_TX_INFO	0x9c
+
+struct i830_sdvo_encode{
+    uint8_t dvi_rev;
+    uint8_t hdmi_rev;
+} __attribute__ ((packed));





More information about the xorg mailing list