Skip to contentSkip to conversation

Fix I2C-Over-AUX handling

PATCH In review Wayne Lin 2 participants 6 messages Apr 24, 2025 – Apr 27, 2025

Subsystems (3)
lore
Share & tools
lore

Wayne Lin

author
#0 lore raw

cover Fix I2C-Over-AUX handling

These two patches are trying to fix how we handle I2C-Over_AUX transactions when sink side can only complte partial data at one time.

We encounter EDID reading error with specific monitor and cause mode list can only be lower resolutions. After analysis, the monitor will reply I2C_ACK|AUX_ACK followed by a byte indicating the read data length fewer than the requested one. Under this case, we should update the request length and request again. Code we have today doesn't handle such case.

Meanwhile, how we handle Write_Status_Update_Request for I2C write over AUX transactions seems wrong as well. The request format should be address only transaction without length and data, and we don't really send it out. Further more, it should be constrained for I2C write case only. Not for I2C read request.

1st patch to fix the I2C write problem and 2nd one to fix the I2C read.

---
Wayne Lin (2):
drm/dp: Correct Write_Status_Update_Request handling drm/dp: Add handling for partially read under I2-readC-over-AUX

 drivers/gpu/drm/display/drm_dp_helper.c | 28 +++++++++++++++++++++----
 1 file changed, 24 insertions(+), 4 deletions(-)
Signature · 1 line
2.43.0
author
#1 lore raw

PATCH 1/2 drm/dp: Correct Write_Status_Update_Request handling

[Why]
Notice few problems under I2C-write-over-Aux with
Write_Status_Update_Request flag set cases:

- I2C-write-over-Aux request with Write_Status_Update_Request flag set won't get sent upon the reply of I2C_ACK|AUX_ACK followed by “M” Value. Now just set the flag but won't send out

- The I2C-over-Aux request command with Write_Status_Update_Request flag set is incorrect. Should be "SYNC->COM3:0 (= 0110)|0000-> 0000|0000-> 0|7-bit I2C address (the same as the last)-> STOP->". Address only transaction without length and data.

- Upon I2C_DEFER|AUX_ACK Reply for I2C-read-over-Aux, soure should repeat the identical I2C-read-over-AUX transaction with the same LEN value. Not with Write_Status_Update_Request set.

[How]
Refer to DP v2.1: 2.11.7.1.5.3 & 2.11.7.1.5.4
- Clean aux msg buffer and size when constructing
write status update request.

- Send out Write_Status_Update_Request upon reply of I2C_ACK|AUX_ACK followed by “M”

- Send Write_Status_Update_Request upon I2C_DEFER|AUX_ACK reply only when the request is I2C-write-over-Aux.

Fixes 68ec2a2a2481 ("drm/dp: Use I2C_WRITE_STATUS_UPDATE to drain partial I2C_WRITE requests")
Cc Ville Syrjälä <[email protected]>
Cc Jani Nikula <[email protected]>
Cc Mario Limonciello <[email protected]>
Cc Harry Wentland <[email protected]>
---
 drivers/gpu/drm/display/drm_dp_helper.c | 27 +++++++++++++++++++++----
 1 file changed, 23 insertions(+), 4 deletions(-)
drivers/gpu/drm/display/drm_dp_helper.c +23 -4
index 6ee51003de3c..28f0708c3b27 100644
@@ -1631,6 +1631,12 @@ static void drm_dp_i2c_msg_write_status_update(struct drm_dp_aux_msg *msg)
 		msg->request &= DP_AUX_I2C_MOT;
 		msg->request |= DP_AUX_I2C_WRITE_STATUS_UPDATE;
 	}
+
+	/*
+	 * Address only transaction
+	 */
+	msg->buffer = NULL;
+	msg->size = 0;
 }
 
 #define AUX_PRECHARGE_LEN 10 /* 10 to 16 */
