OSDN Git Service

ASoC: SOF: Add a new IPC op for parsing topology manifest
authorRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Thu, 9 Jun 2022 03:26:40 +0000 (20:26 -0700)
committerMark Brown <broonie@kernel.org>
Fri, 10 Jun 2022 12:32:08 +0000 (13:32 +0100)
Add a new topology IPC op, parse_manifest. Define and set the op for
IPC4 and IPC4.

Co-developed-by: Jaska Uimonen <jaska.uimonen@linux.intel.com>
Signed-off-by: Jaska Uimonen <jaska.uimonen@linux.intel.com>
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Link: https://lore.kernel.org/r/20220609032643.916882-21-ranjani.sridharan@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sof/ipc3-topology.c
sound/soc/sof/ipc4-topology.c
sound/soc/sof/sof-audio.h
sound/soc/sof/topology.c

index 043554d..a91d7df 100644 (file)
@@ -17,6 +17,9 @@
 /* Full volume for default values */
 #define VOL_ZERO_DB    BIT(VOLUME_FWL)
 
+/* size of tplg ABI in bytes */
+#define SOF_IPC3_TPLG_ABI_SIZE 3
+
 struct sof_widget_data {
        int ctrl_type;
        int ipc_cmd;
@@ -2303,6 +2306,50 @@ static int sof_ipc3_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *da
        return -EINVAL;
 }
 
+static int sof_ipc3_parse_manifest(struct snd_soc_component *scomp, int index,
+                                  struct snd_soc_tplg_manifest *man)
+{
+       u32 size = le32_to_cpu(man->priv.size);
+       u32 abi_version;
+
+       /* backward compatible with tplg without ABI info */
+       if (!size) {
+               dev_dbg(scomp->dev, "No topology ABI info\n");
+               return 0;
+       }
+
+       if (size != SOF_IPC3_TPLG_ABI_SIZE) {
+               dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n",
+                       __func__, size);
+               return -EINVAL;
+       }
+
+       dev_info(scomp->dev,
+                "Topology: ABI %d:%d:%d Kernel ABI %hhu:%hhu:%hhu\n",
+                man->priv.data[0], man->priv.data[1], man->priv.data[2],
+                SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
+
+       abi_version = SOF_ABI_VER(man->priv.data[0], man->priv.data[1], man->priv.data[2]);
+
+       if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, abi_version)) {
+               dev_err(scomp->dev, "%s: Incompatible topology ABI version\n", __func__);
+               return -EINVAL;
+       }
+
+       if (SOF_ABI_VERSION_MINOR(abi_version) > SOF_ABI_MINOR) {
+               if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) {
+                       dev_warn(scomp->dev, "%s: Topology ABI is more recent than kernel\n",
+                                __func__);
+               } else {
+                       dev_err(scomp->dev, "%s: Topology ABI is more recent than kernel\n",
+                               __func__);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
 /* token list for each topology object */
 static enum sof_tokens host_token_list[] = {
        SOF_CORE_TOKENS,
@@ -2413,4 +2460,5 @@ const struct sof_ipc_tplg_ops ipc3_tplg_ops = {
        .dai_get_clk = sof_ipc3_dai_get_clk,
        .set_up_all_pipelines = sof_ipc3_set_up_all_pipelines,
        .tear_down_all_pipelines = sof_ipc3_tear_down_all_pipelines,
+       .parse_manifest = sof_ipc3_parse_manifest,
 };
index 9615034..27ad489 100644 (file)
@@ -16,6 +16,7 @@
 #include "ops.h"
 
 #define SOF_IPC4_GAIN_PARAM_ID  0
+#define SOF_IPC4_TPLG_ABI_SIZE 6
 
 static const struct sof_topology_token ipc4_sched_tokens[] = {
        {SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
@@ -1317,6 +1318,67 @@ static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *
        return 0;
 }
 
+static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index,
+                                  struct snd_soc_tplg_manifest *man)
+{
+       struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+       struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+       struct sof_manifest_tlv *manifest_tlv;
+       struct sof_manifest *manifest;
+       u32 size = le32_to_cpu(man->priv.size);
+       u8 *man_ptr = man->priv.data;
+       u32 len_check;
+       int i;
+
+       if (!size || size < SOF_IPC4_TPLG_ABI_SIZE) {
+               dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n",
+                       __func__, size);
+               return -EINVAL;
+       }
+
+       manifest = (struct sof_manifest *)man_ptr;
+
+       dev_info(scomp->dev,
+                "Topology: ABI %d:%d:%d Kernel ABI %u:%u:%u\n",
+                 le16_to_cpu(manifest->abi_major), le16_to_cpu(manifest->abi_minor),
+                 le16_to_cpu(manifest->abi_patch),
+                 SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
+
+       /* TODO: Add ABI compatibility check */
+
+       /* no more data after the ABI version */
+       if (size <= SOF_IPC4_TPLG_ABI_SIZE)
+               return 0;
+
+       manifest_tlv = manifest->items;
+       len_check = sizeof(struct sof_manifest);
+       for (i = 0; i < le16_to_cpu(manifest->count); i++) {
+               len_check += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size);
+               if (len_check > size)
+                       return -EINVAL;
+
+               switch (le32_to_cpu(manifest_tlv->type)) {
+               case SOF_MANIFEST_DATA_TYPE_NHLT:
+                       /* no NHLT in BIOS, so use the one from topology manifest */
+                       if (ipc4_data->nhlt)
+                               break;
+                       ipc4_data->nhlt = devm_kmemdup(sdev->dev, manifest_tlv->data,
+                                                      le32_to_cpu(manifest_tlv->size), GFP_KERNEL);
+                       if (!ipc4_data->nhlt)
+                               return -ENOMEM;
+                       break;
+               default:
+                       dev_warn(scomp->dev, "Skipping unknown manifest data type %d\n",
+                                manifest_tlv->type);
+                       break;
+               }
+               man_ptr += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size);
+               manifest_tlv = (struct sof_manifest_tlv *)man_ptr;
+       }
+
+       return 0;
+}
+
 static enum sof_tokens host_token_list[] = {
        SOF_COMP_TOKENS,
        SOF_AUDIO_FMT_NUM_TOKENS,
@@ -1402,4 +1464,5 @@ const struct sof_ipc_tplg_ops ipc4_tplg_ops = {
        .route_setup = sof_ipc4_route_setup,
        .route_free = sof_ipc4_route_free,
        .dai_config = sof_ipc4_dai_config,
+       .parse_manifest = sof_ipc4_parse_manifest,
 };
index d896da1..7948626 100644 (file)
@@ -168,6 +168,7 @@ struct sof_ipc_tplg_widget_ops {
  * @dai_get_clk: Function pointer for getting the DAI clock setting
  * @set_up_all_pipelines: Function pointer for setting up all topology pipelines
  * @tear_down_all_pipelines: Function pointer for tearing down all topology pipelines
+ * @parse_manifest: Optional function pointer for ipc4 specific parsing of topology manifest
  */
 struct sof_ipc_tplg_ops {
        const struct sof_ipc_tplg_widget_ops *widget;
@@ -185,6 +186,8 @@ struct sof_ipc_tplg_ops {
        int (*dai_get_clk)(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type);
        int (*set_up_all_pipelines)(struct snd_sof_dev *sdev, bool verify);
        int (*tear_down_all_pipelines)(struct snd_sof_dev *sdev, bool verify);
+       int (*parse_manifest)(struct snd_soc_component *scomp, int index,
+                             struct snd_soc_tplg_manifest *man);
 };
 
 /** struct snd_sof_tuple - Tuple info
index 606dbca..1893c59 100644 (file)
@@ -36,9 +36,6 @@
 #define TLV_STEP       1
 #define TLV_MUTE       2
 
-/* size of tplg abi in byte */
-#define SOF_TPLG_ABI_SIZE 3
-
 /**
  * sof_update_ipc_object - Parse multiple sets of tokens within the token array associated with the
  *                         token ID.
@@ -2020,45 +2017,11 @@ static int sof_complete(struct snd_soc_component *scomp)
 static int sof_manifest(struct snd_soc_component *scomp, int index,
                        struct snd_soc_tplg_manifest *man)
 {
-       u32 size;
-       u32 abi_version;
-
-       size = le32_to_cpu(man->priv.size);
-
-       /* backward compatible with tplg without ABI info */
-       if (!size) {
-               dev_dbg(scomp->dev, "No topology ABI info\n");
-               return 0;
-       }
-
-       if (size != SOF_TPLG_ABI_SIZE) {
-               dev_err(scomp->dev, "error: invalid topology ABI size\n");
-               return -EINVAL;
-       }
-
-       dev_info(scomp->dev,
-                "Topology: ABI %d:%d:%d Kernel ABI %d:%d:%d\n",
-                man->priv.data[0], man->priv.data[1],
-                man->priv.data[2], SOF_ABI_MAJOR, SOF_ABI_MINOR,
-                SOF_ABI_PATCH);
-
-       abi_version = SOF_ABI_VER(man->priv.data[0],
-                                 man->priv.data[1],
-                                 man->priv.data[2]);
-
-       if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, abi_version)) {
-               dev_err(scomp->dev, "error: incompatible topology ABI version\n");
-               return -EINVAL;
-       }
+       struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+       const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg;
 
-       if (SOF_ABI_VERSION_MINOR(abi_version) > SOF_ABI_MINOR) {
-               if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) {
-                       dev_warn(scomp->dev, "warn: topology ABI is more recent than kernel\n");
-               } else {
-                       dev_err(scomp->dev, "error: topology ABI is more recent than kernel\n");
-                       return -EINVAL;
-               }
-       }
+       if (ipc_tplg_ops->parse_manifest)
+               return ipc_tplg_ops->parse_manifest(scomp, index, man);
 
        return 0;
 }