1
2
3
4
5
6
7
8
9
10#include "qemu/osdep.h"
11#include "hw/sysbus.h"
12#include "sysemu/char.h"
13#include "qemu/log.h"
14
15#define TYPE_PL011 "pl011"
16#define PL011(obj) OBJECT_CHECK(PL011State, (obj), TYPE_PL011)
17
18typedef struct PL011State {
19 SysBusDevice parent_obj;
20
21 MemoryRegion iomem;
22 uint32_t readbuff;
23 uint32_t flags;
24 uint32_t lcr;
25 uint32_t rsr;
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;
39 qemu_irq irq;
40 const unsigned char *id;
41} PL011State;
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
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 };
55
56static void pl011_update(PL011State *s)
57{
58 uint32_t flags;
59
60 flags = s->int_level & s->int_enabled;
61 qemu_set_irq(s->irq, flags != 0);
62}
63
64static uint64_t pl011_read(void *opaque, hwaddr offset,
65 unsigned size)
66{
67 PL011State *s = (PL011State *)opaque;
68 uint32_t c;
69
70 if (offset >= 0xfe0 && offset < 0x1000) {
71 return s->id[(offset - 0xfe0) >> 2];
72 }
73 switch (offset >> 2) {
74 case 0:
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 s->rsr = c >> 8;
88 pl011_update(s);
89 if (s->chr) {
90 qemu_chr_accept_input(s->chr);
91 }
92 return c;
93 case 1:
94 return s->rsr;
95 case 6:
96 return s->flags;
97 case 8:
98 return s->ilpr;
99 case 9:
100 return s->ibrd;
101 case 10:
102 return s->fbrd;
103 case 11:
104 return s->lcr;
105 case 12:
106 return s->cr;
107 case 13:
108 return s->ifl;
109 case 14:
110 return s->int_enabled;
111 case 15:
112 return s->int_level;
113 case 16:
114 return s->int_level & s->int_enabled;
115 case 18:
116 return s->dmacr;
117 default:
118 qemu_log_mask(LOG_GUEST_ERROR,
119 "pl011_read: Bad offset %x\n", (int)offset);
120 return 0;
121 }
122}
123
124static void pl011_set_read_trigger(PL011State *s)
125{
126#if 0
127
128
129
130
131 if (s->lcr & 0x10)
132 s->read_trigger = (s->ifl >> 1) & 0x1c;
133 else
134#endif
135 s->read_trigger = 1;
136}
137
138static void pl011_write(void *opaque, hwaddr offset,
139 uint64_t value, unsigned size)
140{
141 PL011State *s = (PL011State *)opaque;
142 unsigned char ch;
143
144 switch (offset >> 2) {
145 case 0:
146
147 ch = value;
148 if (s->chr)
149 qemu_chr_fe_write(s->chr, &ch, 1);
150 s->int_level |= PL011_INT_TX;
151 pl011_update(s);
152 break;
153 case 1:
154 s->rsr = 0;
155 break;
156 case 6:
157
158 break;
159 case 8:
160 s->ilpr = value;
161 break;
162 case 9:
163 s->ibrd = value;
164 break;
165 case 10:
166 s->fbrd = value;
167 break;
168 case 11:
169
170 if ((s->lcr ^ value) & 0x10) {
171 s->read_count = 0;
172 s->read_pos = 0;
173 }
174 s->lcr = value;
175 pl011_set_read_trigger(s);
176 break;
177 case 12:
178
179 s->cr = value;
180 break;
181 case 13:
182 s->ifl = value;
183 pl011_set_read_trigger(s);
184 break;
185 case 14:
186 s->int_enabled = value;
187 pl011_update(s);
188 break;
189 case 17:
190 s->int_level &= ~value;
191 pl011_update(s);
192 break;
193 case 18:
194 s->dmacr = value;
195 if (value & 3) {
196 qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n");
197 }
198 break;
199 default:
200 qemu_log_mask(LOG_GUEST_ERROR,
201 "pl011_write: Bad offset %x\n", (int)offset);
202 }
203}
204
205static int pl011_can_receive(void *opaque)
206{
207 PL011State *s = (PL011State *)opaque;
208
209 if (s->lcr & 0x10)
210 return s->read_count < 16;
211 else
212 return s->read_count < 1;
213}
214
215static void pl011_put_fifo(void *opaque, uint32_t value)
216{
217 PL011State *s = (PL011State *)opaque;
218 int slot;
219
220 slot = s->read_pos + s->read_count;
221 if (slot >= 16)
222 slot -= 16;
223 s->read_fifo[slot] = value;
224 s->read_count++;
225 s->flags &= ~PL011_FLAG_RXFE;
226 if (!(s->lcr & 0x10) || s->read_count == 16) {
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
235static void pl011_receive(void *opaque, const uint8_t *buf, int size)
236{
237 pl011_put_fifo(opaque, *buf);
238}
239
240static void pl011_event(void *opaque, int event)
241{
242 if (event == CHR_EVENT_BREAK)
243 pl011_put_fifo(opaque, 0x400);
244}
245
246static const MemoryRegionOps pl011_ops = {
247 .read = pl011_read,
248 .write = pl011_write,
249 .endianness = DEVICE_NATIVE_ENDIAN,
250};
251
252static const VMStateDescription vmstate_pl011 = {
253 .name = "pl011",
254 .version_id = 2,
255 .minimum_version_id = 2,
256 .fields = (VMStateField[]) {
257 VMSTATE_UINT32(readbuff, PL011State),
258 VMSTATE_UINT32(flags, PL011State),
259 VMSTATE_UINT32(lcr, PL011State),
260 VMSTATE_UINT32(rsr, PL011State),
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),
273 VMSTATE_END_OF_LIST()
274 }
275};
276
277static void pl011_init(Object *obj)
278{
279 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
280 PL011State *s = PL011(obj);
281
282 memory_region_init_io(&s->iomem, OBJECT(s), &pl011_ops, s, "pl011", 0x1000);
283 sysbus_init_mmio(sbd, &s->iomem);
284 sysbus_init_irq(sbd, &s->irq);
285
286 s->read_trigger = 1;
287 s->ifl = 0x12;
288 s->cr = 0x300;
289 s->flags = 0x90;
290
291 s->id = pl011_id_arm;
292}
293
294static void pl011_realize(DeviceState *dev, Error **errp)
295{
296 PL011State *s = PL011(dev);
297
298
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 }
305}
306
307static void pl011_class_init(ObjectClass *oc, void *data)
308{
309 DeviceClass *dc = DEVICE_CLASS(oc);
310
311 dc->realize = pl011_realize;
312 dc->vmsd = &vmstate_pl011;
313
314 dc->cannot_instantiate_with_device_add_yet = true;
315}
316
317static const TypeInfo pl011_arm_info = {
318 .name = TYPE_PL011,
319 .parent = TYPE_SYS_BUS_DEVICE,
320 .instance_size = sizeof(PL011State),
321 .instance_init = pl011_init,
322 .class_init = pl011_class_init,
323};
324
325static void pl011_luminary_init(Object *obj)
326{
327 PL011State *s = PL011(obj);
328
329 s->id = pl011_id_luminary;
330}
331
332static const TypeInfo pl011_luminary_info = {
333 .name = "pl011_luminary",
334 .parent = TYPE_PL011,
335 .instance_init = pl011_luminary_init,
336};
337
338static void pl011_register_types(void)
339{
340 type_register_static(&pl011_arm_info);
341 type_register_static(&pl011_luminary_info);
342}
343
344type_init(pl011_register_types)
345