2 * Arm PrimeCell PL011 UART
4 * Copyright (c) 2006 CodeSourcery.
5 * Written by Paul Brook
7 * This code is licenced under the GPL.
21 uint32_t read_fifo
[16];
34 #define PL011_INT_TX 0x20
35 #define PL011_INT_RX 0x10
37 #define PL011_FLAG_TXFE 0x80
38 #define PL011_FLAG_RXFF 0x40
39 #define PL011_FLAG_TXFF 0x20
40 #define PL011_FLAG_RXFE 0x10
42 static const unsigned char pl011_id
[2][8] = {
43 { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }, /* PL011_ARM */
44 { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 }, /* PL011_LUMINARY */
47 static void pl011_update(pl011_state
*s
)
51 flags
= s
->int_level
& s
->int_enabled
;
52 qemu_set_irq(s
->irq
, flags
!= 0);
55 static uint32_t pl011_read(void *opaque
, target_phys_addr_t offset
)
57 pl011_state
*s
= (pl011_state
*)opaque
;
61 if (offset
>= 0xfe0 && offset
< 0x1000) {
62 return pl011_id
[s
->type
][(offset
- 0xfe0) >> 2];
64 switch (offset
>> 2) {
66 s
->flags
&= ~PL011_FLAG_RXFF
;
67 c
= s
->read_fifo
[s
->read_pos
];
68 if (s
->read_count
> 0) {
70 if (++s
->read_pos
== 16)
73 if (s
->read_count
== 0) {
74 s
->flags
|= PL011_FLAG_RXFE
;
76 if (s
->read_count
== s
->read_trigger
- 1)
77 s
->int_level
&= ~ PL011_INT_RX
;
84 case 8: /* UARTILPR */
86 case 9: /* UARTIBRD */
88 case 10: /* UARTFBRD */
90 case 11: /* UARTLCR_H */
94 case 13: /* UARTIFLS */
96 case 14: /* UARTIMSC */
97 return s
->int_enabled
;
98 case 15: /* UARTRIS */
100 case 16: /* UARTMIS */
101 return s
->int_level
& s
->int_enabled
;
102 case 18: /* UARTDMACR */
105 cpu_abort (cpu_single_env
, "pl011_read: Bad offset %x\n", (int)offset
);
110 static void pl011_set_read_trigger(pl011_state
*s
)
113 /* The docs say the RX interrupt is triggered when the FIFO exceeds
114 the threshold. However linux only reads the FIFO in response to an
115 interrupt. Triggering the interrupt when the FIFO is non-empty seems
116 to make things work. */
118 s
->read_trigger
= (s
->ifl
>> 1) & 0x1c;
124 static void pl011_write(void *opaque
, target_phys_addr_t offset
,
127 pl011_state
*s
= (pl011_state
*)opaque
;
131 switch (offset
>> 2) {
133 /* ??? Check if transmitter is enabled. */
136 qemu_chr_write(s
->chr
, &ch
, 1);
137 s
->int_level
|= PL011_INT_TX
;
144 /* Writes to Flag register are ignored. */
146 case 8: /* UARTUARTILPR */
149 case 9: /* UARTIBRD */
152 case 10: /* UARTFBRD */
155 case 11: /* UARTLCR_H */
157 pl011_set_read_trigger(s
);
159 case 12: /* UARTCR */
160 /* ??? Need to implement the enable and loopback bits. */
163 case 13: /* UARTIFS */
165 pl011_set_read_trigger(s
);
167 case 14: /* UARTIMSC */
168 s
->int_enabled
= value
;
171 case 17: /* UARTICR */
172 s
->int_level
&= ~value
;
175 case 18: /* UARTDMACR */
178 cpu_abort(cpu_single_env
, "PL011: DMA not implemented\n");
181 cpu_abort (cpu_single_env
, "pl011_write: Bad offset %x\n", (int)offset
);
185 static int pl011_can_receive(void *opaque
)
187 pl011_state
*s
= (pl011_state
*)opaque
;
190 return s
->read_count
< 16;
192 return s
->read_count
< 1;
195 static void pl011_receive(void *opaque
, const uint8_t *buf
, int size
)
197 pl011_state
*s
= (pl011_state
*)opaque
;
200 slot
= s
->read_pos
+ s
->read_count
;
203 s
->read_fifo
[slot
] = *buf
;
205 s
->flags
&= ~PL011_FLAG_RXFE
;
206 if (s
->cr
& 0x10 || s
->read_count
== 16) {
207 s
->flags
|= PL011_FLAG_RXFF
;
209 if (s
->read_count
== s
->read_trigger
) {
210 s
->int_level
|= PL011_INT_RX
;
215 static void pl011_event(void *opaque
, int event
)
217 /* ??? Should probably implement break. */
220 static CPUReadMemoryFunc
*pl011_readfn
[] = {
226 static CPUWriteMemoryFunc
*pl011_writefn
[] = {
232 void pl011_init(uint32_t base
, qemu_irq irq
,
233 CharDriverState
*chr
, enum pl011_type type
)
238 s
= (pl011_state
*)qemu_mallocz(sizeof(pl011_state
));
239 iomemtype
= cpu_register_io_memory(0, pl011_readfn
,
241 cpu_register_physical_memory(base
, 0x00001000, iomemtype
);
251 qemu_chr_add_handlers(chr
, pl011_can_receive
, pl011_receive
,
254 /* ??? Save/restore. */