From 1d5b15f77e3567d2497dad69c99a307dd6379c8f Mon Sep 17 00:00:00 2001 From: Wesley Chalmers Date: Mon, 29 Mar 2021 13:27:47 -0400 Subject: [PATCH] drm/amd/display: 7 retries + 50 ms timeout on AUX DEFER [WHY] DP 2.0 SCR specifies that TX devices must retry at least 7 times when receiving an AUX DEFER reply from RX. In addition, the specification states that the TX shall not retry indefinitely, and gives a suggestive timeout interval of 50ms. [HOW] Keep retrying until both 7 or more retries have been made, and the 50ms interval has passed. Signed-off-by: Wesley Chalmers Reviewed-by: Jun Lei Acked-by: Anson Jacob Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dce/dce_aux.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c index 9d5e09b..49cb4e6 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c @@ -616,6 +616,7 @@ int dce_aux_transfer_dmub_raw(struct ddc_service *ddc, #define AUX_MAX_RETRIES 7 #define AUX_MIN_DEFER_RETRIES 7 +#define AUX_MAX_DEFER_TIMEOUT_MS 50 #define AUX_MAX_I2C_DEFER_RETRIES 7 #define AUX_MAX_INVALID_REPLY_RETRIES 2 #define AUX_MAX_TIMEOUT_RETRIES 3 @@ -628,6 +629,10 @@ bool dce_aux_transfer_with_retries(struct ddc_service *ddc, bool payload_reply = true; enum aux_return_code_type operation_result; bool retry_on_defer = false; + struct ddc *ddc_pin = ddc->ddc_pin; + struct dce_aux *aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]; + struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(aux_engine); + uint32_t defer_time_in_ms = 0; int aux_ack_retries = 0, aux_defer_retries = 0, @@ -660,19 +665,26 @@ bool dce_aux_transfer_with_retries(struct ddc_service *ddc, break; case AUX_TRANSACTION_REPLY_AUX_DEFER: + /* polling_timeout_period is in us */ + defer_time_in_ms += aux110->polling_timeout_period / 1000; + /* fall through */ case AUX_TRANSACTION_REPLY_I2C_OVER_AUX_DEFER: retry_on_defer = true; fallthrough; case AUX_TRANSACTION_REPLY_I2C_OVER_AUX_NACK: - if (++aux_defer_retries >= AUX_MIN_DEFER_RETRIES) { + if (++aux_defer_retries >= AUX_MIN_DEFER_RETRIES + && defer_time_in_ms >= AUX_MAX_DEFER_TIMEOUT_MS) { goto fail; } else { if ((*payload->reply == AUX_TRANSACTION_REPLY_AUX_DEFER) || (*payload->reply == AUX_TRANSACTION_REPLY_I2C_OVER_AUX_DEFER)) { - if (payload->defer_delay > 1) + if (payload->defer_delay > 1) { msleep(payload->defer_delay); - else if (payload->defer_delay <= 1) + defer_time_in_ms += payload->defer_delay; + } else if (payload->defer_delay <= 1) { udelay(payload->defer_delay * 1000); + defer_time_in_ms += payload->defer_delay; + } } } break; -- 2.7.4