Merge branch 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / drivers / gpu / drm / i915 / intel_sdvo.c
index d3b74ba..083bec2 100644 (file)
 #include "intel_sdvo_regs.h"
 
 #undef SDVO_DEBUG
-#define I915_SDVO      "i915_sdvo"
+
+static char *tv_format_names[] = {
+       "NTSC_M"   , "NTSC_J"  , "NTSC_443",
+       "PAL_B"    , "PAL_D"   , "PAL_G"   ,
+       "PAL_H"    , "PAL_I"   , "PAL_M"   ,
+       "PAL_N"    , "PAL_NC"  , "PAL_60"  ,
+       "SECAM_B"  , "SECAM_D" , "SECAM_G" ,
+       "SECAM_K"  , "SECAM_K1", "SECAM_L" ,
+       "SECAM_60"
+};
+
+#define TV_FORMAT_NUM  (sizeof(tv_format_names) / sizeof(*tv_format_names))
+
 struct intel_sdvo_priv {
        u8 slave_addr;
 
@@ -71,6 +83,15 @@ 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.
         */
@@ -97,14 +118,6 @@ struct intel_sdvo_priv {
         */
        struct intel_sdvo_sdtv_resolution_reply sdtv_resolutions;
 
-       /**
-        * Current selected TV format.
-        *
-        * This is stored in the same structure that's passed to the device, for
-        * convenience.
-        */
-       struct intel_sdvo_tv_format tv_format;
-
        /*
         * supported encoding mode, used to determine whether HDMI is
         * supported
@@ -114,11 +127,38 @@ struct intel_sdvo_priv {
        /* DDC bus used by this SDVO output */
        uint8_t ddc_bus;
 
+       /* Mac mini hack -- use the same DDC as the analog connector */
+       struct i2c_adapter *analog_ddc_bus;
+
        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;
+       /* add the property for the SDVO-TV */
+       struct drm_property *left_property;
+       struct drm_property *right_property;
+       struct drm_property *top_property;
+       struct drm_property *bottom_property;
+       struct drm_property *hpos_property;
+       struct drm_property *vpos_property;
+
+       /* add the property for the SDVO-TV/LVDS */
+       struct drm_property *brightness_property;
+       struct drm_property *contrast_property;
+       struct drm_property *saturation_property;
+       struct drm_property *hue_property;
+
+       /* Add variable to record current setting for the above property */
+       u32     left_margin, right_margin, top_margin, bottom_margin;
+       /* this is to get the range of margin.*/
+       u32     max_hscan,  max_vscan;
+       u32     max_hpos, cur_hpos;
+       u32     max_vpos, cur_vpos;
+       u32     cur_brightness, max_brightness;
+       u32     cur_contrast,   max_contrast;
+       u32     cur_saturation, max_saturation;
+       u32     cur_hue,        max_hue;
 };
 
 static bool
@@ -188,7 +228,7 @@ static bool intel_sdvo_read_byte(struct intel_output *intel_output, u8 addr,
                return true;
        }
 
-       DRM_DEBUG("i2c transfer returned %d\n", ret);
+       DRM_DEBUG_KMS("i2c transfer returned %d\n", ret);
        return false;
 }
 
@@ -265,6 +305,31 @@ static const struct _sdvo_cmd_name {
     SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT),
     SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SCALED_HDTV_RESOLUTION_SUPPORT),
     SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS),
+    /* Add the op code for SDVO enhancements */
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_POSITION_H),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_POSITION_H),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_POSITION_H),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_POSITION_V),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_POSITION_V),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_POSITION_V),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_SATURATION),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SATURATION),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_SATURATION),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_HUE),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HUE),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HUE),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_CONTRAST),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_CONTRAST),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CONTRAST),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_BRIGHTNESS),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_BRIGHTNESS),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_BRIGHTNESS),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_OVERSCAN_H),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OVERSCAN_H),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OVERSCAN_H),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_OVERSCAN_V),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OVERSCAN_V),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OVERSCAN_V),
     /* HDMI op code */
     SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPP_ENCODE),
     SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ENCODE),
@@ -298,7 +363,7 @@ static void intel_sdvo_debug_write(struct intel_output *intel_output, u8 cmd,
        struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
        int i;
 
-       DRM_DEBUG_KMS(I915_SDVO, "%s: W: %02X ",
+       DRM_DEBUG_KMS("%s: W: %02X ",
                                SDVO_NAME(sdvo_priv), cmd);
        for (i = 0; i < args_len; i++)
                DRM_LOG_KMS("%02X ", ((u8 *)args)[i]);
@@ -351,7 +416,7 @@ static void intel_sdvo_debug_response(struct intel_output *intel_output,
        struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
        int i;
 
-       DRM_DEBUG_KMS(I915_SDVO, "%s: R: ", SDVO_NAME(sdvo_priv));
+       DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(sdvo_priv));
        for (i = 0; i < response_len; i++)
                DRM_LOG_KMS("%02X ", ((u8 *)response)[i]);
        for (; i < 8; i++)
@@ -668,10 +733,10 @@ static int intel_sdvo_get_clock_rate_mult(struct intel_output *intel_output)
        status = intel_sdvo_read_response(intel_output, &response, 1);
 
        if (status != SDVO_CMD_STATUS_SUCCESS) {
-               DRM_DEBUG("Couldn't get SDVO clock rate multiplier\n");
+               DRM_DEBUG_KMS("Couldn't get SDVO clock rate multiplier\n");
                return SDVO_CLOCK_RATE_MULT_1X;
        } else {
-               DRM_DEBUG("Current clock rate multiplier: %d\n", response);
+               DRM_DEBUG_KMS("Current clock rate multiplier: %d\n", response);
        }
 
        return response;
@@ -945,23 +1010,28 @@ static void intel_sdvo_set_avi_infoframe(struct intel_output *output,
 
 static void intel_sdvo_set_tv_format(struct intel_output *output)
 {
+
+       struct intel_sdvo_tv_format format;
        struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
-       struct intel_sdvo_tv_format *format, unset;
-       u8 status;
+       uint32_t format_map, i;
+       uint8_t status;
 
-       format = &sdvo_priv->tv_format;
-       memset(&unset, 0, sizeof(unset));
-       if (memcmp(format, &unset, sizeof(*format))) {
-               DRM_DEBUG("%s: Choosing default TV format of NTSC-M\n",
-                               SDVO_NAME(sdvo_priv));
-               format->ntsc_m = 1;
-               intel_sdvo_write_cmd(output, SDVO_CMD_SET_TV_FORMAT, format,
-                               sizeof(*format));
-               status = intel_sdvo_read_response(output, NULL, 0);
-               if (status != SDVO_CMD_STATUS_SUCCESS)
-                       DRM_DEBUG("%s: Failed to set TV format\n",
-                                       SDVO_NAME(sdvo_priv));
-       }
+       for (i = 0; i < TV_FORMAT_NUM; i++)
+               if (tv_format_names[i] == sdvo_priv->tv_format_name)
+                       break;
+
+       format_map = 1 << i;
+       memset(&format, 0, sizeof(format));
+       memcpy(&format, &format_map, sizeof(format_map) > sizeof(format) ?
+                       sizeof(format) : sizeof(format_map));
+
+       intel_sdvo_write_cmd(output, SDVO_CMD_SET_TV_FORMAT, &format_map,
+                            sizeof(format));
+
+       status = intel_sdvo_read_response(output, NULL, 0);
+       if (status != SDVO_CMD_STATUS_SUCCESS)
+               DRM_DEBUG_KMS("%s: Failed to set TV format\n",
+                         SDVO_NAME(sdvo_priv));
 }
 
 static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
@@ -1230,8 +1300,8 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
                 * a given it the status is a success, we succeeded.
                 */
                if (status == SDVO_CMD_STATUS_SUCCESS && !input1) {
-                       DRM_DEBUG("First %s output reported failure to sync\n",
-                                  SDVO_NAME(sdvo_priv));
+                       DRM_DEBUG_KMS("First %s output reported failure to "
+                                       "sync\n", SDVO_NAME(sdvo_priv));
                }
 
                if (0)
@@ -1326,8 +1396,8 @@ static void intel_sdvo_restore(struct drm_connector *connector)
                        intel_wait_for_vblank(dev);
                status = intel_sdvo_get_trained_inputs(intel_output, &input1, &input2);
                if (status == SDVO_CMD_STATUS_SUCCESS && !input1)
-                       DRM_DEBUG("First %s output reported failure to sync\n",
-                                  SDVO_NAME(sdvo_priv));
+                       DRM_DEBUG_KMS("First %s output reported failure to "
+                                       "sync\n", SDVO_NAME(sdvo_priv));
        }
 
        intel_sdvo_set_active_outputs(intel_output, sdvo_priv->save_active_outputs);
@@ -1405,7 +1475,7 @@ int intel_sdvo_supports_hotplug(struct drm_connector *connector)
        u8 response[2];
        u8 status;
        struct intel_output *intel_output;
-       DRM_DEBUG("\n");
+       DRM_DEBUG_KMS("\n");
 
        if (!connector)
                return 0;
@@ -1478,6 +1548,36 @@ intel_sdvo_multifunc_encoder(struct intel_output *intel_output)
        return (caps > 1);
 }
 
+static struct drm_connector *
+intel_find_analog_connector(struct drm_device *dev)
+{
+       struct drm_connector *connector;
+       struct intel_output *intel_output;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               intel_output = to_intel_output(connector);
+               if (intel_output->type == INTEL_OUTPUT_ANALOG)
+                       return connector;
+       }
+       return NULL;
+}
+
+static int
+intel_analog_is_connected(struct drm_device *dev)
+{
+       struct drm_connector *analog_connector;
+       analog_connector = intel_find_analog_connector(dev);
+
+       if (!analog_connector)
+               return false;
+
+       if (analog_connector->funcs->detect(analog_connector) ==
+                       connector_status_disconnected)
+               return false;
+
+       return true;
+}
+
 enum drm_connector_status
 intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response)
 {
@@ -1488,6 +1588,15 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response)
 
        edid = drm_get_edid(&intel_output->base,
                            intel_output->ddc_bus);
