[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