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