diff mbox series

[4/6] ASoC: SOF: ipc4-topology: Add support for base config extension

Message ID 20230316151137.7598-5-peter.ujfalusi@linux.intel.com (mailing list archive)
State Accepted
Commit f9efae954905a07a9d152e9b30546a6632227eef
Headers show
Series ASoC: SOF: ipc4-topology: Add support for effect widget | expand

Commit Message

Peter Ujfalusi March 16, 2023, 3:11 p.m. UTC
From: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>

Some processing modules need the audio formats for all their input and
output pins appended to the base config during module init. So add support
for building the base config extension using the available pin formats
from topology.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
---
 sound/soc/sof/ipc4-topology.c | 147 ++++++++++++++++++++++++++++++----
 sound/soc/sof/ipc4-topology.h |  10 +++
 2 files changed, 142 insertions(+), 15 deletions(-)
diff mbox series

Patch

diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index 76bd3487bf71..efd53e855601 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -6,6 +6,7 @@ 
 // Copyright(c) 2022 Intel Corporation. All rights reserved.
 //
 //
+#include <linux/bitfield.h>
 #include <uapi/sound/sof/tokens.h>
 #include <sound/pcm_params.h>
 #include <sound/sof/ext_manifest4.h>
@@ -799,8 +800,8 @@  static void sof_ipc4_widget_free_comp_mixer(struct snd_sof_widget *swidget)
 static int sof_ipc4_widget_setup_comp_process(struct snd_sof_widget *swidget)
 {
 	struct snd_soc_component *scomp = swidget->scomp;
+	struct sof_ipc4_fw_module *fw_module;
 	struct sof_ipc4_process *process;
-	int cfg_size;
 	void *cfg;
 	int ret;
 
@@ -815,26 +816,50 @@  static int sof_ipc4_widget_setup_comp_process(struct snd_sof_widget *swidget)
 	if (ret)
 		goto err;
 
-	cfg_size = sizeof(struct sof_ipc4_base_module_cfg);
+	ret = sof_ipc4_widget_setup_msg(swidget, &process->msg);
+	if (ret)
+		goto err;
 
-	cfg = kzalloc(cfg_size, GFP_KERNEL);
+	/* parse process init module payload config type from module info */
+	fw_module = swidget->module_info;
+	process->init_config = FIELD_GET(SOF_IPC4_MODULE_INIT_CONFIG_MASK,
+					 fw_module->man4_module_entry.type);
+
+	process->ipc_config_size = sizeof(struct sof_ipc4_base_module_cfg);
+
+	/* allocate memory for base config extension if needed */
+	if (process->init_config == SOF_IPC4_MODULE_INIT_CONFIG_TYPE_BASE_CFG_WITH_EXT) {
+		struct sof_ipc4_base_module_cfg_ext *base_cfg_ext;
+		u32 ext_size = struct_size(base_cfg_ext, pin_formats,
+						swidget->num_input_pins + swidget->num_output_pins);
+
+		base_cfg_ext = kzalloc(ext_size, GFP_KERNEL);
+		if (!base_cfg_ext) {
+			ret = -ENOMEM;
+			goto free_available_fmt;
+		}
+
+		base_cfg_ext->num_input_pin_fmts = swidget->num_input_pins;
+		base_cfg_ext->num_output_pin_fmts = swidget->num_output_pins;
+		process->base_config_ext = base_cfg_ext;
+		process->base_config_ext_size = ext_size;
+		process->ipc_config_size += ext_size;
+	}
+
+	cfg = kzalloc(process->ipc_config_size, GFP_KERNEL);
 	if (!cfg) {
 		ret = -ENOMEM;
-		goto free_available_fmt;
+		goto free_base_cfg_ext;
 	}
 
 	process->ipc_config_data = cfg;
-	process->ipc_config_size = cfg_size;
-	ret = sof_ipc4_widget_setup_msg(swidget, &process->msg);
-	if (ret)
-		goto free_cfg_data;
 
 	sof_ipc4_widget_update_kcontrol_module_id(swidget);
 
 	return 0;
-free_cfg_data:
-	kfree(process->ipc_config_data);
-	process->ipc_config_data = NULL;
+free_base_cfg_ext:
+	kfree(process->base_config_ext);
+	process->base_config_ext = NULL;
 free_available_fmt:
 	sof_ipc4_free_audio_fmt(&process->available_fmt);
 err:
@@ -851,6 +876,7 @@  static void sof_ipc4_widget_free_comp_process(struct snd_sof_widget *swidget)
 		return;
 
 	kfree(process->ipc_config_data);
+	kfree(process->base_config_ext);
 	sof_ipc4_free_audio_fmt(&process->available_fmt);
 	kfree(swidget->private);
 	swidget->private = NULL;
@@ -1517,6 +1543,84 @@  static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget,
 	return 0;
 }
 
