ASoC: Intel: Skylake: Parse manifest data
authorShreyas NC <shreyas.nc@intel.com>
Tue, 23 Aug 2016 04:01:03 +0000 (09:31 +0530)
committerMark Brown <broonie@kernel.org>
Tue, 23 Aug 2016 11:35:45 +0000 (12:35 +0100)
Topology manifest has lib names and lib count info. So,
define tokens to represent module private data and parse
these tokens to fill up the manifest structure in the driver
accordingly.

Signed-off-by: Shreyas NC <shreyas.nc@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
include/uapi/sound/snd_sst_tokens.h
sound/soc/intel/skylake/skl-topology.c

index f56a932736ca093d123a21855c8a94b2b24a5603..1ee2e943d66a319c6d0536b9deb96b3ea95c5be9 100644 (file)
  *
  * %SKL_TKN_U32_PROC_DOMAIN:    Specify processing domain
  *
+ * %SKL_TKN_U32_LIB_COUNT:      Specifies the number of libraries
+ *
+ * %SKL_TKN_STR_LIB_NAME:       Specifies the library name
+ *
  * module_id and loadable flags dont have tokens as these values will be
  * read from the DSP FW manifest
  */
@@ -202,7 +206,9 @@ enum SKL_TKNS {
        SKL_TKN_U32_CAPS_PARAMS_ID,
        SKL_TKN_U32_CAPS_SIZE,
        SKL_TKN_U32_PROC_DOMAIN,
-       SKL_TKN_MAX = SKL_TKN_U32_PROC_DOMAIN,
+       SKL_TKN_U32_LIB_COUNT,
+       SKL_TKN_STR_LIB_NAME,
+       SKL_TKN_MAX = SKL_TKN_STR_LIB_NAME,
 };
 
 #endif
index 000482e6e2f7da3df46be4fa89616b709a042612..108ebb9ab3291ca5cf939dc7db9142cba344be5d 100644 (file)
@@ -2201,6 +2201,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)
 {
@@ -2211,7 +2402,8 @@ static int skl_manifest_load(struct snd_soc_component *cmpnt,
        int ret = 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",