From 4b3bb988b3b3caac0ab91d5822dd660c82640954 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 14 Feb 2024 08:35:30 -0800 Subject: [PATCH 1/5] ASoC: SOF: pcm: Always stop DMA in the case of stop trigger Make sure to stop the DMA and stop/reset the pipelines during the stop trigger for IPC4. In the case of IPC4, pipelines must be paused before they are reset. So, add a post_trigger op in struct sof_pcm_ops that can be called after stopping the DMA to reset the pipelines. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-dai-ops.c | 6 ++++++ sound/soc/sof/ipc4-pcm.c | 11 +++++----- sound/soc/sof/pcm.c | 35 ++++++++++++++----------------- sound/soc/sof/sof-audio.c | 19 ++++++----------- sound/soc/sof/sof-audio.h | 9 +++----- 5 files changed, 36 insertions(+), 44 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index 01e5f0617ae5b9..8713659edbe791 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -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; diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 0f332c8cdbe6af..d5548f0267894a 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -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) { @@ -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 */ @@ -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); @@ -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, }; diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 2f86aef4bc9c08..ad12e28b9a4c00 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -196,7 +196,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; @@ -211,21 +210,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) { @@ -238,6 +222,8 @@ static int sof_pcm_hw_free(struct snd_soc_component *component, if (ret < 0) err = ret; + spcm->prepared[substream->stream] = false; + cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work); return err; @@ -367,9 +353,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; + } + break; default: break; diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index e693dcb475e4d6..dd05fef62e9465 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -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 */ @@ -862,6 +853,8 @@ 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; + return ret; } diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 64158ee6c3a839..f6d1be0d507a30 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -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 { @@ -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; }; From 47cb14fa7e02e638ccd996243f78cbb6aebc2cef Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 13 Feb 2024 14:29:34 -0600 Subject: [PATCH 2/5] ASoC: SOF: pcm: add stream_stopped state variable Add a state variable to keep track of whether a stream is previously stopped. It is meant to be set only if the post-trigger op is also set. This patch should be iso-functionality, possibly removing no-op cases. The main purpose of this new state variable is to prepare a follow-up patch to reset all PCM and DMAs in case of stop/prepare xrun sequences. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pcm.c | 4 +++- sound/soc/sof/sof-audio.c | 1 + sound/soc/sof/sof-audio.h | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index ad12e28b9a4c00..2db3f78f2a20d6 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -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)); @@ -223,6 +224,7 @@ static int sof_pcm_hw_free(struct snd_soc_component *component, err = ret; spcm->prepared[substream->stream] = false; + spcm->stream_stopped[substream->stream] = false; cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work); @@ -365,8 +367,8 @@ static int sof_pcm_trigger(struct snd_soc_component *component, ret = pcm_ops->post_trigger(sdev->component, substream); if (ret < 0) return ret; + spcm->stream_stopped[substream->stream] = true; } - break; default: break; diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index dd05fef62e9465..91fd858b1bb30e 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -854,6 +854,7 @@ int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *subs } spcm->prepared[substream->stream] = false; + spcm->stream_stopped[substream->stream] = false; return ret; } diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index f6d1be0d507a30..f05a4af4120594 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -341,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 { From c5fa198f0cf2863fa67e3609af0eeedd0e8d1fa1 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 15 Feb 2024 10:13:23 -0800 Subject: [PATCH 3/5] ASoC: SOF: pcm: Free everything in case of xruns Just stopping the DMA and resetting the pipelines during stop isn't enough in the case of xruns. So, reset the DMA and free all widgets to start over from a clean state. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pcm.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 2db3f78f2a20d6..2adcf852953494 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -235,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; @@ -246,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); From aeecb5f9edbd4a65b2d2f0781c7f3be87bcfe778 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 15 Feb 2024 10:23:24 -0800 Subject: [PATCH 4/5] ASoC: SOF: Intel: hda: Clear Soundwire node ID during BE DAI hw_free When an xrun happens, the BE DAI hw_params doesn't get invoked before the stream restarts with a prepare. In this case, clearing the node ID when the DAI widget is freed and unprepared will result in an error when it is re-initialized. In order to avoid this, bring back the free_stream ops for ACE1x platforms and move the code to clear the node ID to this op to keep it balanced with the BE DAI hw_params. Signed-off-by: Ranjani Sridharan --- drivers/soundwire/intel.c | 26 ++++++++++++++++++++++++++ sound/soc/sof/intel/hda.c | 27 +++++++++++++++++++++++++++ sound/soc/sof/ipc4-topology.c | 4 ---- 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index e15666962fe49d..f7b856fea15194 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -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) @@ -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; @@ -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; diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 66126fb31d52db..7fd0f24f9464c8 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -31,6 +31,7 @@ #include "../sof-audio.h" #include "../sof-pci-dev.h" #include "../ops.h" +#include "../ipc4-topology.h" #include "hda.h" #include @@ -68,8 +69,34 @@ 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; + 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, diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index f05b000f1d9dc8..a288dd04bdcfc0 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -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; @@ -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; } } From 0b6c36d2a7ebb6b0d2928146a9b1eb0aaf082fac Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 15 Feb 2024 16:37:07 -0800 Subject: [PATCH 5/5] ASoC: SOF: ipc4-topology: Save the ALH DAI index during hw_params The node_id for multi-gateway ALH DAI's get overwritten with the group_id during the DAI copier's ipc_prepare op. So, save the ALH dai_index during the BE DAI hw_params in the dai_index field of struct ipc4_copier and use that to set the device ID in the configuration blob. This will avoid errors during copier init after an xrun. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda.c | 1 + sound/soc/sof/ipc4-topology.c | 13 +++++++++++-- sound/soc/sof/ipc4-topology.h | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 7fd0f24f9464c8..887feacc993008 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -86,6 +86,7 @@ static int sdw_params_free(struct device *dev, struct sdw_intel_stream_free_data return 0; ipc4_copier = dai->private; + ipc4_copier->dai_index = 0; copier_data = &ipc4_copier->data; /* clear the node ID */ diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index a288dd04bdcfc0..1749e74c66ad59 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1713,6 +1713,8 @@ 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; @@ -1720,7 +1722,11 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, 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 @@ -2839,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: diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h index aa5122c3721d3a..6e33208a357f5d 100644 --- a/sound/soc/sof/ipc4-topology.h +++ b/sound/soc/sof/ipc4-topology.h @@ -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)