diff options
author | Dave Airlie <airlied@redhat.com> | 2022-07-12 11:07:30 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2022-07-12 11:07:32 +1000 |
commit | 344feb7ccf764756937cfd74fa4ac5caba069c99 (patch) | |
tree | b86c7eb43878b310c31702094763d130b7e31dc5 /drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | |
parent | c6a3d73592ae20f2f6306f823aa5121c83c88223 (diff) | |
parent | c5da61cf5bab30059f22ea368702c445ee87171a (diff) |
Merge tag 'amd-drm-next-5.20-2022-07-05' of https://gitlab.freedesktop.org/agd5f/linux into drm-next
amd-drm-next-5.20-2022-07-05:
amdgpu:
- Various spelling and grammer fixes
- Various eDP fixes
- Various DMCUB fixes
- VCN fixes
- GMC 11 fixes
- RAS fixes
- TMZ support for GC 10.3.7
- GPUVM TLB flush fixes
- SMU 13.0.x updates
- DCN 3.2 Support
- DCN 3.2.1 Support
- MES updates
- GFX11 modifiers support
- USB-C fixes
- MMHUB 3.0.1 support
- SDMA 6.0 doorbell fixes
- Initial devcoredump support
- Enable high priority gfx queue on asics which support it
- Enable GPU reset for SMU 13.0.4
- OLED display fixes
- MPO fixes
- DC frame size fixes
- ASPM support for PCIE 7.4/7.6
- GPU reset support for SMU 13.0.0
- GFX11 updates
- VCN JPEG fix
- BACO support for SMU 13.0.7
- VCN instance handling fix
- GFX8 GPUVM TLB flush fix
- GPU reset rework
- VCN 4.0.2 support
- GTT size fixes
- DP link training fixes
- LSDMA 6.0.1 support
- Various backlight fixes
- Color encoding fixes
- Backlight config cleanup
- VCN 4.x unified queue cleanup
amdkfd:
- MMU notifier fixes
- Updates for GC 10.3.6 and 10.3.7
- P2P DMA support using dma-buf
- Add available memory IOCTL
- SDMA 6.0.1 fix
- MES fixes
- HMM profiler support
radeon:
- License fix
- Backlight config cleanup
UAPI:
- Add available memory IOCTL to amdkfd
Proposed userspace: https://www.mail-archive.com/amd-gfx@lists.freedesktop.org/msg75743.html
- HMM profiler support for amdkfd
Proposed userspace: https://lists.freedesktop.org/archives/amd-gfx/2022-June/080805.html
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Alex Deucher <alexander.deucher@amd.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220705212633.6037-1-alexander.deucher@amd.com
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c')
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 376 |
1 files changed, 167 insertions, 209 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 cbc47aecd00f..710797b2f0df 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 @@ -329,51 +329,6 @@ static uint8_t get_dpcd_link_rate(const struct dc_link_settings *link_settings) return link_rate; } -static void vendor_specific_lttpr_wa_one_start(struct dc_link *link) -{ - const uint8_t vendor_lttpr_write_data[4] = {0x1, 0x50, 0x63, 0xff}; - const uint8_t offset = dp_convert_to_count( - link->dpcd_caps.lttpr_caps.phy_repeater_cnt); - uint32_t vendor_lttpr_write_address = 0xF004F; - - if (offset != 0xFF) - vendor_lttpr_write_address += - ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); - - /* W/A for certain LTTPR to reset their lane settings, part one of two */ - core_link_write_dpcd( - link, - vendor_lttpr_write_address, - &vendor_lttpr_write_data[0], - sizeof(vendor_lttpr_write_data)); -} - -static void vendor_specific_lttpr_wa_one_two( - struct dc_link *link, - const uint8_t rate) -{ - if (link->apply_vendor_specific_lttpr_link_rate_wa) { - uint8_t toggle_rate = 0x0; - - if (rate == 0x6) - toggle_rate = 0xA; - else - toggle_rate = 0x6; - - if (link->vendor_specific_lttpr_link_rate_wa == rate) { - /* W/A for certain LTTPR to reset internal state for link training */ - core_link_write_dpcd( - link, - DP_LINK_BW_SET, - &toggle_rate, - 1); - } - - /* Store the last attempted link rate for this link */ - link->vendor_specific_lttpr_link_rate_wa = rate; - } -} - static void dp_fixed_vs_pe_read_lane_adjust( struct dc_link *link, union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX]) @@ -423,51 +378,6 @@ static void dp_fixed_vs_pe_read_lane_adjust( } } -static void vendor_specific_lttpr_wa_four( - struct dc_link *link, - bool apply_wa) -{ - const uint8_t vendor_lttpr_write_data_one[4] = {0x1, 0x55, 0x63, 0x8}; - const uint8_t vendor_lttpr_write_data_two[4] = {0x1, 0x55, 0x63, 0x0}; - const uint8_t offset = dp_convert_to_count( - link->dpcd_caps.lttpr_caps.phy_repeater_cnt); - uint32_t vendor_lttpr_write_address = 0xF004F; - uint8_t sink_status = 0; - uint8_t i; - - if (offset != 0xFF) - vendor_lttpr_write_address += - ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); - - /* W/A to pass through DPCD write of TPS=0 to DPRX */ - if (apply_wa) { - core_link_write_dpcd( - link, - vendor_lttpr_write_address, - &vendor_lttpr_write_data_one[0], - sizeof(vendor_lttpr_write_data_one)); - } - - /* clear training pattern set */ - dpcd_set_training_pattern(link, DP_TRAINING_PATTERN_VIDEOIDLE); - - if (apply_wa) { - core_link_write_dpcd( - link, - vendor_lttpr_write_address, - &vendor_lttpr_write_data_two[0], - sizeof(vendor_lttpr_write_data_two)); - } - - /* poll for intra-hop disable */ - for (i = 0; i < 10; i++) { - if ((core_link_read_dpcd(link, DP_SINK_STATUS, &sink_status, 1) == DC_OK) && - (sink_status & DP_INTRA_HOP_AUX_REPLY_INDICATION) == 0) - break; - udelay(1000); - } -} - static void dp_fixed_vs_pe_set_retimer_lane_settings( struct dc_link *link, const union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX], @@ -561,14 +471,6 @@ enum dc_status dpcd_set_link_settings( <_settings->link_settings.link_rate_set, 1); } else { rate = get_dpcd_link_rate(<_settings->link_settings); - if (link->dc->debug.apply_vendor_specific_lttpr_wa && - (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && - link->lttpr_mode == LTTPR_MODE_TRANSPARENT) - vendor_specific_lttpr_wa_one_start(link); - - if (link->dc->debug.apply_vendor_specific_lttpr_wa && - (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN)) - vendor_specific_lttpr_wa_one_two(link, rate); status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1); } @@ -638,7 +540,7 @@ static void dpcd_set_lt_pattern_and_lane_settings( uint32_t dpcd_base_lt_offset; uint8_t dpcd_lt_buffer[5] = {0}; - union dpcd_training_pattern dpcd_pattern = { 0 }; + union dpcd_training_pattern dpcd_pattern = {0}; uint32_t size_in_bytes; bool edp_workaround = false; /* TODO link_prop.INTERNAL */ dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET; @@ -944,7 +846,7 @@ static void override_lane_settings(const struct link_training_settings *lt_setti return; - for (lane = 1; lane < LANE_COUNT_DP_MAX; lane++) { + for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { if (lt_settings->voltage_swing) lane_settings[lane].VOLTAGE_SWING = *lt_settings->voltage_swing; if (lt_settings->pre_emphasis) @@ -1011,19 +913,10 @@ enum dc_status dp_get_lane_status_and_lane_adjust( offset, lane01_status_address, dpcd_buf[0], lane01_status_address + 1, dpcd_buf[1]); - } else { - DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ", - __func__, - 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)); - if (is_repeater(link, offset)) { DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n" " 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n", __func__, @@ -1033,6 +926,13 @@ enum dc_status dp_get_lane_status_and_lane_adjust( lane01_adjust_address + 1, dpcd_buf[lane_adjust_offset + 1]); } else { + DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ", + __func__, + 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 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n", __func__, lane01_adjust_address, @@ -1303,12 +1203,6 @@ static enum link_training_result perform_channel_equalization_sequence( dp_translate_training_aux_read_interval( link->dpcd_caps.lttpr_caps.aux_rd_interval[offset - 1]); - if (link->dc->debug.apply_vendor_specific_lttpr_wa && - (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && - link->lttpr_mode == LTTPR_MODE_TRANSPARENT) { - wait_time_microsec = 16000; - } - dp_wait_for_training_aux_rd_interval( link, wait_time_microsec); @@ -1326,7 +1220,9 @@ static enum link_training_result perform_channel_equalization_sequence( /* 5. check CR done*/ if (!dp_is_cr_done(lane_count, dpcd_lane_status)) - return LINK_TRAINING_EQ_FAIL_CR; + return dpcd_lane_status[0].bits.CR_DONE_0 ? + LINK_TRAINING_EQ_FAIL_CR_PARTIAL : + LINK_TRAINING_EQ_FAIL_CR; /* 6. check CHEQ done*/ if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) && @@ -1367,7 +1263,7 @@ static enum link_training_result perform_clock_recovery_sequence( enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX]; union lane_align_status_updated dpcd_lane_status_updated; - union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } }; + union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; retries_cr = 0; retry_count = 0; @@ -1413,11 +1309,6 @@ static enum link_training_result perform_clock_recovery_sequence( /* 3. wait receiver to lock-on*/ wait_time_microsec = lt_settings->cr_pattern_time; - if (link->dc->debug.apply_vendor_specific_lttpr_wa && - (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN)) { - wait_time_microsec = 16000; - } - dp_wait_for_training_aux_rd_interval( link, wait_time_microsec); @@ -1658,22 +1549,23 @@ static void override_training_settings( lt_settings->always_match_dpcd_with_hw_lane_settings = false; } for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { - lt_settings->lane_settings[lane].VOLTAGE_SWING = + lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = lt_settings->voltage_swing != NULL ? *lt_settings->voltage_swing : VOLTAGE_SWING_LEVEL0; - lt_settings->lane_settings[lane].PRE_EMPHASIS = + lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = lt_settings->pre_emphasis != NULL ? *lt_settings->pre_emphasis : PRE_EMPHASIS_DISABLED; - lt_settings->lane_settings[lane].POST_CURSOR2 = + lt_settings->hw_lane_settings[lane].POST_CURSOR2 = lt_settings->post_cursor2 != NULL ? *lt_settings->post_cursor2 : POST_CURSOR2_DISABLED; } - dp_hw_to_dpcd_lane_settings(lt_settings, - lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); + if (lt_settings->always_match_dpcd_with_hw_lane_settings) + dp_hw_to_dpcd_lane_settings(lt_settings, + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); /* Initialize training timings */ if (overrides->cr_pattern_time != NULL) @@ -1882,6 +1774,9 @@ static void print_status_message( case LINK_TRAINING_EQ_FAIL_CR: lt_result = "CR failed in EQ"; break; + case LINK_TRAINING_EQ_FAIL_CR_PARTIAL: + lt_result = "CR failed in EQ partially"; + break; case LINK_TRAINING_EQ_FAIL_EQ: lt_result = "EQ failed"; break; @@ -1929,8 +1824,8 @@ static void print_status_message( link_rate, lt_settings->link_settings.lane_count, lt_result, - lt_settings->lane_settings[0].VOLTAGE_SWING, - lt_settings->lane_settings[0].PRE_EMPHASIS, + lt_settings->hw_lane_settings[0].VOLTAGE_SWING, + lt_settings->hw_lane_settings[0].PRE_EMPHASIS, lt_spread); } @@ -2074,7 +1969,8 @@ static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence( uint32_t wait_time = 0; union lane_align_status_updated dpcd_lane_status_updated = {0}; union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; - enum link_training_result status = LINK_TRAINING_SUCCESS; + enum dc_status status = DC_OK; + enum link_training_result result = LINK_TRAINING_SUCCESS; union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; /* Transmit 128b/132b_TPS1 over Main-Link */ @@ -2099,22 +1995,24 @@ static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence( lt_settings->pattern_for_eq, DPRX); /* poll for channel EQ done */ - while (status == LINK_TRAINING_SUCCESS) { + while (result == LINK_TRAINING_SUCCESS) { dp_wait_for_training_aux_rd_interval(link, aux_rd_interval); wait_time += aux_rd_interval; - dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status, + status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status, &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX); dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval); - if (dp_is_ch_eq_done(lt_settings->link_settings.lane_count, + if (status != DC_OK) { + result = LINK_TRAINING_ABORT; + } else if (dp_is_ch_eq_done(lt_settings->link_settings.lane_count, dpcd_lane_status)) { /* pass */ break; } else if (loop_count >= lt_settings->eq_loop_count_limit) { - status = DP_128b_132b_MAX_LOOP_COUNT_REACHED; + result = DP_128b_132b_MAX_LOOP_COUNT_REACHED; } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) { - status = DP_128b_132b_LT_FAILED; + result = DP_128b_132b_LT_FAILED; } else { dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX); dpcd_set_lane_settings(link, lt_settings, DPRX); @@ -2123,24 +2021,26 @@ static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence( } /* poll for EQ interlane align done */ - while (status == LINK_TRAINING_SUCCESS) { - if (dpcd_lane_status_updated.bits.EQ_INTERLANE_ALIGN_DONE_128b_132b) { + while (result == LINK_TRAINING_SUCCESS) { + if (status != DC_OK) { + result = LINK_TRAINING_ABORT; + } else if (dpcd_lane_status_updated.bits.EQ_INTERLANE_ALIGN_DONE_128b_132b) { /* pass */ break; } else if (wait_time >= lt_settings->eq_wait_time_limit) { - status = DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT; + result = DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT; } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) { - status = DP_128b_132b_LT_FAILED; + result = DP_128b_132b_LT_FAILED; } else { dp_wait_for_training_aux_rd_interval(link, lt_settings->eq_pattern_time); wait_time += lt_settings->eq_pattern_time; - dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status, + status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status, &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX); } } - return status; + return result; } static enum link_training_result dp_perform_128b_132b_cds_done_sequence( @@ -2149,34 +2049,37 @@ static enum link_training_result dp_perform_128b_132b_cds_done_sequence( struct link_training_settings *lt_settings) { /* Assumption: assume hardware has transmitted eq pattern */ - enum link_training_result status = LINK_TRAINING_SUCCESS; + enum dc_status status = DC_OK; + enum link_training_result result = LINK_TRAINING_SUCCESS; union lane_align_status_updated dpcd_lane_status_updated = {0}; union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; - union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } }; + union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; uint32_t wait_time = 0; /* initiate CDS done sequence */ dpcd_set_training_pattern(link, lt_settings->pattern_for_cds); /* poll for CDS interlane align done and symbol lock */ - while (status == LINK_TRAINING_SUCCESS) { + while (result == LINK_TRAINING_SUCCESS) { dp_wait_for_training_aux_rd_interval(link, lt_settings->cds_pattern_time); wait_time += lt_settings->cds_pattern_time; - dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status, + status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status, &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX); - if (dp_is_symbol_locked(lt_settings->link_settings.lane_count, dpcd_lane_status) && + if (status != DC_OK) { + result = LINK_TRAINING_ABORT; + } else if (dp_is_symbol_locked(lt_settings->link_settings.lane_count, dpcd_lane_status) && dpcd_lane_status_updated.bits.CDS_INTERLANE_ALIGN_DONE_128b_132b) { /* pass */ break; } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) { - status = DP_128b_132b_LT_FAILED; + result = DP_128b_132b_LT_FAILED; } else if (wait_time >= lt_settings->cds_wait_time_limit) { - status = DP_128b_132b_CDS_DONE_TIMEOUT; + result = DP_128b_132b_CDS_DONE_TIMEOUT; } } - return status; + return result; } static enum link_training_result dp_perform_8b_10b_link_training( @@ -2370,6 +2273,7 @@ static enum link_training_result dp_perform_fixed_vs_pe_training_sequence( link->dpcd_caps.lttpr_caps.phy_repeater_cnt); const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0}; const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x68}; + uint32_t pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa; uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0}; uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0}; uint32_t vendor_lttpr_write_address = 0xF004F; @@ -2392,6 +2296,10 @@ static enum link_training_result dp_perform_fixed_vs_pe_training_sequence( if (offset != 0xFF) { vendor_lttpr_write_address += ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); + + /* Certain display and cable configuration require extra delay */ + if (offset > 2) + pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2; } /* Vendor specific: Reset lane settings */ @@ -2471,6 +2379,7 @@ static enum link_training_result dp_perform_fixed_vs_pe_training_sequence( /* Perform Clock Recovery Sequence */ if (status == LINK_TRAINING_SUCCESS) { + const uint8_t max_vendor_dpcd_retries = 10; uint32_t retries_cr; uint32_t retry_count; uint32_t wait_time_microsec; @@ -2478,6 +2387,8 @@ static enum link_training_result dp_perform_fixed_vs_pe_training_sequence( union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX]; union lane_align_status_updated dpcd_lane_status_updated; union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; + enum dc_status dpcd_status = DC_OK; + uint8_t i = 0; retries_cr = 0; retry_count = 0; @@ -2508,11 +2419,23 @@ static enum link_training_result dp_perform_fixed_vs_pe_training_sequence( lt_settings->pattern_for_cr, 0); /* Vendor specific: Disable intercept */ - core_link_write_dpcd( - link, - vendor_lttpr_write_address, - &vendor_lttpr_write_data_intercept_dis[0], - sizeof(vendor_lttpr_write_data_intercept_dis)); + for (i = 0; i < max_vendor_dpcd_retries; i++) { + msleep(pre_disable_intercept_delay_ms); + dpcd_status = core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_intercept_dis[0], + sizeof(vendor_lttpr_write_data_intercept_dis)); + + if (dpcd_status == DC_OK) + break; + + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_intercept_en[0], + sizeof(vendor_lttpr_write_data_intercept_en)); + } } else { vendor_lttpr_write_data_vs[3] = 0; vendor_lttpr_write_data_pe[3] = 0; @@ -2718,14 +2641,7 @@ enum link_training_result dc_link_dp_perform_link_training( <_settings); /* reset previous training states */ - if (link->dc->debug.apply_vendor_specific_lttpr_wa && - (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && - link->lttpr_mode == LTTPR_MODE_TRANSPARENT) { - link->apply_vendor_specific_lttpr_link_rate_wa = true; - vendor_specific_lttpr_wa_four(link, true); - } else { - dpcd_exit_training_mode(link); - } + dpcd_exit_training_mode(link); /* configure link prior to entering training mode */ dpcd_configure_lttpr_mode(link, <_settings); @@ -2746,14 +2662,7 @@ enum link_training_result dc_link_dp_perform_link_training( ASSERT(0); /* exit training mode */ - if (link->dc->debug.apply_vendor_specific_lttpr_wa && - (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && - link->lttpr_mode == LTTPR_MODE_TRANSPARENT) { - link->apply_vendor_specific_lttpr_link_rate_wa = false; - vendor_specific_lttpr_wa_four(link, (status != LINK_TRAINING_SUCCESS)); - } else { - dpcd_exit_training_mode(link); - } + dpcd_exit_training_mode(link); /* switch to video idle */ if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern) @@ -2804,8 +2713,8 @@ bool perform_link_training_with_retries( j = 0; while (j < attempts && fail_count < (attempts * 10)) { - DC_LOG_HW_LINK_TRAINING("%s: Beginning link training attempt %u of %d @ rate(%d) x lane(%d)\n", - __func__, (unsigned int)j + 1, attempts, cur_link_settings.link_rate, + DC_LOG_HW_LINK_TRAINING("%s: Beginning link(%d) training attempt %u of %d @ rate(%d) x lane(%d)\n", + __func__, link->link_index, (unsigned int)j + 1, attempts, cur_link_settings.link_rate, cur_link_settings.lane_count); dp_enable_link_phy( @@ -2867,14 +2776,17 @@ bool perform_link_training_with_retries( fail_count++; dp_trace_lt_fail_count_update(link, fail_count, false); - /* latest link training still fail, skip delay and keep PHY on - */ - if (j == (attempts - 1) && link->ep_type == DISPLAY_ENDPOINT_PHY) - break; + if (link->ep_type == DISPLAY_ENDPOINT_PHY) { + /* latest link training still fail or link training is aborted + * skip delay and keep PHY on + */ + if (j == (attempts - 1) || (status == LINK_TRAINING_ABORT)) + break; + } - DC_LOG_WARNING("%s: Link training attempt %u of %d failed @ rate(%d) x lane(%d)\n", - __func__, (unsigned int)j + 1, attempts, cur_link_settings.link_rate, - cur_link_settings.lane_count); + DC_LOG_WARNING("%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) : fail reason:(%d)\n", + __func__, link->link_index, (unsigned int)j + 1, attempts, cur_link_settings.link_rate, + cur_link_settings.lane_count, status); dp_disable_link_phy(link, &pipe_ctx->link_res, signal); @@ -2916,8 +2828,13 @@ bool perform_link_training_with_retries( */ req_bw = dc_bandwidth_in_kbps_from_timing(&stream->timing); link_bw = dc_link_bandwidth_kbps(link, &cur_link_settings); - if (req_bw > link_bw) - break; + is_link_bw_low = (req_bw > link_bw); + is_link_bw_min = ((cur_link_settings.link_rate <= LINK_RATE_LOW) && + (cur_link_settings.lane_count <= LANE_COUNT_ONE)); + if (is_link_bw_low) + DC_LOG_WARNING( + "%s: Link(%d) bandwidth too low after fallback req_bw(%d) > link_bw(%d)\n", + __func__, link->link_index, req_bw, link_bw); } msleep(delay_between_attempts); @@ -3596,11 +3513,6 @@ static bool decide_fallback_link_setting( struct dc_link_settings *cur, enum link_training_result training_result) { - if (!cur) - return false; - if (!max) - return false; - if (dp_get_link_encoding_format(max) == DP_128b_132b_ENCODING || link->dc->debug.force_dp2_lt_fallback_method) return decide_fallback_link_setting_max_bw_policy(link, max, cur, @@ -3630,6 +3542,7 @@ static bool decide_fallback_link_setting( break; } case LINK_TRAINING_EQ_FAIL_EQ: + case LINK_TRAINING_EQ_FAIL_CR_PARTIAL: { if (!reached_minimum_lane_count(cur->lane_count)) { cur->lane_count = reduce_lane_count(cur->lane_count); @@ -4186,8 +4099,7 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link) &dpcd_lane_adjustment[0].raw, sizeof(dpcd_lane_adjustment)); - if (link->dc->debug.apply_vendor_specific_lttpr_wa && - (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && + if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && link->lttpr_mode == LTTPR_MODE_TRANSPARENT) dp_fixed_vs_pe_read_lane_adjust( link, @@ -5118,16 +5030,13 @@ static bool dpcd_read_sink_ext_caps(struct dc_link *link) return true; } -bool dp_retrieve_lttpr_cap(struct dc_link *link) +/* Logic to determine LTTPR mode */ +static void determine_lttpr_mode(struct dc_link *link) { - uint8_t lttpr_dpcd_data[8]; bool allow_lttpr_non_transparent_mode = 0; bool vbios_lttpr_enable = link->dc->caps.vbios_lttpr_enable; bool vbios_lttpr_interop = link->dc->caps.vbios_lttpr_aware; - enum dc_status status = DC_ERROR_UNEXPECTED; - bool is_lttpr_present = false; - memset(lttpr_dpcd_data, '\0', sizeof(lttpr_dpcd_data)); if ((link->dc->config.allow_lttpr_non_transparent_mode.bits.DP2_0 && link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED)) { @@ -5137,9 +5046,6 @@ bool dp_retrieve_lttpr_cap(struct dc_link *link) allow_lttpr_non_transparent_mode = 1; } - /* - * Logic to determine LTTPR mode - */ link->lttpr_mode = LTTPR_MODE_NON_LTTPR; if (vbios_lttpr_enable && vbios_lttpr_interop) link->lttpr_mode = LTTPR_MODE_NON_TRANSPARENT; @@ -5161,8 +5067,33 @@ bool dp_retrieve_lttpr_cap(struct dc_link *link) link->dc->debug.dpia_debug.bits.force_non_lttpr) link->lttpr_mode = LTTPR_MODE_NON_LTTPR; #endif +} + +bool dp_retrieve_lttpr_cap(struct dc_link *link) +{ + uint8_t lttpr_dpcd_data[8]; + enum dc_status status = DC_ERROR_UNEXPECTED; + bool is_lttpr_present = false; + + memset(lttpr_dpcd_data, '\0', sizeof(lttpr_dpcd_data)); + + /* Logic to determine LTTPR mode*/ + determine_lttpr_mode(link); if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT || link->lttpr_mode == LTTPR_MODE_TRANSPARENT) { + if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && + !link->dc->debug.disable_fixed_vs_aux_timeout_wa) { + /* Fixed VS workaround for AUX timeout */ + const uint32_t fixed_vs_address = 0xF004F; + const uint8_t fixed_vs_data[4] = {0x1, 0x22, 0x63, 0xc}; + + core_link_write_dpcd( + link, + fixed_vs_address, + fixed_vs_data, + sizeof(fixed_vs_data)); + } + /* By reading LTTPR capability, RX assumes that we will enable * LTTPR extended aux timeout if LTTPR is present. */ @@ -5276,11 +5207,23 @@ static enum dc_status wa_try_to_wake_dprx(struct dc_link *link, uint64_t timeout uint64_t time_taken_ms = 0; enum dc_connection_type type = dc_connection_none; - status = core_link_read_dpcd( - link, - DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV, - &dpcd_data, - sizeof(dpcd_data)); + determine_lttpr_mode(link); + + /* Issue an AUX read to test DPRX responsiveness. If LTTPR is supported the first read is expected to + * be to determine LTTPR capabilities. Otherwise trying to read power state should be an innocuous AUX read. + */ + if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT || link->lttpr_mode == LTTPR_MODE_TRANSPARENT) + status = core_link_read_dpcd( + link, + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV, + &dpcd_data, + sizeof(dpcd_data)); + else + status = core_link_read_dpcd( + link, + DP_SET_POWER, + &dpcd_data, + sizeof(dpcd_data)); if (status != DC_OK) { DC_LOG_WARNING("%s: Read DPCD LTTPR_CAP failed - try to toggle DPCD SET_POWER for %lld ms.", @@ -5794,6 +5737,7 @@ void detect_edp_sink_caps(struct dc_link *link) uint32_t link_rate_in_khz; enum dc_link_rate link_rate = LINK_RATE_UNKNOWN; uint8_t backlight_adj_cap; + uint8_t general_edp_cap; retrieve_link_cap(link); link->dpcd_caps.edp_supported_link_rates_count = 0; @@ -5832,6 +5776,12 @@ void detect_edp_sink_caps(struct dc_link *link) link->dpcd_caps.dynamic_backlight_capable_edp = (backlight_adj_cap & DP_EDP_DYNAMIC_BACKLIGHT_CAP) ? true:false; + core_link_read_dpcd(link, DP_EDP_GENERAL_CAP_1, + &general_edp_cap, sizeof(general_edp_cap)); + + link->dpcd_caps.set_power_state_capable_edp = + (general_edp_cap & DP_EDP_SET_POWER_CAP) ? true:false; + dc_link_set_default_brightness_aux(link); core_link_read_dpcd(link, DP_EDP_DPCD_REV, @@ -6119,8 +6069,7 @@ 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) { - if (link->dc->debug.apply_vendor_specific_lttpr_wa && - (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && + if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && link->lttpr_mode == LTTPR_MODE_TRANSPARENT) { dp_fixed_vs_pe_set_retimer_lane_settings( link, @@ -6861,10 +6810,21 @@ bool dpcd_write_128b_132b_sst_payload_allocation_table( if (allocate) { avg_time_slots_per_mtp = calculate_sst_avg_time_slots_per_mtp(stream, link); req_slot_count = dc_fixpt_ceil(avg_time_slots_per_mtp); + /// Validation should filter out modes that exceed link BW + ASSERT(req_slot_count <= MAX_MTP_SLOT_COUNT); + if (req_slot_count > MAX_MTP_SLOT_COUNT) + return false; } else { /// Leave req_slot_count = 0 if allocate is false. } + proposed_table->stream_count = 1; /// Always 1 stream for SST + proposed_table->stream_allocations[0].slot_count = req_slot_count; + proposed_table->stream_allocations[0].vcp_id = vc_id; + + if (link->aux_access_disabled) + return true; + /// Write DPCD 2C0 = 1 to start updating update_status.bits.VC_PAYLOAD_TABLE_UPDATED = 1; core_link_write_dpcd( @@ -6888,7 +6848,6 @@ bool dpcd_write_128b_132b_sst_payload_allocation_table( &start_time_slot, 1); - ASSERT(req_slot_count <= MAX_MTP_SLOT_COUNT); /// Validation should filter out modes that exceed link BW core_link_write_dpcd( link, DP_PAYLOAD_ALLOCATE_TIME_SLOT_COUNT, @@ -6933,10 +6892,6 @@ bool dpcd_write_128b_132b_sst_payload_allocation_table( // TODO - DP2.0 Payload: Read and log the payload table from downstream branch } - proposed_table->stream_count = 1; /// Always 1 stream for SST - proposed_table->stream_allocations[0].slot_count = req_slot_count; - proposed_table->stream_allocations[0].vcp_id = vc_id; - return result; } @@ -6952,6 +6907,8 @@ bool dpcd_poll_for_allocation_change_trigger(struct dc_link *link) union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX]; union lane_align_status_updated lane_status_updated; + if (link->aux_access_disabled) + return true; for (i = 0; i < act_retries; i++) { get_lane_status(link, link->cur_link_settings.lane_count, dpcd_lane_status, &lane_status_updated); @@ -7099,7 +7056,8 @@ void dp_enable_link_phy( unsigned int i; if (link->connector_signal == SIGNAL_TYPE_EDP) { - link->dc->hwss.edp_power_control(link, true); + if (!link->dc->config.edp_no_power_sequencing) + link->dc->hwss.edp_power_control(link, true); link->dc->hwss.edp_wait_for_hpd_ready(link, true); } |