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 if (reply_result != NULL)
277 *reply_result = (uint8_t)reply_result_32;
279 if (reply_result_32 == 0) { /* ACK */
282 /* First byte was already used to get the command status */
285 /* Do not overflow buffer */
286 if (bytes_replied > size)
289 while (i < bytes_replied) {
290 uint32_t aux_sw_data_val;
292 REG_GET(AUX_SW_DATA, AUX_SW_DATA, &aux_sw_data_val);
293 buffer[i] = aux_sw_data_val;
303 static void process_channel_reply(
304 struct aux_engine *engine,
305 struct aux_reply_transaction_data *reply)
308 uint8_t reply_result;
311 bytes_replied = read_channel_reply(engine, reply->length, reply->data,
312 &reply_result, &sw_status);
314 /* in case HPD is LOW, exit AUX transaction */
315 if ((sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
316 reply->status = AUX_TRANSACTION_REPLY_HPD_DISCON;
320 if (bytes_replied < 0) {
321 /* Need to handle an error case...
322 * Hopefully, upper layer function won't call this function if
323 * the number of bytes in the reply was 0, because there was
324 * surely an error that was asserted that should have been
325 * handled for hot plug case, this could happens
327 if (!(sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
328 reply->status = AUX_TRANSACTION_REPLY_INVALID;
329 ASSERT_CRITICAL(false);
334 switch (reply_result) {
336 reply->status = AUX_TRANSACTION_REPLY_AUX_ACK;
339 reply->status = AUX_TRANSACTION_REPLY_AUX_NACK;
342 reply->status = AUX_TRANSACTION_REPLY_AUX_DEFER;
344 case 4: /* AUX ACK / I2C NACK */
345 reply->status = AUX_TRANSACTION_REPLY_I2C_NACK;
347 case 8: /* AUX ACK / I2C DEFER */
348 reply->status = AUX_TRANSACTION_REPLY_I2C_DEFER;
351 reply->status = AUX_TRANSACTION_REPLY_INVALID;
356 static enum aux_channel_operation_result get_channel_status(
357 struct aux_engine *engine,
358 uint8_t *returned_bytes)
360 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
364 if (returned_bytes == NULL) {
365 /*caller pass NULL pointer*/
366 ASSERT_CRITICAL(false);
367 return AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN;
371 /* poll to make sure that SW_DONE is asserted */
372 value = REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 1,
373 10, aux110->timeout_period/10);
375 /* in case HPD is LOW, exit AUX transaction */
376 if ((value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
377 return AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON;
379 /* Note that the following bits are set in 'status.bits'
380 * during CTS 4.2.1.2 (FW 3.3.1):
381 * AUX_SW_RX_MIN_COUNT_VIOL, AUX_SW_RX_INVALID_STOP,
382 * AUX_SW_RX_RECV_NO_DET, AUX_SW_RX_RECV_INVALID_H.
384 * AUX_SW_RX_MIN_COUNT_VIOL is an internal,
385 * HW debugging bit and should be ignored.
387 if (value & AUX_SW_STATUS__AUX_SW_DONE_MASK) {
388 if ((value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_STATE_MASK) ||
389 (value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_MASK))
390 return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
392 else if ((value & AUX_SW_STATUS__AUX_SW_RX_INVALID_STOP_MASK) ||
393 (value & AUX_SW_STATUS__AUX_SW_RX_RECV_NO_DET_MASK) ||
395 AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_H_MASK) ||
396 (value & AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_L_MASK))
397 return AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
399 *returned_bytes = get_reg_field_value(value,
401 AUX_SW_REPLY_BYTE_COUNT);
403 if (*returned_bytes == 0)
405 AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
407 *returned_bytes -= 1;
408 return AUX_CHANNEL_OPERATION_SUCCEEDED;
411 /*time_elapsed >= aux_engine->timeout_period
412 * AUX_SW_STATUS__AUX_SW_HPD_DISCON = at this point
414 ASSERT_CRITICAL(false);
415 return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
418 static void process_read_reply(
419 struct aux_engine *engine,
420 struct read_command_context *ctx)
422 engine->funcs->process_channel_reply(engine, &ctx->reply);
424 switch (ctx->reply.status) {
425 case AUX_TRANSACTION_REPLY_AUX_ACK:
426 ctx->defer_retry_aux = 0;
427 if (ctx->returned_byte > ctx->current_read_length) {
429 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
430 ctx->operation_succeeded = false;
431 } else if (ctx->returned_byte < ctx->current_read_length) {
432 ctx->current_read_length -= ctx->returned_byte;
434 ctx->offset += ctx->returned_byte;
436 ++ctx->invalid_reply_retry_aux_on_ack;
438 if (ctx->invalid_reply_retry_aux_on_ack >
439 AUX_INVALID_REPLY_RETRY_COUNTER) {
441 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
442 ctx->operation_succeeded = false;
445 ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
446 ctx->transaction_complete = true;
447 ctx->operation_succeeded = true;
450 case AUX_TRANSACTION_REPLY_AUX_NACK:
451 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
452 ctx->operation_succeeded = false;
454 case AUX_TRANSACTION_REPLY_AUX_DEFER:
455 ++ctx->defer_retry_aux;
457 if (ctx->defer_retry_aux > AUX_DEFER_RETRY_COUNTER) {
458 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
459 ctx->operation_succeeded = false;
462 case AUX_TRANSACTION_REPLY_I2C_DEFER:
463 ctx->defer_retry_aux = 0;
465 ++ctx->defer_retry_i2c;
467 if (ctx->defer_retry_i2c > AUX_DEFER_RETRY_COUNTER) {
468 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
469 ctx->operation_succeeded = false;
472 case AUX_TRANSACTION_REPLY_HPD_DISCON:
473 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
474 ctx->operation_succeeded = false;
477 ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
478 ctx->operation_succeeded = false;
481 static void process_read_request(
482 struct aux_engine *engine,
483 struct read_command_context *ctx)
485 enum aux_channel_operation_result operation_result;
487 engine->funcs->submit_channel_request(engine, &ctx->request);
489 operation_result = engine->funcs->get_channel_status(
490 engine, &ctx->returned_byte);
492 switch (operation_result) {
493 case AUX_CHANNEL_OPERATION_SUCCEEDED:
494 if (ctx->returned_byte > ctx->current_read_length) {
496 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
497 ctx->operation_succeeded = false;
499 ctx->timed_out_retry_aux = 0;
500 ctx->invalid_reply_retry_aux = 0;
502 ctx->reply.length = ctx->returned_byte;
503 ctx->reply.data = ctx->buffer;
505 process_read_reply(engine, ctx);
508 case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
509 ++ctx->invalid_reply_retry_aux;
511 if (ctx->invalid_reply_retry_aux >
512 AUX_INVALID_REPLY_RETRY_COUNTER) {
514 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
515 ctx->operation_succeeded = false;
519 case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
520 ++ctx->timed_out_retry_aux;
522 if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
523 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
524 ctx->operation_succeeded = false;
526 /* DP 1.2a, table 2-58:
527 * "S3: AUX Request CMD PENDING:
528 * retry 3 times, with 400usec wait on each"
529 * The HW timeout is set to 550usec,
530 * so we should not wait here
534 case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
535 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
536 ctx->operation_succeeded = false;
539 ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
540 ctx->operation_succeeded = false;
543 static bool read_command(
544 struct aux_engine *engine,
545 struct i2caux_transaction_request *request,
546 bool middle_of_transaction)
548 struct read_command_context ctx;
550 ctx.buffer = request->payload.data;
551 ctx.current_read_length = request->payload.length;
553 ctx.timed_out_retry_aux = 0;
554 ctx.invalid_reply_retry_aux = 0;
555 ctx.defer_retry_aux = 0;
556 ctx.defer_retry_i2c = 0;
557 ctx.invalid_reply_retry_aux_on_ack = 0;
558 ctx.transaction_complete = false;
559 ctx.operation_succeeded = true;
561 if (request->payload.address_space ==
562 I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
563 ctx.request.type = AUX_TRANSACTION_TYPE_DP;
564 ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_READ;
565 ctx.request.address = request->payload.address;
566 } else if (request->payload.address_space ==
567 I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
568 ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
569 ctx.request.action = middle_of_transaction ?
570 I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT :
571 I2CAUX_TRANSACTION_ACTION_I2C_READ;
572 ctx.request.address = request->payload.address >> 1;
574 /* in DAL2, there was no return in such case */
579 ctx.request.delay = 0;
582 memset(ctx.buffer + ctx.offset, 0, ctx.current_read_length);
584 ctx.request.data = ctx.buffer + ctx.offset;
585 ctx.request.length = ctx.current_read_length;
587 process_read_request(engine, &ctx);
589 request->status = ctx.status;
591 if (ctx.operation_succeeded && !ctx.transaction_complete)
592 if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
593 msleep(engine->delay);
594 } while (ctx.operation_succeeded && !ctx.transaction_complete);
596 if (request->payload.address_space ==
597 I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
598 DC_LOG_I2C_AUX("READ: addr:0x%x value:0x%x Result:%d",
599 request->payload.address,
600 request->payload.data[0],
601 ctx.operation_succeeded);
604 return ctx.operation_succeeded;
607 static void process_write_reply(
608 struct aux_engine *engine,
609 struct write_command_context *ctx)
611 engine->funcs->process_channel_reply(engine, &ctx->reply);
613 switch (ctx->reply.status) {
614 case AUX_TRANSACTION_REPLY_AUX_ACK:
615 ctx->operation_succeeded = true;
617 if (ctx->returned_byte) {
618 ctx->request.action = ctx->mot ?
619 I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
620 I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
622 ctx->current_write_length = 0;
626 if (ctx->ack_m_retry > AUX_DEFER_RETRY_COUNTER) {
628 I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
629 ctx->operation_succeeded = false;
633 ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
634 ctx->defer_retry_aux = 0;
635 ctx->ack_m_retry = 0;
636 ctx->transaction_complete = true;
639 case AUX_TRANSACTION_REPLY_AUX_NACK:
640 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
641 ctx->operation_succeeded = false;
643 case AUX_TRANSACTION_REPLY_AUX_DEFER:
644 ++ctx->defer_retry_aux;
646 if (ctx->defer_retry_aux > ctx->max_defer_retry) {
647 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
648 ctx->operation_succeeded = false;
651 case AUX_TRANSACTION_REPLY_I2C_DEFER:
652 ctx->defer_retry_aux = 0;
653 ctx->current_write_length = 0;
655 ctx->request.action = ctx->mot ?
656 I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
657 I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
659 ++ctx->defer_retry_i2c;
661 if (ctx->defer_retry_i2c > ctx->max_defer_retry) {
662 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
663 ctx->operation_succeeded = false;
666 case AUX_TRANSACTION_REPLY_HPD_DISCON:
667 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
668 ctx->operation_succeeded = false;
671 ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
672 ctx->operation_succeeded = false;
675 static void process_write_request(
676 struct aux_engine *engine,
677 struct write_command_context *ctx)
679 enum aux_channel_operation_result operation_result;
681 engine->funcs->submit_channel_request(engine, &ctx->request);
683 operation_result = engine->funcs->get_channel_status(
684 engine, &ctx->returned_byte);
686 switch (operation_result) {
687 case AUX_CHANNEL_OPERATION_SUCCEEDED:
688 ctx->timed_out_retry_aux = 0;
689 ctx->invalid_reply_retry_aux = 0;
691 ctx->reply.length = ctx->returned_byte;
692 ctx->reply.data = ctx->reply_data;
694 process_write_reply(engine, ctx);
696 case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
697 ++ctx->invalid_reply_retry_aux;
699 if (ctx->invalid_reply_retry_aux >
700 AUX_INVALID_REPLY_RETRY_COUNTER) {
702 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
703 ctx->operation_succeeded = false;
707 case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
708 ++ctx->timed_out_retry_aux;
710 if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
711 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
712 ctx->operation_succeeded = false;
714 /* DP 1.2a, table 2-58:
715 * "S3: AUX Request CMD PENDING:
716 * retry 3 times, with 400usec wait on each"
717 * The HW timeout is set to 550usec,
718 * so we should not wait here
722 case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
723 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
724 ctx->operation_succeeded = false;
727 ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
728 ctx->operation_succeeded = false;
731 static bool write_command(
732 struct aux_engine *engine,
733 struct i2caux_transaction_request *request,
734 bool middle_of_transaction)
736 struct write_command_context ctx;
738 ctx.mot = middle_of_transaction;
739 ctx.buffer = request->payload.data;
740 ctx.current_write_length = request->payload.length;
741 ctx.timed_out_retry_aux = 0;
742 ctx.invalid_reply_retry_aux = 0;
743 ctx.defer_retry_aux = 0;
744 ctx.defer_retry_i2c = 0;
746 ctx.transaction_complete = false;
747 ctx.operation_succeeded = true;
749 if (request->payload.address_space ==
750 I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
751 ctx.request.type = AUX_TRANSACTION_TYPE_DP;
752 ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_WRITE;
753 ctx.request.address = request->payload.address;
754 } else if (request->payload.address_space ==
755 I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
756 ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
757 ctx.request.action = middle_of_transaction ?
758 I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT :
759 I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
760 ctx.request.address = request->payload.address >> 1;
762 /* in DAL2, there was no return in such case */
767 ctx.request.delay = 0;
769 ctx.max_defer_retry =
770 (engine->max_defer_write_retry > AUX_DEFER_RETRY_COUNTER) ?
771 engine->max_defer_write_retry : AUX_DEFER_RETRY_COUNTER;
774 ctx.request.data = ctx.buffer;
775 ctx.request.length = ctx.current_write_length;
777 process_write_request(engine, &ctx);
779 request->status = ctx.status;
781 if (ctx.operation_succeeded && !ctx.transaction_complete)
782 if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
783 msleep(engine->delay);
784 } while (ctx.operation_succeeded && !ctx.transaction_complete);
786 if (request->payload.address_space ==
787 I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
788 DC_LOG_I2C_AUX("WRITE: addr:0x%x value:0x%x Result:%d",
789 request->payload.address,
790 request->payload.data[0],
791 ctx.operation_succeeded);
794 return ctx.operation_succeeded;
796 static bool end_of_transaction_command(
797 struct aux_engine *engine,
798 struct i2caux_transaction_request *request)
800 struct i2caux_transaction_request dummy_request;
803 /* [tcheng] We only need to send the stop (read with MOT = 0)
804 * for I2C-over-Aux, not native AUX
807 if (request->payload.address_space !=
808 I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C)
811 dummy_request.operation = request->operation;
812 dummy_request.payload.address_space = request->payload.address_space;
813 dummy_request.payload.address = request->payload.address;
816 * Add a dummy byte due to some receiver quirk
817 * where one byte is sent along with MOT = 0.
818 * Ideally this should be 0.
821 dummy_request.payload.length = 0;
822 dummy_request.payload.data = &dummy_data;
824 if (request->operation == I2CAUX_TRANSACTION_READ)
825 return read_command(engine, &dummy_request, false);
827 return write_command(engine, &dummy_request, false);
829 /* according Syed, it does not need now DoDummyMOT */
831 static bool submit_request(
832 struct aux_engine *engine,
833 struct i2caux_transaction_request *request,
834 bool middle_of_transaction)
838 bool mot_used = true;
840 switch (request->operation) {
841 case I2CAUX_TRANSACTION_READ:
842 result = read_command(engine, request, mot_used);
844 case I2CAUX_TRANSACTION_WRITE:
845 result = write_command(engine, request, mot_used);
852 * need to send stop for the last transaction to free up the AUX
853 * if the above command fails, this would be the last transaction
856 if (!middle_of_transaction || !result)
857 end_of_transaction_command(engine, request);
859 /* mask AUX interrupt */
863 enum i2caux_engine_type get_engine_type(
864 const struct aux_engine *engine)
866 return I2CAUX_ENGINE_TYPE_AUX;
870 struct aux_engine *engine,
874 enum gpio_result result;
876 if (engine->funcs->is_engine_available) {
877 /*check whether SW could use the engine*/
878 if (!engine->funcs->is_engine_available(engine))
882 result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
883 GPIO_DDC_CONFIG_TYPE_MODE_AUX);
885 if (result != GPIO_RESULT_OK)
888 if (!engine->funcs->acquire_engine(engine)) {
898 static const struct aux_engine_funcs aux_engine_funcs = {
899 .acquire_engine = acquire_engine,
900 .submit_channel_request = submit_channel_request,
901 .process_channel_reply = process_channel_reply,
902 .read_channel_reply = read_channel_reply,
903 .get_channel_status = get_channel_status,
904 .is_engine_available = is_engine_available,
905 .release_engine = release_engine,
906 .destroy_engine = dce110_engine_destroy,
907 .submit_request = submit_request,
908 .get_engine_type = get_engine_type,
912 void dce110_engine_destroy(struct aux_engine **engine)
915 struct aux_engine_dce110 *engine110 = FROM_AUX_ENGINE(*engine);
921 struct aux_engine *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_engine110,
922 struct dc_context *ctx,
924 uint32_t timeout_period,
925 const struct dce110_aux_registers *regs)
927 aux_engine110->base.ddc = NULL;
928 aux_engine110->base.ctx = ctx;
929 aux_engine110->base.delay = 0;
930 aux_engine110->base.max_defer_write_retry = 0;
931 aux_engine110->base.funcs = &aux_engine_funcs;
932 aux_engine110->base.inst = inst;
933 aux_engine110->timeout_period = timeout_period;
934 aux_engine110->regs = regs;
936 return &aux_engine110->base;