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 all generic dp link training helper functions and top 28 * level generic training sequence. All variations of dp link training sequence 29 * should be called inside the top level training functions in this file to 30 * ensure the integrity of our overall training procedure across different types 31 * of link encoding and back end hardware. 32 */ 33#include "link_dp_training.h" 34#include "link_dp_training_8b_10b.h" 35#include "link_dp_training_128b_132b.h" 36#include "link_dp_training_auxless.h" 37#include "link_dp_training_dpia.h" 38#include "link_dp_training_fixed_vs_pe_retimer.h" 39#include "link_dpcd.h" 40#include "link/accessories/link_dp_trace.h" 41#include "link_dp_phy.h" 42#include "link_dp_capability.h" 43#include "link_edp_panel_control.h" 44#include "link/link_detection.h" 45#include "link/link_validation.h" 46#include "atomfirmware.h" 47#include "link_enc_cfg.h" 48#include "resource.h" 49#include "dm_helpers.h" 50 51#define DC_LOGGER \ 52 link->ctx->logger 53 54#define POST_LT_ADJ_REQ_LIMIT 6 55#define POST_LT_ADJ_REQ_TIMEOUT 200 56#define LINK_TRAINING_RETRY_DELAY 50 /* ms */ 57 58void dp_log_training_result( 59 struct dc_link *link, 60 const struct link_training_settings *lt_settings, 61 enum link_training_result status) 62{ 63 char *link_rate = "Unknown"; 64 char *lt_result = "Unknown"; 65 char *lt_spread = "Disabled"; 66 67 switch (lt_settings->link_settings.link_rate) { 68 case LINK_RATE_LOW: 69 link_rate = "RBR"; 70 break; 71 case LINK_RATE_RATE_2: 72 link_rate = "R2"; 73 break; 74 case LINK_RATE_RATE_3: 75 link_rate = "R3"; 76 break; 77 case LINK_RATE_HIGH: 78 link_rate = "HBR"; 79 break; 80 case LINK_RATE_RBR2: 81 link_rate = "RBR2"; 82 break; 83 case LINK_RATE_RATE_6: 84 link_rate = "R6"; 85 break; 86 case LINK_RATE_HIGH2: 87 link_rate = "HBR2"; 88 break; 89 case LINK_RATE_RATE_8: 90 link_rate = "R8"; 91 break; 92 case LINK_RATE_HIGH3: 93 link_rate = "HBR3"; 94 break; 95 case LINK_RATE_UHBR10: 96 link_rate = "UHBR10"; 97 break; 98 case LINK_RATE_UHBR13_5: 99 link_rate = "UHBR13.5"; 100 break; 101 case LINK_RATE_UHBR20: 102 link_rate = "UHBR20"; 103 break; 104 default: 105 break; 106 } 107 108 switch (status) { 109 case LINK_TRAINING_SUCCESS: 110 lt_result = "pass"; 111 break; 112 case LINK_TRAINING_CR_FAIL_LANE0: 113 lt_result = "CR failed lane0"; 114 break; 115 case LINK_TRAINING_CR_FAIL_LANE1: 116 lt_result = "CR failed lane1"; 117 break; 118 case LINK_TRAINING_CR_FAIL_LANE23: 119 lt_result = "CR failed lane23"; 120 break; 121 case LINK_TRAINING_EQ_FAIL_CR: 122 lt_result = "CR failed in EQ"; 123 break; 124 case LINK_TRAINING_EQ_FAIL_CR_PARTIAL: 125 lt_result = "CR failed in EQ partially"; 126 break; 127 case LINK_TRAINING_EQ_FAIL_EQ: 128 lt_result = "EQ failed"; 129 break; 130 case LINK_TRAINING_LQA_FAIL: 131 lt_result = "LQA failed"; 132 break; 133 case LINK_TRAINING_LINK_LOSS: 134 lt_result = "Link loss"; 135 break; 136 case DP_128b_132b_LT_FAILED: 137 lt_result = "LT_FAILED received"; 138 break; 139 case DP_128b_132b_MAX_LOOP_COUNT_REACHED: 140 lt_result = "max loop count reached"; 141 break; 142 case DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT: 143 lt_result = "channel EQ timeout"; 144 break; 145 case DP_128b_132b_CDS_DONE_TIMEOUT: 146 lt_result = "CDS timeout"; 147 break; 148 default: 149 break; 150 } 151 152 switch (lt_settings->link_settings.link_spread) { 153 case LINK_SPREAD_DISABLED: 154 lt_spread = "Disabled"; 155 break; 156 case LINK_SPREAD_05_DOWNSPREAD_30KHZ: 157 lt_spread = "0.5% 30KHz"; 158 break; 159 case LINK_SPREAD_05_DOWNSPREAD_33KHZ: 160 lt_spread = "0.5% 33KHz"; 161 break; 162 default: 163 break; 164 } 165 166 /* Connectivity log: link training */ 167 168 /* TODO - DP2.0 Log: add connectivity log for FFE PRESET */ 169 170 CONN_MSG_LT(link, "%sx%d %s VS=%d, PE=%d, DS=%s", 171 link_rate, 172 lt_settings->link_settings.lane_count, 173 lt_result, 174 lt_settings->hw_lane_settings[0].VOLTAGE_SWING, 175 lt_settings->hw_lane_settings[0].PRE_EMPHASIS, 176 lt_spread); 177} 178 179uint8_t dp_initialize_scrambling_data_symbols( 180 struct dc_link *link, 181 enum dc_dp_training_pattern pattern) 182{ 183 uint8_t disable_scrabled_data_symbols = 0; 184 185 switch (pattern) { 186 case DP_TRAINING_PATTERN_SEQUENCE_1: 187 case DP_TRAINING_PATTERN_SEQUENCE_2: 188 case DP_TRAINING_PATTERN_SEQUENCE_3: 189 disable_scrabled_data_symbols = 1; 190 break; 191 case DP_TRAINING_PATTERN_SEQUENCE_4: 192 case DP_128b_132b_TPS1: 193 case DP_128b_132b_TPS2: 194 disable_scrabled_data_symbols = 0; 195 break; 196 default: 197 ASSERT(0); 198 DC_LOG_HW_LINK_TRAINING("%s: Invalid HW Training pattern: %d\n", 199 __func__, pattern); 200 break; 201 } 202 return disable_scrabled_data_symbols; 203} 204 205enum dpcd_training_patterns 206 dp_training_pattern_to_dpcd_training_pattern( 207 struct dc_link *link, 208 enum dc_dp_training_pattern pattern) 209{ 210 enum dpcd_training_patterns dpcd_tr_pattern = 211 DPCD_TRAINING_PATTERN_VIDEOIDLE; 212 213 switch (pattern) { 214 case DP_TRAINING_PATTERN_SEQUENCE_1: 215 DC_LOG_HW_LINK_TRAINING("%s: Using DP training pattern TPS1\n", __func__); 216 dpcd_tr_pattern = DPCD_TRAINING_PATTERN_1; 217 break; 218 case DP_TRAINING_PATTERN_SEQUENCE_2: 219 DC_LOG_HW_LINK_TRAINING("%s: Using DP training pattern TPS2\n", __func__); 220 dpcd_tr_pattern = DPCD_TRAINING_PATTERN_2; 221 break; 222 case DP_TRAINING_PATTERN_SEQUENCE_3: 223 DC_LOG_HW_LINK_TRAINING("%s: Using DP training pattern TPS3\n", __func__); 224 dpcd_tr_pattern = DPCD_TRAINING_PATTERN_3; 225 break; 226 case DP_TRAINING_PATTERN_SEQUENCE_4: 227 DC_LOG_HW_LINK_TRAINING("%s: Using DP training pattern TPS4\n", __func__); 228 dpcd_tr_pattern = DPCD_TRAINING_PATTERN_4; 229 break; 230 case DP_128b_132b_TPS1: 231 DC_LOG_HW_LINK_TRAINING("%s: Using DP 128b/132b training pattern TPS1\n", __func__); 232 dpcd_tr_pattern = DPCD_128b_132b_TPS1; 233 break; 234 case DP_128b_132b_TPS2: 235 DC_LOG_HW_LINK_TRAINING("%s: Using DP 128b/132b training pattern TPS2\n", __func__); 236 dpcd_tr_pattern = DPCD_128b_132b_TPS2; 237 break; 238 case DP_128b_132b_TPS2_CDS: 239 DC_LOG_HW_LINK_TRAINING("%s: Using DP 128b/132b training pattern TPS2 CDS\n", 240 __func__); 241 dpcd_tr_pattern = DPCD_128b_132b_TPS2_CDS; 242 break; 243 case DP_TRAINING_PATTERN_VIDEOIDLE: 244 DC_LOG_HW_LINK_TRAINING("%s: Using DP training pattern videoidle\n", __func__); 245 dpcd_tr_pattern = DPCD_TRAINING_PATTERN_VIDEOIDLE; 246 break; 247 default: 248 ASSERT(0); 249 DC_LOG_HW_LINK_TRAINING("%s: Invalid HW Training pattern: %d\n", 250 __func__, pattern); 251 break; 252 } 253 254 return dpcd_tr_pattern; 255} 256 257uint8_t dp_get_nibble_at_index(const uint8_t *buf, 258 uint32_t index) 259{ 260 uint8_t nibble; 261 nibble = buf[index / 2]; 262 263 if (index % 2) 264 nibble >>= 4; 265 else 266 nibble &= 0x0F; 267 268 return nibble; 269} 270 271void dp_wait_for_training_aux_rd_interval( 272 struct dc_link *link, 273 uint32_t wait_in_micro_secs) 274{ 275 fsleep(wait_in_micro_secs); 276 277 DC_LOG_HW_LINK_TRAINING("%s:\n wait = %d\n", 278 __func__, 279 wait_in_micro_secs); 280} 281 282/* maximum pre emphasis level allowed for each voltage swing level*/ 283static const enum dc_pre_emphasis voltage_swing_to_pre_emphasis[] = { 284 PRE_EMPHASIS_LEVEL3, 285 PRE_EMPHASIS_LEVEL2, 286 PRE_EMPHASIS_LEVEL1, 287 PRE_EMPHASIS_DISABLED }; 288 289static enum dc_pre_emphasis get_max_pre_emphasis_for_voltage_swing( 290 enum dc_voltage_swing voltage) 291{ 292 enum dc_pre_emphasis pre_emphasis; 293 pre_emphasis = PRE_EMPHASIS_MAX_LEVEL; 294 295 if (voltage <= VOLTAGE_SWING_MAX_LEVEL) 296 pre_emphasis = voltage_swing_to_pre_emphasis[voltage]; 297 298 return pre_emphasis; 299 300} 301 302static void maximize_lane_settings(const struct link_training_settings *lt_settings, 303 struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]) 304{ 305 uint32_t lane; 306 struct dc_lane_settings max_requested; 307 308 max_requested.VOLTAGE_SWING = lane_settings[0].VOLTAGE_SWING; 309 max_requested.PRE_EMPHASIS = lane_settings[0].PRE_EMPHASIS; 310 max_requested.FFE_PRESET = lane_settings[0].FFE_PRESET; 311 312 /* Determine what the maximum of the requested settings are*/ 313 for (lane = 1; lane < lt_settings->link_settings.lane_count; lane++) { 314 if (lane_settings[lane].VOLTAGE_SWING > max_requested.VOLTAGE_SWING) 315 max_requested.VOLTAGE_SWING = lane_settings[lane].VOLTAGE_SWING; 316 317 if (lane_settings[lane].PRE_EMPHASIS > max_requested.PRE_EMPHASIS) 318 max_requested.PRE_EMPHASIS = lane_settings[lane].PRE_EMPHASIS; 319 if (lane_settings[lane].FFE_PRESET.settings.level > 320 max_requested.FFE_PRESET.settings.level) 321 max_requested.FFE_PRESET.settings.level = 322 lane_settings[lane].FFE_PRESET.settings.level; 323 } 324 325 /* make sure the requested settings are 326 * not higher than maximum settings*/ 327 if (max_requested.VOLTAGE_SWING > VOLTAGE_SWING_MAX_LEVEL) 328 max_requested.VOLTAGE_SWING = VOLTAGE_SWING_MAX_LEVEL; 329 330 if (max_requested.PRE_EMPHASIS > PRE_EMPHASIS_MAX_LEVEL) 331 max_requested.PRE_EMPHASIS = PRE_EMPHASIS_MAX_LEVEL; 332 if (max_requested.FFE_PRESET.settings.level > DP_FFE_PRESET_MAX_LEVEL) 333 max_requested.FFE_PRESET.settings.level = DP_FFE_PRESET_MAX_LEVEL; 334 335 /* make sure the pre-emphasis matches the voltage swing*/ 336 if (max_requested.PRE_EMPHASIS > 337 get_max_pre_emphasis_for_voltage_swing( 338 max_requested.VOLTAGE_SWING)) 339 max_requested.PRE_EMPHASIS = 340 get_max_pre_emphasis_for_voltage_swing( 341 max_requested.VOLTAGE_SWING); 342 343 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { 344 lane_settings[lane].VOLTAGE_SWING = max_requested.VOLTAGE_SWING; 345 lane_settings[lane].PRE_EMPHASIS = max_requested.PRE_EMPHASIS; 346 lane_settings[lane].FFE_PRESET = max_requested.FFE_PRESET; 347 } 348} 349 350void dp_hw_to_dpcd_lane_settings( 351 const struct link_training_settings *lt_settings, 352 const struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX], 353 union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX]) 354{ 355 uint8_t lane = 0; 356 357 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { 358 if (link_dp_get_encoding_format(<_settings->link_settings) == 359 DP_8b_10b_ENCODING) { 360 dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET = 361 (uint8_t)(hw_lane_settings[lane].VOLTAGE_SWING); 362 dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET = 363 (uint8_t)(hw_lane_settings[lane].PRE_EMPHASIS); 364 dpcd_lane_settings[lane].bits.MAX_SWING_REACHED = 365 (hw_lane_settings[lane].VOLTAGE_SWING == 366 VOLTAGE_SWING_MAX_LEVEL ? 1 : 0); 367 dpcd_lane_settings[lane].bits.MAX_PRE_EMPHASIS_REACHED = 368 (hw_lane_settings[lane].PRE_EMPHASIS == 369 PRE_EMPHASIS_MAX_LEVEL ? 1 : 0); 370 } else if (link_dp_get_encoding_format(<_settings->link_settings) == 371 DP_128b_132b_ENCODING) { 372 dpcd_lane_settings[lane].tx_ffe.PRESET_VALUE = 373 hw_lane_settings[lane].FFE_PRESET.settings.level; 374 } 375 } 376} 377 378uint8_t get_dpcd_link_rate(const struct dc_link_settings *link_settings) 379{ 380 uint8_t link_rate = 0; 381 enum dp_link_encoding encoding = link_dp_get_encoding_format(link_settings); 382 383 if (encoding == DP_128b_132b_ENCODING) 384 switch (link_settings->link_rate) { 385 case LINK_RATE_UHBR10: 386 link_rate = 0x1; 387 break; 388 case LINK_RATE_UHBR20: 389 link_rate = 0x2; 390 break; 391 case LINK_RATE_UHBR13_5: 392 link_rate = 0x4; 393 break; 394 default: 395 link_rate = 0; 396 break; 397 } 398 else if (encoding == DP_8b_10b_ENCODING) 399 link_rate = (uint8_t) link_settings->link_rate; 400 else 401 link_rate = 0; 402 403 return link_rate; 404} 405 406/* Only used for channel equalization */ 407uint32_t dp_translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval) 408{ 409 unsigned int aux_rd_interval_us = 400; 410 411 switch (dpcd_aux_read_interval) { 412 case 0x01: 413 aux_rd_interval_us = 4000; 414 break; 415 case 0x02: 416 aux_rd_interval_us = 8000; 417 break; 418 case 0x03: 419 aux_rd_interval_us = 12000; 420 break; 421 case 0x04: 422 aux_rd_interval_us = 16000; 423 break; 424 case 0x05: 425 aux_rd_interval_us = 32000; 426 break; 427 case 0x06: 428 aux_rd_interval_us = 64000; 429 break; 430 default: 431 break; 432 } 433 434 return aux_rd_interval_us; 435} 436 437enum link_training_result dp_get_cr_failure(enum dc_lane_count ln_count, 438 union lane_status *dpcd_lane_status) 439{ 440 enum link_training_result result = LINK_TRAINING_SUCCESS; 441 442 if (ln_count >= LANE_COUNT_ONE && !dpcd_lane_status[0].bits.CR_DONE_0) 443 result = LINK_TRAINING_CR_FAIL_LANE0; 444 else if (ln_count >= LANE_COUNT_TWO && !dpcd_lane_status[1].bits.CR_DONE_0) 445 result = LINK_TRAINING_CR_FAIL_LANE1; 446 else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[2].bits.CR_DONE_0) 447 result = LINK_TRAINING_CR_FAIL_LANE23; 448 else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[3].bits.CR_DONE_0) 449 result = LINK_TRAINING_CR_FAIL_LANE23; 450 return result; 451} 452 453bool is_repeater(const struct link_training_settings *lt_settings, uint32_t offset) 454{ 455 return (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) && (offset != 0); 456} 457 458bool dp_is_max_vs_reached( 459 const struct link_training_settings *lt_settings) 460{ 461 uint32_t lane; 462 for (lane = 0; lane < 463 (uint32_t)(lt_settings->link_settings.lane_count); 464 lane++) { 465 if (lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET 466 == VOLTAGE_SWING_MAX_LEVEL) 467 return true; 468 } 469 return false; 470 471} 472 473bool dp_is_cr_done(enum dc_lane_count ln_count, 474 union lane_status *dpcd_lane_status) 475{ 476 bool done = true; 477 uint32_t lane; 478 /*LANEx_CR_DONE bits All 1's?*/ 479 for (lane = 0; lane < (uint32_t)(ln_count); lane++) { 480 if (!dpcd_lane_status[lane].bits.CR_DONE_0) 481 done = false; 482 } 483 return done; 484 485} 486 487bool dp_is_ch_eq_done(enum dc_lane_count ln_count, 488 union lane_status *dpcd_lane_status) 489{ 490 bool done = true; 491 uint32_t lane; 492 for (lane = 0; lane < (uint32_t)(ln_count); lane++) 493 if (!dpcd_lane_status[lane].bits.CHANNEL_EQ_DONE_0) 494 done = false; 495 return done; 496} 497 498bool dp_is_symbol_locked(enum dc_lane_count ln_count, 499 union lane_status *dpcd_lane_status) 500{ 501 bool locked = true; 502 uint32_t lane; 503 for (lane = 0; lane < (uint32_t)(ln_count); lane++) 504 if (!dpcd_lane_status[lane].bits.SYMBOL_LOCKED_0) 505 locked = false; 506 return locked; 507} 508 509bool dp_is_interlane_aligned(union lane_align_status_updated align_status) 510{ 511 return align_status.bits.INTERLANE_ALIGN_DONE == 1; 512} 513 514enum link_training_result dp_check_link_loss_status( 515 struct dc_link *link, 516 const struct link_training_settings *link_training_setting) 517{ 518 enum link_training_result status = LINK_TRAINING_SUCCESS; 519 union lane_status lane_status; 520 union lane_align_status_updated dpcd_lane_status_updated; 521 uint8_t dpcd_buf[6] = {0}; 522 uint32_t lane; 523 524 core_link_read_dpcd( 525 link, 526 DP_SINK_COUNT, 527 (uint8_t *)(dpcd_buf), 528 sizeof(dpcd_buf)); 529 530 /*parse lane status*/ 531 for (lane = 0; lane < link->cur_link_settings.lane_count; lane++) { 532 /* 533 * check lanes status 534 */ 535 lane_status.raw = dp_get_nibble_at_index(&dpcd_buf[2], lane); 536 dpcd_lane_status_updated.raw = dpcd_buf[4]; 537 538 if (!lane_status.bits.CHANNEL_EQ_DONE_0 || 539 !lane_status.bits.CR_DONE_0 || 540 !lane_status.bits.SYMBOL_LOCKED_0 || 541 !dp_is_interlane_aligned(dpcd_lane_status_updated)) { 542 /* if one of the channel equalization, clock 543 * recovery or symbol lock is dropped 544 * consider it as (link has been 545 * dropped) dp sink status has changed 546 */ 547 status = LINK_TRAINING_LINK_LOSS; 548 break; 549 } 550 } 551 552 return status; 553} 554 555enum dc_status dp_get_lane_status_and_lane_adjust( 556 struct dc_link *link, 557 const struct link_training_settings *link_training_setting, 558 union lane_status ln_status[LANE_COUNT_DP_MAX], 559 union lane_align_status_updated *ln_align, 560 union lane_adjust ln_adjust[LANE_COUNT_DP_MAX], 561 uint32_t offset) 562{ 563 unsigned int lane01_status_address = DP_LANE0_1_STATUS; 564 uint8_t lane_adjust_offset = 4; 565 unsigned int lane01_adjust_address; 566 uint8_t dpcd_buf[6] = {0}; 567 uint32_t lane; 568 enum dc_status status; 569 570 if (is_repeater(link_training_setting, offset)) { 571 lane01_status_address = 572 DP_LANE0_1_STATUS_PHY_REPEATER1 + 573 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); 574 lane_adjust_offset = 3; 575 } 576 577 status = core_link_read_dpcd( 578 link, 579 lane01_status_address, 580 (uint8_t *)(dpcd_buf), 581 sizeof(dpcd_buf)); 582 583 if (status != DC_OK) { 584 DC_LOG_HW_LINK_TRAINING("%s:\n Failed to read from address 0x%X," 585 " keep current lane status and lane adjust unchanged", 586 __func__, 587 lane01_status_address); 588 return status; 589 } 590 591 for (lane = 0; lane < 592 (uint32_t)(link_training_setting->link_settings.lane_count); 593 lane++) { 594 595 ln_status[lane].raw = 596 dp_get_nibble_at_index(&dpcd_buf[0], lane); 597 ln_adjust[lane].raw = 598 dp_get_nibble_at_index(&dpcd_buf[lane_adjust_offset], lane); 599 } 600 601 ln_align->raw = dpcd_buf[2]; 602 603 if (is_repeater(link_training_setting, offset)) { 604 DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n" 605 " 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ", 606 __func__, 607 offset, 608 lane01_status_address, dpcd_buf[0], 609 lane01_status_address + 1, dpcd_buf[1]); 610 611 lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1_PHY_REPEATER1 + 612 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); 613 614 DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n" 615 " 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n", 616 __func__, 617 offset, 618 lane01_adjust_address, 619 dpcd_buf[lane_adjust_offset], 620 lane01_adjust_address + 1, 621 dpcd_buf[lane_adjust_offset + 1]); 622 } else { 623 DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ", 624 __func__, 625 lane01_status_address, dpcd_buf[0], 626 lane01_status_address + 1, dpcd_buf[1]); 627 628 lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1; 629 630 DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n", 631 __func__, 632 lane01_adjust_address, 633 dpcd_buf[lane_adjust_offset], 634 lane01_adjust_address + 1, 635 dpcd_buf[lane_adjust_offset + 1]); 636 } 637 638 return status; 639} 640 641static void override_lane_settings(const struct link_training_settings *lt_settings, 642 struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]) 643{ 644 uint32_t lane; 645 646 if (lt_settings->voltage_swing == NULL && 647 lt_settings->pre_emphasis == NULL && 648 lt_settings->ffe_preset == NULL && 649 lt_settings->post_cursor2 == NULL) 650 651 return; 652 653 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { 654 if (lt_settings->voltage_swing) 655 lane_settings[lane].VOLTAGE_SWING = *lt_settings->voltage_swing; 656 if (lt_settings->pre_emphasis) 657 lane_settings[lane].PRE_EMPHASIS = *lt_settings->pre_emphasis; 658 if (lt_settings->post_cursor2) 659 lane_settings[lane].POST_CURSOR2 = *lt_settings->post_cursor2; 660 if (lt_settings->ffe_preset) 661 lane_settings[lane].FFE_PRESET = *lt_settings->ffe_preset; 662 } 663} 664 665void dp_get_lttpr_mode_override(struct dc_link *link, enum lttpr_mode *override) 666{ 667 if (!dp_is_lttpr_present(link)) 668 return; 669 670 if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_TRANSPARENT) { 671 *override = LTTPR_MODE_TRANSPARENT; 672 } else if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_NON_TRANSPARENT) { 673 *override = LTTPR_MODE_NON_TRANSPARENT; 674 } else if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_NON_LTTPR) { 675 *override = LTTPR_MODE_NON_LTTPR; 676 } 677 DC_LOG_DC("lttpr_mode_override chose LTTPR_MODE = %d\n", (uint8_t)(*override)); 678} 679 680void override_training_settings( 681 struct dc_link *link, 682 const struct dc_link_training_overrides *overrides, 683 struct link_training_settings *lt_settings) 684{ 685 uint32_t lane; 686 687 /* Override link spread */ 688 if (!link->dp_ss_off && overrides->downspread != NULL) 689 lt_settings->link_settings.link_spread = *overrides->downspread ? 690 LINK_SPREAD_05_DOWNSPREAD_30KHZ 691 : LINK_SPREAD_DISABLED; 692 693 /* Override lane settings */ 694 if (overrides->voltage_swing != NULL) 695 lt_settings->voltage_swing = overrides->voltage_swing; 696 if (overrides->pre_emphasis != NULL) 697 lt_settings->pre_emphasis = overrides->pre_emphasis; 698 if (overrides->post_cursor2 != NULL) 699 lt_settings->post_cursor2 = overrides->post_cursor2; 700 if (overrides->ffe_preset != NULL) 701 lt_settings->ffe_preset = overrides->ffe_preset; 702 /* Override HW lane settings with BIOS forced values if present */ 703 if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && 704 lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) { 705 lt_settings->voltage_swing = &link->bios_forced_drive_settings.VOLTAGE_SWING; 706 lt_settings->pre_emphasis = &link->bios_forced_drive_settings.PRE_EMPHASIS; 707 lt_settings->always_match_dpcd_with_hw_lane_settings = false; 708 } 709 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { 710 lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 711 lt_settings->voltage_swing != NULL ? 712 *lt_settings->voltage_swing : 713 VOLTAGE_SWING_LEVEL0; 714 lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 715 lt_settings->pre_emphasis != NULL ? 716 *lt_settings->pre_emphasis 717 : PRE_EMPHASIS_DISABLED; 718 lt_settings->hw_lane_settings[lane].POST_CURSOR2 = 719 lt_settings->post_cursor2 != NULL ? 720 *lt_settings->post_cursor2 721 : POST_CURSOR2_DISABLED; 722 } 723 724 if (lt_settings->always_match_dpcd_with_hw_lane_settings) 725 dp_hw_to_dpcd_lane_settings(lt_settings, 726 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); 727 728 /* Override training timings */ 729 if (overrides->cr_pattern_time != NULL) 730 lt_settings->cr_pattern_time = *overrides->cr_pattern_time; 731 if (overrides->eq_pattern_time != NULL) 732 lt_settings->eq_pattern_time = *overrides->eq_pattern_time; 733 if (overrides->pattern_for_cr != NULL) 734 lt_settings->pattern_for_cr = *overrides->pattern_for_cr; 735 if (overrides->pattern_for_eq != NULL) 736 lt_settings->pattern_for_eq = *overrides->pattern_for_eq; 737 if (overrides->enhanced_framing != NULL) 738 lt_settings->enhanced_framing = *overrides->enhanced_framing; 739 if (link->preferred_training_settings.fec_enable != NULL) 740 lt_settings->should_set_fec_ready = *link->preferred_training_settings.fec_enable; 741 742 /* Check DP tunnel LTTPR mode debug option. */ 743 if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && link->dc->debug.dpia_debug.bits.force_non_lttpr) 744 lt_settings->lttpr_mode = LTTPR_MODE_NON_LTTPR; 745 746 dp_get_lttpr_mode_override(link, <_settings->lttpr_mode); 747 748} 749 750enum dc_dp_training_pattern decide_cr_training_pattern( 751 const struct dc_link_settings *link_settings) 752{ 753 switch (link_dp_get_encoding_format(link_settings)) { 754 case DP_8b_10b_ENCODING: 755 default: 756 return DP_TRAINING_PATTERN_SEQUENCE_1; 757 case DP_128b_132b_ENCODING: 758 return DP_128b_132b_TPS1; 759 } 760} 761 762enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *link, 763 const struct dc_link_settings *link_settings) 764{ 765 struct link_encoder *link_enc; 766 struct encoder_feature_support *enc_caps; 767 struct dpcd_caps *rx_caps = &link->dpcd_caps; 768 enum dc_dp_training_pattern pattern = DP_TRAINING_PATTERN_SEQUENCE_2; 769 770 link_enc = link_enc_cfg_get_link_enc(link); 771 ASSERT(link_enc); 772 enc_caps = &link_enc->features; 773 774 switch (link_dp_get_encoding_format(link_settings)) { 775 case DP_8b_10b_ENCODING: 776 if (enc_caps->flags.bits.IS_TPS4_CAPABLE && 777 rx_caps->max_down_spread.bits.TPS4_SUPPORTED) 778 pattern = DP_TRAINING_PATTERN_SEQUENCE_4; 779 else if (enc_caps->flags.bits.IS_TPS3_CAPABLE && 780 rx_caps->max_ln_count.bits.TPS3_SUPPORTED) 781 pattern = DP_TRAINING_PATTERN_SEQUENCE_3; 782 else 783 pattern = DP_TRAINING_PATTERN_SEQUENCE_2; 784 break; 785 case DP_128b_132b_ENCODING: 786 pattern = DP_128b_132b_TPS2; 787 break; 788 default: 789 pattern = DP_TRAINING_PATTERN_SEQUENCE_2; 790 break; 791 } 792 return pattern; 793} 794 795enum lttpr_mode dp_decide_lttpr_mode(struct dc_link *link, 796 struct dc_link_settings *link_setting) 797{ 798 enum dp_link_encoding encoding = link_dp_get_encoding_format(link_setting); 799 800 if (encoding == DP_8b_10b_ENCODING) 801 return dp_decide_8b_10b_lttpr_mode(link); 802 else if (encoding == DP_128b_132b_ENCODING) 803 return dp_decide_128b_132b_lttpr_mode(link); 804 805 ASSERT(0); 806 return LTTPR_MODE_NON_LTTPR; 807} 808 809void dp_decide_lane_settings( 810 const struct link_training_settings *lt_settings, 811 const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX], 812 struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX], 813 union dpcd_training_lane *dpcd_lane_settings) 814{ 815 uint32_t lane; 816 817 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { 818 if (link_dp_get_encoding_format(<_settings->link_settings) == 819 DP_8b_10b_ENCODING) { 820 hw_lane_settings[lane].VOLTAGE_SWING = 821 (enum dc_voltage_swing)(ln_adjust[lane].bits. 822 VOLTAGE_SWING_LANE); 823 hw_lane_settings[lane].PRE_EMPHASIS = 824 (enum dc_pre_emphasis)(ln_adjust[lane].bits. 825 PRE_EMPHASIS_LANE); 826 } else if (link_dp_get_encoding_format(<_settings->link_settings) == 827 DP_128b_132b_ENCODING) { 828 hw_lane_settings[lane].FFE_PRESET.raw = 829 ln_adjust[lane].tx_ffe.PRESET_VALUE; 830 } 831 } 832 dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings); 833 834 if (lt_settings->disallow_per_lane_settings) { 835 /* we find the maximum of the requested settings across all lanes*/ 836 /* and set this maximum for all lanes*/ 837 maximize_lane_settings(lt_settings, hw_lane_settings); 838 override_lane_settings(lt_settings, hw_lane_settings); 839 840 if (lt_settings->always_match_dpcd_with_hw_lane_settings) 841 dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings); 842 } 843 844} 845 846void dp_decide_training_settings( 847 struct dc_link *link, 848 const struct dc_link_settings *link_settings, 849 struct link_training_settings *lt_settings) 850{ 851 if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING) 852 decide_8b_10b_training_settings(link, link_settings, lt_settings); 853 else if (link_dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING) 854 decide_128b_132b_training_settings(link, link_settings, lt_settings); 855} 856 857 858enum dc_status configure_lttpr_mode_transparent(struct dc_link *link) 859{ 860 uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT; 861 862 DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__); 863 return core_link_write_dpcd(link, 864 DP_PHY_REPEATER_MODE, 865 (uint8_t *)&repeater_mode, 866 sizeof(repeater_mode)); 867} 868 869static enum dc_status configure_lttpr_mode_non_transparent( 870 struct dc_link *link, 871 const struct link_training_settings *lt_settings) 872{ 873 /* aux timeout is already set to extended */ 874 /* RESET/SET lttpr mode to enable non transparent mode */ 875 uint8_t repeater_cnt; 876 uint32_t aux_interval_address; 877 uint8_t repeater_id; 878 enum dc_status result = DC_ERROR_UNEXPECTED; 879 uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT; 880 const struct dc *dc = link->dc; 881 882 enum dp_link_encoding encoding = dc->link_srv->dp_get_encoding_format(<_settings->link_settings); 883 884 if (encoding == DP_8b_10b_ENCODING) { 885 DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__); 886 result = core_link_write_dpcd(link, 887 DP_PHY_REPEATER_MODE, 888 (uint8_t *)&repeater_mode, 889 sizeof(repeater_mode)); 890 891 } 892 893 if (result == DC_OK) { 894 link->dpcd_caps.lttpr_caps.mode = repeater_mode; 895 } 896 897 if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { 898 899 DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Non Transparent Mode\n", __func__); 900 901 repeater_mode = DP_PHY_REPEATER_MODE_NON_TRANSPARENT; 902 result = core_link_write_dpcd(link, 903 DP_PHY_REPEATER_MODE, 904 (uint8_t *)&repeater_mode, 905 sizeof(repeater_mode)); 906 907 if (result == DC_OK) { 908 link->dpcd_caps.lttpr_caps.mode = repeater_mode; 909 } 910 911 if (encoding == DP_8b_10b_ENCODING) { 912 repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt); 913 914 /* Driver does not need to train the first hop. Skip DPCD read and clear 915 * AUX_RD_INTERVAL for DPTX-to-DPIA hop. 916 */ 917 if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) 918 link->dpcd_caps.lttpr_caps.aux_rd_interval[--repeater_cnt] = 0; 919 920 for (repeater_id = repeater_cnt; repeater_id > 0; repeater_id--) { 921 aux_interval_address = DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1 + 922 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (repeater_id - 1)); 923 core_link_read_dpcd( 924 link, 925 aux_interval_address, 926 (uint8_t *)&link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1], 927 sizeof(link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1])); 928 link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1] &= 0x7F; 929 } 930 } 931 } 932 933 return result; 934} 935 936enum dc_status dpcd_configure_lttpr_mode(struct dc_link *link, struct link_training_settings *lt_settings) 937{ 938 enum dc_status status = DC_OK; 939 940 if (lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) 941 status = configure_lttpr_mode_transparent(link); 942 943 else if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) 944 status = configure_lttpr_mode_non_transparent(link, lt_settings); 945 946 return status; 947} 948 949void repeater_training_done(struct dc_link *link, uint32_t offset) 950{ 951 union dpcd_training_pattern dpcd_pattern = {0}; 952 953 const uint32_t dpcd_base_lt_offset = 954 DP_TRAINING_PATTERN_SET_PHY_REPEATER1 + 955 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); 956 /* Set training not in progress*/ 957 dpcd_pattern.v1_4.TRAINING_PATTERN_SET = DPCD_TRAINING_PATTERN_VIDEOIDLE; 958 959 core_link_write_dpcd( 960 link, 961 dpcd_base_lt_offset, 962 &dpcd_pattern.raw, 963 1); 964 965 DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Id: %d 0x%X pattern = %x\n", 966 __func__, 967 offset, 968 dpcd_base_lt_offset, 969 dpcd_pattern.v1_4.TRAINING_PATTERN_SET); 970} 971 972static void dpcd_exit_training_mode(struct dc_link *link, enum dp_link_encoding encoding) 973{ 974 uint8_t sink_status = 0; 975 uint8_t i; 976 977 /* clear training pattern set */ 978 dpcd_set_training_pattern(link, DP_TRAINING_PATTERN_VIDEOIDLE); 979 980 if (encoding == DP_128b_132b_ENCODING) { 981 /* poll for intra-hop disable */ 982 for (i = 0; i < 10; i++) { 983 if ((core_link_read_dpcd(link, DP_SINK_STATUS, &sink_status, 1) == DC_OK) && 984 (sink_status & DP_INTRA_HOP_AUX_REPLY_INDICATION) == 0) 985 break; 986 fsleep(1000); 987 } 988 } 989} 990 991enum dc_status dpcd_configure_channel_coding(struct dc_link *link, 992 struct link_training_settings *lt_settings) 993{ 994 enum dp_link_encoding encoding = 995 link_dp_get_encoding_format( 996 <_settings->link_settings); 997 enum dc_status status; 998 999 status = core_link_write_dpcd( 1000 link, 1001 DP_MAIN_LINK_CHANNEL_CODING_SET, 1002 (uint8_t *) &encoding, 1003 1); 1004 DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X MAIN_LINK_CHANNEL_CODING_SET = %x\n", 1005 __func__, 1006 DP_MAIN_LINK_CHANNEL_CODING_SET, 1007 encoding); 1008 1009 return status; 1010} 1011 1012void dpcd_set_training_pattern( 1013 struct dc_link *link, 1014 enum dc_dp_training_pattern training_pattern) 1015{ 1016 union dpcd_training_pattern dpcd_pattern = {0}; 1017 1018 dpcd_pattern.v1_4.TRAINING_PATTERN_SET = 1019 dp_training_pattern_to_dpcd_training_pattern( 1020 link, training_pattern); 1021 1022 core_link_write_dpcd( 1023 link, 1024 DP_TRAINING_PATTERN_SET, 1025 &dpcd_pattern.raw, 1026 1); 1027 1028 DC_LOG_HW_LINK_TRAINING("%s\n %x pattern = %x\n", 1029 __func__, 1030 DP_TRAINING_PATTERN_SET, 1031 dpcd_pattern.v1_4.TRAINING_PATTERN_SET); 1032} 1033 1034enum dc_status dpcd_set_link_settings( 1035 struct dc_link *link, 1036 const struct link_training_settings *lt_settings) 1037{ 1038 uint8_t rate; 1039 enum dc_status status; 1040 1041 union down_spread_ctrl downspread = {0}; 1042 union lane_count_set lane_count_set = {0}; 1043 1044 downspread.raw = (uint8_t) 1045 (lt_settings->link_settings.link_spread); 1046 1047 lane_count_set.bits.LANE_COUNT_SET = 1048 lt_settings->link_settings.lane_count; 1049 1050 lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing; 1051 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0; 1052 1053 1054 if (link->ep_type == DISPLAY_ENDPOINT_PHY && 1055 lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) { 1056 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 1057 link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED; 1058 } 1059 1060 status = core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL, 1061 &downspread.raw, sizeof(downspread)); 1062 1063 status = core_link_write_dpcd(link, DP_LANE_COUNT_SET, 1064 &lane_count_set.raw, 1); 1065 1066 if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_13 && 1067 lt_settings->link_settings.use_link_rate_set == true) { 1068 rate = 0; 1069 /* WA for some MUX chips that will power down with eDP and lose supported 1070 * link rate set for eDP 1.4. Source reads DPCD 0x010 again to ensure 1071 * MUX chip gets link rate set back before link training. 1072 */ 1073 if (link->connector_signal == SIGNAL_TYPE_EDP) { 1074 uint8_t supported_link_rates[16] = {0}; 1075 1076 core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES, 1077 supported_link_rates, sizeof(supported_link_rates)); 1078 } 1079 status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1); 1080 status = core_link_write_dpcd(link, DP_LINK_RATE_SET, 1081 <_settings->link_settings.link_rate_set, 1); 1082 } else { 1083 rate = get_dpcd_link_rate(<_settings->link_settings); 1084 1085 status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1); 1086 } 1087 1088 if (rate) { 1089 DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n", 1090 __func__, 1091 DP_LINK_BW_SET, 1092 lt_settings->link_settings.link_rate, 1093 DP_LANE_COUNT_SET, 1094 lt_settings->link_settings.lane_count, 1095 lt_settings->enhanced_framing, 1096 DP_DOWNSPREAD_CTRL, 1097 lt_settings->link_settings.link_spread); 1098 } else { 1099 DC_LOG_HW_LINK_TRAINING("%s\n %x rate set = %x\n %x lane = %x framing = %x\n %x spread = %x\n", 1100 __func__, 1101 DP_LINK_RATE_SET, 1102 lt_settings->link_settings.link_rate_set, 1103 DP_LANE_COUNT_SET, 1104 lt_settings->link_settings.lane_count, 1105 lt_settings->enhanced_framing, 1106 DP_DOWNSPREAD_CTRL, 1107 lt_settings->link_settings.link_spread); 1108 } 1109 1110 return status; 1111} 1112 1113enum dc_status dpcd_set_lane_settings( 1114 struct dc_link *link, 1115 const struct link_training_settings *link_training_setting, 1116 uint32_t offset) 1117{ 1118 unsigned int lane0_set_address; 1119 enum dc_status status; 1120 lane0_set_address = DP_TRAINING_LANE0_SET; 1121 1122 if (is_repeater(link_training_setting, offset)) 1123 lane0_set_address = DP_TRAINING_LANE0_SET_PHY_REPEATER1 + 1124 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); 1125 1126 status = core_link_write_dpcd(link, 1127 lane0_set_address, 1128 (uint8_t *)(link_training_setting->dpcd_lane_settings), 1129 link_training_setting->link_settings.lane_count); 1130 1131 if (is_repeater(link_training_setting, offset)) { 1132 DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n" 1133 " 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", 1134 __func__, 1135 offset, 1136 lane0_set_address, 1137 link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET, 1138 link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET, 1139 link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED, 1140 link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED); 1141 1142 } else { 1143 DC_LOG_HW_LINK_TRAINING("%s\n 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", 1144 __func__, 1145 lane0_set_address, 1146 link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET, 1147 link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET, 1148 link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED, 1149 link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED); 1150 } 1151 1152 return status; 1153} 1154 1155void dpcd_set_lt_pattern_and_lane_settings( 1156 struct dc_link *link, 1157 const struct link_training_settings *lt_settings, 1158 enum dc_dp_training_pattern pattern, 1159 uint32_t offset) 1160{ 1161 uint32_t dpcd_base_lt_offset; 1162 uint8_t dpcd_lt_buffer[5] = {0}; 1163 union dpcd_training_pattern dpcd_pattern = {0}; 1164 uint32_t size_in_bytes; 1165 bool edp_workaround = false; /* TODO link_prop.INTERNAL */ 1166 dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET; 1167 1168 if (is_repeater(lt_settings, offset)) 1169 dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 + 1170 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); 1171 1172 /***************************************************************** 1173 * DpcdAddress_TrainingPatternSet 1174 *****************************************************************/ 1175 dpcd_pattern.v1_4.TRAINING_PATTERN_SET = 1176 dp_training_pattern_to_dpcd_training_pattern(link, pattern); 1177 1178 dpcd_pattern.v1_4.SCRAMBLING_DISABLE = 1179 dp_initialize_scrambling_data_symbols(link, pattern); 1180 1181 dpcd_lt_buffer[DP_TRAINING_PATTERN_SET - DP_TRAINING_PATTERN_SET] 1182 = dpcd_pattern.raw; 1183 1184 if (is_repeater(lt_settings, offset)) { 1185 DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n 0x%X pattern = %x\n", 1186 __func__, 1187 offset, 1188 dpcd_base_lt_offset, 1189 dpcd_pattern.v1_4.TRAINING_PATTERN_SET); 1190 } else { 1191 DC_LOG_HW_LINK_TRAINING("%s\n 0x%X pattern = %x\n", 1192 __func__, 1193 dpcd_base_lt_offset, 1194 dpcd_pattern.v1_4.TRAINING_PATTERN_SET); 1195 } 1196 1197 /* concatenate everything into one buffer*/ 1198 size_in_bytes = lt_settings->link_settings.lane_count * 1199 sizeof(lt_settings->dpcd_lane_settings[0]); 1200 1201 // 0x00103 - 0x00102 1202 memmove( 1203 &dpcd_lt_buffer[DP_TRAINING_LANE0_SET - DP_TRAINING_PATTERN_SET], 1204 lt_settings->dpcd_lane_settings, 1205 size_in_bytes); 1206 1207 if (is_repeater(lt_settings, offset)) { 1208 if (link_dp_get_encoding_format(<_settings->link_settings) == 1209 DP_128b_132b_ENCODING) 1210 DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n" 1211 " 0x%X TX_FFE_PRESET_VALUE = %x\n", 1212 __func__, 1213 offset, 1214 dpcd_base_lt_offset, 1215 lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE); 1216 else if (link_dp_get_encoding_format(<_settings->link_settings) == 1217 DP_8b_10b_ENCODING) 1218 DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n" 1219 " 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", 1220 __func__, 1221 offset, 1222 dpcd_base_lt_offset, 1223 lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET, 1224 lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET, 1225 lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED, 1226 lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED); 1227 } else { 1228 if (link_dp_get_encoding_format(<_settings->link_settings) == 1229 DP_128b_132b_ENCODING) 1230 DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n", 1231 __func__, 1232 dpcd_base_lt_offset, 1233 lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE); 1234 else if (link_dp_get_encoding_format(<_settings->link_settings) == 1235 DP_8b_10b_ENCODING) 1236 DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", 1237 __func__, 1238 dpcd_base_lt_offset, 1239 lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET, 1240 lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET, 1241 lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED, 1242 lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED); 1243 } 1244 if (edp_workaround) { 1245 /* for eDP write in 2 parts because the 5-byte burst is 1246 * causing issues on some eDP panels (EPR#366724) 1247 */ 1248 core_link_write_dpcd( 1249 link, 1250 DP_TRAINING_PATTERN_SET, 1251 &dpcd_pattern.raw, 1252 sizeof(dpcd_pattern.raw)); 1253 1254 core_link_write_dpcd( 1255 link, 1256 DP_TRAINING_LANE0_SET, 1257 (uint8_t *)(lt_settings->dpcd_lane_settings), 1258 size_in_bytes); 1259 1260 } else if (link_dp_get_encoding_format(<_settings->link_settings) == 1261 DP_128b_132b_ENCODING) { 1262 core_link_write_dpcd( 1263 link, 1264 dpcd_base_lt_offset, 1265 dpcd_lt_buffer, 1266 sizeof(dpcd_lt_buffer)); 1267 } else 1268 /* write it all in (1 + number-of-lanes)-byte burst*/ 1269 core_link_write_dpcd( 1270 link, 1271 dpcd_base_lt_offset, 1272 dpcd_lt_buffer, 1273 size_in_bytes + sizeof(dpcd_pattern.raw)); 1274} 1275 1276void start_clock_recovery_pattern_early(struct dc_link *link, 1277 const struct link_resource *link_res, 1278 struct link_training_settings *lt_settings, 1279 uint32_t offset) 1280{ 1281 DC_LOG_HW_LINK_TRAINING("%s\n GPU sends TPS1. Wait 400us.\n", 1282 __func__); 1283 dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, offset); 1284 dp_set_hw_lane_settings(link, link_res, lt_settings, offset); 1285 udelay(400); 1286} 1287 1288void dp_set_hw_test_pattern( 1289 struct dc_link *link, 1290 const struct link_resource *link_res, 1291 enum dp_test_pattern test_pattern, 1292 uint8_t *custom_pattern, 1293 uint32_t custom_pattern_size) 1294{ 1295 const struct link_hwss *link_hwss = get_link_hwss(link, link_res); 1296 struct encoder_set_dp_phy_pattern_param pattern_param = {0}; 1297 1298 pattern_param.dp_phy_pattern = test_pattern; 1299 pattern_param.custom_pattern = custom_pattern; 1300 pattern_param.custom_pattern_size = custom_pattern_size; 1301 pattern_param.dp_panel_mode = dp_get_panel_mode(link); 1302 1303 if (link_hwss->ext.set_dp_link_test_pattern) 1304 link_hwss->ext.set_dp_link_test_pattern(link, link_res, &pattern_param); 1305} 1306 1307bool dp_set_hw_training_pattern( 1308 struct dc_link *link, 1309 const struct link_resource *link_res, 1310 enum dc_dp_training_pattern pattern, 1311 uint32_t offset) 1312{ 1313 enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED; 1314 1315 switch (pattern) { 1316 case DP_TRAINING_PATTERN_SEQUENCE_1: 1317 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN1; 1318 break; 1319 case DP_TRAINING_PATTERN_SEQUENCE_2: 1320 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN2; 1321 break; 1322 case DP_TRAINING_PATTERN_SEQUENCE_3: 1323 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN3; 1324 break; 1325 case DP_TRAINING_PATTERN_SEQUENCE_4: 1326 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4; 1327 break; 1328 case DP_128b_132b_TPS1: 1329 test_pattern = DP_TEST_PATTERN_128b_132b_TPS1_TRAINING_MODE; 1330 break; 1331 case DP_128b_132b_TPS2: 1332 test_pattern = DP_TEST_PATTERN_128b_132b_TPS2_TRAINING_MODE; 1333 break; 1334 default: 1335 break; 1336 } 1337 1338 dp_set_hw_test_pattern(link, link_res, test_pattern, NULL, 0); 1339 1340 return true; 1341} 1342 1343static bool perform_post_lt_adj_req_sequence( 1344 struct dc_link *link, 1345 const struct link_resource *link_res, 1346 struct link_training_settings *lt_settings) 1347{ 1348 enum dc_lane_count lane_count = 1349 lt_settings->link_settings.lane_count; 1350 1351 uint32_t adj_req_count; 1352 uint32_t adj_req_timer; 1353 bool req_drv_setting_changed; 1354 uint32_t lane; 1355 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; 1356 union lane_align_status_updated dpcd_lane_status_updated = {0}; 1357 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; 1358 1359 req_drv_setting_changed = false; 1360 for (adj_req_count = 0; adj_req_count < POST_LT_ADJ_REQ_LIMIT; 1361 adj_req_count++) { 1362 1363 req_drv_setting_changed = false; 1364 1365 for (adj_req_timer = 0; 1366 adj_req_timer < POST_LT_ADJ_REQ_TIMEOUT; 1367 adj_req_timer++) { 1368 1369 dp_get_lane_status_and_lane_adjust( 1370 link, 1371 lt_settings, 1372 dpcd_lane_status, 1373 &dpcd_lane_status_updated, 1374 dpcd_lane_adjust, 1375 DPRX); 1376 1377 if (dpcd_lane_status_updated.bits. 1378 POST_LT_ADJ_REQ_IN_PROGRESS == 0) 1379 return true; 1380 1381 if (!dp_is_cr_done(lane_count, dpcd_lane_status)) 1382 return false; 1383 1384 if (!dp_is_ch_eq_done(lane_count, dpcd_lane_status) || 1385 !dp_is_symbol_locked(lane_count, dpcd_lane_status) || 1386 !dp_is_interlane_aligned(dpcd_lane_status_updated)) 1387 return false; 1388 1389 for (lane = 0; lane < (uint32_t)(lane_count); lane++) { 1390 1391 if (lt_settings-> 1392 dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET != 1393 dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_LANE || 1394 lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET != 1395 dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_LANE) { 1396 1397 req_drv_setting_changed = true; 1398 break; 1399 } 1400 } 1401 1402 if (req_drv_setting_changed) { 1403 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, 1404 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); 1405 1406 dp_set_drive_settings(link, 1407 link_res, 1408 lt_settings); 1409 break; 1410 } 1411 1412 msleep(1); 1413 } 1414 1415 if (!req_drv_setting_changed) { 1416 DC_LOG_WARNING("%s: Post Link Training Adjust Request Timed out\n", 1417 __func__); 1418 1419 ASSERT(0); 1420 return true; 1421 } 1422 } 1423 DC_LOG_WARNING("%s: Post Link Training Adjust Request limit reached\n", 1424 __func__); 1425 1426 ASSERT(0); 1427 return true; 1428 1429} 1430 1431static enum link_training_result dp_transition_to_video_idle( 1432 struct dc_link *link, 1433 const struct link_resource *link_res, 1434 struct link_training_settings *lt_settings, 1435 enum link_training_result status) 1436{ 1437 union lane_count_set lane_count_set = {0}; 1438 1439 /* 4. mainlink output idle pattern*/ 1440 dp_set_hw_test_pattern(link, link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0); 1441 1442 /* 1443 * 5. post training adjust if required 1444 * If the upstream DPTX and downstream DPRX both support TPS4, 1445 * TPS4 must be used instead of POST_LT_ADJ_REQ. 1446 */ 1447 if (link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED != 1 || 1448 lt_settings->pattern_for_eq >= DP_TRAINING_PATTERN_SEQUENCE_4) { 1449 /* delay 5ms after Main Link output idle pattern and then check 1450 * DPCD 0202h. 1451 */ 1452 if (link->connector_signal != SIGNAL_TYPE_EDP && status == LINK_TRAINING_SUCCESS) { 1453 msleep(5); 1454 status = dp_check_link_loss_status(link, lt_settings); 1455 } 1456 return status; 1457 } 1458 1459 if (status == LINK_TRAINING_SUCCESS && 1460 perform_post_lt_adj_req_sequence(link, link_res, lt_settings) == false) 1461 status = LINK_TRAINING_LQA_FAIL; 1462 1463 lane_count_set.bits.LANE_COUNT_SET = lt_settings->link_settings.lane_count; 1464 lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing; 1465 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0; 1466 1467 core_link_write_dpcd( 1468 link, 1469 DP_LANE_COUNT_SET, 1470 &lane_count_set.raw, 1471 sizeof(lane_count_set)); 1472 1473 return status; 1474} 1475 1476enum link_training_result dp_perform_link_training( 1477 struct dc_link *link, 1478 const struct link_resource *link_res, 1479 const struct dc_link_settings *link_settings, 1480 bool skip_video_pattern) 1481{ 1482 enum link_training_result status = LINK_TRAINING_SUCCESS; 1483 struct link_training_settings lt_settings = {0}; 1484 enum dp_link_encoding encoding = 1485 link_dp_get_encoding_format(link_settings); 1486 1487 /* decide training settings */ 1488 dp_decide_training_settings( 1489 link, 1490 link_settings, 1491 <_settings); 1492 1493 override_training_settings( 1494 link, 1495 &link->preferred_training_settings, 1496 <_settings); 1497 1498 /* reset previous training states */ 1499 dpcd_exit_training_mode(link, encoding); 1500 1501 /* configure link prior to entering training mode */ 1502 dpcd_configure_lttpr_mode(link, <_settings); 1503 dp_set_fec_ready(link, link_res, lt_settings.should_set_fec_ready); 1504 dpcd_configure_channel_coding(link, <_settings); 1505 1506 /* enter training mode: 1507 * Per DP specs starting from here, DPTX device shall not issue 1508 * Non-LT AUX transactions inside training mode. 1509 */ 1510 if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && encoding == DP_8b_10b_ENCODING) 1511 status = dp_perform_fixed_vs_pe_training_sequence(link, link_res, <_settings); 1512 else if (encoding == DP_8b_10b_ENCODING) 1513 status = dp_perform_8b_10b_link_training(link, link_res, <_settings); 1514 else if (encoding == DP_128b_132b_ENCODING) 1515 status = dp_perform_128b_132b_link_training(link, link_res, <_settings); 1516 else 1517 ASSERT(0); 1518 1519 /* exit training mode */ 1520 dpcd_exit_training_mode(link, encoding); 1521 1522 /* switch to video idle */ 1523 if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern) 1524 status = dp_transition_to_video_idle(link, 1525 link_res, 1526 <_settings, 1527 status); 1528 1529 /* dump debug data */ 1530 dp_log_training_result(link, <_settings, status); 1531 if (status != LINK_TRAINING_SUCCESS) 1532 link->ctx->dc->debug_data.ltFailCount++; 1533 return status; 1534} 1535 1536bool perform_link_training_with_retries( 1537 const struct dc_link_settings *link_setting, 1538 bool skip_video_pattern, 1539 int attempts, 1540 struct pipe_ctx *pipe_ctx, 1541 enum signal_type signal, 1542 bool do_fallback) 1543{ 1544 int j; 1545 uint8_t delay_between_attempts = LINK_TRAINING_RETRY_DELAY; 1546 struct dc_stream_state *stream = pipe_ctx->stream; 1547 struct dc_link *link = stream->link; 1548 enum dp_panel_mode panel_mode = dp_get_panel_mode(link); 1549 enum link_training_result status = LINK_TRAINING_CR_FAIL_LANE0; 1550 struct dc_link_settings cur_link_settings = *link_setting; 1551 struct dc_link_settings max_link_settings = *link_setting; 1552 const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res); 1553 int fail_count = 0; 1554 bool is_link_bw_low = false; /* link bandwidth < stream bandwidth */ 1555 bool is_link_bw_min = /* RBR x 1 */ 1556 (cur_link_settings.link_rate <= LINK_RATE_LOW) && 1557 (cur_link_settings.lane_count <= LANE_COUNT_ONE); 1558 1559 dp_trace_commit_lt_init(link); 1560 1561 1562 if (link_dp_get_encoding_format(&cur_link_settings) == DP_8b_10b_ENCODING) 1563 /* We need to do this before the link training to ensure the idle 1564 * pattern in SST mode will be sent right after the link training 1565 */ 1566 link_hwss->setup_stream_encoder(pipe_ctx); 1567 1568 dp_trace_set_lt_start_timestamp(link, false); 1569 j = 0; 1570 while (j < attempts && fail_count < (attempts * 10)) { 1571 1572 DC_LOG_HW_LINK_TRAINING("%s: Beginning link(%d) training attempt %u of %d @ rate(%d) x lane(%d) @ spread = %x\n", 1573 __func__, link->link_index, (unsigned int)j + 1, attempts, 1574 cur_link_settings.link_rate, cur_link_settings.lane_count, 1575 cur_link_settings.link_spread); 1576 1577 dp_enable_link_phy( 1578 link, 1579 &pipe_ctx->link_res, 1580 signal, 1581 pipe_ctx->clock_source->id, 1582 &cur_link_settings); 1583 1584 if (stream->sink_patches.dppowerup_delay > 0) { 1585 int delay_dp_power_up_in_ms = stream->sink_patches.dppowerup_delay; 1586 1587 msleep(delay_dp_power_up_in_ms); 1588 } 1589 1590 edp_set_panel_assr(link, pipe_ctx, &panel_mode, true); 1591 1592 dp_set_panel_mode(link, panel_mode); 1593 1594 if (link->aux_access_disabled) { 1595 dp_perform_link_training_skip_aux(link, &pipe_ctx->link_res, &cur_link_settings); 1596 return true; 1597 } else { 1598 /** @todo Consolidate USB4 DP and DPx.x training. */ 1599 if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) { 1600 status = dpia_perform_link_training( 1601 link, 1602 &pipe_ctx->link_res, 1603 &cur_link_settings, 1604 skip_video_pattern); 1605 1606 /* Transmit idle pattern once training successful. */ 1607 if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low) { 1608 dp_set_hw_test_pattern(link, &pipe_ctx->link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0); 1609 // Update verified link settings to current one 1610 // Because DPIA LT might fallback to lower link setting. 1611 if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { 1612 link->verified_link_cap.link_rate = link->cur_link_settings.link_rate; 1613 link->verified_link_cap.lane_count = link->cur_link_settings.lane_count; 1614 dm_helpers_dp_mst_update_branch_bandwidth(link->ctx, link); 1615 } 1616 } 1617 } else { 1618 status = dp_perform_link_training( 1619 link, 1620 &pipe_ctx->link_res, 1621 &cur_link_settings, 1622 skip_video_pattern); 1623 } 1624 1625 dp_trace_lt_total_count_increment(link, false); 1626 dp_trace_lt_result_update(link, status, false); 1627 dp_trace_set_lt_end_timestamp(link, false); 1628 if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low) 1629 return true; 1630 } 1631 1632 fail_count++; 1633 dp_trace_lt_fail_count_update(link, fail_count, false); 1634 if (link->ep_type == DISPLAY_ENDPOINT_PHY) { 1635 /* latest link training still fail or link training is aborted 1636 * skip delay and keep PHY on 1637 */ 1638 if (j == (attempts - 1) || (status == LINK_TRAINING_ABORT)) 1639 break; 1640 } 1641 1642 if (j == (attempts - 1)) { 1643 DC_LOG_WARNING( 1644 "%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) @ spread = %x : fail reason:(%d)\n", 1645 __func__, link->link_index, (unsigned int)j + 1, attempts, 1646 cur_link_settings.link_rate, cur_link_settings.lane_count, 1647 cur_link_settings.link_spread, status); 1648 } else { 1649 DC_LOG_HW_LINK_TRAINING( 1650 "%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) @ spread = %x : fail reason:(%d)\n", 1651 __func__, link->link_index, (unsigned int)j + 1, attempts, 1652 cur_link_settings.link_rate, cur_link_settings.lane_count, 1653 cur_link_settings.link_spread, status); 1654 } 1655 1656 dp_disable_link_phy(link, &pipe_ctx->link_res, signal); 1657 1658 /* Abort link training if failure due to sink being unplugged. */ 1659 if (status == LINK_TRAINING_ABORT) { 1660 enum dc_connection_type type = dc_connection_none; 1661 1662 link_detect_connection_type(link, &type); 1663 if (type == dc_connection_none) { 1664 DC_LOG_HW_LINK_TRAINING("%s: Aborting training because sink unplugged\n", __func__); 1665 break; 1666 } 1667 } 1668 1669 /* Try to train again at original settings if: 1670 * - not falling back between training attempts; 1671 * - aborted previous attempt due to reasons other than sink unplug; 1672 * - successfully trained but at a link rate lower than that required by stream; 1673 * - reached minimum link bandwidth. 1674 */ 1675 if (!do_fallback || (status == LINK_TRAINING_ABORT) || 1676 (status == LINK_TRAINING_SUCCESS && is_link_bw_low) || 1677 is_link_bw_min) { 1678 j++; 1679 cur_link_settings = *link_setting; 1680 delay_between_attempts += LINK_TRAINING_RETRY_DELAY; 1681 is_link_bw_low = false; 1682 is_link_bw_min = (cur_link_settings.link_rate <= LINK_RATE_LOW) && 1683 (cur_link_settings.lane_count <= LANE_COUNT_ONE); 1684 1685 } else if (do_fallback) { /* Try training at lower link bandwidth if doing fallback. */ 1686 uint32_t req_bw; 1687 uint32_t link_bw; 1688 enum dc_link_encoding_format link_encoding = DC_LINK_ENCODING_UNSPECIFIED; 1689 1690 decide_fallback_link_setting(link, &max_link_settings, 1691 &cur_link_settings, status); 1692 1693 if (link_dp_get_encoding_format(&cur_link_settings) == DP_8b_10b_ENCODING) 1694 link_encoding = DC_LINK_ENCODING_DP_8b_10b; 1695 else if (link_dp_get_encoding_format(&cur_link_settings) == DP_128b_132b_ENCODING) 1696 link_encoding = DC_LINK_ENCODING_DP_128b_132b; 1697 1698 /* Flag if reduced link bandwidth no longer meets stream requirements or fallen back to 1699 * minimum link bandwidth. 1700 */ 1701 req_bw = dc_bandwidth_in_kbps_from_timing(&stream->timing, link_encoding); 1702 link_bw = dp_link_bandwidth_kbps(link, &cur_link_settings); 1703 is_link_bw_low = (req_bw > link_bw); 1704 is_link_bw_min = ((cur_link_settings.link_rate <= LINK_RATE_LOW) && 1705 (cur_link_settings.lane_count <= LANE_COUNT_ONE)); 1706 1707 if (is_link_bw_low) 1708 DC_LOG_WARNING( 1709 "%s: Link(%d) bandwidth too low after fallback req_bw(%d) > link_bw(%d)\n", 1710 __func__, link->link_index, req_bw, link_bw); 1711 } 1712 1713 msleep(delay_between_attempts); 1714 } 1715 1716 return false; 1717} 1718 1719