147d7195dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2e4e2d2f4SJeeja KP /* 3e4e2d2f4SJeeja KP * skl-topology.c - Implements Platform component ALSA controls/widget 4e4e2d2f4SJeeja KP * handlers. 5e4e2d2f4SJeeja KP * 6e4e2d2f4SJeeja KP * Copyright (C) 2014-2015 Intel Corp 7e4e2d2f4SJeeja KP * Author: Jeeja KP <jeeja.kp@intel.com> 8e4e2d2f4SJeeja KP * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 9e4e2d2f4SJeeja KP */ 10e4e2d2f4SJeeja KP 11e4e2d2f4SJeeja KP #include <linux/slab.h> 12e4e2d2f4SJeeja KP #include <linux/types.h> 13e4e2d2f4SJeeja KP #include <linux/firmware.h> 14ac9391daSGuenter Roeck #include <linux/uuid.h> 1563643b59SPierre-Louis Bossart #include <sound/intel-nhlt.h> 16e4e2d2f4SJeeja KP #include <sound/soc.h> 171b290ef0SMateusz Gorski #include <sound/soc-acpi.h> 18e4e2d2f4SJeeja KP #include <sound/soc-topology.h> 196277e832SShreyas NC #include <uapi/sound/snd_sst_tokens.h> 200c24fdc0SGuenter Roeck #include <uapi/sound/skl-tplg-interface.h> 21e4e2d2f4SJeeja KP #include "skl-sst-dsp.h" 22e4e2d2f4SJeeja KP #include "skl-sst-ipc.h" 23e4e2d2f4SJeeja KP #include "skl-topology.h" 24e4e2d2f4SJeeja KP #include "skl.h" 256c5768b3SDharageswari R #include "../common/sst-dsp.h" 266c5768b3SDharageswari R #include "../common/sst-dsp-priv.h" 27e4e2d2f4SJeeja KP 28f7590d4fSJeeja KP #define SKL_CH_FIXUP_MASK (1 << 0) 29f7590d4fSJeeja KP #define SKL_RATE_FIXUP_MASK (1 << 1) 30f7590d4fSJeeja KP #define SKL_FMT_FIXUP_MASK (1 << 2) 316277e832SShreyas NC #define SKL_IN_DIR_BIT_MASK BIT(0) 326277e832SShreyas NC #define SKL_PIN_COUNT_MASK GENMASK(7, 4) 33f7590d4fSJeeja KP 347a1b749bSDharageswari R static const int mic_mono_list[] = { 357a1b749bSDharageswari R 0, 1, 2, 3, 367a1b749bSDharageswari R }; 377a1b749bSDharageswari R static const int mic_stereo_list[][SKL_CH_STEREO] = { 387a1b749bSDharageswari R {0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}, 397a1b749bSDharageswari R }; 407a1b749bSDharageswari R static const int mic_trio_list[][SKL_CH_TRIO] = { 417a1b749bSDharageswari R {0, 1, 2}, {0, 1, 3}, {0, 2, 3}, {1, 2, 3}, 427a1b749bSDharageswari R }; 437a1b749bSDharageswari R static const int mic_quatro_list[][SKL_CH_QUATRO] = { 447a1b749bSDharageswari R {0, 1, 2, 3}, 457a1b749bSDharageswari R }; 467a1b749bSDharageswari R 47f6fa56e2SRamesh Babu #define CHECK_HW_PARAMS(ch, freq, bps, prm_ch, prm_freq, prm_bps) \ 48f6fa56e2SRamesh Babu ((ch == prm_ch) && (bps == prm_bps) && (freq == prm_freq)) 49f6fa56e2SRamesh Babu 50bcc2a2dcSCezary Rojewski void skl_tplg_d0i3_get(struct skl_dev *skl, enum d0i3_capability caps) 51a83e3b4cSVinod Koul { 52bcc2a2dcSCezary Rojewski struct skl_d0i3_data *d0i3 = &skl->d0i3; 53a83e3b4cSVinod Koul 54a83e3b4cSVinod Koul switch (caps) { 55a83e3b4cSVinod Koul case SKL_D0I3_NONE: 56a83e3b4cSVinod Koul d0i3->non_d0i3++; 57a83e3b4cSVinod Koul break; 58a83e3b4cSVinod Koul 59a83e3b4cSVinod Koul case SKL_D0I3_STREAMING: 60a83e3b4cSVinod Koul d0i3->streaming++; 61a83e3b4cSVinod Koul break; 62a83e3b4cSVinod Koul 63a83e3b4cSVinod Koul case SKL_D0I3_NON_STREAMING: 64a83e3b4cSVinod Koul d0i3->non_streaming++; 65a83e3b4cSVinod Koul break; 66a83e3b4cSVinod Koul } 67a83e3b4cSVinod Koul } 68a83e3b4cSVinod Koul 69bcc2a2dcSCezary Rojewski void skl_tplg_d0i3_put(struct skl_dev *skl, enum d0i3_capability caps) 70a83e3b4cSVinod Koul { 71bcc2a2dcSCezary Rojewski struct skl_d0i3_data *d0i3 = &skl->d0i3; 72a83e3b4cSVinod Koul 73a83e3b4cSVinod Koul switch (caps) { 74a83e3b4cSVinod Koul case SKL_D0I3_NONE: 75a83e3b4cSVinod Koul d0i3->non_d0i3--; 76a83e3b4cSVinod Koul break; 77a83e3b4cSVinod Koul 78a83e3b4cSVinod Koul case SKL_D0I3_STREAMING: 79a83e3b4cSVinod Koul d0i3->streaming--; 80a83e3b4cSVinod Koul break; 81a83e3b4cSVinod Koul 82a83e3b4cSVinod Koul case SKL_D0I3_NON_STREAMING: 83a83e3b4cSVinod Koul d0i3->non_streaming--; 84a83e3b4cSVinod Koul break; 85a83e3b4cSVinod Koul } 86a83e3b4cSVinod Koul } 87a83e3b4cSVinod Koul 88e4e2d2f4SJeeja KP /* 89e4e2d2f4SJeeja KP * SKL DSP driver modelling uses only few DAPM widgets so for rest we will 90e4e2d2f4SJeeja KP * ignore. This helpers checks if the SKL driver handles this widget type 91e4e2d2f4SJeeja KP */ 92cb1f904dSGuneshwor Singh static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w, 93cb1f904dSGuneshwor Singh struct device *dev) 94e4e2d2f4SJeeja KP { 95cb1f904dSGuneshwor Singh if (w->dapm->dev != dev) 96cb1f904dSGuneshwor Singh return false; 97cb1f904dSGuneshwor Singh 98e4e2d2f4SJeeja KP switch (w->id) { 99e4e2d2f4SJeeja KP case snd_soc_dapm_dai_link: 100e4e2d2f4SJeeja KP case snd_soc_dapm_dai_in: 101e4e2d2f4SJeeja KP case snd_soc_dapm_aif_in: 102e4e2d2f4SJeeja KP case snd_soc_dapm_aif_out: 103e4e2d2f4SJeeja KP case snd_soc_dapm_dai_out: 104e4e2d2f4SJeeja KP case snd_soc_dapm_switch: 105fe65324eSRakesh Ughreja case snd_soc_dapm_output: 106fe65324eSRakesh Ughreja case snd_soc_dapm_mux: 107fe65324eSRakesh Ughreja 108e4e2d2f4SJeeja KP return false; 109e4e2d2f4SJeeja KP default: 110e4e2d2f4SJeeja KP return true; 111e4e2d2f4SJeeja KP } 112e4e2d2f4SJeeja KP } 113e4e2d2f4SJeeja KP 114bcc2a2dcSCezary Rojewski static void skl_dump_mconfig(struct skl_dev *skl, struct skl_module_cfg *mcfg) 115f7590d4fSJeeja KP { 116e8b374b6SCezary Rojewski struct skl_module_iface *iface = &mcfg->module->formats[mcfg->fmt_idx]; 117f6fa56e2SRamesh Babu 118bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "Dumping config\n"); 119bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "Input Format:\n"); 120bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "channels = %d\n", iface->inputs[0].fmt.channels); 121bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "s_freq = %d\n", iface->inputs[0].fmt.s_freq); 122bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "ch_cfg = %d\n", iface->inputs[0].fmt.ch_cfg); 123bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "valid bit depth = %d\n", 124f6fa56e2SRamesh Babu iface->inputs[0].fmt.valid_bit_depth); 125bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "Output Format:\n"); 126bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "channels = %d\n", iface->outputs[0].fmt.channels); 127bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "s_freq = %d\n", iface->outputs[0].fmt.s_freq); 128bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "valid bit depth = %d\n", 129f6fa56e2SRamesh Babu iface->outputs[0].fmt.valid_bit_depth); 130bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "ch_cfg = %d\n", iface->outputs[0].fmt.ch_cfg); 131f7590d4fSJeeja KP } 132f7590d4fSJeeja KP 133ea5a137dSSubhransu S. Prusty static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs) 134ea5a137dSSubhransu S. Prusty { 135ea5a137dSSubhransu S. Prusty int slot_map = 0xFFFFFFFF; 136ea5a137dSSubhransu S. Prusty int start_slot = 0; 137ea5a137dSSubhransu S. Prusty int i; 138ea5a137dSSubhransu S. Prusty 139ea5a137dSSubhransu S. Prusty for (i = 0; i < chs; i++) { 140ea5a137dSSubhransu S. Prusty /* 141ea5a137dSSubhransu S. Prusty * For 2 channels with starting slot as 0, slot map will 142ea5a137dSSubhransu S. Prusty * look like 0xFFFFFF10. 143ea5a137dSSubhransu S. Prusty */ 144ea5a137dSSubhransu S. Prusty slot_map &= (~(0xF << (4 * i)) | (start_slot << (4 * i))); 145ea5a137dSSubhransu S. Prusty start_slot++; 146ea5a137dSSubhransu S. Prusty } 147ea5a137dSSubhransu S. Prusty fmt->ch_map = slot_map; 148ea5a137dSSubhransu S. Prusty } 149ea5a137dSSubhransu S. Prusty 150f7590d4fSJeeja KP static void skl_tplg_update_params(struct skl_module_fmt *fmt, 151f7590d4fSJeeja KP struct skl_pipe_params *params, int fixup) 152f7590d4fSJeeja KP { 153f7590d4fSJeeja KP if (fixup & SKL_RATE_FIXUP_MASK) 154f7590d4fSJeeja KP fmt->s_freq = params->s_freq; 155ea5a137dSSubhransu S. Prusty if (fixup & SKL_CH_FIXUP_MASK) { 156f7590d4fSJeeja KP fmt->channels = params->ch; 157ea5a137dSSubhransu S. Prusty skl_tplg_update_chmap(fmt, fmt->channels); 158ea5a137dSSubhransu S. Prusty } 15998256f83SJeeja KP if (fixup & SKL_FMT_FIXUP_MASK) { 16098256f83SJeeja KP fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt); 16198256f83SJeeja KP 16298256f83SJeeja KP /* 16398256f83SJeeja KP * 16 bit is 16 bit container whereas 24 bit is in 32 bit 16498256f83SJeeja KP * container so update bit depth accordingly 16598256f83SJeeja KP */ 16698256f83SJeeja KP switch (fmt->valid_bit_depth) { 16798256f83SJeeja KP case SKL_DEPTH_16BIT: 16898256f83SJeeja KP fmt->bit_depth = fmt->valid_bit_depth; 16998256f83SJeeja KP break; 17098256f83SJeeja KP 17198256f83SJeeja KP default: 17298256f83SJeeja KP fmt->bit_depth = SKL_DEPTH_32BIT; 17398256f83SJeeja KP break; 17498256f83SJeeja KP } 17598256f83SJeeja KP } 17698256f83SJeeja KP 177f7590d4fSJeeja KP } 178f7590d4fSJeeja KP 179f7590d4fSJeeja KP /* 180f7590d4fSJeeja KP * A pipeline may have modules which impact the pcm parameters, like SRC, 181f7590d4fSJeeja KP * channel converter, format converter. 182f7590d4fSJeeja KP * We need to calculate the output params by applying the 'fixup' 183f7590d4fSJeeja KP * Topology will tell driver which type of fixup is to be applied by 184f7590d4fSJeeja KP * supplying the fixup mask, so based on that we calculate the output 185f7590d4fSJeeja KP * 186f7590d4fSJeeja KP * Now In FE the pcm hw_params is source/target format. Same is applicable 187f7590d4fSJeeja KP * for BE with its hw_params invoked. 188f7590d4fSJeeja KP * here based on FE, BE pipeline and direction we calculate the input and 189f7590d4fSJeeja KP * outfix and then apply that for a module 190f7590d4fSJeeja KP */ 191f7590d4fSJeeja KP static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg, 192f7590d4fSJeeja KP struct skl_pipe_params *params, bool is_fe) 193f7590d4fSJeeja KP { 194f7590d4fSJeeja KP int in_fixup, out_fixup; 195f7590d4fSJeeja KP struct skl_module_fmt *in_fmt, *out_fmt; 196f7590d4fSJeeja KP 1974cd9899fSHardik T Shah /* Fixups will be applied to pin 0 only */ 198e8b374b6SCezary Rojewski in_fmt = &m_cfg->module->formats[m_cfg->fmt_idx].inputs[0].fmt; 199e8b374b6SCezary Rojewski out_fmt = &m_cfg->module->formats[m_cfg->fmt_idx].outputs[0].fmt; 200f7590d4fSJeeja KP 201f7590d4fSJeeja KP if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { 202f7590d4fSJeeja KP if (is_fe) { 203f7590d4fSJeeja KP in_fixup = m_cfg->params_fixup; 204f7590d4fSJeeja KP out_fixup = (~m_cfg->converter) & 205f7590d4fSJeeja KP m_cfg->params_fixup; 206f7590d4fSJeeja KP } else { 207f7590d4fSJeeja KP out_fixup = m_cfg->params_fixup; 208f7590d4fSJeeja KP in_fixup = (~m_cfg->converter) & 209f7590d4fSJeeja KP m_cfg->params_fixup; 210f7590d4fSJeeja KP } 211f7590d4fSJeeja KP } else { 212f7590d4fSJeeja KP if (is_fe) { 213f7590d4fSJeeja KP out_fixup = m_cfg->params_fixup; 214f7590d4fSJeeja KP in_fixup = (~m_cfg->converter) & 215f7590d4fSJeeja KP m_cfg->params_fixup; 216f7590d4fSJeeja KP } else { 217f7590d4fSJeeja KP in_fixup = m_cfg->params_fixup; 218f7590d4fSJeeja KP out_fixup = (~m_cfg->converter) & 219f7590d4fSJeeja KP m_cfg->params_fixup; 220f7590d4fSJeeja KP } 221f7590d4fSJeeja KP } 222f7590d4fSJeeja KP 223f7590d4fSJeeja KP skl_tplg_update_params(in_fmt, params, in_fixup); 224f7590d4fSJeeja KP skl_tplg_update_params(out_fmt, params, out_fixup); 225f7590d4fSJeeja KP } 226f7590d4fSJeeja KP 227f7590d4fSJeeja KP /* 228f7590d4fSJeeja KP * A module needs input and output buffers, which are dependent upon pcm 229f7590d4fSJeeja KP * params, so once we have calculate params, we need buffer calculation as 230f7590d4fSJeeja KP * well. 231f7590d4fSJeeja KP */ 232bcc2a2dcSCezary Rojewski static void skl_tplg_update_buffer_size(struct skl_dev *skl, 233f7590d4fSJeeja KP struct skl_module_cfg *mcfg) 234f7590d4fSJeeja KP { 235f7590d4fSJeeja KP int multiplier = 1; 2364cd9899fSHardik T Shah struct skl_module_fmt *in_fmt, *out_fmt; 237f6fa56e2SRamesh Babu struct skl_module_res *res; 2384cd9899fSHardik T Shah 2394cd9899fSHardik T Shah /* Since fixups is applied to pin 0 only, ibs, obs needs 2404cd9899fSHardik T Shah * change for pin 0 only 2414cd9899fSHardik T Shah */ 242e8b374b6SCezary Rojewski res = &mcfg->module->resources[mcfg->res_idx]; 243e8b374b6SCezary Rojewski in_fmt = &mcfg->module->formats[mcfg->fmt_idx].inputs[0].fmt; 244e8b374b6SCezary Rojewski out_fmt = &mcfg->module->formats[mcfg->fmt_idx].outputs[0].fmt; 245f7590d4fSJeeja KP 246f7590d4fSJeeja KP if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT) 247f7590d4fSJeeja KP multiplier = 5; 248f0c8e1d9SSubhransu S. Prusty 249f6fa56e2SRamesh Babu res->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) * 250998d6fb5STakashi Sakamoto in_fmt->channels * (in_fmt->bit_depth >> 3) * 251f7590d4fSJeeja KP multiplier; 252f7590d4fSJeeja KP 253f6fa56e2SRamesh Babu res->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) * 254998d6fb5STakashi Sakamoto out_fmt->channels * (out_fmt->bit_depth >> 3) * 255f7590d4fSJeeja KP multiplier; 256f7590d4fSJeeja KP } 257f7590d4fSJeeja KP 258db2f586bSSenthilnathan Veppur static u8 skl_tplg_be_dev_type(int dev_type) 259db2f586bSSenthilnathan Veppur { 260db2f586bSSenthilnathan Veppur int ret; 261db2f586bSSenthilnathan Veppur 262db2f586bSSenthilnathan Veppur switch (dev_type) { 263db2f586bSSenthilnathan Veppur case SKL_DEVICE_BT: 264db2f586bSSenthilnathan Veppur ret = NHLT_DEVICE_BT; 265db2f586bSSenthilnathan Veppur break; 266db2f586bSSenthilnathan Veppur 267db2f586bSSenthilnathan Veppur case SKL_DEVICE_DMIC: 268db2f586bSSenthilnathan Veppur ret = NHLT_DEVICE_DMIC; 269db2f586bSSenthilnathan Veppur break; 270db2f586bSSenthilnathan Veppur 271db2f586bSSenthilnathan Veppur case SKL_DEVICE_I2S: 272db2f586bSSenthilnathan Veppur ret = NHLT_DEVICE_I2S; 273db2f586bSSenthilnathan Veppur break; 274db2f586bSSenthilnathan Veppur 275db2f586bSSenthilnathan Veppur default: 276db2f586bSSenthilnathan Veppur ret = NHLT_DEVICE_INVALID; 277db2f586bSSenthilnathan Veppur break; 278db2f586bSSenthilnathan Veppur } 279db2f586bSSenthilnathan Veppur 280db2f586bSSenthilnathan Veppur return ret; 281db2f586bSSenthilnathan Veppur } 282db2f586bSSenthilnathan Veppur 2832d1419a3SJeeja KP static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, 284bcc2a2dcSCezary Rojewski struct skl_dev *skl) 2852d1419a3SJeeja KP { 2862d1419a3SJeeja KP struct skl_module_cfg *m_cfg = w->priv; 2872d1419a3SJeeja KP int link_type, dir; 2882d1419a3SJeeja KP u32 ch, s_freq, s_fmt; 2892d1419a3SJeeja KP struct nhlt_specific_cfg *cfg; 290db2f586bSSenthilnathan Veppur u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type); 291f6fa56e2SRamesh Babu int fmt_idx = m_cfg->fmt_idx; 292f6fa56e2SRamesh Babu struct skl_module_iface *m_iface = &m_cfg->module->formats[fmt_idx]; 2932d1419a3SJeeja KP 2942d1419a3SJeeja KP /* check if we already have blob */ 295*a4ad42d2SKareem Shaik if (m_cfg->formats_config[SKL_PARAM_INIT].caps_size > 0) 2962d1419a3SJeeja KP return 0; 2972d1419a3SJeeja KP 298bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "Applying default cfg blob\n"); 2992d1419a3SJeeja KP switch (m_cfg->dev_type) { 3002d1419a3SJeeja KP case SKL_DEVICE_DMIC: 3012d1419a3SJeeja KP link_type = NHLT_LINK_DMIC; 302c7c6c736SJeeja KP dir = SNDRV_PCM_STREAM_CAPTURE; 303f6fa56e2SRamesh Babu s_freq = m_iface->inputs[0].fmt.s_freq; 304f6fa56e2SRamesh Babu s_fmt = m_iface->inputs[0].fmt.bit_depth; 305f6fa56e2SRamesh Babu ch = m_iface->inputs[0].fmt.channels; 3062d1419a3SJeeja KP break; 3072d1419a3SJeeja KP 3082d1419a3SJeeja KP case SKL_DEVICE_I2S: 3092d1419a3SJeeja KP link_type = NHLT_LINK_SSP; 3102d1419a3SJeeja KP if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) { 311c7c6c736SJeeja KP dir = SNDRV_PCM_STREAM_PLAYBACK; 312f6fa56e2SRamesh Babu s_freq = m_iface->outputs[0].fmt.s_freq; 313f6fa56e2SRamesh Babu s_fmt = m_iface->outputs[0].fmt.bit_depth; 314f6fa56e2SRamesh Babu ch = m_iface->outputs[0].fmt.channels; 315c7c6c736SJeeja KP } else { 316c7c6c736SJeeja KP dir = SNDRV_PCM_STREAM_CAPTURE; 317f6fa56e2SRamesh Babu s_freq = m_iface->inputs[0].fmt.s_freq; 318f6fa56e2SRamesh Babu s_fmt = m_iface->inputs[0].fmt.bit_depth; 319f6fa56e2SRamesh Babu ch = m_iface->inputs[0].fmt.channels; 3202d1419a3SJeeja KP } 3212d1419a3SJeeja KP break; 3222d1419a3SJeeja KP 3232d1419a3SJeeja KP default: 3242d1419a3SJeeja KP return -EINVAL; 3252d1419a3SJeeja KP } 3262d1419a3SJeeja KP 3272d1419a3SJeeja KP /* update the blob based on virtual bus_id and default params */ 3282d1419a3SJeeja KP cfg = skl_get_ep_blob(skl, m_cfg->vbus_id, link_type, 329db2f586bSSenthilnathan Veppur s_fmt, ch, s_freq, dir, dev_type); 3302d1419a3SJeeja KP if (cfg) { 331*a4ad42d2SKareem Shaik m_cfg->formats_config[SKL_PARAM_INIT].caps_size = cfg->size; 332*a4ad42d2SKareem Shaik m_cfg->formats_config[SKL_PARAM_INIT].caps = (u32 *)&cfg->caps; 3332d1419a3SJeeja KP } else { 334bcc2a2dcSCezary Rojewski dev_err(skl->dev, "Blob NULL for id %x type %d dirn %d\n", 3352d1419a3SJeeja KP m_cfg->vbus_id, link_type, dir); 336bcc2a2dcSCezary Rojewski dev_err(skl->dev, "PCM: ch %d, freq %d, fmt %d\n", 3372d1419a3SJeeja KP ch, s_freq, s_fmt); 3382d1419a3SJeeja KP return -EIO; 3392d1419a3SJeeja KP } 3402d1419a3SJeeja KP 3412d1419a3SJeeja KP return 0; 3422d1419a3SJeeja KP } 3432d1419a3SJeeja KP 344f7590d4fSJeeja KP static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w, 345bcc2a2dcSCezary Rojewski struct skl_dev *skl) 346f7590d4fSJeeja KP { 347f7590d4fSJeeja KP struct skl_module_cfg *m_cfg = w->priv; 348f7590d4fSJeeja KP struct skl_pipe_params *params = m_cfg->pipe->p_params; 349f7590d4fSJeeja KP int p_conn_type = m_cfg->pipe->conn_type; 350f7590d4fSJeeja KP bool is_fe; 351f7590d4fSJeeja KP 352f7590d4fSJeeja KP if (!m_cfg->params_fixup) 353f7590d4fSJeeja KP return; 354f7590d4fSJeeja KP 355bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "Mconfig for widget=%s BEFORE updation\n", 356f7590d4fSJeeja KP w->name); 357f7590d4fSJeeja KP 358bcc2a2dcSCezary Rojewski skl_dump_mconfig(skl, m_cfg); 359f7590d4fSJeeja KP 360f7590d4fSJeeja KP if (p_conn_type == SKL_PIPE_CONN_TYPE_FE) 361f7590d4fSJeeja KP is_fe = true; 362f7590d4fSJeeja KP else 363f7590d4fSJeeja KP is_fe = false; 364f7590d4fSJeeja KP 365f7590d4fSJeeja KP skl_tplg_update_params_fixup(m_cfg, params, is_fe); 366bcc2a2dcSCezary Rojewski skl_tplg_update_buffer_size(skl, m_cfg); 367f7590d4fSJeeja KP 368bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "Mconfig for widget=%s AFTER updation\n", 369f7590d4fSJeeja KP w->name); 370f7590d4fSJeeja KP 371bcc2a2dcSCezary Rojewski skl_dump_mconfig(skl, m_cfg); 372f7590d4fSJeeja KP } 373f7590d4fSJeeja KP 374e4e2d2f4SJeeja KP /* 375abb74003SJeeja KP * some modules can have multiple params set from user control and 376abb74003SJeeja KP * need to be set after module is initialized. If set_param flag is 377abb74003SJeeja KP * set module params will be done after module is initialised. 378abb74003SJeeja KP */ 379abb74003SJeeja KP static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w, 380bcc2a2dcSCezary Rojewski struct skl_dev *skl) 381abb74003SJeeja KP { 382abb74003SJeeja KP int i, ret; 383abb74003SJeeja KP struct skl_module_cfg *mconfig = w->priv; 384abb74003SJeeja KP const struct snd_kcontrol_new *k; 385abb74003SJeeja KP struct soc_bytes_ext *sb; 386abb74003SJeeja KP struct skl_algo_data *bc; 387abb74003SJeeja KP struct skl_specific_cfg *sp_cfg; 388abb74003SJeeja KP 389*a4ad42d2SKareem Shaik if (mconfig->formats_config[SKL_PARAM_SET].caps_size > 0 && 390*a4ad42d2SKareem Shaik mconfig->formats_config[SKL_PARAM_SET].set_params == SKL_PARAM_SET) { 391*a4ad42d2SKareem Shaik sp_cfg = &mconfig->formats_config[SKL_PARAM_SET]; 392bcc2a2dcSCezary Rojewski ret = skl_set_module_params(skl, sp_cfg->caps, 393abb74003SJeeja KP sp_cfg->caps_size, 394abb74003SJeeja KP sp_cfg->param_id, mconfig); 395abb74003SJeeja KP if (ret < 0) 396abb74003SJeeja KP return ret; 397abb74003SJeeja KP } 398abb74003SJeeja KP 399abb74003SJeeja KP for (i = 0; i < w->num_kcontrols; i++) { 400abb74003SJeeja KP k = &w->kcontrol_news[i]; 401abb74003SJeeja KP if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 402abb74003SJeeja KP sb = (void *) k->private_value; 403abb74003SJeeja KP bc = (struct skl_algo_data *)sb->dobj.private; 404abb74003SJeeja KP 4054ced1827SJeeja KP if (bc->set_params == SKL_PARAM_SET) { 406bcc2a2dcSCezary Rojewski ret = skl_set_module_params(skl, 4070d682104SDharageswari R (u32 *)bc->params, bc->size, 408abb74003SJeeja KP bc->param_id, mconfig); 409abb74003SJeeja KP if (ret < 0) 410abb74003SJeeja KP return ret; 411abb74003SJeeja KP } 412abb74003SJeeja KP } 413abb74003SJeeja KP } 414abb74003SJeeja KP 415abb74003SJeeja KP return 0; 416abb74003SJeeja KP } 417abb74003SJeeja KP 418abb74003SJeeja KP /* 419abb74003SJeeja KP * some module param can set from user control and this is required as 420abb74003SJeeja KP * when module is initailzed. if module param is required in init it is 421abb74003SJeeja KP * identifed by set_param flag. if set_param flag is not set, then this 422abb74003SJeeja KP * parameter needs to set as part of module init. 423abb74003SJeeja KP */ 424abb74003SJeeja KP static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w) 425abb74003SJeeja KP { 426abb74003SJeeja KP const struct snd_kcontrol_new *k; 427abb74003SJeeja KP struct soc_bytes_ext *sb; 428abb74003SJeeja KP struct skl_algo_data *bc; 429abb74003SJeeja KP struct skl_module_cfg *mconfig = w->priv; 430abb74003SJeeja KP int i; 431abb74003SJeeja KP 432abb74003SJeeja KP for (i = 0; i < w->num_kcontrols; i++) { 433abb74003SJeeja KP k = &w->kcontrol_news[i]; 434abb74003SJeeja KP if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 435abb74003SJeeja KP sb = (struct soc_bytes_ext *)k->private_value; 436abb74003SJeeja KP bc = (struct skl_algo_data *)sb->dobj.private; 437abb74003SJeeja KP 4384ced1827SJeeja KP if (bc->set_params != SKL_PARAM_INIT) 439abb74003SJeeja KP continue; 440abb74003SJeeja KP 441*a4ad42d2SKareem Shaik mconfig->formats_config[SKL_PARAM_INIT].caps = 442*a4ad42d2SKareem Shaik (u32 *)bc->params; 443*a4ad42d2SKareem Shaik mconfig->formats_config[SKL_PARAM_INIT].caps_size = 444*a4ad42d2SKareem Shaik bc->size; 445abb74003SJeeja KP 446abb74003SJeeja KP break; 447abb74003SJeeja KP } 448abb74003SJeeja KP } 449abb74003SJeeja KP 450abb74003SJeeja KP return 0; 451abb74003SJeeja KP } 452abb74003SJeeja KP 453bcc2a2dcSCezary Rojewski static int skl_tplg_module_prepare(struct skl_dev *skl, struct skl_pipe *pipe, 454bb704a73SJeeja KP struct snd_soc_dapm_widget *w, struct skl_module_cfg *mcfg) 455bb704a73SJeeja KP { 456bb704a73SJeeja KP switch (mcfg->dev_type) { 457bb704a73SJeeja KP case SKL_DEVICE_HDAHOST: 458bcc2a2dcSCezary Rojewski return skl_pcm_host_dma_prepare(skl->dev, pipe->p_params); 459bb704a73SJeeja KP 460bb704a73SJeeja KP case SKL_DEVICE_HDALINK: 461bcc2a2dcSCezary Rojewski return skl_pcm_link_dma_prepare(skl->dev, pipe->p_params); 462bb704a73SJeeja KP } 463bb704a73SJeeja KP 464bb704a73SJeeja KP return 0; 465bb704a73SJeeja KP } 466bb704a73SJeeja KP 467abb74003SJeeja KP /* 468e4e2d2f4SJeeja KP * Inside a pipe instance, we can have various modules. These modules need 469e4e2d2f4SJeeja KP * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by 470e4e2d2f4SJeeja KP * skl_init_module() routine, so invoke that for all modules in a pipeline 471e4e2d2f4SJeeja KP */ 472e4e2d2f4SJeeja KP static int 473bcc2a2dcSCezary Rojewski skl_tplg_init_pipe_modules(struct skl_dev *skl, struct skl_pipe *pipe) 474e4e2d2f4SJeeja KP { 475e4e2d2f4SJeeja KP struct skl_pipe_module *w_module; 476e4e2d2f4SJeeja KP struct snd_soc_dapm_widget *w; 477e4e2d2f4SJeeja KP struct skl_module_cfg *mconfig; 478f6fa56e2SRamesh Babu u8 cfg_idx; 479e4e2d2f4SJeeja KP int ret = 0; 480e4e2d2f4SJeeja KP 481e4e2d2f4SJeeja KP list_for_each_entry(w_module, &pipe->w_list, node) { 4829e0784d0SAndy Shevchenko guid_t *uuid_mod; 483e4e2d2f4SJeeja KP w = w_module->w; 484e4e2d2f4SJeeja KP mconfig = w->priv; 485e4e2d2f4SJeeja KP 486b7c50555SVinod Koul /* check if module ids are populated */ 487b7c50555SVinod Koul if (mconfig->id.module_id < 0) { 488bcc2a2dcSCezary Rojewski dev_err(skl->dev, 489a657ae7eSVinod Koul "module %pUL id not populated\n", 4909e0784d0SAndy Shevchenko (guid_t *)mconfig->guid); 491a657ae7eSVinod Koul return -EIO; 492b7c50555SVinod Koul } 493b7c50555SVinod Koul 494f6fa56e2SRamesh Babu cfg_idx = mconfig->pipe->cur_config_idx; 495f6fa56e2SRamesh Babu mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx; 496f6fa56e2SRamesh Babu mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx; 497f6fa56e2SRamesh Babu 498bcc2a2dcSCezary Rojewski if (mconfig->module->loadable && skl->dsp->fw_ops.load_mod) { 499bcc2a2dcSCezary Rojewski ret = skl->dsp->fw_ops.load_mod(skl->dsp, 5006c5768b3SDharageswari R mconfig->id.module_id, mconfig->guid); 5016c5768b3SDharageswari R if (ret < 0) 5026c5768b3SDharageswari R return ret; 5036c5768b3SDharageswari R } 5046c5768b3SDharageswari R 505bb704a73SJeeja KP /* prepare the DMA if the module is gateway cpr */ 506bcc2a2dcSCezary Rojewski ret = skl_tplg_module_prepare(skl, pipe, w, mconfig); 507bb704a73SJeeja KP if (ret < 0) 508bb704a73SJeeja KP return ret; 509bb704a73SJeeja KP 5102d1419a3SJeeja KP /* update blob if blob is null for be with default value */ 511bcc2a2dcSCezary Rojewski skl_tplg_update_be_blob(w, skl); 5122d1419a3SJeeja KP 513f7590d4fSJeeja KP /* 514f7590d4fSJeeja KP * apply fix/conversion to module params based on 515f7590d4fSJeeja KP * FE/BE params 516f7590d4fSJeeja KP */ 517bcc2a2dcSCezary Rojewski skl_tplg_update_module_params(w, skl); 5189e0784d0SAndy Shevchenko uuid_mod = (guid_t *)mconfig->guid; 519bcc2a2dcSCezary Rojewski mconfig->id.pvt_id = skl_get_pvt_id(skl, uuid_mod, 520b26199eaSJeeja KP mconfig->id.instance_id); 521ef2a352cSDharageswari R if (mconfig->id.pvt_id < 0) 522ef2a352cSDharageswari R return ret; 523abb74003SJeeja KP skl_tplg_set_module_init_data(w); 5244147a6e5SPardha Saradhi K 525bcc2a2dcSCezary Rojewski ret = skl_dsp_get_core(skl->dsp, mconfig->core_id); 5264147a6e5SPardha Saradhi K if (ret < 0) { 527bcc2a2dcSCezary Rojewski dev_err(skl->dev, "Failed to wake up core %d ret=%d\n", 5284147a6e5SPardha Saradhi K mconfig->core_id, ret); 5294147a6e5SPardha Saradhi K return ret; 5304147a6e5SPardha Saradhi K } 5314147a6e5SPardha Saradhi K 532bcc2a2dcSCezary Rojewski ret = skl_init_module(skl, mconfig); 533ef2a352cSDharageswari R if (ret < 0) { 534bcc2a2dcSCezary Rojewski skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id); 5354147a6e5SPardha Saradhi K goto err; 536ef2a352cSDharageswari R } 537f2a167caSCezary Rojewski 538bcc2a2dcSCezary Rojewski ret = skl_tplg_set_module_params(w, skl); 539e4e2d2f4SJeeja KP if (ret < 0) 5404147a6e5SPardha Saradhi K goto err; 541e4e2d2f4SJeeja KP } 542e4e2d2f4SJeeja KP 543e4e2d2f4SJeeja KP return 0; 5444147a6e5SPardha Saradhi K err: 545bcc2a2dcSCezary Rojewski skl_dsp_put_core(skl->dsp, mconfig->core_id); 5464147a6e5SPardha Saradhi K return ret; 547e4e2d2f4SJeeja KP } 548d93f8e55SVinod Koul 549bcc2a2dcSCezary Rojewski static int skl_tplg_unload_pipe_modules(struct skl_dev *skl, 5506c5768b3SDharageswari R struct skl_pipe *pipe) 5516c5768b3SDharageswari R { 5524147a6e5SPardha Saradhi K int ret = 0; 55325722cf6SPierre-Louis Bossart struct skl_pipe_module *w_module; 55425722cf6SPierre-Louis Bossart struct skl_module_cfg *mconfig; 5556c5768b3SDharageswari R 5566c5768b3SDharageswari R list_for_each_entry(w_module, &pipe->w_list, node) { 5579e0784d0SAndy Shevchenko guid_t *uuid_mod; 5586c5768b3SDharageswari R mconfig = w_module->w->priv; 5599e0784d0SAndy Shevchenko uuid_mod = (guid_t *)mconfig->guid; 5606c5768b3SDharageswari R 561e4e95d82SGustaw Lewandowski if (mconfig->module->loadable && skl->dsp->fw_ops.unload_mod) { 562bcc2a2dcSCezary Rojewski ret = skl->dsp->fw_ops.unload_mod(skl->dsp, 5636c5768b3SDharageswari R mconfig->id.module_id); 564b0fab9c6SDharageswari R if (ret < 0) 565b0fab9c6SDharageswari R return -EIO; 566b0fab9c6SDharageswari R } 567bcc2a2dcSCezary Rojewski skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id); 5684147a6e5SPardha Saradhi K 569bcc2a2dcSCezary Rojewski ret = skl_dsp_put_core(skl->dsp, mconfig->core_id); 5704147a6e5SPardha Saradhi K if (ret < 0) { 5714147a6e5SPardha Saradhi K /* don't return; continue with other modules */ 572bcc2a2dcSCezary Rojewski dev_err(skl->dev, "Failed to sleep core %d ret=%d\n", 5734147a6e5SPardha Saradhi K mconfig->core_id, ret); 5744147a6e5SPardha Saradhi K } 5756c5768b3SDharageswari R } 5766c5768b3SDharageswari R 5776c5768b3SDharageswari R /* no modules to unload in this path, so return */ 5784147a6e5SPardha Saradhi K return ret; 5796c5768b3SDharageswari R } 5806c5768b3SDharageswari R 5811b450791SMateusz Gorski static bool skl_tplg_is_multi_fmt(struct skl_dev *skl, struct skl_pipe *pipe) 5821b450791SMateusz Gorski { 5831b450791SMateusz Gorski struct skl_pipe_fmt *cur_fmt; 5841b450791SMateusz Gorski struct skl_pipe_fmt *next_fmt; 5851b450791SMateusz Gorski int i; 5861b450791SMateusz Gorski 5871b450791SMateusz Gorski if (pipe->nr_cfgs <= 1) 5881b450791SMateusz Gorski return false; 5891b450791SMateusz Gorski 5901b450791SMateusz Gorski if (pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) 5911b450791SMateusz Gorski return true; 5921b450791SMateusz Gorski 5931b450791SMateusz Gorski for (i = 0; i < pipe->nr_cfgs - 1; i++) { 5941b450791SMateusz Gorski if (pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) { 5951b450791SMateusz Gorski cur_fmt = &pipe->configs[i].out_fmt; 5961b450791SMateusz Gorski next_fmt = &pipe->configs[i + 1].out_fmt; 5971b450791SMateusz Gorski } else { 5981b450791SMateusz Gorski cur_fmt = &pipe->configs[i].in_fmt; 5991b450791SMateusz Gorski next_fmt = &pipe->configs[i + 1].in_fmt; 6001b450791SMateusz Gorski } 6011b450791SMateusz Gorski 6021b450791SMateusz Gorski if (!CHECK_HW_PARAMS(cur_fmt->channels, cur_fmt->freq, 6031b450791SMateusz Gorski cur_fmt->bps, 6041b450791SMateusz Gorski next_fmt->channels, 6051b450791SMateusz Gorski next_fmt->freq, 6061b450791SMateusz Gorski next_fmt->bps)) 6071b450791SMateusz Gorski return true; 6081b450791SMateusz Gorski } 6091b450791SMateusz Gorski 6101b450791SMateusz Gorski return false; 6111b450791SMateusz Gorski } 6121b450791SMateusz Gorski 613d93f8e55SVinod Koul /* 614f6fa56e2SRamesh Babu * Here, we select pipe format based on the pipe type and pipe 615f6fa56e2SRamesh Babu * direction to determine the current config index for the pipeline. 616f6fa56e2SRamesh Babu * The config index is then used to select proper module resources. 617f6fa56e2SRamesh Babu * Intermediate pipes currently have a fixed format hence we select the 618f6fa56e2SRamesh Babu * 0th configuratation by default for such pipes. 619f6fa56e2SRamesh Babu */ 620f6fa56e2SRamesh Babu static int 621bcc2a2dcSCezary Rojewski skl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig) 622f6fa56e2SRamesh Babu { 623f6fa56e2SRamesh Babu struct skl_pipe *pipe = mconfig->pipe; 624f6fa56e2SRamesh Babu struct skl_pipe_params *params = pipe->p_params; 625f6fa56e2SRamesh Babu struct skl_path_config *pconfig = &pipe->configs[0]; 626f6fa56e2SRamesh Babu struct skl_pipe_fmt *fmt = NULL; 627f6fa56e2SRamesh Babu bool in_fmt = false; 628f6fa56e2SRamesh Babu int i; 629f6fa56e2SRamesh Babu 630f6fa56e2SRamesh Babu if (pipe->nr_cfgs == 0) { 631f6fa56e2SRamesh Babu pipe->cur_config_idx = 0; 632f6fa56e2SRamesh Babu return 0; 633f6fa56e2SRamesh Babu } 634f6fa56e2SRamesh Babu 6351b450791SMateusz Gorski if (skl_tplg_is_multi_fmt(skl, pipe)) { 6361b450791SMateusz Gorski pipe->cur_config_idx = pipe->pipe_config_idx; 6371b450791SMateusz Gorski pipe->memory_pages = pconfig->mem_pages; 6381b450791SMateusz Gorski dev_dbg(skl->dev, "found pipe config idx:%d\n", 6391b450791SMateusz Gorski pipe->cur_config_idx); 6401b450791SMateusz Gorski return 0; 6411b450791SMateusz Gorski } 6421b450791SMateusz Gorski 643f6fa56e2SRamesh Babu if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE) { 644bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "No conn_type detected, take 0th config\n"); 645f6fa56e2SRamesh Babu pipe->cur_config_idx = 0; 646f6fa56e2SRamesh Babu pipe->memory_pages = pconfig->mem_pages; 647f6fa56e2SRamesh Babu 648f6fa56e2SRamesh Babu return 0; 649f6fa56e2SRamesh Babu } 650f6fa56e2SRamesh Babu 651f6fa56e2SRamesh Babu if ((pipe->conn_type == SKL_PIPE_CONN_TYPE_FE && 652f6fa56e2SRamesh Babu pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) || 653f6fa56e2SRamesh Babu (pipe->conn_type == SKL_PIPE_CONN_TYPE_BE && 654f6fa56e2SRamesh Babu pipe->direction == SNDRV_PCM_STREAM_CAPTURE)) 655f6fa56e2SRamesh Babu in_fmt = true; 656f6fa56e2SRamesh Babu 657f6fa56e2SRamesh Babu for (i = 0; i < pipe->nr_cfgs; i++) { 658f6fa56e2SRamesh Babu pconfig = &pipe->configs[i]; 659f6fa56e2SRamesh Babu if (in_fmt) 660f6fa56e2SRamesh Babu fmt = &pconfig->in_fmt; 661f6fa56e2SRamesh Babu else 662f6fa56e2SRamesh Babu fmt = &pconfig->out_fmt; 663f6fa56e2SRamesh Babu 664f6fa56e2SRamesh Babu if (CHECK_HW_PARAMS(params->ch, params->s_freq, params->s_fmt, 665f6fa56e2SRamesh Babu fmt->channels, fmt->freq, fmt->bps)) { 666f6fa56e2SRamesh Babu pipe->cur_config_idx = i; 667f6fa56e2SRamesh Babu pipe->memory_pages = pconfig->mem_pages; 668bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "Using pipe config: %d\n", i); 669f6fa56e2SRamesh Babu 670f6fa56e2SRamesh Babu return 0; 671f6fa56e2SRamesh Babu } 672f6fa56e2SRamesh Babu } 673f6fa56e2SRamesh Babu 674bcc2a2dcSCezary Rojewski dev_err(skl->dev, "Invalid pipe config: %d %d %d for pipe: %d\n", 675f6fa56e2SRamesh Babu params->ch, params->s_freq, params->s_fmt, pipe->ppl_id); 676f6fa56e2SRamesh Babu return -EINVAL; 677f6fa56e2SRamesh Babu } 678f6fa56e2SRamesh Babu 679f6fa56e2SRamesh Babu /* 680d93f8e55SVinod Koul * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we 681d93f8e55SVinod Koul * need create the pipeline. So we do following: 682d93f8e55SVinod Koul * - Create the pipeline 683d93f8e55SVinod Koul * - Initialize the modules in pipeline 684d93f8e55SVinod Koul * - finally bind all modules together 685d93f8e55SVinod Koul */ 686d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, 687bcc2a2dcSCezary Rojewski struct skl_dev *skl) 688d93f8e55SVinod Koul { 689d93f8e55SVinod Koul int ret; 690d93f8e55SVinod Koul struct skl_module_cfg *mconfig = w->priv; 691d93f8e55SVinod Koul struct skl_pipe_module *w_module; 692d93f8e55SVinod Koul struct skl_pipe *s_pipe = mconfig->pipe; 693b8c722ddSJeeja KP struct skl_module_cfg *src_module = NULL, *dst_module, *module; 694b8c722ddSJeeja KP struct skl_module_deferred_bind *modules; 695d93f8e55SVinod Koul 696f6fa56e2SRamesh Babu ret = skl_tplg_get_pipe_config(skl, mconfig); 697f6fa56e2SRamesh Babu if (ret < 0) 698f6fa56e2SRamesh Babu return ret; 699f6fa56e2SRamesh Babu 700d93f8e55SVinod Koul /* 701d93f8e55SVinod Koul * Create a list of modules for pipe. 702d93f8e55SVinod Koul * This list contains modules from source to sink 703d93f8e55SVinod Koul */ 704bcc2a2dcSCezary Rojewski ret = skl_create_pipeline(skl, mconfig->pipe); 705d93f8e55SVinod Koul if (ret < 0) 706d93f8e55SVinod Koul return ret; 707d93f8e55SVinod Koul 708d93f8e55SVinod Koul /* Init all pipe modules from source to sink */ 709d93f8e55SVinod Koul ret = skl_tplg_init_pipe_modules(skl, s_pipe); 710d93f8e55SVinod Koul if (ret < 0) 711d93f8e55SVinod Koul return ret; 712d93f8e55SVinod Koul 713d93f8e55SVinod Koul /* Bind modules from source to sink */ 714d93f8e55SVinod Koul list_for_each_entry(w_module, &s_pipe->w_list, node) { 715d93f8e55SVinod Koul dst_module = w_module->w->priv; 716d93f8e55SVinod Koul 717d93f8e55SVinod Koul if (src_module == NULL) { 718d93f8e55SVinod Koul src_module = dst_module; 719d93f8e55SVinod Koul continue; 720d93f8e55SVinod Koul } 721d93f8e55SVinod Koul 722bcc2a2dcSCezary Rojewski ret = skl_bind_modules(skl, src_module, dst_module); 723d93f8e55SVinod Koul if (ret < 0) 724d93f8e55SVinod Koul return ret; 725d93f8e55SVinod Koul 726d93f8e55SVinod Koul src_module = dst_module; 727d93f8e55SVinod Koul } 728d93f8e55SVinod Koul 729b8c722ddSJeeja KP /* 730b8c722ddSJeeja KP * When the destination module is initialized, check for these modules 731b8c722ddSJeeja KP * in deferred bind list. If found, bind them. 732b8c722ddSJeeja KP */ 733b8c722ddSJeeja KP list_for_each_entry(w_module, &s_pipe->w_list, node) { 734b8c722ddSJeeja KP if (list_empty(&skl->bind_list)) 735b8c722ddSJeeja KP break; 736b8c722ddSJeeja KP 737b8c722ddSJeeja KP list_for_each_entry(modules, &skl->bind_list, node) { 738b8c722ddSJeeja KP module = w_module->w->priv; 739b8c722ddSJeeja KP if (modules->dst == module) 740bcc2a2dcSCezary Rojewski skl_bind_modules(skl, modules->src, 741b8c722ddSJeeja KP modules->dst); 742b8c722ddSJeeja KP } 743b8c722ddSJeeja KP } 744b8c722ddSJeeja KP 745d93f8e55SVinod Koul return 0; 746d93f8e55SVinod Koul } 747d93f8e55SVinod Koul 748bcc2a2dcSCezary Rojewski static int skl_fill_sink_instance_id(struct skl_dev *skl, u32 *params, 749bf3e5ef5SDharageswari R int size, struct skl_module_cfg *mcfg) 7505e8f0ee4SDharageswari R { 7515e8f0ee4SDharageswari R int i, pvt_id; 7525e8f0ee4SDharageswari R 753bf3e5ef5SDharageswari R if (mcfg->m_type == SKL_MODULE_TYPE_KPB) { 754bf3e5ef5SDharageswari R struct skl_kpb_params *kpb_params = 755bf3e5ef5SDharageswari R (struct skl_kpb_params *)params; 756f7a9f772SSriram Periyasamy struct skl_mod_inst_map *inst = kpb_params->u.map; 7575e8f0ee4SDharageswari R 758bf3e5ef5SDharageswari R for (i = 0; i < kpb_params->num_modules; i++) { 759bcc2a2dcSCezary Rojewski pvt_id = skl_get_pvt_instance_id_map(skl, inst->mod_id, 760bf3e5ef5SDharageswari R inst->inst_id); 7615e8f0ee4SDharageswari R if (pvt_id < 0) 7625e8f0ee4SDharageswari R return -EINVAL; 763bf3e5ef5SDharageswari R 7645e8f0ee4SDharageswari R inst->inst_id = pvt_id; 7655e8f0ee4SDharageswari R inst++; 7665e8f0ee4SDharageswari R } 7675e8f0ee4SDharageswari R } 7685e8f0ee4SDharageswari R 769bf3e5ef5SDharageswari R return 0; 770bf3e5ef5SDharageswari R } 771cc6a4044SJeeja KP /* 772cc6a4044SJeeja KP * Some modules require params to be set after the module is bound to 773cc6a4044SJeeja KP * all pins connected. 774cc6a4044SJeeja KP * 775cc6a4044SJeeja KP * The module provider initializes set_param flag for such modules and we 776cc6a4044SJeeja KP * send params after binding 777cc6a4044SJeeja KP */ 778cc6a4044SJeeja KP static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, 779bcc2a2dcSCezary Rojewski struct skl_module_cfg *mcfg, struct skl_dev *skl) 780cc6a4044SJeeja KP { 781cc6a4044SJeeja KP int i, ret; 782cc6a4044SJeeja KP struct skl_module_cfg *mconfig = w->priv; 783cc6a4044SJeeja KP const struct snd_kcontrol_new *k; 784cc6a4044SJeeja KP struct soc_bytes_ext *sb; 785cc6a4044SJeeja KP struct skl_algo_data *bc; 786cc6a4044SJeeja KP struct skl_specific_cfg *sp_cfg; 787bf3e5ef5SDharageswari R u32 *params; 788cc6a4044SJeeja KP 789cc6a4044SJeeja KP /* 790cc6a4044SJeeja KP * check all out/in pins are in bind state. 791cc6a4044SJeeja KP * if so set the module param 792cc6a4044SJeeja KP */ 793f6fa56e2SRamesh Babu for (i = 0; i < mcfg->module->max_output_pins; i++) { 794cc6a4044SJeeja KP if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE) 795cc6a4044SJeeja KP return 0; 796cc6a4044SJeeja KP } 797cc6a4044SJeeja KP 798f6fa56e2SRamesh Babu for (i = 0; i < mcfg->module->max_input_pins; i++) { 799cc6a4044SJeeja KP if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE) 800cc6a4044SJeeja KP return 0; 801cc6a4044SJeeja KP } 802cc6a4044SJeeja KP 803*a4ad42d2SKareem Shaik if (mconfig->formats_config[SKL_PARAM_BIND].caps_size > 0 && 804*a4ad42d2SKareem Shaik mconfig->formats_config[SKL_PARAM_BIND].set_params == 805*a4ad42d2SKareem Shaik SKL_PARAM_BIND) { 806*a4ad42d2SKareem Shaik sp_cfg = &mconfig->formats_config[SKL_PARAM_BIND]; 807bcc2a2dcSCezary Rojewski ret = skl_set_module_params(skl, sp_cfg->caps, 808cc6a4044SJeeja KP sp_cfg->caps_size, 809cc6a4044SJeeja KP sp_cfg->param_id, mconfig); 810cc6a4044SJeeja KP if (ret < 0) 811cc6a4044SJeeja KP return ret; 812cc6a4044SJeeja KP } 813cc6a4044SJeeja KP 814cc6a4044SJeeja KP for (i = 0; i < w->num_kcontrols; i++) { 815cc6a4044SJeeja KP k = &w->kcontrol_news[i]; 816cc6a4044SJeeja KP if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 817cc6a4044SJeeja KP sb = (void *) k->private_value; 818cc6a4044SJeeja KP bc = (struct skl_algo_data *)sb->dobj.private; 819cc6a4044SJeeja KP 820cc6a4044SJeeja KP if (bc->set_params == SKL_PARAM_BIND) { 821ca92cc46Szhong jiang params = kmemdup(bc->params, bc->max, GFP_KERNEL); 822bf3e5ef5SDharageswari R if (!params) 823bf3e5ef5SDharageswari R return -ENOMEM; 824bf3e5ef5SDharageswari R 825bcc2a2dcSCezary Rojewski skl_fill_sink_instance_id(skl, params, bc->max, 826bf3e5ef5SDharageswari R mconfig); 827bf3e5ef5SDharageswari R 828bcc2a2dcSCezary Rojewski ret = skl_set_module_params(skl, params, 829bf3e5ef5SDharageswari R bc->max, bc->param_id, mconfig); 830bf3e5ef5SDharageswari R kfree(params); 831bf3e5ef5SDharageswari R 832cc6a4044SJeeja KP if (ret < 0) 833cc6a4044SJeeja KP return ret; 834cc6a4044SJeeja KP } 835cc6a4044SJeeja KP } 836cc6a4044SJeeja KP } 837cc6a4044SJeeja KP 838cc6a4044SJeeja KP return 0; 839cc6a4044SJeeja KP } 840cc6a4044SJeeja KP 841bcc2a2dcSCezary Rojewski static int skl_get_module_id(struct skl_dev *skl, guid_t *uuid) 842f7a9f772SSriram Periyasamy { 843f7a9f772SSriram Periyasamy struct uuid_module *module; 844f7a9f772SSriram Periyasamy 845bcc2a2dcSCezary Rojewski list_for_each_entry(module, &skl->uuid_list, list) { 8469e0784d0SAndy Shevchenko if (guid_equal(uuid, &module->uuid)) 847f7a9f772SSriram Periyasamy return module->id; 848f7a9f772SSriram Periyasamy } 849f7a9f772SSriram Periyasamy 850f7a9f772SSriram Periyasamy return -EINVAL; 851f7a9f772SSriram Periyasamy } 852f7a9f772SSriram Periyasamy 853bcc2a2dcSCezary Rojewski static int skl_tplg_find_moduleid_from_uuid(struct skl_dev *skl, 854f7a9f772SSriram Periyasamy const struct snd_kcontrol_new *k) 855f7a9f772SSriram Periyasamy { 856f7a9f772SSriram Periyasamy struct soc_bytes_ext *sb = (void *) k->private_value; 857f7a9f772SSriram Periyasamy struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private; 858f7a9f772SSriram Periyasamy struct skl_kpb_params *uuid_params, *params; 85976f56faeSRakesh Ughreja struct hdac_bus *bus = skl_to_bus(skl); 860f7a9f772SSriram Periyasamy int i, size, module_id; 861f7a9f772SSriram Periyasamy 862f7a9f772SSriram Periyasamy if (bc->set_params == SKL_PARAM_BIND && bc->max) { 863f7a9f772SSriram Periyasamy uuid_params = (struct skl_kpb_params *)bc->params; 864d00cc2f1SGustavo A. R. Silva size = struct_size(params, u.map, uuid_params->num_modules); 865f7a9f772SSriram Periyasamy 866f7a9f772SSriram Periyasamy params = devm_kzalloc(bus->dev, size, GFP_KERNEL); 867f7a9f772SSriram Periyasamy if (!params) 868f7a9f772SSriram Periyasamy return -ENOMEM; 869f7a9f772SSriram Periyasamy 870f7a9f772SSriram Periyasamy params->num_modules = uuid_params->num_modules; 871f7a9f772SSriram Periyasamy 872f7a9f772SSriram Periyasamy for (i = 0; i < uuid_params->num_modules; i++) { 873bcc2a2dcSCezary Rojewski module_id = skl_get_module_id(skl, 874f7a9f772SSriram Periyasamy &uuid_params->u.map_uuid[i].mod_uuid); 875f7a9f772SSriram Periyasamy if (module_id < 0) { 876f7a9f772SSriram Periyasamy devm_kfree(bus->dev, params); 877f7a9f772SSriram Periyasamy return -EINVAL; 878f7a9f772SSriram Periyasamy } 879f7a9f772SSriram Periyasamy 880f7a9f772SSriram Periyasamy params->u.map[i].mod_id = module_id; 881f7a9f772SSriram Periyasamy params->u.map[i].inst_id = 882f7a9f772SSriram Periyasamy uuid_params->u.map_uuid[i].inst_id; 883f7a9f772SSriram Periyasamy } 884f7a9f772SSriram Periyasamy 885f7a9f772SSriram Periyasamy devm_kfree(bus->dev, bc->params); 886f7a9f772SSriram Periyasamy bc->params = (char *)params; 887f7a9f772SSriram Periyasamy bc->max = size; 888f7a9f772SSriram Periyasamy } 889f7a9f772SSriram Periyasamy 890f7a9f772SSriram Periyasamy return 0; 891f7a9f772SSriram Periyasamy } 892f7a9f772SSriram Periyasamy 893f7a9f772SSriram Periyasamy /* 894f7a9f772SSriram Periyasamy * Retrieve the module id from UUID mentioned in the 895f7a9f772SSriram Periyasamy * post bind params 896f7a9f772SSriram Periyasamy */ 897bcc2a2dcSCezary Rojewski void skl_tplg_add_moduleid_in_bind_params(struct skl_dev *skl, 898f7a9f772SSriram Periyasamy struct snd_soc_dapm_widget *w) 899f7a9f772SSriram Periyasamy { 900f7a9f772SSriram Periyasamy struct skl_module_cfg *mconfig = w->priv; 901f7a9f772SSriram Periyasamy int i; 902f7a9f772SSriram Periyasamy 903f7a9f772SSriram Periyasamy /* 904f7a9f772SSriram Periyasamy * Post bind params are used for only for KPB 905f7a9f772SSriram Periyasamy * to set copier instances to drain the data 906f7a9f772SSriram Periyasamy * in fast mode 907f7a9f772SSriram Periyasamy */ 908f7a9f772SSriram Periyasamy if (mconfig->m_type != SKL_MODULE_TYPE_KPB) 909f7a9f772SSriram Periyasamy return; 910f7a9f772SSriram Periyasamy 911f7a9f772SSriram Periyasamy for (i = 0; i < w->num_kcontrols; i++) 912f7a9f772SSriram Periyasamy if ((w->kcontrol_news[i].access & 913f7a9f772SSriram Periyasamy SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) && 914f7a9f772SSriram Periyasamy (skl_tplg_find_moduleid_from_uuid(skl, 915f7a9f772SSriram Periyasamy &w->kcontrol_news[i]) < 0)) 916bcc2a2dcSCezary Rojewski dev_err(skl->dev, 917f7a9f772SSriram Periyasamy "%s: invalid kpb post bind params\n", 918f7a9f772SSriram Periyasamy __func__); 919f7a9f772SSriram Periyasamy } 920b8c722ddSJeeja KP 921bcc2a2dcSCezary Rojewski static int skl_tplg_module_add_deferred_bind(struct skl_dev *skl, 922b8c722ddSJeeja KP struct skl_module_cfg *src, struct skl_module_cfg *dst) 923b8c722ddSJeeja KP { 924b8c722ddSJeeja KP struct skl_module_deferred_bind *m_list, *modules; 925b8c722ddSJeeja KP int i; 926b8c722ddSJeeja KP 927b8c722ddSJeeja KP /* only supported for module with static pin connection */ 928f6fa56e2SRamesh Babu for (i = 0; i < dst->module->max_input_pins; i++) { 929b8c722ddSJeeja KP struct skl_module_pin *pin = &dst->m_in_pin[i]; 930b8c722ddSJeeja KP 931b8c722ddSJeeja KP if (pin->is_dynamic) 932b8c722ddSJeeja KP continue; 933b8c722ddSJeeja KP 934b8c722ddSJeeja KP if ((pin->id.module_id == src->id.module_id) && 935b8c722ddSJeeja KP (pin->id.instance_id == src->id.instance_id)) { 936b8c722ddSJeeja KP 937b8c722ddSJeeja KP if (!list_empty(&skl->bind_list)) { 938b8c722ddSJeeja KP list_for_each_entry(modules, &skl->bind_list, node) { 939b8c722ddSJeeja KP if (modules->src == src && modules->dst == dst) 940b8c722ddSJeeja KP return 0; 941b8c722ddSJeeja KP } 942b8c722ddSJeeja KP } 943b8c722ddSJeeja KP 944b8c722ddSJeeja KP m_list = kzalloc(sizeof(*m_list), GFP_KERNEL); 945b8c722ddSJeeja KP if (!m_list) 946b8c722ddSJeeja KP return -ENOMEM; 947b8c722ddSJeeja KP 948b8c722ddSJeeja KP m_list->src = src; 949b8c722ddSJeeja KP m_list->dst = dst; 950b8c722ddSJeeja KP 951b8c722ddSJeeja KP list_add(&m_list->node, &skl->bind_list); 952b8c722ddSJeeja KP } 953b8c722ddSJeeja KP } 954b8c722ddSJeeja KP 955b8c722ddSJeeja KP return 0; 956b8c722ddSJeeja KP } 957b8c722ddSJeeja KP 9588724ff17SJeeja KP static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, 959bcc2a2dcSCezary Rojewski struct skl_dev *skl, 9606bd4cf85SJeeja KP struct snd_soc_dapm_widget *src_w, 9618724ff17SJeeja KP struct skl_module_cfg *src_mconfig) 962d93f8e55SVinod Koul { 963d93f8e55SVinod Koul struct snd_soc_dapm_path *p; 9640ed95d76SJeeja KP struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL; 9658724ff17SJeeja KP struct skl_module_cfg *sink_mconfig; 9668724ff17SJeeja KP int ret; 967d93f8e55SVinod Koul 9688724ff17SJeeja KP snd_soc_dapm_widget_for_each_sink_path(w, p) { 969d93f8e55SVinod Koul if (!p->connect) 970d93f8e55SVinod Koul continue; 971d93f8e55SVinod Koul 972bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, 973bcc2a2dcSCezary Rojewski "%s: src widget=%s\n", __func__, w->name); 974bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, 975bcc2a2dcSCezary Rojewski "%s: sink widget=%s\n", __func__, p->sink->name); 976d93f8e55SVinod Koul 9770ed95d76SJeeja KP next_sink = p->sink; 9786bd4cf85SJeeja KP 979bcc2a2dcSCezary Rojewski if (!is_skl_dsp_widget_type(p->sink, skl->dev)) 9806bd4cf85SJeeja KP return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig); 9816bd4cf85SJeeja KP 982d93f8e55SVinod Koul /* 983d93f8e55SVinod Koul * here we will check widgets in sink pipelines, so that 984d93f8e55SVinod Koul * can be any widgets type and we are only interested if 985d93f8e55SVinod Koul * they are ones used for SKL so check that first 986d93f8e55SVinod Koul */ 987d93f8e55SVinod Koul if ((p->sink->priv != NULL) && 988bcc2a2dcSCezary Rojewski is_skl_dsp_widget_type(p->sink, skl->dev)) { 989d93f8e55SVinod Koul 990d93f8e55SVinod Koul sink = p->sink; 991d93f8e55SVinod Koul sink_mconfig = sink->priv; 992d93f8e55SVinod Koul 993b8c722ddSJeeja KP /* 994b8c722ddSJeeja KP * Modules other than PGA leaf can be connected 995b8c722ddSJeeja KP * directly or via switch to a module in another 996b8c722ddSJeeja KP * pipeline. EX: reference path 997b8c722ddSJeeja KP * when the path is enabled, the dst module that needs 998b8c722ddSJeeja KP * to be bound may not be initialized. if the module is 999b8c722ddSJeeja KP * not initialized, add these modules in the deferred 1000b8c722ddSJeeja KP * bind list and when the dst module is initialised, 1001b8c722ddSJeeja KP * bind this module to the dst_module in deferred list. 1002b8c722ddSJeeja KP */ 1003b8c722ddSJeeja KP if (((src_mconfig->m_state == SKL_MODULE_INIT_DONE) 1004b8c722ddSJeeja KP && (sink_mconfig->m_state == SKL_MODULE_UNINIT))) { 1005b8c722ddSJeeja KP 1006b8c722ddSJeeja KP ret = skl_tplg_module_add_deferred_bind(skl, 1007b8c722ddSJeeja KP src_mconfig, sink_mconfig); 1008b8c722ddSJeeja KP 1009b8c722ddSJeeja KP if (ret < 0) 1010b8c722ddSJeeja KP return ret; 1011b8c722ddSJeeja KP 1012b8c722ddSJeeja KP } 1013b8c722ddSJeeja KP 1014b8c722ddSJeeja KP 1015cc6a4044SJeeja KP if (src_mconfig->m_state == SKL_MODULE_UNINIT || 1016cc6a4044SJeeja KP sink_mconfig->m_state == SKL_MODULE_UNINIT) 1017cc6a4044SJeeja KP continue; 1018cc6a4044SJeeja KP 1019d93f8e55SVinod Koul /* Bind source to sink, mixin is always source */ 1020bcc2a2dcSCezary Rojewski ret = skl_bind_modules(skl, src_mconfig, sink_mconfig); 1021d93f8e55SVinod Koul if (ret) 1022d93f8e55SVinod Koul return ret; 1023d93f8e55SVinod Koul 1024cc6a4044SJeeja KP /* set module params after bind */ 1025bcc2a2dcSCezary Rojewski skl_tplg_set_module_bind_params(src_w, 1026bcc2a2dcSCezary Rojewski src_mconfig, skl); 1027bcc2a2dcSCezary Rojewski skl_tplg_set_module_bind_params(sink, 1028bcc2a2dcSCezary Rojewski sink_mconfig, skl); 1029cc6a4044SJeeja KP 1030d93f8e55SVinod Koul /* Start sinks pipe first */ 1031d93f8e55SVinod Koul if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) { 1032d1730c3dSJeeja KP if (sink_mconfig->pipe->conn_type != 1033d1730c3dSJeeja KP SKL_PIPE_CONN_TYPE_FE) 1034bcc2a2dcSCezary Rojewski ret = skl_run_pipe(skl, 1035d1730c3dSJeeja KP sink_mconfig->pipe); 1036d93f8e55SVinod Koul if (ret) 1037d93f8e55SVinod Koul return ret; 1038d93f8e55SVinod Koul } 1039d93f8e55SVinod Koul } 1040d93f8e55SVinod Koul } 1041d93f8e55SVinod Koul 104210a5439fSguneshwor.o.singh@intel.com if (!sink && next_sink) 10436bd4cf85SJeeja KP return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig); 10448724ff17SJeeja KP 10458724ff17SJeeja KP return 0; 10468724ff17SJeeja KP } 10478724ff17SJeeja KP 1048d93f8e55SVinod Koul /* 1049d93f8e55SVinod Koul * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA 1050d93f8e55SVinod Koul * we need to do following: 1051d93f8e55SVinod Koul * - Bind to sink pipeline 1052d93f8e55SVinod Koul * Since the sink pipes can be running and we don't get mixer event on 1053d93f8e55SVinod Koul * connect for already running mixer, we need to find the sink pipes 1054d93f8e55SVinod Koul * here and bind to them. This way dynamic connect works. 1055d93f8e55SVinod Koul * - Start sink pipeline, if not running 1056d93f8e55SVinod Koul * - Then run current pipe 1057d93f8e55SVinod Koul */ 1058d93f8e55SVinod Koul static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, 1059bcc2a2dcSCezary Rojewski struct skl_dev *skl) 1060d93f8e55SVinod Koul { 10618724ff17SJeeja KP struct skl_module_cfg *src_mconfig; 1062d93f8e55SVinod Koul int ret = 0; 1063d93f8e55SVinod Koul 10648724ff17SJeeja KP src_mconfig = w->priv; 1065d93f8e55SVinod Koul 1066d93f8e55SVinod Koul /* 1067d93f8e55SVinod Koul * find which sink it is connected to, bind with the sink, 1068d93f8e55SVinod Koul * if sink is not started, start sink pipe first, then start 1069d93f8e55SVinod Koul * this pipe 1070d93f8e55SVinod Koul */ 10716bd4cf85SJeeja KP ret = skl_tplg_bind_sinks(w, skl, w, src_mconfig); 10728724ff17SJeeja KP if (ret) 10738724ff17SJeeja KP return ret; 10748724ff17SJeeja KP 1075d93f8e55SVinod Koul /* Start source pipe last after starting all sinks */ 1076d1730c3dSJeeja KP if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) 1077bcc2a2dcSCezary Rojewski return skl_run_pipe(skl, src_mconfig->pipe); 1078d93f8e55SVinod Koul 1079d93f8e55SVinod Koul return 0; 1080d93f8e55SVinod Koul } 1081d93f8e55SVinod Koul 10828724ff17SJeeja KP static struct snd_soc_dapm_widget *skl_get_src_dsp_widget( 1083bcc2a2dcSCezary Rojewski struct snd_soc_dapm_widget *w, struct skl_dev *skl) 10848724ff17SJeeja KP { 10858724ff17SJeeja KP struct snd_soc_dapm_path *p; 10868724ff17SJeeja KP struct snd_soc_dapm_widget *src_w = NULL; 10878724ff17SJeeja KP 1088d93f8e55SVinod Koul snd_soc_dapm_widget_for_each_source_path(w, p) { 10898724ff17SJeeja KP src_w = p->source; 1090d93f8e55SVinod Koul if (!p->connect) 1091d93f8e55SVinod Koul continue; 1092d93f8e55SVinod Koul 1093bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "sink widget=%s\n", w->name); 1094bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "src widget=%s\n", p->source->name); 1095d93f8e55SVinod Koul 1096d93f8e55SVinod Koul /* 10978724ff17SJeeja KP * here we will check widgets in sink pipelines, so that can 10988724ff17SJeeja KP * be any widgets type and we are only interested if they are 10998724ff17SJeeja KP * ones used for SKL so check that first 1100d93f8e55SVinod Koul */ 11018724ff17SJeeja KP if ((p->source->priv != NULL) && 1102bcc2a2dcSCezary Rojewski is_skl_dsp_widget_type(p->source, skl->dev)) { 11038724ff17SJeeja KP return p->source; 1104d93f8e55SVinod Koul } 1105d93f8e55SVinod Koul } 1106d93f8e55SVinod Koul 11078724ff17SJeeja KP if (src_w != NULL) 11088724ff17SJeeja KP return skl_get_src_dsp_widget(src_w, skl); 1109d93f8e55SVinod Koul 11108724ff17SJeeja KP return NULL; 1111d93f8e55SVinod Koul } 1112d93f8e55SVinod Koul 1113d93f8e55SVinod Koul /* 1114d93f8e55SVinod Koul * in the Post-PMU event of mixer we need to do following: 1115d93f8e55SVinod Koul * - Check if this pipe is running 1116d93f8e55SVinod Koul * - if not, then 1117d93f8e55SVinod Koul * - bind this pipeline to its source pipeline 1118d93f8e55SVinod Koul * if source pipe is already running, this means it is a dynamic 1119d93f8e55SVinod Koul * connection and we need to bind only to that pipe 1120d93f8e55SVinod Koul * - start this pipeline 1121d93f8e55SVinod Koul */ 1122d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, 1123bcc2a2dcSCezary Rojewski struct skl_dev *skl) 1124d93f8e55SVinod Koul { 1125d93f8e55SVinod Koul int ret = 0; 1126d93f8e55SVinod Koul struct snd_soc_dapm_widget *source, *sink; 1127d93f8e55SVinod Koul struct skl_module_cfg *src_mconfig, *sink_mconfig; 1128d93f8e55SVinod Koul int src_pipe_started = 0; 1129d93f8e55SVinod Koul 1130d93f8e55SVinod Koul sink = w; 1131d93f8e55SVinod Koul sink_mconfig = sink->priv; 1132d93f8e55SVinod Koul 1133d93f8e55SVinod Koul /* 1134d93f8e55SVinod Koul * If source pipe is already started, that means source is driving 1135d93f8e55SVinod Koul * one more sink before this sink got connected, Since source is 1136d93f8e55SVinod Koul * started, bind this sink to source and start this pipe. 1137d93f8e55SVinod Koul */ 11388724ff17SJeeja KP source = skl_get_src_dsp_widget(w, skl); 11398724ff17SJeeja KP if (source != NULL) { 1140d93f8e55SVinod Koul src_mconfig = source->priv; 1141d93f8e55SVinod Koul sink_mconfig = sink->priv; 1142d93f8e55SVinod Koul src_pipe_started = 1; 1143d93f8e55SVinod Koul 1144d93f8e55SVinod Koul /* 11458724ff17SJeeja KP * check pipe state, then no need to bind or start the 11468724ff17SJeeja KP * pipe 1147d93f8e55SVinod Koul */ 1148d93f8e55SVinod Koul if (src_mconfig->pipe->state != SKL_PIPE_STARTED) 1149d93f8e55SVinod Koul src_pipe_started = 0; 1150d93f8e55SVinod Koul } 1151d93f8e55SVinod Koul 1152d93f8e55SVinod Koul if (src_pipe_started) { 1153bcc2a2dcSCezary Rojewski ret = skl_bind_modules(skl, src_mconfig, sink_mconfig); 1154d93f8e55SVinod Koul if (ret) 1155d93f8e55SVinod Koul return ret; 1156d93f8e55SVinod Koul 1157cc6a4044SJeeja KP /* set module params after bind */ 1158bcc2a2dcSCezary Rojewski skl_tplg_set_module_bind_params(source, src_mconfig, skl); 1159bcc2a2dcSCezary Rojewski skl_tplg_set_module_bind_params(sink, sink_mconfig, skl); 1160cc6a4044SJeeja KP 1161d1730c3dSJeeja KP if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) 1162bcc2a2dcSCezary Rojewski ret = skl_run_pipe(skl, sink_mconfig->pipe); 1163d93f8e55SVinod Koul } 1164d93f8e55SVinod Koul 1165d93f8e55SVinod Koul return ret; 1166d93f8e55SVinod Koul } 1167d93f8e55SVinod Koul 1168d93f8e55SVinod Koul /* 1169d93f8e55SVinod Koul * in the Pre-PMD event of mixer we need to do following: 1170d93f8e55SVinod Koul * - Stop the pipe 1171d93f8e55SVinod Koul * - find the source connections and remove that from dapm_path_list 1172d93f8e55SVinod Koul * - unbind with source pipelines if still connected 1173d93f8e55SVinod Koul */ 1174d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w, 1175bcc2a2dcSCezary Rojewski struct skl_dev *skl) 1176d93f8e55SVinod Koul { 1177d93f8e55SVinod Koul struct skl_module_cfg *src_mconfig, *sink_mconfig; 1178ce1b5551SJeeja KP int ret = 0, i; 1179d93f8e55SVinod Koul 1180ce1b5551SJeeja KP sink_mconfig = w->priv; 1181d93f8e55SVinod Koul 1182d93f8e55SVinod Koul /* Stop the pipe */ 1183bcc2a2dcSCezary Rojewski ret = skl_stop_pipe(skl, sink_mconfig->pipe); 1184d93f8e55SVinod Koul if (ret) 1185d93f8e55SVinod Koul return ret; 1186d93f8e55SVinod Koul 1187f6fa56e2SRamesh Babu for (i = 0; i < sink_mconfig->module->max_input_pins; i++) { 1188ce1b5551SJeeja KP if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) { 1189ce1b5551SJeeja KP src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg; 1190ce1b5551SJeeja KP if (!src_mconfig) 1191ce1b5551SJeeja KP continue; 1192d93f8e55SVinod Koul 1193bcc2a2dcSCezary Rojewski ret = skl_unbind_modules(skl, 1194ce1b5551SJeeja KP src_mconfig, sink_mconfig); 1195ce1b5551SJeeja KP } 1196d93f8e55SVinod Koul } 1197d93f8e55SVinod Koul 1198d93f8e55SVinod Koul return ret; 1199d93f8e55SVinod Koul } 1200d93f8e55SVinod Koul 1201d93f8e55SVinod Koul /* 1202d93f8e55SVinod Koul * in the Post-PMD event of mixer we need to do following: 1203d93f8e55SVinod Koul * - Unbind the modules within the pipeline 1204d93f8e55SVinod Koul * - Delete the pipeline (modules are not required to be explicitly 1205d93f8e55SVinod Koul * deleted, pipeline delete is enough here 1206d93f8e55SVinod Koul */ 1207d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, 1208bcc2a2dcSCezary Rojewski struct skl_dev *skl) 1209d93f8e55SVinod Koul { 1210d93f8e55SVinod Koul struct skl_module_cfg *mconfig = w->priv; 1211d93f8e55SVinod Koul struct skl_pipe_module *w_module; 1212d93f8e55SVinod Koul struct skl_module_cfg *src_module = NULL, *dst_module; 1213d93f8e55SVinod Koul struct skl_pipe *s_pipe = mconfig->pipe; 1214550b349aSDan Carpenter struct skl_module_deferred_bind *modules, *tmp; 1215d93f8e55SVinod Koul 1216260eb73aSDharageswari R if (s_pipe->state == SKL_PIPE_INVALID) 1217260eb73aSDharageswari R return -EINVAL; 1218260eb73aSDharageswari R 1219d93f8e55SVinod Koul list_for_each_entry(w_module, &s_pipe->w_list, node) { 1220b8c722ddSJeeja KP if (list_empty(&skl->bind_list)) 1221b8c722ddSJeeja KP break; 1222b8c722ddSJeeja KP 1223b8c722ddSJeeja KP src_module = w_module->w->priv; 1224b8c722ddSJeeja KP 1225550b349aSDan Carpenter list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) { 1226b8c722ddSJeeja KP /* 1227b8c722ddSJeeja KP * When the destination module is deleted, Unbind the 1228b8c722ddSJeeja KP * modules from deferred bind list. 1229b8c722ddSJeeja KP */ 1230b8c722ddSJeeja KP if (modules->dst == src_module) { 1231bcc2a2dcSCezary Rojewski skl_unbind_modules(skl, modules->src, 1232b8c722ddSJeeja KP modules->dst); 1233b8c722ddSJeeja KP } 1234b8c722ddSJeeja KP 1235b8c722ddSJeeja KP /* 1236b8c722ddSJeeja KP * When the source module is deleted, remove this entry 1237b8c722ddSJeeja KP * from the deferred bind list. 1238b8c722ddSJeeja KP */ 1239b8c722ddSJeeja KP if (modules->src == src_module) { 1240b8c722ddSJeeja KP list_del(&modules->node); 1241b8c722ddSJeeja KP modules->src = NULL; 1242b8c722ddSJeeja KP modules->dst = NULL; 1243b8c722ddSJeeja KP kfree(modules); 1244b8c722ddSJeeja KP } 1245b8c722ddSJeeja KP } 1246b8c722ddSJeeja KP } 1247b8c722ddSJeeja KP 1248b8c722ddSJeeja KP list_for_each_entry(w_module, &s_pipe->w_list, node) { 1249d93f8e55SVinod Koul dst_module = w_module->w->priv; 1250d93f8e55SVinod Koul 1251d93f8e55SVinod Koul if (src_module == NULL) { 1252d93f8e55SVinod Koul src_module = dst_module; 1253d93f8e55SVinod Koul continue; 1254d93f8e55SVinod Koul } 1255d93f8e55SVinod Koul 1256bcc2a2dcSCezary Rojewski skl_unbind_modules(skl, src_module, dst_module); 1257d93f8e55SVinod Koul src_module = dst_module; 1258d93f8e55SVinod Koul } 1259d93f8e55SVinod Koul 1260bcc2a2dcSCezary Rojewski skl_delete_pipe(skl, mconfig->pipe); 1261d93f8e55SVinod Koul 1262473a4d51SJeeja KP list_for_each_entry(w_module, &s_pipe->w_list, node) { 1263473a4d51SJeeja KP src_module = w_module->w->priv; 1264473a4d51SJeeja KP src_module->m_state = SKL_MODULE_UNINIT; 1265473a4d51SJeeja KP } 1266473a4d51SJeeja KP 1267bcc2a2dcSCezary Rojewski return skl_tplg_unload_pipe_modules(skl, s_pipe); 1268d93f8e55SVinod Koul } 1269d93f8e55SVinod Koul 1270d93f8e55SVinod Koul /* 1271d93f8e55SVinod Koul * in the Post-PMD event of PGA we need to do following: 1272d93f8e55SVinod Koul * - Stop the pipeline 1273d93f8e55SVinod Koul * - In source pipe is connected, unbind with source pipelines 1274d93f8e55SVinod Koul */ 1275d93f8e55SVinod Koul static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, 1276bcc2a2dcSCezary Rojewski struct skl_dev *skl) 1277d93f8e55SVinod Koul { 1278d93f8e55SVinod Koul struct skl_module_cfg *src_mconfig, *sink_mconfig; 1279ce1b5551SJeeja KP int ret = 0, i; 1280d93f8e55SVinod Koul 1281ce1b5551SJeeja KP src_mconfig = w->priv; 1282d93f8e55SVinod Koul 1283d93f8e55SVinod Koul /* Stop the pipe since this is a mixin module */ 1284bcc2a2dcSCezary Rojewski ret = skl_stop_pipe(skl, src_mconfig->pipe); 1285d93f8e55SVinod Koul if (ret) 1286d93f8e55SVinod Koul return ret; 1287d93f8e55SVinod Koul 1288f6fa56e2SRamesh Babu for (i = 0; i < src_mconfig->module->max_output_pins; i++) { 1289ce1b5551SJeeja KP if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) { 1290ce1b5551SJeeja KP sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg; 1291ce1b5551SJeeja KP if (!sink_mconfig) 1292ce1b5551SJeeja KP continue; 1293d93f8e55SVinod Koul /* 1294ce1b5551SJeeja KP * This is a connecter and if path is found that means 1295d93f8e55SVinod Koul * unbind between source and sink has not happened yet 1296d93f8e55SVinod Koul */ 1297bcc2a2dcSCezary Rojewski ret = skl_unbind_modules(skl, src_mconfig, 1298ce1b5551SJeeja KP sink_mconfig); 1299ce1b5551SJeeja KP } 1300d93f8e55SVinod Koul } 1301d93f8e55SVinod Koul 1302d93f8e55SVinod Koul return ret; 1303d93f8e55SVinod Koul } 1304d93f8e55SVinod Koul 1305d93f8e55SVinod Koul /* 1306d93f8e55SVinod Koul * In modelling, we assume there will be ONLY one mixer in a pipeline. If a 1307d93f8e55SVinod Koul * second one is required that is created as another pipe entity. 1308d93f8e55SVinod Koul * The mixer is responsible for pipe management and represent a pipeline 1309d93f8e55SVinod Koul * instance 1310d93f8e55SVinod Koul */ 1311d93f8e55SVinod Koul static int skl_tplg_mixer_event(struct snd_soc_dapm_widget *w, 1312d93f8e55SVinod Koul struct snd_kcontrol *k, int event) 1313d93f8e55SVinod Koul { 1314d93f8e55SVinod Koul struct snd_soc_dapm_context *dapm = w->dapm; 1315bcc2a2dcSCezary Rojewski struct skl_dev *skl = get_skl_ctx(dapm->dev); 1316d93f8e55SVinod Koul 1317d93f8e55SVinod Koul switch (event) { 1318d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMU: 1319d93f8e55SVinod Koul return skl_tplg_mixer_dapm_pre_pmu_event(w, skl); 1320d93f8e55SVinod Koul 1321d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMU: 1322d93f8e55SVinod Koul return skl_tplg_mixer_dapm_post_pmu_event(w, skl); 1323d93f8e55SVinod Koul 1324d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMD: 1325d93f8e55SVinod Koul return skl_tplg_mixer_dapm_pre_pmd_event(w, skl); 1326d93f8e55SVinod Koul 1327d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMD: 1328d93f8e55SVinod Koul return skl_tplg_mixer_dapm_post_pmd_event(w, skl); 1329d93f8e55SVinod Koul } 1330d93f8e55SVinod Koul 1331d93f8e55SVinod Koul return 0; 1332d93f8e55SVinod Koul } 1333d93f8e55SVinod Koul 1334d93f8e55SVinod Koul /* 1335d93f8e55SVinod Koul * In modelling, we assumed rest of the modules in pipeline are PGA. But we 1336d93f8e55SVinod Koul * are interested in last PGA (leaf PGA) in a pipeline to disconnect with 1337d93f8e55SVinod Koul * the sink when it is running (two FE to one BE or one FE to two BE) 1338d93f8e55SVinod Koul * scenarios 1339d93f8e55SVinod Koul */ 1340d93f8e55SVinod Koul static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w, 1341d93f8e55SVinod Koul struct snd_kcontrol *k, int event) 1342d93f8e55SVinod Koul 1343d93f8e55SVinod Koul { 1344d93f8e55SVinod Koul struct snd_soc_dapm_context *dapm = w->dapm; 1345bcc2a2dcSCezary Rojewski struct skl_dev *skl = get_skl_ctx(dapm->dev); 1346d93f8e55SVinod Koul 1347d93f8e55SVinod Koul switch (event) { 1348d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMU: 1349d93f8e55SVinod Koul return skl_tplg_pga_dapm_pre_pmu_event(w, skl); 1350d93f8e55SVinod Koul 1351d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMD: 1352d93f8e55SVinod Koul return skl_tplg_pga_dapm_post_pmd_event(w, skl); 1353d93f8e55SVinod Koul } 1354d93f8e55SVinod Koul 1355d93f8e55SVinod Koul return 0; 1356d93f8e55SVinod Koul } 1357cfb0a873SVinod Koul 13581b450791SMateusz Gorski static int skl_tplg_multi_config_set_get(struct snd_kcontrol *kcontrol, 13591b450791SMateusz Gorski struct snd_ctl_elem_value *ucontrol, 13601b450791SMateusz Gorski bool is_set) 13611b450791SMateusz Gorski { 13621b450791SMateusz Gorski struct snd_soc_component *component = 13631b450791SMateusz Gorski snd_soc_kcontrol_component(kcontrol); 13641b450791SMateusz Gorski struct hdac_bus *bus = snd_soc_component_get_drvdata(component); 13651b450791SMateusz Gorski struct skl_dev *skl = bus_to_skl(bus); 13661b450791SMateusz Gorski struct skl_pipeline *ppl; 13671b450791SMateusz Gorski struct skl_pipe *pipe = NULL; 13681b450791SMateusz Gorski struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value; 13691b450791SMateusz Gorski u32 *pipe_id; 13701b450791SMateusz Gorski 13711b450791SMateusz Gorski if (!ec) 13721b450791SMateusz Gorski return -EINVAL; 13731b450791SMateusz Gorski 13741b450791SMateusz Gorski if (is_set && ucontrol->value.enumerated.item[0] > ec->items) 13751b450791SMateusz Gorski return -EINVAL; 13761b450791SMateusz Gorski 13771b450791SMateusz Gorski pipe_id = ec->dobj.private; 13781b450791SMateusz Gorski 13791b450791SMateusz Gorski list_for_each_entry(ppl, &skl->ppl_list, node) { 13801b450791SMateusz Gorski if (ppl->pipe->ppl_id == *pipe_id) { 13811b450791SMateusz Gorski pipe = ppl->pipe; 13821b450791SMateusz Gorski break; 13831b450791SMateusz Gorski } 13841b450791SMateusz Gorski } 13851b450791SMateusz Gorski if (!pipe) 13861b450791SMateusz Gorski return -EIO; 13871b450791SMateusz Gorski 13881b450791SMateusz Gorski if (is_set) 13891b450791SMateusz Gorski pipe->pipe_config_idx = ucontrol->value.enumerated.item[0]; 13901b450791SMateusz Gorski else 13911b450791SMateusz Gorski ucontrol->value.enumerated.item[0] = pipe->pipe_config_idx; 13921b450791SMateusz Gorski 13931b450791SMateusz Gorski return 0; 13941b450791SMateusz Gorski } 13951b450791SMateusz Gorski 13961b450791SMateusz Gorski static int skl_tplg_multi_config_get(struct snd_kcontrol *kcontrol, 13971b450791SMateusz Gorski struct snd_ctl_elem_value *ucontrol) 13981b450791SMateusz Gorski { 13991b450791SMateusz Gorski return skl_tplg_multi_config_set_get(kcontrol, ucontrol, false); 14001b450791SMateusz Gorski } 14011b450791SMateusz Gorski 14021b450791SMateusz Gorski static int skl_tplg_multi_config_set(struct snd_kcontrol *kcontrol, 14031b450791SMateusz Gorski struct snd_ctl_elem_value *ucontrol) 14041b450791SMateusz Gorski { 14051b450791SMateusz Gorski return skl_tplg_multi_config_set_get(kcontrol, ucontrol, true); 14061b450791SMateusz Gorski } 14071b450791SMateusz Gorski 14082d744ecfSMateusz Gorski static int skl_tplg_multi_config_get_dmic(struct snd_kcontrol *kcontrol, 14092d744ecfSMateusz Gorski struct snd_ctl_elem_value *ucontrol) 14102d744ecfSMateusz Gorski { 14112d744ecfSMateusz Gorski return skl_tplg_multi_config_set_get(kcontrol, ucontrol, false); 14122d744ecfSMateusz Gorski } 14132d744ecfSMateusz Gorski 14142d744ecfSMateusz Gorski static int skl_tplg_multi_config_set_dmic(struct snd_kcontrol *kcontrol, 14152d744ecfSMateusz Gorski struct snd_ctl_elem_value *ucontrol) 14162d744ecfSMateusz Gorski { 14172d744ecfSMateusz Gorski return skl_tplg_multi_config_set_get(kcontrol, ucontrol, true); 14182d744ecfSMateusz Gorski } 14192d744ecfSMateusz Gorski 1420140adfbaSJeeja KP static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol, 1421140adfbaSJeeja KP unsigned int __user *data, unsigned int size) 1422140adfbaSJeeja KP { 1423140adfbaSJeeja KP struct soc_bytes_ext *sb = 1424140adfbaSJeeja KP (struct soc_bytes_ext *)kcontrol->private_value; 1425140adfbaSJeeja KP struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private; 14267d9f2911SOmair M Abdullah struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); 14277d9f2911SOmair M Abdullah struct skl_module_cfg *mconfig = w->priv; 1428bcc2a2dcSCezary Rojewski struct skl_dev *skl = get_skl_ctx(w->dapm->dev); 14297d9f2911SOmair M Abdullah 14307d9f2911SOmair M Abdullah if (w->power) 1431bcc2a2dcSCezary Rojewski skl_get_module_params(skl, (u32 *)bc->params, 14320d682104SDharageswari R bc->size, bc->param_id, mconfig); 1433140adfbaSJeeja KP 143441556f68SVinod Koul /* decrement size for TLV header */ 143541556f68SVinod Koul size -= 2 * sizeof(u32); 143641556f68SVinod Koul 143741556f68SVinod Koul /* check size as we don't want to send kernel data */ 143841556f68SVinod Koul if (size > bc->max) 143941556f68SVinod Koul size = bc->max; 144041556f68SVinod Koul 1441140adfbaSJeeja KP if (bc->params) { 1442140adfbaSJeeja KP if (copy_to_user(data, &bc->param_id, sizeof(u32))) 1443140adfbaSJeeja KP return -EFAULT; 1444e8bc3c99SDan Carpenter if (copy_to_user(data + 1, &size, sizeof(u32))) 1445140adfbaSJeeja KP return -EFAULT; 1446e8bc3c99SDan Carpenter if (copy_to_user(data + 2, bc->params, size)) 1447140adfbaSJeeja KP return -EFAULT; 1448140adfbaSJeeja KP } 1449140adfbaSJeeja KP 1450140adfbaSJeeja KP return 0; 1451140adfbaSJeeja KP } 1452140adfbaSJeeja KP 1453140adfbaSJeeja KP #define SKL_PARAM_VENDOR_ID 0xff 1454140adfbaSJeeja KP 1455140adfbaSJeeja KP static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol, 1456140adfbaSJeeja KP const unsigned int __user *data, unsigned int size) 1457140adfbaSJeeja KP { 1458140adfbaSJeeja KP struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); 1459140adfbaSJeeja KP struct skl_module_cfg *mconfig = w->priv; 1460140adfbaSJeeja KP struct soc_bytes_ext *sb = 1461140adfbaSJeeja KP (struct soc_bytes_ext *)kcontrol->private_value; 1462140adfbaSJeeja KP struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private; 1463bcc2a2dcSCezary Rojewski struct skl_dev *skl = get_skl_ctx(w->dapm->dev); 1464140adfbaSJeeja KP 1465140adfbaSJeeja KP if (ac->params) { 14660d682104SDharageswari R if (size > ac->max) 14670d682104SDharageswari R return -EINVAL; 14680d682104SDharageswari R ac->size = size; 1469a8cd7066SKamil Lulko 1470140adfbaSJeeja KP if (copy_from_user(ac->params, data, size)) 1471140adfbaSJeeja KP return -EFAULT; 1472140adfbaSJeeja KP 1473140adfbaSJeeja KP if (w->power) 1474bcc2a2dcSCezary Rojewski return skl_set_module_params(skl, 14750d682104SDharageswari R (u32 *)ac->params, ac->size, 1476140adfbaSJeeja KP ac->param_id, mconfig); 1477140adfbaSJeeja KP } 1478140adfbaSJeeja KP 1479140adfbaSJeeja KP return 0; 1480140adfbaSJeeja KP } 1481140adfbaSJeeja KP 14827a1b749bSDharageswari R static int skl_tplg_mic_control_get(struct snd_kcontrol *kcontrol, 14837a1b749bSDharageswari R struct snd_ctl_elem_value *ucontrol) 14847a1b749bSDharageswari R { 14857a1b749bSDharageswari R struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); 14867a1b749bSDharageswari R struct skl_module_cfg *mconfig = w->priv; 14877a1b749bSDharageswari R struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value; 14887a1b749bSDharageswari R u32 ch_type = *((u32 *)ec->dobj.private); 14897a1b749bSDharageswari R 14907a1b749bSDharageswari R if (mconfig->dmic_ch_type == ch_type) 14917a1b749bSDharageswari R ucontrol->value.enumerated.item[0] = 14927a1b749bSDharageswari R mconfig->dmic_ch_combo_index; 14937a1b749bSDharageswari R else 14947a1b749bSDharageswari R ucontrol->value.enumerated.item[0] = 0; 14957a1b749bSDharageswari R 14967a1b749bSDharageswari R return 0; 14977a1b749bSDharageswari R } 14987a1b749bSDharageswari R 14997a1b749bSDharageswari R static int skl_fill_mic_sel_params(struct skl_module_cfg *mconfig, 15007a1b749bSDharageswari R struct skl_mic_sel_config *mic_cfg, struct device *dev) 15017a1b749bSDharageswari R { 1502*a4ad42d2SKareem Shaik struct skl_specific_cfg *sp_cfg = 1503*a4ad42d2SKareem Shaik &mconfig->formats_config[SKL_PARAM_INIT]; 15047a1b749bSDharageswari R 15057a1b749bSDharageswari R sp_cfg->caps_size = sizeof(struct skl_mic_sel_config); 15067a1b749bSDharageswari R sp_cfg->set_params = SKL_PARAM_SET; 15077a1b749bSDharageswari R sp_cfg->param_id = 0x00; 15087a1b749bSDharageswari R if (!sp_cfg->caps) { 15097a1b749bSDharageswari R sp_cfg->caps = devm_kzalloc(dev, sp_cfg->caps_size, GFP_KERNEL); 15107a1b749bSDharageswari R if (!sp_cfg->caps) 15117a1b749bSDharageswari R return -ENOMEM; 15127a1b749bSDharageswari R } 15137a1b749bSDharageswari R 15147a1b749bSDharageswari R mic_cfg->mic_switch = SKL_MIC_SEL_SWITCH; 15157a1b749bSDharageswari R mic_cfg->flags = 0; 15167a1b749bSDharageswari R memcpy(sp_cfg->caps, mic_cfg, sp_cfg->caps_size); 15177a1b749bSDharageswari R 15187a1b749bSDharageswari R return 0; 15197a1b749bSDharageswari R } 15207a1b749bSDharageswari R 15217a1b749bSDharageswari R static int skl_tplg_mic_control_set(struct snd_kcontrol *kcontrol, 15227a1b749bSDharageswari R struct snd_ctl_elem_value *ucontrol) 15237a1b749bSDharageswari R { 15247a1b749bSDharageswari R struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); 15257a1b749bSDharageswari R struct skl_module_cfg *mconfig = w->priv; 15267a1b749bSDharageswari R struct skl_mic_sel_config mic_cfg = {0}; 15277a1b749bSDharageswari R struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value; 15287a1b749bSDharageswari R u32 ch_type = *((u32 *)ec->dobj.private); 15297a1b749bSDharageswari R const int *list; 15307a1b749bSDharageswari R u8 in_ch, out_ch, index; 15317a1b749bSDharageswari R 15327a1b749bSDharageswari R mconfig->dmic_ch_type = ch_type; 15337a1b749bSDharageswari R mconfig->dmic_ch_combo_index = ucontrol->value.enumerated.item[0]; 15347a1b749bSDharageswari R 15357a1b749bSDharageswari R /* enum control index 0 is INVALID, so no channels to be set */ 15367a1b749bSDharageswari R if (mconfig->dmic_ch_combo_index == 0) 15377a1b749bSDharageswari R return 0; 15387a1b749bSDharageswari R 15397a1b749bSDharageswari R /* No valid channel selection map for index 0, so offset by 1 */ 15407a1b749bSDharageswari R index = mconfig->dmic_ch_combo_index - 1; 15417a1b749bSDharageswari R 15427a1b749bSDharageswari R switch (ch_type) { 15437a1b749bSDharageswari R case SKL_CH_MONO: 15447a1b749bSDharageswari R if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_mono_list)) 15457a1b749bSDharageswari R return -EINVAL; 15467a1b749bSDharageswari R 15477a1b749bSDharageswari R list = &mic_mono_list[index]; 15487a1b749bSDharageswari R break; 15497a1b749bSDharageswari R 15507a1b749bSDharageswari R case SKL_CH_STEREO: 15517a1b749bSDharageswari R if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_stereo_list)) 15527a1b749bSDharageswari R return -EINVAL; 15537a1b749bSDharageswari R 15547a1b749bSDharageswari R list = mic_stereo_list[index]; 15557a1b749bSDharageswari R break; 15567a1b749bSDharageswari R 15577a1b749bSDharageswari R case SKL_CH_TRIO: 15587a1b749bSDharageswari R if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_trio_list)) 15597a1b749bSDharageswari R return -EINVAL; 15607a1b749bSDharageswari R 15617a1b749bSDharageswari R list = mic_trio_list[index]; 15627a1b749bSDharageswari R break; 15637a1b749bSDharageswari R 15647a1b749bSDharageswari R case SKL_CH_QUATRO: 15657a1b749bSDharageswari R if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_quatro_list)) 15667a1b749bSDharageswari R return -EINVAL; 15677a1b749bSDharageswari R 15687a1b749bSDharageswari R list = mic_quatro_list[index]; 15697a1b749bSDharageswari R break; 15707a1b749bSDharageswari R 15717a1b749bSDharageswari R default: 15727a1b749bSDharageswari R dev_err(w->dapm->dev, 15737a1b749bSDharageswari R "Invalid channel %d for mic_select module\n", 15747a1b749bSDharageswari R ch_type); 15757a1b749bSDharageswari R return -EINVAL; 15767a1b749bSDharageswari R 15777a1b749bSDharageswari R } 15787a1b749bSDharageswari R 15797a1b749bSDharageswari R /* channel type enum map to number of chanels for that type */ 15807a1b749bSDharageswari R for (out_ch = 0; out_ch < ch_type; out_ch++) { 15817a1b749bSDharageswari R in_ch = list[out_ch]; 15827a1b749bSDharageswari R mic_cfg.blob[out_ch][in_ch] = SKL_DEFAULT_MIC_SEL_GAIN; 15837a1b749bSDharageswari R } 15847a1b749bSDharageswari R 15857a1b749bSDharageswari R return skl_fill_mic_sel_params(mconfig, &mic_cfg, w->dapm->dev); 15867a1b749bSDharageswari R } 15877a1b749bSDharageswari R 1588cfb0a873SVinod Koul /* 15898871dcb9SJeeja KP * Fill the dma id for host and link. In case of passthrough 15908871dcb9SJeeja KP * pipeline, this will both host and link in the same 15918871dcb9SJeeja KP * pipeline, so need to copy the link and host based on dev_type 15928871dcb9SJeeja KP */ 15938871dcb9SJeeja KP static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg, 15948871dcb9SJeeja KP struct skl_pipe_params *params) 15958871dcb9SJeeja KP { 15968871dcb9SJeeja KP struct skl_pipe *pipe = mcfg->pipe; 15978871dcb9SJeeja KP 15988871dcb9SJeeja KP if (pipe->passthru) { 15998871dcb9SJeeja KP switch (mcfg->dev_type) { 16008871dcb9SJeeja KP case SKL_DEVICE_HDALINK: 16018871dcb9SJeeja KP pipe->p_params->link_dma_id = params->link_dma_id; 160212c3be0eSJeeja KP pipe->p_params->link_index = params->link_index; 16037f975a38SJeeja KP pipe->p_params->link_bps = params->link_bps; 16048871dcb9SJeeja KP break; 16058871dcb9SJeeja KP 16068871dcb9SJeeja KP case SKL_DEVICE_HDAHOST: 16078871dcb9SJeeja KP pipe->p_params->host_dma_id = params->host_dma_id; 16087f975a38SJeeja KP pipe->p_params->host_bps = params->host_bps; 16098871dcb9SJeeja KP break; 16108871dcb9SJeeja KP 16118871dcb9SJeeja KP default: 16128871dcb9SJeeja KP break; 16138871dcb9SJeeja KP } 16148871dcb9SJeeja KP pipe->p_params->s_fmt = params->s_fmt; 16158871dcb9SJeeja KP pipe->p_params->ch = params->ch; 16168871dcb9SJeeja KP pipe->p_params->s_freq = params->s_freq; 16178871dcb9SJeeja KP pipe->p_params->stream = params->stream; 161812c3be0eSJeeja KP pipe->p_params->format = params->format; 16198871dcb9SJeeja KP 16208871dcb9SJeeja KP } else { 16218871dcb9SJeeja KP memcpy(pipe->p_params, params, sizeof(*params)); 16228871dcb9SJeeja KP } 16238871dcb9SJeeja KP } 16248871dcb9SJeeja KP 16258871dcb9SJeeja KP /* 1626cfb0a873SVinod Koul * The FE params are passed by hw_params of the DAI. 1627cfb0a873SVinod Koul * On hw_params, the params are stored in Gateway module of the FE and we 1628cfb0a873SVinod Koul * need to calculate the format in DSP module configuration, that 1629cfb0a873SVinod Koul * conversion is done here 1630cfb0a873SVinod Koul */ 1631cfb0a873SVinod Koul int skl_tplg_update_pipe_params(struct device *dev, 1632cfb0a873SVinod Koul struct skl_module_cfg *mconfig, 1633cfb0a873SVinod Koul struct skl_pipe_params *params) 1634cfb0a873SVinod Koul { 1635e8b374b6SCezary Rojewski struct skl_module_res *res; 1636bcc2a2dcSCezary Rojewski struct skl_dev *skl = get_skl_ctx(dev); 1637cfb0a873SVinod Koul struct skl_module_fmt *format = NULL; 1638f6fa56e2SRamesh Babu u8 cfg_idx = mconfig->pipe->cur_config_idx; 1639cfb0a873SVinod Koul 1640e8b374b6SCezary Rojewski res = &mconfig->module->resources[mconfig->res_idx]; 16418871dcb9SJeeja KP skl_tplg_fill_dma_id(mconfig, params); 1642f6fa56e2SRamesh Babu mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx; 1643f6fa56e2SRamesh Babu mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx; 1644f6fa56e2SRamesh Babu 1645f6fa56e2SRamesh Babu if (skl->nr_modules) 1646f6fa56e2SRamesh Babu return 0; 1647cfb0a873SVinod Koul 1648cfb0a873SVinod Koul if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) 1649e8b374b6SCezary Rojewski format = &mconfig->module->formats[mconfig->fmt_idx].inputs[0].fmt; 1650cfb0a873SVinod Koul else 1651e8b374b6SCezary Rojewski format = &mconfig->module->formats[mconfig->fmt_idx].outputs[0].fmt; 1652cfb0a873SVinod Koul 1653cfb0a873SVinod Koul /* set the hw_params */ 1654cfb0a873SVinod Koul format->s_freq = params->s_freq; 1655cfb0a873SVinod Koul format->channels = params->ch; 1656cfb0a873SVinod Koul format->valid_bit_depth = skl_get_bit_depth(params->s_fmt); 1657cfb0a873SVinod Koul 1658cfb0a873SVinod Koul /* 1659cfb0a873SVinod Koul * 16 bit is 16 bit container whereas 24 bit is in 32 bit 1660cfb0a873SVinod Koul * container so update bit depth accordingly 1661cfb0a873SVinod Koul */ 1662cfb0a873SVinod Koul switch (format->valid_bit_depth) { 1663cfb0a873SVinod Koul case SKL_DEPTH_16BIT: 1664cfb0a873SVinod Koul format->bit_depth = format->valid_bit_depth; 1665cfb0a873SVinod Koul break; 1666cfb0a873SVinod Koul 1667cfb0a873SVinod Koul case SKL_DEPTH_24BIT: 16686654f39eSJeeja KP case SKL_DEPTH_32BIT: 1669cfb0a873SVinod Koul format->bit_depth = SKL_DEPTH_32BIT; 1670cfb0a873SVinod Koul break; 1671cfb0a873SVinod Koul 1672cfb0a873SVinod Koul default: 1673cfb0a873SVinod Koul dev_err(dev, "Invalid bit depth %x for pipe\n", 1674cfb0a873SVinod Koul format->valid_bit_depth); 1675cfb0a873SVinod Koul return -EINVAL; 1676cfb0a873SVinod Koul } 1677cfb0a873SVinod Koul 1678cfb0a873SVinod Koul if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { 1679f6fa56e2SRamesh Babu res->ibs = (format->s_freq / 1000) * 1680cfb0a873SVinod Koul (format->channels) * 1681cfb0a873SVinod Koul (format->bit_depth >> 3); 1682cfb0a873SVinod Koul } else { 1683f6fa56e2SRamesh Babu res->obs = (format->s_freq / 1000) * 1684cfb0a873SVinod Koul (format->channels) * 1685cfb0a873SVinod Koul (format->bit_depth >> 3); 1686cfb0a873SVinod Koul } 1687cfb0a873SVinod Koul 1688cfb0a873SVinod Koul return 0; 1689cfb0a873SVinod Koul } 1690cfb0a873SVinod Koul 1691cfb0a873SVinod Koul /* 1692cfb0a873SVinod Koul * Query the module config for the FE DAI 1693cfb0a873SVinod Koul * This is used to find the hw_params set for that DAI and apply to FE 1694cfb0a873SVinod Koul * pipeline 1695cfb0a873SVinod Koul */ 1696cfb0a873SVinod Koul struct skl_module_cfg * 1697cfb0a873SVinod Koul skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream) 1698cfb0a873SVinod Koul { 1699cfb0a873SVinod Koul struct snd_soc_dapm_widget *w; 1700cfb0a873SVinod Koul struct snd_soc_dapm_path *p = NULL; 1701cfb0a873SVinod Koul 1702cfb0a873SVinod Koul if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 1703cfb0a873SVinod Koul w = dai->playback_widget; 1704f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_sink_path(w, p) { 1705cfb0a873SVinod Koul if (p->connect && p->sink->power && 1706cb1f904dSGuneshwor Singh !is_skl_dsp_widget_type(p->sink, dai->dev)) 1707cfb0a873SVinod Koul continue; 1708cfb0a873SVinod Koul 1709cfb0a873SVinod Koul if (p->sink->priv) { 1710cfb0a873SVinod Koul dev_dbg(dai->dev, "set params for %s\n", 1711cfb0a873SVinod Koul p->sink->name); 1712cfb0a873SVinod Koul return p->sink->priv; 1713cfb0a873SVinod Koul } 1714cfb0a873SVinod Koul } 1715cfb0a873SVinod Koul } else { 1716cfb0a873SVinod Koul w = dai->capture_widget; 1717f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_source_path(w, p) { 1718cfb0a873SVinod Koul if (p->connect && p->source->power && 1719cb1f904dSGuneshwor Singh !is_skl_dsp_widget_type(p->source, dai->dev)) 1720cfb0a873SVinod Koul continue; 1721cfb0a873SVinod Koul 1722cfb0a873SVinod Koul if (p->source->priv) { 1723cfb0a873SVinod Koul dev_dbg(dai->dev, "set params for %s\n", 1724cfb0a873SVinod Koul p->source->name); 1725cfb0a873SVinod Koul return p->source->priv; 1726cfb0a873SVinod Koul } 1727cfb0a873SVinod Koul } 1728cfb0a873SVinod Koul } 1729cfb0a873SVinod Koul 1730cfb0a873SVinod Koul return NULL; 1731cfb0a873SVinod Koul } 1732cfb0a873SVinod Koul 1733718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_pb_cpr( 1734718a42b5SDharageswari.R struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w) 1735718a42b5SDharageswari.R { 1736718a42b5SDharageswari.R struct snd_soc_dapm_path *p; 1737718a42b5SDharageswari.R struct skl_module_cfg *mconfig = NULL; 1738718a42b5SDharageswari.R 1739718a42b5SDharageswari.R snd_soc_dapm_widget_for_each_source_path(w, p) { 1740718a42b5SDharageswari.R if (w->endpoints[SND_SOC_DAPM_DIR_OUT] > 0) { 1741718a42b5SDharageswari.R if (p->connect && 1742718a42b5SDharageswari.R (p->sink->id == snd_soc_dapm_aif_out) && 1743718a42b5SDharageswari.R p->source->priv) { 1744718a42b5SDharageswari.R mconfig = p->source->priv; 1745718a42b5SDharageswari.R return mconfig; 1746718a42b5SDharageswari.R } 1747718a42b5SDharageswari.R mconfig = skl_get_mconfig_pb_cpr(dai, p->source); 1748718a42b5SDharageswari.R if (mconfig) 1749718a42b5SDharageswari.R return mconfig; 1750718a42b5SDharageswari.R } 1751718a42b5SDharageswari.R } 1752718a42b5SDharageswari.R return mconfig; 1753718a42b5SDharageswari.R } 1754718a42b5SDharageswari.R 1755718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_cap_cpr( 1756718a42b5SDharageswari.R struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w) 1757718a42b5SDharageswari.R { 1758718a42b5SDharageswari.R struct snd_soc_dapm_path *p; 1759718a42b5SDharageswari.R struct skl_module_cfg *mconfig = NULL; 1760718a42b5SDharageswari.R 1761718a42b5SDharageswari.R snd_soc_dapm_widget_for_each_sink_path(w, p) { 1762718a42b5SDharageswari.R if (w->endpoints[SND_SOC_DAPM_DIR_IN] > 0) { 1763718a42b5SDharageswari.R if (p->connect && 1764718a42b5SDharageswari.R (p->source->id == snd_soc_dapm_aif_in) && 1765718a42b5SDharageswari.R p->sink->priv) { 1766718a42b5SDharageswari.R mconfig = p->sink->priv; 1767718a42b5SDharageswari.R return mconfig; 1768718a42b5SDharageswari.R } 1769718a42b5SDharageswari.R mconfig = skl_get_mconfig_cap_cpr(dai, p->sink); 1770718a42b5SDharageswari.R if (mconfig) 1771718a42b5SDharageswari.R return mconfig; 1772718a42b5SDharageswari.R } 1773718a42b5SDharageswari.R } 1774718a42b5SDharageswari.R return mconfig; 1775718a42b5SDharageswari.R } 1776718a42b5SDharageswari.R 1777718a42b5SDharageswari.R struct skl_module_cfg * 1778718a42b5SDharageswari.R skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, int stream) 1779718a42b5SDharageswari.R { 1780718a42b5SDharageswari.R struct snd_soc_dapm_widget *w; 1781718a42b5SDharageswari.R struct skl_module_cfg *mconfig; 1782718a42b5SDharageswari.R 1783718a42b5SDharageswari.R if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 1784718a42b5SDharageswari.R w = dai->playback_widget; 1785718a42b5SDharageswari.R mconfig = skl_get_mconfig_pb_cpr(dai, w); 1786718a42b5SDharageswari.R } else { 1787718a42b5SDharageswari.R w = dai->capture_widget; 1788718a42b5SDharageswari.R mconfig = skl_get_mconfig_cap_cpr(dai, w); 1789718a42b5SDharageswari.R } 1790718a42b5SDharageswari.R return mconfig; 1791718a42b5SDharageswari.R } 1792718a42b5SDharageswari.R 1793cfb0a873SVinod Koul static u8 skl_tplg_be_link_type(int dev_type) 1794cfb0a873SVinod Koul { 1795cfb0a873SVinod Koul int ret; 1796cfb0a873SVinod Koul 1797cfb0a873SVinod Koul switch (dev_type) { 1798cfb0a873SVinod Koul case SKL_DEVICE_BT: 1799cfb0a873SVinod Koul ret = NHLT_LINK_SSP; 1800cfb0a873SVinod Koul break; 1801cfb0a873SVinod Koul 1802cfb0a873SVinod Koul case SKL_DEVICE_DMIC: 1803cfb0a873SVinod Koul ret = NHLT_LINK_DMIC; 1804cfb0a873SVinod Koul break; 1805cfb0a873SVinod Koul 1806cfb0a873SVinod Koul case SKL_DEVICE_I2S: 1807cfb0a873SVinod Koul ret = NHLT_LINK_SSP; 1808cfb0a873SVinod Koul break; 1809cfb0a873SVinod Koul 1810cfb0a873SVinod Koul case SKL_DEVICE_HDALINK: 1811cfb0a873SVinod Koul ret = NHLT_LINK_HDA; 1812cfb0a873SVinod Koul break; 1813cfb0a873SVinod Koul 1814cfb0a873SVinod Koul default: 1815cfb0a873SVinod Koul ret = NHLT_LINK_INVALID; 1816cfb0a873SVinod Koul break; 1817cfb0a873SVinod Koul } 1818cfb0a873SVinod Koul 1819cfb0a873SVinod Koul return ret; 1820cfb0a873SVinod Koul } 1821cfb0a873SVinod Koul 1822cfb0a873SVinod Koul /* 1823cfb0a873SVinod Koul * Fill the BE gateway parameters 1824cfb0a873SVinod Koul * The BE gateway expects a blob of parameters which are kept in the ACPI 1825cfb0a873SVinod Koul * NHLT blob, so query the blob for interface type (i2s/pdm) and instance. 182687b26526SPiotr Maziarz * The port can have multiple settings so pick based on the pipeline 1827cfb0a873SVinod Koul * parameters 1828cfb0a873SVinod Koul */ 1829cfb0a873SVinod Koul static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai, 1830cfb0a873SVinod Koul struct skl_module_cfg *mconfig, 1831cfb0a873SVinod Koul struct skl_pipe_params *params) 1832cfb0a873SVinod Koul { 1833cfb0a873SVinod Koul struct nhlt_specific_cfg *cfg; 183487b26526SPiotr Maziarz struct skl_pipe *pipe = mconfig->pipe; 183587b26526SPiotr Maziarz struct skl_pipe_fmt *pipe_fmt; 1836bcc2a2dcSCezary Rojewski struct skl_dev *skl = get_skl_ctx(dai->dev); 1837cfb0a873SVinod Koul int link_type = skl_tplg_be_link_type(mconfig->dev_type); 1838db2f586bSSenthilnathan Veppur u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type); 1839cfb0a873SVinod Koul 18408871dcb9SJeeja KP skl_tplg_fill_dma_id(mconfig, params); 1841cfb0a873SVinod Koul 1842b30c275eSJeeja KP if (link_type == NHLT_LINK_HDA) 1843b30c275eSJeeja KP return 0; 1844b30c275eSJeeja KP 184587b26526SPiotr Maziarz if (pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) 184687b26526SPiotr Maziarz pipe_fmt = &pipe->configs[pipe->pipe_config_idx].out_fmt; 184787b26526SPiotr Maziarz else 184887b26526SPiotr Maziarz pipe_fmt = &pipe->configs[pipe->pipe_config_idx].in_fmt; 184987b26526SPiotr Maziarz 1850cfb0a873SVinod Koul /* update the blob based on virtual bus_id*/ 1851cfb0a873SVinod Koul cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type, 185287b26526SPiotr Maziarz pipe_fmt->bps, pipe_fmt->channels, 185387b26526SPiotr Maziarz pipe_fmt->freq, pipe->direction, 1854db2f586bSSenthilnathan Veppur dev_type); 1855cfb0a873SVinod Koul if (cfg) { 1856*a4ad42d2SKareem Shaik mconfig->formats_config[SKL_PARAM_INIT].caps_size = cfg->size; 1857*a4ad42d2SKareem Shaik mconfig->formats_config[SKL_PARAM_INIT].caps = (u32 *)&cfg->caps; 1858cfb0a873SVinod Koul } else { 185987b26526SPiotr Maziarz dev_err(dai->dev, "Blob NULL for id:%d type:%d dirn:%d ch:%d, freq:%d, fmt:%d\n", 186087b26526SPiotr Maziarz mconfig->vbus_id, link_type, params->stream, 1861cfb0a873SVinod Koul params->ch, params->s_freq, params->s_fmt); 1862cfb0a873SVinod Koul return -EINVAL; 1863cfb0a873SVinod Koul } 1864cfb0a873SVinod Koul 1865cfb0a873SVinod Koul return 0; 1866cfb0a873SVinod Koul } 1867cfb0a873SVinod Koul 1868cfb0a873SVinod Koul static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai, 1869cfb0a873SVinod Koul struct snd_soc_dapm_widget *w, 1870cfb0a873SVinod Koul struct skl_pipe_params *params) 1871cfb0a873SVinod Koul { 1872cfb0a873SVinod Koul struct snd_soc_dapm_path *p; 18734d8adccbSSubhransu S. Prusty int ret = -EIO; 1874cfb0a873SVinod Koul 1875f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_source_path(w, p) { 1876cb1f904dSGuneshwor Singh if (p->connect && is_skl_dsp_widget_type(p->source, dai->dev) && 1877cfb0a873SVinod Koul p->source->priv) { 1878cfb0a873SVinod Koul 18799a03cb49SJeeja KP ret = skl_tplg_be_fill_pipe_params(dai, 18809a03cb49SJeeja KP p->source->priv, params); 18814d8adccbSSubhransu S. Prusty if (ret < 0) 18824d8adccbSSubhransu S. Prusty return ret; 1883cfb0a873SVinod Koul } else { 18849a03cb49SJeeja KP ret = skl_tplg_be_set_src_pipe_params(dai, 18859a03cb49SJeeja KP p->source, params); 18864d8adccbSSubhransu S. Prusty if (ret < 0) 18874d8adccbSSubhransu S. Prusty return ret; 1888cfb0a873SVinod Koul } 1889cfb0a873SVinod Koul } 1890cfb0a873SVinod Koul 18914d8adccbSSubhransu S. Prusty return ret; 1892cfb0a873SVinod Koul } 1893cfb0a873SVinod Koul 1894cfb0a873SVinod Koul static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai, 1895cfb0a873SVinod Koul struct snd_soc_dapm_widget *w, struct skl_pipe_params *params) 1896cfb0a873SVinod Koul { 189725722cf6SPierre-Louis Bossart struct snd_soc_dapm_path *p; 18984d8adccbSSubhransu S. Prusty int ret = -EIO; 1899cfb0a873SVinod Koul 1900f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_sink_path(w, p) { 1901cb1f904dSGuneshwor Singh if (p->connect && is_skl_dsp_widget_type(p->sink, dai->dev) && 1902cfb0a873SVinod Koul p->sink->priv) { 1903cfb0a873SVinod Koul 19049a03cb49SJeeja KP ret = skl_tplg_be_fill_pipe_params(dai, 19059a03cb49SJeeja KP p->sink->priv, params); 19064d8adccbSSubhransu S. Prusty if (ret < 0) 19074d8adccbSSubhransu S. Prusty return ret; 19084d8adccbSSubhransu S. Prusty } else { 19094d8adccbSSubhransu S. Prusty ret = skl_tplg_be_set_sink_pipe_params( 1910cfb0a873SVinod Koul dai, p->sink, params); 19114d8adccbSSubhransu S. Prusty if (ret < 0) 19124d8adccbSSubhransu S. Prusty return ret; 1913cfb0a873SVinod Koul } 1914cfb0a873SVinod Koul } 1915cfb0a873SVinod Koul 19164d8adccbSSubhransu S. Prusty return ret; 1917cfb0a873SVinod Koul } 1918cfb0a873SVinod Koul 1919cfb0a873SVinod Koul /* 1920cfb0a873SVinod Koul * BE hw_params can be a source parameters (capture) or sink parameters 1921cfb0a873SVinod Koul * (playback). Based on sink and source we need to either find the source 1922cfb0a873SVinod Koul * list or the sink list and set the pipeline parameters 1923cfb0a873SVinod Koul */ 1924cfb0a873SVinod Koul int skl_tplg_be_update_params(struct snd_soc_dai *dai, 1925cfb0a873SVinod Koul struct skl_pipe_params *params) 1926cfb0a873SVinod Koul { 1927cfb0a873SVinod Koul struct snd_soc_dapm_widget *w; 1928cfb0a873SVinod Koul 1929cfb0a873SVinod Koul if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { 1930cfb0a873SVinod Koul w = dai->playback_widget; 1931cfb0a873SVinod Koul 1932cfb0a873SVinod Koul return skl_tplg_be_set_src_pipe_params(dai, w, params); 1933cfb0a873SVinod Koul 1934cfb0a873SVinod Koul } else { 1935cfb0a873SVinod Koul w = dai->capture_widget; 1936cfb0a873SVinod Koul 1937cfb0a873SVinod Koul return skl_tplg_be_set_sink_pipe_params(dai, w, params); 1938cfb0a873SVinod Koul } 1939cfb0a873SVinod Koul 1940cfb0a873SVinod Koul return 0; 1941cfb0a873SVinod Koul } 19423af36706SVinod Koul 19433af36706SVinod Koul static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = { 19443af36706SVinod Koul {SKL_MIXER_EVENT, skl_tplg_mixer_event}, 19459a1e3507SVinod Koul {SKL_VMIXER_EVENT, skl_tplg_mixer_event}, 19463af36706SVinod Koul {SKL_PGA_EVENT, skl_tplg_pga_event}, 19473af36706SVinod Koul }; 19483af36706SVinod Koul 1949140adfbaSJeeja KP static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = { 1950140adfbaSJeeja KP {SKL_CONTROL_TYPE_BYTE_TLV, skl_tplg_tlv_control_get, 1951140adfbaSJeeja KP skl_tplg_tlv_control_set}, 1952140adfbaSJeeja KP }; 1953140adfbaSJeeja KP 19547a1b749bSDharageswari R static const struct snd_soc_tplg_kcontrol_ops skl_tplg_kcontrol_ops[] = { 19557a1b749bSDharageswari R { 19567a1b749bSDharageswari R .id = SKL_CONTROL_TYPE_MIC_SELECT, 19577a1b749bSDharageswari R .get = skl_tplg_mic_control_get, 19587a1b749bSDharageswari R .put = skl_tplg_mic_control_set, 19597a1b749bSDharageswari R }, 19601b450791SMateusz Gorski { 19611b450791SMateusz Gorski .id = SKL_CONTROL_TYPE_MULTI_IO_SELECT, 19621b450791SMateusz Gorski .get = skl_tplg_multi_config_get, 19631b450791SMateusz Gorski .put = skl_tplg_multi_config_set, 19641b450791SMateusz Gorski }, 19652d744ecfSMateusz Gorski { 19662d744ecfSMateusz Gorski .id = SKL_CONTROL_TYPE_MULTI_IO_SELECT_DMIC, 19672d744ecfSMateusz Gorski .get = skl_tplg_multi_config_get_dmic, 19682d744ecfSMateusz Gorski .put = skl_tplg_multi_config_set_dmic, 19692d744ecfSMateusz Gorski } 19707a1b749bSDharageswari R }; 19717a1b749bSDharageswari R 1972f6fa56e2SRamesh Babu static int skl_tplg_fill_pipe_cfg(struct device *dev, 1973f6fa56e2SRamesh Babu struct skl_pipe *pipe, u32 tkn, 1974f6fa56e2SRamesh Babu u32 tkn_val, int conf_idx, int dir) 1975f6fa56e2SRamesh Babu { 1976f6fa56e2SRamesh Babu struct skl_pipe_fmt *fmt; 1977f6fa56e2SRamesh Babu struct skl_path_config *config; 1978f6fa56e2SRamesh Babu 1979f6fa56e2SRamesh Babu switch (dir) { 1980f6fa56e2SRamesh Babu case SKL_DIR_IN: 1981f6fa56e2SRamesh Babu fmt = &pipe->configs[conf_idx].in_fmt; 1982f6fa56e2SRamesh Babu break; 1983f6fa56e2SRamesh Babu 1984f6fa56e2SRamesh Babu case SKL_DIR_OUT: 1985f6fa56e2SRamesh Babu fmt = &pipe->configs[conf_idx].out_fmt; 1986f6fa56e2SRamesh Babu break; 1987f6fa56e2SRamesh Babu 1988f6fa56e2SRamesh Babu default: 1989f6fa56e2SRamesh Babu dev_err(dev, "Invalid direction: %d\n", dir); 1990f6fa56e2SRamesh Babu return -EINVAL; 1991f6fa56e2SRamesh Babu } 1992f6fa56e2SRamesh Babu 1993f6fa56e2SRamesh Babu config = &pipe->configs[conf_idx]; 1994f6fa56e2SRamesh Babu 1995f6fa56e2SRamesh Babu switch (tkn) { 1996f6fa56e2SRamesh Babu case SKL_TKN_U32_CFG_FREQ: 1997f6fa56e2SRamesh Babu fmt->freq = tkn_val; 1998f6fa56e2SRamesh Babu break; 1999f6fa56e2SRamesh Babu 2000f6fa56e2SRamesh Babu case SKL_TKN_U8_CFG_CHAN: 2001f6fa56e2SRamesh Babu fmt->channels = tkn_val; 2002f6fa56e2SRamesh Babu break; 2003f6fa56e2SRamesh Babu 2004f6fa56e2SRamesh Babu case SKL_TKN_U8_CFG_BPS: 2005f6fa56e2SRamesh Babu fmt->bps = tkn_val; 2006f6fa56e2SRamesh Babu break; 2007f6fa56e2SRamesh Babu 2008f6fa56e2SRamesh Babu case SKL_TKN_U32_PATH_MEM_PGS: 2009f6fa56e2SRamesh Babu config->mem_pages = tkn_val; 2010f6fa56e2SRamesh Babu break; 2011f6fa56e2SRamesh Babu 2012f6fa56e2SRamesh Babu default: 2013f6fa56e2SRamesh Babu dev_err(dev, "Invalid token config: %d\n", tkn); 2014f6fa56e2SRamesh Babu return -EINVAL; 2015f6fa56e2SRamesh Babu } 2016f6fa56e2SRamesh Babu 2017f6fa56e2SRamesh Babu return 0; 2018f6fa56e2SRamesh Babu } 2019f6fa56e2SRamesh Babu 20206277e832SShreyas NC static int skl_tplg_fill_pipe_tkn(struct device *dev, 20216277e832SShreyas NC struct skl_pipe *pipe, u32 tkn, 20226277e832SShreyas NC u32 tkn_val) 20233af36706SVinod Koul { 20243af36706SVinod Koul 20256277e832SShreyas NC switch (tkn) { 20266277e832SShreyas NC case SKL_TKN_U32_PIPE_CONN_TYPE: 20276277e832SShreyas NC pipe->conn_type = tkn_val; 20286277e832SShreyas NC break; 20296277e832SShreyas NC 20306277e832SShreyas NC case SKL_TKN_U32_PIPE_PRIORITY: 20316277e832SShreyas NC pipe->pipe_priority = tkn_val; 20326277e832SShreyas NC break; 20336277e832SShreyas NC 20346277e832SShreyas NC case SKL_TKN_U32_PIPE_MEM_PGS: 20356277e832SShreyas NC pipe->memory_pages = tkn_val; 20366277e832SShreyas NC break; 20376277e832SShreyas NC 20388a0cb236SVinod Koul case SKL_TKN_U32_PMODE: 20398a0cb236SVinod Koul pipe->lp_mode = tkn_val; 20408a0cb236SVinod Koul break; 20418a0cb236SVinod Koul 2042f6fa56e2SRamesh Babu case SKL_TKN_U32_PIPE_DIRECTION: 2043f6fa56e2SRamesh Babu pipe->direction = tkn_val; 2044f6fa56e2SRamesh Babu break; 2045f6fa56e2SRamesh Babu 2046f6fa56e2SRamesh Babu case SKL_TKN_U32_NUM_CONFIGS: 2047f6fa56e2SRamesh Babu pipe->nr_cfgs = tkn_val; 2048f6fa56e2SRamesh Babu break; 2049f6fa56e2SRamesh Babu 20506277e832SShreyas NC default: 20516277e832SShreyas NC dev_err(dev, "Token not handled %d\n", tkn); 20526277e832SShreyas NC return -EINVAL; 20533af36706SVinod Koul } 20546277e832SShreyas NC 20556277e832SShreyas NC return 0; 20563af36706SVinod Koul } 20573af36706SVinod Koul 20583af36706SVinod Koul /* 20596277e832SShreyas NC * Add pipeline by parsing the relevant tokens 20606277e832SShreyas NC * Return an existing pipe if the pipe already exists. 20613af36706SVinod Koul */ 20626277e832SShreyas NC static int skl_tplg_add_pipe(struct device *dev, 2063bcc2a2dcSCezary Rojewski struct skl_module_cfg *mconfig, struct skl_dev *skl, 20646277e832SShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem) 20653af36706SVinod Koul { 20663af36706SVinod Koul struct skl_pipeline *ppl; 20673af36706SVinod Koul struct skl_pipe *pipe; 20683af36706SVinod Koul struct skl_pipe_params *params; 20693af36706SVinod Koul 20703af36706SVinod Koul list_for_each_entry(ppl, &skl->ppl_list, node) { 20716277e832SShreyas NC if (ppl->pipe->ppl_id == tkn_elem->value) { 20726277e832SShreyas NC mconfig->pipe = ppl->pipe; 2073081dc8abSGuneshwor Singh return -EEXIST; 20746277e832SShreyas NC } 20753af36706SVinod Koul } 20763af36706SVinod Koul 20773af36706SVinod Koul ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL); 20783af36706SVinod Koul if (!ppl) 20796277e832SShreyas NC return -ENOMEM; 20803af36706SVinod Koul 20813af36706SVinod Koul pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL); 20823af36706SVinod Koul if (!pipe) 20836277e832SShreyas NC return -ENOMEM; 20843af36706SVinod Koul 20853af36706SVinod Koul params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL); 20863af36706SVinod Koul if (!params) 20876277e832SShreyas NC return -ENOMEM; 20883af36706SVinod Koul 20893af36706SVinod Koul pipe->p_params = params; 20906277e832SShreyas NC pipe->ppl_id = tkn_elem->value; 20913af36706SVinod Koul INIT_LIST_HEAD(&pipe->w_list); 20923af36706SVinod Koul 20933af36706SVinod Koul ppl->pipe = pipe; 20943af36706SVinod Koul list_add(&ppl->node, &skl->ppl_list); 20953af36706SVinod Koul 20966277e832SShreyas NC mconfig->pipe = pipe; 20976277e832SShreyas NC mconfig->pipe->state = SKL_PIPE_INVALID; 20986277e832SShreyas NC 20996277e832SShreyas NC return 0; 21003af36706SVinod Koul } 21013af36706SVinod Koul 21029e0784d0SAndy Shevchenko static int skl_tplg_get_uuid(struct device *dev, guid_t *guid, 210322ebd666SSriram Periyasamy struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn) 21046277e832SShreyas NC { 210522ebd666SSriram Periyasamy if (uuid_tkn->token == SKL_TKN_UUID) { 2106cade2f59SAndy Shevchenko import_guid(guid, uuid_tkn->uuid); 210722ebd666SSriram Periyasamy return 0; 210822ebd666SSriram Periyasamy } 210922ebd666SSriram Periyasamy 211022ebd666SSriram Periyasamy dev_err(dev, "Not an UUID token %d\n", uuid_tkn->token); 211122ebd666SSriram Periyasamy 211222ebd666SSriram Periyasamy return -EINVAL; 211322ebd666SSriram Periyasamy } 211422ebd666SSriram Periyasamy 211522ebd666SSriram Periyasamy static int skl_tplg_fill_pin(struct device *dev, 211622ebd666SSriram Periyasamy struct snd_soc_tplg_vendor_value_elem *tkn_elem, 211722ebd666SSriram Periyasamy struct skl_module_pin *m_pin, 211822ebd666SSriram Periyasamy int pin_index) 211922ebd666SSriram Periyasamy { 2120d9561474SSriram Periyasamy int ret; 2121d9561474SSriram Periyasamy 212222ebd666SSriram Periyasamy switch (tkn_elem->token) { 21236277e832SShreyas NC case SKL_TKN_U32_PIN_MOD_ID: 212422ebd666SSriram Periyasamy m_pin[pin_index].id.module_id = tkn_elem->value; 21256277e832SShreyas NC break; 21266277e832SShreyas NC 21276277e832SShreyas NC case SKL_TKN_U32_PIN_INST_ID: 212822ebd666SSriram Periyasamy m_pin[pin_index].id.instance_id = tkn_elem->value; 21296277e832SShreyas NC break; 21306277e832SShreyas NC 2131d9561474SSriram Periyasamy case SKL_TKN_UUID: 21329e0784d0SAndy Shevchenko ret = skl_tplg_get_uuid(dev, &m_pin[pin_index].id.mod_uuid, 2133d9561474SSriram Periyasamy (struct snd_soc_tplg_vendor_uuid_elem *)tkn_elem); 2134d9561474SSriram Periyasamy if (ret < 0) 2135d9561474SSriram Periyasamy return ret; 2136d9561474SSriram Periyasamy 21376277e832SShreyas NC break; 21386277e832SShreyas NC 21396277e832SShreyas NC default: 214022ebd666SSriram Periyasamy dev_err(dev, "%d Not a pin token\n", tkn_elem->token); 21416277e832SShreyas NC return -EINVAL; 21426277e832SShreyas NC } 21436277e832SShreyas NC 21446277e832SShreyas NC return 0; 21456277e832SShreyas NC } 21466277e832SShreyas NC 21476277e832SShreyas NC /* 21486277e832SShreyas NC * Parse for pin config specific tokens to fill up the 21496277e832SShreyas NC * module private data 21506277e832SShreyas NC */ 21516277e832SShreyas NC static int skl_tplg_fill_pins_info(struct device *dev, 21526277e832SShreyas NC struct skl_module_cfg *mconfig, 21536277e832SShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem, 21546277e832SShreyas NC int dir, int pin_count) 21556277e832SShreyas NC { 21566277e832SShreyas NC int ret; 21576277e832SShreyas NC struct skl_module_pin *m_pin; 21586277e832SShreyas NC 21596277e832SShreyas NC switch (dir) { 21606277e832SShreyas NC case SKL_DIR_IN: 21616277e832SShreyas NC m_pin = mconfig->m_in_pin; 21626277e832SShreyas NC break; 21636277e832SShreyas NC 21646277e832SShreyas NC case SKL_DIR_OUT: 21656277e832SShreyas NC m_pin = mconfig->m_out_pin; 21666277e832SShreyas NC break; 21676277e832SShreyas NC 21686277e832SShreyas NC default: 2169ecd286a9SColin Ian King dev_err(dev, "Invalid direction value\n"); 21706277e832SShreyas NC return -EINVAL; 21716277e832SShreyas NC } 21726277e832SShreyas NC 217322ebd666SSriram Periyasamy ret = skl_tplg_fill_pin(dev, tkn_elem, m_pin, pin_count); 21746277e832SShreyas NC if (ret < 0) 21756277e832SShreyas NC return ret; 21766277e832SShreyas NC 21776277e832SShreyas NC m_pin[pin_count].in_use = false; 21786277e832SShreyas NC m_pin[pin_count].pin_state = SKL_PIN_UNBIND; 21796277e832SShreyas NC 21806277e832SShreyas NC return 0; 21816277e832SShreyas NC } 21826277e832SShreyas NC 21836277e832SShreyas NC /* 21846277e832SShreyas NC * Fill up input/output module config format based 21856277e832SShreyas NC * on the direction 21866277e832SShreyas NC */ 21876277e832SShreyas NC static int skl_tplg_fill_fmt(struct device *dev, 2188ca312fdaSShreyas NC struct skl_module_fmt *dst_fmt, 2189ca312fdaSShreyas NC u32 tkn, u32 value) 21906277e832SShreyas NC { 21916277e832SShreyas NC switch (tkn) { 21926277e832SShreyas NC case SKL_TKN_U32_FMT_CH: 21936277e832SShreyas NC dst_fmt->channels = value; 21946277e832SShreyas NC break; 21956277e832SShreyas NC 21966277e832SShreyas NC case SKL_TKN_U32_FMT_FREQ: 21976277e832SShreyas NC dst_fmt->s_freq = value; 21986277e832SShreyas NC break; 21996277e832SShreyas NC 22006277e832SShreyas NC case SKL_TKN_U32_FMT_BIT_DEPTH: 22016277e832SShreyas NC dst_fmt->bit_depth = value; 22026277e832SShreyas NC break; 22036277e832SShreyas NC 22046277e832SShreyas NC case SKL_TKN_U32_FMT_SAMPLE_SIZE: 22056277e832SShreyas NC dst_fmt->valid_bit_depth = value; 22066277e832SShreyas NC break; 22076277e832SShreyas NC 22086277e832SShreyas NC case SKL_TKN_U32_FMT_CH_CONFIG: 22096277e832SShreyas NC dst_fmt->ch_cfg = value; 22106277e832SShreyas NC break; 22116277e832SShreyas NC 22126277e832SShreyas NC case SKL_TKN_U32_FMT_INTERLEAVE: 22136277e832SShreyas NC dst_fmt->interleaving_style = value; 22146277e832SShreyas NC break; 22156277e832SShreyas NC 22166277e832SShreyas NC case SKL_TKN_U32_FMT_SAMPLE_TYPE: 22176277e832SShreyas NC dst_fmt->sample_type = value; 22186277e832SShreyas NC break; 22196277e832SShreyas NC 22206277e832SShreyas NC case SKL_TKN_U32_FMT_CH_MAP: 22216277e832SShreyas NC dst_fmt->ch_map = value; 22226277e832SShreyas NC break; 22236277e832SShreyas NC 22246277e832SShreyas NC default: 2225ecd286a9SColin Ian King dev_err(dev, "Invalid token %d\n", tkn); 22266277e832SShreyas NC return -EINVAL; 22276277e832SShreyas NC } 22286277e832SShreyas NC 22296277e832SShreyas NC return 0; 22306277e832SShreyas NC } 22316277e832SShreyas NC 2232ca312fdaSShreyas NC static int skl_tplg_widget_fill_fmt(struct device *dev, 2233f6fa56e2SRamesh Babu struct skl_module_iface *fmt, 2234ca312fdaSShreyas NC u32 tkn, u32 val, u32 dir, int fmt_idx) 2235ca312fdaSShreyas NC { 2236ca312fdaSShreyas NC struct skl_module_fmt *dst_fmt; 2237ca312fdaSShreyas NC 2238f6fa56e2SRamesh Babu if (!fmt) 2239f6fa56e2SRamesh Babu return -EINVAL; 2240f6fa56e2SRamesh Babu 2241ca312fdaSShreyas NC switch (dir) { 2242ca312fdaSShreyas NC case SKL_DIR_IN: 2243f6fa56e2SRamesh Babu dst_fmt = &fmt->inputs[fmt_idx].fmt; 2244ca312fdaSShreyas NC break; 2245ca312fdaSShreyas NC 2246ca312fdaSShreyas NC case SKL_DIR_OUT: 2247f6fa56e2SRamesh Babu dst_fmt = &fmt->outputs[fmt_idx].fmt; 2248ca312fdaSShreyas NC break; 2249ca312fdaSShreyas NC 2250ca312fdaSShreyas NC default: 2251ca312fdaSShreyas NC dev_err(dev, "Invalid direction: %d\n", dir); 2252ca312fdaSShreyas NC return -EINVAL; 2253ca312fdaSShreyas NC } 2254ca312fdaSShreyas NC 2255ca312fdaSShreyas NC return skl_tplg_fill_fmt(dev, dst_fmt, tkn, val); 2256ca312fdaSShreyas NC } 2257ca312fdaSShreyas NC 22586277e832SShreyas NC static void skl_tplg_fill_pin_dynamic_val( 22596277e832SShreyas NC struct skl_module_pin *mpin, u32 pin_count, u32 value) 22604cd9899fSHardik T Shah { 22614cd9899fSHardik T Shah int i; 22624cd9899fSHardik T Shah 22636277e832SShreyas NC for (i = 0; i < pin_count; i++) 22646277e832SShreyas NC mpin[i].is_dynamic = value; 22654cd9899fSHardik T Shah } 22666277e832SShreyas NC 22676277e832SShreyas NC /* 2268db6ed55dSShreyas NC * Resource table in the manifest has pin specific resources 2269db6ed55dSShreyas NC * like pin and pin buffer size 2270db6ed55dSShreyas NC */ 2271db6ed55dSShreyas NC static int skl_tplg_manifest_pin_res_tkn(struct device *dev, 2272db6ed55dSShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem, 2273db6ed55dSShreyas NC struct skl_module_res *res, int pin_idx, int dir) 2274db6ed55dSShreyas NC { 2275db6ed55dSShreyas NC struct skl_module_pin_resources *m_pin; 2276db6ed55dSShreyas NC 2277db6ed55dSShreyas NC switch (dir) { 2278db6ed55dSShreyas NC case SKL_DIR_IN: 2279db6ed55dSShreyas NC m_pin = &res->input[pin_idx]; 2280db6ed55dSShreyas NC break; 2281db6ed55dSShreyas NC 2282db6ed55dSShreyas NC case SKL_DIR_OUT: 2283db6ed55dSShreyas NC m_pin = &res->output[pin_idx]; 2284db6ed55dSShreyas NC break; 2285db6ed55dSShreyas NC 2286db6ed55dSShreyas NC default: 2287db6ed55dSShreyas NC dev_err(dev, "Invalid pin direction: %d\n", dir); 2288db6ed55dSShreyas NC return -EINVAL; 2289db6ed55dSShreyas NC } 2290db6ed55dSShreyas NC 2291db6ed55dSShreyas NC switch (tkn_elem->token) { 2292db6ed55dSShreyas NC case SKL_TKN_MM_U32_RES_PIN_ID: 2293db6ed55dSShreyas NC m_pin->pin_index = tkn_elem->value; 2294db6ed55dSShreyas NC break; 2295db6ed55dSShreyas NC 2296db6ed55dSShreyas NC case SKL_TKN_MM_U32_PIN_BUF: 2297db6ed55dSShreyas NC m_pin->buf_size = tkn_elem->value; 2298db6ed55dSShreyas NC break; 2299db6ed55dSShreyas NC 2300db6ed55dSShreyas NC default: 2301db6ed55dSShreyas NC dev_err(dev, "Invalid token: %d\n", tkn_elem->token); 2302db6ed55dSShreyas NC return -EINVAL; 2303db6ed55dSShreyas NC } 2304db6ed55dSShreyas NC 2305db6ed55dSShreyas NC return 0; 2306db6ed55dSShreyas NC } 2307db6ed55dSShreyas NC 2308db6ed55dSShreyas NC /* 2309db6ed55dSShreyas NC * Fill module specific resources from the manifest's resource 2310db6ed55dSShreyas NC * table like CPS, DMA size, mem_pages. 2311db6ed55dSShreyas NC */ 2312db6ed55dSShreyas NC static int skl_tplg_fill_res_tkn(struct device *dev, 2313db6ed55dSShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem, 2314db6ed55dSShreyas NC struct skl_module_res *res, 2315db6ed55dSShreyas NC int pin_idx, int dir) 2316db6ed55dSShreyas NC { 2317db6ed55dSShreyas NC int ret, tkn_count = 0; 2318db6ed55dSShreyas NC 2319db6ed55dSShreyas NC if (!res) 2320db6ed55dSShreyas NC return -EINVAL; 2321db6ed55dSShreyas NC 2322db6ed55dSShreyas NC switch (tkn_elem->token) { 2323db6ed55dSShreyas NC case SKL_TKN_MM_U32_DMA_SIZE: 2324db6ed55dSShreyas NC res->dma_buffer_size = tkn_elem->value; 2325db6ed55dSShreyas NC break; 2326db6ed55dSShreyas NC 2327db6ed55dSShreyas NC case SKL_TKN_MM_U32_CPC: 2328db6ed55dSShreyas NC res->cpc = tkn_elem->value; 2329db6ed55dSShreyas NC break; 2330db6ed55dSShreyas NC 2331db6ed55dSShreyas NC case SKL_TKN_U32_MEM_PAGES: 2332db6ed55dSShreyas NC res->is_pages = tkn_elem->value; 2333db6ed55dSShreyas NC break; 2334db6ed55dSShreyas NC 2335db6ed55dSShreyas NC case SKL_TKN_U32_OBS: 2336db6ed55dSShreyas NC res->obs = tkn_elem->value; 2337db6ed55dSShreyas NC break; 2338db6ed55dSShreyas NC 2339db6ed55dSShreyas NC case SKL_TKN_U32_IBS: 2340db6ed55dSShreyas NC res->ibs = tkn_elem->value; 2341db6ed55dSShreyas NC break; 2342db6ed55dSShreyas NC 2343db6ed55dSShreyas NC case SKL_TKN_MM_U32_RES_PIN_ID: 2344db6ed55dSShreyas NC case SKL_TKN_MM_U32_PIN_BUF: 2345db6ed55dSShreyas NC ret = skl_tplg_manifest_pin_res_tkn(dev, tkn_elem, res, 2346db6ed55dSShreyas NC pin_idx, dir); 2347db6ed55dSShreyas NC if (ret < 0) 2348db6ed55dSShreyas NC return ret; 2349db6ed55dSShreyas NC break; 2350db6ed55dSShreyas NC 235184b71067SCezary Rojewski case SKL_TKN_MM_U32_CPS: 235284b71067SCezary Rojewski case SKL_TKN_U32_MAX_MCPS: 235384b71067SCezary Rojewski /* ignore unused tokens */ 235484b71067SCezary Rojewski break; 235584b71067SCezary Rojewski 2356db6ed55dSShreyas NC default: 2357db6ed55dSShreyas NC dev_err(dev, "Not a res type token: %d", tkn_elem->token); 2358db6ed55dSShreyas NC return -EINVAL; 2359db6ed55dSShreyas NC 2360db6ed55dSShreyas NC } 2361db6ed55dSShreyas NC tkn_count++; 2362db6ed55dSShreyas NC 2363db6ed55dSShreyas NC return tkn_count; 2364db6ed55dSShreyas NC } 2365db6ed55dSShreyas NC 2366db6ed55dSShreyas NC /* 23676277e832SShreyas NC * Parse tokens to fill up the module private data 23686277e832SShreyas NC */ 23696277e832SShreyas NC static int skl_tplg_get_token(struct device *dev, 23706277e832SShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem, 2371bcc2a2dcSCezary Rojewski struct skl_dev *skl, struct skl_module_cfg *mconfig) 23726277e832SShreyas NC { 23736277e832SShreyas NC int tkn_count = 0; 23746277e832SShreyas NC int ret; 23756277e832SShreyas NC static int is_pipe_exists; 2376f6fa56e2SRamesh Babu static int pin_index, dir, conf_idx; 2377f6fa56e2SRamesh Babu struct skl_module_iface *iface = NULL; 2378f6fa56e2SRamesh Babu struct skl_module_res *res = NULL; 2379f6fa56e2SRamesh Babu int res_idx = mconfig->res_idx; 2380f6fa56e2SRamesh Babu int fmt_idx = mconfig->fmt_idx; 2381f6fa56e2SRamesh Babu 2382f6fa56e2SRamesh Babu /* 2383f6fa56e2SRamesh Babu * If the manifest structure contains no modules, fill all 2384f6fa56e2SRamesh Babu * the module data to 0th index. 2385f6fa56e2SRamesh Babu * res_idx and fmt_idx are default set to 0. 2386f6fa56e2SRamesh Babu */ 2387f6fa56e2SRamesh Babu if (skl->nr_modules == 0) { 2388f6fa56e2SRamesh Babu res = &mconfig->module->resources[res_idx]; 2389f6fa56e2SRamesh Babu iface = &mconfig->module->formats[fmt_idx]; 2390f6fa56e2SRamesh Babu } 23916277e832SShreyas NC 23926277e832SShreyas NC if (tkn_elem->token > SKL_TKN_MAX) 23936277e832SShreyas NC return -EINVAL; 23946277e832SShreyas NC 23956277e832SShreyas NC switch (tkn_elem->token) { 23966277e832SShreyas NC case SKL_TKN_U8_IN_QUEUE_COUNT: 2397f6fa56e2SRamesh Babu mconfig->module->max_input_pins = tkn_elem->value; 23986277e832SShreyas NC break; 23996277e832SShreyas NC 24006277e832SShreyas NC case SKL_TKN_U8_OUT_QUEUE_COUNT: 2401f6fa56e2SRamesh Babu mconfig->module->max_output_pins = tkn_elem->value; 24026277e832SShreyas NC break; 24036277e832SShreyas NC 24046277e832SShreyas NC case SKL_TKN_U8_DYN_IN_PIN: 24056277e832SShreyas NC if (!mconfig->m_in_pin) 2406a86854d0SKees Cook mconfig->m_in_pin = 2407a86854d0SKees Cook devm_kcalloc(dev, MAX_IN_QUEUE, 2408a86854d0SKees Cook sizeof(*mconfig->m_in_pin), 2409a86854d0SKees Cook GFP_KERNEL); 2410f6fa56e2SRamesh Babu if (!mconfig->m_in_pin) 24116277e832SShreyas NC return -ENOMEM; 24126277e832SShreyas NC 2413f6fa56e2SRamesh Babu skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin, MAX_IN_QUEUE, 2414f6fa56e2SRamesh Babu tkn_elem->value); 24156277e832SShreyas NC break; 24166277e832SShreyas NC 24176277e832SShreyas NC case SKL_TKN_U8_DYN_OUT_PIN: 24186277e832SShreyas NC if (!mconfig->m_out_pin) 2419a86854d0SKees Cook mconfig->m_out_pin = 2420a86854d0SKees Cook devm_kcalloc(dev, MAX_IN_QUEUE, 2421a86854d0SKees Cook sizeof(*mconfig->m_in_pin), 2422a86854d0SKees Cook GFP_KERNEL); 2423f6fa56e2SRamesh Babu if (!mconfig->m_out_pin) 24246277e832SShreyas NC return -ENOMEM; 24256277e832SShreyas NC 2426f6fa56e2SRamesh Babu skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin, MAX_OUT_QUEUE, 2427f6fa56e2SRamesh Babu tkn_elem->value); 24286277e832SShreyas NC break; 24296277e832SShreyas NC 24306277e832SShreyas NC case SKL_TKN_U8_TIME_SLOT: 24316277e832SShreyas NC mconfig->time_slot = tkn_elem->value; 24326277e832SShreyas NC break; 24336277e832SShreyas NC 24346277e832SShreyas NC case SKL_TKN_U8_CORE_ID: 24356277e832SShreyas NC mconfig->core_id = tkn_elem->value; 24369c80c5a8STakashi Iwai break; 24376277e832SShreyas NC 24386277e832SShreyas NC case SKL_TKN_U8_MOD_TYPE: 24396277e832SShreyas NC mconfig->m_type = tkn_elem->value; 24406277e832SShreyas NC break; 24416277e832SShreyas NC 24426277e832SShreyas NC case SKL_TKN_U8_DEV_TYPE: 24436277e832SShreyas NC mconfig->dev_type = tkn_elem->value; 24446277e832SShreyas NC break; 24456277e832SShreyas NC 24466277e832SShreyas NC case SKL_TKN_U8_HW_CONN_TYPE: 24476277e832SShreyas NC mconfig->hw_conn_type = tkn_elem->value; 24486277e832SShreyas NC break; 24496277e832SShreyas NC 24506277e832SShreyas NC case SKL_TKN_U16_MOD_INST_ID: 24516277e832SShreyas NC mconfig->id.instance_id = 24526277e832SShreyas NC tkn_elem->value; 24536277e832SShreyas NC break; 24546277e832SShreyas NC 24556277e832SShreyas NC case SKL_TKN_U32_MEM_PAGES: 24566277e832SShreyas NC case SKL_TKN_U32_MAX_MCPS: 24576277e832SShreyas NC case SKL_TKN_U32_OBS: 24586277e832SShreyas NC case SKL_TKN_U32_IBS: 24592b79b15cSColin Ian King ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_index, dir); 2460f6fa56e2SRamesh Babu if (ret < 0) 2461f6fa56e2SRamesh Babu return ret; 2462f6fa56e2SRamesh Babu 24636277e832SShreyas NC break; 24646277e832SShreyas NC 24656277e832SShreyas NC case SKL_TKN_U32_VBUS_ID: 24666277e832SShreyas NC mconfig->vbus_id = tkn_elem->value; 24676277e832SShreyas NC break; 24686277e832SShreyas NC 24696277e832SShreyas NC case SKL_TKN_U32_PARAMS_FIXUP: 24706277e832SShreyas NC mconfig->params_fixup = tkn_elem->value; 24716277e832SShreyas NC break; 24726277e832SShreyas NC 24736277e832SShreyas NC case SKL_TKN_U32_CONVERTER: 24746277e832SShreyas NC mconfig->converter = tkn_elem->value; 24756277e832SShreyas NC break; 24766277e832SShreyas NC 2477c0116be3SSubhransu S. Prusty case SKL_TKN_U32_D0I3_CAPS: 24786bd9dcf3SVinod Koul mconfig->d0i3_caps = tkn_elem->value; 24796bd9dcf3SVinod Koul break; 24806bd9dcf3SVinod Koul 24816277e832SShreyas NC case SKL_TKN_U32_PIPE_ID: 24826277e832SShreyas NC ret = skl_tplg_add_pipe(dev, 24836277e832SShreyas NC mconfig, skl, tkn_elem); 24846277e832SShreyas NC 2485081dc8abSGuneshwor Singh if (ret < 0) { 2486081dc8abSGuneshwor Singh if (ret == -EEXIST) { 24876277e832SShreyas NC is_pipe_exists = 1; 2488081dc8abSGuneshwor Singh break; 2489081dc8abSGuneshwor Singh } 2490081dc8abSGuneshwor Singh return is_pipe_exists; 2491081dc8abSGuneshwor Singh } 24926277e832SShreyas NC 24936277e832SShreyas NC break; 24946277e832SShreyas NC 2495f6fa56e2SRamesh Babu case SKL_TKN_U32_PIPE_CONFIG_ID: 2496f6fa56e2SRamesh Babu conf_idx = tkn_elem->value; 2497f6fa56e2SRamesh Babu break; 2498f6fa56e2SRamesh Babu 24996277e832SShreyas NC case SKL_TKN_U32_PIPE_CONN_TYPE: 25006277e832SShreyas NC case SKL_TKN_U32_PIPE_PRIORITY: 25016277e832SShreyas NC case SKL_TKN_U32_PIPE_MEM_PGS: 25028a0cb236SVinod Koul case SKL_TKN_U32_PMODE: 2503f6fa56e2SRamesh Babu case SKL_TKN_U32_PIPE_DIRECTION: 2504f6fa56e2SRamesh Babu case SKL_TKN_U32_NUM_CONFIGS: 25056277e832SShreyas NC if (is_pipe_exists) { 25066277e832SShreyas NC ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe, 25076277e832SShreyas NC tkn_elem->token, tkn_elem->value); 25086277e832SShreyas NC if (ret < 0) 25096277e832SShreyas NC return ret; 25106277e832SShreyas NC } 25116277e832SShreyas NC 25126277e832SShreyas NC break; 25136277e832SShreyas NC 2514f6fa56e2SRamesh Babu case SKL_TKN_U32_PATH_MEM_PGS: 2515f6fa56e2SRamesh Babu case SKL_TKN_U32_CFG_FREQ: 2516f6fa56e2SRamesh Babu case SKL_TKN_U8_CFG_CHAN: 2517f6fa56e2SRamesh Babu case SKL_TKN_U8_CFG_BPS: 2518f6fa56e2SRamesh Babu if (mconfig->pipe->nr_cfgs) { 2519f6fa56e2SRamesh Babu ret = skl_tplg_fill_pipe_cfg(dev, mconfig->pipe, 2520f6fa56e2SRamesh Babu tkn_elem->token, tkn_elem->value, 2521f6fa56e2SRamesh Babu conf_idx, dir); 2522f6fa56e2SRamesh Babu if (ret < 0) 2523f6fa56e2SRamesh Babu return ret; 2524f6fa56e2SRamesh Babu } 2525f6fa56e2SRamesh Babu break; 2526f6fa56e2SRamesh Babu 2527f6fa56e2SRamesh Babu case SKL_TKN_CFG_MOD_RES_ID: 2528f6fa56e2SRamesh Babu mconfig->mod_cfg[conf_idx].res_idx = tkn_elem->value; 2529f6fa56e2SRamesh Babu break; 2530f6fa56e2SRamesh Babu 2531f6fa56e2SRamesh Babu case SKL_TKN_CFG_MOD_FMT_ID: 2532f6fa56e2SRamesh Babu mconfig->mod_cfg[conf_idx].fmt_idx = tkn_elem->value; 2533f6fa56e2SRamesh Babu break; 2534f6fa56e2SRamesh Babu 25356277e832SShreyas NC /* 25366277e832SShreyas NC * SKL_TKN_U32_DIR_PIN_COUNT token has the value for both 25376277e832SShreyas NC * direction and the pin count. The first four bits represent 25386277e832SShreyas NC * direction and next four the pin count. 25396277e832SShreyas NC */ 25406277e832SShreyas NC case SKL_TKN_U32_DIR_PIN_COUNT: 25416277e832SShreyas NC dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK; 25426277e832SShreyas NC pin_index = (tkn_elem->value & 25436277e832SShreyas NC SKL_PIN_COUNT_MASK) >> 4; 25446277e832SShreyas NC 25456277e832SShreyas NC break; 25466277e832SShreyas NC 25476277e832SShreyas NC case SKL_TKN_U32_FMT_CH: 25486277e832SShreyas NC case SKL_TKN_U32_FMT_FREQ: 25496277e832SShreyas NC case SKL_TKN_U32_FMT_BIT_DEPTH: 25506277e832SShreyas NC case SKL_TKN_U32_FMT_SAMPLE_SIZE: 25516277e832SShreyas NC case SKL_TKN_U32_FMT_CH_CONFIG: 25526277e832SShreyas NC case SKL_TKN_U32_FMT_INTERLEAVE: 25536277e832SShreyas NC case SKL_TKN_U32_FMT_SAMPLE_TYPE: 25546277e832SShreyas NC case SKL_TKN_U32_FMT_CH_MAP: 2555f6fa56e2SRamesh Babu ret = skl_tplg_widget_fill_fmt(dev, iface, tkn_elem->token, 25566277e832SShreyas NC tkn_elem->value, dir, pin_index); 25576277e832SShreyas NC 25586277e832SShreyas NC if (ret < 0) 25596277e832SShreyas NC return ret; 25606277e832SShreyas NC 25616277e832SShreyas NC break; 25626277e832SShreyas NC 25636277e832SShreyas NC case SKL_TKN_U32_PIN_MOD_ID: 25646277e832SShreyas NC case SKL_TKN_U32_PIN_INST_ID: 2565d9561474SSriram Periyasamy case SKL_TKN_UUID: 25666277e832SShreyas NC ret = skl_tplg_fill_pins_info(dev, 25676277e832SShreyas NC mconfig, tkn_elem, dir, 25686277e832SShreyas NC pin_index); 25696277e832SShreyas NC if (ret < 0) 25706277e832SShreyas NC return ret; 25716277e832SShreyas NC 25726277e832SShreyas NC break; 25736277e832SShreyas NC 2574*a4ad42d2SKareem Shaik case SKL_TKN_U32_FMT_CFG_IDX: 2575*a4ad42d2SKareem Shaik if (tkn_elem->value > SKL_MAX_PARAMS_TYPES) 2576*a4ad42d2SKareem Shaik return -EINVAL; 2577*a4ad42d2SKareem Shaik 2578*a4ad42d2SKareem Shaik mconfig->fmt_cfg_idx = tkn_elem->value; 2579*a4ad42d2SKareem Shaik break; 2580*a4ad42d2SKareem Shaik 25816277e832SShreyas NC case SKL_TKN_U32_CAPS_SIZE: 2582*a4ad42d2SKareem Shaik mconfig->formats_config[mconfig->fmt_cfg_idx].caps_size = 25836277e832SShreyas NC tkn_elem->value; 25846277e832SShreyas NC 25856277e832SShreyas NC break; 25866277e832SShreyas NC 2587133e6e5cSShreyas NC case SKL_TKN_U32_CAPS_SET_PARAMS: 2588*a4ad42d2SKareem Shaik mconfig->formats_config[mconfig->fmt_cfg_idx].set_params = 2589133e6e5cSShreyas NC tkn_elem->value; 2590133e6e5cSShreyas NC break; 2591133e6e5cSShreyas NC 2592133e6e5cSShreyas NC case SKL_TKN_U32_CAPS_PARAMS_ID: 2593*a4ad42d2SKareem Shaik mconfig->formats_config[mconfig->fmt_cfg_idx].param_id = 2594133e6e5cSShreyas NC tkn_elem->value; 2595133e6e5cSShreyas NC break; 2596133e6e5cSShreyas NC 25976277e832SShreyas NC case SKL_TKN_U32_PROC_DOMAIN: 25986277e832SShreyas NC mconfig->domain = 25996277e832SShreyas NC tkn_elem->value; 26006277e832SShreyas NC 26016277e832SShreyas NC break; 26026277e832SShreyas NC 2603939df3adSRamesh Babu case SKL_TKN_U32_DMA_BUF_SIZE: 2604939df3adSRamesh Babu mconfig->dma_buffer_size = tkn_elem->value; 2605939df3adSRamesh Babu break; 2606939df3adSRamesh Babu 26076277e832SShreyas NC case SKL_TKN_U8_IN_PIN_TYPE: 26086277e832SShreyas NC case SKL_TKN_U8_OUT_PIN_TYPE: 26096277e832SShreyas NC case SKL_TKN_U8_CONN_TYPE: 26106277e832SShreyas NC break; 26116277e832SShreyas NC 26126277e832SShreyas NC default: 26136277e832SShreyas NC dev_err(dev, "Token %d not handled\n", 26146277e832SShreyas NC tkn_elem->token); 26156277e832SShreyas NC return -EINVAL; 26166277e832SShreyas NC } 26176277e832SShreyas NC 26186277e832SShreyas NC tkn_count++; 26196277e832SShreyas NC 26206277e832SShreyas NC return tkn_count; 26216277e832SShreyas NC } 26226277e832SShreyas NC 26236277e832SShreyas NC /* 26246277e832SShreyas NC * Parse the vendor array for specific tokens to construct 26256277e832SShreyas NC * module private data 26266277e832SShreyas NC */ 26276277e832SShreyas NC static int skl_tplg_get_tokens(struct device *dev, 2628bcc2a2dcSCezary Rojewski char *pvt_data, struct skl_dev *skl, 26296277e832SShreyas NC struct skl_module_cfg *mconfig, int block_size) 26306277e832SShreyas NC { 26316277e832SShreyas NC struct snd_soc_tplg_vendor_array *array; 26326277e832SShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem; 26336277e832SShreyas NC int tkn_count = 0, ret; 26346277e832SShreyas NC int off = 0, tuple_size = 0; 2635d9561474SSriram Periyasamy bool is_module_guid = true; 26366277e832SShreyas NC 26376277e832SShreyas NC if (block_size <= 0) 26386277e832SShreyas NC return -EINVAL; 26396277e832SShreyas NC 26406277e832SShreyas NC while (tuple_size < block_size) { 26416277e832SShreyas NC array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off); 26426277e832SShreyas NC 26436277e832SShreyas NC off += array->size; 26446277e832SShreyas NC 26456277e832SShreyas NC switch (array->type) { 26466277e832SShreyas NC case SND_SOC_TPLG_TUPLE_TYPE_STRING: 2647ecd286a9SColin Ian King dev_warn(dev, "no string tokens expected for skl tplg\n"); 26486277e832SShreyas NC continue; 26496277e832SShreyas NC 26506277e832SShreyas NC case SND_SOC_TPLG_TUPLE_TYPE_UUID: 2651d9561474SSriram Periyasamy if (is_module_guid) { 26529e0784d0SAndy Shevchenko ret = skl_tplg_get_uuid(dev, (guid_t *)mconfig->guid, 265322ebd666SSriram Periyasamy array->uuid); 2654d9561474SSriram Periyasamy is_module_guid = false; 2655d9561474SSriram Periyasamy } else { 2656d9561474SSriram Periyasamy ret = skl_tplg_get_token(dev, array->value, skl, 2657d9561474SSriram Periyasamy mconfig); 2658d9561474SSriram Periyasamy } 2659d9561474SSriram Periyasamy 26606277e832SShreyas NC if (ret < 0) 26616277e832SShreyas NC return ret; 26626277e832SShreyas NC 26636277e832SShreyas NC tuple_size += sizeof(*array->uuid); 26646277e832SShreyas NC 26656277e832SShreyas NC continue; 26666277e832SShreyas NC 26676277e832SShreyas NC default: 26686277e832SShreyas NC tkn_elem = array->value; 26696277e832SShreyas NC tkn_count = 0; 26706277e832SShreyas NC break; 26716277e832SShreyas NC } 26726277e832SShreyas NC 26736277e832SShreyas NC while (tkn_count <= (array->num_elems - 1)) { 26746277e832SShreyas NC ret = skl_tplg_get_token(dev, tkn_elem, 26756277e832SShreyas NC skl, mconfig); 26766277e832SShreyas NC 26776277e832SShreyas NC if (ret < 0) 26786277e832SShreyas NC return ret; 26796277e832SShreyas NC 26806277e832SShreyas NC tkn_count = tkn_count + ret; 26816277e832SShreyas NC tkn_elem++; 26826277e832SShreyas NC } 26836277e832SShreyas NC 26846277e832SShreyas NC tuple_size += tkn_count * sizeof(*tkn_elem); 26856277e832SShreyas NC } 26866277e832SShreyas NC 2687133e6e5cSShreyas NC return off; 26886277e832SShreyas NC } 26896277e832SShreyas NC 26906277e832SShreyas NC /* 26916277e832SShreyas NC * Every data block is preceded by a descriptor to read the number 26926277e832SShreyas NC * of data blocks, they type of the block and it's size 26936277e832SShreyas NC */ 26946277e832SShreyas NC static int skl_tplg_get_desc_blocks(struct device *dev, 26956277e832SShreyas NC struct snd_soc_tplg_vendor_array *array) 26966277e832SShreyas NC { 26976277e832SShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem; 26986277e832SShreyas NC 26996277e832SShreyas NC tkn_elem = array->value; 27006277e832SShreyas NC 27016277e832SShreyas NC switch (tkn_elem->token) { 27026277e832SShreyas NC case SKL_TKN_U8_NUM_BLOCKS: 27036277e832SShreyas NC case SKL_TKN_U8_BLOCK_TYPE: 27046277e832SShreyas NC case SKL_TKN_U16_BLOCK_SIZE: 27056277e832SShreyas NC return tkn_elem->value; 27066277e832SShreyas NC 27076277e832SShreyas NC default: 2708ecd286a9SColin Ian King dev_err(dev, "Invalid descriptor token %d\n", tkn_elem->token); 27096277e832SShreyas NC break; 27106277e832SShreyas NC } 27116277e832SShreyas NC 27126277e832SShreyas NC return -EINVAL; 27136277e832SShreyas NC } 27146277e832SShreyas NC 2715ac9391daSGuenter Roeck /* Functions to parse private data from configuration file format v4 */ 2716ac9391daSGuenter Roeck 2717ac9391daSGuenter Roeck /* 2718ac9391daSGuenter Roeck * Add pipeline from topology binary into driver pipeline list 2719ac9391daSGuenter Roeck * 2720ac9391daSGuenter Roeck * If already added we return that instance 2721ac9391daSGuenter Roeck * Otherwise we create a new instance and add into driver list 2722ac9391daSGuenter Roeck */ 2723ac9391daSGuenter Roeck static int skl_tplg_add_pipe_v4(struct device *dev, 2724bcc2a2dcSCezary Rojewski struct skl_module_cfg *mconfig, struct skl_dev *skl, 2725ac9391daSGuenter Roeck struct skl_dfw_v4_pipe *dfw_pipe) 2726ac9391daSGuenter Roeck { 2727ac9391daSGuenter Roeck struct skl_pipeline *ppl; 2728ac9391daSGuenter Roeck struct skl_pipe *pipe; 2729ac9391daSGuenter Roeck struct skl_pipe_params *params; 2730ac9391daSGuenter Roeck 2731ac9391daSGuenter Roeck list_for_each_entry(ppl, &skl->ppl_list, node) { 2732ac9391daSGuenter Roeck if (ppl->pipe->ppl_id == dfw_pipe->pipe_id) { 2733ac9391daSGuenter Roeck mconfig->pipe = ppl->pipe; 2734ac9391daSGuenter Roeck return 0; 2735ac9391daSGuenter Roeck } 2736ac9391daSGuenter Roeck } 2737ac9391daSGuenter Roeck 2738ac9391daSGuenter Roeck ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL); 2739ac9391daSGuenter Roeck if (!ppl) 2740ac9391daSGuenter Roeck return -ENOMEM; 2741ac9391daSGuenter Roeck 2742ac9391daSGuenter Roeck pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL); 2743ac9391daSGuenter Roeck if (!pipe) 2744ac9391daSGuenter Roeck return -ENOMEM; 2745ac9391daSGuenter Roeck 2746ac9391daSGuenter Roeck params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL); 2747ac9391daSGuenter Roeck if (!params) 2748ac9391daSGuenter Roeck return -ENOMEM; 2749ac9391daSGuenter Roeck 2750ac9391daSGuenter Roeck pipe->ppl_id = dfw_pipe->pipe_id; 2751ac9391daSGuenter Roeck pipe->memory_pages = dfw_pipe->memory_pages; 2752ac9391daSGuenter Roeck pipe->pipe_priority = dfw_pipe->pipe_priority; 2753ac9391daSGuenter Roeck pipe->conn_type = dfw_pipe->conn_type; 2754ac9391daSGuenter Roeck pipe->state = SKL_PIPE_INVALID; 2755ac9391daSGuenter Roeck pipe->p_params = params; 2756ac9391daSGuenter Roeck INIT_LIST_HEAD(&pipe->w_list); 2757ac9391daSGuenter Roeck 2758ac9391daSGuenter Roeck ppl->pipe = pipe; 2759ac9391daSGuenter Roeck list_add(&ppl->node, &skl->ppl_list); 2760ac9391daSGuenter Roeck 2761ac9391daSGuenter Roeck mconfig->pipe = pipe; 2762ac9391daSGuenter Roeck 2763ac9391daSGuenter Roeck return 0; 2764ac9391daSGuenter Roeck } 2765ac9391daSGuenter Roeck 2766ac9391daSGuenter Roeck static void skl_fill_module_pin_info_v4(struct skl_dfw_v4_module_pin *dfw_pin, 2767ac9391daSGuenter Roeck struct skl_module_pin *m_pin, 2768ac9391daSGuenter Roeck bool is_dynamic, int max_pin) 2769ac9391daSGuenter Roeck { 2770ac9391daSGuenter Roeck int i; 2771ac9391daSGuenter Roeck 2772ac9391daSGuenter Roeck for (i = 0; i < max_pin; i++) { 2773ac9391daSGuenter Roeck m_pin[i].id.module_id = dfw_pin[i].module_id; 2774ac9391daSGuenter Roeck m_pin[i].id.instance_id = dfw_pin[i].instance_id; 2775ac9391daSGuenter Roeck m_pin[i].in_use = false; 2776ac9391daSGuenter Roeck m_pin[i].is_dynamic = is_dynamic; 2777ac9391daSGuenter Roeck m_pin[i].pin_state = SKL_PIN_UNBIND; 2778ac9391daSGuenter Roeck } 2779ac9391daSGuenter Roeck } 2780ac9391daSGuenter Roeck 2781ac9391daSGuenter Roeck static void skl_tplg_fill_fmt_v4(struct skl_module_pin_fmt *dst_fmt, 2782ac9391daSGuenter Roeck struct skl_dfw_v4_module_fmt *src_fmt, 2783ac9391daSGuenter Roeck int pins) 2784ac9391daSGuenter Roeck { 2785ac9391daSGuenter Roeck int i; 2786ac9391daSGuenter Roeck 2787ac9391daSGuenter Roeck for (i = 0; i < pins; i++) { 2788ac9391daSGuenter Roeck dst_fmt[i].fmt.channels = src_fmt[i].channels; 2789ac9391daSGuenter Roeck dst_fmt[i].fmt.s_freq = src_fmt[i].freq; 2790ac9391daSGuenter Roeck dst_fmt[i].fmt.bit_depth = src_fmt[i].bit_depth; 2791ac9391daSGuenter Roeck dst_fmt[i].fmt.valid_bit_depth = src_fmt[i].valid_bit_depth; 2792ac9391daSGuenter Roeck dst_fmt[i].fmt.ch_cfg = src_fmt[i].ch_cfg; 2793ac9391daSGuenter Roeck dst_fmt[i].fmt.ch_map = src_fmt[i].ch_map; 2794ac9391daSGuenter Roeck dst_fmt[i].fmt.interleaving_style = 2795ac9391daSGuenter Roeck src_fmt[i].interleaving_style; 2796ac9391daSGuenter Roeck dst_fmt[i].fmt.sample_type = src_fmt[i].sample_type; 2797ac9391daSGuenter Roeck } 2798ac9391daSGuenter Roeck } 2799ac9391daSGuenter Roeck 2800ac9391daSGuenter Roeck static int skl_tplg_get_pvt_data_v4(struct snd_soc_tplg_dapm_widget *tplg_w, 2801bcc2a2dcSCezary Rojewski struct skl_dev *skl, struct device *dev, 2802ac9391daSGuenter Roeck struct skl_module_cfg *mconfig) 2803ac9391daSGuenter Roeck { 2804ac9391daSGuenter Roeck struct skl_dfw_v4_module *dfw = 2805ac9391daSGuenter Roeck (struct skl_dfw_v4_module *)tplg_w->priv.data; 2806ac9391daSGuenter Roeck int ret; 2807*a4ad42d2SKareem Shaik int idx = mconfig->fmt_cfg_idx; 2808ac9391daSGuenter Roeck 2809ac9391daSGuenter Roeck dev_dbg(dev, "Parsing Skylake v4 widget topology data\n"); 2810ac9391daSGuenter Roeck 2811ac9391daSGuenter Roeck ret = guid_parse(dfw->uuid, (guid_t *)mconfig->guid); 2812ac9391daSGuenter Roeck if (ret) 2813ac9391daSGuenter Roeck return ret; 2814ac9391daSGuenter Roeck mconfig->id.module_id = -1; 2815ac9391daSGuenter Roeck mconfig->id.instance_id = dfw->instance_id; 281684b71067SCezary Rojewski mconfig->module->resources[0].cpc = dfw->max_mcps / 1000; 2817ac9391daSGuenter Roeck mconfig->module->resources[0].ibs = dfw->ibs; 2818ac9391daSGuenter Roeck mconfig->module->resources[0].obs = dfw->obs; 2819ac9391daSGuenter Roeck mconfig->core_id = dfw->core_id; 2820ac9391daSGuenter Roeck mconfig->module->max_input_pins = dfw->max_in_queue; 2821ac9391daSGuenter Roeck mconfig->module->max_output_pins = dfw->max_out_queue; 2822ac9391daSGuenter Roeck mconfig->module->loadable = dfw->is_loadable; 2823ac9391daSGuenter Roeck skl_tplg_fill_fmt_v4(mconfig->module->formats[0].inputs, dfw->in_fmt, 2824ac9391daSGuenter Roeck MAX_IN_QUEUE); 2825ac9391daSGuenter Roeck skl_tplg_fill_fmt_v4(mconfig->module->formats[0].outputs, dfw->out_fmt, 2826ac9391daSGuenter Roeck MAX_OUT_QUEUE); 2827ac9391daSGuenter Roeck 2828ac9391daSGuenter Roeck mconfig->params_fixup = dfw->params_fixup; 2829ac9391daSGuenter Roeck mconfig->converter = dfw->converter; 2830ac9391daSGuenter Roeck mconfig->m_type = dfw->module_type; 2831ac9391daSGuenter Roeck mconfig->vbus_id = dfw->vbus_id; 2832ac9391daSGuenter Roeck mconfig->module->resources[0].is_pages = dfw->mem_pages; 2833ac9391daSGuenter Roeck 2834ac9391daSGuenter Roeck ret = skl_tplg_add_pipe_v4(dev, mconfig, skl, &dfw->pipe); 2835ac9391daSGuenter Roeck if (ret) 2836ac9391daSGuenter Roeck return ret; 2837ac9391daSGuenter Roeck 2838ac9391daSGuenter Roeck mconfig->dev_type = dfw->dev_type; 2839ac9391daSGuenter Roeck mconfig->hw_conn_type = dfw->hw_conn_type; 2840ac9391daSGuenter Roeck mconfig->time_slot = dfw->time_slot; 2841*a4ad42d2SKareem Shaik mconfig->formats_config[idx].caps_size = dfw->caps.caps_size; 2842ac9391daSGuenter Roeck 2843a86854d0SKees Cook mconfig->m_in_pin = devm_kcalloc(dev, 2844a86854d0SKees Cook MAX_IN_QUEUE, sizeof(*mconfig->m_in_pin), 2845ac9391daSGuenter Roeck GFP_KERNEL); 2846ac9391daSGuenter Roeck if (!mconfig->m_in_pin) 2847ac9391daSGuenter Roeck return -ENOMEM; 2848ac9391daSGuenter Roeck 2849a86854d0SKees Cook mconfig->m_out_pin = devm_kcalloc(dev, 2850a86854d0SKees Cook MAX_OUT_QUEUE, sizeof(*mconfig->m_out_pin), 2851ac9391daSGuenter Roeck GFP_KERNEL); 2852ac9391daSGuenter Roeck if (!mconfig->m_out_pin) 2853ac9391daSGuenter Roeck return -ENOMEM; 2854ac9391daSGuenter Roeck 2855ac9391daSGuenter Roeck skl_fill_module_pin_info_v4(dfw->in_pin, mconfig->m_in_pin, 2856ac9391daSGuenter Roeck dfw->is_dynamic_in_pin, 2857ac9391daSGuenter Roeck mconfig->module->max_input_pins); 2858ac9391daSGuenter Roeck skl_fill_module_pin_info_v4(dfw->out_pin, mconfig->m_out_pin, 2859ac9391daSGuenter Roeck dfw->is_dynamic_out_pin, 2860ac9391daSGuenter Roeck mconfig->module->max_output_pins); 2861ac9391daSGuenter Roeck 2862*a4ad42d2SKareem Shaik if (mconfig->formats_config[idx].caps_size) { 2863*a4ad42d2SKareem Shaik mconfig->formats_config[idx].set_params = dfw->caps.set_params; 2864*a4ad42d2SKareem Shaik mconfig->formats_config[idx].param_id = dfw->caps.param_id; 2865*a4ad42d2SKareem Shaik mconfig->formats_config[idx].caps = 2866*a4ad42d2SKareem Shaik devm_kzalloc(dev, mconfig->formats_config[idx].caps_size, 2867ac9391daSGuenter Roeck GFP_KERNEL); 2868*a4ad42d2SKareem Shaik if (!mconfig->formats_config[idx].caps) 2869ac9391daSGuenter Roeck return -ENOMEM; 2870*a4ad42d2SKareem Shaik memcpy(mconfig->formats_config[idx].caps, dfw->caps.caps, 2871ac9391daSGuenter Roeck dfw->caps.caps_size); 2872ac9391daSGuenter Roeck } 2873ac9391daSGuenter Roeck 2874ac9391daSGuenter Roeck return 0; 2875ac9391daSGuenter Roeck } 2876ac9391daSGuenter Roeck 2877*a4ad42d2SKareem Shaik static int skl_tplg_get_caps_data(struct device *dev, char *data, 2878*a4ad42d2SKareem Shaik struct skl_module_cfg *mconfig) 2879*a4ad42d2SKareem Shaik { 2880*a4ad42d2SKareem Shaik int idx = mconfig->fmt_cfg_idx; 2881*a4ad42d2SKareem Shaik 2882*a4ad42d2SKareem Shaik if (mconfig->formats_config[idx].caps_size > 0) { 2883*a4ad42d2SKareem Shaik mconfig->formats_config[idx].caps = 2884*a4ad42d2SKareem Shaik devm_kzalloc(dev, mconfig->formats_config[idx].caps_size, 2885*a4ad42d2SKareem Shaik GFP_KERNEL); 2886*a4ad42d2SKareem Shaik if (!mconfig->formats_config[idx].caps) 2887*a4ad42d2SKareem Shaik return -ENOMEM; 2888*a4ad42d2SKareem Shaik memcpy(mconfig->formats_config[idx].caps, data, 2889*a4ad42d2SKareem Shaik mconfig->formats_config[idx].caps_size); 2890*a4ad42d2SKareem Shaik } 2891*a4ad42d2SKareem Shaik 2892*a4ad42d2SKareem Shaik return mconfig->formats_config[idx].caps_size; 2893*a4ad42d2SKareem Shaik } 2894*a4ad42d2SKareem Shaik 28956277e832SShreyas NC /* 28966277e832SShreyas NC * Parse the private data for the token and corresponding value. 28976277e832SShreyas NC * The private data can have multiple data blocks. So, a data block 28986277e832SShreyas NC * is preceded by a descriptor for number of blocks and a descriptor 28996277e832SShreyas NC * for the type and size of the suceeding data block. 29006277e832SShreyas NC */ 29016277e832SShreyas NC static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w, 2902bcc2a2dcSCezary Rojewski struct skl_dev *skl, struct device *dev, 29036277e832SShreyas NC struct skl_module_cfg *mconfig) 29046277e832SShreyas NC { 29056277e832SShreyas NC struct snd_soc_tplg_vendor_array *array; 290611a790f9SPierre-Louis Bossart int num_blocks, block_size, block_type, off = 0; 29076277e832SShreyas NC char *data; 29086277e832SShreyas NC int ret; 29096277e832SShreyas NC 2910ac9391daSGuenter Roeck /* 2911ac9391daSGuenter Roeck * v4 configuration files have a valid UUID at the start of 2912ac9391daSGuenter Roeck * the widget's private data. 2913ac9391daSGuenter Roeck */ 2914ac9391daSGuenter Roeck if (uuid_is_valid((char *)tplg_w->priv.data)) 2915ac9391daSGuenter Roeck return skl_tplg_get_pvt_data_v4(tplg_w, skl, dev, mconfig); 2916ac9391daSGuenter Roeck 29176277e832SShreyas NC /* Read the NUM_DATA_BLOCKS descriptor */ 29186277e832SShreyas NC array = (struct snd_soc_tplg_vendor_array *)tplg_w->priv.data; 29196277e832SShreyas NC ret = skl_tplg_get_desc_blocks(dev, array); 29206277e832SShreyas NC if (ret < 0) 29216277e832SShreyas NC return ret; 29226277e832SShreyas NC num_blocks = ret; 29236277e832SShreyas NC 29246277e832SShreyas NC off += array->size; 29256277e832SShreyas NC /* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */ 29266277e832SShreyas NC while (num_blocks > 0) { 2927133e6e5cSShreyas NC array = (struct snd_soc_tplg_vendor_array *) 2928133e6e5cSShreyas NC (tplg_w->priv.data + off); 2929133e6e5cSShreyas NC 29306277e832SShreyas NC ret = skl_tplg_get_desc_blocks(dev, array); 29316277e832SShreyas NC 29326277e832SShreyas NC if (ret < 0) 29336277e832SShreyas NC return ret; 29346277e832SShreyas NC block_type = ret; 29356277e832SShreyas NC off += array->size; 29366277e832SShreyas NC 29376277e832SShreyas NC array = (struct snd_soc_tplg_vendor_array *) 29386277e832SShreyas NC (tplg_w->priv.data + off); 29396277e832SShreyas NC 29406277e832SShreyas NC ret = skl_tplg_get_desc_blocks(dev, array); 29416277e832SShreyas NC 29426277e832SShreyas NC if (ret < 0) 29436277e832SShreyas NC return ret; 29446277e832SShreyas NC block_size = ret; 29456277e832SShreyas NC off += array->size; 29466277e832SShreyas NC 29476277e832SShreyas NC array = (struct snd_soc_tplg_vendor_array *) 29486277e832SShreyas NC (tplg_w->priv.data + off); 29496277e832SShreyas NC 29506277e832SShreyas NC data = (tplg_w->priv.data + off); 29516277e832SShreyas NC 29526277e832SShreyas NC if (block_type == SKL_TYPE_TUPLE) { 29536277e832SShreyas NC ret = skl_tplg_get_tokens(dev, data, 29546277e832SShreyas NC skl, mconfig, block_size); 2955*a4ad42d2SKareem Shaik } else { 2956*a4ad42d2SKareem Shaik ret = skl_tplg_get_caps_data(dev, data, mconfig); 2957*a4ad42d2SKareem Shaik } 29586277e832SShreyas NC 29596277e832SShreyas NC if (ret < 0) 29606277e832SShreyas NC return ret; 29616277e832SShreyas NC 29626277e832SShreyas NC --num_blocks; 2963133e6e5cSShreyas NC off += ret; 29646277e832SShreyas NC } 29656277e832SShreyas NC 29666277e832SShreyas NC return 0; 29674cd9899fSHardik T Shah } 29684cd9899fSHardik T Shah 296956b03b4cSKuninori Morimoto static void skl_clear_pin_config(struct snd_soc_component *component, 2970fe3f4442SDharageswari R struct snd_soc_dapm_widget *w) 2971fe3f4442SDharageswari R { 2972fe3f4442SDharageswari R int i; 2973fe3f4442SDharageswari R struct skl_module_cfg *mconfig; 2974fe3f4442SDharageswari R struct skl_pipe *pipe; 2975fe3f4442SDharageswari R 297656b03b4cSKuninori Morimoto if (!strncmp(w->dapm->component->name, component->name, 297756b03b4cSKuninori Morimoto strlen(component->name))) { 2978fe3f4442SDharageswari R mconfig = w->priv; 2979fe3f4442SDharageswari R pipe = mconfig->pipe; 2980f6fa56e2SRamesh Babu for (i = 0; i < mconfig->module->max_input_pins; i++) { 2981fe3f4442SDharageswari R mconfig->m_in_pin[i].in_use = false; 2982fe3f4442SDharageswari R mconfig->m_in_pin[i].pin_state = SKL_PIN_UNBIND; 2983fe3f4442SDharageswari R } 2984f6fa56e2SRamesh Babu for (i = 0; i < mconfig->module->max_output_pins; i++) { 2985fe3f4442SDharageswari R mconfig->m_out_pin[i].in_use = false; 2986fe3f4442SDharageswari R mconfig->m_out_pin[i].pin_state = SKL_PIN_UNBIND; 2987fe3f4442SDharageswari R } 2988fe3f4442SDharageswari R pipe->state = SKL_PIPE_INVALID; 2989fe3f4442SDharageswari R mconfig->m_state = SKL_MODULE_UNINIT; 2990fe3f4442SDharageswari R } 2991fe3f4442SDharageswari R } 2992fe3f4442SDharageswari R 2993bcc2a2dcSCezary Rojewski void skl_cleanup_resources(struct skl_dev *skl) 2994fe3f4442SDharageswari R { 299556b03b4cSKuninori Morimoto struct snd_soc_component *soc_component = skl->component; 2996fe3f4442SDharageswari R struct snd_soc_dapm_widget *w; 2997fe3f4442SDharageswari R struct snd_soc_card *card; 2998fe3f4442SDharageswari R 299956b03b4cSKuninori Morimoto if (soc_component == NULL) 3000fe3f4442SDharageswari R return; 3001fe3f4442SDharageswari R 300256b03b4cSKuninori Morimoto card = soc_component->card; 3003fe3f4442SDharageswari R if (!card || !card->instantiated) 3004fe3f4442SDharageswari R return; 3005fe3f4442SDharageswari R 3006fe3f4442SDharageswari R list_for_each_entry(w, &card->widgets, list) { 3007bcc2a2dcSCezary Rojewski if (is_skl_dsp_widget_type(w, skl->dev) && w->priv != NULL) 300856b03b4cSKuninori Morimoto skl_clear_pin_config(soc_component, w); 3009fe3f4442SDharageswari R } 3010fe3f4442SDharageswari R 3011bcc2a2dcSCezary Rojewski skl_clear_module_cnt(skl->dsp); 3012fe3f4442SDharageswari R } 3013fe3f4442SDharageswari R 30143af36706SVinod Koul /* 30153af36706SVinod Koul * Topology core widget load callback 30163af36706SVinod Koul * 30173af36706SVinod Koul * This is used to save the private data for each widget which gives 30183af36706SVinod Koul * information to the driver about module and pipeline parameters which DSP 30193af36706SVinod Koul * FW expects like ids, resource values, formats etc 30203af36706SVinod Koul */ 3021c60b613aSLiam Girdwood static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, int index, 30223af36706SVinod Koul struct snd_soc_dapm_widget *w, 30233af36706SVinod Koul struct snd_soc_tplg_dapm_widget *tplg_w) 30243af36706SVinod Koul { 30253af36706SVinod Koul int ret; 302676f56faeSRakesh Ughreja struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt); 3027bcc2a2dcSCezary Rojewski struct skl_dev *skl = bus_to_skl(bus); 30283af36706SVinod Koul struct skl_module_cfg *mconfig; 30293af36706SVinod Koul 30303af36706SVinod Koul if (!tplg_w->priv.size) 30313af36706SVinod Koul goto bind_event; 30323af36706SVinod Koul 30333af36706SVinod Koul mconfig = devm_kzalloc(bus->dev, sizeof(*mconfig), GFP_KERNEL); 30343af36706SVinod Koul 30353af36706SVinod Koul if (!mconfig) 30363af36706SVinod Koul return -ENOMEM; 30373af36706SVinod Koul 3038f6fa56e2SRamesh Babu if (skl->nr_modules == 0) { 3039f6fa56e2SRamesh Babu mconfig->module = devm_kzalloc(bus->dev, 3040f6fa56e2SRamesh Babu sizeof(*mconfig->module), GFP_KERNEL); 3041f6fa56e2SRamesh Babu if (!mconfig->module) 3042f6fa56e2SRamesh Babu return -ENOMEM; 3043f6fa56e2SRamesh Babu } 3044f6fa56e2SRamesh Babu 30453af36706SVinod Koul w->priv = mconfig; 304609305da9SShreyas NC 3047b7c50555SVinod Koul /* 3048b7c50555SVinod Koul * module binary can be loaded later, so set it to query when 3049b7c50555SVinod Koul * module is load for a use case 3050b7c50555SVinod Koul */ 3051b7c50555SVinod Koul mconfig->id.module_id = -1; 30524cd9899fSHardik T Shah 3053*a4ad42d2SKareem Shaik /* To provide backward compatibility, set default as SKL_PARAM_INIT */ 3054*a4ad42d2SKareem Shaik mconfig->fmt_cfg_idx = SKL_PARAM_INIT; 3055*a4ad42d2SKareem Shaik 30566277e832SShreyas NC /* Parse private data for tuples */ 30576277e832SShreyas NC ret = skl_tplg_get_pvt_data(tplg_w, skl, bus->dev, mconfig); 30586277e832SShreyas NC if (ret < 0) 30596277e832SShreyas NC return ret; 3060d14700a0SVinod Koul 3061d14700a0SVinod Koul skl_debug_init_module(skl->debugfs, w, mconfig); 3062d14700a0SVinod Koul 30633af36706SVinod Koul bind_event: 30643af36706SVinod Koul if (tplg_w->event_type == 0) { 30653373f716SVinod Koul dev_dbg(bus->dev, "ASoC: No event handler required\n"); 30663af36706SVinod Koul return 0; 30673af36706SVinod Koul } 30683af36706SVinod Koul 30693af36706SVinod Koul ret = snd_soc_tplg_widget_bind_event(w, skl_tplg_widget_ops, 3070b663a8c5SJeeja KP ARRAY_SIZE(skl_tplg_widget_ops), 3071b663a8c5SJeeja KP tplg_w->event_type); 30723af36706SVinod Koul 30733af36706SVinod Koul if (ret) { 30743af36706SVinod Koul dev_err(bus->dev, "%s: No matching event handlers found for %d\n", 30753af36706SVinod Koul __func__, tplg_w->event_type); 30763af36706SVinod Koul return -EINVAL; 30773af36706SVinod Koul } 30783af36706SVinod Koul 30793af36706SVinod Koul return 0; 30803af36706SVinod Koul } 30813af36706SVinod Koul 3082140adfbaSJeeja KP static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be, 3083140adfbaSJeeja KP struct snd_soc_tplg_bytes_control *bc) 3084140adfbaSJeeja KP { 3085140adfbaSJeeja KP struct skl_algo_data *ac; 3086140adfbaSJeeja KP struct skl_dfw_algo_data *dfw_ac = 3087140adfbaSJeeja KP (struct skl_dfw_algo_data *)bc->priv.data; 3088140adfbaSJeeja KP 3089140adfbaSJeeja KP ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL); 3090140adfbaSJeeja KP if (!ac) 3091140adfbaSJeeja KP return -ENOMEM; 3092140adfbaSJeeja KP 3093140adfbaSJeeja KP /* Fill private data */ 3094140adfbaSJeeja KP ac->max = dfw_ac->max; 3095140adfbaSJeeja KP ac->param_id = dfw_ac->param_id; 3096140adfbaSJeeja KP ac->set_params = dfw_ac->set_params; 30970d682104SDharageswari R ac->size = dfw_ac->max; 3098140adfbaSJeeja KP 3099140adfbaSJeeja KP if (ac->max) { 3100431b67c2SPierre-Louis Bossart ac->params = devm_kzalloc(dev, ac->max, GFP_KERNEL); 3101140adfbaSJeeja KP if (!ac->params) 3102140adfbaSJeeja KP return -ENOMEM; 3103140adfbaSJeeja KP 3104140adfbaSJeeja KP memcpy(ac->params, dfw_ac->params, ac->max); 3105140adfbaSJeeja KP } 3106140adfbaSJeeja KP 3107140adfbaSJeeja KP be->dobj.private = ac; 3108140adfbaSJeeja KP return 0; 3109140adfbaSJeeja KP } 3110140adfbaSJeeja KP 31117a1b749bSDharageswari R static int skl_init_enum_data(struct device *dev, struct soc_enum *se, 31127a1b749bSDharageswari R struct snd_soc_tplg_enum_control *ec) 31137a1b749bSDharageswari R { 31147a1b749bSDharageswari R 31157a1b749bSDharageswari R void *data; 31167a1b749bSDharageswari R 31177a1b749bSDharageswari R if (ec->priv.size) { 31187a1b749bSDharageswari R data = devm_kzalloc(dev, sizeof(ec->priv.size), GFP_KERNEL); 31197a1b749bSDharageswari R if (!data) 31207a1b749bSDharageswari R return -ENOMEM; 31217a1b749bSDharageswari R memcpy(data, ec->priv.data, ec->priv.size); 31227a1b749bSDharageswari R se->dobj.private = data; 31237a1b749bSDharageswari R } 31247a1b749bSDharageswari R 31257a1b749bSDharageswari R return 0; 31267a1b749bSDharageswari R 31277a1b749bSDharageswari R } 31287a1b749bSDharageswari R 3129140adfbaSJeeja KP static int skl_tplg_control_load(struct snd_soc_component *cmpnt, 3130c60b613aSLiam Girdwood int index, 3131140adfbaSJeeja KP struct snd_kcontrol_new *kctl, 3132140adfbaSJeeja KP struct snd_soc_tplg_ctl_hdr *hdr) 3133140adfbaSJeeja KP { 3134140adfbaSJeeja KP struct soc_bytes_ext *sb; 3135140adfbaSJeeja KP struct snd_soc_tplg_bytes_control *tplg_bc; 31367a1b749bSDharageswari R struct snd_soc_tplg_enum_control *tplg_ec; 313776f56faeSRakesh Ughreja struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt); 31387a1b749bSDharageswari R struct soc_enum *se; 3139140adfbaSJeeja KP 3140140adfbaSJeeja KP switch (hdr->ops.info) { 3141140adfbaSJeeja KP case SND_SOC_TPLG_CTL_BYTES: 3142140adfbaSJeeja KP tplg_bc = container_of(hdr, 3143140adfbaSJeeja KP struct snd_soc_tplg_bytes_control, hdr); 3144140adfbaSJeeja KP if (kctl->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 3145140adfbaSJeeja KP sb = (struct soc_bytes_ext *)kctl->private_value; 3146140adfbaSJeeja KP if (tplg_bc->priv.size) 3147140adfbaSJeeja KP return skl_init_algo_data( 3148140adfbaSJeeja KP bus->dev, sb, tplg_bc); 3149140adfbaSJeeja KP } 3150140adfbaSJeeja KP break; 3151140adfbaSJeeja KP 31527a1b749bSDharageswari R case SND_SOC_TPLG_CTL_ENUM: 31537a1b749bSDharageswari R tplg_ec = container_of(hdr, 31547a1b749bSDharageswari R struct snd_soc_tplg_enum_control, hdr); 31552d744ecfSMateusz Gorski if (kctl->access & SNDRV_CTL_ELEM_ACCESS_READ) { 31567a1b749bSDharageswari R se = (struct soc_enum *)kctl->private_value; 31577a1b749bSDharageswari R if (tplg_ec->priv.size) 31582d744ecfSMateusz Gorski skl_init_enum_data(bus->dev, se, tplg_ec); 31597a1b749bSDharageswari R } 31602d744ecfSMateusz Gorski 31612d744ecfSMateusz Gorski /* 31622d744ecfSMateusz Gorski * now that the control initializations are done, remove 31632d744ecfSMateusz Gorski * write permission for the DMIC configuration enums to 31642d744ecfSMateusz Gorski * avoid conflicts between NHLT settings and user interaction 31652d744ecfSMateusz Gorski */ 31662d744ecfSMateusz Gorski 31672d744ecfSMateusz Gorski if (hdr->ops.get == SKL_CONTROL_TYPE_MULTI_IO_SELECT_DMIC) 31682d744ecfSMateusz Gorski kctl->access = SNDRV_CTL_ELEM_ACCESS_READ; 31692d744ecfSMateusz Gorski 31707a1b749bSDharageswari R break; 31717a1b749bSDharageswari R 3172140adfbaSJeeja KP default: 31734362934aSNaveen Manohar dev_dbg(bus->dev, "Control load not supported %d:%d:%d\n", 3174140adfbaSJeeja KP hdr->ops.get, hdr->ops.put, hdr->ops.info); 3175140adfbaSJeeja KP break; 3176140adfbaSJeeja KP } 3177140adfbaSJeeja KP 3178140adfbaSJeeja KP return 0; 3179140adfbaSJeeja KP } 3180140adfbaSJeeja KP 3181541070ceSShreyas NC static int skl_tplg_fill_str_mfest_tkn(struct device *dev, 3182541070ceSShreyas NC struct snd_soc_tplg_vendor_string_elem *str_elem, 3183bcc2a2dcSCezary Rojewski struct skl_dev *skl) 3184541070ceSShreyas NC { 3185541070ceSShreyas NC int tkn_count = 0; 3186541070ceSShreyas NC static int ref_count; 3187541070ceSShreyas NC 3188541070ceSShreyas NC switch (str_elem->token) { 3189541070ceSShreyas NC case SKL_TKN_STR_LIB_NAME: 3190bcc2a2dcSCezary Rojewski if (ref_count > skl->lib_count - 1) { 3191541070ceSShreyas NC ref_count = 0; 3192541070ceSShreyas NC return -EINVAL; 3193541070ceSShreyas NC } 3194541070ceSShreyas NC 3195bcc2a2dcSCezary Rojewski strncpy(skl->lib_info[ref_count].name, 3196eee0e16fSJeeja KP str_elem->string, 3197bcc2a2dcSCezary Rojewski ARRAY_SIZE(skl->lib_info[ref_count].name)); 3198541070ceSShreyas NC ref_count++; 3199541070ceSShreyas NC break; 3200541070ceSShreyas NC 3201541070ceSShreyas NC default: 3202ecd286a9SColin Ian King dev_err(dev, "Not a string token %d\n", str_elem->token); 3203541070ceSShreyas NC break; 3204541070ceSShreyas NC } 3205db6ed55dSShreyas NC tkn_count++; 3206541070ceSShreyas NC 3207541070ceSShreyas NC return tkn_count; 3208541070ceSShreyas NC } 3209541070ceSShreyas NC 3210541070ceSShreyas NC static int skl_tplg_get_str_tkn(struct device *dev, 3211541070ceSShreyas NC struct snd_soc_tplg_vendor_array *array, 3212bcc2a2dcSCezary Rojewski struct skl_dev *skl) 3213541070ceSShreyas NC { 3214541070ceSShreyas NC int tkn_count = 0, ret; 3215541070ceSShreyas NC struct snd_soc_tplg_vendor_string_elem *str_elem; 3216541070ceSShreyas NC 3217541070ceSShreyas NC str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value; 3218541070ceSShreyas NC while (tkn_count < array->num_elems) { 3219eee0e16fSJeeja KP ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, skl); 3220541070ceSShreyas NC str_elem++; 3221541070ceSShreyas NC 3222541070ceSShreyas NC if (ret < 0) 3223541070ceSShreyas NC return ret; 3224541070ceSShreyas NC 3225541070ceSShreyas NC tkn_count = tkn_count + ret; 3226541070ceSShreyas NC } 3227541070ceSShreyas NC 3228541070ceSShreyas NC return tkn_count; 3229541070ceSShreyas NC } 3230541070ceSShreyas NC 3231db6ed55dSShreyas NC static int skl_tplg_manifest_fill_fmt(struct device *dev, 3232db6ed55dSShreyas NC struct skl_module_iface *fmt, 3233db6ed55dSShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem, 3234db6ed55dSShreyas NC u32 dir, int fmt_idx) 3235db6ed55dSShreyas NC { 3236db6ed55dSShreyas NC struct skl_module_pin_fmt *dst_fmt; 3237db6ed55dSShreyas NC struct skl_module_fmt *mod_fmt; 3238db6ed55dSShreyas NC int ret; 3239db6ed55dSShreyas NC 3240db6ed55dSShreyas NC if (!fmt) 3241db6ed55dSShreyas NC return -EINVAL; 3242db6ed55dSShreyas NC 3243db6ed55dSShreyas NC switch (dir) { 3244db6ed55dSShreyas NC case SKL_DIR_IN: 3245db6ed55dSShreyas NC dst_fmt = &fmt->inputs[fmt_idx]; 3246db6ed55dSShreyas NC break; 3247db6ed55dSShreyas NC 3248db6ed55dSShreyas NC case SKL_DIR_OUT: 3249db6ed55dSShreyas NC dst_fmt = &fmt->outputs[fmt_idx]; 3250db6ed55dSShreyas NC break; 3251db6ed55dSShreyas NC 3252db6ed55dSShreyas NC default: 3253db6ed55dSShreyas NC dev_err(dev, "Invalid direction: %d\n", dir); 3254db6ed55dSShreyas NC return -EINVAL; 3255db6ed55dSShreyas NC } 3256db6ed55dSShreyas NC 3257db6ed55dSShreyas NC mod_fmt = &dst_fmt->fmt; 3258db6ed55dSShreyas NC 3259db6ed55dSShreyas NC switch (tkn_elem->token) { 3260db6ed55dSShreyas NC case SKL_TKN_MM_U32_INTF_PIN_ID: 3261db6ed55dSShreyas NC dst_fmt->id = tkn_elem->value; 3262db6ed55dSShreyas NC break; 3263db6ed55dSShreyas NC 3264db6ed55dSShreyas NC default: 3265db6ed55dSShreyas NC ret = skl_tplg_fill_fmt(dev, mod_fmt, tkn_elem->token, 3266db6ed55dSShreyas NC tkn_elem->value); 3267db6ed55dSShreyas NC if (ret < 0) 3268db6ed55dSShreyas NC return ret; 3269db6ed55dSShreyas NC break; 3270db6ed55dSShreyas NC } 3271db6ed55dSShreyas NC 3272db6ed55dSShreyas NC return 0; 3273db6ed55dSShreyas NC } 3274db6ed55dSShreyas NC 3275db6ed55dSShreyas NC static int skl_tplg_fill_mod_info(struct device *dev, 3276db6ed55dSShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem, 3277db6ed55dSShreyas NC struct skl_module *mod) 3278db6ed55dSShreyas NC { 3279db6ed55dSShreyas NC 3280db6ed55dSShreyas NC if (!mod) 3281db6ed55dSShreyas NC return -EINVAL; 3282db6ed55dSShreyas NC 3283db6ed55dSShreyas NC switch (tkn_elem->token) { 3284db6ed55dSShreyas NC case SKL_TKN_U8_IN_PIN_TYPE: 3285db6ed55dSShreyas NC mod->input_pin_type = tkn_elem->value; 3286db6ed55dSShreyas NC break; 3287db6ed55dSShreyas NC 3288db6ed55dSShreyas NC case SKL_TKN_U8_OUT_PIN_TYPE: 3289db6ed55dSShreyas NC mod->output_pin_type = tkn_elem->value; 3290db6ed55dSShreyas NC break; 3291db6ed55dSShreyas NC 3292db6ed55dSShreyas NC case SKL_TKN_U8_IN_QUEUE_COUNT: 3293db6ed55dSShreyas NC mod->max_input_pins = tkn_elem->value; 3294db6ed55dSShreyas NC break; 3295db6ed55dSShreyas NC 3296db6ed55dSShreyas NC case SKL_TKN_U8_OUT_QUEUE_COUNT: 3297db6ed55dSShreyas NC mod->max_output_pins = tkn_elem->value; 3298db6ed55dSShreyas NC break; 3299db6ed55dSShreyas NC 3300db6ed55dSShreyas NC case SKL_TKN_MM_U8_NUM_RES: 3301db6ed55dSShreyas NC mod->nr_resources = tkn_elem->value; 3302db6ed55dSShreyas NC break; 3303db6ed55dSShreyas NC 3304db6ed55dSShreyas NC case SKL_TKN_MM_U8_NUM_INTF: 3305db6ed55dSShreyas NC mod->nr_interfaces = tkn_elem->value; 3306db6ed55dSShreyas NC break; 3307db6ed55dSShreyas NC 3308db6ed55dSShreyas NC default: 3309db6ed55dSShreyas NC dev_err(dev, "Invalid mod info token %d", tkn_elem->token); 3310db6ed55dSShreyas NC return -EINVAL; 3311db6ed55dSShreyas NC } 3312db6ed55dSShreyas NC 3313db6ed55dSShreyas NC return 0; 3314db6ed55dSShreyas NC } 3315db6ed55dSShreyas NC 3316db6ed55dSShreyas NC 3317541070ceSShreyas NC static int skl_tplg_get_int_tkn(struct device *dev, 3318541070ceSShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem, 3319bcc2a2dcSCezary Rojewski struct skl_dev *skl) 3320541070ceSShreyas NC { 3321d00cc2f1SGustavo A. R. Silva int tkn_count = 0, ret; 3322db6ed55dSShreyas NC static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx; 3323db6ed55dSShreyas NC struct skl_module_res *res = NULL; 3324db6ed55dSShreyas NC struct skl_module_iface *fmt = NULL; 3325db6ed55dSShreyas NC struct skl_module *mod = NULL; 332643762355SPradeep Tewani static struct skl_astate_param *astate_table; 332743762355SPradeep Tewani static int astate_cfg_idx, count; 3328db6ed55dSShreyas NC int i; 3329d00cc2f1SGustavo A. R. Silva size_t size; 3330db6ed55dSShreyas NC 3331db6ed55dSShreyas NC if (skl->modules) { 3332db6ed55dSShreyas NC mod = skl->modules[mod_idx]; 3333db6ed55dSShreyas NC res = &mod->resources[res_val_idx]; 3334db6ed55dSShreyas NC fmt = &mod->formats[intf_val_idx]; 3335db6ed55dSShreyas NC } 3336541070ceSShreyas NC 3337541070ceSShreyas NC switch (tkn_elem->token) { 3338541070ceSShreyas NC case SKL_TKN_U32_LIB_COUNT: 3339bcc2a2dcSCezary Rojewski skl->lib_count = tkn_elem->value; 3340db6ed55dSShreyas NC break; 3341db6ed55dSShreyas NC 3342db6ed55dSShreyas NC case SKL_TKN_U8_NUM_MOD: 3343db6ed55dSShreyas NC skl->nr_modules = tkn_elem->value; 3344db6ed55dSShreyas NC skl->modules = devm_kcalloc(dev, skl->nr_modules, 3345db6ed55dSShreyas NC sizeof(*skl->modules), GFP_KERNEL); 3346db6ed55dSShreyas NC if (!skl->modules) 3347db6ed55dSShreyas NC return -ENOMEM; 3348db6ed55dSShreyas NC 3349db6ed55dSShreyas NC for (i = 0; i < skl->nr_modules; i++) { 3350db6ed55dSShreyas NC skl->modules[i] = devm_kzalloc(dev, 3351db6ed55dSShreyas NC sizeof(struct skl_module), GFP_KERNEL); 3352db6ed55dSShreyas NC if (!skl->modules[i]) 3353db6ed55dSShreyas NC return -ENOMEM; 3354db6ed55dSShreyas NC } 3355db6ed55dSShreyas NC break; 3356db6ed55dSShreyas NC 3357db6ed55dSShreyas NC case SKL_TKN_MM_U8_MOD_IDX: 3358db6ed55dSShreyas NC mod_idx = tkn_elem->value; 3359db6ed55dSShreyas NC break; 3360db6ed55dSShreyas NC 336143762355SPradeep Tewani case SKL_TKN_U32_ASTATE_COUNT: 336243762355SPradeep Tewani if (astate_table != NULL) { 336343762355SPradeep Tewani dev_err(dev, "More than one entry for A-State count"); 336443762355SPradeep Tewani return -EINVAL; 336543762355SPradeep Tewani } 336643762355SPradeep Tewani 336743762355SPradeep Tewani if (tkn_elem->value > SKL_MAX_ASTATE_CFG) { 336843762355SPradeep Tewani dev_err(dev, "Invalid A-State count %d\n", 336943762355SPradeep Tewani tkn_elem->value); 337043762355SPradeep Tewani return -EINVAL; 337143762355SPradeep Tewani } 337243762355SPradeep Tewani 3373d00cc2f1SGustavo A. R. Silva size = struct_size(skl->cfg.astate_cfg, astate_table, 3374d00cc2f1SGustavo A. R. Silva tkn_elem->value); 337543762355SPradeep Tewani skl->cfg.astate_cfg = devm_kzalloc(dev, size, GFP_KERNEL); 337643762355SPradeep Tewani if (!skl->cfg.astate_cfg) 337743762355SPradeep Tewani return -ENOMEM; 337843762355SPradeep Tewani 337943762355SPradeep Tewani astate_table = skl->cfg.astate_cfg->astate_table; 338043762355SPradeep Tewani count = skl->cfg.astate_cfg->count = tkn_elem->value; 338143762355SPradeep Tewani break; 338243762355SPradeep Tewani 338343762355SPradeep Tewani case SKL_TKN_U32_ASTATE_IDX: 338443762355SPradeep Tewani if (tkn_elem->value >= count) { 338543762355SPradeep Tewani dev_err(dev, "Invalid A-State index %d\n", 338643762355SPradeep Tewani tkn_elem->value); 338743762355SPradeep Tewani return -EINVAL; 338843762355SPradeep Tewani } 338943762355SPradeep Tewani 339043762355SPradeep Tewani astate_cfg_idx = tkn_elem->value; 339143762355SPradeep Tewani break; 339243762355SPradeep Tewani 339343762355SPradeep Tewani case SKL_TKN_U32_ASTATE_KCPS: 339443762355SPradeep Tewani astate_table[astate_cfg_idx].kcps = tkn_elem->value; 339543762355SPradeep Tewani break; 339643762355SPradeep Tewani 339743762355SPradeep Tewani case SKL_TKN_U32_ASTATE_CLK_SRC: 339843762355SPradeep Tewani astate_table[astate_cfg_idx].clk_src = tkn_elem->value; 339943762355SPradeep Tewani break; 340043762355SPradeep Tewani 3401db6ed55dSShreyas NC case SKL_TKN_U8_IN_PIN_TYPE: 3402db6ed55dSShreyas NC case SKL_TKN_U8_OUT_PIN_TYPE: 3403db6ed55dSShreyas NC case SKL_TKN_U8_IN_QUEUE_COUNT: 3404db6ed55dSShreyas NC case SKL_TKN_U8_OUT_QUEUE_COUNT: 3405db6ed55dSShreyas NC case SKL_TKN_MM_U8_NUM_RES: 3406db6ed55dSShreyas NC case SKL_TKN_MM_U8_NUM_INTF: 3407db6ed55dSShreyas NC ret = skl_tplg_fill_mod_info(dev, tkn_elem, mod); 3408db6ed55dSShreyas NC if (ret < 0) 3409db6ed55dSShreyas NC return ret; 3410db6ed55dSShreyas NC break; 3411db6ed55dSShreyas NC 3412db6ed55dSShreyas NC case SKL_TKN_U32_DIR_PIN_COUNT: 3413db6ed55dSShreyas NC dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK; 3414db6ed55dSShreyas NC pin_idx = (tkn_elem->value & SKL_PIN_COUNT_MASK) >> 4; 3415db6ed55dSShreyas NC break; 3416db6ed55dSShreyas NC 3417db6ed55dSShreyas NC case SKL_TKN_MM_U32_RES_ID: 3418db6ed55dSShreyas NC if (!res) 3419db6ed55dSShreyas NC return -EINVAL; 3420db6ed55dSShreyas NC 3421db6ed55dSShreyas NC res->id = tkn_elem->value; 3422db6ed55dSShreyas NC res_val_idx = tkn_elem->value; 3423db6ed55dSShreyas NC break; 3424db6ed55dSShreyas NC 3425db6ed55dSShreyas NC case SKL_TKN_MM_U32_FMT_ID: 3426db6ed55dSShreyas NC if (!fmt) 3427db6ed55dSShreyas NC return -EINVAL; 3428db6ed55dSShreyas NC 3429db6ed55dSShreyas NC fmt->fmt_idx = tkn_elem->value; 3430db6ed55dSShreyas NC intf_val_idx = tkn_elem->value; 3431db6ed55dSShreyas NC break; 3432db6ed55dSShreyas NC 3433db6ed55dSShreyas NC case SKL_TKN_MM_U32_CPS: 3434db6ed55dSShreyas NC case SKL_TKN_MM_U32_DMA_SIZE: 3435db6ed55dSShreyas NC case SKL_TKN_MM_U32_CPC: 3436db6ed55dSShreyas NC case SKL_TKN_U32_MEM_PAGES: 3437db6ed55dSShreyas NC case SKL_TKN_U32_OBS: 3438db6ed55dSShreyas NC case SKL_TKN_U32_IBS: 3439db6ed55dSShreyas NC case SKL_TKN_MM_U32_RES_PIN_ID: 3440db6ed55dSShreyas NC case SKL_TKN_MM_U32_PIN_BUF: 3441db6ed55dSShreyas NC ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_idx, dir); 3442db6ed55dSShreyas NC if (ret < 0) 3443db6ed55dSShreyas NC return ret; 3444db6ed55dSShreyas NC 3445db6ed55dSShreyas NC break; 3446db6ed55dSShreyas NC 3447db6ed55dSShreyas NC case SKL_TKN_MM_U32_NUM_IN_FMT: 3448db6ed55dSShreyas NC if (!fmt) 3449db6ed55dSShreyas NC return -EINVAL; 3450db6ed55dSShreyas NC 3451db6ed55dSShreyas NC res->nr_input_pins = tkn_elem->value; 3452db6ed55dSShreyas NC break; 3453db6ed55dSShreyas NC 3454db6ed55dSShreyas NC case SKL_TKN_MM_U32_NUM_OUT_FMT: 3455db6ed55dSShreyas NC if (!fmt) 3456db6ed55dSShreyas NC return -EINVAL; 3457db6ed55dSShreyas NC 3458db6ed55dSShreyas NC res->nr_output_pins = tkn_elem->value; 3459db6ed55dSShreyas NC break; 3460db6ed55dSShreyas NC 3461db6ed55dSShreyas NC case SKL_TKN_U32_FMT_CH: 3462db6ed55dSShreyas NC case SKL_TKN_U32_FMT_FREQ: 3463db6ed55dSShreyas NC case SKL_TKN_U32_FMT_BIT_DEPTH: 3464db6ed55dSShreyas NC case SKL_TKN_U32_FMT_SAMPLE_SIZE: 3465db6ed55dSShreyas NC case SKL_TKN_U32_FMT_CH_CONFIG: 3466db6ed55dSShreyas NC case SKL_TKN_U32_FMT_INTERLEAVE: 3467db6ed55dSShreyas NC case SKL_TKN_U32_FMT_SAMPLE_TYPE: 3468db6ed55dSShreyas NC case SKL_TKN_U32_FMT_CH_MAP: 3469db6ed55dSShreyas NC case SKL_TKN_MM_U32_INTF_PIN_ID: 3470db6ed55dSShreyas NC ret = skl_tplg_manifest_fill_fmt(dev, fmt, tkn_elem, 3471db6ed55dSShreyas NC dir, pin_idx); 3472db6ed55dSShreyas NC if (ret < 0) 3473db6ed55dSShreyas NC return ret; 3474541070ceSShreyas NC break; 3475541070ceSShreyas NC 3476541070ceSShreyas NC default: 3477ecd286a9SColin Ian King dev_err(dev, "Not a manifest token %d\n", tkn_elem->token); 3478541070ceSShreyas NC return -EINVAL; 3479541070ceSShreyas NC } 3480db6ed55dSShreyas NC tkn_count++; 3481541070ceSShreyas NC 3482541070ceSShreyas NC return tkn_count; 3483541070ceSShreyas NC } 3484541070ceSShreyas NC 3485541070ceSShreyas NC /* 3486541070ceSShreyas NC * Fill the manifest structure by parsing the tokens based on the 3487541070ceSShreyas NC * type. 3488541070ceSShreyas NC */ 3489541070ceSShreyas NC static int skl_tplg_get_manifest_tkn(struct device *dev, 3490bcc2a2dcSCezary Rojewski char *pvt_data, struct skl_dev *skl, 3491541070ceSShreyas NC int block_size) 3492541070ceSShreyas NC { 3493541070ceSShreyas NC int tkn_count = 0, ret; 3494541070ceSShreyas NC int off = 0, tuple_size = 0; 3495096769eaSAmadeusz Sławiński u8 uuid_index = 0; 3496541070ceSShreyas NC struct snd_soc_tplg_vendor_array *array; 3497541070ceSShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem; 3498541070ceSShreyas NC 3499541070ceSShreyas NC if (block_size <= 0) 3500541070ceSShreyas NC return -EINVAL; 3501541070ceSShreyas NC 3502541070ceSShreyas NC while (tuple_size < block_size) { 3503541070ceSShreyas NC array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off); 3504541070ceSShreyas NC off += array->size; 3505541070ceSShreyas NC switch (array->type) { 3506541070ceSShreyas NC case SND_SOC_TPLG_TUPLE_TYPE_STRING: 3507eee0e16fSJeeja KP ret = skl_tplg_get_str_tkn(dev, array, skl); 3508541070ceSShreyas NC 3509541070ceSShreyas NC if (ret < 0) 3510541070ceSShreyas NC return ret; 35110a716776SShreyas NC tkn_count = ret; 3512541070ceSShreyas NC 3513541070ceSShreyas NC tuple_size += tkn_count * 3514541070ceSShreyas NC sizeof(struct snd_soc_tplg_vendor_string_elem); 3515541070ceSShreyas NC continue; 3516541070ceSShreyas NC 3517541070ceSShreyas NC case SND_SOC_TPLG_TUPLE_TYPE_UUID: 3518096769eaSAmadeusz Sławiński if (array->uuid->token != SKL_TKN_UUID) { 3519096769eaSAmadeusz Sławiński dev_err(dev, "Not an UUID token: %d\n", 3520096769eaSAmadeusz Sławiński array->uuid->token); 3521096769eaSAmadeusz Sławiński return -EINVAL; 3522096769eaSAmadeusz Sławiński } 3523096769eaSAmadeusz Sławiński if (uuid_index >= skl->nr_modules) { 3524096769eaSAmadeusz Sławiński dev_err(dev, "Too many UUID tokens\n"); 3525096769eaSAmadeusz Sławiński return -EINVAL; 3526096769eaSAmadeusz Sławiński } 3527cade2f59SAndy Shevchenko import_guid(&skl->modules[uuid_index++]->uuid, 3528cade2f59SAndy Shevchenko array->uuid->uuid); 3529db6ed55dSShreyas NC 3530db6ed55dSShreyas NC tuple_size += sizeof(*array->uuid); 3531541070ceSShreyas NC continue; 3532541070ceSShreyas NC 3533541070ceSShreyas NC default: 3534541070ceSShreyas NC tkn_elem = array->value; 3535541070ceSShreyas NC tkn_count = 0; 3536541070ceSShreyas NC break; 3537541070ceSShreyas NC } 3538541070ceSShreyas NC 3539541070ceSShreyas NC while (tkn_count <= array->num_elems - 1) { 3540541070ceSShreyas NC ret = skl_tplg_get_int_tkn(dev, 3541eee0e16fSJeeja KP tkn_elem, skl); 3542541070ceSShreyas NC if (ret < 0) 3543541070ceSShreyas NC return ret; 3544541070ceSShreyas NC 3545541070ceSShreyas NC tkn_count = tkn_count + ret; 3546541070ceSShreyas NC tkn_elem++; 3547541070ceSShreyas NC } 35489fc129f6SShreyas NC tuple_size += (tkn_count * sizeof(*tkn_elem)); 3549541070ceSShreyas NC tkn_count = 0; 3550541070ceSShreyas NC } 3551541070ceSShreyas NC 35529fc129f6SShreyas NC return off; 3553541070ceSShreyas NC } 3554541070ceSShreyas NC 3555541070ceSShreyas NC /* 3556541070ceSShreyas NC * Parse manifest private data for tokens. The private data block is 3557541070ceSShreyas NC * preceded by descriptors for type and size of data block. 3558541070ceSShreyas NC */ 3559541070ceSShreyas NC static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest, 3560bcc2a2dcSCezary Rojewski struct device *dev, struct skl_dev *skl) 3561541070ceSShreyas NC { 3562541070ceSShreyas NC struct snd_soc_tplg_vendor_array *array; 3563541070ceSShreyas NC int num_blocks, block_size = 0, block_type, off = 0; 3564541070ceSShreyas NC char *data; 3565541070ceSShreyas NC int ret; 3566541070ceSShreyas NC 3567541070ceSShreyas NC /* Read the NUM_DATA_BLOCKS descriptor */ 3568541070ceSShreyas NC array = (struct snd_soc_tplg_vendor_array *)manifest->priv.data; 3569541070ceSShreyas NC ret = skl_tplg_get_desc_blocks(dev, array); 3570541070ceSShreyas NC if (ret < 0) 3571541070ceSShreyas NC return ret; 3572541070ceSShreyas NC num_blocks = ret; 3573541070ceSShreyas NC 3574541070ceSShreyas NC off += array->size; 3575541070ceSShreyas NC /* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */ 3576541070ceSShreyas NC while (num_blocks > 0) { 35779fc129f6SShreyas NC array = (struct snd_soc_tplg_vendor_array *) 35789fc129f6SShreyas NC (manifest->priv.data + off); 3579541070ceSShreyas NC ret = skl_tplg_get_desc_blocks(dev, array); 3580541070ceSShreyas NC 3581541070ceSShreyas NC if (ret < 0) 3582541070ceSShreyas NC return ret; 3583541070ceSShreyas NC block_type = ret; 3584541070ceSShreyas NC off += array->size; 3585541070ceSShreyas NC 3586541070ceSShreyas NC array = (struct snd_soc_tplg_vendor_array *) 3587541070ceSShreyas NC (manifest->priv.data + off); 3588541070ceSShreyas NC 3589541070ceSShreyas NC ret = skl_tplg_get_desc_blocks(dev, array); 3590541070ceSShreyas NC 3591541070ceSShreyas NC if (ret < 0) 3592541070ceSShreyas NC return ret; 3593541070ceSShreyas NC block_size = ret; 3594541070ceSShreyas NC off += array->size; 3595541070ceSShreyas NC 3596541070ceSShreyas NC array = (struct snd_soc_tplg_vendor_array *) 3597541070ceSShreyas NC (manifest->priv.data + off); 3598541070ceSShreyas NC 3599541070ceSShreyas NC data = (manifest->priv.data + off); 3600541070ceSShreyas NC 3601541070ceSShreyas NC if (block_type == SKL_TYPE_TUPLE) { 3602eee0e16fSJeeja KP ret = skl_tplg_get_manifest_tkn(dev, data, skl, 3603541070ceSShreyas NC block_size); 3604541070ceSShreyas NC 3605541070ceSShreyas NC if (ret < 0) 3606541070ceSShreyas NC return ret; 3607541070ceSShreyas NC 3608541070ceSShreyas NC --num_blocks; 3609541070ceSShreyas NC } else { 3610541070ceSShreyas NC return -EINVAL; 3611541070ceSShreyas NC } 36129fc129f6SShreyas NC off += ret; 3613541070ceSShreyas NC } 3614541070ceSShreyas NC 3615541070ceSShreyas NC return 0; 3616541070ceSShreyas NC } 3617541070ceSShreyas NC 3618c60b613aSLiam Girdwood static int skl_manifest_load(struct snd_soc_component *cmpnt, int index, 361915ecaba9SKranthi G struct snd_soc_tplg_manifest *manifest) 362015ecaba9SKranthi G { 362176f56faeSRakesh Ughreja struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt); 3622bcc2a2dcSCezary Rojewski struct skl_dev *skl = bus_to_skl(bus); 362315ecaba9SKranthi G 3624c15ad605SVinod Koul /* proceed only if we have private data defined */ 3625c15ad605SVinod Koul if (manifest->priv.size == 0) 3626c15ad605SVinod Koul return 0; 3627c15ad605SVinod Koul 3628eee0e16fSJeeja KP skl_tplg_get_manifest_data(manifest, bus->dev, skl); 3629541070ceSShreyas NC 3630bcc2a2dcSCezary Rojewski if (skl->lib_count > SKL_MAX_LIB) { 363115ecaba9SKranthi G dev_err(bus->dev, "Exceeding max Library count. Got:%d\n", 3632bcc2a2dcSCezary Rojewski skl->lib_count); 3633eee0e16fSJeeja KP return -EINVAL; 363415ecaba9SKranthi G } 363515ecaba9SKranthi G 3636eee0e16fSJeeja KP return 0; 363715ecaba9SKranthi G } 363815ecaba9SKranthi G 36392d744ecfSMateusz Gorski static void skl_tplg_complete(struct snd_soc_component *component) 36402d744ecfSMateusz Gorski { 36412d744ecfSMateusz Gorski struct snd_soc_dobj *dobj; 3642bef2897dSNick Desaulniers struct snd_soc_acpi_mach *mach; 3643bef2897dSNick Desaulniers struct snd_ctl_elem_value *val; 36442d744ecfSMateusz Gorski int i; 36452d744ecfSMateusz Gorski 3646bef2897dSNick Desaulniers val = kmalloc(sizeof(*val), GFP_KERNEL); 3647bef2897dSNick Desaulniers if (!val) 3648bef2897dSNick Desaulniers return; 3649bef2897dSNick Desaulniers 3650bef2897dSNick Desaulniers mach = dev_get_platdata(component->card->dev); 36512d744ecfSMateusz Gorski list_for_each_entry(dobj, &component->dobj_list, list) { 36522d744ecfSMateusz Gorski struct snd_kcontrol *kcontrol = dobj->control.kcontrol; 3653c1c3ba1fSRicardo Ribalda struct soc_enum *se; 3654c1c3ba1fSRicardo Ribalda char **texts; 36552d744ecfSMateusz Gorski char chan_text[4]; 36562d744ecfSMateusz Gorski 3657c1c3ba1fSRicardo Ribalda if (dobj->type != SND_SOC_DOBJ_ENUM || !kcontrol || 3658c1c3ba1fSRicardo Ribalda kcontrol->put != skl_tplg_multi_config_set_dmic) 36592d744ecfSMateusz Gorski continue; 3660c1c3ba1fSRicardo Ribalda 3661c1c3ba1fSRicardo Ribalda se = (struct soc_enum *)kcontrol->private_value; 3662c1c3ba1fSRicardo Ribalda texts = dobj->control.dtexts; 36632d744ecfSMateusz Gorski sprintf(chan_text, "c%d", mach->mach_params.dmic_num); 36642d744ecfSMateusz Gorski 36652d744ecfSMateusz Gorski for (i = 0; i < se->items; i++) { 36662d744ecfSMateusz Gorski if (strstr(texts[i], chan_text)) { 3667bef2897dSNick Desaulniers memset(val, 0, sizeof(*val)); 3668bef2897dSNick Desaulniers val->value.enumerated.item[0] = i; 3669bef2897dSNick Desaulniers kcontrol->put(kcontrol, val); 36702d744ecfSMateusz Gorski } 36712d744ecfSMateusz Gorski } 36722d744ecfSMateusz Gorski } 3673bef2897dSNick Desaulniers kfree(val); 36742d744ecfSMateusz Gorski } 36752d744ecfSMateusz Gorski 36763af36706SVinod Koul static struct snd_soc_tplg_ops skl_tplg_ops = { 36773af36706SVinod Koul .widget_load = skl_tplg_widget_load, 3678140adfbaSJeeja KP .control_load = skl_tplg_control_load, 3679140adfbaSJeeja KP .bytes_ext_ops = skl_tlv_ops, 3680140adfbaSJeeja KP .bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops), 36817a1b749bSDharageswari R .io_ops = skl_tplg_kcontrol_ops, 36827a1b749bSDharageswari R .io_ops_count = ARRAY_SIZE(skl_tplg_kcontrol_ops), 368315ecaba9SKranthi G .manifest = skl_manifest_load, 3684606e21fdSGuneshwor Singh .dai_load = skl_dai_load, 36852d744ecfSMateusz Gorski .complete = skl_tplg_complete, 36863af36706SVinod Koul }; 36873af36706SVinod Koul 3688287af4f9SJeeja KP /* 3689287af4f9SJeeja KP * A pipe can have multiple modules, each of them will be a DAPM widget as 3690287af4f9SJeeja KP * well. While managing a pipeline we need to get the list of all the 3691287af4f9SJeeja KP * widgets in a pipelines, so this helper - skl_tplg_create_pipe_widget_list() 3692287af4f9SJeeja KP * helps to get the SKL type widgets in that pipeline 3693287af4f9SJeeja KP */ 369456b03b4cSKuninori Morimoto static int skl_tplg_create_pipe_widget_list(struct snd_soc_component *component) 3695287af4f9SJeeja KP { 3696287af4f9SJeeja KP struct snd_soc_dapm_widget *w; 3697287af4f9SJeeja KP struct skl_module_cfg *mcfg = NULL; 3698287af4f9SJeeja KP struct skl_pipe_module *p_module = NULL; 3699287af4f9SJeeja KP struct skl_pipe *pipe; 3700287af4f9SJeeja KP 370156b03b4cSKuninori Morimoto list_for_each_entry(w, &component->card->widgets, list) { 3702a1f362d8SMark Brown if (is_skl_dsp_widget_type(w, component->dev) && w->priv) { 3703287af4f9SJeeja KP mcfg = w->priv; 3704287af4f9SJeeja KP pipe = mcfg->pipe; 3705287af4f9SJeeja KP 370656b03b4cSKuninori Morimoto p_module = devm_kzalloc(component->dev, 3707287af4f9SJeeja KP sizeof(*p_module), GFP_KERNEL); 3708287af4f9SJeeja KP if (!p_module) 3709287af4f9SJeeja KP return -ENOMEM; 3710287af4f9SJeeja KP 3711287af4f9SJeeja KP p_module->w = w; 3712287af4f9SJeeja KP list_add_tail(&p_module->node, &pipe->w_list); 3713287af4f9SJeeja KP } 3714287af4f9SJeeja KP } 3715287af4f9SJeeja KP 3716287af4f9SJeeja KP return 0; 3717287af4f9SJeeja KP } 3718287af4f9SJeeja KP 3719bcc2a2dcSCezary Rojewski static void skl_tplg_set_pipe_type(struct skl_dev *skl, struct skl_pipe *pipe) 3720f0aa94faSJeeja KP { 3721f0aa94faSJeeja KP struct skl_pipe_module *w_module; 3722f0aa94faSJeeja KP struct snd_soc_dapm_widget *w; 3723f0aa94faSJeeja KP struct skl_module_cfg *mconfig; 3724f0aa94faSJeeja KP bool host_found = false, link_found = false; 3725f0aa94faSJeeja KP 3726f0aa94faSJeeja KP list_for_each_entry(w_module, &pipe->w_list, node) { 3727f0aa94faSJeeja KP w = w_module->w; 3728f0aa94faSJeeja KP mconfig = w->priv; 3729f0aa94faSJeeja KP 3730f0aa94faSJeeja KP if (mconfig->dev_type == SKL_DEVICE_HDAHOST) 3731f0aa94faSJeeja KP host_found = true; 3732f0aa94faSJeeja KP else if (mconfig->dev_type != SKL_DEVICE_NONE) 3733f0aa94faSJeeja KP link_found = true; 3734f0aa94faSJeeja KP } 3735f0aa94faSJeeja KP 3736f0aa94faSJeeja KP if (host_found && link_found) 3737f0aa94faSJeeja KP pipe->passthru = true; 3738f0aa94faSJeeja KP else 3739f0aa94faSJeeja KP pipe->passthru = false; 3740f0aa94faSJeeja KP } 3741f0aa94faSJeeja KP 37423af36706SVinod Koul /* 37433af36706SVinod Koul * SKL topology init routine 37443af36706SVinod Koul */ 374576f56faeSRakesh Ughreja int skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus) 37463af36706SVinod Koul { 37473af36706SVinod Koul int ret; 37483af36706SVinod Koul const struct firmware *fw; 3749bcc2a2dcSCezary Rojewski struct skl_dev *skl = bus_to_skl(bus); 3750f0aa94faSJeeja KP struct skl_pipeline *ppl; 37513af36706SVinod Koul 37524b235c43SVinod Koul ret = request_firmware(&fw, skl->tplg_name, bus->dev); 37533af36706SVinod Koul if (ret < 0) { 37541b290ef0SMateusz Gorski char alt_tplg_name[64]; 37551b290ef0SMateusz Gorski 37561b290ef0SMateusz Gorski snprintf(alt_tplg_name, sizeof(alt_tplg_name), "%s-tplg.bin", 37571b290ef0SMateusz Gorski skl->mach->drv_name); 37581b290ef0SMateusz Gorski dev_info(bus->dev, "tplg fw %s load failed with %d, trying alternative tplg name %s", 37591b290ef0SMateusz Gorski skl->tplg_name, ret, alt_tplg_name); 37601b290ef0SMateusz Gorski 37611b290ef0SMateusz Gorski ret = request_firmware(&fw, alt_tplg_name, bus->dev); 37621b290ef0SMateusz Gorski if (!ret) 37631b290ef0SMateusz Gorski goto component_load; 37641b290ef0SMateusz Gorski 37651b290ef0SMateusz Gorski dev_info(bus->dev, "tplg %s failed with %d, falling back to dfw_sst.bin", 37661b290ef0SMateusz Gorski alt_tplg_name, ret); 37671b290ef0SMateusz Gorski 37684b235c43SVinod Koul ret = request_firmware(&fw, "dfw_sst.bin", bus->dev); 37694b235c43SVinod Koul if (ret < 0) { 37704b235c43SVinod Koul dev_err(bus->dev, "Fallback tplg fw %s load failed with %d\n", 37713af36706SVinod Koul "dfw_sst.bin", ret); 37723af36706SVinod Koul return ret; 37733af36706SVinod Koul } 37744b235c43SVinod Koul } 37753af36706SVinod Koul 37761b290ef0SMateusz Gorski component_load: 3777a5b8f71cSAmadeusz Sławiński ret = snd_soc_tplg_component_load(component, &skl_tplg_ops, fw); 37783af36706SVinod Koul if (ret < 0) { 37793af36706SVinod Koul dev_err(bus->dev, "tplg component load failed%d\n", ret); 37806f437917SAmadeusz Sławiński goto err; 37813af36706SVinod Koul } 37823af36706SVinod Koul 378356b03b4cSKuninori Morimoto ret = skl_tplg_create_pipe_widget_list(component); 37846f437917SAmadeusz Sławiński if (ret < 0) { 37856f437917SAmadeusz Sławiński dev_err(bus->dev, "tplg create pipe widget list failed%d\n", 37866f437917SAmadeusz Sławiński ret); 37876f437917SAmadeusz Sławiński goto err; 37886f437917SAmadeusz Sławiński } 3789d8018361SVinod Koul 3790f0aa94faSJeeja KP list_for_each_entry(ppl, &skl->ppl_list, node) 3791f0aa94faSJeeja KP skl_tplg_set_pipe_type(skl, ppl->pipe); 37923af36706SVinod Koul 37936f437917SAmadeusz Sławiński err: 37946f437917SAmadeusz Sławiński release_firmware(fw); 37956f437917SAmadeusz Sławiński return ret; 37963af36706SVinod Koul } 3797e79986ceSAmadeusz Sławiński 3798e79986ceSAmadeusz Sławiński void skl_tplg_exit(struct snd_soc_component *component, struct hdac_bus *bus) 3799e79986ceSAmadeusz Sławiński { 3800bcc2a2dcSCezary Rojewski struct skl_dev *skl = bus_to_skl(bus); 3801e79986ceSAmadeusz Sławiński struct skl_pipeline *ppl, *tmp; 3802e79986ceSAmadeusz Sławiński 3803e79986ceSAmadeusz Sławiński list_for_each_entry_safe(ppl, tmp, &skl->ppl_list, node) 3804e79986ceSAmadeusz Sławiński list_del(&ppl->node); 3805e79986ceSAmadeusz Sławiński 3806e79986ceSAmadeusz Sławiński /* clean up topology */ 3807a5b8f71cSAmadeusz Sławiński snd_soc_tplg_component_remove(component); 3808e79986ceSAmadeusz Sławiński } 3809