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