xref: /openbmc/qemu/hw/char/pl011.c (revision 19f4ed36)
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 bool pl011_clock_needed(void *opaque)
326 {
327     PL011State *s = PL011(opaque);
328 
329     return s->migrate_clk;
330 }
331 
332 static const VMStateDescription vmstate_pl011_clock = {
333     .name = "pl011/clock",
334     .version_id = 1,
335     .minimum_version_id = 1,
336     .needed = pl011_clock_needed,
337     .fields = (VMStateField[]) {
338         VMSTATE_CLOCK(clk, PL011State),
339         VMSTATE_END_OF_LIST()
340     }
341 };
342 
343 static const VMStateDescription vmstate_pl011 = {
344     .name = "pl011",
345     .version_id = 2,
346     .minimum_version_id = 2,
347     .fields = (VMStateField[]) {
348         VMSTATE_UINT32(readbuff, PL011State),
349         VMSTATE_UINT32(flags, PL011State),
350         VMSTATE_UINT32(lcr, PL011State),
351         VMSTATE_UINT32(rsr, PL011State),
352         VMSTATE_UINT32(cr, PL011State),
353         VMSTATE_UINT32(dmacr, PL011State),
354         VMSTATE_UINT32(int_enabled, PL011State),
355         VMSTATE_UINT32(int_level, PL011State),
356         VMSTATE_UINT32_ARRAY(read_fifo, PL011State, 16),
357         VMSTATE_UINT32(ilpr, PL011State),
358         VMSTATE_UINT32(ibrd, PL011State),
359         VMSTATE_UINT32(fbrd, PL011State),
360         VMSTATE_UINT32(ifl, PL011State),
361         VMSTATE_INT32(read_pos, PL011State),
362         VMSTATE_INT32(read_count, PL011State),
363         VMSTATE_INT32(read_trigger, PL011State),
364         VMSTATE_END_OF_LIST()
365     },
366     .subsections = (const VMStateDescription * []) {
367         &vmstate_pl011_clock,
368         NULL
369     }
370 };
371 
372 static Property pl011_properties[] = {
373     DEFINE_PROP_CHR("chardev", PL011State, chr),
374     DEFINE_PROP_BOOL("migrate-clk", PL011State, migrate_clk, true),
375     DEFINE_PROP_END_OF_LIST(),
376 };
377 
378 static void pl011_init(Object *obj)
379 {
380     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
381     PL011State *s = PL011(obj);
382     int i;
383 
384     memory_region_init_io(&s->iomem, OBJECT(s), &pl011_ops, s, "pl011", 0x1000);
385     sysbus_init_mmio(sbd, &s->iomem);
386     for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
387         sysbus_init_irq(sbd, &s->irq[i]);
388     }
389 
390     s->clk = qdev_init_clock_in(DEVICE(obj), "clk", pl011_clock_update, s,
391                                 ClockUpdate);
392 
393     s->read_trigger = 1;
394     s->ifl = 0x12;
395     s->cr = 0x300;
396     s->flags = 0x90;
397 
398     s->id = pl011_id_arm;
399 }
400 
401 static void pl011_realize(DeviceState *dev, Error **errp)
402 {
403     PL011State *s = PL011(dev);
404 
405     qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive,
406                              pl011_event, NULL, s, NULL, true);
407 }
408 
409 static void pl011_class_init(ObjectClass *oc, void *data)
410 {
411     DeviceClass *dc = DEVICE_CLASS(oc);
412 
413     dc->realize = pl011_realize;
414     dc->vmsd = &vmstate_pl011;
415     device_class_set_props(dc, pl011_properties);
416 }
417 
418 static const TypeInfo pl011_arm_info = {
419     .name          = TYPE_PL011,
420     .parent        = TYPE_SYS_BUS_DEVICE,
421     .instance_size = sizeof(PL011State),
422     .instance_init = pl011_init,
423     .class_init    = pl011_class_init,
424 };
425 
426 static void pl011_luminary_init(Object *obj)
427 {
428     PL011State *s = PL011(obj);
429 
430     s->id = pl011_id_luminary;
431 }
432 
433 static const TypeInfo pl011_luminary_info = {
434     .name          = TYPE_PL011_LUMINARY,
435     .parent        = TYPE_PL011,
436     .instance_init = pl011_luminary_init,
437 };
438 
439 static void pl011_register_types(void)
440 {
441     type_register_static(&pl011_arm_info);
442     type_register_static(&pl011_luminary_info);
443 }
444 
445 type_init(pl011_register_types)
446