[Intel-gfx] [PATCH] update SDVO code in i915 driver

Jesse Barnes jbarnes at virtuousgeek.org
Sat Jan 10 00:55:53 CET 2009


This patch syncs the i915 driver up with the xf86-video-intel driver,
SDVO-wise, pulling in a lot of fixes and improvements.  It's not well tested
at this point though, and review is welcome.

-- 
Jesse Barnes, Intel Open Source Technology Center

diff --git a/drivers/gpu/drm/i915/intel_display.c 
b/drivers/gpu/drm/i915/intel_display.c
index 4372acf..7d05210 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -755,6 +755,8 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,
 		case INTEL_OUTPUT_SDVO:
 		case INTEL_OUTPUT_HDMI:
 			is_sdvo = true;
+			if (intel_output->needs_tv_clock)
+				is_tv = true;
 			break;
 		case INTEL_OUTPUT_DVO:
 			is_dvo = true;
diff --git a/drivers/gpu/drm/i915/intel_drv.h 
b/drivers/gpu/drm/i915/intel_drv.h
index 8a4cc50..957daef 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -82,6 +82,7 @@ struct intel_output {
 	struct intel_i2c_chan *i2c_bus; /* for control functions */
 	struct intel_i2c_chan *ddc_bus; /* for DDC only stuff */
 	bool load_detect_temp;
+	bool needs_tv_clock;
 	void *dev_priv;
 };
 
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c 
b/drivers/gpu/drm/i915/intel_sdvo.c
index 4072154..f610b8d 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -40,13 +40,59 @@
 struct intel_sdvo_priv {
 	struct intel_i2c_chan *i2c_bus;
 	int slaveaddr;
+
+	/* Register for the SDVO device: SDVOB or SDVOC */
 	int output_device;
 
-	u16 active_outputs;
+	/* Active outputs controlled by this SDVO output */
+	uint16_t controlled_output;
 
+	/*
+	 * Capabilities of the SDVO device returned by
+	 * i830_sdvo_get_capabilities()
+	 */
 	struct intel_sdvo_caps caps;
+
+	/* Pixel clock limitations reported by the SDVO device, in kHz */
 	int pixel_clock_min, pixel_clock_max;
 
+	/**
+	 * This is set if we're going to treat the device as TV-out.
+	 *
+	 * While we have these nice friendly flags for output types that ought
+	 * to decide this for us, the S-Video output on our HDMI+S-Video card
+	 * shows up as RGB1 (VGA).
+	 */
+	bool is_tv;
+
+	/**
+	 * This is set if we treat the device as HDMI, instead of DVI.
+	 */
+	bool is_hdmi;
+
+	/**
+	 * Returned SDTV resolutions allowed for the current format, if the
+	 * device reported it.
+	 */
+	struct intel_sdvo_sdtv_resolution_reply sdtv_resolutions;
+
+	/**
+	 * Current selected TV format.
+	 *
+	 * This is stored in the same structure that's passed to the device, for
+	 * convenience.
+	 */
+	struct intel_sdvo_tv_format tv_format;
+
+	/*
+	 * supported encoding mode, used to determine whether HDMI is
+	 * supported
+	 */
+	struct intel_sdvo_encode encode;
+
+	/* DDC bus used by this SDVO output */
+	uint8_t ddc_bus;
+
 	int save_sdvo_mult;
 	u16 save_active_outputs;
 	struct intel_sdvo_dtd save_input_dtd_1, save_input_dtd_2;
@@ -186,8 +232,35 @@ const static struct _sdvo_cmd_name {
     SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_TV_FORMATS),
     SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_FORMAT),
     SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_FORMAT),
-    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_RESOLUTION_SUPPORT),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_POWER_STATES),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_POWER_STATE),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ENCODER_POWER_STATE),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_DISPLAY_POWER_STATE),
     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_SCALED_HDTV_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_SET_ENCODE),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_PIXEL_REPLI),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PIXEL_REPLI),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_COLORIMETRY_CAP),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_COLORIMETRY),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_COLORIMETRY),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_AUDIO_ENCRYPT_PREFER),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_AUDIO_STAT),
+    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_SET_HBUF_AV_SPLIT),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_TXRATE),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HBUF_TXRATE),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HBUF_DATA),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_DATA),
 };
 
 #define SDVO_NAME(dev_priv) ((dev_priv)->output_device == 
SDVOB ? "SDVOB" : "SDVOC")
@@ -506,6 +579,47 @@ static bool intel_sdvo_set_output_timing(struct 
intel_output *intel_output,
 				     SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd);
 }
 
