aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorSonika Jindal <sonika.jindal@intel.com>2015-10-05 07:13:15 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2015-10-06 04:52:22 -0400
commit0b5e88dc25ee6c9040c0355e6e025dcbc9c8de92 (patch)
tree58e1d2cf52f1ca2e64c51f8eb1f00d05128b8e21 /drivers/gpu
parent7b9748cb513a6bef4af87b79f0da3ff7e8b56cd8 (diff)
drm/i915: Add hot_plug hook for hdmi encoder
This patch adds a separate probe function for HDMI EDID read over DDC channel. This function has been registered as a .hot_plug handler for HDMI encoder. The current implementation of hdmi_detect() function re-sets the cached HDMI edid (in connector->detect_edid) in every detect call.This function gets called many times, sometimes directly from userspace probes, forcing drivers to read EDID every detect function call.This causes several problems like: 1. Race conditions in multiple hot_plug / unplug cases, between interrupts bottom halves and userspace detections. 2. Many Un-necessary EDID reads for single hotplug/unplug 3. HDMI complaince failures which expects only one EDID read per hotplug This function will be serving the purpose of really reading the EDID by really probing the DDC channel, and updating the cached EDID. The plan is to: 1. i915 IRQ handler bottom half function already calls intel_encoder->hotplug() function. Adding This probe function which will read the EDID only in case of a hotplug / unplug. 2. During init_connector this probe will be called to read the edid 3. Reuse the cached EDID in hdmi_detect() function. The "< gen7" check is there because this was tested only for >=gen7 platforms. For older platforms the hotplug/reading edid path remains same. v2: Calling set_edid instead of hdmi_probe during init. Also, for platforms having DDI, intel_encoder for DP and HDMI is same (taken from intel_dig_port), so for DP also, hot_plug function gets called which is not intended here. So, check for HDMI in intel_hdmi_probe Rely on HPD for updating edid only for platforms gen > 8 and also for VLV. v3: Dropping the gen < 8 || !VLV check. Now all platforms should rely on hotplug or init for updating the edid.(Daniel) Also, calling hdmi_probe in init instead of set_edid v4: Renaming intel_hdmi_probe to intel_hdmi_hot_plug. Also calling this hotplug handler from intel_hpd_init to take care of init resume scenarios. v5: Moved the call to encoder hotplug during init to separate patch(Daniel) Signed-off-by: Shashank Sharma <shashank.sharma@intel.com> Signed-off-by: Sonika Jindal <sonika.jindal@intel.com> [danvet: Mark intel_hdmi_hot_plug as static.] Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c54
1 files changed, 43 insertions, 11 deletions
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 3b28ed3237d3..03d85909c6ab 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -1369,18 +1369,16 @@ intel_hdmi_set_edid(struct drm_connector *connector, bool force)
1369 return connected; 1369 return connected;
1370} 1370}
1371 1371
1372static enum drm_connector_status 1372static void intel_hdmi_hot_plug(struct intel_encoder *intel_encoder)
1373intel_hdmi_detect(struct drm_connector *connector, bool force)
1374{ 1373{
1375 enum drm_connector_status status; 1374 struct intel_hdmi *intel_hdmi =
1376 struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); 1375 enc_to_intel_hdmi(&intel_encoder->base);
1377 struct drm_i915_private *dev_priv = to_i915(connector->dev); 1376 struct intel_connector *intel_connector =
1377 intel_hdmi->attached_connector;
1378 struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev);
1378 bool live_status = false; 1379 bool live_status = false;
1379 unsigned int retry = 3; 1380 unsigned int retry = 3;
1380 1381
1381 DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
1382 connector->base.id, connector->name);
1383
1384 while (!live_status && --retry) { 1382 while (!live_status && --retry) {
1385 live_status = intel_digital_port_connected(dev_priv, 1383 live_status = intel_digital_port_connected(dev_priv,
1386 hdmi_to_dig_port(intel_hdmi)); 1384 hdmi_to_dig_port(intel_hdmi));
@@ -1390,15 +1388,48 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
1390 if (!live_status) 1388 if (!live_status)
1391 DRM_DEBUG_KMS("Live status not up!"); 1389 DRM_DEBUG_KMS("Live status not up!");
1392 1390
1393 intel_hdmi_unset_edid(connector); 1391 /*
1392 * We are here, means there is a hotplug or a force
1393 * detection. Clear the cached EDID and probe the
1394 * DDC bus to check the current status of HDMI.
1395 */
1396 intel_hdmi_unset_edid(&intel_connector->base);
1397 if (intel_hdmi_set_edid(&intel_connector->base, live_status))
1398 DRM_DEBUG_DRIVER("DDC probe: got EDID\n");
1399 else
1400 DRM_DEBUG_DRIVER("DDC probe: no EDID\n");
1401}
1394 1402
1395 if (intel_hdmi_set_edid(connector, live_status)) { 1403static enum drm_connector_status
1404intel_hdmi_detect(struct drm_connector *connector, bool force)
1405{
1406 enum drm_connector_status status;
1407 struct intel_connector *intel_connector =
1408 to_intel_connector(connector);
1409
1410 DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
1411 connector->base.id, connector->name);
1412
1413 /*
1414 * There are many userspace calls which probe EDID from
1415 * detect path. In case of multiple hotplug/unplug, these
1416 * can cause race conditions while probing EDID. Also its
1417 * waste of CPU cycles to read the EDID again and again
1418 * unless there is a real hotplug.
1419 * So, rely on hotplugs and init to read edid.
1420 * Check connector status based on availability of cached EDID.
1421 */
1422
1423 if (intel_connector->detect_edid) {
1396 struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); 1424 struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
1397 1425
1398 hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI; 1426 hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
1399 status = connector_status_connected; 1427 status = connector_status_connected;
1400 } else 1428 DRM_DEBUG_DRIVER("hdmi status = connected\n");
1429 } else {
1401 status = connector_status_disconnected; 1430 status = connector_status_disconnected;
1431 DRM_DEBUG_DRIVER("hdmi status = disconnected\n");
1432 }
1402 1433
1403 return status; 1434 return status;
1404} 1435}
@@ -2114,6 +2145,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
2114 intel_connector->unregister = intel_connector_unregister; 2145 intel_connector->unregister = intel_connector_unregister;
2115 2146
2116 intel_hdmi_add_properties(intel_hdmi, connector); 2147 intel_hdmi_add_properties(intel_hdmi, connector);
2148 intel_encoder->hot_plug = intel_hdmi_hot_plug;
2117 2149
2118 intel_connector_attach_encoder(intel_connector, intel_encoder); 2150 intel_connector_attach_encoder(intel_connector, intel_encoder);
2119 drm_connector_register(connector); 2151 drm_connector_register(connector);