diff options
| author | Edward O'Callaghan <funfunctor@folklore1984.net> | 2017-04-21 16:07:46 +1000 |
|---|---|---|
| committer | Edward O'Callaghan <funfunctor@folklore1984.net> | 2017-04-21 16:08:04 +1000 |
| commit | a0d8e56b8c9494e879e01477d7f7b9ecf180c27d (patch) | |
| tree | ab803417f16dc1808b710f804187db901b7b5d76 | |
| parent | 5dd3dfd664abdfa044763c76c5cffb4a035bb494 (diff) | |
drm/amdgpu: implement native AUX initnativeaux-bug100745
Signed-off-by: Edward O'Callaghan <funfunctor@folklore1984.net>
| -rw-r--r-- | drivers/gpu/drm/amd/amdgpu/atombios_dp.c | 80 |
1 files changed, 79 insertions, 1 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c index 95df15bfb99b..b399238cea0f 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c @@ -209,14 +209,92 @@ static uint8_t aux_channel_fifo_read(struct radeon_device *rdev, uint32_t block) /***********/ -static int amdgpu_dp_process_aux_ch(struct amdgpu_i2c_chan *chan, +static int amdgpu_native_dp_process_aux_ch(struct amdgpu_i2c_chan *chan, u8 *send, int send_bytes, u8 *recv, int recv_size, u8 delay, u8 *ack) { + struct drm_device *dev = chan->dev; + struct amdgpu_device *adev = dev->dev_private; + uint32_t block; + uint8_t hpd_id, ch_id; + size_t num_bytes_rcvd; + unsigned i, wait; + + hpd_id = chan->rec.hpd & 0x7; + ch_id = chan->rec.i2c_id & 0x7; + + /* ****** XXX ****** */ /* XXX write non-atombios variant */ + + block = channel_id * 0x04 << 2; + atomhw_mask(adev, block + REG_AUX_PAD_EN_CTL, 0xffff, 0x01 << 16); + + block = get_aux_block(channel_id); + atomhw_mask(adev, block + DP_AUX_CTL, HPD_MASK, HPD(hpd_id) | 0x0101); + + /* Tell controller how many bytes we want to send */ + atomhw_mask(adev, block + DP_AUX_FIFO_CTL, 0xff00ff, send_bytes << 16); + + /* Caller should make sure message is 16 bytes or less */ + aux_channel_fifo_write_start(adev, block, *msg++); + while (--send_bytes) + aux_channel_fifo_write(adev, block, *msg++); + + atomhw_mask(adev, block + DP_AUX_CTL2, 0, BIT(1)); + atomhw_mask(adev, block + DP_AUX_FIFO_CTL, 0, BIT(0)); + + wait = 50; + while (!(atomhw_read(adev, block + DP_AUX_STATUS) & XFER_DONE)) { + usleep(10); + if (--wait != 0) + continue; + /* Timed out */ + return -ETIMEDOUT; + } + + if (atomhw_read(adev, block + DP_AUX_STATUS) & AUX_ERROR_FLAGS) + return -EBUSY; + + atomhw_write(adev, block + DP_AUX_FIFO, 0x80000001); + + *ack = aux_channel_fifo_read(adev, block); + num_bytes_rcvd = (atomhw_read(adev, block + DP_AUX_STATUS) >> 24) & 0x1f; + + if (num_bytes_rcvd == 0) + return -EIO; + + /* First byte is the reply field. The others are the data bytes */ + if (--num_bytes_rcvd == 0) + return num_bytes_rcvd; + + for (i = 0; i < min(num_bytes_rcvd, recv_size); i++) + recv[i] = aux_channel_fifo_read(adev, block); + + /* This extra data is lost forever. TODO: Signal an error? */ + for (; i < num_bytes_rcvd; i++) + aux_channel_fifo_read(adev, block); + + /* ****** XXX ****** */ + + *ack >>= 4; + + return num_bytes_rcvd; +} + +#define ATOM_BRAIN 0 +static int amdgpu_dp_process_aux_ch(struct amdgpu_i2c_chan *chan, + u8 *send, int send_bytes, + u8 *recv, int recv_size, + u8 delay, u8 *ack) +{ +#if ATOM_BRAIN return amdgpu_atombios_dp_process_aux_ch(chan, send, send_bytes, recv, recv_size, delay, ack); +#else + return amdgpu_native_dp_process_aux_ch(chan, send, send_bytes, + recv, recv_size, delay, ack); +#endif } #define BARE_ADDRESS_SIZE 3 |
