Home | History | Annotate | Line # | Download | only in dce
      1 /*	$NetBSD: amdgpu_dce_aux.c,v 1.2 2021/12/18 23:45:02 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2012-15 Advanced Micro Devices, Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     22  * OTHER DEALINGS IN THE SOFTWARE.
     23  *
     24  * Authors: AMD
     25  *
     26  */
     27 
     28 #include <sys/cdefs.h>
     29 __KERNEL_RCSID(0, "$NetBSD: amdgpu_dce_aux.c,v 1.2 2021/12/18 23:45:02 riastradh Exp $");
     30 
     31 #include <linux/delay.h>
     32 #include <linux/slab.h>
     33 
     34 #include "dm_services.h"
     35 #include "core_types.h"
     36 #include "dce_aux.h"
     37 #include "dce/dce_11_0_sh_mask.h"
     38 #include "dm_event_log.h"
     39 
     40 #define CTX \
     41 	aux110->base.ctx
     42 #define REG(reg_name)\
     43 	(aux110->regs->reg_name)
     44 
     45 #define DC_LOGGER \
     46 	engine->ctx->logger
     47 
     48 #include "reg_helper.h"
     49 
     50 #undef FN
     51 #define FN(reg_name, field_name) \
     52 	aux110->shift->field_name, aux110->mask->field_name
     53 
     54 #define FROM_AUX_ENGINE(ptr) \
     55 	container_of((ptr), struct aux_engine_dce110, base)
     56 
     57 #define FROM_ENGINE(ptr) \
     58 	FROM_AUX_ENGINE(container_of((ptr), struct dce_aux, base))
     59 
     60 #define FROM_AUX_ENGINE_ENGINE(ptr) \
     61 	container_of((ptr), struct dce_aux, base)
     62 enum {
     63 	AUX_INVALID_REPLY_RETRY_COUNTER = 1,
     64 	AUX_TIMED_OUT_RETRY_COUNTER = 2,
     65 	AUX_DEFER_RETRY_COUNTER = 6
     66 };
     67 
     68 #define TIME_OUT_INCREMENT        1016
     69 #define TIME_OUT_MULTIPLIER_8     8
     70 #define TIME_OUT_MULTIPLIER_16    16
     71 #define TIME_OUT_MULTIPLIER_32    32
     72 #define TIME_OUT_MULTIPLIER_64    64
     73 #define MAX_TIMEOUT_LENGTH        127
     74 #define DEFAULT_AUX_ENGINE_MULT   0
     75 #define DEFAULT_AUX_ENGINE_LENGTH 69
     76 
     77 static void release_engine(
     78 	struct dce_aux *engine)
     79 {
     80 	struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
     81 
     82 	dal_ddc_close(engine->ddc);
     83 
     84 	engine->ddc = NULL;
     85 
     86 	REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_DONE_USING_AUX_REG, 1);
     87 }
     88 
     89 #define SW_CAN_ACCESS_AUX 1
     90 #define DMCU_CAN_ACCESS_AUX 2
     91 
     92 static bool is_engine_available(
     93 	struct dce_aux *engine)
     94 {
     95 	struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
     96 
     97 	uint32_t value = REG_READ(AUX_ARB_CONTROL);
     98 	uint32_t field = get_reg_field_value(
     99 			value,
    100 			AUX_ARB_CONTROL,
    101 			AUX_REG_RW_CNTL_STATUS);
    102 
    103 	return (field != DMCU_CAN_ACCESS_AUX);
    104 }
    105 static bool acquire_engine(
    106 	struct dce_aux *engine)
    107 {
    108 	struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
    109 
    110 	uint32_t value = REG_READ(AUX_ARB_CONTROL);
    111 	uint32_t field = get_reg_field_value(
    112 			value,
    113 			AUX_ARB_CONTROL,
    114 			AUX_REG_RW_CNTL_STATUS);
    115 	if (field == DMCU_CAN_ACCESS_AUX)
    116 		return false;
    117 	/* enable AUX before request SW to access AUX */
    118 	value = REG_READ(AUX_CONTROL);
    119 	field = get_reg_field_value(value,
    120 				AUX_CONTROL,
    121 				AUX_EN);
    122 
    123 	if (field == 0) {
    124 		set_reg_field_value(
    125 				value,
    126 				1,
    127 				AUX_CONTROL,
    128 				AUX_EN);
    129 
    130 		if (REG(AUX_RESET_MASK)) {
    131 			/*DP_AUX block as part of the enable sequence*/
    132 			set_reg_field_value(
    133 				value,
    134 				1,
    135 				AUX_CONTROL,
    136 				AUX_RESET);
    137 		}
    138 
    139 		REG_WRITE(AUX_CONTROL, value);
    140 
    141 		if (REG(AUX_RESET_MASK)) {
    142 			/*poll HW to make sure reset it done*/
    143 
    144 			REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 1,
    145 					1, 11);
    146 
    147 			set_reg_field_value(
    148 				value,
    149 				0,
    150 				AUX_CONTROL,
    151 				AUX_RESET);
    152 
    153 			REG_WRITE(AUX_CONTROL, value);
    154 
    155 			REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 0,
    156 					1, 11);
    157 		}
    158 	} /*if (field)*/
    159 
    160 	/* request SW to access AUX */
    161 	REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_USE_AUX_REG_REQ, 1);
    162 
    163 	value = REG_READ(AUX_ARB_CONTROL);
    164 	field = get_reg_field_value(
    165 			value,
    166 			AUX_ARB_CONTROL,
    167 			AUX_REG_RW_CNTL_STATUS);
    168 
    169 	return (field == SW_CAN_ACCESS_AUX);
    170 }
    171 
    172 #define COMPOSE_AUX_SW_DATA_16_20(command, address) \
    173 	((command) | ((0xF0000 & (address)) >> 16))
    174 
    175 #define COMPOSE_AUX_SW_DATA_8_15(address) \
    176 	((0xFF00 & (address)) >> 8)
    177 
    178 #define COMPOSE_AUX_SW_DATA_0_7(address) \
    179 	(0xFF & (address))
    180 
    181 static void submit_channel_request(
    182 	struct dce_aux *engine,
    183 	struct aux_request_transaction_data *request)
    184 {
    185 	struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
    186 	uint32_t value;
    187 	uint32_t length;
    188 
    189 	bool is_write =
    190 		((request->type == AUX_TRANSACTION_TYPE_DP) &&
    191 		 (request->action == I2CAUX_TRANSACTION_ACTION_DP_WRITE)) ||
    192 		((request->type == AUX_TRANSACTION_TYPE_I2C) &&
    193 		((request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) ||
    194 		 (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT)));
    195 	if (REG(AUXN_IMPCAL)) {
    196 		/* clear_aux_error */
    197 		REG_UPDATE_SEQ_2(AUXN_IMPCAL,
    198 				AUXN_CALOUT_ERROR_AK, 1,
    199 				AUXN_CALOUT_ERROR_AK, 0);
    200 
    201 		REG_UPDATE_SEQ_2(AUXP_IMPCAL,
    202 				AUXP_CALOUT_ERROR_AK, 1,
    203 				AUXP_CALOUT_ERROR_AK, 0);
    204 
    205 		/* force_default_calibrate */
    206 		REG_UPDATE_SEQ_2(AUXN_IMPCAL,
    207 				AUXN_IMPCAL_ENABLE, 1,
    208 				AUXN_IMPCAL_OVERRIDE_ENABLE, 0);
    209 
    210 		/* bug? why AUXN update EN and OVERRIDE_EN 1 by 1 while AUX P toggles OVERRIDE? */
    211 
    212 		REG_UPDATE_SEQ_2(AUXP_IMPCAL,
    213 				AUXP_IMPCAL_OVERRIDE_ENABLE, 1,
    214 				AUXP_IMPCAL_OVERRIDE_ENABLE, 0);
    215 	}
    216 
    217 	REG_UPDATE(AUX_INTERRUPT_CONTROL, AUX_SW_DONE_ACK, 1);
    218 
    219 	REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 0,
    220 				10, aux110->polling_timeout_period/10);
    221 
    222 	/* set the delay and the number of bytes to write */
    223 
    224 	/* The length include
    225 	 * the 4 bit header and the 20 bit address
    226 	 * (that is 3 byte).
    227 	 * If the requested length is non zero this means
    228 	 * an addition byte specifying the length is required.
    229 	 */
    230 
    231 	length = request->length ? 4 : 3;
    232 	if (is_write)
    233 		length += request->length;
    234 
    235 	REG_UPDATE_2(AUX_SW_CONTROL,
    236 			AUX_SW_START_DELAY, request->delay,
    237 			AUX_SW_WR_BYTES, length);
    238 
    239 	/* program action and address and payload data (if 'is_write') */
    240 	value = REG_UPDATE_4(AUX_SW_DATA,
    241 			AUX_SW_INDEX, 0,
    242 			AUX_SW_DATA_RW, 0,
    243 			AUX_SW_AUTOINCREMENT_DISABLE, 1,
    244 			AUX_SW_DATA, COMPOSE_AUX_SW_DATA_16_20(request->action, request->address));
    245 
    246 	value = REG_SET_2(AUX_SW_DATA, value,
    247 			AUX_SW_AUTOINCREMENT_DISABLE, 0,
    248 			AUX_SW_DATA, COMPOSE_AUX_SW_DATA_8_15(request->address));
    249 
    250 	value = REG_SET(AUX_SW_DATA, value,
    251 			AUX_SW_DATA, COMPOSE_AUX_SW_DATA_0_7(request->address));
    252 
    253 	if (request->length) {
    254 		value = REG_SET(AUX_SW_DATA, value,
    255 				AUX_SW_DATA, request->length - 1);
    256 	}
    257 
    258 	if (is_write) {
    259 		/* Load the HW buffer with the Data to be sent.
    260 		 * This is relevant for write operation.
    261 		 * For read, the data recived data will be
    262 		 * processed in process_channel_reply().
    263 		 */
    264 		uint32_t i = 0;
    265 
    266 		while (i < request->length) {
    267 			value = REG_SET(AUX_SW_DATA, value,
    268 					AUX_SW_DATA, request->data[i]);
    269 
    270 			++i;
    271 		}
    272 	}
    273 
    274 	REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1);
    275 	EVENT_LOG_AUX_REQ(engine->ddc->pin_data->en, EVENT_LOG_AUX_ORIGIN_NATIVE,
    276 					request->action, request->address, request->length, request->data);
    277 }
    278 
    279 static int read_channel_reply(struct dce_aux *engine, uint32_t size,
    280 			      uint8_t *buffer, uint8_t *reply_result,
    281 			      uint32_t *sw_status)
    282 {
    283 	struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
    284 	uint32_t bytes_replied;
    285 	uint32_t reply_result_32;
    286 
    287 	*sw_status = REG_GET(AUX_SW_STATUS, AUX_SW_REPLY_BYTE_COUNT,
    288 			     &bytes_replied);
    289 
    290 	/* In case HPD is LOW, exit AUX transaction */
    291 	if ((*sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
    292 		return -1;
    293 
    294 	/* Need at least the status byte */
    295 	if (!bytes_replied)
    296 		return -1;
    297 
    298 	REG_UPDATE_SEQ_3(AUX_SW_DATA,
    299 			  AUX_SW_INDEX, 0,
    300 			  AUX_SW_AUTOINCREMENT_DISABLE, 1,
    301 			  AUX_SW_DATA_RW, 1);
    302 
    303 	REG_GET(AUX_SW_DATA, AUX_SW_DATA, &reply_result_32);
    304 	reply_result_32 = reply_result_32 >> 4;
    305 	if (reply_result != NULL)
    306 		*reply_result = (uint8_t)reply_result_32;
    307 
    308 	if (reply_result_32 == 0) { /* ACK */
    309 		uint32_t i = 0;
    310 
    311 		/* First byte was already used to get the command status */
    312 		--bytes_replied;
    313 
    314 		/* Do not overflow buffer */
    315 		if (bytes_replied > size)
    316 			return -1;
    317 
    318 		while (i < bytes_replied) {
    319 			uint32_t aux_sw_data_val;
    320 
    321 			REG_GET(AUX_SW_DATA, AUX_SW_DATA, &aux_sw_data_val);
    322 			buffer[i] = aux_sw_data_val;
    323 			++i;
    324 		}
    325 
    326 		return i;
    327 	}
    328 
    329 	return 0;
    330 }
    331 
    332 static enum aux_channel_operation_result get_channel_status(
    333 	struct dce_aux *engine,
    334 	uint8_t *returned_bytes)
    335 {
    336 	struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
    337 
    338 	uint32_t value;
    339 
    340 	if (returned_bytes == NULL) {
    341 		/*caller pass NULL pointer*/
    342 		ASSERT_CRITICAL(false);
    343 		return AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN;
    344 	}
    345 	*returned_bytes = 0;
    346 
    347 	/* poll to make sure that SW_DONE is asserted */
    348 	REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 1,
    349 				10, aux110->polling_timeout_period/10);
    350 
    351 	value = REG_READ(AUX_SW_STATUS);
    352 	/* in case HPD is LOW, exit AUX transaction */
    353 	if ((value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
    354 		return AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON;
    355 
    356 	/* Note that the following bits are set in 'status.bits'
    357 	 * during CTS 4.2.1.2 (FW 3.3.1):
    358 	 * AUX_SW_RX_MIN_COUNT_VIOL, AUX_SW_RX_INVALID_STOP,
    359 	 * AUX_SW_RX_RECV_NO_DET, AUX_SW_RX_RECV_INVALID_H.
    360 	 *
    361 	 * AUX_SW_RX_MIN_COUNT_VIOL is an internal,
    362 	 * HW debugging bit and should be ignored.
    363 	 */
    364 	if (value & AUX_SW_STATUS__AUX_SW_DONE_MASK) {
    365 		if ((value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_STATE_MASK) ||
    366 			(value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_MASK))
    367 			return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
    368 
    369 		else if ((value & AUX_SW_STATUS__AUX_SW_RX_INVALID_STOP_MASK) ||
    370 			(value & AUX_SW_STATUS__AUX_SW_RX_RECV_NO_DET_MASK) ||
    371 			(value &
    372 				AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_H_MASK) ||
    373 			(value & AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_L_MASK))
    374 			return AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
    375 
    376 		*returned_bytes = get_reg_field_value(value,
    377 				AUX_SW_STATUS,
    378 				AUX_SW_REPLY_BYTE_COUNT);
    379 
    380 		if (*returned_bytes == 0)
    381 			return
    382 			AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
    383 		else {
    384 			*returned_bytes -= 1;
    385 			return AUX_CHANNEL_OPERATION_SUCCEEDED;
    386 		}
    387 	} else {
    388 		/*time_elapsed >= aux_engine->timeout_period
    389 		 *  AUX_SW_STATUS__AUX_SW_HPD_DISCON = at this point
    390 		 */
    391 		ASSERT_CRITICAL(false);
    392 		return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
    393 	}
    394 }
    395 
    396 enum i2caux_engine_type get_engine_type(
    397 		const struct dce_aux *engine)
    398 {
    399 	return I2CAUX_ENGINE_TYPE_AUX;
    400 }
    401 
    402 static bool acquire(
    403 	struct dce_aux *engine,
    404 	struct ddc *ddc)
    405 {
    406 	enum gpio_result result;
    407 
    408 	if ((engine == NULL) || !is_engine_available(engine))
    409 		return false;
    410 
    411 	result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
    412 		GPIO_DDC_CONFIG_TYPE_MODE_AUX);
    413 
    414 	if (result != GPIO_RESULT_OK)
    415 		return false;
    416 
    417 	if (!acquire_engine(engine)) {
    418 		dal_ddc_close(ddc);
    419 		return false;
    420 	}
    421 
    422 	engine->ddc = ddc;
    423 
    424 	return true;
    425 }
    426 
    427 void dce110_engine_destroy(struct dce_aux **engine)
    428 {
    429 
    430 	struct aux_engine_dce110 *engine110 = FROM_AUX_ENGINE(*engine);
    431 
    432 	kfree(engine110);
    433 	*engine = NULL;
    434 
    435 }
    436 
    437 static uint32_t dce_aux_configure_timeout(struct ddc_service *ddc,
    438 		uint32_t timeout_in_us)
    439 {
    440 	uint32_t multiplier = 0;
    441 	uint32_t length = 0;
    442 	uint32_t prev_length = 0;
    443 	uint32_t prev_mult = 0;
    444 	uint32_t prev_timeout_val = 0;
    445 	struct ddc *ddc_pin = ddc->ddc_pin;
    446 	struct dce_aux *aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en];
    447 	struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(aux_engine);
    448 
    449 	/* 1-Update polling timeout period */
    450 	aux110->polling_timeout_period = timeout_in_us * SW_AUX_TIMEOUT_PERIOD_MULTIPLIER;
    451 
    452 	/* 2-Update aux timeout period length and multiplier */
    453 	if (timeout_in_us == 0) {
    454 		multiplier = DEFAULT_AUX_ENGINE_MULT;
    455 		length = DEFAULT_AUX_ENGINE_LENGTH;
    456 	} else if (timeout_in_us <= TIME_OUT_INCREMENT) {
    457 		multiplier = 0;
    458 		length = timeout_in_us/TIME_OUT_MULTIPLIER_8;
    459 		if (timeout_in_us % TIME_OUT_MULTIPLIER_8 != 0)
    460 			length++;
    461 	} else if (timeout_in_us <= 2 * TIME_OUT_INCREMENT) {
    462 		multiplier = 1;
    463 		length = timeout_in_us/TIME_OUT_MULTIPLIER_16;
    464 		if (timeout_in_us % TIME_OUT_MULTIPLIER_16 != 0)
    465 			length++;
    466 	} else if (timeout_in_us <= 4 * TIME_OUT_INCREMENT) {
    467 		multiplier = 2;
    468 		length = timeout_in_us/TIME_OUT_MULTIPLIER_32;
    469 		if (timeout_in_us % TIME_OUT_MULTIPLIER_32 != 0)
    470 			length++;
    471 	} else if (timeout_in_us > 4 * TIME_OUT_INCREMENT) {
    472 		multiplier = 3;
    473 		length = timeout_in_us/TIME_OUT_MULTIPLIER_64;
    474 		if (timeout_in_us % TIME_OUT_MULTIPLIER_64 != 0)
    475 			length++;
    476 	}
    477 
    478 	length = (length < MAX_TIMEOUT_LENGTH) ? length : MAX_TIMEOUT_LENGTH;
    479 
    480 	REG_GET_2(AUX_DPHY_RX_CONTROL1, AUX_RX_TIMEOUT_LEN, &prev_length, AUX_RX_TIMEOUT_LEN_MUL, &prev_mult);
    481 
    482 	switch (prev_mult) {
    483 	case 0:
    484 		prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_8;
    485 		break;
    486 	case 1:
    487 		prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_16;
    488 		break;
    489 	case 2:
    490 		prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_32;
    491 		break;
    492 	case 3:
    493 		prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_64;
    494 		break;
    495 	default:
    496 		prev_timeout_val = DEFAULT_AUX_ENGINE_LENGTH * TIME_OUT_MULTIPLIER_8;
    497 		break;
    498 	}
    499 
    500 	REG_UPDATE_SEQ_2(AUX_DPHY_RX_CONTROL1, AUX_RX_TIMEOUT_LEN, length, AUX_RX_TIMEOUT_LEN_MUL, multiplier);
    501 
    502 	return prev_timeout_val;
    503 }
    504 
    505 static struct dce_aux_funcs aux_functions = {
    506 	.configure_timeout = NULL,
    507 	.destroy = NULL,
    508 };
    509 
    510 struct dce_aux *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_engine110,
    511 		struct dc_context *ctx,
    512 		uint32_t inst,
    513 		uint32_t timeout_period,
    514 		const struct dce110_aux_registers *regs,
    515 		const struct dce110_aux_registers_mask *mask,
    516 		const struct dce110_aux_registers_shift *shift,
    517 		bool is_ext_aux_timeout_configurable)
    518 {
    519 	aux_engine110->base.ddc = NULL;
    520 	aux_engine110->base.ctx = ctx;
    521 	aux_engine110->base.delay = 0;
    522 	aux_engine110->base.max_defer_write_retry = 0;
    523 	aux_engine110->base.inst = inst;
    524 	aux_engine110->polling_timeout_period = timeout_period;
    525 	aux_engine110->regs = regs;
    526 
    527 	aux_engine110->mask = mask;
    528 	aux_engine110->shift = shift;
    529 	aux_engine110->base.funcs = &aux_functions;
    530 	if (is_ext_aux_timeout_configurable)
    531 		aux_engine110->base.funcs->configure_timeout = &dce_aux_configure_timeout;
    532 
    533 	return &aux_engine110->base;
    534 }
    535 
    536 static enum i2caux_transaction_action i2caux_action_from_payload(struct aux_payload *payload)
    537 {
    538 	if (payload->i2c_over_aux) {
    539 		if (payload->write) {
    540 			if (payload->mot)
    541 				return I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT;
    542 			return I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
    543 		}
    544 		if (payload->mot)
    545 			return I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT;
    546 		return I2CAUX_TRANSACTION_ACTION_I2C_READ;
    547 	}
    548 	if (payload->write)
    549 		return I2CAUX_TRANSACTION_ACTION_DP_WRITE;
    550 	return I2CAUX_TRANSACTION_ACTION_DP_READ;
    551 }
    552 
    553 int dce_aux_transfer_raw(struct ddc_service *ddc,
    554 		struct aux_payload *payload,
    555 		enum aux_channel_operation_result *operation_result)
    556 {
    557 	struct ddc *ddc_pin = ddc->ddc_pin;
    558 	struct dce_aux *aux_engine;
    559 	struct aux_request_transaction_data aux_req;
    560 	struct aux_reply_transaction_data aux_rep;
    561 	uint8_t returned_bytes = 0;
    562 	int res = -1;
    563 	uint32_t status;
    564 
    565 	memset(&aux_req, 0, sizeof(aux_req));
    566 	memset(&aux_rep, 0, sizeof(aux_rep));
    567 
    568 	aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en];
    569 	if (!acquire(aux_engine, ddc_pin)) {
    570 		*operation_result = AUX_CHANNEL_OPERATION_FAILED_ENGINE_ACQUIRE;
    571 		return -1;
    572 	}
    573 
    574 	if (payload->i2c_over_aux)
    575 		aux_req.type = AUX_TRANSACTION_TYPE_I2C;
    576 	else
    577 		aux_req.type = AUX_TRANSACTION_TYPE_DP;
    578 
    579 	aux_req.action = i2caux_action_from_payload(payload);
    580 
    581 	aux_req.address = payload->address;
    582 	aux_req.delay = 0;
    583 	aux_req.length = payload->length;
    584 	aux_req.data = payload->data;
    585 
    586 	submit_channel_request(aux_engine, &aux_req);
    587 	*operation_result = get_channel_status(aux_engine, &returned_bytes);
    588 
    589 	if (*operation_result == AUX_CHANNEL_OPERATION_SUCCEEDED) {
    590 		int bytes_replied = 0;
    591 		bytes_replied = read_channel_reply(aux_engine, payload->length,
    592 					 payload->data, payload->reply,
    593 					 &status);
    594 		EVENT_LOG_AUX_REP(aux_engine->ddc->pin_data->en,
    595 					EVENT_LOG_AUX_ORIGIN_NATIVE, *payload->reply,
    596 					bytes_replied, payload->data);
    597 		res = returned_bytes;
    598 	} else {
    599 		res = -1;
    600 	}
    601 
    602 	release_engine(aux_engine);
    603 	return res;
    604 }
    605 
    606 #define AUX_MAX_RETRIES 7
    607 #define AUX_MAX_DEFER_RETRIES 7
    608 #define AUX_MAX_I2C_DEFER_RETRIES 7
    609 #define AUX_MAX_INVALID_REPLY_RETRIES 2
    610 #define AUX_MAX_TIMEOUT_RETRIES 3
    611 
    612 bool dce_aux_transfer_with_retries(struct ddc_service *ddc,
    613 		struct aux_payload *payload)
    614 {
    615 	int i, ret = 0;
    616 	uint8_t reply;
    617 	bool payload_reply = true;
    618 	enum aux_channel_operation_result operation_result;
    619 	bool retry_on_defer = false;
    620 
    621 	int aux_ack_retries = 0,
    622 		aux_defer_retries = 0,
    623 		aux_i2c_defer_retries = 0,
    624 		aux_timeout_retries = 0,
    625 		aux_invalid_reply_retries = 0;
    626 
    627 	if (!payload->reply) {
    628 		payload_reply = false;
    629 		payload->reply = &reply;
    630 	}
    631 
    632 	for (i = 0; i < AUX_MAX_RETRIES; i++) {
    633 		ret = dce_aux_transfer_raw(ddc, payload, &operation_result);
    634 		switch (operation_result) {
    635 		case AUX_CHANNEL_OPERATION_SUCCEEDED:
    636 			aux_timeout_retries = 0;
    637 			aux_invalid_reply_retries = 0;
    638 
    639 			switch (*payload->reply) {
    640 			case AUX_TRANSACTION_REPLY_AUX_ACK:
    641 				if (!payload->write && payload->length != ret) {
    642 					if (++aux_ack_retries >= AUX_MAX_RETRIES)
    643 						goto fail;
    644 					else
    645 						udelay(300);
    646 				} else
    647 					return true;
    648 			break;
    649 
    650 			case AUX_TRANSACTION_REPLY_AUX_DEFER:
    651 			case AUX_TRANSACTION_REPLY_I2C_OVER_AUX_DEFER:
    652 				retry_on_defer = true;
    653 				/* fall through */
    654 			case AUX_TRANSACTION_REPLY_I2C_OVER_AUX_NACK:
    655 				if (++aux_defer_retries >= AUX_MAX_DEFER_RETRIES) {
    656 					goto fail;
    657 				} else {
    658 					if ((*payload->reply == AUX_TRANSACTION_REPLY_AUX_DEFER) ||
    659 						(*payload->reply == AUX_TRANSACTION_REPLY_I2C_OVER_AUX_DEFER)) {
    660 						if (payload->defer_delay > 0)
    661 							msleep(payload->defer_delay);
    662 					}
    663 				}
    664 				break;
    665 
    666 			case AUX_TRANSACTION_REPLY_I2C_DEFER:
    667 				aux_defer_retries = 0;
    668 				if (++aux_i2c_defer_retries >= AUX_MAX_I2C_DEFER_RETRIES)
    669 					goto fail;
    670 				break;
    671 
    672 			case AUX_TRANSACTION_REPLY_AUX_NACK:
    673 			case AUX_TRANSACTION_REPLY_HPD_DISCON:
    674 			default:
    675 				goto fail;
    676 			}
    677 			break;
    678 
    679 		case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
    680 			if (++aux_invalid_reply_retries >= AUX_MAX_INVALID_REPLY_RETRIES)
    681 				goto fail;
    682 			else
    683 				udelay(400);
    684 			break;
    685 
    686 		case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
    687 			// Check whether a DEFER had occurred before the timeout.
    688 			// If so, treat timeout as a DEFER.
    689 			if (retry_on_defer) {
    690 				if (++aux_defer_retries >= AUX_MAX_DEFER_RETRIES)
    691 					goto fail;
    692 				else if (payload->defer_delay > 0)
    693 					msleep(payload->defer_delay);
    694 			} else {
    695 				if (++aux_timeout_retries >= AUX_MAX_TIMEOUT_RETRIES)
    696 					goto fail;
    697 				else {
    698 					/*
    699 					 * DP 1.4, 2.8.2:  AUX Transaction Response/Reply Timeouts
    700 					 * According to the DP spec there should be 3 retries total
    701 					 * with a 400us wait inbetween each. Hardware already waits
    702 					 * for 550us therefore no wait is required here.
    703 					 */
    704 				}
    705 			}
    706 			break;
    707 
    708 		case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
    709 		case AUX_CHANNEL_OPERATION_FAILED_ENGINE_ACQUIRE:
    710 		case AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN:
    711 		default:
    712 			goto fail;
    713 		}
    714 	}
    715 
    716 fail:
    717 	if (!payload_reply)
    718 		payload->reply = NULL;
    719 	return false;
    720 }
    721