diff --git a/sys/pci/pccbb.c b/sys/pci/pccbb.c new file mode 100644 index 000000000000..ac51e7058c7b --- /dev/null +++ b/sys/pci/pccbb.c @@ -0,0 +1,2374 @@ +/* + * Copyright (c) 1998 and 1999 HAYAKAWA Koichi. 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 HAYAKAWA Koichi. + * 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. + */ +/* $Id: pccbb.c,v 1.12 1999/09/07 17:38:17 gehenna Exp $ */ +/* FreeBSD/newconfig version UCHIYAMA Yasushi 1999 */ +/* $FreeBSD$ */ + +#define CBB_DEBUG +#undef SHOW_REGS +#undef PCCBB_PCMCIA_POLL + +#define CB_PCMCIA_POLL +#define CB_PCMCIA_POLL_ONLY +#define LEVEL2 +#undef CB_PCMCIA_POLL +#undef CB_PCMCIA_POLL_ONLY +#undef LEVEL2 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#define delay(arg) DELAY(arg) +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#define PCIC_FLAG_SOCKETP 0x0001 +#define PCIC_FLAG_CARDP 0x0002 + +/* Chipset ID */ +#define CB_UNKNOWN 0 /* NOT Cardbus-PCI bridge */ +#define CB_TI113X 1 /* TI PCI1130/1131 */ +#define CB_TI12XX 2 /* TI PCI1250/1220 */ +#define CB_RF5C47X 3 /* RICOH RF5C475/476/477 */ +#define CB_RF5C46X 4 /* RICOH RF5C465/466/467 */ +#define CB_TOPIC95 5 /* Toshiba ToPIC95 */ +#define CB_TOPIC95B 6 /* Toshiba ToPIC95B */ +#define CB_TOPIC97 7 /* Toshiba ToPIC97 */ +#define CB_CHIPS_LAST 8 /* Sentinel */ + +#if defined CBB_DEBUG +#define DPRINTF(x) printf x +#define STATIC +#else +#define DPRINTF(x) +#define STATIC static +#endif + +void +pccbb_event_thread (void *arg) +{ + struct pccbb_softc *sc = arg; + bus_space_tag_t memt = sc->sc_base_memt; + bus_space_handle_t memh = sc->sc_base_memh; + u_int32_t sockstate; + + int s; + + while (1) { + s = splhigh(); + if (!sc->sc_queued) { + splx (s); + tsleep (&sc->events, PWAIT, "pccbbev", 0); + } else { + sockstate = bus_space_read_4(memt, memh, CB_SOCKET_STAT); + if (sc->sc_flags & CBB_CARDEXIST) { + DPRINTF(("%s: card removed\n", sc->sc_dev.dv_xname)); + sc->sc_flags &= ~CBB_CARDEXIST; + if (sockstate & CB_SOCKET_STAT_16BIT) { + struct cbb_pcic_handle *ph = &sc->sc_pcmcia_h; + struct pcmcia_softc *psc = (void*)ph->pcmcia; + if (!(ph->flags & PCIC_FLAG_CARDP)) { + panic("pccbbintr: already detached"); + } + psc->sc_if.if_card_deactivate(ph->pcmcia); + pccbb_pcmcia_socket_disable(ph); + pccbb_pcmcia_detach_card(ph, DETACH_FORCE); + } else { + if (sc->sc_cbdev) + config_detach (sc->sc_cbdev, DETACH_FORCE); + else + printf ("no corresponding device instance.\n"); /* XXX should panic */ + } + } else { + DPRINTF(("%s: card inserted\n", sc->sc_dev.dv_xname)); + pccbb_insert (sc); + } + sc->sc_queued = 0; + sc->sc_flags &= ~CBB_CARDSTATUS_BUSY; + splx (s); + } + } + kthread_exit(0); + +} +void +pccbb_create_event_thread (void *arg) +{ + struct pccbb_softc *sc = arg; + if (kthread_create1(pccbb_event_thread, sc, &sc->event_thread, + "%s,%s", sc->sc_dev.dv_xname, "cardbus")) { + printf ("%s: unable to create event thread.\n", + sc->sc_dev.dv_xname); + panic ("pccbb_create_event_thread"); + } else + printf("%s: create event thread\n", sc->sc_dev.dv_xname); +} + +void +pccbb_kthread_init (struct pccbb_softc *sc) +{ + kthread_create(pccbb_create_event_thread, sc); +} + + +int pccbbmatch __P((struct device *, struct cfdata *, void *)); +void pccbbattach __P((struct device *, struct device *, void *)); +int pccbbintr __P((void *)); + +static void pccbb_insert __P((void *)); +static int pccbb_detect_card __P((struct pccbb_softc *)); +static void pccbb_pcmcia_write __P((struct cbb_pcic_handle *, int, u_int8_t)); +static u_int8_t pccbb_pcmcia_read __P((struct cbb_pcic_handle *, int)); +#define Pcic_read(ph, reg) ((ph)->ph_read((ph), (reg))) +#define Pcic_write(ph, reg, val) ((ph)->ph_write((ph), (reg), (val))) + +STATIC int cb_reset __P((struct pccbb_softc *)); +STATIC int cb_detect_voltage __P((struct pccbb_softc *)); +STATIC int cbbprint __P((void *, const char *)); + +static int cb_chipset __P((u_int32_t, char const **, int *)); +static void pccbb_chipinit __P((struct pci_attach_args *, struct pccbb_softc *)); +STATIC void pccbb_pcmcia_attach __P((struct pccbb_softc *)); +STATIC void pccbb_pcmcia_attach_card __P((struct cbb_pcic_handle *)); +STATIC void pccbb_pcmcia_detach_card __P((struct cbb_pcic_handle *, int)); +STATIC void pccbb_pcmcia_deactivate_card __P((struct cbb_pcic_handle *)); + +STATIC int pccbb_ctrl __P((cardbus_chipset_tag_t, int)); +STATIC int pccbb_power __P((cardbus_chipset_tag_t, int)); +STATIC int pccbb_cardenable __P((struct pccbb_softc *sc, int function)); +static int pccbb_io_open __P((cardbus_chipset_tag_t, int, u_int32_t, u_int32_t)); +static int pccbb_io_close __P((cardbus_chipset_tag_t, int)); +static int pccbb_mem_open __P((cardbus_chipset_tag_t, int, u_int32_t, u_int32_t)); +static int pccbb_mem_close __P((cardbus_chipset_tag_t, int)); +static void *pccbb_intr_establish __P((cardbus_chipset_tag_t, int irq, int level, int (* ih)(void *), void *sc)); +static void pccbb_intr_disestablish __P((cardbus_chipset_tag_t ct, void *ih)); +static cardbustag_t pccbb_make_tag __P((cardbus_chipset_tag_t, int, int, int)); +static void pccbb_free_tag __P((cardbus_chipset_tag_t, cardbustag_t)); +static cardbusreg_t pccbb_conf_read __P((cardbus_chipset_tag_t, cardbustag_t, int)); +static void pccbb_conf_write __P((cardbus_chipset_tag_t, cardbustag_t, int, cardbusreg_t)); + +STATIC int pccbb_pcmcia_mem_alloc __P((pcmcia_chipset_handle_t, bus_size_t, + struct pcmcia_mem_handle *)); +STATIC void pccbb_pcmcia_mem_free __P((pcmcia_chipset_handle_t, + struct pcmcia_mem_handle *)); +STATIC int pccbb_pcmcia_mem_map __P((pcmcia_chipset_handle_t, int, bus_addr_t, + bus_size_t, struct pcmcia_mem_handle *, bus_addr_t *, int *)); +STATIC void pccbb_pcmcia_mem_unmap __P((pcmcia_chipset_handle_t, int)); +STATIC int pccbb_pcmcia_io_alloc __P((pcmcia_chipset_handle_t, bus_addr_t, + bus_size_t, bus_size_t, struct pcmcia_io_handle *)); +STATIC void pccbb_pcmcia_io_free __P((pcmcia_chipset_handle_t, + struct pcmcia_io_handle *)); +STATIC int pccbb_pcmcia_io_map __P((pcmcia_chipset_handle_t, int, bus_addr_t, + bus_size_t, struct pcmcia_io_handle *, int *)); +STATIC void pccbb_pcmcia_io_unmap __P((pcmcia_chipset_handle_t, int)); +STATIC void *pccbb_pcmcia_intr_establish __P((pcmcia_chipset_handle_t, + struct pcmcia_function *, int, int (*) (void *), void *)); +STATIC void pccbb_pcmcia_intr_disestablish __P((pcmcia_chipset_handle_t, void *)); +STATIC void pccbb_pcmcia_socket_enable __P((pcmcia_chipset_handle_t)); +STATIC void pccbb_pcmcia_socket_disable __P((pcmcia_chipset_handle_t)); + +static void pccbb_pcmcia_do_io_map __P((struct cbb_pcic_handle *, int)); +static void pccbb_pcmcia_wait_ready __P((struct cbb_pcic_handle *)); +static void pccbb_pcmcia_do_mem_map __P((struct cbb_pcic_handle *, int)); +static int pccbb_pcmcia_print __P((void *, const char *)); +static int pccbb_pcmcia_submatch __P((struct device *, struct cfdata *, void *)); + +static int pccbb_cardbus_submatch __P((struct device *, struct cfdata *, void *)); + +#if defined SHOW_REGS +static void cb_show_regs __P((pci_chipset_tag_t pc, pcitag_t tag, bus_space_tag_t memt, bus_space_handle_t memh)); +#endif + +struct cfattach cbb_pci_ca = { + sizeof(struct pccbb_softc), pccbbmatch, pccbbattach +}; + +static struct pcmcia_chip_functions pccbb_pcmcia_funcs = { + pccbb_pcmcia_mem_alloc, + pccbb_pcmcia_mem_free, + pccbb_pcmcia_mem_map, + pccbb_pcmcia_mem_unmap, + pccbb_pcmcia_io_alloc, + pccbb_pcmcia_io_free, + pccbb_pcmcia_io_map, + pccbb_pcmcia_io_unmap, + pccbb_pcmcia_intr_establish, + pccbb_pcmcia_intr_disestablish, + pccbb_pcmcia_socket_enable, + pccbb_pcmcia_socket_disable, +}; + +static struct cardbus_functions pccbb_funcs = { + pccbb_ctrl, + pccbb_power, + pccbb_mem_open, + pccbb_mem_close, + pccbb_io_open, + pccbb_io_close, + pccbb_intr_establish, + pccbb_intr_disestablish, + pccbb_make_tag, + pccbb_free_tag, + pccbb_conf_read, + pccbb_conf_write, +}; + + +int +pccbbmatch(parent, match, aux) + struct device *parent; + struct cfdata *match; + void *aux; +{ + struct pci_attach_args *pa = (struct pci_attach_args *)aux; + + if ((pa->pa_class & PCI_CLASS_INTERFACE_MASK) == PCI_CLASS_INTERFACE_YENTA) { + /* OK, It must be YENTA PCI-CardBus bridge */ + return 2; /* beat chipset_match */ + } + + return 0; +} + + +#define MAKEID(vendor, prod) (((vendor) << PCI_VENDOR_SHIFT) \ + | ((prod) << PCI_PRODUCT_SHIFT)) + +struct yenta_chipinfo { + pcireg_t yc_id; /* vendor tag | product tag */ + const char *yc_name; + int yc_chiptype; + int yc_flags; +} yc_chipsets[] = { + /* Texas Instruments chips */ + {MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1130), "TI1130", CB_TI113X, + PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32}, + {MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1131), "TI1131", CB_TI113X, + PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32}, + + {MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1250), "TI1250", CB_TI12XX, + PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32}, + {MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1220), "TI1220", CB_TI12XX, + PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32}, + {MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1221), "TI1221", CB_TI12XX, + PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32}, + {MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1225), "TI1225", CB_TI12XX, + PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32}, + {MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI2030), "TI2030", CB_UNKNOWN, + PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32}, + + /* Ricoh chips */ + {MAKEID(PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_RF5C475), "RF5C475", + CB_RF5C47X, PCCBB_PCMCIA_MEM_32}, + {MAKEID(PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_RF5C476), "RF5C476", + CB_RF5C47X, PCCBB_PCMCIA_MEM_32}, + {MAKEID(PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_RF5C477), "RF5C477", + CB_RF5C47X, PCCBB_PCMCIA_MEM_32}, + {MAKEID(PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_RF5C477), "RF5C478", + CB_RF5C47X, PCCBB_PCMCIA_MEM_32}, + + {MAKEID(PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_RF5C465), "RF5C465", + CB_RF5C46X, PCCBB_PCMCIA_MEM_32}, + {MAKEID(PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_RF5C466), "RF5C466", + CB_RF5C46X, PCCBB_PCMCIA_MEM_32}, + + /* Toshiba products */ + {MAKEID(PCI_VENDOR_TOSHIBA2, PCI_PRODUCT_TOSHIBA2_ToPIC95), "ToPIC95", + CB_TOPIC95, PCCBB_PCMCIA_MEM_32}, + {MAKEID(PCI_VENDOR_TOSHIBA2, PCI_PRODUCT_TOSHIBA2_ToPIC95B), "ToPIC95B", + CB_TOPIC95B, PCCBB_PCMCIA_MEM_32}, + {MAKEID(PCI_VENDOR_TOSHIBA2, PCI_PRODUCT_TOSHIBA2_ToPIC95B), "ToPIC97", + CB_TOPIC97, PCCBB_PCMCIA_MEM_32}, + + /* sentinel */ + {0 /* null id */, "unknown", + CB_UNKNOWN, 0}, +}; + + +static int +cb_chipset(pci_id, namep, flagp) + u_int32_t pci_id; + char const **namep; + int *flagp; +{ + int loopend = sizeof(yc_chipsets)/sizeof(yc_chipsets[0]); + struct yenta_chipinfo *ycp, *ycend; + + ycend = yc_chipsets + loopend; + + for (ycp =yc_chipsets; ycp < ycend && pci_id != ycp->yc_id; ++ycp); + + if (ycp == ycend) { + /* not found */ + ycp = yc_chipsets + loopend - 1; /* to point the sentinel */ + } + + if (namep != NULL) { + *namep = ycp->yc_name; + } + + if (flagp != NULL) { + *flagp = ycp->yc_flags; + } + + return ycp->yc_chiptype; +} + +void +pccbbattach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + struct pccbb_softc *sc = (void *)self; + struct pci_attach_args *pa = aux; + pci_chipset_tag_t pc = pa->pa_pc; + pcireg_t sock_base, cbctrl; + bus_addr_t sockbase; + bus_space_tag_t base_memt; + bus_space_handle_t base_memh; + u_int32_t maskreg; + pci_intr_handle_t ih; + const char *intrstr = NULL; + char const *name; + int flags; + + sc->sc_chipset = cb_chipset(pa->pa_id, &name, &flags); + printf(" (%s), flags %d\n", name, flags); + + /* pccbb_machdep.c start */ +#if 0 + pcbb_attach_machdef(pa, sc); +#endif + + /* MAP socket registers and ExCA registers on memory-space + When no valid address is set on socket base registers (on pci + config space), get it not polite way */ + sock_base = pci_conf_read(pc, pa->pa_tag, PCI_SOCKBASE); + + if (PCI_MAPREG_MEM_ADDR(sock_base) <= 0x100000 || + PCI_MAPREG_MEM_ADDR(sock_base) == 0xfffffff0) { + /* The address may be invalid. */ + sc->sc_base_memt = pa->pa_memt; +#if !defined CBB_PCI_BASE +#define CBB_PCI_BASE 0x20000000 +#endif + if (bus_space_alloc(sc->sc_base_memt, CBB_PCI_BASE, 0xffffffff, + 0x1000, /* size */ + (sc->sc_chipset == CB_RF5C47X || sc->sc_chipset == CB_TI113X) ? 0x10000 : 0x1000, /* alignment */ + 0, /* boundary */ + 0, /* flags */ + &sockbase, &sc->sc_base_memh)) { + /* cannot allocate memory space */ + return; + } + pci_conf_write(pc, pa->pa_tag, PCI_SOCKBASE, sockbase); + DPRINTF(("%s: CardBus resister address 0x%x -> 0x%lx\n",sc->sc_dev.dv_xname, + sock_base, pci_conf_read(pc, pa->pa_tag, PCI_SOCKBASE))); + } else { + /* The address must be valid. */ + if (pci_mapreg_map(pa, PCI_SOCKBASE, PCI_MAPREG_TYPE_MEM, 0, + &sc->sc_base_memt, &sc->sc_base_memh, &sockbase, + NULL)) { + printf("%s: can't map socket base address 0x%x\n", sc->sc_dev.dv_xname, + sock_base); + /* I think it's funny: socket base registers must be mapped on + memory space, but ... */ + if (pci_mapreg_map(pa, PCI_SOCKBASE, PCI_MAPREG_TYPE_IO, 0, + &sc->sc_base_memt, &sc->sc_base_memh, + &sockbase, NULL)) { + printf("%s: can't map socket base address 0x%lx: io mode\n", + sc->sc_dev.dv_xname, (u_long)sockbase); + return; + } + } else { + DPRINTF(("%s: socket base address 0x%lx",sc->sc_dev.dv_xname, (u_long)sockbase)); + } + } + + sc->sc_mem_start = CBB_PCI_BASE; /* XXX */ + sc->sc_mem_end = 0xffffffff; /* XXX */ + + /* pccbb_machdep.c end */ + +#if defined CBB_DEBUG + { + static char *intrname[5] = {"NON", "A", "B", "C", "D"}; + printf(" intrpin %s, intrtag %d\n", intrname[pa->pa_intrpin], + pa->pa_intrline); + } +#endif + + /****** setup softc ******/ + sc->sc_pc = pc; + sc->sc_iot = pa->pa_iot; + sc->sc_memt = pa->pa_memt; + sc->sc_tag = pa->pa_tag; + sc->sc_function = pa->pa_function; + + sc->sc_intrline = pa->pa_intrline; + sc->sc_intrtag = pa->pa_intrtag; + sc->sc_intrpin = pa->pa_intrpin; + + pccbb_chipinit(pa, sc); + + base_memt = sc->sc_base_memt; /* socket regs memory tag */ + base_memh = sc->sc_base_memh; /* socket regs memory handle */ + + /* CSC Interrupt: Card detect interrupt on */ + maskreg = bus_space_read_4(base_memt, base_memh, CB_SOCKET_MASK); + maskreg |= CB_SOCKET_MASK_CD; /* Card detect intr is turned on. */ + bus_space_write_4(base_memt, base_memh, CB_SOCKET_MASK, maskreg); + /* reset interrupt */ + bus_space_write_4(base_memt, base_memh, CB_SOCKET_EVENT, + bus_space_read_4(base_memt, base_memh, CB_SOCKET_EVENT)); + + + /* Map and establish the interrupt. */ + if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin, + pa->pa_intrline, &ih)) { + printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname); + return; + } + intrstr = pci_intr_string(pc, ih); + + sc->sc_ih = pci_intr_establish(pc, ih, IPL_BIO, (void(*)(void*))pccbbintr, sc); + /* + * queue creation of a kernel thread to handle insert/removal events. + */ + pccbb_kthread_init (sc); + + if (sc->sc_ih == NULL) { + printf("%s: couldn't establish interrupt", sc->sc_dev.dv_xname); + if (intrstr != NULL) { + printf(" at %s", intrstr); + } + printf("\n"); + return; + } + + printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr); + + /* Check card exists or not. if exists, cb_reset will reset card */ + { + u_int32_t sockstat = bus_space_read_4(base_memt,base_memh, CB_SOCKET_STAT); + if (0 == (sockstat & CB_SOCKET_STAT_CD)) { /* card exist */ + sc->sc_flags |= CBB_CARDEXIST; + } + } + /****** attach cardbus ******/ + { + struct cbslot_attach_args cba; + struct cardbus_softc *csc; /* child softc */ + u_int32_t busreg = pci_conf_read(pc, pa->pa_tag, PCI_BUSNUM); + + /* initialise cbslot_attach */ + cba.cba_busname = "cardbus"; + cba.cba_iot = pa->pa_iot; + cba.cba_memt = pa->pa_memt; + cba.cba_dmat = pa->pa_dmat; +#if 1 /* XXX */ + cba.cba_function = pa->pa_function; +#else + cba.cba_function = 0; +#endif + cba.cba_bus = (busreg >> 8) & 0x0ff; + cba.cba_cc = (void *)sc; + cba.cba_cf = &pccbb_funcs; + cba.cba_intrline = pci_intr_line (pa, ih); +#if defined SHOW_REGS + cb_show_regs(sc->sc_pc, sc->sc_tag, sc->sc_base_memt, sc->sc_base_memh); +#endif + if (NULL != (csc = (void *)config_found(self, &cba, cbbprint))) { + DPRINTF(("pccbbattach: found cardbus\n")); + sc->sc_csc = csc; + } + } + + /****** attach pccard bus ******/ + pccbb_pcmcia_attach(sc); + + return; +} + +static void +pccbb_chipinit(pa, sc) + struct pci_attach_args *pa; + struct pccbb_softc *sc; +{ + pci_chipset_tag_t pc = pa->pa_pc; + bus_space_tag_t base_memt = sc->sc_base_memt; /* socket regs memory tag */ + bus_space_handle_t base_memh = sc->sc_base_memh; /* socket regs memory handle */ + pcireg_t cbctrl; + + /* + Set CardBus latency timer + */ + { + pcireg_t pci_lscp = pci_conf_read(pc, pa->pa_tag, PCI_CB_LSCP_REG); + if (PCI_CB_LATENCY(pci_lscp) < 0x20) { + pci_lscp &= ~(PCI_CB_LATENCY_MASK << PCI_CB_LATENCY_SHIFT); + pci_lscp |= (0x20 << PCI_CB_LATENCY_SHIFT); + pci_conf_write(pc, pa->pa_tag, PCI_CB_LSCP_REG, pci_lscp); + } + printf("CardBus latency time 0x%x\n", PCI_CB_LATENCY(pci_lscp)); + } + + /* + Set PCI latency timer + */ + { + pcireg_t pci_bhlc = pci_conf_read(pc, pa->pa_tag, PCI_BHLC_REG); + if (PCI_LATTIMER(pci_bhlc) < 0x20) { + pci_bhlc &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT); + pci_bhlc |= (0x20 << PCI_LATTIMER_SHIFT); + pci_conf_write(pc, pa->pa_tag, PCI_BHLC_REG, pci_bhlc); + } + printf("PCI latency time 0x%x\n", PCI_LATTIMER(pci_bhlc)); + } + + /* disable Legacy IO */ + + switch (sc->sc_chipset) { + case CB_RF5C46X: + { + pcireg_t bcri = pci_conf_read(pc, pa->pa_tag, PCI_BCR_INTR); + bcri &= ~(CB_BCRI_RL_3E0_ENA | CB_BCRI_RL_3E2_ENA); + pci_conf_write(pc, pa->pa_tag, PCI_BCR_INTR, bcri); + } + break; + default: + /* XXX: I don't know how to kill Legacy IO properly. */ + pci_conf_write(pc, pa->pa_tag, PCI_LEGACY, 0x0); + break; + } + + /****** Interrupt routing ******/ + + /* use PCI interrupt */ + { + u_int32_t bcr = pci_conf_read(pc, pa->pa_tag, PCI_BCR_INTR); + bcr &= ~CB_BCR_INTR_IREQ_ENABLE; /* use PCI Intr */ + bcr |= CB_BCR_WRITE_POST_ENABLE; /* enable write post */ + pci_conf_write(pc, pa->pa_tag, PCI_BCR_INTR, bcr); + } + + if (CB_TI113X == sc->sc_chipset) { + cbctrl = pci_conf_read(pc, pa->pa_tag, PCI_CBCTRL); + if (0 == pa->pa_function) { + cbctrl |= PCI113X_CBCTRL_PCI_IRQ_ENA; + } + cbctrl |= PCI113X_CBCTRL_PCI_IRQ_ENA; /* XXX: bug in PCI113X */ + cbctrl |= PCI113X_CBCTRL_PCI_CSC; /* CSC intr enable */ + cbctrl &= ~PCI113X_CBCTRL_PCI_INTR; /* functional intr prohibit */ + cbctrl &= ~PCI113X_CBCTRL_INT_MASK; /* prohibit ISA routing */ + pci_conf_write(pc, pa->pa_tag, PCI_CBCTRL, cbctrl); + + /* set ExCA regs: PCI113X required to be set bit 4 at Interrupt + and General Register, which is IRQ Enable Register, and clear + bit 3:0 to zero in order to route CSC interrupt to PCI + interrupt pin. */ + bus_space_write_1(base_memt, base_memh, 0x0803, 0x10); + /* set ExCA regs: prohibit all pcmcia-style CSC intr. */ + bus_space_write_1(base_memt, base_memh, 0x0805, 0x00); +#if 1 + DPRINTF(("ExCA regs:")); + DPRINTF((" 0x803: %02x", bus_space_read_1(base_memt, base_memh, 0x803))); + DPRINTF((" 0x805: %02x", bus_space_read_1(base_memt, base_memh, 0x805))); + DPRINTF((" 0x81e: %02x\n", bus_space_read_1(base_memt,base_memh,0x81e))); +#endif + } else if (sc->sc_chipset == CB_TI12XX) { + cbctrl = pci_conf_read(pc, pa->pa_tag, PCI_CBCTRL); + cbctrl &= ~PCI12XX_CBCTRL_INT_MASK; /* intr routing reset */ + cbctrl |= PCI12XX_CBCTRL_INT_PCI; /* PCI intr */ + pci_conf_write(pc, pa->pa_tag, PCI_CBCTRL, cbctrl); + bus_space_write_1(base_memt, base_memh, 0x0803, 0x10); + bus_space_write_1(base_memt, base_memh, 0x0805, 0x00); + } else if (sc->sc_chipset == CB_TOPIC95B) { + cardbusreg_t sock_ctrl, slot_ctrl; + + sock_ctrl = pci_conf_read(pc, pa->pa_tag, TOPIC_SOCKET_CTRL); + pci_conf_write(pc, pa->pa_tag, TOPIC_SOCKET_CTRL, + sock_ctrl | TOPIC_SOCKET_CTRL_SCR_IRQSEL); + + slot_ctrl = pci_conf_read(pc, pa->pa_tag, TOPIC_SLOT_CTRL); + DPRINTF(("%s: topic slot ctrl reg 0x%x -> ", sc->sc_dev.dv_xname, + slot_ctrl)); +/* slot_ctrl &= ~TOPIC_SLOT_CTRL_CLOCK_MASK;*/ + slot_ctrl |= (TOPIC_SLOT_CTRL_SLOTON | TOPIC_SLOT_CTRL_SLOTEN | + TOPIC_SLOT_CTRL_ID_LOCK); + slot_ctrl |= TOPIC_SLOT_CTRL_CARDBUS; + slot_ctrl &= ~TOPIC_SLOT_CTRL_SWDETECT; + pci_conf_write(pc, pa->pa_tag, TOPIC_SLOT_CTRL, slot_ctrl); + DPRINTF(("0x%x\n", slot_ctrl)); + } + + /* close all memory and io windows */ + pci_conf_write(pc, pa->pa_tag, PCI_CB_MEMBASE0, 0xffffffff); + pci_conf_write(pc, pa->pa_tag, PCI_CB_MEMLIMIT0, 0); + pci_conf_write(pc, pa->pa_tag, PCI_CB_MEMBASE1, 0xffffffff); + pci_conf_write(pc, pa->pa_tag, PCI_CB_MEMLIMIT1, 0); + pci_conf_write(pc, pa->pa_tag, PCI_CB_IOBASE0, 0xffffffff); + pci_conf_write(pc, pa->pa_tag, PCI_CB_IOLIMIT0, 0); + pci_conf_write(pc, pa->pa_tag, PCI_CB_IOBASE1, 0xffffffff); + pci_conf_write(pc, pa->pa_tag, PCI_CB_IOLIMIT1, 0); + +} + + +/****** attach pccard bus ******/ +STATIC void +pccbb_pcmcia_attach(sc) + struct pccbb_softc *sc; +{ + struct cbb_pcic_handle *ph = &sc->sc_pcmcia_h; + struct pcmciabus_attach_args paa; + + sc->sc_pcmcia_flags |= (PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32); + + /* initialise pcmcia part in pccbb_softc */ + ph->sc = sc; + ph->sock = sc->sc_function; + ph->flags = 0; + ph->shutdown = 0; + ph->ih_irq = sc->sc_intrline; + ph->ph_iot = sc->sc_base_memt; + ph->ph_ioh = sc->sc_base_memh; + ph->ph_read = pccbb_pcmcia_read; + ph->ph_write = pccbb_pcmcia_write; + sc->sc_pct = &pccbb_pcmcia_funcs; + + Pcic_write(ph, PCIC_CSC_INTR, 0); + Pcic_read(ph, PCIC_CSC); + + /* initialise pcmcia bus attachment */ + paa.paa_busname = "pcmcia"; + paa.pct = sc->sc_pct; + paa.pch = ph; + paa.iobase = 0; /* I don't use them */ + paa.iosize = 0; + + ph->pcmcia = config_found_sm(&ph->sc->sc_dev, &paa, pccbb_pcmcia_print, + pccbb_pcmcia_submatch); + if (ph->pcmcia != NULL) { + if (1 == pccbb_detect_card(sc)) { + printf("%s: a 16-bit pcmcia card found.\n", sc->sc_dev.dv_xname); /*XXX*/ + pccbb_pcmcia_attach_card(ph); + } + } + return; +} + + + +STATIC void +pccbb_pcmcia_attach_card(ph) + struct cbb_pcic_handle *ph; +{ + struct pcmcia_softc *psc = (void*)ph->pcmcia; + if (ph->flags & PCIC_FLAG_CARDP) { + panic("pccbb_pcmcia_attach_card: already attached"); + } + + /* call the MI attach function */ + psc->sc_if.if_card_attach(ph->pcmcia); + ph->flags |= PCIC_FLAG_CARDP; +} + + +STATIC void +pccbb_pcmcia_detach_card(ph, flags) + struct cbb_pcic_handle *ph; + int flags; +{ + struct pcmcia_softc *psc = (void*)ph->pcmcia; + if (!(ph->flags & PCIC_FLAG_CARDP)) { + panic("pccbb_pcmcia_detach_card: already detached"); + } + + ph->flags &= ~PCIC_FLAG_CARDP; + + /* call the MI detach function */ + psc->sc_if.if_card_detach (ph->pcmcia, flags); +} + +/********************************************************************** +* int pccbbintr(arg) +* void *arg; +* This routine handles the interrupt from Yenta PCI-CardBus bridge +* itself. +**********************************************************************/ +int +pccbbintr(arg) + void *arg; +{ + struct pccbb_softc *sc = arg; + bus_space_tag_t memt = sc->sc_base_memt; + bus_space_handle_t memh = sc->sc_base_memh; + u_int32_t sockevent, sockstate; + int s; + + if (!(sockevent = bus_space_read_4 (memt, memh, CB_SOCKET_EVENT))) + return 0; /* not for me */ + /* reset bit */ + bus_space_write_4 (memt, memh, CB_SOCKET_EVENT, sockevent); + + if (sockevent & CB_SOCKET_EVENT_CD) { + if (!(sc->sc_flags & CBB_CARDSTATUS_BUSY)) { + s = splhigh (); /* lock softc */ + sc->sc_queued = 1; + sc->sc_flags |= CBB_CARDSTATUS_BUSY; + splx (s); /* unlock softc */ + wakeup (&sc->events); + } else { + DPRINTF(("%s (pccbbintr): busy", sc->sc_dev.dv_xname)); + sc->sc_flags &= ~CBB_CARDSTATUS_BUSY; /* XXX chatterling interrupts. Should change code like as i82365.c */ + } + } else { + sockstate = bus_space_read_4 (memt, memh, CB_SOCKET_STAT); + DPRINTF(("%s (pccbbintr): 0x%08x", sc->sc_dev.dv_xname, sockevent)); + if (sockevent & CB_SOCKET_EVENT_CSTS) { + DPRINTF((" cstsevent occures, 0x%08x\n", sockstate)); + } else if (sockevent & CB_SOCKET_EVENT_POWER) { + DPRINTF((" pwrevent occures, 0x%08x\n", sockstate)); + } else { + DPRINTF((" unknown event, 0x%08x\n", sockstate)); + } + } + + return 1; +} + +static void +pccbb_insert(arg) + void *arg; +{ + struct pccbb_softc *sc = (struct pccbb_softc *)arg; + u_int32_t sockevent, sockstate; + int timeout = 30; + do { + sockevent = bus_space_read_4(sc->sc_base_memt, sc->sc_base_memh, + CB_SOCKET_EVENT); + sockstate = bus_space_read_4(sc->sc_base_memt, sc->sc_base_memh, + CB_SOCKET_STAT); + } while (sockstate & CB_SOCKET_STAT_CD && --timeout > 0); + if (timeout < 0) { + printf ("%s: insert timeout", sc->sc_dev.dv_xname); + return; + } + DPRINTF(("%s: 0x%08x", sc->sc_dev.dv_xname, sockevent)); + DPRINTF((" card inserted, 0x%08x\n", sockstate)); + sc->sc_flags |= CBB_CARDEXIST; + /* call pccard intterupt handler here */ + if (sockstate & CB_SOCKET_STAT_16BIT) { + /* 16-bit card */ + pccbb_pcmcia_attach_card(&sc->sc_pcmcia_h); + } else if (sockstate & CB_SOCKET_STAT_CB) { + /* 32-bit card */ + sc->sc_cbdev = sc->sc_csc->sc_if.if_card_attach (sc->sc_csc); + } else { + printf ("unknown card type.\n"); + } +} + +#define PCCBB_PCMCIA_OFFSET 0x800 +static u_int8_t +pccbb_pcmcia_read(ph, reg) + struct cbb_pcic_handle *ph; + int reg; +{ + return bus_space_read_1(ph->ph_iot, ph->ph_ioh, PCCBB_PCMCIA_OFFSET + reg); +} + +static void +pccbb_pcmcia_write(ph, reg, val) + struct cbb_pcic_handle *ph; + int reg; + u_int8_t val; +{ + bus_space_write_1(ph->ph_iot, ph->ph_ioh, PCCBB_PCMCIA_OFFSET + reg, val); + + return; +} + +/********************************************************************** +* STATIC int pccbb_ctrl(cardbus_chipset_tag_t, int) +**********************************************************************/ +STATIC int +pccbb_ctrl(ct, command) + cardbus_chipset_tag_t ct; + int command; +{ + struct pccbb_softc *sc = (struct pccbb_softc *)ct; + + switch(command) { + case CARDBUS_CD: + if (2 == pccbb_detect_card(sc)) { + int retval = 0; + int status = cb_detect_voltage(sc); + if (PCCARD_VCC_5V & status) { + retval |= CARDBUS_5V_CARD; + } + if (PCCARD_VCC_3V & status) { + retval |= CARDBUS_3V_CARD; + } + if (PCCARD_VCC_XV & status) { + retval |= CARDBUS_XV_CARD; + } + if (PCCARD_VCC_YV & status) { + retval |= CARDBUS_YV_CARD; + } + return retval; + } else { + return 0; + } + break; + case CARDBUS_RESET: + return cb_reset(sc); + break; + case CARDBUS_IO_ENABLE: /* fallthrough */ + case CARDBUS_IO_DISABLE: /* fallthrough */ + case CARDBUS_MEM_ENABLE: /* fallthrough */ + case CARDBUS_MEM_DISABLE: /* fallthrough */ + case CARDBUS_BM_ENABLE: /* fallthrough */ + case CARDBUS_BM_DISABLE: /* fallthrough */ + return pccbb_cardenable(sc, command); + break; + } + + return 0; +} + + + +/********************************************************************** +* STATIC int pccbb_power(cardbus_chipset_tag_t, int) +* This function returns true when it succeeds and returns false when +* it fails. +**********************************************************************/ +STATIC int +pccbb_power(ct, command) + cardbus_chipset_tag_t ct; + int command; +{ + struct pccbb_softc *sc = (struct pccbb_softc *)ct; + + u_int32_t status, sock_ctrl; + bus_space_tag_t memt = sc->sc_base_memt; + bus_space_handle_t memh = sc->sc_base_memh; + + DPRINTF(("pccbb_power: %s and %s [%x]\n", + (command & CARDBUS_VCCMASK) == CARDBUS_VCC_UC ? "CARDBUS_VCC_UC" : + (command & CARDBUS_VCCMASK) == CARDBUS_VCC_5V ? "CARDBUS_VCC_5V" : + (command & CARDBUS_VCCMASK) == CARDBUS_VCC_3V ? "CARDBUS_VCC_3V" : + (command & CARDBUS_VCCMASK) == CARDBUS_VCC_XV ? "CARDBUS_VCC_XV" : + (command & CARDBUS_VCCMASK) == CARDBUS_VCC_YV ? "CARDBUS_VCC_YV" : + (command & CARDBUS_VCCMASK) == CARDBUS_VCC_0V ? "CARDBUS_VCC_0V" : + "UNKNOWN", + (command & CARDBUS_VPPMASK) == CARDBUS_VPP_UC ? "CARDBUS_VPP_UC" : + (command & CARDBUS_VPPMASK) == CARDBUS_VPP_12V ? "CARDBUS_VPP_12V" : + (command & CARDBUS_VPPMASK) == CARDBUS_VPP_VCC ? "CARDBUS_VPP_VCC" : + (command & CARDBUS_VPPMASK) == CARDBUS_VPP_0V ? "CARDBUS_VPP_0V" : + "UNKNOWN", + command)); + + status = bus_space_read_4(memt, memh, CB_SOCKET_STAT); + sock_ctrl = bus_space_read_4(memt, memh, CB_SOCKET_CTRL); + + switch (command & CARDBUS_VCCMASK) { + case CARDBUS_VCC_UC: + break; + case CARDBUS_VCC_5V: + if (CB_SOCKET_STAT_5VCARD & status) { /* check 5 V card */ + sock_ctrl &= ~CB_SOCKET_CTRL_VCCMASK; + sock_ctrl |= CB_SOCKET_CTRL_VCC_5V; + } else { + printf("%s: BAD voltage request: no 5 V card\n", sc->sc_dev.dv_xname); + } + break; + case CARDBUS_VCC_3V: + if (CB_SOCKET_STAT_3VCARD & status) { + sock_ctrl &= ~CB_SOCKET_CTRL_VCCMASK; + sock_ctrl |= CB_SOCKET_CTRL_VCC_3V; + } else { + printf("%s: BAD voltage request: no 3.3 V card\n", sc->sc_dev.dv_xname); + } + break; + case CARDBUS_VCC_0V: + sock_ctrl &= ~CB_SOCKET_CTRL_VCCMASK; + break; + default: + return 0; /* power NEVER changed */ + break; + } + + switch (command & CARDBUS_VPPMASK) { + case CARDBUS_VPP_UC: + break; + case CARDBUS_VPP_0V: + sock_ctrl &= ~CB_SOCKET_CTRL_VPPMASK; + break; + case CARDBUS_VPP_VCC: + sock_ctrl &= ~CB_SOCKET_CTRL_VPPMASK; + sock_ctrl |= ((sock_ctrl >> 4) & 0x07); + break; + case CARDBUS_VPP_12V: + sock_ctrl &= ~CB_SOCKET_CTRL_VPPMASK; + sock_ctrl |= CB_SOCKET_CTRL_VPP_12V; + break; + } + +#if 0 + DPRINTF(("sock_ctrl: %x\n", sock_ctrl)); +#endif + bus_space_write_4(memt, memh, CB_SOCKET_CTRL, sock_ctrl); + status = bus_space_read_4(memt, memh, CB_SOCKET_STAT); + + { + int timeout = 20; + u_int32_t sockevent; + do { + delay(20*1000); /* wait 20 ms: Vcc setup time */ + sockevent = bus_space_read_4 (memt, memh, CB_SOCKET_EVENT); + } while (!(sockevent & CB_SOCKET_EVENT_POWER) && --timeout > 0); + /* reset event status */ + bus_space_write_4 (memt, memh, CB_SOCKET_EVENT, sockevent); + if ( timeout < 0 ) { + printf ("VCC supply failed.\n"); + return 0; + } + } + /* XXX + delay 400 ms: thgough the standard defines that the Vcc set-up time + is 20 ms, some PC-Card bridge requires longer duration. + */ + delay(400*1000); + + if (status & CB_SOCKET_STAT_BADVCC) { /* bad Vcc request */ + printf("%s: bad Vcc request. sock_ctrl 0x%x, sock_status 0x%x\n", + sc->sc_dev.dv_xname, sock_ctrl ,status); + printf("pccbb_power: %s and %s [%x]\n", + (command & CARDBUS_VCCMASK) == CARDBUS_VCC_UC ? "CARDBUS_VCC_UC" : + (command & CARDBUS_VCCMASK) == CARDBUS_VCC_5V ? "CARDBUS_VCC_5V" : + (command & CARDBUS_VCCMASK) == CARDBUS_VCC_3V ? "CARDBUS_VCC_3V" : + (command & CARDBUS_VCCMASK) == CARDBUS_VCC_XV ? "CARDBUS_VCC_XV" : + (command & CARDBUS_VCCMASK) == CARDBUS_VCC_YV ? "CARDBUS_VCC_YV" : + (command & CARDBUS_VCCMASK) == CARDBUS_VCC_0V ? "CARDBUS_VCC_0V" : + "UNKNOWN", + (command & CARDBUS_VPPMASK) == CARDBUS_VPP_UC ? "CARDBUS_VPP_UC" : + (command & CARDBUS_VPPMASK) == CARDBUS_VPP_12V ? "CARDBUS_VPP_12V" : + (command & CARDBUS_VPPMASK) == CARDBUS_VPP_VCC ? "CARDBUS_VPP_VCC" : + (command & CARDBUS_VPPMASK) == CARDBUS_VPP_0V ? "CARDBUS_VPP_0V" : + "UNKNOWN", + command); +#if defined DIAGNOSTIC + if (command == (CARDBUS_VCC_0V | CARDBUS_VPP_0V)) { + u_int32_t force = bus_space_read_4(memt, memh, CB_SOCKET_FORCE); + /* Reset Bad Vcc request */ + force &= ~CB_SOCKET_FORCE_BADVCC; + bus_space_write_4(memt, memh, CB_SOCKET_FORCE, force); + printf("new status 0x%x\n", bus_space_read_4(memt, memh,CB_SOCKET_STAT)); + return 1; + } +#endif + return 0; + } + return 1; /* power changed correctly */ +} + +/********************************************************************** +* static int pccbb_detect_card(struct pccbb_softc *sc) +* return value: 0 if no card exists. +* 1 if 16-bit card exists. +* 2 if cardbus card exists. +**********************************************************************/ +static int +pccbb_detect_card(sc) + struct pccbb_softc *sc; +{ + bus_space_handle_t base_memh = sc->sc_base_memh; + bus_space_tag_t base_memt = sc->sc_base_memt; + u_int32_t sockstat = bus_space_read_4(base_memt,base_memh, CB_SOCKET_STAT); + int retval = 0; + + if (0x00 == (sockstat & CB_SOCKET_STAT_CD)) { /* CD1 and CD2 asserted */ + /* card must be present */ + if (!(CB_SOCKET_STAT_NOTCARD & sockstat)) { /* NOTACARD DEASSERTED */ + if (CB_SOCKET_STAT_CB & sockstat) { /* CardBus mode */ + retval = 2; + } else if (CB_SOCKET_STAT_16BIT & sockstat) { /* 16-bit mode */ + retval = 1; + } + } + } + return retval; +} + + + + +/********************************************************************** +* STATIC int cb_reset(struct pccbb_softc *sc) +* This function resets the card. +**********************************************************************/ +STATIC int +cb_reset(sc) + struct pccbb_softc *sc; +{ + u_int32_t bcr = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_BCR_INTR); + int delay_us; + delay_us = sc->sc_chipset == CB_RF5C47X ? 400*1000 : 20*1000; + + bcr |= (0x40 << 16); /* Reset bit Assert (bit 6 at 0x3E) */ + pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_BCR_INTR, bcr); + /* Reset Assert at least 20 ms */ + delay(delay_us); + + if (CBB_CARDEXIST & sc->sc_flags) { /* A card exists. Reset it! */ + bcr &= ~(0x40 << 16); /* Reset bit Deassert (bit 6 at 0x3E) */ + pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_BCR_INTR, bcr); + delay(delay_us); + } + /* No card found on the slot. Keep Reset. */ + return 1; +} + +/********************************************************************** +* STATIC int cb_detect_voltage(struct pccbb_softc *sc) +* This function detect card Voltage. +**********************************************************************/ +STATIC int +cb_detect_voltage(sc) + struct pccbb_softc *sc; +{ + u_int32_t psr; /* socket present-state reg */ + bus_space_tag_t iot = sc->sc_base_memt; + bus_space_handle_t ioh = sc->sc_base_memh; + int vol = PCCARD_VCC_UKN; /* set 0 */ + + psr = bus_space_read_4(iot, ioh, CB_SOCKET_STAT); + + if (0x400u & psr) { + vol |= PCCARD_VCC_5V; + } + if (0x800u & psr) { + vol |= PCCARD_VCC_3V; + } + + return vol; +} + +/********************************************************************** +* STATIC int pccbb_cardenable(struct pccbb_softc *sc, int function) +* This function enables and disables the card +**********************************************************************/ +STATIC int +pccbb_cardenable(sc, function) + struct pccbb_softc *sc; + int function; +{ + u_int32_t command = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG); + + DPRINTF(("pccbb_cardenable:")); + switch (function) { + case CARDBUS_IO_ENABLE: + command |= PCI_COMMAND_IO_ENABLE; + break; + case CARDBUS_IO_DISABLE: + command &= ~PCI_COMMAND_IO_ENABLE; + break; + case CARDBUS_MEM_ENABLE: + command |= PCI_COMMAND_MEM_ENABLE; + break; + case CARDBUS_MEM_DISABLE: + command &= ~PCI_COMMAND_MEM_ENABLE; + break; + case CARDBUS_BM_ENABLE: + command |= PCI_COMMAND_MASTER_ENABLE; + break; + case CARDBUS_BM_DISABLE: + command &= ~PCI_COMMAND_MASTER_ENABLE; + break; + default: + return 0; + } + + pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG, command); + DPRINTF((" command reg 0x%x\n", command)); + return 1; +} + + + + + + + +/********************************************************************** +* int pccbb_io_open(cardbus_chipset_tag_t, int, u_int32_t, u_int32_t) +**********************************************************************/ +static int +pccbb_io_open(ct, win, start, end) + cardbus_chipset_tag_t ct; + int win; + u_int32_t start, end; +{ + struct pccbb_softc *sc = (struct pccbb_softc *)ct; + int basereg; + int limitreg; + + if ((win < 0) || (win > 2)) { +#if defined DIAGNOSTIC + printf("cardbus_io_open: window out of range %d\n", win); +#endif + return 0; + } + + basereg = win*8 + 0x2c; + limitreg = win*8 + 0x30; + + DPRINTF(("pccbb_io_open: 0x%x[0x%x] - 0x%x[0x%x]\n", + start, basereg, end, limitreg)); + + pci_conf_write(sc->sc_pc, sc->sc_tag, basereg, start); + pci_conf_write(sc->sc_pc, sc->sc_tag, limitreg, end); + return 1; +} + +/********************************************************************** +* int pccbb_io_close(cardbus_chipset_tag_t, int) +**********************************************************************/ +static int +pccbb_io_close(ct, win) + cardbus_chipset_tag_t ct; + int win; +{ + struct pccbb_softc *sc = (struct pccbb_softc *)ct; + int basereg; + int limitreg; + + if ((win < 0) || (win > 2)) { +#if defined DIAGNOSTIC + printf("cardbus_io_close: window out of range %d\n", win); +#endif + return 0; + } + + basereg = win*8 + 0x2c; + limitreg = win*8 + 0x30; + + pci_conf_write(sc->sc_pc, sc->sc_tag, basereg, 0); + pci_conf_write(sc->sc_pc, sc->sc_tag, limitreg, 0); + return 1; +} + +/********************************************************************** +* int pccbb_mem_open(cardbus_chipset_tag_t, int, u_int32_t, u_int32_t) +**********************************************************************/ +static int +pccbb_mem_open(ct, win, start, end) + cardbus_chipset_tag_t ct; + int win; + u_int32_t start, end; +{ + struct pccbb_softc *sc = (struct pccbb_softc *)ct; + int basereg; + int limitreg; + + if ((win < 0) || (win > 2)) { +#if defined DIAGNOSTIC + printf("cardbus_mem_open: window out of range %d\n", win); +#endif + return 0; + } + + basereg = win*8 + 0x1c; + limitreg = win*8 + 0x20; + + pci_conf_write(sc->sc_pc, sc->sc_tag, basereg, start); + pci_conf_write(sc->sc_pc, sc->sc_tag, limitreg, end); + return 1; +} + + +/********************************************************************** +* int pccbb_mem_close(cardbus_chipset_tag_t, int); +**********************************************************************/ +static int +pccbb_mem_close(ct, win) + cardbus_chipset_tag_t ct; + int win; +{ + struct pccbb_softc *sc = (struct pccbb_softc *)ct; + int basereg; + int limitreg; + + if ((win < 0) || (win > 2)) { +#if defined DIAGNOSTIC + printf("cardbus_mem_close: window out of range %d\n", win); +#endif + return 0; + } + + basereg = win*8 + 0x1c; + limitreg = win*8 + 0x20; + + pci_conf_write(sc->sc_pc, sc->sc_tag, basereg, 0); + pci_conf_write(sc->sc_pc, sc->sc_tag, limitreg, 0); + return 1; +} + + + + + +static void * +pccbb_intr_establish(ct, irq, level, func, arg) + cardbus_chipset_tag_t ct; + int irq, level; + int (* func) __P((void *)); + void *arg; +{ + struct pccbb_softc *sc = (struct pccbb_softc *)ct; + + switch (sc->sc_chipset) { + case CB_TI113X: + { + pcireg_t cbctrl = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_CBCTRL); + cbctrl |= PCI113X_CBCTRL_PCI_INTR; /* functional intr enabled */ + pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_CBCTRL, cbctrl); + } + break; + default: + break; + } + + return pci_intr_establish(sc->sc_pc, irq, level, (void(*)(void*))func, arg); +} + + + + +static void +pccbb_intr_disestablish(ct, ih) + cardbus_chipset_tag_t ct; + void *ih; +{ + struct pccbb_softc *sc = (struct pccbb_softc *)ct; + + switch (sc->sc_chipset) { + case CB_TI113X: + { + pcireg_t cbctrl = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_CBCTRL); + cbctrl &= ~PCI113X_CBCTRL_PCI_INTR; /* functional intr disabled */ + pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_CBCTRL, cbctrl); + } + break; + default: + break; + } + + pci_intr_disestablish(sc->sc_pc, ih); +} + + + + + +#if defined SHOW_REGS +static void +cb_show_regs(pc, tag, memt, memh) + pci_chipset_tag_t pc; + pcitag_t tag; + bus_space_tag_t memt; + bus_space_handle_t memh; +{ + int i; + printf("PCI config regs:"); + for (i = 0; i < 0x50; i += 4) { + if (i % 16 == 0) { + printf("\n 0x%02x:", i); + } + printf(" %08lx", pci_conf_read(pc, tag, i)); + } + for (i = 0x80; i < 0xb0; i += 4) { + if (i % 16 == 0) { + printf("\n 0x%02x:", i); + } + printf(" %08lx", pci_conf_read(pc, tag, i)); + } + + if (memh.addr == 0) {/* XXX */ + printf("\n"); + return; + } + + printf("\nsocket regs:"); + for (i = 0; i <= 0x10; i += 0x04) { + printf(" %08x", bus_space_read_4(memt, memh, i)); + } + printf("\nExCA regs:"); + for (i = 0; i < 0x08; ++i) { + printf(" %02x", bus_space_read_1(memt, memh, 0x800 + i)); + } + printf("\n"); + return; +} +#endif + + +/********************************************************************** +* static cardbustag_t pccbb_make_tag(cardbus_chipset_tag_t cc, +* int busno, int devno, int function); +* This is the function to make a tag to access config space of +* a CardBus Card. It works same as pci_conf_read. +**********************************************************************/ +static cardbustag_t +pccbb_make_tag(cc, busno, devno, function) + cardbus_chipset_tag_t cc; + int busno, devno, function; +{ + struct pccbb_softc *sc = (struct pccbb_softc *)cc; + + return pci_make_tag(sc->sc_pc, busno, devno, function); +} +static void +pccbb_free_tag (cardbus_chipset_tag_t cc, cardbustag_t tag) +{ + struct pccbb_softc *sc = (struct pccbb_softc *)cc; + pci_free_tag (tag); + return; +} + +/********************************************************************** +* static cardbusreg_t pccbb_conf_read(cardbus_chipset_tag_t cc, +* cardbustag_t tag, int offset) +* This is the function to read the config space of a CardBus Card. +* It works same as pci_conf_read. +**********************************************************************/ +static cardbusreg_t +pccbb_conf_read(ct, tag, offset) + cardbus_chipset_tag_t ct; + cardbustag_t tag; + int offset; /* register offset */ +{ + struct pccbb_softc *sc = (struct pccbb_softc *)ct; + + return pci_conf_read(sc->sc_pc, tag, offset); +} + + + +/********************************************************************** +* static void pccbb_conf_write(cardbus_chipset_tag_t cc, cardbustag_t tag, +* int offs, cardbusreg_t val) +* This is the function to write the config space of a CardBus Card. +* It works same as pci_conf_write. +**********************************************************************/ +static void +pccbb_conf_write(ct, tag, reg, val) + cardbus_chipset_tag_t ct; + cardbustag_t tag; + int reg; /* register offset */ + cardbusreg_t val; +{ + struct pccbb_softc *sc = (struct pccbb_softc *)ct; + + pci_conf_write(sc->sc_pc, tag, reg, val); +} + +/********************************************************************** +* STATIC int pccbb_pcmcia_io_alloc(pcmcia_chipset_handle_t pch, +* bus_addr_t start, bus_size_t size, +* bus_size_t align, +* struct pcmcia_io_handle *pcihp +* +* This function only allocates I/O region for pccard. This function +* never maps the allcated region to pccard I/O area. +* +* XXX: The interface of this function is not very good, I believe. +**********************************************************************/ + STATIC int +pccbb_pcmcia_io_alloc(pch, start, size, align, pcihp) + pcmcia_chipset_handle_t pch; + bus_addr_t start; /* start address */ + bus_size_t size; + bus_size_t align; + struct pcmcia_io_handle *pcihp; +{ + struct cbb_pcic_handle *ph = (struct cbb_pcic_handle *)pch; + bus_addr_t ioaddr; + int flags = 0; + bus_space_tag_t iot; + bus_space_handle_t ioh; + + /* + * Allocate some arbitrary I/O space. + */ + + iot = ph->sc->sc_iot; + + if (start) { + ioaddr = start; + if (bus_space_map(iot, start, size, 0, &ioh)) { + return 1; + } + DPRINTF(("pccbb_pcmcia_io_alloc map port %lx+%lx\n", + (u_long) ioaddr, (u_long) size)); + } else { + flags |= PCMCIA_IO_ALLOCATED; + if (bus_space_alloc(iot, 0x700/* ph->sc->sc_iobase */, + 0x800/* ph->sc->sc_iobase + ph->sc->sc_iosize*/, + size, align, 0, 0, &ioaddr, &ioh)) { + /* No room be able to be get. */ + return 1; + } + DPRINTF(("pccbb_pcmmcia_io_alloc alloc port 0x%lx+0x%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; +} + +/********************************************************************** +* STATIC int pccbb_pcmcia_io_free(pcmcia_chipset_handle_t pch, +* struct pcmcia_io_handle *pcihp) +* +* This function only frees I/O region for pccard. +* +* XXX: The interface of this function is not very good, I believe. +**********************************************************************/ +void +pccbb_pcmcia_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 pccbb_pcmcia_io_map(pcmcia_chipset_handle_t pch, int width, +* bus_addr_t offset, bus_size_t size, +* struct pcmcia_io_handle *pcihp, +* int *windowp) +* +* This function maps the allocated I/O region to pccard. This function +* never allocates any I/O region for pccard I/O area. I don't +* understand why the original authors of pcmciabus separated alloc and +* map. I believe the two must be unite. +* +* XXX: no wait timing control? +**********************************************************************/ +int +pccbb_pcmcia_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 cbb_pcic_handle *ph = (struct cbb_pcic_handle *) pch; + bus_addr_t ioaddr = pcihp->addr + offset; + int i, win; +#if defined CBB_DEBUG + static char *width_names[] = { "dynamic", "io8", "io16" }; +#endif + + /* Sanity check I/O handle. */ + + if (ph->sc->sc_iot != pcihp->iot) { + panic("pccbb_pcmcia_io_map iot is bogus"); + } + + /* XXX Sanity check offset/size. */ + + win = -1; + for (i = 0; i < PCIC_IO_WINS; i++) { + if ((ph->ioalloc & (1 << i)) == 0) { + win = i; + ph->ioalloc |= (1 << i); + break; + } + } + + if (win == -1) { + return 1; + } + + *windowp = win; + + /* XXX this is pretty gross */ + + DPRINTF(("pccbb_pcmcia_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? */ + +#if 0 + printf(" port 0x%lx", (u_long) ioaddr); + if (size > 1) { + printf("-0x%lx", (u_long) ioaddr + (u_long) size - 1); + } +#endif + + ph->io[win].addr = ioaddr; + ph->io[win].size = size; + ph->io[win].width = width; + + /* actual dirty register-value changing in the function below. */ + pccbb_pcmcia_do_io_map(ph, win); + + return 0; +} + +/********************************************************************** +* STATIC void pccbb_pcmcia_do_io_map(struct pcic_handle *h, int win) +* +* This function changes register-value to map I/O region for pccard. +**********************************************************************/ +static void +pccbb_pcmcia_do_io_map(ph, win) + struct cbb_pcic_handle *ph; + int win; +{ + static u_int8_t pcic_iowidth[3] = { + PCIC_IOCTL_IO0_IOCS16SRC_CARD, + PCIC_IOCTL_IO0_IOCS16SRC_DATASIZE | PCIC_IOCTL_IO0_DATASIZE_8BIT, + PCIC_IOCTL_IO0_IOCS16SRC_DATASIZE | PCIC_IOCTL_IO0_DATASIZE_16BIT, + }; + +#define PCIC_SIA_START_LOW 0 +#define PCIC_SIA_START_HIGH 1 +#define PCIC_SIA_STOP_LOW 2 +#define PCIC_SIA_STOP_HIGH 3 + + int regbase_win = 0x8 + win*0x04; + u_int8_t ioctl, enable; + + DPRINTF(("pccbb_pcmcia_do_io_map win %d addr 0x%lx size 0x%lx width %d\n", + win, (long) ph->io[win].addr, (long) ph->io[win].size, + ph->io[win].width * 8)); + + Pcic_write(ph, regbase_win + PCIC_SIA_START_LOW, + ph->io[win].addr & 0xff); + Pcic_write(ph, regbase_win + PCIC_SIA_START_HIGH, + (ph->io[win].addr >> 8) & 0xff); + + Pcic_write(ph, regbase_win + PCIC_SIA_STOP_LOW, + (ph->io[win].addr + ph->io[win].size - 1) & 0xff); + Pcic_write(ph, regbase_win + PCIC_SIA_STOP_HIGH, + ((ph->io[win].addr + ph->io[win].size - 1) >> 8) & 0xff); + + ioctl = Pcic_read(ph, PCIC_IOCTL); + enable = Pcic_read(ph, PCIC_ADDRWIN_ENABLE); + switch (win) { + case 0: + ioctl &= ~(PCIC_IOCTL_IO0_WAITSTATE | PCIC_IOCTL_IO0_ZEROWAIT | + PCIC_IOCTL_IO0_IOCS16SRC_MASK | PCIC_IOCTL_IO0_DATASIZE_MASK); + ioctl |= pcic_iowidth[ph->io[win].width]; + enable |= PCIC_ADDRWIN_ENABLE_IO0; + break; + case 1: + ioctl &= ~(PCIC_IOCTL_IO1_WAITSTATE | PCIC_IOCTL_IO1_ZEROWAIT | + PCIC_IOCTL_IO1_IOCS16SRC_MASK | PCIC_IOCTL_IO1_DATASIZE_MASK); + ioctl |= (pcic_iowidth[ph->io[win].width] << 4); + enable |= PCIC_ADDRWIN_ENABLE_IO1; + break; + } + Pcic_write(ph, PCIC_IOCTL, ioctl); + Pcic_write(ph, PCIC_ADDRWIN_ENABLE, enable); +#if defined CBB_DEBUG + { + u_int8_t start_low = Pcic_read(ph, regbase_win + PCIC_SIA_START_LOW); + u_int8_t start_high = Pcic_read(ph, regbase_win + PCIC_SIA_START_HIGH); + u_int8_t stop_low = Pcic_read(ph, regbase_win + PCIC_SIA_STOP_LOW); + u_int8_t stop_high = Pcic_read(ph, regbase_win + PCIC_SIA_STOP_HIGH); + printf(" start %02x %02x, stop %02x %02x, ioctl %02x enable %02x\n", + start_low, start_high, stop_low, stop_high, ioctl, enable); + } +#endif +} + +/********************************************************************** +* STATIC void pccbb_pcmcia_io_unmap(pcmcia_chipset_handle_t *h, int win) +* +* This function unmapss I/O region. No return value. +**********************************************************************/ +STATIC void +pccbb_pcmcia_io_unmap(pch, win) + pcmcia_chipset_handle_t pch; + int win; +{ + struct cbb_pcic_handle *ph = (struct cbb_pcic_handle *)pch; + int reg; + + if (win >= PCIC_IO_WINS || win < 0) { + panic("pccbb_pcmcia_io_unmap: window out of range"); + } + + reg = Pcic_read(ph, PCIC_ADDRWIN_ENABLE); + switch (win) { + case 0: + reg &= ~PCIC_ADDRWIN_ENABLE_IO0; + break; + case 1: + reg &= ~PCIC_ADDRWIN_ENABLE_IO1; + break; + } + Pcic_write(ph, PCIC_ADDRWIN_ENABLE, reg); + + ph->ioalloc &= ~(1 << win); +} + +/********************************************************************** +* static void pccbb_pcmcia_wait_ready(struct cbb_pcic_handle *ph) +* +* This function enables the card. All information is stored in +* the first argument, pcmcia_chipset_handle_t. +**********************************************************************/ +static void +pccbb_pcmcia_wait_ready(ph) + struct cbb_pcic_handle *ph; +{ + int i; + + DPRINTF(("pccbb_pcmcia_wait_ready: status 0x%02x\n", + Pcic_read(ph, PCIC_IF_STATUS))); + + for (i = 0; i < 10000; i++) { + if (Pcic_read(ph, PCIC_IF_STATUS) & PCIC_IF_STATUS_READY) { + return; + } + delay(500); +#ifdef CBB_DEBUG + if ((i > 5000) && (i%100 == 99)) + printf("."); +#endif + } + +#ifdef DIAGNOSTIC + printf("pcic_wait_ready: ready never happened, status = %02x\n", + Pcic_read(ph, PCIC_IF_STATUS)); +#endif +} + +/********************************************************************** +* STATIC void pccbb_pcmcia_socket_enable(pcmcia_chipset_handle_t pch) +* +* This function enables the card. All information is stored in +* the first argument, pcmcia_chipset_handle_t. +**********************************************************************/ +STATIC void +pccbb_pcmcia_socket_enable(pch) + pcmcia_chipset_handle_t pch; +{ + struct cbb_pcic_handle *ph = (struct cbb_pcic_handle *)pch; + struct pccbb_softc *sc = ph->sc; + struct pcmcia_softc *psc = (void*)ph->pcmcia; + int cardtype, win; + u_int8_t power, intr; + pcireg_t spsr; + int voltage; +#define PCIC_INTR_PCI PCIC_INTR_ENABLE + + /* this bit is mostly stolen from pcic_attach_card */ + + DPRINTF(("pccbb_pcmcia_socket_enable:\n")); + + /* get card Vcc info */ + + spsr = bus_space_read_4(sc->sc_base_memt, sc->sc_base_memh, CB_SOCKET_STAT); + if (spsr & CB_SOCKET_STAT_5VCARD) { + printf("5V card\n"); /* XXX */ + voltage = CARDBUS_VCC_5V | CARDBUS_VPP_VCC; + } else if (spsr & CB_SOCKET_STAT_3VCARD) { + printf("3V card\n"); /* XXX */ + voltage = CARDBUS_VCC_3V | CARDBUS_VPP_VCC; + } else { + printf("?V card, 0x%x\n", spsr); /* XXX */ + return; + } + + /* assert reset bit */ + + intr = Pcic_read(ph, PCIC_INTR); + intr &= ~PCIC_INTR_RESET; + intr |= PCIC_INTR_PCI; /* XXX */ + Pcic_write(ph, PCIC_INTR, intr); + + /* disable socket i/o: negate output enable bit */ + + power = Pcic_read(ph, PCIC_PWRCTL); + power &= ~PCIC_PWRCTL_OE; + Pcic_write(ph, PCIC_PWRCTL, power); + + /* power down the socket to reset it, clear the card reset pin */ + + pccbb_power(sc, CARDBUS_VCC_0V | CARDBUS_VPP_0V); + + /* + * wait 300ms until power fails (Tpf). Then, wait 100ms since + * we are changing Vcc (Toff). + */ + delay((300 + 100)*1000); + + /* power up the socket */ + pccbb_power(sc, voltage); + + /* + * wait 100ms until power raise (Tpr) and 20ms to become + * stable (Tsu(Vcc)). + * + * some machines require some more time to be settled + * (another 200ms is added here). + */ + delay((100 + 20 + 200)*1000); + + power = Pcic_read(ph, PCIC_PWRCTL); + Pcic_write(ph, PCIC_PWRCTL, power | PCIC_PWRCTL_OE); + + /* + * hold RESET at least 10us. + */ + delay(10); + delay(2*1000); /* XXX: TI1130 requires it. */ + + /* clear the reset flag */ + + intr = Pcic_read(ph, PCIC_INTR); + Pcic_write(ph, PCIC_INTR, intr | PCIC_INTR_RESET); + + /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */ + + delay(20000); + + /* wait for the chip to finish initializing */ + + pccbb_pcmcia_wait_ready(ph); + + /* zero out the address windows */ + + Pcic_write(ph, PCIC_ADDRWIN_ENABLE, 0); + + /* set the card type */ + + cardtype = psc->sc_if.if_card_gettype(ph->pcmcia); + + intr = Pcic_read(ph, PCIC_INTR); + intr &= ~PCIC_INTR_CARDTYPE_MASK; + intr |= ((cardtype == PCMCIA_IFTYPE_IO) ? + PCIC_INTR_CARDTYPE_IO : + PCIC_INTR_CARDTYPE_MEM); + Pcic_write(ph, PCIC_INTR, intr); + + DPRINTF(("%s: pccbb_pcmcia_socket_enable %02x cardtype %s %02x\n", + ph->sc->sc_dev.dv_xname, ph->sock, + ((cardtype == PCMCIA_IFTYPE_IO) ? "io" : "mem"), intr)); + + /* reinstall all the memory and io mappings */ + + for (win = 0; win < PCIC_MEM_WINS; ++win) { + if (ph->memalloc & (1 << win)) { + pccbb_pcmcia_do_mem_map(ph, win); + } + } + + for (win = 0; win < PCIC_IO_WINS; ++win) { + if (ph->ioalloc & (1 << win)) { + pccbb_pcmcia_do_io_map(ph, win); + } + } +} + +/********************************************************************** +* STATIC void pccbb_pcmcia_socket_disable(pcmcia_chipset_handle_t *ph) +* +* This function disables the card. All information is stored in +* the first argument, pcmcia_chipset_handle_t. +**********************************************************************/ +STATIC void +pccbb_pcmcia_socket_disable(pch) + pcmcia_chipset_handle_t pch; +{ + struct cbb_pcic_handle *ph = (struct cbb_pcic_handle *)pch; + struct pccbb_softc *sc = ph->sc; + u_int8_t power, intr; + + DPRINTF(("pccbb_pcmcia_socket_disable\n")); + + /* reset signal asserting... */ + + intr = Pcic_read(ph, PCIC_INTR); + intr &= ~PCIC_INTR_RESET; + Pcic_write(ph, PCIC_INTR, intr); + delay(2*1000); + + /* power down the socket */ + power = Pcic_read(ph, PCIC_PWRCTL); + power &= ~PCIC_PWRCTL_OE; + Pcic_write(ph, PCIC_PWRCTL, power); + pccbb_power(sc, CARDBUS_VCC_0V | CARDBUS_VPP_0V); + + /* + * wait 300ms until power fails (Tpf). + */ + delay(300 * 1000); +} + +/********************************************************************** +* STATIC int pccbb_pcmcia_mem_alloc(pcmcia_chipset_handle_t pch, +* bus_size_t size, +* struct pcmcia_mem_handle *pcmhp) +* +* This function only allocates memory region for pccard. This +* function never maps the allcated region to pccard memory area. +* +* XXX: Why the argument of start address is not in? +**********************************************************************/ +STATIC int +pccbb_pcmcia_mem_alloc(pch, size, pcmhp) + pcmcia_chipset_handle_t pch; + bus_size_t size; + struct pcmcia_mem_handle *pcmhp; +{ + struct cbb_pcic_handle *ph = (struct cbb_pcic_handle *)pch; + bus_space_handle_t memh; + bus_addr_t addr; + bus_size_t sizepg; + struct pccbb_softc *sc = ph->sc; + + /* out of sc->memh, allocate as many pages as necessary */ + + /* convert size to PCIC pages */ + /* + This is not enough; when the requested region is on the + page boundaries, this may calculate wrong result. + */ + sizepg = (size + (PCIC_MEM_PAGESIZE - 1)) / PCIC_MEM_PAGESIZE; +#if 0 + if (sizepg > PCIC_MAX_MEM_PAGES) { + return 1; + } +#endif + + if (!(sc->sc_pcmcia_flags & PCCBB_PCMCIA_MEM_32)) { + return 1; + } + + addr = 0; /* XXX gcc -Wuninitialized */ + + if (bus_space_alloc(sc->sc_memt, sc->sc_mem_start, sc->sc_mem_end, + sizepg*PCIC_MEM_PAGESIZE, PCIC_MEM_PAGESIZE, + 0 /* boundary */, 0 /* flags */, + &addr, &memh)) { + return 1; + } + + DPRINTF(("pccbb_pcmcia_alloc_mem: addr 0x%lx size 0x%lx, realsize 0x%lx\n", + (u_long)addr, (u_long)size, (u_long)sizepg*PCIC_MEM_PAGESIZE)); + + pcmhp->memt = sc->sc_memt; + pcmhp->memh = memh; + pcmhp->addr = addr; + pcmhp->size = size; + pcmhp->realsize = sizepg * PCIC_MEM_PAGESIZE; + /* What is mhandle? I feel it is very dirty and it must go trush. */ + pcmhp->mhandle = 0; + /* No offset??? Funny. */ + + return 0; +} + +/********************************************************************** +* STATIC void pccbb_pcmcia_mem_free(pcmcia_chipset_handle_t pch, +* struct pcmcia_mem_handle *pcmhp) +* +* This function release the memory space allocated by the fuction +* pccbb_pcmcia_mem_alloc(). +**********************************************************************/ +STATIC void +pccbb_pcmcia_mem_free(pch, pcmhp) + pcmcia_chipset_handle_t pch; + struct pcmcia_mem_handle *pcmhp; +{ + bus_space_free(pcmhp->memt, pcmhp->memh, pcmhp->realsize); +} + +/********************************************************************** +* STATIC void pccbb_pcmcia_do_mem_map(struct cbb_pcic_handle *ph, +* int win) +* +* This function release the memory space allocated by the fuction +* pccbb_pcmcia_mem_alloc(). +**********************************************************************/ +STATIC void +pccbb_pcmcia_do_mem_map(ph, win) + struct cbb_pcic_handle *ph; + int win; +{ + int regbase_win; + bus_addr_t phys_addr; + bus_addr_t phys_end; + +#define PCIC_SMM_START_LOW 0 +#define PCIC_SMM_START_HIGH 1 +#define PCIC_SMM_STOP_LOW 2 +#define PCIC_SMM_STOP_HIGH 3 +#define PCIC_CMA_LOW 4 +#define PCIC_CMA_HIGH 5 + + u_int8_t start_low, start_high = 0; + u_int8_t stop_low, stop_high; + u_int8_t off_low, off_high; + u_int8_t mem_window; + int reg; + + regbase_win = 0x10 + win*0x08; + + phys_addr = ph->mem[win].addr; + phys_end = phys_addr + ph->mem[win].size; + + DPRINTF(("pccbb_pcmcia_do_mem_map: start 0x%lx end 0x%lx off 0x%lx\n", + (u_long)phys_addr, (u_long)phys_end, ph->mem[win].offset)); + +#define PCIC_MEMREG_LSB_SHIFT PCIC_SYSMEM_ADDRX_SHIFT +#define PCIC_MEMREG_MSB_SHIFT (PCIC_SYSMEM_ADDRX_SHIFT + 8) +#define PCIC_MEMREG_WIN_SHIFT (PCIC_SYSMEM_ADDRX_SHIFT + 12) + + start_low = (phys_addr >> PCIC_MEMREG_LSB_SHIFT) & 0xff; /* bit 19:12 */ + start_high = ((phys_addr >> PCIC_MEMREG_MSB_SHIFT) & 0x0f) /* bit 23:20 */ + | PCIC_SYSMEM_ADDRX_START_MSB_DATASIZE_16BIT; /* bit 7 on */ + /* bit 31:24, for 32-bit address */ + mem_window = (phys_addr >> PCIC_MEMREG_WIN_SHIFT) & 0xff; /* bit 31:24 */ + + Pcic_write(ph, regbase_win + PCIC_SMM_START_LOW, start_low); + Pcic_write(ph, regbase_win + PCIC_SMM_START_HIGH, start_high); + + if (ph->sc->sc_pcmcia_flags & PCCBB_PCMCIA_MEM_32) { + Pcic_write(ph, 0x40 + win, mem_window); + } + + +#if 0 + /* XXX do I want 16 bit all the time? */ + PCIC_SYSMEM_ADDRX_START_MSB_DATASIZE_16BIT; +#endif + + + stop_low = (phys_end >> PCIC_MEMREG_LSB_SHIFT) & 0xff; + stop_high = ((phys_end >> PCIC_MEMREG_MSB_SHIFT) & 0x0f) + | PCIC_SYSMEM_ADDRX_STOP_MSB_WAIT2; /* wait 2 cycles */ + /* XXX Geee, WAIT2!! Crazy!! I must rewrite this routine. */ + + Pcic_write(ph, regbase_win + PCIC_SMM_STOP_LOW, stop_low); + Pcic_write(ph, regbase_win + PCIC_SMM_STOP_HIGH, stop_high); + + off_low = (ph->mem[win].offset >> PCIC_CARDMEM_ADDRX_SHIFT) & 0xff; + off_high = ((ph->mem[win].offset >> (PCIC_CARDMEM_ADDRX_SHIFT + 8)) + & PCIC_CARDMEM_ADDRX_MSB_ADDR_MASK) + | ((ph->mem[win].kind == PCMCIA_MEM_ATTR) ? + PCIC_CARDMEM_ADDRX_MSB_REGACTIVE_ATTR : 0); + + Pcic_write(ph, regbase_win + PCIC_CMA_LOW, off_low); + Pcic_write(ph, regbase_win + PCIC_CMA_HIGH, off_high); + + reg = Pcic_read(ph, PCIC_ADDRWIN_ENABLE); + reg |= ((1 << win) | PCIC_ADDRWIN_ENABLE_MEMCS16); + Pcic_write(ph, PCIC_ADDRWIN_ENABLE, reg); + +#if defined CBB_DEBUG + { + int r1, r2, r3, r4, r5, r6, r7 = 0; + + r1 = Pcic_read(ph, regbase_win + PCIC_SMM_START_LOW); + r2 = Pcic_read(ph, regbase_win + PCIC_SMM_START_HIGH); + r3 = Pcic_read(ph, regbase_win + PCIC_SMM_STOP_LOW); + r4 = Pcic_read(ph, regbase_win + PCIC_SMM_STOP_HIGH); + r5 = Pcic_read(ph, regbase_win + PCIC_CMA_LOW); + r6 = Pcic_read(ph, regbase_win + PCIC_CMA_HIGH); + if (ph->sc->sc_pcmcia_flags & PCCBB_PCMCIA_MEM_32) { + r7 = Pcic_read(ph, 0x40 + win); + } + + DPRINTF(("pccbb_pcmcia_do_mem_map window %d: %02x%02x %02x%02x " + "%02x%02x", win, r1, r2, r3, r4, r5, r6)); + if (ph->sc->sc_pcmcia_flags & PCCBB_PCMCIA_MEM_32) { + DPRINTF((" %02x",r7)); + } + DPRINTF(("\n")); + } +#endif +} + +/********************************************************************** +* STATIC int pccbb_pcmcia_mem_map(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) +* +* This function maps memory space allocated by the fuction +* pccbb_pcmcia_mem_alloc(). +**********************************************************************/ +STATIC int +pccbb_pcmcia_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 cbb_pcic_handle *ph = (struct cbb_pcic_handle *)pch; + bus_addr_t busaddr; + long card_offset; + int win; + + for (win = 0; win < PCIC_MEM_WINS; ++win) { + if ((ph->memalloc & (1 << win)) == 0) { + ph->memalloc |= (1 << win); + break; + } + } + + if (win == PCIC_MEM_WINS) { + return 1; + } + + *windowp = win; + + /* XXX this is pretty gross */ + + if (ph->sc->sc_memt != pcmhp->memt) { + panic("pccbb_pcmcia_mem_map memt is bogus"); + } + + busaddr = pcmhp->addr; + + /* + * compute the address offset to the pcmcia address space for the + * pcic. this is intentionally signed. The masks and shifts below + * will cause TRT to happen in the pcic registers. Deal with making + * sure the address is aligned, and return the alignment offset. + */ + + *offsetp = card_addr % PCIC_MEM_PAGESIZE; + card_addr -= *offsetp; + + DPRINTF(("pccbb_pcmcia_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)); + + /* + * 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)); + + ph->mem[win].addr = busaddr; + ph->mem[win].size = size; + ph->mem[win].offset = card_offset; + ph->mem[win].kind = kind; + + pccbb_pcmcia_do_mem_map(ph, win); + + return 0; +} + +/********************************************************************** +* STATIC int pccbb_pcmcia_mem_unmap(pcmcia_chipset_handle_t pch, +* int window) +* +* This function unmaps memory space which mapped by the fuction +* pccbb_pcmcia_mem_map(). +**********************************************************************/ +STATIC void +pccbb_pcmcia_mem_unmap(pch, window) + pcmcia_chipset_handle_t pch; + int window; +{ + struct cbb_pcic_handle *ph = (struct cbb_pcic_handle *)pch; + int reg; + + if (window >= PCIC_MEM_WINS) { + panic("pccbb_pcmcia_mem_unmap: window out of range"); + } + + reg = Pcic_read(ph, PCIC_ADDRWIN_ENABLE); + reg &= ~(1 << window); + Pcic_write(ph, PCIC_ADDRWIN_ENABLE, reg); + + ph->memalloc &= ~(1 << window); +} + + + +#if defined PCCBB_PCMCIA_POLL +struct pccbb_poll_str { + void *arg; + int (* func) __P((void *)); + int level; + struct cbb_pcic_handle *ph; + int count; + int num; +}; + +static struct pccbb_poll_str pccbb_poll[10]; +static int pccbb_poll_n = 0; + +static void pccbb_pcmcia_poll __P((void *arg)); + +static void +pccbb_pcmcia_poll(arg) + void *arg; +{ + struct pccbb_poll_str *poll = arg; + struct cbb_pcic_handle *ph = poll->ph; + struct pccbb_softc *sc = ph->sc; + int s; + u_int32_t spsr; /* socket present-state reg */ + + timeout(pccbb_pcmcia_poll, arg, hz*2); + switch (poll->level) { + case IPL_NET: + s = splnet(); + break; + case IPL_BIO: + s = splbio(); + break; + case IPL_TTY: /* fallthrough */ + default: + s = spltty(); + break; + } + + spsr = bus_space_read_4(sc->sc_base_memt, sc->sc_base_memh, CB_SOCKET_STAT); +// printf("pccbb_pcmcia_poll: socket 0x%08x\n", spsr); + +#if defined PCCBB_PCMCIA_POLL_ONLY && defined LEVEL2 + if (!(spsr & 0x40)) /* CINT low */ +#else + if (1) +#endif + { + if ((*poll->func)(poll->arg) > 0) { + ++poll->count; +// printf("intr: reported from poller, 0x%x\n", spsr); +#if defined LEVEL2 + } else { + printf("intr: miss! 0x%x\n", spsr); +#endif + } + } + splx(s); +} +#endif /* defined CB_PCMCIA_POLL */ + +/********************************************************************** +* STATIC void *pccbb_pcmcia_intr_establish(pcmcia_chipset_handle_t pch, +* struct pcmcia_function *pf, +* int ipl, +* int (*func)(void *), +* void *arg); +* +* This function enables PC-Card interrupt. PCCBB uses PCI interrupt line. +**********************************************************************/ +STATIC void * +pccbb_pcmcia_intr_establish(pch, pf, ipl, func, arg) + pcmcia_chipset_handle_t pch; + struct pcmcia_function *pf; + int ipl; + int (*func) __P((void *)); + void *arg; +{ + struct cbb_pcic_handle *ph = (struct cbb_pcic_handle *)pch; + struct pccbb_softc *sc = ph->sc; + pci_intr_handle_t handle; + void *ih; + + if (!(pf->cfe->flags & PCMCIA_CFE_IRQLEVEL)) { + /* what should I do? */ + if ((pf->cfe->flags & PCMCIA_CFE_IRQLEVEL)) { + DPRINTF(("%s does not provide edge nor pulse interrupt\n", + sc->sc_dev.dv_xname)); + return NULL; + } + /* XXX Noooooo! The interrupt flag must set properly!! */ + /* dumb pcmcia driver!! */ + } + + if (pci_intr_map(sc->sc_pc, sc->sc_intrtag, sc->sc_intrpin, + sc->sc_intrline, &handle)) { + printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname); + return NULL; + } + + DPRINTF(("pccbb_pcmcia_intr_establish: line %d, handle %d\n", + sc->sc_intrline, handle)); + + if (NULL != (ih = pci_intr_establish(sc->sc_pc, handle, ipl, (void(*)(void*))func, arg))) + { + u_int32_t cbctrl; + + if ((CB_TI113X == sc->sc_chipset)) { + cbctrl = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_CBCTRL); + cbctrl |= PCI113X_CBCTRL_PCI_INTR; /* PCI functional intr req */ + pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_CBCTRL, cbctrl); + } + } +#if defined PCCBB_PCMCIA_POLL + if (pccbb_poll_n < 10) { + pccbb_poll[pccbb_poll_n].arg = arg; + pccbb_poll[pccbb_poll_n].func = func; + pccbb_poll[pccbb_poll_n].level = ipl; + pccbb_poll[pccbb_poll_n].count = 0; + pccbb_poll[pccbb_poll_n].num = pccbb_poll_n; + pccbb_poll[pccbb_poll_n].ph = ph; + timeout(pccbb_pcmcia_poll, &pccbb_poll[pccbb_poll_n++], hz*2); + printf("polling set\n"); + } +#endif +#if defined SHOW_REGS + cb_show_regs(sc->sc_pc, sc->sc_tag, sc->sc_base_memt, sc->sc_base_memh); +#endif + + return ih; +} + +/********************************************************************** +* STATIC void pccbb_pcmcia_intr_disestablish(pcmcia_chipset_handle_t pch, +* void *ih) +* +* This function disables PC-Card interrupt. +**********************************************************************/ +STATIC void +pccbb_pcmcia_intr_disestablish(pch, ih) + pcmcia_chipset_handle_t pch; + void *ih; +{ + struct cbb_pcic_handle *ph = (struct cbb_pcic_handle *)pch; + struct pccbb_softc *sc = ph->sc; + + pci_intr_disestablish(sc->sc_pc, ih); +} + +static int +pccbb_pcmcia_submatch(parent, cf, aux) + struct device *parent; + struct cfdata *cf; + void *aux; +{ + struct pcmciabus_attach_args *paa = aux; + struct cbb_pcic_handle *ph = (struct cbb_pcic_handle *)paa->pch; + + if (cf->cf_loc[PCMCIABUSCF_CONTROLLER] != PCMCIABUSCF_CONTROLLER_DEFAULT + && cf->cf_loc[PCMCIABUSCF_CONTROLLER] != 0) { + return 0; + } + + if ((cf->cf_loc[PCMCIABUSCF_CONTROLLER] == PCMCIABUSCF_CONTROLLER_DEFAULT) + || cf->cf_loc[PCMCIABUSCF_CONTROLLER] != ph->sock) { + return ((*cf->cf_attach->ca_match)(parent, cf, aux)); + } + + return 0; +} + +static int +pccbb_pcmcia_print(arg, pnp) + void *arg; + const char *pnp; +{ + struct pcmciabus_attach_args *paa = arg; + struct cbb_pcic_handle *ph = (struct cbb_pcic_handle *)paa->pch; + + if (pnp) { + printf("pcmcia at %s", pnp); + } + + printf(" slot %d", ph->sock); + + return UNCONF; +} +STATIC int +cbbprint(aux, pcic) + void *aux; + const char *pcic; +{ +/* + struct cbslot_attach_args *cba = aux; + + if (cba->cba_slot >= 0) { + printf(" slot %d", cba->cba_slot); + } +*/ + return UNCONF; +} diff --git a/sys/pci/pccbbreg.h b/sys/pci/pccbbreg.h new file mode 100644 index 000000000000..9dad13ae8fcb --- /dev/null +++ b/sys/pci/pccbbreg.h @@ -0,0 +1,228 @@ +/* + * Copyright (c) 1999 HAYAKAWA Koichi. 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 HAYAKAWA Koichi. + * 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. + */ + +/* $Id: pccbbreg.h,v 1.4 1999/08/02 01:35:50 kanaoka Exp $ */ +/* $FreeBSD$ */ + +#ifndef _DEV_PCI_PCCBBREG_H_ +#define _DEV_PCI_PCCBBREG_H_ + +#define PCI_SOCKBASE 0x10 /* Socket Base Address Register */ +#define PCI_BUSNUM 0x18 /* latency timer, Subordinate bus number */ +#define PCI_BCR_INTR 0x3C /* intr line, intr pin, bridge control regs */ +#define PCI_LEGACY 0x44 /* legacy IO register address (32 bits) */ +#define PCI_CBCTRL 0x90 /* Retry status, Card ctrl, Device ctrl */ + +#define PCI_CLASS_INTERFACE_MASK 0xffffff00 +#define PCI_CLASS_INTERFACE_YENTA 0x06070000 + +#define PCI_BHLC_REG 0x0c + +#define PCI_LATTIMER_SHIFT 8 +#define PCI_LATTIMER_MASK 0xff +#define PCI_LATTIMER(bhlcr) \ + (((bhlcr) >> PCI_LATTIMER_SHIFT) & PCI_LATTIMER_MASK) + + +#define PCI_SOCKBASE 0x10 /* Socket Base Address Register */ +#define PCI_BUSNUM 0x18 /* latency timer, Subordinate bus number */ +#define PCI_BCR_INTR 0x3C /* intr line, intr pin, bridge control regs */ +#define PCI_LEGACY 0x44 /* legacy IO register address (32 bits) */ +#define PCI_CBCTRL 0x90 /* Retry status, Card ctrl, Device ctrl */ +#define CB_SOCKET_EVENT 0x00 /* offset of cardbus socket event reg */ +#define CB_SOCKET_MASK 0x04 /* offset of cardbus socket mask register */ +#define CB_SOCKET_STAT 0x08 /* offset of cardbus socket present-state */ +#define CB_SOCKET_FORCE 0x0c /* offset of cardbus socket force event */ +#define CB_SOCKET_CTRL 0x10 /* offset of cardbus socket control reg */ + + +/* CardBus latency timer, Subordinate bus no, CardBus bus no and PCI bus no */ +#define PCI_CB_LSCP_REG 0x18 +/* CardBus memory and io windows */ +#define PCI_CB_MEMBASE0 0x1c +#define PCI_CB_MEMLIMIT0 0x20 +#define PCI_CB_MEMBASE1 0x24 +#define PCI_CB_MEMLIMIT1 0x28 +#define PCI_CB_IOBASE0 0x2c +#define PCI_CB_IOLIMIT0 0x30 +#define PCI_CB_IOBASE1 0x34 +#define PCI_CB_IOLIMIT1 0x38 + +/* PCI_CB_LSCP_REG */ +#define PCI_CB_LATENCY_SHIFT 24 +#define PCI_CB_LATENCY_MASK 0xff +#define PCI_CB_LATENCY(x) (((x) >> PCI_CB_LATENCY_SHIFT) & PCI_CB_LATENCY_MASK) + + + +/* PCI_BCR_INTR bits for generic PCI-CardBus bridge */ +#define CB_BCR_INTR_IREQ_ENABLE 0x0800000 +#define CB_BCR_WRITE_POST_ENABLE 0x4000000 + +/* PCI_CBCTRL bits for TI PCI113X */ +#define PCI113X_CBCTRL_INT_SERIAL 0x040000 +#define PCI113X_CBCTRL_INT_ISA 0x020000 +#define PCI113X_CBCTRL_INT_MASK 0x060000 +#define PCI113X_CBCTRL_RIENB 0x8000 /* Ring indicate output enable */ +#define PCI113X_CBCTRL_ZVENAB 0x4000 /* ZV mode enable */ +#define PCI113X_CBCTRL_PCI_IRQ_ENA 0x2000 /* PCI intr enable (funct and CSC) */ +#define PCI113X_CBCTRL_PCI_INTR 0x1000 /* PCI functional intr req */ +#define PCI113X_CBCTRL_PCI_CSC 0x0800 /* CSC intr route to PCI */ +#define PCI113X_CBCTRL_PCI_CSC_D 0x0400 /* unknown */ +#define PCI113X_CBCTRL_SPK_ENA 0x0200 /* Speaker enable */ +#define PCI113X_CBCTRL_INTR_DET 0x0100 /* functional interrupt detect */ + +/* PCI_CBCTRL bits for TI PCI12XX */ +#define PCI12XX_CBCTRL_INT_SERIAL 0x040000 +#define PCI12XX_CBCTRL_INT_ISA 0x020000 +#define PCI12XX_CBCTRL_INT_PCI 0x000000 +#define PCI12XX_CBCTRL_INT_MASK 0x060000 +#define PCI12XX_CBCTRL_RIENB 0x8000 /* Ring indicate output enable */ +#define PCI12XX_CBCTRL_ZVENAB 0x4000 /* ZV mode enable */ +#define PCI12XX_CBCTRL_AUD2MUX 0x0400 /* unknown */ +#define PCI12XX_CBCTRL_SPK_ENA 0x0200 /* Speaker enable */ +#define PCI12XX_CBCTRL_INTR_DET 0x0100 /* functional interrupt detect */ + +/* PCI_BCR_INTR additional bit for RF5C46[567] */ +#define CB_BCRI_RL_3E0_ENA 0x08000000 +#define CB_BCRI_RL_3E2_ENA 0x10000000 + +/* + * Special resister definition for Toshiba ToPIC95/97 + * These values are borrowed from pcmcia-cs/Linux. + */ +#define TOPIC_SOCKET_CTRL 0x90 +# define TOPIC_SOCKET_CTRL_SCR_IRQSEL 0x00000001 /* PCI intr */ + +#define TOPIC_SLOT_CTRL 0xa0 +# define TOPIC_SLOT_CTRL_SLOTON 0x00000080 +# define TOPIC_SLOT_CTRL_SLOTEN 0x00000040 +# define TOPIC_SLOT_CTRL_ID_LOCK 0x00000020 +# define TOPIC_SLOT_CTRL_ID_WP 0x00000010 +# define TOPIC_SLOT_CTRL_PORT_MASK 0x0000000c +# define TOPIC_SLOT_CTRL_PORT_SHIFT 2 +# define TOPIC_SLOT_CTRL_OSF_MASK 0x00000003 +# define TOPIC_SLOT_CTRL_OSF_SHIFT 0 + +# define TOPIC_SLOT_CTRL_INTB 0x00002000 +# define TOPIC_SLOT_CTRL_INTA 0x00001000 +# define TOPIC_SLOT_CTRL_INT_MASK 0x00003000 +# define TOPIC_SLOT_CTRL_CLOCK_MASK 0x00000c00 +# define TOPIC_SLOT_CTRL_CLOCK_2 0x00000800 /* PCI Clock/2 */ +# define TOPIC_SLOT_CTRL_CLOCK_1 0x00000400 /* PCI Clock */ +# define TOPIC_SLOT_CTRL_CLOCK_0 0x00000000 /* no clock */ + +# define TOPIC_SLOT_CTRL_CARDBUS 0x80000000 +# define TOPIC_SLOT_CTRL_VS1 0x04000000 +# define TOPIC_SLOT_CTRL_VS2 0x02000000 +# define TOPIC_SLOT_CTRL_SWDETECT 0x01000000 + +#define TOPIC_REG_CTRL 0x00a4 +# define TOPIC_REG_CTRL_RESUME_RESET 0x80000000 +# define TOPIC_REG_CTRL_REMOVE_RESET 0x40000000 +# define TOPIC97_REG_CTRL_CLKRUN_ENA 0x20000000 +# define TOPIC97_REG_CTRL_TESTMODE 0x10000000 +# define TOPIC97_REG_CTRL_IOPLUP 0x08000000 +# define TOPIC_REG_CTRL_BUFOFF_PWROFF 0x02000000 +# define TOPIC_REG_CTRL_BUFOFF_SIGOFF 0x01000000 +# define TOPIC97_REG_CTRL_CB_DEV_MASK 0x0000f800 +# define TOPIC97_REG_CTRL_CB_DEV_SHIFT 11 +# define TOPIC97_REG_CTRL_RI_DISABLE 0x00000004 +# define TOPIC97_REG_CTRL_CAUDIO_OFF 0x00000002 +# define TOPIC_REG_CTRL_CAUDIO_INVERT 0x00000001 + + + +/* socket event register (CB_SOCKET_EVENT) elements */ +#define CB_SOCKET_EVENT_CSTS 0x01 /* CARDSTS event occurs */ +#define CB_SOCKET_EVENT_CD 0x06 /* CD event occurs */ +#define CB_SOCKET_EVENT_CD1 0x02 /* CD1 event occurs */ +#define CB_SOCKET_EVENT_CD2 0x04 /* CD2 event occurs */ +#define CB_SOCKET_EVENT_POWER 0x08 /* Power cycle event occurs */ + + +/* socket mask register (CB_SOCKET_MASK) elements */ +#define CB_SOCKET_MASK_CSTS 0x01 /* CARDSTS event mask */ +#define CB_SOCKET_MASK_CD 0x06 /* CD event mask */ +#define CB_SOCKET_MASK_POWER 0x08 /* Power cycle event mask */ + +/* socket present-state register (CB_SOCKET_STAT) elements */ +#define CB_SOCKET_STAT_CARDSTS 0x01 /* card status change bit */ +#define CB_SOCKET_STAT_CD1 0x02 /* card detect 1 */ +#define CB_SOCKET_STAT_CD2 0x04 /* card detect 2 */ +#define CB_SOCKET_STAT_CD 0x06 /* card detect 1 and 2 */ +#define CB_SOCKET_STAT_PWRCYCLE 0x08 /* power cycle */ +#define CB_SOCKET_STAT_16BIT 0x010 /* 16-bit card */ +#define CB_SOCKET_STAT_CB 0x020 /* cardbus card */ +#define CB_SOCKET_STAT_IREQ 0x040 /* READY(~IREQ)//(~CINT) bit */ +#define CB_SOCKET_STAT_NOTCARD 0x080 /* Inserted card is unrecognisable */ +#define CB_SOCKET_STAT_DATALOST 0x0100 /* data lost */ +#define CB_SOCKET_STAT_BADVCC 0x0200 /* Bad Vcc Request */ +#define CB_SOCKET_STAT_5VCARD 0x0400 /* 5 V Card */ +#define CB_SOCKET_STAT_3VCARD 0x0800 /* 3.3 V Card */ +#define CB_SOCKET_STAT_XVCARD 0x01000 /* X.X V Card */ +#define CB_SOCKET_STAT_YVCARD 0x02000 /* Y.Y V Card */ +#define CB_SOCKET_STAT_5VSOCK 0x10000000 /* 5 V Socket */ +#define CB_SOCKET_STAT_3VSOCK 0x20000000 /* 3.3 V Socket */ +#define CB_SOCKET_STAT_XVSOCK 0x20000000 /* X.X V Socket */ +#define CB_SOCKET_STAT_YVSOCK 0x20000000 /* Y.Y V Socket */ + +/* socket force event register (CB_SOCKET_FORCE) elements */ +#define CB_SOCKET_FORCE_BADVCC 0x0200 /* Bad Vcc Request */ + + +/* socket control register (CB_SOCKET_CTRL) elements */ +#define CB_SOCKET_CTRL_VPPMASK 0x07 +#define CB_SOCKET_CTRL_VPP_OFF 0x00 +#define CB_SOCKET_CTRL_VPP_12V 0x01 +#define CB_SOCKET_CTRL_VPP_5V 0x02 +#define CB_SOCKET_CTRL_VPP_3V 0x03 +#define CB_SOCKET_CTRL_VPP_XV 0x04 +#define CB_SOCKET_CTRL_VPP_YV 0x05 + +#define CB_SOCKET_CTRL_VCCMASK 0x070 +#define CB_SOCKET_CTRL_VCC_OFF 0x000 +#define CB_SOCKET_CTRL_VCC_5V 0x020 +#define CB_SOCKET_CTRL_VCC_3V 0x030 +#define CB_SOCKET_CTRL_VCC_XV 0x040 +#define CB_SOCKET_CTRL_VCC_YV 0x050 + +#define CB_SOCKET_CTRL_STOPCLK 0x080 + + + +/* PCCARD VOLTAGE */ +#define PCCARD_VCC_UKN 0x00 /* unknown */ +#define PCCARD_VCC_5V 0x01 +#define PCCARD_VCC_3V 0x02 +#define PCCARD_VCC_XV 0x04 +#define PCCARD_VCC_YV 0x08 + + +#endif /* _DEV_PCI_PCCBBREG_H_ */ diff --git a/sys/pci/pccbbvar.h b/sys/pci/pccbbvar.h new file mode 100644 index 000000000000..20a3ea7ab125 --- /dev/null +++ b/sys/pci/pccbbvar.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1999 HAYAKAWA Koichi. 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 HAYAKAWA Koichi. + * 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. + */ +/* $FreeBSD$ */ + +struct pccbb_softc; + +struct cbb_pcic_handle { + struct pccbb_softc *sc; + bus_space_tag_t ph_iot; + bus_space_handle_t ph_ioh; + u_int8_t (* ph_read) __P((struct cbb_pcic_handle *, int)); + void (* ph_write) __P((struct cbb_pcic_handle *, int, u_int8_t)); + int sock; + + int vendor; + int flags; + int memalloc; + struct { + bus_addr_t addr; + bus_size_t size; + long offset; + int kind; + } mem[PCIC_MEM_WINS]; + int ioalloc; + struct { + bus_addr_t addr; + bus_size_t size; + int width; + } io[PCIC_IO_WINS]; + int ih_irq; + struct device *pcmcia; + + int shutdown; + struct proc *event_thread; + SIMPLEQ_HEAD(, pcic_event) events; +}; + +struct pccbb_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_tag_t sc_memt; + + bus_space_tag_t sc_base_memt; + bus_space_handle_t sc_base_memh; + void *sc_ih; /* interrupt handler */ + int sc_intrline; /* interrupt line */ + pcitag_t sc_intrtag; /* copy of pa->pa_intrtag */ + pci_intr_pin_t sc_intrpin; /* copy of pa->pa_intrpin */ + int sc_function; + u_int32_t sc_flags; +#define CBB_CARDEXIST 0x01 +#define CBB_CARDSTATUS_BUSY 0x01000000 + pci_chipset_tag_t sc_pc; + pcitag_t sc_tag; + int sc_chipset; /* chipset id */ + + bus_addr_t sc_mem_start; /* CardBus/PCMCIA memory start */ + bus_addr_t sc_mem_end; /* CardBus/PCMCIA memory end */ + + /* CardBus stuff */ + struct cardbus_softc *sc_csc; + struct device *sc_cbdev; /* Device which attached to the slot XXX mfc */ + /* pcmcia stuff */ + struct cbb_pcic_handle sc_pcmcia_h; + pcmcia_chipset_tag_t sc_pct; + int sc_pcmcia_flags; +#define PCCBB_PCMCIA_IO_RELOC 0x01 /* IO address relocatable stuff exists */ +#define PCCBB_PCMCIA_MEM_32 0x02 /* 32-bit memory address ready */ + /* kthread staff */ + int sc_queued; + struct proc *event_thread; + SIMPLEQ_HEAD(, pcic_event) events; +};