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