diff options
-rw-r--r-- | share/man/man4/Makefile | 9 | ||||
-rw-r--r-- | share/man/man4/tcic.4 | 63 | ||||
-rw-r--r-- | sys/arch/i386/conf/GENERIC | 4 | ||||
-rw-r--r-- | sys/arch/i386/conf/files.i386 | 8 | ||||
-rw-r--r-- | sys/dev/ic/tcic2.c | 1401 | ||||
-rw-r--r-- | sys/dev/ic/tcic2reg.h | 827 | ||||
-rw-r--r-- | sys/dev/ic/tcic2var.h | 359 | ||||
-rw-r--r-- | sys/dev/isa/tcic2_isa.c | 375 |
8 files changed, 3040 insertions, 6 deletions
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index b64091079e4..7e631e201e5 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.115 2000/04/27 03:59:21 millert Exp $ +# $OpenBSD: Makefile,v 1.116 2000/05/15 04:17:29 jason Exp $ MAN= ac97.4 an.4 atalk.4 atapiscsi.4 audio.4 adv.4 ahc.4 aue.4 bpf.4 \ bridge.4 cardbus.4 ccd.4 cd.4 ch.4 clnp.4 cltp.4 cmpci.4 cnw.4 \ @@ -13,9 +13,10 @@ MAN= ac97.4 an.4 atalk.4 atapiscsi.4 audio.4 adv.4 ahc.4 aue.4 bpf.4 \ null.4 ohci.4 opl.4 options.4 pchb.4 pci.4 pciide.4 pcmcia.4 pty.4 \ qsphy.4 raid.4 \ random.4 ray.4 rl.4 rln.4 rlphy.4 route.4 scsi.4 sd.4 ses.4 sf.4 \ - sis.4 sk.4 sl.4 sm.4 spp.4 sppp.4 sqphy.4 ss.4 st.4 ste.4 sv.4 tb.4 \ - tcp.4 termios.4 ti.4 tl.4 tlphy.4 tp.4 tqphy.4 tty.4 tun.4 tx.4 \ - txphy.4 uaudio.4 udp.4 ugen.4 uhci.4 uhid.4 uk.4 ukphy.4 ulpt.4 \ + sis.4 sk.4 sl.4 sm.4 spp.4 sppp.4 sqphy.4 ss.4 st.4 ste.4 sv.4 \ + tb.4 tcic.4 tcp.4 termios.4 ti.4 tl.4 tlphy.4 tp.4 tqphy.4 tty.4 \ + tun.4 tx.4 txphy.4 \ + uaudio.4 udp.4 ugen.4 uhci.4 uhid.4 uk.4 ukphy.4 ulpt.4 \ umass.4 unix.4 urio.4 usb.4 vlan.4 vnd.4 vr.4 wb.4 wd.4 we.4 wx.4 xl.4 \ ym.4 zero.4 diff --git a/share/man/man4/tcic.4 b/share/man/man4/tcic.4 new file mode 100644 index 00000000000..a42a4d0d236 --- /dev/null +++ b/share/man/man4/tcic.4 @@ -0,0 +1,63 @@ +.\" $OpenBSD: tcic.4,v 1.1 2000/05/15 04:17:29 jason Exp $ +.\" $NetBSD: tcic.4,v 1.1 2000/02/12 11:14:14 fair Exp $ +.\" +.\" Copyright (c) 1999 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the NetBSD +.\" Foundation, Inc. and its contributors. +.\" 4. Neither the name of The NetBSD Foundation nor the names of its +.\" contributors may be used to endorse or promote products derived +.\" from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd May 21, 1999 +.Dt TCIC 4 +.Os +.Sh NAME +.Nm tcic +.Nd Databook PCMCIA controller driver +.Sh SYNOPSIS +.Cd "tcic0 at isa? port 0x240 iomem 0xd0000 iosiz 0x4000" +.Cd "pcmcia* at tcic? controller ? socket ?" +.Sh DESCRIPTION +.Nx +provides support for the +.Tn Databook +DB86082, DB86084, DB86184, and DB86072 +.Tn PCMCIA +controllers. +.Sh SEE ALSO +.Xr pcmcia 4 , +.Xr pcic 4 , +.Xr isa 4 +.Sh HISTORY +The +.Nm +driver appeared in +.Nx 1.4 , +and +.Ox +support first appeared in +.Ox 2.8 . diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC index 4c5ad6554f3..b6ae81faadd 100644 --- a/sys/arch/i386/conf/GENERIC +++ b/sys/arch/i386/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.183 2000/04/27 02:19:42 millert Exp $ +# $OpenBSD: GENERIC,v 1.184 2000/05/15 04:17:30 jason Exp $ # $NetBSD: GENERIC,v 1.48 1996/05/20 18:17:23 mrg Exp $ # # GENERIC -- everything that's currently supported @@ -59,9 +59,11 @@ pcib* at pci? dev ? function ? # PCI-ISA bridges (do nothing) pcic0 at isa? port 0x3e0 iomem 0xd0000 iosiz 0x10000 pcic1 at isa? port 0x3e2 iomem 0xe0000 iosiz 0x4000 pcic2 at isa? port 0x3e4 iomem 0xe0000 iosiz 0x4000 +#tcic0 at isa? port 0x240 iomem 0xd0000 iosiz 0x10000 # PCMCIA bus support pcmcia* at pcic? controller ? socket ? +#pcmcia* at tcic? controller ? socket ? # CardBus bus support (also see NOTE below) #cardbus* at cardslot? diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386 index 778c72658c1..90f4f9a42cd 100644 --- a/sys/arch/i386/conf/files.i386 +++ b/sys/arch/i386/conf/files.i386 @@ -1,4 +1,4 @@ -# $OpenBSD: files.i386,v 1.64 2000/04/08 05:50:49 aaron Exp $ +# $OpenBSD: files.i386,v 1.65 2000/05/15 04:17:29 jason Exp $ # $NetBSD: files.i386,v 1.73 1996/05/07 00:58:36 thorpej Exp $ # # new style config file for i386 architecture @@ -288,6 +288,12 @@ file dev/isa/i82365_isa.c pcic_isa # Code common to ISA and ISAPnP attachments file dev/isa/i82365_isasubr.c pcic_isa | pcic_isapnp +# Databook TCIC/2 pcmcia/isa bridge +device tcic: pcmciabus +file dev/ic/tcic2.c tcic +attach tcic at isa with tcic_isa +file dev/isa/tcic2_isa.c tcic_isa + # # Machine-independent PUC drivers # diff --git a/sys/dev/ic/tcic2.c b/sys/dev/ic/tcic2.c new file mode 100644 index 00000000000..14d3fa3b371 --- /dev/null +++ b/sys/dev/ic/tcic2.c @@ -0,0 +1,1401 @@ +/* $OpenBSD: tcic2.c,v 1.1 2000/05/15 04:17:28 jason Exp $ */ +/* $NetBSD: tcic2.c,v 1.3 2000/01/13 09:38:17 joda Exp $ */ + +#undef TCICDEBUG + +/* + * Copyright (c) 1998, 1999 Christoph Badura. All rights reserved. + * Copyright (c) 1997 Marc Horowitz. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Marc Horowitz. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/extent.h> +#include <sys/malloc.h> +#include <sys/kthread.h> + +#include <vm/vm.h> + +#include <machine/bus.h> +#include <machine/intr.h> + +#include <dev/pcmcia/pcmciareg.h> +#include <dev/pcmcia/pcmciavar.h> + +#include <dev/ic/tcic2reg.h> +#include <dev/ic/tcic2var.h> + +#ifdef TCICDEBUG +int tcic_debug = 1; +#define DPRINTF(arg) if (tcic_debug) printf arg; +#else +#define DPRINTF(arg) +#endif + +/* + * Individual drivers will allocate their own memory and io regions. Memory + * regions must be a multiple of 4k, aligned on a 4k boundary. + */ + +#define TCIC_MEM_ALIGN TCIC_MEM_PAGESIZE + +void tcic_attach_socket __P((struct tcic_handle *)); +void tcic_init_socket __P((struct tcic_handle *)); + +int tcic_submatch __P((struct device *, void *, void *)); +int tcic_print __P((void *arg, const char *pnp)); +int tcic_intr_socket __P((struct tcic_handle *)); + +void tcic_attach_card __P((struct tcic_handle *)); +void tcic_detach_card __P((struct tcic_handle *, int)); +void tcic_deactivate_card __P((struct tcic_handle *)); + +void tcic_chip_do_mem_map __P((struct tcic_handle *, int)); +void tcic_chip_do_io_map __P((struct tcic_handle *, int)); + +void tcic_create_event_thread __P((void *)); +void tcic_event_thread __P((void *)); + +void tcic_queue_event __P((struct tcic_handle *, int)); + +struct cfdriver tcic_cd = { + NULL, "tcic", DV_DULL +}; + +/* Map between irq numbers and internal representation */ +#if 1 +int tcic_irqmap[] = + { 0, 0, 0, 3, 4, 5, 6, 7, 0, 0, 10, 1, 0, 0, 14, 0 }; +int tcic_valid_irqs = 0x4cf8; +#else +int tcic_irqmap[] = /* irqs 9 and 6 switched, some ISA cards */ + { 0, 0, 0, 3, 4, 5, 0, 7, 0, 6, 10, 1, 0, 0, 14, 0 }; +int tcic_valid_irqs = 0x4eb8; +#endif + +int tcic_mem_speed = 250; /* memory access time in nanoseconds */ +int tcic_io_speed = 165; /* io access time in nanoseconds */ + +/* + * Check various reserved and otherwise in their value restricted bits. + */ +int +tcic_check_reserved_bits(iot, ioh) + bus_space_tag_t iot; + bus_space_handle_t ioh; +{ + int val, auxreg; + + DPRINTF(("tcic: chkrsvd 1\n")); + /* R_ADDR bit 30:28 have a restricted range. */ + val = (bus_space_read_2(iot, ioh, TCIC_R_ADDR2) & TCIC_SS_MASK) + >> TCIC_SS_SHIFT; + if (val > 1) + return 0; + + DPRINTF(("tcic: chkrsvd 2\n")); + /* R_SCTRL bits 6,2,1 are reserved. */ + val = bus_space_read_1(iot, ioh, TCIC_R_SCTRL); + if (val & TCIC_SCTRL_RSVD) + return 0; + + DPRINTF(("tcic: chkrsvd 3\n")); + /* R_ICSR bit 2 must be same as bit 3. */ + val = bus_space_read_1(iot, ioh, TCIC_R_ICSR); + if (((val >> 1) & 1) != ((val >> 2) & 1)) + return 0; + + DPRINTF(("tcic: chkrsvd 4\n")); + /* R_IENA bits 7,2 are reserverd. */ + val = bus_space_read_1(iot, ioh, TCIC_R_IENA); + if (val & TCIC_IENA_RSVD) + return 0; + + DPRINTF(("tcic: chkrsvd 5\n")); + /* Some aux registers have reserved bits. */ + /* Which are we looking at? */ + auxreg = bus_space_read_1(iot, ioh, TCIC_R_MODE) + & TCIC_AR_MASK; + val = bus_space_read_2(iot, ioh, TCIC_R_AUX); + DPRINTF(("tcic: auxreg 0x%02x val 0x%04x\n", auxreg, val)); + switch (auxreg) { + case TCIC_AR_SYSCFG: + if (INVALID_AR_SYSCFG(val)) + return 0; + break; + case TCIC_AR_ILOCK: + if (INVALID_AR_ILOCK(val)) + return 0; + break; + case TCIC_AR_TEST: + if (INVALID_AR_TEST(val)) + return 0; + break; + } + + DPRINTF(("tcic: chkrsvd 6\n")); + /* XXX fails if pcmcia bios is enabled. */ + /* Various bits set or not depending if in RESET mode. */ + val = bus_space_read_1(iot, ioh, TCIC_R_SCTRL); + if (val & TCIC_SCTRL_RESET) { + DPRINTF(("tcic: chkrsvd 7\n")); + /* Address bits must be 0 */ + val = bus_space_read_2(iot, ioh, TCIC_R_ADDR); + if (val != 0) + return 0; + val = bus_space_read_2(iot, ioh, TCIC_R_ADDR2); + if (val != 0) + return 0; + DPRINTF(("tcic: chkrsvd 8\n")); + /* EDC bits must be 0 */ + val = bus_space_read_2(iot, ioh, TCIC_R_EDC); + if (val != 0) + return 0; + /* We're OK, so take it out of reset. XXX -chb */ + bus_space_write_1(iot, ioh, TCIC_R_SCTRL, 0); + } + else { /* not in RESET mode */ + int omode; + int val1, val2; + DPRINTF(("tcic: chkrsvd 9\n")); + /* Programming timers must have expired. */ + val = bus_space_read_1(iot, ioh, TCIC_R_SSTAT); + if ((val & (TCIC_SSTAT_6US|TCIC_SSTAT_10US|TCIC_SSTAT_PROGTIME)) + != (TCIC_SSTAT_6US|TCIC_SSTAT_10US|TCIC_SSTAT_PROGTIME)) + return 0; + DPRINTF(("tcic: chkrsvd 10\n")); + /* + * EDC bits should change on read from data space + * as long as either EDC or the data are nonzero. + */ + if ((bus_space_read_2(iot, ioh, TCIC_R_ADDR2) + & TCIC_ADDR2_INDREG) != 0) { + val1 = bus_space_read_2(iot, ioh, TCIC_R_EDC); + val2 = bus_space_read_2(iot, ioh, TCIC_R_DATA); + if (val1 | val2) { + val1 = bus_space_read_2(iot, ioh, TCIC_R_EDC); + if (val1 == val2) + return 0; + } + } + DPRINTF(("tcic: chkrsvd 11\n")); + /* XXX what does this check? -chb */ + omode = bus_space_read_1(iot, ioh, TCIC_R_MODE); + val1 = omode ^ TCIC_AR_MASK; + bus_space_write_1(iot, ioh, TCIC_R_MODE, val1); + val2 = bus_space_read_1(iot, ioh, TCIC_R_MODE); + bus_space_write_1(iot, ioh, TCIC_R_MODE, omode); + if ( val1 != val2) + return 0; + } + /* All tests passed */ + return 1; +} + +/* + * Read chip ID from AR_ILOCK in test mode. + */ +int +tcic_chipid(iot, ioh) + bus_space_tag_t iot; + bus_space_handle_t ioh; +{ + unsigned id, otest; + + otest = tcic_read_aux_2(iot, ioh, TCIC_AR_TEST); + tcic_write_aux_2(iot, ioh, TCIC_AR_TEST, TCIC_TEST_DIAG); + id = tcic_read_aux_2(iot, ioh, TCIC_AR_ILOCK); + tcic_write_aux_2(iot, ioh, TCIC_AR_TEST, otest); + id &= TCIC_ILOCKTEST_ID_MASK; + id >>= TCIC_ILOCKTEST_ID_SHFT; + + /* clear up IRQs inside tcic. XXX -chb */ + while (bus_space_read_1(iot, ioh, TCIC_R_ICSR)) + bus_space_write_1(iot, ioh, TCIC_R_ICSR, TCIC_ICSR_JAM); + + return id; +} +/* + * Indicate whether the driver can handle the chip. + */ +int +tcic_chipid_known(id) + int id; +{ + /* XXX only know how to handle DB86082 -chb */ + switch (id) { + case TCIC_CHIPID_DB86082_1: + case TCIC_CHIPID_DB86082A: + case TCIC_CHIPID_DB86082B_ES: + case TCIC_CHIPID_DB86082B: + case TCIC_CHIPID_DB86084_1: + case TCIC_CHIPID_DB86084A: + case TCIC_CHIPID_DB86184_1: + case TCIC_CHIPID_DB86072_1_ES: + case TCIC_CHIPID_DB86072_1: + return 1; + } + + return 0; +} + +char * +tcic_chipid_to_string(id) + int id; +{ + switch (id) { + case TCIC_CHIPID_DB86082_1: + return ("Databook DB86082"); + case TCIC_CHIPID_DB86082A: + return ("Databook DB86082A"); + case TCIC_CHIPID_DB86082B_ES: + return ("Databook DB86082B-es"); + case TCIC_CHIPID_DB86082B: + return ("Databook DB86082B"); + case TCIC_CHIPID_DB86084_1: + return ("Databook DB86084"); + case TCIC_CHIPID_DB86084A: + return ("Databook DB86084A"); + case TCIC_CHIPID_DB86184_1: + return ("Databook DB86184"); + case TCIC_CHIPID_DB86072_1_ES: + return ("Databook DB86072-es"); + case TCIC_CHIPID_DB86072_1: + return ("Databook DB86072"); + } + + return ("Unknown controller"); +} +/* + * Return bitmask of IRQs that the chip can handle. + * XXX should be table driven. + */ +int +tcic_validirqs(chipid) + int chipid; +{ + switch (chipid) { + case TCIC_CHIPID_DB86082_1: + case TCIC_CHIPID_DB86082A: + case TCIC_CHIPID_DB86082B_ES: + case TCIC_CHIPID_DB86082B: + case TCIC_CHIPID_DB86084_1: + case TCIC_CHIPID_DB86084A: + case TCIC_CHIPID_DB86184_1: + case TCIC_CHIPID_DB86072_1_ES: + case TCIC_CHIPID_DB86072_1: + return tcic_valid_irqs; + } + return 0; +} + +void +tcic_attach(sc) + struct tcic_softc *sc; +{ + int i, reg; + + /* set more chipset dependend parameters in the softc. */ + switch (sc->chipid) { + case TCIC_CHIPID_DB86084_1: + case TCIC_CHIPID_DB86084A: + case TCIC_CHIPID_DB86184_1: + sc->pwrena = TCIC_PWR_ENA; + break; + default: + sc->pwrena = 0; + break; + } + + /* set up global config registers */ + reg = TCIC_WAIT_SYNC | TCIC_WAIT_CCLK | TCIC_WAIT_RISING; + reg |= (tcic_ns2wscnt(250) & TCIC_WAIT_COUNT_MASK); + tcic_write_aux_1(sc->iot, sc->ioh, TCIC_AR_WCTL, TCIC_R_WCTL_WAIT, reg); + reg = TCIC_SYSCFG_MPSEL_RI | TCIC_SYSCFG_MCSFULL; + tcic_write_aux_2(sc->iot, sc->ioh, TCIC_AR_SYSCFG, reg); + reg = tcic_read_aux_2(sc->iot, sc->ioh, TCIC_AR_ILOCK); + reg |= TCIC_ILOCK_HOLD_CCLK; + tcic_write_aux_2(sc->iot, sc->ioh, TCIC_AR_ILOCK, reg); + + /* the TCIC has two sockets */ + /* XXX should i check for actual presence of sockets? -chb */ + for (i = 0; i < TCIC_NSLOTS; i++) { + sc->handle[i].sc = sc; + sc->handle[i].sock = i; + sc->handle[i].flags = TCIC_FLAG_SOCKETP; + sc->handle[i].memwins + = sc->chipid == TCIC_CHIPID_DB86082_1 ? 4 : 5; + } + + /* establish the interrupt */ + reg = tcic_read_1(&sc->handle[0], TCIC_R_IENA); + tcic_write_1(&sc->handle[0], TCIC_R_IENA, + (reg & ~TCIC_IENA_CFG_MASK) | TCIC_IENA_CFG_HIGH); + reg = tcic_read_aux_2(sc->iot, sc->ioh, TCIC_AR_SYSCFG); + tcic_write_aux_2(sc->iot, sc->ioh, TCIC_AR_SYSCFG, + (reg & ~TCIC_SYSCFG_IRQ_MASK) | tcic_irqmap[sc->irq]); + + /* XXX block interrupts? */ + + for (i = 0; i < TCIC_NSLOTS; i++) { + /* XXX make more clear what happens here -chb */ + tcic_sel_sock(&sc->handle[i]); + tcic_write_ind_2(&sc->handle[i], TCIC_IR_SCF1_N(i), 0); + tcic_write_ind_2(&sc->handle[i], TCIC_IR_SCF2_N(i), + (TCIC_SCF2_MCD|TCIC_SCF2_MWP|TCIC_SCF2_MRDY +#if 1 /* XXX explain byte routing issue */ + |TCIC_SCF2_MLBAT2|TCIC_SCF2_MLBAT1|TCIC_SCF2_IDBR)); +#else + |TCIC_SCF2_MLBAT2|TCIC_SCF2_MLBAT1)); +#endif + tcic_write_1(&sc->handle[i], TCIC_R_MODE, 0); + reg = tcic_read_aux_2(sc->iot, sc->ioh, TCIC_AR_SYSCFG); + reg &= ~TCIC_SYSCFG_AUTOBUSY; + tcic_write_aux_2(sc->iot, sc->ioh, TCIC_AR_SYSCFG, reg); + SIMPLEQ_INIT(&sc->handle[i].events); + } + + if ((sc->handle[0].flags & TCIC_FLAG_SOCKETP) || + (sc->handle[1].flags & TCIC_FLAG_SOCKETP)) { + printf("%s: %s has ", sc->dev.dv_xname, + tcic_chipid_to_string(sc->chipid)); + + if ((sc->handle[0].flags & TCIC_FLAG_SOCKETP) && + (sc->handle[1].flags & TCIC_FLAG_SOCKETP)) + printf("sockets A and B\n"); + else if (sc->handle[0].flags & TCIC_FLAG_SOCKETP) + printf("socket A only\n"); + else + printf("socket B only\n"); + + } +} + +void +tcic_attach_sockets(sc) + struct tcic_softc *sc; +{ + int i; + + for (i = 0; i < TCIC_NSLOTS; i++) + if (sc->handle[i].flags & TCIC_FLAG_SOCKETP) + tcic_attach_socket(&sc->handle[i]); +} + +void +tcic_attach_socket(h) + struct tcic_handle *h; +{ + struct pcmciabus_attach_args paa; + + /* initialize the rest of the handle */ + + h->shutdown = 0; + h->memalloc = 0; + h->ioalloc = 0; + h->ih_irq = 0; + + /* now, config one pcmcia device per socket */ + + paa.paa_busname = "pcmcia"; + paa.pct = (pcmcia_chipset_tag_t) h->sc->pct; + paa.pch = (pcmcia_chipset_handle_t) h; + paa.iobase = h->sc->iobase; + paa.iosize = h->sc->iosize; + + h->pcmcia = config_found_sm(&h->sc->dev, &paa, tcic_print, + tcic_submatch); + + /* if there's actually a pcmcia device attached, initialize the slot */ + + if (h->pcmcia) + tcic_init_socket(h); + else + h->flags &= ~TCIC_FLAG_SOCKETP; +} + +void +tcic_create_event_thread(arg) + void *arg; +{ + struct tcic_handle *h = arg; + const char *cs; + + switch (h->sock) { + case 0: + cs = "0"; + break; + case 1: + cs = "1"; + break; + default: + panic("tcic_create_event_thread: unknown tcic socket"); + } + + if (kthread_create(tcic_event_thread, h, &h->event_thread, + "%s,%s", h->sc->dev.dv_xname, cs)) { + printf("%s: unable to create event thread for sock 0x%02x\n", + h->sc->dev.dv_xname, h->sock); + panic("tcic_create_event_thread"); + } +} + +void +tcic_event_thread(arg) + void *arg; +{ + struct tcic_handle *h = arg; + struct tcic_event *pe; + int s; + + while (h->shutdown == 0) { + s = splhigh(); + if ((pe = SIMPLEQ_FIRST(&h->events)) == NULL) { + splx(s); + (void) tsleep(&h->events, PWAIT, "tcicev", 0); + continue; + } + SIMPLEQ_REMOVE_HEAD(&h->events, pe, pe_q); + splx(s); + + switch (pe->pe_type) { + case TCIC_EVENT_INSERTION: + DPRINTF(("%s: insertion event\n", h->sc->dev.dv_xname)); + tcic_attach_card(h); + break; + + case TCIC_EVENT_REMOVAL: + DPRINTF(("%s: removal event\n", h->sc->dev.dv_xname)); + tcic_detach_card(h, DETACH_FORCE); + break; + + default: + panic("tcic_event_thread: unknown event %d", + pe->pe_type); + } + free(pe, M_TEMP); + } + + h->event_thread = NULL; + + /* In case parent is waiting for us to exit. */ + wakeup(h->sc); + + kthread_exit(0); +} + + +void +tcic_init_socket(h) + struct tcic_handle *h; +{ + int reg; + + /* select this socket's config registers */ + tcic_sel_sock(h); + + /* set up the socket to interrupt on card detect */ + reg = tcic_read_ind_2(h, TCIC_IR_SCF2_N(h->sock)); + tcic_write_ind_2(h, TCIC_IR_SCF2_N(h->sock), reg & ~TCIC_SCF2_MCD); + + /* enable CD irq in R_IENA */ + reg = tcic_read_2(h, TCIC_R_IENA); + tcic_write_2(h, TCIC_R_IENA, reg |= TCIC_IENA_CDCHG); + + /* if there's a card there, then attach it. also save sstat */ + h->sstat = reg = tcic_read_1(h, TCIC_R_SSTAT) & TCIC_SSTAT_STAT_MASK; + if (reg & TCIC_SSTAT_CD) + tcic_attach_card(h); +} + +int +tcic_submatch(parent, match, aux) + struct device *parent; + void *match; + void *aux; +{ + struct cfdata *cf = match; + + struct pcmciabus_attach_args *paa = aux; + struct tcic_handle *h = (struct tcic_handle *) paa->pch; + + switch (h->sock) { + case 0: + if (cf->cf_loc[0 /* PCMCIABUSCF_CONTROLLER */] != + -1 /* PCMCIABUSCF_CONTROLLER_DEFAULT */ && + cf->cf_loc[0 /* PCMCIABUSCF_CONTROLLER */] != 0) + return 0; + if (cf->cf_loc[1 /* PCMCIABUSCF_SOCKET */] != + -1 /* PCMCIABUSCF_SOCKET_DEFAULT */ && + cf->cf_loc[1 /* PCMCIABUSCF_SOCKET */] != 0) + return 0; + + break; + case 1: + if (cf->cf_loc[0 /* PCMCIABUSCF_CONTROLLER */] != + -1 /* PCMCIABUSCF_CONTROLLER_DEFAULT */ && + cf->cf_loc[0 /* PCMCIABUSCF_CONTROLLER */] != 0) + return 0; + if (cf->cf_loc[1 /* PCMCIABUSCF_SOCKET */] != + -1 /* PCMCIABUSCF_SOCKET_DEFAULT */ && + cf->cf_loc[1 /* PCMCIABUSCF_SOCKET */] != 1) + return 0; + + break; + default: + panic("unknown tcic socket"); + } + + return ((*cf->cf_attach->ca_match)(parent, cf, aux)); +} + +int +tcic_print(arg, pnp) + void *arg; + const char *pnp; +{ + struct pcmciabus_attach_args *paa = arg; + struct tcic_handle *h = (struct tcic_handle *) paa->pch; + + /* Only "pcmcia"s can attach to "tcic"s... easy. */ + if (pnp) + printf("pcmcia at %s", pnp); + + switch (h->sock) { + case 0: + printf(" socket 0"); + break; + case 1: + printf(" socket 1"); + break; + default: + panic("unknown tcic socket"); + } + return (UNCONF); +} + +int +tcic_intr(arg) + void *arg; +{ + struct tcic_softc *sc = arg; + int i, ret = 0; + + DPRINTF(("%s: intr\n", sc->dev.dv_xname)); + + for (i = 0; i < TCIC_NSLOTS; i++) + if (sc->handle[i].flags & TCIC_FLAG_SOCKETP) + ret += tcic_intr_socket(&sc->handle[i]); + + return (ret ? 1 : 0); +} + +int +tcic_intr_socket(h) + struct tcic_handle *h; +{ + int icsr, rv; + + rv = 0; + tcic_sel_sock(h); + icsr = tcic_read_1(h, TCIC_R_ICSR); + + DPRINTF(("%s: %d icsr: 0x%02x \n", h->sc->dev.dv_xname, h->sock, icsr)); + + /* XXX or should the next three be handled in tcic_intr? -chb */ + if (icsr & TCIC_ICSR_PROGTIME) { + DPRINTF(("%s: %02x PROGTIME\n", h->sc->dev.dv_xname, h->sock)); + rv = 1; + } + if (icsr & TCIC_ICSR_ILOCK) { + DPRINTF(("%s: %02x ILOCK\n", h->sc->dev.dv_xname, h->sock)); + rv = 1; + } + if (icsr & TCIC_ICSR_ERR) { + DPRINTF(("%s: %02x ERR\n", h->sc->dev.dv_xname, h->sock)); + rv = 1; + } + if (icsr & TCIC_ICSR_CDCHG) { + int sstat, delta; + + /* compute what changed since last interrupt */ + sstat = tcic_read_aux_1(h->sc->iot, h->sc->ioh, + TCIC_AR_WCTL, TCIC_R_WCTL_XCSR) & TCIC_XCSR_STAT_MASK; + delta = h->sstat ^ sstat; + h->sstat = sstat; + + if (delta) + rv = 1; + + DPRINTF(("%s: %02x CDCHG %x\n", h->sc->dev.dv_xname, h->sock, + delta)); + + /* + * XXX This should probably schedule something to happen + * after the interrupt handler completes + */ + + if (delta & TCIC_SSTAT_CD) { + if (sstat & TCIC_SSTAT_CD) { + if (!(h->flags & TCIC_FLAG_CARDP)) { + DPRINTF(("%s: enqueing INSERTION event\n", + h->sc->dev.dv_xname)); + tcic_queue_event(h, TCIC_EVENT_INSERTION); + } + } else { + if (h->flags & TCIC_FLAG_CARDP) { + /* Deactivate the card now. */ + DPRINTF(("%s: deactivating card\n", + h->sc->dev.dv_xname)); + tcic_deactivate_card(h); + + DPRINTF(("%s: enqueing REMOVAL event\n", + h->sc->dev.dv_xname)); + tcic_queue_event(h, TCIC_EVENT_REMOVAL); + } + } + } + if (delta & TCIC_SSTAT_RDY) { + DPRINTF(("%s: %02x READY\n", h->sc->dev.dv_xname, h->sock)); + /* shouldn't happen */ + } + if (delta & TCIC_SSTAT_LBAT1) { + DPRINTF(("%s: %02x LBAT1\n", h->sc->dev.dv_xname, h->sock)); + } + if (delta & TCIC_SSTAT_LBAT2) { + DPRINTF(("%s: %02x LBAT2\n", h->sc->dev.dv_xname, h->sock)); + } + if (delta & TCIC_SSTAT_WP) { + DPRINTF(("%s: %02x WP\n", h->sc->dev.dv_xname, h->sock)); + } + } + return rv; +} + +void +tcic_queue_event(h, event) + struct tcic_handle *h; + int event; +{ + struct tcic_event *pe; + int s; + + pe = malloc(sizeof(*pe), M_TEMP, M_NOWAIT); + if (pe == NULL) + panic("tcic_queue_event: can't allocate event"); + + pe->pe_type = event; + s = splhigh(); + SIMPLEQ_INSERT_TAIL(&h->events, pe, pe_q); + splx(s); + wakeup(&h->events); +} +void +tcic_attach_card(h) + struct tcic_handle *h; +{ + DPRINTF(("tcic_attach_card\n")); + + if (h->flags & TCIC_FLAG_CARDP) + panic("tcic_attach_card: already attached"); + + /* call the MI attach function */ + + pcmcia_card_attach(h->pcmcia); + + h->flags |= TCIC_FLAG_CARDP; +} + +void +tcic_detach_card(h, flags) + struct tcic_handle *h; + int flags; /* DETACH_* */ +{ + DPRINTF(("tcic_detach_card\n")); + + if (!(h->flags & TCIC_FLAG_CARDP)) + panic("tcic_detach_card: already detached"); + + h->flags &= ~TCIC_FLAG_CARDP; + + /* call the MI detach function */ + + pcmcia_card_detach(h->pcmcia, flags); + +} + +void +tcic_deactivate_card(h) + struct tcic_handle *h; +{ + int val, reg; + + if (!(h->flags & TCIC_FLAG_CARDP)) + panic("tcic_deactivate_card: already detached"); + + /* call the MI deactivate function */ + pcmcia_card_deactivate(h->pcmcia); + + tcic_sel_sock(h); + + /* XXX disable card detect resume and configuration reset??? */ + + /* power down the socket */ + tcic_write_1(h, TCIC_R_PWR, 0); + + /* reset the card XXX ? -chb */ + + /* turn off irq's for this socket */ + reg = TCIC_IR_SCF1_N(h->sock); + val = tcic_read_ind_2(h, reg); + tcic_write_ind_2(h, reg, (val & ~TCIC_SCF1_IRQ_MASK)|TCIC_SCF1_IRQOFF); + reg = TCIC_IR_SCF2_N(h->sock); + val = tcic_read_ind_2(h, reg); + tcic_write_ind_2(h, reg, + (val | (TCIC_SCF2_MLBAT1|TCIC_SCF2_MLBAT2|TCIC_SCF2_MRDY + |TCIC_SCF2_MWP|TCIC_SCF2_MCD))); +} + +/* XXX the following routine may need to be rewritten. -chb */ +int +tcic_chip_mem_alloc(pch, size, pcmhp) + pcmcia_chipset_handle_t pch; + bus_size_t size; + struct pcmcia_mem_handle *pcmhp; +{ + struct tcic_handle *h = (struct tcic_handle *) pch; + bus_space_handle_t memh; + bus_addr_t addr; + bus_size_t sizepg; + int i, mask, mhandle; + + /* out of sc->memh, allocate as many pages as necessary */ + + /* + * The TCIC can map memory only in sizes that are + * powers of two, aligned at the natural boundary for the size. + */ + i = tcic_log2((u_int)size); + if ((1<<i) < size) + i++; + sizepg = max(i, TCIC_MEM_SHIFT) - (TCIC_MEM_SHIFT-1); + + DPRINTF(("tcic_chip_mem_alloc: size %ld sizepg %ld\n", size, sizepg)); + + /* can't allocate that much anyway */ + if (sizepg > TCIC_MEM_PAGES) /* XXX -chb */ + return 1; + + mask = (1 << sizepg) - 1; + + addr = 0; /* XXX gcc -Wuninitialized */ + mhandle = 0; /* XXX gcc -Wuninitialized */ + + /* XXX i should be initialised to always lay on boundary. -chb */ + for (i = 0; i < (TCIC_MEM_PAGES + 1 - sizepg); i += sizepg) { + if ((h->sc->subregionmask & (mask << i)) == (mask << i)) { + if (bus_space_subregion(h->sc->memt, h->sc->memh, + i * TCIC_MEM_PAGESIZE, + sizepg * TCIC_MEM_PAGESIZE, &memh)) + return (1); + mhandle = mask << i; + addr = h->sc->membase + (i * TCIC_MEM_PAGESIZE); + h->sc->subregionmask &= ~(mhandle); + break; + } + } + + if (i == (TCIC_MEM_PAGES + 1 - sizepg)) + return (1); + + DPRINTF(("tcic_chip_mem_alloc bus addr 0x%lx+0x%lx\n", (u_long) addr, + (u_long) size)); + + pcmhp->memt = h->sc->memt; + pcmhp->memh = memh; + pcmhp->addr = addr; + pcmhp->size = size; + pcmhp->mhandle = mhandle; + pcmhp->realsize = sizepg * TCIC_MEM_PAGESIZE; + + return (0); +} + +/* XXX the following routine may need to be rewritten. -chb */ +void +tcic_chip_mem_free(pch, pcmhp) + pcmcia_chipset_handle_t pch; + struct pcmcia_mem_handle *pcmhp; +{ + struct tcic_handle *h = (struct tcic_handle *) pch; + + h->sc->subregionmask |= pcmhp->mhandle; +} + +void +tcic_chip_do_mem_map(h, win) + struct tcic_handle *h; + int win; +{ + int reg, hwwin, wscnt; + + int kind = h->mem[win].kind & ~PCMCIA_WIDTH_MEM_MASK; + int mem8 = (h->mem[win].kind & PCMCIA_WIDTH_MEM_MASK) == PCMCIA_WIDTH_MEM8; + DPRINTF(("tcic_chip_do_mem_map window %d: 0x%lx+0x%lx 0x%lx\n", + win, (u_long)h->mem[win].addr, (u_long)h->mem[win].size, + (u_long)h->mem[win].offset)); + /* + * the even windows are used for socket 0, + * the odd ones for socket 1. + */ + hwwin = (win << 1) + h->sock; + + /* the WR_MEXT register is MBZ */ + tcic_write_ind_2(h, TCIC_WR_MEXT_N(hwwin), 0); + + /* set the host base address and window size */ + if (h->mem[win].size2 <= 1) { + reg = ((h->mem[win].addr >> TCIC_MEM_SHIFT) & + TCIC_MBASE_ADDR_MASK) | TCIC_MBASE_4K; + } else { + reg = ((h->mem[win].addr >> TCIC_MEM_SHIFT) & + TCIC_MBASE_ADDR_MASK) | (h->mem[win].size2 >> 1); + } + tcic_write_ind_2(h, TCIC_WR_MBASE_N(hwwin), reg); + + /* set the card address and address space */ + reg = 0; + reg = ((h->mem[win].offset >> TCIC_MEM_SHIFT) & TCIC_MMAP_ADDR_MASK); + reg |= (kind == PCMCIA_MEM_ATTR) ? TCIC_MMAP_ATTR : 0; + DPRINTF(("tcic_chip_do_map_mem window %d(%d) mmap 0x%04x\n", + win, hwwin, reg)); + tcic_write_ind_2(h, TCIC_WR_MMAP_N(hwwin), reg); + + /* set the MCTL register */ + /* must save WSCNT field in case this is a DB86082 rev 0 */ + /* XXX why can't I do the following two in one statement? */ + reg = tcic_read_ind_2(h, TCIC_WR_MCTL_N(hwwin)) & TCIC_MCTL_WSCNT_MASK; + reg |= TCIC_MCTL_ENA|TCIC_MCTL_QUIET; + reg |= mem8 ? TCIC_MCTL_B8 : 0; + reg |= (h->sock << TCIC_MCTL_SS_SHIFT) & TCIC_MCTL_SS_MASK; +#ifdef notyet /* XXX must get speed from CIS somehow. -chb */ + wscnt = tcic_ns2wscnt(h->mem[win].speed); +#else + wscnt = tcic_ns2wscnt(tcic_mem_speed); /* 300 is "save" default for CIS memory */ +#endif + if (h->sc->chipid == TCIC_CHIPID_DB86082_1) { + /* + * this chip has the wait state count in window + * register 7 - hwwin. + */ + int reg2; + reg2 = tcic_read_ind_2(h, TCIC_WR_MCTL_N(7-hwwin)); + reg2 &= ~TCIC_MCTL_WSCNT_MASK; + reg2 |= wscnt & TCIC_MCTL_WSCNT_MASK; + tcic_write_ind_2(h, TCIC_WR_MCTL_N(7-hwwin), reg2); + } else { + reg |= wscnt & TCIC_MCTL_WSCNT_MASK; + } + tcic_write_ind_2(h, TCIC_WR_MCTL_N(hwwin), reg); + +#ifdef TCICDEBUG + { + int r1, r2, r3; + + r1 = tcic_read_ind_2(h, TCIC_WR_MBASE_N(hwwin)); + r2 = tcic_read_ind_2(h, TCIC_WR_MMAP_N(hwwin)); + r3 = tcic_read_ind_2(h, TCIC_WR_MCTL_N(hwwin)); + + DPRINTF(("tcic_chip_do_mem_map window %d(%d): %04x %04x %04x\n", + win, hwwin, r1, r2, r3)); + } +#endif +} + +/* XXX needs work */ +int +tcic_chip_mem_map(pch, kind, card_addr, size, pcmhp, offsetp, windowp) + pcmcia_chipset_handle_t pch; + int kind; + bus_addr_t card_addr; + bus_size_t size; + struct pcmcia_mem_handle *pcmhp; + bus_addr_t *offsetp; + int *windowp; +{ + struct tcic_handle *h = (struct tcic_handle *) pch; + bus_addr_t busaddr; + long card_offset; + int i, win; + + win = -1; + for (i = 0; i < h->memwins; i++) { + if ((h->memalloc & (1 << i)) == 0) { + win = i; + h->memalloc |= (1 << i); + break; + } + } + + if (win == -1) + return (1); + + *windowp = win; + + /* XXX this is pretty gross */ + + if (h->sc->memt != pcmhp->memt) + panic("tcic_chip_mem_map memt is bogus"); + + busaddr = pcmhp->addr; + + /* + * compute the address offset to the pcmcia address space for the + * tcic. this is intentionally signed. The masks and shifts below + * will cause TRT to happen in the tcic registers. Deal with making + * sure the address is aligned, and return the alignment offset. + */ + + *offsetp = card_addr % TCIC_MEM_ALIGN; + card_addr -= *offsetp; + + DPRINTF(("tcic_chip_mem_map window %d bus %lx+%lx+%lx at card addr " + "%lx\n", win, (u_long) busaddr, (u_long) * offsetp, (u_long) size, + (u_long) card_addr)); + + /* XXX we can't use size. -chb */ + /* + * include the offset in the size, and decrement size by one, since + * the hw wants start/stop + */ + size += *offsetp - 1; + + card_offset = (((long) card_addr) - ((long) busaddr)); + + DPRINTF(("tcic_chip_mem_map window %d card_offset 0x%lx\n", + win, (u_long)card_offset)); + + h->mem[win].addr = busaddr; + h->mem[win].size = size; + h->mem[win].size2 = tcic_log2((u_int)pcmhp->realsize) - TCIC_MEM_SHIFT; + h->mem[win].offset = card_offset; + h->mem[win].kind = kind; + + tcic_chip_do_mem_map(h, win); + + return (0); +} + +void +tcic_chip_mem_unmap(pch, window) + pcmcia_chipset_handle_t pch; + int window; +{ + struct tcic_handle *h = (struct tcic_handle *) pch; + int reg, hwwin; + + if (window >= h->memwins) + panic("tcic_chip_mem_unmap: window out of range"); + + hwwin = (window << 1) + h->sock; + reg = tcic_read_ind_2(h, TCIC_WR_MCTL_N(hwwin)); + reg &= ~TCIC_MCTL_ENA; + tcic_write_ind_2(h, TCIC_WR_MCTL_N(hwwin), reg); + + h->memalloc &= ~(1 << window); +} + +int +tcic_chip_io_alloc(pch, start, size, align, pcihp) + pcmcia_chipset_handle_t pch; + bus_addr_t start; + bus_size_t size; + bus_size_t align; + struct pcmcia_io_handle *pcihp; +{ + struct tcic_handle *h = (struct tcic_handle *) pch; + bus_space_tag_t iot; + bus_space_handle_t ioh; + bus_addr_t ioaddr; + int size2, flags = 0; + + /* + * Allocate some arbitrary I/O space. + */ + + DPRINTF(("tcic_chip_io_alloc req 0x%lx %ld %ld\n", + (u_long) start, (u_long) size, (u_long) align)); + /* + * The TCIC can map I/O space only in sizes that are + * powers of two, aligned at the natural boundary for the size. + */ + size2 = tcic_log2((u_int)size); + if ((1 << size2) < size) + size2++; + /* can't allocate that much anyway */ + if (size2 > 16) /* XXX 64K -chb */ + return 1; + if (align) { + if ((1 << size2) != align) + return 1; /* not suitably aligned */ + } else { + align = 1 << size2; /* no alignment given, make it natural */ + } + if (start & (align - 1)) + return 1; /* not suitably aligned */ + + iot = h->sc->iot; + + if (start) { + ioaddr = start; + if (bus_space_map(iot, start, size, 0, &ioh)) + return (1); + DPRINTF(("tcic_chip_io_alloc map port %lx+%lx\n", + (u_long) ioaddr, (u_long) size)); + } else { + flags |= PCMCIA_IO_ALLOCATED; + if (bus_space_alloc(iot, h->sc->iobase, + h->sc->iobase + h->sc->iosize, size, align, 0, 0, + &ioaddr, &ioh)) + return (1); + DPRINTF(("tcic_chip_io_alloc alloc port %lx+%lx\n", + (u_long) ioaddr, (u_long) size)); + } + + pcihp->iot = iot; + pcihp->ioh = ioh; + pcihp->addr = ioaddr; + pcihp->size = size; + pcihp->flags = flags; + + return (0); +} + +void +tcic_chip_io_free(pch, pcihp) + pcmcia_chipset_handle_t pch; + struct pcmcia_io_handle *pcihp; +{ + bus_space_tag_t iot = pcihp->iot; + bus_space_handle_t ioh = pcihp->ioh; + bus_size_t size = pcihp->size; + + if (pcihp->flags & PCMCIA_IO_ALLOCATED) + bus_space_free(iot, ioh, size); + else + bus_space_unmap(iot, ioh, size); +} + +static int tcic_iowidth_map[] = + { TCIC_ICTL_AUTOSZ, TCIC_ICTL_B8, TCIC_ICTL_B16 }; + +void +tcic_chip_do_io_map(h, win) + struct tcic_handle *h; + int win; +{ + int reg, size2, iotiny, wbase, hwwin, wscnt; + + DPRINTF(("tcic_chip_do_io_map win %d addr %lx size %lx width %d\n", + win, (long) h->io[win].addr, (long) h->io[win].size, + h->io[win].width * 8)); + + /* + * the even windows are used for socket 0, + * the odd ones for socket 1. + */ + hwwin = (win << 1) + h->sock; + + /* set the WR_BASE register */ + /* XXX what if size isn't power of 2? -chb */ + size2 = tcic_log2((u_int)h->io[win].size); + DPRINTF(("tcic_chip_do_io_map win %d size2 %d\n", win, size2)); + if (size2 < 1) { + iotiny = TCIC_ICTL_TINY; + wbase = h->io[win].addr; + } else { + iotiny = 0; + /* XXX we should do better -chb */ + wbase = h->io[win].addr | (1 << (size2 - 1)); + } + tcic_write_ind_2(h, TCIC_WR_IBASE_N(hwwin), wbase); + + /* set the WR_ICTL register */ + reg = TCIC_ICTL_ENA | TCIC_ICTL_QUIET; + reg |= (h->sock << TCIC_ICTL_SS_SHIFT) & TCIC_ICTL_SS_MASK; + reg |= iotiny | tcic_iowidth_map[h->io[win].width]; + if (h->sc->chipid != TCIC_CHIPID_DB86082_1) + reg |= TCIC_ICTL_PASS16; +#ifdef notyet /* XXX must get speed from CIS somehow. -chb */ + wscnt = tcic_ns2wscnt(h->io[win].speed); +#else + wscnt = tcic_ns2wscnt(tcic_io_speed); /* linux uses 0 as default */ +#endif + reg |= wscnt & TCIC_ICTL_WSCNT_MASK; + tcic_write_ind_2(h, TCIC_WR_ICTL_N(hwwin), reg); + +#ifdef TCICDEBUG + { + int r1, r2; + + r1 = tcic_read_ind_2(h, TCIC_WR_IBASE_N(hwwin)); + r2 = tcic_read_ind_2(h, TCIC_WR_ICTL_N(hwwin)); + + DPRINTF(("tcic_chip_do_io_map window %d(%d): %04x %04x\n", + win, hwwin, r1, r2)); + } +#endif +} + +int +tcic_chip_io_map(pch, width, offset, size, pcihp, windowp) + pcmcia_chipset_handle_t pch; + int width; + bus_addr_t offset; + bus_size_t size; + struct pcmcia_io_handle *pcihp; + int *windowp; +{ + struct tcic_handle *h = (struct tcic_handle *) pch; + bus_addr_t ioaddr = pcihp->addr + offset; + int i, win; +#ifdef TCICDEBUG + static char *width_names[] = { "auto", "io8", "io16" }; +#endif + + /* XXX Sanity check offset/size. */ + + win = -1; + for (i = 0; i < TCIC_IO_WINS; i++) { + if ((h->ioalloc & (1 << i)) == 0) { + win = i; + h->ioalloc |= (1 << i); + break; + } + } + + if (win == -1) + return (1); + + *windowp = win; + + /* XXX this is pretty gross */ + + if (h->sc->iot != pcihp->iot) + panic("tcic_chip_io_map iot is bogus"); + + DPRINTF(("tcic_chip_io_map window %d %s port %lx+%lx\n", + win, width_names[width], (u_long) ioaddr, (u_long) size)); + + /* XXX wtf is this doing here? */ + + printf(" port 0x%lx", (u_long) ioaddr); + if (size > 1) + printf("-0x%lx", (u_long) ioaddr + (u_long) size - 1); + + h->io[win].addr = ioaddr; + h->io[win].size = size; + h->io[win].width = width; + + tcic_chip_do_io_map(h, win); + + return (0); +} + +void +tcic_chip_io_unmap(pch, window) + pcmcia_chipset_handle_t pch; + int window; +{ + struct tcic_handle *h = (struct tcic_handle *) pch; + int reg, hwwin; + + if (window >= TCIC_IO_WINS) + panic("tcic_chip_io_unmap: window out of range"); + + hwwin = (window << 1) + h->sock; + reg = tcic_read_ind_2(h, TCIC_WR_ICTL_N(hwwin)); + reg &= ~TCIC_ICTL_ENA; + tcic_write_ind_2(h, TCIC_WR_ICTL_N(hwwin), reg); + + h->ioalloc &= ~(1 << window); +} + +void +tcic_chip_socket_enable(pch) + pcmcia_chipset_handle_t pch; +{ + struct tcic_handle *h = (struct tcic_handle *) pch; + int cardtype, reg, win; + + tcic_sel_sock(h); + + /* + * power down the socket to reset it. + * put card reset into high-z, put chip outputs to card into high-z + */ + + tcic_write_1(h, TCIC_R_PWR, 0); + reg = tcic_read_aux_2(h->sc->iot, h->sc->ioh, TCIC_AR_ILOCK); + reg |= TCIC_ILOCK_CWAIT; + reg &= ~(TCIC_ILOCK_CRESET|TCIC_ILOCK_CRESENA); + tcic_write_aux_2(h->sc->iot, h->sc->ioh, TCIC_AR_ILOCK, reg); + tcic_write_1(h, TCIC_R_SCTRL, 0); /* clear TCIC_SCTRL_ENA */ + + /* power up the socket */ + + /* turn on VCC, turn of VPP */ + reg = TCIC_PWR_VCC_N(h->sock) | TCIC_PWR_VPP_N(h->sock) | h->sc->pwrena; + if (h->sc->pwrena) /* this is a '84 type chip */ + reg |= TCIC_PWR_VCC5V; + tcic_write_1(h, TCIC_R_PWR, reg); + delay(10000); + + /* enable reset and wiggle it to reset the card */ + reg = tcic_read_aux_2(h->sc->iot, h->sc->ioh, TCIC_AR_ILOCK); + reg |= TCIC_ILOCK_CRESENA; + tcic_write_aux_2(h->sc->iot, h->sc->ioh, TCIC_AR_ILOCK, reg); + /* XXX need bus_space_barrier here */ + reg |= TCIC_ILOCK_CRESET; + tcic_write_aux_2(h->sc->iot, h->sc->ioh, TCIC_AR_ILOCK, reg); + /* enable card signals */ + tcic_write_1(h, TCIC_R_SCTRL, TCIC_SCTRL_ENA); + delay(10); /* wait 10 us */ + + /* clear the reset flag */ + reg = tcic_read_aux_2(h->sc->iot, h->sc->ioh, TCIC_AR_ILOCK); + reg &= ~(TCIC_ILOCK_CRESET); + tcic_write_aux_2(h->sc->iot, h->sc->ioh, TCIC_AR_ILOCK, reg); + + /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */ + delay(20000); + + /* wait for the chip to finish initializing */ + tcic_wait_ready(h); + + /* WWW */ + /* zero out the address windows */ + + /* writing to WR_MBASE_N disables the window */ + for (win = 0; win < h->memwins; win++) { + tcic_write_ind_2(h, TCIC_WR_MBASE_N((win<<1)+h->sock), 0); + } + /* writing to WR_IBASE_N disables the window */ + for (win = 0; win < TCIC_IO_WINS; win++) { + tcic_write_ind_2(h, TCIC_WR_IBASE_N((win<<1)+h->sock), 0); + } + + /* set the card type */ + + cardtype = pcmcia_card_gettype(h->pcmcia); + +#if 0 + reg = tcic_read_ind_2(h, TCIC_IR_SCF1_N(h->sock)); + reg &= ~TCIC_SCF1_IRQ_MASK; +#else + reg = 0; +#endif + reg |= ((cardtype == PCMCIA_IFTYPE_IO) ? + TCIC_SCF1_IOSTS : 0); + reg |= tcic_irqmap[h->ih_irq]; /* enable interrupts */ + reg &= ~TCIC_SCF1_IRQOD; + tcic_write_ind_2(h, TCIC_IR_SCF1_N(h->sock), reg); + + DPRINTF(("%s: tcic_chip_socket_enable %d cardtype %s 0x%02x\n", + h->sc->dev.dv_xname, h->sock, + ((cardtype == PCMCIA_IFTYPE_IO) ? "io" : "mem"), reg)); + + /* reinstall all the memory and io mappings */ + + for (win = 0; win < h->memwins; win++) + if (h->memalloc & (1 << win)) + tcic_chip_do_mem_map(h, win); + + for (win = 0; win < TCIC_IO_WINS; win++) + if (h->ioalloc & (1 << win)) + tcic_chip_do_io_map(h, win); +} + +void +tcic_chip_socket_disable(pch) + pcmcia_chipset_handle_t pch; +{ + struct tcic_handle *h = (struct tcic_handle *) pch; + int val; + + DPRINTF(("tcic_chip_socket_disable\n")); + + tcic_sel_sock(h); + + /* disable interrupts */ + val = tcic_read_ind_2(h, TCIC_IR_SCF1_N(h->sock)); + val &= TCIC_SCF1_IRQ_MASK; + tcic_write_ind_2(h, TCIC_IR_SCF1_N(h->sock), val); + + /* disable the output signals */ + tcic_write_1(h, TCIC_R_SCTRL, 0); + val = tcic_read_aux_2(h->sc->iot, h->sc->ioh, TCIC_AR_ILOCK); + val &= ~TCIC_ILOCK_CRESENA; + tcic_write_aux_2(h->sc->iot, h->sc->ioh, TCIC_AR_ILOCK, val); + + /* power down the socket */ + tcic_write_1(h, TCIC_R_PWR, 0); +} + +/* + * XXX The following is Linux driver but doesn't match the table + * in the manual. + */ +int +tcic_ns2wscnt(ns) + int ns; +{ + if (ns < 14) { + return 0; + } else { + return (2*(ns-14))/70; /* XXX assumes 14.31818 MHz clock. */ + } +} + +int +tcic_log2(val) + u_int val; +{ + int i, l2; + + l2 = i = 0; + while (val) { + if (val & 1) + l2 = i; + i++; + val >>= 1; + } + return l2; +} diff --git a/sys/dev/ic/tcic2reg.h b/sys/dev/ic/tcic2reg.h new file mode 100644 index 00000000000..567c4708228 --- /dev/null +++ b/sys/dev/ic/tcic2reg.h @@ -0,0 +1,827 @@ +/* $OpenBSD: tcic2reg.h,v 1.1 2000/05/15 04:17:28 jason Exp $ */ +/* $NetBSD: tcic2reg.h,v 1.1 1999/03/23 20:04:14 bad Exp $ */ + +/*- + * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christoph Badura. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * All information is from the Databook DB86082 TCIC PC Card Controller for + * Notebook PCs -- Hardware Design Guide, March 22, 1994. + */ + +#ifndef _TCIC2REG_H +#define _TCIC2REG_H +#define TCIC_IOSIZE 16 + +/* TCIC primary registers */ +#define TCIC_R_DATA 0 /* Data register, 16 bit */ +#define TCIC_R_ADDR 2 /* Address register, 32 bit */ +#define TCIC_R_ADDR2 (TCIC_R_ADDR+2) /* high word of addr. reg. */ +#define TCIC_R_SCTRL 6 /* Socket control reg., 8 bit */ +#define TCIC_R_SSTAT 7 /* Socket status reg., 8 bit */ +#define TCIC_R_MODE 8 /* Mode register, 8 bit */ +#define TCIC_R_PWR 9 /* Power control reg., 8 bit */ +#define TCIC_R_EDC 0xA /* Error detect code, 16 bit */ +#define TCIC_R_ICSR 0xC /* Interrupt ctrl/status, 8 bit */ +#define TCIC_R_IENA 0xD /* Interrupt enable, 8 bit */ +#define TCIC_R_AUX 0xE /* Auxiliary Register, 16 bit */ + +/* + * TCIC auxiliary registers. + * These are all 16 bit registers. + * They are accessed by selecting the approriate index in + * bits 7:5 of the mode register. + */ +#define TCIC_AR_MASK 0xe0 /* for masking the mode reg. */ +#define TCIC_AR_TCTL 0x00 /* timing control register */ +#define TCIC_AR_PCTL 0x20 /* programming pulse ctrl. */ +#define TCIC_AR_WCTL 0x40 /* wait state control */ +#define TCIC_AR_EXTERN 0x60 /* external access */ +#define TCIC_AR_PDATA 0x80 /* programming data */ +#define TCIC_AR_SYSCFG 0xA0 /* system configuration */ +#define TCIC_AR_ILOCK 0xC0 /* interlock control/status */ +#define TCIC_AR_TEST 0xE0 /* test */ + +/* + * TCIC indirect registers. + * These are all 16 bit. + * They are accessed by selecting the appropriate address in + * bits 9:0 of the address register with indirect register access mode + * enabled. + */ +#define TCIC_WR_MEM_BASE 0x100 /* base address */ +#define TCIC_WR_MEM_SHFT 3 /* log2 size of one reg set */ +#define TCIC_WR_MEXT_N(n) ((TCIC_WR_MEM_BASE+((n)<<TCIC_WR_MEM_SHFT))+0) +#define TCIC_WR_MBASE_N(n) ((TCIC_WR_MEM_BASE+((n)<<TCIC_WR_MEM_SHFT))+2) +#define TCIC_WR_MMAP_N(n) ((TCIC_WR_MEM_BASE+((n)<<TCIC_WR_MEM_SHFT))+4) +#define TCIC_WR_MCTL_N(n) ((TCIC_WR_MEM_BASE+((n)<<TCIC_WR_MEM_SHFT))+6) + +#define TCIC_WR_IO_BASE 0x200 /* base address */ +#define TCIC_WR_IO_SHFT 2 /* log2 size of one reg set */ +#define TCIC_WR_IBASE_N(n) ((TCIC_WR_IO_BASE+((n)<<TCIC_WR_IO_SHFT))+0) +#define TCIC_WR_ICTL_N(n) ((TCIC_WR_IO_BASE+((n)<<TCIC_WR_IO_SHFT))+2) + +#define TCIC_IR_SCF_BASE 0 /* base address */ +#define TCIC_IR_SCF_SHFT 3 /* log2 size of one reg set */ +#define TCIC_IR_SCF1_N(n) ((TCIC_IR_SCF_BASE+((n)<<TCIC_IR_SCF_SHFT))+0) +#define TCIC_IR_SCF2_N(n) ((TCIC_IR_SCF_BASE+((n)<<TCIC_IR_SCF_SHFT))+2) + + +/* Bits in the ADDR2 register */ +#define TCIC_SS_SHIFT 12 /* location of socket select bits */ +#define TCIC_SS_MASK (7<<(TCIC_SS_SHIFT)) /* socket select mask */ + +#define TCIC_ADDR2_REG (1 << 15) /* select REG space */ +#define TCIC_ADDR2_SS_SHFT TCIC_SS_SHIFT /* select sockets the usual way */ +#define TCIC_ADDR2_SS_MASK TCIC_SS_MASK /* ditto */ +#define TCIC_ADDR2_INDREG (1 << 11) /* access indirect registers + * (not card data) + */ +#define TCIC_ADDR2_IO (1 << 10) /* select I/O cycles, readback + * card /IORD, /IOWR in diag- + * nostic mode. + */ + +/* Bits in address register */ +#define TCIC_ADDR_REG (u_int32_t) TCIC_ADDR2_REG << 16) /* OR with this for REG space */ +#define TCIC_ADDR_SS_SHFT ((u_int32_t) TCIC_ADDR2_SS_SHFT + 16) + /* shift count, cast so that + * you'll get the right type + * if you use it but forget + * to cast the left arg. + */ +#define TCIC_ADDR_SS_MASK ((u_int32_t) TCIC_ADDR2_SS_MASK << 16) +#define TCIC_ADDR_INDREG ((u_int32_t) TCIC_ADDR2_INDREG << 16) +#define TCIC_ADDR_IO ((u_int32_t) TCIC_ADDR2_IO << 16) + +#define TCIC_ADDR_SPACE_SIZE ((u_int32_t) 1 << 26) +#define TCIC_ADDR_MASK (ADDR_SPACE_SIZE - 1) + +/* The following bits are defined in diagnostic mode */ +#define TCIC_ADDR_DIAG_NREG ((u_int32_t) 1 << 31) /* inverted! */ +#define TCIC_ADDR_DIAG_NCEH ((u_int32_t) 1 << 30) +#define TCIC_ADDR_DIAG_NCEL ((u_int32_t) 1 << 29) +#define TCIC_ADDR_DIAG_NCWR ((u_int32_t) 1 << 28) +#define TCIC_ADDR_DIAG_NCRD ((u_int32_t) 1 << 27) +#define TCIC_ADDR_DIAG_CRESET ((u_int32_t) 1 << 26) + +/* Bits in socket control register */ +#define TCIC_SCTRL_ENA (1 << 0) /* enable access to card */ +#define TCIC_SCTRL_INCMODE (3 << 3) /* mask for increment mode: */ +#define TCIC_SCTRL_INCMODE_AUTO (3 << 3) /* auto-increment mode */ +#define TCIC_SCTRL_INCMODE_HOLD (0 << 3) /* byte hold mode */ +#define TCIC_SCTRL_INCMODE_WORD (1 << 3) /* word hold mode */ +#define TCIC_SCTRL_INCMODE_REG (2 << 3) /* reg-space increment mode */ +#define TCIC_SCTRL_EDCSUM (1 << 5) /* if set, use checksum (not CRC) */ +#define TCIC_SCTRL_RESET (1 << 7) /* internal software reset */ +#define TCIC_SCTRL_RSVD 0x46 /* reserved bits, MBZ */ + +/* Bits in the socket status register */ +#define TCIC_SSTAT_6US (1<<0) /* 6 usec have elapsed */ +#define TCIC_SSTAT_10US (1<<1) /* 10 usec have elapsed */ +#define TCIC_SSTAT_PROGTIME (1<<2) /* programming pulse timeout */ +#define TCIC_SSTAT_LBAT1 (1<<3) /* low battery 1 */ +#define TCIC_SSTAT_LBAT2 (1<<4) /* low battery 2 */ +#define TCIC_SSTAT_BATOK (0<<3) /* battery is OK */ +#define TCIC_SSTAT_BATBAD1 (1<<3) /* battery is low */ +#define TCIC_SSTAT_BATLO (2<<3) /* battery is getting low */ +#define TCIC_SSTAT_BATBAD2 (3<<3) /* battery is low */ +#define TCIC_SSTAT_RDY (1<<5) /* card is ready (not busy) */ +#define TCIC_SSTAT_WP (1<<6) /* card is write-proteced */ +#define TCIC_SSTAT_CD (1<<7) /* card present */ +#define TCIC_SSTAT_STAT_MASK 0xf8 + +/* Mode register contents (R_MODE) */ +#define TCIC_MODE_PGMMASK (0x1F) /* the programming mode bits */ +#define TCIC_MODE_NORMAL (0) /* normal mode */ +#define TCIC_MODE_PGMWR (1 << 0) /* assert /WR */ +#define TCIC_MODE_PGMRD (1 << 1) /* assert /RD */ +#define TCIC_MODE_PGMCE (1 << 2) /* assert /CEx */ +#define TCIC_MODE_PGMDBW (1 << 3) /* databus in write mode */ +#define TCIC_MODE_PGMWORD (1 << 4) /* word programming mode */ + +/* Power control register contents (R_PWR) */ +#define TCIC_PWR_VCC_SHFT (0) /* the VCC ctl shift */ +#define TCIC_PWR_VCC_MASK (3 << TCIC_PWR_VCC_SHFT) + +#define TCIC_PWR_VPP_SHFT (3) /* the VPP ctl shift */ +#define TCIC_PWR_VPP_MASK (3 << TCIC_PWR_VPP_SHFT) +#define TCIC_PWR_ENA (1 << 5) /* on 084, successors, this + * must be set to turn on + * power. + */ +#define TCIC_PWR_VCC5V (1 << 2) /* enable +5 (not +3) */ +#if 0 +#define TCIC_PWR_VOFF_POFF (0) /* turn off VCC, VPP */ +#define TCIC_PWR_VON_PVCC (1) /* turn on VCC, VPP=VCC */ +#define TCIC_PWR_VON_PVPP (2) /* turn on VCC, VPP=12V */ +#define TCIC_PWR_VON_POFF (3) /* turn on VCC, VPP=0V */ +#endif +#define TCIC_PWR_VCC_N(n) (1<<((n))) /* VCCSEL for socket n */ +#define TCIC_PWR_VPP_N(n) (1<<(3+(n))) /* VPPSEL for socket n */ + +#define TCIC_PWR_CLIMENA (1 << 6) /* the current-limit enable */ +#define TCIC_PWR_CLIMSTAT (1 << 7) /* current limit sense (r/o) */ + +/* Bits in the icsr reqister. */ +#define TCIC_ICSR_IOCHK (1<<7) /* I/O check */ +#define TCIC_ICSR_CDCHG (1<<6) /* card status change, see SSTAT */ +#define TCIC_ICSR_ERR (1<<5) /* error condition */ +#define TCIC_ICSR_PROGTIME (1<<4) /* program timer ding */ +#define TCIC_ICSR_ILOCK (1<<3) /* interlock change */ +#define TCIC_ICSR_STOPCPU (1<<2) /* Stop CPU was asserted */ +#define TCIC_ICSR_SET (1<<1) /* (w/o) enable writes that set bits */ +#define TCIC_ICSR_CLEAR (1<<0) /* (w/o) enable writes that clear */ +#define TCIC_ICSR_JAM (TCIC_ICSR_SET|TCIC_ICSR_CLEAR) + /* jam value into ICSR */ + +/* bits in the interrupt enable register */ +#define TCIC_IENA_CDCHG (1 << 6) /* enable INT when ICSR_CDCHG is set */ +#define TCIC_IENA_ERR (1 << 5) /* enable INT when ICSR_ERR is set */ +#define TCIC_IENA_PROGTIME (1 << 4) /* enable INT when ICSR_PROGTIME " */ +#define TCIC_IENA_ILOCK (1 << 3) /* enable INT when ICSR_ILOCK is set */ +#define TCIC_IENA_CFG_MASK (3 << 0) /* select the bits for IRQ config: */ +#define TCIC_IENA_CFG_OFF (0 << 0) /* IRQ is high-impedance */ +#define TCIC_IENA_CFG_OD (1 << 0) /* IRQ is active low, open drain. */ +#define TCIC_IENA_CFG_LOW (2 << 0) /* IRQ is active low, totem pole */ +#define TCIC_IENA_CFG_HIGH (3 << 0) /* IRQ is active high, totem pole */ +#define TCIC_IENA_RSVD 0x84 /* reserved bits, MBZ */ + + +/* + * Bits in the auxiliary registers + */ + +/* Bits in the timing control register (AR_TCTL) */ +#define TCIC_TCTL_6US_SHFT (0) /* the shift count for the 6 us ctr */ +#define TCIC_TCTL_10US_SHFT (8) /* the shift count for the 10 us ctr */ +#define TCIC_TCTL_6US_MASK (0xFF << TCIC_TCTL_6US_SHFT) +#define TCIC_TCTL_10US_MASK (0xFF << TCIC_TCTL_10US_SHFT) + +#define TCIC_R_TCTL_6US (TCIC_R_AUX + 0) /* the byte access handle */ +#define TCIC_R_TCTL_10US (TCIC_R_AUX + 1) /* the byte access handle */ + +/* Bits in the programming pulse register (AR_PCTL) */ +#define TCIC_R_PULSE_LO (TCIC_R_AUX + 0) +#define TCIC_R_PULSE_HI (TCIC_R_AUX + 1) + +/* Bits in the wait state control register (AR_WCTL) */ +#define TCIC_WAIT_COUNT_MASK (0x1F) /* the count of 1/2 wait states */ +#define TCIC_WAIT_COUNT_SHFT (0) /* the wait-count shift */ +#define TCIC_WAIT_SYNC (1 << 5) /* set for synch, clear for asynch cycles */ +#define TCIC_WAIT_ASYNC (0) + +#define TCIC_WAIT_SENSE (1 << 6) /* select rising (1) or falling (0) + * edge of wait clock as reference + * edge. + */ +#define TCIC_WAIT_SRC (1 << 7) /* select constant clock (0) or bus + * clock (1) as the timing source + */ + +/* Some derived constants */ +#define TCIC_WAIT_BCLK (1 * TCIC_WAIT_SRC) +#define TCIC_WAIT_CCLK (0 * TCIC_WAIT_SRC) +#define TCIC_WAIT_RISING (1 * TCIC_WAIT_SENSE) +#define TCIC_WAIT_FALLING (0 * TCIC_WAIT_SENSE) + +/* high byte */ +#define TCIC_WCTL_WR (1 << 8) /* control: pulse write */ +#define TCIC_WCTL_RD (1 << 9) /* control: pulse read */ +#define TCIC_WCTL_CE (1 << 10) /* control: pulse chip ena */ +#define TCIC_WCTL_LLBAT1 (1 << 11) /* status: latched LBAT1 */ +#define TCIC_WCTL_LLBAT2 (1 << 12) /* status: latched LBAT2 */ +#define TCIC_WCTL_LRDY (1 << 13) /* status: latched RDY */ +#define TCIC_WCTL_LWP (1 << 14) /* status: latched WP */ +#define TCIC_WCTL_LCD (1 << 15) /* status: latched CD */ + +/* The same thing, from a byte perspective */ +#define TCIC_R_WCTL_WAIT (TCIC_R_AUX + 0) /* the wait state control byte */ +#define TCIC_R_WCTL_XCSR (TCIC_R_AUX + 1) /* extended control/status */ + +#define TCIC_XCSR_WR (1 << 0) /* control: pulse write */ +#define TCIC_XCSR_RD (1 << 1) /* control: pulse read */ +#define TCIC_XCSR_CE (1 << 2) /* control: pulse chip ena */ +#define TCIC_XCSR_LLBAT1 (1 << 3) /* status: latched LBAT1 */ +#define TCIC_XCSR_LLBAT2 (1 << 4) /* status: latched LBAT2 */ +#define TCIC_XCSR_LRDY (1 << 5) /* status: latched RDY */ +#define TCIC_XCSR_LWP (1 << 6) /* status: latched WP */ +#define TCIC_XCSR_LCD (1 << 7) /* status: latched CD */ +#define TCIC_XCSR_STAT_MASK 0xf8 + +/* Bits in the programming data register (AR_PDATA) */ +#define TCIC_R_PDATA_LO (TCIC_R_AUX + 0) +#define TCIC_R_PDATA_HI (TCIC_R_AUX + 1) + +/* Bits in the system configuration register (AR_SYSCFG) */ +/* + * The bottom four bits specify the steering of the socket IRQ. On + * the 2N, the socket IRQ is (by default) pointed at the dedicated + * pin. + */ +#define TCIC_SYSCFG_IRQ_MASK (0xF) /* mask for this bit field. */ +#define TCIC_SYSCFG_SSIRQDFLT (0) /* default: use SKTIRQ (2/N) + * disable (2/P) + */ +#define TCIC_SYSCFG_SSIRQ (0x1) /* use SKTIRQ (explicit) (2/N) + * do not use (2/P) + */ +#define TCIC_SYSCFG_SIRQ3 (0x3) /* use IRQ3 */ +#define TCIC_SYSCFG_SIRQ4 (0x4) /* use IRQ4 */ +#define TCIC_SYSCFG_SIRQ5 (0x5) /* use IRQ5 (2/N) */ +#define TCIC_SYSCFG_SIRQ6 (0x6) /* use IRQ6 (2/N) */ +#define TCIC_SYSCFG_SIRQ7 (0x7) /* use IRQ7 (2/N) */ +#define TCIC_SYSCFG_SIRQ10 (0xA) /* use IRQ10 */ +#define TCIC_SYSCFG_SIRQ14 (0xE) /* use IRQ14 */ + +#define TCIC_SYSCFG_MCSFULL (1 << 4) + /* + * If set, use full address (a[12:23]) for MCS16 generation. + * If clear, run in ISA-compatible mode (only using a[17:23]). + * With many chip sets, the TCIC-2/N's timing will will allow full + * address decoding to be used rather than limiting us to LA[17:23]; + * thus we can get around the ISA spec which limits the granularity + * of bus sizing to 128K blocks. + */ +#define TCIC_SYSCFG_IO1723 (1 << 5) + /* + * Flag indicating that LA[17:23] can be trusted to be zero during a + * true I/O cycle. Setting this bit will allow us to reduce power + * consumption further by eliminating I/O address broadcasts for + * memory cycles. + * + * Unfortunately, you cannot trust LA[17:23] to be zero on all systems, + * because the ISA specs do not require that LA[17:23] be zero when an + * alternate bus master runs an I/O cycle. However, on a palmtop or + * notebook, it is a good guess. + */ + +#define TCIC_SYSCFG_MCSXB (1 << 6) + /* + * If set, assume presence of an external buffer for MCS16: operate + * the driver as a totem-pole output. + * + * If clear, run in pseudo-ISA mode; output is open drain. But note + * that on the 082 the output buffers cannot drive a 300-ohm + * load. + */ +#define TCIC_SYSCFG_ICSXB (1 << 7) + /* + * If set, assume presence of an external buffer for IOCS16*; operate + * the buffer as a totem-pole output. + * + * If clear, run in pseudo-ISA mode; output is open drain. But note + * that on the 082 the output buffers cannot drive a 300-ohm + * load. + */ +#define TCIC_SYSCFG_NOPDN (1 << 8) + /* + * If set, disable the auto power-down sequencing. The chip will + * run card cycles somewhat more quickly (though perhaps not + * significantly so); but it will dissipate significantly more power. + * + * If clear, the low-power operating modes are enabled. This + * causes the part to go into low-power mode automatically at + * system reset. + */ +#define TCIC_SYSCFG_MPSEL_SHFT (9) +#define TCIC_SYSCFG_MPSEL_MASK (7 << 9) + /* + * This field controls the operation of the multipurpose pin on the + * 86082. It has the following codes: + */ +#define TCIC_SYSCFG_MPSEL_OFF (0 << TCIC_SYSCFG_MPSEL_SHFT) + /* + * This is the reset state; it indicates that the Multi-purpose + * pin is not used. The pin will be held in a high-impedance + * state. It can be read by monitoring SYSCFG_MPSENSE. + */ +#define TCIC_SYSCFG_MPSEL_NEEDCLK (1 << TCIC_SYSCFG_MPSEL_SHFT) + /* + * NMULTI is an output. + * External indication that CCLK or BCLK are needed in order + * to complete an internal operation. External logic can use + * this to control the clocks coming to the chip. + */ +#define TCIC_SYSCFG_MPSEL_MIO (2 << TCIC_SYSCFG_MPSEL_SHFT) + /* + * NMULTI is an input; it is an unambiguous M/IO signal, issued + * with timing similar to the LA[] lines. + */ +#define TCIC_SYSCFG_MPSEL_EXTSEL (3 << TCIC_SYSCFG_MPSEL_SHFT) + /* + * NMULTI is an output; it is the external register select + * pulse, generated whenever software attempts to access + * aux register AR_EXTRN. Of course, the 86082 will ignore + * writes to AR_EXTRN, and will float the data bus if + * the CPU reads from AR_EXTRN. + */ + +/* (4 << TCIC_SYSCFG_MPSEL_SHFT) is reserved */ + +#define TCIC_SYSCFG_MPSEL_RI (5 << TCIC_SYSCFG_MPSEL_SHFT) + /* + * NMULTI is an output; it indicates a RI (active-going) + * transition has occurred lately on a an appropriately- + * configured socket. The output is active low. + */ +/* + * Codes 4, 6 and 7 are reserved, and must NOT be output. It is + * indeed possibly hazardous to your system to encode values in + * this field that do not match your hardware! + */ + +/* 1 << 12 reserved */ + +#define TCIC_SYSCFG_MPSENSE (1 << 13) + /* + * This bit, when read, returns the sense of the multi-purpose pin. + */ + +#define TCIC_SYSCFG_AUTOBUSY (1 << 14) + /* + * This bit, when set, causes the busy led to be gated with the + * SYSCFG_ACC bit. When clear, the busy led reflects whether the + * socket is actually enabled. If AUTOBUSY is set and ACC is clear, + * then the busy light will be off, even if a socket is enabled. + * If AUTOBUSY is clear, then the busy light will be on if either + * socket is enabled. + * + * Note, that when in a programming mode, you should either clear this + * bit (causing the busy light to be on whenever the socket is enabled) + * or set both this bit and the ACC bit (causing the light to be on + * all the time). + * + * On the '084 and '184, this bit is per-socket. + */ + +#define TCIC_SYSCFG_ACC (1<<15) + /* + * This bit will be set automatically by the hardware whenever the CPU + * accesses data on a card. It can be cleared under software control. + * + * In AUTOBUSY mode, it has the additional effect of turning on the + * busy light. + * + * Since we'll tristate the command lines as the card is going out of + * the socket, and since the shared lines idle low, there's no real + * danger if the busy light is off even though the socket is enabled. + * + * On the '084 and '184, this bit is per-socket. + */ + + +/* Bits in the ilock aux. register. */ +#define TCIC_ILOCK_OUT (1 << 0) /* interlock output + * per-socket on x84 + */ +#define TCIC_ILOCK_SENSE (1 << 1) /* (r/o) interlock sense + * 0 -> /cilock not asserted; + * 1 -> /cilock is asserted. + * per-socket on x84. + */ +#define TCIC_ILOCK_CRESET (1 << 2) /* card reset output level(S) */ +#define TCIC_ILOCK_CRESENA (1 << 3) /* enable card reset output (S) */ +#define TCIC_ILOCK_CWAIT (1 << 4) /* enable card wait (S) */ +#define TCIC_ILOCK_CWAITSNS (1 << 5) /* (r/o) sense current state of wait + * 0 -> /cwait not asserted; + * 1 -> /cwait is asserted + * (S) + */ +/* The shift count & mask for the hold-time control */ +#define TCIC_ILOCK_HOLD_SHIFT 6 /* shift count for the hold-time ctl (G) */ +#define TCIC_ILOCK_HOLD_MASK (3 << TCIC_ILOCK_HOLD_SHIFT) + +/* + * Quick hold mode waits until we observe that the strobe is high, + * guaranteeing 10ns or so of hold time. + */ +#define TCIC_ILOCK_HOLD_QUICK (0 << TCIC_ILOCK_HOLD_SHIFT) + +/* + * CCLK hold mode waits (asynchronously) for an edge on CCLK. Minimum is 1 + * CCLK + epsilon; maximum is 2 CCLKs + epsilon. + * + * for the 86081 & '82, this mode enables the multi-step + * sequencer that generates setup and hold times based on CCLK. This + * is the recommended mode of operation for the '81 and '82. + * + */ +#define TCIC_ILOCK_HOLD_CCLK (3 << TCIC_ILOCK_HOLD_SHIFT) + +/* The following bits are only present on the x84 and later parts */ +#define TCIC_ILOCK_INPACK (1 << 11) /* (r/o, S) this bit is a diagnostic + * read-back for card input + * acknowledge. + * The sense is inverted from + * the level at the pin. + */ +#define TCIC_ILOCK_CP0 (1 << 12) /* (r/o, S) this bit is a diagnostic + * monitor for card present pin 0. + * The sense is inverted from the + * level at the pin. + */ +#define TCIC_ILOCK_CP1 (1 << 13) /* (r/o, S) this bit is a diagnostic + * monitor for card present pin 1. + * The sense is inverted from the + * level at the pin. + */ +#define TCIC_ILOCK_VS1 (1 << 14) /* (r/o, S) this bit is the primary + * monitor for Card Voltage Sense + * pin 1. + * The sense is inverted from the + * level at the pin. + */ +#define TCIC_ILOCK_VS2 (1 << 15) /* (r/o, S) this bit is the primary + * monitor for Card Voltage Sense + * pin 2. + * The sense is inverted from the + * level at the pin. + */ +/* + * Silicon Version Register + * + * In diagnostic mode, the high byte of the interlock register is defined + * as the silicon identity byte. + * + * In order to read this byte, the chip must be placed in diagnostic + * mode by setting bit 15 of the TESTDIAG register. (This may or may + * not be enforced by the silicon.) + * + * The layout is: + * + * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + * m <-------ID-------> <----ILOCK----> + * + * The fields are: + * + * m Always reset. + * + * ID This field is one of the following: + * + * 0x02 the db86082 + * 0x03 the db86082a + * 0x04 the db86084 + * 0x05 the DB86072ES, (Engineering Sample) + * 0x07 the db86082bES, (Engineering Sample) + * 0x08 the db86084a + * 0x14 the DB86184 + * 0x15 the DB86072, (Production) + * 0x17 the db86082b, (Production) + */ + +/* + * Defines for Chip IDs described above. + * + * Use the following convention for defining TCIC_CHIPID_DBxxxxxY: + * + * TCIC_CHIPID_DBxxxxx_1 The First step of chip. + * TCIC_CHIPID_DBxxxxxA The Second step of chip. + * TCIC_CHIPID_DBxxxxxB The Third step of chip. + * TCIC_CHIPID_DBxxxxx... The ... step of chip. + * + * TCIC_CHIPID_DBxxxxx"step of chip"_ES An Engineering Sample of chip. + * + */ +#define TCIC_CHIPID_DB86082_1 (0x02) +#define TCIC_CHIPID_DB86082A (0x03) +#define TCIC_CHIPID_DB86082B_ES (0x07) +#define TCIC_CHIPID_DB86082B (0x17) + +#define TCIC_CHIPID_DB86084_1 (0x04) +#define TCIC_CHIPID_DB86084A (0x08) + +#define TCIC_CHIPID_DB86184_1 (0x14) + +#define TCIC_CHIPID_DB86072_1_ES (0x05) +#define TCIC_CHIPID_DB86072_1 (0x15) + + +/* the high order bits (in diag mode) give the chip version */ +#define TCIC_R_ILOCK_ID (TCIC_R_AUX + 1) + +#define TCIC_ILOCKTEST_ID_SHFT 8 /* the shift count */ +#define TCIC_ILOCKTEST_ID_MASK (0x7F << TCIC_ILOCKTEST_ID_SHFT) + /* the mask for the field */ +/* + * Use the following convention for defining TCIC_ILOCKTEST_DBxxxxxY: + * + * TCIC_ILOCKTEST_DBxxxxx_1 The First step of chip. + * TCIC_ILOCKTEST_DBxxxxxA The Second step of chip. + * TCIC_ILOCKTEST_DBxxxxxB The Third step of chip. + * TCIC_ILOCKTEST_DBxxxxx... The ... step of chip. + * + * TCIC_ILOCKTEST_DBxxxxx"step of chip"_ES An Engineering Sample of chip. + * + */ +#define TCIC_ILOCKTEST_TCIC2N_1 ((TCIC_CHIPID_DB86082_1) << TCIC_ILOCKTEST_ID_SHFT) +#define TCIC_ILOCKTEST_DB86082_1 TCIC_ILOCKTEST_TCIC2N_1 +#define TCIC_ILOCKTEST_TCIC2N_2 ((TCIC_CHIPID_DB86082A) << TCIC_ILOCKTEST_ID_SHFT) +#define TCIC_ILOCKTEST_DB86082A TCIC_ILOCKTEST_TCIC2N_2 +#define TCIC_ILOCKTEST_TCIC2N_3 ((TCIC_CHIPID_DB86082B_ES) << TCIC_ILOCKTEST_ID_SHFT) +#define TCIC_ILOCKTEST_DB86082B_ES TCIC_ILOCKTEST_TCIC2N_3 + +#define TCIC_ILOCKTEST_DB86082B ((TCIC_CHIPID_DB86082B) << TCIC_ILOCKTEST_ID_SHFT) + +#define TCIC_ILOCKTEST_DB86084_1 ((TCIC_CHIPID_DB86084_1) << TCIC_ILOCKTEST_ID_SHFT) +#define TCIC_ILOCKTEST_DB86084A ((TCIC_CHIPID_DB86084A) << TCIC_ILOCKTEST_ID_SHFT) + +#define TCIC_ILOCKTEST_DB86184_1 ((TCIC_CHIPID_DB86184_1) << TCIC_ILOCKTEST_ID_SHFT) + +#define TCIC_ILOCKTEST_DB86072_1 ((TCIC_CHIPID_DB86072_1) << TCIC_ILOCKTEST_ID_SHFT) +#define TCIC_ILOCKTEST_DB86072_1_ES ((TCIC_CHIPID_DB86072_1_ES) << TCIC_ILOCKTEST_ID_SHFT) + + +/* Bits in the test control register (AR_TEST) */ +#define TCIC_R_TEST (TCIC_R_AUX + 0) +#define TCIC_TEST_AEN (1 << 0) /* force card AEN */ +#define TCIC_TEST_CEN (1 << 1) /* force card CEN */ +#define TCIC_TEST_CTR (1 << 2) /* test programming pulse, address ctrs */ +#define TCIC_TEST_ENA (1 << 3) /* force card-present (for test), and + * special VPP test mode + */ +#define TCIC_TEST_IO (1 << 4) /* feed back some I/O signals + * internally. + */ +#define TCIC_TEST_OUT1 (1 << 5) /* force special address output mode */ +#define TCIC_TEST_ZPB (1 << 6) /* enter ZPB test mode */ +#define TCIC_TEST_WAIT (1 << 7) /* force-enable WAIT pin */ +#define TCIC_TEST_PCTR (1 << 8) /* program counter in read-test mode */ +#define TCIC_TEST_VCTL (1 << 9) /* force-enable power-supply controls */ +#define TCIC_TEST_EXTA (1 << 10) /* external access doesn't override + || internal decoding. + */ +#define TCIC_TEST_DRIVECDB (1 << 11) /* drive the card data bus all the time */ +#define TCIC_TEST_ISTP (1 << 12) /* turn off CCLK to the interrupt CSR */ +#define TCIC_TEST_BSTP (1 << 13) /* turn off BCLK internal to the chip */ +#define TCIC_TEST_CSTP (1 << 14) /* turn off CCLK except to int CSR */ +#define TCIC_TEST_DIAG (1 << 15) /* enable diagnostic read-back mode */ + +/* Bits in the SCF1 register */ +#define TCIC_SCF1_IRQ_MASK (0xF) /* mask for this bit field */ +#define TCIC_SCF1_IRQOFF (0) /* disable */ +#define TCIC_SCF1_SIRQ (0x1) /* use SKTIRQ (2/N) */ +#define TCIC_SCF1_IRQ3 (0x3) /* use IRQ3 */ +#define TCIC_SCF1_IRQ4 (0x4) /* use IRQ4 */ +#define TCIC_SCF1_IRQ5 (0x5) /* use IRQ5 */ +#define TCIC_SCF1_IRQ6 (0x6) /* use IRQ6 */ +#define TCIC_SCF1_IRQ7 (0x7) /* use IRQ7 */ +#define TCIC_SCF1_IRQ9 (0x9) /* use IRQ9 */ +#define TCIC_SCF1_IRQ10 (0xA) /* use IRQ10 */ +#define TCIC_SCF1_IRQ11 (0xB) /* use IRQ11 */ +#define TCIC_SCF1_IRQ12 (0xC) /* use IRQ12 */ +#define TCIC_SCF1_IRQ14 (0xE) /* use IRQ14 */ +#define TCIC_SCF1_IRQ15 (0xF) /* use IRQ15 */ + +/* XXX doc bug? -chb */ +#define TCIC_SCF1_IRQOD (1 << 4) +#define TCIC_SCF1_IRQOC (0) /* selected IRQ is + * open-collector, and active + * low; otherwise it's totem- + * pole and active hi. + */ +#define TCIC_SCF1_PCVT (1 << 5) /* convert level-mode IRQ + * to pulse mode, or stretch + * pulses from card. + */ +#define TCIC_SCF1_IRDY (1 << 6) /* interrupt from RDY (not + * from /IREQ). Used with + * ATA drives. + */ +#define TCIC_SCF1_ATA (1 << 7) /* Special ATA drive mode. + * CEL/H become CE1/2 in + * the IDE sense; CEL is + * activated for even window + * matches, and CEH for + * odd window matches. + */ +#define TCIC_SCF1_DMA_SHIFT 8 /* offset to DMA selects; */ +#define TCIC_SCF1_DMA_MASK (0x7 << IRSCFG_DMA_SHIFT) + +#define TCIC_SCF1_DMAOFF (0 << IRSCFG_DMA_SHIFT) /* disable DMA */ +#define TCIC_SCF1_DREQ2 (2 << IRSCFG_DMA_SHIFT) /* enable DMA on DRQ2 */ + +#define TCIC_SCF1_IOSTS (1 << 11) /* enable I/O status mode; + * allows CIORD/CIOWR to + * become low-Z. + */ +#define TCIC_SCF1_SPKR (1 << 12) /* enable SPKR output from + * this card + */ +#define TCIC_SCF1_FINPACK (1 << 13) /* force card input + * acknowledge during I/O + * cycles. Has no effect + * if no windows map to card + */ +#define TCIC_SCF1_DELWR (1 << 14) /* force -all- data to + * meet 60ns setup time + * ("DELay WRite") + */ +#define TCIC_SCF1_HD7IDE (1 << 15) /* Enable special IDE + * data register mode: odd + * byte addresses in odd + * I/O windows will not + * drive HD7. + */ + +/* Bits in the scrf2 register */ +#define TCIC_SCF2_RI (1 << 0) /* enable RI pin from STSCHG + * (2/N) + `*/ +#define TCIC_SCF2_IDBR (1 << 1) /* force I/O data bus routing + * for this socket, regardless + * of cycle type. (2/N) + `*/ +#define TCIC_SCF2_MDBR (1 << 2) /* force memory window data + * bus routing for this + * socket, regardless of cycle + * type. (2/N) + */ +#define TCIC_SCF2_MLBAT1 (1 << 3) /* disable status change + * ints from LBAT1 (or + * "STSCHG" + */ +#define TCIC_SCF2_MLBAT2 (1 << 4) /* disable status change + * ints from LBAT2 (or "SPKR") + */ +#define TCIC_SCF2_MRDY (1 << 5) /* disable status change ints + * from RDY/BSY (or /IREQ). + * note that you get ints on + * both high- and low-going + * edges if this is enabled. + */ +#define TCIC_SCF2_MWP (1 << 6) /* disable status-change ints + * from WP (or /IOIS16). + * If you're using status + * change ints, you better set + * this once an I/O window is + * enabled, before accessing + * it. + */ +#define TCIC_SCF2_MCD (1 << 7) /* disable status-change ints + * from Card Detect. + */ + +/* + * note that these bits match the top 5 bits of the socket status register + * in order and sense. + */ +#define TCIC_SCF2_DMASRC_MASK (0x3 << 8) /* mask for this bit field */ + /*-- DMA Source --*/ +#define TCIC_SCF2_DRQ_BVD2 (0x0 << 8) /* BVD2 */ +#define TCIC_SCF2_DRQ_IOIS16 (0x1 << 8) /* IOIS16 */ +#define TCIC_SCF2_DRQ_INPACK (0x2 << 8) /* INPACK */ +#define TCIC_SCF2_DRQ_FORCE (0x3 << 8) /* Force it */ + +#define TCIC_SCFS2_RSVD (0xFC00) /* top 6 bits are RFU */ + +/* Bits in the MBASE window registers */ +#define TCIC_MBASE_4K (1 << 14) /* window size is 4K */ +#define TCIC_MBASE_ADDR_MASK 0x0fff /* bits holding the address */ + +/* Bits in the MMAP window registers */ +#define TCIC_MMAP_ATTR (1 << 15) /* map attr or common space */ +#define TCIC_MMAP_ADDR_MASK 0x3fff /* bits holding the address */ + +/* Bits in the MCTL window registers */ +#define TCIC_MCTL_ENA (1 << 15) /* enable this window */ +#define TCIC_MCTL_SS_SHIFT 12 +#define TCIC_MCTL_SS_MASK (7 << TCIC_MCTL_SS_SHIFT) /* which socket does this window map to */ +#define TCIC_MCTL_B8 (1 << 11) /* 8/16 bit access select */ +#define TCIC_MCTL_EDC (1 << 10) /* do EDC calc. on access */ +#define TCIC_MCTL_KE (1 << 9) /* accesses are cacheable */ +#define TCIC_MCTL_ACC (1 << 8) /* window has been accessed */ +#define TCIC_MCTL_WP (1 << 7) /* window is write protected */ +#define TCIC_MCTL_QUIET (1 << 6) /* enable quiet socket mode */ +#define TCIC_MCTL_WSCNT_MASK 0x0f /* wait state counter */ + +/* Bits in the ICTL window registers */ +#define TCIC_ICTL_ENA (1 << 15) /* enable this windo */ +#define TCIC_ICTL_SS_SHIFT 12 +#define TCIC_ICTL_SS_MASK (7 << TCIC_ICTL_SS_SHIFT) /* which socket does this window map to */ +#define TCIC_ICTL_AUTOSZ 0 /* auto size 8/16 bit acc. */ +#define TCIC_ICTL_B8 (1 << 11) /* all accesses 8 bit */ +#define TCIC_ICTL_B16 (1 << 10) /* all accesses 16 bit */ +#define TCIC_ICTL_ATA (3 << 10) /* special ATA mode */ +#define TCIC_ICTL_TINY (1 << 9) /* window size 1 byte */ +#define TCIC_ICTL_ACC (1 << 8) /* window has been accessed */ +#define TCIC_ICTL_1K (1 << 7) /* only 10 bits io decoding */ +#define TCIC_ICTL_QUIET (1 << 6) /* enable quiet socket mode */ +#define TCIC_ICTL_PASS16 (1 << 5) /* pass all 16 bits to card */ +#define TCIC_ICTL_WSCNT_MASK 0x0f /* wait state counter */ + +/* Various validity tests */ +/* + * From Databook sample source: + * MODE_AR_SYSCFG must have, with j = ***read*** (***, R_AUX) + * and k = (j>>9)&7: + * if (k&4) k == 5 + * And also: + * j&0x0f is none of 2, 8, 9, b, c, d, f + * if (j&8) must have (j&3 == 2) + * Can't have j==2 + */ +#if 0 +/* this is from the Databook sample code and apparently is wrong */ +#define INVALID_AR_SYSCFG(x) ((((x)&0x1000) && (((x)&0x0c00) != 0x0200)) \ + || (((((x)&0x08) == 0) || (((x)&0x03) == 2)) \ + && ((x) != 0x02))) +#else +#define INVALID_AR_SYSCFG(x) ((((x)&0x0800) && (((x)&0x0600) != 0x0100)) \ + || ((((((x)&0x08) == 0) && (((x)&0x03) == 2)) \ + || (((x)&0x03) == 2)) \ + && ((x) != 0x02))) +#endif +/* AR_ILOCK must have bits 6 and 7 the same: */ +#define INVALID_AR_ILOCK(x) (((x)&0xc0)==0 || (((x)&0xc0)==0xc0)) + +/* AR_TEST has some reserved bits: */ +#define INVALID_AR_TEST(x) (((x)&0154) != 0) + + +#define TCIC_IO_WINS 2 +#define TCIC_MAX_MEM_WINS 5 + +/* + * Memory window addresses refer to bits A23-A12 of the ISA system memory + * address. This is a shift of 12 bits. The LSB contains A19-A12, and the + * MSB contains A23-A20, plus some other bits. + */ + +#define TCIC_MEM_SHIFT 12 +#define TCIC_MEM_PAGESIZE (1<<TCIC_MEM_SHIFT) + +#endif /* _TCIC2REG_H */ diff --git a/sys/dev/ic/tcic2var.h b/sys/dev/ic/tcic2var.h new file mode 100644 index 00000000000..1eb896c53bd --- /dev/null +++ b/sys/dev/ic/tcic2var.h @@ -0,0 +1,359 @@ +/* $OpenBSD: tcic2var.h,v 1.1 2000/05/15 04:17:28 jason Exp $ */ +/* $NetBSD: tcic2var.h,v 1.1 1999/03/23 20:04:14 bad Exp $ */ + +/* + * Copyright (c) 1998, 1999 Christoph Badura. All rights reserved. + * Copyright (c) 1997 Marc Horowitz. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Marc Horowitz. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _TCIC2VAR_H +#define _TCIC2VAR_H + +#include <sys/device.h> + +#include <dev/pcmcia/pcmciareg.h> +#include <dev/pcmcia/pcmciachip.h> + +#include <dev/ic/tcic2reg.h> + +struct proc; + +struct tcic_event { + SIMPLEQ_ENTRY(tcic_event) pe_q; + int pe_type; +}; + +/* pe_type */ +#define TCIC_EVENT_INSERTION 0 +#define TCIC_EVENT_REMOVAL 1 + + +struct tcic_handle { + struct tcic_softc *sc; + int sock; /* socket number */ + int flags; + int sstat; /* last value of R_SSTAT */ + int memalloc; + int memwins; + struct { + bus_addr_t addr; + bus_size_t size; + int size2; /* size as 2^n scaled by 4K */ + long offset; + int speed; /* in ns */ + int kind; + } mem[TCIC_MAX_MEM_WINS]; + int ioalloc; + struct { + bus_addr_t addr; + bus_size_t size; + int width; + int speed; /* in ns */ + } io[TCIC_IO_WINS]; + int ih_irq; + struct device *pcmcia; + + int shutdown; + struct proc *event_thread; + SIMPLEQ_HEAD(, tcic_event) events; +}; + +#define TCIC_FLAG_SOCKETP 0x0001 +#define TCIC_FLAG_CARDP 0x0002 + +/* + * This is sort of arbitrary. It merely needs to be "enough". It can be + * overridden in the conf file, anyway. + */ + +#define TCIC_MEM_PAGES 4 +#define TCIC_MEMSIZE TCIC_MEM_PAGES*TCIC_MEM_PAGESIZE + +#define TCIC_NSLOTS 2 + +struct tcic_softc { + struct device dev; + + bus_space_tag_t memt; + bus_space_handle_t memh; + bus_space_tag_t iot; + bus_space_handle_t ioh; + + int chipid; + int validirqs; + int pwrena; /* holds TCIC_PWR_ENA on'084 and successors */ + + /* XXX isa_chipset_tag_t, pci_chipset_tag_t, etc. */ + void *intr_est; + + pcmcia_chipset_tag_t pct; + + /* this needs to be large enough to hold TCIC_MEM_PAGES bits */ + int subregionmask; + + /* used by memory window mapping functions */ + bus_addr_t membase; + int memsize2; /* int(log2(memsize)) */ + + /* + * used by io window mapping functions. These can actually overlap + * with another tcic, since the underlying extent mapper will deal + * with individual allocations. This is here to deal with the fact + * that different busses have different real widths (different pc + * hardware seems to use 10 or 12 bits for the I/O bus). + */ + bus_addr_t iobase; + bus_size_t iosize; + + int irq; + void *ih; + + struct tcic_handle handle[TCIC_NSLOTS]; +}; + +int tcic_log2 __P((u_int)); +int tcic_ns2wscnt __P((int)); + +int tcic_check_reserved_bits __P((bus_space_tag_t, bus_space_handle_t)); +int tcic_chipid __P((bus_space_tag_t, bus_space_handle_t)); +int tcic_chipid_known __P((int)); +char *tcic_chipid_to_string __P((int)); +int tcic_validirqs __P((int)); + +void tcic_attach __P((struct tcic_softc *)); +void tcic_attach_sockets __P((struct tcic_softc *)); +int tcic_intr __P((void *arg)); + +static __inline__ int tcic_read_1 __P((struct tcic_handle *, int)); +static __inline__ int tcic_read_2 __P((struct tcic_handle *, int)); +static __inline__ int tcic_read_4 __P((struct tcic_handle *, int)); +static __inline__ void tcic_write_1 __P((struct tcic_handle *, int, int)); +static __inline__ void tcic_write_2 __P((struct tcic_handle *, int, int)); +static __inline__ void tcic_write_4 __P((struct tcic_handle *, int, int)); +static __inline__ int tcic_read_ind_2 __P((struct tcic_handle *, int)); +static __inline__ void tcic_write_ind_2 __P((struct tcic_handle *, int, int)); +static __inline__ void tcic_sel_sock __P((struct tcic_handle *)); +static __inline__ void tcic_wait_ready __P((struct tcic_handle *)); +static __inline__ int tcic_read_aux_1 __P((bus_space_tag_t, bus_space_handle_t, int, int)); +static __inline__ int tcic_read_aux_2 __P((bus_space_tag_t, bus_space_handle_t, int)); +static __inline__ void tcic_write_aux_1 __P((bus_space_tag_t, bus_space_handle_t, int, int, int)); +static __inline__ void tcic_write_aux_2 __P((bus_space_tag_t, bus_space_handle_t, int, int)); + +int tcic_chip_mem_alloc __P((pcmcia_chipset_handle_t, bus_size_t, + struct pcmcia_mem_handle *)); +void tcic_chip_mem_free __P((pcmcia_chipset_handle_t, + struct pcmcia_mem_handle *)); +int tcic_chip_mem_map __P((pcmcia_chipset_handle_t, int, bus_addr_t, + bus_size_t, struct pcmcia_mem_handle *, bus_addr_t *, int *)); +void tcic_chip_mem_unmap __P((pcmcia_chipset_handle_t, int)); + +int tcic_chip_io_alloc __P((pcmcia_chipset_handle_t, bus_addr_t, + bus_size_t, bus_size_t, struct pcmcia_io_handle *)); +void tcic_chip_io_free __P((pcmcia_chipset_handle_t, + struct pcmcia_io_handle *)); +int tcic_chip_io_map __P((pcmcia_chipset_handle_t, int, bus_addr_t, + bus_size_t, struct pcmcia_io_handle *, int *)); +void tcic_chip_io_unmap __P((pcmcia_chipset_handle_t, int)); + +void tcic_chip_socket_enable __P((pcmcia_chipset_handle_t)); +void tcic_chip_socket_disable __P((pcmcia_chipset_handle_t)); + +static __inline__ int tcic_read_1 __P((struct tcic_handle *, int)); +static __inline__ int +tcic_read_1(h, reg) + struct tcic_handle *h; + int reg; +{ + return (bus_space_read_1(h->sc->iot, h->sc->ioh, reg)); +} + +static __inline__ int tcic_read_2 __P((struct tcic_handle *, int)); +static __inline__ int +tcic_read_2(h, reg) + struct tcic_handle *h; + int reg; +{ + return (bus_space_read_2(h->sc->iot, h->sc->ioh, reg)); +} + +static __inline__ int tcic_read_4 __P((struct tcic_handle *, int)); +static __inline__ int +tcic_read_4(h, reg) + struct tcic_handle *h; + int reg; +{ + int val; + val = bus_space_read_2(h->sc->iot, h->sc->ioh, reg); + val |= bus_space_read_2(h->sc->iot, h->sc->ioh, reg+2) << 16; + return val; +} + +static __inline__ void tcic_write_1 __P((struct tcic_handle *, int, int)); +static __inline__ void +tcic_write_1(h, reg, data) + struct tcic_handle *h; + int reg; + int data; +{ + bus_space_write_1(h->sc->iot, h->sc->ioh, reg, (data)); +} + +static __inline__ void tcic_write_2 __P((struct tcic_handle *, int, int)); +static __inline__ void +tcic_write_2(h, reg, data) + struct tcic_handle *h; + int reg; + int data; +{ + bus_space_write_2(h->sc->iot, h->sc->ioh, reg, (data)); +} + +static __inline__ void tcic_write_4 __P((struct tcic_handle *, int, int)); +static __inline__ void +tcic_write_4(h, reg, data) + struct tcic_handle *h; + int reg; + int data; +{ + bus_space_write_2(h->sc->iot, h->sc->ioh, reg, (data)); + bus_space_write_2(h->sc->iot, h->sc->ioh, reg+2, (data)>>16); +} + +static __inline__ int tcic_read_ind_2 __P((struct tcic_handle *, int)); +static __inline__ int +tcic_read_ind_2(h, reg) + struct tcic_handle *h; + int reg; +{ + int r_addr, val; + r_addr = tcic_read_4(h, TCIC_R_ADDR); + tcic_write_4(h, TCIC_R_ADDR, reg|TCIC_ADDR_INDREG); + val = bus_space_read_2(h->sc->iot, h->sc->ioh, TCIC_R_DATA); + tcic_write_4(h, TCIC_R_ADDR, r_addr); + return val; +} + +static __inline__ void tcic_write_ind_2 __P((struct tcic_handle *, int, int)); +static __inline__ void +tcic_write_ind_2(h, reg, data) + struct tcic_handle *h; + int reg; + int data; +{ + int r_addr; + r_addr = tcic_read_4(h, TCIC_R_ADDR); + tcic_write_4(h, TCIC_R_ADDR, reg|TCIC_ADDR_INDREG); + bus_space_write_2(h->sc->iot, h->sc->ioh, TCIC_R_DATA, (data)); + tcic_write_4(h, TCIC_R_ADDR, r_addr); +} + +static __inline__ void tcic_sel_sock __P((struct tcic_handle *)); +static __inline__ void +tcic_sel_sock(h) + struct tcic_handle *h; +{ + int r_addr; + r_addr = tcic_read_2(h, TCIC_R_ADDR2); + tcic_write_2(h, TCIC_R_ADDR2, + (h->sock<<TCIC_ADDR2_SS_SHFT)|(r_addr & ~TCIC_ADDR2_SS_MASK)); +} + +static __inline__ void tcic_wait_ready __P((struct tcic_handle *)); +static __inline__ void +tcic_wait_ready(h) + struct tcic_handle *h; +{ + int i; + + /* XXX appropriate socket must have been selected already. */ + for (i = 0; i < 10000; i++) { + if (tcic_read_1(h, TCIC_R_SSTAT) & TCIC_SSTAT_RDY) + return; + delay(500); + } + +#ifdef DIAGNOSTIC + printf("tcic_wait_ready ready never happened\n"); +#endif +} + +static __inline__ int tcic_read_aux_1 __P((bus_space_tag_t, bus_space_handle_t, int, int)); +static __inline__ int +tcic_read_aux_1(iot, ioh, auxreg, reg) + bus_space_tag_t iot; + bus_space_handle_t ioh; + int auxreg; +{ + int mode, val; + mode = bus_space_read_1(iot, ioh, TCIC_R_MODE); + bus_space_write_1(iot, ioh, TCIC_R_MODE, (mode & ~TCIC_AR_MASK)|auxreg); + val = bus_space_read_1(iot, ioh, reg); + return val; +} + +static __inline__ int tcic_read_aux_2 __P((bus_space_tag_t, bus_space_handle_t, int)); +static __inline__ int +tcic_read_aux_2(iot, ioh, auxreg) + bus_space_tag_t iot; + bus_space_handle_t ioh; + int auxreg; +{ + int mode, val; + mode = bus_space_read_1(iot, ioh, TCIC_R_MODE); + bus_space_write_1(iot, ioh, TCIC_R_MODE, (mode & ~TCIC_AR_MASK)|auxreg); + val = bus_space_read_2(iot, ioh, TCIC_R_AUX); + return val; +} + +static __inline__ void tcic_write_aux_1 __P((bus_space_tag_t, bus_space_handle_t, int, int, int)); +static __inline__ void +tcic_write_aux_1(iot, ioh, auxreg, reg, val) + bus_space_tag_t iot; + bus_space_handle_t ioh; + int auxreg, reg, val; +{ + int mode; + mode = bus_space_read_1(iot, ioh, TCIC_R_MODE); + bus_space_write_1(iot, ioh, TCIC_R_MODE, (mode & ~TCIC_AR_MASK)|auxreg); + bus_space_write_1(iot, ioh, reg, val); +} + +static __inline__ void tcic_write_aux_2 __P((bus_space_tag_t, bus_space_handle_t, int, int)); +static __inline__ void +tcic_write_aux_2(iot, ioh, auxreg, val) + bus_space_tag_t iot; + bus_space_handle_t ioh; + int auxreg, val; +{ + int mode; + mode = bus_space_read_1(iot, ioh, TCIC_R_MODE); + bus_space_write_1(iot, ioh, TCIC_R_MODE, (mode & ~TCIC_AR_MASK)|auxreg); + bus_space_write_2(iot, ioh, TCIC_R_AUX, val); +} + +#endif /* _TCIC2VAR_H */ diff --git a/sys/dev/isa/tcic2_isa.c b/sys/dev/isa/tcic2_isa.c new file mode 100644 index 00000000000..725e5e49fb3 --- /dev/null +++ b/sys/dev/isa/tcic2_isa.c @@ -0,0 +1,375 @@ +/* $OpenBSD: tcic2_isa.c,v 1.1 2000/05/15 04:17:29 jason Exp $ */ +/* $NetBSD: tcic2_isa.c,v 1.2 1999/04/08 16:14:29 bad Exp $ */ + +#undef TCICISADEBUG + +/* + * + * Copyright (c) 1998, 1999 Christoph Badura. All rights reserved. + * Copyright (c) 1997 Marc Horowitz. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Marc Horowitz. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/extent.h> +#include <sys/malloc.h> + +#include <vm/vm.h> + +#include <machine/bus.h> +#include <machine/intr.h> + +#include <dev/isa/isareg.h> +#include <dev/isa/isavar.h> + +#include <dev/pcmcia/pcmciareg.h> +#include <dev/pcmcia/pcmciavar.h> +#include <dev/pcmcia/pcmciachip.h> + +#include <dev/ic/tcic2reg.h> +#include <dev/ic/tcic2var.h> + +/***************************************************************************** + * Configurable parameters. + *****************************************************************************/ + +/* + * Default I/O allocation range. If both are set to non-zero, these + * values will be used instead. Otherwise, the code attempts to probe + * the bus width. Systems with 10 address bits should use 0x300 and 0xff. + * Systems with 12 address bits (most) should use 0x400 and 0xbff. + */ + +#ifndef TCIC_ISA_ALLOC_IOBASE +#define TCIC_ISA_ALLOC_IOBASE 0 +#endif + +#ifndef TCIC_ISA_ALLOC_IOSIZE +#define TCIC_ISA_ALLOC_IOSIZE 0 +#endif + +int tcic_isa_alloc_iobase = TCIC_ISA_ALLOC_IOBASE; +int tcic_isa_alloc_iosize = TCIC_ISA_ALLOC_IOSIZE; + +/* + * Default IRQ allocation bitmask. This defines the range of allowable + * IRQs for PCMCIA slots. Useful if order of probing would screw up other + * devices, or if TCIC hardware/cards have trouble with certain interrupt + * lines. + * + * We disable IRQ 10 by default, since some common laptops (namely, the + * NEC Versa series) reserve IRQ 10 for the docking station SCSI interface. + * + * XXX Do we care about this? the Versa doesn't use a tcic. -chb + */ + +#ifndef TCIC_ISA_INTR_ALLOC_MASK +#define TCIC_ISA_INTR_ALLOC_MASK 0xffff +#endif + +int tcic_isa_intr_alloc_mask = TCIC_ISA_INTR_ALLOC_MASK; + +/***************************************************************************** + * End of configurable parameters. + *****************************************************************************/ + +#ifdef TCICISADEBUG +int tcic_isa_debug = 1; +#define DPRINTF(arg) if (tcic_isa_debug) printf arg; +#else +#define DPRINTF(arg) +#endif + +int tcic_isa_probe __P((struct device *, void *, void *)); +void tcic_isa_attach __P((struct device *, struct device *, void *)); + +void *tcic_isa_chip_intr_establish __P((pcmcia_chipset_handle_t, + struct pcmcia_function *, int, int (*) (void *), void *)); +void tcic_isa_chip_intr_disestablish __P((pcmcia_chipset_handle_t, void *)); + +struct cfattach tcic_isa_ca = { + sizeof(struct tcic_softc), tcic_isa_probe, tcic_isa_attach +}; + +static struct pcmcia_chip_functions tcic_isa_functions = { + tcic_chip_mem_alloc, + tcic_chip_mem_free, + tcic_chip_mem_map, + tcic_chip_mem_unmap, + + tcic_chip_io_alloc, + tcic_chip_io_free, + tcic_chip_io_map, + tcic_chip_io_unmap, + + tcic_isa_chip_intr_establish, + tcic_isa_chip_intr_disestablish, + + tcic_chip_socket_enable, + tcic_chip_socket_disable, +}; + +int +tcic_isa_probe(parent, match, aux) + struct device *parent; + void *match; + void *aux; +{ + struct isa_attach_args *ia = aux; + bus_space_tag_t iot = ia->ia_iot; + bus_space_handle_t ioh, memh; + int val, found; + + /* Disallow wildcarded i/o address. */ + if (ia->ia_iobase == -1 /* ISACF_PORT_DEFAULT */) + return (0); + + if (bus_space_map(iot, ia->ia_iobase, TCIC_IOSIZE, 0, &ioh)) + return (0); + + if (ia->ia_msize == 0) + ia->ia_msize = TCIC_MEMSIZE; + + if (bus_space_map(ia->ia_memt, ia->ia_maddr, ia->ia_msize, 0, &memh)) + return (0); + + DPRINTF(("tcic probing 0x%03x\n", ia->ia_iobase)); + found = 0; + + /* + * First, check for the reserved bits to be zero. + */ + if (tcic_check_reserved_bits(iot, ioh)) { + DPRINTF(("tcic: reserved bits checked OK\n")); + /* Second, check whether the we know how to handle the chip. */ + if ((val = tcic_chipid(iot, ioh))) { + DPRINTF(("tcic id: 0x%02x\n", val)); + if (tcic_chipid_known(val)) + found++; + } + } + else + DPRINTF(("tcic: reserved bits didn't check OK\n")); + + bus_space_unmap(iot, ioh, TCIC_IOSIZE); + bus_space_unmap(ia->ia_memt, memh, ia->ia_msize); + + if (!found) + return (0); + + ia->ia_iosize = TCIC_IOSIZE; + + return (1); +} + +void +tcic_isa_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct tcic_softc *sc = (void *) self; + struct isa_attach_args *ia = aux; + isa_chipset_tag_t ic = ia->ia_ic; + bus_space_tag_t iot = ia->ia_iot; + bus_space_tag_t memt = ia->ia_memt; + bus_space_handle_t ioh; + bus_space_handle_t memh; + + /* Map i/o space. */ + if (bus_space_map(iot, ia->ia_iobase, ia->ia_iosize, 0, &ioh)) { + printf(": can't map i/o space\n"); + return; + } + + /* Map mem space. */ + if (bus_space_map(memt, ia->ia_maddr, ia->ia_msize, 0, &memh)) { + printf(": can't map mem space\n"); + return; + } + + sc->membase = ia->ia_maddr; + sc->subregionmask = (1 << (ia->ia_msize / TCIC_MEM_PAGESIZE)) - 1; + sc->memsize2 = tcic_log2((u_int)ia->ia_msize); + + sc->intr_est = ic; + sc->pct = (pcmcia_chipset_tag_t) & tcic_isa_functions; + + sc->iot = iot; + sc->ioh = ioh; + sc->memt = memt; + sc->memh = memh; + + /* + * determine chip type and initialise some chip type dependend + * parameters in softc. + */ + sc->chipid = tcic_chipid(iot, ioh); + sc->validirqs = tcic_validirqs(sc->chipid); + + /* + * allocate an irq. interrupts are relatively + * scarce but for TCIC controllers very infrequent. + */ + + if ((sc->irq = ia->ia_irq) == IRQUNK) { + if (isa_intr_alloc(ic, + sc->validirqs & (tcic_isa_intr_alloc_mask & 0xff00), + IST_EDGE, &sc->irq)) { + printf("\n%s: can't allocate interrupt\n", + sc->dev.dv_xname); + return; + } + printf(": using irq %d", sc->irq); + } + printf("\n"); + + tcic_attach(sc); + + + /* + * XXX mycroft recommends I/O space range 0x400-0xfff. + */ + + /* + * XXX some hardware doesn't seem to grok addresses in 0x400 range-- + * apparently missing a bit or more of address lines. (e.g. + * CIRRUS_PD672X with Linksys EthernetCard ne2000 clone in TI + * TravelMate 5000--not clear which is at fault) + * + * Add a kludge to detect 10 bit wide buses and deal with them, + * and also a config file option to override the probe. + */ + +#if 0 + /* + * This is what we'd like to use, but... + */ + sc->iobase = 0x400; + sc->iosize = 0xbff; +#else + /* + * ...the above bus width probe doesn't always work. + * So, experimentation has shown the following range + * to not lose on systems that 0x300-0x3ff loses on + * (e.g. the NEC Versa 6030X). + */ + sc->iobase = 0x330; + sc->iosize = 0x0cf; +#endif + + DPRINTF(("%s: bus_space_alloc range 0x%04lx-0x%04lx)\n", + sc->dev.dv_xname, (long) sc->iobase, + (long) sc->iobase + sc->iosize)); + + if (tcic_isa_alloc_iobase && tcic_isa_alloc_iosize) { + sc->iobase = tcic_isa_alloc_iobase; + sc->iosize = tcic_isa_alloc_iosize; + + DPRINTF(("%s: bus_space_alloc range 0x%04lx-0x%04lx " + "(config override)\n", sc->dev.dv_xname, (long) sc->iobase, + (long) sc->iobase + sc->iosize)); + } + sc->ih = isa_intr_establish(ic, sc->irq, IST_EDGE, IPL_TTY, + tcic_intr, sc, sc->dev.dv_xname); + if (sc->ih == NULL) { + printf("%s: can't establish interrupt\n", sc->dev.dv_xname); + return; + } + + tcic_attach_sockets(sc); +} + +void * +tcic_isa_chip_intr_establish(pch, pf, ipl, fct, arg) + pcmcia_chipset_handle_t pch; + struct pcmcia_function *pf; + int ipl; + int (*fct) __P((void *)); + void *arg; +{ + struct tcic_handle *h = (struct tcic_handle *) pch; + int irq, ist, val, reg; + void *ih; + int irqmap[] = { + 0, 0, 0, TCIC_SCF1_IRQ3, TCIC_SCF1_IRQ4, TCIC_SCF1_IRQ5, + TCIC_SCF1_IRQ6, TCIC_SCF1_IRQ7, 0, TCIC_SCF1_IRQ9, + TCIC_SCF1_IRQ10, TCIC_SCF1_IRQ11, TCIC_SCF1_IRQ12, 0, + TCIC_SCF1_IRQ14, TCIC_SCF1_IRQ15 + }; + + DPRINTF(("%s: tcic_isa_chip_intr_establish\n", h->sc->dev.dv_xname)); + + /* XXX should we convert level to pulse? -chb */ + if (pf->cfe->flags & PCMCIA_CFE_IRQLEVEL) + ist = IST_LEVEL; + else if (pf->cfe->flags & PCMCIA_CFE_IRQPULSE) + ist = IST_PULSE; + else + ist = IST_LEVEL; + + if (isa_intr_alloc(h->sc->intr_est, + h->sc->validirqs & tcic_isa_intr_alloc_mask, ist, &irq)) + return (NULL); + if ((ih = isa_intr_establish(h->sc->intr_est, irq, ist, ipl, + fct, arg, h->pcmcia->dv_xname)) == NULL) + return (NULL); + + DPRINTF(("%s: intr established\n", h->sc->dev.dv_xname)); + + h->ih_irq = irq; + + reg = TCIC_IR_SCF1_N(h->sock); + val = (tcic_read_ind_2(h, reg) & (~TCIC_SCF1_IRQ_MASK)) | irqmap[irq]; + tcic_write_ind_2(h, reg, val); + + printf(" irq %d", irq); + return (ih); +} + +void +tcic_isa_chip_intr_disestablish(pch, ih) + pcmcia_chipset_handle_t pch; + void *ih; +{ + struct tcic_handle *h = (struct tcic_handle *) pch; + int val, reg; + + DPRINTF(("%s: tcic_isa_chip_intr_disestablish\n", h->sc->dev.dv_xname)); + + h->ih_irq = 0; + + reg = TCIC_IR_SCF1_N(h->sock); + val = tcic_read_ind_2(h, reg); + val &= ~TCIC_SCF1_IRQ_MASK; + tcic_write_ind_2(h, reg, val); + + isa_intr_disestablish(h->sc->intr_est, ih); +} |