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