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