* [PATCH] ALSA: hda: intel: reset link for HP ENVY 27-p014
@ 2026-08-28 20:29 Casey Tunturi via B4 Relay
2026-09-01 12:07 ` Takashi Iwai
0 siblings, 1 reply; 3+ messages in thread
From: Casey Tunturi via B4 Relay @ 2026-08-28 20:29 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai; +Cc: linux-sound, linux-kernel, Casey Tunturi
From: Casey Tunturi <casey@samaritansolutions.net>
While bringing up audio on an HP ENVY 27-p014, I found that the normal
link reset only discovers the HDMI codec. The CX20753/4 at address 0
appears after a second CRST pulse, with STATESTS left alone and no fixed
delays.
I added that pulse when address 0 is missing, and again before the codecs
resume. Initial setup uses immediate commands long enough to add the
codec, then returns the controller to CORB/RIRB.
That brought analog audio up at boot, and capture kept working through
four deep suspend and resume cycles.
Signed-off-by: Casey Tunturi <casey@samaritansolutions.net>
---
sound/hda/controllers/intel.c | 77 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 77 insertions(+)
diff --git a/sound/hda/controllers/intel.c b/sound/hda/controllers/intel.c
index 24015c73a..0be97a46f 100644
--- a/sound/hda/controllers/intel.c
+++ b/sound/hda/controllers/intel.c
@@ -987,6 +987,46 @@ static bool azx_is_pm_ready(struct snd_card *card)
return true;
}
+static bool hp_envy_27_needs_reset(struct azx *chip)
+{
+ struct pci_dev *pci = chip->pci;
+
+ return pci->subsystem_vendor == 0x103c &&
+ pci->subsystem_device == 0x2b3e;
+}
+
+static u16 hp_envy_27_reset_link(struct azx *chip)
+{
+ struct hdac_bus *bus = azx_bus(chip);
+ u32 gctl;
+ u16 statests;
+ int timeout;
+
+ snd_hdac_bus_stop_chip(bus);
+
+ gctl = snd_hdac_chip_readl(bus, GCTL);
+ snd_hdac_chip_writel(bus, GCTL, gctl & ~AZX_GCTL_RESET);
+ for (timeout = 250; timeout; timeout--) {
+ if (!(snd_hdac_chip_readl(bus, GCTL) & AZX_GCTL_RESET))
+ break;
+ udelay(1);
+ }
+
+ gctl = snd_hdac_chip_readl(bus, GCTL);
+ snd_hdac_chip_writel(bus, GCTL, gctl | AZX_GCTL_RESET);
+ for (timeout = 250; timeout; timeout--) {
+ if (snd_hdac_chip_readl(bus, GCTL) & AZX_GCTL_RESET)
+ break;
+ udelay(1);
+ }
+
+ statests = snd_hdac_chip_readw(bus, STATESTS);
+ bus->codec_mask |= statests;
+ snd_hdac_bus_init_chip(bus, false);
+
+ return statests;
+}
+
static void __azx_runtime_resume(struct azx *chip)
{
struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
@@ -1003,6 +1043,8 @@ static void __azx_runtime_resume(struct azx *chip)
azx_init_pci(chip);
hda_intel_init_chip(chip, true);
+ if (chip->pm_prepared && hp_envy_27_needs_reset(chip))
+ hp_envy_27_reset_link(chip);
/* Avoid codec resume if runtime resume is for system suspend */
if (!chip->pm_prepared) {
@@ -2356,6 +2398,34 @@ static const unsigned int azx_max_codecs[AZX_NUM_DRIVERS] = {
[AZX_DRIVER_TERA] = 1,
};
+static int hp_envy_27_probe_codec(struct azx *chip)
+{
+ struct hdac_bus *bus = azx_bus(chip);
+ struct hda_codec *codec = NULL;
+ bool use_pio;
+ int probe_mask;
+ int err;
+
+ if (!hp_envy_27_needs_reset(chip) || (bus->codec_mask & BIT(0)))
+ return 0;
+ if (!(hp_envy_27_reset_link(chip) & BIT(0)))
+ return -ENODEV;
+
+ probe_mask = chip->codec_probe_mask;
+ use_pio = bus->use_pio_for_commands;
+ chip->codec_probe_mask = BIT(0);
+ bus->use_pio_for_commands = true;
+ err = snd_hda_codec_new(&chip->bus, chip->card, 0, &codec);
+ chip->codec_probe_mask = probe_mask;
+ if (!err && codec)
+ err = snd_hda_codec_configure(codec);
+ else if (!err)
+ err = -ENODEV;
+ bus->use_pio_for_commands = use_pio;
+
+ return err;
+}
+
static int azx_probe_continue(struct azx *chip)
{
struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
@@ -2428,6 +2498,11 @@ static int azx_probe_continue(struct azx *chip)
}
}
+ err = hp_envy_27_probe_codec(chip);
+ if (err < 0 && err != -ENODEV)
+ dev_warn(chip->card->dev,
+ "failed to probe HP ENVY 27 analog codec: %d\n", err);
+
err = snd_card_register(chip->card);
if (err < 0)
goto out_free;
@@ -2444,6 +2519,8 @@ static int azx_probe_continue(struct azx *chip)
pm_runtime_allow(&pci->dev);
pm_runtime_put_autosuspend(&pci->dev);
}
+ if (hp_envy_27_needs_reset(chip))
+ pm_runtime_forbid(&pci->dev);
out_free:
if (err < 0) {
---
base-commit: c4a0927f535f779700d5ccda8182c2db01e9d551
change-id: 20260828-hp-envy-27-hda-reset-40651087e528
Best regards,
--
Casey Tunturi <casey@samaritansolutions.net>
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] ALSA: hda: intel: reset link for HP ENVY 27-p014
2026-08-28 20:29 [PATCH] ALSA: hda: intel: reset link for HP ENVY 27-p014 Casey Tunturi via B4 Relay
@ 2026-09-01 12:07 ` Takashi Iwai
2026-09-03 17:12 ` Casey Tunturi
0 siblings, 1 reply; 3+ messages in thread
From: Takashi Iwai @ 2026-09-01 12:07 UTC (permalink / raw)
To: casey, Casey Tunturi via B4 Relay
Cc: Jaroslav Kysela, Takashi Iwai, linux-sound, linux-kernel
On Fri, 28 Aug 2026 22:29:28 +0200,
Casey Tunturi via B4 Relay wrote:
>
> From: Casey Tunturi <casey@samaritansolutions.net>
>
> While bringing up audio on an HP ENVY 27-p014, I found that the normal
> link reset only discovers the HDMI codec. The CX20753/4 at address 0
> appears after a second CRST pulse, with STATESTS left alone and no fixed
> delays.
>
> I added that pulse when address 0 is missing, and again before the codecs
> resume. Initial setup uses immediate commands long enough to add the
> codec, then returns the controller to CORB/RIRB.
>
> That brought analog audio up at boot, and capture kept working through
> four deep suspend and resume cycles.
>
> Signed-off-by: Casey Tunturi <casey@samaritansolutions.net>
Thanks for the patch. But I must say that it's very hackish, and
we should reconsider to make the changes a bit more generic or
cleaner.
But, first off, could you give more details about your hardware?
At best, give alsa-info.sh output (run with --no-upload option and
attach the output).
Now more about the code change:
> +static u16 hp_envy_27_reset_link(struct azx *chip)
> +{
> + struct hdac_bus *bus = azx_bus(chip);
> + u32 gctl;
> + u16 statests;
> + int timeout;
> +
> + snd_hdac_bus_stop_chip(bus);
> +
> + gctl = snd_hdac_chip_readl(bus, GCTL);
> + snd_hdac_chip_writel(bus, GCTL, gctl & ~AZX_GCTL_RESET);
> + for (timeout = 250; timeout; timeout--) {
> + if (!(snd_hdac_chip_readl(bus, GCTL) & AZX_GCTL_RESET))
> + break;
> + udelay(1);
> + }
> +
> + gctl = snd_hdac_chip_readl(bus, GCTL);
> + snd_hdac_chip_writel(bus, GCTL, gctl | AZX_GCTL_RESET);
> + for (timeout = 250; timeout; timeout--) {
> + if (snd_hdac_chip_readl(bus, GCTL) & AZX_GCTL_RESET)
> + break;
> + udelay(1);
> + }
> +
> + statests = snd_hdac_chip_readw(bus, STATESTS);
> + bus->codec_mask |= statests;
> + snd_hdac_bus_init_chip(bus, false);
> +
> + return statests;
Can't the standard snd_hdac_bus_reset_link() work? If not, we may
tweak there in the standard code instead of open-code here.
> static void __azx_runtime_resume(struct azx *chip)
> {
> struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
> @@ -1003,6 +1043,8 @@ static void __azx_runtime_resume(struct azx *chip)
>
> azx_init_pci(chip);
> hda_intel_init_chip(chip, true);
> + if (chip->pm_prepared && hp_envy_27_needs_reset(chip))
> + hp_envy_27_reset_link(chip);
So you need a bus reset always at each S3/S4 resume?
Or could this be conditional?
> +static int hp_envy_27_probe_codec(struct azx *chip)
> +{
> + struct hdac_bus *bus = azx_bus(chip);
> + struct hda_codec *codec = NULL;
> + bool use_pio;
> + int probe_mask;
> + int err;
> +
> + if (!hp_envy_27_needs_reset(chip) || (bus->codec_mask & BIT(0)))
> + return 0;
> + if (!(hp_envy_27_reset_link(chip) & BIT(0)))
> + return -ENODEV;
Trying the bus reset at probe is understandable, but...
> + probe_mask = chip->codec_probe_mask;
> + use_pio = bus->use_pio_for_commands;
> + chip->codec_probe_mask = BIT(0);
> + bus->use_pio_for_commands = true;
> + err = snd_hda_codec_new(&chip->bus, chip->card, 0, &codec);
> + chip->codec_probe_mask = probe_mask;
> + if (!err && codec)
> + err = snd_hda_codec_configure(codec);
> + else if (!err)
> + err = -ENODEV;
> + bus->use_pio_for_commands = use_pio;
... those look too ugly. The use of PIO mode isn't mentioned in the
description, either. Maybe PIO mode should be used always for your
board?
> @@ -2444,6 +2519,8 @@ static int azx_probe_continue(struct azx *chip)
> pm_runtime_allow(&pci->dev);
> pm_runtime_put_autosuspend(&pci->dev);
> }
> + if (hp_envy_27_needs_reset(chip))
> + pm_runtime_forbid(&pci->dev);
Add to power_save_denylist, instead.
thanks,
Takashi
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] ALSA: hda: intel: reset link for HP ENVY 27-p014
2026-09-01 12:07 ` Takashi Iwai
@ 2026-09-03 17:12 ` Casey Tunturi
0 siblings, 0 replies; 3+ messages in thread
From: Casey Tunturi @ 2026-09-03 17:12 UTC (permalink / raw)
To: Takashi Iwai
Cc: Casey Tunturi via B4 Relay, Jaroslav Kysela, Takashi Iwai,
linux-sound, linux-kernel
On Tue, Sep 1, 2026 at 8:07 AM Takashi Iwai <tiwai@suse.de> wrote:
> Thanks for the patch. But I must say that it's very hackish, and we
> should
> reconsider to make the changes a bit more generic or cleaner.
>
> But, first off, could you give more details about your hardware? At
> best,
> give alsa-info.sh output (run with --no-upload option and attach the
> output).
Thank you for taking the time to review it!
Oh yes, I think it's cursed. This is a hack.
I submitted it just before leaving my in-laws' place so it wouldn't stay
isolated to that one machine. It has been running for about four months,
and it was the only thing I found so far that made the codec enumerate
and gave my father-in-law working analog audio under Linux.
I don't have the machine in front of me now. I'll have it again just
short of two weeks. I'll rerun the tests, collect the alsa-info output,
and work through the reset and PIO questions then.
> Can't the standard snd_hdac_bus_reset_link() work? If not, we may tweak
> there in the standard code instead of open-code here.
I knew I was probably forcing the issue at the wrong layer. I asked
around on Matrix with a couple of devs and couldn't get the standard
reset path to work on this hardware.
I'd appreciate any pointers to code or docs I should read. I'd like to
understand the right fix rather than just keep the workaround.
Casey
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-09-03 17:12 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-28 20:29 [PATCH] ALSA: hda: intel: reset link for HP ENVY 27-p014 Casey Tunturi via B4 Relay
2026-09-01 12:07 ` Takashi Iwai
2026-09-03 17:12 ` Casey Tunturi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox