]> Git Repo - qemu.git/blame - hw/char/pl011.c
Include hw/irq.h a lot less
[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"
64552b6b 23#include "hw/irq.h"
83c9f4ca 24#include "hw/sysbus.h"
4d43a603 25#include "chardev/char-fe.h"
03dd024f 26#include "qemu/log.h"
0b8fa32f 27#include "qemu/module.h"
041ac056 28#include "trace.h"
cdbdb648 29
cdbdb648
PB
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
a3c1ca56
PM
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
a7d518a6
PB
53static const unsigned char pl011_id_arm[8] =
54 { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
55static const unsigned char pl011_id_luminary[8] =
56 { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
cdbdb648 57
a3c1ca56
PM
58/* Which bits in the interrupt status matter for each outbound IRQ line ? */
59static 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
ab640bfc 68static void pl011_update(PL011State *s)
cdbdb648
PB
69{
70 uint32_t flags;
a3c1ca56 71 int i;
3b46e624 72
cdbdb648 73 flags = s->int_level & s->int_enabled;
041ac056 74 trace_pl011_irq_state(flags != 0);
a3c1ca56
PM
75 for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
76 qemu_set_irq(s->irq[i], (flags & irqmask[i]) != 0);
77 }
cdbdb648
PB
78}
79
a8170e5e 80static uint64_t pl011_read(void *opaque, hwaddr offset,
48484757 81 unsigned size)
cdbdb648 82{
ab640bfc 83 PL011State *s = (PL011State *)opaque;
cdbdb648 84 uint32_t c;
041ac056 85 uint64_t r;
cdbdb648 86
cdbdb648
PB
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;
041ac056 101 trace_pl011_read_fifo(s->read_count);
ce8f0905 102 s->rsr = c >> 8;
cdbdb648 103 pl011_update(s);
fa394ed6 104 qemu_chr_fe_accept_input(&s->chr);
041ac056
PM
105 r = c;
106 break;
ce8f0905 107 case 1: /* UARTRSR */
041ac056
PM
108 r = s->rsr;
109 break;
cdbdb648 110 case 6: /* UARTFR */
041ac056
PM
111 r = s->flags;
112 break;
cdbdb648 113 case 8: /* UARTILPR */
041ac056
PM
114 r = s->ilpr;
115 break;
cdbdb648 116 case 9: /* UARTIBRD */
041ac056
PM
117 r = s->ibrd;
118 break;
cdbdb648 119 case 10: /* UARTFBRD */
041ac056
PM
120 r = s->fbrd;
121 break;
cdbdb648 122 case 11: /* UARTLCR_H */
041ac056
PM
123 r = s->lcr;
124 break;
cdbdb648 125 case 12: /* UARTCR */
041ac056
PM
126 r = s->cr;
127 break;
cdbdb648 128 case 13: /* UARTIFLS */
041ac056
PM
129 r = s->ifl;
130 break;
cdbdb648 131 case 14: /* UARTIMSC */
041ac056
PM
132 r = s->int_enabled;
133 break;
cdbdb648 134 case 15: /* UARTRIS */
041ac056
PM
135 r = s->int_level;
136 break;
cdbdb648 137 case 16: /* UARTMIS */
041ac056
PM
138 r = s->int_level & s->int_enabled;
139 break;
cdbdb648 140 case 18: /* UARTDMACR */
041ac056
PM
141 r = s->dmacr;
142 break;
143 case 0x3f8 ... 0x400:
144 r = s->id[(offset - 0xfe0) >> 2];
145 break;
cdbdb648 146 default:
6d5433e0 147 qemu_log_mask(LOG_GUEST_ERROR,
76b09faf 148 "pl011_read: Bad offset 0x%x\n", (int)offset);
041ac056
PM
149 r = 0;
150 break;
cdbdb648 151 }
041ac056
PM
152
153 trace_pl011_read(offset, r);
154 return r;
cdbdb648
PB
155}
156
ab640bfc 157static void pl011_set_read_trigger(PL011State *s)
cdbdb648
PB
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
a8170e5e 171static void pl011_write(void *opaque, hwaddr offset,
48484757 172 uint64_t value, unsigned size)
cdbdb648 173{
ab640bfc 174 PL011State *s = (PL011State *)opaque;
cdbdb648
PB
175 unsigned char ch;
176
041ac056
PM
177 trace_pl011_write(offset, value);
178
cdbdb648
PB
179 switch (offset >> 2) {
180 case 0: /* UARTDR */
181 /* ??? Check if transmitter is enabled. */
182 ch = value;
fa394ed6
MAL
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);
cdbdb648
PB
186 s->int_level |= PL011_INT_TX;
187 pl011_update(s);
188 break;
ce8f0905
RH
189 case 1: /* UARTRSR/UARTECR */
190 s->rsr = 0;
cdbdb648 191 break;
9ee6e8bb
PB
192 case 6: /* UARTFR */
193 /* Writes to Flag register are ignored. */
194 break;
cdbdb648
PB
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 */
22709e90
RH
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 }
cdbdb648
PB
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;
6d5433e0
PM
231 if (value & 3) {
232 qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n");
233 }
cdbdb648
PB
234 break;
235 default:
6d5433e0 236 qemu_log_mask(LOG_GUEST_ERROR,
76b09faf 237 "pl011_write: Bad offset 0x%x\n", (int)offset);
cdbdb648
PB
238 }
239}
240
aa1f17c1 241static int pl011_can_receive(void *opaque)
cdbdb648 242{
ab640bfc 243 PL011State *s = (PL011State *)opaque;
041ac056 244 int r;
cdbdb648 245
041ac056
PM
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;
cdbdb648
PB
253}
254
cc9c9ffc 255static void pl011_put_fifo(void *opaque, uint32_t value)
cdbdb648 256{
ab640bfc 257 PL011State *s = (PL011State *)opaque;
cdbdb648
PB
258 int slot;
259
260 slot = s->read_pos + s->read_count;
261 if (slot >= 16)
262 slot -= 16;
cc9c9ffc 263 s->read_fifo[slot] = value;
cdbdb648
PB
264 s->read_count++;
265 s->flags &= ~PL011_FLAG_RXFE;
041ac056 266 trace_pl011_put_fifo(value, s->read_count);
f72dbf3d 267 if (!(s->lcr & 0x10) || s->read_count == 16) {
041ac056 268 trace_pl011_put_fifo_full();
cdbdb648
PB
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
cc9c9ffc
AJ
277static void pl011_receive(void *opaque, const uint8_t *buf, int size)
278{
279 pl011_put_fifo(opaque, *buf);
280}
281
cdbdb648
PB
282static void pl011_event(void *opaque, int event)
283{
cc9c9ffc
AJ
284 if (event == CHR_EVENT_BREAK)
285 pl011_put_fifo(opaque, 0x400);
cdbdb648
PB
286}
287
48484757
AK
288static const MemoryRegionOps pl011_ops = {
289 .read = pl011_read,
290 .write = pl011_write,
291 .endianness = DEVICE_NATIVE_ENDIAN,
cdbdb648
PB
292};
293
02b68757
JQ
294static const VMStateDescription vmstate_pl011 = {
295 .name = "pl011",
ce8f0905
RH
296 .version_id = 2,
297 .minimum_version_id = 2,
8f1e884b 298 .fields = (VMStateField[]) {
ab640bfc
AF
299 VMSTATE_UINT32(readbuff, PL011State),
300 VMSTATE_UINT32(flags, PL011State),
301 VMSTATE_UINT32(lcr, PL011State),
ce8f0905 302 VMSTATE_UINT32(rsr, PL011State),
ab640bfc
AF
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),
02b68757
JQ
315 VMSTATE_END_OF_LIST()
316 }
317};
23e39294 318
f0d1d2c1
XZ
319static Property pl011_properties[] = {
320 DEFINE_PROP_CHR("chardev", PL011State, chr),
321 DEFINE_PROP_END_OF_LIST(),
322};
323
71ffe1a0 324static void pl011_init(Object *obj)
cdbdb648 325{
71ffe1a0
AF
326 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
327 PL011State *s = PL011(obj);
a3c1ca56 328 int i;
cdbdb648 329
300b1fc6 330 memory_region_init_io(&s->iomem, OBJECT(s), &pl011_ops, s, "pl011", 0x1000);
71ffe1a0 331 sysbus_init_mmio(sbd, &s->iomem);
a3c1ca56
PM
332 for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
333 sysbus_init_irq(sbd, &s->irq[i]);
334 }
a7d518a6 335
cdbdb648
PB
336 s->read_trigger = 1;
337 s->ifl = 0x12;
338 s->cr = 0x300;
339 s->flags = 0x90;
a7d518a6 340
71ffe1a0 341 s->id = pl011_id_arm;
a7d518a6
PB
342}
343
71ffe1a0 344static void pl011_realize(DeviceState *dev, Error **errp)
a7d518a6 345{
71ffe1a0
AF
346 PL011State *s = PL011(dev);
347
fa394ed6 348 qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive,
81517ba3 349 pl011_event, NULL, s, NULL, true);
a7d518a6
PB
350}
351
71ffe1a0 352static void pl011_class_init(ObjectClass *oc, void *data)
999e12bb 353{
71ffe1a0 354 DeviceClass *dc = DEVICE_CLASS(oc);
999e12bb 355
71ffe1a0
AF
356 dc->realize = pl011_realize;
357 dc->vmsd = &vmstate_pl011;
f0d1d2c1 358 dc->props = pl011_properties;
999e12bb
AL
359}
360
8c43a6f0 361static const TypeInfo pl011_arm_info = {
71ffe1a0 362 .name = TYPE_PL011,
39bffca2 363 .parent = TYPE_SYS_BUS_DEVICE,
ab640bfc 364 .instance_size = sizeof(PL011State),
71ffe1a0
AF
365 .instance_init = pl011_init,
366 .class_init = pl011_class_init,
999e12bb
AL
367};
368
71ffe1a0 369static void pl011_luminary_init(Object *obj)
999e12bb 370{
71ffe1a0 371 PL011State *s = PL011(obj);
999e12bb 372
71ffe1a0 373 s->id = pl011_id_luminary;
999e12bb
AL
374}
375
8c43a6f0 376static const TypeInfo pl011_luminary_info = {
694cf209 377 .name = TYPE_PL011_LUMINARY,
71ffe1a0
AF
378 .parent = TYPE_PL011,
379 .instance_init = pl011_luminary_init,
999e12bb
AL
380};
381
83f7d43a 382static void pl011_register_types(void)
a7d518a6 383{
39bffca2
AL
384 type_register_static(&pl011_arm_info);
385 type_register_static(&pl011_luminary_info);
a7d518a6
PB
386}
387
83f7d43a 388type_init(pl011_register_types)
This page took 1.061722 seconds and 4 git commands to generate.