aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/drm_dp_helper.c84
1 files changed, 82 insertions, 2 deletions
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c
index 7069e54e5b43..214a4c649d56 100644
--- a/drivers/gpu/drm/drm_dp_helper.c
+++ b/drivers/gpu/drm/drm_dp_helper.c
@@ -424,6 +424,81 @@ static u32 drm_dp_i2c_functionality(struct i2c_adapter *adapter)
424 I2C_FUNC_10BIT_ADDR; 424 I2C_FUNC_10BIT_ADDR;
425} 425}
426 426
427#define AUX_PRECHARGE_LEN 10 /* 10 to 16 */
428#define AUX_SYNC_LEN (16 + 4) /* preamble + AUX_SYNC_END */
429#define AUX_STOP_LEN 4
430#define AUX_CMD_LEN 4
431#define AUX_ADDRESS_LEN 20
432#define AUX_REPLY_PAD_LEN 4
433#define AUX_LENGTH_LEN 8
434
435/*
436 * Calculate the duration of the AUX request/reply in usec. Gives the
437 * "best" case estimate, ie. successful while as short as possible.
438 */
439static int drm_dp_aux_req_duration(const struct drm_dp_aux_msg *msg)
440{
441 int len = AUX_PRECHARGE_LEN + AUX_SYNC_LEN + AUX_STOP_LEN +
442 AUX_CMD_LEN + AUX_ADDRESS_LEN + AUX_LENGTH_LEN;
443
444 if ((msg->request & DP_AUX_I2C_READ) == 0)
445 len += msg->size * 8;
446
447 return len;
448}
449
450static int drm_dp_aux_reply_duration(const struct drm_dp_aux_msg *msg)
451{
452 int len = AUX_PRECHARGE_LEN + AUX_SYNC_LEN + AUX_STOP_LEN +
453 AUX_CMD_LEN + AUX_REPLY_PAD_LEN;
454
455 /*
456 * For read we expect what was asked. For writes there will
457 * be 0 or 1 data bytes. Assume 0 for the "best" case.
458 */
459 if (msg->request & DP_AUX_I2C_READ)
460 len += msg->size * 8;
461
462 return len;
463}
464
465#define I2C_START_LEN 1
466#define I2C_STOP_LEN 1
467#define I2C_ADDR_LEN 9 /* ADDRESS + R/W + ACK/NACK */
468#define I2C_DATA_LEN 9 /* DATA + ACK/NACK */
469
470/*
471 * Calculate the length of the i2c transfer in usec, assuming
472 * the i2c bus speed is as specified. Gives the the "worst"
473 * case estimate, ie. successful while as long as possible.
474 * Doesn't account the the "MOT" bit, and instead assumes each
475 * message includes a START, ADDRESS and STOP. Neither does it
476 * account for additional random variables such as clock stretching.
477 */
478static int drm_dp_i2c_msg_duration(const struct drm_dp_aux_msg *msg,
479 int i2c_speed_khz)
480{
481 /* AUX bitrate is 1MHz, i2c bitrate as specified */
482 return DIV_ROUND_UP((I2C_START_LEN + I2C_ADDR_LEN +
483 msg->size * I2C_DATA_LEN +
484 I2C_STOP_LEN) * 1000, i2c_speed_khz);
485}
486
487/*
488 * Deterine how many retries should be attempted to successfully transfer
489 * the specified message, based on the estimated durations of the
490 * i2c and AUX transfers.
491 */
492static int drm_dp_i2c_retry_count(const struct drm_dp_aux_msg *msg,
493 int i2c_speed_khz)
494{
495 int aux_time_us = drm_dp_aux_req_duration(msg) +
496 drm_dp_aux_reply_duration(msg);
497 int i2c_time_us = drm_dp_i2c_msg_duration(msg, i2c_speed_khz);
498
499 return DIV_ROUND_UP(i2c_time_us, aux_time_us + AUX_RETRY_INTERVAL);
500}
501
427/* 502/*
428 * Transfer a single I2C-over-AUX message and handle various error conditions, 503 * Transfer a single I2C-over-AUX message and handle various error conditions,
429 * retrying the transaction as appropriate. It is assumed that the 504 * retrying the transaction as appropriate. It is assumed that the
@@ -436,13 +511,18 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
436{ 511{
437 unsigned int retry, defer_i2c; 512 unsigned int retry, defer_i2c;
438 int ret; 513 int ret;
439
440 /* 514 /*
441 * DP1.2 sections 2.7.7.1.5.6.1 and 2.7.7.1.6.6.1: A DP Source device 515 * DP1.2 sections 2.7.7.1.5.6.1 and 2.7.7.1.6.6.1: A DP Source device
442 * is required to retry at least seven times upon receiving AUX_DEFER 516 * is required to retry at least seven times upon receiving AUX_DEFER
443 * before giving up the AUX transaction. 517 * before giving up the AUX transaction.
518 *
519 * We also try to account for the i2c bus speed.
520 * FIXME currently assumes 10 kHz as some real world devices seem
521 * to require it. We should query/set the speed via DPCD if supported.
444 */ 522 */
445 for (retry = 0, defer_i2c = 0; retry < (7 + defer_i2c); retry++) { 523 int max_retries = max(7, drm_dp_i2c_retry_count(msg, 10));
524
525 for (retry = 0, defer_i2c = 0; retry < (max_retries + defer_i2c); retry++) {
446 mutex_lock(&aux->hw_mutex); 526 mutex_lock(&aux->hw_mutex);
447 ret = aux->transfer(aux, msg); 527 ret = aux->transfer(aux, msg);
448 mutex_unlock(&aux->hw_mutex); 528 mutex_unlock(&aux->hw_mutex);