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