1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
From e0c036d4aad50e29f3a2217324e4faf729f59839 Mon Sep 17 00:00:00 2001
From: Sudheesh Mavila <sudheesh.mavila@amd.com>
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 <sudheesh.mavila@amd.com>
---
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
|