1414#include <sound/hda-mlink.h>
1515#include <sound/hda-sdw-bpt.h>
1616#include <sound/sof.h>
17+ #include <sound/sof/ipc4/header.h>
1718#include "../ops.h"
1819#include "../sof-priv.h"
20+ #include "../ipc4-priv.h"
1921#include "hda.h"
2022
2123#define BPT_FREQUENCY 192000 /* The max rate defined in rate_bits[] hdac_device.c */
2224#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+ }
2391
2492static int hda_sdw_bpt_dma_prepare (struct device * dev , struct hdac_ext_stream * * sdw_bpt_stream ,
2593 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 **
46114 }
47115 * sdw_bpt_stream = bpt_stream ;
48116
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+
49132 if (hdac_stream (bpt_stream )-> direction == SNDRV_PCM_STREAM_PLAYBACK ) {
50133 struct hdac_bus * bus = sof_to_bus (sdev );
51134 struct hdac_ext_link * hlink ;
@@ -63,6 +146,8 @@ static int hda_sdw_bpt_dma_deprepare(struct device *dev, struct hdac_ext_stream
63146 struct snd_dma_buffer * dmab_bdl )
64147{
65148 struct snd_sof_dev * sdev = dev_get_drvdata (dev );
149+ struct hdac_stream * hstream ;
150+ u32 mask ;
66151 int ret ;
67152
68153 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
83168 snd_hdac_ext_bus_link_clear_stream_id (hlink , stream_tag );
84169 }
85170
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+
86187 return 0 ;
87188}
88189
@@ -95,6 +196,20 @@ static int hda_sdw_bpt_dma_enable(struct device *dev, struct hdac_ext_stream *sd
95196 if (ret < 0 )
96197 dev_err (sdev -> dev , "%s: SDW BPT DMA trigger start failed\n" , __func__ );
97198
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+
98213 return ret ;
99214}
100215
@@ -103,6 +218,17 @@ static int hda_sdw_bpt_dma_disable(struct device *dev, struct hdac_ext_stream *s
103218 struct snd_sof_dev * sdev = dev_get_drvdata (dev );
104219 int ret ;
105220
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+
106232 ret = hda_cl_trigger (sdev -> dev , sdw_bpt_stream , SNDRV_PCM_TRIGGER_STOP );
107233 if (ret < 0 )
108234 dev_err (sdev -> dev , "%s: SDW BPT DMA trigger stop failed\n" , __func__ );
0 commit comments