[DM9000] Imported Simtec files
[qemu/mini2440.git] / hw / s3c24xx_mmci.c
blob348524767a196f6edafcc2d180c780e656016312
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 struct s3c_mmci_state_s {
15 target_phys_addr_t base;
16 qemu_irq irq;
17 qemu_irq *dma;
19 SDState *card;
21 int blklen;
22 int blknum;
23 int blklen_cnt;
24 int blknum_cnt;
25 uint8_t fifo[64];
26 int fifolen;
27 int fifostart;
28 int data;
30 uint32_t control;
31 uint32_t arg;
32 uint32_t ccontrol;
33 uint32_t cstatus;
34 uint32_t dcontrol;
35 uint32_t dstatus;
36 uint32_t resp[4];
37 uint16_t dtimer;
38 uint32_t mask;
39 uint8_t prescaler;
41 uint16_t model;
42 const target_phys_addr_t *map;
45 void s3c_mmci_reset(struct s3c_mmci_state_s *s)
47 if (!s)
48 return;
50 s->blklen = 0;
51 s->blknum = 0;
52 s->blklen_cnt = 0;
53 s->blknum_cnt = 0;
54 s->fifolen = 0;
55 s->fifostart = 0;
56 s->control = 0;
57 s->arg = 0;
58 s->ccontrol = 0;
59 s->cstatus = 0;
60 s->dcontrol = 0;
61 s->dstatus = 0;
62 s->resp[0] = 0;
63 s->resp[1] = 0;
64 s->resp[2] = 0;
65 s->resp[3] = 0;
66 s->dtimer = 0x2000;
67 s->mask = 0;
68 s->prescaler = 0;
71 static void s3c_mmci_fifo_run(struct s3c_mmci_state_s *s)
73 int len, dmalevel = 0;
74 if (!s->data)
75 goto dmaupdate;
77 len = s->fifolen;
78 if (((s->dcontrol >> 12) & 3) == 2) { /* DatMode */
79 s->dstatus &= ~3;
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))
85 if (-- s->blknum_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 */
98 s->dstatus &= ~3;
99 s->dstatus |= 1 << 0; /* TxDatOn */
100 while (s->fifolen && s->blklen_cnt) {
101 sd_write_data(s->card, s->fifo[s->fifostart ++]);
102 s->fifostart &= 63;
103 s->fifolen --;
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);
114 } else
115 return;
117 if (!s->blklen_cnt) {
118 s->data = 0;
119 s->dstatus &= ~3;
120 s->dstatus |= 1 << 4; /* DatFin */
121 if (s->mask & (1 << 7)) /* DatFin */
122 qemu_irq_raise(s->irq);
124 dmaupdate:
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)
134 int rsplen, i;
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 */
153 /* R2 */
154 if (rsplen < 16)
155 goto timeout;
156 } else {
157 /* R1, R3, R4, R5 or R6 */
158 if (rsplen < 4)
159 goto timeout;
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);
169 complete:
170 s->blklen_cnt = s->blklen;
171 s->blknum_cnt = s->blknum;
173 s->data = 0;
174 if (((s->dcontrol >> 12) & 3) == 1) { /* DatMode */
175 if (s->dcontrol & (1 << 18)) /* BACMD */
176 s->data = 1;
177 } else if (((s->dcontrol >> 12) & 3) == 2) { /* DatMode */
178 if (s->dcontrol & (1 << 19)) /* RACMD */
179 s->data = 1;
180 } else if (((s->dcontrol >> 12) & 3) == 3) /* DatMode */
181 if (s->dcontrol & (1 << 20)) /* RACMD */
182 s->data = 1;
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 */
188 return;
190 timeout:
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;
219 uint32_t ret;
220 addr -= s->base;
221 if (addr > S3C_SDIMAX)
222 goto bad_reg;
223 addr = s->map[addr];
225 switch (addr) {
226 case S3C_SDICON:
227 return s->control;
228 case S3C_SDIPRE:
229 return s->prescaler;
230 case S3C_SDICARG:
231 return s->arg;
232 case S3C_SDICCON:
233 return s->ccontrol;
234 case S3C_SDICSTA:
235 return s->cstatus;
236 case S3C_SDIRSP0:
237 return s->resp[0];
238 case S3C_SDIRSP1:
239 return s->resp[1];
240 case S3C_SDIRSP2:
241 return s->resp[2];
242 case S3C_SDIRSP3:
243 return s->resp[3];
244 case S3C_SDIDTIMER:
245 return s->dtimer;
246 case S3C_SDIBSIZE:
247 return s->blklen;
248 case S3C_SDIDCON:
249 return s->dcontrol;
250 case S3C_SDICNT:
251 return s->blklen_cnt | (s->blknum_cnt << 12);
252 case S3C_SDIDSTA:
253 return s->dstatus;
254 case S3C_SDIFSTA:
255 /* XXX on S3C2440 these bits have to cleared explicitely. */
256 if (((s->dcontrol >> 12) & 3) == 2) /* DatMode */
257 return s->fifolen | /* FFCNT */
258 ((s->fifolen > 31) ? (1 << 7) : 0) | /* RFHalf */
259 ((s->fifolen > 63) ? (1 << 8) : 0) | /* RFFull */
260 (s->blklen_cnt ? 0 : (1 << 9)) | /* RFLast */
261 (3 << 10) | /* TFHalf */
262 (s->fifolen ? (1 << 12) : 0); /* RFDET */
263 else if (((s->dcontrol >> 12) & 3) == 3) /* DatMode */
264 return s->fifolen | /* FFCNT */
265 (s->fifolen ? 0 : (1 << 10)) | /* TFEmpty */
266 ((s->fifolen < 33) ? (1 << 11) : 0) | /* TFHalf */
267 ((s->fifolen < 64) ? (1 << 13) : 0); /* TFDET */
268 else
269 return s->fifolen; /* FFCNT */
270 case S3C_SDIDAT:
271 ret = 0;
272 if (s->fifolen >= 4) {
273 ret |= s->fifo[s->fifostart ++] << 0;
274 s->fifostart &= 63;
275 ret |= s->fifo[s->fifostart ++] << 8;
276 s->fifostart &= 63;
277 ret |= s->fifo[s->fifostart ++] << 16;
278 s->fifostart &= 63;
279 ret |= s->fifo[s->fifostart ++] << 24;
280 s->fifostart &= 63;
281 s->fifolen -= 4;
282 s3c_mmci_fifo_run(s);
283 } else
284 printf("%s: FIFO underrun\n", __FUNCTION__);
286 return ret;
287 case S3C_SDIMSK:
288 return s->mask;
289 default:
290 bad_reg:
291 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long int)addr);
292 break;
294 return 0;
297 static void s3c_mmci_writew(void *opaque, target_phys_addr_t addr,
298 uint32_t value)
300 struct s3c_mmci_state_s *s = (struct s3c_mmci_state_s *) opaque;
301 addr -= s->base;
302 if (addr > S3C_SDIMAX)
303 goto bad_reg;
304 addr = s->map[addr];
306 switch (addr) {
307 case S3C_SDICON:
308 s->control = value & 0x1d;
309 if (value & (1 << 1)) /* FRST */
310 s->fifolen = 0;
311 break;
312 case S3C_SDIPRE:
313 s->prescaler = value & 0xff;
314 break;
315 case S3C_SDICARG:
316 s->arg = value;
317 break;
318 case S3C_SDICCON:
319 s->ccontrol = value & 0x1fff;
320 if (value & (1 << 8)) /* CMST */
321 s3c_mmci_cmd_submit(s);
322 s3c_mmci_fifo_run(s);
323 break;
324 case S3C_SDICSTA:
325 s->cstatus &= ~(value & 0x1e00);
326 break;
327 case S3C_SDIDTIMER:
328 s->dtimer = value & 0xffff;
329 break;
330 case S3C_SDIBSIZE:
331 s->blklen = value & 0xfff;
332 break;
333 case S3C_SDIDCON:
334 s->dcontrol = value;
335 s->blknum = value & 0xfff;
336 if (value & (1 << 14)) /* STOP */
337 s->data = 0;
338 if (((s->dcontrol >> 12) & 3) == 1) { /* DatMode */
339 if (!(s->dcontrol & (1 << 18))) /* BACMD */
340 s->data = 1;
341 } else if (((s->dcontrol >> 12) & 3) == 2) { /* DatMode */
342 if (!(s->dcontrol & (1 << 19))) /* RACMD */
343 s->data = 1;
344 } else if (((s->dcontrol >> 12) & 3) == 3) /* DatMode */
345 if (!(s->dcontrol & (1 << 20))) /* RACMD */
346 s->data = 1;
347 s3c_mmci_fifo_run(s);
348 break;
349 case S3C_SDIDSTA:
350 s->dstatus &= ~(value & 0x3f8);
351 break;
352 case S3C_SDIDAT:
353 s->fifo[(s->fifostart + s->fifolen ++) & 63] = (value >> 0) & 0xff;
354 s->fifo[(s->fifostart + s->fifolen ++) & 63] = (value >> 8) & 0xff;
355 s->fifo[(s->fifostart + s->fifolen ++) & 63] = (value >> 16) & 0xff;
356 s->fifo[(s->fifostart + s->fifolen ++) & 63] = (value >> 24) & 0xff;
357 s3c_mmci_fifo_run(s);
358 break;
359 case S3C_SDIMSK:
360 s->mask = value & 0x3ffff;
361 break;
362 default:
363 bad_reg:
364 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long int)addr);
368 static uint32_t s3c_mmci_readh(void *opaque, target_phys_addr_t addr)
370 struct s3c_mmci_state_s *s = (struct s3c_mmci_state_s *) opaque;
371 uint16_t ret = 0;
373 if (s->map[addr - s->base] == S3C_SDIDAT) {
374 if (s->fifolen >= 2) {
375 ret |= s->fifo[s->fifostart ++] << 0;
376 s->fifostart &= 63;
377 ret |= s->fifo[s->fifostart ++] << 8;
378 s->fifostart &= 63;
379 s->fifolen -= 2;
380 s3c_mmci_fifo_run(s);
381 } else
382 printf("%s: FIFO underrun\n", __FUNCTION__);
384 return ret;
387 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long int)(addr - s->base));
388 return 0;
391 static void s3c_mmci_writeh(void *opaque, target_phys_addr_t addr,
392 uint32_t value)
394 struct s3c_mmci_state_s *s = (struct s3c_mmci_state_s *) opaque;
396 if (s->map[addr - s->base] == S3C_SDIDAT) {
397 s->fifo[(s->fifostart + s->fifolen ++) & 63] = (value >> 0) & 0xff;
398 s->fifo[(s->fifostart + s->fifolen ++) & 63] = (value >> 8) & 0xff;
399 s3c_mmci_fifo_run(s);
400 } else
401 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long int)(addr - s->base));
404 static uint32_t s3c_mmci_readb(void *opaque, target_phys_addr_t addr)
406 struct s3c_mmci_state_s *s = (struct s3c_mmci_state_s *) opaque;
407 uint8_t ret = 0;
409 if (s->map[addr - s->base] == S3C_SDIDAT) {
410 if (s->fifolen > 0) {
411 ret = s->fifo[s->fifostart ++];
412 s->fifostart &= 63;
413 s->fifolen --;
414 s3c_mmci_fifo_run(s);
415 } else
416 printf("%s: FIFO underrun\n", __FUNCTION__);
418 return ret;
421 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long int)(addr - s->base));
422 return 0;
425 static void s3c_mmci_writeb(void *opaque, target_phys_addr_t addr,
426 uint32_t value)
428 struct s3c_mmci_state_s *s = (struct s3c_mmci_state_s *) opaque;
430 if (s->map[addr - s->base] == S3C_SDIDAT) {
431 s->fifo[(s->fifostart + s->fifolen ++) & 63] = value;
432 s3c_mmci_fifo_run(s);
433 } else
434 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long int)(addr - s->base));
437 static CPUReadMemoryFunc *s3c_mmci_readfn[] = {
438 s3c_mmci_readb,
439 s3c_mmci_readh,
440 s3c_mmci_readw,
443 static CPUWriteMemoryFunc *s3c_mmci_writefn[] = {
444 s3c_mmci_writeb,
445 s3c_mmci_writeh,
446 s3c_mmci_writew,
449 static void s3c_mmci_cardirq(void *opaque, int line, int level)
451 struct s3c_mmci_state_s *s = (struct s3c_mmci_state_s *) opaque;
453 if (~s->control & (1 << 3)) /* RcvIOInt */
454 return;
455 if (!level)
456 return;
458 s->dstatus |= 1 << 9; /* IOIntDet */
459 if (s->mask & (1 << 12)) /* IOIntDet */
460 qemu_irq_raise(s->irq);
463 static void s3c_mmci_save(QEMUFile *f, void *opaque)
465 struct s3c_mmci_state_s *s = (struct s3c_mmci_state_s *) opaque;
466 qemu_put_be32(f, s->blklen);
467 qemu_put_be32(f, s->blknum);
468 qemu_put_be32(f, s->blklen_cnt);
469 qemu_put_be32(f, s->blknum_cnt);
470 qemu_put_buffer(f, s->fifo, sizeof(s->fifo));
471 qemu_put_be32(f, s->fifolen);
472 qemu_put_be32(f, s->fifostart);
473 qemu_put_be32(f, s->data);
475 qemu_put_be32s(f, &s->control);
476 qemu_put_be32s(f, &s->arg);
477 qemu_put_be32s(f, &s->ccontrol);
478 qemu_put_be32s(f, &s->cstatus);
479 qemu_put_be32s(f, &s->dcontrol);
480 qemu_put_be32s(f, &s->dstatus);
481 qemu_put_be32s(f, &s->resp[0]);
482 qemu_put_be32s(f, &s->resp[1]);
483 qemu_put_be32s(f, &s->resp[2]);
484 qemu_put_be32s(f, &s->resp[3]);
485 qemu_put_be16s(f, &s->dtimer);
486 qemu_put_be32s(f, &s->mask);
487 qemu_put_8s(f, &s->prescaler);
490 static const target_phys_addr_t s3c2410_regmap[S3C_SDIMAX + 1] = {
491 [0 ... S3C_SDIMAX] = -1,
492 [0x00] = S3C_SDICON,
493 [0x04] = S3C_SDIPRE,
494 [0x08] = S3C_SDICARG,
495 [0x0c] = S3C_SDICCON,
496 [0x10] = S3C_SDICSTA,
497 [0x14] = S3C_SDIRSP0,
498 [0x18] = S3C_SDIRSP1,
499 [0x1c] = S3C_SDIRSP2,
500 [0x20] = S3C_SDIRSP3,
501 [0x24] = S3C_SDIDTIMER,
502 [0x28] = S3C_SDIBSIZE,
503 [0x2c] = S3C_SDIDCON,
504 [0x30] = S3C_SDICNT,
505 [0x34] = S3C_SDIDSTA,
506 [0x38] = S3C_SDIFSTA,
507 [0x3c] = S3C_SDIDAT,
508 [0x40] = S3C_SDIMSK,
511 static const target_phys_addr_t s3c2440_regmap[S3C_SDIMAX + 1] = {
512 [0 ... S3C_SDIMAX] = -1,
513 [0x00] = S3C_SDICON,
514 [0x04] = S3C_SDIPRE,
515 [0x08] = S3C_SDICARG,
516 [0x0c] = S3C_SDICCON,
517 [0x10] = S3C_SDICSTA,
518 [0x14] = S3C_SDIRSP0,
519 [0x18] = S3C_SDIRSP1,
520 [0x1c] = S3C_SDIRSP2,
521 [0x20] = S3C_SDIRSP3,
522 [0x24] = S3C_SDIDTIMER,
523 [0x28] = S3C_SDIBSIZE,
524 [0x2c] = S3C_SDIDCON,
525 [0x30] = S3C_SDICNT,
526 [0x34] = S3C_SDIDSTA,
527 [0x38] = S3C_SDIFSTA,
528 [0x3c] = S3C_SDIMSK,
529 [0x40] = S3C_SDIDAT,
532 static int s3c_mmci_load(QEMUFile *f, void *opaque, int version_id)
534 struct s3c_mmci_state_s *s = (struct s3c_mmci_state_s *) opaque;
535 s->blklen = qemu_get_be32(f);
536 s->blknum = qemu_get_be32(f);
537 s->blklen_cnt = qemu_get_be32(f);
538 s->blknum_cnt = qemu_get_be32(f);
539 qemu_get_buffer(f, s->fifo, sizeof(s->fifo));
540 s->fifolen = qemu_get_be32(f);
541 s->fifostart = qemu_get_be32(f);
542 s->data = qemu_get_be32(f);
544 qemu_get_be32s(f, &s->control);
545 qemu_get_be32s(f, &s->arg);
546 qemu_get_be32s(f, &s->ccontrol);
547 qemu_get_be32s(f, &s->cstatus);
548 qemu_get_be32s(f, &s->dcontrol);
549 qemu_get_be32s(f, &s->dstatus);
550 qemu_get_be32s(f, &s->resp[0]);
551 qemu_get_be32s(f, &s->resp[1]);
552 qemu_get_be32s(f, &s->resp[2]);
553 qemu_get_be32s(f, &s->resp[3]);
554 qemu_get_be16s(f, &s->dtimer);
555 qemu_get_be32s(f, &s->mask);
556 qemu_get_8s(f, &s->prescaler);
558 return 0;
561 struct s3c_mmci_state_s *s3c_mmci_init(target_phys_addr_t base, uint16_t model,
562 SDState *mmc, qemu_irq irq, qemu_irq *dma)
564 int iomemtype;
565 struct s3c_mmci_state_s *s;
567 if (!mmc)
568 return 0;
570 s = (struct s3c_mmci_state_s *)
571 qemu_mallocz(sizeof(struct s3c_mmci_state_s));
572 s->base = base;
573 s->irq = irq;
574 s->dma = dma;
575 s->card = mmc;
576 s->model = model;
577 switch (model) {
578 case 0x2410:
579 s->map = s3c2410_regmap;
580 break;
581 case 0x2440:
582 s->map = s3c2440_regmap;
583 break;
584 default:
585 fprintf(stderr, "%s: unknown MMC/SD/SDIO HC model %04x\n",
586 __FUNCTION__, model);
587 exit(-1);
590 sd_set_cb(mmc, 0, qemu_allocate_irqs(s3c_mmci_cardirq, s, 1)[0]);
591 //mmc->irq = qemu_allocate_irqs(s3c_mmci_cardirq, s, 1)[0];
593 s3c_mmci_reset(s);
595 iomemtype = cpu_register_io_memory(0, s3c_mmci_readfn,
596 s3c_mmci_writefn, s);
597 cpu_register_physical_memory(s->base, 0xffffff, iomemtype);
599 register_savevm("s3c24xx_mmci", 0, 0, s3c_mmci_save, s3c_mmci_load, s);
601 return s;