xref: /openbmc/qemu/hw/char/pl011.c (revision effd60c8)
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 "qapi/error.h"
23 #include "hw/char/pl011.h"
24 #include "hw/irq.h"
25 #include "hw/sysbus.h"
26 #include "hw/qdev-clock.h"
27 #include "hw/qdev-properties.h"
28 #include "hw/qdev-properties-system.h"
29 #include "migration/vmstate.h"
30 #include "chardev/char-fe.h"
31 #include "chardev/char-serial.h"
32 #include "qemu/log.h"
33 #include "qemu/module.h"
34 #include "trace.h"
35 
36 DeviceState *pl011_create(hwaddr addr, qemu_irq irq, Chardev *chr)
37 {
38     DeviceState *dev;
39     SysBusDevice *s;
40 
41     dev = qdev_new("pl011");
42     s = SYS_BUS_DEVICE(dev);
43     qdev_prop_set_chr(dev, "chardev", chr);
44     sysbus_realize_and_unref(s, &error_fatal);
45     sysbus_mmio_map(s, 0, addr);
46     sysbus_connect_irq(s, 0, irq);
47 
48     return dev;
49 }
50 
51 /* Flag Register, UARTFR */
52 #define PL011_FLAG_TXFE 0x80
53 #define PL011_FLAG_RXFF 0x40
54 #define PL011_FLAG_TXFF 0x20
55 #define PL011_FLAG_RXFE 0x10
56 
57 /* Data Register, UARTDR */
58 #define DR_BE   (1 << 10)
59 
60 /* Interrupt status bits in UARTRIS, UARTMIS, UARTIMSC */
61 #define INT_OE (1 << 10)
62 #define INT_BE (1 << 9)
63 #define INT_PE (1 << 8)
64 #define INT_FE (1 << 7)
65 #define INT_RT (1 << 6)
66 #define INT_TX (1 << 5)
67 #define INT_RX (1 << 4)
68 #define INT_DSR (1 << 3)
69 #define INT_DCD (1 << 2)
70 #define INT_CTS (1 << 1)
71 #define INT_RI (1 << 0)
72 #define INT_E (INT_OE | INT_BE | INT_PE | INT_FE)
73 #define INT_MS (INT_RI | INT_DSR | INT_DCD | INT_CTS)
74 
75 /* Line Control Register, UARTLCR_H */
76 #define LCR_FEN     (1 << 4)
77 #define LCR_BRK     (1 << 0)
78 
79 static const unsigned char pl011_id_arm[8] =
80   { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
81 static const unsigned char pl011_id_luminary[8] =
82   { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
83 
84 static const char *pl011_regname(hwaddr offset)
85 {
86     static const char *const rname[] = {
87         [0] = "DR", [1] = "RSR", [6] = "FR", [8] = "ILPR", [9] = "IBRD",
88         [10] = "FBRD", [11] = "LCRH", [12] = "CR", [13] = "IFLS", [14] = "IMSC",
89         [15] = "RIS", [16] = "MIS", [17] = "ICR", [18] = "DMACR",
90     };
91     unsigned idx = offset >> 2;
92 
93     if (idx < ARRAY_SIZE(rname) && rname[idx]) {
94         return rname[idx];
95     }
96     if (idx >= 0x3f8 && idx <= 0x400) {
97         return "ID";
98     }
99     return "UNKN";
100 }
101 
102 /* Which bits in the interrupt status matter for each outbound IRQ line ? */
103 static const uint32_t irqmask[] = {
104     INT_E | INT_MS | INT_RT | INT_TX | INT_RX, /* combined IRQ */
105     INT_RX,
106     INT_TX,
107     INT_RT,
108     INT_MS,
109     INT_E,
110 };
111 
112 static void pl011_update(PL011State *s)
113 {
114     uint32_t flags;
115     int i;
116 
117     flags = s->int_level & s->int_enabled;
118     trace_pl011_irq_state(flags != 0);
119     for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
120         qemu_set_irq(s->irq[i], (flags & irqmask[i]) != 0);
121     }
122 }
123 
124 static bool pl011_is_fifo_enabled(PL011State *s)
125 {
126     return (s->lcr & LCR_FEN) != 0;
127 }
128 
129 static inline unsigned pl011_get_fifo_depth(PL011State *s)
130 {
131     /* Note: FIFO depth is expected to be power-of-2 */
132     return pl011_is_fifo_enabled(s) ? PL011_FIFO_DEPTH : 1;
133 }
134 
135 static inline void pl011_reset_fifo(PL011State *s)
136 {
137     s->read_count = 0;
138     s->read_pos = 0;
139 
140     /* Reset FIFO flags */
141     s->flags &= ~(PL011_FLAG_RXFF | PL011_FLAG_TXFF);
142     s->flags |= PL011_FLAG_RXFE | PL011_FLAG_TXFE;
143 }
144 
145 static uint64_t pl011_read(void *opaque, hwaddr offset,
146                            unsigned size)
147 {
148     PL011State *s = (PL011State *)opaque;
149     uint32_t c;
150     uint64_t r;
151 
152     switch (offset >> 2) {
153     case 0: /* UARTDR */
154         s->flags &= ~PL011_FLAG_RXFF;
155         c = s->read_fifo[s->read_pos];
156         if (s->read_count > 0) {
157             s->read_count--;
158             s->read_pos = (s->read_pos + 1) & (pl011_get_fifo_depth(s) - 1);
159         }
160         if (s->read_count == 0) {
161             s->flags |= PL011_FLAG_RXFE;
162         }
163         if (s->read_count == s->read_trigger - 1)
164             s->int_level &= ~ INT_RX;
165         trace_pl011_read_fifo(s->read_count);
166         s->rsr = c >> 8;
167         pl011_update(s);
168         qemu_chr_fe_accept_input(&s->chr);
169         r = c;
170         break;
171     case 1: /* UARTRSR */
172         r = s->rsr;
173         break;
174     case 6: /* UARTFR */
175         r = s->flags;
176         break;
177     case 8: /* UARTILPR */
178         r = s->ilpr;
179         break;
180     case 9: /* UARTIBRD */
181         r = s->ibrd;
182         break;
183     case 10: /* UARTFBRD */
184         r = s->fbrd;
185         break;
186     case 11: /* UARTLCR_H */
187         r = s->lcr;
188         break;
189     case 12: /* UARTCR */
190         r = s->cr;
191         break;
192     case 13: /* UARTIFLS */
193         r = s->ifl;
194         break;
195     case 14: /* UARTIMSC */
196         r = s->int_enabled;
197         break;
198     case 15: /* UARTRIS */
199         r = s->int_level;
200         break;
201     case 16: /* UARTMIS */
202         r = s->int_level & s->int_enabled;
203         break;
204     case 18: /* UARTDMACR */
205         r = s->dmacr;
206         break;
207     case 0x3f8 ... 0x400:
208         r = s->id[(offset - 0xfe0) >> 2];
209         break;
210     default:
211         qemu_log_mask(LOG_GUEST_ERROR,
212                       "pl011_read: Bad offset 0x%x\n", (int)offset);
213         r = 0;
214         break;
215     }
216 
217     trace_pl011_read(offset, r, pl011_regname(offset));
218     return r;
219 }
220 
221 static void pl011_set_read_trigger(PL011State *s)
222 {
223 #if 0
224     /* The docs say the RX interrupt is triggered when the FIFO exceeds
225        the threshold.  However linux only reads the FIFO in response to an
226        interrupt.  Triggering the interrupt when the FIFO is non-empty seems
227        to make things work.  */
228     if (s->lcr & LCR_FEN)
229         s->read_trigger = (s->ifl >> 1) & 0x1c;
230     else
231 #endif
232         s->read_trigger = 1;
233 }
234 
235 static unsigned int pl011_get_baudrate(const PL011State *s)
236 {
237     uint64_t clk;
238 
239     if (s->ibrd == 0) {
240         return 0;
241     }
242 
243     clk = clock_get_hz(s->clk);
244     return (clk / ((s->ibrd << 6) + s->fbrd)) << 2;
245 }
246 
247 static void pl011_trace_baudrate_change(const PL011State *s)
248 {
249     trace_pl011_baudrate_change(pl011_get_baudrate(s),
250                                 clock_get_hz(s->clk),
251                                 s->ibrd, s->fbrd);
252 }
253 
254 static void pl011_write(void *opaque, hwaddr offset,
255                         uint64_t value, unsigned size)
256 {
257     PL011State *s = (PL011State *)opaque;
258     unsigned char ch;
259 
260     trace_pl011_write(offset, value, pl011_regname(offset));
261 
262     switch (offset >> 2) {
263     case 0: /* UARTDR */
264         /* ??? Check if transmitter is enabled.  */
265         ch = value;
266         /* XXX this blocks entire thread. Rewrite to use
267          * qemu_chr_fe_write and background I/O callbacks */
268         qemu_chr_fe_write_all(&s->chr, &ch, 1);
269         s->int_level |= INT_TX;
270         pl011_update(s);
271         break;
272     case 1: /* UARTRSR/UARTECR */
273         s->rsr = 0;
274         break;
275     case 6: /* UARTFR */
276         /* Writes to Flag register are ignored.  */
277         break;
278     case 8: /* UARTILPR */
279         s->ilpr = value;
280         break;
281     case 9: /* UARTIBRD */
282         s->ibrd = value;
283         pl011_trace_baudrate_change(s);
284         break;
285     case 10: /* UARTFBRD */
286         s->fbrd = value;
287         pl011_trace_baudrate_change(s);
288         break;
289     case 11: /* UARTLCR_H */
290         /* Reset the FIFO state on FIFO enable or disable */
291         if ((s->lcr ^ value) & LCR_FEN) {
292             pl011_reset_fifo(s);
293         }
294         if ((s->lcr ^ value) & LCR_BRK) {
295             int break_enable = value & LCR_BRK;
296             qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
297                               &break_enable);
298         }
299         s->lcr = value;
300         pl011_set_read_trigger(s);
301         break;
302     case 12: /* UARTCR */
303         /* ??? Need to implement the enable and loopback bits.  */
304         s->cr = value;
305         break;
306     case 13: /* UARTIFS */
307         s->ifl = value;
308         pl011_set_read_trigger(s);
309         break;
310     case 14: /* UARTIMSC */
311         s->int_enabled = value;
312         pl011_update(s);
313         break;
314     case 17: /* UARTICR */
315         s->int_level &= ~value;
316         pl011_update(s);
317         break;
318     case 18: /* UARTDMACR */
319         s->dmacr = value;
320         if (value & 3) {
321             qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n");
322         }
323         break;
324     default:
325         qemu_log_mask(LOG_GUEST_ERROR,
326                       "pl011_write: Bad offset 0x%x\n", (int)offset);
327     }
328 }
329 
330 static int pl011_can_receive(void *opaque)
331 {
332     PL011State *s = (PL011State *)opaque;
333     int r;
334 
335     r = s->read_count < pl011_get_fifo_depth(s);
336     trace_pl011_can_receive(s->lcr, s->read_count, r);
337     return r;
338 }
339 
340 static void pl011_put_fifo(void *opaque, uint32_t value)
341 {
342     PL011State *s = (PL011State *)opaque;
343     int slot;
344     unsigned pipe_depth;
345 
346     pipe_depth = pl011_get_fifo_depth(s);
347     slot = (s->read_pos + s->read_count) & (pipe_depth - 1);
348     s->read_fifo[slot] = value;
349     s->read_count++;
350     s->flags &= ~PL011_FLAG_RXFE;
351     trace_pl011_put_fifo(value, s->read_count);
352     if (s->read_count == pipe_depth) {
353         trace_pl011_put_fifo_full();
354         s->flags |= PL011_FLAG_RXFF;
355     }
356     if (s->read_count == s->read_trigger) {
357         s->int_level |= INT_RX;
358         pl011_update(s);
359     }
360 }
361 
362 static void pl011_receive(void *opaque, const uint8_t *buf, int size)
363 {
364     pl011_put_fifo(opaque, *buf);
365 }
366 
367 static void pl011_event(void *opaque, QEMUChrEvent event)
368 {
369     if (event == CHR_EVENT_BREAK) {
370         pl011_put_fifo(opaque, DR_BE);
371     }
372 }
373 
374 static void pl011_clock_update(void *opaque, ClockEvent event)
375 {
376     PL011State *s = PL011(opaque);
377 
378     pl011_trace_baudrate_change(s);
379 }
380 
381 static const MemoryRegionOps pl011_ops = {
382     .read = pl011_read,
383     .write = pl011_write,
384     .endianness = DEVICE_NATIVE_ENDIAN,
385     .impl.min_access_size = 4,
386     .impl.max_access_size = 4,
387 };
388 
389 static bool pl011_clock_needed(void *opaque)
390 {
391     PL011State *s = PL011(opaque);
392 
393     return s->migrate_clk;
394 }
395 
396 static const VMStateDescription vmstate_pl011_clock = {
397     .name = "pl011/clock",
398     .version_id = 1,
399     .minimum_version_id = 1,
400     .needed = pl011_clock_needed,
401     .fields = (const VMStateField[]) {
402         VMSTATE_CLOCK(clk, PL011State),
403         VMSTATE_END_OF_LIST()
404     }
405 };
406 
407 static int pl011_post_load(void *opaque, int version_id)
408 {
409     PL011State* s = opaque;
410 
411     /* Sanity-check input state */
412     if (s->read_pos >= ARRAY_SIZE(s->read_fifo) ||
413         s->read_count > ARRAY_SIZE(s->read_fifo)) {
414         return -1;
415     }
416 
417     if (!pl011_is_fifo_enabled(s) && s->read_count > 0 && s->read_pos > 0) {
418         /*
419          * Older versions of PL011 didn't ensure that the single
420          * character in the FIFO in FIFO-disabled mode is in
421          * element 0 of the array; convert to follow the current
422          * code's assumptions.
423          */
424         s->read_fifo[0] = s->read_fifo[s->read_pos];
425         s->read_pos = 0;
426     }
427 
428     return 0;
429 }
430 
431 static const VMStateDescription vmstate_pl011 = {
432     .name = "pl011",
433     .version_id = 2,
434     .minimum_version_id = 2,
435     .post_load = pl011_post_load,
436     .fields = (const VMStateField[]) {
437         VMSTATE_UINT32(readbuff, PL011State),
438         VMSTATE_UINT32(flags, PL011State),
439         VMSTATE_UINT32(lcr, PL011State),
440         VMSTATE_UINT32(rsr, PL011State),
441         VMSTATE_UINT32(cr, PL011State),
442         VMSTATE_UINT32(dmacr, PL011State),
443         VMSTATE_UINT32(int_enabled, PL011State),
444         VMSTATE_UINT32(int_level, PL011State),
445         VMSTATE_UINT32_ARRAY(read_fifo, PL011State, PL011_FIFO_DEPTH),
446         VMSTATE_UINT32(ilpr, PL011State),
447         VMSTATE_UINT32(ibrd, PL011State),
448         VMSTATE_UINT32(fbrd, PL011State),
449         VMSTATE_UINT32(ifl, PL011State),
450         VMSTATE_INT32(read_pos, PL011State),
451         VMSTATE_INT32(read_count, PL011State),
452         VMSTATE_INT32(read_trigger, PL011State),
453         VMSTATE_END_OF_LIST()
454     },
455     .subsections = (const VMStateDescription * const []) {
456         &vmstate_pl011_clock,
457         NULL
458     }
459 };
460 
461 static Property pl011_properties[] = {
462     DEFINE_PROP_CHR("chardev", PL011State, chr),
463     DEFINE_PROP_BOOL("migrate-clk", PL011State, migrate_clk, true),
464     DEFINE_PROP_END_OF_LIST(),
465 };
466 
467 static void pl011_init(Object *obj)
468 {
469     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
470     PL011State *s = PL011(obj);
471     int i;
472 
473     memory_region_init_io(&s->iomem, OBJECT(s), &pl011_ops, s, "pl011", 0x1000);
474     sysbus_init_mmio(sbd, &s->iomem);
475     for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
476         sysbus_init_irq(sbd, &s->irq[i]);
477     }
478 
479     s->clk = qdev_init_clock_in(DEVICE(obj), "clk", pl011_clock_update, s,
480                                 ClockUpdate);
481 
482     s->id = pl011_id_arm;
483 }
484 
485 static void pl011_realize(DeviceState *dev, Error **errp)
486 {
487     PL011State *s = PL011(dev);
488 
489     qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive,
490                              pl011_event, NULL, s, NULL, true);
491 }
492 
493 static void pl011_reset(DeviceState *dev)
494 {
495     PL011State *s = PL011(dev);
496 
497     s->lcr = 0;
498     s->rsr = 0;
499     s->dmacr = 0;
500     s->int_enabled = 0;
501     s->int_level = 0;
502     s->ilpr = 0;
503     s->ibrd = 0;
504     s->fbrd = 0;
505     s->read_trigger = 1;
506     s->ifl = 0x12;
507     s->cr = 0x300;
508     s->flags = 0;
509     pl011_reset_fifo(s);
510 }
511 
512 static void pl011_class_init(ObjectClass *oc, void *data)
513 {
514     DeviceClass *dc = DEVICE_CLASS(oc);
515 
516     dc->realize = pl011_realize;
517     dc->reset = pl011_reset;
518     dc->vmsd = &vmstate_pl011;
519     device_class_set_props(dc, pl011_properties);
520 }
521 
522 static const TypeInfo pl011_arm_info = {
523     .name          = TYPE_PL011,
524     .parent        = TYPE_SYS_BUS_DEVICE,
525     .instance_size = sizeof(PL011State),
526     .instance_init = pl011_init,
527     .class_init    = pl011_class_init,
528 };
529 
530 static void pl011_luminary_init(Object *obj)
531 {
532     PL011State *s = PL011(obj);
533 
534     s->id = pl011_id_luminary;
535 }
536 
537 static const TypeInfo pl011_luminary_info = {
538     .name          = TYPE_PL011_LUMINARY,
539     .parent        = TYPE_PL011,
540     .instance_init = pl011_luminary_init,
541 };
542 
543 static void pl011_register_types(void)
544 {
545     type_register_static(&pl011_arm_info);
546     type_register_static(&pl011_luminary_info);
547 }
548 
549 type_init(pl011_register_types)
550