xf86-video-intel: Branch 'xf86-video-intel-2.4-branch' - 12 commits - src/common.h src/i810_reg.h src/i830_debug.c src/i830_display.c src/i830_driver.c src/i830.h src/i830_hdmi.c src/i830_sdvo.c src/i830_sdvo.h src/i830_sdvo_regs.h src/Makefile.am

Eric Anholt anholt at kemper.freedesktop.org
Mon Jun 30 10:31:29 PDT 2008


 src/Makefile.am      |    1 
 src/common.h         |    1 
 src/i810_reg.h       |   37 +++++++
 src/i830.h           |    4 
 src/i830_debug.c     |   25 ++++
 src/i830_display.c   |   37 +++++++
 src/i830_driver.c    |   15 ++
 src/i830_hdmi.c      |  233 ++++++++++++++++++++++++++++++++++++++++++++++
 src/i830_sdvo.c      |  257 +++++++++++++++++++++++++++++++++++++++++++++++----
 src/i830_sdvo.h      |    2 
 src/i830_sdvo_regs.h |   36 +++++++
 11 files changed, 624 insertions(+), 24 deletions(-)

New commits:
commit 45c1da56891723dd85153853885dd3b52a23c117
Author: Hong Liu <hong.liu at intel.com>
Date:   Fri Jun 20 10:57:14 2008 +0800

    Fix SDVO HDMI output.
    
    While some cards had enough initialized at startup to work already, others
    required that the driver actually initialize the required AVI info frame.
    (cherry picked from commit 05df8c0b31721a9ccc7215fb1cda1115758367c7)

diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c
index cdfc9c6..d9b76d4 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;
 
@@ -229,6 +232,19 @@ const static struct _sdvo_cmd_name {
     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);
+}
+
+#if 0
+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);
+}
+#endif
+
+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)
+{
+    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.
@@ -1203,6 +1406,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
@@ -1621,17 +1833,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..747f2cd 100644
--- a/src/i830_sdvo_regs.h
+++ b/src/i830_sdvo_regs.h
@@ -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));
commit 894fbc9d124e4c9dd982e14b83d47f51c479d5b6
Author: Jesse Barnes <jbarnes at jbarnes-t61.(none)>
Date:   Tue Jun 24 11:01:46 2008 -0700

    Remove ErrorF debugging from modeset ioctl
    
    Oops.
    (cherry picked from commit 59f39e0ea0ad48c52d9b8f7afb6e04ce95db717e)

diff --git a/src/i830_display.c b/src/i830_display.c
index 43a761c..abe9875 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -749,12 +749,10 @@ static void i830_modeset_ctl(xf86CrtcPtr crtc, int pre)
 	/* On -> off is a pre modeset */
 	modeset.cmd = _DRM_PRE_MODESET;
 	ioctl(pI830->drmSubFD, DRM_IOCTL_MODESET_CTL, &modeset);
-	ErrorF("modeset: on -> off on plane %d\n", modeset.crtc);
     } else if (!pre && intel_crtc->dpms_mode == DPMSModeOff) {
 	/* Off -> on means post modeset */
 	modeset.cmd = _DRM_POST_MODESET;
 	ioctl(pI830->drmSubFD, DRM_IOCTL_MODESET_CTL, &modeset);
-	ErrorF("modeset: off -> on on plane %d\n", modeset.crtc);
     }
 }
 #else
commit 21a63e9e193b91345cdab077a8ec80b3d8a80690
Author: Jesse Barnes <jbarnes at jbarnes-t61.(none)>
Date:   Tue Jun 24 10:41:46 2008 -0700

    Add support for keeping vblank counters sane across mode setting
    
    The DRM supports disabling of vblank interrupts when not in use, but in order
    to function properly it must also be aware of mode setting, which will reset
    the frame counter to 0.  Add code to call into the DRM before and after mode
    setting, so that it can account for any lost vblank events.
    (cherry picked from commit 65eee25d7d2ca979205f3776d620dbb36bf68a13)

diff --git a/src/i830_display.c b/src/i830_display.c
index 7857ee3..43a761c 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -35,6 +35,7 @@
 #include <assert.h>
 #include <stdlib.h>
 #include <math.h>
+#include <sys/ioctl.h>
 
 #include "xf86.h"
 #include "i830.h"
@@ -730,6 +731,39 @@ i830_use_fb_compression(xf86CrtcPtr crtc)
     return TRUE;
 }
 
