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" 296c5768b3SDharageswari R #include "../common/sst-dsp.h" 306c5768b3SDharageswari R #include "../common/sst-dsp-priv.h" 31e4e2d2f4SJeeja KP 32f7590d4fSJeeja KP #define SKL_CH_FIXUP_MASK (1 << 0) 33f7590d4fSJeeja KP #define SKL_RATE_FIXUP_MASK (1 << 1) 34f7590d4fSJeeja KP #define SKL_FMT_FIXUP_MASK (1 << 2) 35f7590d4fSJeeja KP 36e4e2d2f4SJeeja KP /* 37e4e2d2f4SJeeja KP * SKL DSP driver modelling uses only few DAPM widgets so for rest we will 38e4e2d2f4SJeeja KP * ignore. This helpers checks if the SKL driver handles this widget type 39e4e2d2f4SJeeja KP */ 40e4e2d2f4SJeeja KP static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w) 41e4e2d2f4SJeeja KP { 42e4e2d2f4SJeeja KP switch (w->id) { 43e4e2d2f4SJeeja KP case snd_soc_dapm_dai_link: 44e4e2d2f4SJeeja KP case snd_soc_dapm_dai_in: 45e4e2d2f4SJeeja KP case snd_soc_dapm_aif_in: 46e4e2d2f4SJeeja KP case snd_soc_dapm_aif_out: 47e4e2d2f4SJeeja KP case snd_soc_dapm_dai_out: 48e4e2d2f4SJeeja KP case snd_soc_dapm_switch: 49e4e2d2f4SJeeja KP return false; 50e4e2d2f4SJeeja KP default: 51e4e2d2f4SJeeja KP return true; 52e4e2d2f4SJeeja KP } 53e4e2d2f4SJeeja KP } 54e4e2d2f4SJeeja KP 55e4e2d2f4SJeeja KP /* 56e4e2d2f4SJeeja KP * Each pipelines needs memory to be allocated. Check if we have free memory 57*9ba8ffefSDharageswari.R * from available pool. 58e4e2d2f4SJeeja KP */ 59*9ba8ffefSDharageswari.R static bool skl_is_pipe_mem_avail(struct skl *skl, 60e4e2d2f4SJeeja KP struct skl_module_cfg *mconfig) 61e4e2d2f4SJeeja KP { 62e4e2d2f4SJeeja KP struct skl_sst *ctx = skl->skl_sst; 63e4e2d2f4SJeeja KP 64e4e2d2f4SJeeja KP if (skl->resource.mem + mconfig->pipe->memory_pages > 65e4e2d2f4SJeeja KP skl->resource.max_mem) { 66e4e2d2f4SJeeja KP dev_err(ctx->dev, 67e4e2d2f4SJeeja KP "%s: module_id %d instance %d\n", __func__, 68e4e2d2f4SJeeja KP mconfig->id.module_id, 69e4e2d2f4SJeeja KP mconfig->id.instance_id); 70e4e2d2f4SJeeja KP dev_err(ctx->dev, 71e4e2d2f4SJeeja KP "exceeds ppl memory available %d mem %d\n", 72e4e2d2f4SJeeja KP skl->resource.max_mem, skl->resource.mem); 73e4e2d2f4SJeeja KP return false; 74*9ba8ffefSDharageswari.R } else { 75*9ba8ffefSDharageswari.R return true; 76*9ba8ffefSDharageswari.R } 77e4e2d2f4SJeeja KP } 78e4e2d2f4SJeeja KP 79*9ba8ffefSDharageswari.R /* 80*9ba8ffefSDharageswari.R * Add the mem to the mem pool. This is freed when pipe is deleted. 81*9ba8ffefSDharageswari.R * Note: DSP does actual memory management we only keep track for complete 82*9ba8ffefSDharageswari.R * pool 83*9ba8ffefSDharageswari.R */ 84*9ba8ffefSDharageswari.R static void skl_tplg_alloc_pipe_mem(struct skl *skl, 85*9ba8ffefSDharageswari.R struct skl_module_cfg *mconfig) 86*9ba8ffefSDharageswari.R { 87e4e2d2f4SJeeja KP skl->resource.mem += mconfig->pipe->memory_pages; 88e4e2d2f4SJeeja KP } 89e4e2d2f4SJeeja KP 90e4e2d2f4SJeeja KP /* 91e4e2d2f4SJeeja KP * Pipeline needs needs DSP CPU resources for computation, this is 92e4e2d2f4SJeeja KP * quantified in MCPS (Million Clocks Per Second) required for module/pipe 93e4e2d2f4SJeeja KP * 94e4e2d2f4SJeeja KP * Each pipelines needs mcps to be allocated. Check if we have mcps for this 95*9ba8ffefSDharageswari.R * pipe. 96e4e2d2f4SJeeja KP */ 97*9ba8ffefSDharageswari.R 98*9ba8ffefSDharageswari.R static bool skl_is_pipe_mcps_avail(struct skl *skl, 99e4e2d2f4SJeeja KP struct skl_module_cfg *mconfig) 100e4e2d2f4SJeeja KP { 101e4e2d2f4SJeeja KP struct skl_sst *ctx = skl->skl_sst; 102e4e2d2f4SJeeja KP 103e4e2d2f4SJeeja KP if (skl->resource.mcps + mconfig->mcps > skl->resource.max_mcps) { 104e4e2d2f4SJeeja KP dev_err(ctx->dev, 105e4e2d2f4SJeeja KP "%s: module_id %d instance %d\n", __func__, 106e4e2d2f4SJeeja KP mconfig->id.module_id, mconfig->id.instance_id); 107e4e2d2f4SJeeja KP dev_err(ctx->dev, 1087ca42f5aSGuneshwor Singh "exceeds ppl mcps available %d > mem %d\n", 109e4e2d2f4SJeeja KP skl->resource.max_mcps, skl->resource.mcps); 110e4e2d2f4SJeeja KP return false; 111*9ba8ffefSDharageswari.R } else { 112*9ba8ffefSDharageswari.R return true; 113*9ba8ffefSDharageswari.R } 114e4e2d2f4SJeeja KP } 115e4e2d2f4SJeeja KP 116*9ba8ffefSDharageswari.R static void skl_tplg_alloc_pipe_mcps(struct skl *skl, 117*9ba8ffefSDharageswari.R struct skl_module_cfg *mconfig) 118*9ba8ffefSDharageswari.R { 119e4e2d2f4SJeeja KP skl->resource.mcps += mconfig->mcps; 120e4e2d2f4SJeeja KP } 121e4e2d2f4SJeeja KP 122e4e2d2f4SJeeja KP /* 123e4e2d2f4SJeeja KP * Free the mcps when tearing down 124e4e2d2f4SJeeja KP */ 125e4e2d2f4SJeeja KP static void 126e4e2d2f4SJeeja KP skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig) 127e4e2d2f4SJeeja KP { 128e4e2d2f4SJeeja KP skl->resource.mcps -= mconfig->mcps; 129e4e2d2f4SJeeja KP } 130e4e2d2f4SJeeja KP 131e4e2d2f4SJeeja KP /* 132e4e2d2f4SJeeja KP * Free the memory when tearing down 133e4e2d2f4SJeeja KP */ 134e4e2d2f4SJeeja KP static void 135e4e2d2f4SJeeja KP skl_tplg_free_pipe_mem(struct skl *skl, struct skl_module_cfg *mconfig) 136e4e2d2f4SJeeja KP { 137e4e2d2f4SJeeja KP skl->resource.mem -= mconfig->pipe->memory_pages; 138e4e2d2f4SJeeja KP } 139e4e2d2f4SJeeja KP 140f7590d4fSJeeja KP 141f7590d4fSJeeja KP static void skl_dump_mconfig(struct skl_sst *ctx, 142f7590d4fSJeeja KP struct skl_module_cfg *mcfg) 143f7590d4fSJeeja KP { 144f7590d4fSJeeja KP dev_dbg(ctx->dev, "Dumping config\n"); 145f7590d4fSJeeja KP dev_dbg(ctx->dev, "Input Format:\n"); 1464cd9899fSHardik T Shah dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt[0].channels); 1474cd9899fSHardik T Shah dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->in_fmt[0].s_freq); 1484cd9899fSHardik T Shah dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->in_fmt[0].ch_cfg); 1494cd9899fSHardik T Shah dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->in_fmt[0].valid_bit_depth); 150f7590d4fSJeeja KP dev_dbg(ctx->dev, "Output Format:\n"); 1514cd9899fSHardik T Shah dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt[0].channels); 1524cd9899fSHardik T Shah dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->out_fmt[0].s_freq); 1534cd9899fSHardik T Shah dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->out_fmt[0].valid_bit_depth); 1544cd9899fSHardik T Shah dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt[0].ch_cfg); 155f7590d4fSJeeja KP } 156f7590d4fSJeeja KP 157f7590d4fSJeeja KP static void skl_tplg_update_params(struct skl_module_fmt *fmt, 158f7590d4fSJeeja KP struct skl_pipe_params *params, int fixup) 159f7590d4fSJeeja KP { 160f7590d4fSJeeja KP if (fixup & SKL_RATE_FIXUP_MASK) 161f7590d4fSJeeja KP fmt->s_freq = params->s_freq; 162f7590d4fSJeeja KP if (fixup & SKL_CH_FIXUP_MASK) 163f7590d4fSJeeja KP fmt->channels = params->ch; 16498256f83SJeeja KP if (fixup & SKL_FMT_FIXUP_MASK) { 16598256f83SJeeja KP fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt); 16698256f83SJeeja KP 16798256f83SJeeja KP /* 16898256f83SJeeja KP * 16 bit is 16 bit container whereas 24 bit is in 32 bit 16998256f83SJeeja KP * container so update bit depth accordingly 17098256f83SJeeja KP */ 17198256f83SJeeja KP switch (fmt->valid_bit_depth) { 17298256f83SJeeja KP case SKL_DEPTH_16BIT: 17398256f83SJeeja KP fmt->bit_depth = fmt->valid_bit_depth; 17498256f83SJeeja KP break; 17598256f83SJeeja KP 17698256f83SJeeja KP default: 17798256f83SJeeja KP fmt->bit_depth = SKL_DEPTH_32BIT; 17898256f83SJeeja KP break; 17998256f83SJeeja KP } 18098256f83SJeeja KP } 18198256f83SJeeja KP 182f7590d4fSJeeja KP } 183f7590d4fSJeeja KP 184f7590d4fSJeeja KP /* 185f7590d4fSJeeja KP * A pipeline may have modules which impact the pcm parameters, like SRC, 186f7590d4fSJeeja KP * channel converter, format converter. 187f7590d4fSJeeja KP * We need to calculate the output params by applying the 'fixup' 188f7590d4fSJeeja KP * Topology will tell driver which type of fixup is to be applied by 189f7590d4fSJeeja KP * supplying the fixup mask, so based on that we calculate the output 190f7590d4fSJeeja KP * 191f7590d4fSJeeja KP * Now In FE the pcm hw_params is source/target format. Same is applicable 192f7590d4fSJeeja KP * for BE with its hw_params invoked. 193f7590d4fSJeeja KP * here based on FE, BE pipeline and direction we calculate the input and 194f7590d4fSJeeja KP * outfix and then apply that for a module 195f7590d4fSJeeja KP */ 196f7590d4fSJeeja KP static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg, 197f7590d4fSJeeja KP struct skl_pipe_params *params, bool is_fe) 198f7590d4fSJeeja KP { 199f7590d4fSJeeja KP int in_fixup, out_fixup; 200f7590d4fSJeeja KP struct skl_module_fmt *in_fmt, *out_fmt; 201f7590d4fSJeeja KP 2024cd9899fSHardik T Shah /* Fixups will be applied to pin 0 only */ 2034cd9899fSHardik T Shah in_fmt = &m_cfg->in_fmt[0]; 2044cd9899fSHardik T Shah out_fmt = &m_cfg->out_fmt[0]; 205f7590d4fSJeeja KP 206f7590d4fSJeeja KP if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { 207f7590d4fSJeeja KP if (is_fe) { 208f7590d4fSJeeja KP in_fixup = m_cfg->params_fixup; 209f7590d4fSJeeja KP out_fixup = (~m_cfg->converter) & 210f7590d4fSJeeja KP m_cfg->params_fixup; 211f7590d4fSJeeja KP } else { 212f7590d4fSJeeja KP out_fixup = m_cfg->params_fixup; 213f7590d4fSJeeja KP in_fixup = (~m_cfg->converter) & 214f7590d4fSJeeja KP m_cfg->params_fixup; 215f7590d4fSJeeja KP } 216f7590d4fSJeeja KP } else { 217f7590d4fSJeeja KP if (is_fe) { 218f7590d4fSJeeja KP out_fixup = m_cfg->params_fixup; 219f7590d4fSJeeja KP in_fixup = (~m_cfg->converter) & 220f7590d4fSJeeja KP m_cfg->params_fixup; 221f7590d4fSJeeja KP } else { 222f7590d4fSJeeja KP in_fixup = m_cfg->params_fixup; 223f7590d4fSJeeja KP out_fixup = (~m_cfg->converter) & 224f7590d4fSJeeja KP m_cfg->params_fixup; 225f7590d4fSJeeja KP } 226f7590d4fSJeeja KP } 227f7590d4fSJeeja KP 228f7590d4fSJeeja KP skl_tplg_update_params(in_fmt, params, in_fixup); 229f7590d4fSJeeja KP skl_tplg_update_params(out_fmt, params, out_fixup); 230f7590d4fSJeeja KP } 231f7590d4fSJeeja KP 232f7590d4fSJeeja KP /* 233f7590d4fSJeeja KP * A module needs input and output buffers, which are dependent upon pcm 234f7590d4fSJeeja KP * params, so once we have calculate params, we need buffer calculation as 235f7590d4fSJeeja KP * well. 236f7590d4fSJeeja KP */ 237f7590d4fSJeeja KP static void skl_tplg_update_buffer_size(struct skl_sst *ctx, 238f7590d4fSJeeja KP struct skl_module_cfg *mcfg) 239f7590d4fSJeeja KP { 240f7590d4fSJeeja KP int multiplier = 1; 2414cd9899fSHardik T Shah struct skl_module_fmt *in_fmt, *out_fmt; 2424cd9899fSHardik T Shah 2434cd9899fSHardik T Shah 2444cd9899fSHardik T Shah /* Since fixups is applied to pin 0 only, ibs, obs needs 2454cd9899fSHardik T Shah * change for pin 0 only 2464cd9899fSHardik T Shah */ 2474cd9899fSHardik T Shah in_fmt = &mcfg->in_fmt[0]; 2484cd9899fSHardik T Shah out_fmt = &mcfg->out_fmt[0]; 249f7590d4fSJeeja KP 250f7590d4fSJeeja KP if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT) 251f7590d4fSJeeja KP multiplier = 5; 2524cd9899fSHardik T Shah mcfg->ibs = (in_fmt->s_freq / 1000) * 2534cd9899fSHardik T Shah (mcfg->in_fmt->channels) * 2544cd9899fSHardik T Shah (mcfg->in_fmt->bit_depth >> 3) * 255f7590d4fSJeeja KP multiplier; 256f7590d4fSJeeja KP 2574cd9899fSHardik T Shah mcfg->obs = (mcfg->out_fmt->s_freq / 1000) * 2584cd9899fSHardik T Shah (mcfg->out_fmt->channels) * 2594cd9899fSHardik T Shah (mcfg->out_fmt->bit_depth >> 3) * 260f7590d4fSJeeja KP multiplier; 261f7590d4fSJeeja KP } 262f7590d4fSJeeja KP 263f7590d4fSJeeja KP static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w, 264f7590d4fSJeeja KP struct skl_sst *ctx) 265f7590d4fSJeeja KP { 266f7590d4fSJeeja KP struct skl_module_cfg *m_cfg = w->priv; 267f7590d4fSJeeja KP struct skl_pipe_params *params = m_cfg->pipe->p_params; 268f7590d4fSJeeja KP int p_conn_type = m_cfg->pipe->conn_type; 269f7590d4fSJeeja KP bool is_fe; 270f7590d4fSJeeja KP 271f7590d4fSJeeja KP if (!m_cfg->params_fixup) 272f7590d4fSJeeja KP return; 273f7590d4fSJeeja KP 274f7590d4fSJeeja KP dev_dbg(ctx->dev, "Mconfig for widget=%s BEFORE updation\n", 275f7590d4fSJeeja KP w->name); 276f7590d4fSJeeja KP 277f7590d4fSJeeja KP skl_dump_mconfig(ctx, m_cfg); 278f7590d4fSJeeja KP 279f7590d4fSJeeja KP if (p_conn_type == SKL_PIPE_CONN_TYPE_FE) 280f7590d4fSJeeja KP is_fe = true; 281f7590d4fSJeeja KP else 282f7590d4fSJeeja KP is_fe = false; 283f7590d4fSJeeja KP 284f7590d4fSJeeja KP skl_tplg_update_params_fixup(m_cfg, params, is_fe); 285f7590d4fSJeeja KP skl_tplg_update_buffer_size(ctx, m_cfg); 286f7590d4fSJeeja KP 287f7590d4fSJeeja KP dev_dbg(ctx->dev, "Mconfig for widget=%s AFTER updation\n", 288f7590d4fSJeeja KP w->name); 289f7590d4fSJeeja KP 290f7590d4fSJeeja KP skl_dump_mconfig(ctx, m_cfg); 291f7590d4fSJeeja KP } 292f7590d4fSJeeja KP 293e4e2d2f4SJeeja KP /* 294e4e2d2f4SJeeja KP * A pipe can have multiple modules, each of them will be a DAPM widget as 295e4e2d2f4SJeeja KP * well. While managing a pipeline we need to get the list of all the 296e4e2d2f4SJeeja KP * widgets in a pipelines, so this helper - skl_tplg_get_pipe_widget() helps 297e4e2d2f4SJeeja KP * to get the SKL type widgets in that pipeline 298e4e2d2f4SJeeja KP */ 299e4e2d2f4SJeeja KP static int skl_tplg_alloc_pipe_widget(struct device *dev, 300e4e2d2f4SJeeja KP struct snd_soc_dapm_widget *w, struct skl_pipe *pipe) 301e4e2d2f4SJeeja KP { 302e4e2d2f4SJeeja KP struct skl_module_cfg *src_module = NULL; 303e4e2d2f4SJeeja KP struct snd_soc_dapm_path *p = NULL; 304e4e2d2f4SJeeja KP struct skl_pipe_module *p_module = NULL; 305e4e2d2f4SJeeja KP 306e4e2d2f4SJeeja KP p_module = devm_kzalloc(dev, sizeof(*p_module), GFP_KERNEL); 307e4e2d2f4SJeeja KP if (!p_module) 308e4e2d2f4SJeeja KP return -ENOMEM; 309e4e2d2f4SJeeja KP 310e4e2d2f4SJeeja KP p_module->w = w; 311e4e2d2f4SJeeja KP list_add_tail(&p_module->node, &pipe->w_list); 312e4e2d2f4SJeeja KP 313e4e2d2f4SJeeja KP snd_soc_dapm_widget_for_each_sink_path(w, p) { 314e4e2d2f4SJeeja KP if ((p->sink->priv == NULL) 315e4e2d2f4SJeeja KP && (!is_skl_dsp_widget_type(w))) 316e4e2d2f4SJeeja KP continue; 317e4e2d2f4SJeeja KP 318e4e2d2f4SJeeja KP if ((p->sink->priv != NULL) && p->connect 319e4e2d2f4SJeeja KP && is_skl_dsp_widget_type(p->sink)) { 320e4e2d2f4SJeeja KP 321e4e2d2f4SJeeja KP src_module = p->sink->priv; 322e4e2d2f4SJeeja KP if (pipe->ppl_id == src_module->pipe->ppl_id) 323e4e2d2f4SJeeja KP skl_tplg_alloc_pipe_widget(dev, 324e4e2d2f4SJeeja KP p->sink, pipe); 325e4e2d2f4SJeeja KP } 326e4e2d2f4SJeeja KP } 327e4e2d2f4SJeeja KP return 0; 328e4e2d2f4SJeeja KP } 329e4e2d2f4SJeeja KP 330e4e2d2f4SJeeja KP /* 331abb74003SJeeja KP * some modules can have multiple params set from user control and 332abb74003SJeeja KP * need to be set after module is initialized. If set_param flag is 333abb74003SJeeja KP * set module params will be done after module is initialised. 334abb74003SJeeja KP */ 335abb74003SJeeja KP static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w, 336abb74003SJeeja KP struct skl_sst *ctx) 337abb74003SJeeja KP { 338abb74003SJeeja KP int i, ret; 339abb74003SJeeja KP struct skl_module_cfg *mconfig = w->priv; 340abb74003SJeeja KP const struct snd_kcontrol_new *k; 341abb74003SJeeja KP struct soc_bytes_ext *sb; 342abb74003SJeeja KP struct skl_algo_data *bc; 343abb74003SJeeja KP struct skl_specific_cfg *sp_cfg; 344abb74003SJeeja KP 345abb74003SJeeja KP if (mconfig->formats_config.caps_size > 0 && 3464ced1827SJeeja KP mconfig->formats_config.set_params == SKL_PARAM_SET) { 347abb74003SJeeja KP sp_cfg = &mconfig->formats_config; 348abb74003SJeeja KP ret = skl_set_module_params(ctx, sp_cfg->caps, 349abb74003SJeeja KP sp_cfg->caps_size, 350abb74003SJeeja KP sp_cfg->param_id, mconfig); 351abb74003SJeeja KP if (ret < 0) 352abb74003SJeeja KP return ret; 353abb74003SJeeja KP } 354abb74003SJeeja KP 355abb74003SJeeja KP for (i = 0; i < w->num_kcontrols; i++) { 356abb74003SJeeja KP k = &w->kcontrol_news[i]; 357abb74003SJeeja KP if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 358abb74003SJeeja KP sb = (void *) k->private_value; 359abb74003SJeeja KP bc = (struct skl_algo_data *)sb->dobj.private; 360abb74003SJeeja KP 3614ced1827SJeeja KP if (bc->set_params == SKL_PARAM_SET) { 362abb74003SJeeja KP ret = skl_set_module_params(ctx, 363abb74003SJeeja KP (u32 *)bc->params, bc->max, 364abb74003SJeeja KP bc->param_id, mconfig); 365abb74003SJeeja KP if (ret < 0) 366abb74003SJeeja KP return ret; 367abb74003SJeeja KP } 368abb74003SJeeja KP } 369abb74003SJeeja KP } 370abb74003SJeeja KP 371abb74003SJeeja KP return 0; 372abb74003SJeeja KP } 373abb74003SJeeja KP 374abb74003SJeeja KP /* 375abb74003SJeeja KP * some module param can set from user control and this is required as 376abb74003SJeeja KP * when module is initailzed. if module param is required in init it is 377abb74003SJeeja KP * identifed by set_param flag. if set_param flag is not set, then this 378abb74003SJeeja KP * parameter needs to set as part of module init. 379abb74003SJeeja KP */ 380abb74003SJeeja KP static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w) 381abb74003SJeeja KP { 382abb74003SJeeja KP const struct snd_kcontrol_new *k; 383abb74003SJeeja KP struct soc_bytes_ext *sb; 384abb74003SJeeja KP struct skl_algo_data *bc; 385abb74003SJeeja KP struct skl_module_cfg *mconfig = w->priv; 386abb74003SJeeja KP int i; 387abb74003SJeeja KP 388abb74003SJeeja KP for (i = 0; i < w->num_kcontrols; i++) { 389abb74003SJeeja KP k = &w->kcontrol_news[i]; 390abb74003SJeeja KP if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 391abb74003SJeeja KP sb = (struct soc_bytes_ext *)k->private_value; 392abb74003SJeeja KP bc = (struct skl_algo_data *)sb->dobj.private; 393abb74003SJeeja KP 3944ced1827SJeeja KP if (bc->set_params != SKL_PARAM_INIT) 395abb74003SJeeja KP continue; 396abb74003SJeeja KP 397abb74003SJeeja KP mconfig->formats_config.caps = (u32 *)&bc->params; 398abb74003SJeeja KP mconfig->formats_config.caps_size = bc->max; 399abb74003SJeeja KP 400abb74003SJeeja KP break; 401abb74003SJeeja KP } 402abb74003SJeeja KP } 403abb74003SJeeja KP 404abb74003SJeeja KP return 0; 405abb74003SJeeja KP } 406abb74003SJeeja KP 407abb74003SJeeja KP /* 408e4e2d2f4SJeeja KP * Inside a pipe instance, we can have various modules. These modules need 409e4e2d2f4SJeeja KP * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by 410e4e2d2f4SJeeja KP * skl_init_module() routine, so invoke that for all modules in a pipeline 411e4e2d2f4SJeeja KP */ 412e4e2d2f4SJeeja KP static int 413e4e2d2f4SJeeja KP skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) 414e4e2d2f4SJeeja KP { 415e4e2d2f4SJeeja KP struct skl_pipe_module *w_module; 416e4e2d2f4SJeeja KP struct snd_soc_dapm_widget *w; 417e4e2d2f4SJeeja KP struct skl_module_cfg *mconfig; 418e4e2d2f4SJeeja KP struct skl_sst *ctx = skl->skl_sst; 419e4e2d2f4SJeeja KP int ret = 0; 420e4e2d2f4SJeeja KP 421e4e2d2f4SJeeja KP list_for_each_entry(w_module, &pipe->w_list, node) { 422e4e2d2f4SJeeja KP w = w_module->w; 423e4e2d2f4SJeeja KP mconfig = w->priv; 424e4e2d2f4SJeeja KP 425e4e2d2f4SJeeja KP /* check resource available */ 426*9ba8ffefSDharageswari.R if (!skl_is_pipe_mcps_avail(skl, mconfig)) 427e4e2d2f4SJeeja KP return -ENOMEM; 428e4e2d2f4SJeeja KP 4296c5768b3SDharageswari R if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) { 4306c5768b3SDharageswari R ret = ctx->dsp->fw_ops.load_mod(ctx->dsp, 4316c5768b3SDharageswari R mconfig->id.module_id, mconfig->guid); 4326c5768b3SDharageswari R if (ret < 0) 4336c5768b3SDharageswari R return ret; 4346c5768b3SDharageswari R } 4356c5768b3SDharageswari R 436f7590d4fSJeeja KP /* 437f7590d4fSJeeja KP * apply fix/conversion to module params based on 438f7590d4fSJeeja KP * FE/BE params 439f7590d4fSJeeja KP */ 440f7590d4fSJeeja KP skl_tplg_update_module_params(w, ctx); 441abb74003SJeeja KP 442abb74003SJeeja KP skl_tplg_set_module_init_data(w); 4439939a9c3SJeeja KP ret = skl_init_module(ctx, mconfig); 444e4e2d2f4SJeeja KP if (ret < 0) 445e4e2d2f4SJeeja KP return ret; 446abb74003SJeeja KP 447abb74003SJeeja KP ret = skl_tplg_set_module_params(w, ctx); 448e4e2d2f4SJeeja KP if (ret < 0) 449e4e2d2f4SJeeja KP return ret; 450*9ba8ffefSDharageswari.R skl_tplg_alloc_pipe_mcps(skl, mconfig); 451e4e2d2f4SJeeja KP } 452e4e2d2f4SJeeja KP 453e4e2d2f4SJeeja KP return 0; 454e4e2d2f4SJeeja KP } 455d93f8e55SVinod Koul 4566c5768b3SDharageswari R static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx, 4576c5768b3SDharageswari R struct skl_pipe *pipe) 4586c5768b3SDharageswari R { 4596c5768b3SDharageswari R struct skl_pipe_module *w_module = NULL; 4606c5768b3SDharageswari R struct skl_module_cfg *mconfig = NULL; 4616c5768b3SDharageswari R 4626c5768b3SDharageswari R list_for_each_entry(w_module, &pipe->w_list, node) { 4636c5768b3SDharageswari R mconfig = w_module->w->priv; 4646c5768b3SDharageswari R 4656c5768b3SDharageswari R if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod) 4666c5768b3SDharageswari R return ctx->dsp->fw_ops.unload_mod(ctx->dsp, 4676c5768b3SDharageswari R mconfig->id.module_id); 4686c5768b3SDharageswari R } 4696c5768b3SDharageswari R 4706c5768b3SDharageswari R /* no modules to unload in this path, so return */ 4716c5768b3SDharageswari R return 0; 4726c5768b3SDharageswari R } 4736c5768b3SDharageswari R 474d93f8e55SVinod Koul /* 475d93f8e55SVinod Koul * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we 476d93f8e55SVinod Koul * need create the pipeline. So we do following: 477d93f8e55SVinod Koul * - check the resources 478d93f8e55SVinod Koul * - Create the pipeline 479d93f8e55SVinod Koul * - Initialize the modules in pipeline 480d93f8e55SVinod Koul * - finally bind all modules together 481d93f8e55SVinod Koul */ 482d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, 483d93f8e55SVinod Koul struct skl *skl) 484d93f8e55SVinod Koul { 485d93f8e55SVinod Koul int ret; 486d93f8e55SVinod Koul struct skl_module_cfg *mconfig = w->priv; 487d93f8e55SVinod Koul struct skl_pipe_module *w_module; 488d93f8e55SVinod Koul struct skl_pipe *s_pipe = mconfig->pipe; 489d93f8e55SVinod Koul struct skl_module_cfg *src_module = NULL, *dst_module; 490d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 491d93f8e55SVinod Koul 492d93f8e55SVinod Koul /* check resource available */ 493*9ba8ffefSDharageswari.R if (!skl_is_pipe_mcps_avail(skl, mconfig)) 494d93f8e55SVinod Koul return -EBUSY; 495d93f8e55SVinod Koul 496*9ba8ffefSDharageswari.R if (!skl_is_pipe_mem_avail(skl, mconfig)) 497d93f8e55SVinod Koul return -ENOMEM; 498d93f8e55SVinod Koul 499d93f8e55SVinod Koul /* 500d93f8e55SVinod Koul * Create a list of modules for pipe. 501d93f8e55SVinod Koul * This list contains modules from source to sink 502d93f8e55SVinod Koul */ 503d93f8e55SVinod Koul ret = skl_create_pipeline(ctx, mconfig->pipe); 504d93f8e55SVinod Koul if (ret < 0) 505d93f8e55SVinod Koul return ret; 506d93f8e55SVinod Koul 507d93f8e55SVinod Koul /* 508d93f8e55SVinod Koul * we create a w_list of all widgets in that pipe. This list is not 509d93f8e55SVinod Koul * freed on PMD event as widgets within a pipe are static. This 510d93f8e55SVinod Koul * saves us cycles to get widgets in pipe every time. 511d93f8e55SVinod Koul * 512d93f8e55SVinod Koul * So if we have already initialized all the widgets of a pipeline 513d93f8e55SVinod Koul * we skip, so check for list_empty and create the list if empty 514d93f8e55SVinod Koul */ 515d93f8e55SVinod Koul if (list_empty(&s_pipe->w_list)) { 516d93f8e55SVinod Koul ret = skl_tplg_alloc_pipe_widget(ctx->dev, w, s_pipe); 517d93f8e55SVinod Koul if (ret < 0) 518d93f8e55SVinod Koul return ret; 519d93f8e55SVinod Koul } 520d93f8e55SVinod Koul 521d93f8e55SVinod Koul /* Init all pipe modules from source to sink */ 522d93f8e55SVinod Koul ret = skl_tplg_init_pipe_modules(skl, s_pipe); 523d93f8e55SVinod Koul if (ret < 0) 524d93f8e55SVinod Koul return ret; 525d93f8e55SVinod Koul 526d93f8e55SVinod Koul /* Bind modules from source to sink */ 527d93f8e55SVinod Koul list_for_each_entry(w_module, &s_pipe->w_list, node) { 528d93f8e55SVinod Koul dst_module = w_module->w->priv; 529d93f8e55SVinod Koul 530d93f8e55SVinod Koul if (src_module == NULL) { 531d93f8e55SVinod Koul src_module = dst_module; 532d93f8e55SVinod Koul continue; 533d93f8e55SVinod Koul } 534d93f8e55SVinod Koul 535d93f8e55SVinod Koul ret = skl_bind_modules(ctx, src_module, dst_module); 536d93f8e55SVinod Koul if (ret < 0) 537d93f8e55SVinod Koul return ret; 538d93f8e55SVinod Koul 539d93f8e55SVinod Koul src_module = dst_module; 540d93f8e55SVinod Koul } 541d93f8e55SVinod Koul 542*9ba8ffefSDharageswari.R skl_tplg_alloc_pipe_mem(skl, mconfig); 543*9ba8ffefSDharageswari.R skl_tplg_alloc_pipe_mcps(skl, mconfig); 544*9ba8ffefSDharageswari.R 545d93f8e55SVinod Koul return 0; 546d93f8e55SVinod Koul } 547d93f8e55SVinod Koul 5488724ff17SJeeja KP static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, 5498724ff17SJeeja KP struct skl *skl, 5508724ff17SJeeja KP struct skl_module_cfg *src_mconfig) 551d93f8e55SVinod Koul { 552d93f8e55SVinod Koul struct snd_soc_dapm_path *p; 5530ed95d76SJeeja KP struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL; 5548724ff17SJeeja KP struct skl_module_cfg *sink_mconfig; 555d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 5568724ff17SJeeja KP int ret; 557d93f8e55SVinod Koul 5588724ff17SJeeja KP snd_soc_dapm_widget_for_each_sink_path(w, p) { 559d93f8e55SVinod Koul if (!p->connect) 560d93f8e55SVinod Koul continue; 561d93f8e55SVinod Koul 562d93f8e55SVinod Koul dev_dbg(ctx->dev, "%s: src widget=%s\n", __func__, w->name); 563d93f8e55SVinod Koul dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name); 564d93f8e55SVinod Koul 5650ed95d76SJeeja KP next_sink = p->sink; 566d93f8e55SVinod Koul /* 567d93f8e55SVinod Koul * here we will check widgets in sink pipelines, so that 568d93f8e55SVinod Koul * can be any widgets type and we are only interested if 569d93f8e55SVinod Koul * they are ones used for SKL so check that first 570d93f8e55SVinod Koul */ 571d93f8e55SVinod Koul if ((p->sink->priv != NULL) && 572d93f8e55SVinod Koul is_skl_dsp_widget_type(p->sink)) { 573d93f8e55SVinod Koul 574d93f8e55SVinod Koul sink = p->sink; 575d93f8e55SVinod Koul sink_mconfig = sink->priv; 576d93f8e55SVinod Koul 577d93f8e55SVinod Koul /* Bind source to sink, mixin is always source */ 578d93f8e55SVinod Koul ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig); 579d93f8e55SVinod Koul if (ret) 580d93f8e55SVinod Koul return ret; 581d93f8e55SVinod Koul 582d93f8e55SVinod Koul /* Start sinks pipe first */ 583d93f8e55SVinod Koul if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) { 584d1730c3dSJeeja KP if (sink_mconfig->pipe->conn_type != 585d1730c3dSJeeja KP SKL_PIPE_CONN_TYPE_FE) 586d1730c3dSJeeja KP ret = skl_run_pipe(ctx, 587d1730c3dSJeeja KP sink_mconfig->pipe); 588d93f8e55SVinod Koul if (ret) 589d93f8e55SVinod Koul return ret; 590d93f8e55SVinod Koul } 591d93f8e55SVinod Koul } 592d93f8e55SVinod Koul } 593d93f8e55SVinod Koul 5948724ff17SJeeja KP if (!sink) 5950ed95d76SJeeja KP return skl_tplg_bind_sinks(next_sink, skl, src_mconfig); 5968724ff17SJeeja KP 5978724ff17SJeeja KP return 0; 5988724ff17SJeeja KP } 5998724ff17SJeeja KP 600d93f8e55SVinod Koul /* 601d93f8e55SVinod Koul * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA 602d93f8e55SVinod Koul * we need to do following: 603d93f8e55SVinod Koul * - Bind to sink pipeline 604d93f8e55SVinod Koul * Since the sink pipes can be running and we don't get mixer event on 605d93f8e55SVinod Koul * connect for already running mixer, we need to find the sink pipes 606d93f8e55SVinod Koul * here and bind to them. This way dynamic connect works. 607d93f8e55SVinod Koul * - Start sink pipeline, if not running 608d93f8e55SVinod Koul * - Then run current pipe 609d93f8e55SVinod Koul */ 610d93f8e55SVinod Koul static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, 611d93f8e55SVinod Koul struct skl *skl) 612d93f8e55SVinod Koul { 6138724ff17SJeeja KP struct skl_module_cfg *src_mconfig; 614d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 615d93f8e55SVinod Koul int ret = 0; 616d93f8e55SVinod Koul 6178724ff17SJeeja KP src_mconfig = w->priv; 618d93f8e55SVinod Koul 619d93f8e55SVinod Koul /* 620d93f8e55SVinod Koul * find which sink it is connected to, bind with the sink, 621d93f8e55SVinod Koul * if sink is not started, start sink pipe first, then start 622d93f8e55SVinod Koul * this pipe 623d93f8e55SVinod Koul */ 6248724ff17SJeeja KP ret = skl_tplg_bind_sinks(w, skl, src_mconfig); 6258724ff17SJeeja KP if (ret) 6268724ff17SJeeja KP return ret; 6278724ff17SJeeja KP 628d93f8e55SVinod Koul /* Start source pipe last after starting all sinks */ 629d1730c3dSJeeja KP if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) 630d1730c3dSJeeja KP return skl_run_pipe(ctx, src_mconfig->pipe); 631d93f8e55SVinod Koul 632d93f8e55SVinod Koul return 0; 633d93f8e55SVinod Koul } 634d93f8e55SVinod Koul 6358724ff17SJeeja KP static struct snd_soc_dapm_widget *skl_get_src_dsp_widget( 6368724ff17SJeeja KP struct snd_soc_dapm_widget *w, struct skl *skl) 6378724ff17SJeeja KP { 6388724ff17SJeeja KP struct snd_soc_dapm_path *p; 6398724ff17SJeeja KP struct snd_soc_dapm_widget *src_w = NULL; 6408724ff17SJeeja KP struct skl_sst *ctx = skl->skl_sst; 6418724ff17SJeeja KP 642d93f8e55SVinod Koul snd_soc_dapm_widget_for_each_source_path(w, p) { 6438724ff17SJeeja KP src_w = p->source; 644d93f8e55SVinod Koul if (!p->connect) 645d93f8e55SVinod Koul continue; 646d93f8e55SVinod Koul 6478724ff17SJeeja KP dev_dbg(ctx->dev, "sink widget=%s\n", w->name); 6488724ff17SJeeja KP dev_dbg(ctx->dev, "src widget=%s\n", p->source->name); 649d93f8e55SVinod Koul 650d93f8e55SVinod Koul /* 6518724ff17SJeeja KP * here we will check widgets in sink pipelines, so that can 6528724ff17SJeeja KP * be any widgets type and we are only interested if they are 6538724ff17SJeeja KP * ones used for SKL so check that first 654d93f8e55SVinod Koul */ 6558724ff17SJeeja KP if ((p->source->priv != NULL) && 6568724ff17SJeeja KP is_skl_dsp_widget_type(p->source)) { 6578724ff17SJeeja KP return p->source; 658d93f8e55SVinod Koul } 659d93f8e55SVinod Koul } 660d93f8e55SVinod Koul 6618724ff17SJeeja KP if (src_w != NULL) 6628724ff17SJeeja KP return skl_get_src_dsp_widget(src_w, skl); 663d93f8e55SVinod Koul 6648724ff17SJeeja KP return NULL; 665d93f8e55SVinod Koul } 666d93f8e55SVinod Koul 667d93f8e55SVinod Koul /* 668d93f8e55SVinod Koul * in the Post-PMU event of mixer we need to do following: 669d93f8e55SVinod Koul * - Check if this pipe is running 670d93f8e55SVinod Koul * - if not, then 671d93f8e55SVinod Koul * - bind this pipeline to its source pipeline 672d93f8e55SVinod Koul * if source pipe is already running, this means it is a dynamic 673d93f8e55SVinod Koul * connection and we need to bind only to that pipe 674d93f8e55SVinod Koul * - start this pipeline 675d93f8e55SVinod Koul */ 676d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, 677d93f8e55SVinod Koul struct skl *skl) 678d93f8e55SVinod Koul { 679d93f8e55SVinod Koul int ret = 0; 680d93f8e55SVinod Koul struct snd_soc_dapm_widget *source, *sink; 681d93f8e55SVinod Koul struct skl_module_cfg *src_mconfig, *sink_mconfig; 682d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 683d93f8e55SVinod Koul int src_pipe_started = 0; 684d93f8e55SVinod Koul 685d93f8e55SVinod Koul sink = w; 686d93f8e55SVinod Koul sink_mconfig = sink->priv; 687d93f8e55SVinod Koul 688d93f8e55SVinod Koul /* 689d93f8e55SVinod Koul * If source pipe is already started, that means source is driving 690d93f8e55SVinod Koul * one more sink before this sink got connected, Since source is 691d93f8e55SVinod Koul * started, bind this sink to source and start this pipe. 692d93f8e55SVinod Koul */ 6938724ff17SJeeja KP source = skl_get_src_dsp_widget(w, skl); 6948724ff17SJeeja KP if (source != NULL) { 695d93f8e55SVinod Koul src_mconfig = source->priv; 696d93f8e55SVinod Koul sink_mconfig = sink->priv; 697d93f8e55SVinod Koul src_pipe_started = 1; 698d93f8e55SVinod Koul 699d93f8e55SVinod Koul /* 7008724ff17SJeeja KP * check pipe state, then no need to bind or start the 7018724ff17SJeeja KP * pipe 702d93f8e55SVinod Koul */ 703d93f8e55SVinod Koul if (src_mconfig->pipe->state != SKL_PIPE_STARTED) 704d93f8e55SVinod Koul src_pipe_started = 0; 705d93f8e55SVinod Koul } 706d93f8e55SVinod Koul 707d93f8e55SVinod Koul if (src_pipe_started) { 708d93f8e55SVinod Koul ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig); 709d93f8e55SVinod Koul if (ret) 710d93f8e55SVinod Koul return ret; 711d93f8e55SVinod Koul 712d1730c3dSJeeja KP if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) 713d93f8e55SVinod Koul ret = skl_run_pipe(ctx, sink_mconfig->pipe); 714d93f8e55SVinod Koul } 715d93f8e55SVinod Koul 716d93f8e55SVinod Koul return ret; 717d93f8e55SVinod Koul } 718d93f8e55SVinod Koul 719d93f8e55SVinod Koul /* 720d93f8e55SVinod Koul * in the Pre-PMD event of mixer we need to do following: 721d93f8e55SVinod Koul * - Stop the pipe 722d93f8e55SVinod Koul * - find the source connections and remove that from dapm_path_list 723d93f8e55SVinod Koul * - unbind with source pipelines if still connected 724d93f8e55SVinod Koul */ 725d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w, 726d93f8e55SVinod Koul struct skl *skl) 727d93f8e55SVinod Koul { 728d93f8e55SVinod Koul struct skl_module_cfg *src_mconfig, *sink_mconfig; 729ce1b5551SJeeja KP int ret = 0, i; 730d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 731d93f8e55SVinod Koul 732ce1b5551SJeeja KP sink_mconfig = w->priv; 733d93f8e55SVinod Koul 734d93f8e55SVinod Koul /* Stop the pipe */ 735d93f8e55SVinod Koul ret = skl_stop_pipe(ctx, sink_mconfig->pipe); 736d93f8e55SVinod Koul if (ret) 737d93f8e55SVinod Koul return ret; 738d93f8e55SVinod Koul 739ce1b5551SJeeja KP for (i = 0; i < sink_mconfig->max_in_queue; i++) { 740ce1b5551SJeeja KP if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) { 741ce1b5551SJeeja KP src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg; 742ce1b5551SJeeja KP if (!src_mconfig) 743ce1b5551SJeeja KP continue; 744d93f8e55SVinod Koul /* 745ce1b5551SJeeja KP * If path_found == 1, that means pmd for source 746ce1b5551SJeeja KP * pipe has not occurred, source is connected to 747ce1b5551SJeeja KP * some other sink. so its responsibility of sink 748ce1b5551SJeeja KP * to unbind itself from source. 749d93f8e55SVinod Koul */ 750d93f8e55SVinod Koul ret = skl_stop_pipe(ctx, src_mconfig->pipe); 751d93f8e55SVinod Koul if (ret < 0) 752d93f8e55SVinod Koul return ret; 753d93f8e55SVinod Koul 754ce1b5551SJeeja KP ret = skl_unbind_modules(ctx, 755ce1b5551SJeeja KP src_mconfig, sink_mconfig); 756ce1b5551SJeeja KP } 757d93f8e55SVinod Koul } 758d93f8e55SVinod Koul 759d93f8e55SVinod Koul return ret; 760d93f8e55SVinod Koul } 761d93f8e55SVinod Koul 762d93f8e55SVinod Koul /* 763d93f8e55SVinod Koul * in the Post-PMD event of mixer we need to do following: 764d93f8e55SVinod Koul * - Free the mcps used 765d93f8e55SVinod Koul * - Free the mem used 766d93f8e55SVinod Koul * - Unbind the modules within the pipeline 767d93f8e55SVinod Koul * - Delete the pipeline (modules are not required to be explicitly 768d93f8e55SVinod Koul * deleted, pipeline delete is enough here 769d93f8e55SVinod Koul */ 770d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, 771d93f8e55SVinod Koul struct skl *skl) 772d93f8e55SVinod Koul { 773d93f8e55SVinod Koul struct skl_module_cfg *mconfig = w->priv; 774d93f8e55SVinod Koul struct skl_pipe_module *w_module; 775d93f8e55SVinod Koul struct skl_module_cfg *src_module = NULL, *dst_module; 776d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 777d93f8e55SVinod Koul struct skl_pipe *s_pipe = mconfig->pipe; 778d93f8e55SVinod Koul int ret = 0; 779d93f8e55SVinod Koul 780d93f8e55SVinod Koul skl_tplg_free_pipe_mcps(skl, mconfig); 78165976878SVinod Koul skl_tplg_free_pipe_mem(skl, mconfig); 782d93f8e55SVinod Koul 783d93f8e55SVinod Koul list_for_each_entry(w_module, &s_pipe->w_list, node) { 784d93f8e55SVinod Koul dst_module = w_module->w->priv; 785d93f8e55SVinod Koul 7867ae3cb15SVinod Koul skl_tplg_free_pipe_mcps(skl, dst_module); 787d93f8e55SVinod Koul if (src_module == NULL) { 788d93f8e55SVinod Koul src_module = dst_module; 789d93f8e55SVinod Koul continue; 790d93f8e55SVinod Koul } 791d93f8e55SVinod Koul 7927ca42f5aSGuneshwor Singh skl_unbind_modules(ctx, src_module, dst_module); 793d93f8e55SVinod Koul src_module = dst_module; 794d93f8e55SVinod Koul } 795d93f8e55SVinod Koul 796d93f8e55SVinod Koul ret = skl_delete_pipe(ctx, mconfig->pipe); 797d93f8e55SVinod Koul 7986c5768b3SDharageswari R return skl_tplg_unload_pipe_modules(ctx, s_pipe); 799d93f8e55SVinod Koul } 800d93f8e55SVinod Koul 801d93f8e55SVinod Koul /* 802d93f8e55SVinod Koul * in the Post-PMD event of PGA we need to do following: 803d93f8e55SVinod Koul * - Free the mcps used 804d93f8e55SVinod Koul * - Stop the pipeline 805d93f8e55SVinod Koul * - In source pipe is connected, unbind with source pipelines 806d93f8e55SVinod Koul */ 807d93f8e55SVinod Koul static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, 808d93f8e55SVinod Koul struct skl *skl) 809d93f8e55SVinod Koul { 810d93f8e55SVinod Koul struct skl_module_cfg *src_mconfig, *sink_mconfig; 811ce1b5551SJeeja KP int ret = 0, i; 812d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 813d93f8e55SVinod Koul 814ce1b5551SJeeja KP src_mconfig = w->priv; 815d93f8e55SVinod Koul 816d93f8e55SVinod Koul /* Stop the pipe since this is a mixin module */ 817d93f8e55SVinod Koul ret = skl_stop_pipe(ctx, src_mconfig->pipe); 818d93f8e55SVinod Koul if (ret) 819d93f8e55SVinod Koul return ret; 820d93f8e55SVinod Koul 821ce1b5551SJeeja KP for (i = 0; i < src_mconfig->max_out_queue; i++) { 822ce1b5551SJeeja KP if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) { 823ce1b5551SJeeja KP sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg; 824ce1b5551SJeeja KP if (!sink_mconfig) 825ce1b5551SJeeja KP continue; 826d93f8e55SVinod Koul /* 827ce1b5551SJeeja KP * This is a connecter and if path is found that means 828d93f8e55SVinod Koul * unbind between source and sink has not happened yet 829d93f8e55SVinod Koul */ 830ce1b5551SJeeja KP ret = skl_stop_pipe(ctx, sink_mconfig->pipe); 831d93f8e55SVinod Koul if (ret < 0) 832d93f8e55SVinod Koul return ret; 833ce1b5551SJeeja KP ret = skl_unbind_modules(ctx, src_mconfig, 834ce1b5551SJeeja KP sink_mconfig); 835ce1b5551SJeeja KP } 836d93f8e55SVinod Koul } 837d93f8e55SVinod Koul 838d93f8e55SVinod Koul return ret; 839d93f8e55SVinod Koul } 840d93f8e55SVinod Koul 841d93f8e55SVinod Koul /* 842d93f8e55SVinod Koul * In modelling, we assume there will be ONLY one mixer in a pipeline. If 843d93f8e55SVinod Koul * mixer is not required then it is treated as static mixer aka vmixer with 844d93f8e55SVinod Koul * a hard path to source module 845d93f8e55SVinod Koul * So we don't need to check if source is started or not as hard path puts 846d93f8e55SVinod Koul * dependency on each other 847d93f8e55SVinod Koul */ 848d93f8e55SVinod Koul static int skl_tplg_vmixer_event(struct snd_soc_dapm_widget *w, 849d93f8e55SVinod Koul struct snd_kcontrol *k, int event) 850d93f8e55SVinod Koul { 851d93f8e55SVinod Koul struct snd_soc_dapm_context *dapm = w->dapm; 852d93f8e55SVinod Koul struct skl *skl = get_skl_ctx(dapm->dev); 853d93f8e55SVinod Koul 854d93f8e55SVinod Koul switch (event) { 855d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMU: 856d93f8e55SVinod Koul return skl_tplg_mixer_dapm_pre_pmu_event(w, skl); 857d93f8e55SVinod Koul 858d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMD: 859d93f8e55SVinod Koul return skl_tplg_mixer_dapm_post_pmd_event(w, skl); 860d93f8e55SVinod Koul } 861d93f8e55SVinod Koul 862d93f8e55SVinod Koul return 0; 863d93f8e55SVinod Koul } 864d93f8e55SVinod Koul 865d93f8e55SVinod Koul /* 866d93f8e55SVinod Koul * In modelling, we assume there will be ONLY one mixer in a pipeline. If a 867d93f8e55SVinod Koul * second one is required that is created as another pipe entity. 868d93f8e55SVinod Koul * The mixer is responsible for pipe management and represent a pipeline 869d93f8e55SVinod Koul * instance 870d93f8e55SVinod Koul */ 871d93f8e55SVinod Koul static int skl_tplg_mixer_event(struct snd_soc_dapm_widget *w, 872d93f8e55SVinod Koul struct snd_kcontrol *k, int event) 873d93f8e55SVinod Koul { 874d93f8e55SVinod Koul struct snd_soc_dapm_context *dapm = w->dapm; 875d93f8e55SVinod Koul struct skl *skl = get_skl_ctx(dapm->dev); 876d93f8e55SVinod Koul 877d93f8e55SVinod Koul switch (event) { 878d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMU: 879d93f8e55SVinod Koul return skl_tplg_mixer_dapm_pre_pmu_event(w, skl); 880d93f8e55SVinod Koul 881d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMU: 882d93f8e55SVinod Koul return skl_tplg_mixer_dapm_post_pmu_event(w, skl); 883d93f8e55SVinod Koul 884d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMD: 885d93f8e55SVinod Koul return skl_tplg_mixer_dapm_pre_pmd_event(w, skl); 886d93f8e55SVinod Koul 887d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMD: 888d93f8e55SVinod Koul return skl_tplg_mixer_dapm_post_pmd_event(w, skl); 889d93f8e55SVinod Koul } 890d93f8e55SVinod Koul 891d93f8e55SVinod Koul return 0; 892d93f8e55SVinod Koul } 893d93f8e55SVinod Koul 894d93f8e55SVinod Koul /* 895d93f8e55SVinod Koul * In modelling, we assumed rest of the modules in pipeline are PGA. But we 896d93f8e55SVinod Koul * are interested in last PGA (leaf PGA) in a pipeline to disconnect with 897d93f8e55SVinod Koul * the sink when it is running (two FE to one BE or one FE to two BE) 898d93f8e55SVinod Koul * scenarios 899d93f8e55SVinod Koul */ 900d93f8e55SVinod Koul static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w, 901d93f8e55SVinod Koul struct snd_kcontrol *k, int event) 902d93f8e55SVinod Koul 903d93f8e55SVinod Koul { 904d93f8e55SVinod Koul struct snd_soc_dapm_context *dapm = w->dapm; 905d93f8e55SVinod Koul struct skl *skl = get_skl_ctx(dapm->dev); 906d93f8e55SVinod Koul 907d93f8e55SVinod Koul switch (event) { 908d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMU: 909d93f8e55SVinod Koul return skl_tplg_pga_dapm_pre_pmu_event(w, skl); 910d93f8e55SVinod Koul 911d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMD: 912d93f8e55SVinod Koul return skl_tplg_pga_dapm_post_pmd_event(w, skl); 913d93f8e55SVinod Koul } 914d93f8e55SVinod Koul 915d93f8e55SVinod Koul return 0; 916d93f8e55SVinod Koul } 917cfb0a873SVinod Koul 918140adfbaSJeeja KP static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol, 919140adfbaSJeeja KP unsigned int __user *data, unsigned int size) 920140adfbaSJeeja KP { 921140adfbaSJeeja KP struct soc_bytes_ext *sb = 922140adfbaSJeeja KP (struct soc_bytes_ext *)kcontrol->private_value; 923140adfbaSJeeja KP struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private; 9247d9f2911SOmair M Abdullah struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); 9257d9f2911SOmair M Abdullah struct skl_module_cfg *mconfig = w->priv; 9267d9f2911SOmair M Abdullah struct skl *skl = get_skl_ctx(w->dapm->dev); 9277d9f2911SOmair M Abdullah 9287d9f2911SOmair M Abdullah if (w->power) 9297d9f2911SOmair M Abdullah skl_get_module_params(skl->skl_sst, (u32 *)bc->params, 9307d9f2911SOmair M Abdullah bc->max, bc->param_id, mconfig); 931140adfbaSJeeja KP 93241556f68SVinod Koul /* decrement size for TLV header */ 93341556f68SVinod Koul size -= 2 * sizeof(u32); 93441556f68SVinod Koul 93541556f68SVinod Koul /* check size as we don't want to send kernel data */ 93641556f68SVinod Koul if (size > bc->max) 93741556f68SVinod Koul size = bc->max; 93841556f68SVinod Koul 939140adfbaSJeeja KP if (bc->params) { 940140adfbaSJeeja KP if (copy_to_user(data, &bc->param_id, sizeof(u32))) 941140adfbaSJeeja KP return -EFAULT; 942e8bc3c99SDan Carpenter if (copy_to_user(data + 1, &size, sizeof(u32))) 943140adfbaSJeeja KP return -EFAULT; 944e8bc3c99SDan Carpenter if (copy_to_user(data + 2, bc->params, size)) 945140adfbaSJeeja KP return -EFAULT; 946140adfbaSJeeja KP } 947140adfbaSJeeja KP 948140adfbaSJeeja KP return 0; 949140adfbaSJeeja KP } 950140adfbaSJeeja KP 951140adfbaSJeeja KP #define SKL_PARAM_VENDOR_ID 0xff 952140adfbaSJeeja KP 953140adfbaSJeeja KP static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol, 954140adfbaSJeeja KP const unsigned int __user *data, unsigned int size) 955140adfbaSJeeja KP { 956140adfbaSJeeja KP struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); 957140adfbaSJeeja KP struct skl_module_cfg *mconfig = w->priv; 958140adfbaSJeeja KP struct soc_bytes_ext *sb = 959140adfbaSJeeja KP (struct soc_bytes_ext *)kcontrol->private_value; 960140adfbaSJeeja KP struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private; 961140adfbaSJeeja KP struct skl *skl = get_skl_ctx(w->dapm->dev); 962140adfbaSJeeja KP 963140adfbaSJeeja KP if (ac->params) { 964140adfbaSJeeja KP /* 965140adfbaSJeeja KP * if the param_is is of type Vendor, firmware expects actual 966140adfbaSJeeja KP * parameter id and size from the control. 967140adfbaSJeeja KP */ 968140adfbaSJeeja KP if (ac->param_id == SKL_PARAM_VENDOR_ID) { 969140adfbaSJeeja KP if (copy_from_user(ac->params, data, size)) 970140adfbaSJeeja KP return -EFAULT; 971140adfbaSJeeja KP } else { 972140adfbaSJeeja KP if (copy_from_user(ac->params, 973140adfbaSJeeja KP data + 2 * sizeof(u32), size)) 974140adfbaSJeeja KP return -EFAULT; 975140adfbaSJeeja KP } 976140adfbaSJeeja KP 977140adfbaSJeeja KP if (w->power) 978140adfbaSJeeja KP return skl_set_module_params(skl->skl_sst, 979140adfbaSJeeja KP (u32 *)ac->params, ac->max, 980140adfbaSJeeja KP ac->param_id, mconfig); 981140adfbaSJeeja KP } 982140adfbaSJeeja KP 983140adfbaSJeeja KP return 0; 984140adfbaSJeeja KP } 985140adfbaSJeeja KP 986cfb0a873SVinod Koul /* 987cfb0a873SVinod Koul * The FE params are passed by hw_params of the DAI. 988cfb0a873SVinod Koul * On hw_params, the params are stored in Gateway module of the FE and we 989cfb0a873SVinod Koul * need to calculate the format in DSP module configuration, that 990cfb0a873SVinod Koul * conversion is done here 991cfb0a873SVinod Koul */ 992cfb0a873SVinod Koul int skl_tplg_update_pipe_params(struct device *dev, 993cfb0a873SVinod Koul struct skl_module_cfg *mconfig, 994cfb0a873SVinod Koul struct skl_pipe_params *params) 995cfb0a873SVinod Koul { 996cfb0a873SVinod Koul struct skl_pipe *pipe = mconfig->pipe; 997cfb0a873SVinod Koul struct skl_module_fmt *format = NULL; 998cfb0a873SVinod Koul 999cfb0a873SVinod Koul memcpy(pipe->p_params, params, sizeof(*params)); 1000cfb0a873SVinod Koul 1001cfb0a873SVinod Koul if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) 10024cd9899fSHardik T Shah format = &mconfig->in_fmt[0]; 1003cfb0a873SVinod Koul else 10044cd9899fSHardik T Shah format = &mconfig->out_fmt[0]; 1005cfb0a873SVinod Koul 1006cfb0a873SVinod Koul /* set the hw_params */ 1007cfb0a873SVinod Koul format->s_freq = params->s_freq; 1008cfb0a873SVinod Koul format->channels = params->ch; 1009cfb0a873SVinod Koul format->valid_bit_depth = skl_get_bit_depth(params->s_fmt); 1010cfb0a873SVinod Koul 1011cfb0a873SVinod Koul /* 1012cfb0a873SVinod Koul * 16 bit is 16 bit container whereas 24 bit is in 32 bit 1013cfb0a873SVinod Koul * container so update bit depth accordingly 1014cfb0a873SVinod Koul */ 1015cfb0a873SVinod Koul switch (format->valid_bit_depth) { 1016cfb0a873SVinod Koul case SKL_DEPTH_16BIT: 1017cfb0a873SVinod Koul format->bit_depth = format->valid_bit_depth; 1018cfb0a873SVinod Koul break; 1019cfb0a873SVinod Koul 1020cfb0a873SVinod Koul case SKL_DEPTH_24BIT: 10216654f39eSJeeja KP case SKL_DEPTH_32BIT: 1022cfb0a873SVinod Koul format->bit_depth = SKL_DEPTH_32BIT; 1023cfb0a873SVinod Koul break; 1024cfb0a873SVinod Koul 1025cfb0a873SVinod Koul default: 1026cfb0a873SVinod Koul dev_err(dev, "Invalid bit depth %x for pipe\n", 1027cfb0a873SVinod Koul format->valid_bit_depth); 1028cfb0a873SVinod Koul return -EINVAL; 1029cfb0a873SVinod Koul } 1030cfb0a873SVinod Koul 1031cfb0a873SVinod Koul if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { 1032cfb0a873SVinod Koul mconfig->ibs = (format->s_freq / 1000) * 1033cfb0a873SVinod Koul (format->channels) * 1034cfb0a873SVinod Koul (format->bit_depth >> 3); 1035cfb0a873SVinod Koul } else { 1036cfb0a873SVinod Koul mconfig->obs = (format->s_freq / 1000) * 1037cfb0a873SVinod Koul (format->channels) * 1038cfb0a873SVinod Koul (format->bit_depth >> 3); 1039cfb0a873SVinod Koul } 1040cfb0a873SVinod Koul 1041cfb0a873SVinod Koul return 0; 1042cfb0a873SVinod Koul } 1043cfb0a873SVinod Koul 1044cfb0a873SVinod Koul /* 1045cfb0a873SVinod Koul * Query the module config for the FE DAI 1046cfb0a873SVinod Koul * This is used to find the hw_params set for that DAI and apply to FE 1047cfb0a873SVinod Koul * pipeline 1048cfb0a873SVinod Koul */ 1049cfb0a873SVinod Koul struct skl_module_cfg * 1050cfb0a873SVinod Koul skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream) 1051cfb0a873SVinod Koul { 1052cfb0a873SVinod Koul struct snd_soc_dapm_widget *w; 1053cfb0a873SVinod Koul struct snd_soc_dapm_path *p = NULL; 1054cfb0a873SVinod Koul 1055cfb0a873SVinod Koul if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 1056cfb0a873SVinod Koul w = dai->playback_widget; 1057f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_sink_path(w, p) { 1058cfb0a873SVinod Koul if (p->connect && p->sink->power && 1059a28f51dbSJeeja KP !is_skl_dsp_widget_type(p->sink)) 1060cfb0a873SVinod Koul continue; 1061cfb0a873SVinod Koul 1062cfb0a873SVinod Koul if (p->sink->priv) { 1063cfb0a873SVinod Koul dev_dbg(dai->dev, "set params for %s\n", 1064cfb0a873SVinod Koul p->sink->name); 1065cfb0a873SVinod Koul return p->sink->priv; 1066cfb0a873SVinod Koul } 1067cfb0a873SVinod Koul } 1068cfb0a873SVinod Koul } else { 1069cfb0a873SVinod Koul w = dai->capture_widget; 1070f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_source_path(w, p) { 1071cfb0a873SVinod Koul if (p->connect && p->source->power && 1072a28f51dbSJeeja KP !is_skl_dsp_widget_type(p->source)) 1073cfb0a873SVinod Koul continue; 1074cfb0a873SVinod Koul 1075cfb0a873SVinod Koul if (p->source->priv) { 1076cfb0a873SVinod Koul dev_dbg(dai->dev, "set params for %s\n", 1077cfb0a873SVinod Koul p->source->name); 1078cfb0a873SVinod Koul return p->source->priv; 1079cfb0a873SVinod Koul } 1080cfb0a873SVinod Koul } 1081cfb0a873SVinod Koul } 1082cfb0a873SVinod Koul 1083cfb0a873SVinod Koul return NULL; 1084cfb0a873SVinod Koul } 1085cfb0a873SVinod Koul 1086cfb0a873SVinod Koul static u8 skl_tplg_be_link_type(int dev_type) 1087cfb0a873SVinod Koul { 1088cfb0a873SVinod Koul int ret; 1089cfb0a873SVinod Koul 1090cfb0a873SVinod Koul switch (dev_type) { 1091cfb0a873SVinod Koul case SKL_DEVICE_BT: 1092cfb0a873SVinod Koul ret = NHLT_LINK_SSP; 1093cfb0a873SVinod Koul break; 1094cfb0a873SVinod Koul 1095cfb0a873SVinod Koul case SKL_DEVICE_DMIC: 1096cfb0a873SVinod Koul ret = NHLT_LINK_DMIC; 1097cfb0a873SVinod Koul break; 1098cfb0a873SVinod Koul 1099cfb0a873SVinod Koul case SKL_DEVICE_I2S: 1100cfb0a873SVinod Koul ret = NHLT_LINK_SSP; 1101cfb0a873SVinod Koul break; 1102cfb0a873SVinod Koul 1103cfb0a873SVinod Koul case SKL_DEVICE_HDALINK: 1104cfb0a873SVinod Koul ret = NHLT_LINK_HDA; 1105cfb0a873SVinod Koul break; 1106cfb0a873SVinod Koul 1107cfb0a873SVinod Koul default: 1108cfb0a873SVinod Koul ret = NHLT_LINK_INVALID; 1109cfb0a873SVinod Koul break; 1110cfb0a873SVinod Koul } 1111cfb0a873SVinod Koul 1112cfb0a873SVinod Koul return ret; 1113cfb0a873SVinod Koul } 1114cfb0a873SVinod Koul 1115cfb0a873SVinod Koul /* 1116cfb0a873SVinod Koul * Fill the BE gateway parameters 1117cfb0a873SVinod Koul * The BE gateway expects a blob of parameters which are kept in the ACPI 1118cfb0a873SVinod Koul * NHLT blob, so query the blob for interface type (i2s/pdm) and instance. 1119cfb0a873SVinod Koul * The port can have multiple settings so pick based on the PCM 1120cfb0a873SVinod Koul * parameters 1121cfb0a873SVinod Koul */ 1122cfb0a873SVinod Koul static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai, 1123cfb0a873SVinod Koul struct skl_module_cfg *mconfig, 1124cfb0a873SVinod Koul struct skl_pipe_params *params) 1125cfb0a873SVinod Koul { 1126cfb0a873SVinod Koul struct skl_pipe *pipe = mconfig->pipe; 1127cfb0a873SVinod Koul struct nhlt_specific_cfg *cfg; 1128cfb0a873SVinod Koul struct skl *skl = get_skl_ctx(dai->dev); 1129cfb0a873SVinod Koul int link_type = skl_tplg_be_link_type(mconfig->dev_type); 1130cfb0a873SVinod Koul 1131cfb0a873SVinod Koul memcpy(pipe->p_params, params, sizeof(*params)); 1132cfb0a873SVinod Koul 1133b30c275eSJeeja KP if (link_type == NHLT_LINK_HDA) 1134b30c275eSJeeja KP return 0; 1135b30c275eSJeeja KP 1136cfb0a873SVinod Koul /* update the blob based on virtual bus_id*/ 1137cfb0a873SVinod Koul cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type, 1138cfb0a873SVinod Koul params->s_fmt, params->ch, 1139cfb0a873SVinod Koul params->s_freq, params->stream); 1140cfb0a873SVinod Koul if (cfg) { 1141cfb0a873SVinod Koul mconfig->formats_config.caps_size = cfg->size; 1142bc03281aSJeeja KP mconfig->formats_config.caps = (u32 *) &cfg->caps; 1143cfb0a873SVinod Koul } else { 1144cfb0a873SVinod Koul dev_err(dai->dev, "Blob NULL for id %x type %d dirn %d\n", 1145cfb0a873SVinod Koul mconfig->vbus_id, link_type, 1146cfb0a873SVinod Koul params->stream); 1147cfb0a873SVinod Koul dev_err(dai->dev, "PCM: ch %d, freq %d, fmt %d\n", 1148cfb0a873SVinod Koul params->ch, params->s_freq, params->s_fmt); 1149cfb0a873SVinod Koul return -EINVAL; 1150cfb0a873SVinod Koul } 1151cfb0a873SVinod Koul 1152cfb0a873SVinod Koul return 0; 1153cfb0a873SVinod Koul } 1154cfb0a873SVinod Koul 1155cfb0a873SVinod Koul static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai, 1156cfb0a873SVinod Koul struct snd_soc_dapm_widget *w, 1157cfb0a873SVinod Koul struct skl_pipe_params *params) 1158cfb0a873SVinod Koul { 1159cfb0a873SVinod Koul struct snd_soc_dapm_path *p; 11604d8adccbSSubhransu S. Prusty int ret = -EIO; 1161cfb0a873SVinod Koul 1162f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_source_path(w, p) { 1163cfb0a873SVinod Koul if (p->connect && is_skl_dsp_widget_type(p->source) && 1164cfb0a873SVinod Koul p->source->priv) { 1165cfb0a873SVinod Koul 11669a03cb49SJeeja KP ret = skl_tplg_be_fill_pipe_params(dai, 11679a03cb49SJeeja KP p->source->priv, params); 11684d8adccbSSubhransu S. Prusty if (ret < 0) 11694d8adccbSSubhransu S. Prusty return ret; 1170cfb0a873SVinod Koul } else { 11719a03cb49SJeeja KP ret = skl_tplg_be_set_src_pipe_params(dai, 11729a03cb49SJeeja KP p->source, params); 11734d8adccbSSubhransu S. Prusty if (ret < 0) 11744d8adccbSSubhransu S. Prusty return ret; 1175cfb0a873SVinod Koul } 1176cfb0a873SVinod Koul } 1177cfb0a873SVinod Koul 11784d8adccbSSubhransu S. Prusty return ret; 1179cfb0a873SVinod Koul } 1180cfb0a873SVinod Koul 1181cfb0a873SVinod Koul static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai, 1182cfb0a873SVinod Koul struct snd_soc_dapm_widget *w, struct skl_pipe_params *params) 1183cfb0a873SVinod Koul { 1184cfb0a873SVinod Koul struct snd_soc_dapm_path *p = NULL; 11854d8adccbSSubhransu S. Prusty int ret = -EIO; 1186cfb0a873SVinod Koul 1187f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_sink_path(w, p) { 1188cfb0a873SVinod Koul if (p->connect && is_skl_dsp_widget_type(p->sink) && 1189cfb0a873SVinod Koul p->sink->priv) { 1190cfb0a873SVinod Koul 11919a03cb49SJeeja KP ret = skl_tplg_be_fill_pipe_params(dai, 11929a03cb49SJeeja KP p->sink->priv, params); 11934d8adccbSSubhransu S. Prusty if (ret < 0) 11944d8adccbSSubhransu S. Prusty return ret; 11954d8adccbSSubhransu S. Prusty } else { 11964d8adccbSSubhransu S. Prusty ret = skl_tplg_be_set_sink_pipe_params( 1197cfb0a873SVinod Koul dai, p->sink, params); 11984d8adccbSSubhransu S. Prusty if (ret < 0) 11994d8adccbSSubhransu S. Prusty return ret; 1200cfb0a873SVinod Koul } 1201cfb0a873SVinod Koul } 1202cfb0a873SVinod Koul 12034d8adccbSSubhransu S. Prusty return ret; 1204cfb0a873SVinod Koul } 1205cfb0a873SVinod Koul 1206cfb0a873SVinod Koul /* 1207cfb0a873SVinod Koul * BE hw_params can be a source parameters (capture) or sink parameters 1208cfb0a873SVinod Koul * (playback). Based on sink and source we need to either find the source 1209cfb0a873SVinod Koul * list or the sink list and set the pipeline parameters 1210cfb0a873SVinod Koul */ 1211cfb0a873SVinod Koul int skl_tplg_be_update_params(struct snd_soc_dai *dai, 1212cfb0a873SVinod Koul struct skl_pipe_params *params) 1213cfb0a873SVinod Koul { 1214cfb0a873SVinod Koul struct snd_soc_dapm_widget *w; 1215cfb0a873SVinod Koul 1216cfb0a873SVinod Koul if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { 1217cfb0a873SVinod Koul w = dai->playback_widget; 1218cfb0a873SVinod Koul 1219cfb0a873SVinod Koul return skl_tplg_be_set_src_pipe_params(dai, w, params); 1220cfb0a873SVinod Koul 1221cfb0a873SVinod Koul } else { 1222cfb0a873SVinod Koul w = dai->capture_widget; 1223cfb0a873SVinod Koul 1224cfb0a873SVinod Koul return skl_tplg_be_set_sink_pipe_params(dai, w, params); 1225cfb0a873SVinod Koul } 1226cfb0a873SVinod Koul 1227cfb0a873SVinod Koul return 0; 1228cfb0a873SVinod Koul } 12293af36706SVinod Koul 12303af36706SVinod Koul static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = { 12313af36706SVinod Koul {SKL_MIXER_EVENT, skl_tplg_mixer_event}, 12323af36706SVinod Koul {SKL_VMIXER_EVENT, skl_tplg_vmixer_event}, 12333af36706SVinod Koul {SKL_PGA_EVENT, skl_tplg_pga_event}, 12343af36706SVinod Koul }; 12353af36706SVinod Koul 1236140adfbaSJeeja KP static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = { 1237140adfbaSJeeja KP {SKL_CONTROL_TYPE_BYTE_TLV, skl_tplg_tlv_control_get, 1238140adfbaSJeeja KP skl_tplg_tlv_control_set}, 1239140adfbaSJeeja KP }; 1240140adfbaSJeeja KP 12413af36706SVinod Koul /* 12423af36706SVinod Koul * The topology binary passes the pin info for a module so initialize the pin 12433af36706SVinod Koul * info passed into module instance 12443af36706SVinod Koul */ 12456abca1d7SJeeja KP static void skl_fill_module_pin_info(struct skl_dfw_module_pin *dfw_pin, 12463af36706SVinod Koul struct skl_module_pin *m_pin, 12476abca1d7SJeeja KP bool is_dynamic, int max_pin) 12483af36706SVinod Koul { 12493af36706SVinod Koul int i; 12503af36706SVinod Koul 12513af36706SVinod Koul for (i = 0; i < max_pin; i++) { 12526abca1d7SJeeja KP m_pin[i].id.module_id = dfw_pin[i].module_id; 12536abca1d7SJeeja KP m_pin[i].id.instance_id = dfw_pin[i].instance_id; 12543af36706SVinod Koul m_pin[i].in_use = false; 12556abca1d7SJeeja KP m_pin[i].is_dynamic = is_dynamic; 12564f745708SJeeja KP m_pin[i].pin_state = SKL_PIN_UNBIND; 12573af36706SVinod Koul } 12583af36706SVinod Koul } 12593af36706SVinod Koul 12603af36706SVinod Koul /* 12613af36706SVinod Koul * Add pipeline from topology binary into driver pipeline list 12623af36706SVinod Koul * 12633af36706SVinod Koul * If already added we return that instance 12643af36706SVinod Koul * Otherwise we create a new instance and add into driver list 12653af36706SVinod Koul */ 12663af36706SVinod Koul static struct skl_pipe *skl_tplg_add_pipe(struct device *dev, 12673af36706SVinod Koul struct skl *skl, struct skl_dfw_pipe *dfw_pipe) 12683af36706SVinod Koul { 12693af36706SVinod Koul struct skl_pipeline *ppl; 12703af36706SVinod Koul struct skl_pipe *pipe; 12713af36706SVinod Koul struct skl_pipe_params *params; 12723af36706SVinod Koul 12733af36706SVinod Koul list_for_each_entry(ppl, &skl->ppl_list, node) { 12743af36706SVinod Koul if (ppl->pipe->ppl_id == dfw_pipe->pipe_id) 12753af36706SVinod Koul return ppl->pipe; 12763af36706SVinod Koul } 12773af36706SVinod Koul 12783af36706SVinod Koul ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL); 12793af36706SVinod Koul if (!ppl) 12803af36706SVinod Koul return NULL; 12813af36706SVinod Koul 12823af36706SVinod Koul pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL); 12833af36706SVinod Koul if (!pipe) 12843af36706SVinod Koul return NULL; 12853af36706SVinod Koul 12863af36706SVinod Koul params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL); 12873af36706SVinod Koul if (!params) 12883af36706SVinod Koul return NULL; 12893af36706SVinod Koul 12903af36706SVinod Koul pipe->ppl_id = dfw_pipe->pipe_id; 12913af36706SVinod Koul pipe->memory_pages = dfw_pipe->memory_pages; 12923af36706SVinod Koul pipe->pipe_priority = dfw_pipe->pipe_priority; 12933af36706SVinod Koul pipe->conn_type = dfw_pipe->conn_type; 12943af36706SVinod Koul pipe->state = SKL_PIPE_INVALID; 12953af36706SVinod Koul pipe->p_params = params; 12963af36706SVinod Koul INIT_LIST_HEAD(&pipe->w_list); 12973af36706SVinod Koul 12983af36706SVinod Koul ppl->pipe = pipe; 12993af36706SVinod Koul list_add(&ppl->node, &skl->ppl_list); 13003af36706SVinod Koul 13013af36706SVinod Koul return ppl->pipe; 13023af36706SVinod Koul } 13033af36706SVinod Koul 13044cd9899fSHardik T Shah static void skl_tplg_fill_fmt(struct skl_module_fmt *dst_fmt, 13054cd9899fSHardik T Shah struct skl_dfw_module_fmt *src_fmt, 13064cd9899fSHardik T Shah int pins) 13074cd9899fSHardik T Shah { 13084cd9899fSHardik T Shah int i; 13094cd9899fSHardik T Shah 13104cd9899fSHardik T Shah for (i = 0; i < pins; i++) { 13114cd9899fSHardik T Shah dst_fmt[i].channels = src_fmt[i].channels; 13124cd9899fSHardik T Shah dst_fmt[i].s_freq = src_fmt[i].freq; 13134cd9899fSHardik T Shah dst_fmt[i].bit_depth = src_fmt[i].bit_depth; 13144cd9899fSHardik T Shah dst_fmt[i].valid_bit_depth = src_fmt[i].valid_bit_depth; 13154cd9899fSHardik T Shah dst_fmt[i].ch_cfg = src_fmt[i].ch_cfg; 13164cd9899fSHardik T Shah dst_fmt[i].ch_map = src_fmt[i].ch_map; 13174cd9899fSHardik T Shah dst_fmt[i].interleaving_style = src_fmt[i].interleaving_style; 13184cd9899fSHardik T Shah dst_fmt[i].sample_type = src_fmt[i].sample_type; 13194cd9899fSHardik T Shah } 13204cd9899fSHardik T Shah } 13214cd9899fSHardik T Shah 13223af36706SVinod Koul /* 13233af36706SVinod Koul * Topology core widget load callback 13243af36706SVinod Koul * 13253af36706SVinod Koul * This is used to save the private data for each widget which gives 13263af36706SVinod Koul * information to the driver about module and pipeline parameters which DSP 13273af36706SVinod Koul * FW expects like ids, resource values, formats etc 13283af36706SVinod Koul */ 13293af36706SVinod Koul static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, 13303af36706SVinod Koul struct snd_soc_dapm_widget *w, 13313af36706SVinod Koul struct snd_soc_tplg_dapm_widget *tplg_w) 13323af36706SVinod Koul { 13333af36706SVinod Koul int ret; 13343af36706SVinod Koul struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt); 13353af36706SVinod Koul struct skl *skl = ebus_to_skl(ebus); 13363af36706SVinod Koul struct hdac_bus *bus = ebus_to_hbus(ebus); 13373af36706SVinod Koul struct skl_module_cfg *mconfig; 13383af36706SVinod Koul struct skl_pipe *pipe; 1339b663a8c5SJeeja KP struct skl_dfw_module *dfw_config = 1340b663a8c5SJeeja KP (struct skl_dfw_module *)tplg_w->priv.data; 13413af36706SVinod Koul 13423af36706SVinod Koul if (!tplg_w->priv.size) 13433af36706SVinod Koul goto bind_event; 13443af36706SVinod Koul 13453af36706SVinod Koul mconfig = devm_kzalloc(bus->dev, sizeof(*mconfig), GFP_KERNEL); 13463af36706SVinod Koul 13473af36706SVinod Koul if (!mconfig) 13483af36706SVinod Koul return -ENOMEM; 13493af36706SVinod Koul 13503af36706SVinod Koul w->priv = mconfig; 13513af36706SVinod Koul mconfig->id.module_id = dfw_config->module_id; 13523af36706SVinod Koul mconfig->id.instance_id = dfw_config->instance_id; 13533af36706SVinod Koul mconfig->mcps = dfw_config->max_mcps; 13543af36706SVinod Koul mconfig->ibs = dfw_config->ibs; 13553af36706SVinod Koul mconfig->obs = dfw_config->obs; 13563af36706SVinod Koul mconfig->core_id = dfw_config->core_id; 13573af36706SVinod Koul mconfig->max_in_queue = dfw_config->max_in_queue; 13583af36706SVinod Koul mconfig->max_out_queue = dfw_config->max_out_queue; 13593af36706SVinod Koul mconfig->is_loadable = dfw_config->is_loadable; 13604cd9899fSHardik T Shah skl_tplg_fill_fmt(mconfig->in_fmt, dfw_config->in_fmt, 13614cd9899fSHardik T Shah MODULE_MAX_IN_PINS); 13624cd9899fSHardik T Shah skl_tplg_fill_fmt(mconfig->out_fmt, dfw_config->out_fmt, 13634cd9899fSHardik T Shah MODULE_MAX_OUT_PINS); 13644cd9899fSHardik T Shah 13653af36706SVinod Koul mconfig->params_fixup = dfw_config->params_fixup; 13663af36706SVinod Koul mconfig->converter = dfw_config->converter; 13673af36706SVinod Koul mconfig->m_type = dfw_config->module_type; 13683af36706SVinod Koul mconfig->vbus_id = dfw_config->vbus_id; 1369b18c458dSJeeja KP mconfig->mem_pages = dfw_config->mem_pages; 13703af36706SVinod Koul 13713af36706SVinod Koul pipe = skl_tplg_add_pipe(bus->dev, skl, &dfw_config->pipe); 13723af36706SVinod Koul if (pipe) 13733af36706SVinod Koul mconfig->pipe = pipe; 13743af36706SVinod Koul 13753af36706SVinod Koul mconfig->dev_type = dfw_config->dev_type; 13763af36706SVinod Koul mconfig->hw_conn_type = dfw_config->hw_conn_type; 13773af36706SVinod Koul mconfig->time_slot = dfw_config->time_slot; 13783af36706SVinod Koul mconfig->formats_config.caps_size = dfw_config->caps.caps_size; 13793af36706SVinod Koul 138065aecfa8SHardik T Shah if (dfw_config->is_loadable) 138165aecfa8SHardik T Shah memcpy(mconfig->guid, dfw_config->uuid, 138265aecfa8SHardik T Shah ARRAY_SIZE(dfw_config->uuid)); 138365aecfa8SHardik T Shah 13844cd9899fSHardik T Shah mconfig->m_in_pin = devm_kzalloc(bus->dev, (mconfig->max_in_queue) * 13853af36706SVinod Koul sizeof(*mconfig->m_in_pin), 13863af36706SVinod Koul GFP_KERNEL); 13873af36706SVinod Koul if (!mconfig->m_in_pin) 13883af36706SVinod Koul return -ENOMEM; 13893af36706SVinod Koul 13906abca1d7SJeeja KP mconfig->m_out_pin = devm_kzalloc(bus->dev, (mconfig->max_out_queue) * 13913af36706SVinod Koul sizeof(*mconfig->m_out_pin), 13923af36706SVinod Koul GFP_KERNEL); 13933af36706SVinod Koul if (!mconfig->m_out_pin) 13943af36706SVinod Koul return -ENOMEM; 13953af36706SVinod Koul 13966abca1d7SJeeja KP skl_fill_module_pin_info(dfw_config->in_pin, mconfig->m_in_pin, 13976abca1d7SJeeja KP dfw_config->is_dynamic_in_pin, 13983af36706SVinod Koul mconfig->max_in_queue); 13996abca1d7SJeeja KP 14006abca1d7SJeeja KP skl_fill_module_pin_info(dfw_config->out_pin, mconfig->m_out_pin, 14016abca1d7SJeeja KP dfw_config->is_dynamic_out_pin, 14023af36706SVinod Koul mconfig->max_out_queue); 14033af36706SVinod Koul 14046abca1d7SJeeja KP 14053af36706SVinod Koul if (mconfig->formats_config.caps_size == 0) 14063af36706SVinod Koul goto bind_event; 14073af36706SVinod Koul 14083af36706SVinod Koul mconfig->formats_config.caps = (u32 *)devm_kzalloc(bus->dev, 14093af36706SVinod Koul mconfig->formats_config.caps_size, GFP_KERNEL); 14103af36706SVinod Koul 14113af36706SVinod Koul if (mconfig->formats_config.caps == NULL) 14123af36706SVinod Koul return -ENOMEM; 14133af36706SVinod Koul 14143af36706SVinod Koul memcpy(mconfig->formats_config.caps, dfw_config->caps.caps, 14153af36706SVinod Koul dfw_config->caps.caps_size); 1416abb74003SJeeja KP mconfig->formats_config.param_id = dfw_config->caps.param_id; 1417abb74003SJeeja KP mconfig->formats_config.set_params = dfw_config->caps.set_params; 14183af36706SVinod Koul 14193af36706SVinod Koul bind_event: 14203af36706SVinod Koul if (tplg_w->event_type == 0) { 14213373f716SVinod Koul dev_dbg(bus->dev, "ASoC: No event handler required\n"); 14223af36706SVinod Koul return 0; 14233af36706SVinod Koul } 14243af36706SVinod Koul 14253af36706SVinod Koul ret = snd_soc_tplg_widget_bind_event(w, skl_tplg_widget_ops, 1426b663a8c5SJeeja KP ARRAY_SIZE(skl_tplg_widget_ops), 1427b663a8c5SJeeja KP tplg_w->event_type); 14283af36706SVinod Koul 14293af36706SVinod Koul if (ret) { 14303af36706SVinod Koul dev_err(bus->dev, "%s: No matching event handlers found for %d\n", 14313af36706SVinod Koul __func__, tplg_w->event_type); 14323af36706SVinod Koul return -EINVAL; 14333af36706SVinod Koul } 14343af36706SVinod Koul 14353af36706SVinod Koul return 0; 14363af36706SVinod Koul } 14373af36706SVinod Koul 1438140adfbaSJeeja KP static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be, 1439140adfbaSJeeja KP struct snd_soc_tplg_bytes_control *bc) 1440140adfbaSJeeja KP { 1441140adfbaSJeeja KP struct skl_algo_data *ac; 1442140adfbaSJeeja KP struct skl_dfw_algo_data *dfw_ac = 1443140adfbaSJeeja KP (struct skl_dfw_algo_data *)bc->priv.data; 1444140adfbaSJeeja KP 1445140adfbaSJeeja KP ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL); 1446140adfbaSJeeja KP if (!ac) 1447140adfbaSJeeja KP return -ENOMEM; 1448140adfbaSJeeja KP 1449140adfbaSJeeja KP /* Fill private data */ 1450140adfbaSJeeja KP ac->max = dfw_ac->max; 1451140adfbaSJeeja KP ac->param_id = dfw_ac->param_id; 1452140adfbaSJeeja KP ac->set_params = dfw_ac->set_params; 1453140adfbaSJeeja KP 1454140adfbaSJeeja KP if (ac->max) { 1455140adfbaSJeeja KP ac->params = (char *) devm_kzalloc(dev, ac->max, GFP_KERNEL); 1456140adfbaSJeeja KP if (!ac->params) 1457140adfbaSJeeja KP return -ENOMEM; 1458140adfbaSJeeja KP 1459140adfbaSJeeja KP if (dfw_ac->params) 1460140adfbaSJeeja KP memcpy(ac->params, dfw_ac->params, ac->max); 1461140adfbaSJeeja KP } 1462140adfbaSJeeja KP 1463140adfbaSJeeja KP be->dobj.private = ac; 1464140adfbaSJeeja KP return 0; 1465140adfbaSJeeja KP } 1466140adfbaSJeeja KP 1467140adfbaSJeeja KP static int skl_tplg_control_load(struct snd_soc_component *cmpnt, 1468140adfbaSJeeja KP struct snd_kcontrol_new *kctl, 1469140adfbaSJeeja KP struct snd_soc_tplg_ctl_hdr *hdr) 1470140adfbaSJeeja KP { 1471140adfbaSJeeja KP struct soc_bytes_ext *sb; 1472140adfbaSJeeja KP struct snd_soc_tplg_bytes_control *tplg_bc; 1473140adfbaSJeeja KP struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt); 1474140adfbaSJeeja KP struct hdac_bus *bus = ebus_to_hbus(ebus); 1475140adfbaSJeeja KP 1476140adfbaSJeeja KP switch (hdr->ops.info) { 1477140adfbaSJeeja KP case SND_SOC_TPLG_CTL_BYTES: 1478140adfbaSJeeja KP tplg_bc = container_of(hdr, 1479140adfbaSJeeja KP struct snd_soc_tplg_bytes_control, hdr); 1480140adfbaSJeeja KP if (kctl->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 1481140adfbaSJeeja KP sb = (struct soc_bytes_ext *)kctl->private_value; 1482140adfbaSJeeja KP if (tplg_bc->priv.size) 1483140adfbaSJeeja KP return skl_init_algo_data( 1484140adfbaSJeeja KP bus->dev, sb, tplg_bc); 1485140adfbaSJeeja KP } 1486140adfbaSJeeja KP break; 1487140adfbaSJeeja KP 1488140adfbaSJeeja KP default: 1489140adfbaSJeeja KP dev_warn(bus->dev, "Control load not supported %d:%d:%d\n", 1490140adfbaSJeeja KP hdr->ops.get, hdr->ops.put, hdr->ops.info); 1491140adfbaSJeeja KP break; 1492140adfbaSJeeja KP } 1493140adfbaSJeeja KP 1494140adfbaSJeeja KP return 0; 1495140adfbaSJeeja KP } 1496140adfbaSJeeja KP 14973af36706SVinod Koul static struct snd_soc_tplg_ops skl_tplg_ops = { 14983af36706SVinod Koul .widget_load = skl_tplg_widget_load, 1499140adfbaSJeeja KP .control_load = skl_tplg_control_load, 1500140adfbaSJeeja KP .bytes_ext_ops = skl_tlv_ops, 1501140adfbaSJeeja KP .bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops), 15023af36706SVinod Koul }; 15033af36706SVinod Koul 15043af36706SVinod Koul /* This will be read from topology manifest, currently defined here */ 15053af36706SVinod Koul #define SKL_MAX_MCPS 30000000 15063af36706SVinod Koul #define SKL_FW_MAX_MEM 1000000 15073af36706SVinod Koul 15083af36706SVinod Koul /* 15093af36706SVinod Koul * SKL topology init routine 15103af36706SVinod Koul */ 15113af36706SVinod Koul int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus) 15123af36706SVinod Koul { 15133af36706SVinod Koul int ret; 15143af36706SVinod Koul const struct firmware *fw; 15153af36706SVinod Koul struct hdac_bus *bus = ebus_to_hbus(ebus); 15163af36706SVinod Koul struct skl *skl = ebus_to_skl(ebus); 15173af36706SVinod Koul 15183af36706SVinod Koul ret = request_firmware(&fw, "dfw_sst.bin", bus->dev); 15193af36706SVinod Koul if (ret < 0) { 1520b663a8c5SJeeja KP dev_err(bus->dev, "tplg fw %s load failed with %d\n", 15213af36706SVinod Koul "dfw_sst.bin", ret); 15223af36706SVinod Koul return ret; 15233af36706SVinod Koul } 15243af36706SVinod Koul 15253af36706SVinod Koul /* 15263af36706SVinod Koul * The complete tplg for SKL is loaded as index 0, we don't use 15273af36706SVinod Koul * any other index 15283af36706SVinod Koul */ 1529b663a8c5SJeeja KP ret = snd_soc_tplg_component_load(&platform->component, 1530b663a8c5SJeeja KP &skl_tplg_ops, fw, 0); 153187b5ed8eSSudip Mukherjee release_firmware(fw); 15323af36706SVinod Koul if (ret < 0) { 15333af36706SVinod Koul dev_err(bus->dev, "tplg component load failed%d\n", ret); 1534c14a82c7SSudip Mukherjee release_firmware(fw); 15353af36706SVinod Koul return -EINVAL; 15363af36706SVinod Koul } 15373af36706SVinod Koul 15383af36706SVinod Koul skl->resource.max_mcps = SKL_MAX_MCPS; 15393af36706SVinod Koul skl->resource.max_mem = SKL_FW_MAX_MEM; 15403af36706SVinod Koul 15413af36706SVinod Koul return 0; 15423af36706SVinod Koul } 1543