diff mbox

[3/4] drm/i915: implement multifunction SDVO device support

Message ID 1268101319-4841-4-git-send-email-zhenyuw@linux.intel.com (mailing list archive)
State Accepted
Headers show

Commit Message

Zhenyu Wang March 9, 2010, 2:21 a.m. UTC
None
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 60057eb..6181594 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -36,6 +36,17 @@ 
 #include "i915_drv.h"
 #include "intel_sdvo_regs.h"
 
+#define SDVO_TMDS_MASK	(SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)
+#define SDVO_RGB_MASK	(SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1)
+#define SDVO_LVDS_MASK	(SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1)
+#define SDVO_TV_MASK	(SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_SVID0)
+
+#define SDVO_OUTPUT_MASK (SDVO_TMDS_MASK | SDVO_RGB_MASK | SDVO_LVDS_MASK |\
+			  SDVO_TV_MASK)
+
+#define SDVO_CONNECTOR_IS_TV(c)		(c->output_flag & SDVO_TV_MASK)
+#define SDVO_CONNECTOR_IS_LVDS(c)	(c->output_flag & SDVO_LVDS_MASK)
+
 static char *tv_format_names[] = {
 	"NTSC_M"   , "NTSC_J"  , "NTSC_443",
 	"PAL_B"    , "PAL_D"   , "PAL_G"   ,
@@ -48,7 +59,7 @@  static char *tv_format_names[] = {
 
 #define TV_FORMAT_NUM  (sizeof(tv_format_names) / sizeof(*tv_format_names))
 
-struct intel_sdvo_priv {
+struct intel_sdvo_encoder {
 	u8 slave_addr;
 
 	/* Register for the SDVO device: SDVOB or SDVOC */
@@ -72,6 +83,9 @@  struct intel_sdvo_priv {
 	*/
 	uint16_t attached_output;
 
+	/* DDC bus used by this SDVO output */
+	uint8_t ddc_bus;
+
 	/**
 	 * This is set if we're going to treat the device as TV-out.
 	 *
@@ -81,15 +95,6 @@  struct intel_sdvo_priv {
 	 */
 	bool is_tv;
 
-	/* This is for current tv format name */
-	char *tv_format_name;
-
-	/* This contains all current supported TV format */
-	char *tv_format_supported[TV_FORMAT_NUM];
-	int   format_supported_num;
-	struct drm_property *tv_format_property;
-	struct drm_property *tv_format_name_property[TV_FORMAT_NUM];
-
 	/**
 	 * This is set if we treat the device as HDMI, instead of DVI.
 	 */
@@ -101,38 +106,50 @@  struct intel_sdvo_priv {
 	bool is_lvds;
 
 	/**
-	 * This is sdvo flags for input timing.
-	 */
-	uint8_t sdvo_flags;
-
-	/**
 	 * This is sdvo fixed pannel mode pointer
 	 */
 	struct drm_display_mode *sdvo_lvds_fixed_mode;
 
-	/**
-	 * Returned SDTV resolutions allowed for the current format, if the
-	 * device reported it.
-	 */
-	struct intel_sdvo_sdtv_resolution_reply sdtv_resolutions;
-
 	/*
 	 * 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;
+	/**
+	 * This is sdvo flags for input timing.
+	 */
+	uint8_t sdvo_flags;
 
-	/* Mac mini hack -- use the same DDC as the analog connector */
-	struct i2c_adapter *analog_ddc_bus;
+	/* This is for current tv format name */
+	char *tv_format_name;
 
 	int save_sdvo_mult;
 	u16 save_active_outputs;
 	struct intel_sdvo_dtd save_input_dtd_1, save_input_dtd_2;
 	struct intel_sdvo_dtd save_output_dtd[16];
 	u32 save_SDVOX;
+};
+
+struct intel_sdvo_connector {
+	/* Mark the type of connector */
+	uint16_t output_flag;
+
+	/* This contains all current supported TV format */
+	char *tv_format_supported[TV_FORMAT_NUM];
+	int   format_supported_num;
+	struct drm_property *tv_format_property;
+	struct drm_property *tv_format_name_property[TV_FORMAT_NUM];
+
+	/**
+	 * Returned SDTV resolutions allowed for the current format, if the
+	 * device reported it.
+	 */
+	struct intel_sdvo_sdtv_resolution_reply sdtv_resolutions;
+
+	/* Mac mini hack -- use the same DDC as the analog connector */
+	struct i2c_adapter *analog_ddc_bus;
+
 	/* add the property for the SDVO-TV */
 	struct drm_property *left_property;
 	struct drm_property *right_property;
@@ -160,8 +177,13 @@  struct intel_sdvo_priv {
 };
 
 static bool
-intel_sdvo_output_setup(struct intel_encoder *intel_encoder,
-			struct intel_connector *intel_connector, uint16_t flags);
+intel_sdvo_output_setup(struct intel_encoder *intel_encoder);
+static void
+intel_sdvo_tv_create_property(struct drm_encoder *encoder,
+			      struct drm_connector *connector);
+static void
+intel_sdvo_create_enhance_property(struct drm_encoder *encoder,
+				   struct drm_connector *connector);
 
 /**
  * Writes the SDVOB or SDVOC with the given value, but always writes both
@@ -172,11 +194,11 @@  static void intel_sdvo_write_sdvox(struct intel_encoder *intel_encoder, u32 val)
 {
 	struct drm_device *dev = intel_encoder->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_sdvo_priv   *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
 	u32 bval = val, cval = val;
 	int i;
 
-	if (sdvo_priv->output_device == SDVOB) {
+	if (sdvo_encoder->output_device == SDVOB) {
 		cval = I915_READ(SDVOC);
 	} else {
 		bval = I915_READ(SDVOB);
@@ -198,20 +220,20 @@  static void intel_sdvo_write_sdvox(struct intel_encoder *intel_encoder, u32 val)
 static bool intel_sdvo_read_byte(struct intel_encoder *intel_encoder, u8 addr,
 				 u8 *ch)
 {
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
 	u8 out_buf[2];
 	u8 buf[2];
 	int ret;
 
 	struct i2c_msg msgs[] = {
 		{
-			.addr = sdvo_priv->slave_addr >> 1,
+			.addr = sdvo_encoder->slave_addr >> 1,
 			.flags = 0,
 			.len = 1,
 			.buf = out_buf,
 		},
 		{
-			.addr = sdvo_priv->slave_addr >> 1,
+			.addr = sdvo_encoder->slave_addr >> 1,
 			.flags = I2C_M_RD,
 			.len = 1,
 			.buf = buf,
@@ -234,11 +256,11 @@  static bool intel_sdvo_read_byte(struct intel_encoder *intel_encoder, u8 addr,
 static bool intel_sdvo_write_byte(struct intel_encoder *intel_encoder, int addr,
 				  u8 ch)
 {
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
 	u8 out_buf[2];
 	struct i2c_msg msgs[] = {
 		{
-			.addr = sdvo_priv->slave_addr >> 1,
+			.addr = sdvo_encoder->slave_addr >> 1,
 			.flags = 0,
 			.len = 2,
 			.buf = out_buf,
@@ -357,11 +379,11 @@  static const struct _sdvo_cmd_name {
 static void intel_sdvo_debug_write(struct intel_encoder *intel_encoder, u8 cmd,
 				   void *args, int args_len)
 {
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
 	int i;
 
 	DRM_DEBUG_KMS("%s: W: %02X ",
-				SDVO_NAME(sdvo_priv), cmd);
+				SDVO_NAME(sdvo_encoder), cmd);
 	for (i = 0; i < args_len; i++)
 		DRM_LOG_KMS("%02X ", ((u8 *)args)[i]);
 	for (; i < 8; i++)
@@ -406,10 +428,10 @@  static void intel_sdvo_debug_response(struct intel_encoder *intel_encoder,
 				      void *response, int response_len,
 				      u8 status)
 {
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
 	int i;
 
-	DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(sdvo_priv));
+	DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(sdvo_encoder));
 	for (i = 0; i < response_len; i++)
 		DRM_LOG_KMS("%02X ", ((u8 *)response)[i]);
 	for (; i < 8; i++)
@@ -471,24 +493,24 @@  static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode)
 static void intel_sdvo_set_control_bus_switch(struct intel_encoder *intel_encoder,
 					      u8 target)
 {
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
 	u8 out_buf[2], cmd_buf[2], ret_value[2], ret;
 	struct i2c_msg msgs[] = {
 		{
-			.addr = sdvo_priv->slave_addr >> 1,
+			.addr = sdvo_encoder->slave_addr >> 1,
 			.flags = 0,
 			.len = 2,
 			.buf = out_buf,
 		},
 		/* the following two are to read the response */
 		{
-			.addr = sdvo_priv->slave_addr >> 1,
+			.addr = sdvo_encoder->slave_addr >> 1,
 			.flags = 0,
 			.len = 1,
 			.buf = cmd_buf,
 		},
 		{
-			.addr = sdvo_priv->slave_addr >> 1,
+			.addr = sdvo_encoder->slave_addr >> 1,
 			.flags = I2C_M_RD,
 			.len = 1,
 			.buf = ret_value,
@@ -717,7 +739,7 @@  intel_sdvo_create_preferred_input_timing(struct intel_encoder *intel_encoder,
 					 uint16_t height)
 {
 	struct intel_sdvo_preferred_input_timing_args args;
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
 	uint8_t status;
 
 	memset(&args, 0, sizeof(args));
@@ -726,9 +748,9 @@  intel_sdvo_create_preferred_input_timing(struct intel_encoder *intel_encoder,
 	args.height = height;
 	args.interlace = 0;
 
-	if (sdvo_priv->is_lvds &&
-	   (sdvo_priv->sdvo_lvds_fixed_mode->hdisplay != width ||
-	    sdvo_priv->sdvo_lvds_fixed_mode->vdisplay != height))
+	if (sdvo_encoder->is_lvds &&
+	   (sdvo_encoder->sdvo_lvds_fixed_mode->hdisplay != width ||
+	    sdvo_encoder->sdvo_lvds_fixed_mode->vdisplay != height))
 		args.scaled = 1;
 
 	intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING,
@@ -1051,12 +1073,12 @@  static void intel_sdvo_set_tv_format(struct intel_encoder *intel_encoder)
 {
 
 	struct intel_sdvo_tv_format format;
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
 	uint32_t format_map, i;
 	uint8_t status;
 
 	for (i = 0; i < TV_FORMAT_NUM; i++)
-		if (tv_format_names[i] == sdvo_priv->tv_format_name)
+		if (tv_format_names[i] == sdvo_encoder->tv_format_name)
 			break;
 
 	format_map = 1 << i;
@@ -1070,7 +1092,7 @@  static void intel_sdvo_set_tv_format(struct intel_encoder *intel_encoder)
 	status = intel_sdvo_read_response(intel_encoder, NULL, 0);
 	if (status != SDVO_CMD_STATUS_SUCCESS)
 		DRM_DEBUG_KMS("%s: Failed to set TV format\n",
-			  SDVO_NAME(sdvo_priv));
+			  SDVO_NAME(sdvo_encoder));
 }
 
 static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
@@ -1078,9 +1100,9 @@  static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
 				  struct drm_display_mode *adjusted_mode)
 {
 	struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
-	struct intel_sdvo_priv *dev_priv = intel_encoder->dev_priv;
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
 
-	if (dev_priv->is_tv) {
+	if (sdvo_encoder->is_tv) {
 		struct intel_sdvo_dtd output_dtd;
 		bool success;
 
@@ -1094,7 +1116,7 @@  static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
 		/* Set output timings */
 		intel_sdvo_get_dtd_from_mode(&output_dtd, mode);
 		intel_sdvo_set_target_output(intel_encoder,
-					     dev_priv->controlled_output);
+					     sdvo_encoder->attached_output);
 		intel_sdvo_set_output_timing(intel_encoder, &output_dtd);
 
 		/* Set the input timing to the screen. Assume always input 0. */
@@ -1111,7 +1133,7 @@  static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
 			intel_sdvo_get_preferred_input_timing(intel_encoder,
 							     &input_dtd);
 			intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
-			dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags;
+			sdvo_encoder->sdvo_flags = input_dtd.part2.sdvo_flags;
 
 			drm_mode_set_crtcinfo(adjusted_mode, 0);
 
@@ -1122,23 +1144,22 @@  static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
 		} else {
 			return false;
 		}
-	} else if (dev_priv->is_lvds) {
+	} else if (sdvo_encoder->is_lvds) {
 		struct intel_sdvo_dtd output_dtd;
 		bool success;
 
-		drm_mode_set_crtcinfo(dev_priv->sdvo_lvds_fixed_mode, 0);
+		drm_mode_set_crtcinfo(sdvo_encoder->sdvo_lvds_fixed_mode, 0);
 		/* Set output timings */
 		intel_sdvo_get_dtd_from_mode(&output_dtd,
-				dev_priv->sdvo_lvds_fixed_mode);
+					     sdvo_encoder->sdvo_lvds_fixed_mode);
 
 		intel_sdvo_set_target_output(intel_encoder,
-					     dev_priv->controlled_output);
+					     sdvo_encoder->attached_output);
 		intel_sdvo_set_output_timing(intel_encoder, &output_dtd);
 
 		/* Set the input timing to the screen. Assume always input 0. */
 		intel_sdvo_set_target_input(intel_encoder, true, false);
 
-
 		success = intel_sdvo_create_preferred_input_timing(
 				intel_encoder,
 				mode->clock / 10,
@@ -1151,7 +1172,7 @@  static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
 			intel_sdvo_get_preferred_input_timing(intel_encoder,
 							     &input_dtd);
 			intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
-			dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags;
+			sdvo_encoder->sdvo_flags = input_dtd.part2.sdvo_flags;
 
 			drm_mode_set_crtcinfo(adjusted_mode, 0);
 
@@ -1181,7 +1202,7 @@  static void intel_sdvo_mode_set(struct drm_encoder *encoder,
 	struct drm_crtc *crtc = encoder->crtc;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
 	u32 sdvox = 0;
 	int sdvo_pixel_multiply;
 	struct intel_sdvo_in_out_map in_out;
@@ -1197,40 +1218,40 @@  static void intel_sdvo_mode_set(struct drm_encoder *encoder,
 	 * 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.in0 = sdvo_encoder->attached_output;
 	in_out.in1 = 0;
 
 	intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_IN_OUT_MAP,
 			     &in_out, sizeof(in_out));
 	status = intel_sdvo_read_response(intel_encoder, NULL, 0);
 
-	if (sdvo_priv->is_hdmi) {
+	if (sdvo_encoder->is_hdmi) {
 		intel_sdvo_set_avi_infoframe(intel_encoder, mode);
 		sdvox |= SDVO_AUDIO_ENABLE;
 	}
 
 	/* We have tried to get input timing in mode_fixup, and filled into
 	   adjusted_mode */
-	if (sdvo_priv->is_tv || sdvo_priv->is_lvds) {
+	if (sdvo_encoder->is_tv || sdvo_encoder->is_lvds) {
 		intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
-		input_dtd.part2.sdvo_flags = sdvo_priv->sdvo_flags;
+		input_dtd.part2.sdvo_flags = sdvo_encoder->sdvo_flags;
 	} else
 		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 && !sdvo_priv->is_lvds) {
+	if (!sdvo_encoder->is_tv && !sdvo_encoder->is_lvds) {
 		/* Set the output timing to the screen */
 		intel_sdvo_set_target_output(intel_encoder,
-					     sdvo_priv->controlled_output);
+					     sdvo_encoder->attached_output);
 		intel_sdvo_set_output_timing(intel_encoder, &input_dtd);
 	}
 
 	/* Set the input timing to the screen. Assume always input 0. */
 	intel_sdvo_set_target_input(intel_encoder, true, false);
 
-	if (sdvo_priv->is_tv)
+	if (sdvo_encoder->is_tv)
 		intel_sdvo_set_tv_format(intel_encoder);
 
 	/* We would like to use intel_sdvo_create_preferred_input_timing() to
@@ -1272,8 +1293,8 @@  static void intel_sdvo_mode_set(struct drm_encoder *encoder,
 			SDVO_VSYNC_ACTIVE_HIGH |
 			SDVO_HSYNC_ACTIVE_HIGH;
 	} else {
-		sdvox |= I915_READ(sdvo_priv->output_device);
-		switch (sdvo_priv->output_device) {
+		sdvox |= I915_READ(sdvo_encoder->output_device);
+		switch (sdvo_encoder->output_device) {
 		case SDVOB:
 			sdvox &= SDVOB_PRESERVE_MASK;
 			break;
@@ -1295,7 +1316,7 @@  static void intel_sdvo_mode_set(struct drm_encoder *encoder,
 		sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT;
 	}
 
-	if (sdvo_priv->sdvo_flags & SDVO_NEED_TO_STALL)
+	if (sdvo_encoder->sdvo_flags & SDVO_NEED_TO_STALL)
 		sdvox |= SDVO_STALL_SELECT;
 	intel_sdvo_write_sdvox(intel_encoder, sdvox);
 }
@@ -1305,7 +1326,7 @@  static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
 	u32 temp;
 
 	if (mode != DRM_MODE_DPMS_ON) {
@@ -1314,7 +1335,7 @@  static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
 			intel_sdvo_set_encoder_power_state(intel_encoder, mode);
 
 		if (mode == DRM_MODE_DPMS_OFF) {
-			temp = I915_READ(sdvo_priv->output_device);
+			temp = I915_READ(sdvo_encoder->output_device);
 			if ((temp & SDVO_ENABLE) != 0) {
 				intel_sdvo_write_sdvox(intel_encoder, temp & ~SDVO_ENABLE);
 			}
@@ -1324,7 +1345,7 @@  static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
 		int i;
 		u8 status;
 
-		temp = I915_READ(sdvo_priv->output_device);
+		temp = I915_READ(sdvo_encoder->output_device);
 		if ((temp & SDVO_ENABLE) == 0)
 			intel_sdvo_write_sdvox(intel_encoder, temp | SDVO_ENABLE);
 		for (i = 0; i < 2; i++)
@@ -1340,12 +1361,12 @@  static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
 		 */
 		if (status == SDVO_CMD_STATUS_SUCCESS && !input1) {
 			DRM_DEBUG_KMS("First %s output reported failure to "
-					"sync\n", SDVO_NAME(sdvo_priv));
+					"sync\n", SDVO_NAME(sdvo_encoder));
 		}
 
 		if (0)
 			intel_sdvo_set_encoder_power_state(intel_encoder, mode);
-		intel_sdvo_set_active_outputs(intel_encoder, sdvo_priv->controlled_output);
+		intel_sdvo_set_active_outputs(intel_encoder, sdvo_encoder->attached_output);
 	}
 	return;
 }
@@ -1356,39 +1377,39 @@  static void intel_sdvo_save(struct drm_connector *connector)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_encoder *encoder = intel_best_encoder(connector);
 	struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
 	int o;
 
-	sdvo_priv->save_sdvo_mult = intel_sdvo_get_clock_rate_mult(intel_encoder);
-	intel_sdvo_get_active_outputs(intel_encoder, &sdvo_priv->save_active_outputs);
+	sdvo_encoder->save_sdvo_mult = intel_sdvo_get_clock_rate_mult(intel_encoder);
+	intel_sdvo_get_active_outputs(intel_encoder, &sdvo_encoder->save_active_outputs);
 
-	if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) {
+	if (sdvo_encoder->caps.sdvo_inputs_mask & 0x1) {
 		intel_sdvo_set_target_input(intel_encoder, true, false);
 		intel_sdvo_get_input_timing(intel_encoder,
-					    &sdvo_priv->save_input_dtd_1);
+					    &sdvo_encoder->save_input_dtd_1);
 	}
 
-	if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) {
+	if (sdvo_encoder->caps.sdvo_inputs_mask & 0x2) {
 		intel_sdvo_set_target_input(intel_encoder, false, true);
 		intel_sdvo_get_input_timing(intel_encoder,
-					    &sdvo_priv->save_input_dtd_2);
+					    &sdvo_encoder->save_input_dtd_2);
 	}
 
 	for (o = SDVO_OUTPUT_FIRST; o <= SDVO_OUTPUT_LAST; o++)
 	{
 	        u16  this_output = (1 << o);
-		if (sdvo_priv->caps.output_flags & this_output)
+		if (sdvo_encoder->caps.output_flags & this_output)
 		{
 			intel_sdvo_set_target_output(intel_encoder, this_output);
 			intel_sdvo_get_output_timing(intel_encoder,
-						     &sdvo_priv->save_output_dtd[o]);
+						     &sdvo_encoder->save_output_dtd[o]);
 		}
 	}
-	if (sdvo_priv->is_tv) {
+	if (sdvo_encoder->is_tv) {
 		/* XXX: Save TV format/enhancements. */
 	}
 
-	sdvo_priv->save_SDVOX = I915_READ(sdvo_priv->output_device);
+	sdvo_encoder->save_SDVOX = I915_READ(sdvo_encoder->output_device);
 }
 
 static void intel_sdvo_restore(struct drm_connector *connector)
@@ -1396,7 +1417,7 @@  static void intel_sdvo_restore(struct drm_connector *connector)
 	struct drm_device *dev = connector->dev;
 	struct drm_encoder *encoder = intel_best_encoder(connector);
 	struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
 	int o;
 	int i;
 	bool input1, input2;
@@ -1407,41 +1428,41 @@  static void intel_sdvo_restore(struct drm_connector *connector)
 	for (o = SDVO_OUTPUT_FIRST; o <= SDVO_OUTPUT_LAST; o++)
 	{
 		u16  this_output = (1 << o);
-		if (sdvo_priv->caps.output_flags & this_output) {
+		if (sdvo_encoder->caps.output_flags & this_output) {
 			intel_sdvo_set_target_output(intel_encoder, this_output);
-			intel_sdvo_set_output_timing(intel_encoder, &sdvo_priv->save_output_dtd[o]);
+			intel_sdvo_set_output_timing(intel_encoder, &sdvo_encoder->save_output_dtd[o]);
 		}
 	}
 
-	if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) {
+	if (sdvo_encoder->caps.sdvo_inputs_mask & 0x1) {
 		intel_sdvo_set_target_input(intel_encoder, true, false);
-		intel_sdvo_set_input_timing(intel_encoder, &sdvo_priv->save_input_dtd_1);
+		intel_sdvo_set_input_timing(intel_encoder, &sdvo_encoder->save_input_dtd_1);
 	}
 
-	if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) {
+	if (sdvo_encoder->caps.sdvo_inputs_mask & 0x2) {
 		intel_sdvo_set_target_input(intel_encoder, false, true);
-		intel_sdvo_set_input_timing(intel_encoder, &sdvo_priv->save_input_dtd_2);
+		intel_sdvo_set_input_timing(intel_encoder, &sdvo_encoder->save_input_dtd_2);
 	}
 
-	intel_sdvo_set_clock_rate_mult(intel_encoder, sdvo_priv->save_sdvo_mult);
+	intel_sdvo_set_clock_rate_mult(intel_encoder, sdvo_encoder->save_sdvo_mult);
 
-	if (sdvo_priv->is_tv) {
+	if (sdvo_encoder->is_tv) {
 		/* XXX: Restore TV format/enhancements. */
 	}
 
-	intel_sdvo_write_sdvox(intel_encoder, sdvo_priv->save_SDVOX);
+	intel_sdvo_write_sdvox(intel_encoder, sdvo_encoder->save_SDVOX);
 
-	if (sdvo_priv->save_SDVOX & SDVO_ENABLE)
+	if (sdvo_encoder->save_SDVOX & SDVO_ENABLE)
 	{
 		for (i = 0; i < 2; i++)
 			intel_wait_for_vblank(dev);
 		status = intel_sdvo_get_trained_inputs(intel_encoder, &input1, &input2);
 		if (status == SDVO_CMD_STATUS_SUCCESS && !input1)
 			DRM_DEBUG_KMS("First %s output reported failure to "
-					"sync\n", SDVO_NAME(sdvo_priv));
+					"sync\n", SDVO_NAME(sdvo_encoder));
 	}
 
-	intel_sdvo_set_active_outputs(intel_encoder, sdvo_priv->save_active_outputs);
+	intel_sdvo_set_active_outputs(intel_encoder, sdvo_encoder->save_active_outputs);
 }
 
 static int intel_sdvo_mode_valid(struct drm_connector *connector,
@@ -1449,25 +1470,25 @@  static int intel_sdvo_mode_valid(struct drm_connector *connector,
 {
 	struct drm_encoder *encoder = intel_best_encoder(connector);
 	struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
 
 	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
 		return MODE_NO_DBLESCAN;
 
-	if (sdvo_priv->pixel_clock_min > mode->clock)
+	if (sdvo_encoder->pixel_clock_min > mode->clock)
 		return MODE_CLOCK_LOW;
 
-	if (sdvo_priv->pixel_clock_max < mode->clock)
+	if (sdvo_encoder->pixel_clock_max < mode->clock)
 		return MODE_CLOCK_HIGH;
 
-	if (sdvo_priv->is_lvds == true) {
-		if (sdvo_priv->sdvo_lvds_fixed_mode == NULL)
+	if (sdvo_encoder->is_lvds == true) {
+		if (sdvo_encoder->sdvo_lvds_fixed_mode == NULL)
 			return MODE_PANEL;
 
-		if (mode->hdisplay > sdvo_priv->sdvo_lvds_fixed_mode->hdisplay)
+		if (mode->hdisplay > sdvo_encoder->sdvo_lvds_fixed_mode->hdisplay)
 			return MODE_PANEL;
 
-		if (mode->vdisplay > sdvo_priv->sdvo_lvds_fixed_mode->vdisplay)
+		if (mode->vdisplay > sdvo_encoder->sdvo_lvds_fixed_mode->vdisplay)
 			return MODE_PANEL;
 	}
 
@@ -1563,30 +1584,30 @@  void intel_sdvo_set_hotplug(struct drm_connector *connector, int on)
 static bool
 intel_sdvo_multifunc_encoder(struct intel_encoder *intel_encoder)
 {
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
 	int caps = 0;
 
-	if (sdvo_priv->caps.output_flags &
+	if (sdvo_encoder->caps.output_flags &
 		(SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1))
 		caps++;
-	if (sdvo_priv->caps.output_flags &
+	if (sdvo_encoder->caps.output_flags &
 		(SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1))
 		caps++;
-	if (sdvo_priv->caps.output_flags &
+	if (sdvo_encoder->caps.output_flags &
 		(SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_SVID1))
 		caps++;
-	if (sdvo_priv->caps.output_flags &
+	if (sdvo_encoder->caps.output_flags &
 		(SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_CVBS1))
 		caps++;
-	if (sdvo_priv->caps.output_flags &
+	if (sdvo_encoder->caps.output_flags &
 		(SDVO_OUTPUT_YPRPB0 | SDVO_OUTPUT_YPRPB1))
 		caps++;
 
-	if (sdvo_priv->caps.output_flags &
+	if (sdvo_encoder->caps.output_flags &
 		(SDVO_OUTPUT_SCART0 | SDVO_OUTPUT_SCART1))
 		caps++;
 
-	if (sdvo_priv->caps.output_flags &
+	if (sdvo_encoder->caps.output_flags &
 		(SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1))
 		caps++;
 
@@ -1629,7 +1650,8 @@  intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response)
 	struct drm_encoder *encoder = intel_best_encoder(connector);
 	struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
 	struct intel_connector *intel_connector = to_intel_connector(connector);
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
+	struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv;
 	enum drm_connector_status status = connector_status_connected;
 	struct edid *edid = NULL;
 
@@ -1638,43 +1660,44 @@  intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response)
 	/* This is only applied to SDVO cards with multiple outputs */
 	if (edid == NULL && intel_sdvo_multifunc_encoder(intel_encoder)) {
 		uint8_t saved_ddc, temp_ddc;
-		saved_ddc = sdvo_priv->ddc_bus;
-		temp_ddc = sdvo_priv->ddc_bus >> 1;
+		saved_ddc = sdvo_encoder->ddc_bus;
+		temp_ddc = sdvo_encoder->ddc_bus >> 1;
 		/*
 		 * Don't use the 1 as the argument of DDC bus switch to get
 		 * the EDID. It is used for SDVO SPD ROM.
 		 */
 		while(temp_ddc > 1) {
-			sdvo_priv->ddc_bus = temp_ddc;
+			sdvo_encoder->ddc_bus = temp_ddc;
 			edid = drm_get_edid(connector, intel_connector->ddc_bus);
 			if (edid) {
 				/*
 				 * When we can get the EDID, maybe it is the
 				 * correct DDC bus. Update it.
 				 */
-				sdvo_priv->ddc_bus = temp_ddc;
+				sdvo_encoder->ddc_bus = temp_ddc;
 				break;
 			}
 			temp_ddc >>= 1;
 		}
 		if (edid == NULL)
-			sdvo_priv->ddc_bus = saved_ddc;
+			sdvo_encoder->ddc_bus = saved_ddc;
 	}
 	/* when there is no edid and no monitor is connected with VGA
 	 * port, try to use the CRT ddc to read the EDID for DVI-connector
 	 */
 	if (edid == NULL &&
-	    sdvo_priv->analog_ddc_bus &&
+	    sdvo_connector->analog_ddc_bus &&
 	    !intel_analog_is_connected(connector->dev))
 		edid = drm_get_edid(connector,
-				    sdvo_priv->analog_ddc_bus);
+				    sdvo_connector->analog_ddc_bus);
+
 	if (edid != NULL) {
 		/* Don't report the output as connected if it's a DVI-I
 		 * connector with a non-digital EDID coming out.
 		 */
 		if (response & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) {
 			if (edid->input & DRM_EDID_INPUT_DIGITAL)
-				sdvo_priv->is_hdmi =
+				sdvo_encoder->is_hdmi =
 					drm_detect_hdmi_monitor(edid);
 			else
 				status = connector_status_disconnected;
@@ -1696,11 +1719,13 @@  static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect
 	struct drm_encoder *encoder = intel_best_encoder(connector);
 	struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
 	struct intel_connector *intel_connector = to_intel_connector(connector);
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
+	struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv;
+	enum drm_connector_status ret;
 
 	intel_sdvo_write_cmd(intel_encoder,
 			     SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0);
-	if (sdvo_priv->is_tv) {
+	if (sdvo_encoder->is_tv) {
 		/* add 30ms delay when the output type is SDVO-TV */
 		mdelay(30);
 	}
@@ -1714,23 +1739,36 @@  static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect
 	if (response == 0)
 		return connector_status_disconnected;
 
-	if (intel_sdvo_multifunc_encoder(intel_encoder) &&
-		sdvo_priv->attached_output != response) {
-		if (sdvo_priv->controlled_output != response &&
-			intel_sdvo_output_setup(intel_encoder, intel_connector,
-						response) != true)
-			return connector_status_unknown;
-		sdvo_priv->attached_output = response;
+	sdvo_encoder->attached_output = response;
+
+	if ((sdvo_connector->output_flag & response) == 0)
+		ret = connector_status_disconnected;
+	else if (response & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1))
+		ret = intel_sdvo_hdmi_sink_detect(connector, response);
+	else
+		ret = connector_status_connected;
+
+	/* May update encoder flag for like clock for SDVO TV, etc.*/
+	if (ret == connector_status_connected) {
+		sdvo_encoder->is_tv = false;
+		sdvo_encoder->is_lvds = false;
+		intel_encoder->needs_tv_clock = false;
+
+		if (response & SDVO_TV_MASK) {
+			sdvo_encoder->is_tv = true;
+			intel_encoder->needs_tv_clock = true;
+		}
+		if (response & SDVO_LVDS_MASK)
+			sdvo_encoder->is_lvds = true;
 	}
-	return intel_sdvo_hdmi_sink_detect(connector, response);
+
+	return ret;
 }
 
 static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
 {
-	struct drm_encoder *encoder = intel_best_encoder(connector);
-	struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
 	struct intel_connector *intel_connector = to_intel_connector(connector);
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv;
 	int num_modes;
 
 	/* set the bus switch and get the modes */
@@ -1743,14 +1781,14 @@  static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
 	 * which case we'll look there for the digital DDC data.
 	 */
 	if (num_modes == 0 &&
-	    sdvo_priv->analog_ddc_bus &&
+	    sdvo_connector->analog_ddc_bus &&
 	    !intel_analog_is_connected(intel_connector->base.dev)) {
 		struct i2c_adapter *digital_ddc_bus;
 
 		/* Switch to the analog ddc bus and try that
 		 */
 		digital_ddc_bus = intel_connector->ddc_bus;
-		intel_connector->ddc_bus = sdvo_priv->analog_ddc_bus;
+		intel_connector->ddc_bus = sdvo_connector->analog_ddc_bus;
 
 		(void) intel_ddc_get_modes(intel_connector);
 
@@ -1827,7 +1865,7 @@  static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
 {
 	struct drm_encoder *encoder = intel_best_encoder(connector);
 	struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
 	struct intel_sdvo_sdtv_resolution_request tv_res;
 	uint32_t reply = 0, format_map = 0;
 	int i;
@@ -1838,7 +1876,7 @@  static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
 	 * format.
 	 */
 	for (i = 0; i < TV_FORMAT_NUM; i++)
-		if (tv_format_names[i] ==  sdvo_priv->tv_format_name)
+		if (tv_format_names[i] ==  sdvo_encoder->tv_format_name)
 			break;
 
 	format_map = (1 << i);
@@ -1847,7 +1885,7 @@  static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
 	       sizeof(format_map) ? sizeof(format_map) :
 	       sizeof(struct intel_sdvo_sdtv_resolution_request));
 
-	intel_sdvo_set_target_output(intel_encoder, sdvo_priv->controlled_output);
+	intel_sdvo_set_target_output(intel_encoder, sdvo_encoder->attached_output);
 
 	intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
 			     &tv_res, sizeof(tv_res));
@@ -1871,7 +1909,7 @@  static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
 	struct drm_encoder *encoder = intel_best_encoder(connector);
 	struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
 	struct intel_connector *intel_connector = to_intel_connector(connector);
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
 	struct drm_i915_private *dev_priv = connector->dev->dev_private;
 	struct drm_display_mode *newmode;
 
@@ -1899,7 +1937,7 @@  static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
 end:
 	list_for_each_entry(newmode, &connector->probed_modes, head) {
 		if (newmode->type & DRM_MODE_TYPE_PREFERRED) {
-			sdvo_priv->sdvo_lvds_fixed_mode =
+			sdvo_encoder->sdvo_lvds_fixed_mode =
 				drm_mode_duplicate(connector->dev, newmode);
 			break;
 		}
@@ -1909,13 +1947,12 @@  end:
 
 static int intel_sdvo_get_modes(struct drm_connector *connector)
 {
-	struct drm_encoder *encoder = intel_best_encoder(connector);
-	struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_connector *intel_connector = to_intel_connector(connector);
+	struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv;
 
-	if (sdvo_priv->is_tv)
+	if (SDVO_CONNECTOR_IS_TV(sdvo_connector))
 		intel_sdvo_get_tv_modes(connector);
-	else if (sdvo_priv->is_lvds == true)
+	else if (SDVO_CONNECTOR_IS_LVDS(sdvo_connector))
 		intel_sdvo_get_lvds_modes(connector);
 	else
 		intel_sdvo_get_ddc_modes(connector);
@@ -1928,65 +1965,56 @@  static int intel_sdvo_get_modes(struct drm_connector *connector)
 static
 void intel_sdvo_destroy_enhance_property(struct drm_connector *connector)
 {
-	struct drm_encoder *encoder = intel_best_encoder(connector);
-	struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_connector *intel_connector = to_intel_connector(connector);
+	struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv;
 	struct drm_device *dev = connector->dev;
 
-	if (sdvo_priv->is_tv) {
-		if (sdvo_priv->left_property)
-			drm_property_destroy(dev, sdvo_priv->left_property);
-		if (sdvo_priv->right_property)
-			drm_property_destroy(dev, sdvo_priv->right_property);
-		if (sdvo_priv->top_property)
-			drm_property_destroy(dev, sdvo_priv->top_property);
-		if (sdvo_priv->bottom_property)
-			drm_property_destroy(dev, sdvo_priv->bottom_property);
-		if (sdvo_priv->hpos_property)
-			drm_property_destroy(dev, sdvo_priv->hpos_property);
-		if (sdvo_priv->vpos_property)
-			drm_property_destroy(dev, sdvo_priv->vpos_property);
-	}
-	if (sdvo_priv->is_tv) {
-		if (sdvo_priv->saturation_property)
+	if (SDVO_CONNECTOR_IS_TV(sdvo_connector)) {
+		if (sdvo_connector->left_property)
+			drm_property_destroy(dev, sdvo_connector->left_property);
+		if (sdvo_connector->right_property)
+			drm_property_destroy(dev, sdvo_connector->right_property);
+		if (sdvo_connector->top_property)
+			drm_property_destroy(dev, sdvo_connector->top_property);
+		if (sdvo_connector->bottom_property)
+			drm_property_destroy(dev, sdvo_connector->bottom_property);
+		if (sdvo_connector->hpos_property)
+			drm_property_destroy(dev, sdvo_connector->hpos_property);
+		if (sdvo_connector->vpos_property)
+			drm_property_destroy(dev, sdvo_connector->vpos_property);
+		if (sdvo_connector->saturation_property)
 			drm_property_destroy(dev,
-					sdvo_priv->saturation_property);
-		if (sdvo_priv->contrast_property)
+					     sdvo_connector->saturation_property);
+		if (sdvo_connector->contrast_property)
 			drm_property_destroy(dev,
-					sdvo_priv->contrast_property);
-		if (sdvo_priv->hue_property)
-			drm_property_destroy(dev, sdvo_priv->hue_property);
+					     sdvo_connector->contrast_property);
+		if (sdvo_connector->hue_property)
+			drm_property_destroy(dev, sdvo_connector->hue_property);
 	}
-	if (sdvo_priv->is_tv || sdvo_priv->is_lvds) {
-		if (sdvo_priv->brightness_property)
+	if (SDVO_CONNECTOR_IS_TV(sdvo_connector) ||
+		SDVO_CONNECTOR_IS_LVDS(sdvo_connector)) {
+		if (sdvo_connector->brightness_property)
 			drm_property_destroy(dev,
-					sdvo_priv->brightness_property);
+					     sdvo_connector->brightness_property);
 	}
 	return;
 }
 
 static void intel_sdvo_destroy(struct drm_connector *connector)
 {
-	struct drm_encoder *encoder = intel_best_encoder(connector);
-	struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
 	struct intel_connector *intel_connector = to_intel_connector(connector);
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv;
 
 	if (intel_connector->ddc_bus)
 		intel_i2c_destroy(intel_connector->ddc_bus);
-	if (sdvo_priv->analog_ddc_bus)
-		intel_i2c_destroy(sdvo_priv->analog_ddc_bus);
-
-	if (sdvo_priv->sdvo_lvds_fixed_mode != NULL)
-		drm_mode_destroy(connector->dev,
-				 sdvo_priv->sdvo_lvds_fixed_mode);
+	if (sdvo_connector->analog_ddc_bus)
+		intel_i2c_destroy(sdvo_connector->analog_ddc_bus);
 
-	if (sdvo_priv->tv_format_property)
+	if (sdvo_connector->tv_format_property)
 		drm_property_destroy(connector->dev,
-				     sdvo_priv->tv_format_property);
+				     sdvo_connector->tv_format_property);
 
-	if (sdvo_priv->is_tv || sdvo_priv->is_lvds)
-		intel_sdvo_destroy_enhance_property(connector);
+	intel_sdvo_destroy_enhance_property(connector);
 
 	drm_sysfs_connector_remove(connector);
 	drm_connector_cleanup(connector);
@@ -2001,7 +2029,9 @@  intel_sdvo_set_property(struct drm_connector *connector,
 {
 	struct drm_encoder *encoder = intel_best_encoder(connector);
 	struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
+	struct intel_connector *intel_connector = to_intel_connector(connector);
+	struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv;
 	struct drm_crtc *crtc = encoder->crtc;
 	int ret = 0;
 	bool changed = false;
@@ -2012,101 +2042,102 @@  intel_sdvo_set_property(struct drm_connector *connector,
 	if (ret < 0)
 		goto out;
 
-	if (property == sdvo_priv->tv_format_property) {
+	if (property == sdvo_connector->tv_format_property) {
 		if (val >= TV_FORMAT_NUM) {
 			ret = -EINVAL;
 			goto out;
 		}
-		if (sdvo_priv->tv_format_name ==
-		    sdvo_priv->tv_format_supported[val])
+		if (sdvo_encoder->tv_format_name ==
+		    sdvo_connector->tv_format_supported[val])
 			goto out;
 
-		sdvo_priv->tv_format_name = sdvo_priv->tv_format_supported[val];
+		sdvo_encoder->tv_format_name = sdvo_connector->tv_format_supported[val];
 		changed = true;
 	}
 
-	if (sdvo_priv->is_tv || sdvo_priv->is_lvds) {
+	if (SDVO_CONNECTOR_IS_TV(sdvo_connector) ||
+		SDVO_CONNECTOR_IS_LVDS(sdvo_connector)) {
 		cmd = 0;
 		temp_value = val;
-		if (sdvo_priv->left_property == property) {
+		if (sdvo_connector->left_property == property) {
 			drm_connector_property_set_value(connector,
-				sdvo_priv->right_property, val);
-			if (sdvo_priv->left_margin == temp_value)
+				sdvo_connector->right_property, val);
+			if (sdvo_connector->left_margin == temp_value)
 				goto out;
 
-			sdvo_priv->left_margin = temp_value;
-			sdvo_priv->right_margin = temp_value;
-			temp_value = sdvo_priv->max_hscan -
-					sdvo_priv->left_margin;
+			sdvo_connector->left_margin = temp_value;
+			sdvo_connector->right_margin = temp_value;
+			temp_value = sdvo_connector->max_hscan -
+					sdvo_connector->left_margin;
 			cmd = SDVO_CMD_SET_OVERSCAN_H;
-		} else if (sdvo_priv->right_property == property) {
+		} else if (sdvo_connector->right_property == property) {
 			drm_connector_property_set_value(connector,
-				sdvo_priv->left_property, val);
-			if (sdvo_priv->right_margin == temp_value)
+				sdvo_connector->left_property, val);
+			if (sdvo_connector->right_margin == temp_value)
 				goto out;
 
-			sdvo_priv->left_margin = temp_value;
-			sdvo_priv->right_margin = temp_value;
-			temp_value = sdvo_priv->max_hscan -
-				sdvo_priv->left_margin;
+			sdvo_connector->left_margin = temp_value;
+			sdvo_connector->right_margin = temp_value;
+			temp_value = sdvo_connector->max_hscan -
+				sdvo_connector->left_margin;
 			cmd = SDVO_CMD_SET_OVERSCAN_H;
-		} else if (sdvo_priv->top_property == property) {
+		} else if (sdvo_connector->top_property == property) {
 			drm_connector_property_set_value(connector,
-				sdvo_priv->bottom_property, val);
-			if (sdvo_priv->top_margin == temp_value)
+				sdvo_connector->bottom_property, val);
+			if (sdvo_connector->top_margin == temp_value)
 				goto out;
 
-			sdvo_priv->top_margin = temp_value;
-			sdvo_priv->bottom_margin = temp_value;
-			temp_value = sdvo_priv->max_vscan -
-					sdvo_priv->top_margin;
+			sdvo_connector->top_margin = temp_value;
+			sdvo_connector->bottom_margin = temp_value;
+			temp_value = sdvo_connector->max_vscan -
+					sdvo_connector->top_margin;
 			cmd = SDVO_CMD_SET_OVERSCAN_V;
-		} else if (sdvo_priv->bottom_property == property) {
+		} else if (sdvo_connector->bottom_property == property) {
 			drm_connector_property_set_value(connector,
-				sdvo_priv->top_property, val);
-			if (sdvo_priv->bottom_margin == temp_value)
+				sdvo_connector->top_property, val);
+			if (sdvo_connector->bottom_margin == temp_value)
 				goto out;
-			sdvo_priv->top_margin = temp_value;
-			sdvo_priv->bottom_margin = temp_value;
-			temp_value = sdvo_priv->max_vscan -
-					sdvo_priv->top_margin;
+			sdvo_connector->top_margin = temp_value;
+			sdvo_connector->bottom_margin = temp_value;
+			temp_value = sdvo_connector->max_vscan -
+					sdvo_connector->top_margin;
 			cmd = SDVO_CMD_SET_OVERSCAN_V;
-		} else if (sdvo_priv->hpos_property == property) {
-			if (sdvo_priv->cur_hpos == temp_value)
+		} else if (sdvo_connector->hpos_property == property) {
+			if (sdvo_connector->cur_hpos == temp_value)
 				goto out;
 
 			cmd = SDVO_CMD_SET_POSITION_H;
-			sdvo_priv->cur_hpos = temp_value;
-		} else if (sdvo_priv->vpos_property == property) {
-			if (sdvo_priv->cur_vpos == temp_value)
+			sdvo_connector->cur_hpos = temp_value;
+		} else if (sdvo_connector->vpos_property == property) {
+			if (sdvo_connector->cur_vpos == temp_value)
 				goto out;
 
 			cmd = SDVO_CMD_SET_POSITION_V;
-			sdvo_priv->cur_vpos = temp_value;
-		} else if (sdvo_priv->saturation_property == property) {
-			if (sdvo_priv->cur_saturation == temp_value)
+			sdvo_connector->cur_vpos = temp_value;
+		} else if (sdvo_connector->saturation_property == property) {
+			if (sdvo_connector->cur_saturation == temp_value)
 				goto out;
 
 			cmd = SDVO_CMD_SET_SATURATION;
-			sdvo_priv->cur_saturation = temp_value;
-		} else if (sdvo_priv->contrast_property == property) {
-			if (sdvo_priv->cur_contrast == temp_value)
+			sdvo_connector->cur_saturation = temp_value;
+		} else if (sdvo_connector->contrast_property == property) {
+			if (sdvo_connector->cur_contrast == temp_value)
 				goto out;
 
 			cmd = SDVO_CMD_SET_CONTRAST;
-			sdvo_priv->cur_contrast = temp_value;
-		} else if (sdvo_priv->hue_property == property) {
-			if (sdvo_priv->cur_hue == temp_value)
+			sdvo_connector->cur_contrast = temp_value;
+		} else if (sdvo_connector->hue_property == property) {
+			if (sdvo_connector->cur_hue == temp_value)
 				goto out;
 
 			cmd = SDVO_CMD_SET_HUE;
-			sdvo_priv->cur_hue = temp_value;
-		} else if (sdvo_priv->brightness_property == property) {
-			if (sdvo_priv->cur_brightness == temp_value)
+			sdvo_connector->cur_hue = temp_value;
+		} else if (sdvo_connector->brightness_property == property) {
+			if (sdvo_connector->cur_brightness == temp_value)
 				goto out;
 
 			cmd = SDVO_CMD_SET_BRIGHTNESS;
-			sdvo_priv->cur_brightness = temp_value;
+			sdvo_connector->cur_brightness = temp_value;
 		}
 		if (cmd) {
 			intel_sdvo_write_cmd(intel_encoder, cmd, &temp_value, 2);
@@ -2153,9 +2184,15 @@  static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs
 static void intel_sdvo_enc_destroy(struct drm_encoder *encoder)
 {
 	struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
 
 	if (intel_encoder->i2c_bus)
 		intel_i2c_destroy(intel_encoder->i2c_bus);
+
+	if (sdvo_encoder->sdvo_lvds_fixed_mode != NULL)
+		drm_mode_destroy(encoder->dev,
+				 sdvo_encoder->sdvo_lvds_fixed_mode);
+
 	drm_encoder_cleanup(encoder);
 	kfree(encoder);
 }
@@ -2173,7 +2210,7 @@  static const struct drm_encoder_funcs intel_sdvo_enc_funcs = {
  * outputs, then LVDS outputs.
  */
 static void
-intel_sdvo_select_ddc_bus(struct intel_sdvo_priv *dev_priv)
+intel_sdvo_select_ddc_bus(struct intel_sdvo_encoder *dev_priv)
 {
 	uint16_t mask = 0;
 	unsigned int num_bits;
@@ -2210,15 +2247,18 @@  intel_sdvo_select_ddc_bus(struct intel_sdvo_priv *dev_priv)
 }
 
 static bool
-intel_sdvo_get_digital_encoding_mode(struct intel_encoder *intel_encoder)
+intel_sdvo_get_digital_encoding_mode(struct intel_encoder *intel_encoder, int device)
 {
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
 	uint8_t status;
 
-	intel_sdvo_set_target_output(intel_encoder, sdvo_priv->controlled_output);
+	if (device == 0)
+		intel_sdvo_set_target_output(intel_encoder, SDVO_OUTPUT_TMDS0);
+	else
+		intel_sdvo_set_target_output(intel_encoder, SDVO_OUTPUT_TMDS1);
 
 	intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_ENCODE, NULL, 0);
-	status = intel_sdvo_read_response(intel_encoder, &sdvo_priv->is_hdmi, 1);
+	status = intel_sdvo_read_response(intel_encoder, &sdvo_encoder->is_hdmi, 1);
 	if (status != SDVO_CMD_STATUS_SUCCESS)
 		return false;
 	return true;
@@ -2229,16 +2269,13 @@  intel_sdvo_chan_to_intel_connector(struct intel_i2c_chan *chan)
 {
 	struct drm_device *dev = chan->drm_dev;
 	struct drm_connector *connector;
-	struct intel_connector *intel_connector = NULL;
 
-	list_for_each_entry(connector,
-			&dev->mode_config.connector_list, head) {
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		if (to_intel_connector(connector)->ddc_bus == &chan->adapter) {
-			intel_connector = to_intel_connector(connector);
-			break;
+			return to_intel_connector(connector);
 		}
 	}
-	return intel_connector;
+	return NULL;
 }
 
 static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap,
@@ -2248,7 +2285,7 @@  static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap,
 	struct drm_encoder *encoder;
 	struct intel_encoder *intel_encoder;
 	struct intel_connector *intel_connector;
-	struct intel_sdvo_priv *sdvo_priv;
+	struct intel_sdvo_encoder *sdvo_encoder;
 	struct i2c_algo_bit_data *algo_data;
 	const struct i2c_algorithm *algo;
 
@@ -2263,10 +2300,10 @@  static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap,
 	encoder = intel_best_encoder(connector);
 	intel_encoder = to_intel_encoder(encoder);
 
-	sdvo_priv = intel_encoder->dev_priv;
+	sdvo_encoder = intel_encoder->dev_priv;
 	algo = intel_encoder->i2c_bus->algo;
 
-	intel_sdvo_set_control_bus_switch(intel_encoder, sdvo_priv->ddc_bus);
+	intel_sdvo_set_control_bus_switch(intel_encoder, sdvo_encoder->ddc_bus);
 	return algo->master_xfer(i2c_adap, msgs, num);
 }
 
@@ -2312,125 +2349,266 @@  intel_sdvo_get_slave_addr(struct drm_device *dev, int output_device)
 }
 
 static bool
-intel_sdvo_output_setup(struct intel_encoder *intel_encoder,
-			struct intel_connector *intel_connector,
-			uint16_t flags)
+intel_sdvo_connector_alloc (struct drm_device *dev, struct intel_connector **ret)
+{
+	struct intel_connector *intel_connector;
+	struct intel_sdvo_connector *sdvo_connector;
+	struct drm_connector *connector;
+
+	*ret = kzalloc(sizeof(*intel_connector) +
+		       sizeof(*sdvo_connector), GFP_KERNEL);
+	if (!*ret)
+		return false;
+	intel_connector = *ret;
+	connector = &intel_connector->base;
+	sdvo_connector = (struct intel_sdvo_connector *)(intel_connector + 1);
+	intel_connector->dev_priv = sdvo_connector;
+
+	intel_connector->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVO DDC BUS");
+	sdvo_connector->analog_ddc_bus = intel_i2c_create(dev, GPIOA,
+						"SDVO/VGA DDC BUS");
+	if (!intel_connector->ddc_bus || !sdvo_connector->analog_ddc_bus) {
+		kfree(intel_connector);
+		return false;
+	}
+	/* Wrap with our custom algo which switches to DDC mode */
+	intel_connector->ddc_bus->algo = &intel_sdvo_i2c_bit_algo;
+	return true;
+}
+
+static void
+intel_sdvo_connector_create (struct drm_encoder *encoder, struct drm_connector *connector)
+{
+	drm_connector_init(encoder->dev, connector, &intel_sdvo_connector_funcs,
+			   connector->connector_type);
+
+	drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs);
+
+	connector->interlace_allowed = 0;
+	connector->doublescan_allowed = 0;
+	connector->display_info.subpixel_order = SubPixelHorizontalRGB;
+
+	drm_mode_connector_attach_encoder(connector, encoder);
+	drm_sysfs_connector_add(connector);
+}
+
+static bool
+intel_sdvo_dvi_init(struct intel_encoder *intel_encoder, int device)
 {
 	struct drm_encoder *encoder = &intel_encoder->base;
-	struct drm_connector *connector = &intel_connector->base;
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
-	bool ret = true, registered = false;
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
+	struct drm_connector *connector;
+	struct intel_connector *intel_connector;
+	struct intel_sdvo_connector *sdvo_connector;
 
-	sdvo_priv->is_tv = false;
-	intel_encoder->needs_tv_clock = false;
-	sdvo_priv->is_lvds = false;
+	if (!intel_sdvo_connector_alloc(encoder->dev, &intel_connector))
+		return false;
 
-	if (device_is_registered(&connector->kdev)) {
-		drm_sysfs_connector_remove(connector);
-		registered = true;
-	}
+	sdvo_connector = intel_connector->dev_priv;
 
-	if (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;
+	if (device == 0) {
+		sdvo_encoder->controlled_output |= SDVO_OUTPUT_TMDS0;
+		sdvo_connector->output_flag = SDVO_OUTPUT_TMDS0;
+	} else if (device == 1) {
+		sdvo_encoder->controlled_output |= SDVO_OUTPUT_TMDS1;
+		sdvo_connector->output_flag = SDVO_OUTPUT_TMDS1;
+	}
 
-		encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
-		connector->connector_type = DRM_MODE_CONNECTOR_DVID;
+	connector = &intel_connector->base;
+	encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
+	connector->connector_type = DRM_MODE_CONNECTOR_DVID;
 
-		if (intel_sdvo_get_supp_encode(intel_encoder,
-					       &sdvo_priv->encode) &&
-		    intel_sdvo_get_digital_encoding_mode(intel_encoder) &&
-		    sdvo_priv->is_hdmi) {
+	if (intel_sdvo_get_supp_encode(intel_encoder, &sdvo_encoder->encode)
+		&& intel_sdvo_get_digital_encoding_mode(intel_encoder, device)
+		&& sdvo_encoder->is_hdmi) {
 			/* enable hdmi encoding mode if supported */
 			intel_sdvo_set_encode(intel_encoder, SDVO_ENCODE_HDMI);
 			intel_sdvo_set_colorimetry(intel_encoder,
 						   SDVO_COLORIMETRY_RGB256);
 			connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
-			intel_encoder->clone_mask =
-					(1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
-					(1 << INTEL_ANALOG_CLONE_BIT);
-		}
-	} else if (flags & SDVO_OUTPUT_SVID0) {
-
-		sdvo_priv->controlled_output = SDVO_OUTPUT_SVID0;
-		encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
-		connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
-		sdvo_priv->is_tv = true;
-		intel_encoder->needs_tv_clock = true;
-		intel_encoder->clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
-	} else if (flags & SDVO_OUTPUT_RGB0) {
-
-		sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0;
-		encoder->encoder_type = DRM_MODE_ENCODER_DAC;
-		connector->connector_type = DRM_MODE_CONNECTOR_VGA;
-		intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
-					(1 << INTEL_ANALOG_CLONE_BIT);
-	} else if (flags & SDVO_OUTPUT_RGB1) {
-
-		sdvo_priv->controlled_output = SDVO_OUTPUT_RGB1;
-		encoder->encoder_type = DRM_MODE_ENCODER_DAC;
-		connector->connector_type = DRM_MODE_CONNECTOR_VGA;
-		intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
-					(1 << INTEL_ANALOG_CLONE_BIT);
-	} else if (flags & SDVO_OUTPUT_CVBS0) {
-
-		sdvo_priv->controlled_output = SDVO_OUTPUT_CVBS0;
-		encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
-		connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
-		sdvo_priv->is_tv = true;
-		intel_encoder->needs_tv_clock = true;
-		intel_encoder->clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
-	} else if (flags & SDVO_OUTPUT_LVDS0) {
-
-		sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0;
-		encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
-		connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
-		sdvo_priv->is_lvds = true;
-		intel_encoder->clone_mask = (1 << INTEL_ANALOG_CLONE_BIT) |
-					(1 << INTEL_SDVO_LVDS_CLONE_BIT);
-	} else if (flags & SDVO_OUTPUT_LVDS1) {
-
-		sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS1;
-		encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
-		connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
-		sdvo_priv->is_lvds = true;
-		intel_encoder->clone_mask = (1 << INTEL_ANALOG_CLONE_BIT) |
-					(1 << INTEL_SDVO_LVDS_CLONE_BIT);
-	} else {
+	}
+	intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
+				    (1 << INTEL_ANALOG_CLONE_BIT);
+
+	intel_sdvo_connector_create(encoder, connector);
+
+	return true;
+}
+
+static bool
+intel_sdvo_tv_init(struct intel_encoder *intel_encoder, int type)
+{
+	struct drm_encoder *encoder = &intel_encoder->base;
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
+	struct drm_connector *connector;
+	struct intel_connector *intel_connector;
+	struct intel_sdvo_connector *sdvo_connector;
+
+	if (!intel_sdvo_connector_alloc(encoder->dev, &intel_connector))
+		return false;
+
+	connector = &intel_connector->base;
+	encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
+	connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
+	sdvo_connector = intel_connector->dev_priv;
+
+	sdvo_encoder->controlled_output |= type;
+	sdvo_connector->output_flag = type;
+
+	sdvo_encoder->is_tv = true;
+	intel_encoder->needs_tv_clock = true;
+	intel_encoder->clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
+
+	intel_sdvo_connector_create(encoder, connector);
+
+	intel_sdvo_tv_create_property(encoder, connector);
+
+	intel_sdvo_create_enhance_property(encoder, connector);
+
+	return true;
+}
+
+static bool
+intel_sdvo_analog_init(struct intel_encoder *intel_encoder, int device)
+{
+	struct drm_encoder *encoder = &intel_encoder->base;
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
+	struct drm_connector *connector;
+	struct intel_connector *intel_connector;
+	struct intel_sdvo_connector *sdvo_connector;
+
+	if (!intel_sdvo_connector_alloc(encoder->dev, &intel_connector))
+		return false;
+
+	connector = &intel_connector->base;
+	encoder->encoder_type = DRM_MODE_ENCODER_DAC;
+	connector->connector_type = DRM_MODE_CONNECTOR_VGA;
+	sdvo_connector = intel_connector->dev_priv;
+
+	if (device == 0) {
+		sdvo_encoder->controlled_output |= SDVO_OUTPUT_RGB0;
+		sdvo_connector->output_flag = SDVO_OUTPUT_RGB0;
+	} else if (device == 1) {
+		sdvo_encoder->controlled_output |= SDVO_OUTPUT_RGB1;
+		sdvo_connector->output_flag = SDVO_OUTPUT_RGB1;
+	}
+
+	intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
+				    (1 << INTEL_ANALOG_CLONE_BIT);
+
+	intel_sdvo_connector_create(encoder, connector);
+	return true;
+}
+
+static bool
+intel_sdvo_lvds_init(struct intel_encoder *intel_encoder, int device)
+{
+	struct drm_encoder *encoder = &intel_encoder->base;
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
+	struct drm_connector *connector;
+	struct intel_connector *intel_connector;
+	struct intel_sdvo_connector *sdvo_connector;
+
+	if (!intel_sdvo_connector_alloc(encoder->dev, &intel_connector))
+		return false;
+
+	connector = &intel_connector->base;
+	encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
+	connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
+	sdvo_connector = intel_connector->dev_priv;
+
+	sdvo_encoder->is_lvds = true;
+
+	if (device == 0) {
+		sdvo_encoder->controlled_output |= SDVO_OUTPUT_LVDS0;
+		sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0;
+	} else if (device == 1) {
+		sdvo_encoder->controlled_output |= SDVO_OUTPUT_LVDS1;
+		sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1;
+	}
+
+	intel_encoder->clone_mask = (1 << INTEL_ANALOG_CLONE_BIT) |
+				    (1 << INTEL_SDVO_LVDS_CLONE_BIT);
+
+	intel_sdvo_connector_create(encoder, connector);
+	intel_sdvo_create_enhance_property(encoder, connector);
+	return true;
+}
+
+static bool
+intel_sdvo_output_setup(struct intel_encoder *intel_encoder)
+{
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
+	int flags = sdvo_encoder->caps.output_flags;
+
+	intel_encoder->needs_tv_clock = false;
+	sdvo_encoder->is_tv = false;
+	sdvo_encoder->is_lvds = false;
+
+	/* SDVO requires XXX1 function may not exist unless it has XXX0 function.*/
+
+	if (flags & SDVO_OUTPUT_TMDS0)
+		if (!intel_sdvo_dvi_init(intel_encoder, 0))
+			return false;
+
+	if ((flags & SDVO_TMDS_MASK) == SDVO_TMDS_MASK)
+		if (!intel_sdvo_dvi_init(intel_encoder, 1))
+			return false;
+
+	/* TV has no XXX1 function block */
+	if (flags & SDVO_OUTPUT_SVID0)
+		if (!intel_sdvo_tv_init(intel_encoder, SDVO_OUTPUT_SVID0))
+			return false;
+
+	if (flags & SDVO_OUTPUT_CVBS0)
+		if (!intel_sdvo_tv_init(intel_encoder, SDVO_OUTPUT_CVBS0))
+			return false;
+
+	if (flags & SDVO_OUTPUT_RGB0)
+		if (!intel_sdvo_analog_init(intel_encoder, 0))
+			return false;
+
+	if ((flags & SDVO_RGB_MASK) == SDVO_RGB_MASK)
+		if (!intel_sdvo_analog_init(intel_encoder, 1))
+			return false;
+
+	if (flags & SDVO_OUTPUT_LVDS0)
+		if (!intel_sdvo_lvds_init(intel_encoder, 0))
+			return false;
+
+	if ((flags & SDVO_LVDS_MASK) == SDVO_LVDS_MASK)
+		if (!intel_sdvo_lvds_init(intel_encoder, 1))
+			return false;
 
+	if ((flags & SDVO_OUTPUT_MASK) == 0) {
 		unsigned char bytes[2];
 
-		sdvo_priv->controlled_output = 0;
-		memcpy(bytes, &sdvo_priv->caps.output_flags, 2);
+		sdvo_encoder->controlled_output = 0;
+		memcpy(bytes, &sdvo_encoder->caps.output_flags, 2);
 		DRM_DEBUG_KMS("%s: Unknown SDVO output type (0x%02x%02x)\n",
-			      SDVO_NAME(sdvo_priv),
+			      SDVO_NAME(sdvo_encoder),
 			      bytes[0], bytes[1]);
-		ret = false;
+		return false;
 	}
 	intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
 
-	if (ret && registered)
-		ret = drm_sysfs_connector_add(connector) == 0 ? true : false;
-
-
-	return ret;
+	return true;
 
 }
 
-static void intel_sdvo_tv_create_property(struct drm_connector *connector)
+static void intel_sdvo_tv_create_property(struct drm_encoder *encoder,
+					  struct drm_connector *connector)
 {
-	struct drm_encoder *encoder = intel_best_encoder(connector);
 	struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_connector *intel_connector = to_intel_connector(connector);
+	struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv;
+	struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv;
 	struct intel_sdvo_tv_format format;
 	uint32_t format_map, i;
 	uint8_t status;
 
 	intel_sdvo_set_target_output(intel_encoder,
-				     sdvo_priv->controlled_output);
+				     sdvo_encoder->attached_output);
 
 	intel_sdvo_write_cmd(intel_encoder,
 			     SDVO_CMD_GET_SUPPORTED_TV_FORMATS, NULL, 0);
@@ -2445,36 +2623,37 @@  static void intel_sdvo_tv_create_property(struct drm_connector *connector)
 	if (format_map == 0)
 		return;
 
-	sdvo_priv->format_supported_num = 0;
+	sdvo_connector->format_supported_num = 0;
 	for (i = 0 ; i < TV_FORMAT_NUM; i++)
 		if (format_map & (1 << i)) {
-			sdvo_priv->tv_format_supported
-			[sdvo_priv->format_supported_num++] =
+			sdvo_connector->tv_format_supported
+			[sdvo_connector->format_supported_num++] =
 			tv_format_names[i];
 		}
 
 
-	sdvo_priv->tv_format_property =
+	sdvo_connector->tv_format_property =
 			drm_property_create(
 				connector->dev, DRM_MODE_PROP_ENUM,
-				"mode", sdvo_priv->format_supported_num);
+				"mode", sdvo_connector->format_supported_num);
 
-	for (i = 0; i < sdvo_priv->format_supported_num; i++)
+	for (i = 0; i < sdvo_connector->format_supported_num; i++)
 		drm_property_add_enum(
-				sdvo_priv->tv_format_property, i,
-				i, sdvo_priv->tv_format_supported[i]);
+				sdvo_connector->tv_format_property, i,
+				i, sdvo_connector->tv_format_supported[i]);
 
-	sdvo_priv->tv_format_name = sdvo_priv->tv_format_supported[0];
+	sdvo_encoder->tv_format_name = sdvo_connector->tv_format_supported[0];
 	drm_connector_attach_property(
-			connector, sdvo_priv->tv_format_property, 0);
+			connector, sdvo_connector->tv_format_property, 0);
 
 }
 
-static void intel_sdvo_create_enhance_property(struct drm_connector *connector)
+static void intel_sdvo_create_enhance_property(struct drm_encoder *encoder,
+					       struct drm_connector *connector)
 {
-	struct drm_encoder *encoder = intel_best_encoder(connector);
 	struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
-	struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+	struct intel_connector *intel_connector = to_intel_connector(connector);
+	struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv;
 	struct intel_sdvo_enhancements_reply sdvo_data;
 	struct drm_device *dev = connector->dev;
 	uint8_t status;
@@ -2493,7 +2672,7 @@  static void intel_sdvo_create_enhance_property(struct drm_connector *connector)
 		DRM_DEBUG_KMS("No enhancement is supported\n");
 		return;
 	}
-	if (sdvo_priv->is_tv) {
+	if (SDVO_CONNECTOR_IS_TV(sdvo_connector)) {
 		/* when horizontal overscan is supported, Add the left/right
 		 * property
 		 */
@@ -2515,25 +2694,25 @@  static void intel_sdvo_create_enhance_property(struct drm_connector *connector)
 				DRM_DEBUG_KMS("Incorrect SDVO h_overscan\n");
 				return;
 			}
-			sdvo_priv->max_hscan = data_value[0];
-			sdvo_priv->left_margin = data_value[0] - response;
-			sdvo_priv->right_margin = sdvo_priv->left_margin;
-			sdvo_priv->left_property =
+			sdvo_connector->max_hscan = data_value[0];
+			sdvo_connector->left_margin = data_value[0] - response;
+			sdvo_connector->right_margin = sdvo_connector->left_margin;
+			sdvo_connector->left_property =
 				drm_property_create(dev, DRM_MODE_PROP_RANGE,
 						"left_margin", 2);
-			sdvo_priv->left_property->values[0] = 0;
-			sdvo_priv->left_property->values[1] = data_value[0];
+			sdvo_connector->left_property->values[0] = 0;
+			sdvo_connector->left_property->values[1] = data_value[0];
 			drm_connector_attach_property(connector,
-						sdvo_priv->left_property,
-						sdvo_priv->left_margin);
-			sdvo_priv->right_property =
+						sdvo_connector->left_property,
+						sdvo_connector->left_margin);
+			sdvo_connector->right_property =
 				drm_property_create(dev, DRM_MODE_PROP_RANGE,
 						"right_margin", 2);
-			sdvo_priv->right_property->values[0] = 0;
-			sdvo_priv->right_property->values[1] = data_value[0];
+			sdvo_connector->right_property->values[0] = 0;
+			sdvo_connector->right_property->values[1] = data_value[0];
 			drm_connector_attach_property(connector,
-						sdvo_priv->right_property,
-						sdvo_priv->right_margin);
+						sdvo_connector->right_property,
+						sdvo_connector->right_margin);
 			DRM_DEBUG_KMS("h_overscan: max %d, "
 					"default %d, current %d\n",
 					data_value[0], data_value[1], response);
@@ -2556,25 +2735,25 @@  static void intel_sdvo_create_enhance_property(struct drm_connector *connector)
 				DRM_DEBUG_KMS("Incorrect SDVO v_overscan\n");
 				return;
 			}
-			sdvo_priv->max_vscan = data_value[0];
-			sdvo_priv->top_margin = data_value[0] - response;
-			sdvo_priv->bottom_margin = sdvo_priv->top_margin;
-			sdvo_priv->top_property =
+			sdvo_connector->max_vscan = data_value[0];
+			sdvo_connector->top_margin = data_value[0] - response;
+			sdvo_connector->bottom_margin = sdvo_connector->top_margin;
+			sdvo_connector->top_property =
 				drm_property_create(dev, DRM_MODE_PROP_RANGE,
 						"top_margin", 2);
-			sdvo_priv->top_property->values[0] = 0;
-			sdvo_priv->top_property->values[1] = data_value[0];
+			sdvo_connector->top_property->values[0] = 0;
+			sdvo_connector->top_property->values[1] = data_value[0];
 			drm_connector_attach_property(connector,
-						sdvo_priv->top_property,
-						sdvo_priv->top_margin);
-			sdvo_priv->bottom_property =
+						sdvo_connector->top_property,
+						sdvo_connector->top_margin);
+			sdvo_connector->bottom_property =
 				drm_property_create(dev, DRM_MODE_PROP_RANGE,
 						"bottom_margin", 2);
-			sdvo_priv->bottom_property->values[0] = 0;
-			sdvo_priv->bottom_property->values[1] = data_value[0];
+			sdvo_connector->bottom_property->values[0] = 0;
+			sdvo_connector->bottom_property->values[1] = data_value[0];
 			drm_connector_attach_property(connector,
-						sdvo_priv->bottom_property,
-						sdvo_priv->bottom_margin);
+						sdvo_connector->bottom_property,
+						sdvo_connector->bottom_margin);
 			DRM_DEBUG_KMS("v_overscan: max %d, "
 					"default %d, current %d\n",
 					data_value[0], data_value[1], response);
@@ -2596,16 +2775,16 @@  static void intel_sdvo_create_enhance_property(struct drm_connector *connector)
 				DRM_DEBUG_KMS("Incorrect SDVO get h_postion\n");
 				return;
 			}
-			sdvo_priv->max_hpos = data_value[0];
-			sdvo_priv->cur_hpos = response;
-			sdvo_priv->hpos_property =
+			sdvo_connector->max_hpos = data_value[0];
+			sdvo_connector->cur_hpos = response;
+			sdvo_connector->hpos_property =
 				drm_property_create(dev, DRM_MODE_PROP_RANGE,
 						"hpos", 2);
-			sdvo_priv->hpos_property->values[0] = 0;
-			sdvo_priv->hpos_property->values[1] = data_value[0];
+			sdvo_connector->hpos_property->values[0] = 0;
+			sdvo_connector->hpos_property->values[1] = data_value[0];
 			drm_connector_attach_property(connector,
-						sdvo_priv->hpos_property,
-						sdvo_priv->cur_hpos);
+						sdvo_connector->hpos_property,
+						sdvo_connector->cur_hpos);
 			DRM_DEBUG_KMS("h_position: max %d, "
 					"default %d, current %d\n",
 					data_value[0], data_value[1], response);
@@ -2627,22 +2806,20 @@  static void intel_sdvo_create_enhance_property(struct drm_connector *connector)
 				DRM_DEBUG_KMS("Incorrect SDVO get v_postion\n");
 				return;
 			}
-			sdvo_priv->max_vpos = data_value[0];
-			sdvo_priv->cur_vpos = response;
-			sdvo_priv->vpos_property =
+			sdvo_connector->max_vpos = data_value[0];
+			sdvo_connector->cur_vpos = response;
+			sdvo_connector->vpos_property =
 				drm_property_create(dev, DRM_MODE_PROP_RANGE,
 						"vpos", 2);
-			sdvo_priv->vpos_property->values[0] = 0;
-			sdvo_priv->vpos_property->values[1] = data_value[0];
+			sdvo_connector->vpos_property->values[0] = 0;
+			sdvo_connector->vpos_property->values[1] = data_value[0];
 			drm_connector_attach_property(connector,
-						sdvo_priv->vpos_property,
-						sdvo_priv->cur_vpos);
+						sdvo_connector->vpos_property,
+						sdvo_connector->cur_vpos);
 			DRM_DEBUG_KMS("v_position: max %d, "
 					"default %d, current %d\n",
 					data_value[0], data_value[1], response);
 		}
-	}
-	if (sdvo_priv->is_tv) {
 		if (sdvo_data.saturation) {
 			intel_sdvo_write_cmd(intel_encoder,
 				SDVO_CMD_GET_MAX_SATURATION, NULL, 0);
@@ -2660,17 +2837,17 @@  static void intel_sdvo_create_enhance_property(struct drm_connector *connector)
 				DRM_DEBUG_KMS("Incorrect SDVO get sat\n");
 				return;
 			}
-			sdvo_priv->max_saturation = data_value[0];
-			sdvo_priv->cur_saturation = response;
-			sdvo_priv->saturation_property =
+			sdvo_connector->max_saturation = data_value[0];
+			sdvo_connector->cur_saturation = response;
+			sdvo_connector->saturation_property =
 				drm_property_create(dev, DRM_MODE_PROP_RANGE,
 						"saturation", 2);
-			sdvo_priv->saturation_property->values[0] = 0;
-			sdvo_priv->saturation_property->values[1] =
+			sdvo_connector->saturation_property->values[0] = 0;
+			sdvo_connector->saturation_property->values[1] =
 							data_value[0];
 			drm_connector_attach_property(connector,
-						sdvo_priv->saturation_property,
-						sdvo_priv->cur_saturation);
+						sdvo_connector->saturation_property,
+						sdvo_connector->cur_saturation);
 			DRM_DEBUG_KMS("saturation: max %d, "
 					"default %d, current %d\n",
 					data_value[0], data_value[1], response);
@@ -2692,16 +2869,16 @@  static void intel_sdvo_create_enhance_property(struct drm_connector *connector)
 				DRM_DEBUG_KMS("Incorrect SDVO get contrast\n");
 				return;
 			}
-			sdvo_priv->max_contrast = data_value[0];
-			sdvo_priv->cur_contrast = response;
-			sdvo_priv->contrast_property =
+			sdvo_connector->max_contrast = data_value[0];
+			sdvo_connector->cur_contrast = response;
+			sdvo_connector->contrast_property =
 				drm_property_create(dev, DRM_MODE_PROP_RANGE,
 						"contrast", 2);
-			sdvo_priv->contrast_property->values[0] = 0;
-			sdvo_priv->contrast_property->values[1] = data_value[0];
+			sdvo_connector->contrast_property->values[0] = 0;
+			sdvo_connector->contrast_property->values[1] = data_value[0];
 			drm_connector_attach_property(connector,
-						sdvo_priv->contrast_property,
-						sdvo_priv->cur_contrast);
+						sdvo_connector->contrast_property,
+						sdvo_connector->cur_contrast);
 			DRM_DEBUG_KMS("contrast: max %d, "
 					"default %d, current %d\n",
 					data_value[0], data_value[1], response);
@@ -2723,22 +2900,24 @@  static void intel_sdvo_create_enhance_property(struct drm_connector *connector)
 				DRM_DEBUG_KMS("Incorrect SDVO get hue\n");
 				return;
 			}
-			sdvo_priv->max_hue = data_value[0];
-			sdvo_priv->cur_hue = response;
-			sdvo_priv->hue_property =
+			sdvo_connector->max_hue = data_value[0];
+			sdvo_connector->cur_hue = response;
+			sdvo_connector->hue_property =
 				drm_property_create(dev, DRM_MODE_PROP_RANGE,
 						"hue", 2);
-			sdvo_priv->hue_property->values[0] = 0;
-			sdvo_priv->hue_property->values[1] =
+			sdvo_connector->hue_property->values[0] = 0;
+			sdvo_connector->hue_property->values[1] =
 							data_value[0];
 			drm_connector_attach_property(connector,
-						sdvo_priv->hue_property,
-						sdvo_priv->cur_hue);
+						sdvo_connector->hue_property,
+						sdvo_connector->cur_hue);
 			DRM_DEBUG_KMS("hue: max %d, default %d, current %d\n",
 					data_value[0], data_value[1], response);
 		}
 	}
