|
@@ -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);
|