+static bool intel_sdvo_create_preferred_input_timing(struct intel_output 
*output,
+						     uint16_t clock,
+						     uint16_t width,
+						     uint16_t height)
+{
+    struct intel_sdvo_preferred_input_timing_args args;
+    uint8_t status;
+
+    args.clock = clock;
+    args.width = width;
+    args.height = height;
+    intel_sdvo_write_cmd(output, SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING,
+			 &args, sizeof(args));
+    status = intel_sdvo_read_response(output, NULL, 0);
+    if (status != SDVO_CMD_STATUS_SUCCESS)
+	return false;
+
+    return true;
+}
+
+static bool intel_sdvo_get_preferred_input_timing(struct intel_output 
*output,
+						  struct intel_sdvo_dtd *dtd)
+{
+    bool status;
+
+    intel_sdvo_write_cmd(output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1,
+			 NULL, 0);
+
+    status = intel_sdvo_read_response(output, &dtd->part1, 
sizeof(dtd->part1));
+    if (status != SDVO_CMD_STATUS_SUCCESS)
+	return false;
+
+    intel_sdvo_write_cmd(output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2,
+			 NULL, 0);
+
+    status = intel_sdvo_read_response(output, &dtd->part2, 
sizeof(dtd->part2));
+    if (status != SDVO_CMD_STATUS_SUCCESS)
+	return false;
+
+    return false;
+}
 
 static int intel_sdvo_get_clock_rate_mult(struct intel_output *intel_output)
 {
@@ -536,14 +650,334 @@ static bool intel_sdvo_set_clock_rate_mult(struct 
intel_output *intel_output, u8
 	return true;
 }
 
+static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd,
+					 struct drm_display_mode *mode)
+{
+    uint16_t width, height;
+    uint16_t h_blank_len, h_sync_len, v_blank_len, v_sync_len;
+    uint16_t h_sync_offset, v_sync_offset;
+
+    width = mode->crtc_hdisplay;
+    height = mode->crtc_vdisplay;
+
+    /* do some mode translations */
+    h_blank_len = mode->crtc_hblank_end - mode->crtc_hblank_start;
+    h_sync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
+
+    v_blank_len = mode->crtc_vblank_end - mode->crtc_vblank_start;
+    v_sync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
+
+    h_sync_offset = mode->crtc_hsync_start - mode->crtc_hblank_start;
+    v_sync_offset = mode->crtc_vsync_start - mode->crtc_vblank_start;
+
+    dtd->part1.clock = mode->clock / 10;
+    dtd->part1.h_active = width & 0xff;
+    dtd->part1.h_blank = h_blank_len & 0xff;
+    dtd->part1.h_high = (((width >> 8) & 0xf) << 4) |
+	((h_blank_len >> 8) & 0xf);
+    dtd->part1.v_active = height & 0xff;
+    dtd->part1.v_blank = v_blank_len & 0xff;
+    dtd->part1.v_high = (((height >> 8) & 0xf) << 4) |
+	((v_blank_len >> 8) & 0xf);
+
+    dtd->part2.h_sync_off = h_sync_offset;
+    dtd->part2.h_sync_width = h_sync_len & 0xff;
+    dtd->part2.v_sync_off_width = (v_sync_offset & 0xf) << 4 |
+	(v_sync_len & 0xf);
+    dtd->part2.sync_off_width_high = ((h_sync_offset & 0x300) >> 2) |
+	((h_sync_len & 0x300) >> 4) | ((v_sync_offset & 0x30) >> 2) |
+	((v_sync_len & 0x30) >> 4);
+
+    dtd->part2.dtd_flags = 0x18;
+    if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+	dtd->part2.dtd_flags |= 0x2;
+    if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+	dtd->part2.dtd_flags |= 0x4;
+
+    dtd->part2.sdvo_flags = 0;
+    dtd->part2.v_sync_off_high = v_sync_offset & 0xc0;
+    dtd->part2.reserved = 0;
+}
+
+static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode,
+					 struct intel_sdvo_dtd *dtd)
+{
+    uint16_t width, height;
+    uint16_t h_blank_len, h_sync_len, v_blank_len, v_sync_len;
+    uint16_t h_sync_offset, v_sync_offset;
+
+    width = mode->crtc_hdisplay;
+    height = mode->crtc_vdisplay;
+
+    /* do some mode translations */
+    h_blank_len = mode->crtc_hblank_end - mode->crtc_hblank_start;
+    h_sync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
+
+    v_blank_len = mode->crtc_vblank_end - mode->crtc_vblank_start;
+    v_sync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
+
+    h_sync_offset = mode->crtc_hsync_start - mode->crtc_hblank_start;
+    v_sync_offset = mode->crtc_vsync_start - mode->crtc_vblank_start;
+
+    mode->hdisplay = dtd->part1.h_active;
+    mode->hdisplay += ((dtd->part1.h_high >> 4) & 0x0f) << 8;
+    mode->hsync_start = mode->hdisplay + dtd->part2.h_sync_off;
+    mode->hsync_start += (dtd->part2.sync_off_width_high & 0xa0) << 2;
+    mode->hsync_end = mode->hsync_start + dtd->part2.h_sync_width;
+    mode->hsync_end += (dtd->part2.sync_off_width_high & 0x30) << 4;
+    mode->htotal = mode->hdisplay + dtd->part1.h_blank;
+    mode->htotal += (dtd->part1.h_high & 0xf) << 8;
+
+    mode->vdisplay = dtd->part1.v_active;
+    mode->vdisplay += ((dtd->part1.v_high >> 4) & 0x0f) << 8;
+    mode->vsync_start = mode->vdisplay;
+    mode->vsync_start += (dtd->part2.v_sync_off_width >> 4) & 0xf;
+    mode->vsync_start += (dtd->part2.sync_off_width_high & 0x0a) << 2;
+    mode->vsync_start += dtd->part2.v_sync_off_high & 0xc0;
+    mode->vsync_end = mode->vsync_start + (dtd->part2.v_sync_off_width & 
0xf);
+    mode->vsync_end += (dtd->part2.sync_off_width_high & 0x3) << 4;
+    mode->vtotal = mode->vdisplay + dtd->part1.v_blank;
+    mode->vtotal += (dtd->part1.v_high & 0xf) << 8;
+
+    mode->clock = dtd->part1.clock * 10;
+
+    mode->flags &= (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
+    if (dtd->part2.dtd_flags & 0x2)
+	    mode->flags |= DRM_MODE_FLAG_PHSYNC;
+    if (dtd->part2.dtd_flags & 0x4)
+	    mode->flags |= DRM_MODE_FLAG_PVSYNC;
+}
+
+static bool intel_sdvo_get_supp_encode(struct intel_output *output,
+				       struct intel_sdvo_encode *encode)
+{
+    uint8_t status;
+
+    intel_sdvo_write_cmd(output, SDVO_CMD_GET_SUPP_ENCODE, NULL, 0);
+    status = intel_sdvo_read_response(output, encode, sizeof(*encode));
+    if (status != SDVO_CMD_STATUS_SUCCESS) { /* non-support means DVI */
+	memset(encode, 0, sizeof(*encode));
+	return false;
+    }
+
+    return true;
+}
+
+static bool intel_sdvo_set_encode(struct intel_output *output, uint8_t mode)
+{
+    uint8_t status;
+
+    intel_sdvo_write_cmd(output, SDVO_CMD_SET_ENCODE, &mode, 1);
+    status = intel_sdvo_read_response(output, NULL, 0);
+
+    return (status == SDVO_CMD_STATUS_SUCCESS);
+}
+
+static bool intel_sdvo_set_colorimetry(struct intel_output *output,
+				       uint8_t mode)
+{
+    uint8_t status;
+
+    intel_sdvo_write_cmd(output, SDVO_CMD_SET_COLORIMETRY, &mode, 1);
+    status = intel_sdvo_read_response(output, NULL, 0);
+
+    return (status == SDVO_CMD_STATUS_SUCCESS);
+}
+
+#if 0
+static bool intel_sdvo_set_pixel_repli(struct drm_encoder *encoder,
+				       uint8_t repli)
+{
+    uint8_t status;
+
+    intel_sdvo_write_cmd(encoder, SDVO_CMD_SET_PIXEL_REPLI, &repli, 1);
+    status = intel_sdvo_read_response(output, NULL, 0);
+
+    return (status == SDVO_CMD_STATUS_SUCCESS);
+}
+#endif
+
+static void intel_sdvo_dump_hdmi_buf(struct intel_output *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;
+
+    intel_sdvo_write_cmd(output, SDVO_CMD_GET_HBUF_AV_SPLIT, NULL, 0);
+    intel_sdvo_read_response(output, &av_split, 1);
+
+    for (i = 0; i <= av_split; i++) {
+	set_buf_index[0] = i; set_buf_index[1] = 0;
+	intel_sdvo_write_cmd(output, SDVO_CMD_SET_HBUF_INDEX,
+				set_buf_index, 2);
+	intel_sdvo_write_cmd(output, SDVO_CMD_GET_HBUF_INFO, NULL, 0);
+	intel_sdvo_read_response(output, &buf_size, 1);
+
+	pos = buf;
+	for (j = 0; j <= buf_size; j += 8) {
+	    intel_sdvo_write_cmd(output, SDVO_CMD_GET_HBUF_DATA, NULL, 0);
+	    intel_sdvo_read_response(output, pos, 8);
+	    pos += 8;
+	}
+    }
+}
+
+static void intel_sdvo_set_hdmi_buf(struct intel_output *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;
+
+    intel_sdvo_write_cmd(output, SDVO_CMD_SET_HBUF_INDEX, set_buf_index, 2);
+
+    for (; size > 0; size -= 8) {
+	intel_sdvo_write_cmd(output, SDVO_CMD_SET_HBUF_DATA, data, 8);
+	data += 8;
+    }
+
+    intel_sdvo_write_cmd(output, 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];
+
+    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 intel_sdvo_set_avi_infoframe(struct intel_output *output,
+					 struct drm_display_mode * mode)
+{
+	struct dip_infoframe avi_if = {
+		.type = DIP_TYPE_AVI,
+		.version = DIP_VERSION_AVI,
+		.len = DIP_LEN_AVI,
+	};
+
+	avi_if.checksum = intel_sdvo_calc_hbuf_csum((uint8_t *)&avi_if,
+						    4 + avi_if.len);
+	intel_sdvo_set_hdmi_buf(output, 1, (uint8_t *)&avi_if, 4 + avi_if.len,
+				SDVO_HBUF_TX_VSYNC);
+}
+
 static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
 				  struct drm_display_mode *mode,
 				  struct drm_display_mode *adjusted_mode)
 {
-	/* Make the CRTC code factor in the SDVO pixel multiplier.  The SDVO
-	 * device will be told of the multiplier during mode_set.
-	 */
-	adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode);
+	struct intel_output *output = enc_to_intel_output(encoder);
+	struct intel_sdvo_priv *dev_priv = output->dev_priv;
+
+	if (!dev_priv->is_tv) {
+		/* Make the CRTC code factor in the SDVO pixel multiplier.  The
+		 * SDVO device will be told of the multiplier during mode_set.
+		 */
+		adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode);
+	} else {
+		struct intel_sdvo_dtd output_dtd;
+		bool success;
+
+		/* We need to construct preferred input timings based on our
+		 * output timings.  To do that, we have to set the output
+		 * timings, even though this isn't really the right place in
+		 * the sequence to do it. Oh well.
+		 */
+
+
+		/* Set output timings */
+		intel_sdvo_get_dtd_from_mode(&output_dtd, mode);
+		intel_sdvo_set_target_output(output,
+					     dev_priv->controlled_output);
+		intel_sdvo_set_output_timing(output, &output_dtd);
+
+		/* Set the input timing to the screen. Assume always input 0. */
+		intel_sdvo_set_target_input(output, true, false);
+
+
+		success = intel_sdvo_create_preferred_input_timing(output,
+								   mode->clock / 10,
+								   mode->hdisplay,
+								   mode->vdisplay);
+		if (success) {
+			struct intel_sdvo_dtd input_dtd;
+
+			intel_sdvo_get_preferred_input_timing(output,
+							     &input_dtd);
+			intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
+
+		} else {
+			return false;
+		}
+	}
 	return true;
 }
 
