2 * Arm PrimeCell PL011 UART
4 * Copyright (c) 2006 CodeSourcery.
5 * Written by Paul Brook
7 * This code is licensed under the GPL.
11 #include "qemu-char.h"
23 uint32_t read_fifo
[16];
33 const unsigned char *id
;
36 #define PL011_INT_TX 0x20
37 #define PL011_INT_RX 0x10
39 #define PL011_FLAG_TXFE 0x80
40 #define PL011_FLAG_RXFF 0x40
41 #define PL011_FLAG_TXFF 0x20
42 #define PL011_FLAG_RXFE 0x10
44 static const unsigned char pl011_id_arm
[8] =
45 { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
46 static const unsigned char pl011_id_luminary
[8] =
47 { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
49 static void pl011_update(pl011_state
*s
)
53 flags
= s
->int_level
& s
->int_enabled
;
54 qemu_set_irq(s
->irq
, flags
!= 0);
57 static uint64_t pl011_read(void *opaque
, hwaddr offset
,
60 pl011_state
*s
= (pl011_state
*)opaque
;
63 if (offset
>= 0xfe0 && offset
< 0x1000) {
64 return s
->id
[(offset
- 0xfe0) >> 2];
66 switch (offset
>> 2) {
68 s
->flags
&= ~PL011_FLAG_RXFF
;
69 c
= s
->read_fifo
[s
->read_pos
];
70 if (s
->read_count
> 0) {
72 if (++s
->read_pos
== 16)
75 if (s
->read_count
== 0) {
76 s
->flags
|= PL011_FLAG_RXFE
;
78 if (s
->read_count
== s
->read_trigger
- 1)
79 s
->int_level
&= ~ PL011_INT_RX
;
82 qemu_chr_accept_input(s
->chr
);
89 case 8: /* UARTILPR */
91 case 9: /* UARTIBRD */
93 case 10: /* UARTFBRD */
95 case 11: /* UARTLCR_H */
99 case 13: /* UARTIFLS */
101 case 14: /* UARTIMSC */
102 return s
->int_enabled
;
103 case 15: /* UARTRIS */
105 case 16: /* UARTMIS */
106 return s
->int_level
& s
->int_enabled
;
107 case 18: /* UARTDMACR */
110 qemu_log_mask(LOG_GUEST_ERROR
,
111 "pl011_read: Bad offset %x\n", (int)offset
);
116 static void pl011_set_read_trigger(pl011_state
*s
)
119 /* The docs say the RX interrupt is triggered when the FIFO exceeds
120 the threshold. However linux only reads the FIFO in response to an
121 interrupt. Triggering the interrupt when the FIFO is non-empty seems
122 to make things work. */
124 s
->read_trigger
= (s
->ifl
>> 1) & 0x1c;
130 static void pl011_write(void *opaque
, hwaddr offset
,
131 uint64_t value
, unsigned size
)
133 pl011_state
*s
= (pl011_state
*)opaque
;
136 switch (offset
>> 2) {
138 /* ??? Check if transmitter is enabled. */
141 qemu_chr_fe_write(s
->chr
, &ch
, 1);
142 s
->int_level
|= PL011_INT_TX
;
149 /* Writes to Flag register are ignored. */
151 case 8: /* UARTUARTILPR */
154 case 9: /* UARTIBRD */
157 case 10: /* UARTFBRD */
160 case 11: /* UARTLCR_H */
162 pl011_set_read_trigger(s
);
164 case 12: /* UARTCR */
165 /* ??? Need to implement the enable and loopback bits. */
168 case 13: /* UARTIFS */
170 pl011_set_read_trigger(s
);
172 case 14: /* UARTIMSC */
173 s
->int_enabled
= value
;
176 case 17: /* UARTICR */
177 s
->int_level
&= ~value
;
180 case 18: /* UARTDMACR */
183 qemu_log_mask(LOG_UNIMP
, "pl011: DMA not implemented\n");
187 qemu_log_mask(LOG_GUEST_ERROR
,
188 "pl011_write: Bad offset %x\n", (int)offset
);
192 static int pl011_can_receive(void *opaque
)
194 pl011_state
*s
= (pl011_state
*)opaque
;
197 return s
->read_count
< 16;
199 return s
->read_count
< 1;
202 static void pl011_put_fifo(void *opaque
, uint32_t value
)
204 pl011_state
*s
= (pl011_state
*)opaque
;
207 slot
= s
->read_pos
+ s
->read_count
;
210 s
->read_fifo
[slot
] = value
;
212 s
->flags
&= ~PL011_FLAG_RXFE
;
213 if (s
->cr
& 0x10 || s
->read_count
== 16) {
214 s
->flags
|= PL011_FLAG_RXFF
;
216 if (s
->read_count
== s
->read_trigger
) {
217 s
->int_level
|= PL011_INT_RX
;
222 static void pl011_receive(void *opaque
, const uint8_t *buf
, int size
)
224 pl011_put_fifo(opaque
, *buf
);
227 static void pl011_event(void *opaque
, int event
)
229 if (event
== CHR_EVENT_BREAK
)
230 pl011_put_fifo(opaque
, 0x400);
233 static const MemoryRegionOps pl011_ops
= {
235 .write
= pl011_write
,
236 .endianness
= DEVICE_NATIVE_ENDIAN
,
239 static const VMStateDescription vmstate_pl011
= {
242 .minimum_version_id
= 1,
243 .minimum_version_id_old
= 1,
244 .fields
= (VMStateField
[]) {
245 VMSTATE_UINT32(readbuff
, pl011_state
),
246 VMSTATE_UINT32(flags
, pl011_state
),
247 VMSTATE_UINT32(lcr
, pl011_state
),
248 VMSTATE_UINT32(cr
, pl011_state
),
249 VMSTATE_UINT32(dmacr
, pl011_state
),
250 VMSTATE_UINT32(int_enabled
, pl011_state
),
251 VMSTATE_UINT32(int_level
, pl011_state
),
252 VMSTATE_UINT32_ARRAY(read_fifo
, pl011_state
, 16),
253 VMSTATE_UINT32(ilpr
, pl011_state
),
254 VMSTATE_UINT32(ibrd
, pl011_state
),
255 VMSTATE_UINT32(fbrd
, pl011_state
),
256 VMSTATE_UINT32(ifl
, pl011_state
),
257 VMSTATE_INT32(read_pos
, pl011_state
),
258 VMSTATE_INT32(read_count
, pl011_state
),
259 VMSTATE_INT32(read_trigger
, pl011_state
),
260 VMSTATE_END_OF_LIST()
264 static int pl011_init(SysBusDevice
*dev
, const unsigned char *id
)
266 pl011_state
*s
= FROM_SYSBUS(pl011_state
, dev
);
268 memory_region_init_io(&s
->iomem
, &pl011_ops
, s
, "pl011", 0x1000);
269 sysbus_init_mmio(dev
, &s
->iomem
);
270 sysbus_init_irq(dev
, &s
->irq
);
272 s
->chr
= qemu_char_get_next_serial();
279 qemu_chr_add_handlers(s
->chr
, pl011_can_receive
, pl011_receive
,
282 vmstate_register(&dev
->qdev
, -1, &vmstate_pl011
, s
);
286 static int pl011_arm_init(SysBusDevice
*dev
)
288 return pl011_init(dev
, pl011_id_arm
);
291 static int pl011_luminary_init(SysBusDevice
*dev
)
293 return pl011_init(dev
, pl011_id_luminary
);
296 static void pl011_arm_class_init(ObjectClass
*klass
, void *data
)
298 SysBusDeviceClass
*sdc
= SYS_BUS_DEVICE_CLASS(klass
);
300 sdc
->init
= pl011_arm_init
;
303 static TypeInfo pl011_arm_info
= {
305 .parent
= TYPE_SYS_BUS_DEVICE
,
306 .instance_size
= sizeof(pl011_state
),
307 .class_init
= pl011_arm_class_init
,
310 static void pl011_luminary_class_init(ObjectClass
*klass
, void *data
)
312 SysBusDeviceClass
*sdc
= SYS_BUS_DEVICE_CLASS(klass
);
314 sdc
->init
= pl011_luminary_init
;
317 static TypeInfo pl011_luminary_info
= {
318 .name
= "pl011_luminary",
319 .parent
= TYPE_SYS_BUS_DEVICE
,
320 .instance_size
= sizeof(pl011_state
),
321 .class_init
= pl011_luminary_class_init
,
324 static void pl011_register_types(void)
326 type_register_static(&pl011_arm_info
);
327 type_register_static(&pl011_luminary_info
);
330 type_init(pl011_register_types
)