Skip to content

Commit 5a0436e

Browse files
alexVinarskislumag
authored andcommitted
drm/msm/dp: Introduce link training per-segment for LTTPRs
DisplayPort requires per-segment link training when LTTPR are switched to non-transparent mode, starting with LTTPR closest to the source. Only when each segment is trained individually, source can link train to sink. Implement per-segment link traning when LTTPR(s) are detected, to support external docking stations. On higher level, changes are: * Pass phy being trained down to all required helpers * Run CR, EQ link training per phy * Set voltage swing, pre-emphasis levels per phy Since at least some LTTPRs (eg. Parade PS8830) do not correctly report voltage-swing, pre-emphasis level 3 support, always assume level 3 is supported. This is permitted under DP 2.1(a) section 3.6.7.2 stating that LTTPR shall set its transmitter levels as close as possible to those requested by the DPTX, if the DPTX sets the voltage swing or pre-emphasis to a level that the LTTPR does not support. It shall be noted that LTTPR’s level choosing is implementation-specific. This ensures successful link training both when connected directly to the monitor (single LTTPR onboard most X1E laptops) and via the docking station (at least two LTTPRs). Fixes: 72d0af4 ("drm/msm/dp: Add support for LTTPR handling") Tested-by: Jessica Zhang <[email protected]> # SA8775P Tested-by: Johan Hovold <[email protected]> Tested-by: Rob Clark <[email protected]> Tested-by: Stefan Schmidt <[email protected]> Signed-off-by: Aleksandrs Vinarskis <[email protected]> Reviewed-by: Abel Vesa <[email protected]> Reviewed-by: Abhinav Kumar <[email protected]> Reviewed-by: Dmitry Baryshkov <[email protected]> Patchwork: https://patchwork.freedesktop.org/patch/652305/ Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Dmitry Baryshkov <[email protected]>
1 parent 7513ccb commit 5a0436e

File tree

1 file changed

+89
-37
lines changed

1 file changed

+89
-37
lines changed

drivers/gpu/drm/msm/dp/dp_ctrl.c

Lines changed: 89 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,10 +1034,12 @@ static int msm_dp_ctrl_set_vx_px(struct msm_dp_ctrl_private *ctrl,
10341034
return 0;
10351035
}
10361036

1037-
static int msm_dp_ctrl_update_vx_px(struct msm_dp_ctrl_private *ctrl)
1037+
static int msm_dp_ctrl_update_phy_vx_px(struct msm_dp_ctrl_private *ctrl,
1038+
enum drm_dp_phy dp_phy)
10381039
{
10391040
struct msm_dp_link *link = ctrl->link;
1040-
int ret = 0, lane, lane_cnt;
1041+
int lane, lane_cnt, reg;
1042+
int ret = 0;
10411043
u8 buf[4];
10421044
u32 max_level_reached = 0;
10431045
u32 voltage_swing_level = link->phy_params.v_level;
@@ -1075,18 +1077,24 @@ static int msm_dp_ctrl_update_vx_px(struct msm_dp_ctrl_private *ctrl)
10751077

10761078
drm_dbg_dp(ctrl->drm_dev, "sink: p|v=0x%x\n",
10771079
voltage_swing_level | pre_emphasis_level);
1078-
ret = drm_dp_dpcd_write(ctrl->aux, DP_TRAINING_LANE0_SET,
1079-
buf, lane_cnt);
1080+
1081+
if (dp_phy == DP_PHY_DPRX)
1082+
reg = DP_TRAINING_LANE0_SET;
1083+
else
1084+
reg = DP_TRAINING_LANE0_SET_PHY_REPEATER(dp_phy);
1085+
1086+
ret = drm_dp_dpcd_write(ctrl->aux, reg, buf, lane_cnt);
10801087
if (ret == lane_cnt)
10811088
ret = 0;
10821089

10831090
return ret;
10841091
}
10851092

