// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) // // This file is provided under a dual BSD/GPLv2 license. When using or // redistributing this file, you may do so under either license. // // Copyright(c) 2018 Intel Corporation // // Authors: Keyon Jie <yang.jie@linux.intel.com> //
/* * The default method is to fetch NHLT from BIOS. With this parameter set * it is possible to override that with NHLT in the SOF topology manifest.
*/ staticbool hda_use_tplg_nhlt;
module_param_named(sof_use_tplg_nhlt, hda_use_tplg_nhlt, bool, 0444);
MODULE_PARM_DESC(sof_use_tplg_nhlt, "SOF topology nhlt override");
if (!swidget) {
dev_err(sdev->dev, "%s: swidget is NULL\n", __func__); return NULL;
}
if (sdev->dspless_mode_selected) return hda_select_dai_widget_ops(sdev, swidget);
sdai = swidget->private;
/* select and set the DAI widget ops if not set already */ if (!sdai->platform_private) { conststruct hda_dai_widget_dma_ops *ops =
hda_select_dai_widget_ops(sdev, swidget); if (!ops) return NULL;
/* check if mandatory ops are set */ if (!ops || !ops->get_hext_stream) return NULL;
if (!release) { /* * Force stream reconfiguration without releasing the channel on * subsequent stream restart (without free), including LinkDMA * reset. * The stream is released via hda_dai_hw_free()
*/
hext_stream->link_prepared = 0; return 0;
}
if (ops->release_hext_stream)
ops->release_hext_stream(sdev, cpu_dai, substream);
hext_stream->link_prepared = 0;
/* free the host DMA channel reserved by hostless streams */
hda_stream = hstream_to_sof_hda_stream(hext_stream);
hda_stream->host_reserved = 0;
for_each_rtd_cpu_dais(rtd, cpu_dai_id, dai) { if (dai == cpu_dai) break;
}
dma_config_tlv = &ipc4_copier->dma_config_tlv[cpu_dai_id];
dma_config_tlv->type = SOF_IPC4_GTW_DMA_CONFIG_ID; /* dma_config_priv_size is zero */
dma_config_tlv->length = sizeof(dma_config_tlv->dma_config);
dma_config = &dma_config_tlv->dma_config;
dma_config->dma_method = SOF_IPC4_DMA_METHOD_HDA;
dma_config->pre_allocated_by_host = 1;
dma_config->dma_channel_id = stream_id - 1;
dma_config->stream_id = stream_id; /* * Currently we use a DMA for each device in ALH blob. The device will * be copied in sof_ipc4_prepare_copier_module.
*/
dma_config->dma_stream_channel_map.device_count = 1;
dma_config->dma_priv_config_size = 0;
/* nothing more to do if the link is already prepared */ if (hext_stream && hext_stream->link_prepared) return 0;
/* * reset the PCMSyCM registers to handle a prepare callback when the PCM is restarted * due to xruns or after a call to snd_pcm_drain/drop()
*/
ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id,
0, 0, substream->stream); if (ret < 0) {
dev_err(cpu_dai->dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n",
__func__, ret); return ret;
}
hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); if (!hext_stream) return -ENODEV;
/* * in the case of SoundWire we need to program the PCMSyCM registers. In case * of aggregated devices, we need to define the channel mask for each sublink * by reconstructing the split done in soc-pcm.c
*/
for_each_rtd_cpu_dais(rtd, cpu_dai_id, dai) { if (dai == cpu_dai) {
cpu_dai_found = true; break;
}
}
/* * copy the dma_config_tlv to all ipc4_copier in the same link. Because only one copier * will be handled in sof_ipc4_prepare_copier_module.
*/
for_each_rtd_cpu_dais(rtd, i, dai) {
w = snd_soc_dai_get_widget(dai, substream->stream); if (!w) {
dev_err(cpu_dai->dev, "%s widget not found, check amp link num in the topology\n",
dai->name); return -EINVAL;
}
ipc4_copier = widget_to_copier(w);
memcpy(&ipc4_copier->dma_config_tlv[cpu_dai_id], dma_config_tlv, sizeof(*dma_config_tlv));
} return 0;
}
EXPORT_SYMBOL_NS(sdw_hda_dai_hw_params, "SND_SOC_SOF_INTEL_HDA_COMMON");
int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai, int link_id)
{ struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); struct snd_sof_dev *sdev; int ret;
ret = hda_dai_hw_free(substream, cpu_dai); if (ret < 0) {
dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_free failed %d\n", __func__, ret); return ret;
}
sdev = widget_to_sdev(w);
/* in the case of SoundWire we need to reset the PCMSyCM registers */
ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id,
0, 0, substream->stream); if (ret < 0) {
dev_err(cpu_dai->dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n",
__func__, ret); return ret;
}
/* set internal flag for BE */
list_for_each_entry(s, &bus->stream_list, list) {
hext_stream = stream_to_hdac_ext_stream(s);
/* * clear stream. This should already be taken care for running * streams when the SUSPEND trigger is called. But paused * streams do not get suspended, so this needs to be done * explicitly during suspend.
*/ if (hext_stream->link_substream) { conststruct hda_dai_widget_dma_ops *ops; struct snd_sof_widget *swidget; struct snd_soc_dapm_widget *w; struct snd_soc_dai *cpu_dai; struct snd_sof_dev *sdev; struct snd_sof_dai *sdai;
if (rtd->dpcm[hext_stream->link_substream->stream].state !=
SND_SOC_DPCM_STATE_PAUSED) continue;
/* for consistency with TRIGGER_SUSPEND */ if (ops->post_trigger) {
ret = ops->post_trigger(sdev, cpu_dai,
hext_stream->link_substream,
SNDRV_PCM_TRIGGER_SUSPEND); if (ret < 0) return ret;
}
ret = hda_link_dma_cleanup(hext_stream->link_substream,
hext_stream, cpu_dai, true); if (ret < 0) return ret;
}
}
if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) { for (i = 0; i < ops->num_drv; i++) { if (strstr(ops->drv[i].name, "SSP"))
ops->drv[i].ops = &ssp_dai_ops;
}
}
}
if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) { for (i = 0; i < ops->num_drv; i++) { if (strstr(ops->drv[i].name, "DMIC"))
ops->drv[i].ops = &dmic_dai_ops;
}
}
}
int hda_dsp_dais_suspend(struct snd_sof_dev *sdev)
{ /* * In the corner case where a SUSPEND happens during a PAUSE, the ALSA core * does not throw the TRIGGER_SUSPEND. This leaves the DAIs in an unbalanced state. * Since the component suspend is called last, we can trap this corner case * and force the DAIs to release their resources.
*/ #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK) int ret;
ret = hda_dai_suspend(sof_to_bus(sdev)); if (ret < 0) return ret; #endif
return 0;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.