@@ -1119,42 +1119,50 @@ static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev,
11191119
11201120/* update hw_params based on the audio stream format */
11211121static int sof_ipc4_update_hw_params (struct snd_sof_dev * sdev , struct snd_pcm_hw_params * params ,
1122- struct sof_ipc4_audio_format * fmt )
1122+ struct sof_ipc4_audio_format * fmt , u32 param_to_update )
11231123{
1124- snd_pcm_format_t snd_fmt ;
11251124 struct snd_interval * i ;
1126- struct snd_mask * m ;
1127- int valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH (fmt -> fmt_cfg );
1128- unsigned int channels , rate ;
11291125
1130- switch (valid_bits ) {
1131- case 16 :
1132- snd_fmt = SNDRV_PCM_FORMAT_S16_LE ;
1133- break ;
1134- case 24 :
1135- snd_fmt = SNDRV_PCM_FORMAT_S24_LE ;
1136- break ;
1137- case 32 :
1138- snd_fmt = SNDRV_PCM_FORMAT_S32_LE ;
1139- break ;
1140- default :
1141- dev_err (sdev -> dev , "invalid PCM valid_bits %d\n" , valid_bits );
1142- return - EINVAL ;
1126+ if (param_to_update & BIT (SNDRV_PCM_HW_PARAM_FORMAT )) {
1127+ int valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH (fmt -> fmt_cfg );
1128+ snd_pcm_format_t snd_fmt ;
1129+ struct snd_mask * m ;
1130+
1131+ switch (valid_bits ) {
1132+ case 16 :
1133+ snd_fmt = SNDRV_PCM_FORMAT_S16_LE ;
1134+ break ;
1135+ case 24 :
1136+ snd_fmt = SNDRV_PCM_FORMAT_S24_LE ;
1137+ break ;
1138+ case 32 :
1139+ snd_fmt = SNDRV_PCM_FORMAT_S32_LE ;
1140+ break ;
1141+ default :
1142+ dev_err (sdev -> dev , "invalid PCM valid_bits %d\n" , valid_bits );
1143+ return - EINVAL ;
1144+ }
1145+
1146+ m = hw_param_mask (params , SNDRV_PCM_HW_PARAM_FORMAT );
1147+ snd_mask_none (m );
1148+ snd_mask_set_format (m , snd_fmt );
11431149 }
11441150
1145- m = hw_param_mask (params , SNDRV_PCM_HW_PARAM_FORMAT );
1146- snd_mask_none (m );
1147- snd_mask_set_format (m , snd_fmt );
1151+ if (param_to_update & BIT (SNDRV_PCM_HW_PARAM_RATE )) {
1152+ unsigned int rate = fmt -> sampling_frequency ;
11481153
1149- rate = fmt -> sampling_frequency ;
1150- i = hw_param_interval ( params , SNDRV_PCM_HW_PARAM_RATE ) ;
1151- i -> min = rate ;
1152- i -> max = rate ;
1154+ i = hw_param_interval ( params , SNDRV_PCM_HW_PARAM_RATE ) ;
1155+ i -> min = rate ;
1156+ i -> max = rate ;
1157+ }
11531158
1154- channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT (fmt -> fmt_cfg );
1155- i = hw_param_interval (params , SNDRV_PCM_HW_PARAM_CHANNELS );
1156- i -> min = channels ;
1157- i -> max = channels ;
1159+ if (param_to_update & BIT (SNDRV_PCM_HW_PARAM_CHANNELS )) {
1160+ unsigned int channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT (fmt -> fmt_cfg );
1161+
1162+ i = hw_param_interval (params , SNDRV_PCM_HW_PARAM_CHANNELS );
1163+ i -> min = channels ;
1164+ i -> max = channels ;
1165+ }
11581166
11591167 return 0 ;
11601168}
@@ -1412,13 +1420,16 @@ static int snd_sof_get_hw_config_params(struct snd_sof_dev *sdev, struct snd_sof
14121420 return 0 ;
14131421}
14141422
1415- static int snd_sof_get_nhlt_endpoint_data (struct snd_sof_dev * sdev , struct snd_sof_dai * dai ,
1416- struct snd_pcm_hw_params * params , u32 dai_index ,
1417- u32 linktype , u8 dir , u32 * * dst , u32 * len )
1423+ static int
1424+ snd_sof_get_nhlt_endpoint_data (struct snd_sof_dev * sdev , struct snd_sof_dai * dai ,
1425+ bool single_format ,
1426+ struct snd_pcm_hw_params * params , u32 dai_index ,
1427+ u32 linktype , u8 dir , u32 * * dst , u32 * len )
14181428{
14191429 struct sof_ipc4_fw_data * ipc4_data = sdev -> private ;
14201430 struct nhlt_specific_cfg * cfg ;
14211431 int sample_rate , channel_count ;
1432+ bool format_change = false;
14221433 int bit_depth , ret ;
14231434 u32 nhlt_type ;
14241435 int dev_type = 0 ;
@@ -1427,9 +1438,18 @@ static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_s
14271438 switch (linktype ) {
14281439 case SOF_DAI_INTEL_DMIC :
14291440 nhlt_type = NHLT_LINK_DMIC ;
1430- bit_depth = params_width (params );
14311441 channel_count = params_channels (params );
14321442 sample_rate = params_rate (params );
1443+ bit_depth = params_width (params );
1444+ /*
1445+ * Look for 32-bit blob first instead of 16-bit if copier
1446+ * supports multiple formats
1447+ */
1448+ if (bit_depth == 16 && !single_format ) {
1449+ dev_dbg (sdev -> dev , "Looking for 32-bit blob first for DMIC\n" );
1450+ format_change = true;
1451+ bit_depth = 32 ;
1452+ }
14331453 break ;
14341454 case SOF_DAI_INTEL_SSP :
14351455 nhlt_type = NHLT_LINK_SSP ;
@@ -1463,22 +1483,56 @@ static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_s
14631483 dir , dev_type );
14641484
14651485 if (!cfg ) {
1486+ if (format_change ) {
1487+ /*
1488+ * The 32-bit blob was not found in NHLT table, try to
1489+ * look for one based on the params
1490+ */
1491+ bit_depth = params_width (params );
1492+ format_change = false;
1493+
1494+ cfg = intel_nhlt_get_endpoint_blob (sdev -> dev , ipc4_data -> nhlt ,
1495+ dai_index , nhlt_type ,
1496+ bit_depth , bit_depth ,
1497+ channel_count , sample_rate ,
1498+ dir , dev_type );
1499+ if (cfg )
1500+ goto out ;
1501+ }
1502+
14661503 dev_err (sdev -> dev ,
14671504 "no matching blob for sample rate: %d sample width: %d channels: %d\n" ,
14681505 sample_rate , bit_depth , channel_count );
14691506 return - EINVAL ;
14701507 }
14711508
1509+ out :
14721510 /* config length should be in dwords */
14731511 * len = cfg -> size >> 2 ;
14741512 * dst = (u32 * )cfg -> caps ;
14751513
1514+ if (format_change ) {
1515+ /*
1516+ * Update the params to reflect that we have loaded 32-bit blob
1517+ * instead of the 16-bit.
1518+ * This information is going to be used by the caller to find
1519+ * matching copier format on the dai side.
1520+ */
1521+ struct snd_mask * m ;
1522+
1523+ m = hw_param_mask (params , SNDRV_PCM_HW_PARAM_FORMAT );
1524+ snd_mask_none (m );
1525+ snd_mask_set_format (m , SNDRV_PCM_FORMAT_S32_LE );
1526+ }
1527+
14761528 return 0 ;
14771529}
14781530#else
1479- static int snd_sof_get_nhlt_endpoint_data (struct snd_sof_dev * sdev , struct snd_sof_dai * dai ,
1480- struct snd_pcm_hw_params * params , u32 dai_index ,
1481- u32 linktype , u8 dir , u32 * * dst , u32 * len )
1531+ static int
1532+ snd_sof_get_nhlt_endpoint_data (struct snd_sof_dev * sdev , struct snd_sof_dai * dai ,
1533+ bool single_format ,
1534+ struct snd_pcm_hw_params * params , u32 dai_index ,
1535+ u32 linktype , u8 dir , u32 * * dst , u32 * len )
14821536{
14831537 return 0 ;
14841538}
@@ -1509,6 +1563,68 @@ bool sof_ipc4_copier_is_single_format(struct snd_sof_dev *sdev,
15091563 return true;
15101564}
15111565
1566+ static int
1567+ sof_ipc4_prepare_dai_copier (struct snd_sof_dev * sdev , struct snd_sof_dai * dai ,
1568+ struct snd_pcm_hw_params * params , int dir )
1569+ {
1570+ struct sof_ipc4_available_audio_format * available_fmt ;
1571+ struct snd_pcm_hw_params dai_params = * params ;
1572+ struct sof_ipc4_copier_data * copier_data ;
1573+ struct sof_ipc4_copier * ipc4_copier ;
1574+ bool single_format ;
1575+ int ret ;
1576+
1577+ ipc4_copier = dai -> private ;
1578+ copier_data = & ipc4_copier -> data ;
1579+ available_fmt = & ipc4_copier -> available_fmt ;
1580+
1581+ /*
1582+ * If the copier on the DAI side supports only single bit depth then
1583+ * this depth (format) should be used to look for the NHLT blob (if
1584+ * needed) and in case of capture this should be used for the input
1585+ * format lookup
1586+ */
1587+ if (dir == SNDRV_PCM_STREAM_PLAYBACK ) {
1588+ single_format = sof_ipc4_copier_is_single_format (sdev ,
1589+ available_fmt -> output_pin_fmts ,
1590+ available_fmt -> num_output_formats );
1591+
1592+ /* Update the dai_params with the only supported format */
1593+ if (single_format ) {
1594+ ret = sof_ipc4_update_hw_params (sdev , & dai_params ,
1595+ & available_fmt -> output_pin_fmts [0 ].audio_fmt ,
1596+ BIT (SNDRV_PCM_HW_PARAM_FORMAT ));
1597+ if (ret )
1598+ return ret ;
1599+ }
1600+ } else {
1601+ single_format = sof_ipc4_copier_is_single_format (sdev ,
1602+ available_fmt -> input_pin_fmts ,
1603+ available_fmt -> num_input_formats );
1604+
1605+ /* Update the dai_params with the only supported format */
1606+ if (single_format ) {
1607+ ret = sof_ipc4_update_hw_params (sdev , & dai_params ,
1608+ & available_fmt -> input_pin_fmts [0 ].audio_fmt ,
1609+ BIT (SNDRV_PCM_HW_PARAM_FORMAT ));
1610+ if (ret )
1611+ return ret ;
1612+ }
1613+ }
1614+
1615+ ret = snd_sof_get_nhlt_endpoint_data (sdev , dai , single_format ,
1616+ & dai_params ,
1617+ ipc4_copier -> dai_index ,
1618+ ipc4_copier -> dai_type , dir ,
1619+ & ipc4_copier -> copier_config ,
1620+ & copier_data -> gtw_cfg .config_length );
1621+ /* Update the params to reflect the changes made in this function */
1622+ if (!ret )
1623+ * params = dai_params ;
1624+
1625+ return ret ;
1626+ }
1627+
15121628static int
15131629sof_ipc4_prepare_copier_module (struct snd_sof_widget * swidget ,
15141630 struct snd_pcm_hw_params * fe_params ,
@@ -1519,7 +1635,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
15191635 struct snd_soc_component * scomp = swidget -> scomp ;
15201636 struct snd_sof_dev * sdev = snd_soc_component_get_drvdata (scomp );
15211637 struct sof_ipc4_copier_data * copier_data ;
1522- struct snd_pcm_hw_params * ref_params ;
1638+ struct snd_pcm_hw_params ref_params ;
15231639 struct sof_ipc4_copier * ipc4_copier ;
15241640 struct snd_sof_dai * dai ;
15251641 u32 gtw_cfg_config_length ;
@@ -1597,9 +1713,9 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
15971713 * for capture.
15981714 */
15991715 if (dir == SNDRV_PCM_STREAM_PLAYBACK )
1600- ref_params = fe_params ;
1716+ ref_params = * fe_params ;
16011717 else
1602- ref_params = pipeline_params ;
1718+ ref_params = * pipeline_params ;
16031719
16041720 copier_data -> gtw_cfg .node_id &= ~SOF_IPC4_NODE_INDEX_MASK ;
16051721 copier_data -> gtw_cfg .node_id |=
@@ -1625,31 +1741,33 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
16251741 available_fmt = & ipc4_copier -> available_fmt ;
16261742
16271743 /*
1628- * When there is format conversion within a pipeline, the number of supported
1629- * output formats is typically limited to just 1 for the DAI copiers. But when there
1630- * is no format conversion, the DAI copiers input format must match that of the
1631- * FE hw_params for capture and the pipeline params for playback.
1744+ * Use the fe_params as a base for the copier configuration.
1745+ * The ref_params might get updated to reflect what format is
1746+ * supported by the copier on the DAI side.
1747+ *
1748+ * In case of capture the ref_params returned will be used to
1749+ * find the input configuration of the copier.
16321750 */
1633- if (dir == SNDRV_PCM_STREAM_PLAYBACK )
1634- ref_params = pipeline_params ;
1635- else
1636- ref_params = fe_params ;
1637-
1638- ret = snd_sof_get_nhlt_endpoint_data (sdev , dai , fe_params , ipc4_copier -> dai_index ,
1639- ipc4_copier -> dai_type , dir ,
1640- & ipc4_copier -> copier_config ,
1641- & copier_data -> gtw_cfg .config_length );
1751+ ref_params = * fe_params ;
1752+ ret = sof_ipc4_prepare_dai_copier (sdev , dai , & ref_params , dir );
16421753 if (ret < 0 )
16431754 return ret ;
16441755
1756+ /*
1757+ * For playback the pipeline_params needs to be used to find the
1758+ * input configuration of the copier.
1759+ */
1760+ if (dir == SNDRV_PCM_STREAM_PLAYBACK )
1761+ ref_params = * pipeline_params ;
1762+
16451763 break ;
16461764 }
16471765 case snd_soc_dapm_buffer :
16481766 {
16491767 ipc4_copier = (struct sof_ipc4_copier * )swidget -> private ;
16501768 copier_data = & ipc4_copier -> data ;
16511769 available_fmt = & ipc4_copier -> available_fmt ;
1652- ref_params = pipeline_params ;
1770+ ref_params = * pipeline_params ;
16531771
16541772 break ;
16551773 }
@@ -1660,8 +1778,8 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
16601778 }
16611779
16621780 /* set input and output audio formats */
1663- ret = sof_ipc4_init_input_audio_fmt (sdev , swidget , & copier_data -> base_config , ref_params ,
1664- available_fmt );
1781+ ret = sof_ipc4_init_input_audio_fmt (sdev , swidget , & copier_data -> base_config ,
1782+ & ref_params , available_fmt );
16651783 if (ret < 0 )
16661784 return ret ;
16671785
@@ -1844,7 +1962,11 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
18441962 }
18451963
18461964 /* modify the input params for the next widget */
1847- ret = sof_ipc4_update_hw_params (sdev , pipeline_params , & copier_data -> out_format );
1965+ ret = sof_ipc4_update_hw_params (sdev , pipeline_params ,
1966+ & copier_data -> out_format ,
1967+ BIT (SNDRV_PCM_HW_PARAM_FORMAT ) |
1968+ BIT (SNDRV_PCM_HW_PARAM_CHANNELS ) |
1969+ BIT (SNDRV_PCM_HW_PARAM_RATE ));
18481970 if (ret )
18491971 return ret ;
18501972
@@ -2069,7 +2191,10 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget,
20692191 src -> data .sink_rate = out_audio_fmt -> sampling_frequency ;
20702192
20712193 /* update pipeline_params for sink widgets */
2072- return sof_ipc4_update_hw_params (sdev , pipeline_params , out_audio_fmt );
2194+ return sof_ipc4_update_hw_params (sdev , pipeline_params , out_audio_fmt ,
2195+ BIT (SNDRV_PCM_HW_PARAM_FORMAT ) |
2196+ BIT (SNDRV_PCM_HW_PARAM_CHANNELS ) |
2197+ BIT (SNDRV_PCM_HW_PARAM_RATE ));
20732198}
20742199
20752200static int
@@ -2193,7 +2318,11 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget,
21932318 sizeof (struct sof_ipc4_audio_format ));
21942319
21952320 /* modify the pipeline params with the pin 0 output format */
2196- ret = sof_ipc4_update_hw_params (sdev , pipeline_params , & process -> output_format );
2321+ ret = sof_ipc4_update_hw_params (sdev , pipeline_params ,
2322+ & process -> output_format ,
2323+ BIT (SNDRV_PCM_HW_PARAM_FORMAT ) |
2324+ BIT (SNDRV_PCM_HW_PARAM_CHANNELS ) |
2325+ BIT (SNDRV_PCM_HW_PARAM_RATE ));
21972326 if (ret )
21982327 return ret ;
21992328 }
0 commit comments