.. | .. |
---|
23 | 23 | * |
---|
24 | 24 | */ |
---|
25 | 25 | |
---|
| 26 | +#include <linux/delay.h> |
---|
| 27 | +#include <linux/slab.h> |
---|
| 28 | + |
---|
26 | 29 | #include "dm_services.h" |
---|
| 30 | +#include "core_types.h" |
---|
27 | 31 | #include "dce_aux.h" |
---|
28 | 32 | #include "dce/dce_11_0_sh_mask.h" |
---|
| 33 | +#include "dm_event_log.h" |
---|
29 | 34 | |
---|
30 | 35 | #define CTX \ |
---|
31 | 36 | aux110->base.ctx |
---|
.. | .. |
---|
37 | 42 | |
---|
38 | 43 | #include "reg_helper.h" |
---|
39 | 44 | |
---|
| 45 | +#undef FN |
---|
| 46 | +#define FN(reg_name, field_name) \ |
---|
| 47 | + aux110->shift->field_name, aux110->mask->field_name |
---|
| 48 | + |
---|
40 | 49 | #define FROM_AUX_ENGINE(ptr) \ |
---|
41 | 50 | container_of((ptr), struct aux_engine_dce110, base) |
---|
42 | 51 | |
---|
43 | 52 | #define FROM_ENGINE(ptr) \ |
---|
44 | | - FROM_AUX_ENGINE(container_of((ptr), struct aux_engine, base)) |
---|
| 53 | + FROM_AUX_ENGINE(container_of((ptr), struct dce_aux, base)) |
---|
45 | 54 | |
---|
46 | 55 | #define FROM_AUX_ENGINE_ENGINE(ptr) \ |
---|
47 | | - container_of((ptr), struct aux_engine, base) |
---|
| 56 | + container_of((ptr), struct dce_aux, base) |
---|
48 | 57 | enum { |
---|
49 | 58 | AUX_INVALID_REPLY_RETRY_COUNTER = 1, |
---|
50 | 59 | AUX_TIMED_OUT_RETRY_COUNTER = 2, |
---|
51 | 60 | AUX_DEFER_RETRY_COUNTER = 6 |
---|
52 | 61 | }; |
---|
| 62 | + |
---|
| 63 | +#define TIME_OUT_INCREMENT 1016 |
---|
| 64 | +#define TIME_OUT_MULTIPLIER_8 8 |
---|
| 65 | +#define TIME_OUT_MULTIPLIER_16 16 |
---|
| 66 | +#define TIME_OUT_MULTIPLIER_32 32 |
---|
| 67 | +#define TIME_OUT_MULTIPLIER_64 64 |
---|
| 68 | +#define MAX_TIMEOUT_LENGTH 127 |
---|
| 69 | +#define DEFAULT_AUX_ENGINE_MULT 0 |
---|
| 70 | +#define DEFAULT_AUX_ENGINE_LENGTH 69 |
---|
| 71 | + |
---|
53 | 72 | static void release_engine( |
---|
54 | | - struct aux_engine *engine) |
---|
| 73 | + struct dce_aux *engine) |
---|
55 | 74 | { |
---|
56 | 75 | struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); |
---|
57 | 76 | |
---|
.. | .. |
---|
66 | 85 | #define DMCU_CAN_ACCESS_AUX 2 |
---|
67 | 86 | |
---|
68 | 87 | static bool is_engine_available( |
---|
69 | | - struct aux_engine *engine) |
---|
| 88 | + struct dce_aux *engine) |
---|
70 | 89 | { |
---|
71 | 90 | struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); |
---|
72 | 91 | |
---|
.. | .. |
---|
79 | 98 | return (field != DMCU_CAN_ACCESS_AUX); |
---|
80 | 99 | } |
---|
81 | 100 | static bool acquire_engine( |
---|
82 | | - struct aux_engine *engine) |
---|
| 101 | + struct dce_aux *engine) |
---|
83 | 102 | { |
---|
84 | 103 | struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); |
---|
85 | 104 | |
---|
.. | .. |
---|
155 | 174 | (0xFF & (address)) |
---|
156 | 175 | |
---|
157 | 176 | static void submit_channel_request( |
---|
158 | | - struct aux_engine *engine, |
---|
| 177 | + struct dce_aux *engine, |
---|
159 | 178 | struct aux_request_transaction_data *request) |
---|
160 | 179 | { |
---|
161 | 180 | struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); |
---|
.. | .. |
---|
170 | 189 | (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT))); |
---|
171 | 190 | if (REG(AUXN_IMPCAL)) { |
---|
172 | 191 | /* clear_aux_error */ |
---|
173 | | - REG_UPDATE_SEQ(AUXN_IMPCAL, AUXN_CALOUT_ERROR_AK, |
---|
174 | | - 1, |
---|
175 | | - 0); |
---|
| 192 | + REG_UPDATE_SEQ_2(AUXN_IMPCAL, |
---|
| 193 | + AUXN_CALOUT_ERROR_AK, 1, |
---|
| 194 | + AUXN_CALOUT_ERROR_AK, 0); |
---|
176 | 195 | |
---|
177 | | - REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_CALOUT_ERROR_AK, |
---|
178 | | - 1, |
---|
179 | | - 0); |
---|
| 196 | + REG_UPDATE_SEQ_2(AUXP_IMPCAL, |
---|
| 197 | + AUXP_CALOUT_ERROR_AK, 1, |
---|
| 198 | + AUXP_CALOUT_ERROR_AK, 0); |
---|
180 | 199 | |
---|
181 | 200 | /* force_default_calibrate */ |
---|
182 | | - REG_UPDATE_1BY1_2(AUXN_IMPCAL, |
---|
| 201 | + REG_UPDATE_SEQ_2(AUXN_IMPCAL, |
---|
183 | 202 | AUXN_IMPCAL_ENABLE, 1, |
---|
184 | 203 | AUXN_IMPCAL_OVERRIDE_ENABLE, 0); |
---|
185 | 204 | |
---|
186 | 205 | /* bug? why AUXN update EN and OVERRIDE_EN 1 by 1 while AUX P toggles OVERRIDE? */ |
---|
187 | 206 | |
---|
188 | | - REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_IMPCAL_OVERRIDE_ENABLE, |
---|
189 | | - 1, |
---|
190 | | - 0); |
---|
| 207 | + REG_UPDATE_SEQ_2(AUXP_IMPCAL, |
---|
| 208 | + AUXP_IMPCAL_OVERRIDE_ENABLE, 1, |
---|
| 209 | + AUXP_IMPCAL_OVERRIDE_ENABLE, 0); |
---|
191 | 210 | } |
---|
192 | 211 | |
---|
193 | 212 | REG_UPDATE(AUX_INTERRUPT_CONTROL, AUX_SW_DONE_ACK, 1); |
---|
194 | 213 | |
---|
195 | 214 | REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 0, |
---|
196 | | - 10, aux110->timeout_period/10); |
---|
| 215 | + 10, aux110->polling_timeout_period/10); |
---|
197 | 216 | |
---|
198 | 217 | /* set the delay and the number of bytes to write */ |
---|
199 | 218 | |
---|
.. | .. |
---|
248 | 267 | } |
---|
249 | 268 | |
---|
250 | 269 | REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1); |
---|
| 270 | + EVENT_LOG_AUX_REQ(engine->ddc->pin_data->en, EVENT_LOG_AUX_ORIGIN_NATIVE, |
---|
| 271 | + request->action, request->address, request->length, request->data); |
---|
251 | 272 | } |
---|
252 | 273 | |
---|
253 | | -static int read_channel_reply(struct aux_engine *engine, uint32_t size, |
---|
| 274 | +static int read_channel_reply(struct dce_aux *engine, uint32_t size, |
---|
254 | 275 | uint8_t *buffer, uint8_t *reply_result, |
---|
255 | 276 | uint32_t *sw_status) |
---|
256 | 277 | { |
---|
.. | .. |
---|
269 | 290 | if (!bytes_replied) |
---|
270 | 291 | return -1; |
---|
271 | 292 | |
---|
272 | | - REG_UPDATE_1BY1_3(AUX_SW_DATA, |
---|
| 293 | + REG_UPDATE_SEQ_3(AUX_SW_DATA, |
---|
273 | 294 | AUX_SW_INDEX, 0, |
---|
274 | 295 | AUX_SW_AUTOINCREMENT_DISABLE, 1, |
---|
275 | 296 | AUX_SW_DATA_RW, 1); |
---|
276 | 297 | |
---|
277 | 298 | REG_GET(AUX_SW_DATA, AUX_SW_DATA, &reply_result_32); |
---|
278 | 299 | reply_result_32 = reply_result_32 >> 4; |
---|
279 | | - *reply_result = (uint8_t)reply_result_32; |
---|
| 300 | + if (reply_result != NULL) |
---|
| 301 | + *reply_result = (uint8_t)reply_result_32; |
---|
280 | 302 | |
---|
281 | 303 | if (reply_result_32 == 0) { /* ACK */ |
---|
282 | 304 | uint32_t i = 0; |
---|
.. | .. |
---|
302 | 324 | return 0; |
---|
303 | 325 | } |
---|
304 | 326 | |
---|
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 | | - |
---|
358 | 327 | static enum aux_channel_operation_result get_channel_status( |
---|
359 | | - struct aux_engine *engine, |
---|
| 328 | + struct dce_aux *engine, |
---|
360 | 329 | uint8_t *returned_bytes) |
---|
361 | 330 | { |
---|
362 | 331 | struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); |
---|
.. | .. |
---|
371 | 340 | *returned_bytes = 0; |
---|
372 | 341 | |
---|
373 | 342 | /* 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); |
---|
| 343 | + REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 1, |
---|
| 344 | + 10, aux110->polling_timeout_period/10); |
---|
376 | 345 | |
---|
| 346 | + value = REG_READ(AUX_SW_STATUS); |
---|
377 | 347 | /* in case HPD is LOW, exit AUX transaction */ |
---|
378 | 348 | if ((value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) |
---|
379 | 349 | return AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON; |
---|
.. | .. |
---|
417 | 387 | return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT; |
---|
418 | 388 | } |
---|
419 | 389 | } |
---|
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 | 390 | |
---|
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 | | -} |
---|
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 | | -} |
---|
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 | | - |
---|
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 | | -} |
---|
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 | | -} |
---|
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 | | -} |
---|
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 | | -} |
---|
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 | 391 | enum i2caux_engine_type get_engine_type( |
---|
866 | | - const struct aux_engine *engine) |
---|
| 392 | + const struct dce_aux *engine) |
---|
867 | 393 | { |
---|
868 | 394 | return I2CAUX_ENGINE_TYPE_AUX; |
---|
869 | 395 | } |
---|
870 | 396 | |
---|
871 | 397 | static bool acquire( |
---|
872 | | - struct aux_engine *engine, |
---|
| 398 | + struct dce_aux *engine, |
---|
873 | 399 | struct ddc *ddc) |
---|
874 | 400 | { |
---|
875 | | - |
---|
876 | 401 | enum gpio_result result; |
---|
877 | 402 | |
---|
878 | | - if (engine->funcs->is_engine_available) { |
---|
879 | | - /*check whether SW could use the engine*/ |
---|
880 | | - if (!engine->funcs->is_engine_available(engine)) |
---|
881 | | - return false; |
---|
882 | | - } |
---|
| 403 | + if ((engine == NULL) || !is_engine_available(engine)) |
---|
| 404 | + return false; |
---|
883 | 405 | |
---|
884 | 406 | result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE, |
---|
885 | 407 | GPIO_DDC_CONFIG_TYPE_MODE_AUX); |
---|
.. | .. |
---|
887 | 409 | if (result != GPIO_RESULT_OK) |
---|
888 | 410 | return false; |
---|
889 | 411 | |
---|
890 | | - if (!engine->funcs->acquire_engine(engine)) { |
---|
| 412 | + if (!acquire_engine(engine)) { |
---|
891 | 413 | dal_ddc_close(ddc); |
---|
892 | 414 | return false; |
---|
893 | 415 | } |
---|
.. | .. |
---|
897 | 419 | return true; |
---|
898 | 420 | } |
---|
899 | 421 | |
---|
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, |
---|
911 | | - .acquire = acquire, |
---|
912 | | -}; |
---|
913 | | - |
---|
914 | | -void dce110_engine_destroy(struct aux_engine **engine) |
---|
| 422 | +void dce110_engine_destroy(struct dce_aux **engine) |
---|
915 | 423 | { |
---|
916 | 424 | |
---|
917 | 425 | struct aux_engine_dce110 *engine110 = FROM_AUX_ENGINE(*engine); |
---|
.. | .. |
---|
920 | 428 | *engine = NULL; |
---|
921 | 429 | |
---|
922 | 430 | } |
---|
923 | | -struct aux_engine *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_engine110, |
---|
| 431 | + |
---|
| 432 | +static uint32_t dce_aux_configure_timeout(struct ddc_service *ddc, |
---|
| 433 | + uint32_t timeout_in_us) |
---|
| 434 | +{ |
---|
| 435 | + uint32_t multiplier = 0; |
---|
| 436 | + uint32_t length = 0; |
---|
| 437 | + uint32_t prev_length = 0; |
---|
| 438 | + uint32_t prev_mult = 0; |
---|
| 439 | + uint32_t prev_timeout_val = 0; |
---|
| 440 | + struct ddc *ddc_pin = ddc->ddc_pin; |
---|
| 441 | + struct dce_aux *aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]; |
---|
| 442 | + struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(aux_engine); |
---|
| 443 | + |
---|
| 444 | + /* 1-Update polling timeout period */ |
---|
| 445 | + aux110->polling_timeout_period = timeout_in_us * SW_AUX_TIMEOUT_PERIOD_MULTIPLIER; |
---|
| 446 | + |
---|
| 447 | + /* 2-Update aux timeout period length and multiplier */ |
---|
| 448 | + if (timeout_in_us == 0) { |
---|
| 449 | + multiplier = DEFAULT_AUX_ENGINE_MULT; |
---|
| 450 | + length = DEFAULT_AUX_ENGINE_LENGTH; |
---|
| 451 | + } else if (timeout_in_us <= TIME_OUT_INCREMENT) { |
---|
| 452 | + multiplier = 0; |
---|
| 453 | + length = timeout_in_us/TIME_OUT_MULTIPLIER_8; |
---|
| 454 | + if (timeout_in_us % TIME_OUT_MULTIPLIER_8 != 0) |
---|
| 455 | + length++; |
---|
| 456 | + } else if (timeout_in_us <= 2 * TIME_OUT_INCREMENT) { |
---|
| 457 | + multiplier = 1; |
---|
| 458 | + length = timeout_in_us/TIME_OUT_MULTIPLIER_16; |
---|
| 459 | + if (timeout_in_us % TIME_OUT_MULTIPLIER_16 != 0) |
---|
| 460 | + length++; |
---|
| 461 | + } else if (timeout_in_us <= 4 * TIME_OUT_INCREMENT) { |
---|
| 462 | + multiplier = 2; |
---|
| 463 | + length = timeout_in_us/TIME_OUT_MULTIPLIER_32; |
---|
| 464 | + if (timeout_in_us % TIME_OUT_MULTIPLIER_32 != 0) |
---|
| 465 | + length++; |
---|
| 466 | + } else if (timeout_in_us > 4 * TIME_OUT_INCREMENT) { |
---|
| 467 | + multiplier = 3; |
---|
| 468 | + length = timeout_in_us/TIME_OUT_MULTIPLIER_64; |
---|
| 469 | + if (timeout_in_us % TIME_OUT_MULTIPLIER_64 != 0) |
---|
| 470 | + length++; |
---|
| 471 | + } |
---|
| 472 | + |
---|
| 473 | + length = (length < MAX_TIMEOUT_LENGTH) ? length : MAX_TIMEOUT_LENGTH; |
---|
| 474 | + |
---|
| 475 | + REG_GET_2(AUX_DPHY_RX_CONTROL1, AUX_RX_TIMEOUT_LEN, &prev_length, AUX_RX_TIMEOUT_LEN_MUL, &prev_mult); |
---|
| 476 | + |
---|
| 477 | + switch (prev_mult) { |
---|
| 478 | + case 0: |
---|
| 479 | + prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_8; |
---|
| 480 | + break; |
---|
| 481 | + case 1: |
---|
| 482 | + prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_16; |
---|
| 483 | + break; |
---|
| 484 | + case 2: |
---|
| 485 | + prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_32; |
---|
| 486 | + break; |
---|
| 487 | + case 3: |
---|
| 488 | + prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_64; |
---|
| 489 | + break; |
---|
| 490 | + default: |
---|
| 491 | + prev_timeout_val = DEFAULT_AUX_ENGINE_LENGTH * TIME_OUT_MULTIPLIER_8; |
---|
| 492 | + break; |
---|
| 493 | + } |
---|
| 494 | + |
---|
| 495 | + REG_UPDATE_SEQ_2(AUX_DPHY_RX_CONTROL1, AUX_RX_TIMEOUT_LEN, length, AUX_RX_TIMEOUT_LEN_MUL, multiplier); |
---|
| 496 | + |
---|
| 497 | + return prev_timeout_val; |
---|
| 498 | +} |
---|
| 499 | + |
---|
| 500 | +static struct dce_aux_funcs aux_functions = { |
---|
| 501 | + .configure_timeout = NULL, |
---|
| 502 | + .destroy = NULL, |
---|
| 503 | +}; |
---|
| 504 | + |
---|
| 505 | +struct dce_aux *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_engine110, |
---|
924 | 506 | struct dc_context *ctx, |
---|
925 | 507 | uint32_t inst, |
---|
926 | 508 | uint32_t timeout_period, |
---|
927 | | - const struct dce110_aux_registers *regs) |
---|
| 509 | + const struct dce110_aux_registers *regs, |
---|
| 510 | + const struct dce110_aux_registers_mask *mask, |
---|
| 511 | + const struct dce110_aux_registers_shift *shift, |
---|
| 512 | + bool is_ext_aux_timeout_configurable) |
---|
928 | 513 | { |
---|
929 | 514 | aux_engine110->base.ddc = NULL; |
---|
930 | 515 | aux_engine110->base.ctx = ctx; |
---|
931 | 516 | aux_engine110->base.delay = 0; |
---|
932 | 517 | aux_engine110->base.max_defer_write_retry = 0; |
---|
933 | | - aux_engine110->base.funcs = &aux_engine_funcs; |
---|
934 | 518 | aux_engine110->base.inst = inst; |
---|
935 | | - aux_engine110->timeout_period = timeout_period; |
---|
| 519 | + aux_engine110->polling_timeout_period = timeout_period; |
---|
936 | 520 | aux_engine110->regs = regs; |
---|
| 521 | + |
---|
| 522 | + aux_engine110->mask = mask; |
---|
| 523 | + aux_engine110->shift = shift; |
---|
| 524 | + aux_engine110->base.funcs = &aux_functions; |
---|
| 525 | + if (is_ext_aux_timeout_configurable) |
---|
| 526 | + aux_engine110->base.funcs->configure_timeout = &dce_aux_configure_timeout; |
---|
937 | 527 | |
---|
938 | 528 | return &aux_engine110->base; |
---|
939 | 529 | } |
---|
940 | 530 | |
---|
| 531 | +static enum i2caux_transaction_action i2caux_action_from_payload(struct aux_payload *payload) |
---|
| 532 | +{ |
---|
| 533 | + if (payload->i2c_over_aux) { |
---|
| 534 | + if (payload->write) { |
---|
| 535 | + if (payload->mot) |
---|
| 536 | + return I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT; |
---|
| 537 | + return I2CAUX_TRANSACTION_ACTION_I2C_WRITE; |
---|
| 538 | + } |
---|
| 539 | + if (payload->mot) |
---|
| 540 | + return I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT; |
---|
| 541 | + return I2CAUX_TRANSACTION_ACTION_I2C_READ; |
---|
| 542 | + } |
---|
| 543 | + if (payload->write) |
---|
| 544 | + return I2CAUX_TRANSACTION_ACTION_DP_WRITE; |
---|
| 545 | + return I2CAUX_TRANSACTION_ACTION_DP_READ; |
---|
| 546 | +} |
---|
| 547 | + |
---|
| 548 | +int dce_aux_transfer_raw(struct ddc_service *ddc, |
---|
| 549 | + struct aux_payload *payload, |
---|
| 550 | + enum aux_channel_operation_result *operation_result) |
---|
| 551 | +{ |
---|
| 552 | + struct ddc *ddc_pin = ddc->ddc_pin; |
---|
| 553 | + struct dce_aux *aux_engine; |
---|
| 554 | + struct aux_request_transaction_data aux_req; |
---|
| 555 | + struct aux_reply_transaction_data aux_rep; |
---|
| 556 | + uint8_t returned_bytes = 0; |
---|
| 557 | + int res = -1; |
---|
| 558 | + uint32_t status; |
---|
| 559 | + |
---|
| 560 | + memset(&aux_req, 0, sizeof(aux_req)); |
---|
| 561 | + memset(&aux_rep, 0, sizeof(aux_rep)); |
---|
| 562 | + |
---|
| 563 | + aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]; |
---|
| 564 | + if (!acquire(aux_engine, ddc_pin)) { |
---|
| 565 | + *operation_result = AUX_CHANNEL_OPERATION_FAILED_ENGINE_ACQUIRE; |
---|
| 566 | + return -1; |
---|
| 567 | + } |
---|
| 568 | + |
---|
| 569 | + if (payload->i2c_over_aux) |
---|
| 570 | + aux_req.type = AUX_TRANSACTION_TYPE_I2C; |
---|
| 571 | + else |
---|
| 572 | + aux_req.type = AUX_TRANSACTION_TYPE_DP; |
---|
| 573 | + |
---|
| 574 | + aux_req.action = i2caux_action_from_payload(payload); |
---|
| 575 | + |
---|
| 576 | + aux_req.address = payload->address; |
---|
| 577 | + aux_req.delay = 0; |
---|
| 578 | + aux_req.length = payload->length; |
---|
| 579 | + aux_req.data = payload->data; |
---|
| 580 | + |
---|
| 581 | + submit_channel_request(aux_engine, &aux_req); |
---|
| 582 | + *operation_result = get_channel_status(aux_engine, &returned_bytes); |
---|
| 583 | + |
---|
| 584 | + if (*operation_result == AUX_CHANNEL_OPERATION_SUCCEEDED) { |
---|
| 585 | + int bytes_replied = 0; |
---|
| 586 | + bytes_replied = read_channel_reply(aux_engine, payload->length, |
---|
| 587 | + payload->data, payload->reply, |
---|
| 588 | + &status); |
---|
| 589 | + EVENT_LOG_AUX_REP(aux_engine->ddc->pin_data->en, |
---|
| 590 | + EVENT_LOG_AUX_ORIGIN_NATIVE, *payload->reply, |
---|
| 591 | + bytes_replied, payload->data); |
---|
| 592 | + res = returned_bytes; |
---|
| 593 | + } else { |
---|
| 594 | + res = -1; |
---|
| 595 | + } |
---|
| 596 | + |
---|
| 597 | + release_engine(aux_engine); |
---|
| 598 | + return res; |
---|
| 599 | +} |
---|
| 600 | + |
---|
| 601 | +#define AUX_MAX_RETRIES 7 |
---|
| 602 | +#define AUX_MAX_DEFER_RETRIES 7 |
---|
| 603 | +#define AUX_MAX_I2C_DEFER_RETRIES 7 |
---|
| 604 | +#define AUX_MAX_INVALID_REPLY_RETRIES 2 |
---|
| 605 | +#define AUX_MAX_TIMEOUT_RETRIES 3 |
---|
| 606 | + |
---|
| 607 | +bool dce_aux_transfer_with_retries(struct ddc_service *ddc, |
---|
| 608 | + struct aux_payload *payload) |
---|
| 609 | +{ |
---|
| 610 | + int i, ret = 0; |
---|
| 611 | + uint8_t reply; |
---|
| 612 | + bool payload_reply = true; |
---|
| 613 | + enum aux_channel_operation_result operation_result; |
---|
| 614 | + bool retry_on_defer = false; |
---|
| 615 | + |
---|
| 616 | + int aux_ack_retries = 0, |
---|
| 617 | + aux_defer_retries = 0, |
---|
| 618 | + aux_i2c_defer_retries = 0, |
---|
| 619 | + aux_timeout_retries = 0, |
---|
| 620 | + aux_invalid_reply_retries = 0; |
---|
| 621 | + |
---|
| 622 | + if (!payload->reply) { |
---|
| 623 | + payload_reply = false; |
---|
| 624 | + payload->reply = &reply; |
---|
| 625 | + } |
---|
| 626 | + |
---|
| 627 | + for (i = 0; i < AUX_MAX_RETRIES; i++) { |
---|
| 628 | + ret = dce_aux_transfer_raw(ddc, payload, &operation_result); |
---|
| 629 | + switch (operation_result) { |
---|
| 630 | + case AUX_CHANNEL_OPERATION_SUCCEEDED: |
---|
| 631 | + aux_timeout_retries = 0; |
---|
| 632 | + aux_invalid_reply_retries = 0; |
---|
| 633 | + |
---|
| 634 | + switch (*payload->reply) { |
---|
| 635 | + case AUX_TRANSACTION_REPLY_AUX_ACK: |
---|
| 636 | + if (!payload->write && payload->length != ret) { |
---|
| 637 | + if (++aux_ack_retries >= AUX_MAX_RETRIES) |
---|
| 638 | + goto fail; |
---|
| 639 | + else |
---|
| 640 | + udelay(300); |
---|
| 641 | + } else |
---|
| 642 | + return true; |
---|
| 643 | + break; |
---|
| 644 | + |
---|
| 645 | + case AUX_TRANSACTION_REPLY_AUX_DEFER: |
---|
| 646 | + case AUX_TRANSACTION_REPLY_I2C_OVER_AUX_DEFER: |
---|
| 647 | + retry_on_defer = true; |
---|
| 648 | + fallthrough; |
---|
| 649 | + case AUX_TRANSACTION_REPLY_I2C_OVER_AUX_NACK: |
---|
| 650 | + if (++aux_defer_retries >= AUX_MAX_DEFER_RETRIES) { |
---|
| 651 | + goto fail; |
---|
| 652 | + } else { |
---|
| 653 | + if ((*payload->reply == AUX_TRANSACTION_REPLY_AUX_DEFER) || |
---|
| 654 | + (*payload->reply == AUX_TRANSACTION_REPLY_I2C_OVER_AUX_DEFER)) { |
---|
| 655 | + if (payload->defer_delay > 0) |
---|
| 656 | + msleep(payload->defer_delay); |
---|
| 657 | + } |
---|
| 658 | + } |
---|
| 659 | + break; |
---|
| 660 | + |
---|
| 661 | + case AUX_TRANSACTION_REPLY_I2C_DEFER: |
---|
| 662 | + aux_defer_retries = 0; |
---|
| 663 | + if (++aux_i2c_defer_retries >= AUX_MAX_I2C_DEFER_RETRIES) |
---|
| 664 | + goto fail; |
---|
| 665 | + break; |
---|
| 666 | + |
---|
| 667 | + case AUX_TRANSACTION_REPLY_AUX_NACK: |
---|
| 668 | + case AUX_TRANSACTION_REPLY_HPD_DISCON: |
---|
| 669 | + default: |
---|
| 670 | + goto fail; |
---|
| 671 | + } |
---|
| 672 | + break; |
---|
| 673 | + |
---|
| 674 | + case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY: |
---|
| 675 | + if (++aux_invalid_reply_retries >= AUX_MAX_INVALID_REPLY_RETRIES) |
---|
| 676 | + goto fail; |
---|
| 677 | + else |
---|
| 678 | + udelay(400); |
---|
| 679 | + break; |
---|
| 680 | + |
---|
| 681 | + case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT: |
---|
| 682 | + // Check whether a DEFER had occurred before the timeout. |
---|
| 683 | + // If so, treat timeout as a DEFER. |
---|
| 684 | + if (retry_on_defer) { |
---|
| 685 | + if (++aux_defer_retries >= AUX_MAX_DEFER_RETRIES) |
---|
| 686 | + goto fail; |
---|
| 687 | + else if (payload->defer_delay > 0) |
---|
| 688 | + msleep(payload->defer_delay); |
---|
| 689 | + } else { |
---|
| 690 | + if (++aux_timeout_retries >= AUX_MAX_TIMEOUT_RETRIES) |
---|
| 691 | + goto fail; |
---|
| 692 | + else { |
---|
| 693 | + /* |
---|
| 694 | + * DP 1.4, 2.8.2: AUX Transaction Response/Reply Timeouts |
---|
| 695 | + * According to the DP spec there should be 3 retries total |
---|
| 696 | + * with a 400us wait inbetween each. Hardware already waits |
---|
| 697 | + * for 550us therefore no wait is required here. |
---|
| 698 | + */ |
---|
| 699 | + } |
---|
| 700 | + } |
---|
| 701 | + break; |
---|
| 702 | + |
---|
| 703 | + case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON: |
---|
| 704 | + case AUX_CHANNEL_OPERATION_FAILED_ENGINE_ACQUIRE: |
---|
| 705 | + case AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN: |
---|
| 706 | + default: |
---|
| 707 | + goto fail; |
---|
| 708 | + } |
---|
| 709 | + } |
---|
| 710 | + |
---|
| 711 | +fail: |
---|
| 712 | + if (!payload_reply) |
---|
| 713 | + payload->reply = NULL; |
---|
| 714 | + return false; |
---|
| 715 | +} |
---|