Blob Blame History Raw
From 4123c24bd13caa8ff633d9e17fa2089d53b1f766 Mon Sep 17 00:00:00 2001
From: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Date: Thu, 17 Mar 2022 10:50:38 -0700
Subject: [PATCH] ASoC: SOF: Introduce IPC3 PCM hw_free op
Mime-version: 1.0
Content-type: text/plain; charset=UTF-8
Content-transfer-encoding: 8bit
Git-commit: 4123c24bd13caa8ff633d9e17fa2089d53b1f766
Patch-mainline: v5.18-rc1
References: jsc#PED-850

Add the IPC3 PCM ops, define the hw_free op and modify all users to use
the op.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Link: https://lore.kernel.org/r/20220317175044.1752400-14-ranjani.sridharan@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Acked-by: Takashi Iwai <tiwai@suse.de>

---
 sound/soc/sof/Makefile    |  2 +-
 sound/soc/sof/ipc.c       |  5 +++--
 sound/soc/sof/ipc3-ops.h  |  1 +
 sound/soc/sof/ipc3-pcm.c  | 43 ++++++++++++++++++++++++++++++++++++++
 sound/soc/sof/ipc3.c      |  1 +
 sound/soc/sof/pcm.c       | 44 +++++++++++++--------------------------
 sound/soc/sof/sof-audio.c | 11 +++++++---
 7 files changed, 72 insertions(+), 35 deletions(-)
 create mode 100644 sound/soc/sof/ipc3-pcm.c

diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile
index f6d68a3096d9..18acbc001b9a 100644
--- a/sound/soc/sof/Makefile
+++ b/sound/soc/sof/Makefile
@@ -2,7 +2,7 @@
 
 snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\
 		control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o\
-		ipc3-topology.o ipc3.o ipc3-control.o
+		ipc3-topology.o ipc3.o ipc3-control.o ipc3-pcm.o
 ifneq ($(CONFIG_SND_SOC_SOF_CLIENT),)
 snd-sof-objs += sof-client.o
 endif
diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c
index af0ae137842b..5f5753608c79 100644
--- a/sound/soc/sof/ipc.c
+++ b/sound/soc/sof/ipc.c
@@ -1033,8 +1033,9 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev)
 	ipc->ops = &ipc3_ops;
 
 	/* check for mandatory ops */
-	if (!ipc->ops->tplg || !ipc->ops->tplg->widget || !ipc->ops->tplg->control) {
-		dev_err(sdev->dev, "Invalid topology IPC ops\n");
+	if (!ipc->ops->pcm || !ipc->ops->tplg || !ipc->ops->tplg->widget ||
+	    !ipc->ops->tplg->control) {
+		dev_err(sdev->dev, "Invalid IPC ops\n");
 		return NULL;
 	}
 
diff --git a/sound/soc/sof/ipc3-ops.h b/sound/soc/sof/ipc3-ops.h
index f3d6010d0b77..a4784626a3d7 100644
--- a/sound/soc/sof/ipc3-ops.h
+++ b/sound/soc/sof/ipc3-ops.h
@@ -16,5 +16,6 @@
 extern const struct sof_ipc_tplg_ops ipc3_tplg_ops;
 extern const struct sof_ipc_ops ipc3_ops;
 extern const struct sof_ipc_tplg_control_ops tplg_ipc3_control_ops;
+extern const struct sof_ipc_pcm_ops ipc3_pcm_ops;
 
 #endif
diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c
new file mode 100644
index 000000000000..96f498b4b2d6
--- /dev/null
+++ b/sound/soc/sof/ipc3-pcm.c
@@ -0,0 +1,43 @@
+// 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) 2021 Intel Corporation. All rights reserved.
+//
+//
+
+#include <sound/pcm_params.h>
+#include "ipc3-ops.h"
+#include "ops.h"
+#include "sof-priv.h"
+#include "sof-audio.h"
+
+static int sof_ipc3_pcm_hw_free(struct snd_soc_component *component,
+				struct snd_pcm_substream *substream)
+{
+	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
+	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+	struct sof_ipc_stream stream;
+	struct sof_ipc_reply reply;
+	struct snd_sof_pcm *spcm;
+
+	spcm = snd_sof_find_spcm_dai(component, rtd);
+	if (!spcm)
+		return -EINVAL;
+
+	if (!spcm->prepared[substream->stream])
+		return 0;
+
+	stream.hdr.size = sizeof(stream);
+	stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE;
+	stream.comp_id = spcm->stream[substream->stream].comp_id;
+
+	/* send IPC to the DSP */
+	return sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
+				  sizeof(stream), &reply, sizeof(reply));
+}
+
+const struct sof_ipc_pcm_ops ipc3_pcm_ops = {
+	.hw_free = sof_ipc3_pcm_hw_free,
+};
diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c
index e71cf30908c6..03e914b62728 100644
--- a/sound/soc/sof/ipc3.c
+++ b/sound/soc/sof/ipc3.c
@@ -41,4 +41,5 @@ static const struct sof_ipc_pm_ops ipc3_pm_ops = {
 const struct sof_ipc_ops ipc3_ops = {
 	.tplg = &ipc3_tplg_ops,
 	.pm = &ipc3_pm_ops,
+	.pcm = &ipc3_pcm_ops,
 };
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c
index 47599b57ff19..8ef477aff938 100644
--- a/sound/soc/sof/pcm.c
+++ b/sound/soc/sof/pcm.c
@@ -82,29 +82,6 @@ void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream)
 }
 EXPORT_SYMBOL(snd_sof_pcm_period_elapsed);
 
