Commit 1d5b15f7 authored by Wesley Chalmers's avatar Wesley Chalmers Committed by Alex Deucher
Browse files

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: default avatarWesley Chalmers <Wesley.Chalmers@amd.com>
Reviewed-by: default avatarJun Lei <Jun.Lei@amd.com>
Acked-by: default avatarAnson Jacob <Anson.Jacob@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent d307ce4b
Loading
Loading
Loading
Loading
+15 −3
Original line number Diff line number Diff line
@@ -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;