diff mbox series

[03/16] ASoC: Intel: avs: Improve topology parsing of dynamic strings

Message ID 20231011121703.363652-4-amadeuszx.slawinski@linux.intel.com (mailing list archive)
State Superseded
Headers show
Series Harden SSP boards and add TDM support | expand

Commit Message

Amadeusz Sławiński Oct. 11, 2023, 12:16 p.m. UTC
Current mechanism replaces "%d" present in some routes and widget names
with SSP number. However there are also configurations which make use of
TDM number, in which case expected behavior would be to have string in
form of SSP:TDM - see implementation of avs_i2s_platform_register() in
sound/soc/intel/avs/pcm.c.

Implement custom function, which parses string and make use of it when
parsing topology. While at it make sure that we generate dynamic names
only if there is no multiple SSPs or TDMs defined.

Reviewed-by: Cezary Rojewski <cezary.rojewski@intel.com>
Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
---
 sound/soc/intel/avs/topology.c | 102 ++++++++++++++++++++++++++-------
 1 file changed, 80 insertions(+), 22 deletions(-)
diff mbox series

Patch

diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c
index 45d0eb2a8e71..c74e9d622e4c 100644
--- a/sound/soc/intel/avs/topology.c
+++ b/sound/soc/intel/avs/topology.c
@@ -15,6 +15,7 @@ 
 #include "avs.h"
 #include "control.h"
 #include "topology.h"
+#include "utils.h"
 
 /* Get pointer to vendor array at the specified offset. */
 #define avs_tplg_vendor_array_at(array, offset) \
@@ -371,22 +372,50 @@  parse_audio_format_bitfield(struct snd_soc_component *comp, void *elem, void *ob
 	return 0;
 }
 
+static int avs_ssp_sprint(char *buf, size_t size, const char *fmt, int port, int tdm)
+{
+	char *needle = strstr(fmt, "%d");
+	int retsize;
+
+	/*
+	 * If there is %d present in fmt string it should be replaced by either
+	 * SSP or SSP:TDM, where SSP and TDM are numbers, all other formatting
+	 * will be ignored.
+	 */
+	if (needle) {
+		retsize = scnprintf(buf, min_t(size_t, size, needle - fmt + 1), "%s", fmt);
+		retsize += scnprintf(buf + retsize, size - retsize, "%d", port);
+		if (tdm)
+			retsize += scnprintf(buf + retsize, size - retsize, ":%d", tdm);
+		retsize += scnprintf(buf + retsize, size - retsize, "%s", needle + 2);
+		return retsize;
+	}
+
+	return snprintf(buf, size, "%s", fmt);
+}
+
 static int parse_link_formatted_string(struct snd_soc_component *comp, void *elem,
 				       void *object, u32 offset)
 {
 	struct snd_soc_tplg_vendor_string_elem *tuple = elem;
 	struct snd_soc_acpi_mach *mach = dev_get_platdata(comp->card->dev);
 	char *val = (char *)((u8 *)object + offset);
+	int ssp_port, tdm_slot;
 
 	/*
 	 * Dynamic naming - string formats, e.g.: ssp%d - supported only for
 	 * topologies describing single device e.g.: an I2S codec on SSP0.
 	 */
-	if (hweight_long(mach->mach_params.i2s_link_mask) != 1)
+	if (!avs_mach_singular_ssp(mach))
+		return avs_parse_string_token(comp, elem, object, offset);
+
+	ssp_port = avs_mach_ssp_port(mach);
+	if (!avs_mach_singular_tdm(mach, ssp_port))
 		return avs_parse_string_token(comp, elem, object, offset);
 
-	snprintf(val, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, tuple->string,
-		 __ffs(mach->mach_params.i2s_link_mask));
+	tdm_slot = avs_mach_ssp_tdm(mach, ssp_port);
+
+	avs_ssp_sprint(val, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, tuple->string, ssp_port, tdm_slot);
 
 	return 0;
 }
