Skip to content

Commit 4244cf3

Browse files
committed
ASoC: SOF: ipc4-topology: Fixes for pipelines with SRC
Merge series from Peter Ujfalusi <peter.ujfalusi@linux.intel.com>: The SRC component in a pipeline provides flexibility on the sampling rate which was not handled previously. This series will improve the kernel side with the needed logic to be able to deal with the SRC type of components in pipelines.
2 parents 0bbe064 + 70b0924 commit 4244cf3

1 file changed

Lines changed: 89 additions & 45 deletions

File tree

sound/soc/sof/ipc4-topology.c

Lines changed: 89 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1349,23 +1349,29 @@ static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_s
13491349
}
13501350
#endif
13511351

1352-
static int ipc4_set_fmt_mask(struct snd_mask *fmt, unsigned int bit_depth)
1352+
static bool sof_ipc4_copier_is_single_format(struct snd_sof_dev *sdev,
1353+
struct sof_ipc4_pin_format *pin_fmts,
1354+
u32 pin_fmts_size)
13531355
{
1354-
switch (bit_depth) {
1355-
case 16:
1356-
snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
1357-
break;
1358-
case 24:
1359-
snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
1360-
break;
1361-
case 32:
1362-
snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
1363-
break;
1364-
default:
1365-
return -EINVAL;
1356+
struct sof_ipc4_audio_format *fmt;
1357+
u32 valid_bits;
1358+
int i;
1359+
1360+
fmt = &pin_fmts[0].audio_fmt;
1361+
valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
1362+
1363+
/* check if all output formats in topology are the same */
1364+
for (i = 1; i < pin_fmts_size; i++) {
1365+
u32 _valid_bits;
1366+
1367+
fmt = &pin_fmts[i].audio_fmt;
1368+
_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
1369+
1370+
if (_valid_bits != valid_bits)
1371+
return false;
13661372
}
13671373

1368-
return 0;
1374+
return true;
13691375
}
13701376

13711377
static int
@@ -1381,8 +1387,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
13811387
struct snd_pcm_hw_params *ref_params;
13821388
struct sof_ipc4_copier *ipc4_copier;
13831389
struct snd_sof_dai *dai;
1384-
struct snd_mask *fmt;
1385-
int out_sample_valid_bits;
13861390
u32 gtw_cfg_config_length;
13871391
u32 dma_config_tlv_size = 0;
13881392
void **ipc_config_data;
@@ -1392,6 +1396,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
13921396
u32 out_ref_rate, out_ref_channels;
13931397
u32 deep_buffer_dma_ms = 0;
13941398
int output_fmt_index;
1399+
bool single_output_format;
13951400

13961401
dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id);
13971402

@@ -1525,6 +1530,9 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
15251530
return ret;
15261531

15271532
/* set the reference params for output format selection */
1533+
single_output_format = sof_ipc4_copier_is_single_format(sdev,
1534+
available_fmt->output_pin_fmts,
1535+
available_fmt->num_output_formats);
15281536
switch (swidget->id) {
15291537
case snd_soc_dapm_aif_in:
15301538
case snd_soc_dapm_dai_out:
@@ -1535,17 +1543,21 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
15351543
in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt;
15361544
out_ref_rate = in_fmt->sampling_frequency;
15371545
out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
1538-
out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
1546+
1547+
if (!single_output_format)
1548+
out_ref_valid_bits =
1549+
SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
15391550
break;
15401551
}
15411552
case snd_soc_dapm_aif_out:
15421553
case snd_soc_dapm_dai_in:
1543-
out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params);
1544-
if (out_ref_valid_bits < 0)
1545-
return out_ref_valid_bits;
1546-
15471554
out_ref_rate = params_rate(fe_params);
15481555
out_ref_channels = params_channels(fe_params);
1556+
if (!single_output_format) {
1557+
out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params);
1558+
if (out_ref_valid_bits < 0)
1559+
return out_ref_valid_bits;
1560+
}
15491561
break;
15501562
default:
15511563
/*
@@ -1555,6 +1567,21 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
15551567
return -EINVAL;
15561568
}
15571569

1570+
/*
1571+
* if the output format is the same across all available output formats, choose
1572+
* that as the reference.
1573+
*/
1574+
if (single_output_format) {
1575+
struct sof_ipc4_audio_format *out_fmt;
1576+
1577+
out_fmt = &available_fmt->output_pin_fmts[0].audio_fmt;
1578+
out_ref_valid_bits =
1579+
SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(out_fmt->fmt_cfg);
1580+
}
1581+
1582+
dev_dbg(sdev->dev, "copier %s: reference output rate %d, channels %d valid_bits %d\n",
1583+
swidget->widget->name, out_ref_rate, out_ref_channels, out_ref_valid_bits);
1584+
15581585
output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, &copier_data->base_config,
15591586
available_fmt, out_ref_rate,
15601587
out_ref_channels, out_ref_valid_bits);
@@ -1664,11 +1691,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
16641691
}
16651692

