|
|
1.1 ! root 1: /* ! 2: * Intel XScale PXA255/270 MultiMediaCard/SD/SDIO Controller emulation. ! 3: * ! 4: * Copyright (c) 2006 Openedhand Ltd. ! 5: * Written by Andrzej Zaborowski <[email protected]> ! 6: * ! 7: * This code is licensed under the GPLv2. ! 8: */ ! 9: ! 10: #include "hw.h" ! 11: #include "pxa.h" ! 12: #include "sd.h" ! 13: ! 14: struct pxa2xx_mmci_s { ! 15: target_phys_addr_t base; ! 16: qemu_irq irq; ! 17: void *dma; ! 18: ! 19: SDState *card; ! 20: ! 21: uint32_t status; ! 22: uint32_t clkrt; ! 23: uint32_t spi; ! 24: uint32_t cmdat; ! 25: uint32_t resp_tout; ! 26: uint32_t read_tout; ! 27: int blklen; ! 28: int numblk; ! 29: uint32_t intmask; ! 30: uint32_t intreq; ! 31: int cmd; ! 32: uint32_t arg; ! 33: ! 34: int active; ! 35: int bytesleft; ! 36: uint8_t tx_fifo[64]; ! 37: int tx_start; ! 38: int tx_len; ! 39: uint8_t rx_fifo[32]; ! 40: int rx_start; ! 41: int rx_len; ! 42: uint16_t resp_fifo[9]; ! 43: int resp_len; ! 44: ! 45: int cmdreq; ! 46: int ac_width; ! 47: }; ! 48: ! 49: #define MMC_STRPCL 0x00 /* MMC Clock Start/Stop register */ ! 50: #define MMC_STAT 0x04 /* MMC Status register */ ! 51: #define MMC_CLKRT 0x08 /* MMC Clock Rate register */ ! 52: #define MMC_SPI 0x0c /* MMC SPI Mode register */ ! 53: #define MMC_CMDAT 0x10 /* MMC Command/Data register */ ! 54: #define MMC_RESTO 0x14 /* MMC Response Time-Out register */ ! 55: #define MMC_RDTO 0x18 /* MMC Read Time-Out register */ ! 56: #define MMC_BLKLEN 0x1c /* MMC Block Length register */ ! 57: #define MMC_NUMBLK 0x20 /* MMC Number of Blocks register */ ! 58: #define MMC_PRTBUF 0x24 /* MMC Buffer Partly Full register */ ! 59: #define MMC_I_MASK 0x28 /* MMC Interrupt Mask register */ ! 60: #define MMC_I_REG 0x2c /* MMC Interrupt Request register */ ! 61: #define MMC_CMD 0x30 /* MMC Command register */ ! 62: #define MMC_ARGH 0x34 /* MMC Argument High register */ ! 63: #define MMC_ARGL 0x38 /* MMC Argument Low register */ ! 64: #define MMC_RES 0x3c /* MMC Response FIFO */ ! 65: #define MMC_RXFIFO 0x40 /* MMC Receive FIFO */ ! 66: #define MMC_TXFIFO 0x44 /* MMC Transmit FIFO */ ! 67: #define MMC_RDWAIT 0x48 /* MMC RD_WAIT register */ ! 68: #define MMC_BLKS_REM 0x4c /* MMC Blocks Remaining register */ ! 69: ! 70: /* Bitfield masks */ ! 71: #define STRPCL_STOP_CLK (1 << 0) ! 72: #define STRPCL_STRT_CLK (1 << 1) ! 73: #define STAT_TOUT_RES (1 << 1) ! 74: #define STAT_CLK_EN (1 << 8) ! 75: #define STAT_DATA_DONE (1 << 11) ! 76: #define STAT_PRG_DONE (1 << 12) ! 77: #define STAT_END_CMDRES (1 << 13) ! 78: #define SPI_SPI_MODE (1 << 0) ! 79: #define CMDAT_RES_TYPE (3 << 0) ! 80: #define CMDAT_DATA_EN (1 << 2) ! 81: #define CMDAT_WR_RD (1 << 3) ! 82: #define CMDAT_DMA_EN (1 << 7) ! 83: #define CMDAT_STOP_TRAN (1 << 10) ! 84: #define INT_DATA_DONE (1 << 0) ! 85: #define INT_PRG_DONE (1 << 1) ! 86: #define INT_END_CMD (1 << 2) ! 87: #define INT_STOP_CMD (1 << 3) ! 88: #define INT_CLK_OFF (1 << 4) ! 89: #define INT_RXFIFO_REQ (1 << 5) ! 90: #define INT_TXFIFO_REQ (1 << 6) ! 91: #define INT_TINT (1 << 7) ! 92: #define INT_DAT_ERR (1 << 8) ! 93: #define INT_RES_ERR (1 << 9) ! 94: #define INT_RD_STALLED (1 << 10) ! 95: #define INT_SDIO_INT (1 << 11) ! 96: #define INT_SDIO_SACK (1 << 12) ! 97: #define PRTBUF_PRT_BUF (1 << 0) ! 98: ! 99: /* Route internal interrupt lines to the global IC and DMA */ ! 100: static void pxa2xx_mmci_int_update(struct pxa2xx_mmci_s *s) ! 101: { ! 102: uint32_t mask = s->intmask; ! 103: if (s->cmdat & CMDAT_DMA_EN) { ! 104: mask |= INT_RXFIFO_REQ | INT_TXFIFO_REQ; ! 105: ! 106: pxa2xx_dma_request((struct pxa2xx_dma_state_s *) s->dma, ! 107: PXA2XX_RX_RQ_MMCI, !!(s->intreq & INT_RXFIFO_REQ)); ! 108: pxa2xx_dma_request((struct pxa2xx_dma_state_s *) s->dma, ! 109: PXA2XX_TX_RQ_MMCI, !!(s->intreq & INT_TXFIFO_REQ)); ! 110: } ! 111: ! 112: qemu_set_irq(s->irq, !!(s->intreq & ~mask)); ! 113: } ! 114: ! 115: static void pxa2xx_mmci_fifo_update(struct pxa2xx_mmci_s *s) ! 116: { ! 117: if (!s->active) ! 118: return; ! 119: ! 120: if (s->cmdat & CMDAT_WR_RD) { ! 121: while (s->bytesleft && s->tx_len) { ! 122: sd_write_data(s->card, s->tx_fifo[s->tx_start ++]); ! 123: s->tx_start &= 0x1f; ! 124: s->tx_len --; ! 125: s->bytesleft --; ! 126: } ! 127: if (s->bytesleft) ! 128: s->intreq |= INT_TXFIFO_REQ; ! 129: } else ! 130: while (s->bytesleft && s->rx_len < 32) { ! 131: s->rx_fifo[(s->rx_start + (s->rx_len ++)) & 0x1f] = ! 132: sd_read_data(s->card); ! 133: s->bytesleft --; ! 134: s->intreq |= INT_RXFIFO_REQ; ! 135: } ! 136: ! 137: if (!s->bytesleft) { ! 138: s->active = 0; ! 139: s->intreq |= INT_DATA_DONE; ! 140: s->status |= STAT_DATA_DONE; ! 141: ! 142: if (s->cmdat & CMDAT_WR_RD) { ! 143: s->intreq |= INT_PRG_DONE; ! 144: s->status |= STAT_PRG_DONE; ! 145: } ! 146: } ! 147: ! 148: pxa2xx_mmci_int_update(s); ! 149: } ! 150: ! 151: static void pxa2xx_mmci_wakequeues(struct pxa2xx_mmci_s *s) ! 152: { ! 153: int rsplen, i; ! 154: struct sd_request_s request; ! 155: uint8_t response[16]; ! 156: ! 157: s->active = 1; ! 158: s->rx_len = 0; ! 159: s->tx_len = 0; ! 160: s->cmdreq = 0; ! 161: ! 162: request.cmd = s->cmd; ! 163: request.arg = s->arg; ! 164: request.crc = 0; /* FIXME */ ! 165: ! 166: rsplen = sd_do_command(s->card, &request, response); ! 167: s->intreq |= INT_END_CMD; ! 168: ! 169: memset(s->resp_fifo, 0, sizeof(s->resp_fifo)); ! 170: switch (s->cmdat & CMDAT_RES_TYPE) { ! 171: #define PXAMMCI_RESP(wd, value0, value1) \ ! 172: s->resp_fifo[(wd) + 0] |= (value0); \ ! 173: s->resp_fifo[(wd) + 1] |= (value1) << 8; ! 174: case 0: /* No response */ ! 175: goto complete; ! 176: ! 177: case 1: /* R1, R4, R5 or R6 */ ! 178: if (rsplen < 4) ! 179: goto timeout; ! 180: goto complete; ! 181: ! 182: case 2: /* R2 */ ! 183: if (rsplen < 16) ! 184: goto timeout; ! 185: goto complete; ! 186: ! 187: case 3: /* R3 */ ! 188: if (rsplen < 4) ! 189: goto timeout; ! 190: goto complete; ! 191: ! 192: complete: ! 193: for (i = 0; rsplen > 0; i ++, rsplen -= 2) { ! 194: PXAMMCI_RESP(i, response[i * 2], response[i * 2 + 1]); ! 195: } ! 196: s->status |= STAT_END_CMDRES; ! 197: ! 198: if (!(s->cmdat & CMDAT_DATA_EN)) ! 199: s->active = 0; ! 200: else ! 201: s->bytesleft = s->numblk * s->blklen; ! 202: ! 203: s->resp_len = 0; ! 204: break; ! 205: ! 206: timeout: ! 207: s->active = 0; ! 208: s->status |= STAT_TOUT_RES; ! 209: break; ! 210: } ! 211: ! 212: pxa2xx_mmci_fifo_update(s); ! 213: } ! 214: ! 215: static uint32_t pxa2xx_mmci_read(void *opaque, target_phys_addr_t offset) ! 216: { ! 217: struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; ! 218: uint32_t ret; ! 219: offset -= s->base; ! 220: ! 221: switch (offset) { ! 222: case MMC_STRPCL: ! 223: return 0; ! 224: case MMC_STAT: ! 225: return s->status; ! 226: case MMC_CLKRT: ! 227: return s->clkrt; ! 228: case MMC_SPI: ! 229: return s->spi; ! 230: case MMC_CMDAT: ! 231: return s->cmdat; ! 232: case MMC_RESTO: ! 233: return s->resp_tout; ! 234: case MMC_RDTO: ! 235: return s->read_tout; ! 236: case MMC_BLKLEN: ! 237: return s->blklen; ! 238: case MMC_NUMBLK: ! 239: return s->numblk; ! 240: case MMC_PRTBUF: ! 241: return 0; ! 242: case MMC_I_MASK: ! 243: return s->intmask; ! 244: case MMC_I_REG: ! 245: return s->intreq; ! 246: case MMC_CMD: ! 247: return s->cmd | 0x40; ! 248: case MMC_ARGH: ! 249: return s->arg >> 16; ! 250: case MMC_ARGL: ! 251: return s->arg & 0xffff; ! 252: case MMC_RES: ! 253: if (s->resp_len < 9) ! 254: return s->resp_fifo[s->resp_len ++]; ! 255: return 0; ! 256: case MMC_RXFIFO: ! 257: ret = 0; ! 258: while (s->ac_width -- && s->rx_len) { ! 259: ret |= s->rx_fifo[s->rx_start ++] << (s->ac_width << 3); ! 260: s->rx_start &= 0x1f; ! 261: s->rx_len --; ! 262: } ! 263: s->intreq &= ~INT_RXFIFO_REQ; ! 264: pxa2xx_mmci_fifo_update(s); ! 265: return ret; ! 266: case MMC_RDWAIT: ! 267: return 0; ! 268: case MMC_BLKS_REM: ! 269: return s->numblk; ! 270: default: ! 271: cpu_abort(cpu_single_env, "%s: Bad offset " REG_FMT "\n", ! 272: __FUNCTION__, offset); ! 273: } ! 274: ! 275: return 0; ! 276: } ! 277: ! 278: static void pxa2xx_mmci_write(void *opaque, ! 279: target_phys_addr_t offset, uint32_t value) ! 280: { ! 281: struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; ! 282: offset -= s->base; ! 283: ! 284: switch (offset) { ! 285: case MMC_STRPCL: ! 286: if (value & STRPCL_STRT_CLK) { ! 287: s->status |= STAT_CLK_EN; ! 288: s->intreq &= ~INT_CLK_OFF; ! 289: ! 290: if (s->cmdreq && !(s->cmdat & CMDAT_STOP_TRAN)) { ! 291: s->status &= STAT_CLK_EN; ! 292: pxa2xx_mmci_wakequeues(s); ! 293: } ! 294: } ! 295: ! 296: if (value & STRPCL_STOP_CLK) { ! 297: s->status &= ~STAT_CLK_EN; ! 298: s->intreq |= INT_CLK_OFF; ! 299: s->active = 0; ! 300: } ! 301: ! 302: pxa2xx_mmci_int_update(s); ! 303: break; ! 304: ! 305: case MMC_CLKRT: ! 306: s->clkrt = value & 7; ! 307: break; ! 308: ! 309: case MMC_SPI: ! 310: s->spi = value & 0xf; ! 311: if (value & SPI_SPI_MODE) ! 312: printf("%s: attempted to use card in SPI mode\n", __FUNCTION__); ! 313: break; ! 314: ! 315: case MMC_CMDAT: ! 316: s->cmdat = value & 0x3dff; ! 317: s->active = 0; ! 318: s->cmdreq = 1; ! 319: if (!(value & CMDAT_STOP_TRAN)) { ! 320: s->status &= STAT_CLK_EN; ! 321: ! 322: if (s->status & STAT_CLK_EN) ! 323: pxa2xx_mmci_wakequeues(s); ! 324: } ! 325: ! 326: pxa2xx_mmci_int_update(s); ! 327: break; ! 328: ! 329: case MMC_RESTO: ! 330: s->resp_tout = value & 0x7f; ! 331: break; ! 332: ! 333: case MMC_RDTO: ! 334: s->read_tout = value & 0xffff; ! 335: break; ! 336: ! 337: case MMC_BLKLEN: ! 338: s->blklen = value & 0xfff; ! 339: break; ! 340: ! 341: case MMC_NUMBLK: ! 342: s->numblk = value & 0xffff; ! 343: break; ! 344: ! 345: case MMC_PRTBUF: ! 346: if (value & PRTBUF_PRT_BUF) { ! 347: s->tx_start ^= 32; ! 348: s->tx_len = 0; ! 349: } ! 350: pxa2xx_mmci_fifo_update(s); ! 351: break; ! 352: ! 353: case MMC_I_MASK: ! 354: s->intmask = value & 0x1fff; ! 355: pxa2xx_mmci_int_update(s); ! 356: break; ! 357: ! 358: case MMC_CMD: ! 359: s->cmd = value & 0x3f; ! 360: break; ! 361: ! 362: case MMC_ARGH: ! 363: s->arg &= 0x0000ffff; ! 364: s->arg |= value << 16; ! 365: break; ! 366: ! 367: case MMC_ARGL: ! 368: s->arg &= 0xffff0000; ! 369: s->arg |= value & 0x0000ffff; ! 370: break; ! 371: ! 372: case MMC_TXFIFO: ! 373: while (s->ac_width -- && s->tx_len < 0x20) ! 374: s->tx_fifo[(s->tx_start + (s->tx_len ++)) & 0x1f] = ! 375: (value >> (s->ac_width << 3)) & 0xff; ! 376: s->intreq &= ~INT_TXFIFO_REQ; ! 377: pxa2xx_mmci_fifo_update(s); ! 378: break; ! 379: ! 380: case MMC_RDWAIT: ! 381: case MMC_BLKS_REM: ! 382: break; ! 383: ! 384: default: ! 385: cpu_abort(cpu_single_env, "%s: Bad offset " REG_FMT "\n", ! 386: __FUNCTION__, offset); ! 387: } ! 388: } ! 389: ! 390: static uint32_t pxa2xx_mmci_readb(void *opaque, target_phys_addr_t offset) ! 391: { ! 392: struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; ! 393: s->ac_width = 1; ! 394: return pxa2xx_mmci_read(opaque, offset); ! 395: } ! 396: ! 397: static uint32_t pxa2xx_mmci_readh(void *opaque, target_phys_addr_t offset) ! 398: { ! 399: struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; ! 400: s->ac_width = 2; ! 401: return pxa2xx_mmci_read(opaque, offset); ! 402: } ! 403: ! 404: static uint32_t pxa2xx_mmci_readw(void *opaque, target_phys_addr_t offset) ! 405: { ! 406: struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; ! 407: s->ac_width = 4; ! 408: return pxa2xx_mmci_read(opaque, offset); ! 409: } ! 410: ! 411: static CPUReadMemoryFunc *pxa2xx_mmci_readfn[] = { ! 412: pxa2xx_mmci_readb, ! 413: pxa2xx_mmci_readh, ! 414: pxa2xx_mmci_readw ! 415: }; ! 416: ! 417: static void pxa2xx_mmci_writeb(void *opaque, ! 418: target_phys_addr_t offset, uint32_t value) ! 419: { ! 420: struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; ! 421: s->ac_width = 1; ! 422: pxa2xx_mmci_write(opaque, offset, value); ! 423: } ! 424: ! 425: static void pxa2xx_mmci_writeh(void *opaque, ! 426: target_phys_addr_t offset, uint32_t value) ! 427: { ! 428: struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; ! 429: s->ac_width = 2; ! 430: pxa2xx_mmci_write(opaque, offset, value); ! 431: } ! 432: ! 433: static void pxa2xx_mmci_writew(void *opaque, ! 434: target_phys_addr_t offset, uint32_t value) ! 435: { ! 436: struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; ! 437: s->ac_width = 4; ! 438: pxa2xx_mmci_write(opaque, offset, value); ! 439: } ! 440: ! 441: static CPUWriteMemoryFunc *pxa2xx_mmci_writefn[] = { ! 442: pxa2xx_mmci_writeb, ! 443: pxa2xx_mmci_writeh, ! 444: pxa2xx_mmci_writew ! 445: }; ! 446: ! 447: static void pxa2xx_mmci_save(QEMUFile *f, void *opaque) ! 448: { ! 449: struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; ! 450: int i; ! 451: ! 452: qemu_put_be32s(f, &s->status); ! 453: qemu_put_be32s(f, &s->clkrt); ! 454: qemu_put_be32s(f, &s->spi); ! 455: qemu_put_be32s(f, &s->cmdat); ! 456: qemu_put_be32s(f, &s->resp_tout); ! 457: qemu_put_be32s(f, &s->read_tout); ! 458: qemu_put_be32(f, s->blklen); ! 459: qemu_put_be32(f, s->numblk); ! 460: qemu_put_be32s(f, &s->intmask); ! 461: qemu_put_be32s(f, &s->intreq); ! 462: qemu_put_be32(f, s->cmd); ! 463: qemu_put_be32s(f, &s->arg); ! 464: qemu_put_be32(f, s->cmdreq); ! 465: qemu_put_be32(f, s->active); ! 466: qemu_put_be32(f, s->bytesleft); ! 467: ! 468: qemu_put_byte(f, s->tx_len); ! 469: for (i = 0; i < s->tx_len; i ++) ! 470: qemu_put_byte(f, s->tx_fifo[(s->tx_start + i) & 63]); ! 471: ! 472: qemu_put_byte(f, s->rx_len); ! 473: for (i = 0; i < s->rx_len; i ++) ! 474: qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 31]); ! 475: ! 476: qemu_put_byte(f, s->resp_len); ! 477: for (i = s->resp_len; i < 9; i ++) ! 478: qemu_put_be16s(f, &s->resp_fifo[i]); ! 479: } ! 480: ! 481: static int pxa2xx_mmci_load(QEMUFile *f, void *opaque, int version_id) ! 482: { ! 483: struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; ! 484: int i; ! 485: ! 486: qemu_get_be32s(f, &s->status); ! 487: qemu_get_be32s(f, &s->clkrt); ! 488: qemu_get_be32s(f, &s->spi); ! 489: qemu_get_be32s(f, &s->cmdat); ! 490: qemu_get_be32s(f, &s->resp_tout); ! 491: qemu_get_be32s(f, &s->read_tout); ! 492: s->blklen = qemu_get_be32(f); ! 493: s->numblk = qemu_get_be32(f); ! 494: qemu_get_be32s(f, &s->intmask); ! 495: qemu_get_be32s(f, &s->intreq); ! 496: s->cmd = qemu_get_be32(f); ! 497: qemu_get_be32s(f, &s->arg); ! 498: s->cmdreq = qemu_get_be32(f); ! 499: s->active = qemu_get_be32(f); ! 500: s->bytesleft = qemu_get_be32(f); ! 501: ! 502: s->tx_len = qemu_get_byte(f); ! 503: s->tx_start = 0; ! 504: if (s->tx_len >= sizeof(s->tx_fifo) || s->tx_len < 0) ! 505: return -EINVAL; ! 506: for (i = 0; i < s->tx_len; i ++) ! 507: s->tx_fifo[i] = qemu_get_byte(f); ! 508: ! 509: s->rx_len = qemu_get_byte(f); ! 510: s->rx_start = 0; ! 511: if (s->rx_len >= sizeof(s->rx_fifo) || s->rx_len < 0) ! 512: return -EINVAL; ! 513: for (i = 0; i < s->rx_len; i ++) ! 514: s->rx_fifo[i] = qemu_get_byte(f); ! 515: ! 516: s->resp_len = qemu_get_byte(f); ! 517: if (s->resp_len > 9 || s->resp_len < 0) ! 518: return -EINVAL; ! 519: for (i = s->resp_len; i < 9; i ++) ! 520: qemu_get_be16s(f, &s->resp_fifo[i]); ! 521: ! 522: return 0; ! 523: } ! 524: ! 525: struct pxa2xx_mmci_s *pxa2xx_mmci_init(target_phys_addr_t base, ! 526: BlockDriverState *bd, qemu_irq irq, void *dma) ! 527: { ! 528: int iomemtype; ! 529: struct pxa2xx_mmci_s *s; ! 530: ! 531: s = (struct pxa2xx_mmci_s *) qemu_mallocz(sizeof(struct pxa2xx_mmci_s)); ! 532: s->base = base; ! 533: s->irq = irq; ! 534: s->dma = dma; ! 535: ! 536: iomemtype = cpu_register_io_memory(0, pxa2xx_mmci_readfn, ! 537: pxa2xx_mmci_writefn, s); ! 538: cpu_register_physical_memory(base, 0x00100000, iomemtype); ! 539: ! 540: /* Instantiate the actual storage */ ! 541: s->card = sd_init(bd, 0); ! 542: ! 543: register_savevm("pxa2xx_mmci", 0, 0, ! 544: pxa2xx_mmci_save, pxa2xx_mmci_load, s); ! 545: ! 546: return s; ! 547: } ! 548: ! 549: void pxa2xx_mmci_handlers(struct pxa2xx_mmci_s *s, qemu_irq readonly, ! 550: qemu_irq coverswitch) ! 551: { ! 552: sd_set_cb(s->card, readonly, coverswitch); ! 553: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.