10861093
static bool msm_dp_ctrl_train_pattern_set(struct msm_dp_ctrl_private *ctrl,
1087-
u8 pattern)
1094+
u8 pattern, enum drm_dp_phy dp_phy)
10881095
{
10891096
u8 buf;
1097+
int reg;
10901098
int ret = 0;
10911099

10921100
drm_dbg_dp(ctrl->drm_dev, "sink: pattern=%x\n", pattern);
@@ -1096,17 +1104,26 @@ static bool msm_dp_ctrl_train_pattern_set(struct msm_dp_ctrl_private *ctrl,
10961104
if (pattern && pattern != DP_TRAINING_PATTERN_4)
10971105
buf |= DP_LINK_SCRAMBLING_DISABLE;
10981106

1099-
ret = drm_dp_dpcd_writeb(ctrl->aux, DP_TRAINING_PATTERN_SET, buf);
1107+
if (dp_phy == DP_PHY_DPRX)
1108+
reg = DP_TRAINING_PATTERN_SET;
1109+
else
1110+
reg = DP_TRAINING_PATTERN_SET_PHY_REPEATER(dp_phy);
1111+
1112+
ret = drm_dp_dpcd_writeb(ctrl->aux, reg, buf);
11001113
return ret == 1;
11011114
}
11021115

11031116
static int msm_dp_ctrl_link_train_1(struct msm_dp_ctrl_private *ctrl,
1104-
int *training_step)
1117+
int *training_step, enum drm_dp_phy dp_phy)
11051118
{
1119+
int delay_us;
11061120
int tries, old_v_level, ret = 0;
11071121
u8 link_status[DP_LINK_STATUS_SIZE];
11081122
int const maximum_retries = 4;
11091123

1124+
delay_us = drm_dp_read_clock_recovery_delay(ctrl->aux,
1125+
ctrl->panel->dpcd, dp_phy, false);
1126+
11101127
msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
11111128

11121129
*training_step = DP_TRAINING_1;
@@ -1115,18 +1132,19 @@ static int msm_dp_ctrl_link_train_1(struct msm_dp_ctrl_private *ctrl,
11151132
if (ret)
11161133
return ret;
11171134
msm_dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_1 |
1118-
DP_LINK_SCRAMBLING_DISABLE);
1135+
DP_LINK_SCRAMBLING_DISABLE, dp_phy);
11191136

1120-
ret = msm_dp_ctrl_update_vx_px(ctrl);
1137+
msm_dp_link_reset_phy_params_vx_px(ctrl->link);
1138+
ret = msm_dp_ctrl_update_phy_vx_px(ctrl, dp_phy);
11211139
if (ret)
11221140
return ret;
11231141

11241142
tries = 0;
11251143
old_v_level = ctrl->link->phy_params.v_level;
11261144
for (tries = 0; tries < maximum_retries; tries++) {
1127-
drm_dp_link_train_clock_recovery_delay(ctrl->aux, ctrl->panel->dpcd);
1145+
fsleep(delay_us);
11281146

1129-
ret = drm_dp_dpcd_read_link_status(ctrl->aux, link_status);
1147+
ret = drm_dp_dpcd_read_phy_link_status(ctrl->aux, dp_phy, link_status);
11301148
if (ret)
11311149
return ret;
11321150

@@ -1147,7 +1165,7 @@ static int msm_dp_ctrl_link_train_1(struct msm_dp_ctrl_private *ctrl,
11471165
}
11481166

11491167
msm_dp_link_adjust_levels(ctrl->link, link_status);
1150-
ret = msm_dp_ctrl_update_vx_px(ctrl);
1168+
ret = msm_dp_ctrl_update_phy_vx_px(ctrl, dp_phy);
11511169
if (ret)
11521170
return ret;
11531171
}
@@ -1199,21 +1217,31 @@ static int msm_dp_ctrl_link_lane_down_shift(struct msm_dp_ctrl_private *ctrl)
11991217
return 0;
12001218
}
12011219

1202-
static void msm_dp_ctrl_clear_training_pattern(struct msm_dp_ctrl_private *ctrl)
1220+
static void msm_dp_ctrl_clear_training_pattern(struct msm_dp_ctrl_private *ctrl,
1221+
enum drm_dp_phy dp_phy)
12031222
{
1204-
msm_dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_DISABLE);
1205-
drm_dp_link_train_channel_eq_delay(ctrl->aux, ctrl->panel->dpcd);
1223+
int delay_us;
1224+
1225+
msm_dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_DISABLE, dp_phy);
1226+
1227+
delay_us = drm_dp_read_channel_eq_delay(ctrl->aux,
1228+
ctrl->panel->dpcd, dp_phy, false);
1229+
fsleep(delay_us);
12061230
}
12071231

12081232
static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
1209-
int *training_step)
1233+
int *training_step, enum drm_dp_phy dp_phy)
12101234
{
1235+
int delay_us;
12111236
int tries = 0, ret = 0;
12121237
u8 pattern;
12131238
u32 state_ctrl_bit;
12141239
int const maximum_retries = 5;
12151240
u8 link_status[DP_LINK_STATUS_SIZE];
12161241

1242+
delay_us = drm_dp_read_channel_eq_delay(ctrl->aux,
1243+
ctrl->panel->dpcd, dp_phy, false);
1244+
12171245
msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
12181246

12191247
*training_step = DP_TRAINING_2;
@@ -1233,12 +1261,12 @@ static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
12331261
if (ret)
12341262
return ret;
12351263

1236-
msm_dp_ctrl_train_pattern_set(ctrl, pattern);
1264+
msm_dp_ctrl_train_pattern_set(ctrl, pattern, dp_phy);
12371265

12381266
for (tries = 0; tries <= maximum_retries; tries++) {
1239-
drm_dp_link_train_channel_eq_delay(ctrl->aux, ctrl->panel->dpcd);
1267+
fsleep(delay_us);
12401268

1241-
ret = drm_dp_dpcd_read_link_status(ctrl->aux, link_status);
1269+
ret = drm_dp_dpcd_read_phy_link_status(ctrl->aux, dp_phy, link_status);
12421270
if (ret)
12431271
return ret;
12441272

@@ -1248,7 +1276,7 @@ static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
12481276
}
12491277

12501278
msm_dp_link_adjust_levels(ctrl->link, link_status);
1251-
ret = msm_dp_ctrl_update_vx_px(ctrl);
1279+
ret = msm_dp_ctrl_update_phy_vx_px(ctrl, dp_phy);
12521280
if (ret)
12531281
return ret;
12541282

@@ -1257,9 +1285,32 @@ static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
12571285
return -ETIMEDOUT;
12581286
}
12591287

