]> git.proxmox.com Git - mirror_qemu.git/blob - hw/char/pl011.c
hw/arm/virt: Disable pl011 clock migration if needed
[mirror_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 /*
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)
19 */
20
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"
32
33 #define PL011_INT_TX 0x20
34 #define PL011_INT_RX 0x10
35
36 #define PL011_FLAG_TXFE 0x80
37 #define PL011_FLAG_RXFF 0x40
38 #define PL011_FLAG_TXFF 0x20
39 #define PL011_FLAG_RXFE 0x10
40
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)
55
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 };
60
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,
69 };
70
71 static void pl011_update(PL011State *s)
72 {
73 uint32_t flags;
74 int i;
75
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);
80 }
81 }
82
83 static uint64_t pl011_read(void *opaque, hwaddr offset,
84 unsigned size)
85 {
86 PL011State *s = (PL011State *)opaque;
87 uint32_t c;
88 uint64_t r;
89
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;
98 }
99 if (s->read_count == 0) {
100 s->flags |= PL011_FLAG_RXFE;
101 }
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;
154 }
155
156 trace_pl011_read(offset, r);
157 return r;
158 }
159
160 static void pl011_set_read_trigger(PL011State *s)
161 {
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;
172 }
173
174 static unsigned int pl011_get_baudrate(const PL011State *s)
175 {
176 uint64_t clk;
177
178 if (s->fbrd == 0) {
179 return 0;
180 }
181
182 clk = clock_get_hz(s->clk);
183 return (clk / ((s->ibrd << 6) + s->fbrd)) << 2;
184 }
185
186 static void pl011_trace_baudrate_change(const PL011State *s)
187 {
188 trace_pl011_baudrate_change(pl011_get_baudrate(s),
189 clock_get_hz(s->clk),
190 s->ibrd, s->fbrd);
191 }
192
193 static void pl011_write(void *opaque, hwaddr offset,
194 uint64_t value, unsigned size)
195 {
196 PL011State *s = (PL011State *)opaque;
197 unsigned char ch;
198
199 trace_pl011_write(offset, value);
200
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;
233 }
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");
257 }
258 break;
259 default:
260 qemu_log_mask(LOG_GUEST_ERROR,
261 "pl011_write: Bad offset 0x%x\n", (int)offset);
262 }
263 }
264
265 static int pl011_can_receive(void *opaque)
266 {
267 PL011State *s = (PL011State *)opaque;
268 int r;
269
270 if (s->lcr & 0x10) {
271 r = s->read_count < 16;
272 } else {
273 r = s->read_count < 1;
274 }
275 trace_pl011_can_receive(s->lcr, s->read_count, r);
276 return r;
277 }
278
279 static void pl011_put_fifo(void *opaque, uint32_t value)
280 {
281 PL011State *s = (PL011State *)opaque;
282 int slot;
283
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;
294 }
295 if (s->read_count == s->read_trigger) {
296 s->int_level |= PL011_INT_RX;
297 pl011_update(s);
298 }
299 }
300
301 static void pl011_receive(void *opaque, const uint8_t *buf, int size)
302 {
303 pl011_put_fifo(opaque, *buf);
304 }
305
306 static void pl011_event(void *opaque, QEMUChrEvent event)
307 {
308 if (event == CHR_EVENT_BREAK)
309 pl011_put_fifo(opaque, 0x400);
310 }
311
312 static void pl011_clock_update(void *opaque, ClockEvent event)
313 {
314 PL011State *s = PL011(opaque);
315
316 pl011_trace_baudrate_change(s);
317 }
318
319 static const MemoryRegionOps pl011_ops = {
320 .read = pl011_read,
321 .write = pl011_write,
322 .endianness = DEVICE_NATIVE_ENDIAN,
323 };
324
325 static bool pl011_clock_needed(void *opaque)
326 {
327 PL011State *s = PL011(opaque);
328
329 return s->migrate_clk;
330 }
331
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()
340 }
341 };
342
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()
365 },
366 .subsections = (const VMStateDescription * []) {
367 &vmstate_pl011_clock,
368 NULL
369 }
370 };
371
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(),
376 };
377
378 static void pl011_init(Object *obj)
379 {
380 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
381 PL011State *s = PL011(obj);
382 int i;
383
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]);
388 }
389
390 s->clk = qdev_init_clock_in(DEVICE(obj), "clk", pl011_clock_update, s,
391 ClockUpdate);
392
393 s->read_trigger = 1;
394 s->ifl = 0x12;
395 s->cr = 0x300;
396 s->flags = 0x90;
397
398 s->id = pl011_id_arm;
399 }
400
401 static void pl011_realize(DeviceState *dev, Error **errp)
402 {
403 PL011State *s = PL011(dev);
404
405 qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive,
406 pl011_event, NULL, s, NULL, true);
407 }
408
409 static void pl011_class_init(ObjectClass *oc, void *data)
410 {
411 DeviceClass *dc = DEVICE_CLASS(oc);
412
413 dc->realize = pl011_realize;
414 dc->vmsd = &vmstate_pl011;
415 device_class_set_props(dc, pl011_properties);
416 }
417
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,
424 };
425
426 static void pl011_luminary_init(Object *obj)
427 {
428 PL011State *s = PL011(obj);
429
430 s->id = pl011_id_luminary;
431 }
432
433 static const TypeInfo pl011_luminary_info = {
434 .name = TYPE_PL011_LUMINARY,
435 .parent = TYPE_PL011,
436 .instance_init = pl011_luminary_init,
437 };
438
439 static void pl011_register_types(void)
440 {
441 type_register_static(&pl011_arm_info);
442 type_register_static(&pl011_luminary_info);
443 }
444
445 type_init(pl011_register_types)