cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ipc3-topology.c (74190B)


      1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
      2//
      3// This file is provided under a dual BSD/GPLv2 license.  When using or
      4// redistributing this file, you may do so under either license.
      5//
      6// Copyright(c) 2021 Intel Corporation. All rights reserved.
      7//
      8//
      9
     10#include <uapi/sound/sof/tokens.h>
     11#include <sound/pcm_params.h>
     12#include "sof-priv.h"
     13#include "sof-audio.h"
     14#include "ipc3-priv.h"
     15#include "ops.h"
     16
     17/* Full volume for default values */
     18#define VOL_ZERO_DB	BIT(VOLUME_FWL)
     19
     20struct sof_widget_data {
     21	int ctrl_type;
     22	int ipc_cmd;
     23	void *pdata;
     24	size_t pdata_size;
     25	struct snd_sof_control *control;
     26};
     27
     28struct sof_process_types {
     29	const char *name;
     30	enum sof_ipc_process_type type;
     31	enum sof_comp_type comp_type;
     32};
     33
     34static const struct sof_process_types sof_process[] = {
     35	{"EQFIR", SOF_PROCESS_EQFIR, SOF_COMP_EQ_FIR},
     36	{"EQIIR", SOF_PROCESS_EQIIR, SOF_COMP_EQ_IIR},
     37	{"KEYWORD_DETECT", SOF_PROCESS_KEYWORD_DETECT, SOF_COMP_KEYWORD_DETECT},
     38	{"KPB", SOF_PROCESS_KPB, SOF_COMP_KPB},
     39	{"CHAN_SELECTOR", SOF_PROCESS_CHAN_SELECTOR, SOF_COMP_SELECTOR},
     40	{"MUX", SOF_PROCESS_MUX, SOF_COMP_MUX},
     41	{"DEMUX", SOF_PROCESS_DEMUX, SOF_COMP_DEMUX},
     42	{"DCBLOCK", SOF_PROCESS_DCBLOCK, SOF_COMP_DCBLOCK},
     43	{"SMART_AMP", SOF_PROCESS_SMART_AMP, SOF_COMP_SMART_AMP},
     44};
     45
     46static enum sof_ipc_process_type find_process(const char *name)
     47{
     48	int i;
     49
     50	for (i = 0; i < ARRAY_SIZE(sof_process); i++) {
     51		if (strcmp(name, sof_process[i].name) == 0)
     52			return sof_process[i].type;
     53	}
     54
     55	return SOF_PROCESS_NONE;
     56}
     57
     58static int get_token_process_type(void *elem, void *object, u32 offset)
     59{
     60	u32 *val = (u32 *)((u8 *)object + offset);
     61
     62	*val = find_process((const char *)elem);
     63	return 0;
     64}
     65
     66/* Buffers */
     67static const struct sof_topology_token buffer_tokens[] = {
     68	{SOF_TKN_BUF_SIZE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
     69		offsetof(struct sof_ipc_buffer, size)},
     70	{SOF_TKN_BUF_CAPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
     71		offsetof(struct sof_ipc_buffer, caps)},
     72};
     73
     74/* DAI */
     75static const struct sof_topology_token dai_tokens[] = {
     76	{SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type,
     77		offsetof(struct sof_ipc_comp_dai, type)},
     78	{SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
     79		offsetof(struct sof_ipc_comp_dai, dai_index)},
     80	{SOF_TKN_DAI_DIRECTION, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
     81		offsetof(struct sof_ipc_comp_dai, direction)},
     82};
     83
     84/* BE DAI link */
     85static const struct sof_topology_token dai_link_tokens[] = {
     86	{SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type,
     87		offsetof(struct sof_ipc_dai_config, type)},
     88	{SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
     89		offsetof(struct sof_ipc_dai_config, dai_index)},
     90};
     91
     92/* scheduling */
     93static const struct sof_topology_token sched_tokens[] = {
     94	{SOF_TKN_SCHED_PERIOD, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
     95		offsetof(struct sof_ipc_pipe_new, period)},
     96	{SOF_TKN_SCHED_PRIORITY, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
     97		offsetof(struct sof_ipc_pipe_new, priority)},
     98	{SOF_TKN_SCHED_MIPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
     99		offsetof(struct sof_ipc_pipe_new, period_mips)},
    100	{SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    101		offsetof(struct sof_ipc_pipe_new, core)},
    102	{SOF_TKN_SCHED_FRAMES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    103		offsetof(struct sof_ipc_pipe_new, frames_per_sched)},
    104	{SOF_TKN_SCHED_TIME_DOMAIN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    105		offsetof(struct sof_ipc_pipe_new, time_domain)},
    106};
    107
    108static const struct sof_topology_token pipeline_tokens[] = {
    109	{SOF_TKN_SCHED_DYNAMIC_PIPELINE, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
    110		offsetof(struct snd_sof_widget, dynamic_pipeline_widget)},
    111
    112};
    113
    114/* volume */
    115static const struct sof_topology_token volume_tokens[] = {
    116	{SOF_TKN_VOLUME_RAMP_STEP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    117		offsetof(struct sof_ipc_comp_volume, ramp)},
    118	{SOF_TKN_VOLUME_RAMP_STEP_MS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    119		offsetof(struct sof_ipc_comp_volume, initial_ramp)},
    120};
    121
    122/* SRC */
    123static const struct sof_topology_token src_tokens[] = {
    124	{SOF_TKN_SRC_RATE_IN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    125		offsetof(struct sof_ipc_comp_src, source_rate)},
    126	{SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    127		offsetof(struct sof_ipc_comp_src, sink_rate)},
    128};
    129
    130/* ASRC */
    131static const struct sof_topology_token asrc_tokens[] = {
    132	{SOF_TKN_ASRC_RATE_IN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    133		offsetof(struct sof_ipc_comp_asrc, source_rate)},
    134	{SOF_TKN_ASRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    135		offsetof(struct sof_ipc_comp_asrc, sink_rate)},
    136	{SOF_TKN_ASRC_ASYNCHRONOUS_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    137		offsetof(struct sof_ipc_comp_asrc, asynchronous_mode)},
    138	{SOF_TKN_ASRC_OPERATION_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    139		offsetof(struct sof_ipc_comp_asrc, operation_mode)},
    140};
    141
    142/* EFFECT */
    143static const struct sof_topology_token process_tokens[] = {
    144	{SOF_TKN_PROCESS_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_process_type,
    145		offsetof(struct sof_ipc_comp_process, type)},
    146};
    147
    148/* PCM */
    149static const struct sof_topology_token pcm_tokens[] = {
    150	{SOF_TKN_PCM_DMAC_CONFIG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    151		offsetof(struct sof_ipc_comp_host, dmac_config)},
    152};
    153
    154/* Generic components */
    155static const struct sof_topology_token comp_tokens[] = {
    156	{SOF_TKN_COMP_PERIOD_SINK_COUNT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    157		offsetof(struct sof_ipc_comp_config, periods_sink)},
    158	{SOF_TKN_COMP_PERIOD_SOURCE_COUNT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    159		offsetof(struct sof_ipc_comp_config, periods_source)},
    160	{SOF_TKN_COMP_FORMAT,
    161		SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_format,
    162		offsetof(struct sof_ipc_comp_config, frame_fmt)},
    163};
    164
    165/* SSP */
    166static const struct sof_topology_token ssp_tokens[] = {
    167	{SOF_TKN_INTEL_SSP_CLKS_CONTROL, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    168		offsetof(struct sof_ipc_dai_ssp_params, clks_control)},
    169	{SOF_TKN_INTEL_SSP_MCLK_ID, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
    170		offsetof(struct sof_ipc_dai_ssp_params, mclk_id)},
    171	{SOF_TKN_INTEL_SSP_SAMPLE_BITS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    172		offsetof(struct sof_ipc_dai_ssp_params, sample_valid_bits)},
    173	{SOF_TKN_INTEL_SSP_FRAME_PULSE_WIDTH, SND_SOC_TPLG_TUPLE_TYPE_SHORT,	get_token_u16,
    174		offsetof(struct sof_ipc_dai_ssp_params, frame_pulse_width)},
    175	{SOF_TKN_INTEL_SSP_QUIRKS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    176		offsetof(struct sof_ipc_dai_ssp_params, quirks)},
    177	{SOF_TKN_INTEL_SSP_TDM_PADDING_PER_SLOT, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
    178		offsetof(struct sof_ipc_dai_ssp_params, tdm_per_slot_padding_flag)},
    179	{SOF_TKN_INTEL_SSP_BCLK_DELAY, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    180		offsetof(struct sof_ipc_dai_ssp_params, bclk_delay)},
    181};
    182
    183/* ALH */
    184static const struct sof_topology_token alh_tokens[] = {
    185	{SOF_TKN_INTEL_ALH_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    186		offsetof(struct sof_ipc_dai_alh_params, rate)},
    187	{SOF_TKN_INTEL_ALH_CH,	SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    188		offsetof(struct sof_ipc_dai_alh_params, channels)},
    189};
    190
    191/* DMIC */
    192static const struct sof_topology_token dmic_tokens[] = {
    193	{SOF_TKN_INTEL_DMIC_DRIVER_VERSION, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    194		offsetof(struct sof_ipc_dai_dmic_params, driver_ipc_version)},
    195	{SOF_TKN_INTEL_DMIC_CLK_MIN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    196		offsetof(struct sof_ipc_dai_dmic_params, pdmclk_min)},
    197	{SOF_TKN_INTEL_DMIC_CLK_MAX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    198		offsetof(struct sof_ipc_dai_dmic_params, pdmclk_max)},
    199	{SOF_TKN_INTEL_DMIC_SAMPLE_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    200		offsetof(struct sof_ipc_dai_dmic_params, fifo_fs)},
    201	{SOF_TKN_INTEL_DMIC_DUTY_MIN, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
    202		offsetof(struct sof_ipc_dai_dmic_params, duty_min)},
    203	{SOF_TKN_INTEL_DMIC_DUTY_MAX, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
    204		offsetof(struct sof_ipc_dai_dmic_params, duty_max)},
    205	{SOF_TKN_INTEL_DMIC_NUM_PDM_ACTIVE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    206		offsetof(struct sof_ipc_dai_dmic_params, num_pdm_active)},
    207	{SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
    208		offsetof(struct sof_ipc_dai_dmic_params, fifo_bits)},
    209	{SOF_TKN_INTEL_DMIC_UNMUTE_RAMP_TIME_MS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    210		offsetof(struct sof_ipc_dai_dmic_params, unmute_ramp_time)},
    211};
    212
    213/* ESAI */
    214static const struct sof_topology_token esai_tokens[] = {
    215	{SOF_TKN_IMX_ESAI_MCLK_ID, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
    216		offsetof(struct sof_ipc_dai_esai_params, mclk_id)},
    217};
    218
    219/* SAI */
    220static const struct sof_topology_token sai_tokens[] = {
    221	{SOF_TKN_IMX_SAI_MCLK_ID, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
    222		offsetof(struct sof_ipc_dai_sai_params, mclk_id)},
    223};
    224
    225/*
    226 * DMIC PDM Tokens
    227 * SOF_TKN_INTEL_DMIC_PDM_CTRL_ID should be the first token
    228 * as it increments the index while parsing the array of pdm tokens
    229 * and determines the correct offset
    230 */
    231static const struct sof_topology_token dmic_pdm_tokens[] = {
    232	{SOF_TKN_INTEL_DMIC_PDM_CTRL_ID, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
    233		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, id)},
    234	{SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
    235		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, enable_mic_a)},
    236	{SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
    237		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, enable_mic_b)},
    238	{SOF_TKN_INTEL_DMIC_PDM_POLARITY_A, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
    239		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, polarity_mic_a)},
    240	{SOF_TKN_INTEL_DMIC_PDM_POLARITY_B, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
    241		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, polarity_mic_b)},
    242	{SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
    243		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, clk_edge)},
    244	{SOF_TKN_INTEL_DMIC_PDM_SKEW, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
    245		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, skew)},
    246};
    247
    248/* HDA */
    249static const struct sof_topology_token hda_tokens[] = {
    250	{SOF_TKN_INTEL_HDA_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    251		offsetof(struct sof_ipc_dai_hda_params, rate)},
    252	{SOF_TKN_INTEL_HDA_CH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    253		offsetof(struct sof_ipc_dai_hda_params, channels)},
    254};
    255
    256/* AFE */
    257static const struct sof_topology_token afe_tokens[] = {
    258	{SOF_TKN_MEDIATEK_AFE_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    259		offsetof(struct sof_ipc_dai_mtk_afe_params, rate)},
    260	{SOF_TKN_MEDIATEK_AFE_CH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    261		offsetof(struct sof_ipc_dai_mtk_afe_params, channels)},
    262	{SOF_TKN_MEDIATEK_AFE_FORMAT, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_format,
    263		offsetof(struct sof_ipc_dai_mtk_afe_params, format)},
    264};
    265
    266/* Core tokens */
    267static const struct sof_topology_token core_tokens[] = {
    268	{SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
    269		offsetof(struct sof_ipc_comp, core)},
    270};
    271
    272/* Component extended tokens */
    273static const struct sof_topology_token comp_ext_tokens[] = {
    274	{SOF_TKN_COMP_UUID, SND_SOC_TPLG_TUPLE_TYPE_UUID, get_token_uuid,
    275		offsetof(struct snd_sof_widget, uuid)},
    276};
    277
    278static const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = {
    279	[SOF_PCM_TOKENS] = {"PCM tokens", pcm_tokens, ARRAY_SIZE(pcm_tokens)},
    280	[SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)},
    281	[SOF_SCHED_TOKENS] = {"Scheduler tokens", sched_tokens, ARRAY_SIZE(sched_tokens)},
    282	[SOF_COMP_TOKENS] = {"Comp tokens", comp_tokens, ARRAY_SIZE(comp_tokens)},
    283	[SOF_CORE_TOKENS] = {"Core tokens", core_tokens, ARRAY_SIZE(core_tokens)},
    284	[SOF_COMP_EXT_TOKENS] = {"AFE tokens", comp_ext_tokens, ARRAY_SIZE(comp_ext_tokens)},
    285	[SOF_BUFFER_TOKENS] = {"Buffer tokens", buffer_tokens, ARRAY_SIZE(buffer_tokens)},
    286	[SOF_VOLUME_TOKENS] = {"Volume tokens", volume_tokens, ARRAY_SIZE(volume_tokens)},
    287	[SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)},
    288	[SOF_ASRC_TOKENS] = {"ASRC tokens", asrc_tokens, ARRAY_SIZE(asrc_tokens)},
    289	[SOF_PROCESS_TOKENS] = {"Process tokens", process_tokens, ARRAY_SIZE(process_tokens)},
    290	[SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)},
    291	[SOF_DAI_LINK_TOKENS] = {"DAI link tokens", dai_link_tokens, ARRAY_SIZE(dai_link_tokens)},
    292	[SOF_HDA_TOKENS] = {"HDA tokens", hda_tokens, ARRAY_SIZE(hda_tokens)},
    293	[SOF_SSP_TOKENS] = {"SSP tokens", ssp_tokens, ARRAY_SIZE(ssp_tokens)},
    294	[SOF_ALH_TOKENS] = {"ALH tokens", alh_tokens, ARRAY_SIZE(alh_tokens)},
    295	[SOF_DMIC_TOKENS] = {"DMIC tokens", dmic_tokens, ARRAY_SIZE(dmic_tokens)},
    296	[SOF_DMIC_PDM_TOKENS] = {"DMIC PDM tokens", dmic_pdm_tokens, ARRAY_SIZE(dmic_pdm_tokens)},
    297	[SOF_ESAI_TOKENS] = {"ESAI tokens", esai_tokens, ARRAY_SIZE(esai_tokens)},
    298	[SOF_SAI_TOKENS] = {"SAI tokens", sai_tokens, ARRAY_SIZE(sai_tokens)},
    299	[SOF_AFE_TOKENS] = {"AFE tokens", afe_tokens, ARRAY_SIZE(afe_tokens)},
    300};
    301
    302/**
    303 * sof_comp_alloc - allocate and initialize buffer for a new component
    304 * @swidget: pointer to struct snd_sof_widget containing extended data
    305 * @ipc_size: IPC payload size that will be updated depending on valid
    306 *  extended data.
    307 * @index: ID of the pipeline the component belongs to
    308 *
    309 * Return: The pointer to the new allocated component, NULL if failed.
    310 */
    311static void *sof_comp_alloc(struct snd_sof_widget *swidget, size_t *ipc_size,
    312			    int index)
    313{
    314	struct sof_ipc_comp *comp;
    315	size_t total_size = *ipc_size;
    316	size_t ext_size = sizeof(swidget->uuid);
    317
    318	/* only non-zero UUID is valid */
    319	if (!guid_is_null(&swidget->uuid))
    320		total_size += ext_size;
    321
    322	comp = kzalloc(total_size, GFP_KERNEL);
    323	if (!comp)
    324		return NULL;
    325
    326	/* configure comp new IPC message */
    327	comp->hdr.size = total_size;
    328	comp->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW;
    329	comp->id = swidget->comp_id;
    330	comp->pipeline_id = index;
    331	comp->core = swidget->core;
    332
    333	/* handle the extended data if needed */
    334	if (total_size > *ipc_size) {
    335		/* append extended data to the end of the component */
    336		memcpy((u8 *)comp + *ipc_size, &swidget->uuid, ext_size);
    337		comp->ext_data_length = ext_size;
    338	}
    339
    340	/* update ipc_size and return */
    341	*ipc_size = total_size;
    342	return comp;
    343}
    344
    345static void sof_dbg_comp_config(struct snd_soc_component *scomp, struct sof_ipc_comp_config *config)
    346{
    347	dev_dbg(scomp->dev, " config: periods snk %d src %d fmt %d\n",
    348		config->periods_sink, config->periods_source,
    349		config->frame_fmt);
    350}
    351
    352static int sof_ipc3_widget_setup_comp_host(struct snd_sof_widget *swidget)
    353{
    354	struct snd_soc_component *scomp = swidget->scomp;
    355	struct sof_ipc_comp_host *host;
    356	size_t ipc_size = sizeof(*host);
    357	int ret;
    358
    359	host = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
    360	if (!host)
    361		return -ENOMEM;
    362	swidget->private = host;
    363
    364	/* configure host comp IPC message */
    365	host->comp.type = SOF_COMP_HOST;
    366	host->config.hdr.size = sizeof(host->config);
    367
    368	if (swidget->id == snd_soc_dapm_aif_out)
    369		host->direction = SOF_IPC_STREAM_CAPTURE;
    370	else
    371		host->direction = SOF_IPC_STREAM_PLAYBACK;
    372
    373	/* parse one set of pcm_tokens */
    374	ret = sof_update_ipc_object(scomp, host, SOF_PCM_TOKENS, swidget->tuples,
    375				    swidget->num_tuples, sizeof(*host), 1);
    376	if (ret < 0)
    377		goto err;
    378
    379	/* parse one set of comp_tokens */
    380	ret = sof_update_ipc_object(scomp, &host->config, SOF_COMP_TOKENS, swidget->tuples,
    381				    swidget->num_tuples, sizeof(host->config), 1);
    382	if (ret < 0)
    383		goto err;
    384
    385	dev_dbg(scomp->dev, "loaded host %s\n", swidget->widget->name);
    386	sof_dbg_comp_config(scomp, &host->config);
    387
    388	return 0;
    389err:
    390	kfree(swidget->private);
    391	swidget->private = NULL;
    392
    393	return ret;
    394}
    395
    396static void sof_ipc3_widget_free_comp(struct snd_sof_widget *swidget)
    397{
    398	kfree(swidget->private);
    399}
    400
    401static int sof_ipc3_widget_setup_comp_tone(struct snd_sof_widget *swidget)
    402{
    403	struct snd_soc_component *scomp = swidget->scomp;
    404	struct sof_ipc_comp_tone *tone;
    405	size_t ipc_size = sizeof(*tone);
    406	int ret;
    407
    408	tone = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
    409	if (!tone)
    410		return -ENOMEM;
    411
    412	swidget->private = tone;
    413
    414	/* configure siggen IPC message */
    415	tone->comp.type = SOF_COMP_TONE;
    416	tone->config.hdr.size = sizeof(tone->config);
    417
    418	/* parse one set of comp tokens */
    419	ret = sof_update_ipc_object(scomp, &tone->config, SOF_COMP_TOKENS, swidget->tuples,
    420				    swidget->num_tuples, sizeof(tone->config), 1);
    421	if (ret < 0) {
    422		kfree(swidget->private);
    423		swidget->private = NULL;
    424		return ret;
    425	}
    426
    427	dev_dbg(scomp->dev, "tone %s: frequency %d amplitude %d\n",
    428		swidget->widget->name, tone->frequency, tone->amplitude);
    429	sof_dbg_comp_config(scomp, &tone->config);
    430
    431	return 0;
    432}
    433
    434static int sof_ipc3_widget_setup_comp_mixer(struct snd_sof_widget *swidget)
    435{
    436	struct snd_soc_component *scomp = swidget->scomp;
    437	struct sof_ipc_comp_mixer *mixer;
    438	size_t ipc_size = sizeof(*mixer);
    439	int ret;
    440
    441	mixer = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
    442	if (!mixer)
    443		return -ENOMEM;
    444
    445	swidget->private = mixer;
    446
    447	/* configure mixer IPC message */
    448	mixer->comp.type = SOF_COMP_MIXER;
    449	mixer->config.hdr.size = sizeof(mixer->config);
    450
    451	/* parse one set of comp tokens */
    452	ret = sof_update_ipc_object(scomp, &mixer->config, SOF_COMP_TOKENS,
    453				    swidget->tuples, swidget->num_tuples,
    454				    sizeof(mixer->config), 1);
    455	if (ret < 0) {
    456		kfree(swidget->private);
    457		swidget->private = NULL;
    458
    459		return ret;
    460	}
    461
    462	dev_dbg(scomp->dev, "loaded mixer %s\n", swidget->widget->name);
    463	sof_dbg_comp_config(scomp, &mixer->config);
    464
    465	return 0;
    466}
    467
    468static int sof_ipc3_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
    469{
    470	struct snd_soc_component *scomp = swidget->scomp;
    471	struct sof_ipc_pipe_new *pipeline;
    472	struct snd_sof_widget *comp_swidget;
    473	int ret;
    474
    475	pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL);
    476	if (!pipeline)
    477		return -ENOMEM;
    478
    479	/* configure pipeline IPC message */
    480	pipeline->hdr.size = sizeof(*pipeline);
    481	pipeline->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_PIPE_NEW;
    482	pipeline->pipeline_id = swidget->pipeline_id;
    483	pipeline->comp_id = swidget->comp_id;
    484
    485	swidget->private = pipeline;
    486
    487	/* component at start of pipeline is our stream id */
    488	comp_swidget = snd_sof_find_swidget(scomp, swidget->widget->sname);
    489	if (!comp_swidget) {
    490		dev_err(scomp->dev, "scheduler %s refers to non existent widget %s\n",
    491			swidget->widget->name, swidget->widget->sname);
    492		ret = -EINVAL;
    493		goto err;
    494	}
    495
    496	pipeline->sched_id = comp_swidget->comp_id;
    497
    498	/* parse one set of scheduler tokens */
    499	ret = sof_update_ipc_object(scomp, pipeline, SOF_SCHED_TOKENS, swidget->tuples,
    500				    swidget->num_tuples, sizeof(*pipeline), 1);
    501	if (ret < 0)
    502		goto err;
    503
    504	/* parse one set of pipeline tokens */
    505	ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples,
    506				    swidget->num_tuples, sizeof(*swidget), 1);
    507	if (ret < 0)
    508		goto err;
    509
    510	if (sof_debug_check_flag(SOF_DBG_DISABLE_MULTICORE))
    511		pipeline->core = SOF_DSP_PRIMARY_CORE;
    512
    513	if (sof_debug_check_flag(SOF_DBG_DYNAMIC_PIPELINES_OVERRIDE))
    514		swidget->dynamic_pipeline_widget =
    515			sof_debug_check_flag(SOF_DBG_DYNAMIC_PIPELINES_ENABLE);
    516
    517	dev_dbg(scomp->dev, "pipeline %s: period %d pri %d mips %d core %d frames %d dynamic %d\n",
    518		swidget->widget->name, pipeline->period, pipeline->priority,
    519		pipeline->period_mips, pipeline->core, pipeline->frames_per_sched,
    520		swidget->dynamic_pipeline_widget);
    521
    522	swidget->core = pipeline->core;
    523
    524	return 0;
    525
    526err:
    527	kfree(swidget->private);
    528	swidget->private = NULL;
    529
    530	return ret;
    531}
    532
    533static int sof_ipc3_widget_setup_comp_buffer(struct snd_sof_widget *swidget)
    534{
    535	struct snd_soc_component *scomp = swidget->scomp;
    536	struct sof_ipc_buffer *buffer;
    537	int ret;
    538
    539	buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
    540	if (!buffer)
    541		return -ENOMEM;
    542
    543	swidget->private = buffer;
    544
    545	/* configure dai IPC message */
    546	buffer->comp.hdr.size = sizeof(*buffer);
    547	buffer->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_BUFFER_NEW;
    548	buffer->comp.id = swidget->comp_id;
    549	buffer->comp.type = SOF_COMP_BUFFER;
    550	buffer->comp.pipeline_id = swidget->pipeline_id;
    551	buffer->comp.core = swidget->core;
    552
    553	/* parse one set of buffer tokens */
    554	ret = sof_update_ipc_object(scomp, buffer, SOF_BUFFER_TOKENS, swidget->tuples,
    555				    swidget->num_tuples, sizeof(*buffer), 1);
    556	if (ret < 0) {
    557		kfree(swidget->private);
    558		swidget->private = NULL;
    559		return ret;
    560	}
    561
    562	dev_dbg(scomp->dev, "buffer %s: size %d caps 0x%x\n",
    563		swidget->widget->name, buffer->size, buffer->caps);
    564
    565	return 0;
    566}
    567
    568static int sof_ipc3_widget_setup_comp_src(struct snd_sof_widget *swidget)
    569{
    570	struct snd_soc_component *scomp = swidget->scomp;
    571	struct sof_ipc_comp_src *src;
    572	size_t ipc_size = sizeof(*src);
    573	int ret;
    574
    575	src = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
    576	if (!src)
    577		return -ENOMEM;
    578
    579	swidget->private = src;
    580
    581	/* configure src IPC message */
    582	src->comp.type = SOF_COMP_SRC;
    583	src->config.hdr.size = sizeof(src->config);
    584
    585	/* parse one set of src tokens */
    586	ret = sof_update_ipc_object(scomp, src, SOF_SRC_TOKENS, swidget->tuples,
    587				    swidget->num_tuples, sizeof(*src), 1);
    588	if (ret < 0)
    589		goto err;
    590
    591	/* parse one set of comp tokens */
    592	ret = sof_update_ipc_object(scomp, &src->config, SOF_COMP_TOKENS,
    593				    swidget->tuples, swidget->num_tuples, sizeof(src->config), 1);
    594	if (ret < 0)
    595		goto err;
    596
    597	dev_dbg(scomp->dev, "src %s: source rate %d sink rate %d\n",
    598		swidget->widget->name, src->source_rate, src->sink_rate);
    599	sof_dbg_comp_config(scomp, &src->config);
    600
    601	return 0;
    602err:
    603	kfree(swidget->private);
    604	swidget->private = NULL;
    605
    606	return ret;
    607}
    608
    609static int sof_ipc3_widget_setup_comp_asrc(struct snd_sof_widget *swidget)
    610{
    611	struct snd_soc_component *scomp = swidget->scomp;
    612	struct sof_ipc_comp_asrc *asrc;
    613	size_t ipc_size = sizeof(*asrc);
    614	int ret;
    615
    616	asrc = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
    617	if (!asrc)
    618		return -ENOMEM;
    619
    620	swidget->private = asrc;
    621
    622	/* configure ASRC IPC message */
    623	asrc->comp.type = SOF_COMP_ASRC;
    624	asrc->config.hdr.size = sizeof(asrc->config);
    625
    626	/* parse one set of asrc tokens */
    627	ret = sof_update_ipc_object(scomp, asrc, SOF_ASRC_TOKENS, swidget->tuples,
    628				    swidget->num_tuples, sizeof(*asrc), 1);
    629	if (ret < 0)
    630		goto err;
    631
    632	/* parse one set of comp tokens */
    633	ret = sof_update_ipc_object(scomp, &asrc->config, SOF_COMP_TOKENS,
    634				    swidget->tuples, swidget->num_tuples, sizeof(asrc->config), 1);
    635	if (ret < 0)
    636		goto err;
    637
    638	dev_dbg(scomp->dev, "asrc %s: source rate %d sink rate %d asynch %d operation %d\n",
    639		swidget->widget->name, asrc->source_rate, asrc->sink_rate,
    640		asrc->asynchronous_mode, asrc->operation_mode);
    641
    642	sof_dbg_comp_config(scomp, &asrc->config);
    643
    644	return 0;
    645err:
    646	kfree(swidget->private);
    647	swidget->private = NULL;
    648
    649	return ret;
    650}
    651
    652/*
    653 * Mux topology
    654 */
    655static int sof_ipc3_widget_setup_comp_mux(struct snd_sof_widget *swidget)
    656{
    657	struct snd_soc_component *scomp = swidget->scomp;
    658	struct sof_ipc_comp_mux *mux;
    659	size_t ipc_size = sizeof(*mux);
    660	int ret;
    661
    662	mux = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
    663	if (!mux)
    664		return -ENOMEM;
    665
    666	swidget->private = mux;
    667
    668	/* configure mux IPC message */
    669	mux->comp.type = SOF_COMP_MUX;
    670	mux->config.hdr.size = sizeof(mux->config);
    671
    672	/* parse one set of comp tokens */
    673	ret = sof_update_ipc_object(scomp, &mux->config, SOF_COMP_TOKENS,
    674				    swidget->tuples, swidget->num_tuples, sizeof(mux->config), 1);
    675	if (ret < 0) {
    676		kfree(swidget->private);
    677		swidget->private = NULL;
    678		return ret;
    679	}
    680
    681	dev_dbg(scomp->dev, "loaded mux %s\n", swidget->widget->name);
    682	sof_dbg_comp_config(scomp, &mux->config);
    683
    684	return 0;
    685}
    686
    687/*
    688 * PGA Topology
    689 */
    690
    691static int sof_ipc3_widget_setup_comp_pga(struct snd_sof_widget *swidget)
    692{
    693	struct snd_soc_component *scomp = swidget->scomp;
    694	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
    695	struct sof_ipc_comp_volume *volume;
    696	struct snd_sof_control *scontrol;
    697	size_t ipc_size = sizeof(*volume);
    698	int min_step, max_step;
    699	int ret;
    700
    701	volume = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
    702	if (!volume)
    703		return -ENOMEM;
    704
    705	swidget->private = volume;
    706
    707	/* configure volume IPC message */
    708	volume->comp.type = SOF_COMP_VOLUME;
    709	volume->config.hdr.size = sizeof(volume->config);
    710
    711	/* parse one set of volume tokens */
    712	ret = sof_update_ipc_object(scomp, volume, SOF_VOLUME_TOKENS, swidget->tuples,
    713				    swidget->num_tuples, sizeof(*volume), 1);
    714	if (ret < 0)
    715		goto err;
    716
    717	/* parse one set of comp tokens */
    718	ret = sof_update_ipc_object(scomp, &volume->config, SOF_COMP_TOKENS,
    719				    swidget->tuples, swidget->num_tuples,
    720				    sizeof(volume->config), 1);
    721	if (ret < 0)
    722		goto err;
    723
    724	dev_dbg(scomp->dev, "loaded PGA %s\n", swidget->widget->name);
    725	sof_dbg_comp_config(scomp, &volume->config);
    726
    727	list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
    728		if (scontrol->comp_id == swidget->comp_id &&
    729		    scontrol->volume_table) {
    730			min_step = scontrol->min_volume_step;
    731			max_step = scontrol->max_volume_step;
    732			volume->min_value = scontrol->volume_table[min_step];
    733			volume->max_value = scontrol->volume_table[max_step];
    734			volume->channels = scontrol->num_channels;
    735			break;
    736		}
    737	}
    738
    739	return 0;
    740err:
    741	kfree(swidget->private);
    742	swidget->private = NULL;
    743
    744	return ret;
    745}
    746
    747static int sof_get_control_data(struct snd_soc_component *scomp,
    748				struct snd_soc_dapm_widget *widget,
    749				struct sof_widget_data *wdata, size_t *size)
    750{
    751	const struct snd_kcontrol_new *kc;
    752	struct sof_ipc_ctrl_data *cdata;
    753	struct soc_mixer_control *sm;
    754	struct soc_bytes_ext *sbe;
    755	struct soc_enum *se;
    756	int i;
    757
    758	*size = 0;
    759
    760	for (i = 0; i < widget->num_kcontrols; i++) {
    761		kc = &widget->kcontrol_news[i];
    762
    763		switch (widget->dobj.widget.kcontrol_type[i]) {
    764		case SND_SOC_TPLG_TYPE_MIXER:
    765			sm = (struct soc_mixer_control *)kc->private_value;
    766			wdata[i].control = sm->dobj.private;
    767			break;
    768		case SND_SOC_TPLG_TYPE_BYTES:
    769			sbe = (struct soc_bytes_ext *)kc->private_value;
    770			wdata[i].control = sbe->dobj.private;
    771			break;
    772		case SND_SOC_TPLG_TYPE_ENUM:
    773			se = (struct soc_enum *)kc->private_value;
    774			wdata[i].control = se->dobj.private;
    775			break;
    776		default:
    777			dev_err(scomp->dev, "Unknown kcontrol type %u in widget %s\n",
    778				widget->dobj.widget.kcontrol_type[i], widget->name);
    779			return -EINVAL;
    780		}
    781
    782		if (!wdata[i].control) {
    783			dev_err(scomp->dev, "No scontrol for widget %s\n", widget->name);
    784			return -EINVAL;
    785		}
    786
    787		cdata = wdata[i].control->ipc_control_data;
    788
    789		if (widget->dobj.widget.kcontrol_type[i] == SND_SOC_TPLG_TYPE_BYTES) {
    790			/* make sure data is valid - data can be updated at runtime */
    791			if (cdata->data->magic != SOF_ABI_MAGIC)
    792				return -EINVAL;
    793
    794			wdata[i].pdata = cdata->data->data;
    795			wdata[i].pdata_size = cdata->data->size;
    796		} else {
    797			/* points to the control data union */
    798			wdata[i].pdata = cdata->chanv;
    799			/*
    800			 * wdata[i].control->size is calculated with struct_size
    801			 * and includes the size of struct sof_ipc_ctrl_data
    802			 */
    803			wdata[i].pdata_size = wdata[i].control->size -
    804					      sizeof(struct sof_ipc_ctrl_data);
    805		}
    806
    807		*size += wdata[i].pdata_size;
    808
    809		/* get data type */
    810		switch (cdata->cmd) {
    811		case SOF_CTRL_CMD_VOLUME:
    812		case SOF_CTRL_CMD_ENUM:
    813		case SOF_CTRL_CMD_SWITCH:
    814			wdata[i].ipc_cmd = SOF_IPC_COMP_SET_VALUE;
    815			wdata[i].ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET;
    816			break;
    817		case SOF_CTRL_CMD_BINARY:
    818			wdata[i].ipc_cmd = SOF_IPC_COMP_SET_DATA;
    819			wdata[i].ctrl_type = SOF_CTRL_TYPE_DATA_SET;
    820			break;
    821		default:
    822			break;
    823		}
    824	}
    825
    826	return 0;
    827}
    828
    829static int sof_process_load(struct snd_soc_component *scomp,
    830			    struct snd_sof_widget *swidget, int type)
    831{
    832	struct snd_soc_dapm_widget *widget = swidget->widget;
    833	struct sof_ipc_comp_process *process;
    834	struct sof_widget_data *wdata = NULL;
    835	size_t ipc_data_size = 0;
    836	size_t ipc_size;
    837	int offset = 0;
    838	int ret;
    839	int i;
    840
    841	/* allocate struct for widget control data sizes and types */
    842	if (widget->num_kcontrols) {
    843		wdata = kcalloc(widget->num_kcontrols, sizeof(*wdata), GFP_KERNEL);
    844		if (!wdata)
    845			return -ENOMEM;
    846
    847		/* get possible component controls and get size of all pdata */
    848		ret = sof_get_control_data(scomp, widget, wdata, &ipc_data_size);
    849		if (ret < 0)
    850			goto out;
    851	}
    852
    853	ipc_size = sizeof(struct sof_ipc_comp_process) + ipc_data_size;
    854
    855	/* we are exceeding max ipc size, config needs to be sent separately */
    856	if (ipc_size > SOF_IPC_MSG_MAX_SIZE) {
    857		ipc_size -= ipc_data_size;
    858		ipc_data_size = 0;
    859	}
    860
    861	process = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
    862	if (!process) {
    863		ret = -ENOMEM;
    864		goto out;
    865	}
    866
    867	swidget->private = process;
    868
    869	/* configure iir IPC message */
    870	process->comp.type = type;
    871	process->config.hdr.size = sizeof(process->config);
    872
    873	/* parse one set of comp tokens */
    874	ret = sof_update_ipc_object(scomp, &process->config, SOF_COMP_TOKENS,
    875				    swidget->tuples, swidget->num_tuples,
    876				    sizeof(process->config), 1);
    877	if (ret < 0)
    878		goto err;
    879
    880	dev_dbg(scomp->dev, "loaded process %s\n", swidget->widget->name);
    881	sof_dbg_comp_config(scomp, &process->config);
    882
    883	/*
    884	 * found private data in control, so copy it.
    885	 * get possible component controls - get size of all pdata,
    886	 * then memcpy with headers
    887	 */
    888	if (ipc_data_size) {
    889		for (i = 0; i < widget->num_kcontrols; i++) {
    890			if (!wdata[i].pdata_size)
    891				continue;
    892
    893			memcpy(&process->data[offset], wdata[i].pdata,
    894			       wdata[i].pdata_size);
    895			offset += wdata[i].pdata_size;
    896		}
    897	}
    898
    899	process->size = ipc_data_size;
    900
    901	kfree(wdata);
    902
    903	return 0;
    904err:
    905	kfree(swidget->private);
    906	swidget->private = NULL;
    907out:
    908	kfree(wdata);
    909	return ret;
    910}
    911
    912static enum sof_comp_type find_process_comp_type(enum sof_ipc_process_type type)
    913{
    914	int i;
    915
    916	for (i = 0; i < ARRAY_SIZE(sof_process); i++) {
    917		if (sof_process[i].type == type)
    918			return sof_process[i].comp_type;
    919	}
    920
    921	return SOF_COMP_NONE;
    922}
    923
    924/*
    925 * Processing Component Topology - can be "effect", "codec", or general
    926 * "processing".
    927 */
    928
    929static int sof_widget_update_ipc_comp_process(struct snd_sof_widget *swidget)
    930{
    931	struct snd_soc_component *scomp = swidget->scomp;
    932	struct sof_ipc_comp_process config;
    933	int ret;
    934
    935	memset(&config, 0, sizeof(config));
    936	config.comp.core = swidget->core;
    937
    938	/* parse one set of process tokens */
    939	ret = sof_update_ipc_object(scomp, &config, SOF_PROCESS_TOKENS, swidget->tuples,
    940				    swidget->num_tuples, sizeof(config), 1);
    941	if (ret < 0)
    942		return ret;
    943
    944	/* now load process specific data and send IPC */
    945	return sof_process_load(scomp, swidget, find_process_comp_type(config.type));
    946}
    947
    948static int sof_link_hda_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
    949			     struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
    950{
    951	struct sof_dai_private_data *private = dai->private;
    952	u32 size = sizeof(*config);
    953	int ret;
    954
    955	/* init IPC */
    956	memset(&config->hda, 0, sizeof(config->hda));
    957	config->hdr.size = size;
    958
    959	/* parse one set of HDA tokens */
    960	ret = sof_update_ipc_object(scomp, &config->hda, SOF_HDA_TOKENS, slink->tuples,
    961				    slink->num_tuples, size, 1);
    962	if (ret < 0)
    963		return ret;
    964
    965	dev_dbg(scomp->dev, "HDA config rate %d channels %d\n",
    966		config->hda.rate, config->hda.channels);
    967
    968	config->hda.link_dma_ch = DMA_CHAN_INVALID;
    969
    970	dai->number_configs = 1;
    971	dai->current_config = 0;
    972	private->dai_config = kmemdup(config, size, GFP_KERNEL);
    973	if (!private->dai_config)
    974		return -ENOMEM;
    975
    976	return 0;
    977}
    978
    979static void sof_dai_set_format(struct snd_soc_tplg_hw_config *hw_config,
    980			       struct sof_ipc_dai_config *config)
    981{
    982	/* clock directions wrt codec */
    983	config->format &= ~SOF_DAI_FMT_CLOCK_PROVIDER_MASK;
    984	if (hw_config->bclk_provider == SND_SOC_TPLG_BCLK_CP) {
    985		/* codec is bclk provider */
    986		if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CP)
    987			config->format |= SOF_DAI_FMT_CBP_CFP;
    988		else
    989			config->format |= SOF_DAI_FMT_CBP_CFC;
    990	} else {
    991		/* codec is bclk consumer */
    992		if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CP)
    993			config->format |= SOF_DAI_FMT_CBC_CFP;
    994		else
    995			config->format |= SOF_DAI_FMT_CBC_CFC;
    996	}
    997
    998	/* inverted clocks ? */
    999	config->format &= ~SOF_DAI_FMT_INV_MASK;
   1000	if (hw_config->invert_bclk) {
   1001		if (hw_config->invert_fsync)
   1002			config->format |= SOF_DAI_FMT_IB_IF;
   1003		else
   1004			config->format |= SOF_DAI_FMT_IB_NF;
   1005	} else {
   1006		if (hw_config->invert_fsync)
   1007			config->format |= SOF_DAI_FMT_NB_IF;
   1008		else
   1009			config->format |= SOF_DAI_FMT_NB_NF;
   1010	}
   1011}
   1012
   1013static int sof_link_sai_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
   1014			     struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
   1015{
   1016	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
   1017	struct sof_dai_private_data *private = dai->private;
   1018	u32 size = sizeof(*config);
   1019	int ret;
   1020
   1021	/* handle master/slave and inverted clocks */
   1022	sof_dai_set_format(hw_config, config);
   1023
   1024	/* init IPC */
   1025	memset(&config->sai, 0, sizeof(config->sai));
   1026	config->hdr.size = size;
   1027
   1028	/* parse one set of SAI tokens */
   1029	ret = sof_update_ipc_object(scomp, &config->sai, SOF_SAI_TOKENS, slink->tuples,
   1030				    slink->num_tuples, size, 1);
   1031	if (ret < 0)
   1032		return ret;
   1033
   1034	config->sai.mclk_rate = le32_to_cpu(hw_config->mclk_rate);
   1035	config->sai.bclk_rate = le32_to_cpu(hw_config->bclk_rate);
   1036	config->sai.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
   1037	config->sai.mclk_direction = hw_config->mclk_direction;
   1038
   1039	config->sai.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
   1040	config->sai.tdm_slot_width = le32_to_cpu(hw_config->tdm_slot_width);
   1041	config->sai.rx_slots = le32_to_cpu(hw_config->rx_slots);
   1042	config->sai.tx_slots = le32_to_cpu(hw_config->tx_slots);
   1043
   1044	dev_info(scomp->dev,
   1045		 "tplg: config SAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n",
   1046		config->dai_index, config->format,
   1047		config->sai.mclk_rate, config->sai.tdm_slot_width,
   1048		config->sai.tdm_slots, config->sai.mclk_id);
   1049
   1050	if (config->sai.tdm_slots < 1 || config->sai.tdm_slots > 8) {
   1051		dev_err(scomp->dev, "Invalid channel count for SAI%d\n", config->dai_index);
   1052		return -EINVAL;
   1053	}
   1054
   1055	dai->number_configs = 1;
   1056	dai->current_config = 0;
   1057	private->dai_config = kmemdup(config, size, GFP_KERNEL);
   1058	if (!private->dai_config)
   1059		return -ENOMEM;
   1060
   1061	return 0;
   1062}
   1063
   1064static int sof_link_esai_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
   1065			      struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
   1066{
   1067	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
   1068	struct sof_dai_private_data *private = dai->private;
   1069	u32 size = sizeof(*config);
   1070	int ret;
   1071
   1072	/* handle master/slave and inverted clocks */
   1073	sof_dai_set_format(hw_config, config);
   1074
   1075	/* init IPC */
   1076	memset(&config->esai, 0, sizeof(config->esai));
   1077	config->hdr.size = size;
   1078
   1079	/* parse one set of ESAI tokens */
   1080	ret = sof_update_ipc_object(scomp, &config->esai, SOF_ESAI_TOKENS, slink->tuples,
   1081				    slink->num_tuples, size, 1);
   1082	if (ret < 0)
   1083		return ret;
   1084
   1085	config->esai.mclk_rate = le32_to_cpu(hw_config->mclk_rate);
   1086	config->esai.bclk_rate = le32_to_cpu(hw_config->bclk_rate);
   1087	config->esai.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
   1088	config->esai.mclk_direction = hw_config->mclk_direction;
   1089	config->esai.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
   1090	config->esai.tdm_slot_width = le32_to_cpu(hw_config->tdm_slot_width);
   1091	config->esai.rx_slots = le32_to_cpu(hw_config->rx_slots);
   1092	config->esai.tx_slots = le32_to_cpu(hw_config->tx_slots);
   1093
   1094	dev_info(scomp->dev,
   1095		 "tplg: config ESAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n",
   1096		config->dai_index, config->format,
   1097		config->esai.mclk_rate, config->esai.tdm_slot_width,
   1098		config->esai.tdm_slots, config->esai.mclk_id);
   1099
   1100	if (config->esai.tdm_slots < 1 || config->esai.tdm_slots > 8) {
   1101		dev_err(scomp->dev, "Invalid channel count for ESAI%d\n", config->dai_index);
   1102		return -EINVAL;
   1103	}
   1104
   1105	dai->number_configs = 1;
   1106	dai->current_config = 0;
   1107	private->dai_config = kmemdup(config, size, GFP_KERNEL);
   1108	if (!private->dai_config)
   1109		return -ENOMEM;
   1110
   1111	return 0;
   1112}
   1113
   1114static int sof_link_acp_dmic_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
   1115				  struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
   1116{
   1117	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
   1118	struct sof_dai_private_data *private = dai->private;
   1119	u32 size = sizeof(*config);
   1120
   1121       /* handle master/slave and inverted clocks */
   1122	sof_dai_set_format(hw_config, config);
   1123
   1124	/* init IPC */
   1125	memset(&config->acpdmic, 0, sizeof(config->acpdmic));
   1126	config->hdr.size = size;
   1127
   1128	config->acpdmic.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
   1129	config->acpdmic.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
   1130
   1131	dev_info(scomp->dev, "ACP_DMIC config ACP%d channel %d rate %d\n",
   1132		 config->dai_index, config->acpdmic.tdm_slots,
   1133		 config->acpdmic.fsync_rate);
   1134
   1135	dai->number_configs = 1;
   1136	dai->current_config = 0;
   1137	private->dai_config = kmemdup(config, size, GFP_KERNEL);
   1138	if (!private->dai_config)
   1139		return -ENOMEM;
   1140
   1141	return 0;
   1142}
   1143
   1144static int sof_link_acp_bt_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
   1145				struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
   1146{
   1147	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
   1148	struct sof_dai_private_data *private = dai->private;
   1149	u32 size = sizeof(*config);
   1150
   1151	/* handle master/slave and inverted clocks */
   1152	sof_dai_set_format(hw_config, config);
   1153
   1154	/* init IPC */
   1155	memset(&config->acpbt, 0, sizeof(config->acpbt));
   1156	config->hdr.size = size;
   1157
   1158	config->acpbt.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
   1159	config->acpbt.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
   1160
   1161	dev_info(scomp->dev, "ACP_BT config ACP%d channel %d rate %d\n",
   1162		 config->dai_index, config->acpbt.tdm_slots,
   1163		 config->acpbt.fsync_rate);
   1164
   1165	dai->number_configs = 1;
   1166	dai->current_config = 0;
   1167	private->dai_config = kmemdup(config, size, GFP_KERNEL);
   1168	if (!private->dai_config)
   1169		return -ENOMEM;
   1170
   1171	return 0;
   1172}
   1173
   1174static int sof_link_acp_sp_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
   1175				struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
   1176{
   1177	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
   1178	struct sof_dai_private_data *private = dai->private;
   1179	u32 size = sizeof(*config);
   1180
   1181	/* handle master/slave and inverted clocks */
   1182	sof_dai_set_format(hw_config, config);
   1183
   1184	/* init IPC */
   1185	memset(&config->acpsp, 0, sizeof(config->acpsp));
   1186	config->hdr.size = size;
   1187
   1188	config->acpsp.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
   1189	config->acpsp.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
   1190
   1191	dev_info(scomp->dev, "ACP_SP config ACP%d channel %d rate %d\n",
   1192		 config->dai_index, config->acpsp.tdm_slots,
   1193		 config->acpsp.fsync_rate);
   1194
   1195	dai->number_configs = 1;
   1196	dai->current_config = 0;
   1197	private->dai_config = kmemdup(config, size, GFP_KERNEL);
   1198	if (!private->dai_config)
   1199		return -ENOMEM;
   1200
   1201	return 0;
   1202}
   1203
   1204static int sof_link_afe_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
   1205			     struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
   1206{
   1207	struct sof_dai_private_data *private = dai->private;
   1208	u32 size = sizeof(*config);
   1209	int ret;
   1210
   1211	config->hdr.size = size;
   1212
   1213	/* parse the required set of AFE tokens based on num_hw_cfgs */
   1214	ret = sof_update_ipc_object(scomp, &config->afe, SOF_AFE_TOKENS, slink->tuples,
   1215				    slink->num_tuples, size, slink->num_hw_configs);
   1216	if (ret < 0)
   1217		return ret;
   1218
   1219	dev_dbg(scomp->dev, "AFE config rate %d channels %d format:%d\n",
   1220		config->afe.rate, config->afe.channels, config->afe.format);
   1221
   1222	config->afe.stream_id = DMA_CHAN_INVALID;
   1223
   1224	dai->number_configs = 1;
   1225	dai->current_config = 0;
   1226	private->dai_config = kmemdup(config, size, GFP_KERNEL);
   1227	if (!private->dai_config)
   1228		return -ENOMEM;
   1229
   1230	return 0;
   1231}
   1232
   1233static int sof_link_ssp_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
   1234			     struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
   1235{
   1236	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
   1237	struct sof_dai_private_data *private = dai->private;
   1238	u32 size = sizeof(*config);
   1239	int current_config = 0;
   1240	int i, ret;
   1241
   1242	/*
   1243	 * Parse common data, we should have 1 common data per hw_config.
   1244	 */
   1245	ret = sof_update_ipc_object(scomp, &config->ssp, SOF_SSP_TOKENS, slink->tuples,
   1246				    slink->num_tuples, size, slink->num_hw_configs);
   1247	if (ret < 0)
   1248		return ret;
   1249
   1250	/* process all possible hw configs */
   1251	for (i = 0; i < slink->num_hw_configs; i++) {
   1252		if (le32_to_cpu(hw_config[i].id) == slink->default_hw_cfg_id)
   1253			current_config = i;
   1254
   1255		/* handle master/slave and inverted clocks */
   1256		sof_dai_set_format(&hw_config[i], &config[i]);
   1257
   1258		config[i].hdr.size = size;
   1259
   1260		/* copy differentiating hw configs to ipc structs */
   1261		config[i].ssp.mclk_rate = le32_to_cpu(hw_config[i].mclk_rate);
   1262		config[i].ssp.bclk_rate = le32_to_cpu(hw_config[i].bclk_rate);
   1263		config[i].ssp.fsync_rate = le32_to_cpu(hw_config[i].fsync_rate);
   1264		config[i].ssp.tdm_slots = le32_to_cpu(hw_config[i].tdm_slots);
   1265		config[i].ssp.tdm_slot_width = le32_to_cpu(hw_config[i].tdm_slot_width);
   1266		config[i].ssp.mclk_direction = hw_config[i].mclk_direction;
   1267		config[i].ssp.rx_slots = le32_to_cpu(hw_config[i].rx_slots);
   1268		config[i].ssp.tx_slots = le32_to_cpu(hw_config[i].tx_slots);
   1269
   1270		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",
   1271			config[i].dai_index, config[i].format,
   1272			config[i].ssp.mclk_rate, config[i].ssp.bclk_rate,
   1273			config[i].ssp.fsync_rate, config[i].ssp.sample_valid_bits,
   1274			config[i].ssp.tdm_slot_width, config[i].ssp.tdm_slots,
   1275			config[i].ssp.mclk_id, config[i].ssp.quirks, config[i].ssp.clks_control);
   1276
   1277		/* validate SSP fsync rate and channel count */
   1278		if (config[i].ssp.fsync_rate < 8000 || config[i].ssp.fsync_rate > 192000) {
   1279			dev_err(scomp->dev, "Invalid fsync rate for SSP%d\n", config[i].dai_index);
   1280			return -EINVAL;
   1281		}
   1282
   1283		if (config[i].ssp.tdm_slots < 1 || config[i].ssp.tdm_slots > 8) {
   1284			dev_err(scomp->dev, "Invalid channel count for SSP%d\n",
   1285				config[i].dai_index);
   1286			return -EINVAL;
   1287		}
   1288	}
   1289
   1290	dai->number_configs = slink->num_hw_configs;
   1291	dai->current_config = current_config;
   1292	private->dai_config = kmemdup(config, size * slink->num_hw_configs, GFP_KERNEL);
   1293	if (!private->dai_config)
   1294		return -ENOMEM;
   1295
   1296	return 0;
   1297}
   1298
   1299static int sof_link_dmic_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
   1300			      struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
   1301{
   1302	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
   1303	struct sof_dai_private_data *private = dai->private;
   1304	struct sof_ipc_fw_ready *ready = &sdev->fw_ready;
   1305	struct sof_ipc_fw_version *v = &ready->version;
   1306	size_t size = sizeof(*config);
   1307	int i, ret;
   1308
   1309	/* Ensure the entire DMIC config struct is zeros */
   1310	memset(&config->dmic, 0, sizeof(config->dmic));
   1311
   1312	/* parse the required set of DMIC tokens based on num_hw_cfgs */
   1313	ret = sof_update_ipc_object(scomp, &config->dmic, SOF_DMIC_TOKENS, slink->tuples,
   1314				    slink->num_tuples, size, slink->num_hw_configs);
   1315	if (ret < 0)
   1316		return ret;
   1317
   1318	/* parse the required set of DMIC PDM tokens based on number of active PDM's */
   1319	ret = sof_update_ipc_object(scomp, &config->dmic.pdm[0], SOF_DMIC_PDM_TOKENS,
   1320				    slink->tuples, slink->num_tuples,
   1321				    sizeof(struct sof_ipc_dai_dmic_pdm_ctrl),
   1322				    config->dmic.num_pdm_active);
   1323	if (ret < 0)
   1324		return ret;
   1325
   1326	/* set IPC header size */
   1327	config->hdr.size = size;
   1328
   1329	/* debug messages */
   1330	dev_dbg(scomp->dev, "tplg: config DMIC%d driver version %d\n",
   1331		config->dai_index, config->dmic.driver_ipc_version);
   1332	dev_dbg(scomp->dev, "pdmclk_min %d pdm_clkmax %d duty_min %d\n",
   1333		config->dmic.pdmclk_min, config->dmic.pdmclk_max,
   1334		config->dmic.duty_min);
   1335	dev_dbg(scomp->dev, "duty_max %d fifo_fs %d num_pdms active %d\n",
   1336		config->dmic.duty_max, config->dmic.fifo_fs,
   1337		config->dmic.num_pdm_active);
   1338	dev_dbg(scomp->dev, "fifo word length %d\n", config->dmic.fifo_bits);
   1339
   1340	for (i = 0; i < config->dmic.num_pdm_active; i++) {
   1341		dev_dbg(scomp->dev, "pdm %d mic a %d mic b %d\n",
   1342			config->dmic.pdm[i].id,
   1343			config->dmic.pdm[i].enable_mic_a,
   1344			config->dmic.pdm[i].enable_mic_b);
   1345		dev_dbg(scomp->dev, "pdm %d polarity a %d polarity b %d\n",
   1346			config->dmic.pdm[i].id,
   1347			config->dmic.pdm[i].polarity_mic_a,
   1348			config->dmic.pdm[i].polarity_mic_b);
   1349		dev_dbg(scomp->dev, "pdm %d clk_edge %d skew %d\n",
   1350			config->dmic.pdm[i].id,
   1351			config->dmic.pdm[i].clk_edge,
   1352			config->dmic.pdm[i].skew);
   1353	}
   1354
   1355	/*
   1356	 * this takes care of backwards compatible handling of fifo_bits_b.
   1357	 * It is deprecated since firmware ABI version 3.0.1.
   1358	 */
   1359	if (SOF_ABI_VER(v->major, v->minor, v->micro) < SOF_ABI_VER(3, 0, 1))
   1360		config->dmic.fifo_bits_b = config->dmic.fifo_bits;
   1361
   1362	dai->number_configs = 1;
   1363	dai->current_config = 0;
   1364	private->dai_config = kmemdup(config, size, GFP_KERNEL);
   1365	if (!private->dai_config)
   1366		return -ENOMEM;
   1367
   1368	return 0;
   1369}
   1370
   1371static int sof_link_alh_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
   1372			     struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
   1373{
   1374	struct sof_dai_private_data *private = dai->private;
   1375	u32 size = sizeof(*config);
   1376	int ret;
   1377
   1378	/* parse the required set of ALH tokens based on num_hw_cfgs */
   1379	ret = sof_update_ipc_object(scomp, &config->alh, SOF_ALH_TOKENS, slink->tuples,
   1380				    slink->num_tuples, size, slink->num_hw_configs);
   1381	if (ret < 0)
   1382		return ret;
   1383
   1384	/* init IPC */
   1385	config->hdr.size = size;
   1386
   1387	/* set config for all DAI's with name matching the link name */
   1388	dai->number_configs = 1;
   1389	dai->current_config = 0;
   1390	private->dai_config = kmemdup(config, size, GFP_KERNEL);
   1391	if (!private->dai_config)
   1392		return -ENOMEM;
   1393
   1394	return 0;
   1395}
   1396
   1397static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget)
   1398{
   1399	struct snd_soc_component *scomp = swidget->scomp;
   1400	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
   1401	struct snd_sof_dai *dai = swidget->private;
   1402	struct sof_dai_private_data *private;
   1403	struct sof_ipc_comp_dai *comp_dai;
   1404	size_t ipc_size = sizeof(*comp_dai);
   1405	struct sof_ipc_dai_config *config;
   1406	struct snd_sof_dai_link *slink;
   1407	int ret;
   1408
   1409	private = kzalloc(sizeof(*private), GFP_KERNEL);
   1410	if (!private)
   1411		return -ENOMEM;
   1412
   1413	dai->private = private;
   1414
   1415	private->comp_dai = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
   1416	if (!private->comp_dai) {
   1417		ret = -ENOMEM;
   1418		goto free;
   1419	}
   1420
   1421	/* configure dai IPC message */
   1422	comp_dai = private->comp_dai;
   1423	comp_dai->comp.type = SOF_COMP_DAI;
   1424	comp_dai->config.hdr.size = sizeof(comp_dai->config);
   1425
   1426	/* parse one set of DAI tokens */
   1427	ret = sof_update_ipc_object(scomp, comp_dai, SOF_DAI_TOKENS, swidget->tuples,
   1428				    swidget->num_tuples, sizeof(*comp_dai), 1);
   1429	if (ret < 0)
   1430		goto free;
   1431
   1432	/* update comp_tokens */
   1433	ret = sof_update_ipc_object(scomp, &comp_dai->config, SOF_COMP_TOKENS,
   1434				    swidget->tuples, swidget->num_tuples,
   1435				    sizeof(comp_dai->config), 1);
   1436	if (ret < 0)
   1437		goto free;
   1438
   1439	dev_dbg(scomp->dev, "%s dai %s: type %d index %d\n",
   1440		__func__, swidget->widget->name, comp_dai->type, comp_dai->dai_index);
   1441	sof_dbg_comp_config(scomp, &comp_dai->config);
   1442
   1443	/* now update DAI config */
   1444	list_for_each_entry(slink, &sdev->dai_link_list, list) {
   1445		struct sof_ipc_dai_config common_config;
   1446		int i;
   1447
   1448		if (strcmp(slink->link->name, dai->name))
   1449			continue;
   1450
   1451		/* Reserve memory for all hw configs, eventually freed by widget */
   1452		config = kcalloc(slink->num_hw_configs, sizeof(*config), GFP_KERNEL);
   1453		if (!config) {
   1454			ret = -ENOMEM;
   1455			goto free_comp;
   1456		}
   1457
   1458		/* parse one set of DAI link tokens */
   1459		ret = sof_update_ipc_object(scomp, &common_config, SOF_DAI_LINK_TOKENS,
   1460					    slink->tuples, slink->num_tuples,
   1461					    sizeof(common_config), 1);
   1462		if (ret < 0)
   1463			goto free_config;
   1464
   1465		for (i = 0; i < slink->num_hw_configs; i++) {
   1466			config[i].hdr.cmd = SOF_IPC_GLB_DAI_MSG | SOF_IPC_DAI_CONFIG;
   1467			config[i].format = le32_to_cpu(slink->hw_configs[i].fmt);
   1468			config[i].type = common_config.type;
   1469			config[i].dai_index = comp_dai->dai_index;
   1470		}
   1471
   1472		switch (common_config.type) {
   1473		case SOF_DAI_INTEL_SSP:
   1474			ret = sof_link_ssp_load(scomp, slink, config, dai);
   1475			break;
   1476		case SOF_DAI_INTEL_DMIC:
   1477			ret = sof_link_dmic_load(scomp, slink, config, dai);
   1478			break;
   1479		case SOF_DAI_INTEL_HDA:
   1480			ret = sof_link_hda_load(scomp, slink, config, dai);
   1481			break;
   1482		case SOF_DAI_INTEL_ALH:
   1483			ret = sof_link_alh_load(scomp, slink, config, dai);
   1484			break;
   1485		case SOF_DAI_IMX_SAI:
   1486			ret = sof_link_sai_load(scomp, slink, config, dai);
   1487			break;
   1488		case SOF_DAI_IMX_ESAI:
   1489			ret = sof_link_esai_load(scomp, slink, config, dai);
   1490			break;
   1491		case SOF_DAI_AMD_BT:
   1492			ret = sof_link_acp_bt_load(scomp, slink, config, dai);
   1493			break;
   1494		case SOF_DAI_AMD_SP:
   1495			ret = sof_link_acp_sp_load(scomp, slink, config, dai);
   1496			break;
   1497		case SOF_DAI_AMD_DMIC:
   1498			ret = sof_link_acp_dmic_load(scomp, slink, config, dai);
   1499			break;
   1500		case SOF_DAI_MEDIATEK_AFE:
   1501			ret = sof_link_afe_load(scomp, slink, config, dai);
   1502			break;
   1503		default:
   1504			break;
   1505		}
   1506		if (ret < 0) {
   1507			dev_err(scomp->dev, "failed to load config for dai %s\n", dai->name);
   1508			goto free_config;
   1509		}
   1510
   1511		kfree(config);
   1512	}
   1513
   1514	return 0;
   1515free_config:
   1516	kfree(config);
   1517free_comp:
   1518	kfree(comp_dai);
   1519free:
   1520	kfree(private);
   1521	dai->private = NULL;
   1522	return ret;
   1523}
   1524
   1525static void sof_ipc3_widget_free_comp_dai(struct snd_sof_widget *swidget)
   1526{
   1527	switch (swidget->id) {
   1528	case snd_soc_dapm_dai_in:
   1529	case snd_soc_dapm_dai_out:
   1530	{
   1531		struct snd_sof_dai *dai = swidget->private;
   1532		struct sof_dai_private_data *dai_data;
   1533
   1534		if (!dai)
   1535			return;
   1536
   1537		dai_data = dai->private;
   1538		if (dai_data) {
   1539			kfree(dai_data->comp_dai);
   1540			kfree(dai_data->dai_config);
   1541			kfree(dai_data);
   1542		}
   1543		kfree(dai);
   1544		break;
   1545	}
   1546	default:
   1547		break;
   1548	}
   1549}
   1550
   1551static int sof_ipc3_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
   1552{
   1553	struct sof_ipc_pipe_comp_connect connect;
   1554	struct sof_ipc_reply reply;
   1555	int ret;
   1556
   1557	connect.hdr.size = sizeof(connect);
   1558	connect.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_CONNECT;
   1559	connect.source_id = sroute->src_widget->comp_id;
   1560	connect.sink_id = sroute->sink_widget->comp_id;
   1561
   1562	dev_dbg(sdev->dev, "setting up route %s -> %s\n",
   1563		sroute->src_widget->widget->name,
   1564		sroute->sink_widget->widget->name);
   1565
   1566	/* send ipc */
   1567	ret = sof_ipc_tx_message(sdev->ipc, &connect, sizeof(connect), &reply, sizeof(reply));
   1568	if (ret < 0)
   1569		dev_err(sdev->dev, "%s: route %s -> %s failed\n", __func__,
   1570			sroute->src_widget->widget->name, sroute->sink_widget->widget->name);
   1571
   1572	return ret;
   1573}
   1574
   1575static int sof_ipc3_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
   1576{
   1577	struct sof_ipc_ctrl_data *cdata;
   1578	int ret;
   1579
   1580	if (scontrol->max_size < (sizeof(*cdata) + sizeof(struct sof_abi_hdr))) {
   1581		dev_err(sdev->dev, "%s: insufficient size for a bytes control: %zu.\n",
   1582			__func__, scontrol->max_size);
   1583		return -EINVAL;
   1584	}
   1585
   1586	if (scontrol->priv_size > scontrol->max_size - sizeof(*cdata)) {
   1587		dev_err(sdev->dev,
   1588			"%s: bytes data size %zu exceeds max %zu.\n", __func__,
   1589			scontrol->priv_size, scontrol->max_size - sizeof(*cdata));
   1590		return -EINVAL;
   1591	}
   1592
   1593	scontrol->ipc_control_data = kzalloc(scontrol->max_size, GFP_KERNEL);
   1594	if (!scontrol->ipc_control_data)
   1595		return -ENOMEM;
   1596
   1597	scontrol->size = sizeof(struct sof_ipc_ctrl_data) + scontrol->priv_size;
   1598
   1599	cdata = scontrol->ipc_control_data;
   1600	cdata->cmd = SOF_CTRL_CMD_BINARY;
   1601	cdata->index = scontrol->index;
   1602
   1603	if (scontrol->priv_size > 0) {
   1604		memcpy(cdata->data, scontrol->priv, scontrol->priv_size);
   1605		kfree(scontrol->priv);
   1606		scontrol->priv = NULL;
   1607
   1608		if (cdata->data->magic != SOF_ABI_MAGIC) {
   1609			dev_err(sdev->dev, "Wrong ABI magic 0x%08x.\n", cdata->data->magic);
   1610			ret = -EINVAL;
   1611			goto err;
   1612		}
   1613
   1614		if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) {
   1615			dev_err(sdev->dev, "Incompatible ABI version 0x%08x.\n",
   1616				cdata->data->abi);
   1617			ret = -EINVAL;
   1618			goto err;
   1619		}
   1620
   1621		if (cdata->data->size + sizeof(struct sof_abi_hdr) != scontrol->priv_size) {
   1622			dev_err(sdev->dev, "Conflict in bytes vs. priv size.\n");
   1623			ret = -EINVAL;
   1624			goto err;
   1625		}
   1626	}
   1627
   1628	return 0;
   1629err:
   1630	kfree(scontrol->ipc_control_data);
   1631	return ret;
   1632}
   1633
   1634static int sof_ipc3_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
   1635{
   1636	struct sof_ipc_ctrl_data *cdata;
   1637	int i;
   1638
   1639	/* init the volume get/put data */
   1640	scontrol->size = struct_size(cdata, chanv, scontrol->num_channels);
   1641
   1642	scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL);
   1643	if (!scontrol->ipc_control_data)
   1644		return -ENOMEM;
   1645
   1646	cdata = scontrol->ipc_control_data;
   1647	cdata->index = scontrol->index;
   1648
   1649	/* set cmd for mixer control */
   1650	if (scontrol->max == 1) {
   1651		cdata->cmd = SOF_CTRL_CMD_SWITCH;
   1652		return 0;
   1653	}
   1654
   1655	cdata->cmd = SOF_CTRL_CMD_VOLUME;
   1656
   1657	/* set default volume values to 0dB in control */
   1658	for (i = 0; i < scontrol->num_channels; i++) {
   1659		cdata->chanv[i].channel = i;
   1660		cdata->chanv[i].value = VOL_ZERO_DB;
   1661	}
   1662
   1663	return 0;
   1664}
   1665
   1666static int sof_ipc3_control_load_enum(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
   1667{
   1668	struct sof_ipc_ctrl_data *cdata;
   1669
   1670	/* init the enum get/put data */
   1671	scontrol->size = struct_size(cdata, chanv, scontrol->num_channels);
   1672
   1673	scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL);
   1674	if (!scontrol->ipc_control_data)
   1675		return -ENOMEM;
   1676
   1677	cdata = scontrol->ipc_control_data;
   1678	cdata->index = scontrol->index;
   1679	cdata->cmd = SOF_CTRL_CMD_ENUM;
   1680
   1681	return 0;
   1682}
   1683
   1684static int sof_ipc3_control_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
   1685{
   1686	switch (scontrol->info_type) {
   1687	case SND_SOC_TPLG_CTL_VOLSW:
   1688	case SND_SOC_TPLG_CTL_VOLSW_SX:
   1689	case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
   1690		return sof_ipc3_control_load_volume(sdev, scontrol);
   1691	case SND_SOC_TPLG_CTL_BYTES:
   1692		return sof_ipc3_control_load_bytes(sdev, scontrol);
   1693	case SND_SOC_TPLG_CTL_ENUM:
   1694	case SND_SOC_TPLG_CTL_ENUM_VALUE:
   1695		return sof_ipc3_control_load_enum(sdev, scontrol);
   1696	default:
   1697		break;
   1698	}
   1699
   1700	return 0;
   1701}
   1702
   1703static int sof_ipc3_control_free(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
   1704{
   1705	struct sof_ipc_free fcomp;
   1706
   1707	fcomp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_FREE;
   1708	fcomp.hdr.size = sizeof(fcomp);
   1709	fcomp.id = scontrol->comp_id;
   1710
   1711	/* send IPC to the DSP */
   1712	return sof_ipc_tx_message(sdev->ipc, &fcomp, sizeof(fcomp), NULL, 0);
   1713}
   1714
   1715/* send pcm params ipc */
   1716static int sof_ipc3_keyword_detect_pcm_params(struct snd_sof_widget *swidget, int dir)
   1717{
   1718	struct snd_soc_component *scomp = swidget->scomp;
   1719	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
   1720	struct sof_ipc_pcm_params_reply ipc_params_reply;
   1721	struct snd_pcm_hw_params *params;
   1722	struct sof_ipc_pcm_params pcm;
   1723	struct snd_sof_pcm *spcm;
   1724	int ret;
   1725
   1726	/* get runtime PCM params using widget's stream name */
   1727	spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname);
   1728	if (!spcm) {
   1729		dev_err(scomp->dev, "Cannot find PCM for %s\n", swidget->widget->name);
   1730		return -EINVAL;
   1731	}
   1732
   1733	params = &spcm->params[dir];
   1734
   1735	/* set IPC PCM params */
   1736	memset(&pcm, 0, sizeof(pcm));
   1737	pcm.hdr.size = sizeof(pcm);
   1738	pcm.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS;
   1739	pcm.comp_id = swidget->comp_id;
   1740	pcm.params.hdr.size = sizeof(pcm.params);
   1741	pcm.params.direction = dir;
   1742	pcm.params.sample_valid_bytes = params_width(params) >> 3;
   1743	pcm.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED;
   1744	pcm.params.rate = params_rate(params);
   1745	pcm.params.channels = params_channels(params);
   1746	pcm.params.host_period_bytes = params_period_bytes(params);
   1747
   1748	/* set format */
   1749	switch (params_format(params)) {
   1750	case SNDRV_PCM_FORMAT_S16:
   1751		pcm.params.frame_fmt = SOF_IPC_FRAME_S16_LE;
   1752		break;
   1753	case SNDRV_PCM_FORMAT_S24:
   1754		pcm.params.frame_fmt = SOF_IPC_FRAME_S24_4LE;
   1755		break;
   1756	case SNDRV_PCM_FORMAT_S32:
   1757		pcm.params.frame_fmt = SOF_IPC_FRAME_S32_LE;
   1758		break;
   1759	default:
   1760		return -EINVAL;
   1761	}
   1762
   1763	/* send IPC to the DSP */
   1764	ret = sof_ipc_tx_message(sdev->ipc, &pcm, sizeof(pcm),
   1765				 &ipc_params_reply, sizeof(ipc_params_reply));
   1766	if (ret < 0)
   1767		dev_err(scomp->dev, "%s: PCM params failed for %s\n", __func__,
   1768			swidget->widget->name);
   1769
   1770	return ret;
   1771}
   1772
   1773 /* send stream trigger ipc */
   1774static int sof_ipc3_keyword_detect_trigger(struct snd_sof_widget *swidget, int cmd)
   1775{
   1776	struct snd_soc_component *scomp = swidget->scomp;
   1777	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
   1778	struct sof_ipc_stream stream;
   1779	struct sof_ipc_reply reply;
   1780	int ret;
   1781
   1782	/* set IPC stream params */
   1783	stream.hdr.size = sizeof(stream);
   1784	stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | cmd;
   1785	stream.comp_id = swidget->comp_id;
   1786
   1787	/* send IPC to the DSP */
   1788	ret = sof_ipc_tx_message(sdev->ipc, &stream, sizeof(stream), &reply, sizeof(reply));
   1789	if (ret < 0)
   1790		dev_err(scomp->dev, "%s: Failed to trigger %s\n", __func__, swidget->widget->name);
   1791
   1792	return ret;
   1793}
   1794
   1795static int sof_ipc3_keyword_dapm_event(struct snd_soc_dapm_widget *w,
   1796				       struct snd_kcontrol *k, int event)
   1797{
   1798	struct snd_sof_widget *swidget = w->dobj.private;
   1799	struct snd_soc_component *scomp;
   1800	int stream = SNDRV_PCM_STREAM_CAPTURE;
   1801	struct snd_sof_pcm *spcm;
   1802	int ret = 0;
   1803
   1804	if (!swidget)
   1805		return 0;
   1806
   1807	scomp = swidget->scomp;
   1808
   1809	dev_dbg(scomp->dev, "received event %d for widget %s\n",
   1810		event, w->name);
   1811
   1812	/* get runtime PCM params using widget's stream name */
   1813	spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname);
   1814	if (!spcm) {
   1815		dev_err(scomp->dev, "%s: Cannot find PCM for %s\n", __func__,
   1816			swidget->widget->name);
   1817		return -EINVAL;
   1818	}
   1819
   1820	/* process events */
   1821	switch (event) {
   1822	case SND_SOC_DAPM_PRE_PMU:
   1823		if (spcm->stream[stream].suspend_ignored) {
   1824			dev_dbg(scomp->dev, "PRE_PMU event ignored, KWD pipeline is already RUNNING\n");
   1825			return 0;
   1826		}
   1827
   1828		/* set pcm params */
   1829		ret = sof_ipc3_keyword_detect_pcm_params(swidget, stream);
   1830		if (ret < 0) {
   1831			dev_err(scomp->dev, "%s: Failed to set pcm params for widget %s\n",
   1832				__func__, swidget->widget->name);
   1833			break;
   1834		}
   1835
   1836		/* start trigger */
   1837		ret = sof_ipc3_keyword_detect_trigger(swidget, SOF_IPC_STREAM_TRIG_START);
   1838		if (ret < 0)
   1839			dev_err(scomp->dev, "%s: Failed to trigger widget %s\n", __func__,
   1840				swidget->widget->name);
   1841		break;
   1842	case SND_SOC_DAPM_POST_PMD:
   1843		if (spcm->stream[stream].suspend_ignored) {
   1844			dev_dbg(scomp->dev,
   1845				"POST_PMD event ignored, KWD pipeline will remain RUNNING\n");
   1846			return 0;
   1847		}
   1848
   1849		/* stop trigger */
   1850		ret = sof_ipc3_keyword_detect_trigger(swidget, SOF_IPC_STREAM_TRIG_STOP);
   1851		if (ret < 0)
   1852			dev_err(scomp->dev, "%s: Failed to trigger widget %s\n", __func__,
   1853				swidget->widget->name);
   1854
   1855		/* pcm free */
   1856		ret = sof_ipc3_keyword_detect_trigger(swidget, SOF_IPC_STREAM_PCM_FREE);
   1857		if (ret < 0)
   1858			dev_err(scomp->dev, "%s: Failed to free PCM for widget %s\n", __func__,
   1859				swidget->widget->name);
   1860		break;
   1861	default:
   1862		break;
   1863	}
   1864
   1865	return ret;
   1866}
   1867
   1868/* event handlers for keyword detect component */
   1869static const struct snd_soc_tplg_widget_events sof_kwd_events[] = {
   1870	{SOF_KEYWORD_DETECT_DAPM_EVENT, sof_ipc3_keyword_dapm_event},
   1871};
   1872
   1873static int sof_ipc3_widget_bind_event(struct snd_soc_component *scomp,
   1874				      struct snd_sof_widget *swidget, u16 event_type)
   1875{
   1876	struct sof_ipc_comp *ipc_comp;
   1877
   1878	/* validate widget event type */
   1879	switch (event_type) {
   1880	case SOF_KEYWORD_DETECT_DAPM_EVENT:
   1881		/* only KEYWORD_DETECT comps should handle this */
   1882		if (swidget->id != snd_soc_dapm_effect)
   1883			break;
   1884
   1885		ipc_comp = swidget->private;
   1886		if (ipc_comp && ipc_comp->type != SOF_COMP_KEYWORD_DETECT)
   1887			break;
   1888
   1889		/* bind event to keyword detect comp */
   1890		return snd_soc_tplg_widget_bind_event(swidget->widget, sof_kwd_events,
   1891						      ARRAY_SIZE(sof_kwd_events), event_type);
   1892	default:
   1893		break;
   1894	}
   1895
   1896	dev_err(scomp->dev, "Invalid event type %d for widget %s\n", event_type,
   1897		swidget->widget->name);
   1898
   1899	return -EINVAL;
   1900}
   1901
   1902static int sof_ipc3_complete_pipeline(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
   1903{
   1904	struct sof_ipc_pipe_ready ready;
   1905	struct sof_ipc_reply reply;
   1906	int ret;
   1907
   1908	dev_dbg(sdev->dev, "tplg: complete pipeline %s id %d\n",
   1909		swidget->widget->name, swidget->comp_id);
   1910
   1911	memset(&ready, 0, sizeof(ready));
   1912	ready.hdr.size = sizeof(ready);
   1913	ready.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_PIPE_COMPLETE;
   1914	ready.comp_id = swidget->comp_id;
   1915
   1916	ret = sof_ipc_tx_message(sdev->ipc, &ready, sizeof(ready), &reply, sizeof(reply));
   1917	if (ret < 0)
   1918		return ret;
   1919
   1920	return 1;
   1921}
   1922
   1923static int sof_ipc3_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
   1924{
   1925	struct sof_ipc_free ipc_free = {
   1926		.hdr = {
   1927			.size = sizeof(ipc_free),
   1928			.cmd = SOF_IPC_GLB_TPLG_MSG,
   1929		},
   1930		.id = swidget->comp_id,
   1931	};
   1932	struct sof_ipc_reply reply;
   1933	int ret;
   1934
   1935	if (!swidget->private)
   1936		return 0;
   1937
   1938	switch (swidget->id) {
   1939	case snd_soc_dapm_scheduler:
   1940	{
   1941		ipc_free.hdr.cmd |= SOF_IPC_TPLG_PIPE_FREE;
   1942		break;
   1943	}
   1944	case snd_soc_dapm_buffer:
   1945		ipc_free.hdr.cmd |= SOF_IPC_TPLG_BUFFER_FREE;
   1946		break;
   1947	default:
   1948		ipc_free.hdr.cmd |= SOF_IPC_TPLG_COMP_FREE;
   1949		break;
   1950	}
   1951
   1952	ret = sof_ipc_tx_message(sdev->ipc, &ipc_free, sizeof(ipc_free),
   1953				 &reply, sizeof(reply));
   1954	if (ret < 0)
   1955		dev_err(sdev->dev, "failed to free widget %s\n", swidget->widget->name);
   1956
   1957	return ret;
   1958}
   1959
   1960static int sof_ipc3_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
   1961			       unsigned int flags, struct snd_sof_dai_config_data *data)
   1962{
   1963	struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
   1964	struct snd_sof_dai *dai = swidget->private;
   1965	struct sof_dai_private_data *private;
   1966	struct sof_ipc_dai_config *config;
   1967	struct sof_ipc_reply reply;
   1968	int ret = 0;
   1969
   1970	if (!dai || !dai->private) {
   1971		dev_err(sdev->dev, "No private data for DAI %s\n", swidget->widget->name);
   1972		return -EINVAL;
   1973	}
   1974
   1975	private = dai->private;
   1976	if (!private->dai_config) {
   1977		dev_err(sdev->dev, "No config for DAI %s\n", dai->name);
   1978		return -EINVAL;
   1979	}
   1980
   1981	config = &private->dai_config[dai->current_config];
   1982	if (!config) {
   1983		dev_err(sdev->dev, "Invalid current config for DAI %s\n", dai->name);
   1984		return -EINVAL;
   1985	}
   1986
   1987	switch (config->type) {
   1988	case SOF_DAI_INTEL_SSP:
   1989		/*
   1990		 * DAI_CONFIG IPC during hw_params/hw_free for SSP DAI's is not supported in older
   1991		 * firmware
   1992		 */
   1993		if (v->abi_version < SOF_ABI_VER(3, 18, 0) &&
   1994		    ((flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) ||
   1995		     (flags & SOF_DAI_CONFIG_FLAGS_HW_FREE)))
   1996			return 0;
   1997		break;
   1998	case SOF_DAI_INTEL_HDA:
   1999		if (data)
   2000			config->hda.link_dma_ch = data->dai_data;
   2001		break;
   2002	case SOF_DAI_INTEL_ALH:
   2003		if (data) {
   2004			config->dai_index = data->dai_index;
   2005			config->alh.stream_id = data->dai_data;
   2006		}
   2007		break;
   2008	default:
   2009		break;
   2010	}
   2011
   2012	config->flags = flags;
   2013
   2014	/* only send the IPC if the widget is set up in the DSP */
   2015	if (swidget->use_count > 0) {
   2016		ret = sof_ipc_tx_message(sdev->ipc, config, config->hdr.size,
   2017					 &reply, sizeof(reply));
   2018		if (ret < 0)
   2019			dev_err(sdev->dev, "Failed to set dai config for %s\n", dai->name);
   2020	}
   2021
   2022	return ret;
   2023}
   2024
   2025static int sof_ipc3_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
   2026{
   2027	struct sof_ipc_comp_reply reply;
   2028	int ret;
   2029
   2030	if (!swidget->private)
   2031		return 0;
   2032
   2033	switch (swidget->id) {
   2034	case snd_soc_dapm_dai_in:
   2035	case snd_soc_dapm_dai_out:
   2036	{
   2037		struct snd_sof_dai *dai = swidget->private;
   2038		struct sof_dai_private_data *dai_data = dai->private;
   2039		struct sof_ipc_comp *comp = &dai_data->comp_dai->comp;
   2040
   2041		ret = sof_ipc_tx_message(sdev->ipc, dai_data->comp_dai,
   2042					 comp->hdr.size, &reply, sizeof(reply));
   2043		break;
   2044	}
   2045	case snd_soc_dapm_scheduler:
   2046	{
   2047		struct sof_ipc_pipe_new *pipeline;
   2048
   2049		pipeline = swidget->private;
   2050		ret = sof_ipc_tx_message(sdev->ipc, pipeline, sizeof(*pipeline),
   2051					 &reply, sizeof(reply));
   2052		break;
   2053	}
   2054	default:
   2055	{
   2056		struct sof_ipc_cmd_hdr *hdr;
   2057
   2058		hdr = swidget->private;
   2059		ret = sof_ipc_tx_message(sdev->ipc, swidget->private, hdr->size,
   2060					 &reply, sizeof(reply));
   2061		break;
   2062	}
   2063	}
   2064	if (ret < 0)
   2065		dev_err(sdev->dev, "Failed to setup widget %s\n", swidget->widget->name);
   2066
   2067	return ret;
   2068}
   2069
   2070static int sof_ipc3_set_up_all_pipelines(struct snd_sof_dev *sdev, bool verify)
   2071{
   2072	struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
   2073	struct snd_sof_widget *swidget;
   2074	struct snd_sof_route *sroute;
   2075	int ret;
   2076
   2077	/* restore pipeline components */
   2078	list_for_each_entry(swidget, &sdev->widget_list, list) {
   2079		/* only set up the widgets belonging to static pipelines */
   2080		if (!verify && swidget->dynamic_pipeline_widget)
   2081			continue;
   2082
   2083		/*
   2084		 * For older firmware, skip scheduler widgets in this loop,
   2085		 * sof_widget_setup() will be called in the 'complete pipeline' loop
   2086		 */
   2087		if (v->abi_version < SOF_ABI_VER(3, 19, 0) &&
   2088		    swidget->id == snd_soc_dapm_scheduler)
   2089			continue;
   2090
   2091		/* update DAI config. The IPC will be sent in sof_widget_setup() */
   2092		if (WIDGET_IS_DAI(swidget->id)) {
   2093			struct snd_sof_dai *dai = swidget->private;
   2094			struct sof_dai_private_data *private;
   2095			struct sof_ipc_dai_config *config;
   2096
   2097			if (!dai || !dai->private)
   2098				continue;
   2099			private = dai->private;
   2100			if (!private->dai_config)
   2101				continue;
   2102
   2103			config = private->dai_config;
   2104			/*
   2105			 * The link DMA channel would be invalidated for running
   2106			 * streams but not for streams that were in the PAUSED
   2107			 * state during suspend. So invalidate it here before setting
   2108			 * the dai config in the DSP.
   2109			 */
   2110			if (config->type == SOF_DAI_INTEL_HDA)
   2111				config->hda.link_dma_ch = DMA_CHAN_INVALID;
   2112		}
   2113
   2114		ret = sof_widget_setup(sdev, swidget);
   2115		if (ret < 0)
   2116			return ret;
   2117	}
   2118
   2119	/* restore pipeline connections */
   2120	list_for_each_entry(sroute, &sdev->route_list, list) {
   2121		/* only set up routes belonging to static pipelines */
   2122		if (!verify && (sroute->src_widget->dynamic_pipeline_widget ||
   2123				sroute->sink_widget->dynamic_pipeline_widget))
   2124			continue;
   2125
   2126		/*
   2127		 * For virtual routes, both sink and source are not buffer. IPC3 only supports
   2128		 * connections between a buffer and a component. Ignore the rest.
   2129		 */
   2130		if (sroute->src_widget->id != snd_soc_dapm_buffer &&
   2131		    sroute->sink_widget->id != snd_soc_dapm_buffer)
   2132			continue;
   2133
   2134		ret = sof_route_setup(sdev, sroute->src_widget->widget,
   2135				      sroute->sink_widget->widget);
   2136		if (ret < 0) {
   2137			dev_err(sdev->dev, "%s: route set up failed\n", __func__);
   2138			return ret;
   2139		}
   2140	}
   2141
   2142	/* complete pipeline */
   2143	list_for_each_entry(swidget, &sdev->widget_list, list) {
   2144		switch (swidget->id) {
   2145		case snd_soc_dapm_scheduler:
   2146			/* only complete static pipelines */
   2147			if (!verify && swidget->dynamic_pipeline_widget)
   2148				continue;
   2149
   2150			if (v->abi_version < SOF_ABI_VER(3, 19, 0)) {
   2151				ret = sof_widget_setup(sdev, swidget);
   2152				if (ret < 0)
   2153					return ret;
   2154			}
   2155
   2156			swidget->complete = sof_ipc3_complete_pipeline(sdev, swidget);
   2157			if (swidget->complete < 0)
   2158				return swidget->complete;
   2159			break;
   2160		default:
   2161			break;
   2162		}
   2163	}
   2164
   2165	return 0;
   2166}
   2167
   2168/*
   2169 * Free the PCM, its associated widgets and set the prepared flag to false for all PCMs that
   2170 * did not get suspended(ex: paused streams) so the widgets can be set up again during resume.
   2171 */
   2172static int sof_tear_down_left_over_pipelines(struct snd_sof_dev *sdev)
   2173{
   2174	struct snd_sof_widget *swidget;
   2175	struct snd_sof_pcm *spcm;
   2176	int dir, ret;
   2177
   2178	/*
   2179	 * free all PCMs and their associated DAPM widgets if their connected DAPM widget
   2180	 * list is not NULL. This should only be true for paused streams at this point.
   2181	 * This is equivalent to the handling of FE DAI suspend trigger for running streams.
   2182	 */
   2183	list_for_each_entry(spcm, &sdev->pcm_list, list) {
   2184		for_each_pcm_streams(dir) {
   2185			struct snd_pcm_substream *substream = spcm->stream[dir].substream;
   2186
   2187			if (!substream || !substream->runtime)
   2188				continue;
   2189
   2190			if (spcm->stream[dir].list) {
   2191				ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true);
   2192				if (ret < 0)
   2193					return ret;
   2194			}
   2195		}
   2196	}
   2197
   2198	/*
   2199	 * free any left over DAI widgets. This is equivalent to the handling of suspend trigger
   2200	 * for the BE DAI for running streams.
   2201	 */
   2202	list_for_each_entry(swidget, &sdev->widget_list, list)
   2203		if (WIDGET_IS_DAI(swidget->id) && swidget->use_count == 1) {
   2204			ret = sof_widget_free(sdev, swidget);
   2205			if (ret < 0)
   2206				return ret;
   2207		}
   2208
   2209	return 0;
   2210}
   2211
   2212/*
   2213 * For older firmware, this function doesn't free widgets for static pipelines during suspend.
   2214 * It only resets use_count for all widgets.
   2215 */
   2216static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify)
   2217{
   2218	struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
   2219	struct snd_sof_widget *swidget;
   2220	struct snd_sof_route *sroute;
   2221	int ret;
   2222
   2223	/*
   2224	 * This function is called during suspend and for one-time topology verification during
   2225	 * first boot. In both cases, there is no need to protect swidget->use_count and
   2226	 * sroute->setup because during suspend all running streams are suspended and during
   2227	 * topology loading the sound card unavailable to open PCMs.
   2228	 */
   2229	list_for_each_entry(swidget, &sdev->widget_list, list) {
   2230		if (swidget->dynamic_pipeline_widget)
   2231			continue;
   2232
   2233		/* Do not free widgets for static pipelines with FW ABI older than 3.19 */
   2234		if (!verify && !swidget->dynamic_pipeline_widget &&
   2235		    v->abi_version < SOF_ABI_VER(3, 19, 0)) {
   2236			swidget->use_count = 0;
   2237			swidget->complete = 0;
   2238			continue;
   2239		}
   2240
   2241		ret = sof_widget_free(sdev, swidget);
   2242		if (ret < 0)
   2243			return ret;
   2244	}
   2245
   2246	/*
   2247	 * Tear down all pipelines associated with PCMs that did not get suspended
   2248	 * and unset the prepare flag so that they can be set up again during resume.
   2249	 * Skip this step for older firmware.
   2250	 */
   2251	if (!verify && v->abi_version >= SOF_ABI_VER(3, 19, 0)) {
   2252		ret = sof_tear_down_left_over_pipelines(sdev);
   2253		if (ret < 0) {
   2254			dev_err(sdev->dev, "failed to tear down paused pipelines\n");
   2255			return ret;
   2256		}
   2257	}
   2258
   2259	list_for_each_entry(sroute, &sdev->route_list, list)
   2260		sroute->setup = false;
   2261
   2262	/*
   2263	 * before suspending, make sure the refcounts are all zeroed out. There's no way
   2264	 * to recover at this point but this will help root cause bad sequences leading to
   2265	 * more issues on resume
   2266	 */
   2267	list_for_each_entry(swidget, &sdev->widget_list, list) {
   2268		if (swidget->use_count != 0) {
   2269			dev_err(sdev->dev, "%s: widget %s is still in use: count %d\n",
   2270				__func__, swidget->widget->name, swidget->use_count);
   2271		}
   2272	}
   2273
   2274	return 0;
   2275}
   2276
   2277static int sof_ipc3_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type)
   2278{
   2279	struct sof_dai_private_data *private = dai->private;
   2280
   2281	if (!private || !private->dai_config)
   2282		return 0;
   2283
   2284	switch (private->dai_config->type) {
   2285	case SOF_DAI_INTEL_SSP:
   2286		switch (clk_type) {
   2287		case SOF_DAI_CLK_INTEL_SSP_MCLK:
   2288			return private->dai_config->ssp.mclk_rate;
   2289		case SOF_DAI_CLK_INTEL_SSP_BCLK:
   2290			return private->dai_config->ssp.bclk_rate;
   2291		default:
   2292			break;
   2293		}
   2294		dev_err(sdev->dev, "fail to get SSP clk %d rate\n", clk_type);
   2295		break;
   2296	default:
   2297		/* not yet implemented for platforms other than the above */
   2298		dev_err(sdev->dev, "DAI type %d not supported yet!\n", private->dai_config->type);
   2299		break;
   2300	}
   2301
   2302	return -EINVAL;
   2303}
   2304
   2305/* token list for each topology object */
   2306static enum sof_tokens host_token_list[] = {
   2307	SOF_CORE_TOKENS,
   2308	SOF_COMP_EXT_TOKENS,
   2309	SOF_PCM_TOKENS,
   2310	SOF_COMP_TOKENS,
   2311};
   2312
   2313static enum sof_tokens comp_generic_token_list[] = {
   2314	SOF_CORE_TOKENS,
   2315	SOF_COMP_EXT_TOKENS,
   2316	SOF_COMP_TOKENS,
   2317};
   2318
   2319static enum sof_tokens buffer_token_list[] = {
   2320	SOF_BUFFER_TOKENS,
   2321};
   2322
   2323static enum sof_tokens pipeline_token_list[] = {
   2324	SOF_CORE_TOKENS,
   2325	SOF_COMP_EXT_TOKENS,
   2326	SOF_PIPELINE_TOKENS,
   2327	SOF_SCHED_TOKENS,
   2328};
   2329
   2330static enum sof_tokens asrc_token_list[] = {
   2331	SOF_CORE_TOKENS,
   2332	SOF_COMP_EXT_TOKENS,
   2333	SOF_ASRC_TOKENS,
   2334	SOF_COMP_TOKENS,
   2335};
   2336
   2337static enum sof_tokens src_token_list[] = {
   2338	SOF_CORE_TOKENS,
   2339	SOF_COMP_EXT_TOKENS,
   2340	SOF_SRC_TOKENS,
   2341	SOF_COMP_TOKENS
   2342};
   2343
   2344static enum sof_tokens pga_token_list[] = {
   2345	SOF_CORE_TOKENS,
   2346	SOF_COMP_EXT_TOKENS,
   2347	SOF_VOLUME_TOKENS,
   2348	SOF_COMP_TOKENS,
   2349};
   2350
   2351static enum sof_tokens dai_token_list[] = {
   2352	SOF_CORE_TOKENS,
   2353	SOF_COMP_EXT_TOKENS,
   2354	SOF_DAI_TOKENS,
   2355	SOF_COMP_TOKENS,
   2356};
   2357
   2358static enum sof_tokens process_token_list[] = {
   2359	SOF_CORE_TOKENS,
   2360	SOF_COMP_EXT_TOKENS,
   2361	SOF_PROCESS_TOKENS,
   2362	SOF_COMP_TOKENS,
   2363};
   2364
   2365static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = {
   2366	[snd_soc_dapm_aif_in] =  {sof_ipc3_widget_setup_comp_host, sof_ipc3_widget_free_comp,
   2367				  host_token_list, ARRAY_SIZE(host_token_list), NULL},
   2368	[snd_soc_dapm_aif_out] = {sof_ipc3_widget_setup_comp_host, sof_ipc3_widget_free_comp,
   2369				  host_token_list, ARRAY_SIZE(host_token_list), NULL},
   2370
   2371	[snd_soc_dapm_dai_in] = {sof_ipc3_widget_setup_comp_dai, sof_ipc3_widget_free_comp_dai,
   2372				 dai_token_list, ARRAY_SIZE(dai_token_list), NULL},
   2373	[snd_soc_dapm_dai_out] = {sof_ipc3_widget_setup_comp_dai, sof_ipc3_widget_free_comp_dai,
   2374				  dai_token_list, ARRAY_SIZE(dai_token_list), NULL},
   2375	[snd_soc_dapm_buffer] = {sof_ipc3_widget_setup_comp_buffer, sof_ipc3_widget_free_comp,
   2376				 buffer_token_list, ARRAY_SIZE(buffer_token_list), NULL},
   2377	[snd_soc_dapm_mixer] = {sof_ipc3_widget_setup_comp_mixer, sof_ipc3_widget_free_comp,
   2378				comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list),
   2379				NULL},
   2380	[snd_soc_dapm_src] = {sof_ipc3_widget_setup_comp_src, sof_ipc3_widget_free_comp,
   2381			      src_token_list, ARRAY_SIZE(src_token_list), NULL},
   2382	[snd_soc_dapm_asrc] = {sof_ipc3_widget_setup_comp_asrc, sof_ipc3_widget_free_comp,
   2383			       asrc_token_list, ARRAY_SIZE(asrc_token_list), NULL},
   2384	[snd_soc_dapm_siggen] = {sof_ipc3_widget_setup_comp_tone, sof_ipc3_widget_free_comp,
   2385				 comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list),
   2386				 NULL},
   2387	[snd_soc_dapm_scheduler] = {sof_ipc3_widget_setup_comp_pipeline, sof_ipc3_widget_free_comp,
   2388				    pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL},
   2389	[snd_soc_dapm_pga] = {sof_ipc3_widget_setup_comp_pga, sof_ipc3_widget_free_comp,
   2390			      pga_token_list, ARRAY_SIZE(pga_token_list), NULL},
   2391	[snd_soc_dapm_mux] = {sof_ipc3_widget_setup_comp_mux, sof_ipc3_widget_free_comp,
   2392			      comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list), NULL},
   2393	[snd_soc_dapm_demux] = {sof_ipc3_widget_setup_comp_mux, sof_ipc3_widget_free_comp,
   2394				 comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list),
   2395				 NULL},
   2396	[snd_soc_dapm_effect] = {sof_widget_update_ipc_comp_process, sof_ipc3_widget_free_comp,
   2397				 process_token_list, ARRAY_SIZE(process_token_list),
   2398				 sof_ipc3_widget_bind_event},
   2399};
   2400
   2401const struct sof_ipc_tplg_ops ipc3_tplg_ops = {
   2402	.widget = tplg_ipc3_widget_ops,
   2403	.control = &tplg_ipc3_control_ops,
   2404	.route_setup = sof_ipc3_route_setup,
   2405	.control_setup = sof_ipc3_control_setup,
   2406	.control_free = sof_ipc3_control_free,
   2407	.pipeline_complete = sof_ipc3_complete_pipeline,
   2408	.token_list = ipc3_token_list,
   2409	.widget_free = sof_ipc3_widget_free,
   2410	.widget_setup = sof_ipc3_widget_setup,
   2411	.dai_config = sof_ipc3_dai_config,
   2412	.dai_get_clk = sof_ipc3_dai_get_clk,
   2413	.set_up_all_pipelines = sof_ipc3_set_up_all_pipelines,
   2414	.tear_down_all_pipelines = sof_ipc3_tear_down_all_pipelines,
   2415};