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