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