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 };
release_engine(struct aux_engine * engine)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
is_engine_available(struct aux_engine * engine)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 }
acquire_engine(struct aux_engine * engine)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
submit_channel_request(struct aux_engine * engine,struct aux_request_transaction_data * request)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
193 REG_UPDATE(AUX_INTERRUPT_CONTROL, AUX_SW_DONE_ACK, 1);
194
195 REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 0,
196 10, aux110->timeout_period/10);
197
198 /* set the delay and the number of bytes to write */
199
200 /* The length include
201 * the 4 bit header and the 20 bit address
202 * (that is 3 byte).
203 * If the requested length is non zero this means
204 * an addition byte specifying the length is required.
205 */
206
207 length = request->length ? 4 : 3;
208 if (is_write)
209 length += request->length;
210
211 REG_UPDATE_2(AUX_SW_CONTROL,
212 AUX_SW_START_DELAY, request->delay,
213 AUX_SW_WR_BYTES, length);
214
215 /* program action and address and payload data (if 'is_write') */
216 value = REG_UPDATE_4(AUX_SW_DATA,
217 AUX_SW_INDEX, 0,
218 AUX_SW_DATA_RW, 0,
219 AUX_SW_AUTOINCREMENT_DISABLE, 1,
220 AUX_SW_DATA, COMPOSE_AUX_SW_DATA_16_20(request->action, request->address));
221
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));
225
226 value = REG_SET(AUX_SW_DATA, value,
227 AUX_SW_DATA, COMPOSE_AUX_SW_DATA_0_7(request->address));
228
229 if (request->length) {
230 value = REG_SET(AUX_SW_DATA, value,
231 AUX_SW_DATA, request->length - 1);
232 }
233
234 if (is_write) {
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().
239 */
240 uint32_t i = 0;
241
242 while (i < request->length) {
243 value = REG_SET(AUX_SW_DATA, value,
244 AUX_SW_DATA, request->data[i]);
245
246 ++i;
247 }
248 }
249
250 REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1);
251 }
252
read_channel_reply(struct aux_engine * engine,uint32_t size,uint8_t * buffer,uint8_t * reply_result,uint32_t * sw_status)253 static int read_channel_reply(struct aux_engine *engine, uint32_t size,
254 uint8_t *buffer, uint8_t *reply_result,
255 uint32_t *sw_status)
256 {
257 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
258 uint32_t bytes_replied;
259 uint32_t reply_result_32;
260
261 *sw_status = REG_GET(AUX_SW_STATUS, AUX_SW_REPLY_BYTE_COUNT,
262 &bytes_replied);
263
264 /* In case HPD is LOW, exit AUX transaction */
265 if ((*sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
266 return -1;
267
268 /* Need at least the status byte */
269 if (!bytes_replied)
270 return -1;
271
272 REG_UPDATE_1BY1_3(AUX_SW_DATA,
273 AUX_SW_INDEX, 0,
274 AUX_SW_AUTOINCREMENT_DISABLE, 1,
275 AUX_SW_DATA_RW, 1);
276
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;
280
281 if (reply_result_32 == 0) { /* ACK */
282 uint32_t i = 0;
283
284 /* First byte was already used to get the command status */
285 --bytes_replied;
286
287 /* Do not overflow buffer */
288 if (bytes_replied > size)
289 return -1;
290
291 while (i < bytes_replied) {
292 uint32_t aux_sw_data_val;
293
294 REG_GET(AUX_SW_DATA, AUX_SW_DATA, &aux_sw_data_val);
295 buffer[i] = aux_sw_data_val;
296 ++i;
297 }
298
299 return i;
300 }
301
302 return 0;
303 }
304
process_channel_reply(struct aux_engine * engine,struct aux_reply_transaction_data * reply)305 static void process_channel_reply(
306 struct aux_engine *engine,
307 struct aux_reply_transaction_data *reply)
308 {
309 int bytes_replied;
310 uint8_t reply_result;
311 uint32_t sw_status;
312
313 bytes_replied = read_channel_reply(engine, reply->length, reply->data,
314 &reply_result, &sw_status);
315
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;
319 return;
320 }
321
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
328 */
329 if (!(sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
330 reply->status = AUX_TRANSACTION_REPLY_INVALID;
331 ASSERT_CRITICAL(false);
332 return;
333 }
334 } else {
335
336 switch (reply_result) {
337 case 0: /* ACK */
338 reply->status = AUX_TRANSACTION_REPLY_AUX_ACK;
339 break;
340 case 1: /* NACK */
341 reply->status = AUX_TRANSACTION_REPLY_AUX_NACK;
342 break;
343 case 2: /* DEFER */
344 reply->status = AUX_TRANSACTION_REPLY_AUX_DEFER;
345 break;
346 case 4: /* AUX ACK / I2C NACK */
347 reply->status = AUX_TRANSACTION_REPLY_I2C_NACK;
348 break;
349 case 8: /* AUX ACK / I2C DEFER */
350 reply->status = AUX_TRANSACTION_REPLY_I2C_DEFER;
351 break;
352 default:
353 reply->status = AUX_TRANSACTION_REPLY_INVALID;
354 }
355 }
356 }
357
get_channel_status(struct aux_engine * engine,uint8_t * returned_bytes)358 static enum aux_channel_operation_result get_channel_status(
359 struct aux_engine *engine,
360 uint8_t *returned_bytes)
361 {
362 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
363
364 uint32_t value;
365
366 if (returned_bytes == NULL) {
367 /*caller pass NULL pointer*/
368 ASSERT_CRITICAL(false);
369 return AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN;
370 }
371 *returned_bytes = 0;
372
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);
376
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;
380
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.
385 *
386 * AUX_SW_RX_MIN_COUNT_VIOL is an internal,
387 * HW debugging bit and should be ignored.
388 */
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;
393
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) ||
396 (value &
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;
400
401 *returned_bytes = get_reg_field_value(value,
402 AUX_SW_STATUS,
403 AUX_SW_REPLY_BYTE_COUNT);
404
405 if (*returned_bytes == 0)
406 return
407 AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
408 else {
409 *returned_bytes -= 1;
410 return AUX_CHANNEL_OPERATION_SUCCEEDED;
411 }
412 } else {
413 /*time_elapsed >= aux_engine->timeout_period
414 * AUX_SW_STATUS__AUX_SW_HPD_DISCON = at this point
415 */
416 ASSERT_CRITICAL(false);
417 return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
418 }
419 }
process_read_reply(struct aux_engine * engine,struct read_command_context * ctx)420 static void process_read_reply(
421 struct aux_engine *engine,
422 struct read_command_context *ctx)
423 {
424 engine->funcs->process_channel_reply(engine, &ctx->reply);
425
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) {
430 ctx->status =
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;
435
436 ctx->offset += ctx->returned_byte;
437
438 ++ctx->invalid_reply_retry_aux_on_ack;
439
440 if (ctx->invalid_reply_retry_aux_on_ack >
441 AUX_INVALID_REPLY_RETRY_COUNTER) {
442 ctx->status =
443 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
444 ctx->operation_succeeded = false;
445 }
446 } else {
447 ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
448 ctx->transaction_complete = true;
449 ctx->operation_succeeded = true;
450 }
451 break;
452 case AUX_TRANSACTION_REPLY_AUX_NACK:
453 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
454 ctx->operation_succeeded = false;
455 break;
456 case AUX_TRANSACTION_REPLY_AUX_DEFER:
457 ++ctx->defer_retry_aux;
458
459 if (ctx->defer_retry_aux > AUX_DEFER_RETRY_COUNTER) {
460 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
461 ctx->operation_succeeded = false;
462 }
463 break;
464 case AUX_TRANSACTION_REPLY_I2C_DEFER:
465 ctx->defer_retry_aux = 0;
466
467 ++ctx->defer_retry_i2c;
468
469 if (ctx->defer_retry_i2c > AUX_DEFER_RETRY_COUNTER) {
470 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
471 ctx->operation_succeeded = false;
472 }
473 break;
474 case AUX_TRANSACTION_REPLY_HPD_DISCON:
475 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
476 ctx->operation_succeeded = false;
477 break;
478 default:
479 ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
480 ctx->operation_succeeded = false;
481 }
482 }
process_read_request(struct aux_engine * engine,struct read_command_context * ctx)483 static void process_read_request(
484 struct aux_engine *engine,
485 struct read_command_context *ctx)
486 {
487 enum aux_channel_operation_result operation_result;
488
489 engine->funcs->submit_channel_request(engine, &ctx->request);
490
491 operation_result = engine->funcs->get_channel_status(
492 engine, &ctx->returned_byte);
493
494 switch (operation_result) {
495 case AUX_CHANNEL_OPERATION_SUCCEEDED:
496 if (ctx->returned_byte > ctx->current_read_length) {
497 ctx->status =
498 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
499 ctx->operation_succeeded = false;
500 } else {
501 ctx->timed_out_retry_aux = 0;
502 ctx->invalid_reply_retry_aux = 0;
503
504 ctx->reply.length = ctx->returned_byte;
505 ctx->reply.data = ctx->buffer;
506
507 process_read_reply(engine, ctx);
508 }
509 break;
510 case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
511 ++ctx->invalid_reply_retry_aux;
512
513 if (ctx->invalid_reply_retry_aux >
514 AUX_INVALID_REPLY_RETRY_COUNTER) {
515 ctx->status =
516 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
517 ctx->operation_succeeded = false;
518 } else
519 udelay(400);
520 break;
521 case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
522 ++ctx->timed_out_retry_aux;
523
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;
527 } else {
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
533 */
534 }
535 break;
536 case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
537 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
538 ctx->operation_succeeded = false;
539 break;
540 default:
541 ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
542 ctx->operation_succeeded = false;
543 }
544 }
read_command(struct aux_engine * engine,struct i2caux_transaction_request * request,bool middle_of_transaction)545 static bool read_command(
546 struct aux_engine *engine,
547 struct i2caux_transaction_request *request,
548 bool middle_of_transaction)
549 {
550 struct read_command_context ctx;
551
552 ctx.buffer = request->payload.data;
553 ctx.current_read_length = request->payload.length;
554 ctx.offset = 0;
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;
562
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;
575 } else {
576 /* in DAL2, there was no return in such case */
577 BREAK_TO_DEBUGGER();
578 return false;
579 }
580
581 ctx.request.delay = 0;
582
583 do {
584 memset(ctx.buffer + ctx.offset, 0, ctx.current_read_length);
585
586 ctx.request.data = ctx.buffer + ctx.offset;
587 ctx.request.length = ctx.current_read_length;
588
589 process_read_request(engine, &ctx);
590
591 request->status = ctx.status;
592
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);
597
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);
604 }
605
606 return ctx.operation_succeeded;
607 }
608
process_write_reply(struct aux_engine * engine,struct write_command_context * ctx)609 static void process_write_reply(
610 struct aux_engine *engine,
611 struct write_command_context *ctx)
612 {
613 engine->funcs->process_channel_reply(engine, &ctx->reply);
614
615 switch (ctx->reply.status) {
616 case AUX_TRANSACTION_REPLY_AUX_ACK:
617 ctx->operation_succeeded = true;
618
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;
623
624 ctx->current_write_length = 0;
625
626 ++ctx->ack_m_retry;
627
628 if (ctx->ack_m_retry > AUX_DEFER_RETRY_COUNTER) {
629 ctx->status =
630 I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
631 ctx->operation_succeeded = false;
632 } else
633 udelay(300);
634 } else {
635 ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
636 ctx->defer_retry_aux = 0;
637 ctx->ack_m_retry = 0;
638 ctx->transaction_complete = true;
639 }
640 break;
641 case AUX_TRANSACTION_REPLY_AUX_NACK:
642 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
643 ctx->operation_succeeded = false;
644 break;
645 case AUX_TRANSACTION_REPLY_AUX_DEFER:
646 ++ctx->defer_retry_aux;
647
648 if (ctx->defer_retry_aux > ctx->max_defer_retry) {
649 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
650 ctx->operation_succeeded = false;
651 }
652 break;
653 case AUX_TRANSACTION_REPLY_I2C_DEFER:
654 ctx->defer_retry_aux = 0;
655 ctx->current_write_length = 0;
656
657 ctx->request.action = ctx->mot ?
658 I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
659 I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
660
661 ++ctx->defer_retry_i2c;
662
663 if (ctx->defer_retry_i2c > ctx->max_defer_retry) {
664 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
665 ctx->operation_succeeded = false;
666 }
667 break;
668 case AUX_TRANSACTION_REPLY_HPD_DISCON:
669 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
670 ctx->operation_succeeded = false;
671 break;
672 default:
673 ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
674 ctx->operation_succeeded = false;
675 }
676 }
process_write_request(struct aux_engine * engine,struct write_command_context * ctx)677 static void process_write_request(
678 struct aux_engine *engine,
679 struct write_command_context *ctx)
680 {
681 enum aux_channel_operation_result operation_result;
682
683 engine->funcs->submit_channel_request(engine, &ctx->request);
684
685 operation_result = engine->funcs->get_channel_status(
686 engine, &ctx->returned_byte);
687
688 switch (operation_result) {
689 case AUX_CHANNEL_OPERATION_SUCCEEDED:
690 ctx->timed_out_retry_aux = 0;
691 ctx->invalid_reply_retry_aux = 0;
692
693 ctx->reply.length = ctx->returned_byte;
694 ctx->reply.data = ctx->reply_data;
695
696 process_write_reply(engine, ctx);
697 break;
698 case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
699 ++ctx->invalid_reply_retry_aux;
700
701 if (ctx->invalid_reply_retry_aux >
702 AUX_INVALID_REPLY_RETRY_COUNTER) {
703 ctx->status =
704 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
705 ctx->operation_succeeded = false;
706 } else
707 udelay(400);
708 break;
709 case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
710 ++ctx->timed_out_retry_aux;
711
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;
715 } else {
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
721 */
722 }
723 break;
724 case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
725 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
726 ctx->operation_succeeded = false;
727 break;
728 default:
729 ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
730 ctx->operation_succeeded = false;
731 }
732 }
write_command(struct aux_engine * engine,struct i2caux_transaction_request * request,bool middle_of_transaction)733 static bool write_command(
734 struct aux_engine *engine,
735 struct i2caux_transaction_request *request,
736 bool middle_of_transaction)
737 {
738 struct write_command_context ctx;
739
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;
747 ctx.ack_m_retry = 0;
748 ctx.transaction_complete = false;
749 ctx.operation_succeeded = true;
750
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;
763 } else {
764 /* in DAL2, there was no return in such case */
765 BREAK_TO_DEBUGGER();
766 return false;
767 }
768
769 ctx.request.delay = 0;
770
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;
774
775 do {
776 ctx.request.data = ctx.buffer;
777 ctx.request.length = ctx.current_write_length;
778
779 process_write_request(engine, &ctx);
780
781 request->status = ctx.status;
782
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);
787
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);
794 }
795
796 return ctx.operation_succeeded;
797 }
end_of_transaction_command(struct aux_engine * engine,struct i2caux_transaction_request * request)798 static bool end_of_transaction_command(
799 struct aux_engine *engine,
800 struct i2caux_transaction_request *request)
801 {
802 struct i2caux_transaction_request dummy_request;
803 uint8_t dummy_data;
804
805 /* [tcheng] We only need to send the stop (read with MOT = 0)
806 * for I2C-over-Aux, not native AUX
807 */
808
809 if (request->payload.address_space !=
810 I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C)
811 return false;
812
813 dummy_request.operation = request->operation;
814 dummy_request.payload.address_space = request->payload.address_space;
815 dummy_request.payload.address = request->payload.address;
816
817 /*
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.
821 */
822
823 dummy_request.payload.length = 0;
824 dummy_request.payload.data = &dummy_data;
825
826 if (request->operation == I2CAUX_TRANSACTION_READ)
827 return read_command(engine, &dummy_request, false);
828 else
829 return write_command(engine, &dummy_request, false);
830
831 /* according Syed, it does not need now DoDummyMOT */
832 }
submit_request(struct aux_engine * engine,struct i2caux_transaction_request * request,bool middle_of_transaction)833 static bool submit_request(
834 struct aux_engine *engine,
835 struct i2caux_transaction_request *request,
836 bool middle_of_transaction)
837 {
838
839 bool result;
840 bool mot_used = true;
841
842 switch (request->operation) {
843 case I2CAUX_TRANSACTION_READ:
844 result = read_command(engine, request, mot_used);
845 break;
846 case I2CAUX_TRANSACTION_WRITE:
847 result = write_command(engine, request, mot_used);
848 break;
849 default:
850 result = false;
851 }
852
853 /* [tcheng]
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
856 */
857
858 if (!middle_of_transaction || !result)
859 end_of_transaction_command(engine, request);
860
861 /* mask AUX interrupt */
862
863 return result;
864 }
865
866 static
get_engine_type(const struct aux_engine * engine)867 enum i2caux_engine_type get_engine_type(
868 const struct aux_engine *engine)
869 {
870 return I2CAUX_ENGINE_TYPE_AUX;
871 }
872
acquire(struct aux_engine * engine,struct ddc * ddc)873 static bool acquire(
874 struct aux_engine *engine,
875 struct ddc *ddc)
876 {
877
878 enum gpio_result result;
879
880 if (engine->funcs->is_engine_available) {
881 /*check whether SW could use the engine*/
882 if (!engine->funcs->is_engine_available(engine))
883 return false;
884 }
885
886 result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
887 GPIO_DDC_CONFIG_TYPE_MODE_AUX);
888
889 if (result != GPIO_RESULT_OK)
890 return false;
891
892 if (!engine->funcs->acquire_engine(engine)) {
893 dal_ddc_close(ddc);
894 return false;
895 }
896
897 engine->ddc = ddc;
898
899 return true;
900 }
901
902 static const struct aux_engine_funcs aux_engine_funcs = {
903 .acquire_engine = acquire_engine,
904 .submit_channel_request = submit_channel_request,
905 .process_channel_reply = process_channel_reply,
906 .read_channel_reply = read_channel_reply,
907 .get_channel_status = get_channel_status,
908 .is_engine_available = is_engine_available,
909 .release_engine = release_engine,
910 .destroy_engine = dce110_engine_destroy,
911 .submit_request = submit_request,
912 .get_engine_type = get_engine_type,
913 .acquire = acquire,
914 };
915
dce110_engine_destroy(struct aux_engine ** engine)916 void dce110_engine_destroy(struct aux_engine **engine)
917 {
918
919 struct aux_engine_dce110 *engine110 = FROM_AUX_ENGINE(*engine);
920
921 kfree(engine110);
922 *engine = NULL;
923
924 }
dce110_aux_engine_construct(struct aux_engine_dce110 * aux_engine110,struct dc_context * ctx,uint32_t inst,uint32_t timeout_period,const struct dce110_aux_registers * regs)925 struct aux_engine *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_engine110,
926 struct dc_context *ctx,
927 uint32_t inst,
928 uint32_t timeout_period,
929 const struct dce110_aux_registers *regs)
930 {
931 aux_engine110->base.ddc = NULL;
932 aux_engine110->base.ctx = ctx;
933 aux_engine110->base.delay = 0;
934 aux_engine110->base.max_defer_write_retry = 0;
935 aux_engine110->base.funcs = &aux_engine_funcs;
936 aux_engine110->base.inst = inst;
937 aux_engine110->timeout_period = timeout_period;
938 aux_engine110->regs = regs;
939
940 return &aux_engine110->base;
941 }
942
943