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