18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * skl-topology.c - Implements Platform component ALSA controls/widget 48c2ecf20Sopenharmony_ci * handlers. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2014-2015 Intel Corp 78c2ecf20Sopenharmony_ci * Author: Jeeja KP <jeeja.kp@intel.com> 88c2ecf20Sopenharmony_ci * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/types.h> 138c2ecf20Sopenharmony_ci#include <linux/firmware.h> 148c2ecf20Sopenharmony_ci#include <linux/uuid.h> 158c2ecf20Sopenharmony_ci#include <sound/intel-nhlt.h> 168c2ecf20Sopenharmony_ci#include <sound/soc.h> 178c2ecf20Sopenharmony_ci#include <sound/soc-acpi.h> 188c2ecf20Sopenharmony_ci#include <sound/soc-topology.h> 198c2ecf20Sopenharmony_ci#include <uapi/sound/snd_sst_tokens.h> 208c2ecf20Sopenharmony_ci#include <uapi/sound/skl-tplg-interface.h> 218c2ecf20Sopenharmony_ci#include "skl-sst-dsp.h" 228c2ecf20Sopenharmony_ci#include "skl-sst-ipc.h" 238c2ecf20Sopenharmony_ci#include "skl-topology.h" 248c2ecf20Sopenharmony_ci#include "skl.h" 258c2ecf20Sopenharmony_ci#include "../common/sst-dsp.h" 268c2ecf20Sopenharmony_ci#include "../common/sst-dsp-priv.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define SKL_CH_FIXUP_MASK (1 << 0) 298c2ecf20Sopenharmony_ci#define SKL_RATE_FIXUP_MASK (1 << 1) 308c2ecf20Sopenharmony_ci#define SKL_FMT_FIXUP_MASK (1 << 2) 318c2ecf20Sopenharmony_ci#define SKL_IN_DIR_BIT_MASK BIT(0) 328c2ecf20Sopenharmony_ci#define SKL_PIN_COUNT_MASK GENMASK(7, 4) 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic const int mic_mono_list[] = { 358c2ecf20Sopenharmony_ci0, 1, 2, 3, 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_cistatic const int mic_stereo_list[][SKL_CH_STEREO] = { 388c2ecf20Sopenharmony_ci{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}, 398c2ecf20Sopenharmony_ci}; 408c2ecf20Sopenharmony_cistatic const int mic_trio_list[][SKL_CH_TRIO] = { 418c2ecf20Sopenharmony_ci{0, 1, 2}, {0, 1, 3}, {0, 2, 3}, {1, 2, 3}, 428c2ecf20Sopenharmony_ci}; 438c2ecf20Sopenharmony_cistatic const int mic_quatro_list[][SKL_CH_QUATRO] = { 448c2ecf20Sopenharmony_ci{0, 1, 2, 3}, 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define CHECK_HW_PARAMS(ch, freq, bps, prm_ch, prm_freq, prm_bps) \ 488c2ecf20Sopenharmony_ci ((ch == prm_ch) && (bps == prm_bps) && (freq == prm_freq)) 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_civoid skl_tplg_d0i3_get(struct skl_dev *skl, enum d0i3_capability caps) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci struct skl_d0i3_data *d0i3 = &skl->d0i3; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci switch (caps) { 558c2ecf20Sopenharmony_ci case SKL_D0I3_NONE: 568c2ecf20Sopenharmony_ci d0i3->non_d0i3++; 578c2ecf20Sopenharmony_ci break; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci case SKL_D0I3_STREAMING: 608c2ecf20Sopenharmony_ci d0i3->streaming++; 618c2ecf20Sopenharmony_ci break; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci case SKL_D0I3_NON_STREAMING: 648c2ecf20Sopenharmony_ci d0i3->non_streaming++; 658c2ecf20Sopenharmony_ci break; 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_civoid skl_tplg_d0i3_put(struct skl_dev *skl, enum d0i3_capability caps) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci struct skl_d0i3_data *d0i3 = &skl->d0i3; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci switch (caps) { 748c2ecf20Sopenharmony_ci case SKL_D0I3_NONE: 758c2ecf20Sopenharmony_ci d0i3->non_d0i3--; 768c2ecf20Sopenharmony_ci break; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci case SKL_D0I3_STREAMING: 798c2ecf20Sopenharmony_ci d0i3->streaming--; 808c2ecf20Sopenharmony_ci break; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci case SKL_D0I3_NON_STREAMING: 838c2ecf20Sopenharmony_ci d0i3->non_streaming--; 848c2ecf20Sopenharmony_ci break; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci/* 898c2ecf20Sopenharmony_ci * SKL DSP driver modelling uses only few DAPM widgets so for rest we will 908c2ecf20Sopenharmony_ci * ignore. This helpers checks if the SKL driver handles this widget type 918c2ecf20Sopenharmony_ci */ 928c2ecf20Sopenharmony_cistatic int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w, 938c2ecf20Sopenharmony_ci struct device *dev) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci if (w->dapm->dev != dev) 968c2ecf20Sopenharmony_ci return false; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci switch (w->id) { 998c2ecf20Sopenharmony_ci case snd_soc_dapm_dai_link: 1008c2ecf20Sopenharmony_ci case snd_soc_dapm_dai_in: 1018c2ecf20Sopenharmony_ci case snd_soc_dapm_aif_in: 1028c2ecf20Sopenharmony_ci case snd_soc_dapm_aif_out: 1038c2ecf20Sopenharmony_ci case snd_soc_dapm_dai_out: 1048c2ecf20Sopenharmony_ci case snd_soc_dapm_switch: 1058c2ecf20Sopenharmony_ci case snd_soc_dapm_output: 1068c2ecf20Sopenharmony_ci case snd_soc_dapm_mux: 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci return false; 1098c2ecf20Sopenharmony_ci default: 1108c2ecf20Sopenharmony_ci return true; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic void skl_dump_mconfig(struct skl_dev *skl, struct skl_module_cfg *mcfg) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci struct skl_module_iface *iface = &mcfg->module->formats[mcfg->fmt_idx]; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "Dumping config\n"); 1198c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "Input Format:\n"); 1208c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "channels = %d\n", iface->inputs[0].fmt.channels); 1218c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "s_freq = %d\n", iface->inputs[0].fmt.s_freq); 1228c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "ch_cfg = %d\n", iface->inputs[0].fmt.ch_cfg); 1238c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "valid bit depth = %d\n", 1248c2ecf20Sopenharmony_ci iface->inputs[0].fmt.valid_bit_depth); 1258c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "Output Format:\n"); 1268c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "channels = %d\n", iface->outputs[0].fmt.channels); 1278c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "s_freq = %d\n", iface->outputs[0].fmt.s_freq); 1288c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "valid bit depth = %d\n", 1298c2ecf20Sopenharmony_ci iface->outputs[0].fmt.valid_bit_depth); 1308c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "ch_cfg = %d\n", iface->outputs[0].fmt.ch_cfg); 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci int slot_map = 0xFFFFFFFF; 1368c2ecf20Sopenharmony_ci int start_slot = 0; 1378c2ecf20Sopenharmony_ci int i; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci for (i = 0; i < chs; i++) { 1408c2ecf20Sopenharmony_ci /* 1418c2ecf20Sopenharmony_ci * For 2 channels with starting slot as 0, slot map will 1428c2ecf20Sopenharmony_ci * look like 0xFFFFFF10. 1438c2ecf20Sopenharmony_ci */ 1448c2ecf20Sopenharmony_ci slot_map &= (~(0xF << (4 * i)) | (start_slot << (4 * i))); 1458c2ecf20Sopenharmony_ci start_slot++; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci fmt->ch_map = slot_map; 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic void skl_tplg_update_params(struct skl_module_fmt *fmt, 1518c2ecf20Sopenharmony_ci struct skl_pipe_params *params, int fixup) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci if (fixup & SKL_RATE_FIXUP_MASK) 1548c2ecf20Sopenharmony_ci fmt->s_freq = params->s_freq; 1558c2ecf20Sopenharmony_ci if (fixup & SKL_CH_FIXUP_MASK) { 1568c2ecf20Sopenharmony_ci fmt->channels = params->ch; 1578c2ecf20Sopenharmony_ci skl_tplg_update_chmap(fmt, fmt->channels); 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci if (fixup & SKL_FMT_FIXUP_MASK) { 1608c2ecf20Sopenharmony_ci fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* 1638c2ecf20Sopenharmony_ci * 16 bit is 16 bit container whereas 24 bit is in 32 bit 1648c2ecf20Sopenharmony_ci * container so update bit depth accordingly 1658c2ecf20Sopenharmony_ci */ 1668c2ecf20Sopenharmony_ci switch (fmt->valid_bit_depth) { 1678c2ecf20Sopenharmony_ci case SKL_DEPTH_16BIT: 1688c2ecf20Sopenharmony_ci fmt->bit_depth = fmt->valid_bit_depth; 1698c2ecf20Sopenharmony_ci break; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci default: 1728c2ecf20Sopenharmony_ci fmt->bit_depth = SKL_DEPTH_32BIT; 1738c2ecf20Sopenharmony_ci break; 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci/* 1808c2ecf20Sopenharmony_ci * A pipeline may have modules which impact the pcm parameters, like SRC, 1818c2ecf20Sopenharmony_ci * channel converter, format converter. 1828c2ecf20Sopenharmony_ci * We need to calculate the output params by applying the 'fixup' 1838c2ecf20Sopenharmony_ci * Topology will tell driver which type of fixup is to be applied by 1848c2ecf20Sopenharmony_ci * supplying the fixup mask, so based on that we calculate the output 1858c2ecf20Sopenharmony_ci * 1868c2ecf20Sopenharmony_ci * Now In FE the pcm hw_params is source/target format. Same is applicable 1878c2ecf20Sopenharmony_ci * for BE with its hw_params invoked. 1888c2ecf20Sopenharmony_ci * here based on FE, BE pipeline and direction we calculate the input and 1898c2ecf20Sopenharmony_ci * outfix and then apply that for a module 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_cistatic void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg, 1928c2ecf20Sopenharmony_ci struct skl_pipe_params *params, bool is_fe) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci int in_fixup, out_fixup; 1958c2ecf20Sopenharmony_ci struct skl_module_fmt *in_fmt, *out_fmt; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci /* Fixups will be applied to pin 0 only */ 1988c2ecf20Sopenharmony_ci in_fmt = &m_cfg->module->formats[m_cfg->fmt_idx].inputs[0].fmt; 1998c2ecf20Sopenharmony_ci out_fmt = &m_cfg->module->formats[m_cfg->fmt_idx].outputs[0].fmt; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { 2028c2ecf20Sopenharmony_ci if (is_fe) { 2038c2ecf20Sopenharmony_ci in_fixup = m_cfg->params_fixup; 2048c2ecf20Sopenharmony_ci out_fixup = (~m_cfg->converter) & 2058c2ecf20Sopenharmony_ci m_cfg->params_fixup; 2068c2ecf20Sopenharmony_ci } else { 2078c2ecf20Sopenharmony_ci out_fixup = m_cfg->params_fixup; 2088c2ecf20Sopenharmony_ci in_fixup = (~m_cfg->converter) & 2098c2ecf20Sopenharmony_ci m_cfg->params_fixup; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci } else { 2128c2ecf20Sopenharmony_ci if (is_fe) { 2138c2ecf20Sopenharmony_ci out_fixup = m_cfg->params_fixup; 2148c2ecf20Sopenharmony_ci in_fixup = (~m_cfg->converter) & 2158c2ecf20Sopenharmony_ci m_cfg->params_fixup; 2168c2ecf20Sopenharmony_ci } else { 2178c2ecf20Sopenharmony_ci in_fixup = m_cfg->params_fixup; 2188c2ecf20Sopenharmony_ci out_fixup = (~m_cfg->converter) & 2198c2ecf20Sopenharmony_ci m_cfg->params_fixup; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci skl_tplg_update_params(in_fmt, params, in_fixup); 2248c2ecf20Sopenharmony_ci skl_tplg_update_params(out_fmt, params, out_fixup); 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci/* 2288c2ecf20Sopenharmony_ci * A module needs input and output buffers, which are dependent upon pcm 2298c2ecf20Sopenharmony_ci * params, so once we have calculate params, we need buffer calculation as 2308c2ecf20Sopenharmony_ci * well. 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_cistatic void skl_tplg_update_buffer_size(struct skl_dev *skl, 2338c2ecf20Sopenharmony_ci struct skl_module_cfg *mcfg) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci int multiplier = 1; 2368c2ecf20Sopenharmony_ci struct skl_module_fmt *in_fmt, *out_fmt; 2378c2ecf20Sopenharmony_ci struct skl_module_res *res; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci /* Since fixups is applied to pin 0 only, ibs, obs needs 2408c2ecf20Sopenharmony_ci * change for pin 0 only 2418c2ecf20Sopenharmony_ci */ 2428c2ecf20Sopenharmony_ci res = &mcfg->module->resources[mcfg->res_idx]; 2438c2ecf20Sopenharmony_ci in_fmt = &mcfg->module->formats[mcfg->fmt_idx].inputs[0].fmt; 2448c2ecf20Sopenharmony_ci out_fmt = &mcfg->module->formats[mcfg->fmt_idx].outputs[0].fmt; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT) 2478c2ecf20Sopenharmony_ci multiplier = 5; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci res->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) * 2508c2ecf20Sopenharmony_ci in_fmt->channels * (in_fmt->bit_depth >> 3) * 2518c2ecf20Sopenharmony_ci multiplier; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci res->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) * 2548c2ecf20Sopenharmony_ci out_fmt->channels * (out_fmt->bit_depth >> 3) * 2558c2ecf20Sopenharmony_ci multiplier; 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic u8 skl_tplg_be_dev_type(int dev_type) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci int ret; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci switch (dev_type) { 2638c2ecf20Sopenharmony_ci case SKL_DEVICE_BT: 2648c2ecf20Sopenharmony_ci ret = NHLT_DEVICE_BT; 2658c2ecf20Sopenharmony_ci break; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci case SKL_DEVICE_DMIC: 2688c2ecf20Sopenharmony_ci ret = NHLT_DEVICE_DMIC; 2698c2ecf20Sopenharmony_ci break; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci case SKL_DEVICE_I2S: 2728c2ecf20Sopenharmony_ci ret = NHLT_DEVICE_I2S; 2738c2ecf20Sopenharmony_ci break; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci default: 2768c2ecf20Sopenharmony_ci ret = NHLT_DEVICE_INVALID; 2778c2ecf20Sopenharmony_ci break; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci return ret; 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, 2848c2ecf20Sopenharmony_ci struct skl_dev *skl) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci struct skl_module_cfg *m_cfg = w->priv; 2878c2ecf20Sopenharmony_ci int link_type, dir; 2888c2ecf20Sopenharmony_ci u32 ch, s_freq, s_fmt; 2898c2ecf20Sopenharmony_ci struct nhlt_specific_cfg *cfg; 2908c2ecf20Sopenharmony_ci u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type); 2918c2ecf20Sopenharmony_ci int fmt_idx = m_cfg->fmt_idx; 2928c2ecf20Sopenharmony_ci struct skl_module_iface *m_iface = &m_cfg->module->formats[fmt_idx]; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* check if we already have blob */ 2958c2ecf20Sopenharmony_ci if (m_cfg->formats_config.caps_size > 0) 2968c2ecf20Sopenharmony_ci return 0; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "Applying default cfg blob\n"); 2998c2ecf20Sopenharmony_ci switch (m_cfg->dev_type) { 3008c2ecf20Sopenharmony_ci case SKL_DEVICE_DMIC: 3018c2ecf20Sopenharmony_ci link_type = NHLT_LINK_DMIC; 3028c2ecf20Sopenharmony_ci dir = SNDRV_PCM_STREAM_CAPTURE; 3038c2ecf20Sopenharmony_ci s_freq = m_iface->inputs[0].fmt.s_freq; 3048c2ecf20Sopenharmony_ci s_fmt = m_iface->inputs[0].fmt.bit_depth; 3058c2ecf20Sopenharmony_ci ch = m_iface->inputs[0].fmt.channels; 3068c2ecf20Sopenharmony_ci break; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci case SKL_DEVICE_I2S: 3098c2ecf20Sopenharmony_ci link_type = NHLT_LINK_SSP; 3108c2ecf20Sopenharmony_ci if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) { 3118c2ecf20Sopenharmony_ci dir = SNDRV_PCM_STREAM_PLAYBACK; 3128c2ecf20Sopenharmony_ci s_freq = m_iface->outputs[0].fmt.s_freq; 3138c2ecf20Sopenharmony_ci s_fmt = m_iface->outputs[0].fmt.bit_depth; 3148c2ecf20Sopenharmony_ci ch = m_iface->outputs[0].fmt.channels; 3158c2ecf20Sopenharmony_ci } else { 3168c2ecf20Sopenharmony_ci dir = SNDRV_PCM_STREAM_CAPTURE; 3178c2ecf20Sopenharmony_ci s_freq = m_iface->inputs[0].fmt.s_freq; 3188c2ecf20Sopenharmony_ci s_fmt = m_iface->inputs[0].fmt.bit_depth; 3198c2ecf20Sopenharmony_ci ch = m_iface->inputs[0].fmt.channels; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci break; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci default: 3248c2ecf20Sopenharmony_ci return -EINVAL; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* update the blob based on virtual bus_id and default params */ 3288c2ecf20Sopenharmony_ci cfg = skl_get_ep_blob(skl, m_cfg->vbus_id, link_type, 3298c2ecf20Sopenharmony_ci s_fmt, ch, s_freq, dir, dev_type); 3308c2ecf20Sopenharmony_ci if (cfg) { 3318c2ecf20Sopenharmony_ci m_cfg->formats_config.caps_size = cfg->size; 3328c2ecf20Sopenharmony_ci m_cfg->formats_config.caps = (u32 *) &cfg->caps; 3338c2ecf20Sopenharmony_ci } else { 3348c2ecf20Sopenharmony_ci dev_err(skl->dev, "Blob NULL for id %x type %d dirn %d\n", 3358c2ecf20Sopenharmony_ci m_cfg->vbus_id, link_type, dir); 3368c2ecf20Sopenharmony_ci dev_err(skl->dev, "PCM: ch %d, freq %d, fmt %d\n", 3378c2ecf20Sopenharmony_ci ch, s_freq, s_fmt); 3388c2ecf20Sopenharmony_ci return -EIO; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci return 0; 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w, 3458c2ecf20Sopenharmony_ci struct skl_dev *skl) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci struct skl_module_cfg *m_cfg = w->priv; 3488c2ecf20Sopenharmony_ci struct skl_pipe_params *params = m_cfg->pipe->p_params; 3498c2ecf20Sopenharmony_ci int p_conn_type = m_cfg->pipe->conn_type; 3508c2ecf20Sopenharmony_ci bool is_fe; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci if (!m_cfg->params_fixup) 3538c2ecf20Sopenharmony_ci return; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "Mconfig for widget=%s BEFORE updation\n", 3568c2ecf20Sopenharmony_ci w->name); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci skl_dump_mconfig(skl, m_cfg); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci if (p_conn_type == SKL_PIPE_CONN_TYPE_FE) 3618c2ecf20Sopenharmony_ci is_fe = true; 3628c2ecf20Sopenharmony_ci else 3638c2ecf20Sopenharmony_ci is_fe = false; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci skl_tplg_update_params_fixup(m_cfg, params, is_fe); 3668c2ecf20Sopenharmony_ci skl_tplg_update_buffer_size(skl, m_cfg); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "Mconfig for widget=%s AFTER updation\n", 3698c2ecf20Sopenharmony_ci w->name); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci skl_dump_mconfig(skl, m_cfg); 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci/* 3758c2ecf20Sopenharmony_ci * some modules can have multiple params set from user control and 3768c2ecf20Sopenharmony_ci * need to be set after module is initialized. If set_param flag is 3778c2ecf20Sopenharmony_ci * set module params will be done after module is initialised. 3788c2ecf20Sopenharmony_ci */ 3798c2ecf20Sopenharmony_cistatic int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w, 3808c2ecf20Sopenharmony_ci struct skl_dev *skl) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci int i, ret; 3838c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig = w->priv; 3848c2ecf20Sopenharmony_ci const struct snd_kcontrol_new *k; 3858c2ecf20Sopenharmony_ci struct soc_bytes_ext *sb; 3868c2ecf20Sopenharmony_ci struct skl_algo_data *bc; 3878c2ecf20Sopenharmony_ci struct skl_specific_cfg *sp_cfg; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci if (mconfig->formats_config.caps_size > 0 && 3908c2ecf20Sopenharmony_ci mconfig->formats_config.set_params == SKL_PARAM_SET) { 3918c2ecf20Sopenharmony_ci sp_cfg = &mconfig->formats_config; 3928c2ecf20Sopenharmony_ci ret = skl_set_module_params(skl, sp_cfg->caps, 3938c2ecf20Sopenharmony_ci sp_cfg->caps_size, 3948c2ecf20Sopenharmony_ci sp_cfg->param_id, mconfig); 3958c2ecf20Sopenharmony_ci if (ret < 0) 3968c2ecf20Sopenharmony_ci return ret; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci for (i = 0; i < w->num_kcontrols; i++) { 4008c2ecf20Sopenharmony_ci k = &w->kcontrol_news[i]; 4018c2ecf20Sopenharmony_ci if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 4028c2ecf20Sopenharmony_ci sb = (void *) k->private_value; 4038c2ecf20Sopenharmony_ci bc = (struct skl_algo_data *)sb->dobj.private; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (bc->set_params == SKL_PARAM_SET) { 4068c2ecf20Sopenharmony_ci ret = skl_set_module_params(skl, 4078c2ecf20Sopenharmony_ci (u32 *)bc->params, bc->size, 4088c2ecf20Sopenharmony_ci bc->param_id, mconfig); 4098c2ecf20Sopenharmony_ci if (ret < 0) 4108c2ecf20Sopenharmony_ci return ret; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci return 0; 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci/* 4198c2ecf20Sopenharmony_ci * some module param can set from user control and this is required as 4208c2ecf20Sopenharmony_ci * when module is initailzed. if module param is required in init it is 4218c2ecf20Sopenharmony_ci * identifed by set_param flag. if set_param flag is not set, then this 4228c2ecf20Sopenharmony_ci * parameter needs to set as part of module init. 4238c2ecf20Sopenharmony_ci */ 4248c2ecf20Sopenharmony_cistatic int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci const struct snd_kcontrol_new *k; 4278c2ecf20Sopenharmony_ci struct soc_bytes_ext *sb; 4288c2ecf20Sopenharmony_ci struct skl_algo_data *bc; 4298c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig = w->priv; 4308c2ecf20Sopenharmony_ci int i; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci for (i = 0; i < w->num_kcontrols; i++) { 4338c2ecf20Sopenharmony_ci k = &w->kcontrol_news[i]; 4348c2ecf20Sopenharmony_ci if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 4358c2ecf20Sopenharmony_ci sb = (struct soc_bytes_ext *)k->private_value; 4368c2ecf20Sopenharmony_ci bc = (struct skl_algo_data *)sb->dobj.private; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (bc->set_params != SKL_PARAM_INIT) 4398c2ecf20Sopenharmony_ci continue; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci mconfig->formats_config.caps = (u32 *)bc->params; 4428c2ecf20Sopenharmony_ci mconfig->formats_config.caps_size = bc->size; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci break; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci return 0; 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_cistatic int skl_tplg_module_prepare(struct skl_dev *skl, struct skl_pipe *pipe, 4528c2ecf20Sopenharmony_ci struct snd_soc_dapm_widget *w, struct skl_module_cfg *mcfg) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci switch (mcfg->dev_type) { 4558c2ecf20Sopenharmony_ci case SKL_DEVICE_HDAHOST: 4568c2ecf20Sopenharmony_ci return skl_pcm_host_dma_prepare(skl->dev, pipe->p_params); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci case SKL_DEVICE_HDALINK: 4598c2ecf20Sopenharmony_ci return skl_pcm_link_dma_prepare(skl->dev, pipe->p_params); 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci return 0; 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci/* 4668c2ecf20Sopenharmony_ci * Inside a pipe instance, we can have various modules. These modules need 4678c2ecf20Sopenharmony_ci * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by 4688c2ecf20Sopenharmony_ci * skl_init_module() routine, so invoke that for all modules in a pipeline 4698c2ecf20Sopenharmony_ci */ 4708c2ecf20Sopenharmony_cistatic int 4718c2ecf20Sopenharmony_ciskl_tplg_init_pipe_modules(struct skl_dev *skl, struct skl_pipe *pipe) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci struct skl_pipe_module *w_module; 4748c2ecf20Sopenharmony_ci struct snd_soc_dapm_widget *w; 4758c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig; 4768c2ecf20Sopenharmony_ci u8 cfg_idx; 4778c2ecf20Sopenharmony_ci int ret = 0; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci list_for_each_entry(w_module, &pipe->w_list, node) { 4808c2ecf20Sopenharmony_ci guid_t *uuid_mod; 4818c2ecf20Sopenharmony_ci w = w_module->w; 4828c2ecf20Sopenharmony_ci mconfig = w->priv; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci /* check if module ids are populated */ 4858c2ecf20Sopenharmony_ci if (mconfig->id.module_id < 0) { 4868c2ecf20Sopenharmony_ci dev_err(skl->dev, 4878c2ecf20Sopenharmony_ci "module %pUL id not populated\n", 4888c2ecf20Sopenharmony_ci (guid_t *)mconfig->guid); 4898c2ecf20Sopenharmony_ci return -EIO; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci cfg_idx = mconfig->pipe->cur_config_idx; 4938c2ecf20Sopenharmony_ci mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx; 4948c2ecf20Sopenharmony_ci mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (mconfig->module->loadable && skl->dsp->fw_ops.load_mod) { 4978c2ecf20Sopenharmony_ci ret = skl->dsp->fw_ops.load_mod(skl->dsp, 4988c2ecf20Sopenharmony_ci mconfig->id.module_id, mconfig->guid); 4998c2ecf20Sopenharmony_ci if (ret < 0) 5008c2ecf20Sopenharmony_ci return ret; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci mconfig->m_state = SKL_MODULE_LOADED; 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* prepare the DMA if the module is gateway cpr */ 5068c2ecf20Sopenharmony_ci ret = skl_tplg_module_prepare(skl, pipe, w, mconfig); 5078c2ecf20Sopenharmony_ci if (ret < 0) 5088c2ecf20Sopenharmony_ci return ret; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci /* update blob if blob is null for be with default value */ 5118c2ecf20Sopenharmony_ci skl_tplg_update_be_blob(w, skl); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci /* 5148c2ecf20Sopenharmony_ci * apply fix/conversion to module params based on 5158c2ecf20Sopenharmony_ci * FE/BE params 5168c2ecf20Sopenharmony_ci */ 5178c2ecf20Sopenharmony_ci skl_tplg_update_module_params(w, skl); 5188c2ecf20Sopenharmony_ci uuid_mod = (guid_t *)mconfig->guid; 5198c2ecf20Sopenharmony_ci mconfig->id.pvt_id = skl_get_pvt_id(skl, uuid_mod, 5208c2ecf20Sopenharmony_ci mconfig->id.instance_id); 5218c2ecf20Sopenharmony_ci if (mconfig->id.pvt_id < 0) 5228c2ecf20Sopenharmony_ci return ret; 5238c2ecf20Sopenharmony_ci skl_tplg_set_module_init_data(w); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci ret = skl_dsp_get_core(skl->dsp, mconfig->core_id); 5268c2ecf20Sopenharmony_ci if (ret < 0) { 5278c2ecf20Sopenharmony_ci dev_err(skl->dev, "Failed to wake up core %d ret=%d\n", 5288c2ecf20Sopenharmony_ci mconfig->core_id, ret); 5298c2ecf20Sopenharmony_ci return ret; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci ret = skl_init_module(skl, mconfig); 5338c2ecf20Sopenharmony_ci if (ret < 0) { 5348c2ecf20Sopenharmony_ci skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id); 5358c2ecf20Sopenharmony_ci goto err; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci ret = skl_tplg_set_module_params(w, skl); 5398c2ecf20Sopenharmony_ci if (ret < 0) 5408c2ecf20Sopenharmony_ci goto err; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci return 0; 5448c2ecf20Sopenharmony_cierr: 5458c2ecf20Sopenharmony_ci skl_dsp_put_core(skl->dsp, mconfig->core_id); 5468c2ecf20Sopenharmony_ci return ret; 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_cistatic int skl_tplg_unload_pipe_modules(struct skl_dev *skl, 5508c2ecf20Sopenharmony_ci struct skl_pipe *pipe) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci int ret = 0; 5538c2ecf20Sopenharmony_ci struct skl_pipe_module *w_module; 5548c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci list_for_each_entry(w_module, &pipe->w_list, node) { 5578c2ecf20Sopenharmony_ci guid_t *uuid_mod; 5588c2ecf20Sopenharmony_ci mconfig = w_module->w->priv; 5598c2ecf20Sopenharmony_ci uuid_mod = (guid_t *)mconfig->guid; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci if (mconfig->module->loadable && skl->dsp->fw_ops.unload_mod && 5628c2ecf20Sopenharmony_ci mconfig->m_state > SKL_MODULE_UNINIT) { 5638c2ecf20Sopenharmony_ci ret = skl->dsp->fw_ops.unload_mod(skl->dsp, 5648c2ecf20Sopenharmony_ci mconfig->id.module_id); 5658c2ecf20Sopenharmony_ci if (ret < 0) 5668c2ecf20Sopenharmony_ci return -EIO; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci ret = skl_dsp_put_core(skl->dsp, mconfig->core_id); 5718c2ecf20Sopenharmony_ci if (ret < 0) { 5728c2ecf20Sopenharmony_ci /* don't return; continue with other modules */ 5738c2ecf20Sopenharmony_ci dev_err(skl->dev, "Failed to sleep core %d ret=%d\n", 5748c2ecf20Sopenharmony_ci mconfig->core_id, ret); 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci /* no modules to unload in this path, so return */ 5798c2ecf20Sopenharmony_ci return ret; 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_cistatic bool skl_tplg_is_multi_fmt(struct skl_dev *skl, struct skl_pipe *pipe) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci struct skl_pipe_fmt *cur_fmt; 5858c2ecf20Sopenharmony_ci struct skl_pipe_fmt *next_fmt; 5868c2ecf20Sopenharmony_ci int i; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (pipe->nr_cfgs <= 1) 5898c2ecf20Sopenharmony_ci return false; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci if (pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) 5928c2ecf20Sopenharmony_ci return true; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci for (i = 0; i < pipe->nr_cfgs - 1; i++) { 5958c2ecf20Sopenharmony_ci if (pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) { 5968c2ecf20Sopenharmony_ci cur_fmt = &pipe->configs[i].out_fmt; 5978c2ecf20Sopenharmony_ci next_fmt = &pipe->configs[i + 1].out_fmt; 5988c2ecf20Sopenharmony_ci } else { 5998c2ecf20Sopenharmony_ci cur_fmt = &pipe->configs[i].in_fmt; 6008c2ecf20Sopenharmony_ci next_fmt = &pipe->configs[i + 1].in_fmt; 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci if (!CHECK_HW_PARAMS(cur_fmt->channels, cur_fmt->freq, 6048c2ecf20Sopenharmony_ci cur_fmt->bps, 6058c2ecf20Sopenharmony_ci next_fmt->channels, 6068c2ecf20Sopenharmony_ci next_fmt->freq, 6078c2ecf20Sopenharmony_ci next_fmt->bps)) 6088c2ecf20Sopenharmony_ci return true; 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci return false; 6128c2ecf20Sopenharmony_ci} 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci/* 6158c2ecf20Sopenharmony_ci * Here, we select pipe format based on the pipe type and pipe 6168c2ecf20Sopenharmony_ci * direction to determine the current config index for the pipeline. 6178c2ecf20Sopenharmony_ci * The config index is then used to select proper module resources. 6188c2ecf20Sopenharmony_ci * Intermediate pipes currently have a fixed format hence we select the 6198c2ecf20Sopenharmony_ci * 0th configuratation by default for such pipes. 6208c2ecf20Sopenharmony_ci */ 6218c2ecf20Sopenharmony_cistatic int 6228c2ecf20Sopenharmony_ciskl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci struct skl_pipe *pipe = mconfig->pipe; 6258c2ecf20Sopenharmony_ci struct skl_pipe_params *params = pipe->p_params; 6268c2ecf20Sopenharmony_ci struct skl_path_config *pconfig = &pipe->configs[0]; 6278c2ecf20Sopenharmony_ci struct skl_pipe_fmt *fmt = NULL; 6288c2ecf20Sopenharmony_ci bool in_fmt = false; 6298c2ecf20Sopenharmony_ci int i; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci if (pipe->nr_cfgs == 0) { 6328c2ecf20Sopenharmony_ci pipe->cur_config_idx = 0; 6338c2ecf20Sopenharmony_ci return 0; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci if (skl_tplg_is_multi_fmt(skl, pipe)) { 6378c2ecf20Sopenharmony_ci pipe->cur_config_idx = pipe->pipe_config_idx; 6388c2ecf20Sopenharmony_ci pipe->memory_pages = pconfig->mem_pages; 6398c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "found pipe config idx:%d\n", 6408c2ecf20Sopenharmony_ci pipe->cur_config_idx); 6418c2ecf20Sopenharmony_ci return 0; 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE) { 6458c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "No conn_type detected, take 0th config\n"); 6468c2ecf20Sopenharmony_ci pipe->cur_config_idx = 0; 6478c2ecf20Sopenharmony_ci pipe->memory_pages = pconfig->mem_pages; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci return 0; 6508c2ecf20Sopenharmony_ci } 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci if ((pipe->conn_type == SKL_PIPE_CONN_TYPE_FE && 6538c2ecf20Sopenharmony_ci pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) || 6548c2ecf20Sopenharmony_ci (pipe->conn_type == SKL_PIPE_CONN_TYPE_BE && 6558c2ecf20Sopenharmony_ci pipe->direction == SNDRV_PCM_STREAM_CAPTURE)) 6568c2ecf20Sopenharmony_ci in_fmt = true; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci for (i = 0; i < pipe->nr_cfgs; i++) { 6598c2ecf20Sopenharmony_ci pconfig = &pipe->configs[i]; 6608c2ecf20Sopenharmony_ci if (in_fmt) 6618c2ecf20Sopenharmony_ci fmt = &pconfig->in_fmt; 6628c2ecf20Sopenharmony_ci else 6638c2ecf20Sopenharmony_ci fmt = &pconfig->out_fmt; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci if (CHECK_HW_PARAMS(params->ch, params->s_freq, params->s_fmt, 6668c2ecf20Sopenharmony_ci fmt->channels, fmt->freq, fmt->bps)) { 6678c2ecf20Sopenharmony_ci pipe->cur_config_idx = i; 6688c2ecf20Sopenharmony_ci pipe->memory_pages = pconfig->mem_pages; 6698c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "Using pipe config: %d\n", i); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci return 0; 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci dev_err(skl->dev, "Invalid pipe config: %d %d %d for pipe: %d\n", 6768c2ecf20Sopenharmony_ci params->ch, params->s_freq, params->s_fmt, pipe->ppl_id); 6778c2ecf20Sopenharmony_ci return -EINVAL; 6788c2ecf20Sopenharmony_ci} 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci/* 6818c2ecf20Sopenharmony_ci * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we 6828c2ecf20Sopenharmony_ci * need create the pipeline. So we do following: 6838c2ecf20Sopenharmony_ci * - Create the pipeline 6848c2ecf20Sopenharmony_ci * - Initialize the modules in pipeline 6858c2ecf20Sopenharmony_ci * - finally bind all modules together 6868c2ecf20Sopenharmony_ci */ 6878c2ecf20Sopenharmony_cistatic int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, 6888c2ecf20Sopenharmony_ci struct skl_dev *skl) 6898c2ecf20Sopenharmony_ci{ 6908c2ecf20Sopenharmony_ci int ret; 6918c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig = w->priv; 6928c2ecf20Sopenharmony_ci struct skl_pipe_module *w_module; 6938c2ecf20Sopenharmony_ci struct skl_pipe *s_pipe = mconfig->pipe; 6948c2ecf20Sopenharmony_ci struct skl_module_cfg *src_module = NULL, *dst_module, *module; 6958c2ecf20Sopenharmony_ci struct skl_module_deferred_bind *modules; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci ret = skl_tplg_get_pipe_config(skl, mconfig); 6988c2ecf20Sopenharmony_ci if (ret < 0) 6998c2ecf20Sopenharmony_ci return ret; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci /* 7028c2ecf20Sopenharmony_ci * Create a list of modules for pipe. 7038c2ecf20Sopenharmony_ci * This list contains modules from source to sink 7048c2ecf20Sopenharmony_ci */ 7058c2ecf20Sopenharmony_ci ret = skl_create_pipeline(skl, mconfig->pipe); 7068c2ecf20Sopenharmony_ci if (ret < 0) 7078c2ecf20Sopenharmony_ci return ret; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci /* Init all pipe modules from source to sink */ 7108c2ecf20Sopenharmony_ci ret = skl_tplg_init_pipe_modules(skl, s_pipe); 7118c2ecf20Sopenharmony_ci if (ret < 0) 7128c2ecf20Sopenharmony_ci return ret; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci /* Bind modules from source to sink */ 7158c2ecf20Sopenharmony_ci list_for_each_entry(w_module, &s_pipe->w_list, node) { 7168c2ecf20Sopenharmony_ci dst_module = w_module->w->priv; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci if (src_module == NULL) { 7198c2ecf20Sopenharmony_ci src_module = dst_module; 7208c2ecf20Sopenharmony_ci continue; 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci ret = skl_bind_modules(skl, src_module, dst_module); 7248c2ecf20Sopenharmony_ci if (ret < 0) 7258c2ecf20Sopenharmony_ci return ret; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci src_module = dst_module; 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci /* 7318c2ecf20Sopenharmony_ci * When the destination module is initialized, check for these modules 7328c2ecf20Sopenharmony_ci * in deferred bind list. If found, bind them. 7338c2ecf20Sopenharmony_ci */ 7348c2ecf20Sopenharmony_ci list_for_each_entry(w_module, &s_pipe->w_list, node) { 7358c2ecf20Sopenharmony_ci if (list_empty(&skl->bind_list)) 7368c2ecf20Sopenharmony_ci break; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci list_for_each_entry(modules, &skl->bind_list, node) { 7398c2ecf20Sopenharmony_ci module = w_module->w->priv; 7408c2ecf20Sopenharmony_ci if (modules->dst == module) 7418c2ecf20Sopenharmony_ci skl_bind_modules(skl, modules->src, 7428c2ecf20Sopenharmony_ci modules->dst); 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci return 0; 7478c2ecf20Sopenharmony_ci} 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_cistatic int skl_fill_sink_instance_id(struct skl_dev *skl, u32 *params, 7508c2ecf20Sopenharmony_ci int size, struct skl_module_cfg *mcfg) 7518c2ecf20Sopenharmony_ci{ 7528c2ecf20Sopenharmony_ci int i, pvt_id; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci if (mcfg->m_type == SKL_MODULE_TYPE_KPB) { 7558c2ecf20Sopenharmony_ci struct skl_kpb_params *kpb_params = 7568c2ecf20Sopenharmony_ci (struct skl_kpb_params *)params; 7578c2ecf20Sopenharmony_ci struct skl_mod_inst_map *inst = kpb_params->u.map; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci for (i = 0; i < kpb_params->num_modules; i++) { 7608c2ecf20Sopenharmony_ci pvt_id = skl_get_pvt_instance_id_map(skl, inst->mod_id, 7618c2ecf20Sopenharmony_ci inst->inst_id); 7628c2ecf20Sopenharmony_ci if (pvt_id < 0) 7638c2ecf20Sopenharmony_ci return -EINVAL; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci inst->inst_id = pvt_id; 7668c2ecf20Sopenharmony_ci inst++; 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci } 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci return 0; 7718c2ecf20Sopenharmony_ci} 7728c2ecf20Sopenharmony_ci/* 7738c2ecf20Sopenharmony_ci * Some modules require params to be set after the module is bound to 7748c2ecf20Sopenharmony_ci * all pins connected. 7758c2ecf20Sopenharmony_ci * 7768c2ecf20Sopenharmony_ci * The module provider initializes set_param flag for such modules and we 7778c2ecf20Sopenharmony_ci * send params after binding 7788c2ecf20Sopenharmony_ci */ 7798c2ecf20Sopenharmony_cistatic int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, 7808c2ecf20Sopenharmony_ci struct skl_module_cfg *mcfg, struct skl_dev *skl) 7818c2ecf20Sopenharmony_ci{ 7828c2ecf20Sopenharmony_ci int i, ret; 7838c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig = w->priv; 7848c2ecf20Sopenharmony_ci const struct snd_kcontrol_new *k; 7858c2ecf20Sopenharmony_ci struct soc_bytes_ext *sb; 7868c2ecf20Sopenharmony_ci struct skl_algo_data *bc; 7878c2ecf20Sopenharmony_ci struct skl_specific_cfg *sp_cfg; 7888c2ecf20Sopenharmony_ci u32 *params; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci /* 7918c2ecf20Sopenharmony_ci * check all out/in pins are in bind state. 7928c2ecf20Sopenharmony_ci * if so set the module param 7938c2ecf20Sopenharmony_ci */ 7948c2ecf20Sopenharmony_ci for (i = 0; i < mcfg->module->max_output_pins; i++) { 7958c2ecf20Sopenharmony_ci if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE) 7968c2ecf20Sopenharmony_ci return 0; 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci for (i = 0; i < mcfg->module->max_input_pins; i++) { 8008c2ecf20Sopenharmony_ci if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE) 8018c2ecf20Sopenharmony_ci return 0; 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci if (mconfig->formats_config.caps_size > 0 && 8058c2ecf20Sopenharmony_ci mconfig->formats_config.set_params == SKL_PARAM_BIND) { 8068c2ecf20Sopenharmony_ci sp_cfg = &mconfig->formats_config; 8078c2ecf20Sopenharmony_ci ret = skl_set_module_params(skl, sp_cfg->caps, 8088c2ecf20Sopenharmony_ci sp_cfg->caps_size, 8098c2ecf20Sopenharmony_ci sp_cfg->param_id, mconfig); 8108c2ecf20Sopenharmony_ci if (ret < 0) 8118c2ecf20Sopenharmony_ci return ret; 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci for (i = 0; i < w->num_kcontrols; i++) { 8158c2ecf20Sopenharmony_ci k = &w->kcontrol_news[i]; 8168c2ecf20Sopenharmony_ci if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 8178c2ecf20Sopenharmony_ci sb = (void *) k->private_value; 8188c2ecf20Sopenharmony_ci bc = (struct skl_algo_data *)sb->dobj.private; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci if (bc->set_params == SKL_PARAM_BIND) { 8218c2ecf20Sopenharmony_ci params = kmemdup(bc->params, bc->max, GFP_KERNEL); 8228c2ecf20Sopenharmony_ci if (!params) 8238c2ecf20Sopenharmony_ci return -ENOMEM; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci skl_fill_sink_instance_id(skl, params, bc->max, 8268c2ecf20Sopenharmony_ci mconfig); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci ret = skl_set_module_params(skl, params, 8298c2ecf20Sopenharmony_ci bc->max, bc->param_id, mconfig); 8308c2ecf20Sopenharmony_ci kfree(params); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci if (ret < 0) 8338c2ecf20Sopenharmony_ci return ret; 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci } 8368c2ecf20Sopenharmony_ci } 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci return 0; 8398c2ecf20Sopenharmony_ci} 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_cistatic int skl_get_module_id(struct skl_dev *skl, guid_t *uuid) 8428c2ecf20Sopenharmony_ci{ 8438c2ecf20Sopenharmony_ci struct uuid_module *module; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci list_for_each_entry(module, &skl->uuid_list, list) { 8468c2ecf20Sopenharmony_ci if (guid_equal(uuid, &module->uuid)) 8478c2ecf20Sopenharmony_ci return module->id; 8488c2ecf20Sopenharmony_ci } 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci return -EINVAL; 8518c2ecf20Sopenharmony_ci} 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_cistatic int skl_tplg_find_moduleid_from_uuid(struct skl_dev *skl, 8548c2ecf20Sopenharmony_ci const struct snd_kcontrol_new *k) 8558c2ecf20Sopenharmony_ci{ 8568c2ecf20Sopenharmony_ci struct soc_bytes_ext *sb = (void *) k->private_value; 8578c2ecf20Sopenharmony_ci struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private; 8588c2ecf20Sopenharmony_ci struct skl_kpb_params *uuid_params, *params; 8598c2ecf20Sopenharmony_ci struct hdac_bus *bus = skl_to_bus(skl); 8608c2ecf20Sopenharmony_ci int i, size, module_id; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci if (bc->set_params == SKL_PARAM_BIND && bc->max) { 8638c2ecf20Sopenharmony_ci uuid_params = (struct skl_kpb_params *)bc->params; 8648c2ecf20Sopenharmony_ci size = struct_size(params, u.map, uuid_params->num_modules); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci params = devm_kzalloc(bus->dev, size, GFP_KERNEL); 8678c2ecf20Sopenharmony_ci if (!params) 8688c2ecf20Sopenharmony_ci return -ENOMEM; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci params->num_modules = uuid_params->num_modules; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci for (i = 0; i < uuid_params->num_modules; i++) { 8738c2ecf20Sopenharmony_ci module_id = skl_get_module_id(skl, 8748c2ecf20Sopenharmony_ci &uuid_params->u.map_uuid[i].mod_uuid); 8758c2ecf20Sopenharmony_ci if (module_id < 0) { 8768c2ecf20Sopenharmony_ci devm_kfree(bus->dev, params); 8778c2ecf20Sopenharmony_ci return -EINVAL; 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci params->u.map[i].mod_id = module_id; 8818c2ecf20Sopenharmony_ci params->u.map[i].inst_id = 8828c2ecf20Sopenharmony_ci uuid_params->u.map_uuid[i].inst_id; 8838c2ecf20Sopenharmony_ci } 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci devm_kfree(bus->dev, bc->params); 8868c2ecf20Sopenharmony_ci bc->params = (char *)params; 8878c2ecf20Sopenharmony_ci bc->max = size; 8888c2ecf20Sopenharmony_ci } 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci return 0; 8918c2ecf20Sopenharmony_ci} 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci/* 8948c2ecf20Sopenharmony_ci * Retrieve the module id from UUID mentioned in the 8958c2ecf20Sopenharmony_ci * post bind params 8968c2ecf20Sopenharmony_ci */ 8978c2ecf20Sopenharmony_civoid skl_tplg_add_moduleid_in_bind_params(struct skl_dev *skl, 8988c2ecf20Sopenharmony_ci struct snd_soc_dapm_widget *w) 8998c2ecf20Sopenharmony_ci{ 9008c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig = w->priv; 9018c2ecf20Sopenharmony_ci int i; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci /* 9048c2ecf20Sopenharmony_ci * Post bind params are used for only for KPB 9058c2ecf20Sopenharmony_ci * to set copier instances to drain the data 9068c2ecf20Sopenharmony_ci * in fast mode 9078c2ecf20Sopenharmony_ci */ 9088c2ecf20Sopenharmony_ci if (mconfig->m_type != SKL_MODULE_TYPE_KPB) 9098c2ecf20Sopenharmony_ci return; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci for (i = 0; i < w->num_kcontrols; i++) 9128c2ecf20Sopenharmony_ci if ((w->kcontrol_news[i].access & 9138c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) && 9148c2ecf20Sopenharmony_ci (skl_tplg_find_moduleid_from_uuid(skl, 9158c2ecf20Sopenharmony_ci &w->kcontrol_news[i]) < 0)) 9168c2ecf20Sopenharmony_ci dev_err(skl->dev, 9178c2ecf20Sopenharmony_ci "%s: invalid kpb post bind params\n", 9188c2ecf20Sopenharmony_ci __func__); 9198c2ecf20Sopenharmony_ci} 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_cistatic int skl_tplg_module_add_deferred_bind(struct skl_dev *skl, 9228c2ecf20Sopenharmony_ci struct skl_module_cfg *src, struct skl_module_cfg *dst) 9238c2ecf20Sopenharmony_ci{ 9248c2ecf20Sopenharmony_ci struct skl_module_deferred_bind *m_list, *modules; 9258c2ecf20Sopenharmony_ci int i; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci /* only supported for module with static pin connection */ 9288c2ecf20Sopenharmony_ci for (i = 0; i < dst->module->max_input_pins; i++) { 9298c2ecf20Sopenharmony_ci struct skl_module_pin *pin = &dst->m_in_pin[i]; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci if (pin->is_dynamic) 9328c2ecf20Sopenharmony_ci continue; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci if ((pin->id.module_id == src->id.module_id) && 9358c2ecf20Sopenharmony_ci (pin->id.instance_id == src->id.instance_id)) { 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci if (!list_empty(&skl->bind_list)) { 9388c2ecf20Sopenharmony_ci list_for_each_entry(modules, &skl->bind_list, node) { 9398c2ecf20Sopenharmony_ci if (modules->src == src && modules->dst == dst) 9408c2ecf20Sopenharmony_ci return 0; 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ci } 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci m_list = kzalloc(sizeof(*m_list), GFP_KERNEL); 9458c2ecf20Sopenharmony_ci if (!m_list) 9468c2ecf20Sopenharmony_ci return -ENOMEM; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci m_list->src = src; 9498c2ecf20Sopenharmony_ci m_list->dst = dst; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci list_add(&m_list->node, &skl->bind_list); 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci } 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci return 0; 9568c2ecf20Sopenharmony_ci} 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_cistatic int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, 9598c2ecf20Sopenharmony_ci struct skl_dev *skl, 9608c2ecf20Sopenharmony_ci struct snd_soc_dapm_widget *src_w, 9618c2ecf20Sopenharmony_ci struct skl_module_cfg *src_mconfig) 9628c2ecf20Sopenharmony_ci{ 9638c2ecf20Sopenharmony_ci struct snd_soc_dapm_path *p; 9648c2ecf20Sopenharmony_ci struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL; 9658c2ecf20Sopenharmony_ci struct skl_module_cfg *sink_mconfig; 9668c2ecf20Sopenharmony_ci int ret; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci snd_soc_dapm_widget_for_each_sink_path(w, p) { 9698c2ecf20Sopenharmony_ci if (!p->connect) 9708c2ecf20Sopenharmony_ci continue; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci dev_dbg(skl->dev, 9738c2ecf20Sopenharmony_ci "%s: src widget=%s\n", __func__, w->name); 9748c2ecf20Sopenharmony_ci dev_dbg(skl->dev, 9758c2ecf20Sopenharmony_ci "%s: sink widget=%s\n", __func__, p->sink->name); 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci next_sink = p->sink; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci if (!is_skl_dsp_widget_type(p->sink, skl->dev)) 9808c2ecf20Sopenharmony_ci return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig); 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci /* 9838c2ecf20Sopenharmony_ci * here we will check widgets in sink pipelines, so that 9848c2ecf20Sopenharmony_ci * can be any widgets type and we are only interested if 9858c2ecf20Sopenharmony_ci * they are ones used for SKL so check that first 9868c2ecf20Sopenharmony_ci */ 9878c2ecf20Sopenharmony_ci if ((p->sink->priv != NULL) && 9888c2ecf20Sopenharmony_ci is_skl_dsp_widget_type(p->sink, skl->dev)) { 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci sink = p->sink; 9918c2ecf20Sopenharmony_ci sink_mconfig = sink->priv; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci /* 9948c2ecf20Sopenharmony_ci * Modules other than PGA leaf can be connected 9958c2ecf20Sopenharmony_ci * directly or via switch to a module in another 9968c2ecf20Sopenharmony_ci * pipeline. EX: reference path 9978c2ecf20Sopenharmony_ci * when the path is enabled, the dst module that needs 9988c2ecf20Sopenharmony_ci * to be bound may not be initialized. if the module is 9998c2ecf20Sopenharmony_ci * not initialized, add these modules in the deferred 10008c2ecf20Sopenharmony_ci * bind list and when the dst module is initialised, 10018c2ecf20Sopenharmony_ci * bind this module to the dst_module in deferred list. 10028c2ecf20Sopenharmony_ci */ 10038c2ecf20Sopenharmony_ci if (((src_mconfig->m_state == SKL_MODULE_INIT_DONE) 10048c2ecf20Sopenharmony_ci && (sink_mconfig->m_state == SKL_MODULE_UNINIT))) { 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci ret = skl_tplg_module_add_deferred_bind(skl, 10078c2ecf20Sopenharmony_ci src_mconfig, sink_mconfig); 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci if (ret < 0) 10108c2ecf20Sopenharmony_ci return ret; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci if (src_mconfig->m_state == SKL_MODULE_UNINIT || 10168c2ecf20Sopenharmony_ci sink_mconfig->m_state == SKL_MODULE_UNINIT) 10178c2ecf20Sopenharmony_ci continue; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci /* Bind source to sink, mixin is always source */ 10208c2ecf20Sopenharmony_ci ret = skl_bind_modules(skl, src_mconfig, sink_mconfig); 10218c2ecf20Sopenharmony_ci if (ret) 10228c2ecf20Sopenharmony_ci return ret; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci /* set module params after bind */ 10258c2ecf20Sopenharmony_ci skl_tplg_set_module_bind_params(src_w, 10268c2ecf20Sopenharmony_ci src_mconfig, skl); 10278c2ecf20Sopenharmony_ci skl_tplg_set_module_bind_params(sink, 10288c2ecf20Sopenharmony_ci sink_mconfig, skl); 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci /* Start sinks pipe first */ 10318c2ecf20Sopenharmony_ci if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) { 10328c2ecf20Sopenharmony_ci if (sink_mconfig->pipe->conn_type != 10338c2ecf20Sopenharmony_ci SKL_PIPE_CONN_TYPE_FE) 10348c2ecf20Sopenharmony_ci ret = skl_run_pipe(skl, 10358c2ecf20Sopenharmony_ci sink_mconfig->pipe); 10368c2ecf20Sopenharmony_ci if (ret) 10378c2ecf20Sopenharmony_ci return ret; 10388c2ecf20Sopenharmony_ci } 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci if (!sink && next_sink) 10438c2ecf20Sopenharmony_ci return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig); 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci return 0; 10468c2ecf20Sopenharmony_ci} 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci/* 10498c2ecf20Sopenharmony_ci * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA 10508c2ecf20Sopenharmony_ci * we need to do following: 10518c2ecf20Sopenharmony_ci * - Bind to sink pipeline 10528c2ecf20Sopenharmony_ci * Since the sink pipes can be running and we don't get mixer event on 10538c2ecf20Sopenharmony_ci * connect for already running mixer, we need to find the sink pipes 10548c2ecf20Sopenharmony_ci * here and bind to them. This way dynamic connect works. 10558c2ecf20Sopenharmony_ci * - Start sink pipeline, if not running 10568c2ecf20Sopenharmony_ci * - Then run current pipe 10578c2ecf20Sopenharmony_ci */ 10588c2ecf20Sopenharmony_cistatic int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, 10598c2ecf20Sopenharmony_ci struct skl_dev *skl) 10608c2ecf20Sopenharmony_ci{ 10618c2ecf20Sopenharmony_ci struct skl_module_cfg *src_mconfig; 10628c2ecf20Sopenharmony_ci int ret = 0; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci src_mconfig = w->priv; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci /* 10678c2ecf20Sopenharmony_ci * find which sink it is connected to, bind with the sink, 10688c2ecf20Sopenharmony_ci * if sink is not started, start sink pipe first, then start 10698c2ecf20Sopenharmony_ci * this pipe 10708c2ecf20Sopenharmony_ci */ 10718c2ecf20Sopenharmony_ci ret = skl_tplg_bind_sinks(w, skl, w, src_mconfig); 10728c2ecf20Sopenharmony_ci if (ret) 10738c2ecf20Sopenharmony_ci return ret; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci /* Start source pipe last after starting all sinks */ 10768c2ecf20Sopenharmony_ci if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) 10778c2ecf20Sopenharmony_ci return skl_run_pipe(skl, src_mconfig->pipe); 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci return 0; 10808c2ecf20Sopenharmony_ci} 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_cistatic struct snd_soc_dapm_widget *skl_get_src_dsp_widget( 10838c2ecf20Sopenharmony_ci struct snd_soc_dapm_widget *w, struct skl_dev *skl) 10848c2ecf20Sopenharmony_ci{ 10858c2ecf20Sopenharmony_ci struct snd_soc_dapm_path *p; 10868c2ecf20Sopenharmony_ci struct snd_soc_dapm_widget *src_w = NULL; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci snd_soc_dapm_widget_for_each_source_path(w, p) { 10898c2ecf20Sopenharmony_ci src_w = p->source; 10908c2ecf20Sopenharmony_ci if (!p->connect) 10918c2ecf20Sopenharmony_ci continue; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "sink widget=%s\n", w->name); 10948c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "src widget=%s\n", p->source->name); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci /* 10978c2ecf20Sopenharmony_ci * here we will check widgets in sink pipelines, so that can 10988c2ecf20Sopenharmony_ci * be any widgets type and we are only interested if they are 10998c2ecf20Sopenharmony_ci * ones used for SKL so check that first 11008c2ecf20Sopenharmony_ci */ 11018c2ecf20Sopenharmony_ci if ((p->source->priv != NULL) && 11028c2ecf20Sopenharmony_ci is_skl_dsp_widget_type(p->source, skl->dev)) { 11038c2ecf20Sopenharmony_ci return p->source; 11048c2ecf20Sopenharmony_ci } 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci if (src_w != NULL) 11088c2ecf20Sopenharmony_ci return skl_get_src_dsp_widget(src_w, skl); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci return NULL; 11118c2ecf20Sopenharmony_ci} 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci/* 11148c2ecf20Sopenharmony_ci * in the Post-PMU event of mixer we need to do following: 11158c2ecf20Sopenharmony_ci * - Check if this pipe is running 11168c2ecf20Sopenharmony_ci * - if not, then 11178c2ecf20Sopenharmony_ci * - bind this pipeline to its source pipeline 11188c2ecf20Sopenharmony_ci * if source pipe is already running, this means it is a dynamic 11198c2ecf20Sopenharmony_ci * connection and we need to bind only to that pipe 11208c2ecf20Sopenharmony_ci * - start this pipeline 11218c2ecf20Sopenharmony_ci */ 11228c2ecf20Sopenharmony_cistatic int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, 11238c2ecf20Sopenharmony_ci struct skl_dev *skl) 11248c2ecf20Sopenharmony_ci{ 11258c2ecf20Sopenharmony_ci int ret = 0; 11268c2ecf20Sopenharmony_ci struct snd_soc_dapm_widget *source, *sink; 11278c2ecf20Sopenharmony_ci struct skl_module_cfg *src_mconfig, *sink_mconfig; 11288c2ecf20Sopenharmony_ci int src_pipe_started = 0; 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci sink = w; 11318c2ecf20Sopenharmony_ci sink_mconfig = sink->priv; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci /* 11348c2ecf20Sopenharmony_ci * If source pipe is already started, that means source is driving 11358c2ecf20Sopenharmony_ci * one more sink before this sink got connected, Since source is 11368c2ecf20Sopenharmony_ci * started, bind this sink to source and start this pipe. 11378c2ecf20Sopenharmony_ci */ 11388c2ecf20Sopenharmony_ci source = skl_get_src_dsp_widget(w, skl); 11398c2ecf20Sopenharmony_ci if (source != NULL) { 11408c2ecf20Sopenharmony_ci src_mconfig = source->priv; 11418c2ecf20Sopenharmony_ci sink_mconfig = sink->priv; 11428c2ecf20Sopenharmony_ci src_pipe_started = 1; 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci /* 11458c2ecf20Sopenharmony_ci * check pipe state, then no need to bind or start the 11468c2ecf20Sopenharmony_ci * pipe 11478c2ecf20Sopenharmony_ci */ 11488c2ecf20Sopenharmony_ci if (src_mconfig->pipe->state != SKL_PIPE_STARTED) 11498c2ecf20Sopenharmony_ci src_pipe_started = 0; 11508c2ecf20Sopenharmony_ci } 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci if (src_pipe_started) { 11538c2ecf20Sopenharmony_ci ret = skl_bind_modules(skl, src_mconfig, sink_mconfig); 11548c2ecf20Sopenharmony_ci if (ret) 11558c2ecf20Sopenharmony_ci return ret; 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci /* set module params after bind */ 11588c2ecf20Sopenharmony_ci skl_tplg_set_module_bind_params(source, src_mconfig, skl); 11598c2ecf20Sopenharmony_ci skl_tplg_set_module_bind_params(sink, sink_mconfig, skl); 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) 11628c2ecf20Sopenharmony_ci ret = skl_run_pipe(skl, sink_mconfig->pipe); 11638c2ecf20Sopenharmony_ci } 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci return ret; 11668c2ecf20Sopenharmony_ci} 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci/* 11698c2ecf20Sopenharmony_ci * in the Pre-PMD event of mixer we need to do following: 11708c2ecf20Sopenharmony_ci * - Stop the pipe 11718c2ecf20Sopenharmony_ci * - find the source connections and remove that from dapm_path_list 11728c2ecf20Sopenharmony_ci * - unbind with source pipelines if still connected 11738c2ecf20Sopenharmony_ci */ 11748c2ecf20Sopenharmony_cistatic int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w, 11758c2ecf20Sopenharmony_ci struct skl_dev *skl) 11768c2ecf20Sopenharmony_ci{ 11778c2ecf20Sopenharmony_ci struct skl_module_cfg *src_mconfig, *sink_mconfig; 11788c2ecf20Sopenharmony_ci int ret = 0, i; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci sink_mconfig = w->priv; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci /* Stop the pipe */ 11838c2ecf20Sopenharmony_ci ret = skl_stop_pipe(skl, sink_mconfig->pipe); 11848c2ecf20Sopenharmony_ci if (ret) 11858c2ecf20Sopenharmony_ci return ret; 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci for (i = 0; i < sink_mconfig->module->max_input_pins; i++) { 11888c2ecf20Sopenharmony_ci if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) { 11898c2ecf20Sopenharmony_ci src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg; 11908c2ecf20Sopenharmony_ci if (!src_mconfig) 11918c2ecf20Sopenharmony_ci continue; 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci ret = skl_unbind_modules(skl, 11948c2ecf20Sopenharmony_ci src_mconfig, sink_mconfig); 11958c2ecf20Sopenharmony_ci } 11968c2ecf20Sopenharmony_ci } 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci return ret; 11998c2ecf20Sopenharmony_ci} 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci/* 12028c2ecf20Sopenharmony_ci * in the Post-PMD event of mixer we need to do following: 12038c2ecf20Sopenharmony_ci * - Unbind the modules within the pipeline 12048c2ecf20Sopenharmony_ci * - Delete the pipeline (modules are not required to be explicitly 12058c2ecf20Sopenharmony_ci * deleted, pipeline delete is enough here 12068c2ecf20Sopenharmony_ci */ 12078c2ecf20Sopenharmony_cistatic int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, 12088c2ecf20Sopenharmony_ci struct skl_dev *skl) 12098c2ecf20Sopenharmony_ci{ 12108c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig = w->priv; 12118c2ecf20Sopenharmony_ci struct skl_pipe_module *w_module; 12128c2ecf20Sopenharmony_ci struct skl_module_cfg *src_module = NULL, *dst_module; 12138c2ecf20Sopenharmony_ci struct skl_pipe *s_pipe = mconfig->pipe; 12148c2ecf20Sopenharmony_ci struct skl_module_deferred_bind *modules, *tmp; 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci if (s_pipe->state == SKL_PIPE_INVALID) 12178c2ecf20Sopenharmony_ci return -EINVAL; 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci list_for_each_entry(w_module, &s_pipe->w_list, node) { 12208c2ecf20Sopenharmony_ci if (list_empty(&skl->bind_list)) 12218c2ecf20Sopenharmony_ci break; 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci src_module = w_module->w->priv; 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) { 12268c2ecf20Sopenharmony_ci /* 12278c2ecf20Sopenharmony_ci * When the destination module is deleted, Unbind the 12288c2ecf20Sopenharmony_ci * modules from deferred bind list. 12298c2ecf20Sopenharmony_ci */ 12308c2ecf20Sopenharmony_ci if (modules->dst == src_module) { 12318c2ecf20Sopenharmony_ci skl_unbind_modules(skl, modules->src, 12328c2ecf20Sopenharmony_ci modules->dst); 12338c2ecf20Sopenharmony_ci } 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci /* 12368c2ecf20Sopenharmony_ci * When the source module is deleted, remove this entry 12378c2ecf20Sopenharmony_ci * from the deferred bind list. 12388c2ecf20Sopenharmony_ci */ 12398c2ecf20Sopenharmony_ci if (modules->src == src_module) { 12408c2ecf20Sopenharmony_ci list_del(&modules->node); 12418c2ecf20Sopenharmony_ci modules->src = NULL; 12428c2ecf20Sopenharmony_ci modules->dst = NULL; 12438c2ecf20Sopenharmony_ci kfree(modules); 12448c2ecf20Sopenharmony_ci } 12458c2ecf20Sopenharmony_ci } 12468c2ecf20Sopenharmony_ci } 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci list_for_each_entry(w_module, &s_pipe->w_list, node) { 12498c2ecf20Sopenharmony_ci dst_module = w_module->w->priv; 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci if (src_module == NULL) { 12528c2ecf20Sopenharmony_ci src_module = dst_module; 12538c2ecf20Sopenharmony_ci continue; 12548c2ecf20Sopenharmony_ci } 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci skl_unbind_modules(skl, src_module, dst_module); 12578c2ecf20Sopenharmony_ci src_module = dst_module; 12588c2ecf20Sopenharmony_ci } 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci skl_delete_pipe(skl, mconfig->pipe); 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci list_for_each_entry(w_module, &s_pipe->w_list, node) { 12638c2ecf20Sopenharmony_ci src_module = w_module->w->priv; 12648c2ecf20Sopenharmony_ci src_module->m_state = SKL_MODULE_UNINIT; 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci return skl_tplg_unload_pipe_modules(skl, s_pipe); 12688c2ecf20Sopenharmony_ci} 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci/* 12718c2ecf20Sopenharmony_ci * in the Post-PMD event of PGA we need to do following: 12728c2ecf20Sopenharmony_ci * - Stop the pipeline 12738c2ecf20Sopenharmony_ci * - In source pipe is connected, unbind with source pipelines 12748c2ecf20Sopenharmony_ci */ 12758c2ecf20Sopenharmony_cistatic int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, 12768c2ecf20Sopenharmony_ci struct skl_dev *skl) 12778c2ecf20Sopenharmony_ci{ 12788c2ecf20Sopenharmony_ci struct skl_module_cfg *src_mconfig, *sink_mconfig; 12798c2ecf20Sopenharmony_ci int ret = 0, i; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci src_mconfig = w->priv; 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci /* Stop the pipe since this is a mixin module */ 12848c2ecf20Sopenharmony_ci ret = skl_stop_pipe(skl, src_mconfig->pipe); 12858c2ecf20Sopenharmony_ci if (ret) 12868c2ecf20Sopenharmony_ci return ret; 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci for (i = 0; i < src_mconfig->module->max_output_pins; i++) { 12898c2ecf20Sopenharmony_ci if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) { 12908c2ecf20Sopenharmony_ci sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg; 12918c2ecf20Sopenharmony_ci if (!sink_mconfig) 12928c2ecf20Sopenharmony_ci continue; 12938c2ecf20Sopenharmony_ci /* 12948c2ecf20Sopenharmony_ci * This is a connecter and if path is found that means 12958c2ecf20Sopenharmony_ci * unbind between source and sink has not happened yet 12968c2ecf20Sopenharmony_ci */ 12978c2ecf20Sopenharmony_ci ret = skl_unbind_modules(skl, src_mconfig, 12988c2ecf20Sopenharmony_ci sink_mconfig); 12998c2ecf20Sopenharmony_ci } 13008c2ecf20Sopenharmony_ci } 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci return ret; 13038c2ecf20Sopenharmony_ci} 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci/* 13068c2ecf20Sopenharmony_ci * In modelling, we assume there will be ONLY one mixer in a pipeline. If a 13078c2ecf20Sopenharmony_ci * second one is required that is created as another pipe entity. 13088c2ecf20Sopenharmony_ci * The mixer is responsible for pipe management and represent a pipeline 13098c2ecf20Sopenharmony_ci * instance 13108c2ecf20Sopenharmony_ci */ 13118c2ecf20Sopenharmony_cistatic int skl_tplg_mixer_event(struct snd_soc_dapm_widget *w, 13128c2ecf20Sopenharmony_ci struct snd_kcontrol *k, int event) 13138c2ecf20Sopenharmony_ci{ 13148c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = w->dapm; 13158c2ecf20Sopenharmony_ci struct skl_dev *skl = get_skl_ctx(dapm->dev); 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci switch (event) { 13188c2ecf20Sopenharmony_ci case SND_SOC_DAPM_PRE_PMU: 13198c2ecf20Sopenharmony_ci return skl_tplg_mixer_dapm_pre_pmu_event(w, skl); 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 13228c2ecf20Sopenharmony_ci return skl_tplg_mixer_dapm_post_pmu_event(w, skl); 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci case SND_SOC_DAPM_PRE_PMD: 13258c2ecf20Sopenharmony_ci return skl_tplg_mixer_dapm_pre_pmd_event(w, skl); 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci case SND_SOC_DAPM_POST_PMD: 13288c2ecf20Sopenharmony_ci return skl_tplg_mixer_dapm_post_pmd_event(w, skl); 13298c2ecf20Sopenharmony_ci } 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci return 0; 13328c2ecf20Sopenharmony_ci} 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci/* 13358c2ecf20Sopenharmony_ci * In modelling, we assumed rest of the modules in pipeline are PGA. But we 13368c2ecf20Sopenharmony_ci * are interested in last PGA (leaf PGA) in a pipeline to disconnect with 13378c2ecf20Sopenharmony_ci * the sink when it is running (two FE to one BE or one FE to two BE) 13388c2ecf20Sopenharmony_ci * scenarios 13398c2ecf20Sopenharmony_ci */ 13408c2ecf20Sopenharmony_cistatic int skl_tplg_pga_event(struct snd_soc_dapm_widget *w, 13418c2ecf20Sopenharmony_ci struct snd_kcontrol *k, int event) 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci{ 13448c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = w->dapm; 13458c2ecf20Sopenharmony_ci struct skl_dev *skl = get_skl_ctx(dapm->dev); 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci switch (event) { 13488c2ecf20Sopenharmony_ci case SND_SOC_DAPM_PRE_PMU: 13498c2ecf20Sopenharmony_ci return skl_tplg_pga_dapm_pre_pmu_event(w, skl); 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci case SND_SOC_DAPM_POST_PMD: 13528c2ecf20Sopenharmony_ci return skl_tplg_pga_dapm_post_pmd_event(w, skl); 13538c2ecf20Sopenharmony_ci } 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci return 0; 13568c2ecf20Sopenharmony_ci} 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_cistatic int skl_tplg_multi_config_set_get(struct snd_kcontrol *kcontrol, 13598c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol, 13608c2ecf20Sopenharmony_ci bool is_set) 13618c2ecf20Sopenharmony_ci{ 13628c2ecf20Sopenharmony_ci struct snd_soc_component *component = 13638c2ecf20Sopenharmony_ci snd_soc_kcontrol_component(kcontrol); 13648c2ecf20Sopenharmony_ci struct hdac_bus *bus = snd_soc_component_get_drvdata(component); 13658c2ecf20Sopenharmony_ci struct skl_dev *skl = bus_to_skl(bus); 13668c2ecf20Sopenharmony_ci struct skl_pipeline *ppl; 13678c2ecf20Sopenharmony_ci struct skl_pipe *pipe = NULL; 13688c2ecf20Sopenharmony_ci struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value; 13698c2ecf20Sopenharmony_ci u32 *pipe_id; 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci if (!ec) 13728c2ecf20Sopenharmony_ci return -EINVAL; 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci if (is_set && ucontrol->value.enumerated.item[0] > ec->items) 13758c2ecf20Sopenharmony_ci return -EINVAL; 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci pipe_id = ec->dobj.private; 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci list_for_each_entry(ppl, &skl->ppl_list, node) { 13808c2ecf20Sopenharmony_ci if (ppl->pipe->ppl_id == *pipe_id) { 13818c2ecf20Sopenharmony_ci pipe = ppl->pipe; 13828c2ecf20Sopenharmony_ci break; 13838c2ecf20Sopenharmony_ci } 13848c2ecf20Sopenharmony_ci } 13858c2ecf20Sopenharmony_ci if (!pipe) 13868c2ecf20Sopenharmony_ci return -EIO; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci if (is_set) 13898c2ecf20Sopenharmony_ci pipe->pipe_config_idx = ucontrol->value.enumerated.item[0]; 13908c2ecf20Sopenharmony_ci else 13918c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = pipe->pipe_config_idx; 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci return 0; 13948c2ecf20Sopenharmony_ci} 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_cistatic int skl_tplg_multi_config_get(struct snd_kcontrol *kcontrol, 13978c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 13988c2ecf20Sopenharmony_ci{ 13998c2ecf20Sopenharmony_ci return skl_tplg_multi_config_set_get(kcontrol, ucontrol, false); 14008c2ecf20Sopenharmony_ci} 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_cistatic int skl_tplg_multi_config_set(struct snd_kcontrol *kcontrol, 14038c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 14048c2ecf20Sopenharmony_ci{ 14058c2ecf20Sopenharmony_ci return skl_tplg_multi_config_set_get(kcontrol, ucontrol, true); 14068c2ecf20Sopenharmony_ci} 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_cistatic int skl_tplg_multi_config_get_dmic(struct snd_kcontrol *kcontrol, 14098c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 14108c2ecf20Sopenharmony_ci{ 14118c2ecf20Sopenharmony_ci return skl_tplg_multi_config_set_get(kcontrol, ucontrol, false); 14128c2ecf20Sopenharmony_ci} 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_cistatic int skl_tplg_multi_config_set_dmic(struct snd_kcontrol *kcontrol, 14158c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 14168c2ecf20Sopenharmony_ci{ 14178c2ecf20Sopenharmony_ci return skl_tplg_multi_config_set_get(kcontrol, ucontrol, true); 14188c2ecf20Sopenharmony_ci} 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_cistatic int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol, 14218c2ecf20Sopenharmony_ci unsigned int __user *data, unsigned int size) 14228c2ecf20Sopenharmony_ci{ 14238c2ecf20Sopenharmony_ci struct soc_bytes_ext *sb = 14248c2ecf20Sopenharmony_ci (struct soc_bytes_ext *)kcontrol->private_value; 14258c2ecf20Sopenharmony_ci struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private; 14268c2ecf20Sopenharmony_ci struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); 14278c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig = w->priv; 14288c2ecf20Sopenharmony_ci struct skl_dev *skl = get_skl_ctx(w->dapm->dev); 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci if (w->power) 14318c2ecf20Sopenharmony_ci skl_get_module_params(skl, (u32 *)bc->params, 14328c2ecf20Sopenharmony_ci bc->size, bc->param_id, mconfig); 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci /* decrement size for TLV header */ 14358c2ecf20Sopenharmony_ci size -= 2 * sizeof(u32); 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci /* check size as we don't want to send kernel data */ 14388c2ecf20Sopenharmony_ci if (size > bc->max) 14398c2ecf20Sopenharmony_ci size = bc->max; 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci if (bc->params) { 14428c2ecf20Sopenharmony_ci if (copy_to_user(data, &bc->param_id, sizeof(u32))) 14438c2ecf20Sopenharmony_ci return -EFAULT; 14448c2ecf20Sopenharmony_ci if (copy_to_user(data + 1, &size, sizeof(u32))) 14458c2ecf20Sopenharmony_ci return -EFAULT; 14468c2ecf20Sopenharmony_ci if (copy_to_user(data + 2, bc->params, size)) 14478c2ecf20Sopenharmony_ci return -EFAULT; 14488c2ecf20Sopenharmony_ci } 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci return 0; 14518c2ecf20Sopenharmony_ci} 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci#define SKL_PARAM_VENDOR_ID 0xff 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_cistatic int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol, 14568c2ecf20Sopenharmony_ci const unsigned int __user *data, unsigned int size) 14578c2ecf20Sopenharmony_ci{ 14588c2ecf20Sopenharmony_ci struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); 14598c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig = w->priv; 14608c2ecf20Sopenharmony_ci struct soc_bytes_ext *sb = 14618c2ecf20Sopenharmony_ci (struct soc_bytes_ext *)kcontrol->private_value; 14628c2ecf20Sopenharmony_ci struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private; 14638c2ecf20Sopenharmony_ci struct skl_dev *skl = get_skl_ctx(w->dapm->dev); 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci if (ac->params) { 14668c2ecf20Sopenharmony_ci if (size > ac->max) 14678c2ecf20Sopenharmony_ci return -EINVAL; 14688c2ecf20Sopenharmony_ci ac->size = size; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci if (copy_from_user(ac->params, data, size)) 14718c2ecf20Sopenharmony_ci return -EFAULT; 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci if (w->power) 14748c2ecf20Sopenharmony_ci return skl_set_module_params(skl, 14758c2ecf20Sopenharmony_ci (u32 *)ac->params, ac->size, 14768c2ecf20Sopenharmony_ci ac->param_id, mconfig); 14778c2ecf20Sopenharmony_ci } 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci return 0; 14808c2ecf20Sopenharmony_ci} 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_cistatic int skl_tplg_mic_control_get(struct snd_kcontrol *kcontrol, 14838c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 14848c2ecf20Sopenharmony_ci{ 14858c2ecf20Sopenharmony_ci struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); 14868c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig = w->priv; 14878c2ecf20Sopenharmony_ci struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value; 14888c2ecf20Sopenharmony_ci u32 ch_type = *((u32 *)ec->dobj.private); 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci if (mconfig->dmic_ch_type == ch_type) 14918c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 14928c2ecf20Sopenharmony_ci mconfig->dmic_ch_combo_index; 14938c2ecf20Sopenharmony_ci else 14948c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 0; 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci return 0; 14978c2ecf20Sopenharmony_ci} 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_cistatic int skl_fill_mic_sel_params(struct skl_module_cfg *mconfig, 15008c2ecf20Sopenharmony_ci struct skl_mic_sel_config *mic_cfg, struct device *dev) 15018c2ecf20Sopenharmony_ci{ 15028c2ecf20Sopenharmony_ci struct skl_specific_cfg *sp_cfg = &mconfig->formats_config; 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci sp_cfg->caps_size = sizeof(struct skl_mic_sel_config); 15058c2ecf20Sopenharmony_ci sp_cfg->set_params = SKL_PARAM_SET; 15068c2ecf20Sopenharmony_ci sp_cfg->param_id = 0x00; 15078c2ecf20Sopenharmony_ci if (!sp_cfg->caps) { 15088c2ecf20Sopenharmony_ci sp_cfg->caps = devm_kzalloc(dev, sp_cfg->caps_size, GFP_KERNEL); 15098c2ecf20Sopenharmony_ci if (!sp_cfg->caps) 15108c2ecf20Sopenharmony_ci return -ENOMEM; 15118c2ecf20Sopenharmony_ci } 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci mic_cfg->mic_switch = SKL_MIC_SEL_SWITCH; 15148c2ecf20Sopenharmony_ci mic_cfg->flags = 0; 15158c2ecf20Sopenharmony_ci memcpy(sp_cfg->caps, mic_cfg, sp_cfg->caps_size); 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci return 0; 15188c2ecf20Sopenharmony_ci} 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_cistatic int skl_tplg_mic_control_set(struct snd_kcontrol *kcontrol, 15218c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 15228c2ecf20Sopenharmony_ci{ 15238c2ecf20Sopenharmony_ci struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); 15248c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig = w->priv; 15258c2ecf20Sopenharmony_ci struct skl_mic_sel_config mic_cfg = {0}; 15268c2ecf20Sopenharmony_ci struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value; 15278c2ecf20Sopenharmony_ci u32 ch_type = *((u32 *)ec->dobj.private); 15288c2ecf20Sopenharmony_ci const int *list; 15298c2ecf20Sopenharmony_ci u8 in_ch, out_ch, index; 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci mconfig->dmic_ch_type = ch_type; 15328c2ecf20Sopenharmony_ci mconfig->dmic_ch_combo_index = ucontrol->value.enumerated.item[0]; 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci /* enum control index 0 is INVALID, so no channels to be set */ 15358c2ecf20Sopenharmony_ci if (mconfig->dmic_ch_combo_index == 0) 15368c2ecf20Sopenharmony_ci return 0; 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci /* No valid channel selection map for index 0, so offset by 1 */ 15398c2ecf20Sopenharmony_ci index = mconfig->dmic_ch_combo_index - 1; 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci switch (ch_type) { 15428c2ecf20Sopenharmony_ci case SKL_CH_MONO: 15438c2ecf20Sopenharmony_ci if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_mono_list)) 15448c2ecf20Sopenharmony_ci return -EINVAL; 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci list = &mic_mono_list[index]; 15478c2ecf20Sopenharmony_ci break; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci case SKL_CH_STEREO: 15508c2ecf20Sopenharmony_ci if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_stereo_list)) 15518c2ecf20Sopenharmony_ci return -EINVAL; 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci list = mic_stereo_list[index]; 15548c2ecf20Sopenharmony_ci break; 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci case SKL_CH_TRIO: 15578c2ecf20Sopenharmony_ci if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_trio_list)) 15588c2ecf20Sopenharmony_ci return -EINVAL; 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci list = mic_trio_list[index]; 15618c2ecf20Sopenharmony_ci break; 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci case SKL_CH_QUATRO: 15648c2ecf20Sopenharmony_ci if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_quatro_list)) 15658c2ecf20Sopenharmony_ci return -EINVAL; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci list = mic_quatro_list[index]; 15688c2ecf20Sopenharmony_ci break; 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci default: 15718c2ecf20Sopenharmony_ci dev_err(w->dapm->dev, 15728c2ecf20Sopenharmony_ci "Invalid channel %d for mic_select module\n", 15738c2ecf20Sopenharmony_ci ch_type); 15748c2ecf20Sopenharmony_ci return -EINVAL; 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci } 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci /* channel type enum map to number of chanels for that type */ 15798c2ecf20Sopenharmony_ci for (out_ch = 0; out_ch < ch_type; out_ch++) { 15808c2ecf20Sopenharmony_ci in_ch = list[out_ch]; 15818c2ecf20Sopenharmony_ci mic_cfg.blob[out_ch][in_ch] = SKL_DEFAULT_MIC_SEL_GAIN; 15828c2ecf20Sopenharmony_ci } 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci return skl_fill_mic_sel_params(mconfig, &mic_cfg, w->dapm->dev); 15858c2ecf20Sopenharmony_ci} 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci/* 15888c2ecf20Sopenharmony_ci * Fill the dma id for host and link. In case of passthrough 15898c2ecf20Sopenharmony_ci * pipeline, this will both host and link in the same 15908c2ecf20Sopenharmony_ci * pipeline, so need to copy the link and host based on dev_type 15918c2ecf20Sopenharmony_ci */ 15928c2ecf20Sopenharmony_cistatic void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg, 15938c2ecf20Sopenharmony_ci struct skl_pipe_params *params) 15948c2ecf20Sopenharmony_ci{ 15958c2ecf20Sopenharmony_ci struct skl_pipe *pipe = mcfg->pipe; 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci if (pipe->passthru) { 15988c2ecf20Sopenharmony_ci switch (mcfg->dev_type) { 15998c2ecf20Sopenharmony_ci case SKL_DEVICE_HDALINK: 16008c2ecf20Sopenharmony_ci pipe->p_params->link_dma_id = params->link_dma_id; 16018c2ecf20Sopenharmony_ci pipe->p_params->link_index = params->link_index; 16028c2ecf20Sopenharmony_ci pipe->p_params->link_bps = params->link_bps; 16038c2ecf20Sopenharmony_ci break; 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci case SKL_DEVICE_HDAHOST: 16068c2ecf20Sopenharmony_ci pipe->p_params->host_dma_id = params->host_dma_id; 16078c2ecf20Sopenharmony_ci pipe->p_params->host_bps = params->host_bps; 16088c2ecf20Sopenharmony_ci break; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci default: 16118c2ecf20Sopenharmony_ci break; 16128c2ecf20Sopenharmony_ci } 16138c2ecf20Sopenharmony_ci pipe->p_params->s_fmt = params->s_fmt; 16148c2ecf20Sopenharmony_ci pipe->p_params->ch = params->ch; 16158c2ecf20Sopenharmony_ci pipe->p_params->s_freq = params->s_freq; 16168c2ecf20Sopenharmony_ci pipe->p_params->stream = params->stream; 16178c2ecf20Sopenharmony_ci pipe->p_params->format = params->format; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci } else { 16208c2ecf20Sopenharmony_ci memcpy(pipe->p_params, params, sizeof(*params)); 16218c2ecf20Sopenharmony_ci } 16228c2ecf20Sopenharmony_ci} 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci/* 16258c2ecf20Sopenharmony_ci * The FE params are passed by hw_params of the DAI. 16268c2ecf20Sopenharmony_ci * On hw_params, the params are stored in Gateway module of the FE and we 16278c2ecf20Sopenharmony_ci * need to calculate the format in DSP module configuration, that 16288c2ecf20Sopenharmony_ci * conversion is done here 16298c2ecf20Sopenharmony_ci */ 16308c2ecf20Sopenharmony_ciint skl_tplg_update_pipe_params(struct device *dev, 16318c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig, 16328c2ecf20Sopenharmony_ci struct skl_pipe_params *params) 16338c2ecf20Sopenharmony_ci{ 16348c2ecf20Sopenharmony_ci struct skl_module_res *res; 16358c2ecf20Sopenharmony_ci struct skl_dev *skl = get_skl_ctx(dev); 16368c2ecf20Sopenharmony_ci struct skl_module_fmt *format = NULL; 16378c2ecf20Sopenharmony_ci u8 cfg_idx = mconfig->pipe->cur_config_idx; 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci res = &mconfig->module->resources[mconfig->res_idx]; 16408c2ecf20Sopenharmony_ci skl_tplg_fill_dma_id(mconfig, params); 16418c2ecf20Sopenharmony_ci mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx; 16428c2ecf20Sopenharmony_ci mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx; 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci if (skl->nr_modules) 16458c2ecf20Sopenharmony_ci return 0; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) 16488c2ecf20Sopenharmony_ci format = &mconfig->module->formats[mconfig->fmt_idx].inputs[0].fmt; 16498c2ecf20Sopenharmony_ci else 16508c2ecf20Sopenharmony_ci format = &mconfig->module->formats[mconfig->fmt_idx].outputs[0].fmt; 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci /* set the hw_params */ 16538c2ecf20Sopenharmony_ci format->s_freq = params->s_freq; 16548c2ecf20Sopenharmony_ci format->channels = params->ch; 16558c2ecf20Sopenharmony_ci format->valid_bit_depth = skl_get_bit_depth(params->s_fmt); 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci /* 16588c2ecf20Sopenharmony_ci * 16 bit is 16 bit container whereas 24 bit is in 32 bit 16598c2ecf20Sopenharmony_ci * container so update bit depth accordingly 16608c2ecf20Sopenharmony_ci */ 16618c2ecf20Sopenharmony_ci switch (format->valid_bit_depth) { 16628c2ecf20Sopenharmony_ci case SKL_DEPTH_16BIT: 16638c2ecf20Sopenharmony_ci format->bit_depth = format->valid_bit_depth; 16648c2ecf20Sopenharmony_ci break; 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci case SKL_DEPTH_24BIT: 16678c2ecf20Sopenharmony_ci case SKL_DEPTH_32BIT: 16688c2ecf20Sopenharmony_ci format->bit_depth = SKL_DEPTH_32BIT; 16698c2ecf20Sopenharmony_ci break; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci default: 16728c2ecf20Sopenharmony_ci dev_err(dev, "Invalid bit depth %x for pipe\n", 16738c2ecf20Sopenharmony_ci format->valid_bit_depth); 16748c2ecf20Sopenharmony_ci return -EINVAL; 16758c2ecf20Sopenharmony_ci } 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { 16788c2ecf20Sopenharmony_ci res->ibs = (format->s_freq / 1000) * 16798c2ecf20Sopenharmony_ci (format->channels) * 16808c2ecf20Sopenharmony_ci (format->bit_depth >> 3); 16818c2ecf20Sopenharmony_ci } else { 16828c2ecf20Sopenharmony_ci res->obs = (format->s_freq / 1000) * 16838c2ecf20Sopenharmony_ci (format->channels) * 16848c2ecf20Sopenharmony_ci (format->bit_depth >> 3); 16858c2ecf20Sopenharmony_ci } 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci return 0; 16888c2ecf20Sopenharmony_ci} 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci/* 16918c2ecf20Sopenharmony_ci * Query the module config for the FE DAI 16928c2ecf20Sopenharmony_ci * This is used to find the hw_params set for that DAI and apply to FE 16938c2ecf20Sopenharmony_ci * pipeline 16948c2ecf20Sopenharmony_ci */ 16958c2ecf20Sopenharmony_cistruct skl_module_cfg * 16968c2ecf20Sopenharmony_ciskl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream) 16978c2ecf20Sopenharmony_ci{ 16988c2ecf20Sopenharmony_ci struct snd_soc_dapm_widget *w; 16998c2ecf20Sopenharmony_ci struct snd_soc_dapm_path *p = NULL; 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 17028c2ecf20Sopenharmony_ci w = dai->playback_widget; 17038c2ecf20Sopenharmony_ci snd_soc_dapm_widget_for_each_sink_path(w, p) { 17048c2ecf20Sopenharmony_ci if (p->connect && p->sink->power && 17058c2ecf20Sopenharmony_ci !is_skl_dsp_widget_type(p->sink, dai->dev)) 17068c2ecf20Sopenharmony_ci continue; 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci if (p->sink->priv) { 17098c2ecf20Sopenharmony_ci dev_dbg(dai->dev, "set params for %s\n", 17108c2ecf20Sopenharmony_ci p->sink->name); 17118c2ecf20Sopenharmony_ci return p->sink->priv; 17128c2ecf20Sopenharmony_ci } 17138c2ecf20Sopenharmony_ci } 17148c2ecf20Sopenharmony_ci } else { 17158c2ecf20Sopenharmony_ci w = dai->capture_widget; 17168c2ecf20Sopenharmony_ci snd_soc_dapm_widget_for_each_source_path(w, p) { 17178c2ecf20Sopenharmony_ci if (p->connect && p->source->power && 17188c2ecf20Sopenharmony_ci !is_skl_dsp_widget_type(p->source, dai->dev)) 17198c2ecf20Sopenharmony_ci continue; 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci if (p->source->priv) { 17228c2ecf20Sopenharmony_ci dev_dbg(dai->dev, "set params for %s\n", 17238c2ecf20Sopenharmony_ci p->source->name); 17248c2ecf20Sopenharmony_ci return p->source->priv; 17258c2ecf20Sopenharmony_ci } 17268c2ecf20Sopenharmony_ci } 17278c2ecf20Sopenharmony_ci } 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci return NULL; 17308c2ecf20Sopenharmony_ci} 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_cistatic struct skl_module_cfg *skl_get_mconfig_pb_cpr( 17338c2ecf20Sopenharmony_ci struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w) 17348c2ecf20Sopenharmony_ci{ 17358c2ecf20Sopenharmony_ci struct snd_soc_dapm_path *p; 17368c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig = NULL; 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci snd_soc_dapm_widget_for_each_source_path(w, p) { 17398c2ecf20Sopenharmony_ci if (w->endpoints[SND_SOC_DAPM_DIR_OUT] > 0) { 17408c2ecf20Sopenharmony_ci if (p->connect && 17418c2ecf20Sopenharmony_ci (p->sink->id == snd_soc_dapm_aif_out) && 17428c2ecf20Sopenharmony_ci p->source->priv) { 17438c2ecf20Sopenharmony_ci mconfig = p->source->priv; 17448c2ecf20Sopenharmony_ci return mconfig; 17458c2ecf20Sopenharmony_ci } 17468c2ecf20Sopenharmony_ci mconfig = skl_get_mconfig_pb_cpr(dai, p->source); 17478c2ecf20Sopenharmony_ci if (mconfig) 17488c2ecf20Sopenharmony_ci return mconfig; 17498c2ecf20Sopenharmony_ci } 17508c2ecf20Sopenharmony_ci } 17518c2ecf20Sopenharmony_ci return mconfig; 17528c2ecf20Sopenharmony_ci} 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_cistatic struct skl_module_cfg *skl_get_mconfig_cap_cpr( 17558c2ecf20Sopenharmony_ci struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w) 17568c2ecf20Sopenharmony_ci{ 17578c2ecf20Sopenharmony_ci struct snd_soc_dapm_path *p; 17588c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig = NULL; 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci snd_soc_dapm_widget_for_each_sink_path(w, p) { 17618c2ecf20Sopenharmony_ci if (w->endpoints[SND_SOC_DAPM_DIR_IN] > 0) { 17628c2ecf20Sopenharmony_ci if (p->connect && 17638c2ecf20Sopenharmony_ci (p->source->id == snd_soc_dapm_aif_in) && 17648c2ecf20Sopenharmony_ci p->sink->priv) { 17658c2ecf20Sopenharmony_ci mconfig = p->sink->priv; 17668c2ecf20Sopenharmony_ci return mconfig; 17678c2ecf20Sopenharmony_ci } 17688c2ecf20Sopenharmony_ci mconfig = skl_get_mconfig_cap_cpr(dai, p->sink); 17698c2ecf20Sopenharmony_ci if (mconfig) 17708c2ecf20Sopenharmony_ci return mconfig; 17718c2ecf20Sopenharmony_ci } 17728c2ecf20Sopenharmony_ci } 17738c2ecf20Sopenharmony_ci return mconfig; 17748c2ecf20Sopenharmony_ci} 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_cistruct skl_module_cfg * 17778c2ecf20Sopenharmony_ciskl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, int stream) 17788c2ecf20Sopenharmony_ci{ 17798c2ecf20Sopenharmony_ci struct snd_soc_dapm_widget *w; 17808c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig; 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 17838c2ecf20Sopenharmony_ci w = dai->playback_widget; 17848c2ecf20Sopenharmony_ci mconfig = skl_get_mconfig_pb_cpr(dai, w); 17858c2ecf20Sopenharmony_ci } else { 17868c2ecf20Sopenharmony_ci w = dai->capture_widget; 17878c2ecf20Sopenharmony_ci mconfig = skl_get_mconfig_cap_cpr(dai, w); 17888c2ecf20Sopenharmony_ci } 17898c2ecf20Sopenharmony_ci return mconfig; 17908c2ecf20Sopenharmony_ci} 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_cistatic u8 skl_tplg_be_link_type(int dev_type) 17938c2ecf20Sopenharmony_ci{ 17948c2ecf20Sopenharmony_ci int ret; 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci switch (dev_type) { 17978c2ecf20Sopenharmony_ci case SKL_DEVICE_BT: 17988c2ecf20Sopenharmony_ci ret = NHLT_LINK_SSP; 17998c2ecf20Sopenharmony_ci break; 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci case SKL_DEVICE_DMIC: 18028c2ecf20Sopenharmony_ci ret = NHLT_LINK_DMIC; 18038c2ecf20Sopenharmony_ci break; 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci case SKL_DEVICE_I2S: 18068c2ecf20Sopenharmony_ci ret = NHLT_LINK_SSP; 18078c2ecf20Sopenharmony_ci break; 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci case SKL_DEVICE_HDALINK: 18108c2ecf20Sopenharmony_ci ret = NHLT_LINK_HDA; 18118c2ecf20Sopenharmony_ci break; 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci default: 18148c2ecf20Sopenharmony_ci ret = NHLT_LINK_INVALID; 18158c2ecf20Sopenharmony_ci break; 18168c2ecf20Sopenharmony_ci } 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci return ret; 18198c2ecf20Sopenharmony_ci} 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci/* 18228c2ecf20Sopenharmony_ci * Fill the BE gateway parameters 18238c2ecf20Sopenharmony_ci * The BE gateway expects a blob of parameters which are kept in the ACPI 18248c2ecf20Sopenharmony_ci * NHLT blob, so query the blob for interface type (i2s/pdm) and instance. 18258c2ecf20Sopenharmony_ci * The port can have multiple settings so pick based on the PCM 18268c2ecf20Sopenharmony_ci * parameters 18278c2ecf20Sopenharmony_ci */ 18288c2ecf20Sopenharmony_cistatic int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai, 18298c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig, 18308c2ecf20Sopenharmony_ci struct skl_pipe_params *params) 18318c2ecf20Sopenharmony_ci{ 18328c2ecf20Sopenharmony_ci struct nhlt_specific_cfg *cfg; 18338c2ecf20Sopenharmony_ci struct skl_dev *skl = get_skl_ctx(dai->dev); 18348c2ecf20Sopenharmony_ci int link_type = skl_tplg_be_link_type(mconfig->dev_type); 18358c2ecf20Sopenharmony_ci u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type); 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci skl_tplg_fill_dma_id(mconfig, params); 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci if (link_type == NHLT_LINK_HDA) 18408c2ecf20Sopenharmony_ci return 0; 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci /* update the blob based on virtual bus_id*/ 18438c2ecf20Sopenharmony_ci cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type, 18448c2ecf20Sopenharmony_ci params->s_fmt, params->ch, 18458c2ecf20Sopenharmony_ci params->s_freq, params->stream, 18468c2ecf20Sopenharmony_ci dev_type); 18478c2ecf20Sopenharmony_ci if (cfg) { 18488c2ecf20Sopenharmony_ci mconfig->formats_config.caps_size = cfg->size; 18498c2ecf20Sopenharmony_ci mconfig->formats_config.caps = (u32 *) &cfg->caps; 18508c2ecf20Sopenharmony_ci } else { 18518c2ecf20Sopenharmony_ci dev_err(dai->dev, "Blob NULL for id %x type %d dirn %d\n", 18528c2ecf20Sopenharmony_ci mconfig->vbus_id, link_type, 18538c2ecf20Sopenharmony_ci params->stream); 18548c2ecf20Sopenharmony_ci dev_err(dai->dev, "PCM: ch %d, freq %d, fmt %d\n", 18558c2ecf20Sopenharmony_ci params->ch, params->s_freq, params->s_fmt); 18568c2ecf20Sopenharmony_ci return -EINVAL; 18578c2ecf20Sopenharmony_ci } 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci return 0; 18608c2ecf20Sopenharmony_ci} 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_cistatic int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai, 18638c2ecf20Sopenharmony_ci struct snd_soc_dapm_widget *w, 18648c2ecf20Sopenharmony_ci struct skl_pipe_params *params) 18658c2ecf20Sopenharmony_ci{ 18668c2ecf20Sopenharmony_ci struct snd_soc_dapm_path *p; 18678c2ecf20Sopenharmony_ci int ret = -EIO; 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci snd_soc_dapm_widget_for_each_source_path(w, p) { 18708c2ecf20Sopenharmony_ci if (p->connect && is_skl_dsp_widget_type(p->source, dai->dev) && 18718c2ecf20Sopenharmony_ci p->source->priv) { 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci ret = skl_tplg_be_fill_pipe_params(dai, 18748c2ecf20Sopenharmony_ci p->source->priv, params); 18758c2ecf20Sopenharmony_ci if (ret < 0) 18768c2ecf20Sopenharmony_ci return ret; 18778c2ecf20Sopenharmony_ci } else { 18788c2ecf20Sopenharmony_ci ret = skl_tplg_be_set_src_pipe_params(dai, 18798c2ecf20Sopenharmony_ci p->source, params); 18808c2ecf20Sopenharmony_ci if (ret < 0) 18818c2ecf20Sopenharmony_ci return ret; 18828c2ecf20Sopenharmony_ci } 18838c2ecf20Sopenharmony_ci } 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci return ret; 18868c2ecf20Sopenharmony_ci} 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_cistatic int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai, 18898c2ecf20Sopenharmony_ci struct snd_soc_dapm_widget *w, struct skl_pipe_params *params) 18908c2ecf20Sopenharmony_ci{ 18918c2ecf20Sopenharmony_ci struct snd_soc_dapm_path *p; 18928c2ecf20Sopenharmony_ci int ret = -EIO; 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci snd_soc_dapm_widget_for_each_sink_path(w, p) { 18958c2ecf20Sopenharmony_ci if (p->connect && is_skl_dsp_widget_type(p->sink, dai->dev) && 18968c2ecf20Sopenharmony_ci p->sink->priv) { 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci ret = skl_tplg_be_fill_pipe_params(dai, 18998c2ecf20Sopenharmony_ci p->sink->priv, params); 19008c2ecf20Sopenharmony_ci if (ret < 0) 19018c2ecf20Sopenharmony_ci return ret; 19028c2ecf20Sopenharmony_ci } else { 19038c2ecf20Sopenharmony_ci ret = skl_tplg_be_set_sink_pipe_params( 19048c2ecf20Sopenharmony_ci dai, p->sink, params); 19058c2ecf20Sopenharmony_ci if (ret < 0) 19068c2ecf20Sopenharmony_ci return ret; 19078c2ecf20Sopenharmony_ci } 19088c2ecf20Sopenharmony_ci } 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci return ret; 19118c2ecf20Sopenharmony_ci} 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci/* 19148c2ecf20Sopenharmony_ci * BE hw_params can be a source parameters (capture) or sink parameters 19158c2ecf20Sopenharmony_ci * (playback). Based on sink and source we need to either find the source 19168c2ecf20Sopenharmony_ci * list or the sink list and set the pipeline parameters 19178c2ecf20Sopenharmony_ci */ 19188c2ecf20Sopenharmony_ciint skl_tplg_be_update_params(struct snd_soc_dai *dai, 19198c2ecf20Sopenharmony_ci struct skl_pipe_params *params) 19208c2ecf20Sopenharmony_ci{ 19218c2ecf20Sopenharmony_ci struct snd_soc_dapm_widget *w; 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { 19248c2ecf20Sopenharmony_ci w = dai->playback_widget; 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci return skl_tplg_be_set_src_pipe_params(dai, w, params); 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci } else { 19298c2ecf20Sopenharmony_ci w = dai->capture_widget; 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci return skl_tplg_be_set_sink_pipe_params(dai, w, params); 19328c2ecf20Sopenharmony_ci } 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci return 0; 19358c2ecf20Sopenharmony_ci} 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_cistatic const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = { 19388c2ecf20Sopenharmony_ci {SKL_MIXER_EVENT, skl_tplg_mixer_event}, 19398c2ecf20Sopenharmony_ci {SKL_VMIXER_EVENT, skl_tplg_mixer_event}, 19408c2ecf20Sopenharmony_ci {SKL_PGA_EVENT, skl_tplg_pga_event}, 19418c2ecf20Sopenharmony_ci}; 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_cistatic const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = { 19448c2ecf20Sopenharmony_ci {SKL_CONTROL_TYPE_BYTE_TLV, skl_tplg_tlv_control_get, 19458c2ecf20Sopenharmony_ci skl_tplg_tlv_control_set}, 19468c2ecf20Sopenharmony_ci}; 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_cistatic const struct snd_soc_tplg_kcontrol_ops skl_tplg_kcontrol_ops[] = { 19498c2ecf20Sopenharmony_ci { 19508c2ecf20Sopenharmony_ci .id = SKL_CONTROL_TYPE_MIC_SELECT, 19518c2ecf20Sopenharmony_ci .get = skl_tplg_mic_control_get, 19528c2ecf20Sopenharmony_ci .put = skl_tplg_mic_control_set, 19538c2ecf20Sopenharmony_ci }, 19548c2ecf20Sopenharmony_ci { 19558c2ecf20Sopenharmony_ci .id = SKL_CONTROL_TYPE_MULTI_IO_SELECT, 19568c2ecf20Sopenharmony_ci .get = skl_tplg_multi_config_get, 19578c2ecf20Sopenharmony_ci .put = skl_tplg_multi_config_set, 19588c2ecf20Sopenharmony_ci }, 19598c2ecf20Sopenharmony_ci { 19608c2ecf20Sopenharmony_ci .id = SKL_CONTROL_TYPE_MULTI_IO_SELECT_DMIC, 19618c2ecf20Sopenharmony_ci .get = skl_tplg_multi_config_get_dmic, 19628c2ecf20Sopenharmony_ci .put = skl_tplg_multi_config_set_dmic, 19638c2ecf20Sopenharmony_ci } 19648c2ecf20Sopenharmony_ci}; 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_cistatic int skl_tplg_fill_pipe_cfg(struct device *dev, 19678c2ecf20Sopenharmony_ci struct skl_pipe *pipe, u32 tkn, 19688c2ecf20Sopenharmony_ci u32 tkn_val, int conf_idx, int dir) 19698c2ecf20Sopenharmony_ci{ 19708c2ecf20Sopenharmony_ci struct skl_pipe_fmt *fmt; 19718c2ecf20Sopenharmony_ci struct skl_path_config *config; 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_ci switch (dir) { 19748c2ecf20Sopenharmony_ci case SKL_DIR_IN: 19758c2ecf20Sopenharmony_ci fmt = &pipe->configs[conf_idx].in_fmt; 19768c2ecf20Sopenharmony_ci break; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci case SKL_DIR_OUT: 19798c2ecf20Sopenharmony_ci fmt = &pipe->configs[conf_idx].out_fmt; 19808c2ecf20Sopenharmony_ci break; 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci default: 19838c2ecf20Sopenharmony_ci dev_err(dev, "Invalid direction: %d\n", dir); 19848c2ecf20Sopenharmony_ci return -EINVAL; 19858c2ecf20Sopenharmony_ci } 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci config = &pipe->configs[conf_idx]; 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci switch (tkn) { 19908c2ecf20Sopenharmony_ci case SKL_TKN_U32_CFG_FREQ: 19918c2ecf20Sopenharmony_ci fmt->freq = tkn_val; 19928c2ecf20Sopenharmony_ci break; 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci case SKL_TKN_U8_CFG_CHAN: 19958c2ecf20Sopenharmony_ci fmt->channels = tkn_val; 19968c2ecf20Sopenharmony_ci break; 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci case SKL_TKN_U8_CFG_BPS: 19998c2ecf20Sopenharmony_ci fmt->bps = tkn_val; 20008c2ecf20Sopenharmony_ci break; 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci case SKL_TKN_U32_PATH_MEM_PGS: 20038c2ecf20Sopenharmony_ci config->mem_pages = tkn_val; 20048c2ecf20Sopenharmony_ci break; 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci default: 20078c2ecf20Sopenharmony_ci dev_err(dev, "Invalid token config: %d\n", tkn); 20088c2ecf20Sopenharmony_ci return -EINVAL; 20098c2ecf20Sopenharmony_ci } 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci return 0; 20128c2ecf20Sopenharmony_ci} 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_cistatic int skl_tplg_fill_pipe_tkn(struct device *dev, 20158c2ecf20Sopenharmony_ci struct skl_pipe *pipe, u32 tkn, 20168c2ecf20Sopenharmony_ci u32 tkn_val) 20178c2ecf20Sopenharmony_ci{ 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ci switch (tkn) { 20208c2ecf20Sopenharmony_ci case SKL_TKN_U32_PIPE_CONN_TYPE: 20218c2ecf20Sopenharmony_ci pipe->conn_type = tkn_val; 20228c2ecf20Sopenharmony_ci break; 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci case SKL_TKN_U32_PIPE_PRIORITY: 20258c2ecf20Sopenharmony_ci pipe->pipe_priority = tkn_val; 20268c2ecf20Sopenharmony_ci break; 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci case SKL_TKN_U32_PIPE_MEM_PGS: 20298c2ecf20Sopenharmony_ci pipe->memory_pages = tkn_val; 20308c2ecf20Sopenharmony_ci break; 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci case SKL_TKN_U32_PMODE: 20338c2ecf20Sopenharmony_ci pipe->lp_mode = tkn_val; 20348c2ecf20Sopenharmony_ci break; 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci case SKL_TKN_U32_PIPE_DIRECTION: 20378c2ecf20Sopenharmony_ci pipe->direction = tkn_val; 20388c2ecf20Sopenharmony_ci break; 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci case SKL_TKN_U32_NUM_CONFIGS: 20418c2ecf20Sopenharmony_ci pipe->nr_cfgs = tkn_val; 20428c2ecf20Sopenharmony_ci break; 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci default: 20458c2ecf20Sopenharmony_ci dev_err(dev, "Token not handled %d\n", tkn); 20468c2ecf20Sopenharmony_ci return -EINVAL; 20478c2ecf20Sopenharmony_ci } 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci return 0; 20508c2ecf20Sopenharmony_ci} 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci/* 20538c2ecf20Sopenharmony_ci * Add pipeline by parsing the relevant tokens 20548c2ecf20Sopenharmony_ci * Return an existing pipe if the pipe already exists. 20558c2ecf20Sopenharmony_ci */ 20568c2ecf20Sopenharmony_cistatic int skl_tplg_add_pipe(struct device *dev, 20578c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig, struct skl_dev *skl, 20588c2ecf20Sopenharmony_ci struct snd_soc_tplg_vendor_value_elem *tkn_elem) 20598c2ecf20Sopenharmony_ci{ 20608c2ecf20Sopenharmony_ci struct skl_pipeline *ppl; 20618c2ecf20Sopenharmony_ci struct skl_pipe *pipe; 20628c2ecf20Sopenharmony_ci struct skl_pipe_params *params; 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci list_for_each_entry(ppl, &skl->ppl_list, node) { 20658c2ecf20Sopenharmony_ci if (ppl->pipe->ppl_id == tkn_elem->value) { 20668c2ecf20Sopenharmony_ci mconfig->pipe = ppl->pipe; 20678c2ecf20Sopenharmony_ci return -EEXIST; 20688c2ecf20Sopenharmony_ci } 20698c2ecf20Sopenharmony_ci } 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL); 20728c2ecf20Sopenharmony_ci if (!ppl) 20738c2ecf20Sopenharmony_ci return -ENOMEM; 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL); 20768c2ecf20Sopenharmony_ci if (!pipe) 20778c2ecf20Sopenharmony_ci return -ENOMEM; 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_ci params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL); 20808c2ecf20Sopenharmony_ci if (!params) 20818c2ecf20Sopenharmony_ci return -ENOMEM; 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_ci pipe->p_params = params; 20848c2ecf20Sopenharmony_ci pipe->ppl_id = tkn_elem->value; 20858c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&pipe->w_list); 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci ppl->pipe = pipe; 20888c2ecf20Sopenharmony_ci list_add(&ppl->node, &skl->ppl_list); 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci mconfig->pipe = pipe; 20918c2ecf20Sopenharmony_ci mconfig->pipe->state = SKL_PIPE_INVALID; 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_ci return 0; 20948c2ecf20Sopenharmony_ci} 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_cistatic int skl_tplg_get_uuid(struct device *dev, guid_t *guid, 20978c2ecf20Sopenharmony_ci struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn) 20988c2ecf20Sopenharmony_ci{ 20998c2ecf20Sopenharmony_ci if (uuid_tkn->token == SKL_TKN_UUID) { 21008c2ecf20Sopenharmony_ci import_guid(guid, uuid_tkn->uuid); 21018c2ecf20Sopenharmony_ci return 0; 21028c2ecf20Sopenharmony_ci } 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_ci dev_err(dev, "Not an UUID token %d\n", uuid_tkn->token); 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci return -EINVAL; 21078c2ecf20Sopenharmony_ci} 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_cistatic int skl_tplg_fill_pin(struct device *dev, 21108c2ecf20Sopenharmony_ci struct snd_soc_tplg_vendor_value_elem *tkn_elem, 21118c2ecf20Sopenharmony_ci struct skl_module_pin *m_pin, 21128c2ecf20Sopenharmony_ci int pin_index) 21138c2ecf20Sopenharmony_ci{ 21148c2ecf20Sopenharmony_ci int ret; 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci switch (tkn_elem->token) { 21178c2ecf20Sopenharmony_ci case SKL_TKN_U32_PIN_MOD_ID: 21188c2ecf20Sopenharmony_ci m_pin[pin_index].id.module_id = tkn_elem->value; 21198c2ecf20Sopenharmony_ci break; 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci case SKL_TKN_U32_PIN_INST_ID: 21228c2ecf20Sopenharmony_ci m_pin[pin_index].id.instance_id = tkn_elem->value; 21238c2ecf20Sopenharmony_ci break; 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci case SKL_TKN_UUID: 21268c2ecf20Sopenharmony_ci ret = skl_tplg_get_uuid(dev, &m_pin[pin_index].id.mod_uuid, 21278c2ecf20Sopenharmony_ci (struct snd_soc_tplg_vendor_uuid_elem *)tkn_elem); 21288c2ecf20Sopenharmony_ci if (ret < 0) 21298c2ecf20Sopenharmony_ci return ret; 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci break; 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci default: 21348c2ecf20Sopenharmony_ci dev_err(dev, "%d Not a pin token\n", tkn_elem->token); 21358c2ecf20Sopenharmony_ci return -EINVAL; 21368c2ecf20Sopenharmony_ci } 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci return 0; 21398c2ecf20Sopenharmony_ci} 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci/* 21428c2ecf20Sopenharmony_ci * Parse for pin config specific tokens to fill up the 21438c2ecf20Sopenharmony_ci * module private data 21448c2ecf20Sopenharmony_ci */ 21458c2ecf20Sopenharmony_cistatic int skl_tplg_fill_pins_info(struct device *dev, 21468c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig, 21478c2ecf20Sopenharmony_ci struct snd_soc_tplg_vendor_value_elem *tkn_elem, 21488c2ecf20Sopenharmony_ci int dir, int pin_count) 21498c2ecf20Sopenharmony_ci{ 21508c2ecf20Sopenharmony_ci int ret; 21518c2ecf20Sopenharmony_ci struct skl_module_pin *m_pin; 21528c2ecf20Sopenharmony_ci 21538c2ecf20Sopenharmony_ci switch (dir) { 21548c2ecf20Sopenharmony_ci case SKL_DIR_IN: 21558c2ecf20Sopenharmony_ci m_pin = mconfig->m_in_pin; 21568c2ecf20Sopenharmony_ci break; 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci case SKL_DIR_OUT: 21598c2ecf20Sopenharmony_ci m_pin = mconfig->m_out_pin; 21608c2ecf20Sopenharmony_ci break; 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci default: 21638c2ecf20Sopenharmony_ci dev_err(dev, "Invalid direction value\n"); 21648c2ecf20Sopenharmony_ci return -EINVAL; 21658c2ecf20Sopenharmony_ci } 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci ret = skl_tplg_fill_pin(dev, tkn_elem, m_pin, pin_count); 21688c2ecf20Sopenharmony_ci if (ret < 0) 21698c2ecf20Sopenharmony_ci return ret; 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci m_pin[pin_count].in_use = false; 21728c2ecf20Sopenharmony_ci m_pin[pin_count].pin_state = SKL_PIN_UNBIND; 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci return 0; 21758c2ecf20Sopenharmony_ci} 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_ci/* 21788c2ecf20Sopenharmony_ci * Fill up input/output module config format based 21798c2ecf20Sopenharmony_ci * on the direction 21808c2ecf20Sopenharmony_ci */ 21818c2ecf20Sopenharmony_cistatic int skl_tplg_fill_fmt(struct device *dev, 21828c2ecf20Sopenharmony_ci struct skl_module_fmt *dst_fmt, 21838c2ecf20Sopenharmony_ci u32 tkn, u32 value) 21848c2ecf20Sopenharmony_ci{ 21858c2ecf20Sopenharmony_ci switch (tkn) { 21868c2ecf20Sopenharmony_ci case SKL_TKN_U32_FMT_CH: 21878c2ecf20Sopenharmony_ci dst_fmt->channels = value; 21888c2ecf20Sopenharmony_ci break; 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci case SKL_TKN_U32_FMT_FREQ: 21918c2ecf20Sopenharmony_ci dst_fmt->s_freq = value; 21928c2ecf20Sopenharmony_ci break; 21938c2ecf20Sopenharmony_ci 21948c2ecf20Sopenharmony_ci case SKL_TKN_U32_FMT_BIT_DEPTH: 21958c2ecf20Sopenharmony_ci dst_fmt->bit_depth = value; 21968c2ecf20Sopenharmony_ci break; 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci case SKL_TKN_U32_FMT_SAMPLE_SIZE: 21998c2ecf20Sopenharmony_ci dst_fmt->valid_bit_depth = value; 22008c2ecf20Sopenharmony_ci break; 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci case SKL_TKN_U32_FMT_CH_CONFIG: 22038c2ecf20Sopenharmony_ci dst_fmt->ch_cfg = value; 22048c2ecf20Sopenharmony_ci break; 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci case SKL_TKN_U32_FMT_INTERLEAVE: 22078c2ecf20Sopenharmony_ci dst_fmt->interleaving_style = value; 22088c2ecf20Sopenharmony_ci break; 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ci case SKL_TKN_U32_FMT_SAMPLE_TYPE: 22118c2ecf20Sopenharmony_ci dst_fmt->sample_type = value; 22128c2ecf20Sopenharmony_ci break; 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci case SKL_TKN_U32_FMT_CH_MAP: 22158c2ecf20Sopenharmony_ci dst_fmt->ch_map = value; 22168c2ecf20Sopenharmony_ci break; 22178c2ecf20Sopenharmony_ci 22188c2ecf20Sopenharmony_ci default: 22198c2ecf20Sopenharmony_ci dev_err(dev, "Invalid token %d\n", tkn); 22208c2ecf20Sopenharmony_ci return -EINVAL; 22218c2ecf20Sopenharmony_ci } 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci return 0; 22248c2ecf20Sopenharmony_ci} 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_cistatic int skl_tplg_widget_fill_fmt(struct device *dev, 22278c2ecf20Sopenharmony_ci struct skl_module_iface *fmt, 22288c2ecf20Sopenharmony_ci u32 tkn, u32 val, u32 dir, int fmt_idx) 22298c2ecf20Sopenharmony_ci{ 22308c2ecf20Sopenharmony_ci struct skl_module_fmt *dst_fmt; 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci if (!fmt) 22338c2ecf20Sopenharmony_ci return -EINVAL; 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_ci switch (dir) { 22368c2ecf20Sopenharmony_ci case SKL_DIR_IN: 22378c2ecf20Sopenharmony_ci dst_fmt = &fmt->inputs[fmt_idx].fmt; 22388c2ecf20Sopenharmony_ci break; 22398c2ecf20Sopenharmony_ci 22408c2ecf20Sopenharmony_ci case SKL_DIR_OUT: 22418c2ecf20Sopenharmony_ci dst_fmt = &fmt->outputs[fmt_idx].fmt; 22428c2ecf20Sopenharmony_ci break; 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci default: 22458c2ecf20Sopenharmony_ci dev_err(dev, "Invalid direction: %d\n", dir); 22468c2ecf20Sopenharmony_ci return -EINVAL; 22478c2ecf20Sopenharmony_ci } 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci return skl_tplg_fill_fmt(dev, dst_fmt, tkn, val); 22508c2ecf20Sopenharmony_ci} 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_cistatic void skl_tplg_fill_pin_dynamic_val( 22538c2ecf20Sopenharmony_ci struct skl_module_pin *mpin, u32 pin_count, u32 value) 22548c2ecf20Sopenharmony_ci{ 22558c2ecf20Sopenharmony_ci int i; 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_ci for (i = 0; i < pin_count; i++) 22588c2ecf20Sopenharmony_ci mpin[i].is_dynamic = value; 22598c2ecf20Sopenharmony_ci} 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci/* 22628c2ecf20Sopenharmony_ci * Resource table in the manifest has pin specific resources 22638c2ecf20Sopenharmony_ci * like pin and pin buffer size 22648c2ecf20Sopenharmony_ci */ 22658c2ecf20Sopenharmony_cistatic int skl_tplg_manifest_pin_res_tkn(struct device *dev, 22668c2ecf20Sopenharmony_ci struct snd_soc_tplg_vendor_value_elem *tkn_elem, 22678c2ecf20Sopenharmony_ci struct skl_module_res *res, int pin_idx, int dir) 22688c2ecf20Sopenharmony_ci{ 22698c2ecf20Sopenharmony_ci struct skl_module_pin_resources *m_pin; 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci switch (dir) { 22728c2ecf20Sopenharmony_ci case SKL_DIR_IN: 22738c2ecf20Sopenharmony_ci m_pin = &res->input[pin_idx]; 22748c2ecf20Sopenharmony_ci break; 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci case SKL_DIR_OUT: 22778c2ecf20Sopenharmony_ci m_pin = &res->output[pin_idx]; 22788c2ecf20Sopenharmony_ci break; 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_ci default: 22818c2ecf20Sopenharmony_ci dev_err(dev, "Invalid pin direction: %d\n", dir); 22828c2ecf20Sopenharmony_ci return -EINVAL; 22838c2ecf20Sopenharmony_ci } 22848c2ecf20Sopenharmony_ci 22858c2ecf20Sopenharmony_ci switch (tkn_elem->token) { 22868c2ecf20Sopenharmony_ci case SKL_TKN_MM_U32_RES_PIN_ID: 22878c2ecf20Sopenharmony_ci m_pin->pin_index = tkn_elem->value; 22888c2ecf20Sopenharmony_ci break; 22898c2ecf20Sopenharmony_ci 22908c2ecf20Sopenharmony_ci case SKL_TKN_MM_U32_PIN_BUF: 22918c2ecf20Sopenharmony_ci m_pin->buf_size = tkn_elem->value; 22928c2ecf20Sopenharmony_ci break; 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ci default: 22958c2ecf20Sopenharmony_ci dev_err(dev, "Invalid token: %d\n", tkn_elem->token); 22968c2ecf20Sopenharmony_ci return -EINVAL; 22978c2ecf20Sopenharmony_ci } 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci return 0; 23008c2ecf20Sopenharmony_ci} 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci/* 23038c2ecf20Sopenharmony_ci * Fill module specific resources from the manifest's resource 23048c2ecf20Sopenharmony_ci * table like CPS, DMA size, mem_pages. 23058c2ecf20Sopenharmony_ci */ 23068c2ecf20Sopenharmony_cistatic int skl_tplg_fill_res_tkn(struct device *dev, 23078c2ecf20Sopenharmony_ci struct snd_soc_tplg_vendor_value_elem *tkn_elem, 23088c2ecf20Sopenharmony_ci struct skl_module_res *res, 23098c2ecf20Sopenharmony_ci int pin_idx, int dir) 23108c2ecf20Sopenharmony_ci{ 23118c2ecf20Sopenharmony_ci int ret, tkn_count = 0; 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_ci if (!res) 23148c2ecf20Sopenharmony_ci return -EINVAL; 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci switch (tkn_elem->token) { 23178c2ecf20Sopenharmony_ci case SKL_TKN_MM_U32_DMA_SIZE: 23188c2ecf20Sopenharmony_ci res->dma_buffer_size = tkn_elem->value; 23198c2ecf20Sopenharmony_ci break; 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ci case SKL_TKN_MM_U32_CPC: 23228c2ecf20Sopenharmony_ci res->cpc = tkn_elem->value; 23238c2ecf20Sopenharmony_ci break; 23248c2ecf20Sopenharmony_ci 23258c2ecf20Sopenharmony_ci case SKL_TKN_U32_MEM_PAGES: 23268c2ecf20Sopenharmony_ci res->is_pages = tkn_elem->value; 23278c2ecf20Sopenharmony_ci break; 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_ci case SKL_TKN_U32_OBS: 23308c2ecf20Sopenharmony_ci res->obs = tkn_elem->value; 23318c2ecf20Sopenharmony_ci break; 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_ci case SKL_TKN_U32_IBS: 23348c2ecf20Sopenharmony_ci res->ibs = tkn_elem->value; 23358c2ecf20Sopenharmony_ci break; 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_ci case SKL_TKN_MM_U32_RES_PIN_ID: 23388c2ecf20Sopenharmony_ci case SKL_TKN_MM_U32_PIN_BUF: 23398c2ecf20Sopenharmony_ci ret = skl_tplg_manifest_pin_res_tkn(dev, tkn_elem, res, 23408c2ecf20Sopenharmony_ci pin_idx, dir); 23418c2ecf20Sopenharmony_ci if (ret < 0) 23428c2ecf20Sopenharmony_ci return ret; 23438c2ecf20Sopenharmony_ci break; 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_ci case SKL_TKN_MM_U32_CPS: 23468c2ecf20Sopenharmony_ci case SKL_TKN_U32_MAX_MCPS: 23478c2ecf20Sopenharmony_ci /* ignore unused tokens */ 23488c2ecf20Sopenharmony_ci break; 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci default: 23518c2ecf20Sopenharmony_ci dev_err(dev, "Not a res type token: %d", tkn_elem->token); 23528c2ecf20Sopenharmony_ci return -EINVAL; 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_ci } 23558c2ecf20Sopenharmony_ci tkn_count++; 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci return tkn_count; 23588c2ecf20Sopenharmony_ci} 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci/* 23618c2ecf20Sopenharmony_ci * Parse tokens to fill up the module private data 23628c2ecf20Sopenharmony_ci */ 23638c2ecf20Sopenharmony_cistatic int skl_tplg_get_token(struct device *dev, 23648c2ecf20Sopenharmony_ci struct snd_soc_tplg_vendor_value_elem *tkn_elem, 23658c2ecf20Sopenharmony_ci struct skl_dev *skl, struct skl_module_cfg *mconfig) 23668c2ecf20Sopenharmony_ci{ 23678c2ecf20Sopenharmony_ci int tkn_count = 0; 23688c2ecf20Sopenharmony_ci int ret; 23698c2ecf20Sopenharmony_ci static int is_pipe_exists; 23708c2ecf20Sopenharmony_ci static int pin_index, dir, conf_idx; 23718c2ecf20Sopenharmony_ci struct skl_module_iface *iface = NULL; 23728c2ecf20Sopenharmony_ci struct skl_module_res *res = NULL; 23738c2ecf20Sopenharmony_ci int res_idx = mconfig->res_idx; 23748c2ecf20Sopenharmony_ci int fmt_idx = mconfig->fmt_idx; 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_ci /* 23778c2ecf20Sopenharmony_ci * If the manifest structure contains no modules, fill all 23788c2ecf20Sopenharmony_ci * the module data to 0th index. 23798c2ecf20Sopenharmony_ci * res_idx and fmt_idx are default set to 0. 23808c2ecf20Sopenharmony_ci */ 23818c2ecf20Sopenharmony_ci if (skl->nr_modules == 0) { 23828c2ecf20Sopenharmony_ci res = &mconfig->module->resources[res_idx]; 23838c2ecf20Sopenharmony_ci iface = &mconfig->module->formats[fmt_idx]; 23848c2ecf20Sopenharmony_ci } 23858c2ecf20Sopenharmony_ci 23868c2ecf20Sopenharmony_ci if (tkn_elem->token > SKL_TKN_MAX) 23878c2ecf20Sopenharmony_ci return -EINVAL; 23888c2ecf20Sopenharmony_ci 23898c2ecf20Sopenharmony_ci switch (tkn_elem->token) { 23908c2ecf20Sopenharmony_ci case SKL_TKN_U8_IN_QUEUE_COUNT: 23918c2ecf20Sopenharmony_ci mconfig->module->max_input_pins = tkn_elem->value; 23928c2ecf20Sopenharmony_ci break; 23938c2ecf20Sopenharmony_ci 23948c2ecf20Sopenharmony_ci case SKL_TKN_U8_OUT_QUEUE_COUNT: 23958c2ecf20Sopenharmony_ci mconfig->module->max_output_pins = tkn_elem->value; 23968c2ecf20Sopenharmony_ci break; 23978c2ecf20Sopenharmony_ci 23988c2ecf20Sopenharmony_ci case SKL_TKN_U8_DYN_IN_PIN: 23998c2ecf20Sopenharmony_ci if (!mconfig->m_in_pin) 24008c2ecf20Sopenharmony_ci mconfig->m_in_pin = 24018c2ecf20Sopenharmony_ci devm_kcalloc(dev, MAX_IN_QUEUE, 24028c2ecf20Sopenharmony_ci sizeof(*mconfig->m_in_pin), 24038c2ecf20Sopenharmony_ci GFP_KERNEL); 24048c2ecf20Sopenharmony_ci if (!mconfig->m_in_pin) 24058c2ecf20Sopenharmony_ci return -ENOMEM; 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin, MAX_IN_QUEUE, 24088c2ecf20Sopenharmony_ci tkn_elem->value); 24098c2ecf20Sopenharmony_ci break; 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_ci case SKL_TKN_U8_DYN_OUT_PIN: 24128c2ecf20Sopenharmony_ci if (!mconfig->m_out_pin) 24138c2ecf20Sopenharmony_ci mconfig->m_out_pin = 24148c2ecf20Sopenharmony_ci devm_kcalloc(dev, MAX_IN_QUEUE, 24158c2ecf20Sopenharmony_ci sizeof(*mconfig->m_in_pin), 24168c2ecf20Sopenharmony_ci GFP_KERNEL); 24178c2ecf20Sopenharmony_ci if (!mconfig->m_out_pin) 24188c2ecf20Sopenharmony_ci return -ENOMEM; 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_ci skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin, MAX_OUT_QUEUE, 24218c2ecf20Sopenharmony_ci tkn_elem->value); 24228c2ecf20Sopenharmony_ci break; 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci case SKL_TKN_U8_TIME_SLOT: 24258c2ecf20Sopenharmony_ci mconfig->time_slot = tkn_elem->value; 24268c2ecf20Sopenharmony_ci break; 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_ci case SKL_TKN_U8_CORE_ID: 24298c2ecf20Sopenharmony_ci mconfig->core_id = tkn_elem->value; 24308c2ecf20Sopenharmony_ci break; 24318c2ecf20Sopenharmony_ci 24328c2ecf20Sopenharmony_ci case SKL_TKN_U8_MOD_TYPE: 24338c2ecf20Sopenharmony_ci mconfig->m_type = tkn_elem->value; 24348c2ecf20Sopenharmony_ci break; 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_ci case SKL_TKN_U8_DEV_TYPE: 24378c2ecf20Sopenharmony_ci mconfig->dev_type = tkn_elem->value; 24388c2ecf20Sopenharmony_ci break; 24398c2ecf20Sopenharmony_ci 24408c2ecf20Sopenharmony_ci case SKL_TKN_U8_HW_CONN_TYPE: 24418c2ecf20Sopenharmony_ci mconfig->hw_conn_type = tkn_elem->value; 24428c2ecf20Sopenharmony_ci break; 24438c2ecf20Sopenharmony_ci 24448c2ecf20Sopenharmony_ci case SKL_TKN_U16_MOD_INST_ID: 24458c2ecf20Sopenharmony_ci mconfig->id.instance_id = 24468c2ecf20Sopenharmony_ci tkn_elem->value; 24478c2ecf20Sopenharmony_ci break; 24488c2ecf20Sopenharmony_ci 24498c2ecf20Sopenharmony_ci case SKL_TKN_U32_MEM_PAGES: 24508c2ecf20Sopenharmony_ci case SKL_TKN_U32_MAX_MCPS: 24518c2ecf20Sopenharmony_ci case SKL_TKN_U32_OBS: 24528c2ecf20Sopenharmony_ci case SKL_TKN_U32_IBS: 24538c2ecf20Sopenharmony_ci ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_index, dir); 24548c2ecf20Sopenharmony_ci if (ret < 0) 24558c2ecf20Sopenharmony_ci return ret; 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_ci break; 24588c2ecf20Sopenharmony_ci 24598c2ecf20Sopenharmony_ci case SKL_TKN_U32_VBUS_ID: 24608c2ecf20Sopenharmony_ci mconfig->vbus_id = tkn_elem->value; 24618c2ecf20Sopenharmony_ci break; 24628c2ecf20Sopenharmony_ci 24638c2ecf20Sopenharmony_ci case SKL_TKN_U32_PARAMS_FIXUP: 24648c2ecf20Sopenharmony_ci mconfig->params_fixup = tkn_elem->value; 24658c2ecf20Sopenharmony_ci break; 24668c2ecf20Sopenharmony_ci 24678c2ecf20Sopenharmony_ci case SKL_TKN_U32_CONVERTER: 24688c2ecf20Sopenharmony_ci mconfig->converter = tkn_elem->value; 24698c2ecf20Sopenharmony_ci break; 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_ci case SKL_TKN_U32_D0I3_CAPS: 24728c2ecf20Sopenharmony_ci mconfig->d0i3_caps = tkn_elem->value; 24738c2ecf20Sopenharmony_ci break; 24748c2ecf20Sopenharmony_ci 24758c2ecf20Sopenharmony_ci case SKL_TKN_U32_PIPE_ID: 24768c2ecf20Sopenharmony_ci ret = skl_tplg_add_pipe(dev, 24778c2ecf20Sopenharmony_ci mconfig, skl, tkn_elem); 24788c2ecf20Sopenharmony_ci 24798c2ecf20Sopenharmony_ci if (ret < 0) { 24808c2ecf20Sopenharmony_ci if (ret == -EEXIST) { 24818c2ecf20Sopenharmony_ci is_pipe_exists = 1; 24828c2ecf20Sopenharmony_ci break; 24838c2ecf20Sopenharmony_ci } 24848c2ecf20Sopenharmony_ci return is_pipe_exists; 24858c2ecf20Sopenharmony_ci } 24868c2ecf20Sopenharmony_ci 24878c2ecf20Sopenharmony_ci break; 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_ci case SKL_TKN_U32_PIPE_CONFIG_ID: 24908c2ecf20Sopenharmony_ci conf_idx = tkn_elem->value; 24918c2ecf20Sopenharmony_ci break; 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_ci case SKL_TKN_U32_PIPE_CONN_TYPE: 24948c2ecf20Sopenharmony_ci case SKL_TKN_U32_PIPE_PRIORITY: 24958c2ecf20Sopenharmony_ci case SKL_TKN_U32_PIPE_MEM_PGS: 24968c2ecf20Sopenharmony_ci case SKL_TKN_U32_PMODE: 24978c2ecf20Sopenharmony_ci case SKL_TKN_U32_PIPE_DIRECTION: 24988c2ecf20Sopenharmony_ci case SKL_TKN_U32_NUM_CONFIGS: 24998c2ecf20Sopenharmony_ci if (is_pipe_exists) { 25008c2ecf20Sopenharmony_ci ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe, 25018c2ecf20Sopenharmony_ci tkn_elem->token, tkn_elem->value); 25028c2ecf20Sopenharmony_ci if (ret < 0) 25038c2ecf20Sopenharmony_ci return ret; 25048c2ecf20Sopenharmony_ci } 25058c2ecf20Sopenharmony_ci 25068c2ecf20Sopenharmony_ci break; 25078c2ecf20Sopenharmony_ci 25088c2ecf20Sopenharmony_ci case SKL_TKN_U32_PATH_MEM_PGS: 25098c2ecf20Sopenharmony_ci case SKL_TKN_U32_CFG_FREQ: 25108c2ecf20Sopenharmony_ci case SKL_TKN_U8_CFG_CHAN: 25118c2ecf20Sopenharmony_ci case SKL_TKN_U8_CFG_BPS: 25128c2ecf20Sopenharmony_ci if (mconfig->pipe->nr_cfgs) { 25138c2ecf20Sopenharmony_ci ret = skl_tplg_fill_pipe_cfg(dev, mconfig->pipe, 25148c2ecf20Sopenharmony_ci tkn_elem->token, tkn_elem->value, 25158c2ecf20Sopenharmony_ci conf_idx, dir); 25168c2ecf20Sopenharmony_ci if (ret < 0) 25178c2ecf20Sopenharmony_ci return ret; 25188c2ecf20Sopenharmony_ci } 25198c2ecf20Sopenharmony_ci break; 25208c2ecf20Sopenharmony_ci 25218c2ecf20Sopenharmony_ci case SKL_TKN_CFG_MOD_RES_ID: 25228c2ecf20Sopenharmony_ci mconfig->mod_cfg[conf_idx].res_idx = tkn_elem->value; 25238c2ecf20Sopenharmony_ci break; 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci case SKL_TKN_CFG_MOD_FMT_ID: 25268c2ecf20Sopenharmony_ci mconfig->mod_cfg[conf_idx].fmt_idx = tkn_elem->value; 25278c2ecf20Sopenharmony_ci break; 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_ci /* 25308c2ecf20Sopenharmony_ci * SKL_TKN_U32_DIR_PIN_COUNT token has the value for both 25318c2ecf20Sopenharmony_ci * direction and the pin count. The first four bits represent 25328c2ecf20Sopenharmony_ci * direction and next four the pin count. 25338c2ecf20Sopenharmony_ci */ 25348c2ecf20Sopenharmony_ci case SKL_TKN_U32_DIR_PIN_COUNT: 25358c2ecf20Sopenharmony_ci dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK; 25368c2ecf20Sopenharmony_ci pin_index = (tkn_elem->value & 25378c2ecf20Sopenharmony_ci SKL_PIN_COUNT_MASK) >> 4; 25388c2ecf20Sopenharmony_ci 25398c2ecf20Sopenharmony_ci break; 25408c2ecf20Sopenharmony_ci 25418c2ecf20Sopenharmony_ci case SKL_TKN_U32_FMT_CH: 25428c2ecf20Sopenharmony_ci case SKL_TKN_U32_FMT_FREQ: 25438c2ecf20Sopenharmony_ci case SKL_TKN_U32_FMT_BIT_DEPTH: 25448c2ecf20Sopenharmony_ci case SKL_TKN_U32_FMT_SAMPLE_SIZE: 25458c2ecf20Sopenharmony_ci case SKL_TKN_U32_FMT_CH_CONFIG: 25468c2ecf20Sopenharmony_ci case SKL_TKN_U32_FMT_INTERLEAVE: 25478c2ecf20Sopenharmony_ci case SKL_TKN_U32_FMT_SAMPLE_TYPE: 25488c2ecf20Sopenharmony_ci case SKL_TKN_U32_FMT_CH_MAP: 25498c2ecf20Sopenharmony_ci ret = skl_tplg_widget_fill_fmt(dev, iface, tkn_elem->token, 25508c2ecf20Sopenharmony_ci tkn_elem->value, dir, pin_index); 25518c2ecf20Sopenharmony_ci 25528c2ecf20Sopenharmony_ci if (ret < 0) 25538c2ecf20Sopenharmony_ci return ret; 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ci break; 25568c2ecf20Sopenharmony_ci 25578c2ecf20Sopenharmony_ci case SKL_TKN_U32_PIN_MOD_ID: 25588c2ecf20Sopenharmony_ci case SKL_TKN_U32_PIN_INST_ID: 25598c2ecf20Sopenharmony_ci case SKL_TKN_UUID: 25608c2ecf20Sopenharmony_ci ret = skl_tplg_fill_pins_info(dev, 25618c2ecf20Sopenharmony_ci mconfig, tkn_elem, dir, 25628c2ecf20Sopenharmony_ci pin_index); 25638c2ecf20Sopenharmony_ci if (ret < 0) 25648c2ecf20Sopenharmony_ci return ret; 25658c2ecf20Sopenharmony_ci 25668c2ecf20Sopenharmony_ci break; 25678c2ecf20Sopenharmony_ci 25688c2ecf20Sopenharmony_ci case SKL_TKN_U32_CAPS_SIZE: 25698c2ecf20Sopenharmony_ci mconfig->formats_config.caps_size = 25708c2ecf20Sopenharmony_ci tkn_elem->value; 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_ci break; 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_ci case SKL_TKN_U32_CAPS_SET_PARAMS: 25758c2ecf20Sopenharmony_ci mconfig->formats_config.set_params = 25768c2ecf20Sopenharmony_ci tkn_elem->value; 25778c2ecf20Sopenharmony_ci break; 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ci case SKL_TKN_U32_CAPS_PARAMS_ID: 25808c2ecf20Sopenharmony_ci mconfig->formats_config.param_id = 25818c2ecf20Sopenharmony_ci tkn_elem->value; 25828c2ecf20Sopenharmony_ci break; 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci case SKL_TKN_U32_PROC_DOMAIN: 25858c2ecf20Sopenharmony_ci mconfig->domain = 25868c2ecf20Sopenharmony_ci tkn_elem->value; 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ci break; 25898c2ecf20Sopenharmony_ci 25908c2ecf20Sopenharmony_ci case SKL_TKN_U32_DMA_BUF_SIZE: 25918c2ecf20Sopenharmony_ci mconfig->dma_buffer_size = tkn_elem->value; 25928c2ecf20Sopenharmony_ci break; 25938c2ecf20Sopenharmony_ci 25948c2ecf20Sopenharmony_ci case SKL_TKN_U8_IN_PIN_TYPE: 25958c2ecf20Sopenharmony_ci case SKL_TKN_U8_OUT_PIN_TYPE: 25968c2ecf20Sopenharmony_ci case SKL_TKN_U8_CONN_TYPE: 25978c2ecf20Sopenharmony_ci break; 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_ci default: 26008c2ecf20Sopenharmony_ci dev_err(dev, "Token %d not handled\n", 26018c2ecf20Sopenharmony_ci tkn_elem->token); 26028c2ecf20Sopenharmony_ci return -EINVAL; 26038c2ecf20Sopenharmony_ci } 26048c2ecf20Sopenharmony_ci 26058c2ecf20Sopenharmony_ci tkn_count++; 26068c2ecf20Sopenharmony_ci 26078c2ecf20Sopenharmony_ci return tkn_count; 26088c2ecf20Sopenharmony_ci} 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_ci/* 26118c2ecf20Sopenharmony_ci * Parse the vendor array for specific tokens to construct 26128c2ecf20Sopenharmony_ci * module private data 26138c2ecf20Sopenharmony_ci */ 26148c2ecf20Sopenharmony_cistatic int skl_tplg_get_tokens(struct device *dev, 26158c2ecf20Sopenharmony_ci char *pvt_data, struct skl_dev *skl, 26168c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig, int block_size) 26178c2ecf20Sopenharmony_ci{ 26188c2ecf20Sopenharmony_ci struct snd_soc_tplg_vendor_array *array; 26198c2ecf20Sopenharmony_ci struct snd_soc_tplg_vendor_value_elem *tkn_elem; 26208c2ecf20Sopenharmony_ci int tkn_count = 0, ret; 26218c2ecf20Sopenharmony_ci int off = 0, tuple_size = 0; 26228c2ecf20Sopenharmony_ci bool is_module_guid = true; 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_ci if (block_size <= 0) 26258c2ecf20Sopenharmony_ci return -EINVAL; 26268c2ecf20Sopenharmony_ci 26278c2ecf20Sopenharmony_ci while (tuple_size < block_size) { 26288c2ecf20Sopenharmony_ci array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off); 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_ci off += array->size; 26318c2ecf20Sopenharmony_ci 26328c2ecf20Sopenharmony_ci switch (array->type) { 26338c2ecf20Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_STRING: 26348c2ecf20Sopenharmony_ci dev_warn(dev, "no string tokens expected for skl tplg\n"); 26358c2ecf20Sopenharmony_ci continue; 26368c2ecf20Sopenharmony_ci 26378c2ecf20Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_UUID: 26388c2ecf20Sopenharmony_ci if (is_module_guid) { 26398c2ecf20Sopenharmony_ci ret = skl_tplg_get_uuid(dev, (guid_t *)mconfig->guid, 26408c2ecf20Sopenharmony_ci array->uuid); 26418c2ecf20Sopenharmony_ci is_module_guid = false; 26428c2ecf20Sopenharmony_ci } else { 26438c2ecf20Sopenharmony_ci ret = skl_tplg_get_token(dev, array->value, skl, 26448c2ecf20Sopenharmony_ci mconfig); 26458c2ecf20Sopenharmony_ci } 26468c2ecf20Sopenharmony_ci 26478c2ecf20Sopenharmony_ci if (ret < 0) 26488c2ecf20Sopenharmony_ci return ret; 26498c2ecf20Sopenharmony_ci 26508c2ecf20Sopenharmony_ci tuple_size += sizeof(*array->uuid); 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci continue; 26538c2ecf20Sopenharmony_ci 26548c2ecf20Sopenharmony_ci default: 26558c2ecf20Sopenharmony_ci tkn_elem = array->value; 26568c2ecf20Sopenharmony_ci tkn_count = 0; 26578c2ecf20Sopenharmony_ci break; 26588c2ecf20Sopenharmony_ci } 26598c2ecf20Sopenharmony_ci 26608c2ecf20Sopenharmony_ci while (tkn_count <= (array->num_elems - 1)) { 26618c2ecf20Sopenharmony_ci ret = skl_tplg_get_token(dev, tkn_elem, 26628c2ecf20Sopenharmony_ci skl, mconfig); 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_ci if (ret < 0) 26658c2ecf20Sopenharmony_ci return ret; 26668c2ecf20Sopenharmony_ci 26678c2ecf20Sopenharmony_ci tkn_count = tkn_count + ret; 26688c2ecf20Sopenharmony_ci tkn_elem++; 26698c2ecf20Sopenharmony_ci } 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci tuple_size += tkn_count * sizeof(*tkn_elem); 26728c2ecf20Sopenharmony_ci } 26738c2ecf20Sopenharmony_ci 26748c2ecf20Sopenharmony_ci return off; 26758c2ecf20Sopenharmony_ci} 26768c2ecf20Sopenharmony_ci 26778c2ecf20Sopenharmony_ci/* 26788c2ecf20Sopenharmony_ci * Every data block is preceded by a descriptor to read the number 26798c2ecf20Sopenharmony_ci * of data blocks, they type of the block and it's size 26808c2ecf20Sopenharmony_ci */ 26818c2ecf20Sopenharmony_cistatic int skl_tplg_get_desc_blocks(struct device *dev, 26828c2ecf20Sopenharmony_ci struct snd_soc_tplg_vendor_array *array) 26838c2ecf20Sopenharmony_ci{ 26848c2ecf20Sopenharmony_ci struct snd_soc_tplg_vendor_value_elem *tkn_elem; 26858c2ecf20Sopenharmony_ci 26868c2ecf20Sopenharmony_ci tkn_elem = array->value; 26878c2ecf20Sopenharmony_ci 26888c2ecf20Sopenharmony_ci switch (tkn_elem->token) { 26898c2ecf20Sopenharmony_ci case SKL_TKN_U8_NUM_BLOCKS: 26908c2ecf20Sopenharmony_ci case SKL_TKN_U8_BLOCK_TYPE: 26918c2ecf20Sopenharmony_ci case SKL_TKN_U16_BLOCK_SIZE: 26928c2ecf20Sopenharmony_ci return tkn_elem->value; 26938c2ecf20Sopenharmony_ci 26948c2ecf20Sopenharmony_ci default: 26958c2ecf20Sopenharmony_ci dev_err(dev, "Invalid descriptor token %d\n", tkn_elem->token); 26968c2ecf20Sopenharmony_ci break; 26978c2ecf20Sopenharmony_ci } 26988c2ecf20Sopenharmony_ci 26998c2ecf20Sopenharmony_ci return -EINVAL; 27008c2ecf20Sopenharmony_ci} 27018c2ecf20Sopenharmony_ci 27028c2ecf20Sopenharmony_ci/* Functions to parse private data from configuration file format v4 */ 27038c2ecf20Sopenharmony_ci 27048c2ecf20Sopenharmony_ci/* 27058c2ecf20Sopenharmony_ci * Add pipeline from topology binary into driver pipeline list 27068c2ecf20Sopenharmony_ci * 27078c2ecf20Sopenharmony_ci * If already added we return that instance 27088c2ecf20Sopenharmony_ci * Otherwise we create a new instance and add into driver list 27098c2ecf20Sopenharmony_ci */ 27108c2ecf20Sopenharmony_cistatic int skl_tplg_add_pipe_v4(struct device *dev, 27118c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig, struct skl_dev *skl, 27128c2ecf20Sopenharmony_ci struct skl_dfw_v4_pipe *dfw_pipe) 27138c2ecf20Sopenharmony_ci{ 27148c2ecf20Sopenharmony_ci struct skl_pipeline *ppl; 27158c2ecf20Sopenharmony_ci struct skl_pipe *pipe; 27168c2ecf20Sopenharmony_ci struct skl_pipe_params *params; 27178c2ecf20Sopenharmony_ci 27188c2ecf20Sopenharmony_ci list_for_each_entry(ppl, &skl->ppl_list, node) { 27198c2ecf20Sopenharmony_ci if (ppl->pipe->ppl_id == dfw_pipe->pipe_id) { 27208c2ecf20Sopenharmony_ci mconfig->pipe = ppl->pipe; 27218c2ecf20Sopenharmony_ci return 0; 27228c2ecf20Sopenharmony_ci } 27238c2ecf20Sopenharmony_ci } 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_ci ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL); 27268c2ecf20Sopenharmony_ci if (!ppl) 27278c2ecf20Sopenharmony_ci return -ENOMEM; 27288c2ecf20Sopenharmony_ci 27298c2ecf20Sopenharmony_ci pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL); 27308c2ecf20Sopenharmony_ci if (!pipe) 27318c2ecf20Sopenharmony_ci return -ENOMEM; 27328c2ecf20Sopenharmony_ci 27338c2ecf20Sopenharmony_ci params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL); 27348c2ecf20Sopenharmony_ci if (!params) 27358c2ecf20Sopenharmony_ci return -ENOMEM; 27368c2ecf20Sopenharmony_ci 27378c2ecf20Sopenharmony_ci pipe->ppl_id = dfw_pipe->pipe_id; 27388c2ecf20Sopenharmony_ci pipe->memory_pages = dfw_pipe->memory_pages; 27398c2ecf20Sopenharmony_ci pipe->pipe_priority = dfw_pipe->pipe_priority; 27408c2ecf20Sopenharmony_ci pipe->conn_type = dfw_pipe->conn_type; 27418c2ecf20Sopenharmony_ci pipe->state = SKL_PIPE_INVALID; 27428c2ecf20Sopenharmony_ci pipe->p_params = params; 27438c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&pipe->w_list); 27448c2ecf20Sopenharmony_ci 27458c2ecf20Sopenharmony_ci ppl->pipe = pipe; 27468c2ecf20Sopenharmony_ci list_add(&ppl->node, &skl->ppl_list); 27478c2ecf20Sopenharmony_ci 27488c2ecf20Sopenharmony_ci mconfig->pipe = pipe; 27498c2ecf20Sopenharmony_ci 27508c2ecf20Sopenharmony_ci return 0; 27518c2ecf20Sopenharmony_ci} 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_cistatic void skl_fill_module_pin_info_v4(struct skl_dfw_v4_module_pin *dfw_pin, 27548c2ecf20Sopenharmony_ci struct skl_module_pin *m_pin, 27558c2ecf20Sopenharmony_ci bool is_dynamic, int max_pin) 27568c2ecf20Sopenharmony_ci{ 27578c2ecf20Sopenharmony_ci int i; 27588c2ecf20Sopenharmony_ci 27598c2ecf20Sopenharmony_ci for (i = 0; i < max_pin; i++) { 27608c2ecf20Sopenharmony_ci m_pin[i].id.module_id = dfw_pin[i].module_id; 27618c2ecf20Sopenharmony_ci m_pin[i].id.instance_id = dfw_pin[i].instance_id; 27628c2ecf20Sopenharmony_ci m_pin[i].in_use = false; 27638c2ecf20Sopenharmony_ci m_pin[i].is_dynamic = is_dynamic; 27648c2ecf20Sopenharmony_ci m_pin[i].pin_state = SKL_PIN_UNBIND; 27658c2ecf20Sopenharmony_ci } 27668c2ecf20Sopenharmony_ci} 27678c2ecf20Sopenharmony_ci 27688c2ecf20Sopenharmony_cistatic void skl_tplg_fill_fmt_v4(struct skl_module_pin_fmt *dst_fmt, 27698c2ecf20Sopenharmony_ci struct skl_dfw_v4_module_fmt *src_fmt, 27708c2ecf20Sopenharmony_ci int pins) 27718c2ecf20Sopenharmony_ci{ 27728c2ecf20Sopenharmony_ci int i; 27738c2ecf20Sopenharmony_ci 27748c2ecf20Sopenharmony_ci for (i = 0; i < pins; i++) { 27758c2ecf20Sopenharmony_ci dst_fmt[i].fmt.channels = src_fmt[i].channels; 27768c2ecf20Sopenharmony_ci dst_fmt[i].fmt.s_freq = src_fmt[i].freq; 27778c2ecf20Sopenharmony_ci dst_fmt[i].fmt.bit_depth = src_fmt[i].bit_depth; 27788c2ecf20Sopenharmony_ci dst_fmt[i].fmt.valid_bit_depth = src_fmt[i].valid_bit_depth; 27798c2ecf20Sopenharmony_ci dst_fmt[i].fmt.ch_cfg = src_fmt[i].ch_cfg; 27808c2ecf20Sopenharmony_ci dst_fmt[i].fmt.ch_map = src_fmt[i].ch_map; 27818c2ecf20Sopenharmony_ci dst_fmt[i].fmt.interleaving_style = 27828c2ecf20Sopenharmony_ci src_fmt[i].interleaving_style; 27838c2ecf20Sopenharmony_ci dst_fmt[i].fmt.sample_type = src_fmt[i].sample_type; 27848c2ecf20Sopenharmony_ci } 27858c2ecf20Sopenharmony_ci} 27868c2ecf20Sopenharmony_ci 27878c2ecf20Sopenharmony_cistatic int skl_tplg_get_pvt_data_v4(struct snd_soc_tplg_dapm_widget *tplg_w, 27888c2ecf20Sopenharmony_ci struct skl_dev *skl, struct device *dev, 27898c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig) 27908c2ecf20Sopenharmony_ci{ 27918c2ecf20Sopenharmony_ci struct skl_dfw_v4_module *dfw = 27928c2ecf20Sopenharmony_ci (struct skl_dfw_v4_module *)tplg_w->priv.data; 27938c2ecf20Sopenharmony_ci int ret; 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_ci dev_dbg(dev, "Parsing Skylake v4 widget topology data\n"); 27968c2ecf20Sopenharmony_ci 27978c2ecf20Sopenharmony_ci ret = guid_parse(dfw->uuid, (guid_t *)mconfig->guid); 27988c2ecf20Sopenharmony_ci if (ret) 27998c2ecf20Sopenharmony_ci return ret; 28008c2ecf20Sopenharmony_ci mconfig->id.module_id = -1; 28018c2ecf20Sopenharmony_ci mconfig->id.instance_id = dfw->instance_id; 28028c2ecf20Sopenharmony_ci mconfig->module->resources[0].cpc = dfw->max_mcps / 1000; 28038c2ecf20Sopenharmony_ci mconfig->module->resources[0].ibs = dfw->ibs; 28048c2ecf20Sopenharmony_ci mconfig->module->resources[0].obs = dfw->obs; 28058c2ecf20Sopenharmony_ci mconfig->core_id = dfw->core_id; 28068c2ecf20Sopenharmony_ci mconfig->module->max_input_pins = dfw->max_in_queue; 28078c2ecf20Sopenharmony_ci mconfig->module->max_output_pins = dfw->max_out_queue; 28088c2ecf20Sopenharmony_ci mconfig->module->loadable = dfw->is_loadable; 28098c2ecf20Sopenharmony_ci skl_tplg_fill_fmt_v4(mconfig->module->formats[0].inputs, dfw->in_fmt, 28108c2ecf20Sopenharmony_ci MAX_IN_QUEUE); 28118c2ecf20Sopenharmony_ci skl_tplg_fill_fmt_v4(mconfig->module->formats[0].outputs, dfw->out_fmt, 28128c2ecf20Sopenharmony_ci MAX_OUT_QUEUE); 28138c2ecf20Sopenharmony_ci 28148c2ecf20Sopenharmony_ci mconfig->params_fixup = dfw->params_fixup; 28158c2ecf20Sopenharmony_ci mconfig->converter = dfw->converter; 28168c2ecf20Sopenharmony_ci mconfig->m_type = dfw->module_type; 28178c2ecf20Sopenharmony_ci mconfig->vbus_id = dfw->vbus_id; 28188c2ecf20Sopenharmony_ci mconfig->module->resources[0].is_pages = dfw->mem_pages; 28198c2ecf20Sopenharmony_ci 28208c2ecf20Sopenharmony_ci ret = skl_tplg_add_pipe_v4(dev, mconfig, skl, &dfw->pipe); 28218c2ecf20Sopenharmony_ci if (ret) 28228c2ecf20Sopenharmony_ci return ret; 28238c2ecf20Sopenharmony_ci 28248c2ecf20Sopenharmony_ci mconfig->dev_type = dfw->dev_type; 28258c2ecf20Sopenharmony_ci mconfig->hw_conn_type = dfw->hw_conn_type; 28268c2ecf20Sopenharmony_ci mconfig->time_slot = dfw->time_slot; 28278c2ecf20Sopenharmony_ci mconfig->formats_config.caps_size = dfw->caps.caps_size; 28288c2ecf20Sopenharmony_ci 28298c2ecf20Sopenharmony_ci mconfig->m_in_pin = devm_kcalloc(dev, 28308c2ecf20Sopenharmony_ci MAX_IN_QUEUE, sizeof(*mconfig->m_in_pin), 28318c2ecf20Sopenharmony_ci GFP_KERNEL); 28328c2ecf20Sopenharmony_ci if (!mconfig->m_in_pin) 28338c2ecf20Sopenharmony_ci return -ENOMEM; 28348c2ecf20Sopenharmony_ci 28358c2ecf20Sopenharmony_ci mconfig->m_out_pin = devm_kcalloc(dev, 28368c2ecf20Sopenharmony_ci MAX_OUT_QUEUE, sizeof(*mconfig->m_out_pin), 28378c2ecf20Sopenharmony_ci GFP_KERNEL); 28388c2ecf20Sopenharmony_ci if (!mconfig->m_out_pin) 28398c2ecf20Sopenharmony_ci return -ENOMEM; 28408c2ecf20Sopenharmony_ci 28418c2ecf20Sopenharmony_ci skl_fill_module_pin_info_v4(dfw->in_pin, mconfig->m_in_pin, 28428c2ecf20Sopenharmony_ci dfw->is_dynamic_in_pin, 28438c2ecf20Sopenharmony_ci mconfig->module->max_input_pins); 28448c2ecf20Sopenharmony_ci skl_fill_module_pin_info_v4(dfw->out_pin, mconfig->m_out_pin, 28458c2ecf20Sopenharmony_ci dfw->is_dynamic_out_pin, 28468c2ecf20Sopenharmony_ci mconfig->module->max_output_pins); 28478c2ecf20Sopenharmony_ci 28488c2ecf20Sopenharmony_ci if (mconfig->formats_config.caps_size) { 28498c2ecf20Sopenharmony_ci mconfig->formats_config.set_params = dfw->caps.set_params; 28508c2ecf20Sopenharmony_ci mconfig->formats_config.param_id = dfw->caps.param_id; 28518c2ecf20Sopenharmony_ci mconfig->formats_config.caps = 28528c2ecf20Sopenharmony_ci devm_kzalloc(dev, mconfig->formats_config.caps_size, 28538c2ecf20Sopenharmony_ci GFP_KERNEL); 28548c2ecf20Sopenharmony_ci if (!mconfig->formats_config.caps) 28558c2ecf20Sopenharmony_ci return -ENOMEM; 28568c2ecf20Sopenharmony_ci memcpy(mconfig->formats_config.caps, dfw->caps.caps, 28578c2ecf20Sopenharmony_ci dfw->caps.caps_size); 28588c2ecf20Sopenharmony_ci } 28598c2ecf20Sopenharmony_ci 28608c2ecf20Sopenharmony_ci return 0; 28618c2ecf20Sopenharmony_ci} 28628c2ecf20Sopenharmony_ci 28638c2ecf20Sopenharmony_ci/* 28648c2ecf20Sopenharmony_ci * Parse the private data for the token and corresponding value. 28658c2ecf20Sopenharmony_ci * The private data can have multiple data blocks. So, a data block 28668c2ecf20Sopenharmony_ci * is preceded by a descriptor for number of blocks and a descriptor 28678c2ecf20Sopenharmony_ci * for the type and size of the suceeding data block. 28688c2ecf20Sopenharmony_ci */ 28698c2ecf20Sopenharmony_cistatic int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w, 28708c2ecf20Sopenharmony_ci struct skl_dev *skl, struct device *dev, 28718c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig) 28728c2ecf20Sopenharmony_ci{ 28738c2ecf20Sopenharmony_ci struct snd_soc_tplg_vendor_array *array; 28748c2ecf20Sopenharmony_ci int num_blocks, block_size, block_type, off = 0; 28758c2ecf20Sopenharmony_ci char *data; 28768c2ecf20Sopenharmony_ci int ret; 28778c2ecf20Sopenharmony_ci 28788c2ecf20Sopenharmony_ci /* 28798c2ecf20Sopenharmony_ci * v4 configuration files have a valid UUID at the start of 28808c2ecf20Sopenharmony_ci * the widget's private data. 28818c2ecf20Sopenharmony_ci */ 28828c2ecf20Sopenharmony_ci if (uuid_is_valid((char *)tplg_w->priv.data)) 28838c2ecf20Sopenharmony_ci return skl_tplg_get_pvt_data_v4(tplg_w, skl, dev, mconfig); 28848c2ecf20Sopenharmony_ci 28858c2ecf20Sopenharmony_ci /* Read the NUM_DATA_BLOCKS descriptor */ 28868c2ecf20Sopenharmony_ci array = (struct snd_soc_tplg_vendor_array *)tplg_w->priv.data; 28878c2ecf20Sopenharmony_ci ret = skl_tplg_get_desc_blocks(dev, array); 28888c2ecf20Sopenharmony_ci if (ret < 0) 28898c2ecf20Sopenharmony_ci return ret; 28908c2ecf20Sopenharmony_ci num_blocks = ret; 28918c2ecf20Sopenharmony_ci 28928c2ecf20Sopenharmony_ci off += array->size; 28938c2ecf20Sopenharmony_ci /* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */ 28948c2ecf20Sopenharmony_ci while (num_blocks > 0) { 28958c2ecf20Sopenharmony_ci array = (struct snd_soc_tplg_vendor_array *) 28968c2ecf20Sopenharmony_ci (tplg_w->priv.data + off); 28978c2ecf20Sopenharmony_ci 28988c2ecf20Sopenharmony_ci ret = skl_tplg_get_desc_blocks(dev, array); 28998c2ecf20Sopenharmony_ci 29008c2ecf20Sopenharmony_ci if (ret < 0) 29018c2ecf20Sopenharmony_ci return ret; 29028c2ecf20Sopenharmony_ci block_type = ret; 29038c2ecf20Sopenharmony_ci off += array->size; 29048c2ecf20Sopenharmony_ci 29058c2ecf20Sopenharmony_ci array = (struct snd_soc_tplg_vendor_array *) 29068c2ecf20Sopenharmony_ci (tplg_w->priv.data + off); 29078c2ecf20Sopenharmony_ci 29088c2ecf20Sopenharmony_ci ret = skl_tplg_get_desc_blocks(dev, array); 29098c2ecf20Sopenharmony_ci 29108c2ecf20Sopenharmony_ci if (ret < 0) 29118c2ecf20Sopenharmony_ci return ret; 29128c2ecf20Sopenharmony_ci block_size = ret; 29138c2ecf20Sopenharmony_ci off += array->size; 29148c2ecf20Sopenharmony_ci 29158c2ecf20Sopenharmony_ci array = (struct snd_soc_tplg_vendor_array *) 29168c2ecf20Sopenharmony_ci (tplg_w->priv.data + off); 29178c2ecf20Sopenharmony_ci 29188c2ecf20Sopenharmony_ci data = (tplg_w->priv.data + off); 29198c2ecf20Sopenharmony_ci 29208c2ecf20Sopenharmony_ci if (block_type == SKL_TYPE_TUPLE) { 29218c2ecf20Sopenharmony_ci ret = skl_tplg_get_tokens(dev, data, 29228c2ecf20Sopenharmony_ci skl, mconfig, block_size); 29238c2ecf20Sopenharmony_ci 29248c2ecf20Sopenharmony_ci if (ret < 0) 29258c2ecf20Sopenharmony_ci return ret; 29268c2ecf20Sopenharmony_ci 29278c2ecf20Sopenharmony_ci --num_blocks; 29288c2ecf20Sopenharmony_ci } else { 29298c2ecf20Sopenharmony_ci if (mconfig->formats_config.caps_size > 0) 29308c2ecf20Sopenharmony_ci memcpy(mconfig->formats_config.caps, data, 29318c2ecf20Sopenharmony_ci mconfig->formats_config.caps_size); 29328c2ecf20Sopenharmony_ci --num_blocks; 29338c2ecf20Sopenharmony_ci ret = mconfig->formats_config.caps_size; 29348c2ecf20Sopenharmony_ci } 29358c2ecf20Sopenharmony_ci off += ret; 29368c2ecf20Sopenharmony_ci } 29378c2ecf20Sopenharmony_ci 29388c2ecf20Sopenharmony_ci return 0; 29398c2ecf20Sopenharmony_ci} 29408c2ecf20Sopenharmony_ci 29418c2ecf20Sopenharmony_cistatic void skl_clear_pin_config(struct snd_soc_component *component, 29428c2ecf20Sopenharmony_ci struct snd_soc_dapm_widget *w) 29438c2ecf20Sopenharmony_ci{ 29448c2ecf20Sopenharmony_ci int i; 29458c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig; 29468c2ecf20Sopenharmony_ci struct skl_pipe *pipe; 29478c2ecf20Sopenharmony_ci 29488c2ecf20Sopenharmony_ci if (!strncmp(w->dapm->component->name, component->name, 29498c2ecf20Sopenharmony_ci strlen(component->name))) { 29508c2ecf20Sopenharmony_ci mconfig = w->priv; 29518c2ecf20Sopenharmony_ci pipe = mconfig->pipe; 29528c2ecf20Sopenharmony_ci for (i = 0; i < mconfig->module->max_input_pins; i++) { 29538c2ecf20Sopenharmony_ci mconfig->m_in_pin[i].in_use = false; 29548c2ecf20Sopenharmony_ci mconfig->m_in_pin[i].pin_state = SKL_PIN_UNBIND; 29558c2ecf20Sopenharmony_ci } 29568c2ecf20Sopenharmony_ci for (i = 0; i < mconfig->module->max_output_pins; i++) { 29578c2ecf20Sopenharmony_ci mconfig->m_out_pin[i].in_use = false; 29588c2ecf20Sopenharmony_ci mconfig->m_out_pin[i].pin_state = SKL_PIN_UNBIND; 29598c2ecf20Sopenharmony_ci } 29608c2ecf20Sopenharmony_ci pipe->state = SKL_PIPE_INVALID; 29618c2ecf20Sopenharmony_ci mconfig->m_state = SKL_MODULE_UNINIT; 29628c2ecf20Sopenharmony_ci } 29638c2ecf20Sopenharmony_ci} 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_civoid skl_cleanup_resources(struct skl_dev *skl) 29668c2ecf20Sopenharmony_ci{ 29678c2ecf20Sopenharmony_ci struct snd_soc_component *soc_component = skl->component; 29688c2ecf20Sopenharmony_ci struct snd_soc_dapm_widget *w; 29698c2ecf20Sopenharmony_ci struct snd_soc_card *card; 29708c2ecf20Sopenharmony_ci 29718c2ecf20Sopenharmony_ci if (soc_component == NULL) 29728c2ecf20Sopenharmony_ci return; 29738c2ecf20Sopenharmony_ci 29748c2ecf20Sopenharmony_ci card = soc_component->card; 29758c2ecf20Sopenharmony_ci if (!card || !card->instantiated) 29768c2ecf20Sopenharmony_ci return; 29778c2ecf20Sopenharmony_ci 29788c2ecf20Sopenharmony_ci list_for_each_entry(w, &card->widgets, list) { 29798c2ecf20Sopenharmony_ci if (is_skl_dsp_widget_type(w, skl->dev) && w->priv != NULL) 29808c2ecf20Sopenharmony_ci skl_clear_pin_config(soc_component, w); 29818c2ecf20Sopenharmony_ci } 29828c2ecf20Sopenharmony_ci 29838c2ecf20Sopenharmony_ci skl_clear_module_cnt(skl->dsp); 29848c2ecf20Sopenharmony_ci} 29858c2ecf20Sopenharmony_ci 29868c2ecf20Sopenharmony_ci/* 29878c2ecf20Sopenharmony_ci * Topology core widget load callback 29888c2ecf20Sopenharmony_ci * 29898c2ecf20Sopenharmony_ci * This is used to save the private data for each widget which gives 29908c2ecf20Sopenharmony_ci * information to the driver about module and pipeline parameters which DSP 29918c2ecf20Sopenharmony_ci * FW expects like ids, resource values, formats etc 29928c2ecf20Sopenharmony_ci */ 29938c2ecf20Sopenharmony_cistatic int skl_tplg_widget_load(struct snd_soc_component *cmpnt, int index, 29948c2ecf20Sopenharmony_ci struct snd_soc_dapm_widget *w, 29958c2ecf20Sopenharmony_ci struct snd_soc_tplg_dapm_widget *tplg_w) 29968c2ecf20Sopenharmony_ci{ 29978c2ecf20Sopenharmony_ci int ret; 29988c2ecf20Sopenharmony_ci struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt); 29998c2ecf20Sopenharmony_ci struct skl_dev *skl = bus_to_skl(bus); 30008c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig; 30018c2ecf20Sopenharmony_ci 30028c2ecf20Sopenharmony_ci if (!tplg_w->priv.size) 30038c2ecf20Sopenharmony_ci goto bind_event; 30048c2ecf20Sopenharmony_ci 30058c2ecf20Sopenharmony_ci mconfig = devm_kzalloc(bus->dev, sizeof(*mconfig), GFP_KERNEL); 30068c2ecf20Sopenharmony_ci 30078c2ecf20Sopenharmony_ci if (!mconfig) 30088c2ecf20Sopenharmony_ci return -ENOMEM; 30098c2ecf20Sopenharmony_ci 30108c2ecf20Sopenharmony_ci if (skl->nr_modules == 0) { 30118c2ecf20Sopenharmony_ci mconfig->module = devm_kzalloc(bus->dev, 30128c2ecf20Sopenharmony_ci sizeof(*mconfig->module), GFP_KERNEL); 30138c2ecf20Sopenharmony_ci if (!mconfig->module) 30148c2ecf20Sopenharmony_ci return -ENOMEM; 30158c2ecf20Sopenharmony_ci } 30168c2ecf20Sopenharmony_ci 30178c2ecf20Sopenharmony_ci w->priv = mconfig; 30188c2ecf20Sopenharmony_ci 30198c2ecf20Sopenharmony_ci /* 30208c2ecf20Sopenharmony_ci * module binary can be loaded later, so set it to query when 30218c2ecf20Sopenharmony_ci * module is load for a use case 30228c2ecf20Sopenharmony_ci */ 30238c2ecf20Sopenharmony_ci mconfig->id.module_id = -1; 30248c2ecf20Sopenharmony_ci 30258c2ecf20Sopenharmony_ci /* Parse private data for tuples */ 30268c2ecf20Sopenharmony_ci ret = skl_tplg_get_pvt_data(tplg_w, skl, bus->dev, mconfig); 30278c2ecf20Sopenharmony_ci if (ret < 0) 30288c2ecf20Sopenharmony_ci return ret; 30298c2ecf20Sopenharmony_ci 30308c2ecf20Sopenharmony_ci skl_debug_init_module(skl->debugfs, w, mconfig); 30318c2ecf20Sopenharmony_ci 30328c2ecf20Sopenharmony_cibind_event: 30338c2ecf20Sopenharmony_ci if (tplg_w->event_type == 0) { 30348c2ecf20Sopenharmony_ci dev_dbg(bus->dev, "ASoC: No event handler required\n"); 30358c2ecf20Sopenharmony_ci return 0; 30368c2ecf20Sopenharmony_ci } 30378c2ecf20Sopenharmony_ci 30388c2ecf20Sopenharmony_ci ret = snd_soc_tplg_widget_bind_event(w, skl_tplg_widget_ops, 30398c2ecf20Sopenharmony_ci ARRAY_SIZE(skl_tplg_widget_ops), 30408c2ecf20Sopenharmony_ci tplg_w->event_type); 30418c2ecf20Sopenharmony_ci 30428c2ecf20Sopenharmony_ci if (ret) { 30438c2ecf20Sopenharmony_ci dev_err(bus->dev, "%s: No matching event handlers found for %d\n", 30448c2ecf20Sopenharmony_ci __func__, tplg_w->event_type); 30458c2ecf20Sopenharmony_ci return -EINVAL; 30468c2ecf20Sopenharmony_ci } 30478c2ecf20Sopenharmony_ci 30488c2ecf20Sopenharmony_ci return 0; 30498c2ecf20Sopenharmony_ci} 30508c2ecf20Sopenharmony_ci 30518c2ecf20Sopenharmony_cistatic int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be, 30528c2ecf20Sopenharmony_ci struct snd_soc_tplg_bytes_control *bc) 30538c2ecf20Sopenharmony_ci{ 30548c2ecf20Sopenharmony_ci struct skl_algo_data *ac; 30558c2ecf20Sopenharmony_ci struct skl_dfw_algo_data *dfw_ac = 30568c2ecf20Sopenharmony_ci (struct skl_dfw_algo_data *)bc->priv.data; 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_ci ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL); 30598c2ecf20Sopenharmony_ci if (!ac) 30608c2ecf20Sopenharmony_ci return -ENOMEM; 30618c2ecf20Sopenharmony_ci 30628c2ecf20Sopenharmony_ci /* Fill private data */ 30638c2ecf20Sopenharmony_ci ac->max = dfw_ac->max; 30648c2ecf20Sopenharmony_ci ac->param_id = dfw_ac->param_id; 30658c2ecf20Sopenharmony_ci ac->set_params = dfw_ac->set_params; 30668c2ecf20Sopenharmony_ci ac->size = dfw_ac->max; 30678c2ecf20Sopenharmony_ci 30688c2ecf20Sopenharmony_ci if (ac->max) { 30698c2ecf20Sopenharmony_ci ac->params = devm_kzalloc(dev, ac->max, GFP_KERNEL); 30708c2ecf20Sopenharmony_ci if (!ac->params) 30718c2ecf20Sopenharmony_ci return -ENOMEM; 30728c2ecf20Sopenharmony_ci 30738c2ecf20Sopenharmony_ci memcpy(ac->params, dfw_ac->params, ac->max); 30748c2ecf20Sopenharmony_ci } 30758c2ecf20Sopenharmony_ci 30768c2ecf20Sopenharmony_ci be->dobj.private = ac; 30778c2ecf20Sopenharmony_ci return 0; 30788c2ecf20Sopenharmony_ci} 30798c2ecf20Sopenharmony_ci 30808c2ecf20Sopenharmony_cistatic int skl_init_enum_data(struct device *dev, struct soc_enum *se, 30818c2ecf20Sopenharmony_ci struct snd_soc_tplg_enum_control *ec) 30828c2ecf20Sopenharmony_ci{ 30838c2ecf20Sopenharmony_ci 30848c2ecf20Sopenharmony_ci void *data; 30858c2ecf20Sopenharmony_ci 30868c2ecf20Sopenharmony_ci if (ec->priv.size) { 30878c2ecf20Sopenharmony_ci data = devm_kzalloc(dev, sizeof(ec->priv.size), GFP_KERNEL); 30888c2ecf20Sopenharmony_ci if (!data) 30898c2ecf20Sopenharmony_ci return -ENOMEM; 30908c2ecf20Sopenharmony_ci memcpy(data, ec->priv.data, ec->priv.size); 30918c2ecf20Sopenharmony_ci se->dobj.private = data; 30928c2ecf20Sopenharmony_ci } 30938c2ecf20Sopenharmony_ci 30948c2ecf20Sopenharmony_ci return 0; 30958c2ecf20Sopenharmony_ci 30968c2ecf20Sopenharmony_ci} 30978c2ecf20Sopenharmony_ci 30988c2ecf20Sopenharmony_cistatic int skl_tplg_control_load(struct snd_soc_component *cmpnt, 30998c2ecf20Sopenharmony_ci int index, 31008c2ecf20Sopenharmony_ci struct snd_kcontrol_new *kctl, 31018c2ecf20Sopenharmony_ci struct snd_soc_tplg_ctl_hdr *hdr) 31028c2ecf20Sopenharmony_ci{ 31038c2ecf20Sopenharmony_ci struct soc_bytes_ext *sb; 31048c2ecf20Sopenharmony_ci struct snd_soc_tplg_bytes_control *tplg_bc; 31058c2ecf20Sopenharmony_ci struct snd_soc_tplg_enum_control *tplg_ec; 31068c2ecf20Sopenharmony_ci struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt); 31078c2ecf20Sopenharmony_ci struct soc_enum *se; 31088c2ecf20Sopenharmony_ci 31098c2ecf20Sopenharmony_ci switch (hdr->ops.info) { 31108c2ecf20Sopenharmony_ci case SND_SOC_TPLG_CTL_BYTES: 31118c2ecf20Sopenharmony_ci tplg_bc = container_of(hdr, 31128c2ecf20Sopenharmony_ci struct snd_soc_tplg_bytes_control, hdr); 31138c2ecf20Sopenharmony_ci if (kctl->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 31148c2ecf20Sopenharmony_ci sb = (struct soc_bytes_ext *)kctl->private_value; 31158c2ecf20Sopenharmony_ci if (tplg_bc->priv.size) 31168c2ecf20Sopenharmony_ci return skl_init_algo_data( 31178c2ecf20Sopenharmony_ci bus->dev, sb, tplg_bc); 31188c2ecf20Sopenharmony_ci } 31198c2ecf20Sopenharmony_ci break; 31208c2ecf20Sopenharmony_ci 31218c2ecf20Sopenharmony_ci case SND_SOC_TPLG_CTL_ENUM: 31228c2ecf20Sopenharmony_ci tplg_ec = container_of(hdr, 31238c2ecf20Sopenharmony_ci struct snd_soc_tplg_enum_control, hdr); 31248c2ecf20Sopenharmony_ci if (kctl->access & SNDRV_CTL_ELEM_ACCESS_READ) { 31258c2ecf20Sopenharmony_ci se = (struct soc_enum *)kctl->private_value; 31268c2ecf20Sopenharmony_ci if (tplg_ec->priv.size) 31278c2ecf20Sopenharmony_ci skl_init_enum_data(bus->dev, se, tplg_ec); 31288c2ecf20Sopenharmony_ci } 31298c2ecf20Sopenharmony_ci 31308c2ecf20Sopenharmony_ci /* 31318c2ecf20Sopenharmony_ci * now that the control initializations are done, remove 31328c2ecf20Sopenharmony_ci * write permission for the DMIC configuration enums to 31338c2ecf20Sopenharmony_ci * avoid conflicts between NHLT settings and user interaction 31348c2ecf20Sopenharmony_ci */ 31358c2ecf20Sopenharmony_ci 31368c2ecf20Sopenharmony_ci if (hdr->ops.get == SKL_CONTROL_TYPE_MULTI_IO_SELECT_DMIC) 31378c2ecf20Sopenharmony_ci kctl->access = SNDRV_CTL_ELEM_ACCESS_READ; 31388c2ecf20Sopenharmony_ci 31398c2ecf20Sopenharmony_ci break; 31408c2ecf20Sopenharmony_ci 31418c2ecf20Sopenharmony_ci default: 31428c2ecf20Sopenharmony_ci dev_dbg(bus->dev, "Control load not supported %d:%d:%d\n", 31438c2ecf20Sopenharmony_ci hdr->ops.get, hdr->ops.put, hdr->ops.info); 31448c2ecf20Sopenharmony_ci break; 31458c2ecf20Sopenharmony_ci } 31468c2ecf20Sopenharmony_ci 31478c2ecf20Sopenharmony_ci return 0; 31488c2ecf20Sopenharmony_ci} 31498c2ecf20Sopenharmony_ci 31508c2ecf20Sopenharmony_cistatic int skl_tplg_fill_str_mfest_tkn(struct device *dev, 31518c2ecf20Sopenharmony_ci struct snd_soc_tplg_vendor_string_elem *str_elem, 31528c2ecf20Sopenharmony_ci struct skl_dev *skl) 31538c2ecf20Sopenharmony_ci{ 31548c2ecf20Sopenharmony_ci int tkn_count = 0; 31558c2ecf20Sopenharmony_ci static int ref_count; 31568c2ecf20Sopenharmony_ci 31578c2ecf20Sopenharmony_ci switch (str_elem->token) { 31588c2ecf20Sopenharmony_ci case SKL_TKN_STR_LIB_NAME: 31598c2ecf20Sopenharmony_ci if (ref_count > skl->lib_count - 1) { 31608c2ecf20Sopenharmony_ci ref_count = 0; 31618c2ecf20Sopenharmony_ci return -EINVAL; 31628c2ecf20Sopenharmony_ci } 31638c2ecf20Sopenharmony_ci 31648c2ecf20Sopenharmony_ci strncpy(skl->lib_info[ref_count].name, 31658c2ecf20Sopenharmony_ci str_elem->string, 31668c2ecf20Sopenharmony_ci ARRAY_SIZE(skl->lib_info[ref_count].name)); 31678c2ecf20Sopenharmony_ci ref_count++; 31688c2ecf20Sopenharmony_ci break; 31698c2ecf20Sopenharmony_ci 31708c2ecf20Sopenharmony_ci default: 31718c2ecf20Sopenharmony_ci dev_err(dev, "Not a string token %d\n", str_elem->token); 31728c2ecf20Sopenharmony_ci break; 31738c2ecf20Sopenharmony_ci } 31748c2ecf20Sopenharmony_ci tkn_count++; 31758c2ecf20Sopenharmony_ci 31768c2ecf20Sopenharmony_ci return tkn_count; 31778c2ecf20Sopenharmony_ci} 31788c2ecf20Sopenharmony_ci 31798c2ecf20Sopenharmony_cistatic int skl_tplg_get_str_tkn(struct device *dev, 31808c2ecf20Sopenharmony_ci struct snd_soc_tplg_vendor_array *array, 31818c2ecf20Sopenharmony_ci struct skl_dev *skl) 31828c2ecf20Sopenharmony_ci{ 31838c2ecf20Sopenharmony_ci int tkn_count = 0, ret; 31848c2ecf20Sopenharmony_ci struct snd_soc_tplg_vendor_string_elem *str_elem; 31858c2ecf20Sopenharmony_ci 31868c2ecf20Sopenharmony_ci str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value; 31878c2ecf20Sopenharmony_ci while (tkn_count < array->num_elems) { 31888c2ecf20Sopenharmony_ci ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, skl); 31898c2ecf20Sopenharmony_ci str_elem++; 31908c2ecf20Sopenharmony_ci 31918c2ecf20Sopenharmony_ci if (ret < 0) 31928c2ecf20Sopenharmony_ci return ret; 31938c2ecf20Sopenharmony_ci 31948c2ecf20Sopenharmony_ci tkn_count = tkn_count + ret; 31958c2ecf20Sopenharmony_ci } 31968c2ecf20Sopenharmony_ci 31978c2ecf20Sopenharmony_ci return tkn_count; 31988c2ecf20Sopenharmony_ci} 31998c2ecf20Sopenharmony_ci 32008c2ecf20Sopenharmony_cistatic int skl_tplg_manifest_fill_fmt(struct device *dev, 32018c2ecf20Sopenharmony_ci struct skl_module_iface *fmt, 32028c2ecf20Sopenharmony_ci struct snd_soc_tplg_vendor_value_elem *tkn_elem, 32038c2ecf20Sopenharmony_ci u32 dir, int fmt_idx) 32048c2ecf20Sopenharmony_ci{ 32058c2ecf20Sopenharmony_ci struct skl_module_pin_fmt *dst_fmt; 32068c2ecf20Sopenharmony_ci struct skl_module_fmt *mod_fmt; 32078c2ecf20Sopenharmony_ci int ret; 32088c2ecf20Sopenharmony_ci 32098c2ecf20Sopenharmony_ci if (!fmt) 32108c2ecf20Sopenharmony_ci return -EINVAL; 32118c2ecf20Sopenharmony_ci 32128c2ecf20Sopenharmony_ci switch (dir) { 32138c2ecf20Sopenharmony_ci case SKL_DIR_IN: 32148c2ecf20Sopenharmony_ci dst_fmt = &fmt->inputs[fmt_idx]; 32158c2ecf20Sopenharmony_ci break; 32168c2ecf20Sopenharmony_ci 32178c2ecf20Sopenharmony_ci case SKL_DIR_OUT: 32188c2ecf20Sopenharmony_ci dst_fmt = &fmt->outputs[fmt_idx]; 32198c2ecf20Sopenharmony_ci break; 32208c2ecf20Sopenharmony_ci 32218c2ecf20Sopenharmony_ci default: 32228c2ecf20Sopenharmony_ci dev_err(dev, "Invalid direction: %d\n", dir); 32238c2ecf20Sopenharmony_ci return -EINVAL; 32248c2ecf20Sopenharmony_ci } 32258c2ecf20Sopenharmony_ci 32268c2ecf20Sopenharmony_ci mod_fmt = &dst_fmt->fmt; 32278c2ecf20Sopenharmony_ci 32288c2ecf20Sopenharmony_ci switch (tkn_elem->token) { 32298c2ecf20Sopenharmony_ci case SKL_TKN_MM_U32_INTF_PIN_ID: 32308c2ecf20Sopenharmony_ci dst_fmt->id = tkn_elem->value; 32318c2ecf20Sopenharmony_ci break; 32328c2ecf20Sopenharmony_ci 32338c2ecf20Sopenharmony_ci default: 32348c2ecf20Sopenharmony_ci ret = skl_tplg_fill_fmt(dev, mod_fmt, tkn_elem->token, 32358c2ecf20Sopenharmony_ci tkn_elem->value); 32368c2ecf20Sopenharmony_ci if (ret < 0) 32378c2ecf20Sopenharmony_ci return ret; 32388c2ecf20Sopenharmony_ci break; 32398c2ecf20Sopenharmony_ci } 32408c2ecf20Sopenharmony_ci 32418c2ecf20Sopenharmony_ci return 0; 32428c2ecf20Sopenharmony_ci} 32438c2ecf20Sopenharmony_ci 32448c2ecf20Sopenharmony_cistatic int skl_tplg_fill_mod_info(struct device *dev, 32458c2ecf20Sopenharmony_ci struct snd_soc_tplg_vendor_value_elem *tkn_elem, 32468c2ecf20Sopenharmony_ci struct skl_module *mod) 32478c2ecf20Sopenharmony_ci{ 32488c2ecf20Sopenharmony_ci 32498c2ecf20Sopenharmony_ci if (!mod) 32508c2ecf20Sopenharmony_ci return -EINVAL; 32518c2ecf20Sopenharmony_ci 32528c2ecf20Sopenharmony_ci switch (tkn_elem->token) { 32538c2ecf20Sopenharmony_ci case SKL_TKN_U8_IN_PIN_TYPE: 32548c2ecf20Sopenharmony_ci mod->input_pin_type = tkn_elem->value; 32558c2ecf20Sopenharmony_ci break; 32568c2ecf20Sopenharmony_ci 32578c2ecf20Sopenharmony_ci case SKL_TKN_U8_OUT_PIN_TYPE: 32588c2ecf20Sopenharmony_ci mod->output_pin_type = tkn_elem->value; 32598c2ecf20Sopenharmony_ci break; 32608c2ecf20Sopenharmony_ci 32618c2ecf20Sopenharmony_ci case SKL_TKN_U8_IN_QUEUE_COUNT: 32628c2ecf20Sopenharmony_ci mod->max_input_pins = tkn_elem->value; 32638c2ecf20Sopenharmony_ci break; 32648c2ecf20Sopenharmony_ci 32658c2ecf20Sopenharmony_ci case SKL_TKN_U8_OUT_QUEUE_COUNT: 32668c2ecf20Sopenharmony_ci mod->max_output_pins = tkn_elem->value; 32678c2ecf20Sopenharmony_ci break; 32688c2ecf20Sopenharmony_ci 32698c2ecf20Sopenharmony_ci case SKL_TKN_MM_U8_NUM_RES: 32708c2ecf20Sopenharmony_ci mod->nr_resources = tkn_elem->value; 32718c2ecf20Sopenharmony_ci break; 32728c2ecf20Sopenharmony_ci 32738c2ecf20Sopenharmony_ci case SKL_TKN_MM_U8_NUM_INTF: 32748c2ecf20Sopenharmony_ci mod->nr_interfaces = tkn_elem->value; 32758c2ecf20Sopenharmony_ci break; 32768c2ecf20Sopenharmony_ci 32778c2ecf20Sopenharmony_ci default: 32788c2ecf20Sopenharmony_ci dev_err(dev, "Invalid mod info token %d", tkn_elem->token); 32798c2ecf20Sopenharmony_ci return -EINVAL; 32808c2ecf20Sopenharmony_ci } 32818c2ecf20Sopenharmony_ci 32828c2ecf20Sopenharmony_ci return 0; 32838c2ecf20Sopenharmony_ci} 32848c2ecf20Sopenharmony_ci 32858c2ecf20Sopenharmony_ci 32868c2ecf20Sopenharmony_cistatic int skl_tplg_get_int_tkn(struct device *dev, 32878c2ecf20Sopenharmony_ci struct snd_soc_tplg_vendor_value_elem *tkn_elem, 32888c2ecf20Sopenharmony_ci struct skl_dev *skl) 32898c2ecf20Sopenharmony_ci{ 32908c2ecf20Sopenharmony_ci int tkn_count = 0, ret; 32918c2ecf20Sopenharmony_ci static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx; 32928c2ecf20Sopenharmony_ci struct skl_module_res *res = NULL; 32938c2ecf20Sopenharmony_ci struct skl_module_iface *fmt = NULL; 32948c2ecf20Sopenharmony_ci struct skl_module *mod = NULL; 32958c2ecf20Sopenharmony_ci static struct skl_astate_param *astate_table; 32968c2ecf20Sopenharmony_ci static int astate_cfg_idx, count; 32978c2ecf20Sopenharmony_ci int i; 32988c2ecf20Sopenharmony_ci size_t size; 32998c2ecf20Sopenharmony_ci 33008c2ecf20Sopenharmony_ci if (skl->modules) { 33018c2ecf20Sopenharmony_ci mod = skl->modules[mod_idx]; 33028c2ecf20Sopenharmony_ci res = &mod->resources[res_val_idx]; 33038c2ecf20Sopenharmony_ci fmt = &mod->formats[intf_val_idx]; 33048c2ecf20Sopenharmony_ci } 33058c2ecf20Sopenharmony_ci 33068c2ecf20Sopenharmony_ci switch (tkn_elem->token) { 33078c2ecf20Sopenharmony_ci case SKL_TKN_U32_LIB_COUNT: 33088c2ecf20Sopenharmony_ci skl->lib_count = tkn_elem->value; 33098c2ecf20Sopenharmony_ci break; 33108c2ecf20Sopenharmony_ci 33118c2ecf20Sopenharmony_ci case SKL_TKN_U8_NUM_MOD: 33128c2ecf20Sopenharmony_ci skl->nr_modules = tkn_elem->value; 33138c2ecf20Sopenharmony_ci skl->modules = devm_kcalloc(dev, skl->nr_modules, 33148c2ecf20Sopenharmony_ci sizeof(*skl->modules), GFP_KERNEL); 33158c2ecf20Sopenharmony_ci if (!skl->modules) 33168c2ecf20Sopenharmony_ci return -ENOMEM; 33178c2ecf20Sopenharmony_ci 33188c2ecf20Sopenharmony_ci for (i = 0; i < skl->nr_modules; i++) { 33198c2ecf20Sopenharmony_ci skl->modules[i] = devm_kzalloc(dev, 33208c2ecf20Sopenharmony_ci sizeof(struct skl_module), GFP_KERNEL); 33218c2ecf20Sopenharmony_ci if (!skl->modules[i]) 33228c2ecf20Sopenharmony_ci return -ENOMEM; 33238c2ecf20Sopenharmony_ci } 33248c2ecf20Sopenharmony_ci break; 33258c2ecf20Sopenharmony_ci 33268c2ecf20Sopenharmony_ci case SKL_TKN_MM_U8_MOD_IDX: 33278c2ecf20Sopenharmony_ci mod_idx = tkn_elem->value; 33288c2ecf20Sopenharmony_ci break; 33298c2ecf20Sopenharmony_ci 33308c2ecf20Sopenharmony_ci case SKL_TKN_U32_ASTATE_COUNT: 33318c2ecf20Sopenharmony_ci if (astate_table != NULL) { 33328c2ecf20Sopenharmony_ci dev_err(dev, "More than one entry for A-State count"); 33338c2ecf20Sopenharmony_ci return -EINVAL; 33348c2ecf20Sopenharmony_ci } 33358c2ecf20Sopenharmony_ci 33368c2ecf20Sopenharmony_ci if (tkn_elem->value > SKL_MAX_ASTATE_CFG) { 33378c2ecf20Sopenharmony_ci dev_err(dev, "Invalid A-State count %d\n", 33388c2ecf20Sopenharmony_ci tkn_elem->value); 33398c2ecf20Sopenharmony_ci return -EINVAL; 33408c2ecf20Sopenharmony_ci } 33418c2ecf20Sopenharmony_ci 33428c2ecf20Sopenharmony_ci size = struct_size(skl->cfg.astate_cfg, astate_table, 33438c2ecf20Sopenharmony_ci tkn_elem->value); 33448c2ecf20Sopenharmony_ci skl->cfg.astate_cfg = devm_kzalloc(dev, size, GFP_KERNEL); 33458c2ecf20Sopenharmony_ci if (!skl->cfg.astate_cfg) 33468c2ecf20Sopenharmony_ci return -ENOMEM; 33478c2ecf20Sopenharmony_ci 33488c2ecf20Sopenharmony_ci astate_table = skl->cfg.astate_cfg->astate_table; 33498c2ecf20Sopenharmony_ci count = skl->cfg.astate_cfg->count = tkn_elem->value; 33508c2ecf20Sopenharmony_ci break; 33518c2ecf20Sopenharmony_ci 33528c2ecf20Sopenharmony_ci case SKL_TKN_U32_ASTATE_IDX: 33538c2ecf20Sopenharmony_ci if (tkn_elem->value >= count) { 33548c2ecf20Sopenharmony_ci dev_err(dev, "Invalid A-State index %d\n", 33558c2ecf20Sopenharmony_ci tkn_elem->value); 33568c2ecf20Sopenharmony_ci return -EINVAL; 33578c2ecf20Sopenharmony_ci } 33588c2ecf20Sopenharmony_ci 33598c2ecf20Sopenharmony_ci astate_cfg_idx = tkn_elem->value; 33608c2ecf20Sopenharmony_ci break; 33618c2ecf20Sopenharmony_ci 33628c2ecf20Sopenharmony_ci case SKL_TKN_U32_ASTATE_KCPS: 33638c2ecf20Sopenharmony_ci astate_table[astate_cfg_idx].kcps = tkn_elem->value; 33648c2ecf20Sopenharmony_ci break; 33658c2ecf20Sopenharmony_ci 33668c2ecf20Sopenharmony_ci case SKL_TKN_U32_ASTATE_CLK_SRC: 33678c2ecf20Sopenharmony_ci astate_table[astate_cfg_idx].clk_src = tkn_elem->value; 33688c2ecf20Sopenharmony_ci break; 33698c2ecf20Sopenharmony_ci 33708c2ecf20Sopenharmony_ci case SKL_TKN_U8_IN_PIN_TYPE: 33718c2ecf20Sopenharmony_ci case SKL_TKN_U8_OUT_PIN_TYPE: 33728c2ecf20Sopenharmony_ci case SKL_TKN_U8_IN_QUEUE_COUNT: 33738c2ecf20Sopenharmony_ci case SKL_TKN_U8_OUT_QUEUE_COUNT: 33748c2ecf20Sopenharmony_ci case SKL_TKN_MM_U8_NUM_RES: 33758c2ecf20Sopenharmony_ci case SKL_TKN_MM_U8_NUM_INTF: 33768c2ecf20Sopenharmony_ci ret = skl_tplg_fill_mod_info(dev, tkn_elem, mod); 33778c2ecf20Sopenharmony_ci if (ret < 0) 33788c2ecf20Sopenharmony_ci return ret; 33798c2ecf20Sopenharmony_ci break; 33808c2ecf20Sopenharmony_ci 33818c2ecf20Sopenharmony_ci case SKL_TKN_U32_DIR_PIN_COUNT: 33828c2ecf20Sopenharmony_ci dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK; 33838c2ecf20Sopenharmony_ci pin_idx = (tkn_elem->value & SKL_PIN_COUNT_MASK) >> 4; 33848c2ecf20Sopenharmony_ci break; 33858c2ecf20Sopenharmony_ci 33868c2ecf20Sopenharmony_ci case SKL_TKN_MM_U32_RES_ID: 33878c2ecf20Sopenharmony_ci if (!res) 33888c2ecf20Sopenharmony_ci return -EINVAL; 33898c2ecf20Sopenharmony_ci 33908c2ecf20Sopenharmony_ci res->id = tkn_elem->value; 33918c2ecf20Sopenharmony_ci res_val_idx = tkn_elem->value; 33928c2ecf20Sopenharmony_ci break; 33938c2ecf20Sopenharmony_ci 33948c2ecf20Sopenharmony_ci case SKL_TKN_MM_U32_FMT_ID: 33958c2ecf20Sopenharmony_ci if (!fmt) 33968c2ecf20Sopenharmony_ci return -EINVAL; 33978c2ecf20Sopenharmony_ci 33988c2ecf20Sopenharmony_ci fmt->fmt_idx = tkn_elem->value; 33998c2ecf20Sopenharmony_ci intf_val_idx = tkn_elem->value; 34008c2ecf20Sopenharmony_ci break; 34018c2ecf20Sopenharmony_ci 34028c2ecf20Sopenharmony_ci case SKL_TKN_MM_U32_CPS: 34038c2ecf20Sopenharmony_ci case SKL_TKN_MM_U32_DMA_SIZE: 34048c2ecf20Sopenharmony_ci case SKL_TKN_MM_U32_CPC: 34058c2ecf20Sopenharmony_ci case SKL_TKN_U32_MEM_PAGES: 34068c2ecf20Sopenharmony_ci case SKL_TKN_U32_OBS: 34078c2ecf20Sopenharmony_ci case SKL_TKN_U32_IBS: 34088c2ecf20Sopenharmony_ci case SKL_TKN_MM_U32_RES_PIN_ID: 34098c2ecf20Sopenharmony_ci case SKL_TKN_MM_U32_PIN_BUF: 34108c2ecf20Sopenharmony_ci ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_idx, dir); 34118c2ecf20Sopenharmony_ci if (ret < 0) 34128c2ecf20Sopenharmony_ci return ret; 34138c2ecf20Sopenharmony_ci 34148c2ecf20Sopenharmony_ci break; 34158c2ecf20Sopenharmony_ci 34168c2ecf20Sopenharmony_ci case SKL_TKN_MM_U32_NUM_IN_FMT: 34178c2ecf20Sopenharmony_ci if (!fmt) 34188c2ecf20Sopenharmony_ci return -EINVAL; 34198c2ecf20Sopenharmony_ci 34208c2ecf20Sopenharmony_ci res->nr_input_pins = tkn_elem->value; 34218c2ecf20Sopenharmony_ci break; 34228c2ecf20Sopenharmony_ci 34238c2ecf20Sopenharmony_ci case SKL_TKN_MM_U32_NUM_OUT_FMT: 34248c2ecf20Sopenharmony_ci if (!fmt) 34258c2ecf20Sopenharmony_ci return -EINVAL; 34268c2ecf20Sopenharmony_ci 34278c2ecf20Sopenharmony_ci res->nr_output_pins = tkn_elem->value; 34288c2ecf20Sopenharmony_ci break; 34298c2ecf20Sopenharmony_ci 34308c2ecf20Sopenharmony_ci case SKL_TKN_U32_FMT_CH: 34318c2ecf20Sopenharmony_ci case SKL_TKN_U32_FMT_FREQ: 34328c2ecf20Sopenharmony_ci case SKL_TKN_U32_FMT_BIT_DEPTH: 34338c2ecf20Sopenharmony_ci case SKL_TKN_U32_FMT_SAMPLE_SIZE: 34348c2ecf20Sopenharmony_ci case SKL_TKN_U32_FMT_CH_CONFIG: 34358c2ecf20Sopenharmony_ci case SKL_TKN_U32_FMT_INTERLEAVE: 34368c2ecf20Sopenharmony_ci case SKL_TKN_U32_FMT_SAMPLE_TYPE: 34378c2ecf20Sopenharmony_ci case SKL_TKN_U32_FMT_CH_MAP: 34388c2ecf20Sopenharmony_ci case SKL_TKN_MM_U32_INTF_PIN_ID: 34398c2ecf20Sopenharmony_ci ret = skl_tplg_manifest_fill_fmt(dev, fmt, tkn_elem, 34408c2ecf20Sopenharmony_ci dir, pin_idx); 34418c2ecf20Sopenharmony_ci if (ret < 0) 34428c2ecf20Sopenharmony_ci return ret; 34438c2ecf20Sopenharmony_ci break; 34448c2ecf20Sopenharmony_ci 34458c2ecf20Sopenharmony_ci default: 34468c2ecf20Sopenharmony_ci dev_err(dev, "Not a manifest token %d\n", tkn_elem->token); 34478c2ecf20Sopenharmony_ci return -EINVAL; 34488c2ecf20Sopenharmony_ci } 34498c2ecf20Sopenharmony_ci tkn_count++; 34508c2ecf20Sopenharmony_ci 34518c2ecf20Sopenharmony_ci return tkn_count; 34528c2ecf20Sopenharmony_ci} 34538c2ecf20Sopenharmony_ci 34548c2ecf20Sopenharmony_ci/* 34558c2ecf20Sopenharmony_ci * Fill the manifest structure by parsing the tokens based on the 34568c2ecf20Sopenharmony_ci * type. 34578c2ecf20Sopenharmony_ci */ 34588c2ecf20Sopenharmony_cistatic int skl_tplg_get_manifest_tkn(struct device *dev, 34598c2ecf20Sopenharmony_ci char *pvt_data, struct skl_dev *skl, 34608c2ecf20Sopenharmony_ci int block_size) 34618c2ecf20Sopenharmony_ci{ 34628c2ecf20Sopenharmony_ci int tkn_count = 0, ret; 34638c2ecf20Sopenharmony_ci int off = 0, tuple_size = 0; 34648c2ecf20Sopenharmony_ci u8 uuid_index = 0; 34658c2ecf20Sopenharmony_ci struct snd_soc_tplg_vendor_array *array; 34668c2ecf20Sopenharmony_ci struct snd_soc_tplg_vendor_value_elem *tkn_elem; 34678c2ecf20Sopenharmony_ci 34688c2ecf20Sopenharmony_ci if (block_size <= 0) 34698c2ecf20Sopenharmony_ci return -EINVAL; 34708c2ecf20Sopenharmony_ci 34718c2ecf20Sopenharmony_ci while (tuple_size < block_size) { 34728c2ecf20Sopenharmony_ci array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off); 34738c2ecf20Sopenharmony_ci off += array->size; 34748c2ecf20Sopenharmony_ci switch (array->type) { 34758c2ecf20Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_STRING: 34768c2ecf20Sopenharmony_ci ret = skl_tplg_get_str_tkn(dev, array, skl); 34778c2ecf20Sopenharmony_ci 34788c2ecf20Sopenharmony_ci if (ret < 0) 34798c2ecf20Sopenharmony_ci return ret; 34808c2ecf20Sopenharmony_ci tkn_count = ret; 34818c2ecf20Sopenharmony_ci 34828c2ecf20Sopenharmony_ci tuple_size += tkn_count * 34838c2ecf20Sopenharmony_ci sizeof(struct snd_soc_tplg_vendor_string_elem); 34848c2ecf20Sopenharmony_ci continue; 34858c2ecf20Sopenharmony_ci 34868c2ecf20Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_UUID: 34878c2ecf20Sopenharmony_ci if (array->uuid->token != SKL_TKN_UUID) { 34888c2ecf20Sopenharmony_ci dev_err(dev, "Not an UUID token: %d\n", 34898c2ecf20Sopenharmony_ci array->uuid->token); 34908c2ecf20Sopenharmony_ci return -EINVAL; 34918c2ecf20Sopenharmony_ci } 34928c2ecf20Sopenharmony_ci if (uuid_index >= skl->nr_modules) { 34938c2ecf20Sopenharmony_ci dev_err(dev, "Too many UUID tokens\n"); 34948c2ecf20Sopenharmony_ci return -EINVAL; 34958c2ecf20Sopenharmony_ci } 34968c2ecf20Sopenharmony_ci import_guid(&skl->modules[uuid_index++]->uuid, 34978c2ecf20Sopenharmony_ci array->uuid->uuid); 34988c2ecf20Sopenharmony_ci 34998c2ecf20Sopenharmony_ci tuple_size += sizeof(*array->uuid); 35008c2ecf20Sopenharmony_ci continue; 35018c2ecf20Sopenharmony_ci 35028c2ecf20Sopenharmony_ci default: 35038c2ecf20Sopenharmony_ci tkn_elem = array->value; 35048c2ecf20Sopenharmony_ci tkn_count = 0; 35058c2ecf20Sopenharmony_ci break; 35068c2ecf20Sopenharmony_ci } 35078c2ecf20Sopenharmony_ci 35088c2ecf20Sopenharmony_ci while (tkn_count <= array->num_elems - 1) { 35098c2ecf20Sopenharmony_ci ret = skl_tplg_get_int_tkn(dev, 35108c2ecf20Sopenharmony_ci tkn_elem, skl); 35118c2ecf20Sopenharmony_ci if (ret < 0) 35128c2ecf20Sopenharmony_ci return ret; 35138c2ecf20Sopenharmony_ci 35148c2ecf20Sopenharmony_ci tkn_count = tkn_count + ret; 35158c2ecf20Sopenharmony_ci tkn_elem++; 35168c2ecf20Sopenharmony_ci } 35178c2ecf20Sopenharmony_ci tuple_size += (tkn_count * sizeof(*tkn_elem)); 35188c2ecf20Sopenharmony_ci tkn_count = 0; 35198c2ecf20Sopenharmony_ci } 35208c2ecf20Sopenharmony_ci 35218c2ecf20Sopenharmony_ci return off; 35228c2ecf20Sopenharmony_ci} 35238c2ecf20Sopenharmony_ci 35248c2ecf20Sopenharmony_ci/* 35258c2ecf20Sopenharmony_ci * Parse manifest private data for tokens. The private data block is 35268c2ecf20Sopenharmony_ci * preceded by descriptors for type and size of data block. 35278c2ecf20Sopenharmony_ci */ 35288c2ecf20Sopenharmony_cistatic int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest, 35298c2ecf20Sopenharmony_ci struct device *dev, struct skl_dev *skl) 35308c2ecf20Sopenharmony_ci{ 35318c2ecf20Sopenharmony_ci struct snd_soc_tplg_vendor_array *array; 35328c2ecf20Sopenharmony_ci int num_blocks, block_size = 0, block_type, off = 0; 35338c2ecf20Sopenharmony_ci char *data; 35348c2ecf20Sopenharmony_ci int ret; 35358c2ecf20Sopenharmony_ci 35368c2ecf20Sopenharmony_ci /* Read the NUM_DATA_BLOCKS descriptor */ 35378c2ecf20Sopenharmony_ci array = (struct snd_soc_tplg_vendor_array *)manifest->priv.data; 35388c2ecf20Sopenharmony_ci ret = skl_tplg_get_desc_blocks(dev, array); 35398c2ecf20Sopenharmony_ci if (ret < 0) 35408c2ecf20Sopenharmony_ci return ret; 35418c2ecf20Sopenharmony_ci num_blocks = ret; 35428c2ecf20Sopenharmony_ci 35438c2ecf20Sopenharmony_ci off += array->size; 35448c2ecf20Sopenharmony_ci /* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */ 35458c2ecf20Sopenharmony_ci while (num_blocks > 0) { 35468c2ecf20Sopenharmony_ci array = (struct snd_soc_tplg_vendor_array *) 35478c2ecf20Sopenharmony_ci (manifest->priv.data + off); 35488c2ecf20Sopenharmony_ci ret = skl_tplg_get_desc_blocks(dev, array); 35498c2ecf20Sopenharmony_ci 35508c2ecf20Sopenharmony_ci if (ret < 0) 35518c2ecf20Sopenharmony_ci return ret; 35528c2ecf20Sopenharmony_ci block_type = ret; 35538c2ecf20Sopenharmony_ci off += array->size; 35548c2ecf20Sopenharmony_ci 35558c2ecf20Sopenharmony_ci array = (struct snd_soc_tplg_vendor_array *) 35568c2ecf20Sopenharmony_ci (manifest->priv.data + off); 35578c2ecf20Sopenharmony_ci 35588c2ecf20Sopenharmony_ci ret = skl_tplg_get_desc_blocks(dev, array); 35598c2ecf20Sopenharmony_ci 35608c2ecf20Sopenharmony_ci if (ret < 0) 35618c2ecf20Sopenharmony_ci return ret; 35628c2ecf20Sopenharmony_ci block_size = ret; 35638c2ecf20Sopenharmony_ci off += array->size; 35648c2ecf20Sopenharmony_ci 35658c2ecf20Sopenharmony_ci array = (struct snd_soc_tplg_vendor_array *) 35668c2ecf20Sopenharmony_ci (manifest->priv.data + off); 35678c2ecf20Sopenharmony_ci 35688c2ecf20Sopenharmony_ci data = (manifest->priv.data + off); 35698c2ecf20Sopenharmony_ci 35708c2ecf20Sopenharmony_ci if (block_type == SKL_TYPE_TUPLE) { 35718c2ecf20Sopenharmony_ci ret = skl_tplg_get_manifest_tkn(dev, data, skl, 35728c2ecf20Sopenharmony_ci block_size); 35738c2ecf20Sopenharmony_ci 35748c2ecf20Sopenharmony_ci if (ret < 0) 35758c2ecf20Sopenharmony_ci return ret; 35768c2ecf20Sopenharmony_ci 35778c2ecf20Sopenharmony_ci --num_blocks; 35788c2ecf20Sopenharmony_ci } else { 35798c2ecf20Sopenharmony_ci return -EINVAL; 35808c2ecf20Sopenharmony_ci } 35818c2ecf20Sopenharmony_ci off += ret; 35828c2ecf20Sopenharmony_ci } 35838c2ecf20Sopenharmony_ci 35848c2ecf20Sopenharmony_ci return 0; 35858c2ecf20Sopenharmony_ci} 35868c2ecf20Sopenharmony_ci 35878c2ecf20Sopenharmony_cistatic int skl_manifest_load(struct snd_soc_component *cmpnt, int index, 35888c2ecf20Sopenharmony_ci struct snd_soc_tplg_manifest *manifest) 35898c2ecf20Sopenharmony_ci{ 35908c2ecf20Sopenharmony_ci struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt); 35918c2ecf20Sopenharmony_ci struct skl_dev *skl = bus_to_skl(bus); 35928c2ecf20Sopenharmony_ci 35938c2ecf20Sopenharmony_ci /* proceed only if we have private data defined */ 35948c2ecf20Sopenharmony_ci if (manifest->priv.size == 0) 35958c2ecf20Sopenharmony_ci return 0; 35968c2ecf20Sopenharmony_ci 35978c2ecf20Sopenharmony_ci skl_tplg_get_manifest_data(manifest, bus->dev, skl); 35988c2ecf20Sopenharmony_ci 35998c2ecf20Sopenharmony_ci if (skl->lib_count > SKL_MAX_LIB) { 36008c2ecf20Sopenharmony_ci dev_err(bus->dev, "Exceeding max Library count. Got:%d\n", 36018c2ecf20Sopenharmony_ci skl->lib_count); 36028c2ecf20Sopenharmony_ci return -EINVAL; 36038c2ecf20Sopenharmony_ci } 36048c2ecf20Sopenharmony_ci 36058c2ecf20Sopenharmony_ci return 0; 36068c2ecf20Sopenharmony_ci} 36078c2ecf20Sopenharmony_ci 36088c2ecf20Sopenharmony_cistatic void skl_tplg_complete(struct snd_soc_component *component) 36098c2ecf20Sopenharmony_ci{ 36108c2ecf20Sopenharmony_ci struct snd_soc_dobj *dobj; 36118c2ecf20Sopenharmony_ci struct snd_soc_acpi_mach *mach = 36128c2ecf20Sopenharmony_ci dev_get_platdata(component->card->dev); 36138c2ecf20Sopenharmony_ci int i; 36148c2ecf20Sopenharmony_ci 36158c2ecf20Sopenharmony_ci list_for_each_entry(dobj, &component->dobj_list, list) { 36168c2ecf20Sopenharmony_ci struct snd_kcontrol *kcontrol = dobj->control.kcontrol; 36178c2ecf20Sopenharmony_ci struct soc_enum *se; 36188c2ecf20Sopenharmony_ci char **texts; 36198c2ecf20Sopenharmony_ci char chan_text[4]; 36208c2ecf20Sopenharmony_ci 36218c2ecf20Sopenharmony_ci if (dobj->type != SND_SOC_DOBJ_ENUM || !kcontrol || 36228c2ecf20Sopenharmony_ci kcontrol->put != skl_tplg_multi_config_set_dmic) 36238c2ecf20Sopenharmony_ci continue; 36248c2ecf20Sopenharmony_ci 36258c2ecf20Sopenharmony_ci se = (struct soc_enum *)kcontrol->private_value; 36268c2ecf20Sopenharmony_ci texts = dobj->control.dtexts; 36278c2ecf20Sopenharmony_ci sprintf(chan_text, "c%d", mach->mach_params.dmic_num); 36288c2ecf20Sopenharmony_ci 36298c2ecf20Sopenharmony_ci for (i = 0; i < se->items; i++) { 36308c2ecf20Sopenharmony_ci struct snd_ctl_elem_value val = {}; 36318c2ecf20Sopenharmony_ci 36328c2ecf20Sopenharmony_ci if (strstr(texts[i], chan_text)) { 36338c2ecf20Sopenharmony_ci val.value.enumerated.item[0] = i; 36348c2ecf20Sopenharmony_ci kcontrol->put(kcontrol, &val); 36358c2ecf20Sopenharmony_ci } 36368c2ecf20Sopenharmony_ci } 36378c2ecf20Sopenharmony_ci } 36388c2ecf20Sopenharmony_ci} 36398c2ecf20Sopenharmony_ci 36408c2ecf20Sopenharmony_cistatic struct snd_soc_tplg_ops skl_tplg_ops = { 36418c2ecf20Sopenharmony_ci .widget_load = skl_tplg_widget_load, 36428c2ecf20Sopenharmony_ci .control_load = skl_tplg_control_load, 36438c2ecf20Sopenharmony_ci .bytes_ext_ops = skl_tlv_ops, 36448c2ecf20Sopenharmony_ci .bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops), 36458c2ecf20Sopenharmony_ci .io_ops = skl_tplg_kcontrol_ops, 36468c2ecf20Sopenharmony_ci .io_ops_count = ARRAY_SIZE(skl_tplg_kcontrol_ops), 36478c2ecf20Sopenharmony_ci .manifest = skl_manifest_load, 36488c2ecf20Sopenharmony_ci .dai_load = skl_dai_load, 36498c2ecf20Sopenharmony_ci .complete = skl_tplg_complete, 36508c2ecf20Sopenharmony_ci}; 36518c2ecf20Sopenharmony_ci 36528c2ecf20Sopenharmony_ci/* 36538c2ecf20Sopenharmony_ci * A pipe can have multiple modules, each of them will be a DAPM widget as 36548c2ecf20Sopenharmony_ci * well. While managing a pipeline we need to get the list of all the 36558c2ecf20Sopenharmony_ci * widgets in a pipelines, so this helper - skl_tplg_create_pipe_widget_list() 36568c2ecf20Sopenharmony_ci * helps to get the SKL type widgets in that pipeline 36578c2ecf20Sopenharmony_ci */ 36588c2ecf20Sopenharmony_cistatic int skl_tplg_create_pipe_widget_list(struct snd_soc_component *component) 36598c2ecf20Sopenharmony_ci{ 36608c2ecf20Sopenharmony_ci struct snd_soc_dapm_widget *w; 36618c2ecf20Sopenharmony_ci struct skl_module_cfg *mcfg = NULL; 36628c2ecf20Sopenharmony_ci struct skl_pipe_module *p_module = NULL; 36638c2ecf20Sopenharmony_ci struct skl_pipe *pipe; 36648c2ecf20Sopenharmony_ci 36658c2ecf20Sopenharmony_ci list_for_each_entry(w, &component->card->widgets, list) { 36668c2ecf20Sopenharmony_ci if (is_skl_dsp_widget_type(w, component->dev) && w->priv) { 36678c2ecf20Sopenharmony_ci mcfg = w->priv; 36688c2ecf20Sopenharmony_ci pipe = mcfg->pipe; 36698c2ecf20Sopenharmony_ci 36708c2ecf20Sopenharmony_ci p_module = devm_kzalloc(component->dev, 36718c2ecf20Sopenharmony_ci sizeof(*p_module), GFP_KERNEL); 36728c2ecf20Sopenharmony_ci if (!p_module) 36738c2ecf20Sopenharmony_ci return -ENOMEM; 36748c2ecf20Sopenharmony_ci 36758c2ecf20Sopenharmony_ci p_module->w = w; 36768c2ecf20Sopenharmony_ci list_add_tail(&p_module->node, &pipe->w_list); 36778c2ecf20Sopenharmony_ci } 36788c2ecf20Sopenharmony_ci } 36798c2ecf20Sopenharmony_ci 36808c2ecf20Sopenharmony_ci return 0; 36818c2ecf20Sopenharmony_ci} 36828c2ecf20Sopenharmony_ci 36838c2ecf20Sopenharmony_cistatic void skl_tplg_set_pipe_type(struct skl_dev *skl, struct skl_pipe *pipe) 36848c2ecf20Sopenharmony_ci{ 36858c2ecf20Sopenharmony_ci struct skl_pipe_module *w_module; 36868c2ecf20Sopenharmony_ci struct snd_soc_dapm_widget *w; 36878c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig; 36888c2ecf20Sopenharmony_ci bool host_found = false, link_found = false; 36898c2ecf20Sopenharmony_ci 36908c2ecf20Sopenharmony_ci list_for_each_entry(w_module, &pipe->w_list, node) { 36918c2ecf20Sopenharmony_ci w = w_module->w; 36928c2ecf20Sopenharmony_ci mconfig = w->priv; 36938c2ecf20Sopenharmony_ci 36948c2ecf20Sopenharmony_ci if (mconfig->dev_type == SKL_DEVICE_HDAHOST) 36958c2ecf20Sopenharmony_ci host_found = true; 36968c2ecf20Sopenharmony_ci else if (mconfig->dev_type != SKL_DEVICE_NONE) 36978c2ecf20Sopenharmony_ci link_found = true; 36988c2ecf20Sopenharmony_ci } 36998c2ecf20Sopenharmony_ci 37008c2ecf20Sopenharmony_ci if (host_found && link_found) 37018c2ecf20Sopenharmony_ci pipe->passthru = true; 37028c2ecf20Sopenharmony_ci else 37038c2ecf20Sopenharmony_ci pipe->passthru = false; 37048c2ecf20Sopenharmony_ci} 37058c2ecf20Sopenharmony_ci 37068c2ecf20Sopenharmony_ci/* 37078c2ecf20Sopenharmony_ci * SKL topology init routine 37088c2ecf20Sopenharmony_ci */ 37098c2ecf20Sopenharmony_ciint skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus) 37108c2ecf20Sopenharmony_ci{ 37118c2ecf20Sopenharmony_ci int ret; 37128c2ecf20Sopenharmony_ci const struct firmware *fw; 37138c2ecf20Sopenharmony_ci struct skl_dev *skl = bus_to_skl(bus); 37148c2ecf20Sopenharmony_ci struct skl_pipeline *ppl; 37158c2ecf20Sopenharmony_ci 37168c2ecf20Sopenharmony_ci ret = request_firmware(&fw, skl->tplg_name, bus->dev); 37178c2ecf20Sopenharmony_ci if (ret < 0) { 37188c2ecf20Sopenharmony_ci char alt_tplg_name[64]; 37198c2ecf20Sopenharmony_ci 37208c2ecf20Sopenharmony_ci snprintf(alt_tplg_name, sizeof(alt_tplg_name), "%s-tplg.bin", 37218c2ecf20Sopenharmony_ci skl->mach->drv_name); 37228c2ecf20Sopenharmony_ci dev_info(bus->dev, "tplg fw %s load failed with %d, trying alternative tplg name %s", 37238c2ecf20Sopenharmony_ci skl->tplg_name, ret, alt_tplg_name); 37248c2ecf20Sopenharmony_ci 37258c2ecf20Sopenharmony_ci ret = request_firmware(&fw, alt_tplg_name, bus->dev); 37268c2ecf20Sopenharmony_ci if (!ret) 37278c2ecf20Sopenharmony_ci goto component_load; 37288c2ecf20Sopenharmony_ci 37298c2ecf20Sopenharmony_ci dev_info(bus->dev, "tplg %s failed with %d, falling back to dfw_sst.bin", 37308c2ecf20Sopenharmony_ci alt_tplg_name, ret); 37318c2ecf20Sopenharmony_ci 37328c2ecf20Sopenharmony_ci ret = request_firmware(&fw, "dfw_sst.bin", bus->dev); 37338c2ecf20Sopenharmony_ci if (ret < 0) { 37348c2ecf20Sopenharmony_ci dev_err(bus->dev, "Fallback tplg fw %s load failed with %d\n", 37358c2ecf20Sopenharmony_ci "dfw_sst.bin", ret); 37368c2ecf20Sopenharmony_ci return ret; 37378c2ecf20Sopenharmony_ci } 37388c2ecf20Sopenharmony_ci } 37398c2ecf20Sopenharmony_ci 37408c2ecf20Sopenharmony_cicomponent_load: 37418c2ecf20Sopenharmony_ci 37428c2ecf20Sopenharmony_ci /* 37438c2ecf20Sopenharmony_ci * The complete tplg for SKL is loaded as index 0, we don't use 37448c2ecf20Sopenharmony_ci * any other index 37458c2ecf20Sopenharmony_ci */ 37468c2ecf20Sopenharmony_ci ret = snd_soc_tplg_component_load(component, &skl_tplg_ops, fw, 0); 37478c2ecf20Sopenharmony_ci if (ret < 0) { 37488c2ecf20Sopenharmony_ci dev_err(bus->dev, "tplg component load failed%d\n", ret); 37498c2ecf20Sopenharmony_ci goto err; 37508c2ecf20Sopenharmony_ci } 37518c2ecf20Sopenharmony_ci 37528c2ecf20Sopenharmony_ci ret = skl_tplg_create_pipe_widget_list(component); 37538c2ecf20Sopenharmony_ci if (ret < 0) { 37548c2ecf20Sopenharmony_ci dev_err(bus->dev, "tplg create pipe widget list failed%d\n", 37558c2ecf20Sopenharmony_ci ret); 37568c2ecf20Sopenharmony_ci goto err; 37578c2ecf20Sopenharmony_ci } 37588c2ecf20Sopenharmony_ci 37598c2ecf20Sopenharmony_ci list_for_each_entry(ppl, &skl->ppl_list, node) 37608c2ecf20Sopenharmony_ci skl_tplg_set_pipe_type(skl, ppl->pipe); 37618c2ecf20Sopenharmony_ci 37628c2ecf20Sopenharmony_cierr: 37638c2ecf20Sopenharmony_ci release_firmware(fw); 37648c2ecf20Sopenharmony_ci return ret; 37658c2ecf20Sopenharmony_ci} 37668c2ecf20Sopenharmony_ci 37678c2ecf20Sopenharmony_civoid skl_tplg_exit(struct snd_soc_component *component, struct hdac_bus *bus) 37688c2ecf20Sopenharmony_ci{ 37698c2ecf20Sopenharmony_ci struct skl_dev *skl = bus_to_skl(bus); 37708c2ecf20Sopenharmony_ci struct skl_pipeline *ppl, *tmp; 37718c2ecf20Sopenharmony_ci 37728c2ecf20Sopenharmony_ci list_for_each_entry_safe(ppl, tmp, &skl->ppl_list, node) 37738c2ecf20Sopenharmony_ci list_del(&ppl->node); 37748c2ecf20Sopenharmony_ci 37758c2ecf20Sopenharmony_ci /* clean up topology */ 37768c2ecf20Sopenharmony_ci snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL); 37778c2ecf20Sopenharmony_ci} 3778