-
Notifications
You must be signed in to change notification settings - Fork 133
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ALSA/ASoC: hda: Address format selection limitations and ambiguity #4539
ALSA/ASoC: hda: Address format selection limitations and ambiguity #4539
Conversation
Improve granularity of format selection for S32/U32 formats by adding constants representing 20, 24 and 32 most significant bits. To make it easy for drivers to utilize those constants, introduce snd_pcm_subformat_width() and snd_pcm_hw_params_bps(). While the former is self-explanatory, the latter returns the bit-per-sample value based on format, subformat and msbits characteristics of the provided hw_params. Signed-off-by: Cezary Rojewski <[email protected]>
Substream value is currently hardcoded to SNDRV_PCM_SUBFORMAT_STD. Update the constraint procedure so that subformat selection is not ignored. Signed-off-by: Cezary Rojewski <[email protected]>
Update mechanism for querying supported PCMs to allow for granular format selection when container size is 32 bits. Currently always the highest bit depth is selected, regardless of how many actual formats codec in question supports. Signed-off-by: Cezary Rojewski <[email protected]>
Subformat options are ignored when setting up hardware parameters and assigning PCM stream capabilities. Account for them to allow for granular format selection. Signed-off-by: Cezary Rojewski <[email protected]>
Introduce a set of functions that facilite SDxFMT-related calculations in atomic manner: snd_hdac_format_normalize() - format converter. S20_LE, S24_LE and their unsigned and BE friends are invalid from HDAudio perspective but still can be specified as function argument due to compatibility reasons. snd_hdac_stream_format_bps() - obtain just the bits-per-sample value. Does not ignore subformat and msbits parameters. snd_hdac_stream_format() and snd_hdac_spdif_stream_format() - obtain the SDxFMT value given the audio format parameters. The former is stripped away of spdif-related information. Useful for users that do not care about them. Signed-off-by: Cezary Rojewski <[email protected]>
To provide option for selecting different bit-per-sample than just the maximum one, use the new format calculation mechanism. Signed-off-by: Cezary Rojewski <[email protected]>
To provide option for selecting different bit-per-sample than just the maximum one, use the new format calculation mechanism. Signed-off-by: Cezary Rojewski <[email protected]>
To provide option for selecting different bit-per-sample than just the maximum one, use the new format calculation mechanism. Signed-off-by: Cezary Rojewski <[email protected]>
To provide option for selecting different bit-per-sample than just the maximum one, use the new format calculation mechanism. While at it, complete PCM stream initialization with subformat options. Signed-off-by: Cezary Rojewski <[email protected]>
To provide option for selecting different bit-per-sample than just the maximum one, use the new format calculation mechanism. Signed-off-by: Cezary Rojewski <[email protected]>
To provide option for selecting different bit-per-sample than just the maximum one, use the new format calculation mechanism. Signed-off-by: Cezary Rojewski <[email protected]>
To provide option for selecting different bit-per-sample than just the maximum one, use the new format calculation mechanism. Signed-off-by: Cezary Rojewski <[email protected]>
To provide option for selecting different bit-per-sample than just the maximum one, use the new format calculation mechanism. Signed-off-by: Cezary Rojewski <[email protected]>
To provide option for selecting different bit-per-sample than just the maximum one, use the new format calculation mechanism. Signed-off-by: Cezary Rojewski <[email protected]>
There are no users of the function. Signed-off-by: Cezary Rojewski <[email protected]>
Eliminate all occurrences of S24_LE within the HDAudio related pcm code, both HOST and LINK side. Replace those with MSBITS subformats to allow for granular selection when S32_LE is the format of choice. Signed-off-by: Cezary Rojewski <[email protected]>
To not expose more than in fact is supported by the codec, update CPU DAI initialization procedure to rely on codec capabilities instead of hardcoding them. This includes subformat which is currently ignored. As capabilities for HDMI streams are initialized on PCM open, leave it as is for now. Signed-off-by: Cezary Rojewski <[email protected]>
format_val = snd_hdac_calc_stream_format(params_rate(params), params_channels(params), | ||
params_format(params), | ||
params_physical_width(params), | ||
0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there will be a minor conflict with 255f5af, but easy enough to resolve.
I see some timeouts in suspend/resume scenarios and even a panic in check-kmod-load-unload-after-playback case on GML but I fail to find a connection between my patchset and the negative results. |
https://sof-ci.01.org/linuxpr/PR4539/build6261/devicetest/index.html?model=GLK_BOB_DA7219&testcase=check-kmod-load-unload-after-playback is a known issue with the codec driver. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also notice the mismatch of S24_LE and HDA spec and we do some effort to deal with it in SOF FW. I am glad to remove S24_LE from pcm capability and will make life easier for FW developer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@crojewsk-intel, can you explain why the existing msbits support is not good enough when paired with S32_LE?
S32_LE + msbits=24 == 24 bits audio in 32bit
S32_LE + msbits=20 == 20 bits audio in 32bit
S32_LE + msbits=0/32 == 32 bits audio
@@ -2634,8 +2636,7 @@ static int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream) | |||
if (err < 0) | |||
return err; | |||
|
|||
err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_SUBFORMAT, | |||
PARAM_MASK_BIT(SNDRV_PCM_SUBFORMAT_STD)); | |||
err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_SUBFORMAT, hw->subformats); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
snd_pcm_hw_constraint_mask64() ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ack.
@@ -2614,6 +2614,8 @@ static int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream) | |||
int err; | |||
unsigned int mask = 0; | |||
|
|||
/* All PCMs support at least the default STD subformat. */ | |||
hw->subformats |= PARAM_MASK_BIT(SNDRV_PCM_SUBFORMAT_STD); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no definition of SNDRV_PCM_SUBFORMAT_STD that I can find, but it looks to me that it is there to not fail when setting the mask?
SNDRV_PCM_SUBFORMAT_STD does not cover any supported subformat, it is just BIT(0) and to keep snd_pcm_hw_constraint_mask() not to fail few lines down?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
STD is the default and expected to be always supported by any device. So, when adding new flags I had to OR it here to avoid breaking audio for most of the world.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on the upstream discussion, the SNDRV_PCM_SUBFORMAT_STD tells that the whole physical width is used?
But how that maps with S24_LE for example?
I would expect that drivers would set explicit subformats if they care and they might say that I'm not supporting STD and here you override that statement.
if (!hw->subformats)
hw->subformats = PARAM_MASK_BIT(SNDRV_PCM_SUBFORMAT_STD);
might be what should be done here?
@@ -848,8 +849,9 @@ int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid, | |||
*ratesp = rates; | |||
} | |||
|
|||
if (formatsp || bpsp) { | |||
if (formatsp || subformatsp || bpsp) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
commit title is a bit misleading as this patch will not make the code to honor subformat, but it will also querry, set it up based on the hardware.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Honoring a variable from snd_hdac_query_supported_pcm()
point of view is: let it be queryable just like format and bsp are.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For me 'honoring' means that based on the subformat do the right thing, take subformat into account.
"Extend supported format query with subformat support", perhaps better?
* | ||
* Return: The format bitset or zero if invalid. | ||
*/ | ||
unsigned int snd_hdac_spdif_stream_format(unsigned int channels, unsigned int bps, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The 'spdif' in function name implies that it is for SPDIF format type, but it is not..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly to how things are right now. The goal for the split is different - most users call stream-format calculation routine with '0' (ignore) as last parameter. Having two variants - one for those that do not care about spdif bits and one for those that do care - makes things clear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this is to be used in place of snd_hdac_calc_stream_format()
? It is doing the same thing at the end.
snd_hdac_calc_stream_format(params_rate(params), params_channels(params), params_format(params), maxbps, 0);
snd_hdac_spdif_stream_format(params_channels(params), snd_pcm_hw_params_bps(params), params_rate(params), 0);
ctls); | ||
bps = snd_hdac_stream_format_bps(runtime->format, SNDRV_PCM_SUBFORMAT_STD, hinfo->maxbps); | ||
|
||
format_val = snd_hdac_spdif_stream_format(runtime->channels, bps, runtime->rate, ctls); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what the commit message trying to tell. Is it valid to select smaller bps than what required for the format?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's the case even now - set msbits/sigbits to 24 and select format=S16_LE.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand how this achieves the goal set by the commit message. It is switching to a new set of function calls to get the format_val, right?
No change in functionality, or am I missing something?
format = snd_hdac_calc_stream_format(params_rate(hparams), | ||
params_channels(hparams), params_format(hparams), | ||
dai->driver->playback.sig_bits, 0); | ||
bps = snd_hdac_stream_format_bps(params_format(hparams), SNDRV_PCM_SUBFORMAT_STD, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why with the fixed subformat and not the params_subformat() ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto as for hda_controller.c case.
@@ -138,8 +139,8 @@ int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params) | |||
stream = stream_to_hdac_ext_stream(hstream); | |||
snd_hdac_ext_stream_decouple(bus, stream, true); | |||
|
|||
format_val = snd_hdac_calc_stream_format(params->s_freq, | |||
params->ch, params->format, params->host_bps, 0); | |||
bps = snd_hdac_stream_format_bps(params->format, SNDRV_PCM_SUBFORMAT_STD, params->host_bps); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here as well. I beginning to think that I'm missing something fundamental now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
}, | ||
.capture = { | ||
.channels_min = 1, | ||
.channels_max = 8, | ||
.rates = SNDRV_PCM_RATE_8000_192000, | ||
.formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
SNDRV_PCM_FMTBIT_S24_LE | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would not just this change could resolve the unsupported S24_LE advertised to userspace?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Such change alone is insufficient. It blocks usage of S24_LE yes, but simultaneously does not allow for selecting 20, 24 or 32 as valid bit depth.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is blocking the use of msbits?
Yes, we can only say for example that msbits=32 and have no information that the setup actually supports msbits=24, right?
I mean, should the SNDRV_PCM_SUBFMTBIT_MSBITS_24 be more specific, like SNDRV_PCM_SUBFMTBIT_24_MSBITS_IN_32?
If we really want it to be part of this struct snd_soc_pcm_stream
or should we have this as refine information for user space that with S32_LE it could use 20, 24 MSB or 24, 32 MSB and let it deal with it?
With all due respect, I'd like to avoid duplicating the upstream discussion. The exact same question has been asked by Pierre [1]. If you feel more answers are needed, host the questions there. [1]: https://lore.kernel.org/alsa-devel/[email protected]/T/#m66d83b7a47cd1277a4081416b3ec75b4c70ac93d |
* Return: The number of bits per sample based on the format, | ||
* subformat and msbits the specified hw params has. | ||
*/ | ||
int snd_pcm_hw_params_bps(const struct snd_pcm_hw_params *p) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to update the params_width()
so all drivers will get to support the subformat out of box?
@@ -2614,6 +2614,8 @@ static int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream) | |||
int err; | |||
unsigned int mask = 0; | |||
|
|||
/* All PCMs support at least the default STD subformat. */ | |||
hw->subformats |= PARAM_MASK_BIT(SNDRV_PCM_SUBFORMAT_STD); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on the upstream discussion, the SNDRV_PCM_SUBFORMAT_STD tells that the whole physical width is used?
But how that maps with S24_LE for example?
I would expect that drivers would set explicit subformats if they care and they might say that I'm not supporting STD and here you override that statement.
if (!hw->subformats)
hw->subformats = PARAM_MASK_BIT(SNDRV_PCM_SUBFORMAT_STD);
might be what should be done here?
@@ -848,8 +849,9 @@ int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid, | |||
*ratesp = rates; | |||
} | |||
|
|||
if (formatsp || bpsp) { | |||
if (formatsp || subformatsp || bpsp) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For me 'honoring' means that based on the subformat do the right thing, take subformat into account.
"Extend supported format query with subformat support", perhaps better?
* | ||
* Return: The format bitset or zero if invalid. | ||
*/ | ||
unsigned int snd_hdac_spdif_stream_format(unsigned int channels, unsigned int bps, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this is to be used in place of snd_hdac_calc_stream_format()
? It is doing the same thing at the end.
snd_hdac_calc_stream_format(params_rate(params), params_channels(params), params_format(params), maxbps, 0);
snd_hdac_spdif_stream_format(params_channels(params), snd_pcm_hw_params_bps(params), params_rate(params), 0);
ctls); | ||
bps = snd_hdac_stream_format_bps(runtime->format, SNDRV_PCM_SUBFORMAT_STD, hinfo->maxbps); | ||
|
||
format_val = snd_hdac_spdif_stream_format(runtime->channels, bps, runtime->rate, ctls); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand how this achieves the goal set by the commit message. It is switching to a new set of function calls to get the format_val, right?
No change in functionality, or am I missing something?
runtime->format, | ||
hinfo->maxbps, | ||
ctls); | ||
bps = snd_hdac_stream_format_bps(runtime->format, SNDRV_PCM_SUBFORMAT_STD, hinfo->maxbps); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, so this is basically a no functional change to switch function calls to get the format_val?
params_format(params), | ||
maxbps, | ||
0); | ||
format_val = snd_hdac_stream_format(params_channels(params), bps, params_rate(params)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
group the snd_hdac_stream_format_bps()
call here, before calling snd_hdac_stream_format()
?
or the other way around
}, | ||
.capture = { | ||
.channels_min = 1, | ||
.channels_max = 8, | ||
.rates = SNDRV_PCM_RATE_8000_192000, | ||
.formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
SNDRV_PCM_FMTBIT_S24_LE | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is blocking the use of msbits?
Yes, we can only say for example that msbits=32 and have no information that the setup actually supports msbits=24, right?
I mean, should the SNDRV_PCM_SUBFMTBIT_MSBITS_24 be more specific, like SNDRV_PCM_SUBFMTBIT_24_MSBITS_IN_32?
If we really want it to be part of this struct snd_soc_pcm_stream
or should we have this as refine information for user space that with S32_LE it could use 20, 24 MSB or 24, 32 MSB and let it deal with it?
The thread has now moved upstream and there's another alternate proposal from @perexg, closing this PR |
This PR is provided for testing purposes so that no regression occurs on sof-driver side and mirrors thread present on upstream. Once tested, PR will be closed.
Patchset aims to address format selection restrictions present currently in the HDAudio library. Formats which we are concerned about are 20 and 24 valid bits per sample within 32 bit depth container. One may identify them as S20_LE and S24_LE except that those, according to comments found in include/uapi/sound/asound.h, are for LSB-aligned scenarios. HDAudio streams expect MSB-aligned data, no matter if we are speaking of HOST (SDxFMT) or LINK (PPLCxFMT) side - chapter 4.5.1 of the public HDAudio specification. In short, S20_LE and S24_LE are invalid options.
Right now, given the implementation of snd_hdac_query_supported_pcm() within sound/hda/hdac_device.c, even if a codec responds with: "I support all possible formats specified within HDAudio specification", there will be no option to open a 20/32 or 24/32 stream. The kernel will force the stream to be opened using the highest available bit depth.
After discussing subject initially with Jaroslav and Takashi, suggestion was made to utilize 'subformat' option to address the problem. The eye-opening discussion begun much earlier though, in 2019 [1].
Paired with PRs for alsa-utils [2] and alsa-lib [3].
Flow of changes:
The very first patch adds MSBITS subformat options to allow for granular
20/32, 24/32 and 32/32 format selection. The next three make sure
subformat is actually honored during runtime. Most of that code is based
on format-related API.
Follow up is upgrade to the hda stream-format interface - several functions are added to make the granular format selection simple in the HDAudio world. Core of the implementation is based on the existing snd_hdac_calc_stream_format(). The next ten patches are straightforward switch from one interface to another with cleanup of now-unsed function as a finishing touch.
Last but not least - the avs-driver, on which the problem analyzed and debugged, is updated to no longer acknowledge S24_LE as a valid format option.
Changes in v1:
[1]: https://lore.kernel.org/alsa-devel/[email protected]/
[2]: alsa-project/alsa-utils#228
[3]: alsa-project/alsa-lib#342