+#if defined(DRM_IOCTL_MODESET_CTL) && defined(XF86DRI)
+static void i830_modeset_ctl(xf86CrtcPtr crtc, int pre)
+{
+    ScrnInfoPtr pScrn = crtc->scrn;
+    I830Ptr pI830 = I830PTR(pScrn);
+    I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+    struct drm_modeset_ctl modeset;
+
+    modeset.crtc = intel_crtc->plane;
+
+    /*
+     * DPMS will be called many times (especially off), but we only
+     * want to catch the transition from on->off and off->on.
+     */
+    if (pre && intel_crtc->dpms_mode != DPMSModeOff) {
+	/* On -> off is a pre modeset */
+	modeset.cmd = _DRM_PRE_MODESET;
+	ioctl(pI830->drmSubFD, DRM_IOCTL_MODESET_CTL, &modeset);
+	ErrorF("modeset: on -> off on plane %d\n", modeset.crtc);
+    } else if (!pre && intel_crtc->dpms_mode == DPMSModeOff) {
+	/* Off -> on means post modeset */
+	modeset.cmd = _DRM_POST_MODESET;
+	ioctl(pI830->drmSubFD, DRM_IOCTL_MODESET_CTL, &modeset);
+	ErrorF("modeset: off -> on on plane %d\n", modeset.crtc);
+    }
+}
+#else
+static void i830_modeset_ctl(xf86CrtcPtr crtc, int dpms_state)
+{
+    return;
+}
+#endif /* DRM_IOCTL_MODESET_CTL && XF86DRI */
+
 /**
  * Sets the power management mode of the pipe and plane.
  *
@@ -797,8 +831,10 @@ i830_crtc_dpms(xf86CrtcPtr crtc, int mode)
 	/* Reenable compression if needed */
 	if (i830_use_fb_compression(crtc))
 	    i830_enable_fb_compression(crtc);
+	i830_modeset_ctl(crtc, 0);
 	break;
     case DPMSModeOff:
+	i830_modeset_ctl(crtc, 1);
 	/* Shut off compression if in use */
 	if (i830_use_fb_compression(crtc))
 	    i830_disable_fb_compression(crtc);
commit 313e9383121d74f448d4d26910085c0915163d8a
Author: Eric Anholt <eric at anholt.net>
Date:   Thu Jun 19 15:01:00 2008 -0700

    Fix a crash in i830_sdvo_init error paths by setting up dev_priv earlier.
    (cherry picked from commit 6b6be2b2a7179c1c9fa12989e16076aae105f4e2)

diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c
index 8914e1b..cdfc9c6 100644
--- a/src/i830_sdvo.c
+++ b/src/i830_sdvo.c
@@ -1527,10 +1527,12 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
 	return FALSE;
     }
     output->driver_private = intel_output;
+    dev_priv = (struct i830_sdvo_priv *) (intel_output + 1);
+    intel_output->dev_priv = dev_priv;
+
     output->interlaceAllowed = FALSE;
     output->doubleScanAllowed = FALSE;
     
-    dev_priv = (struct i830_sdvo_priv *) (intel_output + 1);
     intel_output->type = I830_OUTPUT_SDVO;
     intel_output->pipe_mask = ((1 << 0) | (1 << 1));
     intel_output->clone_mask = (1 << I830_OUTPUT_SDVO);
@@ -1572,7 +1574,6 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
     }
 
     intel_output->pI2CBus = i2cbus;
-    intel_output->dev_priv = dev_priv;
 
     /* Read the regs to test if we can talk to the device */
     for (i = 0; i < 0x40; i++) {
commit a8f9957b30eb94120c4217a9722c19684fecebb3
Author: Eric Anholt <eric at anholt.net>
Date:   Thu Jun 19 14:27:30 2008 -0700

    Automatically detect the presence of HDMI.
    
    Now, SDVO is only probed if the SDVO detected bit is set.  If the SDVO probe
    fails, but the detect bit is set, assume that it's an HDMI output.
    (cherry picked from commit 65ad29d78793c7804f133a58de80ffaa0404ca28)

diff --git a/src/common.h b/src/common.h
index 5efdc0c..1765bb5 100644
--- a/src/common.h
+++ b/src/common.h
@@ -372,6 +372,7 @@ extern int I810_DEBUG;
 #define HWS_NEED_GFX(pI810) (IS_G33CLASS(pI810) || IS_IGD_GM(pI810) || IS_G4X(pI810))
 /* chipsets require status page in non stolen memory */
 #define HWS_NEED_NONSTOLEN(pI810) (IS_IGD_GM(pI810) || IS_G4X(pI810))
+#define SUPPORTS_INTEGRATED_HDMI(pI810) (IS_IGD_GM(pI810) || IS_G4X(pI810))
 
 #define GTT_PAGE_SIZE			KB(4)
 #define ROUND_TO(x, y)			(((x) + (y) - 1) / (y) * (y))
diff --git a/src/i830_driver.c b/src/i830_driver.c
index 5782d48..28505c8 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -924,13 +924,19 @@ I830SetupOutputs(ScrnInfoPtr pScrn)
       i830_lvds_init(pScrn);
 
    if (IS_I9XX(pI830)) {
-#if 1
-      i830_sdvo_init(pScrn, SDVOB);
-      i830_sdvo_init(pScrn, SDVOC);
-#else
-      i830_hdmi_init(pScrn, SDVOB);
-      i830_hdmi_init(pScrn, SDVOC);
-#endif
+      if (INREG(SDVOB) & SDVO_DETECTED) {
+	 Bool found = i830_sdvo_init(pScrn, SDVOB);
+
+	 if (!found && SUPPORTS_INTEGRATED_HDMI(pI830))
+	    i830_hdmi_init(pScrn, SDVOB);
+      }
+
+      if (INREG(SDVOB) & SDVO_DETECTED) {
+	 Bool found = i830_sdvo_init(pScrn, SDVOC);
+
+	 if (!found && SUPPORTS_INTEGRATED_HDMI(pI830))
+	    i830_hdmi_init(pScrn, SDVOC);
+      }
    } else {
       i830_dvo_init(pScrn);
    }
diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c
index 331059b..8914e1b 100644
--- a/src/i830_sdvo.c
+++ b/src/i830_sdvo.c
@@ -1503,7 +1503,7 @@ i830_sdvo_select_ddc_bus(struct i830_sdvo_priv *dev_priv)
     dev_priv->ddc_bus = 1 << num_bits;
 }
 
