diff mbox series

[1/1] ALSA: hda: cs35l41: Dell Fiorano add missing _DSD properties

Message ID 20231212195243.10666-1-alex.vinarskis@gmail.com (mailing list archive)
State New, archived
Headers show
Series [1/1] ALSA: hda: cs35l41: Dell Fiorano add missing _DSD properties | expand

Commit Message

Aleksandrs Vinarskis Dec. 12, 2023, 7:52 p.m. UTC
Dell XPS 9530 (2023) has two SPI connected CS35L41 amplifiers, however
is missing _DSD properties, cs-gpios and has a firmware bug which caps SPI
controller's speed to unusable 3051Hz. This patch adds _DSD properties and
sets second cs-gpio. In case SPI speed bug is detected, it will not
initialize the device to avoid hangs on wake up.

Resolution of SPI speed bug requires either a patch to `intel-lpss.c` or an
UEFI update with corrected values from Dell. Tested with locally applied
patch to `intel-lpss` on multiple XPS 9530 devices.

Co-developed-by: Jasper Smet <josbeir@gmail.com>
Signed-off-by: Jasper Smet <josbeir@gmail.com>
Signed-off-by: Aleksandrs Vinarskis <alex.vinarskis@gmail.com>
---
 sound/pci/hda/cs35l41_hda_property.c | 47 ++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

Comments

Stuart Henderson Dec. 14, 2023, 3:39 p.m. UTC | #1
On 14/12/2023 11:02, Takashi Iwai wrote:
> On Tue, 12 Dec 2023 20:52:43 +0100,
> Aleksandrs Vinarskis wrote:
>> Dell XPS 9530 (2023) has two SPI connected CS35L41 amplifiers, however
>> is missing _DSD properties, cs-gpios and has a firmware bug which caps SPI
>> controller's speed to unusable 3051Hz. This patch adds _DSD properties and
>> sets second cs-gpio. In case SPI speed bug is detected, it will not
>> initialize the device to avoid hangs on wake up.
>>
>> Resolution of SPI speed bug requires either a patch to `intel-lpss.c` or an
>> UEFI update with corrected values from Dell. Tested with locally applied
>> patch to `intel-lpss` on multiple XPS 9530 devices.
>>
>> Co-developed-by: Jasper Smet <josbeir@gmail.com>
>> Signed-off-by: Jasper Smet <josbeir@gmail.com>
>> Signed-off-by: Aleksandrs Vinarskis <alex.vinarskis@gmail.com>
> Can Cirrus team review this?
>
>
> thanks,
>
> Takashi

The patch looks sensible, with some minor comments below, however we're 
just at the tail end of testing a patch chain that genericises a lot of 
this code and adds support for a rather large batch of other laptops 
with incomplete DSD.  We're hoping to push this upstream on Monday.

Can I be awkward and ask that we hold off on this patch chain until 
then?  Then we can add this laptop using the new approach.

If/when the chain is accepted, we will add support for a few Dell 
laptops as well, including this one.

