Commit 64c12b73 authored by abdoulaye berthe's avatar abdoulaye berthe Committed by Alex Deucher
Browse files

drm/amd/display: implement lttpr logic



1-If at least one repeater is present in the link and we are in non
transparent mode, perform clock recovery then channel equalization
with all repeaters one by one before training DPRX.

2-Mark the end of LT with a repeater by setting training pattern 0
at the end of channel equalization with each repeater.

Signed-off-by: default avatarabdoulaye berthe <abdoulaye.berthe@amd.com>
Reviewed-by: default avatarAric Cyr <Aric.Cyr@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent bad7ab0b
Loading
Loading
Loading
Loading
+251 −68
Original line number Diff line number Diff line
@@ -22,7 +22,7 @@
	link->ctx->logger


#define DP_REPEATER_CONFIGURATION_AND_STATUS_OFFSET   0x50
#define DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE   0x50

/* maximum pre emphasis level allowed for each voltage swing level*/
static const enum dc_pre_emphasis voltage_swing_to_pre_emphasis[] = {
@@ -224,19 +224,31 @@ static enum dpcd_training_patterns
	return dpcd_tr_pattern;
}

static inline bool is_repeater(struct dc_link *link, uint32_t offset)
{
	return (!link->is_lttpr_mode_transparent && offset != 0);
}

static void dpcd_set_lt_pattern_and_lane_settings(
	struct dc_link *link,
	const struct link_training_settings *lt_settings,
	enum dc_dp_training_pattern pattern)
	enum dc_dp_training_pattern pattern,
	uint32_t offset)
{
	union dpcd_training_lane dpcd_lane[LANE_COUNT_DP_MAX] = { { {0} } };
	const uint32_t dpcd_base_lt_offset =
	DP_TRAINING_PATTERN_SET;

	uint32_t dpcd_base_lt_offset;

	uint8_t dpcd_lt_buffer[5] = {0};
	union dpcd_training_pattern dpcd_pattern = { {0} };
	uint32_t lane;
	uint32_t size_in_bytes;
	bool edp_workaround = false; /* TODO link_prop.INTERNAL */
	dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET;

	if (is_repeater(link, offset))
		dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
			((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));

	/*****************************************************************
	* DpcdAddress_TrainingPatternSet
@@ -244,12 +256,12 @@ static void dpcd_set_lt_pattern_and_lane_settings(
	dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
		dc_dp_training_pattern_to_dpcd_training_pattern(link, pattern);

	dpcd_lt_buffer[DP_TRAINING_PATTERN_SET - dpcd_base_lt_offset]
	dpcd_lt_buffer[DP_TRAINING_PATTERN_SET - DP_TRAINING_PATTERN_SET]
		= dpcd_pattern.raw;

	DC_LOG_HW_LINK_TRAINING("%s\n %x pattern = %x\n",
	DC_LOG_HW_LINK_TRAINING("%s\n 0x%X pattern = %x\n",
		__func__,
		DP_TRAINING_PATTERN_SET,
		dpcd_base_lt_offset,
		dpcd_pattern.v1_4.TRAINING_PATTERN_SET);

	/*****************************************************************
@@ -271,19 +283,19 @@ static void dpcd_set_lt_pattern_and_lane_settings(
		PRE_EMPHASIS_MAX_LEVEL ? 1 : 0);
	}

	/* concatinate everything into one buffer*/
	/* concatenate everything into one buffer*/

	size_in_bytes = lt_settings->link_settings.lane_count * sizeof(dpcd_lane[0]);

	 // 0x00103 - 0x00102
	memmove(
		&dpcd_lt_buffer[DP_TRAINING_LANE0_SET - dpcd_base_lt_offset],
		&dpcd_lt_buffer[DP_TRAINING_LANE0_SET - DP_TRAINING_PATTERN_SET],
		dpcd_lane,
		size_in_bytes);

	DC_LOG_HW_LINK_TRAINING("%s:\n %x VS set = %x  PE set = %x max VS Reached = %x  max PE Reached = %x\n",
	DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X VS set = %x  PE set = %x max VS Reached = %x  max PE Reached = %x\n",
		__func__,
		DP_TRAINING_LANE0_SET,
		dpcd_base_lt_offset,
		dpcd_lane[0].bits.VOLTAGE_SWING_SET,
		dpcd_lane[0].bits.PRE_EMPHASIS_SET,
		dpcd_lane[0].bits.MAX_SWING_REACHED,
@@ -498,8 +510,12 @@ static void get_lane_status_and_drive_settings(
	const struct link_training_settings *link_training_setting,
	union lane_status *ln_status,
	union lane_align_status_updated *ln_status_updated,
	struct link_training_settings *req_settings)
	struct link_training_settings *req_settings,
	uint32_t offset)
{
	unsigned int lane01_status_address = DP_LANE0_1_STATUS;
	uint8_t lane_adjust_offset = 4;
	unsigned int lane01_adjust_address;
	uint8_t dpcd_buf[6] = {0};
	union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } };
	struct link_training_settings request_settings = { {0} };
