xilinx_axidma.c 18.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
 * QEMU model of Xilinx AXI-DMA block.
 *
 * Copyright (c) 2011 Edgar E. Iglesias.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

P
Peter Maydell 已提交
25
#include "qemu/osdep.h"
26
#include "hw/sysbus.h"
27
#include "qapi/error.h"
28
#include "qemu/timer.h"
29
#include "hw/ptimer.h"
30
#include "qemu/log.h"
31
#include "qemu/main-loop.h"
32

33
#include "hw/stream.h"
34 35 36

#define D(x)

37
#define TYPE_XILINX_AXI_DMA "xlnx.axi-dma"
38
#define TYPE_XILINX_AXI_DMA_DATA_STREAM "xilinx-axi-dma-data-stream"
39
#define TYPE_XILINX_AXI_DMA_CONTROL_STREAM "xilinx-axi-dma-control-stream"
40 41 42 43

#define XILINX_AXI_DMA(obj) \
     OBJECT_CHECK(XilinxAXIDMA, (obj), TYPE_XILINX_AXI_DMA)

44 45 46 47
#define XILINX_AXI_DMA_DATA_STREAM(obj) \
     OBJECT_CHECK(XilinxAXIDMAStreamSlave, (obj),\
     TYPE_XILINX_AXI_DMA_DATA_STREAM)

48 49 50 51
#define XILINX_AXI_DMA_CONTROL_STREAM(obj) \
     OBJECT_CHECK(XilinxAXIDMAStreamSlave, (obj),\
     TYPE_XILINX_AXI_DMA_CONTROL_STREAM)

52 53 54 55 56 57
#define R_DMACR             (0x00 / 4)
#define R_DMASR             (0x04 / 4)
#define R_CURDESC           (0x08 / 4)
#define R_TAILDESC          (0x10 / 4)
#define R_MAX               (0x30 / 4)

58 59 60
#define CONTROL_PAYLOAD_WORDS 5
#define CONTROL_PAYLOAD_SIZE (CONTROL_PAYLOAD_WORDS * (sizeof(uint32_t)))

61
typedef struct XilinxAXIDMA XilinxAXIDMA;
62
typedef struct XilinxAXIDMAStreamSlave XilinxAXIDMAStreamSlave;
63

64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
enum {
    DMACR_RUNSTOP = 1,
    DMACR_TAILPTR_MODE = 2,
    DMACR_RESET = 4
};

enum {
    DMASR_HALTED = 1,
    DMASR_IDLE  = 2,
    DMASR_IOC_IRQ  = 1 << 12,
    DMASR_DLY_IRQ  = 1 << 13,

    DMASR_IRQ_MASK = 7 << 12
};

struct SDesc {
    uint64_t nxtdesc;
    uint64_t buffer_address;
    uint64_t reserved;
    uint32_t control;
    uint32_t status;
85
    uint8_t app[CONTROL_PAYLOAD_SIZE];
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
};

enum {
    SDESC_CTRL_EOF = (1 << 26),
    SDESC_CTRL_SOF = (1 << 27),

    SDESC_CTRL_LEN_MASK = (1 << 23) - 1
};

enum {
    SDESC_STATUS_EOF = (1 << 26),
    SDESC_STATUS_SOF_BIT = 27,
    SDESC_STATUS_SOF = (1 << SDESC_STATUS_SOF_BIT),
    SDESC_STATUS_COMPLETE = (1 << 31)
};

102
struct Stream {
103 104 105 106 107 108 109 110 111 112
    QEMUBH *bh;
    ptimer_state *ptimer;
    qemu_irq irq;

    int nr;

    struct SDesc desc;
    int pos;
    unsigned int complete_cnt;
    uint32_t regs[R_MAX];
113
    uint8_t app[20];
114 115
};

116 117 118 119 120 121
struct XilinxAXIDMAStreamSlave {
    Object parent;

