]> git.ipfire.org Git - thirdparty/qemu.git/blame - hw/dma/pl080.c
Include migration/vmstate.h less
[thirdparty/qemu.git] / hw / dma / pl080.c
CommitLineData
5fafdf24 1/*
e69954b9 2 * Arm PrimeCell PL080/PL081 DMA controller
cdbdb648
PB
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"
d6454270 12#include "migration/vmstate.h"
fdfba1a2 13#include "exec/address-spaces.h"
03dd024f 14#include "qemu/log.h"
0b8fa32f 15#include "qemu/module.h"
aa74e355 16#include "hw/dma/pl080.h"
64552b6b 17#include "hw/irq.h"
112a829f 18#include "qapi/error.h"
cdbdb648 19
cdbdb648
PB
20#define PL080_CONF_E 0x1
21#define PL080_CONF_M1 0x2
22#define PL080_CONF_M2 0x4
23
24#define PL080_CCONF_H 0x40000
25#define PL080_CCONF_A 0x20000
26#define PL080_CCONF_L 0x10000
27#define PL080_CCONF_ITC 0x08000
28#define PL080_CCONF_IE 0x04000
29#define PL080_CCONF_E 0x00001
30
31#define PL080_CCTRL_I 0x80000000
32#define PL080_CCTRL_DI 0x08000000
33#define PL080_CCTRL_SI 0x04000000
34#define PL080_CCTRL_D 0x02000000
35#define PL080_CCTRL_S 0x01000000
36
ff175853
PM
37static const VMStateDescription vmstate_pl080_channel = {
38 .name = "pl080_channel",
39 .version_id = 1,
40 .minimum_version_id = 1,
41 .fields = (VMStateField[]) {
42 VMSTATE_UINT32(src, pl080_channel),
43 VMSTATE_UINT32(dest, pl080_channel),
44 VMSTATE_UINT32(lli, pl080_channel),
45 VMSTATE_UINT32(ctrl, pl080_channel),
46 VMSTATE_UINT32(conf, pl080_channel),
47 VMSTATE_END_OF_LIST()
48 }
49};
50
51static const VMStateDescription vmstate_pl080 = {
52 .name = "pl080",
53 .version_id = 1,
54 .minimum_version_id = 1,
55 .fields = (VMStateField[]) {
d7ba0a62
AF
56 VMSTATE_UINT8(tc_int, PL080State),
57 VMSTATE_UINT8(tc_mask, PL080State),
58 VMSTATE_UINT8(err_int, PL080State),
59 VMSTATE_UINT8(err_mask, PL080State),
60 VMSTATE_UINT32(conf, PL080State),
61 VMSTATE_UINT32(sync, PL080State),
62 VMSTATE_UINT32(req_single, PL080State),
63 VMSTATE_UINT32(req_burst, PL080State),
64 VMSTATE_UINT8(tc_int, PL080State),
65 VMSTATE_UINT8(tc_int, PL080State),
66 VMSTATE_UINT8(tc_int, PL080State),
67 VMSTATE_STRUCT_ARRAY(chan, PL080State, PL080_MAX_CHANNELS,
ff175853 68 1, vmstate_pl080_channel, pl080_channel),
d7ba0a62 69 VMSTATE_INT32(running, PL080State),
ff175853
PM
70 VMSTATE_END_OF_LIST()
71 }
72};
73
cdbdb648
PB
74static const unsigned char pl080_id[] =
75{ 0x80, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 };
76
e69954b9
PB
77static const unsigned char pl081_id[] =
78{ 0x81, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 };
79
d7ba0a62 80static void pl080_update(PL080State *s)
cdbdb648 81{
6d0ed6ba
PM
82 bool tclevel = (s->tc_int & s->tc_mask);
83 bool errlevel = (s->err_int & s->err_mask);
84
85 qemu_set_irq(s->interr, errlevel);
86 qemu_set_irq(s->inttc, tclevel);
87 qemu_set_irq(s->irq, errlevel || tclevel);
cdbdb648
PB
88}
89
d7ba0a62 90static void pl080_run(PL080State *s)
cdbdb648
PB
91{
92 int c;
93 int flow;
94 pl080_channel *ch;
95 int swidth;
96 int dwidth;
97 int xsize;
98 int n;
99 int src_id;
100 int dest_id;
101 int size;
b55266b5 102 uint8_t buff[4];
cdbdb648
PB
103 uint32_t req;
104
105 s->tc_mask = 0;
e69954b9 106 for (c = 0; c < s->nchannels; c++) {
cdbdb648
PB
107 if (s->chan[c].conf & PL080_CCONF_ITC)
108 s->tc_mask |= 1 << c;
109 if (s->chan[c].conf & PL080_CCONF_IE)
110 s->err_mask |= 1 << c;
111 }
112
113 if ((s->conf & PL080_CONF_E) == 0)
114 return;
115
cdbdb648
PB
116 /* If we are already in the middle of a DMA operation then indicate that
117 there may be new DMA requests and return immediately. */
118 if (s->running) {
119 s->running++;
120 return;
121 }
122 s->running = 1;
123 while (s->running) {
e69954b9 124 for (c = 0; c < s->nchannels; c++) {
cdbdb648
PB
125 ch = &s->chan[c];
126again:
127 /* Test if thiws channel has any pending DMA requests. */
128 if ((ch->conf & (PL080_CCONF_H | PL080_CCONF_E))
129 != PL080_CCONF_E)
130 continue;
131 flow = (ch->conf >> 11) & 7;
132 if (flow >= 4) {
2ac71179 133 hw_error(
cdbdb648
PB
134 "pl080_run: Peripheral flow control not implemented\n");
135 }
136 src_id = (ch->conf >> 1) & 0x1f;
137 dest_id = (ch->conf >> 6) & 0x1f;
138 size = ch->ctrl & 0xfff;
139 req = s->req_single | s->req_burst;
140 switch (flow) {
141 case 0:
142 break;
143 case 1:
144 if ((req & (1u << dest_id)) == 0)
145 size = 0;
146 break;
147 case 2:
148 if ((req & (1u << src_id)) == 0)
149 size = 0;
150 break;
151 case 3:
152 if ((req & (1u << src_id)) == 0
153 || (req & (1u << dest_id)) == 0)
154 size = 0;
155 break;
156 }
157 if (!size)
158 continue;
159
160 /* Transfer one element. */
161 /* ??? Should transfer multiple elements for a burst request. */
162 /* ??? Unclear what the proper behavior is when source and
163 destination widths are different. */
164 swidth = 1 << ((ch->ctrl >> 18) & 7);
165 dwidth = 1 << ((ch->ctrl >> 21) & 7);
166 for (n = 0; n < dwidth; n+= swidth) {
112a829f
PM
167 address_space_read(&s->downstream_as, ch->src,
168 MEMTXATTRS_UNSPECIFIED, buff + n, swidth);
cdbdb648
PB
169 if (ch->ctrl & PL080_CCTRL_SI)
170 ch->src += swidth;
171 }
172 xsize = (dwidth < swidth) ? swidth : dwidth;
173 /* ??? This may pad the value incorrectly for dwidth < 32. */
174 for (n = 0; n < xsize; n += dwidth) {
112a829f
PM
175 address_space_write(&s->downstream_as, ch->dest + n,
176 MEMTXATTRS_UNSPECIFIED, buff + n, dwidth);
cdbdb648
PB
177 if (ch->ctrl & PL080_CCTRL_DI)
178 ch->dest += swidth;
179 }
180
181 size--;
182 ch->ctrl = (ch->ctrl & 0xfffff000) | size;
183 if (size == 0) {
184 /* Transfer complete. */
185 if (ch->lli) {
112a829f 186 ch->src = address_space_ldl_le(&s->downstream_as,
42874d3a
PM
187 ch->lli,
188 MEMTXATTRS_UNSPECIFIED,
189 NULL);
112a829f 190 ch->dest = address_space_ldl_le(&s->downstream_as,
42874d3a
PM
191 ch->lli + 4,
192 MEMTXATTRS_UNSPECIFIED,
193 NULL);
112a829f 194 ch->ctrl = address_space_ldl_le(&s->downstream_as,
42874d3a
PM
195 ch->lli + 12,
196 MEMTXATTRS_UNSPECIFIED,
197 NULL);
112a829f 198 ch->lli = address_space_ldl_le(&s->downstream_as,
42874d3a
PM
199 ch->lli + 8,
200 MEMTXATTRS_UNSPECIFIED,
201 NULL);
cdbdb648
PB
202 } else {
203 ch->conf &= ~PL080_CCONF_E;
204 }
205 if (ch->ctrl & PL080_CCTRL_I) {
206 s->tc_int |= 1 << c;
207 }
208 }
209 goto again;
210 }
211 if (--s->running)
212 s->running = 1;
213 }
214}
215
a8170e5e 216static uint64_t pl080_read(void *opaque, hwaddr offset,
63b02e04 217 unsigned size)
cdbdb648 218{
d7ba0a62 219 PL080State *s = (PL080State *)opaque;
cdbdb648
PB
220 uint32_t i;
221 uint32_t mask;
222
cdbdb648 223 if (offset >= 0xfe0 && offset < 0x1000) {
e69954b9
PB
224 if (s->nchannels == 8) {
225 return pl080_id[(offset - 0xfe0) >> 2];
226 } else {
227 return pl081_id[(offset - 0xfe0) >> 2];
228 }
cdbdb648
PB
229 }
230 if (offset >= 0x100 && offset < 0x200) {
231 i = (offset & 0xe0) >> 5;
e69954b9
PB
232 if (i >= s->nchannels)
233 goto bad_offset;
156448ab 234 switch ((offset >> 2) & 7) {
cdbdb648
PB
235 case 0: /* SrcAddr */
236 return s->chan[i].src;
237 case 1: /* DestAddr */
238 return s->chan[i].dest;
239 case 2: /* LLI */
240 return s->chan[i].lli;
241 case 3: /* Control */
242 return s->chan[i].ctrl;
243 case 4: /* Configuration */
244 return s->chan[i].conf;
245 default:
246 goto bad_offset;
247 }
248 }
249 switch (offset >> 2) {
250 case 0: /* IntStatus */
251 return (s->tc_int & s->tc_mask) | (s->err_int & s->err_mask);
252 case 1: /* IntTCStatus */
253 return (s->tc_int & s->tc_mask);
254 case 3: /* IntErrorStatus */
255 return (s->err_int & s->err_mask);
256 case 5: /* RawIntTCStatus */
257 return s->tc_int;
258 case 6: /* RawIntErrorStatus */
259 return s->err_int;
260 case 7: /* EnbldChns */
261 mask = 0;
e69954b9 262 for (i = 0; i < s->nchannels; i++) {
cdbdb648
PB
263 if (s->chan[i].conf & PL080_CCONF_E)
264 mask |= 1 << i;
265 }
266 return mask;
267 case 8: /* SoftBReq */
268 case 9: /* SoftSReq */
269 case 10: /* SoftLBReq */
270 case 11: /* SoftLSReq */
271 /* ??? Implement these. */
272 return 0;
273 case 12: /* Configuration */
274 return s->conf;
275 case 13: /* Sync */
276 return s->sync;
277 default:
278 bad_offset:
df374162
PM
279 qemu_log_mask(LOG_GUEST_ERROR,
280 "pl080_read: Bad offset %x\n", (int)offset);
cdbdb648
PB
281 return 0;
282 }
283}
284
a8170e5e 285static void pl080_write(void *opaque, hwaddr offset,
63b02e04 286 uint64_t value, unsigned size)
cdbdb648 287{
d7ba0a62 288 PL080State *s = (PL080State *)opaque;
cdbdb648
PB
289 int i;
290
cdbdb648
PB
291 if (offset >= 0x100 && offset < 0x200) {
292 i = (offset & 0xe0) >> 5;
e69954b9
PB
293 if (i >= s->nchannels)
294 goto bad_offset;
156448ab 295 switch ((offset >> 2) & 7) {
cdbdb648
PB
296 case 0: /* SrcAddr */
297 s->chan[i].src = value;
298 break;
299 case 1: /* DestAddr */
300 s->chan[i].dest = value;
301 break;
302 case 2: /* LLI */
303 s->chan[i].lli = value;
304 break;
305 case 3: /* Control */
306 s->chan[i].ctrl = value;
307 break;
308 case 4: /* Configuration */
309 s->chan[i].conf = value;
310 pl080_run(s);
311 break;
312 }
156448ab 313 return;
cdbdb648
PB
314 }
315 switch (offset >> 2) {
316 case 2: /* IntTCClear */
317 s->tc_int &= ~value;
318 break;
319 case 4: /* IntErrorClear */
320 s->err_int &= ~value;
321 break;
322 case 8: /* SoftBReq */
323 case 9: /* SoftSReq */
324 case 10: /* SoftLBReq */
325 case 11: /* SoftLSReq */
326 /* ??? Implement these. */
df374162 327 qemu_log_mask(LOG_UNIMP, "pl080_write: Soft DMA not implemented\n");
cdbdb648
PB
328 break;
329 case 12: /* Configuration */
330 s->conf = value;
04bb79d1 331 if (s->conf & (PL080_CONF_M1 | PL080_CONF_M2)) {
df374162
PM
332 qemu_log_mask(LOG_UNIMP,
333 "pl080_write: Big-endian DMA not implemented\n");
cdbdb648
PB
334 }
335 pl080_run(s);
336 break;
337 case 13: /* Sync */
338 s->sync = value;
339 break;
340 default:
e69954b9 341 bad_offset:
df374162
PM
342 qemu_log_mask(LOG_GUEST_ERROR,
343 "pl080_write: Bad offset %x\n", (int)offset);
cdbdb648
PB
344 }
345 pl080_update(s);
346}
347
63b02e04
AK
348static const MemoryRegionOps pl080_ops = {
349 .read = pl080_read,
350 .write = pl080_write,
351 .endianness = DEVICE_NATIVE_ENDIAN,
cdbdb648
PB
352};
353
c193304d
PM
354static void pl080_reset(DeviceState *dev)
355{
356 PL080State *s = PL080(dev);
357 int i;
358
359 s->tc_int = 0;
360 s->tc_mask = 0;
361 s->err_int = 0;
362 s->err_mask = 0;
363 s->conf = 0;
364 s->sync = 0;
365 s->req_single = 0;
366 s->req_burst = 0;
367 s->running = 0;
368
369 for (i = 0; i < s->nchannels; i++) {
370 s->chan[i].src = 0;
371 s->chan[i].dest = 0;
372 s->chan[i].lli = 0;
373 s->chan[i].ctrl = 0;
374 s->chan[i].conf = 0;
375 }
376}
377
4f800554 378static void pl080_init(Object *obj)
cdbdb648 379{
4f800554
AF
380 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
381 PL080State *s = PL080(obj);
cdbdb648 382
3eadad55 383 memory_region_init_io(&s->iomem, OBJECT(s), &pl080_ops, s, "pl080", 0x1000);
4f800554
AF
384 sysbus_init_mmio(sbd, &s->iomem);
385 sysbus_init_irq(sbd, &s->irq);
6d0ed6ba
PM
386 sysbus_init_irq(sbd, &s->interr);
387 sysbus_init_irq(sbd, &s->inttc);
4f800554 388 s->nchannels = 8;
cdbdb648 389}
b4496b13 390
112a829f
PM
391static void pl080_realize(DeviceState *dev, Error **errp)
392{
393 PL080State *s = PL080(dev);
394
395 if (!s->downstream) {
396 error_setg(errp, "PL080 'downstream' link not set");
397 return;
398 }
399
400 address_space_init(&s->downstream_as, s->downstream, "pl080-downstream");
401}
402
4f800554 403static void pl081_init(Object *obj)
b4496b13 404{
4f800554 405 PL080State *s = PL080(obj);
b4496b13 406
4f800554 407 s->nchannels = 2;
b4496b13
PB
408}
409
112a829f
PM
410static Property pl080_properties[] = {
411 DEFINE_PROP_LINK("downstream", PL080State, downstream,
412 TYPE_MEMORY_REGION, MemoryRegion *),
413 DEFINE_PROP_END_OF_LIST(),
414};
415
4f800554 416static void pl080_class_init(ObjectClass *oc, void *data)
999e12bb 417{
4f800554 418 DeviceClass *dc = DEVICE_CLASS(oc);
999e12bb 419
39bffca2 420 dc->vmsd = &vmstate_pl080;
112a829f
PM
421 dc->realize = pl080_realize;
422 dc->props = pl080_properties;
c193304d 423 dc->reset = pl080_reset;
999e12bb
AL
424}
425
8c43a6f0 426static const TypeInfo pl080_info = {
4f800554 427 .name = TYPE_PL080,
39bffca2 428 .parent = TYPE_SYS_BUS_DEVICE,
d7ba0a62 429 .instance_size = sizeof(PL080State),
4f800554 430 .instance_init = pl080_init,
39bffca2 431 .class_init = pl080_class_init,
ff175853
PM
432};
433
8c43a6f0 434static const TypeInfo pl081_info = {
aa74e355 435 .name = TYPE_PL081,
4f800554
AF
436 .parent = TYPE_PL080,
437 .instance_init = pl081_init,
ff175853
PM
438};
439
b4496b13
PB
440/* The PL080 and PL081 are the same except for the number of channels
441 they implement (8 and 2 respectively). */
83f7d43a 442static void pl080_register_types(void)
b4496b13 443{
39bffca2
AL
444 type_register_static(&pl080_info);
445 type_register_static(&pl081_info);
b4496b13
PB
446}
447
83f7d43a 448type_init(pl080_register_types)