Commit | Line | Data |
---|---|---|
8e8e69d6 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
a40e693c JK |
2 | /* |
3 | * skl-pcm.c -ASoC HDA Platform driver file implementing PCM functionality | |
4 | * | |
5 | * Copyright (C) 2014-2015 Intel Corp | |
6 | * Author: Jeeja KP <jeeja.kp@intel.com> | |
7 | * | |
8 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
9 | * | |
a40e693c | 10 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
a40e693c JK |
11 | */ |
12 | ||
13 | #include <linux/pci.h> | |
14 | #include <linux/pm_runtime.h> | |
fdd85a05 | 15 | #include <linux/delay.h> |
a40e693c JK |
16 | #include <sound/pcm_params.h> |
17 | #include <sound/soc.h> | |
18 | #include "skl.h" | |
b663a8c5 | 19 | #include "skl-topology.h" |
721c3e36 D |
20 | #include "skl-sst-dsp.h" |
21 | #include "skl-sst-ipc.h" | |
a40e693c JK |
22 | |
23 | #define HDA_MONO 1 | |
24 | #define HDA_STEREO 2 | |
8f35bf3f | 25 | #define HDA_QUAD 4 |
3d178713 | 26 | #define HDA_MAX 8 |
a40e693c | 27 | |
8df397ff | 28 | static const struct snd_pcm_hardware azx_pcm_hw = { |
a40e693c JK |
29 | .info = (SNDRV_PCM_INFO_MMAP | |
30 | SNDRV_PCM_INFO_INTERLEAVED | | |
31 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | |
32 | SNDRV_PCM_INFO_MMAP_VALID | | |
33 | SNDRV_PCM_INFO_PAUSE | | |
3637976b | 34 | SNDRV_PCM_INFO_RESUME | |
a40e693c JK |
35 | SNDRV_PCM_INFO_SYNC_START | |
36 | SNDRV_PCM_INFO_HAS_WALL_CLOCK | /* legacy */ | |
37 | SNDRV_PCM_INFO_HAS_LINK_ATIME | | |
38 | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP), | |
06b23d93 JK |
39 | .formats = SNDRV_PCM_FMTBIT_S16_LE | |
40 | SNDRV_PCM_FMTBIT_S32_LE | | |
41 | SNDRV_PCM_FMTBIT_S24_LE, | |
42 | .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | | |
43 | SNDRV_PCM_RATE_8000, | |
44 | .rate_min = 8000, | |
a40e693c | 45 | .rate_max = 48000, |
8f35bf3f | 46 | .channels_min = 1, |
7e12dc87 | 47 | .channels_max = 8, |
a40e693c JK |
48 | .buffer_bytes_max = AZX_MAX_BUF_SIZE, |
49 | .period_bytes_min = 128, | |
50 | .period_bytes_max = AZX_MAX_BUF_SIZE / 2, | |
51 | .periods_min = 2, | |
52 | .periods_max = AZX_MAX_FRAG, | |
53 | .fifo_size = 0, | |
54 | }; | |
55 | ||
56 | static inline | |
57 | struct hdac_ext_stream *get_hdac_ext_stream(struct snd_pcm_substream *substream) | |
58 | { | |
59 | return substream->runtime->private_data; | |
60 | } | |
61 | ||
76f56fae | 62 | static struct hdac_bus *get_bus_ctx(struct snd_pcm_substream *substream) |
a40e693c JK |
63 | { |
64 | struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); | |
65 | struct hdac_stream *hstream = hdac_stream(stream); | |
66 | struct hdac_bus *bus = hstream->bus; | |
76f56fae | 67 | return bus; |
a40e693c JK |
68 | } |
69 | ||
76f56fae | 70 | static int skl_substream_alloc_pages(struct hdac_bus *bus, |
a40e693c JK |
71 | struct snd_pcm_substream *substream, |
72 | size_t size) | |
73 | { | |
74 | struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); | |
75 | ||
76 | hdac_stream(stream)->bufsize = 0; | |
77 | hdac_stream(stream)->period_bytes = 0; | |
78 | hdac_stream(stream)->format_val = 0; | |
79 | ||
80 | return snd_pcm_lib_malloc_pages(substream, size); | |
81 | } | |
82 | ||
83 | static int skl_substream_free_pages(struct hdac_bus *bus, | |
84 | struct snd_pcm_substream *substream) | |
85 | { | |
86 | return snd_pcm_lib_free_pages(substream); | |
87 | } | |
88 | ||
76f56fae | 89 | static void skl_set_pcm_constrains(struct hdac_bus *bus, |
a40e693c JK |
90 | struct snd_pcm_runtime *runtime) |
91 | { | |
92 | snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); | |
93 | ||
94 | /* avoid wrap-around with wall-clock */ | |
95 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, | |
96 | 20, 178000000); | |
97 | } | |
98 | ||
76f56fae | 99 | static enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_bus *bus) |
05057001 | 100 | { |
76f56fae | 101 | if (bus->ppcap) |
05057001 JK |
102 | return HDAC_EXT_STREAM_TYPE_HOST; |
103 | else | |
104 | return HDAC_EXT_STREAM_TYPE_COUPLED; | |
105 | } | |
106 | ||
4557c305 JK |
107 | /* |
108 | * check if the stream opened is marked as ignore_suspend by machine, if so | |
109 | * then enable suspend_active refcount | |
110 | * | |
111 | * The count supend_active does not need lock as it is used in open/close | |
112 | * and suspend context | |
113 | */ | |
114 | static void skl_set_suspend_active(struct snd_pcm_substream *substream, | |
115 | struct snd_soc_dai *dai, bool enable) | |
116 | { | |
76f56fae | 117 | struct hdac_bus *bus = dev_get_drvdata(dai->dev); |
4557c305 | 118 | struct snd_soc_dapm_widget *w; |
bcc2a2dc | 119 | struct skl_dev *skl = bus_to_skl(bus); |
4557c305 JK |
120 | |
121 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | |
122 | w = dai->playback_widget; | |
123 | else | |
124 | w = dai->capture_widget; | |
125 | ||
126 | if (w->ignore_suspend && enable) | |
127 | skl->supend_active++; | |
128 | else if (w->ignore_suspend && !enable) | |
129 | skl->supend_active--; | |
130 | } | |
131 | ||
ad036bde JK |
132 | int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params) |
133 | { | |
76f56fae | 134 | struct hdac_bus *bus = dev_get_drvdata(dev); |
bcc2a2dc | 135 | struct skl_dev *skl = bus_to_skl(bus); |
ad036bde JK |
136 | unsigned int format_val; |
137 | struct hdac_stream *hstream; | |
138 | struct hdac_ext_stream *stream; | |
139 | int err; | |
140 | ||
141 | hstream = snd_hdac_get_stream(bus, params->stream, | |
142 | params->host_dma_id + 1); | |
143 | if (!hstream) | |
144 | return -EINVAL; | |
145 | ||
146 | stream = stream_to_hdac_ext_stream(hstream); | |
76f56fae | 147 | snd_hdac_ext_stream_decouple(bus, stream, true); |
ad036bde JK |
148 | |
149 | format_val = snd_hdac_calc_stream_format(params->s_freq, | |
7f975a38 | 150 | params->ch, params->format, params->host_bps, 0); |
ad036bde JK |
151 | |
152 | dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", | |
153 | format_val, params->s_freq, params->ch, params->format); | |
154 | ||
155 | snd_hdac_stream_reset(hdac_stream(stream)); | |
156 | err = snd_hdac_stream_set_params(hdac_stream(stream), format_val); | |
157 | if (err < 0) | |
158 | return err; | |
159 | ||
d5fcaaba PH |
160 | /* |
161 | * The recommended SDxFMT programming sequence for BXT | |
162 | * platforms is to couple the stream before writing the format | |
163 | */ | |
164 | if (IS_BXT(skl->pci)) { | |
165 | snd_hdac_ext_stream_decouple(bus, stream, false); | |
166 | err = snd_hdac_stream_setup(hdac_stream(stream)); | |
167 | snd_hdac_ext_stream_decouple(bus, stream, true); | |
168 | } else { | |
169 | err = snd_hdac_stream_setup(hdac_stream(stream)); | |
170 | } | |
171 | ||
ad036bde JK |
172 | if (err < 0) |
173 | return err; | |
174 | ||
175 | hdac_stream(stream)->prepared = 1; | |
176 | ||
177 | return 0; | |
178 | } | |
179 | ||
180 | int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params) | |
181 | { | |
76f56fae | 182 | struct hdac_bus *bus = dev_get_drvdata(dev); |
ad036bde JK |
183 | unsigned int format_val; |
184 | struct hdac_stream *hstream; | |
185 | struct hdac_ext_stream *stream; | |
186 | struct hdac_ext_link *link; | |
c899df3e | 187 | unsigned char stream_tag; |
ad036bde JK |
188 | |
189 | hstream = snd_hdac_get_stream(bus, params->stream, | |
190 | params->link_dma_id + 1); | |
191 | if (!hstream) | |
192 | return -EINVAL; | |
193 | ||
194 | stream = stream_to_hdac_ext_stream(hstream); | |
76f56fae | 195 | snd_hdac_ext_stream_decouple(bus, stream, true); |
7f975a38 JK |
196 | format_val = snd_hdac_calc_stream_format(params->s_freq, params->ch, |
197 | params->format, params->link_bps, 0); | |
ad036bde JK |
198 | |
199 | dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", | |
200 | format_val, params->s_freq, params->ch, params->format); | |
201 | ||
202 | snd_hdac_ext_link_stream_reset(stream); | |
203 | ||
204 | snd_hdac_ext_link_stream_setup(stream, format_val); | |
205 | ||
c899df3e RW |
206 | stream_tag = hstream->stream_tag; |
207 | if (stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) { | |
208 | list_for_each_entry(link, &bus->hlink_list, list) { | |
209 | if (link->index == params->link_index) | |
210 | snd_hdac_ext_link_set_stream_id(link, | |
211 | stream_tag); | |
212 | } | |
ad036bde JK |
213 | } |
214 | ||
215 | stream->link_prepared = 1; | |
216 | ||
217 | return 0; | |
218 | } | |
219 | ||
a40e693c JK |
220 | static int skl_pcm_open(struct snd_pcm_substream *substream, |
221 | struct snd_soc_dai *dai) | |
222 | { | |
76f56fae | 223 | struct hdac_bus *bus = dev_get_drvdata(dai->dev); |
a40e693c JK |
224 | struct hdac_ext_stream *stream; |
225 | struct snd_pcm_runtime *runtime = substream->runtime; | |
226 | struct skl_dma_params *dma_params; | |
bcc2a2dc | 227 | struct skl_dev *skl = get_skl_ctx(dai->dev); |
a83e3b4c | 228 | struct skl_module_cfg *mconfig; |
a40e693c JK |
229 | |
230 | dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); | |
a40e693c | 231 | |
76f56fae RU |
232 | stream = snd_hdac_ext_stream_assign(bus, substream, |
233 | skl_get_host_stream_type(bus)); | |
a40e693c JK |
234 | if (stream == NULL) |
235 | return -EBUSY; | |
236 | ||
76f56fae | 237 | skl_set_pcm_constrains(bus, runtime); |
a40e693c JK |
238 | |
239 | /* | |
240 | * disable WALLCLOCK timestamps for capture streams | |
241 | * until we figure out how to handle digital inputs | |
242 | */ | |
243 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { | |
244 | runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_WALL_CLOCK; /* legacy */ | |
245 | runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_LINK_ATIME; | |
246 | } | |
247 | ||
248 | runtime->private_data = stream; | |
249 | ||
250 | dma_params = kzalloc(sizeof(*dma_params), GFP_KERNEL); | |
251 | if (!dma_params) | |
252 | return -ENOMEM; | |
253 | ||
254 | dma_params->stream_tag = hdac_stream(stream)->stream_tag; | |
255 | snd_soc_dai_set_dma_data(dai, substream, dma_params); | |
256 | ||
257 | dev_dbg(dai->dev, "stream tag set in dma params=%d\n", | |
258 | dma_params->stream_tag); | |
4557c305 | 259 | skl_set_suspend_active(substream, dai, true); |
a40e693c JK |
260 | snd_pcm_set_sync(substream); |
261 | ||
a83e3b4c | 262 | mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); |
91ce5497 K |
263 | if (!mconfig) |
264 | return -EINVAL; | |
265 | ||
a83e3b4c VK |
266 | skl_tplg_d0i3_get(skl, mconfig->d0i3_caps); |
267 | ||
a40e693c JK |
268 | return 0; |
269 | } | |
270 | ||
a40e693c JK |
271 | static int skl_pcm_prepare(struct snd_pcm_substream *substream, |
272 | struct snd_soc_dai *dai) | |
273 | { | |
bcc2a2dc | 274 | struct skl_dev *skl = get_skl_ctx(dai->dev); |
2004432f | 275 | struct skl_module_cfg *mconfig; |
74e65192 | 276 | int ret; |
a40e693c JK |
277 | |
278 | dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); | |
a40e693c | 279 | |
2004432f JK |
280 | mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); |
281 | ||
74e65192 PS |
282 | /* |
283 | * In case of XRUN recovery or in the case when the application | |
284 | * calls prepare another time, reset the FW pipe to clean state | |
285 | */ | |
286 | if (mconfig && | |
287 | (substream->runtime->status->state == SNDRV_PCM_STATE_XRUN || | |
288 | mconfig->pipe->state == SKL_PIPE_CREATED || | |
289 | mconfig->pipe->state == SKL_PIPE_PAUSED)) { | |
290 | ||
bcc2a2dc | 291 | ret = skl_reset_pipe(skl, mconfig->pipe); |
74e65192 PS |
292 | |
293 | if (ret < 0) | |
294 | return ret; | |
295 | ||
296 | ret = skl_pcm_host_dma_prepare(dai->dev, | |
297 | mconfig->pipe->p_params); | |
298 | if (ret < 0) | |
299 | return ret; | |
300 | } | |
2004432f | 301 | |
bb704a73 | 302 | return 0; |
a40e693c JK |
303 | } |
304 | ||
305 | static int skl_pcm_hw_params(struct snd_pcm_substream *substream, | |
306 | struct snd_pcm_hw_params *params, | |
307 | struct snd_soc_dai *dai) | |
308 | { | |
76f56fae | 309 | struct hdac_bus *bus = dev_get_drvdata(dai->dev); |
05057001 | 310 | struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); |
a40e693c | 311 | struct snd_pcm_runtime *runtime = substream->runtime; |
b663a8c5 JK |
312 | struct skl_pipe_params p_params = {0}; |
313 | struct skl_module_cfg *m_cfg; | |
05057001 | 314 | int ret, dma_id; |
a40e693c JK |
315 | |
316 | dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); | |
76f56fae | 317 | ret = skl_substream_alloc_pages(bus, substream, |
a40e693c JK |
318 | params_buffer_bytes(params)); |
319 | if (ret < 0) | |
320 | return ret; | |
321 | ||
322 | dev_dbg(dai->dev, "format_val, rate=%d, ch=%d, format=%d\n", | |
323 | runtime->rate, runtime->channels, runtime->format); | |
324 | ||
05057001 JK |
325 | dma_id = hdac_stream(stream)->stream_tag - 1; |
326 | dev_dbg(dai->dev, "dma_id=%d\n", dma_id); | |
327 | ||
b663a8c5 JK |
328 | p_params.s_fmt = snd_pcm_format_width(params_format(params)); |
329 | p_params.ch = params_channels(params); | |
330 | p_params.s_freq = params_rate(params); | |
331 | p_params.host_dma_id = dma_id; | |
332 | p_params.stream = substream->stream; | |
12c3be0e | 333 | p_params.format = params_format(params); |
7f975a38 JK |
334 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
335 | p_params.host_bps = dai->driver->playback.sig_bits; | |
336 | else | |
337 | p_params.host_bps = dai->driver->capture.sig_bits; | |
338 | ||
b663a8c5 JK |
339 | |
340 | m_cfg = skl_tplg_fe_get_cpr_module(dai, p_params.stream); | |
341 | if (m_cfg) | |
342 | skl_tplg_update_pipe_params(dai->dev, m_cfg, &p_params); | |
343 | ||
a40e693c JK |
344 | return 0; |
345 | } | |
346 | ||
347 | static void skl_pcm_close(struct snd_pcm_substream *substream, | |
348 | struct snd_soc_dai *dai) | |
349 | { | |
350 | struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); | |
76f56fae | 351 | struct hdac_bus *bus = dev_get_drvdata(dai->dev); |
a40e693c | 352 | struct skl_dma_params *dma_params = NULL; |
bcc2a2dc | 353 | struct skl_dev *skl = bus_to_skl(bus); |
a83e3b4c | 354 | struct skl_module_cfg *mconfig; |
a40e693c JK |
355 | |
356 | dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); | |
05057001 | 357 | |
76f56fae | 358 | snd_hdac_ext_stream_release(stream, skl_get_host_stream_type(bus)); |
a40e693c JK |
359 | |
360 | dma_params = snd_soc_dai_get_dma_data(dai, substream); | |
361 | /* | |
362 | * now we should set this to NULL as we are freeing by the | |
363 | * dma_params | |
364 | */ | |
365 | snd_soc_dai_set_dma_data(dai, substream, NULL); | |
4557c305 | 366 | skl_set_suspend_active(substream, dai, false); |
a40e693c | 367 | |
721c3e36 D |
368 | /* |
369 | * check if close is for "Reference Pin" and set back the | |
370 | * CGCTL.MISCBDCGE if disabled by driver | |
371 | */ | |
372 | if (!strncmp(dai->name, "Reference Pin", 13) && | |
bcc2a2dc CR |
373 | skl->miscbdcg_disabled) { |
374 | skl->enable_miscbdcge(dai->dev, true); | |
375 | skl->miscbdcg_disabled = false; | |
721c3e36 D |
376 | } |
377 | ||
a83e3b4c | 378 | mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); |
0265ddd7 PB |
379 | if (mconfig) |
380 | skl_tplg_d0i3_put(skl, mconfig->d0i3_caps); | |
a83e3b4c | 381 | |
a40e693c JK |
382 | kfree(dma_params); |
383 | } | |
384 | ||
385 | static int skl_pcm_hw_free(struct snd_pcm_substream *substream, | |
386 | struct snd_soc_dai *dai) | |
387 | { | |
76f56fae | 388 | struct hdac_bus *bus = dev_get_drvdata(dai->dev); |
a40e693c | 389 | struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); |
bcc2a2dc | 390 | struct skl_dev *skl = get_skl_ctx(dai->dev); |
179c2e86 DP |
391 | struct skl_module_cfg *mconfig; |
392 | int ret; | |
a40e693c JK |
393 | |
394 | dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); | |
395 | ||
179c2e86 DP |
396 | mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); |
397 | ||
398 | if (mconfig) { | |
bcc2a2dc | 399 | ret = skl_reset_pipe(skl, mconfig->pipe); |
179c2e86 DP |
400 | if (ret < 0) |
401 | dev_err(dai->dev, "%s:Reset failed ret =%d", | |
402 | __func__, ret); | |
403 | } | |
404 | ||
a40e693c JK |
405 | snd_hdac_stream_cleanup(hdac_stream(stream)); |
406 | hdac_stream(stream)->prepared = 0; | |
407 | ||
76f56fae | 408 | return skl_substream_free_pages(bus, substream); |
a40e693c JK |
409 | } |
410 | ||
b663a8c5 JK |
411 | static int skl_be_hw_params(struct snd_pcm_substream *substream, |
412 | struct snd_pcm_hw_params *params, | |
413 | struct snd_soc_dai *dai) | |
414 | { | |
415 | struct skl_pipe_params p_params = {0}; | |
416 | ||
417 | p_params.s_fmt = snd_pcm_format_width(params_format(params)); | |
418 | p_params.ch = params_channels(params); | |
419 | p_params.s_freq = params_rate(params); | |
420 | p_params.stream = substream->stream; | |
b663a8c5 | 421 | |
4bd073f9 | 422 | return skl_tplg_be_update_params(dai, &p_params); |
b663a8c5 JK |
423 | } |
424 | ||
d1730c3d JK |
425 | static int skl_decoupled_trigger(struct snd_pcm_substream *substream, |
426 | int cmd) | |
427 | { | |
76f56fae | 428 | struct hdac_bus *bus = get_bus_ctx(substream); |
d1730c3d JK |
429 | struct hdac_ext_stream *stream; |
430 | int start; | |
431 | unsigned long cookie; | |
432 | struct hdac_stream *hstr; | |
433 | ||
434 | stream = get_hdac_ext_stream(substream); | |
435 | hstr = hdac_stream(stream); | |
436 | ||
437 | if (!hstr->prepared) | |
438 | return -EPIPE; | |
439 | ||
440 | switch (cmd) { | |
441 | case SNDRV_PCM_TRIGGER_START: | |
442 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | |
443 | case SNDRV_PCM_TRIGGER_RESUME: | |
444 | start = 1; | |
445 | break; | |
446 | ||
447 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | |
448 | case SNDRV_PCM_TRIGGER_SUSPEND: | |
449 | case SNDRV_PCM_TRIGGER_STOP: | |
450 | start = 0; | |
451 | break; | |
452 | ||
453 | default: | |
454 | return -EINVAL; | |
455 | } | |
456 | ||
457 | spin_lock_irqsave(&bus->reg_lock, cookie); | |
458 | ||
459 | if (start) { | |
460 | snd_hdac_stream_start(hdac_stream(stream), true); | |
461 | snd_hdac_stream_timecounter_init(hstr, 0); | |
462 | } else { | |
463 | snd_hdac_stream_stop(hdac_stream(stream)); | |
464 | } | |
465 | ||
466 | spin_unlock_irqrestore(&bus->reg_lock, cookie); | |
467 | ||
468 | return 0; | |
469 | } | |
470 | ||
b663a8c5 JK |
471 | static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, |
472 | struct snd_soc_dai *dai) | |
473 | { | |
bcc2a2dc | 474 | struct skl_dev *skl = get_skl_ctx(dai->dev); |
b663a8c5 | 475 | struct skl_module_cfg *mconfig; |
76f56fae | 476 | struct hdac_bus *bus = get_bus_ctx(substream); |
7e3a17d3 | 477 | struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); |
9a655db0 | 478 | struct snd_soc_dapm_widget *w; |
d1730c3d | 479 | int ret; |
b663a8c5 JK |
480 | |
481 | mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); | |
482 | if (!mconfig) | |
483 | return -EIO; | |
484 | ||
9a655db0 JK |
485 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
486 | w = dai->playback_widget; | |
487 | else | |
488 | w = dai->capture_widget; | |
489 | ||
b663a8c5 | 490 | switch (cmd) { |
7e3a17d3 | 491 | case SNDRV_PCM_TRIGGER_RESUME: |
9a655db0 | 492 | if (!w->ignore_suspend) { |
9a655db0 JK |
493 | /* |
494 | * enable DMA Resume enable bit for the stream, set the | |
495 | * dpib & lpib position to resume before starting the | |
496 | * DMA | |
497 | */ | |
76f56fae | 498 | snd_hdac_ext_stream_drsm_enable(bus, true, |
9a655db0 | 499 | hdac_stream(stream)->index); |
76f56fae | 500 | snd_hdac_ext_stream_set_dpibr(bus, stream, |
a700a1e6 | 501 | stream->lpib); |
9a655db0 JK |
502 | snd_hdac_ext_stream_set_lpib(stream, stream->lpib); |
503 | } | |
e4bfd615 | 504 | /* fall through */ |
748a1d5a | 505 | |
d1730c3d | 506 | case SNDRV_PCM_TRIGGER_START: |
b663a8c5 | 507 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
d1730c3d JK |
508 | /* |
509 | * Start HOST DMA and Start FE Pipe.This is to make sure that | |
510 | * there are no underrun/overrun in the case when the FE | |
511 | * pipeline is started but there is a delay in starting the | |
512 | * DMA channel on the host. | |
513 | */ | |
514 | ret = skl_decoupled_trigger(substream, cmd); | |
515 | if (ret < 0) | |
516 | return ret; | |
bcc2a2dc | 517 | return skl_run_pipe(skl, mconfig->pipe); |
d1730c3d | 518 | break; |
b663a8c5 JK |
519 | |
520 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | |
521 | case SNDRV_PCM_TRIGGER_SUSPEND: | |
d1730c3d JK |
522 | case SNDRV_PCM_TRIGGER_STOP: |
523 | /* | |
524 | * Stop FE Pipe first and stop DMA. This is to make sure that | |
525 | * there are no underrun/overrun in the case if there is a delay | |
526 | * between the two operations. | |
527 | */ | |
bcc2a2dc | 528 | ret = skl_stop_pipe(skl, mconfig->pipe); |
d1730c3d JK |
529 | if (ret < 0) |
530 | return ret; | |
531 | ||
532 | ret = skl_decoupled_trigger(substream, cmd); | |
9a655db0 | 533 | if ((cmd == SNDRV_PCM_TRIGGER_SUSPEND) && !w->ignore_suspend) { |
748a1d5a | 534 | /* save the dpib and lpib positions */ |
76f56fae | 535 | stream->dpib = readl(bus->remap_addr + |
748a1d5a JK |
536 | AZX_REG_VS_SDXDPIB_XBASE + |
537 | (AZX_REG_VS_SDXDPIB_XINTERVAL * | |
538 | hdac_stream(stream)->index)); | |
539 | ||
540 | stream->lpib = snd_hdac_stream_get_pos_lpib( | |
541 | hdac_stream(stream)); | |
76f56fae | 542 | snd_hdac_ext_stream_decouple(bus, stream, false); |
748a1d5a | 543 | } |
d1730c3d | 544 | break; |
b663a8c5 JK |
545 | |
546 | default: | |
d1730c3d | 547 | return -EINVAL; |
b663a8c5 | 548 | } |
d1730c3d JK |
549 | |
550 | return 0; | |
b663a8c5 JK |
551 | } |
552 | ||
76f56fae | 553 | |
05057001 JK |
554 | static int skl_link_hw_params(struct snd_pcm_substream *substream, |
555 | struct snd_pcm_hw_params *params, | |
556 | struct snd_soc_dai *dai) | |
557 | { | |
76f56fae | 558 | struct hdac_bus *bus = dev_get_drvdata(dai->dev); |
05057001 JK |
559 | struct hdac_ext_stream *link_dev; |
560 | struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); | |
05057001 | 561 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
b663a8c5 | 562 | struct skl_pipe_params p_params = {0}; |
12c3be0e | 563 | struct hdac_ext_link *link; |
1011509d | 564 | int stream_tag; |
05057001 | 565 | |
76f56fae | 566 | link_dev = snd_hdac_ext_stream_assign(bus, substream, |
05057001 JK |
567 | HDAC_EXT_STREAM_TYPE_LINK); |
568 | if (!link_dev) | |
569 | return -EBUSY; | |
570 | ||
571 | snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev); | |
572 | ||
76f56fae | 573 | link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name); |
12c3be0e JK |
574 | if (!link) |
575 | return -EINVAL; | |
576 | ||
1011509d JK |
577 | stream_tag = hdac_stream(link_dev)->stream_tag; |
578 | ||
05057001 | 579 | /* set the stream tag in the codec dai dma params */ |
3d178713 RU |
580 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
581 | snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0); | |
582 | else | |
583 | snd_soc_dai_set_tdm_slot(codec_dai, 0, stream_tag, 0, 0); | |
b663a8c5 JK |
584 | |
585 | p_params.s_fmt = snd_pcm_format_width(params_format(params)); | |
586 | p_params.ch = params_channels(params); | |
587 | p_params.s_freq = params_rate(params); | |
588 | p_params.stream = substream->stream; | |
1011509d | 589 | p_params.link_dma_id = stream_tag - 1; |
12c3be0e JK |
590 | p_params.link_index = link->index; |
591 | p_params.format = params_format(params); | |
b663a8c5 | 592 | |
7f975a38 JK |
593 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
594 | p_params.link_bps = codec_dai->driver->playback.sig_bits; | |
595 | else | |
596 | p_params.link_bps = codec_dai->driver->capture.sig_bits; | |
597 | ||
4bd073f9 | 598 | return skl_tplg_be_update_params(dai, &p_params); |
05057001 JK |
599 | } |
600 | ||
601 | static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, | |
602 | struct snd_soc_dai *dai) | |
603 | { | |
bcc2a2dc | 604 | struct skl_dev *skl = get_skl_ctx(dai->dev); |
2004432f | 605 | struct skl_module_cfg *mconfig = NULL; |
05057001 | 606 | |
2004432f JK |
607 | /* In case of XRUN recovery, reset the FW pipe to clean state */ |
608 | mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); | |
7cbfdf87 JK |
609 | if (mconfig && !mconfig->pipe->passthru && |
610 | (substream->runtime->status->state == SNDRV_PCM_STATE_XRUN)) | |
bcc2a2dc | 611 | skl_reset_pipe(skl, mconfig->pipe); |
2004432f | 612 | |
05057001 JK |
613 | return 0; |
614 | } | |
615 | ||
616 | static int skl_link_pcm_trigger(struct snd_pcm_substream *substream, | |
617 | int cmd, struct snd_soc_dai *dai) | |
618 | { | |
619 | struct hdac_ext_stream *link_dev = | |
620 | snd_soc_dai_get_dma_data(dai, substream); | |
76f56fae | 621 | struct hdac_bus *bus = get_bus_ctx(substream); |
920982c9 | 622 | struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); |
05057001 JK |
623 | |
624 | dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd); | |
625 | switch (cmd) { | |
920982c9 | 626 | case SNDRV_PCM_TRIGGER_RESUME: |
05057001 JK |
627 | case SNDRV_PCM_TRIGGER_START: |
628 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | |
05057001 JK |
629 | snd_hdac_ext_link_stream_start(link_dev); |
630 | break; | |
631 | ||
632 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | |
633 | case SNDRV_PCM_TRIGGER_SUSPEND: | |
634 | case SNDRV_PCM_TRIGGER_STOP: | |
635 | snd_hdac_ext_link_stream_clear(link_dev); | |
920982c9 | 636 | if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) |
76f56fae | 637 | snd_hdac_ext_stream_decouple(bus, stream, false); |
05057001 JK |
638 | break; |
639 | ||
640 | default: | |
641 | return -EINVAL; | |
642 | } | |
643 | return 0; | |
644 | } | |
645 | ||
646 | static int skl_link_hw_free(struct snd_pcm_substream *substream, | |
647 | struct snd_soc_dai *dai) | |
648 | { | |
76f56fae | 649 | struct hdac_bus *bus = dev_get_drvdata(dai->dev); |
05057001 JK |
650 | struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); |
651 | struct hdac_ext_stream *link_dev = | |
652 | snd_soc_dai_get_dma_data(dai, substream); | |
653 | struct hdac_ext_link *link; | |
c899df3e | 654 | unsigned char stream_tag; |
05057001 JK |
655 | |
656 | dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); | |
657 | ||
658 | link_dev->link_prepared = 0; | |
659 | ||
76f56fae | 660 | link = snd_hdac_ext_bus_get_link(bus, rtd->codec_dai->component->name); |
05057001 JK |
661 | if (!link) |
662 | return -EINVAL; | |
663 | ||
c899df3e RW |
664 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
665 | stream_tag = hdac_stream(link_dev)->stream_tag; | |
666 | snd_hdac_ext_link_clear_stream_id(link, stream_tag); | |
667 | } | |
668 | ||
05057001 JK |
669 | snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK); |
670 | return 0; | |
671 | } | |
672 | ||
82e2b1e0 | 673 | static const struct snd_soc_dai_ops skl_pcm_dai_ops = { |
a40e693c JK |
674 | .startup = skl_pcm_open, |
675 | .shutdown = skl_pcm_close, | |
676 | .prepare = skl_pcm_prepare, | |
677 | .hw_params = skl_pcm_hw_params, | |
678 | .hw_free = skl_pcm_hw_free, | |
b663a8c5 | 679 | .trigger = skl_pcm_trigger, |
a40e693c JK |
680 | }; |
681 | ||
82e2b1e0 | 682 | static const struct snd_soc_dai_ops skl_dmic_dai_ops = { |
b663a8c5 | 683 | .hw_params = skl_be_hw_params, |
b663a8c5 JK |
684 | }; |
685 | ||
82e2b1e0 | 686 | static const struct snd_soc_dai_ops skl_be_ssp_dai_ops = { |
b663a8c5 | 687 | .hw_params = skl_be_hw_params, |
05057001 JK |
688 | }; |
689 | ||
82e2b1e0 | 690 | static const struct snd_soc_dai_ops skl_link_dai_ops = { |
05057001 JK |
691 | .prepare = skl_link_pcm_prepare, |
692 | .hw_params = skl_link_hw_params, | |
693 | .hw_free = skl_link_hw_free, | |
694 | .trigger = skl_link_pcm_trigger, | |
05057001 JK |
695 | }; |
696 | ||
c3ae22e3 | 697 | static struct snd_soc_dai_driver skl_fe_dai[] = { |
a40e693c JK |
698 | { |
699 | .name = "System Pin", | |
700 | .ops = &skl_pcm_dai_ops, | |
701 | .playback = { | |
702 | .stream_name = "System Playback", | |
703 | .channels_min = HDA_MONO, | |
704 | .channels_max = HDA_STEREO, | |
705 | .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000, | |
dde53bcc SK |
706 | .formats = SNDRV_PCM_FMTBIT_S16_LE | |
707 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, | |
7f975a38 | 708 | .sig_bits = 32, |
a40e693c JK |
709 | }, |
710 | .capture = { | |
711 | .stream_name = "System Capture", | |
712 | .channels_min = HDA_MONO, | |
713 | .channels_max = HDA_STEREO, | |
714 | .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, | |
715 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, | |
7f975a38 | 716 | .sig_bits = 32, |
a40e693c JK |
717 | }, |
718 | }, | |
da3cbb40 NM |
719 | { |
720 | .name = "System Pin2", | |
721 | .ops = &skl_pcm_dai_ops, | |
722 | .playback = { | |
723 | .stream_name = "Headset Playback", | |
724 | .channels_min = HDA_MONO, | |
725 | .channels_max = HDA_STEREO, | |
726 | .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | | |
727 | SNDRV_PCM_RATE_8000, | |
728 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | |
729 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, | |
730 | }, | |
731 | }, | |
732 | { | |
733 | .name = "Echoref Pin", | |
734 | .ops = &skl_pcm_dai_ops, | |
735 | .capture = { | |
736 | .stream_name = "Echoreference Capture", | |
737 | .channels_min = HDA_STEREO, | |
738 | .channels_max = HDA_STEREO, | |
739 | .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | | |
740 | SNDRV_PCM_RATE_8000, | |
741 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | |
742 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, | |
743 | }, | |
744 | }, | |
05057001 JK |
745 | { |
746 | .name = "Reference Pin", | |
747 | .ops = &skl_pcm_dai_ops, | |
748 | .capture = { | |
749 | .stream_name = "Reference Capture", | |
750 | .channels_min = HDA_MONO, | |
8f35bf3f | 751 | .channels_max = HDA_QUAD, |
05057001 JK |
752 | .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, |
753 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, | |
7f975a38 | 754 | .sig_bits = 32, |
05057001 JK |
755 | }, |
756 | }, | |
a40e693c JK |
757 | { |
758 | .name = "Deepbuffer Pin", | |
759 | .ops = &skl_pcm_dai_ops, | |
760 | .playback = { | |
761 | .stream_name = "Deepbuffer Playback", | |
762 | .channels_min = HDA_STEREO, | |
763 | .channels_max = HDA_STEREO, | |
764 | .rates = SNDRV_PCM_RATE_48000, | |
765 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, | |
7f975a38 | 766 | .sig_bits = 32, |
a40e693c JK |
767 | }, |
768 | }, | |
769 | { | |
770 | .name = "LowLatency Pin", | |
771 | .ops = &skl_pcm_dai_ops, | |
772 | .playback = { | |
773 | .stream_name = "Low Latency Playback", | |
774 | .channels_min = HDA_STEREO, | |
775 | .channels_max = HDA_STEREO, | |
776 | .rates = SNDRV_PCM_RATE_48000, | |
777 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, | |
7f975a38 | 778 | .sig_bits = 32, |
a40e693c JK |
779 | }, |
780 | }, | |
8f35bf3f JK |
781 | { |
782 | .name = "DMIC Pin", | |
783 | .ops = &skl_pcm_dai_ops, | |
784 | .capture = { | |
785 | .stream_name = "DMIC Capture", | |
786 | .channels_min = HDA_MONO, | |
787 | .channels_max = HDA_QUAD, | |
788 | .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, | |
789 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, | |
7f975a38 | 790 | .sig_bits = 32, |
8f35bf3f JK |
791 | }, |
792 | }, | |
8cca87c0 SP |
793 | { |
794 | .name = "HDMI1 Pin", | |
795 | .ops = &skl_pcm_dai_ops, | |
796 | .playback = { | |
797 | .stream_name = "HDMI1 Playback", | |
798 | .channels_min = HDA_STEREO, | |
7e12dc87 | 799 | .channels_max = 8, |
8cca87c0 SP |
800 | .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | |
801 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | | |
802 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | | |
803 | SNDRV_PCM_RATE_192000, | |
804 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | | |
805 | SNDRV_PCM_FMTBIT_S32_LE, | |
7f975a38 | 806 | .sig_bits = 32, |
8cca87c0 SP |
807 | }, |
808 | }, | |
809 | { | |
810 | .name = "HDMI2 Pin", | |
811 | .ops = &skl_pcm_dai_ops, | |
812 | .playback = { | |
813 | .stream_name = "HDMI2 Playback", | |
814 | .channels_min = HDA_STEREO, | |
7e12dc87 | 815 | .channels_max = 8, |
8cca87c0 SP |
816 | .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | |
817 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | | |
818 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | | |
819 | SNDRV_PCM_RATE_192000, | |
820 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | | |
821 | SNDRV_PCM_FMTBIT_S32_LE, | |
7f975a38 | 822 | .sig_bits = 32, |
8cca87c0 SP |
823 | }, |
824 | }, | |
825 | { | |
826 | .name = "HDMI3 Pin", | |
827 | .ops = &skl_pcm_dai_ops, | |
828 | .playback = { | |
829 | .stream_name = "HDMI3 Playback", | |
830 | .channels_min = HDA_STEREO, | |
7e12dc87 | 831 | .channels_max = 8, |
8cca87c0 SP |
832 | .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | |
833 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | | |
834 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | | |
835 | SNDRV_PCM_RATE_192000, | |
836 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | | |
837 | SNDRV_PCM_FMTBIT_S32_LE, | |
7f975a38 | 838 | .sig_bits = 32, |
8cca87c0 SP |
839 | }, |
840 | }, | |
c3ae22e3 | 841 | }; |
8f35bf3f | 842 | |
05057001 | 843 | /* BE CPU Dais */ |
c3ae22e3 | 844 | static struct snd_soc_dai_driver skl_platform_dai[] = { |
b663a8c5 JK |
845 | { |
846 | .name = "SSP0 Pin", | |
847 | .ops = &skl_be_ssp_dai_ops, | |
848 | .playback = { | |
849 | .stream_name = "ssp0 Tx", | |
850 | .channels_min = HDA_STEREO, | |
851 | .channels_max = HDA_STEREO, | |
852 | .rates = SNDRV_PCM_RATE_48000, | |
853 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | |
854 | }, | |
855 | .capture = { | |
856 | .stream_name = "ssp0 Rx", | |
857 | .channels_min = HDA_STEREO, | |
858 | .channels_max = HDA_STEREO, | |
859 | .rates = SNDRV_PCM_RATE_48000, | |
860 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | |
861 | }, | |
862 | }, | |
c80fd4da JK |
863 | { |
864 | .name = "SSP1 Pin", | |
865 | .ops = &skl_be_ssp_dai_ops, | |
866 | .playback = { | |
867 | .stream_name = "ssp1 Tx", | |
868 | .channels_min = HDA_STEREO, | |
869 | .channels_max = HDA_STEREO, | |
870 | .rates = SNDRV_PCM_RATE_48000, | |
871 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | |
872 | }, | |
873 | .capture = { | |
874 | .stream_name = "ssp1 Rx", | |
875 | .channels_min = HDA_STEREO, | |
876 | .channels_max = HDA_STEREO, | |
877 | .rates = SNDRV_PCM_RATE_48000, | |
878 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | |
879 | }, | |
880 | }, | |
fcc494af PS |
881 | { |
882 | .name = "SSP2 Pin", | |
883 | .ops = &skl_be_ssp_dai_ops, | |
884 | .playback = { | |
885 | .stream_name = "ssp2 Tx", | |
886 | .channels_min = HDA_STEREO, | |
887 | .channels_max = HDA_STEREO, | |
888 | .rates = SNDRV_PCM_RATE_48000, | |
889 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | |
890 | }, | |
891 | .capture = { | |
892 | .stream_name = "ssp2 Rx", | |
893 | .channels_min = HDA_STEREO, | |
894 | .channels_max = HDA_STEREO, | |
895 | .rates = SNDRV_PCM_RATE_48000, | |
896 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | |
897 | }, | |
898 | }, | |
899 | { | |
900 | .name = "SSP3 Pin", | |
901 | .ops = &skl_be_ssp_dai_ops, | |
902 | .playback = { | |
903 | .stream_name = "ssp3 Tx", | |
904 | .channels_min = HDA_STEREO, | |
905 | .channels_max = HDA_STEREO, | |
906 | .rates = SNDRV_PCM_RATE_48000, | |
907 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | |
908 | }, | |
909 | .capture = { | |
910 | .stream_name = "ssp3 Rx", | |
911 | .channels_min = HDA_STEREO, | |
912 | .channels_max = HDA_STEREO, | |
913 | .rates = SNDRV_PCM_RATE_48000, | |
914 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | |
915 | }, | |
916 | }, | |
917 | { | |
918 | .name = "SSP4 Pin", | |
919 | .ops = &skl_be_ssp_dai_ops, | |
920 | .playback = { | |
921 | .stream_name = "ssp4 Tx", | |
922 | .channels_min = HDA_STEREO, | |
923 | .channels_max = HDA_STEREO, | |
924 | .rates = SNDRV_PCM_RATE_48000, | |
925 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | |
926 | }, | |
927 | .capture = { | |
928 | .stream_name = "ssp4 Rx", | |
929 | .channels_min = HDA_STEREO, | |
930 | .channels_max = HDA_STEREO, | |
931 | .rates = SNDRV_PCM_RATE_48000, | |
932 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | |
933 | }, | |
934 | }, | |
935 | { | |
936 | .name = "SSP5 Pin", | |
937 | .ops = &skl_be_ssp_dai_ops, | |
938 | .playback = { | |
939 | .stream_name = "ssp5 Tx", | |
940 | .channels_min = HDA_STEREO, | |
941 | .channels_max = HDA_STEREO, | |
942 | .rates = SNDRV_PCM_RATE_48000, | |
943 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | |
944 | }, | |
945 | .capture = { | |
946 | .stream_name = "ssp5 Rx", | |
947 | .channels_min = HDA_STEREO, | |
948 | .channels_max = HDA_STEREO, | |
949 | .rates = SNDRV_PCM_RATE_48000, | |
950 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | |
951 | }, | |
952 | }, | |
05057001 | 953 | { |
8cca87c0 | 954 | .name = "iDisp1 Pin", |
05057001 JK |
955 | .ops = &skl_link_dai_ops, |
956 | .playback = { | |
8cca87c0 | 957 | .stream_name = "iDisp1 Tx", |
05057001 | 958 | .channels_min = HDA_STEREO, |
7e12dc87 | 959 | .channels_max = 8, |
05057001 | 960 | .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000, |
8cca87c0 SP |
961 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | |
962 | SNDRV_PCM_FMTBIT_S24_LE, | |
963 | }, | |
964 | }, | |
965 | { | |
966 | .name = "iDisp2 Pin", | |
967 | .ops = &skl_link_dai_ops, | |
968 | .playback = { | |
969 | .stream_name = "iDisp2 Tx", | |
970 | .channels_min = HDA_STEREO, | |
7e12dc87 | 971 | .channels_max = 8, |
8cca87c0 SP |
972 | .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| |
973 | SNDRV_PCM_RATE_48000, | |
974 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | | |
975 | SNDRV_PCM_FMTBIT_S24_LE, | |
976 | }, | |
977 | }, | |
978 | { | |
979 | .name = "iDisp3 Pin", | |
980 | .ops = &skl_link_dai_ops, | |
981 | .playback = { | |
982 | .stream_name = "iDisp3 Tx", | |
983 | .channels_min = HDA_STEREO, | |
7e12dc87 | 984 | .channels_max = 8, |
8cca87c0 SP |
985 | .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| |
986 | SNDRV_PCM_RATE_48000, | |
987 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | | |
988 | SNDRV_PCM_FMTBIT_S24_LE, | |
05057001 JK |
989 | }, |
990 | }, | |
991 | { | |
992 | .name = "DMIC01 Pin", | |
993 | .ops = &skl_dmic_dai_ops, | |
994 | .capture = { | |
995 | .stream_name = "DMIC01 Rx", | |
8f35bf3f JK |
996 | .channels_min = HDA_MONO, |
997 | .channels_max = HDA_QUAD, | |
05057001 JK |
998 | .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, |
999 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, | |
1000 | }, | |
1001 | }, | |
66b48606 PG |
1002 | { |
1003 | .name = "DMIC16k Pin", | |
1004 | .ops = &skl_dmic_dai_ops, | |
1005 | .capture = { | |
1006 | .stream_name = "DMIC16k Rx", | |
1007 | .channels_min = HDA_MONO, | |
1008 | .channels_max = HDA_QUAD, | |
1009 | .rates = SNDRV_PCM_RATE_16000, | |
1010 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | |
1011 | }, | |
1012 | }, | |
05057001 | 1013 | { |
3d178713 | 1014 | .name = "Analog CPU DAI", |
05057001 JK |
1015 | .ops = &skl_link_dai_ops, |
1016 | .playback = { | |
3d178713 RU |
1017 | .stream_name = "Analog CPU Playback", |
1018 | .channels_min = HDA_MONO, | |
1019 | .channels_max = HDA_MAX, | |
1020 | .rates = SNDRV_PCM_RATE_8000_192000, | |
1021 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | | |
1022 | SNDRV_PCM_FMTBIT_S32_LE, | |
05057001 JK |
1023 | }, |
1024 | .capture = { | |
3d178713 RU |
1025 | .stream_name = "Analog CPU Capture", |
1026 | .channels_min = HDA_MONO, | |
1027 | .channels_max = HDA_MAX, | |
1028 | .rates = SNDRV_PCM_RATE_8000_192000, | |
1029 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | | |
1030 | SNDRV_PCM_FMTBIT_S32_LE, | |
1031 | }, | |
1032 | }, | |
1033 | { | |
1034 | .name = "Alt Analog CPU DAI", | |
1035 | .ops = &skl_link_dai_ops, | |
1036 | .playback = { | |
1037 | .stream_name = "Alt Analog CPU Playback", | |
1038 | .channels_min = HDA_MONO, | |
1039 | .channels_max = HDA_MAX, | |
1040 | .rates = SNDRV_PCM_RATE_8000_192000, | |
1041 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | | |
1042 | SNDRV_PCM_FMTBIT_S32_LE, | |
1043 | }, | |
1044 | .capture = { | |
1045 | .stream_name = "Alt Analog CPU Capture", | |
1046 | .channels_min = HDA_MONO, | |
1047 | .channels_max = HDA_MAX, | |
1048 | .rates = SNDRV_PCM_RATE_8000_192000, | |
1049 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | | |
1050 | SNDRV_PCM_FMTBIT_S32_LE, | |
1051 | }, | |
1052 | }, | |
1053 | { | |
1054 | .name = "Digital CPU DAI", | |
1055 | .ops = &skl_link_dai_ops, | |
1056 | .playback = { | |
1057 | .stream_name = "Digital CPU Playback", | |
1058 | .channels_min = HDA_MONO, | |
1059 | .channels_max = HDA_MAX, | |
1060 | .rates = SNDRV_PCM_RATE_8000_192000, | |
1061 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | | |
1062 | SNDRV_PCM_FMTBIT_S32_LE, | |
1063 | }, | |
1064 | .capture = { | |
1065 | .stream_name = "Digital CPU Capture", | |
1066 | .channels_min = HDA_MONO, | |
1067 | .channels_max = HDA_MAX, | |
1068 | .rates = SNDRV_PCM_RATE_8000_192000, | |
1069 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | | |
1070 | SNDRV_PCM_FMTBIT_S32_LE, | |
05057001 JK |
1071 | }, |
1072 | }, | |
a40e693c JK |
1073 | }; |
1074 | ||
c60b613a LG |
1075 | int skl_dai_load(struct snd_soc_component *cmp, int index, |
1076 | struct snd_soc_dai_driver *dai_drv, | |
1077 | struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai) | |
606e21fd | 1078 | { |
c60b613a | 1079 | dai_drv->ops = &skl_pcm_dai_ops; |
606e21fd GS |
1080 | |
1081 | return 0; | |
1082 | } | |
1083 | ||
3507bb5f KM |
1084 | static int skl_platform_soc_open(struct snd_soc_component *component, |
1085 | struct snd_pcm_substream *substream) | |
a40e693c | 1086 | { |
a40e693c JK |
1087 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
1088 | struct snd_soc_dai_link *dai_link = rtd->dai_link; | |
1089 | ||
1090 | dev_dbg(rtd->cpu_dai->dev, "In %s:%s\n", __func__, | |
2bfa8c35 | 1091 | dai_link->cpus->dai_name); |
a40e693c | 1092 | |
a40e693c JK |
1093 | snd_soc_set_runtime_hwparams(substream, &azx_pcm_hw); |
1094 | ||
1095 | return 0; | |
1096 | } | |
1097 | ||
b663a8c5 | 1098 | static int skl_coupled_trigger(struct snd_pcm_substream *substream, |
a40e693c JK |
1099 | int cmd) |
1100 | { | |
76f56fae | 1101 | struct hdac_bus *bus = get_bus_ctx(substream); |
a40e693c JK |
1102 | struct hdac_ext_stream *stream; |
1103 | struct snd_pcm_substream *s; | |
1104 | bool start; | |
1105 | int sbits = 0; | |
1106 | unsigned long cookie; | |
1107 | struct hdac_stream *hstr; | |
1108 | ||
1109 | stream = get_hdac_ext_stream(substream); | |
1110 | hstr = hdac_stream(stream); | |
1111 | ||
1112 | dev_dbg(bus->dev, "In %s cmd=%d\n", __func__, cmd); | |
1113 | ||
1114 | if (!hstr->prepared) | |
1115 | return -EPIPE; | |
1116 | ||
1117 | switch (cmd) { | |
1118 | case SNDRV_PCM_TRIGGER_START: | |
1119 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | |
1120 | case SNDRV_PCM_TRIGGER_RESUME: | |
1121 | start = true; | |
1122 | break; | |
1123 | ||
1124 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | |
1125 | case SNDRV_PCM_TRIGGER_SUSPEND: | |
1126 | case SNDRV_PCM_TRIGGER_STOP: | |
1127 | start = false; | |
1128 | break; | |
1129 | ||
1130 | default: | |
1131 | return -EINVAL; | |
1132 | } | |
1133 | ||
1134 | snd_pcm_group_for_each_entry(s, substream) { | |
1135 | if (s->pcm->card != substream->pcm->card) | |
1136 | continue; | |
1137 | stream = get_hdac_ext_stream(s); | |
1138 | sbits |= 1 << hdac_stream(stream)->index; | |
1139 | snd_pcm_trigger_done(s, substream); | |
1140 | } | |
1141 | ||
1142 | spin_lock_irqsave(&bus->reg_lock, cookie); | |
1143 | ||
1144 | /* first, set SYNC bits of corresponding streams */ | |
1145 | snd_hdac_stream_sync_trigger(hstr, true, sbits, AZX_REG_SSYNC); | |
1146 | ||
1147 | snd_pcm_group_for_each_entry(s, substream) { | |
1148 | if (s->pcm->card != substream->pcm->card) | |
1149 | continue; | |
1150 | stream = get_hdac_ext_stream(s); | |
1151 | if (start) | |
1152 | snd_hdac_stream_start(hdac_stream(stream), true); | |
1153 | else | |
1154 | snd_hdac_stream_stop(hdac_stream(stream)); | |
1155 | } | |
1156 | spin_unlock_irqrestore(&bus->reg_lock, cookie); | |
1157 | ||
1158 | snd_hdac_stream_sync(hstr, start, sbits); | |
1159 | ||
1160 | spin_lock_irqsave(&bus->reg_lock, cookie); | |
1161 | ||
1162 | /* reset SYNC bits */ | |
1163 | snd_hdac_stream_sync_trigger(hstr, false, sbits, AZX_REG_SSYNC); | |
1164 | if (start) | |
1165 | snd_hdac_stream_timecounter_init(hstr, sbits); | |
1166 | spin_unlock_irqrestore(&bus->reg_lock, cookie); | |
1167 | ||
1168 | return 0; | |
1169 | } | |
1170 | ||
3507bb5f KM |
1171 | static int skl_platform_soc_trigger(struct snd_soc_component *component, |
1172 | struct snd_pcm_substream *substream, | |
1173 | int cmd) | |
05057001 | 1174 | { |
76f56fae | 1175 | struct hdac_bus *bus = get_bus_ctx(substream); |
05057001 | 1176 | |
76f56fae | 1177 | if (!bus->ppcap) |
b663a8c5 | 1178 | return skl_coupled_trigger(substream, cmd); |
d1730c3d JK |
1179 | |
1180 | return 0; | |
05057001 JK |
1181 | } |
1182 | ||
3507bb5f KM |
1183 | static snd_pcm_uframes_t skl_platform_soc_pointer( |
1184 | struct snd_soc_component *component, | |
1185 | struct snd_pcm_substream *substream) | |
a40e693c | 1186 | { |
7b96144d | 1187 | struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream); |
76f56fae | 1188 | struct hdac_bus *bus = get_bus_ctx(substream); |
a40e693c | 1189 | unsigned int pos; |
a40e693c | 1190 | |
ca590c1c D |
1191 | /* |
1192 | * Use DPIB for Playback stream as the periodic DMA Position-in- | |
1193 | * Buffer Writes may be scheduled at the same time or later than | |
1194 | * the MSI and does not guarantee to reflect the Position of the | |
1195 | * last buffer that was transferred. Whereas DPIB register in | |
1196 | * HAD space reflects the actual data that is transferred. | |
1197 | * Use the position buffer for capture, as DPIB write gets | |
1198 | * completed earlier than the actual data written to the DDR. | |
fdd85a05 HS |
1199 | * |
1200 | * For capture stream following workaround is required to fix the | |
1201 | * incorrect position reporting. | |
1202 | * | |
1203 | * 1. Wait for 20us before reading the DMA position in buffer once | |
1204 | * the interrupt is generated for stream completion as update happens | |
1205 | * on the HDA frame boundary i.e. 20.833uSec. | |
1206 | * 2. Read DPIB register to flush the DMA position value. This dummy | |
1207 | * read is required to flush DMA position value. | |
1208 | * 3. Read the DMA Position-in-Buffer. This value now will be equal to | |
1209 | * or greater than period boundary. | |
ca590c1c | 1210 | */ |
fdd85a05 HS |
1211 | |
1212 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | |
76f56fae | 1213 | pos = readl(bus->remap_addr + AZX_REG_VS_SDXDPIB_XBASE + |
ca590c1c D |
1214 | (AZX_REG_VS_SDXDPIB_XINTERVAL * |
1215 | hdac_stream(hstream)->index)); | |
fdd85a05 HS |
1216 | } else { |
1217 | udelay(20); | |
76f56fae | 1218 | readl(bus->remap_addr + |
fdd85a05 HS |
1219 | AZX_REG_VS_SDXDPIB_XBASE + |
1220 | (AZX_REG_VS_SDXDPIB_XINTERVAL * | |
1221 | hdac_stream(hstream)->index)); | |
ca590c1c | 1222 | pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream)); |
fdd85a05 | 1223 | } |
a40e693c JK |
1224 | |
1225 | if (pos >= hdac_stream(hstream)->bufsize) | |
1226 | pos = 0; | |
1227 | ||
7b96144d | 1228 | return bytes_to_frames(substream->runtime, pos); |
a40e693c JK |
1229 | } |
1230 | ||
3507bb5f KM |
1231 | static int skl_platform_soc_mmap(struct snd_soc_component *component, |
1232 | struct snd_pcm_substream *substream, | |
1233 | struct vm_area_struct *area) | |
1234 | { | |
1235 | return snd_pcm_lib_default_mmap(substream, area); | |
1236 | } | |
1237 | ||
a40e693c JK |
1238 | static u64 skl_adjust_codec_delay(struct snd_pcm_substream *substream, |
1239 | u64 nsec) | |
1240 | { | |
1241 | struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); | |
1242 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | |
1243 | u64 codec_frames, codec_nsecs; | |
1244 | ||
1245 | if (!codec_dai->driver->ops->delay) | |
1246 | return nsec; | |
1247 | ||
1248 | codec_frames = codec_dai->driver->ops->delay(substream, codec_dai); | |
1249 | codec_nsecs = div_u64(codec_frames * 1000000000LL, | |
1250 | substream->runtime->rate); | |
1251 | ||
1252 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | |
1253 | return nsec + codec_nsecs; | |
1254 | ||
1255 | return (nsec > codec_nsecs) ? nsec - codec_nsecs : 0; | |
1256 | } | |
1257 | ||
3507bb5f KM |
1258 | static int skl_platform_soc_get_time_info( |
1259 | struct snd_soc_component *component, | |
1260 | struct snd_pcm_substream *substream, | |
a40e693c JK |
1261 | struct timespec *system_ts, struct timespec *audio_ts, |
1262 | struct snd_pcm_audio_tstamp_config *audio_tstamp_config, | |
1263 | struct snd_pcm_audio_tstamp_report *audio_tstamp_report) | |
1264 | { | |
1265 | struct hdac_ext_stream *sstream = get_hdac_ext_stream(substream); | |
1266 | struct hdac_stream *hstr = hdac_stream(sstream); | |
1267 | u64 nsec; | |
1268 | ||
1269 | if ((substream->runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_ATIME) && | |
1270 | (audio_tstamp_config->type_requested == SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK)) { | |
1271 | ||
1272 | snd_pcm_gettime(substream->runtime, system_ts); | |
1273 | ||
1274 | nsec = timecounter_read(&hstr->tc); | |
1275 | nsec = div_u64(nsec, 3); /* can be optimized */ | |
1276 | if (audio_tstamp_config->report_delay) | |
1277 | nsec = skl_adjust_codec_delay(substream, nsec); | |
1278 | ||
1279 | *audio_ts = ns_to_timespec(nsec); | |
1280 | ||
1281 | audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK; | |
1282 | audio_tstamp_report->accuracy_report = 1; /* rest of struct is valid */ | |
1283 | audio_tstamp_report->accuracy = 42; /* 24MHzWallClk == 42ns resolution */ | |
1284 | ||
1285 | } else { | |
1286 | audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT; | |
1287 | } | |
1288 | ||
1289 | return 0; | |
1290 | } | |
1291 | ||
3507bb5f KM |
1292 | static void skl_platform_soc_free(struct snd_soc_component *component, |
1293 | struct snd_pcm *pcm) | |
a40e693c JK |
1294 | { |
1295 | snd_pcm_lib_preallocate_free_for_all(pcm); | |
1296 | } | |
1297 | ||
1298 | #define MAX_PREALLOC_SIZE (32 * 1024 * 1024) | |
1299 | ||
3507bb5f KM |
1300 | static int skl_platform_soc_new(struct snd_soc_component *component, |
1301 | struct snd_soc_pcm_runtime *rtd) | |
a40e693c JK |
1302 | { |
1303 | struct snd_soc_dai *dai = rtd->cpu_dai; | |
76f56fae | 1304 | struct hdac_bus *bus = dev_get_drvdata(dai->dev); |
a40e693c JK |
1305 | struct snd_pcm *pcm = rtd->pcm; |
1306 | unsigned int size; | |
bcc2a2dc | 1307 | struct skl_dev *skl = bus_to_skl(bus); |
a40e693c JK |
1308 | |
1309 | if (dai->driver->playback.channels_min || | |
1310 | dai->driver->capture.channels_min) { | |
1311 | /* buffer pre-allocation */ | |
1312 | size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024; | |
1313 | if (size > MAX_PREALLOC_SIZE) | |
1314 | size = MAX_PREALLOC_SIZE; | |
62961dd5 | 1315 | snd_pcm_lib_preallocate_pages_for_all(pcm, |
a40e693c | 1316 | SNDRV_DMA_TYPE_DEV_SG, |
6420c24a | 1317 | &skl->pci->dev, |
a40e693c | 1318 | size, MAX_PREALLOC_SIZE); |
a40e693c JK |
1319 | } |
1320 | ||
62961dd5 | 1321 | return 0; |
a40e693c JK |
1322 | } |
1323 | ||
bcc2a2dc CR |
1324 | static int skl_get_module_info(struct skl_dev *skl, |
1325 | struct skl_module_cfg *mconfig) | |
b26199ea | 1326 | { |
91fe0e70 | 1327 | struct skl_module_inst_id *pin_id; |
9e0784d0 | 1328 | guid_t *uuid_mod, *uuid_tplg; |
91fe0e70 | 1329 | struct skl_module *skl_module; |
b26199ea | 1330 | struct uuid_module *module; |
91fe0e70 | 1331 | int i, ret = -EIO; |
b26199ea | 1332 | |
9e0784d0 | 1333 | uuid_mod = (guid_t *)mconfig->guid; |
b26199ea | 1334 | |
bcc2a2dc CR |
1335 | if (list_empty(&skl->uuid_list)) { |
1336 | dev_err(skl->dev, "Module list is empty\n"); | |
b26199ea JK |
1337 | return -EIO; |
1338 | } | |
1339 | ||
bcc2a2dc | 1340 | list_for_each_entry(module, &skl->uuid_list, list) { |
9e0784d0 | 1341 | if (guid_equal(uuid_mod, &module->uuid)) { |
b26199ea | 1342 | mconfig->id.module_id = module->id; |
f6fa56e2 RB |
1343 | if (mconfig->module) |
1344 | mconfig->module->loadable = module->is_loadable; | |
91fe0e70 JK |
1345 | ret = 0; |
1346 | break; | |
b26199ea JK |
1347 | } |
1348 | } | |
1349 | ||
91fe0e70 JK |
1350 | if (ret) |
1351 | return ret; | |
1352 | ||
1353 | uuid_mod = &module->uuid; | |
1354 | ret = -EIO; | |
1355 | for (i = 0; i < skl->nr_modules; i++) { | |
1356 | skl_module = skl->modules[i]; | |
1357 | uuid_tplg = &skl_module->uuid; | |
9e0784d0 | 1358 | if (guid_equal(uuid_mod, uuid_tplg)) { |
91fe0e70 JK |
1359 | mconfig->module = skl_module; |
1360 | ret = 0; | |
1361 | break; | |
1362 | } | |
1363 | } | |
1364 | if (skl->nr_modules && ret) | |
1365 | return ret; | |
1366 | ||
bcc2a2dc | 1367 | list_for_each_entry(module, &skl->uuid_list, list) { |
91fe0e70 JK |
1368 | for (i = 0; i < MAX_IN_QUEUE; i++) { |
1369 | pin_id = &mconfig->m_in_pin[i].id; | |
9e0784d0 | 1370 | if (guid_equal(&pin_id->mod_uuid, &module->uuid)) |
91fe0e70 JK |
1371 | pin_id->module_id = module->id; |
1372 | } | |
1373 | ||
1374 | for (i = 0; i < MAX_OUT_QUEUE; i++) { | |
1375 | pin_id = &mconfig->m_out_pin[i].id; | |
9e0784d0 | 1376 | if (guid_equal(&pin_id->mod_uuid, &module->uuid)) |
91fe0e70 JK |
1377 | pin_id->module_id = module->id; |
1378 | } | |
1379 | } | |
1380 | ||
1381 | return 0; | |
b26199ea JK |
1382 | } |
1383 | ||
bcc2a2dc | 1384 | static int skl_populate_modules(struct skl_dev *skl) |
64cb1d0a VK |
1385 | { |
1386 | struct skl_pipeline *p; | |
1387 | struct skl_pipe_module *m; | |
1388 | struct snd_soc_dapm_widget *w; | |
1389 | struct skl_module_cfg *mconfig; | |
b26199ea | 1390 | int ret = 0; |
64cb1d0a VK |
1391 | |
1392 | list_for_each_entry(p, &skl->ppl_list, node) { | |
1393 | list_for_each_entry(m, &p->pipe->w_list, node) { | |
64cb1d0a VK |
1394 | w = m->w; |
1395 | mconfig = w->priv; | |
1396 | ||
b26199ea | 1397 | ret = skl_get_module_info(skl, mconfig); |
64cb1d0a | 1398 | if (ret < 0) { |
bcc2a2dc | 1399 | dev_err(skl->dev, |
b26199ea JK |
1400 | "query module info failed\n"); |
1401 | return ret; | |
64cb1d0a | 1402 | } |
f7a9f772 SP |
1403 | |
1404 | skl_tplg_add_moduleid_in_bind_params(skl, w); | |
64cb1d0a VK |
1405 | } |
1406 | } | |
b26199ea | 1407 | |
64cb1d0a VK |
1408 | return ret; |
1409 | } | |
1410 | ||
56b03b4c | 1411 | static int skl_platform_soc_probe(struct snd_soc_component *component) |
b663a8c5 | 1412 | { |
76f56fae | 1413 | struct hdac_bus *bus = dev_get_drvdata(component->dev); |
bcc2a2dc | 1414 | struct skl_dev *skl = bus_to_skl(bus); |
78cdbbda | 1415 | const struct skl_dsp_ops *ops; |
fe3f4442 | 1416 | int ret; |
b663a8c5 | 1417 | |
56b03b4c | 1418 | pm_runtime_get_sync(component->dev); |
76f56fae | 1419 | if (bus->ppcap) { |
56b03b4c | 1420 | skl->component = component; |
5cdf6c09 VK |
1421 | |
1422 | /* init debugfs */ | |
1423 | skl->debugfs = skl_debugfs_init(skl); | |
1424 | ||
76f56fae | 1425 | ret = skl_tplg_init(component, bus); |
fe3f4442 | 1426 | if (ret < 0) { |
56b03b4c | 1427 | dev_err(component->dev, "Failed to init topology!\n"); |
fe3f4442 D |
1428 | return ret; |
1429 | } | |
78cdbbda VK |
1430 | |
1431 | /* load the firmwares, since all is set */ | |
1432 | ops = skl_get_dsp_ops(skl->pci->device); | |
1433 | if (!ops) | |
1434 | return -EIO; | |
1435 | ||
fc9fdd61 SK |
1436 | /* |
1437 | * Disable dynamic clock and power gating during firmware | |
1438 | * and library download | |
1439 | */ | |
bcc2a2dc CR |
1440 | skl->enable_miscbdcge(component->dev, false); |
1441 | skl->clock_power_gating(component->dev, false); | |
d5cc0a1f | 1442 | |
bcc2a2dc CR |
1443 | ret = ops->init_fw(component->dev, skl); |
1444 | skl->enable_miscbdcge(component->dev, true); | |
1445 | skl->clock_power_gating(component->dev, true); | |
78cdbbda | 1446 | if (ret < 0) { |
56b03b4c | 1447 | dev_err(component->dev, "Failed to boot first fw: %d\n", ret); |
78cdbbda VK |
1448 | return ret; |
1449 | } | |
64cb1d0a | 1450 | skl_populate_modules(skl); |
bcc2a2dc | 1451 | skl->update_d0i3c = skl_update_d0i3c; |
9452314d PT |
1452 | |
1453 | if (skl->cfg.astate_cfg != NULL) { | |
bcc2a2dc | 1454 | skl_dsp_set_astate_cfg(skl, |
9452314d PT |
1455 | skl->cfg.astate_cfg->count, |
1456 | skl->cfg.astate_cfg); | |
1457 | } | |
fe3f4442 | 1458 | } |
56b03b4c KM |
1459 | pm_runtime_mark_last_busy(component->dev); |
1460 | pm_runtime_put_autosuspend(component->dev); | |
b663a8c5 JK |
1461 | |
1462 | return 0; | |
1463 | } | |
56b03b4c | 1464 | |
3507bb5f | 1465 | static void skl_platform_soc_remove(struct snd_soc_component *component) |
2e05ddd2 | 1466 | { |
e79986ce | 1467 | struct hdac_bus *bus = dev_get_drvdata(component->dev); |
bcc2a2dc | 1468 | struct skl_dev *skl = bus_to_skl(bus); |
e79986ce AS |
1469 | |
1470 | skl_tplg_exit(component, bus); | |
1471 | ||
1472 | skl_debugfs_exit(skl); | |
2e05ddd2 RS |
1473 | } |
1474 | ||
56b03b4c KM |
1475 | static const struct snd_soc_component_driver skl_component = { |
1476 | .name = "pcm", | |
b663a8c5 | 1477 | .probe = skl_platform_soc_probe, |
3507bb5f KM |
1478 | .remove = skl_platform_soc_remove, |
1479 | .open = skl_platform_soc_open, | |
1480 | .ioctl = snd_soc_pcm_lib_ioctl, | |
1481 | .trigger = skl_platform_soc_trigger, | |
1482 | .pointer = skl_platform_soc_pointer, | |
1483 | .get_time_info = skl_platform_soc_get_time_info, | |
1484 | .mmap = skl_platform_soc_mmap, | |
3507bb5f KM |
1485 | .pcm_construct = skl_platform_soc_new, |
1486 | .pcm_destruct = skl_platform_soc_free, | |
b4ed6b51 | 1487 | .module_get_upon_open = 1, /* increment refcount when a pcm is opened */ |
a40e693c JK |
1488 | }; |
1489 | ||
a40e693c JK |
1490 | int skl_platform_register(struct device *dev) |
1491 | { | |
1492 | int ret; | |
c3ae22e3 GS |
1493 | struct snd_soc_dai_driver *dais; |
1494 | int num_dais = ARRAY_SIZE(skl_platform_dai); | |
76f56fae | 1495 | struct hdac_bus *bus = dev_get_drvdata(dev); |
bcc2a2dc | 1496 | struct skl_dev *skl = bus_to_skl(bus); |
b663a8c5 | 1497 | |
c3ae22e3 GS |
1498 | skl->dais = kmemdup(skl_platform_dai, sizeof(skl_platform_dai), |
1499 | GFP_KERNEL); | |
1500 | if (!skl->dais) { | |
1501 | ret = -ENOMEM; | |
1502 | goto err; | |
1503 | } | |
1504 | ||
1505 | if (!skl->use_tplg_pcm) { | |
1506 | dais = krealloc(skl->dais, sizeof(skl_fe_dai) + | |
1507 | sizeof(skl_platform_dai), GFP_KERNEL); | |
1508 | if (!dais) { | |
1509 | ret = -ENOMEM; | |
1510 | goto err; | |
1511 | } | |
1512 | ||
1513 | skl->dais = dais; | |
1514 | memcpy(&skl->dais[ARRAY_SIZE(skl_platform_dai)], skl_fe_dai, | |
1515 | sizeof(skl_fe_dai)); | |
1516 | num_dais += ARRAY_SIZE(skl_fe_dai); | |
1517 | } | |
1518 | ||
56b03b4c | 1519 | ret = devm_snd_soc_register_component(dev, &skl_component, |
c3ae22e3 | 1520 | skl->dais, num_dais); |
56b03b4c | 1521 | if (ret) |
a40e693c | 1522 | dev_err(dev, "soc component registration failed %d\n", ret); |
c3ae22e3 | 1523 | err: |
a40e693c | 1524 | return ret; |
a40e693c JK |
1525 | } |
1526 | ||
1527 | int skl_platform_unregister(struct device *dev) | |
1528 | { | |
76f56fae | 1529 | struct hdac_bus *bus = dev_get_drvdata(dev); |
bcc2a2dc | 1530 | struct skl_dev *skl = bus_to_skl(bus); |
550b349a | 1531 | struct skl_module_deferred_bind *modules, *tmp; |
b8c722dd JK |
1532 | |
1533 | if (!list_empty(&skl->bind_list)) { | |
550b349a | 1534 | list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) { |
b8c722dd JK |
1535 | list_del(&modules->node); |
1536 | kfree(modules); | |
1537 | } | |
1538 | } | |
1539 | ||
c3ae22e3 GS |
1540 | kfree(skl->dais); |
1541 | ||
a40e693c JK |
1542 | return 0; |
1543 | } |