-void
+Bool
 i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
 {
     xf86OutputPtr	    output;
@@ -1518,13 +1518,13 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
 
     output = xf86OutputCreate (pScrn, &i830_sdvo_output_funcs,NULL);
     if (!output)
-	return;
+	return FALSE;
     intel_output = xnfcalloc (sizeof (I830OutputPrivateRec) +
 			      sizeof (struct i830_sdvo_priv), 1);
     if (!intel_output)
     {
 	xf86OutputDestroy (output);
-	return;
+	return FALSE;
     }
     output->driver_private = intel_output;
     output->interlaceAllowed = FALSE;
@@ -1546,7 +1546,7 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
     if (i2cbus == NULL)
     {
 	xf86OutputDestroy (output);
-	return;
+	return FALSE;
     }
 
     if (output_device == SDVOB) {
@@ -1568,7 +1568,7 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
 		   "Failed to initialize %s I2C device\n",
 		   SDVO_NAME(dev_priv));
 	xf86OutputDestroy (output);
-	return;
+	return FALSE;
     }
 
     intel_output->pI2CBus = i2cbus;
@@ -1581,7 +1581,7 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
 		       "No SDVO device found on SDVO%c\n",
 		       output_device == SDVOB ? 'B' : 'C');
 	    xf86OutputDestroy (output);
-	    return;
+	    return FALSE;
 	}
     }
 
@@ -1594,7 +1594,7 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
     if (ddcbus == NULL) 
     {
 	xf86OutputDestroy (output);
-	return;
+	return FALSE;
     }
     if (output_device == SDVOB)
         ddcbus->BusName = "SDVOB DDC Bus";
@@ -1611,7 +1611,7 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
     if (!xf86I2CBusInit(ddcbus)) 
     {
 	xf86OutputDestroy (output);
-	return;
+	return FALSE;
     }
 
     intel_output->pI2CBus = i2cbus;
@@ -1670,7 +1670,7 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
     if (!xf86OutputRename (output, name))
     {
 	xf86OutputDestroy (output);
-	return;
+	return FALSE;
     }
 
     i830_sdvo_select_ddc_bus(dev_priv);
@@ -1718,4 +1718,5 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
     REPORT_OUTPUT_FLAG(SDVO_OUTPUT_SCART1, "SCART1");
     REPORT_OUTPUT_FLAG(SDVO_OUTPUT_LVDS1, "LVDS1");
 
+    return TRUE;
 }
diff --git a/src/i830_sdvo.h b/src/i830_sdvo.h
index 1368e43..798a88d 100644
--- a/src/i830_sdvo.h
+++ b/src/i830_sdvo.h
@@ -25,7 +25,7 @@
  *
  */
 
-void
+Bool
 i830_sdvo_init(ScrnInfoPtr pScrn, int output_device);
 
 int
commit f8ca634b38229e1eeae026747ee0b6688b7a71a0
Author: Eric Anholt <eric at anholt.net>
Date:   Thu Jun 19 14:10:29 2008 -0700

    Fix hdmi POSTING_READ to use the register number instead of the register value.
    
    We won't dwell too long on how this ever worked.
    (cherry picked from commit ea0d21006ec71bc56acde7291e5f8d28e54b83fe)