@@ -555,118 +989,110 @@ static void intel_sdvo_mode_set(struct drm_encoder 
*encoder,
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_crtc *crtc = encoder->crtc;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct intel_output *intel_output = enc_to_intel_output(encoder);
-	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
-	u16 width, height;
-	u16 h_blank_len, h_sync_len, v_blank_len, v_sync_len;
-	u16 h_sync_offset, v_sync_offset;
-	u32 sdvox;
-	struct intel_sdvo_dtd output_dtd;
+	struct intel_output *output = enc_to_intel_output(encoder);
+	struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
+	u32 sdvox = 0;
 	int sdvo_pixel_multiply;
+	struct intel_sdvo_in_out_map in_out;
+	struct intel_sdvo_dtd input_dtd;
+	u8 status;
 
 	if (!mode)
 		return;
 
-	width = mode->crtc_hdisplay;
-	height = mode->crtc_vdisplay;
-
-	/* do some mode translations */
-	h_blank_len = mode->crtc_hblank_end - mode->crtc_hblank_start;
-	h_sync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
-
-	v_blank_len = mode->crtc_vblank_end - mode->crtc_vblank_start;
-	v_sync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
-
-	h_sync_offset = mode->crtc_hsync_start - mode->crtc_hblank_start;
-	v_sync_offset = mode->crtc_vsync_start - mode->crtc_vblank_start;
-
-	output_dtd.part1.clock = mode->clock / 10;
-	output_dtd.part1.h_active = width & 0xff;
-	output_dtd.part1.h_blank = h_blank_len & 0xff;
-	output_dtd.part1.h_high = (((width >> 8) & 0xf) << 4) |
-		((h_blank_len >> 8) & 0xf);
-	output_dtd.part1.v_active = height & 0xff;
-	output_dtd.part1.v_blank = v_blank_len & 0xff;
-	output_dtd.part1.v_high = (((height >> 8) & 0xf) << 4) |
-		((v_blank_len >> 8) & 0xf);
-
-	output_dtd.part2.h_sync_off = h_sync_offset;
-	output_dtd.part2.h_sync_width = h_sync_len & 0xff;
-	output_dtd.part2.v_sync_off_width = (v_sync_offset & 0xf) << 4 |
-		(v_sync_len & 0xf);
-	output_dtd.part2.sync_off_width_high = ((h_sync_offset & 0x300) >> 2) |
-		((h_sync_len & 0x300) >> 4) | ((v_sync_offset & 0x30) >> 2) |
-		((v_sync_len & 0x30) >> 4);
-
-	output_dtd.part2.dtd_flags = 0x18;
-	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
-		output_dtd.part2.dtd_flags |= 0x2;
-	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
-		output_dtd.part2.dtd_flags |= 0x4;
-
-	output_dtd.part2.sdvo_flags = 0;
-	output_dtd.part2.v_sync_off_high = v_sync_offset & 0xc0;
-	output_dtd.part2.reserved = 0;
-
-	/* Set the output timing to the screen */
-	intel_sdvo_set_target_output(intel_output, sdvo_priv->active_outputs);
-	intel_sdvo_set_output_timing(intel_output, &output_dtd);
+	/* First, set the input mapping for the first input to our controlled
+	 * output. This is only correct if we're a single-input device, in
+	 * which case the first input is the output from the appropriate SDVO
+	 * channel on the motherboard.  In a two-input device, the first input
+	 * will be SDVOB and the second SDVOC.
+	 */
+	in_out.in0 = sdvo_priv->controlled_output;
+	in_out.in1 = 0;
+
+	intel_sdvo_write_cmd(output, SDVO_CMD_SET_IN_OUT_MAP,
+			     &in_out, sizeof(in_out));
+	status = intel_sdvo_read_response(output, NULL, 0);
+
+	if (sdvo_priv->is_hdmi) {
+		intel_sdvo_set_avi_infoframe(output, mode);
+		sdvox |= SDVO_AUDIO_ENABLE;
+	}
+
+	intel_sdvo_get_dtd_from_mode(&input_dtd, mode);
+
+	/* If it's a TV, we already set the output timing in mode_fixup.
+	 * Otherwise, the output timing is equal to the input timing.
+	 */
+	if (!sdvo_priv->is_tv) {
+		/* Set the output timing to the screen */
+		intel_sdvo_set_target_output(output,
+					     sdvo_priv->controlled_output);
+		intel_sdvo_set_output_timing(output, &input_dtd);
+	}
 
 	/* Set the input timing to the screen. Assume always input 0. */
-	intel_sdvo_set_target_input(intel_output, true, false);
+	intel_sdvo_set_target_input(output, true, false);
 
-	/* We would like to use i830_sdvo_create_preferred_input_timing() to
+	/* We would like to use intel_sdvo_create_preferred_input_timing() to
 	 * provide the device with a timing it can support, if it supports that
-	 * feature.  However, presumably we would need to adjust the CRTC to
-	 * output the preferred timing, and we don't support that currently.
+	 * feature.  However, presumably we would need to adjust the CRTC to output
+	 * the preferred timing, and we don't support that currently.
 	 */
-	intel_sdvo_set_input_timing(intel_output, &output_dtd);
+#if 0
+	success = intel_sdvo_create_preferred_input_timing(output, clock,
+							   width, height);
+	if (success) {
+		struct intel_sdvo_dtd *input_dtd;
+
+		intel_sdvo_get_preferred_input_timing(output, &input_dtd);
+		intel_sdvo_set_input_timing(output, &input_dtd);
+	}
+#else
+	intel_sdvo_set_input_timing(output, &input_dtd);
+#endif
 
 	switch (intel_sdvo_get_pixel_multiplier(mode)) {
 	case 1:
-		intel_sdvo_set_clock_rate_mult(intel_output,
-					       SDVO_CLOCK_RATE_MULT_1X);
+		intel_sdvo_set_clock_rate_mult(output, SDVO_CLOCK_RATE_MULT_1X);
 		break;
 	case 2:
-		intel_sdvo_set_clock_rate_mult(intel_output,
-					       SDVO_CLOCK_RATE_MULT_2X);
+		intel_sdvo_set_clock_rate_mult(output, SDVO_CLOCK_RATE_MULT_2X);
 		break;
 	case 4:
-		intel_sdvo_set_clock_rate_mult(intel_output,
-					       SDVO_CLOCK_RATE_MULT_4X);
+		intel_sdvo_set_clock_rate_mult(output, SDVO_CLOCK_RATE_MULT_4X);
 		break;
 	}
 
 	/* Set the SDVO control regs. */
-        if (0/*IS_I965GM(dev)*/) {
-                sdvox = SDVO_BORDER_ENABLE;
-        } else {
-                sdvox = I915_READ(sdvo_priv->output_device);
-                switch (sdvo_priv->output_device) {
-                case SDVOB:
-                        sdvox &= SDVOB_PRESERVE_MASK;
-                        break;
-                case SDVOC:
-                        sdvox &= SDVOC_PRESERVE_MASK;
-                        break;
-                }
-                sdvox |= (9 << 19) | SDVO_BORDER_ENABLE;
-        }
+	if (IS_I965G(dev)) {
+		sdvox |= SDVO_BORDER_ENABLE |
+			SDVO_VSYNC_ACTIVE_HIGH |
+			SDVO_HSYNC_ACTIVE_HIGH;
+	} else {
+		sdvox |= I915_READ(sdvo_priv->output_device);
+		switch (sdvo_priv->output_device) {
+		case SDVOB:
+			sdvox &= SDVOB_PRESERVE_MASK;
+			break;
+		case SDVOC:
+			sdvox &= SDVOC_PRESERVE_MASK;
+			break;
+		}
+		sdvox |= (9 << 19) | SDVO_BORDER_ENABLE;
+	}
 	if (intel_crtc->pipe == 1)
 		sdvox |= SDVO_PIPE_B_SELECT;
 
 	sdvo_pixel_multiply = intel_sdvo_get_pixel_multiplier(mode);
 	if (IS_I965G(dev)) {
-		/* done in crtc_mode_set as the dpll_md reg must be written
-		   early */
-	} else if (IS_I945G(dev) || IS_I945GM(dev)) {
-		/* done in crtc_mode_set as it lives inside the
-		   dpll register */
+		/* done in crtc_mode_set as the dpll_md reg must be written early */
+	} else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) {
+		/* done in crtc_mode_set as it lives inside the dpll register */
 	} else {
 		sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT;
 	}
 
