Skip to content

Commit f283219

Browse files
committed
ASoC: SOF: Intel: HDA/DMIC updates
Merge series from Pierre-Louis Bossart <[email protected]>: The first patch handles a problematic configuration where the wrong machine driver/topology is used: when the hardware reports an external HDaudio codec the direction is to ignore/discard ACPI SoundWire devices. The last two patch deal with DMIC format configurations and allow users to select S16_LE even if the DMIC and internal copiers only support 24 or 32-bits. The code changes are located in sound/soc/sof/ but in the scope of Intel DAIs.
2 parents 1ae14f3 + f920964 commit f283219

File tree

3 files changed

+196
-60
lines changed

3 files changed

+196
-60
lines changed

sound/soc/sof/intel/hda.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1809,6 +1809,7 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
18091809
u32 interface_mask = hda_get_interface_mask(sdev);
18101810
struct snd_sof_pdata *sof_pdata = sdev->pdata;
18111811
const struct sof_dev_desc *desc = sof_pdata->desc;
1812+
struct hdac_bus *bus = sof_to_bus(sdev);
18121813
struct snd_soc_acpi_mach *mach = NULL;
18131814
enum snd_soc_acpi_intel_codec codec_type;
18141815
const char *tplg_filename;
@@ -1981,8 +1982,12 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
19811982
}
19821983
}
19831984

1984-
/* If I2S fails, try SoundWire if it is supported */
1985-
if (!mach && (interface_mask & BIT(SOF_DAI_INTEL_ALH)))
1985+
/*
1986+
* If I2S fails and no external HDaudio codec is detected,
1987+
* try SoundWire if it is supported
1988+
*/
1989+
if (!mach && !HDA_EXT_CODEC(bus->codec_mask) &&
1990+
(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
19861991
mach = hda_sdw_machine_select(sdev);
19871992

19881993
/*

sound/soc/sof/intel/hda.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,8 @@
454454
#define SSP_SET_SFRM_CONSUMER BIT(24)
455455
#define SSP_SET_CBP_CFP (SSP_SET_SCLK_CONSUMER | SSP_SET_SFRM_CONSUMER)
456456

457+
#define HDA_EXT_ADDR 0
458+
#define HDA_EXT_CODEC(x) ((x) & BIT(HDA_EXT_ADDR))
457459
#define HDA_IDISP_ADDR 2
458460
#define HDA_IDISP_CODEC(x) ((x) & BIT(HDA_IDISP_ADDR))
459461

sound/soc/sof/ipc4-topology.c

Lines changed: 187 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -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 */
11211121
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)
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+
15121628
static int
15131629
sof_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

20752200
static 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

Comments
 (0)