aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Deucher <alexdeucher@gmail.com>2014-04-07 10:33:44 -0400
committerChristian König <christian.koenig@amd.com>2014-04-08 10:12:38 -0400
commitccdb516e1873d9c69377bfec1e3392f3ed660102 (patch)
treef1c37f89c63a83145444c55793149f55219c6adf
parent25377b921b4078a509f384fdd328b50d46414d9c (diff)
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: Alex 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: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Christian König <christian.koenig@amd.com>
-rw-r--r--drivers/gpu/drm/drm_dp_helper.c51
1 files changed, 32 insertions, 19 deletions
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c
index 27671489477d..bcfb0d07718e 100644
--- a/drivers/gpu/drm/drm_dp_helper.c
+++ b/drivers/gpu/drm/drm_dp_helper.c
@@ -665,11 +665,26 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
665{ 665{
666 struct drm_dp_aux *aux = adapter->algo_data; 666 struct drm_dp_aux *aux = adapter->algo_data;
667 unsigned int i, j; 667 unsigned int i, j;
668 struct drm_dp_aux_msg msg;
669 int err = 0;
668 670
669 for (i = 0; i < num; i++) { 671 memset(&msg, 0, sizeof(msg));
670 struct drm_dp_aux_msg msg;
671 int err;
672 672
673 for (i = 0; i < num; i++) {
674 msg.address = msgs[i].addr;
675 msg.request = (msgs[i].flags & I2C_M_RD) ?
676 DP_AUX_I2C_READ :
677 DP_AUX_I2C_WRITE;
678 msg.request |= DP_AUX_I2C_MOT;
679 /* Send a bare address packet to start the transaction.
680 * Zero sized messages specify an address only (bare
681 * address) transaction.
682 */
683 msg.buffer = NULL;
684 msg.size = 0;
685 err = drm_dp_i2c_do_msg(aux, &msg);
686 if (err < 0)
687 break;
673 /* 688 /*
674 * Many hardware implementations support FIFOs larger than a 689 * Many hardware implementations support FIFOs larger than a
675 * single byte, but it has been empirically determined that 690 * 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 * transferred byte-by-byte. 693 * transferred byte-by-byte.
679 */ 694 */
680 for (j = 0; j < msgs[i].len; j++) { 695 for (j = 0; j < msgs[i].len; j++) {
681 memset(&msg, 0, sizeof(msg));
682 msg.address = msgs[i].addr;
683
684 msg.request = (msgs[i].flags & I2C_M_RD) ?
685 DP_AUX_I2C_READ :
686 DP_AUX_I2C_WRITE;
687
688 /*
689 * All messages except the last one are middle-of-
690 * transfer messages.
691 */
692 if ((i < num - 1) || (j < msgs[i].len - 1))
693 msg.request |= DP_AUX_I2C_MOT;
694
695 msg.buffer = msgs[i].buf + j; 696 msg.buffer = msgs[i].buf + j;
696 msg.size = 1; 697 msg.size = 1;
697 698
698 err = drm_dp_i2c_do_msg(aux, &msg); 699 err = drm_dp_i2c_do_msg(aux, &msg);
699 if (err < 0) 700 if (err < 0)
700 return err; 701 break;
701 } 702 }
703 if (err < 0)
704 break;
702 } 705 }
706 if (err >= 0)
707 err = num;
708 /* Send a bare address packet to close out the transaction.
709 * Zero sized messages specify an address only (bare
710 * address) transaction.
711 */
712 msg.request &= ~DP_AUX_I2C_MOT;
713 msg.buffer = NULL;
714 msg.size = 0;
715 (void)drm_dp_i2c_do_msg(aux, &msg);
703 716
704 return num; 717 return err;
705} 718}
706 719
707static const struct i2c_algorithm drm_dp_i2c_algo = { 720static const struct i2c_algorithm drm_dp_i2c_algo = {