1/* 2 * Copyright 2022 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: AMD 23 * 24 */ 25 26/* FILE POLICY AND INTENDED USAGE: 27 * This file implements 8b/10b link training specially modified to support an 28 * embedded retimer chip. This retimer chip is referred as fixed vs pe retimer. 29 * Unlike native dp connection this chip requires a modified link training 30 * protocol based on 8b/10b link training. Since this is a non standard sequence 31 * and we must support this hardware, we decided to isolate it in its own 32 * training sequence inside its own file. 33 */ 34#include "link_dp_training_fixed_vs_pe_retimer.h" 35#include "link_dp_training_8b_10b.h" 36#include "link_dpcd.h" 37#include "link_dp_phy.h" 38#include "link_dp_capability.h" 39#include "link_ddc.h" 40 41#define DC_LOGGER \ 42 link->ctx->logger 43 44void dp_fixed_vs_pe_read_lane_adjust( 45 struct dc_link *link, 46 union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX]) 47{ 48 const uint8_t vendor_lttpr_write_data_vs[3] = {0x0, 0x53, 0x63}; 49 const uint8_t vendor_lttpr_write_data_pe[3] = {0x0, 0x54, 0x63}; 50 uint8_t dprx_vs = 0; 51 uint8_t dprx_pe = 0; 52 uint8_t lane; 53 54 /* W/A to read lane settings requested by DPRX */ 55 link_configure_fixed_vs_pe_retimer(link->ddc, 56 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs)); 57 58 link_query_fixed_vs_pe_retimer(link->ddc, &dprx_vs, 1); 59 60 link_configure_fixed_vs_pe_retimer(link->ddc, 61 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe)); 62 63 link_query_fixed_vs_pe_retimer(link->ddc, &dprx_pe, 1); 64 65 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { 66 dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET = (dprx_vs >> (2 * lane)) & 0x3; 67 dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET = (dprx_pe >> (2 * lane)) & 0x3; 68 } 69} 70 71 72void dp_fixed_vs_pe_set_retimer_lane_settings( 73 struct dc_link *link, 74 const union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX], 75 uint8_t lane_count) 76{ 77 const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF}; 78 uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0}; 79 uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0}; 80 uint8_t lane = 0; 81 82 for (lane = 0; lane < lane_count; lane++) { 83 vendor_lttpr_write_data_vs[3] |= 84 dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET << (2 * lane); 85 vendor_lttpr_write_data_pe[3] |= 86 dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET << (2 * lane); 87 } 88 89 /* Force LTTPR to output desired VS and PE */ 90 link_configure_fixed_vs_pe_retimer(link->ddc, 91 &vendor_lttpr_write_data_reset[0], sizeof(vendor_lttpr_write_data_reset)); 92 93 link_configure_fixed_vs_pe_retimer(link->ddc, 94 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs)); 95 96 link_configure_fixed_vs_pe_retimer(link->ddc, 97 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe)); 98} 99 100static enum link_training_result perform_fixed_vs_pe_nontransparent_training_sequence( 101 struct dc_link *link, 102 const struct link_resource *link_res, 103 struct link_training_settings *lt_settings) 104{ 105 enum link_training_result status = LINK_TRAINING_SUCCESS; 106 uint8_t lane = 0; 107 uint8_t toggle_rate = 0x6; 108 uint8_t target_rate = 0x6; 109 bool apply_toggle_rate_wa = false; 110 uint8_t repeater_cnt; 111 uint8_t repeater_id; 112 113 /* Fixed VS/PE specific: Force CR AUX RD Interval to at least 16ms */ 114 if (lt_settings->cr_pattern_time < 16000) 115 lt_settings->cr_pattern_time = 16000; 116 117 /* Fixed VS/PE specific: Toggle link rate */ 118 apply_toggle_rate_wa = ((link->vendor_specific_lttpr_link_rate_wa == target_rate) || (link->vendor_specific_lttpr_link_rate_wa == 0)); 119 target_rate = get_dpcd_link_rate(<_settings->link_settings); 120 toggle_rate = (target_rate == 0x6) ? 0xA : 0x6; 121 122 if (apply_toggle_rate_wa) 123 lt_settings->link_settings.link_rate = toggle_rate; 124 125 if (link->ctx->dc->work_arounds.lt_early_cr_pattern) 126 start_clock_recovery_pattern_early(link, link_res, lt_settings, DPRX); 127 128 /* 1. set link rate, lane count and spread. */ 129 dpcd_set_link_settings(link, lt_settings); 130 131 /* Fixed VS/PE specific: Toggle link rate back*/ 132 if (apply_toggle_rate_wa) { 133 core_link_write_dpcd( 134 link, 135 DP_LINK_BW_SET, 136 &target_rate, 137 1); 138 } 139 140 link->vendor_specific_lttpr_link_rate_wa = target_rate; 141 142 if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { 143 144 /* 2. perform link training (set link training done 145 * to false is done as well) 146 */ 147 repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt); 148 149 for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS); 150 repeater_id--) { 151 status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, repeater_id); 152 153 if (status != LINK_TRAINING_SUCCESS) { 154 repeater_training_done(link, repeater_id); 155 break; 156 } 157 158 status = perform_8b_10b_channel_equalization_sequence(link, 159 link_res, 160 lt_settings, 161 repeater_id); 162 163 repeater_training_done(link, repeater_id); 164 165 if (status != LINK_TRAINING_SUCCESS) 166 break; 167 168 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { 169 lt_settings->dpcd_lane_settings[lane].raw = 0; 170 lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0; 171 lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0; 172 } 173 } 174 } 175 176 if (status == LINK_TRAINING_SUCCESS) { 177 status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, DPRX); 178 if (status == LINK_TRAINING_SUCCESS) { 179 status = perform_8b_10b_channel_equalization_sequence(link, 180 link_res, 181 lt_settings, 182 DPRX); 183 } 184 } 185 186 return status; 187} 188 189 190enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy( 191 struct dc_link *link, 192 const struct link_resource *link_res, 193 struct link_training_settings *lt_settings) 194{ 195 const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF}; 196 const uint8_t offset = dp_parse_lttpr_repeater_count( 197 link->dpcd_caps.lttpr_caps.phy_repeater_cnt); 198 const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0}; 199 const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x68}; 200 uint32_t pre_disable_intercept_delay_ms = 0; 201 uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0}; 202 uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0}; 203 const uint8_t vendor_lttpr_write_data_4lane_1[4] = {0x1, 0x6E, 0xF2, 0x19}; 204 const uint8_t vendor_lttpr_write_data_4lane_2[4] = {0x1, 0x6B, 0xF2, 0x01}; 205 const uint8_t vendor_lttpr_write_data_4lane_3[4] = {0x1, 0x6D, 0xF2, 0x18}; 206 const uint8_t vendor_lttpr_write_data_4lane_4[4] = {0x1, 0x6C, 0xF2, 0x03}; 207 const uint8_t vendor_lttpr_write_data_4lane_5[4] = {0x1, 0x03, 0xF3, 0x06}; 208 enum link_training_result status = LINK_TRAINING_SUCCESS; 209 uint8_t lane = 0; 210 union down_spread_ctrl downspread = {0}; 211 union lane_count_set lane_count_set = {0}; 212 uint8_t toggle_rate; 213 uint8_t rate; 214 215 /* Only 8b/10b is supported */ 216 ASSERT(link_dp_get_encoding_format(<_settings->link_settings) == 217 DP_8b_10b_ENCODING); 218 219 if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { 220 status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings); 221 return status; 222 } 223 224 if (offset != 0xFF) { 225 if (offset == 2) { 226 pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa; 227 228 /* Certain display and cable configuration require extra delay */ 229 } else if (offset > 2) { 230 pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2; 231 } 232 } 233 234 /* Vendor specific: Reset lane settings */ 235 link_configure_fixed_vs_pe_retimer(link->ddc, 236 &vendor_lttpr_write_data_reset[0], sizeof(vendor_lttpr_write_data_reset)); 237 link_configure_fixed_vs_pe_retimer(link->ddc, 238 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs)); 239 link_configure_fixed_vs_pe_retimer(link->ddc, 240 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe)); 241 242 /* Vendor specific: Enable intercept */ 243 link_configure_fixed_vs_pe_retimer(link->ddc, 244 &vendor_lttpr_write_data_intercept_en[0], sizeof(vendor_lttpr_write_data_intercept_en)); 245 246 247 /* 1. set link rate, lane count and spread. */ 248 249 downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread); 250 251 lane_count_set.bits.LANE_COUNT_SET = 252 lt_settings->link_settings.lane_count; 253 254 lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing; 255 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0; 256 257 258 if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) { 259 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 260 link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED; 261 } 262 263 core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL, 264 &downspread.raw, sizeof(downspread)); 265 266 core_link_write_dpcd(link, DP_LANE_COUNT_SET, 267 &lane_count_set.raw, 1); 268 269 rate = get_dpcd_link_rate(<_settings->link_settings); 270 271 /* Vendor specific: Toggle link rate */ 272 toggle_rate = (rate == 0x6) ? 0xA : 0x6; 273 274 if (link->vendor_specific_lttpr_link_rate_wa == rate || link->vendor_specific_lttpr_link_rate_wa == 0) { 275 core_link_write_dpcd( 276 link, 277 DP_LINK_BW_SET, 278 &toggle_rate, 279 1); 280 } 281 282 link->vendor_specific_lttpr_link_rate_wa = rate; 283 284 core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1); 285 286 DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n", 287 __func__, 288 DP_LINK_BW_SET, 289 lt_settings->link_settings.link_rate, 290 DP_LANE_COUNT_SET, 291 lt_settings->link_settings.lane_count, 292 lt_settings->enhanced_framing, 293 DP_DOWNSPREAD_CTRL, 294 lt_settings->link_settings.link_spread); 295 296 if (lt_settings->link_settings.lane_count == LANE_COUNT_FOUR) { 297 link_configure_fixed_vs_pe_retimer(link->ddc, 298 &vendor_lttpr_write_data_4lane_1[0], sizeof(vendor_lttpr_write_data_4lane_1)); 299 link_configure_fixed_vs_pe_retimer(link->ddc, 300 &vendor_lttpr_write_data_4lane_2[0], sizeof(vendor_lttpr_write_data_4lane_2)); 301 link_configure_fixed_vs_pe_retimer(link->ddc, 302 &vendor_lttpr_write_data_4lane_3[0], sizeof(vendor_lttpr_write_data_4lane_3)); 303 link_configure_fixed_vs_pe_retimer(link->ddc, 304 &vendor_lttpr_write_data_4lane_4[0], sizeof(vendor_lttpr_write_data_4lane_4)); 305 link_configure_fixed_vs_pe_retimer(link->ddc, 306 &vendor_lttpr_write_data_4lane_5[0], sizeof(vendor_lttpr_write_data_4lane_5)); 307 } 308 309 /* 2. Perform link training */ 310 311 /* Perform Clock Recovery Sequence */ 312 if (status == LINK_TRAINING_SUCCESS) { 313 const uint8_t max_vendor_dpcd_retries = 10; 314 uint32_t retries_cr; 315 uint32_t retry_count; 316 uint32_t wait_time_microsec; 317 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; 318 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX]; 319 union lane_align_status_updated dpcd_lane_status_updated; 320 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; 321 uint8_t i = 0; 322 323 retries_cr = 0; 324 retry_count = 0; 325 326 memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status)); 327 memset(&dpcd_lane_status_updated, '\0', 328 sizeof(dpcd_lane_status_updated)); 329 330 while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) && 331 (retry_count < LINK_TRAINING_MAX_CR_RETRY)) { 332 333 334 /* 1. call HWSS to set lane settings */ 335 dp_set_hw_lane_settings( 336 link, 337 link_res, 338 lt_settings, 339 0); 340 341 /* 2. update DPCD of the receiver */ 342 if (!retry_count) { 343 /* EPR #361076 - write as a 5-byte burst, 344 * but only for the 1-st iteration. 345 */ 346 dpcd_set_lt_pattern_and_lane_settings( 347 link, 348 lt_settings, 349 lt_settings->pattern_for_cr, 350 0); 351 /* Vendor specific: Disable intercept */ 352 for (i = 0; i < max_vendor_dpcd_retries; i++) { 353 if (pre_disable_intercept_delay_ms != 0) 354 drm_msleep(pre_disable_intercept_delay_ms); 355 if (link_configure_fixed_vs_pe_retimer(link->ddc, 356 &vendor_lttpr_write_data_intercept_dis[0], 357 sizeof(vendor_lttpr_write_data_intercept_dis))) 358 break; 359 360 link_configure_fixed_vs_pe_retimer(link->ddc, 361 &vendor_lttpr_write_data_intercept_en[0], 362 sizeof(vendor_lttpr_write_data_intercept_en)); 363 } 364 } else { 365 vendor_lttpr_write_data_vs[3] = 0; 366 vendor_lttpr_write_data_pe[3] = 0; 367 368 for (lane = 0; lane < lane_count; lane++) { 369 vendor_lttpr_write_data_vs[3] |= 370 lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane); 371 vendor_lttpr_write_data_pe[3] |= 372 lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane); 373 } 374 375 /* Vendor specific: Update VS and PE to DPRX requested value */ 376 link_configure_fixed_vs_pe_retimer(link->ddc, 377 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs)); 378 link_configure_fixed_vs_pe_retimer(link->ddc, 379 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe)); 380 381 dpcd_set_lane_settings( 382 link, 383 lt_settings, 384 0); 385 } 386 387 /* 3. wait receiver to lock-on*/ 388 wait_time_microsec = lt_settings->cr_pattern_time; 389 390 dp_wait_for_training_aux_rd_interval( 391 link, 392 wait_time_microsec); 393 394 /* 4. Read lane status and requested drive 395 * settings as set by the sink 396 */ 397 dp_get_lane_status_and_lane_adjust( 398 link, 399 lt_settings, 400 dpcd_lane_status, 401 &dpcd_lane_status_updated, 402 dpcd_lane_adjust, 403 0); 404 405 /* 5. check CR done*/ 406 if (dp_is_cr_done(lane_count, dpcd_lane_status)) { 407 status = LINK_TRAINING_SUCCESS; 408 break; 409 } 410 411 /* 6. max VS reached*/ 412 if (dp_is_max_vs_reached(lt_settings)) 413 break; 414 415 /* 7. same lane settings */ 416 /* Note: settings are the same for all lanes, 417 * so comparing first lane is sufficient 418 */ 419 if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET == 420 dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE) 421 retries_cr++; 422 else 423 retries_cr = 0; 424 425 /* 8. update VS/PE/PC2 in lt_settings*/ 426 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, 427 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); 428 retry_count++; 429 } 430 431 if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) { 432 ASSERT(0); 433 DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue", 434 __func__, 435 LINK_TRAINING_MAX_CR_RETRY); 436 437 } 438 439 status = dp_get_cr_failure(lane_count, dpcd_lane_status); 440 } 441 442 /* Perform Channel EQ Sequence */ 443 if (status == LINK_TRAINING_SUCCESS) { 444 enum dc_dp_training_pattern tr_pattern; 445 uint32_t retries_ch_eq; 446 uint32_t wait_time_microsec; 447 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; 448 union lane_align_status_updated dpcd_lane_status_updated = {0}; 449 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; 450 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; 451 452 /* Note: also check that TPS4 is a supported feature*/ 453 tr_pattern = lt_settings->pattern_for_eq; 454 455 dp_set_hw_training_pattern(link, link_res, tr_pattern, 0); 456 457 status = LINK_TRAINING_EQ_FAIL_EQ; 458 459 for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT; 460 retries_ch_eq++) { 461 462 dp_set_hw_lane_settings(link, link_res, lt_settings, 0); 463 464 vendor_lttpr_write_data_vs[3] = 0; 465 vendor_lttpr_write_data_pe[3] = 0; 466 467 for (lane = 0; lane < lane_count; lane++) { 468 vendor_lttpr_write_data_vs[3] |= 469 lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane); 470 vendor_lttpr_write_data_pe[3] |= 471 lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane); 472 } 473 474 /* Vendor specific: Update VS and PE to DPRX requested value */ 475 link_configure_fixed_vs_pe_retimer(link->ddc, 476 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs)); 477 link_configure_fixed_vs_pe_retimer(link->ddc, 478 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe)); 479 480 /* 2. update DPCD*/ 481 if (!retries_ch_eq) 482 /* EPR #361076 - write as a 5-byte burst, 483 * but only for the 1-st iteration 484 */ 485 486 dpcd_set_lt_pattern_and_lane_settings( 487 link, 488 lt_settings, 489 tr_pattern, 0); 490 else 491 dpcd_set_lane_settings(link, lt_settings, 0); 492 493 /* 3. wait for receiver to lock-on*/ 494 wait_time_microsec = lt_settings->eq_pattern_time; 495 496 dp_wait_for_training_aux_rd_interval( 497 link, 498 wait_time_microsec); 499 500 /* 4. Read lane status and requested 501 * drive settings as set by the sink 502 */ 503 dp_get_lane_status_and_lane_adjust( 504 link, 505 lt_settings, 506 dpcd_lane_status, 507 &dpcd_lane_status_updated, 508 dpcd_lane_adjust, 509 0); 510 511 /* 5. check CR done*/ 512 if (!dp_is_cr_done(lane_count, dpcd_lane_status)) { 513 status = LINK_TRAINING_EQ_FAIL_CR; 514 break; 515 } 516 517 /* 6. check CHEQ done*/ 518 if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) && 519 dp_is_symbol_locked(lane_count, dpcd_lane_status) && 520 dp_is_interlane_aligned(dpcd_lane_status_updated)) { 521 status = LINK_TRAINING_SUCCESS; 522 break; 523 } 524 525 /* 7. update VS/PE/PC2 in lt_settings*/ 526 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, 527 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); 528 } 529 } 530 531 return status; 532} 533 534enum link_training_result dp_perform_fixed_vs_pe_training_sequence( 535 struct dc_link *link, 536 const struct link_resource *link_res, 537 struct link_training_settings *lt_settings) 538{ 539 const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF}; 540 const uint8_t offset = dp_parse_lttpr_repeater_count( 541 link->dpcd_caps.lttpr_caps.phy_repeater_cnt); 542 const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0}; 543 const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x6E}; 544 const uint8_t vendor_lttpr_write_data_adicora_eq1[4] = {0x1, 0x55, 0x63, 0x2E}; 545 const uint8_t vendor_lttpr_write_data_adicora_eq2[4] = {0x1, 0x55, 0x63, 0x01}; 546 const uint8_t vendor_lttpr_write_data_adicora_eq3[4] = {0x1, 0x55, 0x63, 0x68}; 547 uint32_t pre_disable_intercept_delay_ms = 0; 548 uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0}; 549 uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0}; 550 const uint8_t vendor_lttpr_write_data_4lane_1[4] = {0x1, 0x6E, 0xF2, 0x19}; 551 const uint8_t vendor_lttpr_write_data_4lane_2[4] = {0x1, 0x6B, 0xF2, 0x01}; 552 const uint8_t vendor_lttpr_write_data_4lane_3[4] = {0x1, 0x6D, 0xF2, 0x18}; 553 const uint8_t vendor_lttpr_write_data_4lane_4[4] = {0x1, 0x6C, 0xF2, 0x03}; 554 const uint8_t vendor_lttpr_write_data_4lane_5[4] = {0x1, 0x03, 0xF3, 0x06}; 555 enum link_training_result status = LINK_TRAINING_SUCCESS; 556 uint8_t lane = 0; 557 union down_spread_ctrl downspread = {0}; 558 union lane_count_set lane_count_set = {0}; 559 uint8_t toggle_rate; 560 uint8_t rate; 561 562 /* Only 8b/10b is supported */ 563 ASSERT(link_dp_get_encoding_format(<_settings->link_settings) == 564 DP_8b_10b_ENCODING); 565 566 if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { 567 status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings); 568 return status; 569 } 570 571 if (offset != 0xFF) { 572 if (offset == 2) { 573 pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa; 574 575 /* Certain display and cable configuration require extra delay */ 576 } else if (offset > 2) { 577 pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2; 578 } 579 } 580 581 /* Vendor specific: Reset lane settings */ 582 link_configure_fixed_vs_pe_retimer(link->ddc, 583 &vendor_lttpr_write_data_reset[0], sizeof(vendor_lttpr_write_data_reset)); 584 link_configure_fixed_vs_pe_retimer(link->ddc, 585 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs)); 586 link_configure_fixed_vs_pe_retimer(link->ddc, 587 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe)); 588 589 /* Vendor specific: Enable intercept */ 590 link_configure_fixed_vs_pe_retimer(link->ddc, 591 &vendor_lttpr_write_data_intercept_en[0], sizeof(vendor_lttpr_write_data_intercept_en)); 592 593 /* 1. set link rate, lane count and spread. */ 594 595 downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread); 596 597 lane_count_set.bits.LANE_COUNT_SET = 598 lt_settings->link_settings.lane_count; 599 600 lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing; 601 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0; 602 603 604 if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) { 605 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 606 link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED; 607 } 608 609 core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL, 610 &downspread.raw, sizeof(downspread)); 611 612 core_link_write_dpcd(link, DP_LANE_COUNT_SET, 613 &lane_count_set.raw, 1); 614 615 rate = get_dpcd_link_rate(<_settings->link_settings); 616 617 /* Vendor specific: Toggle link rate */ 618 toggle_rate = (rate == 0x6) ? 0xA : 0x6; 619 620 if (link->vendor_specific_lttpr_link_rate_wa == rate || link->vendor_specific_lttpr_link_rate_wa == 0) { 621 core_link_write_dpcd( 622 link, 623 DP_LINK_BW_SET, 624 &toggle_rate, 625 1); 626 } 627 628 link->vendor_specific_lttpr_link_rate_wa = rate; 629 630 core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1); 631 632 DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n", 633 __func__, 634 DP_LINK_BW_SET, 635 lt_settings->link_settings.link_rate, 636 DP_LANE_COUNT_SET, 637 lt_settings->link_settings.lane_count, 638 lt_settings->enhanced_framing, 639 DP_DOWNSPREAD_CTRL, 640 lt_settings->link_settings.link_spread); 641 642 if (lt_settings->link_settings.lane_count == LANE_COUNT_FOUR) { 643 link_configure_fixed_vs_pe_retimer(link->ddc, 644 &vendor_lttpr_write_data_4lane_1[0], sizeof(vendor_lttpr_write_data_4lane_1)); 645 link_configure_fixed_vs_pe_retimer(link->ddc, 646 &vendor_lttpr_write_data_4lane_2[0], sizeof(vendor_lttpr_write_data_4lane_2)); 647 link_configure_fixed_vs_pe_retimer(link->ddc, 648 &vendor_lttpr_write_data_4lane_3[0], sizeof(vendor_lttpr_write_data_4lane_3)); 649 link_configure_fixed_vs_pe_retimer(link->ddc, 650 &vendor_lttpr_write_data_4lane_4[0], sizeof(vendor_lttpr_write_data_4lane_4)); 651 link_configure_fixed_vs_pe_retimer(link->ddc, 652 &vendor_lttpr_write_data_4lane_5[0], sizeof(vendor_lttpr_write_data_4lane_5)); 653 } 654 655 /* 2. Perform link training */ 656 657 /* Perform Clock Recovery Sequence */ 658 if (status == LINK_TRAINING_SUCCESS) { 659 const uint8_t max_vendor_dpcd_retries = 10; 660 uint32_t retries_cr; 661 uint32_t retry_count; 662 uint32_t wait_time_microsec; 663 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; 664 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX]; 665 union lane_align_status_updated dpcd_lane_status_updated; 666 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; 667 uint8_t i = 0; 668 669 retries_cr = 0; 670 retry_count = 0; 671 672 memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status)); 673 memset(&dpcd_lane_status_updated, '\0', 674 sizeof(dpcd_lane_status_updated)); 675 676 while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) && 677 (retry_count < LINK_TRAINING_MAX_CR_RETRY)) { 678 679 680 /* 1. call HWSS to set lane settings */ 681 dp_set_hw_lane_settings( 682 link, 683 link_res, 684 lt_settings, 685 0); 686 687 /* 2. update DPCD of the receiver */ 688 if (!retry_count) { 689 /* EPR #361076 - write as a 5-byte burst, 690 * but only for the 1-st iteration. 691 */ 692 dpcd_set_lt_pattern_and_lane_settings( 693 link, 694 lt_settings, 695 lt_settings->pattern_for_cr, 696 0); 697 /* Vendor specific: Disable intercept */ 698 for (i = 0; i < max_vendor_dpcd_retries; i++) { 699 if (pre_disable_intercept_delay_ms != 0) 700 drm_msleep(pre_disable_intercept_delay_ms); 701 if (link_configure_fixed_vs_pe_retimer(link->ddc, 702 &vendor_lttpr_write_data_intercept_dis[0], 703 sizeof(vendor_lttpr_write_data_intercept_dis))) 704 break; 705 706 link_configure_fixed_vs_pe_retimer(link->ddc, 707 &vendor_lttpr_write_data_intercept_en[0], 708 sizeof(vendor_lttpr_write_data_intercept_en)); 709 } 710 } else { 711 vendor_lttpr_write_data_vs[3] = 0; 712 vendor_lttpr_write_data_pe[3] = 0; 713 714 for (lane = 0; lane < lane_count; lane++) { 715 vendor_lttpr_write_data_vs[3] |= 716 lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane); 717 vendor_lttpr_write_data_pe[3] |= 718 lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane); 719 } 720 721 /* Vendor specific: Update VS and PE to DPRX requested value */ 722 link_configure_fixed_vs_pe_retimer(link->ddc, 723 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs)); 724 link_configure_fixed_vs_pe_retimer(link->ddc, 725 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe)); 726 727 dpcd_set_lane_settings( 728 link, 729 lt_settings, 730 0); 731 } 732 733 /* 3. wait receiver to lock-on*/ 734 wait_time_microsec = lt_settings->cr_pattern_time; 735 736 dp_wait_for_training_aux_rd_interval( 737 link, 738 wait_time_microsec); 739 740 /* 4. Read lane status and requested drive 741 * settings as set by the sink 742 */ 743 dp_get_lane_status_and_lane_adjust( 744 link, 745 lt_settings, 746 dpcd_lane_status, 747 &dpcd_lane_status_updated, 748 dpcd_lane_adjust, 749 0); 750 751 /* 5. check CR done*/ 752 if (dp_is_cr_done(lane_count, dpcd_lane_status)) { 753 status = LINK_TRAINING_SUCCESS; 754 break; 755 } 756 757 /* 6. max VS reached*/ 758 if (dp_is_max_vs_reached(lt_settings)) 759 break; 760 761 /* 7. same lane settings */ 762 /* Note: settings are the same for all lanes, 763 * so comparing first lane is sufficient 764 */ 765 if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET == 766 dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE) 767 retries_cr++; 768 else 769 retries_cr = 0; 770 771 /* 8. update VS/PE/PC2 in lt_settings*/ 772 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, 773 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); 774 retry_count++; 775 } 776 777 if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) { 778 ASSERT(0); 779 DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue", 780 __func__, 781 LINK_TRAINING_MAX_CR_RETRY); 782 783 } 784 785 status = dp_get_cr_failure(lane_count, dpcd_lane_status); 786 } 787 788 /* Perform Channel EQ Sequence */ 789 if (status == LINK_TRAINING_SUCCESS) { 790 enum dc_dp_training_pattern tr_pattern; 791 uint32_t retries_ch_eq; 792 uint32_t wait_time_microsec; 793 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; 794 union lane_align_status_updated dpcd_lane_status_updated = {0}; 795 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; 796 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; 797 798 link_configure_fixed_vs_pe_retimer(link->ddc, 799 &vendor_lttpr_write_data_adicora_eq1[0], 800 sizeof(vendor_lttpr_write_data_adicora_eq1)); 801 link_configure_fixed_vs_pe_retimer(link->ddc, 802 &vendor_lttpr_write_data_adicora_eq2[0], 803 sizeof(vendor_lttpr_write_data_adicora_eq2)); 804 805 806 /* Note: also check that TPS4 is a supported feature*/ 807 tr_pattern = lt_settings->pattern_for_eq; 808 809 dp_set_hw_training_pattern(link, link_res, tr_pattern, 0); 810 811 status = LINK_TRAINING_EQ_FAIL_EQ; 812 813 for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT; 814 retries_ch_eq++) { 815 816 dp_set_hw_lane_settings(link, link_res, lt_settings, 0); 817 818 vendor_lttpr_write_data_vs[3] = 0; 819 vendor_lttpr_write_data_pe[3] = 0; 820 821 for (lane = 0; lane < lane_count; lane++) { 822 vendor_lttpr_write_data_vs[3] |= 823 lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane); 824 vendor_lttpr_write_data_pe[3] |= 825 lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane); 826 } 827 828 /* Vendor specific: Update VS and PE to DPRX requested value */ 829 link_configure_fixed_vs_pe_retimer(link->ddc, 830 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs)); 831 link_configure_fixed_vs_pe_retimer(link->ddc, 832 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe)); 833 834 /* 2. update DPCD*/ 835 if (!retries_ch_eq) { 836 /* EPR #361076 - write as a 5-byte burst, 837 * but only for the 1-st iteration 838 */ 839 840 dpcd_set_lt_pattern_and_lane_settings( 841 link, 842 lt_settings, 843 tr_pattern, 0); 844 845 link_configure_fixed_vs_pe_retimer(link->ddc, 846 &vendor_lttpr_write_data_adicora_eq3[0], 847 sizeof(vendor_lttpr_write_data_adicora_eq3)); 848 849 } else 850 dpcd_set_lane_settings(link, lt_settings, 0); 851 852 /* 3. wait for receiver to lock-on*/ 853 wait_time_microsec = lt_settings->eq_pattern_time; 854 855 dp_wait_for_training_aux_rd_interval( 856 link, 857 wait_time_microsec); 858 859 /* 4. Read lane status and requested 860 * drive settings as set by the sink 861 */ 862 dp_get_lane_status_and_lane_adjust( 863 link, 864 lt_settings, 865 dpcd_lane_status, 866 &dpcd_lane_status_updated, 867 dpcd_lane_adjust, 868 0); 869 870 /* 5. check CR done*/ 871 if (!dp_is_cr_done(lane_count, dpcd_lane_status)) { 872 status = LINK_TRAINING_EQ_FAIL_CR; 873 break; 874 } 875 876 /* 6. check CHEQ done*/ 877 if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) && 878 dp_is_symbol_locked(lane_count, dpcd_lane_status) && 879 dp_is_interlane_aligned(dpcd_lane_status_updated)) { 880 status = LINK_TRAINING_SUCCESS; 881 break; 882 } 883 884 /* 7. update VS/PE/PC2 in lt_settings*/ 885 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, 886 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); 887 } 888 } 889 890 return status; 891} 892