Skip to content

Commit 237ed86

Browse files
Sonika Jindaldanvet
authored andcommitted
drm/i915: Check live status before reading edid
The Bspec is very clear that Live status must be checked about before trying to read EDID over DDC channel. This patch makes sure that HDMI EDID is read only when live status is up. The live status doesn't seem to perform very consistent across various platforms when tested with different monitors. The reason behind that is some monitors are late to provide right voltage to set live_status up. So, after getting the interrupt, for a small duration, live status reg fluctuates, and then settles down showing the correct staus. This is explained here in, in a rough way: HPD line ________________ |\ T1 = Monitor Hotplug causing IRQ | \______________________________________ | | | | | | T2 = Live status is stable | | _____________________________________ | | /| Live status _____________|_|/ | | | | | | | | | | T0 T1 T2 (Between T1 and T2 Live status fluctuates or can be even low, depending on the monitor) After several experiments, we have concluded that a max delay of 30ms is enough to allow the live status to settle down with most of the monitors. This total delay of 30ms has been split into a resolution of 3 retries of 10ms each, for the better cases. This delay is kept at 30ms, keeping in consideration that, HDCP compliance expect the HPD handler to respond a plug out in 100ms, by disabling port. v2: Adding checks for VLV/CHV as well. Reusing old ibx and g4x functions to check digital port status. Adding a separate function to get bxt live status (Daniel) v3: Using intel_encoder->hpd_pin to check the live status (Siva) Moving the live status read to intel_hdmi_probe and passing parameter to read/not to read the edid. (me) v4: * Added live status check for all platforms using intel_digital_port_connected. * Rebased on top of Jani's DP cleanup series * Some monitors take time in setting the live status. So retry for few times if this is a connect HPD v5: Removed extra "drm/i915" from commit message. Adding Shashank's sob which was missed. v6: Drop the (!detect_edid && !live_status check) check because for DDI ports which are enumerated as hdmi as well as DP, we don't have a mechanism to differentiate between DP and hdmi inside the encoder's hot_plug. This leads to call to the hdmi's hot_plug hook for DP as well as hdmi which leads to issues during unplug because of the above check. v7: Make intel_digital_port_connected global in this patch, some reformatting of while loop, adding a print when live status is not up. (Rodrigo) v8: Rebase it on nightly which involved skipping the hot_plug hook for now and letting the live_status check happen in detect until the hpd handling part is finalized (Daniel) Signed-off-by: Shashank Sharma <shashank.sharma@intel.com> Signed-off-by: Sonika Jindal <sonika.jindal@intel.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
1 parent d2e08c0 commit 237ed86

File tree

3 files changed

+24
-8
lines changed

3 files changed

+24
-8
lines changed

drivers/gpu/drm/i915/intel_dp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4672,7 +4672,7 @@ static bool bxt_digital_port_connected(struct drm_i915_private *dev_priv,
46724672
*
46734673
* Return %true if @port is connected, %false otherwise.
46744674
*/
4675-
static bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
4675+
bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
46764676
struct intel_digital_port *port)
46774677
{
46784678
if (HAS_PCH_IBX(dev_priv))

drivers/gpu/drm/i915/intel_drv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,6 +1218,8 @@ void intel_edp_drrs_disable(struct intel_dp *intel_dp);
12181218
void intel_edp_drrs_invalidate(struct drm_device *dev,
12191219
unsigned frontbuffer_bits);
12201220
void intel_edp_drrs_flush(struct drm_device *dev, unsigned frontbuffer_bits);
1221+
bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
1222+
struct intel_digital_port *port);
12211223
void hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config);
12221224

12231225
/* intel_dp_mst.c */

drivers/gpu/drm/i915/intel_hdmi.c

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,22 +1329,23 @@ intel_hdmi_unset_edid(struct drm_connector *connector)
13291329
}
13301330

13311331
static bool
1332-
intel_hdmi_set_edid(struct drm_connector *connector)
1332+
intel_hdmi_set_edid(struct drm_connector *connector, bool force)
13331333
{
13341334
struct drm_i915_private *dev_priv = to_i915(connector->dev);
13351335
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
13361336
struct intel_encoder *intel_encoder =
13371337
&hdmi_to_dig_port(intel_hdmi)->base;
13381338
enum intel_display_power_domain power_domain;
1339-
struct edid *edid;
1339+
struct edid *edid = NULL;
13401340
bool connected = false;
13411341

13421342
power_domain = intel_display_port_power_domain(intel_encoder);
13431343
intel_display_power_get(dev_priv, power_domain);
13441344

1345-
edid = drm_get_edid(connector,
1346-
intel_gmbus_get_adapter(dev_priv,
1347-
intel_hdmi->ddc_bus));
1345+
if (force)
1346+
edid = drm_get_edid(connector,
1347+
intel_gmbus_get_adapter(dev_priv,
1348+
intel_hdmi->ddc_bus));
13481349

13491350
intel_display_power_put(dev_priv, power_domain);
13501351

@@ -1372,13 +1373,26 @@ static enum drm_connector_status
13721373
intel_hdmi_detect(struct drm_connector *connector, bool force)
13731374
{
13741375
enum drm_connector_status status;
1376+
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
1377+
struct drm_i915_private *dev_priv = to_i915(connector->dev);
1378+
bool live_status = false;
1379+
unsigned int retry = 3;
13751380

13761381
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
13771382
connector->base.id, connector->name);
13781383

1384+
while (!live_status && --retry) {
1385+
live_status = intel_digital_port_connected(dev_priv,
1386+
hdmi_to_dig_port(intel_hdmi));
1387+
mdelay(10);
1388+
}
1389+
1390+
if (!live_status)
1391+
DRM_DEBUG_KMS("Live status not up!");
1392+
13791393
intel_hdmi_unset_edid(connector);
13801394

1381-
if (intel_hdmi_set_edid(connector)) {
1395+
if (intel_hdmi_set_edid(connector, live_status)) {
13821396
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
13831397

13841398
hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
@@ -1402,7 +1416,7 @@ intel_hdmi_force(struct drm_connector *connector)
14021416
if (connector->status != connector_status_connected)
14031417
return;
14041418

1405-
intel_hdmi_set_edid(connector);
1419+
intel_hdmi_set_edid(connector, true);
14061420
hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
14071421
}
14081422

0 commit comments

Comments
 (0)