Commit ccdb516e authored by Alex Deucher's avatar Alex Deucher Committed by Christian König

drm/dp/i2c: send bare addresses to properly reset i2c connections (v4)

We need bare address packets at the start and end of
each i2c over aux transaction to properly reset the connection
between transactions.  This mirrors what the existing dp i2c
over aux algo currently does.

This fixes EDID fetches on certain monitors especially with
dp bridges.

v2: update as per Ville's comments
    - Set buffer to NULL for zero sized packets
    - abort the entre transaction if one of the messages fails
v3: drop leftover debugging code
v4: integrate Thierry's comments
    - add comments about address only transactions
    - switch back to i and j
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Jani Nikula <jani.nikula@intel.com>
Cc: Thierry Reding <treding@nvidia.com>
Reviewed-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: default avatarChristian König <christian.koenig@amd.com>
parent 25377b92
...@@ -665,11 +665,26 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, ...@@ -665,11 +665,26 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
{ {
struct drm_dp_aux *aux = adapter->algo_data; struct drm_dp_aux *aux = adapter->algo_data;
unsigned int i, j; unsigned int i, j;
struct drm_dp_aux_msg msg;
int err = 0;
for (i = 0; i < num; i++) { memset(&msg, 0, sizeof(msg));
struct drm_dp_aux_msg msg;
int err;
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;
/* Send a bare address packet to start the transaction.
* Zero sized messages specify an address only (bare
* address) transaction.
*/
msg.buffer = NULL;
msg.size = 0;
err = drm_dp_i2c_do_msg(aux, &msg);
if (err < 0)
break;
/* /*
* Many hardware implementations support FIFOs larger than a * Many hardware implementations support FIFOs larger than a
* single byte, but it has been empirically determined that * single byte, but it has been empirically determined that
...@@ -678,30 +693,28 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, ...@@ -678,30 +693,28 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
* transferred byte-by-byte. * transferred byte-by-byte.
*/ */
for (j = 0; j < msgs[i].len; j++) { for (j = 0; j < msgs[i].len; j++) {
memset(&msg, 0, sizeof(msg));
msg.address = msgs[i].addr;
msg.request = (msgs[i].flags & I2C_M_RD) ?
DP_AUX_I2C_READ :
DP_AUX_I2C_WRITE;
/*
* All messages except the last one are middle-of-
* transfer messages.
*/
if ((i < num - 1) || (j < msgs[i].len - 1))
msg.request |= DP_AUX_I2C_MOT;
msg.buffer = msgs[i].buf + j; msg.buffer = msgs[i].buf + j;
msg.size = 1; msg.size = 1;
err = drm_dp_i2c_do_msg(aux, &msg); err = drm_dp_i2c_do_msg(aux, &msg);
if (err < 0) if (err < 0)
return err; break;
} }
if (err < 0)
break;
} }
if (err >= 0)
err = num;
/* Send a bare address packet to close out the transaction.
* Zero sized messages specify an address only (bare
* address) transaction.
*/
msg.request &= ~DP_AUX_I2C_MOT;
msg.buffer = NULL;
msg.size = 0;
(void)drm_dp_i2c_do_msg(aux, &msg);
return num; return err;
} }
static const struct i2c_algorithm drm_dp_i2c_algo = { static const struct i2c_algorithm drm_dp_i2c_algo = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment