aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2015-09-01 13:12:54 -0400
committerJani Nikula <jani.nikula@intel.com>2015-09-02 09:08:20 -0400
commit4efa83c8c786ab7ec7982e3dd348cb7e7ecbeb04 (patch)
tree7f952dc87cd0136d0d69bd13ba1f9aae6ef6ce77
parent79a2b161c12a1b751f53a7698494cb722530bca5 (diff)
drm/dp: Adjust i2c-over-aux retry count based on message size and i2c bus speed
Calculate the number of retries we should do for each i2c-over-aux message based on the time it takes to perform the i2c transfer vs. the aux transfer. We assume the shortest possible length for the aux transfer, and the longest possible (exluding clock stretching) for the i2c transfer. The DP spec has some examples on how to calculate this, but we don't calculate things quite the same way. The spec doesn't account for the retry interval (assumes immediate retry on defer), and doesn't assume the best/worst case behaviour as we do. Note that currently we assume 10 kHz speed for the i2c bus. Some real world devices (eg. some Apple DP->VGA dongle) fails with less than 16 retries. and that would correspond to something close to 15 kHz (with our method of calculating things) But let's just go for 10 kHz to be on the safe side. Ideally we should query/set the i2c bus speed via DPCD but for now this should at leaast remove the regression from the 1->16 byte trasnfer size change. And of course if the sink completes the transfer quicker this shouldn't slow things down since we don't change the interval between retries. I did a few experiments with a DP->DVI dongle I have that allows you to change the i2c bus speed. Here are the results of me changing the actual bus speed and the assumed bus speed and seeing when we start to fail the operation: actual i2c khz assumed i2c khz max retries 1 1 ok -> 2 fail 211 ok -> 106 fail 5 8 ok -> 9 fail 27 ok -> 24 fail 10 17 ok -> 18 fail 13 ok -> 12 fail 100 210 ok -> 211 fail 2 ok -> 1 fail So based on that we have a fairly decent safety margin baked into the formula to calculate the max number of retries. Fixes a regression with some DP dongles from: commit 1d002fa720738bcd0bddb9178e9ea0773288e1dd Author: Simon Farnsworth <simon.farnsworth@onelan.co.uk> Date: Tue Feb 10 18:38:08 2015 +0000 drm/dp: Use large transactions for I2C over AUX v2: Use best case for AUX and worst case for i2c (Simon Farnsworth) Add a define our AUX retry interval and account for it v3: Make everything usecs to avoid confusion about units (Daniel) Add a comment reminding people about the AUX bitrate (Daniel) Use DIV_ROUND_UP() since we're after the "worst" case for i2c Cc: Simon Farnsworth <simon.farnsworth@onelan.com> Cc: moosotc@gmail.com Tested-by: moosotc@gmail.com Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=91451 Reviewed-by: Simon Farnsworth <simon.farnsworth@onelan.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com>
-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);