[PATCH 14/20] drm/amd/display: Poll analog connectors
Timur Kristóf
timur.kristof at gmail.com
Wed Jul 23 15:58:07 UTC 2025
VGA connectors don't support any hotplug detection, so the kernel
needs to periodically poll them to see if a display is connected.
DVI-I connectors have hotplug detection for digital signals, and
some analog DVI cables pull up that pin to work with that.
However, in general not all DVI cables do this so we can't rely on
this feature, therefore we need to poll DVI-I connectors as well.
Signed-off-by: Timur Kristóf <timur.kristof at gmail.com>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 60 ++++++++++++++++++-
.../drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c | 8 +++
2 files changed, 66 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index c347b232ae06..13823469fa7c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3736,7 +3736,9 @@ void amdgpu_dm_update_connector_after_detect(
drm_dbg_kms(dev, "DCHPD: connector_id=%d: Old sink=%p New sink=%p\n",
aconnector->connector_id, aconnector->dc_sink, sink);
- guard(mutex)(&dev->mode_config.mutex);
+ /* When polling, DRM has already locked the mutex for us. */
+ if (!drm_kms_helper_is_poll_worker())
+ mutex_lock(&dev->mode_config.mutex);
/*
* 1. Update status of the drm connector
@@ -3799,6 +3801,10 @@ void amdgpu_dm_update_connector_after_detect(
}
update_subconnector_property(aconnector);
+
+ /* When polling, the mutex will be unlocked for us by DRM. */
+ if (!drm_kms_helper_is_poll_worker())
+ mutex_unlock(&dev->mode_config.mutex);
}
static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector)
@@ -7061,10 +7067,48 @@ create_stream_for_sink(struct drm_connector *connector,
return stream;
}
+static enum drm_connector_status
+amdgpu_dm_connector_poll(struct amdgpu_dm_connector *aconnector, bool force)
+{
+ struct drm_connector *connector = &aconnector->base;
+ struct drm_device *dev = connector->dev;
+ struct amdgpu_device *adev = drm_to_adev(dev);
+ struct dc_link *link = aconnector->dc_link;
+ enum dc_connection_type conn_type = dc_connection_none;
+ enum drm_connector_status status = connector_status_disconnected;
+
+ mutex_lock(&aconnector->hpd_lock);
+
+ if (dc_link_detect_connection_type(aconnector->dc_link, &conn_type) &&
+ conn_type != dc_connection_none) {
+ mutex_lock(&adev->dm.dc_lock);
+
+ if (dc_link_detect(link, DETECT_REASON_HPD))
+ status = connector_status_connected;
+
+ mutex_unlock(&adev->dm.dc_lock);
+ }
+
+ if (status == connector_status_disconnected) {
+ if (link->local_sink)
+ dc_sink_release(link->local_sink);
+
+ link->local_sink = NULL;
+ link->dpcd_sink_count = 0;
+ link->type = dc_connection_none;
+ }
+
+ amdgpu_dm_update_connector_after_detect(aconnector);
+
+ mutex_unlock(&aconnector->hpd_lock);
+ return status;
+}
+
static enum drm_connector_status
amdgpu_dm_connector_detect(struct drm_connector *connector, bool force)
{
bool connected;
+ bool analog_connector;
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
/*
@@ -7083,6 +7127,15 @@ amdgpu_dm_connector_detect(struct drm_connector *connector, bool force)
update_subconnector_property(aconnector);
+ analog_connector =
+ aconnector->dc_link->link_id.id == CONNECTOR_ID_DUAL_LINK_DVII ||
+ aconnector->dc_link->link_id.id == CONNECTOR_ID_SINGLE_LINK_DVII ||
+ aconnector->dc_link->link_id.id == CONNECTOR_ID_VGA;
+
+ if (analog_connector && drm_kms_helper_is_poll_worker() &&
+ (!connected || aconnector->dc_sink->edid_caps.analog))
+ return amdgpu_dm_connector_poll(aconnector, force);
+
return (connected ? connector_status_connected :
connector_status_disconnected);
}
@@ -8442,9 +8495,12 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
link->link_enc->features.dp_ycbcr420_supported ? true : false;
break;
case DRM_MODE_CONNECTOR_DVID:
+ aconnector->base.polled = DRM_CONNECTOR_POLL_HPD;
+ break;
case DRM_MODE_CONNECTOR_DVII:
case DRM_MODE_CONNECTOR_VGA:
- aconnector->base.polled = DRM_CONNECTOR_POLL_HPD;
+ aconnector->base.polled =
+ DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
break;
default:
break;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
index b61e210f6246..327a3965fda1 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
@@ -892,6 +892,7 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev)
struct drm_connector_list_iter iter;
int irq_type;
int i;
+ bool need_polling = false;
/* First, clear all hpd and hpdrx interrupts */
for (i = DC_IRQ_SOURCE_HPD1; i <= DC_IRQ_SOURCE_HPD6RX; i++) {
@@ -905,6 +906,8 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev)
struct amdgpu_dm_connector *amdgpu_dm_connector;
const struct dc_link *dc_link;
+ need_polling |= connector->polled != DRM_CONNECTOR_POLL_HPD;
+
if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
continue;
@@ -946,6 +949,11 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev)
}
}
drm_connector_list_iter_end(&iter);
+
+ if (need_polling) {
+ drm_kms_helper_poll_init(dev);
+ drm_kms_helper_poll_enable(dev);
+ }
}
/**
--
2.50.1
More information about the amd-gfx
mailing list