@@ -1797,10 +1803,22 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
 		case DP_AUX_I2C_REPLY_ACK:
 			/*
 			 * Both native ACK and I2C ACK replies received. We
-			 * can assume the transfer was successful.
+			 * can't assume the transfer was completed. Both I2C
+			 * WRITE/READ request may get I2C ack reply with partially
+			 * completion. We have to continue to poll for the
+			 * completion of the request.
 			 */
-			if (ret != msg->size)
-				drm_dp_i2c_msg_write_status_update(msg);
+			if (ret != msg->size) {
+				drm_dbg_kms(aux->drm_dev,
+					    "%s: I2C partially ack (result=%d, size=%zu)\n",
+					    aux->name, ret, msg->size);
+				if (!(msg->request & DP_AUX_I2C_READ)) {
+					usleep_range(AUX_RETRY_INTERVAL, AUX_RETRY_INTERVAL + 100);
+					drm_dp_i2c_msg_write_status_update(msg);
+				}
+
+				continue;
+			}
 			return ret;
 
 		case DP_AUX_I2C_REPLY_NACK:
@@ -1819,7 +1837,8 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
 			if (defer_i2c < 7)
 				defer_i2c++;
 			usleep_range(AUX_RETRY_INTERVAL, AUX_RETRY_INTERVAL + 100);
-			drm_dp_i2c_msg_write_status_update(msg);
+			if (!(msg->request & DP_AUX_I2C_READ))
+				drm_dp_i2c_msg_write_status_update(msg);
 
 			continue;
 
Signature · 1 line
2.43.0
#2 lore raw

Re: [PATCH 1/2] drm/dp: Correct Write_Status_Update_Request handling

Quoted 8 lines · Wayne Lin

[Why]
Notice few problems under I2C-write-over-Aux with
Write_Status_Update_Request flag set cases:

- I2C-write-over-Aux request with Write_Status_Update_Request flag set won't get sent upon the reply of I2C_ACK|AUX_ACK followed by “M” Value. Now just set the flag but won't send out

drm_dp_i2c_drain_msg() should keep going until an error or the full message got transferred.

Quoted 6 lines

- The I2C-over-Aux request command with Write_Status_Update_Request flag set is incorrect. Should be "SYNC->COM3:0 (= 0110)|0000-> 0000|0000-> 0|7-bit I2C address (the same as the last)-> STOP->". Address only transaction without length and data.

This looks like a real issue.

Quoted 5 lines

- Upon I2C_DEFER|AUX_ACK Reply for I2C-read-over-Aux, soure should repeat the identical I2C-read-over-AUX transaction with the same LEN value. Not with Write_Status_Update_Request set.

drm_dp_i2c_msg_write_status_update() already
checks the request type.

Quoted 78 lines

[How]
Refer to DP v2.1: 2.11.7.1.5.3 & 2.11.7.1.5.4
- Clean aux msg buffer and size when constructing
write status update request.

- Send out Write_Status_Update_Request upon reply of I2C_ACK|AUX_ACK followed by “M”

- Send Write_Status_Update_Request upon I2C_DEFER|AUX_ACK reply only when the request is I2C-write-over-Aux.

Fixes 68ec2a2a2481 ("drm/dp: Use I2C_WRITE_STATUS_UPDATE to drain partial I2C_WRITE requests")
Cc Ville Syrjälä <[email protected]>
Cc Jani Nikula <[email protected]>
Cc Mario Limonciello <[email protected]>
Cc Harry Wentland <[email protected]>
---
 drivers/gpu/drm/display/drm_dp_helper.c | 27 +++++++++++++++++++++----
 1 file changed, 23 insertions(+), 4 deletions(-)
drivers/gpu/drm/display/drm_dp_helper.c +23 -4
index 6ee51003de3c..28f0708c3b27 100644
@@ -1631,6 +1631,12 @@ static void drm_dp_i2c_msg_write_status_update(struct drm_dp_aux_msg *msg)
 		msg->request &= DP_AUX_I2C_MOT;
 		msg->request |= DP_AUX_I2C_WRITE_STATUS_UPDATE;
 	}
