From: abdoulaye berthe <abdoulaye.berthe@xxxxxxx> 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: abdoulaye berthe <abdoulaye.berthe@xxxxxxx> Reviewed-by: Aric Cyr <Aric.Cyr@xxxxxxx> --- .../gpu/drm/amd/display/dc/core/dc_link_dp.c | 319 ++++++++++++++---- .../drm/amd/display/dc/core/dc_link_hwss.c | 39 ++- .../gpu/drm/amd/display/dc/inc/link_hwss.h | 6 +- 3 files changed, 292 insertions(+), 72 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 94d5a0ac308f..11b6e14b345e 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -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; + + 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 %x Lane01AdjustRequest = %x\n %x Lane23AdjustRequest = %x\n", + 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, <_settings); + dp_set_hw_lane_settings(link, <_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, <_settings); + dp_set_hw_lane_settings(link, <_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 - /* Configure lttpr mode */ - if (!link->is_lttpr_mode_transparent) + if (!link->is_lttpr_mode_transparent) { + /* Configure lttpr mode */ configure_lttpr_mode(link); - /* 2. perform link training (set link training done - * to false is done as well) - */ - status = perform_clock_recovery_sequence(link, <_settings); + /* 2. perform link training (set link training done + * to false is done as well) + */ + 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, <_settings, repeater_id); + + if (status != LINK_TRAINING_SUCCESS) + break; + + status = perform_channel_equalization_sequence(link, + <_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, <_settings, DPRX); if (status == LINK_TRAINING_SUCCESS) { status = perform_channel_equalization_sequence(link, - <_settings); + <_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, <_settings); + lt_status = perform_clock_recovery_sequence(link, <_settings, DPRX); if (lt_status == LINK_TRAINING_SUCCESS) { lt_status = perform_channel_equalization_sequence(link, - <_settings); + <_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 */ diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c index a519dbc5ecb6..5efbdc1eb173 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c @@ -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); } diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h index 4eff5d38a2f9..9af7ee5bc8ee 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h +++ b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h @@ -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, -- 2.17.1 _______________________________________________ amd-gfx mailing list amd-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/amd-gfx