[BACK]Return to ts102.c CVS log [TXT][DIR] Up to [local] / sys / arch / sparc / dev

Annotation of sys/arch/sparc/dev/ts102.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: ts102.c,v 1.18 2006/08/11 18:57:35 miod Exp $ */
        !             2: /*
        !             3:  * Copyright (c) 2003, 2004, Miodrag Vallat.
        !             4:  *
        !             5:  * Redistribution and use in source and binary forms, with or without
        !             6:  * modification, are permitted provided that the following conditions
        !             7:  * are met:
        !             8:  * 1. Redistributions of source code must retain the above copyright
        !             9:  *    notice, this list of conditions and the following disclaimer.
        !            10:  * 2. Redistributions in binary form must reproduce the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer in the
        !            12:  *    documentation and/or other materials provided with the distribution.
        !            13:  *
        !            14:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            15:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
        !            16:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
        !            17:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
        !            18:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
        !            19:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
        !            20:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            21:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
        !            22:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
        !            23:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            24:  * POSSIBILITY OF SUCH DAMAGE.
        !            25:  */
        !            26:
        !            27: /*
        !            28:  * Driver for the PCMCIA controller found in Tadpole SPARCbook 3 series
        !            29:  * notebooks.
        !            30:  *
        !            31:  * Based on the information provided in the SPARCbook 3 Technical Reference
        !            32:  * Manual (s3gxtrmb.pdf), chapter 7.  A few ramblings against this document
        !            33:  * and/or the chip itself are scattered across this file.
        !            34:  *
        !            35:  * Implementation notes:
        !            36:  *
        !            37:  * - The TS102 exports its PCMCIA windows as SBus memory ranges: 64MB for
        !            38:  *   the common memory window, and 16MB for the attribute and I/O windows.
        !            39:  *
        !            40:  *   Mapping the whole windows would consume 192MB of address space, which
        !            41:  *   is much more that what the iospace can offer.
        !            42:  *
        !            43:  *   A best-effort solution would be to map the windows on demand. However,
        !            44:  *   due to the way mapdev() works, the va used for the mappings would be
        !            45:  *   lost after unmapping (although using an extent to register iospace memory
        !            46:  *   usage would fix this). So, instead, we will do a fixed mapping of a subset
        !            47:  *   of each window upon attach - this is similar to what the stp4020 driver
        !            48:  *   does.
        !            49:  *
        !            50:  * - IPL for the cards interrupt handlers are not respected. See the stp4020
        !            51:  *   driver source for comments about this.
        !            52:  *
        !            53:  * Endianness farce:
        !            54:  *
        !            55:  * - The documentation pretends that the endianness settings only affect the
        !            56:  *   common memory window. Gee, thanks a lot. What about other windows, then?
        !            57:  *   As a result, this driver runs with endianness conversions turned off.
        !            58:  *
        !            59:  * - One of the little-endian SBus and big-endian PCMCIA flags has the reverse
        !            60:  *   meaning, actually. To achieve a ``no endianness conversion'' status,
        !            61:  *   one has to be set and the other unset. It does not matter which one,
        !            62:  *   though.
        !            63:  */
        !            64:
        !            65: #include <sys/param.h>
        !            66: #include <sys/systm.h>
        !            67: #include <sys/conf.h>
        !            68: #include <sys/device.h>
        !            69: #include <sys/kthread.h>
        !            70: #include <sys/proc.h>
        !            71: #include <sys/queue.h>
        !            72:
        !            73: #include <machine/bus.h>
        !            74:
        !            75: #include <uvm/uvm_extern.h>
        !            76:
        !            77: #include <dev/pcmcia/pcmciareg.h>
        !            78: #include <dev/pcmcia/pcmciavar.h>
        !            79: #include <dev/pcmcia/pcmciachip.h>
        !            80:
        !            81: #include <sparc/dev/sbusvar.h>
        !            82: #include <sparc/dev/tctrlvar.h>
        !            83: #include <sparc/dev/ts102reg.h>
        !            84:
        !            85: #define        TS102_NUM_SLOTS         2
        !            86:
        !            87: /*
        !            88:  * Memory ranges
        !            89:  */
        !            90: #define        TS102_RANGE_COMMON      0
        !            91: #define        TS102_RANGE_ATTR        1
        !            92: #define        TS102_RANGE_IO          2
        !            93:
        !            94: #define        TS102_RANGE_CNT         3
        !            95: #define        TS102_NUM_RANGES        (TS102_RANGE_CNT * TS102_NUM_SLOTS)
        !            96:
        !            97: #define        TS102_ARBITRARY_MAP_SIZE        (1 * 1024 * 1024)
        !            98:
        !            99: struct tslot_softc;
        !           100:
        !           101: /*
        !           102:  * Per-slot data
        !           103:  */
        !           104: struct tslot_data {
        !           105:        struct tslot_softc      *td_parent;
        !           106:        struct device           *td_pcmcia;
        !           107:
        !           108:        volatile u_int8_t       *td_regs;
        !           109:        struct rom_reg          td_rr;
        !           110:        vaddr_t                 td_space[TS102_RANGE_CNT];
        !           111:
        !           112:        /* Interrupt handler */
        !           113:        int                     (*td_intr)(void *);
        !           114:        void                    *td_intrarg;
        !           115:
        !           116:        /* Socket status */
        !           117:        int                     td_slot;
        !           118:        int                     td_status;
        !           119: #define        TS_CARD                 0x0001
        !           120: };
        !           121:
        !           122: struct tslot_softc {
        !           123:        struct device   sc_dev;
        !           124:
        !           125:        struct intrhand sc_ih;
        !           126:
        !           127:        pcmcia_chipset_tag_t sc_pct;
        !           128:
        !           129:        struct proc     *sc_thread;                     /* event thread */
        !           130:        unsigned int    sc_events;      /* sockets with pending events */
        !           131:
        !           132:        struct tslot_data sc_slot[TS102_NUM_SLOTS];
        !           133: };
        !           134:
        !           135: void   tslot_attach(struct device *, struct device *, void *);
        !           136: void   tslot_create_event_thread(void *);
        !           137: void   tslot_event_thread(void *);
        !           138: int    tslot_intr(void *);
        !           139: void   tslot_intr_disestablish(pcmcia_chipset_handle_t, void *);
        !           140: void   *tslot_intr_establish(pcmcia_chipset_handle_t, struct pcmcia_function *,
        !           141:            int, int (*)(void *), void *, char *);
        !           142: const char *tslot_intr_string(pcmcia_chipset_handle_t, void *);
        !           143: int    tslot_io_alloc(pcmcia_chipset_handle_t, bus_addr_t, bus_size_t,
        !           144:            bus_size_t, struct pcmcia_io_handle *);
        !           145: void   tslot_io_free(pcmcia_chipset_handle_t, struct pcmcia_io_handle *);
        !           146: int    tslot_io_map(pcmcia_chipset_handle_t, int, bus_addr_t, bus_size_t,
        !           147:            struct pcmcia_io_handle *, int *);
        !           148: void   tslot_io_unmap(pcmcia_chipset_handle_t, int);
        !           149: int    tslot_match(struct device *, void *, void *);
        !           150: int    tslot_mem_alloc(pcmcia_chipset_handle_t, bus_size_t,
        !           151:            struct pcmcia_mem_handle *);
        !           152: void   tslot_mem_free(pcmcia_chipset_handle_t, struct pcmcia_mem_handle *);
        !           153: int    tslot_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t, bus_size_t,
        !           154:            struct pcmcia_mem_handle *, bus_size_t *, int *);
        !           155: void   tslot_mem_unmap(pcmcia_chipset_handle_t, int);
        !           156: int    tslot_print(void *, const char *);
        !           157: void   tslot_queue_event(struct tslot_softc *, int);
        !           158: void   tslot_reset(struct tslot_data *, u_int32_t);
        !           159: void   tslot_slot_disable(pcmcia_chipset_handle_t);
        !           160: void   tslot_slot_enable(pcmcia_chipset_handle_t);
        !           161: void   tslot_slot_intr(struct tslot_data *, int);
        !           162:
        !           163: struct cfattach tslot_ca = {
        !           164:        sizeof(struct tslot_softc), tslot_match, tslot_attach
        !           165: };
        !           166:
        !           167: struct cfdriver tslot_cd = {
        !           168:        NULL, "tslot", DV_DULL
        !           169: };
        !           170:
        !           171: /*
        !           172:  * PCMCIA chipset methods
        !           173:  */
        !           174: struct pcmcia_chip_functions tslot_functions = {
        !           175:        tslot_mem_alloc,
        !           176:        tslot_mem_free,
        !           177:        tslot_mem_map,
        !           178:        tslot_mem_unmap,
        !           179:
        !           180:        tslot_io_alloc,
        !           181:        tslot_io_free,
        !           182:        tslot_io_map,
        !           183:        tslot_io_unmap,
        !           184:
        !           185:        tslot_intr_establish,
        !           186:        tslot_intr_disestablish,
        !           187:        tslot_intr_string,
        !           188:
        !           189:        tslot_slot_enable,
        !           190:        tslot_slot_disable
        !           191: };
        !           192:
        !           193: #define        TSLOT_READ(slot, offset) \
        !           194:        *(volatile u_int16_t *)((slot)->td_regs + (offset))
        !           195: #define        TSLOT_WRITE(slot, offset, value) \
        !           196:        *(volatile u_int16_t *)((slot)->td_regs + (offset)) = (value)
        !           197:
        !           198: /*
        !           199:  * Attachment and initialization
        !           200:  */
        !           201:
        !           202: int
        !           203: tslot_match(struct device *parent, void *vcf, void *aux)
        !           204: {
        !           205:        struct confargs *ca = aux;
        !           206:
        !           207:        return (strcmp("ts102", ca->ca_ra.ra_name) == 0);
        !           208: }
        !           209:
        !           210: void
        !           211: tslot_attach(struct device *parent, struct device *self, void *args)
        !           212: {
        !           213:        struct confargs *ca = args;
        !           214:        struct tslot_softc *sc = (struct tslot_softc *)self;
        !           215:        struct romaux *ra;
        !           216:        struct rom_range ranges[TS102_NUM_RANGES], *range;
        !           217:        struct tslot_data *td;
        !           218:        volatile u_int8_t *regs;
        !           219:        int node, nranges, slot, rnum;
        !           220:
        !           221:        ra = &ca->ca_ra;
        !           222:        node = ra->ra_node;
        !           223:        regs = mapiodev(&ra->ra_reg[0], 0, ra->ra_len);
        !           224:
        !           225:        /*
        !           226:         * Find memory ranges
        !           227:         */
        !           228:        nranges = getproplen(node, "ranges") / sizeof(struct rom_range);
        !           229:        if (nranges < TS102_NUM_RANGES) {
        !           230:                printf(": expected %d memory ranges, got %d\n",
        !           231:                    TS102_NUM_RANGES, nranges);
        !           232:                return;
        !           233:        }
        !           234:        getprop(node, "ranges", ranges, sizeof ranges);
        !           235:
        !           236:        /*
        !           237:         * Ranges being relative to this sbus slot, turn them into absolute
        !           238:         * addresses.
        !           239:         */
        !           240:        for (rnum = 0; rnum < TS102_NUM_RANGES; rnum++) {
        !           241:                ranges[rnum].poffset -= TS102_OFFSET_REGISTERS;
        !           242:        }
        !           243:
        !           244:        sc->sc_ih.ih_fun = tslot_intr;
        !           245:        sc->sc_ih.ih_arg = sc;
        !           246:        intr_establish(ra->ra_intr[0].int_pri, &sc->sc_ih, -1, self->dv_xname);
        !           247:        printf(" pri %d", ra->ra_intr[0].int_pri);
        !           248:
        !           249:        printf(": %d slots\n", TS102_NUM_SLOTS);
        !           250:
        !           251:        /*
        !           252:         * Setup asynchronous event handler
        !           253:         */
        !           254:        sc->sc_events = 0;
        !           255:        kthread_create_deferred(tslot_create_event_thread, sc);
        !           256:
        !           257:        sc->sc_pct = (pcmcia_chipset_tag_t)&tslot_functions;
        !           258:
        !           259:        /*
        !           260:         * Setup slots
        !           261:         */
        !           262:        for (slot = 0; slot < TS102_NUM_SLOTS; slot++) {
        !           263:                td = &sc->sc_slot[slot];
        !           264:                for (rnum = 0; rnum < TS102_RANGE_CNT; rnum++) {
        !           265:                        range = ranges + (slot * TS102_RANGE_CNT + rnum);
        !           266:                        td->td_rr = ra->ra_reg[0];
        !           267:                        td->td_rr.rr_iospace = range->pspace;
        !           268:                        td->td_rr.rr_paddr = (void *)
        !           269:                           ((u_int32_t)td->td_rr.rr_paddr + range->poffset);
        !           270:                        td->td_space[rnum] = (vaddr_t)mapiodev(&td->td_rr, 0,
        !           271:                            TS102_ARBITRARY_MAP_SIZE);
        !           272:                }
        !           273:                td->td_parent = sc;
        !           274:                td->td_regs = regs +
        !           275:                    slot * (TS102_REG_CARD_B_INT - TS102_REG_CARD_A_INT);
        !           276:                td->td_slot = slot;
        !           277:                SET_TAG_LITTLE_ENDIAN(&td->td_rr);
        !           278:                tslot_reset(td, TS102_ARBITRARY_MAP_SIZE);
        !           279:        }
        !           280: }
        !           281:
        !           282: void
        !           283: tslot_reset(struct tslot_data *td, u_int32_t iosize)
        !           284: {
        !           285:        struct pcmciabus_attach_args paa;
        !           286:        int ctl, status;
        !           287:
        !           288:        paa.paa_busname = "pcmcia";
        !           289:        paa.pct = (pcmcia_chipset_tag_t)td->td_parent->sc_pct;
        !           290:        paa.pch = (pcmcia_chipset_handle_t)td;
        !           291:        paa.iobase = 0;
        !           292:        paa.iosize = iosize;
        !           293:
        !           294:        td->td_pcmcia = config_found(&td->td_parent->sc_dev, &paa, tslot_print);
        !           295:
        !           296:        if (td->td_pcmcia == NULL) {
        !           297:                /*
        !           298:                 * If no pcmcia attachment, power down the slot.
        !           299:                 */
        !           300:                tslot_slot_disable((pcmcia_chipset_handle_t)td);
        !           301:                return;
        !           302:        }
        !           303:
        !           304:        /*
        !           305:         * Initialize the slot
        !           306:         */
        !           307:
        !           308:        ctl = TSLOT_READ(td, TS102_REG_CARD_A_CTL);
        !           309:        /* force low addresses */
        !           310:        ctl &= ~(TS102_CARD_CTL_AA_MASK | TS102_CARD_CTL_IA_MASK);
        !           311:        /* Put SBus and PCMCIA in their respective endian mode */
        !           312:        ctl |= TS102_CARD_CTL_SBLE;     /* this is not what it looks like! */
        !           313:        ctl &= ~TS102_CARD_CTL_PCMBE;
        !           314:        /* disable read ahead and address increment */
        !           315:        ctl &= ~TS102_CARD_CTL_RAHD;
        !           316:        ctl |= TS102_CARD_CTL_INCDIS;
        !           317:        /* power on */
        !           318:        ctl &= ~TS102_CARD_CTL_PWRD;
        !           319:        TSLOT_WRITE(td, TS102_REG_CARD_A_CTL, ctl);
        !           320:
        !           321:        /*
        !           322:         * Enable interrupt upon insertion/removal
        !           323:         */
        !           324:
        !           325:        TSLOT_WRITE(td, TS102_REG_CARD_A_INT,
        !           326:            TS102_CARD_INT_MASK_CARDDETECT_STATUS);
        !           327:
        !           328:        status = TSLOT_READ(td, TS102_REG_CARD_A_STS);
        !           329:        if (status & TS102_CARD_STS_PRES) {
        !           330:                tadpole_set_pcmcia(td->td_slot, 1);
        !           331:                td->td_status = TS_CARD;
        !           332:                pcmcia_card_attach(td->td_pcmcia);
        !           333:        } else {
        !           334:                tadpole_set_pcmcia(td->td_slot, 0);
        !           335:                td->td_status = 0;
        !           336:        }
        !           337: }
        !           338:
        !           339: /* XXX there ought to be a common function for this... */
        !           340: int
        !           341: tslot_print(void *aux, const char *description)
        !           342: {
        !           343:        struct pcmciabus_attach_args *paa = aux;
        !           344:        struct tslot_data *td = (struct tslot_data *)paa->pch;
        !           345:
        !           346:        printf(" socket %d", td->td_slot);
        !           347:        return (UNCONF);
        !           348: }
        !           349:
        !           350: /*
        !           351:  * PCMCIA Helpers
        !           352:  */
        !           353:
        !           354: int
        !           355: tslot_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start, bus_size_t size,
        !           356:     bus_size_t align, struct pcmcia_io_handle *pih)
        !           357: {
        !           358:        struct tslot_data *td = (struct tslot_data *)pch;
        !           359:
        !           360: #ifdef TSLOT_DEBUG
        !           361:        printf("[io alloc %x-%x]", start, size);
        !           362: #endif
        !           363:
        !           364:        pih->iot = &td->td_rr;
        !           365:        pih->ioh = (bus_space_handle_t)(td->td_space[TS102_RANGE_IO]);
        !           366:        pih->addr = start;
        !           367:        pih->size = size;
        !           368:        pih->flags = 0;
        !           369:
        !           370:        return (0);
        !           371: }
        !           372:
        !           373: void
        !           374: tslot_io_free(pcmcia_chipset_handle_t pch, struct pcmcia_io_handle *pih)
        !           375: {
        !           376: #ifdef TSLOT_DEBUG
        !           377:        printf("[io free %x-%x]", pih->start, pih->size);
        !           378: #endif
        !           379: }
        !           380:
        !           381: int
        !           382: tslot_io_map(pcmcia_chipset_handle_t pch, int width, bus_addr_t offset,
        !           383:     bus_size_t size, struct pcmcia_io_handle *pih, int *windowp)
        !           384: {
        !           385:        struct tslot_data *td = (struct tslot_data *)pch;
        !           386:
        !           387: #ifdef TSLOT_DEBUG
        !           388:        printf("[io map %x-%x", offset, size);
        !           389: #endif
        !           390:
        !           391:        pih->iot = &td->td_rr;
        !           392:        bus_space_subregion(&td->td_rr, td->td_space[TS102_RANGE_IO],
        !           393:            offset, size, &pih->ioh);
        !           394:        *windowp = TS102_RANGE_IO;
        !           395:
        !           396: #ifdef TSLOT_DEBUG
        !           397:        printf("->%p/%x]", pih->ioh, size);
        !           398: #endif
        !           399:
        !           400:        return (0);
        !           401: }
        !           402:
        !           403: void
        !           404: tslot_io_unmap(pcmcia_chipset_handle_t pch, int win)
        !           405: {
        !           406: #ifdef TSLOT_DEBUG
        !           407:        printf("[io unmap]");
        !           408: #endif
        !           409: }
        !           410:
        !           411: int
        !           412: tslot_mem_alloc(pcmcia_chipset_handle_t pch, bus_size_t size,
        !           413:     struct pcmcia_mem_handle *pmh)
        !           414: {
        !           415:        struct tslot_data *td = (struct tslot_data *)pch;
        !           416:
        !           417: #ifdef TSLOT_DEBUG
        !           418:        printf("[mem alloc %x]", size);
        !           419: #endif
        !           420:        pmh->memt = &td->td_rr;
        !           421:        pmh->size = round_page(size);
        !           422:        pmh->addr = 0;
        !           423:        pmh->mhandle = 0;
        !           424:        pmh->realsize = 0;      /* nothing so far! */
        !           425:
        !           426:        return (0);
        !           427: }
        !           428:
        !           429: void
        !           430: tslot_mem_free(pcmcia_chipset_handle_t pch, struct pcmcia_mem_handle *pmh)
        !           431: {
        !           432: #ifdef TSLOT_DEBUG
        !           433:        printf("[mem free %x]", pmh->size);
        !           434: #endif
        !           435: }
        !           436:
        !           437: int
        !           438: tslot_mem_map(pcmcia_chipset_handle_t pch, int kind, bus_addr_t addr,
        !           439:     bus_size_t size, struct pcmcia_mem_handle *pmh, bus_size_t *offsetp,
        !           440:     int *windowp)
        !           441: {
        !           442:        struct tslot_data *td = (struct tslot_data *)pch;
        !           443:        int slot;
        !           444:
        !           445:        slot = kind & PCMCIA_MEM_ATTR ? TS102_RANGE_ATTR : TS102_RANGE_COMMON;
        !           446: #ifdef TSLOT_DEBUG
        !           447:        printf("[mem map %d %x-%x", slot, addr, size);
        !           448: #endif
        !           449:
        !           450:        addr += pmh->addr;
        !           451:
        !           452:        pmh->memt = &td->td_rr;
        !           453:        bus_space_subregion(&td->td_rr, td->td_space[slot],
        !           454:            addr, size, &pmh->memh);
        !           455:        pmh->realsize = TS102_ARBITRARY_MAP_SIZE - addr;
        !           456:        *offsetp = 0;
        !           457:        *windowp = slot;
        !           458:
        !           459: #ifdef TSLOT_DEBUG
        !           460:        printf("->%p/%x]", pmh->memh, size);
        !           461: #endif
        !           462:
        !           463:        return (0);
        !           464: }
        !           465:
        !           466: void
        !           467: tslot_mem_unmap(pcmcia_chipset_handle_t pch, int win)
        !           468: {
        !           469: #ifdef TSLOT_DEBUG
        !           470:        printf("[mem unmap %d]", win);
        !           471: #endif
        !           472: }
        !           473:
        !           474: void
        !           475: tslot_slot_disable(pcmcia_chipset_handle_t pch)
        !           476: {
        !           477:        struct tslot_data *td = (struct tslot_data *)pch;
        !           478:
        !           479: #ifdef TSLOT_DEBUG
        !           480:        printf("%s: disable slot %d\n",
        !           481:            td->td_parent->sc_dev.dv_xname, td->td_slot);
        !           482: #endif
        !           483:
        !           484:        /*
        !           485:         * Disable card access.
        !           486:         */
        !           487:        TSLOT_WRITE(td, TS102_REG_CARD_A_STS,
        !           488:            TSLOT_READ(td, TS102_REG_CARD_A_STS) & ~TS102_CARD_STS_ACEN);
        !           489:
        !           490:        /*
        !           491:         * Disable interrupts, except for insertion.
        !           492:         */
        !           493:        TSLOT_WRITE(td, TS102_REG_CARD_A_INT,
        !           494:            TS102_CARD_INT_MASK_CARDDETECT_STATUS);
        !           495: }
        !           496:
        !           497: void
        !           498: tslot_slot_enable(pcmcia_chipset_handle_t pch)
        !           499: {
        !           500:        struct tslot_data *td = (struct tslot_data *)pch;
        !           501:        int status, intr, i;
        !           502:
        !           503: #ifdef TSLOT_DEBUG
        !           504:        printf("%s: enable slot %d\n",
        !           505:            td->td_parent->sc_dev.dv_xname, td->td_slot);
        !           506: #endif
        !           507:
        !           508:        /* Power down the socket to reset it */
        !           509:        status = TSLOT_READ(td, TS102_REG_CARD_A_STS);
        !           510:        TSLOT_WRITE(td, TS102_REG_CARD_A_STS, status | TS102_CARD_STS_VCCEN);
        !           511:
        !           512:        /*
        !           513:         * wait 300ms until power fails (Tpf).  Then, wait 100ms since we
        !           514:         * are changing Vcc (Toff).
        !           515:         */
        !           516:        DELAY((300 + 100) * 1000);
        !           517:
        !           518:        /*
        !           519:         * Power on the card if not already done, and enable card access
        !           520:         */
        !           521:        status |= TS102_CARD_STS_ACEN;
        !           522:        status &= ~TS102_CARD_STS_VCCEN;
        !           523:        TSLOT_WRITE(td, TS102_REG_CARD_A_STS, status);
        !           524:
        !           525:        /*
        !           526:         * wait 100ms until power raise (Tpr) and 20ms to become
        !           527:         * stable (Tsu(Vcc)).
        !           528:         */
        !           529:        DELAY((100 + 20) * 1000);
        !           530:
        !           531:        status &= ~TS102_CARD_STS_VPP1_MASK;
        !           532:        status |= TS102_CARD_STS_VPP1_VCC;
        !           533:        TSLOT_WRITE(td, TS102_REG_CARD_A_STS, status);
        !           534:
        !           535:        /*
        !           536:         * hold RESET at least 20us.
        !           537:         */
        !           538:        intr = TSLOT_READ(td, TS102_REG_CARD_A_INT);
        !           539:        TSLOT_WRITE(td, TS102_REG_CARD_A_INT, TS102_CARD_INT_SOFT_RESET);
        !           540:        DELAY(20);
        !           541:        TSLOT_WRITE(td, TS102_REG_CARD_A_INT, intr);
        !           542:
        !           543:        /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
        !           544:        DELAY(20 * 1000);
        !           545:
        !           546:        /* We need level-triggered interrupts for PC Card hardware */
        !           547:        TSLOT_WRITE(td, TS102_REG_CARD_A_STS,
        !           548:                TSLOT_READ(td, TS102_REG_CARD_A_STS) | TS102_CARD_STS_LVL);
        !           549:
        !           550:        /*
        !           551:         * Wait until the card is unbusy. If it is still busy after 3 seconds,
        !           552:         * give up. We could enable card interrupts and wait for the interrupt
        !           553:         * to happen when BUSY is released, but the interrupt could also be
        !           554:         * triggered by the card itself if it's an I/O card, so better poll
        !           555:         * here.
        !           556:         */
        !           557:        for (i = 30000; i != 0; i--) {
        !           558:                status = TSLOT_READ(td, TS102_REG_CARD_A_STS);
        !           559:                /* If the card has been removed, abort */
        !           560:                if ((status & TS102_CARD_STS_PRES) == 0) {
        !           561:                        tslot_slot_disable(pch);
        !           562:                        return;
        !           563:                }
        !           564:                if (status & TS102_CARD_STS_RDY)
        !           565:                        break;
        !           566:                else
        !           567:                        DELAY(100);
        !           568:        }
        !           569:
        !           570:        if (i == 0) {
        !           571:                printf("%s: slot %d still busy after 3 seconds, status 0x%x\n",
        !           572:                    td->td_parent->sc_dev.dv_xname, td->td_slot,
        !           573:                    TSLOT_READ(td, TS102_REG_CARD_A_STS));
        !           574:                return;
        !           575:        }
        !           576:
        !           577:        /*
        !           578:         * Enable the card interrupts if this is an I/O card.
        !           579:         * Note that the TS102_CARD_STS_IO bit in the status register will
        !           580:         * never get set, despite what the documentation says!
        !           581:         */
        !           582:        if (pcmcia_card_gettype(td->td_pcmcia) == PCMCIA_IFTYPE_IO) {
        !           583:                TSLOT_WRITE(td, TS102_REG_CARD_A_STS,
        !           584:                    TSLOT_READ(td, TS102_REG_CARD_A_STS) | TS102_CARD_STS_IO);
        !           585:                TSLOT_WRITE(td, TS102_REG_CARD_A_INT,
        !           586:                    TS102_CARD_INT_MASK_CARDDETECT_STATUS |
        !           587:                    TS102_CARD_INT_MASK_IRQ);
        !           588:        }
        !           589: }
        !           590:
        !           591: /*
        !           592:  * Event management
        !           593:  */
        !           594: void
        !           595: tslot_create_event_thread(void *v)
        !           596: {
        !           597:        struct tslot_softc *sc = v;
        !           598:        const char *name = sc->sc_dev.dv_xname;
        !           599:
        !           600:        if (kthread_create(tslot_event_thread, sc, &sc->sc_thread, "%s",
        !           601:            name) != 0) {
        !           602:                panic("%s: unable to create event kthread", name);
        !           603:        }
        !           604: }
        !           605:
        !           606: void
        !           607: tslot_event_thread(void *v)
        !           608: {
        !           609:        struct tslot_softc *sc = v;
        !           610:        struct tslot_data *td;
        !           611:        int s, status;
        !           612:        unsigned int socket;
        !           613:
        !           614:        for (;;) {
        !           615:                s = splhigh();
        !           616:
        !           617:                if ((socket = ffs(sc->sc_events)) == 0) {
        !           618:                        splx(s);
        !           619:                        tsleep(&sc->sc_events, PWAIT, "tslot_event", 0);
        !           620:                        continue;
        !           621:                }
        !           622:                socket--;
        !           623:                sc->sc_events &= ~(1 << socket);
        !           624:                splx(s);
        !           625:
        !           626:                if (socket >= TS102_NUM_SLOTS) {
        !           627: #ifdef DEBUG
        !           628:                        printf("%s: invalid slot number %d\n",
        !           629:                            sc->sc_dev.dv_xname, te->te_slot);
        !           630: #endif
        !           631:                        continue;
        !           632:                }
        !           633:
        !           634:                td = &sc->sc_slot[socket];
        !           635:                status = TSLOT_READ(td, TS102_REG_CARD_A_STS);
        !           636:
        !           637:                if (status & TS102_CARD_STS_PRES) {
        !           638:                        /* Card insertion */
        !           639:                        if ((td->td_status & TS_CARD) == 0) {
        !           640:                                td->td_status |= TS_CARD;
        !           641:                                tadpole_set_pcmcia(td->td_slot, 1);
        !           642:                                pcmcia_card_attach(td->td_pcmcia);
        !           643:                        }
        !           644:                } else {
        !           645:                        /* Card removal */
        !           646:                        if ((td->td_status & TS_CARD) != 0) {
        !           647:                                td->td_status &= ~TS_CARD;
        !           648:                                tadpole_set_pcmcia(td->td_slot, 0);
        !           649:                                pcmcia_card_detach(td->td_pcmcia,
        !           650:                                    DETACH_FORCE);
        !           651:                        }
        !           652:                }
        !           653:        }
        !           654: }
        !           655:
        !           656: /*
        !           657:  * Interrupt handling
        !           658:  */
        !           659:
        !           660: int
        !           661: tslot_intr(void *v)
        !           662: {
        !           663:        struct tslot_softc *sc = v;
        !           664:        struct tslot_data *td;
        !           665:        int intregs[TS102_NUM_SLOTS], *intreg;
        !           666:        int i, rc = 0;
        !           667:
        !           668:        /*
        !           669:         * Scan slots, and acknowledge the interrupt if necessary first
        !           670:         */
        !           671:        for (i = 0; i < TS102_NUM_SLOTS; i++) {
        !           672:                td = &sc->sc_slot[i];
        !           673:                intreg = &intregs[i];
        !           674:                *intreg = TSLOT_READ(td, TS102_REG_CARD_A_INT);
        !           675:
        !           676:                /*
        !           677:                 * Acknowledge all interrupt situations at once, even if they
        !           678:                 * did not occur.
        !           679:                 */
        !           680:                if ((*intreg & (TS102_CARD_INT_STATUS_IRQ |
        !           681:                    TS102_CARD_INT_STATUS_WP_STATUS_CHANGED |
        !           682:                    TS102_CARD_INT_STATUS_BATTERY_STATUS_CHANGED |
        !           683:                    TS102_CARD_INT_STATUS_CARDDETECT_STATUS_CHANGED)) != 0) {
        !           684:                        rc = 1;
        !           685:                        TSLOT_WRITE(td, TS102_REG_CARD_A_INT, *intreg |
        !           686:                            TS102_CARD_INT_RQST_IRQ |
        !           687:                            TS102_CARD_INT_RQST_WP_STATUS_CHANGED |
        !           688:                            TS102_CARD_INT_RQST_BATTERY_STATUS_CHANGED |
        !           689:                            TS102_CARD_INT_RQST_CARDDETECT_STATUS_CHANGED);
        !           690:                }
        !           691:        }
        !           692:
        !           693:        /*
        !           694:         * Invoke the interrupt handler for each slot
        !           695:         */
        !           696:        for (i = 0; i < TS102_NUM_SLOTS; i++) {
        !           697:                td = &sc->sc_slot[i];
        !           698:                intreg = &intregs[i];
        !           699:
        !           700:                if ((*intreg & (TS102_CARD_INT_STATUS_IRQ |
        !           701:                    TS102_CARD_INT_STATUS_WP_STATUS_CHANGED |
        !           702:                    TS102_CARD_INT_STATUS_BATTERY_STATUS_CHANGED |
        !           703:                    TS102_CARD_INT_STATUS_CARDDETECT_STATUS_CHANGED)) != 0)
        !           704:                        tslot_slot_intr(td, *intreg);
        !           705:        }
        !           706:
        !           707:        return (rc);
        !           708: }
        !           709:
        !           710: void
        !           711: tslot_queue_event(struct tslot_softc *sc, int slot)
        !           712: {
        !           713:        int s;
        !           714:
        !           715:        s = splhigh();
        !           716:        sc->sc_events |= (1 << slot);
        !           717:        splx(s);
        !           718:        wakeup(&sc->sc_events);
        !           719: }
        !           720:
        !           721: void
        !           722: tslot_slot_intr(struct tslot_data *td, int intreg)
        !           723: {
        !           724:        struct tslot_softc *sc = td->td_parent;
        !           725:        int status, sockstat;
        !           726:
        !           727:        status = TSLOT_READ(td, TS102_REG_CARD_A_STS);
        !           728: #ifdef TSLOT_DEBUG
        !           729:        printf("%s: interrupt on socket %d ir %x sts %x\n",
        !           730:            sc->sc_dev.dv_xname, td->td_slot, intreg, status);
        !           731: #endif
        !           732:
        !           733:        sockstat = td->td_status;
        !           734:
        !           735:        /*
        !           736:         * The TS102 queues interrupt requests, and may trigger an interrupt
        !           737:         * for a condition the driver does not want to receive anymore (for
        !           738:         * example, after a card gets removed).
        !           739:         * Thus, only proceed if the driver is currently allowing a particular
        !           740:         * condition.
        !           741:         */
        !           742:
        !           743:        if ((intreg & TS102_CARD_INT_STATUS_CARDDETECT_STATUS_CHANGED) != 0 &&
        !           744:            (intreg & TS102_CARD_INT_MASK_CARDDETECT_STATUS) != 0) {
        !           745:                tslot_queue_event(sc, td->td_slot);
        !           746: #ifdef TSLOT_DEBUG
        !           747:                printf("%s: slot %d status changed from %d to %d\n",
        !           748:                    sc->sc_dev.dv_xname, td->td_slot, sockstat, td->td_status);
        !           749: #endif
        !           750:                /*
        !           751:                 * Ignore extra interrupt bits, they are part of the change.
        !           752:                 */
        !           753:                return;
        !           754:        }
        !           755:
        !           756:        if ((intreg & TS102_CARD_INT_STATUS_IRQ) != 0 &&
        !           757:            (intreg & TS102_CARD_INT_MASK_IRQ) != 0) {
        !           758:                /* ignore interrupts if we have a pending state change */
        !           759:                if (sc->sc_events & (1 << td->td_slot))
        !           760:                        return;
        !           761:
        !           762:                if ((sockstat & TS_CARD) == 0) {
        !           763:                        printf("%s: spurious interrupt on slot %d isr %x\n",
        !           764:                            sc->sc_dev.dv_xname, td->td_slot, intreg);
        !           765:                        return;
        !           766:                }
        !           767:
        !           768:                if (td->td_intr != NULL) {
        !           769:                        /*
        !           770:                         * XXX There is no way to honour the interrupt handler
        !           771:                         * requested IPL level...
        !           772:                         */
        !           773:                        (*td->td_intr)(td->td_intrarg);
        !           774:                }
        !           775:        }
        !           776: }
        !           777:
        !           778: void
        !           779: tslot_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih)
        !           780: {
        !           781:        struct tslot_data *td = (struct tslot_data *)pch;
        !           782:
        !           783:        td->td_intr = NULL;
        !           784:        td->td_intrarg = NULL;
        !           785: }
        !           786:
        !           787: const char *
        !           788: tslot_intr_string(pcmcia_chipset_handle_t pch, void *ih)
        !           789: {
        !           790:        if (ih == NULL)
        !           791:                return ("couldn't establish interrupt");
        !           792:        else
        !           793:                return ("");    /* nothing for now */
        !           794: }
        !           795:
        !           796:
        !           797: void *
        !           798: tslot_intr_establish(pcmcia_chipset_handle_t pch, struct pcmcia_function *pf,
        !           799:     int ipl, int (*handler)(void *), void *arg, char *xname)
        !           800: {
        !           801:        struct tslot_data *td = (struct tslot_data *)pch;
        !           802:
        !           803:        td->td_intr = handler;
        !           804:        td->td_intrarg = arg;
        !           805:
        !           806:        return (td);
        !           807: }

CVSweb