diff options
-rw-r--r-- | drivers/gpu/drm/drm_dp_helper.c | 76 | ||||
-rw-r--r-- | include/drm/drm_dp_helper.h | 5 |
2 files changed, 63 insertions, 18 deletions
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index f1283878ff6d..d5368ea56a0f 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c | |||
@@ -427,11 +427,13 @@ static u32 drm_dp_i2c_functionality(struct i2c_adapter *adapter) | |||
427 | * retrying the transaction as appropriate. It is assumed that the | 427 | * retrying the transaction as appropriate. It is assumed that the |
428 | * aux->transfer function does not modify anything in the msg other than the | 428 | * aux->transfer function does not modify anything in the msg other than the |
429 | * reply field. | 429 | * reply field. |
430 | * | ||
431 | * Returns bytes transferred on success, or a negative error code on failure. | ||
430 | */ | 432 | */ |
431 | static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) | 433 | static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) |
432 | { | 434 | { |
433 | unsigned int retry; | 435 | unsigned int retry; |
434 | int err; | 436 | int ret; |
435 | 437 | ||
436 | /* | 438 | /* |
437 | * DP1.2 sections 2.7.7.1.5.6.1 and 2.7.7.1.6.6.1: A DP Source device | 439 | * DP1.2 sections 2.7.7.1.5.6.1 and 2.7.7.1.6.6.1: A DP Source device |
@@ -440,14 +442,14 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) | |||
440 | */ | 442 | */ |
441 | for (retry = 0; retry < 7; retry++) { | 443 | for (retry = 0; retry < 7; retry++) { |
442 | mutex_lock(&aux->hw_mutex); | 444 | mutex_lock(&aux->hw_mutex); |
443 | err = aux->transfer(aux, msg); | 445 | ret = aux->transfer(aux, msg); |
444 | mutex_unlock(&aux->hw_mutex); | 446 | mutex_unlock(&aux->hw_mutex); |
445 | if (err < 0) { | 447 | if (ret < 0) { |
446 | if (err == -EBUSY) | 448 | if (ret == -EBUSY) |
447 | continue; | 449 | continue; |
448 | 450 | ||
449 | DRM_DEBUG_KMS("transaction failed: %d\n", err); | 451 | DRM_DEBUG_KMS("transaction failed: %d\n", ret); |
450 | return err; | 452 | return ret; |
451 | } | 453 | } |
452 | 454 | ||
453 | 455 | ||
@@ -488,9 +490,7 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) | |||
488 | * Both native ACK and I2C ACK replies received. We | 490 | * Both native ACK and I2C ACK replies received. We |
489 | * can assume the transfer was successful. | 491 | * can assume the transfer was successful. |
490 | */ | 492 | */ |
491 | if (err < msg->size) | 493 | return ret; |
492 | return -EPROTO; | ||
493 | return 0; | ||
494 | 494 | ||
495 | case DP_AUX_I2C_REPLY_NACK: | 495 | case DP_AUX_I2C_REPLY_NACK: |
496 | DRM_DEBUG_KMS("I2C nack\n"); | 496 | DRM_DEBUG_KMS("I2C nack\n"); |
@@ -513,14 +513,55 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) | |||
513 | return -EREMOTEIO; | 513 | return -EREMOTEIO; |
514 | } | 514 | } |
515 | 515 | ||
516 | /* | ||
517 | * Keep retrying drm_dp_i2c_do_msg until all data has been transferred. | ||
518 | * | ||
519 | * Returns an error code on failure, or a recommended transfer size on success. | ||
520 | */ | ||
521 | static int drm_dp_i2c_drain_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *orig_msg) | ||
522 | { | ||
523 | int err, ret = orig_msg->size; | ||
524 | struct drm_dp_aux_msg msg = *orig_msg; | ||
525 | |||
526 | while (msg.size > 0) { | ||
527 | err = drm_dp_i2c_do_msg(aux, &msg); | ||
528 | if (err <= 0) | ||
529 | return err == 0 ? -EPROTO : err; | ||
530 | |||
531 | if (err < msg.size && err < ret) { | ||
532 | DRM_DEBUG_KMS("Partial I2C reply: requested %zu bytes got %d bytes\n", | ||
533 | msg.size, err); | ||
534 | ret = err; | ||
535 | } | ||
536 | |||
537 | msg.size -= err; | ||
538 | msg.buffer += err; | ||
539 | } | ||
540 | |||
541 | return ret; | ||
542 | } | ||
543 | |||
544 | /* | ||
545 | * Bizlink designed DP->DVI-D Dual Link adapters require the I2C over AUX | ||
546 | * packets to be as large as possible. If not, the I2C transactions never | ||
547 | * succeed. Hence the default is maximum. | ||
548 | */ | ||
549 | static int dp_aux_i2c_transfer_size __read_mostly = DP_AUX_MAX_PAYLOAD_BYTES; | ||
550 | module_param_unsafe(dp_aux_i2c_transfer_size, int, 0644); | ||
551 | MODULE_PARM_DESC(dp_aux_i2c_transfer_size, | ||
552 | "Number of bytes to transfer in a single I2C over DP AUX CH message, (1-16, default 16)"); | ||
553 | |||
516 | static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, | 554 | static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, |
517 | int num) | 555 | int num) |
518 | { | 556 | { |
519 | struct drm_dp_aux *aux = adapter->algo_data; | 557 | struct drm_dp_aux *aux = adapter->algo_data; |
520 | unsigned int i, j; | 558 | unsigned int i, j; |
559 | unsigned transfer_size; | ||
521 | struct drm_dp_aux_msg msg; | 560 | struct drm_dp_aux_msg msg; |
522 | int err = 0; | 561 | int err = 0; |
523 | 562 | ||
563 | dp_aux_i2c_transfer_size = clamp(dp_aux_i2c_transfer_size, 1, DP_AUX_MAX_PAYLOAD_BYTES); | ||
564 | |||
524 | memset(&msg, 0, sizeof(msg)); | 565 | memset(&msg, 0, sizeof(msg)); |
525 | 566 | ||
526 | for (i = 0; i < num; i++) { | 567 | for (i = 0; i < num; i++) { |
@@ -538,20 +579,19 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, | |||
538 | err = drm_dp_i2c_do_msg(aux, &msg); | 579 | err = drm_dp_i2c_do_msg(aux, &msg); |
539 | if (err < 0) | 580 | if (err < 0) |
540 | break; | 581 | break; |
541 | /* | 582 | /* We want each transaction to be as large as possible, but |
542 | * Many hardware implementations support FIFOs larger than a | 583 | * we'll go to smaller sizes if the hardware gives us a |
543 | * single byte, but it has been empirically determined that | 584 | * short reply. |
544 | * transferring data in larger chunks can actually lead to | ||
545 | * decreased performance. Therefore each message is simply | ||
546 | * transferred byte-by-byte. | ||
547 | */ | 585 | */ |
548 | for (j = 0; j < msgs[i].len; j++) { | 586 | transfer_size = dp_aux_i2c_transfer_size; |
587 | for (j = 0; j < msgs[i].len; j += msg.size) { | ||
549 | msg.buffer = msgs[i].buf + j; | 588 | msg.buffer = msgs[i].buf + j; |
550 | msg.size = 1; | 589 | msg.size = min(transfer_size, msgs[i].len - j); |
551 | 590 | ||
552 | err = drm_dp_i2c_do_msg(aux, &msg); | 591 | err = drm_dp_i2c_drain_msg(aux, &msg); |
553 | if (err < 0) | 592 | if (err < 0) |
554 | break; | 593 | break; |
594 | transfer_size = err; | ||
555 | } | 595 | } |
556 | if (err < 0) | 596 | if (err < 0) |
557 | break; | 597 | break; |
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index c5fdc2d3ca97..523f04c90dea 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h | |||
@@ -42,6 +42,8 @@ | |||
42 | * 1.2 formally includes both eDP and DPI definitions. | 42 | * 1.2 formally includes both eDP and DPI definitions. |
43 | */ | 43 | */ |
44 | 44 | ||
45 | #define DP_AUX_MAX_PAYLOAD_BYTES 16 | ||
46 | |||
45 | #define DP_AUX_I2C_WRITE 0x0 | 47 | #define DP_AUX_I2C_WRITE 0x0 |
46 | #define DP_AUX_I2C_READ 0x1 | 48 | #define DP_AUX_I2C_READ 0x1 |
47 | #define DP_AUX_I2C_STATUS 0x2 | 49 | #define DP_AUX_I2C_STATUS 0x2 |
@@ -680,6 +682,9 @@ struct drm_dp_aux_msg { | |||
680 | * transactions. The drm_dp_aux_register_i2c_bus() function registers an | 682 | * transactions. The drm_dp_aux_register_i2c_bus() function registers an |
681 | * I2C adapter that can be passed to drm_probe_ddc(). Upon removal, drivers | 683 | * I2C adapter that can be passed to drm_probe_ddc(). Upon removal, drivers |
682 | * should call drm_dp_aux_unregister_i2c_bus() to remove the I2C adapter. | 684 | * should call drm_dp_aux_unregister_i2c_bus() to remove the I2C adapter. |
685 | * The I2C adapter uses long transfers by default; if a partial response is | ||
686 | * received, the adapter will drop down to the size given by the partial | ||
687 | * response for this transaction only. | ||
683 | * | 688 | * |
684 | * Note that the aux helper code assumes that the .transfer() function | 689 | * Note that the aux helper code assumes that the .transfer() function |
685 | * only modifies the reply field of the drm_dp_aux_msg structure. The | 690 | * only modifies the reply field of the drm_dp_aux_msg structure. The |