>> ---
>>   sound/pci/hda/cs35l41_hda_property.c | 47 ++++++++++++++++++++++++++++
>>   1 file changed, 47 insertions(+)
>>
>> diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c
>> index c83328971728..69446a794397 100644
>> --- a/sound/pci/hda/cs35l41_hda_property.c
>> +++ b/sound/pci/hda/cs35l41_hda_property.c
>> @@ -7,9 +7,55 @@
>>   // Author: Stefan Binding <sbinding@opensource.cirrus.com>
>>   
>>   #include <linux/gpio/consumer.h>
>> +#include <linux/spi/spi.h>
>>   #include <linux/string.h>
>>   #include "cs35l41_hda_property.h"
>>   
>> +/*
>> + * Device 10280BEB (Dell XPS 9530) doesn't have _DSD at all. Moreover, pin that is typically
>> + * used for `speaker_id` is missing. SPI's cs-gpios definitions are also missing.
>> + */
>> +static int dell_fiorano_no_acpi(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
>> +				const char *hid)
>> +{
>> +	struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
>> +	struct spi_device *spi = to_spi_device(cs35l41->dev);
>> +
>> +	/*
>> +	 * 10280BEB has a firmware bug, which wrongly enables clock divider for intel-lpss
>> +	 * Resultant SPI clock is 100Mhz/32767=3051Hz, which leads to ~3 minute hang on boot/wake up
>> +	 * Avoid initializing device if lpss was not patched/fixed UEFI was not installed
>> +	 */
>> +	if (spi->max_speed_hz < CS35L41_SPI_MAX_FREQ) {
>> +		dev_err(cs35l41->dev, "SPI's max_speed_hz is capped at %u Hz, will not continue to avoid hanging\n",
>> +			spi->max_speed_hz);
>> +		return -EINVAL;
>> +	}

Instead of erroring out, I wonder if we can noodle our way to the 
appropriate clk and clk_set_rate it up to 4MHz for this particular 
laptop only?  Stefan's taking a look at that.

Also, any SPI rate >~100k is probably just about usable, so we don't 
want to error on <4MHz.  Quite often the spi clock is set at some value 
just below 4MHz.  It's unclear if this is going to get fixed in the BIOS 
at this point, so we don't know what exact rate we'd eventually receive.

>> +
>> +	dev_info(cs35l41->dev, "Adding DSD properties for %s\n", cs35l41->acpi_subsystem_id);
>> +
>> +	/* check SPI address to assign the index */
>> +	cs35l41->index = id;
>> +	cs35l41->channel_index = 0;
>> +	/* 10280BEB is missing pin which is typically assigned to `spk-id-gpios` */
>> +	cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, cs35l41->index, 2, -1);
>> +	cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 1, GPIOD_OUT_LOW);
>> +
>> +	hw_cfg->spk_pos = cs35l41->index  ? 1 : 0;	// 0th L, 1st R
>> +	hw_cfg->bst_type = CS35L41_EXT_BOOST;
>> +	hw_cfg->gpio1.func = CS35l41_VSPK_SWITCH;
>> +	hw_cfg->gpio1.valid = true;
>> +	hw_cfg->gpio2.func = CS35L41_INTERRUPT;
>> +	hw_cfg->gpio2.valid = true;
>> +	hw_cfg->valid = true;
>> +
>> +	/* Add second cs-gpio here */
>> +	if (cs35l41->index)
>> +		spi->cs_gpiod = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH);
This will break once you pick up AMD's multi-cs patches, we should use 
spi_set_csgpiod instead.
>> +
>> +	return 0;
>> +}
>> +
>>   /*
>>    * Device CLSA010(0/1) doesn't have _DSD so a gpiod_get by the label reset won't work.
>>    * And devices created by serial-multi-instantiate don't have their device struct
>> @@ -92,6 +138,7 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = {
>>   	{ "CLSA0100", NULL, lenovo_legion_no_acpi },
>>   	{ "CLSA0101", NULL, lenovo_legion_no_acpi },
>>   	{ "CSC3551", "103C89C6", hp_vision_acpi_fix },
>> +	{ "CSC3551", "10280BEB", dell_fiorano_no_acpi },
>>   	{}
>>   };
>>   
>> -- 
>> 2.40.1
>>
Takashi Iwai Dec. 14, 2023, 3:49 p.m. UTC | #2
On Thu, 14 Dec 2023 16:39:58 +0100,
Stuart Henderson wrote:
> 
> 
> On 14/12/2023 11:02, Takashi Iwai wrote:
> > On Tue, 12 Dec 2023 20:52:43 +0100,
> > Aleksandrs Vinarskis wrote:
> >> Dell XPS 9530 (2023) has two SPI connected CS35L41 amplifiers, however
> >> is missing _DSD properties, cs-gpios and has a firmware bug which caps SPI
> >> controller's speed to unusable 3051Hz. This patch adds _DSD properties and
> >> sets second cs-gpio. In case SPI speed bug is detected, it will not
> >> initialize the device to avoid hangs on wake up.
> >> 
> >> Resolution of SPI speed bug requires either a patch to `intel-lpss.c` or an
> >> UEFI update with corrected values from Dell. Tested with locally applied
> >> patch to `intel-lpss` on multiple XPS 9530 devices.
> >> 
> >> Co-developed-by: Jasper Smet <josbeir@gmail.com>
> >> Signed-off-by: Jasper Smet <josbeir@gmail.com>
> >> Signed-off-by: Aleksandrs Vinarskis <alex.vinarskis@gmail.com>
> > Can Cirrus team review this?
> > 
> > 
> > thanks,
> > 
> > Takashi
> 
> The patch looks sensible, with some minor comments below, however
> we're just at the tail end of testing a patch chain that genericises a
> lot of this code and adds support for a rather large batch of other
> laptops with incomplete DSD.  We're hoping to push this upstream on
> Monday.
> 
> Can I be awkward and ask that we hold off on this patch chain until
> then?  Then we can add this laptop using the new approach.
> 
> If/when the chain is accepted, we will add support for a few Dell
> laptops as well, including this one.

It's fine to wait for a while for me.
Hopefully we can make it in 6.7, and we can catch up in the next
week.

(BTW, I'll be off from the next Tuesday, and the reply will be
delayed, but I can eventually check and merge patches remotely :)

> >> ---
> >>   sound/pci/hda/cs35l41_hda_property.c | 47 ++++++++++++++++++++++++++++
> >>   1 file changed, 47 insertions(+)
> >> 
> >> diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c
> >> index c83328971728..69446a794397 100644
> >> --- a/sound/pci/hda/cs35l41_hda_property.c
> >> +++ b/sound/pci/hda/cs35l41_hda_property.c
> >> @@ -7,9 +7,55 @@
> >>   // Author: Stefan Binding <sbinding@opensource.cirrus.com>
> >>     #include <linux/gpio/consumer.h>
> >> +#include <linux/spi/spi.h>
> >>   #include <linux/string.h>
> >>   #include "cs35l41_hda_property.h"
> >>   +/*
> >> + * Device 10280BEB (Dell XPS 9530) doesn't have _DSD at all. Moreover, pin that is typically
> >> + * used for `speaker_id` is missing. SPI's cs-gpios definitions are also missing.
> >> + */
> >> +static int dell_fiorano_no_acpi(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
> >> +				const char *hid)
> >> +{
> >> +	struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
> >> +	struct spi_device *spi = to_spi_device(cs35l41->dev);
> >> +
> >> +	/*
> >> +	 * 10280BEB has a firmware bug, which wrongly enables clock divider for intel-lpss
> >> +	 * Resultant SPI clock is 100Mhz/32767=3051Hz, which leads to ~3 minute hang on boot/wake up
> >> +	 * Avoid initializing device if lpss was not patched/fixed UEFI was not installed
> >> +	 */
> >> +	if (spi->max_speed_hz < CS35L41_SPI_MAX_FREQ) {
> >> +		dev_err(cs35l41->dev, "SPI's max_speed_hz is capped at %u Hz, will not continue to avoid hanging\n",
> >> +			spi->max_speed_hz);
> >> +		return -EINVAL;
> >> +	}
> 
> Instead of erroring out, I wonder if we can noodle our way to the
> appropriate clk and clk_set_rate it up to 4MHz for this particular
> laptop only?  Stefan's taking a look at that.
> 
> Also, any SPI rate >~100k is probably just about usable, so we don't
> want to error on <4MHz.  Quite often the spi clock is set at some
> value just below 4MHz.  It's unclear if this is going to get fixed in
> the BIOS at this point, so we don't know what exact rate we'd
> eventually receive.

I suppose the error-out was due to safety reasons, but the clock
adjustment works, it should be fine.  Let's see.

> >> +
> >> +	dev_info(cs35l41->dev, "Adding DSD properties for %s\n", cs35l41->acpi_subsystem_id);
> >> +
> >> +	/* check SPI address to assign the index */
> >> +	cs35l41->index = id;
> >> +	cs35l41->channel_index = 0;
> >> +	/* 10280BEB is missing pin which is typically assigned to `spk-id-gpios` */
> >> +	cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, cs35l41->index, 2, -1);
> >> +	cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 1, GPIOD_OUT_LOW);
> >> +
> >> +	hw_cfg->spk_pos = cs35l41->index  ? 1 : 0;	// 0th L, 1st R
> >> +	hw_cfg->bst_type = CS35L41_EXT_BOOST;
> >> +	hw_cfg->gpio1.func = CS35l41_VSPK_SWITCH;
> >> +	hw_cfg->gpio1.valid = true;
> >> +	hw_cfg->gpio2.func = CS35L41_INTERRUPT;
> >> +	hw_cfg->gpio2.valid = true;
> >> +	hw_cfg->valid = true;
> >> +
> >> +	/* Add second cs-gpio here */
> >> +	if (cs35l41->index)
> >> +		spi->cs_gpiod = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH);
> This will break once you pick up AMD's multi-cs patches, we should use
> spi_set_csgpiod instead.

