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