summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2022-07-12 11:07:30 +1000
committerDave Airlie <airlied@redhat.com>2022-07-12 11:07:32 +1000
commit344feb7ccf764756937cfd74fa4ac5caba069c99 (patch)
treeb86c7eb43878b310c31702094763d130b7e31dc5 /drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
parentc6a3d73592ae20f2f6306f823aa5121c83c88223 (diff)
parentc5da61cf5bab30059f22ea368702c445ee87171a (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.c376
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(
&lt_settings->link_settings.link_rate_set, 1);
} else {
rate = get_dpcd_link_rate(&lt_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(
&lt_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, &lt_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);
}