1/*
2 * Copyright 2012-15 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: AMD
23 *
24 */
25
26#include "dm_services.h"
27#include "core_types.h"
28#include "dce_aux.h"
29#include "dce/dce_11_0_sh_mask.h"
30#include "dm_event_log.h"
31#include "dm_helpers.h"
32#include "dmub/inc/dmub_cmd.h"
33
34#define CTX \
35	aux110->base.ctx
36#define REG(reg_name)\
37	(aux110->regs->reg_name)
38
39#define DC_LOGGER \
40	engine->ctx->logger
41
42#define DC_TRACE_LEVEL_MESSAGE(...) do { } while (0)
43#define IS_DC_I2CAUX_LOGGING_ENABLED() (false)
44#define LOG_FLAG_Error_I2cAux LOG_ERROR
45#define LOG_FLAG_I2cAux_DceAux LOG_I2C_AUX
46
47#include "reg_helper.h"
48
49#undef FN
50#define FN(reg_name, field_name) \
51	aux110->shift->field_name, aux110->mask->field_name
52
53#define FROM_AUX_ENGINE(ptr) \
54	container_of((ptr), struct aux_engine_dce110, base)
55
56#define FROM_ENGINE(ptr) \
57	FROM_AUX_ENGINE(container_of((ptr), struct dce_aux, base))
58
59#define FROM_AUX_ENGINE_ENGINE(ptr) \
60	container_of((ptr), struct dce_aux, base)
61enum {
62	AUX_INVALID_REPLY_RETRY_COUNTER = 1,
63	AUX_TIMED_OUT_RETRY_COUNTER = 2,
64	AUX_DEFER_RETRY_COUNTER = 6
65};
66
67#define TIME_OUT_INCREMENT        1016
68#define TIME_OUT_MULTIPLIER_8     8
69#define TIME_OUT_MULTIPLIER_16    16
70#define TIME_OUT_MULTIPLIER_32    32
71#define TIME_OUT_MULTIPLIER_64    64
72#define MAX_TIMEOUT_LENGTH        127
73#define DEFAULT_AUX_ENGINE_MULT   0
74#define DEFAULT_AUX_ENGINE_LENGTH 69
75
76#define DC_TRACE_LEVEL_MESSAGE(...) do { } while (0)
77
78static void release_engine(
79	struct dce_aux *engine)
80{
81	struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
82
83	dal_ddc_close(engine->ddc);
84
85	engine->ddc = NULL;
86
87	REG_UPDATE_2(AUX_ARB_CONTROL, AUX_SW_DONE_USING_AUX_REG, 1,
88		AUX_SW_USE_AUX_REG_REQ, 0);
89}
90
91#define SW_CAN_ACCESS_AUX 1
92#define DMCU_CAN_ACCESS_AUX 2
93
94static bool is_engine_available(
95	struct dce_aux *engine)
96{
97	struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
98
99	uint32_t value = REG_READ(AUX_ARB_CONTROL);
100	uint32_t field = get_reg_field_value(
101			value,
102			AUX_ARB_CONTROL,
103			AUX_REG_RW_CNTL_STATUS);
104
105	return (field != DMCU_CAN_ACCESS_AUX);
106}
107static bool acquire_engine(
108	struct dce_aux *engine)
109{
110	struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
111
112	uint32_t value = REG_READ(AUX_ARB_CONTROL);
113	uint32_t field = get_reg_field_value(
114			value,
115			AUX_ARB_CONTROL,
116			AUX_REG_RW_CNTL_STATUS);
117	if (field == DMCU_CAN_ACCESS_AUX)
118		return false;
119	/* enable AUX before request SW to access AUX */
120	value = REG_READ(AUX_CONTROL);
121	field = get_reg_field_value(value,
122				AUX_CONTROL,
123				AUX_EN);
124
125	if (field == 0) {
126		set_reg_field_value(
127				value,
128				1,
129				AUX_CONTROL,
130				AUX_EN);
131
132		if (REG(AUX_RESET_MASK)) {
133			/*DP_AUX block as part of the enable sequence*/
134			set_reg_field_value(
135				value,
136				1,
137				AUX_CONTROL,
138				AUX_RESET);
139		}
140
141		REG_WRITE(AUX_CONTROL, value);
142
143		if (REG(AUX_RESET_MASK)) {
144			/*poll HW to make sure reset it done*/
145
146			REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 1,
147					1, 11);
148
149			set_reg_field_value(
150				value,
151				0,
152				AUX_CONTROL,
153				AUX_RESET);
154
155			REG_WRITE(AUX_CONTROL, value);
156
157			REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 0,
158					1, 11);
159		}
160	} /*if (field)*/
161
162	/* request SW to access AUX */
163	REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_USE_AUX_REG_REQ, 1);
164
165	value = REG_READ(AUX_ARB_CONTROL);
166	field = get_reg_field_value(
167			value,
168			AUX_ARB_CONTROL,
169			AUX_REG_RW_CNTL_STATUS);
170
171	return (field == SW_CAN_ACCESS_AUX);
172}
173
174#define COMPOSE_AUX_SW_DATA_16_20(command, address) \
175	((command) | ((0xF0000 & (address)) >> 16))
176
177#define COMPOSE_AUX_SW_DATA_8_15(address) \
178	((0xFF00 & (address)) >> 8)
179
180#define COMPOSE_AUX_SW_DATA_0_7(address) \
181	(0xFF & (address))
182
183static void submit_channel_request(
184	struct dce_aux *engine,
185	struct aux_request_transaction_data *request)
186{
187	struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
188	uint32_t value;
189	uint32_t length;
190
191	bool is_write =
192		((request->type == AUX_TRANSACTION_TYPE_DP) &&
193		 (request->action == I2CAUX_TRANSACTION_ACTION_DP_WRITE)) ||
194		((request->type == AUX_TRANSACTION_TYPE_I2C) &&
195		((request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) ||
196		 (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT)));
197	if (REG(AUXN_IMPCAL)) {
198		/* clear_aux_error */
199		REG_UPDATE_SEQ_2(AUXN_IMPCAL,
200				AUXN_CALOUT_ERROR_AK, 1,
201				AUXN_CALOUT_ERROR_AK, 0);
202
203		REG_UPDATE_SEQ_2(AUXP_IMPCAL,
204				AUXP_CALOUT_ERROR_AK, 1,
205				AUXP_CALOUT_ERROR_AK, 0);
206
207		/* force_default_calibrate */
208		REG_UPDATE_SEQ_2(AUXN_IMPCAL,
209				AUXN_IMPCAL_ENABLE, 1,
210				AUXN_IMPCAL_OVERRIDE_ENABLE, 0);
211
212		/* bug? why AUXN update EN and OVERRIDE_EN 1 by 1 while AUX P toggles OVERRIDE? */
213
214		REG_UPDATE_SEQ_2(AUXP_IMPCAL,
215				AUXP_IMPCAL_OVERRIDE_ENABLE, 1,
216				AUXP_IMPCAL_OVERRIDE_ENABLE, 0);
217	}
218
219	REG_UPDATE(AUX_INTERRUPT_CONTROL, AUX_SW_DONE_ACK, 1);
220
221	REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 0,
222				10, aux110->polling_timeout_period/10);
223
224	/* set the delay and the number of bytes to write */
225
226	/* The length include
227	 * the 4 bit header and the 20 bit address
228	 * (that is 3 byte).
229	 * If the requested length is non zero this means
230	 * an addition byte specifying the length is required.
231	 */
232
233	length = request->length ? 4 : 3;
234	if (is_write)
235		length += request->length;
236
237	REG_UPDATE_2(AUX_SW_CONTROL,
238			AUX_SW_START_DELAY, request->delay,
239			AUX_SW_WR_BYTES, length);
240
241	/* program action and address and payload data (if 'is_write') */
242	value = REG_UPDATE_4(AUX_SW_DATA,
243			AUX_SW_INDEX, 0,
244			AUX_SW_DATA_RW, 0,
245			AUX_SW_AUTOINCREMENT_DISABLE, 1,
246			AUX_SW_DATA, COMPOSE_AUX_SW_DATA_16_20(request->action, request->address));
247
248	value = REG_SET_2(AUX_SW_DATA, value,
249			AUX_SW_AUTOINCREMENT_DISABLE, 0,
250			AUX_SW_DATA, COMPOSE_AUX_SW_DATA_8_15(request->address));
251
252	value = REG_SET(AUX_SW_DATA, value,
253			AUX_SW_DATA, COMPOSE_AUX_SW_DATA_0_7(request->address));
254
255	if (request->length) {
256		value = REG_SET(AUX_SW_DATA, value,
257				AUX_SW_DATA, request->length - 1);
258	}
259
260	if (is_write) {
261		/* Load the HW buffer with the Data to be sent.
262		 * This is relevant for write operation.
263		 * For read, the data recived data will be
264		 * processed in process_channel_reply().
265		 */
266		uint32_t i = 0;
267
268		while (i < request->length) {
269			value = REG_SET(AUX_SW_DATA, value,
270					AUX_SW_DATA, request->data[i]);
271
272			++i;
273		}
274	}
275
276	REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1);
277	EVENT_LOG_AUX_REQ(engine->ddc->pin_data->en, EVENT_LOG_AUX_ORIGIN_NATIVE,
278					request->action, request->address, request->length, request->data);
279}
280
281static int read_channel_reply(struct dce_aux *engine, uint32_t size,
282			      uint8_t *buffer, uint8_t *reply_result,
283			      uint32_t *sw_status)
284{
285	struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
286	uint32_t bytes_replied;
287	uint32_t reply_result_32;
288
289	*sw_status = REG_GET(AUX_SW_STATUS, AUX_SW_REPLY_BYTE_COUNT,
290			     &bytes_replied);
291
292	/* In case HPD is LOW, exit AUX transaction */
293	if ((*sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
294		return -1;
295
296	/* Need at least the status byte */
297	if (!bytes_replied)
298		return -1;
299
300	REG_UPDATE_SEQ_3(AUX_SW_DATA,
301			  AUX_SW_INDEX, 0,
302			  AUX_SW_AUTOINCREMENT_DISABLE, 1,
303			  AUX_SW_DATA_RW, 1);
304
305	REG_GET(AUX_SW_DATA, AUX_SW_DATA, &reply_result_32);
306	reply_result_32 = reply_result_32 >> 4;
307	if (reply_result != NULL)
308		*reply_result = (uint8_t)reply_result_32;
309
310	if (reply_result_32 == 0) { /* ACK */
311		uint32_t i = 0;
312
313		/* First byte was already used to get the command status */
314		--bytes_replied;
315
316		/* Do not overflow buffer */
317		if (bytes_replied > size)
318			return -1;
319
320		while (i < bytes_replied) {
321			uint32_t aux_sw_data_val;
322
323			REG_GET(AUX_SW_DATA, AUX_SW_DATA, &aux_sw_data_val);
324			buffer[i] = aux_sw_data_val;
325			++i;
326		}
327
328		return i;
329	}
330
331	return 0;
332}
333
334static enum aux_return_code_type get_channel_status(
335	struct dce_aux *engine,
336	uint8_t *returned_bytes)
337{
338	struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
339
340	uint32_t value;
341
342	if (returned_bytes == NULL) {
343		/*caller pass NULL pointer*/
344		ASSERT_CRITICAL(false);
345		return AUX_RET_ERROR_UNKNOWN;
346	}
347	*returned_bytes = 0;
348
349	/* poll to make sure that SW_DONE is asserted */
350	REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 1,
351				10, aux110->polling_timeout_period/10);
352
353	value = REG_READ(AUX_SW_STATUS);
354	/* in case HPD is LOW, exit AUX transaction */
355	if ((value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
356		return AUX_RET_ERROR_HPD_DISCON;
357
358	/* Note that the following bits are set in 'status.bits'
359	 * during CTS 4.2.1.2 (FW 3.3.1):
360	 * AUX_SW_RX_MIN_COUNT_VIOL, AUX_SW_RX_INVALID_STOP,
361	 * AUX_SW_RX_RECV_NO_DET, AUX_SW_RX_RECV_INVALID_H.
362	 *
363	 * AUX_SW_RX_MIN_COUNT_VIOL is an internal,
364	 * HW debugging bit and should be ignored.
365	 */
366	if (value & AUX_SW_STATUS__AUX_SW_DONE_MASK) {
367		if ((value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_STATE_MASK) ||
368			(value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_MASK))
369			return AUX_RET_ERROR_TIMEOUT;
370
371		else if ((value & AUX_SW_STATUS__AUX_SW_RX_INVALID_STOP_MASK) ||
372			(value & AUX_SW_STATUS__AUX_SW_RX_RECV_NO_DET_MASK) ||
373			(value &
374				AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_H_MASK) ||
375			(value & AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_L_MASK))
376			return AUX_RET_ERROR_INVALID_REPLY;
377
378		*returned_bytes = get_reg_field_value(value,
379				AUX_SW_STATUS,
380				AUX_SW_REPLY_BYTE_COUNT);
381
382		if (*returned_bytes == 0)
383			return
384			AUX_RET_ERROR_INVALID_REPLY;
385		else {
386			*returned_bytes -= 1;
387			return AUX_RET_SUCCESS;
388		}
389	} else {
390		/*time_elapsed >= aux_engine->timeout_period
391		 *  AUX_SW_STATUS__AUX_SW_HPD_DISCON = at this point
392		 */
393		ASSERT_CRITICAL(false);
394		return AUX_RET_ERROR_TIMEOUT;
395	}
396}
397
398static bool acquire(
399	struct dce_aux *engine,
400	struct ddc *ddc)
401{
402	enum gpio_result result;
403
404	if ((engine == NULL) || !is_engine_available(engine))
405		return false;
406
407	result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
408		GPIO_DDC_CONFIG_TYPE_MODE_AUX);
409
410	if (result != GPIO_RESULT_OK)
411		return false;
412
413	if (!acquire_engine(engine)) {
414		engine->ddc = ddc;
415		release_engine(engine);
416		return false;
417	}
418
419	engine->ddc = ddc;
420
421	return true;
422}
423
424void dce110_engine_destroy(struct dce_aux **engine)
425{
426
427	struct aux_engine_dce110 *engine110 = FROM_AUX_ENGINE(*engine);
428
429	kfree(engine110);
430	*engine = NULL;
431
432}
433
434static uint32_t dce_aux_configure_timeout(struct ddc_service *ddc,
435		uint32_t timeout_in_us)
436{
437	uint32_t multiplier = 0;
438	uint32_t length = 0;
439	uint32_t prev_length = 0;
440	uint32_t prev_mult = 0;
441	uint32_t prev_timeout_val = 0;
442	struct ddc *ddc_pin = ddc->ddc_pin;
443	struct dce_aux *aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en];
444	struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(aux_engine);
445
446	/* 1-Update polling timeout period */
447	aux110->polling_timeout_period = timeout_in_us * SW_AUX_TIMEOUT_PERIOD_MULTIPLIER;
448
449	/* 2-Update aux timeout period length and multiplier */
450	if (timeout_in_us == 0) {
451		multiplier = DEFAULT_AUX_ENGINE_MULT;
452		length = DEFAULT_AUX_ENGINE_LENGTH;
453	} else if (timeout_in_us <= TIME_OUT_INCREMENT) {
454		multiplier = 0;
455		length = timeout_in_us/TIME_OUT_MULTIPLIER_8;
456		if (timeout_in_us % TIME_OUT_MULTIPLIER_8 != 0)
457			length++;
458	} else if (timeout_in_us <= 2 * TIME_OUT_INCREMENT) {
459		multiplier = 1;
460		length = timeout_in_us/TIME_OUT_MULTIPLIER_16;
461		if (timeout_in_us % TIME_OUT_MULTIPLIER_16 != 0)
462			length++;
463	} else if (timeout_in_us <= 4 * TIME_OUT_INCREMENT) {
464		multiplier = 2;
465		length = timeout_in_us/TIME_OUT_MULTIPLIER_32;
466		if (timeout_in_us % TIME_OUT_MULTIPLIER_32 != 0)
467			length++;
468	} else if (timeout_in_us > 4 * TIME_OUT_INCREMENT) {
469		multiplier = 3;
470		length = timeout_in_us/TIME_OUT_MULTIPLIER_64;
471		if (timeout_in_us % TIME_OUT_MULTIPLIER_64 != 0)
472			length++;
473	}
474
475	length = (length < MAX_TIMEOUT_LENGTH) ? length : MAX_TIMEOUT_LENGTH;
476
477	REG_GET_2(AUX_DPHY_RX_CONTROL1, AUX_RX_TIMEOUT_LEN, &prev_length, AUX_RX_TIMEOUT_LEN_MUL, &prev_mult);
478
479	switch (prev_mult) {
480	case 0:
481		prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_8;
482		break;
483	case 1:
484		prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_16;
485		break;
486	case 2:
487		prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_32;
488		break;
489	case 3:
490		prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_64;
491		break;
492	default:
493		prev_timeout_val = DEFAULT_AUX_ENGINE_LENGTH * TIME_OUT_MULTIPLIER_8;
494		break;
495	}
496
497	REG_UPDATE_SEQ_2(AUX_DPHY_RX_CONTROL1, AUX_RX_TIMEOUT_LEN, length, AUX_RX_TIMEOUT_LEN_MUL, multiplier);
498
499	return prev_timeout_val;
500}
501
502static struct dce_aux_funcs aux_functions = {
503	.configure_timeout = NULL,
504	.destroy = NULL,
505};
506
507struct dce_aux *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_engine110,
508		struct dc_context *ctx,
509		uint32_t inst,
510		uint32_t timeout_period,
511		const struct dce110_aux_registers *regs,
512		const struct dce110_aux_registers_mask *mask,
513		const struct dce110_aux_registers_shift *shift,
514		bool is_ext_aux_timeout_configurable)
515{
516	aux_engine110->base.ddc = NULL;
517	aux_engine110->base.ctx = ctx;
518	aux_engine110->base.delay = 0;
519	aux_engine110->base.max_defer_write_retry = 0;
520	aux_engine110->base.inst = inst;
521	aux_engine110->polling_timeout_period = timeout_period;
522	aux_engine110->regs = regs;
523
524	aux_engine110->mask = mask;
525	aux_engine110->shift = shift;
526	aux_engine110->base.funcs = &aux_functions;
527	if (is_ext_aux_timeout_configurable)
528		aux_engine110->base.funcs->configure_timeout = &dce_aux_configure_timeout;
529
530	return &aux_engine110->base;
531}
532
533static enum i2caux_transaction_action i2caux_action_from_payload(struct aux_payload *payload)
534{
535	if (payload->i2c_over_aux) {
536		if (payload->write_status_update) {
537			if (payload->mot)
538				return I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT;
539			else
540				return I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
541		}
542		if (payload->write) {
543			if (payload->mot)
544				return I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT;
545			else
546				return I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
547		}
548		if (payload->mot)
549			return I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT;
550
551		return I2CAUX_TRANSACTION_ACTION_I2C_READ;
552	}
553	if (payload->write)
554		return I2CAUX_TRANSACTION_ACTION_DP_WRITE;
555
556	return I2CAUX_TRANSACTION_ACTION_DP_READ;
557}
558
559int dce_aux_transfer_raw(struct ddc_service *ddc,
560		struct aux_payload *payload,
561		enum aux_return_code_type *operation_result)
562{
563	struct ddc *ddc_pin = ddc->ddc_pin;
564	struct dce_aux *aux_engine;
565	struct aux_request_transaction_data aux_req;
566	uint8_t returned_bytes = 0;
567	int res = -1;
568	uint32_t status;
569
570	memset(&aux_req, 0, sizeof(aux_req));
571
572	if (ddc_pin == NULL) {
573		*operation_result = AUX_RET_ERROR_ENGINE_ACQUIRE;
574		return -1;
575	}
576
577	aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en];
578	if (!acquire(aux_engine, ddc_pin)) {
579		*operation_result = AUX_RET_ERROR_ENGINE_ACQUIRE;
580		return -1;
581	}
582
583	if (payload->i2c_over_aux)
584		aux_req.type = AUX_TRANSACTION_TYPE_I2C;
585	else
586		aux_req.type = AUX_TRANSACTION_TYPE_DP;
587
588	aux_req.action = i2caux_action_from_payload(payload);
589
590	aux_req.address = payload->address;
591	aux_req.delay = 0;
592	aux_req.length = payload->length;
593	aux_req.data = payload->data;
594
595	submit_channel_request(aux_engine, &aux_req);
596	*operation_result = get_channel_status(aux_engine, &returned_bytes);
597
598	if (*operation_result == AUX_RET_SUCCESS) {
599		int __maybe_unused bytes_replied = 0;
600
601		bytes_replied = read_channel_reply(aux_engine, payload->length,
602					 payload->data, payload->reply,
603					 &status);
604		EVENT_LOG_AUX_REP(aux_engine->ddc->pin_data->en,
605					EVENT_LOG_AUX_ORIGIN_NATIVE, *payload->reply,
606					bytes_replied, payload->data);
607		res = returned_bytes;
608	} else {
609		res = -1;
610	}
611
612	release_engine(aux_engine);
613	return res;
614}
615
616int dce_aux_transfer_dmub_raw(struct ddc_service *ddc,
617		struct aux_payload *payload,
618		enum aux_return_code_type *operation_result)
619{
620	struct ddc *ddc_pin = ddc->ddc_pin;
621
622	if (ddc_pin != NULL) {
623		struct dce_aux *aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en];
624		/* XXX: Workaround to configure ddc channels for aux transactions */
625		if (!acquire(aux_engine, ddc_pin)) {
626			*operation_result = AUX_RET_ERROR_ENGINE_ACQUIRE;
627			return -1;
628		}
629		release_engine(aux_engine);
630	}
631
632	return dm_helper_dmub_aux_transfer_sync(ddc->ctx, ddc->link, payload, operation_result);
633}
634
635#define AUX_MAX_RETRIES 7
636#define AUX_MIN_DEFER_RETRIES 7
637#define AUX_MAX_DEFER_TIMEOUT_MS 50
638#define AUX_MAX_I2C_DEFER_RETRIES 7
639#define AUX_MAX_INVALID_REPLY_RETRIES 2
640#define AUX_MAX_TIMEOUT_RETRIES 3
641#define AUX_DEFER_DELAY_FOR_DPIA 4 /*ms*/
642
643static void dce_aux_log_payload(const char *payload_name,
644	unsigned char *payload, uint32_t length, uint32_t max_length_to_log)
645{
646	if (!IS_DC_I2CAUX_LOGGING_ENABLED())
647		return;
648
649	if (payload && length) {
650		char hex_str[128] = {0};
651		char *hex_str_ptr = &hex_str[0];
652		uint32_t hex_str_remaining = sizeof(hex_str);
653		unsigned char *payload_ptr = payload;
654		unsigned char *payload_max_to_log_ptr = payload_ptr + min(max_length_to_log, length);
655		unsigned int count;
656		char *padding = "";
657
658		while (payload_ptr < payload_max_to_log_ptr) {
659			count = snprintf_count(hex_str_ptr, hex_str_remaining, "%s%02X", padding, *payload_ptr);
660			padding = " ";
661			hex_str_remaining -= count;
662			hex_str_ptr += count;
663			payload_ptr++;
664		}
665
666		count = snprintf_count(hex_str_ptr, hex_str_remaining, "   ");
667		hex_str_remaining -= count;
668		hex_str_ptr += count;
669
670		payload_ptr = payload;
671		while (payload_ptr < payload_max_to_log_ptr) {
672			count = snprintf_count(hex_str_ptr, hex_str_remaining, "%c",
673				*payload_ptr >= ' ' ? *payload_ptr : '.');
674			hex_str_remaining -= count;
675			hex_str_ptr += count;
676			payload_ptr++;
677		}
678
679		DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_VERBOSE,
680					LOG_FLAG_I2cAux_DceAux,
681					"dce_aux_log_payload: %s: length=%u: data: %s%s",
682					payload_name,
683					length,
684					hex_str,
685					(length > max_length_to_log ? " (...)" : " "));
686	} else {
687		DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_VERBOSE,
688					LOG_FLAG_I2cAux_DceAux,
689					"dce_aux_log_payload: %s: length=%u: data: <empty payload>",
690					payload_name,
691					length);
692	}
693}
694
695bool dce_aux_transfer_with_retries(struct ddc_service *ddc,
696		struct aux_payload *payload)
697{
698	int i, ret = 0;
699	uint8_t reply;
700	bool payload_reply = true;
701	enum aux_return_code_type operation_result;
702	bool retry_on_defer = false;
703	struct ddc *ddc_pin = ddc->ddc_pin;
704	struct dce_aux *aux_engine = NULL;
705	struct aux_engine_dce110 *aux110 = NULL;
706	uint32_t defer_time_in_ms = 0;
707
708	int aux_ack_retries = 0,
709		aux_defer_retries = 0,
710		aux_i2c_defer_retries = 0,
711		aux_timeout_retries = 0,
712		aux_invalid_reply_retries = 0,
713		aux_ack_m_retries = 0;
714
715	if (ddc_pin) {
716		aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en];
717		aux110 = FROM_AUX_ENGINE(aux_engine);
718	}
719
720	if (!payload->reply) {
721		payload_reply = false;
722		payload->reply = &reply;
723	}
724
725	for (i = 0; i < AUX_MAX_RETRIES; i++) {
726		DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
727					LOG_FLAG_I2cAux_DceAux,
728					"dce_aux_transfer_with_retries: link_index=%u: START: retry %d of %d: address=0x%04x length=%u write=%d mot=%d",
729					ddc && ddc->link ? ddc->link->link_index : UINT_MAX,
730					i + 1,
731					(int)AUX_MAX_RETRIES,
732					payload->address,
733					payload->length,
734					(unsigned int) payload->write,
735					(unsigned int) payload->mot);
736		if (payload->write)
737			dce_aux_log_payload("  write", payload->data, payload->length, 16);
738		ret = dce_aux_transfer_raw(ddc, payload, &operation_result);
739		DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
740					LOG_FLAG_I2cAux_DceAux,
741					"dce_aux_transfer_with_retries: link_index=%u: END: retry %d of %d: address=0x%04x length=%u write=%d mot=%d: ret=%d operation_result=%d payload->reply=%u",
742					ddc && ddc->link ? ddc->link->link_index : UINT_MAX,
743					i + 1,
744					(int)AUX_MAX_RETRIES,
745					payload->address,
746					payload->length,
747					(unsigned int) payload->write,
748					(unsigned int) payload->mot,
749					ret,
750					(int)operation_result,
751					(unsigned int) *payload->reply);
752		if (!payload->write)
753			dce_aux_log_payload("  read", payload->data, ret > 0 ? ret : 0, 16);
754
755		switch (operation_result) {
756		case AUX_RET_SUCCESS:
757			aux_timeout_retries = 0;
758			aux_invalid_reply_retries = 0;
759
760			switch (*payload->reply) {
761			case AUX_TRANSACTION_REPLY_AUX_ACK:
762				DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
763							LOG_FLAG_I2cAux_DceAux,
764							"dce_aux_transfer_with_retries: AUX_RET_SUCCESS: AUX_TRANSACTION_REPLY_AUX_ACK");
765				if (!payload->write && payload->length != ret) {
766					if (++aux_ack_retries >= AUX_MAX_RETRIES) {
767						DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
768									LOG_FLAG_Error_I2cAux,
769									"dce_aux_transfer_with_retries: FAILURE: aux_ack_retries=%d >= AUX_MAX_RETRIES=%d",
770									aux_defer_retries,
771									AUX_MAX_RETRIES);
772						goto fail;
773					} else
774						udelay(300);
775				} else if (payload->write && ret > 0) {
776					/* sink requested more time to complete the write via AUX_ACKM */
777					if (++aux_ack_m_retries >= AUX_MAX_RETRIES) {
778						DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
779								LOG_FLAG_Error_I2cAux,
780								"dce_aux_transfer_with_retries: FAILURE: aux_ack_m_retries=%d >= AUX_MAX_RETRIES=%d",
781								aux_ack_m_retries,
782								AUX_MAX_RETRIES);
783						goto fail;
784					}
785
786					/* retry reading the write status until complete
787					 * NOTE: payload is modified here
788					 */
789					payload->write = false;
790					payload->write_status_update = true;
791					payload->length = 0;
792					udelay(300);
793
794				} else
795					return true;
796			break;
797
798			case AUX_TRANSACTION_REPLY_AUX_DEFER:
799				DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
800							LOG_FLAG_I2cAux_DceAux,
801							"dce_aux_transfer_with_retries: AUX_RET_SUCCESS: AUX_TRANSACTION_REPLY_AUX_DEFER");
802
803				/* polling_timeout_period is in us */
804				if (aux110)
805					defer_time_in_ms += aux110->polling_timeout_period / 1000;
806				else
807					defer_time_in_ms += AUX_DEFER_DELAY_FOR_DPIA;
808				++aux_defer_retries;
809				fallthrough;
810			case AUX_TRANSACTION_REPLY_I2C_OVER_AUX_DEFER:
811				if (*payload->reply == AUX_TRANSACTION_REPLY_I2C_OVER_AUX_DEFER)
812					DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
813								LOG_FLAG_I2cAux_DceAux,
814								"dce_aux_transfer_with_retries: AUX_RET_SUCCESS: AUX_TRANSACTION_REPLY_I2C_OVER_AUX_DEFER");
815
816				retry_on_defer = true;
817
818				if (aux_defer_retries >= AUX_MIN_DEFER_RETRIES
819						&& defer_time_in_ms >= AUX_MAX_DEFER_TIMEOUT_MS) {
820					DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
821								LOG_FLAG_Error_I2cAux,
822								"dce_aux_transfer_with_retries: FAILURE: aux_defer_retries=%d >= AUX_MIN_DEFER_RETRIES=%d && defer_time_in_ms=%d >= AUX_MAX_DEFER_TIMEOUT_MS=%d",
823								aux_defer_retries,
824								AUX_MIN_DEFER_RETRIES,
825								defer_time_in_ms,
826								AUX_MAX_DEFER_TIMEOUT_MS);
827					goto fail;
828				} else {
829					if ((*payload->reply == AUX_TRANSACTION_REPLY_AUX_DEFER) ||
830						(*payload->reply == AUX_TRANSACTION_REPLY_I2C_OVER_AUX_DEFER)) {
831						DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
832									LOG_FLAG_I2cAux_DceAux,
833									"dce_aux_transfer_with_retries: payload->defer_delay=%u",
834									payload->defer_delay);
835						fsleep(payload->defer_delay * 1000);
836						defer_time_in_ms += payload->defer_delay;
837					}
838				}
839				break;
840			case AUX_TRANSACTION_REPLY_I2C_OVER_AUX_NACK:
841				DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
842							LOG_FLAG_I2cAux_DceAux,
843							"dce_aux_transfer_with_retries: FAILURE: AUX_TRANSACTION_REPLY_I2C_OVER_AUX_NACK");
844				goto fail;
845			case AUX_TRANSACTION_REPLY_I2C_DEFER:
846				DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
847							LOG_FLAG_I2cAux_DceAux,
848							"dce_aux_transfer_with_retries: AUX_RET_SUCCESS: AUX_TRANSACTION_REPLY_I2C_DEFER");
849
850				aux_defer_retries = 0;
851				if (++aux_i2c_defer_retries >= AUX_MAX_I2C_DEFER_RETRIES) {
852					DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
853								LOG_FLAG_Error_I2cAux,
854								"dce_aux_transfer_with_retries: FAILURE: aux_i2c_defer_retries=%d >= AUX_MAX_I2C_DEFER_RETRIES=%d",
855								aux_i2c_defer_retries,
856								AUX_MAX_I2C_DEFER_RETRIES);
857					goto fail;
858				}
859				break;
860
861			case AUX_TRANSACTION_REPLY_AUX_NACK:
862				DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
863							LOG_FLAG_I2cAux_DceAux,
864							"dce_aux_transfer_with_retries: AUX_RET_SUCCESS: AUX_TRANSACTION_REPLY_AUX_NACK");
865				goto fail;
866
867			case AUX_TRANSACTION_REPLY_HPD_DISCON:
868				DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
869							LOG_FLAG_I2cAux_DceAux,
870							"dce_aux_transfer_with_retries: AUX_RET_SUCCESS: AUX_TRANSACTION_REPLY_HPD_DISCON");
871				goto fail;
872
873			default:
874				DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
875							LOG_FLAG_Error_I2cAux,
876							"dce_aux_transfer_with_retries: AUX_RET_SUCCESS: FAILURE: AUX_TRANSACTION_REPLY_* unknown, default case. Reply: %d", *payload->reply);
877				goto fail;
878			}
879			break;
880
881		case AUX_RET_ERROR_INVALID_REPLY:
882			DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
883						LOG_FLAG_I2cAux_DceAux,
884						"dce_aux_transfer_with_retries: AUX_RET_ERROR_INVALID_REPLY");
885			if (++aux_invalid_reply_retries >= AUX_MAX_INVALID_REPLY_RETRIES) {
886				DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
887							LOG_FLAG_Error_I2cAux,
888							"dce_aux_transfer_with_retries: FAILURE: aux_invalid_reply_retries=%d >= AUX_MAX_INVALID_REPLY_RETRIES=%d",
889							aux_invalid_reply_retries,
890							AUX_MAX_INVALID_REPLY_RETRIES);
891				goto fail;
892			} else
893				udelay(400);
894			break;
895
896		case AUX_RET_ERROR_TIMEOUT:
897			DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
898						LOG_FLAG_I2cAux_DceAux,
899						"dce_aux_transfer_with_retries: AUX_RET_ERROR_TIMEOUT");
900			// Check whether a DEFER had occurred before the timeout.
901			// If so, treat timeout as a DEFER.
902			if (retry_on_defer) {
903				if (++aux_defer_retries >= AUX_MIN_DEFER_RETRIES) {
904					DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
905								LOG_FLAG_Error_I2cAux,
906								"dce_aux_transfer_with_retries: FAILURE: aux_defer_retries=%d >= AUX_MIN_DEFER_RETRIES=%d",
907								aux_defer_retries,
908								AUX_MIN_DEFER_RETRIES);
909					goto fail;
910				} else if (payload->defer_delay > 0) {
911					DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
912								LOG_FLAG_I2cAux_DceAux,
913								"dce_aux_transfer_with_retries: payload->defer_delay=%u",
914								payload->defer_delay);
915					msleep(payload->defer_delay);
916				}
917			} else {
918				if (++aux_timeout_retries >= AUX_MAX_TIMEOUT_RETRIES) {
919					DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
920								LOG_FLAG_Error_I2cAux,
921								"dce_aux_transfer_with_retries: FAILURE: aux_timeout_retries=%d >= AUX_MAX_TIMEOUT_RETRIES=%d",
922								aux_timeout_retries,
923								AUX_MAX_TIMEOUT_RETRIES);
924					goto fail;
925				} else {
926					/*
927					 * DP 1.4, 2.8.2:  AUX Transaction Response/Reply Timeouts
928					 * According to the DP spec there should be 3 retries total
929					 * with a 400us wait inbetween each. Hardware already waits
930					 * for 550us therefore no wait is required here.
931					 */
932				}
933			}
934			break;
935
936		case AUX_RET_ERROR_HPD_DISCON:
937		case AUX_RET_ERROR_ENGINE_ACQUIRE:
938		case AUX_RET_ERROR_UNKNOWN:
939		default:
940			goto fail;
941		}
942	}
943
944fail:
945	DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
946				LOG_FLAG_Error_I2cAux,
947				"%s: Failure: operation_result=%d",
948				__func__,
949				(int)operation_result);
950	if (!payload_reply)
951		payload->reply = NULL;
952
953	return false;
954}
955