162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// This file is provided under a dual BSD/GPLv2 license.  When using or
462306a36Sopenharmony_ci// redistributing this file, you may do so under either license.
562306a36Sopenharmony_ci//
662306a36Sopenharmony_ci// Copyright(c) 2021 Intel Corporation. All rights reserved.
762306a36Sopenharmony_ci//
862306a36Sopenharmony_ci//
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <uapi/sound/sof/tokens.h>
1162306a36Sopenharmony_ci#include <sound/pcm_params.h>
1262306a36Sopenharmony_ci#include "sof-priv.h"
1362306a36Sopenharmony_ci#include "sof-audio.h"
1462306a36Sopenharmony_ci#include "ipc3-priv.h"
1562306a36Sopenharmony_ci#include "ops.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/* Full volume for default values */
1862306a36Sopenharmony_ci#define VOL_ZERO_DB	BIT(VOLUME_FWL)
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* size of tplg ABI in bytes */
2162306a36Sopenharmony_ci#define SOF_IPC3_TPLG_ABI_SIZE 3
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistruct sof_widget_data {
2462306a36Sopenharmony_ci	int ctrl_type;
2562306a36Sopenharmony_ci	int ipc_cmd;
2662306a36Sopenharmony_ci	void *pdata;
2762306a36Sopenharmony_ci	size_t pdata_size;
2862306a36Sopenharmony_ci	struct snd_sof_control *control;
2962306a36Sopenharmony_ci};
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistruct sof_process_types {
3262306a36Sopenharmony_ci	const char *name;
3362306a36Sopenharmony_ci	enum sof_ipc_process_type type;
3462306a36Sopenharmony_ci	enum sof_comp_type comp_type;
3562306a36Sopenharmony_ci};
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic const struct sof_process_types sof_process[] = {
3862306a36Sopenharmony_ci	{"EQFIR", SOF_PROCESS_EQFIR, SOF_COMP_EQ_FIR},
3962306a36Sopenharmony_ci	{"EQIIR", SOF_PROCESS_EQIIR, SOF_COMP_EQ_IIR},
4062306a36Sopenharmony_ci	{"KEYWORD_DETECT", SOF_PROCESS_KEYWORD_DETECT, SOF_COMP_KEYWORD_DETECT},
4162306a36Sopenharmony_ci	{"KPB", SOF_PROCESS_KPB, SOF_COMP_KPB},
4262306a36Sopenharmony_ci	{"CHAN_SELECTOR", SOF_PROCESS_CHAN_SELECTOR, SOF_COMP_SELECTOR},
4362306a36Sopenharmony_ci	{"MUX", SOF_PROCESS_MUX, SOF_COMP_MUX},
4462306a36Sopenharmony_ci	{"DEMUX", SOF_PROCESS_DEMUX, SOF_COMP_DEMUX},
4562306a36Sopenharmony_ci	{"DCBLOCK", SOF_PROCESS_DCBLOCK, SOF_COMP_DCBLOCK},
4662306a36Sopenharmony_ci	{"SMART_AMP", SOF_PROCESS_SMART_AMP, SOF_COMP_SMART_AMP},
4762306a36Sopenharmony_ci};
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic enum sof_ipc_process_type find_process(const char *name)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	int i;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(sof_process); i++) {
5462306a36Sopenharmony_ci		if (strcmp(name, sof_process[i].name) == 0)
5562306a36Sopenharmony_ci			return sof_process[i].type;
5662306a36Sopenharmony_ci	}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	return SOF_PROCESS_NONE;
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic int get_token_process_type(void *elem, void *object, u32 offset)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	u32 *val = (u32 *)((u8 *)object + offset);
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	*val = find_process((const char *)elem);
6662306a36Sopenharmony_ci	return 0;
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci/* Buffers */
7062306a36Sopenharmony_cistatic const struct sof_topology_token buffer_tokens[] = {
7162306a36Sopenharmony_ci	{SOF_TKN_BUF_SIZE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
7262306a36Sopenharmony_ci		offsetof(struct sof_ipc_buffer, size)},
7362306a36Sopenharmony_ci	{SOF_TKN_BUF_CAPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
7462306a36Sopenharmony_ci		offsetof(struct sof_ipc_buffer, caps)},
7562306a36Sopenharmony_ci};
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/* DAI */
7862306a36Sopenharmony_cistatic const struct sof_topology_token dai_tokens[] = {
7962306a36Sopenharmony_ci	{SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type,
8062306a36Sopenharmony_ci		offsetof(struct sof_ipc_comp_dai, type)},
8162306a36Sopenharmony_ci	{SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
8262306a36Sopenharmony_ci		offsetof(struct sof_ipc_comp_dai, dai_index)},
8362306a36Sopenharmony_ci	{SOF_TKN_DAI_DIRECTION, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
8462306a36Sopenharmony_ci		offsetof(struct sof_ipc_comp_dai, direction)},
8562306a36Sopenharmony_ci};
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci/* BE DAI link */
8862306a36Sopenharmony_cistatic const struct sof_topology_token dai_link_tokens[] = {
8962306a36Sopenharmony_ci	{SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type,
9062306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_config, type)},
9162306a36Sopenharmony_ci	{SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
9262306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_config, dai_index)},
9362306a36Sopenharmony_ci};
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci/* scheduling */
9662306a36Sopenharmony_cistatic const struct sof_topology_token sched_tokens[] = {
9762306a36Sopenharmony_ci	{SOF_TKN_SCHED_PERIOD, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
9862306a36Sopenharmony_ci		offsetof(struct sof_ipc_pipe_new, period)},
9962306a36Sopenharmony_ci	{SOF_TKN_SCHED_PRIORITY, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
10062306a36Sopenharmony_ci		offsetof(struct sof_ipc_pipe_new, priority)},
10162306a36Sopenharmony_ci	{SOF_TKN_SCHED_MIPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
10262306a36Sopenharmony_ci		offsetof(struct sof_ipc_pipe_new, period_mips)},
10362306a36Sopenharmony_ci	{SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
10462306a36Sopenharmony_ci		offsetof(struct sof_ipc_pipe_new, core)},
10562306a36Sopenharmony_ci	{SOF_TKN_SCHED_FRAMES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
10662306a36Sopenharmony_ci		offsetof(struct sof_ipc_pipe_new, frames_per_sched)},
10762306a36Sopenharmony_ci	{SOF_TKN_SCHED_TIME_DOMAIN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
10862306a36Sopenharmony_ci		offsetof(struct sof_ipc_pipe_new, time_domain)},
10962306a36Sopenharmony_ci};
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic const struct sof_topology_token pipeline_tokens[] = {
11262306a36Sopenharmony_ci	{SOF_TKN_SCHED_DYNAMIC_PIPELINE, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
11362306a36Sopenharmony_ci		offsetof(struct snd_sof_widget, dynamic_pipeline_widget)},
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci};
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci/* volume */
11862306a36Sopenharmony_cistatic const struct sof_topology_token volume_tokens[] = {
11962306a36Sopenharmony_ci	{SOF_TKN_VOLUME_RAMP_STEP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
12062306a36Sopenharmony_ci		offsetof(struct sof_ipc_comp_volume, ramp)},
12162306a36Sopenharmony_ci	{SOF_TKN_VOLUME_RAMP_STEP_MS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
12262306a36Sopenharmony_ci		offsetof(struct sof_ipc_comp_volume, initial_ramp)},
12362306a36Sopenharmony_ci};
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci/* SRC */
12662306a36Sopenharmony_cistatic const struct sof_topology_token src_tokens[] = {
12762306a36Sopenharmony_ci	{SOF_TKN_SRC_RATE_IN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
12862306a36Sopenharmony_ci		offsetof(struct sof_ipc_comp_src, source_rate)},
12962306a36Sopenharmony_ci	{SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
13062306a36Sopenharmony_ci		offsetof(struct sof_ipc_comp_src, sink_rate)},
13162306a36Sopenharmony_ci};
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci/* ASRC */
13462306a36Sopenharmony_cistatic const struct sof_topology_token asrc_tokens[] = {
13562306a36Sopenharmony_ci	{SOF_TKN_ASRC_RATE_IN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
13662306a36Sopenharmony_ci		offsetof(struct sof_ipc_comp_asrc, source_rate)},
13762306a36Sopenharmony_ci	{SOF_TKN_ASRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
13862306a36Sopenharmony_ci		offsetof(struct sof_ipc_comp_asrc, sink_rate)},
13962306a36Sopenharmony_ci	{SOF_TKN_ASRC_ASYNCHRONOUS_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
14062306a36Sopenharmony_ci		offsetof(struct sof_ipc_comp_asrc, asynchronous_mode)},
14162306a36Sopenharmony_ci	{SOF_TKN_ASRC_OPERATION_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
14262306a36Sopenharmony_ci		offsetof(struct sof_ipc_comp_asrc, operation_mode)},
14362306a36Sopenharmony_ci};
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci/* EFFECT */
14662306a36Sopenharmony_cistatic const struct sof_topology_token process_tokens[] = {
14762306a36Sopenharmony_ci	{SOF_TKN_PROCESS_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_process_type,
14862306a36Sopenharmony_ci		offsetof(struct sof_ipc_comp_process, type)},
14962306a36Sopenharmony_ci};
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci/* PCM */
15262306a36Sopenharmony_cistatic const struct sof_topology_token pcm_tokens[] = {
15362306a36Sopenharmony_ci	{SOF_TKN_PCM_DMAC_CONFIG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
15462306a36Sopenharmony_ci		offsetof(struct sof_ipc_comp_host, dmac_config)},
15562306a36Sopenharmony_ci};
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci/* Generic components */
15862306a36Sopenharmony_cistatic const struct sof_topology_token comp_tokens[] = {
15962306a36Sopenharmony_ci	{SOF_TKN_COMP_PERIOD_SINK_COUNT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
16062306a36Sopenharmony_ci		offsetof(struct sof_ipc_comp_config, periods_sink)},
16162306a36Sopenharmony_ci	{SOF_TKN_COMP_PERIOD_SOURCE_COUNT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
16262306a36Sopenharmony_ci		offsetof(struct sof_ipc_comp_config, periods_source)},
16362306a36Sopenharmony_ci	{SOF_TKN_COMP_FORMAT,
16462306a36Sopenharmony_ci		SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_format,
16562306a36Sopenharmony_ci		offsetof(struct sof_ipc_comp_config, frame_fmt)},
16662306a36Sopenharmony_ci};
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci/* SSP */
16962306a36Sopenharmony_cistatic const struct sof_topology_token ssp_tokens[] = {
17062306a36Sopenharmony_ci	{SOF_TKN_INTEL_SSP_CLKS_CONTROL, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
17162306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_ssp_params, clks_control)},
17262306a36Sopenharmony_ci	{SOF_TKN_INTEL_SSP_MCLK_ID, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
17362306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_ssp_params, mclk_id)},
17462306a36Sopenharmony_ci	{SOF_TKN_INTEL_SSP_SAMPLE_BITS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
17562306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_ssp_params, sample_valid_bits)},
17662306a36Sopenharmony_ci	{SOF_TKN_INTEL_SSP_FRAME_PULSE_WIDTH, SND_SOC_TPLG_TUPLE_TYPE_SHORT,	get_token_u16,
17762306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_ssp_params, frame_pulse_width)},
17862306a36Sopenharmony_ci	{SOF_TKN_INTEL_SSP_QUIRKS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
17962306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_ssp_params, quirks)},
18062306a36Sopenharmony_ci	{SOF_TKN_INTEL_SSP_TDM_PADDING_PER_SLOT, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
18162306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_ssp_params, tdm_per_slot_padding_flag)},
18262306a36Sopenharmony_ci	{SOF_TKN_INTEL_SSP_BCLK_DELAY, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
18362306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_ssp_params, bclk_delay)},
18462306a36Sopenharmony_ci};
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci/* ALH */
18762306a36Sopenharmony_cistatic const struct sof_topology_token alh_tokens[] = {
18862306a36Sopenharmony_ci	{SOF_TKN_INTEL_ALH_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
18962306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_alh_params, rate)},
19062306a36Sopenharmony_ci	{SOF_TKN_INTEL_ALH_CH,	SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
19162306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_alh_params, channels)},
19262306a36Sopenharmony_ci};
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci/* DMIC */
19562306a36Sopenharmony_cistatic const struct sof_topology_token dmic_tokens[] = {
19662306a36Sopenharmony_ci	{SOF_TKN_INTEL_DMIC_DRIVER_VERSION, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
19762306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_dmic_params, driver_ipc_version)},
19862306a36Sopenharmony_ci	{SOF_TKN_INTEL_DMIC_CLK_MIN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
19962306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_dmic_params, pdmclk_min)},
20062306a36Sopenharmony_ci	{SOF_TKN_INTEL_DMIC_CLK_MAX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
20162306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_dmic_params, pdmclk_max)},
20262306a36Sopenharmony_ci	{SOF_TKN_INTEL_DMIC_SAMPLE_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
20362306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_dmic_params, fifo_fs)},
20462306a36Sopenharmony_ci	{SOF_TKN_INTEL_DMIC_DUTY_MIN, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
20562306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_dmic_params, duty_min)},
20662306a36Sopenharmony_ci	{SOF_TKN_INTEL_DMIC_DUTY_MAX, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
20762306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_dmic_params, duty_max)},
20862306a36Sopenharmony_ci	{SOF_TKN_INTEL_DMIC_NUM_PDM_ACTIVE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
20962306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_dmic_params, num_pdm_active)},
21062306a36Sopenharmony_ci	{SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
21162306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_dmic_params, fifo_bits)},
21262306a36Sopenharmony_ci	{SOF_TKN_INTEL_DMIC_UNMUTE_RAMP_TIME_MS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
21362306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_dmic_params, unmute_ramp_time)},
21462306a36Sopenharmony_ci};
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci/* ESAI */
21762306a36Sopenharmony_cistatic const struct sof_topology_token esai_tokens[] = {
21862306a36Sopenharmony_ci	{SOF_TKN_IMX_ESAI_MCLK_ID, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
21962306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_esai_params, mclk_id)},
22062306a36Sopenharmony_ci};
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci/* SAI */
22362306a36Sopenharmony_cistatic const struct sof_topology_token sai_tokens[] = {
22462306a36Sopenharmony_ci	{SOF_TKN_IMX_SAI_MCLK_ID, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
22562306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_sai_params, mclk_id)},
22662306a36Sopenharmony_ci};
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci/*
22962306a36Sopenharmony_ci * DMIC PDM Tokens
23062306a36Sopenharmony_ci * SOF_TKN_INTEL_DMIC_PDM_CTRL_ID should be the first token
23162306a36Sopenharmony_ci * as it increments the index while parsing the array of pdm tokens
23262306a36Sopenharmony_ci * and determines the correct offset
23362306a36Sopenharmony_ci */
23462306a36Sopenharmony_cistatic const struct sof_topology_token dmic_pdm_tokens[] = {
23562306a36Sopenharmony_ci	{SOF_TKN_INTEL_DMIC_PDM_CTRL_ID, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
23662306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, id)},
23762306a36Sopenharmony_ci	{SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
23862306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, enable_mic_a)},
23962306a36Sopenharmony_ci	{SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
24062306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, enable_mic_b)},
24162306a36Sopenharmony_ci	{SOF_TKN_INTEL_DMIC_PDM_POLARITY_A, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
24262306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, polarity_mic_a)},
24362306a36Sopenharmony_ci	{SOF_TKN_INTEL_DMIC_PDM_POLARITY_B, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
24462306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, polarity_mic_b)},
24562306a36Sopenharmony_ci	{SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
24662306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, clk_edge)},
24762306a36Sopenharmony_ci	{SOF_TKN_INTEL_DMIC_PDM_SKEW, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
24862306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, skew)},
24962306a36Sopenharmony_ci};
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci/* HDA */
25262306a36Sopenharmony_cistatic const struct sof_topology_token hda_tokens[] = {
25362306a36Sopenharmony_ci	{SOF_TKN_INTEL_HDA_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
25462306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_hda_params, rate)},
25562306a36Sopenharmony_ci	{SOF_TKN_INTEL_HDA_CH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
25662306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_hda_params, channels)},
25762306a36Sopenharmony_ci};
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci/* AFE */
26062306a36Sopenharmony_cistatic const struct sof_topology_token afe_tokens[] = {
26162306a36Sopenharmony_ci	{SOF_TKN_MEDIATEK_AFE_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
26262306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_mtk_afe_params, rate)},
26362306a36Sopenharmony_ci	{SOF_TKN_MEDIATEK_AFE_CH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
26462306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_mtk_afe_params, channels)},
26562306a36Sopenharmony_ci	{SOF_TKN_MEDIATEK_AFE_FORMAT, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_format,
26662306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_mtk_afe_params, format)},
26762306a36Sopenharmony_ci};
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci/* ACPDMIC */
27062306a36Sopenharmony_cistatic const struct sof_topology_token acpdmic_tokens[] = {
27162306a36Sopenharmony_ci	{SOF_TKN_AMD_ACPDMIC_RATE,
27262306a36Sopenharmony_ci		SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
27362306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_acpdmic_params, pdm_rate)},
27462306a36Sopenharmony_ci	{SOF_TKN_AMD_ACPDMIC_CH,
27562306a36Sopenharmony_ci		SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
27662306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_acpdmic_params, pdm_ch)},
27762306a36Sopenharmony_ci};
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci/* ACPI2S */
28062306a36Sopenharmony_cistatic const struct sof_topology_token acpi2s_tokens[] = {
28162306a36Sopenharmony_ci	{SOF_TKN_AMD_ACPI2S_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
28262306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_acp_params, fsync_rate)},
28362306a36Sopenharmony_ci	{SOF_TKN_AMD_ACPI2S_CH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
28462306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_acp_params, tdm_slots)},
28562306a36Sopenharmony_ci	{SOF_TKN_AMD_ACPI2S_TDM_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
28662306a36Sopenharmony_ci		offsetof(struct sof_ipc_dai_acp_params, tdm_mode)},
28762306a36Sopenharmony_ci};
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci/* Core tokens */
29062306a36Sopenharmony_cistatic const struct sof_topology_token core_tokens[] = {
29162306a36Sopenharmony_ci	{SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
29262306a36Sopenharmony_ci		offsetof(struct sof_ipc_comp, core)},
29362306a36Sopenharmony_ci};
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci/* Component extended tokens */
29662306a36Sopenharmony_cistatic const struct sof_topology_token comp_ext_tokens[] = {
29762306a36Sopenharmony_ci	{SOF_TKN_COMP_UUID, SND_SOC_TPLG_TUPLE_TYPE_UUID, get_token_uuid,
29862306a36Sopenharmony_ci		offsetof(struct snd_sof_widget, uuid)},
29962306a36Sopenharmony_ci};
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_cistatic const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = {
30262306a36Sopenharmony_ci	[SOF_PCM_TOKENS] = {"PCM tokens", pcm_tokens, ARRAY_SIZE(pcm_tokens)},
30362306a36Sopenharmony_ci	[SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)},
30462306a36Sopenharmony_ci	[SOF_SCHED_TOKENS] = {"Scheduler tokens", sched_tokens, ARRAY_SIZE(sched_tokens)},
30562306a36Sopenharmony_ci	[SOF_COMP_TOKENS] = {"Comp tokens", comp_tokens, ARRAY_SIZE(comp_tokens)},
30662306a36Sopenharmony_ci	[SOF_CORE_TOKENS] = {"Core tokens", core_tokens, ARRAY_SIZE(core_tokens)},
30762306a36Sopenharmony_ci	[SOF_COMP_EXT_TOKENS] = {"AFE tokens", comp_ext_tokens, ARRAY_SIZE(comp_ext_tokens)},
30862306a36Sopenharmony_ci	[SOF_BUFFER_TOKENS] = {"Buffer tokens", buffer_tokens, ARRAY_SIZE(buffer_tokens)},
30962306a36Sopenharmony_ci	[SOF_VOLUME_TOKENS] = {"Volume tokens", volume_tokens, ARRAY_SIZE(volume_tokens)},
31062306a36Sopenharmony_ci	[SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)},
31162306a36Sopenharmony_ci	[SOF_ASRC_TOKENS] = {"ASRC tokens", asrc_tokens, ARRAY_SIZE(asrc_tokens)},
31262306a36Sopenharmony_ci	[SOF_PROCESS_TOKENS] = {"Process tokens", process_tokens, ARRAY_SIZE(process_tokens)},
31362306a36Sopenharmony_ci	[SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)},
31462306a36Sopenharmony_ci	[SOF_DAI_LINK_TOKENS] = {"DAI link tokens", dai_link_tokens, ARRAY_SIZE(dai_link_tokens)},
31562306a36Sopenharmony_ci	[SOF_HDA_TOKENS] = {"HDA tokens", hda_tokens, ARRAY_SIZE(hda_tokens)},
31662306a36Sopenharmony_ci	[SOF_SSP_TOKENS] = {"SSP tokens", ssp_tokens, ARRAY_SIZE(ssp_tokens)},
31762306a36Sopenharmony_ci	[SOF_ALH_TOKENS] = {"ALH tokens", alh_tokens, ARRAY_SIZE(alh_tokens)},
31862306a36Sopenharmony_ci	[SOF_DMIC_TOKENS] = {"DMIC tokens", dmic_tokens, ARRAY_SIZE(dmic_tokens)},
31962306a36Sopenharmony_ci	[SOF_DMIC_PDM_TOKENS] = {"DMIC PDM tokens", dmic_pdm_tokens, ARRAY_SIZE(dmic_pdm_tokens)},
32062306a36Sopenharmony_ci	[SOF_ESAI_TOKENS] = {"ESAI tokens", esai_tokens, ARRAY_SIZE(esai_tokens)},
32162306a36Sopenharmony_ci	[SOF_SAI_TOKENS] = {"SAI tokens", sai_tokens, ARRAY_SIZE(sai_tokens)},
32262306a36Sopenharmony_ci	[SOF_AFE_TOKENS] = {"AFE tokens", afe_tokens, ARRAY_SIZE(afe_tokens)},
32362306a36Sopenharmony_ci	[SOF_ACPDMIC_TOKENS] = {"ACPDMIC tokens", acpdmic_tokens, ARRAY_SIZE(acpdmic_tokens)},
32462306a36Sopenharmony_ci	[SOF_ACPI2S_TOKENS]   = {"ACPI2S tokens", acpi2s_tokens, ARRAY_SIZE(acpi2s_tokens)},
32562306a36Sopenharmony_ci};
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci/**
32862306a36Sopenharmony_ci * sof_comp_alloc - allocate and initialize buffer for a new component
32962306a36Sopenharmony_ci * @swidget: pointer to struct snd_sof_widget containing extended data
33062306a36Sopenharmony_ci * @ipc_size: IPC payload size that will be updated depending on valid
33162306a36Sopenharmony_ci *  extended data.
33262306a36Sopenharmony_ci * @index: ID of the pipeline the component belongs to
33362306a36Sopenharmony_ci *
33462306a36Sopenharmony_ci * Return: The pointer to the new allocated component, NULL if failed.
33562306a36Sopenharmony_ci */
33662306a36Sopenharmony_cistatic void *sof_comp_alloc(struct snd_sof_widget *swidget, size_t *ipc_size,
33762306a36Sopenharmony_ci			    int index)
33862306a36Sopenharmony_ci{
33962306a36Sopenharmony_ci	struct sof_ipc_comp *comp;
34062306a36Sopenharmony_ci	size_t total_size = *ipc_size;
34162306a36Sopenharmony_ci	size_t ext_size = sizeof(swidget->uuid);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	/* only non-zero UUID is valid */
34462306a36Sopenharmony_ci	if (!guid_is_null(&swidget->uuid))
34562306a36Sopenharmony_ci		total_size += ext_size;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	comp = kzalloc(total_size, GFP_KERNEL);
34862306a36Sopenharmony_ci	if (!comp)
34962306a36Sopenharmony_ci		return NULL;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	/* configure comp new IPC message */
35262306a36Sopenharmony_ci	comp->hdr.size = total_size;
35362306a36Sopenharmony_ci	comp->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW;
35462306a36Sopenharmony_ci	comp->id = swidget->comp_id;
35562306a36Sopenharmony_ci	comp->pipeline_id = index;
35662306a36Sopenharmony_ci	comp->core = swidget->core;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	/* handle the extended data if needed */
35962306a36Sopenharmony_ci	if (total_size > *ipc_size) {
36062306a36Sopenharmony_ci		/* append extended data to the end of the component */
36162306a36Sopenharmony_ci		memcpy((u8 *)comp + *ipc_size, &swidget->uuid, ext_size);
36262306a36Sopenharmony_ci		comp->ext_data_length = ext_size;
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	/* update ipc_size and return */
36662306a36Sopenharmony_ci	*ipc_size = total_size;
36762306a36Sopenharmony_ci	return comp;
36862306a36Sopenharmony_ci}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_cistatic void sof_dbg_comp_config(struct snd_soc_component *scomp, struct sof_ipc_comp_config *config)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	dev_dbg(scomp->dev, " config: periods snk %d src %d fmt %d\n",
37362306a36Sopenharmony_ci		config->periods_sink, config->periods_source,
37462306a36Sopenharmony_ci		config->frame_fmt);
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_cistatic int sof_ipc3_widget_setup_comp_host(struct snd_sof_widget *swidget)
37862306a36Sopenharmony_ci{
37962306a36Sopenharmony_ci	struct snd_soc_component *scomp = swidget->scomp;
38062306a36Sopenharmony_ci	struct sof_ipc_comp_host *host;
38162306a36Sopenharmony_ci	size_t ipc_size = sizeof(*host);
38262306a36Sopenharmony_ci	int ret;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	host = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
38562306a36Sopenharmony_ci	if (!host)
38662306a36Sopenharmony_ci		return -ENOMEM;
38762306a36Sopenharmony_ci	swidget->private = host;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	/* configure host comp IPC message */
39062306a36Sopenharmony_ci	host->comp.type = SOF_COMP_HOST;
39162306a36Sopenharmony_ci	host->config.hdr.size = sizeof(host->config);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	if (swidget->id == snd_soc_dapm_aif_out)
39462306a36Sopenharmony_ci		host->direction = SOF_IPC_STREAM_CAPTURE;
39562306a36Sopenharmony_ci	else
39662306a36Sopenharmony_ci		host->direction = SOF_IPC_STREAM_PLAYBACK;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	/* parse one set of pcm_tokens */
39962306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, host, SOF_PCM_TOKENS, swidget->tuples,
40062306a36Sopenharmony_ci				    swidget->num_tuples, sizeof(*host), 1);
40162306a36Sopenharmony_ci	if (ret < 0)
40262306a36Sopenharmony_ci		goto err;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	/* parse one set of comp_tokens */
40562306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, &host->config, SOF_COMP_TOKENS, swidget->tuples,
40662306a36Sopenharmony_ci				    swidget->num_tuples, sizeof(host->config), 1);
40762306a36Sopenharmony_ci	if (ret < 0)
40862306a36Sopenharmony_ci		goto err;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	dev_dbg(scomp->dev, "loaded host %s\n", swidget->widget->name);
41162306a36Sopenharmony_ci	sof_dbg_comp_config(scomp, &host->config);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	return 0;
41462306a36Sopenharmony_cierr:
41562306a36Sopenharmony_ci	kfree(swidget->private);
41662306a36Sopenharmony_ci	swidget->private = NULL;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	return ret;
41962306a36Sopenharmony_ci}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_cistatic void sof_ipc3_widget_free_comp(struct snd_sof_widget *swidget)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	kfree(swidget->private);
42462306a36Sopenharmony_ci}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_cistatic int sof_ipc3_widget_setup_comp_tone(struct snd_sof_widget *swidget)
42762306a36Sopenharmony_ci{
42862306a36Sopenharmony_ci	struct snd_soc_component *scomp = swidget->scomp;
42962306a36Sopenharmony_ci	struct sof_ipc_comp_tone *tone;
43062306a36Sopenharmony_ci	size_t ipc_size = sizeof(*tone);
43162306a36Sopenharmony_ci	int ret;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	tone = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
43462306a36Sopenharmony_ci	if (!tone)
43562306a36Sopenharmony_ci		return -ENOMEM;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	swidget->private = tone;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	/* configure siggen IPC message */
44062306a36Sopenharmony_ci	tone->comp.type = SOF_COMP_TONE;
44162306a36Sopenharmony_ci	tone->config.hdr.size = sizeof(tone->config);
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	/* parse one set of comp tokens */
44462306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, &tone->config, SOF_COMP_TOKENS, swidget->tuples,
44562306a36Sopenharmony_ci				    swidget->num_tuples, sizeof(tone->config), 1);
44662306a36Sopenharmony_ci	if (ret < 0) {
44762306a36Sopenharmony_ci		kfree(swidget->private);
44862306a36Sopenharmony_ci		swidget->private = NULL;
44962306a36Sopenharmony_ci		return ret;
45062306a36Sopenharmony_ci	}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	dev_dbg(scomp->dev, "tone %s: frequency %d amplitude %d\n",
45362306a36Sopenharmony_ci		swidget->widget->name, tone->frequency, tone->amplitude);
45462306a36Sopenharmony_ci	sof_dbg_comp_config(scomp, &tone->config);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	return 0;
45762306a36Sopenharmony_ci}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_cistatic int sof_ipc3_widget_setup_comp_mixer(struct snd_sof_widget *swidget)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	struct snd_soc_component *scomp = swidget->scomp;
46262306a36Sopenharmony_ci	struct sof_ipc_comp_mixer *mixer;
46362306a36Sopenharmony_ci	size_t ipc_size = sizeof(*mixer);
46462306a36Sopenharmony_ci	int ret;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	mixer = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
46762306a36Sopenharmony_ci	if (!mixer)
46862306a36Sopenharmony_ci		return -ENOMEM;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	swidget->private = mixer;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	/* configure mixer IPC message */
47362306a36Sopenharmony_ci	mixer->comp.type = SOF_COMP_MIXER;
47462306a36Sopenharmony_ci	mixer->config.hdr.size = sizeof(mixer->config);
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	/* parse one set of comp tokens */
47762306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, &mixer->config, SOF_COMP_TOKENS,
47862306a36Sopenharmony_ci				    swidget->tuples, swidget->num_tuples,
47962306a36Sopenharmony_ci				    sizeof(mixer->config), 1);
48062306a36Sopenharmony_ci	if (ret < 0) {
48162306a36Sopenharmony_ci		kfree(swidget->private);
48262306a36Sopenharmony_ci		swidget->private = NULL;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci		return ret;
48562306a36Sopenharmony_ci	}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	dev_dbg(scomp->dev, "loaded mixer %s\n", swidget->widget->name);
48862306a36Sopenharmony_ci	sof_dbg_comp_config(scomp, &mixer->config);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	return 0;
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistatic int sof_ipc3_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	struct snd_soc_component *scomp = swidget->scomp;
49662306a36Sopenharmony_ci	struct snd_sof_pipeline *spipe = swidget->spipe;
49762306a36Sopenharmony_ci	struct sof_ipc_pipe_new *pipeline;
49862306a36Sopenharmony_ci	struct snd_sof_widget *comp_swidget;
49962306a36Sopenharmony_ci	int ret;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL);
50262306a36Sopenharmony_ci	if (!pipeline)
50362306a36Sopenharmony_ci		return -ENOMEM;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	/* configure pipeline IPC message */
50662306a36Sopenharmony_ci	pipeline->hdr.size = sizeof(*pipeline);
50762306a36Sopenharmony_ci	pipeline->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_PIPE_NEW;
50862306a36Sopenharmony_ci	pipeline->pipeline_id = swidget->pipeline_id;
50962306a36Sopenharmony_ci	pipeline->comp_id = swidget->comp_id;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	swidget->private = pipeline;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	/* component at start of pipeline is our stream id */
51462306a36Sopenharmony_ci	comp_swidget = snd_sof_find_swidget(scomp, swidget->widget->sname);
51562306a36Sopenharmony_ci	if (!comp_swidget) {
51662306a36Sopenharmony_ci		dev_err(scomp->dev, "scheduler %s refers to non existent widget %s\n",
51762306a36Sopenharmony_ci			swidget->widget->name, swidget->widget->sname);
51862306a36Sopenharmony_ci		ret = -EINVAL;
51962306a36Sopenharmony_ci		goto err;
52062306a36Sopenharmony_ci	}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	pipeline->sched_id = comp_swidget->comp_id;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	/* parse one set of scheduler tokens */
52562306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, pipeline, SOF_SCHED_TOKENS, swidget->tuples,
52662306a36Sopenharmony_ci				    swidget->num_tuples, sizeof(*pipeline), 1);
52762306a36Sopenharmony_ci	if (ret < 0)
52862306a36Sopenharmony_ci		goto err;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	/* parse one set of pipeline tokens */
53162306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples,
53262306a36Sopenharmony_ci				    swidget->num_tuples, sizeof(*swidget), 1);
53362306a36Sopenharmony_ci	if (ret < 0)
53462306a36Sopenharmony_ci		goto err;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	if (sof_debug_check_flag(SOF_DBG_DISABLE_MULTICORE))
53762306a36Sopenharmony_ci		pipeline->core = SOF_DSP_PRIMARY_CORE;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	if (sof_debug_check_flag(SOF_DBG_DYNAMIC_PIPELINES_OVERRIDE))
54062306a36Sopenharmony_ci		swidget->dynamic_pipeline_widget =
54162306a36Sopenharmony_ci			sof_debug_check_flag(SOF_DBG_DYNAMIC_PIPELINES_ENABLE);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	dev_dbg(scomp->dev, "pipeline %s: period %d pri %d mips %d core %d frames %d dynamic %d\n",
54462306a36Sopenharmony_ci		swidget->widget->name, pipeline->period, pipeline->priority,
54562306a36Sopenharmony_ci		pipeline->period_mips, pipeline->core, pipeline->frames_per_sched,
54662306a36Sopenharmony_ci		swidget->dynamic_pipeline_widget);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	swidget->core = pipeline->core;
54962306a36Sopenharmony_ci	spipe->core_mask |= BIT(pipeline->core);
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	return 0;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_cierr:
55462306a36Sopenharmony_ci	kfree(swidget->private);
55562306a36Sopenharmony_ci	swidget->private = NULL;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	return ret;
55862306a36Sopenharmony_ci}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_cistatic int sof_ipc3_widget_setup_comp_buffer(struct snd_sof_widget *swidget)
56162306a36Sopenharmony_ci{
56262306a36Sopenharmony_ci	struct snd_soc_component *scomp = swidget->scomp;
56362306a36Sopenharmony_ci	struct sof_ipc_buffer *buffer;
56462306a36Sopenharmony_ci	int ret;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
56762306a36Sopenharmony_ci	if (!buffer)
56862306a36Sopenharmony_ci		return -ENOMEM;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	swidget->private = buffer;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	/* configure dai IPC message */
57362306a36Sopenharmony_ci	buffer->comp.hdr.size = sizeof(*buffer);
57462306a36Sopenharmony_ci	buffer->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_BUFFER_NEW;
57562306a36Sopenharmony_ci	buffer->comp.id = swidget->comp_id;
57662306a36Sopenharmony_ci	buffer->comp.type = SOF_COMP_BUFFER;
57762306a36Sopenharmony_ci	buffer->comp.pipeline_id = swidget->pipeline_id;
57862306a36Sopenharmony_ci	buffer->comp.core = swidget->core;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	/* parse one set of buffer tokens */
58162306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, buffer, SOF_BUFFER_TOKENS, swidget->tuples,
58262306a36Sopenharmony_ci				    swidget->num_tuples, sizeof(*buffer), 1);
58362306a36Sopenharmony_ci	if (ret < 0) {
58462306a36Sopenharmony_ci		kfree(swidget->private);
58562306a36Sopenharmony_ci		swidget->private = NULL;
58662306a36Sopenharmony_ci		return ret;
58762306a36Sopenharmony_ci	}
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	dev_dbg(scomp->dev, "buffer %s: size %d caps 0x%x\n",
59062306a36Sopenharmony_ci		swidget->widget->name, buffer->size, buffer->caps);
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	return 0;
59362306a36Sopenharmony_ci}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_cistatic int sof_ipc3_widget_setup_comp_src(struct snd_sof_widget *swidget)
59662306a36Sopenharmony_ci{
59762306a36Sopenharmony_ci	struct snd_soc_component *scomp = swidget->scomp;
59862306a36Sopenharmony_ci	struct sof_ipc_comp_src *src;
59962306a36Sopenharmony_ci	size_t ipc_size = sizeof(*src);
60062306a36Sopenharmony_ci	int ret;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	src = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
60362306a36Sopenharmony_ci	if (!src)
60462306a36Sopenharmony_ci		return -ENOMEM;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	swidget->private = src;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	/* configure src IPC message */
60962306a36Sopenharmony_ci	src->comp.type = SOF_COMP_SRC;
61062306a36Sopenharmony_ci	src->config.hdr.size = sizeof(src->config);
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	/* parse one set of src tokens */
61362306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, src, SOF_SRC_TOKENS, swidget->tuples,
61462306a36Sopenharmony_ci				    swidget->num_tuples, sizeof(*src), 1);
61562306a36Sopenharmony_ci	if (ret < 0)
61662306a36Sopenharmony_ci		goto err;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	/* parse one set of comp tokens */
61962306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, &src->config, SOF_COMP_TOKENS,
62062306a36Sopenharmony_ci				    swidget->tuples, swidget->num_tuples, sizeof(src->config), 1);
62162306a36Sopenharmony_ci	if (ret < 0)
62262306a36Sopenharmony_ci		goto err;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	dev_dbg(scomp->dev, "src %s: source rate %d sink rate %d\n",
62562306a36Sopenharmony_ci		swidget->widget->name, src->source_rate, src->sink_rate);
62662306a36Sopenharmony_ci	sof_dbg_comp_config(scomp, &src->config);
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	return 0;
62962306a36Sopenharmony_cierr:
63062306a36Sopenharmony_ci	kfree(swidget->private);
63162306a36Sopenharmony_ci	swidget->private = NULL;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	return ret;
63462306a36Sopenharmony_ci}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_cistatic int sof_ipc3_widget_setup_comp_asrc(struct snd_sof_widget *swidget)
63762306a36Sopenharmony_ci{
63862306a36Sopenharmony_ci	struct snd_soc_component *scomp = swidget->scomp;
63962306a36Sopenharmony_ci	struct sof_ipc_comp_asrc *asrc;
64062306a36Sopenharmony_ci	size_t ipc_size = sizeof(*asrc);
64162306a36Sopenharmony_ci	int ret;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	asrc = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
64462306a36Sopenharmony_ci	if (!asrc)
64562306a36Sopenharmony_ci		return -ENOMEM;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	swidget->private = asrc;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	/* configure ASRC IPC message */
65062306a36Sopenharmony_ci	asrc->comp.type = SOF_COMP_ASRC;
65162306a36Sopenharmony_ci	asrc->config.hdr.size = sizeof(asrc->config);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	/* parse one set of asrc tokens */
65462306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, asrc, SOF_ASRC_TOKENS, swidget->tuples,
65562306a36Sopenharmony_ci				    swidget->num_tuples, sizeof(*asrc), 1);
65662306a36Sopenharmony_ci	if (ret < 0)
65762306a36Sopenharmony_ci		goto err;
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	/* parse one set of comp tokens */
66062306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, &asrc->config, SOF_COMP_TOKENS,
66162306a36Sopenharmony_ci				    swidget->tuples, swidget->num_tuples, sizeof(asrc->config), 1);
66262306a36Sopenharmony_ci	if (ret < 0)
66362306a36Sopenharmony_ci		goto err;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	dev_dbg(scomp->dev, "asrc %s: source rate %d sink rate %d asynch %d operation %d\n",
66662306a36Sopenharmony_ci		swidget->widget->name, asrc->source_rate, asrc->sink_rate,
66762306a36Sopenharmony_ci		asrc->asynchronous_mode, asrc->operation_mode);
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	sof_dbg_comp_config(scomp, &asrc->config);
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	return 0;
67262306a36Sopenharmony_cierr:
67362306a36Sopenharmony_ci	kfree(swidget->private);
67462306a36Sopenharmony_ci	swidget->private = NULL;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	return ret;
67762306a36Sopenharmony_ci}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci/*
68062306a36Sopenharmony_ci * Mux topology
68162306a36Sopenharmony_ci */
68262306a36Sopenharmony_cistatic int sof_ipc3_widget_setup_comp_mux(struct snd_sof_widget *swidget)
68362306a36Sopenharmony_ci{
68462306a36Sopenharmony_ci	struct snd_soc_component *scomp = swidget->scomp;
68562306a36Sopenharmony_ci	struct sof_ipc_comp_mux *mux;
68662306a36Sopenharmony_ci	size_t ipc_size = sizeof(*mux);
68762306a36Sopenharmony_ci	int ret;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	mux = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
69062306a36Sopenharmony_ci	if (!mux)
69162306a36Sopenharmony_ci		return -ENOMEM;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	swidget->private = mux;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	/* configure mux IPC message */
69662306a36Sopenharmony_ci	mux->comp.type = SOF_COMP_MUX;
69762306a36Sopenharmony_ci	mux->config.hdr.size = sizeof(mux->config);
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	/* parse one set of comp tokens */
70062306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, &mux->config, SOF_COMP_TOKENS,
70162306a36Sopenharmony_ci				    swidget->tuples, swidget->num_tuples, sizeof(mux->config), 1);
70262306a36Sopenharmony_ci	if (ret < 0) {
70362306a36Sopenharmony_ci		kfree(swidget->private);
70462306a36Sopenharmony_ci		swidget->private = NULL;
70562306a36Sopenharmony_ci		return ret;
70662306a36Sopenharmony_ci	}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	dev_dbg(scomp->dev, "loaded mux %s\n", swidget->widget->name);
70962306a36Sopenharmony_ci	sof_dbg_comp_config(scomp, &mux->config);
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	return 0;
71262306a36Sopenharmony_ci}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci/*
71562306a36Sopenharmony_ci * PGA Topology
71662306a36Sopenharmony_ci */
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_cistatic int sof_ipc3_widget_setup_comp_pga(struct snd_sof_widget *swidget)
71962306a36Sopenharmony_ci{
72062306a36Sopenharmony_ci	struct snd_soc_component *scomp = swidget->scomp;
72162306a36Sopenharmony_ci	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
72262306a36Sopenharmony_ci	struct sof_ipc_comp_volume *volume;
72362306a36Sopenharmony_ci	struct snd_sof_control *scontrol;
72462306a36Sopenharmony_ci	size_t ipc_size = sizeof(*volume);
72562306a36Sopenharmony_ci	int min_step, max_step;
72662306a36Sopenharmony_ci	int ret;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	volume = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
72962306a36Sopenharmony_ci	if (!volume)
73062306a36Sopenharmony_ci		return -ENOMEM;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	swidget->private = volume;
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	/* configure volume IPC message */
73562306a36Sopenharmony_ci	volume->comp.type = SOF_COMP_VOLUME;
73662306a36Sopenharmony_ci	volume->config.hdr.size = sizeof(volume->config);
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	/* parse one set of volume tokens */
73962306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, volume, SOF_VOLUME_TOKENS, swidget->tuples,
74062306a36Sopenharmony_ci				    swidget->num_tuples, sizeof(*volume), 1);
74162306a36Sopenharmony_ci	if (ret < 0)
74262306a36Sopenharmony_ci		goto err;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	/* parse one set of comp tokens */
74562306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, &volume->config, SOF_COMP_TOKENS,
74662306a36Sopenharmony_ci				    swidget->tuples, swidget->num_tuples,
74762306a36Sopenharmony_ci				    sizeof(volume->config), 1);
74862306a36Sopenharmony_ci	if (ret < 0)
74962306a36Sopenharmony_ci		goto err;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	dev_dbg(scomp->dev, "loaded PGA %s\n", swidget->widget->name);
75262306a36Sopenharmony_ci	sof_dbg_comp_config(scomp, &volume->config);
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
75562306a36Sopenharmony_ci		if (scontrol->comp_id == swidget->comp_id &&
75662306a36Sopenharmony_ci		    scontrol->volume_table) {
75762306a36Sopenharmony_ci			min_step = scontrol->min_volume_step;
75862306a36Sopenharmony_ci			max_step = scontrol->max_volume_step;
75962306a36Sopenharmony_ci			volume->min_value = scontrol->volume_table[min_step];
76062306a36Sopenharmony_ci			volume->max_value = scontrol->volume_table[max_step];
76162306a36Sopenharmony_ci			volume->channels = scontrol->num_channels;
76262306a36Sopenharmony_ci			break;
76362306a36Sopenharmony_ci		}
76462306a36Sopenharmony_ci	}
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	return 0;
76762306a36Sopenharmony_cierr:
76862306a36Sopenharmony_ci	kfree(swidget->private);
76962306a36Sopenharmony_ci	swidget->private = NULL;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	return ret;
77262306a36Sopenharmony_ci}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_cistatic int sof_get_control_data(struct snd_soc_component *scomp,
77562306a36Sopenharmony_ci				struct snd_soc_dapm_widget *widget,
77662306a36Sopenharmony_ci				struct sof_widget_data *wdata, size_t *size)
77762306a36Sopenharmony_ci{
77862306a36Sopenharmony_ci	const struct snd_kcontrol_new *kc;
77962306a36Sopenharmony_ci	struct sof_ipc_ctrl_data *cdata;
78062306a36Sopenharmony_ci	struct soc_mixer_control *sm;
78162306a36Sopenharmony_ci	struct soc_bytes_ext *sbe;
78262306a36Sopenharmony_ci	struct soc_enum *se;
78362306a36Sopenharmony_ci	int i;
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	*size = 0;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	for (i = 0; i < widget->num_kcontrols; i++) {
78862306a36Sopenharmony_ci		kc = &widget->kcontrol_news[i];
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci		switch (widget->dobj.widget.kcontrol_type[i]) {
79162306a36Sopenharmony_ci		case SND_SOC_TPLG_TYPE_MIXER:
79262306a36Sopenharmony_ci			sm = (struct soc_mixer_control *)kc->private_value;
79362306a36Sopenharmony_ci			wdata[i].control = sm->dobj.private;
79462306a36Sopenharmony_ci			break;
79562306a36Sopenharmony_ci		case SND_SOC_TPLG_TYPE_BYTES:
79662306a36Sopenharmony_ci			sbe = (struct soc_bytes_ext *)kc->private_value;
79762306a36Sopenharmony_ci			wdata[i].control = sbe->dobj.private;
79862306a36Sopenharmony_ci			break;
79962306a36Sopenharmony_ci		case SND_SOC_TPLG_TYPE_ENUM:
80062306a36Sopenharmony_ci			se = (struct soc_enum *)kc->private_value;
80162306a36Sopenharmony_ci			wdata[i].control = se->dobj.private;
80262306a36Sopenharmony_ci			break;
80362306a36Sopenharmony_ci		default:
80462306a36Sopenharmony_ci			dev_err(scomp->dev, "Unknown kcontrol type %u in widget %s\n",
80562306a36Sopenharmony_ci				widget->dobj.widget.kcontrol_type[i], widget->name);
80662306a36Sopenharmony_ci			return -EINVAL;
80762306a36Sopenharmony_ci		}
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci		if (!wdata[i].control) {
81062306a36Sopenharmony_ci			dev_err(scomp->dev, "No scontrol for widget %s\n", widget->name);
81162306a36Sopenharmony_ci			return -EINVAL;
81262306a36Sopenharmony_ci		}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci		cdata = wdata[i].control->ipc_control_data;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci		if (widget->dobj.widget.kcontrol_type[i] == SND_SOC_TPLG_TYPE_BYTES) {
81762306a36Sopenharmony_ci			/* make sure data is valid - data can be updated at runtime */
81862306a36Sopenharmony_ci			if (cdata->data->magic != SOF_ABI_MAGIC)
81962306a36Sopenharmony_ci				return -EINVAL;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci			wdata[i].pdata = cdata->data->data;
82262306a36Sopenharmony_ci			wdata[i].pdata_size = cdata->data->size;
82362306a36Sopenharmony_ci		} else {
82462306a36Sopenharmony_ci			/* points to the control data union */
82562306a36Sopenharmony_ci			wdata[i].pdata = cdata->chanv;
82662306a36Sopenharmony_ci			/*
82762306a36Sopenharmony_ci			 * wdata[i].control->size is calculated with struct_size
82862306a36Sopenharmony_ci			 * and includes the size of struct sof_ipc_ctrl_data
82962306a36Sopenharmony_ci			 */
83062306a36Sopenharmony_ci			wdata[i].pdata_size = wdata[i].control->size -
83162306a36Sopenharmony_ci					      sizeof(struct sof_ipc_ctrl_data);
83262306a36Sopenharmony_ci		}
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci		*size += wdata[i].pdata_size;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci		/* get data type */
83762306a36Sopenharmony_ci		switch (cdata->cmd) {
83862306a36Sopenharmony_ci		case SOF_CTRL_CMD_VOLUME:
83962306a36Sopenharmony_ci		case SOF_CTRL_CMD_ENUM:
84062306a36Sopenharmony_ci		case SOF_CTRL_CMD_SWITCH:
84162306a36Sopenharmony_ci			wdata[i].ipc_cmd = SOF_IPC_COMP_SET_VALUE;
84262306a36Sopenharmony_ci			wdata[i].ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET;
84362306a36Sopenharmony_ci			break;
84462306a36Sopenharmony_ci		case SOF_CTRL_CMD_BINARY:
84562306a36Sopenharmony_ci			wdata[i].ipc_cmd = SOF_IPC_COMP_SET_DATA;
84662306a36Sopenharmony_ci			wdata[i].ctrl_type = SOF_CTRL_TYPE_DATA_SET;
84762306a36Sopenharmony_ci			break;
84862306a36Sopenharmony_ci		default:
84962306a36Sopenharmony_ci			break;
85062306a36Sopenharmony_ci		}
85162306a36Sopenharmony_ci	}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	return 0;
85462306a36Sopenharmony_ci}
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_cistatic int sof_process_load(struct snd_soc_component *scomp,
85762306a36Sopenharmony_ci			    struct snd_sof_widget *swidget, int type)
85862306a36Sopenharmony_ci{
85962306a36Sopenharmony_ci	struct snd_soc_dapm_widget *widget = swidget->widget;
86062306a36Sopenharmony_ci	struct sof_ipc_comp_process *process;
86162306a36Sopenharmony_ci	struct sof_widget_data *wdata = NULL;
86262306a36Sopenharmony_ci	size_t ipc_data_size = 0;
86362306a36Sopenharmony_ci	size_t ipc_size;
86462306a36Sopenharmony_ci	int offset = 0;
86562306a36Sopenharmony_ci	int ret;
86662306a36Sopenharmony_ci	int i;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	/* allocate struct for widget control data sizes and types */
86962306a36Sopenharmony_ci	if (widget->num_kcontrols) {
87062306a36Sopenharmony_ci		wdata = kcalloc(widget->num_kcontrols, sizeof(*wdata), GFP_KERNEL);
87162306a36Sopenharmony_ci		if (!wdata)
87262306a36Sopenharmony_ci			return -ENOMEM;
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci		/* get possible component controls and get size of all pdata */
87562306a36Sopenharmony_ci		ret = sof_get_control_data(scomp, widget, wdata, &ipc_data_size);
87662306a36Sopenharmony_ci		if (ret < 0)
87762306a36Sopenharmony_ci			goto out;
87862306a36Sopenharmony_ci	}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	ipc_size = sizeof(struct sof_ipc_comp_process) + ipc_data_size;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	/* we are exceeding max ipc size, config needs to be sent separately */
88362306a36Sopenharmony_ci	if (ipc_size > SOF_IPC_MSG_MAX_SIZE) {
88462306a36Sopenharmony_ci		ipc_size -= ipc_data_size;
88562306a36Sopenharmony_ci		ipc_data_size = 0;
88662306a36Sopenharmony_ci	}
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	process = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
88962306a36Sopenharmony_ci	if (!process) {
89062306a36Sopenharmony_ci		ret = -ENOMEM;
89162306a36Sopenharmony_ci		goto out;
89262306a36Sopenharmony_ci	}
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	swidget->private = process;
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	/* configure iir IPC message */
89762306a36Sopenharmony_ci	process->comp.type = type;
89862306a36Sopenharmony_ci	process->config.hdr.size = sizeof(process->config);
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	/* parse one set of comp tokens */
90162306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, &process->config, SOF_COMP_TOKENS,
90262306a36Sopenharmony_ci				    swidget->tuples, swidget->num_tuples,
90362306a36Sopenharmony_ci				    sizeof(process->config), 1);
90462306a36Sopenharmony_ci	if (ret < 0)
90562306a36Sopenharmony_ci		goto err;
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	dev_dbg(scomp->dev, "loaded process %s\n", swidget->widget->name);
90862306a36Sopenharmony_ci	sof_dbg_comp_config(scomp, &process->config);
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	/*
91162306a36Sopenharmony_ci	 * found private data in control, so copy it.
91262306a36Sopenharmony_ci	 * get possible component controls - get size of all pdata,
91362306a36Sopenharmony_ci	 * then memcpy with headers
91462306a36Sopenharmony_ci	 */
91562306a36Sopenharmony_ci	if (ipc_data_size) {
91662306a36Sopenharmony_ci		for (i = 0; i < widget->num_kcontrols; i++) {
91762306a36Sopenharmony_ci			if (!wdata[i].pdata_size)
91862306a36Sopenharmony_ci				continue;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci			memcpy(&process->data[offset], wdata[i].pdata,
92162306a36Sopenharmony_ci			       wdata[i].pdata_size);
92262306a36Sopenharmony_ci			offset += wdata[i].pdata_size;
92362306a36Sopenharmony_ci		}
92462306a36Sopenharmony_ci	}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	process->size = ipc_data_size;
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	kfree(wdata);
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	return 0;
93162306a36Sopenharmony_cierr:
93262306a36Sopenharmony_ci	kfree(swidget->private);
93362306a36Sopenharmony_ci	swidget->private = NULL;
93462306a36Sopenharmony_ciout:
93562306a36Sopenharmony_ci	kfree(wdata);
93662306a36Sopenharmony_ci	return ret;
93762306a36Sopenharmony_ci}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_cistatic enum sof_comp_type find_process_comp_type(enum sof_ipc_process_type type)
94062306a36Sopenharmony_ci{
94162306a36Sopenharmony_ci	int i;
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(sof_process); i++) {
94462306a36Sopenharmony_ci		if (sof_process[i].type == type)
94562306a36Sopenharmony_ci			return sof_process[i].comp_type;
94662306a36Sopenharmony_ci	}
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	return SOF_COMP_NONE;
94962306a36Sopenharmony_ci}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci/*
95262306a36Sopenharmony_ci * Processing Component Topology - can be "effect", "codec", or general
95362306a36Sopenharmony_ci * "processing".
95462306a36Sopenharmony_ci */
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_cistatic int sof_widget_update_ipc_comp_process(struct snd_sof_widget *swidget)
95762306a36Sopenharmony_ci{
95862306a36Sopenharmony_ci	struct snd_soc_component *scomp = swidget->scomp;
95962306a36Sopenharmony_ci	struct sof_ipc_comp_process config;
96062306a36Sopenharmony_ci	int ret;
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	memset(&config, 0, sizeof(config));
96362306a36Sopenharmony_ci	config.comp.core = swidget->core;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	/* parse one set of process tokens */
96662306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, &config, SOF_PROCESS_TOKENS, swidget->tuples,
96762306a36Sopenharmony_ci				    swidget->num_tuples, sizeof(config), 1);
96862306a36Sopenharmony_ci	if (ret < 0)
96962306a36Sopenharmony_ci		return ret;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	/* now load process specific data and send IPC */
97262306a36Sopenharmony_ci	return sof_process_load(scomp, swidget, find_process_comp_type(config.type));
97362306a36Sopenharmony_ci}
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_cistatic int sof_link_hda_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
97662306a36Sopenharmony_ci			     struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
97762306a36Sopenharmony_ci{
97862306a36Sopenharmony_ci	struct sof_dai_private_data *private = dai->private;
97962306a36Sopenharmony_ci	u32 size = sizeof(*config);
98062306a36Sopenharmony_ci	int ret;
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	/* init IPC */
98362306a36Sopenharmony_ci	memset(&config->hda, 0, sizeof(config->hda));
98462306a36Sopenharmony_ci	config->hdr.size = size;
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	/* parse one set of HDA tokens */
98762306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, &config->hda, SOF_HDA_TOKENS, slink->tuples,
98862306a36Sopenharmony_ci				    slink->num_tuples, size, 1);
98962306a36Sopenharmony_ci	if (ret < 0)
99062306a36Sopenharmony_ci		return ret;
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	dev_dbg(scomp->dev, "HDA config rate %d channels %d\n",
99362306a36Sopenharmony_ci		config->hda.rate, config->hda.channels);
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	config->hda.link_dma_ch = DMA_CHAN_INVALID;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	dai->number_configs = 1;
99862306a36Sopenharmony_ci	dai->current_config = 0;
99962306a36Sopenharmony_ci	private->dai_config = kmemdup(config, size, GFP_KERNEL);
100062306a36Sopenharmony_ci	if (!private->dai_config)
100162306a36Sopenharmony_ci		return -ENOMEM;
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	return 0;
100462306a36Sopenharmony_ci}
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_cistatic void sof_dai_set_format(struct snd_soc_tplg_hw_config *hw_config,
100762306a36Sopenharmony_ci			       struct sof_ipc_dai_config *config)
100862306a36Sopenharmony_ci{
100962306a36Sopenharmony_ci	/* clock directions wrt codec */
101062306a36Sopenharmony_ci	config->format &= ~SOF_DAI_FMT_CLOCK_PROVIDER_MASK;
101162306a36Sopenharmony_ci	if (hw_config->bclk_provider == SND_SOC_TPLG_BCLK_CP) {
101262306a36Sopenharmony_ci		/* codec is bclk provider */
101362306a36Sopenharmony_ci		if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CP)
101462306a36Sopenharmony_ci			config->format |= SOF_DAI_FMT_CBP_CFP;
101562306a36Sopenharmony_ci		else
101662306a36Sopenharmony_ci			config->format |= SOF_DAI_FMT_CBP_CFC;
101762306a36Sopenharmony_ci	} else {
101862306a36Sopenharmony_ci		/* codec is bclk consumer */
101962306a36Sopenharmony_ci		if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CP)
102062306a36Sopenharmony_ci			config->format |= SOF_DAI_FMT_CBC_CFP;
102162306a36Sopenharmony_ci		else
102262306a36Sopenharmony_ci			config->format |= SOF_DAI_FMT_CBC_CFC;
102362306a36Sopenharmony_ci	}
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	/* inverted clocks ? */
102662306a36Sopenharmony_ci	config->format &= ~SOF_DAI_FMT_INV_MASK;
102762306a36Sopenharmony_ci	if (hw_config->invert_bclk) {
102862306a36Sopenharmony_ci		if (hw_config->invert_fsync)
102962306a36Sopenharmony_ci			config->format |= SOF_DAI_FMT_IB_IF;
103062306a36Sopenharmony_ci		else
103162306a36Sopenharmony_ci			config->format |= SOF_DAI_FMT_IB_NF;
103262306a36Sopenharmony_ci	} else {
103362306a36Sopenharmony_ci		if (hw_config->invert_fsync)
103462306a36Sopenharmony_ci			config->format |= SOF_DAI_FMT_NB_IF;
103562306a36Sopenharmony_ci		else
103662306a36Sopenharmony_ci			config->format |= SOF_DAI_FMT_NB_NF;
103762306a36Sopenharmony_ci	}
103862306a36Sopenharmony_ci}
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_cistatic int sof_link_sai_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
104162306a36Sopenharmony_ci			     struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
104262306a36Sopenharmony_ci{
104362306a36Sopenharmony_ci	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
104462306a36Sopenharmony_ci	struct sof_dai_private_data *private = dai->private;
104562306a36Sopenharmony_ci	u32 size = sizeof(*config);
104662306a36Sopenharmony_ci	int ret;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	/* handle master/slave and inverted clocks */
104962306a36Sopenharmony_ci	sof_dai_set_format(hw_config, config);
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	/* init IPC */
105262306a36Sopenharmony_ci	memset(&config->sai, 0, sizeof(config->sai));
105362306a36Sopenharmony_ci	config->hdr.size = size;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	/* parse one set of SAI tokens */
105662306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, &config->sai, SOF_SAI_TOKENS, slink->tuples,
105762306a36Sopenharmony_ci				    slink->num_tuples, size, 1);
105862306a36Sopenharmony_ci	if (ret < 0)
105962306a36Sopenharmony_ci		return ret;
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	config->sai.mclk_rate = le32_to_cpu(hw_config->mclk_rate);
106262306a36Sopenharmony_ci	config->sai.bclk_rate = le32_to_cpu(hw_config->bclk_rate);
106362306a36Sopenharmony_ci	config->sai.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
106462306a36Sopenharmony_ci	config->sai.mclk_direction = hw_config->mclk_direction;
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	config->sai.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
106762306a36Sopenharmony_ci	config->sai.tdm_slot_width = le32_to_cpu(hw_config->tdm_slot_width);
106862306a36Sopenharmony_ci	config->sai.rx_slots = le32_to_cpu(hw_config->rx_slots);
106962306a36Sopenharmony_ci	config->sai.tx_slots = le32_to_cpu(hw_config->tx_slots);
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	dev_info(scomp->dev,
107262306a36Sopenharmony_ci		 "tplg: config SAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n",
107362306a36Sopenharmony_ci		config->dai_index, config->format,
107462306a36Sopenharmony_ci		config->sai.mclk_rate, config->sai.tdm_slot_width,
107562306a36Sopenharmony_ci		config->sai.tdm_slots, config->sai.mclk_id);
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	if (config->sai.tdm_slots < 1 || config->sai.tdm_slots > 8) {
107862306a36Sopenharmony_ci		dev_err(scomp->dev, "Invalid channel count for SAI%d\n", config->dai_index);
107962306a36Sopenharmony_ci		return -EINVAL;
108062306a36Sopenharmony_ci	}
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	dai->number_configs = 1;
108362306a36Sopenharmony_ci	dai->current_config = 0;
108462306a36Sopenharmony_ci	private->dai_config = kmemdup(config, size, GFP_KERNEL);
108562306a36Sopenharmony_ci	if (!private->dai_config)
108662306a36Sopenharmony_ci		return -ENOMEM;
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	return 0;
108962306a36Sopenharmony_ci}
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_cistatic int sof_link_esai_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
109262306a36Sopenharmony_ci			      struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
109362306a36Sopenharmony_ci{
109462306a36Sopenharmony_ci	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
109562306a36Sopenharmony_ci	struct sof_dai_private_data *private = dai->private;
109662306a36Sopenharmony_ci	u32 size = sizeof(*config);
109762306a36Sopenharmony_ci	int ret;
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci	/* handle master/slave and inverted clocks */
110062306a36Sopenharmony_ci	sof_dai_set_format(hw_config, config);
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	/* init IPC */
110362306a36Sopenharmony_ci	memset(&config->esai, 0, sizeof(config->esai));
110462306a36Sopenharmony_ci	config->hdr.size = size;
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	/* parse one set of ESAI tokens */
110762306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, &config->esai, SOF_ESAI_TOKENS, slink->tuples,
110862306a36Sopenharmony_ci				    slink->num_tuples, size, 1);
110962306a36Sopenharmony_ci	if (ret < 0)
111062306a36Sopenharmony_ci		return ret;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	config->esai.mclk_rate = le32_to_cpu(hw_config->mclk_rate);
111362306a36Sopenharmony_ci	config->esai.bclk_rate = le32_to_cpu(hw_config->bclk_rate);
111462306a36Sopenharmony_ci	config->esai.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
111562306a36Sopenharmony_ci	config->esai.mclk_direction = hw_config->mclk_direction;
111662306a36Sopenharmony_ci	config->esai.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
111762306a36Sopenharmony_ci	config->esai.tdm_slot_width = le32_to_cpu(hw_config->tdm_slot_width);
111862306a36Sopenharmony_ci	config->esai.rx_slots = le32_to_cpu(hw_config->rx_slots);
111962306a36Sopenharmony_ci	config->esai.tx_slots = le32_to_cpu(hw_config->tx_slots);
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	dev_info(scomp->dev,
112262306a36Sopenharmony_ci		 "tplg: config ESAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n",
112362306a36Sopenharmony_ci		config->dai_index, config->format,
112462306a36Sopenharmony_ci		config->esai.mclk_rate, config->esai.tdm_slot_width,
112562306a36Sopenharmony_ci		config->esai.tdm_slots, config->esai.mclk_id);
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	if (config->esai.tdm_slots < 1 || config->esai.tdm_slots > 8) {
112862306a36Sopenharmony_ci		dev_err(scomp->dev, "Invalid channel count for ESAI%d\n", config->dai_index);
112962306a36Sopenharmony_ci		return -EINVAL;
113062306a36Sopenharmony_ci	}
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	dai->number_configs = 1;
113362306a36Sopenharmony_ci	dai->current_config = 0;
113462306a36Sopenharmony_ci	private->dai_config = kmemdup(config, size, GFP_KERNEL);
113562306a36Sopenharmony_ci	if (!private->dai_config)
113662306a36Sopenharmony_ci		return -ENOMEM;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	return 0;
113962306a36Sopenharmony_ci}
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_cistatic int sof_link_acp_dmic_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
114262306a36Sopenharmony_ci				  struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
114362306a36Sopenharmony_ci{
114462306a36Sopenharmony_ci	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
114562306a36Sopenharmony_ci	struct sof_dai_private_data *private = dai->private;
114662306a36Sopenharmony_ci	u32 size = sizeof(*config);
114762306a36Sopenharmony_ci	int ret;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci       /* handle master/slave and inverted clocks */
115062306a36Sopenharmony_ci	sof_dai_set_format(hw_config, config);
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	config->hdr.size = size;
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	/* parse the required set of ACPDMIC tokens based on num_hw_cfgs */
115562306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, &config->acpdmic, SOF_ACPDMIC_TOKENS, slink->tuples,
115662306a36Sopenharmony_ci				    slink->num_tuples, size, slink->num_hw_configs);
115762306a36Sopenharmony_ci	if (ret < 0)
115862306a36Sopenharmony_ci		return ret;
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci	dev_info(scomp->dev, "ACP_DMIC config ACP%d channel %d rate %d\n",
116162306a36Sopenharmony_ci		 config->dai_index, config->acpdmic.pdm_ch,
116262306a36Sopenharmony_ci		 config->acpdmic.pdm_rate);
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	dai->number_configs = 1;
116562306a36Sopenharmony_ci	dai->current_config = 0;
116662306a36Sopenharmony_ci	private->dai_config = kmemdup(config, size, GFP_KERNEL);
116762306a36Sopenharmony_ci	if (!private->dai_config)
116862306a36Sopenharmony_ci		return -ENOMEM;
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	return 0;
117162306a36Sopenharmony_ci}
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_cistatic int sof_link_acp_bt_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
117462306a36Sopenharmony_ci				struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
117562306a36Sopenharmony_ci{
117662306a36Sopenharmony_ci	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
117762306a36Sopenharmony_ci	struct sof_dai_private_data *private = dai->private;
117862306a36Sopenharmony_ci	u32 size = sizeof(*config);
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	/* handle master/slave and inverted clocks */
118162306a36Sopenharmony_ci	sof_dai_set_format(hw_config, config);
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	/* init IPC */
118462306a36Sopenharmony_ci	memset(&config->acpbt, 0, sizeof(config->acpbt));
118562306a36Sopenharmony_ci	config->hdr.size = size;
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	config->acpbt.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
118862306a36Sopenharmony_ci	config->acpbt.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	dev_info(scomp->dev, "ACP_BT config ACP%d channel %d rate %d\n",
119162306a36Sopenharmony_ci		 config->dai_index, config->acpbt.tdm_slots,
119262306a36Sopenharmony_ci		 config->acpbt.fsync_rate);
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	dai->number_configs = 1;
119562306a36Sopenharmony_ci	dai->current_config = 0;
119662306a36Sopenharmony_ci	private->dai_config = kmemdup(config, size, GFP_KERNEL);
119762306a36Sopenharmony_ci	if (!private->dai_config)
119862306a36Sopenharmony_ci		return -ENOMEM;
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	return 0;
120162306a36Sopenharmony_ci}
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_cistatic int sof_link_acp_sp_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
120462306a36Sopenharmony_ci				struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
120562306a36Sopenharmony_ci{
120662306a36Sopenharmony_ci	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
120762306a36Sopenharmony_ci	struct sof_dai_private_data *private = dai->private;
120862306a36Sopenharmony_ci	u32 size = sizeof(*config);
120962306a36Sopenharmony_ci	int ret;
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	/* handle master/slave and inverted clocks */
121262306a36Sopenharmony_ci	sof_dai_set_format(hw_config, config);
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	/* init IPC */
121562306a36Sopenharmony_ci	memset(&config->acpsp, 0, sizeof(config->acpsp));
121662306a36Sopenharmony_ci	config->hdr.size = size;
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, &config->acpsp, SOF_ACPI2S_TOKENS, slink->tuples,
121962306a36Sopenharmony_ci				    slink->num_tuples, size, slink->num_hw_configs);
122062306a36Sopenharmony_ci	if (ret < 0)
122162306a36Sopenharmony_ci		return ret;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	dev_info(scomp->dev, "ACP_SP config ACP%d channel %d rate %d tdm_mode %d\n",
122562306a36Sopenharmony_ci		 config->dai_index, config->acpsp.tdm_slots,
122662306a36Sopenharmony_ci		 config->acpsp.fsync_rate, config->acpsp.tdm_mode);
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	dai->number_configs = 1;
122962306a36Sopenharmony_ci	dai->current_config = 0;
123062306a36Sopenharmony_ci	private->dai_config = kmemdup(config, size, GFP_KERNEL);
123162306a36Sopenharmony_ci	if (!private->dai_config)
123262306a36Sopenharmony_ci		return -ENOMEM;
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	return 0;
123562306a36Sopenharmony_ci}
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_cistatic int sof_link_acp_hs_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
123862306a36Sopenharmony_ci				struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
123962306a36Sopenharmony_ci{
124062306a36Sopenharmony_ci	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
124162306a36Sopenharmony_ci	struct sof_dai_private_data *private = dai->private;
124262306a36Sopenharmony_ci	u32 size = sizeof(*config);
124362306a36Sopenharmony_ci	int ret;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	/* Configures the DAI hardware format and inverted clocks */
124662306a36Sopenharmony_ci	sof_dai_set_format(hw_config, config);
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	/* init IPC */
124962306a36Sopenharmony_ci	memset(&config->acphs, 0, sizeof(config->acphs));
125062306a36Sopenharmony_ci	config->hdr.size = size;
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, &config->acphs, SOF_ACPI2S_TOKENS, slink->tuples,
125362306a36Sopenharmony_ci				    slink->num_tuples, size, slink->num_hw_configs);
125462306a36Sopenharmony_ci	if (ret < 0)
125562306a36Sopenharmony_ci		return ret;
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	dev_info(scomp->dev, "ACP_HS config ACP%d channel %d rate %d tdm_mode %d\n",
125862306a36Sopenharmony_ci		 config->dai_index, config->acphs.tdm_slots,
125962306a36Sopenharmony_ci		 config->acphs.fsync_rate, config->acphs.tdm_mode);
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	dai->number_configs = 1;
126262306a36Sopenharmony_ci	dai->current_config = 0;
126362306a36Sopenharmony_ci	private->dai_config = kmemdup(config, size, GFP_KERNEL);
126462306a36Sopenharmony_ci	if (!private->dai_config)
126562306a36Sopenharmony_ci		return -ENOMEM;
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	return 0;
126862306a36Sopenharmony_ci}
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_cistatic int sof_link_afe_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
127162306a36Sopenharmony_ci			     struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
127262306a36Sopenharmony_ci{
127362306a36Sopenharmony_ci	struct sof_dai_private_data *private = dai->private;
127462306a36Sopenharmony_ci	u32 size = sizeof(*config);
127562306a36Sopenharmony_ci	int ret;
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	config->hdr.size = size;
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	/* parse the required set of AFE tokens based on num_hw_cfgs */
128062306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, &config->afe, SOF_AFE_TOKENS, slink->tuples,
128162306a36Sopenharmony_ci				    slink->num_tuples, size, slink->num_hw_configs);
128262306a36Sopenharmony_ci	if (ret < 0)
128362306a36Sopenharmony_ci		return ret;
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	dev_dbg(scomp->dev, "AFE config rate %d channels %d format:%d\n",
128662306a36Sopenharmony_ci		config->afe.rate, config->afe.channels, config->afe.format);
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	config->afe.stream_id = DMA_CHAN_INVALID;
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	dai->number_configs = 1;
129162306a36Sopenharmony_ci	dai->current_config = 0;
129262306a36Sopenharmony_ci	private->dai_config = kmemdup(config, size, GFP_KERNEL);
129362306a36Sopenharmony_ci	if (!private->dai_config)
129462306a36Sopenharmony_ci		return -ENOMEM;
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	return 0;
129762306a36Sopenharmony_ci}
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_cistatic int sof_link_ssp_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
130062306a36Sopenharmony_ci			     struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
130162306a36Sopenharmony_ci{
130262306a36Sopenharmony_ci	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
130362306a36Sopenharmony_ci	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
130462306a36Sopenharmony_ci	struct sof_dai_private_data *private = dai->private;
130562306a36Sopenharmony_ci	u32 size = sizeof(*config);
130662306a36Sopenharmony_ci	int current_config = 0;
130762306a36Sopenharmony_ci	int i, ret;
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	/*
131062306a36Sopenharmony_ci	 * Parse common data, we should have 1 common data per hw_config.
131162306a36Sopenharmony_ci	 */
131262306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, &config->ssp, SOF_SSP_TOKENS, slink->tuples,
131362306a36Sopenharmony_ci				    slink->num_tuples, size, slink->num_hw_configs);
131462306a36Sopenharmony_ci	if (ret < 0)
131562306a36Sopenharmony_ci		return ret;
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	/* process all possible hw configs */
131862306a36Sopenharmony_ci	for (i = 0; i < slink->num_hw_configs; i++) {
131962306a36Sopenharmony_ci		if (le32_to_cpu(hw_config[i].id) == slink->default_hw_cfg_id)
132062306a36Sopenharmony_ci			current_config = i;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci		/* handle master/slave and inverted clocks */
132362306a36Sopenharmony_ci		sof_dai_set_format(&hw_config[i], &config[i]);
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci		config[i].hdr.size = size;
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci		if (sdev->mclk_id_override) {
132862306a36Sopenharmony_ci			dev_dbg(scomp->dev, "tplg: overriding topology mclk_id %d by quirk %d\n",
132962306a36Sopenharmony_ci				config[i].ssp.mclk_id, sdev->mclk_id_quirk);
133062306a36Sopenharmony_ci			config[i].ssp.mclk_id = sdev->mclk_id_quirk;
133162306a36Sopenharmony_ci		}
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci		/* copy differentiating hw configs to ipc structs */
133462306a36Sopenharmony_ci		config[i].ssp.mclk_rate = le32_to_cpu(hw_config[i].mclk_rate);
133562306a36Sopenharmony_ci		config[i].ssp.bclk_rate = le32_to_cpu(hw_config[i].bclk_rate);
133662306a36Sopenharmony_ci		config[i].ssp.fsync_rate = le32_to_cpu(hw_config[i].fsync_rate);
133762306a36Sopenharmony_ci		config[i].ssp.tdm_slots = le32_to_cpu(hw_config[i].tdm_slots);
133862306a36Sopenharmony_ci		config[i].ssp.tdm_slot_width = le32_to_cpu(hw_config[i].tdm_slot_width);
133962306a36Sopenharmony_ci		config[i].ssp.mclk_direction = hw_config[i].mclk_direction;
134062306a36Sopenharmony_ci		config[i].ssp.rx_slots = le32_to_cpu(hw_config[i].rx_slots);
134162306a36Sopenharmony_ci		config[i].ssp.tx_slots = le32_to_cpu(hw_config[i].tx_slots);
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci		dev_dbg(scomp->dev, "tplg: config SSP%d fmt %#x mclk %d bclk %d fclk %d width (%d)%d slots %d mclk id %d quirks %d clks_control %#x\n",
134462306a36Sopenharmony_ci			config[i].dai_index, config[i].format,
134562306a36Sopenharmony_ci			config[i].ssp.mclk_rate, config[i].ssp.bclk_rate,
134662306a36Sopenharmony_ci			config[i].ssp.fsync_rate, config[i].ssp.sample_valid_bits,
134762306a36Sopenharmony_ci			config[i].ssp.tdm_slot_width, config[i].ssp.tdm_slots,
134862306a36Sopenharmony_ci			config[i].ssp.mclk_id, config[i].ssp.quirks, config[i].ssp.clks_control);
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci		/* validate SSP fsync rate and channel count */
135162306a36Sopenharmony_ci		if (config[i].ssp.fsync_rate < 8000 || config[i].ssp.fsync_rate > 192000) {
135262306a36Sopenharmony_ci			dev_err(scomp->dev, "Invalid fsync rate for SSP%d\n", config[i].dai_index);
135362306a36Sopenharmony_ci			return -EINVAL;
135462306a36Sopenharmony_ci		}
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci		if (config[i].ssp.tdm_slots < 1 || config[i].ssp.tdm_slots > 8) {
135762306a36Sopenharmony_ci			dev_err(scomp->dev, "Invalid channel count for SSP%d\n",
135862306a36Sopenharmony_ci				config[i].dai_index);
135962306a36Sopenharmony_ci			return -EINVAL;
136062306a36Sopenharmony_ci		}
136162306a36Sopenharmony_ci	}
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	dai->number_configs = slink->num_hw_configs;
136462306a36Sopenharmony_ci	dai->current_config = current_config;
136562306a36Sopenharmony_ci	private->dai_config = kmemdup(config, size * slink->num_hw_configs, GFP_KERNEL);
136662306a36Sopenharmony_ci	if (!private->dai_config)
136762306a36Sopenharmony_ci		return -ENOMEM;
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	return 0;
137062306a36Sopenharmony_ci}
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_cistatic int sof_link_dmic_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
137362306a36Sopenharmony_ci			      struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
137462306a36Sopenharmony_ci{
137562306a36Sopenharmony_ci	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
137662306a36Sopenharmony_ci	struct sof_dai_private_data *private = dai->private;
137762306a36Sopenharmony_ci	struct sof_ipc_fw_ready *ready = &sdev->fw_ready;
137862306a36Sopenharmony_ci	struct sof_ipc_fw_version *v = &ready->version;
137962306a36Sopenharmony_ci	size_t size = sizeof(*config);
138062306a36Sopenharmony_ci	int i, ret;
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	/* Ensure the entire DMIC config struct is zeros */
138362306a36Sopenharmony_ci	memset(&config->dmic, 0, sizeof(config->dmic));
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	/* parse the required set of DMIC tokens based on num_hw_cfgs */
138662306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, &config->dmic, SOF_DMIC_TOKENS, slink->tuples,
138762306a36Sopenharmony_ci				    slink->num_tuples, size, slink->num_hw_configs);
138862306a36Sopenharmony_ci	if (ret < 0)
138962306a36Sopenharmony_ci		return ret;
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	/* parse the required set of DMIC PDM tokens based on number of active PDM's */
139262306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, &config->dmic.pdm[0], SOF_DMIC_PDM_TOKENS,
139362306a36Sopenharmony_ci				    slink->tuples, slink->num_tuples,
139462306a36Sopenharmony_ci				    sizeof(struct sof_ipc_dai_dmic_pdm_ctrl),
139562306a36Sopenharmony_ci				    config->dmic.num_pdm_active);
139662306a36Sopenharmony_ci	if (ret < 0)
139762306a36Sopenharmony_ci		return ret;
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	/* set IPC header size */
140062306a36Sopenharmony_ci	config->hdr.size = size;
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	/* debug messages */
140362306a36Sopenharmony_ci	dev_dbg(scomp->dev, "tplg: config DMIC%d driver version %d\n",
140462306a36Sopenharmony_ci		config->dai_index, config->dmic.driver_ipc_version);
140562306a36Sopenharmony_ci	dev_dbg(scomp->dev, "pdmclk_min %d pdm_clkmax %d duty_min %d\n",
140662306a36Sopenharmony_ci		config->dmic.pdmclk_min, config->dmic.pdmclk_max,
140762306a36Sopenharmony_ci		config->dmic.duty_min);
140862306a36Sopenharmony_ci	dev_dbg(scomp->dev, "duty_max %d fifo_fs %d num_pdms active %d\n",
140962306a36Sopenharmony_ci		config->dmic.duty_max, config->dmic.fifo_fs,
141062306a36Sopenharmony_ci		config->dmic.num_pdm_active);
141162306a36Sopenharmony_ci	dev_dbg(scomp->dev, "fifo word length %d\n", config->dmic.fifo_bits);
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	for (i = 0; i < config->dmic.num_pdm_active; i++) {
141462306a36Sopenharmony_ci		dev_dbg(scomp->dev, "pdm %d mic a %d mic b %d\n",
141562306a36Sopenharmony_ci			config->dmic.pdm[i].id,
141662306a36Sopenharmony_ci			config->dmic.pdm[i].enable_mic_a,
141762306a36Sopenharmony_ci			config->dmic.pdm[i].enable_mic_b);
141862306a36Sopenharmony_ci		dev_dbg(scomp->dev, "pdm %d polarity a %d polarity b %d\n",
141962306a36Sopenharmony_ci			config->dmic.pdm[i].id,
142062306a36Sopenharmony_ci			config->dmic.pdm[i].polarity_mic_a,
142162306a36Sopenharmony_ci			config->dmic.pdm[i].polarity_mic_b);
142262306a36Sopenharmony_ci		dev_dbg(scomp->dev, "pdm %d clk_edge %d skew %d\n",
142362306a36Sopenharmony_ci			config->dmic.pdm[i].id,
142462306a36Sopenharmony_ci			config->dmic.pdm[i].clk_edge,
142562306a36Sopenharmony_ci			config->dmic.pdm[i].skew);
142662306a36Sopenharmony_ci	}
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci	/*
142962306a36Sopenharmony_ci	 * this takes care of backwards compatible handling of fifo_bits_b.
143062306a36Sopenharmony_ci	 * It is deprecated since firmware ABI version 3.0.1.
143162306a36Sopenharmony_ci	 */
143262306a36Sopenharmony_ci	if (SOF_ABI_VER(v->major, v->minor, v->micro) < SOF_ABI_VER(3, 0, 1))
143362306a36Sopenharmony_ci		config->dmic.fifo_bits_b = config->dmic.fifo_bits;
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	dai->number_configs = 1;
143662306a36Sopenharmony_ci	dai->current_config = 0;
143762306a36Sopenharmony_ci	private->dai_config = kmemdup(config, size, GFP_KERNEL);
143862306a36Sopenharmony_ci	if (!private->dai_config)
143962306a36Sopenharmony_ci		return -ENOMEM;
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	return 0;
144262306a36Sopenharmony_ci}
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_cistatic int sof_link_alh_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
144562306a36Sopenharmony_ci			     struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
144662306a36Sopenharmony_ci{
144762306a36Sopenharmony_ci	struct sof_dai_private_data *private = dai->private;
144862306a36Sopenharmony_ci	u32 size = sizeof(*config);
144962306a36Sopenharmony_ci	int ret;
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	/* parse the required set of ALH tokens based on num_hw_cfgs */
145262306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, &config->alh, SOF_ALH_TOKENS, slink->tuples,
145362306a36Sopenharmony_ci				    slink->num_tuples, size, slink->num_hw_configs);
145462306a36Sopenharmony_ci	if (ret < 0)
145562306a36Sopenharmony_ci		return ret;
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	/* init IPC */
145862306a36Sopenharmony_ci	config->hdr.size = size;
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	/* set config for all DAI's with name matching the link name */
146162306a36Sopenharmony_ci	dai->number_configs = 1;
146262306a36Sopenharmony_ci	dai->current_config = 0;
146362306a36Sopenharmony_ci	private->dai_config = kmemdup(config, size, GFP_KERNEL);
146462306a36Sopenharmony_ci	if (!private->dai_config)
146562306a36Sopenharmony_ci		return -ENOMEM;
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	return 0;
146862306a36Sopenharmony_ci}
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_cistatic int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget)
147162306a36Sopenharmony_ci{
147262306a36Sopenharmony_ci	struct snd_soc_component *scomp = swidget->scomp;
147362306a36Sopenharmony_ci	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
147462306a36Sopenharmony_ci	struct snd_sof_dai *dai = swidget->private;
147562306a36Sopenharmony_ci	struct sof_dai_private_data *private;
147662306a36Sopenharmony_ci	struct sof_ipc_comp_dai *comp_dai;
147762306a36Sopenharmony_ci	size_t ipc_size = sizeof(*comp_dai);
147862306a36Sopenharmony_ci	struct sof_ipc_dai_config *config;
147962306a36Sopenharmony_ci	struct snd_sof_dai_link *slink;
148062306a36Sopenharmony_ci	int ret;
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci	private = kzalloc(sizeof(*private), GFP_KERNEL);
148362306a36Sopenharmony_ci	if (!private)
148462306a36Sopenharmony_ci		return -ENOMEM;
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	dai->private = private;
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	private->comp_dai = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
148962306a36Sopenharmony_ci	if (!private->comp_dai) {
149062306a36Sopenharmony_ci		ret = -ENOMEM;
149162306a36Sopenharmony_ci		goto free;
149262306a36Sopenharmony_ci	}
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	/* configure dai IPC message */
149562306a36Sopenharmony_ci	comp_dai = private->comp_dai;
149662306a36Sopenharmony_ci	comp_dai->comp.type = SOF_COMP_DAI;
149762306a36Sopenharmony_ci	comp_dai->config.hdr.size = sizeof(comp_dai->config);
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci	/* parse one set of DAI tokens */
150062306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, comp_dai, SOF_DAI_TOKENS, swidget->tuples,
150162306a36Sopenharmony_ci				    swidget->num_tuples, sizeof(*comp_dai), 1);
150262306a36Sopenharmony_ci	if (ret < 0)
150362306a36Sopenharmony_ci		goto free;
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	/* update comp_tokens */
150662306a36Sopenharmony_ci	ret = sof_update_ipc_object(scomp, &comp_dai->config, SOF_COMP_TOKENS,
150762306a36Sopenharmony_ci				    swidget->tuples, swidget->num_tuples,
150862306a36Sopenharmony_ci				    sizeof(comp_dai->config), 1);
150962306a36Sopenharmony_ci	if (ret < 0)
151062306a36Sopenharmony_ci		goto free;
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci	dev_dbg(scomp->dev, "dai %s: type %d index %d\n",
151362306a36Sopenharmony_ci		swidget->widget->name, comp_dai->type, comp_dai->dai_index);
151462306a36Sopenharmony_ci	sof_dbg_comp_config(scomp, &comp_dai->config);
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	/* now update DAI config */
151762306a36Sopenharmony_ci	list_for_each_entry(slink, &sdev->dai_link_list, list) {
151862306a36Sopenharmony_ci		struct sof_ipc_dai_config common_config;
151962306a36Sopenharmony_ci		int i;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci		if (strcmp(slink->link->name, dai->name))
152262306a36Sopenharmony_ci			continue;
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci		/* Reserve memory for all hw configs, eventually freed by widget */
152562306a36Sopenharmony_ci		config = kcalloc(slink->num_hw_configs, sizeof(*config), GFP_KERNEL);
152662306a36Sopenharmony_ci		if (!config) {
152762306a36Sopenharmony_ci			ret = -ENOMEM;
152862306a36Sopenharmony_ci			goto free_comp;
152962306a36Sopenharmony_ci		}
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci		/* parse one set of DAI link tokens */
153262306a36Sopenharmony_ci		ret = sof_update_ipc_object(scomp, &common_config, SOF_DAI_LINK_TOKENS,
153362306a36Sopenharmony_ci					    slink->tuples, slink->num_tuples,
153462306a36Sopenharmony_ci					    sizeof(common_config), 1);
153562306a36Sopenharmony_ci		if (ret < 0)
153662306a36Sopenharmony_ci			goto free_config;
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci		for (i = 0; i < slink->num_hw_configs; i++) {
153962306a36Sopenharmony_ci			config[i].hdr.cmd = SOF_IPC_GLB_DAI_MSG | SOF_IPC_DAI_CONFIG;
154062306a36Sopenharmony_ci			config[i].format = le32_to_cpu(slink->hw_configs[i].fmt);
154162306a36Sopenharmony_ci			config[i].type = common_config.type;
154262306a36Sopenharmony_ci			config[i].dai_index = comp_dai->dai_index;
154362306a36Sopenharmony_ci		}
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci		switch (common_config.type) {
154662306a36Sopenharmony_ci		case SOF_DAI_INTEL_SSP:
154762306a36Sopenharmony_ci			ret = sof_link_ssp_load(scomp, slink, config, dai);
154862306a36Sopenharmony_ci			break;
154962306a36Sopenharmony_ci		case SOF_DAI_INTEL_DMIC:
155062306a36Sopenharmony_ci			ret = sof_link_dmic_load(scomp, slink, config, dai);
155162306a36Sopenharmony_ci			break;
155262306a36Sopenharmony_ci		case SOF_DAI_INTEL_HDA:
155362306a36Sopenharmony_ci			ret = sof_link_hda_load(scomp, slink, config, dai);
155462306a36Sopenharmony_ci			break;
155562306a36Sopenharmony_ci		case SOF_DAI_INTEL_ALH:
155662306a36Sopenharmony_ci			ret = sof_link_alh_load(scomp, slink, config, dai);
155762306a36Sopenharmony_ci			break;
155862306a36Sopenharmony_ci		case SOF_DAI_IMX_SAI:
155962306a36Sopenharmony_ci			ret = sof_link_sai_load(scomp, slink, config, dai);
156062306a36Sopenharmony_ci			break;
156162306a36Sopenharmony_ci		case SOF_DAI_IMX_ESAI:
156262306a36Sopenharmony_ci			ret = sof_link_esai_load(scomp, slink, config, dai);
156362306a36Sopenharmony_ci			break;
156462306a36Sopenharmony_ci		case SOF_DAI_AMD_BT:
156562306a36Sopenharmony_ci			ret = sof_link_acp_bt_load(scomp, slink, config, dai);
156662306a36Sopenharmony_ci			break;
156762306a36Sopenharmony_ci		case SOF_DAI_AMD_SP:
156862306a36Sopenharmony_ci		case SOF_DAI_AMD_SP_VIRTUAL:
156962306a36Sopenharmony_ci			ret = sof_link_acp_sp_load(scomp, slink, config, dai);
157062306a36Sopenharmony_ci			break;
157162306a36Sopenharmony_ci		case SOF_DAI_AMD_HS:
157262306a36Sopenharmony_ci		case SOF_DAI_AMD_HS_VIRTUAL:
157362306a36Sopenharmony_ci			ret = sof_link_acp_hs_load(scomp, slink, config, dai);
157462306a36Sopenharmony_ci			break;
157562306a36Sopenharmony_ci		case SOF_DAI_AMD_DMIC:
157662306a36Sopenharmony_ci			ret = sof_link_acp_dmic_load(scomp, slink, config, dai);
157762306a36Sopenharmony_ci			break;
157862306a36Sopenharmony_ci		case SOF_DAI_MEDIATEK_AFE:
157962306a36Sopenharmony_ci			ret = sof_link_afe_load(scomp, slink, config, dai);
158062306a36Sopenharmony_ci			break;
158162306a36Sopenharmony_ci		default:
158262306a36Sopenharmony_ci			break;
158362306a36Sopenharmony_ci		}
158462306a36Sopenharmony_ci		if (ret < 0) {
158562306a36Sopenharmony_ci			dev_err(scomp->dev, "failed to load config for dai %s\n", dai->name);
158662306a36Sopenharmony_ci			goto free_config;
158762306a36Sopenharmony_ci		}
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci		kfree(config);
159062306a36Sopenharmony_ci	}
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	return 0;
159362306a36Sopenharmony_cifree_config:
159462306a36Sopenharmony_ci	kfree(config);
159562306a36Sopenharmony_cifree_comp:
159662306a36Sopenharmony_ci	kfree(comp_dai);
159762306a36Sopenharmony_cifree:
159862306a36Sopenharmony_ci	kfree(private);
159962306a36Sopenharmony_ci	dai->private = NULL;
160062306a36Sopenharmony_ci	return ret;
160162306a36Sopenharmony_ci}
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_cistatic void sof_ipc3_widget_free_comp_dai(struct snd_sof_widget *swidget)
160462306a36Sopenharmony_ci{
160562306a36Sopenharmony_ci	switch (swidget->id) {
160662306a36Sopenharmony_ci	case snd_soc_dapm_dai_in:
160762306a36Sopenharmony_ci	case snd_soc_dapm_dai_out:
160862306a36Sopenharmony_ci	{
160962306a36Sopenharmony_ci		struct snd_sof_dai *dai = swidget->private;
161062306a36Sopenharmony_ci		struct sof_dai_private_data *dai_data;
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci		if (!dai)
161362306a36Sopenharmony_ci			return;
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci		dai_data = dai->private;
161662306a36Sopenharmony_ci		if (dai_data) {
161762306a36Sopenharmony_ci			kfree(dai_data->comp_dai);
161862306a36Sopenharmony_ci			kfree(dai_data->dai_config);
161962306a36Sopenharmony_ci			kfree(dai_data);
162062306a36Sopenharmony_ci		}
162162306a36Sopenharmony_ci		kfree(dai);
162262306a36Sopenharmony_ci		break;
162362306a36Sopenharmony_ci	}
162462306a36Sopenharmony_ci	default:
162562306a36Sopenharmony_ci		break;
162662306a36Sopenharmony_ci	}
162762306a36Sopenharmony_ci}
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_cistatic int sof_ipc3_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
163062306a36Sopenharmony_ci{
163162306a36Sopenharmony_ci	struct sof_ipc_pipe_comp_connect connect;
163262306a36Sopenharmony_ci	int ret;
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	connect.hdr.size = sizeof(connect);
163562306a36Sopenharmony_ci	connect.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_CONNECT;
163662306a36Sopenharmony_ci	connect.source_id = sroute->src_widget->comp_id;
163762306a36Sopenharmony_ci	connect.sink_id = sroute->sink_widget->comp_id;
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	dev_dbg(sdev->dev, "setting up route %s -> %s\n",
164062306a36Sopenharmony_ci		sroute->src_widget->widget->name,
164162306a36Sopenharmony_ci		sroute->sink_widget->widget->name);
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci	/* send ipc */
164462306a36Sopenharmony_ci	ret = sof_ipc_tx_message_no_reply(sdev->ipc, &connect, sizeof(connect));
164562306a36Sopenharmony_ci	if (ret < 0)
164662306a36Sopenharmony_ci		dev_err(sdev->dev, "%s: route %s -> %s failed\n", __func__,
164762306a36Sopenharmony_ci			sroute->src_widget->widget->name, sroute->sink_widget->widget->name);
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci	return ret;
165062306a36Sopenharmony_ci}
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_cistatic int sof_ipc3_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
165362306a36Sopenharmony_ci{
165462306a36Sopenharmony_ci	struct sof_ipc_ctrl_data *cdata;
165562306a36Sopenharmony_ci	size_t priv_size_check;
165662306a36Sopenharmony_ci	int ret;
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci	if (scontrol->max_size < (sizeof(*cdata) + sizeof(struct sof_abi_hdr))) {
165962306a36Sopenharmony_ci		dev_err(sdev->dev, "%s: insufficient size for a bytes control: %zu.\n",
166062306a36Sopenharmony_ci			__func__, scontrol->max_size);
166162306a36Sopenharmony_ci		return -EINVAL;
166262306a36Sopenharmony_ci	}
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	if (scontrol->priv_size > scontrol->max_size - sizeof(*cdata)) {
166562306a36Sopenharmony_ci		dev_err(sdev->dev,
166662306a36Sopenharmony_ci			"%s: bytes data size %zu exceeds max %zu.\n", __func__,
166762306a36Sopenharmony_ci			scontrol->priv_size, scontrol->max_size - sizeof(*cdata));
166862306a36Sopenharmony_ci		return -EINVAL;
166962306a36Sopenharmony_ci	}
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci	scontrol->ipc_control_data = kzalloc(scontrol->max_size, GFP_KERNEL);
167262306a36Sopenharmony_ci	if (!scontrol->ipc_control_data)
167362306a36Sopenharmony_ci		return -ENOMEM;
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	scontrol->size = sizeof(struct sof_ipc_ctrl_data) + scontrol->priv_size;
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci	cdata = scontrol->ipc_control_data;
167862306a36Sopenharmony_ci	cdata->cmd = SOF_CTRL_CMD_BINARY;
167962306a36Sopenharmony_ci	cdata->index = scontrol->index;
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci	if (scontrol->priv_size > 0) {
168262306a36Sopenharmony_ci		memcpy(cdata->data, scontrol->priv, scontrol->priv_size);
168362306a36Sopenharmony_ci		kfree(scontrol->priv);
168462306a36Sopenharmony_ci		scontrol->priv = NULL;
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci		if (cdata->data->magic != SOF_ABI_MAGIC) {
168762306a36Sopenharmony_ci			dev_err(sdev->dev, "Wrong ABI magic 0x%08x.\n", cdata->data->magic);
168862306a36Sopenharmony_ci			ret = -EINVAL;
168962306a36Sopenharmony_ci			goto err;
169062306a36Sopenharmony_ci		}
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci		if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) {
169362306a36Sopenharmony_ci			dev_err(sdev->dev, "Incompatible ABI version 0x%08x.\n",
169462306a36Sopenharmony_ci				cdata->data->abi);
169562306a36Sopenharmony_ci			ret = -EINVAL;
169662306a36Sopenharmony_ci			goto err;
169762306a36Sopenharmony_ci		}
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci		priv_size_check = cdata->data->size + sizeof(struct sof_abi_hdr);
170062306a36Sopenharmony_ci		if (priv_size_check != scontrol->priv_size) {
170162306a36Sopenharmony_ci			dev_err(sdev->dev, "Conflict in bytes (%zu) vs. priv size (%zu).\n",
170262306a36Sopenharmony_ci				priv_size_check, scontrol->priv_size);
170362306a36Sopenharmony_ci			ret = -EINVAL;
170462306a36Sopenharmony_ci			goto err;
170562306a36Sopenharmony_ci		}
170662306a36Sopenharmony_ci	}
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci	return 0;
170962306a36Sopenharmony_cierr:
171062306a36Sopenharmony_ci	kfree(scontrol->ipc_control_data);
171162306a36Sopenharmony_ci	scontrol->ipc_control_data = NULL;
171262306a36Sopenharmony_ci	return ret;
171362306a36Sopenharmony_ci}
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_cistatic int sof_ipc3_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
171662306a36Sopenharmony_ci{
171762306a36Sopenharmony_ci	struct sof_ipc_ctrl_data *cdata;
171862306a36Sopenharmony_ci	int i;
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci	/* init the volume get/put data */
172162306a36Sopenharmony_ci	scontrol->size = struct_size(cdata, chanv, scontrol->num_channels);
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL);
172462306a36Sopenharmony_ci	if (!scontrol->ipc_control_data)
172562306a36Sopenharmony_ci		return -ENOMEM;
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	cdata = scontrol->ipc_control_data;
172862306a36Sopenharmony_ci	cdata->index = scontrol->index;
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci	/* set cmd for mixer control */
173162306a36Sopenharmony_ci	if (scontrol->max == 1) {
173262306a36Sopenharmony_ci		cdata->cmd = SOF_CTRL_CMD_SWITCH;
173362306a36Sopenharmony_ci		return 0;
173462306a36Sopenharmony_ci	}
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci	cdata->cmd = SOF_CTRL_CMD_VOLUME;
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_ci	/* set default volume values to 0dB in control */
173962306a36Sopenharmony_ci	for (i = 0; i < scontrol->num_channels; i++) {
174062306a36Sopenharmony_ci		cdata->chanv[i].channel = i;
174162306a36Sopenharmony_ci		cdata->chanv[i].value = VOL_ZERO_DB;
174262306a36Sopenharmony_ci	}
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci	return 0;
174562306a36Sopenharmony_ci}
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_cistatic int sof_ipc3_control_load_enum(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
174862306a36Sopenharmony_ci{
174962306a36Sopenharmony_ci	struct sof_ipc_ctrl_data *cdata;
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci	/* init the enum get/put data */
175262306a36Sopenharmony_ci	scontrol->size = struct_size(cdata, chanv, scontrol->num_channels);
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL);
175562306a36Sopenharmony_ci	if (!scontrol->ipc_control_data)
175662306a36Sopenharmony_ci		return -ENOMEM;
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci	cdata = scontrol->ipc_control_data;
175962306a36Sopenharmony_ci	cdata->index = scontrol->index;
176062306a36Sopenharmony_ci	cdata->cmd = SOF_CTRL_CMD_ENUM;
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci	return 0;
176362306a36Sopenharmony_ci}
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_cistatic int sof_ipc3_control_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
176662306a36Sopenharmony_ci{
176762306a36Sopenharmony_ci	switch (scontrol->info_type) {
176862306a36Sopenharmony_ci	case SND_SOC_TPLG_CTL_VOLSW:
176962306a36Sopenharmony_ci	case SND_SOC_TPLG_CTL_VOLSW_SX:
177062306a36Sopenharmony_ci	case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
177162306a36Sopenharmony_ci		return sof_ipc3_control_load_volume(sdev, scontrol);
177262306a36Sopenharmony_ci	case SND_SOC_TPLG_CTL_BYTES:
177362306a36Sopenharmony_ci		return sof_ipc3_control_load_bytes(sdev, scontrol);
177462306a36Sopenharmony_ci	case SND_SOC_TPLG_CTL_ENUM:
177562306a36Sopenharmony_ci	case SND_SOC_TPLG_CTL_ENUM_VALUE:
177662306a36Sopenharmony_ci		return sof_ipc3_control_load_enum(sdev, scontrol);
177762306a36Sopenharmony_ci	default:
177862306a36Sopenharmony_ci		break;
177962306a36Sopenharmony_ci	}
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ci	return 0;
178262306a36Sopenharmony_ci}
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_cistatic int sof_ipc3_control_free(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
178562306a36Sopenharmony_ci{
178662306a36Sopenharmony_ci	struct sof_ipc_free fcomp;
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	fcomp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_FREE;
178962306a36Sopenharmony_ci	fcomp.hdr.size = sizeof(fcomp);
179062306a36Sopenharmony_ci	fcomp.id = scontrol->comp_id;
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	/* send IPC to the DSP */
179362306a36Sopenharmony_ci	return sof_ipc_tx_message_no_reply(sdev->ipc, &fcomp, sizeof(fcomp));
179462306a36Sopenharmony_ci}
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci/* send pcm params ipc */
179762306a36Sopenharmony_cistatic int sof_ipc3_keyword_detect_pcm_params(struct snd_sof_widget *swidget, int dir)
179862306a36Sopenharmony_ci{
179962306a36Sopenharmony_ci	struct snd_soc_component *scomp = swidget->scomp;
180062306a36Sopenharmony_ci	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
180162306a36Sopenharmony_ci	struct snd_pcm_hw_params *params;
180262306a36Sopenharmony_ci	struct sof_ipc_pcm_params pcm;
180362306a36Sopenharmony_ci	struct snd_sof_pcm *spcm;
180462306a36Sopenharmony_ci	int ret;
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci	/* get runtime PCM params using widget's stream name */
180762306a36Sopenharmony_ci	spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname);
180862306a36Sopenharmony_ci	if (!spcm) {
180962306a36Sopenharmony_ci		dev_err(scomp->dev, "Cannot find PCM for %s\n", swidget->widget->name);
181062306a36Sopenharmony_ci		return -EINVAL;
181162306a36Sopenharmony_ci	}
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci	params = &spcm->params[dir];
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci	/* set IPC PCM params */
181662306a36Sopenharmony_ci	memset(&pcm, 0, sizeof(pcm));
181762306a36Sopenharmony_ci	pcm.hdr.size = sizeof(pcm);
181862306a36Sopenharmony_ci	pcm.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS;
181962306a36Sopenharmony_ci	pcm.comp_id = swidget->comp_id;
182062306a36Sopenharmony_ci	pcm.params.hdr.size = sizeof(pcm.params);
182162306a36Sopenharmony_ci	pcm.params.direction = dir;
182262306a36Sopenharmony_ci	pcm.params.sample_valid_bytes = params_width(params) >> 3;
182362306a36Sopenharmony_ci	pcm.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED;
182462306a36Sopenharmony_ci	pcm.params.rate = params_rate(params);
182562306a36Sopenharmony_ci	pcm.params.channels = params_channels(params);
182662306a36Sopenharmony_ci	pcm.params.host_period_bytes = params_period_bytes(params);
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci	/* set format */
182962306a36Sopenharmony_ci	switch (params_format(params)) {
183062306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_S16:
183162306a36Sopenharmony_ci		pcm.params.frame_fmt = SOF_IPC_FRAME_S16_LE;
183262306a36Sopenharmony_ci		break;
183362306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_S24:
183462306a36Sopenharmony_ci		pcm.params.frame_fmt = SOF_IPC_FRAME_S24_4LE;
183562306a36Sopenharmony_ci		break;
183662306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_S32:
183762306a36Sopenharmony_ci		pcm.params.frame_fmt = SOF_IPC_FRAME_S32_LE;
183862306a36Sopenharmony_ci		break;
183962306a36Sopenharmony_ci	default:
184062306a36Sopenharmony_ci		return -EINVAL;
184162306a36Sopenharmony_ci	}
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci	/* send IPC to the DSP */
184462306a36Sopenharmony_ci	ret = sof_ipc_tx_message_no_reply(sdev->ipc, &pcm, sizeof(pcm));
184562306a36Sopenharmony_ci	if (ret < 0)
184662306a36Sopenharmony_ci		dev_err(scomp->dev, "%s: PCM params failed for %s\n", __func__,
184762306a36Sopenharmony_ci			swidget->widget->name);
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci	return ret;
185062306a36Sopenharmony_ci}
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci /* send stream trigger ipc */
185362306a36Sopenharmony_cistatic int sof_ipc3_keyword_detect_trigger(struct snd_sof_widget *swidget, int cmd)
185462306a36Sopenharmony_ci{
185562306a36Sopenharmony_ci	struct snd_soc_component *scomp = swidget->scomp;
185662306a36Sopenharmony_ci	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
185762306a36Sopenharmony_ci	struct sof_ipc_stream stream;
185862306a36Sopenharmony_ci	int ret;
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci	/* set IPC stream params */
186162306a36Sopenharmony_ci	stream.hdr.size = sizeof(stream);
186262306a36Sopenharmony_ci	stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | cmd;
186362306a36Sopenharmony_ci	stream.comp_id = swidget->comp_id;
186462306a36Sopenharmony_ci
186562306a36Sopenharmony_ci	/* send IPC to the DSP */
186662306a36Sopenharmony_ci	ret = sof_ipc_tx_message_no_reply(sdev->ipc, &stream, sizeof(stream));
186762306a36Sopenharmony_ci	if (ret < 0)
186862306a36Sopenharmony_ci		dev_err(scomp->dev, "%s: Failed to trigger %s\n", __func__, swidget->widget->name);
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	return ret;
187162306a36Sopenharmony_ci}
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_cistatic int sof_ipc3_keyword_dapm_event(struct snd_soc_dapm_widget *w,
187462306a36Sopenharmony_ci				       struct snd_kcontrol *k, int event)
187562306a36Sopenharmony_ci{
187662306a36Sopenharmony_ci	struct snd_sof_widget *swidget = w->dobj.private;
187762306a36Sopenharmony_ci	struct snd_soc_component *scomp;
187862306a36Sopenharmony_ci	int stream = SNDRV_PCM_STREAM_CAPTURE;
187962306a36Sopenharmony_ci	struct snd_sof_pcm *spcm;
188062306a36Sopenharmony_ci	int ret = 0;
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci	if (!swidget)
188362306a36Sopenharmony_ci		return 0;
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci	scomp = swidget->scomp;
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci	dev_dbg(scomp->dev, "received event %d for widget %s\n",
188862306a36Sopenharmony_ci		event, w->name);
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci	/* get runtime PCM params using widget's stream name */
189162306a36Sopenharmony_ci	spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname);
189262306a36Sopenharmony_ci	if (!spcm) {
189362306a36Sopenharmony_ci		dev_err(scomp->dev, "%s: Cannot find PCM for %s\n", __func__,
189462306a36Sopenharmony_ci			swidget->widget->name);
189562306a36Sopenharmony_ci		return -EINVAL;
189662306a36Sopenharmony_ci	}
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	/* process events */
189962306a36Sopenharmony_ci	switch (event) {
190062306a36Sopenharmony_ci	case SND_SOC_DAPM_PRE_PMU:
190162306a36Sopenharmony_ci		if (spcm->stream[stream].suspend_ignored) {
190262306a36Sopenharmony_ci			dev_dbg(scomp->dev, "PRE_PMU event ignored, KWD pipeline is already RUNNING\n");
190362306a36Sopenharmony_ci			return 0;
190462306a36Sopenharmony_ci		}
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci		/* set pcm params */
190762306a36Sopenharmony_ci		ret = sof_ipc3_keyword_detect_pcm_params(swidget, stream);
190862306a36Sopenharmony_ci		if (ret < 0) {
190962306a36Sopenharmony_ci			dev_err(scomp->dev, "%s: Failed to set pcm params for widget %s\n",
191062306a36Sopenharmony_ci				__func__, swidget->widget->name);
191162306a36Sopenharmony_ci			break;
191262306a36Sopenharmony_ci		}
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_ci		/* start trigger */
191562306a36Sopenharmony_ci		ret = sof_ipc3_keyword_detect_trigger(swidget, SOF_IPC_STREAM_TRIG_START);
191662306a36Sopenharmony_ci		if (ret < 0)
191762306a36Sopenharmony_ci			dev_err(scomp->dev, "%s: Failed to trigger widget %s\n", __func__,
191862306a36Sopenharmony_ci				swidget->widget->name);
191962306a36Sopenharmony_ci		break;
192062306a36Sopenharmony_ci	case SND_SOC_DAPM_POST_PMD:
192162306a36Sopenharmony_ci		if (spcm->stream[stream].suspend_ignored) {
192262306a36Sopenharmony_ci			dev_dbg(scomp->dev,
192362306a36Sopenharmony_ci				"POST_PMD event ignored, KWD pipeline will remain RUNNING\n");
192462306a36Sopenharmony_ci			return 0;
192562306a36Sopenharmony_ci		}
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci		/* stop trigger */
192862306a36Sopenharmony_ci		ret = sof_ipc3_keyword_detect_trigger(swidget, SOF_IPC_STREAM_TRIG_STOP);
192962306a36Sopenharmony_ci		if (ret < 0)
193062306a36Sopenharmony_ci			dev_err(scomp->dev, "%s: Failed to trigger widget %s\n", __func__,
193162306a36Sopenharmony_ci				swidget->widget->name);
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_ci		/* pcm free */
193462306a36Sopenharmony_ci		ret = sof_ipc3_keyword_detect_trigger(swidget, SOF_IPC_STREAM_PCM_FREE);
193562306a36Sopenharmony_ci		if (ret < 0)
193662306a36Sopenharmony_ci			dev_err(scomp->dev, "%s: Failed to free PCM for widget %s\n", __func__,
193762306a36Sopenharmony_ci				swidget->widget->name);
193862306a36Sopenharmony_ci		break;
193962306a36Sopenharmony_ci	default:
194062306a36Sopenharmony_ci		break;
194162306a36Sopenharmony_ci	}
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci	return ret;
194462306a36Sopenharmony_ci}
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_ci/* event handlers for keyword detect component */
194762306a36Sopenharmony_cistatic const struct snd_soc_tplg_widget_events sof_kwd_events[] = {
194862306a36Sopenharmony_ci	{SOF_KEYWORD_DETECT_DAPM_EVENT, sof_ipc3_keyword_dapm_event},
194962306a36Sopenharmony_ci};
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_cistatic int sof_ipc3_widget_bind_event(struct snd_soc_component *scomp,
195262306a36Sopenharmony_ci				      struct snd_sof_widget *swidget, u16 event_type)
195362306a36Sopenharmony_ci{
195462306a36Sopenharmony_ci	struct sof_ipc_comp *ipc_comp;
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci	/* validate widget event type */
195762306a36Sopenharmony_ci	switch (event_type) {
195862306a36Sopenharmony_ci	case SOF_KEYWORD_DETECT_DAPM_EVENT:
195962306a36Sopenharmony_ci		/* only KEYWORD_DETECT comps should handle this */
196062306a36Sopenharmony_ci		if (swidget->id != snd_soc_dapm_effect)
196162306a36Sopenharmony_ci			break;
196262306a36Sopenharmony_ci
196362306a36Sopenharmony_ci		ipc_comp = swidget->private;
196462306a36Sopenharmony_ci		if (ipc_comp && ipc_comp->type != SOF_COMP_KEYWORD_DETECT)
196562306a36Sopenharmony_ci			break;
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci		/* bind event to keyword detect comp */
196862306a36Sopenharmony_ci		return snd_soc_tplg_widget_bind_event(swidget->widget, sof_kwd_events,
196962306a36Sopenharmony_ci						      ARRAY_SIZE(sof_kwd_events), event_type);
197062306a36Sopenharmony_ci	default:
197162306a36Sopenharmony_ci		break;
197262306a36Sopenharmony_ci	}
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_ci	dev_err(scomp->dev, "Invalid event type %d for widget %s\n", event_type,
197562306a36Sopenharmony_ci		swidget->widget->name);
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci	return -EINVAL;
197862306a36Sopenharmony_ci}
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_cistatic int sof_ipc3_complete_pipeline(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
198162306a36Sopenharmony_ci{
198262306a36Sopenharmony_ci	struct sof_ipc_pipe_ready ready;
198362306a36Sopenharmony_ci	int ret;
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci	dev_dbg(sdev->dev, "tplg: complete pipeline %s id %d\n",
198662306a36Sopenharmony_ci		swidget->widget->name, swidget->comp_id);
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci	memset(&ready, 0, sizeof(ready));
198962306a36Sopenharmony_ci	ready.hdr.size = sizeof(ready);
199062306a36Sopenharmony_ci	ready.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_PIPE_COMPLETE;
199162306a36Sopenharmony_ci	ready.comp_id = swidget->comp_id;
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_ci	ret = sof_ipc_tx_message_no_reply(sdev->ipc, &ready, sizeof(ready));
199462306a36Sopenharmony_ci	if (ret < 0)
199562306a36Sopenharmony_ci		return ret;
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_ci	return 1;
199862306a36Sopenharmony_ci}
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_cistatic int sof_ipc3_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
200162306a36Sopenharmony_ci{
200262306a36Sopenharmony_ci	struct sof_ipc_free ipc_free = {
200362306a36Sopenharmony_ci		.hdr = {
200462306a36Sopenharmony_ci			.size = sizeof(ipc_free),
200562306a36Sopenharmony_ci			.cmd = SOF_IPC_GLB_TPLG_MSG,
200662306a36Sopenharmony_ci		},
200762306a36Sopenharmony_ci		.id = swidget->comp_id,
200862306a36Sopenharmony_ci	};
200962306a36Sopenharmony_ci	int ret;
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_ci	if (!swidget->private)
201262306a36Sopenharmony_ci		return 0;
201362306a36Sopenharmony_ci
201462306a36Sopenharmony_ci	switch (swidget->id) {
201562306a36Sopenharmony_ci	case snd_soc_dapm_scheduler:
201662306a36Sopenharmony_ci	{
201762306a36Sopenharmony_ci		ipc_free.hdr.cmd |= SOF_IPC_TPLG_PIPE_FREE;
201862306a36Sopenharmony_ci		break;
201962306a36Sopenharmony_ci	}
202062306a36Sopenharmony_ci	case snd_soc_dapm_buffer:
202162306a36Sopenharmony_ci		ipc_free.hdr.cmd |= SOF_IPC_TPLG_BUFFER_FREE;
202262306a36Sopenharmony_ci		break;
202362306a36Sopenharmony_ci	default:
202462306a36Sopenharmony_ci		ipc_free.hdr.cmd |= SOF_IPC_TPLG_COMP_FREE;
202562306a36Sopenharmony_ci		break;
202662306a36Sopenharmony_ci	}
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	ret = sof_ipc_tx_message_no_reply(sdev->ipc, &ipc_free, sizeof(ipc_free));
202962306a36Sopenharmony_ci	if (ret < 0)
203062306a36Sopenharmony_ci		dev_err(sdev->dev, "failed to free widget %s\n", swidget->widget->name);
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci	return ret;
203362306a36Sopenharmony_ci}
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_cistatic int sof_ipc3_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
203662306a36Sopenharmony_ci			       unsigned int flags, struct snd_sof_dai_config_data *data)
203762306a36Sopenharmony_ci{
203862306a36Sopenharmony_ci	struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
203962306a36Sopenharmony_ci	struct snd_sof_dai *dai = swidget->private;
204062306a36Sopenharmony_ci	struct sof_dai_private_data *private;
204162306a36Sopenharmony_ci	struct sof_ipc_dai_config *config;
204262306a36Sopenharmony_ci	int ret = 0;
204362306a36Sopenharmony_ci
204462306a36Sopenharmony_ci	if (!dai || !dai->private) {
204562306a36Sopenharmony_ci		dev_err(sdev->dev, "No private data for DAI %s\n", swidget->widget->name);
204662306a36Sopenharmony_ci		return -EINVAL;
204762306a36Sopenharmony_ci	}
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci	private = dai->private;
205062306a36Sopenharmony_ci	if (!private->dai_config) {
205162306a36Sopenharmony_ci		dev_err(sdev->dev, "No config for DAI %s\n", dai->name);
205262306a36Sopenharmony_ci		return -EINVAL;
205362306a36Sopenharmony_ci	}
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci	config = &private->dai_config[dai->current_config];
205662306a36Sopenharmony_ci	if (!config) {
205762306a36Sopenharmony_ci		dev_err(sdev->dev, "Invalid current config for DAI %s\n", dai->name);
205862306a36Sopenharmony_ci		return -EINVAL;
205962306a36Sopenharmony_ci	}
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci	switch (config->type) {
206262306a36Sopenharmony_ci	case SOF_DAI_INTEL_SSP:
206362306a36Sopenharmony_ci		/*
206462306a36Sopenharmony_ci		 * DAI_CONFIG IPC during hw_params/hw_free for SSP DAI's is not supported in older
206562306a36Sopenharmony_ci		 * firmware
206662306a36Sopenharmony_ci		 */
206762306a36Sopenharmony_ci		if (v->abi_version < SOF_ABI_VER(3, 18, 0) &&
206862306a36Sopenharmony_ci		    ((flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) ||
206962306a36Sopenharmony_ci		     (flags & SOF_DAI_CONFIG_FLAGS_HW_FREE)))
207062306a36Sopenharmony_ci			return 0;
207162306a36Sopenharmony_ci		break;
207262306a36Sopenharmony_ci	case SOF_DAI_INTEL_HDA:
207362306a36Sopenharmony_ci		if (data)
207462306a36Sopenharmony_ci			config->hda.link_dma_ch = data->dai_data;
207562306a36Sopenharmony_ci		break;
207662306a36Sopenharmony_ci	case SOF_DAI_INTEL_ALH:
207762306a36Sopenharmony_ci		if (data) {
207862306a36Sopenharmony_ci			/* save the dai_index during hw_params and reuse it for hw_free */
207962306a36Sopenharmony_ci			if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS)
208062306a36Sopenharmony_ci				config->dai_index = data->dai_index;
208162306a36Sopenharmony_ci			config->alh.stream_id = data->dai_data;
208262306a36Sopenharmony_ci		}
208362306a36Sopenharmony_ci		break;
208462306a36Sopenharmony_ci	default:
208562306a36Sopenharmony_ci		break;
208662306a36Sopenharmony_ci	}
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_ci	/*
208962306a36Sopenharmony_ci	 * The dai_config op is invoked several times and the flags argument varies as below:
209062306a36Sopenharmony_ci	 * BE DAI hw_params: When the op is invoked during the BE DAI hw_params, flags contains
209162306a36Sopenharmony_ci	 * SOF_DAI_CONFIG_FLAGS_HW_PARAMS along with quirks
209262306a36Sopenharmony_ci	 * FE DAI hw_params: When invoked during FE DAI hw_params after the DAI widget has
209362306a36Sopenharmony_ci	 * just been set up in the DSP, flags is set to SOF_DAI_CONFIG_FLAGS_HW_PARAMS with no
209462306a36Sopenharmony_ci	 * quirks
209562306a36Sopenharmony_ci	 * BE DAI trigger: When invoked during the BE DAI trigger, flags is set to
209662306a36Sopenharmony_ci	 * SOF_DAI_CONFIG_FLAGS_PAUSE and contains no quirks
209762306a36Sopenharmony_ci	 * BE DAI hw_free: When invoked during the BE DAI hw_free, flags is set to
209862306a36Sopenharmony_ci	 * SOF_DAI_CONFIG_FLAGS_HW_FREE and contains no quirks
209962306a36Sopenharmony_ci	 * FE DAI hw_free: When invoked during the FE DAI hw_free, flags is set to
210062306a36Sopenharmony_ci	 * SOF_DAI_CONFIG_FLAGS_HW_FREE and contains no quirks
210162306a36Sopenharmony_ci	 *
210262306a36Sopenharmony_ci	 * The DAI_CONFIG IPC is sent to the DSP, only after the widget is set up during the FE
210362306a36Sopenharmony_ci	 * DAI hw_params. But since the BE DAI hw_params precedes the FE DAI hw_params, the quirks
210462306a36Sopenharmony_ci	 * need to be preserved when assigning the flags before sending the IPC.
210562306a36Sopenharmony_ci	 * For the case of PAUSE/HW_FREE, since there are no quirks, flags can be used as is.
210662306a36Sopenharmony_ci	 */
210762306a36Sopenharmony_ci
210862306a36Sopenharmony_ci	if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) {
210962306a36Sopenharmony_ci		/* Clear stale command */
211062306a36Sopenharmony_ci		config->flags &= ~SOF_DAI_CONFIG_FLAGS_CMD_MASK;
211162306a36Sopenharmony_ci		config->flags |= flags;
211262306a36Sopenharmony_ci	} else {
211362306a36Sopenharmony_ci		config->flags = flags;
211462306a36Sopenharmony_ci	}
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci	/* only send the IPC if the widget is set up in the DSP */
211762306a36Sopenharmony_ci	if (swidget->use_count > 0) {
211862306a36Sopenharmony_ci		ret = sof_ipc_tx_message_no_reply(sdev->ipc, config, config->hdr.size);
211962306a36Sopenharmony_ci		if (ret < 0)
212062306a36Sopenharmony_ci			dev_err(sdev->dev, "Failed to set dai config for %s\n", dai->name);
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_ci		/* clear the flags once the IPC has been sent even if it fails */
212362306a36Sopenharmony_ci		config->flags = SOF_DAI_CONFIG_FLAGS_NONE;
212462306a36Sopenharmony_ci	}
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	return ret;
212762306a36Sopenharmony_ci}
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_cistatic int sof_ipc3_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
213062306a36Sopenharmony_ci{
213162306a36Sopenharmony_ci	int ret;
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_ci	if (!swidget->private)
213462306a36Sopenharmony_ci		return 0;
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_ci	switch (swidget->id) {
213762306a36Sopenharmony_ci	case snd_soc_dapm_dai_in:
213862306a36Sopenharmony_ci	case snd_soc_dapm_dai_out:
213962306a36Sopenharmony_ci	{
214062306a36Sopenharmony_ci		struct snd_sof_dai *dai = swidget->private;
214162306a36Sopenharmony_ci		struct sof_dai_private_data *dai_data = dai->private;
214262306a36Sopenharmony_ci		struct sof_ipc_comp *comp = &dai_data->comp_dai->comp;
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci		ret = sof_ipc_tx_message_no_reply(sdev->ipc, dai_data->comp_dai, comp->hdr.size);
214562306a36Sopenharmony_ci		break;
214662306a36Sopenharmony_ci	}
214762306a36Sopenharmony_ci	case snd_soc_dapm_scheduler:
214862306a36Sopenharmony_ci	{
214962306a36Sopenharmony_ci		struct sof_ipc_pipe_new *pipeline;
215062306a36Sopenharmony_ci
215162306a36Sopenharmony_ci		pipeline = swidget->private;
215262306a36Sopenharmony_ci		ret = sof_ipc_tx_message_no_reply(sdev->ipc, pipeline, sizeof(*pipeline));
215362306a36Sopenharmony_ci		break;
215462306a36Sopenharmony_ci	}
215562306a36Sopenharmony_ci	default:
215662306a36Sopenharmony_ci	{
215762306a36Sopenharmony_ci		struct sof_ipc_cmd_hdr *hdr;
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci		hdr = swidget->private;
216062306a36Sopenharmony_ci		ret = sof_ipc_tx_message_no_reply(sdev->ipc, swidget->private, hdr->size);
216162306a36Sopenharmony_ci		break;
216262306a36Sopenharmony_ci	}
216362306a36Sopenharmony_ci	}
216462306a36Sopenharmony_ci	if (ret < 0)
216562306a36Sopenharmony_ci		dev_err(sdev->dev, "Failed to setup widget %s\n", swidget->widget->name);
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_ci	return ret;
216862306a36Sopenharmony_ci}
216962306a36Sopenharmony_ci
217062306a36Sopenharmony_cistatic int sof_ipc3_set_up_all_pipelines(struct snd_sof_dev *sdev, bool verify)
217162306a36Sopenharmony_ci{
217262306a36Sopenharmony_ci	struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
217362306a36Sopenharmony_ci	struct snd_sof_widget *swidget;
217462306a36Sopenharmony_ci	struct snd_sof_route *sroute;
217562306a36Sopenharmony_ci	int ret;
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_ci	/* restore pipeline components */
217862306a36Sopenharmony_ci	list_for_each_entry(swidget, &sdev->widget_list, list) {
217962306a36Sopenharmony_ci		/* only set up the widgets belonging to static pipelines */
218062306a36Sopenharmony_ci		if (!verify && swidget->dynamic_pipeline_widget)
218162306a36Sopenharmony_ci			continue;
218262306a36Sopenharmony_ci
218362306a36Sopenharmony_ci		/*
218462306a36Sopenharmony_ci		 * For older firmware, skip scheduler widgets in this loop,
218562306a36Sopenharmony_ci		 * sof_widget_setup() will be called in the 'complete pipeline' loop
218662306a36Sopenharmony_ci		 */
218762306a36Sopenharmony_ci		if (v->abi_version < SOF_ABI_VER(3, 19, 0) &&
218862306a36Sopenharmony_ci		    swidget->id == snd_soc_dapm_scheduler)
218962306a36Sopenharmony_ci			continue;
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_ci		/* update DAI config. The IPC will be sent in sof_widget_setup() */
219262306a36Sopenharmony_ci		if (WIDGET_IS_DAI(swidget->id)) {
219362306a36Sopenharmony_ci			struct snd_sof_dai *dai = swidget->private;
219462306a36Sopenharmony_ci			struct sof_dai_private_data *private;
219562306a36Sopenharmony_ci			struct sof_ipc_dai_config *config;
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_ci			if (!dai || !dai->private)
219862306a36Sopenharmony_ci				continue;
219962306a36Sopenharmony_ci			private = dai->private;
220062306a36Sopenharmony_ci			if (!private->dai_config)
220162306a36Sopenharmony_ci				continue;
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_ci			config = private->dai_config;
220462306a36Sopenharmony_ci			/*
220562306a36Sopenharmony_ci			 * The link DMA channel would be invalidated for running
220662306a36Sopenharmony_ci			 * streams but not for streams that were in the PAUSED
220762306a36Sopenharmony_ci			 * state during suspend. So invalidate it here before setting
220862306a36Sopenharmony_ci			 * the dai config in the DSP.
220962306a36Sopenharmony_ci			 */
221062306a36Sopenharmony_ci			if (config->type == SOF_DAI_INTEL_HDA)
221162306a36Sopenharmony_ci				config->hda.link_dma_ch = DMA_CHAN_INVALID;
221262306a36Sopenharmony_ci		}
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci		ret = sof_widget_setup(sdev, swidget);
221562306a36Sopenharmony_ci		if (ret < 0)
221662306a36Sopenharmony_ci			return ret;
221762306a36Sopenharmony_ci	}
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	/* restore pipeline connections */
222062306a36Sopenharmony_ci	list_for_each_entry(sroute, &sdev->route_list, list) {
222162306a36Sopenharmony_ci		/* only set up routes belonging to static pipelines */
222262306a36Sopenharmony_ci		if (!verify && (sroute->src_widget->dynamic_pipeline_widget ||
222362306a36Sopenharmony_ci				sroute->sink_widget->dynamic_pipeline_widget))
222462306a36Sopenharmony_ci			continue;
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci		/*
222762306a36Sopenharmony_ci		 * For virtual routes, both sink and source are not buffer. IPC3 only supports
222862306a36Sopenharmony_ci		 * connections between a buffer and a component. Ignore the rest.
222962306a36Sopenharmony_ci		 */
223062306a36Sopenharmony_ci		if (sroute->src_widget->id != snd_soc_dapm_buffer &&
223162306a36Sopenharmony_ci		    sroute->sink_widget->id != snd_soc_dapm_buffer)
223262306a36Sopenharmony_ci			continue;
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci		ret = sof_route_setup(sdev, sroute->src_widget->widget,
223562306a36Sopenharmony_ci				      sroute->sink_widget->widget);
223662306a36Sopenharmony_ci		if (ret < 0) {
223762306a36Sopenharmony_ci			dev_err(sdev->dev, "%s: route set up failed\n", __func__);
223862306a36Sopenharmony_ci			return ret;
223962306a36Sopenharmony_ci		}
224062306a36Sopenharmony_ci	}
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_ci	/* complete pipeline */
224362306a36Sopenharmony_ci	list_for_each_entry(swidget, &sdev->widget_list, list) {
224462306a36Sopenharmony_ci		switch (swidget->id) {
224562306a36Sopenharmony_ci		case snd_soc_dapm_scheduler:
224662306a36Sopenharmony_ci			/* only complete static pipelines */
224762306a36Sopenharmony_ci			if (!verify && swidget->dynamic_pipeline_widget)
224862306a36Sopenharmony_ci				continue;
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci			if (v->abi_version < SOF_ABI_VER(3, 19, 0)) {
225162306a36Sopenharmony_ci				ret = sof_widget_setup(sdev, swidget);
225262306a36Sopenharmony_ci				if (ret < 0)
225362306a36Sopenharmony_ci					return ret;
225462306a36Sopenharmony_ci			}
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci			swidget->spipe->complete = sof_ipc3_complete_pipeline(sdev, swidget);
225762306a36Sopenharmony_ci			if (swidget->spipe->complete < 0)
225862306a36Sopenharmony_ci				return swidget->spipe->complete;
225962306a36Sopenharmony_ci			break;
226062306a36Sopenharmony_ci		default:
226162306a36Sopenharmony_ci			break;
226262306a36Sopenharmony_ci		}
226362306a36Sopenharmony_ci	}
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci	return 0;
226662306a36Sopenharmony_ci}
226762306a36Sopenharmony_ci
226862306a36Sopenharmony_ci/*
226962306a36Sopenharmony_ci * Free the PCM, its associated widgets and set the prepared flag to false for all PCMs that
227062306a36Sopenharmony_ci * did not get suspended(ex: paused streams) so the widgets can be set up again during resume.
227162306a36Sopenharmony_ci */
227262306a36Sopenharmony_cistatic int sof_tear_down_left_over_pipelines(struct snd_sof_dev *sdev)
227362306a36Sopenharmony_ci{
227462306a36Sopenharmony_ci	struct snd_sof_widget *swidget;
227562306a36Sopenharmony_ci	struct snd_sof_pcm *spcm;
227662306a36Sopenharmony_ci	int dir, ret;
227762306a36Sopenharmony_ci
227862306a36Sopenharmony_ci	/*
227962306a36Sopenharmony_ci	 * free all PCMs and their associated DAPM widgets if their connected DAPM widget
228062306a36Sopenharmony_ci	 * list is not NULL. This should only be true for paused streams at this point.
228162306a36Sopenharmony_ci	 * This is equivalent to the handling of FE DAI suspend trigger for running streams.
228262306a36Sopenharmony_ci	 */
228362306a36Sopenharmony_ci	list_for_each_entry(spcm, &sdev->pcm_list, list) {
228462306a36Sopenharmony_ci		for_each_pcm_streams(dir) {
228562306a36Sopenharmony_ci			struct snd_pcm_substream *substream = spcm->stream[dir].substream;
228662306a36Sopenharmony_ci
228762306a36Sopenharmony_ci			if (!substream || !substream->runtime || spcm->stream[dir].suspend_ignored)
228862306a36Sopenharmony_ci				continue;
228962306a36Sopenharmony_ci
229062306a36Sopenharmony_ci			if (spcm->stream[dir].list) {
229162306a36Sopenharmony_ci				ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true);
229262306a36Sopenharmony_ci				if (ret < 0)
229362306a36Sopenharmony_ci					return ret;
229462306a36Sopenharmony_ci			}
229562306a36Sopenharmony_ci		}
229662306a36Sopenharmony_ci	}
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_ci	/*
229962306a36Sopenharmony_ci	 * free any left over DAI widgets. This is equivalent to the handling of suspend trigger
230062306a36Sopenharmony_ci	 * for the BE DAI for running streams.
230162306a36Sopenharmony_ci	 */
230262306a36Sopenharmony_ci	list_for_each_entry(swidget, &sdev->widget_list, list)
230362306a36Sopenharmony_ci		if (WIDGET_IS_DAI(swidget->id) && swidget->use_count == 1) {
230462306a36Sopenharmony_ci			ret = sof_widget_free(sdev, swidget);
230562306a36Sopenharmony_ci			if (ret < 0)
230662306a36Sopenharmony_ci				return ret;
230762306a36Sopenharmony_ci		}
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ci	return 0;
231062306a36Sopenharmony_ci}
231162306a36Sopenharmony_ci
231262306a36Sopenharmony_cistatic int sof_ipc3_free_widgets_in_list(struct snd_sof_dev *sdev, bool include_scheduler,
231362306a36Sopenharmony_ci					 bool *dyn_widgets, bool verify)
231462306a36Sopenharmony_ci{
231562306a36Sopenharmony_ci	struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
231662306a36Sopenharmony_ci	struct snd_sof_widget *swidget;
231762306a36Sopenharmony_ci	int ret;
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci	list_for_each_entry(swidget, &sdev->widget_list, list) {
232062306a36Sopenharmony_ci		if (swidget->dynamic_pipeline_widget) {
232162306a36Sopenharmony_ci			*dyn_widgets = true;
232262306a36Sopenharmony_ci			continue;
232362306a36Sopenharmony_ci		}
232462306a36Sopenharmony_ci
232562306a36Sopenharmony_ci		/* Do not free widgets for static pipelines with FW older than SOF2.2 */
232662306a36Sopenharmony_ci		if (!verify && !swidget->dynamic_pipeline_widget &&
232762306a36Sopenharmony_ci		    SOF_FW_VER(v->major, v->minor, v->micro) < SOF_FW_VER(2, 2, 0)) {
232862306a36Sopenharmony_ci			mutex_lock(&swidget->setup_mutex);
232962306a36Sopenharmony_ci			swidget->use_count = 0;
233062306a36Sopenharmony_ci			mutex_unlock(&swidget->setup_mutex);
233162306a36Sopenharmony_ci			if (swidget->spipe)
233262306a36Sopenharmony_ci				swidget->spipe->complete = 0;
233362306a36Sopenharmony_ci			continue;
233462306a36Sopenharmony_ci		}
233562306a36Sopenharmony_ci
233662306a36Sopenharmony_ci		if (include_scheduler && swidget->id != snd_soc_dapm_scheduler)
233762306a36Sopenharmony_ci			continue;
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_ci		if (!include_scheduler && swidget->id == snd_soc_dapm_scheduler)
234062306a36Sopenharmony_ci			continue;
234162306a36Sopenharmony_ci
234262306a36Sopenharmony_ci		ret = sof_widget_free(sdev, swidget);
234362306a36Sopenharmony_ci		if (ret < 0)
234462306a36Sopenharmony_ci			return ret;
234562306a36Sopenharmony_ci	}
234662306a36Sopenharmony_ci
234762306a36Sopenharmony_ci	return 0;
234862306a36Sopenharmony_ci}
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ci/*
235162306a36Sopenharmony_ci * For older firmware, this function doesn't free widgets for static pipelines during suspend.
235262306a36Sopenharmony_ci * It only resets use_count for all widgets.
235362306a36Sopenharmony_ci */
235462306a36Sopenharmony_cistatic int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify)
235562306a36Sopenharmony_ci{
235662306a36Sopenharmony_ci	struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
235762306a36Sopenharmony_ci	struct snd_sof_widget *swidget;
235862306a36Sopenharmony_ci	struct snd_sof_route *sroute;
235962306a36Sopenharmony_ci	bool dyn_widgets = false;
236062306a36Sopenharmony_ci	int ret;
236162306a36Sopenharmony_ci
236262306a36Sopenharmony_ci	/*
236362306a36Sopenharmony_ci	 * This function is called during suspend and for one-time topology verification during
236462306a36Sopenharmony_ci	 * first boot. In both cases, there is no need to protect swidget->use_count and
236562306a36Sopenharmony_ci	 * sroute->setup because during suspend all running streams are suspended and during
236662306a36Sopenharmony_ci	 * topology loading the sound card unavailable to open PCMs. Do not free the scheduler
236762306a36Sopenharmony_ci	 * widgets yet so that the secondary cores do not get powered down before all the widgets
236862306a36Sopenharmony_ci	 * associated with the scheduler are freed.
236962306a36Sopenharmony_ci	 */
237062306a36Sopenharmony_ci	ret = sof_ipc3_free_widgets_in_list(sdev, false, &dyn_widgets, verify);
237162306a36Sopenharmony_ci	if (ret < 0)
237262306a36Sopenharmony_ci		return ret;
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_ci	/* free all the scheduler widgets now */
237562306a36Sopenharmony_ci	ret = sof_ipc3_free_widgets_in_list(sdev, true, &dyn_widgets, verify);
237662306a36Sopenharmony_ci	if (ret < 0)
237762306a36Sopenharmony_ci		return ret;
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci	/*
238062306a36Sopenharmony_ci	 * Tear down all pipelines associated with PCMs that did not get suspended
238162306a36Sopenharmony_ci	 * and unset the prepare flag so that they can be set up again during resume.
238262306a36Sopenharmony_ci	 * Skip this step for older firmware unless topology has any
238362306a36Sopenharmony_ci	 * dynamic pipeline (in which case the step is mandatory).
238462306a36Sopenharmony_ci	 */
238562306a36Sopenharmony_ci	if (!verify && (dyn_widgets || SOF_FW_VER(v->major, v->minor, v->micro) >=
238662306a36Sopenharmony_ci	    SOF_FW_VER(2, 2, 0))) {
238762306a36Sopenharmony_ci		ret = sof_tear_down_left_over_pipelines(sdev);
238862306a36Sopenharmony_ci		if (ret < 0) {
238962306a36Sopenharmony_ci			dev_err(sdev->dev, "failed to tear down paused pipelines\n");
239062306a36Sopenharmony_ci			return ret;
239162306a36Sopenharmony_ci		}
239262306a36Sopenharmony_ci	}
239362306a36Sopenharmony_ci
239462306a36Sopenharmony_ci	list_for_each_entry(sroute, &sdev->route_list, list)
239562306a36Sopenharmony_ci		sroute->setup = false;
239662306a36Sopenharmony_ci
239762306a36Sopenharmony_ci	/*
239862306a36Sopenharmony_ci	 * before suspending, make sure the refcounts are all zeroed out. There's no way
239962306a36Sopenharmony_ci	 * to recover at this point but this will help root cause bad sequences leading to
240062306a36Sopenharmony_ci	 * more issues on resume
240162306a36Sopenharmony_ci	 */
240262306a36Sopenharmony_ci	list_for_each_entry(swidget, &sdev->widget_list, list) {
240362306a36Sopenharmony_ci		if (swidget->use_count != 0) {
240462306a36Sopenharmony_ci			dev_err(sdev->dev, "%s: widget %s is still in use: count %d\n",
240562306a36Sopenharmony_ci				__func__, swidget->widget->name, swidget->use_count);
240662306a36Sopenharmony_ci		}
240762306a36Sopenharmony_ci	}
240862306a36Sopenharmony_ci
240962306a36Sopenharmony_ci	return 0;
241062306a36Sopenharmony_ci}
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_cistatic int sof_ipc3_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type)
241362306a36Sopenharmony_ci{
241462306a36Sopenharmony_ci	struct sof_dai_private_data *private = dai->private;
241562306a36Sopenharmony_ci
241662306a36Sopenharmony_ci	if (!private || !private->dai_config)
241762306a36Sopenharmony_ci		return 0;
241862306a36Sopenharmony_ci
241962306a36Sopenharmony_ci	switch (private->dai_config->type) {
242062306a36Sopenharmony_ci	case SOF_DAI_INTEL_SSP:
242162306a36Sopenharmony_ci		switch (clk_type) {
242262306a36Sopenharmony_ci		case SOF_DAI_CLK_INTEL_SSP_MCLK:
242362306a36Sopenharmony_ci			return private->dai_config->ssp.mclk_rate;
242462306a36Sopenharmony_ci		case SOF_DAI_CLK_INTEL_SSP_BCLK:
242562306a36Sopenharmony_ci			return private->dai_config->ssp.bclk_rate;
242662306a36Sopenharmony_ci		default:
242762306a36Sopenharmony_ci			break;
242862306a36Sopenharmony_ci		}
242962306a36Sopenharmony_ci		dev_err(sdev->dev, "fail to get SSP clk %d rate\n", clk_type);
243062306a36Sopenharmony_ci		break;
243162306a36Sopenharmony_ci	default:
243262306a36Sopenharmony_ci		/* not yet implemented for platforms other than the above */
243362306a36Sopenharmony_ci		dev_err(sdev->dev, "DAI type %d not supported yet!\n", private->dai_config->type);
243462306a36Sopenharmony_ci		break;
243562306a36Sopenharmony_ci	}
243662306a36Sopenharmony_ci
243762306a36Sopenharmony_ci	return -EINVAL;
243862306a36Sopenharmony_ci}
243962306a36Sopenharmony_ci
244062306a36Sopenharmony_cistatic int sof_ipc3_parse_manifest(struct snd_soc_component *scomp, int index,
244162306a36Sopenharmony_ci				   struct snd_soc_tplg_manifest *man)
244262306a36Sopenharmony_ci{
244362306a36Sopenharmony_ci	u32 size = le32_to_cpu(man->priv.size);
244462306a36Sopenharmony_ci	u32 abi_version;
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_ci	/* backward compatible with tplg without ABI info */
244762306a36Sopenharmony_ci	if (!size) {
244862306a36Sopenharmony_ci		dev_dbg(scomp->dev, "No topology ABI info\n");
244962306a36Sopenharmony_ci		return 0;
245062306a36Sopenharmony_ci	}
245162306a36Sopenharmony_ci
245262306a36Sopenharmony_ci	if (size != SOF_IPC3_TPLG_ABI_SIZE) {
245362306a36Sopenharmony_ci		dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n",
245462306a36Sopenharmony_ci			__func__, size);
245562306a36Sopenharmony_ci		return -EINVAL;
245662306a36Sopenharmony_ci	}
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_ci	dev_info(scomp->dev,
245962306a36Sopenharmony_ci		 "Topology: ABI %d:%d:%d Kernel ABI %d:%d:%d\n",
246062306a36Sopenharmony_ci		 man->priv.data[0], man->priv.data[1], man->priv.data[2],
246162306a36Sopenharmony_ci		 SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci	abi_version = SOF_ABI_VER(man->priv.data[0], man->priv.data[1], man->priv.data[2]);
246462306a36Sopenharmony_ci
246562306a36Sopenharmony_ci	if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, abi_version)) {
246662306a36Sopenharmony_ci		dev_err(scomp->dev, "%s: Incompatible topology ABI version\n", __func__);
246762306a36Sopenharmony_ci		return -EINVAL;
246862306a36Sopenharmony_ci	}
246962306a36Sopenharmony_ci
247062306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS) &&
247162306a36Sopenharmony_ci	    SOF_ABI_VERSION_MINOR(abi_version) > SOF_ABI_MINOR) {
247262306a36Sopenharmony_ci		dev_err(scomp->dev, "%s: Topology ABI is more recent than kernel\n", __func__);
247362306a36Sopenharmony_ci		return -EINVAL;
247462306a36Sopenharmony_ci	}
247562306a36Sopenharmony_ci
247662306a36Sopenharmony_ci	return 0;
247762306a36Sopenharmony_ci}
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_cistatic int sof_ipc3_link_setup(struct snd_sof_dev *sdev, struct snd_soc_dai_link *link)
248062306a36Sopenharmony_ci{
248162306a36Sopenharmony_ci	if (link->no_pcm)
248262306a36Sopenharmony_ci		return 0;
248362306a36Sopenharmony_ci
248462306a36Sopenharmony_ci	/*
248562306a36Sopenharmony_ci	 * set default trigger order for all links. Exceptions to
248662306a36Sopenharmony_ci	 * the rule will be handled in sof_pcm_dai_link_fixup()
248762306a36Sopenharmony_ci	 * For playback, the sequence is the following: start FE,
248862306a36Sopenharmony_ci	 * start BE, stop BE, stop FE; for Capture the sequence is
248962306a36Sopenharmony_ci	 * inverted start BE, start FE, stop FE, stop BE
249062306a36Sopenharmony_ci	 */
249162306a36Sopenharmony_ci	link->trigger[SNDRV_PCM_STREAM_PLAYBACK] = SND_SOC_DPCM_TRIGGER_PRE;
249262306a36Sopenharmony_ci	link->trigger[SNDRV_PCM_STREAM_CAPTURE] = SND_SOC_DPCM_TRIGGER_POST;
249362306a36Sopenharmony_ci
249462306a36Sopenharmony_ci	return 0;
249562306a36Sopenharmony_ci}
249662306a36Sopenharmony_ci
249762306a36Sopenharmony_ci/* token list for each topology object */
249862306a36Sopenharmony_cistatic enum sof_tokens host_token_list[] = {
249962306a36Sopenharmony_ci	SOF_CORE_TOKENS,
250062306a36Sopenharmony_ci	SOF_COMP_EXT_TOKENS,
250162306a36Sopenharmony_ci	SOF_PCM_TOKENS,
250262306a36Sopenharmony_ci	SOF_COMP_TOKENS,
250362306a36Sopenharmony_ci};
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_cistatic enum sof_tokens comp_generic_token_list[] = {
250662306a36Sopenharmony_ci	SOF_CORE_TOKENS,
250762306a36Sopenharmony_ci	SOF_COMP_EXT_TOKENS,
250862306a36Sopenharmony_ci	SOF_COMP_TOKENS,
250962306a36Sopenharmony_ci};
251062306a36Sopenharmony_ci
251162306a36Sopenharmony_cistatic enum sof_tokens buffer_token_list[] = {
251262306a36Sopenharmony_ci	SOF_BUFFER_TOKENS,
251362306a36Sopenharmony_ci};
251462306a36Sopenharmony_ci
251562306a36Sopenharmony_cistatic enum sof_tokens pipeline_token_list[] = {
251662306a36Sopenharmony_ci	SOF_CORE_TOKENS,
251762306a36Sopenharmony_ci	SOF_COMP_EXT_TOKENS,
251862306a36Sopenharmony_ci	SOF_PIPELINE_TOKENS,
251962306a36Sopenharmony_ci	SOF_SCHED_TOKENS,
252062306a36Sopenharmony_ci};
252162306a36Sopenharmony_ci
252262306a36Sopenharmony_cistatic enum sof_tokens asrc_token_list[] = {
252362306a36Sopenharmony_ci	SOF_CORE_TOKENS,
252462306a36Sopenharmony_ci	SOF_COMP_EXT_TOKENS,
252562306a36Sopenharmony_ci	SOF_ASRC_TOKENS,
252662306a36Sopenharmony_ci	SOF_COMP_TOKENS,
252762306a36Sopenharmony_ci};
252862306a36Sopenharmony_ci
252962306a36Sopenharmony_cistatic enum sof_tokens src_token_list[] = {
253062306a36Sopenharmony_ci	SOF_CORE_TOKENS,
253162306a36Sopenharmony_ci	SOF_COMP_EXT_TOKENS,
253262306a36Sopenharmony_ci	SOF_SRC_TOKENS,
253362306a36Sopenharmony_ci	SOF_COMP_TOKENS
253462306a36Sopenharmony_ci};
253562306a36Sopenharmony_ci
253662306a36Sopenharmony_cistatic enum sof_tokens pga_token_list[] = {
253762306a36Sopenharmony_ci	SOF_CORE_TOKENS,
253862306a36Sopenharmony_ci	SOF_COMP_EXT_TOKENS,
253962306a36Sopenharmony_ci	SOF_VOLUME_TOKENS,
254062306a36Sopenharmony_ci	SOF_COMP_TOKENS,
254162306a36Sopenharmony_ci};
254262306a36Sopenharmony_ci
254362306a36Sopenharmony_cistatic enum sof_tokens dai_token_list[] = {
254462306a36Sopenharmony_ci	SOF_CORE_TOKENS,
254562306a36Sopenharmony_ci	SOF_COMP_EXT_TOKENS,
254662306a36Sopenharmony_ci	SOF_DAI_TOKENS,
254762306a36Sopenharmony_ci	SOF_COMP_TOKENS,
254862306a36Sopenharmony_ci};
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_cistatic enum sof_tokens process_token_list[] = {
255162306a36Sopenharmony_ci	SOF_CORE_TOKENS,
255262306a36Sopenharmony_ci	SOF_COMP_EXT_TOKENS,
255362306a36Sopenharmony_ci	SOF_PROCESS_TOKENS,
255462306a36Sopenharmony_ci	SOF_COMP_TOKENS,
255562306a36Sopenharmony_ci};
255662306a36Sopenharmony_ci
255762306a36Sopenharmony_cistatic const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = {
255862306a36Sopenharmony_ci	[snd_soc_dapm_aif_in] =  {sof_ipc3_widget_setup_comp_host, sof_ipc3_widget_free_comp,
255962306a36Sopenharmony_ci				  host_token_list, ARRAY_SIZE(host_token_list), NULL},
256062306a36Sopenharmony_ci	[snd_soc_dapm_aif_out] = {sof_ipc3_widget_setup_comp_host, sof_ipc3_widget_free_comp,
256162306a36Sopenharmony_ci				  host_token_list, ARRAY_SIZE(host_token_list), NULL},
256262306a36Sopenharmony_ci
256362306a36Sopenharmony_ci	[snd_soc_dapm_dai_in] = {sof_ipc3_widget_setup_comp_dai, sof_ipc3_widget_free_comp_dai,
256462306a36Sopenharmony_ci				 dai_token_list, ARRAY_SIZE(dai_token_list), NULL},
256562306a36Sopenharmony_ci	[snd_soc_dapm_dai_out] = {sof_ipc3_widget_setup_comp_dai, sof_ipc3_widget_free_comp_dai,
256662306a36Sopenharmony_ci				  dai_token_list, ARRAY_SIZE(dai_token_list), NULL},
256762306a36Sopenharmony_ci	[snd_soc_dapm_buffer] = {sof_ipc3_widget_setup_comp_buffer, sof_ipc3_widget_free_comp,
256862306a36Sopenharmony_ci				 buffer_token_list, ARRAY_SIZE(buffer_token_list), NULL},
256962306a36Sopenharmony_ci	[snd_soc_dapm_mixer] = {sof_ipc3_widget_setup_comp_mixer, sof_ipc3_widget_free_comp,
257062306a36Sopenharmony_ci				comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list),
257162306a36Sopenharmony_ci				NULL},
257262306a36Sopenharmony_ci	[snd_soc_dapm_src] = {sof_ipc3_widget_setup_comp_src, sof_ipc3_widget_free_comp,
257362306a36Sopenharmony_ci			      src_token_list, ARRAY_SIZE(src_token_list), NULL},
257462306a36Sopenharmony_ci	[snd_soc_dapm_asrc] = {sof_ipc3_widget_setup_comp_asrc, sof_ipc3_widget_free_comp,
257562306a36Sopenharmony_ci			       asrc_token_list, ARRAY_SIZE(asrc_token_list), NULL},
257662306a36Sopenharmony_ci	[snd_soc_dapm_siggen] = {sof_ipc3_widget_setup_comp_tone, sof_ipc3_widget_free_comp,
257762306a36Sopenharmony_ci				 comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list),
257862306a36Sopenharmony_ci				 NULL},
257962306a36Sopenharmony_ci	[snd_soc_dapm_scheduler] = {sof_ipc3_widget_setup_comp_pipeline, sof_ipc3_widget_free_comp,
258062306a36Sopenharmony_ci				    pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL},
258162306a36Sopenharmony_ci	[snd_soc_dapm_pga] = {sof_ipc3_widget_setup_comp_pga, sof_ipc3_widget_free_comp,
258262306a36Sopenharmony_ci			      pga_token_list, ARRAY_SIZE(pga_token_list), NULL},
258362306a36Sopenharmony_ci	[snd_soc_dapm_mux] = {sof_ipc3_widget_setup_comp_mux, sof_ipc3_widget_free_comp,
258462306a36Sopenharmony_ci			      comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list), NULL},
258562306a36Sopenharmony_ci	[snd_soc_dapm_demux] = {sof_ipc3_widget_setup_comp_mux, sof_ipc3_widget_free_comp,
258662306a36Sopenharmony_ci				 comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list),
258762306a36Sopenharmony_ci				 NULL},
258862306a36Sopenharmony_ci	[snd_soc_dapm_effect] = {sof_widget_update_ipc_comp_process, sof_ipc3_widget_free_comp,
258962306a36Sopenharmony_ci				 process_token_list, ARRAY_SIZE(process_token_list),
259062306a36Sopenharmony_ci				 sof_ipc3_widget_bind_event},
259162306a36Sopenharmony_ci};
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_ciconst struct sof_ipc_tplg_ops ipc3_tplg_ops = {
259462306a36Sopenharmony_ci	.widget = tplg_ipc3_widget_ops,
259562306a36Sopenharmony_ci	.control = &tplg_ipc3_control_ops,
259662306a36Sopenharmony_ci	.route_setup = sof_ipc3_route_setup,
259762306a36Sopenharmony_ci	.control_setup = sof_ipc3_control_setup,
259862306a36Sopenharmony_ci	.control_free = sof_ipc3_control_free,
259962306a36Sopenharmony_ci	.pipeline_complete = sof_ipc3_complete_pipeline,
260062306a36Sopenharmony_ci	.token_list = ipc3_token_list,
260162306a36Sopenharmony_ci	.widget_free = sof_ipc3_widget_free,
260262306a36Sopenharmony_ci	.widget_setup = sof_ipc3_widget_setup,
260362306a36Sopenharmony_ci	.dai_config = sof_ipc3_dai_config,
260462306a36Sopenharmony_ci	.dai_get_clk = sof_ipc3_dai_get_clk,
260562306a36Sopenharmony_ci	.set_up_all_pipelines = sof_ipc3_set_up_all_pipelines,
260662306a36Sopenharmony_ci	.tear_down_all_pipelines = sof_ipc3_tear_down_all_pipelines,
260762306a36Sopenharmony_ci	.parse_manifest = sof_ipc3_parse_manifest,
260862306a36Sopenharmony_ci	.link_setup = sof_ipc3_link_setup,
260962306a36Sopenharmony_ci};
2610