From: Ilya Bakoulin <[email protected]> [Why/How] Current method of keeping track of the LT timeout can cause the actual elapsed time to creep past the spec-defined limits.
Adjust the behavior to make timeouts more consistent. Signed-off-by: Ilya Bakoulin <[email protected]> Signed-off-by: Fangzhi Zuo <[email protected]> Reviewed-by: Chris Park <[email protected]> Reviewed-by: Charlene Liu <[email protected]> --- .../display/dc/link/protocols/link_hdmi_frl.c | 58 +++++++++++-------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_hdmi_frl.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_hdmi_frl.c index 7f930097da18..2f1b8c0bc8f8 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_hdmi_frl.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_hdmi_frl.c @@ -442,9 +442,9 @@ static enum link_result hdmi_frl_perform_link_training(struct ddc_service *ddc_s union hdmi_scdc_status_flags_data status_data = {0}; union hdmi_scdc_source_test_req test_req = {0}; union hdmi_scdc_LTP_req_data ltp_req = {0}; - uint16_t num_polls = 0; - uint16_t max_polls = 105; - unsigned long long wait_time_ns = 2000000; + unsigned long long poll_timeout_ns = 200 * 1000 * 1000; + unsigned long long wait_time_ns = 2 * 1000 * 1000; + unsigned long long num_polls = 0; struct hpo_frl_link_encoder *hpo_frl_link_enc = ddc_service->link->hpo_frl_link_enc; struct link_encoder *dio_link_enc = ddc_service->link->link_enc; uint8_t sink_version = 0; @@ -452,7 +452,6 @@ static enum link_result hdmi_frl_perform_link_training(struct ddc_service *ddc_s uint8_t current_FFE = 0; bool override_FFE = false; bool flt_no_timeout = false; - unsigned long long flt_poll_cur_time = 0, flt_poll_last_time = 0, flt_poll_elapsed_time_ns = 0; DC_LOGGER_INIT(ddc_service->link->ctx->logger); FRL_INFO("FRL LINK TRAINING: Starting FRL Link Training.\n"); @@ -483,18 +482,22 @@ static enum link_result hdmi_frl_perform_link_training(struct ddc_service *ddc_s offset = HDMI_SCDC_STATUS_FLAGS; /*LTS:2: Check FLT Ready, poll for 200ms */ - while (num_polls < max_polls) { - flt_poll_cur_time = dm_get_timestamp(ddc_service->ctx); - flt_poll_elapsed_time_ns = dm_get_elapse_time_in_ns(ddc_service->ctx, flt_poll_cur_time, flt_poll_last_time); - if (flt_poll_elapsed_time_ns < wait_time_ns) + unsigned long long flt_poll_start = dm_get_timestamp(ddc_service->ctx); + unsigned long long flt_poll_curr = flt_poll_start; + unsigned long long elapsed = 0; + + do { + flt_poll_curr = dm_get_timestamp(ddc_service->ctx); + elapsed = dm_get_elapse_time_in_ns(ddc_service->ctx, + flt_poll_curr, flt_poll_start); + if (elapsed < (num_polls * wait_time_ns)) continue; - flt_poll_last_time = dm_get_timestamp(ddc_service->ctx); num_polls++; link_query_ddc_data(ddc_service, slave_address, &offset, sizeof(offset), &status_data.byte, sizeof(status_data.byte)); - FRL_INFO("FRL LINK TRAINING: Read FLT_READY = %d. num_polls = %d\n", + FRL_INFO("FRL LINK TRAINING: Read FLT_READY = %d. num_polls = %llu\n", status_data.fields.FLT_READY, num_polls); if (status_data.fields.FLT_READY) { /* Spec recommends to clear update flag, but QD980 has problem */ @@ -506,7 +509,7 @@ static enum link_result hdmi_frl_perform_link_training(struct ddc_service *ddc_s link_settings); break; } - } + } while (elapsed < poll_timeout_ns); /*Test Condition - FLT_no_timeout avoid link training*/ offset = HDMI_SCDC_SOURCE_TEST_REQ; @@ -531,15 +534,19 @@ static enum link_result hdmi_frl_perform_link_training(struct ddc_service *ddc_s /*Start FLT Timer = 200 ms, or 300ms if link rate >= 16Gbps*/ num_polls = 0; if (link_settings->frl_link_rate >= HDMI_FRL_LINK_RATE_16GBPS) - max_polls = 155; - - while (num_polls < max_polls) { - flt_poll_cur_time = dm_get_timestamp(ddc_service->ctx); - flt_poll_elapsed_time_ns = dm_get_elapse_time_in_ns(ddc_service->ctx, flt_poll_cur_time, flt_poll_last_time); - if (flt_poll_elapsed_time_ns < wait_time_ns) + poll_timeout_ns = 300 * 1000 * 1000; + if (flt_no_timeout) + poll_timeout_ns = 1000 * 1000 * 1000; + + flt_poll_start = dm_get_timestamp(ddc_service->ctx); + uint8_t prev_flt_update = 0; + + do { + flt_poll_curr = dm_get_timestamp(ddc_service->ctx); + elapsed = dm_get_elapse_time_in_ns(ddc_service->ctx, + flt_poll_curr, flt_poll_start); + if (elapsed < (num_polls * wait_time_ns)) continue; - flt_poll_last_time = flt_poll_cur_time; - num_polls++; offset = HDMI_SCDC_UPDATE_0; @@ -548,8 +555,12 @@ static enum link_result hdmi_frl_perform_link_training(struct ddc_service *ddc_s &offset, sizeof(offset), &scdc_update.byte[0], sizeof(scdc_update.byte[0])); - FRL_INFO("FRL LINK TRAINING: Read FLT_UPDATE = %d. num_polls = %d\n", - scdc_update.fields.FLT_UPDATE, num_polls); + if (prev_flt_update != scdc_update.fields.FLT_UPDATE) { + FRL_INFO("FRL LINK TRAINING: FLT_UPDATE=%d polls=%llu\n", + scdc_update.fields.FLT_UPDATE, num_polls); + prev_flt_update = scdc_update.fields.FLT_UPDATE; + } + /*Set TxFFE = TxFFE0*/ /*Program FFE_Levels - scdc_config has this field at 0 */ if (override_FFE) { @@ -680,11 +691,8 @@ static enum link_result hdmi_frl_perform_link_training(struct ddc_service *ddc_s /* Workaround for DEDCN3AG-111 * HDMI-FRL Incorrect Serialization Order for LTP4 */ - if (flt_no_timeout) { - return LINK_RESULT_SUCCESS; - } } - } + } while (elapsed < poll_timeout_ns); FRL_INFO("FRL LINK TRAINING: FAILED - Timeout waiting for FLT_UPDATE to be set by sink.\n"); write_buffer[0] = HDMI_SCDC_CONFIG_1; /*FRL_RATE*/ -- 2.53.0
