@@ -1420,13 +1420,16 @@ static int snd_sof_get_hw_config_params(struct snd_sof_dev *sdev, struct snd_sof
14201420 return 0 ;
14211421}
14221422
1423- static int snd_sof_get_nhlt_endpoint_data (struct snd_sof_dev * sdev , struct snd_sof_dai * dai ,
1424- struct snd_pcm_hw_params * params , u32 dai_index ,
1425- 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 )
14261428{
14271429 struct sof_ipc4_fw_data * ipc4_data = sdev -> private ;
14281430 struct nhlt_specific_cfg * cfg ;
14291431 int sample_rate , channel_count ;
1432+ bool format_change = false;
14301433 int bit_depth , ret ;
14311434 u32 nhlt_type ;
14321435 int dev_type = 0 ;
@@ -1435,9 +1438,18 @@ static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_s
14351438 switch (linktype ) {
14361439 case SOF_DAI_INTEL_DMIC :
14371440 nhlt_type = NHLT_LINK_DMIC ;
1438- bit_depth = params_width (params );
14391441 channel_count = params_channels (params );
14401442 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+ }
14411453 break ;
14421454 case SOF_DAI_INTEL_SSP :
14431455 nhlt_type = NHLT_LINK_SSP ;
@@ -1471,22 +1483,56 @@ static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_s
14711483 dir , dev_type );
14721484
14731485 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+
14741503 dev_err (sdev -> dev ,
14751504 "no matching blob for sample rate: %d sample width: %d channels: %d\n" ,
14761505 sample_rate , bit_depth , channel_count );
14771506 return - EINVAL ;
14781507 }
14791508
1509+ out :
14801510 /* config length should be in dwords */
14811511 * len = cfg -> size >> 2 ;
14821512 * dst = (u32 * )cfg -> caps ;
14831513
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+
14841528 return 0 ;
14851529}
14861530#else
1487- static int snd_sof_get_nhlt_endpoint_data (struct snd_sof_dev * sdev , struct snd_sof_dai * dai ,
1488- struct snd_pcm_hw_params * params , u32 dai_index ,
1489- 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 )
14901536{
14911537 return 0 ;
14921538}
@@ -1517,6 +1563,68 @@ bool sof_ipc4_copier_is_single_format(struct snd_sof_dev *sdev,
15171563 return true;
15181564}
15191565
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+
15201628static int
15211629sof_ipc4_prepare_copier_module (struct snd_sof_widget * swidget ,
15221630 struct snd_pcm_hw_params * fe_params ,
@@ -1527,7 +1635,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
15271635 struct snd_soc_component * scomp = swidget -> scomp ;
15281636 struct snd_sof_dev * sdev = snd_soc_component_get_drvdata (scomp );
15291637 struct sof_ipc4_copier_data * copier_data ;
1530- struct snd_pcm_hw_params * ref_params ;
1638+ struct snd_pcm_hw_params ref_params ;
15311639 struct sof_ipc4_copier * ipc4_copier ;
15321640 struct snd_sof_dai * dai ;
15331641 u32 gtw_cfg_config_length ;
@@ -1605,9 +1713,9 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
16051713 * for capture.
16061714 */
16071715 if (dir == SNDRV_PCM_STREAM_PLAYBACK )
1608- ref_params = fe_params ;
1716+ ref_params = * fe_params ;
16091717 else
1610- ref_params = pipeline_params ;
1718+ ref_params = * pipeline_params ;
16111719
16121720 copier_data -> gtw_cfg .node_id &= ~SOF_IPC4_NODE_INDEX_MASK ;
16131721 copier_data -> gtw_cfg .node_id |=
@@ -1633,31 +1741,33 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
16331741 available_fmt = & ipc4_copier -> available_fmt ;
16341742
16351743 /*
1636- * When there is format conversion within a pipeline, the number of supported
1637- * output formats is typically limited to just 1 for the DAI copiers. But when there
1638- * is no format conversion, the DAI copiers input format must match that of the
1639- * 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.
16401750 */
1641- if (dir == SNDRV_PCM_STREAM_PLAYBACK )
1642- ref_params = pipeline_params ;
1643- else
1644- ref_params = fe_params ;
1645-
1646- ret = snd_sof_get_nhlt_endpoint_data (sdev , dai , fe_params , ipc4_copier -> dai_index ,
1647- ipc4_copier -> dai_type , dir ,
1648- & ipc4_copier -> copier_config ,
1649- & copier_data -> gtw_cfg .config_length );
1751+ ref_params = * fe_params ;
1752+ ret = sof_ipc4_prepare_dai_copier (sdev , dai , & ref_params , dir );
16501753 if (ret < 0 )
16511754 return ret ;
16521755
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+
16531763 break ;
16541764 }
16551765 case snd_soc_dapm_buffer :
16561766 {
16571767 ipc4_copier = (struct sof_ipc4_copier * )swidget -> private ;
16581768 copier_data = & ipc4_copier -> data ;
16591769 available_fmt = & ipc4_copier -> available_fmt ;
1660- ref_params = pipeline_params ;
1770+ ref_params = * pipeline_params ;
16611771
16621772 break ;
16631773 }
@@ -1668,8 +1778,8 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
16681778 }
16691779
16701780 /* set input and output audio formats */
1671- ret = sof_ipc4_init_input_audio_fmt (sdev , swidget , & copier_data -> base_config , ref_params ,
1672- available_fmt );
1781+ ret = sof_ipc4_init_input_audio_fmt (sdev , swidget , & copier_data -> base_config ,
1782+ & ref_params , available_fmt );
16731783 if (ret < 0 )
16741784 return ret ;
16751785
0 commit comments