Break up vl.h.
[qemu] / hw / omap_mmc.c
1 /*
2  * OMAP on-chip MMC/SD host emulation.
3  *
4  * Copyright (C) 2006-2007 Andrzej Zaborowski  <balrog@zabor.org>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
19  * MA 02111-1307 USA
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,        /* no response */
95     sd_r1,              /* normal response command */
96     sd_r2,              /* CID, CSD registers */
97     sd_r3,              /* OCR register */
98     sd_r6 = 6,          /* Published RCA response */
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; /* FIXME */
127
128     rsplen = sd_do_command(host->card, &request, response);
129
130     /* TODO: validate CRCs */
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; /* Makes it more real */
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:  /* MMC_CMD */
276         return s->last_cmd;
277
278     case 0x04:  /* MMC_ARGL */
279         return s->arg & 0x0000ffff;
280
281     case 0x08:  /* MMC_ARGH */
282         return s->arg >> 16;
283
284     case 0x0c:  /* MMC_CON */
285         return (s->dw << 15) | (s->mode << 12) | (s->enable << 11);
286
287     case 0x10:  /* MMC_STAT */
288         return s->status;
289
290     case 0x14:  /* MMC_IE */
291         return s->mask;
292
293     case 0x18:  /* MMC_CTO */
294         return s->cto;
295
296     case 0x1c:  /* MMC_DTO */
297         return s->dto;
298
299     case 0x20:  /* MMC_DATA */
300         /* TODO: support 8-bit access */
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:  /* MMC_BLEN */
315         return s->blen_counter;
316
317     case 0x28:  /* MMC_NBLK */
318         return s->nblk_counter;
319
320     case 0x2c:  /* MMC_BUF */
321         return (s->rx_dma << 15) | (s->af_level << 8) |
322             (s->tx_dma << 7) | s->ae_level;
323
324     case 0x30:  /* MMC_SPI */
325         return 0x0000;
326     case 0x34:  /* MMC_SDIO */
327         return s->sdio;
328     case 0x38:  /* MMC_SYST */
329         return 0x0000;
330
331     case 0x3c:  /* MMC_REV */
332         return 0x0001;
333
334     case 0x40:  /* MMC_RSP0 */
335     case 0x44:  /* MMC_RSP1 */
336     case 0x48:  /* MMC_RSP2 */
337     case 0x4c:  /* MMC_RSP3 */
338     case 0x50:  /* MMC_RSP4 */
339     case 0x54:  /* MMC_RSP5 */
340     case 0x58:  /* MMC_RSP6 */
341     case 0x5c:  /* MMC_RSP7 */
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:  /* MMC_CMD */
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:  /* MMC_ARGL */
373         s->arg &= 0xffff0000;
374         s->arg |= 0x0000ffff & value;
375         break;
376
377     case 0x08:  /* MMC_ARGH */
378         s->arg &= 0x0000ffff;
379         s->arg |= value << 16;
380         break;
381
382     case 0x0c:  /* MMC_CON */
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:  /* MMC_STAT */
393         s->status &= ~value;
394         omap_mmc_interrupts_update(s);
395         break;
396
397     case 0x14:  /* MMC_IE */
398         s->mask = value;
399         omap_mmc_interrupts_update(s);
400         break;
401
402     case 0x18:  /* MMC_CTO */
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:  /* MMC_DTO */
409         s->dto = value & 0xffff;
410         break;
411
412     case 0x20:  /* MMC_DATA */
413         /* TODO: support 8-bit access */
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:  /* MMC_BLEN */
424         s->blen = (value & 0x07ff) + 1;
425         s->blen_counter = s->blen;
426         break;
427
428     case 0x28:  /* MMC_NBLK */
429         s->nblk = (value & 0x07ff) + 1;
430         s->nblk_counter = s->nblk;
431         s->blen_counter = s->blen;
432         break;
433
434     case 0x2c:  /* MMC_BUF */
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     /* SPI, SDIO and TEST modes unimplemented */
449     case 0x30:  /* MMC_SPI */
450         break;
451     case 0x34:  /* MMC_SDIO */
452         s->sdio = value & 0x2020;
453         break;
454     case 0x38:  /* MMC_SYST */
455         break;
456
457     case 0x3c:  /* MMC_REV */
458     case 0x40:  /* MMC_RSP0 */
459     case 0x44:  /* MMC_RSP1 */
460     case 0x48:  /* MMC_RSP2 */
461     case 0x4c:  /* MMC_RSP3 */
462     case 0x50:  /* MMC_RSP4 */
463     case 0x54:  /* MMC_RSP5 */
464     case 0x58:  /* MMC_RSP6 */
465     case 0x5c:  /* MMC_RSP7 */
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     /* Instantiate the storage */
528     s->card = sd_init(bd);
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 }