[BACK]Return to pxa2x0_pcic.c CVS log [TXT][DIR] Up to [local] / sys / arch / arm / xscale

Annotation of sys/arch/arm/xscale/pxa2x0_pcic.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: pxa2x0_pcic.c,v 1.17 2005/12/14 15:08:51 uwe Exp $    */
                      2:
                      3: /*
                      4:  * Copyright (c) 2005 Dale Rahn <drahn@openbsd.org>
                      5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  */
                     18:
                     19: #include <sys/param.h>
                     20: #include <sys/systm.h>
                     21: #include <sys/device.h>
                     22: #include <sys/kernel.h>
                     23: #include <sys/kthread.h>
                     24: #include <sys/malloc.h>
                     25: #include <uvm/uvm.h>
                     26:
                     27: #include <machine/bus.h>
                     28: #include <machine/intr.h>
                     29:
                     30: #include <dev/pcmcia/pcmciareg.h>
                     31: #include <dev/pcmcia/pcmciavar.h>
                     32: #include <dev/pcmcia/pcmciachip.h>
                     33:
                     34: #include <arm/xscale/pxa2x0reg.h>
                     35: #include <arm/xscale/pxa2x0var.h>
                     36: #include <arm/xscale/pxa2x0_gpio.h>
                     37: #include <arm/xscale/pxapcicvar.h>
                     38:
                     39: int    pxapcic_print(void *, const char *);
                     40: int    pxapcic_submatch(struct device *, void *, void *);
                     41:
                     42: void   pxapcic_create_event_thread(void *);
                     43: void    pxapcic_event_thread(void *);
                     44: void   pxapcic_event_process(struct pxapcic_socket *);
                     45: void   pxapcic_attach_card(struct pxapcic_socket *);
                     46: void   pxapcic_detach_card(struct pxapcic_socket *, int);
                     47: int    pxapcic_intr(void *);
                     48:
                     49: int    pxapcic_mem_alloc(pcmcia_chipset_handle_t, bus_size_t,
                     50:     struct pcmcia_mem_handle *);
                     51: void   pxapcic_mem_free(pcmcia_chipset_handle_t,
                     52:     struct pcmcia_mem_handle *);
                     53: int    pxapcic_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t,
                     54:     bus_size_t, struct pcmcia_mem_handle *, bus_size_t *, int *);
                     55: void   pxapcic_mem_unmap(pcmcia_chipset_handle_t, int);
                     56:
                     57: int    pxapcic_io_alloc(pcmcia_chipset_handle_t, bus_addr_t,
                     58:     bus_size_t, bus_size_t, struct pcmcia_io_handle *);
                     59: void   pxapcic_io_free(pcmcia_chipset_handle_t,
                     60:     struct pcmcia_io_handle *);
                     61: int    pxapcic_io_map(pcmcia_chipset_handle_t, int,
                     62:     bus_addr_t, bus_size_t, struct pcmcia_io_handle *, int *);
                     63: void   pxapcic_io_unmap(pcmcia_chipset_handle_t, int);
                     64:
                     65: void   *pxapcic_intr_establish(pcmcia_chipset_handle_t,
                     66:     struct pcmcia_function *, int, int (*)(void *), void *, char *);
                     67: void   pxapcic_intr_disestablish(pcmcia_chipset_handle_t, void *);
                     68: const char *pxapcic_intr_string(pcmcia_chipset_handle_t, void *);
                     69:
                     70: void   pxapcic_socket_setup(struct pxapcic_socket *);
                     71: void   pxapcic_socket_enable(pcmcia_chipset_handle_t);
                     72: void   pxapcic_socket_disable(pcmcia_chipset_handle_t);
                     73:
                     74: struct cfdriver pxapcic_cd = {
                     75:        NULL, "pxapcic", DV_DULL
                     76: };
                     77:
                     78: /*
                     79:  * PCMCIA chipset methods
                     80:  */
                     81: struct pcmcia_chip_functions pxapcic_pcmcia_functions = {
                     82:        pxapcic_mem_alloc,
                     83:        pxapcic_mem_free,
                     84:        pxapcic_mem_map,
                     85:        pxapcic_mem_unmap,
                     86:
                     87:        pxapcic_io_alloc,
                     88:        pxapcic_io_free,
                     89:        pxapcic_io_map,
                     90:        pxapcic_io_unmap,
                     91:
                     92:        pxapcic_intr_establish,
                     93:        pxapcic_intr_disestablish,
                     94:        pxapcic_intr_string,
                     95:
                     96:        pxapcic_socket_enable,
                     97:        pxapcic_socket_disable,
                     98: };
                     99:
                    100: /*
                    101:  * PCMCIA Helpers
                    102:  */
                    103:
                    104: int
                    105: pxapcic_mem_alloc(pcmcia_chipset_handle_t pch, bus_size_t size,
                    106:     struct pcmcia_mem_handle *pmh)
                    107: {
                    108:        struct pxapcic_socket *so = pch;
                    109:
                    110:        /* All we need is the bus space tag */
                    111:        memset(pmh, 0, sizeof(*pmh));
                    112:        pmh->memt = so->sc->sc_iot;
                    113:        return (0);
                    114: }
                    115:
                    116: void
                    117: pxapcic_mem_free(pcmcia_chipset_handle_t pch, struct pcmcia_mem_handle *pmh)
                    118: {
                    119: }
                    120:
                    121: int
                    122: pxapcic_mem_map(pcmcia_chipset_handle_t pch, int kind, bus_addr_t card_addr,
                    123:     bus_size_t size, struct pcmcia_mem_handle *pmh, bus_size_t *offsetp,
                    124:     int *windowp)
                    125: {
                    126:        struct pxapcic_socket *so = pch;
                    127:        int error;
                    128:        bus_addr_t pa;
                    129:
                    130:        pa = trunc_page(card_addr);
                    131:        *offsetp = card_addr - pa;
                    132:        size = round_page(card_addr + size) - pa;
                    133:        pmh->realsize = size;
                    134:
                    135: #define PXA2X0_SOCKET_OFFSET   (PXA2X0_PCMCIA_SLOT1-PXA2X0_PCMCIA_SLOT0)
                    136: #define PXAPCIC_ATTR_OFFSET    0x08000000
                    137: #define PXAPCIC_COMMON_OFFSET  0x0C000000
                    138:
                    139:        pa += PXA2X0_PCMCIA_SLOT0;
                    140:        pa += PXA2X0_SOCKET_OFFSET * so->socket;
                    141:
                    142:        switch (kind & ~PCMCIA_WIDTH_MEM_MASK) {
                    143:        case PCMCIA_MEM_ATTR:
                    144:                pa += PXAPCIC_ATTR_OFFSET;
                    145:                break;
                    146:        case PCMCIA_MEM_COMMON:
                    147:                pa += PXAPCIC_COMMON_OFFSET;
                    148:                break;
                    149:        default:
                    150:                panic("pxapcic_mem_map: bogus kind");
                    151:        }
                    152:
                    153:        error = bus_space_map(so->sc->sc_iot, pa, size, 0, &pmh->memh);
                    154:        if (! error)
                    155:                *windowp = (int)pmh->memh;
                    156:        return (error);
                    157: }
                    158:
                    159: void
                    160: pxapcic_mem_unmap(pcmcia_chipset_handle_t pch, int window)
                    161: {
                    162:         struct pxapcic_socket *so = pch;
                    163:
                    164:         bus_space_unmap(so->sc->sc_iot, (bus_addr_t)window, 4096); /* XXX */
                    165: }
                    166:
                    167: int
                    168: pxapcic_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start,
                    169:     bus_size_t size, bus_size_t align, struct pcmcia_io_handle *pih)
                    170: {
                    171:         struct pxapcic_socket *so = pch;
                    172:         int error;
                    173:         bus_addr_t pa;
                    174:
                    175:         memset(pih, 0, sizeof(*pih));
                    176:         pih->iot = so->sc->sc_iot;
                    177:         pih->addr = start;
                    178:         pih->size = size;
                    179:
                    180:         pa = pih->addr;
                    181:         pa += PXA2X0_PCMCIA_SLOT0;
                    182:         pa += PXA2X0_SOCKET_OFFSET * so->socket;
                    183:
                    184: #if 0
                    185:         printf("pxapcic_io_alloc: %x %x\n", (unsigned int)pa,
                    186:                  (unsigned int)size);
                    187: #endif
                    188:         /* XXX Are we ignoring alignment constraints? */
                    189:         error = bus_space_map(so->sc->sc_iot, pa, size, 0, &pih->ioh);
                    190:
                    191:         return (error);
                    192: }
                    193:
                    194: void
                    195: pxapcic_io_free(pcmcia_chipset_handle_t pch, struct pcmcia_io_handle *pih)
                    196: {
                    197:         struct pxapcic_socket *so = pch;
                    198:
                    199:         bus_space_unmap(so->sc->sc_iot, pih->ioh, pih->size);
                    200: }
                    201:
                    202: int
                    203: pxapcic_io_map(pcmcia_chipset_handle_t pch, int width, bus_addr_t offset,
                    204:     bus_size_t size, struct pcmcia_io_handle *pih, int *windowp)
                    205: {
                    206:         return (0);
                    207: }
                    208:
                    209: void pxapcic_io_unmap(pcmcia_chipset_handle_t pch, int window)
                    210: {
                    211: }
                    212:
                    213: void *
                    214: pxapcic_intr_establish(pcmcia_chipset_handle_t pch,
                    215:     struct pcmcia_function *pf, int ipl, int (*fct)(void *), void *arg,
                    216:     char *name)
                    217: {
                    218:         struct pxapcic_socket *so = pch;
                    219:         /* XXX need to check if something should be done here */
                    220:
                    221:        return (pxa2x0_gpio_intr_establish(so->irqpin, IST_EDGE_FALLING,
                    222:            ipl, fct, arg, name));
                    223: }
                    224:
                    225: void
                    226: pxapcic_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih)
                    227: {
                    228:        pxa2x0_gpio_intr_disestablish(ih);
                    229: }
                    230:
                    231: const char *
                    232: pxapcic_intr_string(pcmcia_chipset_handle_t pch, void *ih)
                    233: {
                    234:        return (pxa2x0_gpio_intr_string(ih));
                    235: }
                    236:
                    237: void
                    238: pxapcic_socket_enable(pcmcia_chipset_handle_t pch)
                    239: {
                    240:        struct pxapcic_socket *so = pch;
                    241:        int i;
                    242:
                    243:        /* Power down the card and socket before setting the voltage. */
                    244:        so->pcictag->write(so, PXAPCIC_CARD_POWER, PXAPCIC_POWER_OFF);
                    245:        so->pcictag->set_power(so, PXAPCIC_POWER_OFF);
                    246:
                    247:        /*
                    248:         * Wait 300ms until power fails (Tpf).  Then, wait 100ms since
                    249:         * we are changing Vcc (Toff).
                    250:         */
                    251:        delay((300 + 100) * 1000);
                    252:
                    253:        /* Power up the socket and card at appropriate voltage. */
                    254:        if (so->power_capability & PXAPCIC_POWER_5V) {
                    255:                so->pcictag->set_power(so, PXAPCIC_POWER_5V);
                    256:                so->pcictag->write(so, PXAPCIC_CARD_POWER,
                    257:                    PXAPCIC_POWER_5V);
                    258:        } else {
                    259:                so->pcictag->set_power(so, PXAPCIC_POWER_3V);
                    260:                so->pcictag->write(so, PXAPCIC_CARD_POWER,
                    261:                    PXAPCIC_POWER_3V);
                    262:        }
                    263:
                    264:        /*
                    265:         * Wait 100ms until power raise (Tpr) and 20ms to become
                    266:         * stable (Tsu(Vcc)).
                    267:         *
                    268:         * Some machines require some more time to be settled
                    269:         * (another 200ms is added here).
                    270:         */
                    271:        delay((100 + 20 + 200) * 1000);
                    272:
                    273:        /* Hold RESET at least 10us. */
                    274:        so->pcictag->write(so, PXAPCIC_CARD_RESET, 1);
                    275:        delay(10);
                    276:        /* XXX wrong, but lets TE-CF100 cards work for some reason. */
                    277:        delay(3000);
                    278:        so->pcictag->write(so, PXAPCIC_CARD_RESET, 0);
                    279:
                    280:        /* Wait 20ms as per PC Card standard (r2.01) section 4.3.6. */
                    281:        delay(20000);
                    282:
                    283:        /* Wait for the card to become ready. */
                    284:        for (i = 0; i < 10000; i++) {
                    285:                if (so->pcictag->read(so, PXAPCIC_CARD_READY))
                    286:                        break;
                    287:                delay(500);
                    288: #ifdef PCICDEBUG
                    289:                if ((i>5000) && (i%100 == 99))
                    290:                        printf(".");
                    291: #endif
                    292:        }
                    293: }
                    294:
                    295: void
                    296: pxapcic_socket_disable(pcmcia_chipset_handle_t pch)
                    297: {
                    298:        struct pxapcic_socket *so = pch;
                    299:
                    300: #ifdef PCICDEBUG
                    301:        printf("pxapcic_socket_disable: socket %d\n", so->socket);
                    302: #endif
                    303:
                    304:        /* Power down the card and socket. */
                    305:        so->pcictag->write(so, PXAPCIC_CARD_POWER, PXAPCIC_POWER_OFF);
                    306:        so->pcictag->set_power(so, PXAPCIC_POWER_OFF);
                    307: }
                    308:
                    309: /*
                    310:  * Attachment and initialization
                    311:  */
                    312:
                    313: int
                    314: pxapcic_print(void *aux, const char *name)
                    315: {
                    316:        return (UNCONF);
                    317: }
                    318:
                    319: int
                    320: pxapcic_submatch(struct device *parent, void *match, void *aux)
                    321: {
                    322:        struct cfdata *cf = match;
                    323:
                    324:        return ((*cf->cf_attach->ca_match)(parent, cf, aux));
                    325: }
                    326:
                    327: void
                    328: pxapcic_attach(struct pxapcic_softc *sc,
                    329:     void (*socket_setup_hook)(struct pxapcic_socket *))
                    330: {
                    331:        struct pcmciabus_attach_args paa;
                    332:        struct pxapcic_socket *so;
                    333:        int i;
                    334:
                    335:        printf(": %d slot%s\n", sc->sc_nslots, sc->sc_nslots==1 ? "" : "s");
                    336:
                    337:        if (bus_space_map(sc->sc_iot, PXA2X0_MEMCTL_BASE, PXA2X0_MEMCTL_SIZE,
                    338:            0, &sc->sc_memctl_ioh)) {
                    339:                printf("%s: failed to map MEMCTL\n", sc->sc_dev.dv_xname);
                    340:                return;
                    341:        }
                    342:
                    343:        /* Clear CIT (card present) and set NOS correctly. */
                    344:        bus_space_write_4(sc->sc_iot, sc->sc_memctl_ioh, MEMCTL_MECR,
                    345:            sc->sc_nslots == 2 ? MECR_NOS : 0);
                    346:
                    347:        /* zaurus: configure slot 1 first to make internal drive be wd0. */
                    348:        for (i = sc->sc_nslots-1; i >= 0; i--) {
                    349:                so = &sc->sc_socket[i];
                    350:                so->sc = sc;
                    351:                so->socket = i;
                    352:                so->flags = 0;
                    353:
                    354:                socket_setup_hook(so);
                    355:
                    356:                paa.paa_busname = "pcmcia";
                    357:                paa.pct = (pcmcia_chipset_tag_t)&pxapcic_pcmcia_functions;
                    358:                paa.pch = (pcmcia_chipset_handle_t)so;
                    359:                paa.iobase = 0;
                    360:                paa.iosize = 0x4000000;
                    361:
                    362:                so->pcmcia = config_found_sm(&sc->sc_dev, &paa,
                    363:                    pxapcic_print, pxapcic_submatch);
                    364:
                    365:                pxa2x0_gpio_set_function(sc->sc_irqpin[i], GPIO_IN);
                    366:                pxa2x0_gpio_set_function(sc->sc_irqcfpin[i], GPIO_IN);
                    367:
                    368:                /* Card slot interrupt */
                    369:                so->irq = pxa2x0_gpio_intr_establish(sc->sc_irqcfpin[i],
                    370:                    IST_EDGE_BOTH, IPL_BIO /* XXX */, pxapcic_intr, so,
                    371:                    sc->sc_dev.dv_xname);
                    372:
                    373:                /* GPIO pin for interrupt */
                    374:                so->irqpin = sc->sc_irqpin[i];
                    375:
                    376: #ifdef DO_CONFIG_PENDING
                    377:                config_pending_incr();
                    378: #endif
                    379:                kthread_create_deferred(pxapcic_create_event_thread, so);
                    380:        }
                    381: }
                    382:
                    383: /*
                    384:  * Card slot interrupt handling
                    385:  */
                    386:
                    387: int
                    388: pxapcic_intr(void *arg)
                    389: {
                    390:         struct pxapcic_socket *so = arg;
                    391:
                    392:        so->pcictag->clear_intr(so);
                    393:         wakeup(so);
                    394:         return (1);
                    395: }
                    396:
                    397: /*
                    398:  * Event management
                    399:  */
                    400:
                    401: void
                    402: pxapcic_create_event_thread(void *arg)
                    403: {
                    404:        struct pxapcic_socket *sock = arg;
                    405:        struct pxapcic_softc *sc = sock->sc;
                    406:        u_int cs;
                    407:
                    408:        /* If there's a card there, attach it. */
                    409:        cs = sock->pcictag->read(sock, PXAPCIC_CARD_STATUS);
                    410:        if (cs == PXAPCIC_CARD_VALID)
                    411:                pxapcic_attach_card(sock);
                    412:
                    413:        if (kthread_create(pxapcic_event_thread, sock, &sock->event_thread,
                    414:             sc->sc_dev.dv_xname, sock->socket ? "1" : "0")) {
                    415:                printf("%s: unable to create event thread for %s\n",
                    416:                     sc->sc_dev.dv_xname,  sock->socket ? "1" : "0");
                    417:        }
                    418: #ifdef DO_CONFIG_PENDING
                    419:        config_pending_decr();
                    420: #endif
                    421: }
                    422:
                    423: void
                    424: pxapcic_event_thread(void *arg)
                    425: {
                    426:        struct pxapcic_socket *sock = arg;
                    427:        u_int cs;
                    428:        int present;
                    429:
                    430:        while (sock->sc->sc_shutdown == 0) {
                    431:
                    432:                (void) tsleep(sock, PWAIT, "pxapcicev", 0);
                    433:
                    434:                /* sleep .25s to avoid chattering interrupts */
                    435:                (void) tsleep((caddr_t)sock, PWAIT,
                    436:                    "pxapcicss", hz/4);
                    437:
                    438:                cs = sock->pcictag->read(sock, PXAPCIC_CARD_STATUS);
                    439:
                    440:                present = sock->flags & PXAPCIC_FLAG_CARDP;
                    441:
                    442:                if ((cs == PXAPCIC_CARD_VALID) == (present == 1))
                    443:                        continue; /* state unchanged */
                    444:
                    445:                /* XXX Do both? */
                    446:                pxapcic_event_process(sock);
                    447:        }
                    448:
                    449:        sock->event_thread = NULL;
                    450:
                    451:        /* In case parent is waiting for us to exit. */
                    452:        wakeup(sock->sc);
                    453:
                    454:        kthread_exit(0);
                    455: }
                    456:
                    457: void
                    458: pxapcic_event_process(struct pxapcic_socket *sock)
                    459: {
                    460:        u_int cs;
                    461:
                    462:        cs = sock->pcictag->read(sock, PXAPCIC_CARD_STATUS);
                    463:
                    464:        if (cs == PXAPCIC_CARD_VALID) {
                    465:                if (!(sock->flags & PXAPCIC_FLAG_CARDP))
                    466:                        pxapcic_attach_card(sock);
                    467:        } else {
                    468:                if ((sock->flags & PXAPCIC_FLAG_CARDP))
                    469:                        pxapcic_detach_card(sock, DETACH_FORCE);
                    470:        }
                    471: }
                    472:
                    473: void
                    474: pxapcic_attach_card(struct pxapcic_socket *h)
                    475: {
                    476:        struct pxapcic_softc *sc = h->sc;
                    477:        u_int32_t rv;
                    478:
                    479:        if (h->flags & PXAPCIC_FLAG_CARDP)
                    480:                panic("pcic_attach_card: already attached");
                    481:        h->flags |= PXAPCIC_FLAG_CARDP;
                    482:
                    483:        /* Set CIT if any card is present. */
                    484:        rv = bus_space_read_4(sc->sc_iot, sc->sc_memctl_ioh, MEMCTL_MECR);
                    485:        bus_space_write_4(sc->sc_iot, sc->sc_memctl_ioh, MEMCTL_MECR,
                    486:            rv | MECR_CIT);
                    487:
                    488:        /* call the MI attach function */
                    489:        pcmcia_card_attach(h->pcmcia);
                    490: }
                    491:
                    492: void
                    493: pxapcic_detach_card(struct pxapcic_socket *h, int flags)
                    494: {
                    495:        struct pxapcic_softc *sc = h->sc;
                    496:        u_int32_t rv;
                    497:        int i;
                    498:
                    499:        if (h->flags & PXAPCIC_FLAG_CARDP) {
                    500:                h->flags &= ~PXAPCIC_FLAG_CARDP;
                    501:
                    502:                /* call the MI detach function */
                    503:                pcmcia_card_detach(h->pcmcia, flags);
                    504:        }
                    505:
                    506:        /* Clear CIT if no other card is present. */
                    507:        for (i = 0; i < sc->sc_nslots; i++)
                    508:                if (sc->sc_socket[i].flags & PXAPCIC_FLAG_CARDP)
                    509:                        return;
                    510:        rv = bus_space_read_4(sc->sc_iot, sc->sc_memctl_ioh, MEMCTL_MECR);
                    511:        bus_space_write_4(sc->sc_iot, sc->sc_memctl_ioh, MEMCTL_MECR,
                    512:            rv & ~MECR_CIT);
                    513: }

CVSweb