diff options
Diffstat (limited to 'sound/soc/intel/skylake/skl-topology.c')
-rw-r--r-- | sound/soc/intel/skylake/skl-topology.c | 3605 |
1 files changed, 0 insertions, 3605 deletions
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c deleted file mode 100644 index 602ef4321122..000000000000 --- a/sound/soc/intel/skylake/skl-topology.c +++ /dev/null @@ -1,3605 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * skl-topology.c - Implements Platform component ALSA controls/widget - * handlers. - * - * Copyright (C) 2014-2015 Intel Corp - * Author: Jeeja KP <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#include <linux/slab.h> -#include <linux/types.h> -#include <linux/firmware.h> -#include <linux/uuid.h> -#include <sound/intel-nhlt.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include <sound/soc-topology.h> -#include <uapi/sound/snd_sst_tokens.h> -#include <uapi/sound/skl-tplg-interface.h> -#include "skl-sst-dsp.h" -#include "skl-sst-ipc.h" -#include "skl-topology.h" -#include "skl.h" -#include "../common/sst-dsp.h" -#include "../common/sst-dsp-priv.h" - -#define SKL_CH_FIXUP_MASK (1 << 0) -#define SKL_RATE_FIXUP_MASK (1 << 1) -#define SKL_FMT_FIXUP_MASK (1 << 2) -#define SKL_IN_DIR_BIT_MASK BIT(0) -#define SKL_PIN_COUNT_MASK GENMASK(7, 4) - -static const int mic_mono_list[] = { -0, 1, 2, 3, -}; -static const int mic_stereo_list[][SKL_CH_STEREO] = { -{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}, -}; -static const int mic_trio_list[][SKL_CH_TRIO] = { -{0, 1, 2}, {0, 1, 3}, {0, 2, 3}, {1, 2, 3}, -}; -static const int mic_quatro_list[][SKL_CH_QUATRO] = { -{0, 1, 2, 3}, -}; - -#define CHECK_HW_PARAMS(ch, freq, bps, prm_ch, prm_freq, prm_bps) \ - ((ch == prm_ch) && (bps == prm_bps) && (freq == prm_freq)) - -void skl_tplg_d0i3_get(struct skl_dev *skl, enum d0i3_capability caps) -{ - struct skl_d0i3_data *d0i3 = &skl->d0i3; - - switch (caps) { - case SKL_D0I3_NONE: - d0i3->non_d0i3++; - break; - - case SKL_D0I3_STREAMING: - d0i3->streaming++; - break; - - case SKL_D0I3_NON_STREAMING: - d0i3->non_streaming++; - break; - } -} - -void skl_tplg_d0i3_put(struct skl_dev *skl, enum d0i3_capability caps) -{ - struct skl_d0i3_data *d0i3 = &skl->d0i3; - - switch (caps) { - case SKL_D0I3_NONE: - d0i3->non_d0i3--; - break; - - case SKL_D0I3_STREAMING: - d0i3->streaming--; - break; - - case SKL_D0I3_NON_STREAMING: - d0i3->non_streaming--; - break; - } -} - -/* - * SKL DSP driver modelling uses only few DAPM widgets so for rest we will - * ignore. This helpers checks if the SKL driver handles this widget type - */ -static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w, - struct device *dev) -{ - if (w->dapm->dev != dev) - return false; - - switch (w->id) { - case snd_soc_dapm_dai_link: - case snd_soc_dapm_dai_in: - case snd_soc_dapm_aif_in: - case snd_soc_dapm_aif_out: - case snd_soc_dapm_dai_out: - case snd_soc_dapm_switch: - case snd_soc_dapm_output: - case snd_soc_dapm_mux: - - return false; - default: - return true; - } -} - -static void skl_dump_mconfig(struct skl_dev *skl, struct skl_module_cfg *mcfg) -{ - struct skl_module_iface *iface = &mcfg->module->formats[mcfg->fmt_idx]; - - dev_dbg(skl->dev, "Dumping config\n"); - dev_dbg(skl->dev, "Input Format:\n"); - dev_dbg(skl->dev, "channels = %d\n", iface->inputs[0].fmt.channels); - dev_dbg(skl->dev, "s_freq = %d\n", iface->inputs[0].fmt.s_freq); - dev_dbg(skl->dev, "ch_cfg = %d\n", iface->inputs[0].fmt.ch_cfg); - dev_dbg(skl->dev, "valid bit depth = %d\n", - iface->inputs[0].fmt.valid_bit_depth); - dev_dbg(skl->dev, "Output Format:\n"); - dev_dbg(skl->dev, "channels = %d\n", iface->outputs[0].fmt.channels); - dev_dbg(skl->dev, "s_freq = %d\n", iface->outputs[0].fmt.s_freq); - dev_dbg(skl->dev, "valid bit depth = %d\n", - iface->outputs[0].fmt.valid_bit_depth); - dev_dbg(skl->dev, "ch_cfg = %d\n", iface->outputs[0].fmt.ch_cfg); -} - -static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs) -{ - int slot_map = 0xFFFFFFFF; - int start_slot = 0; - int i; - - for (i = 0; i < chs; i++) { - /* - * For 2 channels with starting slot as 0, slot map will - * look like 0xFFFFFF10. - */ - slot_map &= (~(0xF << (4 * i)) | (start_slot << (4 * i))); - start_slot++; - } - fmt->ch_map = slot_map; -} - -static void skl_tplg_update_params(struct skl_module_fmt *fmt, - struct skl_pipe_params *params, int fixup) -{ - if (fixup & SKL_RATE_FIXUP_MASK) - fmt->s_freq = params->s_freq; - if (fixup & SKL_CH_FIXUP_MASK) { - fmt->channels = params->ch; - skl_tplg_update_chmap(fmt, fmt->channels); - } - if (fixup & SKL_FMT_FIXUP_MASK) { - fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt); - - /* - * 16 bit is 16 bit container whereas 24 bit is in 32 bit - * container so update bit depth accordingly - */ - switch (fmt->valid_bit_depth) { - case SKL_DEPTH_16BIT: - fmt->bit_depth = fmt->valid_bit_depth; - break; - - default: - fmt->bit_depth = SKL_DEPTH_32BIT; - break; - } - } - -} - -/* - * A pipeline may have modules which impact the pcm parameters, like SRC, - * channel converter, format converter. - * We need to calculate the output params by applying the 'fixup' - * Topology will tell driver which type of fixup is to be applied by - * supplying the fixup mask, so based on that we calculate the output - * - * Now In FE the pcm hw_params is source/target format. Same is applicable - * for BE with its hw_params invoked. - * here based on FE, BE pipeline and direction we calculate the input and - * outfix and then apply that for a module - */ -static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg, - struct skl_pipe_params *params, bool is_fe) -{ - int in_fixup, out_fixup; - struct skl_module_fmt *in_fmt, *out_fmt; - - /* Fixups will be applied to pin 0 only */ - in_fmt = &m_cfg->module->formats[m_cfg->fmt_idx].inputs[0].fmt; - out_fmt = &m_cfg->module->formats[m_cfg->fmt_idx].outputs[0].fmt; - - if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { - if (is_fe) { - in_fixup = m_cfg->params_fixup; - out_fixup = (~m_cfg->converter) & - m_cfg->params_fixup; - } else { - out_fixup = m_cfg->params_fixup; - in_fixup = (~m_cfg->converter) & - m_cfg->params_fixup; - } - } else { - if (is_fe) { - out_fixup = m_cfg->params_fixup; - in_fixup = (~m_cfg->converter) & - m_cfg->params_fixup; - } else { - in_fixup = m_cfg->params_fixup; - out_fixup = (~m_cfg->converter) & - m_cfg->params_fixup; - } - } - - skl_tplg_update_params(in_fmt, params, in_fixup); - skl_tplg_update_params(out_fmt, params, out_fixup); -} - -/* - * A module needs input and output buffers, which are dependent upon pcm - * params, so once we have calculate params, we need buffer calculation as - * well. - */ -static void skl_tplg_update_buffer_size(struct skl_dev *skl, - struct skl_module_cfg *mcfg) -{ - int multiplier = 1; - struct skl_module_fmt *in_fmt, *out_fmt; - struct skl_module_res *res; - - /* Since fixups is applied to pin 0 only, ibs, obs needs - * change for pin 0 only - */ - res = &mcfg->module->resources[mcfg->res_idx]; - in_fmt = &mcfg->module->formats[mcfg->fmt_idx].inputs[0].fmt; - out_fmt = &mcfg->module->formats[mcfg->fmt_idx].outputs[0].fmt; - - if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT) - multiplier = 5; - - res->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) * - in_fmt->channels * (in_fmt->bit_depth >> 3) * - multiplier; - - res->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) * - out_fmt->channels * (out_fmt->bit_depth >> 3) * - multiplier; -} - -static u8 skl_tplg_be_dev_type(int dev_type) -{ - int ret; - - switch (dev_type) { - case SKL_DEVICE_BT: - ret = NHLT_DEVICE_BT; - break; - - case SKL_DEVICE_DMIC: - ret = NHLT_DEVICE_DMIC; - break; - - case SKL_DEVICE_I2S: - ret = NHLT_DEVICE_I2S; - break; - - default: - ret = NHLT_DEVICE_INVALID; - break; - } - - return ret; -} - -static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, - struct skl_dev *skl) -{ - struct skl_module_cfg *m_cfg = w->priv; - int link_type, dir; - u32 ch, s_freq, s_fmt, s_cont; - struct nhlt_specific_cfg *cfg; - u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type); - int fmt_idx = m_cfg->fmt_idx; - struct skl_module_iface *m_iface = &m_cfg->module->formats[fmt_idx]; - - /* check if we already have blob */ - if (m_cfg->formats_config[SKL_PARAM_INIT].caps_size > 0) - return 0; - - dev_dbg(skl->dev, "Applying default cfg blob\n"); - switch (m_cfg->dev_type) { - case SKL_DEVICE_DMIC: - link_type = NHLT_LINK_DMIC; - dir = SNDRV_PCM_STREAM_CAPTURE; - s_freq = m_iface->inputs[0].fmt.s_freq; - s_fmt = m_iface->inputs[0].fmt.valid_bit_depth; - s_cont = m_iface->inputs[0].fmt.bit_depth; - ch = m_iface->inputs[0].fmt.channels; - break; - - case SKL_DEVICE_I2S: - link_type = NHLT_LINK_SSP; - if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) { - dir = SNDRV_PCM_STREAM_PLAYBACK; - s_freq = m_iface->outputs[0].fmt.s_freq; - s_fmt = m_iface->outputs[0].fmt.valid_bit_depth; - s_cont = m_iface->outputs[0].fmt.bit_depth; - ch = m_iface->outputs[0].fmt.channels; - } else { - dir = SNDRV_PCM_STREAM_CAPTURE; - s_freq = m_iface->inputs[0].fmt.s_freq; - s_fmt = m_iface->inputs[0].fmt.valid_bit_depth; - s_cont = m_iface->inputs[0].fmt.bit_depth; - ch = m_iface->inputs[0].fmt.channels; - } - break; - - default: - return -EINVAL; - } - - /* update the blob based on virtual bus_id and default params */ - cfg = intel_nhlt_get_endpoint_blob(skl->dev, skl->nhlt, m_cfg->vbus_id, - link_type, s_fmt, s_cont, ch, - s_freq, dir, dev_type); - if (cfg) { - m_cfg->formats_config[SKL_PARAM_INIT].caps_size = cfg->size; - m_cfg->formats_config[SKL_PARAM_INIT].caps = (u32 *)&cfg->caps; - } else { - dev_err(skl->dev, "Blob NULL for id %x type %d dirn %d\n", - m_cfg->vbus_id, link_type, dir); - dev_err(skl->dev, "PCM: ch %d, freq %d, fmt %d/%d\n", - ch, s_freq, s_fmt, s_cont); - return -EIO; - } - - return 0; -} - -static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w, - struct skl_dev *skl) -{ - struct skl_module_cfg *m_cfg = w->priv; - struct skl_pipe_params *params = m_cfg->pipe->p_params; - int p_conn_type = m_cfg->pipe->conn_type; - bool is_fe; - - if (!m_cfg->params_fixup) - return; - - dev_dbg(skl->dev, "Mconfig for widget=%s BEFORE updation\n", - w->name); - - skl_dump_mconfig(skl, m_cfg); - - if (p_conn_type == SKL_PIPE_CONN_TYPE_FE) - is_fe = true; - else - is_fe = false; - - skl_tplg_update_params_fixup(m_cfg, params, is_fe); - skl_tplg_update_buffer_size(skl, m_cfg); - - dev_dbg(skl->dev, "Mconfig for widget=%s AFTER updation\n", - w->name); - - skl_dump_mconfig(skl, m_cfg); -} - -/* - * some modules can have multiple params set from user control and - * need to be set after module is initialized. If set_param flag is - * set module params will be done after module is initialised. - */ -static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w, - struct skl_dev *skl) -{ - int i, ret; - struct skl_module_cfg *mconfig = w->priv; - const struct snd_kcontrol_new *k; - struct soc_bytes_ext *sb; - struct skl_algo_data *bc; - struct skl_specific_cfg *sp_cfg; - - if (mconfig->formats_config[SKL_PARAM_SET].caps_size > 0 && - mconfig->formats_config[SKL_PARAM_SET].set_params == SKL_PARAM_SET) { - sp_cfg = &mconfig->formats_config[SKL_PARAM_SET]; - ret = skl_set_module_params(skl, sp_cfg->caps, - sp_cfg->caps_size, - sp_cfg->param_id, mconfig); - if (ret < 0) - return ret; - } - - for (i = 0; i < w->num_kcontrols; i++) { - k = &w->kcontrol_news[i]; - if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { - sb = (void *) k->private_value; - bc = (struct skl_algo_data *)sb->dobj.private; - - if (bc->set_params == SKL_PARAM_SET) { - ret = skl_set_module_params(skl, - (u32 *)bc->params, bc->size, - bc->param_id, mconfig); - if (ret < 0) - return ret; - } - } - } - - return 0; -} - -/* - * some module param can set from user control and this is required as - * when module is initailzed. if module param is required in init it is - * identifed by set_param flag. if set_param flag is not set, then this - * parameter needs to set as part of module init. - */ -static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w) -{ - const struct snd_kcontrol_new *k; - struct soc_bytes_ext *sb; - struct skl_algo_data *bc; - struct skl_module_cfg *mconfig = w->priv; - int i; - - for (i = 0; i < w->num_kcontrols; i++) { - k = &w->kcontrol_news[i]; - if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { - sb = (struct soc_bytes_ext *)k->private_value; - bc = (struct skl_algo_data *)sb->dobj.private; - - if (bc->set_params != SKL_PARAM_INIT) - continue; - - mconfig->formats_config[SKL_PARAM_INIT].caps = - (u32 *)bc->params; - mconfig->formats_config[SKL_PARAM_INIT].caps_size = - bc->size; - - break; - } - } - - return 0; -} - -static int skl_tplg_module_prepare(struct skl_dev *skl, struct skl_pipe *pipe, - struct snd_soc_dapm_widget *w, struct skl_module_cfg *mcfg) -{ - switch (mcfg->dev_type) { - case SKL_DEVICE_HDAHOST: - return skl_pcm_host_dma_prepare(skl->dev, pipe->p_params); - - case SKL_DEVICE_HDALINK: - return skl_pcm_link_dma_prepare(skl->dev, pipe->p_params); - } - - return 0; -} - -/* - * Inside a pipe instance, we can have various modules. These modules need - * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by - * skl_init_module() routine, so invoke that for all modules in a pipeline - */ -static int -skl_tplg_init_pipe_modules(struct skl_dev *skl, struct skl_pipe *pipe) -{ - struct skl_pipe_module *w_module; - struct snd_soc_dapm_widget *w; - struct skl_module_cfg *mconfig; - u8 cfg_idx; - int ret = 0; - - list_for_each_entry(w_module, &pipe->w_list, node) { - guid_t *uuid_mod; - w = w_module->w; - mconfig = w->priv; - - /* check if module ids are populated */ - if (mconfig->id.module_id < 0) { - dev_err(skl->dev, - "module %pUL id not populated\n", - (guid_t *)mconfig->guid); - return -EIO; - } - - cfg_idx = mconfig->pipe->cur_config_idx; - mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx; - mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx; - - if (mconfig->module->loadable && skl->dsp->fw_ops.load_mod) { - ret = skl->dsp->fw_ops.load_mod(skl->dsp, - mconfig->id.module_id, mconfig->guid); - if (ret < 0) - return ret; - } - - /* prepare the DMA if the module is gateway cpr */ - ret = skl_tplg_module_prepare(skl, pipe, w, mconfig); - if (ret < 0) - return ret; - - /* update blob if blob is null for be with default value */ - skl_tplg_update_be_blob(w, skl); - - /* - * apply fix/conversion to module params based on - * FE/BE params - */ - skl_tplg_update_module_params(w, skl); - uuid_mod = (guid_t *)mconfig->guid; - mconfig->id.pvt_id = skl_get_pvt_id(skl, uuid_mod, - mconfig->id.instance_id); - if (mconfig->id.pvt_id < 0) - return ret; - skl_tplg_set_module_init_data(w); - - ret = skl_dsp_get_core(skl->dsp, mconfig->core_id); - if (ret < 0) { - dev_err(skl->dev, "Failed to wake up core %d ret=%d\n", - mconfig->core_id, ret); - return ret; - } - - ret = skl_init_module(skl, mconfig); - if (ret < 0) { - skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id); - goto err; - } - - ret = skl_tplg_set_module_params(w, skl); - if (ret < 0) - goto err; - } - - return 0; -err: - skl_dsp_put_core(skl->dsp, mconfig->core_id); - return ret; -} - -static int skl_tplg_unload_pipe_modules(struct skl_dev *skl, - struct skl_pipe *pipe) -{ - int ret = 0; - struct skl_pipe_module *w_module; - struct skl_module_cfg *mconfig; - - list_for_each_entry(w_module, &pipe->w_list, node) { - guid_t *uuid_mod; - mconfig = w_module->w->priv; - uuid_mod = (guid_t *)mconfig->guid; - - if (mconfig->module->loadable && skl->dsp->fw_ops.unload_mod) { - ret = skl->dsp->fw_ops.unload_mod(skl->dsp, - mconfig->id.module_id); - if (ret < 0) - return -EIO; - } - skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id); - - ret = skl_dsp_put_core(skl->dsp, mconfig->core_id); - if (ret < 0) { - /* don't return; continue with other modules */ - dev_err(skl->dev, "Failed to sleep core %d ret=%d\n", - mconfig->core_id, ret); - } - } - - /* no modules to unload in this path, so return */ - return ret; -} - -static void skl_tplg_set_pipe_config_idx(struct skl_pipe *pipe, int idx) -{ - pipe->cur_config_idx = idx; - pipe->memory_pages = pipe->configs[idx].mem_pages; -} - -/* - * Here, we select pipe format based on the pipe type and pipe - * direction to determine the current config index for the pipeline. - * The config index is then used to select proper module resources. - * Intermediate pipes currently have a fixed format hence we select the - * 0th configuratation by default for such pipes. - */ -static int -skl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig) -{ - struct skl_pipe *pipe = mconfig->pipe; - struct skl_pipe_params *params = pipe->p_params; - struct skl_path_config *pconfig = &pipe->configs[0]; - struct skl_pipe_fmt *fmt = NULL; - bool in_fmt = false; - int i; - - if (pipe->nr_cfgs == 0) { - skl_tplg_set_pipe_config_idx(pipe, 0); - return 0; - } - - if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE || pipe->nr_cfgs == 1) { - dev_dbg(skl->dev, "No conn_type or just 1 pathcfg, taking 0th for %d\n", - pipe->ppl_id); - skl_tplg_set_pipe_config_idx(pipe, 0); - return 0; - } - - if ((pipe->conn_type == SKL_PIPE_CONN_TYPE_FE && - pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) || - (pipe->conn_type == SKL_PIPE_CONN_TYPE_BE && - pipe->direction == SNDRV_PCM_STREAM_CAPTURE)) - in_fmt = true; - - for (i = 0; i < pipe->nr_cfgs; i++) { - pconfig = &pipe->configs[i]; - if (in_fmt) - fmt = &pconfig->in_fmt; - else - fmt = &pconfig->out_fmt; - - if (CHECK_HW_PARAMS(params->ch, params->s_freq, params->s_fmt, - fmt->channels, fmt->freq, fmt->bps)) { - skl_tplg_set_pipe_config_idx(pipe, i); - dev_dbg(skl->dev, "Using pipe config: %d\n", i); - return 0; - } - } - - dev_err(skl->dev, "Invalid pipe config: %d %d %d for pipe: %d\n", - params->ch, params->s_freq, params->s_fmt, pipe->ppl_id); - return -EINVAL; -} - -/* - * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we - * need create the pipeline. So we do following: - * - Create the pipeline - * - Initialize the modules in pipeline - * - finally bind all modules together - */ -static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, - struct skl_dev *skl) -{ - int ret; - struct skl_module_cfg *mconfig = w->priv; - struct skl_pipe_module *w_module; - struct skl_pipe *s_pipe = mconfig->pipe; - struct skl_module_cfg *src_module = NULL, *dst_module, *module; - struct skl_module_deferred_bind *modules; - - ret = skl_tplg_get_pipe_config(skl, mconfig); - if (ret < 0) - return ret; - - /* - * Create a list of modules for pipe. - * This list contains modules from source to sink - */ - ret = skl_create_pipeline(skl, mconfig->pipe); - if (ret < 0) - return ret; - - /* Init all pipe modules from source to sink */ - ret = skl_tplg_init_pipe_modules(skl, s_pipe); - if (ret < 0) - return ret; - - /* Bind modules from source to sink */ - list_for_each_entry(w_module, &s_pipe->w_list, node) { - dst_module = w_module->w->priv; - - if (src_module == NULL) { - src_module = dst_module; - continue; - } - - ret = skl_bind_modules(skl, src_module, dst_module); - if (ret < 0) - return ret; - - src_module = dst_module; - } - - /* - * When the destination module is initialized, check for these modules - * in deferred bind list. If found, bind them. - */ - list_for_each_entry(w_module, &s_pipe->w_list, node) { - if (list_empty(&skl->bind_list)) - break; - - list_for_each_entry(modules, &skl->bind_list, node) { - module = w_module->w->priv; - if (modules->dst == module) - skl_bind_modules(skl, modules->src, - modules->dst); - } - } - - return 0; -} - -static int skl_fill_sink_instance_id(struct skl_dev *skl, u32 *params, - int size, struct skl_module_cfg *mcfg) -{ - int i, pvt_id; - - if (mcfg->m_type == SKL_MODULE_TYPE_KPB) { - struct skl_kpb_params *kpb_params = - (struct skl_kpb_params *)params; - struct skl_mod_inst_map *inst = kpb_params->u.map; - - for (i = 0; i < kpb_params->num_modules; i++) { - pvt_id = skl_get_pvt_instance_id_map(skl, inst->mod_id, - inst->inst_id); - if (pvt_id < 0) - return -EINVAL; - - inst->inst_id = pvt_id; - inst++; - } - } - - return 0; -} -/* - * Some modules require params to be set after the module is bound to - * all pins connected. - * - * The module provider initializes set_param flag for such modules and we - * send params after binding - */ -static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, - struct skl_module_cfg *mcfg, struct skl_dev *skl) -{ - int i, ret; - struct skl_module_cfg *mconfig = w->priv; - const struct snd_kcontrol_new *k; - struct soc_bytes_ext *sb; - struct skl_algo_data *bc; - struct skl_specific_cfg *sp_cfg; - u32 *params; - - /* - * check all out/in pins are in bind state. - * if so set the module param - */ - for (i = 0; i < mcfg->module->max_output_pins; i++) { - if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE) - return 0; - } - - for (i = 0; i < mcfg->module->max_input_pins; i++) { - if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE) - return 0; - } - - if (mconfig->formats_config[SKL_PARAM_BIND].caps_size > 0 && - mconfig->formats_config[SKL_PARAM_BIND].set_params == - SKL_PARAM_BIND) { - sp_cfg = &mconfig->formats_config[SKL_PARAM_BIND]; - ret = skl_set_module_params(skl, sp_cfg->caps, - sp_cfg->caps_size, - sp_cfg->param_id, mconfig); - if (ret < 0) - return ret; - } - - for (i = 0; i < w->num_kcontrols; i++) { - k = &w->kcontrol_news[i]; - if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { - sb = (void *) k->private_value; - bc = (struct skl_algo_data *)sb->dobj.private; - - if (bc->set_params == SKL_PARAM_BIND) { - params = kmemdup(bc->params, bc->max, GFP_KERNEL); - if (!params) - return -ENOMEM; - - skl_fill_sink_instance_id(skl, params, bc->max, - mconfig); - - ret = skl_set_module_params(skl, params, - bc->max, bc->param_id, mconfig); - kfree(params); - - if (ret < 0) - return ret; - } - } - } - - return 0; -} - -static int skl_get_module_id(struct skl_dev *skl, guid_t *uuid) -{ - struct uuid_module *module; - - list_for_each_entry(module, &skl->uuid_list, list) { - if (guid_equal(uuid, &module->uuid)) - return module->id; - } - - return -EINVAL; -} - -static int skl_tplg_find_moduleid_from_uuid(struct skl_dev *skl, - const struct snd_kcontrol_new *k) -{ - struct soc_bytes_ext *sb = (void *) k->private_value; - struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private; - struct skl_kpb_params *uuid_params, *params; - struct hdac_bus *bus = skl_to_bus(skl); - int i, size, module_id; - - if (bc->set_params == SKL_PARAM_BIND && bc->max) { - uuid_params = (struct skl_kpb_params *)bc->params; - size = struct_size(params, u.map, uuid_params->num_modules); - - params = devm_kzalloc(bus->dev, size, GFP_KERNEL); - if (!params) - return -ENOMEM; - - params->num_modules = uuid_params->num_modules; - - for (i = 0; i < uuid_params->num_modules; i++) { - module_id = skl_get_module_id(skl, - &uuid_params->u.map_uuid[i].mod_uuid); - if (module_id < 0) { - devm_kfree(bus->dev, params); - return -EINVAL; - } - - params->u.map[i].mod_id = module_id; - params->u.map[i].inst_id = - uuid_params->u.map_uuid[i].inst_id; - } - - devm_kfree(bus->dev, bc->params); - bc->params = (char *)params; - bc->max = size; - } - - return 0; -} - -/* - * Retrieve the module id from UUID mentioned in the - * post bind params - */ -void skl_tplg_add_moduleid_in_bind_params(struct skl_dev *skl, - struct snd_soc_dapm_widget *w) -{ - struct skl_module_cfg *mconfig = w->priv; - int i; - - /* - * Post bind params are used for only for KPB - * to set copier instances to drain the data - * in fast mode - */ - if (mconfig->m_type != SKL_MODULE_TYPE_KPB) - return; - - for (i = 0; i < w->num_kcontrols; i++) - if ((w->kcontrol_news[i].access & - SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) && - (skl_tplg_find_moduleid_from_uuid(skl, - &w->kcontrol_news[i]) < 0)) - dev_err(skl->dev, - "%s: invalid kpb post bind params\n", - __func__); -} - -static int skl_tplg_module_add_deferred_bind(struct skl_dev *skl, - struct skl_module_cfg *src, struct skl_module_cfg *dst) -{ - struct skl_module_deferred_bind *m_list, *modules; - int i; - - /* only supported for module with static pin connection */ - for (i = 0; i < dst->module->max_input_pins; i++) { - struct skl_module_pin *pin = &dst->m_in_pin[i]; - - if (pin->is_dynamic) - continue; - - if ((pin->id.module_id == src->id.module_id) && - (pin->id.instance_id == src->id.instance_id)) { - - if (!list_empty(&skl->bind_list)) { - list_for_each_entry(modules, &skl->bind_list, node) { - if (modules->src == src && modules->dst == dst) - return 0; - } - } - - m_list = kzalloc(sizeof(*m_list), GFP_KERNEL); - if (!m_list) - return -ENOMEM; - - m_list->src = src; - m_list->dst = dst; - - list_add(&m_list->node, &skl->bind_list); - } - } - - return 0; -} - -static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, - struct skl_dev *skl, - struct snd_soc_dapm_widget *src_w, - struct skl_module_cfg *src_mconfig) -{ - struct snd_soc_dapm_path *p; - struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL; - struct skl_module_cfg *sink_mconfig; - int ret; - - snd_soc_dapm_widget_for_each_sink_path(w, p) { - if (!p->connect) - continue; - - dev_dbg(skl->dev, - "%s: src widget=%s\n", __func__, w->name); - dev_dbg(skl->dev, - "%s: sink widget=%s\n", __func__, p->sink->name); - - next_sink = p->sink; - - if (!is_skl_dsp_widget_type(p->sink, skl->dev)) - return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig); - - /* - * here we will check widgets in sink pipelines, so that - * can be any widgets type and we are only interested if - * they are ones used for SKL so check that first - */ - if ((p->sink->priv != NULL) && - is_skl_dsp_widget_type(p->sink, skl->dev)) { - - sink = p->sink; - sink_mconfig = sink->priv; - - /* - * Modules other than PGA leaf can be connected - * directly or via switch to a module in another - * pipeline. EX: reference path - * when the path is enabled, the dst module that needs - * to be bound may not be initialized. if the module is - * not initialized, add these modules in the deferred - * bind list and when the dst module is initialised, - * bind this module to the dst_module in deferred list. - */ - if (((src_mconfig->m_state == SKL_MODULE_INIT_DONE) - && (sink_mconfig->m_state == SKL_MODULE_UNINIT))) { - - ret = skl_tplg_module_add_deferred_bind(skl, - src_mconfig, sink_mconfig); - - if (ret < 0) - return ret; - - } - - - if (src_mconfig->m_state == SKL_MODULE_UNINIT || - sink_mconfig->m_state == SKL_MODULE_UNINIT) - continue; - - /* Bind source to sink, mixin is always source */ - ret = skl_bind_modules(skl, src_mconfig, sink_mconfig); - if (ret) - return ret; - - /* set module params after bind */ - skl_tplg_set_module_bind_params(src_w, - src_mconfig, skl); - skl_tplg_set_module_bind_params(sink, - sink_mconfig, skl); - - /* Start sinks pipe first */ - if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) { - if (sink_mconfig->pipe->conn_type != - SKL_PIPE_CONN_TYPE_FE) - ret = skl_run_pipe(skl, - sink_mconfig->pipe); - if (ret) - return ret; - } - } - } - - if (!sink && next_sink) - return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig); - - return 0; -} - -/* - * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA - * we need to do following: - * - Bind to sink pipeline - * Since the sink pipes can be running and we don't get mixer event on - * connect for already running mixer, we need to find the sink pipes - * here and bind to them. This way dynamic connect works. - * - Start sink pipeline, if not running - * - Then run current pipe - */ -static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, - struct skl_dev *skl) -{ - struct skl_module_cfg *src_mconfig; - int ret = 0; - - src_mconfig = w->priv; - - /* - * find which sink it is connected to, bind with the sink, - * if sink is not started, start sink pipe first, then start - * this pipe - */ - ret = skl_tplg_bind_sinks(w, skl, w, src_mconfig); - if (ret) - return ret; - - /* Start source pipe last after starting all sinks */ - if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) - return skl_run_pipe(skl, src_mconfig->pipe); - - return 0; -} - -static struct snd_soc_dapm_widget *skl_get_src_dsp_widget( - struct snd_soc_dapm_widget *w, struct skl_dev *skl) -{ - struct snd_soc_dapm_path *p; - struct snd_soc_dapm_widget *src_w = NULL; - - snd_soc_dapm_widget_for_each_source_path(w, p) { - src_w = p->source; - if (!p->connect) - continue; - - dev_dbg(skl->dev, "sink widget=%s\n", w->name); - dev_dbg(skl->dev, "src widget=%s\n", p->source->name); - - /* - * here we will check widgets in sink pipelines, so that can - * be any widgets type and we are only interested if they are - * ones used for SKL so check that first - */ - if ((p->source->priv != NULL) && - is_skl_dsp_widget_type(p->source, skl->dev)) { - return p->source; - } - } - - if (src_w != NULL) - return skl_get_src_dsp_widget(src_w, skl); - - return NULL; -} - -/* - * in the Post-PMU event of mixer we need to do following: - * - Check if this pipe is running - * - if not, then - * - bind this pipeline to its source pipeline - * if source pipe is already running, this means it is a dynamic - * connection and we need to bind only to that pipe - * - start this pipeline - */ -static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, - struct skl_dev *skl) -{ - int ret = 0; - struct snd_soc_dapm_widget *source, *sink; - struct skl_module_cfg *src_mconfig, *sink_mconfig; - int src_pipe_started = 0; - - sink = w; - sink_mconfig = sink->priv; - - /* - * If source pipe is already started, that means source is driving - * one more sink before this sink got connected, Since source is - * started, bind this sink to source and start this pipe. - */ - source = skl_get_src_dsp_widget(w, skl); - if (source != NULL) { - src_mconfig = source->priv; - sink_mconfig = sink->priv; - src_pipe_started = 1; - - /* - * check pipe state, then no need to bind or start the - * pipe - */ - if (src_mconfig->pipe->state != SKL_PIPE_STARTED) - src_pipe_started = 0; - } - - if (src_pipe_started) { - ret = skl_bind_modules(skl, src_mconfig, sink_mconfig); - if (ret) - return ret; - - /* set module params after bind */ - skl_tplg_set_module_bind_params(source, src_mconfig, skl); - skl_tplg_set_module_bind_params(sink, sink_mconfig, skl); - - if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) - ret = skl_run_pipe(skl, sink_mconfig->pipe); - } - - return ret; -} - -/* - * in the Pre-PMD event of mixer we need |