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, 541 object_property_allow_set_link, 542 OBJ_PROP_LINK_UNREF_ON_RELEASE, 543 &local_errp); 544 object_property_add_link(OBJECT(cs), "dma", TYPE_XILINX_AXI_DMA, 545 (Object **)&cs->dma, 546 object_property_allow_set_link, 547 OBJ_PROP_LINK_UNREF_ON_RELEASE, 548 &local_errp); 549 if (local_errp) { 550 goto xilinx_axidma_realize_fail; 551 } 552 object_property_set_link(OBJECT(ds), OBJECT(s), "dma", &local_errp); 553 object_property_set_link(OBJECT(cs), OBJECT(s), "dma", &local_errp); 554 if (local_errp) { 555 goto xilinx_axidma_realize_fail; 556 } 557 558 int i; 559 560 for (i = 0; i < 2; i++) { 561 s->streams[i].nr = i; 562 s->streams[i].bh = qemu_bh_new(timer_hit, &s->streams[i]); 563 s->streams[i].ptimer = ptimer_init(s->streams[i].bh); 564 ptimer_set_freq(s->streams[i].ptimer, s->freqhz); 565 } 566 return; 567 568 xilinx_axidma_realize_fail: 569 if (!*errp) { 570 *errp = local_errp; 571 } 572 } 573 574 static void xilinx_axidma_init(Object *obj) 575 { 576 XilinxAXIDMA *s = XILINX_AXI_DMA(obj); 577 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 578 579 object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE, 580 (Object **)&s->tx_data_dev, 581 qdev_prop_allow_set_link_before_realize, 582 OBJ_PROP_LINK_UNREF_ON_RELEASE, 583 &error_abort); 584 object_property_add_link(obj, "axistream-control-connected", 585 TYPE_STREAM_SLAVE, 586 (Object **)&s->tx_control_dev, 587 qdev_prop_allow_set_link_before_realize, 588 OBJ_PROP_LINK_UNREF_ON_RELEASE, 589 &error_abort); 590 591 object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev), 592 TYPE_XILINX_AXI_DMA_DATA_STREAM); 593 object_initialize(&s->rx_control_dev, sizeof(s->rx_control_dev), 594 TYPE_XILINX_AXI_DMA_CONTROL_STREAM); 595 object_property_add_child(OBJECT(s), "axistream-connected-target", 596 (Object *)&s->rx_data_dev, &error_abort); 597 object_property_add_child(OBJECT(s), "axistream-control-connected-target", 598 (Object *)&s->rx_control_dev, &error_abort); 599 600 sysbus_init_irq(sbd, &s->streams[0].irq); 601 sysbus_init_irq(sbd, &s->streams[1].irq); 602 603 memory_region_init_io(&s->iomem, obj, &axidma_ops, s, 604 "xlnx.axi-dma", R_MAX * 4 * 2); 605 sysbus_init_mmio(sbd, &s->iomem); 606 } 607 608 static Property axidma_properties[] = { 609 DEFINE_PROP_UINT32("freqhz", XilinxAXIDMA, freqhz, 50000000), 610 DEFINE_PROP_END_OF_LIST(), 611 }; 612 613 static void axidma_class_init(ObjectClass *klass, void *data) 614 { 615 DeviceClass *dc = DEVICE_CLASS(klass); 616 617 dc->realize = xilinx_axidma_realize, 618 dc->reset = xilinx_axidma_reset; 619 dc->props = axidma_properties; 620 } 621 622 static StreamSlaveClass xilinx_axidma_data_stream_class = { 623 .push = xilinx_axidma_data_stream_push, 624 .can_push = xilinx_axidma_data_stream_can_push, 625 }; 626 627 static StreamSlaveClass xilinx_axidma_control_stream_class = { 628 .push = xilinx_axidma_control_stream_push, 629 }; 630 631 static void xilinx_axidma_stream_class_init(ObjectClass *klass, void *data) 632 { 633 StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass); 634 635 ssc->push = ((StreamSlaveClass *)data)->push; 636 ssc->can_push = ((StreamSlaveClass *)data)->can_push; 637 } 638 639 static const TypeInfo axidma_info = { 640 .name = TYPE_XILINX_AXI_DMA, 641 .parent = TYPE_SYS_BUS_DEVICE, 642 .instance_size = sizeof(XilinxAXIDMA), 643 .class_init = axidma_class_init, 644 .instance_init = xilinx_axidma_init, 645 }; 646 647 static const TypeInfo xilinx_axidma_data_stream_info = { 648 .name = TYPE_XILINX_AXI_DMA_DATA_STREAM, 649 .parent = TYPE_OBJECT, 650 .instance_size = sizeof(struct XilinxAXIDMAStreamSlave), 651 .class_init = xilinx_axidma_stream_class_init, 652 .class_data = &xilinx_axidma_data_stream_class, 653 .interfaces = (InterfaceInfo[]) { 654 { TYPE_STREAM_SLAVE }, 655 { } 656 } 657 }; 658 659 static const TypeInfo xilinx_axidma_control_stream_info = { 660 .name = TYPE_XILINX_AXI_DMA_CONTROL_STREAM, 661 .parent = TYPE_OBJECT, 662 .instance_size = sizeof(struct XilinxAXIDMAStreamSlave), 663 .class_init = xilinx_axidma_stream_class_init, 664 .class_data = &xilinx_axidma_control_stream_class, 665 .interfaces = (InterfaceInfo[]) { 666 { TYPE_STREAM_SLAVE }, 667 { } 668 } 669 }; 670 671 static void xilinx_axidma_register_types(void) 672 { 673 type_register_static(&axidma_info); 674 type_register_static(&xilinx_axidma_data_stream_info); 675 type_register_static(&xilinx_axidma_control_stream_info); 676 } 677 678 type_init(xilinx_axidma_register_types) 679