Skip to content

Commit c85578e

Browse files
committed
ASoC: SOF: ipc4-topology: Fix nhlt configuration blob
Merge series from Peter Ujfalusi <[email protected]>: The existing logic to pick a DMIC blob is based on several historical assumptions that the NHLT in BIOS always contains 32-bits per sample type (first patch, [1]). The other issue with the existing logic is that it was designed to care only about the bit depth of the format and fails to find the existing and correct blob when rate/channels are different on the FE side compared to what we should be using on the DAI side (we have components in path which can change rate/channel count). These issues have not been observed in past but with new MTL based (Windows) laptops and new topologies to enhance the audio quality, we started to see weird issues around how our assumptions of vendors failed. Since some NHLT blob handling cleanup has been done for 6.10, this series will complete that work to cover even cases that we don't anticipate to see. [1] thesofproject/linux#4973
2 parents ba2e832 + b65456b commit c85578e

File tree

3 files changed

+115
-58
lines changed

3 files changed

+115
-58
lines changed

sound/soc/sof/ipc4-pcm.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,7 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
650650
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
651651
struct sof_ipc4_audio_format *ipc4_fmt;
652652
struct sof_ipc4_copier *ipc4_copier;
653-
bool single_fmt = false;
653+
bool single_bitdepth = false;
654654
u32 valid_bits = 0;
655655
int dir, ret;
656656

@@ -682,18 +682,18 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
682682
return 0;
683683

