Jobs based on custom runners: documentation and configuration placeholder
[qemu.git] / hw / char / pl011.c
blobdc85527a5f92f48d5700aafab818e7dde88b769f
1 /*
2 * Arm PrimeCell PL011 UART
4 * Copyright (c) 2006 CodeSourcery.
5 * Written by Paul Brook
7 * This code is licensed under the GPL.
8 */
11 * QEMU interface:
12 * + sysbus MMIO region 0: device registers
13 * + sysbus IRQ 0: UARTINTR (combined interrupt line)
14 * + sysbus IRQ 1: UARTRXINTR (receive FIFO interrupt line)
15 * + sysbus IRQ 2: UARTTXINTR (transmit FIFO interrupt line)
16 * + sysbus IRQ 3: UARTRTINTR (receive timeout interrupt line)
17 * + sysbus IRQ 4: UARTMSINTR (momem status interrupt line)
18 * + sysbus IRQ 5: UARTEINTR (error interrupt line)
21 #include "qemu/osdep.h"
22 #include "hw/char/pl011.h"
23 #include "hw/irq.h"
24 #include "hw/sysbus.h"
25 #include "hw/qdev-clock.h"
26 #include "hw/qdev-properties-system.h"
27 #include "migration/vmstate.h"
28 #include "chardev/char-fe.h"
29 #include "qemu/log.h"
30 #include "qemu/module.h"
31 #include "trace.h"
33 #define PL011_INT_TX 0x20
34 #define PL011_INT_RX 0x10
36 #define PL011_FLAG_TXFE 0x80
37 #define PL011_FLAG_RXFF 0x40
38 #define PL011_FLAG_TXFF 0x20
39 #define PL011_FLAG_RXFE 0x10
41 /* Interrupt status bits in UARTRIS, UARTMIS, UARTIMSC */
42 #define INT_OE (1 << 10)
43 #define INT_BE (1 << 9)
44 #define INT_PE (1 << 8)
45 #define INT_FE (1 << 7)
46 #define INT_RT (1 << 6)
47 #define INT_TX (1 << 5)
48 #define INT_RX (1 << 4)
49 #define INT_DSR (1 << 3)
50 #define INT_DCD (1 << 2)
51 #define INT_CTS (1 << 1)
52 #define INT_RI (1 << 0)
53 #define INT_E (INT_OE | INT_BE | INT_PE | INT_FE)
54 #define INT_MS (INT_RI | INT_DSR | INT_DCD | INT_CTS)
56 static const unsigned char pl011_id_arm[8] =
57 { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
58 static const unsigned char pl011_id_luminary[8] =
59 { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
61 /* Which bits in the interrupt status matter for each outbound IRQ line ? */
62 static const uint32_t irqmask[] = {
63 INT_E | INT_MS | INT_RT | INT_TX | INT_RX, /* combined IRQ */
64 INT_RX,
65 INT_TX,
66 INT_RT,
67 INT_MS,
68 INT_E,
71 static void pl011_update(PL011State *s)
73 uint32_t flags;
74 int i;
76 flags = s->int_level & s->int_enabled;
77 trace_pl011_irq_state(flags != 0);
78 for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
79 qemu_set_irq(s->irq[i], (flags & irqmask[i]) != 0);
83 static uint64_t pl011_read(void *opaque, hwaddr offset,
84 unsigned size)
86 PL011State *s = (PL011State *)opaque;
87 uint32_t c;
88 uint64_t r;
90 switch (offset >> 2) {
91 case 0: /* UARTDR */
92 s->flags &= ~PL011_FLAG_RXFF;
93 c = s->read_fifo[s->read_pos];
94 if (s->read_count > 0) {
95 s->read_count--;
96 if (++s->read_pos == 16)
97 s->read_pos = 0;
99 if (s->read_count == 0) {
100 s->flags |= PL011_FLAG_RXFE;
102 if (s->read_count == s->read_trigger - 1)
103 s->int_level &= ~ PL011_INT_RX;
104 trace_pl011_read_fifo(s->read_count);
105 s->rsr = c >> 8;
106 pl011_update(s);
107 qemu_chr_fe_accept_input(&s->chr);
108 r = c;
109 break;
110 case 1: /* UARTRSR */
111 r = s->rsr;
112 break;
113 case 6: /* UARTFR */
114 r = s->flags;
115 break;
116 case 8: /* UARTILPR */
117 r = s->ilpr;
118 break;
119 case 9: /* UARTIBRD */
120 r = s->ibrd;
121 break;
122 case 10: /* UARTFBRD */
123 r = s->fbrd;
124 break;
125 case 11: /* UARTLCR_H */
126 r = s->lcr;
127 break;
128 case 12: /* UARTCR */
129 r = s->cr;
130 break;
131 case 13: /* UARTIFLS */
132 r = s->ifl;
133 break;
134 case 14: /* UARTIMSC */
135 r = s->int_enabled;
136 break;
137 case 15: /* UARTRIS */
138 r = s->int_level;
139 break;
140 case 16: /* UARTMIS */
141 r = s->int_level & s->int_enabled;
142 break;
143 case 18: /* UARTDMACR */
144 r = s->dmacr;
145 break;
146 case 0x3f8 ... 0x400:
147 r = s->id[(offset - 0xfe0) >> 2];
148 break;
149 default:
150 qemu_log_mask(LOG_GUEST_ERROR,
151 "pl011_read: Bad offset 0x%x\n", (int)offset);
152 r = 0;
153 break;
156 trace_pl011_read(offset, r);
157 return r;
160 static void pl011_set_read_trigger(PL011State *s)
162 #if 0
163 /* The docs say the RX interrupt is triggered when the FIFO exceeds
164 the threshold. However linux only reads the FIFO in response to an
165 interrupt. Triggering the interrupt when the FIFO is non-empty seems
166 to make things work. */
167 if (s->lcr & 0x10)
168 s->read_trigger = (s->ifl >> 1) & 0x1c;
169 else
170 #endif
171 s->read_trigger = 1;
174 static unsigned int pl011_get_baudrate(const PL011State *s)
176 uint64_t clk;
178 if (s->fbrd == 0) {
179 return 0;
182 clk = clock_get_hz(s->clk);
183 return (clk / ((s->ibrd << 6) + s->fbrd)) << 2;
186 static void pl011_trace_baudrate_change(const PL011State *s)
188 trace_pl011_baudrate_change(pl011_get_baudrate(s),
189 clock_get_hz(s->clk),
190 s->ibrd, s->fbrd);
193 static void pl011_write(void *opaque, hwaddr offset,
194 uint64_t value, unsigned size)
196 PL011State *s = (PL011State *)opaque;
197 unsigned char ch;
199 trace_pl011_write(offset, value);
201 switch (offset >> 2) {
202 case 0: /* UARTDR */
203 /* ??? Check if transmitter is enabled. */
204 ch = value;
205 /* XXX this blocks entire thread. Rewrite to use
206 * qemu_chr_fe_write and background I/O callbacks */
207 qemu_chr_fe_write_all(&s->chr, &ch, 1);
208 s->int_level |= PL011_INT_TX;
209 pl011_update(s);
210 break;
211 case 1: /* UARTRSR/UARTECR */
212 s->rsr = 0;
213 break;
214 case 6: /* UARTFR */
215 /* Writes to Flag register are ignored. */
216 break;
217 case 8: /* UARTUARTILPR */
218 s->ilpr = value;
219 break;
220 case 9: /* UARTIBRD */
221 s->ibrd = value;
222 pl011_trace_baudrate_change(s);
223 break;
224 case 10: /* UARTFBRD */
225 s->fbrd = value;
226 pl011_trace_baudrate_change(s);
227 break;
228 case 11: /* UARTLCR_H */
229 /* Reset the FIFO state on FIFO enable or disable */
230 if ((s->lcr ^ value) & 0x10) {
231 s->read_count = 0;
232 s->read_pos = 0;
234 s->lcr = value;
235 pl011_set_read_trigger(s);
236 break;
237 case 12: /* UARTCR */
238 /* ??? Need to implement the enable and loopback bits. */
239 s->cr = value;
240 break;
241 case 13: /* UARTIFS */
242 s->ifl = value;
243 pl011_set_read_trigger(s);
244 break;
245 case 14: /* UARTIMSC */
246 s->int_enabled = value;
247 pl011_update(s);
248 break;
249 case 17: /* UARTICR */
250 s->int_level &= ~value;
251 pl011_update(s);
252 break;
253 case 18: /* UARTDMACR */
254 s->dmacr = value;
255 if (value & 3) {
256 qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n");
258 break;
259 default:
260 qemu_log_mask(LOG_GUEST_ERROR,
261 "pl011_write: Bad offset 0x%x\n", (int)offset);
265 static int pl011_can_receive(void *opaque)
267 PL011State *s = (PL011State *)opaque;
268 int r;
270 if (s->lcr & 0x10) {
271 r = s->read_count < 16;
272 } else {
273 r = s->read_count < 1;
275 trace_pl011_can_receive(s->lcr, s->read_count, r);
276 return r;
279 static void pl011_put_fifo(void *opaque, uint32_t value)
281 PL011State *s = (PL011State *)opaque;
282 int slot;
284 slot = s->read_pos + s->read_count;
285 if (slot >= 16)
286 slot -= 16;
287 s->read_fifo[slot] = value;
288 s->read_count++;
289 s->flags &= ~PL011_FLAG_RXFE;
290 trace_pl011_put_fifo(value, s->read_count);
291 if (!(s->lcr & 0x10) || s->read_count == 16) {
292 trace_pl011_put_fifo_full();
293 s->flags |= PL011_FLAG_RXFF;
295 if (s->read_count == s->read_trigger) {
296 s->int_level |= PL011_INT_RX;
297 pl011_update(s);
301 static void pl011_receive(void *opaque, const uint8_t *buf, int size)
303 pl011_put_fifo(opaque, *buf);
306 static void pl011_event(void *opaque, QEMUChrEvent event)
308 if (event == CHR_EVENT_BREAK)
309 pl011_put_fifo(opaque, 0x400);
312 static void pl011_clock_update(void *opaque, ClockEvent event)
314 PL011State *s = PL011(opaque);
316 pl011_trace_baudrate_change(s);
319 static const MemoryRegionOps pl011_ops = {
320 .read = pl011_read,
321 .write = pl011_write,
322 .endianness = DEVICE_NATIVE_ENDIAN,
325 static bool pl011_clock_needed(void *opaque)
327 PL011State *s = PL011(opaque);
329 return s->migrate_clk;
332 static const VMStateDescription vmstate_pl011_clock = {
333 .name = "pl011/clock",
334 .version_id = 1,
335 .minimum_version_id = 1,
336 .needed = pl011_clock_needed,
337 .fields = (VMStateField[]) {
338 VMSTATE_CLOCK(clk, PL011State),
339 VMSTATE_END_OF_LIST()
343 static const VMStateDescription vmstate_pl011 = {
344 .name = "pl011",
345 .version_id = 2,
346 .minimum_version_id = 2,
347 .fields = (VMStateField[]) {
348 VMSTATE_UINT32(readbuff, PL011State),
349 VMSTATE_UINT32(flags, PL011State),
350 VMSTATE_UINT32(lcr, PL011State),
351 VMSTATE_UINT32(rsr, PL011State),
352 VMSTATE_UINT32(cr, PL011State),
353 VMSTATE_UINT32(dmacr, PL011State),
354 VMSTATE_UINT32(int_enabled, PL011State),
355 VMSTATE_UINT32(int_level, PL011State),
356 VMSTATE_UINT32_ARRAY(read_fifo, PL011State, 16),
357 VMSTATE_UINT32(ilpr, PL011State),
358 VMSTATE_UINT32(ibrd, PL011State),
359 VMSTATE_UINT32(fbrd, PL011State),
360 VMSTATE_UINT32(ifl, PL011State),
361 VMSTATE_INT32(read_pos, PL011State),
362 VMSTATE_INT32(read_count, PL011State),
363 VMSTATE_INT32(read_trigger, PL011State),
364 VMSTATE_END_OF_LIST()
366 .subsections = (const VMStateDescription * []) {
367 &vmstate_pl011_clock,
368 NULL
372 static Property pl011_properties[] = {
373 DEFINE_PROP_CHR("chardev", PL011State, chr),
374 DEFINE_PROP_BOOL("migrate-clk", PL011State, migrate_clk, true),
375 DEFINE_PROP_END_OF_LIST(),
378 static void pl011_init(Object *obj)
380 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
381 PL011State *s = PL011(obj);
382 int i;
384 memory_region_init_io(&s->iomem, OBJECT(s), &pl011_ops, s, "pl011", 0x1000);
385 sysbus_init_mmio(sbd, &s->iomem);
386 for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
387 sysbus_init_irq(sbd, &s->irq[i]);
390 s->clk = qdev_init_clock_in(DEVICE(obj), "clk", pl011_clock_update, s,
391 ClockUpdate);
393 s->read_trigger = 1;
394 s->ifl = 0x12;
395 s->cr = 0x300;
396 s->flags = 0x90;
398 s->id = pl011_id_arm;
401 static void pl011_realize(DeviceState *dev, Error **errp)
403 PL011State *s = PL011(dev);
405 qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive,
406 pl011_event, NULL, s, NULL, true);
409 static void pl011_class_init(ObjectClass *oc, void *data)
411 DeviceClass *dc = DEVICE_CLASS(oc);
413 dc->realize = pl011_realize;
414 dc->vmsd = &vmstate_pl011;
415 device_class_set_props(dc, pl011_properties);
418 static const TypeInfo pl011_arm_info = {
419 .name = TYPE_PL011,
420 .parent = TYPE_SYS_BUS_DEVICE,
421 .instance_size = sizeof(PL011State),
422 .instance_init = pl011_init,
423 .class_init = pl011_class_init,
426 static void pl011_luminary_init(Object *obj)
428 PL011State *s = PL011(obj);
430 s->id = pl011_id_luminary;
433 static const TypeInfo pl011_luminary_info = {
434 .name = TYPE_PL011_LUMINARY,
435 .parent = TYPE_PL011,
436 .instance_init = pl011_luminary_init,
439 static void pl011_register_types(void)
441 type_register_static(&pl011_arm_info);
442 type_register_static(&pl011_luminary_info);
445 type_init(pl011_register_types)