Skip to content

Commit

Permalink
drm/i915/sdvo: Only create the analog encoder as required
Browse files Browse the repository at this point in the history
We only need to use the analog encoder for rare devices which share the
DDC between the DVI-I and VGA connectors, so only create as needed.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
  • Loading branch information
Chris Wilson committed Sep 15, 2010
1 parent 3f08e4e commit ff482d8
Showing 1 changed file with 41 additions and 28 deletions.
69 changes: 41 additions & 28 deletions drivers/gpu/drm/i915/intel_sdvo.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,6 @@ struct intel_sdvo {
/* DDC bus used by this SDVO encoder */
uint8_t ddc_bus;

/* Mac mini hack -- use the same DDC as the analog connector */
struct i2c_adapter *analog_ddc_bus;

/* Input timings for adjusted_mode */
struct intel_sdvo_dtd input_dtd;
};
Expand Down Expand Up @@ -1417,6 +1414,34 @@ intel_analog_is_connected(struct drm_device *dev)
return true;
}

/* Mac mini hack -- use the same DDC as the analog connector */
static struct edid *
intel_sdvo_get_analog_edid(struct drm_connector *connector)
{
struct intel_encoder *encoder = intel_attached_encoder(connector);
struct drm_device *dev = connector->dev;
struct i2c_adapter *ddc;
struct edid *edid;
u32 ddc_reg;

if (!intel_analog_is_connected(dev))
return NULL;

if (HAS_PCH_SPLIT(dev))
ddc_reg = PCH_GPIOA;
else
ddc_reg = GPIOA;

ddc = intel_i2c_create(encoder, ddc_reg, "SDVO/VGA DDC BUS");
if (ddc == NULL)
return NULL;

edid = drm_get_edid(connector, ddc);
intel_i2c_destroy(ddc);

return edid;
}

enum drm_connector_status
intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
{
Expand Down Expand Up @@ -1452,10 +1477,8 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
* 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 &&
intel_sdvo->analog_ddc_bus &&
!intel_analog_is_connected(connector->dev))
edid = drm_get_edid(connector, intel_sdvo->analog_ddc_bus);
if (edid == NULL)
edid = intel_sdvo_get_analog_edid(connector);

status = connector_status_disconnected;
if (edid != NULL) {
Expand Down Expand Up @@ -1522,23 +1545,26 @@ 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_sdvo *intel_sdvo = intel_attached_sdvo(connector);
struct edid *edid;
int num_modes;

/* set the bus switch and get the modes */
num_modes = intel_ddc_get_modes(connector, intel_sdvo->base.ddc_bus);
if (num_modes)
return;

/*
* 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.
*/
if (num_modes == 0 &&
intel_sdvo->analog_ddc_bus &&
!intel_analog_is_connected(connector->dev)) {
/* Switch to the analog ddc bus and try that
*/
(void) intel_ddc_get_modes(connector, intel_sdvo->analog_ddc_bus);
edid = intel_sdvo_get_analog_edid(connector);
if (edid != NULL) {
drm_mode_connector_update_edid_property(connector, edid);
drm_add_edid_modes(connector, edid);
connector->display_info.raw_edid = NULL;
kfree(edid);
}
}

Expand Down Expand Up @@ -1898,9 +1924,6 @@ static void intel_sdvo_enc_destroy(struct drm_encoder *encoder)
{
struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);

if (intel_sdvo->analog_ddc_bus)
intel_i2c_destroy(intel_sdvo->analog_ddc_bus);

if (intel_sdvo->sdvo_lvds_fixed_mode != NULL)
drm_mode_destroy(encoder->dev,
intel_sdvo->sdvo_lvds_fixed_mode);
Expand Down Expand Up @@ -2519,7 +2542,7 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
struct intel_sdvo *intel_sdvo;
u8 ch[0x40];
int i;
u32 i2c_reg, ddc_reg, analog_ddc_reg;
u32 i2c_reg, ddc_reg;

intel_sdvo = kzalloc(sizeof(struct intel_sdvo), GFP_KERNEL);
if (!intel_sdvo)
Expand All @@ -2533,11 +2556,9 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
if (HAS_PCH_SPLIT(dev)) {
i2c_reg = PCH_GPIOE;
ddc_reg = PCH_GPIOE;
analog_ddc_reg = PCH_GPIOA;
} else {
i2c_reg = GPIOE;
ddc_reg = GPIOE;
analog_ddc_reg = GPIOA;
}

/* setup the DDC bus. */
Expand Down Expand Up @@ -2572,20 +2593,14 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
intel_encoder->ddc_bus =
intel_i2c_create(intel_encoder,
ddc_reg, "SDVOB DDC BUS");
intel_sdvo->analog_ddc_bus =
intel_i2c_create(intel_encoder,
analog_ddc_reg, "SDVOB/VGA DDC BUS");
dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS;
} else {
intel_encoder->ddc_bus =
intel_i2c_create(intel_encoder,
ddc_reg, "SDVOC DDC BUS");
intel_sdvo->analog_ddc_bus =
intel_i2c_create(intel_encoder,
analog_ddc_reg, "SDVOC/VGA DDC BUS");
dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS;
}
if (intel_encoder->ddc_bus == NULL || intel_sdvo->analog_ddc_bus == NULL)
if (intel_encoder->ddc_bus == NULL)
goto err_i2c;

/* Wrap with our custom algo which switches to DDC mode */
Expand Down Expand Up @@ -2638,8 +2653,6 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
err_enc:
drm_encoder_cleanup(&intel_encoder->base);
err_i2c:
if (intel_sdvo->analog_ddc_bus != NULL)
intel_i2c_destroy(intel_sdvo->analog_ddc_bus);
if (intel_encoder->ddc_bus != NULL)
intel_i2c_destroy(intel_encoder->ddc_bus);
if (intel_encoder->i2c_bus != NULL)
Expand Down

0 comments on commit ff482d8

Please sign in to comment.