2 * Samsung S3C24xx series MMC/SD/SDIO Host Controller interface.
4 * Copyright (c) 2007 OpenMoko, Inc.
5 * Author: Andrzej Zaborowski <andrew@openedhand.com>
7 * This code is licenced under the GNU GPL v2.
14 struct s3c_mmci_state_s
{
15 target_phys_addr_t base
;
42 const target_phys_addr_t
*map
;
45 void s3c_mmci_reset(struct s3c_mmci_state_s
*s
)
71 static void s3c_mmci_fifo_run(struct s3c_mmci_state_s
*s
)
73 int len
, dmalevel
= 0;
78 if (((s
->dcontrol
>> 12) & 3) == 2) { /* DatMode */
80 s
->dstatus
|= 1 << 0; /* RxDatOn */
81 while (s
->fifolen
< 64 && s
->blklen_cnt
) {
82 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] =
83 sd_read_data(s
->card
);
84 if (!(-- s
->blklen_cnt
))
86 s
->blklen_cnt
= s
->blklen
;
88 if ((s
->mask
& (1 << 0)) && /* RFHalf */
89 s
->fifolen
> 31 && len
< 32)
90 qemu_irq_raise(s
->irq
);
91 if ((s
->mask
& (1 << 1)) && /* RFFull */
92 s
->fifolen
> 63 && len
< 64)
93 qemu_irq_raise(s
->irq
);
94 if ((s
->mask
& (1 << 2)) && !s
->blklen_cnt
) /* RFLast */
95 qemu_irq_raise(s
->irq
);
96 dmalevel
= !!s
->fifolen
;
97 } else if (((s
->dcontrol
>> 12) & 3) == 3) { /* DatMode */
99 s
->dstatus
|= 1 << 0; /* TxDatOn */
100 while (s
->fifolen
&& s
->blklen_cnt
) {
101 sd_write_data(s
->card
, s
->fifo
[s
->fifostart
++]);
104 if (!(-- s
->blklen_cnt
))
105 if (-- s
->blknum_cnt
)
106 s
->blklen_cnt
= s
->blklen
;
108 if ((s
->mask
& (1 << 3)) && !s
->fifolen
&& len
) /* TFEmpty */
109 qemu_irq_raise(s
->irq
);
110 if ((s
->mask
& (1 << 4)) && /* TFHalf */
111 s
->fifolen
< 33 && len
> 32)
112 qemu_irq_raise(s
->irq
);
113 dmalevel
= (s
->fifolen
< 64) && (s
->blklen_cnt
> 0);
117 if (!s
->blklen_cnt
) {
120 s
->dstatus
|= 1 << 4; /* DatFin */
121 if (s
->mask
& (1 << 7)) /* DatFin */
122 qemu_irq_raise(s
->irq
);
125 if (s
->dcontrol
& (1 << 15)) { /* EnDMA */
126 qemu_set_irq(s
->dma
[S3C_RQ_SDI0
], dmalevel
);
127 qemu_set_irq(s
->dma
[S3C_RQ_SDI1
], dmalevel
);
128 qemu_set_irq(s
->dma
[S3C_RQ_SDI2
], dmalevel
);
132 static void s3c_mmci_cmd_submit(struct s3c_mmci_state_s
*s
)
135 struct sd_request_s request
;
136 uint8_t response
[16];
138 request
.cmd
= s
->ccontrol
& 0x3f;
139 request
.arg
= s
->arg
;
140 request
.crc
= 0; /* FIXME */
142 rsplen
= sd_do_command(s
->card
, &request
, response
);
143 s
->cstatus
= (s
->cstatus
& ~0x11ff) | request
.cmd
; /* RspIndex */
144 s
->cstatus
|= 1 << 11; /* CmdSent */
145 if (s
->mask
& (1 << 16)) /* CmdSent */
146 qemu_irq_raise(s
->irq
);
148 memset(s
->resp
, 0, sizeof(s
->resp
));
149 if (!(s
->ccontrol
& (1 << 9))) /* WaitRsp */
150 goto complete
; /* No response */
152 if (s
->ccontrol
& (1 << 10)) { /* LongRsp */
157 /* R1, R3, R4, R5 or R6 */
162 for (i
= 0; i
< rsplen
; i
++)
163 s
->resp
[i
>> 2] |= response
[i
] << ((~i
& 3) << 3);
165 s
->cstatus
|= 1 << 9; /* RspFin */
166 if (s
->mask
& (1 << 14)) /* RspEnd */
167 qemu_irq_raise(s
->irq
);
170 s
->blklen_cnt
= s
->blklen
;
171 s
->blknum_cnt
= s
->blknum
;
174 if (((s
->dcontrol
>> 12) & 3) == 1) { /* DatMode */
175 if (s
->dcontrol
& (1 << 18)) /* BACMD */
177 } else if (((s
->dcontrol
>> 12) & 3) == 2) { /* DatMode */
178 if (s
->dcontrol
& (1 << 19)) /* RACMD */
180 } else if (((s
->dcontrol
>> 12) & 3) == 3) /* DatMode */
181 if (s
->dcontrol
& (1 << 20)) /* RACMD */
183 /* HACK: This bit only matters for SDIO but we don't have a good
184 * way to tell if the card is an SDIO, so only check if this is
185 * CMD53, the only SDIO command potentially using the DAT lines. */
186 if (request
.cmd
== 53)
187 s
->data
&= s
->ccontrol
>> 11; /* WithData */
191 s
->cstatus
|= 1 << 10; /* CmdTout */
192 if (s
->mask
& (1 << 15)) /* CmdTout */
193 qemu_irq_raise(s
->irq
);
196 #define S3C_SDICON 0x00 /* SDI Control register */
197 #define S3C_SDIPRE 0x04 /* SDI Baud Rate Prescaler register */
198 #define S3C_SDICARG 0x08 /* SDI Command Argument register */
199 #define S3C_SDICCON 0x0c /* SDI Command Control register */
200 #define S3C_SDICSTA 0x10 /* SDI Command Status register */
201 #define S3C_SDIRSP0 0x14 /* SDI Response register 0 */
202 #define S3C_SDIRSP1 0x18 /* SDI Response register 1 */
203 #define S3C_SDIRSP2 0x1c /* SDI Response register 2 */
204 #define S3C_SDIRSP3 0x20 /* SDI Response register 3 */
205 #define S3C_SDIDTIMER 0x24 /* SDI Data / Busy Timer register */
206 #define S3C_SDIBSIZE 0x28 /* SDI Block Size register */
207 #define S3C_SDIDCON 0x2c /* SDI Data Control register */
208 #define S3C_SDICNT 0x30 /* SDI Data Remain Counter register */
209 #define S3C_SDIDSTA 0x34 /* SDI Data Status register */
210 #define S3C_SDIFSTA 0x38 /* SDI FIFO Status register */
211 #define S3C_SDIDAT 0x3c /* SDI Data register */
212 #define S3C_SDIMSK 0x40 /* SDI Interrupt Mask register */
214 #define S3C_SDIMAX 0x40
216 static uint32_t s3c_mmci_readw(void *opaque
, target_phys_addr_t addr
)
218 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
221 if (addr
> S3C_SDIMAX
)
251 return s
->blklen_cnt
| (s
->blknum_cnt
<< 12);
255 /* XXX on S3C2440 these bits have to cleared explicitely. */
256 if (((s
->dcontrol
>> 12) & 3) == 2) /* DatMode */
257 return s
->fifolen
| /* FFCNT */
258 ((s
->fifolen
> 31) ? (1 << 7) : 0) | /* RFHalf */
259 ((s
->fifolen
> 63) ? (1 << 8) : 0) | /* RFFull */
260 (s
->blklen_cnt
? 0 : (1 << 9)) | /* RFLast */
261 (3 << 10) | /* TFHalf */
262 (s
->fifolen
? (1 << 12) : 0); /* RFDET */
263 else if (((s
->dcontrol
>> 12) & 3) == 3) /* DatMode */
264 return s
->fifolen
| /* FFCNT */
265 (s
->fifolen
? 0 : (1 << 10)) | /* TFEmpty */
266 ((s
->fifolen
< 33) ? (1 << 11) : 0) | /* TFHalf */
267 ((s
->fifolen
< 64) ? (1 << 13) : 0); /* TFDET */
269 return s
->fifolen
; /* FFCNT */
272 if (s
->fifolen
>= 4) {
273 ret
|= s
->fifo
[s
->fifostart
++] << 0;
275 ret
|= s
->fifo
[s
->fifostart
++] << 8;
277 ret
|= s
->fifo
[s
->fifostart
++] << 16;
279 ret
|= s
->fifo
[s
->fifostart
++] << 24;
282 s3c_mmci_fifo_run(s
);
284 printf("%s: FIFO underrun\n", __FUNCTION__
);
291 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long int)addr
);
297 static void s3c_mmci_writew(void *opaque
, target_phys_addr_t addr
,
300 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
302 if (addr
> S3C_SDIMAX
)
308 s
->control
= value
& 0x1d;
309 if (value
& (1 << 1)) /* FRST */
313 s
->prescaler
= value
& 0xff;
319 s
->ccontrol
= value
& 0x1fff;
320 if (value
& (1 << 8)) /* CMST */
321 s3c_mmci_cmd_submit(s
);
322 s3c_mmci_fifo_run(s
);
325 s
->cstatus
&= ~(value
& 0x1e00);
328 s
->dtimer
= value
& 0xffff;
331 s
->blklen
= value
& 0xfff;
335 s
->blknum
= value
& 0xfff;
336 if (value
& (1 << 14)) /* STOP */
338 if (((s
->dcontrol
>> 12) & 3) == 1) { /* DatMode */
339 if (!(s
->dcontrol
& (1 << 18))) /* BACMD */
341 } else if (((s
->dcontrol
>> 12) & 3) == 2) { /* DatMode */
342 if (!(s
->dcontrol
& (1 << 19))) /* RACMD */
344 } else if (((s
->dcontrol
>> 12) & 3) == 3) /* DatMode */
345 if (!(s
->dcontrol
& (1 << 20))) /* RACMD */
347 s3c_mmci_fifo_run(s
);
350 s
->dstatus
&= ~(value
& 0x3f8);
353 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = (value
>> 0) & 0xff;
354 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = (value
>> 8) & 0xff;
355 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = (value
>> 16) & 0xff;
356 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = (value
>> 24) & 0xff;
357 s3c_mmci_fifo_run(s
);
360 s
->mask
= value
& 0x3ffff;
364 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long int)addr
);
368 static uint32_t s3c_mmci_readh(void *opaque
, target_phys_addr_t addr
)
370 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
373 if (s
->map
[addr
- s
->base
] == S3C_SDIDAT
) {
374 if (s
->fifolen
>= 2) {
375 ret
|= s
->fifo
[s
->fifostart
++] << 0;
377 ret
|= s
->fifo
[s
->fifostart
++] << 8;
380 s3c_mmci_fifo_run(s
);
382 printf("%s: FIFO underrun\n", __FUNCTION__
);
387 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long int)(addr
- s
->base
));
391 static void s3c_mmci_writeh(void *opaque
, target_phys_addr_t addr
,
394 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
396 if (s
->map
[addr
- s
->base
] == S3C_SDIDAT
) {
397 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = (value
>> 0) & 0xff;
398 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = (value
>> 8) & 0xff;
399 s3c_mmci_fifo_run(s
);
401 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long int)(addr
- s
->base
));
404 static uint32_t s3c_mmci_readb(void *opaque
, target_phys_addr_t addr
)
406 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
409 if (s
->map
[addr
- s
->base
] == S3C_SDIDAT
) {
410 if (s
->fifolen
> 0) {
411 ret
= s
->fifo
[s
->fifostart
++];
414 s3c_mmci_fifo_run(s
);
416 printf("%s: FIFO underrun\n", __FUNCTION__
);
421 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long int)(addr
- s
->base
));
425 static void s3c_mmci_writeb(void *opaque
, target_phys_addr_t addr
,
428 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
430 if (s
->map
[addr
- s
->base
] == S3C_SDIDAT
) {
431 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = value
;
432 s3c_mmci_fifo_run(s
);
434 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long int)(addr
- s
->base
));
437 static CPUReadMemoryFunc
*s3c_mmci_readfn
[] = {
443 static CPUWriteMemoryFunc
*s3c_mmci_writefn
[] = {
449 static void s3c_mmci_cardirq(void *opaque
, int line
, int level
)
451 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
453 if (~s
->control
& (1 << 3)) /* RcvIOInt */
458 s
->dstatus
|= 1 << 9; /* IOIntDet */
459 if (s
->mask
& (1 << 12)) /* IOIntDet */
460 qemu_irq_raise(s
->irq
);
463 static void s3c_mmci_save(QEMUFile
*f
, void *opaque
)
465 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
466 qemu_put_be32(f
, s
->blklen
);
467 qemu_put_be32(f
, s
->blknum
);
468 qemu_put_be32(f
, s
->blklen_cnt
);
469 qemu_put_be32(f
, s
->blknum_cnt
);
470 qemu_put_buffer(f
, s
->fifo
, sizeof(s
->fifo
));
471 qemu_put_be32(f
, s
->fifolen
);
472 qemu_put_be32(f
, s
->fifostart
);
473 qemu_put_be32(f
, s
->data
);
475 qemu_put_be32s(f
, &s
->control
);
476 qemu_put_be32s(f
, &s
->arg
);
477 qemu_put_be32s(f
, &s
->ccontrol
);
478 qemu_put_be32s(f
, &s
->cstatus
);
479 qemu_put_be32s(f
, &s
->dcontrol
);
480 qemu_put_be32s(f
, &s
->dstatus
);
481 qemu_put_be32s(f
, &s
->resp
[0]);
482 qemu_put_be32s(f
, &s
->resp
[1]);
483 qemu_put_be32s(f
, &s
->resp
[2]);
484 qemu_put_be32s(f
, &s
->resp
[3]);
485 qemu_put_be16s(f
, &s
->dtimer
);
486 qemu_put_be32s(f
, &s
->mask
);
487 qemu_put_8s(f
, &s
->prescaler
);
490 static const target_phys_addr_t s3c2410_regmap
[S3C_SDIMAX
+ 1] = {
491 [0 ... S3C_SDIMAX
] = -1,
494 [0x08] = S3C_SDICARG
,
495 [0x0c] = S3C_SDICCON
,
496 [0x10] = S3C_SDICSTA
,
497 [0x14] = S3C_SDIRSP0
,
498 [0x18] = S3C_SDIRSP1
,
499 [0x1c] = S3C_SDIRSP2
,
500 [0x20] = S3C_SDIRSP3
,
501 [0x24] = S3C_SDIDTIMER
,
502 [0x28] = S3C_SDIBSIZE
,
503 [0x2c] = S3C_SDIDCON
,
505 [0x34] = S3C_SDIDSTA
,
506 [0x38] = S3C_SDIFSTA
,
511 static const target_phys_addr_t s3c2440_regmap
[S3C_SDIMAX
+ 1] = {
512 [0 ... S3C_SDIMAX
] = -1,
515 [0x08] = S3C_SDICARG
,
516 [0x0c] = S3C_SDICCON
,
517 [0x10] = S3C_SDICSTA
,
518 [0x14] = S3C_SDIRSP0
,
519 [0x18] = S3C_SDIRSP1
,
520 [0x1c] = S3C_SDIRSP2
,
521 [0x20] = S3C_SDIRSP3
,
522 [0x24] = S3C_SDIDTIMER
,
523 [0x28] = S3C_SDIBSIZE
,
524 [0x2c] = S3C_SDIDCON
,
526 [0x34] = S3C_SDIDSTA
,
527 [0x38] = S3C_SDIFSTA
,
532 static int s3c_mmci_load(QEMUFile
*f
, void *opaque
, int version_id
)
534 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
535 s
->blklen
= qemu_get_be32(f
);
536 s
->blknum
= qemu_get_be32(f
);
537 s
->blklen_cnt
= qemu_get_be32(f
);
538 s
->blknum_cnt
= qemu_get_be32(f
);
539 qemu_get_buffer(f
, s
->fifo
, sizeof(s
->fifo
));
540 s
->fifolen
= qemu_get_be32(f
);
541 s
->fifostart
= qemu_get_be32(f
);
542 s
->data
= qemu_get_be32(f
);
544 qemu_get_be32s(f
, &s
->control
);
545 qemu_get_be32s(f
, &s
->arg
);
546 qemu_get_be32s(f
, &s
->ccontrol
);
547 qemu_get_be32s(f
, &s
->cstatus
);
548 qemu_get_be32s(f
, &s
->dcontrol
);
549 qemu_get_be32s(f
, &s
->dstatus
);
550 qemu_get_be32s(f
, &s
->resp
[0]);
551 qemu_get_be32s(f
, &s
->resp
[1]);
552 qemu_get_be32s(f
, &s
->resp
[2]);
553 qemu_get_be32s(f
, &s
->resp
[3]);
554 qemu_get_be16s(f
, &s
->dtimer
);
555 qemu_get_be32s(f
, &s
->mask
);
556 qemu_get_8s(f
, &s
->prescaler
);
561 struct s3c_mmci_state_s
*s3c_mmci_init(target_phys_addr_t base
, uint16_t model
,
562 SDState
*mmc
, qemu_irq irq
, qemu_irq
*dma
)
565 struct s3c_mmci_state_s
*s
;
570 s
= (struct s3c_mmci_state_s
*)
571 qemu_mallocz(sizeof(struct s3c_mmci_state_s
));
579 s
->map
= s3c2410_regmap
;
582 s
->map
= s3c2440_regmap
;
585 fprintf(stderr
, "%s: unknown MMC/SD/SDIO HC model %04x\n",
586 __FUNCTION__
, model
);
590 sd_set_cb(mmc
, 0, qemu_allocate_irqs(s3c_mmci_cardirq
, s
, 1)[0]);
591 //mmc->irq = qemu_allocate_irqs(s3c_mmci_cardirq, s, 1)[0];
595 iomemtype
= cpu_register_io_memory(0, s3c_mmci_readfn
,
596 s3c_mmci_writefn
, s
);
597 cpu_register_physical_memory(s
->base
, 0xffffff, iomemtype
);
599 register_savevm("s3c24xx_mmci", 0, 0, s3c_mmci_save
, s3c_mmci_load
, s
);