summaryrefslogtreecommitdiff
path: root/sound/soc/intel/skylake/skl-topology.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/intel/skylake/skl-topology.c')
-rw-r--r--sound/soc/intel/skylake/skl-topology.c3605
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