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