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 #include "s3c24xx_mmci.h"
16 #define S3C_SDICON 0x00 /* SDI Control register */
17 #define S3C_SDIPRE 0x04 /* SDI Baud Rate Prescaler register */
18 #define S3C_SDICARG 0x08 /* SDI Command Argument register */
19 #define S3C_SDICCON 0x0c /* SDI Command Control register */
20 #define S3C_SDICSTA 0x10 /* SDI Command Status register */
21 #define S3C_SDIRSP0 0x14 /* SDI Response register 0 */
22 #define S3C_SDIRSP1 0x18 /* SDI Response register 1 */
23 #define S3C_SDIRSP2 0x1c /* SDI Response register 2 */
24 #define S3C_SDIRSP3 0x20 /* SDI Response register 3 */
25 #define S3C_SDIDTIMER 0x24 /* SDI Data / Busy Timer register */
26 #define S3C_SDIBSIZE 0x28 /* SDI Block Size register */
27 #define S3C_SDIDCON 0x2c /* SDI Data Control register */
28 #define S3C_SDICNT 0x30 /* SDI Data Remain Counter register */
29 #define S3C_SDIDSTA 0x34 /* SDI Data Status register */
30 #define S3C_SDIFSTA 0x38 /* SDI FIFO Status register */
31 #define S3C_SDIDAT 0x3c /* SDI Data register */
32 #define S3C_SDIMSK 0x40 /* SDI Interrupt Mask register */
34 #define S3C_SDIMAX 0x40
36 #define S3C2410_SDIDSTA_COMPLETION (S3C2410_SDIDSTA_TXDATAON|S3C2410_SDIDSTA_RXDATAON)
38 struct s3c_mmci_state_s
{
39 target_phys_addr_t base
;
66 const target_phys_addr_t
*map
;
69 void s3c_mmci_reset(struct s3c_mmci_state_s
*s
)
95 static void s3c_mmci_fifo_run(struct s3c_mmci_state_s
*s
)
97 int len
, dmalevel
= 0;
102 if (((s
->dcontrol
>> 12) & 3) == 2) { /* DatMode */
103 s
->dstatus
&= ~S3C2410_SDIDSTA_COMPLETION
;
104 s
->dstatus
|= S3C2410_SDIDSTA_RXDATAON
; /* RxDatOn */
105 while (s
->fifolen
< 64 && s
->blklen_cnt
) {
106 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] =
107 sd_read_data(s
->card
);
108 if (!(-- s
->blklen_cnt
))
109 if (-- s
->blknum_cnt
)
110 s
->blklen_cnt
= s
->blklen
;
112 if ((s
->mask
& S3C2410_SDIIMSK_RXFIFOHALF
) && /* RFHalf */
113 s
->fifolen
> 31 && len
< 32)
114 qemu_irq_raise(s
->irq
);
115 if ((s
->mask
& S3C2410_SDIIMSK_RXFIFOFULL
) && /* RFFull */
116 s
->fifolen
> 63 && len
< 64)
117 qemu_irq_raise(s
->irq
);
118 if ((s
->mask
& S3C2410_SDIIMSK_RXFIFOLAST
) && !s
->blklen_cnt
) /* RFLast */
119 qemu_irq_raise(s
->irq
);
120 dmalevel
= !!s
->fifolen
;
121 } else if (((s
->dcontrol
>> 12) & 3) == 3) { /* DatMode */
122 s
->dstatus
&= ~S3C2410_SDIDSTA_COMPLETION
;
123 s
->dstatus
|= S3C2410_SDIDSTA_TXDATAON
; /* TxDatOn */
124 while (s
->fifolen
&& s
->blklen_cnt
) {
125 sd_write_data(s
->card
, s
->fifo
[s
->fifostart
++]);
128 if (!(-- s
->blklen_cnt
))
129 if (-- s
->blknum_cnt
)
130 s
->blklen_cnt
= s
->blklen
;
132 if ((s
->mask
& S3C2410_SDIIMSK_TXFIFOEMPTY
) && !s
->fifolen
&& len
) /* TFEmpty */
133 qemu_irq_raise(s
->irq
);
134 if ((s
->mask
& S3C2410_SDIIMSK_TXFIFOHALF
) && /* TFHalf */
135 s
->fifolen
< 33 && len
> 32)
136 qemu_irq_raise(s
->irq
);
137 dmalevel
= (s
->fifolen
< 64) && (s
->blklen_cnt
> 0);
141 if (!s
->blklen_cnt
) {
143 s
->dstatus
&= ~S3C2410_SDIDSTA_COMPLETION
;
144 s
->dstatus
|= S3C2410_SDIDSTA_XFERFINISH
; /* DatFin */
145 if (s
->mask
& S3C2410_SDIIMSK_DATAFINISH
) /* DatFin */
146 qemu_irq_raise(s
->irq
);
149 if (s
->dcontrol
& S3C2410_SDIDCON_DMAEN
) { /* EnDMA */
150 qemu_set_irq(s
->dma
[S3C_RQ_SDI0
], dmalevel
);
151 qemu_set_irq(s
->dma
[S3C_RQ_SDI1
], dmalevel
);
152 qemu_set_irq(s
->dma
[S3C_RQ_SDI2
], dmalevel
);
156 static void s3c_mmci_cmd_submit(struct s3c_mmci_state_s
*s
)
159 struct sd_request_s request
;
160 uint8_t response
[16];
162 request
.cmd
= s
->ccontrol
& 0x3f;
163 request
.arg
= s
->arg
;
164 request
.crc
= 0; /* FIXME */
166 rsplen
= sd_do_command(s
->card
, &request
, response
);
167 s
->cstatus
= (s
->cstatus
& ~0x11ff) | request
.cmd
; /* RspIndex */
168 s
->cstatus
|= S3C2410_SDICMDSTAT_CMDSENT
; /* CmdSent */
169 if (s
->mask
& S3C2410_SDIIMSK_CMDSENT
) /* CmdSent */
170 qemu_irq_raise(s
->irq
);
172 memset(s
->resp
, 0, sizeof(s
->resp
));
173 if (!(s
->ccontrol
& S3C2410_SDICMDCON_WAITRSP
)) /* WaitRsp */
174 goto complete
; /* No response */
176 if (s
->ccontrol
& S3C2410_SDICMDCON_LONGRSP
) { /* LongRsp */
181 /* R1, R3, R4, R5 or R6 */
186 for (i
= 0; i
< rsplen
; i
++)
187 s
->resp
[i
>> 2] |= response
[i
] << ((~i
& 3) << 3);
189 s
->cstatus
|= 1 << 9; /* RspFin */
190 if (s
->mask
& S3C2410_SDIIMSK_RESPONSEND
) /* RspEnd */
191 qemu_irq_raise(s
->irq
);
194 s
->blklen_cnt
= s
->blklen
;
195 s
->blknum_cnt
= s
->blknum
;
198 if (((s
->dcontrol
>> 12) & 3) == 1) { /* DatMode */
199 if (s
->dcontrol
& (1 << 18)) /* BACMD */
201 } else if (((s
->dcontrol
>> 12) & 3) == 2) { /* DatMode */
202 if (s
->dcontrol
& (1 << 19)) /* RACMD */
204 } else if (((s
->dcontrol
>> 12) & 3) == 3) /* DatMode */
205 if (s
->dcontrol
& (1 << 20)) /* RACMD */
207 /* HACK: This bit only matters for SDIO but we don't have a good
208 * way to tell if the card is an SDIO, so only check if this is
209 * CMD53, the only SDIO command potentially using the DAT lines. */
210 if (request
.cmd
== 53)
211 s
->data
&= s
->ccontrol
>> 11; /* WithData */
215 s
->cstatus
|= 1 << 10; /* CmdTout */
216 if (s
->mask
& S3C2410_SDIIMSK_CMDTIMEOUT
) /* CmdTout */
217 qemu_irq_raise(s
->irq
);
221 static uint32_t s3c_mmci_readw(void *opaque
, target_phys_addr_t addr
)
223 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
225 if (addr
> S3C_SDIMAX
)
255 return s
->blklen_cnt
| (s
->blknum_cnt
<< 12);
259 /* TODO: S3C2440 these bits have to cleared explicitely. */
260 if (((s
->dcontrol
>> 12) & 3) == 2) /* DatMode */
261 return s
->fifolen
| /* FFCNT */
262 ((s
->fifolen
> 31) ? S3C2410_SDIFSTA_RFHALF
: 0) | /* RFHalf */
263 ((s
->fifolen
> 63) ? S3C2410_SDIFSTA_RFFULL
: 0) | /* RFFulx */
264 (s
->blklen_cnt
? 0 : S3C2410_SDIFSTA_RFLAST
) | /* RFLast */
265 (3 << 10) | /* TFHalf */
266 (s
->fifolen
? (1 << 12) : 0); /* RFDET */
267 else if (((s
->dcontrol
>> 12) & 3) == 3) /* DatMode */
268 return s
->fifolen
| /* FFCNT */
269 (s
->fifolen
? 0 : S3C2410_SDIFSTA_TFEMPTY
) | /* TFEmpty */
270 ((s
->fifolen
< 33) ? S3C2410_SDIFSTA_TFHALF
: 0) | /* TFHalf */
271 ((s
->fifolen
< 64) ? S3C2410_SDIFSTA_TFDET
: 0); /* TFDET */
273 return s
->fifolen
; /* FFCNT */
276 if (s
->fifolen
>= 4) {
277 ret
|= s
->fifo
[s
->fifostart
++] << 0;
279 ret
|= s
->fifo
[s
->fifostart
++] << 8;
281 ret
|= s
->fifo
[s
->fifostart
++] << 16;
283 ret
|= s
->fifo
[s
->fifostart
++] << 24;
286 s3c_mmci_fifo_run(s
);
288 printf("%s: FIFO underrun\n", __FUNCTION__
);
295 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long int)addr
);
301 static void s3c_mmci_writew(void *opaque
, target_phys_addr_t addr
,
304 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
305 if (addr
> S3C_SDIMAX
)
311 s
->control
= value
& 0x1d;
312 if (value
& (1 << 1)) /* FRST */
316 s
->prescaler
= value
& 0xff;
322 s
->ccontrol
= value
& 0x1fff;
323 if (value
& (1 << 8)) /* CMST */
324 s3c_mmci_cmd_submit(s
);
325 s3c_mmci_fifo_run(s
);
328 s
->cstatus
&= ~(value
& 0x1e00);
331 s
->dtimer
= value
& 0xffff;
334 s
->blklen
= value
& 0xfff;
338 s
->blknum
= value
& 0xfff;
339 if (value
& (1 << 14)) /* STOP */
341 if (((s
->dcontrol
>> 12) & 3) == 1) { /* DatMode */
342 if (!(s
->dcontrol
& (1 << 18))) /* BACMD */
344 } else if (((s
->dcontrol
>> 12) & 3) == 2) { /* DatMode */
345 if (!(s
->dcontrol
& (1 << 19))) /* RACMD */
347 } else if (((s
->dcontrol
>> 12) & 3) == 3) /* DatMode */
348 if (!(s
->dcontrol
& (1 << 20))) /* RACMD */
350 s3c_mmci_fifo_run(s
);
353 s
->dstatus
&= ~(value
& 0x3f8);
356 /* write is tolerated on the s3c2440 */
359 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = (value
>> 0) & 0xff;
360 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = (value
>> 8) & 0xff;
361 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = (value
>> 16) & 0xff;
362 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = (value
>> 24) & 0xff;
363 s3c_mmci_fifo_run(s
);
366 s
->mask
= value
& 0x3ffff;
370 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long int)addr
);
374 static uint32_t s3c_mmci_readh(void *opaque
, target_phys_addr_t addr
)
376 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
379 if (s
->map
[addr
- s
->base
] == S3C_SDIDAT
) {
380 if (s
->fifolen
>= 2) {
381 ret
|= s
->fifo
[s
->fifostart
++] << 0;
383 ret
|= s
->fifo
[s
->fifostart
++] << 8;
386 s3c_mmci_fifo_run(s
);
388 printf("%s: FIFO underrun\n", __FUNCTION__
);
393 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long int)(addr
- s
->base
));
397 static void s3c_mmci_writeh(void *opaque
, target_phys_addr_t addr
,
400 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
402 if (s
->map
[addr
- s
->base
] == S3C_SDIDAT
) {
403 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = (value
>> 0) & 0xff;
404 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = (value
>> 8) & 0xff;
405 s3c_mmci_fifo_run(s
);
407 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long int)(addr
- s
->base
));
410 static uint32_t s3c_mmci_readb(void *opaque
, target_phys_addr_t addr
)
412 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
415 if (s
->map
[addr
- s
->base
] == S3C_SDIDAT
) {
416 if (s
->fifolen
> 0) {
417 ret
= s
->fifo
[s
->fifostart
++];
420 s3c_mmci_fifo_run(s
);
422 printf("%s: FIFO underrun\n", __FUNCTION__
);
427 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long int)(addr
- s
->base
));
431 static void s3c_mmci_writeb(void *opaque
, target_phys_addr_t addr
,
434 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
436 if (s
->map
[addr
- s
->base
] == S3C_SDIDAT
) {
437 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = value
;
438 s3c_mmci_fifo_run(s
);
440 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long int)(addr
- s
->base
));
443 static CPUReadMemoryFunc
*s3c_mmci_readfn
[] = {
449 static CPUWriteMemoryFunc
*s3c_mmci_writefn
[] = {
455 static void s3c_mmci_cardirq(void *opaque
, int line
, int level
)
457 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
459 // printf("%s: level %d (control %04x)\n", __FUNCTION__, level, s->control);
461 if (!(s
->control
& S3C2410_SDICON_SDIOIRQ
)) /* RcvIOInt */
466 s
->dstatus
|= S3C2410_SDIDSTA_SDIOIRQDETECT
; /* IOIntDet */
467 if (s
->mask
& S3C2410_SDIIMSK_SDIOIRQ
) /* IOIntDet */
468 qemu_irq_raise(s
->irq
);
471 static void s3c_mmci_save(QEMUFile
*f
, void *opaque
)
473 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
474 qemu_put_be32(f
, s
->blklen
);
475 qemu_put_be32(f
, s
->blknum
);
476 qemu_put_be32(f
, s
->blklen_cnt
);
477 qemu_put_be32(f
, s
->blknum_cnt
);
478 qemu_put_buffer(f
, s
->fifo
, sizeof(s
->fifo
));
479 qemu_put_be32(f
, s
->fifolen
);
480 qemu_put_be32(f
, s
->fifostart
);
481 qemu_put_be32(f
, s
->data
);
483 qemu_put_be32s(f
, &s
->control
);
484 qemu_put_be32s(f
, &s
->arg
);
485 qemu_put_be32s(f
, &s
->ccontrol
);
486 qemu_put_be32s(f
, &s
->cstatus
);
487 qemu_put_be32s(f
, &s
->dcontrol
);
488 qemu_put_be32s(f
, &s
->dstatus
);
489 qemu_put_be32s(f
, &s
->resp
[0]);
490 qemu_put_be32s(f
, &s
->resp
[1]);
491 qemu_put_be32s(f
, &s
->resp
[2]);
492 qemu_put_be32s(f
, &s
->resp
[3]);
493 qemu_put_be16s(f
, &s
->dtimer
);
494 qemu_put_be32s(f
, &s
->mask
);
495 qemu_put_8s(f
, &s
->prescaler
);
498 static const target_phys_addr_t s3c2410_regmap
[S3C_SDIMAX
+ 1] = {
499 [0 ... S3C_SDIMAX
] = -1,
502 [0x08] = S3C_SDICARG
,
503 [0x0c] = S3C_SDICCON
,
504 [0x10] = S3C_SDICSTA
,
505 [0x14] = S3C_SDIRSP0
,
506 [0x18] = S3C_SDIRSP1
,
507 [0x1c] = S3C_SDIRSP2
,
508 [0x20] = S3C_SDIRSP3
,
509 [0x24] = S3C_SDIDTIMER
,
510 [0x28] = S3C_SDIBSIZE
,
511 [0x2c] = S3C_SDIDCON
,
513 [0x34] = S3C_SDIDSTA
,
514 [0x38] = S3C_SDIFSTA
,
519 static const target_phys_addr_t s3c2440_regmap
[S3C_SDIMAX
+ 1] = {
520 [0 ... S3C_SDIMAX
] = -1,
523 [0x08] = S3C_SDICARG
,
524 [0x0c] = S3C_SDICCON
,
525 [0x10] = S3C_SDICSTA
,
526 [0x14] = S3C_SDIRSP0
,
527 [0x18] = S3C_SDIRSP1
,
528 [0x1c] = S3C_SDIRSP2
,
529 [0x20] = S3C_SDIRSP3
,
530 [0x24] = S3C_SDIDTIMER
,
531 [0x28] = S3C_SDIBSIZE
,
532 [0x2c] = S3C_SDIDCON
,
534 [0x34] = S3C_SDIDSTA
,
535 [0x38] = S3C_SDIFSTA
,
540 static int s3c_mmci_load(QEMUFile
*f
, void *opaque
, int version_id
)
542 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
543 s
->blklen
= qemu_get_be32(f
);
544 s
->blknum
= qemu_get_be32(f
);
545 s
->blklen_cnt
= qemu_get_be32(f
);
546 s
->blknum_cnt
= qemu_get_be32(f
);
547 qemu_get_buffer(f
, s
->fifo
, sizeof(s
->fifo
));
548 s
->fifolen
= qemu_get_be32(f
);
549 s
->fifostart
= qemu_get_be32(f
);
550 s
->data
= qemu_get_be32(f
);
552 qemu_get_be32s(f
, &s
->control
);
553 qemu_get_be32s(f
, &s
->arg
);
554 qemu_get_be32s(f
, &s
->ccontrol
);
555 qemu_get_be32s(f
, &s
->cstatus
);
556 qemu_get_be32s(f
, &s
->dcontrol
);
557 qemu_get_be32s(f
, &s
->dstatus
);
558 qemu_get_be32s(f
, &s
->resp
[0]);
559 qemu_get_be32s(f
, &s
->resp
[1]);
560 qemu_get_be32s(f
, &s
->resp
[2]);
561 qemu_get_be32s(f
, &s
->resp
[3]);
562 qemu_get_be16s(f
, &s
->dtimer
);
563 qemu_get_be32s(f
, &s
->mask
);
564 qemu_get_8s(f
, &s
->prescaler
);
569 struct s3c_mmci_state_s
*s3c_mmci_init(target_phys_addr_t base
, uint32_t cpu_id
,
570 SDState
*mmc
, qemu_irq irq
, qemu_irq
*dma
)
573 struct s3c_mmci_state_s
*s
;
578 s
= (struct s3c_mmci_state_s
*)
579 qemu_mallocz(sizeof(struct s3c_mmci_state_s
));
587 s
->map
= s3c2410_regmap
;
590 s
->map
= s3c2440_regmap
;
593 fprintf(stderr
, "%s: unknown MMC/SD/SDIO HC model %08x\n",
594 __FUNCTION__
, cpu_id
);
598 sd_set_cb(mmc
, 0, qemu_allocate_irqs(s3c_mmci_cardirq
, s
, 1)[0]);
602 iomemtype
= cpu_register_io_memory(0, s3c_mmci_readfn
,
603 s3c_mmci_writefn
, s
);
604 cpu_register_physical_memory(s
->base
, 0xffffff, iomemtype
);
606 register_savevm("s3c24xx_mmci", 0, 0, s3c_mmci_save
, s3c_mmci_load
, s
);