+
+       /* 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 &&
+           !intel_analog_is_connected(intel_output->base.dev))
+               edid = drm_get_edid(&intel_output->base,
+                                   sdvo_priv->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.
@@ -1516,10 +1625,11 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect
        struct intel_output *intel_output = to_intel_output(connector);
        struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
 
-       intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0);
+       intel_sdvo_write_cmd(intel_output,
+                            SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0);
        status = intel_sdvo_read_response(intel_output, &response, 2);
 
-       DRM_DEBUG("SDVO response %d %d\n", response & 0xff, response >> 8);
+       DRM_DEBUG_KMS("SDVO response %d %d\n", response & 0xff, response >> 8);
 
        if (status != SDVO_CMD_STATUS_SUCCESS)
                return connector_status_unknown;
@@ -1540,50 +1650,32 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect
 static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
 {
        struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+       int num_modes;
 
        /* set the bus switch and get the modes */
-       intel_ddc_get_modes(intel_output);
+       num_modes = intel_ddc_get_modes(intel_output);
 
-#if 0
-       struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       /* Mac mini hack.  On this device, I get DDC through the analog, which
-        * load-detects as disconnected.  I fail to DDC through the SDVO DDC,
-        * but it does load-detect as connected.  So, just steal the DDC bits
-        * from analog when we fail at finding it the right way.
+       /*
+        * Mac mini hack.  On this device, the DVI-I connector shares one DDC
+        * link between analog and digital outputs. So, if the regular SDVO
+        * DDC fails, check to see if the analog output is disconnected, in
+        * which case we'll look there for the digital DDC data.
         */
-       crt = xf86_config->output[0];
-       intel_output = crt->driver_private;
-       if (intel_output->type == I830_OUTPUT_ANALOG &&
-           crt->funcs->detect(crt) == XF86OutputStatusDisconnected) {
-               I830I2CInit(pScrn, &intel_output->pDDCBus, GPIOA, "CRTDDC_A");
-               edid_mon = xf86OutputGetEDID(crt, intel_output->pDDCBus);
-               xf86DestroyI2CBusRec(intel_output->pDDCBus, true, true);
-       }
-       if (edid_mon) {
-               xf86OutputSetEDID(output, edid_mon);
-               modes = xf86OutputGetEDIDModes(output);
-       }
-#endif
-}
+       if (num_modes == 0 &&
+           sdvo_priv->analog_ddc_bus &&
+           !intel_analog_is_connected(intel_output->base.dev)) {
+               struct i2c_adapter *digital_ddc_bus;
 
-/**
- * This function checks the current TV format, and chooses a default if
- * it hasn't been set.
- */
-static void
-intel_sdvo_check_tv_format(struct intel_output *output)
-{
-       struct intel_sdvo_priv *dev_priv = output->dev_priv;
-       struct intel_sdvo_tv_format format;
-       uint8_t status;
+               /* Switch to the analog ddc bus and try that
+                */
+               digital_ddc_bus = intel_output->ddc_bus;
+               intel_output->ddc_bus = sdvo_priv->analog_ddc_bus;
 
-       intel_sdvo_write_cmd(output, SDVO_CMD_GET_TV_FORMAT, NULL, 0);
-       status = intel_sdvo_read_response(output, &format, sizeof(format));
-       if (status != SDVO_CMD_STATUS_SUCCESS)
-               return;
+               (void) intel_ddc_get_modes(intel_output);
 
-       memcpy(&dev_priv->tv_format, &format, sizeof(format));
+               intel_output->ddc_bus = digital_ddc_bus;
+       }
 }
 
 /*
@@ -1656,17 +1748,26 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
        struct intel_output *output = to_intel_output(connector);
        struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
        struct intel_sdvo_sdtv_resolution_request tv_res;
-       uint32_t reply = 0;
+       uint32_t reply = 0, format_map = 0;
+       int i;
        uint8_t status;
-       int i = 0;
 
-       intel_sdvo_check_tv_format(output);
 
        /* Read the list of supported input resolutions for the selected TV
         * format.
         */