@@ -813,6 +842,7 @@  static void
 assign_copier_gtw_instance(struct snd_soc_component *comp, struct avs_tplg_modcfg_ext *cfg)
 {
 	struct snd_soc_acpi_mach *mach;
+	int ssp_port, tdm_slot;
 
 	if (!guid_equal(&cfg->type, &AVS_COPIER_MOD_UUID))
 		return;
@@ -826,11 +856,22 @@  assign_copier_gtw_instance(struct snd_soc_component *comp, struct avs_tplg_modcf
 		return;
 	}
 
+	/* If topology sets value don't overwrite it */
+	if (cfg->copier.vindex.i2s.instance)
+		return;
+
 	mach = dev_get_platdata(comp->card->dev);
 
-	/* Automatic assignment only when board describes single SSP. */
-	if (hweight_long(mach->mach_params.i2s_link_mask) == 1 && !cfg->copier.vindex.i2s.instance)
-		cfg->copier.vindex.i2s.instance = __ffs(mach->mach_params.i2s_link_mask);
+	if (!avs_mach_singular_ssp(mach))
+		return;
+	ssp_port = avs_mach_ssp_port(mach);
+
+	if (!avs_mach_singular_tdm(mach, ssp_port))
+		return;
+	tdm_slot = avs_mach_ssp_tdm(mach, ssp_port);
+
+	cfg->copier.vindex.i2s.instance = ssp_port;
+	cfg->copier.vindex.i2s.time_slot = tdm_slot;
 }
 
 static int avs_tplg_parse_modcfg_ext(struct snd_soc_component *comp,
@@ -1381,20 +1422,24 @@  static int avs_route_load(struct snd_soc_component *comp, int index,
 	struct snd_soc_acpi_mach *mach = dev_get_platdata(comp->card->dev);
 	size_t len = SNDRV_CTL_ELEM_ID_NAME_MAXLEN;
 	char buf[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-	u32 port;
+	int ssp_port, tdm_slot;
 
 	/* See parse_link_formatted_string() for dynamic naming when(s). */
-	if (hweight_long(mach->mach_params.i2s_link_mask) == 1) {
-		port = __ffs(mach->mach_params.i2s_link_mask);
-
-		snprintf(buf, len, route->source, port);
-		strscpy((char *)route->source, buf, len);
-		snprintf(buf, len, route->sink, port);
-		strscpy((char *)route->sink, buf, len);
-		if (route->control) {
-			snprintf(buf, len, route->control, port);
-			strscpy((char *)route->control, buf, len);
-		}
+	if (!avs_mach_singular_ssp(mach))
+		return 0;
+	ssp_port = avs_mach_ssp_port(mach);
+
+	if (!avs_mach_singular_tdm(mach, ssp_port))
+		return 0;
+	tdm_slot = avs_mach_ssp_tdm(mach, ssp_port);
+
+	avs_ssp_sprint(buf, len, route->source, ssp_port, tdm_slot);
+	strscpy((char *)route->source, buf, len);
+	avs_ssp_sprint(buf, len, route->sink, ssp_port, tdm_slot);
+	strscpy((char *)route->sink, buf, len);
+	if (route->control) {
+		avs_ssp_sprint(buf, len, route->control, ssp_port, tdm_slot);
+		strscpy((char *)route->control, buf, len);
 	}
 
 	return 0;
@@ -1408,6 +1453,7 @@  static int avs_widget_load(struct snd_soc_component *comp, int index,
 	struct avs_tplg_path_template *template;
 	struct avs_soc_component *acomp = to_avs_soc_component(comp);
 	struct avs_tplg *tplg;
+	int ssp_port, tdm_slot;
 
 	if (!le32_to_cpu(dw->priv.size))
 		return 0;
@@ -1419,16 +1465,28 @@  static int avs_widget_load(struct snd_soc_component *comp, int index,
 
 	tplg = acomp->tplg;
 	mach = dev_get_platdata(comp->card->dev);
+	if (!avs_mach_singular_ssp(mach))
+		goto static_name;
+	ssp_port = avs_mach_ssp_port(mach);
 
 	/* See parse_link_formatted_string() for dynamic naming when(s). */
-	if (hweight_long(mach->mach_params.i2s_link_mask) == 1) {
+	if (avs_mach_singular_tdm(mach, ssp_port)) {
+		/* size is based on possible %d -> SSP:TDM, where SSP and TDM < 10 + '\0' */
+		size_t size = strlen(dw->name) + 2;
+		char *buf;
+
+		tdm_slot = avs_mach_ssp_tdm(mach, ssp_port);
+
+		buf = kmalloc(size, GFP_KERNEL);
+		if (!buf)
+			return -ENOMEM;
+		avs_ssp_sprint(buf, size, dw->name, ssp_port, tdm_slot);
 		kfree(w->name);
 		/* w->name is freed later by soc_tplg_dapm_widget_create() */
-		w->name = kasprintf(GFP_KERNEL, dw->name, __ffs(mach->mach_params.i2s_link_mask));
-		if (!w->name)
-			return -ENOMEM;
+		w->name = buf;
 	}
 
+static_name:
 	template = avs_tplg_path_template_create(comp, tplg, dw->priv.array,
 						 le32_to_cpu(dw->priv.size));
 	if (IS_ERR(template)) {