1288+
static int msm_dp_ctrl_link_train_1_2(struct msm_dp_ctrl_private *ctrl,
1289+
int *training_step, enum drm_dp_phy dp_phy)
1290+
{
1291+
int ret;
1292+
1293+
ret = msm_dp_ctrl_link_train_1(ctrl, training_step, dp_phy);
1294+
if (ret) {
1295+
DRM_ERROR("link training #1 on phy %d failed. ret=%d\n", dp_phy, ret);
1296+
return ret;
1297+
}
1298+
drm_dbg_dp(ctrl->drm_dev, "link training #1 on phy %d successful\n", dp_phy);
1299+
1300+
ret = msm_dp_ctrl_link_train_2(ctrl, training_step, dp_phy);
1301+
if (ret) {
1302+
DRM_ERROR("link training #2 on phy %d failed. ret=%d\n", dp_phy, ret);
1303+
return ret;
1304+
}
1305+
drm_dbg_dp(ctrl->drm_dev, "link training #2 on phy %d successful\n", dp_phy);
1306+
1307+
return 0;
1308+
}
1309+
12601310
static int msm_dp_ctrl_link_train(struct msm_dp_ctrl_private *ctrl,
12611311
int *training_step)
12621312
{
1313+
int i;
12631314
int ret = 0;
12641315
const u8 *dpcd = ctrl->panel->dpcd;
12651316
u8 encoding[] = { 0, DP_SET_ANSI_8B10B };
@@ -1272,8 +1323,6 @@ static int msm_dp_ctrl_link_train(struct msm_dp_ctrl_private *ctrl,
12721323
link_info.rate = ctrl->link->link_params.rate;
12731324
link_info.capabilities = DP_LINK_CAP_ENHANCED_FRAMING;
12741325

1275-
msm_dp_link_reset_phy_params_vx_px(ctrl->link);
1276-
12771326
msm_dp_aux_link_configure(ctrl->aux, &link_info);
12781327

12791328
if (drm_dp_max_downspread(dpcd))
@@ -1288,24 +1337,27 @@ static int msm_dp_ctrl_link_train(struct msm_dp_ctrl_private *ctrl,
12881337
&assr, 1);
12891338
}
12901339

1291-
ret = msm_dp_ctrl_link_train_1(ctrl, training_step);
1340+
for (i = ctrl->link->lttpr_count - 1; i >= 0; i--) {
1341+
enum drm_dp_phy dp_phy = DP_PHY_LTTPR(i);
1342+
1343+
ret = msm_dp_ctrl_link_train_1_2(ctrl, training_step, dp_phy);
1344+
msm_dp_ctrl_clear_training_pattern(ctrl, dp_phy);
1345+
1346+
if (ret)
1347+
break;
1348+
}
1349+
12921350
if (ret) {
1293-
DRM_ERROR("link training #1 failed. ret=%d\n", ret);
1351+
DRM_ERROR("link training of LTTPR(s) failed. ret=%d\n", ret);
12941352
goto end;
12951353
}
12961354

1297-
/* print success info as this is a result of user initiated action */
1298-
drm_dbg_dp(ctrl->drm_dev, "link training #1 successful\n");
1299-
1300-
ret = msm_dp_ctrl_link_train_2(ctrl, training_step);
1355+
ret = msm_dp_ctrl_link_train_1_2(ctrl, training_step, DP_PHY_DPRX);
13011356
if (ret) {
1302-
DRM_ERROR("link training #2 failed. ret=%d\n", ret);
1357+
DRM_ERROR("link training on sink failed. ret=%d\n", ret);
13031358
goto end;
13041359
}
13051360

1306-
/* print success info as this is a result of user initiated action */
1307-
drm_dbg_dp(ctrl->drm_dev, "link training #2 successful\n");
1308-
13091361
end:
13101362
msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
13111363

@@ -1622,7 +1674,7 @@ static int msm_dp_ctrl_link_maintenance(struct msm_dp_ctrl_private *ctrl)
16221674
if (ret)
16231675
goto end;
16241676

1625-
msm_dp_ctrl_clear_training_pattern(ctrl);
1677+
msm_dp_ctrl_clear_training_pattern(ctrl, DP_PHY_DPRX);
16261678

16271679
msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_SEND_VIDEO);
16281680

@@ -1646,7 +1698,7 @@ static bool msm_dp_ctrl_send_phy_test_pattern(struct msm_dp_ctrl_private *ctrl)
16461698
return false;
16471699
}
16481700
msm_dp_catalog_ctrl_send_phy_pattern(ctrl->catalog, pattern_requested);
1649-
msm_dp_ctrl_update_vx_px(ctrl);
1701+
msm_dp_ctrl_update_phy_vx_px(ctrl, DP_PHY_DPRX);
16501702
msm_dp_link_send_test_response(ctrl->link);
16511703

16521704
pattern_sent = msm_dp_catalog_ctrl_read_phy_pattern(ctrl->catalog);
@@ -1888,7 +1940,7 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
18881940
}
18891941

18901942
/* stop link training before start re training */
1891-
msm_dp_ctrl_clear_training_pattern(ctrl);
1943+
msm_dp_ctrl_clear_training_pattern(ctrl, DP_PHY_DPRX);
18921944
}
18931945

18941946
rc = msm_dp_ctrl_reinitialize_mainlink(ctrl);
@@ -1912,7 +1964,7 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
19121964
* link training failed
19131965
* end txing train pattern here
19141966
*/
1915-
msm_dp_ctrl_clear_training_pattern(ctrl);
1967+
msm_dp_ctrl_clear_training_pattern(ctrl, DP_PHY_DPRX);
19161968

19171969
msm_dp_ctrl_deinitialize_mainlink(ctrl);
19181970
rc = -ECONNRESET;
@@ -1983,7 +2035,7 @@ int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train
19832035
msm_dp_ctrl_link_retrain(ctrl);
19842036

19852037
/* stop txing train pattern to end link training */
1986-
msm_dp_ctrl_clear_training_pattern(ctrl);
2038+
msm_dp_ctrl_clear_training_pattern(ctrl, DP_PHY_DPRX);
19872039

19882040
/*
19892041
* Set up transfer unit values and set controller state to send

0 commit comments

Comments
 (0)