block/block-copy: reduce intersecting request lock
[qemu/kevin.git] / hw / char / pl011.c
blob13e784f9d90b5fd55057ff95046aee116aff36ca
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 "migration/vmstate.h"
26 #include "chardev/char-fe.h"
27 #include "qemu/log.h"
28 #include "qemu/module.h"
29 #include "trace.h"
31 #define PL011_INT_TX 0x20
32 #define PL011_INT_RX 0x10
34 #define PL011_FLAG_TXFE 0x80
35 #define PL011_FLAG_RXFF 0x40
36 #define PL011_FLAG_TXFF 0x20
37 #define PL011_FLAG_RXFE 0x10
39 /* Interrupt status bits in UARTRIS, UARTMIS, UARTIMSC */
40 #define INT_OE (1 << 10)
41 #define INT_BE (1 << 9)
42 #define INT_PE (1 << 8)
43 #define INT_FE (1 << 7)
44 #define INT_RT (1 << 6)
45 #define INT_TX (1 << 5)
46 #define INT_RX (1 << 4)
47 #define INT_DSR (1 << 3)
48 #define INT_DCD (1 << 2)
49 #define INT_CTS (1 << 1)
50 #define INT_RI (1 << 0)
51 #define INT_E (INT_OE | INT_BE | INT_PE | INT_FE)
52 #define INT_MS (INT_RI | INT_DSR | INT_DCD | INT_CTS)
54 static const unsigned char pl011_id_arm[8] =
55 { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
56 static const unsigned char pl011_id_luminary[8] =
57 { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
59 /* Which bits in the interrupt status matter for each outbound IRQ line ? */
60 static const uint32_t irqmask[] = {
61 INT_E | INT_MS | INT_RT | INT_TX | INT_RX, /* combined IRQ */
62 INT_RX,
63 INT_TX,
64 INT_RT,
65 INT_MS,
66 INT_E,
69 static void pl011_update(PL011State *s)
71 uint32_t flags;
72 int i;
74 flags = s->int_level & s->int_enabled;
75 trace_pl011_irq_state(flags != 0);
76 for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
77 qemu_set_irq(s->irq[i], (flags & irqmask[i]) != 0);
81 static uint64_t pl011_read(void *opaque, hwaddr offset,
82 unsigned size)
84 PL011State *s = (PL011State *)opaque;
85 uint32_t c;
86 uint64_t r;
88 switch (offset >> 2) {
89 case 0: /* UARTDR */
90 s->flags &= ~PL011_FLAG_RXFF;
91 c = s->read_fifo[s->read_pos];
92 if (s->read_count > 0) {
93 s->read_count--;
94 if (++s->read_pos == 16)
95 s->read_pos = 0;
97 if (s->read_count == 0) {
98 s->flags |= PL011_FLAG_RXFE;
100 if (s->read_count == s->read_trigger - 1)
101 s->int_level &= ~ PL011_INT_RX;
102 trace_pl011_read_fifo(s->read_count);
103 s->rsr = c >> 8;
104 pl011_update(s);
105 qemu_chr_fe_accept_input(&s->chr);
106 r = c;
107 break;
108 case 1: /* UARTRSR */
109 r = s->rsr;
110 break;
111 case 6: /* UARTFR */
112 r = s->flags;
113 break;
114 case 8: /* UARTILPR */
115 r = s->ilpr;
116 break;
117 case 9: /* UARTIBRD */
118 r = s->ibrd;
119 break;
120 case 10: /* UARTFBRD */
121 r = s->fbrd;
122 break;
123 case 11: /* UARTLCR_H */
124 r = s->lcr;
125 break;
126 case 12: /* UARTCR */
127 r = s->cr;
128 break;
129 case 13: /* UARTIFLS */
130 r = s->ifl;
131 break;
132 case 14: /* UARTIMSC */
133 r = s->int_enabled;
134 break;
135 case 15: /* UARTRIS */
136 r = s->int_level;
137 break;
138 case 16: /* UARTMIS */
139 r = s->int_level & s->int_enabled;
140 break;
141 case 18: /* UARTDMACR */
142 r = s->dmacr;
143 break;
144 case 0x3f8 ... 0x400:
145 r = s->id[(offset - 0xfe0) >> 2];
146 break;
147 default:
148 qemu_log_mask(LOG_GUEST_ERROR,
149 "pl011_read: Bad offset 0x%x\n", (int)offset);
150 r = 0;
151 break;
154 trace_pl011_read(offset, r);
155 return r;
158 static void pl011_set_read_trigger(PL011State *s)
160 #if 0
161 /* The docs say the RX interrupt is triggered when the FIFO exceeds
162 the threshold. However linux only reads the FIFO in response to an
163 interrupt. Triggering the interrupt when the FIFO is non-empty seems
164 to make things work. */
165 if (s->lcr & 0x10)
166 s->read_trigger = (s->ifl >> 1) & 0x1c;
167 else
168 #endif
169 s->read_trigger = 1;
172 static void pl011_write(void *opaque, hwaddr offset,
173 uint64_t value, unsigned size)
175 PL011State *s = (PL011State *)opaque;
176 unsigned char ch;
178 trace_pl011_write(offset, value);
180 switch (offset >> 2) {
181 case 0: /* UARTDR */
182 /* ??? Check if transmitter is enabled. */
183 ch = value;
184 /* XXX this blocks entire thread. Rewrite to use
185 * qemu_chr_fe_write and background I/O callbacks */
186 qemu_chr_fe_write_all(&s->chr, &ch, 1);
187 s->int_level |= PL011_INT_TX;
188 pl011_update(s);
189 break;
190 case 1: /* UARTRSR/UARTECR */
191 s->rsr = 0;
192 break;
193 case 6: /* UARTFR */
194 /* Writes to Flag register are ignored. */
195 break;
196 case 8: /* UARTUARTILPR */
197 s->ilpr = value;
198 break;
199 case 9: /* UARTIBRD */
200 s->ibrd = value;
201 break;
202 case 10: /* UARTFBRD */
203 s->fbrd = value;
204 break;
205 case 11: /* UARTLCR_H */
206 /* Reset the FIFO state on FIFO enable or disable */
207 if ((s->lcr ^ value) & 0x10) {
208 s->read_count = 0;
209 s->read_pos = 0;
211 s->lcr = value;
212 pl011_set_read_trigger(s);
213 break;
214 case 12: /* UARTCR */
215 /* ??? Need to implement the enable and loopback bits. */
216 s->cr = value;
217 break;
218 case 13: /* UARTIFS */
219 s->ifl = value;
220 pl011_set_read_trigger(s);
221 break;
222 case 14: /* UARTIMSC */
223 s->int_enabled = value;
224 pl011_update(s);
225 break;
226 case 17: /* UARTICR */
227 s->int_level &= ~value;
228 pl011_update(s);
229 break;
230 case 18: /* UARTDMACR */
231 s->dmacr = value;
232 if (value & 3) {
233 qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n");
235 break;
236 default:
237 qemu_log_mask(LOG_GUEST_ERROR,
238 "pl011_write: Bad offset 0x%x\n", (int)offset);
242 static int pl011_can_receive(void *opaque)
244 PL011State *s = (PL011State *)opaque;
245 int r;
247 if (s->lcr & 0x10) {
248 r = s->read_count < 16;
249 } else {
250 r = s->read_count < 1;
252 trace_pl011_can_receive(s->lcr, s->read_count, r);
253 return r;
256 static void pl011_put_fifo(void *opaque, uint32_t value)
258 PL011State *s = (PL011State *)opaque;
259 int slot;
261 slot = s->read_pos + s->read_count;
262 if (slot >= 16)
263 slot -= 16;
264 s->read_fifo[slot] = value;
265 s->read_count++;
266 s->flags &= ~PL011_FLAG_RXFE;
267 trace_pl011_put_fifo(value, s->read_count);
268 if (!(s->lcr & 0x10) || s->read_count == 16) {
269 trace_pl011_put_fifo_full();
270 s->flags |= PL011_FLAG_RXFF;
272 if (s->read_count == s->read_trigger) {
273 s->int_level |= PL011_INT_RX;
274 pl011_update(s);
278 static void pl011_receive(void *opaque, const uint8_t *buf, int size)
280 pl011_put_fifo(opaque, *buf);
283 static void pl011_event(void *opaque, QEMUChrEvent event)
285 if (event == CHR_EVENT_BREAK)
286 pl011_put_fifo(opaque, 0x400);
289 static const MemoryRegionOps pl011_ops = {
290 .read = pl011_read,
291 .write = pl011_write,
292 .endianness = DEVICE_NATIVE_ENDIAN,
295 static const VMStateDescription vmstate_pl011 = {
296 .name = "pl011",
297 .version_id = 2,
298 .minimum_version_id = 2,
299 .fields = (VMStateField[]) {
300 VMSTATE_UINT32(readbuff, PL011State),
301 VMSTATE_UINT32(flags, PL011State),
302 VMSTATE_UINT32(lcr, PL011State),
303 VMSTATE_UINT32(rsr, PL011State),
304 VMSTATE_UINT32(cr, PL011State),
305 VMSTATE_UINT32(dmacr, PL011State),
306 VMSTATE_UINT32(int_enabled, PL011State),
307 VMSTATE_UINT32(int_level, PL011State),
308 VMSTATE_UINT32_ARRAY(read_fifo, PL011State, 16),
309 VMSTATE_UINT32(ilpr, PL011State),
310 VMSTATE_UINT32(ibrd, PL011State),
311 VMSTATE_UINT32(fbrd, PL011State),
312 VMSTATE_UINT32(ifl, PL011State),
313 VMSTATE_INT32(read_pos, PL011State),
314 VMSTATE_INT32(read_count, PL011State),
315 VMSTATE_INT32(read_trigger, PL011State),
316 VMSTATE_END_OF_LIST()
320 static Property pl011_properties[] = {
321 DEFINE_PROP_CHR("chardev", PL011State, chr),
322 DEFINE_PROP_END_OF_LIST(),
325 static void pl011_init(Object *obj)
327 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
328 PL011State *s = PL011(obj);
329 int i;
331 memory_region_init_io(&s->iomem, OBJECT(s), &pl011_ops, s, "pl011", 0x1000);
332 sysbus_init_mmio(sbd, &s->iomem);
333 for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
334 sysbus_init_irq(sbd, &s->irq[i]);
337 s->read_trigger = 1;
338 s->ifl = 0x12;
339 s->cr = 0x300;
340 s->flags = 0x90;
342 s->id = pl011_id_arm;
345 static void pl011_realize(DeviceState *dev, Error **errp)
347 PL011State *s = PL011(dev);
349 qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive,
350 pl011_event, NULL, s, NULL, true);
353 static void pl011_class_init(ObjectClass *oc, void *data)
355 DeviceClass *dc = DEVICE_CLASS(oc);
357 dc->realize = pl011_realize;
358 dc->vmsd = &vmstate_pl011;
359 device_class_set_props(dc, pl011_properties);
362 static const TypeInfo pl011_arm_info = {
363 .name = TYPE_PL011,
364 .parent = TYPE_SYS_BUS_DEVICE,
365 .instance_size = sizeof(PL011State),
366 .instance_init = pl011_init,
367 .class_init = pl011_class_init,
370 static void pl011_luminary_init(Object *obj)
372 PL011State *s = PL011(obj);
374 s->id = pl011_id_luminary;
377 static const TypeInfo pl011_luminary_info = {
378 .name = TYPE_PL011_LUMINARY,
379 .parent = TYPE_PL011,
380 .instance_init = pl011_luminary_init,
383 static void pl011_register_types(void)
385 type_register_static(&pl011_arm_info);
386 type_register_static(&pl011_luminary_info);
389 type_init(pl011_register_types)