ASoC: SOF: Introduce fragment elapsed notification API
authorDaniel Baluta <daniel.baluta@nxp.com>
Mon, 4 Oct 2021 15:21:47 +0000 (18:21 +0300)
committerMark Brown <broonie@kernel.org>
Thu, 7 Oct 2021 15:57:57 +0000 (16:57 +0100)
This patch prepares the introduction of the compress API with SOF.

After each fragment is accepted by the DSP we need to inform
the userspace applications that they can send the next fragment.
This is done via snd_compr_fragment_elapsed.

Similar with the PCM case, in order to avoid sending an IPC before
the previous IPC is handled we need to schedule a delayed work to
call snd_compr_fragment_elapsed().

See snd_sof_pcm_period_elapsed.

To sum up this patch offers the following API to SOF code:
* snd_sof_compr_init_elapsed_work
* snd_sof_compr_fragment_elapsed

Note that implementation for compressed function is in a new file
selected via CONFIG_SND_SOC_SOF_COMPRESS invisible config option.
This option is automatically selected for platforms that support
the compress interface. For now only i.MX8 platforms support this.

For symmetry we introduce snd_sof_pcm_init_elapsed_work to setup
the work struct for PCM case.

Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
Signed-off-by: Bud Liviu-Alexandru <budliviu@gmail.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Paul Olaru <paul.olaru@oss.nxp.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Link: https://lore.kernel.org/r/20211004152147.1268978-5-daniel.baluta@oss.nxp.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sof/Kconfig
sound/soc/sof/Makefile
sound/soc/sof/compress.c [new file with mode: 0644]
sound/soc/sof/imx/Kconfig
sound/soc/sof/ipc.c
sound/soc/sof/pcm.c
sound/soc/sof/sof-audio.h
sound/soc/sof/topology.c

index 94d1a859fedc34ac3aaa4a6214a3c24f94942c84..6bb4db87af0330abe6f0f94869e4ae6992f8dc37 100644 (file)
@@ -46,6 +46,10 @@ config SND_SOC_SOF_OF
          required to enable i.MX8 devices.
          Say Y if you need this option. If unsure select "N".
 
+config SND_SOC_SOF_COMPRESS
+       tristate
+       select SND_SOC_COMPRESS
+
 config SND_SOC_SOF_DEBUG_PROBES
        bool "SOF enable data probing"
        select SND_SOC_COMPRESS
index c5b97c66a9f16b0bed065a3355bd825b2e5e5cea..06e5f49f7ee8615923c62992be803f9aa391b2c6 100644 (file)
@@ -4,6 +4,7 @@ snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\
                control.o trace.o utils.o sof-audio.o stream-ipc.o
 
 snd-sof-$(CONFIG_SND_SOC_SOF_DEBUG_PROBES) += sof-probes.o
+snd-sof-$(CONFIG_SND_SOC_SOF_COMPRESS) += compress.o
 
 snd-sof-pci-objs := sof-pci-dev.o
 snd-sof-acpi-objs := sof-acpi-dev.o
diff --git a/sound/soc/sof/compress.c b/sound/soc/sof/compress.c
new file mode 100644 (file)
index 0000000..01ca85f
--- /dev/null
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// Copyright 2021 NXP
+//
+// Author: Daniel Baluta <daniel.baluta@nxp.com>
+
+#include <sound/soc.h>
+#include <sound/sof.h>
+#include <sound/compress_driver.h>
+#include "sof-audio.h"
+#include "sof-priv.h"
+
+static void snd_sof_compr_fragment_elapsed_work(struct work_struct *work)
+{
+       struct snd_sof_pcm_stream *sps =
+               container_of(work, struct snd_sof_pcm_stream,
+                            period_elapsed_work);
+
+       snd_compr_fragment_elapsed(sps->cstream);
+}
+
+void snd_sof_compr_init_elapsed_work(struct work_struct *work)
+{
+       INIT_WORK(work, snd_sof_compr_fragment_elapsed_work);
+}
+
+/*
+ * sof compr fragment elapse, this could be called in irq thread context
+ */
+void snd_sof_compr_fragment_elapsed(struct snd_compr_stream *cstream)
+{
+       struct snd_soc_component *component;
+       struct snd_soc_pcm_runtime *rtd;
+       struct snd_sof_pcm *spcm;
+
+       if (!cstream)
+               return;
+
+       rtd = cstream->private_data;
+       component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
+
+       spcm = snd_sof_find_spcm_dai(component, rtd);
+       if (!spcm) {
+               dev_err(component->dev,
+                       "fragment elapsed called for unknown stream!\n");
+               return;
+       }
+
+       /* use the same workqueue-based solution as for PCM, cf. snd_sof_pcm_elapsed */
+       schedule_work(&spcm->stream[cstream->direction].period_elapsed_work);
+}
index 49d605cb09a5a49e0e81d64d7dcedfbb5e21fe6f..34cf228c188f93c1765de3ee0993c30085d4c07d 100644 (file)
@@ -38,6 +38,7 @@ config SND_SOC_SOF_IMX8
        tristate
        select SND_SOC_SOF_IMX_COMMON
        select SND_SOC_SOF_XTENSA
