summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward O'Callaghan <funfunctor@folklore1984.net>2017-04-21 16:07:46 +1000
committerEdward O'Callaghan <funfunctor@folklore1984.net>2017-04-21 16:08:04 +1000
commita0d8e56b8c9494e879e01477d7f7b9ecf180c27d (patch)
treeab803417f16dc1808b710f804187db901b7b5d76
parent5dd3dfd664abdfa044763c76c5cffb4a035bb494 (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.c80
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