ASoC: Intel: Skylake: Update to use instance ids generated
[cascardo/linux.git] / sound / soc / intel / skylake / skl-topology.c
index 000482e..e48f872 100644 (file)
@@ -505,12 +505,15 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
                 * FE/BE params
                 */
                skl_tplg_update_module_params(w, ctx);
-
+               mconfig->id.pvt_id = skl_get_pvt_id(ctx, mconfig);
+               if (mconfig->id.pvt_id < 0)
+                       return ret;
                skl_tplg_set_module_init_data(w);
                ret = skl_init_module(ctx, mconfig);
-               if (ret < 0)
+               if (ret < 0) {
+                       skl_put_pvt_id(ctx, mconfig);
                        return ret;
-
+               }
                skl_tplg_alloc_pipe_mcps(skl, mconfig);
                ret = skl_tplg_set_module_params(w, ctx);
                if (ret < 0)
@@ -523,6 +526,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
 static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
         struct skl_pipe *pipe)
 {
+       int ret;
        struct skl_pipe_module *w_module = NULL;
        struct skl_module_cfg *mconfig = NULL;
 
@@ -530,9 +534,13 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
                mconfig  = w_module->w->priv;
 
                if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod &&
-                       mconfig->m_state > SKL_MODULE_UNINIT)
-                       return ctx->dsp->fw_ops.unload_mod(ctx->dsp,
+                       mconfig->m_state > SKL_MODULE_UNINIT) {
+                       ret = ctx->dsp->fw_ops.unload_mod(ctx->dsp,
                                                mconfig->id.module_id);
+                       if (ret < 0)
+                               return -EIO;
+               }
+               skl_put_pvt_id(ctx, mconfig);
        }
 
        /* no modules to unload in this path, so return */
