Commit | Line | Data |
---|---|---|
40433cd3 | 1 | =========== |
469b7bc4 LG |
2 | Dynamic PCM |
3 | =========== | |
4 | ||
40433cd3 TI |
5 | Description |
6 | =========== | |
469b7bc4 LG |
7 | |
8 | Dynamic PCM allows an ALSA PCM device to digitally route its PCM audio to | |
9 | various digital endpoints during the PCM stream runtime. e.g. PCM0 can route | |
10 | digital audio to I2S DAI0, I2S DAI1 or PDM DAI2. This is useful for on SoC DSP | |
11 | drivers that expose several ALSA PCMs and can route to multiple DAIs. | |
12 | ||
13 | The DPCM runtime routing is determined by the ALSA mixer settings in the same | |
14 | way as the analog signal is routed in an ASoC codec driver. DPCM uses a DAPM | |
15 | graph representing the DSP internal audio paths and uses the mixer settings to | |
511d53ac | 16 | determine the path used by each ALSA PCM. |
469b7bc4 LG |
17 | |
18 | DPCM re-uses all the existing component codec, platform and DAI drivers without | |
19 | any modifications. | |
20 | ||
21 | ||
22 | Phone Audio System with SoC based DSP | |
23 | ------------------------------------- | |
24 | ||
25 | Consider the following phone audio subsystem. This will be used in this | |
26 | document for all examples :- | |
40433cd3 TI |
27 | :: |
28 | ||
29 | | Front End PCMs | SoC DSP | Back End DAIs | Audio devices | | |
30 | ||
31 | ************* | |
32 | PCM0 <------------> * * <----DAI0-----> Codec Headset | |
33 | * * | |
34 | PCM1 <------------> * * <----DAI1-----> Codec Speakers | |
35 | * DSP * | |
36 | PCM2 <------------> * * <----DAI2-----> MODEM | |
37 | * * | |
38 | PCM3 <------------> * * <----DAI3-----> BT | |
39 | * * | |
40 | * * <----DAI4-----> DMIC | |
41 | * * | |
42 | * * <----DAI5-----> FM | |
43 | ************* | |
469b7bc4 LG |
44 | |
45 | This diagram shows a simple smart phone audio subsystem. It supports Bluetooth, | |
46 | FM digital radio, Speakers, Headset Jack, digital microphones and cellular | |
47 | modem. This sound card exposes 4 DSP front end (FE) ALSA PCM devices and | |
48 | supports 6 back end (BE) DAIs. Each FE PCM can digitally route audio data to any | |
49 | of the BE DAIs. The FE PCM devices can also route audio to more than 1 BE DAI. | |
50 | ||
51 | ||
52 | ||
53 | Example - DPCM Switching playback from DAI0 to DAI1 | |
54 | --------------------------------------------------- | |
55 | ||
56 | Audio is being played to the Headset. After a while the user removes the headset | |
57 | and audio continues playing on the speakers. | |
58 | ||
59 | Playback on PCM0 to Headset would look like :- | |
40433cd3 TI |
60 | :: |
61 | ||
62 | ************* | |
63 | PCM0 <============> * * <====DAI0=====> Codec Headset | |
64 | * * | |
65 | PCM1 <------------> * * <----DAI1-----> Codec Speakers | |
66 | * DSP * | |
67 | PCM2 <------------> * * <----DAI2-----> MODEM | |
68 | * * | |
69 | PCM3 <------------> * * <----DAI3-----> BT | |
70 | * * | |
71 | * * <----DAI4-----> DMIC | |
72 | * * | |
73 | * * <----DAI5-----> FM | |
74 | ************* | |
469b7bc4 LG |
75 | |
76 | The headset is removed from the jack by user so the speakers must now be used :- | |
40433cd3 TI |
77 | :: |
78 | ||
79 | ************* | |
80 | PCM0 <============> * * <----DAI0-----> Codec Headset | |
81 | * * | |
82 | PCM1 <------------> * * <====DAI1=====> Codec Speakers | |
83 | * DSP * | |
84 | PCM2 <------------> * * <----DAI2-----> MODEM | |
85 | * * | |
86 | PCM3 <------------> * * <----DAI3-----> BT | |
87 | * * | |
88 | * * <----DAI4-----> DMIC | |
89 | * * | |
90 | * * <----DAI5-----> FM | |
91 | ************* | |
469b7bc4 LG |
92 | |
93 | The audio driver processes this as follows :- | |
94 | ||
40433cd3 | 95 | 1. Machine driver receives Jack removal event. |
469b7bc4 | 96 | |
40433cd3 | 97 | 2. Machine driver OR audio HAL disables the Headset path. |
469b7bc4 | 98 | |
40433cd3 TI |
99 | 3. DPCM runs the PCM trigger(stop), hw_free(), shutdown() operations on DAI0 |
100 | for headset since the path is now disabled. | |
469b7bc4 | 101 | |
40433cd3 | 102 | 4. Machine driver or audio HAL enables the speaker path. |
469b7bc4 | 103 | |
511d53ac | 104 | 5. DPCM runs the PCM ops for startup(), hw_params(), prepare() and |
40433cd3 | 105 | trigger(start) for DAI1 Speakers since the path is enabled. |
469b7bc4 LG |
106 | |
107 | In this example, the machine driver or userspace audio HAL can alter the routing | |
108 | and then DPCM will take care of managing the DAI PCM operations to either bring | |
109 | the link up or down. Audio playback does not stop during this transition. | |
110 | ||
111 | ||
112 | ||
113 | DPCM machine driver | |
114 | =================== | |
115 | ||
116 | The DPCM enabled ASoC machine driver is similar to normal machine drivers | |
117 | except that we also have to :- | |
118 | ||
40433cd3 | 119 | 1. Define the FE and BE DAI links. |
469b7bc4 | 120 | |
40433cd3 | 121 | 2. Define any FE/BE PCM operations. |
469b7bc4 | 122 | |
40433cd3 | 123 | 3. Define widget graph connections. |
469b7bc4 LG |
124 | |
125 | ||
40433cd3 TI |
126 | FE and BE DAI links |
127 | ------------------- | |
128 | :: | |
469b7bc4 | 129 | |
40433cd3 TI |
130 | | Front End PCMs | SoC DSP | Back End DAIs | Audio devices | |
131 | ||
132 | ************* | |
133 | PCM0 <------------> * * <----DAI0-----> Codec Headset | |
134 | * * | |
135 | PCM1 <------------> * * <----DAI1-----> Codec Speakers | |
136 | * DSP * | |
137 | PCM2 <------------> * * <----DAI2-----> MODEM | |
138 | * * | |
139 | PCM3 <------------> * * <----DAI3-----> BT | |
140 | * * | |
141 | * * <----DAI4-----> DMIC | |
142 | * * | |
143 | * * <----DAI5-----> FM | |
144 | ************* | |
469b7bc4 LG |
145 | |
146 | For the example above we have to define 4 FE DAI links and 6 BE DAI links. The | |
147 | FE DAI links are defined as follows :- | |
40433cd3 | 148 | :: |
469b7bc4 | 149 | |
40433cd3 | 150 | static struct snd_soc_dai_link machine_dais[] = { |
469b7bc4 LG |
151 | { |
152 | .name = "PCM0 System", | |
153 | .stream_name = "System Playback", | |
154 | .cpu_dai_name = "System Pin", | |
155 | .platform_name = "dsp-audio", | |
156 | .codec_name = "snd-soc-dummy", | |
157 | .codec_dai_name = "snd-soc-dummy-dai", | |
158 | .dynamic = 1, | |
159 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | |
160 | .dpcm_playback = 1, | |
161 | }, | |
162 | .....< other FE and BE DAI links here > | |
40433cd3 | 163 | }; |
469b7bc4 LG |
164 | |
165 | This FE DAI link is pretty similar to a regular DAI link except that we also | |
40433cd3 TI |
166 | set the DAI link to a DPCM FE with the ``dynamic = 1``. The supported FE stream |
167 | directions should also be set with the ``dpcm_playback`` and ``dpcm_capture`` | |
469b7bc4 LG |
168 | flags. There is also an option to specify the ordering of the trigger call for |
169 | each FE. This allows the ASoC core to trigger the DSP before or after the other | |
170 | components (as some DSPs have strong requirements for the ordering DAI/DSP | |
171 | start and stop sequences). | |
172 | ||
173 | The FE DAI above sets the codec and code DAIs to dummy devices since the BE is | |
174 | dynamic and will change depending on runtime config. | |
175 | ||
176 | The BE DAIs are configured as follows :- | |
40433cd3 | 177 | :: |
469b7bc4 | 178 | |
40433cd3 | 179 | static struct snd_soc_dai_link machine_dais[] = { |
469b7bc4 LG |
180 | .....< FE DAI links here > |
181 | { | |
182 | .name = "Codec Headset", | |
183 | .cpu_dai_name = "ssp-dai.0", | |
184 | .platform_name = "snd-soc-dummy", | |
185 | .no_pcm = 1, | |
186 | .codec_name = "rt5640.0-001c", | |
187 | .codec_dai_name = "rt5640-aif1", | |
188 | .ignore_suspend = 1, | |
189 | .ignore_pmdown_time = 1, | |
190 | .be_hw_params_fixup = hswult_ssp0_fixup, | |
191 | .ops = &haswell_ops, | |
192 | .dpcm_playback = 1, | |
193 | .dpcm_capture = 1, | |
194 | }, | |
195 | .....< other BE DAI links here > | |
40433cd3 | 196 | }; |
469b7bc4 LG |
197 | |
198 | This BE DAI link connects DAI0 to the codec (in this case RT5460 AIF1). It sets | |
40433cd3 TI |
199 | the ``no_pcm`` flag to mark it has a BE and sets flags for supported stream |
200 | directions using ``dpcm_playback`` and ``dpcm_capture`` above. | |
469b7bc4 | 201 | |
b327d25c | 202 | The BE has also flags set for ignoring suspend and PM down time. This allows |
469b7bc4 LG |
203 | the BE to work in a hostless mode where the host CPU is not transferring data |
204 | like a BT phone call :- | |
40433cd3 TI |
205 | :: |
206 | ||
207 | ************* | |
208 | PCM0 <------------> * * <----DAI0-----> Codec Headset | |
209 | * * | |
210 | PCM1 <------------> * * <----DAI1-----> Codec Speakers | |
211 | * DSP * | |
212 | PCM2 <------------> * * <====DAI2=====> MODEM | |
213 | * * | |
214 | PCM3 <------------> * * <====DAI3=====> BT | |
215 | * * | |
216 | * * <----DAI4-----> DMIC | |
217 | * * | |
218 | * * <----DAI5-----> FM | |
219 | ************* | |
469b7bc4 | 220 | |
806654a9 | 221 | This allows the host CPU to sleep while the DSP, MODEM DAI and the BT DAI are |
469b7bc4 LG |
222 | still in operation. |
223 | ||
511d53ac | 224 | A BE DAI link can also set the codec to a dummy device if the codec is a device |
469b7bc4 LG |
225 | that is managed externally. |
226 | ||
227 | Likewise a BE DAI can also set a dummy cpu DAI if the CPU DAI is managed by the | |
228 | DSP firmware. | |
229 | ||
230 | ||
40433cd3 TI |
231 | FE/BE PCM operations |
232 | -------------------- | |
469b7bc4 | 233 | |
40433cd3 | 234 | The BE above also exports some PCM operations and a ``fixup`` callback. The fixup |
469b7bc4 LG |
235 | callback is used by the machine driver to (re)configure the DAI based upon the |
236 | FE hw params. i.e. the DSP may perform SRC or ASRC from the FE to BE. | |
237 | ||
238 | e.g. DSP converts all FE hw params to run at fixed rate of 48k, 16bit, stereo for | |
239 | DAI0. This means all FE hw_params have to be fixed in the machine driver for | |
240 | DAI0 so that the DAI is running at desired configuration regardless of the FE | |
241 | configuration. | |
40433cd3 | 242 | :: |
469b7bc4 | 243 | |
40433cd3 | 244 | static int dai0_fixup(struct snd_soc_pcm_runtime *rtd, |
469b7bc4 | 245 | struct snd_pcm_hw_params *params) |
40433cd3 | 246 | { |
469b7bc4 LG |
247 | struct snd_interval *rate = hw_param_interval(params, |
248 | SNDRV_PCM_HW_PARAM_RATE); | |
249 | struct snd_interval *channels = hw_param_interval(params, | |
250 | SNDRV_PCM_HW_PARAM_CHANNELS); | |
251 | ||
511d53ac | 252 | /* The DSP will convert the FE rate to 48k, stereo */ |
469b7bc4 LG |
253 | rate->min = rate->max = 48000; |
254 | channels->min = channels->max = 2; | |
255 | ||
256 | /* set DAI0 to 16 bit */ | |
533a9274 | 257 | params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); |
469b7bc4 | 258 | return 0; |
40433cd3 | 259 | } |
469b7bc4 LG |
260 | |
261 | The other PCM operation are the same as for regular DAI links. Use as necessary. | |
262 | ||
263 | ||
40433cd3 TI |
264 | Widget graph connections |
265 | ------------------------ | |
469b7bc4 LG |
266 | |
267 | The BE DAI links will normally be connected to the graph at initialisation time | |
268 | by the ASoC DAPM core. However, if the BE codec or BE DAI is a dummy then this | |
269 | has to be set explicitly in the driver :- | |
40433cd3 | 270 | :: |
469b7bc4 | 271 | |
40433cd3 TI |
272 | /* BE for codec Headset - DAI0 is dummy and managed by DSP FW */ |
273 | {"DAI0 CODEC IN", NULL, "AIF1 Capture"}, | |
274 | {"AIF1 Playback", NULL, "DAI0 CODEC OUT"}, | |
469b7bc4 LG |
275 | |
276 | ||
277 | Writing a DPCM DSP driver | |
278 | ========================= | |
279 | ||
280 | The DPCM DSP driver looks much like a standard platform class ASoC driver | |
281 | combined with elements from a codec class driver. A DSP platform driver must | |
282 | implement :- | |
283 | ||
40433cd3 | 284 | 1. Front End PCM DAIs - i.e. struct snd_soc_dai_driver. |
469b7bc4 | 285 | |
40433cd3 | 286 | 2. DAPM graph showing DSP audio routing from FE DAIs to BEs. |
469b7bc4 | 287 | |
40433cd3 | 288 | 3. DAPM widgets from DSP graph. |
469b7bc4 | 289 | |
40433cd3 | 290 | 4. Mixers for gains, routing, etc. |
469b7bc4 | 291 | |
40433cd3 | 292 | 5. DMA configuration. |
469b7bc4 | 293 | |
40433cd3 | 294 | 6. BE AIF widgets. |
469b7bc4 LG |
295 | |
296 | Items 6 is important for routing the audio outside of the DSP. AIF need to be | |
297 | defined for each BE and each stream direction. e.g for BE DAI0 above we would | |
298 | have :- | |
40433cd3 | 299 | :: |
469b7bc4 | 300 | |
40433cd3 TI |
301 | SND_SOC_DAPM_AIF_IN("DAI0 RX", NULL, 0, SND_SOC_NOPM, 0, 0), |
302 | SND_SOC_DAPM_AIF_OUT("DAI0 TX", NULL, 0, SND_SOC_NOPM, 0, 0), | |
469b7bc4 LG |
303 | |
304 | The BE AIF are used to connect the DSP graph to the graphs for the other | |
305 | component drivers (e.g. codec graph). | |
306 | ||
307 | ||
308 | Hostless PCM streams | |
309 | ==================== | |
310 | ||
311 | A hostless PCM stream is a stream that is not routed through the host CPU. An | |
312 | example of this would be a phone call from handset to modem. | |
40433cd3 TI |
313 | :: |
314 | ||
315 | ************* | |
316 | PCM0 <------------> * * <----DAI0-----> Codec Headset | |
317 | * * | |
318 | PCM1 <------------> * * <====DAI1=====> Codec Speakers/Mic | |
319 | * DSP * | |
320 | PCM2 <------------> * * <====DAI2=====> MODEM | |
321 | * * | |
322 | PCM3 <------------> * * <----DAI3-----> BT | |
323 | * * | |
324 | * * <----DAI4-----> DMIC | |
325 | * * | |
326 | * * <----DAI5-----> FM | |
327 | ************* | |
469b7bc4 LG |
328 | |
329 | In this case the PCM data is routed via the DSP. The host CPU in this use case | |
330 | is only used for control and can sleep during the runtime of the stream. | |
331 | ||
332 | The host can control the hostless link either by :- | |
333 | ||
40433cd3 | 334 | 1. Configuring the link as a CODEC <-> CODEC style link. In this case the link |
469b7bc4 LG |
335 | is enabled or disabled by the state of the DAPM graph. This usually means |
336 | there is a mixer control that can be used to connect or disconnect the path | |
337 | between both DAIs. | |
338 | ||
40433cd3 | 339 | 2. Hostless FE. This FE has a virtual connection to the BE DAI links on the DAPM |
b327d25c | 340 | graph. Control is then carried out by the FE as regular PCM operations. |
469b7bc4 LG |
341 | This method gives more control over the DAI links, but requires much more |
342 | userspace code to control the link. Its recommended to use CODEC<->CODEC | |
343 | unless your HW needs more fine grained sequencing of the PCM ops. | |
344 | ||
345 | ||
346 | CODEC <-> CODEC link | |
347 | -------------------- | |
348 | ||
349 | This DAI link is enabled when DAPM detects a valid path within the DAPM graph. | |
350 | The machine driver sets some additional parameters to the DAI link i.e. | |
40433cd3 | 351 | :: |
469b7bc4 | 352 | |
40433cd3 | 353 | static const struct snd_soc_pcm_stream dai_params = { |
469b7bc4 LG |
354 | .formats = SNDRV_PCM_FMTBIT_S32_LE, |
355 | .rate_min = 8000, | |
356 | .rate_max = 8000, | |
357 | .channels_min = 2, | |
358 | .channels_max = 2, | |
40433cd3 | 359 | }; |
469b7bc4 | 360 | |
40433cd3 | 361 | static struct snd_soc_dai_link dais[] = { |
469b7bc4 LG |
362 | < ... more DAI links above ... > |
363 | { | |
364 | .name = "MODEM", | |
365 | .stream_name = "MODEM", | |
366 | .cpu_dai_name = "dai2", | |
367 | .codec_dai_name = "modem-aif1", | |
368 | .codec_name = "modem", | |
369 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | |
370 | | SND_SOC_DAIFMT_CBM_CFM, | |
371 | .params = &dai_params, | |
372 | } | |
373 | < ... more DAI links here ... > | |
374 | ||
375 | These parameters are used to configure the DAI hw_params() when DAPM detects a | |
376 | valid path and then calls the PCM operations to start the link. DAPM will also | |
377 | call the appropriate PCM operations to disable the DAI when the path is no | |
378 | longer valid. | |
379 | ||
380 | ||
381 | Hostless FE | |
382 | ----------- | |
383 | ||
384 | The DAI link(s) are enabled by a FE that does not read or write any PCM data. | |
385 | This means creating a new FE that is connected with a virtual path to both | |
386 | DAI links. The DAI links will be started when the FE PCM is started and stopped | |
387 | when the FE PCM is stopped. Note that the FE PCM cannot read or write data in | |
388 | this configuration. |