Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions drivers/soundwire/intel.c
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,25 @@ static int intel_params_stream(struct sdw_intel *sdw,
* DAI routines
*/

static int intel_free_stream(struct sdw_intel *sdw,
struct snd_pcm_substream *substream,
struct snd_soc_dai *dai,
int link_id)
{
struct sdw_intel_link_res *res = sdw->link_res;
struct sdw_intel_stream_free_data free_data;

free_data.substream = substream;
free_data.dai = dai;
free_data.link_id = link_id;

if (res->ops && res->ops->free_stream && res->dev)
return res->ops->free_stream(res->dev,
&free_data);

return 0;
}

static int intel_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
Expand Down Expand Up @@ -831,6 +850,7 @@ static int
intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
struct sdw_intel *sdw = cdns_to_intel(cdns);
struct sdw_cdns_dai_runtime *dai_runtime;
int ret;

Expand All @@ -851,6 +871,12 @@ intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
return ret;
}

ret = intel_free_stream(sdw, substream, dai, sdw->instance);
if (ret < 0) {
dev_err(dai->dev, "intel_free_stream: failed %d\n", ret);
return ret;
}

dai_runtime->pdi = NULL;

return 0;
Expand Down
6 changes: 6 additions & 0 deletions sound/soc/sof/intel/hda-dai-ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,12 @@ static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *c
* been stopped. So, clear the started_count so that the pipeline can be reset
*/
swidget->spipe->started_count = 0;

ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
SOF_IPC4_PIPE_RESET);
if (ret < 0)
goto out;
pipeline->state = SOF_IPC4_PIPE_RESET;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
break;
Expand Down
28 changes: 28 additions & 0 deletions sound/soc/sof/intel/hda.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "../sof-audio.h"
#include "../sof-pci-dev.h"
#include "../ops.h"
#include "../ipc4-topology.h"
#include "hda.h"

#include <trace/events/sof_intel.h>
Expand Down Expand Up @@ -68,8 +69,35 @@ static int sdw_params_stream(struct device *dev,
return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_PARAMS, &data);
}

static int sdw_params_free(struct device *dev, struct sdw_intel_stream_free_data *free_data)
{
struct snd_soc_dai *d = free_data->dai;
struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(d, free_data->substream->stream);
struct snd_sof_widget *swidget = w->dobj.private;
struct snd_soc_component *component = swidget->scomp;
struct snd_sof_dai *dai = swidget->private;
struct sof_ipc4_copier_data *copier_data;
struct sof_ipc4_copier *ipc4_copier;
struct snd_sof_dev *sdev;

sdev = snd_soc_component_get_drvdata(component);

if (sdev->pdata->ipc_type != SOF_IPC_TYPE_4)
return 0;

ipc4_copier = dai->private;
ipc4_copier->dai_index = 0;
copier_data = &ipc4_copier->data;

/* clear the node ID */
copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;

return 0;
}

struct sdw_intel_ops sdw_callback = {
.params_stream = sdw_params_stream,
.free_stream = sdw_params_free,
};