    struct XilinxAXIDMA *dma;
};

122 123
struct XilinxAXIDMA {
    SysBusDevice busdev;
A
Avi Kivity 已提交
124
    MemoryRegion iomem;
125
    uint32_t freqhz;
126 127
    StreamSlave *tx_data_dev;
    StreamSlave *tx_control_dev;
128
    XilinxAXIDMAStreamSlave rx_data_dev;
129
    XilinxAXIDMAStreamSlave rx_control_dev;
130

131
    struct Stream streams[2];
132 133 134

    StreamCanPushNotifyFn notify;
    void *notify_opaque;
135 136 137
};

/*
V
Veres Lajos 已提交
138
 * Helper calls to extract info from descriptors and other trivial
139 140 141 142 143 144 145 146 147 148 149 150
 * state from regs.
 */
static inline int stream_desc_sof(struct SDesc *d)
{
    return d->control & SDESC_CTRL_SOF;
}

static inline int stream_desc_eof(struct SDesc *d)
{
    return d->control & SDESC_CTRL_EOF;
}

151
static inline int stream_resetting(struct Stream *s)
152 153 154 155
{
    return !!(s->regs[R_DMACR] & DMACR_RESET);
}

156
static inline int stream_running(struct Stream *s)
157 158 159 160
{
    return s->regs[R_DMACR] & DMACR_RUNSTOP;
}

161
static inline int stream_idle(struct Stream *s)
162 163 164 165
{
    return !!(s->regs[R_DMASR] & DMASR_IDLE);
}

166
static void stream_reset(struct Stream *s)
167 168
{
    s->regs[R_DMASR] = DMASR_HALTED;  /* starts up halted.  */
169
    s->regs[R_DMACR] = 1 << 16; /* Starts with one in compl threshold.  */
170 171
}

172
/* Map an offset addr into a channel index.  */
A
Avi Kivity 已提交
173
static inline int streamid_from_addr(hwaddr addr)
174 175 176 177 178 179 180 181
{
    int sid;

    sid = addr / (0x30);
    sid &= 1;
    return sid;
}

A
Avi Kivity 已提交
182
static void stream_desc_load(struct Stream *s, hwaddr addr)
183 184 185
{
    struct SDesc *d = &s->desc;

S
Stefan Weil 已提交
186
    cpu_physical_memory_read(addr, d, sizeof *d);
187 188 189 190 191 192 193 194

    /* Convert from LE into host endianness.  */
    d->buffer_address = le64_to_cpu(d->buffer_address);
    d->nxtdesc = le64_to_cpu(d->nxtdesc);
    d->control = le32_to_cpu(d->control);
    d->status = le32_to_cpu(d->status);
}

A
Avi Kivity 已提交
195
static void stream_desc_store(struct Stream *s, hwaddr addr)
196 197 198 199 200 201 202 203
{
    struct SDesc *d = &s->desc;

    /* Convert from host endianness into LE.  */
    d->buffer_address = cpu_to_le64(d->buffer_address);
    d->nxtdesc = cpu_to_le64(d->nxtdesc);
    d->control = cpu_to_le32(d->control);
    d->status = cpu_to_le32(d->status);
S
Stefan Weil 已提交
204
    cpu_physical_memory_write(addr, d, sizeof *d);
205 206
}

207
static void stream_update_irq(struct Stream *s)
208 209 210 211 212 213 214 215 216 217 218
{
    unsigned int pending, mask, irq;

    pending = s->regs[R_DMASR] & DMASR_IRQ_MASK;
    mask = s->regs[R_DMACR] & DMASR_IRQ_MASK;

    irq = pending & mask;

    qemu_set_irq(s->irq, !!irq);
}

219
static void stream_reload_complete_cnt(struct Stream *s)
220 221 222 223 224 225 226 227
{
    unsigned int comp_th;
    comp_th = (s->regs[R_DMACR] >> 16) & 0xff;
    s->complete_cnt = comp_th;
}

