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