From: Timur Kristóf Date: Fri, 26 Sep 2025 18:02:00 +0000 (+0200) Subject: drm/amd/display: Use DAC load detection on analog connectors (v2) X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ac1bb49522676dfbd83c323376f8d5daa5b1ba84;p=thirdparty%2Fkernel%2Flinux.git drm/amd/display: Use DAC load detection on analog connectors (v2) This feature is useful for analog connections without EDID: - Really old monitors with a VGA connector - Cheap DVI/VGA adapters that don't connect DDC pins When a connection is established through DAC load detection, the driver is supposed to fill in the supported modes for the display, which we already do in amdgpu_dm_connector_get_modes. Also, because the load detection causes visible glitches, do not attempt to poll the connector again after it was detected this way. Note that it will still be polled after sleep/resume or when force is enabled, which is okay. v2: Add dc_connection_dac_load connection type. Properly release sink when no display is connected. Don't print error when EDID isn't read from an analog display. Signed-off-by: Timur Kristóf Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- 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 d18d72a520f2e..a235a5b611860 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -7248,6 +7248,16 @@ amdgpu_dm_connector_poll(struct amdgpu_dm_connector *aconnector, bool force) enum dc_connection_type conn_type = dc_connection_none; enum drm_connector_status status = connector_status_disconnected; + /* When we determined the connection using DAC load detection, + * do NOT poll the connector do detect disconnect because + * that would run DAC load detection again which can cause + * visible visual glitches. + * + * Only allow to poll such a connector again when forcing. + */ + if (!force && link->local_sink && link->type == dc_connection_dac_load) + return connector->status; + mutex_lock(&aconnector->hpd_lock); if (dc_link_detect_connection_type(aconnector->dc_link, &conn_type) && diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 9989c8af5174a..ea6b71c43d2c8 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -353,7 +353,8 @@ enum dc_connection_type { dc_connection_none, dc_connection_single, dc_connection_mst_branch, - dc_connection_sst_branch + dc_connection_sst_branch, + dc_connection_dac_load }; struct dc_csc_adjustments { diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c index d83fd52cb1b0a..c417780f37bca 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c @@ -904,6 +904,37 @@ static bool link_detect_ddc_probe(struct dc_link *link) return true; } +/** + * link_detect_dac_load_detect() - Performs DAC load detection. + * + * Load detection can be used to detect the presence of an + * analog display when we can't read DDC. This causes a visible + * visual glitch so it should be used sparingly. + */ +static bool link_detect_dac_load_detect(struct dc_link *link) +{ + struct dc_bios *bios = link->ctx->dc_bios; + struct link_encoder *link_enc = link->link_enc; + enum engine_id engine_id = link_enc->preferred_engine; + enum dal_device_type device_type = DEVICE_TYPE_CRT; + enum bp_result bp_result; + uint32_t enum_id; + + switch (engine_id) { + case ENGINE_ID_DACB: + enum_id = 2; + break; + case ENGINE_ID_DACA: + default: + engine_id = ENGINE_ID_DACA; + enum_id = 1; + break; + } + + bp_result = bios->funcs->dac_load_detection(bios, engine_id, device_type, enum_id); + return bp_result == BP_RESULT_OK; +} + /* * detect_link_and_local_sink() - Detect if a sink is attached to a given link * @@ -1118,7 +1149,30 @@ static bool detect_link_and_local_sink(struct dc_link *link, DC_LOG_ERROR("Partial EDID valid, abandon invalid blocks.\n"); break; case EDID_NO_RESPONSE: + /* Analog connectors without EDID: + * - old monitor that actually doesn't have EDID + * - cheap DVI-A cable or adapter that doesn't connect DDC + */ + if (dc_connector_supports_analog(link->link_id.id)) { + /* If we didn't do DAC load detection yet, do it now + * to verify there really is a display connected. + */ + if (link->type != dc_connection_dac_load && + !link_detect_dac_load_detect(link)) { + if (prev_sink) + dc_sink_release(prev_sink); + link_disconnect_sink(link); + return false; + } + + DC_LOG_INFO("%s detected analog display without EDID\n", __func__); + link->type = dc_connection_dac_load; + sink->edid_caps.analog = true; + break; + } + DC_LOG_ERROR("No EDID read.\n"); + /* * Abort detection for non-DP connectors if we have * no EDID @@ -1307,6 +1361,11 @@ static bool link_detect_analog(struct dc_link *link, enum dc_connection_type *ty return true; } + if (link_detect_dac_load_detect(link)) { + *type = dc_connection_dac_load; + return true; + } + *type = dc_connection_none; return true; } @@ -1328,7 +1387,7 @@ bool link_detect_connection_type(struct dc_link *link, enum dc_connection_type * } /* Ignore the HPD pin (if any) for analog connectors. - * Instead rely on DDC. + * Instead rely on DDC and DAC. * * - VGA connectors don't have any HPD at all. * - Some DVI-A cables don't connect the HPD pin.