xref: /openbmc/qemu/hw/char/pl011.c (revision 7f709ce7)
1 /*
2  * Arm PrimeCell PL011 UART
3  *
4  * Copyright (c) 2006 CodeSourcery.
5  * Written by Paul Brook
6  *
7  * This code is licensed under the GPL.
8  */
9 
10 #include "qemu/osdep.h"
11 #include "hw/sysbus.h"
12 #include "chardev/char-fe.h"
13 #include "qemu/log.h"
14 #include "trace.h"
15 
16 #define TYPE_PL011 "pl011"
17 #define PL011(obj) OBJECT_CHECK(PL011State, (obj), TYPE_PL011)
18 
19 typedef struct PL011State {
20     SysBusDevice parent_obj;
21 
22     MemoryRegion iomem;
23     uint32_t readbuff;
24     uint32_t flags;
25     uint32_t lcr;
26     uint32_t rsr;
27     uint32_t cr;
28     uint32_t dmacr;
29     uint32_t int_enabled;
30     uint32_t int_level;
31     uint32_t read_fifo[16];
32     uint32_t ilpr;
33     uint32_t ibrd;
34     uint32_t fbrd;
35     uint32_t ifl;
36     int read_pos;
37     int read_count;
38     int read_trigger;
39     CharBackend chr;
40     qemu_irq irq;
41     const unsigned char *id;
42 } PL011State;
43 
44 #define PL011_INT_TX 0x20
45 #define PL011_INT_RX 0x10
46 
47 #define PL011_FLAG_TXFE 0x80
48 #define PL011_FLAG_RXFF 0x40
49 #define PL011_FLAG_TXFF 0x20
50 #define PL011_FLAG_RXFE 0x10
51 
52 static const unsigned char pl011_id_arm[8] =
53   { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
54 static const unsigned char pl011_id_luminary[8] =
55   { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
56 
57 static void pl011_update(PL011State *s)
58 {
59     uint32_t flags;
60 
61     flags = s->int_level & s->int_enabled;
62     trace_pl011_irq_state(flags != 0);
63     qemu_set_irq(s->irq, flags != 0);
64 }
65 
66 static uint64_t pl011_read(void *opaque, hwaddr offset,
67                            unsigned size)
68 {
69     PL011State *s = (PL011State *)opaque;
70     uint32_t c;
71     uint64_t r;
72 
73     switch (offset >> 2) {
74     case 0: /* UARTDR */
75         s->flags &= ~PL011_FLAG_RXFF;
76         c = s->read_fifo[s->read_pos];
77         if (s->read_count > 0) {
78             s->read_count--;
79             if (++s->read_pos == 16)
80                 s->read_pos = 0;
81         }
82         if (s->read_count == 0) {
83             s->flags |= PL011_FLAG_RXFE;
84         }
85         if (s->read_count == s->read_trigger - 1)
86             s->int_level &= ~ PL011_INT_RX;
87         trace_pl011_read_fifo(s->read_count);
88         s->rsr = c >> 8;
89         pl011_update(s);
90         qemu_chr_fe_accept_input(&s->chr);
91         r = c;
92         break;
93     case 1: /* UARTRSR */
94         r = s->rsr;
95         break;
96     case 6: /* UARTFR */
97         r = s->flags;
98         break;
99     case 8: /* UARTILPR */
100         r = s->ilpr;
101         break;
102     case 9: /* UARTIBRD */
103         r = s->ibrd;
104         break;
105     case 10: /* UARTFBRD */
106         r = s->fbrd;
107         break;
108     case 11: /* UARTLCR_H */
109         r = s->lcr;
110         break;
111     case 12: /* UARTCR */
112         r = s->cr;
113         break;
114     case 13: /* UARTIFLS */
115         r = s->ifl;
116         break;
117     case 14: /* UARTIMSC */
118         r = s->int_enabled;
119         break;
120     case 15: /* UARTRIS */
121         r = s->int_level;
122         break;
123     case 16: /* UARTMIS */
124         r = s->int_level & s->int_enabled;
125         break;
126     case 18: /* UARTDMACR */
127         r = s->dmacr;
128         break;
129     case 0x3f8 ... 0x400:
130         r = s->id[(offset - 0xfe0) >> 2];
131         break;
132     default:
133         qemu_log_mask(LOG_GUEST_ERROR,
134                       "pl011_read: Bad offset %x\n", (int)offset);
135         r = 0;
136         break;
137     }
138 
139     trace_pl011_read(offset, r);
140     return r;
141 }
142 
143 static void pl011_set_read_trigger(PL011State *s)
144 {
145 #if 0
146     /* The docs say the RX interrupt is triggered when the FIFO exceeds
147        the threshold.  However linux only reads the FIFO in response to an
148        interrupt.  Triggering the interrupt when the FIFO is non-empty seems
149        to make things work.  */
150     if (s->lcr & 0x10)
151         s->read_trigger = (s->ifl >> 1) & 0x1c;
152     else
153 #endif
154         s->read_trigger = 1;
155 }
156 
157 static void pl011_write(void *opaque, hwaddr offset,
158                         uint64_t value, unsigned size)
159 {
160     PL011State *s = (PL011State *)opaque;
161     unsigned char ch;
162 
163     trace_pl011_write(offset, value);
164 
165     switch (offset >> 2) {
166     case 0: /* UARTDR */
167         /* ??? Check if transmitter is enabled.  */
168         ch = value;
169         /* XXX this blocks entire thread. Rewrite to use
170          * qemu_chr_fe_write and background I/O callbacks */
171         qemu_chr_fe_write_all(&s->chr, &ch, 1);
172         s->int_level |= PL011_INT_TX;
173         pl011_update(s);
174         break;
175     case 1: /* UARTRSR/UARTECR */
176         s->rsr = 0;
177         break;
178     case 6: /* UARTFR */
179         /* Writes to Flag register are ignored.  */
180         break;
181     case 8: /* UARTUARTILPR */
182         s->ilpr = value;
183         break;
184     case 9: /* UARTIBRD */
185         s->ibrd = value;
186         break;
187     case 10: /* UARTFBRD */
188         s->fbrd = value;
189         break;
190     case 11: /* UARTLCR_H */
191         /* Reset the FIFO state on FIFO enable or disable */
192         if ((s->lcr ^ value) & 0x10) {
193             s->read_count = 0;
194             s->read_pos = 0;
195         }
196         s->lcr = value;
197         pl011_set_read_trigger(s);
198         break;
199     case 12: /* UARTCR */
200         /* ??? Need to implement the enable and loopback bits.  */
201         s->cr = value;
202         break;
203     case 13: /* UARTIFS */
204         s->ifl = value;
205         pl011_set_read_trigger(s);
206         break;
207     case 14: /* UARTIMSC */
208         s->int_enabled = value;
209         pl011_update(s);
210         break;
211     case 17: /* UARTICR */
212         s->int_level &= ~value;
213         pl011_update(s);
214         break;
215     case 18: /* UARTDMACR */
216         s->dmacr = value;
217         if (value & 3) {
218             qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n");
219         }
220         break;
221     default:
222         qemu_log_mask(LOG_GUEST_ERROR,
223                       "pl011_write: Bad offset %x\n", (int)offset);
224     }
225 }
226 
227 static int pl011_can_receive(void *opaque)
228 {
229     PL011State *s = (PL011State *)opaque;
230     int r;
231 
232     if (s->lcr & 0x10) {
233         r = s->read_count < 16;
234     } else {
235         r = s->read_count < 1;
236     }
237     trace_pl011_can_receive(s->lcr, s->read_count, r);
238     return r;
239 }
240 
241 static void pl011_put_fifo(void *opaque, uint32_t value)
242 {
243     PL011State *s = (PL011State *)opaque;
244     int slot;
245 
246     slot = s->read_pos + s->read_count;
247     if (slot >= 16)
248         slot -= 16;
249     s->read_fifo[slot] = value;
250     s->read_count++;
251     s->flags &= ~PL011_FLAG_RXFE;
252     trace_pl011_put_fifo(value, s->read_count);
253     if (!(s->lcr & 0x10) || s->read_count == 16) {
254         trace_pl011_put_fifo_full();
255         s->flags |= PL011_FLAG_RXFF;
256     }
257     if (s->read_count == s->read_trigger) {
258         s->int_level |= PL011_INT_RX;
259         pl011_update(s);
260     }
261 }
262 
263 static void pl011_receive(void *opaque, const uint8_t *buf, int size)
264 {
265     pl011_put_fifo(opaque, *buf);
266 }
267 
268 static void pl011_event(void *opaque, int event)
269 {
270     if (event == CHR_EVENT_BREAK)
271         pl011_put_fifo(opaque, 0x400);
272 }
273 
274 static const MemoryRegionOps pl011_ops = {
275     .read = pl011_read,
276     .write = pl011_write,
277     .endianness = DEVICE_NATIVE_ENDIAN,
278 };
279 
280 static const VMStateDescription vmstate_pl011 = {
281     .name = "pl011",
282     .version_id = 2,
283     .minimum_version_id = 2,
284     .fields = (VMStateField[]) {
285         VMSTATE_UINT32(readbuff, PL011State),
286         VMSTATE_UINT32(flags, PL011State),
287         VMSTATE_UINT32(lcr, PL011State),
288         VMSTATE_UINT32(rsr, PL011State),
289         VMSTATE_UINT32(cr, PL011State),
290         VMSTATE_UINT32(dmacr, PL011State),
291         VMSTATE_UINT32(int_enabled, PL011State),
292         VMSTATE_UINT32(int_level, PL011State),
293         VMSTATE_UINT32_ARRAY(read_fifo, PL011State, 16),
294         VMSTATE_UINT32(ilpr, PL011State),
295         VMSTATE_UINT32(ibrd, PL011State),
296         VMSTATE_UINT32(fbrd, PL011State),
297         VMSTATE_UINT32(ifl, PL011State),
298         VMSTATE_INT32(read_pos, PL011State),
299         VMSTATE_INT32(read_count, PL011State),
300         VMSTATE_INT32(read_trigger, PL011State),
301         VMSTATE_END_OF_LIST()
302     }
303 };
304 
305 static Property pl011_properties[] = {
306     DEFINE_PROP_CHR("chardev", PL011State, chr),
307     DEFINE_PROP_END_OF_LIST(),
308 };
309 
310 static void pl011_init(Object *obj)
311 {
312     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
313     PL011State *s = PL011(obj);
314 
315     memory_region_init_io(&s->iomem, OBJECT(s), &pl011_ops, s, "pl011", 0x1000);
316     sysbus_init_mmio(sbd, &s->iomem);
317     sysbus_init_irq(sbd, &s->irq);
318 
319     s->read_trigger = 1;
320     s->ifl = 0x12;
321     s->cr = 0x300;
322     s->flags = 0x90;
323 
324     s->id = pl011_id_arm;
325 }
326 
327 static void pl011_realize(DeviceState *dev, Error **errp)
328 {
329     PL011State *s = PL011(dev);
330 
331     qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive,
332                              pl011_event, NULL, s, NULL, true);
333 }
334 
335 static void pl011_class_init(ObjectClass *oc, void *data)
336 {
337     DeviceClass *dc = DEVICE_CLASS(oc);
338 
339     dc->realize = pl011_realize;
340     dc->vmsd = &vmstate_pl011;
341     dc->props = pl011_properties;
342 }
343 
344 static const TypeInfo pl011_arm_info = {
345     .name          = TYPE_PL011,
346     .parent        = TYPE_SYS_BUS_DEVICE,
347     .instance_size = sizeof(PL011State),
348     .instance_init = pl011_init,
349     .class_init    = pl011_class_init,
350 };
351 
352 static void pl011_luminary_init(Object *obj)
353 {
354     PL011State *s = PL011(obj);
355 
356     s->id = pl011_id_luminary;
357 }
358 
359 static const TypeInfo pl011_luminary_info = {
360     .name          = "pl011_luminary",
361     .parent        = TYPE_PL011,
362     .instance_init = pl011_luminary_init,
363 };
364 
365 static void pl011_register_types(void)
366 {
367     type_register_static(&pl011_arm_info);
368     type_register_static(&pl011_luminary_info);
369 }
370 
371 type_init(pl011_register_types)
372