[BACK]Return to stp4020.c CVS log [TXT][DIR] Up to [local] / sys / dev / sbus

Annotation of sys/dev/sbus/stp4020.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: stp4020.c,v 1.14 2005/11/23 11:39:37 mickey Exp $     */
                      2: /*     $NetBSD: stp4020.c,v 1.23 2002/06/01 23:51:03 lukem Exp $       */
                      3:
                      4: /*-
                      5:  * Copyright (c) 1998 The NetBSD Foundation, Inc.
                      6:  * All rights reserved.
                      7:  *
                      8:  * This code is derived from software contributed to The NetBSD Foundation
                      9:  * by Paul Kranenburg.
                     10:  *
                     11:  * Redistribution and use in source and binary forms, with or without
                     12:  * modification, are permitted provided that the following conditions
                     13:  * are met:
                     14:  * 1. Redistributions of source code must retain the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer.
                     16:  * 2. Redistributions in binary form must reproduce the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer in the
                     18:  *    documentation and/or other materials provided with the distribution.
                     19:  * 3. All advertising materials mentioning features or use of this software
                     20:  *    must display the following acknowledgement:
                     21:  *        This product includes software developed by the NetBSD
                     22:  *        Foundation, Inc. and its contributors.
                     23:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     24:  *    contributors may be used to endorse or promote products derived
                     25:  *    from this software without specific prior written permission.
                     26:  *
                     27:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     28:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     29:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     30:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     31:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     32:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     33:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     34:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     35:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     36:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     37:  * POSSIBILITY OF SUCH DAMAGE.
                     38:  */
                     39:
                     40: /*
                     41:  * STP4020: SBus/PCMCIA bridge supporting one Type-3 PCMCIA card, or up to
                     42:  * two Type-1 and Type-2 PCMCIA cards..
                     43:  */
                     44:
                     45: #include <sys/param.h>
                     46: #include <sys/systm.h>
                     47: #include <sys/errno.h>
                     48: #include <sys/extent.h>
                     49: #include <sys/proc.h>
                     50: #include <sys/kernel.h>
                     51: #include <sys/kthread.h>
                     52: #include <sys/device.h>
                     53:
                     54: #include <dev/pcmcia/pcmciareg.h>
                     55: #include <dev/pcmcia/pcmciavar.h>
                     56: #include <dev/pcmcia/pcmciachip.h>
                     57:
                     58: #include <machine/bus.h>
                     59:
                     60: #include <dev/sbus/stp4020reg.h>
                     61: #include <dev/sbus/stp4020var.h>
                     62:
                     63: /*
                     64:  * We use the three available windows per socket in a simple, fixed
                     65:  * arrangement. Each window maps (at full 1 MB size) one of the pcmcia
                     66:  * spaces into sbus space.
                     67:  */
                     68: #define STP_WIN_ATTR   0       /* index of the attribute memory space window */
                     69: #define        STP_WIN_MEM     1       /* index of the common memory space window */
                     70: #define        STP_WIN_IO      2       /* index of the io space window */
                     71:
                     72: #ifdef STP4020_DEBUG
                     73: int stp4020_debug = 0;
                     74: #define DPRINTF(x)     do { if (stp4020_debug) printf x; } while(0)
                     75: #else
                     76: #define DPRINTF(x)
                     77: #endif
                     78:
                     79: int    stp4020print(void *, const char *);
                     80: void   stp4020_map_window(struct stp4020_socket *, int, int);
                     81: void   stp4020_calc_speed(int, int, int *, int *);
                     82:
                     83: struct cfdriver stp_cd = {
                     84:        NULL, "stp", DV_DULL
                     85: };
                     86:
                     87: #ifdef STP4020_DEBUG
                     88: static void    stp4020_dump_regs(struct stp4020_socket *);
                     89: #endif
                     90:
                     91: static u_int16_t stp4020_rd_sockctl(struct stp4020_socket *, int);
                     92: static void    stp4020_wr_sockctl(struct stp4020_socket *, int, u_int16_t);
                     93: static u_int16_t stp4020_rd_winctl(struct stp4020_socket *, int, int);
                     94: static void    stp4020_wr_winctl(struct stp4020_socket *, int, int, u_int16_t);
                     95:
                     96: void   stp4020_delay(unsigned int);
                     97: void   stp4020_attach_socket(struct stp4020_socket *, int);
                     98: void   stp4020_create_event_thread(void *);
                     99: void   stp4020_event_thread(void *);
                    100: void   stp4020_queue_event(struct stp4020_softc *, int);
                    101:
                    102: int    stp4020_chip_mem_alloc(pcmcia_chipset_handle_t, bus_size_t,
                    103:            struct pcmcia_mem_handle *);
                    104: void   stp4020_chip_mem_free(pcmcia_chipset_handle_t,
                    105:            struct pcmcia_mem_handle *);
                    106: int    stp4020_chip_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t,
                    107:            bus_size_t, struct pcmcia_mem_handle *, bus_size_t *, int *);
                    108: void   stp4020_chip_mem_unmap(pcmcia_chipset_handle_t, int);
                    109:
                    110: int    stp4020_chip_io_alloc(pcmcia_chipset_handle_t,
                    111:            bus_addr_t, bus_size_t, bus_size_t, struct pcmcia_io_handle *);
                    112: void   stp4020_chip_io_free(pcmcia_chipset_handle_t,
                    113:            struct pcmcia_io_handle *);
                    114: int    stp4020_chip_io_map(pcmcia_chipset_handle_t, int, bus_addr_t,
                    115:            bus_size_t, struct pcmcia_io_handle *, int *);
                    116: void   stp4020_chip_io_unmap(pcmcia_chipset_handle_t, int);
                    117:
                    118: void   stp4020_chip_socket_enable(pcmcia_chipset_handle_t);
                    119: void   stp4020_chip_socket_disable(pcmcia_chipset_handle_t);
                    120: void   *stp4020_chip_intr_establish(pcmcia_chipset_handle_t,
                    121:            struct pcmcia_function *, int, int (*) (void *), void *, char *);
                    122: void   stp4020_chip_intr_disestablish(pcmcia_chipset_handle_t, void *);
                    123: const char *stp4020_chip_intr_string(pcmcia_chipset_handle_t, void *);
                    124:
                    125: /* Our PCMCIA chipset methods */
                    126: static struct pcmcia_chip_functions stp4020_functions = {
                    127:        stp4020_chip_mem_alloc,
                    128:        stp4020_chip_mem_free,
                    129:        stp4020_chip_mem_map,
                    130:        stp4020_chip_mem_unmap,
                    131:
                    132:        stp4020_chip_io_alloc,
                    133:        stp4020_chip_io_free,
                    134:        stp4020_chip_io_map,
                    135:        stp4020_chip_io_unmap,
                    136:
                    137:        stp4020_chip_intr_establish,
                    138:        stp4020_chip_intr_disestablish,
                    139:        stp4020_chip_intr_string,
                    140:
                    141:        stp4020_chip_socket_enable,
                    142:        stp4020_chip_socket_disable
                    143: };
                    144:
                    145:
                    146: static __inline__ u_int16_t
                    147: stp4020_rd_sockctl(h, idx)
                    148:        struct stp4020_socket *h;
                    149:        int idx;
                    150: {
                    151:        int o = ((STP4020_SOCKREGS_SIZE * (h->sock)) + idx);
                    152:        return (bus_space_read_2(h->tag, h->regs, o));
                    153: }
                    154:
                    155: static __inline__ void
                    156: stp4020_wr_sockctl(h, idx, v)
                    157:        struct stp4020_socket *h;
                    158:        int idx;
                    159:        u_int16_t v;
                    160: {
                    161:        int o = (STP4020_SOCKREGS_SIZE * (h->sock)) + idx;
                    162:        bus_space_write_2(h->tag, h->regs, o, v);
                    163: }
                    164:
                    165: static __inline__ u_int16_t
                    166: stp4020_rd_winctl(h, win, idx)
                    167:        struct stp4020_socket *h;
                    168:        int win;
                    169:        int idx;
                    170: {
                    171:        int o = (STP4020_SOCKREGS_SIZE * (h->sock)) +
                    172:            (STP4020_WINREGS_SIZE * win) + idx;
                    173:        return (bus_space_read_2(h->tag, h->regs, o));
                    174: }
                    175:
                    176: static __inline__ void
                    177: stp4020_wr_winctl(h, win, idx, v)
                    178:        struct stp4020_socket *h;
                    179:        int win;
                    180:        int idx;
                    181:        u_int16_t v;
                    182: {
                    183:        int o = (STP4020_SOCKREGS_SIZE * (h->sock)) +
                    184:            (STP4020_WINREGS_SIZE * win) + idx;
                    185:        bus_space_write_2(h->tag, h->regs, o, v);
                    186: }
                    187:
                    188:
                    189: int
                    190: stp4020print(aux, busname)
                    191:        void *aux;
                    192:        const char *busname;
                    193: {
                    194:        struct pcmciabus_attach_args *paa = aux;
                    195:        struct stp4020_socket *h = paa->pch;
                    196:
                    197:        printf(" socket %d", h->sock);
                    198:        return (UNCONF);
                    199: }
                    200:
                    201: /*
                    202:  * Attach all the sub-devices we can find
                    203:  */
                    204: void
                    205: stpattach_common(struct stp4020_softc *sc, int clockfreq)
                    206: {
                    207:        int i, rev;
                    208:
                    209:        rev = stp4020_rd_sockctl(&sc->sc_socks[0], STP4020_ISR1_IDX) &
                    210:            STP4020_ISR1_REV_M;
                    211:        printf(": rev %x\n", rev);
                    212:
                    213:        sc->sc_pct = (pcmcia_chipset_tag_t)&stp4020_functions;
                    214:
                    215:        /*
                    216:         * Arrange that a kernel thread be created to handle
                    217:         * insert/removal events.
                    218:         */
                    219:        sc->events = 0;
                    220:        kthread_create_deferred(stp4020_create_event_thread, sc);
                    221:
                    222:        for (i = 0; i < STP4020_NSOCK; i++) {
                    223:                struct stp4020_socket *h = &sc->sc_socks[i];
                    224:                h->sock = i;
                    225:                h->sc = sc;
                    226: #ifdef STP4020_DEBUG
                    227:                if (stp4020_debug)
                    228:                        stp4020_dump_regs(h);
                    229: #endif
                    230:                stp4020_attach_socket(h, clockfreq);
                    231:        }
                    232: }
                    233:
                    234: void
                    235: stp4020_attach_socket(h, speed)
                    236:        struct stp4020_socket *h;
                    237:        int speed;
                    238: {
                    239:        struct pcmciabus_attach_args paa;
                    240:        int v;
                    241:
                    242:        /* Map all three windows */
                    243:        stp4020_map_window(h, STP_WIN_ATTR, speed);
                    244:        stp4020_map_window(h, STP_WIN_MEM, speed);
                    245:        stp4020_map_window(h, STP_WIN_IO, speed);
                    246:
                    247:        /* Configure one pcmcia device per socket */
                    248:        paa.paa_busname = "pcmcia";
                    249:        paa.pct = (pcmcia_chipset_tag_t)h->sc->sc_pct;
                    250:        paa.pch = (pcmcia_chipset_handle_t)h;
                    251:        paa.iobase = 0;
                    252:        paa.iosize = STP4020_WINDOW_SIZE;
                    253:
                    254:        h->pcmcia = config_found(&h->sc->sc_dev, &paa, stp4020print);
                    255:
                    256:        if (h->pcmcia == NULL)
                    257:                return;
                    258:
                    259:        /*
                    260:         * There's actually a pcmcia bus attached; initialize the slot.
                    261:         */
                    262:
                    263:        /*
                    264:         * Clear things up before we enable status change interrupts.
                    265:         * This seems to not be fully initialized by the PROM.
                    266:         */
                    267:        stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
                    268:        stp4020_wr_sockctl(h, STP4020_ICR0_IDX, 0);
                    269:        stp4020_wr_sockctl(h, STP4020_ISR1_IDX, 0x3fff);
                    270:        stp4020_wr_sockctl(h, STP4020_ISR0_IDX, 0x3fff);
                    271:
                    272:        /*
                    273:         * Enable socket status change interrupts.
                    274:         * We use SB_INT[1] for status change interrupts.
                    275:         */
                    276:        v = STP4020_ICR0_ALL_STATUS_IE | STP4020_ICR0_SCILVL_SB1;
                    277:        stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
                    278:
                    279:        /* Get live status bits from ISR0 */
                    280:        v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
                    281:        h->sense = v & (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST);
                    282:        if (h->sense != 0) {
                    283:                h->flags |= STP4020_SOCKET_BUSY;
                    284:                pcmcia_card_attach(h->pcmcia);
                    285:        }
                    286: }
                    287:
                    288:
                    289: /*
                    290:  * Deferred thread creation callback.
                    291:  */
                    292: void
                    293: stp4020_create_event_thread(arg)
                    294:        void *arg;
                    295: {
                    296:        struct stp4020_softc *sc = arg;
                    297:        const char *name = sc->sc_dev.dv_xname;
                    298:
                    299:        if (kthread_create(stp4020_event_thread, sc, &sc->event_thread,
                    300:            "%s", name)) {
                    301:                panic("%s: unable to create event thread", name);
                    302:        }
                    303: }
                    304:
                    305: /*
                    306:  * The actual event handling thread.
                    307:  */
                    308: void
                    309: stp4020_event_thread(arg)
                    310:        void *arg;
                    311: {
                    312:        struct stp4020_softc *sc = arg;
                    313:        int s, sense;
                    314:        unsigned int socket;
                    315:
                    316:        for (;;) {
                    317:                struct stp4020_socket *h;
                    318:
                    319:                s = splhigh();
                    320:                if ((socket = ffs(sc->events)) == 0) {
                    321:                        splx(s);
                    322:                        (void)tsleep(&sc->events, PWAIT, "stp4020_ev", 0);
                    323:                        continue;
                    324:                }
                    325:                socket--;
                    326:                sc->events &= ~(1 << socket);
                    327:                splx(s);
                    328:
                    329:                if (socket >= STP4020_NSOCK) {
                    330: #ifdef DEBUG
                    331:                        printf("stp4020_event_thread: wayward socket number %d\n",
                    332:                            socket);
                    333: #endif
                    334:                        continue;
                    335:                }
                    336:
                    337:                h = &sc->sc_socks[socket];
                    338:
                    339:                /* Read socket's ISR0 for the interrupt status bits */
                    340:                sense = stp4020_rd_sockctl(h, STP4020_ISR0_IDX) &
                    341:                    (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST);
                    342:
                    343:                if (sense > h->sense) {
                    344:                        /*
                    345:                         * If at least one more sensor is asserted, this is
                    346:                         * a card insertion.
                    347:                         */
                    348:                        h->sense = sense;
                    349:                        if ((h->flags & STP4020_SOCKET_BUSY) == 0) {
                    350:                                h->flags |= STP4020_SOCKET_BUSY;
                    351:                                pcmcia_card_attach(h->pcmcia);
                    352:                        }
                    353:                } else if (sense < h->sense) {
                    354:                        /*
                    355:                         * If at least one less sensor is asserted, this is
                    356:                         * a card removal.
                    357:                         */
                    358:                        h->sense = sense;
                    359:                        if (h->flags & STP4020_SOCKET_BUSY) {
                    360:                                h->flags &= ~STP4020_SOCKET_BUSY;
                    361:                                pcmcia_card_detach(h->pcmcia, DETACH_FORCE);
                    362:                        }
                    363:                }
                    364:        }
                    365: }
                    366:
                    367: void
                    368: stp4020_queue_event(sc, sock)
                    369:        struct stp4020_softc *sc;
                    370:        int sock;
                    371: {
                    372:        int s;
                    373:
                    374:        s = splhigh();
                    375:        sc->events |= (1 << sock);
                    376:        splx(s);
                    377:        wakeup(&sc->events);
                    378: }
                    379:
                    380: int
                    381: stp4020_statintr(arg)
                    382:        void *arg;
                    383: {
                    384:        struct stp4020_softc *sc = arg;
                    385:        int i, sense, r = 0;
                    386:
                    387:        /*
                    388:         * Check each socket for pending requests.
                    389:         */
                    390:        for (i = 0 ; i < STP4020_NSOCK; i++) {
                    391:                struct stp4020_socket *h;
                    392:                int v;
                    393:
                    394:                h = &sc->sc_socks[i];
                    395:
                    396:                /* Read socket's ISR0 for the interrupt status bits */
                    397:                v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
                    398:                sense = v & (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST);
                    399:
                    400: #ifdef STP4020_DEBUG
                    401:                if (stp4020_debug != 0)
                    402:                        printf("stp4020_statintr: ISR0=%b\n",
                    403:                            v, STP4020_ISR0_IOBITS);
                    404: #endif
                    405:
                    406:                /* Ack all interrupts at once */
                    407:                stp4020_wr_sockctl(h, STP4020_ISR0_IDX,
                    408:                    STP4020_ISR0_ALL_STATUS_IRQ);
                    409:
                    410:                if ((v & STP4020_ISR0_CDCHG) != 0) {
                    411:                        r = 1;
                    412:
                    413:                        /*
                    414:                         * Card detect status changed. In an ideal world,
                    415:                         * both card detect sensors should be set if a card
                    416:                         * is in the slot, and clear if it is not.
                    417:                         *
                    418:                         * Unfortunately, it turns out that we can get the
                    419:                         * notification before both sensors are set (or
                    420:                         * clear).
                    421:                         *
                    422:                         * This can be very funny if only one sensor is set.
                    423:                         * Is this a removal or an insertion operation?
                    424:                         * Defer appropriate action to the worker thread.
                    425:                         */
                    426:                        if (sense != h->sense)
                    427:                                stp4020_queue_event(sc, i);
                    428:
                    429:                }
                    430:
                    431:                /* informational messages */
                    432:                if ((v & STP4020_ISR0_BVD1CHG) != 0) {
                    433:                        DPRINTF(("stp4020[%d]: Battery change 1\n",
                    434:                            h->sock));
                    435:                        r = 1;
                    436:                }
                    437:
                    438:                if ((v & STP4020_ISR0_BVD2CHG) != 0) {
                    439:                        DPRINTF(("stp4020[%d]: Battery change 2\n",
                    440:                            h->sock));
                    441:                        r = 1;
                    442:                }
                    443:
                    444:                if ((v & STP4020_ISR0_RDYCHG) != 0) {
                    445:                        DPRINTF(("stp4020[%d]: Ready/Busy change\n",
                    446:                            h->sock));
                    447:                        r = 1;
                    448:                }
                    449:
                    450:                if ((v & STP4020_ISR0_WPCHG) != 0) {
                    451:                        DPRINTF(("stp4020[%d]: Write protect change\n",
                    452:                            h->sock));
                    453:                        r = 1;
                    454:                }
                    455:
                    456:                if ((v & STP4020_ISR0_PCTO) != 0) {
                    457:                        DPRINTF(("stp4020[%d]: Card access timeout\n",
                    458:                            h->sock));
                    459:                        r = 1;
                    460:                }
                    461:
                    462:                if ((v & STP4020_ISR0_SCINT) != 0) {
                    463:                        DPRINTF(("stp4020[%d]: Status change\n",
                    464:                            h->sock));
                    465:                        r = 1;
                    466:                }
                    467:
                    468:                /*
                    469:                 * Not interrupts flag per se, but interrupts can occur when
                    470:                 * they are asserted, at least during our slot enable routine.
                    471:                 */
                    472:                if ((h->flags & STP4020_SOCKET_ENABLING) &&
                    473:                    (v & (STP4020_ISR0_WAITST | STP4020_ISR0_PWRON)))
                    474:                        r = 1;
                    475:        }
                    476:
                    477:        return (r);
                    478: }
                    479:
                    480: int
                    481: stp4020_iointr(arg)
                    482:        void *arg;
                    483: {
                    484:        struct stp4020_softc *sc = arg;
                    485:        int i, r = 0;
                    486:
                    487:        /*
                    488:         * Check each socket for pending requests.
                    489:         */
                    490:        for (i = 0 ; i < STP4020_NSOCK; i++) {
                    491:                struct stp4020_socket *h;
                    492:                int v;
                    493:
                    494:                h = &sc->sc_socks[i];
                    495:                v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
                    496:
                    497:                if ((v & STP4020_ISR0_IOINT) != 0) {
                    498:                        /* we can not deny this is ours, no matter what the
                    499:                           card driver says. */
                    500:                        r = 1;
                    501:
                    502:                        /* ack interrupt */
                    503:                        stp4020_wr_sockctl(h, STP4020_ISR0_IDX, v);
                    504:
                    505:                        /* It's a card interrupt */
                    506:                        if ((h->flags & STP4020_SOCKET_BUSY) == 0) {
                    507:                                printf("stp4020[%d]: spurious interrupt?\n",
                    508:                                    h->sock);
                    509:                                continue;
                    510:                        }
                    511:                        /* Call card handler, if any */
                    512:                        if (h->intrhandler != NULL) {
                    513:                                /*
                    514:                                 * We ought to be at an higher ipl level
                    515:                                 * than the callback, since the first
                    516:                                 * interrupt of this device is usually
                    517:                                 * higher than IPL_CLOCK.
                    518:                                 */
                    519:                                splassert(h->ipl);
                    520:                                (*h->intrhandler)(h->intrarg);
                    521:                        }
                    522:                }
                    523:
                    524:        }
                    525:
                    526:        return (r);
                    527: }
                    528:
                    529: /*
                    530:  * The function gets the sbus speed and a access time and calculates
                    531:  * values for the CMDLNG and CMDDLAY registers.
                    532:  */
                    533: void
                    534: stp4020_calc_speed(int bus_speed, int ns, int *length, int *delay)
                    535: {
                    536:        int result;
                    537:
                    538:        if (ns < STP4020_MEM_SPEED_MIN)
                    539:                ns = STP4020_MEM_SPEED_MIN;
                    540:        else if (ns > STP4020_MEM_SPEED_MAX)
                    541:                ns = STP4020_MEM_SPEED_MAX;
                    542:        result = ns * (bus_speed / 1000);
                    543:        if (result % 1000000)
                    544:                result = result / 1000000 + 1;
                    545:        else
                    546:                result /= 1000000;
                    547:        *length = result;
                    548:
                    549:        /* the sbus frequency range is limited, so we can keep this simple */
                    550:        *delay = ns <= STP4020_MEM_SPEED_MIN ? 1 : 2;
                    551: }
                    552:
                    553: void
                    554: stp4020_map_window(struct stp4020_socket *h, int win, int speed)
                    555: {
                    556:        int v, length, delay;
                    557:
                    558:        /*
                    559:         * According to the PC Card standard 300ns access timing should be
                    560:         * used for attribute memory access. Our pcmcia framework does not
                    561:         * seem to propagate timing information, so we use that
                    562:         * everywhere.
                    563:         */
                    564:        stp4020_calc_speed(speed, 300, &length, &delay);
                    565:
                    566:        /*
                    567:         * Fill in the Address Space Select and Base Address
                    568:         * fields of this windows control register 0.
                    569:         */
                    570:        v = ((delay << STP4020_WCR0_CMDDLY_S) & STP4020_WCR0_CMDDLY_M) |
                    571:            ((length << STP4020_WCR0_CMDLNG_S) & STP4020_WCR0_CMDLNG_M);
                    572:        switch (win) {
                    573:        case STP_WIN_ATTR:
                    574:                v |= STP4020_WCR0_ASPSEL_AM;
                    575:                break;
                    576:        case STP_WIN_MEM:
                    577:                v |= STP4020_WCR0_ASPSEL_CM;
                    578:                break;
                    579:        case STP_WIN_IO:
                    580:                v |= STP4020_WCR0_ASPSEL_IO;
                    581:                break;
                    582:        }
                    583:        v |= (STP4020_ADDR2PAGE(0) & STP4020_WCR0_BASE_M);
                    584:        stp4020_wr_winctl(h, win, STP4020_WCR0_IDX, v);
                    585:        stp4020_wr_winctl(h, win, STP4020_WCR1_IDX,
                    586:            1 << STP4020_WCR1_WAITREQ_S);
                    587: }
                    588:
                    589: int
                    590: stp4020_chip_mem_alloc(pch, size, pcmhp)
                    591:        pcmcia_chipset_handle_t pch;
                    592:        bus_size_t size;
                    593:        struct pcmcia_mem_handle *pcmhp;
                    594: {
                    595:        struct stp4020_socket *h = (struct stp4020_socket *)pch;
                    596:
                    597:        /* we can not do much here, defere work to _mem_map */
                    598:        pcmhp->memt = h->wintag;
                    599:        pcmhp->size = size;
                    600:        pcmhp->addr = 0;
                    601:        pcmhp->mhandle = 0;
                    602:        pcmhp->realsize = size;
                    603:
                    604:        return (0);
                    605: }
                    606:
                    607: void
                    608: stp4020_chip_mem_free(pch, pcmhp)
                    609:        pcmcia_chipset_handle_t pch;
                    610:        struct pcmcia_mem_handle *pcmhp;
                    611: {
                    612: }
                    613:
                    614: int
                    615: stp4020_chip_mem_map(pch, kind, card_addr, size, pcmhp, offsetp, windowp)
                    616:        pcmcia_chipset_handle_t pch;
                    617:        int kind;
                    618:        bus_addr_t card_addr;
                    619:        bus_size_t size;
                    620:        struct pcmcia_mem_handle *pcmhp;
                    621:        bus_size_t *offsetp;
                    622:        int *windowp;
                    623: {
                    624:        struct stp4020_socket *h = (struct stp4020_socket *)pch;
                    625:        int win = (kind & PCMCIA_MEM_ATTR) ? STP_WIN_ATTR : STP_WIN_MEM;
                    626:
                    627:        pcmhp->memt = h->wintag;
                    628:        bus_space_subregion(h->wintag, h->windows[win].winaddr,
                    629:            card_addr, size, &pcmhp->memh);
                    630:        pcmhp->size = size;
                    631:        pcmhp->realsize = STP4020_WINDOW_SIZE - card_addr;
                    632:        *offsetp = 0;
                    633:        *windowp = win;
                    634:
                    635:        return (0);
                    636: }
                    637:
                    638: void
                    639: stp4020_chip_mem_unmap(pch, win)
                    640:        pcmcia_chipset_handle_t pch;
                    641:        int win;
                    642: {
                    643: }
                    644:
                    645: int
                    646: stp4020_chip_io_alloc(pch, start, size, align, pcihp)
                    647:        pcmcia_chipset_handle_t pch;
                    648:        bus_addr_t start;
                    649:        bus_size_t size;
                    650:        bus_size_t align;
                    651:        struct pcmcia_io_handle *pcihp;
                    652: {
                    653:        struct stp4020_socket *h = (struct stp4020_socket *)pch;
                    654:
                    655:        pcihp->iot = h->wintag;
                    656:        pcihp->ioh = h->windows[STP_WIN_IO].winaddr;
                    657:        pcihp->size = size;
                    658:        return (0);
                    659: }
                    660:
                    661: void
                    662: stp4020_chip_io_free(pch, pcihp)
                    663:        pcmcia_chipset_handle_t pch;
                    664:        struct pcmcia_io_handle *pcihp;
                    665: {
                    666: }
                    667:
                    668: int
                    669: stp4020_chip_io_map(pch, width, offset, size, pcihp, windowp)
                    670:        pcmcia_chipset_handle_t pch;
                    671:        int width;
                    672:        bus_addr_t offset;
                    673:        bus_size_t size;
                    674:        struct pcmcia_io_handle *pcihp;
                    675:        int *windowp;
                    676: {
                    677:        struct stp4020_socket *h = (struct stp4020_socket *)pch;
                    678:
                    679:        pcihp->iot = h->wintag;
                    680:        bus_space_subregion(h->wintag, h->windows[STP_WIN_IO].winaddr,
                    681:            offset, size, &pcihp->ioh);
                    682:        *windowp = 0;
                    683:        return (0);
                    684: }
                    685:
                    686: void
                    687: stp4020_chip_io_unmap(pch, win)
                    688:        pcmcia_chipset_handle_t pch;
                    689:        int win;
                    690: {
                    691: }
                    692:
                    693: void
                    694: stp4020_chip_socket_enable(pch)
                    695:        pcmcia_chipset_handle_t pch;
                    696: {
                    697:        struct stp4020_socket *h = (struct stp4020_socket *)pch;
                    698:        int i, v;
                    699:
                    700:        h->flags |= STP4020_SOCKET_ENABLING;
                    701:
                    702:        /* this bit is mostly stolen from pcic_attach_card */
                    703:
                    704:        /* Power down the socket to reset it, clear the card reset pin */
                    705:        stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
                    706:
                    707:        /*
                    708:         * wait 300ms until power fails (Tpf).  Then, wait 100ms since
                    709:         * we are changing Vcc (Toff).
                    710:         */
                    711:        stp4020_delay((300 + 100) * 1000);
                    712:
                    713:        /* Power up the socket */
                    714:        v = STP4020_ICR1_MSTPWR;
                    715:        stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
                    716:
                    717:        /*
                    718:         * wait 100ms until power raise (Tpr) and 20ms to become
                    719:         * stable (Tsu(Vcc)).
                    720:         *
                    721:         * some machines require some more time to be settled
                    722:         * (another 200ms is added here).
                    723:         */
                    724:        stp4020_delay((100 + 20 + 200) * 1000);
                    725:
                    726:        v |= STP4020_ICR1_PCIFOE | STP4020_ICR1_VPP1_VCC;
                    727:        stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
                    728:
                    729:        /*
                    730:         * hold RESET at least 20us.
                    731:         */
                    732:        stp4020_wr_sockctl(h, STP4020_ICR0_IDX,
                    733:            stp4020_rd_sockctl(h, STP4020_ICR0_IDX) | STP4020_ICR0_RESET);
                    734:        delay(20);
                    735:        stp4020_wr_sockctl(h, STP4020_ICR0_IDX,
                    736:            stp4020_rd_sockctl(h, STP4020_ICR0_IDX) & ~STP4020_ICR0_RESET);
                    737:
                    738:        /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
                    739:        stp4020_delay(20000);
                    740:
                    741:        /* Wait for the chip to finish initializing (5 seconds max) */
                    742:        for (i = 10000; i > 0; i--) {
                    743:                v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
                    744:                /* If the card has been removed, abort */
                    745:                if ((v & (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST)) == 0) {
                    746:                        h->flags &= ~STP4020_SOCKET_ENABLING;
                    747:                        return;
                    748:                }
                    749:                if ((v & STP4020_ISR0_RDYST) != 0)
                    750:                        break;
                    751:                delay(500);
                    752:        }
                    753:        if (i <= 0) {
                    754: #ifdef STP4020_DEBUG
                    755:                printf("stp4020_chip_socket_enable: not ready: status %b\n",
                    756:                    v, STP4020_ISR0_IOBITS);
                    757: #endif
                    758:                h->flags &= ~STP4020_SOCKET_ENABLING;
                    759:                return;
                    760:        }
                    761:
                    762:        v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
                    763:
                    764:        /*
                    765:         * Check the card type.
                    766:         * Enable socket I/O interrupts for IO cards.
                    767:         * We use level SB_INT[0] for I/O interrupts.
                    768:         */
                    769:        if (pcmcia_card_gettype(h->pcmcia) == PCMCIA_IFTYPE_IO) {
                    770:                v &= ~(STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE);
                    771:                v |= STP4020_ICR0_IFTYPE_IO | STP4020_ICR0_IOIE |
                    772:                    STP4020_ICR0_IOILVL_SB0 | STP4020_ICR0_SPKREN;
                    773:                DPRINTF(("%s: configuring card for IO usage\n",
                    774:                    h->sc->sc_dev.dv_xname));
                    775:        } else {
                    776:                v &= ~(STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE |
                    777:                    STP4020_ICR0_SPKREN | STP4020_ICR0_IOIE);
                    778:                v |= STP4020_ICR0_IFTYPE_MEM;
                    779:                DPRINTF(("%s: configuring card for MEM ONLY usage\n",
                    780:                    h->sc->sc_dev.dv_xname));
                    781:        }
                    782:        stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
                    783:
                    784:        h->flags &= ~STP4020_SOCKET_ENABLING;
                    785: }
                    786:
                    787: void
                    788: stp4020_chip_socket_disable(pch)
                    789:        pcmcia_chipset_handle_t pch;
                    790: {
                    791:        struct stp4020_socket *h = (struct stp4020_socket *)pch;
                    792:        int v;
                    793:
                    794:        /*
                    795:         * Disable socket I/O interrupts.
                    796:         */
                    797:        v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
                    798:        v &= ~(STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE |
                    799:            STP4020_ICR0_SPKREN | STP4020_ICR0_IOIE);
                    800:        stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
                    801:
                    802:        /* Power down the socket */
                    803:        stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
                    804:
                    805:        /*
                    806:         * wait 300ms until power fails (Tpf).
                    807:         */
                    808:        stp4020_delay(300 * 1000);
                    809: }
                    810:
                    811: void *
                    812: stp4020_chip_intr_establish(pch, pf, ipl, handler, arg, xname)
                    813:        pcmcia_chipset_handle_t pch;
                    814:        struct pcmcia_function *pf;
                    815:        int ipl;
                    816:        int (*handler) (void *);
                    817:        void *arg;
                    818:        char *xname;
                    819: {
                    820:        struct stp4020_socket *h = (struct stp4020_socket *)pch;
                    821:
                    822:        h->intrhandler = handler;
                    823:        h->intrarg = arg;
                    824:        h->ipl = ipl;
                    825:        return (h);
                    826: }
                    827:
                    828: void
                    829: stp4020_chip_intr_disestablish(pch, ih)
                    830:        pcmcia_chipset_handle_t pch;
                    831:        void *ih;
                    832: {
                    833:        struct stp4020_socket *h = (struct stp4020_socket *)pch;
                    834:
                    835:        h->intrhandler = NULL;
                    836:        h->intrarg = NULL;
                    837: }
                    838:
                    839: const char *
                    840: stp4020_chip_intr_string(pch, ih)
                    841:        pcmcia_chipset_handle_t pch;
                    842:        void *ih;
                    843: {
                    844:        if (ih == NULL)
                    845:                return ("couldn't establish interrupt");
                    846:        else
                    847:                return ("");    /* nothing for now */
                    848: }
                    849:
                    850: /*
                    851:  * Delay and possibly yield CPU.
                    852:  * XXX - assumes a context
                    853:  */
                    854: void
                    855: stp4020_delay(ms)
                    856:        unsigned int ms;
                    857: {
                    858:        unsigned int ticks;
                    859:
                    860:        /* Convert to ticks */
                    861:        ticks = (ms * hz) / 1000000;
                    862:
                    863:        if (cold || ticks == 0) {
                    864:                delay(ms);
                    865:                return;
                    866:        }
                    867:
                    868: #ifdef DEBUG
                    869:        if (ticks > 60 * hz)
                    870:                panic("stp4020: preposterous delay: %u", ticks);
                    871: #endif
                    872:        tsleep(&ticks, 0, "stp4020_delay", ticks);
                    873: }
                    874:
                    875: #ifdef STP4020_DEBUG
                    876: void
                    877: stp4020_dump_regs(h)
                    878:        struct stp4020_socket *h;
                    879: {
                    880:        /*
                    881:         * Dump control and status registers.
                    882:         */
                    883:        printf("socket[%d] registers:\n"
                    884:            "\tICR0=%b\n\tICR1=%b\n\tISR0=%b\n\tISR1=%x\n", h->sock,
                    885:            stp4020_rd_sockctl(h, STP4020_ICR0_IDX), STP4020_ICR0_BITS,
                    886:            stp4020_rd_sockctl(h, STP4020_ICR1_IDX), STP4020_ICR1_BITS,
                    887:            stp4020_rd_sockctl(h, STP4020_ISR0_IDX), STP4020_ISR0_IOBITS,
                    888:            stp4020_rd_sockctl(h, STP4020_ISR1_IDX));
                    889: }
                    890: #endif /* STP4020_DEBUG */

CVSweb