ASoC: SOF: Add a new IPC op for parsing topology manifest
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>
This commit is contained in:
parent
4453d24d10
commit
323aa1f093
@ -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,
|
||||
};
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
|
||||
const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user