[alsa-devel] [PATCH 00/22] topology: Remaining user space patches of ABI v5
From: Mengdong Lin mengdong.lin@linux.intel.com
This series has all remaining topology user space patches for ABI update of version 5.
Backward compatibility from ABI v4 is assured by the kernel series "ASoC: topology: Remaining kernel patches of ABI v5", submitted as well.
Guneshwor Singh (3): topology: ABI - Define new types for physical DAI topology: Support configuring physical DAIs by C API topology: Export physical DAIs to the binary for kernel
Mengdong Lin (19): topology: ABI - Update stream caps and PCM objects to ABI v5 topology: Parse sig_bits of stream caps topology: Parse flags for PCM topology: Define a function to build a single PCM element topology: Parse and build private data for PCM topology: tplg_elem_lookup() checks parameter before searching topology: Merge an element's be & cc pointer to one link pointer topology: Define a function to build a single physical DAI link topology: ABI - Define DAI physical PCM data formats topology: ABI - Update physical DAI link configurations to ABI v5 topology: Rename varaibles for add physical links by C API topology: Define new type and section name to configure physical links topology: Parse HW configurations of physical DAI links defined by C API topology: Parse HW configurations of physical DAI links in text conf file topology: Parse link flags of physical DAI links topology: Parse and build private data of physical links topology: Parse name and stream name of physical DAI links topology: ABI - Update manifest to ABI v5 topology: Parse physical DAIs in text conf file
include/sound/asoc.h | 108 ++++++- include/topology.h | 149 ++++++++- src/topology/builder.c | 11 + src/topology/data.c | 4 + src/topology/elem.c | 12 + src/topology/parser.c | 38 ++- src/topology/pcm.c | 775 +++++++++++++++++++++++++++++++++++++++++++--- src/topology/tplg_local.h | 21 +- 8 files changed, 1064 insertions(+), 54 deletions(-)
From: Mengdong Lin mengdong.lin@linux.intel.com
Pump ABI version to 5, with the updates for PCM (Front DAI & DAI link) objects:
- add sig_bits to stream caps. - add flags and private data to PCM.
The kernel can handle the ABI update in a backward compatible way with the patch "ASoC: topology: Make PCM backward compatible from ABI v4".
Signed-off-by: Mengdong Lin mengdong.lin@linux.intel.com
diff --git a/include/sound/asoc.h b/include/sound/asoc.h index abe49c5..45872c1 100644 --- a/include/sound/asoc.h +++ b/include/sound/asoc.h @@ -115,6 +115,13 @@ #define SND_SOC_TPLG_TUPLE_TYPE_WORD 4 #define SND_SOC_TPLG_TUPLE_TYPE_SHORT 5
+/* DAI link flags */ +#define SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES (1 << 0) +#define SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS (1 << 1) +#define SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS (1 << 2) +#define SND_SOC_TPLG_LNK_FLGBIT_IGNORE_SUSPEND (1 << 3) +#define SND_SOC_TPLG_LNK_FLGBIT_IGNORE_POWERDOWN_TIME (1 << 4) + /* * Block Header. * This header precedes all object and object arrays below. @@ -242,6 +249,7 @@ struct snd_soc_tplg_stream_caps { __le32 period_size_max; /* max period size bytes */ __le32 buffer_size_min; /* min buffer size bytes */ __le32 buffer_size_max; /* max buffer size bytes */ + __le32 sig_bits; /* number of bits of content */ } __attribute__((packed));
/* @@ -422,6 +430,9 @@ struct snd_soc_tplg_pcm { struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* for DAI link */ __le32 num_streams; /* number of streams */ struct snd_soc_tplg_stream_caps caps[2]; /* playback and capture for DAI */ + __le32 flag_mask; /* bitmask of flags to configure */ + __le32 flags; /* SND_SOC_TPLG_LNK_FLGBIT_* flag value */ + struct snd_soc_tplg_private priv; } __attribute__((packed));
From: Mengdong Lin mengdong.lin@linux.intel.com
Add sig_bits to stream caps template of C API and parse it.
Signed-off-by: Mengdong Lin mengdong.lin@linux.intel.com
diff --git a/include/topology.h b/include/topology.h index 0675b52..ccd8401 100644 --- a/include/topology.h +++ b/include/topology.h @@ -848,6 +848,7 @@ struct snd_tplg_stream_caps_template { unsigned int period_size_max; /*!< max period size bytes */ unsigned int buffer_size_min; /*!< min buffer size bytes */ unsigned int buffer_size_max; /*!< max buffer size bytes */ + unsigned int sig_bits; /*!< number of bits of content */ };
/** \struct snd_tplg_pcm_template diff --git a/src/topology/pcm.c b/src/topology/pcm.c index 0a90cb9..6fdf047 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -572,6 +572,7 @@ static void tplg_add_stream_caps(struct snd_soc_tplg_stream_caps *caps, caps->period_size_max = caps_tpl->period_size_max; caps->buffer_size_min = caps_tpl->buffer_size_min; caps->buffer_size_max = caps_tpl->buffer_size_max; + caps->sig_bits = caps_tpl->sig_bits; }
int tplg_add_pcm_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
From: Mengdong Lin mengdong.lin@linux.intel.com
Users can define flags by both text conf file and C API. Add flags and flag_mask to C API template of PCM object.
Signed-off-by: Mengdong Lin mengdong.lin@linux.intel.com
diff --git a/include/topology.h b/include/topology.h index ccd8401..0a07c94 100644 --- a/include/topology.h +++ b/include/topology.h @@ -606,6 +606,13 @@ extern "C" { * "config3" * ] * } + * + * # Optional flags, the default value is "false". + * symmetric_rates "true or false" + * symmetric_channels "true or false" + * symmetric_sample_bits "true or false" + * ignore_suspend "true or false" + * ignore_powerdown_time "true or false" * } * </pre> * @@ -863,6 +870,8 @@ struct snd_tplg_pcm_template { unsigned int capture; /*!< supports capture mode */ unsigned int compress; /*!< 1 = compressed; 0 = PCM */ struct snd_tplg_stream_caps_template *caps[2]; /*!< playback & capture for DAI */ + unsigned int flag_mask; /*!< bitmask of flags to configure */ + unsigned int flags; /*!< flag value */ int num_streams; /*!< number of supported configs */ struct snd_tplg_stream_template stream[0]; /*!< supported configs */ }; diff --git a/src/topology/pcm.c b/src/topology/pcm.c index 6fdf047..3d9feb0 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -364,6 +364,24 @@ static int tplg_parse_fe_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED, return 0; }
+/* parse a flag bit of the given mask */ +static int parse_flag(snd_config_t *n, unsigned int mask_in, + unsigned int *mask, unsigned int *flags) +{ + const char *val = NULL; + + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + *mask |= mask_in; + if (strcmp(val, "true") == 0) + *flags |= mask_in; + else + *flags &= ~mask_in; + + return 0; +} + /* Parse pcm (for front end DAI & DAI link) */ int tplg_parse_pcm(snd_tplg_t *tplg, snd_config_t *cfg, void *private ATTRIBUTE_UNUSED) @@ -430,6 +448,53 @@ int tplg_parse_pcm(snd_tplg_t *tplg, return err; continue; } + + /* flags */ + if (strcmp(id, "symmetric_rates") == 0) { + err = parse_flag(n, + SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES, + &pcm->flag_mask, &pcm->flags); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "symmetric_channels") == 0) { + err = parse_flag(n, + SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS, + &pcm->flag_mask, &pcm->flags); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "symmetric_sample_bits") == 0) { + err = parse_flag(n, + SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS, + &pcm->flag_mask, &pcm->flags); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "ignore_suspend") == 0) { + err = parse_flag(n, + SND_SOC_TPLG_LNK_FLGBIT_IGNORE_SUSPEND, + &pcm->flag_mask, &pcm->flags); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "ignore_powerdown_time") == 0) { + err = parse_flag(n, + SND_SOC_TPLG_LNK_FLGBIT_IGNORE_POWERDOWN_TIME, + &pcm->flag_mask, &pcm->flags); + if (err < 0) + return err; + continue; + } + }
return 0; @@ -610,6 +675,9 @@ int tplg_add_pcm_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) tplg_add_stream_caps(&pcm->caps[i], pcm_tpl->caps[i]); }
+ pcm->flag_mask = pcm_tpl->flag_mask; + pcm->flags = pcm_tpl->flags; + pcm->num_streams = pcm_tpl->num_streams; for (i = 0; i < pcm_tpl->num_streams; i++) tplg_add_stream_object(&pcm->stream[i], &pcm_tpl->stream[i]);
From: Mengdong Lin mengdong.lin@linux.intel.com
Code refactoring. Rename tplg_build_pcm() to tplg_build_pcms() to build all PCM (FE DAI & DAI link) elements. It will call a new function build_pcm() to build a single PCM elemement.
build_pcm() will be extended to handle more properties of a PCM.
Signed-off-by: Mengdong Lin mengdong.lin@linux.intel.com
diff --git a/src/topology/parser.c b/src/topology/parser.c index 3ab64f4..7b2c879 100644 --- a/src/topology/parser.c +++ b/src/topology/parser.c @@ -267,7 +267,7 @@ static int tplg_build_integ(snd_tplg_t *tplg) if (err < 0) return err;
- err = tplg_build_pcm(tplg, SND_TPLG_TYPE_PCM); + err = tplg_build_pcms(tplg, SND_TPLG_TYPE_PCM); if (err < 0) return err;
diff --git a/src/topology/pcm.c b/src/topology/pcm.c index 3d9feb0..72bab94 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -70,8 +70,20 @@ static int tplg_build_stream_caps(snd_tplg_t *tplg, return 0; }
-/* build FE DAI/PCM configurations */ -int tplg_build_pcm(snd_tplg_t *tplg, unsigned int type) +/* build a PCM (FE DAI & DAI link) element */ +static int build_pcm(snd_tplg_t *tplg, struct tplg_elem *elem) +{ + int err; + + err = tplg_build_stream_caps(tplg, elem->id, elem->pcm->caps); + if (err < 0) + return err; + + return 0; +} + +/* build all PCM (FE DAI & DAI link) elements */ +int tplg_build_pcms(snd_tplg_t *tplg, unsigned int type) { struct list_head *base, *pos; struct tplg_elem *elem; @@ -86,7 +98,7 @@ int tplg_build_pcm(snd_tplg_t *tplg, unsigned int type) return -EINVAL; }
- err = tplg_build_stream_caps(tplg, elem->id, elem->pcm->caps); + err = build_pcm(tplg, elem); if (err < 0) return err;
diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h index cfde4cc..7b30b84 100644 --- a/src/topology/tplg_local.h +++ b/src/topology/tplg_local.h @@ -284,7 +284,7 @@ int tplg_add_enum(snd_tplg_t *tplg, struct snd_tplg_enum_template *enum_ctl, int tplg_add_bytes(snd_tplg_t *tplg, struct snd_tplg_bytes_template *bytes_ctl, struct tplg_elem **e);
-int tplg_build_pcm(snd_tplg_t *tplg, unsigned int type); +int tplg_build_pcms(snd_tplg_t *tplg, unsigned int type); int tplg_build_link_cfg(snd_tplg_t *tplg, unsigned int type); int tplg_add_link_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t); int tplg_add_pcm_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t);
From: Mengdong Lin mengdong.lin@linux.intel.com
Users can define private for PCM (FE DAI & DAI links) elements by both text conf file and C API:
- Text conf file may define multiple data blocks for a PCM and they will be merged in building phase;
- Add private data to C API template of PCM object.
Signed-off-by: Mengdong Lin mengdong.lin@linux.intel.com
diff --git a/include/topology.h b/include/topology.h index 0a07c94..f9e8285 100644 --- a/include/topology.h +++ b/include/topology.h @@ -613,6 +613,8 @@ extern "C" { * symmetric_sample_bits "true or false" * ignore_suspend "true or false" * ignore_powerdown_time "true or false" + * + * data "name" # optional private data * } * </pre> * @@ -872,6 +874,7 @@ struct snd_tplg_pcm_template { struct snd_tplg_stream_caps_template *caps[2]; /*!< playback & capture for DAI */ unsigned int flag_mask; /*!< bitmask of flags to configure */ unsigned int flags; /*!< flag value */ + struct snd_soc_tplg_private *priv; /*!< private data */ int num_streams; /*!< number of supported configs */ struct snd_tplg_stream_template stream[0]; /*!< supported configs */ }; diff --git a/src/topology/pcm.c b/src/topology/pcm.c index 72bab94..33940c6 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -73,12 +73,32 @@ static int tplg_build_stream_caps(snd_tplg_t *tplg, /* build a PCM (FE DAI & DAI link) element */ static int build_pcm(snd_tplg_t *tplg, struct tplg_elem *elem) { + struct tplg_ref *ref; + struct list_head *base, *pos; int err;
err = tplg_build_stream_caps(tplg, elem->id, elem->pcm->caps); if (err < 0) return err;
+ /* merge private data from the referenced data elements */ + base = &elem->ref_list; + list_for_each(pos, base) { + + ref = list_entry(pos, struct tplg_ref, list); + if (ref->type == SND_TPLG_TYPE_DATA) { + err = tplg_copy_data(tplg, elem, ref); + if (err < 0) + return err; + } + if (!ref->elem) { + SNDERR("error: cannot find '%s' referenced by" + " PCM '%s'\n", ref->id, elem->id); + return -EINVAL; + } else if (err < 0) + return err; + } + return 0; }
@@ -394,7 +414,7 @@ static int parse_flag(snd_config_t *n, unsigned int mask_in, return 0; }
-/* Parse pcm (for front end DAI & DAI link) */ +/* Parse PCM (for front end DAI & DAI link) in text conf file */ int tplg_parse_pcm(snd_tplg_t *tplg, snd_config_t *cfg, void *private ATTRIBUTE_UNUSED) { @@ -520,6 +540,7 @@ int tplg_parse_be(snd_tplg_t *tplg, snd_config_iterator_t i, next; snd_config_t *n; const char *id, *val = NULL; + int err;
elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_BE); if (!elem) @@ -559,6 +580,13 @@ int tplg_parse_be(snd_tplg_t *tplg, tplg_dbg("\t%s: %d\n", id, link->id); continue; } + + if (strcmp(id, "data") == 0) { + err = tplg_parse_data_refs(n, elem); + if (err < 0) + return err; + continue; + } }
return 0; @@ -652,10 +680,11 @@ static void tplg_add_stream_caps(struct snd_soc_tplg_stream_caps *caps, caps->sig_bits = caps_tpl->sig_bits; }
+/* Add a PCM element (FE DAI & DAI link) from C API */ int tplg_add_pcm_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) { struct snd_tplg_pcm_template *pcm_tpl = t->pcm; - struct snd_soc_tplg_pcm *pcm; + struct snd_soc_tplg_pcm *pcm, *_pcm; struct tplg_elem *elem; int i;
@@ -694,6 +723,25 @@ int tplg_add_pcm_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) for (i = 0; i < pcm_tpl->num_streams; i++) tplg_add_stream_object(&pcm->stream[i], &pcm_tpl->stream[i]);
+ /* private data */ + if (pcm_tpl->priv != NULL && pcm_tpl->priv->size) { + tplg_dbg("\t priv data size %d\n", pcm_tpl->priv->size); + _pcm = realloc(pcm, + elem->size + pcm_tpl->priv->size); + if (!_pcm) { + tplg_elem_free(elem); + return -ENOMEM; + } + + pcm = _pcm; + elem->pcm = pcm; + elem->size += pcm_tpl->priv->size; + + memcpy(pcm->priv.data, pcm_tpl->priv->data, + pcm_tpl->priv->size); + pcm->priv.size = pcm_tpl->priv->size; + } + return 0; }
From: Mengdong Lin mengdong.lin@linux.intel.com
Check the parameters at first in case of misuse.
Signed-off-by: Mengdong Lin mengdong.lin@linux.intel.com
diff --git a/src/topology/elem.c b/src/topology/elem.c index 029c9ab..724bf26 100644 --- a/src/topology/elem.c +++ b/src/topology/elem.c @@ -111,6 +111,9 @@ struct tplg_elem *tplg_elem_lookup(struct list_head *base, const char* id, struct list_head *pos; struct tplg_elem *elem;
+ if (!base || !id) + return NULL; + list_for_each(pos, base) {
elem = list_entry(pos, struct tplg_elem, list);
From: Mengdong Lin mengdong.lin@linux.intel.com
Code refactoring. Previously an element has two pointers, 'be' and 'cc', for BE (Back End) and CC (Codec-Codec) link respectively. But actually the topology tool processes BE and CC links in the same way, so these two pointers can be merged into one 'link' pointer, which can be used configure any physical links.
Signed-off-by: Mengdong Lin mengdong.lin@linux.intel.com
diff --git a/src/topology/pcm.c b/src/topology/pcm.c index 33940c6..64c8fd9 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -175,11 +175,7 @@ int tplg_build_link_cfg(snd_tplg_t *tplg, unsigned int type) return -EINVAL; }
- if (type == SND_TPLG_TYPE_BE) - link = elem->be; - else - link = elem->cc; - + link = elem->link; err = tplg_build_stream_cfg(tplg, link->stream, link->num_streams); if (err < 0) @@ -546,7 +542,7 @@ int tplg_parse_be(snd_tplg_t *tplg, if (!elem) return -ENOMEM;
- link = elem->be; + link = elem->link; link->size = elem->size;
tplg_dbg(" BE: %s\n", elem->id); @@ -606,7 +602,7 @@ int tplg_parse_cc(snd_tplg_t *tplg, if (!elem) return -ENOMEM;
- link = elem->cc; + link = elem->link; link->size = elem->size;
tplg_dbg(" CC: %s\n", elem->id); @@ -760,14 +756,12 @@ int tplg_add_link_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) if (!elem) return -ENOMEM;
- if (t->type == SND_TPLG_TYPE_BE) { + if (t->type == SND_TPLG_TYPE_BE) tplg_dbg("BE Link: %s", link->name); - lk = elem->be; - } else { + else tplg_dbg("CC Link: %s", link->name); - lk = elem->cc; - }
+ lk = elem->link; lk->size = elem->size; lk->id = link->id; lk->num_streams = link->num_streams; diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h index 7b30b84..3aa51ee 100644 --- a/src/topology/tplg_local.h +++ b/src/topology/tplg_local.h @@ -144,8 +144,7 @@ struct tplg_elem { struct snd_soc_tplg_bytes_control *bytes_ext; struct snd_soc_tplg_dapm_widget *widget; struct snd_soc_tplg_pcm *pcm; - struct snd_soc_tplg_link_config *be; - struct snd_soc_tplg_link_config *cc; + struct snd_soc_tplg_link_config *link;/* physical link */ struct snd_soc_tplg_dapm_graph_elem *route; struct snd_soc_tplg_stream *stream_cfg; struct snd_soc_tplg_stream_caps *stream_caps;
From: Mengdong Lin mengdong.lin@linux.intel.com
Code refactoring. Rename the function to build all physical links from tplg_build_link_config() to tplg_build_links(). And define a new function build_link() to build a single physical DAI link element.
The function build_link() will be extended to handle more properties of a physical DAI link (e.g. backend or codec-codec link).
Signed-off-by: Mengdong Lin mengdong.lin@linux.intel.com
diff --git a/src/topology/parser.c b/src/topology/parser.c index 7b2c879..ded2eb7 100644 --- a/src/topology/parser.c +++ b/src/topology/parser.c @@ -271,11 +271,11 @@ static int tplg_build_integ(snd_tplg_t *tplg) if (err < 0) return err;
- err = tplg_build_link_cfg(tplg, SND_TPLG_TYPE_BE); + err = tplg_build_links(tplg, SND_TPLG_TYPE_BE); if (err < 0) return err;
- err = tplg_build_link_cfg(tplg, SND_TPLG_TYPE_CC); + err = tplg_build_links(tplg, SND_TPLG_TYPE_CC); if (err < 0) return err;
diff --git a/src/topology/pcm.c b/src/topology/pcm.c index 64c8fd9..08f2ca8 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -148,12 +148,31 @@ static int tplg_build_stream_cfg(snd_tplg_t *tplg, return 0; }
+static int build_link(snd_tplg_t *tplg, struct tplg_elem *elem) +{ + struct snd_soc_tplg_link_config *link = elem->link; + struct tplg_elem *ref_elem = NULL; + struct snd_soc_tplg_link_cmpnt *codec, *cmpnt; + struct tplg_ref *ref; + struct list_head *base, *pos; + int i, num_hw_configs = 0, err = 0; + + err = tplg_build_stream_cfg(tplg, link->stream, + link->num_streams); + if (err < 0) + return err; + + /* add link to manifest */ + tplg->manifest.dai_link_elems++; + + return 0; +} + /* build BE/CC DAI link configurations */ -int tplg_build_link_cfg(snd_tplg_t *tplg, unsigned int type) +int tplg_build_links(snd_tplg_t *tplg, unsigned int type) { struct list_head *base, *pos; struct tplg_elem *elem; - struct snd_soc_tplg_link_config *link; int err = 0;
switch (type) { @@ -175,9 +194,7 @@ int tplg_build_link_cfg(snd_tplg_t *tplg, unsigned int type) return -EINVAL; }
- link = elem->link; - err = tplg_build_stream_cfg(tplg, link->stream, - link->num_streams); + err = build_link(tplg, elem); if (err < 0) return err; } diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h index 3aa51ee..548f42d 100644 --- a/src/topology/tplg_local.h +++ b/src/topology/tplg_local.h @@ -284,6 +284,6 @@ int tplg_add_bytes(snd_tplg_t *tplg, struct snd_tplg_bytes_template *bytes_ctl, struct tplg_elem **e);
int tplg_build_pcms(snd_tplg_t *tplg, unsigned int type); -int tplg_build_link_cfg(snd_tplg_t *tplg, unsigned int type); +int tplg_build_links(snd_tplg_t *tplg, unsigned int type); int tplg_add_link_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t); int tplg_add_pcm_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t);
From: Mengdong Lin mengdong.lin@linux.intel.com
Define DAI physical PCM data formats for user space, so users can specify the formats of backends by topology (e.g. the DAI format to set on backend link init).
The kernel will also refer to these formats.
Signed-off-by: Mengdong Lin mengdong.lin@linux.intel.com
diff --git a/include/sound/asoc.h b/include/sound/asoc.h index 45872c1..8e9ee39 100644 --- a/include/sound/asoc.h +++ b/include/sound/asoc.h @@ -122,6 +122,21 @@ #define SND_SOC_TPLG_LNK_FLGBIT_IGNORE_SUSPEND (1 << 3) #define SND_SOC_TPLG_LNK_FLGBIT_IGNORE_POWERDOWN_TIME (1 << 4)
+/* DAI physical PCM data formats. + * Add new formats to the end of the list. + */ +#define SND_SOC_DAI_FORMAT_I2S 1 /* I2S mode */ +#define SND_SOC_DAI_FORMAT_RIGHT_J 2 /* Right Justified mode */ +#define SND_SOC_DAI_FORMAT_LEFT_J 3 /* Left Justified mode */ +#define SND_SOC_DAI_FORMAT_DSP_A 4 /* L data MSB after FRM LRC */ +#define SND_SOC_DAI_FORMAT_DSP_B 5 /* L data MSB during FRM LRC */ +#define SND_SOC_DAI_FORMAT_AC97 6 /* AC97 */ +#define SND_SOC_DAI_FORMAT_PDM 7 /* Pulse density modulation */ + +/* left and right justified also known as MSB and LSB respectively */ +#define SND_SOC_DAI_FORMAT_MSB SND_SOC_DAI_FORMAT_LEFT_J +#define SND_SOC_DAI_FORMAT_LSB SND_SOC_DAI_FORMAT_RIGHT_J + /* * Block Header. * This header precedes all object and object arrays below.
From: Mengdong Lin mengdong.lin@linux.intel.com
This patch update physicals DAI link config to ABI v5:
- Define the types and ABI struct for runtime supported hardware configs e.g. audio hardware formats. The default HW config ID will help topology to find the DAI format to set on init. Topology provides this as a fallback if such HW settings are not available in ACPI or device tree, to avoid hard code in drivers. It's only for config items that can be programmed by SW or FW, not for physical things like link connections or GPIO used for HP etc.
- Add flags. The flags will be used to configure an existing physical links.
- Add private data. The private data is reserved for future extension.
- Add name and stream name to BE DAI links. Kernel can also use name and stream name to find an existing physical link and configure it.
Kernel can handle the ABI update in a backward compatible way via patch 'ASoC: topology: Add support to configure existing physical DAI links'.
Signed-off-by: Mengdong Lin mengdong.lin@linux.intel.com
diff --git a/include/sound/asoc.h b/include/sound/asoc.h index 8e9ee39..9dd4d53 100644 --- a/include/sound/asoc.h +++ b/include/sound/asoc.h @@ -30,6 +30,11 @@ */ #define SND_SOC_TPLG_STREAM_CONFIG_MAX 8
+/* + * Maximum number of physical link's hardware configs + */ +#define SND_SOC_TPLG_HW_CONFIG_MAX 8 + /* individual kcontrol info types - can be mixed with other types */ #define SND_SOC_TPLG_CTL_VOLSW 1 #define SND_SOC_TPLG_CTL_VOLSW_SX 2 @@ -280,6 +285,35 @@ struct snd_soc_tplg_stream { __le32 channels; /* channels */ } __attribute__((packed));
+ +/* + * Describes a physical link's runtime supported hardware config, + * i.e. hardware audio formats. + */ +struct snd_soc_tplg_hw_config { + __le32 size; /* in bytes of this structure */ + __le32 id; /* unique ID - - used to match */ + __le32 fmt; /* SND_SOC_DAI_FORMAT_ format value */ + __u8 clock_gated; /* 1 if clock can be gated to save power */ + __u8 invert_bclk; /* 1 for inverted BCLK, 0 for normal */ + __u8 invert_fsync; /* 1 for inverted frame clock, 0 for normal */ + __u8 bclk_master; /* 1 for master of BCLK, 0 for slave */ + __u8 fsync_master; /* 1 for master of FSYNC, 0 for slave */ + __u8 mclk_direction; /* 0 for input, 1 for output */ + __le16 reserved; /* for 32bit alignment */ + __le32 mclk_rate; /* MCLK or SYSCLK freqency in Hz */ + __le32 bclk_rate; /* BCLK freqency in Hz */ + __le32 fsync_rate; /* frame clock in Hz */ + __le32 tdm_slots; /* number of TDM slots in use */ + __le32 tdm_slot_width; /* width in bits for each slot */ + __le32 tx_slots; /* bit mask for active Tx slots */ + __le32 rx_slots; /* bit mask for active Rx slots */ + __le32 tx_channels; /* number of Tx channels */ + __le32 tx_chanmap[SND_SOC_TPLG_MAX_CHAN]; /* array of slot number */ + __le32 rx_channels; /* number of Rx channels */ + __le32 rx_chanmap[SND_SOC_TPLG_MAX_CHAN]; /* array of slot number */ +} __attribute__((packed)); + /* * Manifest. List totals for each payload type. Not used in parsing, but will * be passed to the component driver before any other objects in order for any @@ -452,9 +486,9 @@ struct snd_soc_tplg_pcm {
/* - * Describes the BE or CC link runtime supported configs or params + * Describes the physical link runtime supported configs or params * - * File block representation for BE/CC link config :- + * File block representation for physical link config :- * +-----------------------------------+-----+ * | struct snd_soc_tplg_hdr | 1 | * +-----------------------------------+-----+ @@ -464,7 +498,15 @@ struct snd_soc_tplg_pcm { struct snd_soc_tplg_link_config { __le32 size; /* in bytes of this structure */ __le32 id; /* unique ID - used to match */ + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* name - used to match */ + char stream_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* stream name - used to match */ struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* supported configs playback and captrure */ __le32 num_streams; /* number of streams */ + struct snd_soc_tplg_hw_config hw_config[SND_SOC_TPLG_HW_CONFIG_MAX]; /* hw configs */ + __le32 num_hw_configs; /* number of hw configs */ + __le32 default_hw_config_id; /* default hw config ID for init */ + __le32 flag_mask; /* bitmask of flags to configure */ + __le32 flags; /* SND_SOC_TPLG_LNK_FLGBIT_* flag value */ + struct snd_soc_tplg_private priv; } __attribute__((packed)); #endif
From: Mengdong Lin mengdong.lin@linux.intel.com
Code refactoring. When adding a physical link element from C API: - Rename "link" to "link_tpl" for physical link config template for C API users. - Rename "lk" to "link" for physical link elements created by topology internally.
Signed-off-by: Mengdong Lin mengdong.lin@linux.intel.com
diff --git a/src/topology/pcm.c b/src/topology/pcm.c index 08f2ca8..3fe77aa 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -758,10 +758,11 @@ int tplg_add_pcm_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) return 0; }
+/* Add a physical DAI link element from C API */ int tplg_add_link_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) { - struct snd_tplg_link_template *link = t->link; - struct snd_soc_tplg_link_config *lk; + struct snd_tplg_link_template *link_tpl = t->link; + struct snd_soc_tplg_link_config *link, *_link; struct tplg_elem *elem; int i;
@@ -769,22 +770,25 @@ int tplg_add_link_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) return -EINVAL;
/* here type can be either BE or CC. */ - elem = tplg_elem_new_common(tplg, NULL, link->name, t->type); + elem = tplg_elem_new_common(tplg, NULL, link_tpl->name, t->type); if (!elem) return -ENOMEM;
if (t->type == SND_TPLG_TYPE_BE) - tplg_dbg("BE Link: %s", link->name); + tplg_dbg("BE Link: %s", link_tpl->name); else - tplg_dbg("CC Link: %s", link->name); + tplg_dbg("CC Link: %s", link_tpl->name);
- lk = elem->link; - lk->size = elem->size; - lk->id = link->id; - lk->num_streams = link->num_streams; + link = elem->link; + link->size = elem->size;
+ link->id = link_tpl->id; + /* stream configs */ + if (link_tpl->num_streams > SND_SOC_TPLG_STREAM_CONFIG_MAX) + return -EINVAL; + link->num_streams = link_tpl->num_streams; for (i = 0; i < link->num_streams; i++) - tplg_add_stream_object(&lk->stream[i], &link->stream[i]); + tplg_add_stream_object(&link->stream[i], &link_tpl->stream[i]);
return 0; }
From: Mengdong Lin mengdong.lin@linux.intel.com
Users may not use DPCM but still need to configure the physical links. So we should not only consider backend links for DPCM.
- SND_TPLG_TYPE_LINK is defined to configure physical links by C API. And SND_TPLG_TYPE_BE is still supported to configure Backend links for DPCM cases.
- SectionLink can be used to configure physical links in text conf file. And SectionBE is still supported to config Backend links for DPCM cases.
Actually, users can also use SND_TPLG_TYPE_LINK and SectionLink to configure backend links for DPCM cases, because BE links are physical links. So the parsing is same and we rename the function from tplg_parse_be to tplg_parse_link.
Signed-off-by: Mengdong Lin mengdong.lin@linux.intel.com
diff --git a/include/topology.h b/include/topology.h index f9e8285..d1ce69c 100644 --- a/include/topology.h +++ b/include/topology.h @@ -618,6 +618,24 @@ extern "C" { * } * </pre> * + * <h4>Physical DAI Link Configurations</h4> + * The runtime configurations of a physical DAI link can be defined by + * SectionLink. <br> Backend DAI links belong to physical links, and can + * be configured by either SectionLink or SectionBE, with same syntax. + * But SectionBE is deprecated atm since the internal processing is + * actually same. + * + * <pre> + * SectionLink."name" { + * + * index "1" # Index number + * + * id "0" # used for binding to the link + * + * data "name" # optional private data + * } + * </pre> + * * <h4>Manifest Private Data</h4> * Manfiest may have private data. Users need to define a manifest section * and add the references to 1 or multiple data sections. Please refer to @@ -658,6 +676,7 @@ enum snd_tplg_type { SND_TPLG_TYPE_MANIFEST, /*!< Topology manifest */ SND_TPLG_TYPE_TOKEN, /*!< Vendor tokens */ SND_TPLG_TYPE_TUPLE, /*!< Vendor tuples */ + SND_TPLG_TYPE_LINK, /*!< Physical DAI link */ };
/** diff --git a/src/topology/parser.c b/src/topology/parser.c index ded2eb7..ed5da87 100644 --- a/src/topology/parser.c +++ b/src/topology/parser.c @@ -133,8 +133,9 @@ static int tplg_parse_config(snd_tplg_t *tplg, snd_config_t *cfg) continue; }
- if (strcmp(id, "SectionBE") == 0) { - err = tplg_parse_compound(tplg, n, tplg_parse_be, + if (strcmp(id, "SectionLink") == 0 + || strcmp(id, "SectionBE") == 0) { + err = tplg_parse_compound(tplg, n, tplg_parse_link, NULL); if (err < 0) return err; diff --git a/src/topology/pcm.c b/src/topology/pcm.c index 3fe77aa..32beeb7 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -545,7 +545,8 @@ int tplg_parse_pcm(snd_tplg_t *tplg, return 0; }
-int tplg_parse_be(snd_tplg_t *tplg, +/* Parse a physical link element in text conf file */ +int tplg_parse_link(snd_tplg_t *tplg, snd_config_t *cfg, void *private ATTRIBUTE_UNUSED) { struct snd_soc_tplg_link_config *link; @@ -562,7 +563,7 @@ int tplg_parse_be(snd_tplg_t *tplg, link = elem->link; link->size = elem->size;
- tplg_dbg(" BE: %s\n", elem->id); + tplg_dbg(" Link: %s\n", elem->id);
snd_config_for_each(i, next, cfg) {
@@ -766,7 +767,8 @@ int tplg_add_link_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) struct tplg_elem *elem; int i;
- if (t->type != SND_TPLG_TYPE_BE && t->type != SND_TPLG_TYPE_CC) + if (t->type != SND_TPLG_TYPE_LINK && t->type != SND_TPLG_TYPE_BE + && t->type != SND_TPLG_TYPE_CC) return -EINVAL;
/* here type can be either BE or CC. */ @@ -774,10 +776,7 @@ int tplg_add_link_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) if (!elem) return -ENOMEM;
- if (t->type == SND_TPLG_TYPE_BE) - tplg_dbg("BE Link: %s", link_tpl->name); - else - tplg_dbg("CC Link: %s", link_tpl->name); + tplg_dbg("Link: %s", link_tpl->name);
link = elem->link; link->size = elem->size; diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h index 548f42d..947f27e 100644 --- a/src/topology/tplg_local.h +++ b/src/topology/tplg_local.h @@ -220,7 +220,7 @@ int tplg_parse_stream_caps(snd_tplg_t *tplg, int tplg_parse_pcm(snd_tplg_t *tplg, snd_config_t *cfg, void *private ATTRIBUTE_UNUSED);
-int tplg_parse_be(snd_tplg_t *tplg, +int tplg_parse_link(snd_tplg_t *tplg, snd_config_t *cfg, void *private ATTRIBUTE_UNUSED);
int tplg_parse_cc(snd_tplg_t *tplg,
From: Mengdong Lin mengdong.lin@linux.intel.com
Add HW configurations to C API template of physical link configuration.
Signed-off-by: Mengdong Lin mengdong.lin@linux.intel.com
diff --git a/include/topology.h b/include/topology.h index d1ce69c..8323dd9 100644 --- a/include/topology.h +++ b/include/topology.h @@ -898,6 +898,33 @@ struct snd_tplg_pcm_template { struct snd_tplg_stream_template stream[0]; /*!< supported configs */ };
+ /** \struct snd_tplg_hw_config_template + * \brief Template type to describe a physical link runtime supported + * hardware config, i.e. hardware audio formats. + */ +struct snd_tplg_hw_config_template { + int id; /* unique ID - - used to match */ + unsigned int fmt; /* SND_SOC_DAI_FORMAT_ format value */ + unsigned char clock_gated; /* 1 if clock can be gated to save power */ + unsigned char invert_bclk; /* 1 for inverted BCLK, 0 for normal */ + unsigned char invert_fsync; /* 1 for inverted frame clock, 0 for normal */ + unsigned char bclk_master; /* 1 for master of BCLK, 0 for slave */ + unsigned char fsync_master; /* 1 for master of FSYNC, 0 for slave */ + unsigned char mclk_direction; /* 0 for input, 1 for output */ + unsigned short reserved; /* for 32bit alignment */ + unsigned int mclk_rate; /* MCLK or SYSCLK freqency in Hz */ + unsigned int bclk_rate; /* BCLK freqency in Hz */ + unsigned int fsync_rate; /* frame clock in Hz */ + unsigned int tdm_slots; /* number of TDM slots in use */ + unsigned int tdm_slot_width; /* width in bits for each slot */ + unsigned int tx_slots; /* bit mask for active Tx slots */ + unsigned int rx_slots; /* bit mask for active Rx slots */ + unsigned int tx_channels; /* number of Tx channels */ + unsigned int *tx_chanmap; /* array of slot number */ + unsigned int rx_channels; /* number of Rx channels */ + unsigned int *rx_chanmap; /* array of slot number */ +}; + /** \struct snd_tplg_link_template * \brief Template type for BE and CC DAI Links. */ @@ -905,7 +932,11 @@ struct snd_tplg_link_template { const char *name; /*!< link name */ int id; /*!< unique ID - used to match with existing BE and CC links */ int num_streams; /*!< number of configs */ - struct snd_tplg_stream_template stream[0]; /*!< supported configs */ + struct snd_tplg_stream_template *stream; /*!< supported configs */ + + struct snd_tplg_hw_config_template *hw_config; /*!< supported HW configs */ + int num_hw_configs; /* number of hw configs */ + int default_hw_config_id; /* default hw config ID for init */ };
/** \struct snd_tplg_obj_template diff --git a/src/topology/elem.c b/src/topology/elem.c index 724bf26..f7ff070 100644 --- a/src/topology/elem.c +++ b/src/topology/elem.c @@ -193,6 +193,7 @@ struct tplg_elem* tplg_elem_new_common(snd_tplg_t *tplg, obj_size = sizeof(struct snd_soc_tplg_pcm); break; case SND_TPLG_TYPE_BE: + case SND_TPLG_TYPE_LINK: list_add_tail(&elem->list, &tplg->be_list); obj_size = sizeof(struct snd_soc_tplg_link_config); break; diff --git a/src/topology/parser.c b/src/topology/parser.c index ed5da87..238943c 100644 --- a/src/topology/parser.c +++ b/src/topology/parser.c @@ -348,6 +348,7 @@ int snd_tplg_add_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) return tplg_add_graph_object(tplg, t); case SND_TPLG_TYPE_PCM: return tplg_add_pcm_object(tplg, t); + case SND_TPLG_TYPE_LINK: case SND_TPLG_TYPE_BE: case SND_TPLG_TYPE_CC: return tplg_add_link_object(tplg, t); diff --git a/src/topology/pcm.c b/src/topology/pcm.c index 32beeb7..58efc2f 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -168,7 +168,7 @@ static int build_link(snd_tplg_t *tplg, struct tplg_elem *elem) return 0; }
-/* build BE/CC DAI link configurations */ +/* build physical DAI link configurations */ int tplg_build_links(snd_tplg_t *tplg, unsigned int type) { struct list_head *base, *pos; @@ -176,6 +176,7 @@ int tplg_build_links(snd_tplg_t *tplg, unsigned int type) int err = 0;
switch (type) { + case SND_TPLG_TYPE_LINK: case SND_TPLG_TYPE_BE: base = &tplg->be_list; break; @@ -189,11 +190,6 @@ int tplg_build_links(snd_tplg_t *tplg, unsigned int type) list_for_each(pos, base) {
elem = list_entry(pos, struct tplg_elem, list); - if (elem->type != type) { - SNDERR("error: invalid elem '%s'\n", elem->id); - return -EINVAL; - } - err = build_link(tplg, elem); if (err < 0) return err; @@ -759,6 +755,47 @@ int tplg_add_pcm_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) return 0; }
+/* Set link HW config from C API template */ +static int set_link_hw_config(struct snd_soc_tplg_hw_config *cfg, + struct snd_tplg_hw_config_template *tpl) +{ + int i; + + cfg->size = sizeof(*cfg); + cfg->id = tpl->id; + + cfg->fmt = tpl->fmt; + cfg->clock_gated = tpl->clock_gated; + cfg->invert_bclk = tpl->invert_bclk; + cfg->invert_fsync = tpl->invert_fsync; + cfg->bclk_master = tpl->bclk_master; + cfg->fsync_master = tpl->fsync_master; + cfg->mclk_direction = tpl->mclk_direction; + cfg->reserved = tpl->reserved; + cfg->mclk_rate = tpl->mclk_rate; + cfg->bclk_rate = tpl->bclk_rate; + cfg->fsync_rate = tpl->fsync_rate; + + cfg->tdm_slots = tpl->tdm_slots; + cfg->tdm_slot_width = tpl->tdm_slot_width; + cfg->tx_slots = tpl->tx_slots; + cfg->rx_slots = tpl->rx_slots; + + if (cfg->tx_channels > SND_SOC_TPLG_MAX_CHAN + || cfg->rx_channels > SND_SOC_TPLG_MAX_CHAN) + return -EINVAL; + + cfg->tx_channels = tpl->tx_channels; + for (i = 0; i < cfg->tx_channels; i++) + cfg->tx_chanmap[i] = tpl->tx_chanmap[i]; + + cfg->rx_channels = tpl->rx_channels; + for (i = 0; i < cfg->rx_channels; i++) + cfg->rx_chanmap[i] = tpl->rx_chanmap[i]; + + return 0; +} + /* Add a physical DAI link element from C API */ int tplg_add_link_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) { @@ -789,5 +826,12 @@ int tplg_add_link_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) for (i = 0; i < link->num_streams; i++) tplg_add_stream_object(&link->stream[i], &link_tpl->stream[i]);
+ /* HW configs */ + if (link_tpl->num_hw_configs > SND_SOC_TPLG_HW_CONFIG_MAX) + return -EINVAL; + link->num_hw_configs = link_tpl->num_hw_configs; + link->default_hw_config_id = link_tpl->default_hw_config_id; + for (i = 0; i < link->num_hw_configs; i++) + set_link_hw_config(&link->hw_config[i], &link_tpl->hw_config[i]); return 0; }
From: Mengdong Lin mengdong.lin@linux.intel.com
Users can configure the runtime supported HW configurations of a physical link by SectionHWConfig. A physical link can refer multiple HW config sections in SectionLink.
Signed-off-by: Mengdong Lin mengdong.lin@linux.intel.com
diff --git a/include/topology.h b/include/topology.h index 8323dd9..cf25de5 100644 --- a/include/topology.h +++ b/include/topology.h @@ -632,10 +632,31 @@ extern "C" { * * id "0" # used for binding to the link * + * hw_configs [ # runtime supported HW configurations, optional + * "config1" + * "config2" + * ... + * ] + * + * default_hw_conf_id "1" #default HW config ID for init + * * data "name" # optional private data * } * </pre> * + * A physical link can refer to multiple runtime supported hardware + * configurations, which is defined by SectionHWConfig. + * + * <pre> + * SectionHWConfig."name" { + * + * id "1" # used for binding to the config + * format "I2S" # physical audio format. + * bclk "master" # Platform is master of bit clock + * fsync "slave" # Platform is slave of fsync + * } + * </pre> + * * <h4>Manifest Private Data</h4> * Manfiest may have private data. Users need to define a manifest section * and add the references to 1 or multiple data sections. Please refer to @@ -677,6 +698,7 @@ enum snd_tplg_type { SND_TPLG_TYPE_TOKEN, /*!< Vendor tokens */ SND_TPLG_TYPE_TUPLE, /*!< Vendor tuples */ SND_TPLG_TYPE_LINK, /*!< Physical DAI link */ + SND_TPLG_TYPE_HW_CONFIG, /*!< Link HW config */ };
/** diff --git a/src/topology/elem.c b/src/topology/elem.c index f7ff070..01dce1f 100644 --- a/src/topology/elem.c +++ b/src/topology/elem.c @@ -208,6 +208,10 @@ struct tplg_elem* tplg_elem_new_common(snd_tplg_t *tplg, list_add_tail(&elem->list, &tplg->tuple_list); elem->free = tplg_free_tuples; break; + case SND_TPLG_TYPE_HW_CONFIG: + list_add_tail(&elem->list, &tplg->hw_cfg_list); + obj_size = sizeof(struct snd_soc_tplg_hw_config); + break; default: free(elem); return NULL; diff --git a/src/topology/parser.c b/src/topology/parser.c index 238943c..7d0486c 100644 --- a/src/topology/parser.c +++ b/src/topology/parser.c @@ -133,6 +133,14 @@ static int tplg_parse_config(snd_tplg_t *tplg, snd_config_t *cfg) continue; }
+ if (strcmp(id, "SectionHWConfig") == 0) { + err = tplg_parse_compound(tplg, n, tplg_parse_hw_config, + NULL); + if (err < 0) + return err; + continue; + } + if (strcmp(id, "SectionLink") == 0 || strcmp(id, "SectionBE") == 0) { err = tplg_parse_compound(tplg, n, tplg_parse_link, @@ -455,6 +463,7 @@ snd_tplg_t *snd_tplg_new(void) INIT_LIST_HEAD(&tplg->bytes_ext_list); INIT_LIST_HEAD(&tplg->token_list); INIT_LIST_HEAD(&tplg->tuple_list); + INIT_LIST_HEAD(&tplg->hw_cfg_list);
return tplg; } @@ -480,6 +489,7 @@ void snd_tplg_free(snd_tplg_t *tplg) tplg_elem_free_list(&tplg->bytes_ext_list); tplg_elem_free_list(&tplg->token_list); tplg_elem_free_list(&tplg->tuple_list); + tplg_elem_free_list(&tplg->hw_cfg_list);
free(tplg); } diff --git a/src/topology/pcm.c b/src/topology/pcm.c index 58efc2f..9e5bb8e 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -162,6 +162,34 @@ static int build_link(snd_tplg_t *tplg, struct tplg_elem *elem) if (err < 0) return err;
+ /* hw configs */ + base = &elem->ref_list; + list_for_each(pos, base) { + + ref = list_entry(pos, struct tplg_ref, list); + + switch (ref->type) { + case SND_TPLG_TYPE_HW_CONFIG: + ref->elem = tplg_elem_lookup(&tplg->hw_cfg_list, + ref->id, SND_TPLG_TYPE_HW_CONFIG); + if (!ref->elem) { + SNDERR("error: cannot find HW config '%s'" + " referenced by link '%s'\n", + ref->id, elem->id); + return -EINVAL; + } + + memcpy(&link->hw_config[num_hw_configs], + ref->elem->hw_cfg, + sizeof(struct snd_soc_tplg_hw_config)); + num_hw_configs++; + break; + + default: + break; + } + } + /* add link to manifest */ tplg->manifest.dai_link_elems++;
@@ -541,6 +569,54 @@ int tplg_parse_pcm(snd_tplg_t *tplg, return 0; }
+/* parse physical link runtime supported HW configs in text conf file */ +static int parse_hw_config_refs(snd_tplg_t *tplg, snd_config_t *cfg, + struct tplg_elem *elem) +{ + struct snd_soc_tplg_link_config *link = elem->link; + snd_config_type_t type; + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id, *val = NULL; + + if (snd_config_get_id(cfg, &id) < 0) + return -EINVAL; + type = snd_config_get_type(cfg); + + /* refer to a single HW config */ + if (type == SND_CONFIG_TYPE_STRING) { + if (snd_config_get_string(cfg, &val) < 0) + return -EINVAL; + + link->num_hw_configs = 1; + return tplg_ref_add(elem, SND_TPLG_TYPE_HW_CONFIG, val); + } + + if (type != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("error: compound type expected for %s", id); + return -EINVAL; + } + + /* refer to a list of HW configs */ + snd_config_for_each(i, next, cfg) { + const char *val; + + n = snd_config_iterator_entry(i); + if (snd_config_get_string(n, &val) < 0) + continue; + + if (link->num_hw_configs >= SND_SOC_TPLG_HW_CONFIG_MAX) { + SNDERR("error: exceed max hw configs for link %s", id); + return -EINVAL; + } + + link->num_hw_configs++; + return tplg_ref_add(elem, SND_TPLG_TYPE_HW_CONFIG, val); + } + + return 0; +} + /* Parse a physical link element in text conf file */ int tplg_parse_link(snd_tplg_t *tplg, snd_config_t *cfg, void *private ATTRIBUTE_UNUSED) @@ -591,6 +667,21 @@ int tplg_parse_link(snd_tplg_t *tplg, continue; }
+ if (strcmp(id, "hw_configs") == 0) { + err = parse_hw_config_refs(tplg, n, elem); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "default_hw_conf_id") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + link->default_hw_config_id = atoi(val); + continue; + } + if (strcmp(id, "data") == 0) { err = tplg_parse_data_refs(n, elem); if (err < 0) @@ -656,6 +747,110 @@ int tplg_parse_cc(snd_tplg_t *tplg, return 0; }
+static int get_audio_hw_format(const char *val) +{ + if (!strlen(val)) + return -EINVAL; + + if (!strcmp(val, "I2S")) + return SND_SOC_DAI_FORMAT_I2S; + + if (!strcmp(val, "RIGHT_J")) + return SND_SOC_DAI_FORMAT_RIGHT_J; + + if (!strcmp(val, "LEFT_J")) + return SND_SOC_DAI_FORMAT_LEFT_J; + + if (!strcmp(val, "DSP_A")) + return SND_SOC_DAI_FORMAT_DSP_A; + + if (!strcmp(val, "LEFT_B")) + return SND_SOC_DAI_FORMAT_DSP_B; + + if (!strcmp(val, "AC97")) + return SND_SOC_DAI_FORMAT_AC97; + + if (!strcmp(val, "PDM")) + return SND_SOC_DAI_FORMAT_PDM; + + SNDERR("error: invalid audio HW format %s\n", val); + return -EINVAL; +} + +int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg, + void *private ATTRIBUTE_UNUSED) +{ + + struct snd_soc_tplg_hw_config *hw_cfg; + struct tplg_elem *elem; + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id, *val = NULL; + int ret; + + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_HW_CONFIG); + if (!elem) + return -ENOMEM; + + hw_cfg = elem->hw_cfg; + hw_cfg->size = elem->size; + + tplg_dbg(" Link HW config: %s\n", elem->id); + + snd_config_for_each(i, next, cfg) { + + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + + /* skip comments */ + if (strcmp(id, "comment") == 0) + continue; + if (id[0] == '#') + continue; + + if (strcmp(id, "id") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + hw_cfg->id = atoi(val); + tplg_dbg("\t%s: %d\n", id, hw_cfg->id); + continue; + } + + if (strcmp(id, "format") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + ret = get_audio_hw_format(val); + if (ret < 0) + return ret; + hw_cfg->fmt = ret; + continue; + } + + if (strcmp(id, "bclk") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + if (!strcmp(val, "master")) + hw_cfg->bclk_master = true; + continue; + } + + if (strcmp(id, "fsync") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + if (!strcmp(val, "master")) + hw_cfg->fsync_master = true; + continue; + } + } + + return 0; +} + /* copy stream object */ static void tplg_add_stream_object(struct snd_soc_tplg_stream *strm, struct snd_tplg_stream_template *strm_tpl) diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h index 947f27e..9e67bf8 100644 --- a/src/topology/tplg_local.h +++ b/src/topology/tplg_local.h @@ -74,6 +74,7 @@ struct snd_tplg { struct list_head manifest_list; struct list_head pcm_config_list; struct list_head pcm_caps_list; + struct list_head hw_cfg_list;
/* type-specific control lists */ struct list_head mixer_list; @@ -148,6 +149,7 @@ struct tplg_elem { struct snd_soc_tplg_dapm_graph_elem *route; struct snd_soc_tplg_stream *stream_cfg; struct snd_soc_tplg_stream_caps *stream_caps; + struct snd_soc_tplg_hw_config *hw_cfg;
/* these do not map to UAPI structs but are internal only */ struct snd_soc_tplg_ctl_tlv *tlv; @@ -226,6 +228,9 @@ int tplg_parse_link(snd_tplg_t *tplg, int tplg_parse_cc(snd_tplg_t *tplg, snd_config_t *cfg, void *private ATTRIBUTE_UNUSED);
+int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg, + void *private ATTRIBUTE_UNUSED); + int tplg_build_data(snd_tplg_t *tplg); int tplg_build_manifest_data(snd_tplg_t *tplg); int tplg_build_controls(snd_tplg_t *tplg);
From: Mengdong Lin mengdong.lin@linux.intel.com
Parse physical DAI link flags in both text conf file or C API template.
Signed-off-by: Mengdong Lin mengdong.lin@linux.intel.com
diff --git a/include/topology.h b/include/topology.h index cf25de5..d7971b7 100644 --- a/include/topology.h +++ b/include/topology.h @@ -640,6 +640,13 @@ extern "C" { * * default_hw_conf_id "1" #default HW config ID for init * + * # Optional flags, the default value is "false". + * symmetric_rates "true or false" + * symmetric_channels "true or false" + * symmetric_sample_bits "true or false" + * ignore_suspend "true or false" + * ignore_powerdown_time "true or false" + * * data "name" # optional private data * } * </pre> @@ -959,6 +966,10 @@ struct snd_tplg_link_template { struct snd_tplg_hw_config_template *hw_config; /*!< supported HW configs */ int num_hw_configs; /* number of hw configs */ int default_hw_config_id; /* default hw config ID for init */ + + unsigned int flag_mask; /* bitmask of flags to configure */ + unsigned int flags; /* SND_SOC_TPLG_LNK_FLGBIT_* flag value */ + struct snd_soc_tplg_private *priv; /*!< private data */ };
/** \struct snd_tplg_obj_template diff --git a/src/topology/pcm.c b/src/topology/pcm.c index 9e5bb8e..daeb32e 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -682,6 +682,53 @@ int tplg_parse_link(snd_tplg_t *tplg, continue; }
+ /* flags */ + if (strcmp(id, "symmetric_rates") == 0) { + err = parse_flag(n, + SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES, + &link->flag_mask, &link->flags); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "symmetric_channels") == 0) { + err = parse_flag(n, + SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS, + &link->flag_mask, &link->flags); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "symmetric_sample_bits") == 0) { + err = parse_flag(n, + SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS, + &link->flag_mask, &link->flags); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "ignore_suspend") == 0) { + err = parse_flag(n, + SND_SOC_TPLG_LNK_FLGBIT_IGNORE_SUSPEND, + &link->flag_mask, &link->flags); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "ignore_powerdown_time") == 0) { + err = parse_flag(n, + SND_SOC_TPLG_LNK_FLGBIT_IGNORE_POWERDOWN_TIME, + &link->flag_mask, &link->flags); + if (err < 0) + return err; + continue; + } + + /* private data */ if (strcmp(id, "data") == 0) { err = tplg_parse_data_refs(n, elem); if (err < 0) @@ -1028,5 +1075,9 @@ int tplg_add_link_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) link->default_hw_config_id = link_tpl->default_hw_config_id; for (i = 0; i < link->num_hw_configs; i++) set_link_hw_config(&link->hw_config[i], &link_tpl->hw_config[i]); + + /* flags */ + link->flag_mask = link_tpl->flag_mask; + link->flags = link_tpl->flags; return 0; }
From: Mengdong Lin mengdong.lin@linux.intel.com
Users can define private data for physical links by C API or text conf file.
Signed-off-by: Mengdong Lin mengdong.lin@linux.intel.com
diff --git a/src/topology/pcm.c b/src/topology/pcm.c index daeb32e..c4857ba 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -162,7 +162,7 @@ static int build_link(snd_tplg_t *tplg, struct tplg_elem *elem) if (err < 0) return err;
- /* hw configs */ + /* hw configs & private data */ base = &elem->ref_list; list_for_each(pos, base) {
@@ -185,6 +185,12 @@ static int build_link(snd_tplg_t *tplg, struct tplg_elem *elem) num_hw_configs++; break;
+ case SND_TPLG_TYPE_DATA: /* merge private data */ + err = tplg_copy_data(tplg, elem, ref); + if (err < 0) + return err; + break; + default: break; } @@ -1079,5 +1085,24 @@ int tplg_add_link_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) /* flags */ link->flag_mask = link_tpl->flag_mask; link->flags = link_tpl->flags; + + /* private data */ + if (link_tpl->priv != NULL && link_tpl->priv->size) { + _link = realloc(link, + elem->size + link_tpl->priv->size); + if (!_link) { + tplg_elem_free(elem); + return -ENOMEM; + } + + link = _link; + elem->link = link; + elem->size += link_tpl->priv->size; + + memcpy(link->priv.data, link_tpl->priv->data, + link_tpl->priv->size); + link->priv.size = link_tpl->priv->size; + } + return 0; }
From: Mengdong Lin mengdong.lin@linux.intel.com
Add name and stream name to C API template of physical DAI links.
Signed-off-by: Mengdong Lin mengdong.lin@linux.intel.com
diff --git a/include/topology.h b/include/topology.h index d7971b7..f7ab7fe 100644 --- a/include/topology.h +++ b/include/topology.h @@ -632,6 +632,8 @@ extern "C" { * * id "0" # used for binding to the link * + * stream_name "name" # used for binding to the link + * * hw_configs [ # runtime supported HW configurations, optional * "config1" * "config2" @@ -960,6 +962,8 @@ struct snd_tplg_hw_config_template { struct snd_tplg_link_template { const char *name; /*!< link name */ int id; /*!< unique ID - used to match with existing BE and CC links */ + const char *stream_name; /*!< stream name of the link */ + int num_streams; /*!< number of configs */ struct snd_tplg_stream_template *stream; /*!< supported configs */
diff --git a/src/topology/pcm.c b/src/topology/pcm.c index c4857ba..67d647b 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -640,6 +640,7 @@ int tplg_parse_link(snd_tplg_t *tplg,
link = elem->link; link->size = elem->size; + elem_copy_text(link->name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
tplg_dbg(" Link: %s\n", elem->id);
@@ -673,6 +674,16 @@ int tplg_parse_link(snd_tplg_t *tplg, continue; }
+ if (strcmp(id, "stream_name") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + elem_copy_text(link->stream_name, val, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + tplg_dbg("\t%s: %s\n", id, val); + continue; + } + if (strcmp(id, "hw_configs") == 0) { err = parse_hw_config_refs(tplg, n, elem); if (err < 0) @@ -1066,7 +1077,13 @@ int tplg_add_link_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) link = elem->link; link->size = elem->size;
+ /* ID and names */ link->id = link_tpl->id; + elem_copy_text(link->name, link_tpl->name, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + elem_copy_text(link->stream_name, link_tpl->stream_name, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + /* stream configs */ if (link_tpl->num_streams > SND_SOC_TPLG_STREAM_CONFIG_MAX) return -EINVAL;
From: Mengdong Lin mengdong.lin@linux.intel.com
Add the following fields to manifest: - a count of physical DAIs. Later patches will add new ABI types for physical DAIs. - some reserved fields for future extenstion.
Pump ABI version to 5.
Kerel will handle this ABI update in a backward compatible way, via patch 'ASoC: topology: Make manifest backward compatible from ABI v4'.
Signed-off-by: Mengdong Lin mengdong.lin@linux.intel.com
diff --git a/include/sound/asoc.h b/include/sound/asoc.h index 9dd4d53..5169153 100644 --- a/include/sound/asoc.h +++ b/include/sound/asoc.h @@ -79,7 +79,8 @@ #define SND_SOC_TPLG_NUM_TEXTS 16
/* ABI version */ -#define SND_SOC_TPLG_ABI_VERSION 0x4 +#define SND_SOC_TPLG_ABI_VERSION 0x5 /* current version */ +#define SND_SOC_TPLG_ABI_VERSION_MIN 0x4 /* oldest version supported */
/* Max size of TLV data */ #define SND_SOC_TPLG_TLV_SIZE 32 @@ -333,6 +334,8 @@ struct snd_soc_tplg_manifest { __le32 graph_elems; /* number of graph elements */ __le32 pcm_elems; /* number of PCM elements */ __le32 dai_link_elems; /* number of DAI link elements */ + __le32 dai_elems; /* number of physical DAI elements */ + __le32 reserved[20]; /* reserved for new ABI element types */ struct snd_soc_tplg_private priv; } __attribute__((packed));
From: Guneshwor Singh guneshwor.o.singh@intel.com
Define the type and ABI struct for physical DAIs (e.g. backend DAIs). They are new to ABI and so no backward compatibility risk.
Signed-off-by: Guneshwor Singh guneshwor.o.singh@intel.com Signed-off-by: Mengdong Lin mengdong.lin@linux.intel.com
diff --git a/include/sound/asoc.h b/include/sound/asoc.h index 5169153..8933a91 100644 --- a/include/sound/asoc.h +++ b/include/sound/asoc.h @@ -102,7 +102,8 @@ #define SND_SOC_TPLG_TYPE_CODEC_LINK 9 #define SND_SOC_TPLG_TYPE_BACKEND_LINK 10 #define SND_SOC_TPLG_TYPE_PDATA 11 -#define SND_SOC_TPLG_TYPE_MAX SND_SOC_TPLG_TYPE_PDATA +#define SND_SOC_TPLG_TYPE_DAI 12 +#define SND_SOC_TPLG_TYPE_MAX SND_SOC_TPLG_TYPE_DAI
/* vendor block IDs - please add new vendor types to end */ #define SND_SOC_TPLG_TYPE_VENDOR_FW 1000 @@ -121,6 +122,11 @@ #define SND_SOC_TPLG_TUPLE_TYPE_WORD 4 #define SND_SOC_TPLG_TUPLE_TYPE_SHORT 5
+/* DAI flags */ +#define SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_RATES (1 << 0) +#define SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS (1 << 1) +#define SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS (1 << 2) + /* DAI link flags */ #define SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES (1 << 0) #define SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS (1 << 1) @@ -512,4 +518,27 @@ struct snd_soc_tplg_link_config { __le32 flags; /* SND_SOC_TPLG_LNK_FLGBIT_* flag value */ struct snd_soc_tplg_private priv; } __attribute__((packed)); + +/* + * Describes SW/FW specific features of physical DAI. + * It can be used to configure backend DAIs for DPCM. + * + * File block representation for physical DAI :- + * +-----------------------------------+-----+ + * | struct snd_soc_tplg_hdr | 1 | + * +-----------------------------------+-----+ + * | struct snd_soc_tplg_dai | N | + * +-----------------------------------+-----+ + */ +struct snd_soc_tplg_dai { + __le32 size; /* in bytes of this structure */ + char dai_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* name - used to match */ + __le32 dai_id; /* unique ID - used to match */ + __le32 playback; /* supports playback mode */ + __le32 capture; /* supports capture mode */ + struct snd_soc_tplg_stream_caps caps[2]; /* playback and capture for DAI */ + __le32 flag_mask; /* bitmask of flags to configure */ + __le32 flags; /* SND_SOC_TPLG_DAI_FLGBIT_* */ + struct snd_soc_tplg_private priv; +} __attribute__((packed)); #endif
From: Mengdong Lin mengdong.lin@linux.intel.com
Add support for parsing physical DAIs in the text configuration file. The syntax of physical DAIs is described in document in topology.h
Signed-off-by: Mengdong Lin mengdong.lin@linux.intel.com
diff --git a/include/topology.h b/include/topology.h index f7ab7fe..c0a4f07 100644 --- a/include/topology.h +++ b/include/topology.h @@ -666,6 +666,36 @@ extern "C" { * } * </pre> * + * <h4>Physical DAI</h4> + * A physical DAI (e.g. backend DAI for DPCM) is defined as a new section + * that can include a unique ID, playback and capture stream capabilities, + * optional flags, and private data. <br> + * Its PCM stream capablities are same as those for PCM objects, + * please refer to section 'PCM Capabilities'. + * + * <pre> + * SectionDAI."name" { + * + * index "1" # Index number + * + * id "0" # used for binding to the Backend DAI + * + * pcm."playback" { + * capabilities "capabilities1" # capabilities for playback + * } + * + * pcm."capture" { + * capabilities "capabilities2" # capabilities for capture + * } + * + * symmetric_rates "true" # optional flags + * symmetric_channels "true" + * symmetric_sample_bits "false" + * + * data "name" # optional private data + * } + * </pre> + * * <h4>Manifest Private Data</h4> * Manfiest may have private data. Users need to define a manifest section * and add the references to 1 or multiple data sections. Please refer to @@ -708,6 +738,7 @@ enum snd_tplg_type { SND_TPLG_TYPE_TUPLE, /*!< Vendor tuples */ SND_TPLG_TYPE_LINK, /*!< Physical DAI link */ SND_TPLG_TYPE_HW_CONFIG, /*!< Link HW config */ + SND_TPLG_TYPE_DAI, /*!< Physical DAI */ };
/** diff --git a/src/topology/data.c b/src/topology/data.c index 59bc970..0d5c430 100644 --- a/src/topology/data.c +++ b/src/topology/data.c @@ -46,6 +46,10 @@ struct snd_soc_tplg_private *get_priv_data(struct tplg_elem *elem) priv = &elem->widget->priv; break;
+ case SND_TPLG_TYPE_DAI: + priv = &elem->dai->priv; + break; + default: SNDERR("error: '%s': no support for private data for type %d\n", elem->id, elem->type); diff --git a/src/topology/elem.c b/src/topology/elem.c index 01dce1f..1a5ac84 100644 --- a/src/topology/elem.c +++ b/src/topology/elem.c @@ -192,6 +192,10 @@ struct tplg_elem* tplg_elem_new_common(snd_tplg_t *tplg, list_add_tail(&elem->list, &tplg->pcm_list); obj_size = sizeof(struct snd_soc_tplg_pcm); break; + case SND_TPLG_TYPE_DAI: + list_add_tail(&elem->list, &tplg->dai_list); + obj_size = sizeof(struct snd_soc_tplg_dai); + break; case SND_TPLG_TYPE_BE: case SND_TPLG_TYPE_LINK: list_add_tail(&elem->list, &tplg->be_list); diff --git a/src/topology/parser.c b/src/topology/parser.c index 7d0486c..72efef4 100644 --- a/src/topology/parser.c +++ b/src/topology/parser.c @@ -133,6 +133,14 @@ static int tplg_parse_config(snd_tplg_t *tplg, snd_config_t *cfg) continue; }
+ if (strcmp(id, "SectionDAI") == 0) { + err = tplg_parse_compound(tplg, n, + tplg_parse_dai, NULL); + if (err < 0) + return err; + continue; + } + if (strcmp(id, "SectionHWConfig") == 0) { err = tplg_parse_compound(tplg, n, tplg_parse_hw_config, NULL); @@ -450,6 +458,7 @@ snd_tplg_t *snd_tplg_new(void) INIT_LIST_HEAD(&tplg->tlv_list); INIT_LIST_HEAD(&tplg->widget_list); INIT_LIST_HEAD(&tplg->pcm_list); + INIT_LIST_HEAD(&tplg->dai_list); INIT_LIST_HEAD(&tplg->be_list); INIT_LIST_HEAD(&tplg->cc_list); INIT_LIST_HEAD(&tplg->route_list); @@ -476,6 +485,7 @@ void snd_tplg_free(snd_tplg_t *tplg) tplg_elem_free_list(&tplg->tlv_list); tplg_elem_free_list(&tplg->widget_list); tplg_elem_free_list(&tplg->pcm_list); + tplg_elem_free_list(&tplg->dai_list); tplg_elem_free_list(&tplg->be_list); tplg_elem_free_list(&tplg->cc_list); tplg_elem_free_list(&tplg->route_list); diff --git a/src/topology/pcm.c b/src/topology/pcm.c index 67d647b..b255978 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -341,6 +341,7 @@ static int tplg_parse_streams(snd_tplg_t *tplg ATTRIBUTE_UNUSED, snd_config_t *n; struct tplg_elem *elem = private; struct snd_soc_tplg_pcm *pcm; + struct snd_soc_tplg_dai *dai; unsigned int *playback, *capture; struct snd_soc_tplg_stream_caps *caps; const char *id, *value; @@ -357,6 +358,14 @@ static int tplg_parse_streams(snd_tplg_t *tplg ATTRIBUTE_UNUSED, capture = &pcm->capture; caps = pcm->caps; break; + + case SND_TPLG_TYPE_DAI: + dai = elem->dai; + playback = &dai->playback; + capture = &dai->capture; + caps = dai->caps; + break; + default: return -EINVAL; } @@ -575,6 +584,109 @@ int tplg_parse_pcm(snd_tplg_t *tplg, return 0; }
+/* Parse physical DAI */ +int tplg_parse_dai(snd_tplg_t *tplg, + snd_config_t *cfg, void *private ATTRIBUTE_UNUSED) +{ + struct snd_soc_tplg_dai *dai; + struct tplg_elem *elem; + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id, *val = NULL; + int err; + + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_DAI); + if (!elem) + return -ENOMEM; + + dai = elem->dai; + dai->size = elem->size; + elem_copy_text(dai->dai_name, elem->id, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + + tplg_dbg(" DAI: %s\n", elem->id); + + snd_config_for_each(i, next, cfg) { + + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + + /* skip comments */ + if (strcmp(id, "comment") == 0) + continue; + if (id[0] == '#') + continue; + + if (strcmp(id, "index") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + elem->index = atoi(val); + tplg_dbg("\t%s: %d\n", id, elem->index); + continue; + } + + if (strcmp(id, "id") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + dai->dai_id = atoi(val); + tplg_dbg("\t%s: %d\n", id, dai->dai_id); + continue; + } + + /* stream capabilities */ + if (strcmp(id, "pcm") == 0) { + err = tplg_parse_compound(tplg, n, + tplg_parse_streams, elem); + if (err < 0) + return err; + continue; + } + + /* flags */ + if (strcmp(id, "symmetric_rates") == 0) { + err = parse_flag(n, + SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_RATES, + &dai->flag_mask, &dai->flags); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "symmetric_channels") == 0) { + err = parse_flag(n, + SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS, + &dai->flag_mask, &dai->flags); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "symmetric_sample_bits") == 0) { + err = parse_flag(n, + SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS, + &dai->flag_mask, &dai->flags); + if (err < 0) + return err; + continue; + } + + /* private data */ + if (strcmp(id, "data") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + tplg_ref_add(elem, SND_TPLG_TYPE_DATA, val); + tplg_dbg("\t%s: %s\n", id, val); + continue; + } + } + + return 0; +} + /* parse physical link runtime supported HW configs in text conf file */ static int parse_hw_config_refs(snd_tplg_t *tplg, snd_config_t *cfg, struct tplg_elem *elem) diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h index 9e67bf8..eeeb0f1 100644 --- a/src/topology/tplg_local.h +++ b/src/topology/tplg_local.h @@ -64,6 +64,7 @@ struct snd_tplg { struct list_head tlv_list; struct list_head widget_list; struct list_head pcm_list; + struct list_head dai_list; struct list_head be_list; struct list_head cc_list; struct list_head route_list; @@ -145,6 +146,7 @@ struct tplg_elem { struct snd_soc_tplg_bytes_control *bytes_ext; struct snd_soc_tplg_dapm_widget *widget; struct snd_soc_tplg_pcm *pcm; + struct snd_soc_tplg_dai *dai; struct snd_soc_tplg_link_config *link;/* physical link */ struct snd_soc_tplg_dapm_graph_elem *route; struct snd_soc_tplg_stream *stream_cfg; @@ -222,6 +224,9 @@ int tplg_parse_stream_caps(snd_tplg_t *tplg, int tplg_parse_pcm(snd_tplg_t *tplg, snd_config_t *cfg, void *private ATTRIBUTE_UNUSED);
+int tplg_parse_dai(snd_tplg_t *tplg, snd_config_t *cfg, + void *private ATTRIBUTE_UNUSED); + int tplg_parse_link(snd_tplg_t *tplg, snd_config_t *cfg, void *private ATTRIBUTE_UNUSED);
From: Guneshwor Singh guneshwor.o.singh@intel.com
In addition to text conf file, BE (Back End) DAI configurations can also be added by C API. This patch defines the template to add BE DAI configurations from C API.
Signed-off-by: Guneshwor Singh guneshwor.o.singh@intel.com Signed-off-by: Mengdong Lin mengdong.lin@linux.intel.com
diff --git a/include/topology.h b/include/topology.h index c0a4f07..7b0f3ad 100644 --- a/include/topology.h +++ b/include/topology.h @@ -987,6 +987,21 @@ struct snd_tplg_hw_config_template { unsigned int *rx_chanmap; /* array of slot number */ };
+/** \struct snd_tplg_be_dai_template + * \brief Template type for Back End DAI. + */ +struct snd_tplg_be_dai_template { + const char *dai_name; /*!< DAI name */ + unsigned int dai_id; /*!< unique ID - used to match */ + unsigned int playback; /*!< supports playback mode */ + unsigned int capture; /*!< supports capture mode */ + struct snd_tplg_stream_caps_template *caps[2]; /*!< playback & capture for DAI */ + unsigned int flag_mask; /*!< bitmask of flags to configure */ + unsigned int flags; /*!< SND_SOC_TPLG_DAI_FLGBIT_* */ + struct snd_soc_tplg_private *priv; /*!< private data */ + +}; + /** \struct snd_tplg_link_template * \brief Template type for BE and CC DAI Links. */ @@ -1023,6 +1038,7 @@ typedef struct snd_tplg_obj_template { struct snd_tplg_graph_template *graph; /*!< Graph elements */ struct snd_tplg_pcm_template *pcm; /*!< PCM elements */ struct snd_tplg_link_template *link; /*!< BE and CC Links */ + struct snd_tplg_be_dai_template *dai; /*!< Physical DAI */ }; } snd_tplg_obj_template_t;
diff --git a/src/topology/parser.c b/src/topology/parser.c index 72efef4..4afa576 100644 --- a/src/topology/parser.c +++ b/src/topology/parser.c @@ -364,6 +364,8 @@ int snd_tplg_add_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) return tplg_add_graph_object(tplg, t); case SND_TPLG_TYPE_PCM: return tplg_add_pcm_object(tplg, t); + case SND_TPLG_TYPE_DAI: + return tplg_add_dai_object(tplg, t); case SND_TPLG_TYPE_LINK: case SND_TPLG_TYPE_BE: case SND_TPLG_TYPE_CC: diff --git a/src/topology/pcm.c b/src/topology/pcm.c index b255978..e1d266a 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -1235,3 +1235,58 @@ int tplg_add_link_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
return 0; } + +int tplg_add_dai_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) +{ + struct snd_tplg_be_dai_template *dai_tpl = t->dai; + struct snd_soc_tplg_dai *dai, *_dai; + struct tplg_elem *elem; + int i; + + tplg_dbg("DAI %s\n", dai_tpl->dai_name); + + elem = tplg_elem_new_common(tplg, NULL, dai_tpl->dai_name, + SND_TPLG_TYPE_DAI); + if (!elem) + return -ENOMEM; + + dai = elem->dai; + dai->size = elem->size; + + elem_copy_text(dai->dai_name, dai_tpl->dai_name, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + dai->dai_id = dai_tpl->dai_id; + + /* stream caps */ + dai->playback = dai_tpl->playback; + dai->capture = dai_tpl->capture; + + for (i = 0; i < 2; i++) { + if (dai_tpl->caps[i]) + tplg_add_stream_caps(&dai->caps[i], dai_tpl->caps[i]); + } + + /* flags */ + dai->flag_mask = dai_tpl->flag_mask; + dai->flags = dai_tpl->flags; + + /* private data */ + if (dai_tpl->priv != NULL) { + _dai = realloc(dai, + elem->size + dai_tpl->priv->size); + if (!_dai) { + tplg_elem_free(elem); + return -ENOMEM; + } + + dai = _dai; + dai->priv.size = dai_tpl->priv->size; + + elem->dai = dai; + elem->size += dai->priv.size; + memcpy(dai->priv.data, dai_tpl->priv->data, + dai->priv.size); + } + + return 0; +} diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h index eeeb0f1..807462b 100644 --- a/src/topology/tplg_local.h +++ b/src/topology/tplg_local.h @@ -297,3 +297,4 @@ int tplg_build_pcms(snd_tplg_t *tplg, unsigned int type); int tplg_build_links(snd_tplg_t *tplg, unsigned int type); int tplg_add_link_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t); int tplg_add_pcm_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t); +int tplg_add_dai_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t);
From: Guneshwor Singh guneshwor.o.singh@intel.com
Export the physical DAI objects to the binary output file for kernel. For physical DAIs defined by the text conf file, find and merge their stream capablities and private data before exporting.
Signed-off-by: Guneshwor Singh guneshwor.o.singh@intel.com Signed-off-by: Mengdong Lin mengdong.lin@linux.intel.com
diff --git a/src/topology/builder.c b/src/topology/builder.c index b0ba54e..20fa925 100644 --- a/src/topology/builder.c +++ b/src/topology/builder.c @@ -204,6 +204,9 @@ static int write_block(snd_tplg_t *tplg, struct list_head *base, case SND_TPLG_TYPE_DATA: return write_elem_block(tplg, base, size, SND_SOC_TPLG_TYPE_PDATA, "data"); + case SND_TPLG_TYPE_DAI: + return write_elem_block(tplg, base, size, + SND_SOC_TPLG_TYPE_DAI, "dai"); default: return -EINVAL; } @@ -293,6 +296,14 @@ int tplg_write_data(snd_tplg_t *tplg) return ret; }
+ /* write physical dai elems */ + ret = write_block(tplg, &tplg->dai_list, + SND_TPLG_TYPE_DAI); + if (ret < 0) { + SNDERR("failed to write physical dai elems %d\n", ret); + return ret; + } + /* write be elems */ ret = write_block(tplg, &tplg->be_list, SND_TPLG_TYPE_BE); diff --git a/src/topology/parser.c b/src/topology/parser.c index 4afa576..c5f9757 100644 --- a/src/topology/parser.c +++ b/src/topology/parser.c @@ -288,6 +288,10 @@ static int tplg_build_integ(snd_tplg_t *tplg) if (err < 0) return err;
+ err = tplg_build_dais(tplg, SND_TPLG_TYPE_DAI); + if (err < 0) + return err; + err = tplg_build_links(tplg, SND_TPLG_TYPE_BE); if (err < 0) return err; diff --git a/src/topology/pcm.c b/src/topology/pcm.c index e1d266a..c41831c 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -129,6 +129,61 @@ int tplg_build_pcms(snd_tplg_t *tplg, unsigned int type) return 0; }
+/* build a physical DAI */ +static int tplg_build_dai(snd_tplg_t *tplg, struct tplg_elem *elem) +{ + struct tplg_ref *ref; + struct list_head *base, *pos; + int err = 0; + + /* get playback & capture stream caps */ + err = tplg_build_stream_caps(tplg, elem->id, elem->dai->caps); + if (err < 0) + return err; + + /* get private data */ + base = &elem->ref_list; + list_for_each(pos, base) { + + ref = list_entry(pos, struct tplg_ref, list); + + if (ref->type == SND_TPLG_TYPE_DATA) { + err = tplg_copy_data(tplg, elem, ref); + if (err < 0) + return err; + } + } + + /* add DAI to manifest */ + tplg->manifest.dai_elems++; + + return 0; +} + +/* build physical DAIs*/ +int tplg_build_dais(snd_tplg_t *tplg, unsigned int type) +{ + struct list_head *base, *pos; + struct tplg_elem *elem; + int err = 0; + + base = &tplg->dai_list; + list_for_each(pos, base) { + + elem = list_entry(pos, struct tplg_elem, list); + if (elem->type != type) { + SNDERR("error: invalid elem '%s'\n", elem->id); + return -EINVAL; + } + + err = tplg_build_dai(tplg, elem); + if (err < 0) + return err; + } + + return 0; +} + static int tplg_build_stream_cfg(snd_tplg_t *tplg, struct snd_soc_tplg_stream *stream, int num_streams) { diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h index 807462b..f913563 100644 --- a/src/topology/tplg_local.h +++ b/src/topology/tplg_local.h @@ -294,6 +294,7 @@ int tplg_add_bytes(snd_tplg_t *tplg, struct snd_tplg_bytes_template *bytes_ctl, struct tplg_elem **e);
int tplg_build_pcms(snd_tplg_t *tplg, unsigned int type); +int tplg_build_dais(snd_tplg_t *tplg, unsigned int type); int tplg_build_links(snd_tplg_t *tplg, unsigned int type); int tplg_add_link_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t); int tplg_add_pcm_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t);
participants (1)
-
mengdong.lin@linux.intel.com