1e4e2d2f4SJeeja KP /* 2e4e2d2f4SJeeja KP * skl-topology.c - Implements Platform component ALSA controls/widget 3e4e2d2f4SJeeja KP * handlers. 4e4e2d2f4SJeeja KP * 5e4e2d2f4SJeeja KP * Copyright (C) 2014-2015 Intel Corp 6e4e2d2f4SJeeja KP * Author: Jeeja KP <jeeja.kp@intel.com> 7e4e2d2f4SJeeja KP * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8e4e2d2f4SJeeja KP * 9e4e2d2f4SJeeja KP * This program is free software; you can redistribute it and/or modify 10e4e2d2f4SJeeja KP * it under the terms of the GNU General Public License as version 2, as 11e4e2d2f4SJeeja KP * published by the Free Software Foundation. 12e4e2d2f4SJeeja KP * 13e4e2d2f4SJeeja KP * This program is distributed in the hope that it will be useful, but 14e4e2d2f4SJeeja KP * WITHOUT ANY WARRANTY; without even the implied warranty of 15e4e2d2f4SJeeja KP * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16e4e2d2f4SJeeja KP * General Public License for more details. 17e4e2d2f4SJeeja KP */ 18e4e2d2f4SJeeja KP 19e4e2d2f4SJeeja KP #include <linux/slab.h> 20e4e2d2f4SJeeja KP #include <linux/types.h> 21e4e2d2f4SJeeja KP #include <linux/firmware.h> 22e4e2d2f4SJeeja KP #include <sound/soc.h> 23e4e2d2f4SJeeja KP #include <sound/soc-topology.h> 246277e832SShreyas NC #include <uapi/sound/snd_sst_tokens.h> 25e4e2d2f4SJeeja KP #include "skl-sst-dsp.h" 26e4e2d2f4SJeeja KP #include "skl-sst-ipc.h" 27e4e2d2f4SJeeja KP #include "skl-topology.h" 28e4e2d2f4SJeeja KP #include "skl.h" 29e4e2d2f4SJeeja KP #include "skl-tplg-interface.h" 306c5768b3SDharageswari R #include "../common/sst-dsp.h" 316c5768b3SDharageswari R #include "../common/sst-dsp-priv.h" 32e4e2d2f4SJeeja KP 33f7590d4fSJeeja KP #define SKL_CH_FIXUP_MASK (1 << 0) 34f7590d4fSJeeja KP #define SKL_RATE_FIXUP_MASK (1 << 1) 35f7590d4fSJeeja KP #define SKL_FMT_FIXUP_MASK (1 << 2) 366277e832SShreyas NC #define SKL_IN_DIR_BIT_MASK BIT(0) 376277e832SShreyas NC #define SKL_PIN_COUNT_MASK GENMASK(7, 4) 38f7590d4fSJeeja KP 397a1b749bSDharageswari R static const int mic_mono_list[] = { 407a1b749bSDharageswari R 0, 1, 2, 3, 417a1b749bSDharageswari R }; 427a1b749bSDharageswari R static const int mic_stereo_list[][SKL_CH_STEREO] = { 437a1b749bSDharageswari R {0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}, 447a1b749bSDharageswari R }; 457a1b749bSDharageswari R static const int mic_trio_list[][SKL_CH_TRIO] = { 467a1b749bSDharageswari R {0, 1, 2}, {0, 1, 3}, {0, 2, 3}, {1, 2, 3}, 477a1b749bSDharageswari R }; 487a1b749bSDharageswari R static const int mic_quatro_list[][SKL_CH_QUATRO] = { 497a1b749bSDharageswari R {0, 1, 2, 3}, 507a1b749bSDharageswari R }; 517a1b749bSDharageswari R 52f6fa56e2SRamesh Babu #define CHECK_HW_PARAMS(ch, freq, bps, prm_ch, prm_freq, prm_bps) \ 53f6fa56e2SRamesh Babu ((ch == prm_ch) && (bps == prm_bps) && (freq == prm_freq)) 54f6fa56e2SRamesh Babu 55a83e3b4cSVinod Koul void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps) 56a83e3b4cSVinod Koul { 57a83e3b4cSVinod Koul struct skl_d0i3_data *d0i3 = &skl->skl_sst->d0i3; 58a83e3b4cSVinod Koul 59a83e3b4cSVinod Koul switch (caps) { 60a83e3b4cSVinod Koul case SKL_D0I3_NONE: 61a83e3b4cSVinod Koul d0i3->non_d0i3++; 62a83e3b4cSVinod Koul break; 63a83e3b4cSVinod Koul 64a83e3b4cSVinod Koul case SKL_D0I3_STREAMING: 65a83e3b4cSVinod Koul d0i3->streaming++; 66a83e3b4cSVinod Koul break; 67a83e3b4cSVinod Koul 68a83e3b4cSVinod Koul case SKL_D0I3_NON_STREAMING: 69a83e3b4cSVinod Koul d0i3->non_streaming++; 70a83e3b4cSVinod Koul break; 71a83e3b4cSVinod Koul } 72a83e3b4cSVinod Koul } 73a83e3b4cSVinod Koul 74a83e3b4cSVinod Koul void skl_tplg_d0i3_put(struct skl *skl, enum d0i3_capability caps) 75a83e3b4cSVinod Koul { 76a83e3b4cSVinod Koul struct skl_d0i3_data *d0i3 = &skl->skl_sst->d0i3; 77a83e3b4cSVinod Koul 78a83e3b4cSVinod Koul switch (caps) { 79a83e3b4cSVinod Koul case SKL_D0I3_NONE: 80a83e3b4cSVinod Koul d0i3->non_d0i3--; 81a83e3b4cSVinod Koul break; 82a83e3b4cSVinod Koul 83a83e3b4cSVinod Koul case SKL_D0I3_STREAMING: 84a83e3b4cSVinod Koul d0i3->streaming--; 85a83e3b4cSVinod Koul break; 86a83e3b4cSVinod Koul 87a83e3b4cSVinod Koul case SKL_D0I3_NON_STREAMING: 88a83e3b4cSVinod Koul d0i3->non_streaming--; 89a83e3b4cSVinod Koul break; 90a83e3b4cSVinod Koul } 91a83e3b4cSVinod Koul } 92a83e3b4cSVinod Koul 93e4e2d2f4SJeeja KP /* 94e4e2d2f4SJeeja KP * SKL DSP driver modelling uses only few DAPM widgets so for rest we will 95e4e2d2f4SJeeja KP * ignore. This helpers checks if the SKL driver handles this widget type 96e4e2d2f4SJeeja KP */ 97cb1f904dSGuneshwor Singh static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w, 98cb1f904dSGuneshwor Singh struct device *dev) 99e4e2d2f4SJeeja KP { 100cb1f904dSGuneshwor Singh if (w->dapm->dev != dev) 101cb1f904dSGuneshwor Singh return false; 102cb1f904dSGuneshwor Singh 103e4e2d2f4SJeeja KP switch (w->id) { 104e4e2d2f4SJeeja KP case snd_soc_dapm_dai_link: 105e4e2d2f4SJeeja KP case snd_soc_dapm_dai_in: 106e4e2d2f4SJeeja KP case snd_soc_dapm_aif_in: 107e4e2d2f4SJeeja KP case snd_soc_dapm_aif_out: 108e4e2d2f4SJeeja KP case snd_soc_dapm_dai_out: 109e4e2d2f4SJeeja KP case snd_soc_dapm_switch: 110e4e2d2f4SJeeja KP return false; 111e4e2d2f4SJeeja KP default: 112e4e2d2f4SJeeja KP return true; 113e4e2d2f4SJeeja KP } 114e4e2d2f4SJeeja KP } 115e4e2d2f4SJeeja KP 116e4e2d2f4SJeeja KP /* 117e4e2d2f4SJeeja KP * Each pipelines needs memory to be allocated. Check if we have free memory 1189ba8ffefSDharageswari.R * from available pool. 119e4e2d2f4SJeeja KP */ 1209ba8ffefSDharageswari.R static bool skl_is_pipe_mem_avail(struct skl *skl, 121e4e2d2f4SJeeja KP struct skl_module_cfg *mconfig) 122e4e2d2f4SJeeja KP { 123e4e2d2f4SJeeja KP struct skl_sst *ctx = skl->skl_sst; 124e4e2d2f4SJeeja KP 125e4e2d2f4SJeeja KP if (skl->resource.mem + mconfig->pipe->memory_pages > 126e4e2d2f4SJeeja KP skl->resource.max_mem) { 127e4e2d2f4SJeeja KP dev_err(ctx->dev, 128e4e2d2f4SJeeja KP "%s: module_id %d instance %d\n", __func__, 129e4e2d2f4SJeeja KP mconfig->id.module_id, 130e4e2d2f4SJeeja KP mconfig->id.instance_id); 131e4e2d2f4SJeeja KP dev_err(ctx->dev, 132e4e2d2f4SJeeja KP "exceeds ppl memory available %d mem %d\n", 133e4e2d2f4SJeeja KP skl->resource.max_mem, skl->resource.mem); 134e4e2d2f4SJeeja KP return false; 1359ba8ffefSDharageswari.R } else { 1369ba8ffefSDharageswari.R return true; 1379ba8ffefSDharageswari.R } 138e4e2d2f4SJeeja KP } 139e4e2d2f4SJeeja KP 1409ba8ffefSDharageswari.R /* 1419ba8ffefSDharageswari.R * Add the mem to the mem pool. This is freed when pipe is deleted. 1429ba8ffefSDharageswari.R * Note: DSP does actual memory management we only keep track for complete 1439ba8ffefSDharageswari.R * pool 1449ba8ffefSDharageswari.R */ 1459ba8ffefSDharageswari.R static void skl_tplg_alloc_pipe_mem(struct skl *skl, 1469ba8ffefSDharageswari.R struct skl_module_cfg *mconfig) 1479ba8ffefSDharageswari.R { 148e4e2d2f4SJeeja KP skl->resource.mem += mconfig->pipe->memory_pages; 149e4e2d2f4SJeeja KP } 150e4e2d2f4SJeeja KP 151e4e2d2f4SJeeja KP /* 152e4e2d2f4SJeeja KP * Pipeline needs needs DSP CPU resources for computation, this is 153e4e2d2f4SJeeja KP * quantified in MCPS (Million Clocks Per Second) required for module/pipe 154e4e2d2f4SJeeja KP * 155e4e2d2f4SJeeja KP * Each pipelines needs mcps to be allocated. Check if we have mcps for this 1569ba8ffefSDharageswari.R * pipe. 157e4e2d2f4SJeeja KP */ 1589ba8ffefSDharageswari.R 1599ba8ffefSDharageswari.R static bool skl_is_pipe_mcps_avail(struct skl *skl, 160e4e2d2f4SJeeja KP struct skl_module_cfg *mconfig) 161e4e2d2f4SJeeja KP { 162e4e2d2f4SJeeja KP struct skl_sst *ctx = skl->skl_sst; 163f6fa56e2SRamesh Babu u8 res_idx = mconfig->res_idx; 164f6fa56e2SRamesh Babu struct skl_module_res *res = &mconfig->module->resources[res_idx]; 165e4e2d2f4SJeeja KP 166f6fa56e2SRamesh Babu if (skl->resource.mcps + res->cps > skl->resource.max_mcps) { 167e4e2d2f4SJeeja KP dev_err(ctx->dev, 168e4e2d2f4SJeeja KP "%s: module_id %d instance %d\n", __func__, 169e4e2d2f4SJeeja KP mconfig->id.module_id, mconfig->id.instance_id); 170e4e2d2f4SJeeja KP dev_err(ctx->dev, 1717ca42f5aSGuneshwor Singh "exceeds ppl mcps available %d > mem %d\n", 172e4e2d2f4SJeeja KP skl->resource.max_mcps, skl->resource.mcps); 173e4e2d2f4SJeeja KP return false; 1749ba8ffefSDharageswari.R } else { 1759ba8ffefSDharageswari.R return true; 1769ba8ffefSDharageswari.R } 177e4e2d2f4SJeeja KP } 178e4e2d2f4SJeeja KP 1799ba8ffefSDharageswari.R static void skl_tplg_alloc_pipe_mcps(struct skl *skl, 1809ba8ffefSDharageswari.R struct skl_module_cfg *mconfig) 1819ba8ffefSDharageswari.R { 182f6fa56e2SRamesh Babu u8 res_idx = mconfig->res_idx; 183f6fa56e2SRamesh Babu struct skl_module_res *res = &mconfig->module->resources[res_idx]; 184f6fa56e2SRamesh Babu 185f6fa56e2SRamesh Babu skl->resource.mcps += res->cps; 186e4e2d2f4SJeeja KP } 187e4e2d2f4SJeeja KP 188e4e2d2f4SJeeja KP /* 189e4e2d2f4SJeeja KP * Free the mcps when tearing down 190e4e2d2f4SJeeja KP */ 191e4e2d2f4SJeeja KP static void 192e4e2d2f4SJeeja KP skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig) 193e4e2d2f4SJeeja KP { 194f6fa56e2SRamesh Babu u8 res_idx = mconfig->res_idx; 195f6fa56e2SRamesh Babu struct skl_module_res *res = &mconfig->module->resources[res_idx]; 196f6fa56e2SRamesh Babu 197f6fa56e2SRamesh Babu skl->resource.mcps -= res->cps; 198e4e2d2f4SJeeja KP } 199e4e2d2f4SJeeja KP 200e4e2d2f4SJeeja KP /* 201e4e2d2f4SJeeja KP * Free the memory when tearing down 202e4e2d2f4SJeeja KP */ 203e4e2d2f4SJeeja KP static void 204e4e2d2f4SJeeja KP skl_tplg_free_pipe_mem(struct skl *skl, struct skl_module_cfg *mconfig) 205e4e2d2f4SJeeja KP { 206e4e2d2f4SJeeja KP skl->resource.mem -= mconfig->pipe->memory_pages; 207e4e2d2f4SJeeja KP } 208e4e2d2f4SJeeja KP 209f7590d4fSJeeja KP 210f7590d4fSJeeja KP static void skl_dump_mconfig(struct skl_sst *ctx, 211f7590d4fSJeeja KP struct skl_module_cfg *mcfg) 212f7590d4fSJeeja KP { 213f6fa56e2SRamesh Babu struct skl_module_iface *iface = &mcfg->module->formats[0]; 214f6fa56e2SRamesh Babu 215f7590d4fSJeeja KP dev_dbg(ctx->dev, "Dumping config\n"); 216f7590d4fSJeeja KP dev_dbg(ctx->dev, "Input Format:\n"); 217f6fa56e2SRamesh Babu dev_dbg(ctx->dev, "channels = %d\n", iface->inputs[0].fmt.channels); 218f6fa56e2SRamesh Babu dev_dbg(ctx->dev, "s_freq = %d\n", iface->inputs[0].fmt.s_freq); 219f6fa56e2SRamesh Babu dev_dbg(ctx->dev, "ch_cfg = %d\n", iface->inputs[0].fmt.ch_cfg); 220f6fa56e2SRamesh Babu dev_dbg(ctx->dev, "valid bit depth = %d\n", 221f6fa56e2SRamesh Babu iface->inputs[0].fmt.valid_bit_depth); 222f7590d4fSJeeja KP dev_dbg(ctx->dev, "Output Format:\n"); 223f6fa56e2SRamesh Babu dev_dbg(ctx->dev, "channels = %d\n", iface->outputs[0].fmt.channels); 224f6fa56e2SRamesh Babu dev_dbg(ctx->dev, "s_freq = %d\n", iface->outputs[0].fmt.s_freq); 225f6fa56e2SRamesh Babu dev_dbg(ctx->dev, "valid bit depth = %d\n", 226f6fa56e2SRamesh Babu iface->outputs[0].fmt.valid_bit_depth); 227f6fa56e2SRamesh Babu dev_dbg(ctx->dev, "ch_cfg = %d\n", iface->outputs[0].fmt.ch_cfg); 228f7590d4fSJeeja KP } 229f7590d4fSJeeja KP 230ea5a137dSSubhransu S. Prusty static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs) 231ea5a137dSSubhransu S. Prusty { 232ea5a137dSSubhransu S. Prusty int slot_map = 0xFFFFFFFF; 233ea5a137dSSubhransu S. Prusty int start_slot = 0; 234ea5a137dSSubhransu S. Prusty int i; 235ea5a137dSSubhransu S. Prusty 236ea5a137dSSubhransu S. Prusty for (i = 0; i < chs; i++) { 237ea5a137dSSubhransu S. Prusty /* 238ea5a137dSSubhransu S. Prusty * For 2 channels with starting slot as 0, slot map will 239ea5a137dSSubhransu S. Prusty * look like 0xFFFFFF10. 240ea5a137dSSubhransu S. Prusty */ 241ea5a137dSSubhransu S. Prusty slot_map &= (~(0xF << (4 * i)) | (start_slot << (4 * i))); 242ea5a137dSSubhransu S. Prusty start_slot++; 243ea5a137dSSubhransu S. Prusty } 244ea5a137dSSubhransu S. Prusty fmt->ch_map = slot_map; 245ea5a137dSSubhransu S. Prusty } 246ea5a137dSSubhransu S. Prusty 247f7590d4fSJeeja KP static void skl_tplg_update_params(struct skl_module_fmt *fmt, 248f7590d4fSJeeja KP struct skl_pipe_params *params, int fixup) 249f7590d4fSJeeja KP { 250f7590d4fSJeeja KP if (fixup & SKL_RATE_FIXUP_MASK) 251f7590d4fSJeeja KP fmt->s_freq = params->s_freq; 252ea5a137dSSubhransu S. Prusty if (fixup & SKL_CH_FIXUP_MASK) { 253f7590d4fSJeeja KP fmt->channels = params->ch; 254ea5a137dSSubhransu S. Prusty skl_tplg_update_chmap(fmt, fmt->channels); 255ea5a137dSSubhransu S. Prusty } 25698256f83SJeeja KP if (fixup & SKL_FMT_FIXUP_MASK) { 25798256f83SJeeja KP fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt); 25898256f83SJeeja KP 25998256f83SJeeja KP /* 26098256f83SJeeja KP * 16 bit is 16 bit container whereas 24 bit is in 32 bit 26198256f83SJeeja KP * container so update bit depth accordingly 26298256f83SJeeja KP */ 26398256f83SJeeja KP switch (fmt->valid_bit_depth) { 26498256f83SJeeja KP case SKL_DEPTH_16BIT: 26598256f83SJeeja KP fmt->bit_depth = fmt->valid_bit_depth; 26698256f83SJeeja KP break; 26798256f83SJeeja KP 26898256f83SJeeja KP default: 26998256f83SJeeja KP fmt->bit_depth = SKL_DEPTH_32BIT; 27098256f83SJeeja KP break; 27198256f83SJeeja KP } 27298256f83SJeeja KP } 27398256f83SJeeja KP 274f7590d4fSJeeja KP } 275f7590d4fSJeeja KP 276f7590d4fSJeeja KP /* 277f7590d4fSJeeja KP * A pipeline may have modules which impact the pcm parameters, like SRC, 278f7590d4fSJeeja KP * channel converter, format converter. 279f7590d4fSJeeja KP * We need to calculate the output params by applying the 'fixup' 280f7590d4fSJeeja KP * Topology will tell driver which type of fixup is to be applied by 281f7590d4fSJeeja KP * supplying the fixup mask, so based on that we calculate the output 282f7590d4fSJeeja KP * 283f7590d4fSJeeja KP * Now In FE the pcm hw_params is source/target format. Same is applicable 284f7590d4fSJeeja KP * for BE with its hw_params invoked. 285f7590d4fSJeeja KP * here based on FE, BE pipeline and direction we calculate the input and 286f7590d4fSJeeja KP * outfix and then apply that for a module 287f7590d4fSJeeja KP */ 288f7590d4fSJeeja KP static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg, 289f7590d4fSJeeja KP struct skl_pipe_params *params, bool is_fe) 290f7590d4fSJeeja KP { 291f7590d4fSJeeja KP int in_fixup, out_fixup; 292f7590d4fSJeeja KP struct skl_module_fmt *in_fmt, *out_fmt; 293f7590d4fSJeeja KP 2944cd9899fSHardik T Shah /* Fixups will be applied to pin 0 only */ 295f6fa56e2SRamesh Babu in_fmt = &m_cfg->module->formats[0].inputs[0].fmt; 296f6fa56e2SRamesh Babu out_fmt = &m_cfg->module->formats[0].outputs[0].fmt; 297f7590d4fSJeeja KP 298f7590d4fSJeeja KP if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { 299f7590d4fSJeeja KP if (is_fe) { 300f7590d4fSJeeja KP in_fixup = m_cfg->params_fixup; 301f7590d4fSJeeja KP out_fixup = (~m_cfg->converter) & 302f7590d4fSJeeja KP m_cfg->params_fixup; 303f7590d4fSJeeja KP } else { 304f7590d4fSJeeja KP out_fixup = m_cfg->params_fixup; 305f7590d4fSJeeja KP in_fixup = (~m_cfg->converter) & 306f7590d4fSJeeja KP m_cfg->params_fixup; 307f7590d4fSJeeja KP } 308f7590d4fSJeeja KP } else { 309f7590d4fSJeeja KP if (is_fe) { 310f7590d4fSJeeja KP out_fixup = m_cfg->params_fixup; 311f7590d4fSJeeja KP in_fixup = (~m_cfg->converter) & 312f7590d4fSJeeja KP m_cfg->params_fixup; 313f7590d4fSJeeja KP } else { 314f7590d4fSJeeja KP in_fixup = m_cfg->params_fixup; 315f7590d4fSJeeja KP out_fixup = (~m_cfg->converter) & 316f7590d4fSJeeja KP m_cfg->params_fixup; 317f7590d4fSJeeja KP } 318f7590d4fSJeeja KP } 319f7590d4fSJeeja KP 320f7590d4fSJeeja KP skl_tplg_update_params(in_fmt, params, in_fixup); 321f7590d4fSJeeja KP skl_tplg_update_params(out_fmt, params, out_fixup); 322f7590d4fSJeeja KP } 323f7590d4fSJeeja KP 324f7590d4fSJeeja KP /* 325f7590d4fSJeeja KP * A module needs input and output buffers, which are dependent upon pcm 326f7590d4fSJeeja KP * params, so once we have calculate params, we need buffer calculation as 327f7590d4fSJeeja KP * well. 328f7590d4fSJeeja KP */ 329f7590d4fSJeeja KP static void skl_tplg_update_buffer_size(struct skl_sst *ctx, 330f7590d4fSJeeja KP struct skl_module_cfg *mcfg) 331f7590d4fSJeeja KP { 332f7590d4fSJeeja KP int multiplier = 1; 3334cd9899fSHardik T Shah struct skl_module_fmt *in_fmt, *out_fmt; 334f6fa56e2SRamesh Babu struct skl_module_res *res; 3354cd9899fSHardik T Shah 3364cd9899fSHardik T Shah /* Since fixups is applied to pin 0 only, ibs, obs needs 3374cd9899fSHardik T Shah * change for pin 0 only 3384cd9899fSHardik T Shah */ 339f6fa56e2SRamesh Babu res = &mcfg->module->resources[0]; 340f6fa56e2SRamesh Babu in_fmt = &mcfg->module->formats[0].inputs[0].fmt; 341f6fa56e2SRamesh Babu out_fmt = &mcfg->module->formats[0].outputs[0].fmt; 342f7590d4fSJeeja KP 343f7590d4fSJeeja KP if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT) 344f7590d4fSJeeja KP multiplier = 5; 345f0c8e1d9SSubhransu S. Prusty 346f6fa56e2SRamesh Babu res->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) * 347998d6fb5STakashi Sakamoto in_fmt->channels * (in_fmt->bit_depth >> 3) * 348f7590d4fSJeeja KP multiplier; 349f7590d4fSJeeja KP 350f6fa56e2SRamesh Babu res->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) * 351998d6fb5STakashi Sakamoto out_fmt->channels * (out_fmt->bit_depth >> 3) * 352f7590d4fSJeeja KP multiplier; 353f7590d4fSJeeja KP } 354f7590d4fSJeeja KP 355db2f586bSSenthilnathan Veppur static u8 skl_tplg_be_dev_type(int dev_type) 356db2f586bSSenthilnathan Veppur { 357db2f586bSSenthilnathan Veppur int ret; 358db2f586bSSenthilnathan Veppur 359db2f586bSSenthilnathan Veppur switch (dev_type) { 360db2f586bSSenthilnathan Veppur case SKL_DEVICE_BT: 361db2f586bSSenthilnathan Veppur ret = NHLT_DEVICE_BT; 362db2f586bSSenthilnathan Veppur break; 363db2f586bSSenthilnathan Veppur 364db2f586bSSenthilnathan Veppur case SKL_DEVICE_DMIC: 365db2f586bSSenthilnathan Veppur ret = NHLT_DEVICE_DMIC; 366db2f586bSSenthilnathan Veppur break; 367db2f586bSSenthilnathan Veppur 368db2f586bSSenthilnathan Veppur case SKL_DEVICE_I2S: 369db2f586bSSenthilnathan Veppur ret = NHLT_DEVICE_I2S; 370db2f586bSSenthilnathan Veppur break; 371db2f586bSSenthilnathan Veppur 372db2f586bSSenthilnathan Veppur default: 373db2f586bSSenthilnathan Veppur ret = NHLT_DEVICE_INVALID; 374db2f586bSSenthilnathan Veppur break; 375db2f586bSSenthilnathan Veppur } 376db2f586bSSenthilnathan Veppur 377db2f586bSSenthilnathan Veppur return ret; 378db2f586bSSenthilnathan Veppur } 379db2f586bSSenthilnathan Veppur 3802d1419a3SJeeja KP static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, 3812d1419a3SJeeja KP struct skl_sst *ctx) 3822d1419a3SJeeja KP { 3832d1419a3SJeeja KP struct skl_module_cfg *m_cfg = w->priv; 3842d1419a3SJeeja KP int link_type, dir; 3852d1419a3SJeeja KP u32 ch, s_freq, s_fmt; 3862d1419a3SJeeja KP struct nhlt_specific_cfg *cfg; 3872d1419a3SJeeja KP struct skl *skl = get_skl_ctx(ctx->dev); 388db2f586bSSenthilnathan Veppur u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type); 389f6fa56e2SRamesh Babu int fmt_idx = m_cfg->fmt_idx; 390f6fa56e2SRamesh Babu struct skl_module_iface *m_iface = &m_cfg->module->formats[fmt_idx]; 3912d1419a3SJeeja KP 3922d1419a3SJeeja KP /* check if we already have blob */ 3932d1419a3SJeeja KP if (m_cfg->formats_config.caps_size > 0) 3942d1419a3SJeeja KP return 0; 3952d1419a3SJeeja KP 396c7c6c736SJeeja KP dev_dbg(ctx->dev, "Applying default cfg blob\n"); 3972d1419a3SJeeja KP switch (m_cfg->dev_type) { 3982d1419a3SJeeja KP case SKL_DEVICE_DMIC: 3992d1419a3SJeeja KP link_type = NHLT_LINK_DMIC; 400c7c6c736SJeeja KP dir = SNDRV_PCM_STREAM_CAPTURE; 401f6fa56e2SRamesh Babu s_freq = m_iface->inputs[0].fmt.s_freq; 402f6fa56e2SRamesh Babu s_fmt = m_iface->inputs[0].fmt.bit_depth; 403f6fa56e2SRamesh Babu ch = m_iface->inputs[0].fmt.channels; 4042d1419a3SJeeja KP break; 4052d1419a3SJeeja KP 4062d1419a3SJeeja KP case SKL_DEVICE_I2S: 4072d1419a3SJeeja KP link_type = NHLT_LINK_SSP; 4082d1419a3SJeeja KP if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) { 409c7c6c736SJeeja KP dir = SNDRV_PCM_STREAM_PLAYBACK; 410f6fa56e2SRamesh Babu s_freq = m_iface->outputs[0].fmt.s_freq; 411f6fa56e2SRamesh Babu s_fmt = m_iface->outputs[0].fmt.bit_depth; 412f6fa56e2SRamesh Babu ch = m_iface->outputs[0].fmt.channels; 413c7c6c736SJeeja KP } else { 414c7c6c736SJeeja KP dir = SNDRV_PCM_STREAM_CAPTURE; 415f6fa56e2SRamesh Babu s_freq = m_iface->inputs[0].fmt.s_freq; 416f6fa56e2SRamesh Babu s_fmt = m_iface->inputs[0].fmt.bit_depth; 417f6fa56e2SRamesh Babu ch = m_iface->inputs[0].fmt.channels; 4182d1419a3SJeeja KP } 4192d1419a3SJeeja KP break; 4202d1419a3SJeeja KP 4212d1419a3SJeeja KP default: 4222d1419a3SJeeja KP return -EINVAL; 4232d1419a3SJeeja KP } 4242d1419a3SJeeja KP 4252d1419a3SJeeja KP /* update the blob based on virtual bus_id and default params */ 4262d1419a3SJeeja KP cfg = skl_get_ep_blob(skl, m_cfg->vbus_id, link_type, 427db2f586bSSenthilnathan Veppur s_fmt, ch, s_freq, dir, dev_type); 4282d1419a3SJeeja KP if (cfg) { 4292d1419a3SJeeja KP m_cfg->formats_config.caps_size = cfg->size; 4302d1419a3SJeeja KP m_cfg->formats_config.caps = (u32 *) &cfg->caps; 4312d1419a3SJeeja KP } else { 4322d1419a3SJeeja KP dev_err(ctx->dev, "Blob NULL for id %x type %d dirn %d\n", 4332d1419a3SJeeja KP m_cfg->vbus_id, link_type, dir); 4342d1419a3SJeeja KP dev_err(ctx->dev, "PCM: ch %d, freq %d, fmt %d\n", 4352d1419a3SJeeja KP ch, s_freq, s_fmt); 4362d1419a3SJeeja KP return -EIO; 4372d1419a3SJeeja KP } 4382d1419a3SJeeja KP 4392d1419a3SJeeja KP return 0; 4402d1419a3SJeeja KP } 4412d1419a3SJeeja KP 442f7590d4fSJeeja KP static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w, 443f7590d4fSJeeja KP struct skl_sst *ctx) 444f7590d4fSJeeja KP { 445f7590d4fSJeeja KP struct skl_module_cfg *m_cfg = w->priv; 446f7590d4fSJeeja KP struct skl_pipe_params *params = m_cfg->pipe->p_params; 447f7590d4fSJeeja KP int p_conn_type = m_cfg->pipe->conn_type; 448f7590d4fSJeeja KP bool is_fe; 449f7590d4fSJeeja KP 450f7590d4fSJeeja KP if (!m_cfg->params_fixup) 451f7590d4fSJeeja KP return; 452f7590d4fSJeeja KP 453f7590d4fSJeeja KP dev_dbg(ctx->dev, "Mconfig for widget=%s BEFORE updation\n", 454f7590d4fSJeeja KP w->name); 455f7590d4fSJeeja KP 456f7590d4fSJeeja KP skl_dump_mconfig(ctx, m_cfg); 457f7590d4fSJeeja KP 458f7590d4fSJeeja KP if (p_conn_type == SKL_PIPE_CONN_TYPE_FE) 459f7590d4fSJeeja KP is_fe = true; 460f7590d4fSJeeja KP else 461f7590d4fSJeeja KP is_fe = false; 462f7590d4fSJeeja KP 463f7590d4fSJeeja KP skl_tplg_update_params_fixup(m_cfg, params, is_fe); 464f7590d4fSJeeja KP skl_tplg_update_buffer_size(ctx, m_cfg); 465f7590d4fSJeeja KP 466f7590d4fSJeeja KP dev_dbg(ctx->dev, "Mconfig for widget=%s AFTER updation\n", 467f7590d4fSJeeja KP w->name); 468f7590d4fSJeeja KP 469f7590d4fSJeeja KP skl_dump_mconfig(ctx, m_cfg); 470f7590d4fSJeeja KP } 471f7590d4fSJeeja KP 472e4e2d2f4SJeeja KP /* 473abb74003SJeeja KP * some modules can have multiple params set from user control and 474abb74003SJeeja KP * need to be set after module is initialized. If set_param flag is 475abb74003SJeeja KP * set module params will be done after module is initialised. 476abb74003SJeeja KP */ 477abb74003SJeeja KP static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w, 478abb74003SJeeja KP struct skl_sst *ctx) 479abb74003SJeeja KP { 480abb74003SJeeja KP int i, ret; 481abb74003SJeeja KP struct skl_module_cfg *mconfig = w->priv; 482abb74003SJeeja KP const struct snd_kcontrol_new *k; 483abb74003SJeeja KP struct soc_bytes_ext *sb; 484abb74003SJeeja KP struct skl_algo_data *bc; 485abb74003SJeeja KP struct skl_specific_cfg *sp_cfg; 486abb74003SJeeja KP 487abb74003SJeeja KP if (mconfig->formats_config.caps_size > 0 && 4884ced1827SJeeja KP mconfig->formats_config.set_params == SKL_PARAM_SET) { 489abb74003SJeeja KP sp_cfg = &mconfig->formats_config; 490abb74003SJeeja KP ret = skl_set_module_params(ctx, sp_cfg->caps, 491abb74003SJeeja KP sp_cfg->caps_size, 492abb74003SJeeja KP sp_cfg->param_id, mconfig); 493abb74003SJeeja KP if (ret < 0) 494abb74003SJeeja KP return ret; 495abb74003SJeeja KP } 496abb74003SJeeja KP 497abb74003SJeeja KP for (i = 0; i < w->num_kcontrols; i++) { 498abb74003SJeeja KP k = &w->kcontrol_news[i]; 499abb74003SJeeja KP if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 500abb74003SJeeja KP sb = (void *) k->private_value; 501abb74003SJeeja KP bc = (struct skl_algo_data *)sb->dobj.private; 502abb74003SJeeja KP 5034ced1827SJeeja KP if (bc->set_params == SKL_PARAM_SET) { 504abb74003SJeeja KP ret = skl_set_module_params(ctx, 5050d682104SDharageswari R (u32 *)bc->params, bc->size, 506abb74003SJeeja KP bc->param_id, mconfig); 507abb74003SJeeja KP if (ret < 0) 508abb74003SJeeja KP return ret; 509abb74003SJeeja KP } 510abb74003SJeeja KP } 511abb74003SJeeja KP } 512abb74003SJeeja KP 513abb74003SJeeja KP return 0; 514abb74003SJeeja KP } 515abb74003SJeeja KP 516abb74003SJeeja KP /* 517abb74003SJeeja KP * some module param can set from user control and this is required as 518abb74003SJeeja KP * when module is initailzed. if module param is required in init it is 519abb74003SJeeja KP * identifed by set_param flag. if set_param flag is not set, then this 520abb74003SJeeja KP * parameter needs to set as part of module init. 521abb74003SJeeja KP */ 522abb74003SJeeja KP static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w) 523abb74003SJeeja KP { 524abb74003SJeeja KP const struct snd_kcontrol_new *k; 525abb74003SJeeja KP struct soc_bytes_ext *sb; 526abb74003SJeeja KP struct skl_algo_data *bc; 527abb74003SJeeja KP struct skl_module_cfg *mconfig = w->priv; 528abb74003SJeeja KP int i; 529abb74003SJeeja KP 530abb74003SJeeja KP for (i = 0; i < w->num_kcontrols; i++) { 531abb74003SJeeja KP k = &w->kcontrol_news[i]; 532abb74003SJeeja KP if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 533abb74003SJeeja KP sb = (struct soc_bytes_ext *)k->private_value; 534abb74003SJeeja KP bc = (struct skl_algo_data *)sb->dobj.private; 535abb74003SJeeja KP 5364ced1827SJeeja KP if (bc->set_params != SKL_PARAM_INIT) 537abb74003SJeeja KP continue; 538abb74003SJeeja KP 539d1a6fe41STakashi Sakamoto mconfig->formats_config.caps = (u32 *)bc->params; 5400d682104SDharageswari R mconfig->formats_config.caps_size = bc->size; 541abb74003SJeeja KP 542abb74003SJeeja KP break; 543abb74003SJeeja KP } 544abb74003SJeeja KP } 545abb74003SJeeja KP 546abb74003SJeeja KP return 0; 547abb74003SJeeja KP } 548abb74003SJeeja KP 549bb704a73SJeeja KP static int skl_tplg_module_prepare(struct skl_sst *ctx, struct skl_pipe *pipe, 550bb704a73SJeeja KP struct snd_soc_dapm_widget *w, struct skl_module_cfg *mcfg) 551bb704a73SJeeja KP { 552bb704a73SJeeja KP switch (mcfg->dev_type) { 553bb704a73SJeeja KP case SKL_DEVICE_HDAHOST: 554bb704a73SJeeja KP return skl_pcm_host_dma_prepare(ctx->dev, pipe->p_params); 555bb704a73SJeeja KP 556bb704a73SJeeja KP case SKL_DEVICE_HDALINK: 557bb704a73SJeeja KP return skl_pcm_link_dma_prepare(ctx->dev, pipe->p_params); 558bb704a73SJeeja KP } 559bb704a73SJeeja KP 560bb704a73SJeeja KP return 0; 561bb704a73SJeeja KP } 562bb704a73SJeeja KP 563abb74003SJeeja KP /* 564e4e2d2f4SJeeja KP * Inside a pipe instance, we can have various modules. These modules need 565e4e2d2f4SJeeja KP * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by 566e4e2d2f4SJeeja KP * skl_init_module() routine, so invoke that for all modules in a pipeline 567e4e2d2f4SJeeja KP */ 568e4e2d2f4SJeeja KP static int 569e4e2d2f4SJeeja KP skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) 570e4e2d2f4SJeeja KP { 571e4e2d2f4SJeeja KP struct skl_pipe_module *w_module; 572e4e2d2f4SJeeja KP struct snd_soc_dapm_widget *w; 573e4e2d2f4SJeeja KP struct skl_module_cfg *mconfig; 574e4e2d2f4SJeeja KP struct skl_sst *ctx = skl->skl_sst; 575f6fa56e2SRamesh Babu u8 cfg_idx; 576e4e2d2f4SJeeja KP int ret = 0; 577e4e2d2f4SJeeja KP 578e4e2d2f4SJeeja KP list_for_each_entry(w_module, &pipe->w_list, node) { 579b26199eaSJeeja KP uuid_le *uuid_mod; 580e4e2d2f4SJeeja KP w = w_module->w; 581e4e2d2f4SJeeja KP mconfig = w->priv; 582e4e2d2f4SJeeja KP 583b7c50555SVinod Koul /* check if module ids are populated */ 584b7c50555SVinod Koul if (mconfig->id.module_id < 0) { 585b7c50555SVinod Koul dev_err(skl->skl_sst->dev, 586a657ae7eSVinod Koul "module %pUL id not populated\n", 587a657ae7eSVinod Koul (uuid_le *)mconfig->guid); 588a657ae7eSVinod Koul return -EIO; 589b7c50555SVinod Koul } 590b7c50555SVinod Koul 591f6fa56e2SRamesh Babu cfg_idx = mconfig->pipe->cur_config_idx; 592f6fa56e2SRamesh Babu mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx; 593f6fa56e2SRamesh Babu mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx; 594f6fa56e2SRamesh Babu 595e4e2d2f4SJeeja KP /* check resource available */ 5969ba8ffefSDharageswari.R if (!skl_is_pipe_mcps_avail(skl, mconfig)) 597e4e2d2f4SJeeja KP return -ENOMEM; 598e4e2d2f4SJeeja KP 599f6fa56e2SRamesh Babu if (mconfig->module->loadable && ctx->dsp->fw_ops.load_mod) { 6006c5768b3SDharageswari R ret = ctx->dsp->fw_ops.load_mod(ctx->dsp, 6016c5768b3SDharageswari R mconfig->id.module_id, mconfig->guid); 6026c5768b3SDharageswari R if (ret < 0) 6036c5768b3SDharageswari R return ret; 604d643678bSJeeja KP 605d643678bSJeeja KP mconfig->m_state = SKL_MODULE_LOADED; 6066c5768b3SDharageswari R } 6076c5768b3SDharageswari R 608bb704a73SJeeja KP /* prepare the DMA if the module is gateway cpr */ 609bb704a73SJeeja KP ret = skl_tplg_module_prepare(ctx, pipe, w, mconfig); 610bb704a73SJeeja KP if (ret < 0) 611bb704a73SJeeja KP return ret; 612bb704a73SJeeja KP 6132d1419a3SJeeja KP /* update blob if blob is null for be with default value */ 6142d1419a3SJeeja KP skl_tplg_update_be_blob(w, ctx); 6152d1419a3SJeeja KP 616f7590d4fSJeeja KP /* 617f7590d4fSJeeja KP * apply fix/conversion to module params based on 618f7590d4fSJeeja KP * FE/BE params 619f7590d4fSJeeja KP */ 620f7590d4fSJeeja KP skl_tplg_update_module_params(w, ctx); 621b26199eaSJeeja KP uuid_mod = (uuid_le *)mconfig->guid; 622b26199eaSJeeja KP mconfig->id.pvt_id = skl_get_pvt_id(ctx, uuid_mod, 623b26199eaSJeeja KP mconfig->id.instance_id); 624ef2a352cSDharageswari R if (mconfig->id.pvt_id < 0) 625ef2a352cSDharageswari R return ret; 626abb74003SJeeja KP skl_tplg_set_module_init_data(w); 6274147a6e5SPardha Saradhi K 6284147a6e5SPardha Saradhi K ret = skl_dsp_get_core(ctx->dsp, mconfig->core_id); 6294147a6e5SPardha Saradhi K if (ret < 0) { 6304147a6e5SPardha Saradhi K dev_err(ctx->dev, "Failed to wake up core %d ret=%d\n", 6314147a6e5SPardha Saradhi K mconfig->core_id, ret); 6324147a6e5SPardha Saradhi K return ret; 6334147a6e5SPardha Saradhi K } 6344147a6e5SPardha Saradhi K 6359939a9c3SJeeja KP ret = skl_init_module(ctx, mconfig); 636ef2a352cSDharageswari R if (ret < 0) { 637b26199eaSJeeja KP skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id); 6384147a6e5SPardha Saradhi K goto err; 639ef2a352cSDharageswari R } 640260eb73aSDharageswari R skl_tplg_alloc_pipe_mcps(skl, mconfig); 641abb74003SJeeja KP ret = skl_tplg_set_module_params(w, ctx); 642e4e2d2f4SJeeja KP if (ret < 0) 6434147a6e5SPardha Saradhi K goto err; 644e4e2d2f4SJeeja KP } 645e4e2d2f4SJeeja KP 646e4e2d2f4SJeeja KP return 0; 6474147a6e5SPardha Saradhi K err: 6484147a6e5SPardha Saradhi K skl_dsp_put_core(ctx->dsp, mconfig->core_id); 6494147a6e5SPardha Saradhi K return ret; 650e4e2d2f4SJeeja KP } 651d93f8e55SVinod Koul 6526c5768b3SDharageswari R static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx, 6536c5768b3SDharageswari R struct skl_pipe *pipe) 6546c5768b3SDharageswari R { 6554147a6e5SPardha Saradhi K int ret = 0; 6566c5768b3SDharageswari R struct skl_pipe_module *w_module = NULL; 6576c5768b3SDharageswari R struct skl_module_cfg *mconfig = NULL; 6586c5768b3SDharageswari R 6596c5768b3SDharageswari R list_for_each_entry(w_module, &pipe->w_list, node) { 660b26199eaSJeeja KP uuid_le *uuid_mod; 6616c5768b3SDharageswari R mconfig = w_module->w->priv; 662b26199eaSJeeja KP uuid_mod = (uuid_le *)mconfig->guid; 6636c5768b3SDharageswari R 664f6fa56e2SRamesh Babu if (mconfig->module->loadable && ctx->dsp->fw_ops.unload_mod && 665b0fab9c6SDharageswari R mconfig->m_state > SKL_MODULE_UNINIT) { 666b0fab9c6SDharageswari R ret = ctx->dsp->fw_ops.unload_mod(ctx->dsp, 6676c5768b3SDharageswari R mconfig->id.module_id); 668b0fab9c6SDharageswari R if (ret < 0) 669b0fab9c6SDharageswari R return -EIO; 670b0fab9c6SDharageswari R } 671b26199eaSJeeja KP skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id); 6724147a6e5SPardha Saradhi K 6734147a6e5SPardha Saradhi K ret = skl_dsp_put_core(ctx->dsp, mconfig->core_id); 6744147a6e5SPardha Saradhi K if (ret < 0) { 6754147a6e5SPardha Saradhi K /* don't return; continue with other modules */ 6764147a6e5SPardha Saradhi K dev_err(ctx->dev, "Failed to sleep core %d ret=%d\n", 6774147a6e5SPardha Saradhi K mconfig->core_id, ret); 6784147a6e5SPardha Saradhi K } 6796c5768b3SDharageswari R } 6806c5768b3SDharageswari R 6816c5768b3SDharageswari R /* no modules to unload in this path, so return */ 6824147a6e5SPardha Saradhi K return ret; 6836c5768b3SDharageswari R } 6846c5768b3SDharageswari R 685d93f8e55SVinod Koul /* 686f6fa56e2SRamesh Babu * Here, we select pipe format based on the pipe type and pipe 687f6fa56e2SRamesh Babu * direction to determine the current config index for the pipeline. 688f6fa56e2SRamesh Babu * The config index is then used to select proper module resources. 689f6fa56e2SRamesh Babu * Intermediate pipes currently have a fixed format hence we select the 690f6fa56e2SRamesh Babu * 0th configuratation by default for such pipes. 691f6fa56e2SRamesh Babu */ 692f6fa56e2SRamesh Babu static int 693f6fa56e2SRamesh Babu skl_tplg_get_pipe_config(struct skl *skl, struct skl_module_cfg *mconfig) 694f6fa56e2SRamesh Babu { 695f6fa56e2SRamesh Babu struct skl_sst *ctx = skl->skl_sst; 696f6fa56e2SRamesh Babu struct skl_pipe *pipe = mconfig->pipe; 697f6fa56e2SRamesh Babu struct skl_pipe_params *params = pipe->p_params; 698f6fa56e2SRamesh Babu struct skl_path_config *pconfig = &pipe->configs[0]; 699f6fa56e2SRamesh Babu struct skl_pipe_fmt *fmt = NULL; 700f6fa56e2SRamesh Babu bool in_fmt = false; 701f6fa56e2SRamesh Babu int i; 702f6fa56e2SRamesh Babu 703f6fa56e2SRamesh Babu if (pipe->nr_cfgs == 0) { 704f6fa56e2SRamesh Babu pipe->cur_config_idx = 0; 705f6fa56e2SRamesh Babu return 0; 706f6fa56e2SRamesh Babu } 707f6fa56e2SRamesh Babu 708f6fa56e2SRamesh Babu if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE) { 709f6fa56e2SRamesh Babu dev_dbg(ctx->dev, "No conn_type detected, take 0th config\n"); 710f6fa56e2SRamesh Babu pipe->cur_config_idx = 0; 711f6fa56e2SRamesh Babu pipe->memory_pages = pconfig->mem_pages; 712f6fa56e2SRamesh Babu 713f6fa56e2SRamesh Babu return 0; 714f6fa56e2SRamesh Babu } 715f6fa56e2SRamesh Babu 716f6fa56e2SRamesh Babu if ((pipe->conn_type == SKL_PIPE_CONN_TYPE_FE && 717f6fa56e2SRamesh Babu pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) || 718f6fa56e2SRamesh Babu (pipe->conn_type == SKL_PIPE_CONN_TYPE_BE && 719f6fa56e2SRamesh Babu pipe->direction == SNDRV_PCM_STREAM_CAPTURE)) 720f6fa56e2SRamesh Babu in_fmt = true; 721f6fa56e2SRamesh Babu 722f6fa56e2SRamesh Babu for (i = 0; i < pipe->nr_cfgs; i++) { 723f6fa56e2SRamesh Babu pconfig = &pipe->configs[i]; 724f6fa56e2SRamesh Babu if (in_fmt) 725f6fa56e2SRamesh Babu fmt = &pconfig->in_fmt; 726f6fa56e2SRamesh Babu else 727f6fa56e2SRamesh Babu fmt = &pconfig->out_fmt; 728f6fa56e2SRamesh Babu 729f6fa56e2SRamesh Babu if (CHECK_HW_PARAMS(params->ch, params->s_freq, params->s_fmt, 730f6fa56e2SRamesh Babu fmt->channels, fmt->freq, fmt->bps)) { 731f6fa56e2SRamesh Babu pipe->cur_config_idx = i; 732f6fa56e2SRamesh Babu pipe->memory_pages = pconfig->mem_pages; 733f6fa56e2SRamesh Babu dev_dbg(ctx->dev, "Using pipe config: %d\n", i); 734f6fa56e2SRamesh Babu 735f6fa56e2SRamesh Babu return 0; 736f6fa56e2SRamesh Babu } 737f6fa56e2SRamesh Babu } 738f6fa56e2SRamesh Babu 739f6fa56e2SRamesh Babu dev_err(ctx->dev, "Invalid pipe config: %d %d %d for pipe: %d\n", 740f6fa56e2SRamesh Babu params->ch, params->s_freq, params->s_fmt, pipe->ppl_id); 741f6fa56e2SRamesh Babu return -EINVAL; 742f6fa56e2SRamesh Babu } 743f6fa56e2SRamesh Babu 744f6fa56e2SRamesh Babu /* 745d93f8e55SVinod Koul * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we 746d93f8e55SVinod Koul * need create the pipeline. So we do following: 747d93f8e55SVinod Koul * - check the resources 748d93f8e55SVinod Koul * - Create the pipeline 749d93f8e55SVinod Koul * - Initialize the modules in pipeline 750d93f8e55SVinod Koul * - finally bind all modules together 751d93f8e55SVinod Koul */ 752d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, 753d93f8e55SVinod Koul struct skl *skl) 754d93f8e55SVinod Koul { 755d93f8e55SVinod Koul int ret; 756d93f8e55SVinod Koul struct skl_module_cfg *mconfig = w->priv; 757d93f8e55SVinod Koul struct skl_pipe_module *w_module; 758d93f8e55SVinod Koul struct skl_pipe *s_pipe = mconfig->pipe; 759b8c722ddSJeeja KP struct skl_module_cfg *src_module = NULL, *dst_module, *module; 760d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 761b8c722ddSJeeja KP struct skl_module_deferred_bind *modules; 762d93f8e55SVinod Koul 763f6fa56e2SRamesh Babu ret = skl_tplg_get_pipe_config(skl, mconfig); 764f6fa56e2SRamesh Babu if (ret < 0) 765f6fa56e2SRamesh Babu return ret; 766f6fa56e2SRamesh Babu 767d93f8e55SVinod Koul /* check resource available */ 7689ba8ffefSDharageswari.R if (!skl_is_pipe_mcps_avail(skl, mconfig)) 769d93f8e55SVinod Koul return -EBUSY; 770d93f8e55SVinod Koul 7719ba8ffefSDharageswari.R if (!skl_is_pipe_mem_avail(skl, mconfig)) 772d93f8e55SVinod Koul return -ENOMEM; 773d93f8e55SVinod Koul 774d93f8e55SVinod Koul /* 775d93f8e55SVinod Koul * Create a list of modules for pipe. 776d93f8e55SVinod Koul * This list contains modules from source to sink 777d93f8e55SVinod Koul */ 778d93f8e55SVinod Koul ret = skl_create_pipeline(ctx, mconfig->pipe); 779d93f8e55SVinod Koul if (ret < 0) 780d93f8e55SVinod Koul return ret; 781d93f8e55SVinod Koul 782260eb73aSDharageswari R skl_tplg_alloc_pipe_mem(skl, mconfig); 783260eb73aSDharageswari R skl_tplg_alloc_pipe_mcps(skl, mconfig); 784d93f8e55SVinod Koul 785d93f8e55SVinod Koul /* Init all pipe modules from source to sink */ 786d93f8e55SVinod Koul ret = skl_tplg_init_pipe_modules(skl, s_pipe); 787d93f8e55SVinod Koul if (ret < 0) 788d93f8e55SVinod Koul return ret; 789d93f8e55SVinod Koul 790d93f8e55SVinod Koul /* Bind modules from source to sink */ 791d93f8e55SVinod Koul list_for_each_entry(w_module, &s_pipe->w_list, node) { 792d93f8e55SVinod Koul dst_module = w_module->w->priv; 793d93f8e55SVinod Koul 794d93f8e55SVinod Koul if (src_module == NULL) { 795d93f8e55SVinod Koul src_module = dst_module; 796d93f8e55SVinod Koul continue; 797d93f8e55SVinod Koul } 798d93f8e55SVinod Koul 799d93f8e55SVinod Koul ret = skl_bind_modules(ctx, src_module, dst_module); 800d93f8e55SVinod Koul if (ret < 0) 801d93f8e55SVinod Koul return ret; 802d93f8e55SVinod Koul 803d93f8e55SVinod Koul src_module = dst_module; 804d93f8e55SVinod Koul } 805d93f8e55SVinod Koul 806b8c722ddSJeeja KP /* 807b8c722ddSJeeja KP * When the destination module is initialized, check for these modules 808b8c722ddSJeeja KP * in deferred bind list. If found, bind them. 809b8c722ddSJeeja KP */ 810b8c722ddSJeeja KP list_for_each_entry(w_module, &s_pipe->w_list, node) { 811b8c722ddSJeeja KP if (list_empty(&skl->bind_list)) 812b8c722ddSJeeja KP break; 813b8c722ddSJeeja KP 814b8c722ddSJeeja KP list_for_each_entry(modules, &skl->bind_list, node) { 815b8c722ddSJeeja KP module = w_module->w->priv; 816b8c722ddSJeeja KP if (modules->dst == module) 817b8c722ddSJeeja KP skl_bind_modules(ctx, modules->src, 818b8c722ddSJeeja KP modules->dst); 819b8c722ddSJeeja KP } 820b8c722ddSJeeja KP } 821b8c722ddSJeeja KP 822d93f8e55SVinod Koul return 0; 823d93f8e55SVinod Koul } 824d93f8e55SVinod Koul 825bf3e5ef5SDharageswari R static int skl_fill_sink_instance_id(struct skl_sst *ctx, u32 *params, 826bf3e5ef5SDharageswari R int size, struct skl_module_cfg *mcfg) 8275e8f0ee4SDharageswari R { 8285e8f0ee4SDharageswari R int i, pvt_id; 8295e8f0ee4SDharageswari R 830bf3e5ef5SDharageswari R if (mcfg->m_type == SKL_MODULE_TYPE_KPB) { 831bf3e5ef5SDharageswari R struct skl_kpb_params *kpb_params = 832bf3e5ef5SDharageswari R (struct skl_kpb_params *)params; 833f7a9f772SSriram Periyasamy struct skl_mod_inst_map *inst = kpb_params->u.map; 8345e8f0ee4SDharageswari R 835bf3e5ef5SDharageswari R for (i = 0; i < kpb_params->num_modules; i++) { 836bf3e5ef5SDharageswari R pvt_id = skl_get_pvt_instance_id_map(ctx, inst->mod_id, 837bf3e5ef5SDharageswari R inst->inst_id); 8385e8f0ee4SDharageswari R if (pvt_id < 0) 8395e8f0ee4SDharageswari R return -EINVAL; 840bf3e5ef5SDharageswari R 8415e8f0ee4SDharageswari R inst->inst_id = pvt_id; 8425e8f0ee4SDharageswari R inst++; 8435e8f0ee4SDharageswari R } 8445e8f0ee4SDharageswari R } 8455e8f0ee4SDharageswari R 846bf3e5ef5SDharageswari R return 0; 847bf3e5ef5SDharageswari R } 848cc6a4044SJeeja KP /* 849cc6a4044SJeeja KP * Some modules require params to be set after the module is bound to 850cc6a4044SJeeja KP * all pins connected. 851cc6a4044SJeeja KP * 852cc6a4044SJeeja KP * The module provider initializes set_param flag for such modules and we 853cc6a4044SJeeja KP * send params after binding 854cc6a4044SJeeja KP */ 855cc6a4044SJeeja KP static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, 856cc6a4044SJeeja KP struct skl_module_cfg *mcfg, struct skl_sst *ctx) 857cc6a4044SJeeja KP { 858cc6a4044SJeeja KP int i, ret; 859cc6a4044SJeeja KP struct skl_module_cfg *mconfig = w->priv; 860cc6a4044SJeeja KP const struct snd_kcontrol_new *k; 861cc6a4044SJeeja KP struct soc_bytes_ext *sb; 862cc6a4044SJeeja KP struct skl_algo_data *bc; 863cc6a4044SJeeja KP struct skl_specific_cfg *sp_cfg; 864bf3e5ef5SDharageswari R u32 *params; 865cc6a4044SJeeja KP 866cc6a4044SJeeja KP /* 867cc6a4044SJeeja KP * check all out/in pins are in bind state. 868cc6a4044SJeeja KP * if so set the module param 869cc6a4044SJeeja KP */ 870f6fa56e2SRamesh Babu for (i = 0; i < mcfg->module->max_output_pins; i++) { 871cc6a4044SJeeja KP if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE) 872cc6a4044SJeeja KP return 0; 873cc6a4044SJeeja KP } 874cc6a4044SJeeja KP 875f6fa56e2SRamesh Babu for (i = 0; i < mcfg->module->max_input_pins; i++) { 876cc6a4044SJeeja KP if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE) 877cc6a4044SJeeja KP return 0; 878cc6a4044SJeeja KP } 879cc6a4044SJeeja KP 880cc6a4044SJeeja KP if (mconfig->formats_config.caps_size > 0 && 881cc6a4044SJeeja KP mconfig->formats_config.set_params == SKL_PARAM_BIND) { 882cc6a4044SJeeja KP sp_cfg = &mconfig->formats_config; 883cc6a4044SJeeja KP ret = skl_set_module_params(ctx, sp_cfg->caps, 884cc6a4044SJeeja KP sp_cfg->caps_size, 885cc6a4044SJeeja KP sp_cfg->param_id, mconfig); 886cc6a4044SJeeja KP if (ret < 0) 887cc6a4044SJeeja KP return ret; 888cc6a4044SJeeja KP } 889cc6a4044SJeeja KP 890cc6a4044SJeeja KP for (i = 0; i < w->num_kcontrols; i++) { 891cc6a4044SJeeja KP k = &w->kcontrol_news[i]; 892cc6a4044SJeeja KP if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 893cc6a4044SJeeja KP sb = (void *) k->private_value; 894cc6a4044SJeeja KP bc = (struct skl_algo_data *)sb->dobj.private; 895cc6a4044SJeeja KP 896cc6a4044SJeeja KP if (bc->set_params == SKL_PARAM_BIND) { 897bf3e5ef5SDharageswari R params = kzalloc(bc->max, GFP_KERNEL); 898bf3e5ef5SDharageswari R if (!params) 899bf3e5ef5SDharageswari R return -ENOMEM; 900bf3e5ef5SDharageswari R 901bf3e5ef5SDharageswari R memcpy(params, bc->params, bc->max); 902bf3e5ef5SDharageswari R skl_fill_sink_instance_id(ctx, params, bc->max, 903bf3e5ef5SDharageswari R mconfig); 904bf3e5ef5SDharageswari R 905bf3e5ef5SDharageswari R ret = skl_set_module_params(ctx, params, 906bf3e5ef5SDharageswari R bc->max, bc->param_id, mconfig); 907bf3e5ef5SDharageswari R kfree(params); 908bf3e5ef5SDharageswari R 909cc6a4044SJeeja KP if (ret < 0) 910cc6a4044SJeeja KP return ret; 911cc6a4044SJeeja KP } 912cc6a4044SJeeja KP } 913cc6a4044SJeeja KP } 914cc6a4044SJeeja KP 915cc6a4044SJeeja KP return 0; 916cc6a4044SJeeja KP } 917cc6a4044SJeeja KP 918f7a9f772SSriram Periyasamy static int skl_get_module_id(struct skl_sst *ctx, uuid_le *uuid) 919f7a9f772SSriram Periyasamy { 920f7a9f772SSriram Periyasamy struct uuid_module *module; 921f7a9f772SSriram Periyasamy 922f7a9f772SSriram Periyasamy list_for_each_entry(module, &ctx->uuid_list, list) { 923f7a9f772SSriram Periyasamy if (uuid_le_cmp(*uuid, module->uuid) == 0) 924f7a9f772SSriram Periyasamy return module->id; 925f7a9f772SSriram Periyasamy } 926f7a9f772SSriram Periyasamy 927f7a9f772SSriram Periyasamy return -EINVAL; 928f7a9f772SSriram Periyasamy } 929f7a9f772SSriram Periyasamy 930f7a9f772SSriram Periyasamy static int skl_tplg_find_moduleid_from_uuid(struct skl *skl, 931f7a9f772SSriram Periyasamy const struct snd_kcontrol_new *k) 932f7a9f772SSriram Periyasamy { 933f7a9f772SSriram Periyasamy struct soc_bytes_ext *sb = (void *) k->private_value; 934f7a9f772SSriram Periyasamy struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private; 935f7a9f772SSriram Periyasamy struct skl_kpb_params *uuid_params, *params; 936f7a9f772SSriram Periyasamy struct hdac_bus *bus = ebus_to_hbus(skl_to_ebus(skl)); 937f7a9f772SSriram Periyasamy int i, size, module_id; 938f7a9f772SSriram Periyasamy 939f7a9f772SSriram Periyasamy if (bc->set_params == SKL_PARAM_BIND && bc->max) { 940f7a9f772SSriram Periyasamy uuid_params = (struct skl_kpb_params *)bc->params; 941f7a9f772SSriram Periyasamy size = uuid_params->num_modules * 942f7a9f772SSriram Periyasamy sizeof(struct skl_mod_inst_map) + 943f7a9f772SSriram Periyasamy sizeof(uuid_params->num_modules); 944f7a9f772SSriram Periyasamy 945f7a9f772SSriram Periyasamy params = devm_kzalloc(bus->dev, size, GFP_KERNEL); 946f7a9f772SSriram Periyasamy if (!params) 947f7a9f772SSriram Periyasamy return -ENOMEM; 948f7a9f772SSriram Periyasamy 949f7a9f772SSriram Periyasamy params->num_modules = uuid_params->num_modules; 950f7a9f772SSriram Periyasamy 951f7a9f772SSriram Periyasamy for (i = 0; i < uuid_params->num_modules; i++) { 952f7a9f772SSriram Periyasamy module_id = skl_get_module_id(skl->skl_sst, 953f7a9f772SSriram Periyasamy &uuid_params->u.map_uuid[i].mod_uuid); 954f7a9f772SSriram Periyasamy if (module_id < 0) { 955f7a9f772SSriram Periyasamy devm_kfree(bus->dev, params); 956f7a9f772SSriram Periyasamy return -EINVAL; 957f7a9f772SSriram Periyasamy } 958f7a9f772SSriram Periyasamy 959f7a9f772SSriram Periyasamy params->u.map[i].mod_id = module_id; 960f7a9f772SSriram Periyasamy params->u.map[i].inst_id = 961f7a9f772SSriram Periyasamy uuid_params->u.map_uuid[i].inst_id; 962f7a9f772SSriram Periyasamy } 963f7a9f772SSriram Periyasamy 964f7a9f772SSriram Periyasamy devm_kfree(bus->dev, bc->params); 965f7a9f772SSriram Periyasamy bc->params = (char *)params; 966f7a9f772SSriram Periyasamy bc->max = size; 967f7a9f772SSriram Periyasamy } 968f7a9f772SSriram Periyasamy 969f7a9f772SSriram Periyasamy return 0; 970f7a9f772SSriram Periyasamy } 971f7a9f772SSriram Periyasamy 972f7a9f772SSriram Periyasamy /* 973f7a9f772SSriram Periyasamy * Retrieve the module id from UUID mentioned in the 974f7a9f772SSriram Periyasamy * post bind params 975f7a9f772SSriram Periyasamy */ 976f7a9f772SSriram Periyasamy void skl_tplg_add_moduleid_in_bind_params(struct skl *skl, 977f7a9f772SSriram Periyasamy struct snd_soc_dapm_widget *w) 978f7a9f772SSriram Periyasamy { 979f7a9f772SSriram Periyasamy struct skl_module_cfg *mconfig = w->priv; 980f7a9f772SSriram Periyasamy int i; 981f7a9f772SSriram Periyasamy 982f7a9f772SSriram Periyasamy /* 983f7a9f772SSriram Periyasamy * Post bind params are used for only for KPB 984f7a9f772SSriram Periyasamy * to set copier instances to drain the data 985f7a9f772SSriram Periyasamy * in fast mode 986f7a9f772SSriram Periyasamy */ 987f7a9f772SSriram Periyasamy if (mconfig->m_type != SKL_MODULE_TYPE_KPB) 988f7a9f772SSriram Periyasamy return; 989f7a9f772SSriram Periyasamy 990f7a9f772SSriram Periyasamy for (i = 0; i < w->num_kcontrols; i++) 991f7a9f772SSriram Periyasamy if ((w->kcontrol_news[i].access & 992f7a9f772SSriram Periyasamy SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) && 993f7a9f772SSriram Periyasamy (skl_tplg_find_moduleid_from_uuid(skl, 994f7a9f772SSriram Periyasamy &w->kcontrol_news[i]) < 0)) 995f7a9f772SSriram Periyasamy dev_err(skl->skl_sst->dev, 996f7a9f772SSriram Periyasamy "%s: invalid kpb post bind params\n", 997f7a9f772SSriram Periyasamy __func__); 998f7a9f772SSriram Periyasamy } 999b8c722ddSJeeja KP 1000b8c722ddSJeeja KP static int skl_tplg_module_add_deferred_bind(struct skl *skl, 1001b8c722ddSJeeja KP struct skl_module_cfg *src, struct skl_module_cfg *dst) 1002b8c722ddSJeeja KP { 1003b8c722ddSJeeja KP struct skl_module_deferred_bind *m_list, *modules; 1004b8c722ddSJeeja KP int i; 1005b8c722ddSJeeja KP 1006b8c722ddSJeeja KP /* only supported for module with static pin connection */ 1007f6fa56e2SRamesh Babu for (i = 0; i < dst->module->max_input_pins; i++) { 1008b8c722ddSJeeja KP struct skl_module_pin *pin = &dst->m_in_pin[i]; 1009b8c722ddSJeeja KP 1010b8c722ddSJeeja KP if (pin->is_dynamic) 1011b8c722ddSJeeja KP continue; 1012b8c722ddSJeeja KP 1013b8c722ddSJeeja KP if ((pin->id.module_id == src->id.module_id) && 1014b8c722ddSJeeja KP (pin->id.instance_id == src->id.instance_id)) { 1015b8c722ddSJeeja KP 1016b8c722ddSJeeja KP if (!list_empty(&skl->bind_list)) { 1017b8c722ddSJeeja KP list_for_each_entry(modules, &skl->bind_list, node) { 1018b8c722ddSJeeja KP if (modules->src == src && modules->dst == dst) 1019b8c722ddSJeeja KP return 0; 1020b8c722ddSJeeja KP } 1021b8c722ddSJeeja KP } 1022b8c722ddSJeeja KP 1023b8c722ddSJeeja KP m_list = kzalloc(sizeof(*m_list), GFP_KERNEL); 1024b8c722ddSJeeja KP if (!m_list) 1025b8c722ddSJeeja KP return -ENOMEM; 1026b8c722ddSJeeja KP 1027b8c722ddSJeeja KP m_list->src = src; 1028b8c722ddSJeeja KP m_list->dst = dst; 1029b8c722ddSJeeja KP 1030b8c722ddSJeeja KP list_add(&m_list->node, &skl->bind_list); 1031b8c722ddSJeeja KP } 1032b8c722ddSJeeja KP } 1033b8c722ddSJeeja KP 1034b8c722ddSJeeja KP return 0; 1035b8c722ddSJeeja KP } 1036b8c722ddSJeeja KP 10378724ff17SJeeja KP static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, 10388724ff17SJeeja KP struct skl *skl, 10396bd4cf85SJeeja KP struct snd_soc_dapm_widget *src_w, 10408724ff17SJeeja KP struct skl_module_cfg *src_mconfig) 1041d93f8e55SVinod Koul { 1042d93f8e55SVinod Koul struct snd_soc_dapm_path *p; 10430ed95d76SJeeja KP struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL; 10448724ff17SJeeja KP struct skl_module_cfg *sink_mconfig; 1045d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 10468724ff17SJeeja KP int ret; 1047d93f8e55SVinod Koul 10488724ff17SJeeja KP snd_soc_dapm_widget_for_each_sink_path(w, p) { 1049d93f8e55SVinod Koul if (!p->connect) 1050d93f8e55SVinod Koul continue; 1051d93f8e55SVinod Koul 1052d93f8e55SVinod Koul dev_dbg(ctx->dev, "%s: src widget=%s\n", __func__, w->name); 1053d93f8e55SVinod Koul dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name); 1054d93f8e55SVinod Koul 10550ed95d76SJeeja KP next_sink = p->sink; 10566bd4cf85SJeeja KP 1057cb1f904dSGuneshwor Singh if (!is_skl_dsp_widget_type(p->sink, ctx->dev)) 10586bd4cf85SJeeja KP return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig); 10596bd4cf85SJeeja KP 1060d93f8e55SVinod Koul /* 1061d93f8e55SVinod Koul * here we will check widgets in sink pipelines, so that 1062d93f8e55SVinod Koul * can be any widgets type and we are only interested if 1063d93f8e55SVinod Koul * they are ones used for SKL so check that first 1064d93f8e55SVinod Koul */ 1065d93f8e55SVinod Koul if ((p->sink->priv != NULL) && 1066cb1f904dSGuneshwor Singh is_skl_dsp_widget_type(p->sink, ctx->dev)) { 1067d93f8e55SVinod Koul 1068d93f8e55SVinod Koul sink = p->sink; 1069d93f8e55SVinod Koul sink_mconfig = sink->priv; 1070d93f8e55SVinod Koul 1071b8c722ddSJeeja KP /* 1072b8c722ddSJeeja KP * Modules other than PGA leaf can be connected 1073b8c722ddSJeeja KP * directly or via switch to a module in another 1074b8c722ddSJeeja KP * pipeline. EX: reference path 1075b8c722ddSJeeja KP * when the path is enabled, the dst module that needs 1076b8c722ddSJeeja KP * to be bound may not be initialized. if the module is 1077b8c722ddSJeeja KP * not initialized, add these modules in the deferred 1078b8c722ddSJeeja KP * bind list and when the dst module is initialised, 1079b8c722ddSJeeja KP * bind this module to the dst_module in deferred list. 1080b8c722ddSJeeja KP */ 1081b8c722ddSJeeja KP if (((src_mconfig->m_state == SKL_MODULE_INIT_DONE) 1082b8c722ddSJeeja KP && (sink_mconfig->m_state == SKL_MODULE_UNINIT))) { 1083b8c722ddSJeeja KP 1084b8c722ddSJeeja KP ret = skl_tplg_module_add_deferred_bind(skl, 1085b8c722ddSJeeja KP src_mconfig, sink_mconfig); 1086b8c722ddSJeeja KP 1087b8c722ddSJeeja KP if (ret < 0) 1088b8c722ddSJeeja KP return ret; 1089b8c722ddSJeeja KP 1090b8c722ddSJeeja KP } 1091b8c722ddSJeeja KP 1092b8c722ddSJeeja KP 1093cc6a4044SJeeja KP if (src_mconfig->m_state == SKL_MODULE_UNINIT || 1094cc6a4044SJeeja KP sink_mconfig->m_state == SKL_MODULE_UNINIT) 1095cc6a4044SJeeja KP continue; 1096cc6a4044SJeeja KP 1097d93f8e55SVinod Koul /* Bind source to sink, mixin is always source */ 1098d93f8e55SVinod Koul ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig); 1099d93f8e55SVinod Koul if (ret) 1100d93f8e55SVinod Koul return ret; 1101d93f8e55SVinod Koul 1102cc6a4044SJeeja KP /* set module params after bind */ 1103cc6a4044SJeeja KP skl_tplg_set_module_bind_params(src_w, src_mconfig, ctx); 1104cc6a4044SJeeja KP skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx); 1105cc6a4044SJeeja KP 1106d93f8e55SVinod Koul /* Start sinks pipe first */ 1107d93f8e55SVinod Koul if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) { 1108d1730c3dSJeeja KP if (sink_mconfig->pipe->conn_type != 1109d1730c3dSJeeja KP SKL_PIPE_CONN_TYPE_FE) 1110d1730c3dSJeeja KP ret = skl_run_pipe(ctx, 1111d1730c3dSJeeja KP sink_mconfig->pipe); 1112d93f8e55SVinod Koul if (ret) 1113d93f8e55SVinod Koul return ret; 1114d93f8e55SVinod Koul } 1115d93f8e55SVinod Koul } 1116d93f8e55SVinod Koul } 1117d93f8e55SVinod Koul 111810a5439fSguneshwor.o.singh@intel.com if (!sink && next_sink) 11196bd4cf85SJeeja KP return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig); 11208724ff17SJeeja KP 11218724ff17SJeeja KP return 0; 11228724ff17SJeeja KP } 11238724ff17SJeeja KP 1124d93f8e55SVinod Koul /* 1125d93f8e55SVinod Koul * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA 1126d93f8e55SVinod Koul * we need to do following: 1127d93f8e55SVinod Koul * - Bind to sink pipeline 1128d93f8e55SVinod Koul * Since the sink pipes can be running and we don't get mixer event on 1129d93f8e55SVinod Koul * connect for already running mixer, we need to find the sink pipes 1130d93f8e55SVinod Koul * here and bind to them. This way dynamic connect works. 1131d93f8e55SVinod Koul * - Start sink pipeline, if not running 1132d93f8e55SVinod Koul * - Then run current pipe 1133d93f8e55SVinod Koul */ 1134d93f8e55SVinod Koul static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, 1135d93f8e55SVinod Koul struct skl *skl) 1136d93f8e55SVinod Koul { 11378724ff17SJeeja KP struct skl_module_cfg *src_mconfig; 1138d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 1139d93f8e55SVinod Koul int ret = 0; 1140d93f8e55SVinod Koul 11418724ff17SJeeja KP src_mconfig = w->priv; 1142d93f8e55SVinod Koul 1143d93f8e55SVinod Koul /* 1144d93f8e55SVinod Koul * find which sink it is connected to, bind with the sink, 1145d93f8e55SVinod Koul * if sink is not started, start sink pipe first, then start 1146d93f8e55SVinod Koul * this pipe 1147d93f8e55SVinod Koul */ 11486bd4cf85SJeeja KP ret = skl_tplg_bind_sinks(w, skl, w, src_mconfig); 11498724ff17SJeeja KP if (ret) 11508724ff17SJeeja KP return ret; 11518724ff17SJeeja KP 1152d93f8e55SVinod Koul /* Start source pipe last after starting all sinks */ 1153d1730c3dSJeeja KP if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) 1154d1730c3dSJeeja KP return skl_run_pipe(ctx, src_mconfig->pipe); 1155d93f8e55SVinod Koul 1156d93f8e55SVinod Koul return 0; 1157d93f8e55SVinod Koul } 1158d93f8e55SVinod Koul 11598724ff17SJeeja KP static struct snd_soc_dapm_widget *skl_get_src_dsp_widget( 11608724ff17SJeeja KP struct snd_soc_dapm_widget *w, struct skl *skl) 11618724ff17SJeeja KP { 11628724ff17SJeeja KP struct snd_soc_dapm_path *p; 11638724ff17SJeeja KP struct snd_soc_dapm_widget *src_w = NULL; 11648724ff17SJeeja KP struct skl_sst *ctx = skl->skl_sst; 11658724ff17SJeeja KP 1166d93f8e55SVinod Koul snd_soc_dapm_widget_for_each_source_path(w, p) { 11678724ff17SJeeja KP src_w = p->source; 1168d93f8e55SVinod Koul if (!p->connect) 1169d93f8e55SVinod Koul continue; 1170d93f8e55SVinod Koul 11718724ff17SJeeja KP dev_dbg(ctx->dev, "sink widget=%s\n", w->name); 11728724ff17SJeeja KP dev_dbg(ctx->dev, "src widget=%s\n", p->source->name); 1173d93f8e55SVinod Koul 1174d93f8e55SVinod Koul /* 11758724ff17SJeeja KP * here we will check widgets in sink pipelines, so that can 11768724ff17SJeeja KP * be any widgets type and we are only interested if they are 11778724ff17SJeeja KP * ones used for SKL so check that first 1178d93f8e55SVinod Koul */ 11798724ff17SJeeja KP if ((p->source->priv != NULL) && 1180cb1f904dSGuneshwor Singh is_skl_dsp_widget_type(p->source, ctx->dev)) { 11818724ff17SJeeja KP return p->source; 1182d93f8e55SVinod Koul } 1183d93f8e55SVinod Koul } 1184d93f8e55SVinod Koul 11858724ff17SJeeja KP if (src_w != NULL) 11868724ff17SJeeja KP return skl_get_src_dsp_widget(src_w, skl); 1187d93f8e55SVinod Koul 11888724ff17SJeeja KP return NULL; 1189d93f8e55SVinod Koul } 1190d93f8e55SVinod Koul 1191d93f8e55SVinod Koul /* 1192d93f8e55SVinod Koul * in the Post-PMU event of mixer we need to do following: 1193d93f8e55SVinod Koul * - Check if this pipe is running 1194d93f8e55SVinod Koul * - if not, then 1195d93f8e55SVinod Koul * - bind this pipeline to its source pipeline 1196d93f8e55SVinod Koul * if source pipe is already running, this means it is a dynamic 1197d93f8e55SVinod Koul * connection and we need to bind only to that pipe 1198d93f8e55SVinod Koul * - start this pipeline 1199d93f8e55SVinod Koul */ 1200d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, 1201d93f8e55SVinod Koul struct skl *skl) 1202d93f8e55SVinod Koul { 1203d93f8e55SVinod Koul int ret = 0; 1204d93f8e55SVinod Koul struct snd_soc_dapm_widget *source, *sink; 1205d93f8e55SVinod Koul struct skl_module_cfg *src_mconfig, *sink_mconfig; 1206d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 1207d93f8e55SVinod Koul int src_pipe_started = 0; 1208d93f8e55SVinod Koul 1209d93f8e55SVinod Koul sink = w; 1210d93f8e55SVinod Koul sink_mconfig = sink->priv; 1211d93f8e55SVinod Koul 1212d93f8e55SVinod Koul /* 1213d93f8e55SVinod Koul * If source pipe is already started, that means source is driving 1214d93f8e55SVinod Koul * one more sink before this sink got connected, Since source is 1215d93f8e55SVinod Koul * started, bind this sink to source and start this pipe. 1216d93f8e55SVinod Koul */ 12178724ff17SJeeja KP source = skl_get_src_dsp_widget(w, skl); 12188724ff17SJeeja KP if (source != NULL) { 1219d93f8e55SVinod Koul src_mconfig = source->priv; 1220d93f8e55SVinod Koul sink_mconfig = sink->priv; 1221d93f8e55SVinod Koul src_pipe_started = 1; 1222d93f8e55SVinod Koul 1223d93f8e55SVinod Koul /* 12248724ff17SJeeja KP * check pipe state, then no need to bind or start the 12258724ff17SJeeja KP * pipe 1226d93f8e55SVinod Koul */ 1227d93f8e55SVinod Koul if (src_mconfig->pipe->state != SKL_PIPE_STARTED) 1228d93f8e55SVinod Koul src_pipe_started = 0; 1229d93f8e55SVinod Koul } 1230d93f8e55SVinod Koul 1231d93f8e55SVinod Koul if (src_pipe_started) { 1232d93f8e55SVinod Koul ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig); 1233d93f8e55SVinod Koul if (ret) 1234d93f8e55SVinod Koul return ret; 1235d93f8e55SVinod Koul 1236cc6a4044SJeeja KP /* set module params after bind */ 1237cc6a4044SJeeja KP skl_tplg_set_module_bind_params(source, src_mconfig, ctx); 1238cc6a4044SJeeja KP skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx); 1239cc6a4044SJeeja KP 1240d1730c3dSJeeja KP if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) 1241d93f8e55SVinod Koul ret = skl_run_pipe(ctx, sink_mconfig->pipe); 1242d93f8e55SVinod Koul } 1243d93f8e55SVinod Koul 1244d93f8e55SVinod Koul return ret; 1245d93f8e55SVinod Koul } 1246d93f8e55SVinod Koul 1247d93f8e55SVinod Koul /* 1248d93f8e55SVinod Koul * in the Pre-PMD event of mixer we need to do following: 1249d93f8e55SVinod Koul * - Stop the pipe 1250d93f8e55SVinod Koul * - find the source connections and remove that from dapm_path_list 1251d93f8e55SVinod Koul * - unbind with source pipelines if still connected 1252d93f8e55SVinod Koul */ 1253d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w, 1254d93f8e55SVinod Koul struct skl *skl) 1255d93f8e55SVinod Koul { 1256d93f8e55SVinod Koul struct skl_module_cfg *src_mconfig, *sink_mconfig; 1257ce1b5551SJeeja KP int ret = 0, i; 1258d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 1259d93f8e55SVinod Koul 1260ce1b5551SJeeja KP sink_mconfig = w->priv; 1261d93f8e55SVinod Koul 1262d93f8e55SVinod Koul /* Stop the pipe */ 1263d93f8e55SVinod Koul ret = skl_stop_pipe(ctx, sink_mconfig->pipe); 1264d93f8e55SVinod Koul if (ret) 1265d93f8e55SVinod Koul return ret; 1266d93f8e55SVinod Koul 1267f6fa56e2SRamesh Babu for (i = 0; i < sink_mconfig->module->max_input_pins; i++) { 1268ce1b5551SJeeja KP if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) { 1269ce1b5551SJeeja KP src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg; 1270ce1b5551SJeeja KP if (!src_mconfig) 1271ce1b5551SJeeja KP continue; 1272d93f8e55SVinod Koul 1273ce1b5551SJeeja KP ret = skl_unbind_modules(ctx, 1274ce1b5551SJeeja KP src_mconfig, sink_mconfig); 1275ce1b5551SJeeja KP } 1276d93f8e55SVinod Koul } 1277d93f8e55SVinod Koul 1278d93f8e55SVinod Koul return ret; 1279d93f8e55SVinod Koul } 1280d93f8e55SVinod Koul 1281d93f8e55SVinod Koul /* 1282d93f8e55SVinod Koul * in the Post-PMD event of mixer we need to do following: 1283d93f8e55SVinod Koul * - Free the mcps used 1284d93f8e55SVinod Koul * - Free the mem used 1285d93f8e55SVinod Koul * - Unbind the modules within the pipeline 1286d93f8e55SVinod Koul * - Delete the pipeline (modules are not required to be explicitly 1287d93f8e55SVinod Koul * deleted, pipeline delete is enough here 1288d93f8e55SVinod Koul */ 1289d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, 1290d93f8e55SVinod Koul struct skl *skl) 1291d93f8e55SVinod Koul { 1292d93f8e55SVinod Koul struct skl_module_cfg *mconfig = w->priv; 1293d93f8e55SVinod Koul struct skl_pipe_module *w_module; 1294d93f8e55SVinod Koul struct skl_module_cfg *src_module = NULL, *dst_module; 1295d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 1296d93f8e55SVinod Koul struct skl_pipe *s_pipe = mconfig->pipe; 1297550b349aSDan Carpenter struct skl_module_deferred_bind *modules, *tmp; 1298d93f8e55SVinod Koul 1299260eb73aSDharageswari R if (s_pipe->state == SKL_PIPE_INVALID) 1300260eb73aSDharageswari R return -EINVAL; 1301260eb73aSDharageswari R 1302d93f8e55SVinod Koul skl_tplg_free_pipe_mcps(skl, mconfig); 130365976878SVinod Koul skl_tplg_free_pipe_mem(skl, mconfig); 1304d93f8e55SVinod Koul 1305d93f8e55SVinod Koul list_for_each_entry(w_module, &s_pipe->w_list, node) { 1306b8c722ddSJeeja KP if (list_empty(&skl->bind_list)) 1307b8c722ddSJeeja KP break; 1308b8c722ddSJeeja KP 1309b8c722ddSJeeja KP src_module = w_module->w->priv; 1310b8c722ddSJeeja KP 1311550b349aSDan Carpenter list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) { 1312b8c722ddSJeeja KP /* 1313b8c722ddSJeeja KP * When the destination module is deleted, Unbind the 1314b8c722ddSJeeja KP * modules from deferred bind list. 1315b8c722ddSJeeja KP */ 1316b8c722ddSJeeja KP if (modules->dst == src_module) { 1317b8c722ddSJeeja KP skl_unbind_modules(ctx, modules->src, 1318b8c722ddSJeeja KP modules->dst); 1319b8c722ddSJeeja KP } 1320b8c722ddSJeeja KP 1321b8c722ddSJeeja KP /* 1322b8c722ddSJeeja KP * When the source module is deleted, remove this entry 1323b8c722ddSJeeja KP * from the deferred bind list. 1324b8c722ddSJeeja KP */ 1325b8c722ddSJeeja KP if (modules->src == src_module) { 1326b8c722ddSJeeja KP list_del(&modules->node); 1327b8c722ddSJeeja KP modules->src = NULL; 1328b8c722ddSJeeja KP modules->dst = NULL; 1329b8c722ddSJeeja KP kfree(modules); 1330b8c722ddSJeeja KP } 1331b8c722ddSJeeja KP } 1332b8c722ddSJeeja KP } 1333b8c722ddSJeeja KP 1334b8c722ddSJeeja KP list_for_each_entry(w_module, &s_pipe->w_list, node) { 1335d93f8e55SVinod Koul dst_module = w_module->w->priv; 1336d93f8e55SVinod Koul 1337260eb73aSDharageswari R if (mconfig->m_state >= SKL_MODULE_INIT_DONE) 13387ae3cb15SVinod Koul skl_tplg_free_pipe_mcps(skl, dst_module); 1339d93f8e55SVinod Koul if (src_module == NULL) { 1340d93f8e55SVinod Koul src_module = dst_module; 1341d93f8e55SVinod Koul continue; 1342d93f8e55SVinod Koul } 1343d93f8e55SVinod Koul 13447ca42f5aSGuneshwor Singh skl_unbind_modules(ctx, src_module, dst_module); 1345d93f8e55SVinod Koul src_module = dst_module; 1346d93f8e55SVinod Koul } 1347d93f8e55SVinod Koul 1348547cafa3SVinod Koul skl_delete_pipe(ctx, mconfig->pipe); 1349d93f8e55SVinod Koul 1350473a4d51SJeeja KP list_for_each_entry(w_module, &s_pipe->w_list, node) { 1351473a4d51SJeeja KP src_module = w_module->w->priv; 1352473a4d51SJeeja KP src_module->m_state = SKL_MODULE_UNINIT; 1353473a4d51SJeeja KP } 1354473a4d51SJeeja KP 13556c5768b3SDharageswari R return skl_tplg_unload_pipe_modules(ctx, s_pipe); 1356d93f8e55SVinod Koul } 1357d93f8e55SVinod Koul 1358d93f8e55SVinod Koul /* 1359d93f8e55SVinod Koul * in the Post-PMD event of PGA we need to do following: 1360d93f8e55SVinod Koul * - Free the mcps used 1361d93f8e55SVinod Koul * - Stop the pipeline 1362d93f8e55SVinod Koul * - In source pipe is connected, unbind with source pipelines 1363d93f8e55SVinod Koul */ 1364d93f8e55SVinod Koul static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, 1365d93f8e55SVinod Koul struct skl *skl) 1366d93f8e55SVinod Koul { 1367d93f8e55SVinod Koul struct skl_module_cfg *src_mconfig, *sink_mconfig; 1368ce1b5551SJeeja KP int ret = 0, i; 1369d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 1370d93f8e55SVinod Koul 1371ce1b5551SJeeja KP src_mconfig = w->priv; 1372d93f8e55SVinod Koul 1373d93f8e55SVinod Koul /* Stop the pipe since this is a mixin module */ 1374d93f8e55SVinod Koul ret = skl_stop_pipe(ctx, src_mconfig->pipe); 1375d93f8e55SVinod Koul if (ret) 1376d93f8e55SVinod Koul return ret; 1377d93f8e55SVinod Koul 1378f6fa56e2SRamesh Babu for (i = 0; i < src_mconfig->module->max_output_pins; i++) { 1379ce1b5551SJeeja KP if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) { 1380ce1b5551SJeeja KP sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg; 1381ce1b5551SJeeja KP if (!sink_mconfig) 1382ce1b5551SJeeja KP continue; 1383d93f8e55SVinod Koul /* 1384ce1b5551SJeeja KP * This is a connecter and if path is found that means 1385d93f8e55SVinod Koul * unbind between source and sink has not happened yet 1386d93f8e55SVinod Koul */ 1387ce1b5551SJeeja KP ret = skl_unbind_modules(ctx, src_mconfig, 1388ce1b5551SJeeja KP sink_mconfig); 1389ce1b5551SJeeja KP } 1390d93f8e55SVinod Koul } 1391d93f8e55SVinod Koul 1392d93f8e55SVinod Koul return ret; 1393d93f8e55SVinod Koul } 1394d93f8e55SVinod Koul 1395d93f8e55SVinod Koul /* 1396d93f8e55SVinod Koul * In modelling, we assume there will be ONLY one mixer in a pipeline. If a 1397d93f8e55SVinod Koul * second one is required that is created as another pipe entity. 1398d93f8e55SVinod Koul * The mixer is responsible for pipe management and represent a pipeline 1399d93f8e55SVinod Koul * instance 1400d93f8e55SVinod Koul */ 1401d93f8e55SVinod Koul static int skl_tplg_mixer_event(struct snd_soc_dapm_widget *w, 1402d93f8e55SVinod Koul struct snd_kcontrol *k, int event) 1403d93f8e55SVinod Koul { 1404d93f8e55SVinod Koul struct snd_soc_dapm_context *dapm = w->dapm; 1405d93f8e55SVinod Koul struct skl *skl = get_skl_ctx(dapm->dev); 1406d93f8e55SVinod Koul 1407d93f8e55SVinod Koul switch (event) { 1408d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMU: 1409d93f8e55SVinod Koul return skl_tplg_mixer_dapm_pre_pmu_event(w, skl); 1410d93f8e55SVinod Koul 1411d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMU: 1412d93f8e55SVinod Koul return skl_tplg_mixer_dapm_post_pmu_event(w, skl); 1413d93f8e55SVinod Koul 1414d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMD: 1415d93f8e55SVinod Koul return skl_tplg_mixer_dapm_pre_pmd_event(w, skl); 1416d93f8e55SVinod Koul 1417d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMD: 1418d93f8e55SVinod Koul return skl_tplg_mixer_dapm_post_pmd_event(w, skl); 1419d93f8e55SVinod Koul } 1420d93f8e55SVinod Koul 1421d93f8e55SVinod Koul return 0; 1422d93f8e55SVinod Koul } 1423d93f8e55SVinod Koul 1424d93f8e55SVinod Koul /* 1425d93f8e55SVinod Koul * In modelling, we assumed rest of the modules in pipeline are PGA. But we 1426d93f8e55SVinod Koul * are interested in last PGA (leaf PGA) in a pipeline to disconnect with 1427d93f8e55SVinod Koul * the sink when it is running (two FE to one BE or one FE to two BE) 1428d93f8e55SVinod Koul * scenarios 1429d93f8e55SVinod Koul */ 1430d93f8e55SVinod Koul static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w, 1431d93f8e55SVinod Koul struct snd_kcontrol *k, int event) 1432d93f8e55SVinod Koul 1433d93f8e55SVinod Koul { 1434d93f8e55SVinod Koul struct snd_soc_dapm_context *dapm = w->dapm; 1435d93f8e55SVinod Koul struct skl *skl = get_skl_ctx(dapm->dev); 1436d93f8e55SVinod Koul 1437d93f8e55SVinod Koul switch (event) { 1438d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMU: 1439d93f8e55SVinod Koul return skl_tplg_pga_dapm_pre_pmu_event(w, skl); 1440d93f8e55SVinod Koul 1441d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMD: 1442d93f8e55SVinod Koul return skl_tplg_pga_dapm_post_pmd_event(w, skl); 1443d93f8e55SVinod Koul } 1444d93f8e55SVinod Koul 1445d93f8e55SVinod Koul return 0; 1446d93f8e55SVinod Koul } 1447cfb0a873SVinod Koul 1448140adfbaSJeeja KP static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol, 1449140adfbaSJeeja KP unsigned int __user *data, unsigned int size) 1450140adfbaSJeeja KP { 1451140adfbaSJeeja KP struct soc_bytes_ext *sb = 1452140adfbaSJeeja KP (struct soc_bytes_ext *)kcontrol->private_value; 1453140adfbaSJeeja KP struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private; 14547d9f2911SOmair M Abdullah struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); 14557d9f2911SOmair M Abdullah struct skl_module_cfg *mconfig = w->priv; 14567d9f2911SOmair M Abdullah struct skl *skl = get_skl_ctx(w->dapm->dev); 14577d9f2911SOmair M Abdullah 14587d9f2911SOmair M Abdullah if (w->power) 14597d9f2911SOmair M Abdullah skl_get_module_params(skl->skl_sst, (u32 *)bc->params, 14600d682104SDharageswari R bc->size, bc->param_id, mconfig); 1461140adfbaSJeeja KP 146241556f68SVinod Koul /* decrement size for TLV header */ 146341556f68SVinod Koul size -= 2 * sizeof(u32); 146441556f68SVinod Koul 146541556f68SVinod Koul /* check size as we don't want to send kernel data */ 146641556f68SVinod Koul if (size > bc->max) 146741556f68SVinod Koul size = bc->max; 146841556f68SVinod Koul 1469140adfbaSJeeja KP if (bc->params) { 1470140adfbaSJeeja KP if (copy_to_user(data, &bc->param_id, sizeof(u32))) 1471140adfbaSJeeja KP return -EFAULT; 1472e8bc3c99SDan Carpenter if (copy_to_user(data + 1, &size, sizeof(u32))) 1473140adfbaSJeeja KP return -EFAULT; 1474e8bc3c99SDan Carpenter if (copy_to_user(data + 2, bc->params, size)) 1475140adfbaSJeeja KP return -EFAULT; 1476140adfbaSJeeja KP } 1477140adfbaSJeeja KP 1478140adfbaSJeeja KP return 0; 1479140adfbaSJeeja KP } 1480140adfbaSJeeja KP 1481140adfbaSJeeja KP #define SKL_PARAM_VENDOR_ID 0xff 1482140adfbaSJeeja KP 1483140adfbaSJeeja KP static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol, 1484140adfbaSJeeja KP const unsigned int __user *data, unsigned int size) 1485140adfbaSJeeja KP { 1486140adfbaSJeeja KP struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); 1487140adfbaSJeeja KP struct skl_module_cfg *mconfig = w->priv; 1488140adfbaSJeeja KP struct soc_bytes_ext *sb = 1489140adfbaSJeeja KP (struct soc_bytes_ext *)kcontrol->private_value; 1490140adfbaSJeeja KP struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private; 1491140adfbaSJeeja KP struct skl *skl = get_skl_ctx(w->dapm->dev); 1492140adfbaSJeeja KP 1493140adfbaSJeeja KP if (ac->params) { 14940d682104SDharageswari R if (size > ac->max) 14950d682104SDharageswari R return -EINVAL; 14960d682104SDharageswari R 14970d682104SDharageswari R ac->size = size; 1498140adfbaSJeeja KP /* 1499140adfbaSJeeja KP * if the param_is is of type Vendor, firmware expects actual 1500140adfbaSJeeja KP * parameter id and size from the control. 1501140adfbaSJeeja KP */ 1502140adfbaSJeeja KP if (ac->param_id == SKL_PARAM_VENDOR_ID) { 1503140adfbaSJeeja KP if (copy_from_user(ac->params, data, size)) 1504140adfbaSJeeja KP return -EFAULT; 1505140adfbaSJeeja KP } else { 1506140adfbaSJeeja KP if (copy_from_user(ac->params, 150765b4bcb8SAlan data + 2, size)) 1508140adfbaSJeeja KP return -EFAULT; 1509140adfbaSJeeja KP } 1510140adfbaSJeeja KP 1511140adfbaSJeeja KP if (w->power) 1512140adfbaSJeeja KP return skl_set_module_params(skl->skl_sst, 15130d682104SDharageswari R (u32 *)ac->params, ac->size, 1514140adfbaSJeeja KP ac->param_id, mconfig); 1515140adfbaSJeeja KP } 1516140adfbaSJeeja KP 1517140adfbaSJeeja KP return 0; 1518140adfbaSJeeja KP } 1519140adfbaSJeeja KP 15207a1b749bSDharageswari R static int skl_tplg_mic_control_get(struct snd_kcontrol *kcontrol, 15217a1b749bSDharageswari R struct snd_ctl_elem_value *ucontrol) 15227a1b749bSDharageswari R { 15237a1b749bSDharageswari R struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); 15247a1b749bSDharageswari R struct skl_module_cfg *mconfig = w->priv; 15257a1b749bSDharageswari R struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value; 15267a1b749bSDharageswari R u32 ch_type = *((u32 *)ec->dobj.private); 15277a1b749bSDharageswari R 15287a1b749bSDharageswari R if (mconfig->dmic_ch_type == ch_type) 15297a1b749bSDharageswari R ucontrol->value.enumerated.item[0] = 15307a1b749bSDharageswari R mconfig->dmic_ch_combo_index; 15317a1b749bSDharageswari R else 15327a1b749bSDharageswari R ucontrol->value.enumerated.item[0] = 0; 15337a1b749bSDharageswari R 15347a1b749bSDharageswari R return 0; 15357a1b749bSDharageswari R } 15367a1b749bSDharageswari R 15377a1b749bSDharageswari R static int skl_fill_mic_sel_params(struct skl_module_cfg *mconfig, 15387a1b749bSDharageswari R struct skl_mic_sel_config *mic_cfg, struct device *dev) 15397a1b749bSDharageswari R { 15407a1b749bSDharageswari R struct skl_specific_cfg *sp_cfg = &mconfig->formats_config; 15417a1b749bSDharageswari R 15427a1b749bSDharageswari R sp_cfg->caps_size = sizeof(struct skl_mic_sel_config); 15437a1b749bSDharageswari R sp_cfg->set_params = SKL_PARAM_SET; 15447a1b749bSDharageswari R sp_cfg->param_id = 0x00; 15457a1b749bSDharageswari R if (!sp_cfg->caps) { 15467a1b749bSDharageswari R sp_cfg->caps = devm_kzalloc(dev, sp_cfg->caps_size, GFP_KERNEL); 15477a1b749bSDharageswari R if (!sp_cfg->caps) 15487a1b749bSDharageswari R return -ENOMEM; 15497a1b749bSDharageswari R } 15507a1b749bSDharageswari R 15517a1b749bSDharageswari R mic_cfg->mic_switch = SKL_MIC_SEL_SWITCH; 15527a1b749bSDharageswari R mic_cfg->flags = 0; 15537a1b749bSDharageswari R memcpy(sp_cfg->caps, mic_cfg, sp_cfg->caps_size); 15547a1b749bSDharageswari R 15557a1b749bSDharageswari R return 0; 15567a1b749bSDharageswari R } 15577a1b749bSDharageswari R 15587a1b749bSDharageswari R static int skl_tplg_mic_control_set(struct snd_kcontrol *kcontrol, 15597a1b749bSDharageswari R struct snd_ctl_elem_value *ucontrol) 15607a1b749bSDharageswari R { 15617a1b749bSDharageswari R struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); 15627a1b749bSDharageswari R struct skl_module_cfg *mconfig = w->priv; 15637a1b749bSDharageswari R struct skl_mic_sel_config mic_cfg = {0}; 15647a1b749bSDharageswari R struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value; 15657a1b749bSDharageswari R u32 ch_type = *((u32 *)ec->dobj.private); 15667a1b749bSDharageswari R const int *list; 15677a1b749bSDharageswari R u8 in_ch, out_ch, index; 15687a1b749bSDharageswari R 15697a1b749bSDharageswari R mconfig->dmic_ch_type = ch_type; 15707a1b749bSDharageswari R mconfig->dmic_ch_combo_index = ucontrol->value.enumerated.item[0]; 15717a1b749bSDharageswari R 15727a1b749bSDharageswari R /* enum control index 0 is INVALID, so no channels to be set */ 15737a1b749bSDharageswari R if (mconfig->dmic_ch_combo_index == 0) 15747a1b749bSDharageswari R return 0; 15757a1b749bSDharageswari R 15767a1b749bSDharageswari R /* No valid channel selection map for index 0, so offset by 1 */ 15777a1b749bSDharageswari R index = mconfig->dmic_ch_combo_index - 1; 15787a1b749bSDharageswari R 15797a1b749bSDharageswari R switch (ch_type) { 15807a1b749bSDharageswari R case SKL_CH_MONO: 15817a1b749bSDharageswari R if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_mono_list)) 15827a1b749bSDharageswari R return -EINVAL; 15837a1b749bSDharageswari R 15847a1b749bSDharageswari R list = &mic_mono_list[index]; 15857a1b749bSDharageswari R break; 15867a1b749bSDharageswari R 15877a1b749bSDharageswari R case SKL_CH_STEREO: 15887a1b749bSDharageswari R if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_stereo_list)) 15897a1b749bSDharageswari R return -EINVAL; 15907a1b749bSDharageswari R 15917a1b749bSDharageswari R list = mic_stereo_list[index]; 15927a1b749bSDharageswari R break; 15937a1b749bSDharageswari R 15947a1b749bSDharageswari R case SKL_CH_TRIO: 15957a1b749bSDharageswari R if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_trio_list)) 15967a1b749bSDharageswari R return -EINVAL; 15977a1b749bSDharageswari R 15987a1b749bSDharageswari R list = mic_trio_list[index]; 15997a1b749bSDharageswari R break; 16007a1b749bSDharageswari R 16017a1b749bSDharageswari R case SKL_CH_QUATRO: 16027a1b749bSDharageswari R if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_quatro_list)) 16037a1b749bSDharageswari R return -EINVAL; 16047a1b749bSDharageswari R 16057a1b749bSDharageswari R list = mic_quatro_list[index]; 16067a1b749bSDharageswari R break; 16077a1b749bSDharageswari R 16087a1b749bSDharageswari R default: 16097a1b749bSDharageswari R dev_err(w->dapm->dev, 16107a1b749bSDharageswari R "Invalid channel %d for mic_select module\n", 16117a1b749bSDharageswari R ch_type); 16127a1b749bSDharageswari R return -EINVAL; 16137a1b749bSDharageswari R 16147a1b749bSDharageswari R } 16157a1b749bSDharageswari R 16167a1b749bSDharageswari R /* channel type enum map to number of chanels for that type */ 16177a1b749bSDharageswari R for (out_ch = 0; out_ch < ch_type; out_ch++) { 16187a1b749bSDharageswari R in_ch = list[out_ch]; 16197a1b749bSDharageswari R mic_cfg.blob[out_ch][in_ch] = SKL_DEFAULT_MIC_SEL_GAIN; 16207a1b749bSDharageswari R } 16217a1b749bSDharageswari R 16227a1b749bSDharageswari R return skl_fill_mic_sel_params(mconfig, &mic_cfg, w->dapm->dev); 16237a1b749bSDharageswari R } 16247a1b749bSDharageswari R 1625cfb0a873SVinod Koul /* 16268871dcb9SJeeja KP * Fill the dma id for host and link. In case of passthrough 16278871dcb9SJeeja KP * pipeline, this will both host and link in the same 16288871dcb9SJeeja KP * pipeline, so need to copy the link and host based on dev_type 16298871dcb9SJeeja KP */ 16308871dcb9SJeeja KP static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg, 16318871dcb9SJeeja KP struct skl_pipe_params *params) 16328871dcb9SJeeja KP { 16338871dcb9SJeeja KP struct skl_pipe *pipe = mcfg->pipe; 16348871dcb9SJeeja KP 16358871dcb9SJeeja KP if (pipe->passthru) { 16368871dcb9SJeeja KP switch (mcfg->dev_type) { 16378871dcb9SJeeja KP case SKL_DEVICE_HDALINK: 16388871dcb9SJeeja KP pipe->p_params->link_dma_id = params->link_dma_id; 163912c3be0eSJeeja KP pipe->p_params->link_index = params->link_index; 16407f975a38SJeeja KP pipe->p_params->link_bps = params->link_bps; 16418871dcb9SJeeja KP break; 16428871dcb9SJeeja KP 16438871dcb9SJeeja KP case SKL_DEVICE_HDAHOST: 16448871dcb9SJeeja KP pipe->p_params->host_dma_id = params->host_dma_id; 16457f975a38SJeeja KP pipe->p_params->host_bps = params->host_bps; 16468871dcb9SJeeja KP break; 16478871dcb9SJeeja KP 16488871dcb9SJeeja KP default: 16498871dcb9SJeeja KP break; 16508871dcb9SJeeja KP } 16518871dcb9SJeeja KP pipe->p_params->s_fmt = params->s_fmt; 16528871dcb9SJeeja KP pipe->p_params->ch = params->ch; 16538871dcb9SJeeja KP pipe->p_params->s_freq = params->s_freq; 16548871dcb9SJeeja KP pipe->p_params->stream = params->stream; 165512c3be0eSJeeja KP pipe->p_params->format = params->format; 16568871dcb9SJeeja KP 16578871dcb9SJeeja KP } else { 16588871dcb9SJeeja KP memcpy(pipe->p_params, params, sizeof(*params)); 16598871dcb9SJeeja KP } 16608871dcb9SJeeja KP } 16618871dcb9SJeeja KP 16628871dcb9SJeeja KP /* 1663cfb0a873SVinod Koul * The FE params are passed by hw_params of the DAI. 1664cfb0a873SVinod Koul * On hw_params, the params are stored in Gateway module of the FE and we 1665cfb0a873SVinod Koul * need to calculate the format in DSP module configuration, that 1666cfb0a873SVinod Koul * conversion is done here 1667cfb0a873SVinod Koul */ 1668cfb0a873SVinod Koul int skl_tplg_update_pipe_params(struct device *dev, 1669cfb0a873SVinod Koul struct skl_module_cfg *mconfig, 1670cfb0a873SVinod Koul struct skl_pipe_params *params) 1671cfb0a873SVinod Koul { 1672f6fa56e2SRamesh Babu struct skl_module_res *res = &mconfig->module->resources[0]; 1673f6fa56e2SRamesh Babu struct skl *skl = get_skl_ctx(dev); 1674cfb0a873SVinod Koul struct skl_module_fmt *format = NULL; 1675f6fa56e2SRamesh Babu u8 cfg_idx = mconfig->pipe->cur_config_idx; 1676cfb0a873SVinod Koul 16778871dcb9SJeeja KP skl_tplg_fill_dma_id(mconfig, params); 1678f6fa56e2SRamesh Babu mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx; 1679f6fa56e2SRamesh Babu mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx; 1680f6fa56e2SRamesh Babu 1681f6fa56e2SRamesh Babu if (skl->nr_modules) 1682f6fa56e2SRamesh Babu return 0; 1683cfb0a873SVinod Koul 1684cfb0a873SVinod Koul if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) 1685f6fa56e2SRamesh Babu format = &mconfig->module->formats[0].inputs[0].fmt; 1686cfb0a873SVinod Koul else 1687f6fa56e2SRamesh Babu format = &mconfig->module->formats[0].outputs[0].fmt; 1688cfb0a873SVinod Koul 1689cfb0a873SVinod Koul /* set the hw_params */ 1690cfb0a873SVinod Koul format->s_freq = params->s_freq; 1691cfb0a873SVinod Koul format->channels = params->ch; 1692cfb0a873SVinod Koul format->valid_bit_depth = skl_get_bit_depth(params->s_fmt); 1693cfb0a873SVinod Koul 1694cfb0a873SVinod Koul /* 1695cfb0a873SVinod Koul * 16 bit is 16 bit container whereas 24 bit is in 32 bit 1696cfb0a873SVinod Koul * container so update bit depth accordingly 1697cfb0a873SVinod Koul */ 1698cfb0a873SVinod Koul switch (format->valid_bit_depth) { 1699cfb0a873SVinod Koul case SKL_DEPTH_16BIT: 1700cfb0a873SVinod Koul format->bit_depth = format->valid_bit_depth; 1701cfb0a873SVinod Koul break; 1702cfb0a873SVinod Koul 1703cfb0a873SVinod Koul case SKL_DEPTH_24BIT: 17046654f39eSJeeja KP case SKL_DEPTH_32BIT: 1705cfb0a873SVinod Koul format->bit_depth = SKL_DEPTH_32BIT; 1706cfb0a873SVinod Koul break; 1707cfb0a873SVinod Koul 1708cfb0a873SVinod Koul default: 1709cfb0a873SVinod Koul dev_err(dev, "Invalid bit depth %x for pipe\n", 1710cfb0a873SVinod Koul format->valid_bit_depth); 1711cfb0a873SVinod Koul return -EINVAL; 1712cfb0a873SVinod Koul } 1713cfb0a873SVinod Koul 1714cfb0a873SVinod Koul if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { 1715f6fa56e2SRamesh Babu res->ibs = (format->s_freq / 1000) * 1716cfb0a873SVinod Koul (format->channels) * 1717cfb0a873SVinod Koul (format->bit_depth >> 3); 1718cfb0a873SVinod Koul } else { 1719f6fa56e2SRamesh Babu res->obs = (format->s_freq / 1000) * 1720cfb0a873SVinod Koul (format->channels) * 1721cfb0a873SVinod Koul (format->bit_depth >> 3); 1722cfb0a873SVinod Koul } 1723cfb0a873SVinod Koul 1724cfb0a873SVinod Koul return 0; 1725cfb0a873SVinod Koul } 1726cfb0a873SVinod Koul 1727cfb0a873SVinod Koul /* 1728cfb0a873SVinod Koul * Query the module config for the FE DAI 1729cfb0a873SVinod Koul * This is used to find the hw_params set for that DAI and apply to FE 1730cfb0a873SVinod Koul * pipeline 1731cfb0a873SVinod Koul */ 1732cfb0a873SVinod Koul struct skl_module_cfg * 1733cfb0a873SVinod Koul skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream) 1734cfb0a873SVinod Koul { 1735cfb0a873SVinod Koul struct snd_soc_dapm_widget *w; 1736cfb0a873SVinod Koul struct snd_soc_dapm_path *p = NULL; 1737cfb0a873SVinod Koul 1738cfb0a873SVinod Koul if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 1739cfb0a873SVinod Koul w = dai->playback_widget; 1740f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_sink_path(w, p) { 1741cfb0a873SVinod Koul if (p->connect && p->sink->power && 1742cb1f904dSGuneshwor Singh !is_skl_dsp_widget_type(p->sink, dai->dev)) 1743cfb0a873SVinod Koul continue; 1744cfb0a873SVinod Koul 1745cfb0a873SVinod Koul if (p->sink->priv) { 1746cfb0a873SVinod Koul dev_dbg(dai->dev, "set params for %s\n", 1747cfb0a873SVinod Koul p->sink->name); 1748cfb0a873SVinod Koul return p->sink->priv; 1749cfb0a873SVinod Koul } 1750cfb0a873SVinod Koul } 1751cfb0a873SVinod Koul } else { 1752cfb0a873SVinod Koul w = dai->capture_widget; 1753f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_source_path(w, p) { 1754cfb0a873SVinod Koul if (p->connect && p->source->power && 1755cb1f904dSGuneshwor Singh !is_skl_dsp_widget_type(p->source, dai->dev)) 1756cfb0a873SVinod Koul continue; 1757cfb0a873SVinod Koul 1758cfb0a873SVinod Koul if (p->source->priv) { 1759cfb0a873SVinod Koul dev_dbg(dai->dev, "set params for %s\n", 1760cfb0a873SVinod Koul p->source->name); 1761cfb0a873SVinod Koul return p->source->priv; 1762cfb0a873SVinod Koul } 1763cfb0a873SVinod Koul } 1764cfb0a873SVinod Koul } 1765cfb0a873SVinod Koul 1766cfb0a873SVinod Koul return NULL; 1767cfb0a873SVinod Koul } 1768cfb0a873SVinod Koul 1769718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_pb_cpr( 1770718a42b5SDharageswari.R struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w) 1771718a42b5SDharageswari.R { 1772718a42b5SDharageswari.R struct snd_soc_dapm_path *p; 1773718a42b5SDharageswari.R struct skl_module_cfg *mconfig = NULL; 1774718a42b5SDharageswari.R 1775718a42b5SDharageswari.R snd_soc_dapm_widget_for_each_source_path(w, p) { 1776718a42b5SDharageswari.R if (w->endpoints[SND_SOC_DAPM_DIR_OUT] > 0) { 1777718a42b5SDharageswari.R if (p->connect && 1778718a42b5SDharageswari.R (p->sink->id == snd_soc_dapm_aif_out) && 1779718a42b5SDharageswari.R p->source->priv) { 1780718a42b5SDharageswari.R mconfig = p->source->priv; 1781718a42b5SDharageswari.R return mconfig; 1782718a42b5SDharageswari.R } 1783718a42b5SDharageswari.R mconfig = skl_get_mconfig_pb_cpr(dai, p->source); 1784718a42b5SDharageswari.R if (mconfig) 1785718a42b5SDharageswari.R return mconfig; 1786718a42b5SDharageswari.R } 1787718a42b5SDharageswari.R } 1788718a42b5SDharageswari.R return mconfig; 1789718a42b5SDharageswari.R } 1790718a42b5SDharageswari.R 1791718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_cap_cpr( 1792718a42b5SDharageswari.R struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w) 1793718a42b5SDharageswari.R { 1794718a42b5SDharageswari.R struct snd_soc_dapm_path *p; 1795718a42b5SDharageswari.R struct skl_module_cfg *mconfig = NULL; 1796718a42b5SDharageswari.R 1797718a42b5SDharageswari.R snd_soc_dapm_widget_for_each_sink_path(w, p) { 1798718a42b5SDharageswari.R if (w->endpoints[SND_SOC_DAPM_DIR_IN] > 0) { 1799718a42b5SDharageswari.R if (p->connect && 1800718a42b5SDharageswari.R (p->source->id == snd_soc_dapm_aif_in) && 1801718a42b5SDharageswari.R p->sink->priv) { 1802718a42b5SDharageswari.R mconfig = p->sink->priv; 1803718a42b5SDharageswari.R return mconfig; 1804718a42b5SDharageswari.R } 1805718a42b5SDharageswari.R mconfig = skl_get_mconfig_cap_cpr(dai, p->sink); 1806718a42b5SDharageswari.R if (mconfig) 1807718a42b5SDharageswari.R return mconfig; 1808718a42b5SDharageswari.R } 1809718a42b5SDharageswari.R } 1810718a42b5SDharageswari.R return mconfig; 1811718a42b5SDharageswari.R } 1812718a42b5SDharageswari.R 1813718a42b5SDharageswari.R struct skl_module_cfg * 1814718a42b5SDharageswari.R skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, int stream) 1815718a42b5SDharageswari.R { 1816718a42b5SDharageswari.R struct snd_soc_dapm_widget *w; 1817718a42b5SDharageswari.R struct skl_module_cfg *mconfig; 1818718a42b5SDharageswari.R 1819718a42b5SDharageswari.R if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 1820718a42b5SDharageswari.R w = dai->playback_widget; 1821718a42b5SDharageswari.R mconfig = skl_get_mconfig_pb_cpr(dai, w); 1822718a42b5SDharageswari.R } else { 1823718a42b5SDharageswari.R w = dai->capture_widget; 1824718a42b5SDharageswari.R mconfig = skl_get_mconfig_cap_cpr(dai, w); 1825718a42b5SDharageswari.R } 1826718a42b5SDharageswari.R return mconfig; 1827718a42b5SDharageswari.R } 1828718a42b5SDharageswari.R 1829cfb0a873SVinod Koul static u8 skl_tplg_be_link_type(int dev_type) 1830cfb0a873SVinod Koul { 1831cfb0a873SVinod Koul int ret; 1832cfb0a873SVinod Koul 1833cfb0a873SVinod Koul switch (dev_type) { 1834cfb0a873SVinod Koul case SKL_DEVICE_BT: 1835cfb0a873SVinod Koul ret = NHLT_LINK_SSP; 1836cfb0a873SVinod Koul break; 1837cfb0a873SVinod Koul 1838cfb0a873SVinod Koul case SKL_DEVICE_DMIC: 1839cfb0a873SVinod Koul ret = NHLT_LINK_DMIC; 1840cfb0a873SVinod Koul break; 1841cfb0a873SVinod Koul 1842cfb0a873SVinod Koul case SKL_DEVICE_I2S: 1843cfb0a873SVinod Koul ret = NHLT_LINK_SSP; 1844cfb0a873SVinod Koul break; 1845cfb0a873SVinod Koul 1846cfb0a873SVinod Koul case SKL_DEVICE_HDALINK: 1847cfb0a873SVinod Koul ret = NHLT_LINK_HDA; 1848cfb0a873SVinod Koul break; 1849cfb0a873SVinod Koul 1850cfb0a873SVinod Koul default: 1851cfb0a873SVinod Koul ret = NHLT_LINK_INVALID; 1852cfb0a873SVinod Koul break; 1853cfb0a873SVinod Koul } 1854cfb0a873SVinod Koul 1855cfb0a873SVinod Koul return ret; 1856cfb0a873SVinod Koul } 1857cfb0a873SVinod Koul 1858cfb0a873SVinod Koul /* 1859cfb0a873SVinod Koul * Fill the BE gateway parameters 1860cfb0a873SVinod Koul * The BE gateway expects a blob of parameters which are kept in the ACPI 1861cfb0a873SVinod Koul * NHLT blob, so query the blob for interface type (i2s/pdm) and instance. 1862cfb0a873SVinod Koul * The port can have multiple settings so pick based on the PCM 1863cfb0a873SVinod Koul * parameters 1864cfb0a873SVinod Koul */ 1865cfb0a873SVinod Koul static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai, 1866cfb0a873SVinod Koul struct skl_module_cfg *mconfig, 1867cfb0a873SVinod Koul struct skl_pipe_params *params) 1868cfb0a873SVinod Koul { 1869cfb0a873SVinod Koul struct nhlt_specific_cfg *cfg; 1870cfb0a873SVinod Koul struct skl *skl = get_skl_ctx(dai->dev); 1871cfb0a873SVinod Koul int link_type = skl_tplg_be_link_type(mconfig->dev_type); 1872db2f586bSSenthilnathan Veppur u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type); 1873cfb0a873SVinod Koul 18748871dcb9SJeeja KP skl_tplg_fill_dma_id(mconfig, params); 1875cfb0a873SVinod Koul 1876b30c275eSJeeja KP if (link_type == NHLT_LINK_HDA) 1877b30c275eSJeeja KP return 0; 1878b30c275eSJeeja KP 1879cfb0a873SVinod Koul /* update the blob based on virtual bus_id*/ 1880cfb0a873SVinod Koul cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type, 1881cfb0a873SVinod Koul params->s_fmt, params->ch, 1882db2f586bSSenthilnathan Veppur params->s_freq, params->stream, 1883db2f586bSSenthilnathan Veppur dev_type); 1884cfb0a873SVinod Koul if (cfg) { 1885cfb0a873SVinod Koul mconfig->formats_config.caps_size = cfg->size; 1886bc03281aSJeeja KP mconfig->formats_config.caps = (u32 *) &cfg->caps; 1887cfb0a873SVinod Koul } else { 1888cfb0a873SVinod Koul dev_err(dai->dev, "Blob NULL for id %x type %d dirn %d\n", 1889cfb0a873SVinod Koul mconfig->vbus_id, link_type, 1890cfb0a873SVinod Koul params->stream); 1891cfb0a873SVinod Koul dev_err(dai->dev, "PCM: ch %d, freq %d, fmt %d\n", 1892cfb0a873SVinod Koul params->ch, params->s_freq, params->s_fmt); 1893cfb0a873SVinod Koul return -EINVAL; 1894cfb0a873SVinod Koul } 1895cfb0a873SVinod Koul 1896cfb0a873SVinod Koul return 0; 1897cfb0a873SVinod Koul } 1898cfb0a873SVinod Koul 1899cfb0a873SVinod Koul static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai, 1900cfb0a873SVinod Koul struct snd_soc_dapm_widget *w, 1901cfb0a873SVinod Koul struct skl_pipe_params *params) 1902cfb0a873SVinod Koul { 1903cfb0a873SVinod Koul struct snd_soc_dapm_path *p; 19044d8adccbSSubhransu S. Prusty int ret = -EIO; 1905cfb0a873SVinod Koul 1906f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_source_path(w, p) { 1907cb1f904dSGuneshwor Singh if (p->connect && is_skl_dsp_widget_type(p->source, dai->dev) && 1908cfb0a873SVinod Koul p->source->priv) { 1909cfb0a873SVinod Koul 19109a03cb49SJeeja KP ret = skl_tplg_be_fill_pipe_params(dai, 19119a03cb49SJeeja KP p->source->priv, params); 19124d8adccbSSubhransu S. Prusty if (ret < 0) 19134d8adccbSSubhransu S. Prusty return ret; 1914cfb0a873SVinod Koul } else { 19159a03cb49SJeeja KP ret = skl_tplg_be_set_src_pipe_params(dai, 19169a03cb49SJeeja KP p->source, params); 19174d8adccbSSubhransu S. Prusty if (ret < 0) 19184d8adccbSSubhransu S. Prusty return ret; 1919cfb0a873SVinod Koul } 1920cfb0a873SVinod Koul } 1921cfb0a873SVinod Koul 19224d8adccbSSubhransu S. Prusty return ret; 1923cfb0a873SVinod Koul } 1924cfb0a873SVinod Koul 1925cfb0a873SVinod Koul static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai, 1926cfb0a873SVinod Koul struct snd_soc_dapm_widget *w, struct skl_pipe_params *params) 1927cfb0a873SVinod Koul { 1928cfb0a873SVinod Koul struct snd_soc_dapm_path *p = NULL; 19294d8adccbSSubhransu S. Prusty int ret = -EIO; 1930cfb0a873SVinod Koul 1931f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_sink_path(w, p) { 1932cb1f904dSGuneshwor Singh if (p->connect && is_skl_dsp_widget_type(p->sink, dai->dev) && 1933cfb0a873SVinod Koul p->sink->priv) { 1934cfb0a873SVinod Koul 19359a03cb49SJeeja KP ret = skl_tplg_be_fill_pipe_params(dai, 19369a03cb49SJeeja KP p->sink->priv, params); 19374d8adccbSSubhransu S. Prusty if (ret < 0) 19384d8adccbSSubhransu S. Prusty return ret; 19394d8adccbSSubhransu S. Prusty } else { 19404d8adccbSSubhransu S. Prusty ret = skl_tplg_be_set_sink_pipe_params( 1941cfb0a873SVinod Koul dai, p->sink, params); 19424d8adccbSSubhransu S. Prusty if (ret < 0) 19434d8adccbSSubhransu S. Prusty return ret; 1944cfb0a873SVinod Koul } 1945cfb0a873SVinod Koul } 1946cfb0a873SVinod Koul 19474d8adccbSSubhransu S. Prusty return ret; 1948cfb0a873SVinod Koul } 1949cfb0a873SVinod Koul 1950cfb0a873SVinod Koul /* 1951cfb0a873SVinod Koul * BE hw_params can be a source parameters (capture) or sink parameters 1952cfb0a873SVinod Koul * (playback). Based on sink and source we need to either find the source 1953cfb0a873SVinod Koul * list or the sink list and set the pipeline parameters 1954cfb0a873SVinod Koul */ 1955cfb0a873SVinod Koul int skl_tplg_be_update_params(struct snd_soc_dai *dai, 1956cfb0a873SVinod Koul struct skl_pipe_params *params) 1957cfb0a873SVinod Koul { 1958cfb0a873SVinod Koul struct snd_soc_dapm_widget *w; 1959cfb0a873SVinod Koul 1960cfb0a873SVinod Koul if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { 1961cfb0a873SVinod Koul w = dai->playback_widget; 1962cfb0a873SVinod Koul 1963cfb0a873SVinod Koul return skl_tplg_be_set_src_pipe_params(dai, w, params); 1964cfb0a873SVinod Koul 1965cfb0a873SVinod Koul } else { 1966cfb0a873SVinod Koul w = dai->capture_widget; 1967cfb0a873SVinod Koul 1968cfb0a873SVinod Koul return skl_tplg_be_set_sink_pipe_params(dai, w, params); 1969cfb0a873SVinod Koul } 1970cfb0a873SVinod Koul 1971cfb0a873SVinod Koul return 0; 1972cfb0a873SVinod Koul } 19733af36706SVinod Koul 19743af36706SVinod Koul static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = { 19753af36706SVinod Koul {SKL_MIXER_EVENT, skl_tplg_mixer_event}, 19769a1e3507SVinod Koul {SKL_VMIXER_EVENT, skl_tplg_mixer_event}, 19773af36706SVinod Koul {SKL_PGA_EVENT, skl_tplg_pga_event}, 19783af36706SVinod Koul }; 19793af36706SVinod Koul 1980140adfbaSJeeja KP static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = { 1981140adfbaSJeeja KP {SKL_CONTROL_TYPE_BYTE_TLV, skl_tplg_tlv_control_get, 1982140adfbaSJeeja KP skl_tplg_tlv_control_set}, 1983140adfbaSJeeja KP }; 1984140adfbaSJeeja KP 19857a1b749bSDharageswari R static const struct snd_soc_tplg_kcontrol_ops skl_tplg_kcontrol_ops[] = { 19867a1b749bSDharageswari R { 19877a1b749bSDharageswari R .id = SKL_CONTROL_TYPE_MIC_SELECT, 19887a1b749bSDharageswari R .get = skl_tplg_mic_control_get, 19897a1b749bSDharageswari R .put = skl_tplg_mic_control_set, 19907a1b749bSDharageswari R }, 19917a1b749bSDharageswari R }; 19927a1b749bSDharageswari R 1993f6fa56e2SRamesh Babu static int skl_tplg_fill_pipe_cfg(struct device *dev, 1994f6fa56e2SRamesh Babu struct skl_pipe *pipe, u32 tkn, 1995f6fa56e2SRamesh Babu u32 tkn_val, int conf_idx, int dir) 1996f6fa56e2SRamesh Babu { 1997f6fa56e2SRamesh Babu struct skl_pipe_fmt *fmt; 1998f6fa56e2SRamesh Babu struct skl_path_config *config; 1999f6fa56e2SRamesh Babu 2000f6fa56e2SRamesh Babu switch (dir) { 2001f6fa56e2SRamesh Babu case SKL_DIR_IN: 2002f6fa56e2SRamesh Babu fmt = &pipe->configs[conf_idx].in_fmt; 2003f6fa56e2SRamesh Babu break; 2004f6fa56e2SRamesh Babu 2005f6fa56e2SRamesh Babu case SKL_DIR_OUT: 2006f6fa56e2SRamesh Babu fmt = &pipe->configs[conf_idx].out_fmt; 2007f6fa56e2SRamesh Babu break; 2008f6fa56e2SRamesh Babu 2009f6fa56e2SRamesh Babu default: 2010f6fa56e2SRamesh Babu dev_err(dev, "Invalid direction: %d\n", dir); 2011f6fa56e2SRamesh Babu return -EINVAL; 2012f6fa56e2SRamesh Babu } 2013f6fa56e2SRamesh Babu 2014f6fa56e2SRamesh Babu config = &pipe->configs[conf_idx]; 2015f6fa56e2SRamesh Babu 2016f6fa56e2SRamesh Babu switch (tkn) { 2017f6fa56e2SRamesh Babu case SKL_TKN_U32_CFG_FREQ: 2018f6fa56e2SRamesh Babu fmt->freq = tkn_val; 2019f6fa56e2SRamesh Babu break; 2020f6fa56e2SRamesh Babu 2021f6fa56e2SRamesh Babu case SKL_TKN_U8_CFG_CHAN: 2022f6fa56e2SRamesh Babu fmt->channels = tkn_val; 2023f6fa56e2SRamesh Babu break; 2024f6fa56e2SRamesh Babu 2025f6fa56e2SRamesh Babu case SKL_TKN_U8_CFG_BPS: 2026f6fa56e2SRamesh Babu fmt->bps = tkn_val; 2027f6fa56e2SRamesh Babu break; 2028f6fa56e2SRamesh Babu 2029f6fa56e2SRamesh Babu case SKL_TKN_U32_PATH_MEM_PGS: 2030f6fa56e2SRamesh Babu config->mem_pages = tkn_val; 2031f6fa56e2SRamesh Babu break; 2032f6fa56e2SRamesh Babu 2033f6fa56e2SRamesh Babu default: 2034f6fa56e2SRamesh Babu dev_err(dev, "Invalid token config: %d\n", tkn); 2035f6fa56e2SRamesh Babu return -EINVAL; 2036f6fa56e2SRamesh Babu } 2037f6fa56e2SRamesh Babu 2038f6fa56e2SRamesh Babu return 0; 2039f6fa56e2SRamesh Babu } 2040f6fa56e2SRamesh Babu 20416277e832SShreyas NC static int skl_tplg_fill_pipe_tkn(struct device *dev, 20426277e832SShreyas NC struct skl_pipe *pipe, u32 tkn, 20436277e832SShreyas NC u32 tkn_val) 20443af36706SVinod Koul { 20453af36706SVinod Koul 20466277e832SShreyas NC switch (tkn) { 20476277e832SShreyas NC case SKL_TKN_U32_PIPE_CONN_TYPE: 20486277e832SShreyas NC pipe->conn_type = tkn_val; 20496277e832SShreyas NC break; 20506277e832SShreyas NC 20516277e832SShreyas NC case SKL_TKN_U32_PIPE_PRIORITY: 20526277e832SShreyas NC pipe->pipe_priority = tkn_val; 20536277e832SShreyas NC break; 20546277e832SShreyas NC 20556277e832SShreyas NC case SKL_TKN_U32_PIPE_MEM_PGS: 20566277e832SShreyas NC pipe->memory_pages = tkn_val; 20576277e832SShreyas NC break; 20586277e832SShreyas NC 20598a0cb236SVinod Koul case SKL_TKN_U32_PMODE: 20608a0cb236SVinod Koul pipe->lp_mode = tkn_val; 20618a0cb236SVinod Koul break; 20628a0cb236SVinod Koul 2063f6fa56e2SRamesh Babu case SKL_TKN_U32_PIPE_DIRECTION: 2064f6fa56e2SRamesh Babu pipe->direction = tkn_val; 2065f6fa56e2SRamesh Babu break; 2066f6fa56e2SRamesh Babu 2067f6fa56e2SRamesh Babu case SKL_TKN_U32_NUM_CONFIGS: 2068f6fa56e2SRamesh Babu pipe->nr_cfgs = tkn_val; 2069f6fa56e2SRamesh Babu break; 2070f6fa56e2SRamesh Babu 20716277e832SShreyas NC default: 20726277e832SShreyas NC dev_err(dev, "Token not handled %d\n", tkn); 20736277e832SShreyas NC return -EINVAL; 20743af36706SVinod Koul } 20756277e832SShreyas NC 20766277e832SShreyas NC return 0; 20773af36706SVinod Koul } 20783af36706SVinod Koul 20793af36706SVinod Koul /* 20806277e832SShreyas NC * Add pipeline by parsing the relevant tokens 20816277e832SShreyas NC * Return an existing pipe if the pipe already exists. 20823af36706SVinod Koul */ 20836277e832SShreyas NC static int skl_tplg_add_pipe(struct device *dev, 20846277e832SShreyas NC struct skl_module_cfg *mconfig, struct skl *skl, 20856277e832SShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem) 20863af36706SVinod Koul { 20873af36706SVinod Koul struct skl_pipeline *ppl; 20883af36706SVinod Koul struct skl_pipe *pipe; 20893af36706SVinod Koul struct skl_pipe_params *params; 20903af36706SVinod Koul 20913af36706SVinod Koul list_for_each_entry(ppl, &skl->ppl_list, node) { 20926277e832SShreyas NC if (ppl->pipe->ppl_id == tkn_elem->value) { 20936277e832SShreyas NC mconfig->pipe = ppl->pipe; 2094081dc8abSGuneshwor Singh return -EEXIST; 20956277e832SShreyas NC } 20963af36706SVinod Koul } 20973af36706SVinod Koul 20983af36706SVinod Koul ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL); 20993af36706SVinod Koul if (!ppl) 21006277e832SShreyas NC return -ENOMEM; 21013af36706SVinod Koul 21023af36706SVinod Koul pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL); 21033af36706SVinod Koul if (!pipe) 21046277e832SShreyas NC return -ENOMEM; 21053af36706SVinod Koul 21063af36706SVinod Koul params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL); 21073af36706SVinod Koul if (!params) 21086277e832SShreyas NC return -ENOMEM; 21093af36706SVinod Koul 21103af36706SVinod Koul pipe->p_params = params; 21116277e832SShreyas NC pipe->ppl_id = tkn_elem->value; 21123af36706SVinod Koul INIT_LIST_HEAD(&pipe->w_list); 21133af36706SVinod Koul 21143af36706SVinod Koul ppl->pipe = pipe; 21153af36706SVinod Koul list_add(&ppl->node, &skl->ppl_list); 21163af36706SVinod Koul 21176277e832SShreyas NC mconfig->pipe = pipe; 21186277e832SShreyas NC mconfig->pipe->state = SKL_PIPE_INVALID; 21196277e832SShreyas NC 21206277e832SShreyas NC return 0; 21213af36706SVinod Koul } 21223af36706SVinod Koul 212322ebd666SSriram Periyasamy static int skl_tplg_get_uuid(struct device *dev, u8 *guid, 212422ebd666SSriram Periyasamy struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn) 21256277e832SShreyas NC { 212622ebd666SSriram Periyasamy if (uuid_tkn->token == SKL_TKN_UUID) { 212722ebd666SSriram Periyasamy memcpy(guid, &uuid_tkn->uuid, 16); 212822ebd666SSriram Periyasamy return 0; 212922ebd666SSriram Periyasamy } 213022ebd666SSriram Periyasamy 213122ebd666SSriram Periyasamy dev_err(dev, "Not an UUID token %d\n", uuid_tkn->token); 213222ebd666SSriram Periyasamy 213322ebd666SSriram Periyasamy return -EINVAL; 213422ebd666SSriram Periyasamy } 213522ebd666SSriram Periyasamy 213622ebd666SSriram Periyasamy static int skl_tplg_fill_pin(struct device *dev, 213722ebd666SSriram Periyasamy struct snd_soc_tplg_vendor_value_elem *tkn_elem, 213822ebd666SSriram Periyasamy struct skl_module_pin *m_pin, 213922ebd666SSriram Periyasamy int pin_index) 214022ebd666SSriram Periyasamy { 2141d9561474SSriram Periyasamy int ret; 2142d9561474SSriram Periyasamy 214322ebd666SSriram Periyasamy switch (tkn_elem->token) { 21446277e832SShreyas NC case SKL_TKN_U32_PIN_MOD_ID: 214522ebd666SSriram Periyasamy m_pin[pin_index].id.module_id = tkn_elem->value; 21466277e832SShreyas NC break; 21476277e832SShreyas NC 21486277e832SShreyas NC case SKL_TKN_U32_PIN_INST_ID: 214922ebd666SSriram Periyasamy m_pin[pin_index].id.instance_id = tkn_elem->value; 21506277e832SShreyas NC break; 21516277e832SShreyas NC 2152d9561474SSriram Periyasamy case SKL_TKN_UUID: 2153d9561474SSriram Periyasamy ret = skl_tplg_get_uuid(dev, m_pin[pin_index].id.mod_uuid.b, 2154d9561474SSriram Periyasamy (struct snd_soc_tplg_vendor_uuid_elem *)tkn_elem); 2155d9561474SSriram Periyasamy if (ret < 0) 2156d9561474SSriram Periyasamy return ret; 2157d9561474SSriram Periyasamy 21586277e832SShreyas NC break; 21596277e832SShreyas NC 21606277e832SShreyas NC default: 216122ebd666SSriram Periyasamy dev_err(dev, "%d Not a pin token\n", tkn_elem->token); 21626277e832SShreyas NC return -EINVAL; 21636277e832SShreyas NC } 21646277e832SShreyas NC 21656277e832SShreyas NC return 0; 21666277e832SShreyas NC } 21676277e832SShreyas NC 21686277e832SShreyas NC /* 21696277e832SShreyas NC * Parse for pin config specific tokens to fill up the 21706277e832SShreyas NC * module private data 21716277e832SShreyas NC */ 21726277e832SShreyas NC static int skl_tplg_fill_pins_info(struct device *dev, 21736277e832SShreyas NC struct skl_module_cfg *mconfig, 21746277e832SShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem, 21756277e832SShreyas NC int dir, int pin_count) 21766277e832SShreyas NC { 21776277e832SShreyas NC int ret; 21786277e832SShreyas NC struct skl_module_pin *m_pin; 21796277e832SShreyas NC 21806277e832SShreyas NC switch (dir) { 21816277e832SShreyas NC case SKL_DIR_IN: 21826277e832SShreyas NC m_pin = mconfig->m_in_pin; 21836277e832SShreyas NC break; 21846277e832SShreyas NC 21856277e832SShreyas NC case SKL_DIR_OUT: 21866277e832SShreyas NC m_pin = mconfig->m_out_pin; 21876277e832SShreyas NC break; 21886277e832SShreyas NC 21896277e832SShreyas NC default: 2190ecd286a9SColin Ian King dev_err(dev, "Invalid direction value\n"); 21916277e832SShreyas NC return -EINVAL; 21926277e832SShreyas NC } 21936277e832SShreyas NC 219422ebd666SSriram Periyasamy ret = skl_tplg_fill_pin(dev, tkn_elem, m_pin, pin_count); 21956277e832SShreyas NC if (ret < 0) 21966277e832SShreyas NC return ret; 21976277e832SShreyas NC 21986277e832SShreyas NC m_pin[pin_count].in_use = false; 21996277e832SShreyas NC m_pin[pin_count].pin_state = SKL_PIN_UNBIND; 22006277e832SShreyas NC 22016277e832SShreyas NC return 0; 22026277e832SShreyas NC } 22036277e832SShreyas NC 22046277e832SShreyas NC /* 22056277e832SShreyas NC * Fill up input/output module config format based 22066277e832SShreyas NC * on the direction 22076277e832SShreyas NC */ 22086277e832SShreyas NC static int skl_tplg_fill_fmt(struct device *dev, 2209ca312fdaSShreyas NC struct skl_module_fmt *dst_fmt, 2210ca312fdaSShreyas NC u32 tkn, u32 value) 22116277e832SShreyas NC { 22126277e832SShreyas NC switch (tkn) { 22136277e832SShreyas NC case SKL_TKN_U32_FMT_CH: 22146277e832SShreyas NC dst_fmt->channels = value; 22156277e832SShreyas NC break; 22166277e832SShreyas NC 22176277e832SShreyas NC case SKL_TKN_U32_FMT_FREQ: 22186277e832SShreyas NC dst_fmt->s_freq = value; 22196277e832SShreyas NC break; 22206277e832SShreyas NC 22216277e832SShreyas NC case SKL_TKN_U32_FMT_BIT_DEPTH: 22226277e832SShreyas NC dst_fmt->bit_depth = value; 22236277e832SShreyas NC break; 22246277e832SShreyas NC 22256277e832SShreyas NC case SKL_TKN_U32_FMT_SAMPLE_SIZE: 22266277e832SShreyas NC dst_fmt->valid_bit_depth = value; 22276277e832SShreyas NC break; 22286277e832SShreyas NC 22296277e832SShreyas NC case SKL_TKN_U32_FMT_CH_CONFIG: 22306277e832SShreyas NC dst_fmt->ch_cfg = value; 22316277e832SShreyas NC break; 22326277e832SShreyas NC 22336277e832SShreyas NC case SKL_TKN_U32_FMT_INTERLEAVE: 22346277e832SShreyas NC dst_fmt->interleaving_style = value; 22356277e832SShreyas NC break; 22366277e832SShreyas NC 22376277e832SShreyas NC case SKL_TKN_U32_FMT_SAMPLE_TYPE: 22386277e832SShreyas NC dst_fmt->sample_type = value; 22396277e832SShreyas NC break; 22406277e832SShreyas NC 22416277e832SShreyas NC case SKL_TKN_U32_FMT_CH_MAP: 22426277e832SShreyas NC dst_fmt->ch_map = value; 22436277e832SShreyas NC break; 22446277e832SShreyas NC 22456277e832SShreyas NC default: 2246ecd286a9SColin Ian King dev_err(dev, "Invalid token %d\n", tkn); 22476277e832SShreyas NC return -EINVAL; 22486277e832SShreyas NC } 22496277e832SShreyas NC 22506277e832SShreyas NC return 0; 22516277e832SShreyas NC } 22526277e832SShreyas NC 2253ca312fdaSShreyas NC static int skl_tplg_widget_fill_fmt(struct device *dev, 2254f6fa56e2SRamesh Babu struct skl_module_iface *fmt, 2255ca312fdaSShreyas NC u32 tkn, u32 val, u32 dir, int fmt_idx) 2256ca312fdaSShreyas NC { 2257ca312fdaSShreyas NC struct skl_module_fmt *dst_fmt; 2258ca312fdaSShreyas NC 2259f6fa56e2SRamesh Babu if (!fmt) 2260f6fa56e2SRamesh Babu return -EINVAL; 2261f6fa56e2SRamesh Babu 2262ca312fdaSShreyas NC switch (dir) { 2263ca312fdaSShreyas NC case SKL_DIR_IN: 2264f6fa56e2SRamesh Babu dst_fmt = &fmt->inputs[fmt_idx].fmt; 2265ca312fdaSShreyas NC break; 2266ca312fdaSShreyas NC 2267ca312fdaSShreyas NC case SKL_DIR_OUT: 2268f6fa56e2SRamesh Babu dst_fmt = &fmt->outputs[fmt_idx].fmt; 2269ca312fdaSShreyas NC break; 2270ca312fdaSShreyas NC 2271ca312fdaSShreyas NC default: 2272ca312fdaSShreyas NC dev_err(dev, "Invalid direction: %d\n", dir); 2273ca312fdaSShreyas NC return -EINVAL; 2274ca312fdaSShreyas NC } 2275ca312fdaSShreyas NC 2276ca312fdaSShreyas NC return skl_tplg_fill_fmt(dev, dst_fmt, tkn, val); 2277ca312fdaSShreyas NC } 2278ca312fdaSShreyas NC 22796277e832SShreyas NC static void skl_tplg_fill_pin_dynamic_val( 22806277e832SShreyas NC struct skl_module_pin *mpin, u32 pin_count, u32 value) 22814cd9899fSHardik T Shah { 22824cd9899fSHardik T Shah int i; 22834cd9899fSHardik T Shah 22846277e832SShreyas NC for (i = 0; i < pin_count; i++) 22856277e832SShreyas NC mpin[i].is_dynamic = value; 22864cd9899fSHardik T Shah } 22876277e832SShreyas NC 22886277e832SShreyas NC /* 2289db6ed55dSShreyas NC * Resource table in the manifest has pin specific resources 2290db6ed55dSShreyas NC * like pin and pin buffer size 2291db6ed55dSShreyas NC */ 2292db6ed55dSShreyas NC static int skl_tplg_manifest_pin_res_tkn(struct device *dev, 2293db6ed55dSShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem, 2294db6ed55dSShreyas NC struct skl_module_res *res, int pin_idx, int dir) 2295db6ed55dSShreyas NC { 2296db6ed55dSShreyas NC struct skl_module_pin_resources *m_pin; 2297db6ed55dSShreyas NC 2298db6ed55dSShreyas NC switch (dir) { 2299db6ed55dSShreyas NC case SKL_DIR_IN: 2300db6ed55dSShreyas NC m_pin = &res->input[pin_idx]; 2301db6ed55dSShreyas NC break; 2302db6ed55dSShreyas NC 2303db6ed55dSShreyas NC case SKL_DIR_OUT: 2304db6ed55dSShreyas NC m_pin = &res->output[pin_idx]; 2305db6ed55dSShreyas NC break; 2306db6ed55dSShreyas NC 2307db6ed55dSShreyas NC default: 2308db6ed55dSShreyas NC dev_err(dev, "Invalid pin direction: %d\n", dir); 2309db6ed55dSShreyas NC return -EINVAL; 2310db6ed55dSShreyas NC } 2311db6ed55dSShreyas NC 2312db6ed55dSShreyas NC switch (tkn_elem->token) { 2313db6ed55dSShreyas NC case SKL_TKN_MM_U32_RES_PIN_ID: 2314db6ed55dSShreyas NC m_pin->pin_index = tkn_elem->value; 2315db6ed55dSShreyas NC break; 2316db6ed55dSShreyas NC 2317db6ed55dSShreyas NC case SKL_TKN_MM_U32_PIN_BUF: 2318db6ed55dSShreyas NC m_pin->buf_size = tkn_elem->value; 2319db6ed55dSShreyas NC break; 2320db6ed55dSShreyas NC 2321db6ed55dSShreyas NC default: 2322db6ed55dSShreyas NC dev_err(dev, "Invalid token: %d\n", tkn_elem->token); 2323db6ed55dSShreyas NC return -EINVAL; 2324db6ed55dSShreyas NC } 2325db6ed55dSShreyas NC 2326db6ed55dSShreyas NC return 0; 2327db6ed55dSShreyas NC } 2328db6ed55dSShreyas NC 2329db6ed55dSShreyas NC /* 2330db6ed55dSShreyas NC * Fill module specific resources from the manifest's resource 2331db6ed55dSShreyas NC * table like CPS, DMA size, mem_pages. 2332db6ed55dSShreyas NC */ 2333db6ed55dSShreyas NC static int skl_tplg_fill_res_tkn(struct device *dev, 2334db6ed55dSShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem, 2335db6ed55dSShreyas NC struct skl_module_res *res, 2336db6ed55dSShreyas NC int pin_idx, int dir) 2337db6ed55dSShreyas NC { 2338db6ed55dSShreyas NC int ret, tkn_count = 0; 2339db6ed55dSShreyas NC 2340db6ed55dSShreyas NC if (!res) 2341db6ed55dSShreyas NC return -EINVAL; 2342db6ed55dSShreyas NC 2343db6ed55dSShreyas NC switch (tkn_elem->token) { 2344db6ed55dSShreyas NC case SKL_TKN_MM_U32_CPS: 2345db6ed55dSShreyas NC res->cps = tkn_elem->value; 2346db6ed55dSShreyas NC break; 2347db6ed55dSShreyas NC 2348db6ed55dSShreyas NC case SKL_TKN_MM_U32_DMA_SIZE: 2349db6ed55dSShreyas NC res->dma_buffer_size = tkn_elem->value; 2350db6ed55dSShreyas NC break; 2351db6ed55dSShreyas NC 2352db6ed55dSShreyas NC case SKL_TKN_MM_U32_CPC: 2353db6ed55dSShreyas NC res->cpc = tkn_elem->value; 2354db6ed55dSShreyas NC break; 2355db6ed55dSShreyas NC 2356db6ed55dSShreyas NC case SKL_TKN_U32_MEM_PAGES: 2357db6ed55dSShreyas NC res->is_pages = tkn_elem->value; 2358db6ed55dSShreyas NC break; 2359db6ed55dSShreyas NC 2360db6ed55dSShreyas NC case SKL_TKN_U32_OBS: 2361db6ed55dSShreyas NC res->obs = tkn_elem->value; 2362db6ed55dSShreyas NC break; 2363db6ed55dSShreyas NC 2364db6ed55dSShreyas NC case SKL_TKN_U32_IBS: 2365db6ed55dSShreyas NC res->ibs = tkn_elem->value; 2366db6ed55dSShreyas NC break; 2367db6ed55dSShreyas NC 2368f6fa56e2SRamesh Babu case SKL_TKN_U32_MAX_MCPS: 2369f6fa56e2SRamesh Babu res->cps = tkn_elem->value; 2370f6fa56e2SRamesh Babu break; 2371f6fa56e2SRamesh Babu 2372db6ed55dSShreyas NC case SKL_TKN_MM_U32_RES_PIN_ID: 2373db6ed55dSShreyas NC case SKL_TKN_MM_U32_PIN_BUF: 2374db6ed55dSShreyas NC ret = skl_tplg_manifest_pin_res_tkn(dev, tkn_elem, res, 2375db6ed55dSShreyas NC pin_idx, dir); 2376db6ed55dSShreyas NC if (ret < 0) 2377db6ed55dSShreyas NC return ret; 2378db6ed55dSShreyas NC break; 2379db6ed55dSShreyas NC 2380db6ed55dSShreyas NC default: 2381db6ed55dSShreyas NC dev_err(dev, "Not a res type token: %d", tkn_elem->token); 2382db6ed55dSShreyas NC return -EINVAL; 2383db6ed55dSShreyas NC 2384db6ed55dSShreyas NC } 2385db6ed55dSShreyas NC tkn_count++; 2386db6ed55dSShreyas NC 2387db6ed55dSShreyas NC return tkn_count; 2388db6ed55dSShreyas NC } 2389db6ed55dSShreyas NC 2390db6ed55dSShreyas NC /* 23916277e832SShreyas NC * Parse tokens to fill up the module private data 23926277e832SShreyas NC */ 23936277e832SShreyas NC static int skl_tplg_get_token(struct device *dev, 23946277e832SShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem, 23956277e832SShreyas NC struct skl *skl, struct skl_module_cfg *mconfig) 23966277e832SShreyas NC { 23976277e832SShreyas NC int tkn_count = 0; 23986277e832SShreyas NC int ret; 23996277e832SShreyas NC static int is_pipe_exists; 2400f6fa56e2SRamesh Babu static int pin_index, dir, conf_idx; 2401f6fa56e2SRamesh Babu struct skl_module_iface *iface = NULL; 2402f6fa56e2SRamesh Babu struct skl_module_res *res = NULL; 2403f6fa56e2SRamesh Babu int res_idx = mconfig->res_idx; 2404f6fa56e2SRamesh Babu int fmt_idx = mconfig->fmt_idx; 2405f6fa56e2SRamesh Babu 2406f6fa56e2SRamesh Babu /* 2407f6fa56e2SRamesh Babu * If the manifest structure contains no modules, fill all 2408f6fa56e2SRamesh Babu * the module data to 0th index. 2409f6fa56e2SRamesh Babu * res_idx and fmt_idx are default set to 0. 2410f6fa56e2SRamesh Babu */ 2411f6fa56e2SRamesh Babu if (skl->nr_modules == 0) { 2412f6fa56e2SRamesh Babu res = &mconfig->module->resources[res_idx]; 2413f6fa56e2SRamesh Babu iface = &mconfig->module->formats[fmt_idx]; 2414f6fa56e2SRamesh Babu } 24156277e832SShreyas NC 24166277e832SShreyas NC if (tkn_elem->token > SKL_TKN_MAX) 24176277e832SShreyas NC return -EINVAL; 24186277e832SShreyas NC 24196277e832SShreyas NC switch (tkn_elem->token) { 24206277e832SShreyas NC case SKL_TKN_U8_IN_QUEUE_COUNT: 2421f6fa56e2SRamesh Babu mconfig->module->max_input_pins = tkn_elem->value; 24226277e832SShreyas NC break; 24236277e832SShreyas NC 24246277e832SShreyas NC case SKL_TKN_U8_OUT_QUEUE_COUNT: 2425f6fa56e2SRamesh Babu mconfig->module->max_output_pins = tkn_elem->value; 24266277e832SShreyas NC break; 24276277e832SShreyas NC 24286277e832SShreyas NC case SKL_TKN_U8_DYN_IN_PIN: 24296277e832SShreyas NC if (!mconfig->m_in_pin) 2430f6fa56e2SRamesh Babu mconfig->m_in_pin = devm_kzalloc(dev, MAX_IN_QUEUE * 2431f6fa56e2SRamesh Babu sizeof(*mconfig->m_in_pin), GFP_KERNEL); 2432f6fa56e2SRamesh Babu if (!mconfig->m_in_pin) 24336277e832SShreyas NC return -ENOMEM; 24346277e832SShreyas NC 2435f6fa56e2SRamesh Babu skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin, MAX_IN_QUEUE, 2436f6fa56e2SRamesh Babu tkn_elem->value); 24376277e832SShreyas NC break; 24386277e832SShreyas NC 24396277e832SShreyas NC case SKL_TKN_U8_DYN_OUT_PIN: 24406277e832SShreyas NC if (!mconfig->m_out_pin) 2441f6fa56e2SRamesh Babu mconfig->m_out_pin = devm_kzalloc(dev, MAX_IN_QUEUE * 2442f6fa56e2SRamesh Babu sizeof(*mconfig->m_in_pin), GFP_KERNEL); 2443f6fa56e2SRamesh Babu if (!mconfig->m_out_pin) 24446277e832SShreyas NC return -ENOMEM; 24456277e832SShreyas NC 2446f6fa56e2SRamesh Babu skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin, MAX_OUT_QUEUE, 2447f6fa56e2SRamesh Babu tkn_elem->value); 24486277e832SShreyas NC break; 24496277e832SShreyas NC 24506277e832SShreyas NC case SKL_TKN_U8_TIME_SLOT: 24516277e832SShreyas NC mconfig->time_slot = tkn_elem->value; 24526277e832SShreyas NC break; 24536277e832SShreyas NC 24546277e832SShreyas NC case SKL_TKN_U8_CORE_ID: 24556277e832SShreyas NC mconfig->core_id = tkn_elem->value; 24566277e832SShreyas NC 24576277e832SShreyas NC case SKL_TKN_U8_MOD_TYPE: 24586277e832SShreyas NC mconfig->m_type = tkn_elem->value; 24596277e832SShreyas NC break; 24606277e832SShreyas NC 24616277e832SShreyas NC case SKL_TKN_U8_DEV_TYPE: 24626277e832SShreyas NC mconfig->dev_type = tkn_elem->value; 24636277e832SShreyas NC break; 24646277e832SShreyas NC 24656277e832SShreyas NC case SKL_TKN_U8_HW_CONN_TYPE: 24666277e832SShreyas NC mconfig->hw_conn_type = tkn_elem->value; 24676277e832SShreyas NC break; 24686277e832SShreyas NC 24696277e832SShreyas NC case SKL_TKN_U16_MOD_INST_ID: 24706277e832SShreyas NC mconfig->id.instance_id = 24716277e832SShreyas NC tkn_elem->value; 24726277e832SShreyas NC break; 24736277e832SShreyas NC 24746277e832SShreyas NC case SKL_TKN_U32_MEM_PAGES: 24756277e832SShreyas NC case SKL_TKN_U32_MAX_MCPS: 24766277e832SShreyas NC case SKL_TKN_U32_OBS: 24776277e832SShreyas NC case SKL_TKN_U32_IBS: 24782b79b15cSColin Ian King ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_index, dir); 2479f6fa56e2SRamesh Babu if (ret < 0) 2480f6fa56e2SRamesh Babu return ret; 2481f6fa56e2SRamesh Babu 24826277e832SShreyas NC break; 24836277e832SShreyas NC 24846277e832SShreyas NC case SKL_TKN_U32_VBUS_ID: 24856277e832SShreyas NC mconfig->vbus_id = tkn_elem->value; 24866277e832SShreyas NC break; 24876277e832SShreyas NC 24886277e832SShreyas NC case SKL_TKN_U32_PARAMS_FIXUP: 24896277e832SShreyas NC mconfig->params_fixup = tkn_elem->value; 24906277e832SShreyas NC break; 24916277e832SShreyas NC 24926277e832SShreyas NC case SKL_TKN_U32_CONVERTER: 24936277e832SShreyas NC mconfig->converter = tkn_elem->value; 24946277e832SShreyas NC break; 24956277e832SShreyas NC 2496c0116be3SSubhransu S. Prusty case SKL_TKN_U32_D0I3_CAPS: 24976bd9dcf3SVinod Koul mconfig->d0i3_caps = tkn_elem->value; 24986bd9dcf3SVinod Koul break; 24996bd9dcf3SVinod Koul 25006277e832SShreyas NC case SKL_TKN_U32_PIPE_ID: 25016277e832SShreyas NC ret = skl_tplg_add_pipe(dev, 25026277e832SShreyas NC mconfig, skl, tkn_elem); 25036277e832SShreyas NC 2504081dc8abSGuneshwor Singh if (ret < 0) { 2505081dc8abSGuneshwor Singh if (ret == -EEXIST) { 25066277e832SShreyas NC is_pipe_exists = 1; 2507081dc8abSGuneshwor Singh break; 2508081dc8abSGuneshwor Singh } 2509081dc8abSGuneshwor Singh return is_pipe_exists; 2510081dc8abSGuneshwor Singh } 25116277e832SShreyas NC 25126277e832SShreyas NC break; 25136277e832SShreyas NC 2514f6fa56e2SRamesh Babu case SKL_TKN_U32_PIPE_CONFIG_ID: 2515f6fa56e2SRamesh Babu conf_idx = tkn_elem->value; 2516f6fa56e2SRamesh Babu break; 2517f6fa56e2SRamesh Babu 25186277e832SShreyas NC case SKL_TKN_U32_PIPE_CONN_TYPE: 25196277e832SShreyas NC case SKL_TKN_U32_PIPE_PRIORITY: 25206277e832SShreyas NC case SKL_TKN_U32_PIPE_MEM_PGS: 25218a0cb236SVinod Koul case SKL_TKN_U32_PMODE: 2522f6fa56e2SRamesh Babu case SKL_TKN_U32_PIPE_DIRECTION: 2523f6fa56e2SRamesh Babu case SKL_TKN_U32_NUM_CONFIGS: 25246277e832SShreyas NC if (is_pipe_exists) { 25256277e832SShreyas NC ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe, 25266277e832SShreyas NC tkn_elem->token, tkn_elem->value); 25276277e832SShreyas NC if (ret < 0) 25286277e832SShreyas NC return ret; 25296277e832SShreyas NC } 25306277e832SShreyas NC 25316277e832SShreyas NC break; 25326277e832SShreyas NC 2533f6fa56e2SRamesh Babu case SKL_TKN_U32_PATH_MEM_PGS: 2534f6fa56e2SRamesh Babu case SKL_TKN_U32_CFG_FREQ: 2535f6fa56e2SRamesh Babu case SKL_TKN_U8_CFG_CHAN: 2536f6fa56e2SRamesh Babu case SKL_TKN_U8_CFG_BPS: 2537f6fa56e2SRamesh Babu if (mconfig->pipe->nr_cfgs) { 2538f6fa56e2SRamesh Babu ret = skl_tplg_fill_pipe_cfg(dev, mconfig->pipe, 2539f6fa56e2SRamesh Babu tkn_elem->token, tkn_elem->value, 2540f6fa56e2SRamesh Babu conf_idx, dir); 2541f6fa56e2SRamesh Babu if (ret < 0) 2542f6fa56e2SRamesh Babu return ret; 2543f6fa56e2SRamesh Babu } 2544f6fa56e2SRamesh Babu break; 2545f6fa56e2SRamesh Babu 2546f6fa56e2SRamesh Babu case SKL_TKN_CFG_MOD_RES_ID: 2547f6fa56e2SRamesh Babu mconfig->mod_cfg[conf_idx].res_idx = tkn_elem->value; 2548f6fa56e2SRamesh Babu break; 2549f6fa56e2SRamesh Babu 2550f6fa56e2SRamesh Babu case SKL_TKN_CFG_MOD_FMT_ID: 2551f6fa56e2SRamesh Babu mconfig->mod_cfg[conf_idx].fmt_idx = tkn_elem->value; 2552f6fa56e2SRamesh Babu break; 2553f6fa56e2SRamesh Babu 25546277e832SShreyas NC /* 25556277e832SShreyas NC * SKL_TKN_U32_DIR_PIN_COUNT token has the value for both 25566277e832SShreyas NC * direction and the pin count. The first four bits represent 25576277e832SShreyas NC * direction and next four the pin count. 25586277e832SShreyas NC */ 25596277e832SShreyas NC case SKL_TKN_U32_DIR_PIN_COUNT: 25606277e832SShreyas NC dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK; 25616277e832SShreyas NC pin_index = (tkn_elem->value & 25626277e832SShreyas NC SKL_PIN_COUNT_MASK) >> 4; 25636277e832SShreyas NC 25646277e832SShreyas NC break; 25656277e832SShreyas NC 25666277e832SShreyas NC case SKL_TKN_U32_FMT_CH: 25676277e832SShreyas NC case SKL_TKN_U32_FMT_FREQ: 25686277e832SShreyas NC case SKL_TKN_U32_FMT_BIT_DEPTH: 25696277e832SShreyas NC case SKL_TKN_U32_FMT_SAMPLE_SIZE: 25706277e832SShreyas NC case SKL_TKN_U32_FMT_CH_CONFIG: 25716277e832SShreyas NC case SKL_TKN_U32_FMT_INTERLEAVE: 25726277e832SShreyas NC case SKL_TKN_U32_FMT_SAMPLE_TYPE: 25736277e832SShreyas NC case SKL_TKN_U32_FMT_CH_MAP: 2574f6fa56e2SRamesh Babu ret = skl_tplg_widget_fill_fmt(dev, iface, tkn_elem->token, 25756277e832SShreyas NC tkn_elem->value, dir, pin_index); 25766277e832SShreyas NC 25776277e832SShreyas NC if (ret < 0) 25786277e832SShreyas NC return ret; 25796277e832SShreyas NC 25806277e832SShreyas NC break; 25816277e832SShreyas NC 25826277e832SShreyas NC case SKL_TKN_U32_PIN_MOD_ID: 25836277e832SShreyas NC case SKL_TKN_U32_PIN_INST_ID: 2584d9561474SSriram Periyasamy case SKL_TKN_UUID: 25856277e832SShreyas NC ret = skl_tplg_fill_pins_info(dev, 25866277e832SShreyas NC mconfig, tkn_elem, dir, 25876277e832SShreyas NC pin_index); 25886277e832SShreyas NC if (ret < 0) 25896277e832SShreyas NC return ret; 25906277e832SShreyas NC 25916277e832SShreyas NC break; 25926277e832SShreyas NC 25936277e832SShreyas NC case SKL_TKN_U32_CAPS_SIZE: 25946277e832SShreyas NC mconfig->formats_config.caps_size = 25956277e832SShreyas NC tkn_elem->value; 25966277e832SShreyas NC 25976277e832SShreyas NC break; 25986277e832SShreyas NC 2599133e6e5cSShreyas NC case SKL_TKN_U32_CAPS_SET_PARAMS: 2600133e6e5cSShreyas NC mconfig->formats_config.set_params = 2601133e6e5cSShreyas NC tkn_elem->value; 2602133e6e5cSShreyas NC break; 2603133e6e5cSShreyas NC 2604133e6e5cSShreyas NC case SKL_TKN_U32_CAPS_PARAMS_ID: 2605133e6e5cSShreyas NC mconfig->formats_config.param_id = 2606133e6e5cSShreyas NC tkn_elem->value; 2607133e6e5cSShreyas NC break; 2608133e6e5cSShreyas NC 26096277e832SShreyas NC case SKL_TKN_U32_PROC_DOMAIN: 26106277e832SShreyas NC mconfig->domain = 26116277e832SShreyas NC tkn_elem->value; 26126277e832SShreyas NC 26136277e832SShreyas NC break; 26146277e832SShreyas NC 2615939df3adSRamesh Babu case SKL_TKN_U32_DMA_BUF_SIZE: 2616939df3adSRamesh Babu mconfig->dma_buffer_size = tkn_elem->value; 2617939df3adSRamesh Babu break; 2618939df3adSRamesh Babu 26196277e832SShreyas NC case SKL_TKN_U8_IN_PIN_TYPE: 26206277e832SShreyas NC case SKL_TKN_U8_OUT_PIN_TYPE: 26216277e832SShreyas NC case SKL_TKN_U8_CONN_TYPE: 26226277e832SShreyas NC break; 26236277e832SShreyas NC 26246277e832SShreyas NC default: 26256277e832SShreyas NC dev_err(dev, "Token %d not handled\n", 26266277e832SShreyas NC tkn_elem->token); 26276277e832SShreyas NC return -EINVAL; 26286277e832SShreyas NC } 26296277e832SShreyas NC 26306277e832SShreyas NC tkn_count++; 26316277e832SShreyas NC 26326277e832SShreyas NC return tkn_count; 26336277e832SShreyas NC } 26346277e832SShreyas NC 26356277e832SShreyas NC /* 26366277e832SShreyas NC * Parse the vendor array for specific tokens to construct 26376277e832SShreyas NC * module private data 26386277e832SShreyas NC */ 26396277e832SShreyas NC static int skl_tplg_get_tokens(struct device *dev, 26406277e832SShreyas NC char *pvt_data, struct skl *skl, 26416277e832SShreyas NC struct skl_module_cfg *mconfig, int block_size) 26426277e832SShreyas NC { 26436277e832SShreyas NC struct snd_soc_tplg_vendor_array *array; 26446277e832SShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem; 26456277e832SShreyas NC int tkn_count = 0, ret; 26466277e832SShreyas NC int off = 0, tuple_size = 0; 2647d9561474SSriram Periyasamy bool is_module_guid = true; 26486277e832SShreyas NC 26496277e832SShreyas NC if (block_size <= 0) 26506277e832SShreyas NC return -EINVAL; 26516277e832SShreyas NC 26526277e832SShreyas NC while (tuple_size < block_size) { 26536277e832SShreyas NC array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off); 26546277e832SShreyas NC 26556277e832SShreyas NC off += array->size; 26566277e832SShreyas NC 26576277e832SShreyas NC switch (array->type) { 26586277e832SShreyas NC case SND_SOC_TPLG_TUPLE_TYPE_STRING: 2659ecd286a9SColin Ian King dev_warn(dev, "no string tokens expected for skl tplg\n"); 26606277e832SShreyas NC continue; 26616277e832SShreyas NC 26626277e832SShreyas NC case SND_SOC_TPLG_TUPLE_TYPE_UUID: 2663d9561474SSriram Periyasamy if (is_module_guid) { 266422ebd666SSriram Periyasamy ret = skl_tplg_get_uuid(dev, mconfig->guid, 266522ebd666SSriram Periyasamy array->uuid); 2666d9561474SSriram Periyasamy is_module_guid = false; 2667d9561474SSriram Periyasamy } else { 2668d9561474SSriram Periyasamy ret = skl_tplg_get_token(dev, array->value, skl, 2669d9561474SSriram Periyasamy mconfig); 2670d9561474SSriram Periyasamy } 2671d9561474SSriram Periyasamy 26726277e832SShreyas NC if (ret < 0) 26736277e832SShreyas NC return ret; 26746277e832SShreyas NC 26756277e832SShreyas NC tuple_size += sizeof(*array->uuid); 26766277e832SShreyas NC 26776277e832SShreyas NC continue; 26786277e832SShreyas NC 26796277e832SShreyas NC default: 26806277e832SShreyas NC tkn_elem = array->value; 26816277e832SShreyas NC tkn_count = 0; 26826277e832SShreyas NC break; 26836277e832SShreyas NC } 26846277e832SShreyas NC 26856277e832SShreyas NC while (tkn_count <= (array->num_elems - 1)) { 26866277e832SShreyas NC ret = skl_tplg_get_token(dev, tkn_elem, 26876277e832SShreyas NC skl, mconfig); 26886277e832SShreyas NC 26896277e832SShreyas NC if (ret < 0) 26906277e832SShreyas NC return ret; 26916277e832SShreyas NC 26926277e832SShreyas NC tkn_count = tkn_count + ret; 26936277e832SShreyas NC tkn_elem++; 26946277e832SShreyas NC } 26956277e832SShreyas NC 26966277e832SShreyas NC tuple_size += tkn_count * sizeof(*tkn_elem); 26976277e832SShreyas NC } 26986277e832SShreyas NC 2699133e6e5cSShreyas NC return off; 27006277e832SShreyas NC } 27016277e832SShreyas NC 27026277e832SShreyas NC /* 27036277e832SShreyas NC * Every data block is preceded by a descriptor to read the number 27046277e832SShreyas NC * of data blocks, they type of the block and it's size 27056277e832SShreyas NC */ 27066277e832SShreyas NC static int skl_tplg_get_desc_blocks(struct device *dev, 27076277e832SShreyas NC struct snd_soc_tplg_vendor_array *array) 27086277e832SShreyas NC { 27096277e832SShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem; 27106277e832SShreyas NC 27116277e832SShreyas NC tkn_elem = array->value; 27126277e832SShreyas NC 27136277e832SShreyas NC switch (tkn_elem->token) { 27146277e832SShreyas NC case SKL_TKN_U8_NUM_BLOCKS: 27156277e832SShreyas NC case SKL_TKN_U8_BLOCK_TYPE: 27166277e832SShreyas NC case SKL_TKN_U16_BLOCK_SIZE: 27176277e832SShreyas NC return tkn_elem->value; 27186277e832SShreyas NC 27196277e832SShreyas NC default: 2720ecd286a9SColin Ian King dev_err(dev, "Invalid descriptor token %d\n", tkn_elem->token); 27216277e832SShreyas NC break; 27226277e832SShreyas NC } 27236277e832SShreyas NC 27246277e832SShreyas NC return -EINVAL; 27256277e832SShreyas NC } 27266277e832SShreyas NC 27276277e832SShreyas NC /* 27286277e832SShreyas NC * Parse the private data for the token and corresponding value. 27296277e832SShreyas NC * The private data can have multiple data blocks. So, a data block 27306277e832SShreyas NC * is preceded by a descriptor for number of blocks and a descriptor 27316277e832SShreyas NC * for the type and size of the suceeding data block. 27326277e832SShreyas NC */ 27336277e832SShreyas NC static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w, 27346277e832SShreyas NC struct skl *skl, struct device *dev, 27356277e832SShreyas NC struct skl_module_cfg *mconfig) 27366277e832SShreyas NC { 27376277e832SShreyas NC struct snd_soc_tplg_vendor_array *array; 27386277e832SShreyas NC int num_blocks, block_size = 0, block_type, off = 0; 27396277e832SShreyas NC char *data; 27406277e832SShreyas NC int ret; 27416277e832SShreyas NC 27426277e832SShreyas NC /* Read the NUM_DATA_BLOCKS descriptor */ 27436277e832SShreyas NC array = (struct snd_soc_tplg_vendor_array *)tplg_w->priv.data; 27446277e832SShreyas NC ret = skl_tplg_get_desc_blocks(dev, array); 27456277e832SShreyas NC if (ret < 0) 27466277e832SShreyas NC return ret; 27476277e832SShreyas NC num_blocks = ret; 27486277e832SShreyas NC 27496277e832SShreyas NC off += array->size; 27506277e832SShreyas NC /* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */ 27516277e832SShreyas NC while (num_blocks > 0) { 2752133e6e5cSShreyas NC array = (struct snd_soc_tplg_vendor_array *) 2753133e6e5cSShreyas NC (tplg_w->priv.data + off); 2754133e6e5cSShreyas NC 27556277e832SShreyas NC ret = skl_tplg_get_desc_blocks(dev, array); 27566277e832SShreyas NC 27576277e832SShreyas NC if (ret < 0) 27586277e832SShreyas NC return ret; 27596277e832SShreyas NC block_type = ret; 27606277e832SShreyas NC off += array->size; 27616277e832SShreyas NC 27626277e832SShreyas NC array = (struct snd_soc_tplg_vendor_array *) 27636277e832SShreyas NC (tplg_w->priv.data + off); 27646277e832SShreyas NC 27656277e832SShreyas NC ret = skl_tplg_get_desc_blocks(dev, array); 27666277e832SShreyas NC 27676277e832SShreyas NC if (ret < 0) 27686277e832SShreyas NC return ret; 27696277e832SShreyas NC block_size = ret; 27706277e832SShreyas NC off += array->size; 27716277e832SShreyas NC 27726277e832SShreyas NC array = (struct snd_soc_tplg_vendor_array *) 27736277e832SShreyas NC (tplg_w->priv.data + off); 27746277e832SShreyas NC 27756277e832SShreyas NC data = (tplg_w->priv.data + off); 27766277e832SShreyas NC 27776277e832SShreyas NC if (block_type == SKL_TYPE_TUPLE) { 27786277e832SShreyas NC ret = skl_tplg_get_tokens(dev, data, 27796277e832SShreyas NC skl, mconfig, block_size); 27806277e832SShreyas NC 27816277e832SShreyas NC if (ret < 0) 27826277e832SShreyas NC return ret; 27836277e832SShreyas NC 27846277e832SShreyas NC --num_blocks; 27856277e832SShreyas NC } else { 27866277e832SShreyas NC if (mconfig->formats_config.caps_size > 0) 27876277e832SShreyas NC memcpy(mconfig->formats_config.caps, data, 27886277e832SShreyas NC mconfig->formats_config.caps_size); 27896277e832SShreyas NC --num_blocks; 2790133e6e5cSShreyas NC ret = mconfig->formats_config.caps_size; 27916277e832SShreyas NC } 2792133e6e5cSShreyas NC off += ret; 27936277e832SShreyas NC } 27946277e832SShreyas NC 27956277e832SShreyas NC return 0; 27964cd9899fSHardik T Shah } 27974cd9899fSHardik T Shah 279856b03b4cSKuninori Morimoto static void skl_clear_pin_config(struct snd_soc_component *component, 2799fe3f4442SDharageswari R struct snd_soc_dapm_widget *w) 2800fe3f4442SDharageswari R { 2801fe3f4442SDharageswari R int i; 2802fe3f4442SDharageswari R struct skl_module_cfg *mconfig; 2803fe3f4442SDharageswari R struct skl_pipe *pipe; 2804fe3f4442SDharageswari R 280556b03b4cSKuninori Morimoto if (!strncmp(w->dapm->component->name, component->name, 280656b03b4cSKuninori Morimoto strlen(component->name))) { 2807fe3f4442SDharageswari R mconfig = w->priv; 2808fe3f4442SDharageswari R pipe = mconfig->pipe; 2809f6fa56e2SRamesh Babu for (i = 0; i < mconfig->module->max_input_pins; i++) { 2810fe3f4442SDharageswari R mconfig->m_in_pin[i].in_use = false; 2811fe3f4442SDharageswari R mconfig->m_in_pin[i].pin_state = SKL_PIN_UNBIND; 2812fe3f4442SDharageswari R } 2813f6fa56e2SRamesh Babu for (i = 0; i < mconfig->module->max_output_pins; i++) { 2814fe3f4442SDharageswari R mconfig->m_out_pin[i].in_use = false; 2815fe3f4442SDharageswari R mconfig->m_out_pin[i].pin_state = SKL_PIN_UNBIND; 2816fe3f4442SDharageswari R } 2817fe3f4442SDharageswari R pipe->state = SKL_PIPE_INVALID; 2818fe3f4442SDharageswari R mconfig->m_state = SKL_MODULE_UNINIT; 2819fe3f4442SDharageswari R } 2820fe3f4442SDharageswari R } 2821fe3f4442SDharageswari R 2822fe3f4442SDharageswari R void skl_cleanup_resources(struct skl *skl) 2823fe3f4442SDharageswari R { 2824fe3f4442SDharageswari R struct skl_sst *ctx = skl->skl_sst; 282556b03b4cSKuninori Morimoto struct snd_soc_component *soc_component = skl->component; 2826fe3f4442SDharageswari R struct snd_soc_dapm_widget *w; 2827fe3f4442SDharageswari R struct snd_soc_card *card; 2828fe3f4442SDharageswari R 282956b03b4cSKuninori Morimoto if (soc_component == NULL) 2830fe3f4442SDharageswari R return; 2831fe3f4442SDharageswari R 283256b03b4cSKuninori Morimoto card = soc_component->card; 2833fe3f4442SDharageswari R if (!card || !card->instantiated) 2834fe3f4442SDharageswari R return; 2835fe3f4442SDharageswari R 2836fe3f4442SDharageswari R skl->resource.mem = 0; 2837fe3f4442SDharageswari R skl->resource.mcps = 0; 2838fe3f4442SDharageswari R 2839fe3f4442SDharageswari R list_for_each_entry(w, &card->widgets, list) { 2840cb1f904dSGuneshwor Singh if (is_skl_dsp_widget_type(w, ctx->dev) && w->priv != NULL) 284156b03b4cSKuninori Morimoto skl_clear_pin_config(soc_component, w); 2842fe3f4442SDharageswari R } 2843fe3f4442SDharageswari R 2844fe3f4442SDharageswari R skl_clear_module_cnt(ctx->dsp); 2845fe3f4442SDharageswari R } 2846fe3f4442SDharageswari R 28473af36706SVinod Koul /* 28483af36706SVinod Koul * Topology core widget load callback 28493af36706SVinod Koul * 28503af36706SVinod Koul * This is used to save the private data for each widget which gives 28513af36706SVinod Koul * information to the driver about module and pipeline parameters which DSP 28523af36706SVinod Koul * FW expects like ids, resource values, formats etc 28533af36706SVinod Koul */ 2854*24ada035SMark Brown static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, 28553af36706SVinod Koul struct snd_soc_dapm_widget *w, 28563af36706SVinod Koul struct snd_soc_tplg_dapm_widget *tplg_w) 28573af36706SVinod Koul { 28583af36706SVinod Koul int ret; 28593af36706SVinod Koul struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt); 28603af36706SVinod Koul struct skl *skl = ebus_to_skl(ebus); 28613af36706SVinod Koul struct hdac_bus *bus = ebus_to_hbus(ebus); 28623af36706SVinod Koul struct skl_module_cfg *mconfig; 28633af36706SVinod Koul 28643af36706SVinod Koul if (!tplg_w->priv.size) 28653af36706SVinod Koul goto bind_event; 28663af36706SVinod Koul 28673af36706SVinod Koul mconfig = devm_kzalloc(bus->dev, sizeof(*mconfig), GFP_KERNEL); 28683af36706SVinod Koul 28693af36706SVinod Koul if (!mconfig) 28703af36706SVinod Koul return -ENOMEM; 28713af36706SVinod Koul 2872f6fa56e2SRamesh Babu if (skl->nr_modules == 0) { 2873f6fa56e2SRamesh Babu mconfig->module = devm_kzalloc(bus->dev, 2874f6fa56e2SRamesh Babu sizeof(*mconfig->module), GFP_KERNEL); 2875f6fa56e2SRamesh Babu if (!mconfig->module) 2876f6fa56e2SRamesh Babu return -ENOMEM; 2877f6fa56e2SRamesh Babu } 2878f6fa56e2SRamesh Babu 28793af36706SVinod Koul w->priv = mconfig; 288009305da9SShreyas NC 2881b7c50555SVinod Koul /* 2882b7c50555SVinod Koul * module binary can be loaded later, so set it to query when 2883b7c50555SVinod Koul * module is load for a use case 2884b7c50555SVinod Koul */ 2885b7c50555SVinod Koul mconfig->id.module_id = -1; 28864cd9899fSHardik T Shah 28876277e832SShreyas NC /* Parse private data for tuples */ 28886277e832SShreyas NC ret = skl_tplg_get_pvt_data(tplg_w, skl, bus->dev, mconfig); 28896277e832SShreyas NC if (ret < 0) 28906277e832SShreyas NC return ret; 2891d14700a0SVinod Koul 2892d14700a0SVinod Koul skl_debug_init_module(skl->debugfs, w, mconfig); 2893d14700a0SVinod Koul 28943af36706SVinod Koul bind_event: 28953af36706SVinod Koul if (tplg_w->event_type == 0) { 28963373f716SVinod Koul dev_dbg(bus->dev, "ASoC: No event handler required\n"); 28973af36706SVinod Koul return 0; 28983af36706SVinod Koul } 28993af36706SVinod Koul 29003af36706SVinod Koul ret = snd_soc_tplg_widget_bind_event(w, skl_tplg_widget_ops, 2901b663a8c5SJeeja KP ARRAY_SIZE(skl_tplg_widget_ops), 2902b663a8c5SJeeja KP tplg_w->event_type); 29033af36706SVinod Koul 29043af36706SVinod Koul if (ret) { 29053af36706SVinod Koul dev_err(bus->dev, "%s: No matching event handlers found for %d\n", 29063af36706SVinod Koul __func__, tplg_w->event_type); 29073af36706SVinod Koul return -EINVAL; 29083af36706SVinod Koul } 29093af36706SVinod Koul 29103af36706SVinod Koul return 0; 29113af36706SVinod Koul } 29123af36706SVinod Koul 2913140adfbaSJeeja KP static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be, 2914140adfbaSJeeja KP struct snd_soc_tplg_bytes_control *bc) 2915140adfbaSJeeja KP { 2916140adfbaSJeeja KP struct skl_algo_data *ac; 2917140adfbaSJeeja KP struct skl_dfw_algo_data *dfw_ac = 2918140adfbaSJeeja KP (struct skl_dfw_algo_data *)bc->priv.data; 2919140adfbaSJeeja KP 2920140adfbaSJeeja KP ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL); 2921140adfbaSJeeja KP if (!ac) 2922140adfbaSJeeja KP return -ENOMEM; 2923140adfbaSJeeja KP 2924140adfbaSJeeja KP /* Fill private data */ 2925140adfbaSJeeja KP ac->max = dfw_ac->max; 2926140adfbaSJeeja KP ac->param_id = dfw_ac->param_id; 2927140adfbaSJeeja KP ac->set_params = dfw_ac->set_params; 29280d682104SDharageswari R ac->size = dfw_ac->max; 2929140adfbaSJeeja KP 2930140adfbaSJeeja KP if (ac->max) { 2931140adfbaSJeeja KP ac->params = (char *) devm_kzalloc(dev, ac->max, GFP_KERNEL); 2932140adfbaSJeeja KP if (!ac->params) 2933140adfbaSJeeja KP return -ENOMEM; 2934140adfbaSJeeja KP 2935140adfbaSJeeja KP memcpy(ac->params, dfw_ac->params, ac->max); 2936140adfbaSJeeja KP } 2937140adfbaSJeeja KP 2938140adfbaSJeeja KP be->dobj.private = ac; 2939140adfbaSJeeja KP return 0; 2940140adfbaSJeeja KP } 2941140adfbaSJeeja KP 29427a1b749bSDharageswari R static int skl_init_enum_data(struct device *dev, struct soc_enum *se, 29437a1b749bSDharageswari R struct snd_soc_tplg_enum_control *ec) 29447a1b749bSDharageswari R { 29457a1b749bSDharageswari R 29467a1b749bSDharageswari R void *data; 29477a1b749bSDharageswari R 29487a1b749bSDharageswari R if (ec->priv.size) { 29497a1b749bSDharageswari R data = devm_kzalloc(dev, sizeof(ec->priv.size), GFP_KERNEL); 29507a1b749bSDharageswari R if (!data) 29517a1b749bSDharageswari R return -ENOMEM; 29527a1b749bSDharageswari R memcpy(data, ec->priv.data, ec->priv.size); 29537a1b749bSDharageswari R se->dobj.private = data; 29547a1b749bSDharageswari R } 29557a1b749bSDharageswari R 29567a1b749bSDharageswari R return 0; 29577a1b749bSDharageswari R 29587a1b749bSDharageswari R } 29597a1b749bSDharageswari R 2960140adfbaSJeeja KP static int skl_tplg_control_load(struct snd_soc_component *cmpnt, 2961140adfbaSJeeja KP struct snd_kcontrol_new *kctl, 2962140adfbaSJeeja KP struct snd_soc_tplg_ctl_hdr *hdr) 2963140adfbaSJeeja KP { 2964140adfbaSJeeja KP struct soc_bytes_ext *sb; 2965140adfbaSJeeja KP struct snd_soc_tplg_bytes_control *tplg_bc; 29667a1b749bSDharageswari R struct snd_soc_tplg_enum_control *tplg_ec; 2967140adfbaSJeeja KP struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt); 2968140adfbaSJeeja KP struct hdac_bus *bus = ebus_to_hbus(ebus); 29697a1b749bSDharageswari R struct soc_enum *se; 2970140adfbaSJeeja KP 2971140adfbaSJeeja KP switch (hdr->ops.info) { 2972140adfbaSJeeja KP case SND_SOC_TPLG_CTL_BYTES: 2973140adfbaSJeeja KP tplg_bc = container_of(hdr, 2974140adfbaSJeeja KP struct snd_soc_tplg_bytes_control, hdr); 2975140adfbaSJeeja KP if (kctl->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 2976140adfbaSJeeja KP sb = (struct soc_bytes_ext *)kctl->private_value; 2977140adfbaSJeeja KP if (tplg_bc->priv.size) 2978140adfbaSJeeja KP return skl_init_algo_data( 2979140adfbaSJeeja KP bus->dev, sb, tplg_bc); 2980140adfbaSJeeja KP } 2981140adfbaSJeeja KP break; 2982140adfbaSJeeja KP 29837a1b749bSDharageswari R case SND_SOC_TPLG_CTL_ENUM: 29847a1b749bSDharageswari R tplg_ec = container_of(hdr, 29857a1b749bSDharageswari R struct snd_soc_tplg_enum_control, hdr); 29867a1b749bSDharageswari R if (kctl->access & SNDRV_CTL_ELEM_ACCESS_READWRITE) { 29877a1b749bSDharageswari R se = (struct soc_enum *)kctl->private_value; 29887a1b749bSDharageswari R if (tplg_ec->priv.size) 29897a1b749bSDharageswari R return skl_init_enum_data(bus->dev, se, 29907a1b749bSDharageswari R tplg_ec); 29917a1b749bSDharageswari R } 29927a1b749bSDharageswari R break; 29937a1b749bSDharageswari R 2994140adfbaSJeeja KP default: 29954362934aSNaveen Manohar dev_dbg(bus->dev, "Control load not supported %d:%d:%d\n", 2996140adfbaSJeeja KP hdr->ops.get, hdr->ops.put, hdr->ops.info); 2997140adfbaSJeeja KP break; 2998140adfbaSJeeja KP } 2999140adfbaSJeeja KP 3000140adfbaSJeeja KP return 0; 3001140adfbaSJeeja KP } 3002140adfbaSJeeja KP 3003541070ceSShreyas NC static int skl_tplg_fill_str_mfest_tkn(struct device *dev, 3004541070ceSShreyas NC struct snd_soc_tplg_vendor_string_elem *str_elem, 3005eee0e16fSJeeja KP struct skl *skl) 3006541070ceSShreyas NC { 3007541070ceSShreyas NC int tkn_count = 0; 3008541070ceSShreyas NC static int ref_count; 3009541070ceSShreyas NC 3010541070ceSShreyas NC switch (str_elem->token) { 3011541070ceSShreyas NC case SKL_TKN_STR_LIB_NAME: 3012eee0e16fSJeeja KP if (ref_count > skl->skl_sst->lib_count - 1) { 3013541070ceSShreyas NC ref_count = 0; 3014541070ceSShreyas NC return -EINVAL; 3015541070ceSShreyas NC } 3016541070ceSShreyas NC 3017eee0e16fSJeeja KP strncpy(skl->skl_sst->lib_info[ref_count].name, 3018eee0e16fSJeeja KP str_elem->string, 3019eee0e16fSJeeja KP ARRAY_SIZE(skl->skl_sst->lib_info[ref_count].name)); 3020541070ceSShreyas NC ref_count++; 3021541070ceSShreyas NC break; 3022541070ceSShreyas NC 3023541070ceSShreyas NC default: 3024ecd286a9SColin Ian King dev_err(dev, "Not a string token %d\n", str_elem->token); 3025541070ceSShreyas NC break; 3026541070ceSShreyas NC } 3027db6ed55dSShreyas NC tkn_count++; 3028541070ceSShreyas NC 3029541070ceSShreyas NC return tkn_count; 3030541070ceSShreyas NC } 3031541070ceSShreyas NC 3032541070ceSShreyas NC static int skl_tplg_get_str_tkn(struct device *dev, 3033541070ceSShreyas NC struct snd_soc_tplg_vendor_array *array, 3034eee0e16fSJeeja KP struct skl *skl) 3035541070ceSShreyas NC { 3036541070ceSShreyas NC int tkn_count = 0, ret; 3037541070ceSShreyas NC struct snd_soc_tplg_vendor_string_elem *str_elem; 3038541070ceSShreyas NC 3039541070ceSShreyas NC str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value; 3040541070ceSShreyas NC while (tkn_count < array->num_elems) { 3041eee0e16fSJeeja KP ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, skl); 3042541070ceSShreyas NC str_elem++; 3043541070ceSShreyas NC 3044541070ceSShreyas NC if (ret < 0) 3045541070ceSShreyas NC return ret; 3046541070ceSShreyas NC 3047541070ceSShreyas NC tkn_count = tkn_count + ret; 3048541070ceSShreyas NC } 3049541070ceSShreyas NC 3050541070ceSShreyas NC return tkn_count; 3051541070ceSShreyas NC } 3052541070ceSShreyas NC 3053db6ed55dSShreyas NC static int skl_tplg_manifest_fill_fmt(struct device *dev, 3054db6ed55dSShreyas NC struct skl_module_iface *fmt, 3055db6ed55dSShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem, 3056db6ed55dSShreyas NC u32 dir, int fmt_idx) 3057db6ed55dSShreyas NC { 3058db6ed55dSShreyas NC struct skl_module_pin_fmt *dst_fmt; 3059db6ed55dSShreyas NC struct skl_module_fmt *mod_fmt; 3060db6ed55dSShreyas NC int ret; 3061db6ed55dSShreyas NC 3062db6ed55dSShreyas NC if (!fmt) 3063db6ed55dSShreyas NC return -EINVAL; 3064db6ed55dSShreyas NC 3065db6ed55dSShreyas NC switch (dir) { 3066db6ed55dSShreyas NC case SKL_DIR_IN: 3067db6ed55dSShreyas NC dst_fmt = &fmt->inputs[fmt_idx]; 3068db6ed55dSShreyas NC break; 3069db6ed55dSShreyas NC 3070db6ed55dSShreyas NC case SKL_DIR_OUT: 3071db6ed55dSShreyas NC dst_fmt = &fmt->outputs[fmt_idx]; 3072db6ed55dSShreyas NC break; 3073db6ed55dSShreyas NC 3074db6ed55dSShreyas NC default: 3075db6ed55dSShreyas NC dev_err(dev, "Invalid direction: %d\n", dir); 3076db6ed55dSShreyas NC return -EINVAL; 3077db6ed55dSShreyas NC } 3078db6ed55dSShreyas NC 3079db6ed55dSShreyas NC mod_fmt = &dst_fmt->fmt; 3080db6ed55dSShreyas NC 3081db6ed55dSShreyas NC switch (tkn_elem->token) { 3082db6ed55dSShreyas NC case SKL_TKN_MM_U32_INTF_PIN_ID: 3083db6ed55dSShreyas NC dst_fmt->id = tkn_elem->value; 3084db6ed55dSShreyas NC break; 3085db6ed55dSShreyas NC 3086db6ed55dSShreyas NC default: 3087db6ed55dSShreyas NC ret = skl_tplg_fill_fmt(dev, mod_fmt, tkn_elem->token, 3088db6ed55dSShreyas NC tkn_elem->value); 3089db6ed55dSShreyas NC if (ret < 0) 3090db6ed55dSShreyas NC return ret; 3091db6ed55dSShreyas NC break; 3092db6ed55dSShreyas NC } 3093db6ed55dSShreyas NC 3094db6ed55dSShreyas NC return 0; 3095db6ed55dSShreyas NC } 3096db6ed55dSShreyas NC 3097db6ed55dSShreyas NC static int skl_tplg_fill_mod_info(struct device *dev, 3098db6ed55dSShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem, 3099db6ed55dSShreyas NC struct skl_module *mod) 3100db6ed55dSShreyas NC { 3101db6ed55dSShreyas NC 3102db6ed55dSShreyas NC if (!mod) 3103db6ed55dSShreyas NC return -EINVAL; 3104db6ed55dSShreyas NC 3105db6ed55dSShreyas NC switch (tkn_elem->token) { 3106db6ed55dSShreyas NC case SKL_TKN_U8_IN_PIN_TYPE: 3107db6ed55dSShreyas NC mod->input_pin_type = tkn_elem->value; 3108db6ed55dSShreyas NC break; 3109db6ed55dSShreyas NC 3110db6ed55dSShreyas NC case SKL_TKN_U8_OUT_PIN_TYPE: 3111db6ed55dSShreyas NC mod->output_pin_type = tkn_elem->value; 3112db6ed55dSShreyas NC break; 3113db6ed55dSShreyas NC 3114db6ed55dSShreyas NC case SKL_TKN_U8_IN_QUEUE_COUNT: 3115db6ed55dSShreyas NC mod->max_input_pins = tkn_elem->value; 3116db6ed55dSShreyas NC break; 3117db6ed55dSShreyas NC 3118db6ed55dSShreyas NC case SKL_TKN_U8_OUT_QUEUE_COUNT: 3119db6ed55dSShreyas NC mod->max_output_pins = tkn_elem->value; 3120db6ed55dSShreyas NC break; 3121db6ed55dSShreyas NC 3122db6ed55dSShreyas NC case SKL_TKN_MM_U8_NUM_RES: 3123db6ed55dSShreyas NC mod->nr_resources = tkn_elem->value; 3124db6ed55dSShreyas NC break; 3125db6ed55dSShreyas NC 3126db6ed55dSShreyas NC case SKL_TKN_MM_U8_NUM_INTF: 3127db6ed55dSShreyas NC mod->nr_interfaces = tkn_elem->value; 3128db6ed55dSShreyas NC break; 3129db6ed55dSShreyas NC 3130db6ed55dSShreyas NC default: 3131db6ed55dSShreyas NC dev_err(dev, "Invalid mod info token %d", tkn_elem->token); 3132db6ed55dSShreyas NC return -EINVAL; 3133db6ed55dSShreyas NC } 3134db6ed55dSShreyas NC 3135db6ed55dSShreyas NC return 0; 3136db6ed55dSShreyas NC } 3137db6ed55dSShreyas NC 3138db6ed55dSShreyas NC 3139541070ceSShreyas NC static int skl_tplg_get_int_tkn(struct device *dev, 3140541070ceSShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem, 3141eee0e16fSJeeja KP struct skl *skl) 3142541070ceSShreyas NC { 314343762355SPradeep Tewani int tkn_count = 0, ret, size; 3144db6ed55dSShreyas NC static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx; 3145db6ed55dSShreyas NC struct skl_module_res *res = NULL; 3146db6ed55dSShreyas NC struct skl_module_iface *fmt = NULL; 3147db6ed55dSShreyas NC struct skl_module *mod = NULL; 314843762355SPradeep Tewani static struct skl_astate_param *astate_table; 314943762355SPradeep Tewani static int astate_cfg_idx, count; 3150db6ed55dSShreyas NC int i; 3151db6ed55dSShreyas NC 3152db6ed55dSShreyas NC if (skl->modules) { 3153db6ed55dSShreyas NC mod = skl->modules[mod_idx]; 3154db6ed55dSShreyas NC res = &mod->resources[res_val_idx]; 3155db6ed55dSShreyas NC fmt = &mod->formats[intf_val_idx]; 3156db6ed55dSShreyas NC } 3157541070ceSShreyas NC 3158541070ceSShreyas NC switch (tkn_elem->token) { 3159541070ceSShreyas NC case SKL_TKN_U32_LIB_COUNT: 3160eee0e16fSJeeja KP skl->skl_sst->lib_count = tkn_elem->value; 3161db6ed55dSShreyas NC break; 3162db6ed55dSShreyas NC 3163db6ed55dSShreyas NC case SKL_TKN_U8_NUM_MOD: 3164db6ed55dSShreyas NC skl->nr_modules = tkn_elem->value; 3165db6ed55dSShreyas NC skl->modules = devm_kcalloc(dev, skl->nr_modules, 3166db6ed55dSShreyas NC sizeof(*skl->modules), GFP_KERNEL); 3167db6ed55dSShreyas NC if (!skl->modules) 3168db6ed55dSShreyas NC return -ENOMEM; 3169db6ed55dSShreyas NC 3170db6ed55dSShreyas NC for (i = 0; i < skl->nr_modules; i++) { 3171db6ed55dSShreyas NC skl->modules[i] = devm_kzalloc(dev, 3172db6ed55dSShreyas NC sizeof(struct skl_module), GFP_KERNEL); 3173db6ed55dSShreyas NC if (!skl->modules[i]) 3174db6ed55dSShreyas NC return -ENOMEM; 3175db6ed55dSShreyas NC } 3176db6ed55dSShreyas NC break; 3177db6ed55dSShreyas NC 3178db6ed55dSShreyas NC case SKL_TKN_MM_U8_MOD_IDX: 3179db6ed55dSShreyas NC mod_idx = tkn_elem->value; 3180db6ed55dSShreyas NC break; 3181db6ed55dSShreyas NC 318243762355SPradeep Tewani case SKL_TKN_U32_ASTATE_COUNT: 318343762355SPradeep Tewani if (astate_table != NULL) { 318443762355SPradeep Tewani dev_err(dev, "More than one entry for A-State count"); 318543762355SPradeep Tewani return -EINVAL; 318643762355SPradeep Tewani } 318743762355SPradeep Tewani 318843762355SPradeep Tewani if (tkn_elem->value > SKL_MAX_ASTATE_CFG) { 318943762355SPradeep Tewani dev_err(dev, "Invalid A-State count %d\n", 319043762355SPradeep Tewani tkn_elem->value); 319143762355SPradeep Tewani return -EINVAL; 319243762355SPradeep Tewani } 319343762355SPradeep Tewani 319443762355SPradeep Tewani size = tkn_elem->value * sizeof(struct skl_astate_param) + 319543762355SPradeep Tewani sizeof(count); 319643762355SPradeep Tewani skl->cfg.astate_cfg = devm_kzalloc(dev, size, GFP_KERNEL); 319743762355SPradeep Tewani if (!skl->cfg.astate_cfg) 319843762355SPradeep Tewani return -ENOMEM; 319943762355SPradeep Tewani 320043762355SPradeep Tewani astate_table = skl->cfg.astate_cfg->astate_table; 320143762355SPradeep Tewani count = skl->cfg.astate_cfg->count = tkn_elem->value; 320243762355SPradeep Tewani break; 320343762355SPradeep Tewani 320443762355SPradeep Tewani case SKL_TKN_U32_ASTATE_IDX: 320543762355SPradeep Tewani if (tkn_elem->value >= count) { 320643762355SPradeep Tewani dev_err(dev, "Invalid A-State index %d\n", 320743762355SPradeep Tewani tkn_elem->value); 320843762355SPradeep Tewani return -EINVAL; 320943762355SPradeep Tewani } 321043762355SPradeep Tewani 321143762355SPradeep Tewani astate_cfg_idx = tkn_elem->value; 321243762355SPradeep Tewani break; 321343762355SPradeep Tewani 321443762355SPradeep Tewani case SKL_TKN_U32_ASTATE_KCPS: 321543762355SPradeep Tewani astate_table[astate_cfg_idx].kcps = tkn_elem->value; 321643762355SPradeep Tewani break; 321743762355SPradeep Tewani 321843762355SPradeep Tewani case SKL_TKN_U32_ASTATE_CLK_SRC: 321943762355SPradeep Tewani astate_table[astate_cfg_idx].clk_src = tkn_elem->value; 322043762355SPradeep Tewani break; 322143762355SPradeep Tewani 3222db6ed55dSShreyas NC case SKL_TKN_U8_IN_PIN_TYPE: 3223db6ed55dSShreyas NC case SKL_TKN_U8_OUT_PIN_TYPE: 3224db6ed55dSShreyas NC case SKL_TKN_U8_IN_QUEUE_COUNT: 3225db6ed55dSShreyas NC case SKL_TKN_U8_OUT_QUEUE_COUNT: 3226db6ed55dSShreyas NC case SKL_TKN_MM_U8_NUM_RES: 3227db6ed55dSShreyas NC case SKL_TKN_MM_U8_NUM_INTF: 3228db6ed55dSShreyas NC ret = skl_tplg_fill_mod_info(dev, tkn_elem, mod); 3229db6ed55dSShreyas NC if (ret < 0) 3230db6ed55dSShreyas NC return ret; 3231db6ed55dSShreyas NC break; 3232db6ed55dSShreyas NC 3233db6ed55dSShreyas NC case SKL_TKN_U32_DIR_PIN_COUNT: 3234db6ed55dSShreyas NC dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK; 3235db6ed55dSShreyas NC pin_idx = (tkn_elem->value & SKL_PIN_COUNT_MASK) >> 4; 3236db6ed55dSShreyas NC break; 3237db6ed55dSShreyas NC 3238db6ed55dSShreyas NC case SKL_TKN_MM_U32_RES_ID: 3239db6ed55dSShreyas NC if (!res) 3240db6ed55dSShreyas NC return -EINVAL; 3241db6ed55dSShreyas NC 3242db6ed55dSShreyas NC res->id = tkn_elem->value; 3243db6ed55dSShreyas NC res_val_idx = tkn_elem->value; 3244db6ed55dSShreyas NC break; 3245db6ed55dSShreyas NC 3246db6ed55dSShreyas NC case SKL_TKN_MM_U32_FMT_ID: 3247db6ed55dSShreyas NC if (!fmt) 3248db6ed55dSShreyas NC return -EINVAL; 3249db6ed55dSShreyas NC 3250db6ed55dSShreyas NC fmt->fmt_idx = tkn_elem->value; 3251db6ed55dSShreyas NC intf_val_idx = tkn_elem->value; 3252db6ed55dSShreyas NC break; 3253db6ed55dSShreyas NC 3254db6ed55dSShreyas NC case SKL_TKN_MM_U32_CPS: 3255db6ed55dSShreyas NC case SKL_TKN_MM_U32_DMA_SIZE: 3256db6ed55dSShreyas NC case SKL_TKN_MM_U32_CPC: 3257db6ed55dSShreyas NC case SKL_TKN_U32_MEM_PAGES: 3258db6ed55dSShreyas NC case SKL_TKN_U32_OBS: 3259db6ed55dSShreyas NC case SKL_TKN_U32_IBS: 3260db6ed55dSShreyas NC case SKL_TKN_MM_U32_RES_PIN_ID: 3261db6ed55dSShreyas NC case SKL_TKN_MM_U32_PIN_BUF: 3262db6ed55dSShreyas NC ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_idx, dir); 3263db6ed55dSShreyas NC if (ret < 0) 3264db6ed55dSShreyas NC return ret; 3265db6ed55dSShreyas NC 3266db6ed55dSShreyas NC break; 3267db6ed55dSShreyas NC 3268db6ed55dSShreyas NC case SKL_TKN_MM_U32_NUM_IN_FMT: 3269db6ed55dSShreyas NC if (!fmt) 3270db6ed55dSShreyas NC return -EINVAL; 3271db6ed55dSShreyas NC 3272db6ed55dSShreyas NC res->nr_input_pins = tkn_elem->value; 3273db6ed55dSShreyas NC break; 3274db6ed55dSShreyas NC 3275db6ed55dSShreyas NC case SKL_TKN_MM_U32_NUM_OUT_FMT: 3276db6ed55dSShreyas NC if (!fmt) 3277db6ed55dSShreyas NC return -EINVAL; 3278db6ed55dSShreyas NC 3279db6ed55dSShreyas NC res->nr_output_pins = tkn_elem->value; 3280db6ed55dSShreyas NC break; 3281db6ed55dSShreyas NC 3282db6ed55dSShreyas NC case SKL_TKN_U32_FMT_CH: 3283db6ed55dSShreyas NC case SKL_TKN_U32_FMT_FREQ: 3284db6ed55dSShreyas NC case SKL_TKN_U32_FMT_BIT_DEPTH: 3285db6ed55dSShreyas NC case SKL_TKN_U32_FMT_SAMPLE_SIZE: 3286db6ed55dSShreyas NC case SKL_TKN_U32_FMT_CH_CONFIG: 3287db6ed55dSShreyas NC case SKL_TKN_U32_FMT_INTERLEAVE: 3288db6ed55dSShreyas NC case SKL_TKN_U32_FMT_SAMPLE_TYPE: 3289db6ed55dSShreyas NC case SKL_TKN_U32_FMT_CH_MAP: 3290db6ed55dSShreyas NC case SKL_TKN_MM_U32_INTF_PIN_ID: 3291db6ed55dSShreyas NC ret = skl_tplg_manifest_fill_fmt(dev, fmt, tkn_elem, 3292db6ed55dSShreyas NC dir, pin_idx); 3293db6ed55dSShreyas NC if (ret < 0) 3294db6ed55dSShreyas NC return ret; 3295541070ceSShreyas NC break; 3296541070ceSShreyas NC 3297541070ceSShreyas NC default: 3298ecd286a9SColin Ian King dev_err(dev, "Not a manifest token %d\n", tkn_elem->token); 3299541070ceSShreyas NC return -EINVAL; 3300541070ceSShreyas NC } 3301db6ed55dSShreyas NC tkn_count++; 3302541070ceSShreyas NC 3303541070ceSShreyas NC return tkn_count; 3304541070ceSShreyas NC } 3305541070ceSShreyas NC 3306db6ed55dSShreyas NC static int skl_tplg_get_manifest_uuid(struct device *dev, 3307db6ed55dSShreyas NC struct skl *skl, 3308db6ed55dSShreyas NC struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn) 3309db6ed55dSShreyas NC { 3310db6ed55dSShreyas NC static int ref_count; 3311db6ed55dSShreyas NC struct skl_module *mod; 3312db6ed55dSShreyas NC 3313db6ed55dSShreyas NC if (uuid_tkn->token == SKL_TKN_UUID) { 3314db6ed55dSShreyas NC mod = skl->modules[ref_count]; 3315db6ed55dSShreyas NC memcpy(&mod->uuid, &uuid_tkn->uuid, sizeof(uuid_tkn->uuid)); 3316db6ed55dSShreyas NC ref_count++; 3317db6ed55dSShreyas NC } else { 3318db6ed55dSShreyas NC dev_err(dev, "Not an UUID token tkn %d\n", uuid_tkn->token); 3319db6ed55dSShreyas NC return -EINVAL; 3320db6ed55dSShreyas NC } 3321db6ed55dSShreyas NC 3322db6ed55dSShreyas NC return 0; 3323db6ed55dSShreyas NC } 3324db6ed55dSShreyas NC 3325541070ceSShreyas NC /* 3326541070ceSShreyas NC * Fill the manifest structure by parsing the tokens based on the 3327541070ceSShreyas NC * type. 3328541070ceSShreyas NC */ 3329541070ceSShreyas NC static int skl_tplg_get_manifest_tkn(struct device *dev, 3330eee0e16fSJeeja KP char *pvt_data, struct skl *skl, 3331541070ceSShreyas NC int block_size) 3332541070ceSShreyas NC { 3333541070ceSShreyas NC int tkn_count = 0, ret; 3334541070ceSShreyas NC int off = 0, tuple_size = 0; 3335541070ceSShreyas NC struct snd_soc_tplg_vendor_array *array; 3336541070ceSShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem; 3337541070ceSShreyas NC 3338541070ceSShreyas NC if (block_size <= 0) 3339541070ceSShreyas NC return -EINVAL; 3340541070ceSShreyas NC 3341541070ceSShreyas NC while (tuple_size < block_size) { 3342541070ceSShreyas NC array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off); 3343541070ceSShreyas NC off += array->size; 3344541070ceSShreyas NC switch (array->type) { 3345541070ceSShreyas NC case SND_SOC_TPLG_TUPLE_TYPE_STRING: 3346eee0e16fSJeeja KP ret = skl_tplg_get_str_tkn(dev, array, skl); 3347541070ceSShreyas NC 3348541070ceSShreyas NC if (ret < 0) 3349541070ceSShreyas NC return ret; 33500a716776SShreyas NC tkn_count = ret; 3351541070ceSShreyas NC 3352541070ceSShreyas NC tuple_size += tkn_count * 3353541070ceSShreyas NC sizeof(struct snd_soc_tplg_vendor_string_elem); 3354541070ceSShreyas NC continue; 3355541070ceSShreyas NC 3356541070ceSShreyas NC case SND_SOC_TPLG_TUPLE_TYPE_UUID: 3357db6ed55dSShreyas NC ret = skl_tplg_get_manifest_uuid(dev, skl, array->uuid); 3358db6ed55dSShreyas NC if (ret < 0) 3359db6ed55dSShreyas NC return ret; 3360db6ed55dSShreyas NC 3361db6ed55dSShreyas NC tuple_size += sizeof(*array->uuid); 3362541070ceSShreyas NC continue; 3363541070ceSShreyas NC 3364541070ceSShreyas NC default: 3365541070ceSShreyas NC tkn_elem = array->value; 3366541070ceSShreyas NC tkn_count = 0; 3367541070ceSShreyas NC break; 3368541070ceSShreyas NC } 3369541070ceSShreyas NC 3370541070ceSShreyas NC while (tkn_count <= array->num_elems - 1) { 3371541070ceSShreyas NC ret = skl_tplg_get_int_tkn(dev, 3372eee0e16fSJeeja KP tkn_elem, skl); 3373541070ceSShreyas NC if (ret < 0) 3374541070ceSShreyas NC return ret; 3375541070ceSShreyas NC 3376541070ceSShreyas NC tkn_count = tkn_count + ret; 3377541070ceSShreyas NC tkn_elem++; 3378541070ceSShreyas NC } 33799fc129f6SShreyas NC tuple_size += (tkn_count * sizeof(*tkn_elem)); 3380541070ceSShreyas NC tkn_count = 0; 3381541070ceSShreyas NC } 3382541070ceSShreyas NC 33839fc129f6SShreyas NC return off; 3384541070ceSShreyas NC } 3385541070ceSShreyas NC 3386541070ceSShreyas NC /* 3387541070ceSShreyas NC * Parse manifest private data for tokens. The private data block is 3388541070ceSShreyas NC * preceded by descriptors for type and size of data block. 3389541070ceSShreyas NC */ 3390541070ceSShreyas NC static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest, 3391eee0e16fSJeeja KP struct device *dev, struct skl *skl) 3392541070ceSShreyas NC { 3393541070ceSShreyas NC struct snd_soc_tplg_vendor_array *array; 3394541070ceSShreyas NC int num_blocks, block_size = 0, block_type, off = 0; 3395541070ceSShreyas NC char *data; 3396541070ceSShreyas NC int ret; 3397541070ceSShreyas NC 3398541070ceSShreyas NC /* Read the NUM_DATA_BLOCKS descriptor */ 3399541070ceSShreyas NC array = (struct snd_soc_tplg_vendor_array *)manifest->priv.data; 3400541070ceSShreyas NC ret = skl_tplg_get_desc_blocks(dev, array); 3401541070ceSShreyas NC if (ret < 0) 3402541070ceSShreyas NC return ret; 3403541070ceSShreyas NC num_blocks = ret; 3404541070ceSShreyas NC 3405541070ceSShreyas NC off += array->size; 3406541070ceSShreyas NC /* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */ 3407541070ceSShreyas NC while (num_blocks > 0) { 34089fc129f6SShreyas NC array = (struct snd_soc_tplg_vendor_array *) 34099fc129f6SShreyas NC (manifest->priv.data + off); 3410541070ceSShreyas NC ret = skl_tplg_get_desc_blocks(dev, array); 3411541070ceSShreyas NC 3412541070ceSShreyas NC if (ret < 0) 3413541070ceSShreyas NC return ret; 3414541070ceSShreyas NC block_type = ret; 3415541070ceSShreyas NC off += array->size; 3416541070ceSShreyas NC 3417541070ceSShreyas NC array = (struct snd_soc_tplg_vendor_array *) 3418541070ceSShreyas NC (manifest->priv.data + off); 3419541070ceSShreyas NC 3420541070ceSShreyas NC ret = skl_tplg_get_desc_blocks(dev, array); 3421541070ceSShreyas NC 3422541070ceSShreyas NC if (ret < 0) 3423541070ceSShreyas NC return ret; 3424541070ceSShreyas NC block_size = ret; 3425541070ceSShreyas NC off += array->size; 3426541070ceSShreyas NC 3427541070ceSShreyas NC array = (struct snd_soc_tplg_vendor_array *) 3428541070ceSShreyas NC (manifest->priv.data + off); 3429541070ceSShreyas NC 3430541070ceSShreyas NC data = (manifest->priv.data + off); 3431541070ceSShreyas NC 3432541070ceSShreyas NC if (block_type == SKL_TYPE_TUPLE) { 3433eee0e16fSJeeja KP ret = skl_tplg_get_manifest_tkn(dev, data, skl, 3434541070ceSShreyas NC block_size); 3435541070ceSShreyas NC 3436541070ceSShreyas NC if (ret < 0) 3437541070ceSShreyas NC return ret; 3438541070ceSShreyas NC 3439541070ceSShreyas NC --num_blocks; 3440541070ceSShreyas NC } else { 3441541070ceSShreyas NC return -EINVAL; 3442541070ceSShreyas NC } 34439fc129f6SShreyas NC off += ret; 3444541070ceSShreyas NC } 3445541070ceSShreyas NC 3446541070ceSShreyas NC return 0; 3447541070ceSShreyas NC } 3448541070ceSShreyas NC 3449*24ada035SMark Brown static int skl_manifest_load(struct snd_soc_component *cmpnt, 345015ecaba9SKranthi G struct snd_soc_tplg_manifest *manifest) 345115ecaba9SKranthi G { 345215ecaba9SKranthi G struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt); 345315ecaba9SKranthi G struct hdac_bus *bus = ebus_to_hbus(ebus); 345415ecaba9SKranthi G struct skl *skl = ebus_to_skl(ebus); 345515ecaba9SKranthi G 3456c15ad605SVinod Koul /* proceed only if we have private data defined */ 3457c15ad605SVinod Koul if (manifest->priv.size == 0) 3458c15ad605SVinod Koul return 0; 3459c15ad605SVinod Koul 3460eee0e16fSJeeja KP skl_tplg_get_manifest_data(manifest, bus->dev, skl); 3461541070ceSShreyas NC 3462eee0e16fSJeeja KP if (skl->skl_sst->lib_count > SKL_MAX_LIB) { 346315ecaba9SKranthi G dev_err(bus->dev, "Exceeding max Library count. Got:%d\n", 3464eee0e16fSJeeja KP skl->skl_sst->lib_count); 3465eee0e16fSJeeja KP return -EINVAL; 346615ecaba9SKranthi G } 346715ecaba9SKranthi G 3468eee0e16fSJeeja KP return 0; 346915ecaba9SKranthi G } 347015ecaba9SKranthi G 34713af36706SVinod Koul static struct snd_soc_tplg_ops skl_tplg_ops = { 34723af36706SVinod Koul .widget_load = skl_tplg_widget_load, 3473140adfbaSJeeja KP .control_load = skl_tplg_control_load, 3474140adfbaSJeeja KP .bytes_ext_ops = skl_tlv_ops, 3475140adfbaSJeeja KP .bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops), 34767a1b749bSDharageswari R .io_ops = skl_tplg_kcontrol_ops, 34777a1b749bSDharageswari R .io_ops_count = ARRAY_SIZE(skl_tplg_kcontrol_ops), 347815ecaba9SKranthi G .manifest = skl_manifest_load, 3479606e21fdSGuneshwor Singh .dai_load = skl_dai_load, 34803af36706SVinod Koul }; 34813af36706SVinod Koul 3482287af4f9SJeeja KP /* 3483287af4f9SJeeja KP * A pipe can have multiple modules, each of them will be a DAPM widget as 3484287af4f9SJeeja KP * well. While managing a pipeline we need to get the list of all the 3485287af4f9SJeeja KP * widgets in a pipelines, so this helper - skl_tplg_create_pipe_widget_list() 3486287af4f9SJeeja KP * helps to get the SKL type widgets in that pipeline 3487287af4f9SJeeja KP */ 348856b03b4cSKuninori Morimoto static int skl_tplg_create_pipe_widget_list(struct snd_soc_component *component) 3489287af4f9SJeeja KP { 3490287af4f9SJeeja KP struct snd_soc_dapm_widget *w; 3491287af4f9SJeeja KP struct skl_module_cfg *mcfg = NULL; 3492287af4f9SJeeja KP struct skl_pipe_module *p_module = NULL; 3493287af4f9SJeeja KP struct skl_pipe *pipe; 3494287af4f9SJeeja KP 349556b03b4cSKuninori Morimoto list_for_each_entry(w, &component->card->widgets, list) { 3496a1f362d8SMark Brown if (is_skl_dsp_widget_type(w, component->dev) && w->priv) { 3497287af4f9SJeeja KP mcfg = w->priv; 3498287af4f9SJeeja KP pipe = mcfg->pipe; 3499287af4f9SJeeja KP 350056b03b4cSKuninori Morimoto p_module = devm_kzalloc(component->dev, 3501287af4f9SJeeja KP sizeof(*p_module), GFP_KERNEL); 3502287af4f9SJeeja KP if (!p_module) 3503287af4f9SJeeja KP return -ENOMEM; 3504287af4f9SJeeja KP 3505287af4f9SJeeja KP p_module->w = w; 3506287af4f9SJeeja KP list_add_tail(&p_module->node, &pipe->w_list); 3507287af4f9SJeeja KP } 3508287af4f9SJeeja KP } 3509287af4f9SJeeja KP 3510287af4f9SJeeja KP return 0; 3511287af4f9SJeeja KP } 3512287af4f9SJeeja KP 3513f0aa94faSJeeja KP static void skl_tplg_set_pipe_type(struct skl *skl, struct skl_pipe *pipe) 3514f0aa94faSJeeja KP { 3515f0aa94faSJeeja KP struct skl_pipe_module *w_module; 3516f0aa94faSJeeja KP struct snd_soc_dapm_widget *w; 3517f0aa94faSJeeja KP struct skl_module_cfg *mconfig; 3518f0aa94faSJeeja KP bool host_found = false, link_found = false; 3519f0aa94faSJeeja KP 3520f0aa94faSJeeja KP list_for_each_entry(w_module, &pipe->w_list, node) { 3521f0aa94faSJeeja KP w = w_module->w; 3522f0aa94faSJeeja KP mconfig = w->priv; 3523f0aa94faSJeeja KP 3524f0aa94faSJeeja KP if (mconfig->dev_type == SKL_DEVICE_HDAHOST) 3525f0aa94faSJeeja KP host_found = true; 3526f0aa94faSJeeja KP else if (mconfig->dev_type != SKL_DEVICE_NONE) 3527f0aa94faSJeeja KP link_found = true; 3528f0aa94faSJeeja KP } 3529f0aa94faSJeeja KP 3530f0aa94faSJeeja KP if (host_found && link_found) 3531f0aa94faSJeeja KP pipe->passthru = true; 3532f0aa94faSJeeja KP else 3533f0aa94faSJeeja KP pipe->passthru = false; 3534f0aa94faSJeeja KP } 3535f0aa94faSJeeja KP 35363af36706SVinod Koul /* This will be read from topology manifest, currently defined here */ 35373af36706SVinod Koul #define SKL_MAX_MCPS 30000000 35383af36706SVinod Koul #define SKL_FW_MAX_MEM 1000000 35393af36706SVinod Koul 35403af36706SVinod Koul /* 35413af36706SVinod Koul * SKL topology init routine 35423af36706SVinod Koul */ 354356b03b4cSKuninori Morimoto int skl_tplg_init(struct snd_soc_component *component, struct hdac_ext_bus *ebus) 35443af36706SVinod Koul { 35453af36706SVinod Koul int ret; 35463af36706SVinod Koul const struct firmware *fw; 35473af36706SVinod Koul struct hdac_bus *bus = ebus_to_hbus(ebus); 35483af36706SVinod Koul struct skl *skl = ebus_to_skl(ebus); 3549f0aa94faSJeeja KP struct skl_pipeline *ppl; 35503af36706SVinod Koul 35514b235c43SVinod Koul ret = request_firmware(&fw, skl->tplg_name, bus->dev); 35523af36706SVinod Koul if (ret < 0) { 355319de7179SChintan Patel dev_info(bus->dev, "tplg fw %s load failed with %d, falling back to dfw_sst.bin", 35544b235c43SVinod Koul skl->tplg_name, ret); 35554b235c43SVinod Koul ret = request_firmware(&fw, "dfw_sst.bin", bus->dev); 35564b235c43SVinod Koul if (ret < 0) { 35574b235c43SVinod Koul dev_err(bus->dev, "Fallback tplg fw %s load failed with %d\n", 35583af36706SVinod Koul "dfw_sst.bin", ret); 35593af36706SVinod Koul return ret; 35603af36706SVinod Koul } 35614b235c43SVinod Koul } 35623af36706SVinod Koul 35633af36706SVinod Koul /* 35643af36706SVinod Koul * The complete tplg for SKL is loaded as index 0, we don't use 35653af36706SVinod Koul * any other index 35663af36706SVinod Koul */ 356756b03b4cSKuninori Morimoto ret = snd_soc_tplg_component_load(component, 3568b663a8c5SJeeja KP &skl_tplg_ops, fw, 0); 35693af36706SVinod Koul if (ret < 0) { 35703af36706SVinod Koul dev_err(bus->dev, "tplg component load failed%d\n", ret); 3571c14a82c7SSudip Mukherjee release_firmware(fw); 35723af36706SVinod Koul return -EINVAL; 35733af36706SVinod Koul } 35743af36706SVinod Koul 35753af36706SVinod Koul skl->resource.max_mcps = SKL_MAX_MCPS; 35763af36706SVinod Koul skl->resource.max_mem = SKL_FW_MAX_MEM; 35773af36706SVinod Koul 3578d8018361SVinod Koul skl->tplg = fw; 357956b03b4cSKuninori Morimoto ret = skl_tplg_create_pipe_widget_list(component); 3580287af4f9SJeeja KP if (ret < 0) 3581287af4f9SJeeja KP return ret; 3582d8018361SVinod Koul 3583f0aa94faSJeeja KP list_for_each_entry(ppl, &skl->ppl_list, node) 3584f0aa94faSJeeja KP skl_tplg_set_pipe_type(skl, ppl->pipe); 35853af36706SVinod Koul 35863af36706SVinod Koul return 0; 3587e4e2d2f4SJeeja KP } 3588