Skip to content

Commit

Permalink
ASoC: SOF: Introduce IPC3 PCM hw_free op
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Ranjani Sridharan authored and Mark Brown committed Mar 18, 2022
1 parent 442c712 commit 4123c24
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 35 deletions.
2 changes: 1 addition & 1 deletion sound/soc/sof/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions sound/soc/sof/ipc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
1 change: 1 addition & 0 deletions sound/soc/sof/ipc3-ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
43 changes: 43 additions & 0 deletions sound/soc/sof/ipc3-pcm.c
Original file line number Diff line number Diff line change
@@ -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,
};
1 change: 1 addition & 0 deletions sound/soc/sof/ipc3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
44 changes: 15 additions & 29 deletions sound/soc/sof/pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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;

Expand All @@ -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);
Expand Down
11 changes: 8 additions & 3 deletions sound/soc/sof/sof-audio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 4123c24

Please sign in to comment.