+       select SND_SOC_SOF_COMPRESS
        help
          This option is not user-selectable but automagically handled by
          'select' statements at a higher level.
@@ -54,6 +55,7 @@ config SND_SOC_SOF_IMX8M
        tristate
        select SND_SOC_SOF_IMX_COMMON
        select SND_SOC_SOF_XTENSA
+       select SND_SOC_SOF_COMPRESS
        help
          This option is not user-selectable but automagically handled by
          'select' statements at a higher level.
index 53593df951559faf658dab67a877fb1c18e38473..1efc2c395c54b14c18450699554a89d3ca398dc8 100644 (file)
@@ -539,8 +539,10 @@ static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id)
 
        memcpy(&stream->posn, &posn, sizeof(posn));
 
-       /* only inform ALSA for period_wakeup mode */
-       if (!stream->substream->runtime->no_period_wakeup)
+       if (spcm->pcm.compress)
+               snd_sof_compr_fragment_elapsed(stream->cstream);
+       else if (!stream->substream->runtime->no_period_wakeup)
+               /* only inform ALSA for period_wakeup mode */
                snd_sof_pcm_period_elapsed(stream->substream);
 }
 
index 374df2dfa81616c8727516e3a09908821d07362f..fa0bfcd2474e0b9800f8ee6a4e570a540f331d4d 100644 (file)
@@ -57,7 +57,7 @@ static int sof_pcm_dsp_params(struct snd_sof_pcm *spcm, struct snd_pcm_substream
 /*
  * sof pcm period elapse work
  */
-void snd_sof_pcm_period_elapsed_work(struct work_struct *work)
+static void snd_sof_pcm_period_elapsed_work(struct work_struct *work)
 {
        struct snd_sof_pcm_stream *sps =
                container_of(work, struct snd_sof_pcm_stream,
@@ -66,6 +66,11 @@ void snd_sof_pcm_period_elapsed_work(struct work_struct *work)
        snd_pcm_period_elapsed(sps->substream);
 }
 
+void snd_sof_pcm_init_elapsed_work(struct work_struct *work)
+{
+        INIT_WORK(work, snd_sof_pcm_period_elapsed_work);
+}
+
 /*
  * sof pcm period elapse, this could be called at irq thread context.
  */
index 149b3dbcddd159ea9beb57ca5cec2e9b4e5d681d..3f16611fbca7f7a1658cf9d170406ef46fd69551 100644 (file)
@@ -36,6 +36,7 @@ struct snd_sof_pcm_stream {
        struct snd_dma_buffer page_table;
        struct sof_ipc_stream_posn posn;
        struct snd_pcm_substream *substream;
+       struct snd_compr_stream *cstream;
        struct work_struct period_elapsed_work;
        struct snd_soc_dapm_widget_list *list; /* list of connected DAPM widgets */
        bool d0i3_compatible; /* DSP can be in D0I3 when this pcm is opened */
@@ -231,7 +232,15 @@ struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_soc_component *scomp,
 const struct sof_ipc_pipe_new *snd_sof_pipeline_find(struct snd_sof_dev *sdev,
                                                     int pipeline_id);
 void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream);
-void snd_sof_pcm_period_elapsed_work(struct work_struct *work);
+void snd_sof_pcm_init_elapsed_work(struct work_struct *work);
+
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS)
+void snd_sof_compr_fragment_elapsed(struct snd_compr_stream *cstream);
+void snd_sof_compr_init_elapsed_work(struct work_struct *work);
+#else
+static inline void snd_sof_compr_fragment_elapsed(struct snd_compr_stream *cstream) { }
+static inline void snd_sof_compr_init_elapsed_work(struct work_struct *work) { }
+#endif
 
 /*
  * Mixer IPC
index 534f004f61622186bcb6209388a3d56071465182..e81fa2058c7d6ae4ac33a3c4a523f12799973291 100644 (file)
@@ -2587,8 +2587,10 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index,
 
        for_each_pcm_streams(stream) {
                spcm->stream[stream].comp_id = COMP_ID_UNASSIGNED;
-               INIT_WORK(&spcm->stream[stream].period_elapsed_work,
-                         snd_sof_pcm_period_elapsed_work);
+               if (pcm->compress)
+                       snd_sof_compr_init_elapsed_work(&spcm->stream[stream].period_elapsed_work);
+               else
+                       snd_sof_pcm_init_elapsed_work(&spcm->stream[stream].period_elapsed_work);
        }
 
        spcm->pcm = *pcm;