From 6327c7297fc86d2203ab31882152a9d0b049f7b2 Mon Sep 17 00:00:00 2001 From: Chao Song Date: Mon, 7 Nov 2022 10:57:04 +0200 Subject: ASoC: SOF: Add support for parsing the number of sink/source pins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for parsing the number of sink/source pins per widget from topology. They will be used to determine the sink/source queue IDs during widget binding. Signed-off-by: Bard Liao Signed-off-by: Chao Song Suggested-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Péter Ujfalusi Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20221107085706.2550-2-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) (limited to 'sound/soc/sof/topology.c') diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 38855dd60617..e839fcdc938b 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -392,6 +392,13 @@ 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)}, +}; + /** * sof_parse_uuid_tokens - Parse multiple sets of UUID tokens * @scomp: pointer to soc component @@ -1259,6 +1266,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; @@ -1277,10 +1285,27 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, swidget->pipeline_id = index; swidget->private = NULL; - 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; + } + + 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; -- cgit v1.2.3 From 3b3acedbd0f30b822e05e5e51b646a67de0031fc Mon Sep 17 00:00:00 2001 From: Chao Song Date: Mon, 7 Nov 2022 10:57:05 +0200 Subject: ASoC: SOF: Add support to parse pin binding array from topology MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for parsing sink/source pin binding array per widget from topology. The pin binding arrays will be used to determine the source and sink queue IDs during widget binding for widget that requires special pin binding. An example of widget that requires special pin binding is the smart amplifier widget, its feedback sink pin has to be connected to a capture DAI copier for codec feedback, while the other sink pin has to be connected to a host DAI copier. Pin ID is required during widget binding for correct route setup. Conversely, the pin ID for 'generic' pins is not defined in the topology and will be allocated by the kernel dynamically. When only one pin is supported, the pin ID shall always be zero. When more than one pin is supported, the pin ID is determined with the ID allocation mechanism in the kernel. Signed-off-by: Chao Song Signed-off-by: Bard Liao Suggested-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Péter Ujfalusi Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20221107085706.2550-3-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- include/uapi/sound/sof/tokens.h | 7 ++ sound/soc/sof/sof-audio.h | 21 ++++++ sound/soc/sof/topology.c | 139 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 163 insertions(+), 4 deletions(-) (limited to 'sound/soc/sof/topology.c') diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index 4f4881850650..f187dfbd9325 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -90,6 +90,13 @@ #define SOF_TKN_COMP_NUM_AUDIO_FORMATS 410 #define SOF_TKN_COMP_NUM_SINK_PINS 411 #define SOF_TKN_COMP_NUM_SOURCE_PINS 412 +/* + * The token for sink/source pin binding, it specifies the widget + * name that the sink/source pin is connected from/to. + */ +#define SOF_TKN_COMP_SINK_PIN_BINDING_WNAME 413 +#define SOF_TKN_COMP_SRC_PIN_BINDING_WNAME 414 + /* SSP */ #define SOF_TKN_INTEL_SSP_CLKS_CONTROL 500 diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index dfca713f00df..efc80a5febc3 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -30,6 +30,10 @@ */ #define SOF_WIDGET_MAX_NUM_PINS 8 +/* The type of a widget pin is either sink or source */ +#define SOF_PIN_TYPE_SINK 0 +#define SOF_PIN_TYPE_SOURCE 1 + /* max number of FE PCMs before BEs */ #define SOF_BE_PCM_BASE 16 @@ -402,6 +406,22 @@ struct snd_sof_widget { u32 num_sink_pins; u32 num_source_pins; + /* + * The sink/source pin binding array, it takes the form of + * [widget_name_connected_to_pin0, widget_name_connected_to_pin1, ...], + * with the index as the queue ID. + * + * The array is used for special pin binding. Note that even if there + * is only one sink/source pin requires special pin binding, pin binding + * should be defined for all sink/source pins in topology, for pin(s) that + * are not used, give the value "NotConnected". + * + * If pin binding is not defined in topology, nothing to parse in the kernel, + * sink_pin_binding and src_pin_binding shall be NULL. + */ + char **sink_pin_binding; + char **src_pin_binding; + void *private; /* core does not touch this */ }; @@ -546,6 +566,7 @@ int get_token_u16(void *elem, void *object, u32 offset); int get_token_comp_format(void *elem, void *object, u32 offset); int get_token_dai_type(void *elem, void *object, u32 offset); int get_token_uuid(void *elem, void *object, u32 offset); +int get_token_string(void *elem, void *object, u32 offset); int sof_update_ipc_object(struct snd_soc_component *scomp, void *object, enum sof_tokens token_id, struct snd_sof_tuple *tuples, int num_tuples, size_t object_size, int token_instance_num); diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index e839fcdc938b..3b1290d34131 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -360,6 +360,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); @@ -399,6 +414,16 @@ static const struct sof_topology_token comp_pin_tokens[] = { 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 @@ -579,7 +604,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++) { @@ -596,7 +621,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++; } @@ -676,6 +703,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); @@ -702,8 +730,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: @@ -1258,6 +1293,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, @@ -1301,6 +1409,26 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, 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, @@ -1496,6 +1624,9 @@ out: if (widget_ops[swidget->id].ipc_free) widget_ops[swidget->id].ipc_free(swidget); + 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 */ -- cgit v1.2.3 From c84443db0fddd188838faa9d71ebd6d9aa280068 Mon Sep 17 00:00:00 2001 From: Chao Song Date: Mon, 7 Nov 2022 10:57:06 +0200 Subject: ASoC: SOF: topology: Add helper to get/put widget queue id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add get/put queue id helper to manage queue id in route setup and route free. The queue allocation rules are: - If widget only has one sink/source pin, zero will be returned as the queue ID directly. - If widget has more than one sink/source pins, and pin binding array is defined in topology, queue ID will be allocated according to the pin binding array. - If widget has more than one sink/sink pins, and pin binding array is not defined, Linux ID allocation will be used to allocate queue ID dynamically. Signed-off-by: Chao Song Signed-off-by: Bard Liao Suggested-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Péter Ujfalusi Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20221107085706.2550-4-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 133 +++++++++++++++++++++++++++++++++++++----- sound/soc/sof/sof-audio.h | 6 ++ sound/soc/sof/topology.c | 5 ++ 3 files changed, 131 insertions(+), 13 deletions(-) (limited to 'sound/soc/sof/topology.c') diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index ab85dde4303b..92b5f934d20f 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1577,6 +1577,88 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget return ret; } +static int sof_ipc4_get_queue_id(struct snd_sof_widget *src_widget, + struct snd_sof_widget *sink_widget, bool pin_type) +{ + struct snd_sof_widget *current_swidget; + struct snd_soc_component *scomp; + struct ida *queue_ida; + const char *buddy_name; + char **pin_binding; + u32 num_pins; + int i; + + if (pin_type == SOF_PIN_TYPE_SOURCE) { + current_swidget = src_widget; + pin_binding = src_widget->src_pin_binding; + queue_ida = &src_widget->src_queue_ida; + num_pins = src_widget->num_source_pins; + buddy_name = sink_widget->widget->name; + } else { + current_swidget = sink_widget; + pin_binding = sink_widget->sink_pin_binding; + queue_ida = &sink_widget->sink_queue_ida; + num_pins = sink_widget->num_sink_pins; + buddy_name = src_widget->widget->name; + } + + scomp = current_swidget->scomp; + + if (num_pins < 1) { + dev_err(scomp->dev, "invalid %s num_pins: %d for queue allocation for %s\n", + (pin_type == SOF_PIN_TYPE_SOURCE ? "source" : "sink"), + num_pins, current_swidget->widget->name); + return -EINVAL; + } + + /* If there is only one sink/source pin, queue id must be 0 */ + if (num_pins == 1) + return 0; + + /* Allocate queue ID from pin binding array if it is defined in topology. */ + if (pin_binding) { + for (i = 0; i < num_pins; i++) { + if (!strcmp(pin_binding[i], buddy_name)) + return i; + } + /* + * Fail if no queue ID found from pin binding array, so that we don't + * mixed use pin binding array and ida for queue ID allocation. + */ + dev_err(scomp->dev, "no %s queue id found from pin binding array for %s\n", + (pin_type == SOF_PIN_TYPE_SOURCE ? "source" : "sink"), + current_swidget->widget->name); + return -EINVAL; + } + + /* If no pin binding array specified in topology, use ida to allocate one */ + return ida_alloc_max(queue_ida, num_pins, GFP_KERNEL); +} + +static void sof_ipc4_put_queue_id(struct snd_sof_widget *swidget, int queue_id, + bool pin_type) +{ + struct ida *queue_ida; + char **pin_binding; + int num_pins; + + if (pin_type == SOF_PIN_TYPE_SOURCE) { + pin_binding = swidget->src_pin_binding; + queue_ida = &swidget->src_queue_ida; + num_pins = swidget->num_source_pins; + } else { + pin_binding = swidget->sink_pin_binding; + queue_ida = &swidget->sink_queue_ida; + num_pins = swidget->num_sink_pins; + } + + /* Nothing to free if queue ID is not allocated with ida. */ + if (num_pins == 1 || pin_binding) + return; + + ida_free(queue_ida, queue_id); +} + static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute) { struct snd_sof_widget *src_widget = sroute->src_widget; @@ -1585,12 +1667,29 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route * struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info; struct sof_ipc4_msg msg = {{ 0 }}; u32 header, extension; - int src_queue = 0; - int dst_queue = 0; int ret; - dev_dbg(sdev->dev, "bind %s -> %s\n", - src_widget->widget->name, sink_widget->widget->name); + sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget, + SOF_PIN_TYPE_SOURCE); + if (sroute->src_queue_id < 0) { + dev_err(sdev->dev, "failed to get queue ID for source widget: %s\n", + src_widget->widget->name); + return sroute->src_queue_id; + } + + sroute->dst_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget, + SOF_PIN_TYPE_SINK); + if (sroute->dst_queue_id < 0) { + dev_err(sdev->dev, "failed to get queue ID for sink widget: %s\n", + sink_widget->widget->name); + sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, + SOF_PIN_TYPE_SOURCE); + return sroute->dst_queue_id; + } + + dev_dbg(sdev->dev, "bind %s:%d -> %s:%d\n", + src_widget->widget->name, sroute->src_queue_id, + sink_widget->widget->name, sroute->dst_queue_id); header = src_fw_module->man4_module_entry.id; header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id); @@ -1600,17 +1699,23 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route * extension = sink_fw_module->man4_module_entry.id; extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id); - extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(dst_queue); - extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(src_queue); + extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id); + extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id); msg.primary = header; msg.extension = extension; ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0); - if (ret < 0) + if (ret < 0) { dev_err(sdev->dev, "%s: failed to bind modules %s -> %s\n", __func__, src_widget->widget->name, sink_widget->widget->name); + sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, + SOF_PIN_TYPE_SOURCE); + sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, + SOF_PIN_TYPE_SINK); + } + return ret; } @@ -1622,12 +1727,11 @@ static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *s struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info; struct sof_ipc4_msg msg = {{ 0 }}; u32 header, extension; - int src_queue = 0; - int dst_queue = 0; int ret; - dev_dbg(sdev->dev, "unbind modules %s -> %s\n", - src_widget->widget->name, sink_widget->widget->name); + dev_dbg(sdev->dev, "unbind modules %s:%d -> %s:%d\n", + src_widget->widget->name, sroute->src_queue_id, + sink_widget->widget->name, sroute->dst_queue_id); header = src_fw_module->man4_module_entry.id; header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id); @@ -1637,8 +1741,8 @@ static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *s extension = sink_fw_module->man4_module_entry.id; extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id); - extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(dst_queue); - extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(src_queue); + extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id); + extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id); msg.primary = header; msg.extension = extension; @@ -1648,6 +1752,9 @@ static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *s dev_err(sdev->dev, "failed to unbind modules %s -> %s\n", src_widget->widget->name, sink_widget->widget->name); + sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_SINK); + sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_SOURCE); + return ret; } diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index efc80a5febc3..1b5b3ea53a6e 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -422,6 +422,9 @@ struct snd_sof_widget { char **sink_pin_binding; char **src_pin_binding; + struct ida src_queue_ida; + struct ida sink_queue_ida; + void *private; /* core does not touch this */ }; @@ -435,6 +438,9 @@ struct snd_sof_route { struct snd_sof_widget *sink_widget; bool setup; + int src_queue_id; + int dst_queue_id; + void *private; }; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 3b1290d34131..176f64a86c26 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1392,6 +1392,8 @@ 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); ret = sof_parse_tokens(scomp, swidget, comp_pin_tokens, ARRAY_SIZE(comp_pin_tokens), priv->array, @@ -1624,6 +1626,9 @@ 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); -- cgit v1.2.3 From 75af41991955205fa0958feb587ce22b35aaa7b0 Mon Sep 17 00:00:00 2001 From: V sujith kumar Reddy Date: Tue, 29 Nov 2022 15:30:59 +0530 Subject: ASoC: SOF: Add DAI configuration support for AMD platforms. Add support for configuring sp and hs DAI from topology. Signed-off-by: V sujith kumar Reddy Link: https://lore.kernel.org/r/20221129100102.826781-1-vsujithkumar.reddy@amd.corp-partner.google.com Signed-off-by: Mark Brown --- include/sound/sof/dai-amd.h | 1 + include/sound/sof/dai.h | 2 ++ include/uapi/sound/sof/tokens.h | 5 +++++ sound/soc/sof/ipc3-pcm.c | 2 ++ sound/soc/sof/ipc3-topology.c | 36 ++++++++++++++++++++++++++++-------- sound/soc/sof/sof-audio.h | 1 + sound/soc/sof/topology.c | 10 ++++++++++ 7 files changed, 49 insertions(+), 8 deletions(-) (limited to 'sound/soc/sof/topology.c') diff --git a/include/sound/sof/dai-amd.h b/include/sound/sof/dai-amd.h index 92f45c180b7c..9df7ac824efe 100644 --- a/include/sound/sof/dai-amd.h +++ b/include/sound/sof/dai-amd.h @@ -17,6 +17,7 @@ struct sof_ipc_dai_acp_params { uint32_t fsync_rate; /* FSYNC frequency in Hz */ uint32_t tdm_slots; + uint32_t tdm_mode; } __packed; /* ACPDMIC Configuration Request - SOF_IPC_DAI_AMD_CONFIG */ diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index 9fbd3832bcdc..3041f5805b7b 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -86,6 +86,8 @@ enum sof_ipc_dai_type { SOF_DAI_AMD_DMIC, /**< AMD ACP DMIC */ SOF_DAI_MEDIATEK_AFE, /**< Mediatek AFE */ SOF_DAI_AMD_HS, /**< Amd HS */ + SOF_DAI_AMD_SP_VIRTUAL, /**< AMD ACP SP VIRTUAL */ + SOF_DAI_AMD_HS_VIRTUAL, /**< AMD ACP HS VIRTUAL */ }; /* general purpose DAI configuration */ diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index f187dfbd9325..bacaf8a6317e 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -198,4 +198,9 @@ /* COPIER */ #define SOF_TKN_INTEL_COPIER_NODE_TYPE 1980 +/* ACP I2S */ +#define SOF_TKN_AMD_ACPI2S_RATE 1700 +#define SOF_TKN_AMD_ACPI2S_CH 1701 +#define SOF_TKN_AMD_ACPI2S_TDM_MODE 1702 + #endif diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c index dad57bef38f6..f10bfc9bd5cb 100644 --- a/sound/soc/sof/ipc3-pcm.c +++ b/sound/soc/sof/ipc3-pcm.c @@ -336,6 +336,7 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, channels->min, channels->max); break; case SOF_DAI_AMD_SP: + case SOF_DAI_AMD_SP_VIRTUAL: rate->min = private->dai_config->acpsp.fsync_rate; rate->max = private->dai_config->acpsp.fsync_rate; channels->min = private->dai_config->acpsp.tdm_slots; @@ -347,6 +348,7 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, channels->min, channels->max); break; case SOF_DAI_AMD_HS: + case SOF_DAI_AMD_HS_VIRTUAL: rate->min = private->dai_config->acphs.fsync_rate; rate->max = private->dai_config->acphs.fsync_rate; channels->min = private->dai_config->acphs.tdm_slots; diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index 0720e1eae084..b94cc40485ed 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -276,6 +276,16 @@ static const struct sof_topology_token acpdmic_tokens[] = { offsetof(struct sof_ipc_dai_acpdmic_params, pdm_ch)}, }; +/* ACPI2S */ +static const struct sof_topology_token acpi2s_tokens[] = { + {SOF_TKN_AMD_ACPI2S_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_acp_params, fsync_rate)}, + {SOF_TKN_AMD_ACPI2S_CH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_acp_params, tdm_slots)}, + {SOF_TKN_AMD_ACPI2S_TDM_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_acp_params, tdm_mode)}, +}; + /* Core tokens */ static const struct sof_topology_token core_tokens[] = { {SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, @@ -311,6 +321,7 @@ static const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = { [SOF_SAI_TOKENS] = {"SAI tokens", sai_tokens, ARRAY_SIZE(sai_tokens)}, [SOF_AFE_TOKENS] = {"AFE tokens", afe_tokens, ARRAY_SIZE(afe_tokens)}, [SOF_ACPDMIC_TOKENS] = {"ACPDMIC tokens", acpdmic_tokens, ARRAY_SIZE(acpdmic_tokens)}, + [SOF_ACPI2S_TOKENS] = {"ACPI2S tokens", acpi2s_tokens, ARRAY_SIZE(acpi2s_tokens)}, }; /** @@ -1193,6 +1204,7 @@ static int sof_link_acp_sp_load(struct snd_soc_component *scomp, struct snd_sof_ struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs; struct sof_dai_private_data *private = dai->private; u32 size = sizeof(*config); + int ret; /* handle master/slave and inverted clocks */ sof_dai_set_format(hw_config, config); @@ -1201,12 +1213,15 @@ static int sof_link_acp_sp_load(struct snd_soc_component *scomp, struct snd_sof_ memset(&config->acpsp, 0, sizeof(config->acpsp)); config->hdr.size = size; - config->acpsp.fsync_rate = le32_to_cpu(hw_config->fsync_rate); - config->acpsp.tdm_slots = le32_to_cpu(hw_config->tdm_slots); + ret = sof_update_ipc_object(scomp, &config->acpsp, SOF_ACPI2S_TOKENS, slink->tuples, + slink->num_tuples, size, slink->num_hw_configs); + if (ret < 0) + return ret; - dev_info(scomp->dev, "ACP_SP config ACP%d channel %d rate %d\n", + + dev_info(scomp->dev, "ACP_SP config ACP%d channel %d rate %d tdm_mode %d\n", config->dai_index, config->acpsp.tdm_slots, - config->acpsp.fsync_rate); + config->acpsp.fsync_rate, config->acpsp.tdm_mode); dai->number_configs = 1; dai->current_config = 0; @@ -1223,6 +1238,7 @@ static int sof_link_acp_hs_load(struct snd_soc_component *scomp, struct snd_sof_ struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs; struct sof_dai_private_data *private = dai->private; u32 size = sizeof(*config); + int ret; /* Configures the DAI hardware format and inverted clocks */ sof_dai_set_format(hw_config, config); @@ -1231,12 +1247,14 @@ static int sof_link_acp_hs_load(struct snd_soc_component *scomp, struct snd_sof_ memset(&config->acphs, 0, sizeof(config->acphs)); config->hdr.size = size; - config->acphs.fsync_rate = le32_to_cpu(hw_config->fsync_rate); - config->acphs.tdm_slots = le32_to_cpu(hw_config->tdm_slots); + ret = sof_update_ipc_object(scomp, &config->acphs, SOF_ACPI2S_TOKENS, slink->tuples, + slink->num_tuples, size, slink->num_hw_configs); + if (ret < 0) + return ret; - dev_info(scomp->dev, "ACP_HS config ACP%d channel %d rate %d\n", + dev_info(scomp->dev, "ACP_HS config ACP%d channel %d rate %d tdm_mode %d\n", config->dai_index, config->acphs.tdm_slots, - config->acphs.fsync_rate); + config->acphs.fsync_rate, config->acphs.tdm_mode); dai->number_configs = 1; dai->current_config = 0; @@ -1545,9 +1563,11 @@ static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget) ret = sof_link_acp_bt_load(scomp, slink, config, dai); break; case SOF_DAI_AMD_SP: + case SOF_DAI_AMD_SP_VIRTUAL: ret = sof_link_acp_sp_load(scomp, slink, config, dai); break; case SOF_DAI_AMD_HS: + case SOF_DAI_AMD_HS_VIRTUAL: ret = sof_link_acp_hs_load(scomp, slink, config, dai); break; case SOF_DAI_AMD_DMIC: diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 1b5b3ea53a6e..29cf951e3526 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -248,6 +248,7 @@ enum sof_tokens { SOF_COPIER_FORMAT_TOKENS, SOF_GAIN_TOKENS, SOF_ACPDMIC_TOKENS, + SOF_ACPI2S_TOKENS, /* this should be the last */ SOF_TOKEN_COUNT, diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 9d9fcaa2a948..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) @@ -1895,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; } -- cgit v1.2.3