[PATCH v2] drm/i915: Test patch for checking if edid change during suspend is fixed by those changes.

Stanislav Lisovskiy stanislav.lisovskiy at intel.com
Wed Jun 26 09:39:48 UTC 2019


Added edid checking to dp and hdmi edid setting functions, which
are called from detect hooks. The result currently is propagated
to calling layer using drm_connector->change_counter(proposed by Daniel Vetter).
drm_helper_hpd_irq_event and intel_encoder_hotplug are currently both
responsible for checking if this counter or connection status is changed.

v2: There are conflicting parts in drm and i915 which attempt
    to do the same job - drm_helper_hpd_irq_event attempts to
    check connector status changes and then call hotplug,
    just as i915_hotplug_work_func, which calls encoder->hotplug
    hook which in turn calls generic intel_encoder_hotplug function
    which attempts to probe if output has changed.
    Looks like both needs to be changed, so added edid checking
    also to intel_encoder_hotplug function which is called both
    for hdmi and dp.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105540
Signed-off-by: Stanislav Lisovskiy <stanislav.lisovskiy at intel.com>
---
 drivers/gpu/drm/drm_connector.c              |  1 +
 drivers/gpu/drm/drm_probe_helper.c           | 29 ++++++++++++++--
 drivers/gpu/drm/i915/display/intel_dp.c      | 35 ++++++++++++++++++--
 drivers/gpu/drm/i915/display/intel_hdmi.c    | 33 ++++++++++++++++--
 drivers/gpu/drm/i915/display/intel_hotplug.c | 20 ++++++++---
 include/drm/drm_connector.h                  |  2 ++
 6 files changed, 108 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 3ccdcf3dfcde..531983707d7f 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -245,6 +245,7 @@ int drm_connector_init(struct drm_device *dev,
 	INIT_LIST_HEAD(&connector->modes);
 	mutex_init(&connector->mutex);
 	connector->edid_blob_ptr = NULL;
+	connector->change_counter = 0;
 	connector->tile_blob_ptr = NULL;
 	connector->status = connector_status_unknown;
 	connector->display_info.panel_orientation =
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index ef2c468205a2..365c11d6f212 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -776,6 +776,7 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev)
 	struct drm_connector_list_iter conn_iter;
 	enum drm_connector_status old_status;
 	bool changed = false;
+	uint64_t old_change_counter;
 
 	if (!dev->mode_config.poll_enabled)
 		return false;
@@ -789,20 +790,44 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev)
 
 		old_status = connector->status;
 
+		old_change_counter = connector->change_counter;
+
+		DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Old change counter %d\n", connector->base.id,
+			      connector->name,
+			      old_change_counter);
+
 		connector->status = drm_helper_probe_detect(connector, NULL, false);
 		DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n",
 			      connector->base.id,
 			      connector->name,
 			      drm_get_connector_status_name(old_status),
 			      drm_get_connector_status_name(connector->status));
-		if (old_status != connector->status)
+
+		DRM_DEBUG_KMS("[CONNECTOR:%d:%s] New change counter %d\n",
+			      connector->base.id,
+			      connector->name,
+			      connector->change_counter);
+
+		if (old_status != connector->status) {
 			changed = true;
+		}
+
+		/* Check changing of edid when a connector status still remains
+		 * as "connector_status_connected".
+		 */
+		if (connector->status == connector_status_connected &&
+		    old_status == connector_status_connected &&
+		    old_change_counter != connector->change_counter) {
+			changed = true;
+		}
 	}
 	drm_connector_list_iter_end(&conn_iter);
 	mutex_unlock(&dev->mode_config.mutex);
 
-	if (changed)
+	if (changed) {
 		drm_kms_helper_hotplug_event(dev);
+		DRM_DEBUG_KMS("Sent hotplug event\n");
+	}
 
 	return changed;
 }
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 4336df46fe78..dd460a68549d 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -5510,11 +5510,42 @@ static void
 intel_dp_set_edid(struct intel_dp *intel_dp)
 {
 	struct intel_connector *intel_connector = intel_dp->attached_connector;
+	struct drm_connector *connector = &intel_connector->base;
 	struct edid *edid;
+	struct edid *old_edid;
+	bool has_old_edid = false;
+	bool has_edid = false;
+	bool edid_changed = false;
 
-	intel_dp_unset_edid(intel_dp);
 	edid = intel_dp_get_edid(intel_dp);
-	intel_connector->detect_edid = edid;
+	old_edid = intel_connector->detect_edid;
+
+	has_old_edid = old_edid != NULL;
+	has_edid = edid != NULL;
+
+	if (has_old_edid != has_edid)
+		edid_changed = true;
+	else if (old_edid && edid) {
+		int old_len, new_len;
+		old_len = EDID_LENGTH * (1 + old_edid->extensions);
+		new_len = EDID_LENGTH * (1 + edid->extensions);
+
+		if (old_len != new_len)
+			edid_changed = true;
+		else if (memcmp(old_edid, edid, old_len))
+			edid_changed = true;
+	}
+	if (edid_changed) {
+		DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Edid was changed! Updating blob property.\n",
+		    connector->base.id, connector->name);
+
+		connector->change_counter += 1;
+		DRM_DEBUG_KMS("Updating change counter to %llu\n", connector->change_counter);
+
+		intel_dp_unset_edid(intel_dp);
+		intel_connector->detect_edid = edid;
+		intel_connector_update_modes(&intel_connector->base, edid);
+	}
 
 	intel_dp->has_audio = drm_detect_monitor_audio(edid);
 	drm_dp_cec_set_edid(&intel_dp->aux, edid);
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 0ebec69bbbfc..fe518c318ecb 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -2503,15 +2503,19 @@ intel_hdmi_set_edid(struct drm_connector *connector)
 	struct drm_i915_private *dev_priv = to_i915(connector->dev);
 	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
 	intel_wakeref_t wakeref;
