Fix I2C-Over-AUX handling
Subsystems (3)
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
PATCH 1/2 drm/dp: Correct Write_Status_Update_Request handling
[Why]
Notice few problems under I2C-write-over-Aux withWrite_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.
--- 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
@@ -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
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 withWrite_Status_Update_Requestflag set cases:- I2C-write-over-Aux request with
Write_Status_Update_Requestflag 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_Requestflag 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_Requestset.
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_Requestupon reply of I2C_ACK|AUX_ACK followed by “M”- Send
Write_Status_Update_Requestupon 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]>Signed-off-by Wayne Lin <[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@@ -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
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: CorrectWrite_Status_Update_RequesthandlingQuoted 8 lines · Wayne Lin
[Why]
Notice few problems under I2C-write-over-Aux withWrite_Status_Update_Requestflag set cases:- I2C-write-over-Aux request with
Write_Status_Update_Requestflag 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_Requestflag 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_Requestset.
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_Requestupon reply of I2C_ACK|AUX_ACK followed by “M”- Send
Write_Status_Update_Requestupon I2C_DEFER|AUX_ACK reply only when the request is I2C-write-over-Aux.Fixes 68ec2a2a2481 ("drm/dp: Use I2C_WRITE_STATUS_UPDATE to drainpartial
I2C_WRITErequests")Cc Ville Syrjälä <[email protected]>Cc Jani Nikula <[email protected]>Cc Mario Limonciello <[email protected]>Cc Harry Wentland <[email protected]>Signed-off-by Wayne Lin <[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@@ -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
-0msg->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, structdrm_dp_aux_msg*msg)
Quoted 4 lines
case
DP_AUX_I2C_REPLY_ACK:
/*
* Both native ACK and I2C ACK replies received. Wedrivers/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
-0if (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
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.
--- 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
@@ -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
[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 handlingThese 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_Requestfor 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: CorrectWrite_Status_Update_Requesthandling drm/dp: Add handling for partially read under I2-readC-over-AUXdrivers/gpu/drm/display/drm_dp_helper.c | 28 +++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-)--
2.43.0