diff --git a/src/i830_hdmi.c b/src/i830_hdmi.c
index c256296..72d4c63 100644
--- a/src/i830_hdmi.c
+++ b/src/i830_hdmi.c
@@ -82,7 +82,7 @@ i830_hdmi_mode_set(xf86OutputPtr output, DisplayModePtr mode,
 	sdvox |= SDVO_PIPE_B_SELECT;
 
     OUTREG(dev_priv->output_reg, sdvox);
-    POSTING_READ(sdvox);
+    POSTING_READ(dev_priv->output_reg);
 }
 
 static void
commit babedc600f8758b7e436adb93ffe8a5f2d7124ae
Author: Eric Anholt <eric at anholt.net>
Date:   Thu Mar 20 15:14:46 2008 -0700

    Get HDMI output working.
    
    HDMI, despite claiming to have pixel multiply support, actually doesn't
    want it, at least in the way that SDVO did.  Disable it.
    
    Also disable the NULL_PACKETS_DURING_VSYNC bit.  Despite the docs telling us
    to set it, the output doesn't like it when you do that, and the BIOS doesn't
    set it.
    
    Also add a posting read to SDVOx setting.  Without it, half the X starts
    wouldn't get anything on the screen.  (interestingly, it was every other
    startup, not just a chance).
    (cherry picked from commit 2fa9240a3b685a0c3d0e2644fc144c927b67b6b3)

diff --git a/src/i830_hdmi.c b/src/i830_hdmi.c
index 931a55c..c256296 100644
--- a/src/i830_hdmi.c
+++ b/src/i830_hdmi.c
@@ -52,25 +52,13 @@ i830_hdmi_mode_valid(xf86OutputPtr output, DisplayModePtr mode)
     return MODE_OK;
 }
 
-static int
-i830_hdmi_get_pixel_multiplier(DisplayModePtr mode)
-{
-    if (mode->Clock >= 100000)
-	return 1;
-    else if (mode->Clock >= 50000)
-	return 2;
-    else
-	return 4;
-}
-
 static Bool
 i830_hdmi_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
 		     DisplayModePtr adjusted_mode)
 {
-    /* Make the CRTC code factor in the SDVO pixel multiplier.
+    /* The HDMI output doesn't need the pixel multiplication that SDVO does,
+     * so no fixup.
      */
-    adjusted_mode->Clock *= i830_hdmi_get_pixel_multiplier(mode);
-
     return TRUE;
 }
 
@@ -88,13 +76,13 @@ i830_hdmi_mode_set(xf86OutputPtr output, DisplayModePtr mode,
 
     sdvox = SDVO_ENCODING_HDMI |
 	SDVO_BORDER_ENABLE |
-	SDVO_NULL_PACKETS_DURING_VSYNC |
 	SDVO_VSYNC_ACTIVE_HIGH |
 	SDVO_HSYNC_ACTIVE_HIGH;
     if (intel_crtc->pipe == 1)
 	sdvox |= SDVO_PIPE_B_SELECT;
 
     OUTREG(dev_priv->output_reg, sdvox);
+    POSTING_READ(sdvox);
 }
 
 static void
commit dcc841756f94ef61a1f1a991949efc917378baf1
Author: Eric Anholt <eric at anholt.net>
Date:   Thu Mar 20 13:49:47 2008 -0700

    Set the sync active bits like we're supposed to, matching the BIOS.
    (cherry picked from commit dc8ab9d35b261b6105a62949cfb47a3554531d0b)

diff --git a/src/i810_reg.h b/src/i810_reg.h
index ecc2686..515e73d 100644
--- a/src/i810_reg.h
+++ b/src/i810_reg.h
@@ -1262,8 +1262,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 /** Requird for HDMI operation */
 #define SDVO_NULL_PACKETS_DURING_VSYNC		(1 << 9)
 #define SDVO_BORDER_ENABLE			(1 << 7)
-/** new with 965, default is to be set */
+/** New with 965, default is to be set */
 #define SDVO_VSYNC_ACTIVE_HIGH			(1 << 4)
+/** New with 965, default is to be set */
 #define SDVO_HSYNC_ACTIVE_HIGH			(1 << 3)
 /** 915/945 only, read-only bit */
 #define SDVOB_PCIE_CONCURRENCY			(1 << 3)
