Commit b30bb3a2e8ebb138494eca055bab75a4ac9c0a26

Authored by balrog
1 parent 1af2b62d

Add OMAP MMC/SD host controller.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3097 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile.target
... ... @@ -463,7 +463,7 @@ VL_OBJS+= arm-semi.o
463 463 VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
464 464 VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o max111x.o max7310.o
465 465 VL_OBJS+= spitz.o ads7846.o ide.o serial.o nand.o $(AUDIODRV) wm8750.o
466   -VL_OBJS+= omap.o omap_lcdc.o omap1_clk.o palm.o
  466 +VL_OBJS+= omap.o omap_lcdc.o omap1_clk.o omap_mmc.o palm.o
467 467 CPPFLAGS += -DHAS_AUDIO
468 468 endif
469 469 ifeq ($(TARGET_BASE_ARCH), sh4)
... ...
hw/omap.c
... ... @@ -22,25 +22,25 @@
22 22 #include "arm_pic.h"
23 23  
24 24 /* Should signal the TCMI */
25   -static uint32_t omap_badwidth_read16(void *opaque, target_phys_addr_t addr)
  25 +uint32_t omap_badwidth_read16(void *opaque, target_phys_addr_t addr)
26 26 {
27 27 OMAP_16B_REG(addr);
28 28 return 0;
29 29 }
30 30  
31   -static void omap_badwidth_write16(void *opaque, target_phys_addr_t addr,
  31 +void omap_badwidth_write16(void *opaque, target_phys_addr_t addr,
32 32 uint32_t value)
33 33 {
34 34 OMAP_16B_REG(addr);
35 35 }
36 36  
37   -static uint32_t omap_badwidth_read32(void *opaque, target_phys_addr_t addr)
  37 +uint32_t omap_badwidth_read32(void *opaque, target_phys_addr_t addr)
38 38 {
39 39 OMAP_32B_REG(addr);
40 40 return 0;
41 41 }
42 42  
43   -static void omap_badwidth_write32(void *opaque, target_phys_addr_t addr,
  43 +void omap_badwidth_write32(void *opaque, target_phys_addr_t addr,
44 44 uint32_t value)
45 45 {
46 46 OMAP_32B_REG(addr);
... ... @@ -2816,6 +2816,7 @@ static void omap_mpu_reset(void *opaque)
2816 2816 omap_uart_reset(mpu->uart1);
2817 2817 omap_uart_reset(mpu->uart2);
2818 2818 omap_uart_reset(mpu->uart3);
  2819 + omap_mmc_reset(mpu->mmc);
2819 2820 cpu_reset(mpu->env);
2820 2821 }
2821 2822  
... ... @@ -2921,6 +2922,9 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
2921 2922 omap_dpll_init(&s->dpll[1], 0xfffed000, omap_findclk(s, "dpll2"));
2922 2923 omap_dpll_init(&s->dpll[2], 0xfffed100, omap_findclk(s, "dpll3"));
2923 2924  
  2925 + s->mmc = omap_mmc_init(0xfffb7800, s->irq[1][OMAP_INT_OQN],
  2926 + &s->drq[OMAP_DMA_MMC_TX], omap_findclk(s, "mmc_ck"));
  2927 +
2924 2928 qemu_register_reset(omap_mpu_reset, s);
2925 2929 s->wakeup = qemu_allocate_irqs(omap_mpu_wakeup, s, 1)[0];
2926 2930  
... ...
hw/omap.h
... ... @@ -163,7 +163,7 @@ struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base,
163 163 # define OMAP_INT_USB_W2FC 20
164 164 # define OMAP_INT_1WIRE 21
165 165 # define OMAP_INT_OS_TIMER 22
166   -# define OMAP_INT_MMC 23
  166 +# define OMAP_INT_OQN 23
167 167 # define OMAP_INT_GAUGE_32K 24
168 168 # define OMAP_INT_RTC_TIMER 25
169 169 # define OMAP_INT_RTC_ALARM 26
... ... @@ -457,6 +457,12 @@ struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq,
457 457 struct omap_dma_lcd_channel_s *dma, DisplayState *ds,
458 458 ram_addr_t imif_base, ram_addr_t emiff_base, omap_clk clk);
459 459  
  460 +/* omap_mmc.c */
  461 +struct omap_mmc_s;
  462 +struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base,
  463 + qemu_irq irq, qemu_irq dma[], omap_clk clk);
  464 +void omap_mmc_reset(struct omap_mmc_s *s);
  465 +
