14
14
#include <sound/hda-mlink.h>
15
15
#include <sound/hda-sdw-bpt.h>
16
16
#include <sound/sof.h>
17
+ #include <sound/sof/ipc4/header.h>
17
18
#include "../ops.h"
18
19
#include "../sof-priv.h"
20
+ #include "../ipc4-priv.h"
19
21
#include "hda.h"
20
22
21
23
#define BPT_FREQUENCY 192000 /* The max rate defined in rate_bits[] hdac_device.c */
22
24
#define BPT_MULTIPLIER ((BPT_FREQUENCY / 48000) - 1)
25
+ #define BPT_CHAIN_DMA_FIFO_MS 10
26
+ /*
27
+ * This routine is directly inspired by sof_ipc4_chain_dma_trigger(),
28
+ * with major simplifications since there are no pipelines defined
29
+ * and no dependency on ALSA hw_params
30
+ */
31
+ static int chain_dma_trigger (struct snd_sof_dev * sdev , unsigned int stream_tag ,
32
+ int direction , int state )
33
+ {
34
+ struct sof_ipc4_fw_data * ipc4_data = sdev -> private ;
35
+ bool allocate , enable , set_fifo_size ;
36
+ struct sof_ipc4_msg msg = {{ 0 }};
37
+ int dma_id ;
38
+
39
+ if (sdev -> pdata -> ipc_type != SOF_IPC_TYPE_4 )
40
+ return - EOPNOTSUPP ;
41
+
42
+ switch (state ) {
43
+ case SOF_IPC4_PIPE_RUNNING : /* Allocate and start the chain */
44
+ allocate = true;
45
+ enable = true;
46
+ set_fifo_size = true;
47
+ break ;
48
+ case SOF_IPC4_PIPE_PAUSED : /* Stop the chain */
49
+ allocate = true;
50
+ enable = false;
51
+ set_fifo_size = false;
52
+ break ;
53
+ case SOF_IPC4_PIPE_RESET : /* Deallocate chain resources and remove the chain */
54
+ allocate = false;
55
+ enable = false;
56
+ set_fifo_size = false;
57
+ break ;
58
+ default :
59
+ dev_err (sdev -> dev , "Unexpected state %d" , state );
60
+ return - EINVAL ;
61
+ }
62
+
63
+ msg .primary = SOF_IPC4_MSG_TYPE_SET (SOF_IPC4_GLB_CHAIN_DMA );
64
+ msg .primary |= SOF_IPC4_MSG_DIR (SOF_IPC4_MSG_REQUEST );
65
+ msg .primary |= SOF_IPC4_MSG_TARGET (SOF_IPC4_FW_GEN_MSG );
66
+
67
+ /* for BPT/BRA we can use the same stream tag for host and link */
68
+ dma_id = stream_tag - 1 ;
69
+ if (direction == SNDRV_PCM_STREAM_CAPTURE )
70
+ dma_id += ipc4_data -> num_playback_streams ;
71
+
72
+ msg .primary |= SOF_IPC4_GLB_CHAIN_DMA_HOST_ID (dma_id );
73
+ msg .primary |= SOF_IPC4_GLB_CHAIN_DMA_LINK_ID (dma_id );
74
+
75
+ /* For BPT/BRA we use 32 bits so SCS is not set */
76
+
77
+ /* CHAIN DMA needs at least 2ms */
78
+ if (set_fifo_size )
79
+ msg .extension |= SOF_IPC4_GLB_EXT_CHAIN_DMA_FIFO_SIZE (BPT_FREQUENCY / 1000 *
80
+ BPT_CHAIN_DMA_FIFO_MS *
81
+ sizeof (u32 ));
82
+
83
+ if (allocate )
84
+ msg .primary |= SOF_IPC4_GLB_CHAIN_DMA_ALLOCATE_MASK ;
85
+
86
+ if (enable )
87
+ msg .primary |= SOF_IPC4_GLB_CHAIN_DMA_ENABLE_MASK ;
88
+
89
+ return sof_ipc_tx_message_no_reply (sdev -> ipc , & msg , 0 );
90
+ }
23
91
24
92
static int hda_sdw_bpt_dma_prepare (struct device * dev , struct hdac_ext_stream * * sdw_bpt_stream ,
25
93
struct snd_dma_buffer * dmab_bdl , u32 bpt_num_bytes ,
@@ -46,6 +114,21 @@ static int hda_sdw_bpt_dma_prepare(struct device *dev, struct hdac_ext_stream **
46
114
}
47
115
* sdw_bpt_stream = bpt_stream ;
48
116
117
+ if (!sdev -> dspless_mode_selected ) {
118
+ struct hdac_stream * hstream ;
119
+ u32 mask ;
120
+
121
+ /* decouple host and link DMA if the DSP is used */
122
+ hstream = & bpt_stream -> hstream ;
123
+ mask = BIT (hstream -> index );
124
+
125
+ snd_sof_dsp_update_bits (sdev , HDA_DSP_PP_BAR , SOF_HDA_REG_PP_PPCTL , mask , mask );
126
+
127
+ snd_hdac_ext_stream_reset (bpt_stream );
128
+
129
+ snd_hdac_ext_stream_setup (bpt_stream , format );
130
+ }
131
+
49
132
if (hdac_stream (bpt_stream )-> direction == SNDRV_PCM_STREAM_PLAYBACK ) {
50
133
struct hdac_bus * bus = sof_to_bus (sdev );
51
134
struct hdac_ext_link * hlink ;
@@ -63,6 +146,8 @@ static int hda_sdw_bpt_dma_deprepare(struct device *dev, struct hdac_ext_stream
63
146
struct snd_dma_buffer * dmab_bdl )
64
147
{
65
148
struct snd_sof_dev * sdev = dev_get_drvdata (dev );
149
+ struct hdac_stream * hstream ;
150
+ u32 mask ;
66
151
int ret ;
67
152
68
153
ret = hda_cl_cleanup (sdev -> dev , dmab_bdl , true, sdw_bpt_stream );
@@ -83,6 +168,22 @@ static int hda_sdw_bpt_dma_deprepare(struct device *dev, struct hdac_ext_stream
83
168
snd_hdac_ext_bus_link_clear_stream_id (hlink , stream_tag );
84
169
}
85
170
171
+ if (!sdev -> dspless_mode_selected ) {
172
+ /* Release CHAIN_DMA resources */
173
+ ret = chain_dma_trigger (sdev , hdac_stream (sdw_bpt_stream )-> stream_tag ,
174
+ hdac_stream (sdw_bpt_stream )-> direction ,
175
+ SOF_IPC4_PIPE_RESET );
176
+ if (ret < 0 )
177
+ dev_err (sdev -> dev , "%s: chain_dma_trigger PIPE_RESET failed: %d\n" ,
178
+ __func__ , ret );
179
+
180
+ /* couple host and link DMA */
181
+ hstream = & sdw_bpt_stream -> hstream ;
182
+ mask = BIT (hstream -> index );
183
+
184
+ snd_sof_dsp_update_bits (sdev , HDA_DSP_PP_BAR , SOF_HDA_REG_PP_PPCTL , mask , 0 );
185
+ }
186
+
86
187
return 0 ;
87
188
}
88
189
@@ -95,6 +196,20 @@ static int hda_sdw_bpt_dma_enable(struct device *dev, struct hdac_ext_stream *sd
95
196
if (ret < 0 )
96
197
dev_err (sdev -> dev , "%s: SDW BPT DMA trigger start failed\n" , __func__ );
97
198
199
+ if (!sdev -> dspless_mode_selected ) {
200
+ /* the chain DMA needs to be programmed before the DMAs */
201
+ ret = chain_dma_trigger (sdev , hdac_stream (sdw_bpt_stream )-> stream_tag ,
202
+ hdac_stream (sdw_bpt_stream )-> direction ,
203
+ SOF_IPC4_PIPE_RUNNING );
204
+ if (ret < 0 ) {
205
+ dev_err (sdev -> dev , "%s: chain_dma_trigger failed: %d\n" ,
206
+ __func__ , ret );
207
+ hda_cl_trigger (sdev -> dev , sdw_bpt_stream , SNDRV_PCM_TRIGGER_STOP );
208
+ return ret ;
209
+ }
210
+ snd_hdac_ext_stream_start (sdw_bpt_stream );
211
+ }
212
+
98
213
return ret ;
99
214
}
100
215
@@ -103,6 +218,17 @@ static int hda_sdw_bpt_dma_disable(struct device *dev, struct hdac_ext_stream *s
103
218
struct snd_sof_dev * sdev = dev_get_drvdata (dev );
104
219
int ret ;
105
220
221
+ if (!sdev -> dspless_mode_selected ) {
222
+ snd_hdac_ext_stream_clear (sdw_bpt_stream );
223
+
224
+ ret = chain_dma_trigger (sdev , hdac_stream (sdw_bpt_stream )-> stream_tag ,
225
+ hdac_stream (sdw_bpt_stream )-> direction ,
226
+ SOF_IPC4_PIPE_PAUSED );
227
+ if (ret < 0 )
228
+ dev_err (sdev -> dev , "%s: chain_dma_trigger PIPE_PAUSED failed: %d\n" ,
229
+ __func__ , ret );
230
+ }
231
+
106
232
ret = hda_cl_trigger (sdev -> dev , sdw_bpt_stream , SNDRV_PCM_TRIGGER_STOP );
107
233
if (ret < 0 )
108
234
dev_err (sdev -> dev , "%s: SDW BPT DMA trigger stop failed\n" , __func__ );
0 commit comments