-	intel_sdvo_write_sdvox(intel_output, sdvox);
+	intel_sdvo_write_sdvox(output, sdvox);
 }
 
 static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
@@ -685,7 +1111,8 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, 
int mode)
 		if (mode == DRM_MODE_DPMS_OFF) {
 			temp = I915_READ(sdvo_priv->output_device);
 			if ((temp & SDVO_ENABLE) != 0) {
-				intel_sdvo_write_sdvox(intel_output, temp & ~SDVO_ENABLE);
+				intel_sdvo_write_sdvox(intel_output,
+						       temp & ~SDVO_ENABLE);
 			}
 		}
 	} else {
@@ -695,7 +1122,8 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, 
int mode)
 
 		temp = I915_READ(sdvo_priv->output_device);
 		if ((temp & SDVO_ENABLE) == 0)
-			intel_sdvo_write_sdvox(intel_output, temp | SDVO_ENABLE);
+			intel_sdvo_write_sdvox(intel_output,
+					       temp | SDVO_ENABLE);
 		for (i = 0; i < 2; i++)
 		  intel_wait_for_vblank(dev);
 
@@ -714,7 +1142,8 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, 
int mode)
 
 		if (0)
 			intel_sdvo_set_encoder_power_state(intel_output, mode);
-		intel_sdvo_set_active_outputs(intel_output, sdvo_priv->active_outputs);
+		intel_sdvo_set_active_outputs(intel_output,
+					      sdvo_priv->controlled_output);
 	}
 	return;
 }
@@ -752,6 +1181,9 @@ static void intel_sdvo_save(struct drm_connector 
*connector)
 						     &sdvo_priv->save_output_dtd[o]);
 		}
 	}
+	if (sdvo_priv->is_tv) {
+		/* XXX: Save TV format/enhancements. */
+	}
 
 	sdvo_priv->save_SDVOX = I915_READ(sdvo_priv->output_device);
 }
@@ -759,7 +1191,6 @@ static void intel_sdvo_save(struct drm_connector 
*connector)
 static void intel_sdvo_restore(struct drm_connector *connector)
 {
 	struct drm_device *dev = connector->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_output *intel_output = to_intel_output(connector);
 	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
 	int o;
@@ -790,7 +1221,11 @@ static void intel_sdvo_restore(struct drm_connector 
*connector)
 
 	intel_sdvo_set_clock_rate_mult(intel_output, sdvo_priv->save_sdvo_mult);
 
-	I915_WRITE(sdvo_priv->output_device, sdvo_priv->save_SDVOX);
+	if (sdvo_priv->is_tv) {
+		/* XXX: Restore TV format/enhancements. */
+	}
+
+	intel_sdvo_write_sdvox(intel_output, sdvo_priv->save_SDVOX);
 
 	if (sdvo_priv->save_SDVOX & SDVO_ENABLE)
 	{
@@ -912,24 +1347,178 @@ static enum drm_connector_status 
intel_sdvo_detect(struct drm_connector *connect
 	u8 status;
 	struct intel_output *intel_output = to_intel_output(connector);
 
-	intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0);
+	intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ATTACHED_DISPLAYS,
+			     NULL, 0);
 	status = intel_sdvo_read_response(intel_output, &response, 2);
 
-	DRM_DEBUG("SDVO response %d %d\n", response[0], response[1]);
+	DRM_ERROR("SDVO response %d %d\n", response[0], response[1]);
+
+	if (status != SDVO_CMD_STATUS_SUCCESS)
+		return connector_status_unknown;
+
 	if ((response[0] != 0) || (response[1] != 0))
 		return connector_status_connected;
 	else
 		return connector_status_disconnected;
 }
 
