diff options
-rw-r--r-- | drivers/gpu/drm/i915/intel_sdvo.c | 96 |
1 files changed, 74 insertions, 22 deletions
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index cabe32df7cd5..c585da8d6627 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c | |||
@@ -127,6 +127,9 @@ struct intel_sdvo_priv { | |||
127 | /* DDC bus used by this SDVO output */ | 127 | /* DDC bus used by this SDVO output */ |
128 | uint8_t ddc_bus; | 128 | uint8_t ddc_bus; |
129 | 129 | ||
130 | /* Mac mini hack -- use the same DDC as the analog connector */ | ||
131 | struct i2c_adapter *analog_ddc_bus; | ||
132 | |||
130 | int save_sdvo_mult; | 133 | int save_sdvo_mult; |
131 | u16 save_active_outputs; | 134 | u16 save_active_outputs; |
132 | struct intel_sdvo_dtd save_input_dtd_1, save_input_dtd_2; | 135 | struct intel_sdvo_dtd save_input_dtd_1, save_input_dtd_2; |
@@ -1496,6 +1499,36 @@ intel_sdvo_multifunc_encoder(struct intel_output *intel_output) | |||
1496 | return (caps > 1); | 1499 | return (caps > 1); |
1497 | } | 1500 | } |
1498 | 1501 | ||
1502 | static struct drm_connector * | ||
1503 | intel_find_analog_connector(struct drm_device *dev) | ||
1504 | { | ||
1505 | struct drm_connector *connector; | ||
1506 | struct intel_output *intel_output; | ||
1507 | |||
1508 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
1509 | intel_output = to_intel_output(connector); | ||
1510 | if (intel_output->type == INTEL_OUTPUT_ANALOG) | ||
1511 | return connector; | ||
1512 | } | ||
1513 | return NULL; | ||
1514 | } | ||
1515 | |||
1516 | static int | ||
1517 | intel_analog_is_connected(struct drm_device *dev) | ||
1518 | { | ||
1519 | struct drm_connector *analog_connector; | ||
1520 | analog_connector = intel_find_analog_connector(dev); | ||
1521 | |||
1522 | if (!analog_connector) | ||
1523 | return false; | ||
1524 | |||
1525 | if (analog_connector->funcs->detect(analog_connector) == | ||
1526 | connector_status_disconnected) | ||
1527 | return false; | ||
1528 | |||
1529 | return true; | ||
1530 | } | ||
1531 | |||
1499 | enum drm_connector_status | 1532 | enum drm_connector_status |
1500 | intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response) | 1533 | intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response) |
1501 | { | 1534 | { |
@@ -1506,6 +1539,15 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response) | |||
1506 | 1539 | ||
1507 | edid = drm_get_edid(&intel_output->base, | 1540 | edid = drm_get_edid(&intel_output->base, |
1508 | intel_output->ddc_bus); | 1541 | intel_output->ddc_bus); |
1542 | |||
1543 | /* when there is no edid and no monitor is connected with VGA | ||
1544 | * port, try to use the CRT ddc to read the EDID for DVI-connector | ||
1545 | */ | ||
1546 | if (edid == NULL && | ||
1547 | sdvo_priv->analog_ddc_bus && | ||
1548 | !intel_analog_is_connected(intel_output->base.dev)) | ||
1549 | edid = drm_get_edid(&intel_output->base, | ||
1550 | sdvo_priv->analog_ddc_bus); | ||
1509 | if (edid != NULL) { | 1551 | if (edid != NULL) { |
1510 | /* Don't report the output as connected if it's a DVI-I | 1552 | /* Don't report the output as connected if it's a DVI-I |
1511 | * connector with a non-digital EDID coming out. | 1553 | * connector with a non-digital EDID coming out. |
@@ -1559,31 +1601,32 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect | |||
1559 | static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) | 1601 | static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) |
1560 | { | 1602 | { |
1561 | struct intel_output *intel_output = to_intel_output(connector); | 1603 | struct intel_output *intel_output = to_intel_output(connector); |
1604 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
1605 | int num_modes; | ||
1562 | 1606 | ||
1563 | /* set the bus switch and get the modes */ | 1607 | /* set the bus switch and get the modes */ |
1564 | intel_ddc_get_modes(intel_output); | 1608 | num_modes = intel_ddc_get_modes(intel_output); |
1565 | 1609 | ||
1566 | #if 0 | 1610 | /* |
1567 | struct drm_device *dev = encoder->dev; | 1611 | * Mac mini hack. On this device, the DVI-I connector shares one DDC |
1568 | struct drm_i915_private *dev_priv = dev->dev_private; | 1612 | * link between analog and digital outputs. So, if the regular SDVO |
1569 | /* Mac mini hack. On this device, I get DDC through the analog, which | 1613 | * DDC fails, check to see if the analog output is disconnected, in |
1570 | * load-detects as disconnected. I fail to DDC through the SDVO DDC, | 1614 | * which case we'll look there for the digital DDC data. |
1571 | * but it does load-detect as connected. So, just steal the DDC bits | ||
1572 | * from analog when we fail at finding it the right way. | ||
1573 | */ | 1615 | */ |
1574 | crt = xf86_config->output[0]; | 1616 | if (num_modes == 0 && |
1575 | intel_output = crt->driver_private; | 1617 | sdvo_priv->analog_ddc_bus && |
1576 | if (intel_output->type == I830_OUTPUT_ANALOG && | 1618 | !intel_analog_is_connected(intel_output->base.dev)) { |
1577 | crt->funcs->detect(crt) == XF86OutputStatusDisconnected) { | 1619 | struct i2c_adapter *digital_ddc_bus; |
1578 | I830I2CInit(pScrn, &intel_output->pDDCBus, GPIOA, "CRTDDC_A"); | 1620 | |
1579 | edid_mon = xf86OutputGetEDID(crt, intel_output->pDDCBus); | 1621 | /* Switch to the analog ddc bus and try that |
1580 | xf86DestroyI2CBusRec(intel_output->pDDCBus, true, true); | 1622 | */ |
1581 | } | 1623 | digital_ddc_bus = intel_output->ddc_bus; |
1582 | if (edid_mon) { | 1624 | intel_output->ddc_bus = sdvo_priv->analog_ddc_bus; |
1583 | xf86OutputSetEDID(output, edid_mon); | 1625 | |
1584 | modes = xf86OutputGetEDIDModes(output); | 1626 | (void) intel_ddc_get_modes(intel_output); |
1627 | |||
1628 | intel_output->ddc_bus = digital_ddc_bus; | ||
1585 | } | 1629 | } |
1586 | #endif | ||
1587 | } | 1630 | } |
1588 | 1631 | ||
1589 | /* | 1632 | /* |
@@ -1758,6 +1801,8 @@ static void intel_sdvo_destroy(struct drm_connector *connector) | |||
1758 | intel_i2c_destroy(intel_output->i2c_bus); | 1801 | intel_i2c_destroy(intel_output->i2c_bus); |
1759 | if (intel_output->ddc_bus) | 1802 | if (intel_output->ddc_bus) |
1760 | intel_i2c_destroy(intel_output->ddc_bus); | 1803 | intel_i2c_destroy(intel_output->ddc_bus); |
1804 | if (sdvo_priv->analog_ddc_bus) | ||
1805 | intel_i2c_destroy(sdvo_priv->analog_ddc_bus); | ||
1761 | 1806 | ||
1762 | if (sdvo_priv->sdvo_lvds_fixed_mode != NULL) | 1807 | if (sdvo_priv->sdvo_lvds_fixed_mode != NULL) |
1763 | drm_mode_destroy(connector->dev, | 1808 | drm_mode_destroy(connector->dev, |
@@ -2177,10 +2222,15 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) | |||
2177 | } | 2222 | } |
2178 | 2223 | ||
2179 | /* setup the DDC bus. */ | 2224 | /* setup the DDC bus. */ |
2180 | if (output_device == SDVOB) | 2225 | if (output_device == SDVOB) { |
2181 | intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS"); | 2226 | intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS"); |
2182 | else | 2227 | sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA, |
2228 | "SDVOB/VGA DDC BUS"); | ||
2229 | } else { | ||
2183 | intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS"); | 2230 | intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS"); |
2231 | sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA, | ||
2232 | "SDVOC/VGA DDC BUS"); | ||
2233 | } | ||
2184 | 2234 | ||
2185 | if (intel_output->ddc_bus == NULL) | 2235 | if (intel_output->ddc_bus == NULL) |
2186 | goto err_i2c; | 2236 | goto err_i2c; |
@@ -2248,6 +2298,8 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) | |||
2248 | return true; | 2298 | return true; |
2249 | 2299 | ||
2250 | err_i2c: | 2300 | err_i2c: |
2301 | if (sdvo_priv->analog_ddc_bus != NULL) | ||
2302 | intel_i2c_destroy(sdvo_priv->analog_ddc_bus); | ||
2251 | if (intel_output->ddc_bus != NULL) | 2303 | if (intel_output->ddc_bus != NULL) |
2252 | intel_i2c_destroy(intel_output->ddc_bus); | 2304 | intel_i2c_destroy(intel_output->ddc_bus); |
2253 | if (intel_output->i2c_bus != NULL) | 2305 | if (intel_output->i2c_bus != NULL) |