+static int
+sof_ipc4_process_set_pin_formats(struct snd_sof_widget *swidget, int pin_type)
+{
+	struct sof_ipc4_process *process = swidget->private;
+	struct sof_ipc4_base_module_cfg_ext *base_cfg_ext = process->base_config_ext;
+	struct sof_ipc4_available_audio_format *available_fmt = &process->available_fmt;
+	struct sof_ipc4_pin_format *pin_format, *format_list_to_search;
+	struct snd_soc_component *scomp = swidget->scomp;
+	int num_pins, format_list_count;
+	int pin_format_offset = 0;
+	int i, j;
+
+	/* set number of pins, offset of pin format and format list to search based on pin type */
+	if (pin_type == SOF_PIN_TYPE_INPUT) {
+		num_pins = swidget->num_input_pins;
+		format_list_to_search = available_fmt->input_pin_fmts;
+		format_list_count = available_fmt->num_input_formats;
+	} else {
+		num_pins = swidget->num_output_pins;
+		pin_format_offset = swidget->num_input_pins;
+		format_list_to_search = available_fmt->output_pin_fmts;
+		format_list_count = available_fmt->num_output_formats;
+	}
+
+	for (i = pin_format_offset; i < num_pins + pin_format_offset; i++) {
+		pin_format = &base_cfg_ext->pin_formats[i];
+
+		/* Pin 0 audio formats are derived from the base config input/output format */
+		if (i == pin_format_offset) {
+			if (pin_type == SOF_PIN_TYPE_INPUT) {
+				pin_format->buffer_size = process->base_config.ibs;
+				pin_format->audio_fmt = process->base_config.audio_fmt;
+			} else {
+				pin_format->buffer_size = process->base_config.obs;
+				pin_format->audio_fmt = process->output_format;
+			}
+			continue;
+		}
+
+		/*
+		 * For all other pins, find the pin formats from those set in topology. If there
+		 * is more than one format specified for a pin, this will pick the first available
+		 * one.
+		 */
+		for (j = 0; j < format_list_count; j++) {
+			struct sof_ipc4_pin_format *pin_format_item = &format_list_to_search[j];
+
+			if (pin_format_item->pin_index == i - pin_format_offset) {
+				*pin_format = *pin_format_item;
+				break;
+			}
+		}
+
+		if (j == format_list_count) {
+			dev_err(scomp->dev, "%s pin %d format not found for %s\n",
+				(pin_type == SOF_PIN_TYPE_INPUT) ? "input" : "output",
+				i - pin_format_offset, swidget->widget->name);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int sof_ipc4_process_add_base_cfg_extn(struct snd_sof_widget *swidget)
+{
+	int ret, i;
+
+	/* copy input and output pin formats */
+	for (i = 0; i <= SOF_PIN_TYPE_OUTPUT; i++) {
+		ret = sof_ipc4_process_set_pin_formats(swidget, i);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
 static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget,
 					   struct snd_pcm_hw_params *fe_params,
 					   struct snd_sof_platform_stream_params *platform_params,
@@ -1536,16 +1640,29 @@  static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget,
 	if (ret < 0)
 		return ret;
 
+	/* copy Pin 0 output format */
+	if (available_fmt->num_output_formats && ret < available_fmt->num_output_formats &&
+	    !available_fmt->output_pin_fmts[ret].pin_index)
+		memcpy(&process->output_format, &available_fmt->output_pin_fmts[ret].audio_fmt,
+		       sizeof(struct sof_ipc4_audio_format));
+
 	/* update pipeline memory usage */
 	sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &process->base_config);
 
-	/*
-	 * ipc_config_data is composed of the base_config, optional output formats followed
-	 * by the data required for module init in that order.
-	 */
+	/* 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));
 	cfg += sizeof(struct sof_ipc4_base_module_cfg);
 
+	if (process->init_config == SOF_IPC4_MODULE_INIT_CONFIG_TYPE_BASE_CFG_WITH_EXT) {
+		struct sof_ipc4_base_module_cfg_ext *base_cfg_ext = process->base_config_ext;
+
+		ret = sof_ipc4_process_add_base_cfg_extn(swidget);
+		if (ret < 0)
+			return ret;
+
+		memcpy(cfg, base_cfg_ext, process->base_config_ext_size);
+	}
+
 	return 0;
 }
 
diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h
index 97264454b8a6..015027b23588 100644
--- a/sound/soc/sof/ipc4-topology.h
+++ b/sound/soc/sof/ipc4-topology.h
@@ -26,6 +26,10 @@ 
 #define SOF_IPC4_MODULE_LL		BIT(5)
 #define SOF_IPC4_MODULE_DP		BIT(6)
 #define SOF_IPC4_MODULE_LIB_CODE		BIT(7)
+#define SOF_IPC4_MODULE_INIT_CONFIG_MASK	GENMASK(11, 8)
+
+#define SOF_IPC4_MODULE_INIT_CONFIG_TYPE_BASE_CFG		0
+#define SOF_IPC4_MODULE_INIT_CONFIG_TYPE_BASE_CFG_WITH_EXT	1
 
 #define SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE 12
 #define SOF_IPC4_PIPELINE_OBJECT_SIZE 448
@@ -367,19 +371,25 @@  struct sof_ipc4_base_module_cfg_ext {
 /**
  * struct sof_ipc4_process - process config data
  * @base_config: IPC base config data
+ * @base_config_ext: Base config extension data for module init
  * @output_format: Output audio format
  * @available_fmt: Available audio format
  * @ipc_config_data: Process module config data
  * @ipc_config_size: Size of process module config data
  * @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_*)
  */
 struct sof_ipc4_process {
 	struct sof_ipc4_base_module_cfg base_config;
+	struct sof_ipc4_base_module_cfg_ext *base_config_ext;
 	struct sof_ipc4_audio_format output_format;
 	struct sof_ipc4_available_audio_format available_fmt;
 	void *ipc_config_data;
 	uint32_t ipc_config_size;
 	struct sof_ipc4_msg msg;
+	u32 base_config_ext_size;
+	u32 init_config;
 };
 
 #endif