-	if (sdvo_priv->is_tv || sdvo_priv->is_lvds) {
+
+	if (SDVO_CONNECTOR_IS_TV(sdvo_connector) ||
+	    SDVO_CONNECTOR_IS_LVDS(sdvo_connector)) {
 		if (sdvo_data.brightness) {
 			intel_sdvo_write_cmd(intel_encoder,
 				SDVO_CMD_GET_MAX_BRIGHTNESS, NULL, 0);
@@ -2756,17 +2935,17 @@  static void intel_sdvo_create_enhance_property(struct drm_connector *connector)
 				DRM_DEBUG_KMS("Incorrect SDVO get brigh\n");
 				return;
 			}
-			sdvo_priv->max_brightness = data_value[0];
-			sdvo_priv->cur_brightness = response;
-			sdvo_priv->brightness_property =
+			sdvo_connector->max_brightness = data_value[0];
+			sdvo_connector->cur_brightness = response;
+			sdvo_connector->brightness_property =
 				drm_property_create(dev, DRM_MODE_PROP_RANGE,
 						"brightness", 2);
-			sdvo_priv->brightness_property->values[0] = 0;
-			sdvo_priv->brightness_property->values[1] =
+			sdvo_connector->brightness_property->values[0] = 0;
+			sdvo_connector->brightness_property->values[1] =
 							data_value[0];
 			drm_connector_attach_property(connector,
-						sdvo_priv->brightness_property,
-						sdvo_priv->cur_brightness);
+						sdvo_connector->brightness_property,
+						sdvo_connector->cur_brightness);
 			DRM_DEBUG_KMS("brightness: max %d, "
 					"default %d, current %d\n",
 					data_value[0], data_value[1], response);
@@ -2778,23 +2957,21 @@  static void intel_sdvo_create_enhance_property(struct drm_connector *connector)
 bool intel_sdvo_init(struct drm_device *dev, int output_device)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_connector *connector;
-	struct intel_connector *intel_connector;
+	struct drm_encoder *encoder;
 	struct intel_encoder *intel_encoder;
-	struct intel_sdvo_priv *sdvo_priv;
+	struct intel_sdvo_encoder *sdvo_encoder;
 	u8 ch[0x40];
 	int i;
 
-	intel_connector = kzalloc(sizeof(*intel_connector), GFP_KERNEL);
-	intel_encoder = kzalloc(sizeof(*intel_encoder) + sizeof(*sdvo_priv), GFP_KERNEL);
+	intel_encoder = kzalloc(sizeof(*intel_encoder) + sizeof(*sdvo_encoder), GFP_KERNEL);
 
-	if (!intel_connector || !intel_encoder)
+	if (!intel_encoder)
 		return false;
 
-	sdvo_priv = (struct intel_sdvo_priv *)(intel_encoder + 1);
-	sdvo_priv->output_device = output_device;
+	sdvo_encoder = (struct intel_sdvo_encoder *)(intel_encoder + 1);
+	sdvo_encoder->output_device = output_device;
 
-	intel_encoder->dev_priv = sdvo_priv;
+	intel_encoder->dev_priv = sdvo_encoder;
 	intel_encoder->type = INTEL_OUTPUT_SDVO;
 
 	/* setup the DDC bus. */
@@ -2804,9 +2981,9 @@  bool intel_sdvo_init(struct drm_device *dev, int output_device)
 		intel_encoder->i2c_bus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC");
 
 	if (!intel_encoder->i2c_bus)
-		goto err_inteloutput;
+		goto err;
 
-	sdvo_priv->slave_addr = intel_sdvo_get_slave_addr(dev, output_device);
+	sdvo_encoder->slave_addr = intel_sdvo_get_slave_addr(dev, output_device);
 
 	/* Save the bit-banging i2c functionality for use by the DDC wrapper */
 	intel_sdvo_i2c_bit_algo.functionality = intel_encoder->i2c_bus->algo->functionality;
@@ -2816,102 +2993,59 @@  bool intel_sdvo_init(struct drm_device *dev, int output_device)
 		if (!intel_sdvo_read_byte(intel_encoder, i, &ch[i])) {
 			DRM_DEBUG_KMS("No SDVO device found on SDVO%c\n",
 					output_device == SDVOB ? 'B' : 'C');
-			goto err_i2c;
+			goto err;
 		}
 	}
 
