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

Annotation of sys/arch/arm/xscale/pxa2x0_mmc.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: pxa2x0_mmc.c,v 1.2 2007/03/18 22:14:52 deraadt Exp $  */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2007 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:  * MMC/SD/SDIO controller driver for Intel PXA27x processors
        !            21:  *
        !            22:  * Power management is beyond control of the processor's SD/SDIO/MMC
        !            23:  * block, so this driver depends on the attachment driver to provide
        !            24:  * us with some callback functions via the "tag" member in our softc.
        !            25:  * Bus power management calls are then dispatched to the attachment
        !            26:  * driver.
        !            27:  */
        !            28:
        !            29: #include <sys/param.h>
        !            30: #include <sys/device.h>
        !            31: #include <sys/kernel.h>
        !            32: #include <sys/proc.h>
        !            33: #include <sys/systm.h>
        !            34:
        !            35: #include <machine/bus.h>
        !            36:
        !            37: #include <arch/arm/xscale/pxa2x0_gpio.h>
        !            38: #include <arch/arm/xscale/pxa2x0reg.h>
        !            39: #include <arch/arm/xscale/pxa2x0var.h>
        !            40: #include <arch/arm/xscale/pxammcvar.h>
        !            41:
        !            42: #include <dev/sdmmc/sdmmcchip.h>
        !            43: #include <dev/sdmmc/sdmmcreg.h>
        !            44: #include <dev/sdmmc/sdmmcvar.h>
        !            45:
        !            46: /* GPIO pins */
        !            47: #define PXAMMC_CARD_DETECT     9 /* XXX zaurus-specific */
        !            48: #define PXAMMC_MMCLK           32
        !            49: #define PXAMMC_MMCMD           112
        !            50: #define PXAMMC_MMDAT0          92
        !            51: #define PXAMMC_MMDAT1          109
        !            52: #define PXAMMC_MMDAT2          110
        !            53: #define PXAMMC_MMDAT3          111
        !            54:
        !            55: int    pxammc_host_reset(sdmmc_chipset_handle_t);
        !            56: u_int32_t pxammc_host_ocr(sdmmc_chipset_handle_t);
        !            57: int    pxammc_host_maxblklen(sdmmc_chipset_handle_t);
        !            58: int    pxammc_card_detect(sdmmc_chipset_handle_t);
        !            59: int    pxammc_bus_power(sdmmc_chipset_handle_t, u_int32_t);
        !            60: int    pxammc_bus_clock(sdmmc_chipset_handle_t, int);
        !            61: void   pxammc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *);
        !            62: void   pxammc_clock_stop(struct pxammc_softc *);
        !            63: void   pxammc_clock_start(struct pxammc_softc *);
        !            64: int    pxammc_card_intr(void *);
        !            65: int    pxammc_intr(void *);
        !            66: void   pxammc_intr_cmd(struct pxammc_softc *);
        !            67: void   pxammc_intr_data(struct pxammc_softc *);
        !            68: void   pxammc_intr_done(struct pxammc_softc *);
        !            69:
        !            70: #define CSR_READ_1(sc, reg) \
        !            71:        bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (reg))
        !            72: #define CSR_WRITE_1(sc, reg, val) \
        !            73:        bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
        !            74: #define CSR_READ_4(sc, reg) \
        !            75:        bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))
        !            76: #define CSR_WRITE_4(sc, reg, val) \
        !            77:        bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
        !            78: #define CSR_SET_4(sc, reg, bits) \
        !            79:        CSR_WRITE_4((sc), (reg), CSR_READ_4((sc), (reg)) | (bits))
        !            80: #define CSR_CLR_4(sc, reg, bits) \
        !            81:        CSR_WRITE_4((sc), (reg), CSR_READ_4((sc), (reg)) & ~(bits))
        !            82:
        !            83: struct sdmmc_chip_functions pxammc_functions = {
        !            84:        /* host controller reset */
        !            85:        pxammc_host_reset,
        !            86:        /* host controller capabilities */
        !            87:        pxammc_host_ocr,
        !            88:        pxammc_host_maxblklen,
        !            89:        /* card detection */
        !            90:        pxammc_card_detect,
        !            91:        /* bus power and clock frequency */
        !            92:        pxammc_bus_power,
        !            93:        pxammc_bus_clock,
        !            94:        /* command execution */
        !            95:        pxammc_exec_command
        !            96: };
        !            97:
        !            98: struct cfdriver pxammc_cd = {
        !            99:        NULL, "pxammc", DV_DULL
        !           100: };
        !           101:
        !           102: #define SDMMC_DEBUG
        !           103: #ifdef SDMMC_DEBUG
        !           104: int sdhcdebug = 0;     /* XXX must be named sdhcdebug for sdmmc.c */
        !           105: #define DPRINTF(n,s)   do { if ((n) <= sdhcdebug) printf s; } while (0)
        !           106: #else
        !           107: #define DPRINTF(n,s)   do {} while (0)
        !           108: #endif
        !           109:
        !           110: int
        !           111: pxammc_match(void)
        !           112: {
        !           113:        return (cputype & ~CPU_ID_XSCALE_COREREV_MASK) == CPU_ID_PXA27X;
        !           114: }
        !           115:
        !           116: void
        !           117: pxammc_attach(struct pxammc_softc *sc, void *aux)
        !           118: {
        !           119:        struct pxaip_attach_args *pxa = aux;
        !           120:        struct sdmmcbus_attach_args saa;
        !           121:        int s;
        !           122:
        !           123:        /* Enable the clocks to the MMC controller. */
        !           124:        pxa2x0_clkman_config(CKEN_MMC, 1);
        !           125:
        !           126:        sc->sc_iot = pxa->pxa_sa.sa_iot;
        !           127:        if (bus_space_map(sc->sc_iot, PXA2X0_MMC_BASE, PXA2X0_MMC_SIZE, 0,
        !           128:            &sc->sc_ioh) != 0) {
        !           129:                printf(": can't map regs\n");
        !           130:                goto fail;
        !           131:        }
        !           132:
        !           133:        /*
        !           134:         * Establish the card detection and MMC interrupt handlers and
        !           135:         * mask all interrupts until we are prepared to handle them.
        !           136:         */
        !           137:        s = splsdmmc();
        !           138:
        !           139:        pxa2x0_gpio_set_function(PXAMMC_CARD_DETECT, GPIO_IN);
        !           140:        sc->sc_card_ih = pxa2x0_gpio_intr_establish(PXAMMC_CARD_DETECT,
        !           141:            IST_EDGE_BOTH, IPL_SDMMC, pxammc_card_intr, sc, "mmccd");
        !           142:        if (sc->sc_card_ih == NULL) {
        !           143:                splx(s);
        !           144:                printf(": can't establish card interrupt\n");
        !           145:                goto fail;
        !           146:        }
        !           147:        pxa2x0_gpio_intr_mask(sc->sc_card_ih);
        !           148:
        !           149:        sc->sc_ih = pxa2x0_intr_establish(PXA2X0_INT_MMC, IPL_SDMMC,
        !           150:            pxammc_intr, sc, sc->sc_dev.dv_xname);
        !           151:        if (sc->sc_ih == NULL) {
        !           152:                splx(s);
        !           153:                printf(": can't establish MMC interrupt\n");
        !           154:                goto fail;
        !           155:        }
        !           156:        CSR_WRITE_4(sc, MMC_I_MASK, 0xffffffff);
        !           157:
        !           158:        splx(s);
        !           159:
        !           160:        printf(": MMC/SD/SDIO controller\n");
        !           161:
        !           162:        /*
        !           163:         * Configure the GPIO pins.  In SD/MMC mode, all pins except
        !           164:         * MMCLK are bidirectional and the direction is controlled in
        !           165:         * hardware without our assistence.
        !           166:         */
        !           167:        pxa2x0_gpio_set_function(PXAMMC_MMCLK, GPIO_ALT_FN_2_OUT);
        !           168:        pxa2x0_gpio_set_function(PXAMMC_MMCMD, GPIO_ALT_FN_1_IN);
        !           169:        pxa2x0_gpio_set_function(PXAMMC_MMDAT0, GPIO_ALT_FN_1_IN);
        !           170:        pxa2x0_gpio_set_function(PXAMMC_MMDAT1, GPIO_ALT_FN_1_IN);
        !           171:        pxa2x0_gpio_set_function(PXAMMC_MMDAT2, GPIO_ALT_FN_1_IN);
        !           172:        pxa2x0_gpio_set_function(PXAMMC_MMDAT3, GPIO_ALT_FN_1_IN);
        !           173:
        !           174:        /*
        !           175:         * Reset the host controller and unmask normal interrupts.
        !           176:         */
        !           177:        (void)pxammc_host_reset(sc);
        !           178:
        !           179:        /*
        !           180:         * Attach the generic sdmmc bus driver.
        !           181:         */
        !           182:        bzero(&saa, sizeof saa);
        !           183:        saa.saa_busname = "sdmmc";
        !           184:        saa.sct = &pxammc_functions;
        !           185:        saa.sch = sc;
        !           186:
        !           187:        sc->sc_sdmmc = config_found(&sc->sc_dev, &saa, NULL);
        !           188:        if (sc->sc_sdmmc == NULL) {
        !           189:                printf("%s: can't attach bus\n", sc->sc_dev.dv_xname);
        !           190:                goto fail;
        !           191:        }
        !           192:
        !           193:        /* Enable card detection interrupt. */
        !           194:        pxa2x0_gpio_intr_unmask(sc->sc_card_ih);
        !           195:        return;
        !           196:
        !           197: fail:
        !           198:        if (sc->sc_ih != NULL) {
        !           199:                pxa2x0_intr_disestablish(sc->sc_ih);
        !           200:                sc->sc_ih = NULL;
        !           201:        }
        !           202:        if (sc->sc_card_ih != NULL) {
        !           203:                pxa2x0_gpio_intr_disestablish(sc->sc_card_ih);
        !           204:                sc->sc_card_ih = NULL;
        !           205:        }
        !           206:        if (sc->sc_ioh != NULL) {
        !           207:                bus_space_unmap(sc->sc_iot, sc->sc_ioh, PXA2X0_MMC_SIZE);
        !           208:                sc->sc_ioh = NULL;
        !           209:        }
        !           210:        pxa2x0_clkman_config(CKEN_MMC, 0);
        !           211: }
        !           212:
        !           213: int
        !           214: pxammc_host_reset(sdmmc_chipset_handle_t sch)
        !           215: {
        !           216:        struct pxammc_softc *sc = sch;
        !           217:        int s = splsdmmc();
        !           218:
        !           219:        /* Make sure to initialize the card before the next command. */
        !           220:        CLR(sc->sc_flags, PMF_CARD_INITED);
        !           221:
        !           222:        /* Disable SPI mode (we don't support SPI). */
        !           223:        CSR_WRITE_4(sc, MMC_SPI, 0);
        !           224:
        !           225:        /* Set response timeout to maximum. */
        !           226:        CSR_WRITE_4(sc, MMC_RESTO, 0x7f);
        !           227:
        !           228:        /* Enable all interrupts. */
        !           229:        CSR_WRITE_4(sc, MMC_I_MASK, 0);
        !           230:
        !           231:        splx(s);
        !           232:        return 0;
        !           233: }
        !           234:
        !           235: int
        !           236: pxammc_host_maxblklen(sdmmc_chipset_handle_t sch)
        !           237: {
        !           238:        return 2048;
        !           239: }
        !           240:
        !           241: u_int32_t
        !           242: pxammc_host_ocr(sdmmc_chipset_handle_t sch)
        !           243: {
        !           244:        struct pxammc_softc *sc = sch;
        !           245:
        !           246:        if (sc->tag.get_ocr != NULL)
        !           247:                return sc->tag.get_ocr(sc->tag.cookie);
        !           248:
        !           249:        DPRINTF(0,("%s: driver lacks get_ocr() function\n",
        !           250:            sc->sc_dev.dv_xname));
        !           251:        return ENXIO;
        !           252: }
        !           253:
        !           254: int
        !           255: pxammc_card_detect(sdmmc_chipset_handle_t sch)
        !           256: {
        !           257:        return !pxa2x0_gpio_get_bit(PXAMMC_CARD_DETECT);
        !           258: }
        !           259:
        !           260: int
        !           261: pxammc_bus_power(sdmmc_chipset_handle_t sch, u_int32_t ocr)
        !           262: {
        !           263:        struct pxammc_softc *sc = sch;
        !           264:
        !           265:        /*
        !           266:         * Bus power management is beyond control of the SD/SDIO/MMC
        !           267:         * block of the PXA2xx processors, so we have to hand this
        !           268:         * task off to the attachment driver.
        !           269:         */
        !           270:        if (sc->tag.set_power != NULL)
        !           271:                return sc->tag.set_power(sc->tag.cookie, ocr);
        !           272:
        !           273:        DPRINTF(0,("%s: driver lacks set_power() function\n",
        !           274:            sc->sc_dev.dv_xname));
        !           275:        return ENXIO;
        !           276: }
        !           277:
        !           278: int
        !           279: pxammc_bus_clock(sdmmc_chipset_handle_t sch, int freq)
        !           280: {
        !           281:        struct pxammc_softc *sc = sch;
        !           282:        int actfreq = 19500; /* KHz */
        !           283:        int div = 0;
        !           284:        int s;
        !           285:
        !           286:        s = splsdmmc();
        !           287:
        !           288:        /* Stop the clock and wait for the interrupt. */
        !           289:        pxammc_clock_stop(sc);
        !           290:
        !           291:        /* Just stop the clock. */
        !           292:        if (freq == 0) {
        !           293:                splx(s);
        !           294:                return 0;
        !           295:        }
        !           296:
        !           297:        /*
        !           298:         * PXA27x Errata...
        !           299:         *
        !           300:         * <snip>
        !           301:         * E40. SDIO: SDIO Devices Not Working at 19.5 Mbps
        !           302:         *
        !           303:         * SD/SDIO controller can only support up to 9.75 Mbps data
        !           304:         * transfer rate for SDIO card.
        !           305:         * </snip>
        !           306:         *
        !           307:         * If we don't limit the frequency, CRC errors will be
        !           308:         * reported by the controller after we set the bus speed.
        !           309:         * XXX slow down incrementally.
        !           310:         */
        !           311:        if (freq > 9750)
        !           312:                freq = 9750;
        !           313:
        !           314:        /*
        !           315:         * Pick the smallest divider that produces a frequency not
        !           316:         * more than `freq' KHz.
        !           317:         */
        !           318:        while (div < 7) {
        !           319:                if (actfreq <= freq)
        !           320:                        break;
        !           321:                actfreq /= 2;
        !           322:                div++;
        !           323:        }
        !           324:        if (div == 7) {
        !           325:                splx(s);
        !           326:                printf("%s: unsupported bus frequency of %d KHz\n",
        !           327:                    sc->sc_dev.dv_xname, freq);
        !           328:                return -1;
        !           329:        }
        !           330:
        !           331:        DPRINTF(1,("pxammc_bus_clock freq=%d actfreq=%d div=%d\n",
        !           332:            freq, actfreq, div));
        !           333:        sc->sc_clkdiv = div;
        !           334:        pxammc_clock_start(sc);
        !           335:        splx(s);
        !           336:        return 0;
        !           337: }
        !           338:
        !           339: void
        !           340: pxammc_exec_command(sdmmc_chipset_handle_t sch,
        !           341:     struct sdmmc_command *cmd)
        !           342: {
        !           343:        struct pxammc_softc *sc = sch;
        !           344:        u_int32_t cmdat;
        !           345:        int timo;
        !           346:        int s;
        !           347:
        !           348:        DPRINTF(1,("%s: cmd %u arg=%#x data=%#x dlen=%d flags=%#x "
        !           349:            "proc=\"%s\"\n", sc->sc_dev.dv_xname, cmd->c_opcode,
        !           350:            cmd->c_arg, cmd->c_data, cmd->c_datalen, cmd->c_flags,
        !           351:            curproc ? curproc->p_comm : ""));
        !           352:
        !           353:        s = splsdmmc();
        !           354:
        !           355:        /* Stop the bus clock (MMCLK). [15.8.3] */
        !           356:        pxammc_clock_stop(sc);
        !           357:
        !           358:        /* Set the command and argument. */
        !           359:        CSR_WRITE_4(sc, MMC_CMD, cmd->c_opcode);
        !           360:        CSR_WRITE_4(sc, MMC_ARGH, (cmd->c_arg >> 16) & 0xffff);
        !           361:        CSR_WRITE_4(sc, MMC_ARGL, cmd->c_arg & 0xffff);
        !           362:
        !           363:        /* Set response characteristics for this command. */
        !           364:        if (!ISSET(cmd->c_flags, SCF_RSP_PRESENT))
        !           365:                cmdat = CMDAT_RESPONSE_FORMAT_NO;
        !           366:        else if (ISSET(cmd->c_flags, SCF_RSP_136))
        !           367:                cmdat = CMDAT_RESPONSE_FORMAT_R2;
        !           368:        else if (!ISSET(cmd->c_flags, SCF_RSP_CRC))
        !           369:                cmdat = CMDAT_RESPONSE_FORMAT_R3;
        !           370:        else
        !           371:                cmdat = CMDAT_RESPONSE_FORMAT_R1;
        !           372:
        !           373:        if (ISSET(cmd->c_flags, SCF_RSP_BSY))
        !           374:                cmdat |= CMDAT_BUSY;
        !           375:
        !           376:        if (!ISSET(cmd->c_flags, SCF_CMD_READ))
        !           377:                cmdat |= CMDAT_WRITE;
        !           378:
        !           379:        /* Fragment the data into proper blocks. */
        !           380:        if (cmd->c_datalen > 0) {
        !           381:                int blklen = MIN(cmd->c_datalen, cmd->c_blklen);
        !           382:                int numblk = cmd->c_datalen / blklen;
        !           383:
        !           384:                if (cmd->c_datalen % blklen > 0) {
        !           385:                        /* XXX: Split this command. (1.7.4) */
        !           386:                        printf("%s: data not a multiple of %d bytes\n",
        !           387:                            sc->sc_dev.dv_xname, blklen);
        !           388:                        cmd->c_error = EINVAL;
        !           389:                        splx(s);
        !           390:                        return;
        !           391:                }
        !           392:
        !           393:                CSR_WRITE_4(sc, MMC_BLKLEN, blklen);
        !           394:                CSR_WRITE_4(sc, MMC_NUMBLK, numblk);
        !           395:
        !           396:                /* Enable data interrupts. */
        !           397:                CSR_CLR_4(sc, MMC_I_MASK, MMC_I_DATA_TRAN_DONE |
        !           398:                    MMC_I_RXFIFO_RD_REQ | MMC_I_TXFIFO_WR_REQ |
        !           399:                    MMC_I_DAT_ERR);
        !           400:
        !           401:                cmd->c_resid = cmd->c_datalen;
        !           402:                cmd->c_buf = cmd->c_data;
        !           403:
        !           404:                cmdat |= CMDAT_DATA_EN;
        !           405:        } else {
        !           406:                cmd->c_resid = 0;
        !           407:                cmd->c_buf = NULL;
        !           408:        }
        !           409:
        !           410:        /*
        !           411:         * "After reset, the MMC card must be initialized by sending
        !           412:         * 80 clocks to it on the MMCLK signal." [15.4.3.2]
        !           413:         */
        !           414:        if (!ISSET(sc->sc_flags, PMF_CARD_INITED)) {
        !           415:                DPRINTF(1,("%s: first command\n", sc->sc_dev.dv_xname));
        !           416:                cmdat |= CMDAT_INIT;
        !           417:                SET(sc->sc_flags, PMF_CARD_INITED);
        !           418:        }
        !           419:
        !           420:        /* Begin the transfer and start the bus clock. */
        !           421:        CSR_WRITE_4(sc, MMC_CMDAT, cmdat);
        !           422:        pxammc_clock_start(sc);
        !           423:
        !           424:        /* Wait for it to complete (in no more than 2 seconds). */
        !           425:        CSR_CLR_4(sc, MMC_I_MASK, MMC_I_END_CMD_RES | MMC_I_RES_ERR);
        !           426:        timo = 2;
        !           427:        sc->sc_cmd = cmd;
        !           428:        do { tsleep(sc, PWAIT, "mmcmd", hz); }
        !           429:        while (sc->sc_cmd == cmd && timo-- > 0);
        !           430:
        !           431:        /* If it completed in time, SCF_ITSDONE is already set. */
        !           432:        if (sc->sc_cmd == cmd) {
        !           433:                sc->sc_cmd = NULL;
        !           434:                cmd->c_error = ETIMEDOUT;
        !           435:                SET(cmd->c_flags, SCF_ITSDONE);
        !           436:        }
        !           437:        splx(s);
        !           438: }
        !           439:
        !           440: void
        !           441: pxammc_clock_stop(struct pxammc_softc *sc)
        !           442: {
        !           443:        if (ISSET(CSR_READ_4(sc, MMC_STAT), STAT_CLK_EN)) {
        !           444:                CSR_CLR_4(sc, MMC_I_MASK, MMC_I_CLK_IS_OFF);
        !           445:                CSR_WRITE_4(sc, MMC_STRPCL, STRPCL_STOP);
        !           446:                while (ISSET(CSR_READ_4(sc, MMC_STAT), STAT_CLK_EN))
        !           447:                        tsleep(sc, PWAIT, "mmclk", 0);
        !           448:        }
        !           449: }
        !           450:
        !           451: void
        !           452: pxammc_clock_start(struct pxammc_softc *sc)
        !           453: {
        !           454:        CSR_WRITE_4(sc, MMC_CLKRT, sc->sc_clkdiv);
        !           455:        CSR_WRITE_4(sc, MMC_STRPCL, STRPCL_START);
        !           456: }
        !           457:
        !           458: int
        !           459: pxammc_card_intr(void *arg)
        !           460: {
        !           461:        struct pxammc_softc *sc = arg;
        !           462:
        !           463:        DPRINTF(1,("%s: card intr\n", sc->sc_dev.dv_xname));
        !           464:
        !           465:        /* Scan for inserted or removed cards. */
        !           466:        sdmmc_needs_discover(sc->sc_sdmmc);
        !           467:
        !           468:        return 1;
        !           469: }
        !           470:
        !           471: int
        !           472: pxammc_intr(void *arg)
        !           473: {
        !           474:        struct pxammc_softc *sc = arg;
        !           475:        int status;
        !           476:
        !           477: #define MMC_I_REG_STR  "\20\001DATADONE\002PRGDONE\003ENDCMDRES"       \
        !           478:                        "\004STOPCMD\005CLKISOFF\006RXFIFO\007TXFIFO"   \
        !           479:                        "\011DATERR\012RESERR\014SDIO"
        !           480:
        !           481:        status = CSR_READ_4(sc, MMC_I_REG) & ~CSR_READ_4(sc, MMC_I_MASK);
        !           482:        DPRINTF(1,("%s: intr %b\n", sc->sc_dev.dv_xname, status,
        !           483:            MMC_I_REG_STR));
        !           484:
        !           485:        /*
        !           486:         * Notify the process waiting in pxammc_clock_stop() when
        !           487:         * the clock has really stopped.
        !           488:         */
        !           489:        if (ISSET(status, MMC_I_CLK_IS_OFF)) {
        !           490:                DPRINTF(2,("%s: clock is now off\n", sc->sc_dev.dv_xname));
        !           491:                wakeup(sc);
        !           492:                CSR_SET_4(sc, MMC_I_MASK, MMC_I_CLK_IS_OFF);
        !           493:                CLR(status, MMC_I_CLK_IS_OFF);
        !           494:        }
        !           495:
        !           496:        if (sc->sc_cmd == NULL)
        !           497:                goto end;
        !           498:
        !           499:        if (ISSET(status, MMC_I_RES_ERR)) {
        !           500:                CSR_SET_4(sc, MMC_I_MASK, MMC_I_RES_ERR);
        !           501:                CLR(status, MMC_I_RES_ERR | MMC_I_END_CMD_RES);
        !           502:                sc->sc_cmd->c_error = ENOEXEC;
        !           503:                pxammc_intr_done(sc);
        !           504:                goto end;
        !           505:        }
        !           506:
        !           507:        if (ISSET(status, MMC_I_END_CMD_RES)) {
        !           508:                pxammc_intr_cmd(sc);
        !           509:                CSR_SET_4(sc, MMC_I_MASK, MMC_I_END_CMD_RES);
        !           510:                CLR(status, MMC_I_END_CMD_RES);
        !           511:                if (sc->sc_cmd == NULL)
        !           512:                        goto end;
        !           513:        }
        !           514:
        !           515:        if (ISSET(status, MMC_I_TXFIFO_WR_REQ | MMC_I_RXFIFO_RD_REQ)) {
        !           516:                pxammc_intr_data(sc);
        !           517:                CLR(status, MMC_I_TXFIFO_WR_REQ | MMC_I_RXFIFO_RD_REQ);
        !           518:        }
        !           519:
        !           520:        if (ISSET(status, MMC_I_DAT_ERR)) {
        !           521:                sc->sc_cmd->c_error = EIO;
        !           522:                pxammc_intr_done(sc);
        !           523:                CSR_SET_4(sc, MMC_I_MASK, MMC_I_DAT_ERR);
        !           524:                CLR(status, MMC_I_DAT_ERR);
        !           525:                goto end;
        !           526:        }
        !           527:
        !           528:        if (ISSET(status, MMC_I_DATA_TRAN_DONE)) {
        !           529:                pxammc_intr_done(sc);
        !           530:                CSR_SET_4(sc, MMC_I_MASK, MMC_I_DATA_TRAN_DONE);
        !           531:                CLR(status, MMC_I_DATA_TRAN_DONE);
        !           532:        }
        !           533:
        !           534: end:
        !           535:        /* Avoid further unhandled interrupts. */
        !           536:        if (status != 0) {
        !           537: #ifdef DIAGNOSTIC
        !           538:                printf("%s: unhandled interrupt %b\n", sc->sc_dev.dv_xname,
        !           539:                    status, MMC_I_REG_STR);
        !           540: #endif
        !           541:                CSR_SET_4(sc, MMC_I_MASK, status);
        !           542:        }
        !           543:
        !           544:        return 1;
        !           545: }
        !           546:
        !           547: void
        !           548: pxammc_intr_cmd(struct pxammc_softc *sc)
        !           549: {
        !           550:        struct sdmmc_command *cmd = sc->sc_cmd;
        !           551:        u_int32_t status;
        !           552:        int i;
        !           553:
        !           554: #define MMC_STAT_STR   "\20\001READ_TIME_OUT\002TIMEOUT_RESPONSE"      \
        !           555:                        "\003CRC_WRITE_ERROR\004CRC_READ_ERROR"         \
        !           556:                        "\005SPI_READ_ERROR_TOKEN\006RES_CRC_ERR"       \
        !           557:                        "\007XMIT_FIFO_EMPTY\010RECV_FIFO_FULL"         \
        !           558:                        "\011CLK_EN\012FLASH_ERR\013SPI_WR_ERR"         \
        !           559:                        "\014DATA_TRAN_DONE\015PRG_DONE\016END_CMD_RES" \
        !           560:                        "\017RD_STALLED\020SDIO_INT\021SDIO_SUSPEND_ACK"
        !           561:
        !           562: #define STAT_ERR       (STAT_READ_TIME_OUT | STAT_TIMEOUT_RESPONSE |   \
        !           563:                         STAT_CRC_WRITE_ERROR | STAT_CRC_READ_ERROR |   \
        !           564:                         STAT_SPI_READ_ERROR_TOKEN | STAT_RES_CRC_ERR)
        !           565:
        !           566:        if (ISSET(cmd->c_flags, SCF_RSP_136)) {
        !           567:                for (i = 3; i >= 0; i--) {
        !           568:                        u_int32_t h = CSR_READ_4(sc, MMC_RES) & 0xffff;
        !           569:                        u_int32_t l = CSR_READ_4(sc, MMC_RES) & 0xffff;
        !           570:                        cmd->c_resp[i] = (h << 16) | l;
        !           571:                }
        !           572:                cmd->c_error = 0;
        !           573:        } else if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
        !           574:                /*
        !           575:                 * Grrr... The processor manual is not clear about
        !           576:                 * the layout of the response FIFO.  It just states
        !           577:                 * that the FIFO is 16 bits wide, has a depth of 8,
        !           578:                 * and that the CRC is not copied into the FIFO.
        !           579:                 *
        !           580:                 * A 16-bit word in the FIFO is filled from highest
        !           581:                 * to lowest bit as the response comes in.  The two
        !           582:                 * start bits and the 6 command index bits are thus
        !           583:                 * stored in the upper 8 bits of the first 16-bit
        !           584:                 * word that we read back from the FIFO.
        !           585:                 *
        !           586:                 * Since the sdmmc(4) framework expects the host
        !           587:                 * controller to discard the first 8 bits of the
        !           588:                 * response, what we must do is discard the upper
        !           589:                 * byte of the first 16-bit word.
        !           590:                 */
        !           591:                u_int32_t h = CSR_READ_4(sc, MMC_RES) & 0xffff;
        !           592:                u_int32_t m = CSR_READ_4(sc, MMC_RES) & 0xffff;
        !           593:                u_int32_t l = CSR_READ_4(sc, MMC_RES) & 0xffff;
        !           594:                cmd->c_resp[0] = h << 24 | m << 8 | l >> 8;
        !           595:                for (i = 1; i < 4; i++)
        !           596:                        cmd->c_resp[i] = 0;
        !           597:                cmd->c_error = 0;
        !           598:        }
        !           599:
        !           600:        status = CSR_READ_4(sc, MMC_STAT);
        !           601:
        !           602:        if (!ISSET(cmd->c_flags, SCF_RSP_PRESENT))
        !           603:                status &= ~STAT_TIMEOUT_RESPONSE;
        !           604:
        !           605:        /* XXX only for R6, not for R2 */
        !           606:        if (!ISSET(cmd->c_flags, SCF_RSP_IDX))
        !           607:                status &= ~STAT_RES_CRC_ERR;
        !           608:
        !           609:        if (ISSET(status, STAT_TIMEOUT_RESPONSE))
        !           610:                cmd->c_error = ETIMEDOUT;
        !           611:        else if (ISSET(status, STAT_ERR))
        !           612:                cmd->c_error = EIO;
        !           613:
        !           614:        if (cmd->c_error || cmd->c_datalen < 1)
        !           615:                pxammc_intr_done(sc);
        !           616: }
        !           617:
        !           618: void
        !           619: pxammc_intr_data(struct pxammc_softc *sc)
        !           620: {
        !           621:        struct sdmmc_command *cmd = sc->sc_cmd;
        !           622:
        !           623:        DPRINTF(2,("%s: cmd %p resid %d\n", sc->sc_dev.dv_xname,
        !           624:            cmd, cmd->c_resid));
        !           625:
        !           626:        if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
        !           627:                int n;
        !           628:
        !           629:                n = MIN(32, cmd->c_resid);
        !           630:                cmd->c_resid -= n;
        !           631:                while (n-- > 0)
        !           632:                        *cmd->c_buf++ = CSR_READ_1(sc, MMC_RXFIFO);
        !           633:
        !           634:                if (cmd->c_resid > 0)
        !           635:                        CSR_CLR_4(sc, MMC_I_MASK, MMC_I_RXFIFO_RD_REQ);
        !           636:                else
        !           637:                        CSR_SET_4(sc, MMC_I_MASK, MMC_I_RXFIFO_RD_REQ);
        !           638:        } else {
        !           639:                int n;
        !           640:                int short_xfer = cmd->c_resid < 32;
        !           641:
        !           642:                n = MIN(32, cmd->c_resid);
        !           643:                cmd->c_resid -= n;
        !           644:                for (n = MIN(32, cmd->c_resid); n > 0; n--)
        !           645:                        CSR_WRITE_1(sc, MMC_TXFIFO, *cmd->c_buf++);
        !           646:                if (short_xfer)
        !           647:                        CSR_WRITE_4(sc, MMC_PRTBUF, 1);
        !           648:
        !           649:                if (cmd->c_resid > 0)
        !           650:                        CSR_CLR_4(sc, MMC_I_MASK, MMC_I_TXFIFO_WR_REQ);
        !           651:                else
        !           652:                        CSR_SET_4(sc, MMC_I_MASK, MMC_I_TXFIFO_WR_REQ);
        !           653:        }
        !           654: }
        !           655:
        !           656: /*
        !           657:  * Wake up the process sleeping in pxammc_exec_command().
        !           658:  */
        !           659: void
        !           660: pxammc_intr_done(struct pxammc_softc *sc)
        !           661: {
        !           662:        u_int32_t status;
        !           663:
        !           664:        status = CSR_READ_4(sc, MMC_STAT);
        !           665:        DPRINTF(1,("%s: status %b\n", sc->sc_dev.dv_xname,
        !           666:            status, MMC_STAT_STR));
        !           667:
        !           668:        CSR_SET_4(sc, MMC_I_MASK, MMC_I_TXFIFO_WR_REQ |
        !           669:            MMC_I_RXFIFO_RD_REQ | MMC_I_DATA_TRAN_DONE |
        !           670:            MMC_I_END_CMD_RES | MMC_I_RES_ERR | MMC_I_DAT_ERR);
        !           671:
        !           672:        SET(sc->sc_cmd->c_flags, SCF_ITSDONE);
        !           673:        sc->sc_cmd = NULL;
        !           674:        wakeup(sc);
        !           675: }

CVSweb