Skip to content

Commit

Permalink
drm/radeon: fix endian issues with DP handling (v3)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Alex Deucher committed Jul 22, 2013
1 parent 3e3e53f commit 34be8c9
Showing 1 changed file with 39 additions and 4 deletions.
43 changes: 39 additions & 4 deletions drivers/gpu/drm/radeon/atombios_dp.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,41 @@ static char *pre_emph_names[] = {
};

/***** radeon AUX functions *****/

/* Atom needs data in little endian format
* so swap as appropriate when copying data to
* or from atom. Note that atom operates on
* dw units.
*/
static void radeon_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le)
{
#ifdef __BIG_ENDIAN
u8 src_tmp[20], dst_tmp[20]; /* used for byteswapping */
u32 *dst32, *src32;
int i;

memcpy(src_tmp, src, num_bytes);
src32 = (u32 *)src_tmp;
dst32 = (u32 *)dst_tmp;
if (to_le) {
for (i = 0; i < ((num_bytes + 3) / 4); i++)
dst32[i] = cpu_to_le32(src32[i]);
memcpy(dst, dst_tmp, num_bytes);
} else {
u8 dws = num_bytes & ~3;
for (i = 0; i < ((num_bytes + 3) / 4); i++)
dst32[i] = le32_to_cpu(src32[i]);
memcpy(dst, dst_tmp, dws);
if (num_bytes % 4) {
for (i = 0; i < (num_bytes % 4); i++)
dst[dws+i] = dst_tmp[dws+i];
}
}
#else
memcpy(dst, src, num_bytes);
#endif
}

union aux_channel_transaction {
PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1;
PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2;
Expand All @@ -65,10 +100,10 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,

base = (unsigned char *)(rdev->mode_info.atom_context->scratch + 1);

memcpy(base, send, send_bytes);
radeon_copy_swap(base, send, send_bytes, true);

args.v1.lpAuxRequest = 0 + 4;
args.v1.lpDataOut = 16 + 4;
args.v1.lpAuxRequest = cpu_to_le16((u16)(0 + 4));
args.v1.lpDataOut = cpu_to_le16((u16)(16 + 4));
args.v1.ucDataOutLen = 0;
args.v1.ucChannelID = chan->rec.i2c_id;
args.v1.ucDelay = delay / 10;
Expand Down Expand Up @@ -102,7 +137,7 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
recv_bytes = recv_size;

if (recv && recv_size)
memcpy(recv, base + 16, recv_bytes);
radeon_copy_swap(recv, base + 16, recv_bytes, false);

return recv_bytes;
}
Expand Down

0 comments on commit 34be8c9

Please sign in to comment.