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,
193 REG_UPDATE(AUX_INTERRUPT_CONTROL, AUX_SW_DONE_ACK, 1);
195 REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 0,
196 10, aux110->timeout_period/10);
198 /* set the delay and the number of bytes to write */
200 /* The length include
201 * the 4 bit header and the 20 bit address
203 * If the requested length is non zero this means
204 * an addition byte specifying the length is required.
207 length = request->length ? 4 : 3;
209 length += request->length;
211 REG_UPDATE_2(AUX_SW_CONTROL,
212 AUX_SW_START_DELAY, request->delay,
213 AUX_SW_WR_BYTES, length);
215 /* program action and address and payload data (if 'is_write') */
216 value = REG_UPDATE_4(AUX_SW_DATA,
219 AUX_SW_AUTOINCREMENT_DISABLE, 1,
220 AUX_SW_DATA, COMPOSE_AUX_SW_DATA_16_20(request->action, request->address));
222 value = REG_SET_2(AUX_SW_DATA, value,
223 AUX_SW_AUTOINCREMENT_DISABLE, 0,
224 AUX_SW_DATA, COMPOSE_AUX_SW_DATA_8_15(request->address));
226 value = REG_SET(AUX_SW_DATA, value,
227 AUX_SW_DATA, COMPOSE_AUX_SW_DATA_0_7(request->address));
229 if (request->length) {
230 value = REG_SET(AUX_SW_DATA, value,
231 AUX_SW_DATA, request->length - 1);
235 /* Load the HW buffer with the Data to be sent.
236 * This is relevant for write operation.
237 * For read, the data recived data will be
238 * processed in process_channel_reply().
242 while (i < request->length) {
243 value = REG_SET(AUX_SW_DATA, value,
244 AUX_SW_DATA, request->data[i]);
250 REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1);
253 static int read_channel_reply(struct aux_engine *engine, uint32_t size,
254 uint8_t *buffer, uint8_t *reply_result,
257 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
258 uint32_t bytes_replied;
259 uint32_t reply_result_32;
261 *sw_status = REG_GET(AUX_SW_STATUS, AUX_SW_REPLY_BYTE_COUNT,
264 /* In case HPD is LOW, exit AUX transaction */
265 if ((*sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
268 /* Need at least the status byte */
272 REG_UPDATE_1BY1_3(AUX_SW_DATA,
274 AUX_SW_AUTOINCREMENT_DISABLE, 1,
277 REG_GET(AUX_SW_DATA, AUX_SW_DATA, &reply_result_32);
278 reply_result_32 = reply_result_32 >> 4;
279 *reply_result = (uint8_t)reply_result_32;
281 if (reply_result_32 == 0) { /* ACK */
284 /* First byte was already used to get the command status */
287 /* Do not overflow buffer */
288 if (bytes_replied > size)
291 while (i < bytes_replied) {
292 uint32_t aux_sw_data_val;
294 REG_GET(AUX_SW_DATA, AUX_SW_DATA, &aux_sw_data_val);
295 buffer[i] = aux_sw_data_val;
305 static void process_channel_reply(
306 struct aux_engine *engine,
307 struct aux_reply_transaction_data *reply)
310 uint8_t reply_result;
313 bytes_replied = read_channel_reply(engine, reply->length, reply->data,
314 &reply_result, &sw_status);
316 /* in case HPD is LOW, exit AUX transaction */
317 if ((sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
318 reply->status = AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON;
322 if (bytes_replied < 0) {
323 /* Need to handle an error case...
324 * Hopefully, upper layer function won't call this function if
325 * the number of bytes in the reply was 0, because there was
326 * surely an error that was asserted that should have been
327 * handled for hot plug case, this could happens
329 if (!(sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
330 reply->status = AUX_TRANSACTION_REPLY_INVALID;
331 ASSERT_CRITICAL(false);
336 switch (reply_result) {
338 reply->status = AUX_TRANSACTION_REPLY_AUX_ACK;
341 reply->status = AUX_TRANSACTION_REPLY_AUX_NACK;
344 reply->status = AUX_TRANSACTION_REPLY_AUX_DEFER;
346 case 4: /* AUX ACK / I2C NACK */
347 reply->status = AUX_TRANSACTION_REPLY_I2C_NACK;
349 case 8: /* AUX ACK / I2C DEFER */
350 reply->status = AUX_TRANSACTION_REPLY_I2C_DEFER;
353 reply->status = AUX_TRANSACTION_REPLY_INVALID;
358 static enum aux_channel_operation_result get_channel_status(
359 struct aux_engine *engine,
360 uint8_t *returned_bytes)
362 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
366 if (returned_bytes == NULL) {
367 /*caller pass NULL pointer*/
368 ASSERT_CRITICAL(false);
369 return AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN;
373 /* poll to make sure that SW_DONE is asserted */
374 value = REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 1,
375 10, aux110->timeout_period/10);
377 /* in case HPD is LOW, exit AUX transaction */
378 if ((value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
379 return AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON;
381 /* Note that the following bits are set in 'status.bits'
382 * during CTS 4.2.1.2 (FW 3.3.1):
383 * AUX_SW_RX_MIN_COUNT_VIOL, AUX_SW_RX_INVALID_STOP,
384 * AUX_SW_RX_RECV_NO_DET, AUX_SW_RX_RECV_INVALID_H.
386 * AUX_SW_RX_MIN_COUNT_VIOL is an internal,
387 * HW debugging bit and should be ignored.
389 if (value & AUX_SW_STATUS__AUX_SW_DONE_MASK) {
390 if ((value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_STATE_MASK) ||
391 (value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_MASK))
392 return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
394 else if ((value & AUX_SW_STATUS__AUX_SW_RX_INVALID_STOP_MASK) ||
395 (value & AUX_SW_STATUS__AUX_SW_RX_RECV_NO_DET_MASK) ||
397 AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_H_MASK) ||
398 (value & AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_L_MASK))
399 return AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
401 *returned_bytes = get_reg_field_value(value,
403 AUX_SW_REPLY_BYTE_COUNT);
405 if (*returned_bytes == 0)
407 AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
409 *returned_bytes -= 1;
410 return AUX_CHANNEL_OPERATION_SUCCEEDED;
413 /*time_elapsed >= aux_engine->timeout_period
414 * AUX_SW_STATUS__AUX_SW_HPD_DISCON = at this point
416 ASSERT_CRITICAL(false);
417 return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
420 static void process_read_reply(
421 struct aux_engine *engine,
422 struct read_command_context *ctx)
424 engine->funcs->process_channel_reply(engine, &ctx->reply);
426 switch (ctx->reply.status) {
427 case AUX_TRANSACTION_REPLY_AUX_ACK:
428 ctx->defer_retry_aux = 0;
429 if (ctx->returned_byte > ctx->current_read_length) {
431 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
432 ctx->operation_succeeded = false;
433 } else if (ctx->returned_byte < ctx->current_read_length) {
434 ctx->current_read_length -= ctx->returned_byte;
436 ctx->offset += ctx->returned_byte;
438 ++ctx->invalid_reply_retry_aux_on_ack;
440 if (ctx->invalid_reply_retry_aux_on_ack >
441 AUX_INVALID_REPLY_RETRY_COUNTER) {
443 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
444 ctx->operation_succeeded = false;
447 ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
448 ctx->transaction_complete = true;
449 ctx->operation_succeeded = true;
452 case AUX_TRANSACTION_REPLY_AUX_NACK:
453 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
454 ctx->operation_succeeded = false;
456 case AUX_TRANSACTION_REPLY_AUX_DEFER:
457 ++ctx->defer_retry_aux;
459 if (ctx->defer_retry_aux > AUX_DEFER_RETRY_COUNTER) {
460 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
461 ctx->operation_succeeded = false;
464 case AUX_TRANSACTION_REPLY_I2C_DEFER:
465 ctx->defer_retry_aux = 0;
467 ++ctx->defer_retry_i2c;
469 if (ctx->defer_retry_i2c > AUX_DEFER_RETRY_COUNTER) {
470 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
471 ctx->operation_succeeded = false;
474 case AUX_TRANSACTION_REPLY_HPD_DISCON:
475 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
476 ctx->operation_succeeded = false;
479 ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
480 ctx->operation_succeeded = false;
483 static void process_read_request(
484 struct aux_engine *engine,
485 struct read_command_context *ctx)
487 enum aux_channel_operation_result operation_result;
489 engine->funcs->submit_channel_request(engine, &ctx->request);
491 operation_result = engine->funcs->get_channel_status(
492 engine, &ctx->returned_byte);
494 switch (operation_result) {
495 case AUX_CHANNEL_OPERATION_SUCCEEDED:
496 if (ctx->returned_byte > ctx->current_read_length) {
498 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
499 ctx->operation_succeeded = false;
501 ctx->timed_out_retry_aux = 0;
502 ctx->invalid_reply_retry_aux = 0;
504 ctx->reply.length = ctx->returned_byte;
505 ctx->reply.data = ctx->buffer;
507 process_read_reply(engine, ctx);
510 case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
511 ++ctx->invalid_reply_retry_aux;
513 if (ctx->invalid_reply_retry_aux >
514 AUX_INVALID_REPLY_RETRY_COUNTER) {
516 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
517 ctx->operation_succeeded = false;
521 case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
522 ++ctx->timed_out_retry_aux;
524 if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
525 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
526 ctx->operation_succeeded = false;
528 /* DP 1.2a, table 2-58:
529 * "S3: AUX Request CMD PENDING:
530 * retry 3 times, with 400usec wait on each"
531 * The HW timeout is set to 550usec,
532 * so we should not wait here
536 case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
537 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
538 ctx->operation_succeeded = false;
541 ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
542 ctx->operation_succeeded = false;
545 static bool read_command(
546 struct aux_engine *engine,
547 struct i2caux_transaction_request *request,
548 bool middle_of_transaction)
550 struct read_command_context ctx;
552 ctx.buffer = request->payload.data;
553 ctx.current_read_length = request->payload.length;
555 ctx.timed_out_retry_aux = 0;
556 ctx.invalid_reply_retry_aux = 0;
557 ctx.defer_retry_aux = 0;
558 ctx.defer_retry_i2c = 0;
559 ctx.invalid_reply_retry_aux_on_ack = 0;
560 ctx.transaction_complete = false;
561 ctx.operation_succeeded = true;
563 if (request->payload.address_space ==
564 I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
565 ctx.request.type = AUX_TRANSACTION_TYPE_DP;
566 ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_READ;
567 ctx.request.address = request->payload.address;
568 } else if (request->payload.address_space ==
569 I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
570 ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
571 ctx.request.action = middle_of_transaction ?
572 I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT :
573 I2CAUX_TRANSACTION_ACTION_I2C_READ;
574 ctx.request.address = request->payload.address >> 1;
576 /* in DAL2, there was no return in such case */
581 ctx.request.delay = 0;
584 memset(ctx.buffer + ctx.offset, 0, ctx.current_read_length);
586 ctx.request.data = ctx.buffer + ctx.offset;
587 ctx.request.length = ctx.current_read_length;
589 process_read_request(engine, &ctx);
591 request->status = ctx.status;
593 if (ctx.operation_succeeded && !ctx.transaction_complete)
594 if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
595 msleep(engine->delay);
596 } while (ctx.operation_succeeded && !ctx.transaction_complete);
598 if (request->payload.address_space ==
599 I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
600 DC_LOG_I2C_AUX("READ: addr:0x%x value:0x%x Result:%d",
601 request->payload.address,
602 request->payload.data[0],
603 ctx.operation_succeeded);
606 return ctx.operation_succeeded;
609 static void process_write_reply(
610 struct aux_engine *engine,
611 struct write_command_context *ctx)
613 engine->funcs->process_channel_reply(engine, &ctx->reply);
615 switch (ctx->reply.status) {
616 case AUX_TRANSACTION_REPLY_AUX_ACK:
617 ctx->operation_succeeded = true;
619 if (ctx->returned_byte) {
620 ctx->request.action = ctx->mot ?
621 I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
622 I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
624 ctx->current_write_length = 0;
628 if (ctx->ack_m_retry > AUX_DEFER_RETRY_COUNTER) {
630 I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
631 ctx->operation_succeeded = false;
635 ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
636 ctx->defer_retry_aux = 0;
637 ctx->ack_m_retry = 0;
638 ctx->transaction_complete = true;
641 case AUX_TRANSACTION_REPLY_AUX_NACK:
642 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
643 ctx->operation_succeeded = false;
645 case AUX_TRANSACTION_REPLY_AUX_DEFER:
646 ++ctx->defer_retry_aux;
648 if (ctx->defer_retry_aux > ctx->max_defer_retry) {
649 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
650 ctx->operation_succeeded = false;
653 case AUX_TRANSACTION_REPLY_I2C_DEFER:
654 ctx->defer_retry_aux = 0;
655 ctx->current_write_length = 0;
657 ctx->request.action = ctx->mot ?
658 I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
659 I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
661 ++ctx->defer_retry_i2c;
663 if (ctx->defer_retry_i2c > ctx->max_defer_retry) {
664 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
665 ctx->operation_succeeded = false;
668 case AUX_TRANSACTION_REPLY_HPD_DISCON:
669 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
670 ctx->operation_succeeded = false;
673 ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
674 ctx->operation_succeeded = false;
677 static void process_write_request(
678 struct aux_engine *engine,
679 struct write_command_context *ctx)
681 enum aux_channel_operation_result operation_result;
683 engine->funcs->submit_channel_request(engine, &ctx->request);
685 operation_result = engine->funcs->get_channel_status(
686 engine, &ctx->returned_byte);
688 switch (operation_result) {
689 case AUX_CHANNEL_OPERATION_SUCCEEDED:
690 ctx->timed_out_retry_aux = 0;
691 ctx->invalid_reply_retry_aux = 0;
693 ctx->reply.length = ctx->returned_byte;
694 ctx->reply.data = ctx->reply_data;
696 process_write_reply(engine, ctx);
698 case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
699 ++ctx->invalid_reply_retry_aux;
701 if (ctx->invalid_reply_retry_aux >
702 AUX_INVALID_REPLY_RETRY_COUNTER) {
704 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
705 ctx->operation_succeeded = false;
709 case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
710 ++ctx->timed_out_retry_aux;
712 if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
713 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
714 ctx->operation_succeeded = false;
716 /* DP 1.2a, table 2-58:
717 * "S3: AUX Request CMD PENDING:
718 * retry 3 times, with 400usec wait on each"
719 * The HW timeout is set to 550usec,
720 * so we should not wait here
724 case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
725 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
726 ctx->operation_succeeded = false;
729 ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
730 ctx->operation_succeeded = false;
733 static bool write_command(
734 struct aux_engine *engine,
735 struct i2caux_transaction_request *request,
736 bool middle_of_transaction)
738 struct write_command_context ctx;
740 ctx.mot = middle_of_transaction;
741 ctx.buffer = request->payload.data;
742 ctx.current_write_length = request->payload.length;
743 ctx.timed_out_retry_aux = 0;
744 ctx.invalid_reply_retry_aux = 0;
745 ctx.defer_retry_aux = 0;
746 ctx.defer_retry_i2c = 0;
748 ctx.transaction_complete = false;
749 ctx.operation_succeeded = true;
751 if (request->payload.address_space ==
752 I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
753 ctx.request.type = AUX_TRANSACTION_TYPE_DP;
754 ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_WRITE;
755 ctx.request.address = request->payload.address;
756 } else if (request->payload.address_space ==
757 I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
758 ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
759 ctx.request.action = middle_of_transaction ?
760 I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT :
761 I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
762 ctx.request.address = request->payload.address >> 1;
764 /* in DAL2, there was no return in such case */
769 ctx.request.delay = 0;
771 ctx.max_defer_retry =
772 (engine->max_defer_write_retry > AUX_DEFER_RETRY_COUNTER) ?
773 engine->max_defer_write_retry : AUX_DEFER_RETRY_COUNTER;
776 ctx.request.data = ctx.buffer;
777 ctx.request.length = ctx.current_write_length;
779 process_write_request(engine, &ctx);
781 request->status = ctx.status;
783 if (ctx.operation_succeeded && !ctx.transaction_complete)
784 if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
785 msleep(engine->delay);
786 } while (ctx.operation_succeeded && !ctx.transaction_complete);
788 if (request->payload.address_space ==
789 I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
790 DC_LOG_I2C_AUX("WRITE: addr:0x%x value:0x%x Result:%d",
791 request->payload.address,
792 request->payload.data[0],
793 ctx.operation_succeeded);
796 return ctx.operation_succeeded;
798 static bool end_of_transaction_command(
799 struct aux_engine *engine,
800 struct i2caux_transaction_request *request)
802 struct i2caux_transaction_request dummy_request;
805 /* [tcheng] We only need to send the stop (read with MOT = 0)
806 * for I2C-over-Aux, not native AUX
809 if (request->payload.address_space !=
810 I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C)
813 dummy_request.operation = request->operation;
814 dummy_request.payload.address_space = request->payload.address_space;
815 dummy_request.payload.address = request->payload.address;
818 * Add a dummy byte due to some receiver quirk
819 * where one byte is sent along with MOT = 0.
820 * Ideally this should be 0.
823 dummy_request.payload.length = 0;
824 dummy_request.payload.data = &dummy_data;
826 if (request->operation == I2CAUX_TRANSACTION_READ)
827 return read_command(engine, &dummy_request, false);
829 return write_command(engine, &dummy_request, false);
831 /* according Syed, it does not need now DoDummyMOT */
833 static bool submit_request(
834 struct aux_engine *engine,
835 struct i2caux_transaction_request *request,
836 bool middle_of_transaction)
840 bool mot_used = true;
842 switch (request->operation) {
843 case I2CAUX_TRANSACTION_READ:
844 result = read_command(engine, request, mot_used);
846 case I2CAUX_TRANSACTION_WRITE:
847 result = write_command(engine, request, mot_used);
854 * need to send stop for the last transaction to free up the AUX
855 * if the above command fails, this would be the last transaction
858 if (!middle_of_transaction || !result)
859 end_of_transaction_command(engine, request);
861 /* mask AUX interrupt */
865 enum i2caux_engine_type get_engine_type(
866 const struct aux_engine *engine)
868 return I2CAUX_ENGINE_TYPE_AUX;
872 struct aux_engine *engine,
876 enum gpio_result result;
878 if (engine->funcs->is_engine_available) {
879 /*check whether SW could use the engine*/
880 if (!engine->funcs->is_engine_available(engine))
884 result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
885 GPIO_DDC_CONFIG_TYPE_MODE_AUX);
887 if (result != GPIO_RESULT_OK)
890 if (!engine->funcs->acquire_engine(engine)) {
900 static const struct aux_engine_funcs aux_engine_funcs = {
901 .acquire_engine = acquire_engine,
902 .submit_channel_request = submit_channel_request,
903 .process_channel_reply = process_channel_reply,
904 .read_channel_reply = read_channel_reply,
905 .get_channel_status = get_channel_status,
906 .is_engine_available = is_engine_available,
907 .release_engine = release_engine,
908 .destroy_engine = dce110_engine_destroy,
909 .submit_request = submit_request,
910 .get_engine_type = get_engine_type,
914 void dce110_engine_destroy(struct aux_engine **engine)
917 struct aux_engine_dce110 *engine110 = FROM_AUX_ENGINE(*engine);
923 struct aux_engine *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_engine110,
924 struct dc_context *ctx,
926 uint32_t timeout_period,
927 const struct dce110_aux_registers *regs)
929 aux_engine110->base.ddc = NULL;
930 aux_engine110->base.ctx = ctx;
931 aux_engine110->base.delay = 0;
932 aux_engine110->base.max_defer_write_retry = 0;
933 aux_engine110->base.funcs = &aux_engine_funcs;
934 aux_engine110->base.inst = inst;
935 aux_engine110->timeout_period = timeout_period;
936 aux_engine110->regs = regs;
938 return &aux_engine110->base;