-	struct edid *edid;
+	struct edid *edid, *old_edid;
 	bool connected = false;
 	struct i2c_adapter *i2c;
+	bool has_edid = false;
+	bool has_old_edid = false;
+	bool edid_changed = false;
 
 	wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
 
 	i2c = intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus);
 
 	edid = drm_get_edid(connector, i2c);
+	has_edid = edid != NULL;
 
 	if (!edid && !intel_gmbus_is_forced_bit(i2c)) {
 		DRM_DEBUG_KMS("HDMI GMBUS EDID read failed, retry using GPIO bit-banging\n");
@@ -2524,11 +2528,34 @@ intel_hdmi_set_edid(struct drm_connector *connector)
 
 	intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref);
 
-	to_intel_connector(connector)->detect_edid = edid;
+	old_edid = to_intel_connector(connector)->detect_edid;
+	has_old_edid = old_edid != NULL;
+
+	if (has_old_edid != has_edid)
+		edid_changed = true;
+	else if (old_edid && edid) {
+		int old_len, new_len;
+		old_len = EDID_LENGTH * (1 + old_edid->extensions);
+		new_len = EDID_LENGTH * (1 + edid->extensions);
+
+		if (old_len != new_len)
+			edid_changed = true;
+		else if (memcmp(old_edid, edid, old_len))
+			edid_changed = true;
+	}
+	if (edid_changed) {
+		intel_connector_update_modes(connector, edid);
+		DRM_DEBUG_KMS("Updating change counter to %llu\n", connector->change_counter);
+		connector->change_counter += 1;
+
+		DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Edid was changed! Updating blob property.\n",
+		    connector->base.id, connector->name);
+		to_intel_connector(connector)->detect_edid = edid;
+	}
+
 	if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
 		intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
 		intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
-
 		connected = true;
 	}
 
diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c b/drivers/gpu/drm/i915/display/intel_hotplug.c
index ea3de4acc850..b976431f1ce5 100644
--- a/drivers/gpu/drm/i915/display/intel_hotplug.c
+++ b/drivers/gpu/drm/i915/display/intel_hotplug.c
@@ -271,23 +271,33 @@ bool intel_encoder_hotplug(struct intel_encoder *encoder,
 {
 	struct drm_device *dev = connector->base.dev;
 	enum drm_connector_status old_status;
+	uint64_t old_change_counter;
+	bool ret = false;
 
 	WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
 	old_status = connector->base.status;
 
+	old_change_counter = connector->base.change_counter;
+
 	connector->base.status =
 		drm_helper_probe_detect(&connector->base, NULL, false);
 
-	if (old_status == connector->base.status)
-		return false;
+	if (old_change_counter != connector->base.change_counter)
+		ret = true;
 
-	DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n",
+	if (old_status != connector->base.status)
+		ret = true;
+
+	if (ret) {
+		DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s(change counter %llu)\n",
 		      connector->base.base.id,
 		      connector->base.name,
 		      drm_get_connector_status_name(old_status),
-		      drm_get_connector_status_name(connector->base.status));
+		      drm_get_connector_status_name(connector->base.status),
+		      connector->base.change_counter);
+	}
 
-	return true;
+	return ret;
 }
 
 static bool intel_encoder_has_hpd_pulse(struct intel_encoder *encoder)
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index c6f8486d8b8f..feaa4eb673f6 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1155,6 +1155,8 @@ struct drm_connector {
 	/** @override_edid: has the EDID been overwritten through debugfs for testing? */
 	bool override_edid;
 
+	uint64_t change_counter;
+
 #define DRM_CONNECTOR_MAX_ENCODER 3
 	/**
 	 * @encoder_ids: Valid encoders for this connector. Please only use
-- 
2.17.1



More information about the Intel-gfx-trybot mailing list