From b5200239c73d1aabfb81290b6464b8b6bc342ee0 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 18 Nov 2022 08:21:38 +0200 Subject: [PATCH 01/83] -- old sof-dev -- From 6130b7e21809ac65d44ed573ae794ce9f1157ceb Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 2 Jun 2026 12:31:13 +0300 Subject: [PATCH 02/83] ASoC: SOF: sof-audio: Fix error path in sof_widget_setup_unlocked() If either tplg_ops->dai_config or widget_kcontrol_setup fail during widget setup we would double decrement the use_count of the widget because the sof_widget_free_unlocked() would be called twice, similarly the core_put would be invoked twice as well. Since the use_count and core_put() is handled within the widget_free function we need to return without falling through the pipe_widget_free label. The fixes tag is picked to the last change around this part of the code which is adequately old enough for backporting purposes. Link: https://github.com/thesofproject/sof/issues/10826 Fixes: 31ed8da1c8e5 ("ASoC: SOF: sof-audio: Modify logic for enabling/disabling topology cores") Signed-off-by: Peter Ujfalusi --- sound/soc/sof/sof-audio.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index acf56607bc9c11..24614e50601932 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -146,7 +146,6 @@ static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev, { const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_sof_pipeline *spipe = swidget->spipe; - bool use_count_decremented = false; int ret; int i; @@ -225,9 +224,10 @@ static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev, return 0; widget_free: - /* widget use_count will be decremented by sof_widget_free() */ + /* widget use_count and core_put handled by sof_widget_free() */ sof_widget_free_unlocked(sdev, swidget); - use_count_decremented = true; + return ret; + pipe_widget_free: if (swidget->id != snd_soc_dapm_scheduler) { sof_widget_free_unlocked(sdev, swidget->spipe->pipe_widget); @@ -242,8 +242,7 @@ static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev, } } use_count_dec: - if (!use_count_decremented) - swidget->use_count--; + swidget->use_count--; return ret; } From 617da5e792c7ec63976e9c6b1579f9afbfcdf526 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 8 Jun 2026 17:05:53 +0300 Subject: [PATCH 03/83] ASoC: SOF: sof-client: Use event-handler mutex consistently Protect IPC RX and FW state handler list unregister/dispatch paths with client_event_handler_mutex to match list registration and locking comments. Fixes: 5c19da34df02 ("ASoC: SOF: Use guard()/scoped_guard() for mutex locks where it makes sense") Signed-off-by: Peter Ujfalusi --- sound/soc/sof/sof-client.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/sof-client.c b/sound/soc/sof/sof-client.c index a90d8243d71a7a..4f3ffceacb5873 100644 --- a/sound/soc/sof/sof-client.c +++ b/sound/soc/sof/sof-client.c @@ -612,7 +612,7 @@ void sof_client_unregister_ipc_rx_handler(struct sof_client_dev *cdev, struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); struct sof_ipc_event_entry *event; - guard(mutex)(&sdev->ipc_client_mutex); + guard(mutex)(&sdev->client_event_handler_mutex); list_for_each_entry(event, &sdev->ipc_rx_handler_list, list) { if (event->cdev == cdev && event->ipc_msg_type == ipc_msg_type) { @@ -629,7 +629,7 @@ void sof_client_fw_state_dispatcher(struct snd_sof_dev *sdev) { struct sof_state_event_entry *event; - guard(mutex)(&sdev->ipc_client_mutex); + guard(mutex)(&sdev->client_event_handler_mutex); list_for_each_entry(event, &sdev->fw_state_handler_list, list) event->callback(event->cdev, sdev->fw_state); @@ -664,7 +664,7 @@ void sof_client_unregister_fw_state_handler(struct sof_client_dev *cdev) struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); struct sof_state_event_entry *event; - guard(mutex)(&sdev->ipc_client_mutex); + guard(mutex)(&sdev->client_event_handler_mutex); list_for_each_entry(event, &sdev->fw_state_handler_list, list) { if (event->cdev == cdev) { From 6c88f4d80d62cb582e81fd6529609c7621ed1d15 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 11 Jun 2026 09:20:33 +0300 Subject: [PATCH 04/83] ASoC: SOF: IPC4: fix reversed pipeline trigger priority order The IPC4 definition of pipeline prioity is: 0 - highest priority 7 - lowest priority RUNNING should use ascending order (highest priority first), otherwise descending order (lowest priority first) should be used. Fixes: 4df7d6a61f2c ("ASoC: SOF: IPC4: sort pipeline based on priority") Cc: stable@vger.kernel.org Signed-off-by: Peter Ujfalusi --- sound/soc/sof/ipc4-pcm.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 5929ecf6642ee3..318f5262d01451 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -148,11 +148,12 @@ static void sof_ipc4_add_pipeline_by_priority(struct ipc4_pipeline_set_state_dat struct sof_ipc4_pipeline *pipeline = pipe_widget->private; int i, j; + /* 0 = highest priority, 7 = lowest */ for (i = 0; i < trigger_list->count; i++) { - /* add pipeline from low priority to high */ + /* ascend=true: sort ascending [0,1,2...] = highest priority first */ if (ascend && pipeline->priority < pipe_priority[i]) break; - /* add pipeline from high priority to low */ + /* ascend=false: sort descending [7,6,5...] = lowest priority first */ else if (!ascend && pipeline->priority > pipe_priority[i]) break; } @@ -187,19 +188,19 @@ sof_ipc4_add_pipeline_to_trigger_list(struct snd_sof_dev *sdev, int state, */ if (spipe->started_count == spipe->paused_count) sof_ipc4_add_pipeline_by_priority(trigger_list, pipe_widget, pipe_priority, - false); + true); break; case SOF_IPC4_PIPE_RESET: /* RESET if the pipeline is neither running nor paused */ if (!spipe->started_count && !spipe->paused_count) sof_ipc4_add_pipeline_by_priority(trigger_list, pipe_widget, pipe_priority, - true); + false); break; case SOF_IPC4_PIPE_PAUSED: /* Pause the pipeline only when its started_count is 1 more than paused_count */ if (spipe->paused_count == (spipe->started_count - 1)) sof_ipc4_add_pipeline_by_priority(trigger_list, pipe_widget, pipe_priority, - true); + false); break; default: break; From d2b1e1801c04463c8c785e51625de76cbf0abf10 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 29 Apr 2025 10:22:52 +0300 Subject: [PATCH 05/83] ASoC: SOF: ipc4-topology: Propagate change caused by NHLT data for SSP We need to adjust the params based on the available and picked SSP blob in the similar way we do for DMIC. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/ipc4-topology.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 2b12954b89b8fa..a4d1d98904e18f 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1823,6 +1823,12 @@ snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai dai_index); if (dev_type < 0) return dev_type; + + if (params_width(params) != bit_depth) { + format_change = true; + dev_dbg(sdev->dev, "SSP sample width change from %d to %d\n", + params_width(params), bit_depth); + } break; default: return 0; From 45fce8f189c3619130096268d4b40251342d5b0a Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 29 Apr 2025 09:38:56 +0300 Subject: [PATCH 06/83] ASoC: SOF: ipc4-topology: Improve playback dai copier in/out format selection The dai copier configuration for playback and capture needs to be separated because it is not correct to configure the dai copier as part of the input format selection for both direction. The input format is the dai format for capture, but it is not for playback, for playback the dai format is on the output side. Currently we configure and adjust the params based on the DAI supported formats when configuring the input side of the copier but right after the format has been adjusted we reset it for playback and loose this information. When using a nocodec passthrough topology (which is a bug) we have SSP blobs supporting 32bit only, copier supporting 16/24/32 bit then on playback the dai and copier will be incorrectly configured: host.copier.in: S16_LE host.copier.out: S16_LE dai.copier.in: S16_LE SSP.blob: S32_LE (we only have S32_LE blobs) dai.copier.out: S16_LE (the dai constraint is ignored) To handle such case the handling of capture and playback streams must be changed: The input format (no changes to previous implementation): for playback it is the pipeline_params for capture it is the adjusted fe_params The output format (no change for capture direction): for playback it is the adjusted fe_params for capture it is the fe_params with this change path format configuration will be correct: host.copier.in: S16_LE host.copier.out: S16_LE dai.copier.in: S16_LE SSP.blob: S32_LE (we only have S32_LE blobs) dai.copier.out: S32_LE Signed-off-by: Peter Ujfalusi --- sound/soc/sof/ipc4-topology.c | 72 +++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 25 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index a4d1d98904e18f..53aa9ed56fef59 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -2193,28 +2193,32 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, copier_data = &ipc4_copier->data; available_fmt = &ipc4_copier->available_fmt; - /* - * Use the fe_params as a base for the copier configuration. - * The ref_params might get updated to reflect what format is - * supported by the copier on the DAI side. - * - * In case of capture the ref_params returned will be used to - * find the input configuration of the copier. - */ - ref_params = kmemdup(fe_params, sizeof(*ref_params), GFP_KERNEL); - if (!ref_params) - return -ENOMEM; - - ret = sof_ipc4_prepare_dai_copier(sdev, dai, ref_params, dir); - if (ret < 0) - return ret; + if (dir == SNDRV_PCM_STREAM_PLAYBACK) { + /* + * For playback the pipeline_params needs to be used to + * find the input configuration of the copier. + */ + ref_params = kmemdup(pipeline_params, sizeof(*ref_params), + GFP_KERNEL); + if (!ref_params) + return -ENOMEM; + } else { + /* + * For capture the adjusted fe_params needs to be used + * to find the input configuration of the copier. + * + * The params might be updated in + * sof_ipc4_prepare_dai_copier() to reflect the supported + * input formats by the copier/dai. + */ + ref_params = kmemdup(fe_params, sizeof(*ref_params), GFP_KERNEL); + if (!ref_params) + return -ENOMEM; - /* - * For playback the pipeline_params needs to be used to find the - * input configuration of the copier. - */ - if (dir == SNDRV_PCM_STREAM_PLAYBACK) - memcpy(ref_params, pipeline_params, sizeof(*ref_params)); + ret = sof_ipc4_prepare_dai_copier(sdev, dai, ref_params, dir); + if (ret < 0) + return ret; + } break; } @@ -2269,15 +2273,33 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, } case snd_soc_dapm_aif_out: case snd_soc_dapm_dai_in: - out_ref_rate = params_rate(fe_params); - out_ref_channels = params_channels(fe_params); - ret = sof_ipc4_get_sample_type(sdev, fe_params); + /* + * For capture the fe_params needs to be used to find the output + * configuration of the copier. + * + * For playback the adjusted fe_params needs to be used + * to find the output configuration of the copier. + * + * The params might be updated in + * sof_ipc4_prepare_dai_copier() to reflect the supported + * output formats by the copier/dai. + */ + memcpy(ref_params, fe_params, sizeof(*ref_params)); + if (dir == SNDRV_PCM_STREAM_PLAYBACK) { + ret = sof_ipc4_prepare_dai_copier(sdev, dai, ref_params, dir); + if (ret < 0) + return ret; + } + + out_ref_rate = params_rate(ref_params); + out_ref_channels = params_channels(ref_params); + ret = sof_ipc4_get_sample_type(sdev, ref_params); if (ret < 0) return ret; out_ref_type = (u32)ret; if (!single_output_bitdepth) { - out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params); + out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, ref_params); if (out_ref_valid_bits < 0) return out_ref_valid_bits; } From 313844621465505d66e11bced5d6e4f3b19a8ff7 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 26 Aug 2025 17:20:01 +0300 Subject: [PATCH 07/83] ASoC: SOF: Intel: Make sure that link and host DMA is coupled after use Couple the Host and Link DMA when the stream is put. When the hda_dsp_stream_hw_free() is called the Link DMA might be still locked and we would leave the DMAs decoupled. hda_dsp_stream_hw_free() is not called for code loader use or in case of probes or trace use for example. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/intel/hda-stream.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 6c4447f52c681a..fae7a669924562 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -293,9 +293,8 @@ static int _hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stre { const struct sof_intel_dsp_desc *chip_info = get_chip_info(sdev->pdata); struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + struct hdac_ext_stream *hext_stream_match = NULL; struct hdac_bus *bus = sof_to_bus(sdev); - struct sof_intel_hda_stream *hda_stream; - struct hdac_ext_stream *hext_stream; struct hdac_ext_stream *link_stream; struct hdac_stream *s; bool dmi_l1_enable = true; @@ -308,6 +307,9 @@ static int _hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stre * that are DMI L1 incompatible. */ list_for_each_entry(s, &bus->stream_list, list) { + struct sof_intel_hda_stream *hda_stream; + struct hdac_ext_stream *hext_stream; + hext_stream = stream_to_hdac_ext_stream(s); hda_stream = container_of(hext_stream, struct sof_intel_hda_stream, hext_stream); @@ -315,6 +317,7 @@ static int _hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stre continue; if (s->direction == direction && s->stream_tag == stream_tag) { + hext_stream_match = hext_stream; s->opened = false; found = true; if (pair) @@ -324,6 +327,20 @@ static int _hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stre } } + if (!sdev->dspless_mode_selected && !pair && hext_stream_match) { + /* + * Couple host and link DMA if link DMA is unused + * In case of channel pair the snd_hdac_ext_stream_release() will + * take care of coupling te HDA channel. + */ + if (!hext_stream_match->link_locked) { + u32 mask = BIT(hext_stream_match->hstream.index); + + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, + SOF_HDA_REG_PP_PPCTL, mask, 0); + } + } + spin_unlock_irq(&bus->reg_lock); /* Enable DMI L1 if permitted */ From f18cc6de90a7d56b2808b468d3090cc4a850b9b0 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 27 May 2025 20:23:06 +0800 Subject: [PATCH 08/83] soundwire: stream: wait initialization_complete in sdw_stream_add_slave Programing SoundWire registers are required for stream process. And we can only program then after the peripheral is attached and initialized. Currently, we wait initialization_complete in codec resume. To reduce the resume time, we will remove the waiting from codec resume in the follow up commits. Signed-off-by: Bard Liao --- drivers/soundwire/stream.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index cbf7bd3d4e7bac..dbbcb3122fb440 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -2124,6 +2124,8 @@ int sdw_stream_remove_master(struct sdw_bus *bus, } EXPORT_SYMBOL(sdw_stream_remove_master); +#define CODEC_INIT_TIMEOUT 500 + /** * sdw_stream_add_slave() - Allocate and add master/slave runtime to a stream * @@ -2147,9 +2149,19 @@ int sdw_stream_add_slave(struct sdw_slave *slave, struct sdw_master_runtime *m_rt; bool alloc_master_rt = false; bool alloc_slave_rt = false; + unsigned long time; int ret; + time = wait_for_completion_timeout(&slave->initialization_complete, + msecs_to_jiffies(CODEC_INIT_TIMEOUT)); + if (!time) { + dev_err(&slave->dev, "%s: Initialization not complete, timed out\n", __func__); + sdw_show_ping_status(slave->bus, true); + + return -ETIMEDOUT; + } + mutex_lock(&slave->bus->bus_lock); /* From 795467781dd097bc6a8162ac92a26a69f1e0d84e Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 3 Jun 2025 09:19:41 +0300 Subject: [PATCH 09/83] ASoC: SOF: ipc4-topology: Store the params change between input/output of a module Based on the input and output formats we can evaluate what param might be changed by the module instance. If there is a difference between the input rate/channels/format and the output rate/channels/format it means that the module can change one or multiple of the params. Store this information during init for later use. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/ipc4-topology.c | 41 +++++++++++++++++++++++++++++++++++ sound/soc/sof/ipc4-topology.h | 3 +++ 2 files changed, 44 insertions(+) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 53aa9ed56fef59..63fcd15be70b65 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -406,6 +406,39 @@ sof_ipc4_get_input_pin_audio_fmt(struct snd_sof_widget *swidget, int pin_index) return NULL; } +static void +sof_ipc4_evaluate_params_change(struct sof_ipc4_available_audio_format *available_fmt) +{ + struct sof_ipc4_audio_format *fmt; + u32 in_rate, in_channels, in_valid_bits; + u32 out_rate, out_channels, out_valid_bits; + u32 changed_params = 0; + int i, j; + + for (i = 0; i < available_fmt->num_input_formats; i++) { + fmt = &available_fmt->input_pin_fmts[i].audio_fmt; + in_rate = fmt->sampling_frequency; + in_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg); + in_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); + + for (j = 0; j < available_fmt->num_output_formats; j++) { + fmt = &available_fmt->output_pin_fmts[j].audio_fmt; + out_rate = fmt->sampling_frequency; + out_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg); + out_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); + + if (in_rate != out_rate) + changed_params |= BIT(SNDRV_PCM_HW_PARAM_RATE); + if (in_channels != out_channels) + changed_params |= BIT(SNDRV_PCM_HW_PARAM_CHANNELS); + if (in_valid_bits != out_valid_bits) + changed_params |= BIT(SNDRV_PCM_HW_PARAM_FORMAT); + } + } + + available_fmt->changed_params = changed_params; +} + /** * sof_ipc4_get_audio_fmt - get available audio formats from swidget->tuples * @scomp: pointer to pointer to SOC component @@ -497,6 +530,8 @@ static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp, available_fmt->num_output_formats); } + sof_ipc4_evaluate_params_change(available_fmt); + return 0; err_out: @@ -661,6 +696,9 @@ static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget) if (ret) goto free_copier; + /* Copier can only change format */ + available_fmt->changed_params &= BIT(SNDRV_PCM_HW_PARAM_FORMAT); + /* * This callback is used by host copier and module-to-module copier, * and only host copier needs to set gtw_cfg. @@ -789,6 +827,9 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) if (ret) goto free_copier; + /* Copier can only change format */ + available_fmt->changed_params &= BIT(SNDRV_PCM_HW_PARAM_FORMAT); + ret = sof_update_ipc_object(scomp, &node_type, SOF_COPIER_TOKENS, swidget->tuples, swidget->num_tuples, sizeof(node_type), 1); diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h index a289c1d8f3ff0e..ce086188d6e1e0 100644 --- a/sound/soc/sof/ipc4-topology.h +++ b/sound/soc/sof/ipc4-topology.h @@ -197,12 +197,15 @@ struct sof_ipc4_pin_format { * @input_pin_fmts: Available input pin formats * @num_input_formats: Number of input pin formats * @num_output_formats: Number of output pin formats + * @changed_params: Mask of changed params by the module instance between it's + * input and output formts (rate, channels, depth) */ struct sof_ipc4_available_audio_format { struct sof_ipc4_pin_format *output_pin_fmts; struct sof_ipc4_pin_format *input_pin_fmts; u32 num_input_formats; u32 num_output_formats; + u32 changed_params; }; /** From 82f6014e9944279510d128af12e79fc1485cd7cd Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 3 Jun 2025 13:55:28 +0300 Subject: [PATCH 10/83] ASoC: SOF: ipc4-topology: Correct the process module's output lookup The process module can change different parameters in the audio path and this change has to be properly evaluated and applied. In case of playback we are converting from multiple input formats to a single format (or just passing through without change), the output format lookup must be based on the input format. In case of capture, we are converting from a single input format to a format which is to be passed to the FE, we need to use the input parameters and the FE parameters to be able to find the correct format: for those parameters that are modified by the module instance we need to use the FE parameter while for the rest we use the input parameters. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/ipc4-topology.c | 66 +++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 63fcd15be70b65..159f57e9983b03 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -2889,39 +2889,69 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget, if (available_fmt->num_output_formats) { struct sof_ipc4_audio_format *in_fmt; struct sof_ipc4_pin_format *pin_fmt; - u32 out_ref_rate, out_ref_channels; - int out_ref_valid_bits, out_ref_type; + u32 ref_rate, ref_channels; + int ref_valid_bits, ref_type; if (available_fmt->num_input_formats) { + /* + * The process module can change parameters and their operation + * depends on the direction: + * Playback: typically they have single output format. This is + * to 'force' the conversion from input to output. + * Use the input format as reference since the single + * format is going to be picked. + * Capture: typically they have multiple output formats to + * convert from dai (input) to FE (output) parameters. + * Use the input format as base and replace the param + * which is changed by the module with the FE parameter + * Reason: we can have module which changes the + * parameters in path, we cannot use the full + * FE param set for the module output lookup. + */ in_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt; - out_ref_rate = in_fmt->sampling_frequency; - out_ref_channels = + ref_rate = in_fmt->sampling_frequency; + ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); - out_ref_valid_bits = + ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); - out_ref_type = sof_ipc4_fmt_cfg_to_type(in_fmt->fmt_cfg); + ref_type = sof_ipc4_fmt_cfg_to_type(in_fmt->fmt_cfg); } else { /* for modules without input formats, use FE params as reference */ - out_ref_rate = params_rate(fe_params); - out_ref_channels = params_channels(fe_params); + ref_rate = params_rate(fe_params); + ref_channels = params_channels(fe_params); ret = sof_ipc4_get_sample_type(sdev, fe_params); if (ret < 0) return ret; - out_ref_type = (u32)ret; + ref_type = (u32)ret; - out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params); - if (out_ref_valid_bits < 0) - return out_ref_valid_bits; + ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params); + if (ref_valid_bits < 0) + return ref_valid_bits; } + if (dir == SNDRV_PCM_STREAM_CAPTURE) { + if (available_fmt->changed_params & BIT(SNDRV_PCM_HW_PARAM_RATE)) + ref_rate = params_rate(fe_params); + if (available_fmt->changed_params & BIT(SNDRV_PCM_HW_PARAM_CHANNELS)) + ref_channels = params_channels(fe_params); + if (available_fmt->changed_params & BIT(SNDRV_PCM_HW_PARAM_FORMAT)) { + ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params); + if (ref_valid_bits < 0) + return ref_valid_bits; + + ref_type = sof_ipc4_get_sample_type(sdev, fe_params); + if (ref_type < 0) + return ref_type; + } + } output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget, &process->base_config, available_fmt, - out_ref_rate, - out_ref_channels, - out_ref_valid_bits, - out_ref_type); + ref_rate, + ref_channels, + ref_valid_bits, + ref_type); if (output_fmt_index < 0) return output_fmt_index; @@ -2935,9 +2965,7 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget, /* modify the pipeline params with the output format */ ret = sof_ipc4_update_hw_params(sdev, pipeline_params, &process->output_format, - BIT(SNDRV_PCM_HW_PARAM_FORMAT) | - BIT(SNDRV_PCM_HW_PARAM_CHANNELS) | - BIT(SNDRV_PCM_HW_PARAM_RATE)); + available_fmt->changed_params); if (ret) return ret; } From e5a7f6121edecb6464ac92fae1e76e51bbd138a8 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 23 Jun 2025 12:45:50 +0300 Subject: [PATCH 11/83] ASoC: SOF: add ops for msg_timeout_handler to drop failed delayed if the message times out and it was delayed, remove it as well. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/intel/apl.c | 1 + sound/soc/sof/intel/cnl.c | 1 + sound/soc/sof/intel/hda-ipc.c | 10 ++++++++++ sound/soc/sof/intel/hda.h | 2 ++ sound/soc/sof/intel/icl.c | 1 + sound/soc/sof/intel/mtl.c | 1 + sound/soc/sof/intel/skl.c | 1 + sound/soc/sof/intel/tgl.c | 1 + sound/soc/sof/ipc4.c | 2 ++ sound/soc/sof/ops.h | 8 ++++++++ sound/soc/sof/sof-priv.h | 2 ++ 11 files changed, 30 insertions(+) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index b0072601181efc..e5452fa872b805 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -71,6 +71,7 @@ int sof_apl_ops_init(struct snd_sof_dev *sdev) /* ipc */ sof_apl_ops.send_msg = hda_dsp_ipc4_send_msg; + sof_apl_ops.msg_timeout_handler = hda_dsp_ipc4_msg_timeout_handler; /* debug */ sof_apl_ops.ipc_dump = hda_ipc4_dump; diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 660c1475e5a43f..50f0ef2e7b9650 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -418,6 +418,7 @@ int sof_cnl_ops_init(struct snd_sof_dev *sdev) /* ipc */ sof_cnl_ops.send_msg = cnl_ipc4_send_msg; + sof_cnl_ops.msg_timeout_handler = hda_dsp_ipc4_msg_timeout_handler; /* debug */ sof_cnl_ops.ipc_dump = cnl_ipc4_dump; diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 2aef3954f4f7f7..3c71b0124f5dd1 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -128,6 +128,16 @@ int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) } EXPORT_SYMBOL_NS(hda_dsp_ipc4_send_msg, "SND_SOC_SOF_INTEL_HDA_COMMON"); +void hda_dsp_ipc4_msg_timeout_handler(struct snd_sof_dev *sdev, + struct snd_sof_ipc_msg *msg) +{ + struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; + + if (hdev->delayed_ipc_tx_msg == msg) + hdev->delayed_ipc_tx_msg = NULL; +} +EXPORT_SYMBOL_NS(hda_dsp_ipc4_msg_timeout_handler, "SND_SOC_SOF_INTEL_HDA_COMMON"); + void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) { struct snd_sof_ipc_msg *msg = sdev->msg; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 8a7c9a10e51c04..94aad096128ea6 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -1024,6 +1024,8 @@ bool hda_ipc4_tx_is_busy(struct snd_sof_dev *sdev); void hda_dsp_ipc4_schedule_d0i3_work(struct sof_intel_hda_dev *hdev, struct snd_sof_ipc_msg *msg); int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg); +void hda_dsp_ipc4_msg_timeout_handler(struct snd_sof_dev *sdev, + struct snd_sof_ipc_msg *msg); void hda_ipc4_dump(struct snd_sof_dev *sdev); extern struct sdw_intel_ops sdw_callback; diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c index c1018893750c4b..b4d211d4f5ecc9 100644 --- a/sound/soc/sof/intel/icl.c +++ b/sound/soc/sof/intel/icl.c @@ -139,6 +139,7 @@ int sof_icl_ops_init(struct snd_sof_dev *sdev) /* ipc */ sof_icl_ops.send_msg = cnl_ipc4_send_msg; + sof_icl_ops.msg_timeout_handler = hda_dsp_ipc4_msg_timeout_handler; /* debug */ sof_icl_ops.ipc_dump = cnl_ipc4_dump; diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index 68cf68135d054a..ce04fbdf7bc549 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -717,6 +717,7 @@ int sof_mtl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops) /* ipc */ dsp_ops->send_msg = mtl_ipc_send_msg; + dsp_ops->msg_timeout_handler = hda_dsp_ipc4_msg_timeout_handler; dsp_ops->get_mailbox_offset = mtl_dsp_ipc_get_mailbox_offset; dsp_ops->get_window_offset = mtl_dsp_ipc_get_window_offset; diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index 90519ebd316810..3b90ab5e4002ac 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -79,6 +79,7 @@ int sof_skl_ops_init(struct snd_sof_dev *sdev) /* ipc */ sof_skl_ops.send_msg = hda_dsp_ipc4_send_msg; + sof_skl_ops.msg_timeout_handler = hda_dsp_ipc4_msg_timeout_handler; /* set DAI driver ops */ hda_set_dai_drv_ops(sdev, &sof_skl_ops); diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index 7936361e2e39f5..a46ed8ebbeb21a 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -109,6 +109,7 @@ int sof_tgl_ops_init(struct snd_sof_dev *sdev) /* ipc */ sof_tgl_ops.send_msg = cnl_ipc4_send_msg; + sof_tgl_ops.msg_timeout_handler = hda_dsp_ipc4_msg_timeout_handler; /* debug */ sof_tgl_ops.ipc_dump = cnl_ipc4_dump; diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c index d9bb8b79f91ecf..4625ac98096f5c 100644 --- a/sound/soc/sof/ipc4.c +++ b/sound/soc/sof/ipc4.c @@ -332,6 +332,8 @@ static int ipc4_wait_tx_done(struct snd_sof_ipc *ipc, void *reply_data) dev_err(sdev->dev, "ipc timed out for %#x|%#x\n", ipc4_msg->primary, ipc4_msg->extension); snd_sof_handle_fw_exception(ipc->sdev, "IPC timeout"); + snd_sof_dsp_msg_timeout_handler(sdev, msg); + return -ETIMEDOUT; } diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 4c9500dd8dd21f..1e606145dc853a 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -412,6 +412,14 @@ static inline int snd_sof_dsp_send_msg(struct snd_sof_dev *sdev, return sof_ops(sdev)->send_msg(sdev, msg); } +/* ipc */ +static inline void snd_sof_dsp_msg_timeout_handler(struct snd_sof_dev *sdev, + struct snd_sof_ipc_msg *msg) +{ + if (sof_ops(sdev)->msg_timeout_handler) + sof_ops(sdev)->msg_timeout_handler(sdev, msg); +} + /* host PCM ops */ static inline int snd_sof_pcm_platform_open(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 3b6ec134d37988..20f033254f07e7 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -225,6 +225,8 @@ struct snd_sof_dsp_ops { /* ipc */ int (*send_msg)(struct snd_sof_dev *sof_dev, struct snd_sof_ipc_msg *msg); /* mandatory */ + void (*msg_timeout_handler)(struct snd_sof_dev *sof_dev, + struct snd_sof_ipc_msg *msg); /* optional */ /* FW loading */ int (*load_firmware)(struct snd_sof_dev *sof_dev, const char *fw_filename); /* mandatory */ From bf56eaa5faa87973f3c6d2315f477f463674c892 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 30 Jun 2025 16:28:54 +0300 Subject: [PATCH 12/83] ASoC: SOF: ipc4-topology: Update the pipeline_params of prepared modules If the module in path has been already prepared on a branch type of topology, where the branching happens downstream: A1--> A2 ---> B1 --> B2 ... B-branch |-> C1 --> C2 ... C-branch In this case if B-branch is started then A1/A2 is prepared, but when C-branch starts we still need to refine the parameters up to C1 to arrive with a correct params to configure C1. This branching can happen with copiers process modules. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/ipc4-topology.c | 94 +++++++++++++++++++++++++++++++++-- sound/soc/sof/sof-audio.c | 5 +- 2 files changed, 92 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 159f57e9983b03..9bb1a62a820856 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -2110,10 +2110,57 @@ static void sof_ipc4_host_config(struct snd_sof_dev *sdev, struct snd_sof_widget } static int -sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, - struct snd_pcm_hw_params *fe_params, - struct snd_sof_platform_stream_params *platform_params, - struct snd_pcm_hw_params *pipeline_params, int dir) +sof_ipc4_copier_module_update_params(struct snd_sof_widget *swidget, + struct snd_pcm_hw_params *pipeline_params) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_ipc4_copier_data *copier_data; + struct sof_ipc4_copier *ipc4_copier; + + switch (swidget->id) { + case snd_soc_dapm_aif_in: + case snd_soc_dapm_aif_out: + case snd_soc_dapm_buffer: + ipc4_copier = swidget->private; + copier_data = &ipc4_copier->data; + break; + case snd_soc_dapm_dai_in: + case snd_soc_dapm_dai_out: + { + struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; + struct sof_ipc4_pipeline *pipeline = pipe_widget->private; + struct snd_sof_dai *dai; + + if (pipeline->use_chain_dma) + return 0; + + dai = swidget->private; + + ipc4_copier = (struct sof_ipc4_copier *)dai->private; + copier_data = &ipc4_copier->data; + + break; + } + default: + dev_err(sdev->dev, "unsupported type %d for copier %s", + swidget->id, swidget->widget->name); + return -EINVAL; + } + + /* modify the input params for the next widget */ + return sof_ipc4_update_hw_params(sdev, pipeline_params, + &copier_data->out_format, + BIT(SNDRV_PCM_HW_PARAM_FORMAT) | + BIT(SNDRV_PCM_HW_PARAM_CHANNELS) | + BIT(SNDRV_PCM_HW_PARAM_RATE)); +} + +static int +_sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, + struct snd_pcm_hw_params *fe_params, + struct snd_sof_platform_stream_params *platform_params, + struct snd_pcm_hw_params *pipeline_params, int dir) { struct sof_ipc4_available_audio_format *available_fmt; struct snd_soc_component *scomp = swidget->scomp; @@ -2607,6 +2654,21 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, return 0; } +static int +sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, + struct snd_pcm_hw_params *fe_params, + struct snd_sof_platform_stream_params *platform_params, + struct snd_pcm_hw_params *pipeline_params, int dir) +{ + if (swidget->prepared) + return sof_ipc4_copier_module_update_params(swidget, + pipeline_params); + + return _sof_ipc4_prepare_copier_module(swidget, fe_params, + platform_params, pipeline_params, + dir); +} + static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget, struct snd_pcm_hw_params *fe_params, struct snd_sof_platform_stream_params *platform_params, @@ -2620,6 +2682,10 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget, u32 out_ref_rate, out_ref_channels, out_ref_valid_bits, out_ref_type; int input_fmt_index, output_fmt_index; + /* This cannot happen */ + if (unlikely(swidget->prepared)) + return 0; + input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, &gain->data.base_config, pipeline_params, @@ -2665,6 +2731,10 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget, u32 out_ref_rate, out_ref_channels, out_ref_valid_bits, out_ref_type; int input_fmt_index, output_fmt_index; + /* Already prepared, nothing to do */ + if (swidget->prepared) + return 0; + input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, &mixer->base_config, pipeline_params, @@ -2711,6 +2781,10 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, u32 out_ref_rate, out_ref_channels, out_ref_valid_bits, out_ref_type; int output_fmt_index, input_fmt_index; + /* This cannot happen */ + if (unlikely(swidget->prepared)) + return 0; + input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, &src->data.base_config, pipeline_params, @@ -2877,6 +2951,18 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget, int ret; if (available_fmt->num_input_formats) { + if (swidget->prepared) { + if (!available_fmt->num_output_formats) + return 0; + + /* modify the pipeline params with the output format */ + return sof_ipc4_update_hw_params(sdev, pipeline_params, + &process->output_format, + BIT(SNDRV_PCM_HW_PARAM_FORMAT) | + BIT(SNDRV_PCM_HW_PARAM_CHANNELS) | + BIT(SNDRV_PCM_HW_PARAM_RATE)); + } + input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, &process->base_config, pipeline_params, diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 24614e50601932..72ff03b0b80d99 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -501,9 +501,8 @@ sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget !sof_widget_in_same_direction(swidget, dir)) return 0; - /* skip widgets already prepared or aggregated DAI widgets*/ - if (!widget_ops[widget->id].ipc_prepare || swidget->prepared || - is_aggregated_dai(swidget)) + /* skip widgets aggregated DAI widgets */ + if (!widget_ops[widget->id].ipc_prepare || is_aggregated_dai(swidget)) goto sink_prepare; /* prepare the source widget */ From 5fec61f20aa158455455562ba455a03799df6e41 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 30 May 2025 16:14:16 +0300 Subject: [PATCH 13/83] ASoC: SOF: ipc4-topology: Always validate the input audio format on fmt init Even if there is a single format supported by the module on it's input, it must be validated that it is matching with the reference parameters. The DAI copier's DAI side reference is adjusted to the formats it supports, but modules deep within the path might have incorrect configuration in topology (single format which is not matching with the previous module's output for example). This should be reported as errors and not silently accepted. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/ipc4-topology.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 9bb1a62a820856..d8667f5c669904 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1657,7 +1657,6 @@ static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev, u32 channels; u32 rate; u32 type; - bool single_format; int sample_valid_bits; int sample_type; int i = 0; @@ -1667,10 +1666,6 @@ static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev, return -EINVAL; } - single_format = sof_ipc4_is_single_format(sdev, pin_fmts, pin_fmts_size); - if (single_format) - goto in_fmt; - sample_valid_bits = sof_ipc4_get_valid_bits(sdev, params); if (sample_valid_bits < 0) return sample_valid_bits; @@ -1695,16 +1690,15 @@ static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev, type = sof_ipc4_fmt_cfg_to_type(fmt->fmt_cfg); if (params_rate(params) == rate && params_channels(params) == channels && sample_valid_bits == valid_bits && sample_type == type) - break; + goto in_fmt; } - if (i == pin_fmts_size) { - dev_err(sdev->dev, - "%s: Unsupported audio format: %uHz, %ubit, %u channels, type: %d\n", - __func__, params_rate(params), sample_valid_bits, - params_channels(params), sample_type); - return -EINVAL; - } + dev_err(sdev->dev, + "%s: Unsupported audio format: %uHz, %ubit, %u channels, type: %d\n", + __func__, params_rate(params), sample_valid_bits, + params_channels(params), sample_type); + + return -EINVAL; in_fmt: /* copy input format */ From d24c5099921372bbda45beced756723b66cb8aed Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 6 May 2026 10:51:43 +0300 Subject: [PATCH 14/83] ASoC: SOF: ipc4-topology: Add debug print to sof_ipc4_host_config Print the same information as we print in _sof_ipc4_prepare_copier_module() since the prepare will be not called on system resume, only the host_config will be executed and tracking the stream tag for the host is valuable information. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/ipc4-topology.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index d8667f5c669904..6bb735479db0a9 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -2093,6 +2093,10 @@ static void sof_ipc4_host_config(struct snd_sof_dev *sdev, struct snd_sof_widget struct sof_ipc4_pipeline *pipeline = pipe_widget->private; u32 host_dma_id = platform_params->stream_tag - 1; + dev_dbg(sdev->dev, "Host copier %s, type %d, ChainDMA: %s, stream_tag: %d\n", + swidget->widget->name, swidget->id, str_yes_no(pipeline->use_chain_dma), + platform_params->stream_tag); + if (pipeline->use_chain_dma) { pipeline->msg.primary &= ~SOF_IPC4_GLB_CHAIN_DMA_HOST_ID_MASK; pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_HOST_ID(host_dma_id); From 6c43c162a889fcd115b6ec229bef5223d015e1b4 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 4 May 2026 16:31:05 +0300 Subject: [PATCH 15/83] ASoC: SOF: Intel: hda: Power down DSP if it is left enabled in pre_fw_run() It is expected that the DSP is in power down state when the firmware boot is attempted. If the DSP for any reason was left powered up then the DSP boot will fail since the ROM boot sequence might not be able to run. Make sure that the DSP is off before proceeding to boot it up. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/intel/hda.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 77c7d2bc6fa211..4dbba9186b29d4 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -421,6 +421,20 @@ static inline void hda_dsp_sdw_process_mic_privacy(struct snd_sof_dev *sdev) { } /* pre fw run operations */ int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev) { + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; + int ret; + + /* Power down DSP if left enabled to ensure a clean boot state. */ + if (hda_dsp_core_is_enabled(sdev, chip->host_managed_cores_mask)) { + dev_dbg(sdev->dev, "DSP core enabled, power down DSP first\n"); + + ret = chip->power_down_dsp(sdev); + if (ret < 0) + dev_warn(sdev->dev, + "%s: failed to power down already-enabled DSP\n", __func__); + } + /* disable clock gating and power gating */ return hda_dsp_ctrl_clock_power_gating(sdev, false); } From f7fe55ac1a8a09ee15e975937f4d5d2bd1357c3f Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 7 May 2026 10:26:19 +0300 Subject: [PATCH 16/83] ASoC: SOF: Intel: mtl: Power down DSP if it is left enabled in pre_fw_run() It is expected that the DSP is in power down state when the firmware boot is attempted. If the DSP for any reason was left powered up then the DSP boot will fail since the ROM boot sequence might not be able to run. Make sure that the DSP is off before proceeding to boot it up. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/intel/mtl.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index ce04fbdf7bc549..f4f39db8a8c5a3 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -236,6 +236,17 @@ int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable) } EXPORT_SYMBOL_NS(mtl_enable_interrupts, "SND_SOC_SOF_INTEL_MTL"); +static bool mtl_dsp_is_enabled(struct snd_sof_dev *sdev) +{ + int val; + + val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFDSSCS); + if (val & MTL_HFDSSCS_CPA_MASK) + return true; + + return false; +} + /* pre fw run operations */ static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) { @@ -249,6 +260,18 @@ static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) u32 dsppwrsts; const struct sof_intel_dsp_desc *chip; + /* Power down the DSP if it is left enabled to ensure clean boot state */ + if (mtl_dsp_is_enabled(sdev)) { + dev_dbg(sdev->dev, "powering down DSP first\n"); + + ret = mtl_power_down_dsp(sdev); + if (ret < 0) { + dev_warn(sdev->dev, + "%s: failed to power down already-enabled DSP\n", __func__); + /* Continue anyway to attempt recovery */ + } + } + chip = get_chip_info(sdev->pdata); if (chip->hw_ip_version > SOF_INTEL_ACE_2_0) { dsppwrctl = PTL_HFPWRCTL2; From 35f7ee0fb4293ba28cbf6ff4203bb3dfacee8b5c Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 12 May 2026 08:32:02 +0300 Subject: [PATCH 17/83] ASoC: SOF: ipc3-control: Fix heap overflow in bytes_ext put/get The ipc_control_data buffer is allocated as kzalloc(max_size), where max_size covers the entire struct sof_ipc_ctrl_data including its flexible array payload. However, the bounds checks in bytes_ext_put and _bytes_ext_get compared user data lengths against max_size directly, ignoring that cdata->data sits at an offset of sizeof(struct sof_ipc_ctrl_data) bytes into the allocation. This allowed writing up to sizeof(struct sof_ipc_ctrl_data) bytes past the end of the heap buffer from unprivileged userspace via the ALSA TLV kcontrol interface, and similarly allowed over-reading adjacent heap data on the get path. Fix all bounds checks to subtract sizeof(*cdata) from max_size so they reflect the actual space available at the cdata->data offset. Also fix the error-path restore in bytes_ext_put which wrote to cdata->data instead of cdata, causing the same overflow. Additionally verify that the TLV payload length is large enough to cover what the ABI header's size field claims, preventing stale data from being sent to the DSP. Fixes: 67ec2a091630 ("ASoC: SOF: Add bytes_ext control IPC ops for IPC3") Signed-off-by: Peter Ujfalusi --- sound/soc/sof/ipc3-control.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/sof/ipc3-control.c b/sound/soc/sof/ipc3-control.c index d1697401b1da0d..fc4b43855144eb 100644 --- a/sound/soc/sof/ipc3-control.c +++ b/sound/soc/sof/ipc3-control.c @@ -449,6 +449,14 @@ static int sof_ipc3_bytes_ext_put(struct snd_sof_control *scontrol, goto err_restore; } + /* Verify user provided enough data for what the ABI header claims */ + if (cdata->data->size > header.length - sizeof(struct sof_abi_hdr)) { + dev_err_ratelimited(scomp->dev, "ABI data size %u exceeds TLV length %u\n", + cdata->data->size, + header.length - (unsigned int)sizeof(struct sof_abi_hdr)); + goto err_restore; + } + /* notify DSP of byte control updates */ if (pm_runtime_active(scomp->dev)) { /* Actually send the data to the DSP; this is an opportunity to validate the data */ From 0d4bbaf1b3f202a726bc60cad853f3a40b059441 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 11 May 2026 15:41:17 +0300 Subject: [PATCH 18/83] soundwire: bus: serialize BPT/BRA transfers per bus On Intel ACE2+ platforms, each SoundWire link uses a single pair of PDIs (PDI0 for TX, PDI1 for RX) and associated DMA resources for Bulk Port Transfers. When two codecs on the same link initiate BRA transfers concurrently (e.g. during firmware download), the second sdw_bpt_send_async() call races with the first: - intel_ace2x_bpt_open_stream() has a TOCTOU on the bpt_stream pointer: both callers see it as NULL and proceed - The second open overwrites the first's stream allocation, leaking the original sdw_stream_runtime - PCMSyCM mappings for the first transfer get overwritten, causing chain DMA to operate with wrong PDI assignments - IOC timeouts, use-after-free, and double-free follow on close Add a per-bus bpt_lock mutex held across the send_async/wait span to serialize BPT transfers. The lock is acquired in sdw_bpt_send_async() before calling the master ops and released in sdw_bpt_wait() after the transfer completes. On send_async failure, the lock is released immediately. Cross-link transfers (different sdw_bus instances) remain concurrent since each bus has its own lock. Signed-off-by: Peter Ujfalusi --- drivers/soundwire/bus.c | 20 ++++++++++++++++++-- include/linux/soundwire/sdw.h | 1 + 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 6013f963f4821b..57bb095d022140 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -87,6 +87,8 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, lockdep_register_key(&bus->bus_lock_key); __mutex_init(&bus->bus_lock, "bus_lock", &bus->bus_lock_key); + mutex_init(&bus->bpt_lock); + INIT_LIST_HEAD(&bus->slaves); INIT_LIST_HEAD(&bus->m_rt_list); @@ -2094,6 +2096,7 @@ EXPORT_SYMBOL(sdw_clear_slave_status); int sdw_bpt_send_async(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg) { int len = 0; + int ret; int i; for (i = 0; i < msg->sections; i++) @@ -2118,13 +2121,26 @@ int sdw_bpt_send_async(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_ return -EOPNOTSUPP; } - return bus->ops->bpt_send_async(bus, slave, msg); + /* Serialize BPT/BRA transfers per bus: PDIs and DMA resources are shared */ + mutex_lock(&bus->bpt_lock); + + ret = bus->ops->bpt_send_async(bus, slave, msg); + if (ret < 0) + mutex_unlock(&bus->bpt_lock); + + /* on success the lock is held until sdw_bpt_wait() */ + return ret; } EXPORT_SYMBOL(sdw_bpt_send_async); int sdw_bpt_wait(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg) { - return bus->ops->bpt_wait(bus, slave, msg); + int ret; + + ret = bus->ops->bpt_wait(bus, slave, msg); + mutex_unlock(&bus->bpt_lock); + + return ret; } EXPORT_SYMBOL(sdw_bpt_wait); diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 3e0d21132ef2f7..dd1743e2f25874 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -1044,6 +1044,7 @@ struct sdw_bus { int stream_refcount; int bpt_stream_refcount; struct sdw_stream_runtime *bpt_stream; + struct mutex bpt_lock; /* serialize BPT/BRA transfers per bus */ const struct sdw_master_ops *ops; const struct sdw_master_port_ops *port_ops; struct sdw_master_prop prop; From 35fddcff7dad3cb951d8bb0d7ea5c3235552614e Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 7 May 2026 16:08:13 +0300 Subject: [PATCH 19/83] ASoC: SOF: Intel: Fix pipeline state transitions for aggregate DAIs For aggregate DAIs (num_cpus > 1) the pre_trigger/post_trigger callbacks send pipeline state IPCs per-DAI without considering that multiple DAIs may share the same pipeline. This causes premature state transitions where the pipeline goes RUNNING before all link DMAs have started, or individual DAIs send redundant IPCs for shared pipelines. Fix this by checking the HDA stream running state in post_trigger: - START/PAUSE_RELEASE: defer RUNNING IPC until all DAIs sharing the same pipeline have their link DMA streams running - STOP/SUSPEND/PAUSE_PUSH: use pipeline state dedup so the PAUSED IPC is sent once regardless of how many DAIs share the pipeline The running-state check naturally handles all aggregate topologies: shared pipelines, independent pipelines, and mixed cases without requiring per-pipeline counters. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/intel/hda-dai-ops.c | 62 ++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index f0be42048db33c..c8ae4710f32cff 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -356,6 +356,39 @@ static struct hdac_ext_link *sdw_get_hlink(struct snd_sof_dev *sdev, return hdac_bus_eml_sdw_get_hlink(bus); } +/* + * Check if all CPU DAIs sharing the same pipeline (spipe) have their link + * DMA streams running. Used to gate pipeline state transitions for aggregate + * DAIs: the RUNNING IPC is deferred until the last DAI's link DMA has started. + */ +static bool hda_ipc4_all_spipe_dmas_running(struct snd_pcm_substream *substream, + struct snd_sof_pipeline *target_spipe) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *dai; + int i; + + for_each_rtd_cpu_dais(rtd, i, dai) { + struct snd_soc_dapm_widget *w; + struct snd_sof_widget *sw; + struct hdac_ext_stream *hext_stream; + + w = snd_soc_dai_get_widget(dai, substream->stream); + if (!w) + continue; + + sw = w->dobj.private; + if (!sw || sw->spipe != target_spipe) + continue; + + hext_stream = snd_soc_dai_get_dma_data(dai, substream); + if (!hext_stream || !hext_stream->hstream.running) + return false; + } + + return true; +} + static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, struct snd_pcm_substream *substream, int cmd) { @@ -383,13 +416,22 @@ static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cp case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: + /* + * For aggregate DAIs with shared pipelines, the state check + * deduplicates: the first DAI sends the IPC, subsequent DAIs + * sharing the same pipeline see it already paused and skip. + * For aggregate DAIs with different pipelines, each DAI pauses + * its own pipeline independently. + */ + if (pipeline->state == SOF_IPC4_PIPE_PAUSED) + break; + ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, SOF_IPC4_PIPE_PAUSED); if (ret < 0) return ret; pipeline->state = SOF_IPC4_PIPE_PAUSED; - break; default: dev_err(sdev->dev, "unknown trigger command %d\n", cmd); @@ -436,11 +478,13 @@ static int hda_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, struct snd_pcm_substream *substream, int cmd) { + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct sof_ipc4_fw_data *ipc4_data = sdev->private; struct snd_sof_widget *pipe_widget; struct sof_ipc4_pipeline *pipeline; struct snd_sof_widget *swidget; struct snd_soc_dapm_widget *w; + int num_cpus = rtd->dai_link->num_cpus; int ret = 0; w = snd_soc_dai_get_widget(cpu_dai, substream->stream); @@ -455,6 +499,16 @@ static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *c switch (cmd) { case SNDRV_PCM_TRIGGER_START: + /* + * For aggregated DAIs (num_cpus > 1), defer pipeline RUNNING + * IPC until all CPU DAIs sharing this pipeline have started + * their link DMAs via hda_trigger(). The running state of each + * DAI's HDA stream naturally tracks completion. + */ + if (num_cpus > 1 && + !hda_ipc4_all_spipe_dmas_running(substream, swidget->spipe)) + break; + if (pipeline->state != SOF_IPC4_PIPE_PAUSED) { ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, SOF_IPC4_PIPE_PAUSED); @@ -473,6 +527,10 @@ static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *c swidget->spipe->started_count++; break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (num_cpus > 1 && + !hda_ipc4_all_spipe_dmas_running(substream, swidget->spipe)) + break; + ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, SOF_IPC4_PIPE_RUNNING); if (ret < 0) @@ -484,7 +542,7 @@ static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *c case SNDRV_PCM_TRIGGER_STOP: /* * STOP/SUSPEND trigger is invoked only once when all users of this pipeline have - * been stopped. So, clear the started_count so that the pipeline can be reset + * been stopped. So, clear the started_count so that the pipeline can be reset. */ swidget->spipe->started_count = 0; break; From 735afb52ec3bd598bdaea04b4282659420562d4e Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 12 Jun 2026 15:57:01 +0300 Subject: [PATCH 20/83] -- pending patches -- From 3e94f3154be458811b25498eeda9716904035227 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 24 Apr 2026 08:52:35 +0300 Subject: [PATCH 21/83] ALSA: compress: pin card module while stream is open Take a module reference in snd_compr_open() and release it in snd_compr_free(). This pins the card driver module for the lifetime of an open compress stream and prevents card removal while the stream file is still in use. Adjust the open() cleanup paths to drop the added module reference only when it was acquired, and keep release ordering safe by dropping the module reference before freeing stream data. Signed-off-by: Peter Ujfalusi --- sound/core/compress_offload.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index fd63d219bf8665..ae8d394aa70986 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -75,11 +75,11 @@ static inline void snd_compr_task_free_all(struct snd_compr_stream *stream) { } static int snd_compr_open(struct inode *inode, struct file *f) { struct snd_compr *compr; - struct snd_compr_file *data; - struct snd_compr_runtime *runtime; + struct snd_compr_file *data = NULL; + struct snd_compr_runtime *runtime = NULL; enum snd_compr_direction dirn; int maj = imajor(inode); - int ret; + int ret = 0; if ((f->f_flags & O_ACCMODE) == O_WRONLY) dirn = SND_COMPRESS_PLAYBACK; @@ -101,16 +101,21 @@ static int snd_compr_open(struct inode *inode, struct file *f) return -ENODEV; } + if (!try_module_get(compr->card->module)) { + snd_card_unref(compr->card); + return -EFAULT; + } + if (dirn != compr->direction) { pr_err("this device doesn't support this direction\n"); - snd_card_unref(compr->card); - return -EINVAL; + ret = -EINVAL; + goto __error; } data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) { - snd_card_unref(compr->card); - return -ENOMEM; + ret = -ENOMEM; + goto __error; } INIT_DELAYED_WORK(&data->stream.error_work, error_delayed_work); @@ -121,9 +126,8 @@ static int snd_compr_open(struct inode *inode, struct file *f) data->stream.device = compr; runtime = kzalloc(sizeof(*runtime), GFP_KERNEL); if (!runtime) { - kfree(data); - snd_card_unref(compr->card); - return -ENOMEM; + ret = -ENOMEM; + goto __error; } runtime->state = SNDRV_PCM_STATE_OPEN; init_waitqueue_head(&runtime->sleep); @@ -134,9 +138,12 @@ static int snd_compr_open(struct inode *inode, struct file *f) f->private_data = (void *)data; scoped_guard(mutex, &compr->lock) ret = compr->ops->open(&data->stream); + +__error: if (ret) { kfree(runtime); kfree(data); + module_put(compr->card->module); } snd_card_unref(compr->card); return ret; @@ -164,6 +171,7 @@ static int snd_compr_free(struct inode *inode, struct file *f) data->stream.ops->free(&data->stream); if (!data->stream.runtime->dma_buffer_p) kfree(data->stream.runtime->buffer); + module_put(data->stream.device->card->module); kfree(data->stream.runtime); kfree(data); return 0; From f41478ae1d4c16e4bac670edd1c30fbf79d061c1 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 24 Apr 2026 10:42:43 +0300 Subject: [PATCH 22/83] ALSA: compress: stop active streams on disconnect Track open compressed streams per device so disconnect can stop active streams and wake waiters before snd_unregister_device(). This aligns compressed stream teardown with PCM disconnect behavior and prevents active userspace streams from running into unregister races. Signed-off-by: Peter Ujfalusi --- include/sound/compress_driver.h | 2 ++ sound/core/compress_offload.c | 49 +++++++++++++++++++++++++++------ 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h index 9e3d801e45ecd5..84f51edc3f9d67 100644 --- a/include/sound/compress_driver.h +++ b/include/sound/compress_driver.h @@ -188,6 +188,7 @@ struct snd_compr_ops { * @card: sound card pointer * @direction: Playback or capture direction * @lock: device lock + * @open_list: list of open compress files * @device: device id * @use_pause_in_draining: allow pause in draining, true when set */ @@ -199,6 +200,7 @@ struct snd_compr { struct snd_card *card; unsigned int direction; struct mutex lock; + struct list_head open_list; int device; bool use_pause_in_draining; #ifdef CONFIG_SND_VERBOSE_PROCFS diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index ae8d394aa70986..b0c9b082f6b1c8 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -42,6 +42,7 @@ #endif struct snd_compr_file { + struct list_head list; unsigned long caps; struct snd_compr_stream stream; }; @@ -117,6 +118,7 @@ static int snd_compr_open(struct inode *inode, struct file *f) ret = -ENOMEM; goto __error; } + INIT_LIST_HEAD(&data->list); INIT_DELAYED_WORK(&data->stream.error_work, error_delayed_work); @@ -136,8 +138,11 @@ static int snd_compr_open(struct inode *inode, struct file *f) #endif data->stream.runtime = runtime; f->private_data = (void *)data; - scoped_guard(mutex, &compr->lock) + scoped_guard(mutex, &compr->lock) { ret = compr->ops->open(&data->stream); + if (!ret) + list_add_tail(&data->list, &compr->open_list); + } __error: if (ret) { @@ -153,17 +158,23 @@ static int snd_compr_free(struct inode *inode, struct file *f) { struct snd_compr_file *data = f->private_data; struct snd_compr_runtime *runtime = data->stream.runtime; + struct snd_compr *compr = data->stream.device; cancel_delayed_work_sync(&data->stream.error_work); - switch (runtime->state) { - case SNDRV_PCM_STATE_RUNNING: - case SNDRV_PCM_STATE_DRAINING: - case SNDRV_PCM_STATE_PAUSED: - data->stream.ops->trigger(&data->stream, SNDRV_PCM_TRIGGER_STOP); - break; - default: - break; + scoped_guard(mutex, &compr->lock) { + if (!list_empty(&data->list)) + list_del_init(&data->list); + + switch (runtime->state) { + case SNDRV_PCM_STATE_RUNNING: + case SNDRV_PCM_STATE_DRAINING: + case SNDRV_PCM_STATE_PAUSED: + data->stream.ops->trigger(&data->stream, SNDRV_PCM_TRIGGER_STOP); + break; + default: + break; + } } snd_compr_task_free_all(&data->stream); @@ -1435,8 +1446,27 @@ static int snd_compress_dev_register(struct snd_device *device) static int snd_compress_dev_disconnect(struct snd_device *device) { struct snd_compr *compr; + struct snd_compr_file *data; compr = device->device_data; + scoped_guard(mutex, &compr->lock) { + list_for_each_entry(data, &compr->open_list, list) { + switch (data->stream.runtime->state) { + case SNDRV_PCM_STATE_RUNNING: + case SNDRV_PCM_STATE_DRAINING: + case SNDRV_PCM_STATE_PAUSED: + data->stream.ops->trigger(&data->stream, + SNDRV_PCM_TRIGGER_STOP); + break; + default: + break; + } + + data->stream.runtime->state = SNDRV_PCM_STATE_DISCONNECTED; + wake_up(&data->stream.runtime->sleep); + } + } + snd_unregister_device(compr->dev); return 0; } @@ -1544,6 +1574,7 @@ int snd_compress_new(struct snd_card *card, int device, compr->device = device; compr->direction = dirn; mutex_init(&compr->lock); + INIT_LIST_HEAD(&compr->open_list); snd_compress_set_id(compr, id); From 8b0393355066efeac6de6f9f24abf7d0aa987d9a Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 13 Jan 2026 11:31:52 +0200 Subject: [PATCH 23/83] ASoC: soc-pcm: Allocate be_substream->runtime for compressed streams With DPCM when compr is used on FE side, the BE is still running as 'normal' PCM. It is expected that the be_substream->runtime on the BE is not NULL, for example some codec drivers expect to have the substream->runtime valid, to store configuration for example. Signed-off-by: Peter Ujfalusi --- sound/soc/soc-pcm.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 0e49290a8c903b..e593aabc10e86d 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1790,6 +1790,8 @@ void dpcm_be_dai_stop(struct snd_soc_pcm_runtime *fe, int stream, } __soc_pcm_close(be, be_substream); + if (fe->fe_compr) + kfree(be_substream->runtime); be_substream->runtime = NULL; be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; } @@ -1837,7 +1839,16 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) dev_dbg(be->dev, "ASoC: open %s BE %s\n", snd_pcm_direction_name(stream), be->dai_link->name); - be_substream->runtime = fe_substream->runtime; + if (!fe->fe_compr) { + be_substream->runtime = fe_substream->runtime; + } else { + be_substream->runtime = kzalloc(sizeof(*be_substream->runtime), GFP_KERNEL); + if (!be_substream->runtime) { + err = -ENOMEM; + goto unwind; + } + } + err = __soc_pcm_open(be, be_substream); if (err < 0) { be->dpcm[stream].users--; From 709486418990935f7542e3426b5317a3c4fdafb8 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 27 Jan 2026 13:54:06 +0200 Subject: [PATCH 24/83] ASoC: soc-compress: Implement trigger FE-BE sequencing as with normal PCMs The FE-BE trigger sequence should be dynamic, similarly how soc-pcm.c dpcm_fe_dai_do_trigger() does it. Signed-off-by: Peter Ujfalusi --- sound/soc/soc-compress.c | 71 +++++++++++++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 9 deletions(-) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index b8402802ae7848..3217dba7bcf011 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -273,31 +273,84 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) return ret; } -static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) +static int soc_compr_trigger_fe_be(struct snd_compr_stream *cstream, int cmd, + bool fe_first) { struct snd_soc_pcm_runtime *fe = cstream->private_data; struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(fe, 0); + int ret; + + if (fe_first) { + dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n", + fe->dai_link->name, cmd); + + ret = snd_soc_dai_compr_trigger(cpu_dai, cstream, cmd); + if (ret < 0) + goto out; + + ret = snd_soc_component_compr_trigger(cstream, cmd); + if (ret < 0) + goto out; + + ret = dpcm_be_dai_trigger(fe, cstream->direction, cmd); + } else { + dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n", + fe->dai_link->name, cmd); + + ret = dpcm_be_dai_trigger(fe, cstream->direction, cmd); + if (ret < 0) + goto out; + + ret = snd_soc_dai_compr_trigger(cpu_dai, cstream, cmd); + if (ret < 0) + goto out; + + ret = snd_soc_component_compr_trigger(cstream, cmd); + } + +out: + return snd_soc_ret(fe->dev, ret, "trigger FE cmd: %d failed\n", cmd); +} + +static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) +{ + struct snd_soc_pcm_runtime *fe = cstream->private_data; int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */ + bool fe_first; int ret; if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN || cmd == SND_COMPR_TRIGGER_DRAIN) return snd_soc_component_compr_trigger(cstream, cmd); + if (fe->dai_link->trigger[stream] == SND_SOC_DPCM_TRIGGER_POST) + fe_first = false; + else + fe_first = true; + snd_soc_card_mutex_lock(fe->card); - ret = snd_soc_dai_compr_trigger(cpu_dai, cstream, cmd); - if (ret < 0) - goto out; + fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ret = soc_compr_trigger_fe_be(cstream, cmd, fe_first); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + ret = soc_compr_trigger_fe_be(cstream, cmd, !fe_first); + break; + default: + ret = -EINVAL; + break; + } - ret = snd_soc_component_compr_trigger(cstream, cmd); if (ret < 0) goto out; - fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; - - ret = dpcm_be_dai_trigger(fe, stream, cmd); - switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: From a7be4308c71ea29ca47dcfc4708609bb67cc6b71 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 3 Feb 2026 18:43:48 +0200 Subject: [PATCH 25/83] ASoC: soc-compress: Stop running dpcm on free If the last trigger that the compr device received is a DRAIN then the DPCM is left in running state (no stop trigger is sent). Before we execute the free we need to send a STOP trigger to make sure that both BE and FE is in expected state and prepared for closing. Signed-off-by: Peter Ujfalusi --- sound/soc/soc-compress.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 3217dba7bcf011..3a8da272248328 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -207,6 +207,16 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) struct snd_soc_dpcm *dpcm; int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */ + /* + * The core will not send a STOP trigger on free if the device is in + * DRAIN state, but we need to stop BE and FE before we can proceed to + * free the stream. + * Run the STOP trigger if the DPCM state is START (DRAIN is not + * changing the DPCM state). + */ + if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_START) + cstream->ops->trigger(cstream, SNDRV_PCM_TRIGGER_STOP); + snd_soc_card_mutex_lock(fe->card); snd_soc_dpcm_mutex_lock(fe); From 251300b482574e1176459908f35c80d884a7fc6c Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 8 Dec 2025 18:55:56 -0800 Subject: [PATCH 26/83] ASoC: SOF: compress: Rename compress ops with ipc3 prefix In preparation for adding support for compressed offload support for IPC4, rename the current compress implementation with the IPC3 prefix. Introduce a new field in struct sof_ipc_pcm_ops to save the IPC-specific compressed ops pointer. This should be set when the component driver ops are assigned during SOF device probe. Expose a couple of common functions that will be used by both IPC-specific implementations and rename the compress.c file to ipc3-compress.c Signed-off-by: Ranjani Sridharan Signed-off-by: Peter Ujfalusi --- sound/soc/sof/Makefile | 2 +- sound/soc/sof/core.c | 10 +- sound/soc/sof/{compress.c => ipc3-compress.c} | 145 ++++-------------- sound/soc/sof/ipc3-pcm.c | 3 + sound/soc/sof/ipc3-priv.h | 3 + sound/soc/sof/pcm.c | 5 +- sound/soc/sof/sof-audio.c | 81 ++++++++++ sound/soc/sof/sof-audio.h | 5 + 8 files changed, 137 insertions(+), 117 deletions(-) rename sound/soc/sof/{compress.c => ipc3-compress.c} (66%) diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 18dea3b4ade4fc..e19eedee76423a 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -19,7 +19,7 @@ ifneq ($(CONFIG_SND_SOC_SOF_CLIENT),) snd-sof-y += sof-client.o endif -snd-sof-$(CONFIG_SND_SOC_SOF_COMPRESS) += compress.o +snd-sof-$(CONFIG_SND_SOC_SOF_COMPRESS) += ipc3-compress.o snd-sof-pci-y := sof-pci-dev.o snd-sof-acpi-y := sof-acpi-dev.o diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 5fa8c40de5d9a1..1f38fe03e49395 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -469,11 +469,12 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE); - /* set up platform component driver */ - snd_sof_new_platform_drv(sdev); - if (sdev->dspless_mode_selected) { sof_set_fw_state(sdev, SOF_DSPLESS_MODE); + + /* set up platform component driver */ + snd_sof_new_platform_drv(sdev); + goto skip_dsp_init; } @@ -498,6 +499,9 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) goto ipc_err; } + /* set up platform component driver after initializing the IPC ops */ + snd_sof_new_platform_drv(sdev); + /* * skip loading/booting firmware and registering the machine driver when DSP OPS testing * is enabled with IPC4. Normal audio operations will be unavailable in this mode. diff --git a/sound/soc/sof/compress.c b/sound/soc/sof/ipc3-compress.c similarity index 66% rename from sound/soc/sof/compress.c rename to sound/soc/sof/ipc3-compress.c index 93f2376585dbf5..115d454bcaf5b7 100644 --- a/sound/soc/sof/compress.c +++ b/sound/soc/sof/ipc3-compress.c @@ -12,88 +12,8 @@ #include "sof-utils.h" #include "ops.h" -static void sof_set_transferred_bytes(struct sof_compr_stream *sstream, - u64 host_pos, u64 buffer_size) -{ - u64 prev_pos; - unsigned int copied; - - div64_u64_rem(sstream->copied_total, buffer_size, &prev_pos); - - if (host_pos < prev_pos) - copied = (buffer_size - prev_pos) + host_pos; - else - copied = host_pos - prev_pos; - - sstream->copied_total += copied; -} - -static void snd_sof_compr_fragment_elapsed_work(struct work_struct *work) -{ - struct snd_sof_pcm_stream *sps = - container_of(work, struct snd_sof_pcm_stream, - period_elapsed_work); - - snd_compr_fragment_elapsed(sps->cstream); -} - -void snd_sof_compr_init_elapsed_work(struct work_struct *work) -{ - INIT_WORK(work, snd_sof_compr_fragment_elapsed_work); -} - -/* - * sof compr fragment elapse, this could be called in irq thread context - */ -void snd_sof_compr_fragment_elapsed(struct snd_compr_stream *cstream) -{ - struct snd_soc_pcm_runtime *rtd; - struct snd_compr_runtime *crtd; - struct snd_soc_component *component; - struct sof_compr_stream *sstream; - struct snd_sof_pcm *spcm; - - if (!cstream) - return; - - rtd = cstream->private_data; - crtd = cstream->runtime; - sstream = crtd->private_data; - component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); - - spcm = snd_sof_find_spcm_dai(component, rtd); - if (!spcm) { - dev_err(component->dev, - "fragment elapsed called for unknown stream!\n"); - return; - } - - sof_set_transferred_bytes(sstream, spcm->stream[cstream->direction].posn.host_posn, - crtd->buffer_size); - - /* use the same workqueue-based solution as for PCM, cf. snd_sof_pcm_elapsed */ - schedule_work(&spcm->stream[cstream->direction].period_elapsed_work); -} - -static int create_page_table(struct snd_soc_component *component, - struct snd_compr_stream *cstream, - unsigned char *dma_area, size_t size) -{ - struct snd_dma_buffer *dmab = cstream->runtime->dma_buffer_p; - struct snd_soc_pcm_runtime *rtd = cstream->private_data; - int dir = cstream->direction; - struct snd_sof_pcm *spcm; - - spcm = snd_sof_find_spcm_dai(component, rtd); - if (!spcm) - return -EINVAL; - - return snd_sof_create_page_table(component->dev, dmab, - spcm->stream[dir].page_table.area, size); -} - -static int sof_compr_open(struct snd_soc_component *component, - struct snd_compr_stream *cstream) +static int sof_ipc3_compr_open(struct snd_soc_component *component, + struct snd_compr_stream *cstream) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_compr_runtime *crtd = cstream->runtime; @@ -128,8 +48,8 @@ static int sof_compr_open(struct snd_soc_component *component, return 0; } -static int sof_compr_free(struct snd_soc_component *component, - struct snd_compr_stream *cstream) +static int sof_ipc3_compr_free(struct snd_soc_component *component, + struct snd_compr_stream *cstream) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct sof_compr_stream *sstream = cstream->runtime->private_data; @@ -159,8 +79,9 @@ static int sof_compr_free(struct snd_soc_component *component, return ret; } -static int sof_compr_set_params(struct snd_soc_component *component, - struct snd_compr_stream *cstream, struct snd_compr_params *params) +static int sof_ipc3_compr_set_params(struct snd_soc_component *component, + struct snd_compr_stream *cstream, + struct snd_compr_params *params) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_soc_pcm_runtime *rtd = cstream->private_data; @@ -213,7 +134,7 @@ static int sof_compr_set_params(struct snd_soc_component *component, if (ret < 0) goto out; - ret = create_page_table(component, cstream, crtd->dma_area, crtd->dma_bytes); + ret = snd_sof_compr_create_page_table(component, cstream, crtd->dma_area, crtd->dma_bytes); if (ret < 0) goto out; @@ -265,8 +186,9 @@ static int sof_compr_set_params(struct snd_soc_component *component, return ret; } -static int sof_compr_get_params(struct snd_soc_component *component, - struct snd_compr_stream *cstream, struct snd_codec *params) +static int sof_ipc3_compr_get_params(struct snd_soc_component *component, + struct snd_compr_stream *cstream, + struct snd_codec *params) { struct sof_compr_stream *sstream = cstream->runtime->private_data; @@ -275,8 +197,8 @@ static int sof_compr_get_params(struct snd_soc_component *component, return 0; } -static int sof_compr_trigger(struct snd_soc_component *component, - struct snd_compr_stream *cstream, int cmd) +static int sof_ipc3_compr_trigger(struct snd_soc_component *component, + struct snd_compr_stream *cstream, int cmd) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_soc_pcm_runtime *rtd = cstream->private_data; @@ -312,8 +234,8 @@ static int sof_compr_trigger(struct snd_soc_component *component, return sof_ipc_tx_message_no_reply(sdev->ipc, &stream, sizeof(stream)); } -static int sof_compr_copy_playback(struct snd_compr_runtime *rtd, - char __user *buf, size_t count) +static int sof_ipc3_compr_copy_playback(struct snd_compr_runtime *rtd, + char __user *buf, size_t count) { void *ptr; unsigned int offset, n; @@ -333,8 +255,8 @@ static int sof_compr_copy_playback(struct snd_compr_runtime *rtd, return count - ret; } -static int sof_compr_copy_capture(struct snd_compr_runtime *rtd, - char __user *buf, size_t count) +static int sof_ipc3_compr_copy_capture(struct snd_compr_runtime *rtd, + char __user *buf, size_t count) { void *ptr; unsigned int offset, n; @@ -354,9 +276,9 @@ static int sof_compr_copy_capture(struct snd_compr_runtime *rtd, return count - ret; } -static int sof_compr_copy(struct snd_soc_component *component, - struct snd_compr_stream *cstream, - char __user *buf, size_t count) +static int sof_ipc3_compr_copy(struct snd_soc_component *component, + struct snd_compr_stream *cstream, + char __user *buf, size_t count) { struct snd_compr_runtime *rtd = cstream->runtime; @@ -364,14 +286,14 @@ static int sof_compr_copy(struct snd_soc_component *component, count = rtd->buffer_size; if (cstream->direction == SND_COMPRESS_PLAYBACK) - return sof_compr_copy_playback(rtd, buf, count); + return sof_ipc3_compr_copy_playback(rtd, buf, count); else - return sof_compr_copy_capture(rtd, buf, count); + return sof_ipc3_compr_copy_capture(rtd, buf, count); } -static int sof_compr_pointer(struct snd_soc_component *component, - struct snd_compr_stream *cstream, - struct snd_compr_tstamp64 *tstamp) +static int sof_ipc3_compr_pointer(struct snd_soc_component *component, + struct snd_compr_stream *cstream, + struct snd_compr_tstamp64 *tstamp) { struct snd_sof_pcm *spcm; struct snd_soc_pcm_runtime *rtd = cstream->private_data; @@ -392,13 +314,12 @@ static int sof_compr_pointer(struct snd_soc_component *component, return 0; } -struct snd_compress_ops sof_compressed_ops = { - .open = sof_compr_open, - .free = sof_compr_free, - .set_params = sof_compr_set_params, - .get_params = sof_compr_get_params, - .trigger = sof_compr_trigger, - .pointer = sof_compr_pointer, - .copy = sof_compr_copy, +const struct snd_compress_ops sof_ipc3_compressed_ops = { + .open = sof_ipc3_compr_open, + .free = sof_ipc3_compr_free, + .set_params = sof_ipc3_compr_set_params, + .get_params = sof_ipc3_compr_get_params, + .trigger = sof_ipc3_compr_trigger, + .pointer = sof_ipc3_compr_pointer, + .copy = sof_ipc3_compr_copy, }; -EXPORT_SYMBOL(sof_compressed_ops); diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c index 90ef5d99f626a9..1e8499b444c0a4 100644 --- a/sound/soc/sof/ipc3-pcm.c +++ b/sound/soc/sof/ipc3-pcm.c @@ -436,4 +436,7 @@ const struct sof_ipc_pcm_ops ipc3_pcm_ops = { .dai_link_fixup = sof_ipc3_pcm_dai_link_fixup, .reset_hw_params_during_stop = true, .d0i3_supported_in_s0ix = true, +#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS) + .compress_ops = &sof_ipc3_compressed_ops, +#endif }; diff --git a/sound/soc/sof/ipc3-priv.h b/sound/soc/sof/ipc3-priv.h index 866c5f67b91a7c..f95957453ab8b2 100644 --- a/sound/soc/sof/ipc3-priv.h +++ b/sound/soc/sof/ipc3-priv.h @@ -17,6 +17,9 @@ extern const struct sof_ipc_tplg_ops ipc3_tplg_ops; extern const struct sof_ipc_tplg_control_ops tplg_ipc3_control_ops; extern const struct sof_ipc_fw_loader_ops ipc3_loader_ops; extern const struct sof_ipc_fw_tracing_ops ipc3_dtrace_ops; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS) +extern const struct snd_compress_ops sof_ipc3_compressed_ops; +#endif /* helpers for fw_ready and ext_manifest parsing */ int sof_ipc3_get_ext_windows(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index f748d072109aa6..941baa48b2759d 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -847,7 +847,10 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) pd->delay = sof_pcm_delay; #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS) - pd->compress_ops = &sof_compressed_ops; + const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); + + if (pcm_ops) + pd->compress_ops = pcm_ops->compress_ops; #endif pd->pcm_new = sof_pcm_new; diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 72ff03b0b80d99..d244e90a734b0b 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -11,6 +11,7 @@ #include #include #include "sof-audio.h" +#include "sof-utils.h" #include "ops.h" /* @@ -1050,3 +1051,83 @@ int sof_dai_get_tdm_slots(struct snd_soc_pcm_runtime *rtd) return sof_dai_get_param(rtd, SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS); } EXPORT_SYMBOL(sof_dai_get_tdm_slots); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS) +static void sof_set_transferred_bytes(struct sof_compr_stream *sstream, + u64 host_pos, u64 buffer_size) +{ + u64 prev_pos; + unsigned int copied; + + div64_u64_rem(sstream->copied_total, buffer_size, &prev_pos); + + if (host_pos < prev_pos) + copied = (buffer_size - prev_pos) + host_pos; + else + copied = host_pos - prev_pos; + + sstream->copied_total += copied; +} + +static void snd_sof_compr_fragment_elapsed_work(struct work_struct *work) +{ + struct snd_sof_pcm_stream *sps = container_of(work, struct snd_sof_pcm_stream, + period_elapsed_work); + + snd_compr_fragment_elapsed(sps->cstream); +} + +void snd_sof_compr_init_elapsed_work(struct work_struct *work) +{ + INIT_WORK(work, snd_sof_compr_fragment_elapsed_work); +} + +/* + * sof compr fragment elapse, this could be called in irq thread context + */ +void snd_sof_compr_fragment_elapsed(struct snd_compr_stream *cstream) +{ + struct snd_soc_pcm_runtime *rtd; + struct snd_compr_runtime *crtd; + struct snd_soc_component *component; + struct sof_compr_stream *sstream; + struct snd_sof_pcm *spcm; + + if (!cstream) + return; + + rtd = cstream->private_data; + crtd = cstream->runtime; + sstream = crtd->private_data; + component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); + + spcm = snd_sof_find_spcm_dai(component, rtd); + if (!spcm) { + dev_err(component->dev, "fragment elapsed called for unknown stream!\n"); + return; + } + + sof_set_transferred_bytes(sstream, spcm->stream[cstream->direction].posn.host_posn, + crtd->buffer_size); + + /* use the same workqueue-based solution as for PCM, cf. snd_sof_pcm_elapsed */ + schedule_work(&spcm->stream[cstream->direction].period_elapsed_work); +} + +int snd_sof_compr_create_page_table(struct snd_soc_component *component, + struct snd_compr_stream *cstream, + unsigned char *dma_area, size_t size) +{ + struct snd_dma_buffer *dmab = cstream->runtime->dma_buffer_p; + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + int dir = cstream->direction; + struct snd_sof_pcm *spcm; + + spcm = snd_sof_find_spcm_dai(component, rtd); + if (!spcm) + return -EINVAL; + + return snd_sof_create_page_table(component->dev, dmab, + spcm->stream[dir].page_table.area, size); +} +#endif diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 138e5fcc2dd094..b1d8309fbc8588 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -119,6 +119,7 @@ struct snd_sof_dai_config_data { * therefore the host must do the same and should stop the DMA during * hw_free. * @d0i3_supported_in_s0ix: Allow DSP D0I3 during S0iX + * @compress_ops: Pointer to ops for compressed streams */ struct sof_ipc_pcm_ops { int (*hw_params)(struct snd_soc_component *component, struct snd_pcm_substream *substream, @@ -139,6 +140,7 @@ struct sof_ipc_pcm_ops { bool ipc_first_on_start; bool platform_stop_during_hw_free; bool d0i3_supported_in_s0ix; + const struct snd_compress_ops *compress_ops; }; /** @@ -660,6 +662,9 @@ void snd_sof_pcm_init_elapsed_work(struct work_struct *work); #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS) void snd_sof_compr_fragment_elapsed(struct snd_compr_stream *cstream); void snd_sof_compr_init_elapsed_work(struct work_struct *work); +int snd_sof_compr_create_page_table(struct snd_soc_component *component, + struct snd_compr_stream *cstream, + unsigned char *dma_area, size_t size); #else static inline void snd_sof_compr_fragment_elapsed(struct snd_compr_stream *cstream) { } static inline void snd_sof_compr_init_elapsed_work(struct work_struct *work) { } From 727ac1cf91202c3f27931505e66d4dfaf29604ca Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 24 Apr 2026 10:43:01 +0300 Subject: [PATCH 27/83] ASoC: SOF: ipc4-pcm: harden pipeline teardown races Serialize trigger/free with pipeline_state_mutex and validate pipeline entries before use. Also clear pipeline_list->count when freeing lists to avoid stale entries during concurrent teardown. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/ipc4-pcm.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 318f5262d01451..c327249e7b8e89 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -435,12 +435,16 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, spcm_dbg(spcm, substream->stream, "cmd: %d, state: %d\n", cmd, state); pipeline_list = &spcm->stream[substream->stream].pipeline_list; + guard(mutex)(&ipc4_data->pipeline_state_mutex); /* nothing to trigger if the list is empty */ if (!pipeline_list->pipelines || !pipeline_list->count) return 0; spipe = pipeline_list->pipelines[0]; + if (!spipe || !spipe->pipe_widget || !spipe->pipe_widget->private) + return 0; + pipe_widget = spipe->pipe_widget; pipeline = pipe_widget->private; @@ -488,8 +492,6 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, return -ENOMEM; } - guard(mutex)(&ipc4_data->pipeline_state_mutex); - /* * IPC4 requires pipelines to be triggered in order starting at the sink and * walking all the way to the source. So traverse the pipeline_list in the order @@ -502,12 +504,16 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, if (state == SOF_IPC4_PIPE_RUNNING || state == SOF_IPC4_PIPE_RESET) for (i = pipeline_list->count - 1; i >= 0; i--) { spipe = pipeline_list->pipelines[i]; + if (!spipe || !spipe->pipe_widget || !spipe->pipe_widget->private) + continue; sof_ipc4_add_pipeline_to_trigger_list(sdev, state, spipe, trigger_list, pipe_priority); } else for (i = 0; i < pipeline_list->count; i++) { spipe = pipeline_list->pipelines[i]; + if (!spipe || !spipe->pipe_widget || !spipe->pipe_widget->private) + continue; sof_ipc4_add_pipeline_to_trigger_list(sdev, state, spipe, trigger_list, pipe_priority); } @@ -547,6 +553,8 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, /* update PAUSED state for all pipelines just triggered */ for (i = 0; i < pipeline_list->count ; i++) { spipe = pipeline_list->pipelines[i]; + if (!spipe || !spipe->pipe_widget || !spipe->pipe_widget->private) + continue; sof_ipc4_update_pipeline_state(sdev, SOF_IPC4_PIPE_PAUSED, cmd, spipe, trigger_list); } @@ -590,6 +598,8 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, /* update RUNNING/RESET state for all pipelines that were just triggered */ for (i = 0; i < pipeline_list->count; i++) { spipe = pipeline_list->pipelines[i]; + if (!spipe || !spipe->pipe_widget || !spipe->pipe_widget->private) + continue; sof_ipc4_update_pipeline_state(sdev, state, cmd, spipe, trigger_list); } @@ -904,13 +914,17 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, static void sof_ipc4_pcm_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm) { struct snd_sof_pcm_stream_pipeline_list *pipeline_list; + struct sof_ipc4_fw_data *ipc4_data = sdev->private; struct sof_ipc4_pcm_stream_priv *stream_priv; int stream; + guard(mutex)(&ipc4_data->pipeline_state_mutex); + for_each_pcm_streams(stream) { pipeline_list = &spcm->stream[stream].pipeline_list; kfree(pipeline_list->pipelines); pipeline_list->pipelines = NULL; + pipeline_list->count = 0; stream_priv = spcm->stream[stream].private; kfree(stream_priv->time_info); From b86c143a0fa6418b9372f9cd63c1770c0d97a984 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 24 Apr 2026 14:18:35 +0300 Subject: [PATCH 28/83] ASoC: SOF: sof-audio: harden recursive widget free walk During widget FREE traversal, SOF walks DAPM sink paths recursively while widgets and paths can be torn down. This can lead to stale pointer usage in sof_free_widgets_in_path() when path entries disappear during recursion. Harden the FREE path by: - validating scheduler/pipeline pointers before recursive free - using a safe DAPM path iterator for sink traversal - carrying a stable widget-list snapshot through recursion - skipping NULL sink edges during traversal The safe traversal can leave path->walking set on surviving edges after FREE, which may short-circuit later DAPM walks and break consecutive playback open/stop cycles. Reset walking flags for widgets in the current DAPM list after FREE walks (including error paths) to keep subsequent traversals clean. This keeps teardown robust for module-remove race scenarios while preserving normal consecutive playback behavior. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/sof-audio.c | 60 ++++++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index d244e90a734b0b..0e4e1bb8c35ff1 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -103,7 +103,7 @@ static int sof_widget_free_unlocked(struct snd_sof_dev *sdev, * decrement ref count for cores associated with all modules in the pipeline and clear * the complete flag */ - if (swidget->id == snd_soc_dapm_scheduler) { + if (swidget->id == snd_soc_dapm_scheduler && spipe) { int i; for_each_set_bit(i, &spipe->core_mask, sdev->num_cores) { @@ -115,16 +115,16 @@ static int sof_widget_free_unlocked(struct snd_sof_dev *sdev, err = ret; } } - swidget->spipe->complete = 0; + spipe->complete = 0; } /* * free the scheduler widget (same as pipe_widget) associated with the current swidget. * skip for static pipelines */ - if (swidget->spipe && swidget->dynamic_pipeline_widget && + if (spipe && spipe->pipe_widget && swidget->dynamic_pipeline_widget && swidget->id != snd_soc_dapm_scheduler) { - ret = sof_widget_free_unlocked(sdev, swidget->spipe->pipe_widget); + ret = sof_widget_free_unlocked(sdev, spipe->pipe_widget); if (ret < 0 && !err) err = ret; } @@ -547,15 +547,20 @@ sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget * free all widgets in the sink path starting from the source widget * (DAI type for capture, AIF type for playback) */ -static int sof_free_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget, - int dir, struct snd_sof_pcm *spcm) +static int sof_free_widgets_in_path_internal(struct snd_sof_dev *sdev, + struct snd_soc_dapm_widget *widget, + int dir, struct snd_sof_pcm *spcm, + struct snd_soc_dapm_widget_list *list) { - struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list; struct snd_sof_widget *swidget = widget->dobj.private; struct snd_soc_dapm_path *p; + struct snd_soc_dapm_path *next_p; int err; int ret = 0; + if (!list) + return 0; + if (is_virtual_widget(sdev, widget, __func__)) return 0; @@ -575,23 +580,52 @@ static int sof_free_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dap ret = err; sink_free: /* free all widgets in the sink paths even in case of error to keep use counts balanced */ - snd_soc_dapm_widget_for_each_sink_path(widget, p) { + snd_soc_dapm_widget_for_each_path_safe(widget, SND_SOC_DAPM_DIR_IN, p, next_p) { if (!p->walking) { + if (!p->sink) + continue; + if (!widget_in_list(list, p->sink)) continue; p->walking = true; - err = sof_free_widgets_in_path(sdev, p->sink, dir, spcm); + err = sof_free_widgets_in_path_internal(sdev, p->sink, + dir, spcm, list); if (err < 0) ret = err; - p->walking = false; } } return ret; } +static int sof_free_widgets_in_path(struct snd_sof_dev *sdev, + struct snd_soc_dapm_widget *widget, + int dir, struct snd_sof_pcm *spcm) +{ + return sof_free_widgets_in_path_internal(sdev, widget, dir, spcm, + spcm->stream[dir].list); +} + +static void sof_reset_path_walking_flags(struct snd_soc_dapm_widget_list *list) +{ + struct snd_soc_dapm_widget *widget; + struct snd_soc_dapm_path *p; + int i; + + if (!list) + return; + + for_each_dapm_widgets(list, i, widget) { + snd_soc_dapm_widget_for_each_sink_path(widget, p) + p->walking = false; + + snd_soc_dapm_widget_for_each_source_path(widget, p) + p->walking = false; + } +} + /* * set up all widgets in the sink path starting from the source widget * (DAI type for capture, AIF type for playback). @@ -726,11 +760,17 @@ sof_walk_widgets_in_order(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, return -EINVAL; } if (ret < 0) { + if (op == SOF_WIDGET_FREE) + sof_reset_path_walking_flags(list); + dev_err(sdev->dev, "Failed to %s connected widgets\n", str); return ret; } } + if (op == SOF_WIDGET_FREE) + sof_reset_path_walking_flags(list); + return 0; } From d053a711b9bcd6de06824c1562162ccd7335a97a Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 8 Dec 2025 20:07:43 -0800 Subject: [PATCH 29/83] ASoC: SOF: sof-audio: Expose a couple of functions These are common functions that will also be needed for the IPC4 compressed support. Signed-off-by: Ranjani Sridharan Signed-off-by: Peter Ujfalusi --- sound/soc/sof/pcm.c | 6 +++--- sound/soc/sof/sof-audio.h | 7 ++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 941baa48b2759d..8f59c200b8ec1c 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -66,7 +66,7 @@ void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream) } EXPORT_SYMBOL(snd_sof_pcm_period_elapsed); -static int +int sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_runtime *rtd, struct snd_sof_pcm *spcm, struct snd_pcm_hw_params *params, struct snd_sof_platform_stream_params *platform_params, int dir) @@ -100,8 +100,8 @@ sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_run return 0; } -static struct snd_sof_widget *snd_sof_find_swidget_by_comp_id(struct snd_sof_dev *sdev, - int comp_id) +struct snd_sof_widget *snd_sof_find_swidget_by_comp_id(struct snd_sof_dev *sdev, + int comp_id) { struct snd_sof_widget *swidget; diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index b1d8309fbc8588..edfde688c86847 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -636,7 +636,12 @@ struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_soc_component *scomp, int *direction); void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream); void snd_sof_pcm_init_elapsed_work(struct work_struct *work); - +int sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_runtime *rtd, + struct snd_sof_pcm *spcm, struct snd_pcm_hw_params *params, + struct snd_sof_platform_stream_params *platform_params, + int dir); +struct snd_sof_widget *snd_sof_find_swidget_by_comp_id(struct snd_sof_dev *sdev, + int comp_id); /* * snd_sof_pcm specific wrappers for dev_dbg() and dev_err() to provide * consistent and useful prints. From c3550ac55e938aa42c00e52469655f72b37c962d Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 8 Dec 2025 20:13:11 -0800 Subject: [PATCH 30/83] ASoC: SOF: pcm: Modify the signature of a couple of PCM IPC ops In order to reuse the pipeline triggering logic for compressed support with IPC4, modify the signature of the trigger and hw_free PCM IPC ops so that they can be reused. Signed-off-by: Ranjani Sridharan Signed-off-by: Peter Ujfalusi --- sound/soc/sof/ipc3-pcm.c | 26 +++++++--------------- sound/soc/sof/ipc4-pcm.c | 45 ++++++++++++++++++++------------------- sound/soc/sof/pcm.c | 7 +++--- sound/soc/sof/sof-audio.h | 7 +++--- 4 files changed, 39 insertions(+), 46 deletions(-) diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c index 1e8499b444c0a4..28c4047b26737d 100644 --- a/sound/soc/sof/ipc3-pcm.c +++ b/sound/soc/sof/ipc3-pcm.c @@ -14,23 +14,18 @@ #include "sof-audio.h" static int sof_ipc3_pcm_hw_free(struct snd_soc_component *component, - struct snd_pcm_substream *substream) + struct snd_pcm_substream *substream, + struct snd_sof_pcm *spcm, int dir) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct sof_ipc_stream stream; - struct snd_sof_pcm *spcm; - - spcm = snd_sof_find_spcm_dai(component, rtd); - if (!spcm) - return -EINVAL; - if (!spcm->prepared[substream->stream]) + if (!spcm->prepared[dir]) 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; + stream.comp_id = spcm->stream[dir].comp_id; /* send IPC to the DSP */ return sof_ipc_tx_message_no_reply(sdev->ipc, &stream, sizeof(stream)); @@ -141,20 +136,15 @@ static int sof_ipc3_pcm_hw_params(struct snd_soc_component *component, } static int sof_ipc3_pcm_trigger(struct snd_soc_component *component, - struct snd_pcm_substream *substream, int cmd) + struct snd_pcm_substream *substream, + struct snd_sof_pcm *spcm, int cmd, int dir) { - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct sof_ipc_stream stream; - struct snd_sof_pcm *spcm; - - spcm = snd_sof_find_spcm_dai(component, rtd); - if (!spcm) - return -EINVAL; stream.hdr.size = sizeof(stream); stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG; - stream.comp_id = spcm->stream[substream->stream].comp_id; + stream.comp_id = spcm->stream[dir].comp_id; switch (cmd) { case SNDRV_PCM_TRIGGER_PAUSE_PUSH: @@ -172,7 +162,7 @@ static int sof_ipc3_pcm_trigger(struct snd_soc_component *component, stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP; break; default: - spcm_err(spcm, substream->stream, "Unhandled trigger cmd %d\n", cmd); + spcm_err(spcm, dir, "Unhandled trigger cmd %d\n", cmd); return -EINVAL; } diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index c327249e7b8e89..cf42148c4dc972 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -413,28 +413,23 @@ static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev, } static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, - struct snd_pcm_substream *substream, int state, int cmd) + struct snd_pcm_substream *substream, int state, int cmd, + struct snd_sof_pcm *spcm, int dir) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_sof_pcm_stream_pipeline_list *pipeline_list; struct sof_ipc4_fw_data *ipc4_data = sdev->private; struct ipc4_pipeline_set_state_data *trigger_list; struct snd_sof_widget *pipe_widget; struct sof_ipc4_pipeline *pipeline; struct snd_sof_pipeline *spipe; - struct snd_sof_pcm *spcm; u8 *pipe_priority; int ret; int i; - spcm = snd_sof_find_spcm_dai(component, rtd); - if (!spcm) - return -EINVAL; + spcm_dbg(spcm, dir, "cmd: %d, state: %d\n", cmd, state); - spcm_dbg(spcm, substream->stream, "cmd: %d, state: %d\n", cmd, state); - - pipeline_list = &spcm->stream[substream->stream].pipeline_list; + pipeline_list = &spcm->stream[dir].pipeline_list; guard(mutex)(&ipc4_data->pipeline_state_mutex); /* nothing to trigger if the list is empty */ @@ -455,9 +450,9 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, if (pipeline->use_chain_dma) { struct sof_ipc4_timestamp_info *time_info; - time_info = sof_ipc4_sps_to_time_info(&spcm->stream[substream->stream]); + time_info = sof_ipc4_sps_to_time_info(&spcm->stream[dir]); - ret = sof_ipc4_chain_dma_trigger(sdev, spcm, substream->stream, + ret = sof_ipc4_chain_dma_trigger(sdev, spcm, dir, pipeline_list, state, cmd); if (ret || !time_info) return ret; @@ -466,12 +461,16 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, /* * Record the DAI position for delay reporting * To handle multiple pause/resume/xrun we need to add - * the positions to simulate how the firmware behaves + * the positions to simulate how the firmware behaves. + * Chained DMA does not support compress streams. We should + * never get here with compress. */ - u64 pos = snd_sof_pcm_get_dai_frame_counter(sdev, component, - substream); + if (substream) { + u64 pos = snd_sof_pcm_get_dai_frame_counter(sdev, component, + substream); - time_info->stream_end_offset += pos; + time_info->stream_end_offset += pos; + } } else if (state == SOF_IPC4_PIPE_RESET) { /* Reset the end offset as the stream is stopped */ time_info->stream_end_offset = 0; @@ -534,7 +533,7 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, */ ret = sof_ipc4_set_multi_pipeline_state(sdev, SOF_IPC4_PIPE_PAUSED, trigger_list); if (ret < 0) { - spcm_err(spcm, substream->stream, "failed to pause all pipelines\n"); + spcm_err(spcm, dir, "failed to pause all pipelines\n"); /* * workaround: if the firmware is crashed or the IPC timed out * while setting the pipeline state we must ignore the error @@ -567,7 +566,7 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, * Invalidate the stream_start_offset to make sure that it is * going to be updated if the stream resumes */ - time_info = sof_ipc4_sps_to_time_info(&spcm->stream[substream->stream]); + time_info = sof_ipc4_sps_to_time_info(&spcm->stream[dir]); if (time_info) time_info->stream_start_offset = SOF_IPC4_INVALID_STREAM_POSITION; @@ -577,7 +576,7 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, /* else set the RUNNING/RESET state in the DSP */ ret = sof_ipc4_set_multi_pipeline_state(sdev, state, trigger_list); if (ret < 0) { - spcm_err(spcm, substream->stream, + spcm_err(spcm, dir, "failed to set final state %d for all pipelines\n", state); /* @@ -610,7 +609,8 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, } static int sof_ipc4_pcm_trigger(struct snd_soc_component *component, - struct snd_pcm_substream *substream, int cmd) + struct snd_pcm_substream *substream, + struct snd_sof_pcm *spcm, int cmd, int dir) { int state; @@ -632,14 +632,15 @@ static int sof_ipc4_pcm_trigger(struct snd_soc_component *component, } /* set the pipeline state */ - return sof_ipc4_trigger_pipelines(component, substream, state, cmd); + return sof_ipc4_trigger_pipelines(component, substream, state, cmd, spcm, dir); } static int sof_ipc4_pcm_hw_free(struct snd_soc_component *component, - struct snd_pcm_substream *substream) + struct snd_pcm_substream *substream, + struct snd_sof_pcm *spcm, int dir) { /* command is not relevant with RESET, so just pass 0 */ - return sof_ipc4_trigger_pipelines(component, substream, SOF_IPC4_PIPE_RESET, 0); + return sof_ipc4_trigger_pipelines(component, substream, SOF_IPC4_PIPE_RESET, 0, spcm, dir); } static int ipc4_ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 8f59c200b8ec1c..42738f12fa3390 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -152,7 +152,7 @@ static int sof_pcm_hw_params(struct snd_soc_component *component, * between. At least ALSA OSS emulation depends on this. */ if (spcm->prepared[substream->stream] && pcm_ops && pcm_ops->hw_free) { - ret = pcm_ops->hw_free(component, substream); + ret = pcm_ops->hw_free(component, substream, spcm, substream->stream); if (ret < 0) return ret; @@ -223,7 +223,8 @@ static int sof_pcm_stream_free(struct snd_sof_dev *sdev, /* free PCM in the DSP */ if (pcm_ops && pcm_ops->hw_free) { - ret = pcm_ops->hw_free(sdev->component, substream); + ret = pcm_ops->hw_free(sdev->component, substream, spcm, + substream->stream); if (ret < 0) { spcm_err(spcm, substream->stream, "pcm_ops->hw_free failed %d\n", ret); @@ -458,7 +459,7 @@ static int sof_pcm_trigger(struct snd_soc_component *component, snd_sof_pcm_platform_trigger(sdev, substream, cmd); if (pcm_ops && pcm_ops->trigger) - ret = pcm_ops->trigger(component, substream, cmd); + ret = pcm_ops->trigger(component, substream, spcm, cmd, substream->stream); switch (cmd) { case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index edfde688c86847..aa685913a18ae9 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -125,9 +125,10 @@ struct sof_ipc_pcm_ops { int (*hw_params)(struct snd_soc_component *component, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_sof_platform_stream_params *platform_params); - int (*hw_free)(struct snd_soc_component *component, struct snd_pcm_substream *substream); - int (*trigger)(struct snd_soc_component *component, struct snd_pcm_substream *substream, - int cmd); + int (*hw_free)(struct snd_soc_component *component, struct snd_pcm_substream *substream, + struct snd_sof_pcm *spcm, int dir); + int (*trigger)(struct snd_soc_component *component, struct snd_pcm_substream *substream, + struct snd_sof_pcm *spcm, int cmd, int dir); 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); From fac3f543b17d436a5c620f91be96d749b175be77 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 8 Dec 2025 20:27:18 -0800 Subject: [PATCH 31/83] ASoC: SOF: intel: hda-stream: Clear the current position when releasing stream After the host DMA ID is released, reset the curr_pos to 0 for a clean start for subsequent stream starts. This is not needed for PCM streams but for compressed streams. Signed-off-by: Ranjani Sridharan Signed-off-by: Peter Ujfalusi --- sound/soc/sof/intel/hda-stream.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index fae7a669924562..05185e007bd5b0 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -320,6 +320,7 @@ static int _hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stre hext_stream_match = hext_stream; s->opened = false; found = true; + s->curr_pos = 0; if (pair) link_stream = hext_stream; } else if (!(hda_stream->flags & SOF_HDA_STREAM_DMI_L1_COMPATIBLE)) { From 68aaa229307f13478244c2629a3e512e42878b1f Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 8 Dec 2025 20:24:36 -0800 Subject: [PATCH 32/83] ASoC: SOF: ops: Add new platform-specific ops for compress Add new ops in the struct snd_sof_ops for platform-specific ops for compresssed streams. Also, define and set them for the HDA platforms. Signed-off-by: Ranjani Sridharan Co-developed-by: Peter Ujfalusi Signed-off-by: Peter Ujfalusi --- sound/soc/sof/intel/hda-common-ops.c | 8 ++ sound/soc/sof/intel/hda-pcm.c | 142 +++++++++++++++++++++++++++ sound/soc/sof/intel/hda-stream.c | 53 +++++++--- sound/soc/sof/intel/hda.h | 15 +++ sound/soc/sof/ops.h | 74 ++++++++++++++ sound/soc/sof/sof-priv.h | 12 +++ 6 files changed, 293 insertions(+), 11 deletions(-) diff --git a/sound/soc/sof/intel/hda-common-ops.c b/sound/soc/sof/intel/hda-common-ops.c index 746b426b1329b0..aa91f2b6fd657b 100644 --- a/sound/soc/sof/intel/hda-common-ops.c +++ b/sound/soc/sof/intel/hda-common-ops.c @@ -57,6 +57,14 @@ const struct snd_sof_dsp_ops sof_hda_common_ops = { .pcm_pointer = hda_dsp_pcm_pointer, .pcm_ack = hda_dsp_pcm_ack, + .compr_open = hda_dsp_compr_open, + .compr_hw_params = hda_dsp_compr_hw_params, + .compr_hw_free = hda_dsp_stream_compr_hw_free, + .compr_close = hda_dsp_compr_close, + .compr_trigger = hda_dsp_compr_trigger, + .compr_pointer = hda_dsp_compr_pointer, + .compr_get_dai_frame_counter = hda_dsp_compr_get_stream_llp, + .get_dai_frame_counter = hda_dsp_get_stream_llp, .get_host_byte_counter = hda_dsp_get_stream_ldp, diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index 16a3640728210b..7d846c1f350967 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -151,6 +151,71 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, } EXPORT_SYMBOL_NS(hda_dsp_pcm_hw_params, "SND_SOC_SOF_INTEL_HDA_COMMON"); +int hda_dsp_compr_hw_params(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, + struct snd_compr_params *params, + struct snd_sof_platform_stream_params *platform_params) +{ + struct hdac_stream *hstream = cstream->runtime->private_data; + struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream); + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + struct snd_dma_buffer *dmab; + u32 bits, rate; + int bps; + int ret; + + hstream->cstream = cstream; + dmab = cstream->runtime->dma_buffer_p; + + /* Use correct format based on the used codec */ + switch (params->codec.id) { + case SND_AUDIOCODEC_PCM: + bps = snd_pcm_format_physical_width(params->codec.format); + break; + case SND_AUDIOCODEC_VORBIS: + bps = snd_pcm_format_physical_width(SNDRV_PCM_FORMAT_S16_LE); + break; + case SND_AUDIOCODEC_FLAC: + { + struct snd_dec_flac *dec_flac = ¶ms->codec.options.flac_d; + + if (dec_flac->sample_size == 16) + bps = snd_pcm_format_physical_width(SNDRV_PCM_FORMAT_S16_LE); + else + bps = snd_pcm_format_physical_width(SNDRV_PCM_FORMAT_S32_LE); + break; + } + default: + bps = snd_pcm_format_physical_width(SNDRV_PCM_FORMAT_S32_LE); + } + + if (bps < 0) + return bps; + bits = hda_dsp_get_bits(sdev, bps); + rate = hda_dsp_get_mult_div(sdev, params->codec.sample_rate); + + hstream->format_val = rate | bits | (params->codec.ch_out - 1); + hstream->bufsize = cstream->runtime->buffer_size; + hstream->period_bytes = cstream->runtime->fragment_size; + hstream->no_period_wakeup = false; + + /* params is not used so pass NULL */ + dmab = cstream->runtime->dma_buffer_p; + ret = hda_dsp_stream_hw_params(sdev, hext_stream, dmab, NULL); + if (ret < 0) { + dev_err(sdev->dev, "%s: hdac prepare failed: %d\n", __func__, ret); + return ret; + } + + if (hda) + platform_params->no_ipc_position = hda->no_ipc_position; + + platform_params->stream_tag = hstream->stream_tag; + + return 0; +} +EXPORT_SYMBOL_NS(hda_dsp_compr_hw_params, "SND_SOC_SOF_INTEL_HDA_COMMON"); + /* update SPIB register with appl position */ int hda_dsp_pcm_ack(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) { @@ -184,6 +249,16 @@ int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev, } EXPORT_SYMBOL_NS(hda_dsp_pcm_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON"); +int hda_dsp_compr_trigger(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, int cmd) +{ + struct hdac_stream *hstream = cstream->runtime->private_data; + struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream); + + return hda_dsp_stream_trigger(sdev, hext_stream, cmd); +} +EXPORT_SYMBOL_NS(hda_dsp_compr_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON"); + snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) { @@ -216,6 +291,20 @@ snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev, } EXPORT_SYMBOL_NS(hda_dsp_pcm_pointer, "SND_SOC_SOF_INTEL_HDA_COMMON"); +int hda_dsp_compr_pointer(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream, + struct snd_compr_tstamp64 *tstamp) +{ + struct hdac_stream *hstream = cstream->runtime->private_data; + + /* hstream->curr_pos is updated when we receive the ioc */ + tstamp->copied_total = hstream->curr_pos; + + tstamp->byte_offset = hda_dsp_stream_get_position(hstream, cstream->direction, true); + + return 0; +} +EXPORT_SYMBOL_NS(hda_dsp_compr_pointer, "SND_SOC_SOF_INTEL_HDA_COMMON"); + int hda_dsp_pcm_open(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) { @@ -342,6 +431,41 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev, } EXPORT_SYMBOL_NS(hda_dsp_pcm_open, "SND_SOC_SOF_INTEL_HDA_COMMON"); +int hda_dsp_compr_open(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *scomp = sdev->component; + struct hdac_ext_stream *dsp_stream; + struct snd_sof_pcm *spcm; + int direction = cstream->direction; + + spcm = snd_sof_find_spcm_dai(scomp, rtd); + if (!spcm) { + dev_err(sdev->dev, "%s: can't find PCM with DAI ID %d\n", + __func__, rtd->dai_link->id); + return -EINVAL; + } + + dsp_stream = hda_dsp_stream_get(sdev, direction, 0); + if (!dsp_stream) { + dev_err(sdev->dev, "%s: no stream available\n", __func__); + return -ENODEV; + } + + /* binding compr stream to hda stream */ + cstream->runtime->private_data = &dsp_stream->hstream; + + /* + * Reset the llp cache values (they are used for LLP compensation in + * case the counter is not reset) + */ + dsp_stream->pplcllpl = 0; + dsp_stream->pplcllpu = 0; + + return 0; +} +EXPORT_SYMBOL_NS(hda_dsp_compr_open, "SND_SOC_SOF_INTEL_HDA_COMMON"); + int hda_dsp_pcm_close(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) { @@ -361,3 +485,21 @@ int hda_dsp_pcm_close(struct snd_sof_dev *sdev, return 0; } EXPORT_SYMBOL_NS(hda_dsp_pcm_close, "SND_SOC_SOF_INTEL_HDA_COMMON"); + +int hda_dsp_compr_close(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream) +{ + struct hdac_stream *hstream = cstream->runtime->private_data; + int direction = cstream->direction; + int ret; + + ret = hda_dsp_stream_put(sdev, direction, hstream->stream_tag); + if (ret) + return -ENODEV; + + /* unbinding compress stream to hda stream */ + hstream->cstream = NULL; + cstream->runtime->private_data = NULL; + + return 0; +} +EXPORT_SYMBOL_NS(hda_dsp_compr_close, "SND_SOC_SOF_INTEL_HDA_COMMON"); diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 05185e007bd5b0..9c873838dff491 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -769,13 +769,12 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, return ret; } -int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream) +static int _hda_dsp_stream_hw_free(struct snd_sof_dev *sdev, + struct hdac_stream *hstream) { - struct hdac_stream *hstream = substream->runtime->private_data; struct hdac_ext_stream *hext_stream = container_of(hstream, - struct hdac_ext_stream, - hstream); + struct hdac_ext_stream, + hstream); int ret; ret = hda_dsp_stream_reset(sdev, hstream); @@ -800,8 +799,21 @@ int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev, return 0; } + +int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + return _hda_dsp_stream_hw_free(sdev, substream->runtime->private_data); +} EXPORT_SYMBOL_NS(hda_dsp_stream_hw_free, "SND_SOC_SOF_INTEL_HDA_COMMON"); +int hda_dsp_stream_compr_hw_free(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream) +{ + return _hda_dsp_stream_hw_free(sdev, cstream->runtime->private_data); +} +EXPORT_SYMBOL_NS(hda_dsp_stream_compr_hw_free, "SND_SOC_SOF_INTEL_HDA_COMMON"); + bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); @@ -1184,11 +1196,9 @@ EXPORT_SYMBOL_NS(hda_dsp_stream_get_position, "SND_SOC_SOF_INTEL_HDA_COMMON"); * * Returns the raw Linear Link Position value */ -u64 hda_dsp_get_stream_llp(struct snd_sof_dev *sdev, - struct snd_soc_component *component, - struct snd_pcm_substream *substream) +static u64 hda_dsp_get_llp(struct snd_sof_dev *sdev, + struct snd_soc_pcm_runtime *rtd, int dir) { - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_pcm_runtime *be_rtd = NULL; struct hdac_ext_stream *hext_stream; struct snd_soc_dai *cpu_dai; @@ -1199,7 +1209,7 @@ u64 hda_dsp_get_stream_llp(struct snd_sof_dev *sdev, * The LLP needs to be read from the Link DMA used for this FE as it is * allowed to use any combination of Link and Host channels */ - for_each_dpcm_be(rtd, substream->stream, dpcm) { + for_each_dpcm_be(rtd, dir, dpcm) { if (dpcm->fe != rtd) continue; @@ -1213,7 +1223,7 @@ u64 hda_dsp_get_stream_llp(struct snd_sof_dev *sdev, if (!cpu_dai) return 0; - hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream); + hext_stream = snd_soc_dai_dma_data_get(cpu_dai, dir); if (!hext_stream) return 0; @@ -1237,8 +1247,29 @@ u64 hda_dsp_get_stream_llp(struct snd_sof_dev *sdev, return merge_u64(llp_u, llp_l); } + +u64 hda_dsp_get_stream_llp(struct snd_sof_dev *sdev, + struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + return hda_dsp_get_llp(sdev, snd_soc_substream_to_rtd(substream), + substream->stream); +} EXPORT_SYMBOL_NS(hda_dsp_get_stream_llp, "SND_SOC_SOF_INTEL_HDA_COMMON"); +/** + * hda_dsp_compr_get_stream_llp - Retrieve the LLP (Linear Link Position) of the stream + * @sdev: SOF device + * @cstream: Compress stream + * + * Returns the raw Linear Link Position value + */ +u64 hda_dsp_compr_get_stream_llp(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream) +{ + return hda_dsp_get_llp(sdev, cstream->private_data, cstream->direction); +} +EXPORT_SYMBOL_NS(hda_dsp_compr_get_stream_llp, "SND_SOC_SOF_INTEL_HDA_COMMON"); + /** * hda_dsp_get_stream_ldp - Retrieve the LDP (Linear DMA Position) of the stream * @sdev: SOF device diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 94aad096128ea6..f9d498f8d23c9b 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -683,6 +683,21 @@ snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream); int hda_dsp_pcm_ack(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream); +int hda_dsp_compr_open(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream); +int hda_dsp_compr_close(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream); +int hda_dsp_compr_hw_params(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, + struct snd_compr_params *params, + struct snd_sof_platform_stream_params *platform_params); +int hda_dsp_stream_compr_hw_free(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream); +int hda_dsp_compr_trigger(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, int cmd); +int hda_dsp_compr_pointer(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream, + struct snd_compr_tstamp64 *tstamp); +u64 hda_dsp_compr_get_stream_llp(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream); + /* * DSP Stream Operations. */ diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 1e606145dc853a..621e85ccce2f8e 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "sof-priv.h" @@ -456,6 +457,79 @@ snd_sof_pcm_platform_hw_params(struct snd_sof_dev *sdev, return 0; } +static inline int +snd_sof_compr_platform_open(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream) +{ + if (sof_ops(sdev) && sof_ops(sdev)->compr_open) + return sof_ops(sdev)->compr_open(sdev, cstream); + + return 0; +} + +/* disconnect pcm substream to a host stream */ +static inline int +snd_sof_compr_platform_close(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream) +{ + if (sof_ops(sdev) && sof_ops(sdev)->compr_close) + return sof_ops(sdev)->compr_close(sdev, cstream); + + return 0; +} + +/* host stream hw params */ +static inline int +snd_sof_compr_platform_hw_params(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, + struct snd_compr_params *params, + struct snd_sof_platform_stream_params *platform_params) +{ + if (sof_ops(sdev) && sof_ops(sdev)->compr_hw_params) + return sof_ops(sdev)->compr_hw_params(sdev, cstream, params, platform_params); + + return 0; +} + +static inline int +snd_sof_compr_platform_hw_free(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream) +{ + if (sof_ops(sdev) && sof_ops(sdev)->compr_hw_free) + return sof_ops(sdev)->compr_hw_free(sdev, cstream); + + return 0; +} + +static inline int +snd_sof_compr_platform_trigger(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, int cmd) +{ + if (sof_ops(sdev) && sof_ops(sdev)->compr_trigger) + return sof_ops(sdev)->compr_trigger(sdev, cstream, cmd); + + return 0; +} + +static inline int +snd_sof_compr_platform_pointer(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream, + struct snd_compr_tstamp64 *tstamp) +{ + if (sof_ops(sdev) && sof_ops(sdev)->compr_pointer) + return sof_ops(sdev)->compr_pointer(sdev, cstream, tstamp); + + return 0; +} + +static inline u64 +snd_sof_compr_get_dai_frame_counter(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream) +{ + if (sof_ops(sdev) && sof_ops(sdev)->compr_get_dai_frame_counter) + return sof_ops(sdev)->compr_get_dai_frame_counter(sdev, cstream); + + return 0; +} + /* host stream hw free */ static inline int snd_sof_pcm_platform_hw_free(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 20f033254f07e7..a3c507e8d46388 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -262,6 +262,18 @@ struct snd_sof_dsp_ops { /* pcm ack */ int (*pcm_ack)(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream); /* optional */ + int (*compr_open)(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream); + int (*compr_close)(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream); + int (*compr_hw_params)(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream, + struct snd_compr_params *params, + struct snd_sof_platform_stream_params *platform_params); + int (*compr_hw_free)(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream); + int (*compr_trigger)(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream, + int cmd); + int (*compr_pointer)(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream, + struct snd_compr_tstamp64 *tstamp); + u64 (*compr_get_dai_frame_counter)(struct snd_sof_dev *sdev, + struct snd_compr_stream *cstream); /* * optional callback to retrieve the number of frames left/arrived from/to * the DSP on the DAI side (link/codec/DMIC/etc). From d31ad10b77dd6a35cf2107a051593738d84b9781 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 12 Jan 2026 18:19:35 +0200 Subject: [PATCH 33/83] ASoC: SOF: ipc4: Add definition of module data in init_ext object type The SOF_IPC4_MOD_INIT_DATA_ID_MODULE_DATA type within the module_init_ext area is module specific init data. Signed-off-by: Peter Ujfalusi --- include/sound/sof/ipc4/header.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/sound/sof/ipc4/header.h b/include/sound/sof/ipc4/header.h index 5fd2486582cd49..144ded268b5b6d 100644 --- a/include/sound/sof/ipc4/header.h +++ b/include/sound/sof/ipc4/header.h @@ -681,7 +681,8 @@ struct sof_ipc4_module_init_ext_object { enum sof_ipc4_mod_init_ext_obj_id { SOF_IPC4_MOD_INIT_DATA_ID_INVALID = 0, SOF_IPC4_MOD_INIT_DATA_ID_DP_DATA, - SOF_IPC4_MOD_INIT_DATA_ID_MAX = SOF_IPC4_MOD_INIT_DATA_ID_DP_DATA, + SOF_IPC4_MOD_INIT_DATA_ID_MODULE_DATA, + SOF_IPC4_MOD_INIT_DATA_ID_MAX = SOF_IPC4_MOD_INIT_DATA_ID_MODULE_DATA, }; /* DP module memory configuration data object for ext_init object array */ From cd504c5cad9e22d80927dee5779320f1bb8ade56 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 13 Jan 2026 09:00:52 +0200 Subject: [PATCH 34/83] ASoC: SOF: ipc4-topology: Support init_ext_module_data for process modules Add support for handling init_ext_module_data for process modules, which is going to be used by decoder and encoder type of process modules. The support is generic and it can be extended to other type of process modules or other module types than process with a small update of sof_ipc4_add_init_ext_module_data() function. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/ipc4-topology.c | 53 +++++++++++++++++++++++++++-------- sound/soc/sof/ipc4-topology.h | 4 +++ sound/soc/sof/sof-audio.h | 1 + 3 files changed, 46 insertions(+), 12 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 6bb735479db0a9..244b6d852bc88a 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -3264,6 +3264,36 @@ static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_contr return 0; } +static void +sof_ipc4_add_init_ext_module_data(struct snd_sof_dev *sdev, + struct snd_sof_widget *swidget, + u32 *payload, u32 *ext_pos, + struct sof_ipc4_module_init_ext_object **hdr) +{ + struct sof_ipc4_process *process = swidget->private; + u32 data_size; + void *data; + + /* + * Check if widget is process module and if it is using + * init_ext_module_data + */ + if (!WIDGET_IS_PROCESS(swidget->id) || !process->init_ext_module_size) + return; + + data_size = process->init_ext_module_size; + data = process->init_ext_module_data; + + *hdr = (struct sof_ipc4_module_init_ext_object *)&payload[*ext_pos]; + (*hdr)->header = SOF_IPC4_MOD_INIT_EXT_OBJ_ID(SOF_IPC4_MOD_INIT_DATA_ID_MODULE_DATA) | + SOF_IPC4_MOD_INIT_EXT_OBJ_WORDS(DIV_ROUND_UP(data_size, sizeof(u32))); + *ext_pos += DIV_ROUND_UP(sizeof(*(*hdr)), sizeof(u32)); + + memcpy(&payload[*ext_pos], data, data_size); + + *ext_pos += DIV_ROUND_UP(data_size, sizeof(u32)); +} + static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, struct sof_ipc4_msg *msg, @@ -3272,20 +3302,11 @@ static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev, { struct sof_ipc4_mod_init_ext_dp_memory_data *dp_mem_data; struct sof_ipc4_module_init_ext_init *ext_init; - struct sof_ipc4_module_init_ext_object *hdr; + struct sof_ipc4_module_init_ext_object *hdr = NULL; int new_size; u32 *payload; u32 ext_pos; - /* For the moment the only reason for adding init_ext_init payload is DP - * memory data. If both stack and heap size are 0 (= use default), then - * there is no need for init_ext_init payload. - */ - if (swidget->comp_domain != SOF_COMP_DOMAIN_DP) { - msg->extension &= ~SOF_IPC4_MOD_EXT_EXTENDED_INIT_MASK; - return 0; - } - payload = kzalloc(sdev->ipc->max_payload_size, GFP_KERNEL); if (!payload) return -ENOMEM; @@ -3300,7 +3321,7 @@ static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev, /* Add dp_memory_data if comp_domain indicates DP */ if (swidget->comp_domain == SOF_COMP_DOMAIN_DP) { hdr = (struct sof_ipc4_module_init_ext_object *)&payload[ext_pos]; - hdr->header = SOF_IPC4_MOD_INIT_EXT_OBJ_LAST_MASK | + hdr->header = SOF_IPC4_MOD_INIT_EXT_OBJ_ID(SOF_IPC4_MOD_INIT_DATA_ID_DP_DATA) | SOF_IPC4_MOD_INIT_EXT_OBJ_WORDS(DIV_ROUND_UP(sizeof(*dp_mem_data), sizeof(u32))); @@ -3312,7 +3333,15 @@ static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev, ext_pos += DIV_ROUND_UP(sizeof(*dp_mem_data), sizeof(u32)); } - /* If another array object is added, remember clear previous OBJ_LAST bit */ + sof_ipc4_add_init_ext_module_data(sdev, swidget, payload, &ext_pos, &hdr); + + /* Set last bit for the last object in the array */ + if (hdr) { + hdr->header |= SOF_IPC4_MOD_INIT_EXT_OBJ_LAST_MASK; + } else { + kfree(payload); + return 0; + } /* Calculate final size and check that it fits to max payload size */ new_size = ext_pos * sizeof(u32) + ipc_size; diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h index ce086188d6e1e0..f2f0af5b5dba59 100644 --- a/sound/soc/sof/ipc4-topology.h +++ b/sound/soc/sof/ipc4-topology.h @@ -521,6 +521,8 @@ struct sof_ipc4_base_module_cfg_ext { * @msg: IPC4 message struct containing header and data info * @base_config_ext_size: Size of the base config extension data in bytes * @init_config: Module init config type (SOF_IPC4_MODULE_INIT_CONFIG_TYPE_*) + * @init_ext_module_data: module_data for init_ext object + * @init_ext_module_size: size of init_ext_module_data */ struct sof_ipc4_process { struct sof_ipc4_base_module_cfg base_config; @@ -532,6 +534,8 @@ struct sof_ipc4_process { struct sof_ipc4_msg msg; u32 base_config_ext_size; u32 init_config; + void *init_ext_module_data; + size_t init_ext_module_size; }; bool sof_ipc4_copier_is_single_bitdepth(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index aa685913a18ae9..3e3acb1895de40 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -43,6 +43,7 @@ #define WIDGET_IS_AIF(id) ((id) == snd_soc_dapm_aif_in || (id) == snd_soc_dapm_aif_out) #define WIDGET_IS_AIF_OR_DAI(id) (WIDGET_IS_DAI(id) || WIDGET_IS_AIF(id)) #define WIDGET_IS_COPIER(id) (WIDGET_IS_AIF_OR_DAI(id) || (id) == snd_soc_dapm_buffer) +#define WIDGET_IS_PROCESS(id) ((id) == snd_soc_dapm_effect) #define SOF_DAI_PARAM_INTEL_SSP_MCLK 0 #define SOF_DAI_PARAM_INTEL_SSP_BCLK 1 From ddf5014a75f4e87446cfed8d952593c374991cfe Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 13 Jan 2026 12:04:26 +0200 Subject: [PATCH 35/83] ASoC: SOF: ipc4-pcm: Make the timestamp info usable outside of ipc4-pcm.c The support for compressed stream will also need to have access to the same information which is used for delay reporting for DAI data progression tracking. Make the necessary struct and functions to be available and premare them to be called without a valid substream. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/ipc4-pcm.c | 40 +++++++++------------------------------ sound/soc/sof/ipc4-priv.h | 31 ++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 31 deletions(-) diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index cf42148c4dc972..b2abcc63447ee6 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -15,29 +15,6 @@ #include "ipc4-topology.h" #include "ipc4-fw-reg.h" -/** - * struct sof_ipc4_timestamp_info - IPC4 timestamp info - * @host_copier: the host copier of the pcm stream - * @dai_copier: the dai copier of the pcm stream - * @stream_start_offset: reported by fw in memory window (converted to - * frames at host_copier sampling rate) - * @stream_end_offset: reported by fw in memory window (converted to - * frames at host_copier sampling rate) - * @llp_offset: llp offset in memory window - * @delay: Calculated and stored in pointer callback. The stored value is - * returned in the delay callback. Expressed in frames at host copier - * sampling rate. - */ -struct sof_ipc4_timestamp_info { - struct sof_ipc4_copier *host_copier; - struct sof_ipc4_copier *dai_copier; - u64 stream_start_offset; - u64 stream_end_offset; - u32 llp_offset; - - snd_pcm_sframes_t delay; -}; - /** * struct sof_ipc4_pcm_stream_priv - IPC4 specific private data * @time_info: pointer to time info struct if it is supported, otherwise NULL @@ -61,7 +38,7 @@ struct sof_ipc4_pcm_stream_priv { #define DELAY_MAX (DELAY_BOUNDARY >> 1) -static inline struct sof_ipc4_timestamp_info * +struct sof_ipc4_timestamp_info * sof_ipc4_sps_to_time_info(struct snd_sof_pcm_stream *sps) { struct sof_ipc4_pcm_stream_priv *stream_priv = sps->private; @@ -991,7 +968,7 @@ static int sof_ipc4_pcm_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm return 0; } -static void sof_ipc4_build_time_info(struct snd_sof_dev *sdev, struct snd_sof_pcm_stream *sps) +void sof_ipc4_build_time_info(struct snd_sof_dev *sdev, struct snd_sof_pcm_stream *sps) { struct sof_ipc4_copier *host_copier = NULL; struct sof_ipc4_copier *dai_copier = NULL; @@ -1089,7 +1066,7 @@ static int sof_ipc4_pcm_hw_params(struct snd_soc_component *component, return 0; } -static u64 sof_ipc4_frames_dai_to_host(struct sof_ipc4_timestamp_info *time_info, u64 value) +u64 sof_ipc4_frames_dai_to_host(struct sof_ipc4_timestamp_info *time_info, u64 value) { u64 dai_rate, host_rate; @@ -1118,10 +1095,10 @@ static u64 sof_ipc4_frames_dai_to_host(struct sof_ipc4_timestamp_info *time_info return value; } -static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream, - struct snd_sof_pcm_stream *sps, - struct sof_ipc4_timestamp_info *time_info) +int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + struct snd_sof_pcm_stream *sps, + struct sof_ipc4_timestamp_info *time_info) { struct sof_ipc4_copier *host_copier = time_info->host_copier; struct sof_ipc4_copier *dai_copier = time_info->dai_copier; @@ -1135,7 +1112,8 @@ static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev, if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_INVALID_NODE_ID) { return -EINVAL; - } else if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_CHAIN_DMA_NODE_ID) { + } else if (substream && + host_copier->data.gtw_cfg.node_id == SOF_IPC4_CHAIN_DMA_NODE_ID) { /* * While the firmware does not support time_info reporting for * streams using ChainDMA, it is granted that ChainDMA can only diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h index a8cdf9bc750b4d..7c0861d63bef4a 100644 --- a/sound/soc/sof/ipc4-priv.h +++ b/sound/soc/sof/ipc4-priv.h @@ -98,6 +98,29 @@ struct sof_ipc4_fw_data { struct mutex pipeline_state_mutex; /* protect pipeline triggers, ref counts and states */ }; +/** + * struct sof_ipc4_timestamp_info - IPC4 timestamp info + * @host_copier: the host copier of the pcm stream + * @dai_copier: the dai copier of the pcm stream + * @stream_start_offset: reported by fw in memory window (converted to + * frames at host_copier sampling rate) + * @stream_end_offset: reported by fw in memory window (converted to + * frames at host_copier sampling rate) + * @llp_offset: llp offset in memory window + * @delay: Calculated and stored in pointer callback. The stored value is + * returned in the delay callback. Expressed in frames at host copier + * sampling rate. + */ +struct sof_ipc4_timestamp_info { + struct sof_ipc4_copier *host_copier; + struct sof_ipc4_copier *dai_copier; + u64 stream_start_offset; + u64 stream_end_offset; + u32 llp_offset; + + snd_pcm_sframes_t delay; +}; + extern const struct sof_ipc_fw_loader_ops ipc4_loader_ops; extern const struct sof_ipc_tplg_ops ipc4_tplg_ops; extern const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops; @@ -129,4 +152,12 @@ void sof_ipc4_mic_privacy_state_change(struct snd_sof_dev *sdev, bool state); enum sof_ipc4_pipeline_state; const char *sof_ipc4_pipeline_state_str(enum sof_ipc4_pipeline_state state); +struct sof_ipc4_timestamp_info *sof_ipc4_sps_to_time_info(struct snd_sof_pcm_stream *sps); +void sof_ipc4_build_time_info(struct snd_sof_dev *sdev, struct snd_sof_pcm_stream *sps); +int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + struct snd_sof_pcm_stream *sps, + struct sof_ipc4_timestamp_info *time_info); +u64 sof_ipc4_frames_dai_to_host(struct sof_ipc4_timestamp_info *time_info, u64 value); + #endif From 2e62e1ccaadbdf56e4c394a1a5b2a2b94cb3d304 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 14 Jan 2026 13:23:40 +0200 Subject: [PATCH 36/83] ASoC: SOF: ipc4/ipc4-loader: Add SOF_INFO and CODEC_INFO to fw_config_params SOF_INFO (id == 35) tuple holds tuple structured information about SOF features. The first entry in SOF_INFO is the SOF_CODEC_INFO (id == 0) which contains information about the supported codecs for decode/encode in the booted firmware. If present in the fw_config payload, make a copy of it and store it sof_ipc4_fw_data->codec_info to be used by the compressed code. Signed-off-by: Peter Ujfalusi --- include/sound/sof/ipc4/header.h | 18 ++++++++---- sound/soc/sof/ipc4-loader.c | 51 +++++++++++++++++++++++++++++++++ sound/soc/sof/ipc4-priv.h | 4 +++ 3 files changed, 67 insertions(+), 6 deletions(-) diff --git a/include/sound/sof/ipc4/header.h b/include/sound/sof/ipc4/header.h index 144ded268b5b6d..2c0d399f4729c1 100644 --- a/include/sound/sof/ipc4/header.h +++ b/include/sound/sof/ipc4/header.h @@ -433,12 +433,10 @@ enum sof_ipc4_fw_config_params { SOF_IPC4_FW_CFG_RESERVED, SOF_IPC4_FW_CFG_POWER_GATING_POLICY, SOF_IPC4_FW_CFG_ASSERT_MODE, - SOF_IPC4_FW_RESERVED1, - SOF_IPC4_FW_RESERVED2, - SOF_IPC4_FW_RESERVED3, - SOF_IPC4_FW_RESERVED4, - SOF_IPC4_FW_RESERVED5, - SOF_IPC4_FW_CONTEXT_SAVE + /* Reserved: 24 - 28 */ + SOF_IPC4_FW_CONTEXT_SAVE = 29, + /* Reserved: 30 - 34 */ + SOF_IPC4_FW_CFG_SOF_INFO = 35, }; struct sof_ipc4_fw_version { @@ -448,6 +446,14 @@ struct sof_ipc4_fw_version { uint16_t build; } __packed; +/* + * tuple based array for SOF specific information under SOF_IPC4_FW_CFG_SOF_INFO + * tuple of fw_config + */ +enum ipc4_fw_sof_info_params { + SOF_IPC4_SOF_CODEC_INFO, +}; + /* Payload data for SOF_IPC4_MOD_SET_DX */ struct sof_ipc4_dx_state_info { /* core(s) to apply the change */ diff --git a/sound/soc/sof/ipc4-loader.c b/sound/soc/sof/ipc4-loader.c index e3007648d78681..8778cac0d52520 100644 --- a/sound/soc/sof/ipc4-loader.c +++ b/sound/soc/sof/ipc4-loader.c @@ -417,6 +417,52 @@ static int sof_ipc4_validate_firmware(struct snd_sof_dev *sdev) return 0; } +static int sof_ipc4_query_sof_info(struct snd_sof_dev *sdev, + void *sof_info_data, u32 sof_info_size) +{ + struct sof_ipc4_fw_data *ipc4_data = sdev->private; + struct sof_ipc4_tuple *tuple; + size_t tuple_size; + size_t offset = 0; + int ret = 0; + + while (offset < sof_info_size) { + if (sof_info_size - offset < sizeof(*tuple)) { + dev_err(sdev->dev, "Invalid SOF info tuple header at offset %zu\n", offset); + ret = -EINVAL; + goto out; + } + + tuple = (struct sof_ipc4_tuple *)((u8 *)sof_info_data + offset); + tuple_size = sizeof(*tuple) + tuple->size; + if (tuple_size < sizeof(*tuple) || tuple_size > sof_info_size - offset) { + dev_err(sdev->dev, + "Invalid SOF info tuple size %u at offset %zu\n", + tuple->size, offset); + ret = -EINVAL; + goto out; + } + + switch (tuple->type) { + case SOF_IPC4_SOF_CODEC_INFO: + ipc4_data->codec_info = devm_kmemdup(sdev->dev, tuple->value, + tuple->size, GFP_KERNEL); + if (!ipc4_data->codec_info) { + ret = -ENOMEM; + goto out; + } + break; + default: + break; + } + + offset += tuple_size; + } + +out: + return ret; +} + int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev) { struct sof_ipc4_fw_data *ipc4_data = sdev->private; @@ -492,6 +538,11 @@ int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev) */ ipc4_data->libraries_restored = ipc4_data->fw_context_save; break; + case SOF_IPC4_FW_CFG_SOF_INFO: + ret = sof_ipc4_query_sof_info(sdev, tuple->value, tuple->size); + if (ret) + goto out; + break; default: break; } diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h index 7c0861d63bef4a..07df6799c7a838 100644 --- a/sound/soc/sof/ipc4-priv.h +++ b/sound/soc/sof/ipc4-priv.h @@ -75,6 +75,8 @@ struct sof_ipc4_fw_library { * @fw_context_save: Firmware supports full context save and restore * @libraries_restored: The libraries have been retained during firmware boot * + * @codec_info: Information about the available codecs in booted firmware. The + * data is to be used by the code for compressed support. * @load_library: Callback function for platform dependent library loading * @pipeline_state_mutex: Mutex to protect pipeline triggers, ref counts, states and deletion */ @@ -91,6 +93,8 @@ struct sof_ipc4_fw_data { bool fw_context_save; bool libraries_restored; + void *codec_info; + int (*load_library)(struct snd_sof_dev *sdev, struct sof_ipc4_fw_library *fw_lib, bool reload); void (*intel_configure_mic_privacy)(struct snd_sof_dev *sdev, From c383d22abaf154a2ca5bf6eda53e521e3e44d8b2 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 30 Jan 2026 17:31:03 +0200 Subject: [PATCH 37/83] ASoC: SOF: ipc4-pcm: Handle COMPR DRAIN triggers as EOS pipeline state The DRAIN trigger is received by a compr device when user space wrote all the data to the buffer and it is waiting for the decoding to be completed. Set the pipeline state to EOS in firmware so it can expect the stream to be stopping anytime soon. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/ipc4-pcm.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index b2abcc63447ee6..c137d8477d04fd 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -154,7 +154,8 @@ 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 && state != SOF_IPC4_PIPE_RESET && + state != SOF_IPC4_PIPE_EOS) return; switch (state) { @@ -174,7 +175,12 @@ sof_ipc4_add_pipeline_to_trigger_list(struct snd_sof_dev *sdev, int state, false); break; case SOF_IPC4_PIPE_PAUSED: - /* Pause the pipeline only when its started_count is 1 more than paused_count */ + case SOF_IPC4_PIPE_EOS: + /* + * Pause the pipeline only when its started_count is 1 more than + * paused_count. + * Same rule applies to EOS state. + */ if (spipe->paused_count == (spipe->started_count - 1)) sof_ipc4_add_pipeline_by_priority(trigger_list, pipe_widget, pipe_priority, false); @@ -500,8 +506,9 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, goto free; } - /* no need to pause before reset or before pause release */ - if (state == SOF_IPC4_PIPE_RESET || cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE) + /* no need to pause before reset, EOS or before pause release */ + if (state == SOF_IPC4_PIPE_RESET || state == SOF_IPC4_PIPE_EOS || + cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE) goto skip_pause_transition; /* @@ -603,6 +610,10 @@ static int sof_ipc4_pcm_trigger(struct snd_soc_component *component, case SNDRV_PCM_TRIGGER_STOP: state = SOF_IPC4_PIPE_PAUSED; break; + case SND_COMPR_TRIGGER_DRAIN: + case SND_COMPR_TRIGGER_PARTIAL_DRAIN: + state = SOF_IPC4_PIPE_EOS; + break; default: dev_err(component->dev, "%s: unhandled trigger cmd %d\n", __func__, cmd); return -EINVAL; From 1044b897bca03256a0222ebc5fe735df141e97ac Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 30 Jan 2026 17:39:45 +0200 Subject: [PATCH 38/83] ASoC: SOF: ipc4-topology: Set FAST_MODE for host copier in compr mode FAST_MODE allows the host DMA to work in opportunistic, free running mode, which matches with the bitstream nature of compressed devices. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/ipc4-topology.c | 3 +++ sound/soc/sof/ipc4-topology.h | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 244b6d852bc88a..0e3a552d9bd2f0 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -744,6 +744,9 @@ static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget) sps->dsp_max_burst_size_in_ms = 1; } + if (spcm->pcm.compress) + ipc4_copier->data.copier_feature_mask |= BIT(SOF_IPC4_COPIER_FAST_MODE); + skip_gtw_cfg: ipc4_copier->gtw_attr = kzalloc_obj(*ipc4_copier->gtw_attr); if (!ipc4_copier->gtw_attr) { diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h index f2f0af5b5dba59..82adde9ba819d9 100644 --- a/sound/soc/sof/ipc4-topology.h +++ b/sound/soc/sof/ipc4-topology.h @@ -222,6 +222,11 @@ struct sof_copier_gateway_cfg { uint32_t config_data[]; }; +/* bit definition in copier_feature_mask */ +enum sof_ipc4_copier_feature { + SOF_IPC4_COPIER_FAST_MODE = 0, /* free running mode of host copier */ +}; + /** * struct sof_ipc4_copier_data - IPC data for copier * @base_config: Base configuration including input audio format From 1a18add39b6200ce48fb9f1ca3bd9a8b09b91c7a Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 8 Dec 2025 20:29:44 -0800 Subject: [PATCH 39/83] ASoC: SOF: Add support for IPC4 compressed Set and define the compressed ops for IPC4. The initial implementation supports basic features: PAUSE PUSH/RELEASE, DRAIN and progress reporting. Tested with PCM, MP3, AAC and VORBIS codec. Signed-off-by: Peter Ujfalusi Co-developed-by: Ranjani Sridharan --- sound/soc/sof/Makefile | 4 +- sound/soc/sof/ipc4-compress.c | 768 ++++++++++++++++++++++++++++++++++ sound/soc/sof/ipc4-pcm.c | 3 + sound/soc/sof/ipc4-priv.h | 10 + sound/soc/sof/sof-audio.h | 1 + 5 files changed, 784 insertions(+), 2 deletions(-) create mode 100644 sound/soc/sof/ipc4-compress.c diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index e19eedee76423a..887abf70da3ba1 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -8,10 +8,12 @@ snd-sof-y := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\ ifneq ($(CONFIG_SND_SOC_SOF_IPC3),) snd-sof-y += ipc3.o ipc3-loader.o ipc3-topology.o ipc3-control.o ipc3-pcm.o\ ipc3-dtrace.o +snd-sof-$(CONFIG_SND_SOC_SOF_COMPRESS) += ipc3-compress.o endif ifneq ($(CONFIG_SND_SOC_SOF_IPC4),) snd-sof-y += ipc4.o ipc4-loader.o ipc4-topology.o ipc4-control.o ipc4-pcm.o\ ipc4-mtrace.o ipc4-telemetry.o +snd-sof-$(CONFIG_SND_SOC_SOF_COMPRESS) += ipc4-compress.o endif # SOF client support @@ -19,8 +21,6 @@ ifneq ($(CONFIG_SND_SOC_SOF_CLIENT),) snd-sof-y += sof-client.o endif -snd-sof-$(CONFIG_SND_SOC_SOF_COMPRESS) += ipc3-compress.o - snd-sof-pci-y := sof-pci-dev.o snd-sof-acpi-y := sof-acpi-dev.o snd-sof-of-y := sof-of-dev.o diff --git a/sound/soc/sof/ipc4-compress.c b/sound/soc/sof/ipc4-compress.c new file mode 100644 index 00000000000000..bb9d32ca585b71 --- /dev/null +++ b/sound/soc/sof/ipc4-compress.c @@ -0,0 +1,768 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// Copyright 2026 Intel Corporation. All rights reserved. +// +#include +#include +#include +#include +#include "sof-audio.h" +#include "sof-priv.h" +#include "sof-utils.h" +#include "ops.h" +#include "ipc4-priv.h" +#include "ipc4-topology.h" +#include "ipc4-fw-reg.h" + +/* Maximum processing size of the decoder/encoder is 2048 bytes */ +#define SOF_IPC4_COMPR_MAX_PROCESSING_SIZE (SZ_2K) + +#define SOF_IPC4_COMPR_MIN_FRAGMENTS 3 +#define SOF_IPC4_COMPR_MAX_FRAGMENT_SIZE (SZ_128K) +#define SOF_IPC4_COMPR_MAX_FRAGMENTS 64 +#define SOF_IPC4_COMPR_MIN_BUFFER_SIZE(min_size) ((min_size) * \ + SOF_IPC4_COMPR_MIN_FRAGMENTS) + +struct sof_ipc4_compr_init_data { + struct snd_codec codec; + u32 dir; +} __packed __aligned(4); + +static struct sof_ipc4_process * +sof_ipc4_compr_get_module(struct snd_sof_pcm *spcm, int dir) +{ + int id = dir ? snd_soc_dapm_encoder : snd_soc_dapm_decoder; + struct snd_sof_pcm_stream *sps = &spcm->stream[dir]; + struct snd_soc_dapm_widget *widget; + int i; + + /* Find the (first) compr module in path */ + for_each_dapm_widgets(sps->list, i, widget) { + struct snd_sof_widget *swidget = widget->dobj.private; + + if (!swidget) + continue; + + if (swidget->widget->id == id) + return swidget->private; + } + + return NULL; +} + +static u32 sof_ipc4_compr_calc_min_fragment_size(struct snd_sof_pcm_stream *sps) +{ + u32 host_buffer_estimate; + + /* Estimated host DMA buffer size based on stereo S32_LE, 48KHz */ + host_buffer_estimate = snd_pcm_format_size(SNDRV_PCM_FORMAT_S32_LE, 2 * 48); + host_buffer_estimate *= sps->dsp_max_burst_size_in_ms; + /* + * The minimum fragment size must not be smaller than the processing size + * or in case of deep buffer on host side, the host DMA buffer size. + */ + return max(SOF_IPC4_COMPR_MAX_PROCESSING_SIZE, host_buffer_estimate); +} + +static int sof_ipc4_compr_open(struct snd_soc_component *component, + struct snd_compr_stream *cstream) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_sof_pcm *spcm; + int dir, ret; + + spcm = snd_sof_find_spcm_dai(component, rtd); + if (!spcm) + return -EINVAL; + + dir = cstream->direction; + + if (spcm->stream[dir].cstream) + return -EBUSY; + + spcm_dbg(spcm, dir, "Entry: open\n"); + + ret = snd_sof_compr_platform_open(sdev, cstream); + if (ret < 0) { + spcm_err(spcm, dir, "platform compress open failed %d\n", ret); + return ret; + } + + spcm->stream[dir].cstream = cstream; + spcm->stream[dir].posn.host_posn = 0; + spcm->stream[dir].posn.dai_posn = 0; + spcm->prepared[dir] = false; + spcm->pending_stop[dir] = false; + + return 0; +} + +static int sof_ipc4_compr_stream_free(struct snd_sof_dev *sdev, + struct snd_sof_pcm *spcm, + struct snd_compr_stream *cstream) +{ + const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); + int dir = cstream->direction; + int ret = 0; + int err = 0; + + if (spcm->prepared[dir]) { + if (spcm->pending_stop[dir]) + pcm_ops->trigger(sdev->component, NULL, spcm, + SNDRV_PCM_TRIGGER_STOP, dir); + + snd_sof_compr_platform_trigger(sdev, cstream, + SNDRV_PCM_TRIGGER_STOP); + + err = pcm_ops->hw_free(sdev->component, NULL, spcm, dir); + if (err < 0) + spcm_err(spcm, dir, "pcm_ops->hw_free failed %d\n", err); + } + + spcm->prepared[dir] = false; + spcm->pending_stop[dir] = false; + spcm->stream[dir].cstream = NULL; + + /* reset the DMA */ + ret = snd_sof_compr_platform_hw_free(sdev, cstream); + if (ret < 0) { + spcm_err(spcm, dir, "platform hw free failed %d\n", ret); + if (!err) + err = ret; + } + + /* free widget list */ + ret = sof_widget_list_free(sdev, spcm, dir); + if (ret < 0 && err == 0) { + spcm_err(spcm, dir, "sof_widget_list_free failed %d\n", ret); + err = ret; + } + + return err; +} + +static int sof_ipc4_compr_free(struct snd_soc_component *component, + struct snd_compr_stream *cstream) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_sof_pcm *spcm; + int ret, err; + + spcm = snd_sof_find_spcm_dai(component, rtd); + if (!spcm) + return -EINVAL; + + spcm_dbg(spcm, cstream->direction, "Entry: free\n"); + + ret = sof_ipc4_compr_stream_free(sdev, spcm, cstream); + + /* unprepare and free the list of DAPM widgets */ + sof_widget_list_unprepare(sdev, spcm, cstream->direction); + + cancel_work_sync(&spcm->stream[cstream->direction].period_elapsed_work); + + snd_compr_free_pages(cstream); + + err = snd_sof_compr_platform_close(sdev, cstream); + if (err < 0) { + spcm_err(spcm, cstream->direction, + "platform compress close failed %d\n", ret); + if (!ret) + ret = err; + } + + return ret; +} + +#define SOF_IPC4_CODEC_INFO_GET_ID(value) ((value) & 0xff) +#define SOF_IPC4_CODEC_INFO_GET_DIR(value) (((value) >> 8) & 0xf) + +struct sof_ipc4_codec_info_data { + u32 count; + u32 items[]; +} __packed __aligned(4); + +static int sof_ipc4_compr_get_caps(struct snd_soc_component *component, + struct snd_compr_stream *cstream, + struct snd_compr_caps *caps) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct sof_ipc4_fw_data *ipc4_data = sdev->private; + struct sof_ipc4_codec_info_data *codec_info = ipc4_data->codec_info; + int dir = cstream->direction; + struct snd_sof_pcm *spcm; + int i; + + spcm = snd_sof_find_spcm_dai(component, rtd); + if (!spcm) + return -EINVAL; + + /* No compress support available in booted firmware */ + if (!codec_info || !codec_info->count) { + spcm_err(spcm, dir, + "Compress is not supported (no codecs available)\n"); + return -EINVAL; + } + + for (i = 0; i < codec_info->count; i++) { + int _dir = SOF_IPC4_CODEC_INFO_GET_DIR(codec_info->items[i]); + + if (_dir == dir) { + int id = SOF_IPC4_CODEC_INFO_GET_ID(codec_info->items[i]); + + if (caps->num_codecs < ARRAY_SIZE(caps->codecs)) { + spcm_dbg(spcm, dir, "codec#%d: %d\n", + caps->num_codecs, id); + caps->codecs[caps->num_codecs++] = id; + } else { + spcm_dbg(spcm, dir, "codec#%d: %d ignored\n", + caps->num_codecs, id); + } + } + } + + caps->direction = dir; + caps->min_fragment_size = + sof_ipc4_compr_calc_min_fragment_size(&spcm->stream[dir]); + caps->max_fragment_size = SOF_IPC4_COMPR_MAX_FRAGMENT_SIZE; + if (caps->max_fragment_size < caps->min_fragment_size) + caps->max_fragment_size = caps->min_fragment_size; + + caps->min_fragments = SOF_IPC4_COMPR_MIN_FRAGMENTS; + caps->max_fragments = SOF_IPC4_COMPR_MAX_FRAGMENTS; + + spcm_dbg(spcm, dir, + "num_codecs: %u, fragment_size: %u-%u, fragments: %u-%u\n", + caps->num_codecs, + caps->min_fragment_size, caps->max_fragment_size, + caps->min_fragments, caps->max_fragments); + return 0; +} + +static int sof_ipc4_compr_alloc_pages(struct device *dev, + struct snd_sof_pcm_stream *sps, + struct snd_soc_component *component, + struct snd_compr_stream *cstream) +{ + u32 min_fragment_size = sof_ipc4_compr_calc_min_fragment_size(sps); + struct snd_compr_runtime *crtd = cstream->runtime; + u64 fragments = crtd->buffer_size; + int ret; + + if (crtd->buffer_size < SOF_IPC4_COMPR_MIN_BUFFER_SIZE(min_fragment_size)) { + dev_err(dev, "%s: Too small buffer size %llu (minimum is %u)\n", + __func__, crtd->buffer_size, + SOF_IPC4_COMPR_MIN_BUFFER_SIZE(min_fragment_size)); + return -EINVAL; + } + + do_div(fragments, crtd->fragment_size); + if (fragments < SOF_IPC4_COMPR_MIN_FRAGMENTS) { + dev_err(dev, + "%s: Insufficient amount of fragments: %llu (minimum is %d)\n", + __func__, fragments, SOF_IPC4_COMPR_MIN_FRAGMENTS); + return -EINVAL; + } + + cstream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV_SG; + cstream->dma_buffer.dev.dev = dev; + + ret = snd_compr_malloc_pages(cstream, crtd->buffer_size); + if (ret < 0) + return ret; + + ret = snd_sof_compr_create_page_table(component, cstream, crtd->dma_area, + crtd->dma_bytes); + if (ret < 0) + snd_compr_free_pages(cstream); + + return ret; +} + +static bool +sof_ipc4_compr_codec_supported(struct snd_sof_dev *sdev, int codec_id, int dir) +{ + struct sof_ipc4_fw_data *ipc4_data = sdev->private; + struct sof_ipc4_codec_info_data *codec_info = ipc4_data->codec_info; + int i; + + /* No compress support available in booted firmware */ + if (!codec_info || !codec_info->count) + return false; + + for (i = 0; i < codec_info->count; i++) { + int _dir = SOF_IPC4_CODEC_INFO_GET_DIR(codec_info->items[i]); + int _id = SOF_IPC4_CODEC_INFO_GET_ID(codec_info->items[i]); + + if (_dir == dir && codec_id == _id) + return true; + } + + return false; +} + +static int sof_ipc4_compr_set_params(struct snd_soc_component *component, + struct snd_compr_stream *cstream, + struct snd_compr_params *params) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); + struct sof_ipc4_compr_init_data *compr_data __free(kfree) = NULL; + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_sof_platform_stream_params *platform_params; + struct sof_ipc4_timestamp_info *time_info; + struct snd_compr_params *compr_params; + struct snd_soc_dapm_widget_list *list; + struct snd_sof_widget *host_swidget; + struct sof_ipc4_process *process; + struct snd_pcm_hw_params p = {0}; + struct snd_interval *interval; + struct snd_sof_pcm *spcm; + struct snd_mask *fmt; + int dir = cstream->direction; + int ret; + + spcm = snd_sof_find_spcm_dai(component, rtd); + if (!spcm) + return -EINVAL; + + host_swidget = snd_sof_find_swidget_by_comp_id(sdev, spcm->stream[dir].comp_id); + if (!host_swidget) { + spcm_err(spcm, dir, "failed to find host widget with comp_id %d\n", + spcm->stream[dir].comp_id); + return -ENODEV; + } + + if (!sof_ipc4_compr_codec_supported(sdev, params->codec.id, dir)) { + spcm_err(spcm, dir, "Unsupported codec id: %u\n", params->codec.id); + return -EINVAL; + } + + spcm_dbg(spcm, dir, + "codec_id: %u, rate: %u, ch in/out: %u/%u, format: %u/%u\n", + params->codec.id, params->codec.sample_rate, params->codec.ch_in, + params->codec.ch_out, params->codec.format, params->codec.pcm_format); + + if (spcm->prepared[dir]) { + /* + * This can only happen if user space re-configures the device + * without closing it, for example after DRAIN completion + */ + ret = sof_ipc4_compr_stream_free(sdev, spcm, cstream); + if (ret) + return ret; + } + + /* save the compress params */ + compr_params = &spcm->cparams[dir]; + memcpy(compr_params, params, sizeof(*params)); + + /* + * Force format, rate and channels and use PCM hw_params structure to + * set up the pipelines. + */ + fmt = hw_param_mask(&p, SNDRV_PCM_HW_PARAM_FORMAT); + snd_mask_none(fmt); + /* Use correct format based on the used codec */ + switch (params->codec.id) { + case SND_AUDIOCODEC_PCM: + snd_mask_set_format(fmt, params->codec.format); + break; + case SND_AUDIOCODEC_VORBIS: + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); + break; + case SND_AUDIOCODEC_FLAC: + { + struct snd_dec_flac *dec_flac = ¶ms->codec.options.flac_d; + + if (dec_flac->sample_size == 16) + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); + else + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); + break; + } + default: + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); + } + + interval = hw_param_interval(&p, SNDRV_PCM_HW_PARAM_CHANNELS); + interval->min = compr_params->codec.ch_out; + interval->max = compr_params->codec.ch_out; + + interval = hw_param_interval(&p, SNDRV_PCM_HW_PARAM_RATE); + interval->min = compr_params->codec.sample_rate; + interval->max = compr_params->codec.sample_rate; + + ret = sof_ipc4_compr_alloc_pages(sdev->dev, &spcm->stream[dir], + component, cstream); + if (ret < 0) + return ret; + + spcm_dbg(spcm, dir, + "buffer_size: %llu, fragment_size: %u (fragments: %u)\n", + cstream->runtime->buffer_size, cstream->runtime->fragment_size, + (u32)cstream->runtime->buffer_size / cstream->runtime->fragment_size); + + interval = hw_param_interval(&p, SNDRV_PCM_HW_PARAM_PERIOD_BYTES); + interval->min = cstream->runtime->fragment_size; + interval->max = cstream->runtime->fragment_size; + + interval = hw_param_interval(&p, SNDRV_PCM_HW_PARAM_BUFFER_BYTES); + interval->min = cstream->runtime->buffer_size; + interval->max = cstream->runtime->buffer_size; + + platform_params = &spcm->platform_params[dir]; + ret = snd_sof_compr_platform_hw_params(sdev, cstream, compr_params, + platform_params); + if (ret < 0) { + spcm_err(spcm, dir, "platform compress hw params failed\n"); + goto free_pages; + } + + /* set up the list of DAPM widgets if not already done */ + if (!spcm->stream[dir].list) { + ret = sof_pcm_setup_connected_widgets(sdev, rtd, spcm, &p, + platform_params, dir); + if (ret < 0) + goto free_pages; + } + + process = sof_ipc4_compr_get_module(spcm, dir); + if (!process) { + ret = -EINVAL; + goto free_list; + } + + compr_data = kzalloc(sizeof(*compr_data), GFP_KERNEL); + if (!compr_data) + goto free_list; + + memcpy(&compr_data->codec, &compr_params->codec, sizeof(compr_data->codec)); + compr_data->dir = dir; + + process->init_ext_module_data = compr_data; + process->init_ext_module_size = sizeof(*compr_data); + + /* + * Make sure that the DSP is booted up, which might not be the + * case if the on-demand DSP boot is used + */ + ret = snd_sof_boot_dsp_firmware(sdev); + if (ret) + goto clear_init_ext; + + /* set the host DMA ID */ + if (tplg_ops && tplg_ops->host_config) + tplg_ops->host_config(sdev, host_swidget, platform_params); + + /* set up the widgets and pipelines in the DSP */ + ret = sof_widget_list_setup(sdev, spcm, &p, platform_params, dir); + if (ret < 0) { + spcm_err(spcm, dir, "widget list set up failed\n"); + goto clear_init_ext; + } + + memcpy(&spcm->params[dir], &p, sizeof(p)); + spcm->prepared[dir] = true; + + time_info = sof_ipc4_sps_to_time_info(&spcm->stream[dir]); + if (time_info) { + /* delay calculation supported */ + time_info->stream_start_offset = SOF_IPC4_INVALID_STREAM_POSITION; + time_info->llp_offset = 0; + + sof_ipc4_build_time_info(sdev, &spcm->stream[dir]); + } + + process->init_ext_module_data = NULL; + process->init_ext_module_size = 0; + + return 0; + +clear_init_ext: + process->init_ext_module_data = NULL; + process->init_ext_module_size = 0; + +free_list: + list = spcm->stream[dir].list; + spcm->stream[dir].list = NULL; + snd_soc_dapm_dai_free_widgets(&list); + +free_pages: + snd_compr_free_pages(cstream); + + return ret; +} + +static int sof_ipc4_compr_get_params(struct snd_soc_component *component, + struct snd_compr_stream *cstream, + struct snd_codec *params) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_sof_pcm *spcm; + /* TODO: we don't query the supported codecs for now, if the + * application asks for an unsupported codec the set_params() will fail. + */ + spcm = snd_sof_find_spcm_dai(component, rtd); + if (!spcm) { + dev_err(sdev->dev, "%s: can't find spcm\n", __func__); + return -EINVAL; + } + + spcm_dbg(spcm, cstream->direction, "Entry: get_params\n"); + + memcpy(params, &spcm->cparams[cstream->direction].codec, + sizeof(*params)); + + return 0; +} + +static int sof_ipc4_compr_trigger(struct snd_soc_component *component, + struct snd_compr_stream *cstream, int cmd) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); + struct snd_sof_pcm *spcm; + int dir = cstream->direction; + bool trigger_platform = false; + int ret = 0; + + spcm = snd_sof_find_spcm_dai(component, rtd); + if (!spcm) { + dev_err(sdev->dev, "%s: can't find spcm\n", __func__); + return -EINVAL; + } + + spcm->pending_stop[dir] = false; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + trigger_platform = true; + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + break; + case SND_COMPR_TRIGGER_DRAIN: + case SND_COMPR_TRIGGER_PARTIAL_DRAIN: + spcm->pending_stop[dir] = true; + break; + case SND_COMPR_TRIGGER_NEXT_TRACK: + spcm_dbg(spcm, dir, "Unsupported trigger cmd: %d\n", cmd); + return -EOPNOTSUPP; + default: + spcm_dbg(spcm, dir, "Unhandled trigger cmd: %d\n", cmd); + return 0; + } + + spcm_dbg(spcm, dir, "Entry: trigger (cmd: %d)\n", cmd); + + ret = pcm_ops->trigger(component, NULL, spcm, cmd, dir); + if (ret < 0) { + spcm_err(spcm, dir, "pcm_ops->trigger failed for cmd %d\n", cmd); + return ret; + } + + if (!ret && trigger_platform) { + ret = snd_sof_compr_platform_trigger(sdev, cstream, cmd); + if (ret < 0) + spcm_err(spcm, dir, + "platform compress trigger start failed %d\n", + ret); + } + + return ret; +} + +static int sof_ipc4_compr_copy_playback(struct snd_soc_component *component, + struct snd_compr_stream *cstream, + char __user *buf, size_t count) +{ + struct snd_compr_runtime *crtd = cstream->runtime; + u64 offset, n; + void *ptr; + int ret; + + div64_u64_rem(crtd->total_bytes_available, crtd->buffer_size, &offset); + ptr = crtd->dma_area + offset; + n = crtd->buffer_size - offset; + + if (count < n) { + ret = copy_from_user(ptr, buf, count); + } else { + ret = copy_from_user(ptr, buf, n); + ret += copy_from_user(crtd->dma_area, buf + n, count - n); + } + + return count - ret; +} + +static int sof_ipc4_compr_copy_capture(struct snd_compr_runtime *crtd, + char __user *buf, size_t count) +{ + u64 offset, n; + void *ptr; + int ret; + + div64_u64_rem(crtd->total_bytes_transferred, crtd->buffer_size, &offset); + ptr = crtd->dma_area + offset; + n = crtd->buffer_size - offset; + + if (count < n) { + ret = copy_to_user(buf, ptr, count); + } else { + ret = copy_to_user(buf, ptr, n); + ret += copy_to_user(buf + n, crtd->dma_area, count - n); + } + + return count - ret; +} + +static int sof_ipc4_compr_copy(struct snd_soc_component *component, + struct snd_compr_stream *cstream, + char __user *buf, size_t count) +{ + struct snd_compr_runtime *crtd = cstream->runtime; + + if (count > crtd->buffer_size) + count = crtd->buffer_size; + + if (cstream->direction == SND_COMPRESS_PLAYBACK) + return sof_ipc4_compr_copy_playback(component, cstream, buf, count); + + return sof_ipc4_compr_copy_capture(crtd, buf, count); +} + +static int sof_ipc4_compr_pointer(struct snd_soc_component *component, + struct snd_compr_stream *cstream, + struct snd_compr_tstamp64 *tstamp) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct sof_ipc4_timestamp_info *time_info; + struct snd_pcm_hw_params *params; + struct snd_sof_pcm_stream *sps; + struct snd_sof_pcm *spcm; + u64 dai_cnt = 0; + int ret; + + spcm = snd_sof_find_spcm_dai(component, rtd); + if (!spcm) + return -EINVAL; + + params = &spcm->params[cstream->direction]; + + ret = snd_sof_compr_platform_pointer(sdev, cstream, tstamp); + if (ret < 0) { + spcm_err(spcm, cstream->direction, + "platform compress pointer failed %d\n", ret); + return ret; + } + + sps = &spcm->stream[cstream->direction]; + time_info = sof_ipc4_sps_to_time_info(sps); + if (!time_info) + goto host_only; + + /* + * stream_start_offset is updated to memory window by FW based on + * pipeline statistics and it may be invalid if host query happens before + * the statistics is complete. And it will not change after the first + * initialization. + */ + if (time_info->stream_start_offset == SOF_IPC4_INVALID_STREAM_POSITION) { + ret = sof_ipc4_get_stream_start_offset(sdev, NULL, sps, time_info); + if (ret < 0) + goto host_only; + } + + if (!time_info->llp_offset) { + dai_cnt = snd_sof_compr_get_dai_frame_counter(sdev, cstream); + } else { + struct sof_ipc4_llp_reading_slot llp; + + sof_mailbox_read(sdev, time_info->llp_offset, &llp, sizeof(llp)); + dai_cnt = ((u64)llp.reading.llp_u << 32) | llp.reading.llp_l; + } + + if (dai_cnt) { + dai_cnt = sof_ipc4_frames_dai_to_host(time_info, dai_cnt); + dai_cnt += time_info->stream_end_offset; + if (dai_cnt < time_info->stream_start_offset) + dai_cnt = 0; + else + dai_cnt -= time_info->stream_start_offset; + } + +host_only: + tstamp->sampling_rate = params_rate(params); + tstamp->pcm_io_frames = dai_cnt; + + return 0; +} + +void sof_ipc4_compr_drain_done(struct snd_sof_dev *sdev, void *ipc_message) +{ + struct sof_ipc4_msg *ipc4_msg = ipc_message; + struct sof_ipc4_notify_module_data *ndata = ipc4_msg->data_ptr; + struct snd_sof_widget *swidget, *host_swidget; + bool widget_found = false; + struct snd_sof_pcm *spcm; + int dir; + + /* Find the swidget based on ndata->module_id and ndata->instance_id */ + swidget = sof_ipc4_find_swidget_by_ids(sdev, ndata->module_id, + ndata->instance_id); + if (!swidget) { + dev_err(sdev->dev, "%s: Failed to find widget for module %u.%u\n", + __func__, ndata->module_id, ndata->instance_id); + return; + } + + if (!swidget->spipe) + return; + + /* Find the swidget of the host copier on the same pipeline */ + list_for_each_entry(host_swidget, &sdev->widget_list, list) { + if (WIDGET_IS_AIF(host_swidget->id) && + host_swidget->pipeline_id == swidget->pipeline_id) { + widget_found = true; + break; + } + } + + if (!widget_found) { + dev_err(sdev->dev, "%s: Host widget not found for pipeline: %s\n", + __func__, swidget->spipe->pipe_widget->widget->name); + return; + } + + /* Look up the spcm of the host copier */ + spcm = snd_sof_find_spcm_comp(sdev->component, host_swidget->comp_id, &dir); + if (!spcm) { + dev_err(sdev->dev, "%s: Stream cannot be found for %s\n", __func__, + host_swidget->widget->name); + return; + } + + spcm_dbg(spcm, dir, "Entry: EOS done\n"); + + if (spcm->stream[dir].cstream) + snd_compr_drain_notify(spcm->stream[dir].cstream); +} + +const struct snd_compress_ops sof_ipc4_compressed_ops = { + .open = sof_ipc4_compr_open, + .free = sof_ipc4_compr_free, + .get_caps = sof_ipc4_compr_get_caps, + .set_params = sof_ipc4_compr_set_params, + .get_params = sof_ipc4_compr_get_params, + .trigger = sof_ipc4_compr_trigger, + .pointer = sof_ipc4_compr_pointer, + .copy = sof_ipc4_compr_copy, +}; diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index c137d8477d04fd..d938e380231fed 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -1337,4 +1337,7 @@ const struct sof_ipc_pcm_ops ipc4_pcm_ops = { .delay = sof_ipc4_pcm_delay, .ipc_first_on_start = true, .platform_stop_during_hw_free = true, +#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS) + .compress_ops = &sof_ipc4_compressed_ops, +#endif }; diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h index 07df6799c7a838..b35930c16c6dbe 100644 --- a/sound/soc/sof/ipc4-priv.h +++ b/sound/soc/sof/ipc4-priv.h @@ -130,6 +130,9 @@ extern const struct sof_ipc_tplg_ops ipc4_tplg_ops; extern const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops; extern const struct sof_ipc_pcm_ops ipc4_pcm_ops; extern const struct sof_ipc_fw_tracing_ops ipc4_mtrace_ops; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS) +extern const struct snd_compress_ops sof_ipc4_compressed_ops; +#endif int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 instance_id, u32 state); int sof_ipc4_mtrace_update_pos(struct snd_sof_dev *sdev, int core); @@ -164,4 +167,11 @@ int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev, struct sof_ipc4_timestamp_info *time_info); u64 sof_ipc4_frames_dai_to_host(struct sof_ipc4_timestamp_info *time_info, u64 value); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS) +void sof_ipc4_compr_drain_done(struct snd_sof_dev *sdev, void *ipc_message); +#else +static inline void sof_ipc4_compr_drain_done(struct snd_sof_dev *sdev, + void *ipc_message) { } +#endif + #endif diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 3e3acb1895de40..5caca0f991c307 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -358,6 +358,7 @@ struct snd_sof_pcm { struct snd_sof_pcm_stream stream[2]; struct list_head list; /* list in sdev pcm list */ struct snd_pcm_hw_params params[2]; + struct snd_compr_params cparams[2]; /* applicable for compress devices */ struct snd_sof_platform_stream_params platform_params[2]; bool prepared[2]; /* PCM_PARAMS set successfully */ bool setup_done[2]; /* the setup of the SOF PCM device is done */ From 8ae246de5bea09ef1c5e2e81137584435fd1f49b Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 30 Jan 2026 17:47:03 +0200 Subject: [PATCH 40/83] ASoC: SOF: ipc4: Handle compressed drain done notification from firmware The decoder module sends a drain done notification when the last chunk of the stream after the EOS from host has been decoded. The notification is a module notification with 0xc0c0 as magic number in event_id upper 16 bit. Call sof_ipc4_compr_drain_done() when the notification arrives to handle it. Signed-off-by: Peter Ujfalusi --- include/sound/sof/ipc4/header.h | 3 ++- sound/soc/sof/ipc4.c | 13 +++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/include/sound/sof/ipc4/header.h b/include/sound/sof/ipc4/header.h index 2c0d399f4729c1..00a9bb2796fc96 100644 --- a/include/sound/sof/ipc4/header.h +++ b/include/sound/sof/ipc4/header.h @@ -622,9 +622,10 @@ struct sof_ipc4_notify_module_data { * The event_data contains the struct sof_ipc4_control_msg_payload of the control * which sent the notification. */ -#define SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_MAGIC_MASK GENMASK(31, 16) +#define SOF_IPC4_NOTIFY_MODULE_EVENTID_SOF_MAGIC_MASK GENMASK(31, 16) #define SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_MAGIC_VAL 0xA15A0000 #define SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_PARAMID_MASK GENMASK(15, 0) +#define SOF_IPC4_NOTIFY_MODULE_EVENTID_COMPR_MAGIC_VAL 0xC0C00000 /* * Macros for creating struct sof_ipc4_module_init_ext_init payload diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c index 4625ac98096f5c..2ceddc43dc3c11 100644 --- a/sound/soc/sof/ipc4.c +++ b/sound/soc/sof/ipc4.c @@ -701,12 +701,21 @@ static void sof_ipc4_module_notification_handler(struct snd_sof_dev *sdev, } /* Handle ALSA kcontrol notification */ - if ((data->event_id & SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_MAGIC_MASK) == - SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_MAGIC_VAL) { + switch (data->event_id & SOF_IPC4_NOTIFY_MODULE_EVENTID_SOF_MAGIC_MASK) { + case SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_MAGIC_VAL: + { const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; if (tplg_ops->control->update) tplg_ops->control->update(sdev, ipc4_msg); + + break; + } + case SOF_IPC4_NOTIFY_MODULE_EVENTID_COMPR_MAGIC_VAL: + sof_ipc4_compr_drain_done(sdev, ipc4_msg); + break; + default: + break; } } From 4d3ecb63b1683e12c126d92ae0d23cc76f62e590 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 31 Dec 2025 15:06:38 +0200 Subject: [PATCH 41/83] ASoC: SOF: Intel: Kconfig: Remove redundant IPC version selects There is no need to select IPC3 and IPC4 along with INTEL_CNL as INTEL_CNL selects both. Similarly, INTEL_MTL selects IPC4, so there is no need to do that for LNL, PTL and NVL. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/intel/Kconfig | 7 ------- 1 file changed, 7 deletions(-) diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index e31f4c4061d80e..a69a9d76dac263 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -186,8 +186,6 @@ config SND_SOC_SOF_INTEL_ICL tristate select SND_SOC_SOF_HDA_GENERIC select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE - select SND_SOC_SOF_IPC3 - select SND_SOC_SOF_IPC4 select SND_SOC_SOF_INTEL_CNL config SND_SOC_SOF_ICELAKE @@ -214,8 +212,6 @@ config SND_SOC_SOF_INTEL_TGL tristate select SND_SOC_SOF_HDA_GENERIC select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE - select SND_SOC_SOF_IPC3 - select SND_SOC_SOF_IPC4 select SND_SOC_SOF_INTEL_CNL config SND_SOC_SOF_TIGERLAKE @@ -270,7 +266,6 @@ config SND_SOC_SOF_INTEL_LNL select SND_SOC_SOF_HDA_GENERIC select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE select SND_SOF_SOF_HDA_SDW_BPT if SND_SOC_SOF_INTEL_SOUNDWIRE != n - select SND_SOC_SOF_IPC4 select SND_SOC_SOF_INTEL_MTL config SND_SOC_SOF_LUNARLAKE @@ -287,7 +282,6 @@ config SND_SOC_SOF_INTEL_PTL tristate select SND_SOC_SOF_HDA_COMMON select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE - select SND_SOC_SOF_IPC4 select SND_SOC_SOF_INTEL_LNL config SND_SOC_SOF_PANTHERLAKE @@ -304,7 +298,6 @@ config SND_SOC_SOF_INTEL_NVL tristate select SND_SOC_SOF_HDA_COMMON select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE - select SND_SOC_SOF_IPC4 select SND_SOC_SOF_INTEL_PTL config SND_SOC_SOF_NOVALAKE From 3b62d899fecf94a4e7dd59f1a7608efcb9029a12 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 31 Dec 2025 15:14:19 +0200 Subject: [PATCH 42/83] ASoC: SOF: Intel: Kconfig: Select compress support for TGL+ platforms Select SOF_COMPRESS for TGL and newer platforms, on Intel devices the compressed support is available with IPC4 only. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/intel/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index a69a9d76dac263..d23394e69406aa 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -213,6 +213,7 @@ config SND_SOC_SOF_INTEL_TGL select SND_SOC_SOF_HDA_GENERIC select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE select SND_SOC_SOF_INTEL_CNL + select SND_SOC_SOF_COMPRESS config SND_SOC_SOF_TIGERLAKE tristate "SOF support for Tigerlake" @@ -249,6 +250,7 @@ config SND_SOC_SOF_INTEL_MTL select SND_SOC_SOF_HDA_GENERIC select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE select SND_SOC_SOF_IPC4 + select SND_SOC_SOF_COMPRESS config SND_SOC_SOF_METEORLAKE tristate "SOF support for Meteorlake" From ed84cf09acb878ebcfb6145676da637bd2349eb3 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 12 Dec 2025 08:29:18 -0800 Subject: [PATCH 43/83] ASoC: SOF: topology: Add support for decoder and encoder widgets Decoder and encoder modules fall under process modules in SOF. Signed-off-by: Ranjani Sridharan Co-developed-by: Peter Ujfalusi Signed-off-by: Peter Ujfalusi --- sound/soc/sof/ipc4-topology.c | 11 +++++++++++ sound/soc/sof/sof-audio.h | 4 +++- sound/soc/sof/topology.c | 2 ++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 0e3a552d9bd2f0..0e323895647e6f 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -3509,6 +3509,8 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget msg = &asrc->msg; break; } + case snd_soc_dapm_decoder: + case snd_soc_dapm_encoder: case snd_soc_dapm_effect: { struct sof_ipc4_process *process = swidget->private; @@ -4268,6 +4270,15 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TY process_token_list, ARRAY_SIZE(process_token_list), NULL, sof_ipc4_prepare_process_module, NULL}, + /* for all practical purposes a decoder is like an effect type widget */ + [snd_soc_dapm_decoder] = {sof_ipc4_widget_setup_comp_process, + sof_ipc4_widget_free_comp_process, + process_token_list, ARRAY_SIZE(process_token_list), + NULL, sof_ipc4_prepare_process_module, NULL}, + [snd_soc_dapm_encoder] = {sof_ipc4_widget_setup_comp_process, + sof_ipc4_widget_free_comp_process, + process_token_list, ARRAY_SIZE(process_token_list), + NULL, sof_ipc4_prepare_process_module, NULL}, }; const struct sof_ipc_tplg_ops ipc4_tplg_ops = { diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 5caca0f991c307..a96583698a6946 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -43,7 +43,9 @@ #define WIDGET_IS_AIF(id) ((id) == snd_soc_dapm_aif_in || (id) == snd_soc_dapm_aif_out) #define WIDGET_IS_AIF_OR_DAI(id) (WIDGET_IS_DAI(id) || WIDGET_IS_AIF(id)) #define WIDGET_IS_COPIER(id) (WIDGET_IS_AIF_OR_DAI(id) || (id) == snd_soc_dapm_buffer) -#define WIDGET_IS_PROCESS(id) ((id) == snd_soc_dapm_effect) +#define WIDGET_IS_PROCESS(id) ((id) == snd_soc_dapm_effect || \ + (id) == snd_soc_dapm_decoder || \ + (id) == snd_soc_dapm_encoder) #define SOF_DAI_PARAM_INTEL_SSP_MCLK 0 #define SOF_DAI_PARAM_INTEL_SSP_BCLK 1 diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 8fc7726aec29d0..e69a74a419ea09 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1521,6 +1521,8 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, list_add(&dai->list, &sdev->dai_list); swidget->private = dai; break; + case snd_soc_dapm_decoder: + case snd_soc_dapm_encoder: case snd_soc_dapm_effect: /* check we have some tokens - we need at least process type */ if (le32_to_cpu(tw->priv.size) == 0) { From 276f9b70af3b6783afe82e88c83fee626bcf83a5 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 24 Apr 2026 12:59:33 +0300 Subject: [PATCH 44/83] -- compress up to this point -- From 7341428243ed9641ad373f9fb8ba0cda92f44d00 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 1 Jun 2026 09:52:29 +0300 Subject: [PATCH 45/83] -- SOF multi-component from here -- From f36f7ca8924ab4781b44ae94786110cc3f8e9f2a Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 28 May 2026 17:07:19 +0300 Subject: [PATCH 46/83] ASoC: SOF: switch to snd_sof_component_get_sdev() Replace direct snd_soc_component_get_drvdata() lookups used to fetch struct snd_sof_dev with snd_sof_component_get_sdev() across sound/soc/sof/. This is a preparatory, mechanical cleanup to keep SOF component accessor naming consistent ahead of follow-up ownership refactoring. No functional behavior change is intended. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/control.c | 22 ++++++++++---------- sound/soc/sof/intel/hda.h | 2 +- sound/soc/sof/ipc3-compress.c | 6 +++--- sound/soc/sof/ipc3-control.c | 2 +- sound/soc/sof/ipc3-pcm.c | 8 ++++---- sound/soc/sof/ipc3-topology.c | 14 ++++++------- sound/soc/sof/ipc3.c | 6 ++---- sound/soc/sof/ipc4-compress.c | 14 ++++++------- sound/soc/sof/ipc4-control.c | 14 ++++++------- sound/soc/sof/ipc4-pcm.c | 8 ++++---- sound/soc/sof/ipc4-topology.c | 22 ++++++++++---------- sound/soc/sof/pcm.c | 24 +++++++++++----------- sound/soc/sof/sof-audio.c | 20 ++++++++++++------ sound/soc/sof/sof-audio.h | 11 +++++++++- sound/soc/sof/topology.c | 38 +++++++++++++++++------------------ 15 files changed, 113 insertions(+), 98 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 74d997a4f6203c..24b32c86e2c2c9 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -21,7 +21,7 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol, struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value; struct snd_sof_control *scontrol = sm->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); if (tplg_ops && tplg_ops->control && tplg_ops->control->volume_get) @@ -36,7 +36,7 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value; struct snd_sof_control *scontrol = sm->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); if (tplg_ops && tplg_ops->control && tplg_ops->control->volume_put) @@ -73,7 +73,7 @@ int snd_sof_switch_get(struct snd_kcontrol *kcontrol, struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value; struct snd_sof_control *scontrol = sm->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); if (tplg_ops && tplg_ops->control && tplg_ops->control->switch_get) @@ -88,7 +88,7 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value; struct snd_sof_control *scontrol = sm->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); if (tplg_ops && tplg_ops->control && tplg_ops->control->switch_put) @@ -103,7 +103,7 @@ int snd_sof_enum_get(struct snd_kcontrol *kcontrol, struct soc_enum *se = (struct soc_enum *)kcontrol->private_value; struct snd_sof_control *scontrol = se->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); if (tplg_ops && tplg_ops->control && tplg_ops->control->enum_get) @@ -118,7 +118,7 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, struct soc_enum *se = (struct soc_enum *)kcontrol->private_value; struct snd_sof_control *scontrol = se->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); if (tplg_ops && tplg_ops->control && tplg_ops->control->enum_put) @@ -133,7 +133,7 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value; struct snd_sof_control *scontrol = be->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_get) @@ -148,7 +148,7 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value; struct snd_sof_control *scontrol = be->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_put) @@ -164,7 +164,7 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value; struct snd_sof_control *scontrol = be->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); /* make sure we have at least a header */ @@ -183,7 +183,7 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _ struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value; struct snd_sof_control *scontrol = be->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); int ret, err; @@ -219,7 +219,7 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value; struct snd_sof_control *scontrol = be->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_ext_get) diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index f9d498f8d23c9b..ca9c5f59b7bd97 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -1103,7 +1103,7 @@ static inline struct snd_sof_dev *widget_to_sdev(struct snd_soc_dapm_widget *w) struct snd_sof_widget *swidget = w->dobj.private; struct snd_soc_component *component = swidget->scomp; - return snd_soc_component_get_drvdata(component); + return snd_sof_component_get_sdev(component); } #endif diff --git a/sound/soc/sof/ipc3-compress.c b/sound/soc/sof/ipc3-compress.c index 115d454bcaf5b7..09716d45331a62 100644 --- a/sound/soc/sof/ipc3-compress.c +++ b/sound/soc/sof/ipc3-compress.c @@ -51,7 +51,7 @@ static int sof_ipc3_compr_open(struct snd_soc_component *component, static int sof_ipc3_compr_free(struct snd_soc_component *component, struct snd_compr_stream *cstream) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct sof_compr_stream *sstream = cstream->runtime->private_data; struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct sof_ipc_stream stream; @@ -83,7 +83,7 @@ static int sof_ipc3_compr_set_params(struct snd_soc_component *component, struct snd_compr_stream *cstream, struct snd_compr_params *params) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_compr_runtime *crtd = cstream->runtime; struct sof_ipc_pcm_params_reply ipc_params_reply; @@ -200,7 +200,7 @@ static int sof_ipc3_compr_get_params(struct snd_soc_component *component, static int sof_ipc3_compr_trigger(struct snd_soc_component *component, struct snd_compr_stream *cstream, int cmd) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct sof_ipc_stream stream; struct snd_sof_pcm *spcm; diff --git a/sound/soc/sof/ipc3-control.c b/sound/soc/sof/ipc3-control.c index fc4b43855144eb..80ae973c31b891 100644 --- a/sound/soc/sof/ipc3-control.c +++ b/sound/soc/sof/ipc3-control.c @@ -15,7 +15,7 @@ static int sof_ipc3_set_get_kcontrol_data(struct snd_sof_control *scontrol, bool set, bool lock) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scontrol->scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scontrol->scomp); struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; const struct sof_ipc_ops *iops = sdev->ipc->ops; enum sof_ipc_ctrl_type ctrl_type; diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c index 28c4047b26737d..dacac8a48bb43c 100644 --- a/sound/soc/sof/ipc3-pcm.c +++ b/sound/soc/sof/ipc3-pcm.c @@ -17,7 +17,7 @@ static int sof_ipc3_pcm_hw_free(struct snd_soc_component *component, struct snd_pcm_substream *substream, struct snd_sof_pcm *spcm, int dir) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct sof_ipc_stream stream; if (!spcm->prepared[dir]) @@ -36,7 +36,7 @@ static int sof_ipc3_pcm_hw_params(struct snd_soc_component *component, struct snd_pcm_hw_params *params, struct snd_sof_platform_stream_params *platform_params) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct sof_ipc_fw_version *v = &sdev->fw_ready.version; struct snd_pcm_runtime *runtime = substream->runtime; @@ -139,7 +139,7 @@ static int sof_ipc3_pcm_trigger(struct snd_soc_component *component, struct snd_pcm_substream *substream, struct snd_sof_pcm *spcm, int cmd, int dir) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct sof_ipc_stream stream; stream.hdr.size = sizeof(stream); @@ -205,7 +205,7 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_sof_dai *dai = snd_sof_find_dai(component, (char *)rtd->dai_link->name); struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct sof_dai_private_data *private; struct snd_soc_dpcm *dpcm; diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index 4e066bbded9179..6a9904274ee251 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -519,7 +519,7 @@ static int sof_ipc3_widget_setup_comp_mixer(struct snd_sof_widget *swidget) static int sof_ipc3_widget_setup_comp_pipeline(struct snd_sof_widget *swidget) { struct snd_soc_component *scomp = swidget->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_sof_pipeline *spipe = swidget->spipe; struct sof_ipc_pipe_new *pipeline; struct snd_sof_widget *comp_swidget; @@ -752,7 +752,7 @@ static int sof_ipc3_widget_setup_comp_mux(struct snd_sof_widget *swidget) static int sof_ipc3_widget_setup_comp_pga(struct snd_sof_widget *swidget) { struct snd_soc_component *scomp = swidget->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct sof_ipc_comp_volume *volume; struct snd_sof_control *scontrol; size_t ipc_size = sizeof(*volume); @@ -1395,7 +1395,7 @@ static int sof_link_afe_load(struct snd_soc_component *scomp, struct snd_sof_dai static int sof_link_ssp_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs; struct sof_dai_private_data *private = dai->private; u32 size = sizeof(*config); @@ -1468,7 +1468,7 @@ static int sof_link_ssp_load(struct snd_soc_component *scomp, struct snd_sof_dai static int sof_link_dmic_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct sof_dai_private_data *private = dai->private; struct sof_ipc_fw_ready *ready = &sdev->fw_ready; struct sof_ipc_fw_version *v = &ready->version; @@ -1566,7 +1566,7 @@ static int sof_link_alh_load(struct snd_soc_component *scomp, struct snd_sof_dai static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget) { struct snd_soc_component *scomp = swidget->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_sof_dai *dai = swidget->private; struct sof_dai_private_data *private; struct sof_ipc_comp_dai *comp_dai; @@ -1911,7 +1911,7 @@ static int sof_ipc3_control_free(struct snd_sof_dev *sdev, struct snd_sof_contro static int sof_ipc3_keyword_detect_pcm_params(struct snd_sof_widget *swidget, int dir) { struct snd_soc_component *scomp = swidget->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_pcm_hw_params *params; struct sof_ipc_pcm_params pcm; struct snd_sof_pcm *spcm; @@ -1967,7 +1967,7 @@ static int sof_ipc3_keyword_detect_pcm_params(struct snd_sof_widget *swidget, in static int sof_ipc3_keyword_detect_trigger(struct snd_sof_widget *swidget, int cmd) { struct snd_soc_component *scomp = swidget->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct sof_ipc_stream stream; int ret; diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c index 85bb22bbe18d08..4a350d9d91226b 100644 --- a/sound/soc/sof/ipc3.c +++ b/sound/soc/sof/ipc3.c @@ -861,13 +861,12 @@ static int ipc3_fw_ready(struct snd_sof_dev *sdev, u32 cmd) /* IPC stream position. */ static void ipc3_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id) { - struct snd_soc_component *scomp = sdev->component; struct snd_sof_pcm_stream *stream; struct sof_ipc_stream_posn posn; struct snd_sof_pcm *spcm; int direction, ret; - spcm = snd_sof_find_spcm_comp(scomp, msg_id, &direction); + spcm = snd_sof_find_spcm_comp_by_sdev(sdev, msg_id, &direction); if (!spcm) { dev_err(sdev->dev, "period elapsed for unknown stream, msg_id %d\n", msg_id); @@ -896,13 +895,12 @@ static void ipc3_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id) /* DSP notifies host of an XRUN within FW */ static void ipc3_xrun(struct snd_sof_dev *sdev, u32 msg_id) { - struct snd_soc_component *scomp = sdev->component; struct snd_sof_pcm_stream *stream; struct sof_ipc_stream_posn posn; struct snd_sof_pcm *spcm; int direction, ret; - spcm = snd_sof_find_spcm_comp(scomp, msg_id, &direction); + spcm = snd_sof_find_spcm_comp_by_sdev(sdev, msg_id, &direction); if (!spcm) { dev_err(sdev->dev, "XRUN for unknown stream, msg_id %d\n", msg_id); diff --git a/sound/soc/sof/ipc4-compress.c b/sound/soc/sof/ipc4-compress.c index bb9d32ca585b71..29e58c8308a9e6 100644 --- a/sound/soc/sof/ipc4-compress.c +++ b/sound/soc/sof/ipc4-compress.c @@ -67,7 +67,7 @@ static u32 sof_ipc4_compr_calc_min_fragment_size(struct snd_sof_pcm_stream *sps) static int sof_ipc4_compr_open(struct snd_soc_component *component, struct snd_compr_stream *cstream) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_sof_pcm *spcm; int dir, ret; @@ -145,7 +145,7 @@ static int sof_ipc4_compr_stream_free(struct snd_sof_dev *sdev, static int sof_ipc4_compr_free(struct snd_soc_component *component, struct snd_compr_stream *cstream) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_sof_pcm *spcm; int ret, err; @@ -188,7 +188,7 @@ static int sof_ipc4_compr_get_caps(struct snd_soc_component *component, struct snd_compr_stream *cstream, struct snd_compr_caps *caps) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct sof_ipc4_fw_data *ipc4_data = sdev->private; struct sof_ipc4_codec_info_data *codec_info = ipc4_data->codec_info; @@ -308,7 +308,7 @@ static int sof_ipc4_compr_set_params(struct snd_soc_component *component, struct snd_compr_stream *cstream, struct snd_compr_params *params) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct sof_ipc4_compr_init_data *compr_data __free(kfree) = NULL; struct snd_soc_pcm_runtime *rtd = cstream->private_data; @@ -501,7 +501,7 @@ static int sof_ipc4_compr_get_params(struct snd_soc_component *component, struct snd_compr_stream *cstream, struct snd_codec *params) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_sof_pcm *spcm; /* TODO: we don't query the supported codecs for now, if the @@ -524,7 +524,7 @@ static int sof_ipc4_compr_get_params(struct snd_soc_component *component, static int sof_ipc4_compr_trigger(struct snd_soc_component *component, struct snd_compr_stream *cstream, int cmd) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_soc_pcm_runtime *rtd = cstream->private_data; const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); struct snd_sof_pcm *spcm; @@ -642,7 +642,7 @@ static int sof_ipc4_compr_pointer(struct snd_soc_component *component, struct snd_compr_stream *cstream, struct snd_compr_tstamp64 *tstamp) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct sof_ipc4_timestamp_info *time_info; struct snd_pcm_hw_params *params; diff --git a/sound/soc/sof/ipc4-control.c b/sound/soc/sof/ipc4-control.c index 8d86d32a16caea..ff29023c0df9f6 100644 --- a/sound/soc/sof/ipc4-control.c +++ b/sound/soc/sof/ipc4-control.c @@ -17,7 +17,7 @@ static int sof_ipc4_set_get_kcontrol_data(struct snd_sof_control *scontrol, bool set, bool lock) { struct snd_soc_component *scomp = scontrol->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); const struct sof_ipc_ops *iops = sdev->ipc->ops; struct snd_sof_widget *swidget; bool widget_found = false; @@ -143,7 +143,7 @@ static bool sof_ipc4_volume_put(struct snd_sof_control *scontrol, { struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; struct snd_soc_component *scomp = scontrol->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); unsigned int channels = scontrol->num_channels; struct snd_sof_widget *swidget; bool widget_found = false; @@ -383,7 +383,7 @@ static bool sof_ipc4_switch_put(struct snd_sof_control *scontrol, { struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; struct snd_soc_component *scomp = scontrol->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_sof_widget *swidget; bool widget_found = false; bool change = false; @@ -442,7 +442,7 @@ static bool sof_ipc4_enum_put(struct snd_sof_control *scontrol, { struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; struct snd_soc_component *scomp = scontrol->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_sof_widget *swidget; bool widget_found = false; bool change = false; @@ -552,7 +552,7 @@ static int sof_ipc4_bytes_put(struct snd_sof_control *scontrol, { struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; struct snd_soc_component *scomp = scontrol->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct sof_abi_hdr *data = cdata->data; const struct sof_abi_hdr *new_hdr = (const struct sof_abi_hdr *)ucontrol->value.bytes.data; @@ -626,7 +626,7 @@ static int sof_ipc4_bytes_ext_put(struct snd_sof_control *scontrol, struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data; struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; struct snd_soc_component *scomp = scontrol->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct sof_abi_hdr *data = cdata->data; struct sof_abi_hdr abi_hdr; struct snd_ctl_tlv header; @@ -725,7 +725,7 @@ static int _sof_ipc4_bytes_ext_get(struct snd_sof_control *scontrol, /* get all the component data from DSP */ if (from_dsp) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); int ret = sof_ipc4_set_get_bytes_data(sdev, scontrol, false, true); if (ret < 0) diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index d938e380231fed..b54d90357dca5f 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -399,7 +399,7 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, struct snd_pcm_substream *substream, int state, int cmd, struct snd_sof_pcm *spcm, int dir) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_sof_pcm_stream_pipeline_list *pipeline_list; struct sof_ipc4_fw_data *ipc4_data = sdev->private; struct ipc4_pipeline_set_state_data *trigger_list; @@ -810,7 +810,7 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); struct snd_sof_dai *dai = snd_sof_find_dai(component, rtd->dai_link->name); struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct sof_ipc4_audio_format *ipc4_fmt; struct sof_ipc4_copier *ipc4_copier; @@ -1055,7 +1055,7 @@ static int sof_ipc4_pcm_hw_params(struct snd_soc_component *component, struct snd_pcm_hw_params *params, struct snd_sof_platform_stream_params *platform_params) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct sof_ipc4_timestamp_info *time_info; struct snd_sof_pcm *spcm; @@ -1180,7 +1180,7 @@ static int sof_ipc4_pcm_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream, snd_pcm_uframes_t *pointer) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct sof_ipc4_timestamp_info *time_info; struct sof_ipc4_llp_reading_slot llp; diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 0e323895647e6f..0f78651ab96784 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -560,7 +560,7 @@ static void sof_ipc4_widget_free_comp_pipeline(struct snd_sof_widget *swidget) static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget) { struct snd_soc_component *scomp = swidget->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); swidget->module_info = sof_ipc4_find_module_by_uuid(sdev, &swidget->uuid); @@ -610,7 +610,7 @@ static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_ static void sof_ipc4_widget_update_kcontrol_module_id(struct snd_sof_widget *swidget) { struct snd_soc_component *scomp = swidget->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct sof_ipc4_fw_module *fw_module = swidget->module_info; struct snd_sof_control *scontrol; @@ -809,7 +809,7 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) { struct sof_ipc4_available_audio_format *available_fmt; struct snd_soc_component *scomp = swidget->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_sof_dai *dai = swidget->private; struct sof_ipc4_copier *ipc4_copier; struct snd_sof_widget *pipe_widget; @@ -989,7 +989,7 @@ static void sof_ipc4_widget_free_comp_dai(struct snd_sof_widget *swidget) static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget) { struct snd_soc_component *scomp = swidget->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct sof_ipc4_pipeline *pipeline; struct snd_sof_pipeline *spipe = swidget->spipe; int ret; @@ -2115,7 +2115,7 @@ sof_ipc4_copier_module_update_params(struct snd_sof_widget *swidget, struct snd_pcm_hw_params *pipeline_params) { struct snd_soc_component *scomp = swidget->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct sof_ipc4_copier_data *copier_data; struct sof_ipc4_copier *ipc4_copier; @@ -2165,7 +2165,7 @@ _sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, { struct sof_ipc4_available_audio_format *available_fmt; struct snd_soc_component *scomp = swidget->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct sof_ipc4_copier_data *copier_data; int input_fmt_index, output_fmt_index; struct sof_ipc4_copier *ipc4_copier; @@ -2676,7 +2676,7 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget, struct snd_pcm_hw_params *pipeline_params, int dir) { struct snd_soc_component *scomp = swidget->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct sof_ipc4_gain *gain = swidget->private; struct sof_ipc4_available_audio_format *available_fmt = &gain->available_fmt; struct sof_ipc4_audio_format *in_fmt; @@ -2725,7 +2725,7 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget, struct snd_pcm_hw_params *pipeline_params, int dir) { struct snd_soc_component *scomp = swidget->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct sof_ipc4_mixer *mixer = swidget->private; struct sof_ipc4_available_audio_format *available_fmt = &mixer->available_fmt; struct sof_ipc4_audio_format *in_fmt; @@ -2774,7 +2774,7 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, struct snd_pcm_hw_params *pipeline_params, int dir) { struct snd_soc_component *scomp = swidget->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct sof_ipc4_src *src = swidget->private; struct sof_ipc4_available_audio_format *available_fmt = &src->available_fmt; struct sof_ipc4_audio_format *out_audio_fmt; @@ -2943,7 +2943,7 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget, struct snd_pcm_hw_params *pipeline_params, int dir) { struct snd_soc_component *scomp = swidget->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct sof_ipc4_process *process = swidget->private; struct sof_ipc4_available_audio_format *available_fmt = &process->available_fmt; void *cfg = process->ipc_config_data; @@ -4011,7 +4011,7 @@ static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget * static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_manifest *man) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct sof_ipc4_fw_data *ipc4_data = sdev->private; struct sof_manifest_tlv *manifest_tlv; struct sof_manifest *manifest; diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 42738f12fa3390..66120fb5d44022 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -117,7 +117,7 @@ static int sof_pcm_hw_params(struct snd_soc_component *component, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); @@ -289,7 +289,7 @@ static int sof_pcm_hw_free(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_dev *sdev = snd_sof_component_get_sdev(component); struct snd_sof_pcm *spcm; int ret; @@ -317,7 +317,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_dev *sdev = snd_sof_component_get_sdev(component); const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); struct snd_sof_platform_stream_params *platform_params; struct snd_soc_dapm_widget_list *list; @@ -387,7 +387,7 @@ static int sof_pcm_trigger(struct snd_soc_component *component, struct snd_pcm_substream *substream, int cmd) { 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_dev *sdev = snd_sof_component_get_sdev(component); const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); struct snd_sof_pcm *spcm; bool reset_hw_params = false; @@ -499,7 +499,7 @@ static snd_pcm_uframes_t sof_pcm_pointer(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_dev *sdev = snd_sof_component_get_sdev(component); const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); struct snd_sof_pcm *spcm; snd_pcm_uframes_t host, dai; @@ -539,7 +539,7 @@ static int sof_pcm_open(struct snd_soc_component *component, { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); const struct snd_sof_dsp_ops *ops = sof_ops(sdev); struct snd_sof_pcm *spcm; struct snd_soc_tplg_stream_caps *caps; @@ -601,7 +601,7 @@ static int sof_pcm_close(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_dev *sdev = snd_sof_component_get_sdev(component); struct snd_sof_pcm *spcm; int err; @@ -638,7 +638,7 @@ static int sof_pcm_close(struct snd_soc_component *component, static int sof_pcm_new(struct snd_soc_component *component, struct snd_soc_pcm_runtime *rtd) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_sof_pcm *spcm; struct snd_pcm *pcm = rtd->pcm; struct snd_soc_tplg_stream_caps *caps; @@ -728,7 +728,7 @@ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_pa snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); struct snd_sof_dai *dai = snd_sof_find_dai(component, (char *)rtd->dai_link->name); - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); /* no topology exists for this BE, try a common configuration */ @@ -759,7 +759,7 @@ EXPORT_SYMBOL(sof_pcm_dai_link_fixup); static int sof_pcm_probe(struct snd_soc_component *component) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_sof_pdata *plat_data = sdev->pdata; const char *tplg_filename; int ret; @@ -804,7 +804,7 @@ static void sof_pcm_remove(struct snd_soc_component *component) static int sof_pcm_ack(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); return snd_sof_pcm_platform_ack(sdev, substream); } @@ -812,7 +812,7 @@ static int sof_pcm_ack(struct snd_soc_component *component, static snd_pcm_sframes_t sof_pcm_delay(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); if (pcm_ops && pcm_ops->delay) diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 0e4e1bb8c35ff1..087c54276c4557 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -950,7 +950,7 @@ bool snd_sof_stream_suspend_ignored(struct snd_sof_dev *sdev) struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_soc_component *scomp, const char *name) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_sof_pcm *spcm; list_for_each_entry(spcm, &sdev->pcm_list, list) { @@ -976,7 +976,15 @@ struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_soc_component *scomp, unsigned int comp_id, int *direction) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); + + return snd_sof_find_spcm_comp_by_sdev(sdev, comp_id, direction); +} + +struct snd_sof_pcm *snd_sof_find_spcm_comp_by_sdev(struct snd_sof_dev *sdev, + unsigned int comp_id, + int *direction) +{ struct snd_sof_pcm *spcm; int dir; @@ -995,7 +1003,7 @@ struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_soc_component *scomp, struct snd_sof_widget *snd_sof_find_swidget(struct snd_soc_component *scomp, const char *name) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_sof_widget *swidget; list_for_each_entry(swidget, &sdev->widget_list, list) { @@ -1011,7 +1019,7 @@ struct snd_sof_widget * snd_sof_find_swidget_sname(struct snd_soc_component *scomp, const char *pcm_name, int dir) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_sof_widget *swidget; enum snd_soc_dapm_type type; @@ -1032,7 +1040,7 @@ snd_sof_find_swidget_sname(struct snd_soc_component *scomp, struct snd_sof_dai *snd_sof_find_dai(struct snd_soc_component *scomp, const char *name) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_sof_dai *dai; list_for_each_entry(dai, &sdev->dai_list, list) { @@ -1049,7 +1057,7 @@ static int sof_dai_get_param(struct snd_soc_pcm_runtime *rtd, int param_type) snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); struct snd_sof_dai *dai = snd_sof_find_dai(component, (char *)rtd->dai_link->name); - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); /* use the tplg configured mclk if existed */ diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index a96583698a6946..cb7121c973ffb1 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -619,11 +619,17 @@ snd_sof_find_swidget_sname(struct snd_soc_component *scomp, struct snd_sof_dai *snd_sof_find_dai(struct snd_soc_component *scomp, const char *name); +static inline struct snd_sof_dev * +snd_sof_component_get_sdev(struct snd_soc_component *scomp) +{ + return snd_soc_component_get_drvdata(scomp); +} + static inline struct snd_sof_pcm *snd_sof_find_spcm_dai(struct snd_soc_component *scomp, struct snd_soc_pcm_runtime *rtd) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_sof_pcm *spcm; list_for_each_entry(spcm, &sdev->pcm_list, list) { @@ -639,6 +645,9 @@ struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_soc_component *scomp, struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_soc_component *scomp, unsigned int comp_id, int *direction); +struct snd_sof_pcm *snd_sof_find_spcm_comp_by_sdev(struct snd_sof_dev *sdev, + unsigned int comp_id, + int *direction); void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream); void snd_sof_pcm_init_elapsed_work(struct work_struct *work); int sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_runtime *rtd, diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index e69a74a419ea09..60b744f1e1fb28 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -64,7 +64,7 @@ int sof_update_ipc_object(struct snd_soc_component *scomp, void *object, enum so struct snd_sof_tuple *tuples, int num_tuples, size_t object_size, int token_instance_num) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); const struct sof_token_info *token_list; const struct sof_topology_token *tokens; @@ -278,7 +278,7 @@ static int set_up_volume_table(struct snd_sof_control *scontrol, int tlv[SOF_TLV_ITEMS], int size) { struct snd_soc_component *scomp = scontrol->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); if (tplg_ops && tplg_ops->control && tplg_ops->control->set_up_volume_table) @@ -839,7 +839,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, struct snd_kcontrol_new *kc, struct snd_soc_tplg_ctl_hdr *hdr) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_soc_tplg_mixer_control *mc = container_of(hdr, struct snd_soc_tplg_mixer_control, hdr); int tlv[SOF_TLV_ITEMS]; @@ -919,7 +919,7 @@ static int sof_control_load_enum(struct snd_soc_component *scomp, struct snd_kcontrol_new *kc, struct snd_soc_tplg_ctl_hdr *hdr) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_soc_tplg_enum_control *ec = container_of(hdr, struct snd_soc_tplg_enum_control, hdr); @@ -941,7 +941,7 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, struct snd_kcontrol_new *kc, struct snd_soc_tplg_ctl_hdr *hdr) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_soc_tplg_bytes_control *control = container_of(hdr, struct snd_soc_tplg_bytes_control, hdr); struct soc_bytes_ext *sbe = (struct soc_bytes_ext *)kc->private_value; @@ -972,7 +972,7 @@ static int sof_control_load(struct snd_soc_component *scomp, int index, struct soc_mixer_control *sm; struct soc_bytes_ext *sbe; struct soc_enum *se; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_soc_dobj *dobj; struct snd_sof_control *scontrol; int ret; @@ -1047,7 +1047,7 @@ static int sof_control_load(struct snd_soc_component *scomp, int index, static int sof_control_unload(struct snd_soc_component *scomp, struct snd_soc_dobj *dobj) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_sof_control *scontrol = dobj->private; int ret = 0; @@ -1182,7 +1182,7 @@ static void sof_disconnect_dai_widget(struct snd_soc_component *scomp, static int spcm_bind(struct snd_soc_component *scomp, struct snd_sof_pcm *spcm, int dir) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_sof_widget *host_widget; if (sdev->dspless_mode_selected) @@ -1220,7 +1220,7 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s struct snd_soc_tplg_dapm_widget *tw, enum sof_tokens *object_token_list, int count) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_soc_tplg_private *private = &tw->priv; const struct sof_token_info *token_list; @@ -1419,7 +1419,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, struct snd_soc_dapm_widget *w, struct snd_soc_tplg_dapm_widget *tw) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); const struct sof_ipc_tplg_widget_ops *widget_ops; struct snd_soc_tplg_private *priv = &tw->priv; @@ -1646,7 +1646,7 @@ static int sof_route_unload(struct snd_soc_component *scomp, static int sof_widget_unload(struct snd_soc_component *scomp, struct snd_soc_dobj *dobj) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); const struct sof_ipc_tplg_widget_ops *widget_ops; const struct snd_kcontrol_new *kc; @@ -1745,7 +1745,7 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, struct snd_soc_dai_driver *dai_drv, struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); const struct sof_ipc_pcm_ops *ipc_pcm_ops = sof_ipc_get_ops(sdev, pcm); struct snd_soc_tplg_stream_caps *caps; struct snd_soc_tplg_private *private = &pcm->priv; @@ -1860,7 +1860,7 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, static int sof_dai_unload(struct snd_soc_component *scomp, struct snd_soc_dobj *dobj) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); const struct sof_ipc_pcm_ops *ipc_pcm_ops = sof_ipc_get_ops(sdev, pcm); struct snd_sof_pcm *spcm = dobj->private; @@ -1891,7 +1891,7 @@ static const struct sof_topology_token common_dai_link_tokens[] = { static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_soc_dai_link *link, struct snd_soc_tplg_link_config *cfg) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_soc_tplg_private *private = &cfg->priv; const struct sof_token_info *token_list; @@ -2095,7 +2095,7 @@ static int sof_link_unload(struct snd_soc_component *scomp, struct snd_soc_dobj static int sof_route_load(struct snd_soc_component *scomp, int index, struct snd_soc_dapm_route *route) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_sof_widget *source_swidget, *sink_swidget; struct snd_soc_dobj *dobj = &route->dobj; struct snd_sof_route *sroute; @@ -2199,7 +2199,7 @@ static int sof_set_widget_pipeline(struct snd_sof_dev *sdev, struct snd_sof_pipe /* completion - called at completion of firmware loading */ static int sof_complete(struct snd_soc_component *scomp) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); const struct sof_ipc_tplg_widget_ops *widget_ops; struct snd_sof_control *scontrol; @@ -2287,7 +2287,7 @@ static int sof_complete(struct snd_soc_component *scomp) static int sof_manifest(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_manifest *man) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); if (tplg_ops && tplg_ops->parse_manifest) @@ -2402,7 +2402,7 @@ static int sof_dspless_widget_ready(struct snd_soc_component *scomp, int index, if (WIDGET_IS_DAI(w->id)) { static const struct sof_topology_token dai_tokens[] = { {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type, 0}}; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_sof_widget *swidget; struct snd_sof_dai *sdai; @@ -2501,7 +2501,7 @@ static const struct snd_soc_tplg_ops sof_dspless_tplg_ops = { int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_sof_pdata *sof_pdata = sdev->pdata; const char *tplg_filename_prefix = sof_pdata->tplg_filename_prefix; const struct firmware *fw; From e1262581a86121afd4c34fc9cd7a78589bdbbb4d Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 28 May 2026 17:26:40 +0300 Subject: [PATCH 47/83] ASoC: SOF: pass component to PCM DSP callbacks Convert the PCM callback family in snd_sof_dsp_ops to pass struct snd_soc_component * instead of struct snd_sof_dev *. Update the PCM callback wrappers and callback implementations to retrieve sdev with snd_sof_component_get_sdev(component). This is a preparatory, mechanical API-churn change only. No functional behavior change is intended, and sdev->component assignment is intentionally kept intact for now. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/amd/acp-pcm.c | 18 ++++++---- sound/soc/sof/amd/acp.h | 8 ++--- sound/soc/sof/intel/hda-pcm.c | 25 ++++++++------ sound/soc/sof/intel/hda-stream.c | 4 ++- sound/soc/sof/intel/hda.h | 15 +++++---- sound/soc/sof/mediatek/mt8365/mt8365.c | 8 ++--- sound/soc/sof/mediatek/mtk-adsp-common.c | 8 ++--- sound/soc/sof/mediatek/mtk-adsp-common.h | 6 ++-- sound/soc/sof/ops.h | 43 ++++++++++++++++-------- sound/soc/sof/pcm.c | 36 ++++++++++---------- sound/soc/sof/sof-priv.h | 19 ++++++----- sound/soc/sof/stream-ipc.c | 4 +-- 12 files changed, 113 insertions(+), 81 deletions(-) diff --git a/sound/soc/sof/amd/acp-pcm.c b/sound/soc/sof/amd/acp-pcm.c index 2802684f26de17..2692407e62ca2b 100644 --- a/sound/soc/sof/amd/acp-pcm.c +++ b/sound/soc/sof/amd/acp-pcm.c @@ -16,10 +16,12 @@ #include "acp.h" #include "acp-dsp-offset.h" -int acp_pcm_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, +int acp_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_sof_platform_stream_params *platform_params) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_pcm_runtime *runtime = substream->runtime; struct acp_dsp_stream *stream = runtime->private_data; unsigned int buf_offset, index; @@ -54,8 +56,10 @@ int acp_pcm_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substr } EXPORT_SYMBOL_NS(acp_pcm_hw_params, "SND_SOC_SOF_AMD_COMMON"); -int acp_pcm_open(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) +int acp_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct acp_dsp_stream *stream; stream = acp_dsp_stream_get(sdev, 0); @@ -69,8 +73,10 @@ int acp_pcm_open(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) } EXPORT_SYMBOL_NS(acp_pcm_open, "SND_SOC_SOF_AMD_COMMON"); -int acp_pcm_close(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) +int acp_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct acp_dsp_stream *stream; stream = substream->runtime->private_data; @@ -86,18 +92,18 @@ int acp_pcm_close(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) } EXPORT_SYMBOL_NS(acp_pcm_close, "SND_SOC_SOF_AMD_COMMON"); -snd_pcm_uframes_t acp_pcm_pointer(struct snd_sof_dev *sdev, +snd_pcm_uframes_t acp_pcm_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_component *scomp = sdev->component; + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_sof_pcm_stream *stream; struct sof_ipc_stream_posn posn; struct snd_sof_pcm *spcm; snd_pcm_uframes_t pos; int ret; - spcm = snd_sof_find_spcm_dai(scomp, rtd); + spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) { dev_warn_ratelimited(sdev->dev, "warn: can't find PCM with DAI ID %d\n", rtd->dai_link->id); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 2799e34b235395..ee6f16adc3c0b3 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -320,12 +320,12 @@ int acp_dsp_stream_put(struct snd_sof_dev *sdev, struct acp_dsp_stream *acp_stre /* * DSP PCM Operations. */ -int acp_pcm_open(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream); -int acp_pcm_close(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream); -int acp_pcm_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, +int acp_pcm_open(struct snd_soc_component *component, struct snd_pcm_substream *substream); +int acp_pcm_close(struct snd_soc_component *component, struct snd_pcm_substream *substream); +int acp_pcm_hw_params(struct snd_soc_component *component, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_sof_platform_stream_params *platform_params); -snd_pcm_uframes_t acp_pcm_pointer(struct snd_sof_dev *sdev, +snd_pcm_uframes_t acp_pcm_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream); extern const struct snd_sof_dsp_ops sof_acp_common_ops; diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index 7d846c1f350967..60da3e7ec2e9c4 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -98,11 +98,12 @@ u32 hda_dsp_get_bits(struct snd_sof_dev *sdev, int sample_bits) } }; -int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, +int hda_dsp_pcm_hw_params(struct snd_soc_component *component, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_sof_platform_stream_params *platform_params) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct hdac_stream *hstream = substream->runtime->private_data; struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream); struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; @@ -217,8 +218,10 @@ int hda_dsp_compr_hw_params(struct snd_sof_dev *sdev, EXPORT_SYMBOL_NS(hda_dsp_compr_hw_params, "SND_SOC_SOF_INTEL_HDA_COMMON"); /* update SPIB register with appl position */ -int hda_dsp_pcm_ack(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) +int hda_dsp_pcm_ack(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct hdac_stream *hstream = substream->runtime->private_data; struct snd_pcm_runtime *runtime = substream->runtime; ssize_t appl_pos, buf_size; @@ -239,9 +242,10 @@ int hda_dsp_pcm_ack(struct snd_sof_dev *sdev, struct snd_pcm_substream *substrea } EXPORT_SYMBOL_NS(hda_dsp_pcm_ack, "SND_SOC_SOF_INTEL_HDA_COMMON"); -int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev, +int hda_dsp_pcm_trigger(struct snd_soc_component *component, struct snd_pcm_substream *substream, int cmd) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct hdac_stream *hstream = substream->runtime->private_data; struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream); @@ -259,17 +263,17 @@ int hda_dsp_compr_trigger(struct snd_sof_dev *sdev, } EXPORT_SYMBOL_NS(hda_dsp_compr_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON"); -snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev, +snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_component *scomp = sdev->component; + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct hdac_stream *hstream = substream->runtime->private_data; struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct snd_sof_pcm *spcm; snd_pcm_uframes_t pos; - spcm = snd_sof_find_spcm_dai(scomp, rtd); + spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) { dev_warn_ratelimited(sdev->dev, "warn: can't find PCM with DAI ID %d\n", rtd->dai_link->id); @@ -305,19 +309,19 @@ int hda_dsp_compr_pointer(struct snd_sof_dev *sdev, struct snd_compr_stream *cst } EXPORT_SYMBOL_NS(hda_dsp_compr_pointer, "SND_SOC_SOF_INTEL_HDA_COMMON"); -int hda_dsp_pcm_open(struct snd_sof_dev *sdev, +int hda_dsp_pcm_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); const struct sof_intel_dsp_desc *chip_info = get_chip_info(sdev->pdata); struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_component *scomp = sdev->component; struct hdac_ext_stream *dsp_stream; struct snd_sof_pcm *spcm; int direction = substream->stream; u32 flags = 0; - spcm = snd_sof_find_spcm_dai(scomp, rtd); + spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) { dev_err(sdev->dev, "error: can't find PCM with DAI ID %d\n", rtd->dai_link->id); return -EINVAL; @@ -466,9 +470,10 @@ int hda_dsp_compr_open(struct snd_sof_dev *sdev, struct snd_compr_stream *cstrea } EXPORT_SYMBOL_NS(hda_dsp_compr_open, "SND_SOC_SOF_INTEL_HDA_COMMON"); -int hda_dsp_pcm_close(struct snd_sof_dev *sdev, +int hda_dsp_pcm_close(struct snd_soc_component *component, struct snd_pcm_substream *substream) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct hdac_stream *hstream = substream->runtime->private_data; int direction = substream->stream; int ret; diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 9c873838dff491..de5afe41204b39 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -800,9 +800,11 @@ static int _hda_dsp_stream_hw_free(struct snd_sof_dev *sdev, return 0; } -int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev, +int hda_dsp_stream_hw_free(struct snd_soc_component *component, struct snd_pcm_substream *substream) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + return _hda_dsp_stream_hw_free(sdev, substream->runtime->private_data); } EXPORT_SYMBOL_NS(hda_dsp_stream_hw_free, "SND_SOC_SOF_INTEL_HDA_COMMON"); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index ca9c5f59b7bd97..a701306b8d352a 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -667,21 +667,22 @@ u32 hda_get_interface_mask(struct snd_sof_dev *sdev); */ u32 hda_dsp_get_mult_div(struct snd_sof_dev *sdev, int rate); u32 hda_dsp_get_bits(struct snd_sof_dev *sdev, int sample_bits); -int hda_dsp_pcm_open(struct snd_sof_dev *sdev, +int hda_dsp_pcm_open(struct snd_soc_component *component, struct snd_pcm_substream *substream); -int hda_dsp_pcm_close(struct snd_sof_dev *sdev, +int hda_dsp_pcm_close(struct snd_soc_component *component, struct snd_pcm_substream *substream); -int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, +int hda_dsp_pcm_hw_params(struct snd_soc_component *component, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_sof_platform_stream_params *platform_params); -int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev, +int hda_dsp_stream_hw_free(struct snd_soc_component *component, struct snd_pcm_substream *substream); -int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev, +int hda_dsp_pcm_trigger(struct snd_soc_component *component, struct snd_pcm_substream *substream, int cmd); -snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev, +snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream); -int hda_dsp_pcm_ack(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream); +int hda_dsp_pcm_ack(struct snd_soc_component *component, + struct snd_pcm_substream *substream); int hda_dsp_compr_open(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream); int hda_dsp_compr_close(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream); diff --git a/sound/soc/sof/mediatek/mt8365/mt8365.c b/sound/soc/sof/mediatek/mt8365/mt8365.c index 7d2c6955c10c69..76a18038b98368 100644 --- a/sound/soc/sof/mediatek/mt8365/mt8365.c +++ b/sound/soc/sof/mediatek/mt8365/mt8365.c @@ -436,7 +436,7 @@ static int mt8365_get_bar_index(struct snd_sof_dev *sdev, u32 type) return type; } -static int mt8365_pcm_hw_params(struct snd_sof_dev *sdev, +static int mt8365_pcm_hw_params(struct snd_soc_component *component, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_sof_platform_stream_params *platform_params) @@ -446,18 +446,18 @@ static int mt8365_pcm_hw_params(struct snd_sof_dev *sdev, return 0; } -static snd_pcm_uframes_t mt8365_pcm_pointer(struct snd_sof_dev *sdev, +static snd_pcm_uframes_t mt8365_pcm_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_sof_pcm *spcm; struct sof_ipc_stream_posn posn; struct snd_sof_pcm_stream *stream; - struct snd_soc_component *scomp = sdev->component; struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); snd_pcm_uframes_t pos; int ret; - spcm = snd_sof_find_spcm_dai(scomp, rtd); + spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) { dev_warn_ratelimited(sdev->dev, "warn: can't find PCM with DAI ID %d\n", rtd->dai_link->id); diff --git a/sound/soc/sof/mediatek/mtk-adsp-common.c b/sound/soc/sof/mediatek/mtk-adsp-common.c index 75b4af4b5111de..57b075a6b85aff 100644 --- a/sound/soc/sof/mediatek/mtk-adsp-common.c +++ b/sound/soc/sof/mediatek/mtk-adsp-common.c @@ -161,7 +161,7 @@ EXPORT_SYMBOL(mtk_adsp_get_bar_index); * @params: hw params * @platform_params: Platform specific SOF stream parameters */ -int mtk_adsp_stream_pcm_hw_params(struct snd_sof_dev *sdev, +int mtk_adsp_stream_pcm_hw_params(struct snd_soc_component *component, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_sof_platform_stream_params *platform_params) @@ -176,18 +176,18 @@ EXPORT_SYMBOL(mtk_adsp_stream_pcm_hw_params); * @sdev: SOF device * @substream: PCM substream */ -snd_pcm_uframes_t mtk_adsp_stream_pcm_pointer(struct snd_sof_dev *sdev, +snd_pcm_uframes_t mtk_adsp_stream_pcm_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_component *scomp = sdev->component; + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_sof_pcm_stream *stream; struct sof_ipc_stream_posn posn; struct snd_sof_pcm *spcm; snd_pcm_uframes_t pos; int ret; - spcm = snd_sof_find_spcm_dai(scomp, rtd); + spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) { dev_warn_ratelimited(sdev->dev, "warn: can't find PCM with DAI ID %d\n", rtd->dai_link->id); diff --git a/sound/soc/sof/mediatek/mtk-adsp-common.h b/sound/soc/sof/mediatek/mtk-adsp-common.h index dc36b91d6779a0..7980cd4ab4c0c2 100644 --- a/sound/soc/sof/mediatek/mtk-adsp-common.h +++ b/sound/soc/sof/mediatek/mtk-adsp-common.h @@ -6,15 +6,17 @@ #define EXCEPT_MAX_HDR_SIZE 0x400 #define MTK_ADSP_STACK_DUMP_SIZE 32 +struct snd_soc_component; + void mtk_adsp_dump(struct snd_sof_dev *sdev, u32 flags); int mtk_adsp_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg); void mtk_adsp_handle_reply(struct mtk_adsp_ipc *ipc); void mtk_adsp_handle_request(struct mtk_adsp_ipc *ipc); int mtk_adsp_get_bar_index(struct snd_sof_dev *sdev, u32 type); -int mtk_adsp_stream_pcm_hw_params(struct snd_sof_dev *sdev, +int mtk_adsp_stream_pcm_hw_params(struct snd_soc_component *component, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_sof_platform_stream_params *platform_params); -snd_pcm_uframes_t mtk_adsp_stream_pcm_pointer(struct snd_sof_dev *sdev, +snd_pcm_uframes_t mtk_adsp_stream_pcm_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream); #endif diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 621e85ccce2f8e..aad1617d272f2b 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -18,6 +18,7 @@ #include #include #include "sof-priv.h" +#include "sof-audio.h" #define sof_ops(sdev) \ ((sdev)->pdata->desc->ops) @@ -423,35 +424,41 @@ static inline void snd_sof_dsp_msg_timeout_handler(struct snd_sof_dev *sdev, /* host PCM ops */ static inline int -snd_sof_pcm_platform_open(struct snd_sof_dev *sdev, +snd_sof_pcm_platform_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + if (sof_ops(sdev) && sof_ops(sdev)->pcm_open) - return sof_ops(sdev)->pcm_open(sdev, substream); + return sof_ops(sdev)->pcm_open(component, substream); return 0; } /* disconnect pcm substream to a host stream */ static inline int -snd_sof_pcm_platform_close(struct snd_sof_dev *sdev, +snd_sof_pcm_platform_close(struct snd_soc_component *component, struct snd_pcm_substream *substream) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + if (sof_ops(sdev) && sof_ops(sdev)->pcm_close) - return sof_ops(sdev)->pcm_close(sdev, substream); + return sof_ops(sdev)->pcm_close(component, substream); return 0; } /* host stream hw params */ static inline int -snd_sof_pcm_platform_hw_params(struct snd_sof_dev *sdev, +snd_sof_pcm_platform_hw_params(struct snd_soc_component *component, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_sof_platform_stream_params *platform_params) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + if (sof_ops(sdev) && sof_ops(sdev)->pcm_hw_params) - return sof_ops(sdev)->pcm_hw_params(sdev, substream, params, + return sof_ops(sdev)->pcm_hw_params(component, substream, params, platform_params); return 0; @@ -532,22 +539,26 @@ snd_sof_compr_get_dai_frame_counter(struct snd_sof_dev *sdev, /* host stream hw free */ static inline int -snd_sof_pcm_platform_hw_free(struct snd_sof_dev *sdev, +snd_sof_pcm_platform_hw_free(struct snd_soc_component *component, struct snd_pcm_substream *substream) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + if (sof_ops(sdev) && sof_ops(sdev)->pcm_hw_free) - return sof_ops(sdev)->pcm_hw_free(sdev, substream); + return sof_ops(sdev)->pcm_hw_free(component, substream); return 0; } /* host stream trigger */ static inline int -snd_sof_pcm_platform_trigger(struct snd_sof_dev *sdev, +snd_sof_pcm_platform_trigger(struct snd_soc_component *component, struct snd_pcm_substream *substream, int cmd) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + if (sof_ops(sdev) && sof_ops(sdev)->pcm_trigger) - return sof_ops(sdev)->pcm_trigger(sdev, substream, cmd); + return sof_ops(sdev)->pcm_trigger(component, substream, cmd); return 0; } @@ -584,21 +595,25 @@ snd_sof_set_stream_data_offset(struct snd_sof_dev *sdev, /* host stream pointer */ static inline snd_pcm_uframes_t -snd_sof_pcm_platform_pointer(struct snd_sof_dev *sdev, +snd_sof_pcm_platform_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + if (sof_ops(sdev) && sof_ops(sdev)->pcm_pointer) - return sof_ops(sdev)->pcm_pointer(sdev, substream); + return sof_ops(sdev)->pcm_pointer(component, substream); return 0; } /* pcm ack */ -static inline int snd_sof_pcm_platform_ack(struct snd_sof_dev *sdev, +static inline int snd_sof_pcm_platform_ack(struct snd_soc_component *component, struct snd_pcm_substream *substream) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + if (sof_ops(sdev) && sof_ops(sdev)->pcm_ack) - return sof_ops(sdev)->pcm_ack(sdev, substream); + return sof_ops(sdev)->pcm_ack(component, substream); return 0; } diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 66120fb5d44022..02392b8bbea419 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -160,7 +160,7 @@ static int sof_pcm_hw_params(struct snd_soc_component *component, } platform_params = &spcm->platform_params[substream->stream]; - ret = snd_sof_pcm_platform_hw_params(sdev, substream, params, platform_params); + ret = snd_sof_pcm_platform_hw_params(component, substream, params, platform_params); if (ret < 0) { spcm_err(spcm, substream->stream, "platform hw params failed\n"); return ret; @@ -207,6 +207,7 @@ static int sof_pcm_hw_params(struct snd_soc_component *component, } static int sof_pcm_stream_free(struct snd_sof_dev *sdev, + struct snd_soc_component *component, struct snd_pcm_substream *substream, struct snd_sof_pcm *spcm, int dir, bool free_widget_list) @@ -218,12 +219,12 @@ static int sof_pcm_stream_free(struct snd_sof_dev *sdev, 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, + snd_sof_pcm_platform_trigger(component, substream, SNDRV_PCM_TRIGGER_STOP); /* free PCM in the DSP */ if (pcm_ops && pcm_ops->hw_free) { - ret = pcm_ops->hw_free(sdev->component, substream, spcm, + ret = pcm_ops->hw_free(component, substream, spcm, substream->stream); if (ret < 0) { spcm_err(spcm, substream->stream, @@ -237,7 +238,7 @@ static int sof_pcm_stream_free(struct snd_sof_dev *sdev, } /* reset the DMA */ - ret = snd_sof_pcm_platform_hw_free(sdev, substream); + ret = snd_sof_pcm_platform_hw_free(component, substream); if (ret < 0) { spcm_err(spcm, substream->stream, "platform hw free failed %d\n", ret); @@ -274,7 +275,7 @@ int sof_pcm_free_all_streams(struct snd_sof_dev *sdev) continue; if (spcm->stream[dir].list) { - ret = sof_pcm_stream_free(sdev, substream, spcm, + ret = sof_pcm_stream_free(sdev, spcm->scomp, substream, spcm, dir, true); if (ret < 0) return ret; @@ -303,7 +304,8 @@ static int sof_pcm_hw_free(struct snd_soc_component *component, spcm_dbg(spcm, substream->stream, "Entry: hw_free\n"); - ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream, true); + ret = sof_pcm_stream_free(sdev, component, substream, spcm, + substream->stream, true); /* unprepare and free the list of DAPM widgets */ sof_widget_list_unprepare(sdev, spcm, substream->stream); @@ -344,7 +346,7 @@ static int sof_pcm_prepare(struct snd_soc_component *component, * this case should be reached in case of xruns where we absolutely * want to free-up and reset all PCM/DMA resources */ - ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream, true); + ret = sof_pcm_stream_free(sdev, component, substream, spcm, dir, true); if (ret < 0) return ret; } @@ -456,7 +458,7 @@ static int sof_pcm_trigger(struct snd_soc_component *component, } if (!ipc_first) - snd_sof_pcm_platform_trigger(sdev, substream, cmd); + snd_sof_pcm_platform_trigger(component, substream, cmd); if (pcm_ops && pcm_ops->trigger) ret = pcm_ops->trigger(component, substream, spcm, cmd, substream->stream); @@ -466,14 +468,14 @@ static int sof_pcm_trigger(struct snd_soc_component *component, case SNDRV_PCM_TRIGGER_START: /* invoke platform trigger to start DMA only if pcm_ops is successful */ if (ipc_first && !ret) - snd_sof_pcm_platform_trigger(sdev, substream, cmd); + snd_sof_pcm_platform_trigger(component, substream, cmd); break; 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); + snd_sof_pcm_platform_trigger(component, substream, cmd); /* * set the pending_stop flag to indicate that pipeline stop has been delayed. @@ -490,7 +492,8 @@ static int sof_pcm_trigger(struct snd_soc_component *component, /* free PCM if reset_hw_params is set and the STOP IPC is successful */ if (!ret && reset_hw_params) - ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream, false); + ret = sof_pcm_stream_free(sdev, component, substream, spcm, + substream->stream, false); return ret; } @@ -517,7 +520,7 @@ static snd_pcm_uframes_t sof_pcm_pointer(struct snd_soc_component *component, /* use dsp ops pointer callback directly if set */ if (sof_ops(sdev)->pcm_pointer) - return sof_ops(sdev)->pcm_pointer(sdev, substream); + return sof_ops(sdev)->pcm_pointer(component, substream); spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) @@ -581,7 +584,7 @@ static int sof_pcm_open(struct snd_soc_component *component, spcm->stream[substream->stream].substream = substream; spcm->prepared[substream->stream] = false; - ret = snd_sof_pcm_platform_open(sdev, substream); + ret = snd_sof_pcm_platform_open(component, substream); if (ret < 0) { spcm_err(spcm, substream->stream, "platform pcm open failed %d\n", ret); @@ -601,7 +604,6 @@ static int sof_pcm_close(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_sof_component_get_sdev(component); struct snd_sof_pcm *spcm; int err; @@ -615,7 +617,7 @@ static int sof_pcm_close(struct snd_soc_component *component, spcm_dbg(spcm, substream->stream, "Entry: close\n"); - err = snd_sof_pcm_platform_close(sdev, substream); + err = snd_sof_pcm_platform_close(component, substream); if (err < 0) { spcm_err(spcm, substream->stream, "platform pcm close failed %d\n", err); @@ -804,9 +806,7 @@ static void sof_pcm_remove(struct snd_soc_component *component) static int sof_pcm_ack(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); - - return snd_sof_pcm_platform_ack(sdev, substream); + return snd_sof_pcm_platform_ack(component, substream); } static snd_pcm_sframes_t sof_pcm_delay(struct snd_soc_component *component, diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index a3c507e8d46388..20160d2a16eda8 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -234,33 +234,34 @@ struct snd_sof_dsp_ops { struct snd_sof_mod_hdr *hdr); /* optional */ /* connect pcm substream to a host stream */ - int (*pcm_open)(struct snd_sof_dev *sdev, + int (*pcm_open)(struct snd_soc_component *component, struct snd_pcm_substream *substream); /* optional */ /* disconnect pcm substream to a host stream */ - int (*pcm_close)(struct snd_sof_dev *sdev, + int (*pcm_close)(struct snd_soc_component *component, struct snd_pcm_substream *substream); /* optional */ /* host stream hw params */ - int (*pcm_hw_params)(struct snd_sof_dev *sdev, + int (*pcm_hw_params)(struct snd_soc_component *component, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_sof_platform_stream_params *platform_params); /* optional */ /* host stream hw_free */ - int (*pcm_hw_free)(struct snd_sof_dev *sdev, + int (*pcm_hw_free)(struct snd_soc_component *component, struct snd_pcm_substream *substream); /* optional */ /* host stream trigger */ - int (*pcm_trigger)(struct snd_sof_dev *sdev, + int (*pcm_trigger)(struct snd_soc_component *component, struct snd_pcm_substream *substream, int cmd); /* optional */ /* host stream pointer */ - snd_pcm_uframes_t (*pcm_pointer)(struct snd_sof_dev *sdev, + snd_pcm_uframes_t (*pcm_pointer)(struct snd_soc_component *component, struct snd_pcm_substream *substream); /* optional */ /* pcm ack */ - int (*pcm_ack)(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream); /* optional */ + int (*pcm_ack)(struct snd_soc_component *component, + struct snd_pcm_substream *substream); /* optional */ int (*compr_open)(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream); int (*compr_close)(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream); @@ -865,9 +866,9 @@ int sof_set_stream_data_offset(struct snd_sof_dev *sdev, struct snd_sof_pcm_stream *sps, size_t posn_offset); -int sof_stream_pcm_open(struct snd_sof_dev *sdev, +int sof_stream_pcm_open(struct snd_soc_component *component, struct snd_pcm_substream *substream); -int sof_stream_pcm_close(struct snd_sof_dev *sdev, +int sof_stream_pcm_close(struct snd_soc_component *component, struct snd_pcm_substream *substream); /* SOF client support */ diff --git a/sound/soc/sof/stream-ipc.c b/sound/soc/sof/stream-ipc.c index 78758cf58f0142..44c0f98e2840ab 100644 --- a/sound/soc/sof/stream-ipc.c +++ b/sound/soc/sof/stream-ipc.c @@ -96,7 +96,7 @@ int sof_set_stream_data_offset(struct snd_sof_dev *sdev, } EXPORT_SYMBOL(sof_set_stream_data_offset); -int sof_stream_pcm_open(struct snd_sof_dev *sdev, +int sof_stream_pcm_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { struct sof_stream *stream = kmalloc_obj(*stream); @@ -118,7 +118,7 @@ int sof_stream_pcm_open(struct snd_sof_dev *sdev, } EXPORT_SYMBOL(sof_stream_pcm_open); -int sof_stream_pcm_close(struct snd_sof_dev *sdev, +int sof_stream_pcm_close(struct snd_soc_component *component, struct snd_pcm_substream *substream) { struct sof_stream *stream = substream->runtime->private_data; From 42629d33acbaeb1f8651ae8d802d1e9a12800361 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 28 May 2026 17:29:56 +0300 Subject: [PATCH 48/83] ASoC: SOF: pass component to compress DSP callbacks Convert the compress callback family in snd_sof_dsp_ops to pass struct snd_soc_component * instead of struct snd_sof_dev *. Update the compress callback wrappers and callback implementations to retrieve sdev with snd_sof_component_get_sdev(component). This is a preparatory, mechanical API-churn change only. No functional behavior change is intended. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/intel/hda-pcm.c | 20 ++++++++++------ sound/soc/sof/intel/hda-stream.c | 4 +++- sound/soc/sof/intel/hda.h | 15 +++++++----- sound/soc/sof/ipc4-compress.c | 21 ++++++++--------- sound/soc/sof/ops.h | 39 ++++++++++++++++++++++---------- sound/soc/sof/sof-priv.h | 18 ++++++++++----- 6 files changed, 74 insertions(+), 43 deletions(-) diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index 60da3e7ec2e9c4..7a381ce44f0559 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -152,11 +152,12 @@ int hda_dsp_pcm_hw_params(struct snd_soc_component *component, } EXPORT_SYMBOL_NS(hda_dsp_pcm_hw_params, "SND_SOC_SOF_INTEL_HDA_COMMON"); -int hda_dsp_compr_hw_params(struct snd_sof_dev *sdev, +int hda_dsp_compr_hw_params(struct snd_soc_component *component, struct snd_compr_stream *cstream, struct snd_compr_params *params, struct snd_sof_platform_stream_params *platform_params) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct hdac_stream *hstream = cstream->runtime->private_data; struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream); struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; @@ -253,9 +254,10 @@ int hda_dsp_pcm_trigger(struct snd_soc_component *component, } EXPORT_SYMBOL_NS(hda_dsp_pcm_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON"); -int hda_dsp_compr_trigger(struct snd_sof_dev *sdev, +int hda_dsp_compr_trigger(struct snd_soc_component *component, struct snd_compr_stream *cstream, int cmd) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct hdac_stream *hstream = cstream->runtime->private_data; struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream); @@ -295,7 +297,8 @@ snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_soc_component *component, } EXPORT_SYMBOL_NS(hda_dsp_pcm_pointer, "SND_SOC_SOF_INTEL_HDA_COMMON"); -int hda_dsp_compr_pointer(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream, +int hda_dsp_compr_pointer(struct snd_soc_component *component, + struct snd_compr_stream *cstream, struct snd_compr_tstamp64 *tstamp) { struct hdac_stream *hstream = cstream->runtime->private_data; @@ -435,15 +438,16 @@ int hda_dsp_pcm_open(struct snd_soc_component *component, } EXPORT_SYMBOL_NS(hda_dsp_pcm_open, "SND_SOC_SOF_INTEL_HDA_COMMON"); -int hda_dsp_compr_open(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream) +int hda_dsp_compr_open(struct snd_soc_component *component, + struct snd_compr_stream *cstream) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_soc_pcm_runtime *rtd = cstream->private_data; - struct snd_soc_component *scomp = sdev->component; struct hdac_ext_stream *dsp_stream; struct snd_sof_pcm *spcm; int direction = cstream->direction; - spcm = snd_sof_find_spcm_dai(scomp, rtd); + spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) { dev_err(sdev->dev, "%s: can't find PCM with DAI ID %d\n", __func__, rtd->dai_link->id); @@ -491,8 +495,10 @@ int hda_dsp_pcm_close(struct snd_soc_component *component, } EXPORT_SYMBOL_NS(hda_dsp_pcm_close, "SND_SOC_SOF_INTEL_HDA_COMMON"); -int hda_dsp_compr_close(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream) +int hda_dsp_compr_close(struct snd_soc_component *component, + struct snd_compr_stream *cstream) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct hdac_stream *hstream = cstream->runtime->private_data; int direction = cstream->direction; int ret; diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index de5afe41204b39..f589b38b3cdf53 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -809,9 +809,11 @@ int hda_dsp_stream_hw_free(struct snd_soc_component *component, } EXPORT_SYMBOL_NS(hda_dsp_stream_hw_free, "SND_SOC_SOF_INTEL_HDA_COMMON"); -int hda_dsp_stream_compr_hw_free(struct snd_sof_dev *sdev, +int hda_dsp_stream_compr_hw_free(struct snd_soc_component *component, struct snd_compr_stream *cstream) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + return _hda_dsp_stream_hw_free(sdev, cstream->runtime->private_data); } EXPORT_SYMBOL_NS(hda_dsp_stream_compr_hw_free, "SND_SOC_SOF_INTEL_HDA_COMMON"); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index a701306b8d352a..0adac1c9f1a5e1 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -684,17 +684,20 @@ snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_soc_component *component, int hda_dsp_pcm_ack(struct snd_soc_component *component, struct snd_pcm_substream *substream); -int hda_dsp_compr_open(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream); -int hda_dsp_compr_close(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream); -int hda_dsp_compr_hw_params(struct snd_sof_dev *sdev, +int hda_dsp_compr_open(struct snd_soc_component *component, + struct snd_compr_stream *cstream); +int hda_dsp_compr_close(struct snd_soc_component *component, + struct snd_compr_stream *cstream); +int hda_dsp_compr_hw_params(struct snd_soc_component *component, struct snd_compr_stream *cstream, struct snd_compr_params *params, struct snd_sof_platform_stream_params *platform_params); -int hda_dsp_stream_compr_hw_free(struct snd_sof_dev *sdev, +int hda_dsp_stream_compr_hw_free(struct snd_soc_component *component, struct snd_compr_stream *cstream); -int hda_dsp_compr_trigger(struct snd_sof_dev *sdev, +int hda_dsp_compr_trigger(struct snd_soc_component *component, struct snd_compr_stream *cstream, int cmd); -int hda_dsp_compr_pointer(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream, +int hda_dsp_compr_pointer(struct snd_soc_component *component, + struct snd_compr_stream *cstream, struct snd_compr_tstamp64 *tstamp); u64 hda_dsp_compr_get_stream_llp(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream); diff --git a/sound/soc/sof/ipc4-compress.c b/sound/soc/sof/ipc4-compress.c index 29e58c8308a9e6..7ccd4fba538246 100644 --- a/sound/soc/sof/ipc4-compress.c +++ b/sound/soc/sof/ipc4-compress.c @@ -67,7 +67,6 @@ static u32 sof_ipc4_compr_calc_min_fragment_size(struct snd_sof_pcm_stream *sps) static int sof_ipc4_compr_open(struct snd_soc_component *component, struct snd_compr_stream *cstream) { - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_sof_pcm *spcm; int dir, ret; @@ -83,7 +82,7 @@ static int sof_ipc4_compr_open(struct snd_soc_component *component, spcm_dbg(spcm, dir, "Entry: open\n"); - ret = snd_sof_compr_platform_open(sdev, cstream); + ret = snd_sof_compr_platform_open(component, cstream); if (ret < 0) { spcm_err(spcm, dir, "platform compress open failed %d\n", ret); return ret; @@ -109,13 +108,13 @@ static int sof_ipc4_compr_stream_free(struct snd_sof_dev *sdev, if (spcm->prepared[dir]) { if (spcm->pending_stop[dir]) - pcm_ops->trigger(sdev->component, NULL, spcm, + pcm_ops->trigger(spcm->scomp, NULL, spcm, SNDRV_PCM_TRIGGER_STOP, dir); - snd_sof_compr_platform_trigger(sdev, cstream, + snd_sof_compr_platform_trigger(spcm->scomp, cstream, SNDRV_PCM_TRIGGER_STOP); - err = pcm_ops->hw_free(sdev->component, NULL, spcm, dir); + err = pcm_ops->hw_free(spcm->scomp, NULL, spcm, dir); if (err < 0) spcm_err(spcm, dir, "pcm_ops->hw_free failed %d\n", err); } @@ -125,7 +124,7 @@ static int sof_ipc4_compr_stream_free(struct snd_sof_dev *sdev, spcm->stream[dir].cstream = NULL; /* reset the DMA */ - ret = snd_sof_compr_platform_hw_free(sdev, cstream); + ret = snd_sof_compr_platform_hw_free(spcm->scomp, cstream); if (ret < 0) { spcm_err(spcm, dir, "platform hw free failed %d\n", ret); if (!err) @@ -165,7 +164,7 @@ static int sof_ipc4_compr_free(struct snd_soc_component *component, snd_compr_free_pages(cstream); - err = snd_sof_compr_platform_close(sdev, cstream); + err = snd_sof_compr_platform_close(component, cstream); if (err < 0) { spcm_err(spcm, cstream->direction, "platform compress close failed %d\n", ret); @@ -415,7 +414,7 @@ static int sof_ipc4_compr_set_params(struct snd_soc_component *component, interval->max = cstream->runtime->buffer_size; platform_params = &spcm->platform_params[dir]; - ret = snd_sof_compr_platform_hw_params(sdev, cstream, compr_params, + ret = snd_sof_compr_platform_hw_params(component, cstream, compr_params, platform_params); if (ret < 0) { spcm_err(spcm, dir, "platform compress hw params failed\n"); @@ -569,7 +568,7 @@ static int sof_ipc4_compr_trigger(struct snd_soc_component *component, } if (!ret && trigger_platform) { - ret = snd_sof_compr_platform_trigger(sdev, cstream, cmd); + ret = snd_sof_compr_platform_trigger(component, cstream, cmd); if (ret < 0) spcm_err(spcm, dir, "platform compress trigger start failed %d\n", @@ -657,7 +656,7 @@ static int sof_ipc4_compr_pointer(struct snd_soc_component *component, params = &spcm->params[cstream->direction]; - ret = snd_sof_compr_platform_pointer(sdev, cstream, tstamp); + ret = snd_sof_compr_platform_pointer(component, cstream, tstamp); if (ret < 0) { spcm_err(spcm, cstream->direction, "platform compress pointer failed %d\n", ret); @@ -743,7 +742,7 @@ void sof_ipc4_compr_drain_done(struct snd_sof_dev *sdev, void *ipc_message) } /* Look up the spcm of the host copier */ - spcm = snd_sof_find_spcm_comp(sdev->component, host_swidget->comp_id, &dir); + spcm = snd_sof_find_spcm_comp_by_sdev(sdev, host_swidget->comp_id, &dir); if (!spcm) { dev_err(sdev->dev, "%s: Stream cannot be found for %s\n", __func__, host_swidget->widget->name); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index aad1617d272f2b..adda98e0262b73 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -465,64 +465,79 @@ snd_sof_pcm_platform_hw_params(struct snd_soc_component *component, } static inline int -snd_sof_compr_platform_open(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream) +snd_sof_compr_platform_open(struct snd_soc_component *component, + struct snd_compr_stream *cstream) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + if (sof_ops(sdev) && sof_ops(sdev)->compr_open) - return sof_ops(sdev)->compr_open(sdev, cstream); + return sof_ops(sdev)->compr_open(component, cstream); return 0; } /* disconnect pcm substream to a host stream */ static inline int -snd_sof_compr_platform_close(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream) +snd_sof_compr_platform_close(struct snd_soc_component *component, + struct snd_compr_stream *cstream) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + if (sof_ops(sdev) && sof_ops(sdev)->compr_close) - return sof_ops(sdev)->compr_close(sdev, cstream); + return sof_ops(sdev)->compr_close(component, cstream); return 0; } /* host stream hw params */ static inline int -snd_sof_compr_platform_hw_params(struct snd_sof_dev *sdev, +snd_sof_compr_platform_hw_params(struct snd_soc_component *component, struct snd_compr_stream *cstream, struct snd_compr_params *params, struct snd_sof_platform_stream_params *platform_params) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + if (sof_ops(sdev) && sof_ops(sdev)->compr_hw_params) - return sof_ops(sdev)->compr_hw_params(sdev, cstream, params, platform_params); + return sof_ops(sdev)->compr_hw_params(component, cstream, params, + platform_params); return 0; } static inline int -snd_sof_compr_platform_hw_free(struct snd_sof_dev *sdev, +snd_sof_compr_platform_hw_free(struct snd_soc_component *component, struct snd_compr_stream *cstream) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + if (sof_ops(sdev) && sof_ops(sdev)->compr_hw_free) - return sof_ops(sdev)->compr_hw_free(sdev, cstream); + return sof_ops(sdev)->compr_hw_free(component, cstream); return 0; } static inline int -snd_sof_compr_platform_trigger(struct snd_sof_dev *sdev, +snd_sof_compr_platform_trigger(struct snd_soc_component *component, struct snd_compr_stream *cstream, int cmd) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + if (sof_ops(sdev) && sof_ops(sdev)->compr_trigger) - return sof_ops(sdev)->compr_trigger(sdev, cstream, cmd); + return sof_ops(sdev)->compr_trigger(component, cstream, cmd); return 0; } static inline int -snd_sof_compr_platform_pointer(struct snd_sof_dev *sdev, +snd_sof_compr_platform_pointer(struct snd_soc_component *component, struct snd_compr_stream *cstream, struct snd_compr_tstamp64 *tstamp) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + if (sof_ops(sdev) && sof_ops(sdev)->compr_pointer) - return sof_ops(sdev)->compr_pointer(sdev, cstream, tstamp); + return sof_ops(sdev)->compr_pointer(component, cstream, tstamp); return 0; } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 20160d2a16eda8..ade107916e160f 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -263,15 +263,21 @@ struct snd_sof_dsp_ops { int (*pcm_ack)(struct snd_soc_component *component, struct snd_pcm_substream *substream); /* optional */ - int (*compr_open)(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream); - int (*compr_close)(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream); - int (*compr_hw_params)(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream, + int (*compr_open)(struct snd_soc_component *component, + struct snd_compr_stream *cstream); + int (*compr_close)(struct snd_soc_component *component, + struct snd_compr_stream *cstream); + int (*compr_hw_params)(struct snd_soc_component *component, + struct snd_compr_stream *cstream, struct snd_compr_params *params, struct snd_sof_platform_stream_params *platform_params); - int (*compr_hw_free)(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream); - int (*compr_trigger)(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream, + int (*compr_hw_free)(struct snd_soc_component *component, + struct snd_compr_stream *cstream); + int (*compr_trigger)(struct snd_soc_component *component, + struct snd_compr_stream *cstream, int cmd); - int (*compr_pointer)(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream, + int (*compr_pointer)(struct snd_soc_component *component, + struct snd_compr_stream *cstream, struct snd_compr_tstamp64 *tstamp); u64 (*compr_get_dai_frame_counter)(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream); From 73237a725ede537244787520b4b1b9d55e9673a0 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 29 May 2026 10:12:18 +0300 Subject: [PATCH 49/83] ASoC: SOF: remove unused component pointer from sdev Drop the snd_sof_dev::component field and the leftover assignment in sof_pcm_probe(). All users were converted to explicit component arguments or helper-based lookups in previous preparatory changes, so this pointer is no longer needed. No functional behavior change is intended. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/pcm.c | 2 -- sound/soc/sof/sof-priv.h | 1 - 2 files changed, 3 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 02392b8bbea419..735a03f3e3773a 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -775,8 +775,6 @@ static int sof_pcm_probe(struct snd_soc_component *component) return ret; /* load the default topology */ - sdev->component = component; - tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, "%s/%s", plat_data->tplg_filename_prefix, diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index ade107916e160f..8d038c1e3ec5a0 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -662,7 +662,6 @@ struct snd_sof_dev { struct list_head dai_list; struct list_head dai_link_list; struct list_head route_list; - struct snd_soc_component *component; u32 enabled_cores_mask; /* keep track of enabled cores */ bool led_present; From a7d7817f73be4305c0d192995b21de332a25dca6 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 29 May 2026 12:10:00 +0300 Subject: [PATCH 50/83] ASoC: SOF: add audio instance bookkeeping Add per-component audio instance bookkeeping in SOF so component probe/remove can register and look up the associated instance. Use snd_sof_component_get_audio_instance() as the helper name for component-to-audio-instance lookup and keep snd_sof_component_get_sdev() as a thin wrapper around component drvdata. This provides infrastructure for the later drvdata migration away from the global sdev pointer. No functional behavior changes are intended here. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/core.c | 2 ++ sound/soc/sof/pcm.c | 20 ++++++++++++++--- sound/soc/sof/sof-audio.c | 47 +++++++++++++++++++++++++++++++++++++++ sound/soc/sof/sof-audio.h | 8 +++++++ sound/soc/sof/sof-priv.h | 10 +++++++++ 5 files changed, 84 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 1f38fe03e49395..40a7eb5d7a472f 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -690,11 +690,13 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) INIT_LIST_HEAD(&sdev->dai_list); INIT_LIST_HEAD(&sdev->dai_link_list); INIT_LIST_HEAD(&sdev->route_list); + INIT_LIST_HEAD(&sdev->audio_instance_list); INIT_LIST_HEAD(&sdev->ipc_client_list); INIT_LIST_HEAD(&sdev->ipc_rx_handler_list); INIT_LIST_HEAD(&sdev->fw_state_handler_list); spin_lock_init(&sdev->ipc_lock); spin_lock_init(&sdev->hw_lock); + spin_lock_init(&sdev->audio_instance_list_lock); mutex_init(&sdev->power_state_access); mutex_init(&sdev->ipc_client_mutex); mutex_init(&sdev->client_event_handler_mutex); diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 735a03f3e3773a..258a9a35734190 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -763,16 +763,23 @@ static int sof_pcm_probe(struct snd_soc_component *component) { struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_sof_pdata *plat_data = sdev->pdata; + struct snd_sof_audio_instance *instance; const char *tplg_filename; int ret; + instance = snd_sof_audio_instance_register(sdev, component); + if (!instance) + return -ENOMEM; + /* * make sure the device is pm_runtime_active before loading the * topology and initiating IPC or bus transactions */ ret = pm_runtime_resume_and_get(component->dev); - if (ret < 0 && ret != -EACCES) + if (ret < 0 && ret != -EACCES) { + snd_sof_audio_instance_unregister(instance); return ret; + } /* load the default topology */ tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, @@ -781,7 +788,7 @@ static int sof_pcm_probe(struct snd_soc_component *component) plat_data->tplg_filename); if (!tplg_filename) { ret = -ENOMEM; - goto pm_error; + goto out; } ret = snd_sof_load_topology(component, tplg_filename); @@ -789,7 +796,9 @@ static int sof_pcm_probe(struct snd_soc_component *component) dev_err(component->dev, "error: failed to load DSP topology %d\n", ret); -pm_error: +out: + if (ret) + snd_sof_audio_instance_unregister(instance); pm_runtime_put_autosuspend(component->dev); return ret; @@ -797,6 +806,11 @@ static int sof_pcm_probe(struct snd_soc_component *component) static void sof_pcm_remove(struct snd_soc_component *component) { + struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(component); + + if (instance) + snd_sof_audio_instance_unregister(instance); + /* remove topology */ snd_soc_tplg_component_remove(component); } diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 087c54276c4557..adce995f6638ec 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -14,6 +14,53 @@ #include "sof-utils.h" #include "ops.h" +struct snd_sof_audio_instance * +snd_sof_audio_instance_register(struct snd_sof_dev *sdev, + struct snd_soc_component *component) +{ + struct snd_sof_audio_instance *instance; + + instance = devm_kzalloc(sdev->dev, sizeof(*instance), GFP_KERNEL); + if (!instance) + return NULL; + + instance->sdev = sdev; + instance->component = component; + + scoped_guard(spinlock, &sdev->audio_instance_list_lock) + list_add_tail_rcu(&instance->list, &sdev->audio_instance_list); + + return instance; +} + +void snd_sof_audio_instance_unregister(struct snd_sof_audio_instance *instance) +{ + struct snd_sof_dev *sdev = instance->sdev; + + scoped_guard(spinlock, &sdev->audio_instance_list_lock) + list_del_rcu(&instance->list); + synchronize_rcu(); +} + +struct snd_sof_audio_instance * +snd_sof_component_get_audio_instance(struct snd_soc_component *component) +{ + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + struct snd_sof_audio_instance *instance; + + if (!sdev) + return NULL; + + guard(rcu)(); + list_for_each_entry_rcu(instance, &sdev->audio_instance_list, list) { + if (instance->component == component) + return instance; + } + + return NULL; +} +EXPORT_SYMBOL(snd_sof_component_get_audio_instance); + /* * Check if a DAI widget is an aggregated DAI. Aggregated DAI's have names ending in numbers * starting with 0. For example: in the case of a SDW speaker with 2 amps, the topology contains diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index cb7121c973ffb1..970686b2d3334c 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -648,6 +648,14 @@ struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_soc_component *scomp, struct snd_sof_pcm *snd_sof_find_spcm_comp_by_sdev(struct snd_sof_dev *sdev, unsigned int comp_id, int *direction); + +struct snd_sof_audio_instance * +snd_sof_audio_instance_register(struct snd_sof_dev *sdev, + struct snd_soc_component *component); +void snd_sof_audio_instance_unregister(struct snd_sof_audio_instance *instance); +struct snd_sof_audio_instance * +snd_sof_component_get_audio_instance(struct snd_soc_component *component); + void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream); void snd_sof_pcm_init_elapsed_work(struct work_struct *work); int sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_runtime *rtd, diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 8d038c1e3ec5a0..bd177eef8859ff 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -128,6 +128,13 @@ struct snd_soc_tplg_ops; struct snd_soc_component; struct snd_sof_pdata; +/* Per-component SOF audio integration state. */ +struct snd_sof_audio_instance { + struct snd_sof_dev *sdev; + struct snd_soc_component *component; + struct list_head list; +}; + /** * struct snd_sof_platform_stream_params - platform dependent stream parameters * @phy_addr: Platform dependent address to be used, if @use_phy_addr @@ -662,6 +669,9 @@ struct snd_sof_dev { struct list_head dai_list; struct list_head dai_link_list; struct list_head route_list; + struct list_head audio_instance_list; + /* Protect audio_instance_list */ + spinlock_t audio_instance_list_lock; u32 enabled_cores_mask; /* keep track of enabled cores */ bool led_present; From 21acafb9b25e3f1b4c64a46fa22c7e790fc9fb18 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 29 May 2026 15:04:38 +0300 Subject: [PATCH 51/83] ASoC: SOF: move pipeline_list to audio instance Move pipeline_list from snd_sof_dev to snd_sof_audio_instance and switch topology users to the component-specific instance list. This keeps audio_instance_list global in sdev and is a small incremental step toward instance-scoped audio state. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/core.c | 1 - sound/soc/sof/sof-audio.c | 1 + sound/soc/sof/sof-priv.h | 2 +- sound/soc/sof/topology.c | 12 ++++++++++-- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 40a7eb5d7a472f..50c1db7070a3e0 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -686,7 +686,6 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) INIT_LIST_HEAD(&sdev->pcm_list); INIT_LIST_HEAD(&sdev->kcontrol_list); INIT_LIST_HEAD(&sdev->widget_list); - INIT_LIST_HEAD(&sdev->pipeline_list); INIT_LIST_HEAD(&sdev->dai_list); INIT_LIST_HEAD(&sdev->dai_link_list); INIT_LIST_HEAD(&sdev->route_list); diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index adce995f6638ec..1d0a5254a67805 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -26,6 +26,7 @@ snd_sof_audio_instance_register(struct snd_sof_dev *sdev, instance->sdev = sdev; instance->component = component; + INIT_LIST_HEAD(&instance->pipeline_list); scoped_guard(spinlock, &sdev->audio_instance_list_lock) list_add_tail_rcu(&instance->list, &sdev->audio_instance_list); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index bd177eef8859ff..995a004e093b0b 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -132,6 +132,7 @@ struct snd_sof_pdata; struct snd_sof_audio_instance { struct snd_sof_dev *sdev; struct snd_soc_component *component; + struct list_head pipeline_list; struct list_head list; }; @@ -665,7 +666,6 @@ struct snd_sof_dev { struct list_head pcm_list; struct list_head kcontrol_list; struct list_head widget_list; - struct list_head pipeline_list; struct list_head dai_list; struct list_head dai_link_list; struct list_head route_list; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 60b744f1e1fb28..46270a0a51d627 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1420,6 +1420,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_dapm_widget *tw) { struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); + struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); const struct sof_ipc_tplg_widget_ops *widget_ops; struct snd_soc_tplg_private *priv = &tw->priv; @@ -1429,6 +1430,9 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, int token_list_size = 0; int ret = 0; + if (!instance) + return -EINVAL; + swidget = kzalloc_obj(*swidget); if (!swidget) return -ENOMEM; @@ -1612,7 +1616,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, spipe->pipe_widget = swidget; swidget->spipe = spipe; - list_add(&spipe->list, &sdev->pipeline_list); + list_add(&spipe->list, &instance->pipeline_list); } w->dobj.private = swidget; @@ -2200,12 +2204,16 @@ static int sof_set_widget_pipeline(struct snd_sof_dev *sdev, struct snd_sof_pipe static int sof_complete(struct snd_soc_component *scomp) { struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); + struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); const struct sof_ipc_tplg_widget_ops *widget_ops; struct snd_sof_control *scontrol; struct snd_sof_pipeline *spipe; int ret; + if (!instance) + return -EINVAL; + widget_ops = tplg_ops ? tplg_ops->widget : NULL; /* first update all control IPC structures based on the IPC version */ @@ -2220,7 +2228,7 @@ static int sof_complete(struct snd_soc_component *scomp) } /* set up the IPC structures for the pipeline widgets */ - list_for_each_entry(spipe, &sdev->pipeline_list, list) { + list_for_each_entry(spipe, &instance->pipeline_list, list) { struct snd_sof_widget *pipe_widget = spipe->pipe_widget; struct snd_sof_widget *swidget; From 76f0812f03d6931b67d6aeaa4827b3ad78090c38 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 29 May 2026 15:13:52 +0300 Subject: [PATCH 52/83] ASoC: SOF: move dai_list to audio instance The dai_list is topology-scoped state that belongs to the audio component instance rather than the global snd_sof_dev. Move it to snd_sof_audio_instance to properly scope DAI tracking per component. Update ipc3 and ipc4 SSP DAI config helpers to take the component pointer so they can look up the audio instance directly, removing the now-unused sdev variable in sof_ipc3_pcm_dai_link_fixup(). Signed-off-by: Peter Ujfalusi --- sound/soc/sof/core.c | 1 - sound/soc/sof/ipc3-pcm.c | 10 ++++++---- sound/soc/sof/ipc4-pcm.c | 8 +++++--- sound/soc/sof/sof-audio.c | 5 +++-- sound/soc/sof/sof-priv.h | 2 +- sound/soc/sof/topology.c | 2 +- 6 files changed, 16 insertions(+), 12 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 50c1db7070a3e0..7e08a8904c9c47 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -686,7 +686,6 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) INIT_LIST_HEAD(&sdev->pcm_list); INIT_LIST_HEAD(&sdev->kcontrol_list); INIT_LIST_HEAD(&sdev->widget_list); - INIT_LIST_HEAD(&sdev->dai_list); INIT_LIST_HEAD(&sdev->dai_link_list); INIT_LIST_HEAD(&sdev->route_list); INIT_LIST_HEAD(&sdev->audio_instance_list); diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c index dacac8a48bb43c..bf0c94fa6512ed 100644 --- a/sound/soc/sof/ipc3-pcm.c +++ b/sound/soc/sof/ipc3-pcm.c @@ -170,9 +170,12 @@ static int sof_ipc3_pcm_trigger(struct snd_soc_component *component, return sof_ipc_tx_message_no_reply(sdev->ipc, &stream, sizeof(stream)); } -static void ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, const char *link_name, +static void ssp_dai_config_pcm_params_match(struct snd_soc_component *component, + const char *link_name, struct snd_pcm_hw_params *params) { + struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct sof_ipc_dai_config *config; struct snd_sof_dai *dai; int i; @@ -181,7 +184,7 @@ static void ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, const char * Search for all matching DAIs as we can have both playback and capture DAI * associated with the same link. */ - list_for_each_entry(dai, &sdev->dai_list, list) { + list_for_each_entry(dai, &instance->dai_list, list) { if (!dai->name || strcmp(link_name, dai->name)) continue; for (i = 0; i < dai->number_configs; i++) { @@ -205,7 +208,6 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_sof_dai *dai = snd_sof_find_dai(component, (char *)rtd->dai_link->name); struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct sof_dai_private_data *private; struct snd_soc_dpcm *dpcm; @@ -244,7 +246,7 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, switch (private->dai_config->type) { case SOF_DAI_INTEL_SSP: /* search for config to pcm params match, if not found use default */ - ssp_dai_config_pcm_params_match(sdev, (char *)rtd->dai_link->name, params); + ssp_dai_config_pcm_params_match(component, (char *)rtd->dai_link->name, params); rate->min = private->dai_config[dai->current_config].ssp.fsync_rate; rate->max = private->dai_config[dai->current_config].ssp.fsync_rate; diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index b54d90357dca5f..029abb50765f99 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -631,10 +631,12 @@ static int sof_ipc4_pcm_hw_free(struct snd_soc_component *component, return sof_ipc4_trigger_pipelines(component, substream, SOF_IPC4_PIPE_RESET, 0, spcm, dir); } -static int ipc4_ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, +static int ipc4_ssp_dai_config_pcm_params_match(struct snd_soc_component *component, const char *link_name, struct snd_pcm_hw_params *params) { + struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(component); + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_sof_dai_link *slink; struct snd_sof_dai *dai; bool dai_link_found = false; @@ -689,7 +691,7 @@ static int ipc4_ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, "hw_config for %s: %d (num_hw_configs: %d) with %s match\n", slink->link->name, current_config, slink->num_hw_configs, partial_match ? "partial" : "full"); - list_for_each_entry(dai, &sdev->dai_list, list) + list_for_each_entry(dai, &instance->dai_list, list) if (!strcmp(slink->link->name, dai->name)) dai->current_config = current_config; @@ -893,7 +895,7 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, } if (ipc4_copier->dai_type == SOF_DAI_INTEL_SSP) - return ipc4_ssp_dai_config_pcm_params_match(sdev, + return ipc4_ssp_dai_config_pcm_params_match(component, (char *)rtd->dai_link->name, params); diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 1d0a5254a67805..bef2740e1e3b0e 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -27,6 +27,7 @@ snd_sof_audio_instance_register(struct snd_sof_dev *sdev, instance->sdev = sdev; instance->component = component; INIT_LIST_HEAD(&instance->pipeline_list); + INIT_LIST_HEAD(&instance->dai_list); scoped_guard(spinlock, &sdev->audio_instance_list_lock) list_add_tail_rcu(&instance->list, &sdev->audio_instance_list); @@ -1088,10 +1089,10 @@ snd_sof_find_swidget_sname(struct snd_soc_component *scomp, struct snd_sof_dai *snd_sof_find_dai(struct snd_soc_component *scomp, const char *name) { - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); + struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); struct snd_sof_dai *dai; - list_for_each_entry(dai, &sdev->dai_list, list) { + list_for_each_entry(dai, &instance->dai_list, list) { if (dai->name && (strcmp(name, dai->name) == 0)) return dai; } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 995a004e093b0b..efe94acfdb9015 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -133,6 +133,7 @@ struct snd_sof_audio_instance { struct snd_sof_dev *sdev; struct snd_soc_component *component; struct list_head pipeline_list; + struct list_head dai_list; struct list_head list; }; @@ -666,7 +667,6 @@ struct snd_sof_dev { struct list_head pcm_list; struct list_head kcontrol_list; struct list_head widget_list; - struct list_head dai_list; struct list_head dai_link_list; struct list_head route_list; struct list_head audio_instance_list; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 46270a0a51d627..34b67e332831ba 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1522,7 +1522,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, kfree(dai); break; } - list_add(&dai->list, &sdev->dai_list); + list_add(&dai->list, &instance->dai_list); swidget->private = dai; break; case snd_soc_dapm_decoder: From 143ac8229ff42bdf6e62e5ce86200b49669cd3e6 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 29 May 2026 15:18:54 +0300 Subject: [PATCH 53/83] ASoC: SOF: move dai_link_list to audio instance The dai_link_list is topology-scoped state that belongs to the audio component instance rather than the global snd_sof_dev. Move it to snd_sof_audio_instance to properly scope DAI link tracking per component. Callers deep in IPC call chains that only have access to sdev iterate sdev->audio_instance_list to find the matching dai_link entry. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/core.c | 1 - sound/soc/sof/ipc3-topology.c | 3 ++- sound/soc/sof/ipc4-pcm.c | 2 +- sound/soc/sof/ipc4-topology.c | 6 ++++-- sound/soc/sof/sof-audio.c | 1 + sound/soc/sof/sof-audio.h | 4 ++++ sound/soc/sof/sof-priv.h | 2 +- sound/soc/sof/topology.c | 3 ++- 8 files changed, 15 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 7e08a8904c9c47..7d3bb7cc3bb9c4 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -686,7 +686,6 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) INIT_LIST_HEAD(&sdev->pcm_list); INIT_LIST_HEAD(&sdev->kcontrol_list); INIT_LIST_HEAD(&sdev->widget_list); - INIT_LIST_HEAD(&sdev->dai_link_list); INIT_LIST_HEAD(&sdev->route_list); INIT_LIST_HEAD(&sdev->audio_instance_list); INIT_LIST_HEAD(&sdev->ipc_client_list); diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index 6a9904274ee251..c7b246b3b15704 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -1566,6 +1566,7 @@ static int sof_link_alh_load(struct snd_soc_component *scomp, struct snd_sof_dai static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget) { struct snd_soc_component *scomp = swidget->scomp; + struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_sof_dai *dai = swidget->private; struct sof_dai_private_data *private; @@ -1622,7 +1623,7 @@ static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget) sof_dbg_comp_config(scomp, &comp_dai->config); /* now update DAI config */ - list_for_each_entry(slink, &sdev->dai_link_list, list) { + list_for_each_entry(slink, &instance->dai_link_list, list) { struct sof_ipc_dai_config common_config; int i; diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 029abb50765f99..88606523808096 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -644,7 +644,7 @@ static int ipc4_ssp_dai_config_pcm_params_match(struct snd_soc_component *compon bool partial_match; int i; - list_for_each_entry(slink, &sdev->dai_link_list, list) { + list_for_each_entry(slink, &instance->dai_link_list, list) { if (!strcmp(slink->link->name, link_name)) { dai_link_found = true; break; diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 0f78651ab96784..9940e068eb6307 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1771,6 +1771,7 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget) static int snd_sof_get_hw_config_params(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int *sample_rate, int *channel_count, int *bit_depth) { + struct snd_sof_audio_instance *instance; struct snd_soc_tplg_hw_config *hw_config; struct snd_sof_dai_link *slink; bool dai_link_found = false; @@ -1778,7 +1779,7 @@ static int snd_sof_get_hw_config_params(struct snd_sof_dev *sdev, struct snd_sof int i; /* get current hw_config from link */ - list_for_each_entry(slink, &sdev->dai_link_list, list) { + for_each_slink_in_instances(slink, sdev, instance) { if (!strcmp(slink->link->name, dai->name)) { dai_link_found = true; break; @@ -4071,6 +4072,7 @@ static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index, static int sof_ipc4_dai_get_param(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int param_type) { + struct snd_sof_audio_instance *instance; struct sof_ipc4_copier *ipc4_copier = dai->private; struct snd_soc_tplg_hw_config *hw_config; struct snd_sof_dai_link *slink; @@ -4081,7 +4083,7 @@ static int sof_ipc4_dai_get_param(struct snd_sof_dev *sdev, struct snd_sof_dai * if (!ipc4_copier) return 0; - list_for_each_entry(slink, &sdev->dai_link_list, list) { + for_each_slink_in_instances(slink, sdev, instance) { if (!strcmp(slink->link->name, dai->name)) { dai_link_found = true; break; diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index bef2740e1e3b0e..a87e443005bd85 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -28,6 +28,7 @@ snd_sof_audio_instance_register(struct snd_sof_dev *sdev, instance->component = component; INIT_LIST_HEAD(&instance->pipeline_list); INIT_LIST_HEAD(&instance->dai_list); + INIT_LIST_HEAD(&instance->dai_link_list); scoped_guard(spinlock, &sdev->audio_instance_list_lock) list_add_tail_rcu(&instance->list, &sdev->audio_instance_list); diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 970686b2d3334c..b143385924ec77 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -47,6 +47,10 @@ (id) == snd_soc_dapm_decoder || \ (id) == snd_soc_dapm_encoder) +#define for_each_slink_in_instances(slink, sdev, instance) \ + list_for_each_entry(instance, &(sdev)->audio_instance_list, list) \ + list_for_each_entry(slink, &(instance)->dai_link_list, list) + #define SOF_DAI_PARAM_INTEL_SSP_MCLK 0 #define SOF_DAI_PARAM_INTEL_SSP_BCLK 1 #define SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS 2 diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index efe94acfdb9015..993ecd36215baf 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -134,6 +134,7 @@ struct snd_sof_audio_instance { struct snd_soc_component *component; struct list_head pipeline_list; struct list_head dai_list; + struct list_head dai_link_list; struct list_head list; }; @@ -667,7 +668,6 @@ struct snd_sof_dev { struct list_head pcm_list; struct list_head kcontrol_list; struct list_head widget_list; - struct list_head dai_link_list; struct list_head route_list; struct list_head audio_instance_list; /* Protect audio_instance_list */ diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 34b67e332831ba..8ce3a541bb2243 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1896,6 +1896,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ struct snd_soc_tplg_link_config *cfg) { struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); + struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_soc_tplg_private *private = &cfg->priv; const struct sof_token_info *token_list; @@ -2067,7 +2068,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ } out: link->dobj.private = slink; - list_add(&slink->list, &sdev->dai_link_list); + list_add(&slink->list, &instance->dai_link_list); return 0; From ddceac47c74d70523f8f9461299f17ab73613e3a Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 29 May 2026 15:24:50 +0300 Subject: [PATCH 54/83] ASoC: SOF: move route_list to audio instance The route_list is topology-scoped state that belongs to the audio component instance rather than the global snd_sof_dev. Move it to snd_sof_audio_instance to properly scope route tracking per component. Callers that have a snd_soc_component available use snd_sof_component_get_audio_instance(), while global operations iterate all instances in the audio_instance_list. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/core.c | 1 - sound/soc/sof/ipc3-topology.c | 6 ++++-- sound/soc/sof/sof-audio.c | 17 ++++++++++++----- sound/soc/sof/sof-audio.h | 4 ++++ sound/soc/sof/sof-priv.h | 2 +- sound/soc/sof/topology.c | 4 ++-- 6 files changed, 23 insertions(+), 11 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 7d3bb7cc3bb9c4..02f5c0976cc34e 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -686,7 +686,6 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) INIT_LIST_HEAD(&sdev->pcm_list); INIT_LIST_HEAD(&sdev->kcontrol_list); INIT_LIST_HEAD(&sdev->widget_list); - INIT_LIST_HEAD(&sdev->route_list); INIT_LIST_HEAD(&sdev->audio_instance_list); INIT_LIST_HEAD(&sdev->ipc_client_list); INIT_LIST_HEAD(&sdev->ipc_rx_handler_list); diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index c7b246b3b15704..b47735ddca51ca 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -2293,6 +2293,7 @@ static int sof_ipc3_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget static int sof_ipc3_set_up_all_pipelines(struct snd_sof_dev *sdev, bool verify) { struct sof_ipc_fw_version *v = &sdev->fw_ready.version; + struct snd_sof_audio_instance *instance; struct snd_sof_widget *swidget; struct snd_sof_route *sroute; int ret; @@ -2340,7 +2341,7 @@ static int sof_ipc3_set_up_all_pipelines(struct snd_sof_dev *sdev, bool verify) } /* restore pipeline connections */ - list_for_each_entry(sroute, &sdev->route_list, list) { + for_each_sroute_in_instances(sroute, sdev, instance) { /* only set up routes belonging to static pipelines */ if (!verify && (sroute->src_widget->dynamic_pipeline_widget || sroute->sink_widget->dynamic_pipeline_widget)) @@ -2465,6 +2466,7 @@ static int sof_ipc3_free_widgets_in_list(struct snd_sof_dev *sdev, bool include_ static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify) { struct sof_ipc_fw_version *v = &sdev->fw_ready.version; + struct snd_sof_audio_instance *instance; struct snd_sof_widget *swidget; struct snd_sof_route *sroute; bool dyn_widgets = false; @@ -2502,7 +2504,7 @@ static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif if (ret < 0) return ret; - list_for_each_entry(sroute, &sdev->route_list, list) + for_each_sroute_in_instances(sroute, sdev, instance) sroute->setup = false; /* diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index a87e443005bd85..12ed514d6a4524 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -29,6 +29,7 @@ snd_sof_audio_instance_register(struct snd_sof_dev *sdev, INIT_LIST_HEAD(&instance->pipeline_list); INIT_LIST_HEAD(&instance->dai_list); INIT_LIST_HEAD(&instance->dai_link_list); + INIT_LIST_HEAD(&instance->route_list); scoped_guard(spinlock, &sdev->audio_instance_list_lock) list_add_tail_rcu(&instance->list, &sdev->audio_instance_list); @@ -95,10 +96,12 @@ static bool is_virtual_widget(struct snd_sof_dev *sdev, struct snd_soc_dapm_widg static void sof_reset_route_setup_status(struct snd_sof_dev *sdev, struct snd_sof_widget *widget) { + struct snd_sof_audio_instance *instance = + snd_sof_component_get_audio_instance(widget->scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_sof_route *sroute; - list_for_each_entry(sroute, &sdev->route_list, list) + list_for_each_entry(sroute, &instance->route_list, list) if (sroute->src_widget == widget || sroute->sink_widget == widget) { if (sroute->setup && tplg_ops && tplg_ops->route_free) tplg_ops->route_free(sdev, sroute); @@ -311,6 +314,8 @@ int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsourc const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_sof_widget *src_widget = wsource->dobj.private; struct snd_sof_widget *sink_widget = wsink->dobj.private; + struct snd_sof_audio_instance *instance = + snd_sof_component_get_audio_instance(src_widget->scomp); struct snd_sof_route *sroute; bool route_found = false; @@ -324,7 +329,7 @@ int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsourc return 0; /* find route matching source and sink widgets */ - list_for_each_entry(sroute, &sdev->route_list, list) + list_for_each_entry(sroute, &instance->route_list, list) if (sroute->src_widget == src_widget && sroute->sink_widget == sink_widget) { route_found = true; break; @@ -377,8 +382,10 @@ static int sof_set_up_same_dir_widget_routes(struct snd_sof_dev *sdev, } static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev, - struct snd_soc_dapm_widget_list *list, int dir) + struct snd_soc_dapm_widget_list *list, + struct snd_soc_component *scomp, int dir) { + struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); struct snd_soc_dapm_widget *widget; struct snd_sof_route *sroute; struct snd_soc_dapm_path *p; @@ -433,7 +440,7 @@ static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev, * different directions, e.g. a sidetone or an amplifier feedback connected to a speaker * protection module. */ - list_for_each_entry(sroute, &sdev->route_list, list) { + list_for_each_entry(sroute, &instance->route_list, list) { bool src_widget_in_dapm_list, sink_widget_in_dapm_list; if (sroute->setup) @@ -875,7 +882,7 @@ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, * error in setting pipeline connections will result in route status being reset for * routes that were successfully set up when the widgets are freed. */ - ret = sof_setup_pipeline_connections(sdev, list, dir); + ret = sof_setup_pipeline_connections(sdev, list, spcm->scomp, dir); if (ret < 0) goto widget_free; diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index b143385924ec77..b0144089e39763 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -51,6 +51,10 @@ list_for_each_entry(instance, &(sdev)->audio_instance_list, list) \ list_for_each_entry(slink, &(instance)->dai_link_list, list) +#define for_each_sroute_in_instances(sroute, sdev, instance) \ + list_for_each_entry(instance, &(sdev)->audio_instance_list, list) \ + list_for_each_entry(sroute, &(instance)->route_list, list) + #define SOF_DAI_PARAM_INTEL_SSP_MCLK 0 #define SOF_DAI_PARAM_INTEL_SSP_BCLK 1 #define SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS 2 diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 993ecd36215baf..8e3403f0eca24c 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -135,6 +135,7 @@ struct snd_sof_audio_instance { struct list_head pipeline_list; struct list_head dai_list; struct list_head dai_link_list; + struct list_head route_list; struct list_head list; }; @@ -668,7 +669,6 @@ struct snd_sof_dev { struct list_head pcm_list; struct list_head kcontrol_list; struct list_head widget_list; - struct list_head route_list; struct list_head audio_instance_list; /* Protect audio_instance_list */ spinlock_t audio_instance_list_lock; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 8ce3a541bb2243..2b6de96396b98f 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2100,7 +2100,7 @@ static int sof_link_unload(struct snd_soc_component *scomp, struct snd_soc_dobj static int sof_route_load(struct snd_soc_component *scomp, int index, struct snd_soc_dapm_route *route) { - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); + struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); struct snd_sof_widget *source_swidget, *sink_swidget; struct snd_soc_dobj *dobj = &route->dobj; struct snd_sof_route *sroute; @@ -2158,7 +2158,7 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, sroute->sink_widget = sink_swidget; /* add route to route list */ - list_add(&sroute->list, &sdev->route_list); + list_add(&sroute->list, &instance->route_list); return 0; err: From 304ab24144c83d1edccdd9178f8261b1bc45d431 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 29 May 2026 15:32:02 +0300 Subject: [PATCH 55/83] ASoC: SOF: move pcm_list to audio instance The pcm_list is topology-scoped state that belongs to the audio component instance rather than the global snd_sof_dev. Move it to snd_sof_audio_instance to properly scope PCM tracking per component. Move the audio instance function declarations before the snd_sof_find_spcm_dai() inline function in sof-audio.h since the inline now calls snd_sof_component_get_audio_instance(). Signed-off-by: Peter Ujfalusi --- sound/soc/sof/core.c | 1 - sound/soc/sof/intel/hda-dsp.c | 3 ++- sound/soc/sof/pcm.c | 3 ++- sound/soc/sof/sof-audio.c | 14 +++++++++----- sound/soc/sof/sof-audio.h | 22 +++++++++++++--------- sound/soc/sof/sof-priv.h | 2 +- sound/soc/sof/topology.c | 3 ++- 7 files changed, 29 insertions(+), 19 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 02f5c0976cc34e..5c2221dc21806c 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -683,7 +683,6 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) if (ret) return ret; - INIT_LIST_HEAD(&sdev->pcm_list); INIT_LIST_HEAD(&sdev->kcontrol_list); INIT_LIST_HEAD(&sdev->widget_list); INIT_LIST_HEAD(&sdev->audio_instance_list); diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 9343102c4b1a9f..fe883f4cb3e7ac 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -529,12 +529,13 @@ static int hda_dsp_update_d0i3c_register(struct snd_sof_dev *sdev, u8 value) */ static bool hda_dsp_d0i3_streaming_applicable(struct snd_sof_dev *sdev) { + struct snd_sof_audio_instance *instance; struct snd_pcm_substream *substream; struct snd_sof_pcm *spcm; bool playback_active = false; int dir; - list_for_each_entry(spcm, &sdev->pcm_list, list) { + for_each_spcm_in_instances(spcm, sdev, instance) { for_each_pcm_streams(dir) { substream = spcm->stream[dir].substream; if (!substream || !substream->runtime) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 258a9a35734190..8beda69a2c8976 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -262,11 +262,12 @@ static int sof_pcm_stream_free(struct snd_sof_dev *sdev, int sof_pcm_free_all_streams(struct snd_sof_dev *sdev) { + struct snd_sof_audio_instance *instance; struct snd_pcm_substream *substream; struct snd_sof_pcm *spcm; int dir, ret; - list_for_each_entry(spcm, &sdev->pcm_list, list) { + for_each_spcm_in_instances(spcm, sdev, instance) { for_each_pcm_streams(dir) { substream = spcm->stream[dir].substream; diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 12ed514d6a4524..e33a3b7b4b75a8 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -30,6 +30,7 @@ snd_sof_audio_instance_register(struct snd_sof_dev *sdev, INIT_LIST_HEAD(&instance->dai_list); INIT_LIST_HEAD(&instance->dai_link_list); INIT_LIST_HEAD(&instance->route_list); + INIT_LIST_HEAD(&instance->pcm_list); scoped_guard(spinlock, &sdev->audio_instance_list_lock) list_add_tail_rcu(&instance->list, &sdev->audio_instance_list); @@ -960,12 +961,13 @@ int sof_widget_list_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int */ bool snd_sof_dsp_only_d0i3_compatible_stream_active(struct snd_sof_dev *sdev) { + struct snd_sof_audio_instance *instance; struct snd_pcm_substream *substream; struct snd_sof_pcm *spcm; bool d0i3_compatible_active = false; int dir; - list_for_each_entry(spcm, &sdev->pcm_list, list) { + for_each_spcm_in_instances(spcm, sdev, instance) { for_each_pcm_streams(dir) { substream = spcm->stream[dir].substream; if (!substream || !substream->runtime) @@ -989,9 +991,10 @@ EXPORT_SYMBOL(snd_sof_dsp_only_d0i3_compatible_stream_active); bool snd_sof_stream_suspend_ignored(struct snd_sof_dev *sdev) { + struct snd_sof_audio_instance *instance; struct snd_sof_pcm *spcm; - list_for_each_entry(spcm, &sdev->pcm_list, list) { + for_each_spcm_in_instances(spcm, sdev, instance) { if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].suspend_ignored || spcm->stream[SNDRV_PCM_STREAM_CAPTURE].suspend_ignored) return true; @@ -1007,10 +1010,10 @@ bool snd_sof_stream_suspend_ignored(struct snd_sof_dev *sdev) struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_soc_component *scomp, const char *name) { - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); + struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); struct snd_sof_pcm *spcm; - list_for_each_entry(spcm, &sdev->pcm_list, list) { + list_for_each_entry(spcm, &instance->pcm_list, list) { /* match with PCM dai name */ if (strcmp(spcm->pcm.dai_name, name) == 0) return spcm; @@ -1042,10 +1045,11 @@ struct snd_sof_pcm *snd_sof_find_spcm_comp_by_sdev(struct snd_sof_dev *sdev, unsigned int comp_id, int *direction) { + struct snd_sof_audio_instance *instance; struct snd_sof_pcm *spcm; int dir; - list_for_each_entry(spcm, &sdev->pcm_list, list) { + for_each_spcm_in_instances(spcm, sdev, instance) { for_each_pcm_streams(dir) { if (spcm->stream[dir].comp_id == comp_id) { *direction = dir; diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index b0144089e39763..067d1cf3ab134b 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -55,6 +55,10 @@ list_for_each_entry(instance, &(sdev)->audio_instance_list, list) \ list_for_each_entry(sroute, &(instance)->route_list, list) +#define for_each_spcm_in_instances(spcm, sdev, instance) \ + list_for_each_entry(instance, &(sdev)->audio_instance_list, list) \ + list_for_each_entry(spcm, &(instance)->pcm_list, list) + #define SOF_DAI_PARAM_INTEL_SSP_MCLK 0 #define SOF_DAI_PARAM_INTEL_SSP_BCLK 1 #define SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS 2 @@ -633,14 +637,21 @@ snd_sof_component_get_sdev(struct snd_soc_component *scomp) return snd_soc_component_get_drvdata(scomp); } +struct snd_sof_audio_instance * +snd_sof_audio_instance_register(struct snd_sof_dev *sdev, + struct snd_soc_component *component); +void snd_sof_audio_instance_unregister(struct snd_sof_audio_instance *instance); +struct snd_sof_audio_instance * +snd_sof_component_get_audio_instance(struct snd_soc_component *component); + static inline struct snd_sof_pcm *snd_sof_find_spcm_dai(struct snd_soc_component *scomp, struct snd_soc_pcm_runtime *rtd) { - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); + struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); struct snd_sof_pcm *spcm; - list_for_each_entry(spcm, &sdev->pcm_list, list) { + list_for_each_entry(spcm, &instance->pcm_list, list) { if (le32_to_cpu(spcm->pcm.dai_id) == rtd->dai_link->id) return spcm; } @@ -657,13 +668,6 @@ struct snd_sof_pcm *snd_sof_find_spcm_comp_by_sdev(struct snd_sof_dev *sdev, unsigned int comp_id, int *direction); -struct snd_sof_audio_instance * -snd_sof_audio_instance_register(struct snd_sof_dev *sdev, - struct snd_soc_component *component); -void snd_sof_audio_instance_unregister(struct snd_sof_audio_instance *instance); -struct snd_sof_audio_instance * -snd_sof_component_get_audio_instance(struct snd_soc_component *component); - void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream); void snd_sof_pcm_init_elapsed_work(struct work_struct *work); int sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_runtime *rtd, diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 8e3403f0eca24c..e6b69213fb4f2a 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -136,6 +136,7 @@ struct snd_sof_audio_instance { struct list_head dai_list; struct list_head dai_link_list; struct list_head route_list; + struct list_head pcm_list; struct list_head list; }; @@ -666,7 +667,6 @@ struct snd_sof_dev { /* topology */ struct snd_soc_tplg_ops *tplg_ops; - struct list_head pcm_list; struct list_head kcontrol_list; struct list_head widget_list; struct list_head audio_instance_list; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 2b6de96396b98f..6be4b1f95fa770 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1750,6 +1750,7 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai) { struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); + struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); const struct sof_ipc_pcm_ops *ipc_pcm_ops = sof_ipc_get_ops(sdev, pcm); struct snd_soc_tplg_stream_caps *caps; struct snd_soc_tplg_private *private = &pcm->priv; @@ -1788,7 +1789,7 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, } dai_drv->dobj.private = spcm; - list_add(&spcm->list, &sdev->pcm_list); + list_add(&spcm->list, &instance->pcm_list); ret = sof_parse_tokens(scomp, spcm, stream_tokens, ARRAY_SIZE(stream_tokens), private->array, From a207717736f31b38167763884d2d94ac9d0ac2ad Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 29 May 2026 15:51:19 +0300 Subject: [PATCH 56/83] ASoC: SOF: move kcontrol_list to audio instance Move kcontrol_list from the global snd_sof_dev to the per-component snd_sof_audio_instance structure. This is part of the ongoing effort to allow multiple audio components to coexist without sharing topology state. Update all call sites across topology.c, ipc3-control.c, and ipc4-control.c to access the kcontrol_list through the audio instance. Functions that have a snd_sof_widget available derive the instance from swidget->scomp via snd_sof_component_get_audio_instance(). Signed-off-by: Peter Ujfalusi --- sound/soc/sof/core.c | 1 - sound/soc/sof/ipc3-control.c | 4 +++- sound/soc/sof/ipc3-topology.c | 4 ++-- sound/soc/sof/ipc4-control.c | 8 ++++++-- sound/soc/sof/ipc4-topology.c | 4 ++-- sound/soc/sof/sof-audio.c | 1 + sound/soc/sof/sof-priv.h | 2 +- sound/soc/sof/topology.c | 10 ++++++---- 8 files changed, 21 insertions(+), 13 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 5c2221dc21806c..a5440cb994baa4 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -683,7 +683,6 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) if (ret) return ret; - INIT_LIST_HEAD(&sdev->kcontrol_list); INIT_LIST_HEAD(&sdev->widget_list); INIT_LIST_HEAD(&sdev->audio_instance_list); INIT_LIST_HEAD(&sdev->ipc_client_list); diff --git a/sound/soc/sof/ipc3-control.c b/sound/soc/sof/ipc3-control.c index 80ae973c31b891..202e47c1929615 100644 --- a/sound/soc/sof/ipc3-control.c +++ b/sound/soc/sof/ipc3-control.c @@ -711,11 +711,13 @@ static void sof_ipc3_control_update(struct snd_sof_dev *sdev, void *ipc_control_ static int sof_ipc3_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) { + struct snd_sof_audio_instance *instance = + snd_sof_component_get_audio_instance(swidget->scomp); struct snd_sof_control *scontrol; int ret; /* set up all controls for the widget */ - list_for_each_entry(scontrol, &sdev->kcontrol_list, list) + list_for_each_entry(scontrol, &instance->kcontrol_list, list) if (scontrol->comp_id == swidget->comp_id) { /* set kcontrol data in DSP */ ret = sof_ipc3_set_get_kcontrol_data(scontrol, true, false); diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index b47735ddca51ca..0fec2cf30548d8 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -752,7 +752,7 @@ static int sof_ipc3_widget_setup_comp_mux(struct snd_sof_widget *swidget) static int sof_ipc3_widget_setup_comp_pga(struct snd_sof_widget *swidget) { struct snd_soc_component *scomp = swidget->scomp; - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); + struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); struct sof_ipc_comp_volume *volume; struct snd_sof_control *scontrol; size_t ipc_size = sizeof(*volume); @@ -785,7 +785,7 @@ static int sof_ipc3_widget_setup_comp_pga(struct snd_sof_widget *swidget) dev_dbg(scomp->dev, "loaded PGA %s\n", swidget->widget->name); sof_dbg_comp_config(scomp, &volume->config); - list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { + list_for_each_entry(scontrol, &instance->kcontrol_list, list) { if (scontrol->comp_id == swidget->comp_id && scontrol->volume_table) { min_step = scontrol->min_volume_step; diff --git a/sound/soc/sof/ipc4-control.c b/sound/soc/sof/ipc4-control.c index ff29023c0df9f6..c28e5cb571e3ed 100644 --- a/sound/soc/sof/ipc4-control.c +++ b/sound/soc/sof/ipc4-control.c @@ -795,6 +795,7 @@ static void sof_ipc4_control_update(struct snd_sof_dev *sdev, void *ipc_message) struct sof_ipc4_msg *ipc4_msg = ipc_message; struct sof_ipc4_notify_module_data *ndata = ipc4_msg->data_ptr; struct sof_ipc4_control_msg_payload *msg_data; + struct snd_sof_audio_instance *instance; struct sof_ipc4_control_data *cdata; struct snd_soc_dapm_widget *widget; struct snd_sof_control *scontrol; @@ -842,7 +843,8 @@ static void sof_ipc4_control_update(struct snd_sof_dev *sdev, void *ipc_message) /* Find the scontrol which is the source of the notification */ msg_data = (struct sof_ipc4_control_msg_payload *)ndata->event_data; - list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { + instance = snd_sof_component_get_audio_instance(swidget->scomp); + list_for_each_entry(scontrol, &instance->kcontrol_list, list) { if (scontrol->comp_id == swidget->comp_id) { u32 local_param_id; @@ -961,10 +963,12 @@ static void sof_ipc4_control_update(struct snd_sof_dev *sdev, void *ipc_message) /* set up all controls for the widget */ static int sof_ipc4_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) { + struct snd_sof_audio_instance *instance = + snd_sof_component_get_audio_instance(swidget->scomp); struct snd_sof_control *scontrol; int ret = 0; - list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { + list_for_each_entry(scontrol, &instance->kcontrol_list, list) { if (scontrol->comp_id == swidget->comp_id) { switch (scontrol->info_type) { case SND_SOC_TPLG_CTL_VOLSW: diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 9940e068eb6307..60a2530ca0f46f 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -610,12 +610,12 @@ static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_ static void sof_ipc4_widget_update_kcontrol_module_id(struct snd_sof_widget *swidget) { struct snd_soc_component *scomp = swidget->scomp; - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); + struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); struct sof_ipc4_fw_module *fw_module = swidget->module_info; struct snd_sof_control *scontrol; /* update module ID for all kcontrols for this widget */ - list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { + list_for_each_entry(scontrol, &instance->kcontrol_list, list) { if (scontrol->comp_id == swidget->comp_id) { struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; struct sof_ipc4_msg *msg = &cdata->msg; diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index e33a3b7b4b75a8..2002c64efab1a3 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -31,6 +31,7 @@ snd_sof_audio_instance_register(struct snd_sof_dev *sdev, INIT_LIST_HEAD(&instance->dai_link_list); INIT_LIST_HEAD(&instance->route_list); INIT_LIST_HEAD(&instance->pcm_list); + INIT_LIST_HEAD(&instance->kcontrol_list); scoped_guard(spinlock, &sdev->audio_instance_list_lock) list_add_tail_rcu(&instance->list, &sdev->audio_instance_list); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index e6b69213fb4f2a..74aaa7c09dd1ef 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -137,6 +137,7 @@ struct snd_sof_audio_instance { struct list_head dai_link_list; struct list_head route_list; struct list_head pcm_list; + struct list_head kcontrol_list; struct list_head list; }; @@ -667,7 +668,6 @@ struct snd_sof_dev { /* topology */ struct snd_soc_tplg_ops *tplg_ops; - struct list_head kcontrol_list; struct list_head widget_list; struct list_head audio_instance_list; /* Protect audio_instance_list */ diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 6be4b1f95fa770..29c1706c2c3a9c 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -972,7 +972,7 @@ static int sof_control_load(struct snd_soc_component *scomp, int index, struct soc_mixer_control *sm; struct soc_bytes_ext *sbe; struct soc_enum *se; - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); + struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); struct snd_soc_dobj *dobj; struct snd_sof_control *scontrol; int ret; @@ -1040,7 +1040,7 @@ static int sof_control_load(struct snd_soc_component *scomp, int index, scontrol->led_ctl.led_value = -1; dobj->private = scontrol; - list_add(&scontrol->list, &sdev->kcontrol_list); + list_add(&scontrol->list, &instance->kcontrol_list); return 0; } @@ -2180,12 +2180,14 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, static int sof_set_widget_pipeline(struct snd_sof_dev *sdev, struct snd_sof_pipeline *spipe, struct snd_sof_widget *swidget) { + struct snd_sof_audio_instance *instance = + snd_sof_component_get_audio_instance(swidget->scomp); struct snd_sof_widget *pipe_widget = spipe->pipe_widget; struct snd_sof_control *scontrol; if (pipe_widget->dynamic_pipeline_widget) { /* dynamic widgets cannot have volatile kcontrols */ - list_for_each_entry(scontrol, &sdev->kcontrol_list, list) + list_for_each_entry(scontrol, &instance->kcontrol_list, list) if (scontrol->comp_id == swidget->comp_id && (scontrol->access & SNDRV_CTL_ELEM_ACCESS_VOLATILE)) { dev_err(sdev->dev, @@ -2220,7 +2222,7 @@ static int sof_complete(struct snd_soc_component *scomp) /* first update all control IPC structures based on the IPC version */ if (tplg_ops && tplg_ops->control_setup) - list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { + list_for_each_entry(scontrol, &instance->kcontrol_list, list) { ret = tplg_ops->control_setup(sdev, scontrol); if (ret < 0) { dev_err(sdev->dev, "failed updating IPC struct for control %s\n", From 34f330d8ae93d2550e45f9af3f11195002be8857 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 29 May 2026 16:03:16 +0300 Subject: [PATCH 57/83] ASoC: SOF: move widget_list to audio instance Move widget_list from the global snd_sof_dev to the per-component snd_sof_audio_instance structure. This completes the migration of all topology list state to the audio instance, allowing multiple audio components to coexist without sharing topology state. Update all call sites across topology.c, ipc3-topology.c, ipc3-control.c, ipc4-topology.c, ipc4-compress.c, pcm.c, and sof-audio.c to access the widget_list through the audio instance. Functions that have a snd_soc_component or snd_sof_widget available use snd_sof_component_get_audio_instance(), while global operations iterate all instances in the audio_instance_list. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/core.c | 1 - sound/soc/sof/ipc3-control.c | 7 +++++-- sound/soc/sof/ipc3-topology.c | 12 +++++++----- sound/soc/sof/ipc4-compress.c | 4 +++- sound/soc/sof/ipc4-control.c | 12 ++++++++---- sound/soc/sof/ipc4-topology.c | 9 ++++++--- sound/soc/sof/pcm.c | 3 ++- sound/soc/sof/sof-audio.c | 9 +++++---- sound/soc/sof/sof-audio.h | 4 ++++ sound/soc/sof/sof-priv.h | 2 +- sound/soc/sof/topology.c | 9 +++++---- 11 files changed, 46 insertions(+), 26 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index a5440cb994baa4..ed2629e7f41ad4 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -683,7 +683,6 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) if (ret) return ret; - INIT_LIST_HEAD(&sdev->widget_list); INIT_LIST_HEAD(&sdev->audio_instance_list); INIT_LIST_HEAD(&sdev->ipc_client_list); INIT_LIST_HEAD(&sdev->ipc_rx_handler_list); diff --git a/sound/soc/sof/ipc3-control.c b/sound/soc/sof/ipc3-control.c index 202e47c1929615..d0526dda4fdfda 100644 --- a/sound/soc/sof/ipc3-control.c +++ b/sound/soc/sof/ipc3-control.c @@ -15,6 +15,8 @@ static int sof_ipc3_set_get_kcontrol_data(struct snd_sof_control *scontrol, bool set, bool lock) { + struct snd_sof_audio_instance *instance = + snd_sof_component_get_audio_instance(scontrol->scomp); struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scontrol->scomp); struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; const struct sof_ipc_ops *iops = sdev->ipc->ops; @@ -24,7 +26,7 @@ static int sof_ipc3_set_get_kcontrol_data(struct snd_sof_control *scontrol, u32 ipc_cmd, msg_bytes; int ret = 0; - list_for_each_entry(swidget, &sdev->widget_list, list) { + list_for_each_entry(swidget, &instance->widget_list, list) { if (swidget->comp_id == scontrol->comp_id) { widget_found = true; break; @@ -587,6 +589,7 @@ static void snd_sof_update_control(struct snd_sof_control *scontrol, static void sof_ipc3_control_update(struct snd_sof_dev *sdev, void *ipc_control_message) { struct sof_ipc_ctrl_data *cdata = ipc_control_message; + struct snd_sof_audio_instance *instance; struct snd_soc_dapm_widget *widget; struct snd_sof_control *scontrol; struct snd_sof_widget *swidget; @@ -605,7 +608,7 @@ static void sof_ipc3_control_update(struct snd_sof_dev *sdev, void *ipc_control_ } /* Find the swidget first */ - list_for_each_entry(swidget, &sdev->widget_list, list) { + for_each_swidget_in_instances(swidget, sdev, instance) { if (swidget->comp_id == cdata->comp_id) { found = true; break; diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index 0fec2cf30548d8..07d8188726b9f1 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -2299,7 +2299,7 @@ static int sof_ipc3_set_up_all_pipelines(struct snd_sof_dev *sdev, bool verify) int ret; /* restore pipeline components */ - list_for_each_entry(swidget, &sdev->widget_list, list) { + for_each_swidget_in_instances(swidget, sdev, instance) { /* only set up the widgets belonging to static pipelines */ if (!verify && swidget->dynamic_pipeline_widget) continue; @@ -2364,7 +2364,7 @@ static int sof_ipc3_set_up_all_pipelines(struct snd_sof_dev *sdev, bool verify) } /* complete pipeline */ - list_for_each_entry(swidget, &sdev->widget_list, list) { + for_each_swidget_in_instances(swidget, sdev, instance) { switch (swidget->id) { case snd_soc_dapm_scheduler: /* only complete static pipelines */ @@ -2395,6 +2395,7 @@ static int sof_ipc3_set_up_all_pipelines(struct snd_sof_dev *sdev, bool verify) */ static int sof_tear_down_left_over_pipelines(struct snd_sof_dev *sdev) { + struct snd_sof_audio_instance *instance; struct snd_sof_widget *swidget; int ret; @@ -2411,7 +2412,7 @@ static int sof_tear_down_left_over_pipelines(struct snd_sof_dev *sdev) * free any left over DAI widgets. This is equivalent to the handling of suspend trigger * for the BE DAI for running streams. */ - list_for_each_entry(swidget, &sdev->widget_list, list) + for_each_swidget_in_instances(swidget, sdev, instance) if (WIDGET_IS_DAI(swidget->id) && swidget->use_count == 1) { ret = sof_widget_free(sdev, swidget); if (ret < 0) @@ -2424,11 +2425,12 @@ static int sof_tear_down_left_over_pipelines(struct snd_sof_dev *sdev) static int sof_ipc3_free_widgets_in_list(struct snd_sof_dev *sdev, bool include_scheduler, bool *dyn_widgets, bool verify) { + struct snd_sof_audio_instance *instance; struct sof_ipc_fw_version *v = &sdev->fw_ready.version; struct snd_sof_widget *swidget; int ret; - list_for_each_entry(swidget, &sdev->widget_list, list) { + for_each_swidget_in_instances(swidget, sdev, instance) { if (swidget->dynamic_pipeline_widget) { *dyn_widgets = true; continue; @@ -2512,7 +2514,7 @@ static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif * to recover at this point but this will help root cause bad sequences leading to * more issues on resume */ - list_for_each_entry(swidget, &sdev->widget_list, list) { + for_each_swidget_in_instances(swidget, sdev, instance) { if (swidget->use_count != 0) { dev_err(sdev->dev, "%s: widget %s is still in use: count %d\n", __func__, swidget->widget->name, swidget->use_count); diff --git a/sound/soc/sof/ipc4-compress.c b/sound/soc/sof/ipc4-compress.c index 7ccd4fba538246..079e0a39cf47a5 100644 --- a/sound/soc/sof/ipc4-compress.c +++ b/sound/soc/sof/ipc4-compress.c @@ -710,6 +710,7 @@ void sof_ipc4_compr_drain_done(struct snd_sof_dev *sdev, void *ipc_message) struct sof_ipc4_msg *ipc4_msg = ipc_message; struct sof_ipc4_notify_module_data *ndata = ipc4_msg->data_ptr; struct snd_sof_widget *swidget, *host_swidget; + struct snd_sof_audio_instance *instance; bool widget_found = false; struct snd_sof_pcm *spcm; int dir; @@ -727,7 +728,8 @@ void sof_ipc4_compr_drain_done(struct snd_sof_dev *sdev, void *ipc_message) return; /* Find the swidget of the host copier on the same pipeline */ - list_for_each_entry(host_swidget, &sdev->widget_list, list) { + instance = snd_sof_component_get_audio_instance(swidget->scomp); + list_for_each_entry(host_swidget, &instance->widget_list, list) { if (WIDGET_IS_AIF(host_swidget->id) && host_swidget->pipeline_id == swidget->pipeline_id) { widget_found = true; diff --git a/sound/soc/sof/ipc4-control.c b/sound/soc/sof/ipc4-control.c index c28e5cb571e3ed..1876c7c2de9c5e 100644 --- a/sound/soc/sof/ipc4-control.c +++ b/sound/soc/sof/ipc4-control.c @@ -17,6 +17,7 @@ static int sof_ipc4_set_get_kcontrol_data(struct snd_sof_control *scontrol, bool set, bool lock) { struct snd_soc_component *scomp = scontrol->scomp; + struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); const struct sof_ipc_ops *iops = sdev->ipc->ops; struct snd_sof_widget *swidget; @@ -24,7 +25,7 @@ static int sof_ipc4_set_get_kcontrol_data(struct snd_sof_control *scontrol, int ret = 0; /* find widget associated with the control */ - list_for_each_entry(swidget, &sdev->widget_list, list) { + list_for_each_entry(swidget, &instance->widget_list, list) { if (swidget->comp_id == scontrol->comp_id) { widget_found = true; break; @@ -143,6 +144,7 @@ static bool sof_ipc4_volume_put(struct snd_sof_control *scontrol, { struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; struct snd_soc_component *scomp = scontrol->scomp; + struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); unsigned int channels = scontrol->num_channels; struct snd_sof_widget *swidget; @@ -165,7 +167,7 @@ static bool sof_ipc4_volume_put(struct snd_sof_control *scontrol, return change; /* find widget associated with the control */ - list_for_each_entry(swidget, &sdev->widget_list, list) { + list_for_each_entry(swidget, &instance->widget_list, list) { if (swidget->comp_id == scontrol->comp_id) { widget_found = true; break; @@ -383,6 +385,7 @@ static bool sof_ipc4_switch_put(struct snd_sof_control *scontrol, { struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; struct snd_soc_component *scomp = scontrol->scomp; + struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_sof_widget *swidget; bool widget_found = false; @@ -403,7 +406,7 @@ static bool sof_ipc4_switch_put(struct snd_sof_control *scontrol, return change; /* find widget associated with the control */ - list_for_each_entry(swidget, &sdev->widget_list, list) { + list_for_each_entry(swidget, &instance->widget_list, list) { if (swidget->comp_id == scontrol->comp_id) { widget_found = true; break; @@ -442,6 +445,7 @@ static bool sof_ipc4_enum_put(struct snd_sof_control *scontrol, { struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; struct snd_soc_component *scomp = scontrol->scomp; + struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_sof_widget *swidget; bool widget_found = false; @@ -462,7 +466,7 @@ static bool sof_ipc4_enum_put(struct snd_sof_control *scontrol, return change; /* find widget associated with the control */ - list_for_each_entry(swidget, &sdev->widget_list, list) { + list_for_each_entry(swidget, &instance->widget_list, list) { if (swidget->comp_id == scontrol->comp_id) { widget_found = true; break; diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 60a2530ca0f46f..97d6a47e7d468f 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -221,9 +221,10 @@ static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = { struct snd_sof_widget *sof_ipc4_find_swidget_by_ids(struct snd_sof_dev *sdev, u32 module_id, int instance_id) { + struct snd_sof_audio_instance *instance; struct snd_sof_widget *swidget; - list_for_each_entry(swidget, &sdev->widget_list, list) { + for_each_swidget_in_instances(swidget, sdev, instance) { struct sof_ipc4_fw_module *fw_module = swidget->module_info; /* Only active module instances have valid instance_id */ @@ -809,6 +810,7 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) { struct sof_ipc4_available_audio_format *available_fmt; struct snd_soc_component *scomp = swidget->scomp; + struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_sof_dai *dai = swidget->private; struct sof_ipc4_copier *ipc4_copier; @@ -893,7 +895,7 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) goto free_available_fmt; } - list_for_each_entry(w, &sdev->widget_list, list) { + list_for_each_entry(w, &instance->widget_list, list) { struct snd_sof_dai *alh_dai; if (!WIDGET_IS_DAI(w->id) || !w->widget->sname || @@ -2166,6 +2168,7 @@ _sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, { struct sof_ipc4_available_audio_format *available_fmt; struct snd_soc_component *scomp = swidget->scomp; + struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct sof_ipc4_copier_data *copier_data; int input_fmt_index, output_fmt_index; @@ -2486,7 +2489,7 @@ _sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, * for all widgets with the same stream name */ i = 0; - list_for_each_entry(w, &sdev->widget_list, list) { + list_for_each_entry(w, &instance->widget_list, list) { u32 node_type; if (!WIDGET_IS_DAI(w->id) || !w->widget->sname || diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 8beda69a2c8976..a6c2725fcf7f15 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -103,9 +103,10 @@ sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_run struct snd_sof_widget *snd_sof_find_swidget_by_comp_id(struct snd_sof_dev *sdev, int comp_id) { + struct snd_sof_audio_instance *instance; struct snd_sof_widget *swidget; - list_for_each_entry(swidget, &sdev->widget_list, list) { + for_each_swidget_in_instances(swidget, sdev, instance) { if (comp_id == swidget->comp_id) return swidget; } diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 2002c64efab1a3..2a5e1739a29182 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -32,6 +32,7 @@ snd_sof_audio_instance_register(struct snd_sof_dev *sdev, INIT_LIST_HEAD(&instance->route_list); INIT_LIST_HEAD(&instance->pcm_list); INIT_LIST_HEAD(&instance->kcontrol_list); + INIT_LIST_HEAD(&instance->widget_list); scoped_guard(spinlock, &sdev->audio_instance_list_lock) list_add_tail_rcu(&instance->list, &sdev->audio_instance_list); @@ -1065,10 +1066,10 @@ struct snd_sof_pcm *snd_sof_find_spcm_comp_by_sdev(struct snd_sof_dev *sdev, struct snd_sof_widget *snd_sof_find_swidget(struct snd_soc_component *scomp, const char *name) { - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); + struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); struct snd_sof_widget *swidget; - list_for_each_entry(swidget, &sdev->widget_list, list) { + list_for_each_entry(swidget, &instance->widget_list, list) { if (strcmp(name, swidget->widget->name) == 0) return swidget; } @@ -1081,7 +1082,7 @@ struct snd_sof_widget * snd_sof_find_swidget_sname(struct snd_soc_component *scomp, const char *pcm_name, int dir) { - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); + struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); struct snd_sof_widget *swidget; enum snd_soc_dapm_type type; @@ -1090,7 +1091,7 @@ snd_sof_find_swidget_sname(struct snd_soc_component *scomp, else type = snd_soc_dapm_aif_out; - list_for_each_entry(swidget, &sdev->widget_list, list) { + list_for_each_entry(swidget, &instance->widget_list, list) { if (!strcmp(pcm_name, swidget->widget->sname) && swidget->id == type) return swidget; diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 067d1cf3ab134b..8c16b51f0a1721 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -59,6 +59,10 @@ list_for_each_entry(instance, &(sdev)->audio_instance_list, list) \ list_for_each_entry(spcm, &(instance)->pcm_list, list) +#define for_each_swidget_in_instances(swidget, sdev, instance) \ + list_for_each_entry(instance, &(sdev)->audio_instance_list, list) \ + list_for_each_entry(swidget, &(instance)->widget_list, list) + #define SOF_DAI_PARAM_INTEL_SSP_MCLK 0 #define SOF_DAI_PARAM_INTEL_SSP_BCLK 1 #define SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS 2 diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 74aaa7c09dd1ef..673fd67884d66f 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -138,6 +138,7 @@ struct snd_sof_audio_instance { struct list_head route_list; struct list_head pcm_list; struct list_head kcontrol_list; + struct list_head widget_list; struct list_head list; }; @@ -668,7 +669,6 @@ struct snd_sof_dev { /* topology */ struct snd_soc_tplg_ops *tplg_ops; - struct list_head widget_list; struct list_head audio_instance_list; /* Protect audio_instance_list */ spinlock_t audio_instance_list_lock; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 29c1706c2c3a9c..ea02a5ea27a607 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1620,7 +1620,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, } w->dobj.private = swidget; - list_add(&swidget->list, &sdev->widget_list); + list_add(&swidget->list, &instance->widget_list); return ret; free: kfree(swidget->private); @@ -2249,7 +2249,7 @@ static int sof_complete(struct snd_soc_component *scomp) } /* set the pipeline and update the IPC structure for the non scheduler widgets */ - list_for_each_entry(swidget, &sdev->widget_list, list) + list_for_each_entry(swidget, &instance->widget_list, list) if (swidget->widget->id != snd_soc_dapm_scheduler && swidget->pipeline_id == pipe_widget->pipeline_id) { ret = sof_set_widget_pipeline(sdev, spipe, swidget); @@ -2414,7 +2414,8 @@ static int sof_dspless_widget_ready(struct snd_soc_component *scomp, int index, if (WIDGET_IS_DAI(w->id)) { static const struct sof_topology_token dai_tokens[] = { {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type, 0}}; - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); + struct snd_sof_audio_instance *instance = + snd_sof_component_get_audio_instance(scomp); struct snd_sof_widget *swidget; struct snd_sof_dai *sdai; @@ -2449,7 +2450,7 @@ static int sof_dspless_widget_ready(struct snd_soc_component *scomp, int index, swidget->private = sdai; mutex_init(&swidget->setup_mutex); w->dobj.private = swidget; - list_add(&swidget->list, &sdev->widget_list); + list_add(&swidget->list, &instance->widget_list); } return 0; From 17f197e2071cf87a464ece42708fc80217bfb6ea Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 2 Jun 2026 16:44:26 +0300 Subject: [PATCH 58/83] ASoC: SOF: introduce struct sof_audio_ops Define a new sof_audio_ops structure for component-centric audio stream callbacks. These ops handle platform-specific stream management (host DMA, stream allocation, etc.) and receive snd_soc_component to identify the audio instance rather than snd_sof_dev. Add the audio_ops pointer to snd_sof_audio_instance, snd_sof_dev, and sof_dev_desc. The audio_ops flow is: sof_dev_desc provides it at probe time, core copies it to sdev, and audio_instance_register copies it from sdev to each instance. This is preparatory work for decoupling audio stream operations from snd_sof_dsp_ops, enabling audio to become a standalone sof-client. No functional change. Signed-off-by: Peter Ujfalusi --- include/sound/sof.h | 2 ++ sound/soc/sof/core.c | 1 + sound/soc/sof/sof-audio.c | 1 + sound/soc/sof/sof-priv.h | 55 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+) diff --git a/include/sound/sof.h b/include/sound/sof.h index 38d6c8cb5e832b..95b12ae4464ef7 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -17,6 +17,7 @@ struct snd_sof_dsp_ops; struct snd_sof_dev; +struct sof_audio_ops; /** * enum sof_fw_state - DSP firmware state definitions @@ -171,6 +172,7 @@ struct sof_dev_desc { const char *default_fw_filename[SOF_IPC_TYPE_COUNT]; const struct snd_sof_dsp_ops *ops; + const struct sof_audio_ops *audio_ops; int (*ops_init)(struct snd_sof_dev *sdev); void (*ops_free)(struct snd_sof_dev *sdev); }; diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index ed2629e7f41ad4..eb773390a28358 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -684,6 +684,7 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) return ret; INIT_LIST_HEAD(&sdev->audio_instance_list); + sdev->audio_ops = plat_data->desc->audio_ops; INIT_LIST_HEAD(&sdev->ipc_client_list); INIT_LIST_HEAD(&sdev->ipc_rx_handler_list); INIT_LIST_HEAD(&sdev->fw_state_handler_list); diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 2a5e1739a29182..6f5778262e05e1 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -26,6 +26,7 @@ snd_sof_audio_instance_register(struct snd_sof_dev *sdev, instance->sdev = sdev; instance->component = component; + instance->audio_ops = sdev->audio_ops; INIT_LIST_HEAD(&instance->pipeline_list); INIT_LIST_HEAD(&instance->dai_list); INIT_LIST_HEAD(&instance->dai_link_list); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 673fd67884d66f..5844d4109aeb66 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -127,11 +127,65 @@ struct snd_sof_debugfs_map; struct snd_soc_tplg_ops; struct snd_soc_component; struct snd_sof_pdata; +struct snd_sof_platform_stream_params; + +/* + * SOF platform-specific audio operations. + * + * These callbacks handle platform-specific stream management (host DMA, + * stream allocation, etc.) and are provided per audio instance. + * All callbacks receive snd_soc_component to identify the instance, + * platform code internally resolves to the hardware device as needed. + */ +struct sof_audio_ops { + /* host stream management */ + int (*pcm_open)(struct snd_soc_component *component, + struct snd_pcm_substream *substream); + int (*pcm_close)(struct snd_soc_component *component, + struct snd_pcm_substream *substream); + int (*pcm_hw_params)(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_sof_platform_stream_params *platform_params); + int (*pcm_hw_free)(struct snd_soc_component *component, + struct snd_pcm_substream *substream); + int (*pcm_trigger)(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd); + snd_pcm_uframes_t (*pcm_pointer)(struct snd_soc_component *component, + struct snd_pcm_substream *substream); + int (*pcm_ack)(struct snd_soc_component *component, + struct snd_pcm_substream *substream); + + /* compressed streams */ + int (*compr_open)(struct snd_soc_component *component, + struct snd_compr_stream *cstream); + int (*compr_close)(struct snd_soc_component *component, + struct snd_compr_stream *cstream); + int (*compr_hw_params)(struct snd_soc_component *component, + struct snd_compr_stream *cstream, + struct snd_compr_params *params, + struct snd_sof_platform_stream_params *platform_params); + int (*compr_hw_free)(struct snd_soc_component *component, + struct snd_compr_stream *cstream); + int (*compr_trigger)(struct snd_soc_component *component, + struct snd_compr_stream *cstream, int cmd); + int (*compr_pointer)(struct snd_soc_component *component, + struct snd_compr_stream *cstream, + struct snd_compr_tstamp64 *tstamp); + + /* DAI drivers */ + struct snd_soc_dai_driver *drv; + int num_drv; + + /* ALSA HW info flags, will be stored in snd_pcm_runtime.hw.info */ + u32 hw_info; +}; /* Per-component SOF audio integration state. */ struct snd_sof_audio_instance { struct snd_sof_dev *sdev; struct snd_soc_component *component; + const struct sof_audio_ops *audio_ops; struct list_head pipeline_list; struct list_head dai_list; struct list_head dai_link_list; @@ -669,6 +723,7 @@ struct snd_sof_dev { /* topology */ struct snd_soc_tplg_ops *tplg_ops; + const struct sof_audio_ops *audio_ops; struct list_head audio_instance_list; /* Protect audio_instance_list */ spinlock_t audio_instance_list_lock; From 8f14ad924fd885ccdd90f106e561e2aa81a78f68 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 2 Jun 2026 16:57:43 +0300 Subject: [PATCH 59/83] ASoC: SOF: Intel: populate sof_audio_ops per platform Define sof_audio_ops instances for all Intel SOF platforms: - sof_hda_audio_ops in hda-common-ops.c, shared by all HDA platforms (SKL, APL, CNL, ICL, TGL, MTL, LNL, NVL, PTL) - sof_bdw_audio_ops in bdw.c for Broadwell - sof_byt_audio_ops and sof_cht_audio_ops in byt.c for Baytrail and Cherrytrail (different num_drv: 3 vs 6 SSPs) - sof_tng_audio_ops in pci-tng.c for Tangier Wire audio_ops into sof_dev_desc for each platform. The callbacks point to the same functions already used in snd_sof_dsp_ops. No functional change. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/intel/bdw.c | 15 ++++++++++++++ sound/soc/sof/intel/byt.c | 31 ++++++++++++++++++++++++++++ sound/soc/sof/intel/hda-common-ops.c | 27 ++++++++++++++++++++++++ sound/soc/sof/intel/hda.h | 1 + sound/soc/sof/intel/pci-apl.c | 2 ++ sound/soc/sof/intel/pci-cnl.c | 3 +++ sound/soc/sof/intel/pci-icl.c | 2 ++ sound/soc/sof/intel/pci-lnl.c | 1 + sound/soc/sof/intel/pci-mtl.c | 3 +++ sound/soc/sof/intel/pci-nvl.c | 2 ++ sound/soc/sof/intel/pci-ptl.c | 2 ++ sound/soc/sof/intel/pci-skl.c | 2 ++ sound/soc/sof/intel/pci-tgl.c | 8 +++++++ sound/soc/sof/intel/pci-tng.c | 15 ++++++++++++++ 14 files changed, 114 insertions(+) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 9534d18be97dfe..5c2e2975a8b227 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -560,6 +560,20 @@ static struct snd_soc_dai_driver bdw_dai[] = { }, }; +static const struct sof_audio_ops sof_bdw_audio_ops = { + .pcm_open = sof_stream_pcm_open, + .pcm_close = sof_stream_pcm_close, + + .drv = bdw_dai, + .num_drv = ARRAY_SIZE(bdw_dai), + + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_BATCH, +}; + /* broadwell ops */ static const struct snd_sof_dsp_ops sof_bdw_ops = { /*Device init */ @@ -646,6 +660,7 @@ static const struct sof_dev_desc sof_acpi_broadwell_desc = { }, .nocodec_tplg_filename = "sof-bdw-nocodec.tplg", .ops = &sof_bdw_ops, + .audio_ops = &sof_bdw_audio_ops, }; static const struct acpi_device_id sof_broadwell_match[] = { diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 18208f77b84dc6..5ce91032027a3f 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -213,6 +213,20 @@ static int byt_acpi_probe(struct snd_sof_dev *sdev) } /* baytrail ops */ +static const struct sof_audio_ops sof_byt_audio_ops = { + .pcm_open = sof_stream_pcm_open, + .pcm_close = sof_stream_pcm_close, + + .drv = atom_dai, + .num_drv = 3, + + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_BATCH, +}; + static const struct snd_sof_dsp_ops sof_byt_ops = { /* device init */ .probe = byt_acpi_probe, @@ -288,6 +302,20 @@ static const struct sof_intel_dsp_desc byt_chip_info = { }; /* cherrytrail and braswell ops */ +static const struct sof_audio_ops sof_cht_audio_ops = { + .pcm_open = sof_stream_pcm_open, + .pcm_close = sof_stream_pcm_close, + + .drv = atom_dai, + .num_drv = 6, + + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_BATCH, +}; + static const struct snd_sof_dsp_ops sof_cht_ops = { /* device init */ .probe = byt_acpi_probe, @@ -384,6 +412,7 @@ static const struct sof_dev_desc sof_acpi_baytrailcr_desc = { }, .nocodec_tplg_filename = "sof-byt-nocodec.tplg", .ops = &sof_byt_ops, + .audio_ops = &sof_byt_audio_ops, }; static const struct sof_dev_desc sof_acpi_baytrail_desc = { @@ -406,6 +435,7 @@ static const struct sof_dev_desc sof_acpi_baytrail_desc = { }, .nocodec_tplg_filename = "sof-byt-nocodec.tplg", .ops = &sof_byt_ops, + .audio_ops = &sof_byt_audio_ops, }; static const struct sof_dev_desc sof_acpi_cherrytrail_desc = { @@ -428,6 +458,7 @@ static const struct sof_dev_desc sof_acpi_cherrytrail_desc = { }, .nocodec_tplg_filename = "sof-cht-nocodec.tplg", .ops = &sof_cht_ops, + .audio_ops = &sof_cht_audio_ops, }; static const struct acpi_device_id sof_baytrail_match[] = { diff --git a/sound/soc/sof/intel/hda-common-ops.c b/sound/soc/sof/intel/hda-common-ops.c index aa91f2b6fd657b..5671f555aaa6c3 100644 --- a/sound/soc/sof/intel/hda-common-ops.c +++ b/sound/soc/sof/intel/hda-common-ops.c @@ -14,6 +14,33 @@ #include "hda.h" #include "../sof-audio.h" +const struct sof_audio_ops sof_hda_audio_ops = { + .pcm_open = hda_dsp_pcm_open, + .pcm_close = hda_dsp_pcm_close, + .pcm_hw_params = hda_dsp_pcm_hw_params, + .pcm_hw_free = hda_dsp_stream_hw_free, + .pcm_trigger = hda_dsp_pcm_trigger, + .pcm_pointer = hda_dsp_pcm_pointer, + .pcm_ack = hda_dsp_pcm_ack, + + .compr_open = hda_dsp_compr_open, + .compr_hw_params = hda_dsp_compr_hw_params, + .compr_hw_free = hda_dsp_stream_compr_hw_free, + .compr_close = hda_dsp_compr_close, + .compr_trigger = hda_dsp_compr_trigger, + .compr_pointer = hda_dsp_compr_pointer, + + .drv = skl_dai, + .num_drv = SOF_SKL_NUM_DAIS, + + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, +}; +EXPORT_SYMBOL_NS(sof_hda_audio_ops, "SND_SOC_SOF_INTEL_HDA_GENERIC"); + const struct snd_sof_dsp_ops sof_hda_common_ops = { /* probe/remove/shutdown */ .probe_early = hda_dsp_probe_early, diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 0adac1c9f1a5e1..b30de753642fd9 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -962,6 +962,7 @@ int hda_dsp_dais_suspend(struct snd_sof_dev *sdev); /* * Platform Specific HW abstraction Ops. */ +extern const struct sof_audio_ops sof_hda_audio_ops; extern const struct snd_sof_dsp_ops sof_hda_common_ops; extern struct snd_sof_dsp_ops sof_skl_ops; diff --git a/sound/soc/sof/intel/pci-apl.c b/sound/soc/sof/intel/pci-apl.c index 3241403efa60a0..69ed5492a8d5f4 100644 --- a/sound/soc/sof/intel/pci-apl.c +++ b/sound/soc/sof/intel/pci-apl.c @@ -47,6 +47,7 @@ static const struct sof_dev_desc bxt_desc = { }, .nocodec_tplg_filename = "sof-apl-nocodec.tplg", .ops = &sof_apl_ops, + .audio_ops = &sof_hda_audio_ops, .ops_init = sof_apl_ops_init, .ops_free = hda_ops_free, }; @@ -79,6 +80,7 @@ static const struct sof_dev_desc glk_desc = { }, .nocodec_tplg_filename = "sof-glk-nocodec.tplg", .ops = &sof_apl_ops, + .audio_ops = &sof_hda_audio_ops, .ops_init = sof_apl_ops_init, .ops_free = hda_ops_free, }; diff --git a/sound/soc/sof/intel/pci-cnl.c b/sound/soc/sof/intel/pci-cnl.c index de48640024e493..ccd7ea7b5a822c 100644 --- a/sound/soc/sof/intel/pci-cnl.c +++ b/sound/soc/sof/intel/pci-cnl.c @@ -48,6 +48,7 @@ static const struct sof_dev_desc cnl_desc = { }, .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", .ops = &sof_cnl_ops, + .audio_ops = &sof_hda_audio_ops, .ops_init = sof_cnl_ops_init, .ops_free = hda_ops_free, }; @@ -81,6 +82,7 @@ static const struct sof_dev_desc cfl_desc = { }, .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", .ops = &sof_cnl_ops, + .audio_ops = &sof_hda_audio_ops, .ops_init = sof_cnl_ops_init, .ops_free = hda_ops_free, }; @@ -114,6 +116,7 @@ static const struct sof_dev_desc cml_desc = { }, .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", .ops = &sof_cnl_ops, + .audio_ops = &sof_hda_audio_ops, .ops_init = sof_cnl_ops_init, .ops_free = hda_ops_free, }; diff --git a/sound/soc/sof/intel/pci-icl.c b/sound/soc/sof/intel/pci-icl.c index fd219e6548445c..87b059997edadf 100644 --- a/sound/soc/sof/intel/pci-icl.c +++ b/sound/soc/sof/intel/pci-icl.c @@ -48,6 +48,7 @@ static const struct sof_dev_desc icl_desc = { }, .nocodec_tplg_filename = "sof-icl-nocodec.tplg", .ops = &sof_icl_ops, + .audio_ops = &sof_hda_audio_ops, .ops_init = sof_icl_ops_init, .ops_free = hda_ops_free, }; @@ -80,6 +81,7 @@ static const struct sof_dev_desc jsl_desc = { }, .nocodec_tplg_filename = "sof-jsl-nocodec.tplg", .ops = &sof_cnl_ops, + .audio_ops = &sof_hda_audio_ops, .ops_init = sof_cnl_ops_init, .ops_free = hda_ops_free, }; diff --git a/sound/soc/sof/intel/pci-lnl.c b/sound/soc/sof/intel/pci-lnl.c index acb4429df9ecf6..3694fccf505fa9 100644 --- a/sound/soc/sof/intel/pci-lnl.c +++ b/sound/soc/sof/intel/pci-lnl.c @@ -55,6 +55,7 @@ static const struct sof_dev_desc lnl_desc = { }, .nocodec_tplg_filename = "sof-lnl-nocodec.tplg", .ops = &sof_lnl_ops, + .audio_ops = &sof_hda_audio_ops, .ops_init = sof_lnl_ops_init, }; diff --git a/sound/soc/sof/intel/pci-mtl.c b/sound/soc/sof/intel/pci-mtl.c index 23adc5d765b475..874cf2e8267e09 100644 --- a/sound/soc/sof/intel/pci-mtl.c +++ b/sound/soc/sof/intel/pci-mtl.c @@ -54,6 +54,7 @@ static const struct sof_dev_desc mtl_desc = { }, .nocodec_tplg_filename = "sof-mtl-nocodec.tplg", .ops = &sof_mtl_ops, + .audio_ops = &sof_hda_audio_ops, .ops_init = sof_mtl_ops_init, .ops_free = hda_ops_free, }; @@ -84,6 +85,7 @@ static const struct sof_dev_desc arl_desc = { }, .nocodec_tplg_filename = "sof-arl-nocodec.tplg", .ops = &sof_mtl_ops, + .audio_ops = &sof_hda_audio_ops, .ops_init = sof_mtl_ops_init, .ops_free = hda_ops_free, }; @@ -114,6 +116,7 @@ static const struct sof_dev_desc arl_s_desc = { }, .nocodec_tplg_filename = "sof-arl-nocodec.tplg", .ops = &sof_mtl_ops, + .audio_ops = &sof_hda_audio_ops, .ops_init = sof_mtl_ops_init, .ops_free = hda_ops_free, }; diff --git a/sound/soc/sof/intel/pci-nvl.c b/sound/soc/sof/intel/pci-nvl.c index bb3c29ef547773..8f370b0729a7d0 100644 --- a/sound/soc/sof/intel/pci-nvl.c +++ b/sound/soc/sof/intel/pci-nvl.c @@ -53,6 +53,7 @@ static const struct sof_dev_desc nvl_desc = { }, .nocodec_tplg_filename = "sof-nvl-nocodec.tplg", .ops = &sof_nvl_ops, + .audio_ops = &sof_hda_audio_ops, .ops_init = sof_nvl_ops_init, }; @@ -83,6 +84,7 @@ static const struct sof_dev_desc nvl_s_desc = { }, .nocodec_tplg_filename = "sof-nvl-nocodec.tplg", .ops = &sof_nvl_ops, + .audio_ops = &sof_hda_audio_ops, .ops_init = sof_nvl_ops_init, }; diff --git a/sound/soc/sof/intel/pci-ptl.c b/sound/soc/sof/intel/pci-ptl.c index 9cb785ef763f63..61b1095503d6bb 100644 --- a/sound/soc/sof/intel/pci-ptl.c +++ b/sound/soc/sof/intel/pci-ptl.c @@ -53,6 +53,7 @@ static const struct sof_dev_desc ptl_desc = { }, .nocodec_tplg_filename = "sof-ptl-nocodec.tplg", .ops = &sof_ptl_ops, + .audio_ops = &sof_hda_audio_ops, .ops_init = sof_ptl_ops_init, }; @@ -83,6 +84,7 @@ static const struct sof_dev_desc wcl_desc = { }, .nocodec_tplg_filename = "sof-ptl-nocodec.tplg", .ops = &sof_ptl_ops, + .audio_ops = &sof_hda_audio_ops, .ops_init = sof_ptl_ops_init, }; diff --git a/sound/soc/sof/intel/pci-skl.c b/sound/soc/sof/intel/pci-skl.c index a16945dc35f7dc..6848f4170d4cb8 100644 --- a/sound/soc/sof/intel/pci-skl.c +++ b/sound/soc/sof/intel/pci-skl.c @@ -38,6 +38,7 @@ static struct sof_dev_desc skl_desc = { }, .nocodec_tplg_filename = "sof-skl-nocodec.tplg", .ops = &sof_skl_ops, + .audio_ops = &sof_hda_audio_ops, .ops_init = sof_skl_ops_init, .ops_free = hda_ops_free, }; @@ -63,6 +64,7 @@ static struct sof_dev_desc kbl_desc = { }, .nocodec_tplg_filename = "sof-kbl-nocodec.tplg", .ops = &sof_skl_ops, + .audio_ops = &sof_hda_audio_ops, .ops_init = sof_skl_ops_init, .ops_free = hda_ops_free, }; diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c index 437c4381982555..28a2b11582a9e2 100644 --- a/sound/soc/sof/intel/pci-tgl.c +++ b/sound/soc/sof/intel/pci-tgl.c @@ -48,6 +48,7 @@ static const struct sof_dev_desc tgl_desc = { }, .nocodec_tplg_filename = "sof-tgl-nocodec.tplg", .ops = &sof_tgl_ops, + .audio_ops = &sof_hda_audio_ops, .ops_init = sof_tgl_ops_init, .ops_free = hda_ops_free, }; @@ -81,6 +82,7 @@ static const struct sof_dev_desc tglh_desc = { }, .nocodec_tplg_filename = "sof-tgl-nocodec.tplg", .ops = &sof_tgl_ops, + .audio_ops = &sof_hda_audio_ops, .ops_init = sof_tgl_ops_init, .ops_free = hda_ops_free, }; @@ -113,6 +115,7 @@ static const struct sof_dev_desc ehl_desc = { }, .nocodec_tplg_filename = "sof-ehl-nocodec.tplg", .ops = &sof_tgl_ops, + .audio_ops = &sof_hda_audio_ops, .ops_init = sof_tgl_ops_init, .ops_free = hda_ops_free, }; @@ -146,6 +149,7 @@ static const struct sof_dev_desc adls_desc = { }, .nocodec_tplg_filename = "sof-adl-nocodec.tplg", .ops = &sof_tgl_ops, + .audio_ops = &sof_hda_audio_ops, .ops_init = sof_tgl_ops_init, .ops_free = hda_ops_free, }; @@ -179,6 +183,7 @@ static const struct sof_dev_desc adl_desc = { }, .nocodec_tplg_filename = "sof-adl-nocodec.tplg", .ops = &sof_tgl_ops, + .audio_ops = &sof_hda_audio_ops, .ops_init = sof_tgl_ops_init, .ops_free = hda_ops_free, }; @@ -212,6 +217,7 @@ static const struct sof_dev_desc adln_desc = { }, .nocodec_tplg_filename = "sof-adl-nocodec.tplg", .ops = &sof_tgl_ops, + .audio_ops = &sof_hda_audio_ops, .ops_init = sof_tgl_ops_init, .ops_free = hda_ops_free, }; @@ -245,6 +251,7 @@ static const struct sof_dev_desc rpls_desc = { }, .nocodec_tplg_filename = "sof-rpl-nocodec.tplg", .ops = &sof_tgl_ops, + .audio_ops = &sof_hda_audio_ops, .ops_init = sof_tgl_ops_init, .ops_free = hda_ops_free, }; @@ -278,6 +285,7 @@ static const struct sof_dev_desc rpl_desc = { }, .nocodec_tplg_filename = "sof-rpl-nocodec.tplg", .ops = &sof_tgl_ops, + .audio_ops = &sof_hda_audio_ops, .ops_init = sof_tgl_ops_init, .ops_free = hda_ops_free, }; diff --git a/sound/soc/sof/intel/pci-tng.c b/sound/soc/sof/intel/pci-tng.c index 0c11cc1fd820eb..1e8960067cb3ff 100644 --- a/sound/soc/sof/intel/pci-tng.c +++ b/sound/soc/sof/intel/pci-tng.c @@ -132,6 +132,20 @@ static int tangier_pci_probe(struct snd_sof_dev *sdev) return ret; } +static const struct sof_audio_ops sof_tng_audio_ops = { + .pcm_open = sof_stream_pcm_open, + .pcm_close = sof_stream_pcm_close, + + .drv = atom_dai, + .num_drv = 3, + + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_BATCH, +}; + const struct snd_sof_dsp_ops sof_tng_ops = { /* device init */ .probe = tangier_pci_probe, @@ -221,6 +235,7 @@ static const struct sof_dev_desc tng_desc = { }, .nocodec_tplg_filename = "sof-byt.tplg", .ops = &sof_tng_ops, + .audio_ops = &sof_tng_audio_ops, }; /* PCI IDs */ From 9c407a9e61964ece92c1e14044c53b82d295077b Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 2 Jun 2026 16:58:17 +0300 Subject: [PATCH 60/83] ASoC: SOF: AMD: populate sof_audio_ops per platform Define per-variant sof_audio_ops for all AMD SOF platforms: Renoir, Rembrandt, Van Gogh, ACP63, and ACP70. Each variant has its own audio_ops with platform-specific DAI drivers and shared ACP PCM callbacks. Set sdev->audio_ops from ops_init since the audio_ops are static to each variant file and the descriptors are in separate pci-*.c files. No functional change. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/amd/acp63.c | 18 ++++++++++++++++++ sound/soc/sof/amd/acp70.c | 18 ++++++++++++++++++ sound/soc/sof/amd/rembrandt.c | 18 ++++++++++++++++++ sound/soc/sof/amd/renoir.c | 18 ++++++++++++++++++ sound/soc/sof/amd/vangogh.c | 18 ++++++++++++++++++ 5 files changed, 90 insertions(+) diff --git a/sound/soc/sof/amd/acp63.c b/sound/soc/sof/amd/acp63.c index a686620b13588b..fcceef47fa8773 100644 --- a/sound/soc/sof/amd/acp63.c +++ b/sound/soc/sof/amd/acp63.c @@ -130,6 +130,22 @@ static struct snd_soc_dai_driver acp63_sof_dai[] = { struct snd_sof_dsp_ops sof_acp63_ops; EXPORT_SYMBOL_NS(sof_acp63_ops, "SND_SOC_SOF_AMD_COMMON"); +static const struct sof_audio_ops sof_acp63_audio_ops = { + .pcm_open = acp_pcm_open, + .pcm_close = acp_pcm_close, + .pcm_hw_params = acp_pcm_hw_params, + .pcm_pointer = acp_pcm_pointer, + + .drv = acp63_sof_dai, + .num_drv = ARRAY_SIZE(acp63_sof_dai), + + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, +}; + int sof_acp63_ops_init(struct snd_sof_dev *sdev) { /* common defaults */ @@ -138,5 +154,7 @@ int sof_acp63_ops_init(struct snd_sof_dev *sdev) sof_acp63_ops.drv = acp63_sof_dai; sof_acp63_ops.num_drv = ARRAY_SIZE(acp63_sof_dai); + sdev->audio_ops = &sof_acp63_audio_ops; + return 0; } diff --git a/sound/soc/sof/amd/acp70.c b/sound/soc/sof/amd/acp70.c index 8314ac4008dae1..c87e8a90e3b764 100644 --- a/sound/soc/sof/amd/acp70.c +++ b/sound/soc/sof/amd/acp70.c @@ -130,6 +130,22 @@ static struct snd_soc_dai_driver acp70_sof_dai[] = { struct snd_sof_dsp_ops sof_acp70_ops; EXPORT_SYMBOL_NS(sof_acp70_ops, "SND_SOC_SOF_AMD_COMMON"); +static const struct sof_audio_ops sof_acp70_audio_ops = { + .pcm_open = acp_pcm_open, + .pcm_close = acp_pcm_close, + .pcm_hw_params = acp_pcm_hw_params, + .pcm_pointer = acp_pcm_pointer, + + .drv = acp70_sof_dai, + .num_drv = ARRAY_SIZE(acp70_sof_dai), + + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, +}; + int sof_acp70_ops_init(struct snd_sof_dev *sdev) { /* common defaults */ @@ -138,5 +154,7 @@ int sof_acp70_ops_init(struct snd_sof_dev *sdev) sof_acp70_ops.drv = acp70_sof_dai; sof_acp70_ops.num_drv = ARRAY_SIZE(acp70_sof_dai); + sdev->audio_ops = &sof_acp70_audio_ops; + return 0; } diff --git a/sound/soc/sof/amd/rembrandt.c b/sound/soc/sof/amd/rembrandt.c index 86ef59743fc875..9afef5ffd9d57c 100644 --- a/sound/soc/sof/amd/rembrandt.c +++ b/sound/soc/sof/amd/rembrandt.c @@ -130,6 +130,22 @@ static struct snd_soc_dai_driver rembrandt_sof_dai[] = { struct snd_sof_dsp_ops sof_rembrandt_ops; EXPORT_SYMBOL_NS(sof_rembrandt_ops, "SND_SOC_SOF_AMD_COMMON"); +static const struct sof_audio_ops sof_rembrandt_audio_ops = { + .pcm_open = acp_pcm_open, + .pcm_close = acp_pcm_close, + .pcm_hw_params = acp_pcm_hw_params, + .pcm_pointer = acp_pcm_pointer, + + .drv = rembrandt_sof_dai, + .num_drv = ARRAY_SIZE(rembrandt_sof_dai), + + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, +}; + int sof_rembrandt_ops_init(struct snd_sof_dev *sdev) { /* common defaults */ @@ -138,5 +154,7 @@ int sof_rembrandt_ops_init(struct snd_sof_dev *sdev) sof_rembrandt_ops.drv = rembrandt_sof_dai; sof_rembrandt_ops.num_drv = ARRAY_SIZE(rembrandt_sof_dai); + sdev->audio_ops = &sof_rembrandt_audio_ops; + return 0; } diff --git a/sound/soc/sof/amd/renoir.c b/sound/soc/sof/amd/renoir.c index b3b4639abf5065..5477081427357c 100644 --- a/sound/soc/sof/amd/renoir.c +++ b/sound/soc/sof/amd/renoir.c @@ -105,6 +105,22 @@ static struct snd_soc_dai_driver renoir_sof_dai[] = { struct snd_sof_dsp_ops sof_renoir_ops; EXPORT_SYMBOL_NS(sof_renoir_ops, "SND_SOC_SOF_AMD_COMMON"); +static const struct sof_audio_ops sof_renoir_audio_ops = { + .pcm_open = acp_pcm_open, + .pcm_close = acp_pcm_close, + .pcm_hw_params = acp_pcm_hw_params, + .pcm_pointer = acp_pcm_pointer, + + .drv = renoir_sof_dai, + .num_drv = ARRAY_SIZE(renoir_sof_dai), + + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, +}; + int sof_renoir_ops_init(struct snd_sof_dev *sdev) { /* common defaults */ @@ -113,5 +129,7 @@ int sof_renoir_ops_init(struct snd_sof_dev *sdev) sof_renoir_ops.drv = renoir_sof_dai; sof_renoir_ops.num_drv = ARRAY_SIZE(renoir_sof_dai); + sdev->audio_ops = &sof_renoir_audio_ops; + return 0; } diff --git a/sound/soc/sof/amd/vangogh.c b/sound/soc/sof/amd/vangogh.c index 6ed5f9aaa414e6..dd5835bd2bc4ee 100644 --- a/sound/soc/sof/amd/vangogh.c +++ b/sound/soc/sof/amd/vangogh.c @@ -151,6 +151,22 @@ static int sof_vangogh_post_fw_run_delay(struct snd_sof_dev *sdev) struct snd_sof_dsp_ops sof_vangogh_ops; EXPORT_SYMBOL_NS(sof_vangogh_ops, "SND_SOC_SOF_AMD_COMMON"); +static const struct sof_audio_ops sof_vangogh_audio_ops = { + .pcm_open = acp_pcm_open, + .pcm_close = acp_pcm_close, + .pcm_hw_params = acp_pcm_hw_params, + .pcm_pointer = acp_pcm_pointer, + + .drv = vangogh_sof_dai, + .num_drv = ARRAY_SIZE(vangogh_sof_dai), + + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, +}; + int sof_vangogh_ops_init(struct snd_sof_dev *sdev) { const struct dmi_system_id *dmi_id; @@ -162,6 +178,8 @@ int sof_vangogh_ops_init(struct snd_sof_dev *sdev) sof_vangogh_ops.drv = vangogh_sof_dai; sof_vangogh_ops.num_drv = ARRAY_SIZE(vangogh_sof_dai); + sdev->audio_ops = &sof_vangogh_audio_ops; + dmi_id = dmi_first_match(acp_sof_quirk_table); if (dmi_id) { quirks = dmi_id->driver_data; From b5a69c76e22fc01c2bec89ed13bf881ffde59f4f Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 2 Jun 2026 16:58:28 +0300 Subject: [PATCH 61/83] ASoC: SOF: i.MX: populate sof_audio_ops per platform Define per-chip sof_audio_ops for i.MX SOF platforms: imx8, imx8m, imx8ulp, and imx95. Each chip has its own audio_ops with chip-specific DAI drivers and shared stream PCM callbacks. Add audio_ops pointer to imx_chip_info so ops_init can select the correct audio_ops per chip variant. No functional change. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/imx/imx-common.h | 1 + sound/soc/sof/imx/imx8.c | 37 ++++++++++++++++++++++++++++++++++ sound/soc/sof/imx/imx9.c | 16 +++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/sound/soc/sof/imx/imx-common.h b/sound/soc/sof/imx/imx-common.h index 9bd711dbb5d03f..5b00b191b29661 100644 --- a/sound/soc/sof/imx/imx-common.h +++ b/sound/soc/sof/imx/imx-common.h @@ -102,6 +102,7 @@ struct imx_chip_info { struct imx_memory_info *memory; struct snd_soc_dai_driver *drv; int num_drv; + const struct sof_audio_ops *audio_ops; /* optional */ const struct imx_chip_ops *ops; }; diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c index 7e9eab2e303472..fbf0086f7a5369 100644 --- a/sound/soc/sof/imx/imx8.c +++ b/sound/soc/sof/imx/imx8.c @@ -270,6 +270,37 @@ static struct snd_soc_dai_driver imx8ulp_dai[] = { IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai6", 1, 32), }; +#define SOF_IMX_HW_INFO (SNDRV_PCM_INFO_MMAP | \ + SNDRV_PCM_INFO_MMAP_VALID | \ + SNDRV_PCM_INFO_INTERLEAVED | \ + SNDRV_PCM_INFO_PAUSE | \ + SNDRV_PCM_INFO_BATCH | \ + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) + +static const struct sof_audio_ops sof_imx8_audio_ops = { + .pcm_open = sof_stream_pcm_open, + .pcm_close = sof_stream_pcm_close, + .drv = imx8_dai, + .num_drv = ARRAY_SIZE(imx8_dai), + .hw_info = SOF_IMX_HW_INFO, +}; + +static const struct sof_audio_ops sof_imx8m_audio_ops = { + .pcm_open = sof_stream_pcm_open, + .pcm_close = sof_stream_pcm_close, + .drv = imx8m_dai, + .num_drv = ARRAY_SIZE(imx8m_dai), + .hw_info = SOF_IMX_HW_INFO, +}; + +static const struct sof_audio_ops sof_imx8ulp_audio_ops = { + .pcm_open = sof_stream_pcm_open, + .pcm_close = sof_stream_pcm_close, + .drv = imx8ulp_dai, + .num_drv = ARRAY_SIZE(imx8ulp_dai), + .hw_info = SOF_IMX_HW_INFO, +}; + static struct snd_sof_dsp_ops sof_imx8_ops; static int imx8_ops_init(struct snd_sof_dev *sdev) @@ -287,6 +318,8 @@ static int imx8_ops_init(struct snd_sof_dev *sdev) sof_imx8_ops.drv = get_chip_info(sdev)->drv; sof_imx8_ops.num_drv = get_chip_info(sdev)->num_drv; + sdev->audio_ops = get_chip_info(sdev)->audio_ops; + return 0; } @@ -341,6 +374,7 @@ static const struct imx_chip_info imx8_chip_info = { .memory = imx8_memory_regions, .drv = imx8_dai, .num_drv = ARRAY_SIZE(imx8_dai), + .audio_ops = &sof_imx8_audio_ops, .ops = &imx8_chip_ops, }; @@ -353,6 +387,7 @@ static const struct imx_chip_info imx8x_chip_info = { .memory = imx8_memory_regions, .drv = imx8_dai, .num_drv = ARRAY_SIZE(imx8_dai), + .audio_ops = &sof_imx8_audio_ops, .ops = &imx8x_chip_ops, }; @@ -365,6 +400,7 @@ static const struct imx_chip_info imx8m_chip_info = { .memory = imx8m_memory_regions, .drv = imx8m_dai, .num_drv = ARRAY_SIZE(imx8m_dai), + .audio_ops = &sof_imx8m_audio_ops, .ops = &imx8m_chip_ops, }; @@ -378,6 +414,7 @@ static const struct imx_chip_info imx8ulp_chip_info = { .memory = imx8ulp_memory_regions, .drv = imx8ulp_dai, .num_drv = ARRAY_SIZE(imx8ulp_dai), + .audio_ops = &sof_imx8ulp_audio_ops, .ops = &imx8ulp_chip_ops, }; diff --git a/sound/soc/sof/imx/imx9.c b/sound/soc/sof/imx/imx9.c index e56e8a1c80222e..6641f282899652 100644 --- a/sound/soc/sof/imx/imx9.c +++ b/sound/soc/sof/imx/imx9.c @@ -14,6 +14,19 @@ static struct snd_soc_dai_driver imx95_dai[] = { IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai3", 1, 32), }; +static const struct sof_audio_ops sof_imx95_audio_ops = { + .pcm_open = sof_stream_pcm_open, + .pcm_close = sof_stream_pcm_close, + .drv = imx95_dai, + .num_drv = ARRAY_SIZE(imx95_dai), + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, +}; + static struct snd_sof_dsp_ops sof_imx9_ops; static int imx95_ops_init(struct snd_sof_dev *sdev) @@ -25,6 +38,8 @@ static int imx95_ops_init(struct snd_sof_dev *sdev) sof_imx9_ops.drv = get_chip_info(sdev)->drv; sof_imx9_ops.num_drv = get_chip_info(sdev)->num_drv; + sdev->audio_ops = get_chip_info(sdev)->audio_ops; + return 0; } @@ -76,6 +91,7 @@ static const struct imx_chip_info imx95_chip_info = { .memory = imx95_memory_regions, .drv = imx95_dai, .num_drv = ARRAY_SIZE(imx95_dai), + .audio_ops = &sof_imx95_audio_ops, .ops = &imx95_chip_ops, }; From dabf36111245511721c43db32e6fc19bf35e4a25 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 2 Jun 2026 16:58:36 +0300 Subject: [PATCH 62/83] ASoC: SOF: MediaTek: populate sof_audio_ops per platform Define per-SoC sof_audio_ops for MediaTek SOF platforms: mt8186, mt8188, mt8195, and mt8365. Each SoC has its own audio_ops with SoC-specific DAI drivers and PCM hw_params/pointer callbacks. For mt8188, set sdev->audio_ops from ops_init since it shares the mt8186 ops file and overrides drv/num_drv at init time. No functional change. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/mediatek/mt8186/mt8186.c | 36 ++++++++++++++++++++++++++ sound/soc/sof/mediatek/mt8195/mt8195.c | 17 ++++++++++++ sound/soc/sof/mediatek/mt8365/mt8365.c | 17 ++++++++++++ 3 files changed, 70 insertions(+) diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c index c1bea967737d52..0c9ce3d3bfce5f 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186.c @@ -379,6 +379,22 @@ static struct snd_soc_dai_driver mt8186_dai[] = { }; /* mt8186 ops */ +static const struct sof_audio_ops sof_mt8186_audio_ops = { + .pcm_open = sof_stream_pcm_open, + .pcm_hw_params = mtk_adsp_stream_pcm_hw_params, + .pcm_pointer = mtk_adsp_stream_pcm_pointer, + .pcm_close = sof_stream_pcm_close, + + .drv = mt8186_dai, + .num_drv = ARRAY_SIZE(mt8186_dai), + + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, +}; + static const struct snd_sof_dsp_ops sof_mt8186_ops = { /* probe and remove */ .probe = mt8186_dsp_probe, @@ -467,6 +483,7 @@ static const struct sof_dev_desc sof_of_mt8186_desc = { }, .nocodec_tplg_filename = "sof-mt8186-nocodec.tplg", .ops = &sof_mt8186_ops, + .audio_ops = &sof_mt8186_audio_ops, }; /* @@ -505,6 +522,22 @@ static struct snd_soc_dai_driver mt8188_dai[] = { }; /* mt8188 ops */ +static const struct sof_audio_ops sof_mt8188_audio_ops = { + .pcm_open = sof_stream_pcm_open, + .pcm_hw_params = mtk_adsp_stream_pcm_hw_params, + .pcm_pointer = mtk_adsp_stream_pcm_pointer, + .pcm_close = sof_stream_pcm_close, + + .drv = mt8188_dai, + .num_drv = ARRAY_SIZE(mt8188_dai), + + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, +}; + static struct snd_sof_dsp_ops sof_mt8188_ops; static int sof_mt8188_ops_init(struct snd_sof_dev *sdev) @@ -515,6 +548,8 @@ static int sof_mt8188_ops_init(struct snd_sof_dev *sdev) sof_mt8188_ops.drv = mt8188_dai; sof_mt8188_ops.num_drv = ARRAY_SIZE(mt8188_dai); + sdev->audio_ops = &sof_mt8188_audio_ops; + return 0; } @@ -541,6 +576,7 @@ static const struct sof_dev_desc sof_of_mt8188_desc = { }, .nocodec_tplg_filename = "sof-mt8188-nocodec.tplg", .ops = &sof_mt8188_ops, + .audio_ops = &sof_mt8188_audio_ops, .ops_init = sof_mt8188_ops_init, }; diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 5dfa8721e059c5..39638f6346ac41 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -402,6 +402,22 @@ static struct snd_soc_dai_driver mt8195_dai[] = { }, }; +static const struct sof_audio_ops sof_mt8195_audio_ops = { + .pcm_open = sof_stream_pcm_open, + .pcm_hw_params = mtk_adsp_stream_pcm_hw_params, + .pcm_pointer = mtk_adsp_stream_pcm_pointer, + .pcm_close = sof_stream_pcm_close, + + .drv = mt8195_dai, + .num_drv = ARRAY_SIZE(mt8195_dai), + + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, +}; + /* mt8195 ops */ static const struct snd_sof_dsp_ops sof_mt8195_ops = { /* probe and remove */ @@ -498,6 +514,7 @@ static const struct sof_dev_desc sof_of_mt8195_desc = { }, .nocodec_tplg_filename = "sof-mt8195-nocodec.tplg", .ops = &sof_mt8195_ops, + .audio_ops = &sof_mt8195_audio_ops, .ipc_timeout = 1000, }; diff --git a/sound/soc/sof/mediatek/mt8365/mt8365.c b/sound/soc/sof/mediatek/mt8365/mt8365.c index 76a18038b98368..05c6ea7df57d5b 100644 --- a/sound/soc/sof/mediatek/mt8365/mt8365.c +++ b/sound/soc/sof/mediatek/mt8365/mt8365.c @@ -534,6 +534,22 @@ static struct snd_soc_dai_driver mt8365_dai[] = { }, }; +static const struct sof_audio_ops sof_mt8365_audio_ops = { + .pcm_open = sof_stream_pcm_open, + .pcm_hw_params = mt8365_pcm_hw_params, + .pcm_pointer = mt8365_pcm_pointer, + .pcm_close = sof_stream_pcm_close, + + .drv = mt8365_dai, + .num_drv = ARRAY_SIZE(mt8365_dai), + + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, +}; + /* mt8365 ops */ static struct snd_sof_dsp_ops sof_mt8365_ops = { /* probe and remove */ @@ -624,6 +640,7 @@ static const struct sof_dev_desc sof_of_mt8365_desc = { }, .nocodec_tplg_filename = "sof-mt8365-nocodec.tplg", .ops = &sof_mt8365_ops, + .audio_ops = &sof_mt8365_audio_ops, .ipc_timeout = 1000, }; From dfc93b5b5a91d4eb5ad8c42941b8fdd4500fc3f8 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 2 Jun 2026 17:05:59 +0300 Subject: [PATCH 63/83] ASoC: SOF: switch audio dispatch to sof_audio_ops Switch the PCM and compress dispatch functions in ops.h from sof_ops(sdev)->callback to audio_instance->audio_ops->callback pattern. This decouples the audio path from snd_sof_dsp_ops and routes through the sof_audio_ops structure instead. Update core.c to read drv/num_drv from sdev->audio_ops for component registration. Update pcm.c to read hw_info and pcm_pointer from audio_ops. Update intel/hda.c to check audio_ops->pcm_pointer for IPC position mode. The compr_get_dai_frame_counter, pcm_get_dai_frame_counter, and pcm_get_host_byte_counter callbacks are not moved as they take sdev directly and are not part of sof_audio_ops. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/core.c | 7 +-- sound/soc/sof/intel/hda.c | 2 +- sound/soc/sof/ops.h | 95 ++++++++++++++++++++++----------------- sound/soc/sof/pcm.c | 12 ++--- 4 files changed, 66 insertions(+), 50 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index eb773390a28358..d443d2410c131a 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -556,8 +556,8 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) /* now register audio DSP platform driver and dai */ ret = devm_snd_soc_register_component(sdev->dev, &sdev->plat_drv, - sof_ops(sdev)->drv, - sof_ops(sdev)->num_drv); + sdev->audio_ops->drv, + sdev->audio_ops->num_drv); if (ret < 0) { dev_err(sdev->dev, "error: failed to register DSP DAI driver %d\n", ret); @@ -678,13 +678,14 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) sof_apply_profile_override(&plat_data->ipc_file_profile_base, plat_data); + sdev->audio_ops = plat_data->desc->audio_ops; + /* Initialize sof_ops based on the initial selected IPC version */ ret = sof_init_sof_ops(sdev); if (ret) return ret; INIT_LIST_HEAD(&sdev->audio_instance_list); - sdev->audio_ops = plat_data->desc->audio_ops; INIT_LIST_HEAD(&sdev->ipc_client_list); INIT_LIST_HEAD(&sdev->ipc_rx_handler_list); INIT_LIST_HEAD(&sdev->fw_state_handler_list); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 4dbba9186b29d4..ec8309a20985d1 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -822,7 +822,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_FORCE_IPC_POSITION) hdev->no_ipc_position = 0; #else - hdev->no_ipc_position = sof_ops(sdev)->pcm_pointer ? 1 : 0; + hdev->no_ipc_position = sdev->audio_ops && sdev->audio_ops->pcm_pointer ? 1 : 0; #endif if (sdev->dspless_mode_selected) diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index adda98e0262b73..7e2d2c3dfdaf1f 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -427,10 +427,11 @@ static inline int snd_sof_pcm_platform_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + struct snd_sof_audio_instance *ins = + snd_sof_component_get_audio_instance(component); - if (sof_ops(sdev) && sof_ops(sdev)->pcm_open) - return sof_ops(sdev)->pcm_open(component, substream); + if (ins && ins->audio_ops && ins->audio_ops->pcm_open) + return ins->audio_ops->pcm_open(component, substream); return 0; } @@ -440,10 +441,11 @@ static inline int snd_sof_pcm_platform_close(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + struct snd_sof_audio_instance *ins = + snd_sof_component_get_audio_instance(component); - if (sof_ops(sdev) && sof_ops(sdev)->pcm_close) - return sof_ops(sdev)->pcm_close(component, substream); + if (ins && ins->audio_ops && ins->audio_ops->pcm_close) + return ins->audio_ops->pcm_close(component, substream); return 0; } @@ -455,11 +457,12 @@ snd_sof_pcm_platform_hw_params(struct snd_soc_component *component, struct snd_pcm_hw_params *params, struct snd_sof_platform_stream_params *platform_params) { - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + struct snd_sof_audio_instance *ins = + snd_sof_component_get_audio_instance(component); - if (sof_ops(sdev) && sof_ops(sdev)->pcm_hw_params) - return sof_ops(sdev)->pcm_hw_params(component, substream, params, - platform_params); + if (ins && ins->audio_ops && ins->audio_ops->pcm_hw_params) + return ins->audio_ops->pcm_hw_params(component, substream, + params, platform_params); return 0; } @@ -468,10 +471,11 @@ static inline int snd_sof_compr_platform_open(struct snd_soc_component *component, struct snd_compr_stream *cstream) { - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + struct snd_sof_audio_instance *ins = + snd_sof_component_get_audio_instance(component); - if (sof_ops(sdev) && sof_ops(sdev)->compr_open) - return sof_ops(sdev)->compr_open(component, cstream); + if (ins && ins->audio_ops && ins->audio_ops->compr_open) + return ins->audio_ops->compr_open(component, cstream); return 0; } @@ -481,10 +485,11 @@ static inline int snd_sof_compr_platform_close(struct snd_soc_component *component, struct snd_compr_stream *cstream) { - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + struct snd_sof_audio_instance *ins = + snd_sof_component_get_audio_instance(component); - if (sof_ops(sdev) && sof_ops(sdev)->compr_close) - return sof_ops(sdev)->compr_close(component, cstream); + if (ins && ins->audio_ops && ins->audio_ops->compr_close) + return ins->audio_ops->compr_close(component, cstream); return 0; } @@ -496,11 +501,12 @@ snd_sof_compr_platform_hw_params(struct snd_soc_component *component, struct snd_compr_params *params, struct snd_sof_platform_stream_params *platform_params) { - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + struct snd_sof_audio_instance *ins = + snd_sof_component_get_audio_instance(component); - if (sof_ops(sdev) && sof_ops(sdev)->compr_hw_params) - return sof_ops(sdev)->compr_hw_params(component, cstream, params, - platform_params); + if (ins && ins->audio_ops && ins->audio_ops->compr_hw_params) + return ins->audio_ops->compr_hw_params(component, cstream, + params, platform_params); return 0; } @@ -509,10 +515,11 @@ static inline int snd_sof_compr_platform_hw_free(struct snd_soc_component *component, struct snd_compr_stream *cstream) { - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + struct snd_sof_audio_instance *ins = + snd_sof_component_get_audio_instance(component); - if (sof_ops(sdev) && sof_ops(sdev)->compr_hw_free) - return sof_ops(sdev)->compr_hw_free(component, cstream); + if (ins && ins->audio_ops && ins->audio_ops->compr_hw_free) + return ins->audio_ops->compr_hw_free(component, cstream); return 0; } @@ -521,10 +528,11 @@ static inline int snd_sof_compr_platform_trigger(struct snd_soc_component *component, struct snd_compr_stream *cstream, int cmd) { - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + struct snd_sof_audio_instance *ins = + snd_sof_component_get_audio_instance(component); - if (sof_ops(sdev) && sof_ops(sdev)->compr_trigger) - return sof_ops(sdev)->compr_trigger(component, cstream, cmd); + if (ins && ins->audio_ops && ins->audio_ops->compr_trigger) + return ins->audio_ops->compr_trigger(component, cstream, cmd); return 0; } @@ -534,10 +542,11 @@ snd_sof_compr_platform_pointer(struct snd_soc_component *component, struct snd_compr_stream *cstream, struct snd_compr_tstamp64 *tstamp) { - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + struct snd_sof_audio_instance *ins = + snd_sof_component_get_audio_instance(component); - if (sof_ops(sdev) && sof_ops(sdev)->compr_pointer) - return sof_ops(sdev)->compr_pointer(component, cstream, tstamp); + if (ins && ins->audio_ops && ins->audio_ops->compr_pointer) + return ins->audio_ops->compr_pointer(component, cstream, tstamp); return 0; } @@ -557,10 +566,11 @@ static inline int snd_sof_pcm_platform_hw_free(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + struct snd_sof_audio_instance *ins = + snd_sof_component_get_audio_instance(component); - if (sof_ops(sdev) && sof_ops(sdev)->pcm_hw_free) - return sof_ops(sdev)->pcm_hw_free(component, substream); + if (ins && ins->audio_ops && ins->audio_ops->pcm_hw_free) + return ins->audio_ops->pcm_hw_free(component, substream); return 0; } @@ -570,10 +580,11 @@ static inline int snd_sof_pcm_platform_trigger(struct snd_soc_component *component, struct snd_pcm_substream *substream, int cmd) { - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + struct snd_sof_audio_instance *ins = + snd_sof_component_get_audio_instance(component); - if (sof_ops(sdev) && sof_ops(sdev)->pcm_trigger) - return sof_ops(sdev)->pcm_trigger(component, substream, cmd); + if (ins && ins->audio_ops && ins->audio_ops->pcm_trigger) + return ins->audio_ops->pcm_trigger(component, substream, cmd); return 0; } @@ -613,10 +624,11 @@ static inline snd_pcm_uframes_t snd_sof_pcm_platform_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + struct snd_sof_audio_instance *ins = + snd_sof_component_get_audio_instance(component); - if (sof_ops(sdev) && sof_ops(sdev)->pcm_pointer) - return sof_ops(sdev)->pcm_pointer(component, substream); + if (ins && ins->audio_ops && ins->audio_ops->pcm_pointer) + return ins->audio_ops->pcm_pointer(component, substream); return 0; } @@ -625,10 +637,11 @@ snd_sof_pcm_platform_pointer(struct snd_soc_component *component, static inline int snd_sof_pcm_platform_ack(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + struct snd_sof_audio_instance *ins = + snd_sof_component_get_audio_instance(component); - if (sof_ops(sdev) && sof_ops(sdev)->pcm_ack) - return sof_ops(sdev)->pcm_ack(component, substream); + if (ins && ins->audio_ops && ins->audio_ops->pcm_ack) + return ins->audio_ops->pcm_ack(component, substream); return 0; } diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index a6c2725fcf7f15..562b73f536c8ee 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -504,6 +504,8 @@ static snd_pcm_uframes_t sof_pcm_pointer(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_audio_instance *ins = + snd_sof_component_get_audio_instance(component); struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); struct snd_sof_pcm *spcm; @@ -521,8 +523,8 @@ static snd_pcm_uframes_t sof_pcm_pointer(struct snd_soc_component *component, return ret ? ret : host; /* use dsp ops pointer callback directly if set */ - if (sof_ops(sdev)->pcm_pointer) - return sof_ops(sdev)->pcm_pointer(component, substream); + if (ins && ins->audio_ops && ins->audio_ops->pcm_pointer) + return ins->audio_ops->pcm_pointer(component, substream); spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) @@ -544,8 +546,8 @@ static int sof_pcm_open(struct snd_soc_component *component, { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); - const struct snd_sof_dsp_ops *ops = sof_ops(sdev); + struct snd_sof_audio_instance *ins = + snd_sof_component_get_audio_instance(component); struct snd_sof_pcm *spcm; struct snd_soc_tplg_stream_caps *caps; int ret; @@ -563,7 +565,7 @@ static int sof_pcm_open(struct snd_soc_component *component, caps = &spcm->pcm.caps[substream->stream]; /* set runtime config */ - runtime->hw.info = ops->hw_info; /* platform-specific */ + runtime->hw.info = ins->audio_ops->hw_info; /* platform-specific */ /* set any runtime constraints based on topology */ runtime->hw.formats = le64_to_cpu(caps->formats); From 1f236f8c79731ce82ebcc7e2943e9eb25e9ceb0b Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 2 Jun 2026 17:16:34 +0300 Subject: [PATCH 64/83] ASoC: SOF: Intel: remove audio ops from snd_sof_dsp_ops instances Remove the pcm, compress, DAI driver and hw_info fields from all Intel snd_sof_dsp_ops struct instances as these are now provided through the sof_audio_ops structures. Update hda_set_dai_drv_ops() and related functions to access the DAI driver array through sdev->audio_ops instead of the dsp_ops parameter. Update set_mach_params() in atom.c and bdw.c to read drv/num_drv from desc->audio_ops. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/intel/apl.c | 2 +- sound/soc/sof/intel/atom.c | 4 ++-- sound/soc/sof/intel/bdw.c | 19 ++------------- sound/soc/sof/intel/byt.c | 31 ------------------------ sound/soc/sof/intel/cnl.c | 2 +- sound/soc/sof/intel/hda-common-ops.c | 23 ------------------ sound/soc/sof/intel/hda-dai.c | 36 ++++++++++++++-------------- sound/soc/sof/intel/hda.c | 4 ++-- sound/soc/sof/intel/hda.h | 2 +- sound/soc/sof/intel/icl.c | 2 +- sound/soc/sof/intel/mtl.c | 2 +- sound/soc/sof/intel/pci-tng.c | 15 ------------ sound/soc/sof/intel/skl.c | 2 +- sound/soc/sof/intel/tgl.c | 2 +- 14 files changed, 31 insertions(+), 115 deletions(-) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index e5452fa872b805..6579e84f6a25f1 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -80,7 +80,7 @@ int sof_apl_ops_init(struct snd_sof_dev *sdev) } /* set DAI driver ops */ - hda_set_dai_drv_ops(sdev, &sof_apl_ops); + hda_set_dai_drv_ops(sdev); /* debug */ sof_apl_ops.debug_map = apl_dsp_debugfs; diff --git a/sound/soc/sof/intel/atom.c b/sound/soc/sof/intel/atom.c index 32bf5e5e597881..7962c5abbe5c34 100644 --- a/sound/soc/sof/intel/atom.c +++ b/sound/soc/sof/intel/atom.c @@ -407,8 +407,8 @@ void atom_set_mach_params(struct snd_soc_acpi_mach *mach, mach_params = &mach->mach_params; mach_params->platform = dev_name(sdev->dev); - mach_params->num_dai_drivers = desc->ops->num_drv; - mach_params->dai_drivers = desc->ops->drv; + mach_params->num_dai_drivers = desc->audio_ops->num_drv; + mach_params->dai_drivers = desc->audio_ops->drv; } EXPORT_SYMBOL_NS(atom_set_mach_params, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP"); diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 5c2e2975a8b227..f7f4058b57e034 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -530,8 +530,8 @@ static void bdw_set_mach_params(struct snd_soc_acpi_mach *mach, mach_params = &mach->mach_params; mach_params->platform = dev_name(sdev->dev); - mach_params->num_dai_drivers = desc->ops->num_drv; - mach_params->dai_drivers = desc->ops->drv; + mach_params->num_dai_drivers = desc->audio_ops->num_drv; + mach_params->dai_drivers = desc->audio_ops->drv; } /* Broadwell DAIs */ @@ -613,24 +613,9 @@ static const struct snd_sof_dsp_ops sof_bdw_ops = { .dbg_dump = bdw_dump, .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, - /* stream callbacks */ - .pcm_open = sof_stream_pcm_open, - .pcm_close = sof_stream_pcm_close, - /*Firmware loading */ .load_firmware = snd_sof_load_firmware_memcpy, - /* DAI drivers */ - .drv = bdw_dai, - .num_drv = ARRAY_SIZE(bdw_dai), - - /* ALSA HW info flags */ - .hw_info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_BATCH, - .dsp_arch_ops = &sof_xtensa_arch_ops, }; diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 5ce91032027a3f..1e311e774600ae 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -270,10 +270,6 @@ static const struct snd_sof_dsp_ops sof_byt_ops = { .dbg_dump = atom_dump, .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, - /* stream callbacks */ - .pcm_open = sof_stream_pcm_open, - .pcm_close = sof_stream_pcm_close, - /*Firmware loading */ .load_firmware = snd_sof_load_firmware_memcpy, @@ -281,17 +277,6 @@ static const struct snd_sof_dsp_ops sof_byt_ops = { .suspend = byt_suspend, .resume = byt_resume, - /* DAI drivers */ - .drv = atom_dai, - .num_drv = 3, /* we have only 3 SSPs on byt*/ - - /* ALSA HW info flags */ - .hw_info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_BATCH, - .dsp_arch_ops = &sof_xtensa_arch_ops, }; @@ -359,10 +344,6 @@ static const struct snd_sof_dsp_ops sof_cht_ops = { .dbg_dump = atom_dump, .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, - /* stream callbacks */ - .pcm_open = sof_stream_pcm_open, - .pcm_close = sof_stream_pcm_close, - /*Firmware loading */ .load_firmware = snd_sof_load_firmware_memcpy, @@ -370,18 +351,6 @@ static const struct snd_sof_dsp_ops sof_cht_ops = { .suspend = byt_suspend, .resume = byt_resume, - /* DAI drivers */ - .drv = atom_dai, - /* all 6 SSPs may be available for cherrytrail */ - .num_drv = 6, - - /* ALSA HW info flags */ - .hw_info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_BATCH, - .dsp_arch_ops = &sof_xtensa_arch_ops, }; diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 50f0ef2e7b9650..4545af67d92316 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -427,7 +427,7 @@ int sof_cnl_ops_init(struct snd_sof_dev *sdev) } /* set DAI driver ops */ - hda_set_dai_drv_ops(sdev, &sof_cnl_ops); + hda_set_dai_drv_ops(sdev); /* debug */ sof_cnl_ops.debug_map = cnl_dsp_debugfs; diff --git a/sound/soc/sof/intel/hda-common-ops.c b/sound/soc/sof/intel/hda-common-ops.c index 5671f555aaa6c3..89920db60e3002 100644 --- a/sound/soc/sof/intel/hda-common-ops.c +++ b/sound/soc/sof/intel/hda-common-ops.c @@ -76,20 +76,6 @@ const struct snd_sof_dsp_ops sof_hda_common_ops = { .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, /* stream callbacks */ - .pcm_open = hda_dsp_pcm_open, - .pcm_close = hda_dsp_pcm_close, - .pcm_hw_params = hda_dsp_pcm_hw_params, - .pcm_hw_free = hda_dsp_stream_hw_free, - .pcm_trigger = hda_dsp_pcm_trigger, - .pcm_pointer = hda_dsp_pcm_pointer, - .pcm_ack = hda_dsp_pcm_ack, - - .compr_open = hda_dsp_compr_open, - .compr_hw_params = hda_dsp_compr_hw_params, - .compr_hw_free = hda_dsp_stream_compr_hw_free, - .compr_close = hda_dsp_compr_close, - .compr_trigger = hda_dsp_compr_trigger, - .compr_pointer = hda_dsp_compr_pointer, .compr_get_dai_frame_counter = hda_dsp_compr_get_stream_llp, .get_dai_frame_counter = hda_dsp_get_stream_llp, @@ -119,8 +105,6 @@ const struct snd_sof_dsp_ops sof_hda_common_ops = { .unregister_ipc_clients = hda_unregister_clients, /* DAI drivers */ - .drv = skl_dai, - .num_drv = SOF_SKL_NUM_DAIS, .is_chain_dma_supported = hda_is_chain_dma_supported, /* PM */ @@ -131,13 +115,6 @@ const struct snd_sof_dsp_ops sof_hda_common_ops = { .runtime_idle = hda_dsp_runtime_idle, .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume, - /* ALSA HW info flags */ - .hw_info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, - .dsp_arch_ops = &sof_xtensa_arch_ops, }; EXPORT_SYMBOL_NS(sof_hda_common_ops, "SND_SOC_SOF_INTEL_HDA_GENERIC"); diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index bb44d4f8a4da04..b1b2d22fce65de 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -705,7 +705,7 @@ static int hda_dai_suspend(struct hdac_bus *bus) return 0; } -static void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) +static void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev) { const struct sof_intel_dsp_desc *chip; int i; @@ -713,14 +713,14 @@ static void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops chip = get_chip_info(sdev->pdata); if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) { - for (i = 0; i < ops->num_drv; i++) { - if (strstr(ops->drv[i].name, "SSP")) - ops->drv[i].ops = &ssp_dai_ops; + for (i = 0; i < sdev->audio_ops->num_drv; i++) { + if (strstr(sdev->audio_ops->drv[i].name, "SSP")) + sdev->audio_ops->drv[i].ops = &ssp_dai_ops; } } } -static void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) +static void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev) { const struct sof_intel_dsp_desc *chip; int i; @@ -728,35 +728,35 @@ static void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_op chip = get_chip_info(sdev->pdata); if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) { - for (i = 0; i < ops->num_drv; i++) { - if (strstr(ops->drv[i].name, "DMIC")) - ops->drv[i].ops = &dmic_dai_ops; + for (i = 0; i < sdev->audio_ops->num_drv; i++) { + if (strstr(sdev->audio_ops->drv[i].name, "DMIC")) + sdev->audio_ops->drv[i].ops = &dmic_dai_ops; } } } #else -static inline void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {} -static inline void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {} +static inline void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev) {} +static inline void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev) {} #endif /* CONFIG_SND_SOC_SOF_HDA_LINK */ -void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) +void hda_set_dai_drv_ops(struct snd_sof_dev *sdev) { int i; - for (i = 0; i < ops->num_drv; i++) { + for (i = 0; i < sdev->audio_ops->num_drv; i++) { #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) - if (strstr(ops->drv[i].name, "iDisp") || - strstr(ops->drv[i].name, "Analog") || - strstr(ops->drv[i].name, "Digital")) - ops->drv[i].ops = &hda_dai_ops; + if (strstr(sdev->audio_ops->drv[i].name, "iDisp") || + strstr(sdev->audio_ops->drv[i].name, "Analog") || + strstr(sdev->audio_ops->drv[i].name, "Digital")) + sdev->audio_ops->drv[i].ops = &hda_dai_ops; #endif } - ssp_set_dai_drv_ops(sdev, ops); - dmic_set_dai_drv_ops(sdev, ops); + ssp_set_dai_drv_ops(sdev); + dmic_set_dai_drv_ops(sdev); if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4 && !hda_use_tplg_nhlt) { struct sof_ipc4_fw_data *ipc4_data = sdev->private; diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index ec8309a20985d1..c5eb71f92c017d 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1460,8 +1460,8 @@ void hda_set_mach_params(struct snd_soc_acpi_mach *mach, sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC)) mach_params->num_dai_drivers = SOF_SKL_NUM_DAIS_NOCODEC; else - mach_params->num_dai_drivers = desc->ops->num_drv; - mach_params->dai_drivers = desc->ops->drv; + mach_params->num_dai_drivers = desc->audio_ops->num_drv; + mach_params->dai_drivers = desc->audio_ops->drv; } static int check_tplg_quirk_mask(struct snd_soc_acpi_mach *mach) diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index b30de753642fd9..4edb3ac4473a71 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -1029,7 +1029,7 @@ struct sof_ipc_dai_config; extern int sof_hda_position_quirk; -void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops); +void hda_set_dai_drv_ops(struct snd_sof_dev *sdev); void hda_ops_free(struct snd_sof_dev *sdev); /* SKL/KBL */ diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c index b4d211d4f5ecc9..de5d8865b89bb5 100644 --- a/sound/soc/sof/intel/icl.c +++ b/sound/soc/sof/intel/icl.c @@ -162,7 +162,7 @@ int sof_icl_ops_init(struct snd_sof_dev *sdev) sof_icl_ops.core_get = hda_dsp_core_get; /* set DAI driver ops */ - hda_set_dai_drv_ops(sdev, &sof_icl_ops); + hda_set_dai_drv_ops(sdev); return 0; }; diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index f4f39db8a8c5a3..2d362ac5f3cf1c 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -778,7 +778,7 @@ int sof_mtl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops) dsp_ops->set_power_state = hda_dsp_set_power_state_ipc4; /* set DAI ops */ - hda_set_dai_drv_ops(sdev, dsp_ops); + hda_set_dai_drv_ops(sdev); return 0; } diff --git a/sound/soc/sof/intel/pci-tng.c b/sound/soc/sof/intel/pci-tng.c index 1e8960067cb3ff..8d9740d51f4f22 100644 --- a/sound/soc/sof/intel/pci-tng.c +++ b/sound/soc/sof/intel/pci-tng.c @@ -188,24 +188,9 @@ const struct snd_sof_dsp_ops sof_tng_ops = { .dbg_dump = atom_dump, .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, - /* stream callbacks */ - .pcm_open = sof_stream_pcm_open, - .pcm_close = sof_stream_pcm_close, - /*Firmware loading */ .load_firmware = snd_sof_load_firmware_memcpy, - /* DAI drivers */ - .drv = atom_dai, - .num_drv = 3, /* we have only 3 SSPs on byt*/ - - /* ALSA HW info flags */ - .hw_info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_BATCH, - .dsp_arch_ops = &sof_xtensa_arch_ops, }; diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index 3b90ab5e4002ac..aa5cbd431a767d 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -82,7 +82,7 @@ int sof_skl_ops_init(struct snd_sof_dev *sdev) sof_skl_ops.msg_timeout_handler = hda_dsp_ipc4_msg_timeout_handler; /* set DAI driver ops */ - hda_set_dai_drv_ops(sdev, &sof_skl_ops); + hda_set_dai_drv_ops(sdev); /* debug */ sof_skl_ops.debug_map = skl_dsp_debugfs; diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index a46ed8ebbeb21a..5ee5018dba5406 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -121,7 +121,7 @@ int sof_tgl_ops_init(struct snd_sof_dev *sdev) } /* set DAI driver ops */ - hda_set_dai_drv_ops(sdev, &sof_tgl_ops); + hda_set_dai_drv_ops(sdev); /* pre/post fw run */ sof_tgl_ops.post_fw_run = hda_dsp_post_fw_run; From 3785ef4d74a7cbfb4be6d39c67cd7dbd056c236c Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 2 Jun 2026 17:16:42 +0300 Subject: [PATCH 65/83] ASoC: SOF: AMD: remove audio ops from snd_sof_dsp_ops instances Remove the pcm_open, pcm_close, pcm_hw_params, pcm_pointer, drv, num_drv and hw_info fields from the AMD common and per-variant snd_sof_dsp_ops struct instances as these are now provided through the sof_audio_ops structures. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/amd/acp-common.c | 12 ------------ sound/soc/sof/amd/acp63.c | 3 --- sound/soc/sof/amd/acp70.c | 3 --- sound/soc/sof/amd/rembrandt.c | 3 --- sound/soc/sof/amd/renoir.c | 3 --- sound/soc/sof/amd/vangogh.c | 3 --- 6 files changed, 27 deletions(-) diff --git a/sound/soc/sof/amd/acp-common.c b/sound/soc/sof/amd/acp-common.c index 0c3a92f5f942d0..85d823e2497e63 100644 --- a/sound/soc/sof/amd/acp-common.c +++ b/sound/soc/sof/amd/acp-common.c @@ -224,18 +224,6 @@ const struct snd_sof_dsp_ops sof_acp_common_ops = { .get_window_offset = acp_sof_ipc_get_window_offset, .irq_thread = acp_sof_ipc_irq_thread, - /* stream callbacks */ - .pcm_open = acp_pcm_open, - .pcm_close = acp_pcm_close, - .pcm_hw_params = acp_pcm_hw_params, - .pcm_pointer = acp_pcm_pointer, - - .hw_info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, - /* Machine driver callbacks */ .machine_select = amd_sof_machine_select, .machine_register = sof_machine_register, diff --git a/sound/soc/sof/amd/acp63.c b/sound/soc/sof/amd/acp63.c index fcceef47fa8773..10dc2113f45546 100644 --- a/sound/soc/sof/amd/acp63.c +++ b/sound/soc/sof/amd/acp63.c @@ -151,9 +151,6 @@ int sof_acp63_ops_init(struct snd_sof_dev *sdev) /* common defaults */ memcpy(&sof_acp63_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops)); - sof_acp63_ops.drv = acp63_sof_dai; - sof_acp63_ops.num_drv = ARRAY_SIZE(acp63_sof_dai); - sdev->audio_ops = &sof_acp63_audio_ops; return 0; diff --git a/sound/soc/sof/amd/acp70.c b/sound/soc/sof/amd/acp70.c index c87e8a90e3b764..ab9f57048fde82 100644 --- a/sound/soc/sof/amd/acp70.c +++ b/sound/soc/sof/amd/acp70.c @@ -151,9 +151,6 @@ int sof_acp70_ops_init(struct snd_sof_dev *sdev) /* common defaults */ memcpy(&sof_acp70_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops)); - sof_acp70_ops.drv = acp70_sof_dai; - sof_acp70_ops.num_drv = ARRAY_SIZE(acp70_sof_dai); - sdev->audio_ops = &sof_acp70_audio_ops; return 0; diff --git a/sound/soc/sof/amd/rembrandt.c b/sound/soc/sof/amd/rembrandt.c index 9afef5ffd9d57c..50351b4ddf6949 100644 --- a/sound/soc/sof/amd/rembrandt.c +++ b/sound/soc/sof/amd/rembrandt.c @@ -151,9 +151,6 @@ int sof_rembrandt_ops_init(struct snd_sof_dev *sdev) /* common defaults */ memcpy(&sof_rembrandt_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops)); - sof_rembrandt_ops.drv = rembrandt_sof_dai; - sof_rembrandt_ops.num_drv = ARRAY_SIZE(rembrandt_sof_dai); - sdev->audio_ops = &sof_rembrandt_audio_ops; return 0; diff --git a/sound/soc/sof/amd/renoir.c b/sound/soc/sof/amd/renoir.c index 5477081427357c..203bcb3610bdf1 100644 --- a/sound/soc/sof/amd/renoir.c +++ b/sound/soc/sof/amd/renoir.c @@ -126,9 +126,6 @@ int sof_renoir_ops_init(struct snd_sof_dev *sdev) /* common defaults */ memcpy(&sof_renoir_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops)); - sof_renoir_ops.drv = renoir_sof_dai; - sof_renoir_ops.num_drv = ARRAY_SIZE(renoir_sof_dai); - sdev->audio_ops = &sof_renoir_audio_ops; return 0; diff --git a/sound/soc/sof/amd/vangogh.c b/sound/soc/sof/amd/vangogh.c index dd5835bd2bc4ee..9057ed9b39e91c 100644 --- a/sound/soc/sof/amd/vangogh.c +++ b/sound/soc/sof/amd/vangogh.c @@ -175,9 +175,6 @@ int sof_vangogh_ops_init(struct snd_sof_dev *sdev) /* common defaults */ memcpy(&sof_vangogh_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops)); - sof_vangogh_ops.drv = vangogh_sof_dai; - sof_vangogh_ops.num_drv = ARRAY_SIZE(vangogh_sof_dai); - sdev->audio_ops = &sof_vangogh_audio_ops; dmi_id = dmi_first_match(acp_sof_quirk_table); From 22ca17e0a759bfcf46f75ca9797f77614d72396a Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 2 Jun 2026 17:16:51 +0300 Subject: [PATCH 66/83] ASoC: SOF: i.MX: remove audio ops from snd_sof_dsp_ops instances Remove the pcm_open, pcm_close, drv, num_drv and hw_info fields from the i.MX common and per-variant snd_sof_dsp_ops struct instances as these are now provided through the sof_audio_ops structures. Also remove the now-orphaned drv and num_drv fields from the imx_chip_info structure and all its instances. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/imx/imx-common.c | 10 ---------- sound/soc/sof/imx/imx-common.h | 2 -- sound/soc/sof/imx/imx8.c | 12 ------------ sound/soc/sof/imx/imx9.c | 6 ------ 4 files changed, 30 deletions(-) diff --git a/sound/soc/sof/imx/imx-common.c b/sound/soc/sof/imx/imx-common.c index 7a03c8cc5dd473..0b8aa523659ad5 100644 --- a/sound/soc/sof/imx/imx-common.c +++ b/sound/soc/sof/imx/imx-common.c @@ -457,22 +457,12 @@ const struct snd_sof_dsp_ops sof_imx_ops = { .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, - .pcm_open = sof_stream_pcm_open, - .pcm_close = sof_stream_pcm_close, - .runtime_suspend = imx_runtime_suspend, .runtime_resume = imx_runtime_resume, .suspend = imx_suspend, .resume = imx_resume, .set_power_state = imx_set_power_state, - - .hw_info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_BATCH | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, }; EXPORT_SYMBOL(sof_imx_ops); diff --git a/sound/soc/sof/imx/imx-common.h b/sound/soc/sof/imx/imx-common.h index 5b00b191b29661..8c21b3a652d068 100644 --- a/sound/soc/sof/imx/imx-common.h +++ b/sound/soc/sof/imx/imx-common.h @@ -100,8 +100,6 @@ struct imx_chip_info { /* does the chip have a reserved memory region for DMA? */ bool has_dma_reserved; struct imx_memory_info *memory; - struct snd_soc_dai_driver *drv; - int num_drv; const struct sof_audio_ops *audio_ops; /* optional */ const struct imx_chip_ops *ops; diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c index fbf0086f7a5369..12baa41c52413b 100644 --- a/sound/soc/sof/imx/imx8.c +++ b/sound/soc/sof/imx/imx8.c @@ -314,10 +314,6 @@ static int imx8_ops_init(struct snd_sof_dev *sdev) sof_imx8_ops.debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem; - /* ... and finally set DAI driver */ - sof_imx8_ops.drv = get_chip_info(sdev)->drv; - sof_imx8_ops.num_drv = get_chip_info(sdev)->num_drv; - sdev->audio_ops = get_chip_info(sdev)->audio_ops; return 0; @@ -372,8 +368,6 @@ static const struct imx_chip_info imx8_chip_info = { .window_offset = 0x800000, }, .memory = imx8_memory_regions, - .drv = imx8_dai, - .num_drv = ARRAY_SIZE(imx8_dai), .audio_ops = &sof_imx8_audio_ops, .ops = &imx8_chip_ops, }; @@ -385,8 +379,6 @@ static const struct imx_chip_info imx8x_chip_info = { .window_offset = 0x800000, }, .memory = imx8_memory_regions, - .drv = imx8_dai, - .num_drv = ARRAY_SIZE(imx8_dai), .audio_ops = &sof_imx8_audio_ops, .ops = &imx8x_chip_ops, }; @@ -398,8 +390,6 @@ static const struct imx_chip_info imx8m_chip_info = { .window_offset = 0x800000, }, .memory = imx8m_memory_regions, - .drv = imx8m_dai, - .num_drv = ARRAY_SIZE(imx8m_dai), .audio_ops = &sof_imx8m_audio_ops, .ops = &imx8m_chip_ops, }; @@ -412,8 +402,6 @@ static const struct imx_chip_info imx8ulp_chip_info = { }, .has_dma_reserved = true, .memory = imx8ulp_memory_regions, - .drv = imx8ulp_dai, - .num_drv = ARRAY_SIZE(imx8ulp_dai), .audio_ops = &sof_imx8ulp_audio_ops, .ops = &imx8ulp_chip_ops, }; diff --git a/sound/soc/sof/imx/imx9.c b/sound/soc/sof/imx/imx9.c index 6641f282899652..117cbd71bc4bc7 100644 --- a/sound/soc/sof/imx/imx9.c +++ b/sound/soc/sof/imx/imx9.c @@ -34,10 +34,6 @@ static int imx95_ops_init(struct snd_sof_dev *sdev) /* first copy from template */ memcpy(&sof_imx9_ops, &sof_imx_ops, sizeof(sof_imx_ops)); - /* ... and finally set DAI driver */ - sof_imx9_ops.drv = get_chip_info(sdev)->drv; - sof_imx9_ops.num_drv = get_chip_info(sdev)->num_drv; - sdev->audio_ops = get_chip_info(sdev)->audio_ops; return 0; @@ -89,8 +85,6 @@ static const struct imx_chip_info imx95_chip_info = { }, .has_dma_reserved = true, .memory = imx95_memory_regions, - .drv = imx95_dai, - .num_drv = ARRAY_SIZE(imx95_dai), .audio_ops = &sof_imx95_audio_ops, .ops = &imx95_chip_ops, }; From a83b3613bcfcc740346092b3a66abaac59ef248b Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 2 Jun 2026 17:16:59 +0300 Subject: [PATCH 67/83] ASoC: SOF: MediaTek: remove audio ops from snd_sof_dsp_ops instances Remove the pcm_open, pcm_close, pcm_hw_params, pcm_pointer, drv, num_drv and hw_info fields from the MediaTek snd_sof_dsp_ops struct instances as these are now provided through the sof_audio_ops structures. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/mediatek/mt8186/mt8186.c | 20 -------------------- sound/soc/sof/mediatek/mt8195/mt8195.c | 17 ----------------- sound/soc/sof/mediatek/mt8365/mt8365.c | 17 ----------------- 3 files changed, 54 deletions(-) diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c index 0c9ce3d3bfce5f..65b4714a22b818 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186.c @@ -428,22 +428,12 @@ static const struct snd_sof_dsp_ops sof_mt8186_ops = { /* misc */ .get_bar_index = mtk_adsp_get_bar_index, - /* stream callbacks */ - .pcm_open = sof_stream_pcm_open, - .pcm_hw_params = mtk_adsp_stream_pcm_hw_params, - .pcm_pointer = mtk_adsp_stream_pcm_pointer, - .pcm_close = sof_stream_pcm_close, - /* firmware loading */ .load_firmware = snd_sof_load_firmware_memcpy, /* Firmware ops */ .dsp_arch_ops = &sof_xtensa_arch_ops, - /* DAI drivers */ - .drv = mt8186_dai, - .num_drv = ARRAY_SIZE(mt8186_dai), - /* Debug information */ .dbg_dump = mt8186_adsp_dump, .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, @@ -451,13 +441,6 @@ static const struct snd_sof_dsp_ops sof_mt8186_ops = { /* PM */ .suspend = mt8186_dsp_suspend, .resume = mt8186_dsp_resume, - - /* ALSA HW info flags */ - .hw_info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, }; static struct snd_sof_of_mach sof_mt8186_machs[] = { @@ -545,9 +528,6 @@ static int sof_mt8188_ops_init(struct snd_sof_dev *sdev) /* common defaults */ memcpy(&sof_mt8188_ops, &sof_mt8186_ops, sizeof(sof_mt8188_ops)); - sof_mt8188_ops.drv = mt8188_dai; - sof_mt8188_ops.num_drv = ARRAY_SIZE(mt8188_dai); - sdev->audio_ops = &sof_mt8188_audio_ops; return 0; diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 39638f6346ac41..bec41f481dacce 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -452,12 +452,6 @@ static const struct snd_sof_dsp_ops sof_mt8195_ops = { /* misc */ .get_bar_index = mtk_adsp_get_bar_index, - /* stream callbacks */ - .pcm_open = sof_stream_pcm_open, - .pcm_hw_params = mtk_adsp_stream_pcm_hw_params, - .pcm_pointer = mtk_adsp_stream_pcm_pointer, - .pcm_close = sof_stream_pcm_close, - /* firmware loading */ .load_firmware = snd_sof_load_firmware_memcpy, @@ -468,20 +462,9 @@ static const struct snd_sof_dsp_ops sof_mt8195_ops = { .dbg_dump = mt8195_adsp_dump, .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, - /* DAI drivers */ - .drv = mt8195_dai, - .num_drv = ARRAY_SIZE(mt8195_dai), - /* PM */ .suspend = mt8195_dsp_suspend, .resume = mt8195_dsp_resume, - - /* ALSA HW info flags */ - .hw_info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, }; static struct snd_sof_of_mach sof_mt8195_machs[] = { diff --git a/sound/soc/sof/mediatek/mt8365/mt8365.c b/sound/soc/sof/mediatek/mt8365/mt8365.c index 05c6ea7df57d5b..83caf3ae667bae 100644 --- a/sound/soc/sof/mediatek/mt8365/mt8365.c +++ b/sound/soc/sof/mediatek/mt8365/mt8365.c @@ -584,12 +584,6 @@ static struct snd_sof_dsp_ops sof_mt8365_ops = { /* misc */ .get_bar_index = mt8365_get_bar_index, - /* stream callbacks */ - .pcm_open = sof_stream_pcm_open, - .pcm_hw_params = mt8365_pcm_hw_params, - .pcm_pointer = mt8365_pcm_pointer, - .pcm_close = sof_stream_pcm_close, - /* firmware loading */ .load_firmware = snd_sof_load_firmware_memcpy, @@ -600,20 +594,9 @@ static struct snd_sof_dsp_ops sof_mt8365_ops = { .dbg_dump = mt8365_adsp_dump, .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, - /* DAI drivers */ - .drv = mt8365_dai, - .num_drv = ARRAY_SIZE(mt8365_dai), - /* PM */ .suspend = mt8365_dsp_suspend, .resume = mt8365_dsp_resume, - - /* ALSA HW info flags */ - .hw_info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, }; static struct snd_sof_of_mach sof_mt8365_machs[] = { From bdc480c7a15b7d3e453b00a8595ad8b1b2706ff8 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 2 Jun 2026 17:16:22 +0300 Subject: [PATCH 68/83] ASoC: SOF: remove audio ops from struct snd_sof_dsp_ops Remove the pcm_open, pcm_close, pcm_hw_params, pcm_hw_free, pcm_trigger, pcm_pointer, pcm_ack, compr_open, compr_close, compr_hw_params, compr_hw_free, compr_trigger, compr_pointer, drv, num_drv and hw_info fields from struct snd_sof_dsp_ops as these are now provided through struct sof_audio_ops. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/sof-priv.h | 53 ---------------------------------------- 1 file changed, 53 deletions(-) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 5844d4109aeb66..e8b8d2dc6b034e 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -301,52 +301,6 @@ struct snd_sof_dsp_ops { int (*load_module)(struct snd_sof_dev *sof_dev, struct snd_sof_mod_hdr *hdr); /* optional */ - /* connect pcm substream to a host stream */ - int (*pcm_open)(struct snd_soc_component *component, - struct snd_pcm_substream *substream); /* optional */ - /* disconnect pcm substream to a host stream */ - int (*pcm_close)(struct snd_soc_component *component, - struct snd_pcm_substream *substream); /* optional */ - - /* host stream hw params */ - int (*pcm_hw_params)(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_sof_platform_stream_params *platform_params); /* optional */ - - /* host stream hw_free */ - int (*pcm_hw_free)(struct snd_soc_component *component, - struct snd_pcm_substream *substream); /* optional */ - - /* host stream trigger */ - int (*pcm_trigger)(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - int cmd); /* optional */ - - /* host stream pointer */ - snd_pcm_uframes_t (*pcm_pointer)(struct snd_soc_component *component, - struct snd_pcm_substream *substream); /* optional */ - - /* pcm ack */ - int (*pcm_ack)(struct snd_soc_component *component, - struct snd_pcm_substream *substream); /* optional */ - - int (*compr_open)(struct snd_soc_component *component, - struct snd_compr_stream *cstream); - int (*compr_close)(struct snd_soc_component *component, - struct snd_compr_stream *cstream); - int (*compr_hw_params)(struct snd_soc_component *component, - struct snd_compr_stream *cstream, - struct snd_compr_params *params, - struct snd_sof_platform_stream_params *platform_params); - int (*compr_hw_free)(struct snd_soc_component *component, - struct snd_compr_stream *cstream); - int (*compr_trigger)(struct snd_soc_component *component, - struct snd_compr_stream *cstream, - int cmd); - int (*compr_pointer)(struct snd_soc_component *component, - struct snd_compr_stream *cstream, - struct snd_compr_tstamp64 *tstamp); u64 (*compr_get_dai_frame_counter)(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream); /* @@ -442,14 +396,8 @@ struct snd_sof_dsp_ops { void (*unregister_ipc_clients)(struct snd_sof_dev *sdev); /* optional */ /* DAI ops */ - struct snd_soc_dai_driver *drv; - int num_drv; - bool (*is_chain_dma_supported)(struct snd_sof_dev *sdev, u32 dai_type); /* optional */ - /* ALSA HW info flags, will be stored in snd_pcm_runtime.hw.info */ - u32 hw_info; - const struct dsp_arch_ops *dsp_arch_ops; }; @@ -725,7 +673,6 @@ struct snd_sof_dev { struct snd_soc_tplg_ops *tplg_ops; const struct sof_audio_ops *audio_ops; struct list_head audio_instance_list; - /* Protect audio_instance_list */ spinlock_t audio_instance_list_lock; u32 enabled_cores_mask; /* keep track of enabled cores */ bool led_present; From 922503e8c3a855cd1caa3a4228f88a55f6b9b13b Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 3 Jun 2026 12:09:03 +0300 Subject: [PATCH 69/83] ASoC: SOF: sof-client: add dspless mode and num_cores accessors Add sof_client_is_dspless() and sof_client_get_num_cores() accessor functions to the sof-client API. These will be needed by the audio client driver to query DSP state without direct access to snd_sof_dev. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/sof-client.c | 16 ++++++++++++++++ sound/soc/sof/sof-client.h | 3 +++ 2 files changed, 19 insertions(+) diff --git a/sound/soc/sof/sof-client.c b/sound/soc/sof/sof-client.c index 4f3ffceacb5873..e3efb9e467cd57 100644 --- a/sound/soc/sof/sof-client.c +++ b/sound/soc/sof/sof-client.c @@ -705,3 +705,19 @@ void sof_client_mailbox_write(struct sof_client_dev *cdev, u32 offset, sof_mailbox_write(sof_client_dev_to_sof_dev(cdev), offset, message, bytes); } EXPORT_SYMBOL_NS_GPL(sof_client_mailbox_write, "SND_SOC_SOF_CLIENT"); + +bool sof_client_is_dspless(struct sof_client_dev *cdev) +{ + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + + return sdev->dspless_mode_selected; +} +EXPORT_SYMBOL_NS_GPL(sof_client_is_dspless, "SND_SOC_SOF_CLIENT"); + +int sof_client_get_num_cores(struct sof_client_dev *cdev) +{ + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + + return sdev->num_cores; +} +EXPORT_SYMBOL_NS_GPL(sof_client_get_num_cores, "SND_SOC_SOF_CLIENT"); diff --git a/sound/soc/sof/sof-client.h b/sound/soc/sof/sof-client.h index e796801570c823..1e5b830b825438 100644 --- a/sound/soc/sof/sof-client.h +++ b/sound/soc/sof/sof-client.h @@ -84,4 +84,7 @@ void sof_client_mailbox_write(struct sof_client_dev *cdev, u32 offset, ssize_t sof_client_ipc4_find_debug_slot_offset_by_type(struct sof_client_dev *cdev, u32 type); +bool sof_client_is_dspless(struct sof_client_dev *cdev); +int sof_client_get_num_cores(struct sof_client_dev *cdev); + #endif /* __SOC_SOF_CLIENT_H */ From 55757afd931fe9bdf6415b3a5f8e50a394747722 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 3 Jun 2026 12:28:15 +0300 Subject: [PATCH 70/83] ASoC: SOF: pass component_driver to snd_sof_new_platform_drv() Refactor snd_sof_new_platform_drv() to take an explicit snd_soc_component_driver pointer instead of always filling sdev->plat_drv directly. This prepares for the audio sof-client driver which will provide its own component_driver. No functional change. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/core.c | 4 ++-- sound/soc/sof/pcm.c | 4 ++-- sound/soc/sof/sof-priv.h | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index d443d2410c131a..cea3d1af38be18 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -473,7 +473,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) sof_set_fw_state(sdev, SOF_DSPLESS_MODE); /* set up platform component driver */ - snd_sof_new_platform_drv(sdev); + snd_sof_new_platform_drv(sdev, &sdev->plat_drv); goto skip_dsp_init; } @@ -500,7 +500,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) } /* set up platform component driver after initializing the IPC ops */ - snd_sof_new_platform_drv(sdev); + snd_sof_new_platform_drv(sdev, &sdev->plat_drv); /* * skip loading/booting firmware and registering the machine driver when DSP OPS testing diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 562b73f536c8ee..657266e5434948 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -837,9 +837,9 @@ static snd_pcm_sframes_t sof_pcm_delay(struct snd_soc_component *component, return 0; } -void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) +void snd_sof_new_platform_drv(struct snd_sof_dev *sdev, + struct snd_soc_component_driver * const pd) { - struct snd_soc_component_driver *pd = &sdev->plat_drv; struct snd_sof_pdata *plat_data = sdev->pdata; const char *drv_name; diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index e8b8d2dc6b034e..6eef91b418a638 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -755,7 +755,8 @@ int snd_sof_prepare(struct device *dev); void snd_sof_complete(struct device *dev); int snd_sof_boot_dsp_firmware(struct snd_sof_dev *sdev); -void snd_sof_new_platform_drv(struct snd_sof_dev *sdev); +void snd_sof_new_platform_drv(struct snd_sof_dev *sdev, + struct snd_soc_component_driver * const pd); /* * Compress support From cdd7cd67890ce4808bbe7d4936694684474c674a Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 3 Jun 2026 12:29:13 +0300 Subject: [PATCH 71/83] ASoC: SOF: sof-client: add machine register/unregister API Add sof_client_machine_register() and sof_client_machine_unregister() to the sof-client API. These allow client drivers to manage machine driver registration without direct access to snd_sof_dev. The audio sof-client driver will use these to register and unregister the machine driver as part of its lifecycle. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/sof-client.c | 16 ++++++++++++++++ sound/soc/sof/sof-client.h | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/sound/soc/sof/sof-client.c b/sound/soc/sof/sof-client.c index e3efb9e467cd57..39567e3d67b4d4 100644 --- a/sound/soc/sof/sof-client.c +++ b/sound/soc/sof/sof-client.c @@ -721,3 +721,19 @@ int sof_client_get_num_cores(struct sof_client_dev *cdev) return sdev->num_cores; } EXPORT_SYMBOL_NS_GPL(sof_client_get_num_cores, "SND_SOC_SOF_CLIENT"); + +int sof_client_machine_register(struct sof_client_dev *cdev) +{ + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + + return snd_sof_machine_register(sdev, sdev->pdata); +} +EXPORT_SYMBOL_NS_GPL(sof_client_machine_register, "SND_SOC_SOF_CLIENT"); + +void sof_client_machine_unregister(struct sof_client_dev *cdev) +{ + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + + snd_sof_machine_unregister(sdev, sdev->pdata); +} +EXPORT_SYMBOL_NS_GPL(sof_client_machine_unregister, "SND_SOC_SOF_CLIENT"); diff --git a/sound/soc/sof/sof-client.h b/sound/soc/sof/sof-client.h index 1e5b830b825438..cac3bb45d7652b 100644 --- a/sound/soc/sof/sof-client.h +++ b/sound/soc/sof/sof-client.h @@ -87,4 +87,8 @@ ssize_t sof_client_ipc4_find_debug_slot_offset_by_type(struct sof_client_dev *cd bool sof_client_is_dspless(struct sof_client_dev *cdev); int sof_client_get_num_cores(struct sof_client_dev *cdev); +/* machine driver registration */ +int sof_client_machine_register(struct sof_client_dev *cdev); +void sof_client_machine_unregister(struct sof_client_dev *cdev); + #endif /* __SOC_SOF_CLIENT_H */ From 79ec121cf86060e629e4246097bf42a1188e05e7 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 12 Jun 2026 14:32:01 +0300 Subject: [PATCH 72/83] ASoC: SOF: use component/widget device for component-scoped log messages Many log messages in the topology, control, PCM and audio-core paths were printing via sdev->dev even though the context is clearly bound to a specific component (scomp), widget (swidget), route (sroute) or control (scontrol). Logging through sdev->dev in those paths forces all messages to appear under the platform device, making it impossible to distinguish which audio component or pipeline instance triggered a given message. Switch all such messages to use the device that belongs to the available context. Several internal helper functions that received struct snd_sof_dev * solely to reach sdev->dev have also been simplified to derive sdev locally or drop the parameter entirely. sdev->dev is retained where there is no component context yet (e.g. early IPC notification handlers before the widget lookup, platform- level firmware loading, and places where the allocation is tied to the lifetime of sdev rather than the component). Signed-off-by: Peter Ujfalusi --- sound/soc/sof/ipc3-control.c | 12 +- sound/soc/sof/ipc3-topology.c | 50 ++++---- sound/soc/sof/ipc4-compress.c | 11 +- sound/soc/sof/ipc4-control.c | 75 +++++------ sound/soc/sof/ipc4-pcm.c | 17 ++- sound/soc/sof/ipc4-topology.c | 230 ++++++++++++++++++---------------- sound/soc/sof/pcm.c | 4 +- sound/soc/sof/sof-audio.c | 75 ++++++----- sound/soc/sof/topology.c | 44 +++---- 9 files changed, 269 insertions(+), 249 deletions(-) diff --git a/sound/soc/sof/ipc3-control.c b/sound/soc/sof/ipc3-control.c index d0526dda4fdfda..95da9be0188a03 100644 --- a/sound/soc/sof/ipc3-control.c +++ b/sound/soc/sof/ipc3-control.c @@ -34,7 +34,7 @@ static int sof_ipc3_set_get_kcontrol_data(struct snd_sof_control *scontrol, } if (!widget_found) { - dev_err(sdev->dev, "%s: can't find widget with id %d\n", __func__, + dev_err(scontrol->scomp->dev, "%s: can't find widget with id %d\n", __func__, scontrol->comp_id); return -EINVAL; } @@ -604,7 +604,7 @@ static void sof_ipc3_control_update(struct snd_sof_dev *sdev, void *ipc_control_ if (cdata->type == SOF_CTRL_TYPE_VALUE_COMP_GET || cdata->type == SOF_CTRL_TYPE_VALUE_COMP_SET) { dev_err(sdev->dev, "Component data is not supported in control notification\n"); - return; + return; /* swidget not yet found, sdev->dev is correct here */ } /* Find the swidget first */ @@ -631,7 +631,7 @@ static void sof_ipc3_control_update(struct snd_sof_dev *sdev, void *ipc_control_ type = SND_SOC_TPLG_TYPE_ENUM; break; default: - dev_err(sdev->dev, "Unknown cmd %u in %s\n", cdata->cmd, __func__); + dev_err(swidget->scomp->dev, "Unknown cmd %u in %s\n", cdata->cmd, __func__); return; } @@ -694,7 +694,7 @@ static void sof_ipc3_control_update(struct snd_sof_dev *sdev, void *ipc_control_ } if (cdata->rhdr.hdr.size != expected_size) { - dev_err(sdev->dev, "Component notification size mismatch\n"); + dev_err(swidget->scomp->dev, "Component notification size mismatch\n"); return; } @@ -725,7 +725,7 @@ static int sof_ipc3_widget_kcontrol_setup(struct snd_sof_dev *sdev, /* set kcontrol data in DSP */ ret = sof_ipc3_set_get_kcontrol_data(scontrol, true, false); if (ret < 0) { - dev_err(sdev->dev, + dev_err(swidget->scomp->dev, "kcontrol %d set up failed for widget %s\n", scontrol->comp_id, swidget->widget->name); return ret; @@ -742,7 +742,7 @@ static int sof_ipc3_widget_kcontrol_setup(struct snd_sof_dev *sdev, ret = sof_ipc3_set_get_kcontrol_data(scontrol, false, false); if (ret < 0) - dev_warn(sdev->dev, + dev_warn(swidget->scomp->dev, "kcontrol %d read failed for widget %s\n", scontrol->comp_id, swidget->widget->name); } diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index 07d8188726b9f1..c58d324007230f 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -1567,7 +1567,6 @@ static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget) { struct snd_soc_component *scomp = swidget->scomp; struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_sof_dai *dai = swidget->private; struct sof_dai_private_data *private; struct sof_ipc_comp_dai *comp_dai; @@ -1609,7 +1608,7 @@ static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget) /* Subtract the base to match the FW dai index. */ if (comp_dai->type == SOF_DAI_INTEL_ALH) { if (comp_dai->dai_index < INTEL_ALH_DAI_INDEX_BASE) { - dev_err(sdev->dev, + dev_err(scomp->dev, "Invalid ALH dai index %d, only Pin numbers >= %d can be used\n", comp_dai->dai_index, INTEL_ALH_DAI_INDEX_BASE); ret = -EINVAL; @@ -1743,6 +1742,7 @@ static void sof_ipc3_widget_free_comp_dai(struct snd_sof_widget *swidget) static int sof_ipc3_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute) { + struct snd_soc_component *scomp = sroute->scomp; struct sof_ipc_pipe_comp_connect connect; int ret; @@ -1751,33 +1751,34 @@ static int sof_ipc3_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route * connect.source_id = sroute->src_widget->comp_id; connect.sink_id = sroute->sink_widget->comp_id; - dev_dbg(sdev->dev, "setting up route %s -> %s\n", + dev_dbg(scomp->dev, "setting up route %s -> %s\n", sroute->src_widget->widget->name, sroute->sink_widget->widget->name); /* send ipc */ ret = sof_ipc_tx_message_no_reply(sdev->ipc, &connect, sizeof(connect)); if (ret < 0) - dev_err(sdev->dev, "%s: route %s -> %s failed\n", __func__, + dev_err(scomp->dev, "%s: route %s -> %s failed\n", __func__, sroute->src_widget->widget->name, sroute->sink_widget->widget->name); return ret; } -static int sof_ipc3_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) +static int sof_ipc3_control_load_bytes(struct snd_sof_control *scontrol) { + struct snd_soc_component *scomp = scontrol->scomp; struct sof_ipc_ctrl_data *cdata; size_t priv_size_check; int ret; if (scontrol->max_size < (sizeof(*cdata) + sizeof(struct sof_abi_hdr))) { - dev_err(sdev->dev, "%s: insufficient size for a bytes control: %zu.\n", + dev_err(scomp->dev, "%s: insufficient size for a bytes control: %zu.\n", __func__, scontrol->max_size); return -EINVAL; } if (scontrol->priv_size > scontrol->max_size - sizeof(*cdata)) { - dev_err(sdev->dev, + dev_err(scomp->dev, "%s: bytes data size %zu exceeds max %zu.\n", __func__, scontrol->priv_size, scontrol->max_size - sizeof(*cdata)); return -EINVAL; @@ -1799,13 +1800,13 @@ static int sof_ipc3_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_ scontrol->priv = NULL; if (cdata->data->magic != SOF_ABI_MAGIC) { - dev_err(sdev->dev, "Wrong ABI magic 0x%08x.\n", cdata->data->magic); + dev_err(scomp->dev, "Wrong ABI magic 0x%08x.\n", cdata->data->magic); ret = -EINVAL; goto err; } if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) { - dev_err(sdev->dev, "Incompatible ABI version 0x%08x.\n", + dev_err(scomp->dev, "Incompatible ABI version 0x%08x.\n", cdata->data->abi); ret = -EINVAL; goto err; @@ -1813,7 +1814,7 @@ static int sof_ipc3_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_ priv_size_check = cdata->data->size + sizeof(struct sof_abi_hdr); if (priv_size_check != scontrol->priv_size) { - dev_err(sdev->dev, "Conflict in bytes (%zu) vs. priv size (%zu).\n", + dev_err(scomp->dev, "Conflict in bytes (%zu) vs. priv size (%zu).\n", priv_size_check, scontrol->priv_size); ret = -EINVAL; goto err; @@ -1885,7 +1886,7 @@ static int sof_ipc3_control_setup(struct snd_sof_dev *sdev, struct snd_sof_contr case SND_SOC_TPLG_CTL_VOLSW_XR_SX: return sof_ipc3_control_load_volume(sdev, scontrol); case SND_SOC_TPLG_CTL_BYTES: - return sof_ipc3_control_load_bytes(sdev, scontrol); + return sof_ipc3_control_load_bytes(scontrol); case SND_SOC_TPLG_CTL_ENUM: case SND_SOC_TPLG_CTL_ENUM_VALUE: return sof_ipc3_control_load_enum(sdev, scontrol); @@ -2094,10 +2095,11 @@ static int sof_ipc3_widget_bind_event(struct snd_soc_component *scomp, static int sof_ipc3_complete_pipeline(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) { + struct snd_soc_component *scomp = swidget->scomp; struct sof_ipc_pipe_ready ready; int ret; - dev_dbg(sdev->dev, "tplg: complete pipeline %s id %d\n", + dev_dbg(scomp->dev, "tplg: complete pipeline %s id %d\n", swidget->widget->name, swidget->comp_id); memset(&ready, 0, sizeof(ready)); @@ -2142,7 +2144,8 @@ static int sof_ipc3_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget ret = sof_ipc_tx_message_no_reply(sdev->ipc, &ipc_free, sizeof(ipc_free)); if (ret < 0) - dev_err(sdev->dev, "failed to free widget %s\n", swidget->widget->name); + dev_err(swidget->scomp->dev, "failed to free widget %s\n", + swidget->widget->name); return ret; } @@ -2157,19 +2160,21 @@ static int sof_ipc3_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget * int ret = 0; if (!dai || !dai->private) { - dev_err(sdev->dev, "No private data for DAI %s\n", swidget->widget->name); + dev_err(swidget->scomp->dev, "No private data for DAI %s\n", + swidget->widget->name); return -EINVAL; } private = dai->private; if (!private->dai_config) { - dev_err(sdev->dev, "No config for DAI %s\n", dai->name); + dev_err(swidget->scomp->dev, "No config for DAI %s\n", dai->name); return -EINVAL; } config = &private->dai_config[dai->current_config]; if (!config) { - dev_err(sdev->dev, "Invalid current config for DAI %s\n", dai->name); + dev_err(swidget->scomp->dev, "Invalid current config for DAI %s\n", + dai->name); return -EINVAL; } @@ -2194,7 +2199,7 @@ static int sof_ipc3_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget * if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) { /* Subtract the base to match the FW dai index. */ if (data->dai_index < INTEL_ALH_DAI_INDEX_BASE) { - dev_err(sdev->dev, + dev_err(swidget->scomp->dev, "Invalid ALH dai index %d, only Pin numbers >= %d can be used\n", config->dai_index, INTEL_ALH_DAI_INDEX_BASE); return -EINVAL; @@ -2240,7 +2245,8 @@ static int sof_ipc3_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget * if (swidget->use_count > 0) { ret = sof_ipc_tx_message_no_reply(sdev->ipc, config, config->hdr.size); if (ret < 0) - dev_err(sdev->dev, "Failed to set dai config for %s\n", dai->name); + dev_err(swidget->scomp->dev, "Failed to set dai config for %s\n", + dai->name); /* clear the flags once the IPC has been sent even if it fails */ config->flags = SOF_DAI_CONFIG_FLAGS_NONE; @@ -2285,7 +2291,8 @@ static int sof_ipc3_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget } } if (ret < 0) - dev_err(sdev->dev, "Failed to setup widget %s\n", swidget->widget->name); + dev_err(swidget->scomp->dev, "Failed to setup widget %s\n", + swidget->widget->name); return ret; } @@ -2358,7 +2365,7 @@ static int sof_ipc3_set_up_all_pipelines(struct snd_sof_dev *sdev, bool verify) ret = sof_route_setup(sdev, sroute->src_widget->widget, sroute->sink_widget->widget); if (ret < 0) { - dev_err(sdev->dev, "%s: route set up failed\n", __func__); + dev_err(sroute->scomp->dev, "%s: route set up failed\n", __func__); return ret; } } @@ -2516,7 +2523,8 @@ static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif */ for_each_swidget_in_instances(swidget, sdev, instance) { if (swidget->use_count != 0) { - dev_err(sdev->dev, "%s: widget %s is still in use: count %d\n", + dev_err(swidget->scomp->dev, + "%s: widget %s is still in use: count %d\n", __func__, swidget->widget->name, swidget->use_count); } } diff --git a/sound/soc/sof/ipc4-compress.c b/sound/soc/sof/ipc4-compress.c index 079e0a39cf47a5..9b00c969c6a964 100644 --- a/sound/soc/sof/ipc4-compress.c +++ b/sound/soc/sof/ipc4-compress.c @@ -395,7 +395,7 @@ static int sof_ipc4_compr_set_params(struct snd_soc_component *component, interval->min = compr_params->codec.sample_rate; interval->max = compr_params->codec.sample_rate; - ret = sof_ipc4_compr_alloc_pages(sdev->dev, &spcm->stream[dir], + ret = sof_ipc4_compr_alloc_pages(component->dev, &spcm->stream[dir], component, cstream); if (ret < 0) return ret; @@ -500,7 +500,6 @@ static int sof_ipc4_compr_get_params(struct snd_soc_component *component, struct snd_compr_stream *cstream, struct snd_codec *params) { - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_sof_pcm *spcm; /* TODO: we don't query the supported codecs for now, if the @@ -508,7 +507,7 @@ static int sof_ipc4_compr_get_params(struct snd_soc_component *component, */ spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) { - dev_err(sdev->dev, "%s: can't find spcm\n", __func__); + dev_err(component->dev, "%s: can't find spcm\n", __func__); return -EINVAL; } @@ -533,7 +532,7 @@ static int sof_ipc4_compr_trigger(struct snd_soc_component *component, spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) { - dev_err(sdev->dev, "%s: can't find spcm\n", __func__); + dev_err(component->dev, "%s: can't find spcm\n", __func__); return -EINVAL; } @@ -738,7 +737,7 @@ void sof_ipc4_compr_drain_done(struct snd_sof_dev *sdev, void *ipc_message) } if (!widget_found) { - dev_err(sdev->dev, "%s: Host widget not found for pipeline: %s\n", + dev_err(swidget->scomp->dev, "%s: Host widget not found for pipeline: %s\n", __func__, swidget->spipe->pipe_widget->widget->name); return; } @@ -746,7 +745,7 @@ void sof_ipc4_compr_drain_done(struct snd_sof_dev *sdev, void *ipc_message) /* Look up the spcm of the host copier */ spcm = snd_sof_find_spcm_comp_by_sdev(sdev, host_swidget->comp_id, &dir); if (!spcm) { - dev_err(sdev->dev, "%s: Stream cannot be found for %s\n", __func__, + dev_err(host_swidget->scomp->dev, "%s: Stream cannot be found for %s\n", __func__, host_swidget->widget->name); return; } diff --git a/sound/soc/sof/ipc4-control.c b/sound/soc/sof/ipc4-control.c index 1876c7c2de9c5e..de485f382b4d06 100644 --- a/sound/soc/sof/ipc4-control.c +++ b/sound/soc/sof/ipc4-control.c @@ -82,9 +82,9 @@ static int sof_ipc4_set_get_kcontrol_data(struct snd_sof_control *scontrol, return ret; } -static int -sof_ipc4_set_volume_data(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, - struct snd_sof_control *scontrol, bool lock) +static int sof_ipc4_set_volume_data(struct snd_sof_widget *swidget, + struct snd_sof_control *scontrol, + bool lock) { struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; struct sof_ipc4_gain *gain = swidget->private; @@ -127,7 +127,7 @@ sof_ipc4_set_volume_data(struct snd_sof_dev *sdev, struct snd_sof_widget *swidge ret = sof_ipc4_set_get_kcontrol_data(scontrol, &msg, true, lock); if (ret < 0) { - dev_err(sdev->dev, "Failed to set volume update for %s\n", + dev_err(swidget->scomp->dev, "Failed to set volume update for %s\n", scontrol->name); return ret; } @@ -145,7 +145,6 @@ static bool sof_ipc4_volume_put(struct snd_sof_control *scontrol, struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); unsigned int channels = scontrol->num_channels; struct snd_sof_widget *swidget; bool widget_found = false; @@ -179,7 +178,7 @@ static bool sof_ipc4_volume_put(struct snd_sof_control *scontrol, return false; } - ret = sof_ipc4_set_volume_data(sdev, swidget, scontrol, true); + ret = sof_ipc4_set_volume_data(swidget, scontrol, true); if (ret < 0) return false; @@ -201,10 +200,9 @@ static int sof_ipc4_volume_get(struct snd_sof_control *scontrol, return 0; } -static int -sof_ipc4_set_generic_control_data(struct snd_sof_dev *sdev, - struct snd_sof_widget *swidget, - struct snd_sof_control *scontrol, bool lock) +static int sof_ipc4_set_generic_control_data(struct snd_sof_widget *swidget, + struct snd_sof_control *scontrol, + bool lock) { struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; struct sof_ipc4_control_msg_payload *data; @@ -231,7 +229,7 @@ sof_ipc4_set_generic_control_data(struct snd_sof_dev *sdev, ret = sof_ipc4_set_get_kcontrol_data(scontrol, &msg, true, lock); if (ret < 0) - dev_err(sdev->dev, "Failed to set control update for %s\n", + dev_err(scontrol->scomp->dev, "Failed to set control update for %s\n", scontrol->name); kfree(data); @@ -386,7 +384,6 @@ static bool sof_ipc4_switch_put(struct snd_sof_control *scontrol, struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_sof_widget *swidget; bool widget_found = false; bool change = false; @@ -418,7 +415,7 @@ static bool sof_ipc4_switch_put(struct snd_sof_control *scontrol, return false; } - ret = sof_ipc4_set_generic_control_data(sdev, swidget, scontrol, true); + ret = sof_ipc4_set_generic_control_data(swidget, scontrol, true); if (ret < 0) return false; @@ -446,7 +443,6 @@ static bool sof_ipc4_enum_put(struct snd_sof_control *scontrol, struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_sof_widget *swidget; bool widget_found = false; bool change = false; @@ -478,7 +474,7 @@ static bool sof_ipc4_enum_put(struct snd_sof_control *scontrol, return false; } - ret = sof_ipc4_set_generic_control_data(sdev, swidget, scontrol, true); + ret = sof_ipc4_set_generic_control_data(swidget, scontrol, true); if (ret < 0) return false; @@ -500,22 +496,22 @@ static int sof_ipc4_enum_get(struct snd_sof_control *scontrol, return 0; } -static int sof_ipc4_set_get_bytes_data(struct snd_sof_dev *sdev, - struct snd_sof_control *scontrol, +static int sof_ipc4_set_get_bytes_data(struct snd_sof_control *scontrol, bool set, bool lock) { struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; + struct snd_soc_component *scomp = scontrol->scomp; struct sof_abi_hdr *data = cdata->data; struct sof_ipc4_msg msg; int ret = 0; /* Send the new data to the firmware only if it is powered up */ if (set) { - if (!pm_runtime_active(sdev->dev)) + if (!pm_runtime_active(scomp->dev)) return 0; if (!data->size) { - dev_dbg(sdev->dev, "%s: No data to be sent.\n", + dev_dbg(scomp->dev, "%s: No data to be sent.\n", scontrol->name); return 0; } @@ -539,7 +535,7 @@ static int sof_ipc4_set_get_bytes_data(struct snd_sof_dev *sdev, ret = sof_ipc4_set_get_kcontrol_data(scontrol, &msg, set, lock); if (ret < 0) { - dev_err(sdev->dev, "Failed to %s for %s\n", + dev_err(scomp->dev, "Failed to %s for %s\n", set ? "set bytes update" : "get bytes", scontrol->name); } else if (!set) { @@ -556,7 +552,6 @@ static int sof_ipc4_bytes_put(struct snd_sof_control *scontrol, { struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; struct snd_soc_component *scomp = scontrol->scomp; - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct sof_abi_hdr *data = cdata->data; const struct sof_abi_hdr *new_hdr = (const struct sof_abi_hdr *)ucontrol->value.bytes.data; @@ -584,7 +579,7 @@ static int sof_ipc4_bytes_put(struct snd_sof_control *scontrol, /* copy from kcontrol */ memcpy(data, ucontrol->value.bytes.data, size); - ret = sof_ipc4_set_get_bytes_data(sdev, scontrol, true, true); + ret = sof_ipc4_set_get_bytes_data(scontrol, true, true); if (!ret) /* Update the cdata size */ scontrol->size = sizeof(*cdata) + size; @@ -630,7 +625,6 @@ static int sof_ipc4_bytes_ext_put(struct snd_sof_control *scontrol, struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data; struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; struct snd_soc_component *scomp = scontrol->scomp; - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct sof_abi_hdr *data = cdata->data; struct sof_abi_hdr abi_hdr; struct snd_ctl_tlv header; @@ -704,7 +698,7 @@ static int sof_ipc4_bytes_ext_put(struct snd_sof_control *scontrol, /* Update the cdata size */ scontrol->size = sizeof(*cdata) + header.length; - return sof_ipc4_set_get_bytes_data(sdev, scontrol, true, true); + return sof_ipc4_set_get_bytes_data(scontrol, true, true); } static int _sof_ipc4_bytes_ext_get(struct snd_sof_control *scontrol, @@ -729,8 +723,7 @@ static int _sof_ipc4_bytes_ext_get(struct snd_sof_control *scontrol, /* get all the component data from DSP */ if (from_dsp) { - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); - int ret = sof_ipc4_set_get_bytes_data(sdev, scontrol, false, true); + int ret = sof_ipc4_set_get_bytes_data(scontrol, false, true); if (ret < 0) return ret; @@ -781,14 +774,14 @@ static int sof_ipc4_bytes_ext_volatile_get(struct snd_sof_control *scontrol, return _sof_ipc4_bytes_ext_get(scontrol, binary_data, size, true); } -static int -sof_ipc4_volsw_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, - struct snd_sof_control *scontrol) +static int sof_ipc4_volsw_setup(struct snd_sof_widget *swidget, + struct snd_sof_control *scontrol) + { if (scontrol->max == 1) - return sof_ipc4_set_generic_control_data(sdev, swidget, scontrol, false); + return sof_ipc4_set_generic_control_data(swidget, scontrol, false); - return sof_ipc4_set_volume_data(sdev, swidget, scontrol, false); + return sof_ipc4_set_volume_data(swidget, scontrol, false); } #define PARAM_ID_FROM_EXTENSION(_ext) (((_ext) & SOF_IPC4_MOD_EXT_MSG_PARAM_ID_MASK) \ @@ -867,7 +860,7 @@ static void sof_ipc4_control_update(struct snd_sof_dev *sdev, void *ipc_message) } if (!scontrol_found) { - dev_err(sdev->dev, + dev_err(swidget->scomp->dev, "%s: Failed to find control on widget %s: %u:%u\n", __func__, swidget->widget->name, ndata->event_id & 0xffff, msg_data->id); @@ -884,7 +877,7 @@ static void sof_ipc4_control_update(struct snd_sof_dev *sdev, void *ipc_message) size_t source_size = struct_size(msg_data, data, msg_data->num_elems); if (source_size > ndata->event_data_size) { - dev_warn(sdev->dev, + dev_warn(swidget->scomp->dev, "%s: invalid bytes notification size for %s (%zu, %u)\n", __func__, scontrol->name, source_size, ndata->event_data_size); @@ -893,7 +886,7 @@ static void sof_ipc4_control_update(struct snd_sof_dev *sdev, void *ipc_message) } if (msg_data->num_elems > scontrol->max_size - sizeof(*data)) { - dev_warn(sdev->dev, + dev_warn(swidget->scomp->dev, "%s: no space for data in %s (%u, %zu)\n", __func__, scontrol->name, msg_data->num_elems, scontrol->max_size - sizeof(*data)); @@ -906,7 +899,7 @@ static void sof_ipc4_control_update(struct snd_sof_dev *sdev, void *ipc_message) size_t source_size = struct_size(msg_data, chanv, msg_data->num_elems); if (source_size > ndata->event_data_size) { - dev_warn(sdev->dev, + dev_warn(swidget->scomp->dev, "%s: invalid channel notification size for %s (%zu, %u)\n", __func__, scontrol->name, source_size, ndata->event_data_size); @@ -918,7 +911,7 @@ static void sof_ipc4_control_update(struct snd_sof_dev *sdev, void *ipc_message) u32 channel = msg_data->chanv[i].channel; if (channel >= scontrol->num_channels) { - dev_warn(sdev->dev, + dev_warn(swidget->scomp->dev, "Invalid channel index for %s: %u\n", scontrol->name, i); @@ -978,23 +971,21 @@ static int sof_ipc4_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_s case SND_SOC_TPLG_CTL_VOLSW: case SND_SOC_TPLG_CTL_VOLSW_SX: case SND_SOC_TPLG_CTL_VOLSW_XR_SX: - ret = sof_ipc4_volsw_setup(sdev, swidget, scontrol); + ret = sof_ipc4_volsw_setup(swidget, scontrol); break; case SND_SOC_TPLG_CTL_BYTES: - ret = sof_ipc4_set_get_bytes_data(sdev, scontrol, - true, false); + ret = sof_ipc4_set_get_bytes_data(scontrol, true, false); break; case SND_SOC_TPLG_CTL_ENUM: case SND_SOC_TPLG_CTL_ENUM_VALUE: - ret = sof_ipc4_set_generic_control_data(sdev, swidget, - scontrol, false); + ret = sof_ipc4_set_generic_control_data(swidget, scontrol, false); break; default: break; } if (ret < 0) { - dev_err(sdev->dev, + dev_err(swidget->scomp->dev, "kcontrol %d set up failed for widget %s\n", scontrol->comp_id, swidget->widget->name); return ret; diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 88606523808096..9ac2c68768f865 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -636,7 +636,6 @@ static int ipc4_ssp_dai_config_pcm_params_match(struct snd_soc_component *compon struct snd_pcm_hw_params *params) { struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(component); - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); struct snd_sof_dai_link *slink; struct snd_sof_dai *dai; bool dai_link_found = false; @@ -681,13 +680,13 @@ static int ipc4_ssp_dai_config_pcm_params_match(struct snd_soc_component *compon } if (current_config < 0) { - dev_err(sdev->dev, + dev_err(component->dev, "%s: No suitable hw_config found for %s (num_hw_configs: %d)\n", __func__, slink->link->name, slink->num_hw_configs); return -EINVAL; } - dev_dbg(sdev->dev, + dev_dbg(component->dev, "hw_config for %s: %d (num_hw_configs: %d) with %s match\n", slink->link->name, current_config, slink->num_hw_configs, partial_match ? "partial" : "full"); @@ -702,7 +701,7 @@ static int ipc4_ssp_dai_config_pcm_params_match(struct snd_soc_component *compon * Fixup DAI link parameters for sampling rate based on * DAI copier configuration. */ -static int sof_ipc4_pcm_dai_link_fixup_rate(struct snd_sof_dev *sdev, +static int sof_ipc4_pcm_dai_link_fixup_rate(struct snd_soc_component *component, struct snd_pcm_hw_params *params, struct sof_ipc4_copier *ipc4_copier) { @@ -743,7 +742,7 @@ static int sof_ipc4_pcm_dai_link_fixup_rate(struct snd_sof_dev *sdev, */ if (!fe_be_rate_match) { if (!single_be_rate) { - dev_err(sdev->dev, "Unable to select sampling rate for DAI link\n"); + dev_err(component->dev, "Unable to select sampling rate for DAI link\n"); return -EINVAL; } @@ -754,7 +753,7 @@ static int sof_ipc4_pcm_dai_link_fixup_rate(struct snd_sof_dev *sdev, return 0; } -static int sof_ipc4_pcm_dai_link_fixup_channels(struct snd_sof_dev *sdev, +static int sof_ipc4_pcm_dai_link_fixup_channels(struct snd_soc_component *component, struct snd_pcm_hw_params *params, struct sof_ipc4_copier *ipc4_copier) { @@ -795,7 +794,7 @@ static int sof_ipc4_pcm_dai_link_fixup_channels(struct snd_sof_dev *sdev, */ if (!fe_be_match) { if (!single_be_channels) { - dev_err(sdev->dev, "Unable to select channels for DAI link\n"); + dev_err(component->dev, "Unable to select channels for DAI link\n"); return -EINVAL; } @@ -865,11 +864,11 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, } } - ret = sof_ipc4_pcm_dai_link_fixup_rate(sdev, params, ipc4_copier); + ret = sof_ipc4_pcm_dai_link_fixup_rate(component, params, ipc4_copier); if (ret) return ret; - ret = sof_ipc4_pcm_dai_link_fixup_channels(sdev, params, ipc4_copier); + ret = sof_ipc4_pcm_dai_link_fixup_channels(component, params, ipc4_copier); if (ret) return ret; diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 97d6a47e7d468f..fe9dd298dfbbc6 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -568,7 +568,7 @@ static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget) if (swidget->module_info) return 0; - dev_err(sdev->dev, "failed to find module info for widget %s with UUID %pUL\n", + dev_err(scomp->dev, "failed to find module info for widget %s with UUID %pUL\n", swidget->widget->name, &swidget->uuid); return -EINVAL; } @@ -1382,9 +1382,11 @@ static void sof_ipc4_widget_free_comp_process(struct snd_sof_widget *swidget) } static void -sof_ipc4_update_resource_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, +sof_ipc4_update_resource_usage(struct snd_sof_widget *swidget, struct sof_ipc4_base_module_cfg *base_config) { + struct snd_soc_component *scomp = swidget->scomp; + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct sof_ipc4_fw_module *fw_module = swidget->module_info; struct snd_sof_widget *pipe_widget; struct sof_ipc4_pipeline *pipeline; @@ -1419,26 +1421,26 @@ sof_ipc4_update_resource_usage(struct snd_sof_dev *sdev, struct snd_sof_widget * sof_ipc4_update_cpc_from_manifest(sdev, fw_module, base_config); if (ignore_cpc) { - dev_dbg(sdev->dev, "%s: ibs / obs: %u / %u, forcing cpc to 0 from %u\n", + dev_dbg(scomp->dev, "%s: ibs / obs: %u / %u, forcing cpc to 0 from %u\n", swidget->widget->name, base_config->ibs, base_config->obs, base_config->cpc); base_config->cpc = 0; } else { - dev_dbg(sdev->dev, "%s: ibs / obs / cpc: %u / %u / %u\n", + dev_dbg(scomp->dev, "%s: ibs / obs / cpc: %u / %u / %u\n", swidget->widget->name, base_config->ibs, base_config->obs, base_config->cpc); } } -static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev, - struct snd_sof_widget *swidget) +static int sof_ipc4_widget_assign_instance_id(struct snd_sof_widget *swidget) { + struct snd_soc_component *scomp = swidget->scomp; struct sof_ipc4_fw_module *fw_module = swidget->module_info; int max_instances = fw_module->man4_module_entry.instance_max_count; swidget->instance_id = ida_alloc_max(&fw_module->m_ida, max_instances, GFP_KERNEL); if (swidget->instance_id < 0) { - dev_err(sdev->dev, "failed to assign instance id for widget %s", + dev_err(scomp->dev, "failed to assign instance id for widget %s", swidget->widget->name); return swidget->instance_id; } @@ -1447,7 +1449,8 @@ static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev, } /* update hw_params based on the audio stream format */ -static int sof_ipc4_update_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params, +static int sof_ipc4_update_hw_params(struct snd_soc_component *scomp, + struct snd_pcm_hw_params *params, struct sof_ipc4_audio_format *fmt, u32 param_to_update) { struct snd_interval *i; @@ -1471,7 +1474,7 @@ static int sof_ipc4_update_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_hw snd_fmt = SNDRV_PCM_FORMAT_U8; break; default: - dev_err(sdev->dev, "Unsupported PCM 8-bit IPC4 type %d\n", type); + dev_err(scomp->dev, "Unsupported PCM 8-bit IPC4 type %d\n", type); return -EINVAL; } break; @@ -1490,12 +1493,12 @@ static int sof_ipc4_update_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_hw snd_fmt = SNDRV_PCM_FORMAT_FLOAT_LE; break; default: - dev_err(sdev->dev, "Unsupported PCM 32-bit IPC4 type %d\n", type); + dev_err(scomp->dev, "Unsupported PCM 32-bit IPC4 type %d\n", type); return -EINVAL; } break; default: - dev_err(sdev->dev, "invalid PCM valid_bits %d\n", valid_bits); + dev_err(scomp->dev, "invalid PCM valid_bits %d\n", valid_bits); return -EINVAL; } @@ -1523,8 +1526,8 @@ static int sof_ipc4_update_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_hw return 0; } -static bool sof_ipc4_is_single_format(struct snd_sof_dev *sdev, - struct sof_ipc4_pin_format *pin_fmts, u32 pin_fmts_size) +static bool sof_ipc4_is_single_format(struct sof_ipc4_pin_format *pin_fmts, + u32 pin_fmts_size) { struct sof_ipc4_audio_format *fmt; u32 rate, channels, valid_bits; @@ -1551,25 +1554,25 @@ static bool sof_ipc4_is_single_format(struct snd_sof_dev *sdev, return true; } -static int sof_ipc4_init_output_audio_fmt(struct snd_sof_dev *sdev, - struct snd_sof_widget *swidget, +static int sof_ipc4_init_output_audio_fmt(struct snd_sof_widget *swidget, struct sof_ipc4_base_module_cfg *base_config, struct sof_ipc4_available_audio_format *available_fmt, u32 out_ref_rate, u32 out_ref_channels, u32 out_ref_valid_bits, u32 out_ref_type) { + struct snd_soc_component *scomp = swidget->scomp; struct sof_ipc4_pin_format *pin_fmts = available_fmt->output_pin_fmts; u32 pin_fmts_size = available_fmt->num_output_formats; bool single_format; int i = 0; if (!pin_fmts_size) { - dev_err(sdev->dev, "no output formats for %s\n", + dev_err(scomp->dev, "no output formats for %s\n", swidget->widget->name); return -EINVAL; } - single_format = sof_ipc4_is_single_format(sdev, pin_fmts, pin_fmts_size); + single_format = sof_ipc4_is_single_format(pin_fmts, pin_fmts_size); /* pick the first format if there's only one available or if all formats are the same */ if (single_format) @@ -1594,7 +1597,7 @@ static int sof_ipc4_init_output_audio_fmt(struct snd_sof_dev *sdev, goto out_fmt; } - dev_err(sdev->dev, + dev_err(scomp->dev, "%s: Unsupported audio format: %uHz, %ubit, %u channels, type: %d\n", __func__, out_ref_rate, out_ref_valid_bits, out_ref_channels, out_ref_type); @@ -1607,7 +1610,8 @@ static int sof_ipc4_init_output_audio_fmt(struct snd_sof_dev *sdev, return i; } -static int sof_ipc4_get_valid_bits(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params) +static int sof_ipc4_get_valid_bits(struct snd_soc_component *scomp, + struct snd_pcm_hw_params *params) { switch (params_format(params)) { case SNDRV_PCM_FORMAT_U8: @@ -1623,12 +1627,13 @@ static int sof_ipc4_get_valid_bits(struct snd_sof_dev *sdev, struct snd_pcm_hw_p case SNDRV_PCM_FORMAT_FLOAT_LE: return 32; default: - dev_err(sdev->dev, "invalid pcm frame format %d\n", params_format(params)); + dev_err(scomp->dev, "invalid pcm frame format %d\n", params_format(params)); return -EINVAL; } } -static int sof_ipc4_get_sample_type(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params) +static int sof_ipc4_get_sample_type(struct snd_soc_component *scomp, + struct snd_pcm_hw_params *params) { switch (params_format(params)) { case SNDRV_PCM_FORMAT_A_LAW: @@ -1645,17 +1650,17 @@ static int sof_ipc4_get_sample_type(struct snd_sof_dev *sdev, struct snd_pcm_hw_ case SNDRV_PCM_FORMAT_FLOAT_LE: return SOF_IPC4_TYPE_FLOAT; default: - dev_err(sdev->dev, "invalid pcm sample type %d\n", params_format(params)); + dev_err(scomp->dev, "invalid pcm sample type %d\n", params_format(params)); return -EINVAL; } } -static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev, - struct snd_sof_widget *swidget, +static int sof_ipc4_init_input_audio_fmt(struct snd_sof_widget *swidget, struct sof_ipc4_base_module_cfg *base_config, struct snd_pcm_hw_params *params, struct sof_ipc4_available_audio_format *available_fmt) { + struct snd_soc_component *scomp = swidget->scomp; struct sof_ipc4_pin_format *pin_fmts = available_fmt->input_pin_fmts; u32 pin_fmts_size = available_fmt->num_input_formats; u32 valid_bits; @@ -1667,15 +1672,15 @@ static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev, int i = 0; if (!pin_fmts_size) { - dev_err(sdev->dev, "no input formats for %s\n", swidget->widget->name); + dev_err(scomp->dev, "no input formats for %s\n", swidget->widget->name); return -EINVAL; } - sample_valid_bits = sof_ipc4_get_valid_bits(sdev, params); + sample_valid_bits = sof_ipc4_get_valid_bits(scomp, params); if (sample_valid_bits < 0) return sample_valid_bits; - sample_type = sof_ipc4_get_sample_type(sdev, params); + sample_type = sof_ipc4_get_sample_type(scomp, params); if (sample_type < 0) return sample_type; @@ -1698,7 +1703,7 @@ static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev, goto in_fmt; } - dev_err(sdev->dev, + dev_err(scomp->dev, "%s: Unsupported audio format: %uHz, %ubit, %u channels, type: %d\n", __func__, params_rate(params), sample_valid_bits, params_channels(params), sample_type); @@ -1992,7 +1997,7 @@ bool sof_ipc4_copier_is_single_bitdepth(struct snd_sof_dev *sdev, } static int -sof_ipc4_adjust_params_to_dai_format(struct snd_sof_dev *sdev, +sof_ipc4_adjust_params_to_dai_format(struct snd_soc_component *scomp, struct snd_pcm_hw_params *params, struct sof_ipc4_pin_format *pin_fmts, u32 pin_fmts_size) @@ -2033,7 +2038,7 @@ sof_ipc4_adjust_params_to_dai_format(struct snd_sof_dev *sdev, } if (params_mask) - return sof_ipc4_update_hw_params(sdev, params, + return sof_ipc4_update_hw_params(scomp, params, &pin_fmts[0].audio_fmt, params_mask); @@ -2070,7 +2075,7 @@ sof_ipc4_prepare_dai_copier(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, num_pin_fmts = available_fmt->num_input_formats; } - ret = sof_ipc4_adjust_params_to_dai_format(sdev, &dai_params, pin_fmts, + ret = sof_ipc4_adjust_params_to_dai_format(dai->scomp, &dai_params, pin_fmts, num_pin_fmts); if (ret) return ret; @@ -2090,16 +2095,18 @@ sof_ipc4_prepare_dai_copier(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, return ret; } -static void sof_ipc4_host_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, +static void sof_ipc4_host_config(struct snd_sof_dev *sdev, + struct snd_sof_widget *swidget, struct snd_sof_platform_stream_params *platform_params) { + struct snd_soc_component *scomp = swidget->scomp; struct sof_ipc4_copier *ipc4_copier = (struct sof_ipc4_copier *)swidget->private; struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; struct sof_ipc4_copier_data *copier_data = &ipc4_copier->data; struct sof_ipc4_pipeline *pipeline = pipe_widget->private; u32 host_dma_id = platform_params->stream_tag - 1; - dev_dbg(sdev->dev, "Host copier %s, type %d, ChainDMA: %s, stream_tag: %d\n", + dev_dbg(scomp->dev, "Host copier %s, type %d, ChainDMA: %s, stream_tag: %d\n", swidget->widget->name, swidget->id, str_yes_no(pipeline->use_chain_dma), platform_params->stream_tag); @@ -2118,7 +2125,6 @@ sof_ipc4_copier_module_update_params(struct snd_sof_widget *swidget, struct snd_pcm_hw_params *pipeline_params) { struct snd_soc_component *scomp = swidget->scomp; - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct sof_ipc4_copier_data *copier_data; struct sof_ipc4_copier *ipc4_copier; @@ -2147,13 +2153,13 @@ sof_ipc4_copier_module_update_params(struct snd_sof_widget *swidget, break; } default: - dev_err(sdev->dev, "unsupported type %d for copier %s", + dev_err(scomp->dev, "unsupported type %d for copier %s", swidget->id, swidget->widget->name); return -EINVAL; } /* modify the input params for the next widget */ - return sof_ipc4_update_hw_params(sdev, pipeline_params, + return sof_ipc4_update_hw_params(scomp, pipeline_params, &copier_data->out_format, BIT(SNDRV_PCM_HW_PARAM_FORMAT) | BIT(SNDRV_PCM_HW_PARAM_CHANNELS) | @@ -2194,7 +2200,7 @@ _sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, struct sof_ipc4_pipeline *pipeline = pipe_widget->private; struct sof_ipc4_gtw_attributes *gtw_attr; - dev_dbg(sdev->dev, + dev_dbg(scomp->dev, "Host copier %s, type %d, ChainDMA: %s, stream_tag: %d\n", swidget->widget->name, swidget->id, str_yes_no(pipeline->use_chain_dma), @@ -2273,7 +2279,7 @@ _sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; struct sof_ipc4_pipeline *pipeline = pipe_widget->private; - dev_dbg(sdev->dev, "Dai copier %s, type %d, ChainDMA: %s\n", + dev_dbg(scomp->dev, "Dai copier %s, type %d, ChainDMA: %s\n", swidget->widget->name, swidget->id, str_yes_no(pipeline->use_chain_dma)); @@ -2317,7 +2323,7 @@ _sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, } case snd_soc_dapm_buffer: { - dev_dbg(sdev->dev, "Module copier %s, type %d\n", + dev_dbg(scomp->dev, "Module copier %s, type %d\n", swidget->widget->name, swidget->id); ipc4_copier = (struct sof_ipc4_copier *)swidget->private; @@ -2331,13 +2337,13 @@ _sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, break; } default: - dev_err(sdev->dev, "unsupported type %d for copier %s", + dev_err(scomp->dev, "unsupported type %d for copier %s", swidget->id, swidget->widget->name); return -EINVAL; } /* set input and output audio formats */ - input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, + input_fmt_index = sof_ipc4_init_input_audio_fmt(swidget, &copier_data->base_config, ref_params, available_fmt); if (input_fmt_index < 0) @@ -2386,13 +2392,13 @@ _sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, out_ref_rate = params_rate(ref_params); out_ref_channels = params_channels(ref_params); - ret = sof_ipc4_get_sample_type(sdev, ref_params); + ret = sof_ipc4_get_sample_type(scomp, ref_params); if (ret < 0) return ret; out_ref_type = (u32)ret; if (!single_output_bitdepth) { - out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, ref_params); + out_ref_valid_bits = sof_ipc4_get_valid_bits(scomp, ref_params); if (out_ref_valid_bits < 0) return out_ref_valid_bits; } @@ -2418,7 +2424,7 @@ _sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, out_ref_type = sof_ipc4_fmt_cfg_to_type(out_fmt->fmt_cfg); } - output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget, + output_fmt_index = sof_ipc4_init_output_audio_fmt(swidget, &copier_data->base_config, available_fmt, out_ref_rate, out_ref_channels, out_ref_valid_bits, @@ -2552,7 +2558,7 @@ _sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, } /* modify the input params for the next widget */ - ret = sof_ipc4_update_hw_params(sdev, pipeline_params, + ret = sof_ipc4_update_hw_params(scomp, pipeline_params, &copier_data->out_format, BIT(SNDRV_PCM_HW_PARAM_FORMAT) | BIT(SNDRV_PCM_HW_PARAM_CHANNELS) | @@ -2574,7 +2580,7 @@ _sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, copier_data->gtw_cfg.dma_buffer_size = max((u32)SOF_IPC4_MIN_DMA_BUFFER_SIZE, deep_buffer_dma_ms) * copier_data->base_config.ibs; - dev_dbg(sdev->dev, "copier %s, dma buffer%s: %u ms (%u bytes)", + dev_dbg(scomp->dev, "copier %s, dma buffer%s: %u ms (%u bytes)", swidget->widget->name, deep_buffer_dma_ms ? " (using Deep Buffer)" : "", max((u32)SOF_IPC4_MIN_DMA_BUFFER_SIZE, deep_buffer_dma_ms), @@ -2588,7 +2594,7 @@ _sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, copier_data->gtw_cfg.dma_buffer_size = max((u32)SOF_IPC4_MIN_DMA_BUFFER_SIZE, deep_buffer_dma_ms) * copier_data->base_config.obs; - dev_dbg(sdev->dev, "copier %s, dma buffer%s: %u ms (%u bytes)", + dev_dbg(scomp->dev, "copier %s, dma buffer%s: %u ms (%u bytes)", swidget->widget->name, deep_buffer_dma_ms ? " (using Deep Buffer)" : "", max((u32)SOF_IPC4_MIN_DMA_BUFFER_SIZE, deep_buffer_dma_ms), @@ -2624,7 +2630,7 @@ _sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, copier_data->gtw_cfg.config_length += dma_config_tlv_size / 4; } - dev_dbg(sdev->dev, "copier %s, IPC size is %d", swidget->widget->name, ipc_size); + dev_dbg(scomp->dev, "copier %s, IPC size is %d", swidget->widget->name, ipc_size); *ipc_config_data = kzalloc(ipc_size, GFP_KERNEL); if (!*ipc_config_data) @@ -2632,11 +2638,11 @@ _sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, *ipc_config_size = ipc_size; - sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt, + sof_ipc4_dbg_module_audio_format(scomp->dev, swidget, available_fmt, input_fmt_index, output_fmt_index); /* update pipeline memory usage */ - sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config); + sof_ipc4_update_resource_usage(swidget, &copier_data->base_config); /* copy IPC data */ memcpy(*ipc_config_data, (void *)copier_data, sizeof(*copier_data)); @@ -2680,7 +2686,6 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget, struct snd_pcm_hw_params *pipeline_params, int dir) { struct snd_soc_component *scomp = swidget->scomp; - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct sof_ipc4_gain *gain = swidget->private; struct sof_ipc4_available_audio_format *available_fmt = &gain->available_fmt; struct sof_ipc4_audio_format *in_fmt; @@ -2691,7 +2696,7 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget, if (unlikely(swidget->prepared)) return 0; - input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, + input_fmt_index = sof_ipc4_init_input_audio_fmt(swidget, &gain->data.base_config, pipeline_params, available_fmt); @@ -2704,7 +2709,7 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget, out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); out_ref_type = sof_ipc4_fmt_cfg_to_type(in_fmt->fmt_cfg); - output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget, + output_fmt_index = sof_ipc4_init_output_audio_fmt(swidget, &gain->data.base_config, available_fmt, out_ref_rate, @@ -2714,11 +2719,11 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget, if (output_fmt_index < 0) return output_fmt_index; - sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt, + sof_ipc4_dbg_module_audio_format(scomp->dev, swidget, available_fmt, input_fmt_index, output_fmt_index); /* update pipeline memory usage */ - sof_ipc4_update_resource_usage(sdev, swidget, &gain->data.base_config); + sof_ipc4_update_resource_usage(swidget, &gain->data.base_config); return 0; } @@ -2729,7 +2734,6 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget, struct snd_pcm_hw_params *pipeline_params, int dir) { struct snd_soc_component *scomp = swidget->scomp; - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct sof_ipc4_mixer *mixer = swidget->private; struct sof_ipc4_available_audio_format *available_fmt = &mixer->available_fmt; struct sof_ipc4_audio_format *in_fmt; @@ -2740,7 +2744,7 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget, if (swidget->prepared) return 0; - input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, + input_fmt_index = sof_ipc4_init_input_audio_fmt(swidget, &mixer->base_config, pipeline_params, available_fmt); @@ -2753,7 +2757,7 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget, out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); out_ref_type = sof_ipc4_fmt_cfg_to_type(in_fmt->fmt_cfg); - output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget, + output_fmt_index = sof_ipc4_init_output_audio_fmt(swidget, &mixer->base_config, available_fmt, out_ref_rate, @@ -2763,11 +2767,11 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget, if (output_fmt_index < 0) return output_fmt_index; - sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt, + sof_ipc4_dbg_module_audio_format(scomp->dev, swidget, available_fmt, input_fmt_index, output_fmt_index); /* update pipeline memory usage */ - sof_ipc4_update_resource_usage(sdev, swidget, &mixer->base_config); + sof_ipc4_update_resource_usage(swidget, &mixer->base_config); return 0; } @@ -2778,7 +2782,6 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, struct snd_pcm_hw_params *pipeline_params, int dir) { struct snd_soc_component *scomp = swidget->scomp; - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct sof_ipc4_src *src = swidget->private; struct sof_ipc4_available_audio_format *available_fmt = &src->available_fmt; struct sof_ipc4_audio_format *out_audio_fmt; @@ -2790,7 +2793,7 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, if (unlikely(swidget->prepared)) return 0; - input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, + input_fmt_index = sof_ipc4_init_input_audio_fmt(swidget, &src->data.base_config, pipeline_params, available_fmt); @@ -2829,7 +2832,7 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, for (i = 1; i < available_fmt->num_output_formats; i++) { out_audio_fmt = &available_fmt->output_pin_fmts[i].audio_fmt; if (out_ref_rate != out_audio_fmt->sampling_frequency) { - dev_err(sdev->dev, + dev_err(scomp->dev, "Cannot determine the output rate for SRC: %s\n", swidget->widget->name); return -EINVAL; @@ -2837,7 +2840,7 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, } } - output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget, + output_fmt_index = sof_ipc4_init_output_audio_fmt(swidget, &src->data.base_config, available_fmt, out_ref_rate, @@ -2847,17 +2850,17 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, if (output_fmt_index < 0) return output_fmt_index; - sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt, + sof_ipc4_dbg_module_audio_format(scomp->dev, swidget, available_fmt, input_fmt_index, output_fmt_index); /* update pipeline memory usage */ - sof_ipc4_update_resource_usage(sdev, swidget, &src->data.base_config); + sof_ipc4_update_resource_usage(swidget, &src->data.base_config); out_audio_fmt = &available_fmt->output_pin_fmts[output_fmt_index].audio_fmt; src->data.sink_rate = out_audio_fmt->sampling_frequency; /* update pipeline_params for sink widgets */ - return sof_ipc4_update_hw_params(sdev, pipeline_params, out_audio_fmt, + return sof_ipc4_update_hw_params(scomp, pipeline_params, out_audio_fmt, BIT(SNDRV_PCM_HW_PARAM_FORMAT) | BIT(SNDRV_PCM_HW_PARAM_CHANNELS) | BIT(SNDRV_PCM_HW_PARAM_RATE)); @@ -2947,7 +2950,6 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget, struct snd_pcm_hw_params *pipeline_params, int dir) { struct snd_soc_component *scomp = swidget->scomp; - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct sof_ipc4_process *process = swidget->private; struct sof_ipc4_available_audio_format *available_fmt = &process->available_fmt; void *cfg = process->ipc_config_data; @@ -2961,14 +2963,14 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget, return 0; /* modify the pipeline params with the output format */ - return sof_ipc4_update_hw_params(sdev, pipeline_params, + return sof_ipc4_update_hw_params(scomp, pipeline_params, &process->output_format, BIT(SNDRV_PCM_HW_PARAM_FORMAT) | BIT(SNDRV_PCM_HW_PARAM_CHANNELS) | BIT(SNDRV_PCM_HW_PARAM_RATE)); } - input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, + input_fmt_index = sof_ipc4_init_input_audio_fmt(swidget, &process->base_config, pipeline_params, available_fmt); @@ -3011,12 +3013,12 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget, /* for modules without input formats, use FE params as reference */ ref_rate = params_rate(fe_params); ref_channels = params_channels(fe_params); - ret = sof_ipc4_get_sample_type(sdev, fe_params); + ret = sof_ipc4_get_sample_type(scomp, fe_params); if (ret < 0) return ret; ref_type = (u32)ret; - ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params); + ref_valid_bits = sof_ipc4_get_valid_bits(scomp, fe_params); if (ref_valid_bits < 0) return ref_valid_bits; } @@ -3027,16 +3029,16 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget, if (available_fmt->changed_params & BIT(SNDRV_PCM_HW_PARAM_CHANNELS)) ref_channels = params_channels(fe_params); if (available_fmt->changed_params & BIT(SNDRV_PCM_HW_PARAM_FORMAT)) { - ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params); + ref_valid_bits = sof_ipc4_get_valid_bits(scomp, fe_params); if (ref_valid_bits < 0) return ref_valid_bits; - ref_type = sof_ipc4_get_sample_type(sdev, fe_params); + ref_type = sof_ipc4_get_sample_type(scomp, fe_params); if (ref_type < 0) return ref_type; } } - output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget, + output_fmt_index = sof_ipc4_init_output_audio_fmt(swidget, &process->base_config, available_fmt, ref_rate, @@ -3054,7 +3056,7 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget, sizeof(struct sof_ipc4_audio_format)); /* modify the pipeline params with the output format */ - ret = sof_ipc4_update_hw_params(sdev, pipeline_params, + ret = sof_ipc4_update_hw_params(scomp, pipeline_params, &process->output_format, available_fmt->changed_params); if (ret) @@ -3072,11 +3074,11 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget, } } - sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt, + sof_ipc4_dbg_module_audio_format(scomp->dev, swidget, available_fmt, input_fmt_index, output_fmt_index); /* update pipeline memory usage */ - sof_ipc4_update_resource_usage(sdev, swidget, &process->base_config); + sof_ipc4_update_resource_usage(swidget, &process->base_config); /* ipc_config_data is composed of the base_config followed by an optional extension */ memcpy(cfg, &process->base_config, sizeof(struct sof_ipc4_base_module_cfg)); @@ -3167,8 +3169,9 @@ static int sof_ipc4_control_load_enum(struct snd_sof_dev *sdev, struct snd_sof_c return 0; } -static int sof_ipc4_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) +static int sof_ipc4_control_load_bytes(struct snd_sof_control *scontrol) { + struct snd_soc_component *scomp = scontrol->scomp; struct sof_ipc4_control_data *control_data; struct sof_ipc4_msg *msg; int ret; @@ -3179,21 +3182,21 @@ static int sof_ipc4_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_ * 'struct sof_ipc4_control_data' */ if (scontrol->max_size < sizeof(struct sof_abi_hdr)) { - dev_err(sdev->dev, + dev_err(scomp->dev, "insufficient maximum size for a bytes control %s: %zu.\n", scontrol->name, scontrol->max_size); return -EINVAL; } if (scontrol->priv_size > scontrol->max_size) { - dev_err(sdev->dev, + dev_err(scomp->dev, "bytes control %s initial data size %zu exceeds max %zu.\n", scontrol->name, scontrol->priv_size, scontrol->max_size); return -EINVAL; } if (scontrol->priv_size && scontrol->priv_size < sizeof(struct sof_abi_hdr)) { - dev_err(sdev->dev, + dev_err(scomp->dev, "bytes control %s initial data size %zu is insufficient.\n", scontrol->name, scontrol->priv_size); return -EINVAL; @@ -3219,7 +3222,7 @@ static int sof_ipc4_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_ scontrol->priv = NULL; if (control_data->data->magic != SOF_IPC4_ABI_MAGIC) { - dev_err(sdev->dev, "Wrong ABI magic (%#x) for control: %s\n", + dev_err(scomp->dev, "Wrong ABI magic (%#x) for control: %s\n", control_data->data->magic, scontrol->name); ret = -EINVAL; goto err; @@ -3229,7 +3232,7 @@ static int sof_ipc4_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_ if (control_data->data->size + sizeof(struct sof_abi_hdr) != scontrol->priv_size) { - dev_err(sdev->dev, "Control %s conflict in bytes %zu vs. priv size %zu.\n", + dev_err(scomp->dev, "Control %s conflict in bytes %zu vs. priv size %zu.\n", scontrol->name, control_data->data->size + sizeof(struct sof_abi_hdr), scontrol->priv_size); @@ -3260,7 +3263,7 @@ static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_contr case SND_SOC_TPLG_CTL_VOLSW_XR_SX: return sof_ipc4_control_load_volume(sdev, scontrol); case SND_SOC_TPLG_CTL_BYTES: - return sof_ipc4_control_load_bytes(sdev, scontrol); + return sof_ipc4_control_load_bytes(scontrol); case SND_SOC_TPLG_CTL_ENUM: case SND_SOC_TPLG_CTL_ENUM_VALUE: return sof_ipc4_control_load_enum(sdev, scontrol); @@ -3307,6 +3310,7 @@ static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev, void *ipc_data, u32 ipc_size, void **new_data) { + struct snd_soc_component *scomp = swidget->scomp; struct sof_ipc4_mod_init_ext_dp_memory_data *dp_mem_data; struct sof_ipc4_module_init_ext_init *ext_init; struct sof_ipc4_module_init_ext_object *hdr = NULL; @@ -3353,7 +3357,7 @@ static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev, /* Calculate final size and check that it fits to max payload size */ new_size = ext_pos * sizeof(u32) + ipc_size; if (new_size > sdev->ipc->max_payload_size) { - dev_err(sdev->dev, "Max ipc payload size %zu exceeded: %u", + dev_err(scomp->dev, "Max ipc payload size %zu exceeded: %u", sdev->ipc->max_payload_size, new_size); kfree(payload); return -EINVAL; @@ -3373,6 +3377,7 @@ static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev, static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) { + struct snd_soc_component *scomp = swidget->scomp; struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; struct sof_ipc4_fw_data *ipc4_data = sdev->private; struct sof_ipc4_pipeline *pipeline; @@ -3387,12 +3392,12 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget pipeline = swidget->private; if (pipeline->use_chain_dma) { - dev_warn(sdev->dev, "use_chain_dma set for scheduler %s", + dev_warn(scomp->dev, "use_chain_dma set for scheduler %s", swidget->widget->name); return 0; } - dev_dbg(sdev->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id, + dev_dbg(scomp->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id, pipeline->mem_usage); msg = &pipeline->msg; @@ -3401,7 +3406,7 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget swidget->instance_id = ida_alloc_max(&pipeline_ida, ipc4_data->max_num_pipelines, GFP_KERNEL); if (swidget->instance_id < 0) { - dev_err(sdev->dev, "failed to assign pipeline id for %s: %d\n", + dev_err(scomp->dev, "failed to assign pipeline id for %s: %d\n", swidget->widget->name, swidget->instance_id); return swidget->instance_id; } @@ -3520,7 +3525,7 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget struct sof_ipc4_process *process = swidget->private; if (!process->ipc_config_size) { - dev_err(sdev->dev, "module %s has no config data!\n", + dev_err(scomp->dev, "module %s has no config data!\n", swidget->widget->name); return -EINVAL; } @@ -3532,16 +3537,16 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget break; } default: - dev_err(sdev->dev, "widget type %d not supported", swidget->id); + dev_err(scomp->dev, "widget type %d not supported", swidget->id); return -EINVAL; } if (swidget->id != snd_soc_dapm_scheduler) { int module_id = msg->primary & SOF_IPC4_MOD_ID_MASK; - ret = sof_ipc4_widget_assign_instance_id(sdev, swidget); + ret = sof_ipc4_widget_assign_instance_id(swidget); if (ret < 0) { - dev_err(sdev->dev, "failed to assign instance id for %s\n", + dev_err(scomp->dev, "failed to assign instance id for %s\n", swidget->widget->name); return ret; } @@ -3555,7 +3560,7 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget msg->extension &= ~SOF_IPC4_MOD_EXT_PPL_ID_MASK; msg->extension |= SOF_IPC4_MOD_EXT_PPL_ID(pipe_widget->instance_id); - dev_dbg(sdev->dev, "Create widget %s (pipe %d) - ID %d, instance %d, core %d\n", + dev_dbg(scomp->dev, "Create widget %s (pipe %d) - ID %d, instance %d, core %d\n", swidget->widget->name, swidget->pipeline_id, module_id, swidget->instance_id, swidget->core); @@ -3569,7 +3574,7 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget ipc_data = ext_data; } } else { - dev_dbg(sdev->dev, "Create pipeline %s (pipe %d) - instance %d, core %d\n", + dev_dbg(scomp->dev, "Create pipeline %s (pipe %d) - instance %d, core %d\n", swidget->widget->name, swidget->pipeline_id, swidget->instance_id, swidget->core); } @@ -3581,7 +3586,7 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget fail: if (ret < 0) { - dev_err(sdev->dev, "failed to create module %s\n", swidget->widget->name); + dev_err(scomp->dev, "failed to create module %s\n", swidget->widget->name); if (swidget->id != snd_soc_dapm_scheduler) { struct sof_ipc4_fw_module *fw_module = swidget->module_info; @@ -3598,6 +3603,7 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) { + struct snd_soc_component *scomp = swidget->scomp; struct sof_ipc4_fw_module *fw_module = swidget->module_info; struct sof_ipc4_fw_data *ipc4_data = sdev->private; int ret = 0; @@ -3611,7 +3617,7 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget u32 header; if (pipeline->use_chain_dma) { - dev_warn(sdev->dev, "use_chain_dma set for scheduler %s", + dev_warn(scomp->dev, "use_chain_dma set for scheduler %s", swidget->widget->name); return 0; } @@ -3625,7 +3631,7 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0); if (ret < 0) - dev_err(sdev->dev, "failed to free pipeline widget %s\n", + dev_err(scomp->dev, "failed to free pipeline widget %s\n", swidget->widget->name); pipeline->mem_usage = 0; @@ -3730,6 +3736,7 @@ static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev, struct snd_sof_widget *sink_widget, struct snd_sof_route *sroute) { + struct snd_soc_component *scomp = sroute->scomp; struct sof_ipc4_copier_config_set_sink_format format; const struct sof_ipc_ops *iops = sdev->ipc->ops; struct sof_ipc4_base_module_cfg *src_config; @@ -3752,7 +3759,7 @@ static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev, pin_fmt = sof_ipc4_get_input_pin_audio_fmt(sink_widget, sroute->dst_queue_id); if (!pin_fmt) { - dev_err(sdev->dev, + dev_err(scomp->dev, "Failed to get input audio format of %s:%d for output of %s:%d\n", sink_widget->widget->name, sroute->dst_queue_id, src_widget->widget->name, sroute->src_queue_id); @@ -3777,6 +3784,7 @@ static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev, static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute) { + struct snd_soc_component *scomp = sroute->scomp; struct snd_sof_widget *src_widget = sroute->src_widget; struct snd_sof_widget *sink_widget = sroute->sink_widget; struct snd_sof_widget *src_pipe_widget = src_widget->spipe->pipe_widget; @@ -3792,7 +3800,7 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route * /* no route set up if chain DMA is used */ if (src_pipeline->use_chain_dma || sink_pipeline->use_chain_dma) { if (!src_pipeline->use_chain_dma || !sink_pipeline->use_chain_dma) { - dev_err(sdev->dev, + dev_err(scomp->dev, "use_chain_dma must be set for both src %s and sink %s pipelines\n", src_widget->widget->name, sink_widget->widget->name); return -EINVAL; @@ -3801,7 +3809,7 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route * } if (!src_fw_module || !sink_fw_module) { - dev_err(sdev->dev, + dev_err(scomp->dev, "cannot bind %s -> %s, no firmware module for: %s%s\n", src_widget->widget->name, sink_widget->widget->name, src_fw_module ? "" : " source", @@ -3813,7 +3821,7 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route * sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget, SOF_PIN_TYPE_OUTPUT); if (sroute->src_queue_id < 0) { - dev_err(sdev->dev, + dev_err(scomp->dev, "failed to get src_queue_id ID from source widget %s\n", src_widget->widget->name); return sroute->src_queue_id; @@ -3822,7 +3830,7 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route * sroute->dst_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget, SOF_PIN_TYPE_INPUT); if (sroute->dst_queue_id < 0) { - dev_err(sdev->dev, + dev_err(scomp->dev, "failed to get dst_queue_id ID from sink widget %s\n", sink_widget->widget->name); sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, @@ -3835,14 +3843,14 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route * ret = sof_ipc4_set_copier_sink_format(sdev, src_widget, sink_widget, sroute); if (ret < 0) { - dev_err(sdev->dev, + dev_err(scomp->dev, "failed to set sink format for source %s:%d\n", src_widget->widget->name, sroute->src_queue_id); goto out; } } - dev_dbg(sdev->dev, "bind %s:%d -> %s:%d\n", + dev_dbg(scomp->dev, "bind %s:%d -> %s:%d\n", src_widget->widget->name, sroute->src_queue_id, sink_widget->widget->name, sroute->dst_queue_id); @@ -3862,7 +3870,7 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route * ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0); if (ret < 0) { - dev_err(sdev->dev, "failed to bind modules %s:%d -> %s:%d\n", + dev_err(scomp->dev, "failed to bind modules %s:%d -> %s:%d\n", src_widget->widget->name, sroute->src_queue_id, sink_widget->widget->name, sroute->dst_queue_id); goto out; @@ -3878,6 +3886,7 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route * static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *sroute) { + struct snd_soc_component *scomp = sroute->scomp; struct snd_sof_widget *src_widget = sroute->src_widget; struct snd_sof_widget *sink_widget = sroute->sink_widget; struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info; @@ -3894,7 +3903,7 @@ static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *s if (src_pipeline->use_chain_dma || sink_pipeline->use_chain_dma) return 0; - dev_dbg(sdev->dev, "unbind modules %s:%d -> %s:%d\n", + dev_dbg(scomp->dev, "unbind modules %s:%d -> %s:%d\n", src_widget->widget->name, sroute->src_queue_id, sink_widget->widget->name, sroute->dst_queue_id); @@ -3921,7 +3930,7 @@ static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *s ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0); if (ret < 0) - dev_err(sdev->dev, "failed to unbind modules %s:%d -> %s:%d\n", + dev_err(scomp->dev, "failed to unbind modules %s:%d -> %s:%d\n", src_widget->widget->name, sroute->src_queue_id, sink_widget->widget->name, sroute->dst_queue_id); out: @@ -3934,6 +3943,7 @@ static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *s static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, unsigned int flags, struct snd_sof_dai_config_data *data) { + struct snd_soc_component *scomp = swidget->scomp; struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; struct sof_ipc4_pipeline *pipeline = pipe_widget->private; struct snd_sof_dai *dai = swidget->private; @@ -3942,7 +3952,7 @@ static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget * struct sof_ipc4_copier *ipc4_copier; if (!dai || !dai->private) { - dev_err(sdev->dev, "Invalid DAI or DAI private data for %s\n", + dev_err(scomp->dev, "Invalid DAI or DAI private data for %s\n", swidget->widget->name); return -EINVAL; } @@ -4004,7 +4014,7 @@ static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget * /* nothing to do for SSP/DMIC */ break; default: - dev_err(sdev->dev, "%s: unsupported dai type %d\n", __func__, + dev_err(scomp->dev, "%s: unsupported dai type %d\n", __func__, ipc4_copier->dai_type); return -EINVAL; } diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 657266e5434948..0895097157b25f 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -365,7 +365,7 @@ static int sof_pcm_prepare(struct snd_soc_component *component, platform_params = &spcm->platform_params[substream->stream]; ret = sof_widget_list_setup(sdev, spcm, params, platform_params, dir); if (ret < 0) { - dev_err(sdev->dev, "failed widget list set up for pcm %d dir %u\n", + dev_err(component->dev, "failed widget list set up for pcm %d dir %u\n", le32_to_cpu(spcm->pcm.pcm_id), dir); spcm->stream[dir].list = NULL; snd_soc_dapm_dai_free_widgets(&list); @@ -786,7 +786,7 @@ static int sof_pcm_probe(struct snd_soc_component *component) } /* load the default topology */ - tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, + tplg_filename = devm_kasprintf(component->dev, GFP_KERNEL, "%s/%s", plat_data->tplg_filename_prefix, plat_data->tplg_filename); diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 6f5778262e05e1..2c8694de8b1bde 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -84,22 +84,26 @@ static bool is_aggregated_dai(struct snd_sof_widget *swidget) swidget->widget->name[strlen(swidget->widget->name) - 1] != '0'); } -static bool is_virtual_widget(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget, - const char *func) +static bool is_virtual_widget(struct snd_soc_dapm_widget *widget, const char *func) { + struct snd_sof_widget *swidget = widget->dobj.private; + switch (widget->id) { case snd_soc_dapm_out_drv: case snd_soc_dapm_output: case snd_soc_dapm_input: - dev_dbg(sdev->dev, "%s: %s is a virtual widget\n", func, widget->name); + if (swidget) + dev_dbg(swidget->scomp->dev, "%s: %s is a virtual widget\n", + func, widget->name); return true; default: return false; } } -static void sof_reset_route_setup_status(struct snd_sof_dev *sdev, struct snd_sof_widget *widget) +static void sof_reset_route_setup_status(struct snd_sof_widget *widget) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(widget->scomp); struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(widget->scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); @@ -115,6 +119,7 @@ static void sof_reset_route_setup_status(struct snd_sof_dev *sdev, struct snd_so } static int sof_widget_free_unlocked(struct snd_sof_dev *sdev, + struct snd_soc_component *scomp, struct snd_sof_widget *swidget) { const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); @@ -132,7 +137,7 @@ static int sof_widget_free_unlocked(struct snd_sof_dev *sdev, return 0; /* reset route setup status for all routes that contain this widget */ - sof_reset_route_setup_status(sdev, swidget); + sof_reset_route_setup_status(swidget); /* free DAI config and continue to free widget even if it fails */ if (WIDGET_IS_DAI(swidget->id)) { @@ -144,7 +149,8 @@ static int sof_widget_free_unlocked(struct snd_sof_dev *sdev, if (tplg_ops && tplg_ops->dai_config) { err = tplg_ops->dai_config(sdev, swidget, flags, &data); if (err < 0) - dev_err(sdev->dev, "failed to free config for widget %s\n", + dev_err(scomp->dev, + "failed to free config for widget %s\n", swidget->widget->name); } } @@ -166,7 +172,8 @@ static int sof_widget_free_unlocked(struct snd_sof_dev *sdev, for_each_set_bit(i, &spipe->core_mask, sdev->num_cores) { ret = snd_sof_dsp_core_put(sdev, i); if (ret < 0) { - dev_err(sdev->dev, "failed to disable target core: %d for pipeline %s\n", + dev_err(scomp->dev, + "failed to disable target core: %d for pipeline %s\n", i, swidget->widget->name); if (!err) err = ret; @@ -181,13 +188,13 @@ static int sof_widget_free_unlocked(struct snd_sof_dev *sdev, */ if (spipe && spipe->pipe_widget && swidget->dynamic_pipeline_widget && swidget->id != snd_soc_dapm_scheduler) { - ret = sof_widget_free_unlocked(sdev, spipe->pipe_widget); + ret = sof_widget_free_unlocked(sdev, scomp, spipe->pipe_widget); if (ret < 0 && !err) err = ret; } if (!err) - dev_dbg(sdev->dev, "widget %s freed\n", swidget->widget->name); + dev_dbg(scomp->dev, "widget %s freed\n", swidget->widget->name); return err; } @@ -195,11 +202,12 @@ static int sof_widget_free_unlocked(struct snd_sof_dev *sdev, int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) { guard(mutex)(&swidget->setup_mutex); - return sof_widget_free_unlocked(sdev, swidget); + return sof_widget_free_unlocked(sdev, swidget->scomp, swidget); } EXPORT_SYMBOL(sof_widget_free); static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev, + struct snd_soc_component *scomp, struct snd_sof_widget *swidget) { const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); @@ -226,12 +234,13 @@ static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev, */ if (swidget->dynamic_pipeline_widget && swidget->id != snd_soc_dapm_scheduler) { if (!swidget->spipe || !swidget->spipe->pipe_widget) { - dev_err(sdev->dev, "No pipeline set for %s\n", swidget->widget->name); + dev_err(scomp->dev, "No pipeline set for %s\n", + swidget->widget->name); ret = -EINVAL; goto use_count_dec; } - ret = sof_widget_setup_unlocked(sdev, swidget->spipe->pipe_widget); + ret = sof_widget_setup_unlocked(sdev, scomp, swidget->spipe->pipe_widget); if (ret < 0) goto use_count_dec; } @@ -241,7 +250,8 @@ static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev, for_each_set_bit(i, &spipe->core_mask, sdev->num_cores) { ret = snd_sof_dsp_core_get(sdev, i); if (ret < 0) { - dev_err(sdev->dev, "failed to enable target core %d for pipeline %s\n", + dev_err(scomp->dev, + "failed to enable target core %d for pipeline %s\n", i, swidget->widget->name); goto pipe_widget_free; } @@ -277,18 +287,18 @@ static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev, goto widget_free; } - dev_dbg(sdev->dev, "widget %s setup complete\n", swidget->widget->name); + dev_dbg(scomp->dev, "widget %s setup complete\n", swidget->widget->name); return 0; widget_free: /* widget use_count and core_put handled by sof_widget_free() */ - sof_widget_free_unlocked(sdev, swidget); + sof_widget_free_unlocked(sdev, scomp, swidget); return ret; pipe_widget_free: if (swidget->id != snd_soc_dapm_scheduler) { - sof_widget_free_unlocked(sdev, swidget->spipe->pipe_widget); + sof_widget_free_unlocked(sdev, scomp, swidget->spipe->pipe_widget); } else { int j; @@ -308,7 +318,7 @@ static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev, int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) { guard(mutex)(&swidget->setup_mutex); - return sof_widget_setup_unlocked(sdev, swidget); + return sof_widget_setup_unlocked(sdev, swidget->scomp, swidget); } EXPORT_SYMBOL(sof_widget_setup); @@ -324,8 +334,8 @@ int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsourc bool route_found = false; /* ignore routes involving virtual widgets in topology */ - if (is_virtual_widget(sdev, src_widget->widget, __func__) || - is_virtual_widget(sdev, sink_widget->widget, __func__)) + if (is_virtual_widget(src_widget->widget, __func__) || + is_virtual_widget(sink_widget->widget, __func__)) return 0; /* skip route if source/sink widget is not set up */ @@ -340,7 +350,8 @@ int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsourc } if (!route_found) { - dev_err(sdev->dev, "error: cannot find SOF route for source %s -> %s sink\n", + dev_err(src_widget->scomp->dev, + "error: cannot find SOF route for source %s -> %s sink\n", wsource->name, wsink->name); return -EINVAL; } @@ -385,10 +396,10 @@ static int sof_set_up_same_dir_widget_routes(struct snd_sof_dev *sdev, return sof_route_setup(sdev, wsource, wsink); } -static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev, - struct snd_soc_dapm_widget_list *list, +static int sof_setup_pipeline_connections(struct snd_soc_dapm_widget_list *list, struct snd_soc_component *scomp, int dir) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); struct snd_sof_audio_instance *instance = snd_sof_component_get_audio_instance(scomp); struct snd_soc_dapm_widget *widget; struct snd_sof_route *sroute; @@ -501,7 +512,7 @@ sof_unprepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widg const struct sof_ipc_tplg_widget_ops *widget_ops; struct snd_soc_dapm_path *p; - if (is_virtual_widget(sdev, widget, __func__)) + if (is_virtual_widget(widget, __func__)) return; if (!swidget) @@ -549,7 +560,7 @@ sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget struct snd_soc_dapm_path *p; int ret; - if (is_virtual_widget(sdev, widget, __func__)) + if (is_virtual_widget(widget, __func__)) return 0; if (!swidget) @@ -571,7 +582,7 @@ sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget ret = widget_ops[widget->id].ipc_prepare(swidget, fe_params, platform_params, pipeline_params, dir); if (ret < 0) { - dev_err(sdev->dev, "failed to prepare widget %s\n", widget->name); + dev_err(swidget->scomp->dev, "failed to prepare widget %s\n", widget->name); return ret; } @@ -622,7 +633,7 @@ static int sof_free_widgets_in_path_internal(struct snd_sof_dev *sdev, if (!list) return 0; - if (is_virtual_widget(sdev, widget, __func__)) + if (is_virtual_widget(widget, __func__)) return 0; if (!swidget) @@ -702,7 +713,7 @@ static int sof_set_up_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_d struct snd_soc_dapm_path *p; int ret; - if (is_virtual_widget(sdev, widget, __func__)) + if (is_virtual_widget(widget, __func__)) return 0; if (swidget) { @@ -817,14 +828,14 @@ sof_walk_widgets_in_order(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, sof_unprepare_widgets_in_path(sdev, widget, list, dir); break; default: - dev_err(sdev->dev, "Invalid widget op %d\n", op); + dev_err(spcm->scomp->dev, "Invalid widget op %d\n", op); return -EINVAL; } if (ret < 0) { if (op == SOF_WIDGET_FREE) sof_reset_path_walking_flags(list); - dev_err(sdev->dev, "Failed to %s connected widgets\n", str); + dev_err(spcm->scomp->dev, "Failed to %s connected widgets\n", str); return ret; } } @@ -886,7 +897,7 @@ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, * error in setting pipeline connections will result in route status being reset for * routes that were successfully set up when the widgets are freed. */ - ret = sof_setup_pipeline_connections(sdev, list, spcm->scomp, dir); + ret = sof_setup_pipeline_connections(list, spcm->scomp, dir); if (ret < 0) goto widget_free; @@ -901,7 +912,7 @@ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, spipe = swidget->spipe; if (!spipe) { - dev_err(sdev->dev, "no pipeline found for %s\n", + dev_err(swidget->scomp->dev, "no pipeline found for %s\n", swidget->widget->name); ret = -EINVAL; goto widget_free; @@ -909,7 +920,7 @@ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, pipe_widget = spipe->pipe_widget; if (!pipe_widget) { - dev_err(sdev->dev, "error: no pipeline widget found for %s\n", + dev_err(swidget->scomp->dev, "error: no pipeline widget found for %s\n", swidget->widget->name); ret = -EINVAL; goto widget_free; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index ea02a5ea27a607..6a4c0ab16d7d2f 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -496,7 +496,7 @@ static int sof_parse_uuid_tokens(struct snd_soc_component *scomp, /** * sof_copy_tuples - Parse tokens and copy them to the @tuples array - * @sdev: pointer to struct snd_sof_dev + * @scomp: pointer to struct snd_soc_component * @array: source pointer to consecutive vendor arrays in topology * @array_size: size of @array * @token_id: Token ID associated with a token array @@ -508,10 +508,12 @@ static int sof_parse_uuid_tokens(struct snd_soc_component *scomp, * @num_copied_tuples: pointer to the number of copied tuples in the tuples array * */ -static int sof_copy_tuples(struct snd_sof_dev *sdev, struct snd_soc_tplg_vendor_array *array, +static int sof_copy_tuples(struct snd_soc_component *scomp, + struct snd_soc_tplg_vendor_array *array, int array_size, u32 token_id, int token_instance_num, struct snd_sof_tuple *tuples, int tuples_size, int *num_copied_tuples) { + struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); const struct sof_token_info *token_list; const struct sof_topology_token *tokens; @@ -525,7 +527,7 @@ static int sof_copy_tuples(struct snd_sof_dev *sdev, struct snd_soc_tplg_vendor_ return 0; if (!tuples || !num_copied_tuples) { - dev_err(sdev->dev, "Invalid tuples array\n"); + dev_err(scomp->dev, "Invalid tuples array\n"); return -EINVAL; } @@ -533,13 +535,13 @@ static int sof_copy_tuples(struct snd_sof_dev *sdev, struct snd_soc_tplg_vendor_ num_tokens = token_list[token_id].count; if (!tokens) { - dev_err(sdev->dev, "No token array defined for token ID: %d\n", token_id); + dev_err(scomp->dev, "No token array defined for token ID: %d\n", token_id); return -EINVAL; } /* check if there's space in the tuples array for new tokens */ if (*num_copied_tuples >= tuples_size) { - dev_err(sdev->dev, "No space in tuples array for new tokens from %s", + dev_err(scomp->dev, "No space in tuples array for new tokens from %s", token_list[token_id].name); return -EINVAL; } @@ -549,14 +551,14 @@ static int sof_copy_tuples(struct snd_sof_dev *sdev, struct snd_soc_tplg_vendor_ /* validate asize */ if (asize < 0) { - dev_err(sdev->dev, "Invalid array size 0x%x\n", asize); + dev_err(scomp->dev, "Invalid array size 0x%x\n", asize); return -EINVAL; } /* make sure there is enough data before parsing */ array_size -= asize; if (array_size < 0) { - dev_err(sdev->dev, "Invalid array size 0x%x\n", asize); + dev_err(scomp->dev, "Invalid array size 0x%x\n", asize); return -EINVAL; } @@ -583,7 +585,7 @@ static int sof_copy_tuples(struct snd_sof_dev *sdev, struct snd_soc_tplg_vendor_ tuples[*num_copied_tuples].token = tokens[j].token; tuples[*num_copied_tuples].value.s = - devm_kasprintf(sdev->dev, GFP_KERNEL, + devm_kasprintf(scomp->dev, GFP_KERNEL, "%s", elem->string); if (!tuples[*num_copied_tuples].value.s) return -ENOMEM; @@ -1276,7 +1278,7 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s num_sets = sof_get_token_value(SOF_TKN_COMP_NUM_INPUT_AUDIO_FORMATS, swidget->tuples, swidget->num_tuples); if (num_sets < 0) { - dev_err(sdev->dev, "Invalid input audio format count for %s\n", + dev_err(scomp->dev, "Invalid input audio format count for %s\n", swidget->widget->name); ret = num_sets; goto err; @@ -1286,7 +1288,7 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s num_sets = sof_get_token_value(SOF_TKN_COMP_NUM_OUTPUT_AUDIO_FORMATS, swidget->tuples, swidget->num_tuples); if (num_sets < 0) { - dev_err(sdev->dev, "Invalid output audio format count for %s\n", + dev_err(scomp->dev, "Invalid output audio format count for %s\n", swidget->widget->name); ret = num_sets; goto err; @@ -1311,7 +1313,7 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s } /* copy one set of tuples per token ID into swidget->tuples */ - ret = sof_copy_tuples(sdev, private->array, le32_to_cpu(private->size), + ret = sof_copy_tuples(scomp, private->array, le32_to_cpu(private->size), object_token_list[i], num_sets, swidget->tuples, num_tuples, &swidget->num_tuples); if (ret < 0) { @@ -2024,7 +2026,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ if (token_list[SOF_DAI_LINK_TOKENS].tokens) { /* parse one set of DAI link tokens */ - ret = sof_copy_tuples(sdev, private->array, le32_to_cpu(private->size), + ret = sof_copy_tuples(scomp, private->array, le32_to_cpu(private->size), SOF_DAI_LINK_TOKENS, 1, slink->tuples, num_tuples, &slink->num_tuples); if (ret < 0) { @@ -2039,7 +2041,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ goto out; /* parse "num_sets" sets of DAI-specific tokens */ - ret = sof_copy_tuples(sdev, private->array, le32_to_cpu(private->size), + ret = sof_copy_tuples(scomp, private->array, le32_to_cpu(private->size), token_id, num_sets, slink->tuples, num_tuples, &slink->num_tuples); if (ret < 0) { dev_err(scomp->dev, "failed to parse %s for dai link %s\n", @@ -2053,12 +2055,12 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ slink->tuples, slink->num_tuples); if (num_sets < 0) { - dev_err(sdev->dev, "Invalid active PDM count for %s\n", link->name); + dev_err(scomp->dev, "Invalid active PDM count for %s\n", link->name); ret = num_sets; goto err; } - ret = sof_copy_tuples(sdev, private->array, le32_to_cpu(private->size), + ret = sof_copy_tuples(scomp, private->array, le32_to_cpu(private->size), SOF_DMIC_PDM_TOKENS, num_sets, slink->tuples, num_tuples, &slink->num_tuples); if (ret < 0) { @@ -2190,7 +2192,7 @@ static int sof_set_widget_pipeline(struct snd_sof_dev *sdev, struct snd_sof_pipe list_for_each_entry(scontrol, &instance->kcontrol_list, list) if (scontrol->comp_id == swidget->comp_id && (scontrol->access & SNDRV_CTL_ELEM_ACCESS_VOLATILE)) { - dev_err(sdev->dev, + dev_err(swidget->scomp->dev, "error: volatile control found for dynamic widget %s\n", swidget->widget->name); return -EINVAL; @@ -2225,7 +2227,7 @@ static int sof_complete(struct snd_soc_component *scomp) list_for_each_entry(scontrol, &instance->kcontrol_list, list) { ret = tplg_ops->control_setup(sdev, scontrol); if (ret < 0) { - dev_err(sdev->dev, "failed updating IPC struct for control %s\n", + dev_err(scomp->dev, "failed updating IPC struct for control %s\n", scontrol->name); return ret; } @@ -2242,7 +2244,7 @@ static int sof_complete(struct snd_soc_component *scomp) if (widget_ops && widget_ops[pipe_widget->id].ipc_setup) { ret = widget_ops[pipe_widget->id].ipc_setup(pipe_widget); if (ret < 0) { - dev_err(sdev->dev, "failed updating IPC struct for %s\n", + dev_err(scomp->dev, "failed updating IPC struct for %s\n", pipe_widget->widget->name); return ret; } @@ -2259,7 +2261,7 @@ static int sof_complete(struct snd_soc_component *scomp) if (widget_ops && widget_ops[swidget->id].ipc_setup) { ret = widget_ops[swidget->id].ipc_setup(swidget); if (ret < 0) { - dev_err(sdev->dev, + dev_err(scomp->dev, "failed updating IPC struct for %s\n", swidget->widget->name); return ret; @@ -2274,14 +2276,14 @@ static int sof_complete(struct snd_soc_component *scomp) tplg_ops->tear_down_all_pipelines) { ret = tplg_ops->set_up_all_pipelines(sdev, true); if (ret < 0) { - dev_err(sdev->dev, "Failed to set up all topology pipelines: %d\n", + dev_err(scomp->dev, "Failed to set up all topology pipelines: %d\n", ret); return ret; } ret = tplg_ops->tear_down_all_pipelines(sdev, true); if (ret < 0) { - dev_err(sdev->dev, "Failed to tear down topology pipelines: %d\n", + dev_err(scomp->dev, "Failed to tear down topology pipelines: %d\n", ret); return ret; } From 63c0c0804873cf0aeff365de8c1ffe7f0952adad Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 3 Jun 2026 12:33:41 +0300 Subject: [PATCH 73/83] ASoC: SOF: register audio as a sof-client auxiliary device Move audio component and machine driver registration from core.c into a dedicated sof-client auxiliary driver (snd-sof-audio.ko). Core.c now registers a 'snd_sof.audio' auxiliary device with the pre-built snd_soc_component_driver and DAI drivers passed as platform_data. The audio client driver's probe registers the ASoC component and machine driver, and its remove handles teardown in the correct order. The component is still registered on the parent device (sdev->dev) via sof_client_get_dma_dev() to maintain machine driver compatibility. SND_SOC_SOF now selects SND_SOC_SOF_CLIENT to ensure the client framework is always available. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/Kconfig | 1 + sound/soc/sof/Makefile | 2 ++ sound/soc/sof/core.c | 39 ++++++++++---------- sound/soc/sof/sof-client-audio.c | 62 ++++++++++++++++++++++++++++++++ sound/soc/sof/sof-client-audio.h | 22 ++++++++++++ 5 files changed, 107 insertions(+), 19 deletions(-) create mode 100644 sound/soc/sof/sof-client-audio.c create mode 100644 sound/soc/sof/sof-client-audio.h diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index f73a0e534851c8..3f5b541a592ba6 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -286,6 +286,7 @@ endif ## SND_SOC_SOF_DEVELOPER_SUPPORT config SND_SOC_SOF tristate select SND_SOC_TOPOLOGY + select SND_SOC_SOF_CLIENT select SND_SOC_SOF_NOCODEC if SND_SOC_SOF_NOCODEC_SUPPORT select SND_SOC_SOF_NOCODEC if SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT help diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 887abf70da3ba1..64d4159a2d2388 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -28,6 +28,7 @@ snd-sof-of-y := sof-of-dev.o snd-sof-ipc-flood-test-y := sof-client-ipc-flood-test.o snd-sof-ipc-msg-injector-y := sof-client-ipc-msg-injector.o snd-sof-ipc-kernel-injector-y := sof-client-ipc-kernel-injector.o +snd-sof-audio-y := sof-client-audio.o snd-sof-probes-y := sof-client-probes.o ifneq ($(CONFIG_SND_SOC_SOF_IPC3),) snd-sof-probes-y += sof-client-probes-ipc3.o @@ -42,6 +43,7 @@ snd-sof-nocodec-y := nocodec.o snd-sof-utils-y := sof-utils.o obj-$(CONFIG_SND_SOC_SOF) += snd-sof.o +obj-$(CONFIG_SND_SOC_SOF) += snd-sof-audio.o obj-$(CONFIG_SND_SOC_SOF_NOCODEC) += snd-sof-nocodec.o obj-$(CONFIG_SND_SOC_SOF) += snd-sof-utils.o diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index cea3d1af38be18..51581360f382bc 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -14,6 +14,7 @@ #include #include "sof-priv.h" #include "sof-of-dev.h" +#include "sof-client-audio.h" #include "ops.h" #define CREATE_TRACE_POINTS @@ -554,27 +555,28 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) /* hereafter all FW boot flows are for PM reasons */ sdev->first_boot = false; - /* now register audio DSP platform driver and dai */ - ret = devm_snd_soc_register_component(sdev->dev, &sdev->plat_drv, - sdev->audio_ops->drv, - sdev->audio_ops->num_drv); - if (ret < 0) { - dev_err(sdev->dev, - "error: failed to register DSP DAI driver %d\n", ret); - goto fw_trace_err; + /* Register audio client device */ + { + struct sof_audio_client_pdata audio_pdata = { + .plat_drv = sdev->plat_drv, + .drv = sdev->audio_ops->drv, + .num_drv = sdev->audio_ops->num_drv, + }; + + ret = sof_client_dev_register(sdev, "audio", 0, + &audio_pdata, + sizeof(audio_pdata)); } - - ret = snd_sof_machine_register(sdev, plat_data); if (ret < 0) { dev_err(sdev->dev, - "error: failed to register machine driver %d\n", ret); + "error: failed to register audio client %d\n", ret); goto fw_trace_err; } ret = sof_register_clients(sdev); if (ret < 0) { dev_err(sdev->dev, "failed to register clients %d\n", ret); - goto sof_machine_err; + goto audio_client_err; } /* @@ -592,8 +594,8 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) return 0; -sof_machine_err: - snd_sof_machine_unregister(sdev, plat_data); +audio_client_err: + sof_client_dev_unregister(sdev, "audio", 0); fw_trace_err: sof_fw_trace_free(sdev); fw_run_err: @@ -747,7 +749,6 @@ EXPORT_SYMBOL(snd_sof_device_probe_completed); int snd_sof_device_remove(struct device *dev) { struct snd_sof_dev *sdev = dev_get_drvdata(dev); - struct snd_sof_pdata *pdata = sdev->pdata; int ret; bool aborted = false; @@ -761,11 +762,11 @@ int snd_sof_device_remove(struct device *dev) sof_unregister_clients(sdev); /* - * Unregister machine driver. This will unbind the snd_card which - * will remove the component driver and unload the topology - * before freeing the snd_card. + * Unregister audio client device. This will unregister the machine + * driver and the ASoC component, which will unbind the snd_card, + * unload the topology and free the snd_card. */ - snd_sof_machine_unregister(sdev, pdata); + sof_client_dev_unregister(sdev, "audio", 0); /* * Balance the runtime pm usage count in case we are faced with an diff --git a/sound/soc/sof/sof-client-audio.c b/sound/soc/sof/sof-client-audio.c new file mode 100644 index 00000000000000..ec961dca4443f4 --- /dev/null +++ b/sound/soc/sof/sof-client-audio.c @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2026 Intel Corporation +// +// Authors: Peter Ujfalusi +// + +#include +#include +#include + +#include "sof-client.h" +#include "sof-client-audio.h" + +static int sof_audio_client_probe(struct auxiliary_device *auxdev, + const struct auxiliary_device_id *id) +{ + struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev); + struct sof_audio_client_pdata *pdata = dev_get_platdata(&auxdev->dev); + struct device *dma_dev = sof_client_get_dma_dev(cdev); + int ret; + + ret = snd_soc_register_component(dma_dev, &pdata->plat_drv, + pdata->drv, pdata->num_drv); + if (ret < 0) + return ret; + + ret = sof_client_machine_register(cdev); + if (ret < 0) { + snd_soc_unregister_component(dma_dev); + return ret; + } + + return 0; +} + +static void sof_audio_client_remove(struct auxiliary_device *auxdev) +{ + struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev); + struct device *dma_dev = sof_client_get_dma_dev(cdev); + + sof_client_machine_unregister(cdev); + snd_soc_unregister_component(dma_dev); +} + +static const struct auxiliary_device_id sof_audio_client_id_table[] = { + { .name = "snd_sof.audio", }, + {}, +}; +MODULE_DEVICE_TABLE(auxiliary, sof_audio_client_id_table); + +static struct auxiliary_driver sof_audio_client_drv = { + .probe = sof_audio_client_probe, + .remove = sof_audio_client_remove, + .id_table = sof_audio_client_id_table, +}; + +module_auxiliary_driver(sof_audio_client_drv); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("SOF Audio Client Driver"); +MODULE_IMPORT_NS("SND_SOC_SOF_CLIENT"); diff --git a/sound/soc/sof/sof-client-audio.h b/sound/soc/sof/sof-client-audio.h new file mode 100644 index 00000000000000..0e844ac8df540d --- /dev/null +++ b/sound/soc/sof/sof-client-audio.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __SOF_CLIENT_AUDIO_H +#define __SOF_CLIENT_AUDIO_H + +#include + +/** + * struct sof_audio_client_pdata - platform data for the audio sof-client + * @plat_drv: Pre-built ASoC component driver + * @drv: Array of DAI drivers to register + * @num_drv: Number of DAI drivers + * @machine: Per-instance copy of the machine descriptor + */ +struct sof_audio_client_pdata { + const struct snd_soc_component_driver plat_drv; + struct snd_soc_dai_driver *drv; + int num_drv; + struct snd_soc_acpi_mach machine; +}; + +#endif /* __SOF_CLIENT_AUDIO_H */ From 80c6665d50dcd53baffd598939c8e2347c023e0e Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 3 Jun 2026 12:59:04 +0300 Subject: [PATCH 74/83] ASoC: SOF: move audio client registration to vendor ops Move the audio client device registration from core.c's probe path into vendor-controlled callbacks in snd_sof_dsp_ops. This allows each vendor/platform to control the audio client lifecycle. Add register_audio_client/unregister_audio_client callbacks to struct snd_sof_dsp_ops and provide default implementations (sof_register_audio_client/sof_unregister_audio_client) that all vendors use for now. The audio client registration is called from sof_register_clients() before the dspless mode early return, ensuring audio works in both normal and dspless modes. The snd_sof_new_platform_drv() call is moved into sof_register_audio_client(), making core.c no longer responsible for building the platform driver or audio client pdata. With the audio client pdata now built locally in the helper, sdev->plat_drv is no longer needed and is removed from struct snd_sof_dev. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/amd/acp-common.c | 6 +++ sound/soc/sof/core.c | 36 +---------------- sound/soc/sof/imx/imx-common.c | 6 +++ sound/soc/sof/intel/bdw.c | 6 +++ sound/soc/sof/intel/byt.c | 10 +++++ sound/soc/sof/intel/hda-common-ops.c | 5 +++ sound/soc/sof/intel/hda.c | 1 + sound/soc/sof/intel/pci-tng.c | 6 +++ sound/soc/sof/mediatek/mt8186/mt8186.c | 6 +++ sound/soc/sof/mediatek/mt8195/mt8195.c | 6 +++ sound/soc/sof/mediatek/mt8365/mt8365.c | 6 +++ sound/soc/sof/sof-client.c | 56 +++++++++++++++++++++++++- sound/soc/sof/sof-client.h | 9 +++++ sound/soc/sof/sof-priv.h | 10 ++--- 14 files changed, 127 insertions(+), 42 deletions(-) diff --git a/sound/soc/sof/amd/acp-common.c b/sound/soc/sof/amd/acp-common.c index 85d823e2497e63..0b73454a59b777 100644 --- a/sound/soc/sof/amd/acp-common.c +++ b/sound/soc/sof/amd/acp-common.c @@ -12,6 +12,7 @@ #include "../sof-priv.h" #include "../sof-audio.h" +#include "../sof-client.h" #include "../ops.h" #include "acp.h" #include "acp-dsp-offset.h" @@ -229,6 +230,10 @@ const struct snd_sof_dsp_ops sof_acp_common_ops = { .machine_register = sof_machine_register, .machine_unregister = sof_machine_unregister, + /* audio client */ + .register_audio_client = sof_register_audio_client, + .unregister_audio_client = sof_unregister_audio_client, + /* Trace Logger */ .trace_init = acp_sof_trace_init, .trace_release = acp_sof_trace_release, @@ -251,5 +256,6 @@ EXPORT_SYMBOL_NS(sof_acp_common_ops, "SND_SOC_SOF_AMD_COMMON"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("ACP SOF COMMON Driver"); MODULE_IMPORT_NS("SND_SOC_SOF_AMD_COMMON"); +MODULE_IMPORT_NS("SND_SOC_SOF_CLIENT"); MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA"); MODULE_IMPORT_NS("SOUNDWIRE_AMD_INIT"); diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 51581360f382bc..cd5aea017d2e62 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -14,7 +14,6 @@ #include #include "sof-priv.h" #include "sof-of-dev.h" -#include "sof-client-audio.h" #include "ops.h" #define CREATE_TRACE_POINTS @@ -473,9 +472,6 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) if (sdev->dspless_mode_selected) { sof_set_fw_state(sdev, SOF_DSPLESS_MODE); - /* set up platform component driver */ - snd_sof_new_platform_drv(sdev, &sdev->plat_drv); - goto skip_dsp_init; } @@ -500,9 +496,6 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) goto ipc_err; } - /* set up platform component driver after initializing the IPC ops */ - snd_sof_new_platform_drv(sdev, &sdev->plat_drv); - /* * skip loading/booting firmware and registering the machine driver when DSP OPS testing * is enabled with IPC4. Normal audio operations will be unavailable in this mode. @@ -555,28 +548,10 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) /* hereafter all FW boot flows are for PM reasons */ sdev->first_boot = false; - /* Register audio client device */ - { - struct sof_audio_client_pdata audio_pdata = { - .plat_drv = sdev->plat_drv, - .drv = sdev->audio_ops->drv, - .num_drv = sdev->audio_ops->num_drv, - }; - - ret = sof_client_dev_register(sdev, "audio", 0, - &audio_pdata, - sizeof(audio_pdata)); - } - if (ret < 0) { - dev_err(sdev->dev, - "error: failed to register audio client %d\n", ret); - goto fw_trace_err; - } - ret = sof_register_clients(sdev); if (ret < 0) { dev_err(sdev->dev, "failed to register clients %d\n", ret); - goto audio_client_err; + goto fw_trace_err; } /* @@ -594,8 +569,6 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) return 0; -audio_client_err: - sof_client_dev_unregister(sdev, "audio", 0); fw_trace_err: sof_fw_trace_free(sdev); fw_run_err: @@ -761,13 +734,6 @@ int snd_sof_device_remove(struct device *dev) */ sof_unregister_clients(sdev); - /* - * Unregister audio client device. This will unregister the machine - * driver and the ASoC component, which will unbind the snd_card, - * unload the topology and free the snd_card. - */ - sof_client_dev_unregister(sdev, "audio", 0); - /* * Balance the runtime pm usage count in case we are faced with an * exception and we forcably prevented D3 power state to preserve diff --git a/sound/soc/sof/imx/imx-common.c b/sound/soc/sof/imx/imx-common.c index 0b8aa523659ad5..65daa45fda5fb6 100644 --- a/sound/soc/sof/imx/imx-common.c +++ b/sound/soc/sof/imx/imx-common.c @@ -12,6 +12,7 @@ #include #include "../ops.h" +#include "../sof-client.h" #include "imx-common.h" @@ -455,6 +456,10 @@ const struct snd_sof_dsp_ops sof_imx_ops = { .get_bar_index = imx_get_bar_index, .load_firmware = snd_sof_load_firmware_memcpy, + /* audio client */ + .register_audio_client = sof_register_audio_client, + .unregister_audio_client = sof_unregister_audio_client, + .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, .runtime_suspend = imx_runtime_suspend, @@ -468,3 +473,4 @@ EXPORT_SYMBOL(sof_imx_ops); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF helpers for IMX platforms"); +MODULE_IMPORT_NS("SND_SOC_SOF_CLIENT"); diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index f7f4058b57e034..bc78bd6858b4e3 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -19,6 +19,7 @@ #include #include #include "../ops.h" +#include "../sof-client.h" #include "shim.h" #include "../sof-acpi-dev.h" #include "../sof-audio.h" @@ -607,6 +608,10 @@ static const struct snd_sof_dsp_ops sof_bdw_ops = { .machine_unregister = sof_machine_unregister, .set_mach_params = bdw_set_mach_params, + /* audio client */ + .register_audio_client = sof_register_audio_client, + .unregister_audio_client = sof_unregister_audio_client, + /* debug */ .debug_map = bdw_debugfs, .debug_map_count = ARRAY_SIZE(bdw_debugfs), @@ -689,5 +694,6 @@ module_platform_driver(snd_sof_acpi_intel_bdw_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for Broadwell platforms"); +MODULE_IMPORT_NS("SND_SOC_SOF_CLIENT"); MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA"); MODULE_IMPORT_NS("SND_SOC_SOF_ACPI_DEV"); diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 1e311e774600ae..a946266420b5cc 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -19,6 +19,7 @@ #include #include #include "../ops.h" +#include "../sof-client.h" #include "atom.h" #include "shim.h" #include "../sof-acpi-dev.h" @@ -264,6 +265,10 @@ static const struct snd_sof_dsp_ops sof_byt_ops = { .machine_unregister = sof_machine_unregister, .set_mach_params = atom_set_mach_params, + /* audio client */ + .register_audio_client = sof_register_audio_client, + .unregister_audio_client = sof_unregister_audio_client, + /* debug */ .debug_map = byt_debugfs, .debug_map_count = ARRAY_SIZE(byt_debugfs), @@ -338,6 +343,10 @@ static const struct snd_sof_dsp_ops sof_cht_ops = { .machine_unregister = sof_machine_unregister, .set_mach_params = atom_set_mach_params, + /* audio client */ + .register_audio_client = sof_register_audio_client, + .unregister_audio_client = sof_unregister_audio_client, + /* debug */ .debug_map = cht_debugfs, .debug_map_count = ARRAY_SIZE(cht_debugfs), @@ -475,6 +484,7 @@ module_platform_driver(snd_sof_acpi_intel_byt_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for Baytrail/Cherrytrail"); +MODULE_IMPORT_NS("SND_SOC_SOF_CLIENT"); MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA"); MODULE_IMPORT_NS("SND_SOC_SOF_ACPI_DEV"); MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_ATOM_HIFI_EP"); diff --git a/sound/soc/sof/intel/hda-common-ops.c b/sound/soc/sof/intel/hda-common-ops.c index 89920db60e3002..d5c77f739bc514 100644 --- a/sound/soc/sof/intel/hda-common-ops.c +++ b/sound/soc/sof/intel/hda-common-ops.c @@ -11,6 +11,7 @@ */ #include "../sof-priv.h" +#include "../sof-client.h" #include "hda.h" #include "../sof-audio.h" @@ -104,6 +105,10 @@ const struct snd_sof_dsp_ops sof_hda_common_ops = { .register_ipc_clients = hda_register_clients, .unregister_ipc_clients = hda_unregister_clients, + /* audio client */ + .register_audio_client = sof_register_audio_client, + .unregister_audio_client = sof_unregister_audio_client, + /* DAI drivers */ .is_chain_dma_supported = hda_is_chain_dma_supported, diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index c5eb71f92c017d..ca04651d975718 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1783,6 +1783,7 @@ MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV"); MODULE_IMPORT_NS("SND_SOC_SOF_HDA_AUDIO_CODEC"); MODULE_IMPORT_NS("SND_SOC_SOF_HDA_AUDIO_CODEC_I915"); MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA"); +MODULE_IMPORT_NS("SND_SOC_SOF_CLIENT"); MODULE_IMPORT_NS("SND_INTEL_SOUNDWIRE_ACPI"); MODULE_IMPORT_NS("SOUNDWIRE_INTEL_INIT"); MODULE_IMPORT_NS("SOUNDWIRE_INTEL"); diff --git a/sound/soc/sof/intel/pci-tng.c b/sound/soc/sof/intel/pci-tng.c index 8d9740d51f4f22..59411585e68ef3 100644 --- a/sound/soc/sof/intel/pci-tng.c +++ b/sound/soc/sof/intel/pci-tng.c @@ -14,6 +14,7 @@ #include #include #include "../ops.h" +#include "../sof-client.h" #include "atom.h" #include "../sof-pci-dev.h" #include "../sof-audio.h" @@ -182,6 +183,10 @@ const struct snd_sof_dsp_ops sof_tng_ops = { .machine_unregister = sof_machine_unregister, .set_mach_params = atom_set_mach_params, + /* audio client */ + .register_audio_client = sof_register_audio_client, + .unregister_audio_client = sof_unregister_audio_client, + /* debug */ .debug_map = tng_debugfs, .debug_map_count = ARRAY_SIZE(tng_debugfs), @@ -245,6 +250,7 @@ module_pci_driver(snd_sof_pci_intel_tng_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for Tangier platforms"); +MODULE_IMPORT_NS("SND_SOC_SOF_CLIENT"); MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA"); MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV"); MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_ATOM_HIFI_EP"); diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c index 65b4714a22b818..720fc29240fd52 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186.c @@ -20,6 +20,7 @@ #include #include #include "../../ops.h" +#include "../../sof-client.h" #include "../../sof-of-dev.h" #include "../adsp_helper.h" #include "../mtk-adsp-common.h" @@ -431,6 +432,10 @@ static const struct snd_sof_dsp_ops sof_mt8186_ops = { /* firmware loading */ .load_firmware = snd_sof_load_firmware_memcpy, + /* audio client */ + .register_audio_client = sof_register_audio_client, + .unregister_audio_client = sof_unregister_audio_client, + /* Firmware ops */ .dsp_arch_ops = &sof_xtensa_arch_ops, @@ -582,5 +587,6 @@ module_platform_driver(snd_sof_of_mt8186_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for MT8186/MT8188 platforms"); +MODULE_IMPORT_NS("SND_SOC_SOF_CLIENT"); MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA"); MODULE_IMPORT_NS("SND_SOC_SOF_MTK_COMMON"); diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index bec41f481dacce..23ec7f1ce5f3bf 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -20,6 +20,7 @@ #include #include #include "../../ops.h" +#include "../../sof-client.h" #include "../../sof-of-dev.h" #include "../adsp_helper.h" #include "../mtk-adsp-common.h" @@ -455,6 +456,10 @@ static const struct snd_sof_dsp_ops sof_mt8195_ops = { /* firmware loading */ .load_firmware = snd_sof_load_firmware_memcpy, + /* audio client */ + .register_audio_client = sof_register_audio_client, + .unregister_audio_client = sof_unregister_audio_client, + /* Firmware ops */ .dsp_arch_ops = &sof_xtensa_arch_ops, @@ -522,5 +527,6 @@ module_platform_driver(snd_sof_of_mt8195_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for MTL 8195 platforms"); +MODULE_IMPORT_NS("SND_SOC_SOF_CLIENT"); MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA"); MODULE_IMPORT_NS("SND_SOC_SOF_MTK_COMMON"); diff --git a/sound/soc/sof/mediatek/mt8365/mt8365.c b/sound/soc/sof/mediatek/mt8365/mt8365.c index 83caf3ae667bae..87b43f4e814254 100644 --- a/sound/soc/sof/mediatek/mt8365/mt8365.c +++ b/sound/soc/sof/mediatek/mt8365/mt8365.c @@ -19,6 +19,7 @@ #include #include #include "../../ops.h" +#include "../../sof-client.h" #include "../../sof-of-dev.h" #include "../../sof-audio.h" #include "../adsp_helper.h" @@ -587,6 +588,10 @@ static struct snd_sof_dsp_ops sof_mt8365_ops = { /* firmware loading */ .load_firmware = snd_sof_load_firmware_memcpy, + /* audio client */ + .register_audio_client = sof_register_audio_client, + .unregister_audio_client = sof_unregister_audio_client, + /* Firmware ops */ .dsp_arch_ops = &sof_xtensa_arch_ops, @@ -646,6 +651,7 @@ static struct platform_driver snd_sof_of_mt8365_driver = { }; module_platform_driver(snd_sof_of_mt8365_driver); +MODULE_IMPORT_NS("SND_SOC_SOF_CLIENT"); MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA"); MODULE_IMPORT_NS("SND_SOC_SOF_MTK_COMMON"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/sof-client.c b/sound/soc/sof/sof-client.c index 39567e3d67b4d4..1ab8c01790469b 100644 --- a/sound/soc/sof/sof-client.c +++ b/sound/soc/sof/sof-client.c @@ -15,6 +15,7 @@ #include #include "ops.h" #include "sof-client.h" +#include "sof-client-audio.h" #include "sof-priv.h" #include "ipc3-priv.h" #include "ipc4-priv.h" @@ -190,6 +191,16 @@ int sof_register_clients(struct snd_sof_dev *sdev) { int ret; + /* Register audio client (needed in dspless mode too) */ + if (sof_ops(sdev) && sof_ops(sdev)->register_audio_client) { + ret = sof_ops(sdev)->register_audio_client(sdev); + if (ret < 0) { + dev_err(sdev->dev, + "audio client registration failed: %d\n", ret); + return ret; + } + } + if (sdev->dspless_mode_selected) return 0; @@ -197,7 +208,7 @@ int sof_register_clients(struct snd_sof_dev *sdev) ret = sof_register_ipc_flood_test(sdev); if (ret) { dev_err(sdev->dev, "IPC flood test client registration failed\n"); - return ret; + goto err_audio; } ret = sof_register_ipc_msg_injector(sdev); @@ -237,6 +248,10 @@ int sof_register_clients(struct snd_sof_dev *sdev) err_msg_injector: sof_unregister_ipc_flood_test(sdev); +err_audio: + if (sof_ops(sdev) && sof_ops(sdev)->unregister_audio_client) + sof_ops(sdev)->unregister_audio_client(sdev); + return ret; } @@ -249,6 +264,10 @@ void sof_unregister_clients(struct snd_sof_dev *sdev) sof_unregister_ipc_msg_injector(sdev); sof_unregister_ipc_flood_test(sdev); sof_unregister_fw_gdb(sdev); + + /* Audio client last (reverse of registration order) */ + if (sof_ops(sdev) && sof_ops(sdev)->unregister_audio_client) + sof_ops(sdev)->unregister_audio_client(sdev); } int sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, u32 id, @@ -733,7 +752,42 @@ EXPORT_SYMBOL_NS_GPL(sof_client_machine_register, "SND_SOC_SOF_CLIENT"); void sof_client_machine_unregister(struct sof_client_dev *cdev) { struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + struct platform_device *pdev = cdev->data; + + if (pdev) { + platform_device_unregister(pdev); + return; + } snd_sof_machine_unregister(sdev, sdev->pdata); } EXPORT_SYMBOL_NS_GPL(sof_client_machine_unregister, "SND_SOC_SOF_CLIENT"); + +void sof_audio_client_init_pdata(struct snd_sof_dev *sdev, + struct sof_audio_client_pdata *pdata) +{ + void *plat_drv = (void *)&pdata->plat_drv; + + memset(pdata, 0, sizeof(*pdata)); + snd_sof_new_platform_drv(sdev, plat_drv); + pdata->drv = sdev->audio_ops->drv; + pdata->num_drv = sdev->audio_ops->num_drv; +} +EXPORT_SYMBOL_NS_GPL(sof_audio_client_init_pdata, "SND_SOC_SOF_CLIENT"); + +int sof_register_audio_client(struct snd_sof_dev *sdev) +{ + struct sof_audio_client_pdata pdata; + + sof_audio_client_init_pdata(sdev, &pdata); + + return sof_client_dev_register(sdev, "audio", 0, + &pdata, sizeof(pdata)); +} +EXPORT_SYMBOL_NS_GPL(sof_register_audio_client, "SND_SOC_SOF_CLIENT"); + +void sof_unregister_audio_client(struct snd_sof_dev *sdev) +{ + sof_client_dev_unregister(sdev, "audio", 0); +} +EXPORT_SYMBOL_NS_GPL(sof_unregister_audio_client, "SND_SOC_SOF_CLIENT"); diff --git a/sound/soc/sof/sof-client.h b/sound/soc/sof/sof-client.h index cac3bb45d7652b..41f10b8774b94f 100644 --- a/sound/soc/sof/sof-client.h +++ b/sound/soc/sof/sof-client.h @@ -91,4 +91,13 @@ int sof_client_get_num_cores(struct sof_client_dev *cdev); int sof_client_machine_register(struct sof_client_dev *cdev); void sof_client_machine_unregister(struct sof_client_dev *cdev); +/* audio client pdata initialization */ +struct sof_audio_client_pdata; +void sof_audio_client_init_pdata(struct snd_sof_dev *sdev, + struct sof_audio_client_pdata *pdata); + +/* default audio client registration for vendor ops */ +int sof_register_audio_client(struct snd_sof_dev *sdev); +void sof_unregister_audio_client(struct snd_sof_dev *sdev); + #endif /* __SOC_SOF_CLIENT_H */ diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 6eef91b418a638..759c2f782f962c 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -395,6 +395,10 @@ struct snd_sof_dsp_ops { int (*register_ipc_clients)(struct snd_sof_dev *sdev); /* optional */ void (*unregister_ipc_clients)(struct snd_sof_dev *sdev); /* optional */ + /* audio client ops */ + int (*register_audio_client)(struct snd_sof_dev *sdev); /* mandatory */ + void (*unregister_audio_client)(struct snd_sof_dev *sdev); /* mandatory */ + /* DAI ops */ bool (*is_chain_dma_supported)(struct snd_sof_dev *sdev, u32 dai_type); /* optional */ @@ -612,12 +616,6 @@ struct snd_sof_dev { /* Main, Base firmware image */ struct sof_firmware basefw; - /* - * ASoC components. plat_drv fields are set dynamically so - * can't use const - */ - struct snd_soc_component_driver plat_drv; - /* current DSP power state */ struct sof_dsp_power_state dsp_power_state; /* mutex to protect the dsp_power_state access */ From bdb82875dde1970eff056358a0b261de0b0cac76 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 3 Jun 2026 14:10:44 +0300 Subject: [PATCH 75/83] ASoC: SOF: Register audio component on the auxiliary device Register the ASoC component on the sof-client auxiliary device (&cdev->auxdev.dev) instead of the parent DSP device (sdev->dev). This gives a natural path from the component to the client device: snd_soc_component_get_drvdata() returns the cdev directly. A new helper snd_sof_component_get_cdev() is added, and the existing snd_sof_component_get_sdev() is updated to go through the client device using sof_client_dev_to_sof_dev(). The machine driver platform name (mach_params.platform) is updated in sof_client_machine_register() to match the auxiliary device name, ensuring machine driver platform matching works correctly. The nocodec path is updated to receive the platform name as a parameter instead of hardcoding dev_name(dev->parent). Add sof_client_core_module_get/put calls in PCM open/close to ensure the core DSP driver module use count is incremented while audio is active. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/debug.c | 2 -- sound/soc/sof/nocodec.c | 14 +++++--- sound/soc/sof/pcm.c | 35 ++++++++++++++++-- sound/soc/sof/sof-audio.h | 8 ++++- sound/soc/sof/sof-client-audio.c | 62 +++++++++++++++++++++++++++++--- sound/soc/sof/sof-client-audio.h | 12 ++++++- sound/soc/sof/sof-client.c | 46 +++++++++++++++++++++--- sound/soc/sof/sof-client.h | 1 + sound/soc/sof/topology.c | 20 +++++++---- 9 files changed, 172 insertions(+), 28 deletions(-) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 9801c875dd7018..908462fec20c05 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -355,8 +355,6 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev) (char **)&plat_data->tplg_filename_prefix); debugfs_create_str("fw_name", 0444, fw_profile, (char **)&plat_data->fw_filename); - debugfs_create_str("tplg_name", 0444, fw_profile, - (char **)&plat_data->tplg_filename); debugfs_create_u32("ipc_type", 0444, fw_profile, (u32 *)&plat_data->ipc_type); diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c index c0c906a78ebae4..53a06b09a9d662 100644 --- a/sound/soc/sof/nocodec.c +++ b/sound/soc/sof/nocodec.c @@ -22,7 +22,8 @@ static struct snd_soc_card sof_nocodec_card = { static int sof_nocodec_bes_setup(struct device *dev, struct snd_soc_dai_driver *drv, struct snd_soc_dai_link *links, - int link_num, struct snd_soc_card *card) + int link_num, struct snd_soc_card *card, + const char *platform_name) { struct snd_soc_dai_link_component *dlc; int i; @@ -54,7 +55,7 @@ static int sof_nocodec_bes_setup(struct device *dev, links[i].id = i; links[i].no_pcm = 1; links[i].cpus->dai_name = drv[i].name; - links[i].platforms->name = dev_name(dev->parent); + links[i].platforms->name = platform_name; links[i].playback_only = drv[i].playback.channels_min && !drv[i].capture.channels_min; links[i].capture_only = !drv[i].playback.channels_min && drv[i].capture.channels_min; @@ -70,7 +71,8 @@ static int sof_nocodec_bes_setup(struct device *dev, static int sof_nocodec_setup(struct device *dev, u32 num_dai_drivers, - struct snd_soc_dai_driver *dai_drivers) + struct snd_soc_dai_driver *dai_drivers, + const char *platform_name) { struct snd_soc_dai_link *links; @@ -79,7 +81,8 @@ static int sof_nocodec_setup(struct device *dev, if (!links) return -ENOMEM; - return sof_nocodec_bes_setup(dev, dai_drivers, links, num_dai_drivers, &sof_nocodec_card); + return sof_nocodec_bes_setup(dev, dai_drivers, links, num_dai_drivers, + &sof_nocodec_card, platform_name); } static int sof_nocodec_probe(struct platform_device *pdev) @@ -93,7 +96,8 @@ static int sof_nocodec_probe(struct platform_device *pdev) mach = pdev->dev.platform_data; ret = sof_nocodec_setup(card->dev, mach->mach_params.num_dai_drivers, - mach->mach_params.dai_drivers); + mach->mach_params.dai_drivers, + mach->mach_params.platform); if (ret < 0) return ret; diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 0895097157b25f..6557da246c8bff 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -17,6 +17,8 @@ #include "sof-of-dev.h" #include "sof-priv.h" #include "sof-audio.h" +#include "sof-client.h" +#include "sof-client-audio.h" #include "sof-utils.h" #include "ops.h" @@ -546,6 +548,7 @@ static int sof_pcm_open(struct snd_soc_component *component, { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_pcm_runtime *runtime = substream->runtime; + struct sof_client_dev *cdev = snd_sof_component_get_cdev(component); struct snd_sof_audio_instance *ins = snd_sof_component_get_audio_instance(component); struct snd_sof_pcm *spcm; @@ -556,6 +559,10 @@ static int sof_pcm_open(struct snd_soc_component *component, if (rtd->dai_link->no_pcm) return 0; + ret = sof_client_core_module_get(cdev); + if (ret) + return ret; + spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) return -EINVAL; @@ -592,6 +599,7 @@ static int sof_pcm_open(struct snd_soc_component *component, if (ret < 0) { spcm_err(spcm, substream->stream, "platform pcm open failed %d\n", ret); + sof_client_core_module_put(cdev); return ret; } @@ -608,6 +616,7 @@ static int sof_pcm_close(struct snd_soc_component *component, struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct sof_client_dev *cdev = snd_sof_component_get_cdev(component); struct snd_sof_pcm *spcm; int err; @@ -633,6 +642,8 @@ static int sof_pcm_close(struct snd_soc_component *component, spcm->stream[substream->stream].substream = NULL; + sof_client_core_module_put(cdev); + return 0; } @@ -765,9 +776,12 @@ EXPORT_SYMBOL(sof_pcm_dai_link_fixup); static int sof_pcm_probe(struct snd_soc_component *component) { - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(component); + struct sof_client_dev *cdev = snd_sof_component_get_cdev(component); + struct sof_audio_client_pdata *audio_pdata = dev_get_platdata(&cdev->auxdev.dev); + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); struct snd_sof_pdata *plat_data = sdev->pdata; struct snd_sof_audio_instance *instance; + bool got_runtime_pm; const char *tplg_filename; int ret; @@ -784,11 +798,14 @@ static int sof_pcm_probe(struct snd_soc_component *component) snd_sof_audio_instance_unregister(instance); return ret; } + got_runtime_pm = ret >= 0; /* load the default topology */ tplg_filename = devm_kasprintf(component->dev, GFP_KERNEL, "%s/%s", plat_data->tplg_filename_prefix, + audio_pdata->machine.sof_tplg_filename ? + audio_pdata->machine.sof_tplg_filename : plat_data->tplg_filename); if (!tplg_filename) { ret = -ENOMEM; @@ -801,9 +818,21 @@ static int sof_pcm_probe(struct snd_soc_component *component) ret); out: - if (ret) + if (ret) { + /* + * Remove topology objects to prevent dangling references. + * When sof_complete() or a late topology file fails, DAIs from + * previously successful loads remain on the component's DAI + * list. Their driver structs are allocated under the card + * device (tplg->dev) which gets freed by devres when mc_probe + * fails, leaving dangling driver pointers. Subsequent card + * binding would crash iterating these DAIs. + */ + snd_soc_tplg_component_remove(component); snd_sof_audio_instance_unregister(instance); - pm_runtime_put_autosuspend(component->dev); + } + if (got_runtime_pm) + pm_runtime_put_autosuspend(component->dev); return ret; } diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 8c16b51f0a1721..77fc292566f1b2 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -635,10 +635,16 @@ snd_sof_find_swidget_sname(struct snd_soc_component *scomp, struct snd_sof_dai *snd_sof_find_dai(struct snd_soc_component *scomp, const char *name); +static inline struct sof_client_dev * +snd_sof_component_get_cdev(struct snd_soc_component *scomp) +{ + return snd_soc_component_get_drvdata(scomp); +} + static inline struct snd_sof_dev * snd_sof_component_get_sdev(struct snd_soc_component *scomp) { - return snd_soc_component_get_drvdata(scomp); + return sof_client_dev_to_sof_dev(snd_sof_component_get_cdev(scomp)); } struct snd_sof_audio_instance * diff --git a/sound/soc/sof/sof-client-audio.c b/sound/soc/sof/sof-client-audio.c index ec961dca4443f4..f5b0057926d081 100644 --- a/sound/soc/sof/sof-client-audio.c +++ b/sound/soc/sof/sof-client-audio.c @@ -6,41 +6,93 @@ // #include +#include #include +#include +#include #include #include "sof-client.h" #include "sof-client-audio.h" +#define SOF_AUDIO_SUSPEND_DELAY_MS 3000 + +static void sof_audio_client_init_debugfs(struct sof_client_dev *cdev, + struct sof_audio_client_pdata *pdata) +{ + struct dentry *debugfs_root = sof_client_get_debugfs_root(cdev); + char *debugfs_dir; + + debugfs_dir = devm_kasprintf(&cdev->auxdev.dev, GFP_KERNEL, "audio.%u", + cdev->auxdev.id); + if (!debugfs_dir) + return; + + pdata->debugfs_root = debugfs_create_dir(debugfs_dir, debugfs_root); + if (IS_ERR_OR_NULL(pdata->debugfs_root)) + return; + + pdata->debug_topology_name = pdata->machine.sof_tplg_filename ? + pdata->machine.sof_tplg_filename : + sof_client_get_topology_name(cdev); + pdata->debug_card_name = pdata->machine.mach_params.card_name; + pdata->debug_machine_driver = pdata->machine.drv_name; + + debugfs_create_str("topology_name", 0444, pdata->debugfs_root, + (char **)&pdata->debug_topology_name); + + if (pdata->debug_card_name) + debugfs_create_str("card_name", 0444, pdata->debugfs_root, + (char **)&pdata->debug_card_name); + + if (pdata->debug_machine_driver) + debugfs_create_str("machine_driver", 0444, pdata->debugfs_root, + (char **)&pdata->debug_machine_driver); +} + static int sof_audio_client_probe(struct auxiliary_device *auxdev, const struct auxiliary_device_id *id) { struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev); struct sof_audio_client_pdata *pdata = dev_get_platdata(&auxdev->dev); - struct device *dma_dev = sof_client_get_dma_dev(cdev); int ret; - ret = snd_soc_register_component(dma_dev, &pdata->plat_drv, + auxiliary_set_drvdata(auxdev, cdev); + + ret = snd_soc_register_component(&auxdev->dev, &pdata->plat_drv, pdata->drv, pdata->num_drv); if (ret < 0) return ret; ret = sof_client_machine_register(cdev); if (ret < 0) { - snd_soc_unregister_component(dma_dev); + snd_soc_unregister_component(&auxdev->dev); return ret; } + sof_audio_client_init_debugfs(cdev, pdata); + + pm_runtime_set_autosuspend_delay(&auxdev->dev, SOF_AUDIO_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(&auxdev->dev); + pm_runtime_enable(&auxdev->dev); + pm_runtime_mark_last_busy(&auxdev->dev); + pm_runtime_idle(&auxdev->dev); + return 0; } static void sof_audio_client_remove(struct auxiliary_device *auxdev) { struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev); - struct device *dma_dev = sof_client_get_dma_dev(cdev); + struct sof_audio_client_pdata *pdata = dev_get_platdata(&auxdev->dev); + + if (pdata && pdata->debugfs_root) + debugfs_remove_recursive(pdata->debugfs_root); + + pm_runtime_disable(&auxdev->dev); sof_client_machine_unregister(cdev); - snd_soc_unregister_component(dma_dev); + snd_soc_unregister_component(&auxdev->dev); } static const struct auxiliary_device_id sof_audio_client_id_table[] = { diff --git a/sound/soc/sof/sof-client-audio.h b/sound/soc/sof/sof-client-audio.h index 0e844ac8df540d..9db10aa7889ada 100644 --- a/sound/soc/sof/sof-client-audio.h +++ b/sound/soc/sof/sof-client-audio.h @@ -5,18 +5,28 @@ #include +struct dentry; + /** * struct sof_audio_client_pdata - platform data for the audio sof-client * @plat_drv: Pre-built ASoC component driver * @drv: Array of DAI drivers to register * @num_drv: Number of DAI drivers * @machine: Per-instance copy of the machine descriptor + * @debugfs_root: Per-audio-client debugfs directory + * @debug_topology_name: Topology loaded by this audio client + * @debug_card_name: Card name for this audio client + * @debug_machine_driver: Machine driver bound to this audio client */ struct sof_audio_client_pdata { - const struct snd_soc_component_driver plat_drv; + struct snd_soc_component_driver plat_drv; struct snd_soc_dai_driver *drv; int num_drv; struct snd_soc_acpi_mach machine; + struct dentry *debugfs_root; + const char *debug_topology_name; + const char *debug_card_name; + const char *debug_machine_driver; }; #endif /* __SOF_CLIENT_AUDIO_H */ diff --git a/sound/soc/sof/sof-client.c b/sound/soc/sof/sof-client.c index 1ab8c01790469b..d6db4edda85741 100644 --- a/sound/soc/sof/sof-client.c +++ b/sound/soc/sof/sof-client.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include "ops.h" @@ -534,6 +535,14 @@ enum sof_ipc_type sof_client_get_ipc_type(struct sof_client_dev *cdev) } EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_type, "SND_SOC_SOF_CLIENT"); +const char *sof_client_get_topology_name(struct sof_client_dev *cdev) +{ + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + + return sdev->pdata->tplg_filename; +} +EXPORT_SYMBOL_NS_GPL(sof_client_get_topology_name, "SND_SOC_SOF_CLIENT"); + int sof_client_boot_dsp(struct sof_client_dev *cdev) { return snd_sof_boot_dsp_firmware(sof_client_dev_to_sof_dev(cdev)); @@ -744,8 +753,39 @@ EXPORT_SYMBOL_NS_GPL(sof_client_get_num_cores, "SND_SOC_SOF_CLIENT"); int sof_client_machine_register(struct sof_client_dev *cdev) { struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + struct sof_audio_client_pdata *pdata = dev_get_platdata(&cdev->auxdev.dev); + struct snd_sof_pdata *spdata = sdev->pdata; + struct snd_soc_acpi_mach *mach; + struct platform_device *pdev; + + /* Per-client machine: register a dedicated machine device */ + if (pdata->machine.drv_name) { + mach = &pdata->machine; + mach->mach_params.platform = dev_name(&cdev->auxdev.dev); + + pdev = platform_device_register_data(sdev->dev, + mach->drv_name, + PLATFORM_DEVID_AUTO, + mach, sizeof(*mach)); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + pdata->plat_drv.ignore_machine = dev_name(&pdev->dev); + cdev->data = pdev; + + return 0; + } + + /* + * Legacy: use shared machine from sdev. + * Update the platform name to match the audio component's device so + * that machine drivers can find the SOF platform component. + */ + mach = (struct snd_soc_acpi_mach *)spdata->machine; + if (mach) + mach->mach_params.platform = dev_name(&cdev->auxdev.dev); - return snd_sof_machine_register(sdev, sdev->pdata); + return snd_sof_machine_register(sdev, spdata); } EXPORT_SYMBOL_NS_GPL(sof_client_machine_register, "SND_SOC_SOF_CLIENT"); @@ -766,10 +806,8 @@ EXPORT_SYMBOL_NS_GPL(sof_client_machine_unregister, "SND_SOC_SOF_CLIENT"); void sof_audio_client_init_pdata(struct snd_sof_dev *sdev, struct sof_audio_client_pdata *pdata) { - void *plat_drv = (void *)&pdata->plat_drv; - memset(pdata, 0, sizeof(*pdata)); - snd_sof_new_platform_drv(sdev, plat_drv); + snd_sof_new_platform_drv(sdev, &pdata->plat_drv); pdata->drv = sdev->audio_ops->drv; pdata->num_drv = sdev->audio_ops->num_drv; } diff --git a/sound/soc/sof/sof-client.h b/sound/soc/sof/sof-client.h index 41f10b8774b94f..fbb2fb3e4806fc 100644 --- a/sound/soc/sof/sof-client.h +++ b/sound/soc/sof/sof-client.h @@ -49,6 +49,7 @@ struct device *sof_client_get_dma_dev(struct sof_client_dev *cdev); const struct sof_ipc_fw_version *sof_client_get_fw_version(struct sof_client_dev *cdev); size_t sof_client_get_ipc_max_payload_size(struct sof_client_dev *cdev); enum sof_ipc_type sof_client_get_ipc_type(struct sof_client_dev *cdev); +const char *sof_client_get_topology_name(struct sof_client_dev *cdev); /* DSP/firmware boot request */ int sof_client_boot_dsp(struct sof_client_dev *cdev); diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 6a4c0ab16d7d2f..b03ca15ecca772 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -17,6 +17,8 @@ #include #include "sof-priv.h" #include "sof-audio.h" +#include "sof-client.h" +#include "sof-client-audio.h" #include "ops.h" static bool disable_function_topology; @@ -2516,8 +2518,12 @@ static const struct snd_soc_tplg_ops sof_dspless_tplg_ops = { int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file) { - struct snd_sof_dev *sdev = snd_sof_component_get_sdev(scomp); + struct sof_client_dev *cdev = snd_sof_component_get_cdev(scomp); + struct sof_audio_client_pdata *audio_pdata = dev_get_platdata(&cdev->auxdev.dev); + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); struct snd_sof_pdata *sof_pdata = sdev->pdata; + const struct snd_soc_acpi_mach *mach = audio_pdata->machine.drv_name ? + &audio_pdata->machine : sof_pdata->machine; const char *tplg_filename_prefix = sof_pdata->tplg_filename_prefix; const struct firmware *fw; const char **tplg_files; @@ -2531,7 +2537,7 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file) /* Try to use function topologies if possible */ if (!sof_pdata->disable_function_topology && !disable_function_topology && - sof_pdata->machine && sof_pdata->machine->get_function_tplg_files) { + mach && mach->get_function_tplg_files) { /* * When the topology name contains 'dummy' word, it means that * there is no fallback option to monolithic topology in case @@ -2546,11 +2552,11 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file) */ bool no_fallback = strstr(file, "dummy"); - tplg_cnt = sof_pdata->machine->get_function_tplg_files(scomp->card, - sof_pdata->machine, - tplg_filename_prefix, - &tplg_files, - no_fallback); + tplg_cnt = mach->get_function_tplg_files(scomp->card, + mach, + tplg_filename_prefix, + &tplg_files, + no_fallback); if (tplg_cnt < 0) { kfree(tplg_files); return tplg_cnt; From e49e2332348d44ce1abd0f0e2c9cef517ef45048 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 3 Jun 2026 19:53:53 +0300 Subject: [PATCH 76/83] ASoC: Intel: sof-function-topology-lib: skip unsupported DAI links When a function topology does not support a DAI link, continue to the next one instead of failing the entire topology load. This allows partial topology loading where not all DAI links have matching function topologies. Signed-off-by: Peter Ujfalusi --- sound/soc/intel/common/sof-function-topology-lib.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/common/sof-function-topology-lib.c b/sound/soc/intel/common/sof-function-topology-lib.c index b6e5a40b78cc60..d2e1d953e01814 100644 --- a/sound/soc/intel/common/sof-function-topology-lib.c +++ b/sound/soc/intel/common/sof-function-topology-lib.c @@ -46,6 +46,11 @@ int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_ int ret; int i; + if (!mach || !mach->sof_tplg_filename) { + dev_err(card->dev, "Missing base topology filename for function topology\n"); + return -EINVAL; + } + ret = sscanf(mach->sof_tplg_filename, "sof-%3s-*.tplg", platform); if (ret != 1) { dev_err(card->dev, "Invalid platform name %s of tplg %s\n", @@ -101,10 +106,7 @@ int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_ dev_dbg(card->dev, "dai_link %s is not supported by separated tplg yet\n", dai_link->name); - if (best_effort) - continue; - - return 0; + continue; } if (tplg_mask & BIT(tplg_dev)) continue; From 6186cb5cd1871699087d1463496f4e90bd38ff15 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 3 Jun 2026 19:54:03 +0300 Subject: [PATCH 77/83] ASoC: core: scope CPU DAI override to component-owned DAIs When soc_check_tplg_fes() overrides BE DAI link CPU component names, only set cpu->name when the DAI is actually registered by the matching component. This prevents cross-component DAI binding issues when multiple components provide identically-named DAIs (e.g., SDW DAIs in soundwire_intel vs SOF audio components). Signed-off-by: Peter Ujfalusi --- sound/soc/soc-core.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3a9342633c4e65..c7caaa1c01a72f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1987,6 +1987,7 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) struct snd_soc_component *component; const struct snd_soc_component_driver *comp_drv; struct snd_soc_dai_link *dai_link; + struct snd_soc_dai_link_component *cpu; int i; for_each_component(component) { @@ -2021,11 +2022,35 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) continue; } - if (component->dev->of_node) + if (component->dev->of_node) { dai_link->platforms->of_node = component->dev->of_node; - else + } else { + struct snd_soc_dai *dai; + int j; + dai_link->platforms->name = component->name; + /* + * Override CPU component name to ensure the + * correct component is matched when multiple + * components provide identically-named DAIs. + * Only override when the DAI is actually + * provided by this component. + */ + for_each_link_cpus(dai_link, j, cpu) { + if (cpu->of_node) + continue; + + for_each_component_dais(component, dai) { + if (cpu->dai_name && + !strcmp(dai->name, cpu->dai_name)) { + cpu->name = component->name; + break; + } + } + } + } + /* convert non BE into BE */ dai_link->no_pcm = 1; From cc75c5e9f2c6908ad2a8ce68a19f42bf8030b28a Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 9 Jun 2026 09:36:17 +0300 Subject: [PATCH 78/83] ASoC: Intel: sof_sdw: add multi-card support Add card_name and dai_type_mask fields to snd_soc_acpi_mach_params to allow per-instance card naming and DAI type filtering. Use card_name in mc_probe() to set the card name when provided. Signed-off-by: Peter Ujfalusi --- include/sound/soc-acpi.h | 2 ++ sound/soc/intel/boards/sof_sdw.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 0519afd7217f13..6b6d9557a4e90b 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -90,6 +90,8 @@ struct snd_soc_acpi_mach_params { unsigned short subsystem_rev; bool subsystem_id_set; u32 bt_link_mask; + const char *card_name; + u32 dai_type_mask; }; /** diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index d5383c8dcdf099..9807090bddd6f8 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1482,7 +1482,8 @@ static int mc_probe(struct platform_device *pdev) ctx->codec_info_list_count = asoc_sdw_get_codec_info_list_count(); card = &ctx->card; card->dev = &pdev->dev; - card->name = "soundwire"; + card->name = mach->mach_params.card_name ? + mach->mach_params.card_name : "soundwire"; card->owner = THIS_MODULE; card->late_probe = sof_sdw_card_late_probe; card->add_dai_link = sof_sdw_add_dai_link; From 3ef4c73a2765fd4ba2a716110655577f85a7f3f1 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 4 Jun 2026 15:54:44 +0300 Subject: [PATCH 79/83] ASoC: sdw_utils: add dai_type_mask filtering for multi-card support Add dai_type_mask field filtering in asoc_sdw_count_sdw_endpoints() and asoc_sdw_parse_sdw_endpoints() to allow multi-card configurations to include only specific DAI types. When dai_type_mask is non-zero, only codec endpoints with matching dai_type bits are counted and parsed. Auxiliary devices for codecs without matching endpoints are also skipped. Signed-off-by: Peter Ujfalusi --- sound/soc/sdw_utils/soc_sdw_utils.c | 89 ++++++++++++++++++++++------- 1 file changed, 68 insertions(+), 21 deletions(-) diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c index 5de33ff0ae7cb7..1269447a787b69 100644 --- a/sound/soc/sdw_utils/soc_sdw_utils.c +++ b/sound/soc/sdw_utils/soc_sdw_utils.c @@ -82,7 +82,10 @@ struct asoc_sdw_codec_info codec_info_list[] = { .direction = {true, false}, .dai_name = "tac5xx2-aif1", .dai_type = SOC_SDW_DAI_TYPE_AMP, - .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, + .dailink = { + SOC_SDW_AMP_OUT_DAI_ID, + SOC_SDW_UNUSED_DAI_ID, + }, .init = asoc_sdw_ti_amp_init, .rtd_init = asoc_sdw_ti_tac5xx2_spk_rtd_init, .controls = lr_spk_controls, @@ -103,7 +106,10 @@ struct asoc_sdw_codec_info codec_info_list[] = { .direction = {true, true}, .dai_name = "tac5xx2-aif3", .dai_type = SOC_SDW_DAI_TYPE_JACK, - .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + .dailink = { + SOC_SDW_JACK_OUT_DAI_ID, + SOC_SDW_JACK_IN_DAI_ID, + }, .controls = generic_jack_controls, .num_controls = ARRAY_SIZE(generic_jack_controls), .widgets = generic_jack_widgets, @@ -1829,6 +1835,29 @@ static int is_sdca_aux_dev_present(struct device *dev, return ret; } +/* + * Check if a codec device has any endpoints matching the dai_type_mask. + * Returns true if no filtering (mask == 0) or at least one endpoint matches. + */ +static bool adr_dev_matches_dai_type_mask(const struct snd_soc_acpi_adr_device *adr_dev, + struct asoc_sdw_codec_info *codec_info, + u32 dai_type_mask) +{ + int j; + + if (!dai_type_mask) + return true; + + for (j = 0; j < adr_dev->num_endpoints; j++) { + int ep_num = adr_dev->endpoints[j].num; + + if (ep_num < codec_info->dai_num && + (dai_type_mask & BIT(codec_info->dais[ep_num].dai_type))) + return true; + } + return false; +} + int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends, int *num_aux) { @@ -1851,6 +1880,11 @@ int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, if (!codec_info) return -EINVAL; + /* Skip aux devices for codecs with no matching endpoints */ + if (!adr_dev_matches_dai_type_mask(adr_dev, codec_info, + mach_params->dai_type_mask)) + continue; + for (j = 0; j < codec_info->aux_num; j++) { ret = is_sdca_aux_dev_present(dev, codec_info->auxs[j].codec_name, adr_link, i); @@ -2015,29 +2049,34 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, if (!codec_info) return -EINVAL; - for (j = 0; j < codec_info->aux_num; j++) { - struct snd_soc_component *component; + /* Skip aux devices for codecs with no matching endpoints */ + if (adr_dev_matches_dai_type_mask(adr_dev, codec_info, + mach_params->dai_type_mask)) { + for (j = 0; j < codec_info->aux_num; j++) { + struct snd_soc_component *component; + const char *aux_name = codec_info->auxs[j].codec_name; - ret = is_sdca_aux_dev_present(dev, codec_info->auxs[j].codec_name, - adr_link, i); - if (ret < 0) - return ret; + ret = is_sdca_aux_dev_present(dev, aux_name, adr_link, i); + if (ret < 0) + return ret; - if (ret == 0) - continue; + if (ret == 0) + continue; - component = snd_soc_lookup_component_by_name(codec_info->auxs[j].codec_name); - if (component) { - dev_dbg(dev, "%s found component %s for aux name %s\n", - __func__, component->name, - codec_info->auxs[j].codec_name); - soc_aux->dlc.name = component->name; - } else { - dev_dbg(dev, "%s the aux component %s is not registered yet\n", - __func__, codec_info->auxs[j].codec_name); - return -EPROBE_DEFER; + component = snd_soc_lookup_component_by_name(aux_name); + if (component) { + dev_dbg(dev, + "found component %s for aux name %s\n", + component->name, aux_name); + soc_aux->dlc.name = component->name; + } else { + dev_dbg(dev, + "aux component %s is not registered yet\n", + aux_name); + return -EPROBE_DEFER; + } + soc_aux++; } - soc_aux++; } ctx->ignore_internal_dmic |= codec_info->ignore_internal_dmic; @@ -2061,6 +2100,14 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, adr_end = &adr_dev->endpoints[j]; dai_info = &codec_info->dais[adr_end->num]; + + /* Filter by DAI type if mask is set */ + if (mach_params->dai_type_mask && + !(mach_params->dai_type_mask & BIT(dai_info->dai_type))) { + (*num_devs)--; + continue; + } + soc_dai = asoc_sdw_find_dailink(soc_dais, adr_end); /* From 3e74fdd5a73637db1de2f5b13e8ba29bc017a78a Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 5 Jun 2026 11:40:19 +0300 Subject: [PATCH 80/83] ASoC: SOF: topology: skip feature topologies without matching BE DAI links Before loading a user-specified feature topology, verify that the card has a matching BE DAI link. Feature topologies extend specific codec function types (amp, jack, mic) and reference widgets that only exist when the corresponding BE DAI links are present. Without this check, loading an amplifier feature topology on a card without SmartAmp DAI links would fail with -EINVAL due to missing route endpoints, killing the entire card probe. This is needed for multi-card configurations where cards are split by function type, but also provides a safety net in single-card mode when feature topologies don't match the hardware. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/topology.c | 63 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index b03ca15ecca772..3fb10de64c569d 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2516,6 +2516,47 @@ static const struct snd_soc_tplg_ops sof_dspless_tplg_ops = { .bytes_ext_ops_count = ARRAY_SIZE(sof_dspless_bytes_ext_ops), }; +/* + * Check if a feature topology is compatible with the current card by + * verifying that matching BE DAI links exist. + * + * Feature topologies extend specific codec function types. If the card + * doesn't have the corresponding BE DAI links, the topology load would + * fail due to missing routes/widgets. This works transparently for both + * multi-card and single-card configurations. + */ +static bool +sof_feature_tplg_matches_card(struct snd_soc_component *scomp, + const char *feature_tplg) +{ + static const struct { + const char *tplg_key; /* substring in feature topology filename */ + const char *dai_key; /* substring in BE DAI link name */ + } match_table[] = { + { "amp", "SmartAmp" }, + { "jack", "SimpleJack" }, + { "mic", "SmartMic" }, + }; + struct snd_soc_dai_link *dai_link; + bool needs_match = false; + int i, j; + + for (i = 0; i < ARRAY_SIZE(match_table); i++) { + if (!strstr(feature_tplg, match_table[i].tplg_key)) + continue; + + needs_match = true; + + for_each_card_prelinks(scomp->card, j, dai_link) { + if (strstr(dai_link->name, match_table[i].dai_key)) + return true; + } + } + + /* Unknown feature type: load it (backwards compatible) */ + return !needs_match; +} + int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file) { struct sof_client_dev *cdev = snd_sof_component_get_cdev(scomp); @@ -2612,11 +2653,25 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file) } } - /* Loading user defined topologies */ + /* + * Loading user defined feature topologies. + * Each feature topology extends a specific function type (amp, jack, + * mic, etc.). Only load if the card has a matching BE DAI link, + * otherwise the routes would fail due to missing widgets. + */ for (i = 0; i < feature_tplg_cnt; i++) { - const char *feature_topology = devm_kasprintf(scomp->dev, GFP_KERNEL, "%s/%s", - tplg_filename_prefix, - feature_topologies[i]); + const char *feature_topology; + + if (!sof_feature_tplg_matches_card(scomp, feature_topologies[i])) { + dev_dbg(scomp->dev, + "skip feature topology %s: no matching BE DAI link\n", + feature_topologies[i]); + continue; + } + + feature_topology = devm_kasprintf(scomp->dev, GFP_KERNEL, "%s/%s", + tplg_filename_prefix, + feature_topologies[i]); if (!feature_topology) { ret = -ENOMEM; From 95a3072f4b32aa483495a6b4bc26aa0287cbfc69 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 3 Jun 2026 19:54:25 +0300 Subject: [PATCH 81/83] ASoC: SOF: Intel: HDA: add multi-card audio client registration Add Intel-specific multi-card audio client registration that creates separate sound cards per codec function type when the multi_card module parameter is set. The registration groups SoundWire endpoints by DAI type (jack, amp, mic) and creates a card per group using codec-specific names (e.g. cs42l43, cs35l56) with a generic function name fallback (jack, speaker, mic). DMIC and HDMI are registered as additional separate cards. Individual card registration failures are non-fatal to allow partial audio functionality when some components fail to probe. When multi_card is not set (default), falls back to the generic single-card sof_register_audio_client(). This is experimental and opt-in via: modprobe snd-sof-intel-hda-generic multi_card=1 Signed-off-by: Peter Ujfalusi --- sound/soc/sof/intel/hda-common-ops.c | 4 +- sound/soc/sof/intel/hda.c | 237 +++++++++++++++++++++++++++ sound/soc/sof/intel/hda.h | 7 + 3 files changed, 246 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-common-ops.c b/sound/soc/sof/intel/hda-common-ops.c index d5c77f739bc514..7331160a68c382 100644 --- a/sound/soc/sof/intel/hda-common-ops.c +++ b/sound/soc/sof/intel/hda-common-ops.c @@ -106,8 +106,8 @@ const struct snd_sof_dsp_ops sof_hda_common_ops = { .unregister_ipc_clients = hda_unregister_clients, /* audio client */ - .register_audio_client = sof_register_audio_client, - .unregister_audio_client = sof_unregister_audio_client, + .register_audio_client = hda_register_audio_client, + .unregister_audio_client = hda_unregister_audio_client, /* DAI drivers */ .is_chain_dma_supported = hda_is_chain_dma_supported, diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index ca04651d975718..fba00096ce14a4 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -31,6 +31,8 @@ #include #include #include "../sof-audio.h" +#include "../sof-client.h" +#include "../sof-client-audio.h" #include "../sof-pci-dev.h" #include "../ops.h" #include "../ipc4-topology.h" @@ -1767,6 +1769,241 @@ int hda_pci_intel_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) } EXPORT_SYMBOL_NS(hda_pci_intel_probe, "SND_SOC_SOF_INTEL_HDA_GENERIC"); +static bool multi_card; +module_param(multi_card, bool, 0444); +MODULE_PARM_DESC(multi_card, "Split audio into per-function cards. Experimental."); + +struct hda_sdw_func_card { + u32 dai_type_bit; + const char *card_name; +}; + +static const struct hda_sdw_func_card sdw_func_cards[] = { + { BIT(SOC_SDW_DAI_TYPE_JACK), "jack" }, + { BIT(SOC_SDW_DAI_TYPE_AMP), "speaker" }, + { BIT(SOC_SDW_DAI_TYPE_MIC), "mic" }, +}; + +/* + * Group SDW DAI types that share physical codec devices. Types on the + * same device must be on the same card because ASoC components can only + * be bound to one card. + * + * Returns the number of groups. Each group's merged DAI type bitmask + * is stored in groups[] and the representative codec name in names[]. + */ +static int hda_sdw_group_dai_types(const struct snd_soc_acpi_mach *mach, + u32 *groups, const char **names, + int max_groups) +{ + const struct snd_soc_acpi_link_adr *adr_link; + int num_groups = 0; + int i, j, k; + + for (adr_link = mach->mach_params.links; + adr_link && adr_link->num_adr; adr_link++) { + for (i = 0; i < adr_link->num_adr; i++) { + const struct snd_soc_acpi_adr_device *adr_dev = + &adr_link->adr_d[i]; + struct asoc_sdw_codec_info *codec_info; + const char *dev_name = NULL; + u32 dev_types = 0; + int merged = -1; + + codec_info = asoc_sdw_find_codec_info_part(adr_dev->adr); + if (!codec_info) + continue; + + for (j = 0; j < adr_dev->num_endpoints; j++) { + int ep_num = adr_dev->endpoints[j].num; + + if (ep_num < codec_info->dai_num) + dev_types |= + BIT(codec_info->dais[ep_num].dai_type); + } + + if (!dev_types) + continue; + + /* + * Pick a representative codec name: prefer + * name_prefix for non-amp codecs, fall back to + * the first DAI's component_name for amps. + */ + if (!codec_info->is_amp) + dev_name = codec_info->name_prefix; + else if (codec_info->dai_num && + codec_info->dais[0].component_name) + dev_name = codec_info->dais[0].component_name; + + /* Merge with any existing group that overlaps */ + for (k = 0; k < num_groups; k++) { + if (!(groups[k] & dev_types)) + continue; + + if (merged < 0) { + groups[k] |= dev_types; + if (dev_name) + names[k] = dev_name; + merged = k; + } else { + groups[merged] |= groups[k]; + groups[k] = groups[--num_groups]; + names[k] = names[num_groups]; + k--; + } + } + + if (merged < 0 && num_groups < max_groups) { + groups[num_groups] = dev_types; + names[num_groups] = dev_name; + num_groups++; + } + } + } + + return num_groups; +} + +static int hda_register_audio_client_multi(struct snd_sof_dev *sdev) +{ + static const struct snd_soc_acpi_link_adr empty_links[] = { {} }; + const struct snd_soc_acpi_mach *mach = sdev->pdata->machine; + struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; + struct sof_audio_client_pdata pdata; + u32 dai_groups[ARRAY_SIZE(sdw_func_cards)]; + const char *group_names[ARRAY_SIZE(sdw_func_cards)]; + int num_groups; + int card_idx = 0; + int ret, i, j; + + if (!mach) + return -ENODEV; + + num_groups = hda_sdw_group_dai_types(mach, dai_groups, group_names, + ARRAY_SIZE(dai_groups)); + + dev_dbg(sdev->dev, "multi_card: %d SDW groups, dmic: %d, idisp: %s\n", + num_groups, mach->mach_params.dmic_num, + HDA_IDISP_CODEC(mach->mach_params.codec_mask) ? "yes" : "no"); + + sof_audio_client_init_pdata(sdev, &pdata); + + /* Create one card per SDW DAI type group */ + for (i = 0; i < num_groups; i++) { + const char *card_name; + + /* + * Prefer codec device name (e.g. "cs42l43") over the + * generic function type name (e.g. "jack"). + */ + card_name = group_names[i]; + if (!card_name) { + for (j = 0; j < ARRAY_SIZE(sdw_func_cards); j++) { + if (dai_groups[i] & sdw_func_cards[j].dai_type_bit) { + card_name = sdw_func_cards[j].card_name; + break; + } + } + } + if (!card_name) + continue; + + dev_dbg(sdev->dev, "multi_card: group %d mask %#x card %s\n", + i, dai_groups[i], card_name); + + memcpy(&pdata.machine, mach, sizeof(pdata.machine)); + pdata.machine.mach_params.dai_type_mask = dai_groups[i]; + pdata.machine.mach_params.codec_mask &= ~BIT(HDA_IDISP_ADDR); + pdata.machine.mach_params.dmic_num = 0; + pdata.machine.mach_params.card_name = card_name; + ret = sof_client_dev_register(sdev, "audio", card_idx, + &pdata, sizeof(pdata)); + if (ret) { + dev_warn(sdev->dev, + "multi_card: failed to register card %s: %d\n", + card_name, ret); + continue; + } + card_idx++; + } + + /* DMIC card */ + if (mach->mach_params.dmic_num) { + memcpy(&pdata.machine, mach, sizeof(pdata.machine)); + pdata.machine.mach_params.links = empty_links; + pdata.machine.mach_params.link_mask = 0; + pdata.machine.mach_params.codec_mask &= ~BIT(HDA_IDISP_ADDR); + pdata.machine.mach_params.card_name = "dmic"; + ret = sof_client_dev_register(sdev, "audio", card_idx, + &pdata, sizeof(pdata)); + if (ret) + dev_warn(sdev->dev, + "multi_card: failed to register card dmic: %d\n", + ret); + else + card_idx++; + } + + /* HDMI card */ + if (HDA_IDISP_CODEC(mach->mach_params.codec_mask)) { + memcpy(&pdata.machine, mach, sizeof(pdata.machine)); + pdata.machine.mach_params.links = empty_links; + pdata.machine.mach_params.link_mask = 0; + pdata.machine.mach_params.codec_mask = BIT(HDA_IDISP_ADDR); + pdata.machine.mach_params.dmic_num = 0; + pdata.machine.mach_params.card_name = "hdmi"; + ret = sof_client_dev_register(sdev, "audio", card_idx, + &pdata, sizeof(pdata)); + if (ret) + dev_warn(sdev->dev, + "multi_card: failed to register card hdmi: %d\n", + ret); + else + card_idx++; + } + + hdev->num_audio_clients = card_idx; + + return 0; +} + +int hda_register_audio_client(struct snd_sof_dev *sdev) +{ + if (multi_card) { + const struct snd_soc_acpi_mach *mach = sdev->pdata->machine; + + if (mach && !sdev->pdata->disable_function_topology && + mach->get_function_tplg_files) + return hda_register_audio_client_multi(sdev); + + dev_warn(sdev->dev, + "multi_card is only supported with function topologies, using single card\n"); + } + + return sof_register_audio_client(sdev); +} + +void hda_unregister_audio_client(struct snd_sof_dev *sdev) +{ + if (multi_card) { + const struct snd_soc_acpi_mach *mach = sdev->pdata->machine; + + if (mach && !sdev->pdata->disable_function_topology && + mach->get_function_tplg_files) { + struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; + int i; + + for (i = hdev->num_audio_clients - 1; i >= 0; i--) + sof_client_dev_unregister(sdev, "audio", i); + hdev->num_audio_clients = 0; + return; + } + } + + sof_unregister_audio_client(sdev); +} + int hda_register_clients(struct snd_sof_dev *sdev) { return hda_probes_register(sdev); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 4edb3ac4473a71..5e7d0505a534ee 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -580,6 +580,9 @@ struct sof_intel_hda_dev { * is received from the DSP for the previous message) */ struct snd_sof_ipc_msg *delayed_ipc_tx_msg; + + /* number of audio client devices registered in multi-card mode */ + int num_audio_clients; }; static inline struct hdac_bus *sof_to_bus(struct snd_sof_dev *s) @@ -1012,6 +1015,10 @@ static inline void hda_probes_unregister(struct snd_sof_dev *sdev) int hda_register_clients(struct snd_sof_dev *sdev); void hda_unregister_clients(struct snd_sof_dev *sdev); +/* SOF audio client registration for HDA platforms (multi-card) */ +int hda_register_audio_client(struct snd_sof_dev *sdev); +void hda_unregister_audio_client(struct snd_sof_dev *sdev); + /* machine driver select */ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev); void hda_set_mach_params(struct snd_soc_acpi_mach *mach, From ac06cdfce68161839c63eafe80612cb0cbfd64fb Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 9 Jun 2026 09:19:20 +0300 Subject: [PATCH 82/83] ASoC: Intel: skl_hda_dsp_generic: use mach params for card setup Use mach_params.card_name when provided. Propagate mach_params.dmic_num to ctx->dmic_be_num. Machine data then controls DMIC BE exposure in this card. This enables per-audio-client card setup for split configurations. Signed-off-by: Peter Ujfalusi --- sound/soc/intel/boards/skl_hda_dsp_generic.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index 519218385fdf74..7d75f9a4cdb27f 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -109,7 +109,8 @@ static int skl_hda_audio_probe(struct platform_device *pdev) if (!card) return -ENOMEM; - card->name = "hda-dsp"; + card->name = mach->mach_params.card_name ? + mach->mach_params.card_name : "hda-dsp"; card->owner = THIS_MODULE; card->fully_routed = true; card->late_probe = skl_hda_card_late_probe; @@ -128,6 +129,8 @@ static int skl_hda_audio_probe(struct platform_device *pdev) if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) ctx->hdmi.idisp_codec = true; + ctx->dmic_be_num = mach->mach_params.dmic_num; + ctx->link_order_overwrite = HDA_LINK_ORDER; ctx->link_id_overwrite = HDA_LINK_IDS; From 4d8743328f4a47d316ca15df57262fa42c5be353 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 11 Jun 2026 11:38:31 +0300 Subject: [PATCH 83/83] ASoC: SOF: Intel: hda: add split_hdmi audio-client mode Add split_hdmi mode to register separate analog and HDMI audio clients when iDisp is present. Keep the analog card on the selected machine configuration with iDisp masked out, and register HDMI as a dedicated generic HDA card using sof-hda-generic-idisp.tplg. Update unregister handling to support split fallback to the legacy single-client path when split registration is not used. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/intel/hda.c | 128 ++++++++++++++++++++++++++++++++++---- 1 file changed, 116 insertions(+), 12 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index fba00096ce14a4..1b861bd58f8604 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1773,6 +1773,10 @@ static bool multi_card; module_param(multi_card, bool, 0444); MODULE_PARM_DESC(multi_card, "Split audio into per-function cards. Experimental."); +static bool split_hdmi; +module_param(split_hdmi, bool, 0444); +MODULE_PARM_DESC(split_hdmi, "Split monolithic audio into analog/HDMI cards."); + struct hda_sdw_func_card { u32 dai_type_bit; const char *card_name; @@ -1784,6 +1788,28 @@ static const struct hda_sdw_func_card sdw_func_cards[] = { { BIT(SOC_SDW_DAI_TYPE_MIC), "mic" }, }; +static int hda_register_hdmi_audio_client(struct snd_sof_dev *sdev, + const struct snd_soc_acpi_mach *mach, + int card_idx) +{ + static const struct snd_soc_acpi_link_adr empty_links[] = { {} }; + struct sof_audio_client_pdata pdata; + + sof_audio_client_init_pdata(sdev, &pdata); + memcpy(&pdata.machine, mach, sizeof(pdata.machine)); + pdata.machine.mach_params.links = empty_links; + pdata.machine.mach_params.link_mask = 0; + pdata.machine.mach_params.codec_mask = BIT(HDA_IDISP_ADDR); + pdata.machine.mach_params.dmic_num = 0; + pdata.machine.mach_params.card_name = "hdmi"; + /* Always use a dedicated HDA generic HDMI card. */ + pdata.machine.get_function_tplg_files = NULL; + pdata.machine.drv_name = "skl_hda_dsp_generic"; + pdata.machine.sof_tplg_filename = "sof-hda-generic-idisp.tplg"; + + return sof_client_dev_register(sdev, "audio", card_idx, &pdata, sizeof(pdata)); +} + /* * Group SDW DAI types that share physical codec devices. Types on the * same device must be on the same card because ASoC components can only @@ -1947,14 +1973,7 @@ static int hda_register_audio_client_multi(struct snd_sof_dev *sdev) /* HDMI card */ if (HDA_IDISP_CODEC(mach->mach_params.codec_mask)) { - memcpy(&pdata.machine, mach, sizeof(pdata.machine)); - pdata.machine.mach_params.links = empty_links; - pdata.machine.mach_params.link_mask = 0; - pdata.machine.mach_params.codec_mask = BIT(HDA_IDISP_ADDR); - pdata.machine.mach_params.dmic_num = 0; - pdata.machine.mach_params.card_name = "hdmi"; - ret = sof_client_dev_register(sdev, "audio", card_idx, - &pdata, sizeof(pdata)); + ret = hda_register_hdmi_audio_client(sdev, mach, card_idx); if (ret) dev_warn(sdev->dev, "multi_card: failed to register card hdmi: %d\n", @@ -1968,11 +1987,75 @@ static int hda_register_audio_client_multi(struct snd_sof_dev *sdev) return 0; } +static int hda_register_audio_client_split_hdmi(struct snd_sof_dev *sdev) +{ + const struct snd_soc_acpi_mach *mach = sdev->pdata->machine; + struct hdac_bus *bus = sof_to_bus(sdev); + struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; + bool function_tplg_enabled; + bool has_analog_card; + struct sof_audio_client_pdata pdata; + int ret; + + hdev->num_audio_clients = 0; + + if (!mach) + return -ENODEV; + + function_tplg_enabled = !sdev->pdata->disable_function_topology && + mach->get_function_tplg_files; + + if (!HDA_IDISP_CODEC(mach->mach_params.codec_mask)) + return sof_register_audio_client(sdev); + + has_analog_card = HDA_EXT_CODEC(bus->codec_mask) || + mach->mach_params.link_mask || + mach->mach_params.dmic_num; + + if (!function_tplg_enabled && !has_analog_card) { + dev_info(sdev->dev, + "split_hdmi is not supported on this machine, using single card\n"); + return sof_register_audio_client(sdev); + } + + sof_audio_client_init_pdata(sdev, &pdata); + + /* Analog card: remove iDisp codec from the base machine configuration */ + memcpy(&pdata.machine, mach, sizeof(pdata.machine)); + pdata.machine.mach_params.codec_mask &= ~BIT(HDA_IDISP_ADDR); + pdata.machine.mach_params.card_name = NULL; + if (function_tplg_enabled) { + pdata.machine.sof_tplg_filename = mach->sof_tplg_filename ? + mach->sof_tplg_filename : sdev->pdata->tplg_filename; + } else { + pdata.machine.get_function_tplg_files = NULL; + pdata.machine.sof_tplg_filename = NULL; + } + ret = sof_client_dev_register(sdev, "audio", 0, &pdata, sizeof(pdata)); + if (ret) { + dev_warn(sdev->dev, + "split_hdmi: failed to register analog card: %d\n", ret); + return sof_register_audio_client(sdev); + } + + ret = hda_register_hdmi_audio_client(sdev, mach, 1); + if (ret) { + dev_warn(sdev->dev, + "split_hdmi: failed to register HDMI card: %d, using single card\n", ret); + sof_client_dev_unregister(sdev, "audio", 0); + return sof_register_audio_client(sdev); + } + + hdev->num_audio_clients = 2; + + return 0; +} + int hda_register_audio_client(struct snd_sof_dev *sdev) { - if (multi_card) { - const struct snd_soc_acpi_mach *mach = sdev->pdata->machine; + const struct snd_soc_acpi_mach *mach = sdev->pdata->machine; + if (multi_card) { if (mach && !sdev->pdata->disable_function_topology && mach->get_function_tplg_files) return hda_register_audio_client_multi(sdev); @@ -1981,14 +2064,17 @@ int hda_register_audio_client(struct snd_sof_dev *sdev) "multi_card is only supported with function topologies, using single card\n"); } + if (split_hdmi) + return hda_register_audio_client_split_hdmi(sdev); + return sof_register_audio_client(sdev); } void hda_unregister_audio_client(struct snd_sof_dev *sdev) { - if (multi_card) { - const struct snd_soc_acpi_mach *mach = sdev->pdata->machine; + const struct snd_soc_acpi_mach *mach = sdev->pdata->machine; + if (multi_card) { if (mach && !sdev->pdata->disable_function_topology && mach->get_function_tplg_files) { struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; @@ -2001,6 +2087,24 @@ void hda_unregister_audio_client(struct snd_sof_dev *sdev) } } + if (split_hdmi && mach && HDA_IDISP_CODEC(mach->mach_params.codec_mask)) { + struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; + int i; + + /* + * split_hdmi may fall back to single-card registration. In that case, + * use the legacy single-client unregister path. + */ + if (hdev->num_audio_clients <= 1) + goto single_client_unregister; + + for (i = hdev->num_audio_clients - 1; i >= 0; i--) + sof_client_dev_unregister(sdev, "audio", i); + hdev->num_audio_clients = 0; + return; + } + +single_client_unregister: sof_unregister_audio_client(sdev); }