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"); 132f7590d4fSJeeja KP dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt.channels); 133f7590d4fSJeeja KP dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->in_fmt.s_freq); 134f7590d4fSJeeja KP dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->in_fmt.ch_cfg); 135f7590d4fSJeeja KP dev_dbg(ctx->dev, "valid bit depth = %d\n", 136f7590d4fSJeeja KP mcfg->in_fmt.valid_bit_depth); 137f7590d4fSJeeja KP dev_dbg(ctx->dev, "Output Format:\n"); 138f7590d4fSJeeja KP dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt.channels); 139f7590d4fSJeeja KP dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->out_fmt.s_freq); 140f7590d4fSJeeja KP dev_dbg(ctx->dev, "valid bit depth = %d\n", 141f7590d4fSJeeja KP mcfg->out_fmt.valid_bit_depth); 142f7590d4fSJeeja KP dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt.ch_cfg); 143f7590d4fSJeeja KP } 144f7590d4fSJeeja KP 145f7590d4fSJeeja KP static void skl_tplg_update_params(struct skl_module_fmt *fmt, 146f7590d4fSJeeja KP struct skl_pipe_params *params, int fixup) 147f7590d4fSJeeja KP { 148f7590d4fSJeeja KP if (fixup & SKL_RATE_FIXUP_MASK) 149f7590d4fSJeeja KP fmt->s_freq = params->s_freq; 150f7590d4fSJeeja KP if (fixup & SKL_CH_FIXUP_MASK) 151f7590d4fSJeeja KP fmt->channels = params->ch; 152f7590d4fSJeeja KP if (fixup & SKL_FMT_FIXUP_MASK) 153f7590d4fSJeeja KP fmt->valid_bit_depth = params->s_fmt; 154f7590d4fSJeeja KP } 155f7590d4fSJeeja KP 156f7590d4fSJeeja KP /* 157f7590d4fSJeeja KP * A pipeline may have modules which impact the pcm parameters, like SRC, 158f7590d4fSJeeja KP * channel converter, format converter. 159f7590d4fSJeeja KP * We need to calculate the output params by applying the 'fixup' 160f7590d4fSJeeja KP * Topology will tell driver which type of fixup is to be applied by 161f7590d4fSJeeja KP * supplying the fixup mask, so based on that we calculate the output 162f7590d4fSJeeja KP * 163f7590d4fSJeeja KP * Now In FE the pcm hw_params is source/target format. Same is applicable 164f7590d4fSJeeja KP * for BE with its hw_params invoked. 165f7590d4fSJeeja KP * here based on FE, BE pipeline and direction we calculate the input and 166f7590d4fSJeeja KP * outfix and then apply that for a module 167f7590d4fSJeeja KP */ 168f7590d4fSJeeja KP static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg, 169f7590d4fSJeeja KP struct skl_pipe_params *params, bool is_fe) 170f7590d4fSJeeja KP { 171f7590d4fSJeeja KP int in_fixup, out_fixup; 172f7590d4fSJeeja KP struct skl_module_fmt *in_fmt, *out_fmt; 173f7590d4fSJeeja KP 174f7590d4fSJeeja KP in_fmt = &m_cfg->in_fmt; 175f7590d4fSJeeja KP out_fmt = &m_cfg->out_fmt; 176f7590d4fSJeeja KP 177f7590d4fSJeeja KP if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { 178f7590d4fSJeeja KP if (is_fe) { 179f7590d4fSJeeja KP in_fixup = m_cfg->params_fixup; 180f7590d4fSJeeja KP out_fixup = (~m_cfg->converter) & 181f7590d4fSJeeja KP m_cfg->params_fixup; 182f7590d4fSJeeja KP } else { 183f7590d4fSJeeja KP out_fixup = m_cfg->params_fixup; 184f7590d4fSJeeja KP in_fixup = (~m_cfg->converter) & 185f7590d4fSJeeja KP m_cfg->params_fixup; 186f7590d4fSJeeja KP } 187f7590d4fSJeeja KP } else { 188f7590d4fSJeeja KP if (is_fe) { 189f7590d4fSJeeja KP out_fixup = m_cfg->params_fixup; 190f7590d4fSJeeja KP in_fixup = (~m_cfg->converter) & 191f7590d4fSJeeja KP m_cfg->params_fixup; 192f7590d4fSJeeja KP } else { 193f7590d4fSJeeja KP in_fixup = m_cfg->params_fixup; 194f7590d4fSJeeja KP out_fixup = (~m_cfg->converter) & 195f7590d4fSJeeja KP m_cfg->params_fixup; 196f7590d4fSJeeja KP } 197f7590d4fSJeeja KP } 198f7590d4fSJeeja KP 199f7590d4fSJeeja KP skl_tplg_update_params(in_fmt, params, in_fixup); 200f7590d4fSJeeja KP skl_tplg_update_params(out_fmt, params, out_fixup); 201f7590d4fSJeeja KP } 202f7590d4fSJeeja KP 203f7590d4fSJeeja KP /* 204f7590d4fSJeeja KP * A module needs input and output buffers, which are dependent upon pcm 205f7590d4fSJeeja KP * params, so once we have calculate params, we need buffer calculation as 206f7590d4fSJeeja KP * well. 207f7590d4fSJeeja KP */ 208f7590d4fSJeeja KP static void skl_tplg_update_buffer_size(struct skl_sst *ctx, 209f7590d4fSJeeja KP struct skl_module_cfg *mcfg) 210f7590d4fSJeeja KP { 211f7590d4fSJeeja KP int multiplier = 1; 212f7590d4fSJeeja KP 213f7590d4fSJeeja KP if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT) 214f7590d4fSJeeja KP multiplier = 5; 215f7590d4fSJeeja KP 216f7590d4fSJeeja KP mcfg->ibs = (mcfg->in_fmt.s_freq / 1000) * 217f7590d4fSJeeja KP (mcfg->in_fmt.channels) * 218f7590d4fSJeeja KP (mcfg->in_fmt.bit_depth >> 3) * 219f7590d4fSJeeja KP multiplier; 220f7590d4fSJeeja KP 221f7590d4fSJeeja KP mcfg->obs = (mcfg->out_fmt.s_freq / 1000) * 222f7590d4fSJeeja KP (mcfg->out_fmt.channels) * 223f7590d4fSJeeja KP (mcfg->out_fmt.bit_depth >> 3) * 224f7590d4fSJeeja KP multiplier; 225f7590d4fSJeeja KP } 226f7590d4fSJeeja KP 227f7590d4fSJeeja KP static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w, 228f7590d4fSJeeja KP struct skl_sst *ctx) 229f7590d4fSJeeja KP { 230f7590d4fSJeeja KP struct skl_module_cfg *m_cfg = w->priv; 231f7590d4fSJeeja KP struct skl_pipe_params *params = m_cfg->pipe->p_params; 232f7590d4fSJeeja KP int p_conn_type = m_cfg->pipe->conn_type; 233f7590d4fSJeeja KP bool is_fe; 234f7590d4fSJeeja KP 235f7590d4fSJeeja KP if (!m_cfg->params_fixup) 236f7590d4fSJeeja KP return; 237f7590d4fSJeeja KP 238f7590d4fSJeeja KP dev_dbg(ctx->dev, "Mconfig for widget=%s BEFORE updation\n", 239f7590d4fSJeeja KP w->name); 240f7590d4fSJeeja KP 241f7590d4fSJeeja KP skl_dump_mconfig(ctx, m_cfg); 242f7590d4fSJeeja KP 243f7590d4fSJeeja KP if (p_conn_type == SKL_PIPE_CONN_TYPE_FE) 244f7590d4fSJeeja KP is_fe = true; 245f7590d4fSJeeja KP else 246f7590d4fSJeeja KP is_fe = false; 247f7590d4fSJeeja KP 248f7590d4fSJeeja KP skl_tplg_update_params_fixup(m_cfg, params, is_fe); 249f7590d4fSJeeja KP skl_tplg_update_buffer_size(ctx, m_cfg); 250f7590d4fSJeeja KP 251f7590d4fSJeeja KP dev_dbg(ctx->dev, "Mconfig for widget=%s AFTER updation\n", 252f7590d4fSJeeja KP w->name); 253f7590d4fSJeeja KP 254f7590d4fSJeeja KP skl_dump_mconfig(ctx, m_cfg); 255f7590d4fSJeeja KP } 256f7590d4fSJeeja KP 257e4e2d2f4SJeeja KP /* 258e4e2d2f4SJeeja KP * A pipe can have multiple modules, each of them will be a DAPM widget as 259e4e2d2f4SJeeja KP * well. While managing a pipeline we need to get the list of all the 260e4e2d2f4SJeeja KP * widgets in a pipelines, so this helper - skl_tplg_get_pipe_widget() helps 261e4e2d2f4SJeeja KP * to get the SKL type widgets in that pipeline 262e4e2d2f4SJeeja KP */ 263e4e2d2f4SJeeja KP static int skl_tplg_alloc_pipe_widget(struct device *dev, 264e4e2d2f4SJeeja KP struct snd_soc_dapm_widget *w, struct skl_pipe *pipe) 265e4e2d2f4SJeeja KP { 266e4e2d2f4SJeeja KP struct skl_module_cfg *src_module = NULL; 267e4e2d2f4SJeeja KP struct snd_soc_dapm_path *p = NULL; 268e4e2d2f4SJeeja KP struct skl_pipe_module *p_module = NULL; 269e4e2d2f4SJeeja KP 270e4e2d2f4SJeeja KP p_module = devm_kzalloc(dev, sizeof(*p_module), GFP_KERNEL); 271e4e2d2f4SJeeja KP if (!p_module) 272e4e2d2f4SJeeja KP return -ENOMEM; 273e4e2d2f4SJeeja KP 274e4e2d2f4SJeeja KP p_module->w = w; 275e4e2d2f4SJeeja KP list_add_tail(&p_module->node, &pipe->w_list); 276e4e2d2f4SJeeja KP 277e4e2d2f4SJeeja KP snd_soc_dapm_widget_for_each_sink_path(w, p) { 278e4e2d2f4SJeeja KP if ((p->sink->priv == NULL) 279e4e2d2f4SJeeja KP && (!is_skl_dsp_widget_type(w))) 280e4e2d2f4SJeeja KP continue; 281e4e2d2f4SJeeja KP 282e4e2d2f4SJeeja KP if ((p->sink->priv != NULL) && p->connect 283e4e2d2f4SJeeja KP && is_skl_dsp_widget_type(p->sink)) { 284e4e2d2f4SJeeja KP 285e4e2d2f4SJeeja KP src_module = p->sink->priv; 286e4e2d2f4SJeeja KP if (pipe->ppl_id == src_module->pipe->ppl_id) 287e4e2d2f4SJeeja KP skl_tplg_alloc_pipe_widget(dev, 288e4e2d2f4SJeeja KP p->sink, pipe); 289e4e2d2f4SJeeja KP } 290e4e2d2f4SJeeja KP } 291e4e2d2f4SJeeja KP return 0; 292e4e2d2f4SJeeja KP } 293e4e2d2f4SJeeja KP 294e4e2d2f4SJeeja KP /* 295e4e2d2f4SJeeja KP * Inside a pipe instance, we can have various modules. These modules need 296e4e2d2f4SJeeja KP * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by 297e4e2d2f4SJeeja KP * skl_init_module() routine, so invoke that for all modules in a pipeline 298e4e2d2f4SJeeja KP */ 299e4e2d2f4SJeeja KP static int 300e4e2d2f4SJeeja KP skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) 301e4e2d2f4SJeeja KP { 302e4e2d2f4SJeeja KP struct skl_pipe_module *w_module; 303e4e2d2f4SJeeja KP struct snd_soc_dapm_widget *w; 304e4e2d2f4SJeeja KP struct skl_module_cfg *mconfig; 305e4e2d2f4SJeeja KP struct skl_sst *ctx = skl->skl_sst; 306e4e2d2f4SJeeja KP int ret = 0; 307e4e2d2f4SJeeja KP 308e4e2d2f4SJeeja KP list_for_each_entry(w_module, &pipe->w_list, node) { 309e4e2d2f4SJeeja KP w = w_module->w; 310e4e2d2f4SJeeja KP mconfig = w->priv; 311e4e2d2f4SJeeja KP 312e4e2d2f4SJeeja KP /* check resource available */ 313e4e2d2f4SJeeja KP if (!skl_tplg_alloc_pipe_mcps(skl, mconfig)) 314e4e2d2f4SJeeja KP return -ENOMEM; 315e4e2d2f4SJeeja KP 316f7590d4fSJeeja KP /* 317f7590d4fSJeeja KP * apply fix/conversion to module params based on 318f7590d4fSJeeja KP * FE/BE params 319f7590d4fSJeeja KP */ 320f7590d4fSJeeja KP skl_tplg_update_module_params(w, ctx); 321e4e2d2f4SJeeja KP ret = skl_init_module(ctx, mconfig, NULL); 322e4e2d2f4SJeeja KP if (ret < 0) 323e4e2d2f4SJeeja KP return ret; 324e4e2d2f4SJeeja KP } 325e4e2d2f4SJeeja KP 326e4e2d2f4SJeeja KP return 0; 327e4e2d2f4SJeeja KP } 328d93f8e55SVinod Koul 329d93f8e55SVinod Koul /* 330d93f8e55SVinod Koul * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we 331d93f8e55SVinod Koul * need create the pipeline. So we do following: 332d93f8e55SVinod Koul * - check the resources 333d93f8e55SVinod Koul * - Create the pipeline 334d93f8e55SVinod Koul * - Initialize the modules in pipeline 335d93f8e55SVinod Koul * - finally bind all modules together 336d93f8e55SVinod Koul */ 337d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, 338d93f8e55SVinod Koul struct skl *skl) 339d93f8e55SVinod Koul { 340d93f8e55SVinod Koul int ret; 341d93f8e55SVinod Koul struct skl_module_cfg *mconfig = w->priv; 342d93f8e55SVinod Koul struct skl_pipe_module *w_module; 343d93f8e55SVinod Koul struct skl_pipe *s_pipe = mconfig->pipe; 344d93f8e55SVinod Koul struct skl_module_cfg *src_module = NULL, *dst_module; 345d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 346d93f8e55SVinod Koul 347d93f8e55SVinod Koul /* check resource available */ 348d93f8e55SVinod Koul if (!skl_tplg_alloc_pipe_mcps(skl, mconfig)) 349d93f8e55SVinod Koul return -EBUSY; 350d93f8e55SVinod Koul 351d93f8e55SVinod Koul if (!skl_tplg_alloc_pipe_mem(skl, mconfig)) 352d93f8e55SVinod Koul return -ENOMEM; 353d93f8e55SVinod Koul 354d93f8e55SVinod Koul /* 355d93f8e55SVinod Koul * Create a list of modules for pipe. 356d93f8e55SVinod Koul * This list contains modules from source to sink 357d93f8e55SVinod Koul */ 358d93f8e55SVinod Koul ret = skl_create_pipeline(ctx, mconfig->pipe); 359d93f8e55SVinod Koul if (ret < 0) 360d93f8e55SVinod Koul return ret; 361d93f8e55SVinod Koul 362d93f8e55SVinod Koul /* 363d93f8e55SVinod Koul * we create a w_list of all widgets in that pipe. This list is not 364d93f8e55SVinod Koul * freed on PMD event as widgets within a pipe are static. This 365d93f8e55SVinod Koul * saves us cycles to get widgets in pipe every time. 366d93f8e55SVinod Koul * 367d93f8e55SVinod Koul * So if we have already initialized all the widgets of a pipeline 368d93f8e55SVinod Koul * we skip, so check for list_empty and create the list if empty 369d93f8e55SVinod Koul */ 370d93f8e55SVinod Koul if (list_empty(&s_pipe->w_list)) { 371d93f8e55SVinod Koul ret = skl_tplg_alloc_pipe_widget(ctx->dev, w, s_pipe); 372d93f8e55SVinod Koul if (ret < 0) 373d93f8e55SVinod Koul return ret; 374d93f8e55SVinod Koul } 375d93f8e55SVinod Koul 376d93f8e55SVinod Koul /* Init all pipe modules from source to sink */ 377d93f8e55SVinod Koul ret = skl_tplg_init_pipe_modules(skl, s_pipe); 378d93f8e55SVinod Koul if (ret < 0) 379d93f8e55SVinod Koul return ret; 380d93f8e55SVinod Koul 381d93f8e55SVinod Koul /* Bind modules from source to sink */ 382d93f8e55SVinod Koul list_for_each_entry(w_module, &s_pipe->w_list, node) { 383d93f8e55SVinod Koul dst_module = w_module->w->priv; 384d93f8e55SVinod Koul 385d93f8e55SVinod Koul if (src_module == NULL) { 386d93f8e55SVinod Koul src_module = dst_module; 387d93f8e55SVinod Koul continue; 388d93f8e55SVinod Koul } 389d93f8e55SVinod Koul 390d93f8e55SVinod Koul ret = skl_bind_modules(ctx, src_module, dst_module); 391d93f8e55SVinod Koul if (ret < 0) 392d93f8e55SVinod Koul return ret; 393d93f8e55SVinod Koul 394d93f8e55SVinod Koul src_module = dst_module; 395d93f8e55SVinod Koul } 396d93f8e55SVinod Koul 397d93f8e55SVinod Koul return 0; 398d93f8e55SVinod Koul } 399d93f8e55SVinod Koul 400d93f8e55SVinod Koul /* 401d93f8e55SVinod Koul * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA 402d93f8e55SVinod Koul * we need to do following: 403d93f8e55SVinod Koul * - Bind to sink pipeline 404d93f8e55SVinod Koul * Since the sink pipes can be running and we don't get mixer event on 405d93f8e55SVinod Koul * connect for already running mixer, we need to find the sink pipes 406d93f8e55SVinod Koul * here and bind to them. This way dynamic connect works. 407d93f8e55SVinod Koul * - Start sink pipeline, if not running 408d93f8e55SVinod Koul * - Then run current pipe 409d93f8e55SVinod Koul */ 410d93f8e55SVinod Koul static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, 411d93f8e55SVinod Koul struct skl *skl) 412d93f8e55SVinod Koul { 413d93f8e55SVinod Koul struct snd_soc_dapm_path *p; 414d93f8e55SVinod Koul struct skl_dapm_path_list *path_list; 415d93f8e55SVinod Koul struct snd_soc_dapm_widget *source, *sink; 416d93f8e55SVinod Koul struct skl_module_cfg *src_mconfig, *sink_mconfig; 417d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 418d93f8e55SVinod Koul int ret = 0; 419d93f8e55SVinod Koul 420d93f8e55SVinod Koul source = w; 421d93f8e55SVinod Koul src_mconfig = source->priv; 422d93f8e55SVinod Koul 423d93f8e55SVinod Koul /* 424d93f8e55SVinod Koul * find which sink it is connected to, bind with the sink, 425d93f8e55SVinod Koul * if sink is not started, start sink pipe first, then start 426d93f8e55SVinod Koul * this pipe 427d93f8e55SVinod Koul */ 428d93f8e55SVinod Koul snd_soc_dapm_widget_for_each_source_path(w, p) { 429d93f8e55SVinod Koul if (!p->connect) 430d93f8e55SVinod Koul continue; 431d93f8e55SVinod Koul 432d93f8e55SVinod Koul dev_dbg(ctx->dev, "%s: src widget=%s\n", __func__, w->name); 433d93f8e55SVinod Koul dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name); 434d93f8e55SVinod Koul 435d93f8e55SVinod Koul /* 436d93f8e55SVinod Koul * here we will check widgets in sink pipelines, so that 437d93f8e55SVinod Koul * can be any widgets type and we are only interested if 438d93f8e55SVinod Koul * they are ones used for SKL so check that first 439d93f8e55SVinod Koul */ 440d93f8e55SVinod Koul if ((p->sink->priv != NULL) && 441d93f8e55SVinod Koul is_skl_dsp_widget_type(p->sink)) { 442d93f8e55SVinod Koul 443d93f8e55SVinod Koul sink = p->sink; 444d93f8e55SVinod Koul src_mconfig = source->priv; 445d93f8e55SVinod Koul sink_mconfig = sink->priv; 446d93f8e55SVinod Koul 447d93f8e55SVinod Koul /* Bind source to sink, mixin is always source */ 448d93f8e55SVinod Koul ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig); 449d93f8e55SVinod Koul if (ret) 450d93f8e55SVinod Koul return ret; 451d93f8e55SVinod Koul 452d93f8e55SVinod Koul /* Start sinks pipe first */ 453d93f8e55SVinod Koul if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) { 454d93f8e55SVinod Koul ret = skl_run_pipe(ctx, sink_mconfig->pipe); 455d93f8e55SVinod Koul if (ret) 456d93f8e55SVinod Koul return ret; 457d93f8e55SVinod Koul } 458d93f8e55SVinod Koul 459d93f8e55SVinod Koul path_list = kzalloc( 460d93f8e55SVinod Koul sizeof(struct skl_dapm_path_list), 461d93f8e55SVinod Koul GFP_KERNEL); 462d93f8e55SVinod Koul if (path_list == NULL) 463d93f8e55SVinod Koul return -ENOMEM; 464d93f8e55SVinod Koul 465d93f8e55SVinod Koul /* Add connected path to one global list */ 466d93f8e55SVinod Koul path_list->dapm_path = p; 467d93f8e55SVinod Koul list_add_tail(&path_list->node, &skl->dapm_path_list); 468d93f8e55SVinod Koul break; 469d93f8e55SVinod Koul } 470d93f8e55SVinod Koul } 471d93f8e55SVinod Koul 472d93f8e55SVinod Koul /* Start source pipe last after starting all sinks */ 473d93f8e55SVinod Koul ret = skl_run_pipe(ctx, src_mconfig->pipe); 474d93f8e55SVinod Koul if (ret) 475d93f8e55SVinod Koul return ret; 476d93f8e55SVinod Koul 477d93f8e55SVinod Koul return 0; 478d93f8e55SVinod Koul } 479d93f8e55SVinod Koul 480d93f8e55SVinod Koul /* 481d93f8e55SVinod Koul * in the Post-PMU event of mixer we need to do following: 482d93f8e55SVinod Koul * - Check if this pipe is running 483d93f8e55SVinod Koul * - if not, then 484d93f8e55SVinod Koul * - bind this pipeline to its source pipeline 485d93f8e55SVinod Koul * if source pipe is already running, this means it is a dynamic 486d93f8e55SVinod Koul * connection and we need to bind only to that pipe 487d93f8e55SVinod Koul * - start this pipeline 488d93f8e55SVinod Koul */ 489d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, 490d93f8e55SVinod Koul struct skl *skl) 491d93f8e55SVinod Koul { 492d93f8e55SVinod Koul int ret = 0; 493d93f8e55SVinod Koul struct snd_soc_dapm_path *p; 494d93f8e55SVinod Koul struct snd_soc_dapm_widget *source, *sink; 495d93f8e55SVinod Koul struct skl_module_cfg *src_mconfig, *sink_mconfig; 496d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 497d93f8e55SVinod Koul int src_pipe_started = 0; 498d93f8e55SVinod Koul 499d93f8e55SVinod Koul sink = w; 500d93f8e55SVinod Koul sink_mconfig = sink->priv; 501d93f8e55SVinod Koul 502d93f8e55SVinod Koul /* 503d93f8e55SVinod Koul * If source pipe is already started, that means source is driving 504d93f8e55SVinod Koul * one more sink before this sink got connected, Since source is 505d93f8e55SVinod Koul * started, bind this sink to source and start this pipe. 506d93f8e55SVinod Koul */ 507d93f8e55SVinod Koul snd_soc_dapm_widget_for_each_sink_path(w, p) { 508d93f8e55SVinod Koul if (!p->connect) 509d93f8e55SVinod Koul continue; 510d93f8e55SVinod Koul 511d93f8e55SVinod Koul dev_dbg(ctx->dev, "sink widget=%s\n", w->name); 512d93f8e55SVinod Koul dev_dbg(ctx->dev, "src widget=%s\n", p->source->name); 513d93f8e55SVinod Koul 514d93f8e55SVinod Koul /* 515d93f8e55SVinod Koul * here we will check widgets in sink pipelines, so that 516d93f8e55SVinod Koul * can be any widgets type and we are only interested if 517d93f8e55SVinod Koul * they are ones used for SKL so check that first 518d93f8e55SVinod Koul */ 519d93f8e55SVinod Koul if ((p->source->priv != NULL) && 520d93f8e55SVinod Koul is_skl_dsp_widget_type(p->source)) { 521d93f8e55SVinod Koul source = p->source; 522d93f8e55SVinod Koul src_mconfig = source->priv; 523d93f8e55SVinod Koul sink_mconfig = sink->priv; 524d93f8e55SVinod Koul src_pipe_started = 1; 525d93f8e55SVinod Koul 526d93f8e55SVinod Koul /* 527d93f8e55SVinod Koul * check pipe state, then no need to bind or start 528d93f8e55SVinod Koul * the pipe 529d93f8e55SVinod Koul */ 530d93f8e55SVinod Koul if (src_mconfig->pipe->state != SKL_PIPE_STARTED) 531d93f8e55SVinod Koul src_pipe_started = 0; 532d93f8e55SVinod Koul } 533d93f8e55SVinod Koul } 534d93f8e55SVinod Koul 535d93f8e55SVinod Koul if (src_pipe_started) { 536d93f8e55SVinod Koul ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig); 537d93f8e55SVinod Koul if (ret) 538d93f8e55SVinod Koul return ret; 539d93f8e55SVinod Koul 540d93f8e55SVinod Koul ret = skl_run_pipe(ctx, sink_mconfig->pipe); 541d93f8e55SVinod Koul } 542d93f8e55SVinod Koul 543d93f8e55SVinod Koul return ret; 544d93f8e55SVinod Koul } 545d93f8e55SVinod Koul 546d93f8e55SVinod Koul /* 547d93f8e55SVinod Koul * in the Pre-PMD event of mixer we need to do following: 548d93f8e55SVinod Koul * - Stop the pipe 549d93f8e55SVinod Koul * - find the source connections and remove that from dapm_path_list 550d93f8e55SVinod Koul * - unbind with source pipelines if still connected 551d93f8e55SVinod Koul */ 552d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w, 553d93f8e55SVinod Koul struct skl *skl) 554d93f8e55SVinod Koul { 555d93f8e55SVinod Koul struct snd_soc_dapm_widget *source, *sink; 556d93f8e55SVinod Koul struct skl_module_cfg *src_mconfig, *sink_mconfig; 557d93f8e55SVinod Koul int ret = 0, path_found = 0; 558d93f8e55SVinod Koul struct skl_dapm_path_list *path_list, *tmp_list; 559d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 560d93f8e55SVinod Koul 561d93f8e55SVinod Koul sink = w; 562d93f8e55SVinod Koul sink_mconfig = sink->priv; 563d93f8e55SVinod Koul 564d93f8e55SVinod Koul /* Stop the pipe */ 565d93f8e55SVinod Koul ret = skl_stop_pipe(ctx, sink_mconfig->pipe); 566d93f8e55SVinod Koul if (ret) 567d93f8e55SVinod Koul return ret; 568d93f8e55SVinod Koul 569d93f8e55SVinod Koul /* 570d93f8e55SVinod Koul * This list, dapm_path_list handling here does not need any locks 571d93f8e55SVinod Koul * as we are under dapm lock while handling widget events. 572d93f8e55SVinod Koul * List can be manipulated safely only under dapm widgets handler 573d93f8e55SVinod Koul * routines 574d93f8e55SVinod Koul */ 575d93f8e55SVinod Koul list_for_each_entry_safe(path_list, tmp_list, 576d93f8e55SVinod Koul &skl->dapm_path_list, node) { 577d93f8e55SVinod Koul if (path_list->dapm_path->sink == sink) { 578d93f8e55SVinod Koul dev_dbg(ctx->dev, "Path found = %s\n", 579d93f8e55SVinod Koul path_list->dapm_path->name); 580d93f8e55SVinod Koul source = path_list->dapm_path->source; 581d93f8e55SVinod Koul src_mconfig = source->priv; 582d93f8e55SVinod Koul path_found = 1; 583d93f8e55SVinod Koul 584d93f8e55SVinod Koul list_del(&path_list->node); 585d93f8e55SVinod Koul kfree(path_list); 586d93f8e55SVinod Koul break; 587d93f8e55SVinod Koul } 588d93f8e55SVinod Koul } 589d93f8e55SVinod Koul 590d93f8e55SVinod Koul /* 591d93f8e55SVinod Koul * If path_found == 1, that means pmd for source pipe has 592d93f8e55SVinod Koul * not occurred, source is connected to some other sink. 593d93f8e55SVinod Koul * so its responsibility of sink to unbind itself from source. 594d93f8e55SVinod Koul */ 595d93f8e55SVinod Koul if (path_found) { 596d93f8e55SVinod Koul ret = skl_stop_pipe(ctx, src_mconfig->pipe); 597d93f8e55SVinod Koul if (ret < 0) 598d93f8e55SVinod Koul return ret; 599d93f8e55SVinod Koul 600d93f8e55SVinod Koul ret = skl_unbind_modules(ctx, src_mconfig, sink_mconfig); 601d93f8e55SVinod Koul } 602d93f8e55SVinod Koul 603d93f8e55SVinod Koul return ret; 604d93f8e55SVinod Koul } 605d93f8e55SVinod Koul 606d93f8e55SVinod Koul /* 607d93f8e55SVinod Koul * in the Post-PMD event of mixer we need to do following: 608d93f8e55SVinod Koul * - Free the mcps used 609d93f8e55SVinod Koul * - Free the mem used 610d93f8e55SVinod Koul * - Unbind the modules within the pipeline 611d93f8e55SVinod Koul * - Delete the pipeline (modules are not required to be explicitly 612d93f8e55SVinod Koul * deleted, pipeline delete is enough here 613d93f8e55SVinod Koul */ 614d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, 615d93f8e55SVinod Koul struct skl *skl) 616d93f8e55SVinod Koul { 617d93f8e55SVinod Koul struct skl_module_cfg *mconfig = w->priv; 618d93f8e55SVinod Koul struct skl_pipe_module *w_module; 619d93f8e55SVinod Koul struct skl_module_cfg *src_module = NULL, *dst_module; 620d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 621d93f8e55SVinod Koul struct skl_pipe *s_pipe = mconfig->pipe; 622d93f8e55SVinod Koul int ret = 0; 623d93f8e55SVinod Koul 624d93f8e55SVinod Koul skl_tplg_free_pipe_mcps(skl, mconfig); 625d93f8e55SVinod Koul 626d93f8e55SVinod Koul list_for_each_entry(w_module, &s_pipe->w_list, node) { 627d93f8e55SVinod Koul dst_module = w_module->w->priv; 628d93f8e55SVinod Koul 629d93f8e55SVinod Koul if (src_module == NULL) { 630d93f8e55SVinod Koul src_module = dst_module; 631d93f8e55SVinod Koul continue; 632d93f8e55SVinod Koul } 633d93f8e55SVinod Koul 634d93f8e55SVinod Koul ret = skl_unbind_modules(ctx, src_module, dst_module); 635d93f8e55SVinod Koul if (ret < 0) 636d93f8e55SVinod Koul return ret; 637d93f8e55SVinod Koul 638d93f8e55SVinod Koul src_module = dst_module; 639d93f8e55SVinod Koul } 640d93f8e55SVinod Koul 641d93f8e55SVinod Koul ret = skl_delete_pipe(ctx, mconfig->pipe); 642d93f8e55SVinod Koul skl_tplg_free_pipe_mem(skl, mconfig); 643d93f8e55SVinod Koul 644d93f8e55SVinod Koul return ret; 645d93f8e55SVinod Koul } 646d93f8e55SVinod Koul 647d93f8e55SVinod Koul /* 648d93f8e55SVinod Koul * in the Post-PMD event of PGA we need to do following: 649d93f8e55SVinod Koul * - Free the mcps used 650d93f8e55SVinod Koul * - Stop the pipeline 651d93f8e55SVinod Koul * - In source pipe is connected, unbind with source pipelines 652d93f8e55SVinod Koul */ 653d93f8e55SVinod Koul static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, 654d93f8e55SVinod Koul struct skl *skl) 655d93f8e55SVinod Koul { 656d93f8e55SVinod Koul struct snd_soc_dapm_widget *source, *sink; 657d93f8e55SVinod Koul struct skl_module_cfg *src_mconfig, *sink_mconfig; 658d93f8e55SVinod Koul int ret = 0, path_found = 0; 659d93f8e55SVinod Koul struct skl_dapm_path_list *path_list, *tmp_path_list; 660d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 661d93f8e55SVinod Koul 662d93f8e55SVinod Koul source = w; 663d93f8e55SVinod Koul src_mconfig = source->priv; 664d93f8e55SVinod Koul 665d93f8e55SVinod Koul skl_tplg_free_pipe_mcps(skl, src_mconfig); 666d93f8e55SVinod Koul /* Stop the pipe since this is a mixin module */ 667d93f8e55SVinod Koul ret = skl_stop_pipe(ctx, src_mconfig->pipe); 668d93f8e55SVinod Koul if (ret) 669d93f8e55SVinod Koul return ret; 670d93f8e55SVinod Koul 671d93f8e55SVinod Koul list_for_each_entry_safe(path_list, tmp_path_list, &skl->dapm_path_list, node) { 672d93f8e55SVinod Koul if (path_list->dapm_path->source == source) { 673d93f8e55SVinod Koul dev_dbg(ctx->dev, "Path found = %s\n", 674d93f8e55SVinod Koul path_list->dapm_path->name); 675d93f8e55SVinod Koul sink = path_list->dapm_path->sink; 676d93f8e55SVinod Koul sink_mconfig = sink->priv; 677d93f8e55SVinod Koul path_found = 1; 678d93f8e55SVinod Koul 679d93f8e55SVinod Koul list_del(&path_list->node); 680d93f8e55SVinod Koul kfree(path_list); 681d93f8e55SVinod Koul break; 682d93f8e55SVinod Koul } 683d93f8e55SVinod Koul } 684d93f8e55SVinod Koul 685d93f8e55SVinod Koul /* 686d93f8e55SVinod Koul * This is a connector and if path is found that means 687d93f8e55SVinod Koul * unbind between source and sink has not happened yet 688d93f8e55SVinod Koul */ 689d93f8e55SVinod Koul if (path_found) { 690d93f8e55SVinod Koul ret = skl_stop_pipe(ctx, src_mconfig->pipe); 691d93f8e55SVinod Koul if (ret < 0) 692d93f8e55SVinod Koul return ret; 693d93f8e55SVinod Koul 694d93f8e55SVinod Koul ret = skl_unbind_modules(ctx, src_mconfig, sink_mconfig); 695d93f8e55SVinod Koul } 696d93f8e55SVinod Koul 697d93f8e55SVinod Koul return ret; 698d93f8e55SVinod Koul } 699d93f8e55SVinod Koul 700d93f8e55SVinod Koul /* 701d93f8e55SVinod Koul * In modelling, we assume there will be ONLY one mixer in a pipeline. If 702d93f8e55SVinod Koul * mixer is not required then it is treated as static mixer aka vmixer with 703d93f8e55SVinod Koul * a hard path to source module 704d93f8e55SVinod Koul * So we don't need to check if source is started or not as hard path puts 705d93f8e55SVinod Koul * dependency on each other 706d93f8e55SVinod Koul */ 707d93f8e55SVinod Koul static int skl_tplg_vmixer_event(struct snd_soc_dapm_widget *w, 708d93f8e55SVinod Koul struct snd_kcontrol *k, int event) 709d93f8e55SVinod Koul { 710d93f8e55SVinod Koul struct snd_soc_dapm_context *dapm = w->dapm; 711d93f8e55SVinod Koul struct skl *skl = get_skl_ctx(dapm->dev); 712d93f8e55SVinod Koul 713d93f8e55SVinod Koul switch (event) { 714d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMU: 715d93f8e55SVinod Koul return skl_tplg_mixer_dapm_pre_pmu_event(w, skl); 716d93f8e55SVinod Koul 717d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMD: 718d93f8e55SVinod Koul return skl_tplg_mixer_dapm_post_pmd_event(w, skl); 719d93f8e55SVinod Koul } 720d93f8e55SVinod Koul 721d93f8e55SVinod Koul return 0; 722d93f8e55SVinod Koul } 723d93f8e55SVinod Koul 724d93f8e55SVinod Koul /* 725d93f8e55SVinod Koul * In modelling, we assume there will be ONLY one mixer in a pipeline. If a 726d93f8e55SVinod Koul * second one is required that is created as another pipe entity. 727d93f8e55SVinod Koul * The mixer is responsible for pipe management and represent a pipeline 728d93f8e55SVinod Koul * instance 729d93f8e55SVinod Koul */ 730d93f8e55SVinod Koul static int skl_tplg_mixer_event(struct snd_soc_dapm_widget *w, 731d93f8e55SVinod Koul struct snd_kcontrol *k, int event) 732d93f8e55SVinod Koul { 733d93f8e55SVinod Koul struct snd_soc_dapm_context *dapm = w->dapm; 734d93f8e55SVinod Koul struct skl *skl = get_skl_ctx(dapm->dev); 735d93f8e55SVinod Koul 736d93f8e55SVinod Koul switch (event) { 737d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMU: 738d93f8e55SVinod Koul return skl_tplg_mixer_dapm_pre_pmu_event(w, skl); 739d93f8e55SVinod Koul 740d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMU: 741d93f8e55SVinod Koul return skl_tplg_mixer_dapm_post_pmu_event(w, skl); 742d93f8e55SVinod Koul 743d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMD: 744d93f8e55SVinod Koul return skl_tplg_mixer_dapm_pre_pmd_event(w, skl); 745d93f8e55SVinod Koul 746d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMD: 747d93f8e55SVinod Koul return skl_tplg_mixer_dapm_post_pmd_event(w, skl); 748d93f8e55SVinod Koul } 749d93f8e55SVinod Koul 750d93f8e55SVinod Koul return 0; 751d93f8e55SVinod Koul } 752d93f8e55SVinod Koul 753d93f8e55SVinod Koul /* 754d93f8e55SVinod Koul * In modelling, we assumed rest of the modules in pipeline are PGA. But we 755d93f8e55SVinod Koul * are interested in last PGA (leaf PGA) in a pipeline to disconnect with 756d93f8e55SVinod Koul * the sink when it is running (two FE to one BE or one FE to two BE) 757d93f8e55SVinod Koul * scenarios 758d93f8e55SVinod Koul */ 759d93f8e55SVinod Koul static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w, 760d93f8e55SVinod Koul struct snd_kcontrol *k, int event) 761d93f8e55SVinod Koul 762d93f8e55SVinod Koul { 763d93f8e55SVinod Koul struct snd_soc_dapm_context *dapm = w->dapm; 764d93f8e55SVinod Koul struct skl *skl = get_skl_ctx(dapm->dev); 765d93f8e55SVinod Koul 766d93f8e55SVinod Koul switch (event) { 767d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMU: 768d93f8e55SVinod Koul return skl_tplg_pga_dapm_pre_pmu_event(w, skl); 769d93f8e55SVinod Koul 770d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMD: 771d93f8e55SVinod Koul return skl_tplg_pga_dapm_post_pmd_event(w, skl); 772d93f8e55SVinod Koul } 773d93f8e55SVinod Koul 774d93f8e55SVinod Koul return 0; 775d93f8e55SVinod Koul } 776cfb0a873SVinod Koul 777cfb0a873SVinod Koul /* 778cfb0a873SVinod Koul * The FE params are passed by hw_params of the DAI. 779cfb0a873SVinod Koul * On hw_params, the params are stored in Gateway module of the FE and we 780cfb0a873SVinod Koul * need to calculate the format in DSP module configuration, that 781cfb0a873SVinod Koul * conversion is done here 782cfb0a873SVinod Koul */ 783cfb0a873SVinod Koul int skl_tplg_update_pipe_params(struct device *dev, 784cfb0a873SVinod Koul struct skl_module_cfg *mconfig, 785cfb0a873SVinod Koul struct skl_pipe_params *params) 786cfb0a873SVinod Koul { 787cfb0a873SVinod Koul struct skl_pipe *pipe = mconfig->pipe; 788cfb0a873SVinod Koul struct skl_module_fmt *format = NULL; 789cfb0a873SVinod Koul 790cfb0a873SVinod Koul memcpy(pipe->p_params, params, sizeof(*params)); 791cfb0a873SVinod Koul 792cfb0a873SVinod Koul if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) 793cfb0a873SVinod Koul format = &mconfig->in_fmt; 794cfb0a873SVinod Koul else 795cfb0a873SVinod Koul format = &mconfig->out_fmt; 796cfb0a873SVinod Koul 797cfb0a873SVinod Koul /* set the hw_params */ 798cfb0a873SVinod Koul format->s_freq = params->s_freq; 799cfb0a873SVinod Koul format->channels = params->ch; 800cfb0a873SVinod Koul format->valid_bit_depth = skl_get_bit_depth(params->s_fmt); 801cfb0a873SVinod Koul 802cfb0a873SVinod Koul /* 803cfb0a873SVinod Koul * 16 bit is 16 bit container whereas 24 bit is in 32 bit 804cfb0a873SVinod Koul * container so update bit depth accordingly 805cfb0a873SVinod Koul */ 806cfb0a873SVinod Koul switch (format->valid_bit_depth) { 807cfb0a873SVinod Koul case SKL_DEPTH_16BIT: 808cfb0a873SVinod Koul format->bit_depth = format->valid_bit_depth; 809cfb0a873SVinod Koul break; 810cfb0a873SVinod Koul 811cfb0a873SVinod Koul case SKL_DEPTH_24BIT: 812cfb0a873SVinod Koul format->bit_depth = SKL_DEPTH_32BIT; 813cfb0a873SVinod Koul break; 814cfb0a873SVinod Koul 815cfb0a873SVinod Koul default: 816cfb0a873SVinod Koul dev_err(dev, "Invalid bit depth %x for pipe\n", 817cfb0a873SVinod Koul format->valid_bit_depth); 818cfb0a873SVinod Koul return -EINVAL; 819cfb0a873SVinod Koul } 820cfb0a873SVinod Koul 821cfb0a873SVinod Koul if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { 822cfb0a873SVinod Koul mconfig->ibs = (format->s_freq / 1000) * 823cfb0a873SVinod Koul (format->channels) * 824cfb0a873SVinod Koul (format->bit_depth >> 3); 825cfb0a873SVinod Koul } else { 826cfb0a873SVinod Koul mconfig->obs = (format->s_freq / 1000) * 827cfb0a873SVinod Koul (format->channels) * 828cfb0a873SVinod Koul (format->bit_depth >> 3); 829cfb0a873SVinod Koul } 830cfb0a873SVinod Koul 831cfb0a873SVinod Koul return 0; 832cfb0a873SVinod Koul } 833cfb0a873SVinod Koul 834cfb0a873SVinod Koul /* 835cfb0a873SVinod Koul * Query the module config for the FE DAI 836cfb0a873SVinod Koul * This is used to find the hw_params set for that DAI and apply to FE 837cfb0a873SVinod Koul * pipeline 838cfb0a873SVinod Koul */ 839cfb0a873SVinod Koul struct skl_module_cfg * 840cfb0a873SVinod Koul skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream) 841cfb0a873SVinod Koul { 842cfb0a873SVinod Koul struct snd_soc_dapm_widget *w; 843cfb0a873SVinod Koul struct snd_soc_dapm_path *p = NULL; 844cfb0a873SVinod Koul 845cfb0a873SVinod Koul if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 846cfb0a873SVinod Koul w = dai->playback_widget; 847cfb0a873SVinod Koul snd_soc_dapm_widget_for_each_source_path(w, p) { 848cfb0a873SVinod Koul if (p->connect && p->sink->power && 849cfb0a873SVinod Koul is_skl_dsp_widget_type(p->sink)) 850cfb0a873SVinod Koul continue; 851cfb0a873SVinod Koul 852cfb0a873SVinod Koul if (p->sink->priv) { 853cfb0a873SVinod Koul dev_dbg(dai->dev, "set params for %s\n", 854cfb0a873SVinod Koul p->sink->name); 855cfb0a873SVinod Koul return p->sink->priv; 856cfb0a873SVinod Koul } 857cfb0a873SVinod Koul } 858cfb0a873SVinod Koul } else { 859cfb0a873SVinod Koul w = dai->capture_widget; 860cfb0a873SVinod Koul snd_soc_dapm_widget_for_each_sink_path(w, p) { 861cfb0a873SVinod Koul if (p->connect && p->source->power && 862cfb0a873SVinod Koul is_skl_dsp_widget_type(p->source)) 863cfb0a873SVinod Koul continue; 864cfb0a873SVinod Koul 865cfb0a873SVinod Koul if (p->source->priv) { 866cfb0a873SVinod Koul dev_dbg(dai->dev, "set params for %s\n", 867cfb0a873SVinod Koul p->source->name); 868cfb0a873SVinod Koul return p->source->priv; 869cfb0a873SVinod Koul } 870cfb0a873SVinod Koul } 871cfb0a873SVinod Koul } 872cfb0a873SVinod Koul 873cfb0a873SVinod Koul return NULL; 874cfb0a873SVinod Koul } 875cfb0a873SVinod Koul 876cfb0a873SVinod Koul static u8 skl_tplg_be_link_type(int dev_type) 877cfb0a873SVinod Koul { 878cfb0a873SVinod Koul int ret; 879cfb0a873SVinod Koul 880cfb0a873SVinod Koul switch (dev_type) { 881cfb0a873SVinod Koul case SKL_DEVICE_BT: 882cfb0a873SVinod Koul ret = NHLT_LINK_SSP; 883cfb0a873SVinod Koul break; 884cfb0a873SVinod Koul 885cfb0a873SVinod Koul case SKL_DEVICE_DMIC: 886cfb0a873SVinod Koul ret = NHLT_LINK_DMIC; 887cfb0a873SVinod Koul break; 888cfb0a873SVinod Koul 889cfb0a873SVinod Koul case SKL_DEVICE_I2S: 890cfb0a873SVinod Koul ret = NHLT_LINK_SSP; 891cfb0a873SVinod Koul break; 892cfb0a873SVinod Koul 893cfb0a873SVinod Koul case SKL_DEVICE_HDALINK: 894cfb0a873SVinod Koul ret = NHLT_LINK_HDA; 895cfb0a873SVinod Koul break; 896cfb0a873SVinod Koul 897cfb0a873SVinod Koul default: 898cfb0a873SVinod Koul ret = NHLT_LINK_INVALID; 899cfb0a873SVinod Koul break; 900cfb0a873SVinod Koul } 901cfb0a873SVinod Koul 902cfb0a873SVinod Koul return ret; 903cfb0a873SVinod Koul } 904cfb0a873SVinod Koul 905cfb0a873SVinod Koul /* 906cfb0a873SVinod Koul * Fill the BE gateway parameters 907cfb0a873SVinod Koul * The BE gateway expects a blob of parameters which are kept in the ACPI 908cfb0a873SVinod Koul * NHLT blob, so query the blob for interface type (i2s/pdm) and instance. 909cfb0a873SVinod Koul * The port can have multiple settings so pick based on the PCM 910cfb0a873SVinod Koul * parameters 911cfb0a873SVinod Koul */ 912cfb0a873SVinod Koul static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai, 913cfb0a873SVinod Koul struct skl_module_cfg *mconfig, 914cfb0a873SVinod Koul struct skl_pipe_params *params) 915cfb0a873SVinod Koul { 916cfb0a873SVinod Koul struct skl_pipe *pipe = mconfig->pipe; 917cfb0a873SVinod Koul struct nhlt_specific_cfg *cfg; 918cfb0a873SVinod Koul struct skl *skl = get_skl_ctx(dai->dev); 919cfb0a873SVinod Koul int link_type = skl_tplg_be_link_type(mconfig->dev_type); 920cfb0a873SVinod Koul 921cfb0a873SVinod Koul memcpy(pipe->p_params, params, sizeof(*params)); 922cfb0a873SVinod Koul 923cfb0a873SVinod Koul /* update the blob based on virtual bus_id*/ 924cfb0a873SVinod Koul cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type, 925cfb0a873SVinod Koul params->s_fmt, params->ch, 926cfb0a873SVinod Koul params->s_freq, params->stream); 927cfb0a873SVinod Koul if (cfg) { 928cfb0a873SVinod Koul mconfig->formats_config.caps_size = cfg->size; 929cfb0a873SVinod Koul memcpy(mconfig->formats_config.caps, &cfg->caps, cfg->size); 930cfb0a873SVinod Koul } else { 931cfb0a873SVinod Koul dev_err(dai->dev, "Blob NULL for id %x type %d dirn %d\n", 932cfb0a873SVinod Koul mconfig->vbus_id, link_type, 933cfb0a873SVinod Koul params->stream); 934cfb0a873SVinod Koul dev_err(dai->dev, "PCM: ch %d, freq %d, fmt %d\n", 935cfb0a873SVinod Koul params->ch, params->s_freq, params->s_fmt); 936cfb0a873SVinod Koul return -EINVAL; 937cfb0a873SVinod Koul } 938cfb0a873SVinod Koul 939cfb0a873SVinod Koul return 0; 940cfb0a873SVinod Koul } 941cfb0a873SVinod Koul 942cfb0a873SVinod Koul static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai, 943cfb0a873SVinod Koul struct snd_soc_dapm_widget *w, 944cfb0a873SVinod Koul struct skl_pipe_params *params) 945cfb0a873SVinod Koul { 946cfb0a873SVinod Koul struct snd_soc_dapm_path *p; 947cfb0a873SVinod Koul 948cfb0a873SVinod Koul snd_soc_dapm_widget_for_each_sink_path(w, p) { 949cfb0a873SVinod Koul if (p->connect && is_skl_dsp_widget_type(p->source) && 950cfb0a873SVinod Koul p->source->priv) { 951cfb0a873SVinod Koul 952cfb0a873SVinod Koul if (!p->source->power) 953cfb0a873SVinod Koul return skl_tplg_be_fill_pipe_params( 954cfb0a873SVinod Koul dai, p->source->priv, 955cfb0a873SVinod Koul params); 956cfb0a873SVinod Koul else 957cfb0a873SVinod Koul return -EBUSY; 958cfb0a873SVinod Koul } else { 959cfb0a873SVinod Koul return skl_tplg_be_set_src_pipe_params( 960cfb0a873SVinod Koul dai, p->source, params); 961cfb0a873SVinod Koul } 962cfb0a873SVinod Koul } 963cfb0a873SVinod Koul 964cfb0a873SVinod Koul return -EIO; 965cfb0a873SVinod Koul } 966cfb0a873SVinod Koul 967cfb0a873SVinod Koul static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai, 968cfb0a873SVinod Koul struct snd_soc_dapm_widget *w, struct skl_pipe_params *params) 969cfb0a873SVinod Koul { 970cfb0a873SVinod Koul struct snd_soc_dapm_path *p = NULL; 971cfb0a873SVinod Koul 972cfb0a873SVinod Koul snd_soc_dapm_widget_for_each_source_path(w, p) { 973cfb0a873SVinod Koul if (p->connect && is_skl_dsp_widget_type(p->sink) && 974cfb0a873SVinod Koul p->sink->priv) { 975cfb0a873SVinod Koul 976cfb0a873SVinod Koul if (!p->sink->power) 977cfb0a873SVinod Koul return skl_tplg_be_fill_pipe_params( 978cfb0a873SVinod Koul dai, p->sink->priv, params); 979cfb0a873SVinod Koul else 980cfb0a873SVinod Koul return -EBUSY; 981cfb0a873SVinod Koul 982cfb0a873SVinod Koul } else { 983cfb0a873SVinod Koul return skl_tplg_be_set_sink_pipe_params( 984cfb0a873SVinod Koul dai, p->sink, params); 985cfb0a873SVinod Koul } 986cfb0a873SVinod Koul } 987cfb0a873SVinod Koul 988cfb0a873SVinod Koul return -EIO; 989cfb0a873SVinod Koul } 990cfb0a873SVinod Koul 991cfb0a873SVinod Koul /* 992cfb0a873SVinod Koul * BE hw_params can be a source parameters (capture) or sink parameters 993cfb0a873SVinod Koul * (playback). Based on sink and source we need to either find the source 994cfb0a873SVinod Koul * list or the sink list and set the pipeline parameters 995cfb0a873SVinod Koul */ 996cfb0a873SVinod Koul int skl_tplg_be_update_params(struct snd_soc_dai *dai, 997cfb0a873SVinod Koul struct skl_pipe_params *params) 998cfb0a873SVinod Koul { 999cfb0a873SVinod Koul struct snd_soc_dapm_widget *w; 1000cfb0a873SVinod Koul 1001cfb0a873SVinod Koul if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { 1002cfb0a873SVinod Koul w = dai->playback_widget; 1003cfb0a873SVinod Koul 1004cfb0a873SVinod Koul return skl_tplg_be_set_src_pipe_params(dai, w, params); 1005cfb0a873SVinod Koul 1006cfb0a873SVinod Koul } else { 1007cfb0a873SVinod Koul w = dai->capture_widget; 1008cfb0a873SVinod Koul 1009cfb0a873SVinod Koul return skl_tplg_be_set_sink_pipe_params(dai, w, params); 1010cfb0a873SVinod Koul } 1011cfb0a873SVinod Koul 1012cfb0a873SVinod Koul return 0; 1013cfb0a873SVinod Koul } 10143af36706SVinod Koul 10153af36706SVinod Koul static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = { 10163af36706SVinod Koul {SKL_MIXER_EVENT, skl_tplg_mixer_event}, 10173af36706SVinod Koul {SKL_VMIXER_EVENT, skl_tplg_vmixer_event}, 10183af36706SVinod Koul {SKL_PGA_EVENT, skl_tplg_pga_event}, 10193af36706SVinod Koul }; 10203af36706SVinod Koul 10213af36706SVinod Koul /* 10223af36706SVinod Koul * The topology binary passes the pin info for a module so initialize the pin 10233af36706SVinod Koul * info passed into module instance 10243af36706SVinod Koul */ 10253af36706SVinod Koul static void skl_fill_module_pin_info(struct device *dev, 10263af36706SVinod Koul struct skl_module_pin *m_pin, 10273af36706SVinod Koul int max_pin) 10283af36706SVinod Koul { 10293af36706SVinod Koul int i; 10303af36706SVinod Koul 10313af36706SVinod Koul for (i = 0; i < max_pin; i++) { 10323af36706SVinod Koul m_pin[i].id.module_id = 0; 10333af36706SVinod Koul m_pin[i].id.instance_id = 0; 10343af36706SVinod Koul m_pin[i].in_use = false; 10353af36706SVinod Koul m_pin[i].is_dynamic = true; 10363af36706SVinod Koul m_pin[i].pin_index = i; 10373af36706SVinod Koul } 10383af36706SVinod Koul } 10393af36706SVinod Koul 10403af36706SVinod Koul /* 10413af36706SVinod Koul * Add pipeline from topology binary into driver pipeline list 10423af36706SVinod Koul * 10433af36706SVinod Koul * If already added we return that instance 10443af36706SVinod Koul * Otherwise we create a new instance and add into driver list 10453af36706SVinod Koul */ 10463af36706SVinod Koul static struct skl_pipe *skl_tplg_add_pipe(struct device *dev, 10473af36706SVinod Koul struct skl *skl, struct skl_dfw_pipe *dfw_pipe) 10483af36706SVinod Koul { 10493af36706SVinod Koul struct skl_pipeline *ppl; 10503af36706SVinod Koul struct skl_pipe *pipe; 10513af36706SVinod Koul struct skl_pipe_params *params; 10523af36706SVinod Koul 10533af36706SVinod Koul list_for_each_entry(ppl, &skl->ppl_list, node) { 10543af36706SVinod Koul if (ppl->pipe->ppl_id == dfw_pipe->pipe_id) 10553af36706SVinod Koul return ppl->pipe; 10563af36706SVinod Koul } 10573af36706SVinod Koul 10583af36706SVinod Koul ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL); 10593af36706SVinod Koul if (!ppl) 10603af36706SVinod Koul return NULL; 10613af36706SVinod Koul 10623af36706SVinod Koul pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL); 10633af36706SVinod Koul if (!pipe) 10643af36706SVinod Koul return NULL; 10653af36706SVinod Koul 10663af36706SVinod Koul params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL); 10673af36706SVinod Koul if (!params) 10683af36706SVinod Koul return NULL; 10693af36706SVinod Koul 10703af36706SVinod Koul pipe->ppl_id = dfw_pipe->pipe_id; 10713af36706SVinod Koul pipe->memory_pages = dfw_pipe->memory_pages; 10723af36706SVinod Koul pipe->pipe_priority = dfw_pipe->pipe_priority; 10733af36706SVinod Koul pipe->conn_type = dfw_pipe->conn_type; 10743af36706SVinod Koul pipe->state = SKL_PIPE_INVALID; 10753af36706SVinod Koul pipe->p_params = params; 10763af36706SVinod Koul INIT_LIST_HEAD(&pipe->w_list); 10773af36706SVinod Koul 10783af36706SVinod Koul ppl->pipe = pipe; 10793af36706SVinod Koul list_add(&ppl->node, &skl->ppl_list); 10803af36706SVinod Koul 10813af36706SVinod Koul return ppl->pipe; 10823af36706SVinod Koul } 10833af36706SVinod Koul 10843af36706SVinod Koul /* 10853af36706SVinod Koul * Topology core widget load callback 10863af36706SVinod Koul * 10873af36706SVinod Koul * This is used to save the private data for each widget which gives 10883af36706SVinod Koul * information to the driver about module and pipeline parameters which DSP 10893af36706SVinod Koul * FW expects like ids, resource values, formats etc 10903af36706SVinod Koul */ 10913af36706SVinod Koul static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, 10923af36706SVinod Koul struct snd_soc_dapm_widget *w, 10933af36706SVinod Koul struct snd_soc_tplg_dapm_widget *tplg_w) 10943af36706SVinod Koul { 10953af36706SVinod Koul int ret; 10963af36706SVinod Koul struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt); 10973af36706SVinod Koul struct skl *skl = ebus_to_skl(ebus); 10983af36706SVinod Koul struct hdac_bus *bus = ebus_to_hbus(ebus); 10993af36706SVinod Koul struct skl_module_cfg *mconfig; 11003af36706SVinod Koul struct skl_pipe *pipe; 1101b663a8c5SJeeja KP struct skl_dfw_module *dfw_config = 1102b663a8c5SJeeja KP (struct skl_dfw_module *)tplg_w->priv.data; 11033af36706SVinod Koul 11043af36706SVinod Koul if (!tplg_w->priv.size) 11053af36706SVinod Koul goto bind_event; 11063af36706SVinod Koul 11073af36706SVinod Koul mconfig = devm_kzalloc(bus->dev, sizeof(*mconfig), GFP_KERNEL); 11083af36706SVinod Koul 11093af36706SVinod Koul if (!mconfig) 11103af36706SVinod Koul return -ENOMEM; 11113af36706SVinod Koul 11123af36706SVinod Koul w->priv = mconfig; 11133af36706SVinod Koul mconfig->id.module_id = dfw_config->module_id; 11143af36706SVinod Koul mconfig->id.instance_id = dfw_config->instance_id; 11153af36706SVinod Koul mconfig->mcps = dfw_config->max_mcps; 11163af36706SVinod Koul mconfig->ibs = dfw_config->ibs; 11173af36706SVinod Koul mconfig->obs = dfw_config->obs; 11183af36706SVinod Koul mconfig->core_id = dfw_config->core_id; 11193af36706SVinod Koul mconfig->max_in_queue = dfw_config->max_in_queue; 11203af36706SVinod Koul mconfig->max_out_queue = dfw_config->max_out_queue; 11213af36706SVinod Koul mconfig->is_loadable = dfw_config->is_loadable; 11223af36706SVinod Koul mconfig->in_fmt.channels = dfw_config->in_fmt.channels; 11233af36706SVinod Koul mconfig->in_fmt.s_freq = dfw_config->in_fmt.freq; 11243af36706SVinod Koul mconfig->in_fmt.bit_depth = dfw_config->in_fmt.bit_depth; 1125b663a8c5SJeeja KP mconfig->in_fmt.valid_bit_depth = 1126b663a8c5SJeeja KP dfw_config->in_fmt.valid_bit_depth; 11273af36706SVinod Koul mconfig->in_fmt.ch_cfg = dfw_config->in_fmt.ch_cfg; 11283af36706SVinod Koul mconfig->out_fmt.channels = dfw_config->out_fmt.channels; 11293af36706SVinod Koul mconfig->out_fmt.s_freq = dfw_config->out_fmt.freq; 11303af36706SVinod Koul mconfig->out_fmt.bit_depth = dfw_config->out_fmt.bit_depth; 1131b663a8c5SJeeja KP mconfig->out_fmt.valid_bit_depth = 1132b663a8c5SJeeja KP dfw_config->out_fmt.valid_bit_depth; 11333af36706SVinod Koul mconfig->out_fmt.ch_cfg = dfw_config->out_fmt.ch_cfg; 11343af36706SVinod Koul mconfig->params_fixup = dfw_config->params_fixup; 11353af36706SVinod Koul mconfig->converter = dfw_config->converter; 11363af36706SVinod Koul mconfig->m_type = dfw_config->module_type; 11373af36706SVinod Koul mconfig->vbus_id = dfw_config->vbus_id; 11383af36706SVinod Koul 11393af36706SVinod Koul pipe = skl_tplg_add_pipe(bus->dev, skl, &dfw_config->pipe); 11403af36706SVinod Koul if (pipe) 11413af36706SVinod Koul mconfig->pipe = pipe; 11423af36706SVinod Koul 11433af36706SVinod Koul mconfig->dev_type = dfw_config->dev_type; 11443af36706SVinod Koul mconfig->hw_conn_type = dfw_config->hw_conn_type; 11453af36706SVinod Koul mconfig->time_slot = dfw_config->time_slot; 11463af36706SVinod Koul mconfig->formats_config.caps_size = dfw_config->caps.caps_size; 11473af36706SVinod Koul 1148b663a8c5SJeeja KP mconfig->m_in_pin = devm_kzalloc(bus->dev, 1149b663a8c5SJeeja KP (mconfig->max_in_queue) * 11503af36706SVinod Koul sizeof(*mconfig->m_in_pin), 11513af36706SVinod Koul GFP_KERNEL); 11523af36706SVinod Koul if (!mconfig->m_in_pin) 11533af36706SVinod Koul return -ENOMEM; 11543af36706SVinod Koul 1155b663a8c5SJeeja KP mconfig->m_out_pin = devm_kzalloc(bus->dev, 1156b663a8c5SJeeja KP (mconfig->max_in_queue) * 11573af36706SVinod Koul sizeof(*mconfig->m_out_pin), 11583af36706SVinod Koul GFP_KERNEL); 11593af36706SVinod Koul if (!mconfig->m_out_pin) 11603af36706SVinod Koul return -ENOMEM; 11613af36706SVinod Koul 11623af36706SVinod Koul skl_fill_module_pin_info(bus->dev, mconfig->m_in_pin, 11633af36706SVinod Koul mconfig->max_in_queue); 11643af36706SVinod Koul skl_fill_module_pin_info(bus->dev, mconfig->m_out_pin, 11653af36706SVinod Koul mconfig->max_out_queue); 11663af36706SVinod Koul 11673af36706SVinod Koul if (mconfig->formats_config.caps_size == 0) 11683af36706SVinod Koul goto bind_event; 11693af36706SVinod Koul 11703af36706SVinod Koul mconfig->formats_config.caps = (u32 *)devm_kzalloc(bus->dev, 11713af36706SVinod Koul mconfig->formats_config.caps_size, GFP_KERNEL); 11723af36706SVinod Koul 11733af36706SVinod Koul if (mconfig->formats_config.caps == NULL) 11743af36706SVinod Koul return -ENOMEM; 11753af36706SVinod Koul 11763af36706SVinod Koul memcpy(mconfig->formats_config.caps, dfw_config->caps.caps, 11773af36706SVinod Koul dfw_config->caps.caps_size); 11783af36706SVinod Koul 11793af36706SVinod Koul bind_event: 11803af36706SVinod Koul if (tplg_w->event_type == 0) { 1181*3373f716SVinod Koul dev_dbg(bus->dev, "ASoC: No event handler required\n"); 11823af36706SVinod Koul return 0; 11833af36706SVinod Koul } 11843af36706SVinod Koul 11853af36706SVinod Koul ret = snd_soc_tplg_widget_bind_event(w, skl_tplg_widget_ops, 1186b663a8c5SJeeja KP ARRAY_SIZE(skl_tplg_widget_ops), 1187b663a8c5SJeeja KP tplg_w->event_type); 11883af36706SVinod Koul 11893af36706SVinod Koul if (ret) { 11903af36706SVinod Koul dev_err(bus->dev, "%s: No matching event handlers found for %d\n", 11913af36706SVinod Koul __func__, tplg_w->event_type); 11923af36706SVinod Koul return -EINVAL; 11933af36706SVinod Koul } 11943af36706SVinod Koul 11953af36706SVinod Koul return 0; 11963af36706SVinod Koul } 11973af36706SVinod Koul 11983af36706SVinod Koul static struct snd_soc_tplg_ops skl_tplg_ops = { 11993af36706SVinod Koul .widget_load = skl_tplg_widget_load, 12003af36706SVinod Koul }; 12013af36706SVinod Koul 12023af36706SVinod Koul /* This will be read from topology manifest, currently defined here */ 12033af36706SVinod Koul #define SKL_MAX_MCPS 30000000 12043af36706SVinod Koul #define SKL_FW_MAX_MEM 1000000 12053af36706SVinod Koul 12063af36706SVinod Koul /* 12073af36706SVinod Koul * SKL topology init routine 12083af36706SVinod Koul */ 12093af36706SVinod Koul int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus) 12103af36706SVinod Koul { 12113af36706SVinod Koul int ret; 12123af36706SVinod Koul const struct firmware *fw; 12133af36706SVinod Koul struct hdac_bus *bus = ebus_to_hbus(ebus); 12143af36706SVinod Koul struct skl *skl = ebus_to_skl(ebus); 12153af36706SVinod Koul 12163af36706SVinod Koul ret = request_firmware(&fw, "dfw_sst.bin", bus->dev); 12173af36706SVinod Koul if (ret < 0) { 1218b663a8c5SJeeja KP dev_err(bus->dev, "tplg fw %s load failed with %d\n", 12193af36706SVinod Koul "dfw_sst.bin", ret); 12203af36706SVinod Koul return ret; 12213af36706SVinod Koul } 12223af36706SVinod Koul 12233af36706SVinod Koul /* 12243af36706SVinod Koul * The complete tplg for SKL is loaded as index 0, we don't use 12253af36706SVinod Koul * any other index 12263af36706SVinod Koul */ 1227b663a8c5SJeeja KP ret = snd_soc_tplg_component_load(&platform->component, 1228b663a8c5SJeeja KP &skl_tplg_ops, fw, 0); 12293af36706SVinod Koul if (ret < 0) { 12303af36706SVinod Koul dev_err(bus->dev, "tplg component load failed%d\n", ret); 12313af36706SVinod Koul return -EINVAL; 12323af36706SVinod Koul } 12333af36706SVinod Koul 12343af36706SVinod Koul skl->resource.max_mcps = SKL_MAX_MCPS; 12353af36706SVinod Koul skl->resource.max_mem = SKL_FW_MAX_MEM; 12363af36706SVinod Koul 12373af36706SVinod Koul return 0; 12383af36706SVinod Koul } 1239