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 
28 /*
29  * Pre-requisites: headers required by header of this unit
30  */
31 #include "include/i2caux_interface.h"
32 #include "engine.h"
33 
34 /*
35  * Header of this unit
36  */
37 
38 #include "aux_engine.h"
39 
40 /*
41  * Post-requisites: headers required by this unit
42  */
43 
44 #include "include/link_service_types.h"
45 
46 /*
47  * This unit
48  */
49 
50 enum {
51 	AUX_INVALID_REPLY_RETRY_COUNTER = 1,
52 	AUX_TIMED_OUT_RETRY_COUNTER = 2,
53 	AUX_DEFER_RETRY_COUNTER = 6
54 };
55 
56 #define FROM_ENGINE(ptr) \
57 	container_of((ptr), struct aux_engine, base)
58 #define DC_LOGGER \
59 	engine->base.ctx->logger
60 
61 enum i2caux_engine_type dal_aux_engine_get_engine_type(
62 	const struct engine *engine)
63 {
64 	return I2CAUX_ENGINE_TYPE_AUX;
65 }
66 
67 bool dal_aux_engine_acquire(
68 	struct engine *engine,
69 	struct ddc *ddc)
70 {
71 	struct aux_engine *aux_engine = FROM_ENGINE(engine);
72 
73 	enum gpio_result result;
74 	if (aux_engine->funcs->is_engine_available) {
75 		/*check whether SW could use the engine*/
76 		if (!aux_engine->funcs->is_engine_available(aux_engine)) {
77 			return false;
78 		}
79 	}
80 
81 	result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
82 		GPIO_DDC_CONFIG_TYPE_MODE_AUX);
83 
84 	if (result != GPIO_RESULT_OK)
85 		return false;
86 
87 	if (!aux_engine->funcs->acquire_engine(aux_engine)) {
88 		dal_ddc_close(ddc);
89 		return false;
90 	}
91 
92 	engine->ddc = ddc;
93 
94 	return true;
95 }
96 
97 struct read_command_context {
98 	uint8_t *buffer;
99 	uint32_t current_read_length;
100 	uint32_t offset;
101 	enum i2caux_transaction_status status;
102 
103 	struct aux_request_transaction_data request;
104 	struct aux_reply_transaction_data reply;
105 
106 	uint8_t returned_byte;
107 
108 	uint32_t timed_out_retry_aux;
109 	uint32_t invalid_reply_retry_aux;
110 	uint32_t defer_retry_aux;
111 	uint32_t defer_retry_i2c;
112 	uint32_t invalid_reply_retry_aux_on_ack;
113 
114 	bool transaction_complete;
115 	bool operation_succeeded;
116 };
117 
118 static void process_read_reply(
119 	struct aux_engine *engine,
120 	struct read_command_context *ctx)
121 {
122 	engine->funcs->process_channel_reply(engine, &ctx->reply);
123 
124 	switch (ctx->reply.status) {
125 	case AUX_TRANSACTION_REPLY_AUX_ACK:
126 		ctx->defer_retry_aux = 0;
127 		if (ctx->returned_byte > ctx->current_read_length) {
128 			ctx->status =
129 				I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
130 			ctx->operation_succeeded = false;
131 		} else if (ctx->returned_byte < ctx->current_read_length) {
132 			ctx->current_read_length -= ctx->returned_byte;
133 
134 			ctx->offset += ctx->returned_byte;
135 
136 			++ctx->invalid_reply_retry_aux_on_ack;
137 
138 			if (ctx->invalid_reply_retry_aux_on_ack >
139 				AUX_INVALID_REPLY_RETRY_COUNTER) {
140 				ctx->status =
141 				I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
142 				ctx->operation_succeeded = false;
143 			}
144 		} else {
145 			ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
146 			ctx->transaction_complete = true;
147 			ctx->operation_succeeded = true;
148 		}
149 	break;
150 	case AUX_TRANSACTION_REPLY_AUX_NACK:
151 		ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
152 		ctx->operation_succeeded = false;
153 	break;
154 	case AUX_TRANSACTION_REPLY_AUX_DEFER:
155 		++ctx->defer_retry_aux;
156 
157 		if (ctx->defer_retry_aux > AUX_DEFER_RETRY_COUNTER) {
158 			ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
159 			ctx->operation_succeeded = false;
160 		}
161 	break;
162 	case AUX_TRANSACTION_REPLY_I2C_DEFER:
163 		ctx->defer_retry_aux = 0;
164 
165 		++ctx->defer_retry_i2c;
166 
167 		if (ctx->defer_retry_i2c > AUX_DEFER_RETRY_COUNTER) {
168 			ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
169 			ctx->operation_succeeded = false;
170 		}
171 	break;
172 	case AUX_TRANSACTION_REPLY_HPD_DISCON:
173 		ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
174 		ctx->operation_succeeded = false;
175 	break;
176 	default:
177 		ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
178 		ctx->operation_succeeded = false;
179 	}
180 }
181 
182 static void process_read_request(
183 	struct aux_engine *engine,
184 	struct read_command_context *ctx)
185 {
186 	enum aux_channel_operation_result operation_result;
187 
188 	engine->funcs->submit_channel_request(engine, &ctx->request);
189 
190 	operation_result = engine->funcs->get_channel_status(
191 		engine, &ctx->returned_byte);
192 
193 	switch (operation_result) {
194 	case AUX_CHANNEL_OPERATION_SUCCEEDED:
195 		if (ctx->returned_byte > ctx->current_read_length) {
196 			ctx->status =
197 				I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
198 			ctx->operation_succeeded = false;
199 		} else {
200 			ctx->timed_out_retry_aux = 0;
201 			ctx->invalid_reply_retry_aux = 0;
202 
203 			ctx->reply.length = ctx->returned_byte;
204 			ctx->reply.data = ctx->buffer;
205 
206 			process_read_reply(engine, ctx);
207 		}
208 	break;
209 	case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
210 		++ctx->invalid_reply_retry_aux;
211 
212 		if (ctx->invalid_reply_retry_aux >
213 			AUX_INVALID_REPLY_RETRY_COUNTER) {
214 			ctx->status =
215 				I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
216 			ctx->operation_succeeded = false;
217 		} else
218 			udelay(400);
219 	break;
220 	case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
221 		++ctx->timed_out_retry_aux;
222 
223 		if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
224 			ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
225 			ctx->operation_succeeded = false;
226 		} else {
227 			/* DP 1.2a, table 2-58:
228 			 * "S3: AUX Request CMD PENDING:
229 			 * retry 3 times, with 400usec wait on each"
230 			 * The HW timeout is set to 550usec,
231 			 * so we should not wait here */
232 		}
233 	break;
234 	case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
235 		ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
236 		ctx->operation_succeeded = false;
237 	break;
238 	default:
239 		ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
240 		ctx->operation_succeeded = false;
241 	}
242 }
243 
244 static bool read_command(
245 	struct aux_engine *engine,
246 	struct i2caux_transaction_request *request,
247 	bool middle_of_transaction)
248 {
249 	struct read_command_context ctx;
250 
251 	ctx.buffer = request->payload.data;
252 	ctx.current_read_length = request->payload.length;
253 	ctx.offset = 0;
254 	ctx.timed_out_retry_aux = 0;
255 	ctx.invalid_reply_retry_aux = 0;
256 	ctx.defer_retry_aux = 0;
257 	ctx.defer_retry_i2c = 0;
258 	ctx.invalid_reply_retry_aux_on_ack = 0;
259 	ctx.transaction_complete = false;
260 	ctx.operation_succeeded = true;
261 
262 	if (request->payload.address_space ==
263 		I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
264 		ctx.request.type = AUX_TRANSACTION_TYPE_DP;
265 		ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_READ;
266 		ctx.request.address = request->payload.address;
267 	} else if (request->payload.address_space ==
268 		I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
269 		ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
270 		ctx.request.action = middle_of_transaction ?
271 			I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT :
272 			I2CAUX_TRANSACTION_ACTION_I2C_READ;
273 		ctx.request.address = request->payload.address >> 1;
274 	} else {
275 		/* in DAL2, there was no return in such case */
276 		BREAK_TO_DEBUGGER();
277 		return false;
278 	}
279 
280 	ctx.request.delay = 0;
281 
282 	do {
283 		memset(ctx.buffer + ctx.offset, 0, ctx.current_read_length);
284 
285 		ctx.request.data = ctx.buffer + ctx.offset;
286 		ctx.request.length = ctx.current_read_length;
287 
288 		process_read_request(engine, &ctx);
289 
290 		request->status = ctx.status;
291 
292 		if (ctx.operation_succeeded && !ctx.transaction_complete)
293 			if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
294 				msleep(engine->delay);
295 	} while (ctx.operation_succeeded && !ctx.transaction_complete);
296 
297 	if (request->payload.address_space ==
298 		I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
299 		DC_LOG_I2C_AUX("READ: addr:0x%x  value:0x%x Result:%d",
300 				request->payload.address,
301 				request->payload.data[0],
302 				ctx.operation_succeeded);
303 	}
304 
305 	return ctx.operation_succeeded;
306 }
307 
308 struct write_command_context {
309 	bool mot;
310 
311 	uint8_t *buffer;
312 	uint32_t current_write_length;
313 	enum i2caux_transaction_status status;
314 
315 	struct aux_request_transaction_data request;
316 	struct aux_reply_transaction_data reply;
317 
318 	uint8_t returned_byte;
319 
320 	uint32_t timed_out_retry_aux;
321 	uint32_t invalid_reply_retry_aux;
322 	uint32_t defer_retry_aux;
323 	uint32_t defer_retry_i2c;
324 	uint32_t max_defer_retry;
325 	uint32_t ack_m_retry;
326 
327 	uint8_t reply_data[DEFAULT_AUX_MAX_DATA_SIZE];
328 
329 	bool transaction_complete;
330 	bool operation_succeeded;
331 };
332 
333 static void process_write_reply(
334 	struct aux_engine *engine,
335 	struct write_command_context *ctx)
336 {
337 	engine->funcs->process_channel_reply(engine, &ctx->reply);
338 
339 	switch (ctx->reply.status) {
340 	case AUX_TRANSACTION_REPLY_AUX_ACK:
341 		ctx->operation_succeeded = true;
342 
343 		if (ctx->returned_byte) {
344 			ctx->request.action = ctx->mot ?
345 			I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
346 			I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
347 
348 			ctx->current_write_length = 0;
349 
350 			++ctx->ack_m_retry;
351 
352 			if (ctx->ack_m_retry > AUX_DEFER_RETRY_COUNTER) {
353 				ctx->status =
354 				I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
355 				ctx->operation_succeeded = false;
356 			} else
357 				udelay(300);
358 		} else {
359 			ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
360 			ctx->defer_retry_aux = 0;
361 			ctx->ack_m_retry = 0;
362 			ctx->transaction_complete = true;
363 		}
364 	break;
365 	case AUX_TRANSACTION_REPLY_AUX_NACK:
366 		ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
367 		ctx->operation_succeeded = false;
368 	break;
369 	case AUX_TRANSACTION_REPLY_AUX_DEFER:
370 		++ctx->defer_retry_aux;
371 
372 		if (ctx->defer_retry_aux > ctx->max_defer_retry) {
373 			ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
374 			ctx->operation_succeeded = false;
375 		}
376 	break;
377 	case AUX_TRANSACTION_REPLY_I2C_DEFER:
378 		ctx->defer_retry_aux = 0;
379 		ctx->current_write_length = 0;
380 
381 		ctx->request.action = ctx->mot ?
382 			I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
383 			I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
384 
385 		++ctx->defer_retry_i2c;
386 
387 		if (ctx->defer_retry_i2c > ctx->max_defer_retry) {
388 			ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
389 			ctx->operation_succeeded = false;
390 		}
391 	break;
392 	case AUX_TRANSACTION_REPLY_HPD_DISCON:
393 		ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
394 		ctx->operation_succeeded = false;
395 	break;
396 	default:
397 		ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
398 		ctx->operation_succeeded = false;
399 	}
400 }
401 
402 static void process_write_request(
403 	struct aux_engine *engine,
404 	struct write_command_context *ctx)
405 {
406 	enum aux_channel_operation_result operation_result;
407 
408 	engine->funcs->submit_channel_request(engine, &ctx->request);
409 
410 	operation_result = engine->funcs->get_channel_status(
411 		engine, &ctx->returned_byte);
412 
413 	switch (operation_result) {
414 	case AUX_CHANNEL_OPERATION_SUCCEEDED:
415 		ctx->timed_out_retry_aux = 0;
416 		ctx->invalid_reply_retry_aux = 0;
417 
418 		ctx->reply.length = ctx->returned_byte;
419 		ctx->reply.data = ctx->reply_data;
420 
421 		process_write_reply(engine, ctx);
422 	break;
423 	case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
424 		++ctx->invalid_reply_retry_aux;
425 
426 		if (ctx->invalid_reply_retry_aux >
427 			AUX_INVALID_REPLY_RETRY_COUNTER) {
428 			ctx->status =
429 				I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
430 			ctx->operation_succeeded = false;
431 		} else
432 			udelay(400);
433 	break;
434 	case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
435 		++ctx->timed_out_retry_aux;
436 
437 		if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
438 			ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
439 			ctx->operation_succeeded = false;
440 		} else {
441 			/* DP 1.2a, table 2-58:
442 			 * "S3: AUX Request CMD PENDING:
443 			 * retry 3 times, with 400usec wait on each"
444 			 * The HW timeout is set to 550usec,
445 			 * so we should not wait here */
446 		}
447 	break;
448 	case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
449 		ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
450 		ctx->operation_succeeded = false;
451 	break;
452 	default:
453 		ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
454 		ctx->operation_succeeded = false;
455 	}
456 }
457 
458 static bool write_command(
459 	struct aux_engine *engine,
460 	struct i2caux_transaction_request *request,
461 	bool middle_of_transaction)
462 {
463 	struct write_command_context ctx;
464 
465 	ctx.mot = middle_of_transaction;
466 	ctx.buffer = request->payload.data;
467 	ctx.current_write_length = request->payload.length;
468 	ctx.timed_out_retry_aux = 0;
469 	ctx.invalid_reply_retry_aux = 0;
470 	ctx.defer_retry_aux = 0;
471 	ctx.defer_retry_i2c = 0;
472 	ctx.ack_m_retry = 0;
473 	ctx.transaction_complete = false;
474 	ctx.operation_succeeded = true;
475 
476 	if (request->payload.address_space ==
477 		I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
478 		ctx.request.type = AUX_TRANSACTION_TYPE_DP;
479 		ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_WRITE;
480 		ctx.request.address = request->payload.address;
481 	} else if (request->payload.address_space ==
482 		I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
483 		ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
484 		ctx.request.action = middle_of_transaction ?
485 			I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT :
486 			I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
487 		ctx.request.address = request->payload.address >> 1;
488 	} else {
489 		/* in DAL2, there was no return in such case */
490 		BREAK_TO_DEBUGGER();
491 		return false;
492 	}
493 
494 	ctx.request.delay = 0;
495 
496 	ctx.max_defer_retry =
497 		(engine->max_defer_write_retry > AUX_DEFER_RETRY_COUNTER) ?
498 			engine->max_defer_write_retry : AUX_DEFER_RETRY_COUNTER;
499 
500 	do {
501 		ctx.request.data = ctx.buffer;
502 		ctx.request.length = ctx.current_write_length;
503 
504 		process_write_request(engine, &ctx);
505 
506 		request->status = ctx.status;
507 
508 		if (ctx.operation_succeeded && !ctx.transaction_complete)
509 			if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
510 				msleep(engine->delay);
511 	} while (ctx.operation_succeeded && !ctx.transaction_complete);
512 
513 	if (request->payload.address_space ==
514 		I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
515 		DC_LOG_I2C_AUX("WRITE: addr:0x%x  value:0x%x Result:%d",
516 				request->payload.address,
517 				request->payload.data[0],
518 				ctx.operation_succeeded);
519 	}
520 
521 	return ctx.operation_succeeded;
522 }
523 
524 static bool end_of_transaction_command(
525 	struct aux_engine *engine,
526 	struct i2caux_transaction_request *request)
527 {
528 	struct i2caux_transaction_request dummy_request;
529 	uint8_t dummy_data;
530 
531 	/* [tcheng] We only need to send the stop (read with MOT = 0)
532 	 * for I2C-over-Aux, not native AUX */
533 
534 	if (request->payload.address_space !=
535 		I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C)
536 		return false;
537 
538 	dummy_request.operation = request->operation;
539 	dummy_request.payload.address_space = request->payload.address_space;
540 	dummy_request.payload.address = request->payload.address;
541 
542 	/*
543 	 * Add a dummy byte due to some receiver quirk
544 	 * where one byte is sent along with MOT = 0.
545 	 * Ideally this should be 0.
546 	 */
547 
548 	dummy_request.payload.length = 0;
549 	dummy_request.payload.data = &dummy_data;
550 
551 	if (request->operation == I2CAUX_TRANSACTION_READ)
552 		return read_command(engine, &dummy_request, false);
553 	else
554 		return write_command(engine, &dummy_request, false);
555 
556 	/* according Syed, it does not need now DoDummyMOT */
557 }
558 
559 bool dal_aux_engine_submit_request(
560 	struct engine *engine,
561 	struct i2caux_transaction_request *request,
562 	bool middle_of_transaction)
563 {
564 	struct aux_engine *aux_engine = FROM_ENGINE(engine);
565 
566 	bool result;
567 	bool mot_used = true;
568 
569 	switch (request->operation) {
570 	case I2CAUX_TRANSACTION_READ:
571 		result = read_command(aux_engine, request, mot_used);
572 	break;
573 	case I2CAUX_TRANSACTION_WRITE:
574 		result = write_command(aux_engine, request, mot_used);
575 	break;
576 	default:
577 		result = false;
578 	}
579 
580 	/* [tcheng]
581 	 * need to send stop for the last transaction to free up the AUX
582 	 * if the above command fails, this would be the last transaction */
583 
584 	if (!middle_of_transaction || !result)
585 		end_of_transaction_command(aux_engine, request);
586 
587 	/* mask AUX interrupt */
588 
589 	return result;
590 }
591 
592 void dal_aux_engine_construct(
593 	struct aux_engine *engine,
594 	struct dc_context *ctx)
595 {
596 	dal_i2caux_construct_engine(&engine->base, ctx);
597 	engine->delay = 0;
598 	engine->max_defer_write_retry = 0;
599 }
600 
601 void dal_aux_engine_destruct(
602 	struct aux_engine *engine)
603 {
604 	dal_i2caux_destruct_engine(&engine->base);
605 }
606