File Index
Files and directories
Sign in
FILE

link_dp_training.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c C
   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	usleep_range_state(wait_in_micro_secs, wait_in_micro_secs, TASK_UNINTERRUPTIBLE);
 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
 333	/* Note, we are not checking
 334	 * if max_requested.FFE_PRESET.settings.level >  DP_FFE_PRESET_MAX_LEVEL,
 335	 * since FFE_PRESET.settings.level is 4 bits and DP_FFE_PRESET_MAX_LEVEL equals 15,
 336	 * so FFE_PRESET.settings.level will never be greater than 15.
 337	 */
 338
 339	/* make sure the pre-emphasis matches the voltage swing*/
 340	if (max_requested.PRE_EMPHASIS >
 341		get_max_pre_emphasis_for_voltage_swing(
 342			max_requested.VOLTAGE_SWING))
 343		max_requested.PRE_EMPHASIS =
 344		get_max_pre_emphasis_for_voltage_swing(
 345			max_requested.VOLTAGE_SWING);
 346
 347	for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
 348		lane_settings[lane].VOLTAGE_SWING = max_requested.VOLTAGE_SWING;
 349		lane_settings[lane].PRE_EMPHASIS = max_requested.PRE_EMPHASIS;
 350		lane_settings[lane].FFE_PRESET = max_requested.FFE_PRESET;
 351	}
 352}
 353
 354void dp_hw_to_dpcd_lane_settings(
 355		const struct link_training_settings *lt_settings,
 356		const struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
 357		union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX])
 358{
 359	uint8_t lane = 0;
 360
 361	for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
 362		if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
 363				DP_8b_10b_ENCODING) {
 364			dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET =
 365					(uint8_t)(hw_lane_settings[lane].VOLTAGE_SWING);
 366			dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET =
 367					(uint8_t)(hw_lane_settings[lane].PRE_EMPHASIS);
 368			dpcd_lane_settings[lane].bits.MAX_SWING_REACHED =
 369					(hw_lane_settings[lane].VOLTAGE_SWING ==
 370							VOLTAGE_SWING_MAX_LEVEL ? 1 : 0);
 371			dpcd_lane_settings[lane].bits.MAX_PRE_EMPHASIS_REACHED =
 372					(hw_lane_settings[lane].PRE_EMPHASIS ==
 373							PRE_EMPHASIS_MAX_LEVEL ? 1 : 0);
 374		} else if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
 375				DP_128b_132b_ENCODING) {
 376			dpcd_lane_settings[lane].tx_ffe.PRESET_VALUE =
 377					hw_lane_settings[lane].FFE_PRESET.settings.level;
 378		}
 379	}
 380}
 381
 382uint8_t get_dpcd_link_rate(const struct dc_link_settings *link_settings)
 383{
 384	uint8_t link_rate = 0;
 385	enum dp_link_encoding encoding = link_dp_get_encoding_format(link_settings);
 386
 387	if (encoding == DP_128b_132b_ENCODING)
 388		switch (link_settings->link_rate) {
 389		case LINK_RATE_UHBR10:
 390			link_rate = 0x1;
 391			break;
 392		case LINK_RATE_UHBR20:
 393			link_rate = 0x2;
 394			break;
 395		case LINK_RATE_UHBR13_5:
 396			link_rate = 0x4;
 397			break;
 398		default:
 399			link_rate = 0;
 400			break;
 401		}
 402	else if (encoding == DP_8b_10b_ENCODING)
 403		link_rate = (uint8_t) link_settings->link_rate;
 404	else
 405		link_rate = 0;
 406
 407	return link_rate;
 408}
 409
 410/* Only used for channel equalization */
 411uint32_t dp_translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval)
 412{
 413	unsigned int aux_rd_interval_us = 400;
 414
 415	switch (dpcd_aux_read_interval) {
 416	case 0x01:
 417		aux_rd_interval_us = 4000;
 418		break;
 419	case 0x02:
 420		aux_rd_interval_us = 8000;
 421		break;
 422	case 0x03:
 423		aux_rd_interval_us = 12000;
 424		break;
 425	case 0x04:
 426		aux_rd_interval_us = 16000;
 427		break;
 428	case 0x05:
 429		aux_rd_interval_us = 32000;
 430		break;
 431	case 0x06:
 432		aux_rd_interval_us = 64000;
 433		break;
 434	default:
 435		break;
 436	}
 437
 438	return aux_rd_interval_us;
 439}
 440
 441enum link_training_result dp_get_cr_failure(enum dc_lane_count ln_count,
 442					union lane_status *dpcd_lane_status)
 443{
 444	enum link_training_result result = LINK_TRAINING_SUCCESS;
 445
 446	if (ln_count >= LANE_COUNT_ONE && !dpcd_lane_status[0].bits.CR_DONE_0)
 447		result = LINK_TRAINING_CR_FAIL_LANE0;
 448	else if (ln_count >= LANE_COUNT_TWO && !dpcd_lane_status[1].bits.CR_DONE_0)
 449		result = LINK_TRAINING_CR_FAIL_LANE1;
 450	else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[2].bits.CR_DONE_0)
 451		result = LINK_TRAINING_CR_FAIL_LANE23;
 452	else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[3].bits.CR_DONE_0)
 453		result = LINK_TRAINING_CR_FAIL_LANE23;
 454	return result;
 455}
 456
 457bool is_repeater(const struct link_training_settings *lt_settings, uint32_t offset)
 458{
 459	return (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) && (offset != 0);
 460}
 461
 462bool dp_is_max_vs_reached(
 463	const struct link_training_settings *lt_settings)
 464{
 465	uint32_t lane;
 466	for (lane = 0; lane <
 467		(uint32_t)(lt_settings->link_settings.lane_count);
 468		lane++) {
 469		if (lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET
 470			== VOLTAGE_SWING_MAX_LEVEL)
 471			return true;
 472	}
 473	return false;
 474
 475}
 476
 477bool dp_is_cr_done(enum dc_lane_count ln_count,
 478	union lane_status *dpcd_lane_status)
 479{
 480	bool done = true;
 481	uint32_t lane;
 482	/*LANEx_CR_DONE bits All 1's?*/
 483	for (lane = 0; lane < (uint32_t)(ln_count); lane++) {
 484		if (!dpcd_lane_status[lane].bits.CR_DONE_0)
 485			done = false;
 486	}
 487	return done;
 488
 489}
 490
 491bool dp_is_ch_eq_done(enum dc_lane_count ln_count,
 492		union lane_status *dpcd_lane_status)
 493{
 494	bool done = true;
 495	uint32_t lane;
 496	for (lane = 0; lane < (uint32_t)(ln_count); lane++)
 497		if (!dpcd_lane_status[lane].bits.CHANNEL_EQ_DONE_0)
 498			done = false;
 499	return done;
 500}
 501
 502bool dp_is_symbol_locked(enum dc_lane_count ln_count,
 503		union lane_status *dpcd_lane_status)
 504{
 505	bool locked = true;
 506	uint32_t lane;
 507	for (lane = 0; lane < (uint32_t)(ln_count); lane++)
 508		if (!dpcd_lane_status[lane].bits.SYMBOL_LOCKED_0)
 509			locked = false;
 510	return locked;
 511}
 512
 513bool dp_is_interlane_aligned(union lane_align_status_updated align_status)
 514{
 515	return align_status.bits.INTERLANE_ALIGN_DONE == 1;
 516}
 517
 518bool dp_check_interlane_aligned(union lane_align_status_updated align_status,
 519		struct dc_link *link,
 520		uint8_t retries)
 521{
 522	/* Take into consideration corner case for DP 1.4a LL Compliance CTS as USB4
 523	 * has to share encoders unlike DP and USBC
 524	 */
 525	return (dp_is_interlane_aligned(align_status) ||
 526			(link->skip_fallback_on_link_loss && retries));
 527}
 528
 529uint32_t dp_get_eq_aux_rd_interval(
 530		const struct dc_link *link,
 531		const struct link_training_settings *lt_settings,
 532		uint32_t offset,
 533		uint8_t retries)
 534{
 535	if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) {
 536		if (offset == 0 && retries == 1 && lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
 537			return max(lt_settings->eq_pattern_time, (uint32_t) DPIA_CLK_SYNC_DELAY);
 538		else
 539			return dpia_get_eq_aux_rd_interval(link, lt_settings, offset);
 540	} else if (is_repeater(lt_settings, offset))
 541		return dp_translate_training_aux_read_interval(
 542				link->dpcd_caps.lttpr_caps.aux_rd_interval[offset - 1]);
 543	else
 544		return lt_settings->eq_pattern_time;
 545}
 546
 547bool dp_check_dpcd_reqeust_status(const struct dc_link *link,
 548		enum dc_status status)
 549{
 550	return (status != DC_OK && link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA);
 551}
 552
 553enum link_training_result dp_check_link_loss_status(
 554	struct dc_link *link,
 555	const struct link_training_settings *link_training_setting)
 556{
 557	enum link_training_result status = LINK_TRAINING_SUCCESS;
 558	union lane_status lane_status;
 559	union lane_align_status_updated dpcd_lane_status_updated;
 560	uint8_t dpcd_buf[6] = {0};
 561	uint32_t lane;
 562
 563	core_link_read_dpcd(
 564			link,
 565			DP_SINK_COUNT,
 566			(uint8_t *)(dpcd_buf),
 567			sizeof(dpcd_buf));
 568
 569	/*parse lane status*/
 570	for (lane = 0; lane < link->cur_link_settings.lane_count; lane++) {
 571		/*
 572		 * check lanes status
 573		 */
 574		lane_status.raw = dp_get_nibble_at_index(&dpcd_buf[2], lane);
 575		dpcd_lane_status_updated.raw = dpcd_buf[4];
 576
 577		if (!lane_status.bits.CHANNEL_EQ_DONE_0 ||
 578			!lane_status.bits.CR_DONE_0 ||
 579			!lane_status.bits.SYMBOL_LOCKED_0 ||
 580			!dp_is_interlane_aligned(dpcd_lane_status_updated)) {
 581			/* if one of the channel equalization, clock
 582			 * recovery or symbol lock is dropped
 583			 * consider it as (link has been
 584			 * dropped) dp sink status has changed
 585			 */
 586			status = LINK_TRAINING_LINK_LOSS;
 587			break;
 588		}
 589	}
 590
 591	return status;
 592}
 593
 594enum dc_status dp_get_lane_status_and_lane_adjust(
 595	struct dc_link *link,
 596	const struct link_training_settings *link_training_setting,
 597	union lane_status ln_status[LANE_COUNT_DP_MAX],
 598	union lane_align_status_updated *ln_align,
 599	union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
 600	uint32_t offset)
 601{
 602	unsigned int lane01_status_address = DP_LANE0_1_STATUS;
 603	uint8_t lane_adjust_offset = 4;
 604	unsigned int lane01_adjust_address;
 605	uint8_t dpcd_buf[6] = {0};
 606	uint32_t lane;
 607	enum dc_status status;
 608
 609	if (is_repeater(link_training_setting, offset)) {
 610		lane01_status_address =
 611				DP_LANE0_1_STATUS_PHY_REPEATER1 +
 612				((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
 613		lane_adjust_offset = 3;
 614	}
 615
 616	status = core_link_read_dpcd(
 617		link,
 618		lane01_status_address,
 619		(uint8_t *)(dpcd_buf),
 620		sizeof(dpcd_buf));
 621
 622	if (status != DC_OK) {
 623		DC_LOG_HW_LINK_TRAINING("%s:\n Failed to read from address 0x%X,"
 624			" keep current lane status and lane adjust unchanged",
 625			__func__,
 626			lane01_status_address);
 627		return status;
 628	}
 629
 630	for (lane = 0; lane <
 631		(uint32_t)(link_training_setting->link_settings.lane_count);
 632		lane++) {
 633
 634		ln_status[lane].raw =
 635			dp_get_nibble_at_index(&dpcd_buf[0], lane);
 636		ln_adjust[lane].raw =
 637			dp_get_nibble_at_index(&dpcd_buf[lane_adjust_offset], lane);
 638	}
 639
 640	ln_align->raw = dpcd_buf[2];
 641
 642	if (is_repeater(link_training_setting, offset)) {
 643		DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
 644				" 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ",
 645			__func__,
 646			offset,
 647			lane01_status_address, dpcd_buf[0],
 648			lane01_status_address + 1, dpcd_buf[1]);
 649
 650		lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1_PHY_REPEATER1 +
 651				((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
 652
 653		DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
 654				" 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n",
 655					__func__,
 656					offset,
 657					lane01_adjust_address,
 658					dpcd_buf[lane_adjust_offset],
 659					lane01_adjust_address + 1,
 660					dpcd_buf[lane_adjust_offset + 1]);
 661	} else {
 662		DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ",
 663			__func__,
 664			lane01_status_address, dpcd_buf[0],
 665			lane01_status_address + 1, dpcd_buf[1]);
 666
 667		lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1;
 668
 669		DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n",
 670			__func__,
 671			lane01_adjust_address,
 672			dpcd_buf[lane_adjust_offset],
 673			lane01_adjust_address + 1,
 674			dpcd_buf[lane_adjust_offset + 1]);
 675	}
 676
 677	return status;
 678}
 679
 680static void override_lane_settings(const struct link_training_settings *lt_settings,
 681		struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX])
 682{
 683	uint32_t lane;
 684
 685	if (lt_settings->voltage_swing == NULL &&
 686			lt_settings->pre_emphasis == NULL &&
 687			lt_settings->ffe_preset == NULL &&
 688			lt_settings->post_cursor2 == NULL)
 689
 690		return;
 691
 692	for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
 693		if (lt_settings->voltage_swing)
 694			lane_settings[lane].VOLTAGE_SWING = *lt_settings->voltage_swing;
 695		if (lt_settings->pre_emphasis)
 696			lane_settings[lane].PRE_EMPHASIS = *lt_settings->pre_emphasis;
 697		if (lt_settings->post_cursor2)
 698			lane_settings[lane].POST_CURSOR2 = *lt_settings->post_cursor2;
 699		if (lt_settings->ffe_preset)
 700			lane_settings[lane].FFE_PRESET = *lt_settings->ffe_preset;
 701	}
 702}
 703
 704void dp_get_lttpr_mode_override(struct dc_link *link, enum lttpr_mode *override)
 705{
 706	if (!dp_is_lttpr_present(link))
 707		return;
 708
 709	if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_TRANSPARENT) {
 710		*override = LTTPR_MODE_TRANSPARENT;
 711	} else if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_NON_TRANSPARENT) {
 712		*override = LTTPR_MODE_NON_TRANSPARENT;
 713	} else if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_NON_LTTPR) {
 714		*override = LTTPR_MODE_NON_LTTPR;
 715	}
 716	DC_LOG_DC("lttpr_mode_override chose LTTPR_MODE = %d\n", (uint8_t)(*override));
 717}
 718
 719void override_training_settings(
 720		struct dc_link *link,
 721		const struct dc_link_training_overrides *overrides,
 722		struct link_training_settings *lt_settings)
 723{
 724	uint32_t lane;
 725
 726	/* Override link spread */
 727	if (!link->dp_ss_off && overrides->downspread != NULL)
 728		lt_settings->link_settings.link_spread = *overrides->downspread ?
 729				LINK_SPREAD_05_DOWNSPREAD_30KHZ
 730				: LINK_SPREAD_DISABLED;
 731
 732	/* Override lane settings */
 733	if (overrides->voltage_swing != NULL)
 734		lt_settings->voltage_swing = overrides->voltage_swing;
 735	if (overrides->pre_emphasis != NULL)
 736		lt_settings->pre_emphasis = overrides->pre_emphasis;
 737	if (overrides->post_cursor2 != NULL)
 738		lt_settings->post_cursor2 = overrides->post_cursor2;
 739	if (link->wa_flags.force_dp_ffe_preset && !dp_is_lttpr_present(link))
 740		lt_settings->ffe_preset = &link->forced_dp_ffe_preset;
 741	if (overrides->ffe_preset != NULL)
 742		lt_settings->ffe_preset = overrides->ffe_preset;
 743	/* Override HW lane settings with BIOS forced values if present */
 744	if ((link->chip_caps & AMD_EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
 745			lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) {
 746		lt_settings->voltage_swing = &link->bios_forced_drive_settings.VOLTAGE_SWING;
 747		lt_settings->pre_emphasis = &link->bios_forced_drive_settings.PRE_EMPHASIS;
 748		lt_settings->always_match_dpcd_with_hw_lane_settings = false;
 749	}
 750	for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
 751		lt_settings->hw_lane_settings[lane].VOLTAGE_SWING =
 752			lt_settings->voltage_swing != NULL ?
 753			*lt_settings->voltage_swing :
 754			VOLTAGE_SWING_LEVEL0;
 755		lt_settings->hw_lane_settings[lane].PRE_EMPHASIS =
 756			lt_settings->pre_emphasis != NULL ?
 757			*lt_settings->pre_emphasis
 758			: PRE_EMPHASIS_DISABLED;
 759		lt_settings->hw_lane_settings[lane].POST_CURSOR2 =
 760			lt_settings->post_cursor2 != NULL ?
 761			*lt_settings->post_cursor2
 762			: POST_CURSOR2_DISABLED;
 763	}
 764
 765	if (lt_settings->always_match_dpcd_with_hw_lane_settings)
 766		dp_hw_to_dpcd_lane_settings(lt_settings,
 767				lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
 768
 769	/* Override training timings */
 770	if (overrides->cr_pattern_time != NULL)
 771		lt_settings->cr_pattern_time = *overrides->cr_pattern_time;
 772	if (overrides->eq_pattern_time != NULL)
 773		lt_settings->eq_pattern_time = *overrides->eq_pattern_time;
 774	if (overrides->pattern_for_cr != NULL)
 775		lt_settings->pattern_for_cr = *overrides->pattern_for_cr;
 776	if (overrides->pattern_for_eq != NULL)
 777		lt_settings->pattern_for_eq = *overrides->pattern_for_eq;
 778	if (overrides->enhanced_framing != NULL)
 779		lt_settings->enhanced_framing = *overrides->enhanced_framing;
 780	if (link->preferred_training_settings.fec_enable != NULL)
 781		lt_settings->should_set_fec_ready = *link->preferred_training_settings.fec_enable;
 782
 783	/* Check DP tunnel LTTPR mode debug option. */
 784	if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && link->dc->debug.dpia_debug.bits.force_non_lttpr)
 785		lt_settings->lttpr_mode = LTTPR_MODE_NON_LTTPR;
 786
 787	dp_get_lttpr_mode_override(link, &lt_settings->lttpr_mode);
 788}
 789
 790enum dc_dp_training_pattern decide_cr_training_pattern(
 791		const struct dc_link_settings *link_settings)
 792{
 793	switch (link_dp_get_encoding_format(link_settings)) {
 794	case DP_8b_10b_ENCODING:
 795	default:
 796		return DP_TRAINING_PATTERN_SEQUENCE_1;
 797	case DP_128b_132b_ENCODING:
 798		return DP_128b_132b_TPS1;
 799	}
 800}
 801
 802enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *link,
 803		const struct link_resource *link_res,
 804		const struct dc_link_settings *link_settings)
 805{
 806	struct link_encoder *link_enc = link_res->dio_link_enc;
 807	struct encoder_feature_support *enc_caps;
 808	struct dpcd_caps *rx_caps = &link->dpcd_caps;
 809	enum dc_dp_training_pattern pattern = DP_TRAINING_PATTERN_SEQUENCE_2;
 810
 811	switch (link_dp_get_encoding_format(link_settings)) {
 812	case DP_8b_10b_ENCODING:
 813		if (!link->dc->config.unify_link_enc_assignment)
 814			link_enc = link_enc_cfg_get_link_enc(link);
 815
 816		if (!link_enc)
 817			break;
 818
 819		enc_caps = &link_enc->features;
 820		if (enc_caps->flags.bits.IS_TPS4_CAPABLE &&
 821				rx_caps->max_down_spread.bits.TPS4_SUPPORTED)
 822			pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
 823		else if (enc_caps->flags.bits.IS_TPS3_CAPABLE &&
 824				rx_caps->max_ln_count.bits.TPS3_SUPPORTED)
 825			pattern = DP_TRAINING_PATTERN_SEQUENCE_3;
 826		else
 827			pattern = DP_TRAINING_PATTERN_SEQUENCE_2;
 828		break;
 829	case DP_128b_132b_ENCODING:
 830		pattern = DP_128b_132b_TPS2;
 831		break;
 832	default:
 833		pattern = DP_TRAINING_PATTERN_SEQUENCE_2;
 834		break;
 835	}
 836	return pattern;
 837}
 838
 839enum lttpr_mode dp_decide_lttpr_mode(struct dc_link *link,
 840		struct dc_link_settings *link_setting)
 841{
 842	enum dp_link_encoding encoding = link_dp_get_encoding_format(link_setting);
 843
 844	if (encoding == DP_8b_10b_ENCODING)
 845		return dp_decide_8b_10b_lttpr_mode(link);
 846	else if (encoding == DP_128b_132b_ENCODING)
 847		return dp_decide_128b_132b_lttpr_mode(link);
 848
 849	ASSERT(0);
 850	return LTTPR_MODE_NON_LTTPR;
 851}
 852
 853void dp_decide_lane_settings(
 854		const struct link_training_settings *lt_settings,
 855		const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
 856		struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
 857		union dpcd_training_lane *dpcd_lane_settings)
 858{
 859	uint32_t lane;
 860
 861	for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
 862		if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
 863				DP_8b_10b_ENCODING) {
 864			hw_lane_settings[lane].VOLTAGE_SWING =
 865					(enum dc_voltage_swing)(ln_adjust[lane].bits.
 866							VOLTAGE_SWING_LANE);
 867			hw_lane_settings[lane].PRE_EMPHASIS =
 868					(enum dc_pre_emphasis)(ln_adjust[lane].bits.
 869							PRE_EMPHASIS_LANE);
 870		} else if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
 871				DP_128b_132b_ENCODING) {
 872			hw_lane_settings[lane].FFE_PRESET.raw =
 873					ln_adjust[lane].tx_ffe.PRESET_VALUE;
 874		}
 875	}
 876	dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings);
 877
 878	if (lt_settings->disallow_per_lane_settings) {
 879		/* we find the maximum of the requested settings across all lanes*/
 880		/* and set this maximum for all lanes*/
 881		maximize_lane_settings(lt_settings, hw_lane_settings);
 882		override_lane_settings(lt_settings, hw_lane_settings);
 883
 884		if (lt_settings->always_match_dpcd_with_hw_lane_settings)
 885			dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings);
 886	}
 887
 888}
 889
 890void dp_decide_training_settings(
 891		struct dc_link *link,
 892		const struct link_resource *link_res,
 893		const struct dc_link_settings *link_settings,
 894		struct link_training_settings *lt_settings)
 895{
 896	if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING)
 897		decide_8b_10b_training_settings(link, link_res, link_settings, lt_settings);
 898	else if (link_dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING)
 899		decide_128b_132b_training_settings(link, link_res, link_settings, lt_settings);
 900}
 901
 902
 903enum dc_status configure_lttpr_mode_transparent(struct dc_link *link)
 904{
 905	uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT;
 906
 907	DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__);
 908	return core_link_write_dpcd(link,
 909			DP_PHY_REPEATER_MODE,
 910			(uint8_t *)&repeater_mode,
 911			sizeof(repeater_mode));
 912}
 913
 914static enum dc_status configure_lttpr_mode_non_transparent(
 915		struct dc_link *link,
 916		const struct link_training_settings *lt_settings)
 917{
 918	/* aux timeout is already set to extended */
 919	/* RESET/SET lttpr mode to enable non transparent mode */
 920	uint8_t repeater_cnt;
 921	uint32_t aux_interval_address;
 922	uint8_t repeater_id;
 923	enum dc_status result = DC_ERROR_UNEXPECTED;
 924	uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT;
 925	const struct dc *dc = link->dc;
 926
 927	enum dp_link_encoding encoding = dc->link_srv->dp_get_encoding_format(&lt_settings->link_settings);
 928
 929	if (encoding == DP_8b_10b_ENCODING) {
 930		DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__);
 931		result = core_link_write_dpcd(link,
 932				DP_PHY_REPEATER_MODE,
 933				(uint8_t *)&repeater_mode,
 934				sizeof(repeater_mode));
 935
 936	}
 937
 938	if (result == DC_OK) {
 939		link->dpcd_caps.lttpr_caps.mode = repeater_mode;
 940	}
 941
 942	if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
 943
 944		DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Non Transparent Mode\n", __func__);
 945
 946		repeater_mode = DP_PHY_REPEATER_MODE_NON_TRANSPARENT;
 947		result = core_link_write_dpcd(link,
 948				DP_PHY_REPEATER_MODE,
 949				(uint8_t *)&repeater_mode,
 950				sizeof(repeater_mode));
 951
 952		if (result == DC_OK) {
 953			link->dpcd_caps.lttpr_caps.mode = repeater_mode;
 954		}
 955
 956		if (encoding == DP_8b_10b_ENCODING) {
 957			repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
 958
 959			/* Driver does not need to train the first hop. Skip DPCD read and clear
 960			 * AUX_RD_INTERVAL for DPTX-to-DPIA hop.
 961			 */
 962			if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && repeater_cnt > 0 && repeater_cnt < MAX_REPEATER_CNT)
 963				link->dpcd_caps.lttpr_caps.aux_rd_interval[--repeater_cnt] = 0;
 964
 965			for (repeater_id = repeater_cnt; repeater_id > 0 && repeater_id < MAX_REPEATER_CNT; repeater_id--) {
 966				aux_interval_address = DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1 +
 967						((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (repeater_id - 1));
 968				core_link_read_dpcd(
 969						link,
 970						aux_interval_address,
 971						(uint8_t *)&link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1],
 972						sizeof(link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1]));
 973				link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1] &= 0x7F;
 974			}
 975		}
 976	}
 977
 978	return result;
 979}
 980
 981enum dc_status dpcd_configure_lttpr_mode(struct dc_link *link, struct link_training_settings *lt_settings)
 982{
 983	enum dc_status status = DC_OK;
 984
 985	if (lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT)
 986		status = configure_lttpr_mode_transparent(link);
 987
 988	else if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
 989		status = configure_lttpr_mode_non_transparent(link, lt_settings);
 990
 991	return status;
 992}
 993
 994void repeater_training_done(struct dc_link *link, uint32_t offset)
 995{
 996	union dpcd_training_pattern dpcd_pattern = {0};
 997
 998	const uint32_t dpcd_base_lt_offset =
 999			DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
1000				((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
1001	/* Set training not in progress*/
1002	dpcd_pattern.v1_4.TRAINING_PATTERN_SET = DPCD_TRAINING_PATTERN_VIDEOIDLE;
1003
1004	core_link_write_dpcd(
1005		link,
1006		dpcd_base_lt_offset,
1007		&dpcd_pattern.raw,
1008		1);
1009
1010	DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Id: %d 0x%X pattern = %x\n",
1011		__func__,
1012		offset,
1013		dpcd_base_lt_offset,
1014		dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
1015}
1016
1017static enum link_training_result dpcd_exit_training_mode(struct dc_link *link, enum dp_link_encoding encoding)
1018{
1019	enum dc_status status;
1020	uint8_t sink_status = 0;
1021	uint32_t i;
1022	uint8_t lttpr_count = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
1023	uint32_t intra_hop_disable_time_ms = (lttpr_count > 0 ? lttpr_count * 300 : 10);
1024
1025	// Each hop could theoretically take over 256ms (max 128b/132b AUX RD INTERVAL)
1026	// To be safe, allow 300ms per LTTPR and 10ms for no LTTPR case
1027
1028	/* clear training pattern set */
1029	status = dpcd_set_training_pattern(link, DP_TRAINING_PATTERN_VIDEOIDLE);
1030
1031	if (dp_check_dpcd_reqeust_status(link, status))
1032		return LINK_TRAINING_ABORT;
1033
1034	if (encoding == DP_128b_132b_ENCODING) {
1035		/* poll for intra-hop disable */
1036		for (i = 0; i < intra_hop_disable_time_ms; i++) {
1037			if ((core_link_read_dpcd(link, DP_SINK_STATUS, &sink_status, 1) == DC_OK) &&
1038					(sink_status & DP_INTRA_HOP_AUX_REPLY_INDICATION) == 0)
1039				break;
1040			fsleep(1000);
1041		}
1042	}
1043
1044	return LINK_TRAINING_SUCCESS;
1045}
1046
1047enum dc_status dpcd_configure_channel_coding(struct dc_link *link,
1048		struct link_training_settings *lt_settings)
1049{
1050	enum dp_link_encoding encoding =
1051			link_dp_get_encoding_format(
1052					&lt_settings->link_settings);
1053	enum dc_status status;
1054
1055	status = core_link_write_dpcd(
1056			link,
1057			DP_MAIN_LINK_CHANNEL_CODING_SET,
1058			(uint8_t *) &encoding,
1059			1);
1060	DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X MAIN_LINK_CHANNEL_CODING_SET = %x\n",
1061					__func__,
1062					DP_MAIN_LINK_CHANNEL_CODING_SET,
1063					encoding);
1064
1065	return status;
1066}
1067
1068enum dc_status dpcd_set_training_pattern(
1069	struct dc_link *link,
1070	enum dc_dp_training_pattern training_pattern)
1071{
1072	enum dc_status status;
1073	union dpcd_training_pattern dpcd_pattern = {0};
1074
1075	dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
1076			dp_training_pattern_to_dpcd_training_pattern(
1077					link, training_pattern);
1078
1079	status = core_link_write_dpcd(
1080		link,
1081		DP_TRAINING_PATTERN_SET,
1082		&dpcd_pattern.raw,
1083		1);
1084
1085	DC_LOG_HW_LINK_TRAINING("%s\n %x pattern = %x\n",
1086		__func__,
1087		DP_TRAINING_PATTERN_SET,
1088		dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
1089
1090	return status;
1091}
1092
1093enum dc_status dpcd_set_link_settings(
1094	struct dc_link *link,
1095	const struct link_training_settings *lt_settings)
1096{
1097	uint8_t rate;
1098	enum dc_status status;
1099
1100	union down_spread_ctrl downspread = {0};
1101	union lane_count_set lane_count_set = {0};
1102
1103	downspread.raw = (uint8_t)
1104	(lt_settings->link_settings.link_spread);
1105
1106	lane_count_set.bits.LANE_COUNT_SET =
1107	lt_settings->link_settings.lane_count;
1108
1109	lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
1110	lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
1111
1112
1113	if (link->ep_type == DISPLAY_ENDPOINT_PHY &&
1114			lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) {
1115		lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
1116				link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
1117	}
1118
1119	status = core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
1120		&downspread.raw, sizeof(downspread));
1121	if (status != DC_OK)
1122		DC_LOG_ERROR("%s:%d: core_link_write_dpcd (DP_DOWNSPREAD_CTRL) failed\n", __func__, __LINE__);
1123
1124	status = core_link_write_dpcd(link, DP_LANE_COUNT_SET,
1125		&lane_count_set.raw, 1);
1126	if (status != DC_OK)
1127		DC_LOG_ERROR("%s:%d: core_link_write_dpcd (DP_LANE_COUNT_SET) failed\n", __func__, __LINE__);
1128
1129	if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_13 &&
1130			lt_settings->link_settings.use_link_rate_set == true) {
1131		rate = 0;
1132		/* WA for some MUX chips that will power down with eDP and lose supported
1133		 * link rate set for eDP 1.4. Source reads DPCD 0x010 again to ensure
1134		 * MUX chip gets link rate set back before link training.
1135		 */
1136		if (link->connector_signal == SIGNAL_TYPE_EDP) {
1137			uint8_t supported_link_rates[16] = {0};
1138
1139			core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES,
1140					supported_link_rates, sizeof(supported_link_rates));
1141		}
1142		status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
1143		if (status != DC_OK)
1144			DC_LOG_ERROR("%s:%d: core_link_write_dpcd (DP_LINK_BW_SET) failed\n", __func__, __LINE__);
1145
1146		status = core_link_write_dpcd(link, DP_LINK_RATE_SET,
1147				&lt_settings->link_settings.link_rate_set, 1);
1148		if (status != DC_OK)
1149			DC_LOG_ERROR("%s:%d: core_link_write_dpcd (DP_LINK_RATE_SET) failed\n", __func__, __LINE__);
1150	} else {
1151		rate = get_dpcd_link_rate(&lt_settings->link_settings);
1152
1153		status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
1154		if (status != DC_OK)
1155			DC_LOG_ERROR("%s:%d: core_link_write_dpcd (DP_LINK_BW_SET) failed\n", __func__, __LINE__);
1156	}
1157
1158	if (rate) {
1159		DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
1160			__func__,
1161			DP_LINK_BW_SET,
1162			lt_settings->link_settings.link_rate,
1163			DP_LANE_COUNT_SET,
1164			lt_settings->link_settings.lane_count,
1165			lt_settings->enhanced_framing,
1166			DP_DOWNSPREAD_CTRL,
1167			lt_settings->link_settings.link_spread);
1168	} else {
1169		DC_LOG_HW_LINK_TRAINING("%s\n %x rate set = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
1170			__func__,
1171			DP_LINK_RATE_SET,
1172			lt_settings->link_settings.link_rate_set,
1173			DP_LANE_COUNT_SET,
1174			lt_settings->link_settings.lane_count,
1175			lt_settings->enhanced_framing,
1176			DP_DOWNSPREAD_CTRL,
1177			lt_settings->link_settings.link_spread);
1178	}
1179
1180	return status;
1181}
1182
1183enum dc_status dpcd_set_lane_settings(
1184	struct dc_link *link,
1185	const struct link_training_settings *link_training_setting,
1186	uint32_t offset)
1187{
1188	unsigned int lane0_set_address;
1189	enum dc_status status;
1190	lane0_set_address = DP_TRAINING_LANE0_SET;
1191
1192	if (is_repeater(link_training_setting, offset))
1193		lane0_set_address = DP_TRAINING_LANE0_SET_PHY_REPEATER1 +
1194		((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
1195
1196	status = core_link_write_dpcd(link,
1197		lane0_set_address,
1198		(uint8_t *)(link_training_setting->dpcd_lane_settings),
1199		link_training_setting->link_settings.lane_count);
1200
1201	if (is_repeater(link_training_setting, offset)) {
1202		DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n"
1203				" 0x%X VS set = %x  PE set = %x max VS Reached = %x  max PE Reached = %x\n",
1204			__func__,
1205			offset,
1206			lane0_set_address,
1207			link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
1208			link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
1209			link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
1210			link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
1211
1212	} else {
1213		DC_LOG_HW_LINK_TRAINING("%s\n 0x%X VS set = %x  PE set = %x max VS Reached = %x  max PE Reached = %x\n",
1214			__func__,
1215			lane0_set_address,
1216			link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
1217			link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
1218			link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
1219			link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
1220	}
1221
1222	return status;
1223}
1224
1225void dpcd_set_lt_pattern_and_lane_settings(
1226	struct dc_link *link,
1227	const struct link_training_settings *lt_settings,
1228	enum dc_dp_training_pattern pattern,
1229	uint32_t offset)
1230{
1231	uint32_t dpcd_base_lt_offset;
1232	uint8_t dpcd_lt_buffer[5] = {0};
1233	union dpcd_training_pattern dpcd_pattern = {0};
1234	uint32_t size_in_bytes;
1235	bool edp_workaround = false; /* TODO link_prop.INTERNAL */
1236	dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET;
1237
1238	if (is_repeater(lt_settings, offset))
1239		dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
1240			((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
1241
1242	/*****************************************************************
1243	* DpcdAddress_TrainingPatternSet
1244	*****************************************************************/
1245	dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
1246		dp_training_pattern_to_dpcd_training_pattern(link, pattern);
1247
1248	dpcd_pattern.v1_4.SCRAMBLING_DISABLE =
1249		dp_initialize_scrambling_data_symbols(link, pattern);
1250
1251	dpcd_lt_buffer[DP_TRAINING_PATTERN_SET - DP_TRAINING_PATTERN_SET]
1252		= dpcd_pattern.raw;
1253
1254	if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
1255		dpia_set_tps_notification(
1256			link,
1257			lt_settings,
1258			dpcd_pattern.v1_4.TRAINING_PATTERN_SET,
1259			offset);
1260
1261	if (is_repeater(lt_settings, offset)) {
1262		DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n 0x%X pattern = %x\n",
1263			__func__,
1264			offset,
1265			dpcd_base_lt_offset,
1266			dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
1267	} else {
1268		DC_LOG_HW_LINK_TRAINING("%s\n 0x%X pattern = %x\n",
1269			__func__,
1270			dpcd_base_lt_offset,
1271			dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
1272	}
1273
1274	/* concatenate everything into one buffer*/
1275	size_in_bytes = lt_settings->link_settings.lane_count *
1276			sizeof(lt_settings->dpcd_lane_settings[0]);
1277
1278	 // 0x00103 - 0x00102
1279	memmove(
1280		&dpcd_lt_buffer[DP_TRAINING_LANE0_SET - DP_TRAINING_PATTERN_SET],
1281		lt_settings->dpcd_lane_settings,
1282		size_in_bytes);
1283
1284	if (is_repeater(lt_settings, offset)) {
1285		if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
1286				DP_128b_132b_ENCODING)
1287			DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
1288					" 0x%X TX_FFE_PRESET_VALUE = %x\n",
1289					__func__,
1290					offset,
1291					dpcd_base_lt_offset,
1292					lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
1293		else if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
1294				DP_8b_10b_ENCODING)
1295		DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
1296				" 0x%X VS set = %x PE set = %x max VS Reached = %x  max PE Reached = %x\n",
1297			__func__,
1298			offset,
1299			dpcd_base_lt_offset,
1300			lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
1301			lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
1302			lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
1303			lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
1304	} else {
1305		if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
1306				DP_128b_132b_ENCODING)
1307			DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n",
1308					__func__,
1309					dpcd_base_lt_offset,
1310					lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
1311		else if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
1312				DP_8b_10b_ENCODING)
1313			DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X VS set = %x  PE set = %x max VS Reached = %x  max PE Reached = %x\n",
1314					__func__,
1315					dpcd_base_lt_offset,
1316					lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
1317					lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
1318					lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
1319					lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
1320	}
1321	if (edp_workaround) {
1322		/* for eDP write in 2 parts because the 5-byte burst is
1323		* causing issues on some eDP panels (EPR#366724)
1324		*/
1325		core_link_write_dpcd(
1326			link,
1327			DP_TRAINING_PATTERN_SET,
1328			&dpcd_pattern.raw,
1329			sizeof(dpcd_pattern.raw));
1330
1331		core_link_write_dpcd(
1332			link,
1333			DP_TRAINING_LANE0_SET,
1334			(uint8_t *)(lt_settings->dpcd_lane_settings),
1335			size_in_bytes);
1336
1337	} else if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
1338			DP_128b_132b_ENCODING) {
1339		core_link_write_dpcd(
1340				link,
1341				dpcd_base_lt_offset,
1342				dpcd_lt_buffer,
1343				sizeof(dpcd_lt_buffer));
1344	} else
1345		/* write it all in (1 + number-of-lanes)-byte burst*/
1346		core_link_write_dpcd(
1347				link,
1348				dpcd_base_lt_offset,
1349				dpcd_lt_buffer,
1350				size_in_bytes + sizeof(dpcd_pattern.raw));
1351}
1352
1353void start_clock_recovery_pattern_early(struct dc_link *link,
1354		const struct link_resource *link_res,
1355		struct link_training_settings *lt_settings,
1356		uint32_t offset)
1357{
1358	DC_LOG_HW_LINK_TRAINING("%s\n GPU sends TPS1. Wait 400us.\n",
1359			__func__);
1360	dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, offset);
1361	dp_set_hw_lane_settings(link, link_res, lt_settings, offset);
1362	udelay(400);
1363}
1364
1365void dp_set_hw_test_pattern(
1366	struct dc_link *link,
1367	const struct link_resource *link_res,
1368	enum dp_test_pattern test_pattern,
1369	uint8_t *custom_pattern,
1370	uint32_t custom_pattern_size)
1371{
1372	const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
1373	struct encoder_set_dp_phy_pattern_param pattern_param = {0};
1374
1375	pattern_param.dp_phy_pattern = test_pattern;
1376	pattern_param.custom_pattern = custom_pattern;
1377	pattern_param.custom_pattern_size = custom_pattern_size;
1378	pattern_param.dp_panel_mode = dp_get_panel_mode(link);
1379
1380	if (link_hwss->ext.set_dp_link_test_pattern)
1381		link_hwss->ext.set_dp_link_test_pattern(link, link_res, &pattern_param);
1382}
1383
1384bool dp_set_hw_training_pattern(
1385	struct dc_link *link,
1386	const struct link_resource *link_res,
1387	enum dc_dp_training_pattern pattern,
1388	uint32_t offset)
1389{
1390	enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED;
1391
1392	switch (pattern) {
1393	case DP_TRAINING_PATTERN_SEQUENCE_1:
1394		test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN1;
1395		break;
1396	case DP_TRAINING_PATTERN_SEQUENCE_2:
1397		test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN2;
1398		break;
1399	case DP_TRAINING_PATTERN_SEQUENCE_3:
1400		test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN3;
1401		break;
1402	case DP_TRAINING_PATTERN_SEQUENCE_4:
1403		test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
1404		break;
1405	case DP_128b_132b_TPS1:
1406		test_pattern = DP_TEST_PATTERN_128b_132b_TPS1_TRAINING_MODE;
1407		break;
1408	case DP_128b_132b_TPS2:
1409		test_pattern = DP_TEST_PATTERN_128b_132b_TPS2_TRAINING_MODE;
1410		break;
1411	default:
1412		break;
1413	}
1414
1415	dp_set_hw_test_pattern(link, link_res, test_pattern, NULL, 0);
1416
1417	return true;
1418}
1419
1420static bool perform_post_lt_adj_req_sequence(
1421		struct dc_link *link,
1422		const struct link_resource *link_res,
1423		struct link_training_settings *lt_settings)
1424{
1425	enum dc_lane_count lane_count =
1426	lt_settings->link_settings.lane_count;
1427
1428	uint32_t adj_req_count;
1429	uint32_t adj_req_timer;
1430	bool req_drv_setting_changed;
1431	uint32_t lane;
1432	union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
1433	union lane_align_status_updated dpcd_lane_status_updated = {0};
1434	union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
1435
1436	req_drv_setting_changed = false;
1437	for (adj_req_count = 0; adj_req_count < POST_LT_ADJ_REQ_LIMIT;
1438	adj_req_count++) {
1439
1440		req_drv_setting_changed = false;
1441
1442		for (adj_req_timer = 0;
1443			adj_req_timer < POST_LT_ADJ_REQ_TIMEOUT;
1444			adj_req_timer++) {
1445
1446			dp_get_lane_status_and_lane_adjust(
1447				link,
1448				lt_settings,
1449				dpcd_lane_status,
1450				&dpcd_lane_status_updated,
1451				dpcd_lane_adjust,
1452				DPRX);
1453
1454			if (dpcd_lane_status_updated.bits.
1455					POST_LT_ADJ_REQ_IN_PROGRESS == 0)
1456				return true;
1457
1458			if (!dp_is_cr_done(lane_count, dpcd_lane_status))
1459				return false;
1460
1461			if (!dp_is_ch_eq_done(lane_count, dpcd_lane_status) ||
1462					!dp_is_symbol_locked(lane_count, dpcd_lane_status) ||
1463					!dp_is_interlane_aligned(dpcd_lane_status_updated))
1464				return false;
1465
1466			for (lane = 0; lane < (uint32_t)(lane_count); lane++) {
1467
1468				if (lt_settings->
1469				dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET !=
1470				dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_LANE ||
1471				lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET !=
1472				dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_LANE) {
1473
1474					req_drv_setting_changed = true;
1475					break;
1476				}
1477			}
1478
1479			if (req_drv_setting_changed) {
1480				dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
1481						lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
1482
1483				dp_set_drive_settings(link,
1484						link_res,
1485						lt_settings);
1486				break;
1487			}
1488
1489			msleep(1);
1490		}
1491
1492		if (!req_drv_setting_changed) {
1493			DC_LOG_WARNING("%s: Post Link Training Adjust Request Timed out\n",
1494				__func__);
1495
1496			ASSERT(0);
1497			return true;
1498		}
1499	}
1500	DC_LOG_WARNING("%s: Post Link Training Adjust Request limit reached\n",
1501		__func__);
1502
1503	ASSERT(0);
1504	return true;
1505
1506}
1507
1508static enum link_training_result dp_transition_to_video_idle(
1509	struct dc_link *link,
1510	const struct link_resource *link_res,
1511	struct link_training_settings *lt_settings,
1512	enum link_training_result status)
1513{
1514	union lane_count_set lane_count_set = {0};
1515
1516	/* 4. mainlink output idle pattern*/
1517	dp_set_hw_test_pattern(link, link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
1518
1519	/*
1520	 * 5. post training adjust if required
1521	 * If the upstream DPTX and downstream DPRX both support TPS4,
1522	 * TPS4 must be used instead of POST_LT_ADJ_REQ.
1523	 */
1524	if (link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED != 1 ||
1525			lt_settings->pattern_for_eq >= DP_TRAINING_PATTERN_SEQUENCE_4) {
1526		/* delay 5ms after Main Link output idle pattern and then check
1527		 * DPCD 0202h.
1528		 */
1529		if (link->connector_signal != SIGNAL_TYPE_EDP && status == LINK_TRAINING_SUCCESS) {
1530			msleep(5);
1531			if (!link->skip_fallback_on_link_loss)
1532				status = dp_check_link_loss_status(link, lt_settings);
1533		}
1534		return status;
1535	}
1536
1537	if (status == LINK_TRAINING_SUCCESS &&
1538		perform_post_lt_adj_req_sequence(link, link_res, lt_settings) == false)
1539		status = LINK_TRAINING_LQA_FAIL;
1540
1541	lane_count_set.bits.LANE_COUNT_SET = lt_settings->link_settings.lane_count;
1542	lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
1543	lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
1544
1545	core_link_write_dpcd(
1546		link,
1547		DP_LANE_COUNT_SET,
1548		&lane_count_set.raw,
1549		sizeof(lane_count_set));
1550
1551	return status;
1552}
1553
1554enum link_training_result dp_perform_link_training(
1555	struct dc_link *link,
1556	const struct link_resource *link_res,
1557	const struct dc_link_settings *link_settings,
1558	bool skip_video_pattern)
1559{
1560	enum link_training_result status = LINK_TRAINING_SUCCESS;
1561	struct link_training_settings lt_settings = {0};
1562	enum dp_link_encoding encoding =
1563			link_dp_get_encoding_format(link_settings);
1564
1565	/* decide training settings */
1566	dp_decide_training_settings(
1567			link,
1568			link_res,
1569			link_settings,
1570			&lt_settings);
1571
1572	override_training_settings(
1573			link,
1574			&link->preferred_training_settings,
1575			&lt_settings);
1576
1577	/* reset previous training states */
1578	dpcd_exit_training_mode(link, encoding);
1579
1580	/* configure link prior to entering training mode */
1581	dpcd_configure_lttpr_mode(link, &lt_settings);
1582	if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING)
1583		dp_set_fec_ready(link, link_res, lt_settings.should_set_fec_ready);
1584	dpcd_configure_channel_coding(link, &lt_settings);
1585
1586	/* enter training mode:
1587	 * Per DP specs starting from here, DPTX device shall not issue
1588	 * Non-LT AUX transactions inside training mode.
1589	 */
1590	if (((link->chip_caps & AMD_EXT_DISPLAY_PATH_CAPS__EXT_CHIP_MASK) == AMD_EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && encoding == DP_8b_10b_ENCODING)
1591		status = dp_perform_fixed_vs_pe_training_sequence(link, link_res, &lt_settings);
1592	else if (encoding == DP_8b_10b_ENCODING)
1593		status = dp_perform_8b_10b_link_training(link, link_res, &lt_settings);
1594	else if (encoding == DP_128b_132b_ENCODING)
1595		status = dp_perform_128b_132b_link_training(link, link_res, &lt_settings);
1596	else
1597		ASSERT(0);
1598
1599	/* exit training mode */
1600	if ((dpcd_exit_training_mode(link, encoding) != LINK_TRAINING_SUCCESS || status == LINK_TRAINING_ABORT) &&
1601			link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
1602		dpia_training_abort(link, &lt_settings, 0);
1603
1604	/* switch to video idle */
1605	if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern)
1606		status = dp_transition_to_video_idle(link,
1607				link_res,
1608				&lt_settings,
1609				status);
1610
1611	/* dump debug data */
1612	dp_log_training_result(link, &lt_settings, status);
1613	if (status != LINK_TRAINING_SUCCESS)
1614		link->ctx->dc->debug_data.ltFailCount++;
1615	return status;
1616}
1617
1618bool perform_link_training_with_retries(
1619	const struct dc_link_settings *link_setting,
1620	bool skip_video_pattern,
1621	int attempts,
1622	struct pipe_ctx *pipe_ctx,
1623	enum signal_type signal,
1624	bool do_fallback)
1625{
1626	int j;
1627	uint8_t delay_between_attempts = LINK_TRAINING_RETRY_DELAY;
1628	struct dc_stream_state *stream = pipe_ctx->stream;
1629	struct dc_link *link = stream->link;
1630	enum dp_panel_mode panel_mode = dp_get_panel_mode(link);
1631	enum link_training_result status = LINK_TRAINING_CR_FAIL_LANE0;
1632	struct dc_link_settings cur_link_settings = *link_setting;
1633	struct dc_link_settings max_link_settings = *link_setting;
1634	const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
1635	int fail_count = 0;
1636	bool is_link_bw_low = false; /* link bandwidth < stream bandwidth */
1637	bool is_link_bw_min = /* RBR x 1 */
1638		(cur_link_settings.link_rate <= LINK_RATE_LOW) &&
1639		(cur_link_settings.lane_count <= LANE_COUNT_ONE);
1640
1641	dp_trace_commit_lt_init(link);
1642
1643
1644	if (link_dp_get_encoding_format(&cur_link_settings) == DP_8b_10b_ENCODING)
1645		/* We need to do this before the link training to ensure the idle
1646		 * pattern in SST mode will be sent right after the link training
1647		 */
1648		link_hwss->setup_stream_encoder(pipe_ctx);
1649
1650	dp_trace_set_lt_start_timestamp(link, false);
1651	j = 0;
1652	while (j < attempts && fail_count < (attempts * 10)) {
1653
1654		DC_LOG_HW_LINK_TRAINING("%s: Beginning link(%d) training attempt %u of %d @ rate(%d) x lane(%d) @ spread = %x\n",
1655					__func__, link->link_index, (unsigned int)j + 1, attempts,
1656				       cur_link_settings.link_rate, cur_link_settings.lane_count,
1657				       cur_link_settings.link_spread);
1658
1659		dp_enable_link_phy(
1660			link,
1661			&pipe_ctx->link_res,
1662			signal,
1663			pipe_ctx->clock_source->id,
1664			&cur_link_settings);
1665
1666		if (stream->sink_patches.dppowerup_delay > 0) {
1667			int delay_dp_power_up_in_ms = stream->sink_patches.dppowerup_delay;
1668
1669			msleep(delay_dp_power_up_in_ms);
1670		}
1671
1672		edp_set_panel_assr(link, pipe_ctx, &panel_mode, true);
1673
1674		dp_set_panel_mode(link, panel_mode);
1675
1676		if (link->aux_access_disabled) {
1677			dp_perform_link_training_skip_aux(link, &pipe_ctx->link_res, &cur_link_settings);
1678			return true;
1679		} else {
1680			if (!link->dc->config.consolidated_dpia_dp_lt && link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) {
1681				status = dpia_perform_link_training(
1682						link,
1683						&pipe_ctx->link_res,
1684						&cur_link_settings,
1685						skip_video_pattern);
1686
1687				/* Transmit idle pattern once training successful. */
1688				if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low) {
1689					dp_set_hw_test_pattern(link, &pipe_ctx->link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
1690					// Update verified link settings to current one
1691					// Because DPIA LT might fallback to lower link setting.
1692					if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
1693						link->verified_link_cap.link_rate = link->cur_link_settings.link_rate;
1694						link->verified_link_cap.lane_count = link->cur_link_settings.lane_count;
1695						dm_helpers_dp_mst_update_branch_bandwidth(link->ctx, link);
1696					}
1697				}
1698			} else {
1699				status = dp_perform_link_training(
1700						link,
1701						&pipe_ctx->link_res,
1702						&cur_link_settings,
1703						skip_video_pattern);
1704			}
1705
1706			dp_trace_lt_total_count_increment(link, false);
1707			dp_trace_lt_result_update(link, status, false);
1708			dp_trace_set_lt_end_timestamp(link, false);
1709			if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low) {
1710				// Update verified link settings to current one
1711				// Because DPIA LT might fallback to lower link setting.
1712				if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
1713						stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
1714					link->verified_link_cap.link_rate = link->cur_link_settings.link_rate;
1715					link->verified_link_cap.lane_count = link->cur_link_settings.lane_count;
1716					dm_helpers_dp_mst_update_branch_bandwidth(link->ctx, link);
1717				}
1718				return true;
1719			}
1720		}
1721
1722		fail_count++;
1723		dp_trace_lt_fail_count_update(link, fail_count, false);
1724		if (link->ep_type == DISPLAY_ENDPOINT_PHY) {
1725			/* latest link training still fail or link training is aborted
1726			 * skip delay and keep PHY on
1727			 */
1728			if (j == (attempts - 1) || (status == LINK_TRAINING_ABORT))
1729				break;
1730		}
1731
1732		if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
1733				stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST &&
1734				!link->dc->config.enable_dpia_pre_training) {
1735			if (j == (attempts - 1))
1736				do_fallback = true;
1737			else
1738				do_fallback = false;
1739		}
1740
1741		if (j == (attempts - 1)) {
1742			DC_LOG_WARNING(
1743				"%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) @ spread = %x : fail reason:(%d)\n",
1744				__func__, link->link_index, (unsigned int)j + 1, attempts,
1745				cur_link_settings.link_rate, cur_link_settings.lane_count,
1746				cur_link_settings.link_spread, status);
1747		} else {
1748			DC_LOG_HW_LINK_TRAINING(
1749				"%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) @ spread = %x : fail reason:(%d)\n",
1750				__func__, link->link_index, (unsigned int)j + 1, attempts,
1751				cur_link_settings.link_rate, cur_link_settings.lane_count,
1752				cur_link_settings.link_spread, status);
1753		}
1754
1755		dp_disable_link_phy(link, &pipe_ctx->link_res, signal);
1756
1757		/* Abort link training if failure due to sink being unplugged. */
1758		if (status == LINK_TRAINING_ABORT) {
1759			enum dc_connection_type type = dc_connection_none;
1760
1761			if (link_detect_connection_type(link, &type) && type == dc_connection_none) {
1762				DC_LOG_HW_LINK_TRAINING("%s: Aborting training because sink unplugged\n", __func__);
1763				break;
1764			}
1765		}
1766
1767		/* Try to train again at original settings if:
1768		 * - not falling back between training attempts;
1769		 * - aborted previous attempt due to reasons other than sink unplug;
1770		 * - successfully trained but at a link rate lower than that required by stream;
1771		 * - reached minimum link bandwidth.
1772		 */
1773		if (!do_fallback || (status == LINK_TRAINING_ABORT) ||
1774				(status == LINK_TRAINING_SUCCESS && is_link_bw_low) ||
1775				is_link_bw_min) {
1776			j++;
1777			cur_link_settings = *link_setting;
1778			delay_between_attempts += LINK_TRAINING_RETRY_DELAY;
1779			is_link_bw_low = false;
1780			is_link_bw_min = (cur_link_settings.link_rate <= LINK_RATE_LOW) &&
1781				(cur_link_settings.lane_count <= LANE_COUNT_ONE);
1782
1783		} else if (do_fallback) { /* Try training at lower link bandwidth if doing fallback. */
1784			uint32_t req_bw;
1785			uint32_t link_bw;
1786			enum dc_link_encoding_format link_encoding = DC_LINK_ENCODING_UNSPECIFIED;
1787
1788			decide_fallback_link_setting(link, &max_link_settings,
1789					&cur_link_settings, status);
1790
1791			if (link_dp_get_encoding_format(&cur_link_settings) == DP_8b_10b_ENCODING)
1792				link_encoding = DC_LINK_ENCODING_DP_8b_10b;
1793			else if (link_dp_get_encoding_format(&cur_link_settings) == DP_128b_132b_ENCODING)
1794				link_encoding = DC_LINK_ENCODING_DP_128b_132b;
1795
1796			/* Flag if reduced link bandwidth no longer meets stream requirements or fallen back to
1797			 * minimum link bandwidth.
1798			 */
1799			req_bw = dc_bandwidth_in_kbps_from_timing(&stream->timing, link_encoding);
1800			link_bw = dp_link_bandwidth_kbps(link, &cur_link_settings);
1801			is_link_bw_low = (req_bw > link_bw);
1802			is_link_bw_min = ((cur_link_settings.link_rate <= LINK_RATE_LOW) &&
1803				(cur_link_settings.lane_count <= LANE_COUNT_ONE));
1804
1805			if (is_link_bw_low)
1806				DC_LOG_WARNING(
1807					"%s: Link(%d) bandwidth too low after fallback req_bw(%d) > link_bw(%d)\n",
1808					__func__, link->link_index, req_bw, link_bw);
1809		}
1810
1811		msleep(delay_between_attempts);
1812	}
1813
1814	return false;
1815}
1816
~/ Read-only file preview.