@@ -1119,42 +1119,50 @@ static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev,
1119
1119
1120
1120
/* update hw_params based on the audio stream format */
1121
1121
static 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 )
1123
1123
{
1124
- snd_pcm_format_t snd_fmt ;
1125
1124
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 ;
1129
1125
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 );
1143
1149
}
1144
1150
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 ;
1148
1153
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
+ }
1153
1158
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
+ }
1158
1166
1159
1167
return 0 ;
1160
1168
}
@@ -1412,13 +1420,16 @@ static int snd_sof_get_hw_config_params(struct snd_sof_dev *sdev, struct snd_sof
1412
1420
return 0 ;
1413
1421
}
1414
1422
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 )
1418
1428
{
1419
1429
struct sof_ipc4_fw_data * ipc4_data = sdev -> private ;
1420
1430
struct nhlt_specific_cfg * cfg ;
1421
1431
int sample_rate , channel_count ;
1432
+ bool format_change = false;
1422
1433
int bit_depth , ret ;
1423
1434
u32 nhlt_type ;
1424
1435
int dev_type = 0 ;
@@ -1427,9 +1438,18 @@ static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_s
1427
1438
switch (linktype ) {
1428
1439
case SOF_DAI_INTEL_DMIC :
1429
1440
nhlt_type = NHLT_LINK_DMIC ;
1430
- bit_depth = params_width (params );
1431
1441
channel_count = params_channels (params );
1432
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
+ }
1433
1453
break ;
1434
1454
case SOF_DAI_INTEL_SSP :
1435
1455
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
1463
1483
dir , dev_type );
1464
1484
1465
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
+
1466
1503
dev_err (sdev -> dev ,
1467
1504
"no matching blob for sample rate: %d sample width: %d channels: %d\n" ,
1468
1505
sample_rate , bit_depth , channel_count );
1469
1506
return - EINVAL ;
1470
1507
}
1471
1508
1509
+ out :
1472
1510
/* config length should be in dwords */
1473
1511
* len = cfg -> size >> 2 ;
1474
1512
* dst = (u32 * )cfg -> caps ;
1475
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
+
1476
1528
return 0 ;
1477
1529
}
1478
1530
#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 )
1482
1536
{
1483
1537
return 0 ;
1484
1538
}
@@ -1509,6 +1563,68 @@ bool sof_ipc4_copier_is_single_format(struct snd_sof_dev *sdev,
1509
1563
return true;
1510
1564
}
1511
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
+
1512
1628
static int
1513
1629
sof_ipc4_prepare_copier_module (struct snd_sof_widget * swidget ,
1514
1630
struct snd_pcm_hw_params * fe_params ,
@@ -1519,7 +1635,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
1519
1635
struct snd_soc_component * scomp = swidget -> scomp ;
1520
1636
struct snd_sof_dev * sdev = snd_soc_component_get_drvdata (scomp );
1521
1637
struct sof_ipc4_copier_data * copier_data ;
1522
- struct snd_pcm_hw_params * ref_params ;
1638
+ struct snd_pcm_hw_params ref_params ;
1523
1639
struct sof_ipc4_copier * ipc4_copier ;
1524
1640
struct snd_sof_dai * dai ;
1525
1641
u32 gtw_cfg_config_length ;
@@ -1597,9 +1713,9 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
1597
1713
* for capture.
1598
1714
*/
1599
1715
if (dir == SNDRV_PCM_STREAM_PLAYBACK )
1600
- ref_params = fe_params ;
1716
+ ref_params = * fe_params ;
1601
1717
else
1602
- ref_params = pipeline_params ;
1718
+ ref_params = * pipeline_params ;
1603
1719
1604
1720
copier_data -> gtw_cfg .node_id &= ~SOF_IPC4_NODE_INDEX_MASK ;
1605
1721
copier_data -> gtw_cfg .node_id |=
@@ -1625,31 +1741,33 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
1625
1741
available_fmt = & ipc4_copier -> available_fmt ;
1626
1742
1627
1743
/*
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.
1632
1750
*/
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 );
1642
1753
if (ret < 0 )
1643
1754
return ret ;
1644
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
+
1645
1763
break ;
1646
1764
}
1647
1765
case snd_soc_dapm_buffer :
1648
1766
{
1649
1767
ipc4_copier = (struct sof_ipc4_copier * )swidget -> private ;
1650
1768
copier_data = & ipc4_copier -> data ;
1651
1769
available_fmt = & ipc4_copier -> available_fmt ;
1652
- ref_params = pipeline_params ;
1770
+ ref_params = * pipeline_params ;
1653
1771
1654
1772
break ;
1655
1773
}
@@ -1660,8 +1778,8 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
1660
1778
}
1661
1779
1662
1780
/* 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 );
1665
1783
if (ret < 0 )
1666
1784
return ret ;
1667
1785
@@ -1844,7 +1962,11 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
1844
1962
}
1845
1963
1846
1964
/* 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 ));
1848
1970
if (ret )
1849
1971
return ret ;
1850
1972
@@ -2069,7 +2191,10 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget,
2069
2191
src -> data .sink_rate = out_audio_fmt -> sampling_frequency ;
2070
2192
2071
2193
/* 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 ));
2073
2198
}
2074
2199
2075
2200
static int
@@ -2193,7 +2318,11 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget,
2193
2318
sizeof (struct sof_ipc4_audio_format ));
2194
2319
2195
2320
/* 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 ));
2197
2326
if (ret )
2198
2327
return ret ;
2199
2328
}
0 commit comments