Set HDAUDIO_PCI_TCSEL to TC0 like Linux does.

Fixes stalled audio on Lenovo X60 with coreboot firmware.

Additionally, move snooping adjustment to be executed on resume too,
as Linux does.
This commit is contained in:
jakllsch 2012-02-01 16:56:34 +00:00
parent 6c9b9f2ea5
commit 232e69ea3e
1 changed files with 32 additions and 13 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: hdaudio_pci.c,v 1.10 2011/11/24 03:35:59 mrg Exp $ */
/* $NetBSD: hdaudio_pci.c,v 1.11 2012/02/01 16:56:34 jakllsch Exp $ */
/*
* Copyright (c) 2009 Precedence Technologies Ltd <support@precedence.co.uk>
@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: hdaudio_pci.c,v 1.10 2011/11/24 03:35:59 mrg Exp $");
__KERNEL_RCSID(0, "$NetBSD: hdaudio_pci.c,v 1.11 2012/02/01 16:56:34 jakllsch Exp $");
#include <sys/types.h>
#include <sys/param.h>
@ -56,6 +56,7 @@ struct hdaudio_pci_softc {
pcitag_t sc_tag;
pci_chipset_tag_t sc_pc;
void *sc_ih;
pcireg_t sc_id;
};
static int hdaudio_pci_match(device_t, cfdata_t, void *);
@ -65,6 +66,7 @@ static int hdaudio_pci_rescan(device_t, const char *, const int *);
static void hdaudio_pci_childdet(device_t, device_t);
static int hdaudio_pci_intr(void *);
static void hdaudio_pci_reinit(struct hdaudio_pci_softc *);
/* power management */
static bool hdaudio_pci_resume(device_t, const pmf_qual_t *);
@ -112,6 +114,7 @@ hdaudio_pci_attach(device_t parent, device_t self, void *opaque)
sc->sc_pc = pa->pa_pc;
sc->sc_tag = pa->pa_tag;
sc->sc_id = pa->pa_id;
sc->sc_hdaudio.sc_subsystem = pci_conf_read(sc->sc_pc, sc->sc_tag,
PCI_SUBSYS_ID_REG);
@ -155,17 +158,7 @@ hdaudio_pci_attach(device_t parent, device_t self, void *opaque)
if (!pmf_device_register(self, NULL, hdaudio_pci_resume))
aprint_error_dev(self, "couldn't establish power handler\n");
switch (PCI_VENDOR(pa->pa_id)) {
case PCI_VENDOR_NVIDIA:
/* enable snooping */
csr = pci_conf_read(sc->sc_pc, sc->sc_tag,
HDAUDIO_NV_REG_SNOOP);
csr &= ~HDAUDIO_NV_SNOOP_MASK;
csr |= HDAUDIO_NV_SNOOP_ENABLE;
pci_conf_write(sc->sc_pc, sc->sc_tag,
HDAUDIO_NV_REG_SNOOP, csr);
break;
}
hdaudio_pci_reinit(sc);
/* Attach bus-independent HD audio layer */
hdaudio_attach(self, &sc->sc_hdaudio);
@ -224,10 +217,36 @@ hdaudio_pci_intr(void *opaque)
return hdaudio_intr(&sc->sc_hdaudio);
}
static void
hdaudio_pci_reinit(struct hdaudio_pci_softc *sc)
{
pcireg_t val;
/* stops playback static */
val = pci_conf_read(sc->sc_pc, sc->sc_tag, HDAUDIO_PCI_TCSEL);
val &= ~7;
val |= 0;
pci_conf_write(sc->sc_pc, sc->sc_tag, HDAUDIO_PCI_TCSEL, val);
switch (PCI_VENDOR(sc->sc_id)) {
case PCI_VENDOR_NVIDIA:
/* enable snooping */
val = pci_conf_read(sc->sc_pc, sc->sc_tag,
HDAUDIO_NV_REG_SNOOP);
val &= ~HDAUDIO_NV_SNOOP_MASK;
val |= HDAUDIO_NV_SNOOP_ENABLE;
pci_conf_write(sc->sc_pc, sc->sc_tag,
HDAUDIO_NV_REG_SNOOP, val);
break;
}
}
static bool
hdaudio_pci_resume(device_t self, const pmf_qual_t *qual)
{
struct hdaudio_pci_softc *sc = device_private(self);
hdaudio_pci_reinit(sc);
return hdaudio_resume(&sc->sc_hdaudio);
}