From: Michael Strauss <michael.stra...@amd.com>

[WHY]
These fields are read for the explicit purpose of detecting embedded LTTPRs
(i.e. between host ASIC and the user-facing port), and thus need to
calculate the correct DPCD address offset based on LTTPR count to target
the appropriate LTTPR's DPCD register space with these queries.

[HOW]
Cascaded LTTPRs in a link each snoop and increment LTTPR count when queried
via DPCD read, so an LTTPR embedded in a source device (e.g. USB4 port on a
laptop) will always be addressible using the max LTTPR count seen by the
host. Therefore we simply need to use a recently added helper function to
calculate the correct DPCD address to target potentially embedded LTTPRs
based on the received LTTPR count.

Cc: Mario Limonciello <mario.limoncie...@amd.com>
Cc: Alex Deucher <alexander.deuc...@amd.com>
Cc: sta...@vger.kernel.org
Reviewed-by: Wenjing Liu <wenjing....@amd.com>
Signed-off-by: Michael Strauss <michael.stra...@amd.com>
Signed-off-by: Alex Hung <alex.h...@amd.com>
---
 drivers/gpu/drm/amd/display/dc/dc_dp_types.h  |  4 +-
 .../dc/link/protocols/link_dp_capability.c    | 38 +++++++++++++++----
 2 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h 
