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