drm/amd/display: Refine aux transaction before retrieve caps
authorLewis Huang <Lewis.Huang@amd.com>
Mon, 8 Aug 2022 05:20:16 +0000 (13:20 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 29 Aug 2022 21:45:20 +0000 (17:45 -0400)
[Why]
LTTPR caps will read fail if aux channel is not active.

[How]
1.Perform 600 read upto 10 retry with 1ms delay in between.
2.If fail, return false and trigger another retry detection.
3.If pass, read LTTPR caps in retrieve link caps.

Reviewed-by: Jimmy Kizito <Jimmy.Kizito@amd.com>
Acked-by: Brian Chang <Brian.Chang@amd.com>
Signed-off-by: Lewis Huang <Lewis.Huang@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c

index f92bbc86772e1b238bbe535551200bb9669d5e11..4c04b5f8eb94a541b074e5c050735b1977dba31f 100644 (file)
@@ -5275,6 +5275,7 @@ static bool retrieve_link_cap(struct dc_link *link)
        union dp_downstream_port_present ds_port = { 0 };
        enum dc_status status = DC_ERROR_UNEXPECTED;
        uint32_t read_dpcd_retry_cnt = 3;
+       uint32_t aux_channel_retry_cnt = 0;
        int i;
        struct dp_sink_hw_fw_revision dp_hw_fw_revision;
        const uint32_t post_oui_delay = 30; // 30ms
@@ -5302,21 +5303,43 @@ static bool retrieve_link_cap(struct dc_link *link)
                status = wa_try_to_wake_dprx(link, timeout_ms);
        }
 
+       while (status != DC_OK && aux_channel_retry_cnt < 10) {
+               status = core_link_read_dpcd(link, DP_SET_POWER,
+                               &dpcd_power_state, sizeof(dpcd_power_state));
+
+               /* Delay 1 ms if AUX CH is in power down state. Based on spec
+                * section 2.3.1.2, if AUX CH may be powered down due to
+                * write to DPCD 600h = 2. Sink AUX CH is monitoring differential
+                * signal and may need up to 1 ms before being able to reply.
+                */
+               if (status != DC_OK || dpcd_power_state == DP_SET_POWER_D3) {
+                       udelay(1000);
+                       aux_channel_retry_cnt++;
+               }
+       }
+
+       /* If aux channel is not active, return false and trigger another detect*/
+       if (status != DC_OK) {
+               dpcd_power_state = DP_SET_POWER_D0;
+               status = core_link_write_dpcd(
+                               link,
+                               DP_SET_POWER,
+                               &dpcd_power_state,
+                               sizeof(dpcd_power_state));
+
+               dpcd_power_state = DP_SET_POWER_D3;
+               status = core_link_write_dpcd(
+                               link,
+                               DP_SET_POWER,
+                               &dpcd_power_state,
+                               sizeof(dpcd_power_state));
+               return false;
+       }
+
        is_lttpr_present = dp_retrieve_lttpr_cap(link);
        /* Read DP tunneling information. */
        status = dpcd_get_tunneling_device_data(link);
 
-       status = core_link_read_dpcd(link, DP_SET_POWER,
-                       &dpcd_power_state, sizeof(dpcd_power_state));
-
-       /* Delay 1 ms if AUX CH is in power down state. Based on spec
-        * section 2.3.1.2, if AUX CH may be powered down due to
-        * write to DPCD 600h = 2. Sink AUX CH is monitoring differential
-        * signal and may need up to 1 ms before being able to reply.
-        */
-       if (status != DC_OK || dpcd_power_state == DP_SET_POWER_D3)
-               udelay(1000);
-
        dpcd_set_source_specific_data(link);
        /* Sink may need to configure internals based on vendor, so allow some
         * time before proceeding with possibly vendor specific transactions