summaryrefslogtreecommitdiffstats
path: root/sound/soc/sof/topology.c
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@linux.intel.com>2023-04-04 12:21:06 +0300
committerMark Brown <broonie@kernel.org>2023-04-04 12:42:34 +0100
commit28d40e7adfd4108c11c9397c6fe9d9f80fed31e9 (patch)
tree18d161fc1246c7b0e3261945d0cee7f92561463b /sound/soc/sof/topology.c
parent59611370f92923089ceb284072d01445164a0191 (diff)
downloadlinux-stable-28d40e7adfd4108c11c9397c6fe9d9f80fed31e9.tar.gz
linux-stable-28d40e7adfd4108c11c9397c6fe9d9f80fed31e9.tar.bz2
linux-stable-28d40e7adfd4108c11c9397c6fe9d9f80fed31e9.zip
ASoC: SOF: Add support for DSPless mode
Via the SOF_DBG_DSPLESS_MODE sof_debug flag the SOF stack can be asked to not use the DSP for audio. The core's support for DSPless mode is only going to be enabled if the platform reports that it can be used without DSP. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com> Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Reviewed-by: Rander Wang <rander.wang@intel.com> Link: https://lore.kernel.org/r/20230404092115.27949-4-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/sof/topology.c')
-rw-r--r--sound/soc/sof/topology.c130
1 files changed, 129 insertions, 1 deletions
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index bc8ca1e05b83..d3d536b0a8f5 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -1144,8 +1144,12 @@ static void sof_disconnect_dai_widget(struct snd_soc_component *scomp,
static int spcm_bind(struct snd_soc_component *scomp, struct snd_sof_pcm *spcm,
int dir)
{
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_sof_widget *host_widget;
+ if (sdev->dspless_mode_selected)
+ return 0;
+
host_widget = snd_sof_find_swidget_sname(scomp,
spcm->pcm.caps[dir].name,
dir);
@@ -2270,6 +2274,126 @@ static struct snd_soc_tplg_ops sof_tplg_ops = {
.bytes_ext_ops_count = ARRAY_SIZE(sof_bytes_ext_ops),
};
+static int snd_sof_dspless_kcontrol(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return 0;
+}
+
+static const struct snd_soc_tplg_kcontrol_ops sof_dspless_io_ops[] = {
+ {SOF_TPLG_KCTL_VOL_ID, snd_sof_dspless_kcontrol, snd_sof_dspless_kcontrol},
+ {SOF_TPLG_KCTL_BYTES_ID, snd_sof_dspless_kcontrol, snd_sof_dspless_kcontrol},
+ {SOF_TPLG_KCTL_ENUM_ID, snd_sof_dspless_kcontrol, snd_sof_dspless_kcontrol},
+ {SOF_TPLG_KCTL_SWITCH_ID, snd_sof_dspless_kcontrol, snd_sof_dspless_kcontrol},
+};
+
+static int snd_sof_dspless_bytes_ext_get(struct snd_kcontrol *kcontrol,
+ unsigned int __user *binary_data,
+ unsigned int size)
+{
+ return 0;
+}
+
+static int snd_sof_dspless_bytes_ext_put(struct snd_kcontrol *kcontrol,
+ const unsigned int __user *binary_data,
+ unsigned int size)
+{
+ return 0;
+}
+
+static const struct snd_soc_tplg_bytes_ext_ops sof_dspless_bytes_ext_ops[] = {
+ {SOF_TPLG_KCTL_BYTES_ID, snd_sof_dspless_bytes_ext_get, snd_sof_dspless_bytes_ext_put},
+ {SOF_TPLG_KCTL_BYTES_VOLATILE_RO, snd_sof_dspless_bytes_ext_get},
+};
+
+/* external widget init - used for any driver specific init */
+static int sof_dspless_widget_ready(struct snd_soc_component *scomp, int index,
+ struct snd_soc_dapm_widget *w,
+ struct snd_soc_tplg_dapm_widget *tw)
+{
+ if (WIDGET_IS_DAI(w->id)) {
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+ struct snd_sof_widget *swidget;
+ struct snd_sof_dai dai;
+ int ret;
+
+ swidget = kzalloc(sizeof(*swidget), GFP_KERNEL);
+ if (!swidget)
+ return -ENOMEM;
+
+ memset(&dai, 0, sizeof(dai));
+
+ ret = sof_connect_dai_widget(scomp, w, tw, &dai);
+ if (ret) {
+ kfree(swidget);
+ return ret;
+ }
+
+ swidget->scomp = scomp;
+ swidget->widget = w;
+ mutex_init(&swidget->setup_mutex);
+ w->dobj.private = swidget;
+ list_add(&swidget->list, &sdev->widget_list);
+ }
+
+ return 0;
+}
+
+static int sof_dspless_widget_unload(struct snd_soc_component *scomp,
+ struct snd_soc_dobj *dobj)
+{
+ struct snd_soc_dapm_widget *w = container_of(dobj, struct snd_soc_dapm_widget, dobj);
+
+ if (WIDGET_IS_DAI(w->id)) {
+ struct snd_sof_widget *swidget = dobj->private;
+
+ sof_disconnect_dai_widget(scomp, w);
+
+ if (!swidget)
+ return 0;
+
+ /* remove and free swidget object */
+ list_del(&swidget->list);
+ kfree(swidget);
+ }
+
+ return 0;
+}
+
+static int sof_dspless_link_load(struct snd_soc_component *scomp, int index,
+ struct snd_soc_dai_link *link,
+ struct snd_soc_tplg_link_config *cfg)
+{
+ link->platforms->name = dev_name(scomp->dev);
+
+ /* Set nonatomic property for FE dai links for FE-BE compatibility */
+ if (!link->no_pcm)
+ link->nonatomic = true;
+
+ return 0;
+}
+
+static struct snd_soc_tplg_ops sof_dspless_tplg_ops = {
+ /* external widget init - used for any driver specific init */
+ .widget_ready = sof_dspless_widget_ready,
+ .widget_unload = sof_dspless_widget_unload,
+
+ /* FE DAI - used for any driver specific init */
+ .dai_load = sof_dai_load,
+ .dai_unload = sof_dai_unload,
+
+ /* DAI link - used for any driver specific init */
+ .link_load = sof_dspless_link_load,
+
+ /* vendor specific kcontrol handlers available for binding */
+ .io_ops = sof_dspless_io_ops,
+ .io_ops_count = ARRAY_SIZE(sof_dspless_io_ops),
+
+ /* vendor specific bytes ext handlers available for binding */
+ .bytes_ext_ops = sof_dspless_bytes_ext_ops,
+ .bytes_ext_ops_count = ARRAY_SIZE(sof_dspless_bytes_ext_ops),
+};
+
int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
@@ -2287,7 +2411,11 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
return ret;
}
- ret = snd_soc_tplg_component_load(scomp, &sof_tplg_ops, fw);
+ if (sdev->dspless_mode_selected)
+ ret = snd_soc_tplg_component_load(scomp, &sof_dspless_tplg_ops, fw);
+ else
+ ret = snd_soc_tplg_component_load(scomp, &sof_tplg_ops, fw);
+
if (ret < 0) {
dev_err(scomp->dev, "error: tplg component load failed %d\n",
ret);