Skip to content

Commit c4f3f11

Browse files
Timur Kristófalexdeucher
authored andcommitted
drm/amd/display: Poll analog connectors (v3)
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. v2: Call drm_kms_helper_poll_fini in amdgpu_dm_hpd_fini. Disable/enable polling on suspend/resume. Don't call full link detection when already connected. v3: Encounter CLANG build failure. Remove unused variable: drivers/gpu/drm/amd/amdgpu/../display/amdgpu_dm/amdgpu_dm_irq.c:980:7: error: variable 'use_polling' set but not used [-Werror,-Wunused-but- set-variable] 980 | bool use_polling = false; Signed-off-by: Timur Kristóf <timur.kristof@gmail.com> Signed-off-by: Wayne Lin <wayne.lin@amd.com> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
1 parent 8223a60 commit c4f3f11

2 files changed

Lines changed: 88 additions & 2 deletions

File tree

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3853,7 +3853,9 @@ void amdgpu_dm_update_connector_after_detect(
38533853
drm_dbg_kms(dev, "DCHPD: connector_id=%d: Old sink=%p New sink=%p\n",
38543854
aconnector->connector_id, aconnector->dc_sink, sink);
38553855

3856-
guard(mutex)(&dev->mode_config.mutex);
3856+
/* When polling, DRM has already locked the mutex for us. */
3857+
if (!drm_kms_helper_is_poll_worker())
3858+
mutex_lock(&dev->mode_config.mutex);
38573859

38583860
/*
38593861
* 1. Update status of the drm connector
@@ -3916,6 +3918,10 @@ void amdgpu_dm_update_connector_after_detect(
39163918
}
39173919

39183920
update_subconnector_property(aconnector);
3921+
3922+
/* When polling, the mutex will be unlocked for us by DRM. */
3923+
if (!drm_kms_helper_is_poll_worker())
3924+
mutex_unlock(&dev->mode_config.mutex);
39193925
}
39203926

39213927
static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector)
@@ -7226,12 +7232,63 @@ create_stream_for_sink(struct drm_connector *connector,
72267232
return stream;
72277233
}
72287234

7235+
/**
7236+
* amdgpu_dm_connector_poll() - Poll a connector to see if it's connected to a display
7237+
*
7238+
* Used for connectors that don't support HPD (hotplug detection)
7239+
* to periodically checked whether the connector is connected to a display.
7240+
*/
7241+
static enum drm_connector_status
7242+
amdgpu_dm_connector_poll(struct amdgpu_dm_connector *aconnector, bool force)
7243+
{
7244+
struct drm_connector *connector = &aconnector->base;
7245+
struct drm_device *dev = connector->dev;
7246+
struct amdgpu_device *adev = drm_to_adev(dev);
7247+
struct dc_link *link = aconnector->dc_link;
7248+
enum dc_connection_type conn_type = dc_connection_none;
7249+
enum drm_connector_status status = connector_status_disconnected;
7250+
7251+
mutex_lock(&aconnector->hpd_lock);
7252+
7253+
if (dc_link_detect_connection_type(aconnector->dc_link, &conn_type) &&
7254+
conn_type != dc_connection_none) {
7255+
mutex_lock(&adev->dm.dc_lock);
7256+
7257+
/* Only call full link detection when a sink isn't created yet,
7258+
* ie. just when the display is plugged in, otherwise we risk flickering.
7259+
*/
7260+
if (link->local_sink ||
7261+
dc_link_detect(link, DETECT_REASON_HPD))
7262+
status = connector_status_connected;
7263+
7264+
mutex_unlock(&adev->dm.dc_lock);
7265+
}
7266+
7267+
if (connector->status != status) {
7268+
if (status == connector_status_disconnected) {
7269+
if (link->local_sink)
7270+
dc_sink_release(link->local_sink);
7271+
7272+
link->local_sink = NULL;
7273+
link->dpcd_sink_count = 0;
7274+
link->type = dc_connection_none;
7275+
}
7276+
7277+
amdgpu_dm_update_connector_after_detect(aconnector);
7278+
}
7279+
7280+
mutex_unlock(&aconnector->hpd_lock);
7281+
return status;
7282+
}
7283+
72297284
/**
72307285
* amdgpu_dm_connector_detect() - Detect whether a DRM connector is connected to a display
72317286
*
72327287
* A connector is considered connected when it has a sink that is not NULL.
72337288
* For connectors that support HPD (hotplug detection), the connection is
72347289
* handled in the HPD interrupt.
7290+
* For connectors that may not support HPD, such as analog connectors,
7291+
* DRM will call this function repeatedly to poll them.
72357292
*
72367293
* Notes:
72377294
* 1. This interface is NOT called in context of HPD irq.
@@ -7251,6 +7308,14 @@ amdgpu_dm_connector_detect(struct drm_connector *connector, bool force)
72517308
else if (aconnector->base.force == DRM_FORCE_OFF)
72527309
return connector_status_disconnected;
72537310

7311+
/* Poll analog connectors and only when either
7312+
* disconnected or connected to an analog display.
7313+
*/
7314+
if (drm_kms_helper_is_poll_worker() &&
7315+
dc_connector_supports_analog(aconnector->dc_link->link_id.id) &&
7316+
(!aconnector->dc_sink || aconnector->dc_sink->edid_caps.analog))
7317+
return amdgpu_dm_connector_poll(aconnector, force);
7318+
72547319
return (aconnector->dc_sink ? connector_status_connected :
72557320
connector_status_disconnected);
72567321
}
@@ -8675,9 +8740,13 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
86758740
link->link_enc->features.dp_ycbcr420_supported ? true : false;
86768741
break;
86778742
case DRM_MODE_CONNECTOR_DVID:
8678-
case DRM_MODE_CONNECTOR_DVII:
86798743
aconnector->base.polled = DRM_CONNECTOR_POLL_HPD;
86808744
break;
8745+
case DRM_MODE_CONNECTOR_DVII:
8746+
case DRM_MODE_CONNECTOR_VGA:
8747+
aconnector->base.polled =
8748+
DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
8749+
break;
86818750
default:
86828751
break;
86838752
}

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,7 @@ void amdgpu_dm_irq_fini(struct amdgpu_device *adev)
476476

