]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/amd/display: Use DAC load detection on analog connectors (v2)
authorTimur Kristóf <timur.kristof@gmail.com>
Fri, 26 Sep 2025 18:02:00 +0000 (20:02 +0200)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 28 Oct 2025 14:10:00 +0000 (10:10 -0400)
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 <timur.kristof@gmail.com>
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/dc/dc_types.h
drivers/gpu/drm/amd/display/dc/link/link_detection.c

index d18d72a520f2efcdf2965105112d62186a320dc9..a235a5b611860826d2bddeb7dccf275dbc22a66d 100644 (file)
@@ -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) &&
index 9989c8af5174a91722867738a6a5c72d0ec60e01..ea6b71c43d2c8bb35c8011e269f44531d0a60284 100644 (file)
@@ -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 {
index d83fd52cb1b0ab834d036c2f146e46f97064f940..c417780f37bca0092ee24e5e0a05f0a4932879fd 100644 (file)
@@ -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.