-int sof_pcm_dsp_pcm_free(struct snd_pcm_substream *substream, struct snd_sof_dev *sdev,
-			 struct snd_sof_pcm *spcm)
-{
-	struct sof_ipc_stream stream;
-	struct sof_ipc_reply reply;
-	int ret;
-
-	if (!spcm->prepared[substream->stream])
-		return 0;
-
-	stream.hdr.size = sizeof(stream);
-	stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE;
-	stream.comp_id = spcm->stream[substream->stream].comp_id;
-
-	/* send IPC to the DSP */
-	ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
-				 sizeof(stream), &reply, sizeof(reply));
-	if (!ret)
-		spcm->prepared[substream->stream] = false;
-
-	return ret;
-}
-
 int sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_runtime *rtd,
 				    struct snd_sof_pcm *spcm, int dir)
 {
@@ -145,6 +122,7 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
+	const struct sof_ipc_pcm_ops *pcm_ops = sdev->ipc->ops->pcm;
 	struct snd_sof_platform_stream_params platform_params = { 0 };
 	struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
 	struct snd_sof_pcm *spcm;
@@ -164,9 +142,13 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
 	 * Handle repeated calls to hw_params() without free_pcm() in
 	 * between. At least ALSA OSS emulation depends on this.
 	 */
-	ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm);
-	if (ret < 0)
-		return ret;
+	if (pcm_ops->hw_free && spcm->prepared[substream->stream]) {
+		ret = pcm_ops->hw_free(component, substream);
+		if (ret < 0)
+			return ret;
+
+		spcm->prepared[substream->stream] = false;
+	}
 
 	dev_dbg(component->dev, "pcm: hw params stream %d dir %d\n",
 		spcm->pcm.pcm_id, substream->stream);
@@ -289,6 +271,7 @@ static int sof_pcm_hw_free(struct snd_soc_component *component,
 {
 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
+	const struct sof_ipc_pcm_ops *pcm_ops = sdev->ipc->ops->pcm;
 	struct snd_sof_pcm *spcm;
 	int ret, err = 0;
 
@@ -304,10 +287,13 @@ static int sof_pcm_hw_free(struct snd_soc_component *component,
 		spcm->pcm.pcm_id, substream->stream);
 
 	/* free PCM in the DSP */
-	ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm);
-	if (ret < 0)
-		err = ret;
+	if (pcm_ops->hw_free && spcm->prepared[substream->stream]) {
+		ret = pcm_ops->hw_free(component, substream);
+		if (ret < 0)
+			err = ret;
 
+		spcm->prepared[substream->stream] = false;
+	}
 
 	/* stop DMA */
 	ret = snd_sof_pcm_platform_hw_free(sdev, substream);
diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c
index 7aa4ac313de3..5088ec7019ed 100644
--- a/sound/soc/sof/sof-audio.c
+++ b/sound/soc/sof/sof-audio.c
@@ -591,12 +591,17 @@ int sof_set_up_pipelines(struct snd_sof_dev *sdev, bool verify)
 int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream,
 			struct snd_sof_pcm *spcm, int dir, bool free_widget_list)
 {
+	const struct sof_ipc_pcm_ops *pcm_ops = sdev->ipc->ops->pcm;
 	int ret;
 
 	/* Send PCM_FREE IPC to reset pipeline */
-	ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm);
-	if (ret < 0)
-		return ret;
+	if (pcm_ops->hw_free && spcm->prepared[substream->stream]) {
+		ret = pcm_ops->hw_free(sdev->component, substream);
+		if (ret < 0)
+			return ret;
+	}
+
+	spcm->prepared[substream->stream] = false;
 
 	/* stop the DMA */
 	ret = snd_sof_pcm_platform_hw_free(sdev, substream);
-- 
2.35.3