static void timer_hit(void *opaque)
{
228
    struct Stream *s = opaque;
229 230 231 232 233 234

    stream_reload_complete_cnt(s);
    s->regs[R_DMASR] |= DMASR_DLY_IRQ;
    stream_update_irq(s);
}

235
static void stream_complete(struct Stream *s)
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
{
    unsigned int comp_delay;

    /* Start the delayed timer.  */
    comp_delay = s->regs[R_DMACR] >> 24;
    if (comp_delay) {
        ptimer_stop(s->ptimer);
        ptimer_set_count(s->ptimer, comp_delay);
        ptimer_run(s->ptimer, 1);
    }

    s->complete_cnt--;
    if (s->complete_cnt == 0) {
        /* Raise the IOC irq.  */
        s->regs[R_DMASR] |= DMASR_IOC_IRQ;
        stream_reload_complete_cnt(s);
    }
}

255 256
static void stream_process_mem2s(struct Stream *s, StreamSlave *tx_data_dev,
                                 StreamSlave *tx_control_dev)
257 258 259 260 261 262 263 264 265 266 267 268 269
{
    uint32_t prev_d;
    unsigned char txbuf[16 * 1024];
    unsigned int txlen;

    if (!stream_running(s) || stream_idle(s)) {
        return;
    }

    while (1) {
        stream_desc_load(s, s->regs[R_CURDESC]);

        if (s->desc.status & SDESC_STATUS_COMPLETE) {
270
            s->regs[R_DMASR] |= DMASR_HALTED;
271 272 273 274 275
            break;
        }

        if (stream_desc_sof(&s->desc)) {
            s->pos = 0;
276
            stream_push(tx_control_dev, s->desc.app, sizeof(s->desc.app));
277 278 279 280 281 282 283 284 285 286 287 288 289
        }

        txlen = s->desc.control & SDESC_CTRL_LEN_MASK;
        if ((txlen + s->pos) > sizeof txbuf) {
            hw_error("%s: too small internal txbuf! %d\n", __func__,
                     txlen + s->pos);
        }

        cpu_physical_memory_read(s->desc.buffer_address,
                                 txbuf + s->pos, txlen);
        s->pos += txlen;

        if (stream_desc_eof(&s->desc)) {
290
            stream_push(tx_data_dev, txbuf, s->pos);
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
            s->pos = 0;
            stream_complete(s);
        }

        /* Update the descriptor.  */
        s->desc.status = txlen | SDESC_STATUS_COMPLETE;
        stream_desc_store(s, s->regs[R_CURDESC]);

        /* Advance.  */
        prev_d = s->regs[R_CURDESC];
        s->regs[R_CURDESC] = s->desc.nxtdesc;
        if (prev_d == s->regs[R_TAILDESC]) {
            s->regs[R_DMASR] |= DMASR_IDLE;
            break;
        }
    }
}

309
static size_t stream_process_s2mem(struct Stream *s, unsigned char *buf,
310
                                   size_t len)
311 312 313
{
    uint32_t prev_d;
    unsigned int rxlen;
314
    size_t pos = 0;
315 316 317
    int sof = 1;

    if (!stream_running(s) || stream_idle(s)) {
318
        return 0;
319 320 321 322 323 324
    }

    while (len) {
        stream_desc_load(s, s->regs[R_CURDESC]);

        if (s->desc.status & SDESC_STATUS_COMPLETE) {
325
            s->regs[R_DMASR] |= DMASR_HALTED;
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
            break;
        }

        rxlen = s->desc.control & SDESC_CTRL_LEN_MASK;
        if (rxlen > len) {
            /* It fits.  */
            rxlen = len;
        }

        cpu_physical_memory_write(s->desc.buffer_address, buf + pos, rxlen);
        len -= rxlen;
        pos += rxlen;

        /* Update the descriptor.  */
        if (!len) {
            stream_complete(s);
342
            memcpy(s->desc.app, s->app, sizeof(s->desc.app));
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
            s->desc.status |= SDESC_STATUS_EOF;
        }

        s->desc.status |= sof << SDESC_STATUS_SOF_BIT;
        s->desc.status |= SDESC_STATUS_COMPLETE;
        stream_desc_store(s, s->regs[R_CURDESC]);
        sof = 0;

        /* Advance.  */
        prev_d = s->regs[R_CURDESC];
        s->regs[R_CURDESC] = s->desc.nxtdesc;
        if (prev_d == s->regs[R_TAILDESC]) {
            s->regs[R_DMASR] |= DMASR_IDLE;
            break;
        }
    }
359 360

    return pos;
361 362
}

