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 579ba8ffefSDharageswari.R * from available pool. 58e4e2d2f4SJeeja KP */ 599ba8ffefSDharageswari.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; 749ba8ffefSDharageswari.R } else { 759ba8ffefSDharageswari.R return true; 769ba8ffefSDharageswari.R } 77e4e2d2f4SJeeja KP } 78e4e2d2f4SJeeja KP 799ba8ffefSDharageswari.R /* 809ba8ffefSDharageswari.R * Add the mem to the mem pool. This is freed when pipe is deleted. 819ba8ffefSDharageswari.R * Note: DSP does actual memory management we only keep track for complete 829ba8ffefSDharageswari.R * pool 839ba8ffefSDharageswari.R */ 849ba8ffefSDharageswari.R static void skl_tplg_alloc_pipe_mem(struct skl *skl, 859ba8ffefSDharageswari.R struct skl_module_cfg *mconfig) 869ba8ffefSDharageswari.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 959ba8ffefSDharageswari.R * pipe. 96e4e2d2f4SJeeja KP */ 979ba8ffefSDharageswari.R 989ba8ffefSDharageswari.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; 1119ba8ffefSDharageswari.R } else { 1129ba8ffefSDharageswari.R return true; 1139ba8ffefSDharageswari.R } 114e4e2d2f4SJeeja KP } 115e4e2d2f4SJeeja KP 1169ba8ffefSDharageswari.R static void skl_tplg_alloc_pipe_mcps(struct skl *skl, 1179ba8ffefSDharageswari.R struct skl_module_cfg *mconfig) 1189ba8ffefSDharageswari.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 157ea5a137dSSubhransu S. Prusty static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs) 158ea5a137dSSubhransu S. Prusty { 159ea5a137dSSubhransu S. Prusty int slot_map = 0xFFFFFFFF; 160ea5a137dSSubhransu S. Prusty int start_slot = 0; 161ea5a137dSSubhransu S. Prusty int i; 162ea5a137dSSubhransu S. Prusty 163ea5a137dSSubhransu S. Prusty for (i = 0; i < chs; i++) { 164ea5a137dSSubhransu S. Prusty /* 165ea5a137dSSubhransu S. Prusty * For 2 channels with starting slot as 0, slot map will 166ea5a137dSSubhransu S. Prusty * look like 0xFFFFFF10. 167ea5a137dSSubhransu S. Prusty */ 168ea5a137dSSubhransu S. Prusty slot_map &= (~(0xF << (4 * i)) | (start_slot << (4 * i))); 169ea5a137dSSubhransu S. Prusty start_slot++; 170ea5a137dSSubhransu S. Prusty } 171ea5a137dSSubhransu S. Prusty fmt->ch_map = slot_map; 172ea5a137dSSubhransu S. Prusty } 173ea5a137dSSubhransu S. Prusty 174f7590d4fSJeeja KP static void skl_tplg_update_params(struct skl_module_fmt *fmt, 175f7590d4fSJeeja KP struct skl_pipe_params *params, int fixup) 176f7590d4fSJeeja KP { 177f7590d4fSJeeja KP if (fixup & SKL_RATE_FIXUP_MASK) 178f7590d4fSJeeja KP fmt->s_freq = params->s_freq; 179ea5a137dSSubhransu S. Prusty if (fixup & SKL_CH_FIXUP_MASK) { 180f7590d4fSJeeja KP fmt->channels = params->ch; 181ea5a137dSSubhransu S. Prusty skl_tplg_update_chmap(fmt, fmt->channels); 182ea5a137dSSubhransu S. Prusty } 18398256f83SJeeja KP if (fixup & SKL_FMT_FIXUP_MASK) { 18498256f83SJeeja KP fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt); 18598256f83SJeeja KP 18698256f83SJeeja KP /* 18798256f83SJeeja KP * 16 bit is 16 bit container whereas 24 bit is in 32 bit 18898256f83SJeeja KP * container so update bit depth accordingly 18998256f83SJeeja KP */ 19098256f83SJeeja KP switch (fmt->valid_bit_depth) { 19198256f83SJeeja KP case SKL_DEPTH_16BIT: 19298256f83SJeeja KP fmt->bit_depth = fmt->valid_bit_depth; 19398256f83SJeeja KP break; 19498256f83SJeeja KP 19598256f83SJeeja KP default: 19698256f83SJeeja KP fmt->bit_depth = SKL_DEPTH_32BIT; 19798256f83SJeeja KP break; 19898256f83SJeeja KP } 19998256f83SJeeja KP } 20098256f83SJeeja KP 201f7590d4fSJeeja KP } 202f7590d4fSJeeja KP 203f7590d4fSJeeja KP /* 204f7590d4fSJeeja KP * A pipeline may have modules which impact the pcm parameters, like SRC, 205f7590d4fSJeeja KP * channel converter, format converter. 206f7590d4fSJeeja KP * We need to calculate the output params by applying the 'fixup' 207f7590d4fSJeeja KP * Topology will tell driver which type of fixup is to be applied by 208f7590d4fSJeeja KP * supplying the fixup mask, so based on that we calculate the output 209f7590d4fSJeeja KP * 210f7590d4fSJeeja KP * Now In FE the pcm hw_params is source/target format. Same is applicable 211f7590d4fSJeeja KP * for BE with its hw_params invoked. 212f7590d4fSJeeja KP * here based on FE, BE pipeline and direction we calculate the input and 213f7590d4fSJeeja KP * outfix and then apply that for a module 214f7590d4fSJeeja KP */ 215f7590d4fSJeeja KP static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg, 216f7590d4fSJeeja KP struct skl_pipe_params *params, bool is_fe) 217f7590d4fSJeeja KP { 218f7590d4fSJeeja KP int in_fixup, out_fixup; 219f7590d4fSJeeja KP struct skl_module_fmt *in_fmt, *out_fmt; 220f7590d4fSJeeja KP 2214cd9899fSHardik T Shah /* Fixups will be applied to pin 0 only */ 2224cd9899fSHardik T Shah in_fmt = &m_cfg->in_fmt[0]; 2234cd9899fSHardik T Shah out_fmt = &m_cfg->out_fmt[0]; 224f7590d4fSJeeja KP 225f7590d4fSJeeja KP if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { 226f7590d4fSJeeja KP if (is_fe) { 227f7590d4fSJeeja KP in_fixup = m_cfg->params_fixup; 228f7590d4fSJeeja KP out_fixup = (~m_cfg->converter) & 229f7590d4fSJeeja KP m_cfg->params_fixup; 230f7590d4fSJeeja KP } else { 231f7590d4fSJeeja KP out_fixup = m_cfg->params_fixup; 232f7590d4fSJeeja KP in_fixup = (~m_cfg->converter) & 233f7590d4fSJeeja KP m_cfg->params_fixup; 234f7590d4fSJeeja KP } 235f7590d4fSJeeja KP } else { 236f7590d4fSJeeja KP if (is_fe) { 237f7590d4fSJeeja KP out_fixup = m_cfg->params_fixup; 238f7590d4fSJeeja KP in_fixup = (~m_cfg->converter) & 239f7590d4fSJeeja KP m_cfg->params_fixup; 240f7590d4fSJeeja KP } else { 241f7590d4fSJeeja KP in_fixup = m_cfg->params_fixup; 242f7590d4fSJeeja KP out_fixup = (~m_cfg->converter) & 243f7590d4fSJeeja KP m_cfg->params_fixup; 244f7590d4fSJeeja KP } 245f7590d4fSJeeja KP } 246f7590d4fSJeeja KP 247f7590d4fSJeeja KP skl_tplg_update_params(in_fmt, params, in_fixup); 248f7590d4fSJeeja KP skl_tplg_update_params(out_fmt, params, out_fixup); 249f7590d4fSJeeja KP } 250f7590d4fSJeeja KP 251f7590d4fSJeeja KP /* 252f7590d4fSJeeja KP * A module needs input and output buffers, which are dependent upon pcm 253f7590d4fSJeeja KP * params, so once we have calculate params, we need buffer calculation as 254f7590d4fSJeeja KP * well. 255f7590d4fSJeeja KP */ 256f7590d4fSJeeja KP static void skl_tplg_update_buffer_size(struct skl_sst *ctx, 257f7590d4fSJeeja KP struct skl_module_cfg *mcfg) 258f7590d4fSJeeja KP { 259f7590d4fSJeeja KP int multiplier = 1; 2604cd9899fSHardik T Shah struct skl_module_fmt *in_fmt, *out_fmt; 261f0c8e1d9SSubhransu S. Prusty int in_rate, out_rate; 2624cd9899fSHardik T Shah 2634cd9899fSHardik T Shah 2644cd9899fSHardik T Shah /* Since fixups is applied to pin 0 only, ibs, obs needs 2654cd9899fSHardik T Shah * change for pin 0 only 2664cd9899fSHardik T Shah */ 2674cd9899fSHardik T Shah in_fmt = &mcfg->in_fmt[0]; 2684cd9899fSHardik T Shah out_fmt = &mcfg->out_fmt[0]; 269f7590d4fSJeeja KP 270f7590d4fSJeeja KP if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT) 271f7590d4fSJeeja KP multiplier = 5; 272f0c8e1d9SSubhransu S. Prusty 273f0c8e1d9SSubhransu S. Prusty if (in_fmt->s_freq % 1000) 274f0c8e1d9SSubhransu S. Prusty in_rate = (in_fmt->s_freq / 1000) + 1; 275f0c8e1d9SSubhransu S. Prusty else 276f0c8e1d9SSubhransu S. Prusty in_rate = (in_fmt->s_freq / 1000); 277f0c8e1d9SSubhransu S. Prusty 278f0c8e1d9SSubhransu S. Prusty mcfg->ibs = in_rate * (mcfg->in_fmt->channels) * 2794cd9899fSHardik T Shah (mcfg->in_fmt->bit_depth >> 3) * 280f7590d4fSJeeja KP multiplier; 281f7590d4fSJeeja KP 282f0c8e1d9SSubhransu S. Prusty if (mcfg->out_fmt->s_freq % 1000) 283f0c8e1d9SSubhransu S. Prusty out_rate = (mcfg->out_fmt->s_freq / 1000) + 1; 284f0c8e1d9SSubhransu S. Prusty else 285f0c8e1d9SSubhransu S. Prusty out_rate = (mcfg->out_fmt->s_freq / 1000); 286f0c8e1d9SSubhransu S. Prusty 287f0c8e1d9SSubhransu S. Prusty mcfg->obs = out_rate * (mcfg->out_fmt->channels) * 2884cd9899fSHardik T Shah (mcfg->out_fmt->bit_depth >> 3) * 289f7590d4fSJeeja KP multiplier; 290f7590d4fSJeeja KP } 291f7590d4fSJeeja KP 2922d1419a3SJeeja KP static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, 2932d1419a3SJeeja KP struct skl_sst *ctx) 2942d1419a3SJeeja KP { 2952d1419a3SJeeja KP struct skl_module_cfg *m_cfg = w->priv; 2962d1419a3SJeeja KP int link_type, dir; 2972d1419a3SJeeja KP u32 ch, s_freq, s_fmt; 2982d1419a3SJeeja KP struct nhlt_specific_cfg *cfg; 2992d1419a3SJeeja KP struct skl *skl = get_skl_ctx(ctx->dev); 3002d1419a3SJeeja KP 3012d1419a3SJeeja KP /* check if we already have blob */ 3022d1419a3SJeeja KP if (m_cfg->formats_config.caps_size > 0) 3032d1419a3SJeeja KP return 0; 3042d1419a3SJeeja KP 305c7c6c736SJeeja KP dev_dbg(ctx->dev, "Applying default cfg blob\n"); 3062d1419a3SJeeja KP switch (m_cfg->dev_type) { 3072d1419a3SJeeja KP case SKL_DEVICE_DMIC: 3082d1419a3SJeeja KP link_type = NHLT_LINK_DMIC; 309c7c6c736SJeeja KP dir = SNDRV_PCM_STREAM_CAPTURE; 3102d1419a3SJeeja KP s_freq = m_cfg->in_fmt[0].s_freq; 3112d1419a3SJeeja KP s_fmt = m_cfg->in_fmt[0].bit_depth; 3122d1419a3SJeeja KP ch = m_cfg->in_fmt[0].channels; 3132d1419a3SJeeja KP break; 3142d1419a3SJeeja KP 3152d1419a3SJeeja KP case SKL_DEVICE_I2S: 3162d1419a3SJeeja KP link_type = NHLT_LINK_SSP; 3172d1419a3SJeeja KP if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) { 318c7c6c736SJeeja KP dir = SNDRV_PCM_STREAM_PLAYBACK; 3192d1419a3SJeeja KP s_freq = m_cfg->out_fmt[0].s_freq; 3202d1419a3SJeeja KP s_fmt = m_cfg->out_fmt[0].bit_depth; 3212d1419a3SJeeja KP ch = m_cfg->out_fmt[0].channels; 322c7c6c736SJeeja KP } else { 323c7c6c736SJeeja KP dir = SNDRV_PCM_STREAM_CAPTURE; 324c7c6c736SJeeja KP s_freq = m_cfg->in_fmt[0].s_freq; 325c7c6c736SJeeja KP s_fmt = m_cfg->in_fmt[0].bit_depth; 326c7c6c736SJeeja KP ch = m_cfg->in_fmt[0].channels; 3272d1419a3SJeeja KP } 3282d1419a3SJeeja KP break; 3292d1419a3SJeeja KP 3302d1419a3SJeeja KP default: 3312d1419a3SJeeja KP return -EINVAL; 3322d1419a3SJeeja KP } 3332d1419a3SJeeja KP 3342d1419a3SJeeja KP /* update the blob based on virtual bus_id and default params */ 3352d1419a3SJeeja KP cfg = skl_get_ep_blob(skl, m_cfg->vbus_id, link_type, 3362d1419a3SJeeja KP s_fmt, ch, s_freq, dir); 3372d1419a3SJeeja KP if (cfg) { 3382d1419a3SJeeja KP m_cfg->formats_config.caps_size = cfg->size; 3392d1419a3SJeeja KP m_cfg->formats_config.caps = (u32 *) &cfg->caps; 3402d1419a3SJeeja KP } else { 3412d1419a3SJeeja KP dev_err(ctx->dev, "Blob NULL for id %x type %d dirn %d\n", 3422d1419a3SJeeja KP m_cfg->vbus_id, link_type, dir); 3432d1419a3SJeeja KP dev_err(ctx->dev, "PCM: ch %d, freq %d, fmt %d\n", 3442d1419a3SJeeja KP ch, s_freq, s_fmt); 3452d1419a3SJeeja KP return -EIO; 3462d1419a3SJeeja KP } 3472d1419a3SJeeja KP 3482d1419a3SJeeja KP return 0; 3492d1419a3SJeeja KP } 3502d1419a3SJeeja KP 351f7590d4fSJeeja KP static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w, 352f7590d4fSJeeja KP struct skl_sst *ctx) 353f7590d4fSJeeja KP { 354f7590d4fSJeeja KP struct skl_module_cfg *m_cfg = w->priv; 355f7590d4fSJeeja KP struct skl_pipe_params *params = m_cfg->pipe->p_params; 356f7590d4fSJeeja KP int p_conn_type = m_cfg->pipe->conn_type; 357f7590d4fSJeeja KP bool is_fe; 358f7590d4fSJeeja KP 359f7590d4fSJeeja KP if (!m_cfg->params_fixup) 360f7590d4fSJeeja KP return; 361f7590d4fSJeeja KP 362f7590d4fSJeeja KP dev_dbg(ctx->dev, "Mconfig for widget=%s BEFORE updation\n", 363f7590d4fSJeeja KP w->name); 364f7590d4fSJeeja KP 365f7590d4fSJeeja KP skl_dump_mconfig(ctx, m_cfg); 366f7590d4fSJeeja KP 367f7590d4fSJeeja KP if (p_conn_type == SKL_PIPE_CONN_TYPE_FE) 368f7590d4fSJeeja KP is_fe = true; 369f7590d4fSJeeja KP else 370f7590d4fSJeeja KP is_fe = false; 371f7590d4fSJeeja KP 372f7590d4fSJeeja KP skl_tplg_update_params_fixup(m_cfg, params, is_fe); 373f7590d4fSJeeja KP skl_tplg_update_buffer_size(ctx, m_cfg); 374f7590d4fSJeeja KP 375f7590d4fSJeeja KP dev_dbg(ctx->dev, "Mconfig for widget=%s AFTER updation\n", 376f7590d4fSJeeja KP w->name); 377f7590d4fSJeeja KP 378f7590d4fSJeeja KP skl_dump_mconfig(ctx, m_cfg); 379f7590d4fSJeeja KP } 380f7590d4fSJeeja KP 381e4e2d2f4SJeeja KP /* 382e4e2d2f4SJeeja KP * A pipe can have multiple modules, each of them will be a DAPM widget as 383e4e2d2f4SJeeja KP * well. While managing a pipeline we need to get the list of all the 384e4e2d2f4SJeeja KP * widgets in a pipelines, so this helper - skl_tplg_get_pipe_widget() helps 385e4e2d2f4SJeeja KP * to get the SKL type widgets in that pipeline 386e4e2d2f4SJeeja KP */ 387e4e2d2f4SJeeja KP static int skl_tplg_alloc_pipe_widget(struct device *dev, 388e4e2d2f4SJeeja KP struct snd_soc_dapm_widget *w, struct skl_pipe *pipe) 389e4e2d2f4SJeeja KP { 390e4e2d2f4SJeeja KP struct skl_module_cfg *src_module = NULL; 391e4e2d2f4SJeeja KP struct snd_soc_dapm_path *p = NULL; 392e4e2d2f4SJeeja KP struct skl_pipe_module *p_module = NULL; 393e4e2d2f4SJeeja KP 394e4e2d2f4SJeeja KP p_module = devm_kzalloc(dev, sizeof(*p_module), GFP_KERNEL); 395e4e2d2f4SJeeja KP if (!p_module) 396e4e2d2f4SJeeja KP return -ENOMEM; 397e4e2d2f4SJeeja KP 398e4e2d2f4SJeeja KP p_module->w = w; 399e4e2d2f4SJeeja KP list_add_tail(&p_module->node, &pipe->w_list); 400e4e2d2f4SJeeja KP 401e4e2d2f4SJeeja KP snd_soc_dapm_widget_for_each_sink_path(w, p) { 402e4e2d2f4SJeeja KP if ((p->sink->priv == NULL) 403e4e2d2f4SJeeja KP && (!is_skl_dsp_widget_type(w))) 404e4e2d2f4SJeeja KP continue; 405e4e2d2f4SJeeja KP 406e4e2d2f4SJeeja KP if ((p->sink->priv != NULL) && p->connect 407e4e2d2f4SJeeja KP && is_skl_dsp_widget_type(p->sink)) { 408e4e2d2f4SJeeja KP 409e4e2d2f4SJeeja KP src_module = p->sink->priv; 410e4e2d2f4SJeeja KP if (pipe->ppl_id == src_module->pipe->ppl_id) 411e4e2d2f4SJeeja KP skl_tplg_alloc_pipe_widget(dev, 412e4e2d2f4SJeeja KP p->sink, pipe); 413e4e2d2f4SJeeja KP } 414e4e2d2f4SJeeja KP } 415e4e2d2f4SJeeja KP return 0; 416e4e2d2f4SJeeja KP } 417e4e2d2f4SJeeja KP 418e4e2d2f4SJeeja KP /* 419abb74003SJeeja KP * some modules can have multiple params set from user control and 420abb74003SJeeja KP * need to be set after module is initialized. If set_param flag is 421abb74003SJeeja KP * set module params will be done after module is initialised. 422abb74003SJeeja KP */ 423abb74003SJeeja KP static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w, 424abb74003SJeeja KP struct skl_sst *ctx) 425abb74003SJeeja KP { 426abb74003SJeeja KP int i, ret; 427abb74003SJeeja KP struct skl_module_cfg *mconfig = w->priv; 428abb74003SJeeja KP const struct snd_kcontrol_new *k; 429abb74003SJeeja KP struct soc_bytes_ext *sb; 430abb74003SJeeja KP struct skl_algo_data *bc; 431abb74003SJeeja KP struct skl_specific_cfg *sp_cfg; 432abb74003SJeeja KP 433abb74003SJeeja KP if (mconfig->formats_config.caps_size > 0 && 4344ced1827SJeeja KP mconfig->formats_config.set_params == SKL_PARAM_SET) { 435abb74003SJeeja KP sp_cfg = &mconfig->formats_config; 436abb74003SJeeja KP ret = skl_set_module_params(ctx, sp_cfg->caps, 437abb74003SJeeja KP sp_cfg->caps_size, 438abb74003SJeeja KP sp_cfg->param_id, mconfig); 439abb74003SJeeja KP if (ret < 0) 440abb74003SJeeja KP return ret; 441abb74003SJeeja KP } 442abb74003SJeeja KP 443abb74003SJeeja KP for (i = 0; i < w->num_kcontrols; i++) { 444abb74003SJeeja KP k = &w->kcontrol_news[i]; 445abb74003SJeeja KP if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 446abb74003SJeeja KP sb = (void *) k->private_value; 447abb74003SJeeja KP bc = (struct skl_algo_data *)sb->dobj.private; 448abb74003SJeeja KP 4494ced1827SJeeja KP if (bc->set_params == SKL_PARAM_SET) { 450abb74003SJeeja KP ret = skl_set_module_params(ctx, 451abb74003SJeeja KP (u32 *)bc->params, bc->max, 452abb74003SJeeja KP bc->param_id, mconfig); 453abb74003SJeeja KP if (ret < 0) 454abb74003SJeeja KP return ret; 455abb74003SJeeja KP } 456abb74003SJeeja KP } 457abb74003SJeeja KP } 458abb74003SJeeja KP 459abb74003SJeeja KP return 0; 460abb74003SJeeja KP } 461abb74003SJeeja KP 462abb74003SJeeja KP /* 463abb74003SJeeja KP * some module param can set from user control and this is required as 464abb74003SJeeja KP * when module is initailzed. if module param is required in init it is 465abb74003SJeeja KP * identifed by set_param flag. if set_param flag is not set, then this 466abb74003SJeeja KP * parameter needs to set as part of module init. 467abb74003SJeeja KP */ 468abb74003SJeeja KP static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w) 469abb74003SJeeja KP { 470abb74003SJeeja KP const struct snd_kcontrol_new *k; 471abb74003SJeeja KP struct soc_bytes_ext *sb; 472abb74003SJeeja KP struct skl_algo_data *bc; 473abb74003SJeeja KP struct skl_module_cfg *mconfig = w->priv; 474abb74003SJeeja KP int i; 475abb74003SJeeja KP 476abb74003SJeeja KP for (i = 0; i < w->num_kcontrols; i++) { 477abb74003SJeeja KP k = &w->kcontrol_news[i]; 478abb74003SJeeja KP if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 479abb74003SJeeja KP sb = (struct soc_bytes_ext *)k->private_value; 480abb74003SJeeja KP bc = (struct skl_algo_data *)sb->dobj.private; 481abb74003SJeeja KP 4824ced1827SJeeja KP if (bc->set_params != SKL_PARAM_INIT) 483abb74003SJeeja KP continue; 484abb74003SJeeja KP 485abb74003SJeeja KP mconfig->formats_config.caps = (u32 *)&bc->params; 486abb74003SJeeja KP mconfig->formats_config.caps_size = bc->max; 487abb74003SJeeja KP 488abb74003SJeeja KP break; 489abb74003SJeeja KP } 490abb74003SJeeja KP } 491abb74003SJeeja KP 492abb74003SJeeja KP return 0; 493abb74003SJeeja KP } 494abb74003SJeeja KP 495abb74003SJeeja KP /* 496e4e2d2f4SJeeja KP * Inside a pipe instance, we can have various modules. These modules need 497e4e2d2f4SJeeja KP * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by 498e4e2d2f4SJeeja KP * skl_init_module() routine, so invoke that for all modules in a pipeline 499e4e2d2f4SJeeja KP */ 500e4e2d2f4SJeeja KP static int 501e4e2d2f4SJeeja KP skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) 502e4e2d2f4SJeeja KP { 503e4e2d2f4SJeeja KP struct skl_pipe_module *w_module; 504e4e2d2f4SJeeja KP struct snd_soc_dapm_widget *w; 505e4e2d2f4SJeeja KP struct skl_module_cfg *mconfig; 506e4e2d2f4SJeeja KP struct skl_sst *ctx = skl->skl_sst; 507e4e2d2f4SJeeja KP int ret = 0; 508e4e2d2f4SJeeja KP 509e4e2d2f4SJeeja KP list_for_each_entry(w_module, &pipe->w_list, node) { 510e4e2d2f4SJeeja KP w = w_module->w; 511e4e2d2f4SJeeja KP mconfig = w->priv; 512e4e2d2f4SJeeja KP 513e4e2d2f4SJeeja KP /* check resource available */ 5149ba8ffefSDharageswari.R if (!skl_is_pipe_mcps_avail(skl, mconfig)) 515e4e2d2f4SJeeja KP return -ENOMEM; 516e4e2d2f4SJeeja KP 5176c5768b3SDharageswari R if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) { 5186c5768b3SDharageswari R ret = ctx->dsp->fw_ops.load_mod(ctx->dsp, 5196c5768b3SDharageswari R mconfig->id.module_id, mconfig->guid); 5206c5768b3SDharageswari R if (ret < 0) 5216c5768b3SDharageswari R return ret; 522d643678bSJeeja KP 523d643678bSJeeja KP mconfig->m_state = SKL_MODULE_LOADED; 5246c5768b3SDharageswari R } 5256c5768b3SDharageswari R 5262d1419a3SJeeja KP /* update blob if blob is null for be with default value */ 5272d1419a3SJeeja KP skl_tplg_update_be_blob(w, ctx); 5282d1419a3SJeeja KP 529f7590d4fSJeeja KP /* 530f7590d4fSJeeja KP * apply fix/conversion to module params based on 531f7590d4fSJeeja KP * FE/BE params 532f7590d4fSJeeja KP */ 533f7590d4fSJeeja KP skl_tplg_update_module_params(w, ctx); 534abb74003SJeeja KP 535abb74003SJeeja KP skl_tplg_set_module_init_data(w); 5369939a9c3SJeeja KP ret = skl_init_module(ctx, mconfig); 537e4e2d2f4SJeeja KP if (ret < 0) 538e4e2d2f4SJeeja KP return ret; 539abb74003SJeeja KP 540*260eb73aSDharageswari R skl_tplg_alloc_pipe_mcps(skl, mconfig); 541abb74003SJeeja KP ret = skl_tplg_set_module_params(w, ctx); 542e4e2d2f4SJeeja KP if (ret < 0) 543e4e2d2f4SJeeja KP return ret; 544e4e2d2f4SJeeja KP } 545e4e2d2f4SJeeja KP 546e4e2d2f4SJeeja KP return 0; 547e4e2d2f4SJeeja KP } 548d93f8e55SVinod Koul 5496c5768b3SDharageswari R static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx, 5506c5768b3SDharageswari R struct skl_pipe *pipe) 5516c5768b3SDharageswari R { 5526c5768b3SDharageswari R struct skl_pipe_module *w_module = NULL; 5536c5768b3SDharageswari R struct skl_module_cfg *mconfig = NULL; 5546c5768b3SDharageswari R 5556c5768b3SDharageswari R list_for_each_entry(w_module, &pipe->w_list, node) { 5566c5768b3SDharageswari R mconfig = w_module->w->priv; 5576c5768b3SDharageswari R 558d643678bSJeeja KP if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod && 559d643678bSJeeja KP mconfig->m_state > SKL_MODULE_UNINIT) 5606c5768b3SDharageswari R return ctx->dsp->fw_ops.unload_mod(ctx->dsp, 5616c5768b3SDharageswari R mconfig->id.module_id); 5626c5768b3SDharageswari R } 5636c5768b3SDharageswari R 5646c5768b3SDharageswari R /* no modules to unload in this path, so return */ 5656c5768b3SDharageswari R return 0; 5666c5768b3SDharageswari R } 5676c5768b3SDharageswari R 568d93f8e55SVinod Koul /* 569d93f8e55SVinod Koul * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we 570d93f8e55SVinod Koul * need create the pipeline. So we do following: 571d93f8e55SVinod Koul * - check the resources 572d93f8e55SVinod Koul * - Create the pipeline 573d93f8e55SVinod Koul * - Initialize the modules in pipeline 574d93f8e55SVinod Koul * - finally bind all modules together 575d93f8e55SVinod Koul */ 576d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, 577d93f8e55SVinod Koul struct skl *skl) 578d93f8e55SVinod Koul { 579d93f8e55SVinod Koul int ret; 580d93f8e55SVinod Koul struct skl_module_cfg *mconfig = w->priv; 581d93f8e55SVinod Koul struct skl_pipe_module *w_module; 582d93f8e55SVinod Koul struct skl_pipe *s_pipe = mconfig->pipe; 583d93f8e55SVinod Koul struct skl_module_cfg *src_module = NULL, *dst_module; 584d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 585d93f8e55SVinod Koul 586d93f8e55SVinod Koul /* check resource available */ 5879ba8ffefSDharageswari.R if (!skl_is_pipe_mcps_avail(skl, mconfig)) 588d93f8e55SVinod Koul return -EBUSY; 589d93f8e55SVinod Koul 5909ba8ffefSDharageswari.R if (!skl_is_pipe_mem_avail(skl, mconfig)) 591d93f8e55SVinod Koul return -ENOMEM; 592d93f8e55SVinod Koul 593d93f8e55SVinod Koul /* 594d93f8e55SVinod Koul * Create a list of modules for pipe. 595d93f8e55SVinod Koul * This list contains modules from source to sink 596d93f8e55SVinod Koul */ 597d93f8e55SVinod Koul ret = skl_create_pipeline(ctx, mconfig->pipe); 598d93f8e55SVinod Koul if (ret < 0) 599d93f8e55SVinod Koul return ret; 600d93f8e55SVinod Koul 601*260eb73aSDharageswari R skl_tplg_alloc_pipe_mem(skl, mconfig); 602*260eb73aSDharageswari R skl_tplg_alloc_pipe_mcps(skl, mconfig); 603*260eb73aSDharageswari R 604d93f8e55SVinod Koul /* 605d93f8e55SVinod Koul * we create a w_list of all widgets in that pipe. This list is not 606d93f8e55SVinod Koul * freed on PMD event as widgets within a pipe are static. This 607d93f8e55SVinod Koul * saves us cycles to get widgets in pipe every time. 608d93f8e55SVinod Koul * 609d93f8e55SVinod Koul * So if we have already initialized all the widgets of a pipeline 610d93f8e55SVinod Koul * we skip, so check for list_empty and create the list if empty 611d93f8e55SVinod Koul */ 612d93f8e55SVinod Koul if (list_empty(&s_pipe->w_list)) { 613d93f8e55SVinod Koul ret = skl_tplg_alloc_pipe_widget(ctx->dev, w, s_pipe); 614d93f8e55SVinod Koul if (ret < 0) 615d93f8e55SVinod Koul return ret; 616d93f8e55SVinod Koul } 617d93f8e55SVinod Koul 618d93f8e55SVinod Koul /* Init all pipe modules from source to sink */ 619d93f8e55SVinod Koul ret = skl_tplg_init_pipe_modules(skl, s_pipe); 620d93f8e55SVinod Koul if (ret < 0) 621d93f8e55SVinod Koul return ret; 622d93f8e55SVinod Koul 623d93f8e55SVinod Koul /* Bind modules from source to sink */ 624d93f8e55SVinod Koul list_for_each_entry(w_module, &s_pipe->w_list, node) { 625d93f8e55SVinod Koul dst_module = w_module->w->priv; 626d93f8e55SVinod Koul 627d93f8e55SVinod Koul if (src_module == NULL) { 628d93f8e55SVinod Koul src_module = dst_module; 629d93f8e55SVinod Koul continue; 630d93f8e55SVinod Koul } 631d93f8e55SVinod Koul 632d93f8e55SVinod Koul ret = skl_bind_modules(ctx, src_module, dst_module); 633d93f8e55SVinod Koul if (ret < 0) 634d93f8e55SVinod Koul return ret; 635d93f8e55SVinod Koul 636d93f8e55SVinod Koul src_module = dst_module; 637d93f8e55SVinod Koul } 638d93f8e55SVinod Koul 639d93f8e55SVinod Koul return 0; 640d93f8e55SVinod Koul } 641d93f8e55SVinod Koul 642cc6a4044SJeeja KP /* 643cc6a4044SJeeja KP * Some modules require params to be set after the module is bound to 644cc6a4044SJeeja KP * all pins connected. 645cc6a4044SJeeja KP * 646cc6a4044SJeeja KP * The module provider initializes set_param flag for such modules and we 647cc6a4044SJeeja KP * send params after binding 648cc6a4044SJeeja KP */ 649cc6a4044SJeeja KP static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, 650cc6a4044SJeeja KP struct skl_module_cfg *mcfg, struct skl_sst *ctx) 651cc6a4044SJeeja KP { 652cc6a4044SJeeja KP int i, ret; 653cc6a4044SJeeja KP struct skl_module_cfg *mconfig = w->priv; 654cc6a4044SJeeja KP const struct snd_kcontrol_new *k; 655cc6a4044SJeeja KP struct soc_bytes_ext *sb; 656cc6a4044SJeeja KP struct skl_algo_data *bc; 657cc6a4044SJeeja KP struct skl_specific_cfg *sp_cfg; 658cc6a4044SJeeja KP 659cc6a4044SJeeja KP /* 660cc6a4044SJeeja KP * check all out/in pins are in bind state. 661cc6a4044SJeeja KP * if so set the module param 662cc6a4044SJeeja KP */ 663cc6a4044SJeeja KP for (i = 0; i < mcfg->max_out_queue; i++) { 664cc6a4044SJeeja KP if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE) 665cc6a4044SJeeja KP return 0; 666cc6a4044SJeeja KP } 667cc6a4044SJeeja KP 668cc6a4044SJeeja KP for (i = 0; i < mcfg->max_in_queue; i++) { 669cc6a4044SJeeja KP if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE) 670cc6a4044SJeeja KP return 0; 671cc6a4044SJeeja KP } 672cc6a4044SJeeja KP 673cc6a4044SJeeja KP if (mconfig->formats_config.caps_size > 0 && 674cc6a4044SJeeja KP mconfig->formats_config.set_params == SKL_PARAM_BIND) { 675cc6a4044SJeeja KP sp_cfg = &mconfig->formats_config; 676cc6a4044SJeeja KP ret = skl_set_module_params(ctx, sp_cfg->caps, 677cc6a4044SJeeja KP sp_cfg->caps_size, 678cc6a4044SJeeja KP sp_cfg->param_id, mconfig); 679cc6a4044SJeeja KP if (ret < 0) 680cc6a4044SJeeja KP return ret; 681cc6a4044SJeeja KP } 682cc6a4044SJeeja KP 683cc6a4044SJeeja KP for (i = 0; i < w->num_kcontrols; i++) { 684cc6a4044SJeeja KP k = &w->kcontrol_news[i]; 685cc6a4044SJeeja KP if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 686cc6a4044SJeeja KP sb = (void *) k->private_value; 687cc6a4044SJeeja KP bc = (struct skl_algo_data *)sb->dobj.private; 688cc6a4044SJeeja KP 689cc6a4044SJeeja KP if (bc->set_params == SKL_PARAM_BIND) { 690cc6a4044SJeeja KP ret = skl_set_module_params(ctx, 691cc6a4044SJeeja KP (u32 *)bc->params, bc->max, 692cc6a4044SJeeja KP bc->param_id, mconfig); 693cc6a4044SJeeja KP if (ret < 0) 694cc6a4044SJeeja KP return ret; 695cc6a4044SJeeja KP } 696cc6a4044SJeeja KP } 697cc6a4044SJeeja KP } 698cc6a4044SJeeja KP 699cc6a4044SJeeja KP return 0; 700cc6a4044SJeeja KP } 701cc6a4044SJeeja KP 7028724ff17SJeeja KP static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, 7038724ff17SJeeja KP struct skl *skl, 7046bd4cf85SJeeja KP struct snd_soc_dapm_widget *src_w, 7058724ff17SJeeja KP struct skl_module_cfg *src_mconfig) 706d93f8e55SVinod Koul { 707d93f8e55SVinod Koul struct snd_soc_dapm_path *p; 7080ed95d76SJeeja KP struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL; 7098724ff17SJeeja KP struct skl_module_cfg *sink_mconfig; 710d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 7118724ff17SJeeja KP int ret; 712d93f8e55SVinod Koul 7138724ff17SJeeja KP snd_soc_dapm_widget_for_each_sink_path(w, p) { 714d93f8e55SVinod Koul if (!p->connect) 715d93f8e55SVinod Koul continue; 716d93f8e55SVinod Koul 717d93f8e55SVinod Koul dev_dbg(ctx->dev, "%s: src widget=%s\n", __func__, w->name); 718d93f8e55SVinod Koul dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name); 719d93f8e55SVinod Koul 7200ed95d76SJeeja KP next_sink = p->sink; 7216bd4cf85SJeeja KP 7226bd4cf85SJeeja KP if (!is_skl_dsp_widget_type(p->sink)) 7236bd4cf85SJeeja KP return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig); 7246bd4cf85SJeeja KP 725d93f8e55SVinod Koul /* 726d93f8e55SVinod Koul * here we will check widgets in sink pipelines, so that 727d93f8e55SVinod Koul * can be any widgets type and we are only interested if 728d93f8e55SVinod Koul * they are ones used for SKL so check that first 729d93f8e55SVinod Koul */ 730d93f8e55SVinod Koul if ((p->sink->priv != NULL) && 731d93f8e55SVinod Koul is_skl_dsp_widget_type(p->sink)) { 732d93f8e55SVinod Koul 733d93f8e55SVinod Koul sink = p->sink; 734d93f8e55SVinod Koul sink_mconfig = sink->priv; 735d93f8e55SVinod Koul 736cc6a4044SJeeja KP if (src_mconfig->m_state == SKL_MODULE_UNINIT || 737cc6a4044SJeeja KP sink_mconfig->m_state == SKL_MODULE_UNINIT) 738cc6a4044SJeeja KP continue; 739cc6a4044SJeeja KP 740d93f8e55SVinod Koul /* Bind source to sink, mixin is always source */ 741d93f8e55SVinod Koul ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig); 742d93f8e55SVinod Koul if (ret) 743d93f8e55SVinod Koul return ret; 744d93f8e55SVinod Koul 745cc6a4044SJeeja KP /* set module params after bind */ 746cc6a4044SJeeja KP skl_tplg_set_module_bind_params(src_w, src_mconfig, ctx); 747cc6a4044SJeeja KP skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx); 748cc6a4044SJeeja KP 749d93f8e55SVinod Koul /* Start sinks pipe first */ 750d93f8e55SVinod Koul if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) { 751d1730c3dSJeeja KP if (sink_mconfig->pipe->conn_type != 752d1730c3dSJeeja KP SKL_PIPE_CONN_TYPE_FE) 753d1730c3dSJeeja KP ret = skl_run_pipe(ctx, 754d1730c3dSJeeja KP sink_mconfig->pipe); 755d93f8e55SVinod Koul if (ret) 756d93f8e55SVinod Koul return ret; 757d93f8e55SVinod Koul } 758d93f8e55SVinod Koul } 759d93f8e55SVinod Koul } 760d93f8e55SVinod Koul 7618724ff17SJeeja KP if (!sink) 7626bd4cf85SJeeja KP return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig); 7638724ff17SJeeja KP 7648724ff17SJeeja KP return 0; 7658724ff17SJeeja KP } 7668724ff17SJeeja KP 767d93f8e55SVinod Koul /* 768d93f8e55SVinod Koul * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA 769d93f8e55SVinod Koul * we need to do following: 770d93f8e55SVinod Koul * - Bind to sink pipeline 771d93f8e55SVinod Koul * Since the sink pipes can be running and we don't get mixer event on 772d93f8e55SVinod Koul * connect for already running mixer, we need to find the sink pipes 773d93f8e55SVinod Koul * here and bind to them. This way dynamic connect works. 774d93f8e55SVinod Koul * - Start sink pipeline, if not running 775d93f8e55SVinod Koul * - Then run current pipe 776d93f8e55SVinod Koul */ 777d93f8e55SVinod Koul static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, 778d93f8e55SVinod Koul struct skl *skl) 779d93f8e55SVinod Koul { 7808724ff17SJeeja KP struct skl_module_cfg *src_mconfig; 781d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 782d93f8e55SVinod Koul int ret = 0; 783d93f8e55SVinod Koul 7848724ff17SJeeja KP src_mconfig = w->priv; 785d93f8e55SVinod Koul 786d93f8e55SVinod Koul /* 787d93f8e55SVinod Koul * find which sink it is connected to, bind with the sink, 788d93f8e55SVinod Koul * if sink is not started, start sink pipe first, then start 789d93f8e55SVinod Koul * this pipe 790d93f8e55SVinod Koul */ 7916bd4cf85SJeeja KP ret = skl_tplg_bind_sinks(w, skl, w, src_mconfig); 7928724ff17SJeeja KP if (ret) 7938724ff17SJeeja KP return ret; 7948724ff17SJeeja KP 795d93f8e55SVinod Koul /* Start source pipe last after starting all sinks */ 796d1730c3dSJeeja KP if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) 797d1730c3dSJeeja KP return skl_run_pipe(ctx, src_mconfig->pipe); 798d93f8e55SVinod Koul 799d93f8e55SVinod Koul return 0; 800d93f8e55SVinod Koul } 801d93f8e55SVinod Koul 8028724ff17SJeeja KP static struct snd_soc_dapm_widget *skl_get_src_dsp_widget( 8038724ff17SJeeja KP struct snd_soc_dapm_widget *w, struct skl *skl) 8048724ff17SJeeja KP { 8058724ff17SJeeja KP struct snd_soc_dapm_path *p; 8068724ff17SJeeja KP struct snd_soc_dapm_widget *src_w = NULL; 8078724ff17SJeeja KP struct skl_sst *ctx = skl->skl_sst; 8088724ff17SJeeja KP 809d93f8e55SVinod Koul snd_soc_dapm_widget_for_each_source_path(w, p) { 8108724ff17SJeeja KP src_w = p->source; 811d93f8e55SVinod Koul if (!p->connect) 812d93f8e55SVinod Koul continue; 813d93f8e55SVinod Koul 8148724ff17SJeeja KP dev_dbg(ctx->dev, "sink widget=%s\n", w->name); 8158724ff17SJeeja KP dev_dbg(ctx->dev, "src widget=%s\n", p->source->name); 816d93f8e55SVinod Koul 817d93f8e55SVinod Koul /* 8188724ff17SJeeja KP * here we will check widgets in sink pipelines, so that can 8198724ff17SJeeja KP * be any widgets type and we are only interested if they are 8208724ff17SJeeja KP * ones used for SKL so check that first 821d93f8e55SVinod Koul */ 8228724ff17SJeeja KP if ((p->source->priv != NULL) && 8238724ff17SJeeja KP is_skl_dsp_widget_type(p->source)) { 8248724ff17SJeeja KP return p->source; 825d93f8e55SVinod Koul } 826d93f8e55SVinod Koul } 827d93f8e55SVinod Koul 8288724ff17SJeeja KP if (src_w != NULL) 8298724ff17SJeeja KP return skl_get_src_dsp_widget(src_w, skl); 830d93f8e55SVinod Koul 8318724ff17SJeeja KP return NULL; 832d93f8e55SVinod Koul } 833d93f8e55SVinod Koul 834d93f8e55SVinod Koul /* 835d93f8e55SVinod Koul * in the Post-PMU event of mixer we need to do following: 836d93f8e55SVinod Koul * - Check if this pipe is running 837d93f8e55SVinod Koul * - if not, then 838d93f8e55SVinod Koul * - bind this pipeline to its source pipeline 839d93f8e55SVinod Koul * if source pipe is already running, this means it is a dynamic 840d93f8e55SVinod Koul * connection and we need to bind only to that pipe 841d93f8e55SVinod Koul * - start this pipeline 842d93f8e55SVinod Koul */ 843d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, 844d93f8e55SVinod Koul struct skl *skl) 845d93f8e55SVinod Koul { 846d93f8e55SVinod Koul int ret = 0; 847d93f8e55SVinod Koul struct snd_soc_dapm_widget *source, *sink; 848d93f8e55SVinod Koul struct skl_module_cfg *src_mconfig, *sink_mconfig; 849d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 850d93f8e55SVinod Koul int src_pipe_started = 0; 851d93f8e55SVinod Koul 852d93f8e55SVinod Koul sink = w; 853d93f8e55SVinod Koul sink_mconfig = sink->priv; 854d93f8e55SVinod Koul 855d93f8e55SVinod Koul /* 856d93f8e55SVinod Koul * If source pipe is already started, that means source is driving 857d93f8e55SVinod Koul * one more sink before this sink got connected, Since source is 858d93f8e55SVinod Koul * started, bind this sink to source and start this pipe. 859d93f8e55SVinod Koul */ 8608724ff17SJeeja KP source = skl_get_src_dsp_widget(w, skl); 8618724ff17SJeeja KP if (source != NULL) { 862d93f8e55SVinod Koul src_mconfig = source->priv; 863d93f8e55SVinod Koul sink_mconfig = sink->priv; 864d93f8e55SVinod Koul src_pipe_started = 1; 865d93f8e55SVinod Koul 866d93f8e55SVinod Koul /* 8678724ff17SJeeja KP * check pipe state, then no need to bind or start the 8688724ff17SJeeja KP * pipe 869d93f8e55SVinod Koul */ 870d93f8e55SVinod Koul if (src_mconfig->pipe->state != SKL_PIPE_STARTED) 871d93f8e55SVinod Koul src_pipe_started = 0; 872d93f8e55SVinod Koul } 873d93f8e55SVinod Koul 874d93f8e55SVinod Koul if (src_pipe_started) { 875d93f8e55SVinod Koul ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig); 876d93f8e55SVinod Koul if (ret) 877d93f8e55SVinod Koul return ret; 878d93f8e55SVinod Koul 879cc6a4044SJeeja KP /* set module params after bind */ 880cc6a4044SJeeja KP skl_tplg_set_module_bind_params(source, src_mconfig, ctx); 881cc6a4044SJeeja KP skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx); 882cc6a4044SJeeja KP 883d1730c3dSJeeja KP if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) 884d93f8e55SVinod Koul ret = skl_run_pipe(ctx, sink_mconfig->pipe); 885d93f8e55SVinod Koul } 886d93f8e55SVinod Koul 887d93f8e55SVinod Koul return ret; 888d93f8e55SVinod Koul } 889d93f8e55SVinod Koul 890d93f8e55SVinod Koul /* 891d93f8e55SVinod Koul * in the Pre-PMD event of mixer we need to do following: 892d93f8e55SVinod Koul * - Stop the pipe 893d93f8e55SVinod Koul * - find the source connections and remove that from dapm_path_list 894d93f8e55SVinod Koul * - unbind with source pipelines if still connected 895d93f8e55SVinod Koul */ 896d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w, 897d93f8e55SVinod Koul struct skl *skl) 898d93f8e55SVinod Koul { 899d93f8e55SVinod Koul struct skl_module_cfg *src_mconfig, *sink_mconfig; 900ce1b5551SJeeja KP int ret = 0, i; 901d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 902d93f8e55SVinod Koul 903ce1b5551SJeeja KP sink_mconfig = w->priv; 904d93f8e55SVinod Koul 905d93f8e55SVinod Koul /* Stop the pipe */ 906d93f8e55SVinod Koul ret = skl_stop_pipe(ctx, sink_mconfig->pipe); 907d93f8e55SVinod Koul if (ret) 908d93f8e55SVinod Koul return ret; 909d93f8e55SVinod Koul 910ce1b5551SJeeja KP for (i = 0; i < sink_mconfig->max_in_queue; i++) { 911ce1b5551SJeeja KP if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) { 912ce1b5551SJeeja KP src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg; 913ce1b5551SJeeja KP if (!src_mconfig) 914ce1b5551SJeeja KP continue; 915d93f8e55SVinod Koul /* 916ce1b5551SJeeja KP * If path_found == 1, that means pmd for source 917ce1b5551SJeeja KP * pipe has not occurred, source is connected to 918ce1b5551SJeeja KP * some other sink. so its responsibility of sink 919ce1b5551SJeeja KP * to unbind itself from source. 920d93f8e55SVinod Koul */ 921d93f8e55SVinod Koul ret = skl_stop_pipe(ctx, src_mconfig->pipe); 922d93f8e55SVinod Koul if (ret < 0) 923d93f8e55SVinod Koul return ret; 924d93f8e55SVinod Koul 925ce1b5551SJeeja KP ret = skl_unbind_modules(ctx, 926ce1b5551SJeeja KP src_mconfig, sink_mconfig); 927ce1b5551SJeeja KP } 928d93f8e55SVinod Koul } 929d93f8e55SVinod Koul 930d93f8e55SVinod Koul return ret; 931d93f8e55SVinod Koul } 932d93f8e55SVinod Koul 933d93f8e55SVinod Koul /* 934d93f8e55SVinod Koul * in the Post-PMD event of mixer we need to do following: 935d93f8e55SVinod Koul * - Free the mcps used 936d93f8e55SVinod Koul * - Free the mem used 937d93f8e55SVinod Koul * - Unbind the modules within the pipeline 938d93f8e55SVinod Koul * - Delete the pipeline (modules are not required to be explicitly 939d93f8e55SVinod Koul * deleted, pipeline delete is enough here 940d93f8e55SVinod Koul */ 941d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, 942d93f8e55SVinod Koul struct skl *skl) 943d93f8e55SVinod Koul { 944d93f8e55SVinod Koul struct skl_module_cfg *mconfig = w->priv; 945d93f8e55SVinod Koul struct skl_pipe_module *w_module; 946d93f8e55SVinod Koul struct skl_module_cfg *src_module = NULL, *dst_module; 947d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 948d93f8e55SVinod Koul struct skl_pipe *s_pipe = mconfig->pipe; 949d93f8e55SVinod Koul int ret = 0; 950d93f8e55SVinod Koul 951*260eb73aSDharageswari R if (s_pipe->state == SKL_PIPE_INVALID) 952*260eb73aSDharageswari R return -EINVAL; 953*260eb73aSDharageswari R 954d93f8e55SVinod Koul skl_tplg_free_pipe_mcps(skl, mconfig); 95565976878SVinod Koul skl_tplg_free_pipe_mem(skl, mconfig); 956d93f8e55SVinod Koul 957d93f8e55SVinod Koul list_for_each_entry(w_module, &s_pipe->w_list, node) { 958d93f8e55SVinod Koul dst_module = w_module->w->priv; 959d93f8e55SVinod Koul 960*260eb73aSDharageswari R if (mconfig->m_state >= SKL_MODULE_INIT_DONE) 9617ae3cb15SVinod Koul skl_tplg_free_pipe_mcps(skl, dst_module); 962d93f8e55SVinod Koul if (src_module == NULL) { 963d93f8e55SVinod Koul src_module = dst_module; 964d93f8e55SVinod Koul continue; 965d93f8e55SVinod Koul } 966d93f8e55SVinod Koul 9677ca42f5aSGuneshwor Singh skl_unbind_modules(ctx, src_module, dst_module); 968d93f8e55SVinod Koul src_module = dst_module; 969d93f8e55SVinod Koul } 970d93f8e55SVinod Koul 971d93f8e55SVinod Koul ret = skl_delete_pipe(ctx, mconfig->pipe); 972d93f8e55SVinod Koul 9736c5768b3SDharageswari R return skl_tplg_unload_pipe_modules(ctx, s_pipe); 974d93f8e55SVinod Koul } 975d93f8e55SVinod Koul 976d93f8e55SVinod Koul /* 977d93f8e55SVinod Koul * in the Post-PMD event of PGA we need to do following: 978d93f8e55SVinod Koul * - Free the mcps used 979d93f8e55SVinod Koul * - Stop the pipeline 980d93f8e55SVinod Koul * - In source pipe is connected, unbind with source pipelines 981d93f8e55SVinod Koul */ 982d93f8e55SVinod Koul static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, 983d93f8e55SVinod Koul struct skl *skl) 984d93f8e55SVinod Koul { 985d93f8e55SVinod Koul struct skl_module_cfg *src_mconfig, *sink_mconfig; 986ce1b5551SJeeja KP int ret = 0, i; 987d93f8e55SVinod Koul struct skl_sst *ctx = skl->skl_sst; 988d93f8e55SVinod Koul 989ce1b5551SJeeja KP src_mconfig = w->priv; 990d93f8e55SVinod Koul 991d93f8e55SVinod Koul /* Stop the pipe since this is a mixin module */ 992d93f8e55SVinod Koul ret = skl_stop_pipe(ctx, src_mconfig->pipe); 993d93f8e55SVinod Koul if (ret) 994d93f8e55SVinod Koul return ret; 995d93f8e55SVinod Koul 996ce1b5551SJeeja KP for (i = 0; i < src_mconfig->max_out_queue; i++) { 997ce1b5551SJeeja KP if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) { 998ce1b5551SJeeja KP sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg; 999ce1b5551SJeeja KP if (!sink_mconfig) 1000ce1b5551SJeeja KP continue; 1001d93f8e55SVinod Koul /* 1002ce1b5551SJeeja KP * This is a connecter and if path is found that means 1003d93f8e55SVinod Koul * unbind between source and sink has not happened yet 1004d93f8e55SVinod Koul */ 1005ce1b5551SJeeja KP ret = skl_unbind_modules(ctx, src_mconfig, 1006ce1b5551SJeeja KP sink_mconfig); 1007ce1b5551SJeeja KP } 1008d93f8e55SVinod Koul } 1009d93f8e55SVinod Koul 1010d93f8e55SVinod Koul return ret; 1011d93f8e55SVinod Koul } 1012d93f8e55SVinod Koul 1013d93f8e55SVinod Koul /* 1014d93f8e55SVinod Koul * In modelling, we assume there will be ONLY one mixer in a pipeline. If 1015d93f8e55SVinod Koul * mixer is not required then it is treated as static mixer aka vmixer with 1016d93f8e55SVinod Koul * a hard path to source module 1017d93f8e55SVinod Koul * So we don't need to check if source is started or not as hard path puts 1018d93f8e55SVinod Koul * dependency on each other 1019d93f8e55SVinod Koul */ 1020d93f8e55SVinod Koul static int skl_tplg_vmixer_event(struct snd_soc_dapm_widget *w, 1021d93f8e55SVinod Koul struct snd_kcontrol *k, int event) 1022d93f8e55SVinod Koul { 1023d93f8e55SVinod Koul struct snd_soc_dapm_context *dapm = w->dapm; 1024d93f8e55SVinod Koul struct skl *skl = get_skl_ctx(dapm->dev); 1025d93f8e55SVinod Koul 1026d93f8e55SVinod Koul switch (event) { 1027d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMU: 1028d93f8e55SVinod Koul return skl_tplg_mixer_dapm_pre_pmu_event(w, skl); 1029d93f8e55SVinod Koul 1030de1fedf2SJeeja KP case SND_SOC_DAPM_POST_PMU: 1031de1fedf2SJeeja KP return skl_tplg_mixer_dapm_post_pmu_event(w, skl); 1032de1fedf2SJeeja KP 1033de1fedf2SJeeja KP case SND_SOC_DAPM_PRE_PMD: 1034de1fedf2SJeeja KP return skl_tplg_mixer_dapm_pre_pmd_event(w, skl); 1035de1fedf2SJeeja KP 1036d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMD: 1037d93f8e55SVinod Koul return skl_tplg_mixer_dapm_post_pmd_event(w, skl); 1038d93f8e55SVinod Koul } 1039d93f8e55SVinod Koul 1040d93f8e55SVinod Koul return 0; 1041d93f8e55SVinod Koul } 1042d93f8e55SVinod Koul 1043d93f8e55SVinod Koul /* 1044d93f8e55SVinod Koul * In modelling, we assume there will be ONLY one mixer in a pipeline. If a 1045d93f8e55SVinod Koul * second one is required that is created as another pipe entity. 1046d93f8e55SVinod Koul * The mixer is responsible for pipe management and represent a pipeline 1047d93f8e55SVinod Koul * instance 1048d93f8e55SVinod Koul */ 1049d93f8e55SVinod Koul static int skl_tplg_mixer_event(struct snd_soc_dapm_widget *w, 1050d93f8e55SVinod Koul struct snd_kcontrol *k, int event) 1051d93f8e55SVinod Koul { 1052d93f8e55SVinod Koul struct snd_soc_dapm_context *dapm = w->dapm; 1053d93f8e55SVinod Koul struct skl *skl = get_skl_ctx(dapm->dev); 1054d93f8e55SVinod Koul 1055d93f8e55SVinod Koul switch (event) { 1056d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMU: 1057d93f8e55SVinod Koul return skl_tplg_mixer_dapm_pre_pmu_event(w, skl); 1058d93f8e55SVinod Koul 1059d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMU: 1060d93f8e55SVinod Koul return skl_tplg_mixer_dapm_post_pmu_event(w, skl); 1061d93f8e55SVinod Koul 1062d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMD: 1063d93f8e55SVinod Koul return skl_tplg_mixer_dapm_pre_pmd_event(w, skl); 1064d93f8e55SVinod Koul 1065d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMD: 1066d93f8e55SVinod Koul return skl_tplg_mixer_dapm_post_pmd_event(w, skl); 1067d93f8e55SVinod Koul } 1068d93f8e55SVinod Koul 1069d93f8e55SVinod Koul return 0; 1070d93f8e55SVinod Koul } 1071d93f8e55SVinod Koul 1072d93f8e55SVinod Koul /* 1073d93f8e55SVinod Koul * In modelling, we assumed rest of the modules in pipeline are PGA. But we 1074d93f8e55SVinod Koul * are interested in last PGA (leaf PGA) in a pipeline to disconnect with 1075d93f8e55SVinod Koul * the sink when it is running (two FE to one BE or one FE to two BE) 1076d93f8e55SVinod Koul * scenarios 1077d93f8e55SVinod Koul */ 1078d93f8e55SVinod Koul static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w, 1079d93f8e55SVinod Koul struct snd_kcontrol *k, int event) 1080d93f8e55SVinod Koul 1081d93f8e55SVinod Koul { 1082d93f8e55SVinod Koul struct snd_soc_dapm_context *dapm = w->dapm; 1083d93f8e55SVinod Koul struct skl *skl = get_skl_ctx(dapm->dev); 1084d93f8e55SVinod Koul 1085d93f8e55SVinod Koul switch (event) { 1086d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMU: 1087d93f8e55SVinod Koul return skl_tplg_pga_dapm_pre_pmu_event(w, skl); 1088d93f8e55SVinod Koul 1089d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMD: 1090d93f8e55SVinod Koul return skl_tplg_pga_dapm_post_pmd_event(w, skl); 1091d93f8e55SVinod Koul } 1092d93f8e55SVinod Koul 1093d93f8e55SVinod Koul return 0; 1094d93f8e55SVinod Koul } 1095cfb0a873SVinod Koul 1096140adfbaSJeeja KP static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol, 1097140adfbaSJeeja KP unsigned int __user *data, unsigned int size) 1098140adfbaSJeeja KP { 1099140adfbaSJeeja KP struct soc_bytes_ext *sb = 1100140adfbaSJeeja KP (struct soc_bytes_ext *)kcontrol->private_value; 1101140adfbaSJeeja KP struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private; 11027d9f2911SOmair M Abdullah struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); 11037d9f2911SOmair M Abdullah struct skl_module_cfg *mconfig = w->priv; 11047d9f2911SOmair M Abdullah struct skl *skl = get_skl_ctx(w->dapm->dev); 11057d9f2911SOmair M Abdullah 11067d9f2911SOmair M Abdullah if (w->power) 11077d9f2911SOmair M Abdullah skl_get_module_params(skl->skl_sst, (u32 *)bc->params, 11087d9f2911SOmair M Abdullah bc->max, bc->param_id, mconfig); 1109140adfbaSJeeja KP 111041556f68SVinod Koul /* decrement size for TLV header */ 111141556f68SVinod Koul size -= 2 * sizeof(u32); 111241556f68SVinod Koul 111341556f68SVinod Koul /* check size as we don't want to send kernel data */ 111441556f68SVinod Koul if (size > bc->max) 111541556f68SVinod Koul size = bc->max; 111641556f68SVinod Koul 1117140adfbaSJeeja KP if (bc->params) { 1118140adfbaSJeeja KP if (copy_to_user(data, &bc->param_id, sizeof(u32))) 1119140adfbaSJeeja KP return -EFAULT; 1120e8bc3c99SDan Carpenter if (copy_to_user(data + 1, &size, sizeof(u32))) 1121140adfbaSJeeja KP return -EFAULT; 1122e8bc3c99SDan Carpenter if (copy_to_user(data + 2, bc->params, size)) 1123140adfbaSJeeja KP return -EFAULT; 1124140adfbaSJeeja KP } 1125140adfbaSJeeja KP 1126140adfbaSJeeja KP return 0; 1127140adfbaSJeeja KP } 1128140adfbaSJeeja KP 1129140adfbaSJeeja KP #define SKL_PARAM_VENDOR_ID 0xff 1130140adfbaSJeeja KP 1131140adfbaSJeeja KP static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol, 1132140adfbaSJeeja KP const unsigned int __user *data, unsigned int size) 1133140adfbaSJeeja KP { 1134140adfbaSJeeja KP struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); 1135140adfbaSJeeja KP struct skl_module_cfg *mconfig = w->priv; 1136140adfbaSJeeja KP struct soc_bytes_ext *sb = 1137140adfbaSJeeja KP (struct soc_bytes_ext *)kcontrol->private_value; 1138140adfbaSJeeja KP struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private; 1139140adfbaSJeeja KP struct skl *skl = get_skl_ctx(w->dapm->dev); 1140140adfbaSJeeja KP 1141140adfbaSJeeja KP if (ac->params) { 1142140adfbaSJeeja KP /* 1143140adfbaSJeeja KP * if the param_is is of type Vendor, firmware expects actual 1144140adfbaSJeeja KP * parameter id and size from the control. 1145140adfbaSJeeja KP */ 1146140adfbaSJeeja KP if (ac->param_id == SKL_PARAM_VENDOR_ID) { 1147140adfbaSJeeja KP if (copy_from_user(ac->params, data, size)) 1148140adfbaSJeeja KP return -EFAULT; 1149140adfbaSJeeja KP } else { 1150140adfbaSJeeja KP if (copy_from_user(ac->params, 115165b4bcb8SAlan data + 2, size)) 1152140adfbaSJeeja KP return -EFAULT; 1153140adfbaSJeeja KP } 1154140adfbaSJeeja KP 1155140adfbaSJeeja KP if (w->power) 1156140adfbaSJeeja KP return skl_set_module_params(skl->skl_sst, 1157140adfbaSJeeja KP (u32 *)ac->params, ac->max, 1158140adfbaSJeeja KP ac->param_id, mconfig); 1159140adfbaSJeeja KP } 1160140adfbaSJeeja KP 1161140adfbaSJeeja KP return 0; 1162140adfbaSJeeja KP } 1163140adfbaSJeeja KP 1164cfb0a873SVinod Koul /* 1165cfb0a873SVinod Koul * The FE params are passed by hw_params of the DAI. 1166cfb0a873SVinod Koul * On hw_params, the params are stored in Gateway module of the FE and we 1167cfb0a873SVinod Koul * need to calculate the format in DSP module configuration, that 1168cfb0a873SVinod Koul * conversion is done here 1169cfb0a873SVinod Koul */ 1170cfb0a873SVinod Koul int skl_tplg_update_pipe_params(struct device *dev, 1171cfb0a873SVinod Koul struct skl_module_cfg *mconfig, 1172cfb0a873SVinod Koul struct skl_pipe_params *params) 1173cfb0a873SVinod Koul { 1174cfb0a873SVinod Koul struct skl_pipe *pipe = mconfig->pipe; 1175cfb0a873SVinod Koul struct skl_module_fmt *format = NULL; 1176cfb0a873SVinod Koul 1177cfb0a873SVinod Koul memcpy(pipe->p_params, params, sizeof(*params)); 1178cfb0a873SVinod Koul 1179cfb0a873SVinod Koul if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) 11804cd9899fSHardik T Shah format = &mconfig->in_fmt[0]; 1181cfb0a873SVinod Koul else 11824cd9899fSHardik T Shah format = &mconfig->out_fmt[0]; 1183cfb0a873SVinod Koul 1184cfb0a873SVinod Koul /* set the hw_params */ 1185cfb0a873SVinod Koul format->s_freq = params->s_freq; 1186cfb0a873SVinod Koul format->channels = params->ch; 1187cfb0a873SVinod Koul format->valid_bit_depth = skl_get_bit_depth(params->s_fmt); 1188cfb0a873SVinod Koul 1189cfb0a873SVinod Koul /* 1190cfb0a873SVinod Koul * 16 bit is 16 bit container whereas 24 bit is in 32 bit 1191cfb0a873SVinod Koul * container so update bit depth accordingly 1192cfb0a873SVinod Koul */ 1193cfb0a873SVinod Koul switch (format->valid_bit_depth) { 1194cfb0a873SVinod Koul case SKL_DEPTH_16BIT: 1195cfb0a873SVinod Koul format->bit_depth = format->valid_bit_depth; 1196cfb0a873SVinod Koul break; 1197cfb0a873SVinod Koul 1198cfb0a873SVinod Koul case SKL_DEPTH_24BIT: 11996654f39eSJeeja KP case SKL_DEPTH_32BIT: 1200cfb0a873SVinod Koul format->bit_depth = SKL_DEPTH_32BIT; 1201cfb0a873SVinod Koul break; 1202cfb0a873SVinod Koul 1203cfb0a873SVinod Koul default: 1204cfb0a873SVinod Koul dev_err(dev, "Invalid bit depth %x for pipe\n", 1205cfb0a873SVinod Koul format->valid_bit_depth); 1206cfb0a873SVinod Koul return -EINVAL; 1207cfb0a873SVinod Koul } 1208cfb0a873SVinod Koul 1209cfb0a873SVinod Koul if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { 1210cfb0a873SVinod Koul mconfig->ibs = (format->s_freq / 1000) * 1211cfb0a873SVinod Koul (format->channels) * 1212cfb0a873SVinod Koul (format->bit_depth >> 3); 1213cfb0a873SVinod Koul } else { 1214cfb0a873SVinod Koul mconfig->obs = (format->s_freq / 1000) * 1215cfb0a873SVinod Koul (format->channels) * 1216cfb0a873SVinod Koul (format->bit_depth >> 3); 1217cfb0a873SVinod Koul } 1218cfb0a873SVinod Koul 1219cfb0a873SVinod Koul return 0; 1220cfb0a873SVinod Koul } 1221cfb0a873SVinod Koul 1222cfb0a873SVinod Koul /* 1223cfb0a873SVinod Koul * Query the module config for the FE DAI 1224cfb0a873SVinod Koul * This is used to find the hw_params set for that DAI and apply to FE 1225cfb0a873SVinod Koul * pipeline 1226cfb0a873SVinod Koul */ 1227cfb0a873SVinod Koul struct skl_module_cfg * 1228cfb0a873SVinod Koul skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream) 1229cfb0a873SVinod Koul { 1230cfb0a873SVinod Koul struct snd_soc_dapm_widget *w; 1231cfb0a873SVinod Koul struct snd_soc_dapm_path *p = NULL; 1232cfb0a873SVinod Koul 1233cfb0a873SVinod Koul if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 1234cfb0a873SVinod Koul w = dai->playback_widget; 1235f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_sink_path(w, p) { 1236cfb0a873SVinod Koul if (p->connect && p->sink->power && 1237a28f51dbSJeeja KP !is_skl_dsp_widget_type(p->sink)) 1238cfb0a873SVinod Koul continue; 1239cfb0a873SVinod Koul 1240cfb0a873SVinod Koul if (p->sink->priv) { 1241cfb0a873SVinod Koul dev_dbg(dai->dev, "set params for %s\n", 1242cfb0a873SVinod Koul p->sink->name); 1243cfb0a873SVinod Koul return p->sink->priv; 1244cfb0a873SVinod Koul } 1245cfb0a873SVinod Koul } 1246cfb0a873SVinod Koul } else { 1247cfb0a873SVinod Koul w = dai->capture_widget; 1248f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_source_path(w, p) { 1249cfb0a873SVinod Koul if (p->connect && p->source->power && 1250a28f51dbSJeeja KP !is_skl_dsp_widget_type(p->source)) 1251cfb0a873SVinod Koul continue; 1252cfb0a873SVinod Koul 1253cfb0a873SVinod Koul if (p->source->priv) { 1254cfb0a873SVinod Koul dev_dbg(dai->dev, "set params for %s\n", 1255cfb0a873SVinod Koul p->source->name); 1256cfb0a873SVinod Koul return p->source->priv; 1257cfb0a873SVinod Koul } 1258cfb0a873SVinod Koul } 1259cfb0a873SVinod Koul } 1260cfb0a873SVinod Koul 1261cfb0a873SVinod Koul return NULL; 1262cfb0a873SVinod Koul } 1263cfb0a873SVinod Koul 1264718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_pb_cpr( 1265718a42b5SDharageswari.R struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w) 1266718a42b5SDharageswari.R { 1267718a42b5SDharageswari.R struct snd_soc_dapm_path *p; 1268718a42b5SDharageswari.R struct skl_module_cfg *mconfig = NULL; 1269718a42b5SDharageswari.R 1270718a42b5SDharageswari.R snd_soc_dapm_widget_for_each_source_path(w, p) { 1271718a42b5SDharageswari.R if (w->endpoints[SND_SOC_DAPM_DIR_OUT] > 0) { 1272718a42b5SDharageswari.R if (p->connect && 1273718a42b5SDharageswari.R (p->sink->id == snd_soc_dapm_aif_out) && 1274718a42b5SDharageswari.R p->source->priv) { 1275718a42b5SDharageswari.R mconfig = p->source->priv; 1276718a42b5SDharageswari.R return mconfig; 1277718a42b5SDharageswari.R } 1278718a42b5SDharageswari.R mconfig = skl_get_mconfig_pb_cpr(dai, p->source); 1279718a42b5SDharageswari.R if (mconfig) 1280718a42b5SDharageswari.R return mconfig; 1281718a42b5SDharageswari.R } 1282718a42b5SDharageswari.R } 1283718a42b5SDharageswari.R return mconfig; 1284718a42b5SDharageswari.R } 1285718a42b5SDharageswari.R 1286718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_cap_cpr( 1287718a42b5SDharageswari.R struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w) 1288718a42b5SDharageswari.R { 1289718a42b5SDharageswari.R struct snd_soc_dapm_path *p; 1290718a42b5SDharageswari.R struct skl_module_cfg *mconfig = NULL; 1291718a42b5SDharageswari.R 1292718a42b5SDharageswari.R snd_soc_dapm_widget_for_each_sink_path(w, p) { 1293718a42b5SDharageswari.R if (w->endpoints[SND_SOC_DAPM_DIR_IN] > 0) { 1294718a42b5SDharageswari.R if (p->connect && 1295718a42b5SDharageswari.R (p->source->id == snd_soc_dapm_aif_in) && 1296718a42b5SDharageswari.R p->sink->priv) { 1297718a42b5SDharageswari.R mconfig = p->sink->priv; 1298718a42b5SDharageswari.R return mconfig; 1299718a42b5SDharageswari.R } 1300718a42b5SDharageswari.R mconfig = skl_get_mconfig_cap_cpr(dai, p->sink); 1301718a42b5SDharageswari.R if (mconfig) 1302718a42b5SDharageswari.R return mconfig; 1303718a42b5SDharageswari.R } 1304718a42b5SDharageswari.R } 1305718a42b5SDharageswari.R return mconfig; 1306718a42b5SDharageswari.R } 1307718a42b5SDharageswari.R 1308718a42b5SDharageswari.R struct skl_module_cfg * 1309718a42b5SDharageswari.R skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, int stream) 1310718a42b5SDharageswari.R { 1311718a42b5SDharageswari.R struct snd_soc_dapm_widget *w; 1312718a42b5SDharageswari.R struct skl_module_cfg *mconfig; 1313718a42b5SDharageswari.R 1314718a42b5SDharageswari.R if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 1315718a42b5SDharageswari.R w = dai->playback_widget; 1316718a42b5SDharageswari.R mconfig = skl_get_mconfig_pb_cpr(dai, w); 1317718a42b5SDharageswari.R } else { 1318718a42b5SDharageswari.R w = dai->capture_widget; 1319718a42b5SDharageswari.R mconfig = skl_get_mconfig_cap_cpr(dai, w); 1320718a42b5SDharageswari.R } 1321718a42b5SDharageswari.R return mconfig; 1322718a42b5SDharageswari.R } 1323718a42b5SDharageswari.R 1324cfb0a873SVinod Koul static u8 skl_tplg_be_link_type(int dev_type) 1325cfb0a873SVinod Koul { 1326cfb0a873SVinod Koul int ret; 1327cfb0a873SVinod Koul 1328cfb0a873SVinod Koul switch (dev_type) { 1329cfb0a873SVinod Koul case SKL_DEVICE_BT: 1330cfb0a873SVinod Koul ret = NHLT_LINK_SSP; 1331cfb0a873SVinod Koul break; 1332cfb0a873SVinod Koul 1333cfb0a873SVinod Koul case SKL_DEVICE_DMIC: 1334cfb0a873SVinod Koul ret = NHLT_LINK_DMIC; 1335cfb0a873SVinod Koul break; 1336cfb0a873SVinod Koul 1337cfb0a873SVinod Koul case SKL_DEVICE_I2S: 1338cfb0a873SVinod Koul ret = NHLT_LINK_SSP; 1339cfb0a873SVinod Koul break; 1340cfb0a873SVinod Koul 1341cfb0a873SVinod Koul case SKL_DEVICE_HDALINK: 1342cfb0a873SVinod Koul ret = NHLT_LINK_HDA; 1343cfb0a873SVinod Koul break; 1344cfb0a873SVinod Koul 1345cfb0a873SVinod Koul default: 1346cfb0a873SVinod Koul ret = NHLT_LINK_INVALID; 1347cfb0a873SVinod Koul break; 1348cfb0a873SVinod Koul } 1349cfb0a873SVinod Koul 1350cfb0a873SVinod Koul return ret; 1351cfb0a873SVinod Koul } 1352cfb0a873SVinod Koul 1353cfb0a873SVinod Koul /* 1354cfb0a873SVinod Koul * Fill the BE gateway parameters 1355cfb0a873SVinod Koul * The BE gateway expects a blob of parameters which are kept in the ACPI 1356cfb0a873SVinod Koul * NHLT blob, so query the blob for interface type (i2s/pdm) and instance. 1357cfb0a873SVinod Koul * The port can have multiple settings so pick based on the PCM 1358cfb0a873SVinod Koul * parameters 1359cfb0a873SVinod Koul */ 1360cfb0a873SVinod Koul static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai, 1361cfb0a873SVinod Koul struct skl_module_cfg *mconfig, 1362cfb0a873SVinod Koul struct skl_pipe_params *params) 1363cfb0a873SVinod Koul { 1364cfb0a873SVinod Koul struct skl_pipe *pipe = mconfig->pipe; 1365cfb0a873SVinod Koul struct nhlt_specific_cfg *cfg; 1366cfb0a873SVinod Koul struct skl *skl = get_skl_ctx(dai->dev); 1367cfb0a873SVinod Koul int link_type = skl_tplg_be_link_type(mconfig->dev_type); 1368cfb0a873SVinod Koul 1369cfb0a873SVinod Koul memcpy(pipe->p_params, params, sizeof(*params)); 1370cfb0a873SVinod Koul 1371b30c275eSJeeja KP if (link_type == NHLT_LINK_HDA) 1372b30c275eSJeeja KP return 0; 1373b30c275eSJeeja KP 1374cfb0a873SVinod Koul /* update the blob based on virtual bus_id*/ 1375cfb0a873SVinod Koul cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type, 1376cfb0a873SVinod Koul params->s_fmt, params->ch, 1377cfb0a873SVinod Koul params->s_freq, params->stream); 1378cfb0a873SVinod Koul if (cfg) { 1379cfb0a873SVinod Koul mconfig->formats_config.caps_size = cfg->size; 1380bc03281aSJeeja KP mconfig->formats_config.caps = (u32 *) &cfg->caps; 1381cfb0a873SVinod Koul } else { 1382cfb0a873SVinod Koul dev_err(dai->dev, "Blob NULL for id %x type %d dirn %d\n", 1383cfb0a873SVinod Koul mconfig->vbus_id, link_type, 1384cfb0a873SVinod Koul params->stream); 1385cfb0a873SVinod Koul dev_err(dai->dev, "PCM: ch %d, freq %d, fmt %d\n", 1386cfb0a873SVinod Koul params->ch, params->s_freq, params->s_fmt); 1387cfb0a873SVinod Koul return -EINVAL; 1388cfb0a873SVinod Koul } 1389cfb0a873SVinod Koul 1390cfb0a873SVinod Koul return 0; 1391cfb0a873SVinod Koul } 1392cfb0a873SVinod Koul 1393cfb0a873SVinod Koul static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai, 1394cfb0a873SVinod Koul struct snd_soc_dapm_widget *w, 1395cfb0a873SVinod Koul struct skl_pipe_params *params) 1396cfb0a873SVinod Koul { 1397cfb0a873SVinod Koul struct snd_soc_dapm_path *p; 13984d8adccbSSubhransu S. Prusty int ret = -EIO; 1399cfb0a873SVinod Koul 1400f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_source_path(w, p) { 1401cfb0a873SVinod Koul if (p->connect && is_skl_dsp_widget_type(p->source) && 1402cfb0a873SVinod Koul p->source->priv) { 1403cfb0a873SVinod Koul 14049a03cb49SJeeja KP ret = skl_tplg_be_fill_pipe_params(dai, 14059a03cb49SJeeja KP p->source->priv, params); 14064d8adccbSSubhransu S. Prusty if (ret < 0) 14074d8adccbSSubhransu S. Prusty return ret; 1408cfb0a873SVinod Koul } else { 14099a03cb49SJeeja KP ret = skl_tplg_be_set_src_pipe_params(dai, 14109a03cb49SJeeja KP p->source, params); 14114d8adccbSSubhransu S. Prusty if (ret < 0) 14124d8adccbSSubhransu S. Prusty return ret; 1413cfb0a873SVinod Koul } 1414cfb0a873SVinod Koul } 1415cfb0a873SVinod Koul 14164d8adccbSSubhransu S. Prusty return ret; 1417cfb0a873SVinod Koul } 1418cfb0a873SVinod Koul 1419cfb0a873SVinod Koul static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai, 1420cfb0a873SVinod Koul struct snd_soc_dapm_widget *w, struct skl_pipe_params *params) 1421cfb0a873SVinod Koul { 1422cfb0a873SVinod Koul struct snd_soc_dapm_path *p = NULL; 14234d8adccbSSubhransu S. Prusty int ret = -EIO; 1424cfb0a873SVinod Koul 1425f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_sink_path(w, p) { 1426cfb0a873SVinod Koul if (p->connect && is_skl_dsp_widget_type(p->sink) && 1427cfb0a873SVinod Koul p->sink->priv) { 1428cfb0a873SVinod Koul 14299a03cb49SJeeja KP ret = skl_tplg_be_fill_pipe_params(dai, 14309a03cb49SJeeja KP p->sink->priv, params); 14314d8adccbSSubhransu S. Prusty if (ret < 0) 14324d8adccbSSubhransu S. Prusty return ret; 14334d8adccbSSubhransu S. Prusty } else { 14344d8adccbSSubhransu S. Prusty ret = skl_tplg_be_set_sink_pipe_params( 1435cfb0a873SVinod Koul dai, p->sink, params); 14364d8adccbSSubhransu S. Prusty if (ret < 0) 14374d8adccbSSubhransu S. Prusty return ret; 1438cfb0a873SVinod Koul } 1439cfb0a873SVinod Koul } 1440cfb0a873SVinod Koul 14414d8adccbSSubhransu S. Prusty return ret; 1442cfb0a873SVinod Koul } 1443cfb0a873SVinod Koul 1444cfb0a873SVinod Koul /* 1445cfb0a873SVinod Koul * BE hw_params can be a source parameters (capture) or sink parameters 1446cfb0a873SVinod Koul * (playback). Based on sink and source we need to either find the source 1447cfb0a873SVinod Koul * list or the sink list and set the pipeline parameters 1448cfb0a873SVinod Koul */ 1449cfb0a873SVinod Koul int skl_tplg_be_update_params(struct snd_soc_dai *dai, 1450cfb0a873SVinod Koul struct skl_pipe_params *params) 1451cfb0a873SVinod Koul { 1452cfb0a873SVinod Koul struct snd_soc_dapm_widget *w; 1453cfb0a873SVinod Koul 1454cfb0a873SVinod Koul if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { 1455cfb0a873SVinod Koul w = dai->playback_widget; 1456cfb0a873SVinod Koul 1457cfb0a873SVinod Koul return skl_tplg_be_set_src_pipe_params(dai, w, params); 1458cfb0a873SVinod Koul 1459cfb0a873SVinod Koul } else { 1460cfb0a873SVinod Koul w = dai->capture_widget; 1461cfb0a873SVinod Koul 1462cfb0a873SVinod Koul return skl_tplg_be_set_sink_pipe_params(dai, w, params); 1463cfb0a873SVinod Koul } 1464cfb0a873SVinod Koul 1465cfb0a873SVinod Koul return 0; 1466cfb0a873SVinod Koul } 14673af36706SVinod Koul 14683af36706SVinod Koul static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = { 14693af36706SVinod Koul {SKL_MIXER_EVENT, skl_tplg_mixer_event}, 14703af36706SVinod Koul {SKL_VMIXER_EVENT, skl_tplg_vmixer_event}, 14713af36706SVinod Koul {SKL_PGA_EVENT, skl_tplg_pga_event}, 14723af36706SVinod Koul }; 14733af36706SVinod Koul 1474140adfbaSJeeja KP static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = { 1475140adfbaSJeeja KP {SKL_CONTROL_TYPE_BYTE_TLV, skl_tplg_tlv_control_get, 1476140adfbaSJeeja KP skl_tplg_tlv_control_set}, 1477140adfbaSJeeja KP }; 1478140adfbaSJeeja KP 14793af36706SVinod Koul /* 14803af36706SVinod Koul * The topology binary passes the pin info for a module so initialize the pin 14813af36706SVinod Koul * info passed into module instance 14823af36706SVinod Koul */ 14836abca1d7SJeeja KP static void skl_fill_module_pin_info(struct skl_dfw_module_pin *dfw_pin, 14843af36706SVinod Koul struct skl_module_pin *m_pin, 14856abca1d7SJeeja KP bool is_dynamic, int max_pin) 14863af36706SVinod Koul { 14873af36706SVinod Koul int i; 14883af36706SVinod Koul 14893af36706SVinod Koul for (i = 0; i < max_pin; i++) { 14906abca1d7SJeeja KP m_pin[i].id.module_id = dfw_pin[i].module_id; 14916abca1d7SJeeja KP m_pin[i].id.instance_id = dfw_pin[i].instance_id; 14923af36706SVinod Koul m_pin[i].in_use = false; 14936abca1d7SJeeja KP m_pin[i].is_dynamic = is_dynamic; 14944f745708SJeeja KP m_pin[i].pin_state = SKL_PIN_UNBIND; 14953af36706SVinod Koul } 14963af36706SVinod Koul } 14973af36706SVinod Koul 14983af36706SVinod Koul /* 14993af36706SVinod Koul * Add pipeline from topology binary into driver pipeline list 15003af36706SVinod Koul * 15013af36706SVinod Koul * If already added we return that instance 15023af36706SVinod Koul * Otherwise we create a new instance and add into driver list 15033af36706SVinod Koul */ 15043af36706SVinod Koul static struct skl_pipe *skl_tplg_add_pipe(struct device *dev, 15053af36706SVinod Koul struct skl *skl, struct skl_dfw_pipe *dfw_pipe) 15063af36706SVinod Koul { 15073af36706SVinod Koul struct skl_pipeline *ppl; 15083af36706SVinod Koul struct skl_pipe *pipe; 15093af36706SVinod Koul struct skl_pipe_params *params; 15103af36706SVinod Koul 15113af36706SVinod Koul list_for_each_entry(ppl, &skl->ppl_list, node) { 15123af36706SVinod Koul if (ppl->pipe->ppl_id == dfw_pipe->pipe_id) 15133af36706SVinod Koul return ppl->pipe; 15143af36706SVinod Koul } 15153af36706SVinod Koul 15163af36706SVinod Koul ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL); 15173af36706SVinod Koul if (!ppl) 15183af36706SVinod Koul return NULL; 15193af36706SVinod Koul 15203af36706SVinod Koul pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL); 15213af36706SVinod Koul if (!pipe) 15223af36706SVinod Koul return NULL; 15233af36706SVinod Koul 15243af36706SVinod Koul params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL); 15253af36706SVinod Koul if (!params) 15263af36706SVinod Koul return NULL; 15273af36706SVinod Koul 15283af36706SVinod Koul pipe->ppl_id = dfw_pipe->pipe_id; 15293af36706SVinod Koul pipe->memory_pages = dfw_pipe->memory_pages; 15303af36706SVinod Koul pipe->pipe_priority = dfw_pipe->pipe_priority; 15313af36706SVinod Koul pipe->conn_type = dfw_pipe->conn_type; 15323af36706SVinod Koul pipe->state = SKL_PIPE_INVALID; 15333af36706SVinod Koul pipe->p_params = params; 15343af36706SVinod Koul INIT_LIST_HEAD(&pipe->w_list); 15353af36706SVinod Koul 15363af36706SVinod Koul ppl->pipe = pipe; 15373af36706SVinod Koul list_add(&ppl->node, &skl->ppl_list); 15383af36706SVinod Koul 15393af36706SVinod Koul return ppl->pipe; 15403af36706SVinod Koul } 15413af36706SVinod Koul 15424cd9899fSHardik T Shah static void skl_tplg_fill_fmt(struct skl_module_fmt *dst_fmt, 15434cd9899fSHardik T Shah struct skl_dfw_module_fmt *src_fmt, 15444cd9899fSHardik T Shah int pins) 15454cd9899fSHardik T Shah { 15464cd9899fSHardik T Shah int i; 15474cd9899fSHardik T Shah 15484cd9899fSHardik T Shah for (i = 0; i < pins; i++) { 15494cd9899fSHardik T Shah dst_fmt[i].channels = src_fmt[i].channels; 15504cd9899fSHardik T Shah dst_fmt[i].s_freq = src_fmt[i].freq; 15514cd9899fSHardik T Shah dst_fmt[i].bit_depth = src_fmt[i].bit_depth; 15524cd9899fSHardik T Shah dst_fmt[i].valid_bit_depth = src_fmt[i].valid_bit_depth; 15534cd9899fSHardik T Shah dst_fmt[i].ch_cfg = src_fmt[i].ch_cfg; 15544cd9899fSHardik T Shah dst_fmt[i].ch_map = src_fmt[i].ch_map; 15554cd9899fSHardik T Shah dst_fmt[i].interleaving_style = src_fmt[i].interleaving_style; 15564cd9899fSHardik T Shah dst_fmt[i].sample_type = src_fmt[i].sample_type; 15574cd9899fSHardik T Shah } 15584cd9899fSHardik T Shah } 15594cd9899fSHardik T Shah 15603af36706SVinod Koul /* 15613af36706SVinod Koul * Topology core widget load callback 15623af36706SVinod Koul * 15633af36706SVinod Koul * This is used to save the private data for each widget which gives 15643af36706SVinod Koul * information to the driver about module and pipeline parameters which DSP 15653af36706SVinod Koul * FW expects like ids, resource values, formats etc 15663af36706SVinod Koul */ 15673af36706SVinod Koul static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, 15683af36706SVinod Koul struct snd_soc_dapm_widget *w, 15693af36706SVinod Koul struct snd_soc_tplg_dapm_widget *tplg_w) 15703af36706SVinod Koul { 15713af36706SVinod Koul int ret; 15723af36706SVinod Koul struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt); 15733af36706SVinod Koul struct skl *skl = ebus_to_skl(ebus); 15743af36706SVinod Koul struct hdac_bus *bus = ebus_to_hbus(ebus); 15753af36706SVinod Koul struct skl_module_cfg *mconfig; 15763af36706SVinod Koul struct skl_pipe *pipe; 1577b663a8c5SJeeja KP struct skl_dfw_module *dfw_config = 1578b663a8c5SJeeja KP (struct skl_dfw_module *)tplg_w->priv.data; 15793af36706SVinod Koul 15803af36706SVinod Koul if (!tplg_w->priv.size) 15813af36706SVinod Koul goto bind_event; 15823af36706SVinod Koul 15833af36706SVinod Koul mconfig = devm_kzalloc(bus->dev, sizeof(*mconfig), GFP_KERNEL); 15843af36706SVinod Koul 15853af36706SVinod Koul if (!mconfig) 15863af36706SVinod Koul return -ENOMEM; 15873af36706SVinod Koul 15883af36706SVinod Koul w->priv = mconfig; 158909305da9SShreyas NC memcpy(&mconfig->guid, &dfw_config->uuid, 16); 159009305da9SShreyas NC 1591ea6b3e94SShreyas NC ret = snd_skl_get_module_info(skl->skl_sst, mconfig->guid, dfw_config); 1592ea6b3e94SShreyas NC if (ret < 0) 1593ea6b3e94SShreyas NC return ret; 1594ea6b3e94SShreyas NC 15953af36706SVinod Koul mconfig->id.module_id = dfw_config->module_id; 15963af36706SVinod Koul mconfig->id.instance_id = dfw_config->instance_id; 15973af36706SVinod Koul mconfig->mcps = dfw_config->max_mcps; 15983af36706SVinod Koul mconfig->ibs = dfw_config->ibs; 15993af36706SVinod Koul mconfig->obs = dfw_config->obs; 16003af36706SVinod Koul mconfig->core_id = dfw_config->core_id; 16013af36706SVinod Koul mconfig->max_in_queue = dfw_config->max_in_queue; 16023af36706SVinod Koul mconfig->max_out_queue = dfw_config->max_out_queue; 16033af36706SVinod Koul mconfig->is_loadable = dfw_config->is_loadable; 16044cd9899fSHardik T Shah skl_tplg_fill_fmt(mconfig->in_fmt, dfw_config->in_fmt, 16054cd9899fSHardik T Shah MODULE_MAX_IN_PINS); 16064cd9899fSHardik T Shah skl_tplg_fill_fmt(mconfig->out_fmt, dfw_config->out_fmt, 16074cd9899fSHardik T Shah MODULE_MAX_OUT_PINS); 16084cd9899fSHardik T Shah 16093af36706SVinod Koul mconfig->params_fixup = dfw_config->params_fixup; 16103af36706SVinod Koul mconfig->converter = dfw_config->converter; 16113af36706SVinod Koul mconfig->m_type = dfw_config->module_type; 16123af36706SVinod Koul mconfig->vbus_id = dfw_config->vbus_id; 1613b18c458dSJeeja KP mconfig->mem_pages = dfw_config->mem_pages; 16143af36706SVinod Koul 16153af36706SVinod Koul pipe = skl_tplg_add_pipe(bus->dev, skl, &dfw_config->pipe); 16163af36706SVinod Koul if (pipe) 16173af36706SVinod Koul mconfig->pipe = pipe; 16183af36706SVinod Koul 16193af36706SVinod Koul mconfig->dev_type = dfw_config->dev_type; 16203af36706SVinod Koul mconfig->hw_conn_type = dfw_config->hw_conn_type; 16213af36706SVinod Koul mconfig->time_slot = dfw_config->time_slot; 16223af36706SVinod Koul mconfig->formats_config.caps_size = dfw_config->caps.caps_size; 16233af36706SVinod Koul 16244cd9899fSHardik T Shah mconfig->m_in_pin = devm_kzalloc(bus->dev, (mconfig->max_in_queue) * 16253af36706SVinod Koul sizeof(*mconfig->m_in_pin), 16263af36706SVinod Koul GFP_KERNEL); 16273af36706SVinod Koul if (!mconfig->m_in_pin) 16283af36706SVinod Koul return -ENOMEM; 16293af36706SVinod Koul 16306abca1d7SJeeja KP mconfig->m_out_pin = devm_kzalloc(bus->dev, (mconfig->max_out_queue) * 16313af36706SVinod Koul sizeof(*mconfig->m_out_pin), 16323af36706SVinod Koul GFP_KERNEL); 16333af36706SVinod Koul if (!mconfig->m_out_pin) 16343af36706SVinod Koul return -ENOMEM; 16353af36706SVinod Koul 16366abca1d7SJeeja KP skl_fill_module_pin_info(dfw_config->in_pin, mconfig->m_in_pin, 16376abca1d7SJeeja KP dfw_config->is_dynamic_in_pin, 16383af36706SVinod Koul mconfig->max_in_queue); 16396abca1d7SJeeja KP 16406abca1d7SJeeja KP skl_fill_module_pin_info(dfw_config->out_pin, mconfig->m_out_pin, 16416abca1d7SJeeja KP dfw_config->is_dynamic_out_pin, 16423af36706SVinod Koul mconfig->max_out_queue); 16433af36706SVinod Koul 16446abca1d7SJeeja KP 16453af36706SVinod Koul if (mconfig->formats_config.caps_size == 0) 16463af36706SVinod Koul goto bind_event; 16473af36706SVinod Koul 16483af36706SVinod Koul mconfig->formats_config.caps = (u32 *)devm_kzalloc(bus->dev, 16493af36706SVinod Koul mconfig->formats_config.caps_size, GFP_KERNEL); 16503af36706SVinod Koul 16513af36706SVinod Koul if (mconfig->formats_config.caps == NULL) 16523af36706SVinod Koul return -ENOMEM; 16533af36706SVinod Koul 16543af36706SVinod Koul memcpy(mconfig->formats_config.caps, dfw_config->caps.caps, 16553af36706SVinod Koul dfw_config->caps.caps_size); 1656abb74003SJeeja KP mconfig->formats_config.param_id = dfw_config->caps.param_id; 1657abb74003SJeeja KP mconfig->formats_config.set_params = dfw_config->caps.set_params; 16583af36706SVinod Koul 16593af36706SVinod Koul bind_event: 16603af36706SVinod Koul if (tplg_w->event_type == 0) { 16613373f716SVinod Koul dev_dbg(bus->dev, "ASoC: No event handler required\n"); 16623af36706SVinod Koul return 0; 16633af36706SVinod Koul } 16643af36706SVinod Koul 16653af36706SVinod Koul ret = snd_soc_tplg_widget_bind_event(w, skl_tplg_widget_ops, 1666b663a8c5SJeeja KP ARRAY_SIZE(skl_tplg_widget_ops), 1667b663a8c5SJeeja KP tplg_w->event_type); 16683af36706SVinod Koul 16693af36706SVinod Koul if (ret) { 16703af36706SVinod Koul dev_err(bus->dev, "%s: No matching event handlers found for %d\n", 16713af36706SVinod Koul __func__, tplg_w->event_type); 16723af36706SVinod Koul return -EINVAL; 16733af36706SVinod Koul } 16743af36706SVinod Koul 16753af36706SVinod Koul return 0; 16763af36706SVinod Koul } 16773af36706SVinod Koul 1678140adfbaSJeeja KP static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be, 1679140adfbaSJeeja KP struct snd_soc_tplg_bytes_control *bc) 1680140adfbaSJeeja KP { 1681140adfbaSJeeja KP struct skl_algo_data *ac; 1682140adfbaSJeeja KP struct skl_dfw_algo_data *dfw_ac = 1683140adfbaSJeeja KP (struct skl_dfw_algo_data *)bc->priv.data; 1684140adfbaSJeeja KP 1685140adfbaSJeeja KP ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL); 1686140adfbaSJeeja KP if (!ac) 1687140adfbaSJeeja KP return -ENOMEM; 1688140adfbaSJeeja KP 1689140adfbaSJeeja KP /* Fill private data */ 1690140adfbaSJeeja KP ac->max = dfw_ac->max; 1691140adfbaSJeeja KP ac->param_id = dfw_ac->param_id; 1692140adfbaSJeeja KP ac->set_params = dfw_ac->set_params; 1693140adfbaSJeeja KP 1694140adfbaSJeeja KP if (ac->max) { 1695140adfbaSJeeja KP ac->params = (char *) devm_kzalloc(dev, ac->max, GFP_KERNEL); 1696140adfbaSJeeja KP if (!ac->params) 1697140adfbaSJeeja KP return -ENOMEM; 1698140adfbaSJeeja KP 1699140adfbaSJeeja KP memcpy(ac->params, dfw_ac->params, ac->max); 1700140adfbaSJeeja KP } 1701140adfbaSJeeja KP 1702140adfbaSJeeja KP be->dobj.private = ac; 1703140adfbaSJeeja KP return 0; 1704140adfbaSJeeja KP } 1705140adfbaSJeeja KP 1706140adfbaSJeeja KP static int skl_tplg_control_load(struct snd_soc_component *cmpnt, 1707140adfbaSJeeja KP struct snd_kcontrol_new *kctl, 1708140adfbaSJeeja KP struct snd_soc_tplg_ctl_hdr *hdr) 1709140adfbaSJeeja KP { 1710140adfbaSJeeja KP struct soc_bytes_ext *sb; 1711140adfbaSJeeja KP struct snd_soc_tplg_bytes_control *tplg_bc; 1712140adfbaSJeeja KP struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt); 1713140adfbaSJeeja KP struct hdac_bus *bus = ebus_to_hbus(ebus); 1714140adfbaSJeeja KP 1715140adfbaSJeeja KP switch (hdr->ops.info) { 1716140adfbaSJeeja KP case SND_SOC_TPLG_CTL_BYTES: 1717140adfbaSJeeja KP tplg_bc = container_of(hdr, 1718140adfbaSJeeja KP struct snd_soc_tplg_bytes_control, hdr); 1719140adfbaSJeeja KP if (kctl->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 1720140adfbaSJeeja KP sb = (struct soc_bytes_ext *)kctl->private_value; 1721140adfbaSJeeja KP if (tplg_bc->priv.size) 1722140adfbaSJeeja KP return skl_init_algo_data( 1723140adfbaSJeeja KP bus->dev, sb, tplg_bc); 1724140adfbaSJeeja KP } 1725140adfbaSJeeja KP break; 1726140adfbaSJeeja KP 1727140adfbaSJeeja KP default: 1728140adfbaSJeeja KP dev_warn(bus->dev, "Control load not supported %d:%d:%d\n", 1729140adfbaSJeeja KP hdr->ops.get, hdr->ops.put, hdr->ops.info); 1730140adfbaSJeeja KP break; 1731140adfbaSJeeja KP } 1732140adfbaSJeeja KP 1733140adfbaSJeeja KP return 0; 1734140adfbaSJeeja KP } 1735140adfbaSJeeja KP 17363af36706SVinod Koul static struct snd_soc_tplg_ops skl_tplg_ops = { 17373af36706SVinod Koul .widget_load = skl_tplg_widget_load, 1738140adfbaSJeeja KP .control_load = skl_tplg_control_load, 1739140adfbaSJeeja KP .bytes_ext_ops = skl_tlv_ops, 1740140adfbaSJeeja KP .bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops), 17413af36706SVinod Koul }; 17423af36706SVinod Koul 17433af36706SVinod Koul /* This will be read from topology manifest, currently defined here */ 17443af36706SVinod Koul #define SKL_MAX_MCPS 30000000 17453af36706SVinod Koul #define SKL_FW_MAX_MEM 1000000 17463af36706SVinod Koul 17473af36706SVinod Koul /* 17483af36706SVinod Koul * SKL topology init routine 17493af36706SVinod Koul */ 17503af36706SVinod Koul int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus) 17513af36706SVinod Koul { 17523af36706SVinod Koul int ret; 17533af36706SVinod Koul const struct firmware *fw; 17543af36706SVinod Koul struct hdac_bus *bus = ebus_to_hbus(ebus); 17553af36706SVinod Koul struct skl *skl = ebus_to_skl(ebus); 17563af36706SVinod Koul 17574b235c43SVinod Koul ret = request_firmware(&fw, skl->tplg_name, bus->dev); 17583af36706SVinod Koul if (ret < 0) { 1759b663a8c5SJeeja KP dev_err(bus->dev, "tplg fw %s load failed with %d\n", 17604b235c43SVinod Koul skl->tplg_name, ret); 17614b235c43SVinod Koul ret = request_firmware(&fw, "dfw_sst.bin", bus->dev); 17624b235c43SVinod Koul if (ret < 0) { 17634b235c43SVinod Koul dev_err(bus->dev, "Fallback tplg fw %s load failed with %d\n", 17643af36706SVinod Koul "dfw_sst.bin", ret); 17653af36706SVinod Koul return ret; 17663af36706SVinod Koul } 17674b235c43SVinod Koul } 17683af36706SVinod Koul 17693af36706SVinod Koul /* 17703af36706SVinod Koul * The complete tplg for SKL is loaded as index 0, we don't use 17713af36706SVinod Koul * any other index 17723af36706SVinod Koul */ 1773b663a8c5SJeeja KP ret = snd_soc_tplg_component_load(&platform->component, 1774b663a8c5SJeeja KP &skl_tplg_ops, fw, 0); 17753af36706SVinod Koul if (ret < 0) { 17763af36706SVinod Koul dev_err(bus->dev, "tplg component load failed%d\n", ret); 1777c14a82c7SSudip Mukherjee release_firmware(fw); 17783af36706SVinod Koul return -EINVAL; 17793af36706SVinod Koul } 17803af36706SVinod Koul 17813af36706SVinod Koul skl->resource.max_mcps = SKL_MAX_MCPS; 17823af36706SVinod Koul skl->resource.max_mem = SKL_FW_MAX_MEM; 17833af36706SVinod Koul 1784d8018361SVinod Koul skl->tplg = fw; 1785d8018361SVinod Koul 17863af36706SVinod Koul return 0; 17873af36706SVinod Koul } 1788