static int sdw_ace2x_params_stream(struct device *dev,
Expand Down
11 changes: 5 additions & 6 deletions sound/soc/sof/ipc4-pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ sof_ipc4_add_pipeline_to_trigger_list(struct snd_sof_dev *sdev, int state,
struct snd_sof_widget *pipe_widget = spipe->pipe_widget;
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;

if (pipeline->skip_during_fe_trigger && state != SOF_IPC4_PIPE_RESET)
if (pipeline->skip_during_fe_trigger)
return;

switch (state) {
Expand Down Expand Up @@ -136,7 +136,7 @@ sof_ipc4_update_pipeline_state(struct snd_sof_dev *sdev, int state, int cmd,
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
int i;

if (pipeline->skip_during_fe_trigger && state != SOF_IPC4_PIPE_RESET)
if (pipeline->skip_during_fe_trigger)
return;

/* set state for pipeline if it was just triggered */
Expand Down Expand Up @@ -485,8 +485,8 @@ static int sof_ipc4_pcm_trigger(struct snd_soc_component *component,
return sof_ipc4_trigger_pipelines(component, substream, state, cmd);
}

static int sof_ipc4_pcm_hw_free(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
static int sof_ipc4_pcm_post_trigger(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
/* command is not relevant with RESET, so just pass 0 */
return sof_ipc4_trigger_pipelines(component, substream, SOF_IPC4_PIPE_RESET, 0);
Expand Down Expand Up @@ -937,11 +937,10 @@ static snd_pcm_sframes_t sof_ipc4_pcm_delay(struct snd_soc_component *component,
const struct sof_ipc_pcm_ops ipc4_pcm_ops = {
.hw_params = sof_ipc4_pcm_hw_params,
.trigger = sof_ipc4_pcm_trigger,
.hw_free = sof_ipc4_pcm_hw_free,
.dai_link_fixup = sof_ipc4_pcm_dai_link_fixup,
.pcm_setup = sof_ipc4_pcm_setup,
.pcm_free = sof_ipc4_pcm_free,
.delay = sof_ipc4_pcm_delay,
.ipc_first_on_start = true,
.platform_stop_during_hw_free = true,
.post_trigger = sof_ipc4_pcm_post_trigger,
};
17 changes: 11 additions & 6 deletions sound/soc/sof/ipc4-topology.c
Original file line number Diff line number Diff line change
Expand Up @@ -1277,7 +1277,6 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
}

if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
struct sof_ipc4_copier_data *copier_data = &ipc4_copier->data;
struct sof_ipc4_alh_configuration_blob *blob;
unsigned int group_id;

Expand All @@ -1287,9 +1286,6 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
ALH_MULTI_GTW_BASE;
ida_free(&alh_group_ida, group_id);
}

/* clear the node ID */
copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
}
}

Expand Down Expand Up @@ -1717,14 +1713,20 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
*/
i = 0;
list_for_each_entry(w, &sdev->widget_list, list) {
u32 node_type;

if (w->widget->sname &&
strcmp(w->widget->sname, swidget->widget->sname))
continue;

dai = w->private;
alh_copier = (struct sof_ipc4_copier *)dai->private;
alh_data = &alh_copier->data;
blob->alh_cfg.mapping[i].device = alh_data->gtw_cfg.node_id;
node_type = SOF_IPC4_GET_NODE_TYPE(alh_data->gtw_cfg.node_id);
blob->alh_cfg.mapping[i].device =
SOF_IPC4_GET_NODE_TYPE(node_type);
blob->alh_cfg.mapping[i].device |=
SOF_IPC4_NODE_INDEX(alh_copier->dai_index);

/*
* The mapping[i] device in ALH blob should be the same as the
Expand Down Expand Up @@ -2843,12 +2845,15 @@ static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *
/*
* Do not clear the node ID when this op is invoked with
* SOF_DAI_CONFIG_FLAGS_HW_FREE. It is needed to free the group_ida during
* unprepare.
* unprepare. The node_id for multi-gateway DAI's will be overwritten with the
* group_id during copier's ipc_prepare op.
*/
if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) {
ipc4_copier->dai_index = data->dai_node_id;
copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_node_id);
}

break;
case SOF_DAI_INTEL_DMIC:
case SOF_DAI_INTEL_SSP:
Expand Down
1 change: 1 addition & 0 deletions sound/soc/sof/ipc4-topology.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#define SOF_IPC4_NODE_INDEX_MASK 0xFF
#define SOF_IPC4_NODE_INDEX(x) ((x) & SOF_IPC4_NODE_INDEX_MASK)
#define SOF_IPC4_NODE_TYPE(x) ((x) << 8)
#define SOF_IPC4_GET_NODE_TYPE(node_id) ((node_id) >> 8)

/* Node ID for SSP type DAI copiers */
#define SOF_IPC4_NODE_INDEX_INTEL_SSP(x) (((x) & 0xf) << 4)
Expand Down
50 changes: 29 additions & 21 deletions sound/soc/sof/pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
}

spcm->prepared[substream->stream] = true;
spcm->stream_stopped[substream->stream] = false;

/* save pcm hw_params */
memcpy(&spcm->params[substream->stream], params, sizeof(*params));
Expand All @@ -196,7 +197,6 @@ static int sof_pcm_hw_free(struct snd_soc_component *component,
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
struct snd_sof_pcm *spcm;
int ret, err = 0;

Expand All @@ -211,21 +211,6 @@ static int sof_pcm_hw_free(struct snd_soc_component *component,
dev_dbg(component->dev, "pcm: free stream %d dir %d\n",
spcm->pcm.pcm_id, substream->stream);

if (spcm->prepared[substream->stream]) {
/* stop DMA first if needed */
if (pcm_ops && pcm_ops->platform_stop_during_hw_free)
snd_sof_pcm_platform_trigger(sdev, substream, SNDRV_PCM_TRIGGER_STOP);

/* free PCM in the DSP */
if (pcm_ops && pcm_ops->hw_free) {
ret = pcm_ops->hw_free(component, substream);
if (ret < 0)
err = ret;
}

spcm->prepared[substream->stream] = false;
}

/* reset DMA */
ret = snd_sof_pcm_platform_hw_free(sdev, substream);
if (ret < 0) {
Expand All @@ -238,6 +223,9 @@ static int sof_pcm_hw_free(struct snd_soc_component *component,
if (ret < 0)
err = ret;

spcm->prepared[substream->stream] = false;
spcm->stream_stopped[substream->stream] = false;

cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work);

return err;
Expand All @@ -247,6 +235,7 @@ static int sof_pcm_prepare(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
struct snd_sof_pcm *spcm;
int ret;

Expand All @@ -258,8 +247,16 @@ static int sof_pcm_prepare(struct snd_soc_component *component,
if (!spcm)
return -EINVAL;

if (spcm->prepared[substream->stream])
return 0;
if (spcm->prepared[substream->stream]) {
/* reset DMA and free widget lists to start over */
if (spcm->stream_stopped[substream->stream]) {
ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream, true);
if (ret < 0)
return ret;
} else {
return 0;
}
}

dev_dbg(component->dev, "pcm: prepare stream %d dir %d\n",
spcm->pcm.pcm_id, substream->stream);
Expand Down Expand Up @@ -367,9 +364,20 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_STOP:
/* invoke platform trigger to stop DMA even if pcm_ops isn't set or if it failed */
if (!pcm_ops || !pcm_ops->platform_stop_during_hw_free)
snd_sof_pcm_platform_trigger(sdev, substream, cmd);
/* always invoke platform trigger to stop DMA */
snd_sof_pcm_platform_trigger(sdev, substream, cmd);

/* nothing more to do for DSP-less mode */
if (!pcm_ops || cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH)
break;

/* For IPC4, reset pipelines after stopping DMA */
if (pcm_ops->post_trigger) {
ret = pcm_ops->post_trigger(sdev->component, substream);
if (ret < 0)
return ret;
spcm->stream_stopped[substream->stream] = true;
}
break;
default:
break;
Expand Down
20 changes: 7 additions & 13 deletions sound/soc/sof/sof-audio.c
Original file line number Diff line number Diff line change
Expand Up @@ -835,19 +835,10 @@ int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *subs
const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
int ret;

if (spcm->prepared[substream->stream]) {
/* stop DMA first if needed */
if (pcm_ops && pcm_ops->platform_stop_during_hw_free)
snd_sof_pcm_platform_trigger(sdev, substream, SNDRV_PCM_TRIGGER_STOP);

/* Send PCM_FREE IPC to reset pipeline */
if (pcm_ops && pcm_ops->hw_free) {
ret = pcm_ops->hw_free(sdev->component, substream);
if (ret < 0)
return ret;
}

spcm->prepared[substream->stream] = false;
if (pcm_ops && pcm_ops->hw_free) {
ret = pcm_ops->hw_free(sdev->component, substream);
if (ret < 0)
return ret;
}

/* reset the DMA */
Expand All @@ -862,6 +853,9 @@ int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *subs
dev_err(sdev->dev, "failed to free widgets during suspend\n");
}

spcm->prepared[substream->stream] = false;
spcm->stream_stopped[substream->stream] = false;

return ret;
}

Expand Down
10 changes: 4 additions & 6 deletions sound/soc/sof/sof-audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,16 +104,12 @@ struct snd_sof_dai_config_data {
* additional memory in the SOF PCM stream structure
* @pcm_free: Function pointer for PCM free that can be used for freeing any
* additional memory in the SOF PCM stream structure
* @post_trigger: Op to perform operations after platform trigger has been completed
* @delay: Function pointer for pcm delay calculation
* @reset_hw_params_during_stop: Flag indicating whether the hw_params should be reset during the
* STOP pcm trigger
* @ipc_first_on_start: Send IPC before invoking platform trigger during
* START/PAUSE_RELEASE triggers
* @platform_stop_during_hw_free: Invoke the platform trigger during hw_free. This is needed for
* IPC4 where a pipeline is only paused during stop/pause/suspend
* triggers. The FW keeps the host DMA running in this case and
* therefore the host must do the same and should stop the DMA during
* hw_free.
* @d0i3_supported_in_s0ix: Allow DSP D0I3 during S0iX
*/
struct sof_ipc_pcm_ops {
Expand All @@ -126,11 +122,12 @@ struct sof_ipc_pcm_ops {
int (*dai_link_fixup)(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params);
int (*pcm_setup)(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm);
void (*pcm_free)(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm);
int (*post_trigger)(struct snd_soc_component *component,
struct snd_pcm_substream *substream);
snd_pcm_sframes_t (*delay)(struct snd_soc_component *component,
struct snd_pcm_substream *substream);
bool reset_hw_params_during_stop;
bool ipc_first_on_start;
bool platform_stop_during_hw_free;
bool d0i3_supported_in_s0ix;
};

Expand Down Expand Up @@ -344,6 +341,7 @@ struct snd_sof_pcm {
struct list_head list; /* list in sdev pcm list */
struct snd_pcm_hw_params params[2];
bool prepared[2]; /* PCM_PARAMS set successfully */
bool stream_stopped[2]; /* only used with pcm_ops->post_trigger */
};

struct snd_sof_led_control {
Expand Down