diff options
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/sof/pcm.c | 12 | ||||
-rw-r--r-- | sound/soc/sof/topology.c | 167 |
2 files changed, 51 insertions, 128 deletions
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 0885826adb6c..e9679fcba428 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -639,6 +639,7 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); struct snd_sof_dai *dai = snd_sof_find_dai(component, (char *)rtd->dai_link->name); + struct snd_soc_dpcm *dpcm; /* no topology exists for this BE, try a common configuration */ if (!dai) { @@ -702,7 +703,16 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, } break; case SOF_DAI_INTEL_HDA: - /* do nothing for HDA dai_link */ + /* + * HDaudio does not follow the default trigger + * sequence due to firmware implementation + */ + for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_PLAYBACK, dpcm) { + struct snd_soc_pcm_runtime *fe = dpcm->fe; + + fe->dai_link->trigger[SNDRV_PCM_STREAM_PLAYBACK] = + SND_SOC_DPCM_TRIGGER_POST; + } break; case SOF_DAI_INTEL_ALH: /* do nothing for ALH dai_link */ diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index e88ffc25025f..8ab0fc558054 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2673,7 +2673,11 @@ static void sof_dai_set_format(struct snd_soc_tplg_hw_config *hw_config, } } -/* set config for all DAI's with name matching the link name */ +/* + * Send IPC and set the same config for all DAIs with name matching the link + * name. Note that the function can only be used for the case that all DAIs + * have a common DAI config for now. + */ static int sof_set_dai_config(struct snd_sof_dev *sdev, u32 size, struct snd_soc_dai_link *link, struct sof_ipc_dai_config *config) @@ -2686,6 +2690,27 @@ static int sof_set_dai_config(struct snd_sof_dev *sdev, u32 size, continue; if (strcmp(link->name, dai->name) == 0) { + struct sof_ipc_reply reply; + int ret; + + /* + * the same dai config will be applied to all DAIs in + * the same dai link. We have to ensure that the ipc + * dai config's dai_index match to the component's + * dai_index. + */ + config->dai_index = dai->comp_dai.dai_index; + + /* send message to DSP */ + ret = sof_ipc_tx_message(sdev->ipc, + config->hdr.cmd, config, size, + &reply, sizeof(reply)); + + if (ret < 0) { + dev_err(sdev->dev, "error: failed to set DAI config for %s index %d\n", + dai->name, config->dai_index); + return ret; + } dai->dai_config = kmemdup(config, size, GFP_KERNEL); if (!dai->dai_config) return -ENOMEM; @@ -2718,7 +2743,6 @@ static int sof_link_ssp_load(struct snd_soc_component *scomp, int index, { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_private *private = &cfg->priv; - struct sof_ipc_reply reply; u32 size = sizeof(*config); int ret; @@ -2767,17 +2791,6 @@ static int sof_link_ssp_load(struct snd_soc_component *scomp, int index, return -EINVAL; } - /* send message to DSP */ - ret = sof_ipc_tx_message(sdev->ipc, - config->hdr.cmd, config, size, &reply, - sizeof(reply)); - - if (ret < 0) { - dev_err(scomp->dev, "error: failed to set DAI config for SSP%d\n", - config->dai_index); - return ret; - } - /* set config for all DAI's with name matching the link name */ ret = sof_set_dai_config(sdev, size, link, config); if (ret < 0) @@ -2795,7 +2808,6 @@ static int sof_link_sai_load(struct snd_soc_component *scomp, int index, { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_private *private = &cfg->priv; - struct sof_ipc_reply reply; u32 size = sizeof(*config); int ret; @@ -2835,17 +2847,6 @@ static int sof_link_sai_load(struct snd_soc_component *scomp, int index, return -EINVAL; } - /* send message to DSP */ - ret = sof_ipc_tx_message(sdev->ipc, - config->hdr.cmd, config, size, &reply, - sizeof(reply)); - - if (ret < 0) { - dev_err(scomp->dev, "error: failed to set DAI config for SAI%d\n", - config->dai_index); - return ret; - } - /* set config for all DAI's with name matching the link name */ ret = sof_set_dai_config(sdev, size, link, config); if (ret < 0) @@ -2863,7 +2864,6 @@ static int sof_link_esai_load(struct snd_soc_component *scomp, int index, { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_private *private = &cfg->priv; - struct sof_ipc_reply reply; u32 size = sizeof(*config); int ret; @@ -2904,16 +2904,6 @@ static int sof_link_esai_load(struct snd_soc_component *scomp, int index, return -EINVAL; } - /* send message to DSP */ - ret = sof_ipc_tx_message(sdev->ipc, - config->hdr.cmd, config, size, &reply, - sizeof(reply)); - if (ret < 0) { - dev_err(scomp->dev, "error: failed to set DAI config for ESAI%d\n", - config->dai_index); - return ret; - } - /* set config for all DAI's with name matching the link name */ ret = sof_set_dai_config(sdev, size, link, config); if (ret < 0) @@ -2931,7 +2921,6 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_private *private = &cfg->priv; - struct sof_ipc_reply reply; struct sof_ipc_fw_ready *ready = &sdev->fw_ready; struct sof_ipc_fw_version *v = &ready->version; size_t size = sizeof(*config); @@ -3007,17 +2996,6 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, if (SOF_ABI_VER(v->major, v->minor, v->micro) < SOF_ABI_VER(3, 0, 1)) config->dmic.fifo_bits_b = config->dmic.fifo_bits; - /* send message to DSP */ - ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, size, - &reply, sizeof(reply)); - - if (ret < 0) { - dev_err(scomp->dev, - "error: failed to set DAI config for DMIC%d\n", - config->dai_index); - goto err; - } - /* set config for all DAI's with name matching the link name */ ret = sof_set_dai_config(sdev, size, link, config); if (ret < 0) @@ -3030,66 +3008,6 @@ err: return ret; } -/* - * for hda link, playback and capture are supported by different dai - * in FW. Here get the dai_index, set dma channel of each dai - * and send config to FW. In FW, each dai sets config by dai_index - */ -static int sof_link_hda_process(struct snd_sof_dev *sdev, - struct snd_soc_dai_link *link, - struct sof_ipc_dai_config *config) -{ - struct sof_ipc_reply reply; - u32 size = sizeof(*config); - struct snd_sof_dai *sof_dai; - int found = 0; - int ret; - - list_for_each_entry(sof_dai, &sdev->dai_list, list) { - if (!sof_dai->name) - continue; - - if (strcmp(link->name, sof_dai->name) == 0) { - config->dai_index = sof_dai->comp_dai.dai_index; - found = 1; - - config->hda.link_dma_ch = DMA_CHAN_INVALID; - - /* save config in dai component */ - sof_dai->dai_config = kmemdup(config, size, GFP_KERNEL); - if (!sof_dai->dai_config) - return -ENOMEM; - - sof_dai->cpu_dai_name = link->cpus->dai_name; - - /* send message to DSP */ - ret = sof_ipc_tx_message(sdev->ipc, - config->hdr.cmd, config, size, - &reply, sizeof(reply)); - - if (ret < 0) { - dev_err(sdev->dev, "error: failed to set DAI config for direction:%d of HDA dai %d\n", - sof_dai->comp_dai.direction, - config->dai_index); - - return ret; - } - } - } - - /* - * machine driver may define a dai link with playback and capture - * dai enabled, but the dai link in topology would support both, one - * or none of them. Here print a warning message to notify user - */ - if (!found) { - dev_warn(sdev->dev, "warning: failed to find dai for dai link %s", - link->name); - } - - return 0; -} - static int sof_link_hda_load(struct snd_soc_component *scomp, int index, struct snd_soc_dai_link *link, struct snd_soc_tplg_link_config *cfg, @@ -3126,7 +3044,9 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index, return -EINVAL; } - ret = sof_link_hda_process(sdev, link, config); + config->hda.link_dma_ch = DMA_CHAN_INVALID; + + ret = sof_set_dai_config(sdev, size, link, config); if (ret < 0) dev_err(scomp->dev, "error: failed to process hda dai link %s", link->name); @@ -3142,7 +3062,6 @@ static int sof_link_alh_load(struct snd_soc_component *scomp, int index, { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_private *private = &cfg->priv; - struct sof_ipc_reply reply; u32 size = sizeof(*config); int ret; @@ -3158,20 +3077,6 @@ static int sof_link_alh_load(struct snd_soc_component *scomp, int index, /* init IPC */ config->hdr.size = size; - dev_dbg(scomp->dev, "ALH config rate %d channels %d\n", - config->alh.rate, config->alh.channels); - - /* send message to DSP */ - ret = sof_ipc_tx_message(sdev->ipc, - config->hdr.cmd, config, size, &reply, - sizeof(reply)); - - if (ret < 0) { - dev_err(scomp->dev, "error: failed to set DAI config for ALH %d\n", - config->dai_index); - return ret; - } - /* set config for all DAI's with name matching the link name */ ret = sof_set_dai_config(sdev, size, link, config); if (ret < 0) @@ -3206,9 +3111,17 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, if (!link->no_pcm) { link->nonatomic = true; - /* set trigger order */ - link->trigger[0] = SND_SOC_DPCM_TRIGGER_POST; - link->trigger[1] = SND_SOC_DPCM_TRIGGER_POST; + /* + * set default trigger order for all links. Exceptions to + * the rule will be handled in sof_pcm_dai_link_fixup() + * For playback, the sequence is the following: start FE, + * start BE, stop BE, stop FE; for Capture the sequence is + * inverted start BE, start FE, stop FE, stop BE + */ + link->trigger[SNDRV_PCM_STREAM_PLAYBACK] = + SND_SOC_DPCM_TRIGGER_PRE; + link->trigger[SNDRV_PCM_STREAM_CAPTURE] = + SND_SOC_DPCM_TRIGGER_POST; /* nothing more to do for FE dai links */ return 0; |