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
;
220 if (addr
> S3C_SDIMAX
)
250 return s
->blklen_cnt
| (s
->blknum_cnt
<< 12);
254 /* XXX on S3C2440 these bits have to cleared explicitely. */
255 if (((s
->dcontrol
>> 12) & 3) == 2) /* DatMode */
256 return s
->fifolen
| /* FFCNT */
257 ((s
->fifolen
> 31) ? (1 << 7) : 0) | /* RFHalf */
258 ((s
->fifolen
> 63) ? (1 << 8) : 0) | /* RFFull */
259 (s
->blklen_cnt
? 0 : (1 << 9)) | /* RFLast */
260 (3 << 10) | /* TFHalf */
261 (s
->fifolen
? (1 << 12) : 0); /* RFDET */
262 else if (((s
->dcontrol
>> 12) & 3) == 3) /* DatMode */
263 return s
->fifolen
| /* FFCNT */
264 (s
->fifolen
? 0 : (1 << 10)) | /* TFEmpty */
265 ((s
->fifolen
< 33) ? (1 << 11) : 0) | /* TFHalf */
266 ((s
->fifolen
< 64) ? (1 << 13) : 0); /* TFDET */
268 return s
->fifolen
; /* FFCNT */
271 if (s
->fifolen
>= 4) {
272 ret
|= s
->fifo
[s
->fifostart
++] << 0;
274 ret
|= s
->fifo
[s
->fifostart
++] << 8;
276 ret
|= s
->fifo
[s
->fifostart
++] << 16;
278 ret
|= s
->fifo
[s
->fifostart
++] << 24;
281 s3c_mmci_fifo_run(s
);
283 printf("%s: FIFO underrun\n", __FUNCTION__
);
290 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long int)addr
);
296 static void s3c_mmci_writew(void *opaque
, target_phys_addr_t addr
,
299 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
300 if (addr
> S3C_SDIMAX
)
306 s
->control
= value
& 0x1d;
307 if (value
& (1 << 1)) /* FRST */
311 s
->prescaler
= value
& 0xff;
317 s
->ccontrol
= value
& 0x1fff;
318 if (value
& (1 << 8)) /* CMST */
319 s3c_mmci_cmd_submit(s
);
320 s3c_mmci_fifo_run(s
);
323 s
->cstatus
&= ~(value
& 0x1e00);
326 s
->dtimer
= value
& 0xffff;
329 s
->blklen
= value
& 0xfff;
333 s
->blknum
= value
& 0xfff;
334 if (value
& (1 << 14)) /* STOP */
336 if (((s
->dcontrol
>> 12) & 3) == 1) { /* DatMode */
337 if (!(s
->dcontrol
& (1 << 18))) /* BACMD */
339 } else if (((s
->dcontrol
>> 12) & 3) == 2) { /* DatMode */
340 if (!(s
->dcontrol
& (1 << 19))) /* RACMD */
342 } else if (((s
->dcontrol
>> 12) & 3) == 3) /* DatMode */
343 if (!(s
->dcontrol
& (1 << 20))) /* RACMD */
345 s3c_mmci_fifo_run(s
);
348 s
->dstatus
&= ~(value
& 0x3f8);
351 /* write is tolerated on the s3c2440 */
354 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = (value
>> 0) & 0xff;
355 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = (value
>> 8) & 0xff;
356 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = (value
>> 16) & 0xff;
357 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = (value
>> 24) & 0xff;
358 s3c_mmci_fifo_run(s
);
361 s
->mask
= value
& 0x3ffff;
365 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long int)addr
);
369 static uint32_t s3c_mmci_readh(void *opaque
, target_phys_addr_t addr
)
371 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
374 if (s
->map
[addr
- s
->base
] == S3C_SDIDAT
) {
375 if (s
->fifolen
>= 2) {
376 ret
|= s
->fifo
[s
->fifostart
++] << 0;
378 ret
|= s
->fifo
[s
->fifostart
++] << 8;
381 s3c_mmci_fifo_run(s
);
383 printf("%s: FIFO underrun\n", __FUNCTION__
);
388 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long int)(addr
- s
->base
));
392 static void s3c_mmci_writeh(void *opaque
, target_phys_addr_t addr
,
395 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
397 if (s
->map
[addr
- s
->base
] == S3C_SDIDAT
) {
398 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = (value
>> 0) & 0xff;
399 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = (value
>> 8) & 0xff;
400 s3c_mmci_fifo_run(s
);
402 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long int)(addr
- s
->base
));
405 static uint32_t s3c_mmci_readb(void *opaque
, target_phys_addr_t addr
)
407 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
410 if (s
->map
[addr
- s
->base
] == S3C_SDIDAT
) {
411 if (s
->fifolen
> 0) {
412 ret
= s
->fifo
[s
->fifostart
++];
415 s3c_mmci_fifo_run(s
);
417 printf("%s: FIFO underrun\n", __FUNCTION__
);
422 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long int)(addr
- s
->base
));
426 static void s3c_mmci_writeb(void *opaque
, target_phys_addr_t addr
,
429 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
431 if (s
->map
[addr
- s
->base
] == S3C_SDIDAT
) {
432 s
->fifo
[(s
->fifostart
+ s
->fifolen
++) & 63] = value
;
433 s3c_mmci_fifo_run(s
);
435 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long int)(addr
- s
->base
));
438 static CPUReadMemoryFunc
*s3c_mmci_readfn
[] = {
444 static CPUWriteMemoryFunc
*s3c_mmci_writefn
[] = {
450 static void s3c_mmci_cardirq(void *opaque
, int line
, int level
)
452 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
454 if (~s
->control
& (1 << 3)) /* RcvIOInt */
459 s
->dstatus
|= 1 << 9; /* IOIntDet */
460 if (s
->mask
& (1 << 12)) /* IOIntDet */
461 qemu_irq_raise(s
->irq
);
464 static void s3c_mmci_save(QEMUFile
*f
, void *opaque
)
466 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
467 qemu_put_be32(f
, s
->blklen
);
468 qemu_put_be32(f
, s
->blknum
);
469 qemu_put_be32(f
, s
->blklen_cnt
);
470 qemu_put_be32(f
, s
->blknum_cnt
);
471 qemu_put_buffer(f
, s
->fifo
, sizeof(s
->fifo
));
472 qemu_put_be32(f
, s
->fifolen
);
473 qemu_put_be32(f
, s
->fifostart
);
474 qemu_put_be32(f
, s
->data
);
476 qemu_put_be32s(f
, &s
->control
);
477 qemu_put_be32s(f
, &s
->arg
);
478 qemu_put_be32s(f
, &s
->ccontrol
);
479 qemu_put_be32s(f
, &s
->cstatus
);
480 qemu_put_be32s(f
, &s
->dcontrol
);
481 qemu_put_be32s(f
, &s
->dstatus
);
482 qemu_put_be32s(f
, &s
->resp
[0]);
483 qemu_put_be32s(f
, &s
->resp
[1]);
484 qemu_put_be32s(f
, &s
->resp
[2]);
485 qemu_put_be32s(f
, &s
->resp
[3]);
486 qemu_put_be16s(f
, &s
->dtimer
);
487 qemu_put_be32s(f
, &s
->mask
);
488 qemu_put_8s(f
, &s
->prescaler
);
491 static const target_phys_addr_t s3c2410_regmap
[S3C_SDIMAX
+ 1] = {
492 [0 ... S3C_SDIMAX
] = -1,
495 [0x08] = S3C_SDICARG
,
496 [0x0c] = S3C_SDICCON
,
497 [0x10] = S3C_SDICSTA
,
498 [0x14] = S3C_SDIRSP0
,
499 [0x18] = S3C_SDIRSP1
,
500 [0x1c] = S3C_SDIRSP2
,
501 [0x20] = S3C_SDIRSP3
,
502 [0x24] = S3C_SDIDTIMER
,
503 [0x28] = S3C_SDIBSIZE
,
504 [0x2c] = S3C_SDIDCON
,
506 [0x34] = S3C_SDIDSTA
,
507 [0x38] = S3C_SDIFSTA
,
512 static const target_phys_addr_t s3c2440_regmap
[S3C_SDIMAX
+ 1] = {
513 [0 ... S3C_SDIMAX
] = -1,
516 [0x08] = S3C_SDICARG
,
517 [0x0c] = S3C_SDICCON
,
518 [0x10] = S3C_SDICSTA
,
519 [0x14] = S3C_SDIRSP0
,
520 [0x18] = S3C_SDIRSP1
,
521 [0x1c] = S3C_SDIRSP2
,
522 [0x20] = S3C_SDIRSP3
,
523 [0x24] = S3C_SDIDTIMER
,
524 [0x28] = S3C_SDIBSIZE
,
525 [0x2c] = S3C_SDIDCON
,
527 [0x34] = S3C_SDIDSTA
,
528 [0x38] = S3C_SDIFSTA
,
533 static int s3c_mmci_load(QEMUFile
*f
, void *opaque
, int version_id
)
535 struct s3c_mmci_state_s
*s
= (struct s3c_mmci_state_s
*) opaque
;
536 s
->blklen
= qemu_get_be32(f
);
537 s
->blknum
= qemu_get_be32(f
);
538 s
->blklen_cnt
= qemu_get_be32(f
);
539 s
->blknum_cnt
= qemu_get_be32(f
);
540 qemu_get_buffer(f
, s
->fifo
, sizeof(s
->fifo
));
541 s
->fifolen
= qemu_get_be32(f
);
542 s
->fifostart
= qemu_get_be32(f
);
543 s
->data
= qemu_get_be32(f
);
545 qemu_get_be32s(f
, &s
->control
);
546 qemu_get_be32s(f
, &s
->arg
);
547 qemu_get_be32s(f
, &s
->ccontrol
);
548 qemu_get_be32s(f
, &s
->cstatus
);
549 qemu_get_be32s(f
, &s
->dcontrol
);
550 qemu_get_be32s(f
, &s
->dstatus
);
551 qemu_get_be32s(f
, &s
->resp
[0]);
552 qemu_get_be32s(f
, &s
->resp
[1]);
553 qemu_get_be32s(f
, &s
->resp
[2]);
554 qemu_get_be32s(f
, &s
->resp
[3]);
555 qemu_get_be16s(f
, &s
->dtimer
);
556 qemu_get_be32s(f
, &s
->mask
);
557 qemu_get_8s(f
, &s
->prescaler
);
562 struct s3c_mmci_state_s
*s3c_mmci_init(target_phys_addr_t base
, uint16_t model
,
563 SDState
*mmc
, qemu_irq irq
, qemu_irq
*dma
)
566 struct s3c_mmci_state_s
*s
;
571 s
= (struct s3c_mmci_state_s
*)
572 qemu_mallocz(sizeof(struct s3c_mmci_state_s
));
580 s
->map
= s3c2410_regmap
;
583 s
->map
= s3c2440_regmap
;
586 fprintf(stderr
, "%s: unknown MMC/SD/SDIO HC model %04x\n",
587 __FUNCTION__
, model
);
591 sd_set_cb(mmc
, 0, qemu_allocate_irqs(s3c_mmci_cardirq
, s
, 1)[0]);
592 //mmc->irq = qemu_allocate_irqs(s3c_mmci_cardirq, s, 1)[0];
596 iomemtype
= cpu_register_io_memory(0, s3c_mmci_readfn
,
597 s3c_mmci_writefn
, s
);
598 cpu_register_physical_memory(s
->base
, 0xffffff, iomemtype
);
600 register_savevm("s3c24xx_mmci", 0, 0, s3c_mmci_save
, s3c_mmci_load
, s
);