mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-26 04:20:54 +07:00
drm/dp: Use I2C_WRITE_STATUS_UPDATE to drain partial I2C_WRITE requests
When an i2c WRITE gets an i2c defer or short i2c ack reply, we are supposed to switch the request from I2C_WRITE to I2C_WRITE_STATUS_UPDATE when we continue to poll for the completion of the request. v2: Don't assume DP_AUX_I2C_WRITE is 0 even though it is, to make the code more obvious to the casual reader (Jani) Acked-by: Alex Deucher <alexander.deucher@amd.com> Reviewed-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> [danvet: Resolve conflict due to changed context.] Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
parent
f993406182
commit
68ec2a2a24
@ -422,6 +422,19 @@ static u32 drm_dp_i2c_functionality(struct i2c_adapter *adapter)
|
||||
I2C_FUNC_10BIT_ADDR;
|
||||
}
|
||||
|
||||
static void drm_dp_i2c_msg_write_status_update(struct drm_dp_aux_msg *msg)
|
||||
{
|
||||
/*
|
||||
* In case of i2c defer or short i2c ack reply to a write,
|
||||
* we need to switch to WRITE_STATUS_UPDATE to drain the
|
||||
* rest of the message
|
||||
*/
|
||||
if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_I2C_WRITE) {
|
||||
msg->request &= DP_AUX_I2C_MOT;
|
||||
msg->request |= DP_AUX_I2C_WRITE_STATUS_UPDATE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Transfer a single I2C-over-AUX message and handle various error conditions,
|
||||
* retrying the transaction as appropriate. It is assumed that the
|
||||
@ -490,6 +503,8 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
|
||||
* Both native ACK and I2C ACK replies received. We
|
||||
* can assume the transfer was successful.
|
||||
*/
|
||||
if (ret != msg->size)
|
||||
drm_dp_i2c_msg_write_status_update(msg);
|
||||
return ret;
|
||||
|
||||
case DP_AUX_I2C_REPLY_NACK:
|
||||
@ -507,6 +522,7 @@ 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(400, 500);
|
||||
drm_dp_i2c_msg_write_status_update(msg);
|
||||
continue;
|
||||
|
||||
default:
|
||||
@ -519,6 +535,14 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
static void drm_dp_i2c_msg_set_request(struct drm_dp_aux_msg *msg,
|
||||
const struct i2c_msg *i2c_msg)
|
||||
{
|
||||
msg->request = (i2c_msg->flags & I2C_M_RD) ?
|
||||
DP_AUX_I2C_READ : DP_AUX_I2C_WRITE;
|
||||
msg->request |= DP_AUX_I2C_MOT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Keep retrying drm_dp_i2c_do_msg until all data has been transferred.
|
||||
*
|
||||
@ -572,10 +596,7 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
msg.address = msgs[i].addr;
|
||||
msg.request = (msgs[i].flags & I2C_M_RD) ?
|
||||
DP_AUX_I2C_READ :
|
||||
DP_AUX_I2C_WRITE;
|
||||
msg.request |= DP_AUX_I2C_MOT;
|
||||
drm_dp_i2c_msg_set_request(&msg, &msgs[i]);
|
||||
/* Send a bare address packet to start the transaction.
|
||||
* Zero sized messages specify an address only (bare
|
||||
* address) transaction.
|
||||
@ -583,6 +604,13 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
|
||||
msg.buffer = NULL;
|
||||
msg.size = 0;
|
||||
err = drm_dp_i2c_do_msg(aux, &msg);
|
||||
|
||||
/*
|
||||
* Reset msg.request in case in case it got
|
||||
* changed into a WRITE_STATUS_UPDATE.
|
||||
*/
|
||||
drm_dp_i2c_msg_set_request(&msg, &msgs[i]);
|
||||
|
||||
if (err < 0)
|
||||
break;
|
||||
/* We want each transaction to be as large as possible, but
|
||||
@ -595,6 +623,13 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
|
||||
msg.size = min(transfer_size, msgs[i].len - j);
|
||||
|
||||
err = drm_dp_i2c_drain_msg(aux, &msg);
|
||||
|
||||
/*
|
||||
* Reset msg.request in case in case it got
|
||||
* changed into a WRITE_STATUS_UPDATE.
|
||||
*/
|
||||
drm_dp_i2c_msg_set_request(&msg, &msgs[i]);
|
||||
|
||||
if (err < 0)
|
||||
break;
|
||||
transfer_size = err;
|
||||
|
Loading…
Reference in New Issue
Block a user