+
+	/*
+	 * Address only transaction
+	 */
+	msg->buffer = NULL;
+	msg->size = 0;
 }
 
 #define AUX_PRECHARGE_LEN 10 /* 10 to 16 */
@@ -1797,10 +1803,22 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
 		case DP_AUX_I2C_REPLY_ACK:
 			/*
 			 * Both native ACK and I2C ACK replies received. We
-			 * can assume the transfer was successful.
+			 * can't assume the transfer was completed. Both I2C
+			 * WRITE/READ request may get I2C ack reply with partially
+			 * completion. We have to continue to poll for the
+			 * completion of the request.
 			 */
-			if (ret != msg->size)
-				drm_dp_i2c_msg_write_status_update(msg);
+			if (ret != msg->size) {
+				drm_dbg_kms(aux->drm_dev,
+					    "%s: I2C partially ack (result=%d, size=%zu)\n",
+					    aux->name, ret, msg->size);
+				if (!(msg->request & DP_AUX_I2C_READ)) {
+					usleep_range(AUX_RETRY_INTERVAL, AUX_RETRY_INTERVAL + 100);
+					drm_dp_i2c_msg_write_status_update(msg);
+				}
+
+				continue;
+			}
 			return ret;
 
 		case DP_AUX_I2C_REPLY_NACK:
@@ -1819,7 +1837,8 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
 			if (defer_i2c < 7)
 				defer_i2c++;
 			usleep_range(AUX_RETRY_INTERVAL, AUX_RETRY_INTERVAL + 100);
-			drm_dp_i2c_msg_write_status_update(msg);
+			if (!(msg->request & DP_AUX_I2C_READ))
+				drm_dp_i2c_msg_write_status_update(msg);
 
 			continue;
 
Signature · 1 line
2.43.0
Signature · 2 lines
Ville Syrjälä
Intel
author
#3 lore raw

RE: [PATCH 1/2] drm/dp: Correct Write_Status_Update_Request handling

[Public]

Thanks for you time Ville Syrjälä !
And like what you pointed out here, sorry I realized that I misread the code flow just after I sent it out. Will have another patch for fixing the aux request format only. Thanks!

Regards,
Wayne

Quoted 130 lines

-----Original Message-----
From: Ville Syrjälä <[email protected]>
Sent: Friday, April 25, 2025 10:48 PM
To: Lin, Wayne <[email protected]>
Cc: [email protected]; [email protected]; Limonciello, Mario <[email protected]>; Wentland, Harry <[email protected]>; [email protected]
Subject: Re: [PATCH 1/2] drm/dp: Correct Write_Status_Update_Request handling

Quoted 8 lines · Wayne Lin

[Why]
Notice few problems under I2C-write-over-Aux with Write_Status_Update_Request flag set cases:

- I2C-write-over-Aux request with Write_Status_Update_Request flag set won't get sent upon the reply of I2C_ACK|AUX_ACK followed by “M” Value. Now just set the flag but won't send out

drm_dp_i2c_drain_msg() should keep going until an error or the full message got transferred.

Quoted 6 lines

- The I2C-over-Aux request command with Write_Status_Update_Request flag set is incorrect. Should be "SYNC->COM3:0 (= 0110)|0000-> 0000|0000-> 0|7-bit I2C address (the same as the last)-> STOP->". Address only transaction without length and data.

This looks like a real issue.

Quoted 5 lines

- Upon I2C_DEFER|AUX_ACK Reply for I2C-read-over-Aux, soure should repeat the identical I2C-read-over-AUX transaction with the same LEN value. Not with Write_Status_Update_Request set.

drm_dp_i2c_msg_write_status_update() already checks the request type.

drivers/gpu/drm/display/drm_dp_helper.c static void

