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> 24e4e2d2f4SJeeja KP #include "skl-sst-dsp.h" 25e4e2d2f4SJeeja KP #include "skl-sst-ipc.h" 26e4e2d2f4SJeeja KP #include "skl-topology.h" 27e4e2d2f4SJeeja KP #include "skl.h" 28e4e2d2f4SJeeja KP #include "skl-tplg-interface.h" 29e4e2d2f4SJeeja KP 30f7590d4fSJeeja KP #define SKL_CH_FIXUP_MASK (1 << 0) 31f7590d4fSJeeja KP #define SKL_RATE_FIXUP_MASK (1 << 1) 32f7590d4fSJeeja KP #define SKL_FMT_FIXUP_MASK (1 << 2) 33f7590d4fSJeeja KP 34e4e2d2f4SJeeja KP /* 35e4e2d2f4SJeeja KP * SKL DSP driver modelling uses only few DAPM widgets so for rest we will 36e4e2d2f4SJeeja KP * ignore. This helpers checks if the SKL driver handles this widget type 37e4e2d2f4SJeeja KP */ 38e4e2d2f4SJeeja KP static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w) 39e4e2d2f4SJeeja KP { 40e4e2d2f4SJeeja KP switch (w->id) { 41e4e2d2f4SJeeja KP case snd_soc_dapm_dai_link: 42e4e2d2f4SJeeja KP case snd_soc_dapm_dai_in: 43e4e2d2f4SJeeja KP case snd_soc_dapm_aif_in: 44e4e2d2f4SJeeja KP case snd_soc_dapm_aif_out: 45e4e2d2f4SJeeja KP case snd_soc_dapm_dai_out: 46e4e2d2f4SJeeja KP case snd_soc_dapm_switch: 47e4e2d2f4SJeeja KP return false; 48e4e2d2f4SJeeja KP default: 49e4e2d2f4SJeeja KP return true; 50e4e2d2f4SJeeja KP } 51e4e2d2f4SJeeja KP } 52e4e2d2f4SJeeja KP 53e4e2d2f4SJeeja KP /* 54e4e2d2f4SJeeja KP * Each pipelines needs memory to be allocated. Check if we have free memory 55e4e2d2f4SJeeja KP * from available pool. Then only add this to pool 56e4e2d2f4SJeeja KP * This is freed when pipe is deleted 57e4e2d2f4SJeeja KP * Note: DSP does actual memory management we only keep track for complete 58e4e2d2f4SJeeja KP * pool 59e4e2d2f4SJeeja KP */ 60e4e2d2f4SJeeja KP static bool skl_tplg_alloc_pipe_mem(struct skl *skl, 61e4e2d2f4SJeeja KP struct skl_module_cfg *mconfig) 62e4e2d2f4SJeeja KP { 63e4e2d2f4SJeeja KP struct skl_sst *ctx = skl->skl_sst; 64e4e2d2f4SJeeja KP 65e4e2d2f4SJeeja KP if (skl->resource.mem + mconfig->pipe->memory_pages > 66e4e2d2f4SJeeja KP skl->resource.max_mem) { 67e4e2d2f4SJeeja KP dev_err(ctx->dev, 68e4e2d2f4SJeeja KP "%s: module_id %d instance %d\n", __func__, 69e4e2d2f4SJeeja KP mconfig->id.module_id, 70e4e2d2f4SJeeja KP mconfig->id.instance_id); 71e4e2d2f4SJeeja KP dev_err(ctx->dev, 72e4e2d2f4SJeeja KP "exceeds ppl memory available %d mem %d\n", 73e4e2d2f4SJeeja KP skl->resource.max_mem, skl->resource.mem); 74e4e2d2f4SJeeja KP return false; 75e4e2d2f4SJeeja KP } 76e4e2d2f4SJeeja KP 77e4e2d2f4SJeeja KP skl->resource.mem += mconfig->pipe->memory_pages; 78e4e2d2f4SJeeja KP return true; 79e4e2d2f4SJeeja KP } 80e4e2d2f4SJeeja KP 81e4e2d2f4SJeeja KP /* 82e4e2d2f4SJeeja KP * Pipeline needs needs DSP CPU resources for computation, this is 83e4e2d2f4SJeeja KP * quantified in MCPS (Million Clocks Per Second) required for module/pipe 84e4e2d2f4SJeeja KP * 85e4e2d2f4SJeeja KP * Each pipelines needs mcps to be allocated. Check if we have mcps for this 86e4e2d2f4SJeeja KP * pipe. This adds the mcps to driver counter 87e4e2d2f4SJeeja KP * This is removed on pipeline delete 88e4e2d2f4SJeeja KP */ 89e4e2d2f4SJeeja KP static bool skl_tplg_alloc_pipe_mcps(struct skl *skl, 90e4e2d2f4SJeeja KP struct skl_module_cfg *mconfig) 91e4e2d2f4SJeeja KP { 92e4e2d2f4SJeeja KP struct skl_sst *ctx = skl->skl_sst; 93e4e2d2f4SJeeja KP 94e4e2d2f4SJeeja KP if (skl->resource.mcps + mconfig->mcps > skl->resource.max_mcps) { 95e4e2d2f4SJeeja KP dev_err(ctx->dev, 96e4e2d2f4SJeeja KP "%s: module_id %d instance %d\n", __func__, 97e4e2d2f4SJeeja KP mconfig->id.module_id, mconfig->id.instance_id); 98e4e2d2f4SJeeja KP dev_err(ctx->dev, 99e4e2d2f4SJeeja KP "exceeds ppl memory available %d > mem %d\n", 100e4e2d2f4SJeeja KP skl->resource.max_mcps, skl->resource.mcps); 101e4e2d2f4SJeeja KP return false; 102e4e2d2f4SJeeja KP } 103e4e2d2f4SJeeja KP 104e4e2d2f4SJeeja KP skl->resource.mcps += mconfig->mcps; 105e4e2d2f4SJeeja KP return true; 106e4e2d2f4SJeeja KP } 107e4e2d2f4SJeeja KP 108e4e2d2f4SJeeja KP /* 109e4e2d2f4SJeeja KP * Free the mcps when tearing down 110e4e2d2f4SJeeja KP */ 111e4e2d2f4SJeeja KP static void 112e4e2d2f4SJeeja KP skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig) 113e4e2d2f4SJeeja KP { 114e4e2d2f4SJeeja KP skl->resource.mcps -= mconfig->mcps; 115e4e2d2f4SJeeja KP } 116e4e2d2f4SJeeja KP 117e4e2d2f4SJeeja KP /* 118e4e2d2f4SJeeja KP * Free the memory when tearing down 119e4e2d2f4SJeeja KP */ 120e4e2d2f4SJeeja KP static void 121e4e2d2f4SJeeja KP skl_tplg_free_pipe_mem(struct skl *skl, struct skl_module_cfg *mconfig) 122e4e2d2f4SJeeja KP { 123e4e2d2f4SJeeja KP skl->resource.mem -= mconfig->pipe->memory_pages; 124e4e2d2f4SJeeja KP } 125e4e2d2f4SJeeja KP 126f7590d4fSJeeja KP 127f7590d4fSJeeja KP static void skl_dump_mconfig(struct skl_sst *ctx, 128f7590d4fSJeeja KP struct skl_module_cfg *mcfg) 129f7590d4fSJeeja KP { 130f7590d4fSJeeja KP dev_dbg(ctx->dev, "Dumping config\n"); 131f7590d4fSJeeja KP dev_dbg(ctx->dev, "Input Format:\n"); 1324cd9899fSHardik T Shah dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt[0].channels); 1334cd9899fSHardik T Shah dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->in_fmt[0].s_freq); 1344cd9899fSHardik T Shah dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->in_fmt[0].ch_cfg); 1354cd9899fSHardik T Shah dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->in_fmt[0].valid_bit_depth); 136f7590d4fSJeeja KP dev_dbg(ctx->dev, "Output Format:\n"); 1374cd9899fSHardik T Shah dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt[0].channels); 1384cd9899fSHardik T Shah dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->out_fmt[0].s_freq); 1394cd9899fSHardik T Shah dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->out_fmt[0].valid_bit_depth); 1404cd9899fSHardik T Shah dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt[0].ch_cfg); 141f7590d4fSJeeja KP } 142f7590d4fSJeeja KP 143f7590d4fSJeeja KP static void skl_tplg_update_params(struct skl_module_fmt *fmt, 144f7590d4fSJeeja KP struct skl_pipe_params *params, int fixup) 145f7590d4fSJeeja KP { 146f7590d4fSJeeja KP if (fixup & SKL_RATE_FIXUP_MASK) 147f7590d4fSJeeja KP fmt->s_freq = params->s_freq; 148f7590d4fSJeeja KP if (fixup & SKL_CH_FIXUP_MASK) 149f7590d4fSJeeja KP fmt->channels = params->ch; 15098256f83SJeeja KP if (fixup & SKL_FMT_FIXUP_MASK) { 15198256f83SJeeja KP fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt); 15298256f83SJeeja KP 15398256f83SJeeja KP /* 15498256f83SJeeja KP * 16 bit is 16 bit container whereas 24 bit is in 32 bit 15598256f83SJeeja KP * container so update bit depth accordingly 15698256f83SJeeja KP */ 15798256f83SJeeja KP switch (fmt->valid_bit_depth) { 15898256f83SJeeja KP case SKL_DEPTH_16BIT: 15998256f83SJeeja KP fmt->bit_depth = fmt->valid_bit_depth; 16098256f83SJeeja KP break; 16198256f83SJeeja KP 16298256f83SJeeja KP default: 16398256f83SJeeja KP fmt->bit_depth = SKL_DEPTH_32BIT; 16498256f83SJeeja KP break; 16598256f83SJeeja KP } 16698256f83SJeeja KP } 16798256f83SJeeja KP 168f7590d4fSJeeja KP } 169f7590d4fSJeeja KP 170f7590d4fSJeeja KP /* 171f7590d4fSJeeja KP * A pipeline may have modules which impact the pcm parameters, like SRC, 172f7590d4fSJeeja KP * channel converter, format converter. 173f7590d4fSJeeja KP * We need to calculate the output params by applying the 'fixup' 174f7590d4fSJeeja KP * Topology will tell driver which type of fixup is to be applied by 175f7590d4fSJeeja KP * supplying the fixup mask, so based on that we calculate the output 176f7590d4fSJeeja KP * 177f7590d4fSJeeja KP * Now In FE the pcm hw_params is source/target format. Same is applicable 178f7590d4fSJeeja KP * for BE with its hw_params invoked. 179f7590d4fSJeeja KP * here based on FE, BE pipeline and direction we calculate the input and 180f7590d4fSJeeja KP * outfix and then apply that for a module 181f7590d4fSJeeja KP */ 182f7590d4fSJeeja KP static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg, 183f7590d4fSJeeja KP struct skl_pipe_params *params, bool is_fe) 184f7590d4fSJeeja KP { 185f7590d4fSJeeja KP int in_fixup, out_fixup; 186f7590d4fSJeeja KP struct skl_module_fmt *in_fmt, *out_fmt; 187f7590d4fSJeeja KP 1884cd9899fSHardik T Shah /* Fixups will be applied to pin 0 only */ 1894cd9899fSHardik T Shah in_fmt = &m_cfg->in_fmt[0]; 1904cd9899fSHardik T Shah out_fmt = &m_cfg->out_fmt[0]; 191f7590d4fSJeeja KP 192f7590d4fSJeeja KP if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { 193f7590d4fSJeeja KP if (is_fe) { 194f7590d4fSJeeja KP in_fixup = m_cfg->params_fixup; 195f7590d4fSJeeja KP out_fixup = (~m_cfg->converter) & 196f7590d4fSJeeja KP m_cfg->params_fixup; 197f7590d4fSJeeja KP } else { 198f7590d4fSJeeja KP out_fixup = m_cfg->params_fixup; 199f7590d4fSJeeja KP in_fixup = (~m_cfg->converter) & 200f7590d4fSJeeja KP m_cfg->params_fixup; 201f7590d4fSJeeja KP } 202f7590d4fSJeeja KP } else { 203f7590d4fSJeeja KP if (is_fe) { 204f7590d4fSJeeja KP out_fixup = m_cfg->params_fixup; 205f7590d4fSJeeja KP in_fixup = (~m_cfg->converter) & 206f7590d4fSJeeja KP m_cfg->params_fixup; 207f7590d4fSJeeja KP } else { 208f7590d4fSJeeja KP in_fixup = m_cfg->params_fixup; 209f7590d4fSJeeja KP out_fixup = (~m_cfg->converter) & 210f7590d4fSJeeja KP m_cfg->params_fixup; 211f7590d4fSJeeja KP } 212f7590d4fSJeeja KP } 213f7590d4fSJeeja KP 214f7590d4fSJeeja KP skl_tplg_update_params(in_fmt, params, in_fixup); 215f7590d4fSJeeja KP skl_tplg_update_params(out_fmt, params, out_fixup); 216f7590d4fSJeeja KP } 217f7590d4fSJeeja KP 218f7590d4fSJeeja KP /* 219f7590d4fSJeeja KP * A module needs input and output buffers, which are dependent upon pcm 220f7590d4fSJeeja KP * params, so once we have calculate params, we need buffer calculation as 221f7590d4fSJeeja KP * well. 222f7590d4fSJeeja KP */ 223f7590d4fSJeeja KP static void skl_tplg_update_buffer_size(struct skl_sst *ctx, 224f7590d4fSJeeja KP struct skl_module_cfg *mcfg) 225f7590d4fSJeeja KP { 226f7590d4fSJeeja KP int multiplier = 1; 2274cd9899fSHardik T Shah struct skl_module_fmt *in_fmt, *out_fmt; 2284cd9899fSHardik T Shah 2294cd9899fSHardik T Shah 2304cd9899fSHardik T Shah /* Since fixups is applied to pin 0 only, ibs, obs needs 2314cd9899fSHardik T Shah * change for pin 0 only 2324cd9899fSHardik T Shah */ 2334cd9899fSHardik T Shah in_fmt = &mcfg->in_fmt[0]; 2344cd9899fSHardik T Shah out_fmt = &mcfg->out_fmt[0]; 235f7590d4fSJeeja KP 236f7590d4fSJeeja KP if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT) 237f7590d4fSJeeja KP multiplier = 5; 2384cd9899fSHardik T Shah mcfg->ibs = (in_fmt->s_freq / 1000) * 2394cd9899fSHardik T Shah (mcfg->in_fmt->channels) * 2404cd9899fSHardik T Shah (mcfg->in_fmt->bit_depth >> 3) * 241f7590d4fSJeeja KP multiplier; 242f7590d4fSJeeja KP 2434cd9899fSHardik T Shah mcfg->obs = (mcfg->out_fmt->s_freq / 1000) * 2444cd9899fSHardik T Shah (mcfg->out_fmt->channels) * 2454cd9899fSHardik T Shah (mcfg->out_fmt->bit_depth >> 3) * 246f7590d4fSJeeja KP multiplier; 247f7590d4fSJeeja KP } 248f7590d4fSJeeja KP 249f7590d4fSJeeja KP static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w, 250f7590d4fSJeeja KP struct skl_sst *ctx) 251f7590d4fSJeeja KP { 252f7590d4fSJeeja KP struct skl_module_cfg *m_cfg = w->priv; 253f7590d4fSJeeja KP struct skl_pipe_params *params = m_cfg->pipe->p_params; 254f7590d4fSJeeja KP int p_conn_type = m_cfg->pipe->conn_type; 255f7590d4fSJeeja KP bool is_fe; 256f7590d4fSJeeja KP 257f7590d4fSJeeja KP if (!m_cfg->params_fixup) 258f7590d4fSJeeja KP return; 259f7590d4fSJeeja KP 260f7590d4fSJeeja KP dev_dbg(ctx->dev, "Mconfig for widget=%s BEFORE updation\n", 261f7590d4fSJeeja KP w->name); 262f7590d4fSJeeja KP 263f7590d4fSJeeja KP skl_dump_mconfig(ctx, m_cfg); 264f7590d4fSJeeja KP 265f7590d4fSJeeja KP if (p_conn_type == SKL_PIPE_CONN_TYPE_FE) 266f7590d4fSJeeja KP is_fe = true; 267f7590d4fSJeeja KP else 268f7590d4fSJeeja KP is_fe = false; 269f7590d4fSJeeja KP 270f7590d4fSJeeja KP skl_tplg_update_params_fixup(m_cfg, params, is_fe); 271f7590d4fSJeeja KP skl_tplg_update_buffer_size(ctx, m_cfg); 272f7590d4fSJeeja KP 273f7590d4fSJeeja KP dev_dbg(ctx->dev, "Mconfig for widget=%s AFTER updation\n", 274f7590d4fSJeeja KP w->name); 275f7590d4fSJeeja KP 276f7590d4fSJeeja KP skl_dump_mconfig(ctx, m_cfg); 277f7590d4fSJeeja KP } 278f7590d4fSJeeja KP 279e4e2d2f4SJeeja KP /* 280e4e2d2f4SJeeja KP * A pipe can have multiple modules, each of them will be a DAPM widget as 281e4e2d2f4SJeeja KP * well. While managing a pipeline we need to get the list of all the 282e4e2d2f4SJeeja KP * widgets in a pipelines, so this helper - skl_tplg_get_pipe_widget() helps 283e4e2d2f4SJeeja KP * to get the SKL type widgets in that pipeline 284e4e2d2f4SJeeja KP */ 285e4e2d2f4SJeeja KP static int skl_tplg_alloc_pipe_widget(struct device *dev, 286e4e2d2f4SJeeja KP struct snd_soc_dapm_widget *w, struct skl_pipe *pipe) 287e4e2d2f4SJeeja KP { 288e4e2d2f4SJeeja KP struct skl_module_cfg *src_module = NULL; 289e4e2d2f4SJeeja KP struct snd_soc_dapm_path *p = NULL; 290e4e2d2f4SJeeja KP struct skl_pipe_module *p_module = NULL; 291e4e2d2f4SJeeja KP 292e4e2d2f4SJeeja KP p_module = devm_kzalloc(dev, sizeof(*p_module), GFP_KERNEL); 293e4e2d2f4SJeeja KP if (!p_module) 294e4e2d2f4SJeeja KP return -ENOMEM; 295e4e2d2f4SJeeja KP 296e4e2d2f4SJeeja KP p_module->w = w; 297e4e2d2f4SJeeja KP list_add_tail(&p_module->node, &pipe->w_list); 298e4e2d2f4SJeeja KP 299e4e2d2f4SJeeja KP snd_soc_dapm_widget_for_each_sink_path(w, p) { 300e4e2d2f4SJeeja KP if ((p->sink->priv == NULL) 301e4e2d2f4SJeeja KP && (!is_skl_dsp_widget_type(w))) 302e4e2d2f4SJeeja KP continue; 303e4e2d2f4SJeeja KP 304e4e2d2f4SJeeja KP if ((p->sink->priv != NULL) && p->connect 305e4e2d2f4SJeeja KP && is_skl_dsp_widget_type(p->sink)) { 306e4e2d2f4SJeeja KP 307e4e2d2f4SJeeja KP src_module = p->sink->priv; 308e4e2d2f4SJeeja KP if (pipe->ppl_id == src_module->pipe->ppl_id) 309e4e2d2f4SJeeja KP skl_tplg_alloc_pipe_widget(dev, 310e4e2d2f4SJeeja KP p->sink, pipe); 311e4e2d2f4SJeeja KP } 312e4e2d2f4SJeeja KP } 313e4e2d2f4SJeeja KP return 0; 314e4e2d2f4SJeeja KP } 315e4e2d2f4SJeeja KP 316e4e2d2f4SJeeja KP /* 317*abb74003SJeeja KP * some modules can have multiple params set from user control and 318*abb74003SJeeja KP * need to be set after module is initialized. If set_param flag is 319*abb74003SJeeja KP * set module params will be done after module is initialised. 320*abb74003SJeeja KP */ 321*abb74003SJeeja KP static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w, 322*abb74003SJeeja KP struct skl_sst *ctx) 323*abb74003SJeeja KP { 324*abb74003SJeeja KP int i, ret; 325*abb74003SJeeja KP struct skl_module_cfg *mconfig = w->priv; 326*abb74003SJeeja KP const struct snd_kcontrol_new *k; 327*abb74003SJeeja KP struct soc_bytes_ext *sb; 328*abb74003SJeeja KP struct skl_algo_data *bc; 329*abb74003SJeeja KP struct skl_specific_cfg *sp_cfg; 330*abb74003SJeeja KP 331*abb74003SJeeja KP if (mconfig->formats_config.caps_size > 0 && 332*abb74003SJeeja KP mconfig->formats_config.set_params) { 333*abb74003SJeeja KP sp_cfg = &mconfig->formats_config; 334*abb74003SJeeja KP ret = skl_set_module_params(ctx, sp_cfg->caps, 335*abb74003SJeeja KP sp_cfg->caps_size, 336*abb74003SJeeja KP sp_cfg->param_id, mconfig); 337*abb74003SJeeja KP if (ret < 0) 338*abb74003SJeeja KP return ret; 339*abb74003SJeeja KP } 340*abb74003SJeeja KP 341*abb74003SJeeja KP for (i = 0; i < w->num_kcontrols; i++) { 342*abb74003SJeeja KP k = &w->kcontrol_news[i]; 343*abb74003SJeeja KP if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 344*abb74003SJeeja KP sb = (void *) k->private_value; 345*abb74003SJeeja KP bc = (struct skl_algo_data *)sb->dobj.private; 346*abb74003SJeeja KP 347*abb74003SJeeja KP if (bc->set_params) { 348*abb74003SJeeja KP ret = skl_set_module_params(ctx, 349*abb74003SJeeja KP (u32 *)bc->params, bc->max, 350*abb74003SJeeja KP bc->param_id, mconfig); 351*abb74003SJeeja KP if (ret < 0) 352*abb74003SJeeja KP return ret; 353*abb74003SJeeja KP } 354*abb74003SJeeja KP } 355*abb74003SJeeja KP } 356*abb74003SJeeja KP 357*abb74003SJeeja KP return 0; 358*abb74003SJeeja KP } 359*abb74003SJeeja KP 360*abb74003SJeeja KP /* 361*abb74003SJeeja KP * some module param can set from user control and this is required as 362*abb74003SJeeja KP * when module is initailzed. if module param is required in init it is 363*abb74003SJeeja KP * identifed by set_param flag. if set_param flag is not set, then this 364*abb74003SJeeja KP * parameter needs to set as part of module init. 365*abb74003SJeeja KP */ 366*abb74003SJeeja KP static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w) 367*abb74003SJeeja KP { 368*abb74003SJeeja KP const struct snd_kcontrol_new *k; 369*abb74003SJeeja KP struct soc_bytes_ext *sb; 370*abb74003SJeeja KP struct skl_algo_data *bc; 371*abb74003SJeeja KP struct skl_module_cfg *mconfig = w->priv; 372*abb74003SJeeja KP int i; 373*abb74003SJeeja KP 374*abb74003SJeeja KP for (i = 0; i < w->num_kcontrols; i++) { 375*abb74003SJeeja KP k = &w->kcontrol_news[i]; 376*abb74003SJeeja KP if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 377*abb74003SJeeja KP sb = (struct soc_bytes_ext *)k->private_value; 378*abb74003SJeeja KP bc = (struct skl_algo_data *)sb->dobj.private; 379*abb74003SJeeja KP 380*abb74003SJeeja KP if (bc->set_params) 381*abb74003SJeeja KP continue; 382*abb74003SJeeja KP 383*abb74003SJeeja KP mconfig->formats_config.caps = (u32 *)&bc->params; 384*abb74003SJeeja KP mconfig->formats_config.caps_size = bc->max; 385*abb74003SJeeja KP 386*abb74003SJeeja KP break; 387*abb74003SJeeja KP } 388*abb74003SJeeja KP } 389*abb74003SJeeja KP 390*abb74003SJeeja KP return 0; 391*abb74003SJeeja KP } 392*abb74003SJeeja KP 393*abb74003SJeeja KP /* 394e4e2d2f4SJeeja KP * Inside a pipe instance, we can have various modules. These modules need 395e4e2d2f4SJeeja KP * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by 396e4e2d2f4SJeeja KP * skl_init_module() routine, so invoke that for all modules in a pipeline 397e4e2d2f4SJeeja KP */ 398e4e2d2f4SJeeja KP static int 399e4e2d2f4SJeeja KP skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) 400e4e2d2f4SJeeja KP { 401e4e2d2f4SJeeja KP struct skl_pipe_module *w_module; 402e4e2d2f4SJeeja KP struct snd_soc_dapm_widget *w; 403e4e2d2f4SJeeja KP struct skl_module_cfg *mconfig; 404e4e2d2f4SJeeja KP struct skl_sst *ctx = skl->skl_sst; 405e4e2d2f4SJeeja KP int ret = 0; 406e4e2d2f4SJeeja KP 407e4e2d2f4SJeeja KP list_for_each_entry(w_module, &pipe->w_list, node) { 408e4e2d2f4SJeeja KP w = w_module->w; 409e4e2d2f4SJeeja KP mconfig = w->priv; 410e4e2d2f4SJeeja KP 411e4e2d2f4SJeeja KP /* check resource available */ 412e4e2d2f4SJeeja KP if (!skl_tplg_alloc_pipe_mcps(skl, mconfig)) 413e4e2d2f4SJeeja KP return -ENOMEM; 414e4e2d2f4SJeeja KP 415f7590d4fSJeeja KP /* 416f7590d4fSJeeja KP * apply fix/conversion to module params based on 417f7590d4fSJeeja KP * FE/BE params 418f7590d4fSJeeja KP */ 419f7590d4fSJeeja KP skl_tplg_update_module_params(w, ctx); 420*abb74003SJeeja KP 421*abb74003SJeeja KP skl_tplg_set_module_init_data(w); 4229939a9c3SJeeja KP ret = skl_init_module(ctx, mconfig); 423e4e2d2f4SJeeja KP if (ret < 0) 424e4e2d2f4SJeeja KP return ret; 425*abb74003SJeeja KP 426*abb74003SJeeja KP ret = skl_tplg_set_module_params(w, ctx); 427*abb74003SJeeja KP if (ret < 0) 428*abb74003SJeeja KP return ret; 429e4e2d2f4SJeeja KP } 430e4e2d2f4SJeeja KP 431e4e2d2f4SJeeja KP return 0; 432e4e2d2f4SJeeja KP } 433d93f8e55SVinod Koul 434d93f8e55SVinod Koul /* 435d93f8e55SVinod Koul * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we 436d93f8e55SVinod Koul * need create the pipeline. So we do following: 437d93f8e55SVinod Koul * - check the resources 438d93f8e55SVinod Koul * - Create the pipeline 439d93f8e55SVinod Koul * - Initialize the modules in pipeline 440d93f8e55SVinod Koul * - finally bind all modules together 441d93f8e55SVinod Koul */ 442d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, 443d93f8e55SVinod Koul struct skl *skl) 444d93f8e55SVinod Koul { 445d93f8e55SVinod Koul int ret; 446d93f8e55SVinod Koul struct skl_module_cfg *mconfig = w->priv; 447d93f8e55SVinod Koul struct skl_pipe_module *w_module; 448d93f8e55SVinod Koul struct skl_pipe *s_pipe = mconfig->pipe; 449d93f8e55SVinod Koul struct skl_module_cfg *src_module = NULL, *dst_module; 450d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 451d93f8e55SVinod Koul 452d93f8e55SVinod Koul /* check resource available */ 453d93f8e55SVinod Koul if (!skl_tplg_alloc_pipe_mcps(skl, mconfig)) 454d93f8e55SVinod Koul return -EBUSY; 455d93f8e55SVinod Koul 456d93f8e55SVinod Koul if (!skl_tplg_alloc_pipe_mem(skl, mconfig)) 457d93f8e55SVinod Koul return -ENOMEM; 458d93f8e55SVinod Koul 459d93f8e55SVinod Koul /* 460d93f8e55SVinod Koul * Create a list of modules for pipe. 461d93f8e55SVinod Koul * This list contains modules from source to sink 462d93f8e55SVinod Koul */ 463d93f8e55SVinod Koul ret = skl_create_pipeline(ctx, mconfig->pipe); 464d93f8e55SVinod Koul if (ret < 0) 465d93f8e55SVinod Koul return ret; 466d93f8e55SVinod Koul 467d93f8e55SVinod Koul /* 468d93f8e55SVinod Koul * we create a w_list of all widgets in that pipe. This list is not 469d93f8e55SVinod Koul * freed on PMD event as widgets within a pipe are static. This 470d93f8e55SVinod Koul * saves us cycles to get widgets in pipe every time. 471d93f8e55SVinod Koul * 472d93f8e55SVinod Koul * So if we have already initialized all the widgets of a pipeline 473d93f8e55SVinod Koul * we skip, so check for list_empty and create the list if empty 474d93f8e55SVinod Koul */ 475d93f8e55SVinod Koul if (list_empty(&s_pipe->w_list)) { 476d93f8e55SVinod Koul ret = skl_tplg_alloc_pipe_widget(ctx->dev, w, s_pipe); 477d93f8e55SVinod Koul if (ret < 0) 478d93f8e55SVinod Koul return ret; 479d93f8e55SVinod Koul } 480d93f8e55SVinod Koul 481d93f8e55SVinod Koul /* Init all pipe modules from source to sink */ 482d93f8e55SVinod Koul ret = skl_tplg_init_pipe_modules(skl, s_pipe); 483d93f8e55SVinod Koul if (ret < 0) 484d93f8e55SVinod Koul return ret; 485d93f8e55SVinod Koul 486d93f8e55SVinod Koul /* Bind modules from source to sink */ 487d93f8e55SVinod Koul list_for_each_entry(w_module, &s_pipe->w_list, node) { 488d93f8e55SVinod Koul dst_module = w_module->w->priv; 489d93f8e55SVinod Koul 490d93f8e55SVinod Koul if (src_module == NULL) { 491d93f8e55SVinod Koul src_module = dst_module; 492d93f8e55SVinod Koul continue; 493d93f8e55SVinod Koul } 494d93f8e55SVinod Koul 495d93f8e55SVinod Koul ret = skl_bind_modules(ctx, src_module, dst_module); 496d93f8e55SVinod Koul if (ret < 0) 497d93f8e55SVinod Koul return ret; 498d93f8e55SVinod Koul 499d93f8e55SVinod Koul src_module = dst_module; 500d93f8e55SVinod Koul } 501d93f8e55SVinod Koul 502d93f8e55SVinod Koul return 0; 503d93f8e55SVinod Koul } 504d93f8e55SVinod Koul 5058724ff17SJeeja KP static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, 5068724ff17SJeeja KP struct skl *skl, 5078724ff17SJeeja KP struct skl_module_cfg *src_mconfig) 508d93f8e55SVinod Koul { 509d93f8e55SVinod Koul struct snd_soc_dapm_path *p; 5100ed95d76SJeeja KP struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL; 5118724ff17SJeeja KP struct skl_module_cfg *sink_mconfig; 512d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 5138724ff17SJeeja KP int ret; 514d93f8e55SVinod Koul 5158724ff17SJeeja KP snd_soc_dapm_widget_for_each_sink_path(w, p) { 516d93f8e55SVinod Koul if (!p->connect) 517d93f8e55SVinod Koul continue; 518d93f8e55SVinod Koul 519d93f8e55SVinod Koul dev_dbg(ctx->dev, "%s: src widget=%s\n", __func__, w->name); 520d93f8e55SVinod Koul dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name); 521d93f8e55SVinod Koul 5220ed95d76SJeeja KP next_sink = p->sink; 523d93f8e55SVinod Koul /* 524d93f8e55SVinod Koul * here we will check widgets in sink pipelines, so that 525d93f8e55SVinod Koul * can be any widgets type and we are only interested if 526d93f8e55SVinod Koul * they are ones used for SKL so check that first 527d93f8e55SVinod Koul */ 528d93f8e55SVinod Koul if ((p->sink->priv != NULL) && 529d93f8e55SVinod Koul is_skl_dsp_widget_type(p->sink)) { 530d93f8e55SVinod Koul 531d93f8e55SVinod Koul sink = p->sink; 532d93f8e55SVinod Koul sink_mconfig = sink->priv; 533d93f8e55SVinod Koul 534d93f8e55SVinod Koul /* Bind source to sink, mixin is always source */ 535d93f8e55SVinod Koul ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig); 536d93f8e55SVinod Koul if (ret) 537d93f8e55SVinod Koul return ret; 538d93f8e55SVinod Koul 539d93f8e55SVinod Koul /* Start sinks pipe first */ 540d93f8e55SVinod Koul if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) { 541d1730c3dSJeeja KP if (sink_mconfig->pipe->conn_type != 542d1730c3dSJeeja KP SKL_PIPE_CONN_TYPE_FE) 543d1730c3dSJeeja KP ret = skl_run_pipe(ctx, 544d1730c3dSJeeja KP sink_mconfig->pipe); 545d93f8e55SVinod Koul if (ret) 546d93f8e55SVinod Koul return ret; 547d93f8e55SVinod Koul } 548d93f8e55SVinod Koul } 549d93f8e55SVinod Koul } 550d93f8e55SVinod Koul 5518724ff17SJeeja KP if (!sink) 5520ed95d76SJeeja KP return skl_tplg_bind_sinks(next_sink, skl, src_mconfig); 5538724ff17SJeeja KP 5548724ff17SJeeja KP return 0; 5558724ff17SJeeja KP } 5568724ff17SJeeja KP 5578724ff17SJeeja KP /* 5588724ff17SJeeja KP * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA 5598724ff17SJeeja KP * we need to do following: 5608724ff17SJeeja KP * - Bind to sink pipeline 5618724ff17SJeeja KP * Since the sink pipes can be running and we don't get mixer event on 5628724ff17SJeeja KP * connect for already running mixer, we need to find the sink pipes 5638724ff17SJeeja KP * here and bind to them. This way dynamic connect works. 5648724ff17SJeeja KP * - Start sink pipeline, if not running 5658724ff17SJeeja KP * - Then run current pipe 5668724ff17SJeeja KP */ 5678724ff17SJeeja KP static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, 5688724ff17SJeeja KP struct skl *skl) 5698724ff17SJeeja KP { 5708724ff17SJeeja KP struct skl_module_cfg *src_mconfig; 5718724ff17SJeeja KP struct skl_sst *ctx = skl->skl_sst; 5728724ff17SJeeja KP int ret = 0; 5738724ff17SJeeja KP 5748724ff17SJeeja KP src_mconfig = w->priv; 5758724ff17SJeeja KP 5768724ff17SJeeja KP /* 5778724ff17SJeeja KP * find which sink it is connected to, bind with the sink, 5788724ff17SJeeja KP * if sink is not started, start sink pipe first, then start 5798724ff17SJeeja KP * this pipe 5808724ff17SJeeja KP */ 5818724ff17SJeeja KP ret = skl_tplg_bind_sinks(w, skl, src_mconfig); 5828724ff17SJeeja KP if (ret) 5838724ff17SJeeja KP return ret; 5848724ff17SJeeja KP 585d93f8e55SVinod Koul /* Start source pipe last after starting all sinks */ 586d1730c3dSJeeja KP if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) 587d1730c3dSJeeja KP return skl_run_pipe(ctx, src_mconfig->pipe); 588d93f8e55SVinod Koul 589d93f8e55SVinod Koul return 0; 590d93f8e55SVinod Koul } 591d93f8e55SVinod Koul 5928724ff17SJeeja KP static struct snd_soc_dapm_widget *skl_get_src_dsp_widget( 5938724ff17SJeeja KP struct snd_soc_dapm_widget *w, struct skl *skl) 5948724ff17SJeeja KP { 5958724ff17SJeeja KP struct snd_soc_dapm_path *p; 5968724ff17SJeeja KP struct snd_soc_dapm_widget *src_w = NULL; 5978724ff17SJeeja KP struct skl_sst *ctx = skl->skl_sst; 5988724ff17SJeeja KP 5998724ff17SJeeja KP snd_soc_dapm_widget_for_each_source_path(w, p) { 6008724ff17SJeeja KP src_w = p->source; 6018724ff17SJeeja KP if (!p->connect) 6028724ff17SJeeja KP continue; 6038724ff17SJeeja KP 6048724ff17SJeeja KP dev_dbg(ctx->dev, "sink widget=%s\n", w->name); 6058724ff17SJeeja KP dev_dbg(ctx->dev, "src widget=%s\n", p->source->name); 6068724ff17SJeeja KP 6078724ff17SJeeja KP /* 6088724ff17SJeeja KP * here we will check widgets in sink pipelines, so that can 6098724ff17SJeeja KP * be any widgets type and we are only interested if they are 6108724ff17SJeeja KP * ones used for SKL so check that first 6118724ff17SJeeja KP */ 6128724ff17SJeeja KP if ((p->source->priv != NULL) && 6138724ff17SJeeja KP is_skl_dsp_widget_type(p->source)) { 6148724ff17SJeeja KP return p->source; 6158724ff17SJeeja KP } 6168724ff17SJeeja KP } 6178724ff17SJeeja KP 6188724ff17SJeeja KP if (src_w != NULL) 6198724ff17SJeeja KP return skl_get_src_dsp_widget(src_w, skl); 6208724ff17SJeeja KP 6218724ff17SJeeja KP return NULL; 6228724ff17SJeeja KP } 6238724ff17SJeeja KP 624d93f8e55SVinod Koul /* 625d93f8e55SVinod Koul * in the Post-PMU event of mixer we need to do following: 626d93f8e55SVinod Koul * - Check if this pipe is running 627d93f8e55SVinod Koul * - if not, then 628d93f8e55SVinod Koul * - bind this pipeline to its source pipeline 629d93f8e55SVinod Koul * if source pipe is already running, this means it is a dynamic 630d93f8e55SVinod Koul * connection and we need to bind only to that pipe 631d93f8e55SVinod Koul * - start this pipeline 632d93f8e55SVinod Koul */ 633d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, 634d93f8e55SVinod Koul struct skl *skl) 635d93f8e55SVinod Koul { 636d93f8e55SVinod Koul int ret = 0; 637d93f8e55SVinod Koul struct snd_soc_dapm_widget *source, *sink; 638d93f8e55SVinod Koul struct skl_module_cfg *src_mconfig, *sink_mconfig; 639d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 640d93f8e55SVinod Koul int src_pipe_started = 0; 641d93f8e55SVinod Koul 642d93f8e55SVinod Koul sink = w; 643d93f8e55SVinod Koul sink_mconfig = sink->priv; 644d93f8e55SVinod Koul 645d93f8e55SVinod Koul /* 646d93f8e55SVinod Koul * If source pipe is already started, that means source is driving 647d93f8e55SVinod Koul * one more sink before this sink got connected, Since source is 648d93f8e55SVinod Koul * started, bind this sink to source and start this pipe. 649d93f8e55SVinod Koul */ 6508724ff17SJeeja KP source = skl_get_src_dsp_widget(w, skl); 6518724ff17SJeeja KP if (source != NULL) { 652d93f8e55SVinod Koul src_mconfig = source->priv; 653d93f8e55SVinod Koul sink_mconfig = sink->priv; 654d93f8e55SVinod Koul src_pipe_started = 1; 655d93f8e55SVinod Koul 656d93f8e55SVinod Koul /* 6578724ff17SJeeja KP * check pipe state, then no need to bind or start the 6588724ff17SJeeja KP * pipe 659d93f8e55SVinod Koul */ 660d93f8e55SVinod Koul if (src_mconfig->pipe->state != SKL_PIPE_STARTED) 661d93f8e55SVinod Koul src_pipe_started = 0; 662d93f8e55SVinod Koul } 663d93f8e55SVinod Koul 664d93f8e55SVinod Koul if (src_pipe_started) { 665d93f8e55SVinod Koul ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig); 666d93f8e55SVinod Koul if (ret) 667d93f8e55SVinod Koul return ret; 668d93f8e55SVinod Koul 669d1730c3dSJeeja KP if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) 670d93f8e55SVinod Koul ret = skl_run_pipe(ctx, sink_mconfig->pipe); 671d93f8e55SVinod Koul } 672d93f8e55SVinod Koul 673d93f8e55SVinod Koul return ret; 674d93f8e55SVinod Koul } 675d93f8e55SVinod Koul 676d93f8e55SVinod Koul /* 677d93f8e55SVinod Koul * in the Pre-PMD event of mixer we need to do following: 678d93f8e55SVinod Koul * - Stop the pipe 679d93f8e55SVinod Koul * - find the source connections and remove that from dapm_path_list 680d93f8e55SVinod Koul * - unbind with source pipelines if still connected 681d93f8e55SVinod Koul */ 682d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w, 683d93f8e55SVinod Koul struct skl *skl) 684d93f8e55SVinod Koul { 685d93f8e55SVinod Koul struct skl_module_cfg *src_mconfig, *sink_mconfig; 686ce1b5551SJeeja KP int ret = 0, i; 687d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 688d93f8e55SVinod Koul 689ce1b5551SJeeja KP sink_mconfig = w->priv; 690d93f8e55SVinod Koul 691d93f8e55SVinod Koul /* Stop the pipe */ 692d93f8e55SVinod Koul ret = skl_stop_pipe(ctx, sink_mconfig->pipe); 693d93f8e55SVinod Koul if (ret) 694d93f8e55SVinod Koul return ret; 695d93f8e55SVinod Koul 696ce1b5551SJeeja KP for (i = 0; i < sink_mconfig->max_in_queue; i++) { 697ce1b5551SJeeja KP if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) { 698ce1b5551SJeeja KP src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg; 699ce1b5551SJeeja KP if (!src_mconfig) 700ce1b5551SJeeja KP continue; 701d93f8e55SVinod Koul /* 702ce1b5551SJeeja KP * If path_found == 1, that means pmd for source 703ce1b5551SJeeja KP * pipe has not occurred, source is connected to 704ce1b5551SJeeja KP * some other sink. so its responsibility of sink 705ce1b5551SJeeja KP * to unbind itself from source. 706d93f8e55SVinod Koul */ 707d93f8e55SVinod Koul ret = skl_stop_pipe(ctx, src_mconfig->pipe); 708d93f8e55SVinod Koul if (ret < 0) 709d93f8e55SVinod Koul return ret; 710d93f8e55SVinod Koul 711ce1b5551SJeeja KP ret = skl_unbind_modules(ctx, 712ce1b5551SJeeja KP src_mconfig, sink_mconfig); 713ce1b5551SJeeja KP } 714d93f8e55SVinod Koul } 715d93f8e55SVinod Koul 716d93f8e55SVinod Koul return ret; 717d93f8e55SVinod Koul } 718d93f8e55SVinod Koul 719d93f8e55SVinod Koul /* 720d93f8e55SVinod Koul * in the Post-PMD event of mixer we need to do following: 721d93f8e55SVinod Koul * - Free the mcps used 722d93f8e55SVinod Koul * - Free the mem used 723d93f8e55SVinod Koul * - Unbind the modules within the pipeline 724d93f8e55SVinod Koul * - Delete the pipeline (modules are not required to be explicitly 725d93f8e55SVinod Koul * deleted, pipeline delete is enough here 726d93f8e55SVinod Koul */ 727d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, 728d93f8e55SVinod Koul struct skl *skl) 729d93f8e55SVinod Koul { 730d93f8e55SVinod Koul struct skl_module_cfg *mconfig = w->priv; 731d93f8e55SVinod Koul struct skl_pipe_module *w_module; 732d93f8e55SVinod Koul struct skl_module_cfg *src_module = NULL, *dst_module; 733d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 734d93f8e55SVinod Koul struct skl_pipe *s_pipe = mconfig->pipe; 735d93f8e55SVinod Koul int ret = 0; 736d93f8e55SVinod Koul 737d93f8e55SVinod Koul skl_tplg_free_pipe_mcps(skl, mconfig); 73865976878SVinod Koul skl_tplg_free_pipe_mem(skl, mconfig); 739d93f8e55SVinod Koul 740d93f8e55SVinod Koul list_for_each_entry(w_module, &s_pipe->w_list, node) { 741d93f8e55SVinod Koul dst_module = w_module->w->priv; 742d93f8e55SVinod Koul 7437ae3cb15SVinod Koul skl_tplg_free_pipe_mcps(skl, dst_module); 744d93f8e55SVinod Koul if (src_module == NULL) { 745d93f8e55SVinod Koul src_module = dst_module; 746d93f8e55SVinod Koul continue; 747d93f8e55SVinod Koul } 748d93f8e55SVinod Koul 749d93f8e55SVinod Koul ret = skl_unbind_modules(ctx, src_module, dst_module); 750d93f8e55SVinod Koul if (ret < 0) 751d93f8e55SVinod Koul return ret; 752d93f8e55SVinod Koul 753d93f8e55SVinod Koul src_module = dst_module; 754d93f8e55SVinod Koul } 755d93f8e55SVinod Koul 756d93f8e55SVinod Koul ret = skl_delete_pipe(ctx, mconfig->pipe); 757d93f8e55SVinod Koul 758d93f8e55SVinod Koul return ret; 759d93f8e55SVinod Koul } 760d93f8e55SVinod Koul 761d93f8e55SVinod Koul /* 762d93f8e55SVinod Koul * in the Post-PMD event of PGA we need to do following: 763d93f8e55SVinod Koul * - Free the mcps used 764d93f8e55SVinod Koul * - Stop the pipeline 765d93f8e55SVinod Koul * - In source pipe is connected, unbind with source pipelines 766d93f8e55SVinod Koul */ 767d93f8e55SVinod Koul static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, 768d93f8e55SVinod Koul struct skl *skl) 769d93f8e55SVinod Koul { 770d93f8e55SVinod Koul struct skl_module_cfg *src_mconfig, *sink_mconfig; 771ce1b5551SJeeja KP int ret = 0, i; 772d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 773d93f8e55SVinod Koul 774ce1b5551SJeeja KP src_mconfig = w->priv; 775d93f8e55SVinod Koul 776d93f8e55SVinod Koul /* Stop the pipe since this is a mixin module */ 777d93f8e55SVinod Koul ret = skl_stop_pipe(ctx, src_mconfig->pipe); 778d93f8e55SVinod Koul if (ret) 779d93f8e55SVinod Koul return ret; 780d93f8e55SVinod Koul 781ce1b5551SJeeja KP for (i = 0; i < src_mconfig->max_out_queue; i++) { 782ce1b5551SJeeja KP if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) { 783ce1b5551SJeeja KP sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg; 784ce1b5551SJeeja KP if (!sink_mconfig) 785ce1b5551SJeeja KP continue; 786d93f8e55SVinod Koul /* 787ce1b5551SJeeja KP * This is a connecter and if path is found that means 788d93f8e55SVinod Koul * unbind between source and sink has not happened yet 789d93f8e55SVinod Koul */ 790ce1b5551SJeeja KP ret = skl_stop_pipe(ctx, sink_mconfig->pipe); 791d93f8e55SVinod Koul if (ret < 0) 792d93f8e55SVinod Koul return ret; 793ce1b5551SJeeja KP ret = skl_unbind_modules(ctx, src_mconfig, 794ce1b5551SJeeja KP sink_mconfig); 795ce1b5551SJeeja KP } 796d93f8e55SVinod Koul } 797d93f8e55SVinod Koul 798d93f8e55SVinod Koul return ret; 799d93f8e55SVinod Koul } 800d93f8e55SVinod Koul 801d93f8e55SVinod Koul /* 802d93f8e55SVinod Koul * In modelling, we assume there will be ONLY one mixer in a pipeline. If 803d93f8e55SVinod Koul * mixer is not required then it is treated as static mixer aka vmixer with 804d93f8e55SVinod Koul * a hard path to source module 805d93f8e55SVinod Koul * So we don't need to check if source is started or not as hard path puts 806d93f8e55SVinod Koul * dependency on each other 807d93f8e55SVinod Koul */ 808d93f8e55SVinod Koul static int skl_tplg_vmixer_event(struct snd_soc_dapm_widget *w, 809d93f8e55SVinod Koul struct snd_kcontrol *k, int event) 810d93f8e55SVinod Koul { 811d93f8e55SVinod Koul struct snd_soc_dapm_context *dapm = w->dapm; 812d93f8e55SVinod Koul struct skl *skl = get_skl_ctx(dapm->dev); 813d93f8e55SVinod Koul 814d93f8e55SVinod Koul switch (event) { 815d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMU: 816d93f8e55SVinod Koul return skl_tplg_mixer_dapm_pre_pmu_event(w, skl); 817d93f8e55SVinod Koul 818d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMD: 819d93f8e55SVinod Koul return skl_tplg_mixer_dapm_post_pmd_event(w, skl); 820d93f8e55SVinod Koul } 821d93f8e55SVinod Koul 822d93f8e55SVinod Koul return 0; 823d93f8e55SVinod Koul } 824d93f8e55SVinod Koul 825d93f8e55SVinod Koul /* 826d93f8e55SVinod Koul * In modelling, we assume there will be ONLY one mixer in a pipeline. If a 827d93f8e55SVinod Koul * second one is required that is created as another pipe entity. 828d93f8e55SVinod Koul * The mixer is responsible for pipe management and represent a pipeline 829d93f8e55SVinod Koul * instance 830d93f8e55SVinod Koul */ 831d93f8e55SVinod Koul static int skl_tplg_mixer_event(struct snd_soc_dapm_widget *w, 832d93f8e55SVinod Koul struct snd_kcontrol *k, int event) 833d93f8e55SVinod Koul { 834d93f8e55SVinod Koul struct snd_soc_dapm_context *dapm = w->dapm; 835d93f8e55SVinod Koul struct skl *skl = get_skl_ctx(dapm->dev); 836d93f8e55SVinod Koul 837d93f8e55SVinod Koul switch (event) { 838d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMU: 839d93f8e55SVinod Koul return skl_tplg_mixer_dapm_pre_pmu_event(w, skl); 840d93f8e55SVinod Koul 841d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMU: 842d93f8e55SVinod Koul return skl_tplg_mixer_dapm_post_pmu_event(w, skl); 843d93f8e55SVinod Koul 844d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMD: 845d93f8e55SVinod Koul return skl_tplg_mixer_dapm_pre_pmd_event(w, skl); 846d93f8e55SVinod Koul 847d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMD: 848d93f8e55SVinod Koul return skl_tplg_mixer_dapm_post_pmd_event(w, skl); 849d93f8e55SVinod Koul } 850d93f8e55SVinod Koul 851d93f8e55SVinod Koul return 0; 852d93f8e55SVinod Koul } 853d93f8e55SVinod Koul 854d93f8e55SVinod Koul /* 855d93f8e55SVinod Koul * In modelling, we assumed rest of the modules in pipeline are PGA. But we 856d93f8e55SVinod Koul * are interested in last PGA (leaf PGA) in a pipeline to disconnect with 857d93f8e55SVinod Koul * the sink when it is running (two FE to one BE or one FE to two BE) 858d93f8e55SVinod Koul * scenarios 859d93f8e55SVinod Koul */ 860d93f8e55SVinod Koul static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w, 861d93f8e55SVinod Koul struct snd_kcontrol *k, int event) 862d93f8e55SVinod Koul 863d93f8e55SVinod Koul { 864d93f8e55SVinod Koul struct snd_soc_dapm_context *dapm = w->dapm; 865d93f8e55SVinod Koul struct skl *skl = get_skl_ctx(dapm->dev); 866d93f8e55SVinod Koul 867d93f8e55SVinod Koul switch (event) { 868d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMU: 869d93f8e55SVinod Koul return skl_tplg_pga_dapm_pre_pmu_event(w, skl); 870d93f8e55SVinod Koul 871d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMD: 872d93f8e55SVinod Koul return skl_tplg_pga_dapm_post_pmd_event(w, skl); 873d93f8e55SVinod Koul } 874d93f8e55SVinod Koul 875d93f8e55SVinod Koul return 0; 876d93f8e55SVinod Koul } 877cfb0a873SVinod Koul 878cfb0a873SVinod Koul /* 879cfb0a873SVinod Koul * The FE params are passed by hw_params of the DAI. 880cfb0a873SVinod Koul * On hw_params, the params are stored in Gateway module of the FE and we 881cfb0a873SVinod Koul * need to calculate the format in DSP module configuration, that 882cfb0a873SVinod Koul * conversion is done here 883cfb0a873SVinod Koul */ 884cfb0a873SVinod Koul int skl_tplg_update_pipe_params(struct device *dev, 885cfb0a873SVinod Koul struct skl_module_cfg *mconfig, 886cfb0a873SVinod Koul struct skl_pipe_params *params) 887cfb0a873SVinod Koul { 888cfb0a873SVinod Koul struct skl_pipe *pipe = mconfig->pipe; 889cfb0a873SVinod Koul struct skl_module_fmt *format = NULL; 890cfb0a873SVinod Koul 891cfb0a873SVinod Koul memcpy(pipe->p_params, params, sizeof(*params)); 892cfb0a873SVinod Koul 893cfb0a873SVinod Koul if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) 8944cd9899fSHardik T Shah format = &mconfig->in_fmt[0]; 895cfb0a873SVinod Koul else 8964cd9899fSHardik T Shah format = &mconfig->out_fmt[0]; 897cfb0a873SVinod Koul 898cfb0a873SVinod Koul /* set the hw_params */ 899cfb0a873SVinod Koul format->s_freq = params->s_freq; 900cfb0a873SVinod Koul format->channels = params->ch; 901cfb0a873SVinod Koul format->valid_bit_depth = skl_get_bit_depth(params->s_fmt); 902cfb0a873SVinod Koul 903cfb0a873SVinod Koul /* 904cfb0a873SVinod Koul * 16 bit is 16 bit container whereas 24 bit is in 32 bit 905cfb0a873SVinod Koul * container so update bit depth accordingly 906cfb0a873SVinod Koul */ 907cfb0a873SVinod Koul switch (format->valid_bit_depth) { 908cfb0a873SVinod Koul case SKL_DEPTH_16BIT: 909cfb0a873SVinod Koul format->bit_depth = format->valid_bit_depth; 910cfb0a873SVinod Koul break; 911cfb0a873SVinod Koul 912cfb0a873SVinod Koul case SKL_DEPTH_24BIT: 9136654f39eSJeeja KP case SKL_DEPTH_32BIT: 914cfb0a873SVinod Koul format->bit_depth = SKL_DEPTH_32BIT; 915cfb0a873SVinod Koul break; 916cfb0a873SVinod Koul 917cfb0a873SVinod Koul default: 918cfb0a873SVinod Koul dev_err(dev, "Invalid bit depth %x for pipe\n", 919cfb0a873SVinod Koul format->valid_bit_depth); 920cfb0a873SVinod Koul return -EINVAL; 921cfb0a873SVinod Koul } 922cfb0a873SVinod Koul 923cfb0a873SVinod Koul if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { 924cfb0a873SVinod Koul mconfig->ibs = (format->s_freq / 1000) * 925cfb0a873SVinod Koul (format->channels) * 926cfb0a873SVinod Koul (format->bit_depth >> 3); 927cfb0a873SVinod Koul } else { 928cfb0a873SVinod Koul mconfig->obs = (format->s_freq / 1000) * 929cfb0a873SVinod Koul (format->channels) * 930cfb0a873SVinod Koul (format->bit_depth >> 3); 931cfb0a873SVinod Koul } 932cfb0a873SVinod Koul 933cfb0a873SVinod Koul return 0; 934cfb0a873SVinod Koul } 935cfb0a873SVinod Koul 936cfb0a873SVinod Koul /* 937cfb0a873SVinod Koul * Query the module config for the FE DAI 938cfb0a873SVinod Koul * This is used to find the hw_params set for that DAI and apply to FE 939cfb0a873SVinod Koul * pipeline 940cfb0a873SVinod Koul */ 941cfb0a873SVinod Koul struct skl_module_cfg * 942cfb0a873SVinod Koul skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream) 943cfb0a873SVinod Koul { 944cfb0a873SVinod Koul struct snd_soc_dapm_widget *w; 945cfb0a873SVinod Koul struct snd_soc_dapm_path *p = NULL; 946cfb0a873SVinod Koul 947cfb0a873SVinod Koul if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 948cfb0a873SVinod Koul w = dai->playback_widget; 949f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_sink_path(w, p) { 950cfb0a873SVinod Koul if (p->connect && p->sink->power && 951a28f51dbSJeeja KP !is_skl_dsp_widget_type(p->sink)) 952cfb0a873SVinod Koul continue; 953cfb0a873SVinod Koul 954cfb0a873SVinod Koul if (p->sink->priv) { 955cfb0a873SVinod Koul dev_dbg(dai->dev, "set params for %s\n", 956cfb0a873SVinod Koul p->sink->name); 957cfb0a873SVinod Koul return p->sink->priv; 958cfb0a873SVinod Koul } 959cfb0a873SVinod Koul } 960cfb0a873SVinod Koul } else { 961cfb0a873SVinod Koul w = dai->capture_widget; 962f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_source_path(w, p) { 963cfb0a873SVinod Koul if (p->connect && p->source->power && 964a28f51dbSJeeja KP !is_skl_dsp_widget_type(p->source)) 965cfb0a873SVinod Koul continue; 966cfb0a873SVinod Koul 967cfb0a873SVinod Koul if (p->source->priv) { 968cfb0a873SVinod Koul dev_dbg(dai->dev, "set params for %s\n", 969cfb0a873SVinod Koul p->source->name); 970cfb0a873SVinod Koul return p->source->priv; 971cfb0a873SVinod Koul } 972cfb0a873SVinod Koul } 973cfb0a873SVinod Koul } 974cfb0a873SVinod Koul 975cfb0a873SVinod Koul return NULL; 976cfb0a873SVinod Koul } 977cfb0a873SVinod Koul 978cfb0a873SVinod Koul static u8 skl_tplg_be_link_type(int dev_type) 979cfb0a873SVinod Koul { 980cfb0a873SVinod Koul int ret; 981cfb0a873SVinod Koul 982cfb0a873SVinod Koul switch (dev_type) { 983cfb0a873SVinod Koul case SKL_DEVICE_BT: 984cfb0a873SVinod Koul ret = NHLT_LINK_SSP; 985cfb0a873SVinod Koul break; 986cfb0a873SVinod Koul 987cfb0a873SVinod Koul case SKL_DEVICE_DMIC: 988cfb0a873SVinod Koul ret = NHLT_LINK_DMIC; 989cfb0a873SVinod Koul break; 990cfb0a873SVinod Koul 991cfb0a873SVinod Koul case SKL_DEVICE_I2S: 992cfb0a873SVinod Koul ret = NHLT_LINK_SSP; 993cfb0a873SVinod Koul break; 994cfb0a873SVinod Koul 995cfb0a873SVinod Koul case SKL_DEVICE_HDALINK: 996cfb0a873SVinod Koul ret = NHLT_LINK_HDA; 997cfb0a873SVinod Koul break; 998cfb0a873SVinod Koul 999cfb0a873SVinod Koul default: 1000cfb0a873SVinod Koul ret = NHLT_LINK_INVALID; 1001cfb0a873SVinod Koul break; 1002cfb0a873SVinod Koul } 1003cfb0a873SVinod Koul 1004cfb0a873SVinod Koul return ret; 1005cfb0a873SVinod Koul } 1006cfb0a873SVinod Koul 1007cfb0a873SVinod Koul /* 1008cfb0a873SVinod Koul * Fill the BE gateway parameters 1009cfb0a873SVinod Koul * The BE gateway expects a blob of parameters which are kept in the ACPI 1010cfb0a873SVinod Koul * NHLT blob, so query the blob for interface type (i2s/pdm) and instance. 1011cfb0a873SVinod Koul * The port can have multiple settings so pick based on the PCM 1012cfb0a873SVinod Koul * parameters 1013cfb0a873SVinod Koul */ 1014cfb0a873SVinod Koul static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai, 1015cfb0a873SVinod Koul struct skl_module_cfg *mconfig, 1016cfb0a873SVinod Koul struct skl_pipe_params *params) 1017cfb0a873SVinod Koul { 1018cfb0a873SVinod Koul struct skl_pipe *pipe = mconfig->pipe; 1019cfb0a873SVinod Koul struct nhlt_specific_cfg *cfg; 1020cfb0a873SVinod Koul struct skl *skl = get_skl_ctx(dai->dev); 1021cfb0a873SVinod Koul int link_type = skl_tplg_be_link_type(mconfig->dev_type); 1022cfb0a873SVinod Koul 1023cfb0a873SVinod Koul memcpy(pipe->p_params, params, sizeof(*params)); 1024cfb0a873SVinod Koul 1025b30c275eSJeeja KP if (link_type == NHLT_LINK_HDA) 1026b30c275eSJeeja KP return 0; 1027b30c275eSJeeja KP 1028cfb0a873SVinod Koul /* update the blob based on virtual bus_id*/ 1029cfb0a873SVinod Koul cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type, 1030cfb0a873SVinod Koul params->s_fmt, params->ch, 1031cfb0a873SVinod Koul params->s_freq, params->stream); 1032cfb0a873SVinod Koul if (cfg) { 1033cfb0a873SVinod Koul mconfig->formats_config.caps_size = cfg->size; 1034bc03281aSJeeja KP mconfig->formats_config.caps = (u32 *) &cfg->caps; 1035cfb0a873SVinod Koul } else { 1036cfb0a873SVinod Koul dev_err(dai->dev, "Blob NULL for id %x type %d dirn %d\n", 1037cfb0a873SVinod Koul mconfig->vbus_id, link_type, 1038cfb0a873SVinod Koul params->stream); 1039cfb0a873SVinod Koul dev_err(dai->dev, "PCM: ch %d, freq %d, fmt %d\n", 1040cfb0a873SVinod Koul params->ch, params->s_freq, params->s_fmt); 1041cfb0a873SVinod Koul return -EINVAL; 1042cfb0a873SVinod Koul } 1043cfb0a873SVinod Koul 1044cfb0a873SVinod Koul return 0; 1045cfb0a873SVinod Koul } 1046cfb0a873SVinod Koul 1047cfb0a873SVinod Koul static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai, 1048cfb0a873SVinod Koul struct snd_soc_dapm_widget *w, 1049cfb0a873SVinod Koul struct skl_pipe_params *params) 1050cfb0a873SVinod Koul { 1051cfb0a873SVinod Koul struct snd_soc_dapm_path *p; 10524d8adccbSSubhransu S. Prusty int ret = -EIO; 1053cfb0a873SVinod Koul 1054f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_source_path(w, p) { 1055cfb0a873SVinod Koul if (p->connect && is_skl_dsp_widget_type(p->source) && 1056cfb0a873SVinod Koul p->source->priv) { 1057cfb0a873SVinod Koul 10589a03cb49SJeeja KP ret = skl_tplg_be_fill_pipe_params(dai, 10599a03cb49SJeeja KP p->source->priv, params); 10604d8adccbSSubhransu S. Prusty if (ret < 0) 10614d8adccbSSubhransu S. Prusty return ret; 1062cfb0a873SVinod Koul } else { 10639a03cb49SJeeja KP ret = skl_tplg_be_set_src_pipe_params(dai, 10649a03cb49SJeeja KP p->source, params); 10654d8adccbSSubhransu S. Prusty if (ret < 0) 10664d8adccbSSubhransu S. Prusty return ret; 1067cfb0a873SVinod Koul } 1068cfb0a873SVinod Koul } 1069cfb0a873SVinod Koul 10704d8adccbSSubhransu S. Prusty return ret; 1071cfb0a873SVinod Koul } 1072cfb0a873SVinod Koul 1073cfb0a873SVinod Koul static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai, 1074cfb0a873SVinod Koul struct snd_soc_dapm_widget *w, struct skl_pipe_params *params) 1075cfb0a873SVinod Koul { 1076cfb0a873SVinod Koul struct snd_soc_dapm_path *p = NULL; 10774d8adccbSSubhransu S. Prusty int ret = -EIO; 1078cfb0a873SVinod Koul 1079f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_sink_path(w, p) { 1080cfb0a873SVinod Koul if (p->connect && is_skl_dsp_widget_type(p->sink) && 1081cfb0a873SVinod Koul p->sink->priv) { 1082cfb0a873SVinod Koul 10839a03cb49SJeeja KP ret = skl_tplg_be_fill_pipe_params(dai, 10849a03cb49SJeeja KP p->sink->priv, params); 10854d8adccbSSubhransu S. Prusty if (ret < 0) 10864d8adccbSSubhransu S. Prusty return ret; 10874d8adccbSSubhransu S. Prusty } else { 10884d8adccbSSubhransu S. Prusty ret = skl_tplg_be_set_sink_pipe_params( 1089cfb0a873SVinod Koul dai, p->sink, params); 10904d8adccbSSubhransu S. Prusty if (ret < 0) 10914d8adccbSSubhransu S. Prusty return ret; 1092cfb0a873SVinod Koul } 1093cfb0a873SVinod Koul } 1094cfb0a873SVinod Koul 10954d8adccbSSubhransu S. Prusty return ret; 1096cfb0a873SVinod Koul } 1097cfb0a873SVinod Koul 1098cfb0a873SVinod Koul /* 1099cfb0a873SVinod Koul * BE hw_params can be a source parameters (capture) or sink parameters 1100cfb0a873SVinod Koul * (playback). Based on sink and source we need to either find the source 1101cfb0a873SVinod Koul * list or the sink list and set the pipeline parameters 1102cfb0a873SVinod Koul */ 1103cfb0a873SVinod Koul int skl_tplg_be_update_params(struct snd_soc_dai *dai, 1104cfb0a873SVinod Koul struct skl_pipe_params *params) 1105cfb0a873SVinod Koul { 1106cfb0a873SVinod Koul struct snd_soc_dapm_widget *w; 1107cfb0a873SVinod Koul 1108cfb0a873SVinod Koul if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { 1109cfb0a873SVinod Koul w = dai->playback_widget; 1110cfb0a873SVinod Koul 1111cfb0a873SVinod Koul return skl_tplg_be_set_src_pipe_params(dai, w, params); 1112cfb0a873SVinod Koul 1113cfb0a873SVinod Koul } else { 1114cfb0a873SVinod Koul w = dai->capture_widget; 1115cfb0a873SVinod Koul 1116cfb0a873SVinod Koul return skl_tplg_be_set_sink_pipe_params(dai, w, params); 1117cfb0a873SVinod Koul } 1118cfb0a873SVinod Koul 1119cfb0a873SVinod Koul return 0; 1120cfb0a873SVinod Koul } 11213af36706SVinod Koul 11223af36706SVinod Koul static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = { 11233af36706SVinod Koul {SKL_MIXER_EVENT, skl_tplg_mixer_event}, 11243af36706SVinod Koul {SKL_VMIXER_EVENT, skl_tplg_vmixer_event}, 11253af36706SVinod Koul {SKL_PGA_EVENT, skl_tplg_pga_event}, 11263af36706SVinod Koul }; 11273af36706SVinod Koul 11283af36706SVinod Koul /* 11293af36706SVinod Koul * The topology binary passes the pin info for a module so initialize the pin 11303af36706SVinod Koul * info passed into module instance 11313af36706SVinod Koul */ 11326abca1d7SJeeja KP static void skl_fill_module_pin_info(struct skl_dfw_module_pin *dfw_pin, 11333af36706SVinod Koul struct skl_module_pin *m_pin, 11346abca1d7SJeeja KP bool is_dynamic, int max_pin) 11353af36706SVinod Koul { 11363af36706SVinod Koul int i; 11373af36706SVinod Koul 11383af36706SVinod Koul for (i = 0; i < max_pin; i++) { 11396abca1d7SJeeja KP m_pin[i].id.module_id = dfw_pin[i].module_id; 11406abca1d7SJeeja KP m_pin[i].id.instance_id = dfw_pin[i].instance_id; 11413af36706SVinod Koul m_pin[i].in_use = false; 11426abca1d7SJeeja KP m_pin[i].is_dynamic = is_dynamic; 11434f745708SJeeja KP m_pin[i].pin_state = SKL_PIN_UNBIND; 11443af36706SVinod Koul } 11453af36706SVinod Koul } 11463af36706SVinod Koul 11473af36706SVinod Koul /* 11483af36706SVinod Koul * Add pipeline from topology binary into driver pipeline list 11493af36706SVinod Koul * 11503af36706SVinod Koul * If already added we return that instance 11513af36706SVinod Koul * Otherwise we create a new instance and add into driver list 11523af36706SVinod Koul */ 11533af36706SVinod Koul static struct skl_pipe *skl_tplg_add_pipe(struct device *dev, 11543af36706SVinod Koul struct skl *skl, struct skl_dfw_pipe *dfw_pipe) 11553af36706SVinod Koul { 11563af36706SVinod Koul struct skl_pipeline *ppl; 11573af36706SVinod Koul struct skl_pipe *pipe; 11583af36706SVinod Koul struct skl_pipe_params *params; 11593af36706SVinod Koul 11603af36706SVinod Koul list_for_each_entry(ppl, &skl->ppl_list, node) { 11613af36706SVinod Koul if (ppl->pipe->ppl_id == dfw_pipe->pipe_id) 11623af36706SVinod Koul return ppl->pipe; 11633af36706SVinod Koul } 11643af36706SVinod Koul 11653af36706SVinod Koul ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL); 11663af36706SVinod Koul if (!ppl) 11673af36706SVinod Koul return NULL; 11683af36706SVinod Koul 11693af36706SVinod Koul pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL); 11703af36706SVinod Koul if (!pipe) 11713af36706SVinod Koul return NULL; 11723af36706SVinod Koul 11733af36706SVinod Koul params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL); 11743af36706SVinod Koul if (!params) 11753af36706SVinod Koul return NULL; 11763af36706SVinod Koul 11773af36706SVinod Koul pipe->ppl_id = dfw_pipe->pipe_id; 11783af36706SVinod Koul pipe->memory_pages = dfw_pipe->memory_pages; 11793af36706SVinod Koul pipe->pipe_priority = dfw_pipe->pipe_priority; 11803af36706SVinod Koul pipe->conn_type = dfw_pipe->conn_type; 11813af36706SVinod Koul pipe->state = SKL_PIPE_INVALID; 11823af36706SVinod Koul pipe->p_params = params; 11833af36706SVinod Koul INIT_LIST_HEAD(&pipe->w_list); 11843af36706SVinod Koul 11853af36706SVinod Koul ppl->pipe = pipe; 11863af36706SVinod Koul list_add(&ppl->node, &skl->ppl_list); 11873af36706SVinod Koul 11883af36706SVinod Koul return ppl->pipe; 11893af36706SVinod Koul } 11903af36706SVinod Koul 11914cd9899fSHardik T Shah static void skl_tplg_fill_fmt(struct skl_module_fmt *dst_fmt, 11924cd9899fSHardik T Shah struct skl_dfw_module_fmt *src_fmt, 11934cd9899fSHardik T Shah int pins) 11944cd9899fSHardik T Shah { 11954cd9899fSHardik T Shah int i; 11964cd9899fSHardik T Shah 11974cd9899fSHardik T Shah for (i = 0; i < pins; i++) { 11984cd9899fSHardik T Shah dst_fmt[i].channels = src_fmt[i].channels; 11994cd9899fSHardik T Shah dst_fmt[i].s_freq = src_fmt[i].freq; 12004cd9899fSHardik T Shah dst_fmt[i].bit_depth = src_fmt[i].bit_depth; 12014cd9899fSHardik T Shah dst_fmt[i].valid_bit_depth = src_fmt[i].valid_bit_depth; 12024cd9899fSHardik T Shah dst_fmt[i].ch_cfg = src_fmt[i].ch_cfg; 12034cd9899fSHardik T Shah dst_fmt[i].ch_map = src_fmt[i].ch_map; 12044cd9899fSHardik T Shah dst_fmt[i].interleaving_style = src_fmt[i].interleaving_style; 12054cd9899fSHardik T Shah dst_fmt[i].sample_type = src_fmt[i].sample_type; 12064cd9899fSHardik T Shah } 12074cd9899fSHardik T Shah } 12084cd9899fSHardik T Shah 12093af36706SVinod Koul /* 12103af36706SVinod Koul * Topology core widget load callback 12113af36706SVinod Koul * 12123af36706SVinod Koul * This is used to save the private data for each widget which gives 12133af36706SVinod Koul * information to the driver about module and pipeline parameters which DSP 12143af36706SVinod Koul * FW expects like ids, resource values, formats etc 12153af36706SVinod Koul */ 12163af36706SVinod Koul static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, 12173af36706SVinod Koul struct snd_soc_dapm_widget *w, 12183af36706SVinod Koul struct snd_soc_tplg_dapm_widget *tplg_w) 12193af36706SVinod Koul { 12203af36706SVinod Koul int ret; 12213af36706SVinod Koul struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt); 12223af36706SVinod Koul struct skl *skl = ebus_to_skl(ebus); 12233af36706SVinod Koul struct hdac_bus *bus = ebus_to_hbus(ebus); 12243af36706SVinod Koul struct skl_module_cfg *mconfig; 12253af36706SVinod Koul struct skl_pipe *pipe; 1226b663a8c5SJeeja KP struct skl_dfw_module *dfw_config = 1227b663a8c5SJeeja KP (struct skl_dfw_module *)tplg_w->priv.data; 12283af36706SVinod Koul 12293af36706SVinod Koul if (!tplg_w->priv.size) 12303af36706SVinod Koul goto bind_event; 12313af36706SVinod Koul 12323af36706SVinod Koul mconfig = devm_kzalloc(bus->dev, sizeof(*mconfig), GFP_KERNEL); 12333af36706SVinod Koul 12343af36706SVinod Koul if (!mconfig) 12353af36706SVinod Koul return -ENOMEM; 12363af36706SVinod Koul 12373af36706SVinod Koul w->priv = mconfig; 12383af36706SVinod Koul mconfig->id.module_id = dfw_config->module_id; 12393af36706SVinod Koul mconfig->id.instance_id = dfw_config->instance_id; 12403af36706SVinod Koul mconfig->mcps = dfw_config->max_mcps; 12413af36706SVinod Koul mconfig->ibs = dfw_config->ibs; 12423af36706SVinod Koul mconfig->obs = dfw_config->obs; 12433af36706SVinod Koul mconfig->core_id = dfw_config->core_id; 12443af36706SVinod Koul mconfig->max_in_queue = dfw_config->max_in_queue; 12453af36706SVinod Koul mconfig->max_out_queue = dfw_config->max_out_queue; 12463af36706SVinod Koul mconfig->is_loadable = dfw_config->is_loadable; 12474cd9899fSHardik T Shah skl_tplg_fill_fmt(mconfig->in_fmt, dfw_config->in_fmt, 12484cd9899fSHardik T Shah MODULE_MAX_IN_PINS); 12494cd9899fSHardik T Shah skl_tplg_fill_fmt(mconfig->out_fmt, dfw_config->out_fmt, 12504cd9899fSHardik T Shah MODULE_MAX_OUT_PINS); 12514cd9899fSHardik T Shah 12523af36706SVinod Koul mconfig->params_fixup = dfw_config->params_fixup; 12533af36706SVinod Koul mconfig->converter = dfw_config->converter; 12543af36706SVinod Koul mconfig->m_type = dfw_config->module_type; 12553af36706SVinod Koul mconfig->vbus_id = dfw_config->vbus_id; 12563af36706SVinod Koul 12573af36706SVinod Koul pipe = skl_tplg_add_pipe(bus->dev, skl, &dfw_config->pipe); 12583af36706SVinod Koul if (pipe) 12593af36706SVinod Koul mconfig->pipe = pipe; 12603af36706SVinod Koul 12613af36706SVinod Koul mconfig->dev_type = dfw_config->dev_type; 12623af36706SVinod Koul mconfig->hw_conn_type = dfw_config->hw_conn_type; 12633af36706SVinod Koul mconfig->time_slot = dfw_config->time_slot; 12643af36706SVinod Koul mconfig->formats_config.caps_size = dfw_config->caps.caps_size; 12653af36706SVinod Koul 126665aecfa8SHardik T Shah if (dfw_config->is_loadable) 126765aecfa8SHardik T Shah memcpy(mconfig->guid, dfw_config->uuid, 126865aecfa8SHardik T Shah ARRAY_SIZE(dfw_config->uuid)); 126965aecfa8SHardik T Shah 12704cd9899fSHardik T Shah mconfig->m_in_pin = devm_kzalloc(bus->dev, (mconfig->max_in_queue) * 12713af36706SVinod Koul sizeof(*mconfig->m_in_pin), 12723af36706SVinod Koul GFP_KERNEL); 12733af36706SVinod Koul if (!mconfig->m_in_pin) 12743af36706SVinod Koul return -ENOMEM; 12753af36706SVinod Koul 12766abca1d7SJeeja KP mconfig->m_out_pin = devm_kzalloc(bus->dev, (mconfig->max_out_queue) * 12773af36706SVinod Koul sizeof(*mconfig->m_out_pin), 12783af36706SVinod Koul GFP_KERNEL); 12793af36706SVinod Koul if (!mconfig->m_out_pin) 12803af36706SVinod Koul return -ENOMEM; 12813af36706SVinod Koul 12826abca1d7SJeeja KP skl_fill_module_pin_info(dfw_config->in_pin, mconfig->m_in_pin, 12836abca1d7SJeeja KP dfw_config->is_dynamic_in_pin, 12843af36706SVinod Koul mconfig->max_in_queue); 12856abca1d7SJeeja KP 12866abca1d7SJeeja KP skl_fill_module_pin_info(dfw_config->out_pin, mconfig->m_out_pin, 12876abca1d7SJeeja KP dfw_config->is_dynamic_out_pin, 12883af36706SVinod Koul mconfig->max_out_queue); 12893af36706SVinod Koul 12906abca1d7SJeeja KP 12913af36706SVinod Koul if (mconfig->formats_config.caps_size == 0) 12923af36706SVinod Koul goto bind_event; 12933af36706SVinod Koul 12943af36706SVinod Koul mconfig->formats_config.caps = (u32 *)devm_kzalloc(bus->dev, 12953af36706SVinod Koul mconfig->formats_config.caps_size, GFP_KERNEL); 12963af36706SVinod Koul 12973af36706SVinod Koul if (mconfig->formats_config.caps == NULL) 12983af36706SVinod Koul return -ENOMEM; 12993af36706SVinod Koul 13003af36706SVinod Koul memcpy(mconfig->formats_config.caps, dfw_config->caps.caps, 13013af36706SVinod Koul dfw_config->caps.caps_size); 1302*abb74003SJeeja KP mconfig->formats_config.param_id = dfw_config->caps.param_id; 1303*abb74003SJeeja KP mconfig->formats_config.set_params = dfw_config->caps.set_params; 13043af36706SVinod Koul 13053af36706SVinod Koul bind_event: 13063af36706SVinod Koul if (tplg_w->event_type == 0) { 13073373f716SVinod Koul dev_dbg(bus->dev, "ASoC: No event handler required\n"); 13083af36706SVinod Koul return 0; 13093af36706SVinod Koul } 13103af36706SVinod Koul 13113af36706SVinod Koul ret = snd_soc_tplg_widget_bind_event(w, skl_tplg_widget_ops, 1312b663a8c5SJeeja KP ARRAY_SIZE(skl_tplg_widget_ops), 1313b663a8c5SJeeja KP tplg_w->event_type); 13143af36706SVinod Koul 13153af36706SVinod Koul if (ret) { 13163af36706SVinod Koul dev_err(bus->dev, "%s: No matching event handlers found for %d\n", 13173af36706SVinod Koul __func__, tplg_w->event_type); 13183af36706SVinod Koul return -EINVAL; 13193af36706SVinod Koul } 13203af36706SVinod Koul 13213af36706SVinod Koul return 0; 13223af36706SVinod Koul } 13233af36706SVinod Koul 13243af36706SVinod Koul static struct snd_soc_tplg_ops skl_tplg_ops = { 13253af36706SVinod Koul .widget_load = skl_tplg_widget_load, 13263af36706SVinod Koul }; 13273af36706SVinod Koul 13283af36706SVinod Koul /* This will be read from topology manifest, currently defined here */ 13293af36706SVinod Koul #define SKL_MAX_MCPS 30000000 13303af36706SVinod Koul #define SKL_FW_MAX_MEM 1000000 13313af36706SVinod Koul 13323af36706SVinod Koul /* 13333af36706SVinod Koul * SKL topology init routine 13343af36706SVinod Koul */ 13353af36706SVinod Koul int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus) 13363af36706SVinod Koul { 13373af36706SVinod Koul int ret; 13383af36706SVinod Koul const struct firmware *fw; 13393af36706SVinod Koul struct hdac_bus *bus = ebus_to_hbus(ebus); 13403af36706SVinod Koul struct skl *skl = ebus_to_skl(ebus); 13413af36706SVinod Koul 13423af36706SVinod Koul ret = request_firmware(&fw, "dfw_sst.bin", bus->dev); 13433af36706SVinod Koul if (ret < 0) { 1344b663a8c5SJeeja KP dev_err(bus->dev, "tplg fw %s load failed with %d\n", 13453af36706SVinod Koul "dfw_sst.bin", ret); 13463af36706SVinod Koul return ret; 13473af36706SVinod Koul } 13483af36706SVinod Koul 13493af36706SVinod Koul /* 13503af36706SVinod Koul * The complete tplg for SKL is loaded as index 0, we don't use 13513af36706SVinod Koul * any other index 13523af36706SVinod Koul */ 1353b663a8c5SJeeja KP ret = snd_soc_tplg_component_load(&platform->component, 1354b663a8c5SJeeja KP &skl_tplg_ops, fw, 0); 13553af36706SVinod Koul if (ret < 0) { 13563af36706SVinod Koul dev_err(bus->dev, "tplg component load failed%d\n", ret); 13573af36706SVinod Koul return -EINVAL; 13583af36706SVinod Koul } 13593af36706SVinod Koul 13603af36706SVinod Koul skl->resource.max_mcps = SKL_MAX_MCPS; 13613af36706SVinod Koul skl->resource.max_mem = SKL_FW_MAX_MEM; 13623af36706SVinod Koul 13633af36706SVinod Koul return 0; 13643af36706SVinod Koul } 1365