-	/* setup the DDC bus. */
-	if (output_device == SDVOB) {
-		intel_connector->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS");
-		sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA,
-						"SDVOB/VGA DDC BUS");
+	if (output_device == SDVOB)
 		dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS;
-	} else {
-		intel_connector->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS");
-		sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA,
-						"SDVOC/VGA DDC BUS");
+	else
 		dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS;
-	}
 
-	if (intel_connector->ddc_bus == NULL)
-		goto err_i2c;
-
-	/* Wrap with our custom algo which switches to DDC mode */
-	intel_connector->ddc_bus->algo = &intel_sdvo_i2c_bit_algo;
+	encoder = &intel_encoder->base;
+	/* encoder type will be decided later */
+	drm_encoder_init(dev, encoder, &intel_sdvo_enc_funcs, 0);
+	drm_encoder_helper_add(encoder, &intel_sdvo_helper_funcs);
 
 	/* In default case sdvo lvds is false */
-	intel_sdvo_get_capabilities(intel_encoder, &sdvo_priv->caps);
+	intel_sdvo_get_capabilities(intel_encoder, &sdvo_encoder->caps);
 
-	if (intel_sdvo_output_setup(intel_encoder, intel_connector,
-				    sdvo_priv->caps.output_flags) != true) {
+	if (intel_sdvo_output_setup(intel_encoder) != true) {
 		DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n",
 			  output_device == SDVOB ? 'B' : 'C');
-		goto err_i2c;
+		goto err;
 	}
 
