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 "hw/qdev-clock.h"
26 #include "hw/qdev-properties-system.h"
27 #include "migration/vmstate.h"
28 #include "chardev/char-fe.h"
30 #include "qemu/module.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 */
71 static void pl011_update(PL011State
*s
)
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
,
86 PL011State
*s
= (PL011State
*)opaque
;
90 switch (offset
>> 2) {
92 s
->flags
&= ~PL011_FLAG_RXFF
;
93 c
= s
->read_fifo
[s
->read_pos
];
94 if (s
->read_count
> 0) {
96 if (++s
->read_pos
== 16)
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
);
107 qemu_chr_fe_accept_input(&s
->chr
);
110 case 1: /* UARTRSR */
116 case 8: /* UARTILPR */
119 case 9: /* UARTIBRD */
122 case 10: /* UARTFBRD */
125 case 11: /* UARTLCR_H */
128 case 12: /* UARTCR */
131 case 13: /* UARTIFLS */
134 case 14: /* UARTIMSC */
137 case 15: /* UARTRIS */
140 case 16: /* UARTMIS */
141 r
= s
->int_level
& s
->int_enabled
;
143 case 18: /* UARTDMACR */
146 case 0x3f8 ... 0x400:
147 r
= s
->id
[(offset
- 0xfe0) >> 2];
150 qemu_log_mask(LOG_GUEST_ERROR
,
151 "pl011_read: Bad offset 0x%x\n", (int)offset
);
156 trace_pl011_read(offset
, r
);
160 static void pl011_set_read_trigger(PL011State
*s
)
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. */
168 s
->read_trigger
= (s
->ifl
>> 1) & 0x1c;
174 static unsigned int pl011_get_baudrate(const PL011State
*s
)
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
),
193 static void pl011_write(void *opaque
, hwaddr offset
,
194 uint64_t value
, unsigned size
)
196 PL011State
*s
= (PL011State
*)opaque
;
199 trace_pl011_write(offset
, value
);
201 switch (offset
>> 2) {
203 /* ??? Check if transmitter is enabled. */
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
;
211 case 1: /* UARTRSR/UARTECR */
215 /* Writes to Flag register are ignored. */
217 case 8: /* UARTUARTILPR */
220 case 9: /* UARTIBRD */
222 pl011_trace_baudrate_change(s
);
224 case 10: /* UARTFBRD */
226 pl011_trace_baudrate_change(s
);
228 case 11: /* UARTLCR_H */
229 /* Reset the FIFO state on FIFO enable or disable */
230 if ((s
->lcr
^ value
) & 0x10) {
235 pl011_set_read_trigger(s
);
237 case 12: /* UARTCR */
238 /* ??? Need to implement the enable and loopback bits. */
241 case 13: /* UARTIFS */
243 pl011_set_read_trigger(s
);
245 case 14: /* UARTIMSC */
246 s
->int_enabled
= value
;
249 case 17: /* UARTICR */
250 s
->int_level
&= ~value
;
253 case 18: /* UARTDMACR */
256 qemu_log_mask(LOG_UNIMP
, "pl011: DMA not implemented\n");
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
;
271 r
= s
->read_count
< 16;
273 r
= s
->read_count
< 1;
275 trace_pl011_can_receive(s
->lcr
, s
->read_count
, r
);
279 static void pl011_put_fifo(void *opaque
, uint32_t value
)
281 PL011State
*s
= (PL011State
*)opaque
;
284 slot
= s
->read_pos
+ s
->read_count
;
287 s
->read_fifo
[slot
] = value
;
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
;
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
= {
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",
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
= {
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
,
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
);
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
,
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
= {
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
)