Use correct type for card field.
[qemu] / hw / pl181.c
1 /* 
2  * Arm PrimeCell PL181 MultiMedia Card Interface
3  *
4  * Copyright (c) 2007 CodeSourcery.
5  * Written by Paul Brook
6  *
7  * This code is licenced under the GPL.
8  */
9
10 #include "vl.h"
11 #include "sd.h"
12
13 //#define DEBUG_PL181 1
14
15 #ifdef DEBUG_PL181
16 #define DPRINTF(fmt, args...) \
17 do { printf("pl181: " fmt , ##args); } while (0)
18 #else
19 #define DPRINTF(fmt, args...) do {} while(0)
20 #endif
21
22 #define PL181_FIFO_LEN 16
23
24 typedef struct {
25     SDState *card;
26     uint32_t base;
27     uint32_t clock;
28     uint32_t power;
29     uint32_t cmdarg;
30     uint32_t cmd;
31     uint32_t datatimer;
32     uint32_t datalength;
33     uint32_t respcmd;
34     uint32_t response[4];
35     uint32_t datactrl;
36     uint32_t datacnt;
37     uint32_t status;
38     uint32_t mask[2];
39     uint32_t fifocnt;
40     int fifo_pos;
41     int fifo_len;
42     uint32_t fifo[PL181_FIFO_LEN];
43     void *pic;
44     int irq[2];
45 } pl181_state;
46
47 #define PL181_CMD_INDEX     0x3f
48 #define PL181_CMD_RESPONSE  (1 << 6)
49 #define PL181_CMD_LONGRESP  (1 << 7)
50 #define PL181_CMD_INTERRUPT (1 << 8)
51 #define PL181_CMD_PENDING   (1 << 9)
52 #define PL181_CMD_ENABLE    (1 << 10)
53
54 #define PL181_DATA_ENABLE             (1 << 0)
55 #define PL181_DATA_DIRECTION          (1 << 1)
56 #define PL181_DATA_MODE               (1 << 2)
57 #define PL181_DATA_DMAENABLE          (1 << 3)
58
59 #define PL181_STATUS_CMDCRCFAIL       (1 << 0)
60 #define PL181_STATUS_DATACRCFAIL      (1 << 1)
61 #define PL181_STATUS_CMDTIMEOUT       (1 << 2)
62 #define PL181_STATUS_DATATIMEOUT      (1 << 3)
63 #define PL181_STATUS_TXUNDERRUN       (1 << 4)
64 #define PL181_STATUS_RXOVERRUN        (1 << 5)
65 #define PL181_STATUS_CMDRESPEND       (1 << 6)
66 #define PL181_STATUS_CMDSENT          (1 << 7)
67 #define PL181_STATUS_DATAEND          (1 << 8)
68 #define PL181_STATUS_DATABLOCKEND     (1 << 10)
69 #define PL181_STATUS_CMDACTIVE        (1 << 11)
70 #define PL181_STATUS_TXACTIVE         (1 << 12)
71 #define PL181_STATUS_RXACTIVE         (1 << 13)
72 #define PL181_STATUS_TXFIFOHALFEMPTY  (1 << 14)
73 #define PL181_STATUS_RXFIFOHALFFULL   (1 << 15)
74 #define PL181_STATUS_TXFIFOFULL       (1 << 16)
75 #define PL181_STATUS_RXFIFOFULL       (1 << 17)
76 #define PL181_STATUS_TXFIFOEMPTY      (1 << 18)
77 #define PL181_STATUS_RXFIFOEMPTY      (1 << 19)
78 #define PL181_STATUS_TXDATAAVLBL      (1 << 20)
79 #define PL181_STATUS_RXDATAAVLBL      (1 << 21)
80
81 #define PL181_STATUS_TX_FIFO (PL181_STATUS_TXACTIVE \
82                              |PL181_STATUS_TXFIFOHALFEMPTY \
83                              |PL181_STATUS_TXFIFOFULL \
84                              |PL181_STATUS_TXFIFOEMPTY \
85                              |PL181_STATUS_TXDATAAVLBL)
86 #define PL181_STATUS_RX_FIFO (PL181_STATUS_RXACTIVE \
87                              |PL181_STATUS_RXFIFOHALFFULL \
88                              |PL181_STATUS_RXFIFOFULL \
89                              |PL181_STATUS_RXFIFOEMPTY \
90                              |PL181_STATUS_RXDATAAVLBL)
91
92 static const unsigned char pl181_id[] =
93 { 0x81, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
94
95 static void pl181_update(pl181_state *s)
96 {
97     int i;
98     for (i = 0; i < 2; i++) {
99         pic_set_irq_new(s->pic, s->irq[i], (s->status & s->mask[i]) != 0);
100     }
101 }
102
103 static void pl181_fifo_push(pl181_state *s, uint32_t value)
104 {
105     int n;
106
107     if (s->fifo_len == PL181_FIFO_LEN) {
108         fprintf(stderr, "pl181: FIFO overflow\n");
109         return;
110     }
111     n = (s->fifo_pos + s->fifo_len) & (PL181_FIFO_LEN - 1);
112     s->fifo_len++;
113     s->fifo[n] = value;
114     DPRINTF("FIFO push %08x\n", (int)value);
115 }
116
117 static uint32_t pl181_fifo_pop(pl181_state *s)
118 {
119     uint32_t value;
120
121     if (s->fifo_len == 0) {
122         fprintf(stderr, "pl181: FIFO underflow\n");
123         return 0;
124     }
125     value = s->fifo[s->fifo_pos];
126     s->fifo_len--;
127     s->fifo_pos = (s->fifo_pos + 1) & (PL181_FIFO_LEN - 1);
128     DPRINTF("FIFO pop %08x\n", (int)value);
129     return value;
130 }
131
132 static void pl181_send_command(pl181_state *s)
133 {
134     struct sd_request_s request;
135     uint8_t response[16];
136     int rlen;
137
138     request.cmd = s->cmd & PL181_CMD_INDEX;
139     request.arg = s->cmdarg;
140     DPRINTF("Command %d %08x\n", request.cmd, request.arg);
141     rlen = sd_do_command(s->card, &request, response);
142     if (rlen < 0)
143         goto error;
144     if (s->cmd & PL181_CMD_RESPONSE) {
145 #define RWORD(n) ((response[n] << 24) | (response[n + 1] << 16) \
146                   | (response[n + 2] << 8) | response[n + 3])
147         if (rlen == 0 || (rlen == 4 && (s->cmd & PL181_CMD_LONGRESP)))
148             goto error;
149         if (rlen != 4 && rlen != 16)
150             goto error;
151         s->response[0] = RWORD(0);
152         if (rlen == 4) {
153             s->response[1] = s->response[2] = s->response[3] = 0;
154         } else {
155             s->response[1] = RWORD(4);
156             s->response[2] = RWORD(8);
157             s->response[3] = RWORD(12) & ~1;
158         }
159         DPRINTF("Response recieved\n");
160         s->status |= PL181_STATUS_CMDRESPEND;
161 #undef RWORD
162     } else {
163         DPRINTF("Command sent\n");
164         s->status |= PL181_STATUS_CMDSENT;
165     }
166     return;
167
168 error:
169     DPRINTF("Timeout\n");
170     s->status |= PL181_STATUS_CMDTIMEOUT;
171 }
172
173 /* Transfer data between teh card and the FIFO.  This is complicated by
174    the FIFO holding 32-bit words and the card taking data in single byte
175    chunks.  FIFO bytes are transferred in little-endian order.  */
176    
177 static void pl181_fifo_run(pl181_state *s)
178 {
179     uint32_t bits;
180     uint32_t value;
181     int n;
182     int limit;
183     int is_read;
184
185     is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0;
186     if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card))) {
187         limit = is_read ? PL181_FIFO_LEN : 0;
188         n = 0;
189         value = 0;
190         while (s->datacnt && s->fifo_len != limit) {
191             if (is_read) {
192                 value |= (uint32_t)sd_read_data(s->card) << (n * 8);
193                 n++;
194                 if (n == 4) {
195                     pl181_fifo_push(s, value);
196                     value = 0;
197                     n = 0;
198                 }
199             } else {
200                 if (n == 0) {
201                     value = pl181_fifo_pop(s);
202                     n = 4;
203                 }
204                 sd_write_data(s->card, value & 0xff);
205                 value >>= 8;
206                 n--;
207             }
208             s->datacnt--;
209         }
210         if (n && is_read) {
211             pl181_fifo_push(s, value);
212         }
213     }
214     s->status &= ~(PL181_STATUS_RX_FIFO | PL181_STATUS_TX_FIFO);
215     if (s->datacnt == 0) {
216         s->status |= PL181_STATUS_DATAEND;
217         /* HACK: */
218         s->status |= PL181_STATUS_DATABLOCKEND;
219         DPRINTF("Transfer Complete\n");
220     }
221     if (s->datacnt == 0 && s->fifocnt == 0) {
222         s->datactrl &= ~PL181_DATA_ENABLE;
223         DPRINTF("Data engine idle\n");
224     } else {
225         /* Update FIFO bits.  */
226         bits = PL181_STATUS_TXACTIVE | PL181_STATUS_RXACTIVE;
227         if (s->fifo_len == 0) {
228             bits |= PL181_STATUS_TXFIFOEMPTY;
229             bits |= PL181_STATUS_RXFIFOEMPTY;
230         } else {
231             bits |= PL181_STATUS_TXDATAAVLBL;
232             bits |= PL181_STATUS_RXDATAAVLBL;
233         }
234         if (s->fifo_len == 16) {
235             bits |= PL181_STATUS_TXFIFOFULL;
236             bits |= PL181_STATUS_RXFIFOFULL;
237         }
238         if (s->fifo_len <= 8) {
239             bits |= PL181_STATUS_TXFIFOHALFEMPTY;
240         }
241         if (s->fifo_len >= 8) {
242             bits |= PL181_STATUS_RXFIFOHALFFULL;
243         }
244         if (s->datactrl & PL181_DATA_DIRECTION) {
245             bits &= PL181_STATUS_RX_FIFO;
246         } else {
247             bits &= PL181_STATUS_TX_FIFO;
248         }
249         s->status |= bits;
250     }
251 }
252
253 static uint32_t pl181_read(void *opaque, target_phys_addr_t offset)
254 {
255     pl181_state *s = (pl181_state *)opaque;
256
257     offset -= s->base;
258     if (offset >= 0xfe0 && offset < 0x1000) {
259         return pl181_id[(offset - 0xfe0) >> 2];
260     }
261     switch (offset) {
262     case 0x00: /* Power */
263         return s->power;
264     case 0x04: /* Clock */
265         return s->clock;
266     case 0x08: /* Argument */
267         return s->cmdarg;
268     case 0x0c: /* Command */
269         return s->cmd;
270     case 0x10: /* RespCmd */
271         return s->respcmd;
272     case 0x14: /* Response0 */
273         return s->response[0];
274     case 0x18: /* Response1 */
275         return s->response[1];
276     case 0x1c: /* Response2 */
277         return s->response[2];
278     case 0x20: /* Response3 */
279         return s->response[3];
280     case 0x24: /* DataTimer */
281         return s->datatimer;
282     case 0x28: /* DataLength */
283         return s->datalength;
284     case 0x2c: /* DataCtrl */
285         return s->datactrl;
286     case 0x30: /* DataCnt */
287         return s->datacnt;
288     case 0x34: /* Status */
289         return s->status;
290     case 0x3c: /* Mask0 */
291         return s->mask[0];
292     case 0x40: /* Mask1 */
293         return s->mask[1];
294     case 0x48: /* FifoCnt */
295         return s->fifocnt;
296     case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
297     case 0x90: case 0x94: case 0x98: case 0x9c:
298     case 0xa0: case 0xa4: case 0xa8: case 0xac:
299     case 0xb0: case 0xb4: case 0xb8: case 0xbc:
300         if (s->fifocnt == 0) {
301             fprintf(stderr, "pl181: Unexpected FIFO read\n");
302             return 0;
303         } else {
304             uint32_t value;
305             s->fifocnt--;
306             value = pl181_fifo_pop(s);
307             pl181_fifo_run(s);
308             pl181_update(s);
309             return value;
310         }
311     default:
312         cpu_abort (cpu_single_env, "pl181_read: Bad offset %x\n", offset);
313         return 0;
314     }
315 }
316
317 static void pl181_write(void *opaque, target_phys_addr_t offset,
318                           uint32_t value)
319 {
320     pl181_state *s = (pl181_state *)opaque;
321
322     offset -= s->base;
323     switch (offset) {
324     case 0x00: /* Power */
325         s->power = value & 0xff;
326         break;
327     case 0x04: /* Clock */
328         s->clock = value & 0xff;
329         break;
330     case 0x08: /* Argument */
331         s->cmdarg = value;
332         break;
333     case 0x0c: /* Command */
334         s->cmd = value;
335         if (s->cmd & PL181_CMD_ENABLE) {
336             if (s->cmd & PL181_CMD_INTERRUPT) {
337                 fprintf(stderr, "pl181: Interrupt mode not implemented\n");
338                 abort();
339             } if (s->cmd & PL181_CMD_PENDING) {
340                 fprintf(stderr, "pl181: Pending commands not implemented\n");
341                 abort();
342             } else {
343                 pl181_send_command(s);
344                 pl181_fifo_run(s);
345             }
346             /* The command has completed one way or the other.  */
347             s->cmd &= ~PL181_CMD_ENABLE;
348         }
349         break;
350     case 0x24: /* DataTimer */
351         s->datatimer = value;
352         break;
353     case 0x28: /* DataLength */
354         s->datalength = value & 0xffff;
355         break;
356     case 0x2c: /* DataCtrl */
357         s->datactrl = value & 0xff;
358         if (value & PL181_DATA_ENABLE) {
359             s->datacnt = s->datalength;
360             s->fifocnt = (s->datalength + 3) >> 2;
361             pl181_fifo_run(s);
362         }
363         break;
364     case 0x38: /* Clear */
365         s->status &= ~(value & 0x7ff);
366         break;
367     case 0x3c: /* Mask0 */
368         s->mask[0] = value;
369         break;
370     case 0x40: /* Mask1 */
371         s->mask[1] = value;
372         break;
373     case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
374     case 0x90: case 0x94: case 0x98: case 0x9c:
375     case 0xa0: case 0xa4: case 0xa8: case 0xac:
376     case 0xb0: case 0xb4: case 0xb8: case 0xbc:
377         if (s->fifocnt == 0) {
378             fprintf(stderr, "pl181: Unexpected FIFO write\n");
379         } else {
380             s->fifocnt--;
381             pl181_fifo_push(s, value);
382             pl181_fifo_run(s);
383         }
384         break;
385     default:
386         cpu_abort (cpu_single_env, "pl181_write: Bad offset %x\n", offset);
387     }
388     pl181_update(s);
389 }
390
391 static CPUReadMemoryFunc *pl181_readfn[] = {
392    pl181_read,
393    pl181_read,
394    pl181_read
395 };
396
397 static CPUWriteMemoryFunc *pl181_writefn[] = {
398    pl181_write,
399    pl181_write,
400    pl181_write
401 };
402
403 static void pl181_reset(void *opaque)
404 {
405     pl181_state *s = (pl181_state *)opaque;
406
407     s->power = 0;
408     s->cmdarg = 0;
409     s->cmd = 0;
410     s->datatimer = 0;
411     s->datalength = 0;
412     s->respcmd = 0;
413     s->response[0] = 0;
414     s->response[1] = 0;
415     s->response[2] = 0;
416     s->response[3] = 0;
417     s->datatimer = 0;
418     s->datalength = 0;
419     s->datactrl = 0;
420     s->datacnt = 0;
421     s->status = 0;
422     s->mask[0] = 0;
423     s->mask[1] = 0;
424     s->fifocnt = 0;
425 }
426
427 void pl181_init(uint32_t base, BlockDriverState *bd,
428                 void *pic, int irq0, int irq1)
429 {
430     int iomemtype;
431     pl181_state *s;
432
433     s = (pl181_state *)qemu_mallocz(sizeof(pl181_state));
434     iomemtype = cpu_register_io_memory(0, pl181_readfn,
435                                        pl181_writefn, s);
436     cpu_register_physical_memory(base, 0x00000fff, iomemtype);
437     s->base = base;
438     s->card = sd_init(bd);
439     s->pic = pic;
440     s->irq[0] = irq0;
441     s->irq[1] = irq1;
442     qemu_register_reset(pl181_reset, s);
443     pl181_reset(s);
444     /* ??? Save/restore.  */
445 }