Subject: [PATCH] drm/i915: Fetch EDID for SDVO output on Mac machine. Because Mac machine has only one port, which can connect VGA, DVI or TV by adapter, share ddc bus(GPIOA), in sdvo get modes function we need to check VGA, and steal the ddc bus, then return after operaton. This is actually a sync with UMS Signed-off-by: Ma Ling --- drivers/gpu/drm/i915/intel_sdvo.c | 105 +++++++++++++++++++++++++++++++------- 1 file changed, 87 insertions(+), 18 deletions(-) Index: linux-2.6/drivers/gpu/drm/i915/intel_sdvo.c =================================================================== --- linux-2.6.orig/drivers/gpu/drm/i915/intel_sdvo.c 2009-08-07 17:33:21.000000000 +0800 +++ linux-2.6/drivers/gpu/drm/i915/intel_sdvo.c 2009-08-07 17:58:13.000000000 +0800 @@ -1478,6 +1478,53 @@ return (caps > 1); } +static struct edid *intel_sdvo_get_edid(struct drm_connector *connector) +{ + struct intel_output *intel_output = to_intel_output(connector); + struct edid *edid = NULL; + struct drm_connector *vgaconn = NULL; + struct i2c_adapter *ddcbus = NULL; + + edid = drm_get_edid(connector, intel_output->ddc_bus); + if (edid) + return edid; + + /* 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. + */ + + list_for_each_entry(vgaconn, + &connector->dev->mode_config.connector_list, head) { + /* We check all connector to guarantee CRT is invalid, + * then steal CRT ddcbus. + */ + enum drm_connector_status status; + struct intel_output *intel_vga_output = + to_intel_output(vgaconn); + if (intel_vga_output->type == INTEL_OUTPUT_ANALOG) { + status = vgaconn->funcs->detect(connector); + if (status == connector_status_connected) + return NULL; + break; + } + } + ddcbus = intel_i2c_create(connector->dev, + GPIOA, "CRTDDC_A"); + if (!ddcbus) { + return NULL; + } + intel_i2c_quirk_set(intel_output->base.dev, true); + edid = drm_get_edid(connector, ddcbus); + intel_i2c_quirk_set(intel_output->base.dev, false); + /* + * Because user might connect CRT later, delete temporary bus. + */ + intel_i2c_destroy(ddcbus); + return edid; +} + enum drm_connector_status intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response) { @@ -1486,8 +1533,7 @@ enum drm_connector_status status = connector_status_connected; struct edid *edid = NULL; - edid = drm_get_edid(&intel_output->base, - intel_output->ddc_bus); + edid = intel_sdvo_get_edid(connector); if (edid != NULL) { /* Don't report the output as connected if it's a DVI-I * connector with a non-digital EDID coming out. @@ -1540,31 +1586,54 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) { struct intel_output *intel_output = to_intel_output(connector); + struct drm_connector *vgaconn; + struct i2c_adapter *ddcbus; + int ret; /* set the bus switch and get the modes */ - intel_ddc_get_modes(intel_output); + ret = intel_ddc_get_modes(intel_output); + + if (ret) + return; -#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. */ - 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); + + list_for_each_entry(vgaconn, + &connector->dev->mode_config.connector_list, head) { + /* We check all connector to guarantee CRT is invalid, + * then steal CRT ddcbus. + */ + enum drm_connector_status status; + struct intel_output *intel_vga_output = + to_intel_output(vgaconn); + if (intel_vga_output->type == INTEL_OUTPUT_ANALOG) { + status = vgaconn->funcs->detect(connector); + if (status == connector_status_connected) + return; + break; + } + } + /*Resever SDVO DDC bus */ + ddcbus = intel_output->ddc_bus; + intel_output->ddc_bus = intel_i2c_create(connector->dev, + GPIOA, "CRTDDC_A"); + if (!intel_output->ddc_bus) { + intel_output->ddc_bus = ddcbus; + return; } -#endif + + intel_ddc_get_modes(intel_output); + + /* + * Because user might connect CRT later, + * so we need to restore ddc bus. + */ + intel_i2c_destroy(intel_output->ddc_bus); + intel_output->ddc_bus = ddcbus; } /**