2 * Arm PrimeCell PL011 UART
4 * Copyright (c) 2006 CodeSourcery.
5 * Written by Paul Brook
7 * This code is licensed under the GPL.
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"
24 #include "hw/sysbus.h"
25 #include "migration/vmstate.h"
26 #include "chardev/char-fe.h"
28 #include "qemu/module.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 */
69 static void pl011_update(PL011State
*s
)
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
,
84 PL011State
*s
= (PL011State
*)opaque
;
88 switch (offset
>> 2) {
90 s
->flags
&= ~PL011_FLAG_RXFF
;
91 c
= s
->read_fifo
[s
->read_pos
];
92 if (s
->read_count
> 0) {
94 if (++s
->read_pos
== 16)
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
);
105 qemu_chr_fe_accept_input(&s
->chr
);
108 case 1: /* UARTRSR */
114 case 8: /* UARTILPR */
117 case 9: /* UARTIBRD */
120 case 10: /* UARTFBRD */
123 case 11: /* UARTLCR_H */
126 case 12: /* UARTCR */
129 case 13: /* UARTIFLS */
132 case 14: /* UARTIMSC */
135 case 15: /* UARTRIS */
138 case 16: /* UARTMIS */
139 r
= s
->int_level
& s
->int_enabled
;
141 case 18: /* UARTDMACR */
144 case 0x3f8 ... 0x400:
145 r
= s
->id
[(offset
- 0xfe0) >> 2];
148 qemu_log_mask(LOG_GUEST_ERROR
,
149 "pl011_read: Bad offset 0x%x\n", (int)offset
);
154 trace_pl011_read(offset
, r
);
158 static void pl011_set_read_trigger(PL011State
*s
)
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. */
166 s
->read_trigger
= (s
->ifl
>> 1) & 0x1c;
172 static void pl011_write(void *opaque
, hwaddr offset
,
173 uint64_t value
, unsigned size
)
175 PL011State
*s
= (PL011State
*)opaque
;
178 trace_pl011_write(offset
, value
);
180 switch (offset
>> 2) {
182 /* ??? Check if transmitter is enabled. */
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
;
190 case 1: /* UARTRSR/UARTECR */
194 /* Writes to Flag register are ignored. */
196 case 8: /* UARTUARTILPR */
199 case 9: /* UARTIBRD */
202 case 10: /* UARTFBRD */
205 case 11: /* UARTLCR_H */
206 /* Reset the FIFO state on FIFO enable or disable */
207 if ((s
->lcr
^ value
) & 0x10) {
212 pl011_set_read_trigger(s
);
214 case 12: /* UARTCR */
215 /* ??? Need to implement the enable and loopback bits. */
218 case 13: /* UARTIFS */
220 pl011_set_read_trigger(s
);
222 case 14: /* UARTIMSC */
223 s
->int_enabled
= value
;
226 case 17: /* UARTICR */
227 s
->int_level
&= ~value
;
230 case 18: /* UARTDMACR */
233 qemu_log_mask(LOG_UNIMP
, "pl011: DMA not implemented\n");
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
;
248 r
= s
->read_count
< 16;
250 r
= s
->read_count
< 1;
252 trace_pl011_can_receive(s
->lcr
, s
->read_count
, r
);
256 static void pl011_put_fifo(void *opaque
, uint32_t value
)
258 PL011State
*s
= (PL011State
*)opaque
;
261 slot
= s
->read_pos
+ s
->read_count
;
264 s
->read_fifo
[slot
] = value
;
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
;
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
= {
291 .write
= pl011_write
,
292 .endianness
= DEVICE_NATIVE_ENDIAN
,
295 static const VMStateDescription vmstate_pl011
= {
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
);
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
]);
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
= {
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
)