qemu/hw/dma/csu_stream_dma.c
<<
>>
Prefs
   1/*
   2 * QEMU model of ZynqMP CSU Stream DMA
   3 *
   4 * Copyright (c) 2013 Xilinx Inc
   5 * Copyright (c) 2013 Peter Crosthwaite <peter.crosthwaite@xilinx.com>
   6 * Copyright (c) 2013 Edgar E. Iglesias <edgar.iglesias@xilinx.com>
   7 *
   8 * Permission is hereby granted, free of charge, to any person obtaining a copy
   9 * of this software and associated documentation files (the "Software"), to deal
  10 * in the Software without restriction, including without limitation the rights
  11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12 * copies of the Software, and to permit persons to whom the Software is
  13 * furnished to do so, subject to the following conditions:
  14 *
  15 * The above copyright notice and this permission notice shall be included in
  16 * all copies or substantial portions of the Software.
  17 *
  18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24 * THE SOFTWARE.
  25 */
  26
  27#include "qemu/osdep.h"
  28#include "hw/sysbus.h"
  29#include "qemu/log.h"
  30
  31#include "hw/stream.h"
  32#include "hw/dma-ctrl.h"
  33#include "hw/ptimer.h"
  34#include "qemu/bitops.h"
  35#include "sysemu/dma.h"
  36#include "hw/register.h"
  37#include "qapi/error.h"
  38#include "qemu/main-loop.h"
  39#include "migration/vmstate.h"
  40#include "hw/qdev-properties.h"
  41
  42#include "hw/fdt_generic_util.h"
  43
  44#define TYPE_ZYNQMP_CSU_DMA "zynqmp.csu-dma"
  45
  46#define ZYNQMP_CSU_DMA(obj) \
  47     OBJECT_CHECK(ZynqMPCSUDMA, (obj), TYPE_ZYNQMP_CSU_DMA)
  48
  49#ifndef ZYNQMP_CSU_DMA_ERR_DEBUG
  50#define ZYNQMP_CSU_DMA_ERR_DEBUG 0
  51#endif
  52
  53#define DB_PRINT_L(lvl, fmt, args...) do {\
  54    if (ZYNQMP_CSU_DMA_ERR_DEBUG > lvl) {\
  55        qemu_log(TYPE_ZYNQMP_CSU_DMA ": %s:" fmt, __func__, ## args);\
  56    } \
  57} while (0);
  58
  59#define DB_PRINT(fmt, args...) DB_PRINT_L(0, fmt, ##args)
  60
  61REG32(ADDR, 0x0)
  62    FIELD(ADDR, ADDR, 2, 30)
  63REG32(SIZE, 0x4)
  64    FIELD(SIZE, SIZE, 2, 27)
  65    FIELD(SIZE, LAST_WORD, 0, 1)
  66REG32(STATUS, 0x8)
  67    FIELD(STATUS, CMD_Q_EMPTY, 17, 1)
  68    FIELD(STATUS, CMD_Q_FULL, 16, 1)
  69    FIELD(STATUS, DONE_CNT, 13, 3)
  70    FIELD(STATUS, SRC_FIFO_LEVEL, 5, 8)
  71    FIELD(STATUS, RD_OUTSTANDING, 1, 4)
  72    FIELD(STATUS, BUSY, 0, 1)
  73REG32(CTRL, 0xc)
  74    FIELD(CTRL, APB_ERR_RESP, 24, 1)
  75    FIELD(CTRL, ENDIANNESS, 23, 1)
  76    FIELD(CTRL, AXI_BRST_TYPE, 22, 1)
  77    FIELD(CTRL, TIMEOUT_VAL, 10, 12)
  78    FIELD(CTRL, FIFO_THRESH, 2, 8)
  79    FIELD(CTRL, PAUSE_STRM, 1, 1)
  80    FIELD(CTRL, PAUSE_MEM, 0, 1)
  81REG32(CRC0, 0x10)
  82REG32(INT_STATUS, 0x14)
  83    FIELD(INT_STATUS, WR_FULL_CMDQ, 7, 1)
  84    FIELD(INT_STATUS, INVALID_APB, 6, 1)
  85    FIELD(INT_STATUS, THRESH_HIT, 5, 1)
  86    FIELD(INT_STATUS, TIMEOUT_MEM, 4, 1)
  87    FIELD(INT_STATUS, TIMEOUT_STRM, 3, 1)
  88    FIELD(INT_STATUS, AXI_RDERR, 2, 1)
  89    FIELD(INT_STATUS, DONE, 1, 1)
  90    FIELD(INT_STATUS, MEM_DONE, 0, 1)
  91REG32(INT_ENABLE, 0x18)
  92    FIELD(INT_ENABLE, WR_FULL_CMDQ, 7, 1)
  93    FIELD(INT_ENABLE, INVALID_APB, 6, 1)
  94    FIELD(INT_ENABLE, THRESH_HIT, 5, 1)
  95    FIELD(INT_ENABLE, TIMEOUT_MEM, 4, 1)
  96    FIELD(INT_ENABLE, TIMEOUT_STRM, 3, 1)
  97    FIELD(INT_ENABLE, AXI_RDERR, 2, 1)
  98    FIELD(INT_ENABLE, DONE, 1, 1)
  99    FIELD(INT_ENABLE, MEM_DONE, 0, 1)
 100REG32(INT_DISABLE, 0x1c)
 101    FIELD(INT_DISABLE, WR_FULL_CMDQ, 7, 1)
 102    FIELD(INT_DISABLE, INVALID_APB, 6, 1)
 103    FIELD(INT_DISABLE, THRESH_HIT, 5, 1)
 104    FIELD(INT_DISABLE, TIMEOUT_MEM, 4, 1)
 105    FIELD(INT_DISABLE, TIMEOUT_STRM, 3, 1)
 106    FIELD(INT_DISABLE, AXI_RDERR, 2, 1)
 107    FIELD(INT_DISABLE, DONE, 1, 1)
 108    FIELD(INT_DISABLE, MEM_DONE, 0, 1)
 109REG32(INT_MASK, 0x20)
 110    FIELD(INT_MASK, WR_FULL_CMDQ, 7, 1)
 111    FIELD(INT_MASK, INVALID_APB, 6, 1)
 112    FIELD(INT_MASK, THRESH_HIT, 5, 1)
 113    FIELD(INT_MASK, TIMEOUT_MEM, 4, 1)
 114    FIELD(INT_MASK, TIMEOUT_STRM, 3, 1)
 115    FIELD(INT_MASK, AXI_RDERR, 2, 1)
 116    FIELD(INT_MASK, DONE, 1, 1)
 117    FIELD(INT_MASK, MEM_DONE, 0, 1)
 118REG32(CTRL2, 0x24)
 119    FIELD(CTRL2, RAM_EMASA, 27, 1)
 120    FIELD(CTRL2, ARCACHE, 24, 3)
 121    FIELD(CTRL2, ROUTE_BIT, 23, 1)
 122    FIELD(CTRL2, TIMEOUT_EN, 22, 1)
 123    FIELD(CTRL2, RAM_EMAB, 19, 3)
 124    FIELD(CTRL2, RAM_EMAA, 16, 3)
 125    FIELD(CTRL2, TIMEOUT_PRE, 4, 12)
 126    FIELD(CTRL2, MAX_OUTS_CMDS, 0, 4)
 127REG32(ADDR_MSB, 0x28)
 128    FIELD(ADDR_MSB, ADDR_MSB, 0, 17)
 129
 130#define R_MAX (R_ADDR_MSB + 1)
 131
 132/* Remove these */
 133#define CTRL_RSVD       (~((1 << 25) - 1))
 134
 135#define INT_RSVD        (~((1 << 8) - 1))
 136#define INT_ALL_SRC     ((~(INT_RSVD)) & (~(R_INT_STATUS_WR_FULL_CMDQ_MASK)))
 137#define INT_ALL_DST     ((~(INT_RSVD)) & (~(R_INT_STATUS_MEM_DONE_MASK)))
 138
 139#define CTRL2_RSVD      (~((1 << 28) - 1))
 140#define SIZE_MASK       ((1 << 29) - 1)
 141
 142typedef struct ZynqMPCSUDMA {
 143    SysBusDevice busdev;
 144    MemoryRegion iomem;
 145    MemTxAttrs *attr;
 146    MemoryRegion *dma_mr;
 147    AddressSpace *dma_as;
 148    qemu_irq irq;
 149    StreamSlave *tx_dev;  /* Used as generic StreamSlave */
 150    StreamSlave *tx_dev0; /* Used for pmc dma0 */
 151    StreamSlave *tx_dev1; /* Used for pmc dma1 */
 152    ptimer_state *src_timer;
 153
 154    bool is_dst;
 155    bool byte_align;
 156    uint16_t width;
 157    uint32_t r_size_last_word_mask;
 158
 159    StreamCanPushNotifyFn notify;
 160    void *notify_opaque;
 161
 162    dmactrl_notify_fn dma_ctrl_notify;
 163    void *dma_ctrl_opaque;
 164
 165    uint32_t regs[R_MAX];
 166    RegisterInfo regs_info[R_MAX];
 167} ZynqMPCSUDMA;
 168
 169static bool dmach_is_paused(ZynqMPCSUDMA *s)
 170{
 171    bool paused;
 172
 173    paused = !!(s->regs[R_CTRL] & R_CTRL_PAUSE_STRM_MASK);
 174    paused |= !!(s->regs[R_CTRL] & R_CTRL_PAUSE_MEM_MASK);
 175    return paused;
 176}
 177
 178static bool dmach_get_eop(ZynqMPCSUDMA *s)
 179{
 180    return !!(s->regs[R_SIZE] & s->r_size_last_word_mask);
 181}
 182
 183static uint32_t dmach_get_size(ZynqMPCSUDMA *s)
 184{
 185    uint32_t ret;
 186
 187    if (s->byte_align) {
 188        ret = s->regs[R_SIZE];
 189    } else {
 190        ret = s->regs[R_SIZE] & ~3;
 191    }
 192
 193    ret &= SIZE_MASK;
 194    return ret;
 195}
 196
 197static void dmach_set_size(ZynqMPCSUDMA *s, uint32_t size)
 198{
 199    size &= SIZE_MASK;
 200    if (!s->byte_align) {
 201        assert((size & 3) == 0);
 202    }
 203    s->regs[R_SIZE] &= s->r_size_last_word_mask;
 204    s->regs[R_SIZE] |= size;
 205}
 206
 207static bool dmach_burst_is_fixed(ZynqMPCSUDMA *s)
 208{
 209    return !!(s->regs[R_CTRL] & R_CTRL_AXI_BRST_TYPE_MASK);
 210}
 211
 212static bool dmach_timeout_enabled(ZynqMPCSUDMA *s)
 213{
 214    return s->regs[R_CTRL2] & R_CTRL2_TIMEOUT_EN_MASK;
 215}
 216
 217static inline void dmach_update_dma_cnt(ZynqMPCSUDMA *s, int a)
 218{
 219    int cnt;
 220
 221    /* Increase dma_cnt.  */
 222    cnt = ARRAY_FIELD_EX32(s->regs, STATUS, DONE_CNT) + a;
 223    ARRAY_FIELD_DP32(s->regs, STATUS, DONE_CNT, cnt);
 224}
 225
 226static void dmach_done(ZynqMPCSUDMA *s)
 227{
 228    dmach_update_dma_cnt(s, +1);
 229    s->regs[R_STATUS] &= ~R_STATUS_BUSY_MASK;
 230
 231    DB_PRINT("\n");
 232    s->regs[R_INT_STATUS] |= R_INT_STATUS_DONE_MASK;
 233    if (!s->is_dst) {
 234        s->regs[R_INT_STATUS] |= R_INT_STATUS_MEM_DONE_MASK;
 235    }
 236}
 237
 238static void dmach_advance(ZynqMPCSUDMA *s, unsigned int len)
 239{
 240    uint32_t size = dmach_get_size(s);
 241
 242    if (!s->byte_align) {
 243        /* Has to be 32bit aligned.  */
 244        assert((len & 3) == 0);
 245    }
 246    assert(len <= size);
 247
 248    if (!dmach_burst_is_fixed(s)) {
 249        s->regs[R_ADDR] += len;
 250    }
 251
 252    size -= len;
 253    dmach_set_size(s, size);
 254
 255    /* Notify dma-ctrl clients when the transfer has been completed */
 256    if (size == 0 && s->dma_ctrl_notify) {
 257        s->dma_ctrl_notify(s->dma_ctrl_opaque);
 258    }
 259
 260    if (size == 0) {
 261        dmach_done(s);
 262    }
 263}
 264
 265static void dmach_data_process(ZynqMPCSUDMA *s, uint8_t *buf, unsigned int len)
 266{
 267    unsigned int bswap;
 268    unsigned int i;
 269
 270    /* Xor only for src channel.  */
 271    bswap = s->regs[R_CTRL] & R_CTRL_ENDIANNESS_MASK;
 272    if (s->is_dst && !bswap) {
 273        /* Fast!  */
 274        return;
 275    }
 276
 277    if (!s->byte_align) {
 278        /* buf might not be 32bit aligned... slooow.  */
 279        assert((len & 3) == 0);
 280    }
 281    /* FIXME: move me to bitops.c for global reusability */
 282    for (i = 0; i < len; i += 4) {
 283        uint8_t *b = &buf[i];
 284        union {
 285            uint8_t u8[4];
 286            uint32_t u32;
 287        } v = {
 288            .u8 = { b[0], b[1], b[2], b[3] }
 289        };
 290
 291        if (!s->is_dst) {
 292            s->regs[R_CRC0] += v.u32;
 293        }
 294        if (bswap) {
 295            /* No point using bswap, we need to writeback
 296               into a potentially unaligned pointer..   */
 297            b[0] = v.u8[3];
 298            b[1] = v.u8[2];
 299            b[2] = v.u8[1];
 300            b[3] = v.u8[0];
 301        }
 302    }
 303}
 304
 305static inline uint64_t dmach_addr(ZynqMPCSUDMA *s)
 306{
 307    uint64_t addr;
 308
 309    addr = s->regs[R_ADDR];
 310    addr |= (uint64_t) s->regs[R_ADDR_MSB] << 32;
 311    return addr;
 312}
 313
 314/* len is in bytes.  */
 315static void dmach_write(ZynqMPCSUDMA *s, uint8_t *buf, unsigned int len)
 316{
 317    uint64_t addr = dmach_addr(s);
 318
 319    dmach_data_process(s, buf, len);
 320    if (dmach_burst_is_fixed(s)) {
 321        unsigned int i;
 322
 323        for (i = 0; i < len; i += s->width) {
 324            unsigned int wlen = MIN(len - i, s->width);
 325
 326            address_space_rw(s->dma_as, addr, *s->attr, buf, wlen, true);
 327            buf += wlen;
 328        }
 329    } else {
 330        address_space_rw(s->dma_as, addr, *s->attr, buf, len, true);
 331    }
 332}
 333
 334/* len is in bytes.  */
 335static inline void dmach_read(ZynqMPCSUDMA *s, uint8_t *buf, unsigned int len)
 336{
 337    uint64_t addr = dmach_addr(s);
 338
 339    if (dmach_burst_is_fixed(s)) {
 340        unsigned int i;
 341
 342        for (i = 0; i < len; i += s->width) {
 343            unsigned int rlen = MIN(len - i, s->width);
 344
 345            address_space_rw(s->dma_as, addr, *s->attr, buf + i, rlen, false);
 346        }
 347    } else {
 348        address_space_rw(s->dma_as, addr, *s->attr, buf, len, false);
 349    }
 350    dmach_data_process(s, buf, len);
 351}
 352
 353static void ronaldu_csu_dma_update_irq(ZynqMPCSUDMA *s)
 354{
 355    qemu_set_irq(s->irq, !!(s->regs[R_INT_STATUS] & ~s->regs[R_INT_MASK]));
 356}
 357
 358static void zynqmp_csu_dma_reset(DeviceState *dev)
 359{
 360    ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(dev);
 361    int i;
 362
 363    for (i = 0; i < R_MAX; i++) {
 364        register_reset(&s->regs_info[i]);
 365    }
 366}
 367
 368static size_t zynqmp_csu_dma_stream_push(StreamSlave *obj, uint8_t *buf,
 369                                          size_t len, bool eop)
 370{
 371    ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(obj);
 372    uint32_t size = dmach_get_size(s);
 373    uint32_t btt = MIN(size, len);
 374
 375    assert(s->is_dst);
 376    if (len && (dmach_is_paused(s) || btt == 0)) {
 377        qemu_log_mask(LOG_GUEST_ERROR,
 378                      "csu-dma: DST channel dropping %zd b of data.\n", len);
 379        s->regs[R_INT_STATUS] |= R_INT_STATUS_WR_FULL_CMDQ_MASK;
 380        return len;
 381    }
 382
 383    if (!btt) {
 384        return 0;
 385    }
 386
 387    /* DMA transfer.  */
 388    dmach_write(s, buf, btt);
 389    dmach_advance(s, btt);
 390    ronaldu_csu_dma_update_irq(s);
 391    return btt;
 392}
 393
 394static bool zynqmp_csu_dma_stream_can_push(StreamSlave *obj,
 395                                            StreamCanPushNotifyFn notify,
 396                                            void *notify_opaque)
 397{
 398    ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(obj);
 399    /* FIXME: DST channel side has no flow-control.  */
 400    if (dmach_get_size(s) != 0) {
 401        return true;
 402    } else {
 403        s->notify = notify;
 404        s->notify_opaque = notify_opaque;
 405        return false;
 406    }
 407}
 408
 409static void zynqmp_csu_dma_src_notify(void *opaque)
 410{
 411    ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(opaque);
 412    unsigned char buf[4 * 1024];
 413
 414    ptimer_transaction_begin(s->src_timer);
 415    /* Stop the backpreassure timer.  */
 416    ptimer_stop(s->src_timer);
 417
 418    while (dmach_get_size(s) && !dmach_is_paused(s) &&
 419           stream_can_push(s->tx_dev, zynqmp_csu_dma_src_notify, s)) {
 420        uint32_t size = dmach_get_size(s);
 421        unsigned int plen = MIN(size, sizeof buf);
 422        bool eop = false;
 423        size_t ret;
 424
 425        /* Did we fit it all?  */
 426        if (size == plen && dmach_get_eop(s)) {
 427            eop = true;
 428        }
 429
 430        /* DMA transfer.  */
 431        dmach_read(s, buf, plen);
 432        ret = stream_push(s->tx_dev, buf, plen, eop);
 433        dmach_advance(s, ret);
 434    }
 435
 436    /* REMOVE-ME?: Check for flow-control timeout. This is all theoretical as
 437       we currently never see backpressure.  */
 438    if (dmach_timeout_enabled(s) && dmach_get_size(s)
 439        && !stream_can_push(s->tx_dev, zynqmp_csu_dma_src_notify, s)) {
 440        unsigned int timeout = ARRAY_FIELD_EX32(s->regs, CTRL, TIMEOUT_VAL);
 441        unsigned int div = extract32(s->regs[R_CTRL2], 4, 12) + 1;
 442        unsigned int freq = 400 * 1000 * 1000;
 443
 444        freq /= div;
 445        ptimer_set_freq(s->src_timer, freq);
 446        ptimer_set_count(s->src_timer, timeout);
 447        ptimer_run(s->src_timer, 1);
 448    }
 449
 450    ptimer_transaction_commit(s->src_timer);
 451    ronaldu_csu_dma_update_irq(s);
 452}
 453
 454static void r_ctrl_post_write(RegisterInfo *reg, uint64_t val)
 455{
 456    ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(reg->opaque);
 457
 458    if (!s->is_dst) {
 459        if (!dmach_is_paused(s)) {
 460            zynqmp_csu_dma_src_notify(s);
 461        }
 462    } else {
 463        if (!dmach_is_paused(s) && s->notify) {
 464            s->notify(s->notify_opaque);
 465        }
 466    }
 467}
 468
 469static uint64_t size_pre_write(RegisterInfo *reg, uint64_t val)
 470{
 471    ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(reg->opaque);
 472    if (dmach_get_size(s) != 0) {
 473        qemu_log_mask(LOG_GUEST_ERROR,
 474                      "csu-dma: Starting DMA while already running.\n");
 475    }
 476    return val;
 477}
 478
 479static void size_post_write(RegisterInfo *reg, uint64_t val)
 480{
 481    ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(reg->opaque);
 482
 483    s->regs[R_STATUS] |= R_STATUS_BUSY_MASK;
 484    /* When starting the DMA channel with a zero length, it signals
 485       done immediately.  */
 486    if (dmach_get_size(s) == 0) {
 487        dmach_done(s);
 488        ronaldu_csu_dma_update_irq(s);
 489        return;
 490    }
 491
 492    if (!s->is_dst) {
 493        zynqmp_csu_dma_src_notify(s);
 494    } else {
 495        if (s->notify) {
 496            s->notify(s->notify_opaque);
 497        }
 498    }
 499}
 500
 501static uint64_t int_status_pre_write(RegisterInfo *reg, uint64_t val)
 502{
 503    ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(reg->opaque);
 504
 505    /* DMA counter decrements on interrupt clear */
 506    if (~val & s->regs[R_INT_STATUS] & R_INT_STATUS_DONE_MASK) {
 507        dmach_update_dma_cnt(s, -1);
 508    }
 509
 510    return val;
 511}
 512
 513static void int_status_post_write(RegisterInfo *reg, uint64_t val)
 514{
 515    ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(reg->opaque);
 516
 517    ronaldu_csu_dma_update_irq(s);
 518}
 519
 520static uint64_t int_enable_pre_write(RegisterInfo *reg, uint64_t val)
 521{
 522    ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(reg->opaque);
 523    uint32_t v32 = val;
 524
 525    s->regs[R_INT_MASK] &= ~v32;
 526    ronaldu_csu_dma_update_irq(s);
 527    return 0;
 528}
 529
 530static uint64_t int_disable_pre_write(RegisterInfo *reg, uint64_t val)
 531{
 532    ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(reg->opaque);
 533    uint32_t v32 = val;
 534
 535    s->regs[R_INT_MASK] |= v32;
 536    ronaldu_csu_dma_update_irq(s);
 537    return 0;
 538}
 539
 540static void src_timeout_hit(void *opaque)
 541{
 542    ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(opaque);
 543
 544    /* Ignore if the timeout is masked.  */
 545    if (!dmach_timeout_enabled(s)) {
 546        return;
 547    }
 548
 549    s->regs[R_INT_STATUS] |= R_INT_STATUS_TIMEOUT_STRM_MASK;
 550    ronaldu_csu_dma_update_irq(s);
 551}
 552
 553static void
 554zynqmp_csu_dma_dma_ctrl_read(DmaCtrl *dma_ctrl, hwaddr addr, uint32_t len,
 555 DmaCtrlNotify *notify, bool start_dma)
 556{
 557    ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(dma_ctrl);
 558    RegisterInfo *reg = &s->regs_info[R_SIZE];
 559    uint64_t we = MAKE_64BIT_MASK(0, 4 * 8);
 560
 561    s->regs[R_ADDR] = addr;
 562    s->regs[R_ADDR_MSB] = (uint64_t)addr >> 32;
 563
 564    if (notify) {
 565        s->dma_ctrl_notify = notify->cb;
 566        s->dma_ctrl_opaque = notify->opaque;
 567    }
 568
 569    if (start_dma) {
 570        register_write(reg, len, we, object_get_typename(OBJECT(s)),
 571                       ZYNQMP_CSU_DMA_ERR_DEBUG);
 572    } else {
 573        dmach_set_size(s, len);
 574    }
 575}
 576
 577static const RegisterAccessInfo *zynqmp_csu_dma_regs_info[] = {
 578#define DMACH_REGINFO(NAME, snd)                                              \
 579(const RegisterAccessInfo []) {                                               \
 580    {   .name = #NAME "_ADDR",          .addr = A_ADDR,                       \
 581    },{ .name = #NAME "_SIZE",          .addr = A_SIZE,                       \
 582        .pre_write = size_pre_write,                                          \
 583        .post_write = size_post_write                                         \
 584    },{ .name = #NAME "_STATUS",        .addr = A_STATUS,                     \
 585        .w1c = R_STATUS_DONE_CNT_MASK                                         \
 586    },{ .name = #NAME "_CTRL",          .addr = A_CTRL,                       \
 587        .ro = snd ? CTRL_RSVD : 0,                                            \
 588        .reset = (snd ? 0 : 0x40 << R_CTRL_FIFO_THRESH_SHIFT) |               \
 589                     R_CTRL_TIMEOUT_VAL_MASK |                                \
 590                     0x80 << R_CTRL_FIFO_THRESH_SHIFT,                        \
 591        .post_write = r_ctrl_post_write                                       \
 592    },{ .name =  #NAME "_CRC0",          .addr = A_CRC0,                      \
 593    },{ .name =  #NAME "_INT_STATUS",   .addr = A_INT_STATUS,                 \
 594        .w1c = ~0,                                                            \
 595        .pre_write = int_status_pre_write,                                    \
 596        .post_write = int_status_post_write                                   \
 597    },{ .name =  #NAME "_INT_ENABLE",   .addr = A_INT_ENABLE,                 \
 598        .pre_write = int_enable_pre_write                                     \
 599    },{ .name =  #NAME "_INT_DISABLE",  .addr = A_INT_DISABLE,                \
 600        .pre_write = int_disable_pre_write                                    \
 601    },{ .name =  #NAME "_INT_MASK",     .addr = A_INT_MASK,                   \
 602        .ro = ~0,                                                             \
 603        .reset = snd ? INT_ALL_SRC : INT_ALL_DST,                             \
 604    },{ .name =  #NAME "_CTRL2",        .addr = A_CTRL2,                      \
 605        .ro = CTRL2_RSVD,                                                     \
 606        .reset = 0x8 << R_CTRL2_MAX_OUTS_CMDS_SHIFT |                         \
 607                     0xFFF << R_CTRL2_TIMEOUT_PRE_SHIFT | 0x081b0000,         \
 608    },{ .name =  #NAME "_ADDR_MSB",     .addr = A_ADDR_MSB,                   \
 609    }                                                                         \
 610}
 611    DMACH_REGINFO(DMA_SRC, true),
 612    DMACH_REGINFO(DMA_DST, false)
 613};
 614
 615static const MemoryRegionOps zynqmp_csu_dma_ops = {
 616    .read = register_read_memory,
 617    .write = register_write_memory,
 618    .endianness = DEVICE_LITTLE_ENDIAN,
 619    .valid = {
 620        .min_access_size = 4,
 621        .max_access_size = 4,
 622    }
 623};
 624
 625static void zynqmp_csu_dma_realize(DeviceState *dev, Error **errp)
 626{
 627    ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(dev);
 628    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
 629    RegisterInfoArray *reg_array;
 630
 631    reg_array =
 632        register_init_block32(dev, zynqmp_csu_dma_regs_info[!!s->is_dst],
 633                              R_MAX,
 634                              s->regs_info, s->regs,
 635                              &zynqmp_csu_dma_ops,
 636                              ZYNQMP_CSU_DMA_ERR_DEBUG,
 637                              R_MAX * 4);
 638    memory_region_add_subregion(&s->iomem,
 639                                0x0,
 640                                &reg_array->mem);
 641    sysbus_init_mmio(sbd, &s->iomem);
 642
 643    if (!s->tx_dev) {
 644        if (s->tx_dev0 && s->tx_dev1) {
 645            error_setg(&error_fatal, "zynqmp.csu-dma: Both tx_dev0 & tx_dev1"
 646                             " StreamSlaves are defined");
 647        }
 648        s->tx_dev = s->tx_dev0 ? s->tx_dev0 :
 649                                 s->tx_dev1 ? s->tx_dev1 : 0;
 650    }
 651    s->src_timer = ptimer_init(src_timeout_hit, s, PTIMER_POLICY_DEFAULT);
 652
 653    if (s->dma_mr) {
 654        s->dma_as = g_malloc0(sizeof(AddressSpace));
 655        address_space_init(s->dma_as, s->dma_mr, NULL);
 656    } else {
 657        s->dma_as = &address_space_memory;
 658    }
 659
 660    if (!s->attr) {
 661        s->attr = MEMORY_TRANSACTION_ATTR(
 662                      object_new(TYPE_MEMORY_TRANSACTION_ATTR));
 663    }
 664
 665    /*
 666     * If byte alignment is enabled last word control bit is moved
 667     * to bit 29.
 668     */
 669    s->r_size_last_word_mask = 1 << (s->byte_align ? 29 : 0);
 670}
 671
 672static void zynqmp_csu_dma_init(Object *obj)
 673{
 674    ZynqMPCSUDMA *s = ZYNQMP_CSU_DMA(obj);
 675    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 676
 677    memory_region_init(&s->iomem, obj, "zynqmp.csu-dma",
 678                       R_MAX * 4);
 679
 680    sysbus_init_irq(sbd, &s->irq);
 681
 682    object_property_add_link(obj, "stream-connected-dma", TYPE_STREAM_SLAVE,
 683                             (Object **)&s->tx_dev,
 684                             qdev_prop_allow_set_link_before_realize,
 685                             OBJ_PROP_LINK_STRONG);
 686    object_property_add_link(obj, "stream-connected-dma0", TYPE_STREAM_SLAVE,
 687                             (Object **)&s->tx_dev0,
 688                             qdev_prop_allow_set_link_before_realize,
 689                             OBJ_PROP_LINK_STRONG);
 690    object_property_add_link(obj, "stream-connected-dma1", TYPE_STREAM_SLAVE,
 691                             (Object **)&s->tx_dev1,
 692                             qdev_prop_allow_set_link_before_realize,
 693                             OBJ_PROP_LINK_STRONG);
 694    object_property_add_link(obj, "dma", TYPE_MEMORY_REGION,
 695                             (Object **)&s->dma_mr,
 696                             qdev_prop_allow_set_link_before_realize,
 697                             OBJ_PROP_LINK_STRONG);
 698    object_property_add_link(obj, "memattr", TYPE_MEMORY_TRANSACTION_ATTR,
 699                             (Object **)&s->attr,
 700                             qdev_prop_allow_set_link_before_realize,
 701                             OBJ_PROP_LINK_STRONG);
 702
 703}
 704
 705static const VMStateDescription vmstate_zynqmp_csu_dma = {
 706    .name = "zynqmp_csu_dma",
 707    .version_id = 2,
 708    .minimum_version_id = 2,
 709    .minimum_version_id_old = 2,
 710    .fields = (VMStateField[]) {
 711        VMSTATE_PTIMER(src_timer, ZynqMPCSUDMA),
 712        VMSTATE_UINT32_ARRAY(regs, ZynqMPCSUDMA, R_MAX),
 713        VMSTATE_END_OF_LIST(),
 714    }
 715};
 716
 717static Property zynqmp_csu_dma_properties [] = {
 718    DEFINE_PROP_BOOL("is-dst", ZynqMPCSUDMA, is_dst, false),
 719    DEFINE_PROP_UINT16("dma-width", ZynqMPCSUDMA, width, 4),
 720    DEFINE_PROP_BOOL("byte-align", ZynqMPCSUDMA, byte_align, false),
 721    DEFINE_PROP_END_OF_LIST(),
 722};
 723
 724static void zynqmp_csu_dma_class_init(ObjectClass *klass, void *data)
 725{
 726    DeviceClass *dc = DEVICE_CLASS(klass);
 727    StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
 728    DmaCtrlClass *dcc = DMA_CTRL_CLASS(klass);
 729
 730    dc->reset = zynqmp_csu_dma_reset;
 731    dc->realize = zynqmp_csu_dma_realize;
 732    dc->vmsd = &vmstate_zynqmp_csu_dma;
 733    device_class_set_props(dc, zynqmp_csu_dma_properties);
 734
 735    ssc->push = zynqmp_csu_dma_stream_push;
 736    ssc->can_push = zynqmp_csu_dma_stream_can_push;
 737    dcc->read = zynqmp_csu_dma_dma_ctrl_read;
 738}
 739
 740static const TypeInfo zynqmp_csu_dma_info = {
 741    .name          = TYPE_ZYNQMP_CSU_DMA,
 742    .parent        = TYPE_SYS_BUS_DEVICE,
 743    .instance_size = sizeof(ZynqMPCSUDMA),
 744    .class_init    = zynqmp_csu_dma_class_init,
 745    .instance_init = zynqmp_csu_dma_init,
 746    .interfaces = (InterfaceInfo[]) {
 747        { TYPE_STREAM_SLAVE },
 748        { TYPE_DMA_CTRL },
 749        { }
 750    }
 751};
 752
 753static void zynqmp_csu_dma_register_types(void)
 754{
 755    type_register_static(&zynqmp_csu_dma_info);
 756}
 757
 758type_init(zynqmp_csu_dma_register_types)
 759