MINI2440: General update
[qemu/mini2440.git] / hw / s3c24xx_mmci.c
blob417d9dd7314c0323939a109ffdd54406bef2ceb3
1 /*
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.
9 */
11 #include "s3c.h"
12 #include "sd.h"
13 #include "hw.h"
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;
41 qemu_irq irq;
42 qemu_irq *dma;
44 SDState *card;
46 int blklen;
47 int blknum;
48 int blklen_cnt;
49 int blknum_cnt;
50 uint8_t fifo[64];
51 int fifolen;
52 int fifostart;
53 int data;
55 uint32_t control;
56 uint32_t arg;
57 uint32_t ccontrol;
58 uint32_t cstatus;
59 uint32_t dcontrol;
60 uint32_t dstatus;
61 uint32_t resp[4];
62 uint16_t dtimer;
63 uint32_t mask;
64 uint8_t prescaler;
66 uint32_t cpu_id;
67 const target_phys_addr_t *map;
70 void s3c_mmci_reset(struct s3c_mmci_state_s *s)
72 if (!s)
73 return;
75 s->blklen = 0;
76 s->blknum = 0;
77 s->blklen_cnt = 0;
78 s->blknum_cnt = 0;
79 s->fifolen = 0;
80 s->fifostart = 0;
81 s->control = 0;
82 s->arg = 0;
83 s->ccontrol = 0;
84 s->cstatus = 0;
85 s->dcontrol = 0;
86 s->dstatus = 0;
87 s->resp[0] = 0;
88 s->resp[1] = 0;
89 s->resp[2] = 0;
90 s->resp[3] = 0;
91 s->dtimer = 0x2000;
92 s->mask = 0;
93 s->prescaler = 0;
96 static void s3c_mmci_fifo_run(struct s3c_mmci_state_s *s)
98 int len, dmalevel = 0;
99 if (!s->data)
100 goto dmaupdate;
102 len = s->fifolen;
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 ++]);
127 s->fifostart &= 63;
128 s->fifolen --;
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);
139 } else
140 return;
142 if (!s->blklen_cnt) {
143 s->data = 0;
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);
149 dmaupdate:
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)
159 int rsplen, i;
160 SDRequest request;
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 */
178 /* R2 */
179 if (rsplen < 16)
180 goto timeout;
181 } else {
182 /* R1, R3, R4, R5 or R6 */
183 if (rsplen < 4)
184 goto timeout;
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);
194 complete:
195 s->blklen_cnt = s->blklen;
196 s->blknum_cnt = s->blknum;
198 s->data = 0;
199 if (((s->dcontrol >> 12) & 3) == 1) { /* DatMode */
200 if (s->dcontrol & (1 << 18)) /* BACMD */
201 s->data = 1;
202 } else if (((s->dcontrol >> 12) & 3) == 2) { /* DatMode */
203 if (s->dcontrol & (1 << 19)) /* RACMD */
204 s->data = 1;
205 } else if (((s->dcontrol >> 12) & 3) == 3) /* DatMode */
206 if (s->dcontrol & (1 << 20)) /* RACMD */
207 s->data = 1;
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 */
213 return;
215 timeout:
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;
225 uint32_t ret;
226 if (addr > S3C_SDIMAX)
227 goto bad_reg;
228 addr = s->map[addr];
230 switch (addr) {
231 case S3C_SDICON:
232 return s->control;
233 case S3C_SDIPRE:
234 return s->prescaler;
235 case S3C_SDICARG:
236 return s->arg;
237 case S3C_SDICCON:
238 return s->ccontrol;
239 case S3C_SDICSTA:
240 return s->cstatus;
241 case S3C_SDIRSP0:
242 return s->resp[0];
243 case S3C_SDIRSP1:
244 return s->resp[1];
245 case S3C_SDIRSP2:
246 return s->resp[2];
247 case S3C_SDIRSP3:
248 return s->resp[3];
249 case S3C_SDIDTIMER:
250 return s->dtimer;
251 case S3C_SDIBSIZE:
252 return s->blklen;
253 case S3C_SDIDCON:
254 return s->dcontrol;
255 case S3C_SDICNT:
256 return s->blklen_cnt | (s->blknum_cnt << 12);
257 case S3C_SDIDSTA:
258 return s->dstatus;
259 case S3C_SDIFSTA:
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 */
273 else
274 return s->fifolen; /* FFCNT */
275 case S3C_SDIDAT:
276 ret = 0;
277 if (s->fifolen >= 4) {
278 ret |= s->fifo[s->fifostart ++] << 0;
279 s->fifostart &= 63;
280 ret |= s->fifo[s->fifostart ++] << 8;
281 s->fifostart &= 63;
282 ret |= s->fifo[s->fifostart ++] << 16;
283 s->fifostart &= 63;
284 ret |= s->fifo[s->fifostart ++] << 24;
285 s->fifostart &= 63;
286 s->fifolen -= 4;
287 s3c_mmci_fifo_run(s);
288 } else
289 printf("%s: FIFO underrun\n", __FUNCTION__);
291 return ret;
292 case S3C_SDIMSK:
293 return s->mask;
294 default:
295 bad_reg:
296 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long int)addr);
297 break;
299 return 0;
302 static void s3c_mmci_writew(void *opaque, target_phys_addr_t addr,
303 uint32_t value)
305 struct s3c_mmci_state_s *s = (struct s3c_mmci_state_s *) opaque;
306 if (addr > S3C_SDIMAX)
307 goto bad_reg;
308 addr = s->map[addr];
310 switch (addr) {
311 case S3C_SDICON:
312 s->control = value & 0x1d;
313 if (value & (1 << 1)) /* FRST */
314 s->fifolen = 0;
315 break;
316 case S3C_SDIPRE:
317 s->prescaler = value & 0xff;
318 break;
319 case S3C_SDICARG:
320 s->arg = value;
321 break;
322 case S3C_SDICCON:
323 s->ccontrol = value & 0x1fff;
324 if (value & (1 << 8)) /* CMST */
325 s3c_mmci_cmd_submit(s);
326 s3c_mmci_fifo_run(s);
327 break;
328 case S3C_SDICSTA:
329 s->cstatus &= ~(value & 0x1e00);
330 break;
331 case S3C_SDIDTIMER:
332 s->dtimer = value & 0xffff;
333 break;
334 case S3C_SDIBSIZE:
335 s->blklen = value & 0xfff;
336 break;
337 case S3C_SDIDCON:
338 s->dcontrol = value;
339 s->blknum = value & 0xfff;
340 if (value & (1 << 14)) /* STOP */
341 s->data = 0;
342 if (((s->dcontrol >> 12) & 3) == 1) { /* DatMode */
343 if (!(s->dcontrol & (1 << 18))) /* BACMD */
344 s->data = 1;
345 } else if (((s->dcontrol >> 12) & 3) == 2) { /* DatMode */
346 if (!(s->dcontrol & (1 << 19))) /* RACMD */
347 s->data = 1;
348 } else if (((s->dcontrol >> 12) & 3) == 3) /* DatMode */
349 if (!(s->dcontrol & (1 << 20))) /* RACMD */
350 s->data = 1;
351 s3c_mmci_fifo_run(s);
352 break;
353 case S3C_SDIDSTA:
354 s->dstatus &= ~(value & 0x3f8);
355 break;
356 case S3C_SDIFSTA:
357 /* write is tolerated on the s3c2440 */
358 break;
359 case S3C_SDIDAT:
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);
365 break;
366 case S3C_SDIMSK:
367 s->mask = value & 0x3ffff;
368 break;
369 default:
370 bad_reg:
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;
378 uint16_t ret = 0;
380 if (s->map[addr - s->base] == S3C_SDIDAT) {
381 if (s->fifolen >= 2) {
382 ret |= s->fifo[s->fifostart ++] << 0;
383 s->fifostart &= 63;
384 ret |= s->fifo[s->fifostart ++] << 8;
385 s->fifostart &= 63;
386 s->fifolen -= 2;
387 s3c_mmci_fifo_run(s);
388 } else
389 printf("%s: FIFO underrun\n", __FUNCTION__);
391 return ret;
394 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long int)(addr - s->base));
395 return 0;
398 static void s3c_mmci_writeh(void *opaque, target_phys_addr_t addr,
399 uint32_t value)
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);
407 } else
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;
414 uint8_t ret = 0;
416 if (s->map[addr - s->base] == S3C_SDIDAT) {
417 if (s->fifolen > 0) {
418 ret = s->fifo[s->fifostart ++];
419 s->fifostart &= 63;
420 s->fifolen --;
421 s3c_mmci_fifo_run(s);
422 } else
423 printf("%s: FIFO underrun\n", __FUNCTION__);
425 return ret;
428 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long int)(addr - s->base));
429 return 0;
432 static void s3c_mmci_writeb(void *opaque, target_phys_addr_t addr,
433 uint32_t value)
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);
440 } else
441 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long int)(addr - s->base));
444 static CPUReadMemoryFunc *s3c_mmci_readfn[] = {
445 s3c_mmci_readb,
446 s3c_mmci_readh,
447 s3c_mmci_readw,
450 static CPUWriteMemoryFunc *s3c_mmci_writefn[] = {
451 s3c_mmci_writeb,
452 s3c_mmci_writeh,
453 s3c_mmci_writew,
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 */
463 return;
464 if (!level)
465 return;
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,
501 [0x00] = S3C_SDICON,
502 [0x04] = S3C_SDIPRE,
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,
513 [0x30] = S3C_SDICNT,
514 [0x34] = S3C_SDIDSTA,
515 [0x38] = S3C_SDIFSTA,
516 [0x3c] = S3C_SDIDAT,
517 [0x40] = S3C_SDIMSK,
520 static const target_phys_addr_t s3c2440_regmap[S3C_SDIMAX + 1] = {
521 [0 ... S3C_SDIMAX] = -1,
522 [0x00] = S3C_SDICON,
523 [0x04] = S3C_SDIPRE,
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,
534 [0x30] = S3C_SDICNT,
535 [0x34] = S3C_SDIDSTA,
536 [0x38] = S3C_SDIFSTA,
537 [0x3c] = S3C_SDIMSK,
538 [0x40] = S3C_SDIDAT,
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);
567 return 0;
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)
573 int iomemtype;
574 struct s3c_mmci_state_s *s;
576 if (!mmc)
577 return 0;
579 s = (struct s3c_mmci_state_s *)
580 qemu_mallocz(sizeof(struct s3c_mmci_state_s));
581 s->base = base;
582 s->irq = irq;
583 s->dma = dma;
584 s->card = mmc;
585 s->cpu_id = cpu_id;
586 switch (cpu_id) {
587 case S3C_CPU_2410:
588 s->map = s3c2410_regmap;
589 break;
590 case S3C_CPU_2440:
591 s->map = s3c2440_regmap;
592 break;
593 default:
594 fprintf(stderr, "%s: unknown MMC/SD/SDIO HC model %08x\n",
595 __FUNCTION__, cpu_id);
596 exit(-1);
599 sd_set_cb(mmc, 0, qemu_allocate_irqs(s3c_mmci_cardirq, s, 1)[0]);
601 s3c_mmci_reset(s);
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);
609 return s;