-       memset(&tv_res, 0, sizeof(tv_res));
-       memcpy(&tv_res, &sdvo_priv->tv_format, sizeof(tv_res));
+       for (i = 0; i < TV_FORMAT_NUM; i++)
+               if (tv_format_names[i] ==  sdvo_priv->tv_format_name)
+                       break;
+
+       format_map = (1 << i);
+       memcpy(&tv_res, &format_map,
+              sizeof(struct intel_sdvo_sdtv_resolution_request) >
+              sizeof(format_map) ? sizeof(format_map) :
+              sizeof(struct intel_sdvo_sdtv_resolution_request));
+
+       intel_sdvo_set_target_output(output, sdvo_priv->controlled_output);
+
        intel_sdvo_write_cmd(output, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
                             &tv_res, sizeof(tv_res));
        status = intel_sdvo_read_response(output, &reply, 3);
@@ -1681,6 +1782,7 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
                        if (nmode)
                                drm_mode_probed_add(connector, nmode);
                }
+
 }
 
 static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
@@ -1739,6 +1841,45 @@ static int intel_sdvo_get_modes(struct drm_connector *connector)
        return 1;
 }
 
+static
+void intel_sdvo_destroy_enhance_property(struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_sdvo_priv *sdvo_priv = intel_output->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)
+                       drm_property_destroy(dev,
+                                       sdvo_priv->saturation_property);
+               if (sdvo_priv->contrast_property)
+                       drm_property_destroy(dev,
+                                       sdvo_priv->contrast_property);
+               if (sdvo_priv->hue_property)
+                       drm_property_destroy(dev, sdvo_priv->hue_property);
+       }
+       if (sdvo_priv->is_tv || sdvo_priv->is_lvds) {
+               if (sdvo_priv->brightness_property)
+                       drm_property_destroy(dev,
+                                       sdvo_priv->brightness_property);
+       }
+       return;
+}
+
 static void intel_sdvo_destroy(struct drm_connector *connector)
 {
        struct intel_output *intel_output = to_intel_output(connector);
@@ -1748,17 +1889,158 @@ static void intel_sdvo_destroy(struct drm_connector *connector)
                intel_i2c_destroy(intel_output->i2c_bus);
        if (intel_output->ddc_bus)
                intel_i2c_destroy(intel_output->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_priv->tv_format_property)
+               drm_property_destroy(connector->dev,
+                                    sdvo_priv->tv_format_property);
+
+       if (sdvo_priv->is_tv || sdvo_priv->is_lvds)
+               intel_sdvo_destroy_enhance_property(connector);
+
        drm_sysfs_connector_remove(connector);
        drm_connector_cleanup(connector);
 
        kfree(intel_output);
 }
 
