ASoC: SOF: Introduce IPC3 PCM hw_free op
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>
This commit is contained in:
parent
442c712821
commit
4123c24bd1
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
};
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue