[PATCH] drm/dp: Use large transactions for I2C over AUX

Simon Farnsworth simon.farnsworth at onelan.co.uk
Fri Jan 23 10:40:38 PST 2015


DisplayPort to DVI-D Dual Link adapters designed by Bizlink have bugs in
their I2C over AUX implementation. They work fine with Windows, but fail
with Linux.

It turns out that they cannot keep an I2C transaction open unless the
previous read was 16 bytes; shorter reads can only be followed by a zero
byte transfer ending the I2C transaction.

Copy Windows's behaviour, and read 16 bytes at a time. Analysis of the
failure state was provided by Datapath Ltd.

Signed-off-by: Simon Farnsworth <simon.farnsworth at onelan.co.uk>
---
Thierry,

You put in the comment about "decreased performance", back in December 2013;
would you mind testing that this still works with the devices you tested?

Unfortunately, Bizlink are the only game in town for DP->DVI-DL adapters -
and their firmware is prone to giving up on I2C if we look at it
wrongly. Even Apple's device is Bizlink designed.

 drivers/gpu/drm/drm_dp_helper.c | 13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c
index 79968e3..b4a9d4a 100644
--- a/drivers/gpu/drm/drm_dp_helper.c
+++ b/drivers/gpu/drm/drm_dp_helper.c
@@ -507,16 +507,13 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
 		err = drm_dp_i2c_do_msg(aux, &msg);
 		if (err < 0)
 			break;
-		/*
-		 * Many hardware implementations support FIFOs larger than a
-		 * single byte, but it has been empirically determined that
-		 * transferring data in larger chunks can actually lead to
-		 * decreased performance. Therefore each message is simply
-		 * transferred byte-by-byte.
+		/* Bizlink designed DP->DVI-D Dual Link adapters require the
+                 * I2C over AUX packets to be as large as possible. If not,
+                 * the I2C transactions never succeed.
 		 */
-		for (j = 0; j < msgs[i].len; j++) {
+		for (j = 0; j < msgs[i].len; j+=16) {
 			msg.buffer = msgs[i].buf + j;
-			msg.size = 1;
+			msg.size = min(16, msgs[i].len - 16);
 
 			err = drm_dp_i2c_do_msg(aux, &msg);
 			if (err < 0)
-- 
2.1.0



More information about the dri-devel mailing list