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