@@ -599,6 +607,26 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
+static int skl_fill_sink_instance_id(struct skl_sst *ctx,
+                               struct skl_algo_data *alg_data)
+{
+       struct skl_kpb_params *params = (struct skl_kpb_params *)alg_data->params;
+       struct skl_mod_inst_map *inst;
+       int i, pvt_id;
+
+       inst = params->map;
+
+       for (i = 0; i < params->num_modules; i++) {
+               pvt_id = skl_get_pvt_instance_id_map(ctx,
+                                       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.
@@ -647,6 +675,8 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w,
                        bc = (struct skl_algo_data *)sb->dobj.private;
 
                        if (bc->set_params == SKL_PARAM_BIND) {
+                               if (mconfig->m_type == SKL_MODULE_TYPE_KPB)
+                                       skl_fill_sink_instance_id(ctx, bc);
                                ret = skl_set_module_params(ctx,
                                                (u32 *)bc->params, bc->max,
                                                bc->param_id, mconfig);
@@ -2201,6 +2231,197 @@ static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
        return 0;
 }
 
+static int skl_tplg_fill_str_mfest_tkn(struct device *dev,
+               struct snd_soc_tplg_vendor_string_elem *str_elem,
+               struct skl_dfw_manifest *minfo)
+{
+       int tkn_count = 0;
+       static int ref_count;
+
+       switch (str_elem->token) {
+       case SKL_TKN_STR_LIB_NAME:
+               if (ref_count > minfo->lib_count - 1) {
+                       ref_count = 0;
+                       return -EINVAL;
+               }
+
+               strncpy(minfo->lib[ref_count].name, str_elem->string,
+                               ARRAY_SIZE(minfo->lib[ref_count].name));
+               ref_count++;
+               tkn_count++;
+               break;
+
+       default:
+               dev_err(dev, "Not a string token %d", str_elem->token);
+               break;
+       }
+
+       return tkn_count;
+}
+
+static int skl_tplg_get_str_tkn(struct device *dev,
+               struct snd_soc_tplg_vendor_array *array,
+               struct skl_dfw_manifest *minfo)
+{
+       int tkn_count = 0, ret;
+       struct snd_soc_tplg_vendor_string_elem *str_elem;
+
+       str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value;
+       while (tkn_count < array->num_elems) {
+               ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, minfo);
+               str_elem++;
+
+               if (ret < 0)
+                       return ret;
+
+               tkn_count = tkn_count + ret;
+       }
+
+       return tkn_count;
+}
+
+static int skl_tplg_get_int_tkn(struct device *dev,
+               struct snd_soc_tplg_vendor_value_elem *tkn_elem,
+               struct skl_dfw_manifest *minfo)
+{
+       int tkn_count = 0;
+
+       switch (tkn_elem->token) {
+       case SKL_TKN_U32_LIB_COUNT:
+               minfo->lib_count = tkn_elem->value;
+               tkn_count++;
+               break;
+
+       default:
+               dev_err(dev, "Not a manifest token %d", tkn_elem->token);
+               return -EINVAL;
+       }
+
+       return tkn_count;
+}
+
+/*
+ * 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_dfw_manifest *minfo,
+               int block_size)
+{
+       int tkn_count = 0, ret;
+       int off = 0, tuple_size = 0;
+       struct snd_soc_tplg_vendor_array *array;
+       struct snd_soc_tplg_vendor_value_elem *tkn_elem;
+
+       if (block_size <= 0)
+               return -EINVAL;
+
+       while (tuple_size < block_size) {
+               array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
+               off += array->size;
+               switch (array->type) {
+               case SND_SOC_TPLG_TUPLE_TYPE_STRING:
+                       ret = skl_tplg_get_str_tkn(dev, array, minfo);
+
+                       if (ret < 0)
+                               return ret;
+                       tkn_count += ret;
+
+                       tuple_size += tkn_count *
+                               sizeof(struct snd_soc_tplg_vendor_string_elem);
+                       continue;
+
+               case SND_SOC_TPLG_TUPLE_TYPE_UUID:
+                       dev_warn(dev, "no uuid tokens for skl tplf manifest");
+                       continue;
+
+               default:
+                       tkn_elem = array->value;
+                       tkn_count = 0;
+                       break;
+               }
+
+               while (tkn_count <= array->num_elems - 1) {
+                       ret = skl_tplg_get_int_tkn(dev,
+                                       tkn_elem, minfo);
+                       if (ret < 0)
+                               return ret;
+
+                       tkn_count = tkn_count + ret;
+                       tkn_elem++;
+                       tuple_size += tkn_count *
+                               sizeof(struct snd_soc_tplg_vendor_value_elem);
+                       break;
+               }
+               tkn_count = 0;
+       }
+
+       return 0;
+}
+
+/*
+ * Parse manifest private data for tokens. The private data block is
+ * 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_dfw_manifest *minfo)
+{
+       struct snd_soc_tplg_vendor_array *array;
+       int num_blocks, block_size = 0, block_type, off = 0;
+       char *data;
+       int ret;
+
+       /* Read the NUM_DATA_BLOCKS descriptor */
+       array = (struct snd_soc_tplg_vendor_array *)manifest->priv.data;
+       ret = skl_tplg_get_desc_blocks(dev, array);
+       if (ret < 0)
+               return ret;
+       num_blocks = ret;
+
+       off += array->size;
+       array = (struct snd_soc_tplg_vendor_array *)
+                       (manifest->priv.data + off);
+
+       /* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
+       while (num_blocks > 0) {
+               ret = skl_tplg_get_desc_blocks(dev, array);
+
+               if (ret < 0)
+                       return ret;
+               block_type = ret;
+               off += array->size;
+
+               array = (struct snd_soc_tplg_vendor_array *)
+                       (manifest->priv.data + off);
+
+               ret = skl_tplg_get_desc_blocks(dev, array);
+
+               if (ret < 0)
+                       return ret;
+               block_size = ret;
+               off += array->size;
+
+               array = (struct snd_soc_tplg_vendor_array *)
+                       (manifest->priv.data + off);
+
+               data = (manifest->priv.data + off);
+
+               if (block_type == SKL_TYPE_TUPLE) {
+                       ret = skl_tplg_get_manifest_tkn(dev, data, minfo,
+                                       block_size);
+
+                       if (ret < 0)
+                               return ret;
+
+                       --num_blocks;
+               } else {
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
 static int skl_manifest_load(struct snd_soc_component *cmpnt,
                                struct snd_soc_tplg_manifest *manifest)
 {
@@ -2210,8 +2431,13 @@ static int skl_manifest_load(struct snd_soc_component *cmpnt,
        struct skl *skl = ebus_to_skl(ebus);
        int ret = 0;
 
+       /* proceed only if we have private data defined */
+       if (manifest->priv.size == 0)
+               return 0;
+
        minfo = &skl->skl_sst->manifest;
-       memcpy(minfo, manifest->priv.data, sizeof(struct skl_dfw_manifest));
+
+       skl_tplg_get_manifest_data(manifest, bus->dev, minfo);
 
        if (minfo->lib_count > HDA_MAX_LIB) {
                dev_err(bus->dev, "Exceeding max Library count. Got:%d\n",