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. Signed-off-by: Timur Kristóf <timur.kris...@gmail.com> --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 12 ++++++ .../drm/amd/display/dc/link/link_detection.c | 43 +++++++++++++++++++ 2 files changed, 55 insertions(+) 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 13823469fa7c..49ee516dc83d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -7077,6 +7077,18 @@ 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 the EDID is missing on an analog connector, that means + * we determined the connection using DAC load detection. + * In this case 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->local_sink->edid_caps.analog && + !aconnector->drm_edid) + 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/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c index fcabc83464af..6dd96e2797f4 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c @@ -1073,6 +1073,20 @@ static bool detect_link_and_local_sink(struct dc_link *link, break; case EDID_NO_RESPONSE: DC_LOG_ERROR("No EDID read.\n"); + + /* Analog connectors without EDID. + * This can be an old monitor that actually doesn't have EDID, + * or could be a cheap DVI/VGA adapter that doesn't connect DDC, + * and therefore we can't read the EDID. + */ + if (link->link_enc->connector.id == CONNECTOR_ID_VGA || + link->link_enc->connector.id == CONNECTOR_ID_DUAL_LINK_DVII || + link->link_enc->connector.id == CONNECTOR_ID_SINGLE_LINK_DVII) { + DC_LOG_INFO("%s detected analog display without EDID\n", __func__); + sink->edid_caps.analog = true; + break; + } + /* * Abort detection for non-DP connectors if we have * no EDID @@ -1280,6 +1294,30 @@ static bool link_detect_ddc_probe(struct dc_link *link) return true; } +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; +} + /** * Determines if there is an analog sink connected. */ @@ -1296,6 +1334,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_single; + return true; + } + *type = dc_connection_none; return true; } -- 2.50.1