1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21: #include "hw.h"
22: #include "omap.h"
23: #include "sd.h"
24:
25: struct omap_mmc_s {
26: target_phys_addr_t base;
27: qemu_irq irq;
28: qemu_irq *dma;
29: omap_clk clk;
30: SDState *card;
31: uint16_t last_cmd;
32: uint16_t sdio;
33: uint16_t rsp[8];
34: uint32_t arg;
35: int dw;
36: int mode;
37: int enable;
38: uint16_t status;
39: uint16_t mask;
40: uint8_t cto;
41: uint16_t dto;
42: uint16_t fifo[32];
43: int fifo_start;
44: int fifo_len;
45: uint16_t blen;
46: uint16_t blen_counter;
47: uint16_t nblk;
48: uint16_t nblk_counter;
49: int tx_dma;
50: int rx_dma;
51: int af_level;
52: int ae_level;
53:
54: int ddir;
55: int transfer;
56: };
57:
58: static void omap_mmc_interrupts_update(struct omap_mmc_s *s)
59: {
60: qemu_set_irq(s->irq, !!(s->status & s->mask));
61: }
62:
63: static void omap_mmc_fifolevel_update(struct omap_mmc_s *host)
64: {
65: if (!host->transfer && !host->fifo_len) {
66: host->status &= 0xf3ff;
67: return;
68: }
69:
70: if (host->fifo_len > host->af_level && host->ddir) {
71: if (host->rx_dma) {
72: host->status &= 0xfbff;
73: qemu_irq_raise(host->dma[1]);
74: } else
75: host->status |= 0x0400;
76: } else {
77: host->status &= 0xfbff;
78: qemu_irq_lower(host->dma[1]);
79: }
80:
81: if (host->fifo_len < host->ae_level && !host->ddir) {
82: if (host->tx_dma) {
83: host->status &= 0xf7ff;
84: qemu_irq_raise(host->dma[0]);
85: } else
86: host->status |= 0x0800;
87: } else {
88: qemu_irq_lower(host->dma[0]);
89: host->status &= 0xf7ff;
90: }
91: }
92:
93: typedef enum {
94: sd_nore = 0,
95: sd_r1,
96: sd_r2,
97: sd_r3,
98: sd_r6 = 6,
99: sd_r1b = -1,
100: } sd_rsp_type_t;
101:
102: static void omap_mmc_command(struct omap_mmc_s *host, int cmd, int dir,
103: sd_cmd_type_t type, int busy, sd_rsp_type_t resptype, int init)
104: {
105: uint32_t rspstatus, mask;
106: int rsplen, timeout;
107: struct sd_request_s request;
108: uint8_t response[16];
109:
110: if (resptype == sd_r1 && busy)
111: resptype = sd_r1b;
112:
113: if (type == sd_adtc) {
114: host->fifo_start = 0;
115: host->fifo_len = 0;
116: host->transfer = 1;
117: host->ddir = dir;
118: } else
119: host->transfer = 0;
120: timeout = 0;
121: mask = 0;
122: rspstatus = 0;
123:
124: request.cmd = cmd;
125: request.arg = host->arg;
126: request.crc = 0;
127:
128: rsplen = sd_do_command(host->card, &request, response);
129:
130:
131: switch (resptype) {
132: case sd_nore:
133: rsplen = 0;
134: break;
135:
136: case sd_r1:
137: case sd_r1b:
138: if (rsplen < 4) {
139: timeout = 1;
140: break;
141: }
142: rsplen = 4;
143:
144: mask = OUT_OF_RANGE | ADDRESS_ERROR | BLOCK_LEN_ERROR |
145: ERASE_SEQ_ERROR | ERASE_PARAM | WP_VIOLATION |
146: LOCK_UNLOCK_FAILED | COM_CRC_ERROR | ILLEGAL_COMMAND |
147: CARD_ECC_FAILED | CC_ERROR | SD_ERROR |
148: CID_CSD_OVERWRITE;
149: if (host->sdio & (1 << 13))
150: mask |= AKE_SEQ_ERROR;
151: rspstatus = (response[0] << 24) | (response[1] << 16) |
152: (response[2] << 8) | (response[3] << 0);
153: break;
154:
155: case sd_r2:
156: if (rsplen < 16) {
157: timeout = 1;
158: break;
159: }
160: rsplen = 16;
161: break;
162:
163: case sd_r3:
164: if (rsplen < 4) {
165: timeout = 1;
166: break;
167: }
168: rsplen = 4;
169:
170: rspstatus = (response[0] << 24) | (response[1] << 16) |
171: (response[2] << 8) | (response[3] << 0);
172: if (rspstatus & 0x80000000)
173: host->status &= 0xe000;
174: else
175: host->status |= 0x1000;
176: break;
177:
178: case sd_r6:
179: if (rsplen < 4) {
180: timeout = 1;
181: break;
182: }
183: rsplen = 4;
184:
185: mask = 0xe000 | AKE_SEQ_ERROR;
186: rspstatus = (response[2] << 8) | (response[3] << 0);
187: }
188:
189: if (rspstatus & mask)
190: host->status |= 0x4000;
191: else
192: host->status &= 0xb000;
193:
194: if (rsplen)
195: for (rsplen = 0; rsplen < 8; rsplen ++)
196: host->rsp[~rsplen & 7] = response[(rsplen << 1) | 1] |
197: (response[(rsplen << 1) | 0] << 8);
198:
199: if (timeout)
200: host->status |= 0x0080;
201: else if (cmd == 12)
202: host->status |= 0x0005;
203: else
204: host->status |= 0x0001;
205: }
206:
207: static void omap_mmc_transfer(struct omap_mmc_s *host)
208: {
209: uint8_t value;
210:
211: if (!host->transfer)
212: return;
213:
214: while (1) {
215: if (host->ddir) {
216: if (host->fifo_len > host->af_level)
217: break;
218:
219: value = sd_read_data(host->card);
220: host->fifo[(host->fifo_start + host->fifo_len) & 31] = value;
221: if (-- host->blen_counter) {
222: value = sd_read_data(host->card);
223: host->fifo[(host->fifo_start + host->fifo_len) & 31] |=
224: value << 8;
225: host->blen_counter --;
226: }
227:
228: host->fifo_len ++;
229: } else {
230: if (!host->fifo_len)
231: break;
232:
233: value = host->fifo[host->fifo_start] & 0xff;
234: sd_write_data(host->card, value);
235: if (-- host->blen_counter) {
236: value = host->fifo[host->fifo_start] >> 8;
237: sd_write_data(host->card, value);
238: host->blen_counter --;
239: }
240:
241: host->fifo_start ++;
242: host->fifo_len --;
243: host->fifo_start &= 31;
244: }
245:
246: if (host->blen_counter == 0) {
247: host->nblk_counter --;
248: host->blen_counter = host->blen;
249:
250: if (host->nblk_counter == 0) {
251: host->nblk_counter = host->nblk;
252: host->transfer = 0;
253: host->status |= 0x0008;
254: break;
255: }
256: }
257: }
258: }
259:
260: static void omap_mmc_update(void *opaque)
261: {
262: struct omap_mmc_s *s = opaque;
263: omap_mmc_transfer(s);
264: omap_mmc_fifolevel_update(s);
265: omap_mmc_interrupts_update(s);
266: }
267:
268: static uint32_t omap_mmc_read(void *opaque, target_phys_addr_t offset)
269: {
270: uint16_t i;
271: struct omap_mmc_s *s = (struct omap_mmc_s *) opaque;
272: offset &= OMAP_MPUI_REG_MASK;
273:
274: switch (offset) {
275: case 0x00:
276: return s->last_cmd;
277:
278: case 0x04:
279: return s->arg & 0x0000ffff;
280:
281: case 0x08:
282: return s->arg >> 16;
283:
284: case 0x0c:
285: return (s->dw << 15) | (s->mode << 12) | (s->enable << 11);
286:
287: case 0x10:
288: return s->status;
289:
290: case 0x14:
291: return s->mask;
292:
293: case 0x18:
294: return s->cto;
295:
296: case 0x1c:
297: return s->dto;
298:
299: case 0x20:
300:
301: i = s->fifo[s->fifo_start];
302: if (s->fifo_len == 0) {
303: printf("MMC: FIFO underrun\n");
304: return i;
305: }
306: s->fifo_start ++;
307: s->fifo_len --;
308: s->fifo_start &= 31;
309: omap_mmc_transfer(s);
310: omap_mmc_fifolevel_update(s);
311: omap_mmc_interrupts_update(s);
312: return i;
313:
314: case 0x24:
315: return s->blen_counter;
316:
317: case 0x28:
318: return s->nblk_counter;
319:
320: case 0x2c:
321: return (s->rx_dma << 15) | (s->af_level << 8) |
322: (s->tx_dma << 7) | s->ae_level;
323:
324: case 0x30:
325: return 0x0000;
326: case 0x34:
327: return s->sdio;
328: case 0x38:
329: return 0x0000;
330:
331: case 0x3c:
332: return 0x0001;
333:
334: case 0x40:
335: case 0x44:
336: case 0x48:
337: case 0x4c:
338: case 0x50:
339: case 0x54:
340: case 0x58:
341: case 0x5c:
342: return s->rsp[(offset - 0x40) >> 2];
343: }
344:
345: OMAP_BAD_REG(offset);
346: return 0;
347: }
348:
349: static void omap_mmc_write(void *opaque, target_phys_addr_t offset,
350: uint32_t value)
351: {
352: int i;
353: struct omap_mmc_s *s = (struct omap_mmc_s *) opaque;
354: offset &= OMAP_MPUI_REG_MASK;
355:
356: switch (offset) {
357: case 0x00:
358: if (!s->enable)
359: break;
360:
361: s->last_cmd = value;
362: for (i = 0; i < 8; i ++)
363: s->rsp[i] = 0x0000;
364: omap_mmc_command(s, value & 63, (value >> 15) & 1,
365: (sd_cmd_type_t) ((value >> 12) & 3),
366: (value >> 11) & 1,
367: (sd_rsp_type_t) ((value >> 8) & 7),
368: (value >> 7) & 1);
369: omap_mmc_update(s);
370: break;
371:
372: case 0x04:
373: s->arg &= 0xffff0000;
374: s->arg |= 0x0000ffff & value;
375: break;
376:
377: case 0x08:
378: s->arg &= 0x0000ffff;
379: s->arg |= value << 16;
380: break;
381:
382: case 0x0c:
383: s->dw = (value >> 15) & 1;
384: s->mode = (value >> 12) & 3;
385: s->enable = (value >> 11) & 1;
386: if (s->mode != 0)
387: printf("SD mode %i unimplemented!\n", s->mode);
388: if (s->dw != 0)
389: printf("4-bit SD bus enabled\n");
390: break;
391:
392: case 0x10:
393: s->status &= ~value;
394: omap_mmc_interrupts_update(s);
395: break;
396:
397: case 0x14:
398: s->mask = value;
399: omap_mmc_interrupts_update(s);
400: break;
401:
402: case 0x18:
403: s->cto = value & 0xff;
404: if (s->cto > 0xfd)
405: printf("MMC: CTO of 0xff and 0xfe cannot be used!\n");
406: break;
407:
408: case 0x1c:
409: s->dto = value & 0xffff;
410: break;
411:
412: case 0x20:
413:
414: if (s->fifo_len == 32)
415: break;
416: s->fifo[(s->fifo_start + s->fifo_len) & 31] = value;
417: s->fifo_len ++;
418: omap_mmc_transfer(s);
419: omap_mmc_fifolevel_update(s);
420: omap_mmc_interrupts_update(s);
421: break;
422:
423: case 0x24:
424: s->blen = (value & 0x07ff) + 1;
425: s->blen_counter = s->blen;
426: break;
427:
428: case 0x28:
429: s->nblk = (value & 0x07ff) + 1;
430: s->nblk_counter = s->nblk;
431: s->blen_counter = s->blen;
432: break;
433:
434: case 0x2c:
435: s->rx_dma = (value >> 15) & 1;
436: s->af_level = (value >> 8) & 0x1f;
437: s->tx_dma = (value >> 7) & 1;
438: s->ae_level = value & 0x1f;
439:
440: if (s->rx_dma)
441: s->status &= 0xfbff;
442: if (s->tx_dma)
443: s->status &= 0xf7ff;
444: omap_mmc_fifolevel_update(s);
445: omap_mmc_interrupts_update(s);
446: break;
447:
448:
449: case 0x30:
450: break;
451: case 0x34:
452: s->sdio = value & 0x2020;
453: break;
454: case 0x38:
455: break;
456:
457: case 0x3c:
458: case 0x40:
459: case 0x44:
460: case 0x48:
461: case 0x4c:
462: case 0x50:
463: case 0x54:
464: case 0x58:
465: case 0x5c:
466: OMAP_RO_REG(offset);
467: break;
468:
469: default:
470: OMAP_BAD_REG(offset);
471: }
472: }
473:
474: static CPUReadMemoryFunc *omap_mmc_readfn[] = {
475: omap_badwidth_read16,
476: omap_mmc_read,
477: omap_badwidth_read16,
478: };
479:
480: static CPUWriteMemoryFunc *omap_mmc_writefn[] = {
481: omap_badwidth_write16,
482: omap_mmc_write,
483: omap_badwidth_write16,
484: };
485:
486: void omap_mmc_reset(struct omap_mmc_s *host)
487: {
488: host->last_cmd = 0;
489: memset(host->rsp, 0, sizeof(host->rsp));
490: host->arg = 0;
491: host->dw = 0;
492: host->mode = 0;
493: host->enable = 0;
494: host->status = 0;
495: host->mask = 0;
496: host->cto = 0;
497: host->dto = 0;
498: host->fifo_len = 0;
499: host->blen = 0;
500: host->blen_counter = 0;
501: host->nblk = 0;
502: host->nblk_counter = 0;
503: host->tx_dma = 0;
504: host->rx_dma = 0;
505: host->ae_level = 0x00;
506: host->af_level = 0x1f;
507: host->transfer = 0;
508: }
509:
510: struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base,
511: BlockDriverState *bd,
512: qemu_irq irq, qemu_irq dma[], omap_clk clk)
513: {
514: int iomemtype;
515: struct omap_mmc_s *s = (struct omap_mmc_s *)
516: qemu_mallocz(sizeof(struct omap_mmc_s));
517:
518: s->irq = irq;
519: s->base = base;
520: s->dma = dma;
521: s->clk = clk;
522:
523: iomemtype = cpu_register_io_memory(0, omap_mmc_readfn,
524: omap_mmc_writefn, s);
525: cpu_register_physical_memory(s->base, 0x800, iomemtype);
526:
527:
528: s->card = sd_init(bd, 0);
529:
530: return s;
531: }
532:
533: void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover)
534: {
535: sd_set_cb(s->card, ro, cover);
536: }