b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
index 0bad8304ccf6..d346f8ae1634 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
@@ -1172,8 +1172,8 @@ struct dc_lttpr_caps {
        union dp_128b_132b_supported_lttpr_link_rates supported_128b_132b_rates;
        union dp_alpm_lttpr_cap alpm;
        uint8_t aux_rd_interval[MAX_REPEATER_CNT - 1];
-       uint8_t lttpr_ieee_oui[3];
-       uint8_t lttpr_device_id[6];
+       uint8_t lttpr_ieee_oui[3]; // Always read from closest LTTPR to host
+       uint8_t lttpr_device_id[6]; // Always read from closest LTTPR to host
 };
 
 struct dc_dongle_dfp_cap_ext {
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c 
b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
index a5127c2d47ef..0f965380a9b4 100644
--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
@@ -385,9 +385,15 @@ bool dp_is_128b_132b_signal(struct pipe_ctx *pipe_ctx)
 bool dp_is_lttpr_present(struct dc_link *link)
 {
        /* Some sink devices report invalid LTTPR revision, so don't validate 
against that cap */
-       return 
(dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) != 
0 &&
+       uint32_t lttpr_count = 
dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+       bool is_lttpr_present = (lttpr_count > 0 &&
                        link->dpcd_caps.lttpr_caps.max_lane_count > 0 &&
                        link->dpcd_caps.lttpr_caps.max_lane_count <= 4);
+
+       if (lttpr_count > 0 && !is_lttpr_present)
+               DC_LOG_ERROR("LTTPR count is nonzero but invalid lane count 
reported. Assuming no LTTPR present.\n");
+
+       return is_lttpr_present;
 }
 
 /* in DP compliance test, DPR-120 may have
@@ -1551,6 +1557,8 @@ enum dc_status dp_retrieve_lttpr_cap(struct dc_link *link)
        uint8_t lttpr_dpcd_data[10] = {0};
        enum dc_status status;
        bool is_lttpr_present;
+       uint32_t lttpr_count;
+       uint32_t closest_lttpr_offset;
 
        /* Logic to determine LTTPR support*/
        bool vbios_lttpr_interop = link->dc->caps.vbios_lttpr_aware;
@@ -1602,20 +1610,22 @@ enum dc_status dp_retrieve_lttpr_cap(struct dc_link 
*link)
                        lttpr_dpcd_data[DP_LTTPR_ALPM_CAPABILITIES -
                                                        
DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
 
+       lttpr_count = 
dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+
        /* If this chip cap is set, at least one retimer must exist in the chain
         * Override count to 1 if we receive a known bad count (0 or an invalid 
value) */
        if (((link->chip_caps & AMD_EXT_DISPLAY_PATH_CAPS__EXT_CHIP_MASK) == 
AMD_EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
-                       
(dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) == 
0)) {
+                       lttpr_count == 0) {
                /* If you see this message consistently, either the host 
platform has FIXED_VS flag
                 * incorrectly configured or the sink device is returning an 
invalid count.
                 */
                DC_LOG_ERROR("lttpr_caps phy_repeater_cnt is 0x%x, forcing it 
to 0x80.",
                             link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
                link->dpcd_caps.lttpr_caps.phy_repeater_cnt = 0x80;
+               lttpr_count = 1;
                DC_LOG_DC("lttpr_caps forced phy_repeater_cnt = %d\n", 
link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
        }
 
-       /* Attempt to train in LTTPR transparent mode if repeater count exceeds 
8. */
        is_lttpr_present = dp_is_lttpr_present(link);
 
        DC_LOG_DC("is_lttpr_present = %d\n", is_lttpr_present);
@@ -1623,11 +1633,25 @@ enum dc_status dp_retrieve_lttpr_cap(struct dc_link 
*link)
        if (is_lttpr_present) {
                CONN_DATA_DETECT(link, lttpr_dpcd_data, 
sizeof(lttpr_dpcd_data), "LTTPR Caps: ");
 
-               core_link_read_dpcd(link, DP_LTTPR_IEEE_OUI, 
link->dpcd_caps.lttpr_caps.lttpr_ieee_oui, 
sizeof(link->dpcd_caps.lttpr_caps.lttpr_ieee_oui));
-               CONN_DATA_DETECT(link, 
link->dpcd_caps.lttpr_caps.lttpr_ieee_oui, 
sizeof(link->dpcd_caps.lttpr_caps.lttpr_ieee_oui), "LTTPR IEEE OUI: ");
+               // Identify closest LTTPR to determine if workarounds required 
for known embedded LTTPR
+               closest_lttpr_offset = dp_get_closest_lttpr_offset(lttpr_count);
 
-               core_link_read_dpcd(link, DP_LTTPR_DEVICE_ID, 
link->dpcd_caps.lttpr_caps.lttpr_device_id, 
sizeof(link->dpcd_caps.lttpr_caps.lttpr_device_id));
-               CONN_DATA_DETECT(link, 
link->dpcd_caps.lttpr_caps.lttpr_device_id, 
sizeof(link->dpcd_caps.lttpr_caps.lttpr_device_id), "LTTPR Device ID: ");
+               core_link_read_dpcd(link, (DP_LTTPR_IEEE_OUI + 
closest_lttpr_offset),
+                               link->dpcd_caps.lttpr_caps.lttpr_ieee_oui, 
sizeof(link->dpcd_caps.lttpr_caps.lttpr_ieee_oui));
+               core_link_read_dpcd(link, (DP_LTTPR_DEVICE_ID + 
closest_lttpr_offset),
+                               link->dpcd_caps.lttpr_caps.lttpr_device_id, 
sizeof(link->dpcd_caps.lttpr_caps.lttpr_device_id));
+
+               if (lttpr_count > 1) {
+                       CONN_DATA_DETECT(link, 
link->dpcd_caps.lttpr_caps.lttpr_ieee_oui, 
sizeof(link->dpcd_caps.lttpr_caps.lttpr_ieee_oui),
+                                       "Closest LTTPR To Host's IEEE OUI: ");
+                       CONN_DATA_DETECT(link, 
link->dpcd_caps.lttpr_caps.lttpr_device_id, 
sizeof(link->dpcd_caps.lttpr_caps.lttpr_device_id),
+                                       "Closest LTTPR To Host's LTTPR Device 
ID: ");
+               } else {
+                       CONN_DATA_DETECT(link, 
link->dpcd_caps.lttpr_caps.lttpr_ieee_oui, 
sizeof(link->dpcd_caps.lttpr_caps.lttpr_ieee_oui),
+                                       "LTTPR IEEE OUI: ");
+                       CONN_DATA_DETECT(link, 
link->dpcd_caps.lttpr_caps.lttpr_device_id, 
sizeof(link->dpcd_caps.lttpr_caps.lttpr_device_id),
+                                       "LTTPR Device ID: ");
+               }
        }
 
        return status;
-- 
2.43.0

Reply via email to