2 * OMAP3 Multimedia Card/Secure Digital/Secure Digital I/O (MMC/SD/SDIO) Card Interface emulation
\r
4 * Copyright (C) 2008 yajin <yajin@vm-kernel.org>
\r
6 * This program is free software; you can redistribute it and/or
\r
7 * modify it under the terms of the GNU General Public License as
\r
8 * published by the Free Software Foundation; either version 2 or
\r
9 * (at your option) version 3 of the License.
\r
11 * This program is distributed in the hope that it will be useful,
\r
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 * GNU General Public License for more details.
\r
16 * You should have received a copy of the GNU General Public License
\r
17 * along with this program; if not, write to the Free Software
\r
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
\r
24 /*The MMCHS of OMAP3530/3430 is different from OMAP1 and OAMP2420.*/
\r
35 qemu_irq coverswitch;
\r
40 uint32_t sysconfig; /*0x10 */
\r
41 uint32_t sysstatus; /*0x14 */
\r
42 uint32_t csre; /*0x24 */
\r
43 uint32_t systest; /*0x28 */
\r
44 uint32_t con; /*0x2c */
\r
45 uint32_t pwcnt; /*0x30 */
\r
46 uint32_t blk; /*0x104 */
\r
47 uint32_t arg; /*0x108 */
\r
48 uint32_t cmd; /*0x10c */
\r
49 uint32_t rsp10; /*0x110 */
\r
50 uint32_t rsp32; /*0x114 */
\r
51 uint32_t rsp54; /*0x118 */
\r
52 uint32_t rsp76; /*0x11c */
\r
53 uint32_t data; /*0x120 */
\r
54 uint32_t pstate; /*0x124 */
\r
55 uint32_t hctl; /*0x128 */
\r
56 uint32_t sysctl; /*0x12c */
\r
57 uint32_t stat; /*0x130 */
\r
58 uint32_t ie; /*0x134 */
\r
59 uint32_t ise; /*0x138 */
\r
60 uint32_t ac12; /*0x13c */
\r
61 uint32_t capa; /*0x140 */
\r
62 uint32_t cur_capa; /*0x148 */
\r
63 uint32_t rev; /*0x1fc */
\r
65 /*for quick reference */
\r
66 uint16_t blen_counter;
\r
67 uint16_t nblk_counter;
\r
76 uint32_t stat_pending;
\r
82 sd_nore = 0, /* no response */
\r
83 sd_136_bits = 1, /*Response Length 136 bits */
\r
84 sd_48_bits = 2, /*Response Length 48 bits */
\r
85 sd_48b_bits = 3, /*Response Length 48 bits with busy after response */
\r
86 } omap3_sd_rsp_type_t;
\r
89 static void omap3_mmc_interrupts_update(struct omap3_mmc_s *s)
\r
91 qemu_set_irq(s->irq, !!((s->stat | s->stat_pending) & s->ise & s->ie));
\r
94 static void omap3_mmc_fifolevel_update(struct omap3_mmc_s *host,int de)
\r
102 if (host->fifo_len<(host->blk&0x7f))
\r
104 /*DMA has read one byte from fifo*/
\r
105 qemu_irq_lower(host->dma[1]);
\r
110 if (host->fifo_len>0)
\r
112 /*DMA has written one byte to fifo*/
\r
113 qemu_irq_lower(host->dma[0]);
\r
119 static void omap3_mmc_transfer(struct omap3_mmc_s *host, int msbs, int ace,
\r
125 if (!host->transfer)
\r
131 /*data read. card->host */
\r
132 for (i = 0; i < 4; i++)
\r
134 if (host->blen_counter)
\r
136 value = sd_read_data(host->card);
\r
137 //if (host->arg==0x13c00)
\r
138 // printf("value %x ",value);
\r
139 host->fifo[(host->fifo_start + host->fifo_len) & 255] |=
\r
141 host->blen_counter--;
\r
150 /*data write. host->card */
\r
151 if (!host->fifo_len)
\r
153 for (i = 0; i < 4; i++)
\r
155 if (host->blen_counter)
\r
157 value = (host->fifo[host->fifo_start] >> (i * 8)) & 0xff;
\r
158 sd_write_data(host->card, value);
\r
159 host->blen_counter--;
\r
164 host->fifo_start++;
\r
166 host->fifo_start &= 255;
\r
169 if (host->blen_counter == 0)
\r
171 host->nblk_counter--;
\r
172 host->blen_counter = host->blk & 0x7ff;
\r
175 /*multi block transfer */
\r
176 if (host->nblk_counter == 0)
\r
178 host->nblk_counter = (host->blk >> 16) & 0xffff;
\r
179 host->transfer = 0;
\r
180 host->stat_pending |= 0x2; /*tc */
\r
186 /*single block transfer*/
\r
187 host->transfer = 0;
\r
188 host->stat_pending |= 0x2; /*tc */
\r
195 /*transfer complete*/
\r
202 qemu_irq_raise(host->dma[1]);
\r
206 qemu_irq_raise(host->dma[0]);
\r
209 host->stat &= ~0x30;
\r
210 host->stat_pending &= ~0x30;
\r
217 host->pstate |= 0x800; /*BRE*/
\r
218 host->pstate &= ~0x400; /*BWE*/ /*can not write*/
\r
219 host->stat_pending |= 0x20; /*BRR*/
\r
220 host->stat &= ~0x10; /*BWR*/
\r
221 host->stat_pending &= ~0x10;
\r
225 host->pstate &= ~0x800; /*BRE*/
\r
226 host->pstate |= 0x400; /*BWE*/
\r
227 host->stat_pending |= 0x10; /*BWR*/
\r
228 host->stat &= ~0x20; /*BRR*/
\r
229 host->stat_pending &= ~0x20;
\r
234 //printf("after MMC TRANS host->stat %x \n",host->stat);
\r
239 static void omap3_mmc_command(struct omap3_mmc_s *host, int indx, int dp,
\r
240 omap3_sd_rsp_type_t rsp_type, int ddir)
\r
242 uint32_t rspstatus, mask;
\r
243 int rsplen, timeout;
\r
244 struct sd_request_s request;
\r
245 uint8_t response[16];
\r
247 //printf("CMD %d host->arg %x \n",indx,host->arg);
\r
249 if ((host->con & 2) && !indx) /* INIT and CMD0 */
\r
251 host->stat_pending |= 0x1;
\r
252 host->pstate &= 0xfffffffe;
\r
258 host->fifo_start = 0;
\r
259 host->fifo_len = 0;
\r
260 host->transfer = 1;
\r
264 host->transfer = 0;
\r
270 request.cmd = indx;
\r
271 request.arg = host->arg;
\r
272 request.crc = 0; /* FIXME */
\r
274 rsplen = sd_do_command(host->card, &request, response);
\r
288 host->rsp76 = (response[0] << 24) | (response[1] << 16) |
\r
289 (response[2] << 8) | (response[3] << 0);
\r
290 host->rsp54 = (response[4] << 24) | (response[5] << 16) |
\r
291 (response[6] << 8) | (response[7] << 0);
\r
292 host->rsp32 = (response[8] << 24) | (response[9] << 16) |
\r
293 (response[10] << 8) | (response[11] << 0);
\r
294 host->rsp10 = (response[12] << 24) | (response[13] << 16) |
\r
295 (response[14] << 8) | (response[15] << 0);
\r
305 host->rsp10 = (response[0] << 24) | (response[1] << 16) |
\r
306 (response[2] << 8) | (response[3] << 0);
\r
314 mask = OUT_OF_RANGE | ADDRESS_ERROR | BLOCK_LEN_ERROR |
\r
315 ERASE_SEQ_ERROR | ERASE_PARAM | WP_VIOLATION |
\r
316 LOCK_UNLOCK_FAILED | COM_CRC_ERROR | ILLEGAL_COMMAND |
\r
317 CARD_ECC_FAILED | CC_ERROR | SD_ERROR |
\r
318 CID_CSD_OVERWRITE | WP_ERASE_SKIP;
\r
319 rspstatus = (response[0] << 24) | (response[1] << 16) |
\r
320 (response[2] << 8) | (response[3] << 0);
\r
328 if (rspstatus & mask & host->csre)
\r
329 host->stat_pending |= 0x10000000;
\r
331 host->stat &= ~0x10000000;
\r
332 host->stat_pending &= ~0x10000000;
\r
336 host->stat_pending |= 0x10000;
\r
338 host->stat_pending |= 0x1;
\r
340 /*do we allow to set the stat bit? */
\r
341 host->stat_pending &= host->ie;
\r
343 if (host->stat_pending & 0xffff0000)
\r
344 host->stat_pending |= 0x8000;
\r
347 static void omap3_mmc_reset(struct omap3_mmc_s *s)
\r
349 s->sysconfig = 0x00000015;
\r
350 s->con = 0x00000500;
\r
351 s->pstate = 0x00040000;
\r
352 s->capa = 0x00e10080;
\r
353 s->rev = 0x26000000;
\r
359 static uint32_t omap3_mmc_read(void *opaque, target_phys_addr_t addr)
\r
361 struct omap3_mmc_s *s = (struct omap3_mmc_s *) opaque;
\r
363 //if ((offset!=0x12c)&&(offset!=0x120))
\r
364 //fprintf(stderr, "%s: addr %03x pc %08x \n", __FUNCTION__, addr, cpu_single_env->regs[15]);
\r
368 return s->sysconfig;
\r
370 return s->sysstatus | 0x1; /*reset completed */
\r
375 case 0x2c: /* MMCHS_CON */
\r
379 case 0x104: /* MMCHS_BLK */
\r
381 case 0x108: /* MMCHS_ARG */
\r
395 i = s->fifo[s->fifo_start];
\r
396 /*set the buffer to default value*/
\r
397 s->fifo[s->fifo_start] = 0x0;
\r
398 if (s->fifo_len == 0) {
\r
399 printf("MMC: FIFO underrun\n");
\r
404 s->fifo_start &= 255;
\r
405 omap3_mmc_transfer(s,(s->cmd>>5)&1,(s->cmd>>2)&1,(s->cmd>>1)&1,(s->cmd)&1);
\r
406 omap3_mmc_fifolevel_update(s,s->cmd&1);
\r
407 omap3_mmc_interrupts_update(s);
\r
410 case 0x124: /* MMCHS_PSTATE */
\r
414 case 0x12c: /* MMCHS_SYSCTL */
\r
416 case 0x130: /* MMCHS_STAT */
\r
417 s->stat |= s->stat_pending;
\r
418 s->stat_pending = 0;
\r
419 //fprintf(stderr, "%s: MMCHS_STAT = %08x\n", __FUNCTION__, s->stat);
\r
427 case 0x140: /* MMCHS_CAPA */
\r
430 return s->cur_capa;
\r
434 OMAP_BAD_REG(addr);
\r
441 static void omap3_mmc_write(void *opaque, target_phys_addr_t addr,
\r
444 struct omap3_mmc_s *s = (struct omap3_mmc_s *) opaque;
\r
445 //fprintf(stderr, "%s: addr %x value %08x \n", __FUNCTION__, addr, value);
\r
459 if (value & 2) omap3_mmc_reset(s);
\r
460 s->sysconfig = value & 0x31d;
\r
466 s->systest = value;
\r
468 case 0x2c: /* MMCHS_CON */
\r
469 if (value & 0x10) {
\r
470 fprintf(stderr, "%s: SYSTEST mode is not supported\n", __FUNCTION__);
\r
473 if (value & 0x20) {
\r
474 fprintf(stderr, "%s: 8-bit data width is not supported\n", __FUNCTION__);
\r
477 s->con = value & 0x1ffff;
\r
482 case 0x104: /* MMCHS_BLK */
\r
483 s->blk = value & 0xffff07ff;
\r
484 s->blen_counter = value & 0x7ff;
\r
485 s->nblk_counter = (value & 0xffff) >> 16;
\r
487 case 0x108: /* MMCHS_ARG */
\r
490 case 0x10c: /* MMCHS_CMD */
\r
491 s->cmd = value & 0x3ffb0037;
\r
492 omap3_mmc_command(s, (value >> 24) & 0x3f, (value >> 21) & 1,
\r
493 (value >> 16) & 3, (value >> 4) & 1);
\r
494 omap3_mmc_transfer(s,(s->cmd>>5)&1,(s->cmd>>2)&1,(s->cmd>>1)&1,(s->cmd)&1);
\r
495 omap3_mmc_fifolevel_update(s,s->cmd&0x1);
\r
496 omap3_mmc_interrupts_update(s);
\r
500 if (s->fifo_len == 256)
\r
502 s->fifo[(s->fifo_start + s->fifo_len) & 255] = value;
\r
504 omap3_mmc_transfer(s,(s->cmd>>5)&1,(s->cmd>>2)&1,(s->cmd>>1)&1,(s->cmd)&1);
\r
505 omap3_mmc_fifolevel_update(s,s->cmd&0x1);
\r
506 omap3_mmc_interrupts_update(s);
\r
509 case 0x128: /* MMCHS_HCTL */
\r
510 s->hctl = value & 0xf0f0f02;
\r
512 case 0x12c: /* MMCHS_SYSCTL */
\r
513 if (value & 0x04000000) { /* SRD */
\r
515 s->pstate &= ~0x00000f06; /* BRE, BWE, RTA, WTA, DLA, DATI */
\r
516 s->hctl &= ~0x00030000; /* SGBR, CR */
\r
517 s->stat &= ~0x00000034; /* BRR, BWR, BGE */
\r
518 s->stat_pending &= ~0x00000034;
\r
522 if (value & 0x02000000) { /* SRC */
\r
523 s->pstate &= ~0x00000001; /* CMDI */
\r
525 if (value & 0x01000000) { /* SRA */
\r
526 uint32_t capa = s->capa;
\r
527 uint32_t cur_capa = s->cur_capa;
\r
528 omap3_mmc_reset(s);
\r
530 s->cur_capa = cur_capa;
\r
532 value = (value & ~2) | ((value & 1) << 1); /* copy ICE directly to ICS */
\r
533 s->sysctl = value & 0x000fffc7;
\r
536 value = value & 0X317f0237;
\r
538 /* stat_pending is NOT cleared */
\r
540 case 0x134: /* MMCHS_IE */
\r
541 if (!(s->con & 0x4000)) /* if CON:OBIE is clear, ignore write to OBI_ENABLE */
\r
542 value = (value & ~0x200) | (s->ie & 0x200);
\r
543 s->ie = value & 0x317f0337;
\r
544 if (!(s->ie & 0x100)) {
\r
546 s->stat_pending &= ~0x100;
\r
548 omap3_mmc_interrupts_update(s);
\r
551 s->ise = value & 0x317f0337;
\r
552 omap3_mmc_interrupts_update(s);
\r
554 case 0x140: /* MMCHS_CAPA */
\r
555 s->capa = value & 0x07000000;
\r
558 s->cur_capa = value & 0xffffff;
\r
561 OMAP_BAD_REG(addr);
\r
566 static CPUReadMemoryFunc *omap3_mmc_readfn[] = {
\r
567 omap_badwidth_read32,
\r
568 omap_badwidth_read32,
\r
572 static CPUWriteMemoryFunc *omap3_mmc_writefn[] = {
\r
573 omap_badwidth_write32,
\r
574 omap_badwidth_write32,
\r
578 static void omap3_mmc_enable(struct omap3_mmc_s *s, int enable)
\r
580 sd_enable(s->card, enable);
\r
583 struct omap3_mmc_s *omap3_mmc_init(struct omap_target_agent_s *ta,
\r
584 BlockDriverState * bd, qemu_irq irq,
\r
585 qemu_irq dma[], omap_clk fclk, omap_clk iclk)
\r
588 struct omap3_mmc_s *s = (struct omap3_mmc_s *)
\r
589 qemu_mallocz(sizeof(struct omap3_mmc_s));
\r
595 omap3_mmc_reset(s);
\r
597 iomemtype = l4_register_io_memory(0, omap3_mmc_readfn,
\r
598 omap3_mmc_writefn, s);
\r
599 omap_l4_attach(ta, 0, iomemtype);
\r
601 /* Instantiate the storage */
\r
603 s->card = sd_init(bd, 0);
\r
604 omap3_mmc_enable(s,1);
\r