Unverified Commit 7711a2bb authored by Libin Yang's avatar Libin Yang Committed by Mark Brown
Browse files

ASoC: SOF: ipc4-topology: add effect widget support



Add the general support of IPC4 effect widgets.

IPC4 effect widgets, known as process modules,  can be EQFIR,
EQIIR, KEYWORD_DETECT, KPB, CHAN_SELECTOR, SMART_AMP and etc.

Signed-off-by: default avatarLibin Yang <libin.yang@intel.com>
Reviewed-by: default avatarRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: default avatarPéter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: default avatarPeter Ujfalusi <peter.ujfalusi@linux.intel.com>
Link: https://lore.kernel.org/r/20230316151137.7598-3-peter.ujfalusi@linux.intel.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 04b522a4
Loading
Loading
Loading
Loading
+124 −0
Original line number Diff line number Diff line
@@ -793,6 +793,69 @@ static void sof_ipc4_widget_free_comp_mixer(struct snd_sof_widget *swidget)
	swidget->private = NULL;
}

/*
 * Add the process modules support. The process modules are defined as snd_soc_dapm_effect modules.
 */
static int sof_ipc4_widget_setup_comp_process(struct snd_sof_widget *swidget)
{
	struct snd_soc_component *scomp = swidget->scomp;
	struct sof_ipc4_process *process;
	int cfg_size;
	void *cfg;
	int ret;

	process = kzalloc(sizeof(*process), GFP_KERNEL);
	if (!process)
		return -ENOMEM;

	swidget->private = process;

	ret = sof_ipc4_get_audio_fmt(scomp, swidget, &process->available_fmt,
				     &process->base_config);
	if (ret)
		goto err;

	cfg_size = sizeof(struct sof_ipc4_base_module_cfg);

	cfg = kzalloc(cfg_size, GFP_KERNEL);
	if (!cfg) {
		ret = -ENOMEM;
		goto free_available_fmt;
	}

	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_available_fmt:
	sof_ipc4_free_audio_fmt(&process->available_fmt);
err:
	kfree(process);
	swidget->private = NULL;
	return ret;
}

static void sof_ipc4_widget_free_comp_process(struct snd_sof_widget *swidget)
{
	struct sof_ipc4_process *process = swidget->private;

	if (!process)
		return;

	kfree(process->ipc_config_data);
	sof_ipc4_free_audio_fmt(&process->available_fmt);
	kfree(swidget->private);
	swidget->private = NULL;
}

static void
sof_ipc4_update_pipeline_mem_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
				   struct sof_ipc4_base_module_cfg *base_config)
@@ -1454,6 +1517,38 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget,
	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,
					   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 sof_ipc4_process *process = swidget->private;
	struct sof_ipc4_available_audio_format *available_fmt = &process->available_fmt;
	void *cfg = process->ipc_config_data;
	int ret;

	ret = sof_ipc4_init_audio_fmt(sdev, swidget, &process->base_config,
				      pipeline_params, available_fmt,
				      available_fmt->input_pin_fmts,
				      available_fmt->num_input_formats);
	if (ret < 0)
		return ret;

	/* 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.
	 */
	memcpy(cfg, &process->base_config, sizeof(struct sof_ipc4_base_module_cfg));
	cfg += sizeof(struct sof_ipc4_base_module_cfg);

	return 0;
}

static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
{
	struct sof_ipc4_control_data *control_data;
@@ -1652,6 +1747,22 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
		msg = &src->msg;
		break;
	}
	case snd_soc_dapm_effect:
	{
		struct sof_ipc4_process *process = swidget->private;

		if (!process->ipc_config_size) {
			dev_err(sdev->dev, "module %s has no config data!\n",
				swidget->widget->name);
			return -EINVAL;
		}

		ipc_size = process->ipc_config_size;
		ipc_data = process->ipc_config_data;

		msg = &process->msg;
		break;
	}
	default:
		dev_err(sdev->dev, "widget type %d not supported", swidget->id);
		return -EINVAL;
@@ -2257,6 +2368,14 @@ static enum sof_tokens src_token_list[] = {
	SOF_COMP_EXT_TOKENS,
};

static enum sof_tokens process_token_list[] = {
	SOF_COMP_TOKENS,
	SOF_AUDIO_FMT_NUM_TOKENS,
	SOF_IN_AUDIO_FORMAT_TOKENS,
	SOF_OUT_AUDIO_FORMAT_TOKENS,
	SOF_COMP_EXT_TOKENS,
};

static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = {
	[snd_soc_dapm_aif_in] =  {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
				  common_copier_token_list, ARRAY_SIZE(common_copier_token_list),
@@ -2294,6 +2413,11 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TY
				src_token_list, ARRAY_SIZE(src_token_list),
				NULL, sof_ipc4_prepare_src_module,
				NULL},
	[snd_soc_dapm_effect] = {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 = {
+18 −0
Original line number Diff line number Diff line
@@ -347,4 +347,22 @@ struct sof_ipc4_src {
	struct sof_ipc4_msg msg;
};

/**
 * struct sof_ipc4_process - process config data
 * @base_config: IPC base config data
 * @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
 */
struct sof_ipc4_process {
	struct sof_ipc4_base_module_cfg base_config;
	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;
};

#endif