[Intel-gfx] [PATCH 3/4] drm/i915: implement multifunction SDVO device support

Zhenyu Wang zhenyuw at linux.intel.com
Tue Mar 9 03:21:58 CET 2010


With new intel_encoder/intel_connector structure change, each supported
connector type on SDVO device will be created as a new 'intel_connector', and
all attached to one 'intel_encoder' for its SDVO port. The SDVO encoder will
handle SDVO protocol stuff, and each connector does its own part of work now,
like detection is only to check if current active output is itself, etc.

This is SDVO specific part of change within original big patch for intel
encoder/connector rework.

Update:
- Fix TMDS digital encode type detection for TMDS0 and TMDS1

Signed-off-by: Zhenyu Wang <zhenyuw at linux.intel.com>
---
 drivers/gpu/drm/i915/intel_sdvo.c | 1144 +++++++++++++++++++++----------------
 1 files changed, 639 insertions(+), 505 deletions(-)

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;
 }
-- 
1.7.0




More information about the Intel-gfx mailing list