]> git.proxmox.com Git - mirror_qemu.git/blame - hw/char/pl011.c
char: move CharBackend handling in char-fe unit
[mirror_qemu.git] / hw / char / pl011.c
CommitLineData
5fafdf24 1/*
cdbdb648
PB
2 * Arm PrimeCell PL011 UART
3 *
4 * Copyright (c) 2006 CodeSourcery.
5 * Written by Paul Brook
6 *
8e31bf38 7 * This code is licensed under the GPL.
cdbdb648
PB
8 */
9
8ef94f0b 10#include "qemu/osdep.h"
83c9f4ca 11#include "hw/sysbus.h"
4d43a603 12#include "chardev/char-fe.h"
03dd024f 13#include "qemu/log.h"
041ac056 14#include "trace.h"
cdbdb648 15
71ffe1a0
AF
16#define TYPE_PL011 "pl011"
17#define PL011(obj) OBJECT_CHECK(PL011State, (obj), TYPE_PL011)
18
ab640bfc 19typedef struct PL011State {
71ffe1a0
AF
20 SysBusDevice parent_obj;
21
48484757 22 MemoryRegion iomem;
cdbdb648
PB
23 uint32_t readbuff;
24 uint32_t flags;
25 uint32_t lcr;
ce8f0905 26 uint32_t rsr;
cdbdb648
PB
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;
becdfa00 39 CharBackend chr;
d537cf6c 40 qemu_irq irq;
a7d518a6 41 const unsigned char *id;
ab640bfc 42} PL011State;
cdbdb648
PB
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
a7d518a6
PB
52static const unsigned char pl011_id_arm[8] =
53 { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
54static const unsigned char pl011_id_luminary[8] =
55 { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
cdbdb648 56
ab640bfc 57static void pl011_update(PL011State *s)
cdbdb648
PB
58{
59 uint32_t flags;
3b46e624 60
cdbdb648 61 flags = s->int_level & s->int_enabled;
041ac056 62 trace_pl011_irq_state(flags != 0);
d537cf6c 63 qemu_set_irq(s->irq, flags != 0);
cdbdb648
PB
64}
65
a8170e5e 66static uint64_t pl011_read(void *opaque, hwaddr offset,
48484757 67 unsigned size)
cdbdb648 68{
ab640bfc 69 PL011State *s = (PL011State *)opaque;
cdbdb648 70 uint32_t c;
041ac056 71 uint64_t r;
cdbdb648 72
cdbdb648
PB
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;
041ac056 87 trace_pl011_read_fifo(s->read_count);
ce8f0905 88 s->rsr = c >> 8;
cdbdb648 89 pl011_update(s);
fa394ed6 90 qemu_chr_fe_accept_input(&s->chr);
041ac056
PM
91 r = c;
92 break;
ce8f0905 93 case 1: /* UARTRSR */
041ac056
PM
94 r = s->rsr;
95 break;
cdbdb648 96 case 6: /* UARTFR */
041ac056
PM
97 r = s->flags;
98 break;
cdbdb648 99 case 8: /* UARTILPR */
041ac056
PM
100 r = s->ilpr;
101 break;
cdbdb648 102 case 9: /* UARTIBRD */
041ac056
PM
103 r = s->ibrd;
104 break;
cdbdb648 105 case 10: /* UARTFBRD */
041ac056
PM
106 r = s->fbrd;
107 break;
cdbdb648 108 case 11: /* UARTLCR_H */
041ac056
PM
109 r = s->lcr;
110 break;
cdbdb648 111 case 12: /* UARTCR */
041ac056
PM
112 r = s->cr;
113 break;
cdbdb648 114 case 13: /* UARTIFLS */
041ac056
PM
115 r = s->ifl;
116 break;
cdbdb648 117 case 14: /* UARTIMSC */
041ac056
PM
118 r = s->int_enabled;
119 break;
cdbdb648 120 case 15: /* UARTRIS */
041ac056
PM
121 r = s->int_level;
122 break;
cdbdb648 123 case 16: /* UARTMIS */
041ac056
PM
124 r = s->int_level & s->int_enabled;
125 break;
cdbdb648 126 case 18: /* UARTDMACR */
041ac056
PM
127 r = s->dmacr;
128 break;
129 case 0x3f8 ... 0x400:
130 r = s->id[(offset - 0xfe0) >> 2];
131 break;
cdbdb648 132 default:
6d5433e0
PM
133 qemu_log_mask(LOG_GUEST_ERROR,
134 "pl011_read: Bad offset %x\n", (int)offset);
041ac056
PM
135 r = 0;
136 break;
cdbdb648 137 }
041ac056
PM
138
139 trace_pl011_read(offset, r);
140 return r;
cdbdb648
PB
141}
142
ab640bfc 143static void pl011_set_read_trigger(PL011State *s)
cdbdb648
PB
144{
145#if 0
146 /* The docs say the RX interrupt is triggered when the FIFO exceeds
147 the threshold. However linux only reads the FIFO in response to an
148 interrupt. Triggering the interrupt when the FIFO is non-empty seems
149 to make things work. */
150 if (s->lcr & 0x10)
151 s->read_trigger = (s->ifl >> 1) & 0x1c;
152 else
153#endif
154 s->read_trigger = 1;
155}
156
a8170e5e 157static void pl011_write(void *opaque, hwaddr offset,
48484757 158 uint64_t value, unsigned size)
cdbdb648 159{
ab640bfc 160 PL011State *s = (PL011State *)opaque;
cdbdb648
PB
161 unsigned char ch;
162
041ac056
PM
163 trace_pl011_write(offset, value);
164
cdbdb648
PB
165 switch (offset >> 2) {
166 case 0: /* UARTDR */
167 /* ??? Check if transmitter is enabled. */
168 ch = value;
fa394ed6
MAL
169 /* XXX this blocks entire thread. Rewrite to use
170 * qemu_chr_fe_write and background I/O callbacks */
171 qemu_chr_fe_write_all(&s->chr, &ch, 1);
cdbdb648
PB
172 s->int_level |= PL011_INT_TX;
173 pl011_update(s);
174 break;
ce8f0905
RH
175 case 1: /* UARTRSR/UARTECR */
176 s->rsr = 0;
cdbdb648 177 break;
9ee6e8bb
PB
178 case 6: /* UARTFR */
179 /* Writes to Flag register are ignored. */
180 break;
cdbdb648
PB
181 case 8: /* UARTUARTILPR */
182 s->ilpr = value;
183 break;
184 case 9: /* UARTIBRD */
185 s->ibrd = value;
186 break;
187 case 10: /* UARTFBRD */
188 s->fbrd = value;
189 break;
190 case 11: /* UARTLCR_H */
22709e90
RH
191 /* Reset the FIFO state on FIFO enable or disable */
192 if ((s->lcr ^ value) & 0x10) {
193 s->read_count = 0;
194 s->read_pos = 0;
195 }
cdbdb648
PB
196 s->lcr = value;
197 pl011_set_read_trigger(s);
198 break;
199 case 12: /* UARTCR */
200 /* ??? Need to implement the enable and loopback bits. */
201 s->cr = value;
202 break;
203 case 13: /* UARTIFS */
204 s->ifl = value;
205 pl011_set_read_trigger(s);
206 break;
207 case 14: /* UARTIMSC */
208 s->int_enabled = value;
209 pl011_update(s);
210 break;
211 case 17: /* UARTICR */
212 s->int_level &= ~value;
213 pl011_update(s);
214 break;
215 case 18: /* UARTDMACR */
216 s->dmacr = value;
6d5433e0
PM
217 if (value & 3) {
218 qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n");
219 }
cdbdb648
PB
220 break;
221 default:
6d5433e0
PM
222 qemu_log_mask(LOG_GUEST_ERROR,
223 "pl011_write: Bad offset %x\n", (int)offset);
cdbdb648
PB
224 }
225}
226
aa1f17c1 227static int pl011_can_receive(void *opaque)
cdbdb648 228{
ab640bfc 229 PL011State *s = (PL011State *)opaque;
041ac056 230 int r;
cdbdb648 231
041ac056
PM
232 if (s->lcr & 0x10) {
233 r = s->read_count < 16;
234 } else {
235 r = s->read_count < 1;
236 }
237 trace_pl011_can_receive(s->lcr, s->read_count, r);
238 return r;
cdbdb648
PB
239}
240
cc9c9ffc 241static void pl011_put_fifo(void *opaque, uint32_t value)
cdbdb648 242{
ab640bfc 243 PL011State *s = (PL011State *)opaque;
cdbdb648
PB
244 int slot;
245
246 slot = s->read_pos + s->read_count;
247 if (slot >= 16)
248 slot -= 16;
cc9c9ffc 249 s->read_fifo[slot] = value;
cdbdb648
PB
250 s->read_count++;
251 s->flags &= ~PL011_FLAG_RXFE;
041ac056 252 trace_pl011_put_fifo(value, s->read_count);
f72dbf3d 253 if (!(s->lcr & 0x10) || s->read_count == 16) {
041ac056 254 trace_pl011_put_fifo_full();
cdbdb648
PB
255 s->flags |= PL011_FLAG_RXFF;
256 }
257 if (s->read_count == s->read_trigger) {
258 s->int_level |= PL011_INT_RX;
259 pl011_update(s);
260 }
261}
262
cc9c9ffc
AJ
263static void pl011_receive(void *opaque, const uint8_t *buf, int size)
264{
265 pl011_put_fifo(opaque, *buf);
266}
267
cdbdb648
PB
268static void pl011_event(void *opaque, int event)
269{
cc9c9ffc
AJ
270 if (event == CHR_EVENT_BREAK)
271 pl011_put_fifo(opaque, 0x400);
cdbdb648
PB
272}
273
48484757
AK
274static const MemoryRegionOps pl011_ops = {
275 .read = pl011_read,
276 .write = pl011_write,
277 .endianness = DEVICE_NATIVE_ENDIAN,
cdbdb648
PB
278};
279
02b68757
JQ
280static const VMStateDescription vmstate_pl011 = {
281 .name = "pl011",
ce8f0905
RH
282 .version_id = 2,
283 .minimum_version_id = 2,
8f1e884b 284 .fields = (VMStateField[]) {
ab640bfc
AF
285 VMSTATE_UINT32(readbuff, PL011State),
286 VMSTATE_UINT32(flags, PL011State),
287 VMSTATE_UINT32(lcr, PL011State),
ce8f0905 288 VMSTATE_UINT32(rsr, PL011State),
ab640bfc
AF
289 VMSTATE_UINT32(cr, PL011State),
290 VMSTATE_UINT32(dmacr, PL011State),
291 VMSTATE_UINT32(int_enabled, PL011State),
292 VMSTATE_UINT32(int_level, PL011State),
293 VMSTATE_UINT32_ARRAY(read_fifo, PL011State, 16),
294 VMSTATE_UINT32(ilpr, PL011State),
295 VMSTATE_UINT32(ibrd, PL011State),
296 VMSTATE_UINT32(fbrd, PL011State),
297 VMSTATE_UINT32(ifl, PL011State),
298 VMSTATE_INT32(read_pos, PL011State),
299 VMSTATE_INT32(read_count, PL011State),
300 VMSTATE_INT32(read_trigger, PL011State),
02b68757
JQ
301 VMSTATE_END_OF_LIST()
302 }
303};
23e39294 304
f0d1d2c1
XZ
305static Property pl011_properties[] = {
306 DEFINE_PROP_CHR("chardev", PL011State, chr),
307 DEFINE_PROP_END_OF_LIST(),
308};
309
71ffe1a0 310static void pl011_init(Object *obj)
cdbdb648 311{
71ffe1a0
AF
312 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
313 PL011State *s = PL011(obj);
cdbdb648 314
300b1fc6 315 memory_region_init_io(&s->iomem, OBJECT(s), &pl011_ops, s, "pl011", 0x1000);
71ffe1a0
AF
316 sysbus_init_mmio(sbd, &s->iomem);
317 sysbus_init_irq(sbd, &s->irq);
a7d518a6 318
cdbdb648
PB
319 s->read_trigger = 1;
320 s->ifl = 0x12;
321 s->cr = 0x300;
322 s->flags = 0x90;
a7d518a6 323
71ffe1a0 324 s->id = pl011_id_arm;
a7d518a6
PB
325}
326
71ffe1a0 327static void pl011_realize(DeviceState *dev, Error **errp)
a7d518a6 328{
71ffe1a0
AF
329 PL011State *s = PL011(dev);
330
fa394ed6 331 qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive,
39ab61c6 332 pl011_event, s, NULL, true);
a7d518a6
PB
333}
334
71ffe1a0 335static void pl011_class_init(ObjectClass *oc, void *data)
999e12bb 336{
71ffe1a0 337 DeviceClass *dc = DEVICE_CLASS(oc);
999e12bb 338
71ffe1a0
AF
339 dc->realize = pl011_realize;
340 dc->vmsd = &vmstate_pl011;
f0d1d2c1 341 dc->props = pl011_properties;
999e12bb
AL
342}
343
8c43a6f0 344static const TypeInfo pl011_arm_info = {
71ffe1a0 345 .name = TYPE_PL011,
39bffca2 346 .parent = TYPE_SYS_BUS_DEVICE,
ab640bfc 347 .instance_size = sizeof(PL011State),
71ffe1a0
AF
348 .instance_init = pl011_init,
349 .class_init = pl011_class_init,
999e12bb
AL
350};
351
71ffe1a0 352static void pl011_luminary_init(Object *obj)
999e12bb 353{
71ffe1a0 354 PL011State *s = PL011(obj);
999e12bb 355
71ffe1a0 356 s->id = pl011_id_luminary;
999e12bb
AL
357}
358
8c43a6f0 359static const TypeInfo pl011_luminary_info = {
39bffca2 360 .name = "pl011_luminary",
71ffe1a0
AF
361 .parent = TYPE_PL011,
362 .instance_init = pl011_luminary_init,
999e12bb
AL
363};
364
83f7d43a 365static void pl011_register_types(void)
a7d518a6 366{
39bffca2
AL
367 type_register_static(&pl011_arm_info);
368 type_register_static(&pl011_luminary_info);
a7d518a6
PB
369}
370
83f7d43a 371type_init(pl011_register_types)