[S3C] Removed a spurious trace
[qemu/mini2440.git] / hw / s3c24xx_mmci.c
blob923446fdc995a9233fa8dfa1a55c146f1452003e
1 /*
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.
8 */
10 #include "s3c.h"
11 #include "sd.h"
12 #include "hw.h"
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;
40 qemu_irq irq;
41 qemu_irq *dma;
43 SDState *card;
45 int blklen;
46 int blknum;
47 int blklen_cnt;
48 int blknum_cnt;
49 uint8_t fifo[64];
50 int fifolen;
51 int fifostart;
52 int data;
54 uint32_t control;
55 uint32_t arg;
56 uint32_t ccontrol;
57 uint32_t cstatus;
58 uint32_t dcontrol;
59 uint32_t dstatus;
60 uint32_t resp[4];
61 uint16_t dtimer;
62 uint32_t mask;
63 uint8_t prescaler;
65 uint32_t cpu_id;
66 const target_phys_addr_t *map;
69 void s3c_mmci_reset(struct s3c_mmci_state_s *s)
71 if (!s)
72 return;
74 s->blklen = 0;
75 s->blknum = 0;
76 s->blklen_cnt = 0;
77 s->blknum_cnt = 0;
78 s->fifolen = 0;
79 s->fifostart = 0;
80 s->control = 0;
81 s->arg = 0;
82 s->ccontrol = 0;
83 s->cstatus = 0;
84 s->dcontrol = 0;
85 s->dstatus = 0;
86 s->resp[0] = 0;
87 s->resp[1] = 0;
88 s->resp[2] = 0;
89 s->resp[3] = 0;
90 s->dtimer = 0x2000;
91 s->mask = 0;
92 s->prescaler = 0;
95 static void s3c_mmci_fifo_run(struct s3c_mmci_state_s *s)
97 int len, dmalevel = 0;
98 if (!s->data)
99 goto dmaupdate;
101 len = s->fifolen;
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 ++]);
126 s->fifostart &= 63;
127 s->fifolen --;
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);
138 } else
139 return;
141 if (!s->blklen_cnt) {
142 s->data = 0;
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);
148 dmaupdate:
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)
158 int rsplen, i;
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 */
177 /* R2 */
178 if (rsplen < 16)
179 goto timeout;
180 } else {
181 /* R1, R3, R4, R5 or R6 */
182 if (rsplen < 4)
183 goto timeout;
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);
193 complete:
194 s->blklen_cnt = s->blklen;
195 s->blknum_cnt = s->blknum;
197 s->data = 0;
198 if (((s->dcontrol >> 12) & 3) == 1) { /* DatMode */
199 if (s->dcontrol & (1 << 18)) /* BACMD */
200 s->data = 1;
201 } else if (((s->dcontrol >> 12) & 3) == 2) { /* DatMode */
202 if (s->dcontrol & (1 << 19)) /* RACMD */
203 s->data = 1;
204 } else if (((s->dcontrol >> 12) & 3) == 3) /* DatMode */
205 if (s->dcontrol & (1 << 20)) /* RACMD */
206 s->data = 1;
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 */
212 return;
214 timeout:
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;
224 uint32_t ret;
225 if (addr > S3C_SDIMAX)
226 goto bad_reg;
227 addr = s->map[addr];
229 switch (addr) {
230 case S3C_SDICON:
231 return s->control;
232 case S3C_SDIPRE:
233 return s->prescaler;
234 case S3C_SDICARG:
235 return s->arg;
236 case S3C_SDICCON:
237 return s->ccontrol;
238 case S3C_SDICSTA:
239 return s->cstatus;
240 case S3C_SDIRSP0:
241 return s->resp[0];
242 case S3C_SDIRSP1:
243 return s->resp[1];
244 case S3C_SDIRSP2:
245 return s->resp[2];
246 case S3C_SDIRSP3:
247 return s->resp[3];
248 case S3C_SDIDTIMER:
249 return s->dtimer;
250 case S3C_SDIBSIZE:
251 return s->blklen;
252 case S3C_SDIDCON:
253 return s->dcontrol;
254 case S3C_SDICNT:
255 return s->blklen_cnt | (s->blknum_cnt << 12);
256 case S3C_SDIDSTA:
257 return s->dstatus;
258 case S3C_SDIFSTA:
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 */
272 else
273 return s->fifolen; /* FFCNT */
274 case S3C_SDIDAT:
275 ret = 0;
276 if (s->fifolen >= 4) {
277 ret |= s->fifo[s->fifostart ++] << 0;
278 s->fifostart &= 63;
279 ret |= s->fifo[s->fifostart ++] << 8;
280 s->fifostart &= 63;
281 ret |= s->fifo[s->fifostart ++] << 16;
282 s->fifostart &= 63;
283 ret |= s->fifo[s->fifostart ++] << 24;
284 s->fifostart &= 63;
285 s->fifolen -= 4;
286 s3c_mmci_fifo_run(s);
287 } else
288 printf("%s: FIFO underrun\n", __FUNCTION__);
290 return ret;
291 case S3C_SDIMSK:
292 return s->mask;
293 default:
294 bad_reg:
295 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long int)addr);
296 break;
298 return 0;
301 static void s3c_mmci_writew(void *opaque, target_phys_addr_t addr,
302 uint32_t value)
304 struct s3c_mmci_state_s *s = (struct s3c_mmci_state_s *) opaque;
305 if (addr > S3C_SDIMAX)
306 goto bad_reg;
307 addr = s->map[addr];
309 switch (addr) {
310 case S3C_SDICON:
311 s->control = value & 0x1d;
312 if (value & (1 << 1)) /* FRST */
313 s->fifolen = 0;
314 break;
315 case S3C_SDIPRE:
316 s->prescaler = value & 0xff;
317 break;
318 case S3C_SDICARG:
319 s->arg = value;
320 break;
321 case S3C_SDICCON:
322 s->ccontrol = value & 0x1fff;
323 if (value & (1 << 8)) /* CMST */
324 s3c_mmci_cmd_submit(s);
325 s3c_mmci_fifo_run(s);
326 break;
327 case S3C_SDICSTA:
328 s->cstatus &= ~(value & 0x1e00);
329 break;
330 case S3C_SDIDTIMER:
331 s->dtimer = value & 0xffff;
332 break;
333 case S3C_SDIBSIZE:
334 s->blklen = value & 0xfff;
335 break;
336 case S3C_SDIDCON:
337 s->dcontrol = value;
338 s->blknum = value & 0xfff;
339 if (value & (1 << 14)) /* STOP */
340 s->data = 0;
341 if (((s->dcontrol >> 12) & 3) == 1) { /* DatMode */
342 if (!(s->dcontrol & (1 << 18))) /* BACMD */
343 s->data = 1;
344 } else if (((s->dcontrol >> 12) & 3) == 2) { /* DatMode */
345 if (!(s->dcontrol & (1 << 19))) /* RACMD */
346 s->data = 1;
347 } else if (((s->dcontrol >> 12) & 3) == 3) /* DatMode */
348 if (!(s->dcontrol & (1 << 20))) /* RACMD */
349 s->data = 1;
350 s3c_mmci_fifo_run(s);
351 break;
352 case S3C_SDIDSTA:
353 s->dstatus &= ~(value & 0x3f8);
354 break;
355 case S3C_SDIFSTA:
356 /* write is tolerated on the s3c2440 */
357 break;
358 case S3C_SDIDAT:
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);
364 break;
365 case S3C_SDIMSK:
366 s->mask = value & 0x3ffff;
367 break;
368 default:
369 bad_reg:
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;
377 uint16_t ret = 0;
379 if (s->map[addr - s->base] == S3C_SDIDAT) {
380 if (s->fifolen >= 2) {
381 ret |= s->fifo[s->fifostart ++] << 0;
382 s->fifostart &= 63;
383 ret |= s->fifo[s->fifostart ++] << 8;
384 s->fifostart &= 63;
385 s->fifolen -= 2;
386 s3c_mmci_fifo_run(s);
387 } else
388 printf("%s: FIFO underrun\n", __FUNCTION__);
390 return ret;
393 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long int)(addr - s->base));
394 return 0;
397 static void s3c_mmci_writeh(void *opaque, target_phys_addr_t addr,
398 uint32_t value)
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);
406 } else
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;
413 uint8_t ret = 0;
415 if (s->map[addr - s->base] == S3C_SDIDAT) {
416 if (s->fifolen > 0) {
417 ret = s->fifo[s->fifostart ++];
418 s->fifostart &= 63;
419 s->fifolen --;
420 s3c_mmci_fifo_run(s);
421 } else
422 printf("%s: FIFO underrun\n", __FUNCTION__);
424 return ret;
427 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long int)(addr - s->base));
428 return 0;
431 static void s3c_mmci_writeb(void *opaque, target_phys_addr_t addr,
432 uint32_t value)
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);
439 } else
440 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long int)(addr - s->base));
443 static CPUReadMemoryFunc *s3c_mmci_readfn[] = {
444 s3c_mmci_readb,
445 s3c_mmci_readh,
446 s3c_mmci_readw,
449 static CPUWriteMemoryFunc *s3c_mmci_writefn[] = {
450 s3c_mmci_writeb,
451 s3c_mmci_writeh,
452 s3c_mmci_writew,
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 */
462 return;
463 if (!level)
464 return;
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,
500 [0x00] = S3C_SDICON,
501 [0x04] = S3C_SDIPRE,
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,
512 [0x30] = S3C_SDICNT,
513 [0x34] = S3C_SDIDSTA,
514 [0x38] = S3C_SDIFSTA,
515 [0x3c] = S3C_SDIDAT,
516 [0x40] = S3C_SDIMSK,
519 static const target_phys_addr_t s3c2440_regmap[S3C_SDIMAX + 1] = {
520 [0 ... S3C_SDIMAX] = -1,
521 [0x00] = S3C_SDICON,
522 [0x04] = S3C_SDIPRE,
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,
533 [0x30] = S3C_SDICNT,
534 [0x34] = S3C_SDIDSTA,
535 [0x38] = S3C_SDIFSTA,
536 [0x3c] = S3C_SDIMSK,
537 [0x40] = S3C_SDIDAT,
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);
566 return 0;
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)
572 int iomemtype;
573 struct s3c_mmci_state_s *s;
575 if (!mmc)
576 return 0;
578 s = (struct s3c_mmci_state_s *)
579 qemu_mallocz(sizeof(struct s3c_mmci_state_s));
580 s->base = base;
581 s->irq = irq;
582 s->dma = dma;
583 s->card = mmc;
584 s->cpu_id = cpu_id;
585 switch (cpu_id) {
586 case S3C_CPU_2410:
587 s->map = s3c2410_regmap;
588 break;
589 case S3C_CPU_2440:
590 s->map = s3c2440_regmap;
591 break;
592 default:
593 fprintf(stderr, "%s: unknown MMC/SD/SDIO HC model %08x\n",
594 __FUNCTION__, cpu_id);
595 exit(-1);
598 sd_set_cb(mmc, 0, qemu_allocate_irqs(s3c_mmci_cardirq, s, 1)[0]);
600 s3c_mmci_reset(s);
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);
608 return s;