Thanks, good to know.

I'm looking forward to your revised patches :)


Takashi
Aleksandrs Vinarskis Dec. 14, 2023, 7:36 p.m. UTC | #3
> Can I be awkward and ask that we hold off on this patch chain until
> then?  Then we can add this laptop using the new approach.

> If/when the chain is accepted, we will add support for a few Dell
> laptops as well, including this one.

Sounds reasonable. I'll be looking forward to your new framework.
Once up, I can adjust my patch, and if everything still works as expected,
push updated version for review.

> Instead of erroring out, I wonder if we can noodle our way to the
> appropriate clk and clk_set_rate it up to 4MHz for this particular
> laptop only?  Stefan's taking a look at that.
Thanks for the initiative. Potentially that would work, however, it would
require to go up the clock tree to the divider. Since its clearly a
firmware bug causing lpss miss-configuration, I intially thought it would
be best to have it resolved there. If you need more information, I would be
happy to share results of our debugging with you via private email.

> Also, any SPI rate >~100k is probably just about usable, so we don't
> want to error on <4MHz.  Quite often the spi clock is set at some value
> just below 4MHz.  It's unclear if this is going to get fixed in the BIOS
> at this point, so we don't know what exact rate we'd eventually receive.
I'm afraid I have to disagree here, 100k is _way_ too slow. Not sure
intentionally or not, but wake up from suspend is held back by Cirrus
driver. At 100k, I got these results, on boot:

```
[    5.561244] cs35l41-hda spi1-CSC3551:00-cs35l41-hda.0: Adding DSD properties for 10280BEB
..
[   11.251145] cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: CS35L41 Bound - SSID: 10280BEB, BST: 1, VSPK: 1, CH: R, FW EN: 1, SPKID: -19
```

And on wake-up from suspend:
```
[  307.162720] cs35l41-hda spi1-CSC3551:00-cs35l41-hda.0: DSP1: Firmware version: 3
...
[  312.515588] cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: 100000 Hz actual, DMA
```

This means ~5.5 additional seconds of black screen on wake up, in my opnion
this is completely unacceptable. With 4Mhz, it takes sub 1second. Moreover,
the first time (after preconfigured by ALSA delay) sound is played, it
seems it needs to communicate with amplifier, and it takes additional few
seconds to start playing at 100Khz. With 4Mhz, its practically instant.

I agree that it is unlikely for Dell to ever fix its firmware. Thus either
in case of intel-lpss patch, or via clk_set_rate direclty from Cirrus
driver, lpss divider would be set 1:1, SPI controller would receive 100Mhz
clock directly, and set it to whatever is requested internally (currently
4Mhz). This way, lowest 'usable' rate should be irrelevant.

> Quite often the spi clock is set at some value just below 4MHz
Perhaps to address this, we could error out on say half requested rate? In
reality, it will be either requested rate/just sub requested, or something
totally off, like the default 3051Hz in this case.

> This will break once you pick up AMD's multi-cs patches, we should use
> spi_set_csgpiod instead.
Thanks, will correct.

> I suppose the error-out was due to safety reasons, but the clock
> adjustment works, it should be fine.  Let's see.
Precisely, since it is indeed unknown when exaclty/if ever firmware will
be fixed, and/or when our patch to intel-lpss will be accepted.

Regards,
Alex
Andy Shevchenko Dec. 18, 2023, 11:51 a.m. UTC | #4
On Thu, Dec 14, 2023 at 04:49:23PM +0100, Takashi Iwai wrote:
> On Thu, 14 Dec 2023 16:39:58 +0100,
> Stuart Henderson wrote:
> > On 14/12/2023 11:02, Takashi Iwai wrote:
> > > On Tue, 12 Dec 2023 20:52:43 +0100,
> > > Aleksandrs Vinarskis wrote:

...

> > > Can Cirrus team review this?

