2 * Copyright 2012-15 Advanced Micro Devices, Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
26 #include "dm_services.h"
28 #include "dce/dce_11_0_sh_mask.h"
32 #define REG(reg_name)\
33 (aux110->regs->reg_name)
38 #include "reg_helper.h"
40 #define FROM_AUX_ENGINE(ptr) \
41 container_of((ptr), struct aux_engine_dce110, base)
43 #define FROM_ENGINE(ptr) \
44 FROM_AUX_ENGINE(container_of((ptr), struct aux_engine, base))
46 #define FROM_AUX_ENGINE_ENGINE(ptr) \
47 container_of((ptr), struct aux_engine, base)
49 AUX_INVALID_REPLY_RETRY_COUNTER = 1,
50 AUX_TIMED_OUT_RETRY_COUNTER = 2,
51 AUX_DEFER_RETRY_COUNTER = 6
53 static void release_engine(
54 struct aux_engine *engine)
56 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
58 dal_ddc_close(engine->ddc);
62 REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_DONE_USING_AUX_REG, 1);
65 #define SW_CAN_ACCESS_AUX 1
66 #define DMCU_CAN_ACCESS_AUX 2
68 static bool is_engine_available(
69 struct aux_engine *engine)
71 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
73 uint32_t value = REG_READ(AUX_ARB_CONTROL);
74 uint32_t field = get_reg_field_value(
77 AUX_REG_RW_CNTL_STATUS);
79 return (field != DMCU_CAN_ACCESS_AUX);
81 static bool acquire_engine(
82 struct aux_engine *engine)
84 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
86 uint32_t value = REG_READ(AUX_ARB_CONTROL);
87 uint32_t field = get_reg_field_value(
90 AUX_REG_RW_CNTL_STATUS);
91 if (field == DMCU_CAN_ACCESS_AUX)
93 /* enable AUX before request SW to access AUX */
94 value = REG_READ(AUX_CONTROL);
95 field = get_reg_field_value(value,
106 if (REG(AUX_RESET_MASK)) {
107 /*DP_AUX block as part of the enable sequence*/
115 REG_WRITE(AUX_CONTROL, value);
117 if (REG(AUX_RESET_MASK)) {
118 /*poll HW to make sure reset it done*/
120 REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 1,
129 REG_WRITE(AUX_CONTROL, value);
131 REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 0,
136 /* request SW to access AUX */
137 REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_USE_AUX_REG_REQ, 1);
139 value = REG_READ(AUX_ARB_CONTROL);
140 field = get_reg_field_value(
143 AUX_REG_RW_CNTL_STATUS);
145 return (field == SW_CAN_ACCESS_AUX);
148 #define COMPOSE_AUX_SW_DATA_16_20(command, address) \
149 ((command) | ((0xF0000 & (address)) >> 16))
151 #define COMPOSE_AUX_SW_DATA_8_15(address) \
152 ((0xFF00 & (address)) >> 8)
154 #define COMPOSE_AUX_SW_DATA_0_7(address) \
157 static void submit_channel_request(
158 struct aux_engine *engine,
159 struct aux_request_transaction_data *request)
161 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
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,
177 REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_CALOUT_ERROR_AK,
181 /* force_default_calibrate */
182 REG_UPDATE_1BY1_2(AUXN_IMPCAL,
183 AUXN_IMPCAL_ENABLE, 1,
184 AUXN_IMPCAL_OVERRIDE_ENABLE, 0);
186 /* bug? why AUXN update EN and OVERRIDE_EN 1 by 1 while AUX P toggles OVERRIDE? */
188 REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_IMPCAL_OVERRIDE_ENABLE,
192 /* set the delay and the number of bytes to write */
194 /* The length include
195 * the 4 bit header and the 20 bit address
197 * If the requested length is non zero this means
198 * an addition byte specifying the length is required.
201 length = request->length ? 4 : 3;
203 length += request->length;
205 REG_UPDATE_2(AUX_SW_CONTROL,
206 AUX_SW_START_DELAY, request->delay,
207 AUX_SW_WR_BYTES, length);
209 /* program action and address and payload data (if 'is_write') */
210 value = REG_UPDATE_4(AUX_SW_DATA,
213 AUX_SW_AUTOINCREMENT_DISABLE, 1,
214 AUX_SW_DATA, COMPOSE_AUX_SW_DATA_16_20(request->action, request->address));
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));
220 value = REG_SET(AUX_SW_DATA, value,
221 AUX_SW_DATA, COMPOSE_AUX_SW_DATA_0_7(request->address));
223 if (request->length) {
224 value = REG_SET(AUX_SW_DATA, value,
225 AUX_SW_DATA, request->length - 1);
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().
236 while (i < request->length) {
237 value = REG_SET(AUX_SW_DATA, value,
238 AUX_SW_DATA, request->data[i]);
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);
250 static int read_channel_reply(struct aux_engine *engine, uint32_t size,
251 uint8_t *buffer, uint8_t *reply_result,
254 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
255 uint32_t bytes_replied;
256 uint32_t reply_result_32;
258 *sw_status = REG_GET(AUX_SW_STATUS, AUX_SW_REPLY_BYTE_COUNT,
261 /* In case HPD is LOW, exit AUX transaction */
262 if ((*sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
265 /* Need at least the status byte */
269 REG_UPDATE_1BY1_3(AUX_SW_DATA,
271 AUX_SW_AUTOINCREMENT_DISABLE, 1,
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;
278 if (reply_result_32 == 0) { /* ACK */
281 /* First byte was already used to get the command status */
284 /* Do not overflow buffer */
285 if (bytes_replied > size)
288 while (i < bytes_replied) {
289 uint32_t aux_sw_data_val;
291 REG_GET(AUX_SW_DATA, AUX_SW_DATA, &aux_sw_data_val);
292 buffer[i] = aux_sw_data_val;
302 static void process_channel_reply(
303 struct aux_engine *engine,
304 struct aux_reply_transaction_data *reply)
307 uint8_t reply_result;
310 bytes_replied = read_channel_reply(engine, reply->length, reply->data,
311 &reply_result, &sw_status);
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;
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
326 if (!(sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
327 reply->status = AUX_TRANSACTION_REPLY_INVALID;
328 ASSERT_CRITICAL(false);
333 switch (reply_result) {
335 reply->status = AUX_TRANSACTION_REPLY_AUX_ACK;
338 reply->status = AUX_TRANSACTION_REPLY_AUX_NACK;
341 reply->status = AUX_TRANSACTION_REPLY_AUX_DEFER;
343 case 4: /* AUX ACK / I2C NACK */
344 reply->status = AUX_TRANSACTION_REPLY_I2C_NACK;
346 case 8: /* AUX ACK / I2C DEFER */
347 reply->status = AUX_TRANSACTION_REPLY_I2C_DEFER;
350 reply->status = AUX_TRANSACTION_REPLY_INVALID;
355 static enum aux_channel_operation_result get_channel_status(
356 struct aux_engine *engine,
357 uint8_t *returned_bytes)
359 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
363 if (returned_bytes == NULL) {
364 /*caller pass NULL pointer*/
365 ASSERT_CRITICAL(false);
366 return AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN;
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);
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;
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.
383 * AUX_SW_RX_MIN_COUNT_VIOL is an internal,
384 * HW debugging bit and should be ignored.
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;
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) ||
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;
398 *returned_bytes = get_reg_field_value(value,
400 AUX_SW_REPLY_BYTE_COUNT);
402 if (*returned_bytes == 0)
404 AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
406 *returned_bytes -= 1;
407 return AUX_CHANNEL_OPERATION_SUCCEEDED;
410 /*time_elapsed >= aux_engine->timeout_period
411 * AUX_SW_STATUS__AUX_SW_HPD_DISCON = at this point
413 ASSERT_CRITICAL(false);
414 return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
417 static void process_read_reply(
418 struct aux_engine *engine,
419 struct read_command_context *ctx)
421 engine->funcs->process_channel_reply(engine, &ctx->reply);
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) {
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;
433 ctx->offset += ctx->returned_byte;
435 ++ctx->invalid_reply_retry_aux_on_ack;
437 if (ctx->invalid_reply_retry_aux_on_ack >
438 AUX_INVALID_REPLY_RETRY_COUNTER) {
440 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
441 ctx->operation_succeeded = false;
444 ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
445 ctx->transaction_complete = true;
446 ctx->operation_succeeded = true;
449 case AUX_TRANSACTION_REPLY_AUX_NACK:
450 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
451 ctx->operation_succeeded = false;
453 case AUX_TRANSACTION_REPLY_AUX_DEFER:
454 ++ctx->defer_retry_aux;
456 if (ctx->defer_retry_aux > AUX_DEFER_RETRY_COUNTER) {
457 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
458 ctx->operation_succeeded = false;
461 case AUX_TRANSACTION_REPLY_I2C_DEFER:
462 ctx->defer_retry_aux = 0;
464 ++ctx->defer_retry_i2c;
466 if (ctx->defer_retry_i2c > AUX_DEFER_RETRY_COUNTER) {
467 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
468 ctx->operation_succeeded = false;
471 case AUX_TRANSACTION_REPLY_HPD_DISCON:
472 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
473 ctx->operation_succeeded = false;
476 ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
477 ctx->operation_succeeded = false;
480 static void process_read_request(
481 struct aux_engine *engine,
482 struct read_command_context *ctx)
484 enum aux_channel_operation_result operation_result;
486 engine->funcs->submit_channel_request(engine, &ctx->request);
488 operation_result = engine->funcs->get_channel_status(
489 engine, &ctx->returned_byte);
491 switch (operation_result) {
492 case AUX_CHANNEL_OPERATION_SUCCEEDED:
493 if (ctx->returned_byte > ctx->current_read_length) {
495 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
496 ctx->operation_succeeded = false;
498 ctx->timed_out_retry_aux = 0;
499 ctx->invalid_reply_retry_aux = 0;
501 ctx->reply.length = ctx->returned_byte;
502 ctx->reply.data = ctx->buffer;
504 process_read_reply(engine, ctx);
507 case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
508 ++ctx->invalid_reply_retry_aux;
510 if (ctx->invalid_reply_retry_aux >
511 AUX_INVALID_REPLY_RETRY_COUNTER) {
513 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
514 ctx->operation_succeeded = false;
518 case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
519 ++ctx->timed_out_retry_aux;
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;
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
533 case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
534 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
535 ctx->operation_succeeded = false;
538 ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
539 ctx->operation_succeeded = false;
542 static bool read_command(
543 struct aux_engine *engine,
544 struct i2caux_transaction_request *request,
545 bool middle_of_transaction)
547 struct read_command_context ctx;
549 ctx.buffer = request->payload.data;
550 ctx.current_read_length = request->payload.length;
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;
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;
573 /* in DAL2, there was no return in such case */
578 ctx.request.delay = 0;
581 memset(ctx.buffer + ctx.offset, 0, ctx.current_read_length);
583 ctx.request.data = ctx.buffer + ctx.offset;
584 ctx.request.length = ctx.current_read_length;
586 process_read_request(engine, &ctx);
588 request->status = ctx.status;
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);
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);
603 return ctx.operation_succeeded;
606 static void process_write_reply(
607 struct aux_engine *engine,
608 struct write_command_context *ctx)
610 engine->funcs->process_channel_reply(engine, &ctx->reply);
612 switch (ctx->reply.status) {
613 case AUX_TRANSACTION_REPLY_AUX_ACK:
614 ctx->operation_succeeded = true;
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;
621 ctx->current_write_length = 0;
625 if (ctx->ack_m_retry > AUX_DEFER_RETRY_COUNTER) {
627 I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
628 ctx->operation_succeeded = false;
632 ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
633 ctx->defer_retry_aux = 0;
634 ctx->ack_m_retry = 0;
635 ctx->transaction_complete = true;
638 case AUX_TRANSACTION_REPLY_AUX_NACK:
639 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
640 ctx->operation_succeeded = false;
642 case AUX_TRANSACTION_REPLY_AUX_DEFER:
643 ++ctx->defer_retry_aux;
645 if (ctx->defer_retry_aux > ctx->max_defer_retry) {
646 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
647 ctx->operation_succeeded = false;
650 case AUX_TRANSACTION_REPLY_I2C_DEFER:
651 ctx->defer_retry_aux = 0;
652 ctx->current_write_length = 0;
654 ctx->request.action = ctx->mot ?
655 I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
656 I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
658 ++ctx->defer_retry_i2c;
660 if (ctx->defer_retry_i2c > ctx->max_defer_retry) {
661 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
662 ctx->operation_succeeded = false;
665 case AUX_TRANSACTION_REPLY_HPD_DISCON:
666 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
667 ctx->operation_succeeded = false;
670 ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
671 ctx->operation_succeeded = false;
674 static void process_write_request(
675 struct aux_engine *engine,
676 struct write_command_context *ctx)
678 enum aux_channel_operation_result operation_result;
680 engine->funcs->submit_channel_request(engine, &ctx->request);
682 operation_result = engine->funcs->get_channel_status(
683 engine, &ctx->returned_byte);
685 switch (operation_result) {
686 case AUX_CHANNEL_OPERATION_SUCCEEDED:
687 ctx->timed_out_retry_aux = 0;
688 ctx->invalid_reply_retry_aux = 0;
690 ctx->reply.length = ctx->returned_byte;
691 ctx->reply.data = ctx->reply_data;
693 process_write_reply(engine, ctx);
695 case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
696 ++ctx->invalid_reply_retry_aux;
698 if (ctx->invalid_reply_retry_aux >
699 AUX_INVALID_REPLY_RETRY_COUNTER) {
701 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
702 ctx->operation_succeeded = false;
706 case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
707 ++ctx->timed_out_retry_aux;
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;
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
721 case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
722 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
723 ctx->operation_succeeded = false;
726 ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
727 ctx->operation_succeeded = false;
730 static bool write_command(
731 struct aux_engine *engine,
732 struct i2caux_transaction_request *request,
733 bool middle_of_transaction)
735 struct write_command_context ctx;
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;
745 ctx.transaction_complete = false;
746 ctx.operation_succeeded = true;
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;
761 /* in DAL2, there was no return in such case */
766 ctx.request.delay = 0;
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;
773 ctx.request.data = ctx.buffer;
774 ctx.request.length = ctx.current_write_length;
776 process_write_request(engine, &ctx);
778 request->status = ctx.status;
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);
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);
793 return ctx.operation_succeeded;
795 static bool end_of_transaction_command(
796 struct aux_engine *engine,
797 struct i2caux_transaction_request *request)
799 struct i2caux_transaction_request dummy_request;
802 /* [tcheng] We only need to send the stop (read with MOT = 0)
803 * for I2C-over-Aux, not native AUX
806 if (request->payload.address_space !=
807 I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C)
810 dummy_request.operation = request->operation;
811 dummy_request.payload.address_space = request->payload.address_space;
812 dummy_request.payload.address = request->payload.address;
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.
820 dummy_request.payload.length = 0;
821 dummy_request.payload.data = &dummy_data;
823 if (request->operation == I2CAUX_TRANSACTION_READ)
824 return read_command(engine, &dummy_request, false);
826 return write_command(engine, &dummy_request, false);
828 /* according Syed, it does not need now DoDummyMOT */
830 static bool submit_request(
831 struct aux_engine *engine,
832 struct i2caux_transaction_request *request,
833 bool middle_of_transaction)
837 bool mot_used = true;
839 switch (request->operation) {
840 case I2CAUX_TRANSACTION_READ:
841 result = read_command(engine, request, mot_used);
843 case I2CAUX_TRANSACTION_WRITE:
844 result = write_command(engine, request, mot_used);
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
855 if (!middle_of_transaction || !result)
856 end_of_transaction_command(engine, request);
858 /* mask AUX interrupt */
862 enum i2caux_engine_type get_engine_type(
863 const struct aux_engine *engine)
865 return I2CAUX_ENGINE_TYPE_AUX;
869 struct aux_engine *engine,
873 enum gpio_result result;
875 if (engine->funcs->is_engine_available) {
876 /*check whether SW could use the engine*/
877 if (!engine->funcs->is_engine_available(engine))
881 result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
882 GPIO_DDC_CONFIG_TYPE_MODE_AUX);
884 if (result != GPIO_RESULT_OK)
887 if (!engine->funcs->acquire_engine(engine)) {
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,
911 void dce110_engine_destroy(struct aux_engine **engine)
914 struct aux_engine_dce110 *engine110 = FROM_AUX_ENGINE(*engine);
920 struct aux_engine *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_engine110,
921 struct dc_context *ctx,
923 uint32_t timeout_period,
924 const struct dce110_aux_registers *regs)
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;
935 return &aux_engine110->base;