]> git.proxmox.com Git - qemu.git/blame - hw/char/pl011.c
sysemu: avoid proliferation of include/ subdirectories
[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
83c9f4ca 10#include "hw/sysbus.h"
dccfcd0e 11#include "sysemu/char.h"
cdbdb648
PB
12
13typedef struct {
a7d518a6 14 SysBusDevice busdev;
48484757 15 MemoryRegion iomem;
cdbdb648
PB
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;
d537cf6c 32 qemu_irq irq;
a7d518a6 33 const unsigned char *id;
cdbdb648
PB
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
a7d518a6
PB
44static const unsigned char pl011_id_arm[8] =
45 { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
46static const unsigned char pl011_id_luminary[8] =
47 { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
cdbdb648
PB
48
49static void pl011_update(pl011_state *s)
50{
51 uint32_t flags;
3b46e624 52
cdbdb648 53 flags = s->int_level & s->int_enabled;
d537cf6c 54 qemu_set_irq(s->irq, flags != 0);
cdbdb648
PB
55}
56
a8170e5e 57static uint64_t pl011_read(void *opaque, hwaddr offset,
48484757 58 unsigned size)
cdbdb648
PB
59{
60 pl011_state *s = (pl011_state *)opaque;
61 uint32_t c;
62
cdbdb648 63 if (offset >= 0xfe0 && offset < 0x1000) {
a7d518a6 64 return s->id[(offset - 0xfe0) >> 2];
cdbdb648
PB
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);
0d4abda8
PM
81 if (s->chr) {
82 qemu_chr_accept_input(s->chr);
83 }
cdbdb648
PB
84 return c;
85 case 1: /* UARTCR */
86 return 0;
87 case 6: /* UARTFR */
88 return s->flags;
89 case 8: /* UARTILPR */
90 return s->ilpr;
91 case 9: /* UARTIBRD */
92 return s->ibrd;
93 case 10: /* UARTFBRD */
94 return s->fbrd;
95 case 11: /* UARTLCR_H */
96 return s->lcr;
97 case 12: /* UARTCR */
98 return s->cr;
99 case 13: /* UARTIFLS */
100 return s->ifl;
101 case 14: /* UARTIMSC */
102 return s->int_enabled;
103 case 15: /* UARTRIS */
104 return s->int_level;
105 case 16: /* UARTMIS */
106 return s->int_level & s->int_enabled;
107 case 18: /* UARTDMACR */
108 return s->dmacr;
109 default:
6d5433e0
PM
110 qemu_log_mask(LOG_GUEST_ERROR,
111 "pl011_read: Bad offset %x\n", (int)offset);
cdbdb648
PB
112 return 0;
113 }
114}
115
116static void pl011_set_read_trigger(pl011_state *s)
117{
118#if 0
119 /* The docs say the RX interrupt is triggered when the FIFO exceeds
120 the threshold. However linux only reads the FIFO in response to an
121 interrupt. Triggering the interrupt when the FIFO is non-empty seems
122 to make things work. */
123 if (s->lcr & 0x10)
124 s->read_trigger = (s->ifl >> 1) & 0x1c;
125 else
126#endif
127 s->read_trigger = 1;
128}
129
a8170e5e 130static void pl011_write(void *opaque, hwaddr offset,
48484757 131 uint64_t value, unsigned size)
cdbdb648
PB
132{
133 pl011_state *s = (pl011_state *)opaque;
134 unsigned char ch;
135
cdbdb648
PB
136 switch (offset >> 2) {
137 case 0: /* UARTDR */
138 /* ??? Check if transmitter is enabled. */
139 ch = value;
140 if (s->chr)
2cc6e0a1 141 qemu_chr_fe_write(s->chr, &ch, 1);
cdbdb648
PB
142 s->int_level |= PL011_INT_TX;
143 pl011_update(s);
144 break;
145 case 1: /* UARTCR */
146 s->cr = value;
147 break;
9ee6e8bb
PB
148 case 6: /* UARTFR */
149 /* Writes to Flag register are ignored. */
150 break;
cdbdb648
PB
151 case 8: /* UARTUARTILPR */
152 s->ilpr = value;
153 break;
154 case 9: /* UARTIBRD */
155 s->ibrd = value;
156 break;
157 case 10: /* UARTFBRD */
158 s->fbrd = value;
159 break;
160 case 11: /* UARTLCR_H */
161 s->lcr = value;
162 pl011_set_read_trigger(s);
163 break;
164 case 12: /* UARTCR */
165 /* ??? Need to implement the enable and loopback bits. */
166 s->cr = value;
167 break;
168 case 13: /* UARTIFS */
169 s->ifl = value;
170 pl011_set_read_trigger(s);
171 break;
172 case 14: /* UARTIMSC */
173 s->int_enabled = value;
174 pl011_update(s);
175 break;
176 case 17: /* UARTICR */
177 s->int_level &= ~value;
178 pl011_update(s);
179 break;
180 case 18: /* UARTDMACR */
181 s->dmacr = value;
6d5433e0
PM
182 if (value & 3) {
183 qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n");
184 }
cdbdb648
PB
185 break;
186 default:
6d5433e0
PM
187 qemu_log_mask(LOG_GUEST_ERROR,
188 "pl011_write: Bad offset %x\n", (int)offset);
cdbdb648
PB
189 }
190}
191
aa1f17c1 192static int pl011_can_receive(void *opaque)
cdbdb648
PB
193{
194 pl011_state *s = (pl011_state *)opaque;
195
196 if (s->lcr & 0x10)
197 return s->read_count < 16;
198 else
199 return s->read_count < 1;
200}
201
cc9c9ffc 202static void pl011_put_fifo(void *opaque, uint32_t value)
cdbdb648
PB
203{
204 pl011_state *s = (pl011_state *)opaque;
205 int slot;
206
207 slot = s->read_pos + s->read_count;
208 if (slot >= 16)
209 slot -= 16;
cc9c9ffc 210 s->read_fifo[slot] = value;
cdbdb648
PB
211 s->read_count++;
212 s->flags &= ~PL011_FLAG_RXFE;
213 if (s->cr & 0x10 || s->read_count == 16) {
214 s->flags |= PL011_FLAG_RXFF;
215 }
216 if (s->read_count == s->read_trigger) {
217 s->int_level |= PL011_INT_RX;
218 pl011_update(s);
219 }
220}
221
cc9c9ffc
AJ
222static void pl011_receive(void *opaque, const uint8_t *buf, int size)
223{
224 pl011_put_fifo(opaque, *buf);
225}
226
cdbdb648
PB
227static void pl011_event(void *opaque, int event)
228{
cc9c9ffc
AJ
229 if (event == CHR_EVENT_BREAK)
230 pl011_put_fifo(opaque, 0x400);
cdbdb648
PB
231}
232
48484757
AK
233static const MemoryRegionOps pl011_ops = {
234 .read = pl011_read,
235 .write = pl011_write,
236 .endianness = DEVICE_NATIVE_ENDIAN,
cdbdb648
PB
237};
238
02b68757
JQ
239static const VMStateDescription vmstate_pl011 = {
240 .name = "pl011",
241 .version_id = 1,
242 .minimum_version_id = 1,
243 .minimum_version_id_old = 1,
244 .fields = (VMStateField[]) {
245 VMSTATE_UINT32(readbuff, pl011_state),
246 VMSTATE_UINT32(flags, pl011_state),
247 VMSTATE_UINT32(lcr, pl011_state),
248 VMSTATE_UINT32(cr, pl011_state),
249 VMSTATE_UINT32(dmacr, pl011_state),
250 VMSTATE_UINT32(int_enabled, pl011_state),
251 VMSTATE_UINT32(int_level, pl011_state),
252 VMSTATE_UINT32_ARRAY(read_fifo, pl011_state, 16),
253 VMSTATE_UINT32(ilpr, pl011_state),
254 VMSTATE_UINT32(ibrd, pl011_state),
255 VMSTATE_UINT32(fbrd, pl011_state),
256 VMSTATE_UINT32(ifl, pl011_state),
257 VMSTATE_INT32(read_pos, pl011_state),
258 VMSTATE_INT32(read_count, pl011_state),
259 VMSTATE_INT32(read_trigger, pl011_state),
260 VMSTATE_END_OF_LIST()
261 }
262};
23e39294 263
81a322d4 264static int pl011_init(SysBusDevice *dev, const unsigned char *id)
cdbdb648 265{
a7d518a6 266 pl011_state *s = FROM_SYSBUS(pl011_state, dev);
cdbdb648 267
48484757 268 memory_region_init_io(&s->iomem, &pl011_ops, s, "pl011", 0x1000);
750ecd44 269 sysbus_init_mmio(dev, &s->iomem);
a7d518a6
PB
270 sysbus_init_irq(dev, &s->irq);
271 s->id = id;
0beb4942 272 s->chr = qemu_char_get_next_serial();
a7d518a6 273
cdbdb648
PB
274 s->read_trigger = 1;
275 s->ifl = 0x12;
276 s->cr = 0x300;
277 s->flags = 0x90;
a7d518a6
PB
278 if (s->chr) {
279 qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive,
e5b0bc44 280 pl011_event, s);
cdbdb648 281 }
02b68757 282 vmstate_register(&dev->qdev, -1, &vmstate_pl011, s);
81a322d4 283 return 0;
cdbdb648 284}
a7d518a6 285
999e12bb 286static int pl011_arm_init(SysBusDevice *dev)
a7d518a6 287{
81a322d4 288 return pl011_init(dev, pl011_id_arm);
a7d518a6
PB
289}
290
999e12bb 291static int pl011_luminary_init(SysBusDevice *dev)
a7d518a6 292{
81a322d4 293 return pl011_init(dev, pl011_id_luminary);
a7d518a6
PB
294}
295
999e12bb
AL
296static void pl011_arm_class_init(ObjectClass *klass, void *data)
297{
298 SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
299
300 sdc->init = pl011_arm_init;
301}
302
8c43a6f0 303static const TypeInfo pl011_arm_info = {
39bffca2
AL
304 .name = "pl011",
305 .parent = TYPE_SYS_BUS_DEVICE,
306 .instance_size = sizeof(pl011_state),
307 .class_init = pl011_arm_class_init,
999e12bb
AL
308};
309
310static void pl011_luminary_class_init(ObjectClass *klass, void *data)
311{
312 SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
313
314 sdc->init = pl011_luminary_init;
315}
316
8c43a6f0 317static const TypeInfo pl011_luminary_info = {
39bffca2
AL
318 .name = "pl011_luminary",
319 .parent = TYPE_SYS_BUS_DEVICE,
320 .instance_size = sizeof(pl011_state),
321 .class_init = pl011_luminary_class_init,
999e12bb
AL
322};
323
83f7d43a 324static void pl011_register_types(void)
a7d518a6 325{
39bffca2
AL
326 type_register_static(&pl011_arm_info);
327 type_register_static(&pl011_luminary_info);
a7d518a6
PB
328}
329
83f7d43a 330type_init(pl011_register_types)