drm/amd/display: move dp link training logic to link_dp_training
[why] Extract dp link training logic out to their own files. link_dp_training - high level training sequence and helper functions. link_dp_training_8b_10b - dp1.x training link_dp_training_auxless - aux-less training link_dp_traininig_dpia - dpia training link_dp_training_fixed_vs_pe_retimer - fixed vs pe retimer training link_dp_training_128b_132b - dp2.1 training Tested-by: Daniel Wheeler <Daniel.Wheeler@amd.com> Reviewed-by: Wesley Chalmers <Wesley.Chalmers@amd.com> Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com> Signed-off-by: Wenjing Liu <wenjing.liu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
899dd5b835
commit
630168a973
@ -54,6 +54,7 @@
|
||||
#include "link/link_dpcd.h"
|
||||
#include "link/link_dp_trace.h"
|
||||
#include "link/link_hpd.h"
|
||||
#include "link/link_dp_training.h"
|
||||
|
||||
#include "dc/dcn30/dcn30_vpg.h"
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -975,6 +975,9 @@ struct dpcd_usb4_dp_tunneling_info {
|
||||
/* TODO - Use DRM header to replace above once available */
|
||||
#endif // DP_INTRA_HOP_AUX_REPLY_INDICATION
|
||||
|
||||
#ifndef DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE
|
||||
#define DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE 0x50
|
||||
#endif
|
||||
union dp_main_line_channel_coding_cap {
|
||||
struct {
|
||||
uint8_t DP_8b_10b_SUPPORTED :1;
|
||||
|
@ -459,27 +459,6 @@ void dc_link_dp_set_drive_settings(
|
||||
const struct link_resource *link_res,
|
||||
struct link_training_settings *lt_settings);
|
||||
|
||||
bool dc_link_dp_perform_link_training_skip_aux(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
const struct dc_link_settings *link_setting);
|
||||
|
||||
enum link_training_result dc_link_dp_perform_link_training(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
const struct dc_link_settings *link_settings,
|
||||
bool skip_video_pattern);
|
||||
|
||||
bool dc_link_dp_sync_lt_begin(struct dc_link *link);
|
||||
|
||||
enum link_training_result dc_link_dp_sync_lt_attempt(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
struct dc_link_settings *link_setting,
|
||||
struct dc_link_training_overrides *lt_settings);
|
||||
|
||||
bool dc_link_dp_sync_lt_end(struct dc_link *link, bool link_down);
|
||||
|
||||
bool dc_link_dp_set_test_pattern(
|
||||
struct dc_link *link,
|
||||
enum dp_test_pattern test_pattern,
|
||||
@ -601,4 +580,7 @@ bool reset_cur_dp_mst_topology(struct dc_link *link);
|
||||
int dc_link_aux_transfer_raw(struct ddc_service *ddc,
|
||||
struct aux_payload *payload,
|
||||
enum aux_return_code_type *operation_result);
|
||||
|
||||
enum lttpr_mode dc_link_decide_lttpr_mode(struct dc_link *link,
|
||||
struct dc_link_settings *link_setting);
|
||||
#endif /* DC_LINK_H_ */
|
||||
|
@ -31,7 +31,6 @@
|
||||
#define LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD 3200 /*us*/
|
||||
#define LINK_AUX_DEFAULT_TIMEOUT_PERIOD 552 /*us*/
|
||||
#define MAX_MTP_SLOT_COUNT 64
|
||||
#define DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE 0x50
|
||||
#define TRAINING_AUX_RD_INTERVAL 100 //us
|
||||
#define LINK_AUX_WAKE_TIMEOUT_MS 1500 // Timeout when trying to wake unresponsive DPRX.
|
||||
|
||||
@ -40,11 +39,6 @@ struct dc_stream_state;
|
||||
struct dc_link_settings;
|
||||
|
||||
enum {
|
||||
LINK_TRAINING_MAX_RETRY_COUNT = 5,
|
||||
/* to avoid infinite loop where-in the receiver
|
||||
* switches between different VS
|
||||
*/
|
||||
LINK_TRAINING_MAX_CR_RETRY = 100,
|
||||
/*
|
||||
* Some receivers fail to train on first try and are good
|
||||
* on subsequent tries. 2 retries should be plenty. If we
|
||||
@ -74,17 +68,8 @@ bool decide_link_settings(
|
||||
struct dc_stream_state *stream,
|
||||
struct dc_link_settings *link_setting);
|
||||
|
||||
bool perform_link_training_with_retries(
|
||||
const struct dc_link_settings *link_setting,
|
||||
bool skip_video_pattern,
|
||||
int attempts,
|
||||
struct pipe_ctx *pipe_ctx,
|
||||
enum signal_type signal,
|
||||
bool do_fallback);
|
||||
|
||||
bool hpd_rx_irq_check_link_loss_status(
|
||||
struct dc_link *link,
|
||||
union hpd_irq_data *hpd_irq_dpcd_data);
|
||||
bool hpd_rx_irq_check_link_loss_status(struct dc_link *link,
|
||||
union hpd_irq_data *hpd_irq_dpcd_data);
|
||||
|
||||
bool is_mst_supported(struct dc_link *link);
|
||||
|
||||
@ -109,63 +94,6 @@ void dpcd_set_source_specific_data(struct dc_link *link);
|
||||
|
||||
void dpcd_write_cable_id_to_dprx(struct dc_link *link);
|
||||
|
||||
/* Write DPCD link configuration data. */
|
||||
enum dc_status dpcd_set_link_settings(
|
||||
struct dc_link *link,
|
||||
const struct link_training_settings *lt_settings);
|
||||
/* Write DPCD drive settings. */
|
||||
enum dc_status dpcd_set_lane_settings(
|
||||
struct dc_link *link,
|
||||
const struct link_training_settings *link_training_setting,
|
||||
uint32_t offset);
|
||||
/* Read training status and adjustment requests from DPCD. */
|
||||
enum dc_status dp_get_lane_status_and_lane_adjust(
|
||||
struct dc_link *link,
|
||||
const struct link_training_settings *link_training_setting,
|
||||
union lane_status ln_status[LANE_COUNT_DP_MAX],
|
||||
union lane_align_status_updated *ln_align,
|
||||
union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
|
||||
uint32_t offset);
|
||||
|
||||
void dp_wait_for_training_aux_rd_interval(
|
||||
struct dc_link *link,
|
||||
uint32_t wait_in_micro_secs);
|
||||
|
||||
bool dp_is_cr_done(enum dc_lane_count ln_count,
|
||||
union lane_status *dpcd_lane_status);
|
||||
|
||||
enum link_training_result dp_get_cr_failure(enum dc_lane_count ln_count,
|
||||
union lane_status *dpcd_lane_status);
|
||||
|
||||
bool dp_is_ch_eq_done(enum dc_lane_count ln_count,
|
||||
union lane_status *dpcd_lane_status);
|
||||
bool dp_is_symbol_locked(enum dc_lane_count ln_count,
|
||||
union lane_status *dpcd_lane_status);
|
||||
bool dp_is_interlane_aligned(union lane_align_status_updated align_status);
|
||||
|
||||
bool dp_is_max_vs_reached(
|
||||
const struct link_training_settings *lt_settings);
|
||||
void dp_hw_to_dpcd_lane_settings(
|
||||
const struct link_training_settings *lt_settings,
|
||||
const struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
|
||||
union dpcd_training_lane dpcd_lane_settings[]);
|
||||
void dp_decide_lane_settings(
|
||||
const struct link_training_settings *lt_settings,
|
||||
const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
|
||||
struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
|
||||
union dpcd_training_lane dpcd_lane_settings[]);
|
||||
|
||||
uint32_t dp_translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval);
|
||||
|
||||
enum dpcd_training_patterns
|
||||
dc_dp_training_pattern_to_dpcd_training_pattern(
|
||||
struct dc_link *link,
|
||||
enum dc_dp_training_pattern pattern);
|
||||
|
||||
uint8_t dc_dp_initialize_scrambling_data_symbols(
|
||||
struct dc_link *link,
|
||||
enum dc_dp_training_pattern pattern);
|
||||
|
||||
enum dc_status dp_set_fec_ready(struct dc_link *link, const struct link_resource *link_res, bool ready);
|
||||
void dp_set_fec_enable(struct dc_link *link, bool enable);
|
||||
bool dp_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable);
|
||||
@ -183,32 +111,15 @@ void dp_decide_training_settings(
|
||||
/* Convert PHY repeater count read from DPCD uint8_t. */
|
||||
uint8_t dp_convert_to_count(uint8_t lttpr_repeater_count);
|
||||
|
||||
/* Check DPCD training status registers to detect link loss. */
|
||||
enum link_training_result dp_check_link_loss_status(
|
||||
struct dc_link *link,
|
||||
const struct link_training_settings *link_training_setting);
|
||||
|
||||
enum dc_status dpcd_configure_lttpr_mode(
|
||||
struct dc_link *link,
|
||||
struct link_training_settings *lt_settings);
|
||||
|
||||
enum dp_link_encoding dp_get_link_encoding_format(const struct dc_link_settings *link_settings);
|
||||
enum dc_status dp_retrieve_lttpr_cap(struct dc_link *link);
|
||||
bool dp_is_lttpr_present(struct dc_link *link);
|
||||
enum lttpr_mode dp_decide_lttpr_mode(struct dc_link *link, struct dc_link_settings *link_setting);
|
||||
void dp_get_lttpr_mode_override(struct dc_link *link, enum lttpr_mode *override);
|
||||
enum lttpr_mode dp_decide_8b_10b_lttpr_mode(struct dc_link *link);
|
||||
enum lttpr_mode dp_decide_128b_132b_lttpr_mode(struct dc_link *link);
|
||||
bool dpcd_write_128b_132b_sst_payload_allocation_table(
|
||||
const struct dc_stream_state *stream,
|
||||
struct dc_link *link,
|
||||
struct link_mst_stream_allocation_table *proposed_table,
|
||||
bool allocate);
|
||||
|
||||
enum dc_status dpcd_configure_channel_coding(
|
||||
struct dc_link *link,
|
||||
struct link_training_settings *lt_settings);
|
||||
|
||||
bool dpcd_poll_for_allocation_change_trigger(struct dc_link *link);
|
||||
|
||||
struct fixed31_32 calculate_sst_avg_time_slots_per_mtp(
|
||||
@ -220,7 +131,6 @@ void enable_dp_hpo_output(struct dc_link *link,
|
||||
void disable_dp_hpo_output(struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
enum signal_type signal);
|
||||
|
||||
void setup_dp_hpo_stream(struct pipe_ctx *pipe_ctx, bool enable);
|
||||
bool is_dp_128b_132b_signal(struct pipe_ctx *pipe_ctx);
|
||||
void edp_panel_backlight_power_on(struct dc_link *link, bool wait_for_hpd);
|
||||
@ -242,26 +152,20 @@ void dp_disable_link_phy(struct dc_link *link, const struct link_resource *link_
|
||||
void dp_disable_link_phy_mst(struct dc_link *link, const struct link_resource *link_res,
|
||||
enum signal_type signal);
|
||||
|
||||
bool dp_set_hw_training_pattern(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
enum dc_dp_training_pattern pattern,
|
||||
uint32_t offset);
|
||||
|
||||
void dp_set_hw_lane_settings(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
const struct link_training_settings *link_settings,
|
||||
uint32_t offset);
|
||||
|
||||
void dp_set_hw_test_pattern(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
enum dp_test_pattern test_pattern,
|
||||
uint8_t *custom_pattern,
|
||||
uint32_t custom_pattern_size);
|
||||
|
||||
void dp_retrain_link_dp_test(struct dc_link *link,
|
||||
struct dc_link_settings *link_setting,
|
||||
bool skip_video_pattern);
|
||||
|
||||
bool decide_fallback_link_setting(
|
||||
struct dc_link *link,
|
||||
struct dc_link_settings *max,
|
||||
struct dc_link_settings *cur,
|
||||
enum link_training_result training_result);
|
||||
|
||||
#endif /* __DC_LINK_DP_H__ */
|
||||
|
@ -24,7 +24,9 @@
|
||||
# PHY, HPD, DDC and etc).
|
||||
|
||||
LINK = link_hwss_dio.o link_hwss_dpia.o link_hwss_hpo_dp.o link_dp_trace.o \
|
||||
link_hpd.o link_ddc.o link_dpcd.o link_dp_dpia.o
|
||||
link_hpd.o link_ddc.o link_dpcd.o link_dp_dpia.o link_dp_training.o \
|
||||
link_dp_training_8b_10b.o link_dp_training_128b_132b.o link_dp_training_dpia.o \
|
||||
link_dp_training_auxless.o link_dp_training_fixed_vs_pe_retimer.o
|
||||
|
||||
AMD_DAL_LINK = $(addprefix $(AMDDALPATH)/dc/link/,$(LINK))
|
||||
|
||||
|
@ -34,12 +34,20 @@
|
||||
#include "link_hwss.h"
|
||||
#include "dm_helpers.h"
|
||||
#include "dmub/inc/dmub_cmd.h"
|
||||
#include "link/link_dpcd.h"
|
||||
#include "link_dpcd.h"
|
||||
#include "link_dp_training.h"
|
||||
#include "dc_dmub_srv.h"
|
||||
|
||||
#define DC_LOGGER \
|
||||
link->ctx->logger
|
||||
|
||||
/** @note Can remove once DP tunneling registers in upstream include/drm/drm_dp_helper.h */
|
||||
/* DPCD DP Tunneling over USB4 */
|
||||
#define DP_TUNNELING_CAPABILITIES_SUPPORT 0xe000d
|
||||
#define DP_IN_ADAPTER_INFO 0xe000e
|
||||
#define DP_USB4_DRIVER_ID 0xe000f
|
||||
#define DP_USB4_ROUTER_TOPOLOGY_ID 0xe001b
|
||||
|
||||
enum dc_status dpcd_get_tunneling_device_data(struct dc_link *link)
|
||||
{
|
||||
enum dc_status status = DC_OK;
|
||||
@ -47,19 +55,20 @@ enum dc_status dpcd_get_tunneling_device_data(struct dc_link *link)
|
||||
uint8_t dpcd_topology_data[DPCD_USB4_TOPOLOGY_ID_LEN] = {0};
|
||||
uint8_t i = 0;
|
||||
|
||||
status = core_link_read_dpcd(link,
|
||||
status = core_link_read_dpcd(
|
||||
link,
|
||||
DP_TUNNELING_CAPABILITIES_SUPPORT,
|
||||
dpcd_dp_tun_data,
|
||||
sizeof(dpcd_dp_tun_data));
|
||||
|
||||
status = core_link_read_dpcd(link,
|
||||
status = core_link_read_dpcd(
|
||||
link,
|
||||
DP_USB4_ROUTER_TOPOLOGY_ID,
|
||||
dpcd_topology_data,
|
||||
sizeof(dpcd_topology_data));
|
||||
|
||||
link->dpcd_caps.usb4_dp_tun_info.dp_tun_cap.raw =
|
||||
dpcd_dp_tun_data[DP_TUNNELING_CAPABILITIES_SUPPORT -
|
||||
DP_TUNNELING_CAPABILITIES_SUPPORT];
|
||||
dpcd_dp_tun_data[DP_TUNNELING_CAPABILITIES_SUPPORT - DP_TUNNELING_CAPABILITIES_SUPPORT];
|
||||
link->dpcd_caps.usb4_dp_tun_info.dpia_info.raw =
|
||||
dpcd_dp_tun_data[DP_IN_ADAPTER_INFO - DP_TUNNELING_CAPABILITIES_SUPPORT];
|
||||
link->dpcd_caps.usb4_dp_tun_info.usb4_driver_id =
|
||||
@ -96,929 +105,3 @@ bool dc_link_dpia_query_hpd_status(struct dc_link *link)
|
||||
return is_hpd_high;
|
||||
}
|
||||
|
||||
/* Configure link as prescribed in link_setting; set LTTPR mode; and
|
||||
* Initialize link training settings.
|
||||
* Abort link training if sink unplug detected.
|
||||
*
|
||||
* @param link DPIA link being trained.
|
||||
* @param[in] link_setting Lane count, link rate and downspread control.
|
||||
* @param[out] lt_settings Link settings and drive settings (voltage swing and pre-emphasis).
|
||||
*/
|
||||
static enum link_training_result dpia_configure_link(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
const struct dc_link_settings *link_setting,
|
||||
struct link_training_settings *lt_settings)
|
||||
{
|
||||
enum dc_status status;
|
||||
bool fec_enable;
|
||||
|
||||
DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) configuring\n - LTTPR mode(%d)\n",
|
||||
__func__,
|
||||
link->link_id.enum_id - ENUM_ID_1,
|
||||
lt_settings->lttpr_mode);
|
||||
|
||||
dp_decide_training_settings(link,
|
||||
link_setting,
|
||||
lt_settings);
|
||||
|
||||
dp_get_lttpr_mode_override(link, <_settings->lttpr_mode);
|
||||
|
||||
status = dpcd_configure_channel_coding(link, lt_settings);
|
||||
if (status != DC_OK && link->is_hpd_pending)
|
||||
return LINK_TRAINING_ABORT;
|
||||
|
||||
/* Configure lttpr mode */
|
||||
status = dpcd_configure_lttpr_mode(link, lt_settings);
|
||||
if (status != DC_OK && link->is_hpd_pending)
|
||||
return LINK_TRAINING_ABORT;
|
||||
|
||||
/* Set link rate, lane count and spread. */
|
||||
status = dpcd_set_link_settings(link, lt_settings);
|
||||
if (status != DC_OK && link->is_hpd_pending)
|
||||
return LINK_TRAINING_ABORT;
|
||||
|
||||
if (link->preferred_training_settings.fec_enable)
|
||||
fec_enable = *link->preferred_training_settings.fec_enable;
|
||||
else
|
||||
fec_enable = true;
|
||||
status = dp_set_fec_ready(link, link_res, fec_enable);
|
||||
if (status != DC_OK && link->is_hpd_pending)
|
||||
return LINK_TRAINING_ABORT;
|
||||
|
||||
return LINK_TRAINING_SUCCESS;
|
||||
}
|
||||
|
||||
static enum dc_status core_link_send_set_config(struct dc_link *link,
|
||||
uint8_t msg_type,
|
||||
uint8_t msg_data)
|
||||
{
|
||||
struct set_config_cmd_payload payload;
|
||||
enum set_config_status set_config_result = SET_CONFIG_PENDING;
|
||||
|
||||
/* prepare set_config payload */
|
||||
payload.msg_type = msg_type;
|
||||
payload.msg_data = msg_data;
|
||||
|
||||
if (!link->ddc->ddc_pin && !link->aux_access_disabled &&
|
||||
(dm_helpers_dmub_set_config_sync(link->ctx, link,
|
||||
&payload, &set_config_result) == -1)) {
|
||||
return DC_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
/* set_config should return ACK if successful */
|
||||
return (set_config_result == SET_CONFIG_ACK_RECEIVED) ? DC_OK : DC_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
/* Build SET_CONFIG message data payload for specified message type. */
|
||||
static uint8_t dpia_build_set_config_data(enum dpia_set_config_type type,
|
||||
struct dc_link *link,
|
||||
struct link_training_settings *lt_settings)
|
||||
{
|
||||
union dpia_set_config_data data;
|
||||
|
||||
data.raw = 0;
|
||||
|
||||
switch (type) {
|
||||
case DPIA_SET_CFG_SET_LINK:
|
||||
data.set_link.mode = lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT ? 1 : 0;
|
||||
break;
|
||||
case DPIA_SET_CFG_SET_PHY_TEST_MODE:
|
||||
break;
|
||||
case DPIA_SET_CFG_SET_VSPE:
|
||||
/* Assume all lanes have same drive settings. */
|
||||
data.set_vspe.swing = lt_settings->hw_lane_settings[0].VOLTAGE_SWING;
|
||||
data.set_vspe.pre_emph = lt_settings->hw_lane_settings[0].PRE_EMPHASIS;
|
||||
data.set_vspe.max_swing_reached =
|
||||
lt_settings->hw_lane_settings[0].VOLTAGE_SWING ==
|
||||
VOLTAGE_SWING_MAX_LEVEL ? 1 : 0;
|
||||
data.set_vspe.max_pre_emph_reached =
|
||||
lt_settings->hw_lane_settings[0].PRE_EMPHASIS ==
|
||||
PRE_EMPHASIS_MAX_LEVEL ? 1 : 0;
|
||||
break;
|
||||
default:
|
||||
ASSERT(false); /* Message type not supported by helper function. */
|
||||
break;
|
||||
}
|
||||
|
||||
return data.raw;
|
||||
}
|
||||
|
||||
/* Convert DC training pattern to DPIA training stage. */
|
||||
static enum dc_status convert_trng_ptn_to_trng_stg(enum dc_dp_training_pattern tps, enum dpia_set_config_ts *ts)
|
||||
{
|
||||
enum dc_status status = DC_OK;
|
||||
|
||||
switch (tps) {
|
||||
case DP_TRAINING_PATTERN_SEQUENCE_1:
|
||||
*ts = DPIA_TS_TPS1;
|
||||
break;
|
||||
case DP_TRAINING_PATTERN_SEQUENCE_2:
|
||||
*ts = DPIA_TS_TPS2;
|
||||
break;
|
||||
case DP_TRAINING_PATTERN_SEQUENCE_3:
|
||||
*ts = DPIA_TS_TPS3;
|
||||
break;
|
||||
case DP_TRAINING_PATTERN_SEQUENCE_4:
|
||||
*ts = DPIA_TS_TPS4;
|
||||
break;
|
||||
case DP_TRAINING_PATTERN_VIDEOIDLE:
|
||||
*ts = DPIA_TS_DPRX_DONE;
|
||||
break;
|
||||
default: /* TPS not supported by helper function. */
|
||||
ASSERT(false);
|
||||
*ts = DPIA_TS_DPRX_DONE;
|
||||
status = DC_UNSUPPORTED_VALUE;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Write training pattern to DPCD. */
|
||||
static enum dc_status dpcd_set_lt_pattern(struct dc_link *link,
|
||||
enum dc_dp_training_pattern pattern,
|
||||
uint32_t hop)
|
||||
{
|
||||
union dpcd_training_pattern dpcd_pattern = {0};
|
||||
uint32_t dpcd_tps_offset = DP_TRAINING_PATTERN_SET;
|
||||
enum dc_status status;
|
||||
|
||||
if (hop != DPRX)
|
||||
dpcd_tps_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
|
||||
((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (hop - 1));
|
||||
|
||||
/* DpcdAddress_TrainingPatternSet */
|
||||
dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
|
||||
dc_dp_training_pattern_to_dpcd_training_pattern(link, pattern);
|
||||
|
||||
dpcd_pattern.v1_4.SCRAMBLING_DISABLE =
|
||||
dc_dp_initialize_scrambling_data_symbols(link, pattern);
|
||||
|
||||
if (hop != DPRX) {
|
||||
DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n 0x%X pattern = %x\n",
|
||||
__func__,
|
||||
hop,
|
||||
dpcd_tps_offset,
|
||||
dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
|
||||
} else {
|
||||
DC_LOG_HW_LINK_TRAINING("%s\n 0x%X pattern = %x\n",
|
||||
__func__,
|
||||
dpcd_tps_offset,
|
||||
dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
|
||||
}
|
||||
|
||||
status = core_link_write_dpcd(link,
|
||||
dpcd_tps_offset,
|
||||
&dpcd_pattern.raw,
|
||||
sizeof(dpcd_pattern.raw));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Execute clock recovery phase of link training for specified hop in display
|
||||
* path.in non-transparent mode:
|
||||
* - Driver issues both DPCD and SET_CONFIG transactions.
|
||||
* - TPS1 is transmitted for any hops downstream of DPOA.
|
||||
* - Drive (VS/PE) only transmitted for the hop immediately downstream of DPOA.
|
||||
* - CR for the first hop (DPTX-to-DPIA) is assumed to be successful.
|
||||
*
|
||||
* @param link DPIA link being trained.
|
||||
* @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis).
|
||||
* @param hop The Hop in display path. DPRX = 0.
|
||||
*/
|
||||
static enum link_training_result dpia_training_cr_non_transparent(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
struct link_training_settings *lt_settings,
|
||||
uint32_t hop)
|
||||
{
|
||||
enum link_training_result result = LINK_TRAINING_CR_FAIL_LANE0;
|
||||
uint8_t repeater_cnt = 0; /* Number of hops/repeaters in display path. */
|
||||
enum dc_status status;
|
||||
uint32_t retries_cr = 0; /* Number of consecutive attempts with same VS or PE. */
|
||||
uint32_t retry_count = 0;
|
||||
/* From DP spec, CR read interval is always 100us. */
|
||||
uint32_t wait_time_microsec = TRAINING_AUX_RD_INTERVAL;
|
||||
enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
|
||||
union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
|
||||
union lane_align_status_updated dpcd_lane_status_updated = {0};
|
||||
union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
|
||||
uint8_t set_cfg_data;
|
||||
enum dpia_set_config_ts ts;
|
||||
|
||||
repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
|
||||
|
||||
/* Cap of LINK_TRAINING_MAX_CR_RETRY attempts at clock recovery.
|
||||
* Fix inherited from perform_clock_recovery_sequence() -
|
||||
* the DP equivalent of this function:
|
||||
* Required for Synaptics MST hub which can put the LT in
|
||||
* infinite loop by switching the VS between level 0 and level 1
|
||||
* continuously.
|
||||
*/
|
||||
while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
|
||||
(retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
|
||||
/* DPTX-to-DPIA */
|
||||
if (hop == repeater_cnt) {
|
||||
/* Send SET_CONFIG(SET_LINK:LC,LR,LTTPR) to notify DPOA that
|
||||
* non-transparent link training has started.
|
||||
* This also enables the transmission of clk_sync packets.
|
||||
*/
|
||||
set_cfg_data = dpia_build_set_config_data(DPIA_SET_CFG_SET_LINK,
|
||||
link,
|
||||
lt_settings);
|
||||
status = core_link_send_set_config(link,
|
||||
DPIA_SET_CFG_SET_LINK,
|
||||
set_cfg_data);
|
||||
/* CR for this hop is considered successful as long as
|
||||
* SET_CONFIG message is acknowledged by DPOA.
|
||||
*/
|
||||
if (status == DC_OK)
|
||||
result = LINK_TRAINING_SUCCESS;
|
||||
else
|
||||
result = LINK_TRAINING_ABORT;
|
||||
break;
|
||||
}
|
||||
|
||||
/* DPOA-to-x */
|
||||
/* Instruct DPOA to transmit TPS1 then update DPCD. */
|
||||
if (retry_count == 0) {
|
||||
status = convert_trng_ptn_to_trng_stg(lt_settings->pattern_for_cr, &ts);
|
||||
if (status != DC_OK) {
|
||||
result = LINK_TRAINING_ABORT;
|
||||
break;
|
||||
}
|
||||
status = dpcd_set_lt_pattern(link, lt_settings->pattern_for_cr, hop);
|
||||
if (status != DC_OK) {
|
||||
result = LINK_TRAINING_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update DPOA drive settings then DPCD. DPOA does only adjusts
|
||||
* drive settings for hops immediately downstream.
|
||||
*/
|
||||
if (hop == repeater_cnt - 1) {
|
||||
set_cfg_data = dpia_build_set_config_data(DPIA_SET_CFG_SET_VSPE,
|
||||
link,
|
||||
lt_settings);
|
||||
status = core_link_send_set_config(link,
|
||||
DPIA_SET_CFG_SET_VSPE,
|
||||
set_cfg_data);
|
||||
if (status != DC_OK) {
|
||||
result = LINK_TRAINING_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
status = dpcd_set_lane_settings(link, lt_settings, hop);
|
||||
if (status != DC_OK) {
|
||||
result = LINK_TRAINING_ABORT;
|
||||
break;
|
||||
}
|
||||
|
||||
dp_wait_for_training_aux_rd_interval(link, wait_time_microsec);
|
||||
|
||||
/* Read status and adjustment requests from DPCD. */
|
||||
status = dp_get_lane_status_and_lane_adjust(
|
||||
link,
|
||||
lt_settings,
|
||||
dpcd_lane_status,
|
||||
&dpcd_lane_status_updated,
|
||||
dpcd_lane_adjust,
|
||||
hop);
|
||||
if (status != DC_OK) {
|
||||
result = LINK_TRAINING_ABORT;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check if clock recovery successful. */
|
||||
if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
|
||||
result = LINK_TRAINING_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
result = dp_get_cr_failure(lane_count, dpcd_lane_status);
|
||||
|
||||
if (dp_is_max_vs_reached(lt_settings))
|
||||
break;
|
||||
|
||||
/* Count number of attempts with same drive settings.
|
||||
* Note: settings are the same for all lanes,
|
||||
* so comparing first lane is sufficient.
|
||||
*/
|
||||
if ((lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
|
||||
dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
|
||||
&& (lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET ==
|
||||
dpcd_lane_adjust[0].bits.PRE_EMPHASIS_LANE))
|
||||
retries_cr++;
|
||||
else
|
||||
retries_cr = 0;
|
||||
|
||||
/* Update VS/PE. */
|
||||
dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
|
||||
lt_settings->hw_lane_settings,
|
||||
lt_settings->dpcd_lane_settings);
|
||||
retry_count++;
|
||||
}
|
||||
|
||||
/* Abort link training if clock recovery failed due to HPD unplug. */
|
||||
if (link->is_hpd_pending)
|
||||
result = LINK_TRAINING_ABORT;
|
||||
|
||||
DC_LOG_HW_LINK_TRAINING(
|
||||
"%s\n DPIA(%d) clock recovery\n -hop(%d)\n - result(%d)\n - retries(%d)\n - status(%d)\n",
|
||||
__func__,
|
||||
link->link_id.enum_id - ENUM_ID_1,
|
||||
hop,
|
||||
result,
|
||||
retry_count,
|
||||
status);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Execute clock recovery phase of link training in transparent LTTPR mode:
|
||||
* - Driver only issues DPCD transactions and leaves USB4 tunneling (SET_CONFIG) messages to DPIA.
|
||||
* - Driver writes TPS1 to DPCD to kick off training.
|
||||
* - Clock recovery (CR) for link is handled by DPOA, which reports result to DPIA on completion.
|
||||
* - DPIA communicates result to driver by updating CR status when driver reads DPCD.
|
||||
*
|
||||
* @param link DPIA link being trained.
|
||||
* @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis).
|
||||
*/
|
||||
static enum link_training_result dpia_training_cr_transparent(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
struct link_training_settings *lt_settings)
|
||||
{
|
||||
enum link_training_result result = LINK_TRAINING_CR_FAIL_LANE0;
|
||||
enum dc_status status;
|
||||
uint32_t retries_cr = 0; /* Number of consecutive attempts with same VS or PE. */
|
||||
uint32_t retry_count = 0;
|
||||
uint32_t wait_time_microsec = lt_settings->cr_pattern_time;
|
||||
enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
|
||||
union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
|
||||
union lane_align_status_updated dpcd_lane_status_updated = {0};
|
||||
union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
|
||||
|
||||
/* Cap of LINK_TRAINING_MAX_CR_RETRY attempts at clock recovery.
|
||||
* Fix inherited from perform_clock_recovery_sequence() -
|
||||
* the DP equivalent of this function:
|
||||
* Required for Synaptics MST hub which can put the LT in
|
||||
* infinite loop by switching the VS between level 0 and level 1
|
||||
* continuously.
|
||||
*/
|
||||
while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
|
||||
(retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
|
||||
/* Write TPS1 (not VS or PE) to DPCD to start CR phase.
|
||||
* DPIA sends SET_CONFIG(SET_LINK) to notify DPOA to
|
||||
* start link training.
|
||||
*/
|
||||
if (retry_count == 0) {
|
||||
status = dpcd_set_lt_pattern(link, lt_settings->pattern_for_cr, DPRX);
|
||||
if (status != DC_OK) {
|
||||
result = LINK_TRAINING_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dp_wait_for_training_aux_rd_interval(link, wait_time_microsec);
|
||||
|
||||
/* Read status and adjustment requests from DPCD. */
|
||||
status = dp_get_lane_status_and_lane_adjust(
|
||||
link,
|
||||
lt_settings,
|
||||
dpcd_lane_status,
|
||||
&dpcd_lane_status_updated,
|
||||
dpcd_lane_adjust,
|
||||
DPRX);
|
||||
if (status != DC_OK) {
|
||||
result = LINK_TRAINING_ABORT;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check if clock recovery successful. */
|
||||
if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
|
||||
result = LINK_TRAINING_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
result = dp_get_cr_failure(lane_count, dpcd_lane_status);
|
||||
|
||||
if (dp_is_max_vs_reached(lt_settings))
|
||||
break;
|
||||
|
||||
/* Count number of attempts with same drive settings.
|
||||
* Note: settings are the same for all lanes,
|
||||
* so comparing first lane is sufficient.
|
||||
*/
|
||||
if ((lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
|
||||
dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
|
||||
&& (lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET ==
|
||||
dpcd_lane_adjust[0].bits.PRE_EMPHASIS_LANE))
|
||||
retries_cr++;
|
||||
else
|
||||
retries_cr = 0;
|
||||
|
||||
/* Update VS/PE. */
|
||||
dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
|
||||
lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
|
||||
retry_count++;
|
||||
}
|
||||
|
||||
/* Abort link training if clock recovery failed due to HPD unplug. */
|
||||
if (link->is_hpd_pending)
|
||||
result = LINK_TRAINING_ABORT;
|
||||
|
||||
DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) clock recovery\n"
|
||||
" -hop(%d)\n - result(%d)\n - retries(%d)\n",
|
||||
__func__,
|
||||
link->link_id.enum_id - ENUM_ID_1,
|
||||
DPRX,
|
||||
result,
|
||||
retry_count);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Execute clock recovery phase of link training for specified hop in display
|
||||
* path.
|
||||
*
|
||||
* @param link DPIA link being trained.
|
||||
* @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis).
|
||||
* @param hop The Hop in display path. DPRX = 0.
|
||||
*/
|
||||
static enum link_training_result dpia_training_cr_phase(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
struct link_training_settings *lt_settings,
|
||||
uint32_t hop)
|
||||
{
|
||||
enum link_training_result result = LINK_TRAINING_CR_FAIL_LANE0;
|
||||
|
||||
if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
|
||||
result = dpia_training_cr_non_transparent(link, link_res, lt_settings, hop);
|
||||
else
|
||||
result = dpia_training_cr_transparent(link, link_res, lt_settings);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Return status read interval during equalization phase. */
|
||||
static uint32_t dpia_get_eq_aux_rd_interval(const struct dc_link *link,
|
||||
const struct link_training_settings *lt_settings,
|
||||
uint32_t hop)
|
||||
{
|
||||
uint32_t wait_time_microsec;
|
||||
|
||||
if (hop == DPRX)
|
||||
wait_time_microsec = lt_settings->eq_pattern_time;
|
||||
else
|
||||
wait_time_microsec =
|
||||
dp_translate_training_aux_read_interval(
|
||||
link->dpcd_caps.lttpr_caps.aux_rd_interval[hop - 1]);
|
||||
|
||||
/* Check debug option for extending aux read interval. */
|
||||
if (link->dc->debug.dpia_debug.bits.extend_aux_rd_interval)
|
||||
wait_time_microsec = DPIA_DEBUG_EXTENDED_AUX_RD_INTERVAL_US;
|
||||
|
||||
return wait_time_microsec;
|
||||
}
|
||||
|
||||
/* Execute equalization phase of link training for specified hop in display
|
||||
* path in non-transparent mode:
|
||||
* - driver issues both DPCD and SET_CONFIG transactions.
|
||||
* - TPSx is transmitted for any hops downstream of DPOA.
|
||||
* - Drive (VS/PE) only transmitted for the hop immediately downstream of DPOA.
|
||||
* - EQ for the first hop (DPTX-to-DPIA) is assumed to be successful.
|
||||
* - DPRX EQ only reported successful when both DPRX and DPIA requirements
|
||||
* (clk sync packets sent) fulfilled.
|
||||
*
|
||||
* @param link DPIA link being trained.
|
||||
* @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis).
|
||||
* @param hop The Hop in display path. DPRX = 0.
|
||||
*/
|
||||
static enum link_training_result dpia_training_eq_non_transparent(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
struct link_training_settings *lt_settings,
|
||||
uint32_t hop)
|
||||
{
|
||||
enum link_training_result result = LINK_TRAINING_EQ_FAIL_EQ;
|
||||
uint8_t repeater_cnt = 0; /* Number of hops/repeaters in display path. */
|
||||
uint32_t retries_eq = 0;
|
||||
enum dc_status status;
|
||||
enum dc_dp_training_pattern tr_pattern;
|
||||
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};
|
||||
union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
|
||||
uint8_t set_cfg_data;
|
||||
enum dpia_set_config_ts ts;
|
||||
|
||||
/* Training pattern is TPS4 for repeater;
|
||||
* TPS2/3/4 for DPRX depending on what it supports.
|
||||
*/
|
||||
if (hop == DPRX)
|
||||
tr_pattern = lt_settings->pattern_for_eq;
|
||||
else
|
||||
tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
|
||||
|
||||
repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
|
||||
|
||||
for (retries_eq = 0; retries_eq < LINK_TRAINING_MAX_RETRY_COUNT; retries_eq++) {
|
||||
/* DPTX-to-DPIA equalization always successful. */
|
||||
if (hop == repeater_cnt) {
|
||||
result = LINK_TRAINING_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Instruct DPOA to transmit TPSn then update DPCD. */
|
||||
if (retries_eq == 0) {
|
||||
status = convert_trng_ptn_to_trng_stg(tr_pattern, &ts);
|
||||
if (status != DC_OK) {
|
||||
result = LINK_TRAINING_ABORT;
|
||||
break;
|
||||
}
|
||||
status = core_link_send_set_config(link,
|
||||
DPIA_SET_CFG_SET_TRAINING,
|
||||
ts);
|
||||
if (status != DC_OK) {
|
||||
result = LINK_TRAINING_ABORT;
|
||||
break;
|
||||
}
|
||||
status = dpcd_set_lt_pattern(link, tr_pattern, hop);
|
||||
if (status != DC_OK) {
|
||||
result = LINK_TRAINING_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update DPOA drive settings then DPCD. DPOA only adjusts
|
||||
* drive settings for hop immediately downstream.
|
||||
*/
|
||||
if (hop == repeater_cnt - 1) {
|
||||
set_cfg_data = dpia_build_set_config_data(DPIA_SET_CFG_SET_VSPE,
|
||||
link,
|
||||
lt_settings);
|
||||
status = core_link_send_set_config(link,
|
||||
DPIA_SET_CFG_SET_VSPE,
|
||||
set_cfg_data);
|
||||
if (status != DC_OK) {
|
||||
result = LINK_TRAINING_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
status = dpcd_set_lane_settings(link, lt_settings, hop);
|
||||
if (status != DC_OK) {
|
||||
result = LINK_TRAINING_ABORT;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Extend wait time on second equalisation attempt on final hop to
|
||||
* ensure clock sync packets have been sent.
|
||||
*/
|
||||
if (hop == DPRX && retries_eq == 1)
|
||||
wait_time_microsec = max(wait_time_microsec, (uint32_t)DPIA_CLK_SYNC_DELAY);
|
||||
else
|
||||
wait_time_microsec = dpia_get_eq_aux_rd_interval(link, lt_settings, hop);
|
||||
|
||||
dp_wait_for_training_aux_rd_interval(link, wait_time_microsec);
|
||||
|
||||
/* Read status and adjustment requests from DPCD. */
|
||||
status = dp_get_lane_status_and_lane_adjust(
|
||||
link,
|
||||
lt_settings,
|
||||
dpcd_lane_status,
|
||||
&dpcd_lane_status_updated,
|
||||
dpcd_lane_adjust,
|
||||
hop);
|
||||
if (status != DC_OK) {
|
||||
result = LINK_TRAINING_ABORT;
|
||||
break;
|
||||
}
|
||||
|
||||
/* CR can still fail during EQ phase. Fail training if CR fails. */
|
||||
if (!dp_is_cr_done(lane_count, dpcd_lane_status)) {
|
||||
result = LINK_TRAINING_EQ_FAIL_CR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
|
||||
dp_is_symbol_locked(link->cur_link_settings.lane_count, dpcd_lane_status) &&
|
||||
dp_is_interlane_aligned(dpcd_lane_status_updated)) {
|
||||
result = LINK_TRAINING_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Update VS/PE. */
|
||||
dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
|
||||
lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
|
||||
}
|
||||
|
||||
/* Abort link training if equalization failed due to HPD unplug. */
|
||||
if (link->is_hpd_pending)
|
||||
result = LINK_TRAINING_ABORT;
|
||||
|
||||
DC_LOG_HW_LINK_TRAINING(
|
||||
"%s\n DPIA(%d) equalization\n - hop(%d)\n - result(%d)\n - retries(%d)\n - status(%d)\n",
|
||||
__func__,
|
||||
link->link_id.enum_id - ENUM_ID_1,
|
||||
hop,
|
||||
result,
|
||||
retries_eq,
|
||||
status);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Execute equalization phase of link training for specified hop in display
|
||||
* path in transparent LTTPR mode:
|
||||
* - driver only issues DPCD transactions leaves USB4 tunneling (SET_CONFIG) messages to DPIA.
|
||||
* - driver writes TPSx to DPCD to notify DPIA that is in equalization phase.
|
||||
* - equalization (EQ) for link is handled by DPOA, which reports result to DPIA on completion.
|
||||
* - DPIA communicates result to driver by updating EQ status when driver reads DPCD.
|
||||
*
|
||||
* @param link DPIA link being trained.
|
||||
* @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis).
|
||||
* @param hop The Hop in display path. DPRX = 0.
|
||||
*/
|
||||
static enum link_training_result dpia_training_eq_transparent(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
struct link_training_settings *lt_settings)
|
||||
{
|
||||
enum link_training_result result = LINK_TRAINING_EQ_FAIL_EQ;
|
||||
uint32_t retries_eq = 0;
|
||||
enum dc_status status;
|
||||
enum dc_dp_training_pattern tr_pattern = lt_settings->pattern_for_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};
|
||||
union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
|
||||
|
||||
wait_time_microsec = dpia_get_eq_aux_rd_interval(link, lt_settings, DPRX);
|
||||
|
||||
for (retries_eq = 0; retries_eq < LINK_TRAINING_MAX_RETRY_COUNT; retries_eq++) {
|
||||
if (retries_eq == 0) {
|
||||
status = dpcd_set_lt_pattern(link, tr_pattern, DPRX);
|
||||
if (status != DC_OK) {
|
||||
result = LINK_TRAINING_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dp_wait_for_training_aux_rd_interval(link, wait_time_microsec);
|
||||
|
||||
/* Read status and adjustment requests from DPCD. */
|
||||
status = dp_get_lane_status_and_lane_adjust(
|
||||
link,
|
||||
lt_settings,
|
||||
dpcd_lane_status,
|
||||
&dpcd_lane_status_updated,
|
||||
dpcd_lane_adjust,
|
||||
DPRX);
|
||||
if (status != DC_OK) {
|
||||
result = LINK_TRAINING_ABORT;
|
||||
break;
|
||||
}
|
||||
|
||||
/* CR can still fail during EQ phase. Fail training if CR fails. */
|
||||
if (!dp_is_cr_done(lane_count, dpcd_lane_status)) {
|
||||
result = LINK_TRAINING_EQ_FAIL_CR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
|
||||
dp_is_symbol_locked(link->cur_link_settings.lane_count, dpcd_lane_status)) {
|
||||
/* Take into consideration corner case for DP 1.4a LL Compliance CTS as USB4
|
||||
* has to share encoders unlike DP and USBC
|
||||
*/
|
||||
if (dp_is_interlane_aligned(dpcd_lane_status_updated) || (link->is_automated && retries_eq)) {
|
||||
result = LINK_TRAINING_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update VS/PE. */
|
||||
dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
|
||||
lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
|
||||
}
|
||||
|
||||
/* Abort link training if equalization failed due to HPD unplug. */
|
||||
if (link->is_hpd_pending)
|
||||
result = LINK_TRAINING_ABORT;
|
||||
|
||||
DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) equalization\n"
|
||||
" - hop(%d)\n - result(%d)\n - retries(%d)\n",
|
||||
__func__,
|
||||
link->link_id.enum_id - ENUM_ID_1,
|
||||
DPRX,
|
||||
result,
|
||||
retries_eq);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Execute equalization phase of link training for specified hop in display
|
||||
* path.
|
||||
*
|
||||
* @param link DPIA link being trained.
|
||||
* @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis).
|
||||
* @param hop The Hop in display path. DPRX = 0.
|
||||
*/
|
||||
static enum link_training_result dpia_training_eq_phase(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
struct link_training_settings *lt_settings,
|
||||
uint32_t hop)
|
||||
{
|
||||
enum link_training_result result;
|
||||
|
||||
if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
|
||||
result = dpia_training_eq_non_transparent(link, link_res, lt_settings, hop);
|
||||
else
|
||||
result = dpia_training_eq_transparent(link, link_res, lt_settings);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* End training of specified hop in display path. */
|
||||
static enum dc_status dpcd_clear_lt_pattern(struct dc_link *link, uint32_t hop)
|
||||
{
|
||||
union dpcd_training_pattern dpcd_pattern = {0};
|
||||
uint32_t dpcd_tps_offset = DP_TRAINING_PATTERN_SET;
|
||||
enum dc_status status;
|
||||
|
||||
if (hop != DPRX)
|
||||
dpcd_tps_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
|
||||
((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (hop - 1));
|
||||
|
||||
status = core_link_write_dpcd(link,
|
||||
dpcd_tps_offset,
|
||||
&dpcd_pattern.raw,
|
||||
sizeof(dpcd_pattern.raw));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* End training of specified hop in display path.
|
||||
*
|
||||
* In transparent LTTPR mode:
|
||||
* - driver clears training pattern for the specified hop in DPCD.
|
||||
* In non-transparent LTTPR mode:
|
||||
* - in addition to clearing training pattern, driver issues USB4 tunneling
|
||||
* (SET_CONFIG) messages to notify DPOA when training is done for first hop
|
||||
* (DPTX-to-DPIA) and last hop (DPRX).
|
||||
*
|
||||
* @param link DPIA link being trained.
|
||||
* @param hop The Hop in display path. DPRX = 0.
|
||||
*/
|
||||
static enum link_training_result dpia_training_end(struct dc_link *link,
|
||||
struct link_training_settings *lt_settings,
|
||||
uint32_t hop)
|
||||
{
|
||||
enum link_training_result result = LINK_TRAINING_SUCCESS;
|
||||
uint8_t repeater_cnt = 0; /* Number of hops/repeaters in display path. */
|
||||
enum dc_status status;
|
||||
|
||||
if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
|
||||
repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
|
||||
|
||||
if (hop == repeater_cnt) { /* DPTX-to-DPIA */
|
||||
/* Send SET_CONFIG(SET_TRAINING:0xff) to notify DPOA that
|
||||
* DPTX-to-DPIA hop trained. No DPCD write needed for first hop.
|
||||
*/
|
||||
status = core_link_send_set_config(link,
|
||||
DPIA_SET_CFG_SET_TRAINING,
|
||||
DPIA_TS_UFP_DONE);
|
||||
if (status != DC_OK)
|
||||
result = LINK_TRAINING_ABORT;
|
||||
} else { /* DPOA-to-x */
|
||||
/* Write 0x0 to TRAINING_PATTERN_SET */
|
||||
status = dpcd_clear_lt_pattern(link, hop);
|
||||
if (status != DC_OK)
|
||||
result = LINK_TRAINING_ABORT;
|
||||
}
|
||||
|
||||
/* Notify DPOA that non-transparent link training of DPRX done. */
|
||||
if (hop == DPRX && result != LINK_TRAINING_ABORT) {
|
||||
status = core_link_send_set_config(link,
|
||||
DPIA_SET_CFG_SET_TRAINING,
|
||||
DPIA_TS_DPRX_DONE);
|
||||
if (status != DC_OK)
|
||||
result = LINK_TRAINING_ABORT;
|
||||
}
|
||||
|
||||
} else { /* non-LTTPR or transparent LTTPR. */
|
||||
/* Write 0x0 to TRAINING_PATTERN_SET */
|
||||
status = dpcd_clear_lt_pattern(link, hop);
|
||||
if (status != DC_OK)
|
||||
result = LINK_TRAINING_ABORT;
|
||||
}
|
||||
|
||||
DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) end\n - hop(%d)\n - result(%d)\n - LTTPR mode(%d)\n",
|
||||
__func__,
|
||||
link->link_id.enum_id - ENUM_ID_1,
|
||||
hop,
|
||||
result,
|
||||
lt_settings->lttpr_mode);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* When aborting training of specified hop in display path, clean up by:
|
||||
* - Attempting to clear DPCD TRAINING_PATTERN_SET, LINK_BW_SET and LANE_COUNT_SET.
|
||||
* - Sending SET_CONFIG(SET_LINK) with lane count and link rate set to 0.
|
||||
*
|
||||
* @param link DPIA link being trained.
|
||||
* @param hop The Hop in display path. DPRX = 0.
|
||||
*/
|
||||
static void dpia_training_abort(struct dc_link *link,
|
||||
struct link_training_settings *lt_settings,
|
||||
uint32_t hop)
|
||||
{
|
||||
uint8_t data = 0;
|
||||
uint32_t dpcd_tps_offset = DP_TRAINING_PATTERN_SET;
|
||||
|
||||
DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) aborting\n - LTTPR mode(%d)\n - HPD(%d)\n",
|
||||
__func__,
|
||||
link->link_id.enum_id - ENUM_ID_1,
|
||||
lt_settings->lttpr_mode,
|
||||
link->is_hpd_pending);
|
||||
|
||||
/* Abandon clean-up if sink unplugged. */
|
||||
if (link->is_hpd_pending)
|
||||
return;
|
||||
|
||||
if (hop != DPRX)
|
||||
dpcd_tps_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
|
||||
((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (hop - 1));
|
||||
|
||||
core_link_write_dpcd(link, dpcd_tps_offset, &data, 1);
|
||||
core_link_write_dpcd(link, DP_LINK_BW_SET, &data, 1);
|
||||
core_link_write_dpcd(link, DP_LANE_COUNT_SET, &data, 1);
|
||||
core_link_send_set_config(link, DPIA_SET_CFG_SET_LINK, data);
|
||||
}
|
||||
|
||||
enum link_training_result dc_link_dpia_perform_link_training(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
const struct dc_link_settings *link_setting,
|
||||
bool skip_video_pattern)
|
||||
{
|
||||
enum link_training_result result;
|
||||
struct link_training_settings lt_settings = {0};
|
||||
uint8_t repeater_cnt = 0; /* Number of hops/repeaters in display path. */
|
||||
int8_t repeater_id; /* Current hop. */
|
||||
|
||||
struct dc_link_settings link_settings = *link_setting; // non-const copy to pass in
|
||||
|
||||
lt_settings.lttpr_mode = dp_decide_lttpr_mode(link, &link_settings);
|
||||
|
||||
/* Configure link as prescribed in link_setting and set LTTPR mode. */
|
||||
result = dpia_configure_link(link, link_res, link_setting, <_settings);
|
||||
if (result != LINK_TRAINING_SUCCESS)
|
||||
return result;
|
||||
|
||||
if (lt_settings.lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
|
||||
repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
|
||||
|
||||
/* Train each hop in turn starting with the one closest to DPTX.
|
||||
* In transparent or non-LTTPR mode, train only the final hop (DPRX).
|
||||
*/
|
||||
for (repeater_id = repeater_cnt; repeater_id >= 0; repeater_id--) {
|
||||
/* Clock recovery. */
|
||||
result = dpia_training_cr_phase(link, link_res, <_settings, repeater_id);
|
||||
if (result != LINK_TRAINING_SUCCESS)
|
||||
break;
|
||||
|
||||
/* Equalization. */
|
||||
result = dpia_training_eq_phase(link, link_res, <_settings, repeater_id);
|
||||
if (result != LINK_TRAINING_SUCCESS)
|
||||
break;
|
||||
|
||||
/* Stop training hop. */
|
||||
result = dpia_training_end(link, <_settings, repeater_id);
|
||||
if (result != LINK_TRAINING_SUCCESS)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Double-check link status if training successful; gracefully abort
|
||||
* training of current hop if training failed due to message tunneling
|
||||
* failure; end training of hop if training ended conventionally and
|
||||
* falling back to lower bandwidth settings possible.
|
||||
*/
|
||||
if (result == LINK_TRAINING_SUCCESS) {
|
||||
msleep(5);
|
||||
if (!link->is_automated)
|
||||
result = dp_check_link_loss_status(link, <_settings);
|
||||
} else if (result == LINK_TRAINING_ABORT) {
|
||||
dpia_training_abort(link, <_settings, repeater_id);
|
||||
} else {
|
||||
dpia_training_end(link, <_settings, repeater_id);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -28,57 +28,6 @@
|
||||
#define __DC_LINK_DPIA_H__
|
||||
|
||||
#include "link.h"
|
||||
/* This module implements functionality for training DPIA links. */
|
||||
|
||||
/* The approximate time (us) it takes to transmit 9 USB4 DP clock sync packets. */
|
||||
#define DPIA_CLK_SYNC_DELAY 16000
|
||||
|
||||
/* Extend interval between training status checks for manual testing. */
|
||||
#define DPIA_DEBUG_EXTENDED_AUX_RD_INTERVAL_US 60000000
|
||||
|
||||
/** @note Can remove once DP tunneling registers in upstream include/drm/drm_dp_helper.h */
|
||||
/* DPCD DP Tunneling over USB4 */
|
||||
#define DP_TUNNELING_CAPABILITIES_SUPPORT 0xe000d
|
||||
#define DP_IN_ADAPTER_INFO 0xe000e
|
||||
#define DP_USB4_DRIVER_ID 0xe000f
|
||||
#define DP_USB4_ROUTER_TOPOLOGY_ID 0xe001b
|
||||
|
||||
/* SET_CONFIG message types sent by driver. */
|
||||
enum dpia_set_config_type {
|
||||
DPIA_SET_CFG_SET_LINK = 0x01,
|
||||
DPIA_SET_CFG_SET_PHY_TEST_MODE = 0x05,
|
||||
DPIA_SET_CFG_SET_TRAINING = 0x18,
|
||||
DPIA_SET_CFG_SET_VSPE = 0x19
|
||||
};
|
||||
|
||||
/* Training stages (TS) in SET_CONFIG(SET_TRAINING) message. */
|
||||
enum dpia_set_config_ts {
|
||||
DPIA_TS_DPRX_DONE = 0x00, /* Done training DPRX. */
|
||||
DPIA_TS_TPS1 = 0x01,
|
||||
DPIA_TS_TPS2 = 0x02,
|
||||
DPIA_TS_TPS3 = 0x03,
|
||||
DPIA_TS_TPS4 = 0x07,
|
||||
DPIA_TS_UFP_DONE = 0xff /* Done training DPTX-to-DPIA hop. */
|
||||
};
|
||||
|
||||
/* SET_CONFIG message data associated with messages sent by driver. */
|
||||
union dpia_set_config_data {
|
||||
struct {
|
||||
uint8_t mode : 1;
|
||||
uint8_t reserved : 7;
|
||||
} set_link;
|
||||
struct {
|
||||
uint8_t stage;
|
||||
} set_training;
|
||||
struct {
|
||||
uint8_t swing : 2;
|
||||
uint8_t max_swing_reached : 1;
|
||||
uint8_t pre_emph : 2;
|
||||
uint8_t max_pre_emph_reached : 1;
|
||||
uint8_t reserved : 2;
|
||||
} set_vspe;
|
||||
uint8_t raw;
|
||||
};
|
||||
|
||||
/* Read tunneling device capability from DPCD and update link capability
|
||||
* accordingly.
|
||||
@ -90,14 +39,5 @@ enum dc_status dpcd_get_tunneling_device_data(struct dc_link *link);
|
||||
*/
|
||||
bool dc_link_dpia_query_hpd_status(struct dc_link *link);
|
||||
|
||||
/* Train DP tunneling link for USB4 DPIA display endpoint.
|
||||
* DPIA equivalent of dc_link_dp_perfrorm_link_training.
|
||||
* Aborts link training upon detection of sink unplug.
|
||||
*/
|
||||
enum link_training_result dc_link_dpia_perform_link_training(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
const struct dc_link_settings *link_setting,
|
||||
bool skip_video_pattern);
|
||||
|
||||
#endif /* __DC_LINK_DPIA_H__ */
|
||||
|
1698
drivers/gpu/drm/amd/display/dc/link/link_dp_training.c
Normal file
1698
drivers/gpu/drm/amd/display/dc/link/link_dp_training.c
Normal file
File diff suppressed because it is too large
Load Diff
179
drivers/gpu/drm/amd/display/dc/link/link_dp_training.h
Normal file
179
drivers/gpu/drm/amd/display/dc/link/link_dp_training.h
Normal file
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright 2022 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: AMD
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __DC_LINK_DP_TRAINING_H__
|
||||
#define __DC_LINK_DP_TRAINING_H__
|
||||
#include "link.h"
|
||||
|
||||
bool perform_link_training_with_retries(
|
||||
const struct dc_link_settings *link_setting,
|
||||
bool skip_video_pattern,
|
||||
int attempts,
|
||||
struct pipe_ctx *pipe_ctx,
|
||||
enum signal_type signal,
|
||||
bool do_fallback);
|
||||
|
||||
enum link_training_result dp_perform_link_training(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
const struct dc_link_settings *link_settings,
|
||||
bool skip_video_pattern);
|
||||
|
||||
bool dp_set_hw_training_pattern(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
enum dc_dp_training_pattern pattern,
|
||||
uint32_t offset);
|
||||
|
||||
void dp_set_hw_test_pattern(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
enum dp_test_pattern test_pattern,
|
||||
uint8_t *custom_pattern,
|
||||
uint32_t custom_pattern_size);
|
||||
|
||||
void dpcd_set_training_pattern(
|
||||
struct dc_link *link,
|
||||
enum dc_dp_training_pattern training_pattern);
|
||||
|
||||
/* Write DPCD drive settings. */
|
||||
enum dc_status dpcd_set_lane_settings(
|
||||
struct dc_link *link,
|
||||
const struct link_training_settings *link_training_setting,
|
||||
uint32_t offset);
|
||||
|
||||
/* Write DPCD link configuration data. */
|
||||
enum dc_status dpcd_set_link_settings(
|
||||
struct dc_link *link,
|
||||
const struct link_training_settings *lt_settings);
|
||||
|
||||
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,
|
||||
uint32_t offset);
|
||||
|
||||
/* Read training status and adjustment requests from DPCD. */
|
||||
enum dc_status dp_get_lane_status_and_lane_adjust(
|
||||
struct dc_link *link,
|
||||
const struct link_training_settings *link_training_setting,
|
||||
union lane_status ln_status[LANE_COUNT_DP_MAX],
|
||||
union lane_align_status_updated *ln_align,
|
||||
union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
|
||||
uint32_t offset);
|
||||
|
||||
enum dc_status dpcd_configure_lttpr_mode(
|
||||
struct dc_link *link,
|
||||
struct link_training_settings *lt_settings);
|
||||
|
||||
enum dc_status configure_lttpr_mode_transparent(struct dc_link *link);
|
||||
|
||||
enum dc_status dpcd_configure_channel_coding(
|
||||
struct dc_link *link,
|
||||
struct link_training_settings *lt_settings);
|
||||
|
||||
void repeater_training_done(struct dc_link *link, uint32_t offset);
|
||||
|
||||
void start_clock_recovery_pattern_early(struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
struct link_training_settings *lt_settings,
|
||||
uint32_t offset);
|
||||
|
||||
void dp_decide_training_settings(
|
||||
struct dc_link *link,
|
||||
const struct dc_link_settings *link_settings,
|
||||
struct link_training_settings *lt_settings);
|
||||
|
||||
void dp_decide_lane_settings(
|
||||
const struct link_training_settings *lt_settings,
|
||||
const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
|
||||
struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
|
||||
union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX]);
|
||||
|
||||
enum dc_dp_training_pattern decide_cr_training_pattern(
|
||||
const struct dc_link_settings *link_settings);
|
||||
|
||||
enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *link,
|
||||
const struct dc_link_settings *link_settings);
|
||||
|
||||
void dp_get_lttpr_mode_override(struct dc_link *link,
|
||||
enum lttpr_mode *override);
|
||||
|
||||
void override_training_settings(
|
||||
struct dc_link *link,
|
||||
const struct dc_link_training_overrides *overrides,
|
||||
struct link_training_settings *lt_settings);
|
||||
|
||||
/* Check DPCD training status registers to detect link loss. */
|
||||
enum link_training_result dp_check_link_loss_status(
|
||||
struct dc_link *link,
|
||||
const struct link_training_settings *link_training_setting);
|
||||
|
||||
bool dp_is_cr_done(enum dc_lane_count ln_count,
|
||||
union lane_status *dpcd_lane_status);
|
||||
|
||||
bool dp_is_ch_eq_done(enum dc_lane_count ln_count,
|
||||
union lane_status *dpcd_lane_status);
|
||||
bool dp_is_symbol_locked(enum dc_lane_count ln_count,
|
||||
union lane_status *dpcd_lane_status);
|
||||
bool dp_is_interlane_aligned(union lane_align_status_updated align_status);
|
||||
|
||||
bool is_repeater(const struct link_training_settings *lt_settings, uint32_t offset);
|
||||
|
||||
bool dp_is_max_vs_reached(
|
||||
const struct link_training_settings *lt_settings);
|
||||
|
||||
uint8_t get_dpcd_link_rate(const struct dc_link_settings *link_settings);
|
||||
|
||||
enum link_training_result dp_get_cr_failure(enum dc_lane_count ln_count,
|
||||
union lane_status *dpcd_lane_status);
|
||||
|
||||
void dp_hw_to_dpcd_lane_settings(
|
||||
const struct link_training_settings *lt_settings,
|
||||
const struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
|
||||
union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX]);
|
||||
|
||||
void dp_wait_for_training_aux_rd_interval(
|
||||
struct dc_link *link,
|
||||
uint32_t wait_in_micro_secs);
|
||||
|
||||
enum dpcd_training_patterns
|
||||
dp_training_pattern_to_dpcd_training_pattern(
|
||||
struct dc_link *link,
|
||||
enum dc_dp_training_pattern pattern);
|
||||
|
||||
uint8_t dp_initialize_scrambling_data_symbols(
|
||||
struct dc_link *link,
|
||||
enum dc_dp_training_pattern pattern);
|
||||
|
||||
void dp_log_training_result(
|
||||
struct dc_link *link,
|
||||
const struct link_training_settings *lt_settings,
|
||||
enum link_training_result status);
|
||||
|
||||
uint32_t dp_translate_training_aux_read_interval(
|
||||
uint32_t dpcd_aux_read_interval);
|
||||
#endif /* __DC_LINK_DP_TRAINING_H__ */
|
258
drivers/gpu/drm/amd/display/dc/link/link_dp_training_128b_132b.c
Normal file
258
drivers/gpu/drm/amd/display/dc/link/link_dp_training_128b_132b.c
Normal file
@ -0,0 +1,258 @@
|
||||
/*
|
||||
* Copyright 2022 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: AMD
|
||||
*
|
||||
*/
|
||||
|
||||
/* FILE POLICY AND INTENDED USAGE:
|
||||
* This file implements dp 128b/132b link training software policies and
|
||||
* sequences.
|
||||
*/
|
||||
#include "link_dp_training_128b_132b.h"
|
||||
#include "link_dp_training_8b_10b.h"
|
||||
#include "link_dpcd.h"
|
||||
#include "dc_link_dp.h"
|
||||
|
||||
#define DC_LOGGER \
|
||||
link->ctx->logger
|
||||
|
||||
static enum dc_status dpcd_128b_132b_set_lane_settings(
|
||||
struct dc_link *link,
|
||||
const struct link_training_settings *link_training_setting)
|
||||
{
|
||||
enum dc_status status = core_link_write_dpcd(link,
|
||||
DP_TRAINING_LANE0_SET,
|
||||
(uint8_t *)(link_training_setting->dpcd_lane_settings),
|
||||
sizeof(link_training_setting->dpcd_lane_settings));
|
||||
|
||||
DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n",
|
||||
__func__,
|
||||
DP_TRAINING_LANE0_SET,
|
||||
link_training_setting->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
|
||||
return status;
|
||||
}
|
||||
|
||||
static void dpcd_128b_132b_get_aux_rd_interval(struct dc_link *link,
|
||||
uint32_t *interval_in_us)
|
||||
{
|
||||
union dp_128b_132b_training_aux_rd_interval dpcd_interval;
|
||||
uint32_t interval_unit = 0;
|
||||
|
||||
dpcd_interval.raw = 0;
|
||||
core_link_read_dpcd(link, DP_128B132B_TRAINING_AUX_RD_INTERVAL,
|
||||
&dpcd_interval.raw, sizeof(dpcd_interval.raw));
|
||||
interval_unit = dpcd_interval.bits.UNIT ? 1 : 2; /* 0b = 2 ms, 1b = 1 ms */
|
||||
/* (128b/132b_TRAINING_AUX_RD_INTERVAL value + 1) *
|
||||
* INTERVAL_UNIT. The maximum is 256 ms
|
||||
*/
|
||||
*interval_in_us = (dpcd_interval.bits.VALUE + 1) * interval_unit * 1000;
|
||||
}
|
||||
|
||||
static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
struct link_training_settings *lt_settings)
|
||||
{
|
||||
uint8_t loop_count;
|
||||
uint32_t aux_rd_interval = 0;
|
||||
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};
|
||||
union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
|
||||
enum dc_status status = DC_OK;
|
||||
enum link_training_result result = LINK_TRAINING_SUCCESS;
|
||||
|
||||
/* Transmit 128b/132b_TPS1 over Main-Link */
|
||||
dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, DPRX);
|
||||
|
||||
/* Set TRAINING_PATTERN_SET to 01h */
|
||||
dpcd_set_training_pattern(link, lt_settings->pattern_for_cr);
|
||||
|
||||
/* Adjust TX_FFE_PRESET_VALUE and Transmit 128b/132b_TPS2 over Main-Link */
|
||||
dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval);
|
||||
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);
|
||||
dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX);
|
||||
dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_eq, DPRX);
|
||||
|
||||
/* Set loop counter to start from 1 */
|
||||
loop_count = 1;
|
||||
|
||||
/* Set TRAINING_PATTERN_SET to 02h and TX_FFE_PRESET_VALUE in one AUX transaction */
|
||||
dpcd_set_lt_pattern_and_lane_settings(link, lt_settings,
|
||||
lt_settings->pattern_for_eq, DPRX);
|
||||
|
||||
/* poll for channel EQ done */
|
||||
while (result == LINK_TRAINING_SUCCESS) {
|
||||
dp_wait_for_training_aux_rd_interval(link, aux_rd_interval);
|
||||
wait_time += aux_rd_interval;
|
||||
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 (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) {
|
||||
result = DP_128b_132b_MAX_LOOP_COUNT_REACHED;
|
||||
} else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) {
|
||||
result = DP_128b_132b_LT_FAILED;
|
||||
} else {
|
||||
dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX);
|
||||
dpcd_128b_132b_set_lane_settings(link, lt_settings);
|
||||
}
|
||||
loop_count++;
|
||||
}
|
||||
|
||||
/* poll for EQ interlane align done */
|
||||
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) {
|
||||
result = DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT;
|
||||
} else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) {
|
||||
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;
|
||||
status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
|
||||
&dpcd_lane_status_updated, dpcd_lane_adjust, DPRX);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static enum link_training_result dp_perform_128b_132b_cds_done_sequence(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
struct link_training_settings *lt_settings)
|
||||
{
|
||||
/* Assumption: assume hardware has transmitted eq pattern */
|
||||
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};
|
||||
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 (result == LINK_TRAINING_SUCCESS) {
|
||||
dp_wait_for_training_aux_rd_interval(link,
|
||||
lt_settings->cds_pattern_time);
|
||||
wait_time += lt_settings->cds_pattern_time;
|
||||
status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
|
||||
&dpcd_lane_status_updated, dpcd_lane_adjust, DPRX);
|
||||
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) {
|
||||
result = DP_128b_132b_LT_FAILED;
|
||||
} else if (wait_time >= lt_settings->cds_wait_time_limit) {
|
||||
result = DP_128b_132b_CDS_DONE_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
enum link_training_result dp_perform_128b_132b_link_training(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
struct link_training_settings *lt_settings)
|
||||
{
|
||||
enum link_training_result result = LINK_TRAINING_SUCCESS;
|
||||
|
||||
/* TODO - DP2.0 Link: remove legacy_dp2_lt logic */
|
||||
if (link->dc->debug.legacy_dp2_lt) {
|
||||
struct link_training_settings legacy_settings;
|
||||
|
||||
decide_8b_10b_training_settings(link,
|
||||
<_settings->link_settings,
|
||||
&legacy_settings);
|
||||
return dp_perform_8b_10b_link_training(link, link_res, &legacy_settings);
|
||||
}
|
||||
|
||||
dpcd_set_link_settings(link, lt_settings);
|
||||
|
||||
if (result == LINK_TRAINING_SUCCESS)
|
||||
result = dp_perform_128b_132b_channel_eq_done_sequence(link, link_res, lt_settings);
|
||||
|
||||
if (result == LINK_TRAINING_SUCCESS)
|
||||
result = dp_perform_128b_132b_cds_done_sequence(link, link_res, lt_settings);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void decide_128b_132b_training_settings(struct dc_link *link,
|
||||
const struct dc_link_settings *link_settings,
|
||||
struct link_training_settings *lt_settings)
|
||||
{
|
||||
memset(lt_settings, 0, sizeof(*lt_settings));
|
||||
|
||||
lt_settings->link_settings = *link_settings;
|
||||
/* TODO: should decide link spread when populating link_settings */
|
||||
lt_settings->link_settings.link_spread = link->dp_ss_off ? LINK_SPREAD_DISABLED :
|
||||
LINK_SPREAD_05_DOWNSPREAD_30KHZ;
|
||||
|
||||
lt_settings->pattern_for_cr = decide_cr_training_pattern(link_settings);
|
||||
lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_settings);
|
||||
lt_settings->eq_pattern_time = 2500;
|
||||
lt_settings->eq_wait_time_limit = 400000;
|
||||
lt_settings->eq_loop_count_limit = 20;
|
||||
lt_settings->pattern_for_cds = DP_128b_132b_TPS2_CDS;
|
||||
lt_settings->cds_pattern_time = 2500;
|
||||
lt_settings->cds_wait_time_limit = (dp_convert_to_count(
|
||||
link->dpcd_caps.lttpr_caps.phy_repeater_cnt) + 1) * 20000;
|
||||
lt_settings->disallow_per_lane_settings = true;
|
||||
lt_settings->lttpr_mode = dp_decide_128b_132b_lttpr_mode(link);
|
||||
dp_hw_to_dpcd_lane_settings(lt_settings,
|
||||
lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
|
||||
}
|
||||
|
||||
enum lttpr_mode dp_decide_128b_132b_lttpr_mode(struct dc_link *link)
|
||||
{
|
||||
enum lttpr_mode mode = LTTPR_MODE_NON_LTTPR;
|
||||
|
||||
if (dp_is_lttpr_present(link))
|
||||
mode = LTTPR_MODE_NON_TRANSPARENT;
|
||||
|
||||
DC_LOG_DC("128b_132b chose LTTPR_MODE %d.\n", mode);
|
||||
return mode;
|
||||
}
|
||||
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2022 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: AMD
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __DC_LINK_DP_TRAINING_128B_132B_H__
|
||||
#define __DC_LINK_DP_TRAINING_128B_132B_H__
|
||||
#include "link_dp_training.h"
|
||||
|
||||
enum link_training_result dp_perform_128b_132b_link_training(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
struct link_training_settings *lt_settings);
|
||||
|
||||
void decide_128b_132b_training_settings(struct dc_link *link,
|
||||
const struct dc_link_settings *link_settings,
|
||||
struct link_training_settings *lt_settings);
|
||||
|
||||
enum lttpr_mode dp_decide_128b_132b_lttpr_mode(struct dc_link *link);
|
||||
|
||||
#endif /* __DC_LINK_DP_TRAINING_128B_132B_H__ */
|
413
drivers/gpu/drm/amd/display/dc/link/link_dp_training_8b_10b.c
Normal file
413
drivers/gpu/drm/amd/display/dc/link/link_dp_training_8b_10b.c
Normal file
@ -0,0 +1,413 @@
|
||||
/*
|
||||
* Copyright 2022 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: AMD
|
||||
*
|
||||
*/
|
||||
|
||||
/* FILE POLICY AND INTENDED USAGE:
|
||||
* This file implements dp 8b/10b link training software policies and
|
||||
* sequences.
|
||||
*/
|
||||
#include "link_dp_training_8b_10b.h"
|
||||
#include "link_dpcd.h"
|
||||
#include "dc_link_dp.h"
|
||||
|
||||
#define DC_LOGGER \
|
||||
link->ctx->logger
|
||||
|
||||
static int32_t get_cr_training_aux_rd_interval(struct dc_link *link,
|
||||
const struct dc_link_settings *link_settings)
|
||||
{
|
||||
union training_aux_rd_interval training_rd_interval;
|
||||
uint32_t wait_in_micro_secs = 100;
|
||||
|
||||
memset(&training_rd_interval, 0, sizeof(training_rd_interval));
|
||||
if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING &&
|
||||
link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) {
|
||||
core_link_read_dpcd(
|
||||
link,
|
||||
DP_TRAINING_AUX_RD_INTERVAL,
|
||||
(uint8_t *)&training_rd_interval,
|
||||
sizeof(training_rd_interval));
|
||||
if (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL)
|
||||
wait_in_micro_secs = training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000;
|
||||
}
|
||||
return wait_in_micro_secs;
|
||||
}
|
||||
|
||||
static uint32_t get_eq_training_aux_rd_interval(
|
||||
struct dc_link *link,
|
||||
const struct dc_link_settings *link_settings)
|
||||
{
|
||||
union training_aux_rd_interval training_rd_interval;
|
||||
|
||||
memset(&training_rd_interval, 0, sizeof(training_rd_interval));
|
||||
if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
|
||||
core_link_read_dpcd(
|
||||
link,
|
||||
DP_128B132B_TRAINING_AUX_RD_INTERVAL,
|
||||
(uint8_t *)&training_rd_interval,
|
||||
sizeof(training_rd_interval));
|
||||
} else if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING &&
|
||||
link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) {
|
||||
core_link_read_dpcd(
|
||||
link,
|
||||
DP_TRAINING_AUX_RD_INTERVAL,
|
||||
(uint8_t *)&training_rd_interval,
|
||||
sizeof(training_rd_interval));
|
||||
}
|
||||
|
||||
switch (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL) {
|
||||
case 0: return 400;
|
||||
case 1: return 4000;
|
||||
case 2: return 8000;
|
||||
case 3: return 12000;
|
||||
case 4: return 16000;
|
||||
case 5: return 32000;
|
||||
case 6: return 64000;
|
||||
default: return 400;
|
||||
}
|
||||
}
|
||||
|
||||
void decide_8b_10b_training_settings(
|
||||
struct dc_link *link,
|
||||
const struct dc_link_settings *link_setting,
|
||||
struct link_training_settings *lt_settings)
|
||||
{
|
||||
memset(lt_settings, '\0', sizeof(struct link_training_settings));
|
||||
|
||||
/* Initialize link settings */
|
||||
lt_settings->link_settings.use_link_rate_set = link_setting->use_link_rate_set;
|
||||
lt_settings->link_settings.link_rate_set = link_setting->link_rate_set;
|
||||
lt_settings->link_settings.link_rate = link_setting->link_rate;
|
||||
lt_settings->link_settings.lane_count = link_setting->lane_count;
|
||||
/* TODO hard coded to SS for now
|
||||
* lt_settings.link_settings.link_spread =
|
||||
* dal_display_path_is_ss_supported(
|
||||
* path_mode->display_path) ?
|
||||
* LINK_SPREAD_05_DOWNSPREAD_30KHZ :
|
||||
* LINK_SPREAD_DISABLED;
|
||||
*/
|
||||
lt_settings->link_settings.link_spread = link->dp_ss_off ?
|
||||
LINK_SPREAD_DISABLED : LINK_SPREAD_05_DOWNSPREAD_30KHZ;
|
||||
lt_settings->cr_pattern_time = get_cr_training_aux_rd_interval(link, link_setting);
|
||||
lt_settings->eq_pattern_time = get_eq_training_aux_rd_interval(link, link_setting);
|
||||
lt_settings->pattern_for_cr = decide_cr_training_pattern(link_setting);
|
||||
lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_setting);
|
||||
lt_settings->enhanced_framing = 1;
|
||||
lt_settings->should_set_fec_ready = true;
|
||||
lt_settings->disallow_per_lane_settings = true;
|
||||
lt_settings->always_match_dpcd_with_hw_lane_settings = true;
|
||||
lt_settings->lttpr_mode = dp_decide_8b_10b_lttpr_mode(link);
|
||||
dp_hw_to_dpcd_lane_settings(lt_settings, lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
|
||||
}
|
||||
|
||||
enum lttpr_mode dp_decide_8b_10b_lttpr_mode(struct dc_link *link)
|
||||
{
|
||||
bool is_lttpr_present = dp_is_lttpr_present(link);
|
||||
bool vbios_lttpr_force_non_transparent = link->dc->caps.vbios_lttpr_enable;
|
||||
bool vbios_lttpr_aware = link->dc->caps.vbios_lttpr_aware;
|
||||
|
||||
if (!is_lttpr_present)
|
||||
return LTTPR_MODE_NON_LTTPR;
|
||||
|
||||
if (vbios_lttpr_aware) {
|
||||
if (vbios_lttpr_force_non_transparent) {
|
||||
DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT due to VBIOS DCE_INFO_CAPS_LTTPR_SUPPORT_ENABLE set to 1.\n");
|
||||
return LTTPR_MODE_NON_TRANSPARENT;
|
||||
} else {
|
||||
DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT by default due to VBIOS not set DCE_INFO_CAPS_LTTPR_SUPPORT_ENABLE set to 1.\n");
|
||||
return LTTPR_MODE_TRANSPARENT;
|
||||
}
|
||||
}
|
||||
|
||||
if (link->dc->config.allow_lttpr_non_transparent_mode.bits.DP1_4A &&
|
||||
link->dc->caps.extended_aux_timeout_support) {
|
||||
DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT by default and dc->config.allow_lttpr_non_transparent_mode.bits.DP1_4A set to 1.\n");
|
||||
return LTTPR_MODE_NON_TRANSPARENT;
|
||||
}
|
||||
|
||||
DC_LOG_DC("chose LTTPR_MODE_NON_LTTPR.\n");
|
||||
return LTTPR_MODE_NON_LTTPR;
|
||||
}
|
||||
|
||||
enum link_training_result perform_8b_10b_clock_recovery_sequence(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
struct link_training_settings *lt_settings,
|
||||
uint32_t offset)
|
||||
{
|
||||
uint32_t retries_cr;
|
||||
uint32_t retry_count;
|
||||
uint32_t wait_time_microsec;
|
||||
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};
|
||||
|
||||
retries_cr = 0;
|
||||
retry_count = 0;
|
||||
|
||||
memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
|
||||
memset(&dpcd_lane_status_updated, '\0',
|
||||
sizeof(dpcd_lane_status_updated));
|
||||
|
||||
if (!link->ctx->dc->work_arounds.lt_early_cr_pattern)
|
||||
dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, offset);
|
||||
|
||||
/* najeeb - The synaptics MST hub can put the LT in
|
||||
* infinite loop by switching the VS
|
||||
*/
|
||||
/* between level 0 and level 1 continuously, here
|
||||
* we try for CR lock for LinkTrainingMaxCRRetry count*/
|
||||
while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
|
||||
(retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
|
||||
|
||||
|
||||
/* 1. call HWSS to set lane settings*/
|
||||
dp_set_hw_lane_settings(
|
||||
link,
|
||||
link_res,
|
||||
lt_settings,
|
||||
offset);
|
||||
|
||||
/* 2. update DPCD of the receiver*/
|
||||
if (!retry_count)
|
||||
/* EPR #361076 - write as a 5-byte burst,
|
||||
* but only for the 1-st iteration.*/
|
||||
dpcd_set_lt_pattern_and_lane_settings(
|
||||
link,
|
||||
lt_settings,
|
||||
lt_settings->pattern_for_cr,
|
||||
offset);
|
||||
else
|
||||
dpcd_set_lane_settings(
|
||||
link,
|
||||
lt_settings,
|
||||
offset);
|
||||
|
||||
/* 3. wait receiver to lock-on*/
|
||||
wait_time_microsec = lt_settings->cr_pattern_time;
|
||||
|
||||
dp_wait_for_training_aux_rd_interval(
|
||||
link,
|
||||
wait_time_microsec);
|
||||
|
||||
/* 4. Read lane status and requested drive
|
||||
* settings as set by the sink
|
||||
*/
|
||||
dp_get_lane_status_and_lane_adjust(
|
||||
link,
|
||||
lt_settings,
|
||||
dpcd_lane_status,
|
||||
&dpcd_lane_status_updated,
|
||||
dpcd_lane_adjust,
|
||||
offset);
|
||||
|
||||
/* 5. check CR done*/
|
||||
if (dp_is_cr_done(lane_count, dpcd_lane_status))
|
||||
return LINK_TRAINING_SUCCESS;
|
||||
|
||||
/* 6. max VS reached*/
|
||||
if ((dp_get_link_encoding_format(<_settings->link_settings) ==
|
||||
DP_8b_10b_ENCODING) &&
|
||||
dp_is_max_vs_reached(lt_settings))
|
||||
break;
|
||||
|
||||
/* 7. same lane settings*/
|
||||
/* Note: settings are the same for all lanes,
|
||||
* so comparing first lane is sufficient*/
|
||||
if ((dp_get_link_encoding_format(<_settings->link_settings) == DP_8b_10b_ENCODING) &&
|
||||
lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
|
||||
dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
|
||||
retries_cr++;
|
||||
else if ((dp_get_link_encoding_format(<_settings->link_settings) == DP_128b_132b_ENCODING) &&
|
||||
lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE ==
|
||||
dpcd_lane_adjust[0].tx_ffe.PRESET_VALUE)
|
||||
retries_cr++;
|
||||
else
|
||||
retries_cr = 0;
|
||||
|
||||
/* 8. update VS/PE/PC2 in lt_settings*/
|
||||
dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
|
||||
lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
|
||||
retry_count++;
|
||||
}
|
||||
|
||||
if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
|
||||
ASSERT(0);
|
||||
DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
|
||||
__func__,
|
||||
LINK_TRAINING_MAX_CR_RETRY);
|
||||
|
||||
}
|
||||
|
||||
return dp_get_cr_failure(lane_count, dpcd_lane_status);
|
||||
}
|
||||
|
||||
enum link_training_result perform_8b_10b_channel_equalization_sequence(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
struct link_training_settings *lt_settings,
|
||||
uint32_t offset)
|
||||
{
|
||||
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};
|
||||
union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
|
||||
|
||||
/* Note: also check that TPS4 is a supported feature*/
|
||||
tr_pattern = lt_settings->pattern_for_eq;
|
||||
|
||||
if (is_repeater(lt_settings, offset) && dp_get_link_encoding_format(<_settings->link_settings) == DP_8b_10b_ENCODING)
|
||||
tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
|
||||
|
||||
dp_set_hw_training_pattern(link, link_res, 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, link_res, 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
|
||||
*/
|
||||
|
||||
dpcd_set_lt_pattern_and_lane_settings(
|
||||
link,
|
||||
lt_settings,
|
||||
tr_pattern, offset);
|
||||
else
|
||||
dpcd_set_lane_settings(link, lt_settings, offset);
|
||||
|
||||
/* 3. wait for receiver to lock-on*/
|
||||
wait_time_microsec = lt_settings->eq_pattern_time;
|
||||
|
||||
if (is_repeater(lt_settings, offset))
|
||||
wait_time_microsec =
|
||||
dp_translate_training_aux_read_interval(
|
||||
link->dpcd_caps.lttpr_caps.aux_rd_interval[offset - 1]);
|
||||
|
||||
dp_wait_for_training_aux_rd_interval(
|
||||
link,
|
||||
wait_time_microsec);
|
||||
|
||||
/* 4. Read lane status and requested
|
||||
* drive settings as set by the sink*/
|
||||
|
||||
dp_get_lane_status_and_lane_adjust(
|
||||
link,
|
||||
lt_settings,
|
||||
dpcd_lane_status,
|
||||
&dpcd_lane_status_updated,
|
||||
dpcd_lane_adjust,
|
||||
offset);
|
||||
|
||||
/* 5. check CR done*/
|
||||
if (!dp_is_cr_done(lane_count, dpcd_lane_status))
|
||||
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) &&
|
||||
dp_is_symbol_locked(lane_count, dpcd_lane_status) &&
|
||||
dp_is_interlane_aligned(dpcd_lane_status_updated))
|
||||
return LINK_TRAINING_SUCCESS;
|
||||
|
||||
/* 7. update VS/PE/PC2 in lt_settings*/
|
||||
dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
|
||||
lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
|
||||
}
|
||||
|
||||
return LINK_TRAINING_EQ_FAIL_EQ;
|
||||
|
||||
}
|
||||
|
||||
enum link_training_result dp_perform_8b_10b_link_training(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
struct link_training_settings *lt_settings)
|
||||
{
|
||||
enum link_training_result status = LINK_TRAINING_SUCCESS;
|
||||
|
||||
uint8_t repeater_cnt;
|
||||
uint8_t repeater_id;
|
||||
uint8_t lane = 0;
|
||||
|
||||
if (link->ctx->dc->work_arounds.lt_early_cr_pattern)
|
||||
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_mode == LTTPR_MODE_NON_TRANSPARENT) {
|
||||
|
||||
/* 2. perform link training (set link training done
|
||||
* to false is done as well)
|
||||
*/
|
||||
repeater_cnt = dp_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_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, repeater_id);
|
||||
|
||||
if (status != LINK_TRAINING_SUCCESS) {
|
||||
repeater_training_done(link, repeater_id);
|
||||
break;
|
||||
}
|
||||
|
||||
status = perform_8b_10b_channel_equalization_sequence(link,
|
||||
link_res,
|
||||
lt_settings,
|
||||
repeater_id);
|
||||
|
||||
repeater_training_done(link, repeater_id);
|
||||
|
||||
if (status != LINK_TRAINING_SUCCESS)
|
||||
break;
|
||||
|
||||
for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
|
||||
lt_settings->dpcd_lane_settings[lane].raw = 0;
|
||||
lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0;
|
||||
lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (status == LINK_TRAINING_SUCCESS) {
|
||||
status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, DPRX);
|
||||
if (status == LINK_TRAINING_SUCCESS) {
|
||||
status = perform_8b_10b_channel_equalization_sequence(link,
|
||||
link_res,
|
||||
lt_settings,
|
||||
DPRX);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2022 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: AMD
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __DC_LINK_DP_TRAINING_8B_10B_H__
|
||||
#define __DC_LINK_DP_TRAINING_8B_10B_H__
|
||||
#include "link_dp_training.h"
|
||||
|
||||
/* to avoid infinite loop where-in the receiver
|
||||
* switches between different VS
|
||||
*/
|
||||
#define LINK_TRAINING_MAX_CR_RETRY 100
|
||||
#define LINK_TRAINING_MAX_RETRY_COUNT 5
|
||||
|
||||
enum link_training_result dp_perform_8b_10b_link_training(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
struct link_training_settings *lt_settings);
|
||||
|
||||
enum link_training_result perform_8b_10b_clock_recovery_sequence(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
struct link_training_settings *lt_settings,
|
||||
uint32_t offset);
|
||||
|
||||
enum link_training_result perform_8b_10b_channel_equalization_sequence(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
struct link_training_settings *lt_settings,
|
||||
uint32_t offset);
|
||||
|
||||
enum lttpr_mode dp_decide_8b_10b_lttpr_mode(struct dc_link *link);
|
||||
|
||||
void decide_8b_10b_training_settings(
|
||||
struct dc_link *link,
|
||||
const struct dc_link_settings *link_setting,
|
||||
struct link_training_settings *lt_settings);
|
||||
|
||||
#endif /* __DC_LINK_DP_TRAINING_8B_10B_H__ */
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2022 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: AMD
|
||||
*
|
||||
*/
|
||||
|
||||
/* FILE POLICY AND INTENDED USAGE:
|
||||
*
|
||||
*/
|
||||
#include "link_dp_training_auxless.h"
|
||||
#include "dc_link_dp.h"
|
||||
|
||||
#define DC_LOGGER \
|
||||
link->ctx->logger
|
||||
bool dc_link_dp_perform_link_training_skip_aux(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
const struct dc_link_settings *link_setting)
|
||||
{
|
||||
struct link_training_settings lt_settings = {0};
|
||||
|
||||
dp_decide_training_settings(
|
||||
link,
|
||||
link_setting,
|
||||
<_settings);
|
||||
override_training_settings(
|
||||
link,
|
||||
&link->preferred_training_settings,
|
||||
<_settings);
|
||||
|
||||
/* 1. Perform_clock_recovery_sequence. */
|
||||
|
||||
/* transmit training pattern for clock recovery */
|
||||
dp_set_hw_training_pattern(link, link_res, lt_settings.pattern_for_cr, DPRX);
|
||||
|
||||
/* call HWSS to set lane settings*/
|
||||
dp_set_hw_lane_settings(link, link_res, <_settings, DPRX);
|
||||
|
||||
/* wait receiver to lock-on*/
|
||||
dp_wait_for_training_aux_rd_interval(link, lt_settings.cr_pattern_time);
|
||||
|
||||
/* 2. Perform_channel_equalization_sequence. */
|
||||
|
||||
/* transmit training pattern for channel equalization. */
|
||||
dp_set_hw_training_pattern(link, link_res, lt_settings.pattern_for_eq, DPRX);
|
||||
|
||||
/* call HWSS to set lane settings*/
|
||||
dp_set_hw_lane_settings(link, link_res, <_settings, DPRX);
|
||||
|
||||
/* wait receiver to lock-on. */
|
||||
dp_wait_for_training_aux_rd_interval(link, lt_settings.eq_pattern_time);
|
||||
|
||||
/* 3. Perform_link_training_int. */
|
||||
|
||||
/* Mainlink output idle pattern. */
|
||||
dp_set_hw_test_pattern(link, link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
|
||||
|
||||
dp_log_training_result(link, <_settings, LINK_TRAINING_SUCCESS);
|
||||
|
||||
return true;
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2022 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: AMD
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __DC_LINK_DP_TRAINING_AUXLESS_H__
|
||||
#define __DC_LINK_DP_TRAINING_AUXLESS_H__
|
||||
#include "link_dp_training.h"
|
||||
|
||||
bool dc_link_dp_perform_link_training_skip_aux(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
const struct dc_link_settings *link_setting);
|
||||
#endif /* __DC_LINK_DP_TRAINING_AUXLESS_H__ */
|
1044
drivers/gpu/drm/amd/display/dc/link/link_dp_training_dpia.c
Normal file
1044
drivers/gpu/drm/amd/display/dc/link/link_dp_training_dpia.c
Normal file
File diff suppressed because it is too large
Load Diff
41
drivers/gpu/drm/amd/display/dc/link/link_dp_training_dpia.h
Normal file
41
drivers/gpu/drm/amd/display/dc/link/link_dp_training_dpia.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2022 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: AMD
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __DC_LINK_DP_TRAINING_DPIA_H__
|
||||
#define __DC_LINK_DP_TRAINING_DPIA_H__
|
||||
#include "link_dp_training.h"
|
||||
|
||||
/* Train DP tunneling link for USB4 DPIA display endpoint.
|
||||
* DPIA equivalent of dc_link_dp_perfrorm_link_training.
|
||||
* Aborts link training upon detection of sink unplug.
|
||||
*/
|
||||
enum link_training_result dc_link_dpia_perform_link_training(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
const struct dc_link_settings *link_setting,
|
||||
bool skip_video_pattern);
|
||||
|
||||
#endif /* __DC_LINK_DP_TRAINING_DPIA_H__ */
|
@ -0,0 +1,578 @@
|
||||
/*
|
||||
* Copyright 2022 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: AMD
|
||||
*
|
||||
*/
|
||||
|
||||
/* FILE POLICY AND INTENDED USAGE:
|
||||
* This file implements 8b/10b link training specially modified to support an
|
||||
* embedded retimer chip. This retimer chip is referred as fixed vs pe retimer.
|
||||
* Unlike native dp connection this chip requires a modified link training
|
||||
* protocol based on 8b/10b link training. Since this is a non standard sequence
|
||||
* and we must support this hardware, we decided to isolate it in its own
|
||||
* training sequence inside its own file.
|
||||
*/
|
||||
#include "link_dp_training_fixed_vs_pe_retimer.h"
|
||||
#include "link_dp_training_8b_10b.h"
|
||||
#include "link_dpcd.h"
|
||||
#include "dc_link_dp.h"
|
||||
|
||||
#define DC_LOGGER \
|
||||
link->ctx->logger
|
||||
|
||||
void dp_fixed_vs_pe_read_lane_adjust(
|
||||
struct dc_link *link,
|
||||
union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX])
|
||||
{
|
||||
const uint8_t vendor_lttpr_write_data_vs[3] = {0x0, 0x53, 0x63};
|
||||
const uint8_t vendor_lttpr_write_data_pe[3] = {0x0, 0x54, 0x63};
|
||||
const uint8_t offset = dp_convert_to_count(
|
||||
link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
|
||||
uint32_t vendor_lttpr_write_address = 0xF004F;
|
||||
uint32_t vendor_lttpr_read_address = 0xF0053;
|
||||
uint8_t dprx_vs = 0;
|
||||
uint8_t dprx_pe = 0;
|
||||
uint8_t lane;
|
||||
|
||||
if (offset != 0xFF) {
|
||||
vendor_lttpr_write_address +=
|
||||
((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
|
||||
vendor_lttpr_read_address +=
|
||||
((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
|
||||
}
|
||||
|
||||
/* W/A to read lane settings requested by DPRX */
|
||||
core_link_write_dpcd(
|
||||
link,
|
||||
vendor_lttpr_write_address,
|
||||
&vendor_lttpr_write_data_vs[0],
|
||||
sizeof(vendor_lttpr_write_data_vs));
|
||||
core_link_read_dpcd(
|
||||
link,
|
||||
vendor_lttpr_read_address,
|
||||
&dprx_vs,
|
||||
1);
|
||||
core_link_write_dpcd(
|
||||
link,
|
||||
vendor_lttpr_write_address,
|
||||
&vendor_lttpr_write_data_pe[0],
|
||||
sizeof(vendor_lttpr_write_data_pe));
|
||||
core_link_read_dpcd(
|
||||
link,
|
||||
vendor_lttpr_read_address,
|
||||
&dprx_pe,
|
||||
1);
|
||||
|
||||
for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
|
||||
dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET = (dprx_vs >> (2 * lane)) & 0x3;
|
||||
dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET = (dprx_pe >> (2 * lane)) & 0x3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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],
|
||||
uint8_t lane_count)
|
||||
{
|
||||
const uint8_t offset = dp_convert_to_count(
|
||||
link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
|
||||
const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF};
|
||||
uint32_t vendor_lttpr_write_address = 0xF004F;
|
||||
uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
|
||||
uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
|
||||
uint8_t lane = 0;
|
||||
|
||||
if (offset != 0xFF) {
|
||||
vendor_lttpr_write_address +=
|
||||
((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
|
||||
}
|
||||
|
||||
for (lane = 0; lane < lane_count; lane++) {
|
||||
vendor_lttpr_write_data_vs[3] |=
|
||||
dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
|
||||
vendor_lttpr_write_data_pe[3] |=
|
||||
dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
|
||||
}
|
||||
|
||||
/* Force LTTPR to output desired VS and PE */
|
||||
core_link_write_dpcd(
|
||||
link,
|
||||
vendor_lttpr_write_address,
|
||||
&vendor_lttpr_write_data_reset[0],
|
||||
sizeof(vendor_lttpr_write_data_reset));
|
||||
core_link_write_dpcd(
|
||||
link,
|
||||
vendor_lttpr_write_address,
|
||||
&vendor_lttpr_write_data_vs[0],
|
||||
sizeof(vendor_lttpr_write_data_vs));
|
||||
core_link_write_dpcd(
|
||||
link,
|
||||
vendor_lttpr_write_address,
|
||||
&vendor_lttpr_write_data_pe[0],
|
||||
sizeof(vendor_lttpr_write_data_pe));
|
||||
}
|
||||
|
||||
static enum link_training_result perform_fixed_vs_pe_nontransparent_training_sequence(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
struct link_training_settings *lt_settings)
|
||||
{
|
||||
enum link_training_result status = LINK_TRAINING_SUCCESS;
|
||||
uint8_t lane = 0;
|
||||
uint8_t toggle_rate = 0x6;
|
||||
uint8_t target_rate = 0x6;
|
||||
bool apply_toggle_rate_wa = false;
|
||||
uint8_t repeater_cnt;
|
||||
uint8_t repeater_id;
|
||||
|
||||
/* Fixed VS/PE specific: Force CR AUX RD Interval to at least 16ms */
|
||||
if (lt_settings->cr_pattern_time < 16000)
|
||||
lt_settings->cr_pattern_time = 16000;
|
||||
|
||||
/* Fixed VS/PE specific: Toggle link rate */
|
||||
apply_toggle_rate_wa = (link->vendor_specific_lttpr_link_rate_wa == target_rate);
|
||||
target_rate = get_dpcd_link_rate(<_settings->link_settings);
|
||||
toggle_rate = (target_rate == 0x6) ? 0xA : 0x6;
|
||||
|
||||
if (apply_toggle_rate_wa)
|
||||
lt_settings->link_settings.link_rate = toggle_rate;
|
||||
|
||||
if (link->ctx->dc->work_arounds.lt_early_cr_pattern)
|
||||
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);
|
||||
|
||||
/* Fixed VS/PE specific: Toggle link rate back*/
|
||||
if (apply_toggle_rate_wa) {
|
||||
core_link_write_dpcd(
|
||||
link,
|
||||
DP_LINK_BW_SET,
|
||||
&target_rate,
|
||||
1);
|
||||
}
|
||||
|
||||
link->vendor_specific_lttpr_link_rate_wa = target_rate;
|
||||
|
||||
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_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_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, repeater_id);
|
||||
|
||||
if (status != LINK_TRAINING_SUCCESS) {
|
||||
repeater_training_done(link, repeater_id);
|
||||
break;
|
||||
}
|
||||
|
||||
status = perform_8b_10b_channel_equalization_sequence(link,
|
||||
link_res,
|
||||
lt_settings,
|
||||
repeater_id);
|
||||
|
||||
repeater_training_done(link, repeater_id);
|
||||
|
||||
if (status != LINK_TRAINING_SUCCESS)
|
||||
break;
|
||||
|
||||
for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
|
||||
lt_settings->dpcd_lane_settings[lane].raw = 0;
|
||||
lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0;
|
||||
lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (status == LINK_TRAINING_SUCCESS) {
|
||||
status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, DPRX);
|
||||
if (status == LINK_TRAINING_SUCCESS) {
|
||||
status = perform_8b_10b_channel_equalization_sequence(link,
|
||||
link_res,
|
||||
lt_settings,
|
||||
DPRX);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
struct link_training_settings *lt_settings)
|
||||
{
|
||||
const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF};
|
||||
const uint8_t offset = dp_convert_to_count(
|
||||
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;
|
||||
enum link_training_result status = LINK_TRAINING_SUCCESS;
|
||||
uint8_t lane = 0;
|
||||
union down_spread_ctrl downspread = {0};
|
||||
union lane_count_set lane_count_set = {0};
|
||||
uint8_t toggle_rate;
|
||||
uint8_t rate;
|
||||
|
||||
/* Only 8b/10b is supported */
|
||||
ASSERT(dp_get_link_encoding_format(<_settings->link_settings) ==
|
||||
DP_8b_10b_ENCODING);
|
||||
|
||||
if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
|
||||
status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings);
|
||||
return status;
|
||||
}
|
||||
|
||||
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 */
|
||||
core_link_write_dpcd(
|
||||
link,
|
||||
vendor_lttpr_write_address,
|
||||
&vendor_lttpr_write_data_reset[0],
|
||||
sizeof(vendor_lttpr_write_data_reset));
|
||||
core_link_write_dpcd(
|
||||
link,
|
||||
vendor_lttpr_write_address,
|
||||
&vendor_lttpr_write_data_vs[0],
|
||||
sizeof(vendor_lttpr_write_data_vs));
|
||||
core_link_write_dpcd(
|
||||
link,
|
||||
vendor_lttpr_write_address,
|
||||
&vendor_lttpr_write_data_pe[0],
|
||||
sizeof(vendor_lttpr_write_data_pe));
|
||||
|
||||
/* Vendor specific: Enable intercept */
|
||||
core_link_write_dpcd(
|
||||
link,
|
||||
vendor_lttpr_write_address,
|
||||
&vendor_lttpr_write_data_intercept_en[0],
|
||||
sizeof(vendor_lttpr_write_data_intercept_en));
|
||||
|
||||
/* 1. set link rate, lane count and spread. */
|
||||
|
||||
downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread);
|
||||
|
||||
lane_count_set.bits.LANE_COUNT_SET =
|
||||
lt_settings->link_settings.lane_count;
|
||||
|
||||
lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
|
||||
lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
|
||||
|
||||
|
||||
if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) {
|
||||
lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
|
||||
link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
|
||||
}
|
||||
|
||||
core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
|
||||
&downspread.raw, sizeof(downspread));
|
||||
|
||||
core_link_write_dpcd(link, DP_LANE_COUNT_SET,
|
||||
&lane_count_set.raw, 1);
|
||||
|
||||
rate = get_dpcd_link_rate(<_settings->link_settings);
|
||||
|
||||
/* Vendor specific: Toggle link rate */
|
||||
toggle_rate = (rate == 0x6) ? 0xA : 0x6;
|
||||
|
||||
if (link->vendor_specific_lttpr_link_rate_wa == rate) {
|
||||
core_link_write_dpcd(
|
||||
link,
|
||||
DP_LINK_BW_SET,
|
||||
&toggle_rate,
|
||||
1);
|
||||
}
|
||||
|
||||
link->vendor_specific_lttpr_link_rate_wa = rate;
|
||||
|
||||
core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
|
||||
|
||||
DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
|
||||
__func__,
|
||||
DP_LINK_BW_SET,
|
||||
lt_settings->link_settings.link_rate,
|
||||
DP_LANE_COUNT_SET,
|
||||
lt_settings->link_settings.lane_count,
|
||||
lt_settings->enhanced_framing,
|
||||
DP_DOWNSPREAD_CTRL,
|
||||
lt_settings->link_settings.link_spread);
|
||||
|
||||
/* 2. Perform link training */
|
||||
|
||||
/* 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;
|
||||
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};
|
||||
enum dc_status dpcd_status = DC_OK;
|
||||
uint8_t i = 0;
|
||||
|
||||
retries_cr = 0;
|
||||
retry_count = 0;
|
||||
|
||||
memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
|
||||
memset(&dpcd_lane_status_updated, '\0',
|
||||
sizeof(dpcd_lane_status_updated));
|
||||
|
||||
while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
|
||||
(retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
|
||||
|
||||
|
||||
/* 1. call HWSS to set lane settings */
|
||||
dp_set_hw_lane_settings(
|
||||
link,
|
||||
link_res,
|
||||
lt_settings,
|
||||
0);
|
||||
|
||||
/* 2. update DPCD of the receiver */
|
||||
if (!retry_count) {
|
||||
/* EPR #361076 - write as a 5-byte burst,
|
||||
* but only for the 1-st iteration.
|
||||
*/
|
||||
dpcd_set_lt_pattern_and_lane_settings(
|
||||
link,
|
||||
lt_settings,
|
||||
lt_settings->pattern_for_cr,
|
||||
0);
|
||||
/* Vendor specific: Disable intercept */
|
||||
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;
|
||||
|
||||
for (lane = 0; lane < lane_count; lane++) {
|
||||
vendor_lttpr_write_data_vs[3] |=
|
||||
lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
|
||||
vendor_lttpr_write_data_pe[3] |=
|
||||
lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
|
||||
}
|
||||
|
||||
/* Vendor specific: Update VS and PE to DPRX requested value */
|
||||
core_link_write_dpcd(
|
||||
link,
|
||||
vendor_lttpr_write_address,
|
||||
&vendor_lttpr_write_data_vs[0],
|
||||
sizeof(vendor_lttpr_write_data_vs));
|
||||
core_link_write_dpcd(
|
||||
link,
|
||||
vendor_lttpr_write_address,
|
||||
&vendor_lttpr_write_data_pe[0],
|
||||
sizeof(vendor_lttpr_write_data_pe));
|
||||
|
||||
dpcd_set_lane_settings(
|
||||
link,
|
||||
lt_settings,
|
||||
0);
|
||||
}
|
||||
|
||||
/* 3. wait receiver to lock-on*/
|
||||
wait_time_microsec = lt_settings->cr_pattern_time;
|
||||
|
||||
dp_wait_for_training_aux_rd_interval(
|
||||
link,
|
||||
wait_time_microsec);
|
||||
|
||||
/* 4. Read lane status and requested drive
|
||||
* settings as set by the sink
|
||||
*/
|
||||
dp_get_lane_status_and_lane_adjust(
|
||||
link,
|
||||
lt_settings,
|
||||
dpcd_lane_status,
|
||||
&dpcd_lane_status_updated,
|
||||
dpcd_lane_adjust,
|
||||
0);
|
||||
|
||||
/* 5. check CR done*/
|
||||
if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
|
||||
status = LINK_TRAINING_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
/* 6. max VS reached*/
|
||||
if (dp_is_max_vs_reached(lt_settings))
|
||||
break;
|
||||
|
||||
/* 7. same lane settings */
|
||||
/* Note: settings are the same for all lanes,
|
||||
* so comparing first lane is sufficient
|
||||
*/
|
||||
if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
|
||||
dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
|
||||
retries_cr++;
|
||||
else
|
||||
retries_cr = 0;
|
||||
|
||||
/* 8. update VS/PE/PC2 in lt_settings*/
|
||||
dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
|
||||
lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
|
||||
retry_count++;
|
||||
}
|
||||
|
||||
if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
|
||||
ASSERT(0);
|
||||
DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
|
||||
__func__,
|
||||
LINK_TRAINING_MAX_CR_RETRY);
|
||||
|
||||
}
|
||||
|
||||
status = dp_get_cr_failure(lane_count, dpcd_lane_status);
|
||||
}
|
||||
|
||||
/* Perform Channel EQ Sequence */
|
||||
if (status == LINK_TRAINING_SUCCESS) {
|
||||
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};
|
||||
union lane_adjust dpcd_lane_adjust[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, link_res, tr_pattern, 0);
|
||||
|
||||
status = LINK_TRAINING_EQ_FAIL_EQ;
|
||||
|
||||
for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
|
||||
retries_ch_eq++) {
|
||||
|
||||
dp_set_hw_lane_settings(link, link_res, lt_settings, 0);
|
||||
|
||||
vendor_lttpr_write_data_vs[3] = 0;
|
||||
vendor_lttpr_write_data_pe[3] = 0;
|
||||
|
||||
for (lane = 0; lane < lane_count; lane++) {
|
||||
vendor_lttpr_write_data_vs[3] |=
|
||||
lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
|
||||
vendor_lttpr_write_data_pe[3] |=
|
||||
lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
|
||||
}
|
||||
|
||||
/* Vendor specific: Update VS and PE to DPRX requested value */
|
||||
core_link_write_dpcd(
|
||||
link,
|
||||
vendor_lttpr_write_address,
|
||||
&vendor_lttpr_write_data_vs[0],
|
||||
sizeof(vendor_lttpr_write_data_vs));
|
||||
core_link_write_dpcd(
|
||||
link,
|
||||
vendor_lttpr_write_address,
|
||||
&vendor_lttpr_write_data_pe[0],
|
||||
sizeof(vendor_lttpr_write_data_pe));
|
||||
|
||||
/* 2. update DPCD*/
|
||||
if (!retries_ch_eq)
|
||||
/* EPR #361076 - write as a 5-byte burst,
|
||||
* but only for the 1-st iteration
|
||||
*/
|
||||
|
||||
dpcd_set_lt_pattern_and_lane_settings(
|
||||
link,
|
||||
lt_settings,
|
||||
tr_pattern, 0);
|
||||
else
|
||||
dpcd_set_lane_settings(link, lt_settings, 0);
|
||||
|
||||
/* 3. wait for receiver to lock-on*/
|
||||
wait_time_microsec = lt_settings->eq_pattern_time;
|
||||
|
||||
dp_wait_for_training_aux_rd_interval(
|
||||
link,
|
||||
wait_time_microsec);
|
||||
|
||||
/* 4. Read lane status and requested
|
||||
* drive settings as set by the sink
|
||||
*/
|
||||
dp_get_lane_status_and_lane_adjust(
|
||||
link,
|
||||
lt_settings,
|
||||
dpcd_lane_status,
|
||||
&dpcd_lane_status_updated,
|
||||
dpcd_lane_adjust,
|
||||
0);
|
||||
|
||||
/* 5. check CR done*/
|
||||
if (!dp_is_cr_done(lane_count, dpcd_lane_status)) {
|
||||
status = LINK_TRAINING_EQ_FAIL_CR;
|
||||
break;
|
||||
}
|
||||
|
||||
/* 6. check CHEQ done*/
|
||||
if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
|
||||
dp_is_symbol_locked(lane_count, dpcd_lane_status) &&
|
||||
dp_is_interlane_aligned(dpcd_lane_status_updated)) {
|
||||
status = LINK_TRAINING_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
/* 7. update VS/PE/PC2 in lt_settings*/
|
||||
dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
|
||||
lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2022 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: AMD
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __DC_LINK_DP_FIXED_VS_PE_RETIMER_H__
|
||||
#define __DC_LINK_DP_FIXED_VS_PE_RETIMER_H__
|
||||
#include "link_dp_training.h"
|
||||
|
||||
enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
|
||||
struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
struct link_training_settings *lt_settings);
|
||||
|
||||
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],
|
||||
uint8_t lane_count);
|
||||
|
||||
void dp_fixed_vs_pe_read_lane_adjust(
|
||||
struct dc_link *link,
|
||||
union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX]);
|
||||
|
||||
#endif /* __DC_LINK_DP_FIXED_VS_PE_RETIMER_H__ */
|
@ -26,6 +26,7 @@
|
||||
#ifndef __LINK_DPCD_H__
|
||||
#define __LINK_DPCD_H__
|
||||
#include "link.h"
|
||||
#include "dpcd_defs.h"
|
||||
|
||||
enum dc_status core_link_read_dpcd(
|
||||
struct dc_link *link,
|
||||
|
@ -133,6 +133,11 @@ static const uint8_t DP_SINK_DEVICE_STR_ID_2[] = {7, 1, 8, 7, 5};
|
||||
|
||||
static const u8 DP_SINK_BRANCH_DEV_NAME_7580[] = "7580\x80u";
|
||||
|
||||
/*Travis*/
|
||||
static const uint8_t DP_VGA_LVDS_CONVERTER_ID_2[] = "sivarT";
|
||||
/*Nutmeg*/
|
||||
static const uint8_t DP_VGA_LVDS_CONVERTER_ID_3[] = "dnomlA";
|
||||
|
||||
/*MST Dock*/
|
||||
static const uint8_t SYNAPTICS_DEVICE_ID[] = "SYNA";
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user