684684
if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
685-
if (sof_ipc4_copier_is_single_format(sdev,
685+
if (sof_ipc4_copier_is_single_bitdepth(sdev,
686686
available_fmt->output_pin_fmts,
687687
available_fmt->num_output_formats)) {
688688
ipc4_fmt = &available_fmt->output_pin_fmts->audio_fmt;
689-
single_fmt = true;
689+
single_bitdepth = true;
690690
}
691691
} else {
692-
if (sof_ipc4_copier_is_single_format(sdev,
692+
if (sof_ipc4_copier_is_single_bitdepth(sdev,
693693
available_fmt->input_pin_fmts,
694694
available_fmt->num_input_formats)) {
695695
ipc4_fmt = &available_fmt->input_pin_fmts->audio_fmt;
696-
single_fmt = true;
696+
single_bitdepth = true;
697697
}
698698
}
699699
}
@@ -703,7 +703,7 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
703703
if (ret)
704704
return ret;
705705

706-
if (single_fmt) {
706+
if (single_bitdepth) {
707707
snd_mask_none(fmt);
708708
valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(ipc4_fmt->fmt_cfg);
709709
dev_dbg(component->dev, "Set %s to %d bit format\n", dai->name, valid_bits);

sound/soc/sof/ipc4-topology.c

Lines changed: 106 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,10 @@ static void sof_ipc4_dbg_audio_format(struct device *dev, struct sof_ipc4_pin_fo
195195
for (i = 0; i < num_formats; i++) {
196196
struct sof_ipc4_audio_format *fmt = &pin_fmt[i].audio_fmt;
197197
dev_dbg(dev,
198-
"Pin index #%d: %uHz, %ubit (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x) buffer size %d\n",
199-
pin_fmt[i].pin_index, fmt->sampling_frequency, fmt->bit_depth, fmt->ch_map,
200-
fmt->ch_cfg, fmt->interleaving_style, fmt->fmt_cfg,
198+
"Pin index #%d: %uHz, %ubit, %luch (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x) buffer size %d\n",
199+
pin_fmt[i].pin_index, fmt->sampling_frequency, fmt->bit_depth,
200+
SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg),
201+
fmt->ch_map, fmt->ch_cfg, fmt->interleaving_style, fmt->fmt_cfg,
201202
pin_fmt[i].buffer_size);
202203
}
203204
}
@@ -1430,7 +1431,7 @@ static int snd_sof_get_hw_config_params(struct snd_sof_dev *sdev, struct snd_sof
14301431

14311432
static int
14321433
snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
1433-
bool single_format,
1434+
bool single_bitdepth,
14341435
struct snd_pcm_hw_params *params, u32 dai_index,
14351436
u32 linktype, u8 dir, u32 **dst, u32 *len)
14361437
{
@@ -1453,7 +1454,7 @@ snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai
14531454
* Look for 32-bit blob first instead of 16-bit if copier
14541455
* supports multiple formats
14551456
*/
1456-
if (bit_depth == 16 && !single_format) {
1457+
if (bit_depth == 16 && !single_bitdepth) {
14571458
dev_dbg(sdev->dev, "Looking for 32-bit blob first for DMIC\n");
14581459
format_change = true;
14591460
bit_depth = 32;
@@ -1491,14 +1492,29 @@ snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai
14911492
dir, dev_type);
14921493

14931494
if (!cfg) {
1495+
bool get_new_blob = false;
1496+
14941497
if (format_change) {
14951498
/*
14961499
* The 32-bit blob was not found in NHLT table, try to
14971500
* look for one based on the params
14981501
*/
14991502
bit_depth = params_width(params);
15001503
format_change = false;
1504+
get_new_blob = true;
1505+
} else if (linktype == SOF_DAI_INTEL_DMIC && !single_bitdepth) {
1506+
/*
1507+
* The requested 32-bit blob (no format change for the
1508+
* blob request) was not found in NHLT table, try to
1509+
* look for 16-bit blob if the copier supports multiple
1510+
* formats
1511+
*/
1512+
bit_depth = 16;
1513+
format_change = true;
1514+
get_new_blob = true;
1515+
}
15011516

1517+
if (get_new_blob) {
15021518
cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt,
15031519
dai_index, nhlt_type,
15041520
bit_depth, bit_depth,
@@ -1521,34 +1537,38 @@ snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai
15211537

15221538
if (format_change) {
15231539
/*
1524-
* Update the params to reflect that we have loaded 32-bit blob
1525-
* instead of the 16-bit.
1540+
* Update the params to reflect that different blob was loaded
1541+
* instead of the requested bit depth (16 -> 32 or 32 -> 16).
15261542
* This information is going to be used by the caller to find
15271543
* matching copier format on the dai side.
15281544
*/
15291545
struct snd_mask *m;
15301546

15311547
m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
15321548
snd_mask_none(m);
1533-
snd_mask_set_format(m, SNDRV_PCM_FORMAT_S32_LE);
1549+
if (bit_depth == 16)
1550+
snd_mask_set_format(m, SNDRV_PCM_FORMAT_S16_LE);
1551+
else
1552+
snd_mask_set_format(m, SNDRV_PCM_FORMAT_S32_LE);
1553+
15341554
}
15351555

15361556
return 0;
15371557
}
15381558
#else
15391559
static int
15401560
snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
1541-
bool single_format,
1561+
bool single_bitdepth,
15421562
struct snd_pcm_hw_params *params, u32 dai_index,
15431563
u32 linktype, u8 dir, u32 **dst, u32 *len)
15441564
{
15451565
return 0;
15461566
}
15471567
#endif
15481568

1549-
bool sof_ipc4_copier_is_single_format(struct snd_sof_dev *sdev,
1550-
struct sof_ipc4_pin_format *pin_fmts,
1551-
u32 pin_fmts_size)
1569+
bool sof_ipc4_copier_is_single_bitdepth(struct snd_sof_dev *sdev,
1570+
struct sof_ipc4_pin_format *pin_fmts,
1571+
u32 pin_fmts_size)
15521572
{
15531573
struct sof_ipc4_audio_format *fmt;
15541574
u32 valid_bits;
@@ -1571,56 +1591,93 @@ bool sof_ipc4_copier_is_single_format(struct snd_sof_dev *sdev,
15711591
return true;
15721592
}
15731593

1594+
static int
1595+
sof_ipc4_adjust_params_to_dai_format(struct snd_sof_dev *sdev,
1596+
struct snd_pcm_hw_params *params,
1597+
struct sof_ipc4_pin_format *pin_fmts,
1598+
u32 pin_fmts_size)
1599+
{
1600+
u32 params_mask = BIT(SNDRV_PCM_HW_PARAM_RATE) |
1601+
BIT(SNDRV_PCM_HW_PARAM_CHANNELS) |
1602+
BIT(SNDRV_PCM_HW_PARAM_FORMAT);
1603+
struct sof_ipc4_audio_format *fmt;
1604+
u32 rate, channels, valid_bits;
1605+
int i;
1606+
1607+
fmt = &pin_fmts[0].audio_fmt;
1608+
rate = fmt->sampling_frequency;
1609+
channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
1610+
valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
1611+
1612+
/* check if parameters in topology defined formats are the same */
1613+
for (i = 1; i < pin_fmts_size; i++) {
1614+
u32 val;
1615+
1616+
fmt = &pin_fmts[i].audio_fmt;
1617+
1618+
if (params_mask & BIT(SNDRV_PCM_HW_PARAM_RATE)) {
1619+
val = fmt->sampling_frequency;
1620+
if (val != rate)
1621+
params_mask &= ~BIT(SNDRV_PCM_HW_PARAM_RATE);
1622+
}
1623+
if (params_mask & BIT(SNDRV_PCM_HW_PARAM_CHANNELS)) {
1624+
val = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
1625+
if (val != channels)
1626+
params_mask &= ~BIT(SNDRV_PCM_HW_PARAM_CHANNELS);
1627+
}
1628+
if (params_mask & BIT(SNDRV_PCM_HW_PARAM_FORMAT)) {
1629+
val = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
1630+
if (val != valid_bits)
1631+
params_mask &= ~BIT(SNDRV_PCM_HW_PARAM_FORMAT);
1632+
}
1633+
}
1634+
1635+
if (params_mask)
1636+
return sof_ipc4_update_hw_params(sdev, params,
1637+
&pin_fmts[0].audio_fmt,
1638+
params_mask);
1639+
1640+
return 0;
1641+
}
1642+
15741643
static int
15751644
sof_ipc4_prepare_dai_copier(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
15761645
struct snd_pcm_hw_params *params, int dir)
15771646
{
15781647
struct sof_ipc4_available_audio_format *available_fmt;
15791648
struct snd_pcm_hw_params dai_params = *params;
15801649
struct sof_ipc4_copier_data *copier_data;
1650+
struct sof_ipc4_pin_format *pin_fmts;
15811651
struct sof_ipc4_copier *ipc4_copier;
1582-
bool single_format;
1652+
bool single_bitdepth;
1653+
u32 num_pin_fmts;
15831654
int ret;
15841655

15851656
ipc4_copier = dai->private;
15861657
copier_data = &ipc4_copier->data;
15871658
available_fmt = &ipc4_copier->available_fmt;
15881659

15891660
/*
1590-
* If the copier on the DAI side supports only single bit depth then
1591-
* this depth (format) should be used to look for the NHLT blob (if
1592-
* needed) and in case of capture this should be used for the input
1593-
* format lookup
1661+
* Fixup the params based on the format parameters of the DAI. If any
1662+
* of the RATE, CHANNELS, bit depth is static among the formats then
1663+
* narrow the params to only allow that specific parameter value.
15941664
*/
15951665
if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
1596-
single_format = sof_ipc4_copier_is_single_format(sdev,
1597-
available_fmt->output_pin_fmts,
1598-
available_fmt->num_output_formats);
1599-
1600-
/* Update the dai_params with the only supported format */
1601-
if (single_format) {
1602-
ret = sof_ipc4_update_hw_params(sdev, &dai_params,
1603-
&available_fmt->output_pin_fmts[0].audio_fmt,
1604-
BIT(SNDRV_PCM_HW_PARAM_FORMAT));
1605-
if (ret)
1606-
return ret;
1607-
}
1666+
pin_fmts = available_fmt->output_pin_fmts;
1667+
num_pin_fmts = available_fmt->num_output_formats;
16081668
} else {
1609-
single_format = sof_ipc4_copier_is_single_format(sdev,
1610-
available_fmt->input_pin_fmts,
1611-
available_fmt->num_input_formats);
1612-
1613-
/* Update the dai_params with the only supported format */
1614-
if (single_format) {
1615-
ret = sof_ipc4_update_hw_params(sdev, &dai_params,
1616-
&available_fmt->input_pin_fmts[0].audio_fmt,
1617-
BIT(SNDRV_PCM_HW_PARAM_FORMAT));
1618-
if (ret)
1619-
return ret;
1620-
}
1669+
pin_fmts = available_fmt->input_pin_fmts;
1670+
num_pin_fmts = available_fmt->num_input_formats;
16211671
}
16221672

1623-
ret = snd_sof_get_nhlt_endpoint_data(sdev, dai, single_format,
1673+
ret = sof_ipc4_adjust_params_to_dai_format(sdev, &dai_params, pin_fmts,
1674+
num_pin_fmts);
1675+
if (ret)
1676+
return ret;
1677+
1678+
single_bitdepth = sof_ipc4_copier_is_single_bitdepth(sdev, pin_fmts,
1679+
num_pin_fmts);
1680+
ret = snd_sof_get_nhlt_endpoint_data(sdev, dai, single_bitdepth,
16241681
&dai_params,
16251682
ipc4_copier->dai_index,
16261683
ipc4_copier->dai_type, dir,
@@ -1655,7 +1712,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
16551712
u32 out_ref_rate, out_ref_channels;
16561713
u32 deep_buffer_dma_ms = 0;
16571714
int output_fmt_index;
1658-
bool single_output_format;
1715+
bool single_output_bitdepth;
16591716
int i;
16601717

16611718
dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id);
@@ -1792,9 +1849,9 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
17921849
return ret;
17931850

17941851
/* set the reference params for output format selection */
1795-
single_output_format = sof_ipc4_copier_is_single_format(sdev,
1796-
available_fmt->output_pin_fmts,
1797-
available_fmt->num_output_formats);
1852+
single_output_bitdepth = sof_ipc4_copier_is_single_bitdepth(sdev,
1853+
available_fmt->output_pin_fmts,
1854+
available_fmt->num_output_formats);
17981855
switch (swidget->id) {
17991856
case snd_soc_dapm_aif_in:
18001857
case snd_soc_dapm_dai_out:
@@ -1806,7 +1863,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
18061863
out_ref_rate = in_fmt->sampling_frequency;
18071864
out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
18081865

1809-
if (!single_output_format)
1866+
if (!single_output_bitdepth)
18101867
out_ref_valid_bits =
18111868
SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
18121869
break;
@@ -1815,7 +1872,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
18151872
case snd_soc_dapm_dai_in:
18161873
out_ref_rate = params_rate(fe_params);
18171874
out_ref_channels = params_channels(fe_params);
1818-
if (!single_output_format) {
1875+
if (!single_output_bitdepth) {
18191876
out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params);
18201877
if (out_ref_valid_bits < 0)
18211878
return out_ref_valid_bits;
@@ -1833,7 +1890,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
18331890
* if the output format is the same across all available output formats, choose
18341891
* that as the reference.
18351892
*/
1836-
if (single_output_format) {
1893+
if (single_output_bitdepth) {
18371894
struct sof_ipc4_audio_format *out_fmt;
18381895

18391896
out_fmt = &available_fmt->output_pin_fmts[0].audio_fmt;

sound/soc/sof/ipc4-topology.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,7 @@ struct sof_ipc4_process {
476476
u32 init_config;
477477
};
478478

479-
bool sof_ipc4_copier_is_single_format(struct snd_sof_dev *sdev,
480-
struct sof_ipc4_pin_format *pin_fmts,
481-
u32 pin_fmts_size);
479+
bool sof_ipc4_copier_is_single_bitdepth(struct snd_sof_dev *sdev,
480+
struct sof_ipc4_pin_format *pin_fmts,
481+
u32 pin_fmts_size);
482482
#endif

0 commit comments

Comments
 (0)