Skip to content

Commit 509580f

Browse files
ideaktursulin
authored andcommitted
drm/i915/dp: Don't switch the LTTPR mode on an active link
Switching to transparent mode leads to a loss of link synchronization, so prevent doing this on an active link. This happened at least on an Intel N100 system / DELL UD22 dock, the LTTPR residing either on the host or the dock. To fix the issue, keep the current mode on an active link, adjusting the LTTPR count accordingly (resetting it to 0 in transparent mode). v2: Adjust code comment during link training about reiniting the LTTPRs. (Ville) Fixes: 7b2a4ab ("drm/i915: Switch to LTTPR transparent mode link training") Reported-and-tested-by: Gareth Yu <[email protected]> Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/10902 Cc: <[email protected]> # v5.15+ Cc: Ville Syrjälä <[email protected]> Reviewed-by: Ville Syrjälä <[email protected]> Reviewed-by: Ankit Nautiyal <[email protected]> Signed-off-by: Imre Deak <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected] (cherry picked from commit 211ad49) Signed-off-by: Tvrtko Ursulin <[email protected]>
1 parent d13e2a6 commit 509580f

File tree

1 file changed

+48
-7
lines changed

1 file changed

+48
-7
lines changed

drivers/gpu/drm/i915/display/intel_dp_link_training.c

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,24 @@ intel_dp_set_lttpr_transparent_mode(struct intel_dp *intel_dp, bool enable)
117117
return drm_dp_dpcd_write(&intel_dp->aux, DP_PHY_REPEATER_MODE, &val, 1) == 1;
118118
}
119119

120-
static int intel_dp_init_lttpr(struct intel_dp *intel_dp, const u8 dpcd[DP_RECEIVER_CAP_SIZE])
120+
static bool intel_dp_lttpr_transparent_mode_enabled(struct intel_dp *intel_dp)
121+
{
122+
return intel_dp->lttpr_common_caps[DP_PHY_REPEATER_MODE -
123+
DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV] ==
124+
DP_PHY_REPEATER_MODE_TRANSPARENT;
125+
}
126+
127+
/*
128+
* Read the LTTPR common capabilities and switch the LTTPR PHYs to
129+
* non-transparent mode if this is supported. Preserve the
130+
* transparent/non-transparent mode on an active link.
131+
*
132+
* Return the number of detected LTTPRs in non-transparent mode or 0 if the
133+
* LTTPRs are in transparent mode or the detection failed.
134+
*/
135+
static int intel_dp_init_lttpr_phys(struct intel_dp *intel_dp, const u8 dpcd[DP_RECEIVER_CAP_SIZE])
121136
{
122137
int lttpr_count;
123-
int i;
124138

125139
if (!intel_dp_read_lttpr_common_caps(intel_dp, dpcd))
126140
return 0;
@@ -134,6 +148,19 @@ static int intel_dp_init_lttpr(struct intel_dp *intel_dp, const u8 dpcd[DP_RECEI
134148
if (lttpr_count == 0)
135149
return 0;
136150

151+
/*
152+
* Don't change the mode on an active link, to prevent a loss of link
153+
* synchronization. See DP Standard v2.0 3.6.7. about the LTTPR
154+
* resetting its internal state when the mode is changed from
155+
* non-transparent to transparent.
156+
*/
157+
if (intel_dp->link_trained) {
158+
if (lttpr_count < 0 || intel_dp_lttpr_transparent_mode_enabled(intel_dp))
159+
goto out_reset_lttpr_count;
160+
161+
return lttpr_count;
162+
}
163+
137164
/*
138165
* See DP Standard v2.0 3.6.6.1. about the explicit disabling of
139166
* non-transparent mode and the disable->enable non-transparent mode
@@ -154,11 +181,25 @@ static int intel_dp_init_lttpr(struct intel_dp *intel_dp, const u8 dpcd[DP_RECEI
154181
"Switching to LTTPR non-transparent LT mode failed, fall-back to transparent mode\n");
155182

156183
intel_dp_set_lttpr_transparent_mode(intel_dp, true);
157-
intel_dp_reset_lttpr_count(intel_dp);
158184

159-
return 0;
185+
goto out_reset_lttpr_count;
160186
}
161187

188+
return lttpr_count;
189+
190+
out_reset_lttpr_count:
191+
intel_dp_reset_lttpr_count(intel_dp);
192+
193+
return 0;
194+
}
195+
196+
static int intel_dp_init_lttpr(struct intel_dp *intel_dp, const u8 dpcd[DP_RECEIVER_CAP_SIZE])
197+
{
198+
int lttpr_count;
199+
int i;
200+
201+
lttpr_count = intel_dp_init_lttpr_phys(intel_dp, dpcd);
202+
162203
for (i = 0; i < lttpr_count; i++)
163204
intel_dp_read_lttpr_phy_caps(intel_dp, dpcd, DP_PHY_LTTPR(i));
164205

@@ -1482,10 +1523,10 @@ void intel_dp_start_link_train(struct intel_atomic_state *state,
14821523
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
14831524
struct intel_encoder *encoder = &dig_port->base;
14841525
bool passed;
1485-
14861526
/*
1487-
* TODO: Reiniting LTTPRs here won't be needed once proper connector
1488-
* HW state readout is added.
1527+
* Reinit the LTTPRs here to ensure that they are switched to
1528+
* non-transparent mode. During an earlier LTTPR detection this
1529+
* could've been prevented by an active link.
14891530
*/
14901531
int lttpr_count = intel_dp_init_lttpr_and_dprx_caps(intel_dp);
14911532

0 commit comments

Comments
 (0)