@@ -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
13711377static 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
18741918static int
0 commit comments