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