[alsa-devel] [PATCH v2 0/3] ASoC: topology: Add support for BE DAIs
From: Mengdong Lin mengdong.lin@linux.intel.com
There is topology ABI udpate in this series. Topology core can check size of each ABI objects to detect version mismatch between user space and kernel.
This series adds support for BE (Back End) DAIs: - Define the type and ABI struct for Backend DAIs. - The topology core can configure an existing BE DAI or create new BE DAIs.
The user space series "topology: Add support for BE DAIs" is also submitted.
There will be 2 pairs of kernel & user space series for PCM & BE links later.
History: v2: Remove unused argument to fix the compiler warning. sound/soc/soc-topology.c: In function ‘soc_tplg_be_dai_config’: sound/soc/soc-topology.c:1789:22: warning: too many arguments for format [-Wformat-extra-args] dev_err(tplg->dev, "ASoC: Invalid BE DAI name\n",
Mengdong Lin (3): ASoC: topology: ABI - Add the types for BE DAI ASoC: topology: Add support for configuring existing BE DAIs ASoC: topology: Able to create BE DAIs
include/sound/soc-topology.h | 1 + include/uapi/sound/asoc.h | 34 +++++++++- sound/soc/soc-core.c | 3 +- sound/soc/soc-topology.c | 155 ++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 188 insertions(+), 5 deletions(-)
From: Mengdong Lin mengdong.lin@linux.intel.com
Define the type and ABI struct for Backend DAIs. Add the number of BE DAIs to manifest, and some reserved fields for future extensions.
Pump the version number to 5.
Topology core will check size of ABI objects to detect version mismatch between user space and kernel.
Signed-off-by: Guneshwor Singh guneshwor.o.singh@intel.com Signed-off-by: Mengdong Lin mengdong.lin@linux.intel.com
diff --git a/include/uapi/sound/asoc.h b/include/uapi/sound/asoc.h index e4701a3..f734bea 100644 --- a/include/uapi/sound/asoc.h +++ b/include/uapi/sound/asoc.h @@ -83,7 +83,7 @@ #define SND_SOC_TPLG_NUM_TEXTS 16
/* ABI version */ -#define SND_SOC_TPLG_ABI_VERSION 0x4 +#define SND_SOC_TPLG_ABI_VERSION 0x5
/* Max size of TLV data */ #define SND_SOC_TPLG_TLV_SIZE 32 @@ -105,7 +105,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_BE_DAI 12 +#define SND_SOC_TPLG_TYPE_MAX SND_SOC_TPLG_TYPE_BE_DAI
/* vendor block IDs - please add new vendor types to end */ #define SND_SOC_TPLG_TYPE_VENDOR_FW 1000 @@ -124,6 +125,11 @@ #define SND_SOC_TPLG_TUPLE_TYPE_WORD 4 #define SND_SOC_TPLG_TUPLE_TYPE_SHORT 5
+/* BE 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) + /* * Block Header. * This header precedes all object and object arrays below. @@ -285,6 +291,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 be_dai_elems; /* number of BE DAI elements */ + __le32 reserved[20]; /* reserved for new ABI element types */ struct snd_soc_tplg_private priv; } __attribute__((packed));
@@ -450,4 +458,26 @@ struct snd_soc_tplg_link_config { struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* supported configs playback and captrure */ __le32 num_streams; /* number of streams */ } __attribute__((packed)); + +/* + * Describes SW/FW specific features of BE DAI. + * + * File block representation for BE DAI :- + * +-----------------------------------+-----+ + * | struct snd_soc_tplg_hdr | 1 | + * +-----------------------------------+-----+ + * | struct snd_soc_tplg_be_dai | N | + * +-----------------------------------+-----+ + */ +struct snd_soc_tplg_be_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
The platform driver may just specify the BE (Back End) DAI name and ID. And topology will find the existing BE DAI by its name and ID, and then configure its stream caps and flags.
Signed-off-by: Mengdong Lin mengdong.lin@linux.intel.com
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index ee7f15a..05a18f6 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -48,9 +48,10 @@ #define SOC_TPLG_PASS_PCM_DAI 4 #define SOC_TPLG_PASS_GRAPH 5 #define SOC_TPLG_PASS_PINS 6 +#define SOC_TPLG_PASS_BE_DAI 7
#define SOC_TPLG_PASS_START SOC_TPLG_PASS_MANIFEST -#define SOC_TPLG_PASS_END SOC_TPLG_PASS_PINS +#define SOC_TPLG_PASS_END SOC_TPLG_PASS_BE_DAI
struct soc_tplg { const struct firmware *fw; @@ -1556,6 +1557,24 @@ static void set_stream_info(struct snd_soc_pcm_stream *stream, stream->formats = caps->formats; }
+static void set_dai_flags(struct snd_soc_dai_driver *dai_drv, + unsigned int flag_mask, unsigned int flags) +{ + if (flag_mask & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_RATES) + dai_drv->symmetric_rates = + flags & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_RATES ? 1 : 0; + + if (flag_mask & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS) + dai_drv->symmetric_channels = + flags & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS ? + 1 : 0; + + if (flag_mask & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS) + dai_drv->symmetric_samplebits = + flags & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS ? + 1 : 0; +} + static int soc_tplg_dai_create(struct soc_tplg *tplg, struct snd_soc_tplg_pcm *pcm) { @@ -1690,8 +1709,96 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, return 0; }
+/* * + * soc_tplg_be_dai_config - Find and configure an existing BE DAI. + * @tplg: topology context + * @be: topology BE DAI configs. + * + * The BE dai should already be registered by the platform driver. The + * platform driver should specify the BE DAI name and ID for matching. + */ +static int soc_tplg_be_dai_config(struct soc_tplg *tplg, + struct snd_soc_tplg_be_dai *be) +{ + struct snd_soc_dai_link_component dai_component = {0}; + struct snd_soc_dai *dai; + struct snd_soc_dai_driver *dai_drv; + struct snd_soc_pcm_stream *stream; + struct snd_soc_tplg_stream_caps *caps; + int ret; + + dai_component.dai_name = be->dai_name; + dai = snd_soc_find_dai(&dai_component); + if (!dai) { + dev_err(tplg->dev, "ASoC: BE DAI %s not registered\n", + be->dai_name); + return -EINVAL; + } + + if (be->dai_id != dai->id) { + dev_err(tplg->dev, "ASoC: BE DAI %s id mismatch\n", + be->dai_name); + return -EINVAL; + } + + dai_drv = dai->driver; + if (!dai_drv) + return -EINVAL; + + if (be->playback) { + stream = &dai_drv->playback; + caps = &be->caps[SND_SOC_TPLG_STREAM_PLAYBACK]; + set_stream_info(stream, caps); + } + + if (be->capture) { + stream = &dai_drv->capture; + caps = &be->caps[SND_SOC_TPLG_STREAM_CAPTURE]; + set_stream_info(stream, caps); + } + + if (be->flag_mask) + set_dai_flags(dai_drv, be->flag_mask, be->flags); + + /* pass control to component driver for optional further init */ + ret = soc_tplg_dai_load(tplg, dai_drv); + if (ret < 0) { + dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n"); + return ret; + } + + return 0; +} + +static int soc_tplg_be_dai_elems_load(struct soc_tplg *tplg, + struct snd_soc_tplg_hdr *hdr) +{ + struct snd_soc_tplg_be_dai *be; + int count = hdr->count; + int i; + + if (tplg->pass != SOC_TPLG_PASS_BE_DAI) + return 0; + + /* config the existing BE DAIs */ + for (i = 0; i < count; i++) { + be = (struct snd_soc_tplg_be_dai *)tplg->pos; + if (be->size != sizeof(*be)) { + dev_err(tplg->dev, "ASoC: invalid BE DAI size\n"); + return -EINVAL; + } + + soc_tplg_be_dai_config(tplg, be); + tplg->pos += (sizeof(*be) + be->priv.size); + } + + dev_dbg(tplg->dev, "ASoC: Configure %d BE DAIs\n", count); + return 0; +} + + static int soc_tplg_manifest_load(struct soc_tplg *tplg, - struct snd_soc_tplg_hdr *hdr) + struct snd_soc_tplg_hdr *hdr) { struct snd_soc_tplg_manifest *manifest;
@@ -1793,6 +1900,8 @@ static int soc_tplg_load_header(struct soc_tplg *tplg, return soc_tplg_dapm_widget_elems_load(tplg, hdr); case SND_SOC_TPLG_TYPE_PCM: return soc_tplg_pcm_elems_load(tplg, hdr); + case SND_SOC_TPLG_TYPE_BE_DAI: + return soc_tplg_be_dai_elems_load(tplg, hdr); case SND_SOC_TPLG_TYPE_MANIFEST: return soc_tplg_manifest_load(tplg, hdr); default:
From: Mengdong Lin mengdong.lin@linux.intel.com
Topology will check with ASoC if a BE DAI already exists by checking its name. If the BE DAI doesn't exist, topology will create a new one and the dai_load ops will be called for device specific init.
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/soc-topology.h b/include/sound/soc-topology.h index d318fe4..9ebb9f2 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -39,6 +39,7 @@ enum snd_soc_dobj_type { SND_SOC_DOBJ_ENUM, SND_SOC_DOBJ_BYTES, SND_SOC_DOBJ_PCM, + SND_SOC_DOBJ_BE_DAI, SND_SOC_DOBJ_DAI_LINK, SND_SOC_DOBJ_CODEC_LINK, SND_SOC_DOBJ_WIDGET, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 16369ca..c0ee988 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2872,7 +2872,8 @@ int snd_soc_register_dai(struct snd_soc_component *component, struct snd_soc_dai *dai; int ret;
- if (dai_drv->dobj.type != SND_SOC_DOBJ_PCM) { + if (!(dai_drv->dobj.type == SND_SOC_DOBJ_PCM || + dai_drv->dobj.type == SND_SOC_DOBJ_BE_DAI)) { dev_err(component->dev, "Invalid dai type %d\n", dai_drv->dobj.type); return -EINVAL; diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 05a18f6..f01448d 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1709,42 +1709,14 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, return 0; }
-/* * - * soc_tplg_be_dai_config - Find and configure an existing BE DAI. - * @tplg: topology context - * @be: topology BE DAI configs. - * - * The BE dai should already be registered by the platform driver. The - * platform driver should specify the BE DAI name and ID for matching. - */ -static int soc_tplg_be_dai_config(struct soc_tplg *tplg, +static int config_be_dai(struct soc_tplg *tplg, + struct snd_soc_dai_driver *dai_drv, struct snd_soc_tplg_be_dai *be) { - struct snd_soc_dai_link_component dai_component = {0}; - struct snd_soc_dai *dai; - struct snd_soc_dai_driver *dai_drv; struct snd_soc_pcm_stream *stream; struct snd_soc_tplg_stream_caps *caps; int ret;
- dai_component.dai_name = be->dai_name; - dai = snd_soc_find_dai(&dai_component); - if (!dai) { - dev_err(tplg->dev, "ASoC: BE DAI %s not registered\n", - be->dai_name); - return -EINVAL; - } - - if (be->dai_id != dai->id) { - dev_err(tplg->dev, "ASoC: BE DAI %s id mismatch\n", - be->dai_name); - return -EINVAL; - } - - dai_drv = dai->driver; - if (!dai_drv) - return -EINVAL; - if (be->playback) { stream = &dai_drv->playback; caps = &be->caps[SND_SOC_TPLG_STREAM_PLAYBACK]; @@ -1770,6 +1742,73 @@ static int soc_tplg_be_dai_config(struct soc_tplg *tplg, return 0; }
+static int soc_tplg_be_dai_create(struct soc_tplg *tplg, + struct snd_soc_tplg_be_dai *be) +{ + struct snd_soc_dai_driver *dai_drv; + int ret; + + dai_drv = kzalloc(sizeof(struct snd_soc_dai_driver), GFP_KERNEL); + if (dai_drv == NULL) + return -ENOMEM; + + dai_drv->name = be->dai_name; + dai_drv->id = be->dai_id; + + ret = config_be_dai(tplg, dai_drv, be); + if (ret < 0) { + kfree(dai_drv); + return ret; + } + + dai_drv->dobj.index = tplg->index; + dai_drv->dobj.ops = tplg->ops; + dai_drv->dobj.type = SND_SOC_DOBJ_BE_DAI; + list_add(&dai_drv->dobj.list, &tplg->comp->dobj_list); + + /* register the DAI to the component */ + return snd_soc_register_dai(tplg->comp, dai_drv); +} + +/* * + * soc_tplg_be_dai_config - Create a new BE DAI or configure an existing one. + * @tplg: topology context + * @be: topology BE DAI configs. + * + * The BE dai should already be registered by the platform driver. The + * platform driver should specify the BE DAI name and ID for matching. + */ +static int soc_tplg_be_dai_config(struct soc_tplg *tplg, + struct snd_soc_tplg_be_dai *be) +{ + struct snd_soc_dai_link_component dai_component = {0}; + struct snd_soc_dai *dai; + struct snd_soc_dai_driver *dai_drv; + + if (!strlen(be->dai_name)) { + dev_err(tplg->dev, "ASoC: Invalid BE DAI name\n"); + return -EINVAL; + } + + dai_component.dai_name = be->dai_name; + dai = snd_soc_find_dai(&dai_component); + if (!dai) /* BE DAI doesn't exist, create it */ + return soc_tplg_be_dai_create(tplg, be); + + /* configure an existing BE DAI */ + if (be->dai_id != dai->id) { + dev_err(tplg->dev, "ASoC: BE DAI %s id mismatch\n", + be->dai_name); + return -EINVAL; + } + + dai_drv = dai->driver; + if (!dai_drv) + return -EINVAL; + + return config_be_dai(tplg, dai_drv, be); +} + static int soc_tplg_be_dai_elems_load(struct soc_tplg *tplg, struct snd_soc_tplg_hdr *hdr) { @@ -2061,6 +2100,9 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index) case SND_SOC_DOBJ_PCM: remove_dai(comp, dobj, pass); break; + case SND_SOC_DOBJ_BE_DAI: + remove_dai(comp, dobj, pass); + break; case SND_SOC_DOBJ_DAI_LINK: remove_link(comp, dobj, pass); break;
Excuse me, I'll be on vacation until Aug. 14th. Please kindly leave your comments if you review the patches, and I'll address when I'm back to work.
Thanks Mengdong
-----Original Message----- From: mengdong.lin@linux.intel.com [mailto:mengdong.lin@linux.intel.com] Sent: Tuesday, July 26, 2016 2:31 PM To: alsa-devel@alsa-project.org; broonie@kernel.org Cc: tiwai@suse.de; perex@perex.cz; liam.r.girdwood@linux.intel.com; Shah, Hardik T; Singh, Guneshwor O; Lin, Mengdong; Mengdong Lin Subject: [PATCH v2 0/3] ASoC: topology: Add support for BE DAIs
From: Mengdong Lin mengdong.lin@linux.intel.com
There is topology ABI udpate in this series. Topology core can check size of each ABI objects to detect version mismatch between user space and kernel.
This series adds support for BE (Back End) DAIs:
- Define the type and ABI struct for Backend DAIs.
- The topology core can configure an existing BE DAI or create new BE DAIs.
The user space series "topology: Add support for BE DAIs" is also submitted.
There will be 2 pairs of kernel & user space series for PCM & BE links later.
History: v2: Remove unused argument to fix the compiler warning. sound/soc/soc-topology.c: In function ‘soc_tplg_be_dai_config’: sound/soc/soc-topology.c:1789:22: warning: too many arguments for format [-Wformat-extra-args] dev_err(tplg->dev, "ASoC: Invalid BE DAI name\n",
Mengdong Lin (3): ASoC: topology: ABI - Add the types for BE DAI ASoC: topology: Add support for configuring existing BE DAIs ASoC: topology: Able to create BE DAIs
include/sound/soc-topology.h | 1 + include/uapi/sound/asoc.h | 34 +++++++++- sound/soc/soc-core.c | 3 +- sound/soc/soc-topology.c | 155 ++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 188 insertions(+), 5 deletions(-)
-- 2.5.0
participants (2)
-
Lin, Mengdong
-
mengdong.lin@linux.intel.com