Commit 9c3bd790 authored by Mark Brown's avatar Mark Brown

ASoC: SOF: ipc4: Add support for formats per pins

Merge series from Peter Ujfalusi <peter.ujfalusi@linux.intel.com>:

The modules in IPC4 can have multiple 'pins' on their input and output
and these pins can receive or output audio in different formats.
Currently we assume that all pins are using the same format which is a
limitation that needs to be lifted in order to support more complex
components.

This series will extend and rework the format handling to allow
different formats on pins.
parents bec88efd ad70f2f0
......@@ -88,14 +88,16 @@
#define SOF_TKN_COMP_CPC 406
#define SOF_TKN_COMP_IS_PAGES 409
#define SOF_TKN_COMP_NUM_AUDIO_FORMATS 410
#define SOF_TKN_COMP_NUM_SINK_PINS 411
#define SOF_TKN_COMP_NUM_SOURCE_PINS 412
#define SOF_TKN_COMP_NUM_INPUT_PINS 411
#define SOF_TKN_COMP_NUM_OUTPUT_PINS 412
/*
* The token for sink/source pin binding, it specifies the widget
* name that the sink/source pin is connected from/to.
* The token for input/output pin binding, it specifies the widget
* name that the input/output pin is connected from/to.
*/
#define SOF_TKN_COMP_SINK_PIN_BINDING_WNAME 413
#define SOF_TKN_COMP_SRC_PIN_BINDING_WNAME 414
#define SOF_TKN_COMP_INPUT_PIN_BINDING_WNAME 413
#define SOF_TKN_COMP_OUTPUT_PIN_BINDING_WNAME 414
#define SOF_TKN_COMP_NUM_INPUT_AUDIO_FORMATS 415
#define SOF_TKN_COMP_NUM_OUTPUT_AUDIO_FORMATS 416
/* SSP */
......@@ -173,17 +175,18 @@
/* CAVS AUDIO FORMAT */
#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_RATE 1900
#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_BIT_DEPTH 1901
#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_VALID_BIT 1902
#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_VALID_BIT_DEPTH 1902
#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_CHANNELS 1903
#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_MAP 1904
#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_CFG 1905
#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_INTERLEAVING_STYLE 1906
#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_FMT_CFG 1907
#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_SAMPLE_TYPE 1908
#define SOF_TKN_CAVS_AUDIO_FORMAT_PIN_INDEX 1909
/* intentional token numbering discontinuity, reserved for future use */
#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_RATE 1930
#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_BIT_DEPTH 1931
#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_VALID_BIT 1932
#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_VALID_BIT_DEPTH 1932
#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CHANNELS 1933
#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_MAP 1934
#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_CFG 1935
......@@ -197,6 +200,7 @@
/* COPIER */
#define SOF_TKN_INTEL_COPIER_NODE_TYPE 1980
#define SOF_TKN_INTEL_COPIER_DEEP_BUFFER_DMA_MS 1981
/* ACP I2S */
#define SOF_TKN_AMD_ACPI2S_RATE 1700
......
......@@ -389,7 +389,7 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
snd_mask_none(fmt);
snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
rate->min = ipc4_copier->available_fmt.base_config->audio_fmt.sampling_frequency;
rate->min = ipc4_copier->available_fmt.input_pin_fmts->audio_fmt.sampling_frequency;
rate->max = rate->min;
switch (ipc4_copier->dai_type) {
......
This diff is collapsed.
......@@ -55,6 +55,9 @@
#define SOF_IPC4_INVALID_NODE_ID 0xffffffff
/* FW requires minimum 2ms DMA buffer size */
#define SOF_IPC4_MIN_DMA_BUFFER_SIZE 2
/*
* The base of multi-gateways. Multi-gateways addressing starts from
* ALH_MULTI_GTW_BASE and there are ALH_MULTI_GTW_COUNT multi-sources
......@@ -142,20 +145,33 @@ struct ipc4_pipeline_set_state_data {
DECLARE_FLEX_ARRAY(u32, pipeline_ids);
} __packed;
/**
* struct sof_ipc4_pin_format - Module pin format
* @pin_index: pin index
* @buffer_size: buffer size in bytes
* @audio_fmt: audio format for the pin
*
* This structure can be used for both output or input pins and the pin_index is relative to the
* pin type i.e output/input pin
*/
struct sof_ipc4_pin_format {
u32 pin_index;
u32 buffer_size;
struct sof_ipc4_audio_format audio_fmt;
};
/**
* struct sof_ipc4_available_audio_format - Available audio formats
* @base_config: Available base config
* @out_audio_fmt: Available output audio format
* @ref_audio_fmt: Reference audio format to match runtime audio format
* @dma_buffer_size: Available Gateway DMA buffer size (in bytes)
* @audio_fmt_num: Number of available audio formats
* @output_pin_fmts: Available output pin formats
* @input_pin_fmts: Available input pin formats
* @num_input_formats: Number of input pin formats
* @num_output_formats: Number of output pin formats
*/
struct sof_ipc4_available_audio_format {
struct sof_ipc4_base_module_cfg *base_config;
struct sof_ipc4_audio_format *out_audio_fmt;
struct sof_ipc4_audio_format *ref_audio_fmt;
u32 *dma_buffer_size;
int audio_fmt_num;
struct sof_ipc4_pin_format *output_pin_fmts;
struct sof_ipc4_pin_format *input_pin_fmts;
u32 num_input_formats;
u32 num_output_formats;
};
/**
......
......@@ -30,9 +30,9 @@
*/
#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
/* Widget pin type */
#define SOF_PIN_TYPE_INPUT 0
#define SOF_PIN_TYPE_OUTPUT 1
/* max number of FE PCMs before BEs */
#define SOF_BE_PCM_BASE 16
......@@ -256,8 +256,7 @@ enum sof_tokens {
SOF_COMP_EXT_TOKENS,
SOF_IN_AUDIO_FORMAT_TOKENS,
SOF_OUT_AUDIO_FORMAT_TOKENS,
SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
SOF_COPIER_GATEWAY_CFG_TOKENS,
SOF_COPIER_DEEP_BUFFER_TOKENS,
SOF_COPIER_TOKENS,
SOF_AUDIO_FMT_NUM_TOKENS,
SOF_COPIER_FORMAT_TOKENS,
......@@ -433,31 +432,31 @@ struct snd_sof_widget {
struct snd_sof_tuple *tuples;
/*
* The allowed range for num_sink/source_pins is [0, SOF_WIDGET_MAX_NUM_PINS].
* Widgets may have zero sink or source pins, for example the tone widget has
* zero sink pins.
* The allowed range for num_input/output_pins is [0, SOF_WIDGET_MAX_NUM_PINS].
* Widgets may have zero input or output pins, for example the tone widget has
* zero input pins.
*/
u32 num_sink_pins;
u32 num_source_pins;
u32 num_input_pins;
u32 num_output_pins;
/*
* The sink/source pin binding array, it takes the form of
* The input/output 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
* is only one input/output pin requires special pin binding, pin binding
* should be defined for all input/output 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.
* input_pin_binding and output_pin_binding shall be NULL.
*/
char **sink_pin_binding;
char **src_pin_binding;
char **input_pin_binding;
char **output_pin_binding;
struct ida src_queue_ida;
struct ida sink_queue_ida;
struct ida output_queue_ida;
struct ida input_queue_ida;
void *private; /* core does not touch this */
};
......
......@@ -416,19 +416,19 @@ static const struct sof_topology_token led_tokens[] = {
};
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_TKN_COMP_NUM_INPUT_PINS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct snd_sof_widget, num_input_pins)},
{SOF_TKN_COMP_NUM_OUTPUT_PINS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct snd_sof_widget, num_output_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,
static const struct sof_topology_token comp_input_pin_binding_tokens[] = {
{SOF_TKN_COMP_INPUT_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,
static const struct sof_topology_token comp_output_pin_binding_tokens[] = {
{SOF_TKN_COMP_OUTPUT_PIN_BINDING_WNAME, SND_SOC_TPLG_TUPLE_TYPE_STRING,
get_token_string, 0},
};
......@@ -1231,37 +1231,43 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s
continue;
case SOF_IN_AUDIO_FORMAT_TOKENS:
case SOF_OUT_AUDIO_FORMAT_TOKENS:
case SOF_COPIER_GATEWAY_CFG_TOKENS:
case SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS:
num_sets = sof_get_token_value(SOF_TKN_COMP_NUM_AUDIO_FORMATS,
num_sets = sof_get_token_value(SOF_TKN_COMP_NUM_INPUT_AUDIO_FORMATS,
swidget->tuples, swidget->num_tuples);
if (num_sets < 0) {
dev_err(sdev->dev, "Invalid audio format count for %s\n",
dev_err(sdev->dev, "Invalid input audio format count for %s\n",
swidget->widget->name);
ret = num_sets;
goto err;
}
if (num_sets > 1) {
struct snd_sof_tuple *new_tuples;
num_tuples += token_list[object_token_list[i]].count * num_sets;
new_tuples = krealloc(swidget->tuples,
sizeof(*new_tuples) * num_tuples, GFP_KERNEL);
if (!new_tuples) {
ret = -ENOMEM;
goto err;
}
swidget->tuples = new_tuples;
break;
case SOF_OUT_AUDIO_FORMAT_TOKENS:
num_sets = sof_get_token_value(SOF_TKN_COMP_NUM_OUTPUT_AUDIO_FORMATS,
swidget->tuples, swidget->num_tuples);
if (num_sets < 0) {
dev_err(sdev->dev, "Invalid output audio format count for %s\n",
swidget->widget->name);
ret = num_sets;
goto err;
}
break;
default:
break;
}
if (num_sets > 1) {
struct snd_sof_tuple *new_tuples;
num_tuples += token_list[object_token_list[i]].count * num_sets;
new_tuples = krealloc(swidget->tuples,
sizeof(*new_tuples) * num_tuples, GFP_KERNEL);
if (!new_tuples) {
ret = -ENOMEM;
goto err;
}
swidget->tuples = new_tuples;
}
/* copy one set of tuples per token ID into swidget->tuples */
ret = sof_copy_tuples(sdev, private->array, le32_to_cpu(private->size),
object_token_list[i], num_sets, swidget->tuples,
......@@ -1286,12 +1292,12 @@ static void sof_free_pin_binding(struct snd_sof_widget *swidget,
u32 num_pins;
int i;
if (pin_type == SOF_PIN_TYPE_SINK) {
pin_binding = swidget->sink_pin_binding;
num_pins = swidget->num_sink_pins;
if (pin_type == SOF_PIN_TYPE_INPUT) {
pin_binding = swidget->input_pin_binding;
num_pins = swidget->num_input_pins;
} else {
pin_binding = swidget->src_pin_binding;
num_pins = swidget->num_source_pins;
pin_binding = swidget->output_pin_binding;
num_pins = swidget->num_output_pins;
}
if (pin_binding) {
......@@ -1313,14 +1319,14 @@ static int sof_parse_pin_binding(struct snd_sof_widget *swidget,
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);
if (pin_type == SOF_PIN_TYPE_INPUT) {
num_pins = swidget->num_input_pins;
pin_binding_token = comp_input_pin_binding_tokens;
token_count = ARRAY_SIZE(comp_input_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);
num_pins = swidget->num_output_pins;
pin_binding_token = comp_output_pin_binding_tokens;
token_count = ARRAY_SIZE(comp_output_pin_binding_tokens);
}
memset(pin_binding, 0, SOF_WIDGET_MAX_NUM_PINS * sizeof(char *));
......@@ -1337,10 +1343,10 @@ static int sof_parse_pin_binding(struct snd_sof_widget *swidget,
ret = -ENOMEM;
goto err;
}
if (pin_type == SOF_PIN_TYPE_SINK)
swidget->sink_pin_binding = pb;
if (pin_type == SOF_PIN_TYPE_INPUT)
swidget->input_pin_binding = pb;
else
swidget->src_pin_binding = pb;
swidget->output_pin_binding = pb;
}
return 0;
......@@ -1379,8 +1385,8 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
swidget->private = NULL;
mutex_init(&swidget->setup_mutex);
ida_init(&swidget->src_queue_ida);
ida_init(&swidget->sink_queue_ida);
ida_init(&swidget->output_queue_ida);
ida_init(&swidget->input_queue_ida);
ret = sof_parse_tokens(scomp, swidget, comp_pin_tokens,
ARRAY_SIZE(comp_pin_tokens), priv->array,
......@@ -1391,29 +1397,29 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
goto widget_free;
}
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);
if (swidget->num_input_pins > SOF_WIDGET_MAX_NUM_PINS ||
swidget->num_output_pins > SOF_WIDGET_MAX_NUM_PINS) {
dev_err(scomp->dev, "invalid pins for %s: [input: %d, output: %d]\n",
swidget->widget->name, swidget->num_input_pins, swidget->num_output_pins);
ret = -EINVAL;
goto widget_free;
}
if (swidget->num_sink_pins > 1) {
ret = sof_parse_pin_binding(swidget, priv, SOF_PIN_TYPE_SINK);
if (swidget->num_input_pins > 1) {
ret = sof_parse_pin_binding(swidget, priv, SOF_PIN_TYPE_INPUT);
/* 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",
dev_err(scomp->dev, "failed to parse input pin binding for %s\n",
w->name);
goto widget_free;
}
}
if (swidget->num_source_pins > 1) {
ret = sof_parse_pin_binding(swidget, priv, SOF_PIN_TYPE_SOURCE);
if (swidget->num_output_pins > 1) {
ret = sof_parse_pin_binding(swidget, priv, SOF_PIN_TYPE_OUTPUT);
/* 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",
dev_err(scomp->dev, "failed to parse output pin binding for %s\n",
w->name);
goto widget_free;
}
......@@ -1422,7 +1428,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
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,
swidget->num_input_pins, swidget->num_output_pins,
strnlen(w->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0 ? w->sname : "none");
widget_ops = tplg_ops ? tplg_ops->widget : NULL;
......@@ -1643,11 +1649,11 @@ static int sof_widget_unload(struct snd_soc_component *scomp,
if (widget_ops && 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);
ida_destroy(&swidget->output_queue_ida);
ida_destroy(&swidget->input_queue_ida);
sof_free_pin_binding(swidget, SOF_PIN_TYPE_SINK);
sof_free_pin_binding(swidget, SOF_PIN_TYPE_SOURCE);
sof_free_pin_binding(swidget, SOF_PIN_TYPE_INPUT);
sof_free_pin_binding(swidget, SOF_PIN_TYPE_OUTPUT);
kfree(swidget->tuples);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment