Merge branch 'for-2.6.30' of git://linux-nfs.org/~bfields/linux
[safe/jmp/linux-2.6] / drivers / gpu / drm / i915 / intel_sdvo.c
index 31cd9b8..f3ef6bf 100644 (file)
@@ -69,6 +69,10 @@ struct intel_sdvo_priv {
         * This is set if we treat the device as HDMI, instead of DVI.
         */
        bool is_hdmi;
+       /**
+        * This is set if we detect output of sdvo device as LVDS.
+        */
+       bool is_lvds;
 
        /**
         * Returned SDTV resolutions allowed for the current format, if the
@@ -589,9 +593,12 @@ intel_sdvo_create_preferred_input_timing(struct intel_output *output,
        struct intel_sdvo_preferred_input_timing_args args;
        uint8_t status;
 
+       memset(&args, 0, sizeof(args));
        args.clock = clock;
        args.width = width;
        args.height = height;
+       args.interlace = 0;
+       args.scaled = 0;
        intel_sdvo_write_cmd(output, SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING,
                             &args, sizeof(args));
        status = intel_sdvo_read_response(output, NULL, 0);
@@ -908,6 +915,27 @@ static void intel_sdvo_set_avi_infoframe(struct intel_output *output,
                                SDVO_HBUF_TX_VSYNC);
 }
 
+static void intel_sdvo_set_tv_format(struct intel_output *output)
+{
+       struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
+       struct intel_sdvo_tv_format *format, unset;
+       u8 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));
+       }
+}
+
 static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
                                  struct drm_display_mode *mode,
                                  struct drm_display_mode *adjusted_mode)
@@ -952,6 +980,12 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
                                                             &input_dtd);
                        intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
 
+                       drm_mode_set_crtcinfo(adjusted_mode, 0);
+
+                       mode->clock = adjusted_mode->clock;
+
+                       adjusted_mode->clock *=
+                               intel_sdvo_get_pixel_multiplier(mode);
                } else {
                        return false;
                }
@@ -996,7 +1030,12 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
                sdvox |= SDVO_AUDIO_ENABLE;
        }
 
-       intel_sdvo_get_dtd_from_mode(&input_dtd, mode);
+       /* We have tried to get input timing in mode_fixup, and filled into
+          adjusted_mode */
+       if (sdvo_priv->is_tv)
+               intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
+       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.
@@ -1011,6 +1050,9 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
        /* Set the input timing to the screen. Assume always input 0. */
        intel_sdvo_set_target_input(output, true, false);
 
+       if (sdvo_priv->is_tv)
+               intel_sdvo_set_tv_format(output);
+
        /* We would like to use intel_sdvo_create_preferred_input_timing() to
         * provide the device with a timing it can support, if it supports that
         * feature.  However, presumably we would need to adjust the CRTC to
@@ -1319,6 +1361,23 @@ void intel_sdvo_set_hotplug(struct drm_connector *connector, int on)
        intel_sdvo_read_response(intel_output, &response, 2);
 }
 
+static void
+intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+       struct edid *edid = NULL;
+
+       intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus);
+       edid = drm_get_edid(&intel_output->base,
+                           &intel_output->ddc_bus->adapter);
+       if (edid != NULL) {
+               sdvo_priv->is_hdmi = drm_detect_hdmi_monitor(edid);
+               kfree(edid);
+               intel_output->base.display_info.raw_edid = NULL;
+       }
+}
+
 static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector)
 {
        u8 response[2];
@@ -1333,19 +1392,18 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect
        if (status != SDVO_CMD_STATUS_SUCCESS)
                return connector_status_unknown;
 
-       if ((response[0] != 0) || (response[1] != 0))
+       if ((response[0] != 0) || (response[1] != 0)) {
+               intel_sdvo_hdmi_sink_detect(connector);
                return connector_status_connected;
-       else
+       else
                return connector_status_disconnected;
 }
 
 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;
 
        /* set the bus switch and get the modes */
-       intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus);
        intel_ddc_get_modes(intel_output);
 
 #if 0
