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

Annotation of sys/dev/sdmmc/sdhc.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: sdhc.c,v 1.21 2007/05/31 23:37:21 uwe Exp $   */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2006 Uwe Stuehler <uwe@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: /*
        !            20:  * SD Host Controller driver based on the SD Host Controller Standard
        !            21:  * Simplified Specification Version 1.00 (www.sdcard.com).
        !            22:  */
        !            23:
        !            24: #include <sys/param.h>
        !            25: #include <sys/device.h>
        !            26: #include <sys/kernel.h>
        !            27: #include <sys/kthread.h>
        !            28: #include <sys/malloc.h>
        !            29: #include <sys/systm.h>
        !            30:
        !            31: #include <dev/sdmmc/sdhcreg.h>
        !            32: #include <dev/sdmmc/sdhcvar.h>
        !            33: #include <dev/sdmmc/sdmmcchip.h>
        !            34: #include <dev/sdmmc/sdmmcreg.h>
        !            35: #include <dev/sdmmc/sdmmcvar.h>
        !            36:
        !            37: #define SDHC_COMMAND_TIMEOUT   hz
        !            38: #define SDHC_BUFFER_TIMEOUT    hz
        !            39: #define SDHC_TRANSFER_TIMEOUT  hz
        !            40:
        !            41: struct sdhc_host {
        !            42:        struct sdhc_softc *sc;          /* host controller device */
        !            43:        struct device *sdmmc;           /* generic SD/MMC device */
        !            44:        bus_space_tag_t iot;            /* host register set tag */
        !            45:        bus_space_handle_t ioh;         /* host register set handle */
        !            46:        u_int clkbase;                  /* base clock frequency in KHz */
        !            47:        int maxblklen;                  /* maximum block length */
        !            48:        int flags;                      /* flags for this host */
        !            49:        u_int32_t ocr;                  /* OCR value from capabilities */
        !            50:        u_int8_t regs[14];              /* host controller state */
        !            51:        u_int16_t intr_status;          /* soft interrupt status */
        !            52:        u_int16_t intr_error_status;    /* soft error status */
        !            53: };
        !            54:
        !            55: #define HDEVNAME(hp)   ((hp)->sc->sc_dev.dv_xname)
        !            56:
        !            57: /* flag values */
        !            58: #define SHF_USE_DMA            0x0001
        !            59:
        !            60: #define HREAD1(hp, reg)                                                        \
        !            61:        (bus_space_read_1((hp)->iot, (hp)->ioh, (reg)))
        !            62: #define HREAD2(hp, reg)                                                        \
        !            63:        (bus_space_read_2((hp)->iot, (hp)->ioh, (reg)))
        !            64: #define HREAD4(hp, reg)                                                        \
        !            65:        (bus_space_read_4((hp)->iot, (hp)->ioh, (reg)))
        !            66: #define HWRITE1(hp, reg, val)                                          \
        !            67:        bus_space_write_1((hp)->iot, (hp)->ioh, (reg), (val))
        !            68: #define HWRITE2(hp, reg, val)                                          \
        !            69:        bus_space_write_2((hp)->iot, (hp)->ioh, (reg), (val))
        !            70: #define HWRITE4(hp, reg, val)                                          \
        !            71:        bus_space_write_4((hp)->iot, (hp)->ioh, (reg), (val))
        !            72: #define HCLR1(hp, reg, bits)                                           \
        !            73:        HWRITE1((hp), (reg), HREAD1((hp), (reg)) & ~(bits))
        !            74: #define HCLR2(hp, reg, bits)                                           \
        !            75:        HWRITE2((hp), (reg), HREAD2((hp), (reg)) & ~(bits))
        !            76: #define HSET1(hp, reg, bits)                                           \
        !            77:        HWRITE1((hp), (reg), HREAD1((hp), (reg)) | (bits))
        !            78: #define HSET2(hp, reg, bits)                                           \
        !            79:        HWRITE2((hp), (reg), HREAD2((hp), (reg)) | (bits))
        !            80:
        !            81: int    sdhc_host_reset(sdmmc_chipset_handle_t);
        !            82: u_int32_t sdhc_host_ocr(sdmmc_chipset_handle_t);
        !            83: int    sdhc_host_maxblklen(sdmmc_chipset_handle_t);
        !            84: int    sdhc_card_detect(sdmmc_chipset_handle_t);
        !            85: int    sdhc_bus_power(sdmmc_chipset_handle_t, u_int32_t);
        !            86: int    sdhc_bus_clock(sdmmc_chipset_handle_t, int);
        !            87: void   sdhc_card_intr_mask(sdmmc_chipset_handle_t, int);
        !            88: void   sdhc_card_intr_ack(sdmmc_chipset_handle_t);
        !            89: void   sdhc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *);
        !            90: int    sdhc_start_command(struct sdhc_host *, struct sdmmc_command *);
        !            91: int    sdhc_wait_state(struct sdhc_host *, u_int32_t, u_int32_t);
        !            92: int    sdhc_soft_reset(struct sdhc_host *, int);
        !            93: int    sdhc_wait_intr(struct sdhc_host *, int, int);
        !            94: void   sdhc_transfer_data(struct sdhc_host *, struct sdmmc_command *);
        !            95: void   sdhc_read_data(struct sdhc_host *, u_char *, int);
        !            96: void   sdhc_write_data(struct sdhc_host *, u_char *, int);
        !            97:
        !            98: #ifdef SDHC_DEBUG
        !            99: int sdhcdebug = 0;
        !           100: #define DPRINTF(n,s)   do { if ((n) <= sdhcdebug) printf s; } while (0)
        !           101: void   sdhc_dump_regs(struct sdhc_host *);
        !           102: #else
        !           103: #define DPRINTF(n,s)   do {} while(0)
        !           104: #endif
        !           105:
        !           106: struct sdmmc_chip_functions sdhc_functions = {
        !           107:        /* host controller reset */
        !           108:        sdhc_host_reset,
        !           109:        /* host controller capabilities */
        !           110:        sdhc_host_ocr,
        !           111:        sdhc_host_maxblklen,
        !           112:        /* card detection */
        !           113:        sdhc_card_detect,
        !           114:        /* bus power and clock frequency */
        !           115:        sdhc_bus_power,
        !           116:        sdhc_bus_clock,
        !           117:        /* command execution */
        !           118:        sdhc_exec_command,
        !           119:        /* card interrupt */
        !           120:        sdhc_card_intr_mask,
        !           121:        sdhc_card_intr_ack
        !           122: };
        !           123:
        !           124: struct cfdriver sdhc_cd = {
        !           125:        NULL, "sdhc", DV_DULL
        !           126: };
        !           127:
        !           128: /*
        !           129:  * Called by attachment driver.  For each SD card slot there is one SD
        !           130:  * host controller standard register set. (1.3)
        !           131:  */
        !           132: int
        !           133: sdhc_host_found(struct sdhc_softc *sc, bus_space_tag_t iot,
        !           134:     bus_space_handle_t ioh, bus_size_t iosize, int usedma)
        !           135: {
        !           136:        struct sdmmcbus_attach_args saa;
        !           137:        struct sdhc_host *hp;
        !           138:        u_int32_t caps;
        !           139:        int error = 1;
        !           140: #ifdef SDHC_DEBUG
        !           141:        u_int16_t version;
        !           142:
        !           143:        version = bus_space_read_2(iot, ioh, SDHC_HOST_CTL_VERSION);
        !           144:        printf("%s: SD Host Specification/Vendor Version ",
        !           145:            sc->sc_dev.dv_xname);
        !           146:        switch(SDHC_SPEC_VERSION(version)) {
        !           147:        case 0x00:
        !           148:                printf("1.0/%u\n", SDHC_VENDOR_VERSION(version));
        !           149:                break;
        !           150:        default:
        !           151:                printf(">1.0/%u\n", SDHC_VENDOR_VERSION(version));
        !           152:                break;
        !           153:        }
        !           154: #endif
        !           155:
        !           156:        /* Allocate one more host structure. */
        !           157:        sc->sc_nhosts++;
        !           158:        MALLOC(hp, struct sdhc_host *, sizeof(struct sdhc_host),
        !           159:            M_DEVBUF, M_WAITOK);
        !           160:        sc->sc_host[sc->sc_nhosts - 1] = hp;
        !           161:
        !           162:        /* Fill in the new host structure. */
        !           163:        bzero(hp, sizeof(struct sdhc_host));
        !           164:        hp->sc = sc;
        !           165:        hp->iot = iot;
        !           166:        hp->ioh = ioh;
        !           167:
        !           168:        /*
        !           169:         * Reset the host controller and enable interrupts.
        !           170:         */
        !           171:        (void)sdhc_host_reset(hp);
        !           172:
        !           173:        /* Determine host capabilities. */
        !           174:        caps = HREAD4(hp, SDHC_CAPABILITIES);
        !           175:
        !           176:        /* Use DMA if the host system and the controller support it. */
        !           177:        if (usedma && ISSET(caps, SDHC_DMA_SUPPORT))
        !           178:                SET(hp->flags, SHF_USE_DMA);
        !           179:
        !           180:        /*
        !           181:         * Determine the base clock frequency. (2.2.24)
        !           182:         */
        !           183:        if (SDHC_BASE_FREQ_KHZ(caps) != 0)
        !           184:                hp->clkbase = SDHC_BASE_FREQ_KHZ(caps);
        !           185:        if (hp->clkbase == 0) {
        !           186:                /* The attachment driver must tell us. */
        !           187:                printf("%s: base clock frequency unknown\n",
        !           188:                    sc->sc_dev.dv_xname);
        !           189:                goto err;
        !           190:        } else if (hp->clkbase < 10000 || hp->clkbase > 63000) {
        !           191:                /* SDHC 1.0 supports only 10-63 MHz. */
        !           192:                printf("%s: base clock frequency out of range: %u MHz\n",
        !           193:                    sc->sc_dev.dv_xname, hp->clkbase / 1000);
        !           194:                goto err;
        !           195:        }
        !           196:
        !           197:        /*
        !           198:         * XXX Set the data timeout counter value according to
        !           199:         * capabilities. (2.2.15)
        !           200:         */
        !           201:
        !           202:        /*
        !           203:         * Determine SD bus voltage levels supported by the controller.
        !           204:         */
        !           205:        if (ISSET(caps, SDHC_VOLTAGE_SUPP_1_8V))
        !           206:                SET(hp->ocr, MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V);
        !           207:        if (ISSET(caps, SDHC_VOLTAGE_SUPP_3_0V))
        !           208:                SET(hp->ocr, MMC_OCR_2_9V_3_0V | MMC_OCR_3_0V_3_1V);
        !           209:        if (ISSET(caps, SDHC_VOLTAGE_SUPP_3_3V))
        !           210:                SET(hp->ocr, MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V);
        !           211:
        !           212:        /*
        !           213:         * Determine the maximum block length supported by the host
        !           214:         * controller. (2.2.24)
        !           215:         */
        !           216:        switch((caps >> SDHC_MAX_BLK_LEN_SHIFT) & SDHC_MAX_BLK_LEN_MASK) {
        !           217:        case SDHC_MAX_BLK_LEN_512:
        !           218:                hp->maxblklen = 512;
        !           219:                break;
        !           220:        case SDHC_MAX_BLK_LEN_1024:
        !           221:                hp->maxblklen = 1024;
        !           222:                break;
        !           223:        case SDHC_MAX_BLK_LEN_2048:
        !           224:                hp->maxblklen = 2048;
        !           225:                break;
        !           226:        default:
        !           227:                hp->maxblklen = 1;
        !           228:                break;
        !           229:        }
        !           230:
        !           231:        /*
        !           232:         * Attach the generic SD/MMC bus driver.  (The bus driver must
        !           233:         * not invoke any chipset functions before it is attached.)
        !           234:         */
        !           235:        bzero(&saa, sizeof(saa));
        !           236:        saa.saa_busname = "sdmmc";
        !           237:        saa.sct = &sdhc_functions;
        !           238:        saa.sch = hp;
        !           239:
        !           240:        hp->sdmmc = config_found(&sc->sc_dev, &saa, NULL);
        !           241:        if (hp->sdmmc == NULL) {
        !           242:                error = 0;
        !           243:                goto err;
        !           244:        }
        !           245:
        !           246:        return 0;
        !           247:
        !           248: err:
        !           249:        FREE(hp, M_DEVBUF);
        !           250:        sc->sc_host[sc->sc_nhosts - 1] = NULL;
        !           251:        sc->sc_nhosts--;
        !           252:        return (error);
        !           253: }
        !           254:
        !           255: /*
        !           256:  * Power hook established by or called from attachment driver.
        !           257:  */
        !           258: void
        !           259: sdhc_power(int why, void *arg)
        !           260: {
        !           261:        struct sdhc_softc *sc = arg;
        !           262:        struct sdhc_host *hp;
        !           263:        int n, i;
        !           264:
        !           265:        switch(why) {
        !           266:        case PWR_STANDBY:
        !           267:        case PWR_SUSPEND:
        !           268:                /* XXX poll for command completion or suspend command
        !           269:                 * in progress */
        !           270:
        !           271:                /* Save the host controller state. */
        !           272:                for (n = 0; n < sc->sc_nhosts; n++) {
        !           273:                        hp = sc->sc_host[n];
        !           274:                        for (i = 0; i < sizeof hp->regs; i++)
        !           275:                                hp->regs[i] = HREAD1(hp, i);
        !           276:                }
        !           277:                break;
        !           278:
        !           279:        case PWR_RESUME:
        !           280:                /* Restore the host controller state. */
        !           281:                for (n = 0; n < sc->sc_nhosts; n++) {
        !           282:                        hp = sc->sc_host[n];
        !           283:                        (void)sdhc_host_reset(hp);
        !           284:                        for (i = 0; i < sizeof hp->regs; i++)
        !           285:                                HWRITE1(hp, i, hp->regs[i]);
        !           286:                }
        !           287:                break;
        !           288:        }
        !           289: }
        !           290:
        !           291: /*
        !           292:  * Shutdown hook established by or called from attachment driver.
        !           293:  */
        !           294: void
        !           295: sdhc_shutdown(void *arg)
        !           296: {
        !           297:        struct sdhc_softc *sc = arg;
        !           298:        struct sdhc_host *hp;
        !           299:        int i;
        !           300:
        !           301:        /* XXX chip locks up if we don't disable it before reboot. */
        !           302:        for (i = 0; i < sc->sc_nhosts; i++) {
        !           303:                hp = sc->sc_host[i];
        !           304:                (void)sdhc_host_reset(hp);
        !           305:        }
        !           306: }
        !           307:
        !           308: /*
        !           309:  * Reset the host controller.  Called during initialization, when
        !           310:  * cards are removed, upon resume, and during error recovery.
        !           311:  */
        !           312: int
        !           313: sdhc_host_reset(sdmmc_chipset_handle_t sch)
        !           314: {
        !           315:        struct sdhc_host *hp = sch;
        !           316:        u_int16_t imask;
        !           317:        int error;
        !           318:        int s;
        !           319:
        !           320:        s = splsdmmc();
        !           321:
        !           322:        /* Disable all interrupts. */
        !           323:        HWRITE2(hp, SDHC_NINTR_SIGNAL_EN, 0);
        !           324:
        !           325:        /*
        !           326:         * Reset the entire host controller and wait up to 100ms for
        !           327:         * the controller to clear the reset bit.
        !           328:         */
        !           329:        if ((error = sdhc_soft_reset(hp, SDHC_RESET_ALL)) != 0) {
        !           330:                splx(s);
        !           331:                return (error);
        !           332:        }
        !           333:
        !           334:        /* Set data timeout counter value to max for now. */
        !           335:        HWRITE1(hp, SDHC_TIMEOUT_CTL, SDHC_TIMEOUT_MAX);
        !           336:
        !           337:        /* Enable interrupts. */
        !           338:        imask = SDHC_CARD_REMOVAL | SDHC_CARD_INSERTION |
        !           339:            SDHC_BUFFER_READ_READY | SDHC_BUFFER_WRITE_READY |
        !           340:            SDHC_DMA_INTERRUPT | SDHC_BLOCK_GAP_EVENT |
        !           341:            SDHC_TRANSFER_COMPLETE | SDHC_COMMAND_COMPLETE;
        !           342:
        !           343:        HWRITE2(hp, SDHC_NINTR_STATUS_EN, imask);
        !           344:        HWRITE2(hp, SDHC_EINTR_STATUS_EN, SDHC_EINTR_STATUS_MASK);
        !           345:        HWRITE2(hp, SDHC_NINTR_SIGNAL_EN, imask);
        !           346:        HWRITE2(hp, SDHC_EINTR_SIGNAL_EN, SDHC_EINTR_SIGNAL_MASK);
        !           347:
        !           348:        splx(s);
        !           349:        return 0;
        !           350: }
        !           351:
        !           352: u_int32_t
        !           353: sdhc_host_ocr(sdmmc_chipset_handle_t sch)
        !           354: {
        !           355:        struct sdhc_host *hp = sch;
        !           356:        return hp->ocr;
        !           357: }
        !           358:
        !           359: int
        !           360: sdhc_host_maxblklen(sdmmc_chipset_handle_t sch)
        !           361: {
        !           362:        struct sdhc_host *hp = sch;
        !           363:        return hp->maxblklen;
        !           364: }
        !           365:
        !           366: /*
        !           367:  * Return non-zero if the card is currently inserted.
        !           368:  */
        !           369: int
        !           370: sdhc_card_detect(sdmmc_chipset_handle_t sch)
        !           371: {
        !           372:        struct sdhc_host *hp = sch;
        !           373:        return ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_CARD_INSERTED) ?
        !           374:            1 : 0;
        !           375: }
        !           376:
        !           377: /*
        !           378:  * Set or change SD bus voltage and enable or disable SD bus power.
        !           379:  * Return zero on success.
        !           380:  */
        !           381: int
        !           382: sdhc_bus_power(sdmmc_chipset_handle_t sch, u_int32_t ocr)
        !           383: {
        !           384:        struct sdhc_host *hp = sch;
        !           385:        u_int8_t vdd;
        !           386:        int s;
        !           387:
        !           388:        s = splsdmmc();
        !           389:
        !           390:        /*
        !           391:         * Disable bus power before voltage change.
        !           392:         */
        !           393:        HWRITE1(hp, SDHC_POWER_CTL, 0);
        !           394:
        !           395:        /* If power is disabled, reset the host and return now. */
        !           396:        if (ocr == 0) {
        !           397:                splx(s);
        !           398:                (void)sdhc_host_reset(hp);
        !           399:                return 0;
        !           400:        }
        !           401:
        !           402:        /*
        !           403:         * Select the maximum voltage according to capabilities.
        !           404:         */
        !           405:        ocr &= hp->ocr;
        !           406:        if (ISSET(ocr, MMC_OCR_3_2V_3_3V|MMC_OCR_3_3V_3_4V))
        !           407:                vdd = SDHC_VOLTAGE_3_3V;
        !           408:        else if (ISSET(ocr, MMC_OCR_2_9V_3_0V|MMC_OCR_3_0V_3_1V))
        !           409:                vdd = SDHC_VOLTAGE_3_0V;
        !           410:        else if (ISSET(ocr, MMC_OCR_1_7V_1_8V|MMC_OCR_1_8V_1_9V))
        !           411:                vdd = SDHC_VOLTAGE_1_8V;
        !           412:        else {
        !           413:                /* Unsupported voltage level requested. */
        !           414:                splx(s);
        !           415:                return EINVAL;
        !           416:        }
        !           417:
        !           418:        /*
        !           419:         * Enable bus power.  Wait at least 1 ms (or 74 clocks) plus
        !           420:         * voltage ramp until power rises.
        !           421:         */
        !           422:        HWRITE1(hp, SDHC_POWER_CTL, (vdd << SDHC_VOLTAGE_SHIFT) |
        !           423:            SDHC_BUS_POWER);
        !           424:        sdmmc_delay(10000);
        !           425:
        !           426:        /*
        !           427:         * The host system may not power the bus due to battery low,
        !           428:         * etc.  In that case, the host controller should clear the
        !           429:         * bus power bit.
        !           430:         */
        !           431:        if (!ISSET(HREAD1(hp, SDHC_POWER_CTL), SDHC_BUS_POWER)) {
        !           432:                splx(s);
        !           433:                return ENXIO;
        !           434:        }
        !           435:
        !           436:        splx(s);
        !           437:        return 0;
        !           438: }
        !           439:
        !           440: /*
        !           441:  * Return the smallest possible base clock frequency divisor value
        !           442:  * for the CLOCK_CTL register to produce `freq' (KHz).
        !           443:  */
        !           444: static int
        !           445: sdhc_clock_divisor(struct sdhc_host *hp, u_int freq)
        !           446: {
        !           447:        int div;
        !           448:
        !           449:        for (div = 1; div <= 256; div *= 2)
        !           450:                if ((hp->clkbase / div) <= freq)
        !           451:                        return (div / 2);
        !           452:        /* No divisor found. */
        !           453:        return -1;
        !           454: }
        !           455:
        !           456: /*
        !           457:  * Set or change SDCLK frequency or disable the SD clock.
        !           458:  * Return zero on success.
        !           459:  */
        !           460: int
        !           461: sdhc_bus_clock(sdmmc_chipset_handle_t sch, int freq)
        !           462: {
        !           463:        struct sdhc_host *hp = sch;
        !           464:        int s;
        !           465:        int div;
        !           466:        int timo;
        !           467:        int error = 0;
        !           468:
        !           469:        s = splsdmmc();
        !           470:
        !           471: #ifdef DIAGNOSTIC
        !           472:        /* Must not stop the clock if commands are in progress. */
        !           473:        if (ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_CMD_INHIBIT_MASK) &&
        !           474:            sdhc_card_detect(hp))
        !           475:                printf("sdhc_sdclk_frequency_select: command in progress\n");
        !           476: #endif
        !           477:
        !           478:        /*
        !           479:         * Stop SD clock before changing the frequency.
        !           480:         */
        !           481:        HWRITE2(hp, SDHC_CLOCK_CTL, 0);
        !           482:        if (freq == SDMMC_SDCLK_OFF)
        !           483:                goto ret;
        !           484:
        !           485:        /*
        !           486:         * Set the minimum base clock frequency divisor.
        !           487:         */
        !           488:        if ((div = sdhc_clock_divisor(hp, freq)) < 0) {
        !           489:                /* Invalid base clock frequency or `freq' value. */
        !           490:                error = EINVAL;
        !           491:                goto ret;
        !           492:        }
        !           493:        HWRITE2(hp, SDHC_CLOCK_CTL, div << SDHC_SDCLK_DIV_SHIFT);
        !           494:
        !           495:        /*
        !           496:         * Start internal clock.  Wait 10ms for stabilization.
        !           497:         */
        !           498:        HSET2(hp, SDHC_CLOCK_CTL, SDHC_INTCLK_ENABLE);
        !           499:        for (timo = 1000; timo > 0; timo--) {
        !           500:                if (ISSET(HREAD2(hp, SDHC_CLOCK_CTL), SDHC_INTCLK_STABLE))
        !           501:                        break;
        !           502:                sdmmc_delay(10);
        !           503:        }
        !           504:        if (timo == 0) {
        !           505:                error = ETIMEDOUT;
        !           506:                goto ret;
        !           507:        }
        !           508:
        !           509:        /*
        !           510:         * Enable SD clock.
        !           511:         */
        !           512:        HSET2(hp, SDHC_CLOCK_CTL, SDHC_SDCLK_ENABLE);
        !           513:
        !           514: ret:
        !           515:        splx(s);
        !           516:        return error;
        !           517: }
        !           518:
        !           519: void
        !           520: sdhc_card_intr_mask(sdmmc_chipset_handle_t sch, int enable)
        !           521: {
        !           522:        struct sdhc_host *hp = sch;
        !           523:
        !           524:        if (enable) {
        !           525:                HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
        !           526:                HSET2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_CARD_INTERRUPT);
        !           527:        } else {
        !           528:                HCLR2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_CARD_INTERRUPT);
        !           529:                HCLR2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
        !           530:        }
        !           531: }
        !           532:
        !           533: void
        !           534: sdhc_card_intr_ack(sdmmc_chipset_handle_t sch)
        !           535: {
        !           536:        struct sdhc_host *hp = sch;
        !           537:
        !           538:        HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
        !           539: }
        !           540:
        !           541: int
        !           542: sdhc_wait_state(struct sdhc_host *hp, u_int32_t mask, u_int32_t value)
        !           543: {
        !           544:        u_int32_t state;
        !           545:        int timeout;
        !           546:
        !           547:        for (timeout = 10; timeout > 0; timeout--) {
        !           548:                if (((state = HREAD4(hp, SDHC_PRESENT_STATE)) & mask)
        !           549:                    == value)
        !           550:                        return 0;
        !           551:                sdmmc_delay(10000);
        !           552:        }
        !           553:        DPRINTF(0,("%s: timeout waiting for %x (state=%b)\n", HDEVNAME(hp),
        !           554:            value, state, SDHC_PRESENT_STATE_BITS));
        !           555:        return ETIMEDOUT;
        !           556: }
        !           557:
        !           558: void
        !           559: sdhc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
        !           560: {
        !           561:        struct sdhc_host *hp = sch;
        !           562:        int error;
        !           563:
        !           564:        /*
        !           565:         * Start the MMC command, or mark `cmd' as failed and return.
        !           566:         */
        !           567:        error = sdhc_start_command(hp, cmd);
        !           568:        if (error != 0) {
        !           569:                cmd->c_error = error;
        !           570:                SET(cmd->c_flags, SCF_ITSDONE);
        !           571:                return;
        !           572:        }
        !           573:
        !           574:        /*
        !           575:         * Wait until the command phase is done, or until the command
        !           576:         * is marked done for any other reason.
        !           577:         */
        !           578:        if (!sdhc_wait_intr(hp, SDHC_COMMAND_COMPLETE,
        !           579:            SDHC_COMMAND_TIMEOUT)) {
        !           580:                cmd->c_error = ETIMEDOUT;
        !           581:                SET(cmd->c_flags, SCF_ITSDONE);
        !           582:                return;
        !           583:        }
        !           584:
        !           585:        /*
        !           586:         * The host controller removes bits [0:7] from the response
        !           587:         * data (CRC) and we pass the data up unchanged to the bus
        !           588:         * driver (without padding).
        !           589:         */
        !           590:        if (cmd->c_error == 0 && ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
        !           591:                if (ISSET(cmd->c_flags, SCF_RSP_136)) {
        !           592:                        u_char *p = (u_char *)cmd->c_resp;
        !           593:                        int i;
        !           594:
        !           595:                        for (i = 0; i < 15; i++)
        !           596:                                *p++ = HREAD1(hp, SDHC_RESPONSE + i);
        !           597:                } else
        !           598:                        cmd->c_resp[0] = HREAD4(hp, SDHC_RESPONSE);
        !           599:        }
        !           600:
        !           601:        /*
        !           602:         * If the command has data to transfer in any direction,
        !           603:         * execute the transfer now.
        !           604:         */
        !           605:        if (cmd->c_error == 0 && cmd->c_data != NULL)
        !           606:                sdhc_transfer_data(hp, cmd);
        !           607:
        !           608:        /* Turn off the LED. */
        !           609:        HCLR1(hp, SDHC_HOST_CTL, SDHC_LED_ON);
        !           610:
        !           611:        DPRINTF(1,("%s: cmd %u done (flags=%#x error=%d)\n",
        !           612:            HDEVNAME(hp), cmd->c_opcode, cmd->c_flags, cmd->c_error));
        !           613:        SET(cmd->c_flags, SCF_ITSDONE);
        !           614: }
        !           615:
        !           616: int
        !           617: sdhc_start_command(struct sdhc_host *hp, struct sdmmc_command *cmd)
        !           618: {
        !           619:        u_int16_t blksize = 0;
        !           620:        u_int16_t blkcount = 0;
        !           621:        u_int16_t mode;
        !           622:        u_int16_t command;
        !           623:        int error;
        !           624:        int s;
        !           625:
        !           626:        DPRINTF(1,("%s: start cmd %u arg=%#x data=%#x dlen=%d flags=%#x "
        !           627:            "proc=\"%s\"\n", HDEVNAME(hp), cmd->c_opcode, cmd->c_arg,
        !           628:            cmd->c_data, cmd->c_datalen, cmd->c_flags, curproc ?
        !           629:            curproc->p_comm : ""));
        !           630:
        !           631:        /*
        !           632:         * The maximum block length for commands should be the minimum
        !           633:         * of the host buffer size and the card buffer size. (1.7.2)
        !           634:         */
        !           635:
        !           636:        /* Fragment the data into proper blocks. */
        !           637:        if (cmd->c_datalen > 0) {
        !           638:                blksize = MIN(cmd->c_datalen, cmd->c_blklen);
        !           639:                blkcount = cmd->c_datalen / blksize;
        !           640:                if (cmd->c_datalen % blksize > 0) {
        !           641:                        /* XXX: Split this command. (1.7.4) */
        !           642:                        printf("%s: data not a multiple of %d bytes\n",
        !           643:                            HDEVNAME(hp), blksize);
        !           644:                        return EINVAL;
        !           645:                }
        !           646:        }
        !           647:
        !           648:        /* Check limit imposed by 9-bit block count. (1.7.2) */
        !           649:        if (blkcount > SDHC_BLOCK_COUNT_MAX) {
        !           650:                printf("%s: too much data\n", HDEVNAME(hp));
        !           651:                return EINVAL;
        !           652:        }
        !           653:
        !           654:        /* Prepare transfer mode register value. (2.2.5) */
        !           655:        mode = 0;
        !           656:        if (ISSET(cmd->c_flags, SCF_CMD_READ))
        !           657:                mode |= SDHC_READ_MODE;
        !           658:        if (blkcount > 0) {
        !           659:                mode |= SDHC_BLOCK_COUNT_ENABLE;
        !           660:                if (blkcount > 1) {
        !           661:                        mode |= SDHC_MULTI_BLOCK_MODE;
        !           662:                        /* XXX only for memory commands? */
        !           663:                        mode |= SDHC_AUTO_CMD12_ENABLE;
        !           664:                }
        !           665:        }
        !           666: #ifdef notyet
        !           667:        if (ISSET(hp->flags, SHF_USE_DMA))
        !           668:                mode |= SDHC_DMA_ENABLE;
        !           669: #endif
        !           670:
        !           671:        /*
        !           672:         * Prepare command register value. (2.2.6)
        !           673:         */
        !           674:        command = (cmd->c_opcode & SDHC_COMMAND_INDEX_MASK) <<
        !           675:            SDHC_COMMAND_INDEX_SHIFT;
        !           676:
        !           677:        if (ISSET(cmd->c_flags, SCF_RSP_CRC))
        !           678:                command |= SDHC_CRC_CHECK_ENABLE;
        !           679:        if (ISSET(cmd->c_flags, SCF_RSP_IDX))
        !           680:                command |= SDHC_INDEX_CHECK_ENABLE;
        !           681:        if (cmd->c_data != NULL)
        !           682:                command |= SDHC_DATA_PRESENT_SELECT;
        !           683:
        !           684:        if (!ISSET(cmd->c_flags, SCF_RSP_PRESENT))
        !           685:                command |= SDHC_NO_RESPONSE;
        !           686:        else if (ISSET(cmd->c_flags, SCF_RSP_136))
        !           687:                command |= SDHC_RESP_LEN_136;
        !           688:        else if (ISSET(cmd->c_flags, SCF_RSP_BSY))
        !           689:                command |= SDHC_RESP_LEN_48_CHK_BUSY;
        !           690:        else
        !           691:                command |= SDHC_RESP_LEN_48;
        !           692:
        !           693:        /* Wait until command and data inhibit bits are clear. (1.5) */
        !           694:        if ((error = sdhc_wait_state(hp, SDHC_CMD_INHIBIT_MASK, 0)) != 0)
        !           695:                return error;
        !           696:
        !           697:        s = splsdmmc();
        !           698:
        !           699:        /* Alert the user not to remove the card. */
        !           700:        HSET1(hp, SDHC_HOST_CTL, SDHC_LED_ON);
        !           701:
        !           702:        /* XXX: Set DMA start address if SHF_USE_DMA is set. */
        !           703:
        !           704:        DPRINTF(1,("%s: cmd=%#x mode=%#x blksize=%d blkcount=%d\n",
        !           705:            HDEVNAME(hp), command, mode, blksize, blkcount));
        !           706:
        !           707:        /*
        !           708:         * Start a CPU data transfer.  Writing to the high order byte
        !           709:         * of the SDHC_COMMAND register triggers the SD command. (1.5)
        !           710:         */
        !           711:        HWRITE2(hp, SDHC_TRANSFER_MODE, mode);
        !           712:        HWRITE2(hp, SDHC_BLOCK_SIZE, blksize);
        !           713:        if (blkcount > 1)
        !           714:                HWRITE2(hp, SDHC_BLOCK_COUNT, blkcount);
        !           715:        HWRITE4(hp, SDHC_ARGUMENT, cmd->c_arg);
        !           716:        HWRITE2(hp, SDHC_COMMAND, command);
        !           717:
        !           718:        splx(s);
        !           719:        return 0;
        !           720: }
        !           721:
        !           722: void
        !           723: sdhc_transfer_data(struct sdhc_host *hp, struct sdmmc_command *cmd)
        !           724: {
        !           725:        u_char *datap = cmd->c_data;
        !           726:        int i, datalen;
        !           727:        int mask;
        !           728:        int error;
        !           729:
        !           730:        mask = ISSET(cmd->c_flags, SCF_CMD_READ) ?
        !           731:            SDHC_BUFFER_READ_ENABLE : SDHC_BUFFER_WRITE_ENABLE;
        !           732:        error = 0;
        !           733:        datalen = cmd->c_datalen;
        !           734:
        !           735:        DPRINTF(1,("%s: resp=%#x datalen=%d\n", HDEVNAME(hp),
        !           736:            MMC_R1(cmd->c_resp), datalen));
        !           737:
        !           738: #ifdef SDHC_DEBUG
        !           739:        /* XXX I forgot why I wanted to know when this happens :-( */
        !           740:        if ((cmd->c_opcode == 52 || cmd->c_opcode == 53) &&
        !           741:            ISSET(MMC_R1(cmd->c_resp), 0xcb00))
        !           742:                printf("%s: CMD52/53 error response flags %#x\n",
        !           743:                    HDEVNAME(hp), MMC_R1(cmd->c_resp) & 0xff00);
        !           744: #endif
        !           745:
        !           746:        while (datalen > 0) {
        !           747:                if (!sdhc_wait_intr(hp, SDHC_BUFFER_READ_READY|
        !           748:                    SDHC_BUFFER_WRITE_READY, SDHC_BUFFER_TIMEOUT)) {
        !           749:                        error = ETIMEDOUT;
        !           750:                        break;
        !           751:                }
        !           752:
        !           753:                if ((error = sdhc_wait_state(hp, mask, mask)) != 0)
        !           754:                        break;
        !           755:
        !           756:                i = MIN(datalen, cmd->c_blklen);
        !           757:                if (ISSET(cmd->c_flags, SCF_CMD_READ))
        !           758:                        sdhc_read_data(hp, datap, i);
        !           759:                else
        !           760:                        sdhc_write_data(hp, datap, i);
        !           761:
        !           762:                datap += i;
        !           763:                datalen -= i;
        !           764:        }
        !           765:
        !           766:        if (error == 0 && !sdhc_wait_intr(hp, SDHC_TRANSFER_COMPLETE,
        !           767:            SDHC_TRANSFER_TIMEOUT))
        !           768:                error = ETIMEDOUT;
        !           769:
        !           770:        if (error != 0)
        !           771:                cmd->c_error = error;
        !           772:        SET(cmd->c_flags, SCF_ITSDONE);
        !           773:
        !           774:        DPRINTF(1,("%s: data transfer done (error=%d)\n",
        !           775:            HDEVNAME(hp), cmd->c_error));
        !           776: }
        !           777:
        !           778: void
        !           779: sdhc_read_data(struct sdhc_host *hp, u_char *datap, int datalen)
        !           780: {
        !           781:        while (datalen > 3) {
        !           782:                *(u_int32_t *)datap = HREAD4(hp, SDHC_DATA);
        !           783:                datap += 4;
        !           784:                datalen -= 4;
        !           785:        }
        !           786:        if (datalen > 0) {
        !           787:                u_int32_t rv = HREAD4(hp, SDHC_DATA);
        !           788:                do {
        !           789:                        *datap++ = rv & 0xff;
        !           790:                        rv = rv >> 8;
        !           791:                } while (--datalen > 0);
        !           792:        }
        !           793: }
        !           794:
        !           795: void
        !           796: sdhc_write_data(struct sdhc_host *hp, u_char *datap, int datalen)
        !           797: {
        !           798:        while (datalen > 3) {
        !           799:                DPRINTF(3,("%08x\n", *(u_int32_t *)datap));
        !           800:                HWRITE4(hp, SDHC_DATA, *((u_int32_t *)datap)++);
        !           801:                datalen -= 4;
        !           802:        }
        !           803:        if (datalen > 0) {
        !           804:                u_int32_t rv = *datap++;
        !           805:                if (datalen > 1)
        !           806:                        rv |= *datap++ << 8;
        !           807:                if (datalen > 2)
        !           808:                        rv |= *datap++ << 16;
        !           809:                DPRINTF(3,("rv %08x\n", rv));
        !           810:                HWRITE4(hp, SDHC_DATA, rv);
        !           811:        }
        !           812: }
        !           813:
        !           814: /* Prepare for another command. */
        !           815: int
        !           816: sdhc_soft_reset(struct sdhc_host *hp, int mask)
        !           817: {
        !           818:        int timo;
        !           819:
        !           820:        DPRINTF(1,("%s: software reset reg=%#x\n", HDEVNAME(hp), mask));
        !           821:
        !           822:        HWRITE1(hp, SDHC_SOFTWARE_RESET, mask);
        !           823:        for (timo = 10; timo > 0; timo--) {
        !           824:                if (!ISSET(HREAD1(hp, SDHC_SOFTWARE_RESET), mask))
        !           825:                        break;
        !           826:                sdmmc_delay(10000);
        !           827:                HWRITE1(hp, SDHC_SOFTWARE_RESET, 0);
        !           828:        }
        !           829:        if (timo == 0) {
        !           830:                DPRINTF(1,("%s: timeout reg=%#x\n", HDEVNAME(hp),
        !           831:                    HREAD1(hp, SDHC_SOFTWARE_RESET)));
        !           832:                HWRITE1(hp, SDHC_SOFTWARE_RESET, 0);
        !           833:                return (ETIMEDOUT);
        !           834:        }
        !           835:
        !           836:        return (0);
        !           837: }
        !           838:
        !           839: int
        !           840: sdhc_wait_intr(struct sdhc_host *hp, int mask, int timo)
        !           841: {
        !           842:        int status;
        !           843:        int s;
        !           844:
        !           845:        mask |= SDHC_ERROR_INTERRUPT;
        !           846:
        !           847:        s = splsdmmc();
        !           848:        status = hp->intr_status & mask;
        !           849:        while (status == 0) {
        !           850:                if (tsleep(&hp->intr_status, PWAIT, "hcintr", timo)
        !           851:                    == EWOULDBLOCK) {
        !           852:                        status |= SDHC_ERROR_INTERRUPT;
        !           853:                        break;
        !           854:                }
        !           855:                status = hp->intr_status & mask;
        !           856:        }
        !           857:        hp->intr_status &= ~status;
        !           858:
        !           859:        DPRINTF(2,("%s: intr status %#x error %#x\n", HDEVNAME(hp), status,
        !           860:            hp->intr_error_status));
        !           861:
        !           862:        /* Command timeout has higher priority than command complete. */
        !           863:        if (ISSET(status, SDHC_ERROR_INTERRUPT)) {
        !           864:                hp->intr_error_status = 0;
        !           865:                (void)sdhc_soft_reset(hp, SDHC_RESET_DAT|SDHC_RESET_CMD);
        !           866:                status = 0;
        !           867:        }
        !           868:
        !           869:        splx(s);
        !           870:        return status;
        !           871: }
        !           872:
        !           873: /*
        !           874:  * Established by attachment driver at interrupt priority IPL_SDMMC.
        !           875:  */
        !           876: int
        !           877: sdhc_intr(void *arg)
        !           878: {
        !           879:        struct sdhc_softc *sc = arg;
        !           880:        int host;
        !           881:        int done = 0;
        !           882:
        !           883:        /* We got an interrupt, but we don't know from which slot. */
        !           884:        for (host = 0; host < sc->sc_nhosts; host++) {
        !           885:                struct sdhc_host *hp = sc->sc_host[host];
        !           886:                u_int16_t status;
        !           887:
        !           888:                if (hp == NULL)
        !           889:                        continue;
        !           890:
        !           891:                /* Find out which interrupts are pending. */
        !           892:                status = HREAD2(hp, SDHC_NINTR_STATUS);
        !           893:                if (!ISSET(status, SDHC_NINTR_STATUS_MASK))
        !           894:                        continue; /* no interrupt for us */
        !           895:
        !           896:                /* Acknowledge the interrupts we are about to handle. */
        !           897:                HWRITE2(hp, SDHC_NINTR_STATUS, status);
        !           898:                DPRINTF(2,("%s: interrupt status=%b\n", HDEVNAME(hp),
        !           899:                    status, SDHC_NINTR_STATUS_BITS));
        !           900:
        !           901:                /* Claim this interrupt. */
        !           902:                done = 1;
        !           903:
        !           904:                /*
        !           905:                 * Service error interrupts.
        !           906:                 */
        !           907:                if (ISSET(status, SDHC_ERROR_INTERRUPT)) {
        !           908:                        u_int16_t error;
        !           909:
        !           910:                        /* Acknowledge error interrupts. */
        !           911:                        error = HREAD2(hp, SDHC_EINTR_STATUS);
        !           912:                        HWRITE2(hp, SDHC_EINTR_STATUS, error);
        !           913:                        DPRINTF(2,("%s: error interrupt, status=%b\n",
        !           914:                            HDEVNAME(hp), error, SDHC_EINTR_STATUS_BITS));
        !           915:
        !           916:                        if (ISSET(error, SDHC_CMD_TIMEOUT_ERROR|
        !           917:                            SDHC_DATA_TIMEOUT_ERROR)) {
        !           918:                                hp->intr_error_status |= error;
        !           919:                                hp->intr_status |= status;
        !           920:                                wakeup(&hp->intr_status);
        !           921:                        }
        !           922:                }
        !           923:
        !           924:                /*
        !           925:                 * Wake up the sdmmc event thread to scan for cards.
        !           926:                 */
        !           927:                if (ISSET(status, SDHC_CARD_REMOVAL|SDHC_CARD_INSERTION))
        !           928:                        sdmmc_needs_discover(hp->sdmmc);
        !           929:
        !           930:                /*
        !           931:                 * Wake up the blocking process to service command
        !           932:                 * related interrupt(s).
        !           933:                 */
        !           934:                if (ISSET(status, SDHC_BUFFER_READ_READY|
        !           935:                    SDHC_BUFFER_WRITE_READY|SDHC_COMMAND_COMPLETE|
        !           936:                    SDHC_TRANSFER_COMPLETE)) {
        !           937:                        hp->intr_status |= status;
        !           938:                        wakeup(&hp->intr_status);
        !           939:                }
        !           940:
        !           941:                /*
        !           942:                 * Service SD card interrupts.
        !           943:                 */
        !           944:                if (ISSET(status, SDHC_CARD_INTERRUPT)) {
        !           945:                        DPRINTF(0,("%s: card interrupt\n", HDEVNAME(hp)));
        !           946:                        HCLR2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
        !           947:                        sdmmc_card_intr(hp->sdmmc);
        !           948:                }
        !           949:        }
        !           950:        return done;
        !           951: }
        !           952:
        !           953: #ifdef SDHC_DEBUG
        !           954: void
        !           955: sdhc_dump_regs(struct sdhc_host *hp)
        !           956: {
        !           957:        printf("0x%02x PRESENT_STATE:    %b\n", SDHC_PRESENT_STATE,
        !           958:            HREAD4(hp, SDHC_PRESENT_STATE), SDHC_PRESENT_STATE_BITS);
        !           959:        printf("0x%02x POWER_CTL:        %x\n", SDHC_POWER_CTL,
        !           960:            HREAD1(hp, SDHC_POWER_CTL));
        !           961:        printf("0x%02x NINTR_STATUS:     %x\n", SDHC_NINTR_STATUS,
        !           962:            HREAD2(hp, SDHC_NINTR_STATUS));
        !           963:        printf("0x%02x EINTR_STATUS:     %x\n", SDHC_EINTR_STATUS,
        !           964:            HREAD2(hp, SDHC_EINTR_STATUS));
        !           965:        printf("0x%02x NINTR_STATUS_EN:  %x\n", SDHC_NINTR_STATUS_EN,
        !           966:            HREAD2(hp, SDHC_NINTR_STATUS_EN));
        !           967:        printf("0x%02x EINTR_STATUS_EN:  %x\n", SDHC_EINTR_STATUS_EN,
        !           968:            HREAD2(hp, SDHC_EINTR_STATUS_EN));
        !           969:        printf("0x%02x NINTR_SIGNAL_EN:  %x\n", SDHC_NINTR_SIGNAL_EN,
        !           970:            HREAD2(hp, SDHC_NINTR_SIGNAL_EN));
        !           971:        printf("0x%02x EINTR_SIGNAL_EN:  %x\n", SDHC_EINTR_SIGNAL_EN,
        !           972:            HREAD2(hp, SDHC_EINTR_SIGNAL_EN));
        !           973:        printf("0x%02x CAPABILITIES:     %x\n", SDHC_CAPABILITIES,
        !           974:            HREAD4(hp, SDHC_CAPABILITIES));
        !           975:        printf("0x%02x MAX_CAPABILITIES: %x\n", SDHC_MAX_CAPABILITIES,
        !           976:            HREAD4(hp, SDHC_MAX_CAPABILITIES));
        !           977: }
        !           978: #endif

CVSweb