From cf4ce59b3b70238352c7f1729f0f7223214828ad Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Fri, 20 Sep 2024 01:46:19 +0000 Subject: [PATCH] rtl88x2CE_WiFi_linux add concurrent mode --- kernel/sound/soc/intel/skylake/skl-topology.c | 770 ++++++++++++++++++++++++++++++----------------------------- 1 files changed, 393 insertions(+), 377 deletions(-) diff --git a/kernel/sound/soc/intel/skylake/skl-topology.c b/kernel/sound/soc/intel/skylake/skl-topology.c index f99c600..73976c6 100644 --- a/kernel/sound/soc/intel/skylake/skl-topology.c +++ b/kernel/sound/soc/intel/skylake/skl-topology.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * skl-topology.c - Implements Platform component ALSA controls/widget * handlers. @@ -5,22 +6,15 @@ * Copyright (C) 2014-2015 Intel Corp * Author: Jeeja KP <jeeja.kp@intel.com> * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as version 2, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. */ #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> @@ -53,9 +47,9 @@ #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 *skl, enum d0i3_capability caps) +void skl_tplg_d0i3_get(struct skl_dev *skl, enum d0i3_capability caps) { - struct skl_d0i3_data *d0i3 = &skl->skl_sst->d0i3; + struct skl_d0i3_data *d0i3 = &skl->d0i3; switch (caps) { case SKL_D0I3_NONE: @@ -72,9 +66,9 @@ } } -void skl_tplg_d0i3_put(struct skl *skl, enum d0i3_capability caps) +void skl_tplg_d0i3_put(struct skl_dev *skl, enum d0i3_capability caps) { - struct skl_d0i3_data *d0i3 = &skl->skl_sst->d0i3; + struct skl_d0i3_data *d0i3 = &skl->d0i3; switch (caps) { case SKL_D0I3_NONE: @@ -117,118 +111,23 @@ } } -/* - * Each pipelines needs memory to be allocated. Check if we have free memory - * from available pool. - */ -static bool skl_is_pipe_mem_avail(struct skl *skl, - struct skl_module_cfg *mconfig) +static void skl_dump_mconfig(struct skl_dev *skl, struct skl_module_cfg *mcfg) { - struct skl_sst *ctx = skl->skl_sst; + struct skl_module_iface *iface = &mcfg->module->formats[mcfg->fmt_idx]; - if (skl->resource.mem + mconfig->pipe->memory_pages > - skl->resource.max_mem) { - dev_err(ctx->dev, - "%s: module_id %d instance %d\n", __func__, - mconfig->id.module_id, - mconfig->id.instance_id); - dev_err(ctx->dev, - "exceeds ppl memory available %d mem %d\n", - skl->resource.max_mem, skl->resource.mem); - return false; - } else { - return true; - } -} - -/* - * Add the mem to the mem pool. This is freed when pipe is deleted. - * Note: DSP does actual memory management we only keep track for complete - * pool - */ -static void skl_tplg_alloc_pipe_mem(struct skl *skl, - struct skl_module_cfg *mconfig) -{ - skl->resource.mem += mconfig->pipe->memory_pages; -} - -/* - * Pipeline needs needs DSP CPU resources for computation, this is - * quantified in MCPS (Million Clocks Per Second) required for module/pipe - * - * Each pipelines needs mcps to be allocated. Check if we have mcps for this - * pipe. - */ - -static bool skl_is_pipe_mcps_avail(struct skl *skl, - struct skl_module_cfg *mconfig) -{ - struct skl_sst *ctx = skl->skl_sst; - u8 res_idx = mconfig->res_idx; - struct skl_module_res *res = &mconfig->module->resources[res_idx]; - - if (skl->resource.mcps + res->cps > skl->resource.max_mcps) { - dev_err(ctx->dev, - "%s: module_id %d instance %d\n", __func__, - mconfig->id.module_id, mconfig->id.instance_id); - dev_err(ctx->dev, - "exceeds ppl mcps available %d > mem %d\n", - skl->resource.max_mcps, skl->resource.mcps); - return false; - } else { - return true; - } -} - -static void skl_tplg_alloc_pipe_mcps(struct skl *skl, - struct skl_module_cfg *mconfig) -{ - u8 res_idx = mconfig->res_idx; - struct skl_module_res *res = &mconfig->module->resources[res_idx]; - - skl->resource.mcps += res->cps; -} - -/* - * Free the mcps when tearing down - */ -static void -skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig) -{ - u8 res_idx = mconfig->res_idx; - struct skl_module_res *res = &mconfig->module->resources[res_idx]; - - skl->resource.mcps -= res->cps; -} - -/* - * Free the memory when tearing down - */ -static void -skl_tplg_free_pipe_mem(struct skl *skl, struct skl_module_cfg *mconfig) -{ - skl->resource.mem -= mconfig->pipe->memory_pages; -} - - -static void skl_dump_mconfig(struct skl_sst *ctx, - struct skl_module_cfg *mcfg) -{ - struct skl_module_iface *iface = &mcfg->module->formats[0]; - - dev_dbg(ctx->dev, "Dumping config\n"); - dev_dbg(ctx->dev, "Input Format:\n"); - dev_dbg(ctx->dev, "channels = %d\n", iface->inputs[0].fmt.channels); - dev_dbg(ctx->dev, "s_freq = %d\n", iface->inputs[0].fmt.s_freq); - dev_dbg(ctx->dev, "ch_cfg = %d\n", iface->inputs[0].fmt.ch_cfg); - dev_dbg(ctx->dev, "valid bit depth = %d\n", + 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(ctx->dev, "Output Format:\n"); - dev_dbg(ctx->dev, "channels = %d\n", iface->outputs[0].fmt.channels); - dev_dbg(ctx->dev, "s_freq = %d\n", iface->outputs[0].fmt.s_freq); - dev_dbg(ctx->dev, "valid bit depth = %d\n", + 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(ctx->dev, "ch_cfg = %d\n", iface->outputs[0].fmt.ch_cfg); + 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) @@ -296,8 +195,8 @@ struct skl_module_fmt *in_fmt, *out_fmt; /* Fixups will be applied to pin 0 only */ - in_fmt = &m_cfg->module->formats[0].inputs[0].fmt; - out_fmt = &m_cfg->module->formats[0].outputs[0].fmt; + 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) { @@ -330,7 +229,7 @@ * params, so once we have calculate params, we need buffer calculation as * well. */ -static void skl_tplg_update_buffer_size(struct skl_sst *ctx, +static void skl_tplg_update_buffer_size(struct skl_dev *skl, struct skl_module_cfg *mcfg) { int multiplier = 1; @@ -340,9 +239,9 @@ /* Since fixups is applied to pin 0 only, ibs, obs needs * change for pin 0 only */ - res = &mcfg->module->resources[0]; - in_fmt = &mcfg->module->formats[0].inputs[0].fmt; - out_fmt = &mcfg->module->formats[0].outputs[0].fmt; + 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; @@ -382,13 +281,12 @@ } static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, - struct skl_sst *ctx) + struct skl_dev *skl) { struct skl_module_cfg *m_cfg = w->priv; int link_type, dir; u32 ch, s_freq, s_fmt; struct nhlt_specific_cfg *cfg; - struct skl *skl = get_skl_ctx(ctx->dev); 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]; @@ -397,7 +295,7 @@ if (m_cfg->formats_config.caps_size > 0) return 0; - dev_dbg(ctx->dev, "Applying default cfg blob\n"); + dev_dbg(skl->dev, "Applying default cfg blob\n"); switch (m_cfg->dev_type) { case SKL_DEVICE_DMIC: link_type = NHLT_LINK_DMIC; @@ -433,9 +331,9 @@ m_cfg->formats_config.caps_size = cfg->size; m_cfg->formats_config.caps = (u32 *) &cfg->caps; } else { - dev_err(ctx->dev, "Blob NULL for id %x type %d dirn %d\n", + dev_err(skl->dev, "Blob NULL for id %x type %d dirn %d\n", m_cfg->vbus_id, link_type, dir); - dev_err(ctx->dev, "PCM: ch %d, freq %d, fmt %d\n", + dev_err(skl->dev, "PCM: ch %d, freq %d, fmt %d\n", ch, s_freq, s_fmt); return -EIO; } @@ -444,7 +342,7 @@ } static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w, - struct skl_sst *ctx) + struct skl_dev *skl) { struct skl_module_cfg *m_cfg = w->priv; struct skl_pipe_params *params = m_cfg->pipe->p_params; @@ -454,10 +352,10 @@ if (!m_cfg->params_fixup) return; - dev_dbg(ctx->dev, "Mconfig for widget=%s BEFORE updation\n", + dev_dbg(skl->dev, "Mconfig for widget=%s BEFORE updation\n", w->name); - skl_dump_mconfig(ctx, m_cfg); + skl_dump_mconfig(skl, m_cfg); if (p_conn_type == SKL_PIPE_CONN_TYPE_FE) is_fe = true; @@ -465,12 +363,12 @@ is_fe = false; skl_tplg_update_params_fixup(m_cfg, params, is_fe); - skl_tplg_update_buffer_size(ctx, m_cfg); + skl_tplg_update_buffer_size(skl, m_cfg); - dev_dbg(ctx->dev, "Mconfig for widget=%s AFTER updation\n", + dev_dbg(skl->dev, "Mconfig for widget=%s AFTER updation\n", w->name); - skl_dump_mconfig(ctx, m_cfg); + skl_dump_mconfig(skl, m_cfg); } /* @@ -479,7 +377,7 @@ * 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_sst *ctx) + struct skl_dev *skl) { int i, ret; struct skl_module_cfg *mconfig = w->priv; @@ -491,7 +389,7 @@ if (mconfig->formats_config.caps_size > 0 && mconfig->formats_config.set_params == SKL_PARAM_SET) { sp_cfg = &mconfig->formats_config; - ret = skl_set_module_params(ctx, sp_cfg->caps, + ret = skl_set_module_params(skl, sp_cfg->caps, sp_cfg->caps_size, sp_cfg->param_id, mconfig); if (ret < 0) @@ -505,7 +403,7 @@ bc = (struct skl_algo_data *)sb->dobj.private; if (bc->set_params == SKL_PARAM_SET) { - ret = skl_set_module_params(ctx, + ret = skl_set_module_params(skl, (u32 *)bc->params, bc->size, bc->param_id, mconfig); if (ret < 0) @@ -550,15 +448,15 @@ return 0; } -static int skl_tplg_module_prepare(struct skl_sst *ctx, struct skl_pipe *pipe, +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(ctx->dev, pipe->p_params); + return skl_pcm_host_dma_prepare(skl->dev, pipe->p_params); case SKL_DEVICE_HDALINK: - return skl_pcm_link_dma_prepare(ctx->dev, pipe->p_params); + return skl_pcm_link_dma_prepare(skl->dev, pipe->p_params); } return 0; @@ -570,25 +468,24 @@ * skl_init_module() routine, so invoke that for all modules in a pipeline */ static int -skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) +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; - struct skl_sst *ctx = skl->skl_sst; u8 cfg_idx; int ret = 0; list_for_each_entry(w_module, &pipe->w_list, node) { - uuid_le *uuid_mod; + 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->skl_sst->dev, + dev_err(skl->dev, "module %pUL id not populated\n", - (uuid_le *)mconfig->guid); + (guid_t *)mconfig->guid); return -EIO; } @@ -596,12 +493,8 @@ mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx; mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx; - /* check resource available */ - if (!skl_is_pipe_mcps_avail(skl, mconfig)) - return -ENOMEM; - - if (mconfig->module->loadable && ctx->dsp->fw_ops.load_mod) { - ret = ctx->dsp->fw_ops.load_mod(ctx->dsp, + 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; @@ -610,80 +503,112 @@ } /* prepare the DMA if the module is gateway cpr */ - ret = skl_tplg_module_prepare(ctx, pipe, w, mconfig); + 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, ctx); + skl_tplg_update_be_blob(w, skl); /* * apply fix/conversion to module params based on * FE/BE params */ - skl_tplg_update_module_params(w, ctx); - uuid_mod = (uuid_le *)mconfig->guid; - mconfig->id.pvt_id = skl_get_pvt_id(ctx, uuid_mod, + 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(ctx->dsp, mconfig->core_id); + ret = skl_dsp_get_core(skl->dsp, mconfig->core_id); if (ret < 0) { - dev_err(ctx->dev, "Failed to wake up core %d ret=%d\n", + dev_err(skl->dev, "Failed to wake up core %d ret=%d\n", mconfig->core_id, ret); return ret; } - ret = skl_init_module(ctx, mconfig); + ret = skl_init_module(skl, mconfig); if (ret < 0) { - skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id); + skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id); goto err; } - skl_tplg_alloc_pipe_mcps(skl, mconfig); - ret = skl_tplg_set_module_params(w, ctx); + + ret = skl_tplg_set_module_params(w, skl); if (ret < 0) goto err; } return 0; err: - skl_dsp_put_core(ctx->dsp, mconfig->core_id); + skl_dsp_put_core(skl->dsp, mconfig->core_id); return ret; } -static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx, +static int skl_tplg_unload_pipe_modules(struct skl_dev *skl, struct skl_pipe *pipe) { int ret = 0; - struct skl_pipe_module *w_module = NULL; - struct skl_module_cfg *mconfig = NULL; + struct skl_pipe_module *w_module; + struct skl_module_cfg *mconfig; list_for_each_entry(w_module, &pipe->w_list, node) { - uuid_le *uuid_mod; + guid_t *uuid_mod; mconfig = w_module->w->priv; - uuid_mod = (uuid_le *)mconfig->guid; + uuid_mod = (guid_t *)mconfig->guid; - if (mconfig->module->loadable && ctx->dsp->fw_ops.unload_mod && + if (mconfig->module->loadable && skl->dsp->fw_ops.unload_mod && mconfig->m_state > SKL_MODULE_UNINIT) { - ret = ctx->dsp->fw_ops.unload_mod(ctx->dsp, + ret = skl->dsp->fw_ops.unload_mod(skl->dsp, mconfig->id.module_id); if (ret < 0) return -EIO; } - skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id); + skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id); - ret = skl_dsp_put_core(ctx->dsp, mconfig->core_id); + ret = skl_dsp_put_core(skl->dsp, mconfig->core_id); if (ret < 0) { /* don't return; continue with other modules */ - dev_err(ctx->dev, "Failed to sleep core %d ret=%d\n", + 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 bool skl_tplg_is_multi_fmt(struct skl_dev *skl, struct skl_pipe *pipe) +{ + struct skl_pipe_fmt *cur_fmt; + struct skl_pipe_fmt *next_fmt; + int i; + + if (pipe->nr_cfgs <= 1) + return false; + + if (pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) + return true; + + for (i = 0; i < pipe->nr_cfgs - 1; i++) { + if (pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) { + cur_fmt = &pipe->configs[i].out_fmt; + next_fmt = &pipe->configs[i + 1].out_fmt; + } else { + cur_fmt = &pipe->configs[i].in_fmt; + next_fmt = &pipe->configs[i + 1].in_fmt; + } + + if (!CHECK_HW_PARAMS(cur_fmt->channels, cur_fmt->freq, + cur_fmt->bps, + next_fmt->channels, + next_fmt->freq, + next_fmt->bps)) + return true; + } + + return false; } /* @@ -694,9 +619,8 @@ * 0th configuratation by default for such pipes. */ static int -skl_tplg_get_pipe_config(struct skl *skl, struct skl_module_cfg *mconfig) +skl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig) { - struct skl_sst *ctx = skl->skl_sst; struct skl_pipe *pipe = mconfig->pipe; struct skl_pipe_params *params = pipe->p_params; struct skl_path_config *pconfig = &pipe->configs[0]; @@ -709,8 +633,16 @@ return 0; } + if (skl_tplg_is_multi_fmt(skl, pipe)) { + pipe->cur_config_idx = pipe->pipe_config_idx; + pipe->memory_pages = pconfig->mem_pages; + dev_dbg(skl->dev, "found pipe config idx:%d\n", + pipe->cur_config_idx); + return 0; + } + if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE) { - dev_dbg(ctx->dev, "No conn_type detected, take 0th config\n"); + dev_dbg(skl->dev, "No conn_type detected, take 0th config\n"); pipe->cur_config_idx = 0; pipe->memory_pages = pconfig->mem_pages; @@ -734,13 +666,13 @@ fmt->channels, fmt->freq, fmt->bps)) { pipe->cur_config_idx = i; pipe->memory_pages = pconfig->mem_pages; - dev_dbg(ctx->dev, "Using pipe config: %d\n", i); + dev_dbg(skl->dev, "Using pipe config: %d\n", i); return 0; } } - dev_err(ctx->dev, "Invalid pipe config: %d %d %d for pipe: %d\n", + 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; } @@ -748,43 +680,31 @@ /* * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we * need create the pipeline. So we do following: - * - check the resources * - 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 *skl) + 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_sst *ctx = skl->skl_sst; struct skl_module_deferred_bind *modules; ret = skl_tplg_get_pipe_config(skl, mconfig); if (ret < 0) return ret; - /* check resource available */ - if (!skl_is_pipe_mcps_avail(skl, mconfig)) - return -EBUSY; - - if (!skl_is_pipe_mem_avail(skl, mconfig)) - return -ENOMEM; - /* * Create a list of modules for pipe. * This list contains modules from source to sink */ - ret = skl_create_pipeline(ctx, mconfig->pipe); + ret = skl_create_pipeline(skl, mconfig->pipe); if (ret < 0) return ret; - - skl_tplg_alloc_pipe_mem(skl, mconfig); - skl_tplg_alloc_pipe_mcps(skl, mconfig); /* Init all pipe modules from source to sink */ ret = skl_tplg_init_pipe_modules(skl, s_pipe); @@ -800,7 +720,7 @@ continue; } - ret = skl_bind_modules(ctx, src_module, dst_module); + ret = skl_bind_modules(skl, src_module, dst_module); if (ret < 0) return ret; @@ -818,7 +738,7 @@ list_for_each_entry(modules, &skl->bind_list, node) { module = w_module->w->priv; if (modules->dst == module) - skl_bind_modules(ctx, modules->src, + skl_bind_modules(skl, modules->src, modules->dst); } } @@ -826,7 +746,7 @@ return 0; } -static int skl_fill_sink_instance_id(struct skl_sst *ctx, u32 *params, +static int skl_fill_sink_instance_id(struct skl_dev *skl, u32 *params, int size, struct skl_module_cfg *mcfg) { int i, pvt_id; @@ -837,7 +757,7 @@ 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(ctx, inst->mod_id, + pvt_id = skl_get_pvt_instance_id_map(skl, inst->mod_id, inst->inst_id); if (pvt_id < 0) return -EINVAL; @@ -857,7 +777,7 @@ * 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_sst *ctx) + struct skl_module_cfg *mcfg, struct skl_dev *skl) { int i, ret; struct skl_module_cfg *mconfig = w->priv; @@ -884,7 +804,7 @@ if (mconfig->formats_config.caps_size > 0 && mconfig->formats_config.set_params == SKL_PARAM_BIND) { sp_cfg = &mconfig->formats_config; - ret = skl_set_module_params(ctx, sp_cfg->caps, + ret = skl_set_module_params(skl, sp_cfg->caps, sp_cfg->caps_size, sp_cfg->param_id, mconfig); if (ret < 0) @@ -898,15 +818,14 @@ bc = (struct skl_algo_data *)sb->dobj.private; if (bc->set_params == SKL_PARAM_BIND) { - params = kzalloc(bc->max, GFP_KERNEL); + params = kmemdup(bc->params, bc->max, GFP_KERNEL); if (!params) return -ENOMEM; - memcpy(params, bc->params, bc->max); - skl_fill_sink_instance_id(ctx, params, bc->max, + skl_fill_sink_instance_id(skl, params, bc->max, mconfig); - ret = skl_set_module_params(ctx, params, + ret = skl_set_module_params(skl, params, bc->max, bc->param_id, mconfig); kfree(params); @@ -919,19 +838,19 @@ return 0; } -static int skl_get_module_id(struct skl_sst *ctx, uuid_le *uuid) +static int skl_get_module_id(struct skl_dev *skl, guid_t *uuid) { struct uuid_module *module; - list_for_each_entry(module, &ctx->uuid_list, list) { - if (uuid_le_cmp(*uuid, module->uuid) == 0) + 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 *skl, +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; @@ -942,9 +861,7 @@ if (bc->set_params == SKL_PARAM_BIND && bc->max) { uuid_params = (struct skl_kpb_params *)bc->params; - size = uuid_params->num_modules * - sizeof(struct skl_mod_inst_map) + - sizeof(uuid_params->num_modules); + size = struct_size(params, u.map, uuid_params->num_modules); params = devm_kzalloc(bus->dev, size, GFP_KERNEL); if (!params) @@ -953,7 +870,7 @@ params->num_modules = uuid_params->num_modules; for (i = 0; i < uuid_params->num_modules; i++) { - module_id = skl_get_module_id(skl->skl_sst, + module_id = skl_get_module_id(skl, &uuid_params->u.map_uuid[i].mod_uuid); if (module_id < 0) { devm_kfree(bus->dev, params); @@ -977,7 +894,7 @@ * Retrieve the module id from UUID mentioned in the * post bind params */ -void skl_tplg_add_moduleid_in_bind_params(struct skl *skl, +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; @@ -996,12 +913,12 @@ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) && (skl_tplg_find_moduleid_from_uuid(skl, &w->kcontrol_news[i]) < 0)) - dev_err(skl->skl_sst->dev, + dev_err(skl->dev, "%s: invalid kpb post bind params\n", __func__); } -static int skl_tplg_module_add_deferred_bind(struct skl *skl, +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; @@ -1039,26 +956,27 @@ } static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, - struct skl *skl, + 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; - struct skl_sst *ctx = skl->skl_sst; int ret; snd_soc_dapm_widget_for_each_sink_path(w, p) { if (!p->connect) continue; - dev_dbg(ctx->dev, "%s: src widget=%s\n", __func__, w->name); - dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name); + 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, ctx->dev)) + if (!is_skl_dsp_widget_type(p->sink, skl->dev)) return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig); /* @@ -1067,7 +985,7 @@ * they are ones used for SKL so check that first */ if ((p->sink->priv != NULL) && - is_skl_dsp_widget_type(p->sink, ctx->dev)) { + is_skl_dsp_widget_type(p->sink, skl->dev)) { sink = p->sink; sink_mconfig = sink->priv; @@ -1099,19 +1017,21 @@ continue; /* Bind source to sink, mixin is always source */ - ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig); + 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, ctx); - skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx); + 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(ctx, + ret = skl_run_pipe(skl, sink_mconfig->pipe); if (ret) return ret; @@ -1136,10 +1056,9 @@ * - Then run current pipe */ static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, - struct skl *skl) + struct skl_dev *skl) { struct skl_module_cfg *src_mconfig; - struct skl_sst *ctx = skl->skl_sst; int ret = 0; src_mconfig = w->priv; @@ -1155,25 +1074,24 @@ /* Start source pipe last after starting all sinks */ if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) - return skl_run_pipe(ctx, src_mconfig->pipe); + 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 *skl) + struct snd_soc_dapm_widget *w, struct skl_dev *skl) { struct snd_soc_dapm_path *p; struct snd_soc_dapm_widget *src_w = NULL; - struct skl_sst *ctx = skl->skl_sst; snd_soc_dapm_widget_for_each_source_path(w, p) { src_w = p->source; if (!p->connect) continue; - dev_dbg(ctx->dev, "sink widget=%s\n", w->name); - dev_dbg(ctx->dev, "src widget=%s\n", p->source->name); + 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 @@ -1181,7 +1099,7 @@ * ones used for SKL so check that first */ if ((p->source->priv != NULL) && - is_skl_dsp_widget_type(p->source, ctx->dev)) { + is_skl_dsp_widget_type(p->source, skl->dev)) { return p->source; } } @@ -1202,12 +1120,11 @@ * - start this pipeline */ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, - struct skl *skl) + struct skl_dev *skl) { int ret = 0; struct snd_soc_dapm_widget *source, *sink; struct skl_module_cfg *src_mconfig, *sink_mconfig; - struct skl_sst *ctx = skl->skl_sst; int src_pipe_started = 0; sink = w; @@ -1233,16 +1150,16 @@ } if (src_pipe_started) { - ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig); + 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, ctx); - skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx); + 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(ctx, sink_mconfig->pipe); + ret = skl_run_pipe(skl, sink_mconfig->pipe); } return ret; @@ -1255,16 +1172,15 @@ * - unbind with source pipelines if still connected */ static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w, - struct skl *skl) + struct skl_dev *skl) { struct skl_module_cfg *src_mconfig, *sink_mconfig; int ret = 0, i; - struct skl_sst *ctx = skl->skl_sst; sink_mconfig = w->priv; /* Stop the pipe */ - ret = skl_stop_pipe(ctx, sink_mconfig->pipe); + ret = skl_stop_pipe(skl, sink_mconfig->pipe); if (ret) return ret; @@ -1274,7 +1190,7 @@ if (!src_mconfig) continue; - ret = skl_unbind_modules(ctx, + ret = skl_unbind_modules(skl, src_mconfig, sink_mconfig); } } @@ -1284,27 +1200,21 @@ /* * in the Post-PMD event of mixer we need to do following: - * - Free the mcps used - * - Free the mem used * - Unbind the modules within the pipeline * - Delete the pipeline (modules are not required to be explicitly * deleted, pipeline delete is enough here */ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, - struct skl *skl) + struct skl_dev *skl) { struct skl_module_cfg *mconfig = w->priv; struct skl_pipe_module *w_module; struct skl_module_cfg *src_module = NULL, *dst_module; - struct skl_sst *ctx = skl->skl_sst; struct skl_pipe *s_pipe = mconfig->pipe; struct skl_module_deferred_bind *modules, *tmp; if (s_pipe->state == SKL_PIPE_INVALID) return -EINVAL; - - skl_tplg_free_pipe_mcps(skl, mconfig); - skl_tplg_free_pipe_mem(skl, mconfig); list_for_each_entry(w_module, &s_pipe->w_list, node) { if (list_empty(&skl->bind_list)) @@ -1318,7 +1228,7 @@ * modules from deferred bind list. */ if (modules->dst == src_module) { - skl_unbind_modules(ctx, modules->src, + skl_unbind_modules(skl, modules->src, modules->dst); } @@ -1338,44 +1248,40 @@ list_for_each_entry(w_module, &s_pipe->w_list, node) { dst_module = w_module->w->priv; - if (mconfig->m_state >= SKL_MODULE_INIT_DONE) - skl_tplg_free_pipe_mcps(skl, dst_module); if (src_module == NULL) { src_module = dst_module; continue; } - skl_unbind_modules(ctx, src_module, dst_module); + skl_unbind_modules(skl, src_module, dst_module); src_module = dst_module; } - skl_delete_pipe(ctx, mconfig->pipe); + skl_delete_pipe(skl, mconfig->pipe); list_for_each_entry(w_module, &s_pipe->w_list, node) { src_module = w_module->w->priv; src_module->m_state = SKL_MODULE_UNINIT; } - return skl_tplg_unload_pipe_modules(ctx, s_pipe); + return skl_tplg_unload_pipe_modules(skl, s_pipe); } /* * in the Post-PMD event of PGA we need to do following: - * - Free the mcps used * - Stop the pipeline * - In source pipe is connected, unbind with source pipelines */ static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, - struct skl *skl) + struct skl_dev *skl) { struct skl_module_cfg *src_mconfig, *sink_mconfig; int ret = 0, i; - struct skl_sst *ctx = skl->skl_sst; src_mconfig = w->priv; /* Stop the pipe since this is a mixin module */ - ret = skl_stop_pipe(ctx, src_mconfig->pipe); + ret = skl_stop_pipe(skl, src_mconfig->pipe); if (ret) return ret; @@ -1388,7 +1294,7 @@ * This is a connecter and if path is found that means * unbind between source and sink has not happened yet */ - ret = skl_unbind_modules(ctx, src_mconfig, + ret = skl_unbind_modules(skl, src_mconfig, sink_mconfig); } } @@ -1406,7 +1312,7 @@ struct snd_kcontrol *k, int event) { struct snd_soc_dapm_context *dapm = w->dapm; - struct skl *skl = get_skl_ctx(dapm->dev); + struct skl_dev *skl = get_skl_ctx(dapm->dev); switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -1436,7 +1342,7 @@ { struct snd_soc_dapm_context *dapm = w->dapm; - struct skl *skl = get_skl_ctx(dapm->dev); + struct skl_dev *skl = get_skl_ctx(dapm->dev); switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -1449,6 +1355,68 @@ return 0; } +static int skl_tplg_multi_config_set_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol, + bool is_set) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct hdac_bus *bus = snd_soc_component_get_drvdata(component); + struct skl_dev *skl = bus_to_skl(bus); + struct skl_pipeline *ppl; + struct skl_pipe *pipe = NULL; + struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value; + u32 *pipe_id; + + if (!ec) + return -EINVAL; + + if (is_set && ucontrol->value.enumerated.item[0] > ec->items) + return -EINVAL; + + pipe_id = ec->dobj.private; + + list_for_each_entry(ppl, &skl->ppl_list, node) { + if (ppl->pipe->ppl_id == *pipe_id) { + pipe = ppl->pipe; + break; + } + } + if (!pipe) + return -EIO; + + if (is_set) + pipe->pipe_config_idx = ucontrol->value.enumerated.item[0]; + else + ucontrol->value.enumerated.item[0] = pipe->pipe_config_idx; + + return 0; +} + +static int skl_tplg_multi_config_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return skl_tplg_multi_config_set_get(kcontrol, ucontrol, false); +} + +static int skl_tplg_multi_config_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return skl_tplg_multi_config_set_get(kcontrol, ucontrol, true); +} + +static int skl_tplg_multi_config_get_dmic(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return skl_tplg_multi_config_set_get(kcontrol, ucontrol, false); +} + +static int skl_tplg_multi_config_set_dmic(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return skl_tplg_multi_config_set_get(kcontrol, ucontrol, true); +} + static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol, unsigned int __user *data, unsigned int size) { @@ -1457,10 +1425,10 @@ struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private; struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); struct skl_module_cfg *mconfig = w->priv; - struct skl *skl = get_skl_ctx(w->dapm->dev); + struct skl_dev *skl = get_skl_ctx(w->dapm->dev); if (w->power) - skl_get_module_params(skl->skl_sst, (u32 *)bc->params, + skl_get_module_params(skl, (u32 *)bc->params, bc->size, bc->param_id, mconfig); /* decrement size for TLV header */ @@ -1492,28 +1460,18 @@ struct soc_bytes_ext *sb = (struct soc_bytes_ext *)kcontrol->private_value; struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private; - struct skl *skl = get_skl_ctx(w->dapm->dev); + struct skl_dev *skl = get_skl_ctx(w->dapm->dev); if (ac->params) { if (size > ac->max) return -EINVAL; - ac->size = size; - /* - * if the param_is is of type Vendor, firmware expects actual - * parameter id and size from the control. - */ - if (ac->param_id == SKL_PARAM_VENDOR_ID) { - if (copy_from_user(ac->params, data, size)) - return -EFAULT; - } else { - if (copy_from_user(ac->params, - data + 2, size)) - return -EFAULT; - } + + if (copy_from_user(ac->params, data, size)) + return -EFAULT; if (w->power) - return skl_set_module_params(skl->skl_sst, + return skl_set_module_params(skl, (u32 *)ac->params, ac->size, ac->param_id, mconfig); } @@ -1673,11 +1631,12 @@ struct skl_module_cfg *mconfig, struct skl_pipe_params *params) { - struct skl_module_res *res = &mconfig->module->resources[0]; - struct skl *skl = get_skl_ctx(dev); + struct skl_module_res *res; + struct skl_dev *skl = get_skl_ctx(dev); struct skl_module_fmt *format = NULL; u8 cfg_idx = mconfig->pipe->cur_config_idx; + res = &mconfig->module->resources[mconfig->res_idx]; skl_tplg_fill_dma_id(mconfig, params); mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx; mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx; @@ -1686,9 +1645,9 @@ return 0; if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) - format = &mconfig->module->formats[0].inputs[0].fmt; + format = &mconfig->module->formats[mconfig->fmt_idx].inputs[0].fmt; else - format = &mconfig->module->formats[0].outputs[0].fmt; + format = &mconfig->module->formats[mconfig->fmt_idx].outputs[0].fmt; /* set the hw_params */ format->s_freq = params->s_freq; @@ -1871,7 +1830,7 @@ struct skl_pipe_params *params) { struct nhlt_specific_cfg *cfg; - struct skl *skl = get_skl_ctx(dai->dev); + struct skl_dev *skl = get_skl_ctx(dai->dev); int link_type = skl_tplg_be_link_type(mconfig->dev_type); u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type); @@ -1929,7 +1888,7 @@ static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w, struct skl_pipe_params *params) { - struct snd_soc_dapm_path *p = NULL; + struct snd_soc_dapm_path *p; int ret = -EIO; snd_soc_dapm_widget_for_each_sink_path(w, p) { @@ -1992,6 +1951,16 @@ .get = skl_tplg_mic_control_get, .put = skl_tplg_mic_control_set, }, + { + .id = SKL_CONTROL_TYPE_MULTI_IO_SELECT, + .get = skl_tplg_multi_config_get, + .put = skl_tplg_multi_config_set, + }, + { + .id = SKL_CONTROL_TYPE_MULTI_IO_SELECT_DMIC, + .get = skl_tplg_multi_config_get_dmic, + .put = skl_tplg_multi_config_set_dmic, + } }; static int skl_tplg_fill_pipe_cfg(struct device *dev, @@ -2085,7 +2054,7 @@ * Return an existing pipe if the pipe already exists. */ static int skl_tplg_add_pipe(struct device *dev, - struct skl_module_cfg *mconfig, struct skl *skl, + struct skl_module_cfg *mconfig, struct skl_dev *skl, struct snd_soc_tplg_vendor_value_elem *tkn_elem) { struct skl_pipeline *ppl; @@ -2124,11 +2093,11 @@ return 0; } -static int skl_tplg_get_uuid(struct device *dev, u8 *guid, +static int skl_tplg_get_uuid(struct device *dev, guid_t *guid, struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn) { if (uuid_tkn->token == SKL_TKN_UUID) { - memcpy(guid, &uuid_tkn->uuid, 16); + import_guid(guid, uuid_tkn->uuid); return 0; } @@ -2154,7 +2123,7 @@ break; case SKL_TKN_UUID: - ret = skl_tplg_get_uuid(dev, m_pin[pin_index].id.mod_uuid.b, + ret = skl_tplg_get_uuid(dev, &m_pin[pin_index].id.mod_uuid, (struct snd_soc_tplg_vendor_uuid_elem *)tkn_elem); if (ret < 0) return ret; @@ -2345,10 +2314,6 @@ return -EINVAL; switch (tkn_elem->token) { - case SKL_TKN_MM_U32_CPS: - res->cps = tkn_elem->value; - break; - case SKL_TKN_MM_U32_DMA_SIZE: res->dma_buffer_size = tkn_elem->value; break; @@ -2369,16 +2334,17 @@ res->ibs = tkn_elem->value; break; - case SKL_TKN_U32_MAX_MCPS: - res->cps = tkn_elem->value; - break; - case SKL_TKN_MM_U32_RES_PIN_ID: case SKL_TKN_MM_U32_PIN_BUF: ret = skl_tplg_manifest_pin_res_tkn(dev, tkn_elem, res, pin_idx, dir); if (ret < 0) return ret; + break; + + case SKL_TKN_MM_U32_CPS: + case SKL_TKN_U32_MAX_MCPS: + /* ignore unused tokens */ break; default: @@ -2396,7 +2362,7 @@ */ static int skl_tplg_get_token(struct device *dev, struct snd_soc_tplg_vendor_value_elem *tkn_elem, - struct skl *skl, struct skl_module_cfg *mconfig) + struct skl_dev *skl, struct skl_module_cfg *mconfig) { int tkn_count = 0; int ret; @@ -2646,7 +2612,7 @@ * module private data */ static int skl_tplg_get_tokens(struct device *dev, - char *pvt_data, struct skl *skl, + char *pvt_data, struct skl_dev *skl, struct skl_module_cfg *mconfig, int block_size) { struct snd_soc_tplg_vendor_array *array; @@ -2670,7 +2636,7 @@ case SND_SOC_TPLG_TUPLE_TYPE_UUID: if (is_module_guid) { - ret = skl_tplg_get_uuid(dev, mconfig->guid, + ret = skl_tplg_get_uuid(dev, (guid_t *)mconfig->guid, array->uuid); is_module_guid = false; } else { @@ -2742,8 +2708,8 @@ * Otherwise we create a new instance and add into driver list */ static int skl_tplg_add_pipe_v4(struct device *dev, - struct skl_module_cfg *mconfig, struct skl *skl, - struct skl_dfw_v4_pipe *dfw_pipe) + struct skl_module_cfg *mconfig, struct skl_dev *skl, + struct skl_dfw_v4_pipe *dfw_pipe) { struct skl_pipeline *ppl; struct skl_pipe *pipe; @@ -2819,7 +2785,7 @@ } static int skl_tplg_get_pvt_data_v4(struct snd_soc_tplg_dapm_widget *tplg_w, - struct skl *skl, struct device *dev, + struct skl_dev *skl, struct device *dev, struct skl_module_cfg *mconfig) { struct skl_dfw_v4_module *dfw = @@ -2833,7 +2799,7 @@ return ret; mconfig->id.module_id = -1; mconfig->id.instance_id = dfw->instance_id; - mconfig->module->resources[0].cps = dfw->max_mcps; + mconfig->module->resources[0].cpc = dfw->max_mcps / 1000; mconfig->module->resources[0].ibs = dfw->ibs; mconfig->module->resources[0].obs = dfw->obs; mconfig->core_id = dfw->core_id; @@ -2901,11 +2867,11 @@ * for the type and size of the suceeding data block. */ static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w, - struct skl *skl, struct device *dev, + struct skl_dev *skl, struct device *dev, struct skl_module_cfg *mconfig) { struct snd_soc_tplg_vendor_array *array; - int num_blocks, block_size = 0, block_type, off = 0; + int num_blocks, block_size, block_type, off = 0; char *data; int ret; @@ -2996,9 +2962,8 @@ } } -void skl_cleanup_resources(struct skl *skl) +void skl_cleanup_resources(struct skl_dev *skl) { - struct skl_sst *ctx = skl->skl_sst; struct snd_soc_component *soc_component = skl->component; struct snd_soc_dapm_widget *w; struct snd_soc_card *card; @@ -3010,15 +2975,12 @@ if (!card || !card->instantiated) return; - skl->resource.mem = 0; - skl->resource.mcps = 0; - list_for_each_entry(w, &card->widgets, list) { - if (is_skl_dsp_widget_type(w, ctx->dev) && w->priv != NULL) + if (is_skl_dsp_widget_type(w, skl->dev) && w->priv != NULL) skl_clear_pin_config(soc_component, w); } - skl_clear_module_cnt(ctx->dsp); + skl_clear_module_cnt(skl->dsp); } /* @@ -3034,7 +2996,7 @@ { int ret; struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); struct skl_module_cfg *mconfig; if (!tplg_w->priv.size) @@ -3104,7 +3066,7 @@ ac->size = dfw_ac->max; if (ac->max) { - ac->params = (char *) devm_kzalloc(dev, ac->max, GFP_KERNEL); + ac->params = devm_kzalloc(dev, ac->max, GFP_KERNEL); if (!ac->params) return -ENOMEM; @@ -3159,12 +3121,21 @@ case SND_SOC_TPLG_CTL_ENUM: tplg_ec = container_of(hdr, struct snd_soc_tplg_enum_control, hdr); - if (kctl->access & SNDRV_CTL_ELEM_ACCESS_READWRITE) { + if (kctl->access & SNDRV_CTL_ELEM_ACCESS_READ) { se = (struct soc_enum *)kctl->private_value; if (tplg_ec->priv.size) - return skl_init_enum_data(bus->dev, se, - tplg_ec); + skl_init_enum_data(bus->dev, se, tplg_ec); } + + /* + * now that the control initializations are done, remove + * write permission for the DMIC configuration enums to + * avoid conflicts between NHLT settings and user interaction + */ + + if (hdr->ops.get == SKL_CONTROL_TYPE_MULTI_IO_SELECT_DMIC) + kctl->access = SNDRV_CTL_ELEM_ACCESS_READ; + break; default: @@ -3178,21 +3149,21 @@ static int skl_tplg_fill_str_mfest_tkn(struct device *dev, struct snd_soc_tplg_vendor_string_elem *str_elem, - struct skl *skl) + struct skl_dev *skl) { int tkn_count = 0; static int ref_count; switch (str_elem->token) { case SKL_TKN_STR_LIB_NAME: - if (ref_count > skl->skl_sst->lib_count - 1) { + if (ref_count > skl->lib_count - 1) { ref_count = 0; return -EINVAL; } - strncpy(skl->skl_sst->lib_info[ref_count].name, + strncpy(skl->lib_info[ref_count].name, str_elem->string, - ARRAY_SIZE(skl->skl_sst->lib_info[ref_count].name)); + ARRAY_SIZE(skl->lib_info[ref_count].name)); ref_count++; break; @@ -3207,7 +3178,7 @@ static int skl_tplg_get_str_tkn(struct device *dev, struct snd_soc_tplg_vendor_array *array, - struct skl *skl) + struct skl_dev *skl) { int tkn_count = 0, ret; struct snd_soc_tplg_vendor_string_elem *str_elem; @@ -3314,9 +3285,9 @@ static int skl_tplg_get_int_tkn(struct device *dev, struct snd_soc_tplg_vendor_value_elem *tkn_elem, - struct skl *skl) + struct skl_dev *skl) { - int tkn_count = 0, ret, size; + int tkn_count = 0, ret; static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx; struct skl_module_res *res = NULL; struct skl_module_iface *fmt = NULL; @@ -3324,6 +3295,7 @@ static struct skl_astate_param *astate_table; static int astate_cfg_idx, count; int i; + size_t size; if (skl->modules) { mod = skl->modules[mod_idx]; @@ -3333,7 +3305,7 @@ switch (tkn_elem->token) { case SKL_TKN_U32_LIB_COUNT: - skl->skl_sst->lib_count = tkn_elem->value; + skl->lib_count = tkn_elem->value; break; case SKL_TKN_U8_NUM_MOD: @@ -3367,8 +3339,8 @@ return -EINVAL; } - size = tkn_elem->value * sizeof(struct skl_astate_param) + - sizeof(count); + size = struct_size(skl->cfg.astate_cfg, astate_table, + tkn_elem->value); skl->cfg.astate_cfg = devm_kzalloc(dev, size, GFP_KERNEL); if (!skl->cfg.astate_cfg) return -ENOMEM; @@ -3479,35 +3451,17 @@ return tkn_count; } -static int skl_tplg_get_manifest_uuid(struct device *dev, - struct skl *skl, - struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn) -{ - static int ref_count; - struct skl_module *mod; - - if (uuid_tkn->token == SKL_TKN_UUID) { - mod = skl->modules[ref_count]; - memcpy(&mod->uuid, &uuid_tkn->uuid, sizeof(uuid_tkn->uuid)); - ref_count++; - } else { - dev_err(dev, "Not an UUID token tkn %d\n", uuid_tkn->token); - return -EINVAL; - } - - return 0; -} - /* * Fill the manifest structure by parsing the tokens based on the * type. */ static int skl_tplg_get_manifest_tkn(struct device *dev, - char *pvt_data, struct skl *skl, + char *pvt_data, struct skl_dev *skl, int block_size) { int tkn_count = 0, ret; int off = 0, tuple_size = 0; + u8 uuid_index = 0; struct snd_soc_tplg_vendor_array *array; struct snd_soc_tplg_vendor_value_elem *tkn_elem; @@ -3530,9 +3484,17 @@ continue; case SND_SOC_TPLG_TUPLE_TYPE_UUID: - ret = skl_tplg_get_manifest_uuid(dev, skl, array->uuid); - if (ret < 0) - return ret; + if (array->uuid->token != SKL_TKN_UUID) { + dev_err(dev, "Not an UUID token: %d\n", + array->uuid->token); + return -EINVAL; + } + if (uuid_index >= skl->nr_modules) { + dev_err(dev, "Too many UUID tokens\n"); + return -EINVAL; + } + import_guid(&skl->modules[uuid_index++]->uuid, + array->uuid->uuid); tuple_size += sizeof(*array->uuid); continue; @@ -3564,7 +3526,7 @@ * preceded by descriptors for type and size of data block. */ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest, - struct device *dev, struct skl *skl) + struct device *dev, struct skl_dev *skl) { struct snd_soc_tplg_vendor_array *array; int num_blocks, block_size = 0, block_type, off = 0; @@ -3626,7 +3588,7 @@ struct snd_soc_tplg_manifest *manifest) { struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); /* proceed only if we have private data defined */ if (manifest->priv.size == 0) @@ -3634,13 +3596,45 @@ skl_tplg_get_manifest_data(manifest, bus->dev, skl); - if (skl->skl_sst->lib_count > SKL_MAX_LIB) { + if (skl->lib_count > SKL_MAX_LIB) { dev_err(bus->dev, "Exceeding max Library count. Got:%d\n", - skl->skl_sst->lib_count); + skl->lib_count); return -EINVAL; } return 0; +} + +static void skl_tplg_complete(struct snd_soc_component *component) +{ + struct snd_soc_dobj *dobj; + struct snd_soc_acpi_mach *mach = + dev_get_platdata(component->card->dev); + int i; + + list_for_each_entry(dobj, &component->dobj_list, list) { + struct snd_kcontrol *kcontrol = dobj->control.kcontrol; + struct soc_enum *se; + char **texts; + char chan_text[4]; + + if (dobj->type != SND_SOC_DOBJ_ENUM || !kcontrol || + kcontrol->put != skl_tplg_multi_config_set_dmic) + continue; + + se = (struct soc_enum *)kcontrol->private_value; + texts = dobj->control.dtexts; + sprintf(chan_text, "c%d", mach->mach_params.dmic_num); + + for (i = 0; i < se->items; i++) { + struct snd_ctl_elem_value val = {}; + + if (strstr(texts[i], chan_text)) { + val.value.enumerated.item[0] = i; + kcontrol->put(kcontrol, &val); + } + } + } } static struct snd_soc_tplg_ops skl_tplg_ops = { @@ -3652,6 +3646,7 @@ .io_ops_count = ARRAY_SIZE(skl_tplg_kcontrol_ops), .manifest = skl_manifest_load, .dai_load = skl_dai_load, + .complete = skl_tplg_complete, }; /* @@ -3685,7 +3680,7 @@ return 0; } -static void skl_tplg_set_pipe_type(struct skl *skl, struct skl_pipe *pipe) +static void skl_tplg_set_pipe_type(struct skl_dev *skl, struct skl_pipe *pipe) { struct skl_pipe_module *w_module; struct snd_soc_dapm_widget *w; @@ -3708,10 +3703,6 @@ pipe->passthru = false; } -/* This will be read from topology manifest, currently defined here */ -#define SKL_MAX_MCPS 30000000 -#define SKL_FW_MAX_MEM 1000000 - /* * SKL topology init routine */ @@ -3719,13 +3710,25 @@ { int ret; const struct firmware *fw; - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); struct skl_pipeline *ppl; ret = request_firmware(&fw, skl->tplg_name, bus->dev); if (ret < 0) { - dev_info(bus->dev, "tplg fw %s load failed with %d, falling back to dfw_sst.bin", - skl->tplg_name, ret); + char alt_tplg_name[64]; + + snprintf(alt_tplg_name, sizeof(alt_tplg_name), "%s-tplg.bin", + skl->mach->drv_name); + dev_info(bus->dev, "tplg fw %s load failed with %d, trying alternative tplg name %s", + skl->tplg_name, ret, alt_tplg_name); + + ret = request_firmware(&fw, alt_tplg_name, bus->dev); + if (!ret) + goto component_load; + + dev_info(bus->dev, "tplg %s failed with %d, falling back to dfw_sst.bin", + alt_tplg_name, ret); + ret = request_firmware(&fw, "dfw_sst.bin", bus->dev); if (ret < 0) { dev_err(bus->dev, "Fallback tplg fw %s load failed with %d\n", @@ -3734,28 +3737,41 @@ } } +component_load: + /* * The complete tplg for SKL is loaded as index 0, we don't use * any other index */ - ret = snd_soc_tplg_component_load(component, - &skl_tplg_ops, fw, 0); + ret = snd_soc_tplg_component_load(component, &skl_tplg_ops, fw, 0); if (ret < 0) { dev_err(bus->dev, "tplg component load failed%d\n", ret); - release_firmware(fw); - return -EINVAL; + goto err; } - skl->resource.max_mcps = SKL_MAX_MCPS; - skl->resource.max_mem = SKL_FW_MAX_MEM; - - skl->tplg = fw; ret = skl_tplg_create_pipe_widget_list(component); - if (ret < 0) - return ret; + if (ret < 0) { + dev_err(bus->dev, "tplg create pipe widget list failed%d\n", + ret); + goto err; + } list_for_each_entry(ppl, &skl->ppl_list, node) skl_tplg_set_pipe_type(skl, ppl->pipe); - return 0; +err: + release_firmware(fw); + return ret; +} + +void skl_tplg_exit(struct snd_soc_component *component, struct hdac_bus *bus) +{ + struct skl_dev *skl = bus_to_skl(bus); + struct skl_pipeline *ppl, *tmp; + + list_for_each_entry_safe(ppl, tmp, &skl->ppl_list, node) + list_del(&ppl->node); + + /* clean up topology */ + snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL); } -- Gitblit v1.6.2