]> git.ipfire.org Git - thirdparty/qemu.git/blob - hw/char/pl011.c
Include hw/irq.h a lot less
[thirdparty/qemu.git] / hw / char / pl011.c
1 /*
2 * Arm PrimeCell PL011 UART
3 *
4 * Copyright (c) 2006 CodeSourcery.
5 * Written by Paul Brook
6 *
7 * This code is licensed under the GPL.
8 */
9
10 /*
11 * QEMU interface:
12 * + sysbus MMIO region 0: device registers
13 * + sysbus IRQ 0: UARTINTR (combined interrupt line)
14 * + sysbus IRQ 1: UARTRXINTR (receive FIFO interrupt line)
15 * + sysbus IRQ 2: UARTTXINTR (transmit FIFO interrupt line)
16 * + sysbus IRQ 3: UARTRTINTR (receive timeout interrupt line)
17 * + sysbus IRQ 4: UARTMSINTR (momem status interrupt line)
18 * + sysbus IRQ 5: UARTEINTR (error interrupt line)
19 */
20
21 #include "qemu/osdep.h"
22 #include "hw/char/pl011.h"
23 #include "hw/irq.h"
24 #include "hw/sysbus.h"
25 #include "chardev/char-fe.h"
26 #include "qemu/log.h"
27 #include "qemu/module.h"
28 #include "trace.h"
29
30 #define PL011_INT_TX 0x20
31 #define PL011_INT_RX 0x10
32
33 #define PL011_FLAG_TXFE 0x80
34 #define PL011_FLAG_RXFF 0x40
35 #define PL011_FLAG_TXFF 0x20
36 #define PL011_FLAG_RXFE 0x10
37
38 /* Interrupt status bits in UARTRIS, UARTMIS, UARTIMSC */
39 #define INT_OE (1 << 10)
40 #define INT_BE (1 << 9)
41 #define INT_PE (1 << 8)
42 #define INT_FE (1 << 7)
43 #define INT_RT (1 << 6)
44 #define INT_TX (1 << 5)
45 #define INT_RX (1 << 4)
46 #define INT_DSR (1 << 3)
47 #define INT_DCD (1 << 2)
48 #define INT_CTS (1 << 1)
49 #define INT_RI (1 << 0)
50 #define INT_E (INT_OE | INT_BE | INT_PE | INT_FE)
51 #define INT_MS (INT_RI | INT_DSR | INT_DCD | INT_CTS)
52
53 static const unsigned char pl011_id_arm[8] =
54 { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
55 static const unsigned char pl011_id_luminary[8] =
56 { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
57
58 /* Which bits in the interrupt status matter for each outbound IRQ line ? */
59 static const uint32_t irqmask[] = {
60 INT_E | INT_MS | INT_RT | INT_TX | INT_RX, /* combined IRQ */
61 INT_RX,
62 INT_TX,
63 INT_RT,
64 INT_MS,
65 INT_E,
66 };
67
68 static void pl011_update(PL011State *s)
69 {
70 uint32_t flags;
71 int i;
72
73 flags = s->int_level & s->int_enabled;
74 trace_pl011_irq_state(flags != 0);
75 for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
76 qemu_set_irq(s->irq[i], (flags & irqmask[i]) != 0);
77 }
78 }
79
80 static uint64_t pl011_read(void *opaque, hwaddr offset,
81 unsigned size)
82 {
83 PL011State *s = (PL011State *)opaque;
84 uint32_t c;
85 uint64_t r;
86
87 switch (offset >> 2) {
88 case 0: /* UARTDR */
89 s->flags &= ~PL011_FLAG_RXFF;
90 c = s->read_fifo[s->read_pos];
91 if (s->read_count > 0) {
92 s->read_count--;
93 if (++s->read_pos == 16)
94 s->read_pos = 0;
95 }
96 if (s->read_count == 0) {
97 s->flags |= PL011_FLAG_RXFE;
98 }
99 if (s->read_count == s->read_trigger - 1)
100 s->int_level &= ~ PL011_INT_RX;
101 trace_pl011_read_fifo(s->read_count);
102 s->rsr = c >> 8;
103 pl011_update(s);
104 qemu_chr_fe_accept_input(&s->chr);
105 r = c;
106 break;
107 case 1: /* UARTRSR */
108 r = s->rsr;
109 break;
110 case 6: /* UARTFR */
111 r = s->flags;
112 break;
113 case 8: /* UARTILPR */
114 r = s->ilpr;
115 break;
116 case 9: /* UARTIBRD */
117 r = s->ibrd;
118 break;
119 case 10: /* UARTFBRD */
120 r = s->fbrd;
121 break;
122 case 11: /* UARTLCR_H */
123 r = s->lcr;
124 break;
125 case 12: /* UARTCR */
126 r = s->cr;
127 break;
128 case 13: /* UARTIFLS */
129 r = s->ifl;
130 break;
131 case 14: /* UARTIMSC */
132 r = s->int_enabled;
133 break;
134 case 15: /* UARTRIS */
135 r = s->int_level;
136 break;
137 case 16: /* UARTMIS */
138 r = s->int_level & s->int_enabled;
139 break;
140 case 18: /* UARTDMACR */
141 r = s->dmacr;
142 break;
143 case 0x3f8 ... 0x400:
144 r = s->id[(offset - 0xfe0) >> 2];
145 break;
146 default:
147 qemu_log_mask(LOG_GUEST_ERROR,
148 "pl011_read: Bad offset 0x%x\n", (int)offset);
149 r = 0;
150 break;
151 }
152
153 trace_pl011_read(offset, r);
154 return r;
155 }
156
157 static void pl011_set_read_trigger(PL011State *s)
158 {
159 #if 0
160 /* The docs say the RX interrupt is triggered when the FIFO exceeds
161 the threshold. However linux only reads the FIFO in response to an
162 interrupt. Triggering the interrupt when the FIFO is non-empty seems
163 to make things work. */
164 if (s->lcr & 0x10)
165 s->read_trigger = (s->ifl >> 1) & 0x1c;
166 else
167 #endif
168 s->read_trigger = 1;
169 }
170
171 static void pl011_write(void *opaque, hwaddr offset,
172 uint64_t value, unsigned size)
173 {
174 PL011State *s = (PL011State *)opaque;
175 unsigned char ch;
176
177 trace_pl011_write(offset, value);
178
179 switch (offset >> 2) {
180 case 0: /* UARTDR */
181 /* ??? Check if transmitter is enabled. */
182 ch = value;
183 /* XXX this blocks entire thread. Rewrite to use
184 * qemu_chr_fe_write and background I/O callbacks */
185 qemu_chr_fe_write_all(&s->chr, &ch, 1);
186 s->int_level |= PL011_INT_TX;
187 pl011_update(s);
188 break;
189 case 1: /* UARTRSR/UARTECR */
190 s->rsr = 0;
191 break;
192 case 6: /* UARTFR */
193 /* Writes to Flag register are ignored. */
194 break;
195 case 8: /* UARTUARTILPR */
196 s->ilpr = value;
197 break;
198 case 9: /* UARTIBRD */
199 s->ibrd = value;
200 break;
201 case 10: /* UARTFBRD */
202 s->fbrd = value;
203 break;
204 case 11: /* UARTLCR_H */
205 /* Reset the FIFO state on FIFO enable or disable */
206 if ((s->lcr ^ value) & 0x10) {
207 s->read_count = 0;
208 s->read_pos = 0;
209 }
210 s->lcr = value;
211 pl011_set_read_trigger(s);
212 break;
213 case 12: /* UARTCR */
214 /* ??? Need to implement the enable and loopback bits. */
215 s->cr = value;
216 break;
217 case 13: /* UARTIFS */
218 s->ifl = value;
219 pl011_set_read_trigger(s);
220 break;
221 case 14: /* UARTIMSC */
222 s->int_enabled = value;
223 pl011_update(s);
224 break;
225 case 17: /* UARTICR */
226 s->int_level &= ~value;
227 pl011_update(s);
228 break;
229 case 18: /* UARTDMACR */
230 s->dmacr = value;
231 if (value & 3) {
232 qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n");
233 }
234 break;
235 default:
236 qemu_log_mask(LOG_GUEST_ERROR,
237 "pl011_write: Bad offset 0x%x\n", (int)offset);
238 }
239 }
240
241 static int pl011_can_receive(void *opaque)
242 {
243 PL011State *s = (PL011State *)opaque;
244 int r;
245
246 if (s->lcr & 0x10) {
247 r = s->read_count < 16;
248 } else {
249 r = s->read_count < 1;
250 }
251 trace_pl011_can_receive(s->lcr, s->read_count, r);
252 return r;
253 }
254
255 static void pl011_put_fifo(void *opaque, uint32_t value)
256 {
257 PL011State *s = (PL011State *)opaque;
258 int slot;
259
260 slot = s->read_pos + s->read_count;
261 if (slot >= 16)
262 slot -= 16;
263 s->read_fifo[slot] = value;
264 s->read_count++;
265 s->flags &= ~PL011_FLAG_RXFE;
266 trace_pl011_put_fifo(value, s->read_count);
267 if (!(s->lcr & 0x10) || s->read_count == 16) {
268 trace_pl011_put_fifo_full();
269 s->flags |= PL011_FLAG_RXFF;
270 }
271 if (s->read_count == s->read_trigger) {
272 s->int_level |= PL011_INT_RX;
273 pl011_update(s);
274 }
275 }
276
277 static void pl011_receive(void *opaque, const uint8_t *buf, int size)
278 {
279 pl011_put_fifo(opaque, *buf);
280 }
281
282 static void pl011_event(void *opaque, int event)
283 {
284 if (event == CHR_EVENT_BREAK)
285 pl011_put_fifo(opaque, 0x400);
286 }
287
288 static const MemoryRegionOps pl011_ops = {
289 .read = pl011_read,
290 .write = pl011_write,
291 .endianness = DEVICE_NATIVE_ENDIAN,
292 };
293
294 static const VMStateDescription vmstate_pl011 = {
295 .name = "pl011",
296 .version_id = 2,
297 .minimum_version_id = 2,
298 .fields = (VMStateField[]) {
299 VMSTATE_UINT32(readbuff, PL011State),
300 VMSTATE_UINT32(flags, PL011State),
301 VMSTATE_UINT32(lcr, PL011State),
302 VMSTATE_UINT32(rsr, PL011State),
303 VMSTATE_UINT32(cr, PL011State),
304 VMSTATE_UINT32(dmacr, PL011State),
305 VMSTATE_UINT32(int_enabled, PL011State),
306 VMSTATE_UINT32(int_level, PL011State),
307 VMSTATE_UINT32_ARRAY(read_fifo, PL011State, 16),
308 VMSTATE_UINT32(ilpr, PL011State),
309 VMSTATE_UINT32(ibrd, PL011State),
310 VMSTATE_UINT32(fbrd, PL011State),
311 VMSTATE_UINT32(ifl, PL011State),
312 VMSTATE_INT32(read_pos, PL011State),
313 VMSTATE_INT32(read_count, PL011State),
314 VMSTATE_INT32(read_trigger, PL011State),
315 VMSTATE_END_OF_LIST()
316 }
317 };
318
319 static Property pl011_properties[] = {
320 DEFINE_PROP_CHR("chardev", PL011State, chr),
321 DEFINE_PROP_END_OF_LIST(),
322 };
323
324 static void pl011_init(Object *obj)
325 {
326 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
327 PL011State *s = PL011(obj);
328 int i;
329
330 memory_region_init_io(&s->iomem, OBJECT(s), &pl011_ops, s, "pl011", 0x1000);
331 sysbus_init_mmio(sbd, &s->iomem);
332 for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
333 sysbus_init_irq(sbd, &s->irq[i]);
334 }
335
336 s->read_trigger = 1;
337 s->ifl = 0x12;
338 s->cr = 0x300;
339 s->flags = 0x90;
340
341 s->id = pl011_id_arm;
342 }
343
344 static void pl011_realize(DeviceState *dev, Error **errp)
345 {
346 PL011State *s = PL011(dev);
347
348 qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive,
349 pl011_event, NULL, s, NULL, true);
350 }
351
352 static void pl011_class_init(ObjectClass *oc, void *data)
353 {
354 DeviceClass *dc = DEVICE_CLASS(oc);
355
356 dc->realize = pl011_realize;
357 dc->vmsd = &vmstate_pl011;
358 dc->props = pl011_properties;
359 }
360
361 static const TypeInfo pl011_arm_info = {
362 .name = TYPE_PL011,
363 .parent = TYPE_SYS_BUS_DEVICE,
364 .instance_size = sizeof(PL011State),
365 .instance_init = pl011_init,
366 .class_init = pl011_class_init,
367 };
368
369 static void pl011_luminary_init(Object *obj)
370 {
371 PL011State *s = PL011(obj);
372
373 s->id = pl011_id_luminary;
374 }
375
376 static const TypeInfo pl011_luminary_info = {
377 .name = TYPE_PL011_LUMINARY,
378 .parent = TYPE_PL011,
379 .instance_init = pl011_luminary_init,
380 };
381
382 static void pl011_register_types(void)
383 {
384 type_register_static(&pl011_arm_info);
385 type_register_static(&pl011_luminary_info);
386 }
387
388 type_init(pl011_register_types)