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 40 #define DC_LOGGER \ 41 link->ctx->logger 42 43 void dp_fixed_vs_pe_read_lane_adjust( 44 struct dc_link *link, 45 union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX]) 46 { 47 const uint8_t vendor_lttpr_write_data_vs[3] = {0x0, 0x53, 0x63}; 48 const uint8_t vendor_lttpr_write_data_pe[3] = {0x0, 0x54, 0x63}; 49 const uint8_t offset = dp_parse_lttpr_repeater_count( 50 link->dpcd_caps.lttpr_caps.phy_repeater_cnt); 51 uint32_t vendor_lttpr_write_address = 0xF004F; 52 uint32_t vendor_lttpr_read_address = 0xF0053; 53 uint8_t dprx_vs = 0; 54 uint8_t dprx_pe = 0; 55 uint8_t lane; 56 57 if (offset != 0xFF) { 58 vendor_lttpr_write_address += 59 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); 60 vendor_lttpr_read_address += 61 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); 62 } 63 64 /* W/A to read lane settings requested by DPRX */ 65 core_link_write_dpcd( 66 link, 67 vendor_lttpr_write_address, 68 &vendor_lttpr_write_data_vs[0], 69 sizeof(vendor_lttpr_write_data_vs)); 70 core_link_read_dpcd( 71 link, 72 vendor_lttpr_read_address, 73 &dprx_vs, 74 1); 75 core_link_write_dpcd( 76 link, 77 vendor_lttpr_write_address, 78 &vendor_lttpr_write_data_pe[0], 79 sizeof(vendor_lttpr_write_data_pe)); 80 core_link_read_dpcd( 81 link, 82 vendor_lttpr_read_address, 83 &dprx_pe, 84 1); 85 86 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { 87 dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET = (dprx_vs >> (2 * lane)) & 0x3; 88 dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET = (dprx_pe >> (2 * lane)) & 0x3; 89 } 90 } 91 92 93 void dp_fixed_vs_pe_set_retimer_lane_settings( 94 struct dc_link *link, 95 const union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX], 96 uint8_t lane_count) 97 { 98 const uint8_t offset = dp_parse_lttpr_repeater_count( 99 link->dpcd_caps.lttpr_caps.phy_repeater_cnt); 100 const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF}; 101 uint32_t vendor_lttpr_write_address = 0xF004F; 102 uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0}; 103 uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0}; 104 uint8_t lane = 0; 105 106 if (offset != 0xFF) { 107 vendor_lttpr_write_address += 108 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); 109 } 110 111 for (lane = 0; lane < lane_count; lane++) { 112 vendor_lttpr_write_data_vs[3] |= 113 dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET << (2 * lane); 114 vendor_lttpr_write_data_pe[3] |= 115 dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET << (2 * lane); 116 } 117 118 /* Force LTTPR to output desired VS and PE */ 119 core_link_write_dpcd( 120 link, 121 vendor_lttpr_write_address, 122 &vendor_lttpr_write_data_reset[0], 123 sizeof(vendor_lttpr_write_data_reset)); 124 core_link_write_dpcd( 125 link, 126 vendor_lttpr_write_address, 127 &vendor_lttpr_write_data_vs[0], 128 sizeof(vendor_lttpr_write_data_vs)); 129 core_link_write_dpcd( 130 link, 131 vendor_lttpr_write_address, 132 &vendor_lttpr_write_data_pe[0], 133 sizeof(vendor_lttpr_write_data_pe)); 134 } 135 136 static enum link_training_result perform_fixed_vs_pe_nontransparent_training_sequence( 137 struct dc_link *link, 138 const struct link_resource *link_res, 139 struct link_training_settings *lt_settings) 140 { 141 enum link_training_result status = LINK_TRAINING_SUCCESS; 142 uint8_t lane = 0; 143 uint8_t toggle_rate = 0x6; 144 uint8_t target_rate = 0x6; 145 bool apply_toggle_rate_wa = false; 146 uint8_t repeater_cnt; 147 uint8_t repeater_id; 148 149 /* Fixed VS/PE specific: Force CR AUX RD Interval to at least 16ms */ 150 if (lt_settings->cr_pattern_time < 16000) 151 lt_settings->cr_pattern_time = 16000; 152 153 /* Fixed VS/PE specific: Toggle link rate */ 154 apply_toggle_rate_wa = (link->vendor_specific_lttpr_link_rate_wa == target_rate); 155 target_rate = get_dpcd_link_rate(<_settings->link_settings); 156 toggle_rate = (target_rate == 0x6) ? 0xA : 0x6; 157 158 if (apply_toggle_rate_wa) 159 lt_settings->link_settings.link_rate = toggle_rate; 160 161 if (link->ctx->dc->work_arounds.lt_early_cr_pattern) 162 start_clock_recovery_pattern_early(link, link_res, lt_settings, DPRX); 163 164 /* 1. set link rate, lane count and spread. */ 165 dpcd_set_link_settings(link, lt_settings); 166 167 /* Fixed VS/PE specific: Toggle link rate back*/ 168 if (apply_toggle_rate_wa) { 169 core_link_write_dpcd( 170 link, 171 DP_LINK_BW_SET, 172 &target_rate, 173 1); 174 } 175 176 link->vendor_specific_lttpr_link_rate_wa = target_rate; 177 178 if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { 179 180 /* 2. perform link training (set link training done 181 * to false is done as well) 182 */ 183 repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt); 184 185 for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS); 186 repeater_id--) { 187 status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, repeater_id); 188 189 if (status != LINK_TRAINING_SUCCESS) { 190 repeater_training_done(link, repeater_id); 191 break; 192 } 193 194 status = perform_8b_10b_channel_equalization_sequence(link, 195 link_res, 196 lt_settings, 197 repeater_id); 198 199 repeater_training_done(link, repeater_id); 200 201 if (status != LINK_TRAINING_SUCCESS) 202 break; 203 204 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { 205 lt_settings->dpcd_lane_settings[lane].raw = 0; 206 lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0; 207 lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0; 208 } 209 } 210 } 211 212 if (status == LINK_TRAINING_SUCCESS) { 213 status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, DPRX); 214 if (status == LINK_TRAINING_SUCCESS) { 215 status = perform_8b_10b_channel_equalization_sequence(link, 216 link_res, 217 lt_settings, 218 DPRX); 219 } 220 } 221 222 return status; 223 } 224 225 226 enum link_training_result dp_perform_fixed_vs_pe_training_sequence( 227 struct dc_link *link, 228 const struct link_resource *link_res, 229 struct link_training_settings *lt_settings) 230 { 231 const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF}; 232 const uint8_t offset = dp_parse_lttpr_repeater_count( 233 link->dpcd_caps.lttpr_caps.phy_repeater_cnt); 234 const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0}; 235 const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x68}; 236 uint32_t pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa; 237 uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0}; 238 uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0}; 239 uint32_t vendor_lttpr_write_address = 0xF004F; 240 enum link_training_result status = LINK_TRAINING_SUCCESS; 241 uint8_t lane = 0; 242 union down_spread_ctrl downspread = {0}; 243 union lane_count_set lane_count_set = {0}; 244 uint8_t toggle_rate; 245 uint8_t rate; 246 247 /* Only 8b/10b is supported */ 248 ASSERT(link_dp_get_encoding_format(<_settings->link_settings) == 249 DP_8b_10b_ENCODING); 250 251 if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { 252 status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings); 253 return status; 254 } 255 256 if (offset != 0xFF) { 257 vendor_lttpr_write_address += 258 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); 259 260 /* Certain display and cable configuration require extra delay */ 261 if (offset > 2) 262 pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2; 263 } 264 265 /* Vendor specific: Reset lane settings */ 266 core_link_write_dpcd( 267 link, 268 vendor_lttpr_write_address, 269 &vendor_lttpr_write_data_reset[0], 270 sizeof(vendor_lttpr_write_data_reset)); 271 core_link_write_dpcd( 272 link, 273 vendor_lttpr_write_address, 274 &vendor_lttpr_write_data_vs[0], 275 sizeof(vendor_lttpr_write_data_vs)); 276 core_link_write_dpcd( 277 link, 278 vendor_lttpr_write_address, 279 &vendor_lttpr_write_data_pe[0], 280 sizeof(vendor_lttpr_write_data_pe)); 281 282 /* Vendor specific: Enable intercept */ 283 core_link_write_dpcd( 284 link, 285 vendor_lttpr_write_address, 286 &vendor_lttpr_write_data_intercept_en[0], 287 sizeof(vendor_lttpr_write_data_intercept_en)); 288 289 /* 1. set link rate, lane count and spread. */ 290 291 downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread); 292 293 lane_count_set.bits.LANE_COUNT_SET = 294 lt_settings->link_settings.lane_count; 295 296 lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing; 297 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0; 298 299 300 if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) { 301 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 302 link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED; 303 } 304 305 core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL, 306 &downspread.raw, sizeof(downspread)); 307 308 core_link_write_dpcd(link, DP_LANE_COUNT_SET, 309 &lane_count_set.raw, 1); 310 311 rate = get_dpcd_link_rate(<_settings->link_settings); 312 313 /* Vendor specific: Toggle link rate */ 314 toggle_rate = (rate == 0x6) ? 0xA : 0x6; 315 316 if (link->vendor_specific_lttpr_link_rate_wa == rate) { 317 core_link_write_dpcd( 318 link, 319 DP_LINK_BW_SET, 320 &toggle_rate, 321 1); 322 } 323 324 link->vendor_specific_lttpr_link_rate_wa = rate; 325 326 core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1); 327 328 DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n", 329 __func__, 330 DP_LINK_BW_SET, 331 lt_settings->link_settings.link_rate, 332 DP_LANE_COUNT_SET, 333 lt_settings->link_settings.lane_count, 334 lt_settings->enhanced_framing, 335 DP_DOWNSPREAD_CTRL, 336 lt_settings->link_settings.link_spread); 337 338 /* 2. Perform link training */ 339 340 /* Perform Clock Recovery Sequence */ 341 if (status == LINK_TRAINING_SUCCESS) { 342 const uint8_t max_vendor_dpcd_retries = 10; 343 uint32_t retries_cr; 344 uint32_t retry_count; 345 uint32_t wait_time_microsec; 346 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; 347 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX]; 348 union lane_align_status_updated dpcd_lane_status_updated; 349 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; 350 enum dc_status dpcd_status = DC_OK; 351 uint8_t i = 0; 352 353 retries_cr = 0; 354 retry_count = 0; 355 356 memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status)); 357 memset(&dpcd_lane_status_updated, '\0', 358 sizeof(dpcd_lane_status_updated)); 359 360 while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) && 361 (retry_count < LINK_TRAINING_MAX_CR_RETRY)) { 362 363 364 /* 1. call HWSS to set lane settings */ 365 dp_set_hw_lane_settings( 366 link, 367 link_res, 368 lt_settings, 369 0); 370 371 /* 2. update DPCD of the receiver */ 372 if (!retry_count) { 373 /* EPR #361076 - write as a 5-byte burst, 374 * but only for the 1-st iteration. 375 */ 376 dpcd_set_lt_pattern_and_lane_settings( 377 link, 378 lt_settings, 379 lt_settings->pattern_for_cr, 380 0); 381 /* Vendor specific: Disable intercept */ 382 for (i = 0; i < max_vendor_dpcd_retries; i++) { 383 msleep(pre_disable_intercept_delay_ms); 384 dpcd_status = core_link_write_dpcd( 385 link, 386 vendor_lttpr_write_address, 387 &vendor_lttpr_write_data_intercept_dis[0], 388 sizeof(vendor_lttpr_write_data_intercept_dis)); 389 390 if (dpcd_status == DC_OK) 391 break; 392 393 core_link_write_dpcd( 394 link, 395 vendor_lttpr_write_address, 396 &vendor_lttpr_write_data_intercept_en[0], 397 sizeof(vendor_lttpr_write_data_intercept_en)); 398 } 399 } else { 400 vendor_lttpr_write_data_vs[3] = 0; 401 vendor_lttpr_write_data_pe[3] = 0; 402 403 for (lane = 0; lane < lane_count; lane++) { 404 vendor_lttpr_write_data_vs[3] |= 405 lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane); 406 vendor_lttpr_write_data_pe[3] |= 407 lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane); 408 } 409 410 /* Vendor specific: Update VS and PE to DPRX requested value */ 411 core_link_write_dpcd( 412 link, 413 vendor_lttpr_write_address, 414 &vendor_lttpr_write_data_vs[0], 415 sizeof(vendor_lttpr_write_data_vs)); 416 core_link_write_dpcd( 417 link, 418 vendor_lttpr_write_address, 419 &vendor_lttpr_write_data_pe[0], 420 sizeof(vendor_lttpr_write_data_pe)); 421 422 dpcd_set_lane_settings( 423 link, 424 lt_settings, 425 0); 426 } 427 428 /* 3. wait receiver to lock-on*/ 429 wait_time_microsec = lt_settings->cr_pattern_time; 430 431 dp_wait_for_training_aux_rd_interval( 432 link, 433 wait_time_microsec); 434 435 /* 4. Read lane status and requested drive 436 * settings as set by the sink 437 */ 438 dp_get_lane_status_and_lane_adjust( 439 link, 440 lt_settings, 441 dpcd_lane_status, 442 &dpcd_lane_status_updated, 443 dpcd_lane_adjust, 444 0); 445 446 /* 5. check CR done*/ 447 if (dp_is_cr_done(lane_count, dpcd_lane_status)) { 448 status = LINK_TRAINING_SUCCESS; 449 break; 450 } 451 452 /* 6. max VS reached*/ 453 if (dp_is_max_vs_reached(lt_settings)) 454 break; 455 456 /* 7. same lane settings */ 457 /* Note: settings are the same for all lanes, 458 * so comparing first lane is sufficient 459 */ 460 if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET == 461 dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE) 462 retries_cr++; 463 else 464 retries_cr = 0; 465 466 /* 8. update VS/PE/PC2 in lt_settings*/ 467 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, 468 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); 469 retry_count++; 470 } 471 472 if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) { 473 ASSERT(0); 474 DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue", 475 __func__, 476 LINK_TRAINING_MAX_CR_RETRY); 477 478 } 479 480 status = dp_get_cr_failure(lane_count, dpcd_lane_status); 481 } 482 483 /* Perform Channel EQ Sequence */ 484 if (status == LINK_TRAINING_SUCCESS) { 485 enum dc_dp_training_pattern tr_pattern; 486 uint32_t retries_ch_eq; 487 uint32_t wait_time_microsec; 488 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; 489 union lane_align_status_updated dpcd_lane_status_updated = {0}; 490 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; 491 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; 492 493 /* Note: also check that TPS4 is a supported feature*/ 494 tr_pattern = lt_settings->pattern_for_eq; 495 496 dp_set_hw_training_pattern(link, link_res, tr_pattern, 0); 497 498 status = LINK_TRAINING_EQ_FAIL_EQ; 499 500 for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT; 501 retries_ch_eq++) { 502 503 dp_set_hw_lane_settings(link, link_res, lt_settings, 0); 504 505 vendor_lttpr_write_data_vs[3] = 0; 506 vendor_lttpr_write_data_pe[3] = 0; 507 508 for (lane = 0; lane < lane_count; lane++) { 509 vendor_lttpr_write_data_vs[3] |= 510 lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane); 511 vendor_lttpr_write_data_pe[3] |= 512 lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane); 513 } 514 515 /* Vendor specific: Update VS and PE to DPRX requested value */ 516 core_link_write_dpcd( 517 link, 518 vendor_lttpr_write_address, 519 &vendor_lttpr_write_data_vs[0], 520 sizeof(vendor_lttpr_write_data_vs)); 521 core_link_write_dpcd( 522 link, 523 vendor_lttpr_write_address, 524 &vendor_lttpr_write_data_pe[0], 525 sizeof(vendor_lttpr_write_data_pe)); 526 527 /* 2. update DPCD*/ 528 if (!retries_ch_eq) 529 /* EPR #361076 - write as a 5-byte burst, 530 * but only for the 1-st iteration 531 */ 532 533 dpcd_set_lt_pattern_and_lane_settings( 534 link, 535 lt_settings, 536 tr_pattern, 0); 537 else 538 dpcd_set_lane_settings(link, lt_settings, 0); 539 540 /* 3. wait for receiver to lock-on*/ 541 wait_time_microsec = lt_settings->eq_pattern_time; 542 543 dp_wait_for_training_aux_rd_interval( 544 link, 545 wait_time_microsec); 546 547 /* 4. Read lane status and requested 548 * drive settings as set by the sink 549 */ 550 dp_get_lane_status_and_lane_adjust( 551 link, 552 lt_settings, 553 dpcd_lane_status, 554 &dpcd_lane_status_updated, 555 dpcd_lane_adjust, 556 0); 557 558 /* 5. check CR done*/ 559 if (!dp_is_cr_done(lane_count, dpcd_lane_status)) { 560 status = LINK_TRAINING_EQ_FAIL_CR; 561 break; 562 } 563 564 /* 6. check CHEQ done*/ 565 if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) && 566 dp_is_symbol_locked(lane_count, dpcd_lane_status) && 567 dp_is_interlane_aligned(dpcd_lane_status_updated)) { 568 status = LINK_TRAINING_SUCCESS; 569 break; 570 } 571 572 /* 7. update VS/PE/PC2 in lt_settings*/ 573 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, 574 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); 575 } 576 } 577 578 return status; 579 } 580