1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#include "qemu/osdep.h"
28#include "hw/sysbus.h"
29#include "qemu/log.h"
30
31#include "hw/stream.h"
32#include "hw/dma-ctrl.h"
33#include "hw/ptimer.h"
34#include "qemu/bitops.h"
35#include "sysemu/dma.h"
36#include "hw/register.h"
37#include "qapi/error.h"
38#include "qemu/main-loop.h"
39#include "migration/vmstate.h"
40#include "hw/qdev-properties.h"
41
42#include "hw/fdt_generic_util.h"
43
44#define TYPE_ZYNQMP_CSU_DMA "zynqmp.csu-dma"
45
46#define ZYNQMP_CSU_DMA(obj) \
47 OBJECT_CHECK(ZynqMPCSUDMA, (obj), TYPE_ZYNQMP_CSU_DMA)
48
49#ifndef ZYNQMP_CSU_DMA_ERR_DEBUG
50#define ZYNQMP_CSU_DMA_ERR_DEBUG 0
51#endif
52
53#define DB_PRINT_L(lvl, fmt, args...) do {\
54 if (ZYNQMP_CSU_DMA_ERR_DEBUG > lvl) {\
55 qemu_log(TYPE_ZYNQMP_CSU_DMA ": %s:" fmt, __func__, ## args);\
56 } \
57} while (0);
58
59#define DB_PRINT(fmt, args...) DB_PRINT_L(0, fmt, ##args)
60
61REG32(ADDR, 0x0)
62 FIELD(ADDR, ADDR, 2, 30)
63REG32(SIZE, 0x4)
64 FIELD(SIZE, SIZE, 2, 27)
65 FIELD(SIZE, LAST_WORD, 0, 1)
66REG32(STATUS, 0x8)
67 FIELD(STATUS, CMD_Q_EMPTY, 17, 1)
68 FIELD(STATUS, CMD_Q_FULL, 16, 1)
69 FIELD(STATUS, DONE_CNT, 13, 3)
70 FIELD(STATUS, SRC_FIFO_LEVEL, 5, 8)
71 FIELD(STATUS, RD_OUTSTANDING, 1, 4)
72 FIELD(STATUS, BUSY, 0, 1)
73REG32(CTRL, 0xc)
74 FIELD(CTRL, APB_ERR_RESP, 24, 1)
75 FIELD(CTRL, ENDIANNESS, 23, 1)
76 FIELD(CTRL, AXI_BRST_TYPE, 22, 1)
77 FIELD(CTRL, TIMEOUT_VAL, 10, 12)
78 FIELD(CTRL, FIFO_THRESH, 2, 8)
79 FIELD(CTRL, PAUSE_STRM, 1, 1)
80 FIELD(CTRL, PAUSE_MEM, 0, 1)
81REG32(CRC0, 0x10)
82REG32(INT_STATUS, 0x14)
83 FIELD(INT_STATUS, WR_FULL_CMDQ, 7, 1)
84 FIELD(INT_STATUS, INVALID_APB, 6, 1)
85 FIELD(INT_STATUS, THRESH_HIT, 5, 1)
86 FIELD(INT_STATUS, TIMEOUT_MEM, 4, 1)
87 FIELD(INT_STATUS, TIMEOUT_STRM, 3, 1)
88 FIELD(INT_STATUS, AXI_RDERR, 2, 1)
89 FIELD(INT_STATUS, DONE, 1, 1)
90 FIELD(INT_STATUS, MEM_DONE, 0, 1)
91REG32(INT_ENABLE, 0x18)
92 FIELD(INT_ENABLE, WR_FULL_CMDQ, 7, 1)
93 FIELD(INT_ENABLE, INVALID_APB, 6, 1)
94 FIELD(INT_ENABLE, THRESH_HIT, 5, 1)
95 FIELD(INT_ENABLE, TIMEOUT_MEM, 4, 1)
96 FIELD(INT_ENABLE, TIMEOUT_STRM, 3, 1)
97 FIELD(INT_ENABLE, AXI_RDERR, 2, 1)
98 FIELD(INT_ENABLE, DONE, 1, 1)
99 FIELD(INT_ENABLE, MEM_DONE, 0, 1)
100REG32(INT_DISABLE, 0x1c)
101 FIELD(INT_DISABLE, WR_FULL_CMDQ, 7, 1)
102 FIELD(INT_DISABLE, INVALID_APB, 6, 1)
103 FIELD(INT_DISABLE, THRESH_HIT, 5, 1)
104 FIELD(INT_DISABLE, TIMEOUT_MEM, 4, 1)
105 FIELD(INT_DISABLE, TIMEOUT_STRM, 3, 1)
106 FIELD(INT_DISABLE, AXI_RDERR, 2, 1)
107 FIELD(INT_DISABLE, DONE, 1, 1)
108 FIELD(INT_DISABLE, MEM_DONE, 0, 1)
109REG32(INT_MASK, 0x20)
110 FIELD(INT_MASK, WR_FULL_CMDQ, 7, 1)
111 FIELD(INT_MASK, INVALID_APB, 6, 1)
112 FIELD(INT_MASK, THRESH_HIT, 5, 1)
113 FIELD(INT_MASK, TIMEOUT_MEM, 4, 1)
114 FIELD(INT_MASK, TIMEOUT_STRM, 3, 1)
115 FIELD(INT_MASK, AXI_RDERR, 2, 1)
116 FIELD(INT_MASK, DONE, 1, 1)
117 FIELD(INT_MASK, MEM_DONE, 0, 1)
118REG32(CTRL2, 0x24)
119 FIELD(CTRL2, RAM_EMASA, 27, 1)
120 FIELD(CTRL2, ARCACHE, 24, 3)
121 FIELD(CTRL2, ROUTE_BIT, 23, 1)
122 FIELD(CTRL2, TIMEOUT_EN, 22, 1)
123 FIELD(CTRL2, RAM_EMAB, 19, 3)
124 FIELD(CTRL2, RAM_EMAA, 16, 3)
125 FIELD(CTRL2, TIMEOUT_PRE, 4, 12)
126 FIELD(CTRL2, MAX_OUTS_CMDS, 0, 4)
127REG32(ADDR_MSB, 0x28)
128 FIELD(ADDR_MSB, ADDR_MSB, 0, 17)
129
130#define R_MAX (R_ADDR_MSB + 1)
131
132
133#define CTRL_RSVD (~((1 << 25) - 1))
134
135#define INT_RSVD (~((1 << 8) - 1))
136#define INT_ALL_SRC ((~(INT_RSVD)) & (~(R_INT_STATUS_WR_FULL_CMDQ_MASK)))
137#define INT_ALL_DST ((~(INT_RSVD)) & (~(R_INT_STATUS_MEM_DONE_MASK)))
138
139#define CTRL2_RSVD (~((1 << 28) - 1))
140#define SIZE_MASK ((1 << 29) - 1)
141
142typedef struct ZynqMPCSUDMA {
143 SysBusDevice busdev;
144 MemoryRegion iomem;
145 MemTxAttrs *attr;
146 MemoryRegion *dma_mr;
147 AddressSpace *dma_as;
148 qemu_irq irq;
149 StreamSlave *tx_dev;
150 StreamSlave *tx_dev0;
151 StreamSlave *tx_dev1;
152 ptimer_state *src_timer;
153
154 bool is_dst;
155 bool byte_align;
156 uint16_t width;
157 uint32_t r_size_last_word_mask;
158
159 StreamCanPushNotifyFn notify;
160 void *notify_opaque;
161
162 dmactrl_notify_fn dma_ctrl_notify;
163 void *dma_ctrl_opaque;
164
165 uint32_t regs[R_MAX];
166 RegisterInfo regs_info[R_MAX];
167} ZynqMPCSUDMA;
168
169static bool dmach_is_paused(ZynqMPCSUDMA *s)
170{
171 bool paused;
172
173 paused = !!(s->regs[R_CTRL] & R_CTRL_PAUSE_STRM_MASK);
174 paused |= !!(s->regs[R_CTRL] & R_CTRL_PAUSE_MEM_MASK);
175 return paused;
176}
177
178static bool dmach_get_eop(ZynqMPCSUDMA *s)
179{
180 return !!(s->regs[R_SIZE] & s->r_size_last_word_mask);
181}
182
183static uint32_t dmach_get_size(ZynqMPCSUDMA *s)
184{
185 uint32_t ret;
186
187 if (s->byte_align) {
188 ret = s->regs[R_SIZE];
189 } else {
190 ret = s->regs[R_SIZE] & ~3;
191 }
192
193 ret &= SIZE_MASK;
194 return ret;
195}
196
197static void dmach_set_size(ZynqMPCSUDMA *s, uint32_t size)
198{
199 size &= SIZE_MASK;
200 if (!s->byte_align) {
201 assert((size & 3) == 0);
202 }
203 s->regs[R_SIZE] &= s->r_size_last_word_mask;
204 s->regs[R_SIZE] |= size;
205}
206
207static bool dmach_burst_is_fixed(ZynqMPCSUDMA *s)
208{
209 return !!(s->regs[R_CTRL] & R_CTRL_AXI_BRST_TYPE_MASK);
210}
211
212static bool dmach_timeout_enabled(ZynqMPCSUDMA *s)
213{
214 return s->regs[R_CTRL2] & R_CTRL2_TIMEOUT_EN_MASK;
215}
216
217static inline void dmach_update_dma_cnt(ZynqMPCSUDMA *s, int a)
218{
219 int cnt;
220
221
222 cnt = ARRAY_FIELD_EX32(s->regs, STATUS, DONE_CNT) + a;
223 ARRAY_FIELD_DP32(s->regs, STATUS, DONE_CNT, cnt);
224}
225
226static void dmach_done(ZynqMPCSUDMA *s)
227{
228 dmach_update_dma_cnt(s, +1);
229 s->regs[R_STATUS] &= ~R_STATUS_BUSY_MASK;
230
231 DB_PRINT("\n");
232 s->regs[R_INT_STATUS] |= R_INT_STATUS_DONE_MASK;
233 if (!s->is_dst) {
234 s->regs[R_INT_STATUS] |= R_INT_STATUS_MEM_DONE_MASK;
235 }
236}
237
238static void dmach_advance(ZynqMPCSUDMA *s, unsigned int len)
239{
240 uint32_t size = dmach_get_size(s);
241
242 if (!s->byte_align) {
243
244 assert((len & 3) == 0);
245 }
246 assert(len <= size);
247
248 if (!dmach_burst_is_fixed(s)) {
249 s->regs[R_ADDR] += len;
250 }
251
252 size -= len;
253 dmach_set_size(s, size);
254
255
256 if (size == 0 && s->dma_ctrl_notify) {
257 s->dma_ctrl_notify(s->dma_ctrl_opaque);
258 }
259
260 if (size == 0) {
261 dmach_done(s);
262 }
263}
264
265static void dmach_data_process(ZynqMPCSUDMA *s, uint8_t *buf, unsigned int len)
266{
267 unsigned int bswap;
268 unsigned int i;
269
270
271 bswap = s->regs[R_CTRL] & R_CTRL_ENDIANNESS_MASK;
272 if (s->is_dst && !bswap) {
273
274 return;
275 }
276
277 if (!s->byte_align) {
278
279 assert((len & 3) == 0);
280 }
281
282 for (i = 0; i < len; i += 4) {
283 uint8_t *b = &buf[i];
284 union {
285 uint8_t u8[4];
286 uint32_t u32;
287 } v = {
288 .u8 = { b[0], b[1], b[2], b[3] }
289 };
290
291 if (!s->is_dst) {
292 s->regs[R_CRC0] += v.u32;
293 }
294 if (bswap) {
295
296
297 b[0] = v.u8[3];
298 b[1] = v.u8[2];
299 b[2] = v.u8[1];
300 b[3] = v.u8[0];
301 }
302 }
303}
304
305static inline uint64_t dmach_addr(ZynqMPCSUDMA *s)
306{
307 uint64_t addr;
308
309 addr = s->regs[R_ADDR];
310 addr |= (uint64_t) s->regs[R_ADDR_MSB] << 32;
311 return addr;
312}
313
314
315static void dmach_write(ZynqMPCSUDMA *s, uint8_t *buf, unsigned int len)
316{
317 uint64_t addr = dmach_addr(s);
318
319 dmach_data_process(s, buf, len);
320 if (dmach_burst_is_fixed(s)) {
321 unsigned int i;
322
323 for (i = 0; i < len; i += s->width) {
324 unsigned int wlen = MIN(len - i, s->width);
325
326 address_space_rw(s->dma_as, addr, *s->attr, buf, wlen, true);
327 buf += wlen;
328 }
329 } else {
330 address_space_rw(s->dma_as, addr, *s->attr, buf, len, true);
331 }
332}
333
334
335static inline void dmach_read(ZynqMPCSUDMA *s, uint8_t *buf, unsigned int len)
336{
337 uint64_t addr = dmach_addr(s);
338
339 if (dmach_burst_is_fixed(s)) {
340 unsigned int i;
341
342 for (i = 0; i < len; i += s->width) {
343 unsigned int rlen = MIN(len - i, s->width);
344
345 address_space_rw(s->dma_as, addr, *s->attr, buf + i, rlen, false);
346 }
347 } else {
348 address_space_rw(s->dma_as, addr, *s->attr, buf, len, false);
349 }
350 dmach_data_process(s, buf, len);
351}
352
353static void ronaldu_csu_dma_update_irq(ZynqMPCSUDMA *s)
354{
355 qemu_set_irq(s->irq, !!(s->regs[R_INT_STATUS] & ~s->regs[R_INT_MASK]));
356}
357
358static void zynqmp_csu_dma_reset(DeviceState *dev)
359{
360 ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(dev);
361 int i;
362
363 for (i = 0; i < R_MAX; i++) {
364 register_reset(&s->regs_info[i]);
365 }
366}
367
368static size_t zynqmp_csu_dma_stream_push(StreamSlave *obj, uint8_t *buf,
369 size_t len, bool eop)
370{
371 ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(obj);
372 uint32_t size = dmach_get_size(s);
373 uint32_t btt = MIN(size, len);
374
375 assert(s->is_dst);
376 if (len && (dmach_is_paused(s) || btt == 0)) {
377 qemu_log_mask(LOG_GUEST_ERROR,
378 "csu-dma: DST channel dropping %zd b of data.\n", len);
379 s->regs[R_INT_STATUS] |= R_INT_STATUS_WR_FULL_CMDQ_MASK;
380 return len;
381 }
382
383 if (!btt) {
384 return 0;
385 }
386
387
388 dmach_write(s, buf, btt);
389 dmach_advance(s, btt);
390 ronaldu_csu_dma_update_irq(s);
391 return btt;
392}
393
394static bool zynqmp_csu_dma_stream_can_push(StreamSlave *obj,
395 StreamCanPushNotifyFn notify,
396 void *notify_opaque)
397{
398 ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(obj);
399
400 if (dmach_get_size(s) != 0) {
401 return true;
402 } else {
403 s->notify = notify;
404 s->notify_opaque = notify_opaque;
405 return false;
406 }
407}
408
409static void zynqmp_csu_dma_src_notify(void *opaque)
410{
411 ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(opaque);
412 unsigned char buf[4 * 1024];
413
414 ptimer_transaction_begin(s->src_timer);
415
416 ptimer_stop(s->src_timer);
417
418 while (dmach_get_size(s) && !dmach_is_paused(s) &&
419 stream_can_push(s->tx_dev, zynqmp_csu_dma_src_notify, s)) {
420 uint32_t size = dmach_get_size(s);
421 unsigned int plen = MIN(size, sizeof buf);
422 bool eop = false;
423 size_t ret;
424
425
426 if (size == plen && dmach_get_eop(s)) {
427 eop = true;
428 }
429
430
431 dmach_read(s, buf, plen);
432 ret = stream_push(s->tx_dev, buf, plen, eop);
433 dmach_advance(s, ret);
434 }
435
436
437
438 if (dmach_timeout_enabled(s) && dmach_get_size(s)
439 && !stream_can_push(s->tx_dev, zynqmp_csu_dma_src_notify, s)) {
440 unsigned int timeout = ARRAY_FIELD_EX32(s->regs, CTRL, TIMEOUT_VAL);
441 unsigned int div = extract32(s->regs[R_CTRL2], 4, 12) + 1;
442 unsigned int freq = 400 * 1000 * 1000;
443
444 freq /= div;
445 ptimer_set_freq(s->src_timer, freq);
446 ptimer_set_count(s->src_timer, timeout);
447 ptimer_run(s->src_timer, 1);
448 }
449
450 ptimer_transaction_commit(s->src_timer);
451 ronaldu_csu_dma_update_irq(s);
452}
453
454static void r_ctrl_post_write(RegisterInfo *reg, uint64_t val)
455{
456 ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(reg->opaque);
457
458 if (!s->is_dst) {
459 if (!dmach_is_paused(s)) {
460 zynqmp_csu_dma_src_notify(s);
461 }
462 } else {
463 if (!dmach_is_paused(s) && s->notify) {
464 s->notify(s->notify_opaque);
465 }
466 }
467}
468
469static uint64_t size_pre_write(RegisterInfo *reg, uint64_t val)
470{
471 ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(reg->opaque);
472 if (dmach_get_size(s) != 0) {
473 qemu_log_mask(LOG_GUEST_ERROR,
474 "csu-dma: Starting DMA while already running.\n");
475 }
476 return val;
477}
478
479static void size_post_write(RegisterInfo *reg, uint64_t val)
480{
481 ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(reg->opaque);
482
483 s->regs[R_STATUS] |= R_STATUS_BUSY_MASK;
484
485
486 if (dmach_get_size(s) == 0) {
487 dmach_done(s);
488 ronaldu_csu_dma_update_irq(s);
489 return;
490 }
491
492 if (!s->is_dst) {
493 zynqmp_csu_dma_src_notify(s);
494 } else {
495 if (s->notify) {
496 s->notify(s->notify_opaque);
497 }
498 }
499}
500
501static uint64_t int_status_pre_write(RegisterInfo *reg, uint64_t val)
502{
503 ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(reg->opaque);
504
505
506 if (~val & s->regs[R_INT_STATUS] & R_INT_STATUS_DONE_MASK) {
507 dmach_update_dma_cnt(s, -1);
508 }
509
510 return val;
511}
512
513static void int_status_post_write(RegisterInfo *reg, uint64_t val)
514{
515 ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(reg->opaque);
516
517 ronaldu_csu_dma_update_irq(s);
518}
519
520static uint64_t int_enable_pre_write(RegisterInfo *reg, uint64_t val)
521{
522 ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(reg->opaque);
523 uint32_t v32 = val;
524
525 s->regs[R_INT_MASK] &= ~v32;
526 ronaldu_csu_dma_update_irq(s);
527 return 0;
528}
529
530static uint64_t int_disable_pre_write(RegisterInfo *reg, uint64_t val)
531{
532 ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(reg->opaque);
533 uint32_t v32 = val;
534
535 s->regs[R_INT_MASK] |= v32;
536 ronaldu_csu_dma_update_irq(s);
537 return 0;
538}
539
540static void src_timeout_hit(void *opaque)
541{
542 ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(opaque);
543
544
545 if (!dmach_timeout_enabled(s)) {
546 return;
547 }
548
549 s->regs[R_INT_STATUS] |= R_INT_STATUS_TIMEOUT_STRM_MASK;
550 ronaldu_csu_dma_update_irq(s);
551}
552
553static void
554zynqmp_csu_dma_dma_ctrl_read(DmaCtrl *dma_ctrl, hwaddr addr, uint32_t len,
555 DmaCtrlNotify *notify, bool start_dma)
556{
557 ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(dma_ctrl);
558 RegisterInfo *reg = &s->regs_info[R_SIZE];
559 uint64_t we = MAKE_64BIT_MASK(0, 4 * 8);
560
561 s->regs[R_ADDR] = addr;
562 s->regs[R_ADDR_MSB] = (uint64_t)addr >> 32;
563
564 if (notify) {
565 s->dma_ctrl_notify = notify->cb;
566 s->dma_ctrl_opaque = notify->opaque;
567 }
568
569 if (start_dma) {
570 register_write(reg, len, we, object_get_typename(OBJECT(s)),
571 ZYNQMP_CSU_DMA_ERR_DEBUG);
572 } else {
573 dmach_set_size(s, len);
574 }
575}
576
577static const RegisterAccessInfo *zynqmp_csu_dma_regs_info[] = {
578#define DMACH_REGINFO(NAME, snd) \
579(const RegisterAccessInfo []) { \
580 { .name = #NAME "_ADDR", .addr = A_ADDR, \
581 },{ .name = #NAME "_SIZE", .addr = A_SIZE, \
582 .pre_write = size_pre_write, \
583 .post_write = size_post_write \
584 },{ .name = #NAME "_STATUS", .addr = A_STATUS, \
585 .w1c = R_STATUS_DONE_CNT_MASK \
586 },{ .name = #NAME "_CTRL", .addr = A_CTRL, \
587 .ro = snd ? CTRL_RSVD : 0, \
588 .reset = (snd ? 0 : 0x40 << R_CTRL_FIFO_THRESH_SHIFT) | \
589 R_CTRL_TIMEOUT_VAL_MASK | \
590 0x80 << R_CTRL_FIFO_THRESH_SHIFT, \
591 .post_write = r_ctrl_post_write \
592 },{ .name = #NAME "_CRC0", .addr = A_CRC0, \
593 },{ .name = #NAME "_INT_STATUS", .addr = A_INT_STATUS, \
594 .w1c = ~0, \
595 .pre_write = int_status_pre_write, \
596 .post_write = int_status_post_write \
597 },{ .name = #NAME "_INT_ENABLE", .addr = A_INT_ENABLE, \
598 .pre_write = int_enable_pre_write \
599 },{ .name = #NAME "_INT_DISABLE", .addr = A_INT_DISABLE, \
600 .pre_write = int_disable_pre_write \
601 },{ .name = #NAME "_INT_MASK", .addr = A_INT_MASK, \
602 .ro = ~0, \
603 .reset = snd ? INT_ALL_SRC : INT_ALL_DST, \
604 },{ .name = #NAME "_CTRL2", .addr = A_CTRL2, \
605 .ro = CTRL2_RSVD, \
606 .reset = 0x8 << R_CTRL2_MAX_OUTS_CMDS_SHIFT | \
607 0xFFF << R_CTRL2_TIMEOUT_PRE_SHIFT | 0x081b0000, \
608 },{ .name = #NAME "_ADDR_MSB", .addr = A_ADDR_MSB, \
609 } \
610}
611 DMACH_REGINFO(DMA_SRC, true),
612 DMACH_REGINFO(DMA_DST, false)
613};
614
615static const MemoryRegionOps zynqmp_csu_dma_ops = {
616 .read = register_read_memory,
617 .write = register_write_memory,
618 .endianness = DEVICE_LITTLE_ENDIAN,
619 .valid = {
620 .min_access_size = 4,
621 .max_access_size = 4,
622 }
623};
624
625static void zynqmp_csu_dma_realize(DeviceState *dev, Error **errp)
626{
627 ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(dev);
628 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
629 RegisterInfoArray *reg_array;
630
631 reg_array =
632 register_init_block32(dev, zynqmp_csu_dma_regs_info[!!s->is_dst],
633 R_MAX,
634 s->regs_info, s->regs,
635 &zynqmp_csu_dma_ops,
636 ZYNQMP_CSU_DMA_ERR_DEBUG,
637 R_MAX * 4);
638 memory_region_add_subregion(&s->iomem,
639 0x0,
640 ®_array->mem);
641 sysbus_init_mmio(sbd, &s->iomem);
642
643 if (!s->tx_dev) {
644 if (s->tx_dev0 && s->tx_dev1) {
645 error_setg(&error_fatal, "zynqmp.csu-dma: Both tx_dev0 & tx_dev1"
646 " StreamSlaves are defined");
647 }
648 s->tx_dev = s->tx_dev0 ? s->tx_dev0 :
649 s->tx_dev1 ? s->tx_dev1 : 0;
650 }
651 s->src_timer = ptimer_init(src_timeout_hit, s, PTIMER_POLICY_DEFAULT);
652
653 if (s->dma_mr) {
654 s->dma_as = g_malloc0(sizeof(AddressSpace));
655 address_space_init(s->dma_as, s->dma_mr, NULL);
656 } else {
657 s->dma_as = &address_space_memory;
658 }
659
660 if (!s->attr) {
661 s->attr = MEMORY_TRANSACTION_ATTR(
662 object_new(TYPE_MEMORY_TRANSACTION_ATTR));
663 }
664
665
666
667
668
669 s->r_size_last_word_mask = 1 << (s->byte_align ? 29 : 0);
670}
671
672static void zynqmp_csu_dma_init(Object *obj)
673{
674 ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(obj);
675 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
676
677 memory_region_init(&s->iomem, obj, "zynqmp.csu-dma",
678 R_MAX * 4);
679
680 sysbus_init_irq(sbd, &s->irq);
681
682 object_property_add_link(obj, "stream-connected-dma", TYPE_STREAM_SLAVE,
683 (Object **)&s->tx_dev,
684 qdev_prop_allow_set_link_before_realize,
685 OBJ_PROP_LINK_STRONG);
686 object_property_add_link(obj, "stream-connected-dma0", TYPE_STREAM_SLAVE,
687 (Object **)&s->tx_dev0,
688 qdev_prop_allow_set_link_before_realize,
689 OBJ_PROP_LINK_STRONG);
690 object_property_add_link(obj, "stream-connected-dma1", TYPE_STREAM_SLAVE,
691 (Object **)&s->tx_dev1,
692 qdev_prop_allow_set_link_before_realize,
693 OBJ_PROP_LINK_STRONG);
694 object_property_add_link(obj, "dma", TYPE_MEMORY_REGION,
695 (Object **)&s->dma_mr,
696 qdev_prop_allow_set_link_before_realize,
697 OBJ_PROP_LINK_STRONG);
698 object_property_add_link(obj, "memattr", TYPE_MEMORY_TRANSACTION_ATTR,
699 (Object **)&s->attr,
700 qdev_prop_allow_set_link_before_realize,
701 OBJ_PROP_LINK_STRONG);
702
703}
704
705static const VMStateDescription vmstate_zynqmp_csu_dma = {
706 .name = "zynqmp_csu_dma",
707 .version_id = 2,
708 .minimum_version_id = 2,
709 .minimum_version_id_old = 2,
710 .fields = (VMStateField[]) {
711 VMSTATE_PTIMER(src_timer, ZynqMPCSUDMA),
712 VMSTATE_UINT32_ARRAY(regs, ZynqMPCSUDMA, R_MAX),
713 VMSTATE_END_OF_LIST(),
714 }
715};
716
717static Property zynqmp_csu_dma_properties [] = {
718 DEFINE_PROP_BOOL("is-dst", ZynqMPCSUDMA, is_dst, false),
719 DEFINE_PROP_UINT16("dma-width", ZynqMPCSUDMA, width, 4),
720 DEFINE_PROP_BOOL("byte-align", ZynqMPCSUDMA, byte_align, false),
721 DEFINE_PROP_END_OF_LIST(),
722};
723
724static void zynqmp_csu_dma_class_init(ObjectClass *klass, void *data)
725{
726 DeviceClass *dc = DEVICE_CLASS(klass);
727 StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
728 DmaCtrlClass *dcc = DMA_CTRL_CLASS(klass);
729
730 dc->reset = zynqmp_csu_dma_reset;
731 dc->realize = zynqmp_csu_dma_realize;
732 dc->vmsd = &vmstate_zynqmp_csu_dma;
733 device_class_set_props(dc, zynqmp_csu_dma_properties);
734
735 ssc->push = zynqmp_csu_dma_stream_push;
736 ssc->can_push = zynqmp_csu_dma_stream_can_push;
737 dcc->read = zynqmp_csu_dma_dma_ctrl_read;
738}
739
740static const TypeInfo zynqmp_csu_dma_info = {
741 .name = TYPE_ZYNQMP_CSU_DMA,
742 .parent = TYPE_SYS_BUS_DEVICE,
743 .instance_size = sizeof(ZynqMPCSUDMA),
744 .class_init = zynqmp_csu_dma_class_init,
745 .instance_init = zynqmp_csu_dma_init,
746 .interfaces = (InterfaceInfo[]) {
747 { TYPE_STREAM_SLAVE },
748 { TYPE_DMA_CTRL },
749 { }
750 }
751};
752
753static void zynqmp_csu_dma_register_types(void)
754{
755 type_register_static(&zynqmp_csu_dma_info);
756}
757
758type_init(zynqmp_csu_dma_register_types)
759