File Index
Files and directories
Sign in
FILE

ipc4-topology.c

File preview with syntax highlighting.

linux-6.19.14/sound/soc/sof/ipc4-topology.c C
   1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
   2//
   3// This file is provided under a dual BSD/GPLv2 license.  When using or
   4// redistributing this file, you may do so under either license.
   5//
   6// Copyright(c) 2022 Intel Corporation
   7//
   8//
   9#include <linux/bitfield.h>
  10#include <linux/cleanup.h>
  11#include <uapi/sound/sof/tokens.h>
  12#include <sound/pcm_params.h>
  13#include <sound/sof/ext_manifest4.h>
  14#include <sound/intel-nhlt.h>
  15#include "sof-priv.h"
  16#include "sof-audio.h"
  17#include "ipc4-priv.h"
  18#include "ipc4-topology.h"
  19#include "ops.h"
  20
  21/*
  22 * The ignore_cpc flag can be used to ignore the CPC value for all modules by
  23 * using 0 instead.
  24 * The CPC is sent to the firmware along with the SOF_IPC4_MOD_INIT_INSTANCE
  25 * message and it is used for clock scaling.
  26 * 0 as CPC value will instruct the firmware to use maximum frequency, thus
  27 * deactivating the clock scaling.
  28 */
  29static bool ignore_cpc;
  30module_param_named(ipc4_ignore_cpc, ignore_cpc, bool, 0444);
  31MODULE_PARM_DESC(ipc4_ignore_cpc,
  32		 "Ignore CPC values. This option will disable clock scaling in firmware.");
  33
  34#define SOF_IPC4_GAIN_PARAM_ID  0
  35#define SOF_IPC4_TPLG_ABI_SIZE 6
  36
  37static DEFINE_IDA(alh_group_ida);
  38static DEFINE_IDA(pipeline_ida);
  39
  40struct sof_comp_domains {
  41	const char *name;
  42	enum sof_comp_domain domain;
  43};
  44
  45static const struct sof_comp_domains sof_domains[] = {
  46	{ "LL", SOF_COMP_DOMAIN_LL, },
  47	{ "DP", SOF_COMP_DOMAIN_DP, }
  48};
  49
  50static enum sof_comp_domain find_domain(const char *name)
  51{
  52	int i;
  53
  54	for (i = 0; i < ARRAY_SIZE(sof_domains); i++) {
  55		if (strcmp(name, sof_domains[i].name) == 0)
  56			return sof_domains[i].domain;
  57	}
  58	/* No valid value found, fall back to manifest value */
  59	return SOF_COMP_DOMAIN_UNSET;
  60}
  61
  62static int get_token_comp_domain(void *elem, void *object, u32 offset)
  63{
  64	u32 *val = (u32 *)((u8 *)object + offset);
  65
  66	*val = find_domain((const char *)elem);
  67	return 0;
  68}
  69
  70static const struct sof_topology_token ipc4_sched_tokens[] = {
  71	{SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
  72		offsetof(struct sof_ipc4_pipeline, lp_mode)},
  73	{SOF_TKN_SCHED_USE_CHAIN_DMA, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
  74		offsetof(struct sof_ipc4_pipeline, use_chain_dma)},
  75	{SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
  76		offsetof(struct sof_ipc4_pipeline, core_id)},
  77	{SOF_TKN_SCHED_PRIORITY, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
  78		offsetof(struct sof_ipc4_pipeline, priority)},
  79};
  80
  81static const struct sof_topology_token pipeline_tokens[] = {
  82	{SOF_TKN_SCHED_DYNAMIC_PIPELINE, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
  83		offsetof(struct snd_sof_widget, dynamic_pipeline_widget)},
  84};
  85
  86static const struct sof_topology_token ipc4_comp_tokens[] = {
  87	{SOF_TKN_COMP_IS_PAGES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
  88		offsetof(struct sof_ipc4_base_module_cfg, is_pages)},
  89};
  90
  91static const struct sof_topology_token ipc4_in_audio_format_tokens[] = {
  92	{SOF_TKN_CAVS_AUDIO_FORMAT_IN_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
  93		offsetof(struct sof_ipc4_pin_format, audio_fmt.sampling_frequency)},
  94	{SOF_TKN_CAVS_AUDIO_FORMAT_IN_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
  95		offsetof(struct sof_ipc4_pin_format, audio_fmt.bit_depth)},
  96	{SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
  97		offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_map)},
  98	{SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
  99		offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_cfg)},
 100	{SOF_TKN_CAVS_AUDIO_FORMAT_IN_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
 101		get_token_u32, offsetof(struct sof_ipc4_pin_format,
 102		audio_fmt.interleaving_style)},
 103	{SOF_TKN_CAVS_AUDIO_FORMAT_IN_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 104		offsetof(struct sof_ipc4_pin_format, audio_fmt.fmt_cfg)},
 105	{SOF_TKN_CAVS_AUDIO_FORMAT_INPUT_PIN_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 106		offsetof(struct sof_ipc4_pin_format, pin_index)},
 107	{SOF_TKN_CAVS_AUDIO_FORMAT_IBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 108		offsetof(struct sof_ipc4_pin_format, buffer_size)},
 109};
 110
 111static const struct sof_topology_token ipc4_out_audio_format_tokens[] = {
 112	{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 113		offsetof(struct sof_ipc4_pin_format, audio_fmt.sampling_frequency)},
 114	{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 115		offsetof(struct sof_ipc4_pin_format, audio_fmt.bit_depth)},
 116	{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 117		offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_map)},
 118	{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 119		offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_cfg)},
 120	{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
 121		get_token_u32, offsetof(struct sof_ipc4_pin_format,
 122		audio_fmt.interleaving_style)},
 123	{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 124		offsetof(struct sof_ipc4_pin_format, audio_fmt.fmt_cfg)},
 125	{SOF_TKN_CAVS_AUDIO_FORMAT_OUTPUT_PIN_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 126		offsetof(struct sof_ipc4_pin_format, pin_index)},
 127	{SOF_TKN_CAVS_AUDIO_FORMAT_OBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 128		offsetof(struct sof_ipc4_pin_format, buffer_size)},
 129};
 130
 131static const struct sof_topology_token ipc4_copier_deep_buffer_tokens[] = {
 132	{SOF_TKN_INTEL_COPIER_DEEP_BUFFER_DMA_MS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0},
 133};
 134
 135static const struct sof_topology_token ipc4_copier_tokens[] = {
 136	{SOF_TKN_INTEL_COPIER_NODE_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0},
 137};
 138
 139static const struct sof_topology_token ipc4_audio_fmt_num_tokens[] = {
 140	{SOF_TKN_COMP_NUM_INPUT_AUDIO_FORMATS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 141		offsetof(struct sof_ipc4_available_audio_format, num_input_formats)},
 142	{SOF_TKN_COMP_NUM_OUTPUT_AUDIO_FORMATS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 143		offsetof(struct sof_ipc4_available_audio_format, num_output_formats)},
 144};
 145
 146static const struct sof_topology_token dai_tokens[] = {
 147	{SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type,
 148		offsetof(struct sof_ipc4_copier, dai_type)},
 149	{SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 150		offsetof(struct sof_ipc4_copier, dai_index)},
 151};
 152
 153/* Component extended tokens */
 154static const struct sof_topology_token comp_ext_tokens[] = {
 155	{SOF_TKN_COMP_UUID, SND_SOC_TPLG_TUPLE_TYPE_UUID, get_token_uuid,
 156		offsetof(struct snd_sof_widget, uuid)},
 157	{SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 158		offsetof(struct snd_sof_widget, core)},
 159	{SOF_TKN_COMP_SCHED_DOMAIN, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_domain,
 160		offsetof(struct snd_sof_widget, comp_domain)},
 161};
 162
 163static const struct sof_topology_token gain_tokens[] = {
 164	{SOF_TKN_GAIN_RAMP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
 165		get_token_u32, offsetof(struct sof_ipc4_gain_params, curve_type)},
 166	{SOF_TKN_GAIN_RAMP_DURATION,
 167		SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 168		offsetof(struct sof_ipc4_gain_params, curve_duration_l)},
 169	{SOF_TKN_GAIN_VAL, SND_SOC_TPLG_TUPLE_TYPE_WORD,
 170		get_token_u32, offsetof(struct sof_ipc4_gain_params, init_val)},
 171};
 172
 173/* SRC */
 174static const struct sof_topology_token src_tokens[] = {
 175	{SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 176		offsetof(struct sof_ipc4_src_data, sink_rate)},
 177};
 178
 179/* ASRC */
 180static const struct sof_topology_token asrc_tokens[] = {
 181	{SOF_TKN_ASRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 182		offsetof(struct sof_ipc4_asrc_data, out_freq)},
 183	{SOF_TKN_ASRC_OPERATION_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 184		offsetof(struct sof_ipc4_asrc_data, asrc_mode)},
 185};
 186
 187static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = {
 188	[SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)},
 189	[SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)},
 190	[SOF_SCHED_TOKENS] = {"Scheduler tokens", ipc4_sched_tokens,
 191		ARRAY_SIZE(ipc4_sched_tokens)},
 192	[SOF_COMP_EXT_TOKENS] = {"Comp extended tokens", comp_ext_tokens,
 193		ARRAY_SIZE(comp_ext_tokens)},
 194	[SOF_COMP_TOKENS] = {"IPC4 Component tokens",
 195		ipc4_comp_tokens, ARRAY_SIZE(ipc4_comp_tokens)},
 196	[SOF_IN_AUDIO_FORMAT_TOKENS] = {"IPC4 Input Audio format tokens",
 197		ipc4_in_audio_format_tokens, ARRAY_SIZE(ipc4_in_audio_format_tokens)},
 198	[SOF_OUT_AUDIO_FORMAT_TOKENS] = {"IPC4 Output Audio format tokens",
 199		ipc4_out_audio_format_tokens, ARRAY_SIZE(ipc4_out_audio_format_tokens)},
 200	[SOF_COPIER_DEEP_BUFFER_TOKENS] = {"IPC4 Copier deep buffer tokens",
 201		ipc4_copier_deep_buffer_tokens, ARRAY_SIZE(ipc4_copier_deep_buffer_tokens)},
 202	[SOF_COPIER_TOKENS] = {"IPC4 Copier tokens", ipc4_copier_tokens,
 203		ARRAY_SIZE(ipc4_copier_tokens)},
 204	[SOF_AUDIO_FMT_NUM_TOKENS] = {"IPC4 Audio format number tokens",
 205		ipc4_audio_fmt_num_tokens, ARRAY_SIZE(ipc4_audio_fmt_num_tokens)},
 206	[SOF_GAIN_TOKENS] = {"Gain tokens", gain_tokens, ARRAY_SIZE(gain_tokens)},
 207	[SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)},
 208	[SOF_ASRC_TOKENS] = {"ASRC tokens", asrc_tokens, ARRAY_SIZE(asrc_tokens)},
 209};
 210
 211struct snd_sof_widget *sof_ipc4_find_swidget_by_ids(struct snd_sof_dev *sdev,
 212						    u32 module_id, int instance_id)
 213{
 214	struct snd_sof_widget *swidget;
 215
 216	list_for_each_entry(swidget, &sdev->widget_list, list) {
 217		struct sof_ipc4_fw_module *fw_module = swidget->module_info;
 218
 219		/* Only active module instances have valid instance_id */
 220		if (!swidget->use_count)
 221			continue;
 222
 223		if (fw_module && fw_module->man4_module_entry.id == module_id &&
 224		    swidget->instance_id == instance_id)
 225			return swidget;
 226	}
 227
 228	return NULL;
 229}
 230
 231static void sof_ipc4_dbg_audio_format(struct device *dev, struct sof_ipc4_pin_format *pin_fmt,
 232				      int num_formats)
 233{
 234	int i;
 235
 236	for (i = 0; i < num_formats; i++) {
 237		struct sof_ipc4_audio_format *fmt = &pin_fmt[i].audio_fmt;
 238		dev_dbg(dev,
 239			"Pin #%d: %uHz, %ubit, %luch (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x) buffer size %d\n",
 240			pin_fmt[i].pin_index, fmt->sampling_frequency, fmt->bit_depth,
 241			SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg),
 242			fmt->ch_map, fmt->ch_cfg, fmt->interleaving_style, fmt->fmt_cfg,
 243			pin_fmt[i].buffer_size);
 244	}
 245}
 246
 247static void
 248sof_ipc4_dbg_module_audio_format(struct device *dev,
 249				 struct snd_sof_widget *swidget,
 250				 struct sof_ipc4_available_audio_format *available_fmt,
 251				 int in_fmt_index, int out_fmt_index)
 252{
 253	struct sof_ipc4_audio_format *in_fmt, *out_fmt;
 254	u32 out_rate, out_channels, out_valid_bits;
 255	u32 in_rate, in_channels, in_valid_bits;
 256	struct sof_ipc4_pin_format *pin_fmt;
 257
 258	if (!available_fmt->num_input_formats &&
 259	    !available_fmt->num_output_formats)
 260		return;
 261
 262	/* Only input or output is supported by the module */
 263	if (!available_fmt->num_input_formats) {
 264		if (available_fmt->num_output_formats == 1)
 265			dev_dbg(dev, "Output audio format for %s:\n",
 266				swidget->widget->name);
 267		else
 268			dev_dbg(dev,
 269				"Output audio format (format index: %d) for %s:\n",
 270				out_fmt_index, swidget->widget->name);
 271
 272		pin_fmt = &available_fmt->output_pin_fmts[out_fmt_index];
 273		sof_ipc4_dbg_audio_format(dev, pin_fmt, 1);
 274
 275		return;
 276	} else if (!available_fmt->num_output_formats) {
 277		if (available_fmt->num_input_formats == 1)
 278			dev_dbg(dev, "Input audio format for %s:\n",
 279				swidget->widget->name);
 280		else
 281			dev_dbg(dev,
 282				"Input audio format (format index: %d) for %s:\n",
 283				out_fmt_index, swidget->widget->name);
 284
 285		pin_fmt = &available_fmt->input_pin_fmts[in_fmt_index];
 286		sof_ipc4_dbg_audio_format(dev, pin_fmt, 1);
 287
 288		return;
 289	}
 290
 291	in_fmt = &available_fmt->input_pin_fmts[in_fmt_index].audio_fmt;
 292	out_fmt = &available_fmt->output_pin_fmts[out_fmt_index].audio_fmt;
 293
 294	in_rate = in_fmt->sampling_frequency;
 295	in_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
 296	in_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
 297
 298	out_rate = out_fmt->sampling_frequency;
 299	out_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(out_fmt->fmt_cfg);
 300	out_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(out_fmt->fmt_cfg);
 301
 302	if (!(in_valid_bits != out_valid_bits || in_rate != out_rate ||
 303	      in_channels != out_channels)) {
 304		/* There is no change in format */
 305		if (available_fmt->num_input_formats == 1 &&
 306		    available_fmt->num_output_formats == 1)
 307			dev_dbg(dev, "Audio format for %s:\n",
 308				swidget->widget->name);
 309		else
 310			dev_dbg(dev,
 311				"Audio format (in/out format index: %d/%d) for %s:\n",
 312				in_fmt_index, out_fmt_index, swidget->widget->name);
 313
 314		pin_fmt = &available_fmt->input_pin_fmts[in_fmt_index];
 315		sof_ipc4_dbg_audio_format(dev, pin_fmt, 1);
 316
 317		return;
 318	}
 319
 320	/* The format is changed by the module */
 321	if (available_fmt->num_input_formats == 1)
 322		dev_dbg(dev, "Input audio format for %s:\n",
 323			swidget->widget->name);
 324	else
 325		dev_dbg(dev, "Input audio format (format index: %d) for %s:\n",
 326			in_fmt_index, swidget->widget->name);
 327
 328	pin_fmt = &available_fmt->input_pin_fmts[in_fmt_index];
 329	sof_ipc4_dbg_audio_format(dev, pin_fmt, 1);
 330
 331	if (available_fmt->num_output_formats == 1)
 332		dev_dbg(dev, "Output audio format for %s:\n",
 333			swidget->widget->name);
 334	else
 335		dev_dbg(dev, "Output audio format (format index: %d) for %s:\n",
 336			out_fmt_index, swidget->widget->name);
 337
 338	pin_fmt = &available_fmt->output_pin_fmts[out_fmt_index];
 339	sof_ipc4_dbg_audio_format(dev, pin_fmt, 1);
 340}
 341
 342static const struct sof_ipc4_audio_format *
 343sof_ipc4_get_input_pin_audio_fmt(struct snd_sof_widget *swidget, int pin_index)
 344{
 345	struct sof_ipc4_base_module_cfg_ext *base_cfg_ext;
 346	struct sof_ipc4_process *process;
 347	int i;
 348
 349	if (swidget->id != snd_soc_dapm_effect) {
 350		struct sof_ipc4_base_module_cfg *base = swidget->private;
 351
 352		/* For non-process modules, base module config format is used for all input pins */
 353		return &base->audio_fmt;
 354	}
 355
 356	process = swidget->private;
 357
 358	/*
 359	 * For process modules without base config extension, base module config
 360	 * format is used for all input pins
 361	 */
 362	if (process->init_config != SOF_IPC4_MODULE_INIT_CONFIG_TYPE_BASE_CFG_WITH_EXT)
 363		return &process->base_config.audio_fmt;
 364
 365	base_cfg_ext = process->base_config_ext;
 366
 367	/*
 368	 * If there are multiple input formats available for a pin, the first available format
 369	 * is chosen.
 370	 */
 371	for (i = 0; i < base_cfg_ext->num_input_pin_fmts; i++) {
 372		struct sof_ipc4_pin_format *pin_format = &base_cfg_ext->pin_formats[i];
 373
 374		if (pin_format->pin_index == pin_index)
 375			return &pin_format->audio_fmt;
 376	}
 377
 378	return NULL;
 379}
 380
 381/**
 382 * sof_ipc4_get_audio_fmt - get available audio formats from swidget->tuples
 383 * @scomp: pointer to pointer to SOC component
 384 * @swidget: pointer to struct snd_sof_widget containing tuples
 385 * @available_fmt: pointer to struct sof_ipc4_available_audio_format being filling in
 386 * @module_base_cfg: Pointer to the base_config in the module init IPC payload
 387 *
 388 * Return: 0 if successful
 389 */
 390static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp,
 391				  struct snd_sof_widget *swidget,
 392				  struct sof_ipc4_available_audio_format *available_fmt,
 393				  struct sof_ipc4_base_module_cfg *module_base_cfg)
 394{
 395	struct sof_ipc4_pin_format *in_format = NULL;
 396	struct sof_ipc4_pin_format *out_format;
 397	int ret;
 398
 399	ret = sof_update_ipc_object(scomp, available_fmt,
 400				    SOF_AUDIO_FMT_NUM_TOKENS, swidget->tuples,
 401				    swidget->num_tuples, sizeof(*available_fmt), 1);
 402	if (ret) {
 403		dev_err(scomp->dev, "Failed to parse audio format token count\n");
 404		return ret;
 405	}
 406
 407	if (!available_fmt->num_input_formats && !available_fmt->num_output_formats) {
 408		dev_err(scomp->dev, "No input/output pin formats set in topology\n");
 409		return -EINVAL;
 410	}
 411
 412	dev_dbg(scomp->dev,
 413		"Number of input audio formats: %d. Number of output audio formats: %d\n",
 414		available_fmt->num_input_formats, available_fmt->num_output_formats);
 415
 416	/* set is_pages in the module's base_config */
 417	ret = sof_update_ipc_object(scomp, module_base_cfg, SOF_COMP_TOKENS, swidget->tuples,
 418				    swidget->num_tuples, sizeof(*module_base_cfg), 1);
 419	if (ret) {
 420		dev_err(scomp->dev, "parse comp tokens for %s failed, error: %d\n",
 421			swidget->widget->name, ret);
 422		return ret;
 423	}
 424
 425	dev_dbg(scomp->dev, "widget %s: is_pages: %d\n", swidget->widget->name,
 426		module_base_cfg->is_pages);
 427
 428	if (available_fmt->num_input_formats) {
 429		in_format = kcalloc(available_fmt->num_input_formats,
 430				    sizeof(*in_format), GFP_KERNEL);
 431		if (!in_format)
 432			return -ENOMEM;
 433		available_fmt->input_pin_fmts = in_format;
 434
 435		ret = sof_update_ipc_object(scomp, in_format,
 436					    SOF_IN_AUDIO_FORMAT_TOKENS, swidget->tuples,
 437					    swidget->num_tuples, sizeof(*in_format),
 438					    available_fmt->num_input_formats);
 439		if (ret) {
 440			dev_err(scomp->dev, "parse input audio fmt tokens failed %d\n", ret);
 441			goto err_in;
 442		}
 443
 444		dev_dbg(scomp->dev, "Input audio formats for %s\n", swidget->widget->name);
 445		sof_ipc4_dbg_audio_format(scomp->dev, in_format,
 446					  available_fmt->num_input_formats);
 447	}
 448
 449	if (available_fmt->num_output_formats) {
 450		out_format = kcalloc(available_fmt->num_output_formats, sizeof(*out_format),
 451				     GFP_KERNEL);
 452		if (!out_format) {
 453			ret = -ENOMEM;
 454			goto err_in;
 455		}
 456
 457		ret = sof_update_ipc_object(scomp, out_format,
 458					    SOF_OUT_AUDIO_FORMAT_TOKENS, swidget->tuples,
 459					    swidget->num_tuples, sizeof(*out_format),
 460					    available_fmt->num_output_formats);
 461		if (ret) {
 462			dev_err(scomp->dev, "parse output audio fmt tokens failed\n");
 463			goto err_out;
 464		}
 465
 466		available_fmt->output_pin_fmts = out_format;
 467		dev_dbg(scomp->dev, "Output audio formats for %s\n", swidget->widget->name);
 468		sof_ipc4_dbg_audio_format(scomp->dev, out_format,
 469					  available_fmt->num_output_formats);
 470	}
 471
 472	return 0;
 473
 474err_out:
 475	kfree(out_format);
 476err_in:
 477	kfree(in_format);
 478	available_fmt->input_pin_fmts = NULL;
 479	return ret;
 480}
 481
 482/* release the memory allocated in sof_ipc4_get_audio_fmt */
 483static void sof_ipc4_free_audio_fmt(struct sof_ipc4_available_audio_format *available_fmt)
 484
 485{
 486	kfree(available_fmt->output_pin_fmts);
 487	available_fmt->output_pin_fmts = NULL;
 488	kfree(available_fmt->input_pin_fmts);
 489	available_fmt->input_pin_fmts = NULL;
 490}
 491
 492static void sof_ipc4_widget_free_comp_pipeline(struct snd_sof_widget *swidget)
 493{
 494	kfree(swidget->private);
 495}
 496
 497static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget)
 498{
 499	struct snd_soc_component *scomp = swidget->scomp;
 500	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
 501
 502	swidget->module_info = sof_ipc4_find_module_by_uuid(sdev, &swidget->uuid);
 503
 504	if (swidget->module_info)
 505		return 0;
 506
 507	dev_err(sdev->dev, "failed to find module info for widget %s with UUID %pUL\n",
 508		swidget->widget->name, &swidget->uuid);
 509	return -EINVAL;
 510}
 511
 512static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_ipc4_msg *msg)
 513{
 514	struct sof_ipc4_fw_module *fw_module;
 515	uint32_t type;
 516	int ret;
 517
 518	ret = sof_ipc4_widget_set_module_info(swidget);
 519	if (ret)
 520		return ret;
 521
 522	fw_module = swidget->module_info;
 523
 524	msg->primary = fw_module->man4_module_entry.id;
 525	msg->primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_INIT_INSTANCE);
 526	msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
 527	msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
 528
 529	msg->extension = SOF_IPC4_MOD_EXT_CORE_ID(swidget->core);
 530
 531	switch (swidget->comp_domain) {
 532	case SOF_COMP_DOMAIN_LL:
 533		type = 0;
 534		break;
 535	case SOF_COMP_DOMAIN_DP:
 536		type = 1;
 537		break;
 538	default:
 539		type = (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_DP) ? 1 : 0;
 540		break;
 541	}
 542	msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(type);
 543
 544	return 0;
 545}
 546
 547static void sof_ipc4_widget_update_kcontrol_module_id(struct snd_sof_widget *swidget)
 548{
 549	struct snd_soc_component *scomp = swidget->scomp;
 550	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
 551	struct sof_ipc4_fw_module *fw_module = swidget->module_info;
 552	struct snd_sof_control *scontrol;
 553
 554	/* update module ID for all kcontrols for this widget */
 555	list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
 556		if (scontrol->comp_id == swidget->comp_id) {
 557			struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
 558			struct sof_ipc4_msg *msg = &cdata->msg;
 559
 560			msg->primary |= fw_module->man4_module_entry.id;
 561		}
 562	}
 563}
 564
 565static int
 566sof_ipc4_update_card_components_string(struct snd_sof_widget *swidget,
 567				       struct snd_sof_pcm *spcm, int dir)
 568{
 569	struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
 570	struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
 571	struct snd_soc_component *scomp = spcm->scomp;
 572	struct snd_soc_card *card = scomp->card;
 573	const char *pt_marker = "iec61937-pcm";
 574
 575	/*
 576	 * Update the card's components list with iec61937-pcm and a list of PCM
 577	 * ids where ChainDMA is enabled.
 578	 * These PCMs can be used for bytestream passthrough.
 579	 */
 580	if (!pipeline->use_chain_dma)
 581		return 0;
 582
 583	if (card->components) {
 584		const char *tmp = card->components;
 585
 586		if (strstr(card->components, pt_marker))
 587			card->components = devm_kasprintf(card->dev, GFP_KERNEL,
 588							  "%s,%d",
 589							  card->components,
 590							  spcm->pcm.pcm_id);
 591		else
 592			card->components = devm_kasprintf(card->dev, GFP_KERNEL,
 593							  "%s %s:%d",
 594							  card->components,
 595							  pt_marker,
 596							  spcm->pcm.pcm_id);
 597
 598		devm_kfree(card->dev, tmp);
 599	} else {
 600		card->components = devm_kasprintf(card->dev, GFP_KERNEL,
 601						  "%s:%d", pt_marker,
 602						  spcm->pcm.pcm_id);
 603	}
 604
 605	if (!card->components)
 606		return -ENOMEM;
 607
 608	return 0;
 609}
 610
 611static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget)
 612{
 613	struct sof_ipc4_available_audio_format *available_fmt;
 614	struct snd_soc_component *scomp = swidget->scomp;
 615	struct sof_ipc4_copier *ipc4_copier;
 616	struct snd_sof_pcm *spcm;
 617	int node_type = 0;
 618	int ret, dir;
 619
 620	ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL);
 621	if (!ipc4_copier)
 622		return -ENOMEM;
 623
 624	swidget->private = ipc4_copier;
 625	available_fmt = &ipc4_copier->available_fmt;
 626
 627	dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
 628
 629	ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt,
 630				     &ipc4_copier->data.base_config);
 631	if (ret)
 632		goto free_copier;
 633
 634	/*
 635	 * This callback is used by host copier and module-to-module copier,
 636	 * and only host copier needs to set gtw_cfg.
 637	 */
 638	if (!WIDGET_IS_AIF(swidget->id))
 639		goto skip_gtw_cfg;
 640
 641	ret = sof_update_ipc_object(scomp, &node_type,
 642				    SOF_COPIER_TOKENS, swidget->tuples,
 643				    swidget->num_tuples, sizeof(node_type), 1);
 644
 645	if (ret) {
 646		dev_err(scomp->dev, "parse host copier node type token failed %d\n",
 647			ret);
 648		goto free_available_fmt;
 649	}
 650	dev_dbg(scomp->dev, "host copier '%s' node_type %u\n", swidget->widget->name, node_type);
 651
 652	spcm = snd_sof_find_spcm_comp(scomp, swidget->comp_id, &dir);
 653	if (!spcm)
 654		goto skip_gtw_cfg;
 655
 656	ret = sof_ipc4_update_card_components_string(swidget, spcm, dir);
 657	if (ret)
 658		goto free_available_fmt;
 659
 660	if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
 661		struct snd_sof_pcm_stream *sps = &spcm->stream[dir];
 662
 663		sof_update_ipc_object(scomp, &sps->dsp_max_burst_size_in_ms,
 664				      SOF_COPIER_DEEP_BUFFER_TOKENS,
 665				      swidget->tuples,
 666				      swidget->num_tuples, sizeof(u32), 1);
 667		/* Set default DMA buffer size if it is not specified in topology */
 668		if (!sps->dsp_max_burst_size_in_ms) {
 669			struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
 670			struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
 671
 672			sps->dsp_max_burst_size_in_ms = pipeline->use_chain_dma ?
 673				SOF_IPC4_CHAIN_DMA_BUFFER_SIZE : SOF_IPC4_MIN_DMA_BUFFER_SIZE;
 674		}
 675	} else {
 676		/* Capture data is copied from DSP to host in 1ms bursts */
 677		spcm->stream[dir].dsp_max_burst_size_in_ms = 1;
 678	}
 679
 680skip_gtw_cfg:
 681	ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL);
 682	if (!ipc4_copier->gtw_attr) {
 683		ret = -ENOMEM;
 684		goto free_available_fmt;
 685	}
 686
 687	ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr;
 688	ipc4_copier->data.gtw_cfg.config_length =
 689		sizeof(struct sof_ipc4_gtw_attributes) >> 2;
 690
 691	switch (swidget->id) {
 692	case snd_soc_dapm_aif_in:
 693	case snd_soc_dapm_aif_out:
 694		ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type);
 695		break;
 696	case snd_soc_dapm_buffer:
 697		ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_INVALID_NODE_ID;
 698		ipc4_copier->ipc_config_size = 0;
 699		break;
 700	default:
 701		dev_err(scomp->dev, "invalid widget type %d\n", swidget->id);
 702		ret = -EINVAL;
 703		goto free_gtw_attr;
 704	}
 705
 706	/* set up module info and message header */
 707	ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg);
 708	if (ret)
 709		goto free_gtw_attr;
 710
 711	return 0;
 712
 713free_gtw_attr:
 714	kfree(ipc4_copier->gtw_attr);
 715free_available_fmt:
 716	sof_ipc4_free_audio_fmt(available_fmt);
 717free_copier:
 718	kfree(ipc4_copier);
 719	swidget->private = NULL;
 720	return ret;
 721}
 722
 723static void sof_ipc4_widget_free_comp_pcm(struct snd_sof_widget *swidget)
 724{
 725	struct sof_ipc4_copier *ipc4_copier = swidget->private;
 726	struct sof_ipc4_available_audio_format *available_fmt;
 727
 728	if (!ipc4_copier)
 729		return;
 730
 731	available_fmt = &ipc4_copier->available_fmt;
 732	kfree(available_fmt->output_pin_fmts);
 733	kfree(ipc4_copier->gtw_attr);
 734	kfree(ipc4_copier);
 735	swidget->private = NULL;
 736}
 737
 738static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
 739{
 740	struct sof_ipc4_available_audio_format *available_fmt;
 741	struct snd_soc_component *scomp = swidget->scomp;
 742	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
 743	struct snd_sof_dai *dai = swidget->private;
 744	struct sof_ipc4_copier *ipc4_copier;
 745	struct snd_sof_widget *pipe_widget;
 746	struct sof_ipc4_pipeline *pipeline;
 747	int node_type = 0;
 748	int ret;
 749
 750	ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL);
 751	if (!ipc4_copier)
 752		return -ENOMEM;
 753
 754	available_fmt = &ipc4_copier->available_fmt;
 755
 756	dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
 757
 758	ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt,
 759				     &ipc4_copier->data.base_config);
 760	if (ret)
 761		goto free_copier;
 762
 763	ret = sof_update_ipc_object(scomp, &node_type,
 764				    SOF_COPIER_TOKENS, swidget->tuples,
 765				    swidget->num_tuples, sizeof(node_type), 1);
 766	if (ret) {
 767		dev_err(scomp->dev, "parse dai node type failed %d\n", ret);
 768		goto free_available_fmt;
 769	}
 770
 771	ret = sof_update_ipc_object(scomp, ipc4_copier,
 772				    SOF_DAI_TOKENS, swidget->tuples,
 773				    swidget->num_tuples, sizeof(u32), 1);
 774	if (ret) {
 775		dev_err(scomp->dev, "parse dai copier node token failed %d\n", ret);
 776		goto free_available_fmt;
 777	}
 778
 779	dev_dbg(scomp->dev, "dai %s node_type %u dai_type %u dai_index %d\n", swidget->widget->name,
 780		node_type, ipc4_copier->dai_type, ipc4_copier->dai_index);
 781
 782	dai->type = ipc4_copier->dai_type;
 783	ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type);
 784
 785	pipe_widget = swidget->spipe->pipe_widget;
 786	pipeline = pipe_widget->private;
 787
 788	if (pipeline->use_chain_dma &&
 789	    !snd_sof_is_chain_dma_supported(sdev, ipc4_copier->dai_type)) {
 790		dev_err(scomp->dev, "Bad DAI type '%d', Chain DMA is not supported\n",
 791			ipc4_copier->dai_type);
 792		ret = -ENODEV;
 793		goto free_available_fmt;
 794	}
 795
 796	switch (ipc4_copier->dai_type) {
 797	case SOF_DAI_INTEL_ALH:
 798	{
 799		struct sof_ipc4_alh_configuration_blob *blob;
 800		struct snd_soc_dapm_path *p;
 801		struct snd_sof_widget *w;
 802		int src_num = 0;
 803
 804		snd_soc_dapm_widget_for_each_source_path(swidget->widget, p)
 805			src_num++;
 806
 807		if (swidget->id == snd_soc_dapm_dai_in && src_num == 0) {
 808			/*
 809			 * The blob will not be used if the ALH copier is playback direction
 810			 * and doesn't connect to any source.
 811			 * It is fine to call kfree(ipc4_copier->copier_config) since
 812			 * ipc4_copier->copier_config is null.
 813			 */
 814			break;
 815		}
 816
 817		blob = kzalloc(sizeof(*blob), GFP_KERNEL);
 818		if (!blob) {
 819			ret = -ENOMEM;
 820			goto free_available_fmt;
 821		}
 822
 823		list_for_each_entry(w, &sdev->widget_list, list) {
 824			struct snd_sof_dai *alh_dai;
 825
 826			if (!WIDGET_IS_DAI(w->id) || !w->widget->sname ||
 827			    strcmp(w->widget->sname, swidget->widget->sname))
 828				continue;
 829
 830			alh_dai = w->private;
 831			if (alh_dai->type != SOF_DAI_INTEL_ALH)
 832				continue;
 833
 834			blob->alh_cfg.device_count++;
 835		}
 836
 837		ipc4_copier->copier_config = (uint32_t *)blob;
 838		/* set data.gtw_cfg.config_length based on device_count */
 839		ipc4_copier->data.gtw_cfg.config_length = (sizeof(blob->gw_attr) +
 840							   sizeof(blob->alh_cfg.device_count) +
 841							   sizeof(*blob->alh_cfg.mapping) *
 842							   blob->alh_cfg.device_count) >> 2;
 843		break;
 844	}
 845	case SOF_DAI_INTEL_SSP:
 846		/* set SSP DAI index as the node_id */
 847		ipc4_copier->data.gtw_cfg.node_id |=
 848			SOF_IPC4_NODE_INDEX_INTEL_SSP(ipc4_copier->dai_index);
 849		break;
 850	case SOF_DAI_INTEL_DMIC:
 851		/* set DMIC DAI index as the node_id */
 852		ipc4_copier->data.gtw_cfg.node_id |=
 853			SOF_IPC4_NODE_INDEX_INTEL_DMIC(ipc4_copier->dai_index);
 854		break;
 855	default:
 856		ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL);
 857		if (!ipc4_copier->gtw_attr) {
 858			ret = -ENOMEM;
 859			goto free_available_fmt;
 860		}
 861
 862		ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr;
 863		ipc4_copier->data.gtw_cfg.config_length =
 864			sizeof(struct sof_ipc4_gtw_attributes) >> 2;
 865		break;
 866	}
 867
 868	dai->scomp = scomp;
 869	dai->private = ipc4_copier;
 870
 871	/* set up module info and message header */
 872	ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg);
 873	if (ret)
 874		goto free_copier_config;
 875
 876	return 0;
 877
 878free_copier_config:
 879	kfree(ipc4_copier->copier_config);
 880free_available_fmt:
 881	sof_ipc4_free_audio_fmt(available_fmt);
 882free_copier:
 883	kfree(ipc4_copier);
 884	dai->private = NULL;
 885	dai->scomp = NULL;
 886	return ret;
 887}
 888
 889static void sof_ipc4_widget_free_comp_dai(struct snd_sof_widget *swidget)
 890{
 891	struct sof_ipc4_available_audio_format *available_fmt;
 892	struct snd_sof_dai *dai = swidget->private;
 893	struct sof_ipc4_copier *ipc4_copier;
 894
 895	if (!dai)
 896		return;
 897
 898	if (!dai->private) {
 899		kfree(dai);
 900		swidget->private = NULL;
 901		return;
 902	}
 903
 904	ipc4_copier = dai->private;
 905	available_fmt = &ipc4_copier->available_fmt;
 906
 907	kfree(available_fmt->output_pin_fmts);
 908	if (ipc4_copier->dai_type != SOF_DAI_INTEL_SSP &&
 909	    ipc4_copier->dai_type != SOF_DAI_INTEL_DMIC)
 910		kfree(ipc4_copier->copier_config);
 911	kfree(dai->private);
 912	kfree(dai);
 913	swidget->private = NULL;
 914}
 915
 916static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
 917{
 918	struct snd_soc_component *scomp = swidget->scomp;
 919	struct sof_ipc4_pipeline *pipeline;
 920	struct snd_sof_pipeline *spipe = swidget->spipe;
 921	int ret;
 922
 923	pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL);
 924	if (!pipeline)
 925		return -ENOMEM;
 926
 927	ret = sof_update_ipc_object(scomp, pipeline, SOF_SCHED_TOKENS, swidget->tuples,
 928				    swidget->num_tuples, sizeof(*pipeline), 1);
 929	if (ret) {
 930		dev_err(scomp->dev, "parsing scheduler tokens failed\n");
 931		goto err;
 932	}
 933
 934	swidget->core = pipeline->core_id;
 935	spipe->core_mask |= BIT(pipeline->core_id);
 936
 937	if (pipeline->use_chain_dma) {
 938		dev_dbg(scomp->dev, "Set up chain DMA for %s\n", swidget->widget->name);
 939		swidget->private = pipeline;
 940		return 0;
 941	}
 942
 943	/* parse one set of pipeline tokens */
 944	ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples,
 945				    swidget->num_tuples, sizeof(*swidget), 1);
 946	if (ret) {
 947		dev_err(scomp->dev, "parsing pipeline tokens failed\n");
 948		goto err;
 949	}
 950
 951	dev_dbg(scomp->dev, "pipeline '%s': id %d, pri %d, core_id %u, lp mode %d\n",
 952		swidget->widget->name, swidget->pipeline_id,
 953		pipeline->priority, pipeline->core_id, pipeline->lp_mode);
 954
 955	swidget->private = pipeline;
 956
 957	pipeline->msg.primary = SOF_IPC4_GLB_PIPE_PRIORITY(pipeline->priority);
 958	pipeline->msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_CREATE_PIPELINE);
 959	pipeline->msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
 960	pipeline->msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
 961
 962	pipeline->msg.extension = pipeline->lp_mode;
 963	pipeline->msg.extension |= SOF_IPC4_GLB_PIPE_EXT_CORE_ID(pipeline->core_id);
 964	pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
 965
 966	return 0;
 967err:
 968	kfree(pipeline);
 969	return ret;
 970}
 971
 972static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget)
 973{
 974	struct snd_soc_component *scomp = swidget->scomp;
 975	struct sof_ipc4_gain *gain;
 976	int ret;
 977
 978	gain = kzalloc(sizeof(*gain), GFP_KERNEL);
 979	if (!gain)
 980		return -ENOMEM;
 981
 982	swidget->private = gain;
 983
 984	gain->data.params.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
 985	gain->data.params.init_val = SOF_IPC4_VOL_ZERO_DB;
 986
 987	ret = sof_ipc4_get_audio_fmt(scomp, swidget, &gain->available_fmt, &gain->data.base_config);
 988	if (ret)
 989		goto err;
 990
 991	ret = sof_update_ipc_object(scomp, &gain->data.params, SOF_GAIN_TOKENS,
 992				    swidget->tuples, swidget->num_tuples, sizeof(gain->data), 1);
 993	if (ret) {
 994		dev_err(scomp->dev, "Parsing gain tokens failed\n");
 995		goto err;
 996	}
 997
 998	dev_dbg(scomp->dev,
 999		"pga widget %s: ramp type: %d, ramp duration %d, initial gain value: %#x\n",
1000		swidget->widget->name, gain->data.params.curve_type,
1001		gain->data.params.curve_duration_l, gain->data.params.init_val);
1002
1003	ret = sof_ipc4_widget_setup_msg(swidget, &gain->msg);
1004	if (ret)
1005		goto err;
1006
1007	sof_ipc4_widget_update_kcontrol_module_id(swidget);
1008
1009	return 0;
1010err:
1011	sof_ipc4_free_audio_fmt(&gain->available_fmt);
1012	kfree(gain);
1013	swidget->private = NULL;
1014	return ret;
1015}
1016
1017static void sof_ipc4_widget_free_comp_pga(struct snd_sof_widget *swidget)
1018{
1019	struct sof_ipc4_gain *gain = swidget->private;
1020
1021	if (!gain)
1022		return;
1023
1024	sof_ipc4_free_audio_fmt(&gain->available_fmt);
1025	kfree(swidget->private);
1026	swidget->private = NULL;
1027}
1028
1029static int sof_ipc4_widget_setup_comp_mixer(struct snd_sof_widget *swidget)
1030{
1031	struct snd_soc_component *scomp = swidget->scomp;
1032	struct sof_ipc4_mixer *mixer;
1033	int ret;
1034
1035	dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
1036
1037	mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
1038	if (!mixer)
1039		return -ENOMEM;
1040
1041	swidget->private = mixer;
1042
1043	ret = sof_ipc4_get_audio_fmt(scomp, swidget, &mixer->available_fmt,
1044				     &mixer->base_config);
1045	if (ret)
1046		goto err;
1047
1048	ret = sof_ipc4_widget_setup_msg(swidget, &mixer->msg);
1049	if (ret)
1050		goto err;
1051
1052	return 0;
1053err:
1054	sof_ipc4_free_audio_fmt(&mixer->available_fmt);
1055	kfree(mixer);
1056	swidget->private = NULL;
1057	return ret;
1058}
1059
1060static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget)
1061{
1062	struct snd_soc_component *scomp = swidget->scomp;
1063	struct snd_sof_pipeline *spipe = swidget->spipe;
1064	struct sof_ipc4_src *src;
1065	int ret;
1066
1067	dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
1068
1069	src = kzalloc(sizeof(*src), GFP_KERNEL);
1070	if (!src)
1071		return -ENOMEM;
1072
1073	swidget->private = src;
1074
1075	ret = sof_ipc4_get_audio_fmt(scomp, swidget, &src->available_fmt,
1076				     &src->data.base_config);
1077	if (ret)
1078		goto err;
1079
1080	ret = sof_update_ipc_object(scomp, &src->data, SOF_SRC_TOKENS, swidget->tuples,
1081				    swidget->num_tuples, sizeof(*src), 1);
1082	if (ret) {
1083		dev_err(scomp->dev, "Parsing SRC tokens failed\n");
1084		goto err;
1085	}
1086
1087	spipe->core_mask |= BIT(swidget->core);
1088
1089	dev_dbg(scomp->dev, "SRC sink rate %d\n", src->data.sink_rate);
1090
1091	ret = sof_ipc4_widget_setup_msg(swidget, &src->msg);
1092	if (ret)
1093		goto err;
1094
1095	return 0;
1096err:
1097	sof_ipc4_free_audio_fmt(&src->available_fmt);
1098	kfree(src);
1099	swidget->private = NULL;
1100	return ret;
1101}
1102
1103static int sof_ipc4_widget_setup_comp_asrc(struct snd_sof_widget *swidget)
1104{
1105	struct snd_soc_component *scomp = swidget->scomp;
1106	struct snd_sof_pipeline *spipe = swidget->spipe;
1107	struct sof_ipc4_asrc *asrc;
1108	int ret;
1109
1110	dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
1111
1112	asrc = kzalloc(sizeof(*asrc), GFP_KERNEL);
1113	if (!asrc)
1114		return -ENOMEM;
1115
1116	swidget->private = asrc;
1117
1118	ret = sof_ipc4_get_audio_fmt(scomp, swidget, &asrc->available_fmt,
1119				     &asrc->data.base_config);
1120	if (ret)
1121		goto err;
1122
1123	ret = sof_update_ipc_object(scomp, &asrc->data, SOF_ASRC_TOKENS, swidget->tuples,
1124				    swidget->num_tuples, sizeof(*asrc), 1);
1125	if (ret) {
1126		dev_err(scomp->dev, "Parsing ASRC tokens failed\n");
1127		goto err;
1128	}
1129
1130	spipe->core_mask |= BIT(swidget->core);
1131
1132	dev_dbg(scomp->dev, "ASRC sink rate %d, mode 0x%08x\n",
1133		asrc->data.out_freq, asrc->data.asrc_mode);
1134
1135	ret = sof_ipc4_widget_setup_msg(swidget, &asrc->msg);
1136	if (ret)
1137		goto err;
1138
1139	return 0;
1140err:
1141	sof_ipc4_free_audio_fmt(&asrc->available_fmt);
1142	kfree(asrc);
1143	swidget->private = NULL;
1144	return ret;
1145}
1146
1147static void sof_ipc4_widget_free_comp_src(struct snd_sof_widget *swidget)
1148{
1149	struct sof_ipc4_src *src = swidget->private;
1150
1151	if (!src)
1152		return;
1153
1154	sof_ipc4_free_audio_fmt(&src->available_fmt);
1155	kfree(swidget->private);
1156	swidget->private = NULL;
1157}
1158
1159static void sof_ipc4_widget_free_comp_asrc(struct snd_sof_widget *swidget)
1160{
1161	struct sof_ipc4_asrc *asrc = swidget->private;
1162
1163	if (!asrc)
1164		return;
1165
1166	sof_ipc4_free_audio_fmt(&asrc->available_fmt);
1167	kfree(swidget->private);
1168	swidget->private = NULL;
1169}
1170
1171static void sof_ipc4_widget_free_comp_mixer(struct snd_sof_widget *swidget)
1172{
1173	struct sof_ipc4_mixer *mixer = swidget->private;
1174
1175	if (!mixer)
1176		return;
1177
1178	sof_ipc4_free_audio_fmt(&mixer->available_fmt);
1179	kfree(swidget->private);
1180	swidget->private = NULL;
1181}
1182
1183/*
1184 * Add the process modules support. The process modules are defined as snd_soc_dapm_effect modules.
1185 */
1186static int sof_ipc4_widget_setup_comp_process(struct snd_sof_widget *swidget)
1187{
1188	struct snd_soc_component *scomp = swidget->scomp;
1189	struct sof_ipc4_fw_module *fw_module;
1190	struct snd_sof_pipeline *spipe = swidget->spipe;
1191	struct sof_ipc4_process *process;
1192	void *cfg;
1193	int ret;
1194
1195	process = kzalloc(sizeof(*process), GFP_KERNEL);
1196	if (!process)
1197		return -ENOMEM;
1198
1199	swidget->private = process;
1200
1201	ret = sof_ipc4_get_audio_fmt(scomp, swidget, &process->available_fmt,
1202				     &process->base_config);
1203	if (ret)
1204		goto err;
1205
1206	ret = sof_ipc4_widget_setup_msg(swidget, &process->msg);
1207	if (ret)
1208		goto err;
1209
1210	/* parse process init module payload config type from module info */
1211	fw_module = swidget->module_info;
1212	process->init_config = FIELD_GET(SOF_IPC4_MODULE_INIT_CONFIG_MASK,
1213					 fw_module->man4_module_entry.type);
1214
1215	process->ipc_config_size = sizeof(struct sof_ipc4_base_module_cfg);
1216
1217	/* allocate memory for base config extension if needed */
1218	if (process->init_config == SOF_IPC4_MODULE_INIT_CONFIG_TYPE_BASE_CFG_WITH_EXT) {
1219		struct sof_ipc4_base_module_cfg_ext *base_cfg_ext;
1220		u32 ext_size = struct_size(base_cfg_ext, pin_formats,
1221					   size_add(swidget->num_input_pins,
1222						    swidget->num_output_pins));
1223
1224		base_cfg_ext = kzalloc(ext_size, GFP_KERNEL);
1225		if (!base_cfg_ext) {
1226			ret = -ENOMEM;
1227			goto free_available_fmt;
1228		}
1229
1230		base_cfg_ext->num_input_pin_fmts = swidget->num_input_pins;
1231		base_cfg_ext->num_output_pin_fmts = swidget->num_output_pins;
1232		process->base_config_ext = base_cfg_ext;
1233		process->base_config_ext_size = ext_size;
1234		process->ipc_config_size += ext_size;
1235	}
1236
1237	cfg = kzalloc(process->ipc_config_size, GFP_KERNEL);
1238	if (!cfg) {
1239		ret = -ENOMEM;
1240		goto free_base_cfg_ext;
1241	}
1242
1243	process->ipc_config_data = cfg;
1244
1245	sof_ipc4_widget_update_kcontrol_module_id(swidget);
1246
1247	/* set pipeline core mask to keep track of the core the module is scheduled to run on */
1248	spipe->core_mask |= BIT(swidget->core);
1249
1250	return 0;
1251free_base_cfg_ext:
1252	kfree(process->base_config_ext);
1253	process->base_config_ext = NULL;
1254free_available_fmt:
1255	sof_ipc4_free_audio_fmt(&process->available_fmt);
1256err:
1257	kfree(process);
1258	swidget->private = NULL;
1259	return ret;
1260}
1261
1262static void sof_ipc4_widget_free_comp_process(struct snd_sof_widget *swidget)
1263{
1264	struct sof_ipc4_process *process = swidget->private;
1265
1266	if (!process)
1267		return;
1268
1269	kfree(process->ipc_config_data);
1270	kfree(process->base_config_ext);
1271	sof_ipc4_free_audio_fmt(&process->available_fmt);
1272	kfree(swidget->private);
1273	swidget->private = NULL;
1274}
1275
1276static void
1277sof_ipc4_update_resource_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
1278			       struct sof_ipc4_base_module_cfg *base_config)
1279{
1280	struct sof_ipc4_fw_module *fw_module = swidget->module_info;
1281	struct snd_sof_widget *pipe_widget;
1282	struct sof_ipc4_pipeline *pipeline;
1283	int task_mem, queue_mem;
1284	int ibs, bss, total;
1285
1286	ibs = base_config->ibs;
1287	bss = base_config->is_pages;
1288
1289	task_mem = SOF_IPC4_PIPELINE_OBJECT_SIZE;
1290	task_mem += SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE + bss;
1291
1292	if (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_LL) {
1293		task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_LL_TASK_OBJECT_SIZE);
1294		task_mem += SOF_IPC4_FW_MAX_QUEUE_COUNT * SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE;
1295		task_mem += SOF_IPC4_LL_TASK_LIST_ITEM_SIZE;
1296	} else {
1297		task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_DP_TASK_OBJECT_SIZE);
1298		task_mem += SOF_IPC4_DP_TASK_LIST_SIZE;
1299	}
1300
1301	ibs = SOF_IPC4_FW_ROUNDUP(ibs);
1302	queue_mem = SOF_IPC4_FW_MAX_QUEUE_COUNT * (SOF_IPC4_DATA_QUEUE_OBJECT_SIZE +  ibs);
1303
1304	total = SOF_IPC4_FW_PAGE(task_mem + queue_mem);
1305
1306	pipe_widget = swidget->spipe->pipe_widget;
1307	pipeline = pipe_widget->private;
1308	pipeline->mem_usage += total;
1309
1310	/* Update base_config->cpc from the module manifest */
1311	sof_ipc4_update_cpc_from_manifest(sdev, fw_module, base_config);
1312
1313	if (ignore_cpc) {
1314		dev_dbg(sdev->dev, "%s: ibs / obs: %u / %u, forcing cpc to 0 from %u\n",
1315			swidget->widget->name, base_config->ibs, base_config->obs,
1316			base_config->cpc);
1317		base_config->cpc = 0;
1318	} else {
1319		dev_dbg(sdev->dev, "%s: ibs / obs / cpc: %u / %u / %u\n",
1320			swidget->widget->name, base_config->ibs, base_config->obs,
1321			base_config->cpc);
1322	}
1323}
1324
1325static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev,
1326					      struct snd_sof_widget *swidget)
1327{
1328	struct sof_ipc4_fw_module *fw_module = swidget->module_info;
1329	int max_instances = fw_module->man4_module_entry.instance_max_count;
1330
1331	swidget->instance_id = ida_alloc_max(&fw_module->m_ida, max_instances, GFP_KERNEL);
1332	if (swidget->instance_id < 0) {
1333		dev_err(sdev->dev, "failed to assign instance id for widget %s",
1334			swidget->widget->name);
1335		return swidget->instance_id;
1336	}
1337
1338	return 0;
1339}
1340
1341static u32 sof_ipc4_fmt_cfg_to_type(u32 fmt_cfg)
1342{
1343	/* Fetch  the sample type from the fmt for 8 and 32 bit formats */
1344	u32 __bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt_cfg);
1345
1346	if (__bits == 8 || __bits == 32)
1347		return SOF_IPC4_AUDIO_FORMAT_CFG_SAMPLE_TYPE(fmt_cfg);
1348
1349	/*
1350	 * Return LSB integer type for 20 and 24 formats as the firmware is
1351	 * handling the LSB/MSB alignment internally, for the kernel this
1352	 * should not be taken into account, we treat them as LSB to match with
1353	 * the format we support on the PCM side.
1354	 */
1355	return SOF_IPC4_TYPE_LSB_INTEGER;
1356}
1357
1358/* update hw_params based on the audio stream format */
1359static int sof_ipc4_update_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params,
1360				     struct sof_ipc4_audio_format *fmt, u32 param_to_update)
1361{
1362	struct snd_interval *i;
1363
1364	if (param_to_update & BIT(SNDRV_PCM_HW_PARAM_FORMAT)) {
1365		int valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
1366		int type = sof_ipc4_fmt_cfg_to_type(fmt->fmt_cfg);
1367		snd_pcm_format_t snd_fmt;
1368		struct snd_mask *m;
1369
1370		switch (valid_bits) {
1371		case 8:
1372			switch (type) {
1373			case SOF_IPC4_TYPE_A_LAW:
1374				snd_fmt = SNDRV_PCM_FORMAT_A_LAW;
1375				break;
1376			case SOF_IPC4_TYPE_MU_LAW:
1377				snd_fmt = SNDRV_PCM_FORMAT_MU_LAW;
1378				break;
1379			case SOF_IPC4_TYPE_UNSIGNED_INTEGER:
1380				snd_fmt = SNDRV_PCM_FORMAT_U8;
1381				break;
1382			default:
1383				dev_err(sdev->dev, "Unsupported PCM 8-bit IPC4 type %d\n", type);
1384				return -EINVAL;
1385			}
1386			break;
1387		case 16:
1388			snd_fmt = SNDRV_PCM_FORMAT_S16_LE;
1389			break;
1390		case 24:
1391			snd_fmt = SNDRV_PCM_FORMAT_S24_LE;
1392			break;
1393		case 32:
1394			switch (type) {
1395			case SOF_IPC4_TYPE_LSB_INTEGER:
1396				snd_fmt = SNDRV_PCM_FORMAT_S32_LE;
1397				break;
1398			case SOF_IPC4_TYPE_FLOAT:
1399				snd_fmt = SNDRV_PCM_FORMAT_FLOAT_LE;
1400				break;
1401			default:
1402				dev_err(sdev->dev, "Unsupported PCM 32-bit IPC4 type %d\n", type);
1403				return -EINVAL;
1404			}
1405			break;
1406		default:
1407			dev_err(sdev->dev, "invalid PCM valid_bits %d\n", valid_bits);
1408			return -EINVAL;
1409		}
1410
1411		m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
1412		snd_mask_none(m);
1413		snd_mask_set_format(m, snd_fmt);
1414	}
1415
1416	if (param_to_update & BIT(SNDRV_PCM_HW_PARAM_RATE)) {
1417		unsigned int rate = fmt->sampling_frequency;
1418
1419		i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
1420		i->min = rate;
1421		i->max = rate;
1422	}
1423
1424	if (param_to_update & BIT(SNDRV_PCM_HW_PARAM_CHANNELS)) {
1425		unsigned int channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
1426
1427		i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
1428		i->min = channels;
1429		i->max = channels;
1430	}
1431
1432	return 0;
1433}
1434
1435static bool sof_ipc4_is_single_format(struct snd_sof_dev *sdev,
1436				      struct sof_ipc4_pin_format *pin_fmts, u32 pin_fmts_size)
1437{
1438	struct sof_ipc4_audio_format *fmt;
1439	u32 rate, channels, valid_bits;
1440	int i;
1441
1442	fmt = &pin_fmts[0].audio_fmt;
1443	rate = fmt->sampling_frequency;
1444	channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
1445	valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
1446
1447	/* check if all output formats in topology are the same */
1448	for (i = 1; i < pin_fmts_size; i++) {
1449		u32 _rate, _channels, _valid_bits;
1450
1451		fmt = &pin_fmts[i].audio_fmt;
1452		_rate = fmt->sampling_frequency;
1453		_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
1454		_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
1455
1456		if (_rate != rate || _channels != channels || _valid_bits != valid_bits)
1457			return false;
1458	}
1459
1460	return true;
1461}
1462
1463static int sof_ipc4_init_output_audio_fmt(struct snd_sof_dev *sdev,
1464					  struct snd_sof_widget *swidget,
1465					  struct sof_ipc4_base_module_cfg *base_config,
1466					  struct sof_ipc4_available_audio_format *available_fmt,
1467					  u32 out_ref_rate, u32 out_ref_channels,
1468					  u32 out_ref_valid_bits, u32 out_ref_type)
1469{
1470	struct sof_ipc4_pin_format *pin_fmts = available_fmt->output_pin_fmts;
1471	u32 pin_fmts_size = available_fmt->num_output_formats;
1472	bool single_format;
1473	int i = 0;
1474
1475	if (!pin_fmts_size) {
1476		dev_err(sdev->dev, "no output formats for %s\n",
1477			swidget->widget->name);
1478		return -EINVAL;
1479	}
1480
1481	single_format = sof_ipc4_is_single_format(sdev, pin_fmts, pin_fmts_size);
1482
1483	/* pick the first format if there's only one available or if all formats are the same */
1484	if (single_format)
1485		goto out_fmt;
1486
1487	/*
1488	 * if there are multiple output formats, then choose the output format that matches
1489	 * the reference params
1490	 */
1491	for (i = 0; i < pin_fmts_size; i++) {
1492		struct sof_ipc4_audio_format *fmt = &pin_fmts[i].audio_fmt;
1493
1494		u32 _out_rate, _out_channels, _out_valid_bits, _out_type;
1495
1496		_out_rate = fmt->sampling_frequency;
1497		_out_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
1498		_out_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
1499		_out_type = sof_ipc4_fmt_cfg_to_type(fmt->fmt_cfg);
1500
1501		if (_out_rate == out_ref_rate && _out_channels == out_ref_channels &&
1502		    _out_valid_bits == out_ref_valid_bits && _out_type == out_ref_type)
1503			goto out_fmt;
1504	}
1505
1506	dev_err(sdev->dev,
1507		"%s: Unsupported audio format: %uHz, %ubit, %u channels, type: %d\n",
1508		__func__, out_ref_rate, out_ref_valid_bits, out_ref_channels,
1509		out_ref_type);
1510
1511	return -EINVAL;
1512
1513out_fmt:
1514	base_config->obs = pin_fmts[i].buffer_size;
1515
1516	return i;
1517}
1518
1519static int sof_ipc4_get_valid_bits(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params)
1520{
1521	switch (params_format(params)) {
1522	case SNDRV_PCM_FORMAT_U8:
1523	case SNDRV_PCM_FORMAT_MU_LAW:
1524	case SNDRV_PCM_FORMAT_A_LAW:
1525		return 8;
1526	case SNDRV_PCM_FORMAT_S16_LE:
1527		return 16;
1528	case SNDRV_PCM_FORMAT_S24_LE:
1529		return 24;
1530	case SNDRV_PCM_FORMAT_S32_LE:
1531		return 32;
1532	case SNDRV_PCM_FORMAT_FLOAT_LE:
1533		return 32;
1534	default:
1535		dev_err(sdev->dev, "invalid pcm frame format %d\n", params_format(params));
1536		return -EINVAL;
1537	}
1538}
1539
1540static int sof_ipc4_get_sample_type(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params)
1541{
1542	switch (params_format(params)) {
1543	case SNDRV_PCM_FORMAT_A_LAW:
1544		return SOF_IPC4_TYPE_A_LAW;
1545	case SNDRV_PCM_FORMAT_MU_LAW:
1546		return SOF_IPC4_TYPE_MU_LAW;
1547	case SNDRV_PCM_FORMAT_U8:
1548		return SOF_IPC4_TYPE_UNSIGNED_INTEGER;
1549	case SNDRV_PCM_FORMAT_S16_LE:
1550	case SNDRV_PCM_FORMAT_S24_LE:
1551	case SNDRV_PCM_FORMAT_S32_LE:
1552	case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
1553		return SOF_IPC4_TYPE_LSB_INTEGER;
1554	case SNDRV_PCM_FORMAT_FLOAT_LE:
1555		return SOF_IPC4_TYPE_FLOAT;
1556	default:
1557		dev_err(sdev->dev, "invalid pcm sample type %d\n", params_format(params));
1558		return -EINVAL;
1559	}
1560}
1561
1562static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev,
1563					 struct snd_sof_widget *swidget,
1564					 struct sof_ipc4_base_module_cfg *base_config,
1565					 struct snd_pcm_hw_params *params,
1566					 struct sof_ipc4_available_audio_format *available_fmt)
1567{
1568	struct sof_ipc4_pin_format *pin_fmts = available_fmt->input_pin_fmts;
1569	u32 pin_fmts_size = available_fmt->num_input_formats;
1570	u32 valid_bits;
1571	u32 channels;
1572	u32 rate;
1573	u32 type;
1574	bool single_format;
1575	int sample_valid_bits;
1576	int sample_type;
1577	int i = 0;
1578
1579	if (!pin_fmts_size) {
1580		dev_err(sdev->dev, "no input formats for %s\n", swidget->widget->name);
1581		return -EINVAL;
1582	}
1583
1584	single_format = sof_ipc4_is_single_format(sdev, pin_fmts, pin_fmts_size);
1585	if (single_format)
1586		goto in_fmt;
1587
1588	sample_valid_bits = sof_ipc4_get_valid_bits(sdev, params);
1589	if (sample_valid_bits < 0)
1590		return sample_valid_bits;
1591
1592	sample_type = sof_ipc4_get_sample_type(sdev, params);
1593	if (sample_type < 0)
1594		return sample_type;
1595
1596	/*
1597	 * Search supported input audio formats with pin index 0 to match rate, channels and
1598	 * sample_valid_bits from reference params
1599	 */
1600	for (i = 0; i < pin_fmts_size; i++) {
1601		struct sof_ipc4_audio_format *fmt = &pin_fmts[i].audio_fmt;
1602
1603		if (pin_fmts[i].pin_index)
1604			continue;
1605
1606		rate = fmt->sampling_frequency;
1607		channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
1608		valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
1609		type = sof_ipc4_fmt_cfg_to_type(fmt->fmt_cfg);
1610		if (params_rate(params) == rate && params_channels(params) == channels &&
1611		    sample_valid_bits == valid_bits && sample_type == type)
1612			break;
1613	}
1614
1615	if (i == pin_fmts_size) {
1616		dev_err(sdev->dev,
1617			"%s: Unsupported audio format: %uHz, %ubit, %u channels, type: %d\n",
1618			__func__, params_rate(params), sample_valid_bits,
1619			params_channels(params), sample_type);
1620		return -EINVAL;
1621	}
1622
1623in_fmt:
1624	/* copy input format */
1625	memcpy(&base_config->audio_fmt, &pin_fmts[i].audio_fmt,
1626	       sizeof(struct sof_ipc4_audio_format));
1627
1628	/* set base_cfg ibs/obs */
1629	base_config->ibs = pin_fmts[i].buffer_size;
1630
1631	return i;
1632}
1633
1634static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
1635{
1636	struct sof_ipc4_copier *ipc4_copier = NULL;
1637	struct snd_sof_widget *pipe_widget;
1638	struct sof_ipc4_pipeline *pipeline;
1639
1640	/* reset pipeline memory usage */
1641	pipe_widget = swidget->spipe->pipe_widget;
1642	pipeline = pipe_widget->private;
1643	pipeline->mem_usage = 0;
1644
1645	if (WIDGET_IS_AIF(swidget->id) || swidget->id == snd_soc_dapm_buffer) {
1646		if (pipeline->use_chain_dma) {
1647			pipeline->msg.primary = 0;
1648			pipeline->msg.extension = 0;
1649		}
1650		ipc4_copier = swidget->private;
1651	} else if (WIDGET_IS_DAI(swidget->id)) {
1652		struct snd_sof_dai *dai = swidget->private;
1653
1654		ipc4_copier = dai->private;
1655
1656		if (pipeline->use_chain_dma) {
1657			/*
1658			 * Preserve the DMA Link ID and clear other bits since
1659			 * the DMA Link ID is only configured once during
1660			 * dai_config, other fields are expected to be 0 for
1661			 * re-configuration
1662			 */
1663			pipeline->msg.primary &= SOF_IPC4_GLB_CHAIN_DMA_LINK_ID_MASK;
1664			pipeline->msg.extension = 0;
1665		}
1666
1667		if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
1668			struct sof_ipc4_alh_configuration_blob *blob;
1669			unsigned int group_id;
1670
1671			blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
1672			if (blob->alh_cfg.device_count > 1) {
1673				group_id = SOF_IPC4_NODE_INDEX(ipc4_copier->data.gtw_cfg.node_id) -
1674					   ALH_MULTI_GTW_BASE;
1675				ida_free(&alh_group_ida, group_id);
1676			}
1677		}
1678	}
1679
1680	if (ipc4_copier) {
1681		kfree(ipc4_copier->ipc_config_data);
1682		ipc4_copier->ipc_config_data = NULL;
1683		ipc4_copier->ipc_config_size = 0;
1684	}
1685}
1686
1687#if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_INTEL_NHLT)
1688static int snd_sof_get_hw_config_params(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
1689					int *sample_rate, int *channel_count, int *bit_depth)
1690{
1691	struct snd_soc_tplg_hw_config *hw_config;
1692	struct snd_sof_dai_link *slink;
1693	bool dai_link_found = false;
1694	bool hw_cfg_found = false;
1695	int i;
1696
1697	/* get current hw_config from link */
1698	list_for_each_entry(slink, &sdev->dai_link_list, list) {
1699		if (!strcmp(slink->link->name, dai->name)) {
1700			dai_link_found = true;
1701			break;
1702		}
1703	}
1704
1705	if (!dai_link_found) {
1706		dev_err(sdev->dev, "%s: no DAI link found for DAI %s\n", __func__, dai->name);
1707		return -EINVAL;
1708	}
1709
1710	for (i = 0; i < slink->num_hw_configs; i++) {
1711		hw_config = &slink->hw_configs[i];
1712		if (dai->current_config == le32_to_cpu(hw_config->id)) {
1713			hw_cfg_found = true;
1714			break;
1715		}
1716	}
1717
1718	if (!hw_cfg_found) {
1719		dev_err(sdev->dev, "%s: no matching hw_config found for DAI %s\n", __func__,
1720			dai->name);
1721		return -EINVAL;
1722	}
1723
1724	*bit_depth = le32_to_cpu(hw_config->tdm_slot_width);
1725	*channel_count = le32_to_cpu(hw_config->tdm_slots);
1726	*sample_rate = le32_to_cpu(hw_config->fsync_rate);
1727
1728	dev_dbg(sdev->dev, "sample rate: %d sample width: %d channels: %d\n",
1729		*sample_rate, *bit_depth, *channel_count);
1730
1731	return 0;
1732}
1733
1734static int
1735snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
1736			       bool single_bitdepth,
1737			       struct snd_pcm_hw_params *params, u32 dai_index,
1738			       u32 linktype, u8 dir, u32 **dst, u32 *len)
1739{
1740	struct sof_ipc4_fw_data *ipc4_data = sdev->private;
1741	struct nhlt_specific_cfg *cfg;
1742	int sample_rate, channel_count;
1743	bool format_change = false;
1744	int bit_depth, ret;
1745	u32 nhlt_type;
1746	int dev_type = 0;
1747
1748	/* convert to NHLT type */
1749	switch (linktype) {
1750	case SOF_DAI_INTEL_DMIC:
1751		nhlt_type = NHLT_LINK_DMIC;
1752		channel_count = params_channels(params);
1753		sample_rate = params_rate(params);
1754		bit_depth = params_width(params);
1755
1756		/* Prefer 32-bit blob if copier supports multiple formats */
1757		if (bit_depth <= 16 && !single_bitdepth) {
1758			dev_dbg(sdev->dev, "Looking for 32-bit blob first for DMIC\n");
1759			format_change = true;
1760			bit_depth = 32;
1761		}
1762		break;
1763	case SOF_DAI_INTEL_SSP:
1764		nhlt_type = NHLT_LINK_SSP;
1765		ret = snd_sof_get_hw_config_params(sdev, dai, &sample_rate, &channel_count,
1766						   &bit_depth);
1767		if (ret < 0)
1768			return ret;
1769
1770		/*
1771		 * We need to know the type of the external device attached to a SSP
1772		 * port to retrieve the blob from NHLT. However, device type is not
1773		 * specified in topology.
1774		 * Query the type for the port and then pass that information back
1775		 * to the blob lookup function.
1776		 */
1777		dev_type = intel_nhlt_ssp_device_type(sdev->dev, ipc4_data->nhlt,
1778						      dai_index);
1779		if (dev_type < 0)
1780			return dev_type;
1781		break;
1782	default:
1783		return 0;
1784	}
1785
1786	dev_dbg(sdev->dev, "dai index %d nhlt type %d direction %d dev type %d\n",
1787		dai_index, nhlt_type, dir, dev_type);
1788
1789	/* find NHLT blob with matching params */
1790	cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt, dai_index, nhlt_type,
1791					   bit_depth, bit_depth, channel_count, sample_rate,
1792					   dir, dev_type);
1793
1794	if (!cfg) {
1795		bool get_new_blob = false;
1796
1797		if (format_change) {
1798			/*
1799			 * The 32-bit blob was not found in NHLT table, try to
1800			 * look for 16-bit for DMIC or based on the params for
1801			 * SSP
1802			 */
1803			if (linktype == SOF_DAI_INTEL_DMIC) {
1804				bit_depth = 16;
1805				if (params_width(params) == 16)
1806					format_change = false;
1807			} else {
1808				bit_depth = params_width(params);
1809				format_change = false;
1810			}
1811
1812			get_new_blob = true;
1813		} else if (linktype == SOF_DAI_INTEL_DMIC && !single_bitdepth) {
1814			/*
1815			 * The requested 32-bit blob (no format change for the
1816			 * blob request) was not found in NHLT table, try to
1817			 * look for 16-bit blob if the copier supports multiple
1818			 * formats
1819			 */
1820			bit_depth = 16;
1821			format_change = true;
1822			get_new_blob = true;
1823		}
1824
1825		if (get_new_blob) {
1826			cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt,
1827							   dai_index, nhlt_type,
1828							   bit_depth, bit_depth,
1829							   channel_count, sample_rate,
1830							   dir, dev_type);
1831			if (cfg)
1832				goto out;
1833		}
1834
1835		dev_err(sdev->dev,
1836			"no matching blob for sample rate: %d sample width: %d channels: %d\n",
1837			sample_rate, bit_depth, channel_count);
1838		return -EINVAL;
1839	}
1840
1841out:
1842	/* config length should be in dwords */
1843	*len = cfg->size >> 2;
1844	*dst = (u32 *)cfg->caps;
1845
1846	if (format_change || params_format(params) == SNDRV_PCM_FORMAT_FLOAT_LE) {
1847		/*
1848		 * Update the params to reflect that different blob was loaded
1849		 * instead of the requested bit depth (16 -> 32 or 32 -> 16).
1850		 * This information is going to be used by the caller to find
1851		 * matching copier format on the dai side.
1852		 */
1853		struct snd_mask *m;
1854
1855		m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
1856		snd_mask_none(m);
1857		if (bit_depth == 16)
1858			snd_mask_set_format(m, SNDRV_PCM_FORMAT_S16_LE);
1859		else
1860			snd_mask_set_format(m, SNDRV_PCM_FORMAT_S32_LE);
1861
1862	}
1863
1864	return 0;
1865}
1866#else
1867static int
1868snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
1869			       bool single_bitdepth,
1870			       struct snd_pcm_hw_params *params, u32 dai_index,
1871			       u32 linktype, u8 dir, u32 **dst, u32 *len)
1872{
1873	return 0;
1874}
1875#endif
1876
1877bool sof_ipc4_copier_is_single_bitdepth(struct snd_sof_dev *sdev,
1878					struct sof_ipc4_pin_format *pin_fmts,
1879					u32 pin_fmts_size)
1880{
1881	struct sof_ipc4_audio_format *fmt;
1882	u32 valid_bits;
1883	int i;
1884
1885	fmt = &pin_fmts[0].audio_fmt;
1886	valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
1887
1888	/* check if all formats in topology are the same */
1889	for (i = 1; i < pin_fmts_size; i++) {
1890		u32 _valid_bits;
1891
1892		fmt = &pin_fmts[i].audio_fmt;
1893		_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
1894
1895		if (_valid_bits != valid_bits)
1896			return false;
1897	}
1898
1899	return true;
1900}
1901
1902static int
1903sof_ipc4_adjust_params_to_dai_format(struct snd_sof_dev *sdev,
1904				     struct snd_pcm_hw_params *params,
1905				     struct sof_ipc4_pin_format *pin_fmts,
1906				     u32 pin_fmts_size)
1907{
1908	u32 params_mask = BIT(SNDRV_PCM_HW_PARAM_RATE) |
1909			  BIT(SNDRV_PCM_HW_PARAM_CHANNELS) |
1910			  BIT(SNDRV_PCM_HW_PARAM_FORMAT);
1911	struct sof_ipc4_audio_format *fmt;
1912	u32 rate, channels, valid_bits;
1913	int i;
1914
1915	fmt = &pin_fmts[0].audio_fmt;
1916	rate = fmt->sampling_frequency;
1917	channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
1918	valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
1919
1920	/* check if parameters in topology defined formats are the same */
1921	for (i = 1; i < pin_fmts_size; i++) {
1922		u32 val;
1923
1924		fmt = &pin_fmts[i].audio_fmt;
1925
1926		if (params_mask & BIT(SNDRV_PCM_HW_PARAM_RATE)) {
1927			val = fmt->sampling_frequency;
1928			if (val != rate)
1929				params_mask &= ~BIT(SNDRV_PCM_HW_PARAM_RATE);
1930		}
1931		if (params_mask & BIT(SNDRV_PCM_HW_PARAM_CHANNELS)) {
1932			val = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
1933			if (val != channels)
1934				params_mask &= ~BIT(SNDRV_PCM_HW_PARAM_CHANNELS);
1935		}
1936		if (params_mask & BIT(SNDRV_PCM_HW_PARAM_FORMAT)) {
1937			val = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
1938			if (val != valid_bits)
1939				params_mask &= ~BIT(SNDRV_PCM_HW_PARAM_FORMAT);
1940		}
1941	}
1942
1943	if (params_mask)
1944		return sof_ipc4_update_hw_params(sdev, params,
1945						 &pin_fmts[0].audio_fmt,
1946						 params_mask);
1947
1948	return 0;
1949}
1950
1951static int
1952sof_ipc4_prepare_dai_copier(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
1953			    struct snd_pcm_hw_params *params, int dir)
1954{
1955	struct sof_ipc4_available_audio_format *available_fmt;
1956	struct snd_pcm_hw_params dai_params = *params;
1957	struct sof_ipc4_copier_data *copier_data;
1958	struct sof_ipc4_pin_format *pin_fmts;
1959	struct sof_ipc4_copier *ipc4_copier;
1960	bool single_bitdepth;
1961	u32 num_pin_fmts;
1962	int ret;
1963
1964	ipc4_copier = dai->private;
1965	copier_data = &ipc4_copier->data;
1966	available_fmt = &ipc4_copier->available_fmt;
1967
1968	/*
1969	 * Fixup the params based on the format parameters of the DAI. If any
1970	 * of the RATE, CHANNELS, bit depth is static among the formats then
1971	 * narrow the params to only allow that specific parameter value.
1972	 */
1973	if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
1974		pin_fmts = available_fmt->output_pin_fmts;
1975		num_pin_fmts = available_fmt->num_output_formats;
1976	} else {
1977		pin_fmts = available_fmt->input_pin_fmts;
1978		num_pin_fmts = available_fmt->num_input_formats;
1979	}
1980
1981	ret = sof_ipc4_adjust_params_to_dai_format(sdev, &dai_params, pin_fmts,
1982						   num_pin_fmts);
1983	if (ret)
1984		return ret;
1985
1986	single_bitdepth = sof_ipc4_copier_is_single_bitdepth(sdev, pin_fmts,
1987							     num_pin_fmts);
1988	ret = snd_sof_get_nhlt_endpoint_data(sdev, dai, single_bitdepth,
1989					     &dai_params,
1990					     ipc4_copier->dai_index,
1991					     ipc4_copier->dai_type, dir,
1992					     &ipc4_copier->copier_config,
1993					     &copier_data->gtw_cfg.config_length);
1994	/* Update the params to reflect the changes made in this function */
1995	if (!ret)
1996		*params = dai_params;
1997
1998	return ret;
1999}
2000
2001static int
2002sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
2003			       struct snd_pcm_hw_params *fe_params,
2004			       struct snd_sof_platform_stream_params *platform_params,
2005			       struct snd_pcm_hw_params *pipeline_params, int dir)
2006{
2007	struct sof_ipc4_available_audio_format *available_fmt;
2008	struct snd_soc_component *scomp = swidget->scomp;
2009	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
2010	struct sof_ipc4_copier_data *copier_data;
2011	int input_fmt_index, output_fmt_index;
2012	struct sof_ipc4_copier *ipc4_copier;
2013	struct snd_pcm_hw_params *ref_params __free(kfree) = NULL;
2014	struct snd_sof_dai *dai;
2015	u32 gtw_cfg_config_length;
2016	u32 dma_config_tlv_size = 0;
2017	void **ipc_config_data;
2018	int *ipc_config_size;
2019	u32 **data;
2020	int ipc_size, ret, out_ref_valid_bits;
2021	u32 out_ref_rate, out_ref_channels, out_ref_type;
2022	u32 deep_buffer_dma_ms = 0;
2023	bool single_output_bitdepth;
2024	int i;
2025
2026	switch (swidget->id) {
2027	case snd_soc_dapm_aif_in:
2028	case snd_soc_dapm_aif_out:
2029	{
2030		struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
2031		struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
2032		struct sof_ipc4_gtw_attributes *gtw_attr;
2033
2034		dev_dbg(sdev->dev,
2035			"Host copier %s, type %d, ChainDMA: %s, stream_tag: %d\n",
2036			swidget->widget->name, swidget->id,
2037			str_yes_no(pipeline->use_chain_dma),
2038			platform_params->stream_tag);
2039
2040		/* parse the deep buffer dma size */
2041		ret = sof_update_ipc_object(scomp, &deep_buffer_dma_ms,
2042					    SOF_COPIER_DEEP_BUFFER_TOKENS, swidget->tuples,
2043					    swidget->num_tuples, sizeof(u32), 1);
2044		if (ret) {
2045			dev_err(scomp->dev, "Failed to parse deep buffer dma size for %s\n",
2046				swidget->widget->name);
2047			return ret;
2048		}
2049
2050		ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
2051		gtw_attr = ipc4_copier->gtw_attr;
2052		copier_data = &ipc4_copier->data;
2053		available_fmt = &ipc4_copier->available_fmt;
2054
2055		if (pipeline->use_chain_dma) {
2056			u32 host_dma_id;
2057			u32 fifo_size;
2058
2059			host_dma_id = platform_params->stream_tag - 1;
2060			pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_HOST_ID(host_dma_id);
2061
2062			if (params_format(fe_params) == SNDRV_PCM_FORMAT_S16_LE)
2063				pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_SCS_MASK;
2064
2065			/* Set SCS bit for 8 and 16 bit formats */
2066			if (params_physical_width(fe_params) <= 16)
2067				pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_SCS_MASK;
2068
2069			/*
2070			 * Despite its name the bitfield 'fifo_size' is used to define DMA buffer
2071			 * size. The expression calculates 2ms buffer size.
2072			 */
2073			fifo_size = DIV_ROUND_UP((SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS *
2074						  params_rate(fe_params) *
2075						  params_channels(fe_params) *
2076						  params_physical_width(fe_params)), 8000);
2077			pipeline->msg.extension |= SOF_IPC4_GLB_EXT_CHAIN_DMA_FIFO_SIZE(fifo_size);
2078
2079			/*
2080			 * Chain DMA does not support stream timestamping, but it
2081			 * can use the host side registers for delay calculation.
2082			 */
2083			copier_data->gtw_cfg.node_id = SOF_IPC4_CHAIN_DMA_NODE_ID;
2084
2085			return 0;
2086		}
2087
2088		/*
2089		 * Use the input_pin_fmts to match pcm params for playback and the output_pin_fmts
2090		 * for capture.
2091		 */
2092		if (dir == SNDRV_PCM_STREAM_PLAYBACK)
2093			ref_params = kmemdup(fe_params, sizeof(*ref_params), GFP_KERNEL);
2094		else
2095			ref_params = kmemdup(pipeline_params, sizeof(*ref_params), GFP_KERNEL);
2096		if (!ref_params)
2097			return -ENOMEM;
2098
2099		copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
2100		copier_data->gtw_cfg.node_id |=
2101			SOF_IPC4_NODE_INDEX(platform_params->stream_tag - 1);
2102
2103		/* set gateway attributes */
2104		gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
2105		break;
2106	}
2107	case snd_soc_dapm_dai_in:
2108	case snd_soc_dapm_dai_out:
2109	{
2110		struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
2111		struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
2112
2113		dev_dbg(sdev->dev, "Dai copier %s, type %d, ChainDMA: %s\n",
2114			swidget->widget->name, swidget->id,
2115			str_yes_no(pipeline->use_chain_dma));
2116
2117		if (pipeline->use_chain_dma)
2118			return 0;
2119
2120		dai = swidget->private;
2121
2122		ipc4_copier = (struct sof_ipc4_copier *)dai->private;
2123		copier_data = &ipc4_copier->data;
2124		available_fmt = &ipc4_copier->available_fmt;
2125
2126		/*
2127		 * Use the fe_params as a base for the copier configuration.
2128		 * The ref_params might get updated to reflect what format is
2129		 * supported by the copier on the DAI side.
2130		 *
2131		 * In case of capture the ref_params returned will be used to
2132		 * find the input configuration of the copier.
2133		 */
2134		ref_params = kmemdup(fe_params, sizeof(*ref_params), GFP_KERNEL);
2135		if (!ref_params)
2136			return -ENOMEM;
2137
2138		ret = sof_ipc4_prepare_dai_copier(sdev, dai, ref_params, dir);
2139		if (ret < 0)
2140			return ret;
2141
2142		/*
2143		 * For playback the pipeline_params needs to be used to find the
2144		 * input configuration of the copier.
2145		 */
2146		if (dir == SNDRV_PCM_STREAM_PLAYBACK)
2147			memcpy(ref_params, pipeline_params, sizeof(*ref_params));
2148
2149		break;
2150	}
2151	case snd_soc_dapm_buffer:
2152	{
2153		dev_dbg(sdev->dev, "Module copier %s, type %d\n",
2154			swidget->widget->name, swidget->id);
2155
2156		ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
2157		copier_data = &ipc4_copier->data;
2158		available_fmt = &ipc4_copier->available_fmt;
2159
2160		ref_params = kmemdup(pipeline_params, sizeof(*ref_params), GFP_KERNEL);
2161		if (!ref_params)
2162			return -ENOMEM;
2163
2164		break;
2165	}
2166	default:
2167		dev_err(sdev->dev, "unsupported type %d for copier %s",
2168			swidget->id, swidget->widget->name);
2169		return -EINVAL;
2170	}
2171
2172	/* set input and output audio formats */
2173	input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget,
2174							&copier_data->base_config,
2175							ref_params, available_fmt);
2176	if (input_fmt_index < 0)
2177		return input_fmt_index;
2178
2179	/* set the reference params for output format selection */
2180	single_output_bitdepth = sof_ipc4_copier_is_single_bitdepth(sdev,
2181					available_fmt->output_pin_fmts,
2182					available_fmt->num_output_formats);
2183	switch (swidget->id) {
2184	case snd_soc_dapm_aif_in:
2185	case snd_soc_dapm_dai_out:
2186	case snd_soc_dapm_buffer:
2187	{
2188		struct sof_ipc4_audio_format *in_fmt;
2189
2190		in_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt;
2191		out_ref_rate = in_fmt->sampling_frequency;
2192		out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
2193		out_ref_type = sof_ipc4_fmt_cfg_to_type(in_fmt->fmt_cfg);
2194
2195		if (!single_output_bitdepth)
2196			out_ref_valid_bits =
2197				SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
2198		break;
2199	}
2200	case snd_soc_dapm_aif_out:
2201	case snd_soc_dapm_dai_in:
2202		out_ref_rate = params_rate(fe_params);
2203		out_ref_channels = params_channels(fe_params);
2204		ret = sof_ipc4_get_sample_type(sdev, fe_params);
2205		if (ret < 0)
2206			return ret;
2207		out_ref_type = (u32)ret;
2208
2209		if (!single_output_bitdepth) {
2210			out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params);
2211			if (out_ref_valid_bits < 0)
2212				return out_ref_valid_bits;
2213		}
2214		break;
2215	default:
2216		/*
2217		 * Unsupported type should be caught by the former switch default
2218		 * case, this should never happen in reality.
2219		 */
2220		return -EINVAL;
2221	}
2222
2223	/*
2224	 * if the output format is the same across all available output formats, choose
2225	 * that as the reference.
2226	 */
2227	if (single_output_bitdepth) {
2228		struct sof_ipc4_audio_format *out_fmt;
2229
2230		out_fmt = &available_fmt->output_pin_fmts[0].audio_fmt;
2231		out_ref_valid_bits =
2232			SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(out_fmt->fmt_cfg);
2233		out_ref_type = sof_ipc4_fmt_cfg_to_type(out_fmt->fmt_cfg);
2234	}
2235
2236	output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget,
2237							  &copier_data->base_config,
2238							  available_fmt, out_ref_rate,
2239							  out_ref_channels, out_ref_valid_bits,
2240							  out_ref_type);
2241	if (output_fmt_index < 0)
2242		return output_fmt_index;
2243
2244	/*
2245	 * Set the output format. Current topology defines pin 0 input and output formats in pairs.
2246	 * This assumes that the pin 0 formats are defined before all other pins.
2247	 * So pick the output audio format with the same index as the chosen
2248	 * input format. This logic will need to be updated when the format definitions
2249	 * in topology change.
2250	 */
2251	memcpy(&copier_data->out_format,
2252	       &available_fmt->output_pin_fmts[output_fmt_index].audio_fmt,
2253	       sizeof(struct sof_ipc4_audio_format));
2254
2255	switch (swidget->id) {
2256	case snd_soc_dapm_dai_in:
2257	case snd_soc_dapm_dai_out:
2258	{
2259		/*
2260		 * Only SOF_DAI_INTEL_ALH needs copier_data to set blob.
2261		 * That's why only ALH dai's blob is set after sof_ipc4_init_input_audio_fmt
2262		 */
2263		if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
2264			struct sof_ipc4_alh_configuration_blob *blob;
2265			struct sof_ipc4_dma_config *dma_config;
2266			struct sof_ipc4_copier_data *alh_data;
2267			struct sof_ipc4_copier *alh_copier;
2268			struct snd_sof_widget *w;
2269			u32 ch_count = 0;
2270			u32 ch_mask = 0;
2271			u32 ch_map;
2272			u32 step;
2273			u32 mask;
2274
2275			blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
2276
2277			blob->gw_attr.lp_buffer_alloc = 0;
2278
2279			/* Get channel_mask from ch_map */
2280			ch_map = copier_data->base_config.audio_fmt.ch_map;
2281			for (i = 0; ch_map; i++) {
2282				if ((ch_map & 0xf) != 0xf) {
2283					ch_mask |= BIT(i);
2284					ch_count++;
2285				}
2286				ch_map >>= 4;
2287			}
2288
2289			if (swidget->id == snd_soc_dapm_dai_in && ch_count == out_ref_channels) {
2290				/*
2291				 * For playback DAI widgets where the channel number is equal to
2292				 * the output reference channels, set the step = 0 to ensure all
2293				 * the ch_mask is applied to all alh mappings.
2294				 */
2295				mask = ch_mask;
2296				step = 0;
2297			} else {
2298				step = ch_count / blob->alh_cfg.device_count;
2299				mask =  GENMASK(step - 1, 0);
2300			}
2301
2302			/*
2303			 * Set each gtw_cfg.node_id to blob->alh_cfg.mapping[]
2304			 * for all widgets with the same stream name
2305			 */
2306			i = 0;
2307			list_for_each_entry(w, &sdev->widget_list, list) {
2308				u32 node_type;
2309
2310				if (!WIDGET_IS_DAI(w->id) || !w->widget->sname ||
2311				    strcmp(w->widget->sname, swidget->widget->sname))
2312					continue;
2313
2314				dai = w->private;
2315				if (dai->type != SOF_DAI_INTEL_ALH)
2316					continue;
2317				alh_copier = (struct sof_ipc4_copier *)dai->private;
2318				alh_data = &alh_copier->data;
2319				node_type = SOF_IPC4_GET_NODE_TYPE(alh_data->gtw_cfg.node_id);
2320				blob->alh_cfg.mapping[i].device = SOF_IPC4_NODE_TYPE(node_type);
2321				blob->alh_cfg.mapping[i].device |=
2322					SOF_IPC4_NODE_INDEX(alh_copier->dai_index);
2323
2324				/*
2325				 * The mapping[i] device in ALH blob should be the same as the
2326				 * dma_config_tlv[i] mapping device if a dma_config_tlv is present.
2327				 * The device id will be used for DMA tlv mapping purposes.
2328				 */
2329				if (ipc4_copier->dma_config_tlv[i].length) {
2330					dma_config = &ipc4_copier->dma_config_tlv[i].dma_config;
2331					blob->alh_cfg.mapping[i].device =
2332						dma_config->dma_stream_channel_map.mapping[0].device;
2333				}
2334
2335				/*
2336				 * Set the same channel mask if the widget channel count is the same
2337				 * as the FE channels for playback as the audio data is duplicated
2338				 * for all speakers in this case. Otherwise, split the channels
2339				 * among the aggregated DAIs. For example, with 4 channels on 2
2340				 * aggregated DAIs, the channel_mask should be 0x3 and 0xc for the
2341				 * two DAI's.
2342				 * The channel masks used depend on the cpu_dais used in the
2343				 * dailink at the machine driver level, which actually comes from
2344				 * the tables in soc_acpi files depending on the _ADR and devID
2345				 * registers for each codec.
2346				 */
2347				blob->alh_cfg.mapping[i].channel_mask = mask << (step * i);
2348
2349				i++;
2350			}
2351			if (blob->alh_cfg.device_count > 1) {
2352				int group_id;
2353
2354				group_id = ida_alloc_max(&alh_group_ida, ALH_MULTI_GTW_COUNT - 1,
2355							 GFP_KERNEL);
2356
2357				if (group_id < 0)
2358					return group_id;
2359
2360				/* add multi-gateway base */
2361				group_id += ALH_MULTI_GTW_BASE;
2362				copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
2363				copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(group_id);
2364			}
2365		}
2366	}
2367	}
2368
2369	/* modify the input params for the next widget */
2370	ret = sof_ipc4_update_hw_params(sdev, pipeline_params,
2371					&copier_data->out_format,
2372					BIT(SNDRV_PCM_HW_PARAM_FORMAT) |
2373					BIT(SNDRV_PCM_HW_PARAM_CHANNELS) |
2374					BIT(SNDRV_PCM_HW_PARAM_RATE));
2375	if (ret)
2376		return ret;
2377
2378	/*
2379	 * Set the gateway dma_buffer_size to 2ms buffer size to meet the FW expectation. In the
2380	 * deep buffer case, set the dma_buffer_size depending on the deep_buffer_dma_ms set
2381	 * in topology.
2382	 */
2383	switch (swidget->id) {
2384	case snd_soc_dapm_dai_in:
2385		copier_data->gtw_cfg.dma_buffer_size =
2386			SOF_IPC4_MIN_DMA_BUFFER_SIZE * copier_data->base_config.ibs;
2387		break;
2388	case snd_soc_dapm_aif_in:
2389		copier_data->gtw_cfg.dma_buffer_size =
2390			max((u32)SOF_IPC4_MIN_DMA_BUFFER_SIZE, deep_buffer_dma_ms) *
2391				copier_data->base_config.ibs;
2392		dev_dbg(sdev->dev, "copier %s, dma buffer%s: %u ms (%u bytes)",
2393			swidget->widget->name,
2394			deep_buffer_dma_ms ? " (using Deep Buffer)" : "",
2395			max((u32)SOF_IPC4_MIN_DMA_BUFFER_SIZE, deep_buffer_dma_ms),
2396			copier_data->gtw_cfg.dma_buffer_size);
2397		break;
2398	case snd_soc_dapm_dai_out:
2399	case snd_soc_dapm_aif_out:
2400		copier_data->gtw_cfg.dma_buffer_size =
2401			SOF_IPC4_MIN_DMA_BUFFER_SIZE * copier_data->base_config.obs;
2402		break;
2403	default:
2404		break;
2405	}
2406
2407	data = &ipc4_copier->copier_config;
2408	ipc_config_size = &ipc4_copier->ipc_config_size;
2409	ipc_config_data = &ipc4_copier->ipc_config_data;
2410
2411	/* config_length is DWORD based */
2412	gtw_cfg_config_length = copier_data->gtw_cfg.config_length * 4;
2413	ipc_size = sizeof(*copier_data) + gtw_cfg_config_length;
2414
2415	dma_config_tlv_size = 0;
2416	for (i = 0; i < SOF_IPC4_DMA_DEVICE_MAX_COUNT; i++) {
2417		if (ipc4_copier->dma_config_tlv[i].type != SOF_IPC4_GTW_DMA_CONFIG_ID)
2418			continue;
2419		dma_config_tlv_size += ipc4_copier->dma_config_tlv[i].length;
2420		dma_config_tlv_size +=
2421			ipc4_copier->dma_config_tlv[i].dma_config.dma_priv_config_size;
2422		dma_config_tlv_size += (sizeof(ipc4_copier->dma_config_tlv[i]) -
2423			sizeof(ipc4_copier->dma_config_tlv[i].dma_config));
2424	}
2425
2426	if (dma_config_tlv_size) {
2427		ipc_size += dma_config_tlv_size;
2428
2429		/* we also need to increase the size at the gtw level */
2430		copier_data->gtw_cfg.config_length += dma_config_tlv_size / 4;
2431	}
2432
2433	dev_dbg(sdev->dev, "copier %s, IPC size is %d", swidget->widget->name, ipc_size);
2434
2435	*ipc_config_data = kzalloc(ipc_size, GFP_KERNEL);
2436	if (!*ipc_config_data)
2437		return -ENOMEM;
2438
2439	*ipc_config_size = ipc_size;
2440
2441	sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt,
2442					 input_fmt_index, output_fmt_index);
2443
2444	/* update pipeline memory usage */
2445	sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config);
2446
2447	/* copy IPC data */
2448	memcpy(*ipc_config_data, (void *)copier_data, sizeof(*copier_data));
2449	if (gtw_cfg_config_length)
2450		memcpy(*ipc_config_data + sizeof(*copier_data),
2451		       *data, gtw_cfg_config_length);
2452
2453	/* add DMA Config TLV, if configured */
2454	if (dma_config_tlv_size)
2455		memcpy(*ipc_config_data + sizeof(*copier_data) +
2456		       gtw_cfg_config_length,
2457		       &ipc4_copier->dma_config_tlv, dma_config_tlv_size);
2458
2459	/*
2460	 * Restore gateway config length now that IPC payload is prepared. This avoids
2461	 * counting the DMA CONFIG TLV multiple times
2462	 */
2463	copier_data->gtw_cfg.config_length = gtw_cfg_config_length / 4;
2464
2465	return 0;
2466}
2467
2468static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget,
2469					struct snd_pcm_hw_params *fe_params,
2470					struct snd_sof_platform_stream_params *platform_params,
2471					struct snd_pcm_hw_params *pipeline_params, int dir)
2472{
2473	struct snd_soc_component *scomp = swidget->scomp;
2474	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
2475	struct sof_ipc4_gain *gain = swidget->private;
2476	struct sof_ipc4_available_audio_format *available_fmt = &gain->available_fmt;
2477	struct sof_ipc4_audio_format *in_fmt;
2478	u32 out_ref_rate, out_ref_channels, out_ref_valid_bits, out_ref_type;
2479	int input_fmt_index, output_fmt_index;
2480
2481	input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget,
2482							&gain->data.base_config,
2483							pipeline_params,
2484							available_fmt);
2485	if (input_fmt_index < 0)
2486		return input_fmt_index;
2487
2488	in_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt;
2489	out_ref_rate = in_fmt->sampling_frequency;
2490	out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
2491	out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
2492	out_ref_type = sof_ipc4_fmt_cfg_to_type(in_fmt->fmt_cfg);
2493
2494	output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget,
2495							  &gain->data.base_config,
2496							  available_fmt,
2497							  out_ref_rate,
2498							  out_ref_channels,
2499							  out_ref_valid_bits,
2500							  out_ref_type);
2501	if (output_fmt_index < 0)
2502		return output_fmt_index;
2503
2504	sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt,
2505					 input_fmt_index, output_fmt_index);
2506
2507	/* update pipeline memory usage */
2508	sof_ipc4_update_resource_usage(sdev, swidget, &gain->data.base_config);
2509
2510	return 0;
2511}
2512
2513static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget,
2514					 struct snd_pcm_hw_params *fe_params,
2515					 struct snd_sof_platform_stream_params *platform_params,
2516					 struct snd_pcm_hw_params *pipeline_params, int dir)
2517{
2518	struct snd_soc_component *scomp = swidget->scomp;
2519	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
2520	struct sof_ipc4_mixer *mixer = swidget->private;
2521	struct sof_ipc4_available_audio_format *available_fmt = &mixer->available_fmt;
2522	struct sof_ipc4_audio_format *in_fmt;
2523	u32 out_ref_rate, out_ref_channels, out_ref_valid_bits, out_ref_type;
2524	int input_fmt_index, output_fmt_index;
2525
2526	input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget,
2527							&mixer->base_config,
2528							pipeline_params,
2529							available_fmt);
2530	if (input_fmt_index < 0)
2531		return input_fmt_index;
2532
2533	in_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt;
2534	out_ref_rate = in_fmt->sampling_frequency;
2535	out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
2536	out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
2537	out_ref_type = sof_ipc4_fmt_cfg_to_type(in_fmt->fmt_cfg);
2538
2539	output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget,
2540							  &mixer->base_config,
2541							  available_fmt,
2542							  out_ref_rate,
2543							  out_ref_channels,
2544							  out_ref_valid_bits,
2545							  out_ref_type);
2546	if (output_fmt_index < 0)
2547		return output_fmt_index;
2548
2549	sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt,
2550					 input_fmt_index, output_fmt_index);
2551
2552	/* update pipeline memory usage */
2553	sof_ipc4_update_resource_usage(sdev, swidget, &mixer->base_config);
2554
2555	return 0;
2556}
2557
2558static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget,
2559				       struct snd_pcm_hw_params *fe_params,
2560				       struct snd_sof_platform_stream_params *platform_params,
2561				       struct snd_pcm_hw_params *pipeline_params, int dir)
2562{
2563	struct snd_soc_component *scomp = swidget->scomp;
2564	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
2565	struct sof_ipc4_src *src = swidget->private;
2566	struct sof_ipc4_available_audio_format *available_fmt = &src->available_fmt;
2567	struct sof_ipc4_audio_format *out_audio_fmt;
2568	struct sof_ipc4_audio_format *in_audio_fmt;
2569	u32 out_ref_rate, out_ref_channels, out_ref_valid_bits, out_ref_type;
2570	int output_fmt_index, input_fmt_index;
2571
2572	input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget,
2573							&src->data.base_config,
2574							pipeline_params,
2575							available_fmt);
2576	if (input_fmt_index < 0)
2577		return input_fmt_index;
2578
2579	/*
2580	 * For playback, the SRC sink rate will be configured based on the requested output
2581	 * format, which is restricted to only deal with DAI's with a single format for now.
2582	 */
2583	if (dir == SNDRV_PCM_STREAM_PLAYBACK && available_fmt->num_output_formats > 1) {
2584		dev_err(sdev->dev, "Invalid number of output formats: %d for SRC %s\n",
2585			available_fmt->num_output_formats, swidget->widget->name);
2586		return -EINVAL;
2587	}
2588
2589	/*
2590	 * SRC does not perform format conversion, so the output channels and valid bit depth must
2591	 * be the same as that of the input.
2592	 */
2593	in_audio_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt;
2594	out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_audio_fmt->fmt_cfg);
2595	out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_audio_fmt->fmt_cfg);
2596	out_ref_type = sof_ipc4_fmt_cfg_to_type(in_audio_fmt->fmt_cfg);
2597
2598	/*
2599	 * For capture, the SRC module should convert the rate to match the rate requested by the
2600	 * PCM hw_params. Set the reference params based on the fe_params unconditionally as it
2601	 * will be ignored for playback anyway.
2602	 */
2603	out_ref_rate = params_rate(fe_params);
2604
2605	output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget,
2606							  &src->data.base_config,
2607							  available_fmt,
2608							  out_ref_rate,
2609							  out_ref_channels,
2610							  out_ref_valid_bits,
2611							  out_ref_type);
2612	if (output_fmt_index < 0)
2613		return output_fmt_index;
2614
2615	sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt,
2616					 input_fmt_index, output_fmt_index);
2617
2618	/* update pipeline memory usage */
2619	sof_ipc4_update_resource_usage(sdev, swidget, &src->data.base_config);
2620
2621	out_audio_fmt = &available_fmt->output_pin_fmts[output_fmt_index].audio_fmt;
2622	src->data.sink_rate = out_audio_fmt->sampling_frequency;
2623
2624	/* update pipeline_params for sink widgets */
2625	return sof_ipc4_update_hw_params(sdev, pipeline_params, out_audio_fmt,
2626					 BIT(SNDRV_PCM_HW_PARAM_FORMAT) |
2627					 BIT(SNDRV_PCM_HW_PARAM_CHANNELS) |
2628					 BIT(SNDRV_PCM_HW_PARAM_RATE));
2629}
2630
2631static int
2632sof_ipc4_process_set_pin_formats(struct snd_sof_widget *swidget, int pin_type)
2633{
2634	struct sof_ipc4_process *process = swidget->private;
2635	struct sof_ipc4_base_module_cfg_ext *base_cfg_ext = process->base_config_ext;
2636	struct sof_ipc4_available_audio_format *available_fmt = &process->available_fmt;
2637	struct sof_ipc4_pin_format *pin_format, *format_list_to_search;
2638	struct snd_soc_component *scomp = swidget->scomp;
2639	int num_pins, format_list_count;
2640	int pin_format_offset = 0;
2641	int i, j;
2642
2643	/* set number of pins, offset of pin format and format list to search based on pin type */
2644	if (pin_type == SOF_PIN_TYPE_INPUT) {
2645		num_pins = swidget->num_input_pins;
2646		format_list_to_search = available_fmt->input_pin_fmts;
2647		format_list_count = available_fmt->num_input_formats;
2648	} else {
2649		num_pins = swidget->num_output_pins;
2650		pin_format_offset = swidget->num_input_pins;
2651		format_list_to_search = available_fmt->output_pin_fmts;
2652		format_list_count = available_fmt->num_output_formats;
2653	}
2654
2655	for (i = pin_format_offset; i < num_pins + pin_format_offset; i++) {
2656		pin_format = &base_cfg_ext->pin_formats[i];
2657
2658		/* Pin 0 audio formats are derived from the base config input/output format */
2659		if (i == pin_format_offset) {
2660			if (pin_type == SOF_PIN_TYPE_INPUT) {
2661				pin_format->buffer_size = process->base_config.ibs;
2662				pin_format->audio_fmt = process->base_config.audio_fmt;
2663			} else {
2664				pin_format->buffer_size = process->base_config.obs;
2665				pin_format->audio_fmt = process->output_format;
2666			}
2667			continue;
2668		}
2669
2670		/*
2671		 * For all other pins, find the pin formats from those set in topology. If there
2672		 * is more than one format specified for a pin, this will pick the first available
2673		 * one.
2674		 */
2675		for (j = 0; j < format_list_count; j++) {
2676			struct sof_ipc4_pin_format *pin_format_item = &format_list_to_search[j];
2677
2678			if (pin_format_item->pin_index == i - pin_format_offset) {
2679				*pin_format = *pin_format_item;
2680				break;
2681			}
2682		}
2683
2684		if (j == format_list_count) {
2685			dev_err(scomp->dev, "%s pin %d format not found for %s\n",
2686				(pin_type == SOF_PIN_TYPE_INPUT) ? "input" : "output",
2687				i - pin_format_offset, swidget->widget->name);
2688			return -EINVAL;
2689		}
2690	}
2691
2692	return 0;
2693}
2694
2695static int sof_ipc4_process_add_base_cfg_extn(struct snd_sof_widget *swidget)
2696{
2697	int ret, i;
2698
2699	/* copy input and output pin formats */
2700	for (i = 0; i <= SOF_PIN_TYPE_OUTPUT; i++) {
2701		ret = sof_ipc4_process_set_pin_formats(swidget, i);
2702		if (ret < 0)
2703			return ret;
2704	}
2705
2706	return 0;
2707}
2708
2709static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget,
2710					   struct snd_pcm_hw_params *fe_params,
2711					   struct snd_sof_platform_stream_params *platform_params,
2712					   struct snd_pcm_hw_params *pipeline_params, int dir)
2713{
2714	struct snd_soc_component *scomp = swidget->scomp;
2715	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
2716	struct sof_ipc4_process *process = swidget->private;
2717	struct sof_ipc4_available_audio_format *available_fmt = &process->available_fmt;
2718	void *cfg = process->ipc_config_data;
2719	int output_fmt_index = 0;
2720	int input_fmt_index = 0;
2721	int ret;
2722
2723	input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget,
2724							&process->base_config,
2725							pipeline_params,
2726							available_fmt);
2727	if (input_fmt_index < 0)
2728		return input_fmt_index;
2729
2730	/* Configure output audio format only if the module supports output */
2731	if (available_fmt->num_output_formats) {
2732		struct sof_ipc4_audio_format *in_fmt;
2733		struct sof_ipc4_pin_format *pin_fmt;
2734		u32 out_ref_rate, out_ref_channels;
2735		int out_ref_valid_bits, out_ref_type;
2736
2737		in_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt;
2738
2739		out_ref_rate = in_fmt->sampling_frequency;
2740		out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
2741		out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
2742		out_ref_type = sof_ipc4_fmt_cfg_to_type(in_fmt->fmt_cfg);
2743
2744		output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget,
2745								  &process->base_config,
2746								  available_fmt,
2747								  out_ref_rate,
2748								  out_ref_channels,
2749								  out_ref_valid_bits,
2750								  out_ref_type);
2751		if (output_fmt_index < 0)
2752			return output_fmt_index;
2753
2754		pin_fmt = &available_fmt->output_pin_fmts[output_fmt_index];
2755
2756		/* copy Pin output format for Pin 0 only */
2757		if (pin_fmt->pin_index == 0) {
2758			memcpy(&process->output_format, &pin_fmt->audio_fmt,
2759			       sizeof(struct sof_ipc4_audio_format));
2760
2761			/* modify the pipeline params with the output format */
2762			ret = sof_ipc4_update_hw_params(sdev, pipeline_params,
2763							&process->output_format,
2764							BIT(SNDRV_PCM_HW_PARAM_FORMAT) |
2765							BIT(SNDRV_PCM_HW_PARAM_CHANNELS) |
2766							BIT(SNDRV_PCM_HW_PARAM_RATE));
2767			if (ret)
2768				return ret;
2769		}
2770	}
2771
2772	sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt,
2773					 input_fmt_index, output_fmt_index);
2774
2775	/* update pipeline memory usage */
2776	sof_ipc4_update_resource_usage(sdev, swidget, &process->base_config);
2777
2778	/* ipc_config_data is composed of the base_config followed by an optional extension */
2779	memcpy(cfg, &process->base_config, sizeof(struct sof_ipc4_base_module_cfg));
2780	cfg += sizeof(struct sof_ipc4_base_module_cfg);
2781
2782	if (process->init_config == SOF_IPC4_MODULE_INIT_CONFIG_TYPE_BASE_CFG_WITH_EXT) {
2783		struct sof_ipc4_base_module_cfg_ext *base_cfg_ext = process->base_config_ext;
2784
2785		ret = sof_ipc4_process_add_base_cfg_extn(swidget);
2786		if (ret < 0)
2787			return ret;
2788
2789		memcpy(cfg, base_cfg_ext, process->base_config_ext_size);
2790	}
2791
2792	return 0;
2793}
2794
2795static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
2796{
2797	struct sof_ipc4_control_data *control_data;
2798	struct sof_ipc4_msg *msg;
2799	int i;
2800
2801	scontrol->size = struct_size(control_data, chanv, scontrol->num_channels);
2802
2803	/* scontrol->ipc_control_data will be freed in sof_control_unload */
2804	scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL);
2805	if (!scontrol->ipc_control_data)
2806		return -ENOMEM;
2807
2808	control_data = scontrol->ipc_control_data;
2809	control_data->index = scontrol->index;
2810
2811	msg = &control_data->msg;
2812	msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET);
2813	msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
2814	msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
2815
2816	/* volume controls with range 0-1 (off/on) are switch controls */
2817	if (scontrol->max == 1)
2818		msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_SWITCH_CONTROL_PARAM_ID);
2819	else
2820		msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_GAIN_PARAM_ID);
2821
2822	for (i = 0; i < scontrol->num_channels; i++) {
2823		control_data->chanv[i].channel = i;
2824		/*
2825		 * Default, initial values:
2826		 * - 0dB for volume controls
2827		 * - off (0) for switch controls - value already zero after
2828		 *				   memory allocation
2829		 */
2830		if (scontrol->max > 1)
2831			control_data->chanv[i].value = SOF_IPC4_VOL_ZERO_DB;
2832	}
2833
2834	return 0;
2835}
2836
2837static int sof_ipc4_control_load_enum(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
2838{
2839	struct sof_ipc4_control_data *control_data;
2840	struct sof_ipc4_msg *msg;
2841	int i;
2842
2843	scontrol->size = struct_size(control_data, chanv, scontrol->num_channels);
2844
2845	/* scontrol->ipc_control_data will be freed in sof_control_unload */
2846	scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL);
2847	if (!scontrol->ipc_control_data)
2848		return -ENOMEM;
2849
2850	control_data = scontrol->ipc_control_data;
2851	control_data->index = scontrol->index;
2852
2853	msg = &control_data->msg;
2854	msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET);
2855	msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
2856	msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
2857
2858	msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_ENUM_CONTROL_PARAM_ID);
2859
2860	/* Default, initial value for enums: first enum entry is selected (0) */
2861	for (i = 0; i < scontrol->num_channels; i++)
2862		control_data->chanv[i].channel = i;
2863
2864	return 0;
2865}
2866
2867static int sof_ipc4_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
2868{
2869	struct sof_ipc4_control_data *control_data;
2870	struct sof_ipc4_msg *msg;
2871	int ret;
2872
2873	/*
2874	 * The max_size is coming from topology and indicates the maximum size
2875	 * of sof_abi_hdr plus the payload, which excludes the local only
2876	 * 'struct sof_ipc4_control_data'
2877	 */
2878	if (scontrol->max_size < sizeof(struct sof_abi_hdr)) {
2879		dev_err(sdev->dev,
2880			"insufficient maximum size for a bytes control %s: %zu.\n",
2881			scontrol->name, scontrol->max_size);
2882		return -EINVAL;
2883	}
2884
2885	if (scontrol->priv_size > scontrol->max_size) {
2886		dev_err(sdev->dev,
2887			"bytes control %s initial data size %zu exceeds max %zu.\n",
2888			scontrol->name, scontrol->priv_size, scontrol->max_size);
2889		return -EINVAL;
2890	}
2891
2892	if (scontrol->priv_size && scontrol->priv_size < sizeof(struct sof_abi_hdr)) {
2893		dev_err(sdev->dev,
2894			"bytes control %s initial data size %zu is insufficient.\n",
2895			scontrol->name, scontrol->priv_size);
2896		return -EINVAL;
2897	}
2898
2899	/*
2900	 * The used size behind the cdata pointer, which can be smaller than
2901	 * the maximum size
2902	 */
2903	scontrol->size = sizeof(*control_data) + scontrol->priv_size;
2904
2905	/* Allocate the cdata: local struct size + maximum payload size */
2906	scontrol->ipc_control_data = kzalloc(sizeof(*control_data) + scontrol->max_size,
2907					     GFP_KERNEL);
2908	if (!scontrol->ipc_control_data)
2909		return -ENOMEM;
2910
2911	control_data = scontrol->ipc_control_data;
2912	control_data->index = scontrol->index;
2913	if (scontrol->priv_size > 0) {
2914		memcpy(control_data->data, scontrol->priv, scontrol->priv_size);
2915		kfree(scontrol->priv);
2916		scontrol->priv = NULL;
2917
2918		if (control_data->data->magic != SOF_IPC4_ABI_MAGIC) {
2919			dev_err(sdev->dev, "Wrong ABI magic (%#x) for control: %s\n",
2920				control_data->data->magic, scontrol->name);
2921			ret = -EINVAL;
2922			goto err;
2923		}
2924
2925		/* TODO: check the ABI version */
2926
2927		if (control_data->data->size + sizeof(struct sof_abi_hdr) !=
2928		    scontrol->priv_size) {
2929			dev_err(sdev->dev, "Control %s conflict in bytes %zu vs. priv size %zu.\n",
2930				scontrol->name,
2931				control_data->data->size + sizeof(struct sof_abi_hdr),
2932				scontrol->priv_size);
2933			ret = -EINVAL;
2934			goto err;
2935		}
2936	}
2937
2938	msg = &control_data->msg;
2939	msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET);
2940	msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
2941	msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
2942
2943	return 0;
2944
2945err:
2946	kfree(scontrol->ipc_control_data);
2947	scontrol->ipc_control_data = NULL;
2948	return ret;
2949}
2950
2951static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
2952{
2953	switch (scontrol->info_type) {
2954	case SND_SOC_TPLG_CTL_VOLSW:
2955	case SND_SOC_TPLG_CTL_VOLSW_SX:
2956	case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
2957		return sof_ipc4_control_load_volume(sdev, scontrol);
2958	case SND_SOC_TPLG_CTL_BYTES:
2959		return sof_ipc4_control_load_bytes(sdev, scontrol);
2960	case SND_SOC_TPLG_CTL_ENUM:
2961	case SND_SOC_TPLG_CTL_ENUM_VALUE:
2962		return sof_ipc4_control_load_enum(sdev, scontrol);
2963	default:
2964		break;
2965	}
2966
2967	return 0;
2968}
2969
2970static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
2971{
2972	struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
2973	struct sof_ipc4_fw_data *ipc4_data = sdev->private;
2974	struct sof_ipc4_pipeline *pipeline;
2975	struct sof_ipc4_msg *msg;
2976	void *ipc_data = NULL;
2977	u32 ipc_size = 0;
2978	int ret;
2979
2980	switch (swidget->id) {
2981	case snd_soc_dapm_scheduler:
2982		pipeline = swidget->private;
2983
2984		if (pipeline->use_chain_dma) {
2985			dev_warn(sdev->dev, "use_chain_dma set for scheduler %s",
2986				 swidget->widget->name);
2987			return 0;
2988		}
2989
2990		dev_dbg(sdev->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id,
2991			pipeline->mem_usage);
2992
2993		msg = &pipeline->msg;
2994		msg->primary |= pipeline->mem_usage;
2995
2996		swidget->instance_id = ida_alloc_max(&pipeline_ida, ipc4_data->max_num_pipelines,
2997						     GFP_KERNEL);
2998		if (swidget->instance_id < 0) {
2999			dev_err(sdev->dev, "failed to assign pipeline id for %s: %d\n",
3000				swidget->widget->name, swidget->instance_id);
3001			return swidget->instance_id;
3002		}
3003		msg->primary &= ~SOF_IPC4_GLB_PIPE_INSTANCE_MASK;
3004		msg->primary |= SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id);
3005		break;
3006	case snd_soc_dapm_aif_in:
3007	case snd_soc_dapm_aif_out:
3008	case snd_soc_dapm_buffer:
3009	{
3010		struct sof_ipc4_copier *ipc4_copier = swidget->private;
3011
3012		pipeline = pipe_widget->private;
3013		if (pipeline->use_chain_dma)
3014			return 0;
3015
3016		ipc_size = ipc4_copier->ipc_config_size;
3017		ipc_data = ipc4_copier->ipc_config_data;
3018
3019		msg = &ipc4_copier->msg;
3020		break;
3021	}
3022	case snd_soc_dapm_dai_in:
3023	case snd_soc_dapm_dai_out:
3024	{
3025		struct snd_sof_dai *dai = swidget->private;
3026		struct sof_ipc4_copier *ipc4_copier = dai->private;
3027
3028		pipeline = pipe_widget->private;
3029		if (pipeline->use_chain_dma)
3030			return 0;
3031
3032		ipc_size = ipc4_copier->ipc_config_size;
3033		ipc_data = ipc4_copier->ipc_config_data;
3034
3035		msg = &ipc4_copier->msg;
3036		break;
3037	}
3038	case snd_soc_dapm_pga:
3039	{
3040		struct sof_ipc4_gain *gain = swidget->private;
3041
3042		ipc_size = sizeof(gain->data);
3043		ipc_data = &gain->data;
3044
3045		msg = &gain->msg;
3046		break;
3047	}
3048	case snd_soc_dapm_mixer:
3049	{
3050		struct sof_ipc4_mixer *mixer = swidget->private;
3051
3052		ipc_size = sizeof(mixer->base_config);
3053		ipc_data = &mixer->base_config;
3054
3055		msg = &mixer->msg;
3056		break;
3057	}
3058	case snd_soc_dapm_src:
3059	{
3060		struct sof_ipc4_src *src = swidget->private;
3061
3062		ipc_size = sizeof(src->data);
3063		ipc_data = &src->data;
3064
3065		msg = &src->msg;
3066		break;
3067	}
3068	case snd_soc_dapm_asrc:
3069	{
3070		struct sof_ipc4_asrc *asrc = swidget->private;
3071
3072		ipc_size = sizeof(asrc->data);
3073		ipc_data = &asrc->data;
3074
3075		msg = &asrc->msg;
3076		break;
3077	}
3078	case snd_soc_dapm_effect:
3079	{
3080		struct sof_ipc4_process *process = swidget->private;
3081
3082		if (!process->ipc_config_size) {
3083			dev_err(sdev->dev, "module %s has no config data!\n",
3084				swidget->widget->name);
3085			return -EINVAL;
3086		}
3087
3088		ipc_size = process->ipc_config_size;
3089		ipc_data = process->ipc_config_data;
3090
3091		msg = &process->msg;
3092		break;
3093	}
3094	default:
3095		dev_err(sdev->dev, "widget type %d not supported", swidget->id);
3096		return -EINVAL;
3097	}
3098
3099	if (swidget->id != snd_soc_dapm_scheduler) {
3100		int module_id = msg->primary & SOF_IPC4_MOD_ID_MASK;
3101
3102		ret = sof_ipc4_widget_assign_instance_id(sdev, swidget);
3103		if (ret < 0) {
3104			dev_err(sdev->dev, "failed to assign instance id for %s\n",
3105				swidget->widget->name);
3106			return ret;
3107		}
3108
3109		msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK;
3110		msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id);
3111
3112		msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK;
3113		msg->extension |= SOF_IPC4_MOD_EXT_PARAM_SIZE(ipc_size >> 2);
3114
3115		msg->extension &= ~SOF_IPC4_MOD_EXT_PPL_ID_MASK;
3116		msg->extension |= SOF_IPC4_MOD_EXT_PPL_ID(pipe_widget->instance_id);
3117
3118		dev_dbg(sdev->dev, "Create widget %s (pipe %d) - ID %d, instance %d, core %d\n",
3119			swidget->widget->name, swidget->pipeline_id, module_id,
3120			swidget->instance_id, swidget->core);
3121	} else {
3122		dev_dbg(sdev->dev, "Create pipeline %s (pipe %d) - instance %d, core %d\n",
3123			swidget->widget->name, swidget->pipeline_id,
3124			swidget->instance_id, swidget->core);
3125	}
3126
3127	msg->data_size = ipc_size;
3128	msg->data_ptr = ipc_data;
3129
3130	ret = sof_ipc_tx_message_no_reply(sdev->ipc, msg, ipc_size);
3131	if (ret < 0) {
3132		dev_err(sdev->dev, "failed to create module %s\n", swidget->widget->name);
3133
3134		if (swidget->id != snd_soc_dapm_scheduler) {
3135			struct sof_ipc4_fw_module *fw_module = swidget->module_info;
3136
3137			ida_free(&fw_module->m_ida, swidget->instance_id);
3138		} else {
3139			ida_free(&pipeline_ida, swidget->instance_id);
3140		}
3141	}
3142
3143	return ret;
3144}
3145
3146static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
3147{
3148	struct sof_ipc4_fw_module *fw_module = swidget->module_info;
3149	struct sof_ipc4_fw_data *ipc4_data = sdev->private;
3150	int ret = 0;
3151
3152	mutex_lock(&ipc4_data->pipeline_state_mutex);
3153
3154	/* freeing a pipeline frees all the widgets associated with it */
3155	if (swidget->id == snd_soc_dapm_scheduler) {
3156		struct sof_ipc4_pipeline *pipeline = swidget->private;
3157		struct sof_ipc4_msg msg = {{ 0 }};
3158		u32 header;
3159
3160		if (pipeline->use_chain_dma) {
3161			dev_warn(sdev->dev, "use_chain_dma set for scheduler %s",
3162				 swidget->widget->name);
3163			mutex_unlock(&ipc4_data->pipeline_state_mutex);
3164			return 0;
3165		}
3166
3167		header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id);
3168		header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE);
3169		header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
3170		header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
3171
3172		msg.primary = header;
3173
3174		ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0);
3175		if (ret < 0)
3176			dev_err(sdev->dev, "failed to free pipeline widget %s\n",
3177				swidget->widget->name);
3178
3179		pipeline->mem_usage = 0;
3180		pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
3181		ida_free(&pipeline_ida, swidget->instance_id);
3182		swidget->instance_id = -EINVAL;
3183	} else {
3184		struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
3185		struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
3186
3187		if (!pipeline->use_chain_dma)
3188			ida_free(&fw_module->m_ida, swidget->instance_id);
3189	}
3190
3191	mutex_unlock(&ipc4_data->pipeline_state_mutex);
3192
3193	return ret;
3194}
3195
3196static int sof_ipc4_get_queue_id(struct snd_sof_widget *src_widget,
3197				 struct snd_sof_widget *sink_widget, bool pin_type)
3198{
3199	struct snd_sof_widget *current_swidget;
3200	struct snd_soc_component *scomp;
3201	struct ida *queue_ida;
3202	const char *buddy_name;
3203	char **pin_binding;
3204	u32 num_pins;
3205	int i;
3206
3207	if (pin_type == SOF_PIN_TYPE_OUTPUT) {
3208		current_swidget = src_widget;
3209		pin_binding = src_widget->output_pin_binding;
3210		queue_ida = &src_widget->output_queue_ida;
3211		num_pins = src_widget->num_output_pins;
3212		buddy_name = sink_widget->widget->name;
3213	} else {
3214		current_swidget = sink_widget;
3215		pin_binding = sink_widget->input_pin_binding;
3216		queue_ida = &sink_widget->input_queue_ida;
3217		num_pins = sink_widget->num_input_pins;
3218		buddy_name = src_widget->widget->name;
3219	}
3220
3221	scomp = current_swidget->scomp;
3222
3223	if (num_pins < 1) {
3224		dev_err(scomp->dev, "invalid %s num_pins: %d for queue allocation for %s\n",
3225			(pin_type == SOF_PIN_TYPE_OUTPUT ? "output" : "input"),
3226			num_pins, current_swidget->widget->name);
3227		return -EINVAL;
3228	}
3229
3230	/* If there is only one input/output pin, queue id must be 0 */
3231	if (num_pins == 1)
3232		return 0;
3233
3234	/* Allocate queue ID from pin binding array if it is defined in topology. */
3235	if (pin_binding) {
3236		for (i = 0; i < num_pins; i++) {
3237			if (!strcmp(pin_binding[i], buddy_name))
3238				return i;
3239		}
3240		/*
3241		 * Fail if no queue ID found from pin binding array, so that we don't
3242		 * mixed use pin binding array and ida for queue ID allocation.
3243		 */
3244		dev_err(scomp->dev, "no %s queue id found from pin binding array for %s\n",
3245			(pin_type == SOF_PIN_TYPE_OUTPUT ? "output" : "input"),
3246			current_swidget->widget->name);
3247		return -EINVAL;
3248	}
3249
3250	/* If no pin binding array specified in topology, use ida to allocate one */
3251	return ida_alloc_max(queue_ida, num_pins, GFP_KERNEL);
3252}
3253
3254static void sof_ipc4_put_queue_id(struct snd_sof_widget *swidget, int queue_id,
3255				  bool pin_type)
3256{
3257	struct ida *queue_ida;
3258	char **pin_binding;
3259	int num_pins;
3260
3261	if (pin_type == SOF_PIN_TYPE_OUTPUT) {
3262		pin_binding = swidget->output_pin_binding;
3263		queue_ida = &swidget->output_queue_ida;
3264		num_pins = swidget->num_output_pins;
3265	} else {
3266		pin_binding = swidget->input_pin_binding;
3267		queue_ida = &swidget->input_queue_ida;
3268		num_pins = swidget->num_input_pins;
3269	}
3270
3271	/* Nothing to free if queue ID is not allocated with ida. */
3272	if (num_pins == 1 || pin_binding)
3273		return;
3274
3275	ida_free(queue_ida, queue_id);
3276}
3277
3278static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev,
3279					   struct snd_sof_widget *src_widget,
3280					   struct snd_sof_widget *sink_widget,
3281					   struct snd_sof_route *sroute)
3282{
3283	struct sof_ipc4_copier_config_set_sink_format format;
3284	const struct sof_ipc_ops *iops = sdev->ipc->ops;
3285	struct sof_ipc4_base_module_cfg *src_config;
3286	const struct sof_ipc4_audio_format *pin_fmt;
3287	struct sof_ipc4_fw_module *fw_module;
3288	struct sof_ipc4_msg msg = {{ 0 }};
3289
3290	if (WIDGET_IS_DAI(src_widget->id)) {
3291		struct snd_sof_dai *dai = src_widget->private;
3292
3293		src_config = dai->private;
3294	} else {
3295		src_config = src_widget->private;
3296	}
3297
3298	fw_module = src_widget->module_info;
3299
3300	format.sink_id = sroute->src_queue_id;
3301	memcpy(&format.source_fmt, &src_config->audio_fmt, sizeof(format.source_fmt));
3302
3303	pin_fmt = sof_ipc4_get_input_pin_audio_fmt(sink_widget, sroute->dst_queue_id);
3304	if (!pin_fmt) {
3305		dev_err(sdev->dev,
3306			"Failed to get input audio format of %s:%d for output of %s:%d\n",
3307			sink_widget->widget->name, sroute->dst_queue_id,
3308			src_widget->widget->name, sroute->src_queue_id);
3309		return -EINVAL;
3310	}
3311
3312	memcpy(&format.sink_fmt, pin_fmt, sizeof(format.sink_fmt));
3313
3314	msg.data_size = sizeof(format);
3315	msg.data_ptr = &format;
3316
3317	msg.primary = fw_module->man4_module_entry.id;
3318	msg.primary |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
3319	msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
3320	msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
3321
3322	msg.extension =
3323		SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_COPIER_MODULE_CFG_PARAM_SET_SINK_FORMAT);
3324
3325	return iops->set_get_data(sdev, &msg, msg.data_size, true);
3326}
3327
3328static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
3329{
3330	struct snd_sof_widget *src_widget = sroute->src_widget;
3331	struct snd_sof_widget *sink_widget = sroute->sink_widget;
3332	struct snd_sof_widget *src_pipe_widget = src_widget->spipe->pipe_widget;
3333	struct snd_sof_widget *sink_pipe_widget = sink_widget->spipe->pipe_widget;
3334	struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
3335	struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
3336	struct sof_ipc4_pipeline *src_pipeline = src_pipe_widget->private;
3337	struct sof_ipc4_pipeline *sink_pipeline = sink_pipe_widget->private;
3338	struct sof_ipc4_msg msg = {{ 0 }};
3339	u32 header, extension;
3340	int ret;
3341
3342	/* no route set up if chain DMA is used */
3343	if (src_pipeline->use_chain_dma || sink_pipeline->use_chain_dma) {
3344		if (!src_pipeline->use_chain_dma || !sink_pipeline->use_chain_dma) {
3345			dev_err(sdev->dev,
3346				"use_chain_dma must be set for both src %s and sink %s pipelines\n",
3347				src_widget->widget->name, sink_widget->widget->name);
3348			return -EINVAL;
3349		}
3350		return 0;
3351	}
3352
3353	if (!src_fw_module || !sink_fw_module) {
3354		dev_err(sdev->dev,
3355			"cannot bind %s -> %s, no firmware module for: %s%s\n",
3356			src_widget->widget->name, sink_widget->widget->name,
3357			src_fw_module ? "" : " source",
3358			sink_fw_module ? "" : " sink");
3359
3360		return -ENODEV;
3361	}
3362
3363	sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
3364						     SOF_PIN_TYPE_OUTPUT);
3365	if (sroute->src_queue_id < 0) {
3366		dev_err(sdev->dev,
3367			"failed to get src_queue_id ID from source widget %s\n",
3368			src_widget->widget->name);
3369		return sroute->src_queue_id;
3370	}
3371
3372	sroute->dst_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
3373						     SOF_PIN_TYPE_INPUT);
3374	if (sroute->dst_queue_id < 0) {
3375		dev_err(sdev->dev,
3376			"failed to get dst_queue_id ID from sink widget %s\n",
3377			sink_widget->widget->name);
3378		sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id,
3379				      SOF_PIN_TYPE_OUTPUT);
3380		return sroute->dst_queue_id;
3381	}
3382
3383	/* Pin 0 format is already set during copier module init */
3384	if (sroute->src_queue_id > 0 && WIDGET_IS_COPIER(src_widget->id)) {
3385		ret = sof_ipc4_set_copier_sink_format(sdev, src_widget,
3386						      sink_widget, sroute);
3387		if (ret < 0) {
3388			dev_err(sdev->dev,
3389				"failed to set sink format for source %s:%d\n",
3390				src_widget->widget->name, sroute->src_queue_id);
3391			goto out;
3392		}
3393	}
3394
3395	dev_dbg(sdev->dev, "bind %s:%d -> %s:%d\n",
3396		src_widget->widget->name, sroute->src_queue_id,
3397		sink_widget->widget->name, sroute->dst_queue_id);
3398
3399	header = src_fw_module->man4_module_entry.id;
3400	header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
3401	header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_BIND);
3402	header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
3403	header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
3404
3405	extension = sink_fw_module->man4_module_entry.id;
3406	extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id);
3407	extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id);
3408	extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id);
3409
3410	msg.primary = header;
3411	msg.extension = extension;
3412
3413	ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0);
3414	if (ret < 0) {
3415		dev_err(sdev->dev, "failed to bind modules %s:%d -> %s:%d\n",
3416			src_widget->widget->name, sroute->src_queue_id,
3417			sink_widget->widget->name, sroute->dst_queue_id);
3418		goto out;
3419	}
3420
3421	return ret;
3422
3423out:
3424	sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_OUTPUT);
3425	sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_INPUT);
3426	return ret;
3427}
3428
3429static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
3430{
3431	struct snd_sof_widget *src_widget = sroute->src_widget;
3432	struct snd_sof_widget *sink_widget = sroute->sink_widget;
3433	struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
3434	struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
3435	struct sof_ipc4_msg msg = {{ 0 }};
3436	struct snd_sof_widget *src_pipe_widget = src_widget->spipe->pipe_widget;
3437	struct snd_sof_widget *sink_pipe_widget = sink_widget->spipe->pipe_widget;
3438	struct sof_ipc4_pipeline *src_pipeline = src_pipe_widget->private;
3439	struct sof_ipc4_pipeline *sink_pipeline = sink_pipe_widget->private;
3440	u32 header, extension;
3441	int ret = 0;
3442
3443	/* no route is set up if chain DMA is used */
3444	if (src_pipeline->use_chain_dma || sink_pipeline->use_chain_dma)
3445		return 0;
3446
3447	dev_dbg(sdev->dev, "unbind modules %s:%d -> %s:%d\n",
3448		src_widget->widget->name, sroute->src_queue_id,
3449		sink_widget->widget->name, sroute->dst_queue_id);
3450
3451	/*
3452	 * routes belonging to the same pipeline will be disconnected by the FW when the pipeline
3453	 * is freed. So avoid sending this IPC which will be ignored by the FW anyway.
3454	 */
3455	if (src_widget->spipe->pipe_widget == sink_widget->spipe->pipe_widget)
3456		goto out;
3457
3458	header = src_fw_module->man4_module_entry.id;
3459	header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
3460	header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_UNBIND);
3461	header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
3462	header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
3463
3464	extension = sink_fw_module->man4_module_entry.id;
3465	extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id);
3466	extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id);
3467	extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id);
3468
3469	msg.primary = header;
3470	msg.extension = extension;
3471
3472	ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0);
3473	if (ret < 0)
3474		dev_err(sdev->dev, "failed to unbind modules %s:%d -> %s:%d\n",
3475			src_widget->widget->name, sroute->src_queue_id,
3476			sink_widget->widget->name, sroute->dst_queue_id);
3477out:
3478	sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_INPUT);
3479	sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_OUTPUT);
3480
3481	return ret;
3482}
3483
3484static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
3485			       unsigned int flags, struct snd_sof_dai_config_data *data)
3486{
3487	struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
3488	struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
3489	struct snd_sof_dai *dai = swidget->private;
3490	struct sof_ipc4_gtw_attributes *gtw_attr;
3491	struct sof_ipc4_copier_data *copier_data;
3492	struct sof_ipc4_copier *ipc4_copier;
3493
3494	if (!dai || !dai->private) {
3495		dev_err(sdev->dev, "Invalid DAI or DAI private data for %s\n",
3496			swidget->widget->name);
3497		return -EINVAL;
3498	}
3499
3500	ipc4_copier = (struct sof_ipc4_copier *)dai->private;
3501	copier_data = &ipc4_copier->data;
3502
3503	if (!data)
3504		return 0;
3505
3506	if (pipeline->use_chain_dma) {
3507		/*
3508		 * Only configure the DMA Link ID for ChainDMA when this op is
3509		 * invoked with SOF_DAI_CONFIG_FLAGS_HW_PARAMS
3510		 */
3511		if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) {
3512			pipeline->msg.primary &= ~SOF_IPC4_GLB_CHAIN_DMA_LINK_ID_MASK;
3513			pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_LINK_ID(data->dai_data);
3514		}
3515		return 0;
3516	}
3517
3518	switch (ipc4_copier->dai_type) {
3519	case SOF_DAI_INTEL_HDA:
3520		gtw_attr = ipc4_copier->gtw_attr;
3521		gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
3522		if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) {
3523			copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
3524			copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_data);
3525		}
3526		break;
3527	case SOF_DAI_INTEL_ALH:
3528		/*
3529		 * Do not clear the node ID when this op is invoked with
3530		 * SOF_DAI_CONFIG_FLAGS_HW_FREE. It is needed to free the group_ida during
3531		 * unprepare. The node_id for multi-gateway DAI's will be overwritten with the
3532		 * group_id during copier's ipc_prepare op.
3533		 */
3534		if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) {
3535			struct sof_ipc4_alh_configuration_blob *blob;
3536
3537			blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
3538			ipc4_copier->dai_index = data->dai_node_id;
3539
3540			/*
3541			 * no need to set the node_id for aggregated DAI's. These will be assigned
3542			 * a group_id during widget ipc_prepare
3543			 */
3544			if (blob->alh_cfg.device_count == 1) {
3545				copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
3546				copier_data->gtw_cfg.node_id |=
3547					SOF_IPC4_NODE_INDEX(data->dai_node_id);
3548			}
3549		}
3550
3551		break;
3552	case SOF_DAI_INTEL_DMIC:
3553	case SOF_DAI_INTEL_SSP:
3554		/* nothing to do for SSP/DMIC */
3555		break;
3556	default:
3557		dev_err(sdev->dev, "%s: unsupported dai type %d\n", __func__,
3558			ipc4_copier->dai_type);
3559		return -EINVAL;
3560	}
3561
3562	return 0;
3563}
3564
3565static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index,
3566				   struct snd_soc_tplg_manifest *man)
3567{
3568	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
3569	struct sof_ipc4_fw_data *ipc4_data = sdev->private;
3570	struct sof_manifest_tlv *manifest_tlv;
3571	struct sof_manifest *manifest;
3572	u32 size = le32_to_cpu(man->priv.size);
3573	u8 *man_ptr = man->priv.data;
3574	u32 len_check;
3575	int i;
3576
3577	if (!size || size < SOF_IPC4_TPLG_ABI_SIZE) {
3578		dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n",
3579			__func__, size);
3580		return -EINVAL;
3581	}
3582
3583	manifest = (struct sof_manifest *)man_ptr;
3584
3585	dev_info(scomp->dev,
3586		 "Topology: ABI %d:%d:%d Kernel ABI %u:%u:%u\n",
3587		  le16_to_cpu(manifest->abi_major), le16_to_cpu(manifest->abi_minor),
3588		  le16_to_cpu(manifest->abi_patch),
3589		  SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
3590
3591	/* TODO: Add ABI compatibility check */
3592
3593	/* no more data after the ABI version */
3594	if (size <= SOF_IPC4_TPLG_ABI_SIZE)
3595		return 0;
3596
3597	manifest_tlv = manifest->items;
3598	len_check = sizeof(struct sof_manifest);
3599	for (i = 0; i < le16_to_cpu(manifest->count); i++) {
3600		len_check += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size);
3601		if (len_check > size)
3602			return -EINVAL;
3603
3604		switch (le32_to_cpu(manifest_tlv->type)) {
3605		case SOF_MANIFEST_DATA_TYPE_NHLT:
3606			/* no NHLT in BIOS, so use the one from topology manifest */
3607			if (ipc4_data->nhlt)
3608				break;
3609			ipc4_data->nhlt = devm_kmemdup(sdev->dev, manifest_tlv->data,
3610						       le32_to_cpu(manifest_tlv->size), GFP_KERNEL);
3611			if (!ipc4_data->nhlt)
3612				return -ENOMEM;
3613			break;
3614		default:
3615			dev_warn(scomp->dev, "Skipping unknown manifest data type %d\n",
3616				 manifest_tlv->type);
3617			break;
3618		}
3619		man_ptr += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size);
3620		manifest_tlv = (struct sof_manifest_tlv *)man_ptr;
3621	}
3622
3623	return 0;
3624}
3625
3626static int sof_ipc4_dai_get_param(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int param_type)
3627{
3628	struct sof_ipc4_copier *ipc4_copier = dai->private;
3629	struct snd_soc_tplg_hw_config *hw_config;
3630	struct snd_sof_dai_link *slink;
3631	bool dai_link_found = false;
3632	bool hw_cfg_found = false;
3633	int i;
3634
3635	if (!ipc4_copier)
3636		return 0;
3637
3638	list_for_each_entry(slink, &sdev->dai_link_list, list) {
3639		if (!strcmp(slink->link->name, dai->name)) {
3640			dai_link_found = true;
3641			break;
3642		}
3643	}
3644
3645	if (!dai_link_found) {
3646		dev_err(sdev->dev, "no DAI link found for DAI %s\n", dai->name);
3647		return -EINVAL;
3648	}
3649
3650	for (i = 0; i < slink->num_hw_configs; i++) {
3651		hw_config = &slink->hw_configs[i];
3652		if (dai->current_config == le32_to_cpu(hw_config->id)) {
3653			hw_cfg_found = true;
3654			break;
3655		}
3656	}
3657
3658	if (!hw_cfg_found) {
3659		dev_err(sdev->dev, "no matching hw_config found for DAI %s\n", dai->name);
3660		return -EINVAL;
3661	}
3662
3663	switch (ipc4_copier->dai_type) {
3664	case SOF_DAI_INTEL_SSP:
3665		switch (param_type) {
3666		case SOF_DAI_PARAM_INTEL_SSP_MCLK:
3667			return le32_to_cpu(hw_config->mclk_rate);
3668		case SOF_DAI_PARAM_INTEL_SSP_BCLK:
3669			return le32_to_cpu(hw_config->bclk_rate);
3670		case SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS:
3671			return le32_to_cpu(hw_config->tdm_slots);
3672		default:
3673			dev_err(sdev->dev, "invalid SSP param %d\n", param_type);
3674			break;
3675		}
3676		break;
3677	default:
3678		dev_err(sdev->dev, "DAI type %d not supported yet!\n", ipc4_copier->dai_type);
3679		break;
3680	}
3681
3682	return -EINVAL;
3683}
3684
3685static int sof_ipc4_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify)
3686{
3687	/*
3688	 * This function is called during system suspend, we need to make sure
3689	 * that all streams have been freed up.
3690	 * Freeing might have been skipped when xrun happened just at the start
3691	 * of the suspend and it sent a SNDRV_PCM_TRIGGER_STOP to the active
3692	 * stream. This will call sof_pcm_stream_free() with
3693	 * free_widget_list = false which will leave the kernel and firmware out
3694	 * of sync during suspend/resume.
3695	 *
3696	 * This will also make sure that paused streams handled correctly.
3697	 */
3698
3699	return sof_pcm_free_all_streams(sdev);
3700}
3701
3702static int sof_ipc4_link_setup(struct snd_sof_dev *sdev, struct snd_soc_dai_link *link)
3703{
3704	if (link->no_pcm)
3705		return 0;
3706
3707	/*
3708	 * set default trigger order for all links. Exceptions to
3709	 * the rule will be handled in sof_pcm_dai_link_fixup()
3710	 * For playback, the sequence is the following: start BE,
3711	 * start FE, stop FE, stop BE; for Capture the sequence is
3712	 * inverted start FE, start BE, stop BE, stop FE
3713	 */
3714	link->trigger[SNDRV_PCM_STREAM_PLAYBACK] = SND_SOC_DPCM_TRIGGER_POST;
3715	link->trigger[SNDRV_PCM_STREAM_CAPTURE] = SND_SOC_DPCM_TRIGGER_PRE;
3716
3717	return 0;
3718}
3719
3720/* Tokens needed for different copier variants (aif, dai and buffer) */
3721static enum sof_tokens copier_token_list[] = {
3722	SOF_COMP_TOKENS,
3723	SOF_COPIER_TOKENS,
3724	SOF_AUDIO_FMT_NUM_TOKENS,
3725	SOF_IN_AUDIO_FORMAT_TOKENS,
3726	SOF_OUT_AUDIO_FORMAT_TOKENS,
3727	SOF_COMP_EXT_TOKENS,
3728
3729	SOF_COPIER_DEEP_BUFFER_TOKENS,	/* for AIF copier */
3730	SOF_DAI_TOKENS,			/* for DAI copier */
3731};
3732
3733static enum sof_tokens pipeline_token_list[] = {
3734	SOF_SCHED_TOKENS,
3735	SOF_PIPELINE_TOKENS,
3736};
3737
3738static enum sof_tokens pga_token_list[] = {
3739	SOF_COMP_TOKENS,
3740	SOF_GAIN_TOKENS,
3741	SOF_AUDIO_FMT_NUM_TOKENS,
3742	SOF_IN_AUDIO_FORMAT_TOKENS,
3743	SOF_OUT_AUDIO_FORMAT_TOKENS,
3744	SOF_COMP_EXT_TOKENS,
3745};
3746
3747static enum sof_tokens mixer_token_list[] = {
3748	SOF_COMP_TOKENS,
3749	SOF_AUDIO_FMT_NUM_TOKENS,
3750	SOF_IN_AUDIO_FORMAT_TOKENS,
3751	SOF_OUT_AUDIO_FORMAT_TOKENS,
3752	SOF_COMP_EXT_TOKENS,
3753};
3754
3755static enum sof_tokens src_token_list[] = {
3756	SOF_COMP_TOKENS,
3757	SOF_SRC_TOKENS,
3758	SOF_AUDIO_FMT_NUM_TOKENS,
3759	SOF_IN_AUDIO_FORMAT_TOKENS,
3760	SOF_OUT_AUDIO_FORMAT_TOKENS,
3761	SOF_COMP_EXT_TOKENS,
3762};
3763
3764static enum sof_tokens asrc_token_list[] = {
3765	SOF_COMP_TOKENS,
3766	SOF_ASRC_TOKENS,
3767	SOF_AUDIO_FMT_NUM_TOKENS,
3768	SOF_IN_AUDIO_FORMAT_TOKENS,
3769	SOF_OUT_AUDIO_FORMAT_TOKENS,
3770	SOF_COMP_EXT_TOKENS,
3771};
3772
3773static enum sof_tokens process_token_list[] = {
3774	SOF_COMP_TOKENS,
3775	SOF_AUDIO_FMT_NUM_TOKENS,
3776	SOF_IN_AUDIO_FORMAT_TOKENS,
3777	SOF_OUT_AUDIO_FORMAT_TOKENS,
3778	SOF_COMP_EXT_TOKENS,
3779};
3780
3781static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = {
3782	[snd_soc_dapm_aif_in] =  {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
3783				  copier_token_list, ARRAY_SIZE(copier_token_list),
3784				  NULL, sof_ipc4_prepare_copier_module,
3785				  sof_ipc4_unprepare_copier_module},
3786	[snd_soc_dapm_aif_out] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
3787				  copier_token_list, ARRAY_SIZE(copier_token_list),
3788				  NULL, sof_ipc4_prepare_copier_module,
3789				  sof_ipc4_unprepare_copier_module},
3790	[snd_soc_dapm_dai_in] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
3791				 copier_token_list, ARRAY_SIZE(copier_token_list), NULL,
3792				 sof_ipc4_prepare_copier_module,
3793				 sof_ipc4_unprepare_copier_module},
3794	[snd_soc_dapm_dai_out] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
3795				  copier_token_list, ARRAY_SIZE(copier_token_list), NULL,
3796				  sof_ipc4_prepare_copier_module,
3797				  sof_ipc4_unprepare_copier_module},
3798	[snd_soc_dapm_buffer] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
3799				 copier_token_list, ARRAY_SIZE(copier_token_list),
3800				 NULL, sof_ipc4_prepare_copier_module,
3801				 sof_ipc4_unprepare_copier_module},
3802	[snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline,
3803				    sof_ipc4_widget_free_comp_pipeline,
3804				    pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL,
3805				    NULL, NULL},
3806	[snd_soc_dapm_pga] = {sof_ipc4_widget_setup_comp_pga, sof_ipc4_widget_free_comp_pga,
3807			      pga_token_list, ARRAY_SIZE(pga_token_list), NULL,
3808			      sof_ipc4_prepare_gain_module,
3809			      NULL},
3810	[snd_soc_dapm_mixer] = {sof_ipc4_widget_setup_comp_mixer, sof_ipc4_widget_free_comp_mixer,
3811				mixer_token_list, ARRAY_SIZE(mixer_token_list),
3812				NULL, sof_ipc4_prepare_mixer_module,
3813				NULL},
3814	[snd_soc_dapm_src] = {sof_ipc4_widget_setup_comp_src, sof_ipc4_widget_free_comp_src,
3815				src_token_list, ARRAY_SIZE(src_token_list),
3816				NULL, sof_ipc4_prepare_src_module,
3817				NULL},
3818	[snd_soc_dapm_asrc] = {sof_ipc4_widget_setup_comp_asrc, sof_ipc4_widget_free_comp_asrc,
3819				asrc_token_list, ARRAY_SIZE(asrc_token_list),
3820				NULL, sof_ipc4_prepare_src_module, /* Common prepare with SRC */
3821				NULL},
3822	[snd_soc_dapm_effect] = {sof_ipc4_widget_setup_comp_process,
3823				sof_ipc4_widget_free_comp_process,
3824				process_token_list, ARRAY_SIZE(process_token_list),
3825				NULL, sof_ipc4_prepare_process_module,
3826				NULL},
3827};
3828
3829const struct sof_ipc_tplg_ops ipc4_tplg_ops = {
3830	.widget = tplg_ipc4_widget_ops,
3831	.token_list = ipc4_token_list,
3832	.control_setup = sof_ipc4_control_setup,
3833	.control = &tplg_ipc4_control_ops,
3834	.widget_setup = sof_ipc4_widget_setup,
3835	.widget_free = sof_ipc4_widget_free,
3836	.route_setup = sof_ipc4_route_setup,
3837	.route_free = sof_ipc4_route_free,
3838	.dai_config = sof_ipc4_dai_config,
3839	.parse_manifest = sof_ipc4_parse_manifest,
3840	.dai_get_param = sof_ipc4_dai_get_param,
3841	.tear_down_all_pipelines = sof_ipc4_tear_down_all_pipelines,
3842	.link_setup = sof_ipc4_link_setup,
3843};
~/ Read-only file preview.