2 * Samsung S3C24xx series MMC/SD/SDIO Host Controller interface.
4 * Copyright (c) 2007 OpenMoko, Inc.
5 * Author: Andrzej Zaborowski <andrew@openedhand.com>
6 * With: Michel Pollet <buserror@gmail.com>
8 * This code is licenced under the GNU GPL v2.
15 #include "s3c24xx_mmci.h"
17 #define S3C_SDICON 0x00 /* SDI Control register */
18 #define S3C_SDIPRE 0x04 /* SDI Baud Rate Prescaler register */
19 #define S3C_SDICARG 0x08 /* SDI Command Argument register */
20 #define S3C_SDICCON 0x0c /* SDI Command Control register */
21 #define S3C_SDICSTA 0x10 /* SDI Command Status register */
22 #define S3C_SDIRSP0 0x14 /* SDI Response register 0 */
23 #define S3C_SDIRSP1 0x18 /* SDI Response register 1 */
24 #define S3C_SDIRSP2 0x1c /* SDI Response register 2 */
25 #define S3C_SDIRSP3 0x20 /* SDI Response register 3 */
26 #define S3C_SDIDTIMER 0x24 /* SDI Data / Busy Timer register */
27 #define S3C_SDIBSIZE 0x28 /* SDI Block Size register */
28 #define S3C_SDIDCON 0x2c /* SDI Data Control register */
29 #define S3C_SDICNT 0x30 /* SDI Data Remain Counter register */
30 #define S3C_SDIDSTA 0x34 /* SDI Data Status register */
31 #define S3C_SDIFSTA 0x38 /* SDI FIFO Status register */
32 #define S3C_SDIDAT 0x3c /* SDI Data register */
33 #define S3C_SDIMSK 0x40 /* SDI Interrupt Mask register */
35 #define S3C_SDIMAX 0x40
37 #define S3C2410_SDIDSTA_COMPLETION (S3C2410_SDIDSTA_TXDATAON|S3C2410_SDIDSTA_RXDATAON)
39 struct s3c_mmci_state_s
{
40 target_phys_addr_t base
;
67 const target_phys_addr_t
*map
;
70 void s3c_mmci_reset(struct s3c_mmci_state_s
*s
)
96 static void s3c_mmci_fifo_run(struct s3c_mmci_state_s
*s
)
98 int len
, dmalevel
= 0;
103 if (((s
->dcontrol
>> 12) & 3) == 2) { /* DatMode */
104 s
->dstatus
&= ~S3C2410_SDIDSTA_COMPLETION
;
105 s
->dstatus
|= S3C2410_SDIDSTA_RXDATAON
; /* RxDatOn */
106 while (s
->fifolen
< 64 && s
->blklen_cnt
) {
107 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] =
108 sd_read_data(s
->card
);
109 if (!(-- s
->blklen_cnt
))
110 if (-- s
->blknum_cnt
)
111 s
->blklen_cnt
= s
->blklen
;
113 if ((s
->mask
& S3C2410_SDIIMSK_RXFIFOHALF
) && /* RFHalf */
114 s
->fifolen
> 31 && len
< 32)
115 qemu_irq_raise(s
->irq
);
116 if ((s
->mask
& S3C2410_SDIIMSK_RXFIFOFULL
) && /* RFFull */
117 s
->fifolen
> 63 && len
< 64)
118 qemu_irq_raise(s
->irq
);
119 if ((s
->mask
& S3C2410_SDIIMSK_RXFIFOLAST
) && !s
->blklen_cnt
) /* RFLast */
120 qemu_irq_raise(s
->irq
);
121 dmalevel
= !!s
->fifolen
;
122 } else if (((s
->dcontrol
>> 12) & 3) == 3) { /* DatMode */
123 s
->dstatus
&= ~S3C2410_SDIDSTA_COMPLETION
;
124 s
->dstatus
|= S3C2410_SDIDSTA_TXDATAON
; /* TxDatOn */
125 while (s
->fifolen
&& s
->blklen_cnt
) {
126 sd_write_data(s
->card
, s
->fifo
[s
->fifostart
++]);
129 if (!(-- s
->blklen_cnt
))
130 if (-- s
->blknum_cnt
)
131 s
->blklen_cnt
= s
->blklen
;
133 if ((s
->mask
& S3C2410_SDIIMSK_TXFIFOEMPTY
) && !s
->fifolen
&& len
) /* TFEmpty */
134 qemu_irq_raise(s
->irq
);
135 if ((s
->mask
& S3C2410_SDIIMSK_TXFIFOHALF
) && /* TFHalf */
136 s
->fifolen
< 33 && len
> 32)
137 qemu_irq_raise(s
->irq
);
138 dmalevel
= (s
->fifolen
< 64) && (s
->blklen_cnt
> 0);
142 if (!s
->blklen_cnt
) {
144 s
->dstatus
&= ~S3C2410_SDIDSTA_COMPLETION
;
145 s
->dstatus
|= S3C2410_SDIDSTA_XFERFINISH
; /* DatFin */
146 if (s
->mask
& S3C2410_SDIIMSK_DATAFINISH
) /* DatFin */
147 qemu_irq_raise(s
->irq
);
150 if (s
->dcontrol
& S3C2410_SDIDCON_DMAEN
) { /* EnDMA */
151 qemu_set_irq(s
->dma
[S3C_RQ_SDI0
], dmalevel
);
152 qemu_set_irq(s
->dma
[S3C_RQ_SDI1
], dmalevel
);
153 qemu_set_irq(s
->dma
[S3C_RQ_SDI2
], dmalevel
);
157 static void s3c_mmci_cmd_submit(struct s3c_mmci_state_s
*s
)
161 uint8_t response
[16];
163 request
.cmd
= s
->ccontrol
& 0x3f;
164 request
.arg
= s
->arg
;
165 request
.crc
= 0; /* FIXME */
167 rsplen
= sd_do_command(s
->card
, &request
, response
);
168 s
->cstatus
= (s
->cstatus
& ~0x11ff) | request
.cmd
; /* RspIndex */
169 s
->cstatus
|= S3C2410_SDICMDSTAT_CMDSENT
; /* CmdSent */
170 if (s
->mask
& S3C2410_SDIIMSK_CMDSENT
) /* CmdSent */
171 qemu_irq_raise(s
->irq
);
173 memset(s
->resp
, 0, sizeof(s
->resp
));
174 if (!(s
->ccontrol
& S3C2410_SDICMDCON_WAITRSP
)) /* WaitRsp */
175 goto complete
; /* No response */
177 if (s
->ccontrol
& S3C2410_SDICMDCON_LONGRSP
) { /* LongRsp */
182 /* R1, R3, R4, R5 or R6 */
187 for (i
= 0; i
< rsplen
; i
++)
188 s
->resp
[i
>> 2] |= response
[i
] << ((~i
& 3) << 3);
190 s
->cstatus
|= 1 << 9; /* RspFin */
191 if (s
->mask
& S3C2410_SDIIMSK_RESPONSEND
) /* RspEnd */
192 qemu_irq_raise(s
->irq
);
195 s
->blklen_cnt
= s
->blklen
;
196 s
->blknum_cnt
= s
->blknum
;
199 if (((s
->dcontrol
>> 12) & 3) == 1) { /* DatMode */
200 if (s
->dcontrol
& (1 << 18)) /* BACMD */
202 } else if (((s
->dcontrol
>> 12) & 3) == 2) { /* DatMode */
203 if (s
->dcontrol
& (1 << 19)) /* RACMD */
205 } else if (((s
->dcontrol
>> 12) & 3) == 3) /* DatMode */
206 if (s
->dcontrol
& (1 << 20)) /* RACMD */
208 /* HACK: This bit only matters for SDIO but we don't have a good
209 * way to tell if the card is an SDIO, so only check if this is
210 * CMD53, the only SDIO command potentially using the DAT lines. */
211 if (request
.cmd
== 53)
212 s
->data
&= s
->ccontrol
>> 11; /* WithData */
216 s
->cstatus
|= 1 << 10; /* CmdTout */
217 if (s
->mask
& S3C2410_SDIIMSK_CMDTIMEOUT
) /* CmdTout */
218 qemu_irq_raise(s
->irq
);
222 static uint32_t s3c_mmci_readw(void *opaque
, target_phys_addr_t addr
)
224 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
226 if (addr
> S3C_SDIMAX
)
256 return s
->blklen_cnt
| (s
->blknum_cnt
<< 12);
260 /* TODO: S3C2440 these bits have to cleared explicitely. */
261 if (((s
->dcontrol
>> 12) & 3) == 2) /* DatMode */
262 return s
->fifolen
| /* FFCNT */
263 ((s
->fifolen
> 31) ? S3C2410_SDIFSTA_RFHALF
: 0) | /* RFHalf */
264 ((s
->fifolen
> 63) ? S3C2410_SDIFSTA_RFFULL
: 0) | /* RFFulx */
265 (s
->blklen_cnt
? 0 : S3C2410_SDIFSTA_RFLAST
) | /* RFLast */
266 (3 << 10) | /* TFHalf */
267 (s
->fifolen
? (1 << 12) : 0); /* RFDET */
268 else if (((s
->dcontrol
>> 12) & 3) == 3) /* DatMode */
269 return s
->fifolen
| /* FFCNT */
270 (s
->fifolen
? 0 : S3C2410_SDIFSTA_TFEMPTY
) | /* TFEmpty */
271 ((s
->fifolen
< 33) ? S3C2410_SDIFSTA_TFHALF
: 0) | /* TFHalf */
272 ((s
->fifolen
< 64) ? S3C2410_SDIFSTA_TFDET
: 0); /* TFDET */
274 return s
->fifolen
; /* FFCNT */
277 if (s
->fifolen
>= 4) {
278 ret
|= s
->fifo
[s
->fifostart
++] << 0;
280 ret
|= s
->fifo
[s
->fifostart
++] << 8;
282 ret
|= s
->fifo
[s
->fifostart
++] << 16;
284 ret
|= s
->fifo
[s
->fifostart
++] << 24;
287 s3c_mmci_fifo_run(s
);
289 printf("%s: FIFO underrun\n", __FUNCTION__
);
296 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long int)addr
);
302 static void s3c_mmci_writew(void *opaque
, target_phys_addr_t addr
,
305 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
306 if (addr
> S3C_SDIMAX
)
312 s
->control
= value
& 0x1d;
313 if (value
& (1 << 1)) /* FRST */
317 s
->prescaler
= value
& 0xff;
323 s
->ccontrol
= value
& 0x1fff;
324 if (value
& (1 << 8)) /* CMST */
325 s3c_mmci_cmd_submit(s
);
326 s3c_mmci_fifo_run(s
);
329 s
->cstatus
&= ~(value
& 0x1e00);
332 s
->dtimer
= value
& 0xffff;
335 s
->blklen
= value
& 0xfff;
339 s
->blknum
= value
& 0xfff;
340 if (value
& (1 << 14)) /* STOP */
342 if (((s
->dcontrol
>> 12) & 3) == 1) { /* DatMode */
343 if (!(s
->dcontrol
& (1 << 18))) /* BACMD */
345 } else if (((s
->dcontrol
>> 12) & 3) == 2) { /* DatMode */
346 if (!(s
->dcontrol
& (1 << 19))) /* RACMD */
348 } else if (((s
->dcontrol
>> 12) & 3) == 3) /* DatMode */
349 if (!(s
->dcontrol
& (1 << 20))) /* RACMD */
351 s3c_mmci_fifo_run(s
);
354 s
->dstatus
&= ~(value
& 0x3f8);
357 /* write is tolerated on the s3c2440 */
360 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = (value
>> 0) & 0xff;
361 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = (value
>> 8) & 0xff;
362 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = (value
>> 16) & 0xff;
363 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = (value
>> 24) & 0xff;
364 s3c_mmci_fifo_run(s
);
367 s
->mask
= value
& 0x3ffff;
371 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long int)addr
);
375 static uint32_t s3c_mmci_readh(void *opaque
, target_phys_addr_t addr
)
377 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
380 if (s
->map
[addr
- s
->base
] == S3C_SDIDAT
) {
381 if (s
->fifolen
>= 2) {
382 ret
|= s
->fifo
[s
->fifostart
++] << 0;
384 ret
|= s
->fifo
[s
->fifostart
++] << 8;
387 s3c_mmci_fifo_run(s
);
389 printf("%s: FIFO underrun\n", __FUNCTION__
);
394 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long int)(addr
- s
->base
));
398 static void s3c_mmci_writeh(void *opaque
, target_phys_addr_t addr
,
401 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
403 if (s
->map
[addr
- s
->base
] == S3C_SDIDAT
) {
404 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = (value
>> 0) & 0xff;
405 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = (value
>> 8) & 0xff;
406 s3c_mmci_fifo_run(s
);
408 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long int)(addr
- s
->base
));
411 static uint32_t s3c_mmci_readb(void *opaque
, target_phys_addr_t addr
)
413 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
416 if (s
->map
[addr
- s
->base
] == S3C_SDIDAT
) {
417 if (s
->fifolen
> 0) {
418 ret
= s
->fifo
[s
->fifostart
++];
421 s3c_mmci_fifo_run(s
);
423 printf("%s: FIFO underrun\n", __FUNCTION__
);
428 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long int)(addr
- s
->base
));
432 static void s3c_mmci_writeb(void *opaque
, target_phys_addr_t addr
,
435 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
437 if (s
->map
[addr
- s
->base
] == S3C_SDIDAT
) {
438 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = value
;
439 s3c_mmci_fifo_run(s
);
441 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long int)(addr
- s
->base
));
444 static CPUReadMemoryFunc
*s3c_mmci_readfn
[] = {
450 static CPUWriteMemoryFunc
*s3c_mmci_writefn
[] = {
456 static void s3c_mmci_cardirq(void *opaque
, int line
, int level
)
458 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
460 // printf("%s: level %d (control %04x)\n", __FUNCTION__, level, s->control);
462 if (!(s
->control
& S3C2410_SDICON_SDIOIRQ
)) /* RcvIOInt */
467 s
->dstatus
|= S3C2410_SDIDSTA_SDIOIRQDETECT
; /* IOIntDet */
468 if (s
->mask
& S3C2410_SDIIMSK_SDIOIRQ
) /* IOIntDet */
469 qemu_irq_raise(s
->irq
);
472 static void s3c_mmci_save(QEMUFile
*f
, void *opaque
)
474 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
475 qemu_put_be32(f
, s
->blklen
);
476 qemu_put_be32(f
, s
->blknum
);
477 qemu_put_be32(f
, s
->blklen_cnt
);
478 qemu_put_be32(f
, s
->blknum_cnt
);
479 qemu_put_buffer(f
, s
->fifo
, sizeof(s
->fifo
));
480 qemu_put_be32(f
, s
->fifolen
);
481 qemu_put_be32(f
, s
->fifostart
);
482 qemu_put_be32(f
, s
->data
);
484 qemu_put_be32s(f
, &s
->control
);
485 qemu_put_be32s(f
, &s
->arg
);
486 qemu_put_be32s(f
, &s
->ccontrol
);
487 qemu_put_be32s(f
, &s
->cstatus
);
488 qemu_put_be32s(f
, &s
->dcontrol
);
489 qemu_put_be32s(f
, &s
->dstatus
);
490 qemu_put_be32s(f
, &s
->resp
[0]);
491 qemu_put_be32s(f
, &s
->resp
[1]);
492 qemu_put_be32s(f
, &s
->resp
[2]);
493 qemu_put_be32s(f
, &s
->resp
[3]);
494 qemu_put_be16s(f
, &s
->dtimer
);
495 qemu_put_be32s(f
, &s
->mask
);
496 qemu_put_8s(f
, &s
->prescaler
);
499 static const target_phys_addr_t s3c2410_regmap
[S3C_SDIMAX
+ 1] = {
500 [0 ... S3C_SDIMAX
] = -1,
503 [0x08] = S3C_SDICARG
,
504 [0x0c] = S3C_SDICCON
,
505 [0x10] = S3C_SDICSTA
,
506 [0x14] = S3C_SDIRSP0
,
507 [0x18] = S3C_SDIRSP1
,
508 [0x1c] = S3C_SDIRSP2
,
509 [0x20] = S3C_SDIRSP3
,
510 [0x24] = S3C_SDIDTIMER
,
511 [0x28] = S3C_SDIBSIZE
,
512 [0x2c] = S3C_SDIDCON
,
514 [0x34] = S3C_SDIDSTA
,
515 [0x38] = S3C_SDIFSTA
,
520 static const target_phys_addr_t s3c2440_regmap
[S3C_SDIMAX
+ 1] = {
521 [0 ... S3C_SDIMAX
] = -1,
524 [0x08] = S3C_SDICARG
,
525 [0x0c] = S3C_SDICCON
,
526 [0x10] = S3C_SDICSTA
,
527 [0x14] = S3C_SDIRSP0
,
528 [0x18] = S3C_SDIRSP1
,
529 [0x1c] = S3C_SDIRSP2
,
530 [0x20] = S3C_SDIRSP3
,
531 [0x24] = S3C_SDIDTIMER
,
532 [0x28] = S3C_SDIBSIZE
,
533 [0x2c] = S3C_SDIDCON
,
535 [0x34] = S3C_SDIDSTA
,
536 [0x38] = S3C_SDIFSTA
,
541 static int s3c_mmci_load(QEMUFile
*f
, void *opaque
, int version_id
)
543 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
544 s
->blklen
= qemu_get_be32(f
);
545 s
->blknum
= qemu_get_be32(f
);
546 s
->blklen_cnt
= qemu_get_be32(f
);
547 s
->blknum_cnt
= qemu_get_be32(f
);
548 qemu_get_buffer(f
, s
->fifo
, sizeof(s
->fifo
));
549 s
->fifolen
= qemu_get_be32(f
);
550 s
->fifostart
= qemu_get_be32(f
);
551 s
->data
= qemu_get_be32(f
);
553 qemu_get_be32s(f
, &s
->control
);
554 qemu_get_be32s(f
, &s
->arg
);
555 qemu_get_be32s(f
, &s
->ccontrol
);
556 qemu_get_be32s(f
, &s
->cstatus
);
557 qemu_get_be32s(f
, &s
->dcontrol
);
558 qemu_get_be32s(f
, &s
->dstatus
);
559 qemu_get_be32s(f
, &s
->resp
[0]);
560 qemu_get_be32s(f
, &s
->resp
[1]);
561 qemu_get_be32s(f
, &s
->resp
[2]);
562 qemu_get_be32s(f
, &s
->resp
[3]);
563 qemu_get_be16s(f
, &s
->dtimer
);
564 qemu_get_be32s(f
, &s
->mask
);
565 qemu_get_8s(f
, &s
->prescaler
);
570 struct s3c_mmci_state_s
*s3c_mmci_init(target_phys_addr_t base
, uint32_t cpu_id
,
571 SDState
*mmc
, qemu_irq irq
, qemu_irq
*dma
)
574 struct s3c_mmci_state_s
*s
;
579 s
= (struct s3c_mmci_state_s
*)
580 qemu_mallocz(sizeof(struct s3c_mmci_state_s
));
588 s
->map
= s3c2410_regmap
;
591 s
->map
= s3c2440_regmap
;
594 fprintf(stderr
, "%s: unknown MMC/SD/SDIO HC model %08x\n",
595 __FUNCTION__
, cpu_id
);
599 sd_set_cb(mmc
, 0, qemu_allocate_irqs(s3c_mmci_cardirq
, s
, 1)[0]);
603 iomemtype
= cpu_register_io_memory(0, s3c_mmci_readfn
,
604 s3c_mmci_writefn
, s
);
605 cpu_register_physical_memory(s
->base
, 0xffffff, iomemtype
);
607 register_savevm("s3c24xx_mmci", 0, 0, s3c_mmci_save
, s3c_mmci_load
, s
);