xref: /openbmc/qemu/hw/char/pl011.c (revision e8ddc2eae5ccc41f0815e5c43e70cb04a7e67e2e)
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     CharDriverState *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) {
91             qemu_chr_accept_input(s->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)
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, &ch, 1);
175         s->int_level |= PL011_INT_TX;
176         pl011_update(s);
177         break;
178     case 1: /* UARTRSR/UARTECR */
179         s->rsr = 0;
180         break;
181     case 6: /* UARTFR */
182         /* Writes to Flag register are ignored.  */
183         break;
184     case 8: /* UARTUARTILPR */
185         s->ilpr = value;
186         break;
187     case 9: /* UARTIBRD */
188         s->ibrd = value;
189         break;
190     case 10: /* UARTFBRD */
191         s->fbrd = value;
192         break;
193     case 11: /* UARTLCR_H */
194         /* Reset the FIFO state on FIFO enable or disable */
195         if ((s->lcr ^ value) & 0x10) {
196             s->read_count = 0;
197             s->read_pos = 0;
198         }
199         s->lcr = value;
200         pl011_set_read_trigger(s);
201         break;
202     case 12: /* UARTCR */
203         /* ??? Need to implement the enable and loopback bits.  */
204         s->cr = value;
205         break;
206     case 13: /* UARTIFS */
207         s->ifl = value;
208         pl011_set_read_trigger(s);
209         break;
210     case 14: /* UARTIMSC */
211         s->int_enabled = value;
212         pl011_update(s);
213         break;
214     case 17: /* UARTICR */
215         s->int_level &= ~value;
216         pl011_update(s);
217         break;
218     case 18: /* UARTDMACR */
219         s->dmacr = value;
220         if (value & 3) {
221             qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n");
222         }
223         break;
224     default:
225         qemu_log_mask(LOG_GUEST_ERROR,
226                       "pl011_write: Bad offset %x\n", (int)offset);
227     }
228 }
229 
230 static int pl011_can_receive(void *opaque)
231 {
232     PL011State *s = (PL011State *)opaque;
233     int r;
234 
235     if (s->lcr & 0x10) {
236         r = s->read_count < 16;
237     } else {
238         r = s->read_count < 1;
239     }
240     trace_pl011_can_receive(s->lcr, s->read_count, r);
241     return r;
242 }
243 
244 static void pl011_put_fifo(void *opaque, uint32_t value)
245 {
246     PL011State *s = (PL011State *)opaque;
247     int slot;
248 
249     slot = s->read_pos + s->read_count;
250     if (slot >= 16)
251         slot -= 16;
252     s->read_fifo[slot] = value;
253     s->read_count++;
254     s->flags &= ~PL011_FLAG_RXFE;
255     trace_pl011_put_fifo(value, s->read_count);
256     if (!(s->lcr & 0x10) || s->read_count == 16) {
257         trace_pl011_put_fifo_full();
258         s->flags |= PL011_FLAG_RXFF;
259     }
260     if (s->read_count == s->read_trigger) {
261         s->int_level |= PL011_INT_RX;
262         pl011_update(s);
263     }
264 }
265 
266 static void pl011_receive(void *opaque, const uint8_t *buf, int size)
267 {
268     pl011_put_fifo(opaque, *buf);
269 }
270 
271 static void pl011_event(void *opaque, int event)
272 {
273     if (event == CHR_EVENT_BREAK)
274         pl011_put_fifo(opaque, 0x400);
275 }
276 
277 static const MemoryRegionOps pl011_ops = {
278     .read = pl011_read,
279     .write = pl011_write,
280     .endianness = DEVICE_NATIVE_ENDIAN,
281 };
282 
283 static const VMStateDescription vmstate_pl011 = {
284     .name = "pl011",
285     .version_id = 2,
286     .minimum_version_id = 2,
287     .fields = (VMStateField[]) {
288         VMSTATE_UINT32(readbuff, PL011State),
289         VMSTATE_UINT32(flags, PL011State),
290         VMSTATE_UINT32(lcr, PL011State),
291         VMSTATE_UINT32(rsr, PL011State),
292         VMSTATE_UINT32(cr, PL011State),
293         VMSTATE_UINT32(dmacr, PL011State),
294         VMSTATE_UINT32(int_enabled, PL011State),
295         VMSTATE_UINT32(int_level, PL011State),
296         VMSTATE_UINT32_ARRAY(read_fifo, PL011State, 16),
297         VMSTATE_UINT32(ilpr, PL011State),
298         VMSTATE_UINT32(ibrd, PL011State),
299         VMSTATE_UINT32(fbrd, PL011State),
300         VMSTATE_UINT32(ifl, PL011State),
301         VMSTATE_INT32(read_pos, PL011State),
302         VMSTATE_INT32(read_count, PL011State),
303         VMSTATE_INT32(read_trigger, PL011State),
304         VMSTATE_END_OF_LIST()
305     }
306 };
307 
308 static Property pl011_properties[] = {
309     DEFINE_PROP_CHR("chardev", PL011State, chr),
310     DEFINE_PROP_END_OF_LIST(),
311 };
312 
313 static void pl011_init(Object *obj)
314 {
315     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
316     PL011State *s = PL011(obj);
317 
318     memory_region_init_io(&s->iomem, OBJECT(s), &pl011_ops, s, "pl011", 0x1000);
319     sysbus_init_mmio(sbd, &s->iomem);
320     sysbus_init_irq(sbd, &s->irq);
321 
322     s->read_trigger = 1;
323     s->ifl = 0x12;
324     s->cr = 0x300;
325     s->flags = 0x90;
326 
327     s->id = pl011_id_arm;
328 }
329 
330 static void pl011_realize(DeviceState *dev, Error **errp)
331 {
332     PL011State *s = PL011(dev);
333 
334     if (s->chr) {
335         qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive,
336                               pl011_event, s);
337     }
338 }
339 
340 static void pl011_class_init(ObjectClass *oc, void *data)
341 {
342     DeviceClass *dc = DEVICE_CLASS(oc);
343 
344     dc->realize = pl011_realize;
345     dc->vmsd = &vmstate_pl011;
346     dc->props = pl011_properties;
347 }
348 
349 static const TypeInfo pl011_arm_info = {
350     .name          = TYPE_PL011,
351     .parent        = TYPE_SYS_BUS_DEVICE,
352     .instance_size = sizeof(PL011State),
353     .instance_init = pl011_init,
354     .class_init    = pl011_class_init,
355 };
356 
357 static void pl011_luminary_init(Object *obj)
358 {
359     PL011State *s = PL011(obj);
360 
361     s->id = pl011_id_luminary;
362 }
363 
364 static const TypeInfo pl011_luminary_info = {
365     .name          = "pl011_luminary",
366     .parent        = TYPE_PL011,
367     .instance_init = pl011_luminary_init,
368 };
369 
370 static void pl011_register_types(void)
371 {
372     type_register_static(&pl011_arm_info);
373     type_register_static(&pl011_luminary_info);
374 }
375 
376 type_init(pl011_register_types)
377