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 |