-
-	connector = &intel_connector->base;
-	drm_connector_init(dev, connector, &intel_sdvo_connector_funcs,
-			   connector->connector_type);
-
-	drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs);
-	connector->interlace_allowed = 0;
-	connector->doublescan_allowed = 0;
-	connector->display_info.subpixel_order = SubPixelHorizontalRGB;
-
-	drm_encoder_init(dev, &intel_encoder->base,
-			&intel_sdvo_enc_funcs, intel_encoder->base.encoder_type);
-
-	drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs);
-
-	drm_mode_connector_attach_encoder(&intel_connector->base, &intel_encoder->base);
-	if (sdvo_priv->is_tv)
-		intel_sdvo_tv_create_property(connector);
-
-	if (sdvo_priv->is_tv || sdvo_priv->is_lvds)
-		intel_sdvo_create_enhance_property(connector);
-
-	drm_sysfs_connector_add(connector);
-
-	intel_sdvo_select_ddc_bus(sdvo_priv);
+	intel_sdvo_select_ddc_bus(sdvo_encoder);
 
 	/* Set the input timing to the screen. Assume always input 0. */
 	intel_sdvo_set_target_input(intel_encoder, true, false);
 
 	intel_sdvo_get_input_pixel_clock_range(intel_encoder,
-					       &sdvo_priv->pixel_clock_min,
-					       &sdvo_priv->pixel_clock_max);
+					       &sdvo_encoder->pixel_clock_min,
+					       &sdvo_encoder->pixel_clock_max);
 
 
 	DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, "
 			"clock range %dMHz - %dMHz, "
 			"input 1: %c, input 2: %c, "
 			"output 1: %c, output 2: %c\n",
