| .. | .. |
|---|
| 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 | +} |
|---|