1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
3 // This file is provided under a dual BSD/GPLv2 license. When using or
4 // redistributing this file, you may do so under either license.
6 // Copyright(c) 2018 Intel Corporation
8 // Authors: Keyon Jie <yang.jie@linux.intel.com>
11 #include <sound/pcm_params.h>
12 #include <sound/hdaudio_ext.h>
13 #include <sound/hda-mlink.h>
14 #include <sound/hda_register.h>
15 #include <sound/intel-nhlt.h>
16 #include <sound/sof/ipc4/header.h>
17 #include <uapi/sound/sof/header.h>
18 #include "../ipc4-priv.h"
19 #include "../ipc4-topology.h"
20 #include "../sof-priv.h"
21 #include "../sof-audio.h"
25 * The default method is to fetch NHLT from BIOS. With this parameter set
26 * it is possible to override that with NHLT in the SOF topology manifest.
28 static bool hda_use_tplg_nhlt
;
29 module_param_named(sof_use_tplg_nhlt
, hda_use_tplg_nhlt
, bool, 0444);
30 MODULE_PARM_DESC(sof_use_tplg_nhlt
, "SOF topology nhlt override");
32 int hda_dai_config(struct snd_soc_dapm_widget
*w
, unsigned int flags
,
33 struct snd_sof_dai_config_data
*data
)
35 struct snd_sof_widget
*swidget
= w
->dobj
.private;
36 const struct sof_ipc_tplg_ops
*tplg_ops
;
37 struct snd_sof_dev
*sdev
;
43 sdev
= widget_to_sdev(w
);
44 tplg_ops
= sof_ipc_get_ops(sdev
, tplg
);
46 if (tplg_ops
&& tplg_ops
->dai_config
) {
47 ret
= tplg_ops
->dai_config(sdev
, swidget
, flags
, data
);
49 dev_err(sdev
->dev
, "DAI config with flags %x failed for widget %s\n",
57 EXPORT_SYMBOL_NS(hda_dai_config
, "SND_SOC_SOF_INTEL_HDA_COMMON");
59 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
61 static struct snd_sof_dev
*dai_to_sdev(struct snd_pcm_substream
*substream
,
62 struct snd_soc_dai
*cpu_dai
)
64 struct snd_soc_dapm_widget
*w
= snd_soc_dai_get_widget(cpu_dai
, substream
->stream
);
66 return widget_to_sdev(w
);
69 static const struct hda_dai_widget_dma_ops
*
70 hda_dai_get_ops(struct snd_pcm_substream
*substream
, struct snd_soc_dai
*cpu_dai
)
72 struct snd_soc_dapm_widget
*w
= snd_soc_dai_get_widget(cpu_dai
, substream
->stream
);
73 struct snd_sof_widget
*swidget
= w
->dobj
.private;
74 struct snd_sof_dev
*sdev
;
75 struct snd_sof_dai
*sdai
;
77 sdev
= widget_to_sdev(w
);
80 dev_err(sdev
->dev
, "%s: swidget is NULL\n", __func__
);
84 if (sdev
->dspless_mode_selected
)
85 return hda_select_dai_widget_ops(sdev
, swidget
);
87 sdai
= swidget
->private;
89 /* select and set the DAI widget ops if not set already */
90 if (!sdai
->platform_private
) {
91 const struct hda_dai_widget_dma_ops
*ops
=
92 hda_select_dai_widget_ops(sdev
, swidget
);
96 /* check if mandatory ops are set */
97 if (!ops
|| !ops
->get_hext_stream
)
100 sdai
->platform_private
= ops
;
103 return sdai
->platform_private
;
106 int hda_link_dma_cleanup(struct snd_pcm_substream
*substream
, struct hdac_ext_stream
*hext_stream
,
107 struct snd_soc_dai
*cpu_dai
)
109 const struct hda_dai_widget_dma_ops
*ops
= hda_dai_get_ops(substream
, cpu_dai
);
110 struct sof_intel_hda_stream
*hda_stream
;
111 struct hdac_ext_link
*hlink
;
112 struct snd_sof_dev
*sdev
;
116 dev_err(cpu_dai
->dev
, "DAI widget ops not set\n");
120 sdev
= dai_to_sdev(substream
, cpu_dai
);
122 hlink
= ops
->get_hlink(sdev
, substream
);
126 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
127 stream_tag
= hdac_stream(hext_stream
)->stream_tag
;
128 snd_hdac_ext_bus_link_clear_stream_id(hlink
, stream_tag
);
131 if (ops
->release_hext_stream
)
132 ops
->release_hext_stream(sdev
, cpu_dai
, substream
);
134 hext_stream
->link_prepared
= 0;
136 /* free the host DMA channel reserved by hostless streams */
137 hda_stream
= hstream_to_sof_hda_stream(hext_stream
);
138 hda_stream
->host_reserved
= 0;
143 static int hda_link_dma_hw_params(struct snd_pcm_substream
*substream
,
144 struct snd_pcm_hw_params
*params
, struct snd_soc_dai
*cpu_dai
)
146 const struct hda_dai_widget_dma_ops
*ops
= hda_dai_get_ops(substream
, cpu_dai
);
147 struct hdac_ext_stream
*hext_stream
;
148 struct hdac_stream
*hstream
;
149 struct hdac_ext_link
*hlink
;
150 struct snd_sof_dev
*sdev
;
154 dev_err(cpu_dai
->dev
, "DAI widget ops not set\n");
158 sdev
= dai_to_sdev(substream
, cpu_dai
);
160 hlink
= ops
->get_hlink(sdev
, substream
);
164 hext_stream
= ops
->get_hext_stream(sdev
, cpu_dai
, substream
);
167 if (ops
->assign_hext_stream
)
168 hext_stream
= ops
->assign_hext_stream(sdev
, cpu_dai
, substream
);
174 hstream
= &hext_stream
->hstream
;
175 stream_tag
= hstream
->stream_tag
;
177 if (hext_stream
->hstream
.direction
== SNDRV_PCM_STREAM_PLAYBACK
)
178 snd_hdac_ext_bus_link_set_stream_id(hlink
, stream_tag
);
180 /* set the hdac_stream in the codec dai */
181 if (ops
->codec_dai_set_stream
)
182 ops
->codec_dai_set_stream(sdev
, substream
, hstream
);
184 if (ops
->reset_hext_stream
)
185 ops
->reset_hext_stream(sdev
, hext_stream
);
187 if (ops
->calc_stream_format
&& ops
->setup_hext_stream
) {
188 unsigned int format_val
= ops
->calc_stream_format(sdev
, substream
, params
);
190 ops
->setup_hext_stream(sdev
, hext_stream
, format_val
);
193 hext_stream
->link_prepared
= 1;
198 static int __maybe_unused
hda_dai_hw_free(struct snd_pcm_substream
*substream
,
199 struct snd_soc_dai
*cpu_dai
)
201 const struct hda_dai_widget_dma_ops
*ops
= hda_dai_get_ops(substream
, cpu_dai
);
202 struct hdac_ext_stream
*hext_stream
;
203 struct snd_sof_dev
*sdev
= dai_to_sdev(substream
, cpu_dai
);
206 dev_err(cpu_dai
->dev
, "DAI widget ops not set\n");
210 hext_stream
= ops
->get_hext_stream(sdev
, cpu_dai
, substream
);
214 return hda_link_dma_cleanup(substream
, hext_stream
, cpu_dai
);
217 static int __maybe_unused
hda_dai_hw_params_data(struct snd_pcm_substream
*substream
,
218 struct snd_pcm_hw_params
*params
,
219 struct snd_soc_dai
*dai
,
220 struct snd_sof_dai_config_data
*data
,
223 struct snd_soc_dapm_widget
*w
= snd_soc_dai_get_widget(dai
, substream
->stream
);
224 const struct hda_dai_widget_dma_ops
*ops
= hda_dai_get_ops(substream
, dai
);
225 struct hdac_ext_stream
*hext_stream
;
226 struct snd_sof_dev
*sdev
= widget_to_sdev(w
);
230 dev_err(sdev
->dev
, "DAI widget ops not set\n");
234 hext_stream
= ops
->get_hext_stream(sdev
, dai
, substream
);
235 if (hext_stream
&& hext_stream
->link_prepared
)
238 ret
= hda_link_dma_hw_params(substream
, params
, dai
);
242 hext_stream
= ops
->get_hext_stream(sdev
, dai
, substream
);
244 flags
|= SOF_DAI_CONFIG_FLAGS_2_STEP_STOP
<< SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT
;
245 data
->dai_data
= hdac_stream(hext_stream
)->stream_tag
- 1;
247 return hda_dai_config(w
, flags
, data
);
250 static int __maybe_unused
hda_dai_hw_params(struct snd_pcm_substream
*substream
,
251 struct snd_pcm_hw_params
*params
,
252 struct snd_soc_dai
*dai
)
254 struct snd_sof_dai_config_data data
= { 0 };
255 unsigned int flags
= SOF_DAI_CONFIG_FLAGS_HW_PARAMS
;
257 return hda_dai_hw_params_data(substream
, params
, dai
, &data
, flags
);
261 * In contrast to IPC3, the dai trigger in IPC4 mixes pipeline state changes
262 * (over IPC channel) and DMA state change (direct host register changes).
264 static int __maybe_unused
hda_dai_trigger(struct snd_pcm_substream
*substream
, int cmd
,
265 struct snd_soc_dai
*dai
)
267 const struct hda_dai_widget_dma_ops
*ops
= hda_dai_get_ops(substream
, dai
);
268 struct hdac_ext_stream
*hext_stream
;
269 struct snd_sof_dev
*sdev
;
273 dev_err(dai
->dev
, "DAI widget ops not set\n");
277 dev_dbg(dai
->dev
, "cmd=%d dai %s direction %d\n", cmd
,
278 dai
->name
, substream
->stream
);
280 sdev
= dai_to_sdev(substream
, dai
);
282 hext_stream
= ops
->get_hext_stream(sdev
, dai
, substream
);
286 if (ops
->pre_trigger
) {
287 ret
= ops
->pre_trigger(sdev
, dai
, substream
, cmd
);
293 ret
= ops
->trigger(sdev
, dai
, substream
, cmd
);
298 if (ops
->post_trigger
) {
299 ret
= ops
->post_trigger(sdev
, dai
, substream
, cmd
);
305 case SNDRV_PCM_TRIGGER_STOP
:
306 case SNDRV_PCM_TRIGGER_SUSPEND
:
307 ret
= hda_link_dma_cleanup(substream
, hext_stream
, dai
);
309 dev_err(sdev
->dev
, "%s: failed to clean up link DMA\n", __func__
);
320 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
322 static int hda_dai_prepare(struct snd_pcm_substream
*substream
, struct snd_soc_dai
*dai
)
324 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
325 int stream
= substream
->stream
;
327 return hda_dai_hw_params(substream
, &rtd
->dpcm
[stream
].hw_params
, dai
);
330 static const struct snd_soc_dai_ops hda_dai_ops
= {
331 .hw_params
= hda_dai_hw_params
,
332 .hw_free
= hda_dai_hw_free
,
333 .trigger
= hda_dai_trigger
,
334 .prepare
= hda_dai_prepare
,
339 static struct sof_ipc4_copier
*widget_to_copier(struct snd_soc_dapm_widget
*w
)
341 struct snd_sof_widget
*swidget
= w
->dobj
.private;
342 struct snd_sof_dai
*sdai
= swidget
->private;
343 struct sof_ipc4_copier
*ipc4_copier
= (struct sof_ipc4_copier
*)sdai
->private;
348 static int non_hda_dai_hw_params_data(struct snd_pcm_substream
*substream
,
349 struct snd_pcm_hw_params
*params
,
350 struct snd_soc_dai
*cpu_dai
,
351 struct snd_sof_dai_config_data
*data
,
354 struct snd_soc_dapm_widget
*w
= snd_soc_dai_get_widget(cpu_dai
, substream
->stream
);
355 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
356 struct sof_ipc4_dma_config_tlv
*dma_config_tlv
;
357 const struct hda_dai_widget_dma_ops
*ops
;
358 struct sof_ipc4_dma_config
*dma_config
;
359 struct sof_ipc4_copier
*ipc4_copier
;
360 struct hdac_ext_stream
*hext_stream
;
361 struct hdac_stream
*hstream
;
362 struct snd_sof_dev
*sdev
;
363 struct snd_soc_dai
*dai
;
368 ops
= hda_dai_get_ops(substream
, cpu_dai
);
370 dev_err(cpu_dai
->dev
, "DAI widget ops not set\n");
374 sdev
= widget_to_sdev(w
);
375 hext_stream
= ops
->get_hext_stream(sdev
, cpu_dai
, substream
);
377 /* nothing more to do if the link is already prepared */
378 if (hext_stream
&& hext_stream
->link_prepared
)
381 /* use HDaudio stream handling */
382 ret
= hda_dai_hw_params_data(substream
, params
, cpu_dai
, data
, flags
);
384 dev_err(cpu_dai
->dev
, "%s: hda_dai_hw_params_data failed: %d\n", __func__
, ret
);
388 if (sdev
->dspless_mode_selected
)
392 hext_stream
= ops
->get_hext_stream(sdev
, cpu_dai
, substream
);
395 dev_err(cpu_dai
->dev
, "%s: no hext_stream found\n", __func__
);
399 hstream
= &hext_stream
->hstream
;
400 stream_id
= hstream
->stream_tag
;
403 dev_err(cpu_dai
->dev
, "%s: no stream_id allocated\n", __func__
);
408 ipc4_copier
= widget_to_copier(w
);
410 for_each_rtd_cpu_dais(rtd
, cpu_dai_id
, dai
) {
415 dma_config_tlv
= &ipc4_copier
->dma_config_tlv
[cpu_dai_id
];
416 dma_config_tlv
->type
= SOF_IPC4_GTW_DMA_CONFIG_ID
;
417 /* dma_config_priv_size is zero */
418 dma_config_tlv
->length
= sizeof(dma_config_tlv
->dma_config
);
420 dma_config
= &dma_config_tlv
->dma_config
;
422 dma_config
->dma_method
= SOF_IPC4_DMA_METHOD_HDA
;
423 dma_config
->pre_allocated_by_host
= 1;
424 dma_config
->dma_channel_id
= stream_id
- 1;
425 dma_config
->stream_id
= stream_id
;
427 * Currently we use a DMA for each device in ALH blob. The device will
428 * be copied in sof_ipc4_prepare_copier_module.
430 dma_config
->dma_stream_channel_map
.device_count
= 1;
431 dma_config
->dma_priv_config_size
= 0;
436 static int non_hda_dai_hw_params(struct snd_pcm_substream
*substream
,
437 struct snd_pcm_hw_params
*params
,
438 struct snd_soc_dai
*cpu_dai
)
440 struct snd_sof_dai_config_data data
= { 0 };
441 unsigned int flags
= SOF_DAI_CONFIG_FLAGS_HW_PARAMS
;
443 return non_hda_dai_hw_params_data(substream
, params
, cpu_dai
, &data
, flags
);
446 static int non_hda_dai_prepare(struct snd_pcm_substream
*substream
,
447 struct snd_soc_dai
*cpu_dai
)
449 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
450 int stream
= substream
->stream
;
452 return non_hda_dai_hw_params(substream
, &rtd
->dpcm
[stream
].hw_params
, cpu_dai
);
455 static const struct snd_soc_dai_ops ssp_dai_ops
= {
456 .hw_params
= non_hda_dai_hw_params
,
457 .hw_free
= hda_dai_hw_free
,
458 .trigger
= hda_dai_trigger
,
459 .prepare
= non_hda_dai_prepare
,
462 static const struct snd_soc_dai_ops dmic_dai_ops
= {
463 .hw_params
= non_hda_dai_hw_params
,
464 .hw_free
= hda_dai_hw_free
,
465 .trigger
= hda_dai_trigger
,
466 .prepare
= non_hda_dai_prepare
,
469 int sdw_hda_dai_hw_params(struct snd_pcm_substream
*substream
,
470 struct snd_pcm_hw_params
*params
,
471 struct snd_soc_dai
*cpu_dai
,
475 struct snd_soc_dapm_widget
*w
= snd_soc_dai_get_widget(cpu_dai
, substream
->stream
);
476 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
477 struct sof_ipc4_dma_config_tlv
*dma_config_tlv
;
478 struct snd_sof_dai_config_data data
= { 0 };
479 unsigned int flags
= SOF_DAI_CONFIG_FLAGS_HW_PARAMS
;
480 const struct hda_dai_widget_dma_ops
*ops
;
481 struct sof_ipc4_dma_config
*dma_config
;
482 struct sof_ipc4_copier
*ipc4_copier
;
483 struct hdac_ext_stream
*hext_stream
;
484 struct snd_soc_dai
*dai
;
485 struct snd_sof_dev
*sdev
;
486 bool cpu_dai_found
= false;
492 ops
= hda_dai_get_ops(substream
, cpu_dai
);
494 dev_err(cpu_dai
->dev
, "DAI widget ops not set\n");
498 sdev
= widget_to_sdev(w
);
499 hext_stream
= ops
->get_hext_stream(sdev
, cpu_dai
, substream
);
501 /* nothing more to do if the link is already prepared */
502 if (hext_stream
&& hext_stream
->link_prepared
)
506 * reset the PCMSyCM registers to handle a prepare callback when the PCM is restarted
507 * due to xruns or after a call to snd_pcm_drain/drop()
509 ret
= hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev
), link_id
, cpu_dai
->id
,
510 0, 0, substream
->stream
);
512 dev_err(cpu_dai
->dev
, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n",
517 data
.dai_index
= (link_id
<< 8) | cpu_dai
->id
;
518 data
.dai_node_id
= intel_alh_id
;
519 ret
= non_hda_dai_hw_params_data(substream
, params
, cpu_dai
, &data
, flags
);
521 dev_err(cpu_dai
->dev
, "%s: non_hda_dai_hw_params failed %d\n", __func__
, ret
);
525 hext_stream
= ops
->get_hext_stream(sdev
, cpu_dai
, substream
);
530 * in the case of SoundWire we need to program the PCMSyCM registers. In case
531 * of aggregated devices, we need to define the channel mask for each sublink
532 * by reconstructing the split done in soc-pcm.c
534 for_each_rtd_cpu_dais(rtd
, cpu_dai_id
, dai
) {
535 if (dai
== cpu_dai
) {
536 cpu_dai_found
= true;
544 ch_mask
= GENMASK(params_channels(params
) - 1, 0);
546 ret
= hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev
), link_id
, cpu_dai
->id
,
548 hdac_stream(hext_stream
)->stream_tag
,
551 dev_err(cpu_dai
->dev
, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n",
556 if (sdev
->dspless_mode_selected
)
559 ipc4_copier
= widget_to_copier(w
);
560 dma_config_tlv
= &ipc4_copier
->dma_config_tlv
[cpu_dai_id
];
561 dma_config
= &dma_config_tlv
->dma_config
;
562 dma_config
->dma_stream_channel_map
.mapping
[0].device
= data
.dai_index
;
563 dma_config
->dma_stream_channel_map
.mapping
[0].channel_mask
= ch_mask
;
566 * copy the dma_config_tlv to all ipc4_copier in the same link. Because only one copier
567 * will be handled in sof_ipc4_prepare_copier_module.
569 for_each_rtd_cpu_dais(rtd
, i
, dai
) {
570 w
= snd_soc_dai_get_widget(dai
, substream
->stream
);
571 ipc4_copier
= widget_to_copier(w
);
572 memcpy(&ipc4_copier
->dma_config_tlv
[cpu_dai_id
], dma_config_tlv
,
573 sizeof(*dma_config_tlv
));
577 EXPORT_SYMBOL_NS(sdw_hda_dai_hw_params
, "SND_SOC_SOF_INTEL_HDA_COMMON");
579 int sdw_hda_dai_hw_free(struct snd_pcm_substream
*substream
,
580 struct snd_soc_dai
*cpu_dai
,
583 struct snd_soc_dapm_widget
*w
= snd_soc_dai_get_widget(cpu_dai
, substream
->stream
);
584 struct snd_sof_dev
*sdev
;
587 ret
= hda_dai_hw_free(substream
, cpu_dai
);
589 dev_err(cpu_dai
->dev
, "%s: non_hda_dai_hw_free failed %d\n", __func__
, ret
);
593 sdev
= widget_to_sdev(w
);
595 /* in the case of SoundWire we need to reset the PCMSyCM registers */
596 ret
= hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev
), link_id
, cpu_dai
->id
,
597 0, 0, substream
->stream
);
599 dev_err(cpu_dai
->dev
, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n",
606 EXPORT_SYMBOL_NS(sdw_hda_dai_hw_free
, "SND_SOC_SOF_INTEL_HDA_COMMON");
608 int sdw_hda_dai_trigger(struct snd_pcm_substream
*substream
, int cmd
,
609 struct snd_soc_dai
*cpu_dai
)
611 return hda_dai_trigger(substream
, cmd
, cpu_dai
);
613 EXPORT_SYMBOL_NS(sdw_hda_dai_trigger
, "SND_SOC_SOF_INTEL_HDA_COMMON");
615 static int hda_dai_suspend(struct hdac_bus
*bus
)
617 struct snd_soc_pcm_runtime
*rtd
;
618 struct hdac_ext_stream
*hext_stream
;
619 struct hdac_stream
*s
;
622 /* set internal flag for BE */
623 list_for_each_entry(s
, &bus
->stream_list
, list
) {
625 hext_stream
= stream_to_hdac_ext_stream(s
);
628 * clear stream. This should already be taken care for running
629 * streams when the SUSPEND trigger is called. But paused
630 * streams do not get suspended, so this needs to be done
631 * explicitly during suspend.
633 if (hext_stream
->link_substream
) {
634 const struct hda_dai_widget_dma_ops
*ops
;
635 struct snd_sof_widget
*swidget
;
636 struct snd_soc_dapm_widget
*w
;
637 struct snd_soc_dai
*cpu_dai
;
638 struct snd_sof_dev
*sdev
;
639 struct snd_sof_dai
*sdai
;
641 rtd
= snd_soc_substream_to_rtd(hext_stream
->link_substream
);
642 cpu_dai
= snd_soc_rtd_to_cpu(rtd
, 0);
643 w
= snd_soc_dai_get_widget(cpu_dai
, hdac_stream(hext_stream
)->direction
);
644 swidget
= w
->dobj
.private;
645 sdev
= widget_to_sdev(w
);
646 sdai
= swidget
->private;
647 ops
= sdai
->platform_private
;
649 if (rtd
->dpcm
[hext_stream
->link_substream
->stream
].state
!=
650 SND_SOC_DPCM_STATE_PAUSED
)
653 /* for consistency with TRIGGER_SUSPEND */
654 if (ops
->post_trigger
) {
655 ret
= ops
->post_trigger(sdev
, cpu_dai
,
656 hext_stream
->link_substream
,
657 SNDRV_PCM_TRIGGER_SUSPEND
);
662 ret
= hda_link_dma_cleanup(hext_stream
->link_substream
,
673 static void ssp_set_dai_drv_ops(struct snd_sof_dev
*sdev
, struct snd_sof_dsp_ops
*ops
)
675 const struct sof_intel_dsp_desc
*chip
;
678 chip
= get_chip_info(sdev
->pdata
);
680 if (chip
->hw_ip_version
>= SOF_INTEL_ACE_2_0
) {
681 for (i
= 0; i
< ops
->num_drv
; i
++) {
682 if (strstr(ops
->drv
[i
].name
, "SSP"))
683 ops
->drv
[i
].ops
= &ssp_dai_ops
;
688 static void dmic_set_dai_drv_ops(struct snd_sof_dev
*sdev
, struct snd_sof_dsp_ops
*ops
)
690 const struct sof_intel_dsp_desc
*chip
;
693 chip
= get_chip_info(sdev
->pdata
);
695 if (chip
->hw_ip_version
>= SOF_INTEL_ACE_2_0
) {
696 for (i
= 0; i
< ops
->num_drv
; i
++) {
697 if (strstr(ops
->drv
[i
].name
, "DMIC"))
698 ops
->drv
[i
].ops
= &dmic_dai_ops
;
705 static inline void ssp_set_dai_drv_ops(struct snd_sof_dev
*sdev
, struct snd_sof_dsp_ops
*ops
) {}
706 static inline void dmic_set_dai_drv_ops(struct snd_sof_dev
*sdev
, struct snd_sof_dsp_ops
*ops
) {}
708 #endif /* CONFIG_SND_SOC_SOF_HDA_LINK */
710 void hda_set_dai_drv_ops(struct snd_sof_dev
*sdev
, struct snd_sof_dsp_ops
*ops
)
714 for (i
= 0; i
< ops
->num_drv
; i
++) {
715 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
716 if (strstr(ops
->drv
[i
].name
, "iDisp") ||
717 strstr(ops
->drv
[i
].name
, "Analog") ||
718 strstr(ops
->drv
[i
].name
, "Digital"))
719 ops
->drv
[i
].ops
= &hda_dai_ops
;
723 ssp_set_dai_drv_ops(sdev
, ops
);
724 dmic_set_dai_drv_ops(sdev
, ops
);
726 if (sdev
->pdata
->ipc_type
== SOF_IPC_TYPE_4
&& !hda_use_tplg_nhlt
) {
727 struct sof_ipc4_fw_data
*ipc4_data
= sdev
->private;
729 ipc4_data
->nhlt
= intel_nhlt_init(sdev
->dev
);
732 EXPORT_SYMBOL_NS(hda_set_dai_drv_ops
, "SND_SOC_SOF_INTEL_HDA_COMMON");
734 void hda_ops_free(struct snd_sof_dev
*sdev
)
736 if (sdev
->pdata
->ipc_type
== SOF_IPC_TYPE_4
) {
737 struct sof_ipc4_fw_data
*ipc4_data
= sdev
->private;
739 if (!hda_use_tplg_nhlt
)
740 intel_nhlt_free(ipc4_data
->nhlt
);
742 kfree(sdev
->private);
743 sdev
->private = NULL
;
746 EXPORT_SYMBOL_NS(hda_ops_free
, "SND_SOC_SOF_INTEL_HDA_COMMON");
749 * common dai driver for skl+ platforms.
750 * some products who use this DAI array only physically have a subset of
751 * the DAIs, but no harm is done here by adding the whole set.
753 struct snd_soc_dai_driver skl_dai
[] = {
821 .name
= "DMIC01 Pin",
828 .name
= "DMIC16k Pin",
834 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
836 .name
= "iDisp1 Pin",
843 .name
= "iDisp2 Pin",
850 .name
= "iDisp3 Pin",
857 .name
= "iDisp4 Pin",
864 .name
= "Analog CPU DAI",
875 .name
= "Digital CPU DAI",
886 .name
= "Alt Analog CPU DAI",
898 EXPORT_SYMBOL_NS(skl_dai
, "SND_SOC_SOF_INTEL_HDA_COMMON");
900 int hda_dsp_dais_suspend(struct snd_sof_dev
*sdev
)
903 * In the corner case where a SUSPEND happens during a PAUSE, the ALSA core
904 * does not throw the TRIGGER_SUSPEND. This leaves the DAIs in an unbalanced state.
905 * Since the component suspend is called last, we can trap this corner case
906 * and force the DAIs to release their resources.
908 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
911 ret
= hda_dai_suspend(sof_to_bus(sdev
));