xref: /openbmc/qemu/hw/dma/xilinx_axidma.c (revision b2c623a3)
1 /*
2  * QEMU model of Xilinx AXI-DMA block.
3  *
4  * Copyright (c) 2011 Edgar E. Iglesias.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 
25 #include "hw/sysbus.h"
26 #include "qemu/timer.h"
27 #include "hw/ptimer.h"
28 #include "qemu/log.h"
29 #include "qapi/qmp/qerror.h"
30 #include "qemu/main-loop.h"
31 
32 #include "hw/stream.h"
33 
34 #define D(x)
35 
36 #define TYPE_XILINX_AXI_DMA "xlnx.axi-dma"
37 #define TYPE_XILINX_AXI_DMA_DATA_STREAM "xilinx-axi-dma-data-stream"
38 #define TYPE_XILINX_AXI_DMA_CONTROL_STREAM "xilinx-axi-dma-control-stream"
39 
40 #define XILINX_AXI_DMA(obj) \
41      OBJECT_CHECK(XilinxAXIDMA, (obj), TYPE_XILINX_AXI_DMA)
42 
43 #define XILINX_AXI_DMA_DATA_STREAM(obj) \
44      OBJECT_CHECK(XilinxAXIDMAStreamSlave, (obj),\
45      TYPE_XILINX_AXI_DMA_DATA_STREAM)
46 
47 #define XILINX_AXI_DMA_CONTROL_STREAM(obj) \
48      OBJECT_CHECK(XilinxAXIDMAStreamSlave, (obj),\
49      TYPE_XILINX_AXI_DMA_CONTROL_STREAM)
50 
51 #define R_DMACR             (0x00 / 4)
52 #define R_DMASR             (0x04 / 4)
53 #define R_CURDESC           (0x08 / 4)
54 #define R_TAILDESC          (0x10 / 4)
55 #define R_MAX               (0x30 / 4)
56 
57 #define CONTROL_PAYLOAD_WORDS 5
58 #define CONTROL_PAYLOAD_SIZE (CONTROL_PAYLOAD_WORDS * (sizeof(uint32_t)))
59 
60 typedef struct XilinxAXIDMA XilinxAXIDMA;
61 typedef struct XilinxAXIDMAStreamSlave XilinxAXIDMAStreamSlave;
62 
63 enum {
64     DMACR_RUNSTOP = 1,
65     DMACR_TAILPTR_MODE = 2,
66     DMACR_RESET = 4
67 };
68 
69 enum {
70     DMASR_HALTED = 1,
71     DMASR_IDLE  = 2,
72     DMASR_IOC_IRQ  = 1 << 12,
73     DMASR_DLY_IRQ  = 1 << 13,
74 
75     DMASR_IRQ_MASK = 7 << 12
76 };
77 
78 struct SDesc {
79     uint64_t nxtdesc;
80     uint64_t buffer_address;
81     uint64_t reserved;
82     uint32_t control;
83     uint32_t status;
84     uint8_t app[CONTROL_PAYLOAD_SIZE];
85 };
86 
87 enum {
88     SDESC_CTRL_EOF = (1 << 26),
89     SDESC_CTRL_SOF = (1 << 27),
90 
91     SDESC_CTRL_LEN_MASK = (1 << 23) - 1
92 };
93 
94 enum {
95     SDESC_STATUS_EOF = (1 << 26),
96     SDESC_STATUS_SOF_BIT = 27,
97     SDESC_STATUS_SOF = (1 << SDESC_STATUS_SOF_BIT),
98     SDESC_STATUS_COMPLETE = (1 << 31)
99 };
100 
101 struct Stream {
102     QEMUBH *bh;
103     ptimer_state *ptimer;
104     qemu_irq irq;
105 
106     int nr;
107 
108     struct SDesc desc;
109     int pos;
110     unsigned int complete_cnt;
111     uint32_t regs[R_MAX];
112     uint8_t app[20];
113 };
114 
115 struct XilinxAXIDMAStreamSlave {
116     Object parent;
117 
118     struct XilinxAXIDMA *dma;
119 };
120 
121 struct XilinxAXIDMA {
122     SysBusDevice busdev;
123     MemoryRegion iomem;
124     uint32_t freqhz;
125     StreamSlave *tx_data_dev;
126     StreamSlave *tx_control_dev;
127     XilinxAXIDMAStreamSlave rx_data_dev;
128     XilinxAXIDMAStreamSlave rx_control_dev;
129 
130     struct Stream streams[2];
131 
132     StreamCanPushNotifyFn notify;
133     void *notify_opaque;
134 };
135 
136 /*
137  * Helper calls to extract info from desriptors and other trivial
138  * state from regs.
139  */
140 static inline int stream_desc_sof(struct SDesc *d)
141 {
142     return d->control & SDESC_CTRL_SOF;
143 }
144 
145 static inline int stream_desc_eof(struct SDesc *d)
146 {
147     return d->control & SDESC_CTRL_EOF;
148 }
149 
150 static inline int stream_resetting(struct Stream *s)
151 {
152     return !!(s->regs[R_DMACR] & DMACR_RESET);
153 }
154 
155 static inline int stream_running(struct Stream *s)
156 {
157     return s->regs[R_DMACR] & DMACR_RUNSTOP;
158 }
159 
160 static inline int stream_halted(struct Stream *s)
161 {
162     return s->regs[R_DMASR] & DMASR_HALTED;
163 }
164 
165 static inline int stream_idle(struct Stream *s)
166 {
167     return !!(s->regs[R_DMASR] & DMASR_IDLE);
168 }
169 
170 static void stream_reset(struct Stream *s)
171 {
172     s->regs[R_DMASR] = DMASR_HALTED;  /* starts up halted.  */
173     s->regs[R_DMACR] = 1 << 16; /* Starts with one in compl threshold.  */
174 }
175 
176 /* Map an offset addr into a channel index.  */
177 static inline int streamid_from_addr(hwaddr addr)
178 {
179     int sid;
180 
181     sid = addr / (0x30);
182     sid &= 1;
183     return sid;
184 }
185 
186 #ifdef DEBUG_ENET
187 static void stream_desc_show(struct SDesc *d)
188 {
189     qemu_log("buffer_addr  = " PRIx64 "\n", d->buffer_address);
190     qemu_log("nxtdesc      = " PRIx64 "\n", d->nxtdesc);
191     qemu_log("control      = %x\n", d->control);
192     qemu_log("status       = %x\n", d->status);
193 }
194 #endif
195 
196 static void stream_desc_load(struct Stream *s, hwaddr addr)
197 {
198     struct SDesc *d = &s->desc;
199 
200     cpu_physical_memory_read(addr, d, sizeof *d);
201 
202     /* Convert from LE into host endianness.  */
203     d->buffer_address = le64_to_cpu(d->buffer_address);
204     d->nxtdesc = le64_to_cpu(d->nxtdesc);
205     d->control = le32_to_cpu(d->control);
206     d->status = le32_to_cpu(d->status);
207 }
208 
209 static void stream_desc_store(struct Stream *s, hwaddr addr)
210 {
211     struct SDesc *d = &s->desc;
212 
213     /* Convert from host endianness into LE.  */
214     d->buffer_address = cpu_to_le64(d->buffer_address);
215     d->nxtdesc = cpu_to_le64(d->nxtdesc);
216     d->control = cpu_to_le32(d->control);
217     d->status = cpu_to_le32(d->status);
218     cpu_physical_memory_write(addr, d, sizeof *d);
219 }
220 
221 static void stream_update_irq(struct Stream *s)
222 {
223     unsigned int pending, mask, irq;
224 
225     pending = s->regs[R_DMASR] & DMASR_IRQ_MASK;
226     mask = s->regs[R_DMACR] & DMASR_IRQ_MASK;
227 
228     irq = pending & mask;
229 
230     qemu_set_irq(s->irq, !!irq);
231 }
232 
233 static void stream_reload_complete_cnt(struct Stream *s)
234 {
235     unsigned int comp_th;
236     comp_th = (s->regs[R_DMACR] >> 16) & 0xff;
237     s->complete_cnt = comp_th;
238 }
239 
240 static void timer_hit(void *opaque)
241 {
242     struct Stream *s = opaque;
243 
244     stream_reload_complete_cnt(s);
245     s->regs[R_DMASR] |= DMASR_DLY_IRQ;
246     stream_update_irq(s);
247 }
248 
249 static void stream_complete(struct Stream *s)
250 {
251     unsigned int comp_delay;
252 
253     /* Start the delayed timer.  */
254     comp_delay = s->regs[R_DMACR] >> 24;
255     if (comp_delay) {
256         ptimer_stop(s->ptimer);
257         ptimer_set_count(s->ptimer, comp_delay);
258         ptimer_run(s->ptimer, 1);
259     }
260 
261     s->complete_cnt--;
262     if (s->complete_cnt == 0) {
263         /* Raise the IOC irq.  */
264         s->regs[R_DMASR] |= DMASR_IOC_IRQ;
265         stream_reload_complete_cnt(s);
266     }
267 }
268 
269 static void stream_process_mem2s(struct Stream *s, StreamSlave *tx_data_dev,
270                                  StreamSlave *tx_control_dev)
271 {
272     uint32_t prev_d;
273     unsigned char txbuf[16 * 1024];
274     unsigned int txlen;
275 
276     if (!stream_running(s) || stream_idle(s)) {
277         return;
278     }
279 
280     while (1) {
281         stream_desc_load(s, s->regs[R_CURDESC]);
282 
283         if (s->desc.status & SDESC_STATUS_COMPLETE) {
284             s->regs[R_DMASR] |= DMASR_HALTED;
285             break;
286         }
287 
288         if (stream_desc_sof(&s->desc)) {
289             s->pos = 0;
290             stream_push(tx_control_dev, s->desc.app, sizeof(s->desc.app));
291         }
292 
293         txlen = s->desc.control & SDESC_CTRL_LEN_MASK;
294         if ((txlen + s->pos) > sizeof txbuf) {
295             hw_error("%s: too small internal txbuf! %d\n", __func__,
296                      txlen + s->pos);
297         }
298 
299         cpu_physical_memory_read(s->desc.buffer_address,
300                                  txbuf + s->pos, txlen);
301         s->pos += txlen;
302 
303         if (stream_desc_eof(&s->desc)) {
304             stream_push(tx_data_dev, txbuf, s->pos);
305             s->pos = 0;
306             stream_complete(s);
307         }
308 
309         /* Update the descriptor.  */
310         s->desc.status = txlen | SDESC_STATUS_COMPLETE;
311         stream_desc_store(s, s->regs[R_CURDESC]);
312 
313         /* Advance.  */
314         prev_d = s->regs[R_CURDESC];
315         s->regs[R_CURDESC] = s->desc.nxtdesc;
316         if (prev_d == s->regs[R_TAILDESC]) {
317             s->regs[R_DMASR] |= DMASR_IDLE;
318             break;
319         }
320     }
321 }
322 
323 static size_t stream_process_s2mem(struct Stream *s, unsigned char *buf,
324                                    size_t len)
325 {
326     uint32_t prev_d;
327     unsigned int rxlen;
328     size_t pos = 0;
329     int sof = 1;
330 
331     if (!stream_running(s) || stream_idle(s)) {
332         return 0;
333     }
334 
335     while (len) {
336         stream_desc_load(s, s->regs[R_CURDESC]);
337 
338         if (s->desc.status & SDESC_STATUS_COMPLETE) {
339             s->regs[R_DMASR] |= DMASR_HALTED;
340             break;
341         }
342 
343         rxlen = s->desc.control & SDESC_CTRL_LEN_MASK;
344         if (rxlen > len) {
345             /* It fits.  */
346             rxlen = len;
347         }
348 
349         cpu_physical_memory_write(s->desc.buffer_address, buf + pos, rxlen);
350         len -= rxlen;
351         pos += rxlen;
352 
353         /* Update the descriptor.  */
354         if (!len) {
355             stream_complete(s);
356             memcpy(s->desc.app, s->app, sizeof(s->desc.app));
357             s->desc.status |= SDESC_STATUS_EOF;
358         }
359 
360         s->desc.status |= sof << SDESC_STATUS_SOF_BIT;
361         s->desc.status |= SDESC_STATUS_COMPLETE;
362         stream_desc_store(s, s->regs[R_CURDESC]);
363         sof = 0;
364 
365         /* Advance.  */
366         prev_d = s->regs[R_CURDESC];
367         s->regs[R_CURDESC] = s->desc.nxtdesc;
368         if (prev_d == s->regs[R_TAILDESC]) {
369             s->regs[R_DMASR] |= DMASR_IDLE;
370             break;
371         }
372     }
373 
374     return pos;
375 }
376 
377 static void xilinx_axidma_reset(DeviceState *dev)
378 {
379     int i;
380     XilinxAXIDMA *s = XILINX_AXI_DMA(dev);
381 
382     for (i = 0; i < 2; i++) {
383         stream_reset(&s->streams[i]);
384     }
385 }
386 
387 static size_t
388 xilinx_axidma_control_stream_push(StreamSlave *obj, unsigned char *buf,
389                                   size_t len)
390 {
391     XilinxAXIDMAStreamSlave *cs = XILINX_AXI_DMA_CONTROL_STREAM(obj);
392     struct Stream *s = &cs->dma->streams[1];
393 
394     if (len != CONTROL_PAYLOAD_SIZE) {
395         hw_error("AXI DMA requires %d byte control stream payload\n",
396                  (int)CONTROL_PAYLOAD_SIZE);
397     }
398 
399     memcpy(s->app, buf, len);
400     return len;
401 }
402 
403 static bool
404 xilinx_axidma_data_stream_can_push(StreamSlave *obj,
405                                    StreamCanPushNotifyFn notify,
406                                    void *notify_opaque)
407 {
408     XilinxAXIDMAStreamSlave *ds = XILINX_AXI_DMA_DATA_STREAM(obj);
409     struct Stream *s = &ds->dma->streams[1];
410 
411     if (!stream_running(s) || stream_idle(s)) {
412         ds->dma->notify = notify;
413         ds->dma->notify_opaque = notify_opaque;
414         return false;
415     }
416 
417     return true;
418 }
419 
420 static size_t
421 xilinx_axidma_data_stream_push(StreamSlave *obj, unsigned char *buf, size_t len)
422 {
423     XilinxAXIDMAStreamSlave *ds = XILINX_AXI_DMA_DATA_STREAM(obj);
424     struct Stream *s = &ds->dma->streams[1];
425     size_t ret;
426 
427     ret = stream_process_s2mem(s, buf, len);
428     stream_update_irq(s);
429     return ret;
430 }
431 
432 static uint64_t axidma_read(void *opaque, hwaddr addr,
433                             unsigned size)
434 {
435     XilinxAXIDMA *d = opaque;
436     struct Stream *s;
437     uint32_t r = 0;
438     int sid;
439 
440     sid = streamid_from_addr(addr);
441     s = &d->streams[sid];
442 
443     addr = addr % 0x30;
444     addr >>= 2;
445     switch (addr) {
446         case R_DMACR:
447             /* Simulate one cycles reset delay.  */
448             s->regs[addr] &= ~DMACR_RESET;
449             r = s->regs[addr];
450             break;
451         case R_DMASR:
452             s->regs[addr] &= 0xffff;
453             s->regs[addr] |= (s->complete_cnt & 0xff) << 16;
454             s->regs[addr] |= (ptimer_get_count(s->ptimer) & 0xff) << 24;
455             r = s->regs[addr];
456             break;
457         default:
458             r = s->regs[addr];
459             D(qemu_log("%s ch=%d addr=" TARGET_FMT_plx " v=%x\n",
460                            __func__, sid, addr * 4, r));
461             break;
462     }
463     return r;
464 
465 }
466 
467 static void axidma_write(void *opaque, hwaddr addr,
468                          uint64_t value, unsigned size)
469 {
470     XilinxAXIDMA *d = opaque;
471     struct Stream *s;
472     int sid;
473 
474     sid = streamid_from_addr(addr);
475     s = &d->streams[sid];
476 
477     addr = addr % 0x30;
478     addr >>= 2;
479     switch (addr) {
480         case R_DMACR:
481             /* Tailptr mode is always on.  */
482             value |= DMACR_TAILPTR_MODE;
483             /* Remember our previous reset state.  */
484             value |= (s->regs[addr] & DMACR_RESET);
485             s->regs[addr] = value;
486 
487             if (value & DMACR_RESET) {
488                 stream_reset(s);
489             }
490 
491             if ((value & 1) && !stream_resetting(s)) {
492                 /* Start processing.  */
493                 s->regs[R_DMASR] &= ~(DMASR_HALTED | DMASR_IDLE);
494             }
495             stream_reload_complete_cnt(s);
496             break;
497 
498         case R_DMASR:
499             /* Mask away write to clear irq lines.  */
500             value &= ~(value & DMASR_IRQ_MASK);
501             s->regs[addr] = value;
502             break;
503 
504         case R_TAILDESC:
505             s->regs[addr] = value;
506             s->regs[R_DMASR] &= ~DMASR_IDLE; /* Not idle.  */
507             if (!sid) {
508                 stream_process_mem2s(s, d->tx_data_dev, d->tx_control_dev);
509             }
510             break;
511         default:
512             D(qemu_log("%s: ch=%d addr=" TARGET_FMT_plx " v=%x\n",
513                   __func__, sid, addr * 4, (unsigned)value));
514             s->regs[addr] = value;
515             break;
516     }
517     if (sid == 1 && d->notify) {
518         StreamCanPushNotifyFn notifytmp = d->notify;
519         d->notify = NULL;
520         notifytmp(d->notify_opaque);
521     }
522     stream_update_irq(s);
523 }
524 
525 static const MemoryRegionOps axidma_ops = {
526     .read = axidma_read,
527     .write = axidma_write,
528     .endianness = DEVICE_NATIVE_ENDIAN,
529 };
530 
531 static void xilinx_axidma_realize(DeviceState *dev, Error **errp)
532 {
533     XilinxAXIDMA *s = XILINX_AXI_DMA(dev);
534     XilinxAXIDMAStreamSlave *ds = XILINX_AXI_DMA_DATA_STREAM(&s->rx_data_dev);
535     XilinxAXIDMAStreamSlave *cs = XILINX_AXI_DMA_CONTROL_STREAM(
536                                                             &s->rx_control_dev);
537     Error *local_errp = NULL;
538 
539     object_property_add_link(OBJECT(ds), "dma", TYPE_XILINX_AXI_DMA,
540                              (Object **)&ds->dma, &local_errp);
541     object_property_add_link(OBJECT(cs), "dma", TYPE_XILINX_AXI_DMA,
542                              (Object **)&cs->dma, &local_errp);
543     if (local_errp) {
544         goto xilinx_axidma_realize_fail;
545     }
546     object_property_set_link(OBJECT(ds), OBJECT(s), "dma", &local_errp);
547     object_property_set_link(OBJECT(cs), OBJECT(s), "dma", &local_errp);
548     if (local_errp) {
549         goto xilinx_axidma_realize_fail;
550     }
551 
552     int i;
553 
554     for (i = 0; i < 2; i++) {
555         s->streams[i].nr = i;
556         s->streams[i].bh = qemu_bh_new(timer_hit, &s->streams[i]);
557         s->streams[i].ptimer = ptimer_init(s->streams[i].bh);
558         ptimer_set_freq(s->streams[i].ptimer, s->freqhz);
559     }
560     return;
561 
562 xilinx_axidma_realize_fail:
563     if (!*errp) {
564         *errp = local_errp;
565     }
566 }
567 
568 static void xilinx_axidma_init(Object *obj)
569 {
570     XilinxAXIDMA *s = XILINX_AXI_DMA(obj);
571     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
572 
573     object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
574                              (Object **)&s->tx_data_dev, &error_abort);
575     object_property_add_link(obj, "axistream-control-connected",
576                              TYPE_STREAM_SLAVE,
577                              (Object **)&s->tx_control_dev, &error_abort);
578 
579     object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev),
580                       TYPE_XILINX_AXI_DMA_DATA_STREAM);
581     object_initialize(&s->rx_control_dev, sizeof(s->rx_control_dev),
582                       TYPE_XILINX_AXI_DMA_CONTROL_STREAM);
583     object_property_add_child(OBJECT(s), "axistream-connected-target",
584                               (Object *)&s->rx_data_dev, &error_abort);
585     object_property_add_child(OBJECT(s), "axistream-control-connected-target",
586                               (Object *)&s->rx_control_dev, &error_abort);
587 
588     sysbus_init_irq(sbd, &s->streams[0].irq);
589     sysbus_init_irq(sbd, &s->streams[1].irq);
590 
591     memory_region_init_io(&s->iomem, obj, &axidma_ops, s,
592                           "xlnx.axi-dma", R_MAX * 4 * 2);
593     sysbus_init_mmio(sbd, &s->iomem);
594 }
595 
596 static Property axidma_properties[] = {
597     DEFINE_PROP_UINT32("freqhz", XilinxAXIDMA, freqhz, 50000000),
598     DEFINE_PROP_END_OF_LIST(),
599 };
600 
601 static void axidma_class_init(ObjectClass *klass, void *data)
602 {
603     DeviceClass *dc = DEVICE_CLASS(klass);
604 
605     dc->realize = xilinx_axidma_realize,
606     dc->reset = xilinx_axidma_reset;
607     dc->props = axidma_properties;
608 }
609 
610 static StreamSlaveClass xilinx_axidma_data_stream_class = {
611     .push = xilinx_axidma_data_stream_push,
612     .can_push = xilinx_axidma_data_stream_can_push,
613 };
614 
615 static StreamSlaveClass xilinx_axidma_control_stream_class = {
616     .push = xilinx_axidma_control_stream_push,
617 };
618 
619 static void xilinx_axidma_stream_class_init(ObjectClass *klass, void *data)
620 {
621     StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
622 
623     ssc->push = ((StreamSlaveClass *)data)->push;
624     ssc->can_push = ((StreamSlaveClass *)data)->can_push;
625 }
626 
627 static const TypeInfo axidma_info = {
628     .name          = TYPE_XILINX_AXI_DMA,
629     .parent        = TYPE_SYS_BUS_DEVICE,
630     .instance_size = sizeof(XilinxAXIDMA),
631     .class_init    = axidma_class_init,
632     .instance_init = xilinx_axidma_init,
633 };
634 
635 static const TypeInfo xilinx_axidma_data_stream_info = {
636     .name          = TYPE_XILINX_AXI_DMA_DATA_STREAM,
637     .parent        = TYPE_OBJECT,
638     .instance_size = sizeof(struct XilinxAXIDMAStreamSlave),
639     .class_init    = xilinx_axidma_stream_class_init,
640     .class_data    = &xilinx_axidma_data_stream_class,
641     .interfaces = (InterfaceInfo[]) {
642         { TYPE_STREAM_SLAVE },
643         { }
644     }
645 };
646 
647 static const TypeInfo xilinx_axidma_control_stream_info = {
648     .name          = TYPE_XILINX_AXI_DMA_CONTROL_STREAM,
649     .parent        = TYPE_OBJECT,
650     .instance_size = sizeof(struct XilinxAXIDMAStreamSlave),
651     .class_init    = xilinx_axidma_stream_class_init,
652     .class_data    = &xilinx_axidma_control_stream_class,
653     .interfaces = (InterfaceInfo[]) {
654         { TYPE_STREAM_SLAVE },
655         { }
656     }
657 };
658 
659 static void xilinx_axidma_register_types(void)
660 {
661     type_register_static(&axidma_info);
662     type_register_static(&xilinx_axidma_data_stream_info);
663     type_register_static(&xilinx_axidma_control_stream_info);
664 }
665 
666 type_init(xilinx_axidma_register_types)
667