From e0c036d4aad50e29f3a2217324e4faf729f59839 Mon Sep 17 00:00:00 2001 From: Sudheesh Mavila Date: Tue, 8 Jan 2019 12:05:52 +0530 Subject: [PATCH 5727/5758] amd-i2s dma pointer uses Link position counter.This has been changed to Linear position counter and this rectifies underruns. Signed-off-by: Sudheesh Mavila --- sound/soc/amd/raven/acp3x-pcm-dma.c | 64 ++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 11 deletions(-) diff --git a/sound/soc/amd/raven/acp3x-pcm-dma.c b/sound/soc/amd/raven/acp3x-pcm-dma.c index 3abdf1f..3bb4ad3 100755 --- a/sound/soc/amd/raven/acp3x-pcm-dma.c +++ b/sound/soc/amd/raven/acp3x-pcm-dma.c @@ -37,12 +37,24 @@ struct i2s_dev_data { struct snd_pcm_substream *capture_stream; }; +union acp3x_dma_count { + struct { + u32 low; + u32 high; + } bcount; + u64 bytescount; +}; + + struct i2s_stream_instance { u16 num_pages; u16 channels; u32 xfer_resolution; u32 val; dma_addr_t dma_addr; + u32 byte_cnt_high_reg_offset; + u32 byte_cnt_low_reg_offset; + u64 bytescount; void __iomem *acp3x_base; }; @@ -335,6 +347,25 @@ static int acp3x_dma_open(struct snd_pcm_substream *substream) return 0; } +static u64 acp_get_byte_count(struct i2s_stream_instance *rtd, int direction) +{ + union acp3x_dma_count byte_count; + + if (direction == SNDRV_PCM_STREAM_PLAYBACK) { + byte_count.bcount.high = rv_readl(rtd->acp3x_base + + mmACP_BT_TX_LINEARPOSITIONCNTR_HIGH); + byte_count.bcount.low = rv_readl(rtd->acp3x_base + + mmACP_BT_TX_LINEARPOSITIONCNTR_LOW); + } else { + byte_count.bcount.high = rv_readl(rtd->acp3x_base + + mmACP_BT_RX_LINEARPOSITIONCNTR_HIGH); + byte_count.bcount.low = rv_readl(rtd->acp3x_base + + mmACP_BT_RX_LINEARPOSITIONCNTR_LOW); + } + return byte_count.bytescount; +} + + static int acp3x_dma_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -366,18 +397,28 @@ static int acp3x_dma_hw_params(struct snd_pcm_substream *substream, static snd_pcm_uframes_t acp3x_dma_pointer(struct snd_pcm_substream *substream) { + u64 bytescount = 0; u32 pos = 0; - struct i2s_stream_instance *rtd = substream->runtime->private_data; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - pos = rv_readl(rtd->acp3x_base + - mmACP_BT_TX_LINKPOSITIONCNTR); - else - pos = rv_readl(rtd->acp3x_base + - mmACP_BT_RX_LINKPOSITIONCNTR); - - if (pos >= MAX_BUFFER) - pos = 0; + u32 buffersize = 0; + struct i2s_stream_instance *rtd = + substream->runtime->private_data; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + buffersize = frames_to_bytes(substream->runtime, + substream->runtime->buffer_size); + bytescount = acp_get_byte_count(rtd, substream->stream); + if (bytescount > rtd->bytescount) + bytescount -= rtd->bytescount; + pos = do_div(bytescount, buffersize); + } else { + buffersize = frames_to_bytes(substream->runtime, + substream->runtime->buffer_size); + bytescount = acp_get_byte_count(rtd, substream->stream); + if (bytescount > rtd->bytescount) + bytescount -= rtd->bytescount; + pos = do_div(bytescount, buffersize); + } + if (pos >= MAX_BUFFER) + pos %= buffersize; return bytes_to_frames(substream->runtime, pos); } @@ -545,6 +586,7 @@ static int acp3x_dai_i2s_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + rtd->bytescount = acp_get_byte_count(rtd, substream->stream); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER); val = val | BIT(0); -- 2.7.4