-			SDVO_NAME(sdvo_priv),
-			sdvo_priv->caps.vendor_id, sdvo_priv->caps.device_id,
-			sdvo_priv->caps.device_rev_id,
-			sdvo_priv->pixel_clock_min / 1000,
-			sdvo_priv->pixel_clock_max / 1000,
-			(sdvo_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N',
-			(sdvo_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N',
+			SDVO_NAME(sdvo_encoder),
+			sdvo_encoder->caps.vendor_id, sdvo_encoder->caps.device_id,
+			sdvo_encoder->caps.device_rev_id,
+			sdvo_encoder->pixel_clock_min / 1000,
+			sdvo_encoder->pixel_clock_max / 1000,
+			(sdvo_encoder->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N',
+			(sdvo_encoder->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N',
 			/* check currently supported outputs */
-			sdvo_priv->caps.output_flags &
+			sdvo_encoder->caps.output_flags &
 			(SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N',
-			sdvo_priv->caps.output_flags &
+			sdvo_encoder->caps.output_flags &
 			(SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N');
 
 	return true;
 
-err_i2c:
-	if (sdvo_priv->analog_ddc_bus != NULL)
-		intel_i2c_destroy(sdvo_priv->analog_ddc_bus);
-	if (intel_connector->ddc_bus != NULL)
-		intel_i2c_destroy(intel_connector->ddc_bus);
-	if (intel_encoder->i2c_bus != NULL)
-		intel_i2c_destroy(intel_encoder->i2c_bus);
-err_inteloutput:
+err:
 	kfree(intel_encoder);
-	kfree(intel_connector);
-
 	return false;
 }