460 466 # define cpu_is_omap310(cpu) (cpu->mpu_model == omap310)
461 467 # define cpu_is_omap1510(cpu) (cpu->mpu_model == omap1510)
462 468 # define cpu_is_omap15xx(cpu) \
... ... @@ -497,6 +503,8 @@ struct omap_mpu_state_s {
497 503 struct omap_uart_s *uart1;
498 504 struct omap_uart_s *uart2;
499 505  
  506 + struct omap_mmc_s *mmc;
  507 +
500 508 /* MPU private TIPB peripherals */
501 509 struct omap_intr_handler_s *ih[2];
502 510  
... ... @@ -566,6 +574,13 @@ struct omap_mpu_state_s {
566 574 # error TARGET_PHYS_ADDR_BITS undefined
567 575 # endif
568 576  
  577 +uint32_t omap_badwidth_read16(void *opaque, target_phys_addr_t addr);
  578 +void omap_badwidth_write16(void *opaque, target_phys_addr_t addr,
  579 + uint32_t value);
  580 +uint32_t omap_badwidth_read32(void *opaque, target_phys_addr_t addr);
  581 +void omap_badwidth_write32(void *opaque, target_phys_addr_t addr,
  582 + uint32_t value);
  583 +
569 584 # define OMAP_BAD_REG(paddr) \
570 585 printf("%s: Bad register " OMAP_FMT_plx "\n", __FUNCTION__, paddr)
571 586 # define OMAP_RO_REG(paddr) \
... ...
hw/omap_mmc.c 0 โ†’ 100644
  1 +/*
  2 + * OMAP on-chip MMC/SD host emulation.
  3 + *
  4 + * Copyright (C) 2006-2007 Andrzej Zaborowski <balrog@zabor.org>
  5 + *
  6 + * This program is free software; you can redistribute it and/or
  7 + * modify it under the terms of the GNU General Public License as
  8 + * published by the Free Software Foundation; either version 2 of
  9 + * the License, or (at your option) any later version.
  10 + *
  11 + * This program is distributed in the hope that it will be useful,
  12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14 + * GNU General Public License for more details.
  15 + *
  16 + * You should have received a copy of the GNU General Public License
  17 + * along with this program; if not, write to the Free Software
  18 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  19 + * MA 02111-1307 USA
  20 + */
  21 +#include "vl.h"
  22 +#include "sd.h"
  23 +
  24 +struct omap_mmc_s {
  25 + target_phys_addr_t base;
  26 + qemu_irq irq;
  27 + qemu_irq *dma;
  28 + omap_clk clk;
  29 + SDState *card;
  30 + uint16_t last_cmd;
  31 + uint16_t sdio;
  32 + uint16_t rsp[8];
  33 + uint32_t arg;
  34 + int dw;
  35 + int mode;
  36 + int enable;
  37 + uint16_t status;
  38 + uint16_t mask;
  39 + uint8_t cto;
  40 + uint16_t dto;
  41 + uint16_t fifo[32];
  42 + int fifo_start;
  43 + int fifo_len;
  44 + uint16_t blen;
  45 + uint16_t blen_counter;
  46 + uint16_t nblk;
  47 + uint16_t nblk_counter;
  48 + int tx_dma;
  49 + int rx_dma;
  50 + int af_level;
  51 + int ae_level;
  52 +
  53 + int ddir;
  54 + int transfer;
  55 +};
  56 +
  57 +static void omap_mmc_interrupts_update(struct omap_mmc_s *s)
  58 +{
  59 + qemu_set_irq(s->irq, !!(s->status & s->mask));
  60 +}
  61 +
  62 +static void omap_mmc_fifolevel_update(struct omap_mmc_s *host)
  63 +{
  64 + if (!host->transfer && !host->fifo_len) {
  65 + host->status &= 0xf3ff;
  66 + return;
  67 + }
  68 +
  69 + if (host->fifo_len > host->af_level && host->ddir) {
  70 + if (host->rx_dma) {
  71 + host->status &= 0xfbff;
  72 + qemu_irq_raise(host->dma[1]);
  73 + } else
  74 + host->status |= 0x0400;
  75 + } else {
  76 + host->status &= 0xfbff;
  77 + qemu_irq_lower(host->dma[1]);
  78 + }
  79 +
  80 + if (host->fifo_len < host->ae_level && !host->ddir) {
  81 + if (host->tx_dma) {
  82 + host->status &= 0xf7ff;
  83 + qemu_irq_raise(host->dma[0]);
  84 + } else
  85 + host->status |= 0x0800;
  86 + } else {
  87 + qemu_irq_lower(host->dma[0]);
  88 + host->status &= 0xf7ff;
  89 + }
  90 +}
  91 +
  92 +typedef enum {
  93 + sd_nore = 0, /* no response */
  94 + sd_r1, /* normal response command */
  95 + sd_r2, /* CID, CSD registers */
  96 + sd_r3, /* OCR register */
  97 + sd_r6 = 6, /* Published RCA response */
  98 + sd_r1b = -1,
  99 +} sd_rsp_type_t;
  100 +
  101 +static void omap_mmc_command(struct omap_mmc_s *host, int cmd, int dir,
  102 + sd_cmd_type_t type, int busy, sd_rsp_type_t resptype, int init)
  103 +{
  104 + uint32_t rspstatus, mask;
  105 + int rsplen, timeout;
  106 + struct sd_request_s request;
  107 + uint8_t response[16];
  108 +
  109 + if (resptype == sd_r1 && busy)
  110 + resptype = sd_r1b;
  111 +
  112 + if (type == sd_adtc) {
  113 + host->fifo_start = 0;
  114 + host->fifo_len = 0;
  115 + host->transfer = 1;
  116 + host->ddir = dir;
  117 + } else
  118 + host->transfer = 0;
  119 + timeout = 0;
  120 + mask = 0;
  121 + rspstatus = 0;
  122 +
  123 + request.cmd = cmd;
  124 + request.arg = host->arg;
  125 + request.crc = 0; /* FIXME */
  126 +
  127 + rsplen = sd_do_command(host->card, &request, response);
  128 +
  129 + /* TODO: validate CRCs */
  130 + switch (resptype) {
  131 + case sd_nore:
  132 + rsplen = 0;
  133 + break;
  134 +
  135 + case sd_r1:
  136 + case sd_r1b:
  137 + if (rsplen < 4) {
  138 + timeout = 1;
  139 + break;
  140 + }
  141 + rsplen = 4;
  142 +
  143 + mask = OUT_OF_RANGE | ADDRESS_ERROR | BLOCK_LEN_ERROR |
  144 + ERASE_SEQ_ERROR | ERASE_PARAM | WP_VIOLATION |
  145 + LOCK_UNLOCK_FAILED | COM_CRC_ERROR | ILLEGAL_COMMAND |
  146 + CARD_ECC_FAILED | CC_ERROR | SD_ERROR |
  147 + CID_CSD_OVERWRITE;
  148 + if (host->sdio & (1 << 13))
  149 + mask |= AKE_SEQ_ERROR;
  150 + rspstatus = (response[0] << 24) | (response[1] << 16) |
  151 + (response[2] << 8) | (response[3] << 0);
  152 + break;
  153 +
  154 + case sd_r2:
  155 + if (rsplen < 16) {
  156 + timeout = 1;
  157 + break;
  158 + }
  159 + rsplen = 16;
  160 + break;
  161 +
  162 + case sd_r3:
  163 + if (rsplen < 4) {
  164 + timeout = 1;
  165 + break;
  166 + }
  167 + rsplen = 4;
  168 +
  169 + rspstatus = (response[0] << 24) | (response[1] << 16) |
  170 + (response[2] << 8) | (response[3] << 0);
  171 + if (rspstatus & 0x80000000)
  172 + host->status &= 0xe000;
  173 + else
  174 + host->status |= 0x1000;
  175 + break;
  176 +
  177 + case sd_r6:
  178 + if (rsplen < 4) {
  179 + timeout = 1;
  180 + break;
  181 + }
  182 + rsplen = 4;
  183 +
  184 + mask = 0xe000 | AKE_SEQ_ERROR;
  185 + rspstatus = (response[2] << 8) | (response[3] << 0);
  186 + }
  187 +
  188 + if (rspstatus & mask)
  189 + host->status |= 0x4000;
  190 + else
  191 + host->status &= 0xb000;
  192 +
  193 + if (rsplen)
  194 + for (rsplen = 0; rsplen < 8; rsplen ++)
  195 + host->rsp[~rsplen & 7] = response[(rsplen << 1) | 1] |
  196 + (response[(rsplen << 1) | 0] << 8);
  197 +
  198 + if (timeout)
  199 + host->status |= 0x0080;
  200 + else if (cmd == 12)
  201 + host->status |= 0x0005; /* Makes it more real */
  202 + else
  203 + host->status |= 0x0001;
  204 +}
  205 +
  206 +static void omap_mmc_transfer(struct omap_mmc_s *host)
  207 +{
  208 + uint8_t value;
  209 +
  210 + if (!host->transfer)
  211 + return;
  212 +
  213 + while (1) {
  214 + if (host->ddir) {
  215 + if (host->fifo_len > host->af_level)
  216 + break;
  217 +
  218 + value = sd_read_data(host->card);
  219 + host->fifo[(host->fifo_start + host->fifo_len) & 31] = value;
  220 + if (-- host->blen_counter) {
  221 + value = sd_read_data(host->card);
  222 + host->fifo[(host->fifo_start + host->fifo_len) & 31] |=
  223 + value << 8;
  224 + host->blen_counter --;
  225 + }
  226 +
  227 + host->fifo_len ++;
  228 + } else {
  229 + if (!host->fifo_len)
  230 + break;
  231 +
  232 + value = host->fifo[host->fifo_start] & 0xff;
  233 + sd_write_data(host->card, value);
  234 + if (-- host->blen_counter) {
  235 + value = host->fifo[host->fifo_start] >> 8;
  236 + sd_write_data(host->card, value);
  237 + host->blen_counter --;
  238 + }
  239 +
  240 + host->fifo_start ++;
  241 + host->fifo_len --;
  242 + host->fifo_start &= 31;
  243 + }
  244 +
  245 + if (host->blen_counter == 0) {
  246 + host->nblk_counter --;
  247 + host->blen_counter = host->blen;
  248 +
  249 + if (host->nblk_counter == 0) {
  250 + host->nblk_counter = host->nblk;
  251 + host->transfer = 0;
  252 + host->status |= 0x0008;
  253 + break;
  254 + }
  255 + }
  256 + }
  257 +}
  258 +
  259 +static void omap_mmc_update(void *opaque)
  260 +{
  261 + struct omap_mmc_s *s = opaque;
  262 + omap_mmc_transfer(s);
  263 + omap_mmc_fifolevel_update(s);
  264 + omap_mmc_interrupts_update(s);
  265 +}
  266 +
  267 +static uint32_t omap_mmc_read(void *opaque, target_phys_addr_t offset)
  268 +{
  269 + uint16_t i;
  270 + struct omap_mmc_s *s = (struct omap_mmc_s *) opaque;
  271 + offset -= s->base;
  272 +
  273 + switch (offset) {
  274 + case 0x00: /* MMC_CMD */
  275 + return s->last_cmd;
  276 +
  277 + case 0x04: /* MMC_ARGL */
  278 + return s->arg & 0x0000ffff;
  279 +
  280 + case 0x08: /* MMC_ARGH */
  281 + return s->arg >> 16;
  282 +
  283 + case 0x0c: /* MMC_CON */
  284 + return (s->dw << 15) | (s->mode << 12) | (s->enable << 11);
  285 +
  286 + case 0x10: /* MMC_STAT */
  287 + return s->status;
  288 +
  289 + case 0x14: /* MMC_IE */
  290 + return s->mask;
  291 +
  292 + case 0x18: /* MMC_CTO */
  293 + return s->cto;
  294 +
  295 + case 0x1c: /* MMC_DTO */
  296 + return s->dto;
  297 +
  298 + case 0x20: /* MMC_DATA */
  299 + /* TODO: support 8-bit access */
  300 + i = s->fifo[s->fifo_start];
  301 + if (s->fifo_len == 0) {
  302 + printf("MMC: FIFO underrun\n");
  303 + return i;
  304 + }
  305 + s->fifo_start ++;
  306 + s->fifo_len --;
  307 + s->fifo_start &= 31;
  308 + omap_mmc_transfer(s);
  309 + omap_mmc_fifolevel_update(s);
  310 + omap_mmc_interrupts_update(s);
  311 + return i;
  312 +
  313 + case 0x24: /* MMC_BLEN */
  314 + return s->blen_counter;
  315 +
  316 + case 0x28: /* MMC_NBLK */
  317 + return s->nblk_counter;
  318 +
  319 + case 0x2c: /* MMC_BUF */
  320 + return (s->rx_dma << 15) | (s->af_level << 8) |
  321 + (s->tx_dma << 7) | s->ae_level;
  322 +
  323 + case 0x30: /* MMC_SPI */
  324 + return 0x0000;
  325 + case 0x34: /* MMC_SDIO */
  326 + return s->sdio;
  327 + case 0x38: /* MMC_SYST */
  328 + return 0x0000;
  329 +
  330 + case 0x3c: /* MMC_REV */
  331 + return 0x0001;
  332 +
  333 + case 0x40: /* MMC_RSP0 */
  334 + case 0x44: /* MMC_RSP1 */
  335 + case 0x48: /* MMC_RSP2 */
  336 + case 0x4c: /* MMC_RSP3 */
  337 + case 0x50: /* MMC_RSP4 */
  338 + case 0x54: /* MMC_RSP5 */
  339 + case 0x58: /* MMC_RSP6 */
  340 + case 0x5c: /* MMC_RSP7 */
  341 + return s->rsp[(offset - 0x40) >> 2];
  342 + }
  343 +
  344 + OMAP_BAD_REG(offset);
  345 + return 0;
  346 +}
  347 +
  348 +static void omap_mmc_write(void *opaque, target_phys_addr_t offset,
  349 + uint32_t value)
  350 +{
  351 + int i;
  352 + struct omap_mmc_s *s = (struct omap_mmc_s *) opaque;
  353 + offset -= s->base;
  354 +
  355 + switch (offset) {
  356 + case 0x00: /* MMC_CMD */
  357 + if (!s->enable)
  358 + break;
  359 +
  360 + s->last_cmd = value;
  361 + for (i = 0; i < 8; i ++)
  362 + s->rsp[i] = 0x0000;
  363 + omap_mmc_command(s, value & 63, (value >> 15) & 1,
  364 + (sd_cmd_type_t) ((value >> 12) & 3),
  365 + (value >> 11) & 1,
  366 + (sd_rsp_type_t) ((value >> 8) & 7),
  367 + (value >> 7) & 1);
  368 + omap_mmc_update(s);
  369 + break;
  370 +
  371 + case 0x04: /* MMC_ARGL */
  372 + s->arg &= 0xffff0000;
  373 + s->arg |= 0x0000ffff & value;
  374 + break;
  375 +
  376 + case 0x08: /* MMC_ARGH */
  377 + s->arg &= 0x0000ffff;
  378 + s->arg |= value << 16;
  379 + break;
  380 +
  381 + case 0x0c: /* MMC_CON */
  382 + s->dw = (value >> 15) & 1;
  383 + s->mode = (value >> 12) & 3;
  384 + s->enable = (value >> 11) & 1;
  385 + if (s->mode != 0)
  386 + printf("SD mode %i unimplemented!\n", s->mode);
  387 + if (s->dw != 0)
  388 + printf("4-bit SD bus enabled\n");
  389 + break;
  390 +
  391 + case 0x10: /* MMC_STAT */
  392 + s->status &= ~value;
  393 + omap_mmc_interrupts_update(s);
  394 + break;
  395 +
  396 + case 0x14: /* MMC_IE */
  397 + s->mask = value;
  398 + omap_mmc_interrupts_update(s);
  399 + break;
  400 +
  401 + case 0x18: /* MMC_CTO */
  402 + s->cto = value & 0xff;
  403 + if (s->cto > 0xfd)
  404 + printf("MMC: CTO of 0xff and 0xfe cannot be used!\n");
  405 + break;
  406 +
  407 + case 0x1c: /* MMC_DTO */
  408 + s->dto = value & 0xffff;
  409 + break;
  410 +
  411 + case 0x20: /* MMC_DATA */
  412 + /* TODO: support 8-bit access */
  413 + if (s->fifo_len == 32)
  414 + break;
  415 + s->fifo[(s->fifo_start + s->fifo_len) & 31] = value;
  416 + s->fifo_len ++;
  417 + omap_mmc_transfer(s);
  418 + omap_mmc_fifolevel_update(s);
  419 + omap_mmc_interrupts_update(s);
  420 + break;
  421 +
  422 + case 0x24: /* MMC_BLEN */
  423 + s->blen = (value & 0x07ff) + 1;
  424 + s->blen_counter = s->blen;
  425 + break;
  426 +
  427 + case 0x28: /* MMC_NBLK */
  428 + s->nblk = (value & 0x07ff) + 1;
  429 + s->nblk_counter = s->nblk;
  430 + s->blen_counter = s->blen;
  431 + break;
  432 +
  433 + case 0x2c: /* MMC_BUF */
  434 + s->rx_dma = (value >> 15) & 1;
  435 + s->af_level = (value >> 8) & 0x1f;
  436 + s->tx_dma = (value >> 7) & 1;
  437 + s->ae_level = value & 0x1f;
  438 +
  439 + if (s->rx_dma)
  440 + s->status &= 0xfbff;
  441 + if (s->tx_dma)
  442 + s->status &= 0xf7ff;
  443 + omap_mmc_fifolevel_update(s);
  444 + omap_mmc_interrupts_update(s);
  445 + break;
  446 +
  447 + /* SPI, SDIO and TEST modes unimplemented */
  448 + case 0x30: /* MMC_SPI */
  449 + break;
  450 + case 0x34: /* MMC_SDIO */
  451 + s->sdio = value & 0x2020;
  452 + break;
  453 + case 0x38: /* MMC_SYST */
  454 + break;
  455 +
  456 + case 0x3c: /* MMC_REV */
  457 + case 0x40: /* MMC_RSP0 */
  458 + case 0x44: /* MMC_RSP1 */
  459 + case 0x48: /* MMC_RSP2 */
  460 + case 0x4c: /* MMC_RSP3 */
  461 + case 0x50: /* MMC_RSP4 */
  462 + case 0x54: /* MMC_RSP5 */
  463 + case 0x58: /* MMC_RSP6 */
  464 + case 0x5c: /* MMC_RSP7 */
  465 + OMAP_RO_REG(offset);
  466 + break;
  467 +
  468 + default:
  469 + OMAP_BAD_REG(offset);
  470 + }
  471 +}
  472 +
  473 +static CPUReadMemoryFunc *omap_mmc_readfn[] = {
  474 + omap_badwidth_read16,
  475 + omap_mmc_read,
  476 + omap_badwidth_read16,
  477 +};
  478 +
  479 +static CPUWriteMemoryFunc *omap_mmc_writefn[] = {
  480 + omap_badwidth_write16,
  481 + omap_mmc_write,
  482 + omap_badwidth_write16,
  483 +};
  484 +
  485 +void omap_mmc_reset(struct omap_mmc_s *host)
  486 +{
  487 + host->last_cmd = 0;
  488 + memset(host->rsp, 0, sizeof(host->rsp));
  489 + host->arg = 0;
  490 + host->dw = 0;
  491 + host->mode = 0;
  492 + host->enable = 0;
  493 + host->status = 0;
  494 + host->mask = 0;
  495 + host->cto = 0;
  496 + host->dto = 0;
  497 + host->fifo_len = 0;
  498 + host->blen = 0;
  499 + host->blen_counter = 0;
  500 + host->nblk = 0;
  501 + host->nblk_counter = 0;
  502 + host->tx_dma = 0;
  503 + host->rx_dma = 0;
  504 + host->ae_level = 0x00;
  505 + host->af_level = 0x1f;
  506 + host->transfer = 0;
  507 +}
  508 +
  509 +struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base,
  510 + qemu_irq irq, qemu_irq dma[], omap_clk clk)
  511 +{
  512 + int iomemtype;
  513 + struct omap_mmc_s *s = (struct omap_mmc_s *)
  514 + qemu_mallocz(sizeof(struct omap_mmc_s));
  515 +
  516 + s->irq = irq;
  517 + s->base = base;
  518 + s->dma = dma;
  519 + s->clk = clk;
  520 +
  521 + iomemtype = cpu_register_io_memory(0, omap_mmc_readfn,
  522 + omap_mmc_writefn, s);
  523 + cpu_register_physical_memory(s->base, 0x800, iomemtype);
  524 +
  525 + /* Instantiate the storage */
  526 + s->card = sd_init(sd_bdrv);
  527 +
  528 + return s;
  529 +}
  530 +
  531 +/* TODO: insertion and read-only handlers */
... ...