]> git.proxmox.com Git - qemu.git/blob - hw/pl011.c
bbef0a4c6d9ae985168c9e137ab9f0567591908b
[qemu.git] / hw / pl011.c
1 /*
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 "hw.h"
11 #include "qemu-char.h"
12 #include "primecell.h"
13
14 typedef struct {
15 uint32_t base;
16 uint32_t readbuff;
17 uint32_t flags;
18 uint32_t lcr;
19 uint32_t cr;
20 uint32_t dmacr;
21 uint32_t int_enabled;
22 uint32_t int_level;
23 uint32_t read_fifo[16];
24 uint32_t ilpr;
25 uint32_t ibrd;
26 uint32_t fbrd;
27 uint32_t ifl;
28 int read_pos;
29 int read_count;
30 int read_trigger;
31 CharDriverState *chr;
32 qemu_irq irq;
33 enum pl011_type type;
34 } pl011_state;
35
36 #define PL011_INT_TX 0x20
37 #define PL011_INT_RX 0x10
38
39 #define PL011_FLAG_TXFE 0x80
40 #define PL011_FLAG_RXFF 0x40
41 #define PL011_FLAG_TXFF 0x20
42 #define PL011_FLAG_RXFE 0x10
43
44 static const unsigned char pl011_id[2][8] = {
45 { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }, /* PL011_ARM */
46 { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 }, /* PL011_LUMINARY */
47 };
48
49 static void pl011_update(pl011_state *s)
50 {
51 uint32_t flags;
52
53 flags = s->int_level & s->int_enabled;
54 qemu_set_irq(s->irq, flags != 0);
55 }
56
57 static uint32_t pl011_read(void *opaque, target_phys_addr_t offset)
58 {
59 pl011_state *s = (pl011_state *)opaque;
60 uint32_t c;
61
62 offset -= s->base;
63 if (offset >= 0xfe0 && offset < 0x1000) {
64 return pl011_id[s->type][(offset - 0xfe0) >> 2];
65 }
66 switch (offset >> 2) {
67 case 0: /* UARTDR */
68 s->flags &= ~PL011_FLAG_RXFF;
69 c = s->read_fifo[s->read_pos];
70 if (s->read_count > 0) {
71 s->read_count--;
72 if (++s->read_pos == 16)
73 s->read_pos = 0;
74 }
75 if (s->read_count == 0) {
76 s->flags |= PL011_FLAG_RXFE;
77 }
78 if (s->read_count == s->read_trigger - 1)
79 s->int_level &= ~ PL011_INT_RX;
80 pl011_update(s);
81 qemu_chr_accept_input(s->chr);
82 return c;
83 case 1: /* UARTCR */
84 return 0;
85 case 6: /* UARTFR */
86 return s->flags;
87 case 8: /* UARTILPR */
88 return s->ilpr;
89 case 9: /* UARTIBRD */
90 return s->ibrd;
91 case 10: /* UARTFBRD */
92 return s->fbrd;
93 case 11: /* UARTLCR_H */
94 return s->lcr;
95 case 12: /* UARTCR */
96 return s->cr;
97 case 13: /* UARTIFLS */
98 return s->ifl;
99 case 14: /* UARTIMSC */
100 return s->int_enabled;
101 case 15: /* UARTRIS */
102 return s->int_level;
103 case 16: /* UARTMIS */
104 return s->int_level & s->int_enabled;
105 case 18: /* UARTDMACR */
106 return s->dmacr;
107 default:
108 cpu_abort (cpu_single_env, "pl011_read: Bad offset %x\n", (int)offset);
109 return 0;
110 }
111 }
112
113 static void pl011_set_read_trigger(pl011_state *s)
114 {
115 #if 0
116 /* The docs say the RX interrupt is triggered when the FIFO exceeds
117 the threshold. However linux only reads the FIFO in response to an
118 interrupt. Triggering the interrupt when the FIFO is non-empty seems
119 to make things work. */
120 if (s->lcr & 0x10)
121 s->read_trigger = (s->ifl >> 1) & 0x1c;
122 else
123 #endif
124 s->read_trigger = 1;
125 }
126
127 static void pl011_write(void *opaque, target_phys_addr_t offset,
128 uint32_t value)
129 {
130 pl011_state *s = (pl011_state *)opaque;
131 unsigned char ch;
132
133 offset -= s->base;
134 switch (offset >> 2) {
135 case 0: /* UARTDR */
136 /* ??? Check if transmitter is enabled. */
137 ch = value;
138 if (s->chr)
139 qemu_chr_write(s->chr, &ch, 1);
140 s->int_level |= PL011_INT_TX;
141 pl011_update(s);
142 break;
143 case 1: /* UARTCR */
144 s->cr = value;
145 break;
146 case 6: /* UARTFR */
147 /* Writes to Flag register are ignored. */
148 break;
149 case 8: /* UARTUARTILPR */
150 s->ilpr = value;
151 break;
152 case 9: /* UARTIBRD */
153 s->ibrd = value;
154 break;
155 case 10: /* UARTFBRD */
156 s->fbrd = value;
157 break;
158 case 11: /* UARTLCR_H */
159 s->lcr = value;
160 pl011_set_read_trigger(s);
161 break;
162 case 12: /* UARTCR */
163 /* ??? Need to implement the enable and loopback bits. */
164 s->cr = value;
165 break;
166 case 13: /* UARTIFS */
167 s->ifl = value;
168 pl011_set_read_trigger(s);
169 break;
170 case 14: /* UARTIMSC */
171 s->int_enabled = value;
172 pl011_update(s);
173 break;
174 case 17: /* UARTICR */
175 s->int_level &= ~value;
176 pl011_update(s);
177 break;
178 case 18: /* UARTDMACR */
179 s->dmacr = value;
180 if (value & 3)
181 cpu_abort(cpu_single_env, "PL011: DMA not implemented\n");
182 break;
183 default:
184 cpu_abort (cpu_single_env, "pl011_write: Bad offset %x\n", (int)offset);
185 }
186 }
187
188 static int pl011_can_receive(void *opaque)
189 {
190 pl011_state *s = (pl011_state *)opaque;
191
192 if (s->lcr & 0x10)
193 return s->read_count < 16;
194 else
195 return s->read_count < 1;
196 }
197
198 static void pl011_put_fifo(void *opaque, uint32_t value)
199 {
200 pl011_state *s = (pl011_state *)opaque;
201 int slot;
202
203 slot = s->read_pos + s->read_count;
204 if (slot >= 16)
205 slot -= 16;
206 s->read_fifo[slot] = value;
207 s->read_count++;
208 s->flags &= ~PL011_FLAG_RXFE;
209 if (s->cr & 0x10 || s->read_count == 16) {
210 s->flags |= PL011_FLAG_RXFF;
211 }
212 if (s->read_count == s->read_trigger) {
213 s->int_level |= PL011_INT_RX;
214 pl011_update(s);
215 }
216 }
217
218 static void pl011_receive(void *opaque, const uint8_t *buf, int size)
219 {
220 pl011_put_fifo(opaque, *buf);
221 }
222
223 static void pl011_event(void *opaque, int event)
224 {
225 if (event == CHR_EVENT_BREAK)
226 pl011_put_fifo(opaque, 0x400);
227 }
228
229 static CPUReadMemoryFunc *pl011_readfn[] = {
230 pl011_read,
231 pl011_read,
232 pl011_read
233 };
234
235 static CPUWriteMemoryFunc *pl011_writefn[] = {
236 pl011_write,
237 pl011_write,
238 pl011_write
239 };
240
241 static void pl011_save(QEMUFile *f, void *opaque)
242 {
243 pl011_state *s = (pl011_state *)opaque;
244 int i;
245
246 qemu_put_be32(f, s->readbuff);
247 qemu_put_be32(f, s->flags);
248 qemu_put_be32(f, s->lcr);
249 qemu_put_be32(f, s->cr);
250 qemu_put_be32(f, s->dmacr);
251 qemu_put_be32(f, s->int_enabled);
252 qemu_put_be32(f, s->int_level);
253 for (i = 0; i < 16; i++)
254 qemu_put_be32(f, s->read_fifo[i]);
255 qemu_put_be32(f, s->ilpr);
256 qemu_put_be32(f, s->ibrd);
257 qemu_put_be32(f, s->fbrd);
258 qemu_put_be32(f, s->ifl);
259 qemu_put_be32(f, s->read_pos);
260 qemu_put_be32(f, s->read_count);
261 qemu_put_be32(f, s->read_trigger);
262 }
263
264 static int pl011_load(QEMUFile *f, void *opaque, int version_id)
265 {
266 pl011_state *s = (pl011_state *)opaque;
267 int i;
268
269 if (version_id != 1)
270 return -EINVAL;
271
272 s->readbuff = qemu_get_be32(f);
273 s->flags = qemu_get_be32(f);
274 s->lcr = qemu_get_be32(f);
275 s->cr = qemu_get_be32(f);
276 s->dmacr = qemu_get_be32(f);
277 s->int_enabled = qemu_get_be32(f);
278 s->int_level = qemu_get_be32(f);
279 for (i = 0; i < 16; i++)
280 s->read_fifo[i] = qemu_get_be32(f);
281 s->ilpr = qemu_get_be32(f);
282 s->ibrd = qemu_get_be32(f);
283 s->fbrd = qemu_get_be32(f);
284 s->ifl = qemu_get_be32(f);
285 s->read_pos = qemu_get_be32(f);
286 s->read_count = qemu_get_be32(f);
287 s->read_trigger = qemu_get_be32(f);
288
289 return 0;
290 }
291
292 void pl011_init(uint32_t base, qemu_irq irq,
293 CharDriverState *chr, enum pl011_type type)
294 {
295 int iomemtype;
296 pl011_state *s;
297
298 s = (pl011_state *)qemu_mallocz(sizeof(pl011_state));
299 iomemtype = cpu_register_io_memory(0, pl011_readfn,
300 pl011_writefn, s);
301 cpu_register_physical_memory(base, 0x00001000, iomemtype);
302 s->base = base;
303 s->irq = irq;
304 s->type = type;
305 s->chr = chr;
306 s->read_trigger = 1;
307 s->ifl = 0x12;
308 s->cr = 0x300;
309 s->flags = 0x90;
310 if (chr){
311 qemu_chr_add_handlers(chr, pl011_can_receive, pl011_receive,
312 pl011_event, s);
313 }
314 register_savevm("pl011_uart", -1, 1, pl011_save, pl011_load, s);
315 }
316