diff options
Diffstat (limited to 'sound/soc/intel/skylake/skl-topology.c')
-rw-r--r-- | sound/soc/intel/skylake/skl-topology.c | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 3b1dca419883..9e4c2cb88dea 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -19,6 +19,7 @@ #include <linux/slab.h> #include <linux/types.h> #include <linux/firmware.h> +#include <linux/uuid.h> #include <sound/soc.h> #include <sound/soc-topology.h> #include <uapi/sound/snd_sst_tokens.h> @@ -2724,6 +2725,167 @@ static int skl_tplg_get_desc_blocks(struct device *dev, return -EINVAL; } +/* Functions to parse private data from configuration file format v4 */ + +/* + * Add pipeline from topology binary into driver pipeline list + * + * If already added we return that instance + * 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_pipeline *ppl; + struct skl_pipe *pipe; + struct skl_pipe_params *params; + + list_for_each_entry(ppl, &skl->ppl_list, node) { + if (ppl->pipe->ppl_id == dfw_pipe->pipe_id) { + mconfig->pipe = ppl->pipe; + return 0; + } + } + + ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL); + if (!ppl) + return -ENOMEM; + + pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL); + if (!pipe) + return -ENOMEM; + + params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL); + if (!params) + return -ENOMEM; + + pipe->ppl_id = dfw_pipe->pipe_id; + pipe->memory_pages = dfw_pipe->memory_pages; + pipe->pipe_priority = dfw_pipe->pipe_priority; + pipe->conn_type = dfw_pipe->conn_type; + pipe->state = SKL_PIPE_INVALID; + pipe->p_params = params; + INIT_LIST_HEAD(&pipe->w_list); + + ppl->pipe = pipe; + list_add(&ppl->node, &skl->ppl_list); + + mconfig->pipe = pipe; + + return 0; +} + +static void skl_fill_module_pin_info_v4(struct skl_dfw_v4_module_pin *dfw_pin, + struct skl_module_pin *m_pin, + bool is_dynamic, int max_pin) +{ + int i; + + for (i = 0; i < max_pin; i++) { + m_pin[i].id.module_id = dfw_pin[i].module_id; + m_pin[i].id.instance_id = dfw_pin[i].instance_id; + m_pin[i].in_use = false; + m_pin[i].is_dynamic = is_dynamic; + m_pin[i].pin_state = SKL_PIN_UNBIND; + } +} + +static void skl_tplg_fill_fmt_v4(struct skl_module_pin_fmt *dst_fmt, + struct skl_dfw_v4_module_fmt *src_fmt, + int pins) +{ + int i; + + for (i = 0; i < pins; i++) { + dst_fmt[i].fmt.channels = src_fmt[i].channels; + dst_fmt[i].fmt.s_freq = src_fmt[i].freq; + dst_fmt[i].fmt.bit_depth = src_fmt[i].bit_depth; + dst_fmt[i].fmt.valid_bit_depth = src_fmt[i].valid_bit_depth; + dst_fmt[i].fmt.ch_cfg = src_fmt[i].ch_cfg; + dst_fmt[i].fmt.ch_map = src_fmt[i].ch_map; + dst_fmt[i].fmt.interleaving_style = + src_fmt[i].interleaving_style; + dst_fmt[i].fmt.sample_type = src_fmt[i].sample_type; + } +} + +static int skl_tplg_get_pvt_data_v4(struct snd_soc_tplg_dapm_widget *tplg_w, + struct skl *skl, struct device *dev, + struct skl_module_cfg *mconfig) +{ + struct skl_dfw_v4_module *dfw = + (struct skl_dfw_v4_module *)tplg_w->priv.data; + int ret; + + dev_dbg(dev, "Parsing Skylake v4 widget topology data\n"); + + ret = guid_parse(dfw->uuid, (guid_t *)mconfig->guid); + if (ret) + 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].ibs = dfw->ibs; + mconfig->module->resources[0].obs = dfw->obs; + mconfig->core_id = dfw->core_id; + mconfig->module->max_input_pins = dfw->max_in_queue; + mconfig->module->max_output_pins = dfw->max_out_queue; + mconfig->module->loadable = dfw->is_loadable; + skl_tplg_fill_fmt_v4(mconfig->module->formats[0].inputs, dfw->in_fmt, + MAX_IN_QUEUE); + skl_tplg_fill_fmt_v4(mconfig->module->formats[0].outputs, dfw->out_fmt, + MAX_OUT_QUEUE); + + mconfig->params_fixup = dfw->params_fixup; + mconfig->converter = dfw->converter; + mconfig->m_type = dfw->module_type; + mconfig->vbus_id = dfw->vbus_id; + mconfig->module->resources[0].is_pages = dfw->mem_pages; + + ret = skl_tplg_add_pipe_v4(dev, mconfig, skl, &dfw->pipe); + if (ret) + return ret; + + mconfig->dev_type = dfw->dev_type; + mconfig->hw_conn_type = dfw->hw_conn_type; + mconfig->time_slot = dfw->time_slot; + mconfig->formats_config.caps_size = dfw->caps.caps_size; + + mconfig->m_in_pin = devm_kzalloc(dev, + MAX_IN_QUEUE * sizeof(*mconfig->m_in_pin), + GFP_KERNEL); + if (!mconfig->m_in_pin) + return -ENOMEM; + + mconfig->m_out_pin = devm_kzalloc(dev, + MAX_OUT_QUEUE * sizeof(*mconfig->m_out_pin), + GFP_KERNEL); + if (!mconfig->m_out_pin) + return -ENOMEM; + + skl_fill_module_pin_info_v4(dfw->in_pin, mconfig->m_in_pin, + dfw->is_dynamic_in_pin, + mconfig->module->max_input_pins); + skl_fill_module_pin_info_v4(dfw->out_pin, mconfig->m_out_pin, + dfw->is_dynamic_out_pin, + mconfig->module->max_output_pins); + + if (mconfig->formats_config.caps_size) { + mconfig->formats_config.set_params = dfw->caps.set_params; + mconfig->formats_config.param_id = dfw->caps.param_id; + mconfig->formats_config.caps = + devm_kzalloc(dev, mconfig->formats_config.caps_size, + GFP_KERNEL); + if (!mconfig->formats_config.caps) + return -ENOMEM; + memcpy(mconfig->formats_config.caps, dfw->caps.caps, + dfw->caps.caps_size); + } + + return 0; +} + /* * Parse the private data for the token and corresponding value. * The private data can have multiple data blocks. So, a data block @@ -2739,6 +2901,13 @@ static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w, char *data; int ret; + /* + * v4 configuration files have a valid UUID at the start of + * the widget's private data. + */ + if (uuid_is_valid((char *)tplg_w->priv.data)) + return skl_tplg_get_pvt_data_v4(tplg_w, skl, dev, mconfig); + /* Read the NUM_DATA_BLOCKS descriptor */ array = (struct snd_soc_tplg_vendor_array *)tplg_w->priv.data; ret = skl_tplg_get_desc_blocks(dev, array); |