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