diff --git a/src/i830_hdmi.c b/src/i830_hdmi.c
index 77a51c6..931a55c 100644
--- a/src/i830_hdmi.c
+++ b/src/i830_hdmi.c
@@ -88,7 +88,9 @@ i830_hdmi_mode_set(xf86OutputPtr output, DisplayModePtr mode,
 
     sdvox = SDVO_ENCODING_HDMI |
 	SDVO_BORDER_ENABLE |
-	SDVO_NULL_PACKETS_DURING_VSYNC;
+	SDVO_NULL_PACKETS_DURING_VSYNC |
+	SDVO_VSYNC_ACTIVE_HIGH |
+	SDVO_HSYNC_ACTIVE_HIGH;
     if (intel_crtc->pipe == 1)
 	sdvox |= SDVO_PIPE_B_SELECT;
 
commit a927099505391efff6ef64d299ccbf14c28f7b5f
Author: Eric Anholt <eric at anholt.net>
Date:   Mon Mar 10 11:51:05 2008 -0700

    Add pixel multiplier support for HDMI
    (cherry picked from commit af13826ed063b60a1e4179101e8889b4ab7a9d0b)

diff --git a/src/i830_hdmi.c b/src/i830_hdmi.c
index a5d2265..77a51c6 100644
--- a/src/i830_hdmi.c
+++ b/src/i830_hdmi.c
@@ -52,10 +52,25 @@ i830_hdmi_mode_valid(xf86OutputPtr output, DisplayModePtr mode)
     return MODE_OK;
 }
 
+static int
+i830_hdmi_get_pixel_multiplier(DisplayModePtr mode)
+{
+    if (mode->Clock >= 100000)
+	return 1;
+    else if (mode->Clock >= 50000)
+	return 2;
+    else
+	return 4;
+}
+
 static Bool
 i830_hdmi_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
 		     DisplayModePtr adjusted_mode)
 {
+    /* Make the CRTC code factor in the SDVO pixel multiplier.
+     */
+    adjusted_mode->Clock *= i830_hdmi_get_pixel_multiplier(mode);
+
     return TRUE;
 }
 
commit 82300116af8b01fc3c071d9c8625ffea122431fa
Author: Eric Anholt <eric at anholt.net>
Date:   Mon Mar 10 11:47:15 2008 -0700

    The phase shift its are now reserved, and add HDMI clock limits.
    (cherry picked from commit 9a05662918223477eb1cf6f80ffac08712721c70)

diff --git a/src/i830_display.c b/src/i830_display.c
index 7697d4f..7857ee3 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -1175,7 +1175,7 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
 	    dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
 	    break;
 	}
