]> git.proxmox.com Git - mirror_qemu.git/blame - hw/char/pl011.c
hw/char/pl011: add a clock input
[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
a3c1ca56
PM
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
8ef94f0b 21#include "qemu/osdep.h"
694cf209 22#include "hw/char/pl011.h"
64552b6b 23#include "hw/irq.h"
83c9f4ca 24#include "hw/sysbus.h"
aac63e0e 25#include "hw/qdev-clock.h"
d6454270 26#include "migration/vmstate.h"
4d43a603 27#include "chardev/char-fe.h"
03dd024f 28#include "qemu/log.h"
0b8fa32f 29#include "qemu/module.h"
041ac056 30#include "trace.h"
cdbdb648 31
cdbdb648
PB
32#define PL011_INT_TX 0x20
33#define PL011_INT_RX 0x10
34
35#define PL011_FLAG_TXFE 0x80
36#define PL011_FLAG_RXFF 0x40
37#define PL011_FLAG_TXFF 0x20
38#define PL011_FLAG_RXFE 0x10
39
a3c1ca56
PM
40/* Interrupt status bits in UARTRIS, UARTMIS, UARTIMSC */
41#define INT_OE (1 << 10)
42#define INT_BE (1 << 9)
43#define INT_PE (1 << 8)
44#define INT_FE (1 << 7)
45#define INT_RT (1 << 6)
46#define INT_TX (1 << 5)
47#define INT_RX (1 << 4)
48#define INT_DSR (1 << 3)
49#define INT_DCD (1 << 2)
50#define INT_CTS (1 << 1)
51#define INT_RI (1 << 0)
52#define INT_E (INT_OE | INT_BE | INT_PE | INT_FE)
53#define INT_MS (INT_RI | INT_DSR | INT_DCD | INT_CTS)
54
a7d518a6
PB
55static const unsigned char pl011_id_arm[8] =
56 { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
57static const unsigned char pl011_id_luminary[8] =
58 { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
cdbdb648 59
a3c1ca56
PM
60/* Which bits in the interrupt status matter for each outbound IRQ line ? */
61static const uint32_t irqmask[] = {
62 INT_E | INT_MS | INT_RT | INT_TX | INT_RX, /* combined IRQ */
63 INT_RX,
64 INT_TX,
65 INT_RT,
66 INT_MS,
67 INT_E,
68};
69
ab640bfc 70static void pl011_update(PL011State *s)
cdbdb648
PB
71{
72 uint32_t flags;
a3c1ca56 73 int i;
3b46e624 74
cdbdb648 75 flags = s->int_level & s->int_enabled;
041ac056 76 trace_pl011_irq_state(flags != 0);
a3c1ca56
PM
77 for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
78 qemu_set_irq(s->irq[i], (flags & irqmask[i]) != 0);
79 }
cdbdb648
PB
80}
81
a8170e5e 82static uint64_t pl011_read(void *opaque, hwaddr offset,
48484757 83 unsigned size)
cdbdb648 84{
ab640bfc 85 PL011State *s = (PL011State *)opaque;
cdbdb648 86 uint32_t c;
041ac056 87 uint64_t r;
cdbdb648 88
cdbdb648
PB
89 switch (offset >> 2) {
90 case 0: /* UARTDR */
91 s->flags &= ~PL011_FLAG_RXFF;
92 c = s->read_fifo[s->read_pos];
93 if (s->read_count > 0) {
94 s->read_count--;
95 if (++s->read_pos == 16)
96 s->read_pos = 0;
97 }
98 if (s->read_count == 0) {
99 s->flags |= PL011_FLAG_RXFE;
100 }
101 if (s->read_count == s->read_trigger - 1)
102 s->int_level &= ~ PL011_INT_RX;
041ac056 103 trace_pl011_read_fifo(s->read_count);
ce8f0905 104 s->rsr = c >> 8;
cdbdb648 105 pl011_update(s);
fa394ed6 106 qemu_chr_fe_accept_input(&s->chr);
041ac056
PM
107 r = c;
108 break;
ce8f0905 109 case 1: /* UARTRSR */
041ac056
PM
110 r = s->rsr;
111 break;
cdbdb648 112 case 6: /* UARTFR */
041ac056
PM
113 r = s->flags;
114 break;
cdbdb648 115 case 8: /* UARTILPR */
041ac056
PM
116 r = s->ilpr;
117 break;
cdbdb648 118 case 9: /* UARTIBRD */
041ac056
PM
119 r = s->ibrd;
120 break;
cdbdb648 121 case 10: /* UARTFBRD */
041ac056
PM
122 r = s->fbrd;
123 break;
cdbdb648 124 case 11: /* UARTLCR_H */
041ac056
PM
125 r = s->lcr;
126 break;
cdbdb648 127 case 12: /* UARTCR */
041ac056
PM
128 r = s->cr;
129 break;
cdbdb648 130 case 13: /* UARTIFLS */
041ac056
PM
131 r = s->ifl;
132 break;
cdbdb648 133 case 14: /* UARTIMSC */
041ac056
PM
134 r = s->int_enabled;
135 break;
cdbdb648 136 case 15: /* UARTRIS */
041ac056
PM
137 r = s->int_level;
138 break;
cdbdb648 139 case 16: /* UARTMIS */
041ac056
PM
140 r = s->int_level & s->int_enabled;
141 break;
cdbdb648 142 case 18: /* UARTDMACR */
041ac056
PM
143 r = s->dmacr;
144 break;
145 case 0x3f8 ... 0x400:
146 r = s->id[(offset - 0xfe0) >> 2];
147 break;
cdbdb648 148 default:
6d5433e0 149 qemu_log_mask(LOG_GUEST_ERROR,
76b09faf 150 "pl011_read: Bad offset 0x%x\n", (int)offset);
041ac056
PM
151 r = 0;
152 break;
cdbdb648 153 }
041ac056
PM
154
155 trace_pl011_read(offset, r);
156 return r;
cdbdb648
PB
157}
158
ab640bfc 159static void pl011_set_read_trigger(PL011State *s)
cdbdb648
PB
160{
161#if 0
162 /* The docs say the RX interrupt is triggered when the FIFO exceeds
163 the threshold. However linux only reads the FIFO in response to an
164 interrupt. Triggering the interrupt when the FIFO is non-empty seems
165 to make things work. */
166 if (s->lcr & 0x10)
167 s->read_trigger = (s->ifl >> 1) & 0x1c;
168 else
169#endif
170 s->read_trigger = 1;
171}
172
aac63e0e
LM
173static unsigned int pl011_get_baudrate(const PL011State *s)
174{
175 uint64_t clk;
176
177 if (s->fbrd == 0) {
178 return 0;
179 }
180
181 clk = clock_get_hz(s->clk);
182 return (clk / ((s->ibrd << 6) + s->fbrd)) << 2;
183}
184
185static void pl011_trace_baudrate_change(const PL011State *s)
186{
187 trace_pl011_baudrate_change(pl011_get_baudrate(s),
188 clock_get_hz(s->clk),
189 s->ibrd, s->fbrd);
190}
191
a8170e5e 192static void pl011_write(void *opaque, hwaddr offset,
48484757 193 uint64_t value, unsigned size)
cdbdb648 194{
ab640bfc 195 PL011State *s = (PL011State *)opaque;
cdbdb648
PB
196 unsigned char ch;
197
041ac056
PM
198 trace_pl011_write(offset, value);
199
cdbdb648
PB
200 switch (offset >> 2) {
201 case 0: /* UARTDR */
202 /* ??? Check if transmitter is enabled. */
203 ch = value;
fa394ed6
MAL
204 /* XXX this blocks entire thread. Rewrite to use
205 * qemu_chr_fe_write and background I/O callbacks */
206 qemu_chr_fe_write_all(&s->chr, &ch, 1);
cdbdb648
PB
207 s->int_level |= PL011_INT_TX;
208 pl011_update(s);
209 break;
ce8f0905
RH
210 case 1: /* UARTRSR/UARTECR */
211 s->rsr = 0;
cdbdb648 212 break;
9ee6e8bb
PB
213 case 6: /* UARTFR */
214 /* Writes to Flag register are ignored. */
215 break;
cdbdb648
PB
216 case 8: /* UARTUARTILPR */
217 s->ilpr = value;
218 break;
219 case 9: /* UARTIBRD */
220 s->ibrd = value;
aac63e0e 221 pl011_trace_baudrate_change(s);
cdbdb648
PB
222 break;
223 case 10: /* UARTFBRD */
224 s->fbrd = value;
aac63e0e 225 pl011_trace_baudrate_change(s);
cdbdb648
PB
226 break;
227 case 11: /* UARTLCR_H */
22709e90
RH
228 /* Reset the FIFO state on FIFO enable or disable */
229 if ((s->lcr ^ value) & 0x10) {
230 s->read_count = 0;
231 s->read_pos = 0;
232 }
cdbdb648
PB
233 s->lcr = value;
234 pl011_set_read_trigger(s);
235 break;
236 case 12: /* UARTCR */
237 /* ??? Need to implement the enable and loopback bits. */
238 s->cr = value;
239 break;
240 case 13: /* UARTIFS */
241 s->ifl = value;
242 pl011_set_read_trigger(s);
243 break;
244 case 14: /* UARTIMSC */
245 s->int_enabled = value;
246 pl011_update(s);
247 break;
248 case 17: /* UARTICR */
249 s->int_level &= ~value;
250 pl011_update(s);
251 break;
252 case 18: /* UARTDMACR */
253 s->dmacr = value;
6d5433e0
PM
254 if (value & 3) {
255 qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n");
256 }
cdbdb648
PB
257 break;
258 default:
6d5433e0 259 qemu_log_mask(LOG_GUEST_ERROR,
76b09faf 260 "pl011_write: Bad offset 0x%x\n", (int)offset);
cdbdb648
PB
261 }
262}
263
aa1f17c1 264static int pl011_can_receive(void *opaque)
cdbdb648 265{
ab640bfc 266 PL011State *s = (PL011State *)opaque;
041ac056 267 int r;
cdbdb648 268
041ac056
PM
269 if (s->lcr & 0x10) {
270 r = s->read_count < 16;
271 } else {
272 r = s->read_count < 1;
273 }
274 trace_pl011_can_receive(s->lcr, s->read_count, r);
275 return r;
cdbdb648
PB
276}
277
cc9c9ffc 278static void pl011_put_fifo(void *opaque, uint32_t value)
cdbdb648 279{
ab640bfc 280 PL011State *s = (PL011State *)opaque;
cdbdb648
PB
281 int slot;
282
283 slot = s->read_pos + s->read_count;
284 if (slot >= 16)
285 slot -= 16;
cc9c9ffc 286 s->read_fifo[slot] = value;
cdbdb648
PB
287 s->read_count++;
288 s->flags &= ~PL011_FLAG_RXFE;
041ac056 289 trace_pl011_put_fifo(value, s->read_count);
f72dbf3d 290 if (!(s->lcr & 0x10) || s->read_count == 16) {
041ac056 291 trace_pl011_put_fifo_full();
cdbdb648
PB
292 s->flags |= PL011_FLAG_RXFF;
293 }
294 if (s->read_count == s->read_trigger) {
295 s->int_level |= PL011_INT_RX;
296 pl011_update(s);
297 }
298}
299
cc9c9ffc
AJ
300static void pl011_receive(void *opaque, const uint8_t *buf, int size)
301{
302 pl011_put_fifo(opaque, *buf);
303}
304
083b266f 305static void pl011_event(void *opaque, QEMUChrEvent event)
cdbdb648 306{
cc9c9ffc
AJ
307 if (event == CHR_EVENT_BREAK)
308 pl011_put_fifo(opaque, 0x400);
cdbdb648
PB
309}
310
aac63e0e
LM
311static void pl011_clock_update(void *opaque)
312{
313 PL011State *s = PL011(opaque);
314
315 pl011_trace_baudrate_change(s);
316}
317
48484757
AK
318static const MemoryRegionOps pl011_ops = {
319 .read = pl011_read,
320 .write = pl011_write,
321 .endianness = DEVICE_NATIVE_ENDIAN,
cdbdb648
PB
322};
323
aac63e0e
LM
324static const VMStateDescription vmstate_pl011_clock = {
325 .name = "pl011/clock",
326 .version_id = 1,
327 .minimum_version_id = 1,
328 .fields = (VMStateField[]) {
329 VMSTATE_CLOCK(clk, PL011State),
330 VMSTATE_END_OF_LIST()
331 }
332};
333
02b68757
JQ
334static const VMStateDescription vmstate_pl011 = {
335 .name = "pl011",
ce8f0905
RH
336 .version_id = 2,
337 .minimum_version_id = 2,
8f1e884b 338 .fields = (VMStateField[]) {
ab640bfc
AF
339 VMSTATE_UINT32(readbuff, PL011State),
340 VMSTATE_UINT32(flags, PL011State),
341 VMSTATE_UINT32(lcr, PL011State),
ce8f0905 342 VMSTATE_UINT32(rsr, PL011State),
ab640bfc
AF
343 VMSTATE_UINT32(cr, PL011State),
344 VMSTATE_UINT32(dmacr, PL011State),
345 VMSTATE_UINT32(int_enabled, PL011State),
346 VMSTATE_UINT32(int_level, PL011State),
347 VMSTATE_UINT32_ARRAY(read_fifo, PL011State, 16),
348 VMSTATE_UINT32(ilpr, PL011State),
349 VMSTATE_UINT32(ibrd, PL011State),
350 VMSTATE_UINT32(fbrd, PL011State),
351 VMSTATE_UINT32(ifl, PL011State),
352 VMSTATE_INT32(read_pos, PL011State),
353 VMSTATE_INT32(read_count, PL011State),
354 VMSTATE_INT32(read_trigger, PL011State),
02b68757 355 VMSTATE_END_OF_LIST()
aac63e0e
LM
356 },
357 .subsections = (const VMStateDescription * []) {
358 &vmstate_pl011_clock,
359 NULL
02b68757
JQ
360 }
361};
23e39294 362
f0d1d2c1
XZ
363static Property pl011_properties[] = {
364 DEFINE_PROP_CHR("chardev", PL011State, chr),
365 DEFINE_PROP_END_OF_LIST(),
366};
367
71ffe1a0 368static void pl011_init(Object *obj)
cdbdb648 369{
71ffe1a0
AF
370 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
371 PL011State *s = PL011(obj);
a3c1ca56 372 int i;
cdbdb648 373
300b1fc6 374 memory_region_init_io(&s->iomem, OBJECT(s), &pl011_ops, s, "pl011", 0x1000);
71ffe1a0 375 sysbus_init_mmio(sbd, &s->iomem);
a3c1ca56
PM
376 for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
377 sysbus_init_irq(sbd, &s->irq[i]);
378 }
a7d518a6 379
aac63e0e
LM
380 s->clk = qdev_init_clock_in(DEVICE(obj), "clk", pl011_clock_update, s);
381
cdbdb648
PB
382 s->read_trigger = 1;
383 s->ifl = 0x12;
384 s->cr = 0x300;
385 s->flags = 0x90;
a7d518a6 386
71ffe1a0 387 s->id = pl011_id_arm;
a7d518a6
PB
388}
389
71ffe1a0 390static void pl011_realize(DeviceState *dev, Error **errp)
a7d518a6 391{
71ffe1a0
AF
392 PL011State *s = PL011(dev);
393
fa394ed6 394 qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive,
81517ba3 395 pl011_event, NULL, s, NULL, true);
a7d518a6
PB
396}
397
71ffe1a0 398static void pl011_class_init(ObjectClass *oc, void *data)
999e12bb 399{
71ffe1a0 400 DeviceClass *dc = DEVICE_CLASS(oc);
999e12bb 401
71ffe1a0
AF
402 dc->realize = pl011_realize;
403 dc->vmsd = &vmstate_pl011;
4f67d30b 404 device_class_set_props(dc, pl011_properties);
999e12bb
AL
405}
406
8c43a6f0 407static const TypeInfo pl011_arm_info = {
71ffe1a0 408 .name = TYPE_PL011,
39bffca2 409 .parent = TYPE_SYS_BUS_DEVICE,
ab640bfc 410 .instance_size = sizeof(PL011State),
71ffe1a0
AF
411 .instance_init = pl011_init,
412 .class_init = pl011_class_init,
999e12bb
AL
413};
414
71ffe1a0 415static void pl011_luminary_init(Object *obj)
999e12bb 416{
71ffe1a0 417 PL011State *s = PL011(obj);
999e12bb 418
71ffe1a0 419 s->id = pl011_id_luminary;
999e12bb
AL
420}
421
8c43a6f0 422static const TypeInfo pl011_luminary_info = {
694cf209 423 .name = TYPE_PL011_LUMINARY,
71ffe1a0
AF
424 .parent = TYPE_PL011,
425 .instance_init = pl011_luminary_init,
999e12bb
AL
426};
427
83f7d43a 428static void pl011_register_types(void)
a7d518a6 429{
39bffca2
AL
430 type_register_static(&pl011_arm_info);
431 type_register_static(&pl011_luminary_info);
a7d518a6
PB
432}
433
83f7d43a 434type_init(pl011_register_types)