]> Git Repo - qemu.git/blob - hw/char/pl011.c
char: replace PROP_CHR with CharBackend
[qemu.git] / hw / char / pl011.c
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)
This page took 0.046294 seconds and 4 git commands to generate.