aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Deucher <alexander.deucher@amd.com>2013-07-18 11:13:53 -0400
committerAlex Deucher <alexander.deucher@amd.com>2013-07-22 15:57:12 -0400
commit34be8c9af7b8728465963740fc11136ae90dfc36 (patch)
tree507be978a890dc152df26f11f64e13bf6bc1bbe5
parent3e3e53f86bee87bb14474213c879595605e35112 (diff)
drm/radeon: fix endian issues with DP handling (v3)
The atom interpreter expects data in LE format, so swap the message buffer as apprioriate. v2: properly handle non-dw aligned byte counts. v3: properly handle remainder Signed-off-by: Alex Deucher <alexander.deucher@amd.com> Cc: Dong He <hedonghust@gmail.com> Cc: stable@vger.kernel.org
-rw-r--r--drivers/gpu/drm/radeon/atombios_dp.c43
1 files changed, 39 insertions, 4 deletions
diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c
index 064023bed480..32501f6ec991 100644
--- a/drivers/gpu/drm/radeon/atombios_dp.c
+++ b/drivers/gpu/drm/radeon/atombios_dp.c
@@ -44,6 +44,41 @@ static char *pre_emph_names[] = {
44}; 44};
45 45
46/***** radeon AUX functions *****/ 46/***** radeon AUX functions *****/
47
48/* Atom needs data in little endian format
49 * so swap as appropriate when copying data to
50 * or from atom. Note that atom operates on
51 * dw units.
52 */
53static void radeon_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le)
54{
55#ifdef __BIG_ENDIAN
56 u8 src_tmp[20], dst_tmp[20]; /* used for byteswapping */
57 u32 *dst32, *src32;
58 int i;
59
60 memcpy(src_tmp, src, num_bytes);
61 src32 = (u32 *)src_tmp;
62 dst32 = (u32 *)dst_tmp;
63 if (to_le) {
64 for (i = 0; i < ((num_bytes + 3) / 4); i++)
65 dst32[i] = cpu_to_le32(src32[i]);
66 memcpy(dst, dst_tmp, num_bytes);
67 } else {
68 u8 dws = num_bytes & ~3;
69 for (i = 0; i < ((num_bytes + 3) / 4); i++)
70 dst32[i] = le32_to_cpu(src32[i]);
71 memcpy(dst, dst_tmp, dws);
72 if (num_bytes % 4) {
73 for (i = 0; i < (num_bytes % 4); i++)
74 dst[dws+i] = dst_tmp[dws+i];
75 }
76 }
77#else
78 memcpy(dst, src, num_bytes);
79#endif
80}
81
47union aux_channel_transaction { 82union aux_channel_transaction {
48 PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1; 83 PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1;
49 PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2; 84 PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2;
@@ -65,10 +100,10 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
65 100
66 base = (unsigned char *)(rdev->mode_info.atom_context->scratch + 1); 101 base = (unsigned char *)(rdev->mode_info.atom_context->scratch + 1);
67 102
68 memcpy(base, send, send_bytes); 103 radeon_copy_swap(base, send, send_bytes, true);
69 104
70 args.v1.lpAuxRequest = 0 + 4; 105 args.v1.lpAuxRequest = cpu_to_le16((u16)(0 + 4));
71 args.v1.lpDataOut = 16 + 4; 106 args.v1.lpDataOut = cpu_to_le16((u16)(16 + 4));
72 args.v1.ucDataOutLen = 0; 107 args.v1.ucDataOutLen = 0;
73 args.v1.ucChannelID = chan->rec.i2c_id; 108 args.v1.ucChannelID = chan->rec.i2c_id;
74 args.v1.ucDelay = delay / 10; 109 args.v1.ucDelay = delay / 10;
@@ -102,7 +137,7 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
102 recv_bytes = recv_size; 137 recv_bytes = recv_size;
103 138
104 if (recv && recv_size) 139 if (recv && recv_size)
105 memcpy(recv, base + 16, recv_bytes); 140 radeon_copy_swap(recv, base + 16, recv_bytes, false);
106 141
107 return recv_bytes; 142 return recv_bytes;
108} 143}