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 39a83e3b4cSVinod Koul void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps) 40a83e3b4cSVinod Koul { 41a83e3b4cSVinod Koul struct skl_d0i3_data *d0i3 = &skl->skl_sst->d0i3; 42a83e3b4cSVinod Koul 43a83e3b4cSVinod Koul switch (caps) { 44a83e3b4cSVinod Koul case SKL_D0I3_NONE: 45a83e3b4cSVinod Koul d0i3->non_d0i3++; 46a83e3b4cSVinod Koul break; 47a83e3b4cSVinod Koul 48a83e3b4cSVinod Koul case SKL_D0I3_STREAMING: 49a83e3b4cSVinod Koul d0i3->streaming++; 50a83e3b4cSVinod Koul break; 51a83e3b4cSVinod Koul 52a83e3b4cSVinod Koul case SKL_D0I3_NON_STREAMING: 53a83e3b4cSVinod Koul d0i3->non_streaming++; 54a83e3b4cSVinod Koul break; 55a83e3b4cSVinod Koul } 56a83e3b4cSVinod Koul } 57a83e3b4cSVinod Koul 58a83e3b4cSVinod Koul void skl_tplg_d0i3_put(struct skl *skl, enum d0i3_capability caps) 59a83e3b4cSVinod Koul { 60a83e3b4cSVinod Koul struct skl_d0i3_data *d0i3 = &skl->skl_sst->d0i3; 61a83e3b4cSVinod Koul 62a83e3b4cSVinod Koul switch (caps) { 63a83e3b4cSVinod Koul case SKL_D0I3_NONE: 64a83e3b4cSVinod Koul d0i3->non_d0i3--; 65a83e3b4cSVinod Koul break; 66a83e3b4cSVinod Koul 67a83e3b4cSVinod Koul case SKL_D0I3_STREAMING: 68a83e3b4cSVinod Koul d0i3->streaming--; 69a83e3b4cSVinod Koul break; 70a83e3b4cSVinod Koul 71a83e3b4cSVinod Koul case SKL_D0I3_NON_STREAMING: 72a83e3b4cSVinod Koul d0i3->non_streaming--; 73a83e3b4cSVinod Koul break; 74a83e3b4cSVinod Koul } 75a83e3b4cSVinod Koul } 76a83e3b4cSVinod Koul 77e4e2d2f4SJeeja KP /* 78e4e2d2f4SJeeja KP * SKL DSP driver modelling uses only few DAPM widgets so for rest we will 79e4e2d2f4SJeeja KP * ignore. This helpers checks if the SKL driver handles this widget type 80e4e2d2f4SJeeja KP */ 81e4e2d2f4SJeeja KP static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w) 82e4e2d2f4SJeeja KP { 83e4e2d2f4SJeeja KP switch (w->id) { 84e4e2d2f4SJeeja KP case snd_soc_dapm_dai_link: 85e4e2d2f4SJeeja KP case snd_soc_dapm_dai_in: 86e4e2d2f4SJeeja KP case snd_soc_dapm_aif_in: 87e4e2d2f4SJeeja KP case snd_soc_dapm_aif_out: 88e4e2d2f4SJeeja KP case snd_soc_dapm_dai_out: 89e4e2d2f4SJeeja KP case snd_soc_dapm_switch: 90e4e2d2f4SJeeja KP return false; 91e4e2d2f4SJeeja KP default: 92e4e2d2f4SJeeja KP return true; 93e4e2d2f4SJeeja KP } 94e4e2d2f4SJeeja KP } 95e4e2d2f4SJeeja KP 96e4e2d2f4SJeeja KP /* 97e4e2d2f4SJeeja KP * Each pipelines needs memory to be allocated. Check if we have free memory 989ba8ffefSDharageswari.R * from available pool. 99e4e2d2f4SJeeja KP */ 1009ba8ffefSDharageswari.R static bool skl_is_pipe_mem_avail(struct skl *skl, 101e4e2d2f4SJeeja KP struct skl_module_cfg *mconfig) 102e4e2d2f4SJeeja KP { 103e4e2d2f4SJeeja KP struct skl_sst *ctx = skl->skl_sst; 104e4e2d2f4SJeeja KP 105e4e2d2f4SJeeja KP if (skl->resource.mem + mconfig->pipe->memory_pages > 106e4e2d2f4SJeeja KP skl->resource.max_mem) { 107e4e2d2f4SJeeja KP dev_err(ctx->dev, 108e4e2d2f4SJeeja KP "%s: module_id %d instance %d\n", __func__, 109e4e2d2f4SJeeja KP mconfig->id.module_id, 110e4e2d2f4SJeeja KP mconfig->id.instance_id); 111e4e2d2f4SJeeja KP dev_err(ctx->dev, 112e4e2d2f4SJeeja KP "exceeds ppl memory available %d mem %d\n", 113e4e2d2f4SJeeja KP skl->resource.max_mem, skl->resource.mem); 114e4e2d2f4SJeeja KP return false; 1159ba8ffefSDharageswari.R } else { 1169ba8ffefSDharageswari.R return true; 1179ba8ffefSDharageswari.R } 118e4e2d2f4SJeeja KP } 119e4e2d2f4SJeeja KP 1209ba8ffefSDharageswari.R /* 1219ba8ffefSDharageswari.R * Add the mem to the mem pool. This is freed when pipe is deleted. 1229ba8ffefSDharageswari.R * Note: DSP does actual memory management we only keep track for complete 1239ba8ffefSDharageswari.R * pool 1249ba8ffefSDharageswari.R */ 1259ba8ffefSDharageswari.R static void skl_tplg_alloc_pipe_mem(struct skl *skl, 1269ba8ffefSDharageswari.R struct skl_module_cfg *mconfig) 1279ba8ffefSDharageswari.R { 128e4e2d2f4SJeeja KP skl->resource.mem += mconfig->pipe->memory_pages; 129e4e2d2f4SJeeja KP } 130e4e2d2f4SJeeja KP 131e4e2d2f4SJeeja KP /* 132e4e2d2f4SJeeja KP * Pipeline needs needs DSP CPU resources for computation, this is 133e4e2d2f4SJeeja KP * quantified in MCPS (Million Clocks Per Second) required for module/pipe 134e4e2d2f4SJeeja KP * 135e4e2d2f4SJeeja KP * Each pipelines needs mcps to be allocated. Check if we have mcps for this 1369ba8ffefSDharageswari.R * pipe. 137e4e2d2f4SJeeja KP */ 1389ba8ffefSDharageswari.R 1399ba8ffefSDharageswari.R static bool skl_is_pipe_mcps_avail(struct skl *skl, 140e4e2d2f4SJeeja KP struct skl_module_cfg *mconfig) 141e4e2d2f4SJeeja KP { 142e4e2d2f4SJeeja KP struct skl_sst *ctx = skl->skl_sst; 143e4e2d2f4SJeeja KP 144e4e2d2f4SJeeja KP if (skl->resource.mcps + mconfig->mcps > skl->resource.max_mcps) { 145e4e2d2f4SJeeja KP dev_err(ctx->dev, 146e4e2d2f4SJeeja KP "%s: module_id %d instance %d\n", __func__, 147e4e2d2f4SJeeja KP mconfig->id.module_id, mconfig->id.instance_id); 148e4e2d2f4SJeeja KP dev_err(ctx->dev, 1497ca42f5aSGuneshwor Singh "exceeds ppl mcps available %d > mem %d\n", 150e4e2d2f4SJeeja KP skl->resource.max_mcps, skl->resource.mcps); 151e4e2d2f4SJeeja KP return false; 1529ba8ffefSDharageswari.R } else { 1539ba8ffefSDharageswari.R return true; 1549ba8ffefSDharageswari.R } 155e4e2d2f4SJeeja KP } 156e4e2d2f4SJeeja KP 1579ba8ffefSDharageswari.R static void skl_tplg_alloc_pipe_mcps(struct skl *skl, 1589ba8ffefSDharageswari.R struct skl_module_cfg *mconfig) 1599ba8ffefSDharageswari.R { 160e4e2d2f4SJeeja KP skl->resource.mcps += mconfig->mcps; 161e4e2d2f4SJeeja KP } 162e4e2d2f4SJeeja KP 163e4e2d2f4SJeeja KP /* 164e4e2d2f4SJeeja KP * Free the mcps when tearing down 165e4e2d2f4SJeeja KP */ 166e4e2d2f4SJeeja KP static void 167e4e2d2f4SJeeja KP skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig) 168e4e2d2f4SJeeja KP { 169e4e2d2f4SJeeja KP skl->resource.mcps -= mconfig->mcps; 170e4e2d2f4SJeeja KP } 171e4e2d2f4SJeeja KP 172e4e2d2f4SJeeja KP /* 173e4e2d2f4SJeeja KP * Free the memory when tearing down 174e4e2d2f4SJeeja KP */ 175e4e2d2f4SJeeja KP static void 176e4e2d2f4SJeeja KP skl_tplg_free_pipe_mem(struct skl *skl, struct skl_module_cfg *mconfig) 177e4e2d2f4SJeeja KP { 178e4e2d2f4SJeeja KP skl->resource.mem -= mconfig->pipe->memory_pages; 179e4e2d2f4SJeeja KP } 180e4e2d2f4SJeeja KP 181f7590d4fSJeeja KP 182f7590d4fSJeeja KP static void skl_dump_mconfig(struct skl_sst *ctx, 183f7590d4fSJeeja KP struct skl_module_cfg *mcfg) 184f7590d4fSJeeja KP { 185f7590d4fSJeeja KP dev_dbg(ctx->dev, "Dumping config\n"); 186f7590d4fSJeeja KP dev_dbg(ctx->dev, "Input Format:\n"); 1874cd9899fSHardik T Shah dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt[0].channels); 1884cd9899fSHardik T Shah dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->in_fmt[0].s_freq); 1894cd9899fSHardik T Shah dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->in_fmt[0].ch_cfg); 1904cd9899fSHardik T Shah dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->in_fmt[0].valid_bit_depth); 191f7590d4fSJeeja KP dev_dbg(ctx->dev, "Output Format:\n"); 1924cd9899fSHardik T Shah dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt[0].channels); 1934cd9899fSHardik T Shah dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->out_fmt[0].s_freq); 1944cd9899fSHardik T Shah dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->out_fmt[0].valid_bit_depth); 1954cd9899fSHardik T Shah dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt[0].ch_cfg); 196f7590d4fSJeeja KP } 197f7590d4fSJeeja KP 198ea5a137dSSubhransu S. Prusty static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs) 199ea5a137dSSubhransu S. Prusty { 200ea5a137dSSubhransu S. Prusty int slot_map = 0xFFFFFFFF; 201ea5a137dSSubhransu S. Prusty int start_slot = 0; 202ea5a137dSSubhransu S. Prusty int i; 203ea5a137dSSubhransu S. Prusty 204ea5a137dSSubhransu S. Prusty for (i = 0; i < chs; i++) { 205ea5a137dSSubhransu S. Prusty /* 206ea5a137dSSubhransu S. Prusty * For 2 channels with starting slot as 0, slot map will 207ea5a137dSSubhransu S. Prusty * look like 0xFFFFFF10. 208ea5a137dSSubhransu S. Prusty */ 209ea5a137dSSubhransu S. Prusty slot_map &= (~(0xF << (4 * i)) | (start_slot << (4 * i))); 210ea5a137dSSubhransu S. Prusty start_slot++; 211ea5a137dSSubhransu S. Prusty } 212ea5a137dSSubhransu S. Prusty fmt->ch_map = slot_map; 213ea5a137dSSubhransu S. Prusty } 214ea5a137dSSubhransu S. Prusty 215f7590d4fSJeeja KP static void skl_tplg_update_params(struct skl_module_fmt *fmt, 216f7590d4fSJeeja KP struct skl_pipe_params *params, int fixup) 217f7590d4fSJeeja KP { 218f7590d4fSJeeja KP if (fixup & SKL_RATE_FIXUP_MASK) 219f7590d4fSJeeja KP fmt->s_freq = params->s_freq; 220ea5a137dSSubhransu S. Prusty if (fixup & SKL_CH_FIXUP_MASK) { 221f7590d4fSJeeja KP fmt->channels = params->ch; 222ea5a137dSSubhransu S. Prusty skl_tplg_update_chmap(fmt, fmt->channels); 223ea5a137dSSubhransu S. Prusty } 22498256f83SJeeja KP if (fixup & SKL_FMT_FIXUP_MASK) { 22598256f83SJeeja KP fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt); 22698256f83SJeeja KP 22798256f83SJeeja KP /* 22898256f83SJeeja KP * 16 bit is 16 bit container whereas 24 bit is in 32 bit 22998256f83SJeeja KP * container so update bit depth accordingly 23098256f83SJeeja KP */ 23198256f83SJeeja KP switch (fmt->valid_bit_depth) { 23298256f83SJeeja KP case SKL_DEPTH_16BIT: 23398256f83SJeeja KP fmt->bit_depth = fmt->valid_bit_depth; 23498256f83SJeeja KP break; 23598256f83SJeeja KP 23698256f83SJeeja KP default: 23798256f83SJeeja KP fmt->bit_depth = SKL_DEPTH_32BIT; 23898256f83SJeeja KP break; 23998256f83SJeeja KP } 24098256f83SJeeja KP } 24198256f83SJeeja KP 242f7590d4fSJeeja KP } 243f7590d4fSJeeja KP 244f7590d4fSJeeja KP /* 245f7590d4fSJeeja KP * A pipeline may have modules which impact the pcm parameters, like SRC, 246f7590d4fSJeeja KP * channel converter, format converter. 247f7590d4fSJeeja KP * We need to calculate the output params by applying the 'fixup' 248f7590d4fSJeeja KP * Topology will tell driver which type of fixup is to be applied by 249f7590d4fSJeeja KP * supplying the fixup mask, so based on that we calculate the output 250f7590d4fSJeeja KP * 251f7590d4fSJeeja KP * Now In FE the pcm hw_params is source/target format. Same is applicable 252f7590d4fSJeeja KP * for BE with its hw_params invoked. 253f7590d4fSJeeja KP * here based on FE, BE pipeline and direction we calculate the input and 254f7590d4fSJeeja KP * outfix and then apply that for a module 255f7590d4fSJeeja KP */ 256f7590d4fSJeeja KP static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg, 257f7590d4fSJeeja KP struct skl_pipe_params *params, bool is_fe) 258f7590d4fSJeeja KP { 259f7590d4fSJeeja KP int in_fixup, out_fixup; 260f7590d4fSJeeja KP struct skl_module_fmt *in_fmt, *out_fmt; 261f7590d4fSJeeja KP 2624cd9899fSHardik T Shah /* Fixups will be applied to pin 0 only */ 2634cd9899fSHardik T Shah in_fmt = &m_cfg->in_fmt[0]; 2644cd9899fSHardik T Shah out_fmt = &m_cfg->out_fmt[0]; 265f7590d4fSJeeja KP 266f7590d4fSJeeja KP if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { 267f7590d4fSJeeja KP if (is_fe) { 268f7590d4fSJeeja KP in_fixup = m_cfg->params_fixup; 269f7590d4fSJeeja KP out_fixup = (~m_cfg->converter) & 270f7590d4fSJeeja KP m_cfg->params_fixup; 271f7590d4fSJeeja KP } else { 272f7590d4fSJeeja KP out_fixup = m_cfg->params_fixup; 273f7590d4fSJeeja KP in_fixup = (~m_cfg->converter) & 274f7590d4fSJeeja KP m_cfg->params_fixup; 275f7590d4fSJeeja KP } 276f7590d4fSJeeja KP } else { 277f7590d4fSJeeja KP if (is_fe) { 278f7590d4fSJeeja KP out_fixup = m_cfg->params_fixup; 279f7590d4fSJeeja KP in_fixup = (~m_cfg->converter) & 280f7590d4fSJeeja KP m_cfg->params_fixup; 281f7590d4fSJeeja KP } else { 282f7590d4fSJeeja KP in_fixup = m_cfg->params_fixup; 283f7590d4fSJeeja KP out_fixup = (~m_cfg->converter) & 284f7590d4fSJeeja KP m_cfg->params_fixup; 285f7590d4fSJeeja KP } 286f7590d4fSJeeja KP } 287f7590d4fSJeeja KP 288f7590d4fSJeeja KP skl_tplg_update_params(in_fmt, params, in_fixup); 289f7590d4fSJeeja KP skl_tplg_update_params(out_fmt, params, out_fixup); 290f7590d4fSJeeja KP } 291f7590d4fSJeeja KP 292f7590d4fSJeeja KP /* 293f7590d4fSJeeja KP * A module needs input and output buffers, which are dependent upon pcm 294f7590d4fSJeeja KP * params, so once we have calculate params, we need buffer calculation as 295f7590d4fSJeeja KP * well. 296f7590d4fSJeeja KP */ 297f7590d4fSJeeja KP static void skl_tplg_update_buffer_size(struct skl_sst *ctx, 298f7590d4fSJeeja KP struct skl_module_cfg *mcfg) 299f7590d4fSJeeja KP { 300f7590d4fSJeeja KP int multiplier = 1; 3014cd9899fSHardik T Shah struct skl_module_fmt *in_fmt, *out_fmt; 302f0c8e1d9SSubhransu S. Prusty int in_rate, out_rate; 3034cd9899fSHardik T Shah 3044cd9899fSHardik T Shah 3054cd9899fSHardik T Shah /* Since fixups is applied to pin 0 only, ibs, obs needs 3064cd9899fSHardik T Shah * change for pin 0 only 3074cd9899fSHardik T Shah */ 3084cd9899fSHardik T Shah in_fmt = &mcfg->in_fmt[0]; 3094cd9899fSHardik T Shah out_fmt = &mcfg->out_fmt[0]; 310f7590d4fSJeeja KP 311f7590d4fSJeeja KP if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT) 312f7590d4fSJeeja KP multiplier = 5; 313f0c8e1d9SSubhransu S. Prusty 314f0c8e1d9SSubhransu S. Prusty if (in_fmt->s_freq % 1000) 315f0c8e1d9SSubhransu S. Prusty in_rate = (in_fmt->s_freq / 1000) + 1; 316f0c8e1d9SSubhransu S. Prusty else 317f0c8e1d9SSubhransu S. Prusty in_rate = (in_fmt->s_freq / 1000); 318f0c8e1d9SSubhransu S. Prusty 319f0c8e1d9SSubhransu S. Prusty mcfg->ibs = in_rate * (mcfg->in_fmt->channels) * 3204cd9899fSHardik T Shah (mcfg->in_fmt->bit_depth >> 3) * 321f7590d4fSJeeja KP multiplier; 322f7590d4fSJeeja KP 323f0c8e1d9SSubhransu S. Prusty if (mcfg->out_fmt->s_freq % 1000) 324f0c8e1d9SSubhransu S. Prusty out_rate = (mcfg->out_fmt->s_freq / 1000) + 1; 325f0c8e1d9SSubhransu S. Prusty else 326f0c8e1d9SSubhransu S. Prusty out_rate = (mcfg->out_fmt->s_freq / 1000); 327f0c8e1d9SSubhransu S. Prusty 328f0c8e1d9SSubhransu S. Prusty mcfg->obs = out_rate * (mcfg->out_fmt->channels) * 3294cd9899fSHardik T Shah (mcfg->out_fmt->bit_depth >> 3) * 330f7590d4fSJeeja KP multiplier; 331f7590d4fSJeeja KP } 332f7590d4fSJeeja KP 3332d1419a3SJeeja KP static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, 3342d1419a3SJeeja KP struct skl_sst *ctx) 3352d1419a3SJeeja KP { 3362d1419a3SJeeja KP struct skl_module_cfg *m_cfg = w->priv; 3372d1419a3SJeeja KP int link_type, dir; 3382d1419a3SJeeja KP u32 ch, s_freq, s_fmt; 3392d1419a3SJeeja KP struct nhlt_specific_cfg *cfg; 3402d1419a3SJeeja KP struct skl *skl = get_skl_ctx(ctx->dev); 3412d1419a3SJeeja KP 3422d1419a3SJeeja KP /* check if we already have blob */ 3432d1419a3SJeeja KP if (m_cfg->formats_config.caps_size > 0) 3442d1419a3SJeeja KP return 0; 3452d1419a3SJeeja KP 346c7c6c736SJeeja KP dev_dbg(ctx->dev, "Applying default cfg blob\n"); 3472d1419a3SJeeja KP switch (m_cfg->dev_type) { 3482d1419a3SJeeja KP case SKL_DEVICE_DMIC: 3492d1419a3SJeeja KP link_type = NHLT_LINK_DMIC; 350c7c6c736SJeeja KP dir = SNDRV_PCM_STREAM_CAPTURE; 3512d1419a3SJeeja KP s_freq = m_cfg->in_fmt[0].s_freq; 3522d1419a3SJeeja KP s_fmt = m_cfg->in_fmt[0].bit_depth; 3532d1419a3SJeeja KP ch = m_cfg->in_fmt[0].channels; 3542d1419a3SJeeja KP break; 3552d1419a3SJeeja KP 3562d1419a3SJeeja KP case SKL_DEVICE_I2S: 3572d1419a3SJeeja KP link_type = NHLT_LINK_SSP; 3582d1419a3SJeeja KP if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) { 359c7c6c736SJeeja KP dir = SNDRV_PCM_STREAM_PLAYBACK; 3602d1419a3SJeeja KP s_freq = m_cfg->out_fmt[0].s_freq; 3612d1419a3SJeeja KP s_fmt = m_cfg->out_fmt[0].bit_depth; 3622d1419a3SJeeja KP ch = m_cfg->out_fmt[0].channels; 363c7c6c736SJeeja KP } else { 364c7c6c736SJeeja KP dir = SNDRV_PCM_STREAM_CAPTURE; 365c7c6c736SJeeja KP s_freq = m_cfg->in_fmt[0].s_freq; 366c7c6c736SJeeja KP s_fmt = m_cfg->in_fmt[0].bit_depth; 367c7c6c736SJeeja KP ch = m_cfg->in_fmt[0].channels; 3682d1419a3SJeeja KP } 3692d1419a3SJeeja KP break; 3702d1419a3SJeeja KP 3712d1419a3SJeeja KP default: 3722d1419a3SJeeja KP return -EINVAL; 3732d1419a3SJeeja KP } 3742d1419a3SJeeja KP 3752d1419a3SJeeja KP /* update the blob based on virtual bus_id and default params */ 3762d1419a3SJeeja KP cfg = skl_get_ep_blob(skl, m_cfg->vbus_id, link_type, 3772d1419a3SJeeja KP s_fmt, ch, s_freq, dir); 3782d1419a3SJeeja KP if (cfg) { 3792d1419a3SJeeja KP m_cfg->formats_config.caps_size = cfg->size; 3802d1419a3SJeeja KP m_cfg->formats_config.caps = (u32 *) &cfg->caps; 3812d1419a3SJeeja KP } else { 3822d1419a3SJeeja KP dev_err(ctx->dev, "Blob NULL for id %x type %d dirn %d\n", 3832d1419a3SJeeja KP m_cfg->vbus_id, link_type, dir); 3842d1419a3SJeeja KP dev_err(ctx->dev, "PCM: ch %d, freq %d, fmt %d\n", 3852d1419a3SJeeja KP ch, s_freq, s_fmt); 3862d1419a3SJeeja KP return -EIO; 3872d1419a3SJeeja KP } 3882d1419a3SJeeja KP 3892d1419a3SJeeja KP return 0; 3902d1419a3SJeeja KP } 3912d1419a3SJeeja KP 392f7590d4fSJeeja KP static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w, 393f7590d4fSJeeja KP struct skl_sst *ctx) 394f7590d4fSJeeja KP { 395f7590d4fSJeeja KP struct skl_module_cfg *m_cfg = w->priv; 396f7590d4fSJeeja KP struct skl_pipe_params *params = m_cfg->pipe->p_params; 397f7590d4fSJeeja KP int p_conn_type = m_cfg->pipe->conn_type; 398f7590d4fSJeeja KP bool is_fe; 399f7590d4fSJeeja KP 400f7590d4fSJeeja KP if (!m_cfg->params_fixup) 401f7590d4fSJeeja KP return; 402f7590d4fSJeeja KP 403f7590d4fSJeeja KP dev_dbg(ctx->dev, "Mconfig for widget=%s BEFORE updation\n", 404f7590d4fSJeeja KP w->name); 405f7590d4fSJeeja KP 406f7590d4fSJeeja KP skl_dump_mconfig(ctx, m_cfg); 407f7590d4fSJeeja KP 408f7590d4fSJeeja KP if (p_conn_type == SKL_PIPE_CONN_TYPE_FE) 409f7590d4fSJeeja KP is_fe = true; 410f7590d4fSJeeja KP else 411f7590d4fSJeeja KP is_fe = false; 412f7590d4fSJeeja KP 413f7590d4fSJeeja KP skl_tplg_update_params_fixup(m_cfg, params, is_fe); 414f7590d4fSJeeja KP skl_tplg_update_buffer_size(ctx, m_cfg); 415f7590d4fSJeeja KP 416f7590d4fSJeeja KP dev_dbg(ctx->dev, "Mconfig for widget=%s AFTER updation\n", 417f7590d4fSJeeja KP w->name); 418f7590d4fSJeeja KP 419f7590d4fSJeeja KP skl_dump_mconfig(ctx, m_cfg); 420f7590d4fSJeeja KP } 421f7590d4fSJeeja KP 422e4e2d2f4SJeeja KP /* 423abb74003SJeeja KP * some modules can have multiple params set from user control and 424abb74003SJeeja KP * need to be set after module is initialized. If set_param flag is 425abb74003SJeeja KP * set module params will be done after module is initialised. 426abb74003SJeeja KP */ 427abb74003SJeeja KP static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w, 428abb74003SJeeja KP struct skl_sst *ctx) 429abb74003SJeeja KP { 430abb74003SJeeja KP int i, ret; 431abb74003SJeeja KP struct skl_module_cfg *mconfig = w->priv; 432abb74003SJeeja KP const struct snd_kcontrol_new *k; 433abb74003SJeeja KP struct soc_bytes_ext *sb; 434abb74003SJeeja KP struct skl_algo_data *bc; 435abb74003SJeeja KP struct skl_specific_cfg *sp_cfg; 436abb74003SJeeja KP 437abb74003SJeeja KP if (mconfig->formats_config.caps_size > 0 && 4384ced1827SJeeja KP mconfig->formats_config.set_params == SKL_PARAM_SET) { 439abb74003SJeeja KP sp_cfg = &mconfig->formats_config; 440abb74003SJeeja KP ret = skl_set_module_params(ctx, sp_cfg->caps, 441abb74003SJeeja KP sp_cfg->caps_size, 442abb74003SJeeja KP sp_cfg->param_id, mconfig); 443abb74003SJeeja KP if (ret < 0) 444abb74003SJeeja KP return ret; 445abb74003SJeeja KP } 446abb74003SJeeja KP 447abb74003SJeeja KP for (i = 0; i < w->num_kcontrols; i++) { 448abb74003SJeeja KP k = &w->kcontrol_news[i]; 449abb74003SJeeja KP if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 450abb74003SJeeja KP sb = (void *) k->private_value; 451abb74003SJeeja KP bc = (struct skl_algo_data *)sb->dobj.private; 452abb74003SJeeja KP 4534ced1827SJeeja KP if (bc->set_params == SKL_PARAM_SET) { 454abb74003SJeeja KP ret = skl_set_module_params(ctx, 4550d682104SDharageswari R (u32 *)bc->params, bc->size, 456abb74003SJeeja KP bc->param_id, mconfig); 457abb74003SJeeja KP if (ret < 0) 458abb74003SJeeja KP return ret; 459abb74003SJeeja KP } 460abb74003SJeeja KP } 461abb74003SJeeja KP } 462abb74003SJeeja KP 463abb74003SJeeja KP return 0; 464abb74003SJeeja KP } 465abb74003SJeeja KP 466abb74003SJeeja KP /* 467abb74003SJeeja KP * some module param can set from user control and this is required as 468abb74003SJeeja KP * when module is initailzed. if module param is required in init it is 469abb74003SJeeja KP * identifed by set_param flag. if set_param flag is not set, then this 470abb74003SJeeja KP * parameter needs to set as part of module init. 471abb74003SJeeja KP */ 472abb74003SJeeja KP static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w) 473abb74003SJeeja KP { 474abb74003SJeeja KP const struct snd_kcontrol_new *k; 475abb74003SJeeja KP struct soc_bytes_ext *sb; 476abb74003SJeeja KP struct skl_algo_data *bc; 477abb74003SJeeja KP struct skl_module_cfg *mconfig = w->priv; 478abb74003SJeeja KP int i; 479abb74003SJeeja KP 480abb74003SJeeja KP for (i = 0; i < w->num_kcontrols; i++) { 481abb74003SJeeja KP k = &w->kcontrol_news[i]; 482abb74003SJeeja KP if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 483abb74003SJeeja KP sb = (struct soc_bytes_ext *)k->private_value; 484abb74003SJeeja KP bc = (struct skl_algo_data *)sb->dobj.private; 485abb74003SJeeja KP 4864ced1827SJeeja KP if (bc->set_params != SKL_PARAM_INIT) 487abb74003SJeeja KP continue; 488abb74003SJeeja KP 489abb74003SJeeja KP mconfig->formats_config.caps = (u32 *)&bc->params; 4900d682104SDharageswari R mconfig->formats_config.caps_size = bc->size; 491abb74003SJeeja KP 492abb74003SJeeja KP break; 493abb74003SJeeja KP } 494abb74003SJeeja KP } 495abb74003SJeeja KP 496abb74003SJeeja KP return 0; 497abb74003SJeeja KP } 498abb74003SJeeja KP 499abb74003SJeeja KP /* 500e4e2d2f4SJeeja KP * Inside a pipe instance, we can have various modules. These modules need 501e4e2d2f4SJeeja KP * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by 502e4e2d2f4SJeeja KP * skl_init_module() routine, so invoke that for all modules in a pipeline 503e4e2d2f4SJeeja KP */ 504e4e2d2f4SJeeja KP static int 505e4e2d2f4SJeeja KP skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) 506e4e2d2f4SJeeja KP { 507e4e2d2f4SJeeja KP struct skl_pipe_module *w_module; 508e4e2d2f4SJeeja KP struct snd_soc_dapm_widget *w; 509e4e2d2f4SJeeja KP struct skl_module_cfg *mconfig; 510e4e2d2f4SJeeja KP struct skl_sst *ctx = skl->skl_sst; 511e4e2d2f4SJeeja KP int ret = 0; 512e4e2d2f4SJeeja KP 513e4e2d2f4SJeeja KP list_for_each_entry(w_module, &pipe->w_list, node) { 514e4e2d2f4SJeeja KP w = w_module->w; 515e4e2d2f4SJeeja KP mconfig = w->priv; 516e4e2d2f4SJeeja KP 517b7c50555SVinod Koul /* check if module ids are populated */ 518b7c50555SVinod Koul if (mconfig->id.module_id < 0) { 519b7c50555SVinod Koul dev_err(skl->skl_sst->dev, 520a657ae7eSVinod Koul "module %pUL id not populated\n", 521a657ae7eSVinod Koul (uuid_le *)mconfig->guid); 522a657ae7eSVinod Koul return -EIO; 523b7c50555SVinod Koul } 524b7c50555SVinod Koul 525e4e2d2f4SJeeja KP /* check resource available */ 5269ba8ffefSDharageswari.R if (!skl_is_pipe_mcps_avail(skl, mconfig)) 527e4e2d2f4SJeeja KP return -ENOMEM; 528e4e2d2f4SJeeja KP 5296c5768b3SDharageswari R if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) { 5306c5768b3SDharageswari R ret = ctx->dsp->fw_ops.load_mod(ctx->dsp, 5316c5768b3SDharageswari R mconfig->id.module_id, mconfig->guid); 5326c5768b3SDharageswari R if (ret < 0) 5336c5768b3SDharageswari R return ret; 534d643678bSJeeja KP 535d643678bSJeeja KP mconfig->m_state = SKL_MODULE_LOADED; 5366c5768b3SDharageswari R } 5376c5768b3SDharageswari R 5382d1419a3SJeeja KP /* update blob if blob is null for be with default value */ 5392d1419a3SJeeja KP skl_tplg_update_be_blob(w, ctx); 5402d1419a3SJeeja KP 541f7590d4fSJeeja KP /* 542f7590d4fSJeeja KP * apply fix/conversion to module params based on 543f7590d4fSJeeja KP * FE/BE params 544f7590d4fSJeeja KP */ 545f7590d4fSJeeja KP skl_tplg_update_module_params(w, ctx); 546ef2a352cSDharageswari R mconfig->id.pvt_id = skl_get_pvt_id(ctx, mconfig); 547ef2a352cSDharageswari R if (mconfig->id.pvt_id < 0) 548ef2a352cSDharageswari R return ret; 549abb74003SJeeja KP skl_tplg_set_module_init_data(w); 5509939a9c3SJeeja KP ret = skl_init_module(ctx, mconfig); 551ef2a352cSDharageswari R if (ret < 0) { 552ef2a352cSDharageswari R skl_put_pvt_id(ctx, mconfig); 553e4e2d2f4SJeeja KP return ret; 554ef2a352cSDharageswari R } 555260eb73aSDharageswari R skl_tplg_alloc_pipe_mcps(skl, mconfig); 556abb74003SJeeja KP ret = skl_tplg_set_module_params(w, ctx); 557e4e2d2f4SJeeja KP if (ret < 0) 558e4e2d2f4SJeeja KP return ret; 559e4e2d2f4SJeeja KP } 560e4e2d2f4SJeeja KP 561e4e2d2f4SJeeja KP return 0; 562e4e2d2f4SJeeja KP } 563d93f8e55SVinod Koul 5646c5768b3SDharageswari R static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx, 5656c5768b3SDharageswari R struct skl_pipe *pipe) 5666c5768b3SDharageswari R { 567b0fab9c6SDharageswari R int ret; 5686c5768b3SDharageswari R struct skl_pipe_module *w_module = NULL; 5696c5768b3SDharageswari R struct skl_module_cfg *mconfig = NULL; 5706c5768b3SDharageswari R 5716c5768b3SDharageswari R list_for_each_entry(w_module, &pipe->w_list, node) { 5726c5768b3SDharageswari R mconfig = w_module->w->priv; 5736c5768b3SDharageswari R 574d643678bSJeeja KP if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod && 575b0fab9c6SDharageswari R mconfig->m_state > SKL_MODULE_UNINIT) { 576b0fab9c6SDharageswari R ret = ctx->dsp->fw_ops.unload_mod(ctx->dsp, 5776c5768b3SDharageswari R mconfig->id.module_id); 578b0fab9c6SDharageswari R if (ret < 0) 579b0fab9c6SDharageswari R return -EIO; 580b0fab9c6SDharageswari R } 581ef2a352cSDharageswari R skl_put_pvt_id(ctx, mconfig); 5826c5768b3SDharageswari R } 5836c5768b3SDharageswari R 5846c5768b3SDharageswari R /* no modules to unload in this path, so return */ 5856c5768b3SDharageswari R return 0; 5866c5768b3SDharageswari R } 5876c5768b3SDharageswari R 588d93f8e55SVinod Koul /* 589d93f8e55SVinod Koul * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we 590d93f8e55SVinod Koul * need create the pipeline. So we do following: 591d93f8e55SVinod Koul * - check the resources 592d93f8e55SVinod Koul * - Create the pipeline 593d93f8e55SVinod Koul * - Initialize the modules in pipeline 594d93f8e55SVinod Koul * - finally bind all modules together 595d93f8e55SVinod Koul */ 596d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, 597d93f8e55SVinod Koul struct skl *skl) 598d93f8e55SVinod Koul { 599d93f8e55SVinod Koul int ret; 600d93f8e55SVinod Koul struct skl_module_cfg *mconfig = w->priv; 601d93f8e55SVinod Koul struct skl_pipe_module *w_module; 602d93f8e55SVinod Koul struct skl_pipe *s_pipe = mconfig->pipe; 603d93f8e55SVinod Koul struct skl_module_cfg *src_module = NULL, *dst_module; 604d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 605d93f8e55SVinod Koul 606d93f8e55SVinod Koul /* check resource available */ 6079ba8ffefSDharageswari.R if (!skl_is_pipe_mcps_avail(skl, mconfig)) 608d93f8e55SVinod Koul return -EBUSY; 609d93f8e55SVinod Koul 6109ba8ffefSDharageswari.R if (!skl_is_pipe_mem_avail(skl, mconfig)) 611d93f8e55SVinod Koul return -ENOMEM; 612d93f8e55SVinod Koul 613d93f8e55SVinod Koul /* 614d93f8e55SVinod Koul * Create a list of modules for pipe. 615d93f8e55SVinod Koul * This list contains modules from source to sink 616d93f8e55SVinod Koul */ 617d93f8e55SVinod Koul ret = skl_create_pipeline(ctx, mconfig->pipe); 618d93f8e55SVinod Koul if (ret < 0) 619d93f8e55SVinod Koul return ret; 620d93f8e55SVinod Koul 621260eb73aSDharageswari R skl_tplg_alloc_pipe_mem(skl, mconfig); 622260eb73aSDharageswari R skl_tplg_alloc_pipe_mcps(skl, mconfig); 623d93f8e55SVinod Koul 624d93f8e55SVinod Koul /* Init all pipe modules from source to sink */ 625d93f8e55SVinod Koul ret = skl_tplg_init_pipe_modules(skl, s_pipe); 626d93f8e55SVinod Koul if (ret < 0) 627d93f8e55SVinod Koul return ret; 628d93f8e55SVinod Koul 629d93f8e55SVinod Koul /* Bind modules from source to sink */ 630d93f8e55SVinod Koul list_for_each_entry(w_module, &s_pipe->w_list, node) { 631d93f8e55SVinod Koul dst_module = w_module->w->priv; 632d93f8e55SVinod Koul 633d93f8e55SVinod Koul if (src_module == NULL) { 634d93f8e55SVinod Koul src_module = dst_module; 635d93f8e55SVinod Koul continue; 636d93f8e55SVinod Koul } 637d93f8e55SVinod Koul 638d93f8e55SVinod Koul ret = skl_bind_modules(ctx, src_module, dst_module); 639d93f8e55SVinod Koul if (ret < 0) 640d93f8e55SVinod Koul return ret; 641d93f8e55SVinod Koul 642d93f8e55SVinod Koul src_module = dst_module; 643d93f8e55SVinod Koul } 644d93f8e55SVinod Koul 645d93f8e55SVinod Koul return 0; 646d93f8e55SVinod Koul } 647d93f8e55SVinod Koul 6485e8f0ee4SDharageswari R static int skl_fill_sink_instance_id(struct skl_sst *ctx, 6495e8f0ee4SDharageswari R struct skl_algo_data *alg_data) 6505e8f0ee4SDharageswari R { 6515e8f0ee4SDharageswari R struct skl_kpb_params *params = (struct skl_kpb_params *)alg_data->params; 6525e8f0ee4SDharageswari R struct skl_mod_inst_map *inst; 6535e8f0ee4SDharageswari R int i, pvt_id; 6545e8f0ee4SDharageswari R 6555e8f0ee4SDharageswari R inst = params->map; 6565e8f0ee4SDharageswari R 6575e8f0ee4SDharageswari R for (i = 0; i < params->num_modules; i++) { 6585e8f0ee4SDharageswari R pvt_id = skl_get_pvt_instance_id_map(ctx, 6595e8f0ee4SDharageswari R inst->mod_id, inst->inst_id); 6605e8f0ee4SDharageswari R if (pvt_id < 0) 6615e8f0ee4SDharageswari R return -EINVAL; 6625e8f0ee4SDharageswari R inst->inst_id = pvt_id; 6635e8f0ee4SDharageswari R inst++; 6645e8f0ee4SDharageswari R } 6655e8f0ee4SDharageswari R return 0; 6665e8f0ee4SDharageswari R } 6675e8f0ee4SDharageswari R 668cc6a4044SJeeja KP /* 669cc6a4044SJeeja KP * Some modules require params to be set after the module is bound to 670cc6a4044SJeeja KP * all pins connected. 671cc6a4044SJeeja KP * 672cc6a4044SJeeja KP * The module provider initializes set_param flag for such modules and we 673cc6a4044SJeeja KP * send params after binding 674cc6a4044SJeeja KP */ 675cc6a4044SJeeja KP static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, 676cc6a4044SJeeja KP struct skl_module_cfg *mcfg, struct skl_sst *ctx) 677cc6a4044SJeeja KP { 678cc6a4044SJeeja KP int i, ret; 679cc6a4044SJeeja KP struct skl_module_cfg *mconfig = w->priv; 680cc6a4044SJeeja KP const struct snd_kcontrol_new *k; 681cc6a4044SJeeja KP struct soc_bytes_ext *sb; 682cc6a4044SJeeja KP struct skl_algo_data *bc; 683cc6a4044SJeeja KP struct skl_specific_cfg *sp_cfg; 684cc6a4044SJeeja KP 685cc6a4044SJeeja KP /* 686cc6a4044SJeeja KP * check all out/in pins are in bind state. 687cc6a4044SJeeja KP * if so set the module param 688cc6a4044SJeeja KP */ 689cc6a4044SJeeja KP for (i = 0; i < mcfg->max_out_queue; i++) { 690cc6a4044SJeeja KP if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE) 691cc6a4044SJeeja KP return 0; 692cc6a4044SJeeja KP } 693cc6a4044SJeeja KP 694cc6a4044SJeeja KP for (i = 0; i < mcfg->max_in_queue; i++) { 695cc6a4044SJeeja KP if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE) 696cc6a4044SJeeja KP return 0; 697cc6a4044SJeeja KP } 698cc6a4044SJeeja KP 699cc6a4044SJeeja KP if (mconfig->formats_config.caps_size > 0 && 700cc6a4044SJeeja KP mconfig->formats_config.set_params == SKL_PARAM_BIND) { 701cc6a4044SJeeja KP sp_cfg = &mconfig->formats_config; 702cc6a4044SJeeja KP ret = skl_set_module_params(ctx, sp_cfg->caps, 703cc6a4044SJeeja KP sp_cfg->caps_size, 704cc6a4044SJeeja KP sp_cfg->param_id, mconfig); 705cc6a4044SJeeja KP if (ret < 0) 706cc6a4044SJeeja KP return ret; 707cc6a4044SJeeja KP } 708cc6a4044SJeeja KP 709cc6a4044SJeeja KP for (i = 0; i < w->num_kcontrols; i++) { 710cc6a4044SJeeja KP k = &w->kcontrol_news[i]; 711cc6a4044SJeeja KP if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 712cc6a4044SJeeja KP sb = (void *) k->private_value; 713cc6a4044SJeeja KP bc = (struct skl_algo_data *)sb->dobj.private; 714cc6a4044SJeeja KP 715cc6a4044SJeeja KP if (bc->set_params == SKL_PARAM_BIND) { 7165e8f0ee4SDharageswari R if (mconfig->m_type == SKL_MODULE_TYPE_KPB) 7175e8f0ee4SDharageswari R skl_fill_sink_instance_id(ctx, bc); 718cc6a4044SJeeja KP ret = skl_set_module_params(ctx, 719cc6a4044SJeeja KP (u32 *)bc->params, bc->max, 720cc6a4044SJeeja KP bc->param_id, mconfig); 721cc6a4044SJeeja KP if (ret < 0) 722cc6a4044SJeeja KP return ret; 723cc6a4044SJeeja KP } 724cc6a4044SJeeja KP } 725cc6a4044SJeeja KP } 726cc6a4044SJeeja KP 727cc6a4044SJeeja KP return 0; 728cc6a4044SJeeja KP } 729cc6a4044SJeeja KP 7308724ff17SJeeja KP static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, 7318724ff17SJeeja KP struct skl *skl, 7326bd4cf85SJeeja KP struct snd_soc_dapm_widget *src_w, 7338724ff17SJeeja KP struct skl_module_cfg *src_mconfig) 734d93f8e55SVinod Koul { 735d93f8e55SVinod Koul struct snd_soc_dapm_path *p; 7360ed95d76SJeeja KP struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL; 7378724ff17SJeeja KP struct skl_module_cfg *sink_mconfig; 738d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 7398724ff17SJeeja KP int ret; 740d93f8e55SVinod Koul 7418724ff17SJeeja KP snd_soc_dapm_widget_for_each_sink_path(w, p) { 742d93f8e55SVinod Koul if (!p->connect) 743d93f8e55SVinod Koul continue; 744d93f8e55SVinod Koul 745d93f8e55SVinod Koul dev_dbg(ctx->dev, "%s: src widget=%s\n", __func__, w->name); 746d93f8e55SVinod Koul dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name); 747d93f8e55SVinod Koul 7480ed95d76SJeeja KP next_sink = p->sink; 7496bd4cf85SJeeja KP 7506bd4cf85SJeeja KP if (!is_skl_dsp_widget_type(p->sink)) 7516bd4cf85SJeeja KP return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig); 7526bd4cf85SJeeja KP 753d93f8e55SVinod Koul /* 754d93f8e55SVinod Koul * here we will check widgets in sink pipelines, so that 755d93f8e55SVinod Koul * can be any widgets type and we are only interested if 756d93f8e55SVinod Koul * they are ones used for SKL so check that first 757d93f8e55SVinod Koul */ 758d93f8e55SVinod Koul if ((p->sink->priv != NULL) && 759d93f8e55SVinod Koul is_skl_dsp_widget_type(p->sink)) { 760d93f8e55SVinod Koul 761d93f8e55SVinod Koul sink = p->sink; 762d93f8e55SVinod Koul sink_mconfig = sink->priv; 763d93f8e55SVinod Koul 764cc6a4044SJeeja KP if (src_mconfig->m_state == SKL_MODULE_UNINIT || 765cc6a4044SJeeja KP sink_mconfig->m_state == SKL_MODULE_UNINIT) 766cc6a4044SJeeja KP continue; 767cc6a4044SJeeja KP 768d93f8e55SVinod Koul /* Bind source to sink, mixin is always source */ 769d93f8e55SVinod Koul ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig); 770d93f8e55SVinod Koul if (ret) 771d93f8e55SVinod Koul return ret; 772d93f8e55SVinod Koul 773cc6a4044SJeeja KP /* set module params after bind */ 774cc6a4044SJeeja KP skl_tplg_set_module_bind_params(src_w, src_mconfig, ctx); 775cc6a4044SJeeja KP skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx); 776cc6a4044SJeeja KP 777d93f8e55SVinod Koul /* Start sinks pipe first */ 778d93f8e55SVinod Koul if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) { 779d1730c3dSJeeja KP if (sink_mconfig->pipe->conn_type != 780d1730c3dSJeeja KP SKL_PIPE_CONN_TYPE_FE) 781d1730c3dSJeeja KP ret = skl_run_pipe(ctx, 782d1730c3dSJeeja KP sink_mconfig->pipe); 783d93f8e55SVinod Koul if (ret) 784d93f8e55SVinod Koul return ret; 785d93f8e55SVinod Koul } 786d93f8e55SVinod Koul } 787d93f8e55SVinod Koul } 788d93f8e55SVinod Koul 7898724ff17SJeeja KP if (!sink) 7906bd4cf85SJeeja KP return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig); 7918724ff17SJeeja KP 7928724ff17SJeeja KP return 0; 7938724ff17SJeeja KP } 7948724ff17SJeeja KP 795d93f8e55SVinod Koul /* 796d93f8e55SVinod Koul * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA 797d93f8e55SVinod Koul * we need to do following: 798d93f8e55SVinod Koul * - Bind to sink pipeline 799d93f8e55SVinod Koul * Since the sink pipes can be running and we don't get mixer event on 800d93f8e55SVinod Koul * connect for already running mixer, we need to find the sink pipes 801d93f8e55SVinod Koul * here and bind to them. This way dynamic connect works. 802d93f8e55SVinod Koul * - Start sink pipeline, if not running 803d93f8e55SVinod Koul * - Then run current pipe 804d93f8e55SVinod Koul */ 805d93f8e55SVinod Koul static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, 806d93f8e55SVinod Koul struct skl *skl) 807d93f8e55SVinod Koul { 8088724ff17SJeeja KP struct skl_module_cfg *src_mconfig; 809d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 810d93f8e55SVinod Koul int ret = 0; 811d93f8e55SVinod Koul 8128724ff17SJeeja KP src_mconfig = w->priv; 813d93f8e55SVinod Koul 814d93f8e55SVinod Koul /* 815d93f8e55SVinod Koul * find which sink it is connected to, bind with the sink, 816d93f8e55SVinod Koul * if sink is not started, start sink pipe first, then start 817d93f8e55SVinod Koul * this pipe 818d93f8e55SVinod Koul */ 8196bd4cf85SJeeja KP ret = skl_tplg_bind_sinks(w, skl, w, src_mconfig); 8208724ff17SJeeja KP if (ret) 8218724ff17SJeeja KP return ret; 8228724ff17SJeeja KP 823d93f8e55SVinod Koul /* Start source pipe last after starting all sinks */ 824d1730c3dSJeeja KP if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) 825d1730c3dSJeeja KP return skl_run_pipe(ctx, src_mconfig->pipe); 826d93f8e55SVinod Koul 827d93f8e55SVinod Koul return 0; 828d93f8e55SVinod Koul } 829d93f8e55SVinod Koul 8308724ff17SJeeja KP static struct snd_soc_dapm_widget *skl_get_src_dsp_widget( 8318724ff17SJeeja KP struct snd_soc_dapm_widget *w, struct skl *skl) 8328724ff17SJeeja KP { 8338724ff17SJeeja KP struct snd_soc_dapm_path *p; 8348724ff17SJeeja KP struct snd_soc_dapm_widget *src_w = NULL; 8358724ff17SJeeja KP struct skl_sst *ctx = skl->skl_sst; 8368724ff17SJeeja KP 837d93f8e55SVinod Koul snd_soc_dapm_widget_for_each_source_path(w, p) { 8388724ff17SJeeja KP src_w = p->source; 839d93f8e55SVinod Koul if (!p->connect) 840d93f8e55SVinod Koul continue; 841d93f8e55SVinod Koul 8428724ff17SJeeja KP dev_dbg(ctx->dev, "sink widget=%s\n", w->name); 8438724ff17SJeeja KP dev_dbg(ctx->dev, "src widget=%s\n", p->source->name); 844d93f8e55SVinod Koul 845d93f8e55SVinod Koul /* 8468724ff17SJeeja KP * here we will check widgets in sink pipelines, so that can 8478724ff17SJeeja KP * be any widgets type and we are only interested if they are 8488724ff17SJeeja KP * ones used for SKL so check that first 849d93f8e55SVinod Koul */ 8508724ff17SJeeja KP if ((p->source->priv != NULL) && 8518724ff17SJeeja KP is_skl_dsp_widget_type(p->source)) { 8528724ff17SJeeja KP return p->source; 853d93f8e55SVinod Koul } 854d93f8e55SVinod Koul } 855d93f8e55SVinod Koul 8568724ff17SJeeja KP if (src_w != NULL) 8578724ff17SJeeja KP return skl_get_src_dsp_widget(src_w, skl); 858d93f8e55SVinod Koul 8598724ff17SJeeja KP return NULL; 860d93f8e55SVinod Koul } 861d93f8e55SVinod Koul 862d93f8e55SVinod Koul /* 863d93f8e55SVinod Koul * in the Post-PMU event of mixer we need to do following: 864d93f8e55SVinod Koul * - Check if this pipe is running 865d93f8e55SVinod Koul * - if not, then 866d93f8e55SVinod Koul * - bind this pipeline to its source pipeline 867d93f8e55SVinod Koul * if source pipe is already running, this means it is a dynamic 868d93f8e55SVinod Koul * connection and we need to bind only to that pipe 869d93f8e55SVinod Koul * - start this pipeline 870d93f8e55SVinod Koul */ 871d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, 872d93f8e55SVinod Koul struct skl *skl) 873d93f8e55SVinod Koul { 874d93f8e55SVinod Koul int ret = 0; 875d93f8e55SVinod Koul struct snd_soc_dapm_widget *source, *sink; 876d93f8e55SVinod Koul struct skl_module_cfg *src_mconfig, *sink_mconfig; 877d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 878d93f8e55SVinod Koul int src_pipe_started = 0; 879d93f8e55SVinod Koul 880d93f8e55SVinod Koul sink = w; 881d93f8e55SVinod Koul sink_mconfig = sink->priv; 882d93f8e55SVinod Koul 883d93f8e55SVinod Koul /* 884d93f8e55SVinod Koul * If source pipe is already started, that means source is driving 885d93f8e55SVinod Koul * one more sink before this sink got connected, Since source is 886d93f8e55SVinod Koul * started, bind this sink to source and start this pipe. 887d93f8e55SVinod Koul */ 8888724ff17SJeeja KP source = skl_get_src_dsp_widget(w, skl); 8898724ff17SJeeja KP if (source != NULL) { 890d93f8e55SVinod Koul src_mconfig = source->priv; 891d93f8e55SVinod Koul sink_mconfig = sink->priv; 892d93f8e55SVinod Koul src_pipe_started = 1; 893d93f8e55SVinod Koul 894d93f8e55SVinod Koul /* 8958724ff17SJeeja KP * check pipe state, then no need to bind or start the 8968724ff17SJeeja KP * pipe 897d93f8e55SVinod Koul */ 898d93f8e55SVinod Koul if (src_mconfig->pipe->state != SKL_PIPE_STARTED) 899d93f8e55SVinod Koul src_pipe_started = 0; 900d93f8e55SVinod Koul } 901d93f8e55SVinod Koul 902d93f8e55SVinod Koul if (src_pipe_started) { 903d93f8e55SVinod Koul ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig); 904d93f8e55SVinod Koul if (ret) 905d93f8e55SVinod Koul return ret; 906d93f8e55SVinod Koul 907cc6a4044SJeeja KP /* set module params after bind */ 908cc6a4044SJeeja KP skl_tplg_set_module_bind_params(source, src_mconfig, ctx); 909cc6a4044SJeeja KP skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx); 910cc6a4044SJeeja KP 911d1730c3dSJeeja KP if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) 912d93f8e55SVinod Koul ret = skl_run_pipe(ctx, sink_mconfig->pipe); 913d93f8e55SVinod Koul } 914d93f8e55SVinod Koul 915d93f8e55SVinod Koul return ret; 916d93f8e55SVinod Koul } 917d93f8e55SVinod Koul 918d93f8e55SVinod Koul /* 919d93f8e55SVinod Koul * in the Pre-PMD event of mixer we need to do following: 920d93f8e55SVinod Koul * - Stop the pipe 921d93f8e55SVinod Koul * - find the source connections and remove that from dapm_path_list 922d93f8e55SVinod Koul * - unbind with source pipelines if still connected 923d93f8e55SVinod Koul */ 924d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w, 925d93f8e55SVinod Koul struct skl *skl) 926d93f8e55SVinod Koul { 927d93f8e55SVinod Koul struct skl_module_cfg *src_mconfig, *sink_mconfig; 928ce1b5551SJeeja KP int ret = 0, i; 929d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 930d93f8e55SVinod Koul 931ce1b5551SJeeja KP sink_mconfig = w->priv; 932d93f8e55SVinod Koul 933d93f8e55SVinod Koul /* Stop the pipe */ 934d93f8e55SVinod Koul ret = skl_stop_pipe(ctx, sink_mconfig->pipe); 935d93f8e55SVinod Koul if (ret) 936d93f8e55SVinod Koul return ret; 937d93f8e55SVinod Koul 938ce1b5551SJeeja KP for (i = 0; i < sink_mconfig->max_in_queue; i++) { 939ce1b5551SJeeja KP if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) { 940ce1b5551SJeeja KP src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg; 941ce1b5551SJeeja KP if (!src_mconfig) 942ce1b5551SJeeja KP continue; 943d93f8e55SVinod Koul /* 944ce1b5551SJeeja KP * If path_found == 1, that means pmd for source 945ce1b5551SJeeja KP * pipe has not occurred, source is connected to 946ce1b5551SJeeja KP * some other sink. so its responsibility of sink 947ce1b5551SJeeja KP * to unbind itself from source. 948d93f8e55SVinod Koul */ 949d93f8e55SVinod Koul ret = skl_stop_pipe(ctx, src_mconfig->pipe); 950d93f8e55SVinod Koul if (ret < 0) 951d93f8e55SVinod Koul return ret; 952d93f8e55SVinod Koul 953ce1b5551SJeeja KP ret = skl_unbind_modules(ctx, 954ce1b5551SJeeja KP src_mconfig, sink_mconfig); 955ce1b5551SJeeja KP } 956d93f8e55SVinod Koul } 957d93f8e55SVinod Koul 958d93f8e55SVinod Koul return ret; 959d93f8e55SVinod Koul } 960d93f8e55SVinod Koul 961d93f8e55SVinod Koul /* 962d93f8e55SVinod Koul * in the Post-PMD event of mixer we need to do following: 963d93f8e55SVinod Koul * - Free the mcps used 964d93f8e55SVinod Koul * - Free the mem used 965d93f8e55SVinod Koul * - Unbind the modules within the pipeline 966d93f8e55SVinod Koul * - Delete the pipeline (modules are not required to be explicitly 967d93f8e55SVinod Koul * deleted, pipeline delete is enough here 968d93f8e55SVinod Koul */ 969d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, 970d93f8e55SVinod Koul struct skl *skl) 971d93f8e55SVinod Koul { 972d93f8e55SVinod Koul struct skl_module_cfg *mconfig = w->priv; 973d93f8e55SVinod Koul struct skl_pipe_module *w_module; 974d93f8e55SVinod Koul struct skl_module_cfg *src_module = NULL, *dst_module; 975d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 976d93f8e55SVinod Koul struct skl_pipe *s_pipe = mconfig->pipe; 977d93f8e55SVinod Koul 978260eb73aSDharageswari R if (s_pipe->state == SKL_PIPE_INVALID) 979260eb73aSDharageswari R return -EINVAL; 980260eb73aSDharageswari R 981d93f8e55SVinod Koul skl_tplg_free_pipe_mcps(skl, mconfig); 98265976878SVinod Koul skl_tplg_free_pipe_mem(skl, mconfig); 983d93f8e55SVinod Koul 984d93f8e55SVinod Koul list_for_each_entry(w_module, &s_pipe->w_list, node) { 985d93f8e55SVinod Koul dst_module = w_module->w->priv; 986d93f8e55SVinod Koul 987260eb73aSDharageswari R if (mconfig->m_state >= SKL_MODULE_INIT_DONE) 9887ae3cb15SVinod Koul skl_tplg_free_pipe_mcps(skl, dst_module); 989d93f8e55SVinod Koul if (src_module == NULL) { 990d93f8e55SVinod Koul src_module = dst_module; 991d93f8e55SVinod Koul continue; 992d93f8e55SVinod Koul } 993d93f8e55SVinod Koul 9947ca42f5aSGuneshwor Singh skl_unbind_modules(ctx, src_module, dst_module); 995d93f8e55SVinod Koul src_module = dst_module; 996d93f8e55SVinod Koul } 997d93f8e55SVinod Koul 998*547cafa3SVinod Koul skl_delete_pipe(ctx, mconfig->pipe); 999d93f8e55SVinod Koul 10006c5768b3SDharageswari R return skl_tplg_unload_pipe_modules(ctx, s_pipe); 1001d93f8e55SVinod Koul } 1002d93f8e55SVinod Koul 1003d93f8e55SVinod Koul /* 1004d93f8e55SVinod Koul * in the Post-PMD event of PGA we need to do following: 1005d93f8e55SVinod Koul * - Free the mcps used 1006d93f8e55SVinod Koul * - Stop the pipeline 1007d93f8e55SVinod Koul * - In source pipe is connected, unbind with source pipelines 1008d93f8e55SVinod Koul */ 1009d93f8e55SVinod Koul static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, 1010d93f8e55SVinod Koul struct skl *skl) 1011d93f8e55SVinod Koul { 1012d93f8e55SVinod Koul struct skl_module_cfg *src_mconfig, *sink_mconfig; 1013ce1b5551SJeeja KP int ret = 0, i; 1014d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 1015d93f8e55SVinod Koul 1016ce1b5551SJeeja KP src_mconfig = w->priv; 1017d93f8e55SVinod Koul 1018d93f8e55SVinod Koul /* Stop the pipe since this is a mixin module */ 1019d93f8e55SVinod Koul ret = skl_stop_pipe(ctx, src_mconfig->pipe); 1020d93f8e55SVinod Koul if (ret) 1021d93f8e55SVinod Koul return ret; 1022d93f8e55SVinod Koul 1023ce1b5551SJeeja KP for (i = 0; i < src_mconfig->max_out_queue; i++) { 1024ce1b5551SJeeja KP if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) { 1025ce1b5551SJeeja KP sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg; 1026ce1b5551SJeeja KP if (!sink_mconfig) 1027ce1b5551SJeeja KP continue; 1028d93f8e55SVinod Koul /* 1029ce1b5551SJeeja KP * This is a connecter and if path is found that means 1030d93f8e55SVinod Koul * unbind between source and sink has not happened yet 1031d93f8e55SVinod Koul */ 1032ce1b5551SJeeja KP ret = skl_unbind_modules(ctx, src_mconfig, 1033ce1b5551SJeeja KP sink_mconfig); 1034ce1b5551SJeeja KP } 1035d93f8e55SVinod Koul } 1036d93f8e55SVinod Koul 1037d93f8e55SVinod Koul return ret; 1038d93f8e55SVinod Koul } 1039d93f8e55SVinod Koul 1040d93f8e55SVinod Koul /* 1041d93f8e55SVinod Koul * In modelling, we assume there will be ONLY one mixer in a pipeline. If 1042d93f8e55SVinod Koul * mixer is not required then it is treated as static mixer aka vmixer with 1043d93f8e55SVinod Koul * a hard path to source module 1044d93f8e55SVinod Koul * So we don't need to check if source is started or not as hard path puts 1045d93f8e55SVinod Koul * dependency on each other 1046d93f8e55SVinod Koul */ 1047d93f8e55SVinod Koul static int skl_tplg_vmixer_event(struct snd_soc_dapm_widget *w, 1048d93f8e55SVinod Koul struct snd_kcontrol *k, int event) 1049d93f8e55SVinod Koul { 1050d93f8e55SVinod Koul struct snd_soc_dapm_context *dapm = w->dapm; 1051d93f8e55SVinod Koul struct skl *skl = get_skl_ctx(dapm->dev); 1052d93f8e55SVinod Koul 1053d93f8e55SVinod Koul switch (event) { 1054d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMU: 1055d93f8e55SVinod Koul return skl_tplg_mixer_dapm_pre_pmu_event(w, skl); 1056d93f8e55SVinod Koul 1057de1fedf2SJeeja KP case SND_SOC_DAPM_POST_PMU: 1058de1fedf2SJeeja KP return skl_tplg_mixer_dapm_post_pmu_event(w, skl); 1059de1fedf2SJeeja KP 1060de1fedf2SJeeja KP case SND_SOC_DAPM_PRE_PMD: 1061de1fedf2SJeeja KP return skl_tplg_mixer_dapm_pre_pmd_event(w, skl); 1062de1fedf2SJeeja KP 1063d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMD: 1064d93f8e55SVinod Koul return skl_tplg_mixer_dapm_post_pmd_event(w, skl); 1065d93f8e55SVinod Koul } 1066d93f8e55SVinod Koul 1067d93f8e55SVinod Koul return 0; 1068d93f8e55SVinod Koul } 1069d93f8e55SVinod Koul 1070d93f8e55SVinod Koul /* 1071d93f8e55SVinod Koul * In modelling, we assume there will be ONLY one mixer in a pipeline. If a 1072d93f8e55SVinod Koul * second one is required that is created as another pipe entity. 1073d93f8e55SVinod Koul * The mixer is responsible for pipe management and represent a pipeline 1074d93f8e55SVinod Koul * instance 1075d93f8e55SVinod Koul */ 1076d93f8e55SVinod Koul static int skl_tplg_mixer_event(struct snd_soc_dapm_widget *w, 1077d93f8e55SVinod Koul struct snd_kcontrol *k, int event) 1078d93f8e55SVinod Koul { 1079d93f8e55SVinod Koul struct snd_soc_dapm_context *dapm = w->dapm; 1080d93f8e55SVinod Koul struct skl *skl = get_skl_ctx(dapm->dev); 1081d93f8e55SVinod Koul 1082d93f8e55SVinod Koul switch (event) { 1083d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMU: 1084d93f8e55SVinod Koul return skl_tplg_mixer_dapm_pre_pmu_event(w, skl); 1085d93f8e55SVinod Koul 1086d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMU: 1087d93f8e55SVinod Koul return skl_tplg_mixer_dapm_post_pmu_event(w, skl); 1088d93f8e55SVinod Koul 1089d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMD: 1090d93f8e55SVinod Koul return skl_tplg_mixer_dapm_pre_pmd_event(w, skl); 1091d93f8e55SVinod Koul 1092d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMD: 1093d93f8e55SVinod Koul return skl_tplg_mixer_dapm_post_pmd_event(w, skl); 1094d93f8e55SVinod Koul } 1095d93f8e55SVinod Koul 1096d93f8e55SVinod Koul return 0; 1097d93f8e55SVinod Koul } 1098d93f8e55SVinod Koul 1099d93f8e55SVinod Koul /* 1100d93f8e55SVinod Koul * In modelling, we assumed rest of the modules in pipeline are PGA. But we 1101d93f8e55SVinod Koul * are interested in last PGA (leaf PGA) in a pipeline to disconnect with 1102d93f8e55SVinod Koul * the sink when it is running (two FE to one BE or one FE to two BE) 1103d93f8e55SVinod Koul * scenarios 1104d93f8e55SVinod Koul */ 1105d93f8e55SVinod Koul static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w, 1106d93f8e55SVinod Koul struct snd_kcontrol *k, int event) 1107d93f8e55SVinod Koul 1108d93f8e55SVinod Koul { 1109d93f8e55SVinod Koul struct snd_soc_dapm_context *dapm = w->dapm; 1110d93f8e55SVinod Koul struct skl *skl = get_skl_ctx(dapm->dev); 1111d93f8e55SVinod Koul 1112d93f8e55SVinod Koul switch (event) { 1113d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMU: 1114d93f8e55SVinod Koul return skl_tplg_pga_dapm_pre_pmu_event(w, skl); 1115d93f8e55SVinod Koul 1116d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMD: 1117d93f8e55SVinod Koul return skl_tplg_pga_dapm_post_pmd_event(w, skl); 1118d93f8e55SVinod Koul } 1119d93f8e55SVinod Koul 1120d93f8e55SVinod Koul return 0; 1121d93f8e55SVinod Koul } 1122cfb0a873SVinod Koul 1123140adfbaSJeeja KP static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol, 1124140adfbaSJeeja KP unsigned int __user *data, unsigned int size) 1125140adfbaSJeeja KP { 1126140adfbaSJeeja KP struct soc_bytes_ext *sb = 1127140adfbaSJeeja KP (struct soc_bytes_ext *)kcontrol->private_value; 1128140adfbaSJeeja KP struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private; 11297d9f2911SOmair M Abdullah struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); 11307d9f2911SOmair M Abdullah struct skl_module_cfg *mconfig = w->priv; 11317d9f2911SOmair M Abdullah struct skl *skl = get_skl_ctx(w->dapm->dev); 11327d9f2911SOmair M Abdullah 11337d9f2911SOmair M Abdullah if (w->power) 11347d9f2911SOmair M Abdullah skl_get_module_params(skl->skl_sst, (u32 *)bc->params, 11350d682104SDharageswari R bc->size, bc->param_id, mconfig); 1136140adfbaSJeeja KP 113741556f68SVinod Koul /* decrement size for TLV header */ 113841556f68SVinod Koul size -= 2 * sizeof(u32); 113941556f68SVinod Koul 114041556f68SVinod Koul /* check size as we don't want to send kernel data */ 114141556f68SVinod Koul if (size > bc->max) 114241556f68SVinod Koul size = bc->max; 114341556f68SVinod Koul 1144140adfbaSJeeja KP if (bc->params) { 1145140adfbaSJeeja KP if (copy_to_user(data, &bc->param_id, sizeof(u32))) 1146140adfbaSJeeja KP return -EFAULT; 1147e8bc3c99SDan Carpenter if (copy_to_user(data + 1, &size, sizeof(u32))) 1148140adfbaSJeeja KP return -EFAULT; 1149e8bc3c99SDan Carpenter if (copy_to_user(data + 2, bc->params, size)) 1150140adfbaSJeeja KP return -EFAULT; 1151140adfbaSJeeja KP } 1152140adfbaSJeeja KP 1153140adfbaSJeeja KP return 0; 1154140adfbaSJeeja KP } 1155140adfbaSJeeja KP 1156140adfbaSJeeja KP #define SKL_PARAM_VENDOR_ID 0xff 1157140adfbaSJeeja KP 1158140adfbaSJeeja KP static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol, 1159140adfbaSJeeja KP const unsigned int __user *data, unsigned int size) 1160140adfbaSJeeja KP { 1161140adfbaSJeeja KP struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); 1162140adfbaSJeeja KP struct skl_module_cfg *mconfig = w->priv; 1163140adfbaSJeeja KP struct soc_bytes_ext *sb = 1164140adfbaSJeeja KP (struct soc_bytes_ext *)kcontrol->private_value; 1165140adfbaSJeeja KP struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private; 1166140adfbaSJeeja KP struct skl *skl = get_skl_ctx(w->dapm->dev); 1167140adfbaSJeeja KP 1168140adfbaSJeeja KP if (ac->params) { 11690d682104SDharageswari R if (size > ac->max) 11700d682104SDharageswari R return -EINVAL; 11710d682104SDharageswari R 11720d682104SDharageswari R ac->size = size; 1173140adfbaSJeeja KP /* 1174140adfbaSJeeja KP * if the param_is is of type Vendor, firmware expects actual 1175140adfbaSJeeja KP * parameter id and size from the control. 1176140adfbaSJeeja KP */ 1177140adfbaSJeeja KP if (ac->param_id == SKL_PARAM_VENDOR_ID) { 1178140adfbaSJeeja KP if (copy_from_user(ac->params, data, size)) 1179140adfbaSJeeja KP return -EFAULT; 1180140adfbaSJeeja KP } else { 1181140adfbaSJeeja KP if (copy_from_user(ac->params, 118265b4bcb8SAlan data + 2, size)) 1183140adfbaSJeeja KP return -EFAULT; 1184140adfbaSJeeja KP } 1185140adfbaSJeeja KP 1186140adfbaSJeeja KP if (w->power) 1187140adfbaSJeeja KP return skl_set_module_params(skl->skl_sst, 11880d682104SDharageswari R (u32 *)ac->params, ac->size, 1189140adfbaSJeeja KP ac->param_id, mconfig); 1190140adfbaSJeeja KP } 1191140adfbaSJeeja KP 1192140adfbaSJeeja KP return 0; 1193140adfbaSJeeja KP } 1194140adfbaSJeeja KP 1195cfb0a873SVinod Koul /* 11968871dcb9SJeeja KP * Fill the dma id for host and link. In case of passthrough 11978871dcb9SJeeja KP * pipeline, this will both host and link in the same 11988871dcb9SJeeja KP * pipeline, so need to copy the link and host based on dev_type 11998871dcb9SJeeja KP */ 12008871dcb9SJeeja KP static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg, 12018871dcb9SJeeja KP struct skl_pipe_params *params) 12028871dcb9SJeeja KP { 12038871dcb9SJeeja KP struct skl_pipe *pipe = mcfg->pipe; 12048871dcb9SJeeja KP 12058871dcb9SJeeja KP if (pipe->passthru) { 12068871dcb9SJeeja KP switch (mcfg->dev_type) { 12078871dcb9SJeeja KP case SKL_DEVICE_HDALINK: 12088871dcb9SJeeja KP pipe->p_params->link_dma_id = params->link_dma_id; 12098871dcb9SJeeja KP break; 12108871dcb9SJeeja KP 12118871dcb9SJeeja KP case SKL_DEVICE_HDAHOST: 12128871dcb9SJeeja KP pipe->p_params->host_dma_id = params->host_dma_id; 12138871dcb9SJeeja KP break; 12148871dcb9SJeeja KP 12158871dcb9SJeeja KP default: 12168871dcb9SJeeja KP break; 12178871dcb9SJeeja KP } 12188871dcb9SJeeja KP pipe->p_params->s_fmt = params->s_fmt; 12198871dcb9SJeeja KP pipe->p_params->ch = params->ch; 12208871dcb9SJeeja KP pipe->p_params->s_freq = params->s_freq; 12218871dcb9SJeeja KP pipe->p_params->stream = params->stream; 12228871dcb9SJeeja KP 12238871dcb9SJeeja KP } else { 12248871dcb9SJeeja KP memcpy(pipe->p_params, params, sizeof(*params)); 12258871dcb9SJeeja KP } 12268871dcb9SJeeja KP } 12278871dcb9SJeeja KP 12288871dcb9SJeeja KP /* 1229cfb0a873SVinod Koul * The FE params are passed by hw_params of the DAI. 1230cfb0a873SVinod Koul * On hw_params, the params are stored in Gateway module of the FE and we 1231cfb0a873SVinod Koul * need to calculate the format in DSP module configuration, that 1232cfb0a873SVinod Koul * conversion is done here 1233cfb0a873SVinod Koul */ 1234cfb0a873SVinod Koul int skl_tplg_update_pipe_params(struct device *dev, 1235cfb0a873SVinod Koul struct skl_module_cfg *mconfig, 1236cfb0a873SVinod Koul struct skl_pipe_params *params) 1237cfb0a873SVinod Koul { 1238cfb0a873SVinod Koul struct skl_module_fmt *format = NULL; 1239cfb0a873SVinod Koul 12408871dcb9SJeeja KP skl_tplg_fill_dma_id(mconfig, params); 1241cfb0a873SVinod Koul 1242cfb0a873SVinod Koul if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) 12434cd9899fSHardik T Shah format = &mconfig->in_fmt[0]; 1244cfb0a873SVinod Koul else 12454cd9899fSHardik T Shah format = &mconfig->out_fmt[0]; 1246cfb0a873SVinod Koul 1247cfb0a873SVinod Koul /* set the hw_params */ 1248cfb0a873SVinod Koul format->s_freq = params->s_freq; 1249cfb0a873SVinod Koul format->channels = params->ch; 1250cfb0a873SVinod Koul format->valid_bit_depth = skl_get_bit_depth(params->s_fmt); 1251cfb0a873SVinod Koul 1252cfb0a873SVinod Koul /* 1253cfb0a873SVinod Koul * 16 bit is 16 bit container whereas 24 bit is in 32 bit 1254cfb0a873SVinod Koul * container so update bit depth accordingly 1255cfb0a873SVinod Koul */ 1256cfb0a873SVinod Koul switch (format->valid_bit_depth) { 1257cfb0a873SVinod Koul case SKL_DEPTH_16BIT: 1258cfb0a873SVinod Koul format->bit_depth = format->valid_bit_depth; 1259cfb0a873SVinod Koul break; 1260cfb0a873SVinod Koul 1261cfb0a873SVinod Koul case SKL_DEPTH_24BIT: 12626654f39eSJeeja KP case SKL_DEPTH_32BIT: 1263cfb0a873SVinod Koul format->bit_depth = SKL_DEPTH_32BIT; 1264cfb0a873SVinod Koul break; 1265cfb0a873SVinod Koul 1266cfb0a873SVinod Koul default: 1267cfb0a873SVinod Koul dev_err(dev, "Invalid bit depth %x for pipe\n", 1268cfb0a873SVinod Koul format->valid_bit_depth); 1269cfb0a873SVinod Koul return -EINVAL; 1270cfb0a873SVinod Koul } 1271cfb0a873SVinod Koul 1272cfb0a873SVinod Koul if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { 1273cfb0a873SVinod Koul mconfig->ibs = (format->s_freq / 1000) * 1274cfb0a873SVinod Koul (format->channels) * 1275cfb0a873SVinod Koul (format->bit_depth >> 3); 1276cfb0a873SVinod Koul } else { 1277cfb0a873SVinod Koul mconfig->obs = (format->s_freq / 1000) * 1278cfb0a873SVinod Koul (format->channels) * 1279cfb0a873SVinod Koul (format->bit_depth >> 3); 1280cfb0a873SVinod Koul } 1281cfb0a873SVinod Koul 1282cfb0a873SVinod Koul return 0; 1283cfb0a873SVinod Koul } 1284cfb0a873SVinod Koul 1285cfb0a873SVinod Koul /* 1286cfb0a873SVinod Koul * Query the module config for the FE DAI 1287cfb0a873SVinod Koul * This is used to find the hw_params set for that DAI and apply to FE 1288cfb0a873SVinod Koul * pipeline 1289cfb0a873SVinod Koul */ 1290cfb0a873SVinod Koul struct skl_module_cfg * 1291cfb0a873SVinod Koul skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream) 1292cfb0a873SVinod Koul { 1293cfb0a873SVinod Koul struct snd_soc_dapm_widget *w; 1294cfb0a873SVinod Koul struct snd_soc_dapm_path *p = NULL; 1295cfb0a873SVinod Koul 1296cfb0a873SVinod Koul if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 1297cfb0a873SVinod Koul w = dai->playback_widget; 1298f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_sink_path(w, p) { 1299cfb0a873SVinod Koul if (p->connect && p->sink->power && 1300a28f51dbSJeeja KP !is_skl_dsp_widget_type(p->sink)) 1301cfb0a873SVinod Koul continue; 1302cfb0a873SVinod Koul 1303cfb0a873SVinod Koul if (p->sink->priv) { 1304cfb0a873SVinod Koul dev_dbg(dai->dev, "set params for %s\n", 1305cfb0a873SVinod Koul p->sink->name); 1306cfb0a873SVinod Koul return p->sink->priv; 1307cfb0a873SVinod Koul } 1308cfb0a873SVinod Koul } 1309cfb0a873SVinod Koul } else { 1310cfb0a873SVinod Koul w = dai->capture_widget; 1311f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_source_path(w, p) { 1312cfb0a873SVinod Koul if (p->connect && p->source->power && 1313a28f51dbSJeeja KP !is_skl_dsp_widget_type(p->source)) 1314cfb0a873SVinod Koul continue; 1315cfb0a873SVinod Koul 1316cfb0a873SVinod Koul if (p->source->priv) { 1317cfb0a873SVinod Koul dev_dbg(dai->dev, "set params for %s\n", 1318cfb0a873SVinod Koul p->source->name); 1319cfb0a873SVinod Koul return p->source->priv; 1320cfb0a873SVinod Koul } 1321cfb0a873SVinod Koul } 1322cfb0a873SVinod Koul } 1323cfb0a873SVinod Koul 1324cfb0a873SVinod Koul return NULL; 1325cfb0a873SVinod Koul } 1326cfb0a873SVinod Koul 1327718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_pb_cpr( 1328718a42b5SDharageswari.R struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w) 1329718a42b5SDharageswari.R { 1330718a42b5SDharageswari.R struct snd_soc_dapm_path *p; 1331718a42b5SDharageswari.R struct skl_module_cfg *mconfig = NULL; 1332718a42b5SDharageswari.R 1333718a42b5SDharageswari.R snd_soc_dapm_widget_for_each_source_path(w, p) { 1334718a42b5SDharageswari.R if (w->endpoints[SND_SOC_DAPM_DIR_OUT] > 0) { 1335718a42b5SDharageswari.R if (p->connect && 1336718a42b5SDharageswari.R (p->sink->id == snd_soc_dapm_aif_out) && 1337718a42b5SDharageswari.R p->source->priv) { 1338718a42b5SDharageswari.R mconfig = p->source->priv; 1339718a42b5SDharageswari.R return mconfig; 1340718a42b5SDharageswari.R } 1341718a42b5SDharageswari.R mconfig = skl_get_mconfig_pb_cpr(dai, p->source); 1342718a42b5SDharageswari.R if (mconfig) 1343718a42b5SDharageswari.R return mconfig; 1344718a42b5SDharageswari.R } 1345718a42b5SDharageswari.R } 1346718a42b5SDharageswari.R return mconfig; 1347718a42b5SDharageswari.R } 1348718a42b5SDharageswari.R 1349718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_cap_cpr( 1350718a42b5SDharageswari.R struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w) 1351718a42b5SDharageswari.R { 1352718a42b5SDharageswari.R struct snd_soc_dapm_path *p; 1353718a42b5SDharageswari.R struct skl_module_cfg *mconfig = NULL; 1354718a42b5SDharageswari.R 1355718a42b5SDharageswari.R snd_soc_dapm_widget_for_each_sink_path(w, p) { 1356718a42b5SDharageswari.R if (w->endpoints[SND_SOC_DAPM_DIR_IN] > 0) { 1357718a42b5SDharageswari.R if (p->connect && 1358718a42b5SDharageswari.R (p->source->id == snd_soc_dapm_aif_in) && 1359718a42b5SDharageswari.R p->sink->priv) { 1360718a42b5SDharageswari.R mconfig = p->sink->priv; 1361718a42b5SDharageswari.R return mconfig; 1362718a42b5SDharageswari.R } 1363718a42b5SDharageswari.R mconfig = skl_get_mconfig_cap_cpr(dai, p->sink); 1364718a42b5SDharageswari.R if (mconfig) 1365718a42b5SDharageswari.R return mconfig; 1366718a42b5SDharageswari.R } 1367718a42b5SDharageswari.R } 1368718a42b5SDharageswari.R return mconfig; 1369718a42b5SDharageswari.R } 1370718a42b5SDharageswari.R 1371718a42b5SDharageswari.R struct skl_module_cfg * 1372718a42b5SDharageswari.R skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, int stream) 1373718a42b5SDharageswari.R { 1374718a42b5SDharageswari.R struct snd_soc_dapm_widget *w; 1375718a42b5SDharageswari.R struct skl_module_cfg *mconfig; 1376718a42b5SDharageswari.R 1377718a42b5SDharageswari.R if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 1378718a42b5SDharageswari.R w = dai->playback_widget; 1379718a42b5SDharageswari.R mconfig = skl_get_mconfig_pb_cpr(dai, w); 1380718a42b5SDharageswari.R } else { 1381718a42b5SDharageswari.R w = dai->capture_widget; 1382718a42b5SDharageswari.R mconfig = skl_get_mconfig_cap_cpr(dai, w); 1383718a42b5SDharageswari.R } 1384718a42b5SDharageswari.R return mconfig; 1385718a42b5SDharageswari.R } 1386718a42b5SDharageswari.R 1387cfb0a873SVinod Koul static u8 skl_tplg_be_link_type(int dev_type) 1388cfb0a873SVinod Koul { 1389cfb0a873SVinod Koul int ret; 1390cfb0a873SVinod Koul 1391cfb0a873SVinod Koul switch (dev_type) { 1392cfb0a873SVinod Koul case SKL_DEVICE_BT: 1393cfb0a873SVinod Koul ret = NHLT_LINK_SSP; 1394cfb0a873SVinod Koul break; 1395cfb0a873SVinod Koul 1396cfb0a873SVinod Koul case SKL_DEVICE_DMIC: 1397cfb0a873SVinod Koul ret = NHLT_LINK_DMIC; 1398cfb0a873SVinod Koul break; 1399cfb0a873SVinod Koul 1400cfb0a873SVinod Koul case SKL_DEVICE_I2S: 1401cfb0a873SVinod Koul ret = NHLT_LINK_SSP; 1402cfb0a873SVinod Koul break; 1403cfb0a873SVinod Koul 1404cfb0a873SVinod Koul case SKL_DEVICE_HDALINK: 1405cfb0a873SVinod Koul ret = NHLT_LINK_HDA; 1406cfb0a873SVinod Koul break; 1407cfb0a873SVinod Koul 1408cfb0a873SVinod Koul default: 1409cfb0a873SVinod Koul ret = NHLT_LINK_INVALID; 1410cfb0a873SVinod Koul break; 1411cfb0a873SVinod Koul } 1412cfb0a873SVinod Koul 1413cfb0a873SVinod Koul return ret; 1414cfb0a873SVinod Koul } 1415cfb0a873SVinod Koul 1416cfb0a873SVinod Koul /* 1417cfb0a873SVinod Koul * Fill the BE gateway parameters 1418cfb0a873SVinod Koul * The BE gateway expects a blob of parameters which are kept in the ACPI 1419cfb0a873SVinod Koul * NHLT blob, so query the blob for interface type (i2s/pdm) and instance. 1420cfb0a873SVinod Koul * The port can have multiple settings so pick based on the PCM 1421cfb0a873SVinod Koul * parameters 1422cfb0a873SVinod Koul */ 1423cfb0a873SVinod Koul static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai, 1424cfb0a873SVinod Koul struct skl_module_cfg *mconfig, 1425cfb0a873SVinod Koul struct skl_pipe_params *params) 1426cfb0a873SVinod Koul { 1427cfb0a873SVinod Koul struct nhlt_specific_cfg *cfg; 1428cfb0a873SVinod Koul struct skl *skl = get_skl_ctx(dai->dev); 1429cfb0a873SVinod Koul int link_type = skl_tplg_be_link_type(mconfig->dev_type); 1430cfb0a873SVinod Koul 14318871dcb9SJeeja KP skl_tplg_fill_dma_id(mconfig, params); 1432cfb0a873SVinod Koul 1433b30c275eSJeeja KP if (link_type == NHLT_LINK_HDA) 1434b30c275eSJeeja KP return 0; 1435b30c275eSJeeja KP 1436cfb0a873SVinod Koul /* update the blob based on virtual bus_id*/ 1437cfb0a873SVinod Koul cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type, 1438cfb0a873SVinod Koul params->s_fmt, params->ch, 1439cfb0a873SVinod Koul params->s_freq, params->stream); 1440cfb0a873SVinod Koul if (cfg) { 1441cfb0a873SVinod Koul mconfig->formats_config.caps_size = cfg->size; 1442bc03281aSJeeja KP mconfig->formats_config.caps = (u32 *) &cfg->caps; 1443cfb0a873SVinod Koul } else { 1444cfb0a873SVinod Koul dev_err(dai->dev, "Blob NULL for id %x type %d dirn %d\n", 1445cfb0a873SVinod Koul mconfig->vbus_id, link_type, 1446cfb0a873SVinod Koul params->stream); 1447cfb0a873SVinod Koul dev_err(dai->dev, "PCM: ch %d, freq %d, fmt %d\n", 1448cfb0a873SVinod Koul params->ch, params->s_freq, params->s_fmt); 1449cfb0a873SVinod Koul return -EINVAL; 1450cfb0a873SVinod Koul } 1451cfb0a873SVinod Koul 1452cfb0a873SVinod Koul return 0; 1453cfb0a873SVinod Koul } 1454cfb0a873SVinod Koul 1455cfb0a873SVinod Koul static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai, 1456cfb0a873SVinod Koul struct snd_soc_dapm_widget *w, 1457cfb0a873SVinod Koul struct skl_pipe_params *params) 1458cfb0a873SVinod Koul { 1459cfb0a873SVinod Koul struct snd_soc_dapm_path *p; 14604d8adccbSSubhransu S. Prusty int ret = -EIO; 1461cfb0a873SVinod Koul 1462f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_source_path(w, p) { 1463cfb0a873SVinod Koul if (p->connect && is_skl_dsp_widget_type(p->source) && 1464cfb0a873SVinod Koul p->source->priv) { 1465cfb0a873SVinod Koul 14669a03cb49SJeeja KP ret = skl_tplg_be_fill_pipe_params(dai, 14679a03cb49SJeeja KP p->source->priv, params); 14684d8adccbSSubhransu S. Prusty if (ret < 0) 14694d8adccbSSubhransu S. Prusty return ret; 1470cfb0a873SVinod Koul } else { 14719a03cb49SJeeja KP ret = skl_tplg_be_set_src_pipe_params(dai, 14729a03cb49SJeeja KP p->source, params); 14734d8adccbSSubhransu S. Prusty if (ret < 0) 14744d8adccbSSubhransu S. Prusty return ret; 1475cfb0a873SVinod Koul } 1476cfb0a873SVinod Koul } 1477cfb0a873SVinod Koul 14784d8adccbSSubhransu S. Prusty return ret; 1479cfb0a873SVinod Koul } 1480cfb0a873SVinod Koul 1481cfb0a873SVinod Koul static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai, 1482cfb0a873SVinod Koul struct snd_soc_dapm_widget *w, struct skl_pipe_params *params) 1483cfb0a873SVinod Koul { 1484cfb0a873SVinod Koul struct snd_soc_dapm_path *p = NULL; 14854d8adccbSSubhransu S. Prusty int ret = -EIO; 1486cfb0a873SVinod Koul 1487f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_sink_path(w, p) { 1488cfb0a873SVinod Koul if (p->connect && is_skl_dsp_widget_type(p->sink) && 1489cfb0a873SVinod Koul p->sink->priv) { 1490cfb0a873SVinod Koul 14919a03cb49SJeeja KP ret = skl_tplg_be_fill_pipe_params(dai, 14929a03cb49SJeeja KP p->sink->priv, params); 14934d8adccbSSubhransu S. Prusty if (ret < 0) 14944d8adccbSSubhransu S. Prusty return ret; 14954d8adccbSSubhransu S. Prusty } else { 14964d8adccbSSubhransu S. Prusty ret = skl_tplg_be_set_sink_pipe_params( 1497cfb0a873SVinod Koul dai, p->sink, params); 14984d8adccbSSubhransu S. Prusty if (ret < 0) 14994d8adccbSSubhransu S. Prusty return ret; 1500cfb0a873SVinod Koul } 1501cfb0a873SVinod Koul } 1502cfb0a873SVinod Koul 15034d8adccbSSubhransu S. Prusty return ret; 1504cfb0a873SVinod Koul } 1505cfb0a873SVinod Koul 1506cfb0a873SVinod Koul /* 1507cfb0a873SVinod Koul * BE hw_params can be a source parameters (capture) or sink parameters 1508cfb0a873SVinod Koul * (playback). Based on sink and source we need to either find the source 1509cfb0a873SVinod Koul * list or the sink list and set the pipeline parameters 1510cfb0a873SVinod Koul */ 1511cfb0a873SVinod Koul int skl_tplg_be_update_params(struct snd_soc_dai *dai, 1512cfb0a873SVinod Koul struct skl_pipe_params *params) 1513cfb0a873SVinod Koul { 1514cfb0a873SVinod Koul struct snd_soc_dapm_widget *w; 1515cfb0a873SVinod Koul 1516cfb0a873SVinod Koul if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { 1517cfb0a873SVinod Koul w = dai->playback_widget; 1518cfb0a873SVinod Koul 1519cfb0a873SVinod Koul return skl_tplg_be_set_src_pipe_params(dai, w, params); 1520cfb0a873SVinod Koul 1521cfb0a873SVinod Koul } else { 1522cfb0a873SVinod Koul w = dai->capture_widget; 1523cfb0a873SVinod Koul 1524cfb0a873SVinod Koul return skl_tplg_be_set_sink_pipe_params(dai, w, params); 1525cfb0a873SVinod Koul } 1526cfb0a873SVinod Koul 1527cfb0a873SVinod Koul return 0; 1528cfb0a873SVinod Koul } 15293af36706SVinod Koul 15303af36706SVinod Koul static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = { 15313af36706SVinod Koul {SKL_MIXER_EVENT, skl_tplg_mixer_event}, 15323af36706SVinod Koul {SKL_VMIXER_EVENT, skl_tplg_vmixer_event}, 15333af36706SVinod Koul {SKL_PGA_EVENT, skl_tplg_pga_event}, 15343af36706SVinod Koul }; 15353af36706SVinod Koul 1536140adfbaSJeeja KP static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = { 1537140adfbaSJeeja KP {SKL_CONTROL_TYPE_BYTE_TLV, skl_tplg_tlv_control_get, 1538140adfbaSJeeja KP skl_tplg_tlv_control_set}, 1539140adfbaSJeeja KP }; 1540140adfbaSJeeja KP 15416277e832SShreyas NC static int skl_tplg_fill_pipe_tkn(struct device *dev, 15426277e832SShreyas NC struct skl_pipe *pipe, u32 tkn, 15436277e832SShreyas NC u32 tkn_val) 15443af36706SVinod Koul { 15453af36706SVinod Koul 15466277e832SShreyas NC switch (tkn) { 15476277e832SShreyas NC case SKL_TKN_U32_PIPE_CONN_TYPE: 15486277e832SShreyas NC pipe->conn_type = tkn_val; 15496277e832SShreyas NC break; 15506277e832SShreyas NC 15516277e832SShreyas NC case SKL_TKN_U32_PIPE_PRIORITY: 15526277e832SShreyas NC pipe->pipe_priority = tkn_val; 15536277e832SShreyas NC break; 15546277e832SShreyas NC 15556277e832SShreyas NC case SKL_TKN_U32_PIPE_MEM_PGS: 15566277e832SShreyas NC pipe->memory_pages = tkn_val; 15576277e832SShreyas NC break; 15586277e832SShreyas NC 15598a0cb236SVinod Koul case SKL_TKN_U32_PMODE: 15608a0cb236SVinod Koul pipe->lp_mode = tkn_val; 15618a0cb236SVinod Koul break; 15628a0cb236SVinod Koul 15636277e832SShreyas NC default: 15646277e832SShreyas NC dev_err(dev, "Token not handled %d\n", tkn); 15656277e832SShreyas NC return -EINVAL; 15663af36706SVinod Koul } 15676277e832SShreyas NC 15686277e832SShreyas NC return 0; 15693af36706SVinod Koul } 15703af36706SVinod Koul 15713af36706SVinod Koul /* 15726277e832SShreyas NC * Add pipeline by parsing the relevant tokens 15736277e832SShreyas NC * Return an existing pipe if the pipe already exists. 15743af36706SVinod Koul */ 15756277e832SShreyas NC static int skl_tplg_add_pipe(struct device *dev, 15766277e832SShreyas NC struct skl_module_cfg *mconfig, struct skl *skl, 15776277e832SShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem) 15783af36706SVinod Koul { 15793af36706SVinod Koul struct skl_pipeline *ppl; 15803af36706SVinod Koul struct skl_pipe *pipe; 15813af36706SVinod Koul struct skl_pipe_params *params; 15823af36706SVinod Koul 15833af36706SVinod Koul list_for_each_entry(ppl, &skl->ppl_list, node) { 15846277e832SShreyas NC if (ppl->pipe->ppl_id == tkn_elem->value) { 15856277e832SShreyas NC mconfig->pipe = ppl->pipe; 15866277e832SShreyas NC return EEXIST; 15876277e832SShreyas NC } 15883af36706SVinod Koul } 15893af36706SVinod Koul 15903af36706SVinod Koul ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL); 15913af36706SVinod Koul if (!ppl) 15926277e832SShreyas NC return -ENOMEM; 15933af36706SVinod Koul 15943af36706SVinod Koul pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL); 15953af36706SVinod Koul if (!pipe) 15966277e832SShreyas NC return -ENOMEM; 15973af36706SVinod Koul 15983af36706SVinod Koul params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL); 15993af36706SVinod Koul if (!params) 16006277e832SShreyas NC return -ENOMEM; 16013af36706SVinod Koul 16023af36706SVinod Koul pipe->p_params = params; 16036277e832SShreyas NC pipe->ppl_id = tkn_elem->value; 16043af36706SVinod Koul INIT_LIST_HEAD(&pipe->w_list); 16053af36706SVinod Koul 16063af36706SVinod Koul ppl->pipe = pipe; 16073af36706SVinod Koul list_add(&ppl->node, &skl->ppl_list); 16083af36706SVinod Koul 16096277e832SShreyas NC mconfig->pipe = pipe; 16106277e832SShreyas NC mconfig->pipe->state = SKL_PIPE_INVALID; 16116277e832SShreyas NC 16126277e832SShreyas NC return 0; 16133af36706SVinod Koul } 16143af36706SVinod Koul 16156277e832SShreyas NC static int skl_tplg_fill_pin(struct device *dev, u32 tkn, 16166277e832SShreyas NC struct skl_module_pin *m_pin, 16176277e832SShreyas NC int pin_index, u32 value) 16186277e832SShreyas NC { 16196277e832SShreyas NC switch (tkn) { 16206277e832SShreyas NC case SKL_TKN_U32_PIN_MOD_ID: 16216277e832SShreyas NC m_pin[pin_index].id.module_id = value; 16226277e832SShreyas NC break; 16236277e832SShreyas NC 16246277e832SShreyas NC case SKL_TKN_U32_PIN_INST_ID: 16256277e832SShreyas NC m_pin[pin_index].id.instance_id = value; 16266277e832SShreyas NC break; 16276277e832SShreyas NC 16286277e832SShreyas NC default: 16296277e832SShreyas NC dev_err(dev, "%d Not a pin token\n", value); 16306277e832SShreyas NC return -EINVAL; 16316277e832SShreyas NC } 16326277e832SShreyas NC 16336277e832SShreyas NC return 0; 16346277e832SShreyas NC } 16356277e832SShreyas NC 16366277e832SShreyas NC /* 16376277e832SShreyas NC * Parse for pin config specific tokens to fill up the 16386277e832SShreyas NC * module private data 16396277e832SShreyas NC */ 16406277e832SShreyas NC static int skl_tplg_fill_pins_info(struct device *dev, 16416277e832SShreyas NC struct skl_module_cfg *mconfig, 16426277e832SShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem, 16436277e832SShreyas NC int dir, int pin_count) 16446277e832SShreyas NC { 16456277e832SShreyas NC int ret; 16466277e832SShreyas NC struct skl_module_pin *m_pin; 16476277e832SShreyas NC 16486277e832SShreyas NC switch (dir) { 16496277e832SShreyas NC case SKL_DIR_IN: 16506277e832SShreyas NC m_pin = mconfig->m_in_pin; 16516277e832SShreyas NC break; 16526277e832SShreyas NC 16536277e832SShreyas NC case SKL_DIR_OUT: 16546277e832SShreyas NC m_pin = mconfig->m_out_pin; 16556277e832SShreyas NC break; 16566277e832SShreyas NC 16576277e832SShreyas NC default: 1658ecd286a9SColin Ian King dev_err(dev, "Invalid direction value\n"); 16596277e832SShreyas NC return -EINVAL; 16606277e832SShreyas NC } 16616277e832SShreyas NC 16626277e832SShreyas NC ret = skl_tplg_fill_pin(dev, tkn_elem->token, 16636277e832SShreyas NC m_pin, pin_count, tkn_elem->value); 16646277e832SShreyas NC 16656277e832SShreyas NC if (ret < 0) 16666277e832SShreyas NC return ret; 16676277e832SShreyas NC 16686277e832SShreyas NC m_pin[pin_count].in_use = false; 16696277e832SShreyas NC m_pin[pin_count].pin_state = SKL_PIN_UNBIND; 16706277e832SShreyas NC 16716277e832SShreyas NC return 0; 16726277e832SShreyas NC } 16736277e832SShreyas NC 16746277e832SShreyas NC /* 16756277e832SShreyas NC * Fill up input/output module config format based 16766277e832SShreyas NC * on the direction 16776277e832SShreyas NC */ 16786277e832SShreyas NC static int skl_tplg_fill_fmt(struct device *dev, 16796277e832SShreyas NC struct skl_module_cfg *mconfig, u32 tkn, 16806277e832SShreyas NC u32 value, u32 dir, u32 pin_count) 16816277e832SShreyas NC { 16826277e832SShreyas NC struct skl_module_fmt *dst_fmt; 16836277e832SShreyas NC 16846277e832SShreyas NC switch (dir) { 16856277e832SShreyas NC case SKL_DIR_IN: 16866277e832SShreyas NC dst_fmt = mconfig->in_fmt; 16876277e832SShreyas NC dst_fmt += pin_count; 16886277e832SShreyas NC break; 16896277e832SShreyas NC 16906277e832SShreyas NC case SKL_DIR_OUT: 16916277e832SShreyas NC dst_fmt = mconfig->out_fmt; 16926277e832SShreyas NC dst_fmt += pin_count; 16936277e832SShreyas NC break; 16946277e832SShreyas NC 16956277e832SShreyas NC default: 1696ecd286a9SColin Ian King dev_err(dev, "Invalid direction value\n"); 16976277e832SShreyas NC return -EINVAL; 16986277e832SShreyas NC } 16996277e832SShreyas NC 17006277e832SShreyas NC switch (tkn) { 17016277e832SShreyas NC case SKL_TKN_U32_FMT_CH: 17026277e832SShreyas NC dst_fmt->channels = value; 17036277e832SShreyas NC break; 17046277e832SShreyas NC 17056277e832SShreyas NC case SKL_TKN_U32_FMT_FREQ: 17066277e832SShreyas NC dst_fmt->s_freq = value; 17076277e832SShreyas NC break; 17086277e832SShreyas NC 17096277e832SShreyas NC case SKL_TKN_U32_FMT_BIT_DEPTH: 17106277e832SShreyas NC dst_fmt->bit_depth = value; 17116277e832SShreyas NC break; 17126277e832SShreyas NC 17136277e832SShreyas NC case SKL_TKN_U32_FMT_SAMPLE_SIZE: 17146277e832SShreyas NC dst_fmt->valid_bit_depth = value; 17156277e832SShreyas NC break; 17166277e832SShreyas NC 17176277e832SShreyas NC case SKL_TKN_U32_FMT_CH_CONFIG: 17186277e832SShreyas NC dst_fmt->ch_cfg = value; 17196277e832SShreyas NC break; 17206277e832SShreyas NC 17216277e832SShreyas NC case SKL_TKN_U32_FMT_INTERLEAVE: 17226277e832SShreyas NC dst_fmt->interleaving_style = value; 17236277e832SShreyas NC break; 17246277e832SShreyas NC 17256277e832SShreyas NC case SKL_TKN_U32_FMT_SAMPLE_TYPE: 17266277e832SShreyas NC dst_fmt->sample_type = value; 17276277e832SShreyas NC break; 17286277e832SShreyas NC 17296277e832SShreyas NC case SKL_TKN_U32_FMT_CH_MAP: 17306277e832SShreyas NC dst_fmt->ch_map = value; 17316277e832SShreyas NC break; 17326277e832SShreyas NC 17336277e832SShreyas NC default: 1734ecd286a9SColin Ian King dev_err(dev, "Invalid token %d\n", tkn); 17356277e832SShreyas NC return -EINVAL; 17366277e832SShreyas NC } 17376277e832SShreyas NC 17386277e832SShreyas NC return 0; 17396277e832SShreyas NC } 17406277e832SShreyas NC 17416277e832SShreyas NC static int skl_tplg_get_uuid(struct device *dev, struct skl_module_cfg *mconfig, 17426277e832SShreyas NC struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn) 17436277e832SShreyas NC { 17446277e832SShreyas NC if (uuid_tkn->token == SKL_TKN_UUID) 17456277e832SShreyas NC memcpy(&mconfig->guid, &uuid_tkn->uuid, 16); 17466277e832SShreyas NC else { 1747ecd286a9SColin Ian King dev_err(dev, "Not an UUID token tkn %d\n", uuid_tkn->token); 17486277e832SShreyas NC return -EINVAL; 17496277e832SShreyas NC } 17506277e832SShreyas NC 17516277e832SShreyas NC return 0; 17526277e832SShreyas NC } 17536277e832SShreyas NC 17546277e832SShreyas NC static void skl_tplg_fill_pin_dynamic_val( 17556277e832SShreyas NC struct skl_module_pin *mpin, u32 pin_count, u32 value) 17564cd9899fSHardik T Shah { 17574cd9899fSHardik T Shah int i; 17584cd9899fSHardik T Shah 17596277e832SShreyas NC for (i = 0; i < pin_count; i++) 17606277e832SShreyas NC mpin[i].is_dynamic = value; 17614cd9899fSHardik T Shah } 17626277e832SShreyas NC 17636277e832SShreyas NC /* 17646277e832SShreyas NC * Parse tokens to fill up the module private data 17656277e832SShreyas NC */ 17666277e832SShreyas NC static int skl_tplg_get_token(struct device *dev, 17676277e832SShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem, 17686277e832SShreyas NC struct skl *skl, struct skl_module_cfg *mconfig) 17696277e832SShreyas NC { 17706277e832SShreyas NC int tkn_count = 0; 17716277e832SShreyas NC int ret; 17726277e832SShreyas NC static int is_pipe_exists; 17736277e832SShreyas NC static int pin_index, dir; 17746277e832SShreyas NC 17756277e832SShreyas NC if (tkn_elem->token > SKL_TKN_MAX) 17766277e832SShreyas NC return -EINVAL; 17776277e832SShreyas NC 17786277e832SShreyas NC switch (tkn_elem->token) { 17796277e832SShreyas NC case SKL_TKN_U8_IN_QUEUE_COUNT: 17806277e832SShreyas NC mconfig->max_in_queue = tkn_elem->value; 17816277e832SShreyas NC mconfig->m_in_pin = devm_kzalloc(dev, mconfig->max_in_queue * 17826277e832SShreyas NC sizeof(*mconfig->m_in_pin), 17836277e832SShreyas NC GFP_KERNEL); 17846277e832SShreyas NC if (!mconfig->m_in_pin) 17856277e832SShreyas NC return -ENOMEM; 17866277e832SShreyas NC 17876277e832SShreyas NC break; 17886277e832SShreyas NC 17896277e832SShreyas NC case SKL_TKN_U8_OUT_QUEUE_COUNT: 17906277e832SShreyas NC mconfig->max_out_queue = tkn_elem->value; 17916277e832SShreyas NC mconfig->m_out_pin = devm_kzalloc(dev, mconfig->max_out_queue * 17926277e832SShreyas NC sizeof(*mconfig->m_out_pin), 17936277e832SShreyas NC GFP_KERNEL); 17946277e832SShreyas NC 17956277e832SShreyas NC if (!mconfig->m_out_pin) 17966277e832SShreyas NC return -ENOMEM; 17976277e832SShreyas NC 17986277e832SShreyas NC break; 17996277e832SShreyas NC 18006277e832SShreyas NC case SKL_TKN_U8_DYN_IN_PIN: 18016277e832SShreyas NC if (!mconfig->m_in_pin) 18026277e832SShreyas NC return -ENOMEM; 18036277e832SShreyas NC 18046277e832SShreyas NC skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin, 18056277e832SShreyas NC mconfig->max_in_queue, tkn_elem->value); 18066277e832SShreyas NC 18076277e832SShreyas NC break; 18086277e832SShreyas NC 18096277e832SShreyas NC case SKL_TKN_U8_DYN_OUT_PIN: 18106277e832SShreyas NC if (!mconfig->m_out_pin) 18116277e832SShreyas NC return -ENOMEM; 18126277e832SShreyas NC 18136277e832SShreyas NC skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin, 18146277e832SShreyas NC mconfig->max_out_queue, tkn_elem->value); 18156277e832SShreyas NC 18166277e832SShreyas NC break; 18176277e832SShreyas NC 18186277e832SShreyas NC case SKL_TKN_U8_TIME_SLOT: 18196277e832SShreyas NC mconfig->time_slot = tkn_elem->value; 18206277e832SShreyas NC break; 18216277e832SShreyas NC 18226277e832SShreyas NC case SKL_TKN_U8_CORE_ID: 18236277e832SShreyas NC mconfig->core_id = tkn_elem->value; 18246277e832SShreyas NC 18256277e832SShreyas NC case SKL_TKN_U8_MOD_TYPE: 18266277e832SShreyas NC mconfig->m_type = tkn_elem->value; 18276277e832SShreyas NC break; 18286277e832SShreyas NC 18296277e832SShreyas NC case SKL_TKN_U8_DEV_TYPE: 18306277e832SShreyas NC mconfig->dev_type = tkn_elem->value; 18316277e832SShreyas NC break; 18326277e832SShreyas NC 18336277e832SShreyas NC case SKL_TKN_U8_HW_CONN_TYPE: 18346277e832SShreyas NC mconfig->hw_conn_type = tkn_elem->value; 18356277e832SShreyas NC break; 18366277e832SShreyas NC 18376277e832SShreyas NC case SKL_TKN_U16_MOD_INST_ID: 18386277e832SShreyas NC mconfig->id.instance_id = 18396277e832SShreyas NC tkn_elem->value; 18406277e832SShreyas NC break; 18416277e832SShreyas NC 18426277e832SShreyas NC case SKL_TKN_U32_MEM_PAGES: 18436277e832SShreyas NC mconfig->mem_pages = tkn_elem->value; 18446277e832SShreyas NC break; 18456277e832SShreyas NC 18466277e832SShreyas NC case SKL_TKN_U32_MAX_MCPS: 18476277e832SShreyas NC mconfig->mcps = tkn_elem->value; 18486277e832SShreyas NC break; 18496277e832SShreyas NC 18506277e832SShreyas NC case SKL_TKN_U32_OBS: 18516277e832SShreyas NC mconfig->obs = tkn_elem->value; 18526277e832SShreyas NC break; 18536277e832SShreyas NC 18546277e832SShreyas NC case SKL_TKN_U32_IBS: 18556277e832SShreyas NC mconfig->ibs = tkn_elem->value; 18566277e832SShreyas NC break; 18576277e832SShreyas NC 18586277e832SShreyas NC case SKL_TKN_U32_VBUS_ID: 18596277e832SShreyas NC mconfig->vbus_id = tkn_elem->value; 18606277e832SShreyas NC break; 18616277e832SShreyas NC 18626277e832SShreyas NC case SKL_TKN_U32_PARAMS_FIXUP: 18636277e832SShreyas NC mconfig->params_fixup = tkn_elem->value; 18646277e832SShreyas NC break; 18656277e832SShreyas NC 18666277e832SShreyas NC case SKL_TKN_U32_CONVERTER: 18676277e832SShreyas NC mconfig->converter = tkn_elem->value; 18686277e832SShreyas NC break; 18696277e832SShreyas NC 18706bd9dcf3SVinod Koul case SKL_TKL_U32_D0I3_CAPS: 18716bd9dcf3SVinod Koul mconfig->d0i3_caps = tkn_elem->value; 18726bd9dcf3SVinod Koul break; 18736bd9dcf3SVinod Koul 18746277e832SShreyas NC case SKL_TKN_U32_PIPE_ID: 18756277e832SShreyas NC ret = skl_tplg_add_pipe(dev, 18766277e832SShreyas NC mconfig, skl, tkn_elem); 18776277e832SShreyas NC 18786277e832SShreyas NC if (ret < 0) 18796277e832SShreyas NC return is_pipe_exists; 18806277e832SShreyas NC 18816277e832SShreyas NC if (ret == EEXIST) 18826277e832SShreyas NC is_pipe_exists = 1; 18836277e832SShreyas NC 18846277e832SShreyas NC break; 18856277e832SShreyas NC 18866277e832SShreyas NC case SKL_TKN_U32_PIPE_CONN_TYPE: 18876277e832SShreyas NC case SKL_TKN_U32_PIPE_PRIORITY: 18886277e832SShreyas NC case SKL_TKN_U32_PIPE_MEM_PGS: 18898a0cb236SVinod Koul case SKL_TKN_U32_PMODE: 18906277e832SShreyas NC if (is_pipe_exists) { 18916277e832SShreyas NC ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe, 18926277e832SShreyas NC tkn_elem->token, tkn_elem->value); 18936277e832SShreyas NC if (ret < 0) 18946277e832SShreyas NC return ret; 18956277e832SShreyas NC } 18966277e832SShreyas NC 18976277e832SShreyas NC break; 18986277e832SShreyas NC 18996277e832SShreyas NC /* 19006277e832SShreyas NC * SKL_TKN_U32_DIR_PIN_COUNT token has the value for both 19016277e832SShreyas NC * direction and the pin count. The first four bits represent 19026277e832SShreyas NC * direction and next four the pin count. 19036277e832SShreyas NC */ 19046277e832SShreyas NC case SKL_TKN_U32_DIR_PIN_COUNT: 19056277e832SShreyas NC dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK; 19066277e832SShreyas NC pin_index = (tkn_elem->value & 19076277e832SShreyas NC SKL_PIN_COUNT_MASK) >> 4; 19086277e832SShreyas NC 19096277e832SShreyas NC break; 19106277e832SShreyas NC 19116277e832SShreyas NC case SKL_TKN_U32_FMT_CH: 19126277e832SShreyas NC case SKL_TKN_U32_FMT_FREQ: 19136277e832SShreyas NC case SKL_TKN_U32_FMT_BIT_DEPTH: 19146277e832SShreyas NC case SKL_TKN_U32_FMT_SAMPLE_SIZE: 19156277e832SShreyas NC case SKL_TKN_U32_FMT_CH_CONFIG: 19166277e832SShreyas NC case SKL_TKN_U32_FMT_INTERLEAVE: 19176277e832SShreyas NC case SKL_TKN_U32_FMT_SAMPLE_TYPE: 19186277e832SShreyas NC case SKL_TKN_U32_FMT_CH_MAP: 19196277e832SShreyas NC ret = skl_tplg_fill_fmt(dev, mconfig, tkn_elem->token, 19206277e832SShreyas NC tkn_elem->value, dir, pin_index); 19216277e832SShreyas NC 19226277e832SShreyas NC if (ret < 0) 19236277e832SShreyas NC return ret; 19246277e832SShreyas NC 19256277e832SShreyas NC break; 19266277e832SShreyas NC 19276277e832SShreyas NC case SKL_TKN_U32_PIN_MOD_ID: 19286277e832SShreyas NC case SKL_TKN_U32_PIN_INST_ID: 19296277e832SShreyas NC ret = skl_tplg_fill_pins_info(dev, 19306277e832SShreyas NC mconfig, tkn_elem, dir, 19316277e832SShreyas NC pin_index); 19326277e832SShreyas NC if (ret < 0) 19336277e832SShreyas NC return ret; 19346277e832SShreyas NC 19356277e832SShreyas NC break; 19366277e832SShreyas NC 19376277e832SShreyas NC case SKL_TKN_U32_CAPS_SIZE: 19386277e832SShreyas NC mconfig->formats_config.caps_size = 19396277e832SShreyas NC tkn_elem->value; 19406277e832SShreyas NC 19416277e832SShreyas NC break; 19426277e832SShreyas NC 19436277e832SShreyas NC case SKL_TKN_U32_PROC_DOMAIN: 19446277e832SShreyas NC mconfig->domain = 19456277e832SShreyas NC tkn_elem->value; 19466277e832SShreyas NC 19476277e832SShreyas NC break; 19486277e832SShreyas NC 19496277e832SShreyas NC case SKL_TKN_U8_IN_PIN_TYPE: 19506277e832SShreyas NC case SKL_TKN_U8_OUT_PIN_TYPE: 19516277e832SShreyas NC case SKL_TKN_U8_CONN_TYPE: 19526277e832SShreyas NC break; 19536277e832SShreyas NC 19546277e832SShreyas NC default: 19556277e832SShreyas NC dev_err(dev, "Token %d not handled\n", 19566277e832SShreyas NC tkn_elem->token); 19576277e832SShreyas NC return -EINVAL; 19586277e832SShreyas NC } 19596277e832SShreyas NC 19606277e832SShreyas NC tkn_count++; 19616277e832SShreyas NC 19626277e832SShreyas NC return tkn_count; 19636277e832SShreyas NC } 19646277e832SShreyas NC 19656277e832SShreyas NC /* 19666277e832SShreyas NC * Parse the vendor array for specific tokens to construct 19676277e832SShreyas NC * module private data 19686277e832SShreyas NC */ 19696277e832SShreyas NC static int skl_tplg_get_tokens(struct device *dev, 19706277e832SShreyas NC char *pvt_data, struct skl *skl, 19716277e832SShreyas NC struct skl_module_cfg *mconfig, int block_size) 19726277e832SShreyas NC { 19736277e832SShreyas NC struct snd_soc_tplg_vendor_array *array; 19746277e832SShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem; 19756277e832SShreyas NC int tkn_count = 0, ret; 19766277e832SShreyas NC int off = 0, tuple_size = 0; 19776277e832SShreyas NC 19786277e832SShreyas NC if (block_size <= 0) 19796277e832SShreyas NC return -EINVAL; 19806277e832SShreyas NC 19816277e832SShreyas NC while (tuple_size < block_size) { 19826277e832SShreyas NC array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off); 19836277e832SShreyas NC 19846277e832SShreyas NC off += array->size; 19856277e832SShreyas NC 19866277e832SShreyas NC switch (array->type) { 19876277e832SShreyas NC case SND_SOC_TPLG_TUPLE_TYPE_STRING: 1988ecd286a9SColin Ian King dev_warn(dev, "no string tokens expected for skl tplg\n"); 19896277e832SShreyas NC continue; 19906277e832SShreyas NC 19916277e832SShreyas NC case SND_SOC_TPLG_TUPLE_TYPE_UUID: 19926277e832SShreyas NC ret = skl_tplg_get_uuid(dev, mconfig, array->uuid); 19936277e832SShreyas NC if (ret < 0) 19946277e832SShreyas NC return ret; 19956277e832SShreyas NC 19966277e832SShreyas NC tuple_size += sizeof(*array->uuid); 19976277e832SShreyas NC 19986277e832SShreyas NC continue; 19996277e832SShreyas NC 20006277e832SShreyas NC default: 20016277e832SShreyas NC tkn_elem = array->value; 20026277e832SShreyas NC tkn_count = 0; 20036277e832SShreyas NC break; 20046277e832SShreyas NC } 20056277e832SShreyas NC 20066277e832SShreyas NC while (tkn_count <= (array->num_elems - 1)) { 20076277e832SShreyas NC ret = skl_tplg_get_token(dev, tkn_elem, 20086277e832SShreyas NC skl, mconfig); 20096277e832SShreyas NC 20106277e832SShreyas NC if (ret < 0) 20116277e832SShreyas NC return ret; 20126277e832SShreyas NC 20136277e832SShreyas NC tkn_count = tkn_count + ret; 20146277e832SShreyas NC tkn_elem++; 20156277e832SShreyas NC } 20166277e832SShreyas NC 20176277e832SShreyas NC tuple_size += tkn_count * sizeof(*tkn_elem); 20186277e832SShreyas NC } 20196277e832SShreyas NC 20206277e832SShreyas NC return 0; 20216277e832SShreyas NC } 20226277e832SShreyas NC 20236277e832SShreyas NC /* 20246277e832SShreyas NC * Every data block is preceded by a descriptor to read the number 20256277e832SShreyas NC * of data blocks, they type of the block and it's size 20266277e832SShreyas NC */ 20276277e832SShreyas NC static int skl_tplg_get_desc_blocks(struct device *dev, 20286277e832SShreyas NC struct snd_soc_tplg_vendor_array *array) 20296277e832SShreyas NC { 20306277e832SShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem; 20316277e832SShreyas NC 20326277e832SShreyas NC tkn_elem = array->value; 20336277e832SShreyas NC 20346277e832SShreyas NC switch (tkn_elem->token) { 20356277e832SShreyas NC case SKL_TKN_U8_NUM_BLOCKS: 20366277e832SShreyas NC case SKL_TKN_U8_BLOCK_TYPE: 20376277e832SShreyas NC case SKL_TKN_U16_BLOCK_SIZE: 20386277e832SShreyas NC return tkn_elem->value; 20396277e832SShreyas NC 20406277e832SShreyas NC default: 2041ecd286a9SColin Ian King dev_err(dev, "Invalid descriptor token %d\n", tkn_elem->token); 20426277e832SShreyas NC break; 20436277e832SShreyas NC } 20446277e832SShreyas NC 20456277e832SShreyas NC return -EINVAL; 20466277e832SShreyas NC } 20476277e832SShreyas NC 20486277e832SShreyas NC /* 20496277e832SShreyas NC * Parse the private data for the token and corresponding value. 20506277e832SShreyas NC * The private data can have multiple data blocks. So, a data block 20516277e832SShreyas NC * is preceded by a descriptor for number of blocks and a descriptor 20526277e832SShreyas NC * for the type and size of the suceeding data block. 20536277e832SShreyas NC */ 20546277e832SShreyas NC static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w, 20556277e832SShreyas NC struct skl *skl, struct device *dev, 20566277e832SShreyas NC struct skl_module_cfg *mconfig) 20576277e832SShreyas NC { 20586277e832SShreyas NC struct snd_soc_tplg_vendor_array *array; 20596277e832SShreyas NC int num_blocks, block_size = 0, block_type, off = 0; 20606277e832SShreyas NC char *data; 20616277e832SShreyas NC int ret; 20626277e832SShreyas NC 20636277e832SShreyas NC /* Read the NUM_DATA_BLOCKS descriptor */ 20646277e832SShreyas NC array = (struct snd_soc_tplg_vendor_array *)tplg_w->priv.data; 20656277e832SShreyas NC ret = skl_tplg_get_desc_blocks(dev, array); 20666277e832SShreyas NC if (ret < 0) 20676277e832SShreyas NC return ret; 20686277e832SShreyas NC num_blocks = ret; 20696277e832SShreyas NC 20706277e832SShreyas NC off += array->size; 20716277e832SShreyas NC array = (struct snd_soc_tplg_vendor_array *)(tplg_w->priv.data + off); 20726277e832SShreyas NC 20736277e832SShreyas NC /* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */ 20746277e832SShreyas NC while (num_blocks > 0) { 20756277e832SShreyas NC ret = skl_tplg_get_desc_blocks(dev, array); 20766277e832SShreyas NC 20776277e832SShreyas NC if (ret < 0) 20786277e832SShreyas NC return ret; 20796277e832SShreyas NC block_type = ret; 20806277e832SShreyas NC off += array->size; 20816277e832SShreyas NC 20826277e832SShreyas NC array = (struct snd_soc_tplg_vendor_array *) 20836277e832SShreyas NC (tplg_w->priv.data + off); 20846277e832SShreyas NC 20856277e832SShreyas NC ret = skl_tplg_get_desc_blocks(dev, array); 20866277e832SShreyas NC 20876277e832SShreyas NC if (ret < 0) 20886277e832SShreyas NC return ret; 20896277e832SShreyas NC block_size = ret; 20906277e832SShreyas NC off += array->size; 20916277e832SShreyas NC 20926277e832SShreyas NC array = (struct snd_soc_tplg_vendor_array *) 20936277e832SShreyas NC (tplg_w->priv.data + off); 20946277e832SShreyas NC 20956277e832SShreyas NC data = (tplg_w->priv.data + off); 20966277e832SShreyas NC 20976277e832SShreyas NC if (block_type == SKL_TYPE_TUPLE) { 20986277e832SShreyas NC ret = skl_tplg_get_tokens(dev, data, 20996277e832SShreyas NC skl, mconfig, block_size); 21006277e832SShreyas NC 21016277e832SShreyas NC if (ret < 0) 21026277e832SShreyas NC return ret; 21036277e832SShreyas NC 21046277e832SShreyas NC --num_blocks; 21056277e832SShreyas NC } else { 21066277e832SShreyas NC if (mconfig->formats_config.caps_size > 0) 21076277e832SShreyas NC memcpy(mconfig->formats_config.caps, data, 21086277e832SShreyas NC mconfig->formats_config.caps_size); 21096277e832SShreyas NC --num_blocks; 21106277e832SShreyas NC } 21116277e832SShreyas NC } 21126277e832SShreyas NC 21136277e832SShreyas NC return 0; 21144cd9899fSHardik T Shah } 21154cd9899fSHardik T Shah 2116fe3f4442SDharageswari R static void skl_clear_pin_config(struct snd_soc_platform *platform, 2117fe3f4442SDharageswari R struct snd_soc_dapm_widget *w) 2118fe3f4442SDharageswari R { 2119fe3f4442SDharageswari R int i; 2120fe3f4442SDharageswari R struct skl_module_cfg *mconfig; 2121fe3f4442SDharageswari R struct skl_pipe *pipe; 2122fe3f4442SDharageswari R 2123fe3f4442SDharageswari R if (!strncmp(w->dapm->component->name, platform->component.name, 2124fe3f4442SDharageswari R strlen(platform->component.name))) { 2125fe3f4442SDharageswari R mconfig = w->priv; 2126fe3f4442SDharageswari R pipe = mconfig->pipe; 2127fe3f4442SDharageswari R for (i = 0; i < mconfig->max_in_queue; i++) { 2128fe3f4442SDharageswari R mconfig->m_in_pin[i].in_use = false; 2129fe3f4442SDharageswari R mconfig->m_in_pin[i].pin_state = SKL_PIN_UNBIND; 2130fe3f4442SDharageswari R } 2131fe3f4442SDharageswari R for (i = 0; i < mconfig->max_out_queue; i++) { 2132fe3f4442SDharageswari R mconfig->m_out_pin[i].in_use = false; 2133fe3f4442SDharageswari R mconfig->m_out_pin[i].pin_state = SKL_PIN_UNBIND; 2134fe3f4442SDharageswari R } 2135fe3f4442SDharageswari R pipe->state = SKL_PIPE_INVALID; 2136fe3f4442SDharageswari R mconfig->m_state = SKL_MODULE_UNINIT; 2137fe3f4442SDharageswari R } 2138fe3f4442SDharageswari R } 2139fe3f4442SDharageswari R 2140fe3f4442SDharageswari R void skl_cleanup_resources(struct skl *skl) 2141fe3f4442SDharageswari R { 2142fe3f4442SDharageswari R struct skl_sst *ctx = skl->skl_sst; 2143fe3f4442SDharageswari R struct snd_soc_platform *soc_platform = skl->platform; 2144fe3f4442SDharageswari R struct snd_soc_dapm_widget *w; 2145fe3f4442SDharageswari R struct snd_soc_card *card; 2146fe3f4442SDharageswari R 2147fe3f4442SDharageswari R if (soc_platform == NULL) 2148fe3f4442SDharageswari R return; 2149fe3f4442SDharageswari R 2150fe3f4442SDharageswari R card = soc_platform->component.card; 2151fe3f4442SDharageswari R if (!card || !card->instantiated) 2152fe3f4442SDharageswari R return; 2153fe3f4442SDharageswari R 2154fe3f4442SDharageswari R skl->resource.mem = 0; 2155fe3f4442SDharageswari R skl->resource.mcps = 0; 2156fe3f4442SDharageswari R 2157fe3f4442SDharageswari R list_for_each_entry(w, &card->widgets, list) { 2158fe3f4442SDharageswari R if (is_skl_dsp_widget_type(w) && (w->priv != NULL)) 2159fe3f4442SDharageswari R skl_clear_pin_config(soc_platform, w); 2160fe3f4442SDharageswari R } 2161fe3f4442SDharageswari R 2162fe3f4442SDharageswari R skl_clear_module_cnt(ctx->dsp); 2163fe3f4442SDharageswari R } 2164fe3f4442SDharageswari R 21653af36706SVinod Koul /* 21663af36706SVinod Koul * Topology core widget load callback 21673af36706SVinod Koul * 21683af36706SVinod Koul * This is used to save the private data for each widget which gives 21693af36706SVinod Koul * information to the driver about module and pipeline parameters which DSP 21703af36706SVinod Koul * FW expects like ids, resource values, formats etc 21713af36706SVinod Koul */ 21723af36706SVinod Koul static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, 21733af36706SVinod Koul struct snd_soc_dapm_widget *w, 21743af36706SVinod Koul struct snd_soc_tplg_dapm_widget *tplg_w) 21753af36706SVinod Koul { 21763af36706SVinod Koul int ret; 21773af36706SVinod Koul struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt); 21783af36706SVinod Koul struct skl *skl = ebus_to_skl(ebus); 21793af36706SVinod Koul struct hdac_bus *bus = ebus_to_hbus(ebus); 21803af36706SVinod Koul struct skl_module_cfg *mconfig; 21813af36706SVinod Koul 21823af36706SVinod Koul if (!tplg_w->priv.size) 21833af36706SVinod Koul goto bind_event; 21843af36706SVinod Koul 21853af36706SVinod Koul mconfig = devm_kzalloc(bus->dev, sizeof(*mconfig), GFP_KERNEL); 21863af36706SVinod Koul 21873af36706SVinod Koul if (!mconfig) 21883af36706SVinod Koul return -ENOMEM; 21893af36706SVinod Koul 21903af36706SVinod Koul w->priv = mconfig; 219109305da9SShreyas NC 2192b7c50555SVinod Koul /* 2193b7c50555SVinod Koul * module binary can be loaded later, so set it to query when 2194b7c50555SVinod Koul * module is load for a use case 2195b7c50555SVinod Koul */ 2196b7c50555SVinod Koul mconfig->id.module_id = -1; 21974cd9899fSHardik T Shah 21986277e832SShreyas NC /* Parse private data for tuples */ 21996277e832SShreyas NC ret = skl_tplg_get_pvt_data(tplg_w, skl, bus->dev, mconfig); 22006277e832SShreyas NC if (ret < 0) 22016277e832SShreyas NC return ret; 22023af36706SVinod Koul bind_event: 22033af36706SVinod Koul if (tplg_w->event_type == 0) { 22043373f716SVinod Koul dev_dbg(bus->dev, "ASoC: No event handler required\n"); 22053af36706SVinod Koul return 0; 22063af36706SVinod Koul } 22073af36706SVinod Koul 22083af36706SVinod Koul ret = snd_soc_tplg_widget_bind_event(w, skl_tplg_widget_ops, 2209b663a8c5SJeeja KP ARRAY_SIZE(skl_tplg_widget_ops), 2210b663a8c5SJeeja KP tplg_w->event_type); 22113af36706SVinod Koul 22123af36706SVinod Koul if (ret) { 22133af36706SVinod Koul dev_err(bus->dev, "%s: No matching event handlers found for %d\n", 22143af36706SVinod Koul __func__, tplg_w->event_type); 22153af36706SVinod Koul return -EINVAL; 22163af36706SVinod Koul } 22173af36706SVinod Koul 22183af36706SVinod Koul return 0; 22193af36706SVinod Koul } 22203af36706SVinod Koul 2221140adfbaSJeeja KP static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be, 2222140adfbaSJeeja KP struct snd_soc_tplg_bytes_control *bc) 2223140adfbaSJeeja KP { 2224140adfbaSJeeja KP struct skl_algo_data *ac; 2225140adfbaSJeeja KP struct skl_dfw_algo_data *dfw_ac = 2226140adfbaSJeeja KP (struct skl_dfw_algo_data *)bc->priv.data; 2227140adfbaSJeeja KP 2228140adfbaSJeeja KP ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL); 2229140adfbaSJeeja KP if (!ac) 2230140adfbaSJeeja KP return -ENOMEM; 2231140adfbaSJeeja KP 2232140adfbaSJeeja KP /* Fill private data */ 2233140adfbaSJeeja KP ac->max = dfw_ac->max; 2234140adfbaSJeeja KP ac->param_id = dfw_ac->param_id; 2235140adfbaSJeeja KP ac->set_params = dfw_ac->set_params; 22360d682104SDharageswari R ac->size = dfw_ac->max; 2237140adfbaSJeeja KP 2238140adfbaSJeeja KP if (ac->max) { 2239140adfbaSJeeja KP ac->params = (char *) devm_kzalloc(dev, ac->max, GFP_KERNEL); 2240140adfbaSJeeja KP if (!ac->params) 2241140adfbaSJeeja KP return -ENOMEM; 2242140adfbaSJeeja KP 2243140adfbaSJeeja KP memcpy(ac->params, dfw_ac->params, ac->max); 2244140adfbaSJeeja KP } 2245140adfbaSJeeja KP 2246140adfbaSJeeja KP be->dobj.private = ac; 2247140adfbaSJeeja KP return 0; 2248140adfbaSJeeja KP } 2249140adfbaSJeeja KP 2250140adfbaSJeeja KP static int skl_tplg_control_load(struct snd_soc_component *cmpnt, 2251140adfbaSJeeja KP struct snd_kcontrol_new *kctl, 2252140adfbaSJeeja KP struct snd_soc_tplg_ctl_hdr *hdr) 2253140adfbaSJeeja KP { 2254140adfbaSJeeja KP struct soc_bytes_ext *sb; 2255140adfbaSJeeja KP struct snd_soc_tplg_bytes_control *tplg_bc; 2256140adfbaSJeeja KP struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt); 2257140adfbaSJeeja KP struct hdac_bus *bus = ebus_to_hbus(ebus); 2258140adfbaSJeeja KP 2259140adfbaSJeeja KP switch (hdr->ops.info) { 2260140adfbaSJeeja KP case SND_SOC_TPLG_CTL_BYTES: 2261140adfbaSJeeja KP tplg_bc = container_of(hdr, 2262140adfbaSJeeja KP struct snd_soc_tplg_bytes_control, hdr); 2263140adfbaSJeeja KP if (kctl->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 2264140adfbaSJeeja KP sb = (struct soc_bytes_ext *)kctl->private_value; 2265140adfbaSJeeja KP if (tplg_bc->priv.size) 2266140adfbaSJeeja KP return skl_init_algo_data( 2267140adfbaSJeeja KP bus->dev, sb, tplg_bc); 2268140adfbaSJeeja KP } 2269140adfbaSJeeja KP break; 2270140adfbaSJeeja KP 2271140adfbaSJeeja KP default: 2272140adfbaSJeeja KP dev_warn(bus->dev, "Control load not supported %d:%d:%d\n", 2273140adfbaSJeeja KP hdr->ops.get, hdr->ops.put, hdr->ops.info); 2274140adfbaSJeeja KP break; 2275140adfbaSJeeja KP } 2276140adfbaSJeeja KP 2277140adfbaSJeeja KP return 0; 2278140adfbaSJeeja KP } 2279140adfbaSJeeja KP 2280541070ceSShreyas NC static int skl_tplg_fill_str_mfest_tkn(struct device *dev, 2281541070ceSShreyas NC struct snd_soc_tplg_vendor_string_elem *str_elem, 2282541070ceSShreyas NC struct skl_dfw_manifest *minfo) 2283541070ceSShreyas NC { 2284541070ceSShreyas NC int tkn_count = 0; 2285541070ceSShreyas NC static int ref_count; 2286541070ceSShreyas NC 2287541070ceSShreyas NC switch (str_elem->token) { 2288541070ceSShreyas NC case SKL_TKN_STR_LIB_NAME: 2289541070ceSShreyas NC if (ref_count > minfo->lib_count - 1) { 2290541070ceSShreyas NC ref_count = 0; 2291541070ceSShreyas NC return -EINVAL; 2292541070ceSShreyas NC } 2293541070ceSShreyas NC 2294541070ceSShreyas NC strncpy(minfo->lib[ref_count].name, str_elem->string, 2295541070ceSShreyas NC ARRAY_SIZE(minfo->lib[ref_count].name)); 2296541070ceSShreyas NC ref_count++; 2297541070ceSShreyas NC tkn_count++; 2298541070ceSShreyas NC break; 2299541070ceSShreyas NC 2300541070ceSShreyas NC default: 2301ecd286a9SColin Ian King dev_err(dev, "Not a string token %d\n", str_elem->token); 2302541070ceSShreyas NC break; 2303541070ceSShreyas NC } 2304541070ceSShreyas NC 2305541070ceSShreyas NC return tkn_count; 2306541070ceSShreyas NC } 2307541070ceSShreyas NC 2308541070ceSShreyas NC static int skl_tplg_get_str_tkn(struct device *dev, 2309541070ceSShreyas NC struct snd_soc_tplg_vendor_array *array, 2310541070ceSShreyas NC struct skl_dfw_manifest *minfo) 2311541070ceSShreyas NC { 2312541070ceSShreyas NC int tkn_count = 0, ret; 2313541070ceSShreyas NC struct snd_soc_tplg_vendor_string_elem *str_elem; 2314541070ceSShreyas NC 2315541070ceSShreyas NC str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value; 2316541070ceSShreyas NC while (tkn_count < array->num_elems) { 2317541070ceSShreyas NC ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, minfo); 2318541070ceSShreyas NC str_elem++; 2319541070ceSShreyas NC 2320541070ceSShreyas NC if (ret < 0) 2321541070ceSShreyas NC return ret; 2322541070ceSShreyas NC 2323541070ceSShreyas NC tkn_count = tkn_count + ret; 2324541070ceSShreyas NC } 2325541070ceSShreyas NC 2326541070ceSShreyas NC return tkn_count; 2327541070ceSShreyas NC } 2328541070ceSShreyas NC 2329541070ceSShreyas NC static int skl_tplg_get_int_tkn(struct device *dev, 2330541070ceSShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem, 2331541070ceSShreyas NC struct skl_dfw_manifest *minfo) 2332541070ceSShreyas NC { 2333541070ceSShreyas NC int tkn_count = 0; 2334541070ceSShreyas NC 2335541070ceSShreyas NC switch (tkn_elem->token) { 2336541070ceSShreyas NC case SKL_TKN_U32_LIB_COUNT: 2337541070ceSShreyas NC minfo->lib_count = tkn_elem->value; 2338541070ceSShreyas NC tkn_count++; 2339541070ceSShreyas NC break; 2340541070ceSShreyas NC 2341541070ceSShreyas NC default: 2342ecd286a9SColin Ian King dev_err(dev, "Not a manifest token %d\n", tkn_elem->token); 2343541070ceSShreyas NC return -EINVAL; 2344541070ceSShreyas NC } 2345541070ceSShreyas NC 2346541070ceSShreyas NC return tkn_count; 2347541070ceSShreyas NC } 2348541070ceSShreyas NC 2349541070ceSShreyas NC /* 2350541070ceSShreyas NC * Fill the manifest structure by parsing the tokens based on the 2351541070ceSShreyas NC * type. 2352541070ceSShreyas NC */ 2353541070ceSShreyas NC static int skl_tplg_get_manifest_tkn(struct device *dev, 2354541070ceSShreyas NC char *pvt_data, struct skl_dfw_manifest *minfo, 2355541070ceSShreyas NC int block_size) 2356541070ceSShreyas NC { 2357541070ceSShreyas NC int tkn_count = 0, ret; 2358541070ceSShreyas NC int off = 0, tuple_size = 0; 2359541070ceSShreyas NC struct snd_soc_tplg_vendor_array *array; 2360541070ceSShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem; 2361541070ceSShreyas NC 2362541070ceSShreyas NC if (block_size <= 0) 2363541070ceSShreyas NC return -EINVAL; 2364541070ceSShreyas NC 2365541070ceSShreyas NC while (tuple_size < block_size) { 2366541070ceSShreyas NC array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off); 2367541070ceSShreyas NC off += array->size; 2368541070ceSShreyas NC switch (array->type) { 2369541070ceSShreyas NC case SND_SOC_TPLG_TUPLE_TYPE_STRING: 2370541070ceSShreyas NC ret = skl_tplg_get_str_tkn(dev, array, minfo); 2371541070ceSShreyas NC 2372541070ceSShreyas NC if (ret < 0) 2373541070ceSShreyas NC return ret; 2374541070ceSShreyas NC tkn_count += ret; 2375541070ceSShreyas NC 2376541070ceSShreyas NC tuple_size += tkn_count * 2377541070ceSShreyas NC sizeof(struct snd_soc_tplg_vendor_string_elem); 2378541070ceSShreyas NC continue; 2379541070ceSShreyas NC 2380541070ceSShreyas NC case SND_SOC_TPLG_TUPLE_TYPE_UUID: 2381ecd286a9SColin Ian King dev_warn(dev, "no uuid tokens for skl tplf manifest\n"); 2382541070ceSShreyas NC continue; 2383541070ceSShreyas NC 2384541070ceSShreyas NC default: 2385541070ceSShreyas NC tkn_elem = array->value; 2386541070ceSShreyas NC tkn_count = 0; 2387541070ceSShreyas NC break; 2388541070ceSShreyas NC } 2389541070ceSShreyas NC 2390541070ceSShreyas NC while (tkn_count <= array->num_elems - 1) { 2391541070ceSShreyas NC ret = skl_tplg_get_int_tkn(dev, 2392541070ceSShreyas NC tkn_elem, minfo); 2393541070ceSShreyas NC if (ret < 0) 2394541070ceSShreyas NC return ret; 2395541070ceSShreyas NC 2396541070ceSShreyas NC tkn_count = tkn_count + ret; 2397541070ceSShreyas NC tkn_elem++; 2398541070ceSShreyas NC tuple_size += tkn_count * 2399541070ceSShreyas NC sizeof(struct snd_soc_tplg_vendor_value_elem); 2400541070ceSShreyas NC break; 2401541070ceSShreyas NC } 2402541070ceSShreyas NC tkn_count = 0; 2403541070ceSShreyas NC } 2404541070ceSShreyas NC 2405541070ceSShreyas NC return 0; 2406541070ceSShreyas NC } 2407541070ceSShreyas NC 2408541070ceSShreyas NC /* 2409541070ceSShreyas NC * Parse manifest private data for tokens. The private data block is 2410541070ceSShreyas NC * preceded by descriptors for type and size of data block. 2411541070ceSShreyas NC */ 2412541070ceSShreyas NC static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest, 2413541070ceSShreyas NC struct device *dev, struct skl_dfw_manifest *minfo) 2414541070ceSShreyas NC { 2415541070ceSShreyas NC struct snd_soc_tplg_vendor_array *array; 2416541070ceSShreyas NC int num_blocks, block_size = 0, block_type, off = 0; 2417541070ceSShreyas NC char *data; 2418541070ceSShreyas NC int ret; 2419541070ceSShreyas NC 2420541070ceSShreyas NC /* Read the NUM_DATA_BLOCKS descriptor */ 2421541070ceSShreyas NC array = (struct snd_soc_tplg_vendor_array *)manifest->priv.data; 2422541070ceSShreyas NC ret = skl_tplg_get_desc_blocks(dev, array); 2423541070ceSShreyas NC if (ret < 0) 2424541070ceSShreyas NC return ret; 2425541070ceSShreyas NC num_blocks = ret; 2426541070ceSShreyas NC 2427541070ceSShreyas NC off += array->size; 2428541070ceSShreyas NC array = (struct snd_soc_tplg_vendor_array *) 2429541070ceSShreyas NC (manifest->priv.data + off); 2430541070ceSShreyas NC 2431541070ceSShreyas NC /* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */ 2432541070ceSShreyas NC while (num_blocks > 0) { 2433541070ceSShreyas NC ret = skl_tplg_get_desc_blocks(dev, array); 2434541070ceSShreyas NC 2435541070ceSShreyas NC if (ret < 0) 2436541070ceSShreyas NC return ret; 2437541070ceSShreyas NC block_type = ret; 2438541070ceSShreyas NC off += array->size; 2439541070ceSShreyas NC 2440541070ceSShreyas NC array = (struct snd_soc_tplg_vendor_array *) 2441541070ceSShreyas NC (manifest->priv.data + off); 2442541070ceSShreyas NC 2443541070ceSShreyas NC ret = skl_tplg_get_desc_blocks(dev, array); 2444541070ceSShreyas NC 2445541070ceSShreyas NC if (ret < 0) 2446541070ceSShreyas NC return ret; 2447541070ceSShreyas NC block_size = ret; 2448541070ceSShreyas NC off += array->size; 2449541070ceSShreyas NC 2450541070ceSShreyas NC array = (struct snd_soc_tplg_vendor_array *) 2451541070ceSShreyas NC (manifest->priv.data + off); 2452541070ceSShreyas NC 2453541070ceSShreyas NC data = (manifest->priv.data + off); 2454541070ceSShreyas NC 2455541070ceSShreyas NC if (block_type == SKL_TYPE_TUPLE) { 2456541070ceSShreyas NC ret = skl_tplg_get_manifest_tkn(dev, data, minfo, 2457541070ceSShreyas NC block_size); 2458541070ceSShreyas NC 2459541070ceSShreyas NC if (ret < 0) 2460541070ceSShreyas NC return ret; 2461541070ceSShreyas NC 2462541070ceSShreyas NC --num_blocks; 2463541070ceSShreyas NC } else { 2464541070ceSShreyas NC return -EINVAL; 2465541070ceSShreyas NC } 2466541070ceSShreyas NC } 2467541070ceSShreyas NC 2468541070ceSShreyas NC return 0; 2469541070ceSShreyas NC } 2470541070ceSShreyas NC 247115ecaba9SKranthi G static int skl_manifest_load(struct snd_soc_component *cmpnt, 247215ecaba9SKranthi G struct snd_soc_tplg_manifest *manifest) 247315ecaba9SKranthi G { 247415ecaba9SKranthi G struct skl_dfw_manifest *minfo; 247515ecaba9SKranthi G struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt); 247615ecaba9SKranthi G struct hdac_bus *bus = ebus_to_hbus(ebus); 247715ecaba9SKranthi G struct skl *skl = ebus_to_skl(ebus); 247815ecaba9SKranthi G int ret = 0; 247915ecaba9SKranthi G 2480c15ad605SVinod Koul /* proceed only if we have private data defined */ 2481c15ad605SVinod Koul if (manifest->priv.size == 0) 2482c15ad605SVinod Koul return 0; 2483c15ad605SVinod Koul 248415ecaba9SKranthi G minfo = &skl->skl_sst->manifest; 2485541070ceSShreyas NC 2486541070ceSShreyas NC skl_tplg_get_manifest_data(manifest, bus->dev, minfo); 248715ecaba9SKranthi G 248815ecaba9SKranthi G if (minfo->lib_count > HDA_MAX_LIB) { 248915ecaba9SKranthi G dev_err(bus->dev, "Exceeding max Library count. Got:%d\n", 249015ecaba9SKranthi G minfo->lib_count); 249115ecaba9SKranthi G ret = -EINVAL; 249215ecaba9SKranthi G } 249315ecaba9SKranthi G 249415ecaba9SKranthi G return ret; 249515ecaba9SKranthi G } 249615ecaba9SKranthi G 24973af36706SVinod Koul static struct snd_soc_tplg_ops skl_tplg_ops = { 24983af36706SVinod Koul .widget_load = skl_tplg_widget_load, 2499140adfbaSJeeja KP .control_load = skl_tplg_control_load, 2500140adfbaSJeeja KP .bytes_ext_ops = skl_tlv_ops, 2501140adfbaSJeeja KP .bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops), 250215ecaba9SKranthi G .manifest = skl_manifest_load, 25033af36706SVinod Koul }; 25043af36706SVinod Koul 2505287af4f9SJeeja KP /* 2506287af4f9SJeeja KP * A pipe can have multiple modules, each of them will be a DAPM widget as 2507287af4f9SJeeja KP * well. While managing a pipeline we need to get the list of all the 2508287af4f9SJeeja KP * widgets in a pipelines, so this helper - skl_tplg_create_pipe_widget_list() 2509287af4f9SJeeja KP * helps to get the SKL type widgets in that pipeline 2510287af4f9SJeeja KP */ 2511287af4f9SJeeja KP static int skl_tplg_create_pipe_widget_list(struct snd_soc_platform *platform) 2512287af4f9SJeeja KP { 2513287af4f9SJeeja KP struct snd_soc_dapm_widget *w; 2514287af4f9SJeeja KP struct skl_module_cfg *mcfg = NULL; 2515287af4f9SJeeja KP struct skl_pipe_module *p_module = NULL; 2516287af4f9SJeeja KP struct skl_pipe *pipe; 2517287af4f9SJeeja KP 2518287af4f9SJeeja KP list_for_each_entry(w, &platform->component.card->widgets, list) { 2519287af4f9SJeeja KP if (is_skl_dsp_widget_type(w) && w->priv != NULL) { 2520287af4f9SJeeja KP mcfg = w->priv; 2521287af4f9SJeeja KP pipe = mcfg->pipe; 2522287af4f9SJeeja KP 2523287af4f9SJeeja KP p_module = devm_kzalloc(platform->dev, 2524287af4f9SJeeja KP sizeof(*p_module), GFP_KERNEL); 2525287af4f9SJeeja KP if (!p_module) 2526287af4f9SJeeja KP return -ENOMEM; 2527287af4f9SJeeja KP 2528287af4f9SJeeja KP p_module->w = w; 2529287af4f9SJeeja KP list_add_tail(&p_module->node, &pipe->w_list); 2530287af4f9SJeeja KP } 2531287af4f9SJeeja KP } 2532287af4f9SJeeja KP 2533287af4f9SJeeja KP return 0; 2534287af4f9SJeeja KP } 2535287af4f9SJeeja KP 2536f0aa94faSJeeja KP static void skl_tplg_set_pipe_type(struct skl *skl, struct skl_pipe *pipe) 2537f0aa94faSJeeja KP { 2538f0aa94faSJeeja KP struct skl_pipe_module *w_module; 2539f0aa94faSJeeja KP struct snd_soc_dapm_widget *w; 2540f0aa94faSJeeja KP struct skl_module_cfg *mconfig; 2541f0aa94faSJeeja KP bool host_found = false, link_found = false; 2542f0aa94faSJeeja KP 2543f0aa94faSJeeja KP list_for_each_entry(w_module, &pipe->w_list, node) { 2544f0aa94faSJeeja KP w = w_module->w; 2545f0aa94faSJeeja KP mconfig = w->priv; 2546f0aa94faSJeeja KP 2547f0aa94faSJeeja KP if (mconfig->dev_type == SKL_DEVICE_HDAHOST) 2548f0aa94faSJeeja KP host_found = true; 2549f0aa94faSJeeja KP else if (mconfig->dev_type != SKL_DEVICE_NONE) 2550f0aa94faSJeeja KP link_found = true; 2551f0aa94faSJeeja KP } 2552f0aa94faSJeeja KP 2553f0aa94faSJeeja KP if (host_found && link_found) 2554f0aa94faSJeeja KP pipe->passthru = true; 2555f0aa94faSJeeja KP else 2556f0aa94faSJeeja KP pipe->passthru = false; 2557f0aa94faSJeeja KP } 2558f0aa94faSJeeja KP 25593af36706SVinod Koul /* This will be read from topology manifest, currently defined here */ 25603af36706SVinod Koul #define SKL_MAX_MCPS 30000000 25613af36706SVinod Koul #define SKL_FW_MAX_MEM 1000000 25623af36706SVinod Koul 25633af36706SVinod Koul /* 25643af36706SVinod Koul * SKL topology init routine 25653af36706SVinod Koul */ 25663af36706SVinod Koul int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus) 25673af36706SVinod Koul { 25683af36706SVinod Koul int ret; 25693af36706SVinod Koul const struct firmware *fw; 25703af36706SVinod Koul struct hdac_bus *bus = ebus_to_hbus(ebus); 25713af36706SVinod Koul struct skl *skl = ebus_to_skl(ebus); 2572f0aa94faSJeeja KP struct skl_pipeline *ppl; 25733af36706SVinod Koul 25744b235c43SVinod Koul ret = request_firmware(&fw, skl->tplg_name, bus->dev); 25753af36706SVinod Koul if (ret < 0) { 2576b663a8c5SJeeja KP dev_err(bus->dev, "tplg fw %s load failed with %d\n", 25774b235c43SVinod Koul skl->tplg_name, ret); 25784b235c43SVinod Koul ret = request_firmware(&fw, "dfw_sst.bin", bus->dev); 25794b235c43SVinod Koul if (ret < 0) { 25804b235c43SVinod Koul dev_err(bus->dev, "Fallback tplg fw %s load failed with %d\n", 25813af36706SVinod Koul "dfw_sst.bin", ret); 25823af36706SVinod Koul return ret; 25833af36706SVinod Koul } 25844b235c43SVinod Koul } 25853af36706SVinod Koul 25863af36706SVinod Koul /* 25873af36706SVinod Koul * The complete tplg for SKL is loaded as index 0, we don't use 25883af36706SVinod Koul * any other index 25893af36706SVinod Koul */ 2590b663a8c5SJeeja KP ret = snd_soc_tplg_component_load(&platform->component, 2591b663a8c5SJeeja KP &skl_tplg_ops, fw, 0); 25923af36706SVinod Koul if (ret < 0) { 25933af36706SVinod Koul dev_err(bus->dev, "tplg component load failed%d\n", ret); 2594c14a82c7SSudip Mukherjee release_firmware(fw); 25953af36706SVinod Koul return -EINVAL; 25963af36706SVinod Koul } 25973af36706SVinod Koul 25983af36706SVinod Koul skl->resource.max_mcps = SKL_MAX_MCPS; 25993af36706SVinod Koul skl->resource.max_mem = SKL_FW_MAX_MEM; 26003af36706SVinod Koul 2601d8018361SVinod Koul skl->tplg = fw; 2602287af4f9SJeeja KP ret = skl_tplg_create_pipe_widget_list(platform); 2603287af4f9SJeeja KP if (ret < 0) 2604287af4f9SJeeja KP return ret; 2605d8018361SVinod Koul 2606f0aa94faSJeeja KP list_for_each_entry(ppl, &skl->ppl_list, node) 2607f0aa94faSJeeja KP skl_tplg_set_pipe_type(skl, ppl->pipe); 26083af36706SVinod Koul 26093af36706SVinod Koul return 0; 2610e4e2d2f4SJeeja KP } 2611