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