summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Campbell <aaron@cvs.openbsd.org>2001-02-09 21:15:24 +0000
committerAaron Campbell <aaron@cvs.openbsd.org>2001-02-09 21:15:24 +0000
commit1bd4318d2c2bcdc45b4f63692b4d7af75ca821de (patch)
treec3cbe816029a75f771fdea7102721aa37eefa0c6
parent23b15947b95f88bf6700bb11501da91c07aa4b14 (diff)
Tickle D0 power state so the cs4281 works after reboots from Windows 2000.
From NetBSD, tested on a dual-boot IBM ThinkPad X20.
-rw-r--r--sys/dev/pci/cs4281.c30
-rw-r--r--sys/dev/pci/cs4281reg.h3
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