> > The patch looks sensible, with some minor comments below, however
> > we're just at the tail end of testing a patch chain that genericises a
> > lot of this code and adds support for a rather large batch of other
> > laptops with incomplete DSD.  We're hoping to push this upstream on
> > Monday.
> > 
> > Can I be awkward and ask that we hold off on this patch chain until
> > then?  Then we can add this laptop using the new approach.
> > 
> > If/when the chain is accepted, we will add support for a few Dell
> > laptops as well, including this one.
> 
> It's fine to wait for a while for me.
> Hopefully we can make it in 6.7, and we can catch up in the next
> week.
> 
> (BTW, I'll be off from the next Tuesday, and the reply will be
> delayed, but I can eventually check and merge patches remotely :)

Since v6.7 is going to be an LTS, I think we are eagerly want to have
one or the other to be included. In case Cirrus is slow with their
patch, I would like to see this one being included. Let's make an
xmas/ny gift to all users of this codec!
Stefan Binding Dec. 20, 2023, 1:43 p.m. UTC | #5
Hi,

On 20/12/2023 07:38, Aleksandrs Vinarskis wrote:
> Some devices with intel-lpss based SPI controllers may have misconfigured
> clock divider due to firmware bug. This would result in capped SPI speeds,
> which leads to longer DSP firmware loading times.
> This safety guards against possible hangs during wake-up by not
> initializing the device if lpss was not patched/fixed UEFI was not
> installed
>
> Signed-off-by: Aleksandrs Vinarskis <alex.vinarskis@gmail.com>
> ---
>   sound/pci/hda/cs35l41_hda_property.c | 15 +++++++++++++--
>   1 file changed, 13 insertions(+), 2 deletions(-)
>
> diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c
> index c9eb70290973..cb305b093311 100644
> --- a/sound/pci/hda/cs35l41_hda_property.c
> +++ b/sound/pci/hda/cs35l41_hda_property.c
> @@ -210,6 +210,19 @@ static int generic_dsd_config(struct cs35l41_hda *cs35l41, struct device *physde
>   
>   	if (cfg->bus == SPI) {
>   		cs35l41->index = id;
> +		/*
> +		 * Some devices with intel-lpss based SPI controllers may have misconfigured
> +		 * clock divider due to firmware bug. This would result in capped SPI speeds,
> +		 * which leads to longer DSP firmware loading times.
> +		 * Avoid initializing device if lpss was not patched/fixed UEFI was not installed
> +		 */
> +		spi = to_spi_device(cs35l41->dev);
> +		if (spi->max_speed_hz < CS35L41_SPI_MAX_FREQ/2) {
> +			dev_err(cs35l41->dev,
> +				"SPI's max_speed_hz is capped at %u Hz, will not continue to avoid hanging\n",
> +				spi->max_speed_hz);
> +			return -EINVAL;
> +		}

Not sure I agree with completely disabling the CS35L41 Speaker Driver if 
the SPI speed is low (for laptops without _DSD).
With a slow speed the driver does not hang - it just takes a long time 
(~80s per amp) to load the firmware.
Instead I would prefer that we instead disable the loading of the 
firmware in this case.
Without loading firmware, the volume is much lower, but at least you 
still have audio.
I have a patch to do that, which I was planning on pushing up 
(hopefully) today.

Thanks,

Stefan

>   		/*
>   		 * Manually set the Chip Select for the second amp <cs_gpio_index> in the node.
>   		 * This is only supported for systems with 2 amps, since we cannot expand the
> @@ -219,8 +232,6 @@ static int generic_dsd_config(struct cs35l41_hda *cs35l41, struct device *physde
>   		 * first.
>   		 */
>   		if (cfg->cs_gpio_index >= 0) {
> -			spi = to_spi_device(cs35l41->dev);
> -
>   			if (cfg->num_amps != 2) {
>   				dev_warn(cs35l41->dev,
>   					 "Cannot update SPI CS, Number of Amps (%d) != 2\n",
Stefan Binding Dec. 20, 2023, 1:47 p.m. UTC | #6
Hi,

On 20/12/2023 07:38, Aleksandrs Vinarskis wrote:
> Add new model entries into configuration table.
>
> Co-developed-by: Jasper Smet <josbeir@gmail.com>
> Signed-off-by: Jasper Smet <josbeir@gmail.com>
> Signed-off-by: Aleksandrs Vinarskis <alex.vinarskis@gmail.com>
> ---
>   sound/pci/hda/cs35l41_hda_property.c | 2 ++
>   1 file changed, 2 insertions(+)
>
> diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c
> index cb305b093311..ee105743333f 100644
> --- a/sound/pci/hda/cs35l41_hda_property.c
> +++ b/sound/pci/hda/cs35l41_hda_property.c
> @@ -41,6 +41,7 @@ static const struct cs35l41_config cs35l41_config_table[] = {
>    * Since this laptop has valid ACPI, we do not need to handle cs-gpios, since that already exists
>    * in the ACPI. The Reset GPIO is also valid, so we can use the Reset defined in _DSD.
>    */
> +	{ "10280BEB", SPI, 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 0, 0, 0 },

The configuration is correct, however the comment above it applies to 
the laptop below, so the entry needs to be above the comment.

I was planning on pushing up a patch myself (hopefully today) which 
includes this laptop, as well as a couple of other Dell laptops.
In the same chain is a patch to prevent firmware loading on systems with 
slow SPI speed.

It may be wise to wait for those patches instead.

Thanks,

Stefan

>   	{ "103C89C6", SPI, 2, INTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, 0, 0 }, -1, -1, -1, 1000, 4500, 24 },
>   	{ "104312AF", SPI, 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
>   	{ "10431433", I2C, 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
> @@ -355,6 +356,7 @@ struct cs35l41_prop_model {
>   static const struct cs35l41_prop_model cs35l41_prop_model_table[] = {
>   	{ "CLSA0100", NULL, lenovo_legion_no_acpi },
>   	{ "CLSA0101", NULL, lenovo_legion_no_acpi },
> +	{ "CSC3551", "10280BEB", generic_dsd_config },
>   	{ "CSC3551", "103C89C6", generic_dsd_config },
>   	{ "CSC3551", "104312AF", generic_dsd_config },
>   	{ "CSC3551", "10431433", generic_dsd_config },
Aleksandrs Vinarskis Dec. 21, 2023, 11:24 a.m. UTC | #7
Sorry for incorrect expression and confusion, it is indeed not the driver
that hangs. What I meant is that _computer_ "hangs" on wake up from
suspend. Unlike boot, where driver does not delay boot process, on wake up
from suspend it seems it does - after lid was opened/power button pressed,
with firmware loading taking ~180seconds in total, computer still has
black screen and is irresponsive for said duration, which is completely
unacceptable.

I do not have enough expertise in particular area, but it sounds very weird
to me that audio driver is delaying system wake up process at first place.
Was this intentional? I would assume/guess most correct solution would be
for driver to run non-blocking, like it does on boot, but again, I am not
too familiar with the subject.

> (~80s per amp) to load the firmware.

Besides firmware loading, there are general initialization/communication
taking place as well. I have disabled firmware loading to try: at a speed
of 3051Hz, it takes ~16 seconds on boot (non blocking, so not a big deal)
and ~7-8 seconds on wake up from suspend (blocking, so it is still not
acceptable).

I am myself extremely exited to get support for 9530 in upstream, but I am
just afraid that such a big wake up delay is a huge hit on a end user, and
would affect everyone with 9530 where intel-lpss patch was not applied yet.

> Instead I would prefer that we instead disable the loading of the 
> firmware in this case.
> Without loading firmware, the volume is much lower, but at least you 
> still have audio.

This indeed sounds like a better approach, I did not think of that. This
should work much better for generic cases, but unfortunately, will still
not prevent devices with _extremely_ slow SPI from badly affecting UX

Taking into account the above, and unless driver being blocking on wake up
can be resolved, perhaps it would makes sense to do both?
a) Your suggestion - disable firmware loading if SPI speed is not in MHz
range and
b) Do not initialize device at all, if SPI speed is ridiculously low (like
for example 3051 Hz)?

I have tested on 9530 without firmware loading, with SPI speed set to
50000Hz: it delays wake up by ~0.9-1 seconds. Subjectively, I think this is
the maximum acceptable delay.

> I have a patch to do that, which I was planning on pushing up 
> (hopefully) today.

Thanks for following up on this!

> 
> Thanks,
> 
> Stefan
> 
> >   		/*
> >   		 * Manually set the Chip Select for the second amp <cs_gpio_index> in the node.
> >   		 * This is only supported for systems with 2 amps, since we cannot expand the
> > @@ -219,8 +232,6 @@ static int generic_dsd_config(struct cs35l41_hda *cs35l41, struct device *physde
> >   		 * first.
> >   		 */
> >   		if (cfg->cs_gpio_index >= 0) {
> > -			spi = to_spi_device(cs35l41->dev);
> > -
> >   			if (cfg->num_amps != 2) {
> >   				dev_warn(cs35l41->dev,
> >   					 "Cannot update SPI CS, Number of Amps (%d) != 2\n",

FYI intel-lpss patch was submitted for review [1]. However, as it is in
different tree, it cannot be guaranteed that it will be always applied
when your patch for 9530 and other Dell devices will be applied, which is
why I am insisting on safety guard against _extremely_ low SPI speeds.

[1]: https://lore.kernel.org/all/20231220205621.8575-1-alex.vinarskis@gmail.com/
Stefan Binding Dec. 21, 2023, 3:09 p.m. UTC | #8
Hi,

> -----Original Message-----
> From: Aleksandrs Vinarskis <alex.vinarskis@gmail.com>
> Sent: Thursday, December 21, 2023 11:25 AM
> To: sbinding@opensource.cirrus.com
> Cc: alex.vinarskis@gmail.com; alsa-devel@alsa-project.org;
> david.rhodes@cirrus.com; james.schulman@cirrus.com;
> josbeir@gmail.com; linux-kernel@vger.kernel.org;
> patches@opensource.cirrus.com; perex@perex.cz;
> stuarth@opensource.cirrus.com; tiwai@suse.com; tiwai@suse.de
> Subject: Re: [PATCH v2 1/2] ALSA: hda: cs35l41: Safety-guard against
> capped SPI speed
> 
> Sorry for incorrect expression and confusion, it is indeed not the
driver
> that hangs. What I meant is that _computer_ "hangs" on wake up from
> suspend. Unlike boot, where driver does not delay boot process, on
wake
> up
> from suspend it seems it does - after lid was opened/power button
> pressed,
> with firmware loading taking ~180seconds in total, computer still
has
> black screen and is irresponsive for said duration, which is
completely
> unacceptable.
> 
> I do not have enough expertise in particular area, but it sounds
very weird
> to me that audio driver is delaying system wake up process at first
place.
> Was this intentional? I would assume/guess most correct solution
would be
> for driver to run non-blocking, like it does on boot, but again, I
am not
> too familiar with the subject.
> 
> > (~80s per amp) to load the firmware.
> 
> Besides firmware loading, there are general
initialization/communication
> taking place as well. I have disabled firmware loading to try: at a
speed
> of 3051Hz, it takes ~16 seconds on boot (non blocking, so not a big
deal)
> and ~7-8 seconds on wake up from suspend (blocking, so it is still
not
> acceptable).

In my opinion it would be wrong to kill the speaker driver because the
SPI
performance is so poor, even if the cost is an extra ~8s on wake up.
In the case where an extra 8s on wake up is unacceptable, there are
easier
ways to disable the driver without having to modify kernel code, than
if you
had to do the opposite, and re-enable it in code.

Thanks,
Stefan

> 
> I am myself extremely exited to get support for 9530 in upstream,
but I am
> just afraid that such a big wake up delay is a huge hit on a end
user, and
> would affect everyone with 9530 where intel-lpss patch was not
applied
> yet.
> 
> > Instead I would prefer that we instead disable the loading of the
> > firmware in this case.
> > Without loading firmware, the volume is much lower, but at least
you
> > still have audio.
> 
> This indeed sounds like a better approach, I did not think of that.
This
> should work much better for generic cases, but unfortunately, will
still
> not prevent devices with _extremely_ slow SPI from badly affecting
UX
> 
> Taking into account the above, and unless driver being blocking on
wake up
> can be resolved, perhaps it would makes sense to do both?
> a) Your suggestion - disable firmware loading if SPI speed is not in
MHz
> range and
> b) Do not initialize device at all, if SPI speed is ridiculously low
(like
> for example 3051 Hz)?
> 
> I have tested on 9530 without firmware loading, with SPI speed set
to
> 50000Hz: it delays wake up by ~0.9-1 seconds. Subjectively, I think
this is
> the maximum acceptable delay.
> 
> > I have a patch to do that, which I was planning on pushing up
> > (hopefully) today.
> 
> Thanks for following up on this!
> 
> >
> > Thanks,
> >
> > Stefan
> >
> > >   		/*
> > >   		 * Manually set the Chip Select for the second
amp
> <cs_gpio_index> in the node.
> > >   		 * This is only supported for systems with 2
amps, since
> we cannot expand the
> > > @@ -219,8 +232,6 @@ static int generic_dsd_config(struct
> cs35l41_hda *cs35l41, struct device *physde
> > >   		 * first.
> > >   		 */
> > >   		if (cfg->cs_gpio_index >= 0) {
> > > -			spi = to_spi_device(cs35l41->dev);
> > > -
> > >   			if (cfg->num_amps != 2) {
> > >   				dev_warn(cs35l41->dev,
> > >   					 "Cannot update SPI
CS, Number
> of Amps (%d) != 2\n",
> 
> FYI intel-lpss patch was submitted for review [1]. However, as it is
in
> different tree, it cannot be guaranteed that it will be always
applied
> when your patch for 9530 and other Dell devices will be applied,
which is
> why I am insisting on safety guard against _extremely_ low SPI
speeds.
> 
> [1]: https://lore.kernel.org/all/20231220205621.8575-1-
> alex.vinarskis@gmail.com/
diff mbox series

Patch

diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c
index c83328971728..69446a794397 100644
--- a/sound/pci/hda/cs35l41_hda_property.c
+++ b/sound/pci/hda/cs35l41_hda_property.c
@@ -7,9 +7,55 @@ 
 // Author: Stefan Binding <sbinding@opensource.cirrus.com>
 
 #include <linux/gpio/consumer.h>
+#include <linux/spi/spi.h>
 #include <linux/string.h>
 #include "cs35l41_hda_property.h"
 
+/*
+ * Device 10280BEB (Dell XPS 9530) doesn't have _DSD at all. Moreover, pin that is typically
+ * used for `speaker_id` is missing. SPI's cs-gpios definitions are also missing.
+ */
+static int dell_fiorano_no_acpi(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
+				const char *hid)
+{
+	struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
+	struct spi_device *spi = to_spi_device(cs35l41->dev);
+
+	/*
+	 * 10280BEB has a firmware bug, which wrongly enables clock divider for intel-lpss
+	 * Resultant SPI clock is 100Mhz/32767=3051Hz, which leads to ~3 minute hang on boot/wake up
+	 * Avoid initializing device if lpss was not patched/fixed UEFI was not installed
+	 */
+	if (spi->max_speed_hz < CS35L41_SPI_MAX_FREQ) {
+		dev_err(cs35l41->dev, "SPI's max_speed_hz is capped at %u Hz, will not continue to avoid hanging\n",
+			spi->max_speed_hz);
+		return -EINVAL;
+	}
+
+	dev_info(cs35l41->dev, "Adding DSD properties for %s\n", cs35l41->acpi_subsystem_id);
+
+	/* check SPI address to assign the index */
+	cs35l41->index = id;
+	cs35l41->channel_index = 0;
+	/* 10280BEB is missing pin which is typically assigned to `spk-id-gpios` */
+	cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, cs35l41->index, 2, -1);
+	cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 1, GPIOD_OUT_LOW);
+
+	hw_cfg->spk_pos = cs35l41->index  ? 1 : 0;	// 0th L, 1st R
+	hw_cfg->bst_type = CS35L41_EXT_BOOST;
+	hw_cfg->gpio1.func = CS35l41_VSPK_SWITCH;
+	hw_cfg->gpio1.valid = true;
+	hw_cfg->gpio2.func = CS35L41_INTERRUPT;
+	hw_cfg->gpio2.valid = true;
+	hw_cfg->valid = true;
+
+	/* Add second cs-gpio here */
+	if (cs35l41->index)
+		spi->cs_gpiod = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH);
+
+	return 0;
+}
+
 /*
  * Device CLSA010(0/1) doesn't have _DSD so a gpiod_get by the label reset won't work.
  * And devices created by serial-multi-instantiate don't have their device struct
@@ -92,6 +138,7 @@  static const struct cs35l41_prop_model cs35l41_prop_model_table[] = {
 	{ "CLSA0100", NULL, lenovo_legion_no_acpi },
 	{ "CLSA0101", NULL, lenovo_legion_no_acpi },
 	{ "CSC3551", "103C89C6", hp_vision_acpi_fix },
+	{ "CSC3551", "10280BEB", dell_fiorano_no_acpi },
 	{}
 };