@@ -1379,7 +1437,7 @@ static void
 intel_sdvo_check_tv_format(struct intel_output *output)
 {
        struct intel_sdvo_priv *dev_priv = output->dev_priv;
-       struct intel_sdvo_tv_format format, unset;
+       struct intel_sdvo_tv_format format;
        uint8_t status;
 
        intel_sdvo_write_cmd(output, SDVO_CMD_GET_TV_FORMAT, NULL, 0);
@@ -1387,15 +1445,7 @@ intel_sdvo_check_tv_format(struct intel_output *output)
        if (status != SDVO_CMD_STATUS_SUCCESS)
                return;
 
-       memset(&unset, 0, sizeof(unset));
-       if (memcmp(&format, &unset, sizeof(format))) {
-               DRM_DEBUG("%s: Choosing default TV format of NTSC-M\n",
-                         SDVO_NAME(dev_priv));
-
-               format.ntsc_m = true;
-               intel_sdvo_write_cmd(output, SDVO_CMD_SET_TV_FORMAT, NULL, 0);
-               status = intel_sdvo_read_response(output, NULL, 0);
-       }
+       memcpy(&dev_priv->tv_format, &format, sizeof(format));
 }
 
 /*
@@ -1404,68 +1454,70 @@ intel_sdvo_check_tv_format(struct intel_output *output)
  * XXX: all 60Hz refresh?
  */
 struct drm_display_mode sdvo_tv_modes[] = {
-       { DRM_MODE("320x200", DRM_MODE_TYPE_DRIVER, 5815680, 321, 384, 416,
-                  200, 0, 232, 201, 233, 4196112, 0,
+       { DRM_MODE("320x200", DRM_MODE_TYPE_DRIVER, 5815, 320, 321, 384,
+                  416, 0, 200, 201, 232, 233, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("320x240", DRM_MODE_TYPE_DRIVER, 6814080, 321, 384, 416,
-                  240, 0, 272, 241, 273, 4196112, 0,
+       { DRM_MODE("320x240", DRM_MODE_TYPE_DRIVER, 6814, 320, 321, 384,
+                  416, 0, 240, 241, 272, 273, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("400x300", DRM_MODE_TYPE_DRIVER, 9910080, 401, 464, 496,
-                  300, 0, 332, 301, 333, 4196112, 0,
+       { DRM_MODE("400x300", DRM_MODE_TYPE_DRIVER, 9910, 400, 401, 464,
+                  496, 0, 300, 301, 332, 333, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 16913280, 641, 704, 736,
-                  350, 0, 382, 351, 383, 4196112, 0,
+       { DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 16913, 640, 641, 704,
+                  736, 0, 350, 351, 382, 383, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 19121280, 641, 704, 736,
-                  400, 0, 432, 401, 433, 4196112, 0,
+       { DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 19121, 640, 641, 704,
+                  736, 0, 400, 401, 432, 433, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 19121280, 641, 704, 736,
-                  400, 0, 432, 401, 433, 4196112, 0,
+       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 22654, 640, 641, 704,
+                  736, 0, 480, 481, 512, 513, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("704x480", DRM_MODE_TYPE_DRIVER, 24624000, 705, 768, 800,
-                  480, 0, 512, 481, 513, 4196112, 0,
+       { DRM_MODE("704x480", DRM_MODE_TYPE_DRIVER, 24624, 704, 705, 768,
+                  800, 0, 480, 481, 512, 513, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("704x576", DRM_MODE_TYPE_DRIVER, 29232000, 705, 768, 800,
-                  576, 0, 608, 577, 609, 4196112, 0,
+       { DRM_MODE("704x576", DRM_MODE_TYPE_DRIVER, 29232, 704, 705, 768,
+                  800, 0, 576, 577, 608, 609, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("720x350", DRM_MODE_TYPE_DRIVER, 18751680, 721, 784, 816,
-                  350, 0, 382, 351, 383, 4196112, 0,
+       { DRM_MODE("720x350", DRM_MODE_TYPE_DRIVER, 18751, 720, 721, 784,
+                  816, 0, 350, 351, 382, 383, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 21199680, 721, 784, 816,
-                  400, 0, 432, 401, 433, 4196112, 0,
+       { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 21199, 720, 721, 784,
+                  816, 0, 400, 401, 432, 433, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 25116480, 721, 784, 816,
-                  480, 0, 512, 481, 513, 4196112, 0,
+       { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 25116, 720, 721, 784,
+                  816, 0, 480, 481, 512, 513, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("720x540", DRM_MODE_TYPE_DRIVER, 28054080, 721, 784, 816,
-                  540, 0, 572, 541, 573, 4196112, 0,
+       { DRM_MODE("720x540", DRM_MODE_TYPE_DRIVER, 28054, 720, 721, 784,
+                  816, 0, 540, 541, 572, 573, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 29816640, 721, 784, 816,
-                  576, 0, 608, 577, 609, 4196112, 0,
+       { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 29816, 720, 721, 784,
+                  816, 0, 576, 577, 608, 609, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("768x576", DRM_MODE_TYPE_DRIVER, 31570560, 769, 832, 864,
-                  576, 0, 608, 577, 609, 4196112, 0,
+       { DRM_MODE("768x576", DRM_MODE_TYPE_DRIVER, 31570, 768, 769, 832,
+                  864, 0, 576, 577, 608, 609, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 34030080, 801, 864, 896,
-                  600, 0, 632, 601, 633, 4196112, 0,
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 34030, 800, 801, 864,
+                  896, 0, 600, 601, 632, 633, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 36581760, 833, 896, 928,
-                  624, 0, 656, 625, 657, 4196112, 0,
+       { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 36581, 832, 833, 896,
+                  928, 0, 624, 625, 656, 657, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("920x766", DRM_MODE_TYPE_DRIVER, 48707040, 921, 984, 1016,
-                  766, 0, 798, 767, 799, 4196112, 0,
+       { DRM_MODE("920x766", DRM_MODE_TYPE_DRIVER, 48707, 920, 921, 984,
+                  1016, 0, 766, 767, 798, 799, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 53827200, 1025, 1088, 1120,
-                  768, 0, 800, 769, 801, 4196112, 0,
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 53827, 1024, 1025, 1088,
+                  1120, 0, 768, 769, 800, 801, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 87265920, 1281, 1344, 1376,
-                  1024, 0, 1056, 1025, 1057, 4196112, 0,
+       { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 87265, 1280, 1281, 1344,
+                  1376, 0, 1024, 1025, 1056, 1057, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
 };
 
 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;
        uint8_t status;
        int i = 0;
@@ -1475,15 +1527,53 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
        /* 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));
        intel_sdvo_write_cmd(output, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
-                            NULL, 0);
+                            &tv_res, sizeof(tv_res));
        status = intel_sdvo_read_response(output, &reply, 3);
        if (status != SDVO_CMD_STATUS_SUCCESS)
                return;
 
        for (i = 0; i < ARRAY_SIZE(sdvo_tv_modes); i++)
-               if (reply & (1 << i))
-                       drm_mode_probed_add(connector, &sdvo_tv_modes[i]);
+               if (reply & (1 << i)) {
+                       struct drm_display_mode *nmode;
+                       nmode = drm_mode_duplicate(connector->dev,
+                                       &sdvo_tv_modes[i]);
+                       if (nmode)
+                               drm_mode_probed_add(connector, nmode);
+               }
+}
+
+static void intel_sdvo_get_lvds_modes(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_i915_private *dev_priv = connector->dev->dev_private;
+
+       /*
+        * Attempt to get the mode list from DDC.
+        * Assume that the preferred modes are
+        * arranged in priority order.
+        */
+       /* set the bus switch and get the modes */
+       intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus);
+       intel_ddc_get_modes(intel_output);
+       if (list_empty(&connector->probed_modes) == false)
+               return;
+
+       /* Fetch modes from VBT */
+       if (dev_priv->sdvo_lvds_vbt_mode != NULL) {
+               struct drm_display_mode *newmode;
+               newmode = drm_mode_duplicate(connector->dev,
+                                            dev_priv->sdvo_lvds_vbt_mode);
+               if (newmode != NULL) {
+                       /* Guarantee the mode is preferred */
+                       newmode->type = (DRM_MODE_TYPE_PREFERRED |
+                                        DRM_MODE_TYPE_DRIVER);
+                       drm_mode_probed_add(connector, newmode);
+               }
+       }
 }
 
 static int intel_sdvo_get_modes(struct drm_connector *connector)
@@ -1493,6 +1583,8 @@ static int intel_sdvo_get_modes(struct drm_connector *connector)
 
        if (sdvo_priv->is_tv)
                intel_sdvo_get_tv_modes(connector);
+       else if (sdvo_priv->is_lvds == true)
+               intel_sdvo_get_lvds_modes(connector);
        else
                intel_sdvo_get_ddc_modes(connector);
 
@@ -1507,6 +1599,9 @@ static void intel_sdvo_destroy(struct drm_connector *connector)
 
        if (intel_output->i2c_bus)
                intel_i2c_destroy(intel_output->i2c_bus);
+       if (intel_output->ddc_bus)
+               intel_i2c_destroy(intel_output->ddc_bus);
+
        drm_sysfs_connector_remove(connector);
        drm_connector_cleanup(connector);
        kfree(intel_output);
@@ -1603,12 +1698,56 @@ intel_sdvo_get_digital_encoding_mode(struct intel_output *output)
        return true;
 }
 
+static struct intel_output *
+intel_sdvo_chan_to_intel_output(struct intel_i2c_chan *chan)
+{
+       struct drm_device *dev = chan->drm_dev;
+       struct drm_connector *connector;
+       struct intel_output *intel_output = NULL;
+
+       list_for_each_entry(connector,
+                       &dev->mode_config.connector_list, head) {
+               if (to_intel_output(connector)->ddc_bus == chan) {
+                       intel_output = to_intel_output(connector);
+                       break;
+               }
+       }
+       return intel_output;
+}
+
+static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap,
+                                 struct i2c_msg msgs[], int num)
+{
+       struct intel_output *intel_output;
+       struct intel_sdvo_priv *sdvo_priv;
+       struct i2c_algo_bit_data *algo_data;
+       struct i2c_algorithm *algo;
+
+       algo_data = (struct i2c_algo_bit_data *)i2c_adap->algo_data;
+       intel_output =
+               intel_sdvo_chan_to_intel_output(
+                               (struct intel_i2c_chan *)(algo_data->data));
+       if (intel_output == NULL)
+               return -EINVAL;
+
+       sdvo_priv = intel_output->dev_priv;
+       algo = (struct i2c_algorithm *)intel_output->i2c_bus->adapter.algo;
+
+       intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus);
+       return algo->master_xfer(i2c_adap, msgs, num);
+}
+
+static struct i2c_algorithm intel_sdvo_i2c_bit_algo = {
+       .master_xfer    = intel_sdvo_master_xfer,
+};
+
 bool intel_sdvo_init(struct drm_device *dev, int output_device)
 {
        struct drm_connector *connector;
        struct intel_output *intel_output;
        struct intel_sdvo_priv *sdvo_priv;
        struct intel_i2c_chan *i2cbus = NULL;
+       struct intel_i2c_chan *ddcbus = NULL;
        int connector_type;
        u8 ch[0x40];
        int i;
@@ -1619,17 +1758,9 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
                return false;
        }
 
-       connector = &intel_output->base;
-
-       drm_connector_init(dev, connector, &intel_sdvo_connector_funcs,
-                          DRM_MODE_CONNECTOR_Unknown);
-       drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs);
        sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1);
        intel_output->type = INTEL_OUTPUT_SDVO;
 
-       connector->interlace_allowed = 0;
-       connector->doublescan_allowed = 0;
-
        /* setup the DDC bus. */
        if (output_device == SDVOB)
                i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB");
@@ -1637,7 +1768,7 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
                i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC");
 
        if (!i2cbus)
-               goto err_connector;
+               goto err_inteloutput;
 
        sdvo_priv->i2c_bus = i2cbus;
 
@@ -1653,7 +1784,6 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
        intel_output->i2c_bus = i2cbus;
        intel_output->dev_priv = sdvo_priv;
 
-
        /* 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])) {
@@ -1663,6 +1793,22 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
                }
        }
 
+       /* setup the DDC bus. */
+       if (output_device == SDVOB)
+               ddcbus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS");
+       else
+               ddcbus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS");
+
+       if (ddcbus == NULL)
+               goto err_i2c;
+
+       intel_sdvo_i2c_bit_algo.functionality =
+               intel_output->i2c_bus->adapter.algo->functionality;
+       ddcbus->adapter.algo = &intel_sdvo_i2c_bit_algo;
+       intel_output->ddc_bus = ddcbus;
+
+       /* In defaut case sdvo lvds is false */
+       sdvo_priv->is_lvds = false;
        intel_sdvo_get_capabilities(intel_output, &sdvo_priv->caps);
 
        if (sdvo_priv->caps.output_flags &
@@ -1672,7 +1818,6 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
                else
                        sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS1;
 
-               connector->display_info.subpixel_order = SubPixelHorizontalRGB;
                encoder_type = DRM_MODE_ENCODER_TMDS;
                connector_type = DRM_MODE_CONNECTOR_DVID;
 
@@ -1690,7 +1835,6 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
        else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_SVID0)
        {
                sdvo_priv->controlled_output = SDVO_OUTPUT_SVID0;
-               connector->display_info.subpixel_order = SubPixelHorizontalRGB;
                encoder_type = DRM_MODE_ENCODER_TVDAC;
                connector_type = DRM_MODE_CONNECTOR_SVIDEO;
                sdvo_priv->is_tv = true;
@@ -1699,30 +1843,28 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
        else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0)
        {
                sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0;
-               connector->display_info.subpixel_order = SubPixelHorizontalRGB;
                encoder_type = DRM_MODE_ENCODER_DAC;
                connector_type = DRM_MODE_CONNECTOR_VGA;
        }
        else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1)
        {
                sdvo_priv->controlled_output = SDVO_OUTPUT_RGB1;
-               connector->display_info.subpixel_order = SubPixelHorizontalRGB;
                encoder_type = DRM_MODE_ENCODER_DAC;
                connector_type = DRM_MODE_CONNECTOR_VGA;
        }
        else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS0)
        {
                sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0;
-               connector->display_info.subpixel_order = SubPixelHorizontalRGB;
                encoder_type = DRM_MODE_ENCODER_LVDS;
                connector_type = DRM_MODE_CONNECTOR_LVDS;
+               sdvo_priv->is_lvds = true;
        }
        else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS1)
        {
                sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS1;
-               connector->display_info.subpixel_order = SubPixelHorizontalRGB;
                encoder_type = DRM_MODE_ENCODER_LVDS;
                connector_type = DRM_MODE_CONNECTOR_LVDS;
+               sdvo_priv->is_lvds = true;
        }
        else
        {
@@ -1738,9 +1880,16 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
                goto err_i2c;
        }
 
+       connector = &intel_output->base;
+       drm_connector_init(dev, connector, &intel_sdvo_connector_funcs,
+                          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_output->enc, &intel_sdvo_enc_funcs, encoder_type);
        drm_encoder_helper_add(&intel_output->enc, &intel_sdvo_helper_funcs);
-       connector->connector_type = connector_type;
 
        drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
        drm_sysfs_connector_add(connector);
@@ -1772,14 +1921,13 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
                  sdvo_priv->caps.output_flags &
                        (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N');
 
-       intel_output->ddc_bus = i2cbus;
-
        return true;
 
 err_i2c:
+       if (ddcbus != NULL)
+               intel_i2c_destroy(intel_output->ddc_bus);
        intel_i2c_destroy(intel_output->i2c_bus);
-err_connector:
-       drm_connector_cleanup(connector);
+err_inteloutput:
        kfree(intel_output);
 
        return false;