summaryrefslogtreecommitdiffstats
path: root/sys/dev/pccbb
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2006-08-12 09:06:55 +0000
committerimp <imp@FreeBSD.org>2006-08-12 09:06:55 +0000
commit29d2f94ff579fce0722989a39a5f5f3efde4cb28 (patch)
treee22afce7c8f74e5783aabb323f1b346343a1ebf3 /sys/dev/pccbb
parent99a2d2e8b4221b9e09ed977bd97f84da880a6da1 (diff)
downloadFreeBSD-src-29d2f94ff579fce0722989a39a5f5f3efde4cb28.zip
FreeBSD-src-29d2f94ff579fce0722989a39a5f5f3efde4cb28.tar.gz
Batch of changes:
o when turning off the socket for a 16-bit card, write 0 to INTR register rather than just tying to just clear the rest bit. this seems to fix card insert detection after an eject on TI bridges (ricoh bridges work either way, apparently). This is a MFp4. o Cope better with TOPIC95 bridges on powerup. According to NetBSD driver, these bridges don't set POWER_STATE, so cope accordingly in our power code. They also need a little extra time to settle, so do that as well. o It appears that we need to turn on/off one of the clocks to the card when we power up/down that socket on a TOPIC97, also from NetBSD. o TOPIC97 bridges need to specifically enable LV card support. Unconditionally do this in the hopes that all laptops that have these chips support LV voltages (they should, since they are required for CardBus). o TOPIC register name regularization. Registers specific to models of TOPIC are now called out as such. # I need a machine with a TOPIC95 for testing.
Diffstat (limited to 'sys/dev/pccbb')
-rw-r--r--sys/dev/pccbb/pccbb.c55
-rw-r--r--sys/dev/pccbb/pccbb_pci.c44
-rw-r--r--sys/dev/pccbb/pccbbreg.h74
3 files changed, 112 insertions, 61 deletions
diff --git a/sys/dev/pccbb/pccbb.c b/sys/dev/pccbb/pccbb.c
index 3451b12..4971e89 100644
--- a/sys/dev/pccbb/pccbb.c
+++ b/sys/dev/pccbb/pccbb.c
@@ -700,7 +700,7 @@ cbb_o2micro_power_hack2(struct cbb_softc *sc, uint8_t reg)
int
cbb_power(device_t brdev, int volts)
{
- uint32_t status, sock_ctrl, mask;
+ uint32_t status, sock_ctrl, reg_ctrl, mask;
struct cbb_softc *sc = device_get_softc(brdev);
int cnt, sane;
int retval = 0;
@@ -744,14 +744,15 @@ cbb_power(device_t brdev, int volts)
reg = cbb_o2micro_power_hack(sc);
/*
- * We have to mask the card change detect interrupt while we're
- * messing with the power. It is allowed to bounce while we're
- * messing with power as things settle down. In addition, we mask off
- * the card's function interrupt by routing it via the ISA bus. This
- * bit generally only affects 16bit cards. Some bridges allow one to
- * set another bit to have it also affect 32bit cards. Since 32bit
- * cards are required to be better behaved, we don't bother to get
- * into those bridge specific features.
+ * We have to mask the card change detect interrupt while
+ * we're messing with the power. It is allowed to bounce
+ * while we're messing with power as things settle down. In
+ * addition, we mask off the card's function interrupt by
+ * routing it via the ISA bus. This bit generally only
+ * affects 16-bit cards. Some bridges allow one to set
+ * another bit to have it also affect 32-bit cards. Since
+ * 32-bit cards are required to be better behaved, we don't
+ * bother to get into those bridge specific features.
*/
mask = cbb_get(sc, CBB_SOCKET_MASK);
mask |= CBB_SOCKET_MASK_POWER;
@@ -763,13 +764,29 @@ cbb_power(device_t brdev, int volts)
if (on) {
mtx_lock(&sc->mtx);
cnt = sc->powerintr;
- sane = 200;
+ /*
+ * We have a shortish timeout of 500ms here. Some
+ * bridges do not generate a POWER_CYCLE event for
+ * 16-bit cards. In those cases, we have to cope the
+ * best we can, and having only a short delay is
+ * better than the alternatives.
+ */
+ sane = 10;
while (!(cbb_get(sc, CBB_SOCKET_STATE) & CBB_STATE_POWER_CYCLE) &&
cnt == sc->powerintr && sane-- > 0)
- cv_timedwait(&sc->powercv, &sc->mtx, hz / 10);
+ cv_timedwait(&sc->powercv, &sc->mtx, hz / 20);
mtx_unlock(&sc->mtx);
- if (sane <= 0)
+ /*
+ * The TOPIC95B requires a little bit extra time to get
+ * its act together, so delay for an additional 100ms. Also
+ * as documented below, it doesn't seem to set the POWER_CYCLE
+ * bit, so don't whine if it never came on.
+ */
+ if (sc->chipset == CB_TOPIC95) {
+ tsleep(sc, PZERO, "cbb95B", hz / 10);
+ } else if (sane <= 0) {
device_printf(sc->dev, "power timeout, doom?\n");
+ }
}
/*
@@ -782,10 +799,13 @@ cbb_power(device_t brdev, int volts)
* we're called from the card insertion code, in which case the cbb
* thread will turn it on for us before it waits to be woken by a
* change event.
+ *
+ * NB: Topic95B doesn't set the power cycle bit. we assume that
+ * both it and the TOPIC95 behave the same.
*/
cbb_clrb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_POWER);
status = cbb_get(sc, CBB_SOCKET_STATE);
- if (on) {
+ if (on && sc->chipset != CB_TOPIC95) {
if ((status & CBB_STATE_POWER_CYCLE) == 0)
device_printf(sc->dev, "Power not on?\n");
}
@@ -794,6 +814,15 @@ cbb_power(device_t brdev, int volts)
/* XXX Do we want to do something to mitigate things here? */
goto done;
}
+ if (sc->chipset == CB_TOPIC97) {
+ reg_ctrl = pci_read_config(sc->dev, TOPIC_REG_CTRL, 4);
+ reg_ctrl &= ~TOPIC97_REG_CTRL_TESTMODE;
+ if (on)
+ reg_ctrl |= TOPIC97_REG_CTRL_CLKRUN_ENA;
+ else
+ reg_ctrl &= ~TOPIC97_REG_CTRL_CLKRUN_ENA;
+ pci_write_config(sc->dev, TOPIC_REG_CTRL, reg_ctrl, 4);
+ }
PCI_MASK_CONFIG(brdev, CBBR_BRIDGECTRL,
& ~CBBM_BRIDGECTRL_INTR_IREQ_ISA_EN, 2);
retval = 1;
diff --git a/sys/dev/pccbb/pccbb_pci.c b/sys/dev/pccbb/pccbb_pci.c
index 6a13bd7..07abaff 100644
--- a/sys/dev/pccbb/pccbb_pci.c
+++ b/sys/dev/pccbb/pccbb_pci.c
@@ -302,10 +302,11 @@ cbb_pci_attach(device_t brdev)
{
static int curr_bus_number = 2; /* XXX EVILE BAD (see below) */
struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(brdev);
- int rid;
- device_t parent;
struct sysctl_ctx_list *sctx;
struct sysctl_oid *soid;
+ int rid;
+ device_t parent;
+ uint32_t pribus;
parent = device_get_parent(brdev);
mtx_init(&sc->mtx, device_get_nameunit(brdev), "cbb", MTX_DEF);
@@ -317,7 +318,7 @@ cbb_pci_attach(device_t brdev)
sc->exca[0].pccarddev = NULL;
sc->secbus = pci_read_config(brdev, PCIR_SECBUS_2, 1);
sc->subbus = pci_read_config(brdev, PCIR_SUBBUS_2, 1);
- sc->pribus = pci_read_config(brdev, PCIR_PRIBUS_2, 1);
+ sc->pribus = pcib_get_bus(parent);
SLIST_INIT(&sc->rl);
cbb_powerstate_d0(brdev);
@@ -359,10 +360,11 @@ cbb_pci_attach(device_t brdev)
* are in an appropriate range.
*/
DEVPRINTF((brdev, "Secondary bus is %d\n", sc->secbus));
- if (sc->secbus == 0) {
+ pribus = pci_read_config(brdev, PCIR_PRIBUS_2, 1);
+ if (sc->secbus == 0 || sc->pribus != pribus) {
if (curr_bus_number <= sc->pribus)
curr_bus_number = sc->pribus + 1;
- if (pci_read_config(brdev, PCIR_PRIBUS_2, 1) != sc->pribus) {
+ if (pribus != sc->pribus) {
DEVPRINTF((brdev, "Setting primary bus to %d\n",
sc->pribus));
pci_write_config(brdev, PCIR_PRIBUS_2, sc->pribus, 1);
@@ -553,27 +555,32 @@ cbb_chipinit(struct cbb_softc *sc)
reg = (reg & 0x0f) |
EXCA_O2CC_IREQ_INTC | EXCA_O2CC_STSCHG_INTC;
exca_putb(&sc->exca[0], EXCA_O2MICRO_CTRL_C, reg);
-
break;
case CB_TOPIC97:
/*
* Disable Zoom Video, ToPIC 97, 100.
*/
- pci_write_config(sc->dev, CBBR_TOPIC_ZV_CONTROL, 0, 1);
+ pci_write_config(sc->dev, TOPIC97_ZV_CONTROL, 0, 1);
/*
* ToPIC 97, 100
* At offset 0xa1: INTERRUPT CONTROL register
* 0x1: Turn on INT interrupts.
*/
- PCI_MASK_CONFIG(sc->dev, CBBR_TOPIC_INTCTRL,
- | CBBM_TOPIC_INTCTRL_INTIRQSEL, 1);
+ PCI_MASK_CONFIG(sc->dev, TOPIC_INTCTRL,
+ | TOPIC97_INTCTRL_INTIRQSEL, 1);
+ /*
+ * ToPIC97, 100
+ * Need to assert support for low voltage cards
+ */
+ exca_setb(&sc->exca[0], EXCA_TOPIC97_CTRL,
+ EXCA_TOPIC97_CTRL_LV_MASK);
goto topic_common;
case CB_TOPIC95:
/*
* SOCKETCTRL appears to be TOPIC 95/B specific
*/
- PCI_MASK_CONFIG(sc->dev, CBBR_TOPIC_SOCKETCTRL,
- | CBBM_TOPIC_SOCKETCTRL_SCR_IRQSEL, 4);
+ PCI_MASK_CONFIG(sc->dev, TOPIC95_SOCKETCTRL,
+ | TOPIC95_SOCKETCTRL_SCR_IRQSEL, 4);
topic_common:;
/*
@@ -586,20 +593,19 @@ cbb_chipinit(struct cbb_softc *sc)
* in legacy mode to 0x3e0 and offset 0. (legacy
* mode is determined elsewhere)
*/
- pci_write_config(sc->dev, CBBR_TOPIC_SLOTCTRL,
- CBBM_TOPIC_SLOTCTRL_SLOTON |
- CBBM_TOPIC_SLOTCTRL_SLOTEN |
- CBBM_TOPIC_SLOTCTRL_ID_LOCK |
- CBBM_TOPIC_SLOTCTRL_ID_WP, 1);
+ pci_write_config(sc->dev, TOPIC_SLOTCTRL,
+ TOPIC_SLOTCTRL_SLOTON |
+ TOPIC_SLOTCTRL_SLOTEN |
+ TOPIC_SLOTCTRL_ID_LOCK |
+ TOPIC_SLOTCTRL_ID_WP, 1);
/*
* At offset 0xa3 Card Detect Control Register
* 0x80 CARDBUS enbale
* 0x01 Cleared for hardware change detect
*/
- PCI_MASK2_CONFIG(sc->dev, CBBR_TOPIC_CDC,
- | CBBM_TOPIC_CDC_CARDBUS,
- & ~CBBM_TOPIC_CDC_SWDETECT, 4);
+ PCI_MASK2_CONFIG(sc->dev, TOPIC_CDC,
+ | TOPIC_CDC_CARDBUS, & ~TOPIC_CDC_SWDETECT, 4);
break;
}
diff --git a/sys/dev/pccbb/pccbbreg.h b/sys/dev/pccbb/pccbbreg.h
index a8ca264..ae73fe1 100644
--- a/sys/dev/pccbb/pccbbreg.h
+++ b/sys/dev/pccbb/pccbbreg.h
@@ -132,44 +132,60 @@
# define CBBM_DEVCTRL_INT_PCI 0x02
/* ToPIC 95 ONLY */
-#define CBBR_TOPIC_SOCKETCTRL 0x90
-# define CBBM_TOPIC_SOCKETCTRL_SCR_IRQSEL 0x00000001 /* PCI intr */
+#define TOPIC95_SOCKETCTRL 0x90
+# define TOPIC95_SOCKETCTRL_SCR_IRQSEL 0x00000001 /* PCI intr */
/* ToPIC 97, 100 */
-#define CBBR_TOPIC_ZV_CONTROL 0x9c /* 1 byte */
-# define CBBM_TOPIC_ZVC_ENABLE 0x1
+#define TOPIC97_ZV_CONTROL 0x9c /* 1 byte */
+# define TOPIC97_ZVC_ENABLE 0x1
/* TOPIC 95+ */
-#define CBBR_TOPIC_SLOTCTRL 0xa0 /* 1 byte */
-# define CBBM_TOPIC_SLOTCTRL_SLOTON 0x80
-# define CBBM_TOPIC_SLOTCTRL_SLOTEN 0x40
-# define CBBM_TOPIC_SLOTCTRL_ID_LOCK 0x20
-# define CBBM_TOPIC_SLOTCTRL_ID_WP 0x10
-# define CBBM_TOPIC_SLOTCTRL_PORT_MASK 0x0c
-# define CBBM_TOPIC_SLOTCTRL_PORT_SHIFT 2
-# define CBBM_TOPIC_SLOTCTRL_OSF_MASK 0x03
-# define CBBM_TOPIC_SLOTCTRL_OSF_SHIFT 0
+#define TOPIC_SLOTCTRL 0xa0 /* 1 byte */
+# define TOPIC_SLOTCTRL_SLOTON 0x80
+# define TOPIC_SLOTCTRL_SLOTEN 0x40
+# define TOPIC_SLOTCTRL_ID_LOCK 0x20
+# define TOPIC_SLOTCTRL_ID_WP 0x10
+# define TOPIC_SLOTCTRL_PORT_MASK 0x0c
+# define TOPIC_SLOTCTRL_PORT_SHIFT 2
+# define TOPIC_SLOTCTRL_OSF_MASK 0x03
+# define TOPIC_SLOTCTRL_OSF_SHIFT 0
/* TOPIC 95+ */
-#define CBBR_TOPIC_INTCTRL 0xa1 /* 1 byte */
-# define CBBM_TOPIC_INTCTRL_INTB 0x20
-# define CBBM_TOPIC_INTCTRL_INTA 0x10
-# define CBBM_TOPIC_INTCTRL_INT_MASK 0x30
+#define TOPIC_INTCTRL 0xa1 /* 1 byte */
+# define TOPIC_INTCTRL_INTB 0x20
+# define TOPIC_INTCTRL_INTA 0x10
+# define TOPIC_INTCTRL_INT_MASK 0x30
/* The following bits may be for ToPIC 95 only */
-# define CBBM_TOPIC_INTCTRL_CLOCK_MASK 0x0c
-# define CBBM_TOPIC_INTCTRL_CLOCK_2 0x08 /* PCI Clk/2 */
-# define CBBM_TOPIC_INTCTRL_CLOCK_1 0x04 /* PCI Clk */
-# define CBBM_TOPIC_INTCTRL_CLOCK_0 0x00 /* no clock */
+# define TOPIC95_INTCTRL_CLOCK_MASK 0x0c
+# define TOPIC95_INTCTRL_CLOCK_2 0x08 /* PCI Clk/2 */
+# define TOPIC95_INTCTRL_CLOCK_1 0x04 /* PCI Clk */
+# define TOPIC95_INTCTRL_CLOCK_0 0x00 /* no clock */
/* ToPIC97, 100 defines the following bits */
-# define CBBM_TOPIC_INTCTRL_STSIRQNP 0x04
-# define CBBM_TOPIC_INTCTRL_IRQNP 0x02
-# define CBBM_TOPIC_INTCTRL_INTIRQSEL 0x01
+# define TOPIC97_INTCTRL_STSIRQNP 0x04
+# define TOPIC97_INTCTRL_IRQNP 0x02
+# define TOPIC97_INTCTRL_INTIRQSEL 0x01
/* TOPIC 95+ */
-#define CBBR_TOPIC_CDC 0xa3 /* 1 byte */
-# define CBBM_TOPIC_CDC_CARDBUS 0x80
-# define CBBM_TOPIC_CDC_VS1 0x04
-# define CBBM_TOPIC_CDC_VS2 0x02
-# define CBBM_TOPIC_CDC_SWDETECT 0x01
+#define TOPIC_CDC 0xa3 /* 1 byte */
+# define TOPIC_CDC_CARDBUS 0x80
+# define TOPIC_CDC_VS1 0x04
+# define TOPIC_CDC_VS2 0x02
+# define TOPIC_CDC_SWDETECT 0x01
+
+/* TOPIC97+? */
+#define TOPIC_REG_CTRL 0xa4 /* 4 bytes */
+# define TOPIC_REG_CTRL_RESUME_RESET 0x80000000
+# define TOPIC_REG_CTRL_REMOVE_RESET 0x40000000
+# define TOPIC97_REG_CTRL_CLKRUN_ENA 0x20000000
+# define TOPIC97_REG_CTRL_TESTMODE 0x10000000
+# define TOPIC97_REG_CTRL_IOPLUP 0x08000000
+# define TOPIC_REG_CTRL_BUFOFF_PWROFF 0x02000000
+# define TOPIC_REG_CTRL_BUFOFF_SIGOFF 0x01000000
+# define TOPIC97_REG_CTRL_CB_DEV_MASK 0x0000f800
+# define TOPIC97_REG_CTRL_CB_DEV_SHIFT 11
+# define TOPIC97_REG_CTRL_RI_DISABLE 0x00000004
+# define TOPIC97_REG_CTRL_CAUDIO_OFF 0x00000002
+# define TOPIC_REG_CTRL_CAUDIO_INVERT 0x00000001
+
/* Socket definitions */
#define CBB_SOCKET_EVENT_CSTS 0x01 /* Card Status Change */
OpenPOWER on IntegriCloud