@@ -1420,13 +1420,16 @@ static int snd_sof_get_hw_config_params(struct snd_sof_dev *sdev, struct snd_sof
1420
1420
return 0 ;
1421
1421
}
1422
1422
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 )
1426
1428
{
1427
1429
struct sof_ipc4_fw_data * ipc4_data = sdev -> private ;
1428
1430
struct nhlt_specific_cfg * cfg ;
1429
1431
int sample_rate , channel_count ;
1432
+ bool format_change = false;
1430
1433
int bit_depth , ret ;
1431
1434
u32 nhlt_type ;
1432
1435
int dev_type = 0 ;
@@ -1435,9 +1438,18 @@ static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_s
1435
1438
switch (linktype ) {
1436
1439
case SOF_DAI_INTEL_DMIC :
1437
1440
nhlt_type = NHLT_LINK_DMIC ;
1438
- bit_depth = params_width (params );
1439
1441
channel_count = params_channels (params );
1440
1442
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
+ }
1441
1453
break ;
1442
1454
case SOF_DAI_INTEL_SSP :
1443
1455
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
1471
1483
dir , dev_type );
1472
1484
1473
1485
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
+
1474
1503
dev_err (sdev -> dev ,
1475
1504
"no matching blob for sample rate: %d sample width: %d channels: %d\n" ,
1476
1505
sample_rate , bit_depth , channel_count );
1477
1506
return - EINVAL ;
1478
1507
}
1479
1508
1509
+ out :
1480
1510
/* config length should be in dwords */
1481
1511
* len = cfg -> size >> 2 ;
1482
1512
* dst = (u32 * )cfg -> caps ;
1483
1513
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
+
1484
1528
return 0 ;
1485
1529
}
1486
1530
#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 )
1490
1536
{
1491
1537
return 0 ;
1492
1538
}
@@ -1517,6 +1563,68 @@ bool sof_ipc4_copier_is_single_format(struct snd_sof_dev *sdev,
1517
1563
return true;
1518
1564
}
1519
1565
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
+
1520
1628
static int
1521
1629
sof_ipc4_prepare_copier_module (struct snd_sof_widget * swidget ,
1522
1630
struct snd_pcm_hw_params * fe_params ,
@@ -1527,7 +1635,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
1527
1635
struct snd_soc_component * scomp = swidget -> scomp ;
1528
1636
struct snd_sof_dev * sdev = snd_soc_component_get_drvdata (scomp );
1529
1637
struct sof_ipc4_copier_data * copier_data ;
1530
- struct snd_pcm_hw_params * ref_params ;
1638
+ struct snd_pcm_hw_params ref_params ;
1531
1639
struct sof_ipc4_copier * ipc4_copier ;
1532
1640
struct snd_sof_dai * dai ;
1533
1641
u32 gtw_cfg_config_length ;
@@ -1605,9 +1713,9 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
1605
1713
* for capture.
1606
1714
*/
1607
1715
if (dir == SNDRV_PCM_STREAM_PLAYBACK )
1608
- ref_params = fe_params ;
1716
+ ref_params = * fe_params ;
1609
1717
else
1610
- ref_params = pipeline_params ;
1718
+ ref_params = * pipeline_params ;
1611
1719
1612
1720
copier_data -> gtw_cfg .node_id &= ~SOF_IPC4_NODE_INDEX_MASK ;
1613
1721
copier_data -> gtw_cfg .node_id |=
@@ -1633,31 +1741,33 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
1633
1741
available_fmt = & ipc4_copier -> available_fmt ;
1634
1742
1635
1743
/*
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.
1640
1750
*/
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 );
1650
1753
if (ret < 0 )
1651
1754
return ret ;
1652
1755
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
+
1653
1763
break ;
1654
1764
}
1655
1765
case snd_soc_dapm_buffer :
1656
1766
{
1657
1767
ipc4_copier = (struct sof_ipc4_copier * )swidget -> private ;
1658
1768
copier_data = & ipc4_copier -> data ;
1659
1769
available_fmt = & ipc4_copier -> available_fmt ;
1660
- ref_params = pipeline_params ;
1770
+ ref_params = * pipeline_params ;
1661
1771
1662
1772
break ;
1663
1773
}
@@ -1668,8 +1778,8 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
1668
1778
}
1669
1779
1670
1780
/* 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 );
1673
1783
if (ret < 0 )
1674
1784
return ret ;
1675
1785
0 commit comments