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 "dce_aux.h"
28 #include "dce/dce_11_0_sh_mask.h"
29 
30 #define CTX \
31 	aux110->base.ctx
32 #define REG(reg_name)\
33 	(aux110->regs->reg_name)
34 
35 #define DC_LOGGER \
36 	engine->ctx->logger
37 
38 #include "reg_helper.h"
39 
40 #define FROM_AUX_ENGINE(ptr) \
41 	container_of((ptr), struct aux_engine_dce110, base)
42 
43 #define FROM_ENGINE(ptr) \
44 	FROM_AUX_ENGINE(container_of((ptr), struct aux_engine, base))
45 
46 #define FROM_AUX_ENGINE_ENGINE(ptr) \
47 	container_of((ptr), struct aux_engine, base)
48 enum {
49 	AUX_INVALID_REPLY_RETRY_COUNTER = 1,
50 	AUX_TIMED_OUT_RETRY_COUNTER = 2,
51 	AUX_DEFER_RETRY_COUNTER = 6
52 };
53 static void release_engine(
54 	struct aux_engine *engine)
55 {
56 	struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
57 
58 	dal_ddc_close(engine->ddc);
59 
60 	engine->ddc = NULL;
61 
62 	REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_DONE_USING_AUX_REG, 1);
63 }
64 
65 #define SW_CAN_ACCESS_AUX 1
66 #define DMCU_CAN_ACCESS_AUX 2
67 
68 static bool is_engine_available(
69 	struct aux_engine *engine)
70 {
71 	struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
72 
73 	uint32_t value = REG_READ(AUX_ARB_CONTROL);
74 	uint32_t field = get_reg_field_value(
75 			value,
76 			AUX_ARB_CONTROL,
77 			AUX_REG_RW_CNTL_STATUS);
78 
79 	return (field != DMCU_CAN_ACCESS_AUX);
80 }
81 static bool acquire_engine(
82 	struct aux_engine *engine)
83 {
84 	struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
85 
86 	uint32_t value = REG_READ(AUX_ARB_CONTROL);
87 	uint32_t field = get_reg_field_value(
88 			value,
89 			AUX_ARB_CONTROL,
90 			AUX_REG_RW_CNTL_STATUS);
91 	if (field == DMCU_CAN_ACCESS_AUX)
92 		return false;
93 	/* enable AUX before request SW to access AUX */
94 	value = REG_READ(AUX_CONTROL);
95 	field = get_reg_field_value(value,
96 				AUX_CONTROL,
97 				AUX_EN);
98 
99 	if (field == 0) {
100 		set_reg_field_value(
101 				value,
102 				1,
103 				AUX_CONTROL,
104 				AUX_EN);
105 
106 		if (REG(AUX_RESET_MASK)) {
107 			/*DP_AUX block as part of the enable sequence*/
108 			set_reg_field_value(
109 				value,
110 				1,
111 				AUX_CONTROL,
112 				AUX_RESET);
113 		}
114 
115 		REG_WRITE(AUX_CONTROL, value);
116 
117 		if (REG(AUX_RESET_MASK)) {
118 			/*poll HW to make sure reset it done*/
119 
120 			REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 1,
121 					1, 11);
122 
123 			set_reg_field_value(
124 				value,
125 				0,
126 				AUX_CONTROL,
127 				AUX_RESET);
128 
129 			REG_WRITE(AUX_CONTROL, value);
130 
131 			REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 0,
132 					1, 11);
133 		}
134 	} /*if (field)*/
135 
136 	/* request SW to access AUX */
137 	REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_USE_AUX_REG_REQ, 1);
138 
139 	value = REG_READ(AUX_ARB_CONTROL);
140 	field = get_reg_field_value(
141 			value,
142 			AUX_ARB_CONTROL,
143 			AUX_REG_RW_CNTL_STATUS);
144 
145 	return (field == SW_CAN_ACCESS_AUX);
146 }
147 
148 #define COMPOSE_AUX_SW_DATA_16_20(command, address) \
149 	((command) | ((0xF0000 & (address)) >> 16))
150 
151 #define COMPOSE_AUX_SW_DATA_8_15(address) \
152 	((0xFF00 & (address)) >> 8)
153 
154 #define COMPOSE_AUX_SW_DATA_0_7(address) \
155 	(0xFF & (address))
156 
157 static void submit_channel_request(
158 	struct aux_engine *engine,
159 	struct aux_request_transaction_data *request)
160 {
161 	struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
162 	uint32_t value;
163 	uint32_t length;
164 
165 	bool is_write =
166 		((request->type == AUX_TRANSACTION_TYPE_DP) &&
167 		 (request->action == I2CAUX_TRANSACTION_ACTION_DP_WRITE)) ||
168 		((request->type == AUX_TRANSACTION_TYPE_I2C) &&
169 		((request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) ||
170 		 (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT)));
171 	if (REG(AUXN_IMPCAL)) {
172 		/* clear_aux_error */
173 		REG_UPDATE_SEQ(AUXN_IMPCAL, AUXN_CALOUT_ERROR_AK,
174 				1,
175 				0);
176 
177 		REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_CALOUT_ERROR_AK,
178 				1,
179 				0);
180 
181 		/* force_default_calibrate */
182 		REG_UPDATE_1BY1_2(AUXN_IMPCAL,
183 				AUXN_IMPCAL_ENABLE, 1,
184 				AUXN_IMPCAL_OVERRIDE_ENABLE, 0);
185 
186 		/* bug? why AUXN update EN and OVERRIDE_EN 1 by 1 while AUX P toggles OVERRIDE? */
187 
188 		REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_IMPCAL_OVERRIDE_ENABLE,
189 				1,
190 				0);
191 	}
192 	/* set the delay and the number of bytes to write */
193 
194 	/* The length include
195 	 * the 4 bit header and the 20 bit address
196 	 * (that is 3 byte).
197 	 * If the requested length is non zero this means
198 	 * an addition byte specifying the length is required.
199 	 */
200 
201 	length = request->length ? 4 : 3;
202 	if (is_write)
203 		length += request->length;
204 
205 	REG_UPDATE_2(AUX_SW_CONTROL,
206 			AUX_SW_START_DELAY, request->delay,
207 			AUX_SW_WR_BYTES, length);
208 
209 	/* program action and address and payload data (if 'is_write') */
210 	value = REG_UPDATE_4(AUX_SW_DATA,
211 			AUX_SW_INDEX, 0,
212 			AUX_SW_DATA_RW, 0,
213 			AUX_SW_AUTOINCREMENT_DISABLE, 1,
214 			AUX_SW_DATA, COMPOSE_AUX_SW_DATA_16_20(request->action, request->address));
215 
216 	value = REG_SET_2(AUX_SW_DATA, value,
217 			AUX_SW_AUTOINCREMENT_DISABLE, 0,
218 			AUX_SW_DATA, COMPOSE_AUX_SW_DATA_8_15(request->address));
219 
220 	value = REG_SET(AUX_SW_DATA, value,
221 			AUX_SW_DATA, COMPOSE_AUX_SW_DATA_0_7(request->address));
222 
223 	if (request->length) {
224 		value = REG_SET(AUX_SW_DATA, value,
225 				AUX_SW_DATA, request->length - 1);
226 	}
227 
228 	if (is_write) {
229 		/* Load the HW buffer with the Data to be sent.
230 		 * This is relevant for write operation.
231 		 * For read, the data recived data will be
232 		 * processed in process_channel_reply().
233 		 */
234 		uint32_t i = 0;
235 
236 		while (i < request->length) {
237 			value = REG_SET(AUX_SW_DATA, value,
238 					AUX_SW_DATA, request->data[i]);
239 
240 			++i;
241 		}
242 	}
243 
244 	REG_UPDATE(AUX_INTERRUPT_CONTROL, AUX_SW_DONE_ACK, 1);
245 	REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 0,
246 				10, aux110->timeout_period/10);
247 	REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1);
248 }
249 
250 static int read_channel_reply(struct aux_engine *engine, uint32_t size,
251 			      uint8_t *buffer, uint8_t *reply_result,
252 			      uint32_t *sw_status)
253 {
254 	struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
255 	uint32_t bytes_replied;
256 	uint32_t reply_result_32;
257 
258 	*sw_status = REG_GET(AUX_SW_STATUS, AUX_SW_REPLY_BYTE_COUNT,
259 			     &bytes_replied);
260 
261 	/* In case HPD is LOW, exit AUX transaction */
262 	if ((*sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
263 		return -1;
264 
265 	/* Need at least the status byte */
266 	if (!bytes_replied)
267 		return -1;
268 
269 	REG_UPDATE_1BY1_3(AUX_SW_DATA,
270 			  AUX_SW_INDEX, 0,
271 			  AUX_SW_AUTOINCREMENT_DISABLE, 1,
272 			  AUX_SW_DATA_RW, 1);
273 
274 	REG_GET(AUX_SW_DATA, AUX_SW_DATA, &reply_result_32);
275 	reply_result_32 = reply_result_32 >> 4;
276 	*reply_result = (uint8_t)reply_result_32;
277 
278 	if (reply_result_32 == 0) { /* ACK */
279 		uint32_t i = 0;
280 
281 		/* First byte was already used to get the command status */
282 		--bytes_replied;
283 
284 		/* Do not overflow buffer */
285 		if (bytes_replied > size)
286 			return -1;
287 
288 		while (i < bytes_replied) {
289 			uint32_t aux_sw_data_val;
290 
291 			REG_GET(AUX_SW_DATA, AUX_SW_DATA, &aux_sw_data_val);
292 			buffer[i] = aux_sw_data_val;
293 			++i;
294 		}
295 
296 		return i;
297 	}
298 
299 	return 0;
300 }
301 
302 static void process_channel_reply(
303 	struct aux_engine *engine,
304 	struct aux_reply_transaction_data *reply)
305 {
306 	int bytes_replied;
307 	uint8_t reply_result;
308 	uint32_t sw_status;
309 
310 	bytes_replied = read_channel_reply(engine, reply->length, reply->data,
311 					   &reply_result, &sw_status);
312 
313 	/* in case HPD is LOW, exit AUX transaction */
314 	if ((sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
315 		reply->status = AUX_TRANSACTION_REPLY_HPD_DISCON;
316 		return;
317 	}
318 
319 	if (bytes_replied < 0) {
320 		/* Need to handle an error case...
321 		 * Hopefully, upper layer function won't call this function if
322 		 * the number of bytes in the reply was 0, because there was
323 		 * surely an error that was asserted that should have been
324 		 * handled for hot plug case, this could happens
325 		 */
326 		if (!(sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
327 			reply->status = AUX_TRANSACTION_REPLY_INVALID;
328 			ASSERT_CRITICAL(false);
329 			return;
330 		}
331 	} else {
332 
333 		switch (reply_result) {
334 		case 0: /* ACK */
335 			reply->status = AUX_TRANSACTION_REPLY_AUX_ACK;
336 		break;
337 		case 1: /* NACK */
338 			reply->status = AUX_TRANSACTION_REPLY_AUX_NACK;
339 		break;
340 		case 2: /* DEFER */
341 			reply->status = AUX_TRANSACTION_REPLY_AUX_DEFER;
342 		break;
343 		case 4: /* AUX ACK / I2C NACK */
344 			reply->status = AUX_TRANSACTION_REPLY_I2C_NACK;
345 		break;
346 		case 8: /* AUX ACK / I2C DEFER */
347 			reply->status = AUX_TRANSACTION_REPLY_I2C_DEFER;
348 		break;
349 		default:
350 			reply->status = AUX_TRANSACTION_REPLY_INVALID;
351 		}
352 	}
353 }
354 
355 static enum aux_channel_operation_result get_channel_status(
356 	struct aux_engine *engine,
357 	uint8_t *returned_bytes)
358 {
359 	struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
360 
361 	uint32_t value;
362 
363 	if (returned_bytes == NULL) {
364 		/*caller pass NULL pointer*/
365 		ASSERT_CRITICAL(false);
366 		return AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN;
367 	}
368 	*returned_bytes = 0;
369 
370 	/* poll to make sure that SW_DONE is asserted */
371 	value = REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 1,
372 				10, aux110->timeout_period/10);
373 
374 	/* in case HPD is LOW, exit AUX transaction */
375 	if ((value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
376 		return AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON;
377 
378 	/* Note that the following bits are set in 'status.bits'
379 	 * during CTS 4.2.1.2 (FW 3.3.1):
380 	 * AUX_SW_RX_MIN_COUNT_VIOL, AUX_SW_RX_INVALID_STOP,
381 	 * AUX_SW_RX_RECV_NO_DET, AUX_SW_RX_RECV_INVALID_H.
382 	 *
383 	 * AUX_SW_RX_MIN_COUNT_VIOL is an internal,
384 	 * HW debugging bit and should be ignored.
385 	 */
386 	if (value & AUX_SW_STATUS__AUX_SW_DONE_MASK) {
387 		if ((value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_STATE_MASK) ||
388 			(value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_MASK))
389 			return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
390 
391 		else if ((value & AUX_SW_STATUS__AUX_SW_RX_INVALID_STOP_MASK) ||
392 			(value & AUX_SW_STATUS__AUX_SW_RX_RECV_NO_DET_MASK) ||
393 			(value &
394 				AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_H_MASK) ||
395 			(value & AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_L_MASK))
396 			return AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
397 
398 		*returned_bytes = get_reg_field_value(value,
399 				AUX_SW_STATUS,
400 				AUX_SW_REPLY_BYTE_COUNT);
401 
402 		if (*returned_bytes == 0)
403 			return
404 			AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
405 		else {
406 			*returned_bytes -= 1;
407 			return AUX_CHANNEL_OPERATION_SUCCEEDED;
408 		}
409 	} else {
410 		/*time_elapsed >= aux_engine->timeout_period
411 		 *  AUX_SW_STATUS__AUX_SW_HPD_DISCON = at this point
412 		 */
413 		ASSERT_CRITICAL(false);
414 		return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
415 	}
416 }
417 static void process_read_reply(
418 	struct aux_engine *engine,
419 	struct read_command_context *ctx)
420 {
421 	engine->funcs->process_channel_reply(engine, &ctx->reply);
422 
423 	switch (ctx->reply.status) {
424 	case AUX_TRANSACTION_REPLY_AUX_ACK:
425 		ctx->defer_retry_aux = 0;
426 		if (ctx->returned_byte > ctx->current_read_length) {
427 			ctx->status =
428 				I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
429 			ctx->operation_succeeded = false;
430 		} else if (ctx->returned_byte < ctx->current_read_length) {
431 			ctx->current_read_length -= ctx->returned_byte;
432 
433 			ctx->offset += ctx->returned_byte;
434 
435 			++ctx->invalid_reply_retry_aux_on_ack;
436 
437 			if (ctx->invalid_reply_retry_aux_on_ack >
438 				AUX_INVALID_REPLY_RETRY_COUNTER) {
439 				ctx->status =
440 				I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
441 				ctx->operation_succeeded = false;
442 			}
443 		} else {
444 			ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
445 			ctx->transaction_complete = true;
446 			ctx->operation_succeeded = true;
447 		}
448 	break;
449 	case AUX_TRANSACTION_REPLY_AUX_NACK:
450 		ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
451 		ctx->operation_succeeded = false;
452 	break;
453 	case AUX_TRANSACTION_REPLY_AUX_DEFER:
454 		++ctx->defer_retry_aux;
455 
456 		if (ctx->defer_retry_aux > AUX_DEFER_RETRY_COUNTER) {
457 			ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
458 			ctx->operation_succeeded = false;
459 		}
460 	break;
461 	case AUX_TRANSACTION_REPLY_I2C_DEFER:
462 		ctx->defer_retry_aux = 0;
463 
464 		++ctx->defer_retry_i2c;
465 
466 		if (ctx->defer_retry_i2c > AUX_DEFER_RETRY_COUNTER) {
467 			ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
468 			ctx->operation_succeeded = false;
469 		}
470 	break;
471 	case AUX_TRANSACTION_REPLY_HPD_DISCON:
472 		ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
473 		ctx->operation_succeeded = false;
474 	break;
475 	default:
476 		ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
477 		ctx->operation_succeeded = false;
478 	}
479 }
480 static void process_read_request(
481 	struct aux_engine *engine,
482 	struct read_command_context *ctx)
483 {
484 	enum aux_channel_operation_result operation_result;
485 
486 	engine->funcs->submit_channel_request(engine, &ctx->request);
487 
488 	operation_result = engine->funcs->get_channel_status(
489 		engine, &ctx->returned_byte);
490 
491 	switch (operation_result) {
492 	case AUX_CHANNEL_OPERATION_SUCCEEDED:
493 		if (ctx->returned_byte > ctx->current_read_length) {
494 			ctx->status =
495 				I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
496 			ctx->operation_succeeded = false;
497 		} else {
498 			ctx->timed_out_retry_aux = 0;
499 			ctx->invalid_reply_retry_aux = 0;
500 
501 			ctx->reply.length = ctx->returned_byte;
502 			ctx->reply.data = ctx->buffer;
503 
504 			process_read_reply(engine, ctx);
505 		}
506 	break;
507 	case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
508 		++ctx->invalid_reply_retry_aux;
509 
510 		if (ctx->invalid_reply_retry_aux >
511 			AUX_INVALID_REPLY_RETRY_COUNTER) {
512 			ctx->status =
513 				I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
514 			ctx->operation_succeeded = false;
515 		} else
516 			udelay(400);
517 	break;
518 	case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
519 		++ctx->timed_out_retry_aux;
520 
521 		if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
522 			ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
523 			ctx->operation_succeeded = false;
524 		} else {
525 			/* DP 1.2a, table 2-58:
526 			 * "S3: AUX Request CMD PENDING:
527 			 * retry 3 times, with 400usec wait on each"
528 			 * The HW timeout is set to 550usec,
529 			 * so we should not wait here
530 			 */
531 		}
532 	break;
533 	case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
534 		ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
535 		ctx->operation_succeeded = false;
536 	break;
537 	default:
538 		ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
539 		ctx->operation_succeeded = false;
540 	}
541 }
542 static bool read_command(
543 	struct aux_engine *engine,
544 	struct i2caux_transaction_request *request,
545 	bool middle_of_transaction)
546 {
547 	struct read_command_context ctx;
548 
549 	ctx.buffer = request->payload.data;
550 	ctx.current_read_length = request->payload.length;
551 	ctx.offset = 0;
552 	ctx.timed_out_retry_aux = 0;
553 	ctx.invalid_reply_retry_aux = 0;
554 	ctx.defer_retry_aux = 0;
555 	ctx.defer_retry_i2c = 0;
556 	ctx.invalid_reply_retry_aux_on_ack = 0;
557 	ctx.transaction_complete = false;
558 	ctx.operation_succeeded = true;
559 
560 	if (request->payload.address_space ==
561 		I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
562 		ctx.request.type = AUX_TRANSACTION_TYPE_DP;
563 		ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_READ;
564 		ctx.request.address = request->payload.address;
565 	} else if (request->payload.address_space ==
566 		I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
567 		ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
568 		ctx.request.action = middle_of_transaction ?
569 			I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT :
570 			I2CAUX_TRANSACTION_ACTION_I2C_READ;
571 		ctx.request.address = request->payload.address >> 1;
572 	} else {
573 		/* in DAL2, there was no return in such case */
574 		BREAK_TO_DEBUGGER();
575 		return false;
576 	}
577 
578 	ctx.request.delay = 0;
579 
580 	do {
581 		memset(ctx.buffer + ctx.offset, 0, ctx.current_read_length);
582 
583 		ctx.request.data = ctx.buffer + ctx.offset;
584 		ctx.request.length = ctx.current_read_length;
585 
586 		process_read_request(engine, &ctx);
587 
588 		request->status = ctx.status;
589 
590 		if (ctx.operation_succeeded && !ctx.transaction_complete)
591 			if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
592 				msleep(engine->delay);
593 	} while (ctx.operation_succeeded && !ctx.transaction_complete);
594 
595 	if (request->payload.address_space ==
596 		I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
597 		DC_LOG_I2C_AUX("READ: addr:0x%x  value:0x%x Result:%d",
598 				request->payload.address,
599 				request->payload.data[0],
600 				ctx.operation_succeeded);
601 	}
602 
603 	return ctx.operation_succeeded;
604 }
605 
606 static void process_write_reply(
607 	struct aux_engine *engine,
608 	struct write_command_context *ctx)
609 {
610 	engine->funcs->process_channel_reply(engine, &ctx->reply);
611 
612 	switch (ctx->reply.status) {
613 	case AUX_TRANSACTION_REPLY_AUX_ACK:
614 		ctx->operation_succeeded = true;
615 
616 		if (ctx->returned_byte) {
617 			ctx->request.action = ctx->mot ?
618 			I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
619 			I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
620 
621 			ctx->current_write_length = 0;
622 
623 			++ctx->ack_m_retry;
624 
625 			if (ctx->ack_m_retry > AUX_DEFER_RETRY_COUNTER) {
626 				ctx->status =
627 				I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
628 				ctx->operation_succeeded = false;
629 			} else
630 				udelay(300);
631 		} else {
632 			ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
633 			ctx->defer_retry_aux = 0;
634 			ctx->ack_m_retry = 0;
635 			ctx->transaction_complete = true;
636 		}
637 	break;
638 	case AUX_TRANSACTION_REPLY_AUX_NACK:
639 		ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
640 		ctx->operation_succeeded = false;
641 	break;
642 	case AUX_TRANSACTION_REPLY_AUX_DEFER:
643 		++ctx->defer_retry_aux;
644 
645 		if (ctx->defer_retry_aux > ctx->max_defer_retry) {
646 			ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
647 			ctx->operation_succeeded = false;
648 		}
649 	break;
650 	case AUX_TRANSACTION_REPLY_I2C_DEFER:
651 		ctx->defer_retry_aux = 0;
652 		ctx->current_write_length = 0;
653 
654 		ctx->request.action = ctx->mot ?
655 			I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
656 			I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
657 
658 		++ctx->defer_retry_i2c;
659 
660 		if (ctx->defer_retry_i2c > ctx->max_defer_retry) {
661 			ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
662 			ctx->operation_succeeded = false;
663 		}
664 	break;
665 	case AUX_TRANSACTION_REPLY_HPD_DISCON:
666 		ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
667 		ctx->operation_succeeded = false;
668 	break;
669 	default:
670 		ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
671 		ctx->operation_succeeded = false;
672 	}
673 }
674 static void process_write_request(
675 	struct aux_engine *engine,
676 	struct write_command_context *ctx)
677 {
678 	enum aux_channel_operation_result operation_result;
679 
680 	engine->funcs->submit_channel_request(engine, &ctx->request);
681 
682 	operation_result = engine->funcs->get_channel_status(
683 		engine, &ctx->returned_byte);
684 
685 	switch (operation_result) {
686 	case AUX_CHANNEL_OPERATION_SUCCEEDED:
687 		ctx->timed_out_retry_aux = 0;
688 		ctx->invalid_reply_retry_aux = 0;
689 
690 		ctx->reply.length = ctx->returned_byte;
691 		ctx->reply.data = ctx->reply_data;
692 
693 		process_write_reply(engine, ctx);
694 	break;
695 	case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
696 		++ctx->invalid_reply_retry_aux;
697 
698 		if (ctx->invalid_reply_retry_aux >
699 			AUX_INVALID_REPLY_RETRY_COUNTER) {
700 			ctx->status =
701 				I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
702 			ctx->operation_succeeded = false;
703 		} else
704 			udelay(400);
705 	break;
706 	case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
707 		++ctx->timed_out_retry_aux;
708 
709 		if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
710 			ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
711 			ctx->operation_succeeded = false;
712 		} else {
713 			/* DP 1.2a, table 2-58:
714 			 * "S3: AUX Request CMD PENDING:
715 			 * retry 3 times, with 400usec wait on each"
716 			 * The HW timeout is set to 550usec,
717 			 * so we should not wait here
718 			 */
719 		}
720 	break;
721 	case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
722 		ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
723 		ctx->operation_succeeded = false;
724 	break;
725 	default:
726 		ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
727 		ctx->operation_succeeded = false;
728 	}
729 }
730 static bool write_command(
731 	struct aux_engine *engine,
732 	struct i2caux_transaction_request *request,
733 	bool middle_of_transaction)
734 {
735 	struct write_command_context ctx;
736 
737 	ctx.mot = middle_of_transaction;
738 	ctx.buffer = request->payload.data;
739 	ctx.current_write_length = request->payload.length;
740 	ctx.timed_out_retry_aux = 0;
741 	ctx.invalid_reply_retry_aux = 0;
742 	ctx.defer_retry_aux = 0;
743 	ctx.defer_retry_i2c = 0;
744 	ctx.ack_m_retry = 0;
745 	ctx.transaction_complete = false;
746 	ctx.operation_succeeded = true;
747 
748 	if (request->payload.address_space ==
749 		I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
750 		ctx.request.type = AUX_TRANSACTION_TYPE_DP;
751 		ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_WRITE;
752 		ctx.request.address = request->payload.address;
753 	} else if (request->payload.address_space ==
754 		I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
755 		ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
756 		ctx.request.action = middle_of_transaction ?
757 			I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT :
758 			I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
759 		ctx.request.address = request->payload.address >> 1;
760 	} else {
761 		/* in DAL2, there was no return in such case */
762 		BREAK_TO_DEBUGGER();
763 		return false;
764 	}
765 
766 	ctx.request.delay = 0;
767 
768 	ctx.max_defer_retry =
769 		(engine->max_defer_write_retry > AUX_DEFER_RETRY_COUNTER) ?
770 			engine->max_defer_write_retry : AUX_DEFER_RETRY_COUNTER;
771 
772 	do {
773 		ctx.request.data = ctx.buffer;
774 		ctx.request.length = ctx.current_write_length;
775 
776 		process_write_request(engine, &ctx);
777 
778 		request->status = ctx.status;
779 
780 		if (ctx.operation_succeeded && !ctx.transaction_complete)
781 			if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
782 				msleep(engine->delay);
783 	} while (ctx.operation_succeeded && !ctx.transaction_complete);
784 
785 	if (request->payload.address_space ==
786 		I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
787 		DC_LOG_I2C_AUX("WRITE: addr:0x%x  value:0x%x Result:%d",
788 				request->payload.address,
789 				request->payload.data[0],
790 				ctx.operation_succeeded);
791 	}
792 
793 	return ctx.operation_succeeded;
794 }
795 static bool end_of_transaction_command(
796 	struct aux_engine *engine,
797 	struct i2caux_transaction_request *request)
798 {
799 	struct i2caux_transaction_request dummy_request;
800 	uint8_t dummy_data;
801 
802 	/* [tcheng] We only need to send the stop (read with MOT = 0)
803 	 * for I2C-over-Aux, not native AUX
804 	 */
805 
806 	if (request->payload.address_space !=
807 		I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C)
808 		return false;
809 
810 	dummy_request.operation = request->operation;
811 	dummy_request.payload.address_space = request->payload.address_space;
812 	dummy_request.payload.address = request->payload.address;
813 
814 	/*
815 	 * Add a dummy byte due to some receiver quirk
816 	 * where one byte is sent along with MOT = 0.
817 	 * Ideally this should be 0.
818 	 */
819 
820 	dummy_request.payload.length = 0;
821 	dummy_request.payload.data = &dummy_data;
822 
823 	if (request->operation == I2CAUX_TRANSACTION_READ)
824 		return read_command(engine, &dummy_request, false);
825 	else
826 		return write_command(engine, &dummy_request, false);
827 
828 	/* according Syed, it does not need now DoDummyMOT */
829 }
830 static bool submit_request(
831 	struct aux_engine *engine,
832 	struct i2caux_transaction_request *request,
833 	bool middle_of_transaction)
834 {
835 
836 	bool result;
837 	bool mot_used = true;
838 
839 	switch (request->operation) {
840 	case I2CAUX_TRANSACTION_READ:
841 		result = read_command(engine, request, mot_used);
842 	break;
843 	case I2CAUX_TRANSACTION_WRITE:
844 		result = write_command(engine, request, mot_used);
845 	break;
846 	default:
847 		result = false;
848 	}
849 
850 	/* [tcheng]
851 	 * need to send stop for the last transaction to free up the AUX
852 	 * if the above command fails, this would be the last transaction
853 	 */
854 
855 	if (!middle_of_transaction || !result)
856 		end_of_transaction_command(engine, request);
857 
858 	/* mask AUX interrupt */
859 
860 	return result;
861 }
862 enum i2caux_engine_type get_engine_type(
863 		const struct aux_engine *engine)
864 {
865 	return I2CAUX_ENGINE_TYPE_AUX;
866 }
867 
868 static bool acquire(
869 	struct aux_engine *engine,
870 	struct ddc *ddc)
871 {
872 
873 	enum gpio_result result;
874 
875 	if (engine->funcs->is_engine_available) {
876 		/*check whether SW could use the engine*/
877 		if (!engine->funcs->is_engine_available(engine))
878 			return false;
879 	}
880 
881 	result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
882 		GPIO_DDC_CONFIG_TYPE_MODE_AUX);
883 
884 	if (result != GPIO_RESULT_OK)
885 		return false;
886 
887 	if (!engine->funcs->acquire_engine(engine)) {
888 		dal_ddc_close(ddc);
889 		return false;
890 	}
891 
892 	engine->ddc = ddc;
893 
894 	return true;
895 }
896 
897 static const struct aux_engine_funcs aux_engine_funcs = {
898 	.acquire_engine = acquire_engine,
899 	.submit_channel_request = submit_channel_request,
900 	.process_channel_reply = process_channel_reply,
901 	.read_channel_reply = read_channel_reply,
902 	.get_channel_status = get_channel_status,
903 	.is_engine_available = is_engine_available,
904 	.release_engine = release_engine,
905 	.destroy_engine = dce110_engine_destroy,
906 	.submit_request = submit_request,
907 	.get_engine_type = get_engine_type,
908 	.acquire = acquire,
909 };
910 
911 void dce110_engine_destroy(struct aux_engine **engine)
912 {
913 
914 	struct aux_engine_dce110 *engine110 = FROM_AUX_ENGINE(*engine);
915 
916 	kfree(engine110);
917 	*engine = NULL;
918 
919 }
920 struct aux_engine *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_engine110,
921 		struct dc_context *ctx,
922 		uint32_t inst,
923 		uint32_t timeout_period,
924 		const struct dce110_aux_registers *regs)
925 {
926 	aux_engine110->base.ddc = NULL;
927 	aux_engine110->base.ctx = ctx;
928 	aux_engine110->base.delay = 0;
929 	aux_engine110->base.max_defer_write_retry = 0;
930 	aux_engine110->base.funcs = &aux_engine_funcs;
931 	aux_engine110->base.inst = inst;
932 	aux_engine110->timeout_period = timeout_period;
933 	aux_engine110->regs = regs;
934 
935 	return &aux_engine110->base;
936 }
937 
938