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