363 364 365 366 367 368 369 370 371 372
static void xilinx_axidma_reset(DeviceState *dev)
{
    int i;
    XilinxAXIDMA *s = XILINX_AXI_DMA(dev);

    for (i = 0; i < 2; i++) {
        stream_reset(&s->streams[i]);
    }
}

373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
static size_t
xilinx_axidma_control_stream_push(StreamSlave *obj, unsigned char *buf,
                                  size_t len)
{
    XilinxAXIDMAStreamSlave *cs = XILINX_AXI_DMA_CONTROL_STREAM(obj);
    struct Stream *s = &cs->dma->streams[1];

    if (len != CONTROL_PAYLOAD_SIZE) {
        hw_error("AXI DMA requires %d byte control stream payload\n",
                 (int)CONTROL_PAYLOAD_SIZE);
    }

    memcpy(s->app, buf, len);
    return len;
}

389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
static bool
xilinx_axidma_data_stream_can_push(StreamSlave *obj,
                                   StreamCanPushNotifyFn notify,
                                   void *notify_opaque)
{
    XilinxAXIDMAStreamSlave *ds = XILINX_AXI_DMA_DATA_STREAM(obj);
    struct Stream *s = &ds->dma->streams[1];

    if (!stream_running(s) || stream_idle(s)) {
        ds->dma->notify = notify;
        ds->dma->notify_opaque = notify_opaque;
        return false;
    }

    return true;
}

P
Peter Crosthwaite 已提交
406
static size_t
407
xilinx_axidma_data_stream_push(StreamSlave *obj, unsigned char *buf, size_t len)
408
{
409 410
    XilinxAXIDMAStreamSlave *ds = XILINX_AXI_DMA_DATA_STREAM(obj);
    struct Stream *s = &ds->dma->streams[1];
411
    size_t ret;
412

413
    ret = stream_process_s2mem(s, buf, len);
414
    stream_update_irq(s);
415
    return ret;
416 417
}

A
Avi Kivity 已提交
418
static uint64_t axidma_read(void *opaque, hwaddr addr,
A
Avi Kivity 已提交
419
                            unsigned size)
420
{
421
    XilinxAXIDMA *d = opaque;
422
    struct Stream *s;
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
    uint32_t r = 0;
    int sid;

    sid = streamid_from_addr(addr);
    s = &d->streams[sid];

    addr = addr % 0x30;
    addr >>= 2;
    switch (addr) {
        case R_DMACR:
            /* Simulate one cycles reset delay.  */
            s->regs[addr] &= ~DMACR_RESET;
            r = s->regs[addr];
            break;
        case R_DMASR:
            s->regs[addr] &= 0xffff;
            s->regs[addr] |= (s->complete_cnt & 0xff) << 16;
            s->regs[addr] |= (ptimer_get_count(s->ptimer) & 0xff) << 24;
            r = s->regs[addr];
            break;
        default:
            r = s->regs[addr];
            D(qemu_log("%s ch=%d addr=" TARGET_FMT_plx " v=%x\n",
                           __func__, sid, addr * 4, r));
            break;
    }
    return r;

}