477477
void amdgpu_dm_irq_suspend(struct amdgpu_device *adev)
478478
{
479+
struct drm_device *dev = adev_to_drm(adev);
479480
int src;
480481
struct list_head *hnd_list_h;
481482
struct list_head *hnd_list_l;
@@ -512,6 +513,9 @@ void amdgpu_dm_irq_suspend(struct amdgpu_device *adev)
512513
}
513514

514515
DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
516+
517+
if (dev->mode_config.poll_enabled)
518+
drm_kms_helper_poll_disable(dev);
515519
}
516520

517521
void amdgpu_dm_irq_resume_early(struct amdgpu_device *adev)
@@ -537,6 +541,7 @@ void amdgpu_dm_irq_resume_early(struct amdgpu_device *adev)
537541

538542
void amdgpu_dm_irq_resume_late(struct amdgpu_device *adev)
539543
{
544+
struct drm_device *dev = adev_to_drm(adev);
540545
int src;
541546
struct list_head *hnd_list_h, *hnd_list_l;
542547
unsigned long irq_table_flags;
@@ -557,6 +562,9 @@ void amdgpu_dm_irq_resume_late(struct amdgpu_device *adev)
557562
}
558563

559564
DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
565+
566+
if (dev->mode_config.poll_enabled)
567+
drm_kms_helper_poll_enable(dev);
560568
}
561569

562570
/*
@@ -893,6 +901,7 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev)
893901
struct drm_connector_list_iter iter;
894902
int irq_type;
895903
int i;
904+
bool use_polling = false;
896905

897906
/* First, clear all hpd and hpdrx interrupts */
898907
for (i = DC_IRQ_SOURCE_HPD1; i <= DC_IRQ_SOURCE_HPD6RX; i++) {
@@ -906,6 +915,8 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev)
906915
struct amdgpu_dm_connector *amdgpu_dm_connector;
907916
const struct dc_link *dc_link;
908917

918+
use_polling |= connector->polled != DRM_CONNECTOR_POLL_HPD;
919+
909920
if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
910921
continue;
911922

@@ -947,6 +958,9 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev)
947958
}
948959
}
949960
drm_connector_list_iter_end(&iter);
961+
962+
if (use_polling)
963+
drm_kms_helper_poll_init(dev);
950964
}
951965

952966
/**
@@ -997,4 +1011,7 @@ void amdgpu_dm_hpd_fini(struct amdgpu_device *adev)
9971011
}
9981012
}
9991013
drm_connector_list_iter_end(&iter);
1014+
1015+
if (dev->mode_config.poll_enabled)
1016+
drm_kms_helper_poll_fini(dev);
10001017
}

0 commit comments

Comments
 (0)