@@ -507,9 +523,16 @@ static void get_lane_status_and_drive_settings(

	memset(req_settings, '\0', sizeof(struct link_training_settings));

	if (is_repeater(link, offset)) {
		lane01_status_address =
				DP_LANE0_1_STATUS_PHY_REPEATER1 +
				((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
		lane_adjust_offset = 3;
	}

	core_link_read_dpcd(
		link,
		DP_LANE0_1_STATUS,
		lane01_status_address,
		(uint8_t *)(dpcd_buf),
		sizeof(dpcd_buf));

@@ -520,22 +543,28 @@ static void get_lane_status_and_drive_settings(
		ln_status[lane].raw =
			get_nibble_at_index(&dpcd_buf[0], lane);
		dpcd_lane_adjust[lane].raw =
			get_nibble_at_index(&dpcd_buf[4], lane);
			get_nibble_at_index(&dpcd_buf[lane_adjust_offset], lane);
	}

	ln_status_updated->raw = dpcd_buf[2];

	DC_LOG_HW_LINK_TRAINING("%s:\n%x Lane01Status = %x\n %x Lane23Status = %x\n ",
	DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ",
		__func__,
		DP_LANE0_1_STATUS, dpcd_buf[0],
		DP_LANE2_3_STATUS, dpcd_buf[1]);
		lane01_status_address, dpcd_buf[0],
		lane01_status_address + 1, dpcd_buf[1]);

	lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1;

	DC_LOG_HW_LINK_TRAINING("%s:\n %x Lane01AdjustRequest = %x\n %x Lane23AdjustRequest = %x\n",
	if (is_repeater(link, offset))
		lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1_PHY_REPEATER1 +
				((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));

	DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n",
		__func__,
		DP_ADJUST_REQUEST_LANE0_1,
		dpcd_buf[4],
		DP_ADJUST_REQUEST_LANE2_3,
		dpcd_buf[5]);
		lane01_adjust_address,
		dpcd_buf[lane_adjust_offset],
		lane01_adjust_address + 1,
		dpcd_buf[lane_adjust_offset + 1]);

	/*copy to req_settings*/
	request_settings.link_settings.lane_count =
@@ -574,10 +603,18 @@ static void get_lane_status_and_drive_settings(

static void dpcd_set_lane_settings(
	struct dc_link *link,
	const struct link_training_settings *link_training_setting)
	const struct link_training_settings *link_training_setting,
	uint32_t offset)
{
	union dpcd_training_lane dpcd_lane[LANE_COUNT_DP_MAX] = {{{0}}};
	uint32_t lane;
	unsigned int lane0_set_address;

	lane0_set_address = DP_TRAINING_LANE0_SET;

	if (is_repeater(link, offset))
		lane0_set_address = DP_TRAINING_LANE0_SET_PHY_REPEATER1 +
		((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));

	for (lane = 0; lane <
		(uint32_t)(link_training_setting->
@@ -600,7 +637,7 @@ static void dpcd_set_lane_settings(
	}

	core_link_write_dpcd(link,
		DP_TRAINING_LANE0_SET,
		lane0_set_address,
		(uint8_t *)(dpcd_lane),
		link_training_setting->link_settings.lane_count);

@@ -623,9 +660,9 @@ static void dpcd_set_lane_settings(
	}
	*/

	DC_LOG_HW_LINK_TRAINING("%s\n %x VS set = %x  PE set = %x max VS Reached = %x  max PE Reached = %x\n",
	DC_LOG_HW_LINK_TRAINING("%s\n 0x%X VS set = %x  PE set = %x max VS Reached = %x  max PE Reached = %x\n",
		__func__,
		DP_TRAINING_LANE0_SET,
		lane0_set_address,
		dpcd_lane[0].bits.VOLTAGE_SWING_SET,
		dpcd_lane[0].bits.PRE_EMPHASIS_SET,
		dpcd_lane[0].bits.MAX_SWING_REACHED,
@@ -650,17 +687,6 @@ static bool is_max_vs_reached(

}

void dc_link_dp_set_drive_settings(
	struct dc_link *link,
	struct link_training_settings *lt_settings)
{
	/* program ASIC PHY settings*/
	dp_set_hw_lane_settings(link, lt_settings);

	/* Notify DP sink the PHY settings from source */
	dpcd_set_lane_settings(link, lt_settings);
}

static bool perform_post_lt_adj_req_sequence(
	struct dc_link *link,
	struct link_training_settings *lt_settings)
@@ -693,7 +719,8 @@ static bool perform_post_lt_adj_req_sequence(
			lt_settings,
			dpcd_lane_status,
			&dpcd_lane_status_updated,
			&req_settings);
			&req_settings,
			DPRX);

			if (dpcd_lane_status_updated.bits.
					POST_LT_ADJ_REQ_IN_PROGRESS == 0)
@@ -750,6 +777,31 @@ static bool perform_post_lt_adj_req_sequence(

}

/* Only used for channel equalization */
static uint32_t translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval)
{
	unsigned int aux_rd_interval_us = 400;

	switch (dpcd_aux_read_interval) {
	case 0x01:
		aux_rd_interval_us = 400;
		break;
	case 0x02:
		aux_rd_interval_us = 4000;
		break;
	case 0x03:
		aux_rd_interval_us = 8000;
		break;
	case 0x04:
		aux_rd_interval_us = 16000;
		break;
	default:
		break;
	}

	return aux_rd_interval_us;
}

static enum link_training_result get_cr_failure(enum dc_lane_count ln_count,
					union lane_status *dpcd_lane_status)
{
@@ -768,37 +820,55 @@ static enum link_training_result get_cr_failure(enum dc_lane_count ln_count,

static enum link_training_result perform_channel_equalization_sequence(
	struct dc_link *link,
	struct link_training_settings *lt_settings)
	struct link_training_settings *lt_settings,
	uint32_t offset)
{
	struct link_training_settings req_settings;
	enum dc_dp_training_pattern tr_pattern;
	uint32_t retries_ch_eq;
	uint32_t wait_time_microsec;
	enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
	union lane_align_status_updated dpcd_lane_status_updated = { {0} };
	union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = { { {0} } };

	/* Note: also check that TPS4 is a supported feature*/

	tr_pattern = lt_settings->pattern_for_eq;

	dp_set_hw_training_pattern(link, tr_pattern);
	if (is_repeater(link, offset))
		tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4;

	dp_set_hw_training_pattern(link, tr_pattern, offset);

	for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
		retries_ch_eq++) {

		dp_set_hw_lane_settings(link, lt_settings);
		dp_set_hw_lane_settings(link, lt_settings, offset);

		/* 2. update DPCD*/
		if (!retries_ch_eq)
			/* EPR #361076 - write as a 5-byte burst,
			 * but only for the 1-st iteration*/
			 * but only for the 1-st iteration
			 */

			dpcd_set_lt_pattern_and_lane_settings(
				link,
				lt_settings,
				tr_pattern);
				tr_pattern, offset);
		else
			dpcd_set_lane_settings(link, lt_settings);
			dpcd_set_lane_settings(link, lt_settings, offset);

		/* 3. wait for receiver to lock-on*/
		wait_for_training_aux_rd_interval(link, lt_settings->eq_pattern_time);
		wait_time_microsec = lt_settings->eq_pattern_time;

		if (!link->is_lttpr_mode_transparent)
			wait_time_microsec =
					translate_training_aux_read_interval(
						link->dpcd_caps.lttpr_caps.aux_rd_interval[offset]);

		wait_for_training_aux_rd_interval(
				link,
				wait_time_microsec);

		/* 4. Read lane status and requested
		 * drive settings as set by the sink*/
@@ -808,7 +878,8 @@ static enum link_training_result perform_channel_equalization_sequence(
			lt_settings,
			dpcd_lane_status,
			&dpcd_lane_status_updated,
			&req_settings);
			&req_settings,
			offset);

		/* 5. check CR done*/
		if (!is_cr_done(lane_count, dpcd_lane_status))
@@ -827,13 +898,16 @@ static enum link_training_result perform_channel_equalization_sequence(
	return LINK_TRAINING_EQ_FAIL_EQ;

}
#define TRAINING_AUX_RD_INTERVAL 100 //us

static enum link_training_result perform_clock_recovery_sequence(
	struct dc_link *link,
	struct link_training_settings *lt_settings)
	struct link_training_settings *lt_settings,
	uint32_t offset)
{
	uint32_t retries_cr;
	uint32_t retry_count;
	uint32_t wait_time_microsec;
	struct link_training_settings req_settings;
	enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
	enum dc_dp_training_pattern tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_1;
@@ -843,7 +917,7 @@ static enum link_training_result perform_clock_recovery_sequence(
	retries_cr = 0;
	retry_count = 0;

	dp_set_hw_training_pattern(link, tr_pattern);
	dp_set_hw_training_pattern(link, tr_pattern, offset);

	/* najeeb - The synaptics MST hub can put the LT in
	* infinite loop by switching the VS
@@ -860,7 +934,8 @@ static enum link_training_result perform_clock_recovery_sequence(
		/* 1. call HWSS to set lane settings*/
		dp_set_hw_lane_settings(
				link,
				lt_settings);
				lt_settings,
				offset);

		/* 2. update DPCD of the receiver*/
		if (!retries_cr)
@@ -869,16 +944,23 @@ static enum link_training_result perform_clock_recovery_sequence(
			dpcd_set_lt_pattern_and_lane_settings(
					link,
					lt_settings,
					tr_pattern);
					tr_pattern,
					offset);
		else
			dpcd_set_lane_settings(
					link,
					lt_settings);
					lt_settings,
					offset);

		/* 3. wait receiver to lock-on*/
		wait_time_microsec = lt_settings->cr_pattern_time;

		if (!link->is_lttpr_mode_transparent)
			wait_time_microsec = TRAINING_AUX_RD_INTERVAL;

		wait_for_training_aux_rd_interval(
				link,
				lt_settings->cr_pattern_time);
				wait_time_microsec);

		/* 4. Read lane status and requested drive
		* settings as set by the sink
@@ -888,7 +970,8 @@ static enum link_training_result perform_clock_recovery_sequence(
				lt_settings,
				dpcd_lane_status,
				&dpcd_lane_status_updated,
				&req_settings);
				&req_settings,
				offset);

		/* 5. check CR done*/
		if (is_cr_done(lane_count, dpcd_lane_status))
@@ -1057,10 +1140,38 @@ static void initialize_training_settings(
		lt_settings->enhanced_framing = 1;
}

static uint8_t convert_to_count(uint8_t lttpr_repeater_count)
{
	switch (lttpr_repeater_count) {
	case 0x80: // 1 lttpr repeater
		return 1;
	case 0x40: // 2 lttpr repeaters
		return 2;
	case 0x20: // 3 lttpr repeaters
		return 3;
	case 0x10: // 4 lttpr repeaters
		return 4;
	case 0x08: // 5 lttpr repeaters
		return 5;
	case 0x04: // 6 lttpr repeaters
		return 6;
	case 0x02: // 7 lttpr repeaters
		return 7;
	case 0x01: // 8 lttpr repeaters
		return 8;
	default:
		break;
	}
	return 0; // invalid value
}

static void configure_lttpr_mode(struct dc_link *link)
{
	/* aux timeout is already set to extended */
	/* RESET/SET lttpr mode to enable non transparent mode */
	uint8_t repeater_cnt;
	uint32_t aux_interval_address;
	uint8_t repeater_id;
	enum lttpr_mode repeater_mode = phy_repeater_mode_transparent;

	core_link_write_dpcd(link,
@@ -1074,9 +1185,43 @@ static void configure_lttpr_mode(struct dc_link *link)
				DP_PHY_REPEATER_MODE,
				(uint8_t *)&repeater_mode,
				sizeof(repeater_mode));

		repeater_cnt = convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
		for (repeater_id = repeater_cnt; repeater_id > 0; repeater_id--) {
			aux_interval_address = DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1 +
						((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (repeater_id - 1));
			core_link_read_dpcd(
				link,
				aux_interval_address,
				(uint8_t *)&link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1],
				sizeof(link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1]));
			link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1] &= 0x7F;
		}
	}
}