A
Avi Kivity 已提交
453
static void axidma_write(void *opaque, hwaddr addr,
A
Avi Kivity 已提交
454
                         uint64_t value, unsigned size)
455
{
456
    XilinxAXIDMA *d = opaque;
457
    struct Stream *s;
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
    int sid;

    sid = streamid_from_addr(addr);
    s = &d->streams[sid];

    addr = addr % 0x30;
    addr >>= 2;
    switch (addr) {
        case R_DMACR:
            /* Tailptr mode is always on.  */
            value |= DMACR_TAILPTR_MODE;
            /* Remember our previous reset state.  */
            value |= (s->regs[addr] & DMACR_RESET);
            s->regs[addr] = value;

            if (value & DMACR_RESET) {
                stream_reset(s);
            }

            if ((value & 1) && !stream_resetting(s)) {
                /* Start processing.  */
                s->regs[R_DMASR] &= ~(DMASR_HALTED | DMASR_IDLE);
            }
            stream_reload_complete_cnt(s);
            break;

        case R_DMASR:
            /* Mask away write to clear irq lines.  */
            value &= ~(value & DMASR_IRQ_MASK);
            s->regs[addr] = value;
            break;

        case R_TAILDESC:
            s->regs[addr] = value;
            s->regs[R_DMASR] &= ~DMASR_IDLE; /* Not idle.  */
            if (!sid) {
494
                stream_process_mem2s(s, d->tx_data_dev, d->tx_control_dev);
495 496 497 498
            }
            break;
        default:
            D(qemu_log("%s: ch=%d addr=" TARGET_FMT_plx " v=%x\n",
499
                  __func__, sid, addr * 4, (unsigned)value));
500 501 502
            s->regs[addr] = value;
            break;
    }
503
    if (sid == 1 && d->notify) {
504
        StreamCanPushNotifyFn notifytmp = d->notify;
505
        d->notify = NULL;
506
        notifytmp(d->notify_opaque);
507
    }
508 509 510
    stream_update_irq(s);
}

A
Avi Kivity 已提交
511 512 513 514
static const MemoryRegionOps axidma_ops = {
    .read = axidma_read,
    .write = axidma_write,
    .endianness = DEVICE_NATIVE_ENDIAN,
515 516
};

517
static void xilinx_axidma_realize(DeviceState *dev, Error **errp)
518
{
519
    XilinxAXIDMA *s = XILINX_AXI_DMA(dev);
520
    XilinxAXIDMAStreamSlave *ds = XILINX_AXI_DMA_DATA_STREAM(&s->rx_data_dev);
521 522
    XilinxAXIDMAStreamSlave *cs = XILINX_AXI_DMA_CONTROL_STREAM(
                                                            &s->rx_control_dev);
523
    Error *local_err = NULL;
524 525

    object_property_add_link(OBJECT(ds), "dma", TYPE_XILINX_AXI_DMA,
526
                             (Object **)&ds->dma,
527
                             object_property_allow_set_link,
528
                             OBJ_PROP_LINK_UNREF_ON_RELEASE,
529
                             &local_err);
530
    object_property_add_link(OBJECT(cs), "dma", TYPE_XILINX_AXI_DMA,
531
                             (Object **)&cs->dma,
532
                             object_property_allow_set_link,
533
                             OBJ_PROP_LINK_UNREF_ON_RELEASE,
534 535
                             &local_err);
    if (local_err) {
536 537
        goto xilinx_axidma_realize_fail;
    }
538 539 540
    object_property_set_link(OBJECT(ds), OBJECT(s), "dma", &local_err);
    object_property_set_link(OBJECT(cs), OBJECT(s), "dma", &local_err);
    if (local_err) {
541 542 543
        goto xilinx_axidma_realize_fail;
    }

544 545 546
    int i;

    for (i = 0; i < 2; i++) {
547 548 549 550
        struct Stream *st = &s->streams[i];

        st->nr = i;
        st->bh = qemu_bh_new(timer_hit, st);
551
        st->ptimer = ptimer_init(st->bh, PTIMER_POLICY_DEFAULT);
552
        ptimer_set_freq(st->ptimer, s->freqhz);
553
    }
554 555 556 557
    return;

xilinx_axidma_realize_fail:
    if (!*errp) {
558
        *errp = local_err;
559
    }
560 561
}