Quoted 31 lines

[How]
Refer to DP v2.1: 2.11.7.1.5.3 & 2.11.7.1.5.4
- Clean aux msg buffer and size when constructing write status update request.

- Send out Write_Status_Update_Request upon reply of I2C_ACK|AUX_ACK followed by “M”

- Send Write_Status_Update_Request upon I2C_DEFER|AUX_ACK reply only when the request is I2C-write-over-Aux.

Fixes 68ec2a2a2481 ("drm/dp: Use I2C_WRITE_STATUS_UPDATE to drain

partial I2C_WRITE requests")

Cc Ville Syrjälä <[email protected]>
Cc Jani Nikula <[email protected]>
Cc Mario Limonciello <[email protected]>
Cc Harry Wentland <[email protected]>
---
 drivers/gpu/drm/display/drm_dp_helper.c | 27
+++++++++++++++++++++----
 1 file changed, 23 insertions(+), 4 deletions(-)
drivers/gpu/drm/display/drm_dp_helper.c +0 -0
index 6ee51003de3c..28f0708c3b27 100644
@@ -1631,6 +1631,12 @@ static void

drm_dp_i2c_msg_write_status_update(struct drm_dp_aux_msg *msg)

Quoted 12 lines
drivers/gpu/drm/display/drm_dp_helper.c +6 -0
            msg->request &= DP_AUX_I2C_MOT;
            msg->request |= DP_AUX_I2C_WRITE_STATUS_UPDATE;
    }
+
+   /*
+    * Address only transaction
+    */
+   msg->buffer = NULL;
+   msg->size = 0;
 }
 
 #define AUX_PRECHARGE_LEN 10 /* 10 to 16 */ @@ -1797,10 +1803,22 @@
Quoted 1 line

static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg

*msg)

Quoted 4 lines

case DP_AUX_I2C_REPLY_ACK:
/*
* Both native ACK and I2C ACK replies received. We

drivers/gpu/drm/display/drm_dp_helper.c +0 -1
-                    * can assume the transfer was successful.

drivers/gpu/drm/display/drm_dp_helper.c static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)

Quoted 10 lines
drivers/gpu/drm/display/drm_dp_helper.c +7 -2
+                    * can't assume the transfer was completed. Both I2C
+                    * WRITE/READ request may get I2C ack reply with partially
+                    * completion. We have to continue to poll for the
+                    * completion of the request.
                     */
-                   if (ret != msg->size)
-                           drm_dp_i2c_msg_write_status_update(msg);
+                   if (ret != msg->size) {
+                           drm_dbg_kms(aux->drm_dev,
+                                       "%s: I2C partially ack (result=%d,

size=%zu)\n",

drivers/gpu/drm/display/drm_dp_helper.c static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)

Quoted 3 lines
drivers/gpu/drm/display/drm_dp_helper.c +3 -0
+                                       aux->name, ret, msg->size);
+                           if (!(msg->request & DP_AUX_I2C_READ)) {
+                                   usleep_range(AUX_RETRY_INTERVAL,

AUX_RETRY_INTERVAL + 100);

drivers/gpu/drm/display/drm_dp_helper.c static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux,

Quoted 9 lines
drivers/gpu/drm/display/drm_dp_helper.c +5 -0
+                                   drm_dp_i2c_msg_write_status_update(msg);
+                           }
+
+                           continue;
+                   }
                    return ret;
 
            case DP_AUX_I2C_REPLY_NACK:
@@ -1819,7 +1837,8 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux,

struct drm_dp_aux_msg *msg)

drivers/gpu/drm/display/drm_dp_helper.c static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)

Quoted 3 lines
drivers/gpu/drm/display/drm_dp_helper.c +0 -0
                    if (defer_i2c < 7)
                            defer_i2c++;
                    usleep_range(AUX_RETRY_INTERVAL,

AUX_RETRY_INTERVAL + 100);

