mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-21 19:53:59 +08:00
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 <ling.ma@intel.com> [anholt: Hand application for conflict, fixed error path] Signed-off-by: Eric Anholt <eric@anholt.net>
This commit is contained in:
parent
ad5b2a6db3
commit
619ac3b75a
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user