From 7086c87fb1446ceb37918ffa0941359a7c2ec6cf Mon Sep 17 00:00:00 2001 From: Ma Ling Date: Wed, 13 May 2009 11:20:06 +0800 Subject: drm/i915: Return SDVO LVDS VBT mode if no EDID modes are detected. Some new SDVO LVDS hardware doesn't have DDC available, and this should fix the display on it. Signed-off-by: Ma Ling Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_sdvo.c | 41 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'drivers/gpu/drm/i915/intel_sdvo.c') diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 9913651c1e1..f79ebf4de63 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -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 @@ -1543,6 +1547,37 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) } } +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) { struct intel_output *output = to_intel_output(connector); @@ -1550,6 +1585,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); @@ -1720,6 +1757,8 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) } } + /* 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 & @@ -1773,6 +1812,7 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) 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) { @@ -1780,6 +1820,7 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) connector->display_info.subpixel_order = SubPixelHorizontalRGB; encoder_type = DRM_MODE_ENCODER_LVDS; connector_type = DRM_MODE_CONNECTOR_LVDS; + sdvo_priv->is_lvds = true; } else { -- cgit v1.2.3 From ad5b2a6db3eddc41358d8a73f5cfe1c38e7e3a19 Mon Sep 17 00:00:00 2001 From: Jonas Bonn Date: Fri, 15 May 2009 09:10:41 +0200 Subject: drm/i915: Determine type before initialising connector drm_connector_init sets both the connector type and the connector type_id on the newly initialised connector. As the connector type_id is coupled to the connector type, the connector type cannot simply be modified on an initialised connector. This patch changes the order of operations on intel_sdvo_init so that the type is determined before the connector is intialised. This fixes a bug whereby the name card0-VGA-1 would be allocted to both a CRT and an SDVO connector since the SDVO connector would be initialised with type 'unknown' and hence have its type_id assigned from the wrong pool. Signed-off-by: Jonas Bonn Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_sdvo.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_sdvo.c') diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index f79ebf4de63..ded122c1ae2 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1713,17 +1713,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"); @@ -1731,7 +1723,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; @@ -1747,7 +1739,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])) { @@ -1768,7 +1759,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; @@ -1786,7 +1776,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; @@ -1795,21 +1784,18 @@ 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; @@ -1817,7 +1803,6 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) 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; @@ -1836,9 +1821,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); @@ -1876,8 +1868,7 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) err_i2c: intel_i2c_destroy(intel_output->i2c_bus); -err_connector: - drm_connector_cleanup(connector); +err_inteloutput: kfree(intel_output); return false; -- cgit v1.2.3 From 619ac3b75a1e9b2df66857f6a0fb466f1da5fa9e Mon Sep 17 00:00:00 2001 From: Ma Ling Date: Mon, 18 May 2009 16:12:46 +0800 Subject: drm/i915: Use an I2C algo to do the flip to SDVO DDC bus. Previously, we would set the control bus switch before calls were made to request EDID information over DDC. But recently the DDC code started doing multiple I2C transfers to get the EDID extensions as well. This tripped up SDVO, because the control bus switch is only in effect until the next STOP after a START. By doing our own algo, we can wrap each i2c transaction on the DDC I2C bus with the control bus switch it requires. freedesktop.org bug #21042 Signed-off-by: Ma Ling [anholt: Hand application for conflict, fixed error path] Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_sdvo.c | 67 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_sdvo.c') diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index ded122c1ae2..f3ef6bfd8ff 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1402,10 +1402,8 @@ 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; /* 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 @@ -1601,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); @@ -1697,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; @@ -1748,6 +1793,20 @@ 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); @@ -1862,11 +1921,11 @@ 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_inteloutput: kfree(intel_output); -- cgit v1.2.3