562
static void xilinx_axidma_init(Object *obj)
563
{
564
    XilinxAXIDMA *s = XILINX_AXI_DMA(obj);
565
    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
566 567

    object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
568
                             (Object **)&s->tx_data_dev,
569
                             qdev_prop_allow_set_link_before_realize,
570 571
                             OBJ_PROP_LINK_UNREF_ON_RELEASE,
                             &error_abort);
572 573
    object_property_add_link(obj, "axistream-control-connected",
                             TYPE_STREAM_SLAVE,
574
                             (Object **)&s->tx_control_dev,
575
                             qdev_prop_allow_set_link_before_realize,
576 577
                             OBJ_PROP_LINK_UNREF_ON_RELEASE,
                             &error_abort);
578

579 580 581 582
    object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev),
                      TYPE_XILINX_AXI_DMA_DATA_STREAM);
    object_initialize(&s->rx_control_dev, sizeof(s->rx_control_dev),
                      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 589 590
    sysbus_init_irq(sbd, &s->streams[0].irq);
    sysbus_init_irq(sbd, &s->streams[1].irq);

591
    memory_region_init_io(&s->iomem, obj, &axidma_ops, s,
592 593
                          "xlnx.axi-dma", R_MAX * 4 * 2);
    sysbus_init_mmio(sbd, &s->iomem);
594 595
}

596
static Property axidma_properties[] = {
597
    DEFINE_PROP_UINT32("freqhz", XilinxAXIDMA, freqhz, 50000000),
598 599 600 601 602
    DEFINE_PROP_END_OF_LIST(),
};

static void axidma_class_init(ObjectClass *klass, void *data)
{
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 611 612 613 614
static StreamSlaveClass xilinx_axidma_data_stream_class = {
    .push = xilinx_axidma_data_stream_push,
    .can_push = xilinx_axidma_data_stream_can_push,
};

615 616 617 618
static StreamSlaveClass xilinx_axidma_control_stream_class = {
    .push = xilinx_axidma_control_stream_push,
};

619 620 621 622
static void xilinx_axidma_stream_class_init(ObjectClass *klass, void *data)
{
    StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);

623 624
    ssc->push = ((StreamSlaveClass *)data)->push;
    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 636 637 638 639
};

static const TypeInfo xilinx_axidma_data_stream_info = {
    .name          = TYPE_XILINX_AXI_DMA_DATA_STREAM,
    .parent        = TYPE_OBJECT,
    .instance_size = sizeof(struct XilinxAXIDMAStreamSlave),
    .class_init    = xilinx_axidma_stream_class_init,
640
    .class_data    = &xilinx_axidma_data_stream_class,
641 642 643 644
    .interfaces = (InterfaceInfo[]) {
        { TYPE_STREAM_SLAVE },
        { }
    }
645 646
};

647 648 649 650 651 652 653 654 655 656 657 658
static const TypeInfo xilinx_axidma_control_stream_info = {
    .name          = TYPE_XILINX_AXI_DMA_CONTROL_STREAM,
    .parent        = TYPE_OBJECT,
    .instance_size = sizeof(struct XilinxAXIDMAStreamSlave),
    .class_init    = xilinx_axidma_stream_class_init,
    .class_data    = &xilinx_axidma_control_stream_class,
    .interfaces = (InterfaceInfo[]) {
        { TYPE_STREAM_SLAVE },
        { }
    }
};

A
Andreas Färber 已提交
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
}

A
Andreas Färber 已提交
666
type_init(xilinx_axidma_register_types)