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