Quoted 8 lines
drivers/gpu/drm/display/drm_dp_helper.c +2 -2
-                   drm_dp_i2c_msg_write_status_update(msg);
+                   if (!(msg->request & DP_AUX_I2C_READ))
+                           drm_dp_i2c_msg_write_status_update(msg);
 
                    continue;
 
--

2.43.0

--
Ville Syrjälä
Intel

author
#4 lore raw

PATCH 2/2 drm/dp: Add handling for partially read under I2-readC-over-AUX

In reply to Wayne Lin

[Why]
There is no handling for I2C-read-over-AUX when receive reply of I2C_ACK|AUX_ACK followed by the total number of data bytes Fewer than LEN + 1

[How]
Refer to DP v2.1: 2.11.7.1.6.3 & 2.11.7.1.6.4, repeat the identical I2C-read-over-AUX transaction with the updated LEN value equal to the original LEN value minus the total number of data bytes received so far.

Fixes 68ec2a2a2481 ("drm/dp: Use I2C_WRITE_STATUS_UPDATE to drain partial I2C_WRITE requests")
Cc Ville Syrjälä <[email protected]>
Cc Jani Nikula <[email protected]>
Cc Mario Limonciello <[email protected]>
Cc Harry Wentland <[email protected]>
---
 drivers/gpu/drm/display/drm_dp_helper.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/gpu/drm/display/drm_dp_helper.c +4 -3
index 28f0708c3b27..938214a980a9 100644
@@ -1812,10 +1812,11 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
 				drm_dbg_kms(aux->drm_dev,
 					    "%s: I2C partially ack (result=%d, size=%zu)\n",
 					    aux->name, ret, msg->size);
-				if (!(msg->request & DP_AUX_I2C_READ)) {
-					usleep_range(AUX_RETRY_INTERVAL, AUX_RETRY_INTERVAL + 100);
+				usleep_range(AUX_RETRY_INTERVAL, AUX_RETRY_INTERVAL + 100);
+				if (msg->request & DP_AUX_I2C_READ)
+					msg->size -= ret;
+				else
 					drm_dp_i2c_msg_write_status_update(msg);
-				}
 
 				continue;
 			}
Signature · 1 line
2.43.0
author
#5 lore raw
In reply to Wayne Lin

[Public]

Sorry for spamming.
Please ignore this patch set. I misread the code flow here a bit. Will refine another version later if needed.

Thanks!

Regards,
Wayne

Quoted 36 lines

-----Original Message-----
From: Wayne Lin <[email protected]>
Sent: Thursday, April 24, 2025 11:08 AM
To: [email protected]
Cc: [email protected]; [email protected]; Limonciello, Mario <[email protected]>; Wentland, Harry <[email protected]>; Lin, Wayne <[email protected]>
Subject: [PATCH 0/2] Fix I2C-Over-AUX handling

These two patches are trying to fix how we handle I2C-Over_AUX transactions when sink side can only complte partial data at one time.

We encounter EDID reading error with specific monitor and cause mode list can only be lower resolutions. After analysis, the monitor will reply I2C_ACK|AUX_ACK followed by a byte indicating the read data length fewer than the requested one. Under this case, we should update the request length and request again. Code we have today doesn't handle such case.

Meanwhile, how we handle Write_Status_Update_Request for I2C write over AUX transactions seems wrong as well. The request format should be address only transaction without length and data, and we don't really send it out. Further more, it should be constrained for I2C write case only. Not for I2C read request.

1st patch to fix the I2C write problem and 2nd one to fix the I2C read.

---
Wayne Lin (2):
drm/dp: Correct Write_Status_Update_Request handling drm/dp: Add handling for partially read under I2-readC-over-AUX

 drivers/gpu/drm/display/drm_dp_helper.c | 28 +++++++++++++++++++++----
 1 file changed, 24 insertions(+), 4 deletions(-)

--
2.43.0