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) {
......
......@@ -41,45 +41,48 @@ static const struct sof_topology_token ipc4_comp_tokens[] = {
offsetof(struct sof_ipc4_base_module_cfg, is_pages)},
};
static const struct sof_topology_token ipc4_audio_format_buffer_size_tokens[] = {
{SOF_TKN_CAVS_AUDIO_FORMAT_IBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_base_module_cfg, ibs)},
{SOF_TKN_CAVS_AUDIO_FORMAT_OBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_base_module_cfg, obs)},
};
static const struct sof_topology_token ipc4_in_audio_format_tokens[] = {
{SOF_TKN_CAVS_AUDIO_FORMAT_IN_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_audio_format, sampling_frequency)},
offsetof(struct sof_ipc4_pin_format, audio_fmt.sampling_frequency)},
{SOF_TKN_CAVS_AUDIO_FORMAT_IN_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_audio_format, bit_depth)},
offsetof(struct sof_ipc4_pin_format, audio_fmt.bit_depth)},
{SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_audio_format, ch_map)},
offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_map)},
{SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_audio_format, ch_cfg)},
offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_cfg)},
{SOF_TKN_CAVS_AUDIO_FORMAT_IN_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
get_token_u32, offsetof(struct sof_ipc4_audio_format, interleaving_style)},
get_token_u32, offsetof(struct sof_ipc4_pin_format,
audio_fmt.interleaving_style)},
{SOF_TKN_CAVS_AUDIO_FORMAT_IN_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_audio_format, fmt_cfg)},
offsetof(struct sof_ipc4_pin_format, audio_fmt.fmt_cfg)},
{SOF_TKN_CAVS_AUDIO_FORMAT_PIN_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_pin_format, pin_index)},
{SOF_TKN_CAVS_AUDIO_FORMAT_IBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_pin_format, buffer_size)},
};
static const struct sof_topology_token ipc4_out_audio_format_tokens[] = {
{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_audio_format, sampling_frequency)},
offsetof(struct sof_ipc4_pin_format, audio_fmt.sampling_frequency)},
{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_audio_format, bit_depth)},
offsetof(struct sof_ipc4_pin_format, audio_fmt.bit_depth)},
{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_audio_format, ch_map)},
offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_map)},
{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_audio_format, ch_cfg)},
offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_cfg)},
{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
get_token_u32, offsetof(struct sof_ipc4_audio_format, interleaving_style)},
get_token_u32, offsetof(struct sof_ipc4_pin_format,
audio_fmt.interleaving_style)},
{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_audio_format, fmt_cfg)},
offsetof(struct sof_ipc4_pin_format, audio_fmt.fmt_cfg)},
{SOF_TKN_CAVS_AUDIO_FORMAT_PIN_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_pin_format, pin_index)},
{SOF_TKN_CAVS_AUDIO_FORMAT_OBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_pin_format, buffer_size)},
};
static const struct sof_topology_token ipc4_copier_gateway_cfg_tokens[] = {
{SOF_TKN_CAVS_AUDIO_FORMAT_DMA_BUFFER_SIZE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0},
static const struct sof_topology_token ipc4_copier_deep_buffer_tokens[] = {
{SOF_TKN_INTEL_COPIER_DEEP_BUFFER_DMA_MS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0},
};
static const struct sof_topology_token ipc4_copier_tokens[] = {
......@@ -87,8 +90,10 @@ static const struct sof_topology_token ipc4_copier_tokens[] = {
};
static const struct sof_topology_token ipc4_audio_fmt_num_tokens[] = {
{SOF_TKN_COMP_NUM_AUDIO_FORMATS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
0},
{SOF_TKN_COMP_NUM_INPUT_AUDIO_FORMATS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_available_audio_format, num_input_formats)},
{SOF_TKN_COMP_NUM_OUTPUT_AUDIO_FORMATS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_available_audio_format, num_output_formats)},
};
static const struct sof_topology_token dai_tokens[] = {
......@@ -135,11 +140,8 @@ static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = {
ipc4_in_audio_format_tokens, ARRAY_SIZE(ipc4_in_audio_format_tokens)},
[SOF_OUT_AUDIO_FORMAT_TOKENS] = {"IPC4 Output Audio format tokens",
ipc4_out_audio_format_tokens, ARRAY_SIZE(ipc4_out_audio_format_tokens)},
[SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS] = {"IPC4 Audio format buffer size tokens",
ipc4_audio_format_buffer_size_tokens,
ARRAY_SIZE(ipc4_audio_format_buffer_size_tokens)},
[SOF_COPIER_GATEWAY_CFG_TOKENS] = {"IPC4 Copier gateway config tokens",
ipc4_copier_gateway_cfg_tokens, ARRAY_SIZE(ipc4_copier_gateway_cfg_tokens)},
[SOF_COPIER_DEEP_BUFFER_TOKENS] = {"IPC4 Copier deep buffer tokens",
ipc4_copier_deep_buffer_tokens, ARRAY_SIZE(ipc4_copier_deep_buffer_tokens)},
[SOF_COPIER_TOKENS] = {"IPC4 Copier tokens", ipc4_copier_tokens,
ARRAY_SIZE(ipc4_copier_tokens)},
[SOF_AUDIO_FMT_NUM_TOKENS] = {"IPC4 Audio format number tokens",
......@@ -148,20 +150,18 @@ static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = {
[SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)},
};
static void sof_ipc4_dbg_audio_format(struct device *dev,
struct sof_ipc4_audio_format *format,
size_t object_size, int num_format)
static void sof_ipc4_dbg_audio_format(struct device *dev, struct sof_ipc4_pin_format *pin_fmt,
int num_formats)
{
struct sof_ipc4_audio_format *fmt;
void *ptr = format;
int i;
for (i = 0; i < num_format; i++, ptr = (u8 *)ptr + object_size) {
fmt = ptr;
for (i = 0; i < num_formats; i++) {
struct sof_ipc4_audio_format *fmt = &pin_fmt[i].audio_fmt;
dev_dbg(dev,
" #%d: %uHz, %ubit (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x)\n",
i, fmt->sampling_frequency, fmt->bit_depth, fmt->ch_map,
fmt->ch_cfg, fmt->interleaving_style, fmt->fmt_cfg);
"Pin index #%d: %uHz, %ubit (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x) buffer size %d\n",
pin_fmt[i].pin_index, fmt->sampling_frequency, fmt->bit_depth, fmt->ch_map,
fmt->ch_cfg, fmt->interleaving_style, fmt->fmt_cfg,
pin_fmt[i].buffer_size);
}
}
......@@ -170,108 +170,98 @@ static void sof_ipc4_dbg_audio_format(struct device *dev,
* @scomp: pointer to pointer to SOC component
* @swidget: pointer to struct snd_sof_widget containing tuples
* @available_fmt: pointer to struct sof_ipc4_available_audio_format being filling in
* @has_out_format: true if available_fmt contains output format
* @module_base_cfg: Pointer to the base_config in the module init IPC payload
*
* Return: 0 if successful
*/
static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp,
struct snd_sof_widget *swidget,
struct sof_ipc4_available_audio_format *available_fmt,
bool has_out_format)
struct sof_ipc4_base_module_cfg *module_base_cfg)
{
struct sof_ipc4_base_module_cfg *base_config;
struct sof_ipc4_audio_format *out_format;
int audio_fmt_num = 0;
int ret, i;
struct sof_ipc4_pin_format *out_format, *in_format;
int ret;
ret = sof_update_ipc_object(scomp, &audio_fmt_num,
ret = sof_update_ipc_object(scomp, available_fmt,
SOF_AUDIO_FMT_NUM_TOKENS, swidget->tuples,
swidget->num_tuples, sizeof(audio_fmt_num), 1);
if (ret || audio_fmt_num <= 0) {
dev_err(scomp->dev, "Invalid number of audio formats: %d\n", audio_fmt_num);
return -EINVAL;
}
available_fmt->audio_fmt_num = audio_fmt_num;
dev_dbg(scomp->dev, "Number of audio formats: %d\n", available_fmt->audio_fmt_num);
base_config = kcalloc(available_fmt->audio_fmt_num, sizeof(*base_config), GFP_KERNEL);
if (!base_config)
return -ENOMEM;
/* set cpc and is_pages for all base_cfg */
for (i = 0; i < available_fmt->audio_fmt_num; i++) {
ret = sof_update_ipc_object(scomp, &base_config[i],
SOF_COMP_TOKENS, swidget->tuples,
swidget->num_tuples, sizeof(*base_config), 1);
if (ret) {
dev_err(scomp->dev, "parse comp tokens failed %d\n", ret);
goto err_in;
}
swidget->num_tuples, sizeof(available_fmt), 1);
if (ret) {
dev_err(scomp->dev, "Failed to parse audio format token count\n");
return ret;
}
/* copy the ibs/obs for each base_cfg */
ret = sof_update_ipc_object(scomp, base_config,
SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, swidget->tuples,
swidget->num_tuples, sizeof(*base_config),
available_fmt->audio_fmt_num);
if (ret) {
dev_err(scomp->dev, "parse buffer size tokens failed %d\n", ret);
goto err_in;
if (!available_fmt->num_input_formats && !available_fmt->num_output_formats) {
dev_err(scomp->dev, "No input/output pin formats set in topology\n");
return -EINVAL;
}
for (i = 0; i < available_fmt->audio_fmt_num; i++)
dev_dbg(scomp->dev, "%d: ibs: %d obs: %d cpc: %d is_pages: %d\n", i,
base_config[i].ibs, base_config[i].obs,
base_config[i].cpc, base_config[i].is_pages);
dev_dbg(scomp->dev,
"Number of input audio formats: %d. Number of output audio formats: %d\n",
available_fmt->num_input_formats, available_fmt->num_output_formats);
ret = sof_update_ipc_object(scomp, &base_config->audio_fmt,
SOF_IN_AUDIO_FORMAT_TOKENS, swidget->tuples,
swidget->num_tuples, sizeof(*base_config),
available_fmt->audio_fmt_num);
/* set cpc and is_pages in the module's base_config */
ret = sof_update_ipc_object(scomp, module_base_cfg, SOF_COMP_TOKENS, swidget->tuples,
swidget->num_tuples, sizeof(*module_base_cfg), 1);
if (ret) {
dev_err(scomp->dev, "parse base_config audio_fmt tokens failed %d\n", ret);
goto err_in;
dev_err(scomp->dev, "parse comp tokens for %s failed, error: %d\n",
swidget->widget->name, ret);
return ret;
}
dev_dbg(scomp->dev, "Get input audio formats for %s\n", swidget->widget->name);
sof_ipc4_dbg_audio_format(scomp->dev, &base_config->audio_fmt,
sizeof(*base_config),
available_fmt->audio_fmt_num);
dev_dbg(scomp->dev, "widget %s cpc: %d is_pages: %d\n",
swidget->widget->name, module_base_cfg->cpc, module_base_cfg->is_pages);
available_fmt->base_config = base_config;
if (available_fmt->num_input_formats) {
in_format = kcalloc(available_fmt->num_input_formats,
sizeof(*in_format), GFP_KERNEL);
if (!in_format)
return -ENOMEM;
available_fmt->input_pin_fmts = in_format;
if (!has_out_format)
return 0;
ret = sof_update_ipc_object(scomp, in_format,
SOF_IN_AUDIO_FORMAT_TOKENS, swidget->tuples,
swidget->num_tuples, sizeof(*in_format),
available_fmt->num_input_formats);
if (ret) {
dev_err(scomp->dev, "parse input audio fmt tokens failed %d\n", ret);
goto err_in;
}
out_format = kcalloc(available_fmt->audio_fmt_num, sizeof(*out_format), GFP_KERNEL);
if (!out_format) {
ret = -ENOMEM;
goto err_in;
dev_dbg(scomp->dev, "Input audio formats for %s\n", swidget->widget->name);
sof_ipc4_dbg_audio_format(scomp->dev, in_format,
available_fmt->num_input_formats);
}
ret = sof_update_ipc_object(scomp, out_format,
SOF_OUT_AUDIO_FORMAT_TOKENS, swidget->tuples,
swidget->num_tuples, sizeof(*out_format),
available_fmt->audio_fmt_num);
if (available_fmt->num_output_formats) {
out_format = kcalloc(available_fmt->num_output_formats, sizeof(*out_format),
GFP_KERNEL);
if (!out_format) {
ret = -ENOMEM;
goto err_in;
}
if (ret) {
dev_err(scomp->dev, "parse output audio_fmt tokens failed\n");
goto err_out;
}
ret = sof_update_ipc_object(scomp, out_format,
SOF_OUT_AUDIO_FORMAT_TOKENS, swidget->tuples,
swidget->num_tuples, sizeof(*out_format),
available_fmt->num_output_formats);
if (ret) {
dev_err(scomp->dev, "parse output audio fmt tokens failed\n");
goto err_out;
}
available_fmt->out_audio_fmt = out_format;
dev_dbg(scomp->dev, "Get output audio formats for %s\n", swidget->widget->name);
sof_ipc4_dbg_audio_format(scomp->dev, out_format, sizeof(*out_format),
available_fmt->audio_fmt_num);
available_fmt->output_pin_fmts = out_format;
dev_dbg(scomp->dev, "Output audio formats for %s\n", swidget->widget->name);
sof_ipc4_dbg_audio_format(scomp->dev, out_format,
available_fmt->num_output_formats);
}
return 0;
err_out:
kfree(out_format);
err_in:
kfree(base_config);
kfree(in_format);
available_fmt->input_pin_fmts = NULL;
return ret;
}
......@@ -279,10 +269,10 @@ static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp,
static void sof_ipc4_free_audio_fmt(struct sof_ipc4_available_audio_format *available_fmt)
{
kfree(available_fmt->base_config);
available_fmt->base_config = NULL;
kfree(available_fmt->out_audio_fmt);
available_fmt->out_audio_fmt = NULL;
kfree(available_fmt->output_pin_fmts);
available_fmt->output_pin_fmts = NULL;
kfree(available_fmt->input_pin_fmts);
available_fmt->input_pin_fmts = NULL;
}
static void sof_ipc4_widget_free_comp_pipeline(struct snd_sof_widget *swidget)
......@@ -336,7 +326,7 @@ static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget)
struct snd_soc_component *scomp = swidget->scomp;
struct sof_ipc4_copier *ipc4_copier;
int node_type = 0;
int ret, i;
int ret;
ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL);
if (!ipc4_copier)
......@@ -347,17 +337,11 @@ static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget)
dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt, true);
ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt,
&ipc4_copier->data.base_config);
if (ret)
goto free_copier;
available_fmt->dma_buffer_size = kcalloc(available_fmt->audio_fmt_num, sizeof(u32),
GFP_KERNEL);
if (!available_fmt->dma_buffer_size) {
ret = -ENOMEM;
goto free_available_fmt;
}
/*
* This callback is used by host copier and module-to-module copier,
* and only host copier needs to set gtw_cfg.
......@@ -365,21 +349,6 @@ static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget)
if (!WIDGET_IS_AIF(swidget->id))
goto skip_gtw_cfg;
ret = sof_update_ipc_object(scomp, available_fmt->dma_buffer_size,
SOF_COPIER_GATEWAY_CFG_TOKENS, swidget->tuples,
swidget->num_tuples, sizeof(u32),
available_fmt->audio_fmt_num);
if (ret) {
dev_err(scomp->dev, "Failed to parse dma buffer size in audio format for %s\n",
swidget->widget->name);
goto err;
}
dev_dbg(scomp->dev, "dma buffer size:\n");
for (i = 0; i < available_fmt->audio_fmt_num; i++)
dev_dbg(scomp->dev, "%d: %u\n", i,
available_fmt->dma_buffer_size[i]);
ret = sof_update_ipc_object(scomp, &node_type,
SOF_COPIER_TOKENS, swidget->tuples,
swidget->num_tuples, sizeof(node_type), 1);
......@@ -387,7 +356,7 @@ static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget)
if (ret) {
dev_err(scomp->dev, "parse host copier node type token failed %d\n",
ret);
goto err;
goto free_available_fmt;
}
dev_dbg(scomp->dev, "host copier '%s' node_type %u\n", swidget->widget->name, node_type);
......@@ -395,7 +364,7 @@ static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget)
ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL);
if (!ipc4_copier->gtw_attr) {
ret = -ENOMEM;
goto err;
goto free_available_fmt;
}
ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr;
......@@ -426,8 +395,6 @@ static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget)
free_gtw_attr:
kfree(ipc4_copier->gtw_attr);
err:
kfree(available_fmt->dma_buffer_size);
free_available_fmt:
sof_ipc4_free_audio_fmt(available_fmt);
free_copier:
......@@ -445,9 +412,7 @@ static void sof_ipc4_widget_free_comp_pcm(struct snd_sof_widget *swidget)
return;
available_fmt = &ipc4_copier->available_fmt;
kfree(available_fmt->dma_buffer_size);
kfree(available_fmt->base_config);
kfree(available_fmt->out_audio_fmt);
kfree(available_fmt->output_pin_fmts);
kfree(ipc4_copier->gtw_attr);
kfree(ipc4_copier);
swidget->private = NULL;
......@@ -460,7 +425,7 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
struct snd_sof_dai *dai = swidget->private;
struct sof_ipc4_copier *ipc4_copier;
int node_type = 0;
int ret, i;
int ret;
ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL);
if (!ipc4_copier)
......@@ -470,37 +435,17 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt, true);
ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt,
&ipc4_copier->data.base_config);
if (ret)
goto free_copier;
available_fmt->dma_buffer_size = kcalloc(available_fmt->audio_fmt_num, sizeof(u32),
GFP_KERNEL);
if (!available_fmt->dma_buffer_size) {
ret = -ENOMEM;
goto free_available_fmt;
}
ret = sof_update_ipc_object(scomp, available_fmt->dma_buffer_size,
SOF_COPIER_GATEWAY_CFG_TOKENS, swidget->tuples,
swidget->num_tuples, sizeof(u32),
available_fmt->audio_fmt_num);
if (ret) {
dev_err(scomp->dev, "Failed to parse dma buffer size in audio format for %s\n",
swidget->widget->name);
goto err;
}
for (i = 0; i < available_fmt->audio_fmt_num; i++)
dev_dbg(scomp->dev, "%d: dma buffer size: %u\n", i,
available_fmt->dma_buffer_size[i]);
ret = sof_update_ipc_object(scomp, &node_type,
SOF_COPIER_TOKENS, swidget->tuples,
swidget->num_tuples, sizeof(node_type), 1);
if (ret) {
dev_err(scomp->dev, "parse dai node type failed %d\n", ret);
goto err;
goto free_available_fmt;
}
ret = sof_update_ipc_object(scomp, ipc4_copier,
......@@ -508,7 +453,7 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
swidget->num_tuples, sizeof(u32), 1);
if (ret) {
dev_err(scomp->dev, "parse dai copier node token failed %d\n", ret);
goto err;
goto free_available_fmt;
}
dev_dbg(scomp->dev, "dai %s node_type %u dai_type %u dai_index %d\n", swidget->widget->name,
......@@ -542,7 +487,7 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
blob = kzalloc(sizeof(*blob), GFP_KERNEL);
if (!blob) {
ret = -ENOMEM;
goto err;
goto free_available_fmt;
}
list_for_each_entry(w, &sdev->widget_list, list) {
......@@ -571,7 +516,7 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL);
if (!ipc4_copier->gtw_attr) {
ret = -ENOMEM;
goto err;
goto free_available_fmt;
}
ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr;
......@@ -592,8 +537,6 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
free_copier_config:
kfree(ipc4_copier->copier_config);
err:
kfree(available_fmt->dma_buffer_size);
free_available_fmt:
sof_ipc4_free_audio_fmt(available_fmt);
free_copier:
......@@ -621,9 +564,7 @@ static void sof_ipc4_widget_free_comp_dai(struct snd_sof_widget *swidget)
ipc4_copier = dai->private;
available_fmt = &ipc4_copier->available_fmt;
kfree(available_fmt->dma_buffer_size);
kfree(available_fmt->base_config);
kfree(available_fmt->out_audio_fmt);
kfree(available_fmt->output_pin_fmts);
if (ipc4_copier->dai_type != SOF_DAI_INTEL_SSP &&
ipc4_copier->dai_type != SOF_DAI_INTEL_DMIC)
kfree(ipc4_copier->copier_config);
......@@ -701,8 +642,7 @@ static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget)
gain->data.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
gain->data.init_val = SOF_IPC4_VOL_ZERO_DB;
/* The out_audio_fmt in topology is ignored as it is not required to be sent to the FW */
ret = sof_ipc4_get_audio_fmt(scomp, swidget, &gain->available_fmt, false);
ret = sof_ipc4_get_audio_fmt(scomp, swidget, &gain->available_fmt, &gain->base_config);
if (ret)
goto err;
......@@ -767,8 +707,8 @@ static int sof_ipc4_widget_setup_comp_mixer(struct snd_sof_widget *swidget)
swidget->private = mixer;
/* The out_audio_fmt in topology is ignored as it is not required to be sent to the FW */
ret = sof_ipc4_get_audio_fmt(scomp, swidget, &mixer->available_fmt, false);
ret = sof_ipc4_get_audio_fmt(scomp, swidget, &mixer->available_fmt,
&mixer->base_config);
if (ret)
goto err;
......@@ -798,8 +738,7 @@ static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget)
swidget->private = src;
/* The out_audio_fmt in topology is ignored as it is not required by SRC */
ret = sof_ipc4_get_audio_fmt(scomp, swidget, &src->available_fmt, false);
ret = sof_ipc4_get_audio_fmt(scomp, swidget, &src->available_fmt, &src->base_config);
if (ret)
goto err;
......@@ -902,19 +841,17 @@ static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev,
static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev,
struct snd_sof_widget *swidget,
struct sof_ipc4_base_module_cfg *base_config,
struct sof_ipc4_audio_format *out_format,
struct snd_pcm_hw_params *params,
struct sof_ipc4_available_audio_format *available_fmt,
size_t object_offset)
struct sof_ipc4_pin_format *pin_fmts, u32 pin_fmts_size)
{
void *ptr = available_fmt->ref_audio_fmt;
u32 valid_bits;
u32 channels;
u32 rate;
int sample_valid_bits;
int i;
if (!ptr) {
if (!pin_fmts) {
dev_err(sdev->dev, "no reference formats for %s\n", swidget->widget->name);
return -EINVAL;
}
......@@ -934,53 +871,53 @@ static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev,
return -EINVAL;
}
if (!available_fmt->audio_fmt_num) {
if (!pin_fmts_size) {
dev_err(sdev->dev, "no formats available for %s\n", swidget->widget->name);
return -EINVAL;
}
/*
* Search supported audio formats to match rate, channels ,and
* Search supported audio formats with pin index 0 to match rate, channels ,and
* sample_valid_bytes from runtime params
*/
for (i = 0; i < available_fmt->audio_fmt_num; i++, ptr = (u8 *)ptr + object_offset) {
struct sof_ipc4_audio_format *fmt = ptr;
for (i = 0; i < pin_fmts_size; i++) {
struct sof_ipc4_audio_format *fmt = &pin_fmts[i].audio_fmt;
if (pin_fmts[i].pin_index)
continue;
rate = fmt->sampling_frequency;
channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
if (params_rate(params) == rate && params_channels(params) == channels &&
sample_valid_bits == valid_bits) {
dev_dbg(sdev->dev, "matching audio format index for %uHz, %ubit, %u channels: %d\n",
dev_dbg(sdev->dev, "matched audio format index for %uHz, %ubit, %u channels: %d\n",
rate, valid_bits, channels, i);
/* copy ibs/obs and input format */
memcpy(base_config, &available_fmt->base_config[i],
sizeof(struct sof_ipc4_base_module_cfg));
/* copy output format */
if (out_format)
memcpy(out_format, &available_fmt->out_audio_fmt[i],
sizeof(struct sof_ipc4_audio_format));
break;
}
}
if (i == available_fmt->audio_fmt_num) {
if (i == pin_fmts_size) {
dev_err(sdev->dev, "%s: Unsupported audio format: %uHz, %ubit, %u channels\n",
__func__, params_rate(params), sample_valid_bits, params_channels(params));
return -EINVAL;
}
dev_dbg(sdev->dev, "Init input audio formats for %s\n", swidget->widget->name);
sof_ipc4_dbg_audio_format(sdev->dev, &base_config->audio_fmt,
sizeof(*base_config), 1);
if (out_format) {
dev_dbg(sdev->dev, "Init output audio formats for %s\n", swidget->widget->name);
sof_ipc4_dbg_audio_format(sdev->dev, out_format,
sizeof(*out_format), 1);
/* copy input format */
if (available_fmt->num_input_formats && i < available_fmt->num_input_formats) {
memcpy(&base_config->audio_fmt, &available_fmt->input_pin_fmts[i].audio_fmt,
sizeof(struct sof_ipc4_audio_format));
/* set base_cfg ibs/obs */
base_config->ibs = available_fmt->input_pin_fmts[i].buffer_size;
dev_dbg(sdev->dev, "Init input audio formats for %s\n", swidget->widget->name);
sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->input_pin_fmts[i], 1);
}
if (available_fmt->num_output_formats && i < available_fmt->num_output_formats)
base_config->obs = available_fmt->output_pin_fmts[i].buffer_size;
/* Return the index of the matched format */
return i;
}
......@@ -1141,17 +1078,19 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
struct sof_ipc4_available_audio_format *available_fmt;
struct snd_soc_component *scomp = swidget->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct sof_ipc4_pin_format *format_list_to_search;
struct sof_ipc4_copier_data *copier_data;
struct snd_pcm_hw_params *ref_params;
struct sof_ipc4_copier *ipc4_copier;
struct snd_sof_dai *dai;
struct snd_mask *fmt;
int out_sample_valid_bits;
size_t ref_audio_fmt_size;
void **ipc_config_data;
int *ipc_config_size;
u32 **data;
int ipc_size, ret;
u32 deep_buffer_dma_ms = 0;
u32 format_list_count;
dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id);
......@@ -1163,6 +1102,16 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
struct snd_sof_widget *pipe_widget;
struct sof_ipc4_pipeline *pipeline;
/* parse the deep buffer dma size */
ret = sof_update_ipc_object(scomp, &deep_buffer_dma_ms,
SOF_COPIER_DEEP_BUFFER_TOKENS, swidget->tuples,
swidget->num_tuples, sizeof(u32), 1);
if (ret) {
dev_err(scomp->dev, "Failed to parse deep buffer dma size for %s\n",
swidget->widget->name);
return ret;
}
pipe_widget = swidget->spipe->pipe_widget;
pipeline = pipe_widget->private;
ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
......@@ -1171,17 +1120,17 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
available_fmt = &ipc4_copier->available_fmt;
/*
* base_config->audio_fmt and out_audio_fmt represent the input and output audio
* formats. Use the input format as the reference to match pcm params for playback
* and the output format as reference for capture.
* Use the input_pin_fmts to match pcm params for playback and the output_pin_fmts
* for capture.
*/
if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt;
ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg);
format_list_to_search = available_fmt->input_pin_fmts;
format_list_count = available_fmt->num_input_formats;
} else {
available_fmt->ref_audio_fmt = available_fmt->out_audio_fmt;
ref_audio_fmt_size = sizeof(struct sof_ipc4_audio_format);
format_list_to_search = available_fmt->output_pin_fmts;
format_list_count = available_fmt->num_output_formats;
}
copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
copier_data->gtw_cfg.node_id |=
SOF_IPC4_NODE_INDEX(platform_params->stream_tag - 1);
......@@ -1200,8 +1149,8 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
copier_data = &ipc4_copier->data;
available_fmt = &ipc4_copier->available_fmt;
if (dir == SNDRV_PCM_STREAM_CAPTURE) {
available_fmt->ref_audio_fmt = available_fmt->out_audio_fmt;
ref_audio_fmt_size = sizeof(struct sof_ipc4_audio_format);
format_list_to_search = available_fmt->output_pin_fmts;
format_list_count = available_fmt->num_output_formats;
/*
* modify the input params for the dai copier as it only supports
......@@ -1211,8 +1160,8 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
snd_mask_none(fmt);
snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
} else {
available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt;
ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg);
format_list_to_search = available_fmt->input_pin_fmts;
format_list_count = available_fmt->num_input_formats;
}
ref_params = pipeline_params;
......@@ -1232,12 +1181,9 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
copier_data = &ipc4_copier->data;
available_fmt = &ipc4_copier->available_fmt;
/*
* base_config->audio_fmt represent the input audio formats. Use
* the input format as the reference to match pcm params
*/
available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt;
ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg);
/* Use the input formats to match pcm params */
format_list_to_search = available_fmt->input_pin_fmts;
format_list_count = available_fmt->num_input_formats;
ref_params = pipeline_params;
break;
......@@ -1249,12 +1195,23 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
}
/* set input and output audio formats */
ret = sof_ipc4_init_audio_fmt(sdev, swidget, &copier_data->base_config,
&copier_data->out_format, ref_params,
available_fmt, ref_audio_fmt_size);
ret = sof_ipc4_init_audio_fmt(sdev, swidget, &copier_data->base_config, ref_params,
available_fmt, format_list_to_search, format_list_count);
if (ret < 0)
return ret;
/*
* Set the output format. Current topology defines pin 0 input and output formats in pairs.
* This assumes that the pin 0 formats are defined before all other pins.
* So pick the output audio format with the same index as the chosen
* input format. This logic will need to be updated when the format definitions
* in topology change.
*/
memcpy(&copier_data->out_format, &available_fmt->output_pin_fmts[ret].audio_fmt,
sizeof(struct sof_ipc4_audio_format));
dev_dbg(sdev->dev, "Output audio format for %s\n", swidget->widget->name);
sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->output_pin_fmts[ret], 1);
switch (swidget->id) {
case snd_soc_dapm_dai_in:
case snd_soc_dapm_dai_out:
......@@ -1362,8 +1319,29 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
return -EINVAL;
}
/* set the gateway dma_buffer_size using the matched ID returned above */
copier_data->gtw_cfg.dma_buffer_size = available_fmt->dma_buffer_size[ret];
/*
* Set the gateway dma_buffer_size to 2ms buffer size to meet the FW expectation. In the
* deep buffer case, set the dma_buffer_size depending on the deep_buffer_dma_ms set
* in topology.
*/
switch (swidget->id) {
case snd_soc_dapm_dai_in:
copier_data->gtw_cfg.dma_buffer_size =
SOF_IPC4_MIN_DMA_BUFFER_SIZE * copier_data->base_config.ibs;
break;
case snd_soc_dapm_aif_in:
copier_data->gtw_cfg.dma_buffer_size =
max((u32)SOF_IPC4_MIN_DMA_BUFFER_SIZE, deep_buffer_dma_ms) *
copier_data->base_config.ibs;
break;
case snd_soc_dapm_dai_out:
case snd_soc_dapm_aif_out:
copier_data->gtw_cfg.dma_buffer_size =
SOF_IPC4_MIN_DMA_BUFFER_SIZE * copier_data->base_config.obs;
break;
default:
break;
}
data = &ipc4_copier->copier_config;
ipc_config_size = &ipc4_copier->ipc_config_size;
......@@ -1400,14 +1378,13 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget,
struct snd_soc_component *scomp = swidget->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct sof_ipc4_gain *gain = swidget->private;
struct sof_ipc4_available_audio_format *available_fmt = &gain->available_fmt;
int ret;
gain->available_fmt.ref_audio_fmt = &gain->available_fmt.base_config->audio_fmt;
/* output format is not required to be sent to the FW for gain */
ret = sof_ipc4_init_audio_fmt(sdev, swidget, &gain->base_config,
NULL, pipeline_params, &gain->available_fmt,
sizeof(gain->base_config));
pipeline_params, available_fmt,
available_fmt->input_pin_fmts,
available_fmt->num_input_formats);
if (ret < 0)
return ret;
......@@ -1425,15 +1402,13 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget,
struct snd_soc_component *scomp = swidget->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct sof_ipc4_mixer *mixer = swidget->private;
struct sof_ipc4_available_audio_format *available_fmt = &mixer->available_fmt;
int ret;
/* only 32bit is supported by mixer */
mixer->available_fmt.ref_audio_fmt = &mixer->available_fmt.base_config->audio_fmt;
/* output format is not required to be sent to the FW for mixer */
ret = sof_ipc4_init_audio_fmt(sdev, swidget, &mixer->base_config,
NULL, pipeline_params, &mixer->available_fmt,
sizeof(mixer->base_config));
pipeline_params, available_fmt,
available_fmt->input_pin_fmts,
available_fmt->num_input_formats);
if (ret < 0)
return ret;
......@@ -1451,15 +1426,14 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget,
struct snd_soc_component *scomp = swidget->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct sof_ipc4_src *src = swidget->private;
struct sof_ipc4_available_audio_format *available_fmt = &src->available_fmt;
struct snd_interval *rate;
int ret;
src->available_fmt.ref_audio_fmt = &src->available_fmt.base_config->audio_fmt;
/* output format is not required to be sent to the FW for SRC */
ret = sof_ipc4_init_audio_fmt(sdev, swidget, &src->base_config,
NULL, pipeline_params, &src->available_fmt,
sizeof(src->base_config));
pipeline_params, available_fmt,
available_fmt->input_pin_fmts,
available_fmt->num_input_formats);
if (ret < 0)
return ret;
......@@ -1765,17 +1739,17 @@ static int sof_ipc4_get_queue_id(struct snd_sof_widget *src_widget,
u32 num_pins;
int i;
if (pin_type == SOF_PIN_TYPE_SOURCE) {
if (pin_type == SOF_PIN_TYPE_OUTPUT) {
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;
pin_binding = src_widget->output_pin_binding;
queue_ida = &src_widget->output_queue_ida;
num_pins = src_widget->num_output_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;
pin_binding = sink_widget->input_pin_binding;
queue_ida = &sink_widget->input_queue_ida;
num_pins = sink_widget->num_input_pins;
buddy_name = src_widget->widget->name;
}
......@@ -1783,12 +1757,12 @@ static int sof_ipc4_get_queue_id(struct snd_sof_widget *src_widget,
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"),
(pin_type == SOF_PIN_TYPE_OUTPUT ? "output" : "input"),
num_pins, current_swidget->widget->name);
return -EINVAL;
}
/* If there is only one sink/source pin, queue id must be 0 */
/* If there is only one input/output pin, queue id must be 0 */
if (num_pins == 1)
return 0;
......@@ -1803,7 +1777,7 @@ static int sof_ipc4_get_queue_id(struct snd_sof_widget *src_widget,
* 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"),
(pin_type == SOF_PIN_TYPE_OUTPUT ? "output" : "input"),
current_swidget->widget->name);
return -EINVAL;
}
......@@ -1819,14 +1793,14 @@ static void sof_ipc4_put_queue_id(struct snd_sof_widget *swidget, int queue_id,
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;
if (pin_type == SOF_PIN_TYPE_OUTPUT) {
pin_binding = swidget->output_pin_binding;
queue_ida = &swidget->output_queue_ida;
num_pins = swidget->num_output_pins;
} else {
pin_binding = swidget->sink_pin_binding;
queue_ida = &swidget->sink_queue_ida;
num_pins = swidget->num_sink_pins;
pin_binding = swidget->input_pin_binding;
queue_ida = &swidget->input_queue_ida;
num_pins = swidget->num_input_pins;
}
/* Nothing to free if queue ID is not allocated with ida. */
......@@ -1896,7 +1870,7 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *
int ret;
sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
SOF_PIN_TYPE_SOURCE);
SOF_PIN_TYPE_OUTPUT);
if (sroute->src_queue_id < 0) {
dev_err(sdev->dev, "failed to get queue ID for source widget: %s\n",
src_widget->widget->name);
......@@ -1904,12 +1878,12 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *
}
sroute->dst_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
SOF_PIN_TYPE_SINK);
SOF_PIN_TYPE_INPUT);
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);
SOF_PIN_TYPE_OUTPUT);
return sroute->dst_queue_id;
}
......@@ -1953,8 +1927,8 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *
return ret;
out:
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);
sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_OUTPUT);
sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_INPUT);
return ret;
}
......@@ -1999,8 +1973,8 @@ static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *s
src_widget->widget->name, sroute->src_queue_id,
sink_widget->widget->name, sroute->dst_queue_id);
out:
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);
sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_INPUT);
sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_OUTPUT);
return ret;
}
......@@ -2229,10 +2203,9 @@ static int sof_ipc4_link_setup(struct snd_sof_dev *sdev, struct snd_soc_dai_link
static enum sof_tokens common_copier_token_list[] = {
SOF_COMP_TOKENS,
SOF_AUDIO_FMT_NUM_TOKENS,
SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
SOF_IN_AUDIO_FORMAT_TOKENS,
SOF_OUT_AUDIO_FORMAT_TOKENS,
SOF_COPIER_GATEWAY_CFG_TOKENS,
SOF_COPIER_DEEP_BUFFER_TOKENS,
SOF_COPIER_TOKENS,
SOF_COMP_EXT_TOKENS,
};
......@@ -2245,10 +2218,8 @@ static enum sof_tokens pipeline_token_list[] = {
static enum sof_tokens dai_token_list[] = {
SOF_COMP_TOKENS,
SOF_AUDIO_FMT_NUM_TOKENS,
SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
SOF_IN_AUDIO_FORMAT_TOKENS,
SOF_OUT_AUDIO_FORMAT_TOKENS,
SOF_COPIER_GATEWAY_CFG_TOKENS,
SOF_COPIER_TOKENS,
SOF_DAI_TOKENS,
SOF_COMP_EXT_TOKENS,
......@@ -2258,8 +2229,8 @@ static enum sof_tokens pga_token_list[] = {
SOF_COMP_TOKENS,
SOF_GAIN_TOKENS,
SOF_AUDIO_FMT_NUM_TOKENS,
SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
SOF_IN_AUDIO_FORMAT_TOKENS,
SOF_OUT_AUDIO_FORMAT_TOKENS,
SOF_COMP_EXT_TOKENS,
};
......@@ -2267,7 +2238,7 @@ static enum sof_tokens mixer_token_list[] = {
SOF_COMP_TOKENS,
SOF_AUDIO_FMT_NUM_TOKENS,
SOF_IN_AUDIO_FORMAT_TOKENS,
SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
SOF_OUT_AUDIO_FORMAT_TOKENS,
SOF_COMP_EXT_TOKENS,
};
......@@ -2276,7 +2247,7 @@ static enum sof_tokens src_token_list[] = {
SOF_SRC_TOKENS,
SOF_AUDIO_FMT_NUM_TOKENS,
SOF_IN_AUDIO_FORMAT_TOKENS,
SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
SOF_OUT_AUDIO_FORMAT_TOKENS,
SOF_COMP_EXT_TOKENS,
};
......
......@@ -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