[NAND] Added readraw() to read underlying data storage
[qemu/mini2440.git] / hw / s3c24xx_mmci.c
blobd846afc092925f6c25cd8d8479da598a471188b0
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 if (addr > S3C_SDIMAX)
221 goto bad_reg;
222 addr = s->map[addr];
224 switch (addr) {
225 case S3C_SDICON:
226 return s->control;
227 case S3C_SDIPRE:
228 return s->prescaler;
229 case S3C_SDICARG:
230 return s->arg;
231 case S3C_SDICCON:
232 return s->ccontrol;
233 case S3C_SDICSTA:
234 return s->cstatus;
235 case S3C_SDIRSP0:
236 return s->resp[0];
237 case S3C_SDIRSP1:
238 return s->resp[1];
239 case S3C_SDIRSP2:
240 return s->resp[2];
241 case S3C_SDIRSP3:
242 return s->resp[3];
243 case S3C_SDIDTIMER:
244 return s->dtimer;
245 case S3C_SDIBSIZE:
246 return s->blklen;
247 case S3C_SDIDCON:
248 return s->dcontrol;
249 case S3C_SDICNT:
250 return s->blklen_cnt | (s->blknum_cnt << 12);
251 case S3C_SDIDSTA:
252 return s->dstatus;
253 case S3C_SDIFSTA:
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 */
267 else
268 return s->fifolen; /* FFCNT */
269 case S3C_SDIDAT:
270 ret = 0;
271 if (s->fifolen >= 4) {
272 ret |= s->fifo[s->fifostart ++] << 0;
273 s->fifostart &= 63;
274 ret |= s->fifo[s->fifostart ++] << 8;
275 s->fifostart &= 63;
276 ret |= s->fifo[s->fifostart ++] << 16;
277 s->fifostart &= 63;
278 ret |= s->fifo[s->fifostart ++] << 24;
279 s->fifostart &= 63;
280 s->fifolen -= 4;
281 s3c_mmci_fifo_run(s);
282 } else
283 printf("%s: FIFO underrun\n", __FUNCTION__);
285 return ret;
286 case S3C_SDIMSK:
287 return s->mask;
288 default:
289 bad_reg:
290 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long int)addr);
291 break;
293 return 0;
296 static void s3c_mmci_writew(void *opaque, target_phys_addr_t addr,
297 uint32_t value)
299 struct s3c_mmci_state_s *s = (struct s3c_mmci_state_s *) opaque;
300 if (addr > S3C_SDIMAX)
301 goto bad_reg;
302 addr = s->map[addr];
304 switch (addr) {
305 case S3C_SDICON:
306 s->control = value & 0x1d;
307 if (value & (1 << 1)) /* FRST */
308 s->fifolen = 0;
309 break;
310 case S3C_SDIPRE:
311 s->prescaler = value & 0xff;
312 break;
313 case S3C_SDICARG:
314 s->arg = value;
315 break;
316 case S3C_SDICCON:
317 s->ccontrol = value & 0x1fff;
318 if (value & (1 << 8)) /* CMST */
319 s3c_mmci_cmd_submit(s);
320 s3c_mmci_fifo_run(s);
321 break;
322 case S3C_SDICSTA:
323 s->cstatus &= ~(value & 0x1e00);
324 break;
325 case S3C_SDIDTIMER:
326 s->dtimer = value & 0xffff;
327 break;
328 case S3C_SDIBSIZE:
329 s->blklen = value & 0xfff;
330 break;
331 case S3C_SDIDCON:
332 s->dcontrol = value;
333 s->blknum = value & 0xfff;
334 if (value & (1 << 14)) /* STOP */
335 s->data = 0;
336 if (((s->dcontrol >> 12) & 3) == 1) { /* DatMode */
337 if (!(s->dcontrol & (1 << 18))) /* BACMD */
338 s->data = 1;
339 } else if (((s->dcontrol >> 12) & 3) == 2) { /* DatMode */
340 if (!(s->dcontrol & (1 << 19))) /* RACMD */
341 s->data = 1;
342 } else if (((s->dcontrol >> 12) & 3) == 3) /* DatMode */
343 if (!(s->dcontrol & (1 << 20))) /* RACMD */
344 s->data = 1;
345 s3c_mmci_fifo_run(s);
346 break;
347 case S3C_SDIDSTA:
348 s->dstatus &= ~(value & 0x3f8);
349 break;
350 case S3C_SDIFSTA:
351 /* write is tolerated on the s3c2440 */
352 break;
353 case S3C_SDIDAT:
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);
359 break;
360 case S3C_SDIMSK:
361 s->mask = value & 0x3ffff;
362 break;
363 default:
364 bad_reg:
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;
372 uint16_t ret = 0;
374 if (s->map[addr - s->base] == S3C_SDIDAT) {
375 if (s->fifolen >= 2) {
376 ret |= s->fifo[s->fifostart ++] << 0;
377 s->fifostart &= 63;
378 ret |= s->fifo[s->fifostart ++] << 8;
379 s->fifostart &= 63;
380 s->fifolen -= 2;
381 s3c_mmci_fifo_run(s);
382 } else
383 printf("%s: FIFO underrun\n", __FUNCTION__);
385 return ret;
388 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long int)(addr - s->base));
389 return 0;
392 static void s3c_mmci_writeh(void *opaque, target_phys_addr_t addr,
393 uint32_t value)
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);
401 } else
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;
408 uint8_t ret = 0;
410 if (s->map[addr - s->base] == S3C_SDIDAT) {
411 if (s->fifolen > 0) {
412 ret = s->fifo[s->fifostart ++];
413 s->fifostart &= 63;
414 s->fifolen --;
415 s3c_mmci_fifo_run(s);
416 } else
417 printf("%s: FIFO underrun\n", __FUNCTION__);
419 return ret;
422 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long int)(addr - s->base));
423 return 0;
426 static void s3c_mmci_writeb(void *opaque, target_phys_addr_t addr,
427 uint32_t value)
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);
434 } else
435 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long int)(addr - s->base));
438 static CPUReadMemoryFunc *s3c_mmci_readfn[] = {
439 s3c_mmci_readb,
440 s3c_mmci_readh,
441 s3c_mmci_readw,
444 static CPUWriteMemoryFunc *s3c_mmci_writefn[] = {
445 s3c_mmci_writeb,
446 s3c_mmci_writeh,
447 s3c_mmci_writew,
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 */
455 return;
456 if (!level)
457 return;
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,
493 [0x00] = S3C_SDICON,
494 [0x04] = S3C_SDIPRE,
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,
505 [0x30] = S3C_SDICNT,
506 [0x34] = S3C_SDIDSTA,
507 [0x38] = S3C_SDIFSTA,
508 [0x3c] = S3C_SDIDAT,
509 [0x40] = S3C_SDIMSK,
512 static const target_phys_addr_t s3c2440_regmap[S3C_SDIMAX + 1] = {
513 [0 ... S3C_SDIMAX] = -1,
514 [0x00] = S3C_SDICON,
515 [0x04] = S3C_SDIPRE,
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,
526 [0x30] = S3C_SDICNT,
527 [0x34] = S3C_SDIDSTA,
528 [0x38] = S3C_SDIFSTA,
529 [0x3c] = S3C_SDIMSK,
530 [0x40] = S3C_SDIDAT,
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);
559 return 0;
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)
565 int iomemtype;
566 struct s3c_mmci_state_s *s;
568 if (!mmc)
569 return 0;
571 s = (struct s3c_mmci_state_s *)
572 qemu_mallocz(sizeof(struct s3c_mmci_state_s));
573 s->base = base;
574 s->irq = irq;
575 s->dma = dma;
576 s->card = mmc;
577 s->model = model;
578 switch (model) {
579 case 0x2410:
580 s->map = s3c2410_regmap;
581 break;
582 case 0x2440:
583 s->map = s3c2440_regmap;
584 break;
585 default:
586 fprintf(stderr, "%s: unknown MMC/SD/SDIO HC model %04x\n",
587 __FUNCTION__, model);
588 exit(-1);
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];
594 s3c_mmci_reset(s);
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);
602 return s;