[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     ! 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