summaryrefslogtreecommitdiffstats
path: root/sound/soc/sof/topology.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2022-12-22 09:11:48 +0100
committerTakashi Iwai <tiwai@suse.de>2022-12-22 09:11:48 +0100
commit2d78eb0342dd2c9c5cde9ae9ada1d33f189a858b (patch)
treef711bc9cab45f4963e4883ef15ff4c54a6cbc12e /sound/soc/sof/topology.c
parentb47068b4aa53a57552398e3f60d0ed1918700c2b (diff)
parentee0b089d660021792e4ab4dda191b097ce1e964f (diff)
downloadlinux-2d78eb0342dd2c9c5cde9ae9ada1d33f189a858b.tar.bz2
Merge branch 'for-next' into for-linus
Diffstat (limited to 'sound/soc/sof/topology.c')
-rw-r--r--sound/soc/sof/topology.c187
1 files changed, 179 insertions, 8 deletions
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index 6a0e7f3b5023..c668bd9d21ec 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -289,6 +289,9 @@ static const struct sof_dai_types sof_dais[] = {
{"ACPDMIC", SOF_DAI_AMD_DMIC},
{"ACPHS", SOF_DAI_AMD_HS},
{"AFE", SOF_DAI_MEDIATEK_AFE},
+ {"ACPSP_VIRTUAL", SOF_DAI_AMD_SP_VIRTUAL},
+ {"ACPHS_VIRTUAL", SOF_DAI_AMD_HS_VIRTUAL},
+
};
static enum sof_ipc_dai_type find_dai(const char *name)
@@ -360,6 +363,21 @@ int get_token_uuid(void *elem, void *object, u32 offset)
return 0;
}
+/*
+ * The string gets from topology will be stored in heap, the owner only
+ * holds a char* member point to the heap.
+ */
+int get_token_string(void *elem, void *object, u32 offset)
+{
+ /* "dst" here points to the char* member of the owner */
+ char **dst = (char **)((u8 *)object + offset);
+
+ *dst = kstrdup(elem, GFP_KERNEL);
+ if (!*dst)
+ return -ENOMEM;
+ return 0;
+};
+
int get_token_comp_format(void *elem, void *object, u32 offset)
{
u32 *val = (u32 *)((u8 *)object + offset);
@@ -392,6 +410,23 @@ static const struct sof_topology_token led_tokens[] = {
offsetof(struct snd_sof_led_control, direction)},
};
+static const struct sof_topology_token comp_pin_tokens[] = {
+ {SOF_TKN_COMP_NUM_SINK_PINS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct snd_sof_widget, num_sink_pins)},
+ {SOF_TKN_COMP_NUM_SOURCE_PINS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct snd_sof_widget, num_source_pins)},
+};
+
+static const struct sof_topology_token comp_sink_pin_binding_tokens[] = {
+ {SOF_TKN_COMP_SINK_PIN_BINDING_WNAME, SND_SOC_TPLG_TUPLE_TYPE_STRING,
+ get_token_string, 0},
+};
+
+static const struct sof_topology_token comp_src_pin_binding_tokens[] = {
+ {SOF_TKN_COMP_SRC_PIN_BINDING_WNAME, SND_SOC_TPLG_TUPLE_TYPE_STRING,
+ get_token_string, 0},
+};
+
/**
* sof_parse_uuid_tokens - Parse multiple sets of UUID tokens
* @scomp: pointer to soc component
@@ -572,7 +607,7 @@ static int sof_parse_string_tokens(struct snd_soc_component *scomp,
{
struct snd_soc_tplg_vendor_string_elem *elem;
int found = 0;
- int i, j;
+ int i, j, ret;
/* parse element by element */
for (i = 0; i < le32_to_cpu(array->num_elems); i++) {
@@ -589,7 +624,9 @@ static int sof_parse_string_tokens(struct snd_soc_component *scomp,
continue;
/* matched - now load token */
- tokens[j].get_token(elem->string, object, offset + tokens[j].offset);
+ ret = tokens[j].get_token(elem->string, object, offset + tokens[j].offset);
+ if (ret < 0)
+ return ret;
found++;
}
@@ -669,6 +706,7 @@ static int sof_parse_token_sets(struct snd_soc_component *scomp,
int found = 0;
int total = 0;
int asize;
+ int ret;
while (array_size > 0 && total < count * token_instance_num) {
asize = le32_to_cpu(array->size);
@@ -695,8 +733,15 @@ static int sof_parse_token_sets(struct snd_soc_component *scomp,
array);
break;
case SND_SOC_TPLG_TUPLE_TYPE_STRING:
- found += sof_parse_string_tokens(scomp, object, offset, tokens, count,
- array);
+
+ ret = sof_parse_string_tokens(scomp, object, offset, tokens, count,
+ array);
+ if (ret < 0) {
+ dev_err(scomp->dev, "error: no memory to copy string token\n");
+ return ret;
+ }
+
+ found += ret;
break;
case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
@@ -1251,6 +1296,79 @@ err:
return ret;
}
+static void sof_free_pin_binding(struct snd_sof_widget *swidget,
+ bool pin_type)
+{
+ char **pin_binding;
+ u32 num_pins;
+ int i;
+
+ if (pin_type == SOF_PIN_TYPE_SINK) {
+ pin_binding = swidget->sink_pin_binding;
+ num_pins = swidget->num_sink_pins;
+ } else {
+ pin_binding = swidget->src_pin_binding;
+ num_pins = swidget->num_source_pins;
+ }
+
+ if (pin_binding) {
+ for (i = 0; i < num_pins; i++)
+ kfree(pin_binding[i]);
+ }
+
+ kfree(pin_binding);
+}
+
+static int sof_parse_pin_binding(struct snd_sof_widget *swidget,
+ struct snd_soc_tplg_private *priv, bool pin_type)
+{
+ const struct sof_topology_token *pin_binding_token;
+ char *pin_binding[SOF_WIDGET_MAX_NUM_PINS];
+ int token_count;
+ u32 num_pins;
+ char **pb;
+ int ret;
+ int i;
+
+ if (pin_type == SOF_PIN_TYPE_SINK) {
+ num_pins = swidget->num_sink_pins;
+ pin_binding_token = comp_sink_pin_binding_tokens;
+ token_count = ARRAY_SIZE(comp_sink_pin_binding_tokens);
+ } else {
+ num_pins = swidget->num_source_pins;
+ pin_binding_token = comp_src_pin_binding_tokens;
+ token_count = ARRAY_SIZE(comp_src_pin_binding_tokens);
+ }
+
+ memset(pin_binding, 0, SOF_WIDGET_MAX_NUM_PINS * sizeof(char *));
+ ret = sof_parse_token_sets(swidget->scomp, pin_binding, pin_binding_token,
+ token_count, priv->array, le32_to_cpu(priv->size),
+ num_pins, sizeof(char *));
+ if (ret < 0)
+ goto err;
+
+ /* copy pin binding array to swidget only if it is defined in topology */
+ if (pin_binding[0]) {
+ pb = kmemdup(pin_binding, num_pins * sizeof(char *), GFP_KERNEL);
+ if (!pb) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ if (pin_type == SOF_PIN_TYPE_SINK)
+ swidget->sink_pin_binding = pb;
+ else
+ swidget->src_pin_binding = pb;
+ }
+
+ return 0;
+
+err:
+ for (i = 0; i < num_pins; i++)
+ kfree(pin_binding[i]);
+
+ return ret;
+}
+
/* external widget init - used for any driver specific init */
static int sof_widget_ready(struct snd_soc_component *scomp, int index,
struct snd_soc_dapm_widget *w,
@@ -1259,6 +1377,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget;
+ struct snd_soc_tplg_private *priv = &tw->priv;
struct snd_sof_widget *swidget;
struct snd_sof_dai *dai;
enum sof_tokens *token_list;
@@ -1276,11 +1395,50 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
swidget->id = w->id;
swidget->pipeline_id = index;
swidget->private = NULL;
+ ida_init(&swidget->src_queue_ida);
+ ida_init(&swidget->sink_queue_ida);
- dev_dbg(scomp->dev, "tplg: ready widget id %d pipe %d type %d name : %s stream %s\n",
- swidget->comp_id, index, swidget->id, tw->name,
- strnlen(tw->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0
- ? tw->sname : "none");
+ ret = sof_parse_tokens(scomp, swidget, comp_pin_tokens,
+ ARRAY_SIZE(comp_pin_tokens), priv->array,
+ le32_to_cpu(priv->size));
+ if (ret < 0) {
+ dev_err(scomp->dev, "failed to parse component pin tokens for %s\n",
+ w->name);
+ return ret;
+ }
+
+ if (swidget->num_sink_pins > SOF_WIDGET_MAX_NUM_PINS ||
+ swidget->num_source_pins > SOF_WIDGET_MAX_NUM_PINS) {
+ dev_err(scomp->dev, "invalid pins for %s: [sink: %d, src: %d]\n",
+ swidget->widget->name, swidget->num_sink_pins, swidget->num_source_pins);
+ return -EINVAL;
+ }
+
+ if (swidget->num_sink_pins > 1) {
+ ret = sof_parse_pin_binding(swidget, priv, SOF_PIN_TYPE_SINK);
+ /* on parsing error, pin binding is not allocated, nothing to free. */
+ if (ret < 0) {
+ dev_err(scomp->dev, "failed to parse sink pin binding for %s\n",
+ w->name);
+ return ret;
+ }
+ }
+
+ if (swidget->num_source_pins > 1) {
+ ret = sof_parse_pin_binding(swidget, priv, SOF_PIN_TYPE_SOURCE);
+ /* on parsing error, pin binding is not allocated, nothing to free. */
+ if (ret < 0) {
+ dev_err(scomp->dev, "failed to parse source pin binding for %s\n",
+ w->name);
+ return ret;
+ }
+ }
+
+ dev_dbg(scomp->dev,
+ "tplg: widget %d (%s) is ready [type: %d, pipe: %d, pins: %d / %d, stream: %s]\n",
+ swidget->comp_id, w->name, swidget->id, index,
+ swidget->num_sink_pins, swidget->num_source_pins,
+ strnlen(w->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0 ? w->sname : "none");
token_list = widget_ops[w->id].token_list;
token_list_size = widget_ops[w->id].token_list_size;
@@ -1471,6 +1629,12 @@ out:
if (widget_ops[swidget->id].ipc_free)
widget_ops[swidget->id].ipc_free(swidget);
+ ida_destroy(&swidget->src_queue_ida);
+ ida_destroy(&swidget->sink_queue_ida);
+
+ sof_free_pin_binding(swidget, SOF_PIN_TYPE_SINK);
+ sof_free_pin_binding(swidget, SOF_PIN_TYPE_SOURCE);
+
kfree(swidget->tuples);
/* remove and free swidget object */
@@ -1734,6 +1898,13 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_
token_id = SOF_ACPDMIC_TOKENS;
num_tuples += token_list[SOF_ACPDMIC_TOKENS].count;
break;
+ case SOF_DAI_AMD_SP:
+ case SOF_DAI_AMD_HS:
+ case SOF_DAI_AMD_SP_VIRTUAL:
+ case SOF_DAI_AMD_HS_VIRTUAL:
+ token_id = SOF_ACPI2S_TOKENS;
+ num_tuples += token_list[SOF_ACPI2S_TOKENS].count;
+ break;
default:
break;
}