static void repeater_training_done(struct dc_link *link, uint32_t offset)
{
	union dpcd_training_pattern dpcd_pattern = { {0} };

	const uint32_t dpcd_base_lt_offset =
			DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
				((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
	/* Set training not in progress*/
	dpcd_pattern.v1_4.TRAINING_PATTERN_SET = DPCD_TRAINING_PATTERN_VIDEOIDLE;

	core_link_write_dpcd(
		link,
		dpcd_base_lt_offset,
		&dpcd_pattern.raw,
		1);

	DC_LOG_HW_LINK_TRAINING("%s\n 0x%X pattern = %x\n",
		__func__,
		dpcd_base_lt_offset,
		dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
}

static void print_status_message(
	struct dc_link *link,
	const struct link_training_settings *lt_settings,
@@ -1156,6 +1301,17 @@ static void print_status_message(
				lt_spread);
}

void dc_link_dp_set_drive_settings(
	struct dc_link *link,
	struct link_training_settings *lt_settings)
{
	/* program ASIC PHY settings*/
	dp_set_hw_lane_settings(link, lt_settings, DPRX);

	/* Notify DP sink the PHY settings from source */
	dpcd_set_lane_settings(link, lt_settings, DPRX);
}

bool dc_link_dp_perform_link_training_skip_aux(
	struct dc_link *link,
	const struct dc_link_settings *link_setting)
@@ -1172,10 +1328,10 @@ bool dc_link_dp_perform_link_training_skip_aux(
	/* 1. Perform_clock_recovery_sequence. */

	/* transmit training pattern for clock recovery */
	dp_set_hw_training_pattern(link, pattern_for_cr);
	dp_set_hw_training_pattern(link, pattern_for_cr, DPRX);

	/* call HWSS to set lane settings*/
	dp_set_hw_lane_settings(link, &lt_settings);
	dp_set_hw_lane_settings(link, &lt_settings, DPRX);

	/* wait receiver to lock-on*/
	wait_for_training_aux_rd_interval(link, lt_settings.cr_pattern_time);
@@ -1183,10 +1339,10 @@ bool dc_link_dp_perform_link_training_skip_aux(
	/* 2. Perform_channel_equalization_sequence. */

	/* transmit training pattern for channel equalization. */
	dp_set_hw_training_pattern(link, lt_settings.pattern_for_eq);
	dp_set_hw_training_pattern(link, lt_settings.pattern_for_eq, DPRX);

	/* call HWSS to set lane settings*/
	dp_set_hw_lane_settings(link, &lt_settings);
	dp_set_hw_lane_settings(link, &lt_settings, DPRX);

	/* wait receiver to lock-on. */
	wait_for_training_aux_rd_interval(link, lt_settings.eq_pattern_time);
@@ -1208,9 +1364,12 @@ enum link_training_result dc_link_dp_perform_link_training(
{
	enum link_training_result status = LINK_TRAINING_SUCCESS;
	struct link_training_settings lt_settings;

#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
	bool fec_enable;
#endif
	uint8_t repeater_cnt;
	uint8_t repeater_id;

	initialize_training_settings(
			link,
@@ -1230,17 +1389,40 @@ enum link_training_result dc_link_dp_perform_link_training(
	dp_set_fec_ready(link, fec_enable);
#endif

	if (!link->is_lttpr_mode_transparent) {
		/* Configure lttpr mode */
	if (!link->is_lttpr_mode_transparent)
		configure_lttpr_mode(link);

		/* 2. perform link training (set link training done
		 *  to false is done as well)
		 */
	status = perform_clock_recovery_sequence(link, &lt_settings);
		repeater_cnt = convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);

		for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS);
				repeater_id--) {
			status = perform_clock_recovery_sequence(link, &lt_settings, repeater_id);

			if (status != LINK_TRAINING_SUCCESS)
				break;

			status = perform_channel_equalization_sequence(link,
					&lt_settings,
					repeater_id);

			if (status != LINK_TRAINING_SUCCESS)
				break;

			repeater_training_done(link, repeater_id);
		}
	}

	if (status == LINK_TRAINING_SUCCESS) {
		status = perform_clock_recovery_sequence(link, &lt_settings, DPRX);
	if (status == LINK_TRAINING_SUCCESS) {
		status = perform_channel_equalization_sequence(link,
				&lt_settings);
					&lt_settings,
					DPRX);
		}
	}

	if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern) {
@@ -1393,10 +1575,11 @@ enum link_training_result dc_link_dp_sync_lt_attempt(
	/* 2. perform link training (set link training done
	 *  to false is done as well)
	 */
	lt_status = perform_clock_recovery_sequence(link, &lt_settings);
	lt_status = perform_clock_recovery_sequence(link, &lt_settings, DPRX);
	if (lt_status == LINK_TRAINING_SUCCESS) {
		lt_status = perform_channel_equalization_sequence(link,
						&lt_settings);
						&lt_settings,
						DPRX);
	}

	/* 3. Sync LT must skip TRAINING_PATTERN_SET:0 (video pattern)*/
@@ -3355,8 +3538,8 @@ bool dc_link_dp_set_test_pattern(
	if (is_dp_phy_pattern(test_pattern)) {
		/* Set DPCD Lane Settings before running test pattern */
		if (p_link_settings != NULL) {
			dp_set_hw_lane_settings(link, p_link_settings);
			dpcd_set_lane_settings(link, p_link_settings);
			dp_set_hw_lane_settings(link, p_link_settings, DPRX);
			dpcd_set_lane_settings(link, p_link_settings, DPRX);
		}

		/* Blank stream if running test pattern */
+37 −2
Original line number Diff line number Diff line
@@ -19,6 +19,36 @@
#include "resource.h"
#endif

static uint8_t convert_to_count(uint8_t lttpr_repeater_count)
{
	switch (lttpr_repeater_count) {
	case 0x80: // 1 lttpr repeater
		return 1;
	case 0x40: // 2 lttpr repeaters
		return 2;
	case 0x20: // 3 lttpr repeaters
		return 3;
	case 0x10: // 4 lttpr repeaters
		return 4;
	case 0x08: // 5 lttpr repeaters
		return 5;
	case 0x04: // 6 lttpr repeaters
		return 6;
	case 0x02: // 7 lttpr repeaters
		return 7;
	case 0x01: // 8 lttpr repeaters
		return 8;
	default:
		break;
	}
	return 0; // invalid value
}

static inline bool is_immediate_downstream(struct dc_link *link, uint32_t offset)
{
	return (convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) == offset);
}

enum dc_status core_link_read_dpcd(
	struct dc_link *link,
	uint32_t address,
@@ -212,7 +242,8 @@ void dp_disable_link_phy_mst(struct dc_link *link, enum signal_type signal)

bool dp_set_hw_training_pattern(
	struct dc_link *link,
	enum dc_dp_training_pattern pattern)
	enum dc_dp_training_pattern pattern,
	uint32_t offset)
{
	enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED;

@@ -240,10 +271,14 @@ bool dp_set_hw_training_pattern(

void dp_set_hw_lane_settings(
	struct dc_link *link,
	const struct link_training_settings *link_settings)
	const struct link_training_settings *link_settings,
	uint32_t offset)
{
	struct link_encoder *encoder = link->link_enc;

	if (!link->is_lttpr_mode_transparent && !is_immediate_downstream(link, offset))
		return;

	/* call Encoder to set lane settings */
	encoder->funcs->dp_set_lane_settings(encoder, link_settings);
}
+4 −2
Original line number Diff line number Diff line
@@ -60,11 +60,13 @@ void dp_disable_link_phy_mst(struct dc_link *link, enum signal_type signal);

bool dp_set_hw_training_pattern(
	struct dc_link *link,
	enum dc_dp_training_pattern pattern);
	enum dc_dp_training_pattern pattern,
	uint32_t offset);

void dp_set_hw_lane_settings(
	struct dc_link *link,
	const struct link_training_settings *link_settings);
	const struct link_training_settings *link_settings,
	uint32_t offset);

void dp_set_hw_test_pattern(
	struct dc_link *link,