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