OSDN Git Service

drm/amd/display: fix issues with bad AUX reply on some displays
authorAnthony Koo <anthony.koo@amd.com>
Wed, 15 May 2019 20:39:23 +0000 (16:39 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 31 May 2019 15:39:32 +0000 (10:39 -0500)
[Why]
Some displays take some time to power up AUX CH once they are
put into D3 state via write to DPCD 600h=2.

Interestingly enough, some display may simply NACK, but some might
also ACK with a bunch of 0s, which can cause issues with receiver
cap retrieval. Note that not all DPCD address return 0s, but in
particular it has been observed on some higher DPCD address such
as DPCD 2200h, etc.

[How]
Based on spec, receiver will monitor differential signal while in D3 and
AUX CH is in low power mode. When detected, it may allow up to
1 ms to power up AUX CH and reply.

If we read Sink power state D3, we should add 1 ms delay to satisfy
this spec requirement.

Signed-off-by: Anthony Koo <anthony.koo@amd.com>
Reviewed-by: Wenjing Liu <Wenjing.Liu@amd.com>
Acked-by: Leo Li <sunpeng.li@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c

index 1ee544a..65d6cae 100644 (file)
@@ -2361,6 +2361,7 @@ static bool retrieve_link_cap(struct dc_link *link)
        /*Only need to read 1 byte starting from DP_DPRX_FEATURE_ENUMERATION_LIST.
         */
        uint8_t dpcd_dprx_data = '\0';
+       uint8_t dpcd_power_state = '\0';
 
        struct dp_device_vendor_id sink_id;
        union down_stream_port_count down_strm_port_count;
@@ -2377,6 +2378,17 @@ static bool retrieve_link_cap(struct dc_link *link)
        memset(&edp_config_cap, '\0',
                sizeof(union edp_configuration_cap));
 
+       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);
+
        for (i = 0; i < read_dpcd_retry_cnt; i++) {
                status = core_link_read_dpcd(
                                link,