-static int intel_sdvo_get_modes(struct drm_connector *connector)
+static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
 {
-	struct intel_output *intel_output = to_intel_output(connector);
+	struct intel_output *intel_output =
+		enc_to_intel_output(connector->encoder);
 
-	/* set the bus switch and get the modes */
 	intel_sdvo_set_control_bus_switch(intel_output, SDVO_CONTROL_BUS_DDC2);
 	intel_ddc_get_modes(intel_output);
 
+#if 0
+	struct drm_device *dev = encoder->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+	/* Mac mini hack.  On this device, I get DDC through the analog, which
+	 * load-detects as disconnected.  I fail to DDC through the SDVO DDC,
+	 * but it does load-detect as connected.  So, just steal the DDC bits
+	 * from analog when we fail at finding it the right way.
+	 */
+	crt = xf86_config->output[0];
+	intel_output = crt->driver_private;
+	if (intel_output->type == I830_OUTPUT_ANALOG &&
+	    crt->funcs->detect(crt) == XF86OutputStatusDisconnected) {
+		I830I2CInit(pScrn, &intel_output->pDDCBus, GPIOA, "CRTDDC_A");
+		edid_mon = xf86OutputGetEDID(crt, intel_output->pDDCBus);
+		xf86DestroyI2CBusRec(intel_output->pDDCBus, true, true);
+	}
+	if (edid_mon) {
+		xf86OutputSetEDID(output, edid_mon);
+		modes = xf86OutputGetEDIDModes(output);
+	}
+#endif
+}
+
+/**
+ * This function checks the current TV format, and chooses a default if
+ * it hasn't been set.
+ */
+static void
+intel_sdvo_check_tv_format(struct intel_output *output)
+{
+	struct intel_sdvo_priv *dev_priv = output->dev_priv;
+	struct intel_sdvo_tv_format format, unset;
+	uint8_t status;
+
+	intel_sdvo_write_cmd(output, SDVO_CMD_GET_TV_FORMAT, NULL, 0);
+	status = intel_sdvo_read_response(output, &format, sizeof(format));
+	if (status != SDVO_CMD_STATUS_SUCCESS)
+		return;
+
+	memset(&unset, 0, sizeof(unset));
+	if (memcmp(&format, &unset, sizeof(format))) {
+		DRM_DEBUG("%s: Choosing default TV format of NTSC-M\n",
+			  SDVO_NAME(dev_priv));
+
+		format.ntsc_m = true;
+		intel_sdvo_write_cmd(output, SDVO_CMD_SET_TV_FORMAT, NULL, 0);
+		status = intel_sdvo_read_response(output, NULL, 0);
+	}
+}
+
+/*
+ * Set of SDVO TV modes.
+ * Note!  This is in reply order (see loop in get_tv_modes).
+ * XXX: all 60Hz refresh?
+ */
+struct drm_display_mode sdvo_tv_modes[] = {
+        { DRM_MODE("320x200", DRM_MODE_TYPE_DRIVER, 5815680, 321, 384, 416,
+		   200, 0, 232, 201, 233, 4196112, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+        { DRM_MODE("320x240", DRM_MODE_TYPE_DRIVER, 6814080, 321, 384, 416,
+		   240, 0, 272, 241, 273, 4196112, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+        { DRM_MODE("400x300", DRM_MODE_TYPE_DRIVER, 9910080, 401, 464, 496,
+		   300, 0, 332, 301, 333, 4196112, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+        { DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 16913280, 641, 704, 736,
+		   350, 0, 382, 351, 383, 4196112, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+        { DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 19121280, 641, 704, 736,
+		   400, 0, 432, 401, 433, 4196112, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+        { DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 19121280, 641, 704, 736,
+		   400, 0, 432, 401, 433, 4196112, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+        { DRM_MODE("704x480", DRM_MODE_TYPE_DRIVER, 24624000, 705, 768, 800,
+		   480, 0, 512, 481, 513, 4196112, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+        { DRM_MODE("704x576", DRM_MODE_TYPE_DRIVER, 29232000, 705, 768, 800,
+		   576, 0, 608, 577, 609, 4196112, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+        { DRM_MODE("720x350", DRM_MODE_TYPE_DRIVER, 18751680, 721, 784, 816,
+		   350, 0, 382, 351, 383, 4196112, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+        { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 21199680, 721, 784, 816,
+		   400, 0, 432, 401, 433, 4196112, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+        { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 25116480, 721, 784, 816,
+		   480, 0, 512, 481, 513, 4196112, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+        { DRM_MODE("720x540", DRM_MODE_TYPE_DRIVER, 28054080, 721, 784, 816,
+		   540, 0, 572, 541, 573, 4196112, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+        { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 29816640, 721, 784, 816,
+		   576, 0, 608, 577, 609, 4196112, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+        { DRM_MODE("768x576", DRM_MODE_TYPE_DRIVER, 31570560, 769, 832, 864,
+		   576, 0, 608, 577, 609, 4196112, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+        { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 34030080, 801, 864, 896,
+		   600, 0, 632, 601, 633, 4196112, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+        { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 36581760, 833, 896, 928,
+		   624, 0, 656, 625, 657, 4196112, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+        { DRM_MODE("920x766", DRM_MODE_TYPE_DRIVER, 48707040, 921, 984, 1016,
+		   766, 0, 798, 767, 799, 4196112, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+        { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 53827200, 1025, 1088, 
1120,
+		   768, 0, 800, 769, 801, 4196112, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+        { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 87265920, 1281, 1344, 
1376,
+		   1024, 0, 1056, 1025, 1057, 4196112, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+};
+
+static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
+{
+	struct intel_output *output = enc_to_intel_output(connector->encoder);
+	uint32_t reply = 0;
+	uint8_t status;
+	int i = 0;
+
+	intel_sdvo_check_tv_format(output);
+
+	/* Read the list of supported input resolutions for the selected TV
+	 * format.
+	 */
+	intel_sdvo_write_cmd(output, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
+			     NULL, 0);
+	status = intel_sdvo_read_response(output, &reply, 3);
+	if (status != SDVO_CMD_STATUS_SUCCESS)
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(sdvo_tv_modes); i++)
+		if (reply & (1 << i))
+			drm_mode_probed_add(connector, &sdvo_tv_modes[i]);
+}
+
+static int intel_sdvo_get_modes(struct drm_connector *connector)
+{
+	struct intel_output *output = enc_to_intel_output(connector->encoder);
+	struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
+
+	if (sdvo_priv->is_tv)
+		intel_sdvo_get_tv_modes(connector);
+	else
+		intel_sdvo_get_ddc_modes(connector);
+
 	if (list_empty(&connector->probed_modes))
 		return 0;
 	return 1;
@@ -978,6 +1567,65 @@ static const struct drm_encoder_funcs 
intel_sdvo_enc_funcs = {
 };
 
 
+/**
+ * Choose the appropriate DDC bus for control bus switch command for this
+ * SDVO output based on the controlled output.
+ *
+ * DDC bus number assignment is in a priority order of RGB outputs, then TMDS
+ * outputs, then LVDS outputs.
+ */
+static void
+intel_sdvo_select_ddc_bus(struct intel_sdvo_priv *dev_priv)
+{
+    uint16_t mask = 0;
+    unsigned int num_bits;
+
+    /* Make a mask of outputs less than or equal to our own priority in the
+     * list.
+     */
+    switch (dev_priv->controlled_output) {
+    case SDVO_OUTPUT_LVDS1:
+	mask |= SDVO_OUTPUT_LVDS1;
+    case SDVO_OUTPUT_LVDS0:
+	mask |= SDVO_OUTPUT_LVDS0;
+    case SDVO_OUTPUT_TMDS1:
+	mask |= SDVO_OUTPUT_TMDS1;
+    case SDVO_OUTPUT_TMDS0:
+	mask |= SDVO_OUTPUT_TMDS0;
+    case SDVO_OUTPUT_RGB1:
+	mask |= SDVO_OUTPUT_RGB1;
+    case SDVO_OUTPUT_RGB0:
+	mask |= SDVO_OUTPUT_RGB0;
+	break;
+    }
+
+    /* Count bits to find what number we are in the priority list. */
+    mask &= dev_priv->caps.output_flags;
+    num_bits = hweight16(mask);
+    if (num_bits > 3) {
+	/* if more than 3 outputs, default to DDC bus 3 for now */
+	num_bits = 3;
+    }
+
+    /* Corresponds to SDVO_CONTROL_BUS_DDCx */
+    dev_priv->ddc_bus = 1 << num_bits;
+}
+
+static bool
+intel_sdvo_get_digital_encoding_mode(struct intel_output *output)
+{
+	struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
+	uint8_t status;
+
+	intel_sdvo_set_target_output(output, sdvo_priv->controlled_output);
+
+	intel_sdvo_write_cmd(output, SDVO_CMD_GET_ENCODE, NULL, 0);
+	status = intel_sdvo_read_response(output, &sdvo_priv->is_hdmi, 1);
+	if (status != SDVO_CMD_STATUS_SUCCESS)
+		return false;
+	return true;
+}
+
 bool intel_sdvo_init(struct drm_device *dev, int output_device)
 {
 	struct drm_connector *connector;
@@ -989,7 +1637,8 @@ bool intel_sdvo_init(struct drm_device *dev, int 
output_device)
 	int i;
 	int encoder_type, output_id;
 
-	intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct 
intel_sdvo_priv), 1, GFP_KERNEL);
+	intel_output = kcalloc(sizeof(struct intel_output) +
+			       sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL);
 	if (!intel_output) {
 		return false;
 	}
@@ -1040,45 +1689,76 @@ bool intel_sdvo_init(struct drm_device *dev, int 
output_device)
 
 	intel_sdvo_get_capabilities(intel_output, &sdvo_priv->caps);
 
-	memset(&sdvo_priv->active_outputs, 0, sizeof(sdvo_priv->active_outputs));
+	if (sdvo_priv->caps.output_flags &
+	    (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) {
+		if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0)
+			sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS0;
+		else
+			sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS1;
+
+		connector->display_info.subpixel_order = SubPixelHorizontalRGB;
+		encoder_type = DRM_MODE_ENCODER_TMDS;
+		connector_type = DRM_MODE_CONNECTOR_DVID;
 
-	/* TODO, CVBS, SVID, YPRPB & SCART outputs. */
-	if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0)
+		if (intel_sdvo_get_supp_encode(intel_output,
+					       &sdvo_priv->encode) &&
+		    intel_sdvo_get_digital_encoding_mode(intel_output) &&
+		    sdvo_priv->is_hdmi) {
+			/* enable hdmi encoding mode if supported */
+			intel_sdvo_set_encode(intel_output, SDVO_ENCODE_HDMI);
+			intel_sdvo_set_colorimetry(intel_output,
+						   SDVO_COLORIMETRY_RGB256);
+			connector_type = DRM_MODE_CONNECTOR_HDMIA;
+		}
+	}
+	else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_SVID0)
+	{
+		sdvo_priv->controlled_output = SDVO_OUTPUT_SVID0;
+		connector->display_info.subpixel_order = SubPixelHorizontalRGB;
+		encoder_type = DRM_MODE_ENCODER_TVDAC;
+		connector_type = DRM_MODE_CONNECTOR_SVIDEO;
+		sdvo_priv->is_tv = true;
+		intel_output->needs_tv_clock = true;
+	}
+	else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0)
 	{
-		sdvo_priv->active_outputs = SDVO_OUTPUT_RGB0;
+		sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0;
 		connector->display_info.subpixel_order = SubPixelHorizontalRGB;
 		encoder_type = DRM_MODE_ENCODER_DAC;
 		connector_type = DRM_MODE_CONNECTOR_VGA;
 	}
 	else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1)
 	{
-		sdvo_priv->active_outputs = SDVO_OUTPUT_RGB1;
+		sdvo_priv->controlled_output = SDVO_OUTPUT_RGB1;
 		connector->display_info.subpixel_order = SubPixelHorizontalRGB;
 		encoder_type = DRM_MODE_ENCODER_DAC;
 		connector_type = DRM_MODE_CONNECTOR_VGA;
 	}
-	else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0)
+	else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS0)
 	{
-		sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS0;
+		sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0;
 		connector->display_info.subpixel_order = SubPixelHorizontalRGB;
-		encoder_type = DRM_MODE_ENCODER_TMDS;
-		connector_type = DRM_MODE_CONNECTOR_DVID;
+		encoder_type = DRM_MODE_ENCODER_LVDS;
+		connector_type = DRM_MODE_CONNECTOR_LVDS;
 	}
-	else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS1)
+	else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS1)
 	{
-		sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS1;
+		sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS1;
 		connector->display_info.subpixel_order = SubPixelHorizontalRGB;
-		encoder_type = DRM_MODE_ENCODER_TMDS;
-		connector_type = DRM_MODE_CONNECTOR_DVID;
+		encoder_type = DRM_MODE_ENCODER_LVDS;
+		connector_type = DRM_MODE_CONNECTOR_LVDS;
 	}
 	else
 	{
 		unsigned char bytes[2];
 
+		sdvo_priv->controlled_output = 0;
 		memcpy (bytes, &sdvo_priv->caps.output_flags, 2);
-		DRM_DEBUG("%s: No active RGB or TMDS outputs (0x%02x%02x)\n",
+		DRM_DEBUG("%s: Unknown SDVO output type (0x%02x%02x)\n",
 			  SDVO_NAME(sdvo_priv),
 			  bytes[0], bytes[1]);
+		encoder_type = DRM_MODE_ENCODER_NONE;
+		connector_type = DRM_MODE_CONNECTOR_Unknown;
 		goto err_i2c;
 	}
 
@@ -1089,6 +1769,8 @@ bool intel_sdvo_init(struct drm_device *dev, int 
output_device)
 	drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
 	drm_sysfs_connector_add(connector);
 
+	intel_sdvo_select_ddc_bus(sdvo_priv);
+
 	/* Set the input timing to the screen. Assume always input 0. */
 	intel_sdvo_set_target_input(intel_output, true, false);
 
diff --git a/drivers/gpu/drm/i915/intel_sdvo_regs.h 
b/drivers/gpu/drm/i915/intel_sdvo_regs.h
index 861a43f..1117b9c 100644
--- a/drivers/gpu/drm/i915/intel_sdvo_regs.h
+++ b/drivers/gpu/drm/i915/intel_sdvo_regs.h
@@ -173,6 +173,9 @@ struct intel_sdvo_get_trained_inputs_response {
  * Returns two struct intel_sdvo_output_flags structures.
  */
 #define SDVO_CMD_GET_IN_OUT_MAP				0x06
+struct intel_sdvo_in_out_map {
+    u16 in0, in1;
+};
 
 /**
  * Sets the current mapping of SDVO inputs to outputs on the device.
@@ -206,7 +209,8 @@ struct intel_sdvo_get_trained_inputs_response {
 struct intel_sdvo_get_interrupt_event_source_response {
     u16 interrupt_status;
     unsigned int ambient_light_interrupt:1;
-    unsigned int pad:7;
+    unsigned int hdmi_audio_encrypt_change:1;
+    unsigned int pad:6;
 } __attribute__((packed));
 
 /**
@@ -305,23 +309,411 @@ struct intel_sdvo_set_target_input_args {
 # define SDVO_CLOCK_RATE_MULT_4X				(1 << 3)
 
 #define SDVO_CMD_GET_SUPPORTED_TV_FORMATS		0x27
+/** 5 bytes of bit flags for TV formats shared by all TV format functions */
+struct intel_sdvo_tv_format {
+    unsigned int ntsc_m:1;
+    unsigned int ntsc_j:1;
+    unsigned int ntsc_443:1;
+    unsigned int pal_b:1;
+    unsigned int pal_d:1;
+    unsigned int pal_g:1;
+    unsigned int pal_h:1;
+    unsigned int pal_i:1;
+
+    unsigned int pal_m:1;
+    unsigned int pal_n:1;
+    unsigned int pal_nc:1;
+    unsigned int pal_60:1;
+    unsigned int secam_b:1;
+    unsigned int secam_d:1;
+    unsigned int secam_g:1;
+    unsigned int secam_k:1;
+
+    unsigned int secam_k1:1;
+    unsigned int secam_l:1;
+    unsigned int secam_60:1;
+    unsigned int hdtv_std_smpte_240m_1080i_59:1;
+    unsigned int hdtv_std_smpte_240m_1080i_60:1;
+    unsigned int hdtv_std_smpte_260m_1080i_59:1;
+    unsigned int hdtv_std_smpte_260m_1080i_60:1;
+    unsigned int hdtv_std_smpte_274m_1080i_50:1;
+
+    unsigned int hdtv_std_smpte_274m_1080i_59:1;
+    unsigned int hdtv_std_smpte_274m_1080i_60:1;
+    unsigned int hdtv_std_smpte_274m_1080p_23:1;
+    unsigned int hdtv_std_smpte_274m_1080p_24:1;
+    unsigned int hdtv_std_smpte_274m_1080p_25:1;
+    unsigned int hdtv_std_smpte_274m_1080p_29:1;
+    unsigned int hdtv_std_smpte_274m_1080p_30:1;
+    unsigned int hdtv_std_smpte_274m_1080p_50:1;
+
+    unsigned int hdtv_std_smpte_274m_1080p_59:1;
+    unsigned int hdtv_std_smpte_274m_1080p_60:1;
+    unsigned int hdtv_std_smpte_295m_1080i_50:1;
+    unsigned int hdtv_std_smpte_295m_1080p_50:1;
+    unsigned int hdtv_std_smpte_296m_720p_59:1;
+    unsigned int hdtv_std_smpte_296m_720p_60:1;
+    unsigned int hdtv_std_smpte_296m_720p_50:1;
+    unsigned int hdtv_std_smpte_293m_480p_59:1;
+
+    unsigned int hdtv_std_smpte_170m_480i_59:1;
+    unsigned int hdtv_std_iturbt601_576i_50:1;
+    unsigned int hdtv_std_iturbt601_576p_50:1;
+    unsigned int hdtv_std_eia_7702a_480i_60:1;
+    unsigned int hdtv_std_eia_7702a_480p_60:1;
+    unsigned int pad:3;
+} __attribute__((packed));
 
 #define SDVO_CMD_GET_TV_FORMAT				0x28
 
 #define SDVO_CMD_SET_TV_FORMAT				0x29
 
+/** Returns the resolutiosn that can be used with the given TV format */
+#define SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT		0x83
+struct intel_sdvo_sdtv_resolution_request {
+    unsigned int ntsc_m:1;
+    unsigned int ntsc_j:1;
+    unsigned int ntsc_443:1;
+    unsigned int pal_b:1;
+    unsigned int pal_d:1;
+    unsigned int pal_g:1;
+    unsigned int pal_h:1;
+    unsigned int pal_i:1;
+
+    unsigned int pal_m:1;
+    unsigned int pal_n:1;
+    unsigned int pal_nc:1;
+    unsigned int pal_60:1;
+    unsigned int secam_b:1;
+    unsigned int secam_d:1;
+    unsigned int secam_g:1;
+    unsigned int secam_k:1;
+
+    unsigned int secam_k1:1;
+    unsigned int secam_l:1;
+    unsigned int secam_60:1;
+    unsigned int pad:5;
+} __attribute__((packed));
+
+struct intel_sdvo_sdtv_resolution_reply {
+    unsigned int res_320x200:1;
+    unsigned int res_320x240:1;
+    unsigned int res_400x300:1;
+    unsigned int res_640x350:1;
+    unsigned int res_640x400:1;
+    unsigned int res_640x480:1;
+    unsigned int res_704x480:1;
+    unsigned int res_704x576:1;
+
+    unsigned int res_720x350:1;
+    unsigned int res_720x400:1;
+    unsigned int res_720x480:1;
+    unsigned int res_720x540:1;
+    unsigned int res_720x576:1;
+    unsigned int res_768x576:1;
+    unsigned int res_800x600:1;
+    unsigned int res_832x624:1;
+
+    unsigned int res_920x766:1;
+    unsigned int res_1024x768:1;
+    unsigned int res_1280x1024:1;
+    unsigned int pad:5;
+} __attribute__((packed));
+
+/* Get supported resolution with squire pixel aspect ratio that can be
+   scaled for the requested HDTV format */
+#define SDVO_CMD_GET_SCALED_HDTV_RESOLUTION_SUPPORT		0x85
+
+struct intel_sdvo_hdtv_resolution_request {
+    unsigned int hdtv_std_smpte_240m_1080i_59:1;
+    unsigned int hdtv_std_smpte_240m_1080i_60:1;
+    unsigned int hdtv_std_smpte_260m_1080i_59:1;
+    unsigned int hdtv_std_smpte_260m_1080i_60:1;
+    unsigned int hdtv_std_smpte_274m_1080i_50:1;
+    unsigned int hdtv_std_smpte_274m_1080i_59:1;
+    unsigned int hdtv_std_smpte_274m_1080i_60:1;
+    unsigned int hdtv_std_smpte_274m_1080p_23:1;
+
+    unsigned int hdtv_std_smpte_274m_1080p_24:1;
+    unsigned int hdtv_std_smpte_274m_1080p_25:1;
+    unsigned int hdtv_std_smpte_274m_1080p_29:1;
+    unsigned int hdtv_std_smpte_274m_1080p_30:1;
+    unsigned int hdtv_std_smpte_274m_1080p_50:1;
+    unsigned int hdtv_std_smpte_274m_1080p_59:1;
+    unsigned int hdtv_std_smpte_274m_1080p_60:1;
+    unsigned int hdtv_std_smpte_295m_1080i_50:1;
+
+    unsigned int hdtv_std_smpte_295m_1080p_50:1;
+    unsigned int hdtv_std_smpte_296m_720p_59:1;
+    unsigned int hdtv_std_smpte_296m_720p_60:1;
+    unsigned int hdtv_std_smpte_296m_720p_50:1;
+    unsigned int hdtv_std_smpte_293m_480p_59:1;
+    unsigned int hdtv_std_smpte_170m_480i_59:1;
+    unsigned int hdtv_std_iturbt601_576i_50:1;
+    unsigned int hdtv_std_iturbt601_576p_50:1;
+
+    unsigned int hdtv_std_eia_7702a_480i_60:1;
+    unsigned int hdtv_std_eia_7702a_480p_60:1;
+    unsigned int pad:6;
+} __attribute__((packed));
+
+struct intel_sdvo_hdtv_resolution_reply {
+    unsigned int res_640x480:1;
+    unsigned int res_800x600:1;
+    unsigned int res_1024x768:1;
+    unsigned int res_1280x960:1;
+    unsigned int res_1400x1050:1;
+    unsigned int res_1600x1200:1;
+    unsigned int res_1920x1440:1;
+    unsigned int res_2048x1536:1;
+
+    unsigned int res_2560x1920:1;
+    unsigned int res_3200x2400:1;
+    unsigned int res_3840x2880:1;
+    unsigned int pad1:5;
+
+    unsigned int res_848x480:1;
+    unsigned int res_1064x600:1;
+    unsigned int res_1280x720:1;
+    unsigned int res_1360x768:1;
+    unsigned int res_1704x960:1;
+    unsigned int res_1864x1050:1;
+    unsigned int res_1920x1080:1;
+    unsigned int res_2128x1200:1;
+
+    unsigned int res_2560x1400:1;
+    unsigned int res_2728x1536:1;
+    unsigned int res_3408x1920:1;
+    unsigned int res_4264x2400:1;
+    unsigned int res_5120x2880:1;
+    unsigned int pad2:3;
+
+    unsigned int res_768x480:1;
+    unsigned int res_960x600:1;
+    unsigned int res_1152x720:1;
+    unsigned int res_1124x768:1;
+    unsigned int res_1536x960:1;
+    unsigned int res_1680x1050:1;
+    unsigned int res_1728x1080:1;
+    unsigned int res_1920x1200:1;
+
+    unsigned int res_2304x1440:1;
+    unsigned int res_2456x1536:1;
+    unsigned int res_3072x1920:1;
+    unsigned int res_3840x2400:1;
+    unsigned int res_4608x2880:1;
+    unsigned int pad3:3;
+
+    unsigned int res_1280x1024:1;
+    unsigned int pad4:7;
+
+    unsigned int res_1280x768:1;
+    unsigned int pad5:7;
+} __attribute__((packed));
+
+/* Get supported power state returns info for encoder and monitor, rely on
+   last SetTargetInput and SetTargetOutput calls */
 #define SDVO_CMD_GET_SUPPORTED_POWER_STATES		0x2a
+/* Get power state returns info for encoder and monitor, rely on last
+   SetTargetInput and SetTargetOutput calls */
+#define SDVO_CMD_GET_POWER_STATE			0x2b
 #define SDVO_CMD_GET_ENCODER_POWER_STATE		0x2b
 #define SDVO_CMD_SET_ENCODER_POWER_STATE		0x2c
 # define SDVO_ENCODER_STATE_ON					(1 << 0)
 # define SDVO_ENCODER_STATE_STANDBY				(1 << 1)
 # define SDVO_ENCODER_STATE_SUSPEND				(1 << 2)
 # define SDVO_ENCODER_STATE_OFF					(1 << 3)
+# define SDVO_MONITOR_STATE_ON					(1 << 4)
+# define SDVO_MONITOR_STATE_STANDBY				(1 << 5)
+# define SDVO_MONITOR_STATE_SUSPEND				(1 << 6)
+# define SDVO_MONITOR_STATE_OFF					(1 << 7)
+
+#define SDVO_CMD_GET_MAX_PANEL_POWER_SEQUENCING		0x2d
+#define SDVO_CMD_GET_PANEL_POWER_SEQUENCING		0x2e
+#define SDVO_CMD_SET_PANEL_POWER_SEQUENCING		0x2f
+/**
+ * The panel power sequencing parameters are in units of milliseconds.
+ * The high fields are bits 8:9 of the 10-bit values.
+ */
+struct sdvo_panel_power_sequencing {
+    u8 t0;
+    u8 t1;
+    u8 t2;
+    u8 t3;
+    u8 t4;
+
+    unsigned int t0_high:2;
+    unsigned int t1_high:2;
+    unsigned int t2_high:2;
+    unsigned int t3_high:2;
+
+    unsigned int t4_high:2;
+    unsigned int pad:6;
+} __attribute__((packed));
+
+#define SDVO_CMD_GET_MAX_BACKLIGHT_LEVEL		0x30
+struct sdvo_max_backlight_reply {
+    u8 max_value;
+    u8 default_value;
+} __attribute__((packed));
+
+#define SDVO_CMD_GET_BACKLIGHT_LEVEL			0x31
+#define SDVO_CMD_SET_BACKLIGHT_LEVEL			0x32
+
+#define SDVO_CMD_GET_AMBIENT_LIGHT			0x33
+struct sdvo_get_ambient_light_reply {
+    u16 trip_low;
+    u16 trip_high;
+    u16 value;
+} __attribute__((packed));
+#define SDVO_CMD_SET_AMBIENT_LIGHT			0x34
+struct sdvo_set_ambient_light_reply {
+    u16 trip_low;
+    u16 trip_high;
+    unsigned int enable:1;
+    unsigned int pad:7;
+} __attribute__((packed));
+
+/* Set display power state */
+#define SDVO_CMD_SET_DISPLAY_POWER_STATE		0x7d
+# define SDVO_DISPLAY_STATE_ON				(1 << 0)
+# define SDVO_DISPLAY_STATE_STANDBY			(1 << 1)
+# define SDVO_DISPLAY_STATE_SUSPEND			(1 << 2)
+# define SDVO_DISPLAY_STATE_OFF				(1 << 3)
+
+#define SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS		0x84
+struct intel_sdvo_enhancements_reply {
+    unsigned int flicker_filter:1;
+    unsigned int flicker_filter_adaptive:1;
+    unsigned int flicker_filter_2d:1;
+    unsigned int saturation:1;
+    unsigned int hue:1;
+    unsigned int brightness:1;
+    unsigned int contrast:1;
+    unsigned int overscan_h:1;
+
+    unsigned int overscan_v:1;
+    unsigned int position_h:1;
+    unsigned int position_v:1;
+    unsigned int sharpness:1;
+    unsigned int dot_crawl:1;
+    unsigned int dither:1;
+    unsigned int max_tv_chroma_filter:1;
+    unsigned int max_tv_luma_filter:1;
+} __attribute__((packed));
+
+/* Picture enhancement limits below are dependent on the current TV format,
+ * and thus need to be queried and set after it.
+ */
+#define SDVO_CMD_GET_MAX_FLICKER_FITER			0x4d
+#define SDVO_CMD_GET_MAX_ADAPTIVE_FLICKER_FITER		0x7b
+#define SDVO_CMD_GET_MAX_2D_FLICKER_FITER		0x52
+#define SDVO_CMD_GET_MAX_SATURATION			0x55
+#define SDVO_CMD_GET_MAX_HUE				0x58
+#define SDVO_CMD_GET_MAX_BRIGHTNESS			0x5b
+#define SDVO_CMD_GET_MAX_CONTRAST			0x5e
+#define SDVO_CMD_GET_MAX_OVERSCAN_H			0x61
+#define SDVO_CMD_GET_MAX_OVERSCAN_V			0x64
+#define SDVO_CMD_GET_MAX_POSITION_H			0x67
+#define SDVO_CMD_GET_MAX_POSITION_V			0x6a
+#define SDVO_CMD_GET_MAX_SHARPNESS_V			0x6d
+#define SDVO_CMD_GET_MAX_TV_CHROMA			0x74
+#define SDVO_CMD_GET_MAX_TV_LUMA			0x77
+struct intel_sdvo_enhancement_limits_reply {
+    u16 max_value;
+    u16 default_value;
+} __attribute__((packed));
 
-#define SDVO_CMD_SET_TV_RESOLUTION_SUPPORT		0x93
+#define SDVO_CMD_GET_LVDS_PANEL_INFORMATION		0x7f
+#define SDVO_CMD_SET_LVDS_PANEL_INFORMATION		0x80
+# define SDVO_LVDS_COLOR_DEPTH_18			(0 << 0)
+# define SDVO_LVDS_COLOR_DEPTH_24			(1 << 0)
+# define SDVO_LVDS_CONNECTOR_SPWG			(0 << 2)
+# define SDVO_LVDS_CONNECTOR_OPENLDI			(1 << 2)
+# define SDVO_LVDS_SINGLE_CHANNEL			(0 << 4)
+# define SDVO_LVDS_DUAL_CHANNEL				(1 << 4)
+
+#define SDVO_CMD_GET_FLICKER_FILTER			0x4e
+#define SDVO_CMD_SET_FLICKER_FILTER			0x4f
+#define SDVO_CMD_GET_ADAPTIVE_FLICKER_FITER		0x50
+#define SDVO_CMD_SET_ADAPTIVE_FLICKER_FITER		0x51
+#define SDVO_CMD_GET_2D_FLICKER_FITER			0x53
+#define SDVO_CMD_SET_2D_FLICKER_FITER			0x54
+#define SDVO_CMD_GET_SATURATION				0x56
+#define SDVO_CMD_SET_SATURATION				0x57
+#define SDVO_CMD_GET_HUE				0x59
+#define SDVO_CMD_SET_HUE				0x5a
+#define SDVO_CMD_GET_BRIGHTNESS				0x5c
+#define SDVO_CMD_SET_BRIGHTNESS				0x5d
+#define SDVO_CMD_GET_CONTRAST				0x5f
+#define SDVO_CMD_SET_CONTRAST				0x60
+#define SDVO_CMD_GET_OVERSCAN_H				0x62
+#define SDVO_CMD_SET_OVERSCAN_H				0x63
+#define SDVO_CMD_GET_OVERSCAN_V				0x65
+#define SDVO_CMD_SET_OVERSCAN_V				0x66
+#define SDVO_CMD_GET_POSITION_H				0x68
+#define SDVO_CMD_SET_POSITION_H				0x69
+#define SDVO_CMD_GET_POSITION_V				0x6b
+#define SDVO_CMD_SET_POSITION_V				0x6c
+#define SDVO_CMD_GET_SHARPNESS				0x6e
+#define SDVO_CMD_SET_SHARPNESS				0x6f
+#define SDVO_CMD_GET_TV_CHROMA				0x75
+#define SDVO_CMD_SET_TV_CHROMA				0x76
+#define SDVO_CMD_GET_TV_LUMA				0x78
+#define SDVO_CMD_SET_TV_LUMA				0x79
+struct intel_sdvo_enhancements_arg {
+    u16 value;
+}__attribute__((packed));
+
+#define SDVO_CMD_GET_DOT_CRAWL				0x70
+#define SDVO_CMD_SET_DOT_CRAWL				0x71
+# define SDVO_DOT_CRAWL_ON					(1 << 0)
+# define SDVO_DOT_CRAWL_DEFAULT_ON				(1 << 1)
+
+#define SDVO_CMD_GET_DITHER				0x72
+#define SDVO_CMD_SET_DITHER				0x73
+# define SDVO_DITHER_ON						(1 << 0)
+# define SDVO_DITHER_DEFAULT_ON					(1 << 1)
 
 #define SDVO_CMD_SET_CONTROL_BUS_SWITCH			0x7a
-# define SDVO_CONTROL_BUS_PROM				0x0
-# define SDVO_CONTROL_BUS_DDC1				0x1
-# define SDVO_CONTROL_BUS_DDC2				0x2
-# define SDVO_CONTROL_BUS_DDC3				0x3
+# define SDVO_CONTROL_BUS_PROM				(1 << 0)
+# define SDVO_CONTROL_BUS_DDC1				(1 << 1)
+# 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 intel_sdvo_encode{
+    u8 dvi_rev;
+    u8 hdmi_rev;
+} __attribute__ ((packed));



More information about the Intel-gfx mailing list