]> git.proxmox.com Git - mirror_qemu.git/blame - hw/pl011.c
find -type f | xargs sed -i 's/[\t ]*$//g' # Yes, again. Note the star in the regex.
[mirror_qemu.git] / hw / pl011.c
CommitLineData
5fafdf24 1/*
cdbdb648
PB
2 * Arm PrimeCell PL011 UART
3 *
4 * Copyright (c) 2006 CodeSourcery.
5 * Written by Paul Brook
6 *
7 * This code is licenced under the GPL.
8 */
9
10#include "vl.h"
11
12typedef struct {
13 uint32_t base;
14 uint32_t readbuff;
15 uint32_t flags;
16 uint32_t lcr;
17 uint32_t cr;
18 uint32_t dmacr;
19 uint32_t int_enabled;
20 uint32_t int_level;
21 uint32_t read_fifo[16];
22 uint32_t ilpr;
23 uint32_t ibrd;
24 uint32_t fbrd;
25 uint32_t ifl;
26 int read_pos;
27 int read_count;
28 int read_trigger;
29 CharDriverState *chr;
d537cf6c 30 qemu_irq irq;
cdbdb648
PB
31} pl011_state;
32
33#define PL011_INT_TX 0x20
34#define PL011_INT_RX 0x10
35
36#define PL011_FLAG_TXFE 0x80
37#define PL011_FLAG_RXFF 0x40
38#define PL011_FLAG_TXFF 0x20
39#define PL011_FLAG_RXFE 0x10
40
41static const unsigned char pl011_id[] =
42{ 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
43
44static void pl011_update(pl011_state *s)
45{
46 uint32_t flags;
3b46e624 47
cdbdb648 48 flags = s->int_level & s->int_enabled;
d537cf6c 49 qemu_set_irq(s->irq, flags != 0);
cdbdb648
PB
50}
51
52static uint32_t pl011_read(void *opaque, target_phys_addr_t offset)
53{
54 pl011_state *s = (pl011_state *)opaque;
55 uint32_t c;
56
57 offset -= s->base;
58 if (offset >= 0xfe0 && offset < 0x1000) {
59 return pl011_id[(offset - 0xfe0) >> 2];
60 }
61 switch (offset >> 2) {
62 case 0: /* UARTDR */
63 s->flags &= ~PL011_FLAG_RXFF;
64 c = s->read_fifo[s->read_pos];
65 if (s->read_count > 0) {
66 s->read_count--;
67 if (++s->read_pos == 16)
68 s->read_pos = 0;
69 }
70 if (s->read_count == 0) {
71 s->flags |= PL011_FLAG_RXFE;
72 }
73 if (s->read_count == s->read_trigger - 1)
74 s->int_level &= ~ PL011_INT_RX;
75 pl011_update(s);
76 return c;
77 case 1: /* UARTCR */
78 return 0;
79 case 6: /* UARTFR */
80 return s->flags;
81 case 8: /* UARTILPR */
82 return s->ilpr;
83 case 9: /* UARTIBRD */
84 return s->ibrd;
85 case 10: /* UARTFBRD */
86 return s->fbrd;
87 case 11: /* UARTLCR_H */
88 return s->lcr;
89 case 12: /* UARTCR */
90 return s->cr;
91 case 13: /* UARTIFLS */
92 return s->ifl;
93 case 14: /* UARTIMSC */
94 return s->int_enabled;
95 case 15: /* UARTRIS */
96 return s->int_level;
97 case 16: /* UARTMIS */
98 return s->int_level & s->int_enabled;
99 case 18: /* UARTDMACR */
100 return s->dmacr;
101 default:
102 cpu_abort (cpu_single_env, "pl011_read: Bad offset %x\n", offset);
103 return 0;
104 }
105}
106
107static void pl011_set_read_trigger(pl011_state *s)
108{
109#if 0
110 /* The docs say the RX interrupt is triggered when the FIFO exceeds
111 the threshold. However linux only reads the FIFO in response to an
112 interrupt. Triggering the interrupt when the FIFO is non-empty seems
113 to make things work. */
114 if (s->lcr & 0x10)
115 s->read_trigger = (s->ifl >> 1) & 0x1c;
116 else
117#endif
118 s->read_trigger = 1;
119}
120
121static void pl011_write(void *opaque, target_phys_addr_t offset,
122 uint32_t value)
123{
124 pl011_state *s = (pl011_state *)opaque;
125 unsigned char ch;
126
127 offset -= s->base;
128 switch (offset >> 2) {
129 case 0: /* UARTDR */
130 /* ??? Check if transmitter is enabled. */
131 ch = value;
132 if (s->chr)
133 qemu_chr_write(s->chr, &ch, 1);
134 s->int_level |= PL011_INT_TX;
135 pl011_update(s);
136 break;
137 case 1: /* UARTCR */
138 s->cr = value;
139 break;
140 case 8: /* UARTUARTILPR */
141 s->ilpr = value;
142 break;
143 case 9: /* UARTIBRD */
144 s->ibrd = value;
145 break;
146 case 10: /* UARTFBRD */
147 s->fbrd = value;
148 break;
149 case 11: /* UARTLCR_H */
150 s->lcr = value;
151 pl011_set_read_trigger(s);
152 break;
153 case 12: /* UARTCR */
154 /* ??? Need to implement the enable and loopback bits. */
155 s->cr = value;
156 break;
157 case 13: /* UARTIFS */
158 s->ifl = value;
159 pl011_set_read_trigger(s);
160 break;
161 case 14: /* UARTIMSC */
162 s->int_enabled = value;
163 pl011_update(s);
164 break;
165 case 17: /* UARTICR */
166 s->int_level &= ~value;
167 pl011_update(s);
168 break;
169 case 18: /* UARTDMACR */
170 s->dmacr = value;
171 if (value & 3)
172 cpu_abort(cpu_single_env, "PL011: DMA not implemented\n");
173 break;
174 default:
175 cpu_abort (cpu_single_env, "pl011_write: Bad offset %x\n", offset);
176 }
177}
178
aa1f17c1 179static int pl011_can_receive(void *opaque)
cdbdb648
PB
180{
181 pl011_state *s = (pl011_state *)opaque;
182
183 if (s->lcr & 0x10)
184 return s->read_count < 16;
185 else
186 return s->read_count < 1;
187}
188
aa1f17c1 189static void pl011_receive(void *opaque, const uint8_t *buf, int size)
cdbdb648
PB
190{
191 pl011_state *s = (pl011_state *)opaque;
192 int slot;
193
194 slot = s->read_pos + s->read_count;
195 if (slot >= 16)
196 slot -= 16;
197 s->read_fifo[slot] = *buf;
198 s->read_count++;
199 s->flags &= ~PL011_FLAG_RXFE;
200 if (s->cr & 0x10 || s->read_count == 16) {
201 s->flags |= PL011_FLAG_RXFF;
202 }
203 if (s->read_count == s->read_trigger) {
204 s->int_level |= PL011_INT_RX;
205 pl011_update(s);
206 }
207}
208
209static void pl011_event(void *opaque, int event)
210{
211 /* ??? Should probably implement break. */
212}
213
214static CPUReadMemoryFunc *pl011_readfn[] = {
215 pl011_read,
216 pl011_read,
217 pl011_read
218};
219
220static CPUWriteMemoryFunc *pl011_writefn[] = {
221 pl011_write,
222 pl011_write,
223 pl011_write
224};
225
d537cf6c 226void pl011_init(uint32_t base, qemu_irq irq,
cdbdb648
PB
227 CharDriverState *chr)
228{
229 int iomemtype;
230 pl011_state *s;
231
232 s = (pl011_state *)qemu_mallocz(sizeof(pl011_state));
233 iomemtype = cpu_register_io_memory(0, pl011_readfn,
234 pl011_writefn, s);
187337f8 235 cpu_register_physical_memory(base, 0x00001000, iomemtype);
cdbdb648 236 s->base = base;
cdbdb648
PB
237 s->irq = irq;
238 s->chr = chr;
239 s->read_trigger = 1;
240 s->ifl = 0x12;
241 s->cr = 0x300;
242 s->flags = 0x90;
5fafdf24 243 if (chr){
aa1f17c1 244 qemu_chr_add_handlers(chr, pl011_can_receive, pl011_receive,
e5b0bc44 245 pl011_event, s);
cdbdb648
PB
246 }
247 /* ??? Save/restore. */
248}
249