drm/amd/display: Add early 8b/10b channel equalization test pattern sequence

[WHY]
Early EQ pattern sequence is required for some LTTPR + old dongle
combinations.

[HOW]
If DP_EARLY_8B10B_TPS2 chip cap is set, this new sequence programs phy
to output TPS2 before initiating link training and writes TPS1 to
LTTPR training pattern register as instructed by vendor.

Add function to get embedded LTTPR target address offset.

Reviewed-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Michael Strauss <michael.strauss@amd.com>
Signed-off-by: TungYu Lu <tungyu.lu@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Michael Strauss
2023-12-04 16:30:39 +08:00
committed by Alex Deucher
parent 90af999835
commit 8989cb919b
5 changed files with 62 additions and 4 deletions

View File

@@ -158,6 +158,14 @@ uint8_t dp_parse_lttpr_repeater_count(uint8_t lttpr_repeater_count)
return 0; // invalid value
}
uint32_t dp_get_closest_lttpr_offset(uint8_t lttpr_count)
{
/* Calculate offset for LTTPR closest to DPTX which is highest in the chain
* Offset is 0 for single LTTPR cases as base LTTPR DPCD addresses target LTTPR 1
*/
return DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE * (lttpr_count - 1);
}
uint32_t link_bw_kbps_from_raw_frl_link_rate_data(uint8_t bw)
{
switch (bw) {

View File

@@ -48,6 +48,9 @@ enum dc_status dp_retrieve_lttpr_cap(struct dc_link *link);
/* Convert PHY repeater count read from DPCD uint8_t. */
uint8_t dp_parse_lttpr_repeater_count(uint8_t lttpr_repeater_count);
/* Calculate embedded LTTPR address offset for vendor-specific behaviour */
uint32_t dp_get_closest_lttpr_offset(uint8_t lttpr_count);
bool dp_is_sink_present(struct dc_link *link);
bool dp_is_lttpr_present(struct dc_link *link);

View File

@@ -785,7 +785,6 @@ void override_training_settings(
lt_settings->lttpr_mode = LTTPR_MODE_NON_LTTPR;
dp_get_lttpr_mode_override(link, &lt_settings->lttpr_mode);
}
enum dc_dp_training_pattern decide_cr_training_pattern(

View File

@@ -142,6 +142,14 @@ void decide_8b_10b_training_settings(
lt_settings->lttpr_mode = dp_decide_8b_10b_lttpr_mode(link);
lt_settings->cr_pattern_time = get_cr_training_aux_rd_interval(link, link_setting, lt_settings->lttpr_mode);
dp_hw_to_dpcd_lane_settings(lt_settings, lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
/* Some embedded LTTPRs rely on receiving TPS2 before LT to interop reliably with sensitive VGA dongles
* This allows these LTTPRs to minimize freq/phase and skew variation during lock and deskew sequences
*/
if ((link->chip_caps & AMD_EXT_DISPLAY_PATH_CAPS__EXT_CHIP_MASK) ==
AMD_EXT_DISPLAY_PATH_CAPS__DP_EARLY_8B10B_TPS2) {
lt_settings->lttpr_early_tps2 = true;
}
}
enum lttpr_mode dp_decide_8b_10b_lttpr_mode(struct dc_link *link)
@@ -173,6 +181,42 @@ enum lttpr_mode dp_decide_8b_10b_lttpr_mode(struct dc_link *link)
return LTTPR_MODE_NON_LTTPR;
}
static void set_link_settings_and_perform_early_tps2_retimer_pre_lt_sequence(struct dc_link *link,
const struct link_resource *link_res,
struct link_training_settings *lt_settings,
uint32_t lttpr_count)
{
/* Vendor-specific LTTPR early TPS2 sequence:
* 1. Output TPS2
* 2. Wait 400us
* 3. Set link settings as usual
* 4. Write TPS1 to DP_TRAINING_PATTERN_SET_PHY_REPEATERx targeting LTTPR closest to host
* 5. Wait 1ms
* 6. Begin link training as usual
* */
uint32_t closest_lttpr_address_offset = dp_get_closest_lttpr_offset(lttpr_count);
union dpcd_training_pattern dpcd_pattern = {0};
dpcd_pattern.v1_4.TRAINING_PATTERN_SET = 1;
dpcd_pattern.v1_4.SCRAMBLING_DISABLE = 1;
DC_LOG_HW_LINK_TRAINING("%s\n GPU sends TPS2. Wait 400us.\n", __func__);
dp_set_hw_training_pattern(link, link_res, DP_TRAINING_PATTERN_SEQUENCE_2, DPRX);
dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX);
udelay(400);
dpcd_set_link_settings(link, lt_settings);
core_link_write_dpcd(link, DP_TRAINING_PATTERN_SET_PHY_REPEATER1 + closest_lttpr_address_offset, &dpcd_pattern.raw, 1);
udelay(1000);
}
enum link_training_result perform_8b_10b_clock_recovery_sequence(
struct dc_link *link,
const struct link_resource *link_res,
@@ -383,7 +427,7 @@ enum link_training_result dp_perform_8b_10b_link_training(
{
enum link_training_result status = LINK_TRAINING_SUCCESS;
uint8_t repeater_cnt;
uint8_t repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
uint8_t repeater_id;
uint8_t lane = 0;
@@ -391,14 +435,16 @@ enum link_training_result dp_perform_8b_10b_link_training(
start_clock_recovery_pattern_early(link, link_res, lt_settings, DPRX);
/* 1. set link rate, lane count and spread. */
dpcd_set_link_settings(link, lt_settings);
if (lt_settings->lttpr_early_tps2)
set_link_settings_and_perform_early_tps2_retimer_pre_lt_sequence(link, link_res, lt_settings, repeater_cnt);
else
dpcd_set_link_settings(link, lt_settings);
if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
/* 2. perform link training (set link training done
* to false is done as well)
*/
repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS);
repeater_id--) {

View File

@@ -89,6 +89,8 @@ struct link_training_settings {
bool enhanced_framing;
enum lttpr_mode lttpr_mode;
bool lttpr_early_tps2;
/* disallow different lanes to have different lane settings */
bool disallow_per_lane_settings;
/* dpcd lane settings will always use the same hw lane settings