16661693
/* modify the input params for the next widget */
1667-
fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT);
1668-
out_sample_valid_bits =
1669-
SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(copier_data->out_format.fmt_cfg);
1670-
snd_mask_none(fmt);
1671-
ret = ipc4_set_fmt_mask(fmt, out_sample_valid_bits);
1694+
ret = sof_ipc4_update_hw_params(sdev, pipeline_params, &copier_data->out_format);
16721695
if (ret)
16731696
return ret;
16741697

@@ -1838,37 +1861,58 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget,
18381861
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
18391862
struct sof_ipc4_src *src = swidget->private;
18401863
struct sof_ipc4_available_audio_format *available_fmt = &src->available_fmt;
1841-
struct sof_ipc4_audio_format *in_fmt;
1864+
struct sof_ipc4_audio_format *out_audio_fmt;
1865+
struct sof_ipc4_audio_format *in_audio_fmt;
18421866
u32 out_ref_rate, out_ref_channels, out_ref_valid_bits;
1843-
struct snd_interval *rate;
1844-
int ret;
1867+
int output_format_index, input_format_index;
18451868

1846-
ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &src->base_config,
1847-
pipeline_params, available_fmt);
1848-
if (ret < 0)
1849-
return ret;
1869+
input_format_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, &src->base_config,
1870+
pipeline_params, available_fmt);
1871+
if (input_format_index < 0)
1872+
return input_format_index;
18501873

1851-
in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt;
1852-
out_ref_rate = in_fmt->sampling_frequency;
1853-
out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
1854-
out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
1874+
/*
1875+
* For playback, the SRC sink rate will be configured based on the requested output
1876+
* format, which is restricted to only deal with DAI's with a single format for now.
1877+
*/
1878+
if (dir == SNDRV_PCM_STREAM_PLAYBACK && available_fmt->num_output_formats > 1) {
1879+
dev_err(sdev->dev, "Invalid number of output formats: %d for SRC %s\n",
1880+
available_fmt->num_output_formats, swidget->widget->name);
1881+
return -EINVAL;
1882+
}
18551883

1856-
ret = sof_ipc4_init_output_audio_fmt(sdev, &src->base_config, available_fmt,
1857-
out_ref_rate, out_ref_channels, out_ref_valid_bits);
1858-
if (ret < 0) {
1884+
/*
1885+
* SRC does not perform format conversion, so the output channels and valid bit depth must
1886+
* be the same as that of the input.
1887+
*/
1888+
in_audio_fmt = &available_fmt->input_pin_fmts[input_format_index].audio_fmt;
1889+
out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_audio_fmt->fmt_cfg);
1890+
out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_audio_fmt->fmt_cfg);
1891+
1892+
/*
1893+
* For capture, the SRC module should convert the rate to match the rate requested by the
1894+
* PCM hw_params. Set the reference params based on the fe_params unconditionally as it
1895+
* will be ignored for playback anyway.
1896+
*/
1897+
out_ref_rate = params_rate(fe_params);
1898+
1899+
output_format_index = sof_ipc4_init_output_audio_fmt(sdev, &src->base_config,
1900+
available_fmt, out_ref_rate,
1901+
out_ref_channels, out_ref_valid_bits);
1902+
if (output_format_index < 0) {
18591903
dev_err(sdev->dev, "Failed to initialize output format for %s",
18601904
swidget->widget->name);
1905+
return output_format_index;
18611906
}
18621907

18631908
/* update pipeline memory usage */
18641909
sof_ipc4_update_resource_usage(sdev, swidget, &src->base_config);
18651910

1866-
/* update pipeline_params for sink widgets */
1867-
rate = hw_param_interval(pipeline_params, SNDRV_PCM_HW_PARAM_RATE);
1868-
rate->min = src->sink_rate;
1869-
rate->max = rate->min;
1911+
out_audio_fmt = &available_fmt->output_pin_fmts[output_format_index].audio_fmt;
1912+
src->sink_rate = out_audio_fmt->sampling_frequency;
18701913

1871-
return 0;
1914+
/* update pipeline_params for sink widgets */
1915+
return sof_ipc4_update_hw_params(sdev, pipeline_params, out_audio_fmt);
18721916
}
18731917

18741918
static int

0 commit comments

Comments
 (0)