+static int
+intel_sdvo_set_property(struct drm_connector *connector,
+                       struct drm_property *property,
+                       uint64_t val)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+       struct drm_encoder *encoder = &intel_output->enc;
+       struct drm_crtc *crtc = encoder->crtc;
+       int ret = 0;
+       bool changed = false;
+       uint8_t cmd, status;
+       uint16_t temp_value;
+
+       ret = drm_connector_property_set_value(connector, property, val);
+       if (ret < 0)
+               goto out;
+
+       if (property == sdvo_priv->tv_format_property) {
+               if (val >= TV_FORMAT_NUM) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+               if (sdvo_priv->tv_format_name ==
+                   sdvo_priv->tv_format_supported[val])
+                       goto out;
+
+               sdvo_priv->tv_format_name = sdvo_priv->tv_format_supported[val];
+               changed = true;
+       }
+
+       if (sdvo_priv->is_tv || sdvo_priv->is_lvds) {
+               cmd = 0;
+               temp_value = val;
+               if (sdvo_priv->left_property == property) {
+                       drm_connector_property_set_value(connector,
+                               sdvo_priv->right_property, val);
+                       if (sdvo_priv->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;
+                       cmd = SDVO_CMD_SET_OVERSCAN_H;
+               } else if (sdvo_priv->right_property == property) {
+                       drm_connector_property_set_value(connector,
+                               sdvo_priv->left_property, val);
+                       if (sdvo_priv->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;
+                       cmd = SDVO_CMD_SET_OVERSCAN_H;
+               } else if (sdvo_priv->top_property == property) {
+                       drm_connector_property_set_value(connector,
+                               sdvo_priv->bottom_property, val);
+                       if (sdvo_priv->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;
+                       cmd = SDVO_CMD_SET_OVERSCAN_V;
+               } else if (sdvo_priv->bottom_property == property) {
+                       drm_connector_property_set_value(connector,
+                               sdvo_priv->top_property, val);
+                       if (sdvo_priv->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;
+                       cmd = SDVO_CMD_SET_OVERSCAN_V;
+               } else if (sdvo_priv->hpos_property == property) {
+                       if (sdvo_priv->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)
+                               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)
+                               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)
+                               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)
+                               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)
+                               goto out;
+
+                       cmd = SDVO_CMD_SET_BRIGHTNESS;
+                       sdvo_priv->cur_brightness = temp_value;
+               }
+               if (cmd) {
+                       intel_sdvo_write_cmd(intel_output, cmd, &temp_value, 2);
+                       status = intel_sdvo_read_response(intel_output,
+                                                               NULL, 0);
+                       if (status != SDVO_CMD_STATUS_SUCCESS) {
+                               DRM_DEBUG_KMS("Incorrect SDVO command \n");
+                               return -EINVAL;
+                       }
+                       changed = true;
+               }
+       }
+       if (changed && crtc)
+               drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
+                               crtc->y, crtc->fb);
+out:
+       return ret;
+}
+
 static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = {
        .dpms = intel_sdvo_dpms,
        .mode_fixup = intel_sdvo_mode_fixup,
@@ -1773,6 +2055,7 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
        .restore = intel_sdvo_restore,
        .detect = intel_sdvo_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
+       .set_property = intel_sdvo_set_property,
        .destroy = intel_sdvo_destroy,
 };
 
@@ -1991,6 +2274,8 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
                sdvo_priv->controlled_output = SDVO_OUTPUT_RGB1;
                encoder->encoder_type = DRM_MODE_ENCODER_DAC;
                connector->connector_type = DRM_MODE_CONNECTOR_VGA;
+               intel_output->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
+                                       (1 << INTEL_ANALOG_CLONE_BIT);
        } else if (flags & SDVO_OUTPUT_LVDS0) {
 
                sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0;
@@ -2013,10 +2298,9 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
 
                sdvo_priv->controlled_output = 0;
                memcpy(bytes, &sdvo_priv->caps.output_flags, 2);
-               DRM_DEBUG_KMS(I915_SDVO,
-                               "%s: Unknown SDVO output type (0x%02x%02x)\n",
-                                 SDVO_NAME(sdvo_priv),
-                                 bytes[0], bytes[1]);
+               DRM_DEBUG_KMS("%s: Unknown SDVO output type (0x%02x%02x)\n",
+                             SDVO_NAME(sdvo_priv),
+                             bytes[0], bytes[1]);
                ret = false;
        }
        intel_output->crtc_mask = (1 << 0) | (1 << 1);
@@ -2029,6 +2313,359 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
 
 }
 
+static void intel_sdvo_tv_create_property(struct drm_connector *connector)
+{
+      struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+       struct intel_sdvo_tv_format format;
+       uint32_t format_map, i;
+       uint8_t status;
+
+       intel_sdvo_set_target_output(intel_output,
+                                    sdvo_priv->controlled_output);
+
+       intel_sdvo_write_cmd(intel_output,
+                            SDVO_CMD_GET_SUPPORTED_TV_FORMATS, NULL, 0);
+       status = intel_sdvo_read_response(intel_output,
+                                         &format, sizeof(format));
+       if (status != SDVO_CMD_STATUS_SUCCESS)
+               return;
+
+       memcpy(&format_map, &format, sizeof(format) > sizeof(format_map) ?
+              sizeof(format_map) : sizeof(format));
+
+       if (format_map == 0)
+               return;
+
+       sdvo_priv->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++] =
+                       tv_format_names[i];
+               }
+
+
+       sdvo_priv->tv_format_property =
+                       drm_property_create(
+                               connector->dev, DRM_MODE_PROP_ENUM,
+                               "mode", sdvo_priv->format_supported_num);
+
+       for (i = 0; i < sdvo_priv->format_supported_num; i++)
+               drm_property_add_enum(
+                               sdvo_priv->tv_format_property, i,
+                               i, sdvo_priv->tv_format_supported[i]);
+
+       sdvo_priv->tv_format_name = sdvo_priv->tv_format_supported[0];
+       drm_connector_attach_property(
+                       connector, sdvo_priv->tv_format_property, 0);
+
+}
+
+static void intel_sdvo_create_enhance_property(struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+       struct intel_sdvo_enhancements_reply sdvo_data;
+       struct drm_device *dev = connector->dev;
+       uint8_t status;
+       uint16_t response, data_value[2];
+
+       intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS,
+                                               NULL, 0);
+       status = intel_sdvo_read_response(intel_output, &sdvo_data,
+                                       sizeof(sdvo_data));
+       if (status != SDVO_CMD_STATUS_SUCCESS) {
+               DRM_DEBUG_KMS(" incorrect response is returned\n");
+               return;
+       }
+       response = *((uint16_t *)&sdvo_data);
+       if (!response) {
+               DRM_DEBUG_KMS("No enhancement is supported\n");
+               return;
+       }
+       if (sdvo_priv->is_tv) {
+               /* when horizontal overscan is supported, Add the left/right
+                * property
+                */
+               if (sdvo_data.overscan_h) {
+                       intel_sdvo_write_cmd(intel_output,
+                               SDVO_CMD_GET_MAX_OVERSCAN_H, NULL, 0);
+                       status = intel_sdvo_read_response(intel_output,
+                               &data_value, 4);
+                       if (status != SDVO_CMD_STATUS_SUCCESS) {
+                               DRM_DEBUG_KMS("Incorrect SDVO max "
+                                               "h_overscan\n");
+                               return;
+                       }
+                       intel_sdvo_write_cmd(intel_output,
+                               SDVO_CMD_GET_OVERSCAN_H, NULL, 0);
+                       status = intel_sdvo_read_response(intel_output,
+                               &response, 2);
+                       if (status != SDVO_CMD_STATUS_SUCCESS) {
+                               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 =
+                               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];
+                       drm_connector_attach_property(connector,
+                                               sdvo_priv->left_property,
+                                               sdvo_priv->left_margin);
+                       sdvo_priv->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];
+                       drm_connector_attach_property(connector,
+                                               sdvo_priv->right_property,
+                                               sdvo_priv->right_margin);
+                       DRM_DEBUG_KMS("h_overscan: max %d, "
+                                       "default %d, current %d\n",
+                                       data_value[0], data_value[1], response);
+               }
+               if (sdvo_data.overscan_v) {
+                       intel_sdvo_write_cmd(intel_output,
+                               SDVO_CMD_GET_MAX_OVERSCAN_V, NULL, 0);
+                       status = intel_sdvo_read_response(intel_output,
+                               &data_value, 4);
+                       if (status != SDVO_CMD_STATUS_SUCCESS) {
+                               DRM_DEBUG_KMS("Incorrect SDVO max "
+                                               "v_overscan\n");
+                               return;
+                       }
+                       intel_sdvo_write_cmd(intel_output,
+                               SDVO_CMD_GET_OVERSCAN_V, NULL, 0);
+                       status = intel_sdvo_read_response(intel_output,
+                               &response, 2);
+                       if (status != SDVO_CMD_STATUS_SUCCESS) {
+                               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 =
+                               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];
+                       drm_connector_attach_property(connector,
+                                               sdvo_priv->top_property,
+                                               sdvo_priv->top_margin);
+                       sdvo_priv->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];
+                       drm_connector_attach_property(connector,
+                                               sdvo_priv->bottom_property,
+                                               sdvo_priv->bottom_margin);
+                       DRM_DEBUG_KMS("v_overscan: max %d, "
+                                       "default %d, current %d\n",
+                                       data_value[0], data_value[1], response);
+               }
+               if (sdvo_data.position_h) {
+                       intel_sdvo_write_cmd(intel_output,
+                               SDVO_CMD_GET_MAX_POSITION_H, NULL, 0);
+                       status = intel_sdvo_read_response(intel_output,
+                               &data_value, 4);
+                       if (status != SDVO_CMD_STATUS_SUCCESS) {
+                               DRM_DEBUG_KMS("Incorrect SDVO Max h_pos\n");
+                               return;
+                       }
+                       intel_sdvo_write_cmd(intel_output,
+                               SDVO_CMD_GET_POSITION_H, NULL, 0);
+                       status = intel_sdvo_read_response(intel_output,
+                               &response, 2);
+                       if (status != SDVO_CMD_STATUS_SUCCESS) {
+                               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 =
+                               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];
+                       drm_connector_attach_property(connector,
+                                               sdvo_priv->hpos_property,
+                                               sdvo_priv->cur_hpos);
+                       DRM_DEBUG_KMS("h_position: max %d, "
+                                       "default %d, current %d\n",
+                                       data_value[0], data_value[1], response);
+               }
+               if (sdvo_data.position_v) {
+                       intel_sdvo_write_cmd(intel_output,
+                               SDVO_CMD_GET_MAX_POSITION_V, NULL, 0);
+                       status = intel_sdvo_read_response(intel_output,
+                               &data_value, 4);
+                       if (status != SDVO_CMD_STATUS_SUCCESS) {
+                               DRM_DEBUG_KMS("Incorrect SDVO Max v_pos\n");
+                               return;
+                       }
+                       intel_sdvo_write_cmd(intel_output,
+                               SDVO_CMD_GET_POSITION_V, NULL, 0);
+                       status = intel_sdvo_read_response(intel_output,
+                               &response, 2);
+                       if (status != SDVO_CMD_STATUS_SUCCESS) {
+                               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 =
+                               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];
+                       drm_connector_attach_property(connector,
+                                               sdvo_priv->vpos_property,
+                                               sdvo_priv->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_output,
+                               SDVO_CMD_GET_MAX_SATURATION, NULL, 0);
+                       status = intel_sdvo_read_response(intel_output,
+                               &data_value, 4);
+                       if (status != SDVO_CMD_STATUS_SUCCESS) {
+                               DRM_DEBUG_KMS("Incorrect SDVO Max sat\n");
+                               return;
+                       }
+                       intel_sdvo_write_cmd(intel_output,
+                               SDVO_CMD_GET_SATURATION, NULL, 0);
+                       status = intel_sdvo_read_response(intel_output,
+                               &response, 2);
+                       if (status != SDVO_CMD_STATUS_SUCCESS) {
+                               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 =
+                               drm_property_create(dev, DRM_MODE_PROP_RANGE,
+                                               "saturation", 2);
+                       sdvo_priv->saturation_property->values[0] = 0;
+                       sdvo_priv->saturation_property->values[1] =
+                                                       data_value[0];
+                       drm_connector_attach_property(connector,
+                                               sdvo_priv->saturation_property,
+                                               sdvo_priv->cur_saturation);
+                       DRM_DEBUG_KMS("saturation: max %d, "
+                                       "default %d, current %d\n",
+                                       data_value[0], data_value[1], response);
+               }
+               if (sdvo_data.contrast) {
+                       intel_sdvo_write_cmd(intel_output,
+                               SDVO_CMD_GET_MAX_CONTRAST, NULL, 0);
+                       status = intel_sdvo_read_response(intel_output,
+                               &data_value, 4);
+                       if (status != SDVO_CMD_STATUS_SUCCESS) {
+                               DRM_DEBUG_KMS("Incorrect SDVO Max contrast\n");
+                               return;
+                       }
+                       intel_sdvo_write_cmd(intel_output,
+                               SDVO_CMD_GET_CONTRAST, NULL, 0);
+                       status = intel_sdvo_read_response(intel_output,
+                               &response, 2);
+                       if (status != SDVO_CMD_STATUS_SUCCESS) {
+                               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 =
+                               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];
+                       drm_connector_attach_property(connector,
+                                               sdvo_priv->contrast_property,
+                                               sdvo_priv->cur_contrast);
+                       DRM_DEBUG_KMS("contrast: max %d, "
+                                       "default %d, current %d\n",
+                                       data_value[0], data_value[1], response);
+               }
+               if (sdvo_data.hue) {
+                       intel_sdvo_write_cmd(intel_output,
+                               SDVO_CMD_GET_MAX_HUE, NULL, 0);
+                       status = intel_sdvo_read_response(intel_output,
+                               &data_value, 4);
+                       if (status != SDVO_CMD_STATUS_SUCCESS) {
+                               DRM_DEBUG_KMS("Incorrect SDVO Max hue\n");
+                               return;
+                       }
+                       intel_sdvo_write_cmd(intel_output,
+                               SDVO_CMD_GET_HUE, NULL, 0);
+                       status = intel_sdvo_read_response(intel_output,
+                               &response, 2);
+                       if (status != SDVO_CMD_STATUS_SUCCESS) {
+                               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 =
+                               drm_property_create(dev, DRM_MODE_PROP_RANGE,
+                                               "hue", 2);
+                       sdvo_priv->hue_property->values[0] = 0;
+                       sdvo_priv->hue_property->values[1] =
+                                                       data_value[0];
+                       drm_connector_attach_property(connector,
+                                               sdvo_priv->hue_property,
+                                               sdvo_priv->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_data.brightness) {
+                       intel_sdvo_write_cmd(intel_output,
+                               SDVO_CMD_GET_MAX_BRIGHTNESS, NULL, 0);
+                       status = intel_sdvo_read_response(intel_output,
+                               &data_value, 4);
+                       if (status != SDVO_CMD_STATUS_SUCCESS) {
+                               DRM_DEBUG_KMS("Incorrect SDVO Max bright\n");
+                               return;
+                       }
+                       intel_sdvo_write_cmd(intel_output,
+                               SDVO_CMD_GET_BRIGHTNESS, NULL, 0);
+                       status = intel_sdvo_read_response(intel_output,
+                               &response, 2);
+                       if (status != SDVO_CMD_STATUS_SUCCESS) {
+                               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 =
+                               drm_property_create(dev, DRM_MODE_PROP_RANGE,
+                                               "brightness", 2);
+                       sdvo_priv->brightness_property->values[0] = 0;
+                       sdvo_priv->brightness_property->values[1] =
+                                                       data_value[0];
+                       drm_connector_attach_property(connector,
+                                               sdvo_priv->brightness_property,
+                                               sdvo_priv->cur_brightness);
+                       DRM_DEBUG_KMS("brightness: max %d, "
+                                       "default %d, current %d\n",
+                                       data_value[0], data_value[1], response);
+               }
+       }
+       return;
+}
+
 bool intel_sdvo_init(struct drm_device *dev, int output_device)
 {
        struct drm_connector *connector;
@@ -2066,18 +2703,22 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
        /* Read the regs to test if we can talk to the device */
        for (i = 0; i < 0x40; i++) {
                if (!intel_sdvo_read_byte(intel_output, i, &ch[i])) {
-                       DRM_DEBUG_KMS(I915_SDVO,
-                                       "No SDVO device found on SDVO%c\n",
+                       DRM_DEBUG_KMS("No SDVO device found on SDVO%c\n",
                                        output_device == SDVOB ? 'B' : 'C');
                        goto err_i2c;
                }
        }
 
        /* setup the DDC bus. */
-       if (output_device == SDVOB)
+       if (output_device == SDVOB) {
                intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS");
-       else
+               sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA,
+                                               "SDVOB/VGA DDC BUS");
+       } else {
                intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS");
+               sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA,
+                                               "SDVOC/VGA DDC BUS");
+       }
 
        if (intel_output->ddc_bus == NULL)
                goto err_i2c;
@@ -2090,7 +2731,7 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
 
        if (intel_sdvo_output_setup(intel_output,
                                    sdvo_priv->caps.output_flags) != true) {
-               DRM_DEBUG("SDVO output failed to setup on SDVO%c\n",
+               DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n",
                          output_device == SDVOB ? 'B' : 'C');
                goto err_i2c;
        }
@@ -2111,6 +2752,12 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
        drm_encoder_helper_add(&intel_output->enc, &intel_sdvo_helper_funcs);
 
        drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
+       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);
@@ -2123,7 +2770,7 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
                                               &sdvo_priv->pixel_clock_max);
 
 
-       DRM_DEBUG_KMS(I915_SDVO, "%s device VID/DID: %02X:%02X.%02X, "
+       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",
@@ -2143,6 +2790,8 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
        return true;
 
 err_i2c:
+       if (sdvo_priv->analog_ddc_bus != NULL)
+               intel_i2c_destroy(sdvo_priv->analog_ddc_bus);
        if (intel_output->ddc_bus != NULL)
                intel_i2c_destroy(intel_output->ddc_bus);
        if (intel_output->i2c_bus != NULL)