configure: change "found" to "find"
[qemu] / hw / pl011.c
1 /*
2  * Arm PrimeCell PL011 UART
3  *
4  * Copyright (c) 2006 CodeSourcery.
5  * Written by Paul Brook
6  *
7  * This code is licenced under the GPL.
8  */
9
10 #include "sysbus.h"
11 #include "qemu-char.h"
12
13 typedef struct {
14     SysBusDevice busdev;
15     uint32_t readbuff;
16     uint32_t flags;
17     uint32_t lcr;
18     uint32_t cr;
19     uint32_t dmacr;
20     uint32_t int_enabled;
21     uint32_t int_level;
22     uint32_t read_fifo[16];
23     uint32_t ilpr;
24     uint32_t ibrd;
25     uint32_t fbrd;
26     uint32_t ifl;
27     int read_pos;
28     int read_count;
29     int read_trigger;
30     CharDriverState *chr;
31     qemu_irq irq;
32     const unsigned char *id;
33 } pl011_state;
34
35 #define PL011_INT_TX 0x20
36 #define PL011_INT_RX 0x10
37
38 #define PL011_FLAG_TXFE 0x80
39 #define PL011_FLAG_RXFF 0x40
40 #define PL011_FLAG_TXFF 0x20
41 #define PL011_FLAG_RXFE 0x10
42
43 static const unsigned char pl011_id_arm[8] =
44   { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
45 static const unsigned char pl011_id_luminary[8] =
46   { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
47
48 static void pl011_update(pl011_state *s)
49 {
50     uint32_t flags;
51
52     flags = s->int_level & s->int_enabled;
53     qemu_set_irq(s->irq, flags != 0);
54 }
55
56 static uint32_t pl011_read(void *opaque, target_phys_addr_t offset)
57 {
58     pl011_state *s = (pl011_state *)opaque;
59     uint32_t c;
60
61     if (offset >= 0xfe0 && offset < 0x1000) {
62         return s->id[(offset - 0xfe0) >> 2];
63     }
64     switch (offset >> 2) {
65     case 0: /* UARTDR */
66         s->flags &= ~PL011_FLAG_RXFF;
67         c = s->read_fifo[s->read_pos];
68         if (s->read_count > 0) {
69             s->read_count--;
70             if (++s->read_pos == 16)
71                 s->read_pos = 0;
72         }
73         if (s->read_count == 0) {
74             s->flags |= PL011_FLAG_RXFE;
75         }
76         if (s->read_count == s->read_trigger - 1)
77             s->int_level &= ~ PL011_INT_RX;
78         pl011_update(s);
79         qemu_chr_accept_input(s->chr);
80         return c;
81     case 1: /* UARTCR */
82         return 0;
83     case 6: /* UARTFR */
84         return s->flags;
85     case 8: /* UARTILPR */
86         return s->ilpr;
87     case 9: /* UARTIBRD */
88         return s->ibrd;
89     case 10: /* UARTFBRD */
90         return s->fbrd;
91     case 11: /* UARTLCR_H */
92         return s->lcr;
93     case 12: /* UARTCR */
94         return s->cr;
95     case 13: /* UARTIFLS */
96         return s->ifl;
97     case 14: /* UARTIMSC */
98         return s->int_enabled;
99     case 15: /* UARTRIS */
100         return s->int_level;
101     case 16: /* UARTMIS */
102         return s->int_level & s->int_enabled;
103     case 18: /* UARTDMACR */
104         return s->dmacr;
105     default:
106         hw_error("pl011_read: Bad offset %x\n", (int)offset);
107         return 0;
108     }
109 }
110
111 static void pl011_set_read_trigger(pl011_state *s)
112 {
113 #if 0
114     /* The docs say the RX interrupt is triggered when the FIFO exceeds
115        the threshold.  However linux only reads the FIFO in response to an
116        interrupt.  Triggering the interrupt when the FIFO is non-empty seems
117        to make things work.  */
118     if (s->lcr & 0x10)
119         s->read_trigger = (s->ifl >> 1) & 0x1c;
120     else
121 #endif
122         s->read_trigger = 1;
123 }
124
125 static void pl011_write(void *opaque, target_phys_addr_t offset,
126                           uint32_t value)
127 {
128     pl011_state *s = (pl011_state *)opaque;
129     unsigned char ch;
130
131     switch (offset >> 2) {
132     case 0: /* UARTDR */
133         /* ??? Check if transmitter is enabled.  */
134         ch = value;
135         if (s->chr)
136             qemu_chr_write(s->chr, &ch, 1);
137         s->int_level |= PL011_INT_TX;
138         pl011_update(s);
139         break;
140     case 1: /* UARTCR */
141         s->cr = value;
142         break;
143     case 6: /* UARTFR */
144         /* Writes to Flag register are ignored.  */
145         break;
146     case 8: /* UARTUARTILPR */
147         s->ilpr = value;
148         break;
149     case 9: /* UARTIBRD */
150         s->ibrd = value;
151         break;
152     case 10: /* UARTFBRD */
153         s->fbrd = value;
154         break;
155     case 11: /* UARTLCR_H */
156         s->lcr = value;
157         pl011_set_read_trigger(s);
158         break;
159     case 12: /* UARTCR */
160         /* ??? Need to implement the enable and loopback bits.  */
161         s->cr = value;
162         break;
163     case 13: /* UARTIFS */
164         s->ifl = value;
165         pl011_set_read_trigger(s);
166         break;
167     case 14: /* UARTIMSC */
168         s->int_enabled = value;
169         pl011_update(s);
170         break;
171     case 17: /* UARTICR */
172         s->int_level &= ~value;
173         pl011_update(s);
174         break;
175     case 18: /* UARTDMACR */
176         s->dmacr = value;
177         if (value & 3)
178             hw_error("PL011: DMA not implemented\n");
179         break;
180     default:
181         hw_error("pl011_write: Bad offset %x\n", (int)offset);
182     }
183 }
184
185 static int pl011_can_receive(void *opaque)
186 {
187     pl011_state *s = (pl011_state *)opaque;
188
189     if (s->lcr & 0x10)
190         return s->read_count < 16;
191     else
192         return s->read_count < 1;
193 }
194
195 static void pl011_put_fifo(void *opaque, uint32_t value)
196 {
197     pl011_state *s = (pl011_state *)opaque;
198     int slot;
199
200     slot = s->read_pos + s->read_count;
201     if (slot >= 16)
202         slot -= 16;
203     s->read_fifo[slot] = value;
204     s->read_count++;
205     s->flags &= ~PL011_FLAG_RXFE;
206     if (s->cr & 0x10 || s->read_count == 16) {
207         s->flags |= PL011_FLAG_RXFF;
208     }
209     if (s->read_count == s->read_trigger) {
210         s->int_level |= PL011_INT_RX;
211         pl011_update(s);
212     }
213 }
214
215 static void pl011_receive(void *opaque, const uint8_t *buf, int size)
216 {
217     pl011_put_fifo(opaque, *buf);
218 }
219
220 static void pl011_event(void *opaque, int event)
221 {
222     if (event == CHR_EVENT_BREAK)
223         pl011_put_fifo(opaque, 0x400);
224 }
225
226 static CPUReadMemoryFunc * const pl011_readfn[] = {
227    pl011_read,
228    pl011_read,
229    pl011_read
230 };
231
232 static CPUWriteMemoryFunc * const pl011_writefn[] = {
233    pl011_write,
234    pl011_write,
235    pl011_write
236 };
237
238 static void pl011_save(QEMUFile *f, void *opaque)
239 {
240     pl011_state *s = (pl011_state *)opaque;
241     int i;
242
243     qemu_put_be32(f, s->readbuff);
244     qemu_put_be32(f, s->flags);
245     qemu_put_be32(f, s->lcr);
246     qemu_put_be32(f, s->cr);
247     qemu_put_be32(f, s->dmacr);
248     qemu_put_be32(f, s->int_enabled);
249     qemu_put_be32(f, s->int_level);
250     for (i = 0; i < 16; i++)
251         qemu_put_be32(f, s->read_fifo[i]);
252     qemu_put_be32(f, s->ilpr);
253     qemu_put_be32(f, s->ibrd);
254     qemu_put_be32(f, s->fbrd);
255     qemu_put_be32(f, s->ifl);
256     qemu_put_be32(f, s->read_pos);
257     qemu_put_be32(f, s->read_count);
258     qemu_put_be32(f, s->read_trigger);
259 }
260
261 static int pl011_load(QEMUFile *f, void *opaque, int version_id)
262 {
263     pl011_state *s = (pl011_state *)opaque;
264     int i;
265
266     if (version_id != 1)
267         return -EINVAL;
268
269     s->readbuff = qemu_get_be32(f);
270     s->flags = qemu_get_be32(f);
271     s->lcr = qemu_get_be32(f);
272     s->cr = qemu_get_be32(f);
273     s->dmacr = qemu_get_be32(f);
274     s->int_enabled = qemu_get_be32(f);
275     s->int_level = qemu_get_be32(f);
276     for (i = 0; i < 16; i++)
277         s->read_fifo[i] = qemu_get_be32(f);
278     s->ilpr = qemu_get_be32(f);
279     s->ibrd = qemu_get_be32(f);
280     s->fbrd = qemu_get_be32(f);
281     s->ifl = qemu_get_be32(f);
282     s->read_pos = qemu_get_be32(f);
283     s->read_count = qemu_get_be32(f);
284     s->read_trigger = qemu_get_be32(f);
285
286     return 0;
287 }
288
289 static int pl011_init(SysBusDevice *dev, const unsigned char *id)
290 {
291     int iomemtype;
292     pl011_state *s = FROM_SYSBUS(pl011_state, dev);
293
294     iomemtype = cpu_register_io_memory(pl011_readfn,
295                                        pl011_writefn, s);
296     sysbus_init_mmio(dev, 0x1000,iomemtype);
297     sysbus_init_irq(dev, &s->irq);
298     s->id = id;
299     s->chr = qdev_init_chardev(&dev->qdev);
300
301     s->read_trigger = 1;
302     s->ifl = 0x12;
303     s->cr = 0x300;
304     s->flags = 0x90;
305     if (s->chr) {
306         qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive,
307                               pl011_event, s);
308     }
309     register_savevm("pl011_uart", -1, 1, pl011_save, pl011_load, s);
310     return 0;
311 }
312
313 static int pl011_init_arm(SysBusDevice *dev)
314 {
315     return pl011_init(dev, pl011_id_arm);
316 }
317
318 static int pl011_init_luminary(SysBusDevice *dev)
319 {
320     return pl011_init(dev, pl011_id_luminary);
321 }
322
323 static void pl011_register_devices(void)
324 {
325     sysbus_register_dev("pl011", sizeof(pl011_state),
326                         pl011_init_arm);
327     sysbus_register_dev("pl011_luminary", sizeof(pl011_state),
328                         pl011_init_luminary);
329 }
330
331 device_init(pl011_register_devices)