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[] =
43 { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
45 static void pl011_update(pl011_state *s)
49 flags = s->int_level & s->int_enabled;
50 pic_set_irq_new(s->pic, s->irq, flags != 0);
53 static uint32_t pl011_read(void *opaque, target_phys_addr_t offset)
55 pl011_state *s = (pl011_state *)opaque;
59 if (offset >= 0xfe0 && offset < 0x1000) {
60 return pl011_id[(offset - 0xfe0) >> 2];
62 switch (offset >> 2) {
64 s->flags &= ~PL011_FLAG_RXFF;
65 c = s->read_fifo[s->read_pos];
66 if (s->read_count > 0) {
68 if (++s->read_pos == 16)
71 if (s->read_count == 0) {
72 s->flags |= PL011_FLAG_RXFE;
74 if (s->read_count == s->read_trigger - 1)
75 s->int_level &= ~ PL011_INT_RX;
82 case 8: /* UARTILPR */
84 case 9: /* UARTIBRD */
86 case 10: /* UARTFBRD */
88 case 11: /* UARTLCR_H */
92 case 13: /* UARTIFLS */
94 case 14: /* UARTIMSC */
95 return s->int_enabled;
96 case 15: /* UARTRIS */
98 case 16: /* UARTMIS */
99 return s->int_level & s->int_enabled;
100 case 18: /* UARTDMACR */
103 cpu_abort (cpu_single_env, "pl011_read: Bad offset %x\n", offset);
108 static void pl011_set_read_trigger(pl011_state *s)
111 /* The docs say the RX interrupt is triggered when the FIFO exceeds
112 the threshold. However linux only reads the FIFO in response to an
113 interrupt. Triggering the interrupt when the FIFO is non-empty seems
114 to make things work. */
116 s->read_trigger = (s->ifl >> 1) & 0x1c;
122 static void pl011_write(void *opaque, target_phys_addr_t offset,
125 pl011_state *s = (pl011_state *)opaque;
129 switch (offset >> 2) {
131 /* ??? Check if transmitter is enabled. */
134 qemu_chr_write(s->chr, &ch, 1);
135 s->int_level |= PL011_INT_TX;
141 case 8: /* UARTUARTILPR */
144 case 9: /* UARTIBRD */
147 case 10: /* UARTFBRD */
150 case 11: /* UARTLCR_H */
152 pl011_set_read_trigger(s);
154 case 12: /* UARTCR */
155 /* ??? Need to implement the enable and loopback bits. */
158 case 13: /* UARTIFS */
160 pl011_set_read_trigger(s);
162 case 14: /* UARTIMSC */
163 s->int_enabled = value;
166 case 17: /* UARTICR */
167 s->int_level &= ~value;
170 case 18: /* UARTDMACR */
173 cpu_abort(cpu_single_env, "PL011: DMA not implemented\n");
176 cpu_abort (cpu_single_env, "pl011_write: Bad offset %x\n", offset);
180 static int pl011_can_recieve(void *opaque)
182 pl011_state *s = (pl011_state *)opaque;
185 return s->read_count < 16;
187 return s->read_count < 1;
190 static void pl011_recieve(void *opaque, const uint8_t *buf, int size)
192 pl011_state *s = (pl011_state *)opaque;
195 slot = s->read_pos + s->read_count;
198 s->read_fifo[slot] = *buf;
200 s->flags &= ~PL011_FLAG_RXFE;
201 if (s->cr & 0x10 || s->read_count == 16) {
202 s->flags |= PL011_FLAG_RXFF;
204 if (s->read_count == s->read_trigger) {
205 s->int_level |= PL011_INT_RX;
210 static void pl011_event(void *opaque, int event)
212 /* ??? Should probably implement break. */
215 static CPUReadMemoryFunc *pl011_readfn[] = {
221 static CPUWriteMemoryFunc *pl011_writefn[] = {
227 void pl011_init(uint32_t base, void *pic, int irq,
228 CharDriverState *chr)
233 s = (pl011_state *)qemu_mallocz(sizeof(pl011_state));
234 iomemtype = cpu_register_io_memory(0, pl011_readfn,
236 cpu_register_physical_memory(base, 0x00000fff, iomemtype);
246 qemu_chr_add_read_handler(chr, pl011_can_recieve, pl011_recieve, s);
247 qemu_chr_add_event_handler(chr, pl011_event);
249 /* ??? Save/restore. */