-	if (IS_I965G(pI830))
+	if (IS_I965G(pI830) && !IS_IGD_GM(pI830))
 	    dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
     } else {
 	if (is_lvds) {
diff --git a/src/i830_hdmi.c b/src/i830_hdmi.c
index 103443f..a5d2265 100644
--- a/src/i830_hdmi.c
+++ b/src/i830_hdmi.c
@@ -43,6 +43,12 @@ struct i830_hdmi_priv {
 static int
 i830_hdmi_mode_valid(xf86OutputPtr output, DisplayModePtr mode)
 {
+    if (mode->Clock > 165000)
+	return MODE_CLOCK_HIGH;
+
+    if (mode->Clock < 20000)
+	return MODE_CLOCK_LOW;
+
     return MODE_OK;
 }
 
commit 56f5a189df288b87f6596804d9bc38a8308d0848
Author: Eric Anholt <eric at anholt.net>
Date:   Thu Mar 6 16:05:17 2008 -0800

    Initial HDMI work.  Not currently hooked up at startup.
    (cherry picked from commit beba1dd3561e38573ed9f507328caf7f8fb9f84a)

diff --git a/src/Makefile.am b/src/Makefile.am
index 0784c06..9dd9b37 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -100,6 +100,7 @@ intel_drv_la_SOURCES = \
          i830_driver.c \
 	 i830_dvo.c \
          i830.h \
+	 i830_hdmi.c \
          i830_i2c.c \
          i830_io.c \
 	 i830_lvds.c \
diff --git a/src/i810_reg.h b/src/i810_reg.h
index dcf14bf..ecc2686 100644
--- a/src/i810_reg.h
+++ b/src/i810_reg.h
@@ -1216,6 +1216,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 # define FP_M2_DIV_SHIFT			0
 
 #define PORT_HOTPLUG_EN		0x61110
+# define HDMIB_HOTPLUG_INT_EN			(1 << 29)
+# define HDMIC_HOTPLUG_INT_EN			(1 << 28)
+# define HDMID_HOTPLUG_INT_EN			(1 << 27)
 # define SDVOB_HOTPLUG_INT_EN			(1 << 26)
 # define SDVOC_HOTPLUG_INT_EN			(1 << 25)
 # define TV_HOTPLUG_INT_EN			(1 << 18)
@@ -1223,6 +1226,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 # define CRT_HOTPLUG_FORCE_DETECT		(1 << 3)
 
 #define PORT_HOTPLUG_STAT	0x61114
+# define HDMIB_HOTPLUG_INT_STATUS		(1 << 29)
+# define HDMIC_HOTPLUG_INT_STATUS		(1 << 28)
+# define HDMID_HOTPLUG_INT_STATUS		(1 << 27)
 # define CRT_HOTPLUG_INT_STATUS			(1 << 11)
 # define TV_HOTPLUG_INT_STATUS			(1 << 10)
 # define CRT_HOTPLUG_MONITOR_MASK		(3 << 8)
@@ -1251,6 +1257,10 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #define SDVO_PHASE_SELECT_DEFAULT		(6 << 19)
 #define SDVO_CLOCK_OUTPUT_INVERT		(1 << 18)
 #define SDVOC_GANG_MODE				(1 << 16)
+#define SDVO_ENCODING_SDVO			(0x0 << 10)
+#define SDVO_ENCODING_HDMI			(0x2 << 10)
+/** Requird for HDMI operation */
+#define SDVO_NULL_PACKETS_DURING_VSYNC		(1 << 9)
 #define SDVO_BORDER_ENABLE			(1 << 7)
 /** new with 965, default is to be set */
 #define SDVO_VSYNC_ACTIVE_HIGH			(1 << 4)
diff --git a/src/i830.h b/src/i830.h
index 2a804ab..00a5059 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -238,6 +238,7 @@ typedef struct {
 #define I830_OUTPUT_SDVO 5
 #define I830_OUTPUT_LVDS 6
 #define I830_OUTPUT_TVOUT 7
+#define I830_OUTPUT_HDMI 8
 
 struct _I830DVODriver {
    int type;
@@ -802,6 +803,9 @@ void i830_crt_init(ScrnInfoPtr pScrn);
 /* i830_dvo.c */
 void i830_dvo_init(ScrnInfoPtr pScrn);
 
+/* i830_hdmi.c */
+void i830_hdmi_init(ScrnInfoPtr pScrn, int output_reg);
+
 /* i830_lvds.c */
 void i830_lvds_init(ScrnInfoPtr pScrn);
 
diff --git a/src/i830_display.c b/src/i830_display.c
index 56a718d..7697d4f 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -1103,6 +1103,7 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
 	    lvds_bits = intel_output->lvds_bits;
 	    break;
 	case I830_OUTPUT_SDVO:
+	case I830_OUTPUT_HDMI:
 	    is_sdvo = TRUE;
 	    if (intel_output->needs_tv_clock)
 		is_tv = TRUE;
diff --git a/src/i830_driver.c b/src/i830_driver.c
index 604665e..5782d48 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -924,8 +924,13 @@ I830SetupOutputs(ScrnInfoPtr pScrn)
       i830_lvds_init(pScrn);
 
    if (IS_I9XX(pI830)) {
+#if 1
       i830_sdvo_init(pScrn, SDVOB);
       i830_sdvo_init(pScrn, SDVOC);
+#else
+      i830_hdmi_init(pScrn, SDVOB);
+      i830_hdmi_init(pScrn, SDVOC);
+#endif
    } else {
       i830_dvo_init(pScrn);
    }
diff --git a/src/i830_hdmi.c b/src/i830_hdmi.c
new file mode 100644
index 0000000..103443f
--- /dev/null
+++ b/src/i830_hdmi.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright © 2007 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric at anholt.net>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "xf86.h"
+#include "i830.h"
+#include "xf86Modes.h"
+#include "i830_display.h"
+
+struct i830_hdmi_priv {
+    uint32_t output_reg;
+
+    uint32_t save_SDVO;
+};
+
+static int
+i830_hdmi_mode_valid(xf86OutputPtr output, DisplayModePtr mode)
+{
+    return MODE_OK;
+}
+
+static Bool
+i830_hdmi_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
+		     DisplayModePtr adjusted_mode)
+{
+    return TRUE;
+}
+
+static void
+i830_hdmi_mode_set(xf86OutputPtr output, DisplayModePtr mode,
+		   DisplayModePtr adjusted_mode)
+{
+    ScrnInfoPtr pScrn = output->scrn;
+    I830OutputPrivatePtr intel_output = output->driver_private;
+    struct i830_hdmi_priv *dev_priv = intel_output->dev_priv;
+    I830Ptr pI830 = I830PTR(pScrn);
+    xf86CrtcPtr crtc = output->crtc;
+    I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+    uint32_t sdvox;
+
+    sdvox = SDVO_ENCODING_HDMI |
+	SDVO_BORDER_ENABLE |
+	SDVO_NULL_PACKETS_DURING_VSYNC;
+    if (intel_crtc->pipe == 1)
+	sdvox |= SDVO_PIPE_B_SELECT;
+
+    OUTREG(dev_priv->output_reg, sdvox);
+}
+
+static void
+i830_hdmi_dpms(xf86OutputPtr output, int mode)
+{
+    ScrnInfoPtr pScrn = output->scrn;
+    I830OutputPrivatePtr intel_output = output->driver_private;
+    struct i830_hdmi_priv *dev_priv = intel_output->dev_priv;
+    I830Ptr pI830 = I830PTR(pScrn);
+    uint32_t  temp;
+
+    if (mode == DPMSModeOff) {
+	temp = INREG(dev_priv->output_reg);
+	OUTREG(dev_priv->output_reg, temp & ~SDVO_ENABLE);
+    } else {
+	temp = INREG(dev_priv->output_reg);
+	OUTREG(dev_priv->output_reg, temp | SDVO_ENABLE);
+    }
+}
+
+static void
+i830_hdmi_save(xf86OutputPtr output)
+{
+    ScrnInfoPtr pScrn = output->scrn;
+    I830OutputPrivatePtr intel_output = output->driver_private;
+    struct i830_hdmi_priv *dev_priv = intel_output->dev_priv;
+    I830Ptr pI830 = I830PTR(pScrn);
+
+    dev_priv->save_SDVO = INREG(dev_priv->output_reg);
+}
+
+static void
+i830_hdmi_restore(xf86OutputPtr output)
+{
+    ScrnInfoPtr pScrn = output->scrn;
+    I830OutputPrivatePtr intel_output = output->driver_private;
+    struct i830_hdmi_priv *dev_priv = intel_output->dev_priv;
+    I830Ptr pI830 = I830PTR(pScrn);
+
+    OUTREG(dev_priv->output_reg, dev_priv->save_SDVO);
+}
+
+/**
+ * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect HDMI connection.
+ *
+ * \return TRUE if HDMI port is connected.
+ * \return FALSE if HDMI port is disconnected.
+ */
+static xf86OutputStatus
+i830_hdmi_detect(xf86OutputPtr output)
+{
+    ScrnInfoPtr	pScrn = output->scrn;
+    I830OutputPrivatePtr intel_output = output->driver_private;
+    struct i830_hdmi_priv *dev_priv = intel_output->dev_priv;
+    I830Ptr pI830 = I830PTR(pScrn);
+    uint32_t temp, bit;
+
+    temp = INREG(PORT_HOTPLUG_EN);
+
+    OUTREG(PORT_HOTPLUG_EN,
+	   temp |
+	   HDMIB_HOTPLUG_INT_EN |
+	   HDMIC_HOTPLUG_INT_EN |
+	   HDMID_HOTPLUG_INT_EN);
+
+    POSTING_READ(PORT_HOTPLUG_EN);
+
+    switch (dev_priv->output_reg) {
+    case SDVOB:
+	bit = HDMIB_HOTPLUG_INT_STATUS;
+	break;
+    case SDVOC:
+	bit = HDMIC_HOTPLUG_INT_STATUS;
+	break;
+    default:
+	return XF86OutputStatusUnknown;
+    }
+
+    if ((INREG(PORT_HOTPLUG_STAT) & bit) != 0)
+	return XF86OutputStatusConnected;
+    else
+	return XF86OutputStatusDisconnected;
+}
+
+static void
+i830_hdmi_destroy (xf86OutputPtr output)
+{
+    I830OutputPrivatePtr intel_output = output->driver_private;
+
+    if (intel_output != NULL) {
+	xf86DestroyI2CBusRec(intel_output->pDDCBus, FALSE, FALSE);
+	xfree(intel_output);
+    }
+}
+
+static const xf86OutputFuncsRec i830_hdmi_output_funcs = {
+    .dpms = i830_hdmi_dpms,
+    .save = i830_hdmi_save,
+    .restore = i830_hdmi_restore,
+    .mode_valid = i830_hdmi_mode_valid,
+    .mode_fixup = i830_hdmi_mode_fixup,
+    .prepare = i830_output_prepare,
+    .mode_set = i830_hdmi_mode_set,
+    .commit = i830_output_commit,
+    .detect = i830_hdmi_detect,
+    .get_modes = i830_ddc_get_modes,
+    .destroy = i830_hdmi_destroy
+};
+
+void
+i830_hdmi_init(ScrnInfoPtr pScrn, int output_reg)
+{
+    xf86OutputPtr output;
+    I830OutputPrivatePtr intel_output;
+    struct i830_hdmi_priv *dev_priv;
+
+    output = xf86OutputCreate(pScrn, &i830_hdmi_output_funcs,
+			      (output_reg == SDVOB) ? "HDMI-1" : "HDMI-2");
+    if (!output)
+	return;
+    intel_output = xnfcalloc(sizeof (I830OutputPrivateRec) +
+			     sizeof (struct i830_hdmi_priv), 1);
+    if (intel_output == NULL) {
+	xf86OutputDestroy(output);
+	return;
+    }
+    output->driver_private = intel_output;
+    output->interlaceAllowed = FALSE;
+    output->doubleScanAllowed = FALSE;
+
+    dev_priv = (struct i830_hdmi_priv *)(intel_output + 1);
+    dev_priv->output_reg = output_reg;
+
+    intel_output->dev_priv = dev_priv;
+    intel_output->type = I830_OUTPUT_HDMI;
+    intel_output->pipe_mask = ((1 << 0) | (1 << 1));
+    intel_output->clone_mask = (1 << I830_OUTPUT_HDMI);
+
+    /* Set up the DDC bus. */
+    if (output_reg == SDVOB)
+	I830I2CInit(pScrn, &intel_output->pDDCBus, GPIOE, "HDMIDDC_B");
+    else
+	I830I2CInit(pScrn, &intel_output->pDDCBus, GPIOE, "HDMIDDC_C");
+
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+	       "HDMI output %d detected\n",
+	       1 + (output_reg - SDVOB));
+}
commit 9381703787069aa348dccb955839a0058db55c0b
Author: Eric Anholt <eric at anholt.net>
Date:   Thu Mar 6 14:57:57 2008 -0800

    Add DisplayPort registers.
    (cherry picked from commit da58dc3b02999f3244d0eaf77180b828d85bd609)

diff --git a/src/i810_reg.h b/src/i810_reg.h
index dc4f5e8..dcf14bf 100644
--- a/src/i810_reg.h
+++ b/src/i810_reg.h
@@ -1451,6 +1451,30 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 /** @} */
 
+#define DP_B			0x64100
+#define DPB_AUX_CH_CTL		0x64110
+#define DPB_AUX_CH_DATA1	0x64114
+#define DPB_AUX_CH_DATA2	0x64118
+#define DPB_AUX_CH_DATA3	0x6411c
+#define DPB_AUX_CH_DATA4	0x64120
+#define DPB_AUX_CH_DATA5	0x64124
+
+#define DP_C			0x64200
+#define DPC_AUX_CH_CTL		0x64210
+#define DPC_AUX_CH_DATA1	0x64214
+#define DPC_AUX_CH_DATA2	0x64218
+#define DPC_AUX_CH_DATA3	0x6421c
+#define DPC_AUX_CH_DATA4	0x64220
+#define DPC_AUX_CH_DATA5	0x64224
+
+#define DP_D			0x64300
+#define DPD_AUX_CH_CTL		0x64310
+#define DPD_AUX_CH_DATA1	0x64314
+#define DPD_AUX_CH_DATA2	0x64318
+#define DPD_AUX_CH_DATA3	0x6431c
+#define DPD_AUX_CH_DATA4	0x64320
+#define DPD_AUX_CH_DATA5	0x64324
+
 /*
  * Two channel clock control. Turn this on if you need clkb for two channel mode
  * Overridden by global LVDS power sequencing
diff --git a/src/i830_debug.c b/src/i830_debug.c
index 074e8b9..8830050 100644
--- a/src/i830_debug.c
+++ b/src/i830_debug.c
@@ -628,6 +628,31 @@ static struct i830SnapshotRec {
     DEFINEREG(MI_ARB_STATE),
     DEFINEREG(MI_RDRET_STATE),
     DEFINEREG(ECOSKPD),
+
+    DEFINEREG(DP_B),
+    DEFINEREG(DPB_AUX_CH_CTL),
+    DEFINEREG(DPB_AUX_CH_DATA1),
+    DEFINEREG(DPB_AUX_CH_DATA2),
+    DEFINEREG(DPB_AUX_CH_DATA3),
+    DEFINEREG(DPB_AUX_CH_DATA4),
+    DEFINEREG(DPB_AUX_CH_DATA5),
+
+    DEFINEREG(DP_C),
+    DEFINEREG(DPC_AUX_CH_CTL),
+    DEFINEREG(DPC_AUX_CH_DATA1),
+    DEFINEREG(DPC_AUX_CH_DATA2),
+    DEFINEREG(DPC_AUX_CH_DATA3),
+    DEFINEREG(DPC_AUX_CH_DATA4),
+    DEFINEREG(DPC_AUX_CH_DATA5),
+
+    DEFINEREG(DP_D),
+    DEFINEREG(DPD_AUX_CH_CTL),
+    DEFINEREG(DPD_AUX_CH_DATA1),
+    DEFINEREG(DPD_AUX_CH_DATA2),
+    DEFINEREG(DPD_AUX_CH_DATA3),
+    DEFINEREG(DPD_AUX_CH_DATA4),
+    DEFINEREG(DPD_AUX_CH_DATA5),
+
 #if 0
     DEFINEREG2(FENCE_NEW + 0, i810_debug_fence_new),
     DEFINEREG2(FENCE_NEW + 8, i810_debug_fence_new),


More information about the xorg-commit mailing list