@@ -1867,6 +1867,7 @@ int drm_connector_update_edid_property(struct drm_connector *connector,
struct drm_device *dev = connector->dev;
size_t size = 0;
int ret;
+ const struct edid *old_edid;
/* ignore requests to set edid when overridden */
if (connector->override_edid)
@@ -1888,6 +1889,20 @@ int drm_connector_update_edid_property(struct drm_connector *connector,
else
drm_reset_display_info(connector);
+ if (connector->edid_blob_ptr) {
+ old_edid = (const struct edid *)connector->edid_blob_ptr->data;
+ if (old_edid) {
+ if (!drm_edid_are_equal(edid, old_edid)) {
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Edid was changed.\n",
+ connector->base.id, connector->name);
+
+ connector->epoch_counter += 1;
+ DRM_DEBUG_KMS("Updating change counter to %llu\n",
+ connector->epoch_counter);
+ }
+ }
+ }
+
drm_object_property_set_value(&connector->base,
dev->mode_config.non_desktop_property,
connector->display_info.non_desktop);
@@ -1369,7 +1369,7 @@ static bool drm_edid_is_zero(const u8 *in_edid, int length)
* This helper can be used during probing to determine if
* edid had changed.
*/
-bool drm_edid_are_equal(struct edid *edid1, struct edid *edid2)
+bool drm_edid_are_equal(const struct edid *edid1, const struct edid *edid2)
{
int edid1_len, edid2_len;
bool edid1_present = edid1 != NULL;
@@ -1803,6 +1803,9 @@ struct edid *drm_get_edid(struct drm_connector *connector,
edid = drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter);
if (edid)
drm_get_displayid(connector, edid);
+
+ drm_connector_update_edid_property(connector, edid);
+
return edid;
}
EXPORT_SYMBOL(drm_get_edid);
@@ -813,7 +813,7 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev)
changed = true;
}
- /* Check changing of edid when a connector status still remains
+ /* Check changing of epoch counter when a connector status still remains
* as "connector_status_connected".
*/
if (connector->status == connector_status_connected &&
@@ -280,23 +280,34 @@ intel_encoder_hotplug(struct intel_encoder *encoder,
{
struct drm_device *dev = connector->base.dev;
enum drm_connector_status old_status;
+ u64 old_epoch_counter;
+ bool ret = false;
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
old_status = connector->base.status;
+ old_epoch_counter = connector->base.epoch_counter;
+
connector->base.status =
drm_helper_probe_detect(&connector->base, NULL, false);
- if (old_status == connector->base.status)
- return INTEL_HOTPLUG_UNCHANGED;
+ if (old_status != connector->base.status)
+ ret = true;
+
+ if (old_epoch_counter != connector->base.epoch_counter)
+ ret = true;
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n",
+ 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.epoch_counter);
+ return INTEL_HOTPLUG_CHANGED;
+ }
- return INTEL_HOTPLUG_CHANGED;
+ return INTEL_HOTPLUG_UNCHANGED;
}
static bool intel_encoder_has_hpd_pulse(struct intel_encoder *encoder)
@@ -361,7 +361,7 @@ drm_load_edid_firmware(struct drm_connector *connector)
* This helper can be used during probing to determine if
* edid had changed.
*/
-bool drm_edid_are_equal(struct edid *edid1, struct edid *edid2);
+bool drm_edid_are_equal(const struct edid *edid1, const struct edid *edid2);
int
drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame,
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. 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. v2: Renamed change counter to epoch counter. Fixed type name. v3: Fixed rebase conflict v4: Remove duplicate drm_edid_equal checks from hdmi and dp, lets use only once edid property is getting updated and increment epoch counter from there. Also lets now call drm_connector_update_edid_property right after we get edid always to make sure there is a unified way to handle edid change, without having to change tons of source code as currently drm_connector_update_edid_property is called only in certain cases like reprobing and not right after edid is actually updated. v5: Fixed const modifiers, removed blank line Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105540 Signed-off-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> --- drivers/gpu/drm/drm_connector.c | 15 ++++++++++++++ drivers/gpu/drm/drm_edid.c | 5 ++++- drivers/gpu/drm/drm_probe_helper.c | 2 +- drivers/gpu/drm/i915/display/intel_hotplug.c | 21 +++++++++++++++----- include/drm/drm_edid.h | 2 +- 5 files changed, 37 insertions(+), 8 deletions(-)