Commit e84ecdc5 authored by Jimmy Kizito's avatar Jimmy Kizito Committed by Alex Deucher

drm/amd/display: Expand DP module clock recovery API.

[Why & How]
Add functionality useful for DP clock recovery phase of link training to
public interface.
Signed-off-by: default avatarJimmy Kizito <Jimmy.Kizito@amd.com>
Reviewed-by: default avatarJun Lei <Jun.Lei@amd.com>
Acked-by: default avatarQingqing Zhuo <qingqing.zhuo@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 7211b605
...@@ -25,8 +25,6 @@ static const uint8_t DP_VGA_LVDS_CONVERTER_ID_3[] = "dnomlA"; ...@@ -25,8 +25,6 @@ static const uint8_t DP_VGA_LVDS_CONVERTER_ID_3[] = "dnomlA";
link->ctx->logger link->ctx->logger
#define DC_TRACE_LEVEL_MESSAGE(...) /* do nothing */ #define DC_TRACE_LEVEL_MESSAGE(...) /* do nothing */
#define DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE 0x50
/* maximum pre emphasis level allowed for each voltage swing level*/ /* maximum pre emphasis level allowed for each voltage swing level*/
static const enum dc_pre_emphasis static const enum dc_pre_emphasis
voltage_swing_to_pre_emphasis[] = { PRE_EMPHASIS_LEVEL3, voltage_swing_to_pre_emphasis[] = { PRE_EMPHASIS_LEVEL3,
...@@ -39,14 +37,6 @@ enum { ...@@ -39,14 +37,6 @@ enum {
POST_LT_ADJ_REQ_TIMEOUT = 200 POST_LT_ADJ_REQ_TIMEOUT = 200
}; };
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
};
static bool decide_fallback_link_setting( static bool decide_fallback_link_setting(
struct dc_link_settings initial_link_settings, struct dc_link_settings initial_link_settings,
struct dc_link_settings *current_link_setting, struct dc_link_settings *current_link_setting,
...@@ -97,7 +87,7 @@ static uint32_t get_eq_training_aux_rd_interval( ...@@ -97,7 +87,7 @@ static uint32_t get_eq_training_aux_rd_interval(
return wait_in_micro_secs; return wait_in_micro_secs;
} }
static void wait_for_training_aux_rd_interval( void dp_wait_for_training_aux_rd_interval(
struct dc_link *link, struct dc_link *link,
uint32_t wait_in_micro_secs) uint32_t wait_in_micro_secs)
{ {
...@@ -108,7 +98,7 @@ static void wait_for_training_aux_rd_interval( ...@@ -108,7 +98,7 @@ static void wait_for_training_aux_rd_interval(
wait_in_micro_secs); wait_in_micro_secs);
} }
static enum dpcd_training_patterns enum dpcd_training_patterns
dc_dp_training_pattern_to_dpcd_training_pattern( dc_dp_training_pattern_to_dpcd_training_pattern(
struct dc_link *link, struct dc_link *link,
enum dc_dp_training_pattern pattern) enum dc_dp_training_pattern pattern)
...@@ -284,7 +274,7 @@ enum dc_status dpcd_set_link_settings( ...@@ -284,7 +274,7 @@ enum dc_status dpcd_set_link_settings(
return status; return status;
} }
static uint8_t dc_dp_initialize_scrambling_data_symbols( uint8_t dc_dp_initialize_scrambling_data_symbols(
struct dc_link *link, struct dc_link *link,
enum dc_dp_training_pattern pattern) enum dc_dp_training_pattern pattern)
{ {
...@@ -433,7 +423,7 @@ static void dpcd_set_lt_pattern_and_lane_settings( ...@@ -433,7 +423,7 @@ static void dpcd_set_lt_pattern_and_lane_settings(
link->cur_lane_setting = lt_settings->lane_settings[0]; link->cur_lane_setting = lt_settings->lane_settings[0];
} }
static bool is_cr_done(enum dc_lane_count ln_count, bool dp_is_cr_done(enum dc_lane_count ln_count,
union lane_status *dpcd_lane_status) union lane_status *dpcd_lane_status)
{ {
uint32_t lane; uint32_t lane;
...@@ -472,7 +462,7 @@ static inline bool is_interlane_aligned(union lane_align_status_updated align_st ...@@ -472,7 +462,7 @@ static inline bool is_interlane_aligned(union lane_align_status_updated align_st
return align_status.bits.INTERLANE_ALIGN_DONE == 1; return align_status.bits.INTERLANE_ALIGN_DONE == 1;
} }
static void update_drive_settings( void dp_update_drive_settings(
struct link_training_settings *dest, struct link_training_settings *dest,
struct link_training_settings src) struct link_training_settings src)
{ {
...@@ -616,7 +606,7 @@ static void find_max_drive_settings( ...@@ -616,7 +606,7 @@ static void find_max_drive_settings(
} }
static void get_lane_status_and_drive_settings( enum dc_status dp_get_lane_status_and_drive_settings(
struct dc_link *link, struct dc_link *link,
const struct link_training_settings *link_training_setting, const struct link_training_settings *link_training_setting,
union lane_status *ln_status, union lane_status *ln_status,
...@@ -631,6 +621,7 @@ static void get_lane_status_and_drive_settings( ...@@ -631,6 +621,7 @@ static void get_lane_status_and_drive_settings(
union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } }; union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } };
struct link_training_settings request_settings = { {0} }; struct link_training_settings request_settings = { {0} };
uint32_t lane; uint32_t lane;
enum dc_status status;
memset(req_settings, '\0', sizeof(struct link_training_settings)); memset(req_settings, '\0', sizeof(struct link_training_settings));
...@@ -641,7 +632,7 @@ static void get_lane_status_and_drive_settings( ...@@ -641,7 +632,7 @@ static void get_lane_status_and_drive_settings(
lane_adjust_offset = 3; lane_adjust_offset = 3;
} }
core_link_read_dpcd( status = core_link_read_dpcd(
link, link,
lane01_status_address, lane01_status_address,
(uint8_t *)(dpcd_buf), (uint8_t *)(dpcd_buf),
...@@ -729,9 +720,10 @@ static void get_lane_status_and_drive_settings( ...@@ -729,9 +720,10 @@ static void get_lane_status_and_drive_settings(
* read DpcdAddress_AdjustRequestPostCursor2 = 0x020C * read DpcdAddress_AdjustRequestPostCursor2 = 0x020C
*/ */
return status;
} }
static void dpcd_set_lane_settings( enum dc_status dpcd_set_lane_settings(
struct dc_link *link, struct dc_link *link,
const struct link_training_settings *link_training_setting, const struct link_training_settings *link_training_setting,
uint32_t offset) uint32_t offset)
...@@ -739,6 +731,7 @@ static void dpcd_set_lane_settings( ...@@ -739,6 +731,7 @@ static void dpcd_set_lane_settings(
union dpcd_training_lane dpcd_lane[LANE_COUNT_DP_MAX] = {{{0}}}; union dpcd_training_lane dpcd_lane[LANE_COUNT_DP_MAX] = {{{0}}};
uint32_t lane; uint32_t lane;
unsigned int lane0_set_address; unsigned int lane0_set_address;
enum dc_status status;
lane0_set_address = DP_TRAINING_LANE0_SET; lane0_set_address = DP_TRAINING_LANE0_SET;
...@@ -766,7 +759,7 @@ static void dpcd_set_lane_settings( ...@@ -766,7 +759,7 @@ static void dpcd_set_lane_settings(
PRE_EMPHASIS_MAX_LEVEL ? 1 : 0); PRE_EMPHASIS_MAX_LEVEL ? 1 : 0);
} }
core_link_write_dpcd(link, status = core_link_write_dpcd(link,
lane0_set_address, lane0_set_address,
(uint8_t *)(dpcd_lane), (uint8_t *)(dpcd_lane),
link_training_setting->link_settings.lane_count); link_training_setting->link_settings.lane_count);
...@@ -812,9 +805,10 @@ static void dpcd_set_lane_settings( ...@@ -812,9 +805,10 @@ static void dpcd_set_lane_settings(
} }
link->cur_lane_setting = link_training_setting->lane_settings[0]; link->cur_lane_setting = link_training_setting->lane_settings[0];
return status;
} }
static bool is_max_vs_reached( bool dp_is_max_vs_reached(
const struct link_training_settings *lt_settings) const struct link_training_settings *lt_settings)
{ {
uint32_t lane; uint32_t lane;
...@@ -856,19 +850,19 @@ static bool perform_post_lt_adj_req_sequence( ...@@ -856,19 +850,19 @@ static bool perform_post_lt_adj_req_sequence(
union lane_align_status_updated union lane_align_status_updated
dpcd_lane_status_updated; dpcd_lane_status_updated;
get_lane_status_and_drive_settings( dp_get_lane_status_and_drive_settings(
link, link,
lt_settings, lt_settings,
dpcd_lane_status, dpcd_lane_status,
&dpcd_lane_status_updated, &dpcd_lane_status_updated,
&req_settings, &req_settings,
DPRX); DPRX);
if (dpcd_lane_status_updated.bits. if (dpcd_lane_status_updated.bits.
POST_LT_ADJ_REQ_IN_PROGRESS == 0) POST_LT_ADJ_REQ_IN_PROGRESS == 0)
return true; return true;
if (!is_cr_done(lane_count, dpcd_lane_status)) if (!dp_is_cr_done(lane_count, dpcd_lane_status))
return false; return false;
if (!is_ch_eq_done(lane_count, dpcd_lane_status) || if (!is_ch_eq_done(lane_count, dpcd_lane_status) ||
...@@ -891,7 +885,7 @@ static bool perform_post_lt_adj_req_sequence( ...@@ -891,7 +885,7 @@ static bool perform_post_lt_adj_req_sequence(
} }
if (req_drv_setting_changed) { if (req_drv_setting_changed) {
update_drive_settings( dp_update_drive_settings(
lt_settings, req_settings); lt_settings, req_settings);
dc_link_dp_set_drive_settings(link, dc_link_dp_set_drive_settings(link,
...@@ -943,7 +937,7 @@ static uint32_t translate_training_aux_read_interval(uint32_t dpcd_aux_read_inte ...@@ -943,7 +937,7 @@ static uint32_t translate_training_aux_read_interval(uint32_t dpcd_aux_read_inte
return aux_rd_interval_us; return aux_rd_interval_us;
} }
static enum link_training_result get_cr_failure(enum dc_lane_count ln_count, enum link_training_result dp_get_cr_failure(enum dc_lane_count ln_count,
union lane_status *dpcd_lane_status) union lane_status *dpcd_lane_status)
{ {
enum link_training_result result = LINK_TRAINING_SUCCESS; enum link_training_result result = LINK_TRAINING_SUCCESS;
...@@ -1007,14 +1001,14 @@ static enum link_training_result perform_channel_equalization_sequence( ...@@ -1007,14 +1001,14 @@ static enum link_training_result perform_channel_equalization_sequence(
translate_training_aux_read_interval( translate_training_aux_read_interval(
link->dpcd_caps.lttpr_caps.aux_rd_interval[offset - 1]); link->dpcd_caps.lttpr_caps.aux_rd_interval[offset - 1]);
wait_for_training_aux_rd_interval( dp_wait_for_training_aux_rd_interval(
link, link,
wait_time_microsec); wait_time_microsec);
/* 4. Read lane status and requested /* 4. Read lane status and requested
* drive settings as set by the sink*/ * drive settings as set by the sink*/
get_lane_status_and_drive_settings( dp_get_lane_status_and_drive_settings(
link, link,
lt_settings, lt_settings,
dpcd_lane_status, dpcd_lane_status,
...@@ -1023,7 +1017,7 @@ static enum link_training_result perform_channel_equalization_sequence( ...@@ -1023,7 +1017,7 @@ static enum link_training_result perform_channel_equalization_sequence(
offset); offset);
/* 5. check CR done*/ /* 5. check CR done*/
if (!is_cr_done(lane_count, dpcd_lane_status)) if (!dp_is_cr_done(lane_count, dpcd_lane_status))
return LINK_TRAINING_EQ_FAIL_CR; return LINK_TRAINING_EQ_FAIL_CR;
/* 6. check CHEQ done*/ /* 6. check CHEQ done*/
...@@ -1033,13 +1027,12 @@ static enum link_training_result perform_channel_equalization_sequence( ...@@ -1033,13 +1027,12 @@ static enum link_training_result perform_channel_equalization_sequence(
return LINK_TRAINING_SUCCESS; return LINK_TRAINING_SUCCESS;
/* 7. update VS/PE/PC2 in lt_settings*/ /* 7. update VS/PE/PC2 in lt_settings*/
update_drive_settings(lt_settings, req_settings); dp_update_drive_settings(lt_settings, req_settings);
} }
return LINK_TRAINING_EQ_FAIL_EQ; return LINK_TRAINING_EQ_FAIL_EQ;
} }
#define TRAINING_AUX_RD_INTERVAL 100 //us
static void start_clock_recovery_pattern_early(struct dc_link *link, static void start_clock_recovery_pattern_early(struct dc_link *link,
struct link_training_settings *lt_settings, struct link_training_settings *lt_settings,
...@@ -1110,14 +1103,14 @@ static enum link_training_result perform_clock_recovery_sequence( ...@@ -1110,14 +1103,14 @@ static enum link_training_result perform_clock_recovery_sequence(
if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
wait_time_microsec = TRAINING_AUX_RD_INTERVAL; wait_time_microsec = TRAINING_AUX_RD_INTERVAL;
wait_for_training_aux_rd_interval( dp_wait_for_training_aux_rd_interval(
link, link,
wait_time_microsec); wait_time_microsec);
/* 4. Read lane status and requested drive /* 4. Read lane status and requested drive
* settings as set by the sink * settings as set by the sink
*/ */
get_lane_status_and_drive_settings( dp_get_lane_status_and_drive_settings(
link, link,
lt_settings, lt_settings,
dpcd_lane_status, dpcd_lane_status,
...@@ -1126,11 +1119,11 @@ static enum link_training_result perform_clock_recovery_sequence( ...@@ -1126,11 +1119,11 @@ static enum link_training_result perform_clock_recovery_sequence(
offset); offset);
/* 5. check CR done*/ /* 5. check CR done*/
if (is_cr_done(lane_count, dpcd_lane_status)) if (dp_is_cr_done(lane_count, dpcd_lane_status))
return LINK_TRAINING_SUCCESS; return LINK_TRAINING_SUCCESS;
/* 6. max VS reached*/ /* 6. max VS reached*/
if (is_max_vs_reached(lt_settings)) if (dp_is_max_vs_reached(lt_settings))
break; break;
/* 7. same lane settings*/ /* 7. same lane settings*/
...@@ -1145,7 +1138,7 @@ static enum link_training_result perform_clock_recovery_sequence( ...@@ -1145,7 +1138,7 @@ static enum link_training_result perform_clock_recovery_sequence(
retries_cr = 0; retries_cr = 0;
/* 8. update VS/PE/PC2 in lt_settings*/ /* 8. update VS/PE/PC2 in lt_settings*/
update_drive_settings(lt_settings, req_settings); dp_update_drive_settings(lt_settings, req_settings);
retry_count++; retry_count++;
} }
...@@ -1158,7 +1151,7 @@ static enum link_training_result perform_clock_recovery_sequence( ...@@ -1158,7 +1151,7 @@ static enum link_training_result perform_clock_recovery_sequence(
} }
return get_cr_failure(lane_count, dpcd_lane_status); return dp_get_cr_failure(lane_count, dpcd_lane_status);
} }
static inline enum link_training_result dp_transition_to_video_idle( static inline enum link_training_result dp_transition_to_video_idle(
...@@ -1585,7 +1578,7 @@ bool dc_link_dp_perform_link_training_skip_aux( ...@@ -1585,7 +1578,7 @@ bool dc_link_dp_perform_link_training_skip_aux(
dp_set_hw_lane_settings(link, &lt_settings, DPRX); dp_set_hw_lane_settings(link, &lt_settings, DPRX);
/* wait receiver to lock-on*/ /* wait receiver to lock-on*/
wait_for_training_aux_rd_interval(link, lt_settings.cr_pattern_time); dp_wait_for_training_aux_rd_interval(link, lt_settings.cr_pattern_time);
/* 2. Perform_channel_equalization_sequence. */ /* 2. Perform_channel_equalization_sequence. */
...@@ -1596,7 +1589,7 @@ bool dc_link_dp_perform_link_training_skip_aux( ...@@ -1596,7 +1589,7 @@ bool dc_link_dp_perform_link_training_skip_aux(
dp_set_hw_lane_settings(link, &lt_settings, DPRX); dp_set_hw_lane_settings(link, &lt_settings, DPRX);
/* wait receiver to lock-on. */ /* wait receiver to lock-on. */
wait_for_training_aux_rd_interval(link, lt_settings.eq_pattern_time); dp_wait_for_training_aux_rd_interval(link, lt_settings.eq_pattern_time);
/* 3. Perform_link_training_int. */ /* 3. Perform_link_training_int. */
......
...@@ -30,11 +30,21 @@ ...@@ -30,11 +30,21 @@
#define LINK_TRAINING_RETRY_DELAY 50 /* ms */ #define LINK_TRAINING_RETRY_DELAY 50 /* ms */
#define LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD 3200 /*us*/ #define LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD 3200 /*us*/
#define LINK_AUX_DEFAULT_TIMEOUT_PERIOD 552 /*us*/ #define LINK_AUX_DEFAULT_TIMEOUT_PERIOD 552 /*us*/
#define DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE 0x50
#define TRAINING_AUX_RD_INTERVAL 100 //us
struct dc_link; struct dc_link;
struct dc_stream_state; struct dc_stream_state;
struct dc_link_settings; 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
};
bool dp_verify_link_cap( bool dp_verify_link_cap(
struct dc_link *link, struct dc_link *link,
struct dc_link_settings *known_limit_link_setting, struct dc_link_settings *known_limit_link_setting,
...@@ -96,6 +106,45 @@ void dpcd_set_source_specific_data(struct dc_link *link); ...@@ -96,6 +106,45 @@ void dpcd_set_source_specific_data(struct dc_link *link);
enum dc_status dpcd_set_link_settings( enum dc_status dpcd_set_link_settings(
struct dc_link *link, struct dc_link *link,
const struct link_training_settings *lt_settings); 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_drive_settings(
struct dc_link *link,
const struct link_training_settings *link_training_setting,
union lane_status *ln_status,
union lane_align_status_updated *ln_status_updated,
struct link_training_settings *req_settings,
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_max_vs_reached(
const struct link_training_settings *lt_settings);
void dp_update_drive_settings(
struct link_training_settings *dest,
struct link_training_settings src);
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, bool ready); enum dc_status dp_set_fec_ready(struct dc_link *link, bool ready);
void dp_set_fec_enable(struct dc_link *link, bool enable); void dp_set_fec_enable(struct dc_link *link, bool enable);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment