diff options
author | Aaron Campbell <aaron@cvs.openbsd.org> | 2001-02-09 21:15:24 +0000 |
---|---|---|
committer | Aaron Campbell <aaron@cvs.openbsd.org> | 2001-02-09 21:15:24 +0000 |
commit | 1bd4318d2c2bcdc45b4f63692b4d7af75ca821de (patch) | |
tree | c3cbe816029a75f771fdea7102721aa37eefa0c6 /sys | |
parent | 23b15947b95f88bf6700bb11501da91c07aa4b14 (diff) |
Tickle D0 power state so the cs4281 works after reboots from Windows 2000.
From NetBSD, tested on a dual-boot IBM ThinkPad X20.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/pci/cs4281.c | 30 | ||||
-rw-r--r-- | sys/dev/pci/cs4281reg.h | 3 |
2 files changed, 31 insertions, 2 deletions
diff --git a/sys/dev/pci/cs4281.c b/sys/dev/pci/cs4281.c index 273df86deec..a7193e147e9 100644 --- a/sys/dev/pci/cs4281.c +++ b/sys/dev/pci/cs4281.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cs4281.c,v 1.1 2001/01/13 19:53:50 aaron Exp $ */ +/* $OpenBSD: cs4281.c,v 1.2 2001/02/09 21:15:22 aaron Exp $ */ /* $Tera: cs4281.c,v 1.18 2000/12/27 14:24:45 tacha Exp $ */ /* @@ -301,6 +301,7 @@ cs4281_attach(parent, self, aux) char const *intrstr; pci_intr_handle_t ih; pcireg_t csr; + int pci_pwrmgmt_cap_reg, pci_pwrmgmt_csr_reg; /* Map I/O register */ if (pci_mapreg_map(pa, CSCC_PCI_BA0, @@ -318,6 +319,25 @@ cs4281_attach(parent, self, aux) sc->sc_dmatag = pa->pa_dmat; + /* + * Set Power State D0. + * Without doing this, 0xffffffff is read from all registers after + * using Windows and rebooting into OpenBSD. + * On my IBM ThinkPad X20, it is set to D3 after using Windows2000. + */ + if (pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_PWRMGMT, + &pci_pwrmgmt_cap_reg, 0)) { + pcireg_t reg; + + pci_pwrmgmt_csr_reg = pci_pwrmgmt_cap_reg + 4; + reg = pci_conf_read(pa->pa_pc, pa->pa_tag, pci_pwrmgmt_csr_reg); + if ((reg & PCI_PMCSR_STATE_MASK) != PCI_PMCSR_STATE_D0) { + pci_conf_write(pc, pa->pa_tag, pci_pwrmgmt_csr_reg, + (reg & ~PCI_PMCSR_STATE_MASK) | + PCI_PMCSR_STATE_D0); + } + } + /* Enable the device (set bus master flag) */ csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, @@ -863,6 +883,14 @@ cs4281_init(sc) * 0x4281 to allow to write */ BA0WRITE4(sc, CS4281_CWPR, 0x4281); + /* + * Unset "Full Power-Down bit of Extended PCI Power Management + * Control" register to release the reset state. + */ + dat32 = BA0READ4(sc, CS4281_EPPMC); + if (dat32 & EPPMC_FPDN) + BA0WRITE4(sc, CS4281_EPPMC, dat32 & ~EPPMC_FPDN); + /* Start PLL out in known state */ BA0WRITE4(sc, CS4281_CLKCR1, 0); /* Start serial ports out in known state */ diff --git a/sys/dev/pci/cs4281reg.h b/sys/dev/pci/cs4281reg.h index 73f2c39118e..4e8230a209b 100644 --- a/sys/dev/pci/cs4281reg.h +++ b/sys/dev/pci/cs4281reg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cs4281reg.h,v 1.1 2001/01/13 19:53:50 aaron Exp $ */ +/* $OpenBSD: cs4281reg.h,v 1.2 2001/02/09 21:15:23 aaron Exp $ */ /* $Tera: cs4281reg.h,v 1.9 2000/12/31 10:52:25 tacha Exp $ */ /* @@ -161,6 +161,7 @@ #define CS4281_PMCS 0x344 /* Power Management Control/Status */ #define CS4281_CWPR 0x3E0 /* Configuration Write Protect Register */ #define CS4281_EPPMC 0x3E4 /* Extended PCI Power Management Control */ +#define EPPMC_FPDN (0x1 << 14) #define CS4281_GPIOR 0x3E8 /* GPIO Pin Interface Register */ #define CS4281_SPMC 0x3EC /* Serial Port Power Management Control (& ASDIN2 enable) */ #define SPMC_RSTN 0x00000001 |