qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

xlnx_csu_dma.c (25848B)


      1 /*
      2  * Xilinx Platform CSU Stream DMA emulation
      3  *
      4  * This implementation is based on
      5  * https://github.com/Xilinx/qemu/blob/master/hw/dma/csu_stream_dma.c
      6  *
      7  * This program is free software; you can redistribute it and/or
      8  * modify it under the terms of the GNU General Public License as
      9  * published by the Free Software Foundation; either version 2 or
     10  * (at your option) version 3 of the License.
     11  *
     12  * This program is distributed in the hope that it will be useful,
     13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     15  * GNU General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU General Public License along
     18  * with this program; if not, see <http://www.gnu.org/licenses/>.
     19  */
     20 
     21 #include "qemu/osdep.h"
     22 #include "qemu/log.h"
     23 #include "qapi/error.h"
     24 #include "hw/irq.h"
     25 #include "hw/qdev-properties.h"
     26 #include "hw/sysbus.h"
     27 #include "migration/vmstate.h"
     28 #include "sysemu/dma.h"
     29 #include "hw/ptimer.h"
     30 #include "hw/stream.h"
     31 #include "hw/register.h"
     32 #include "hw/dma/xlnx_csu_dma.h"
     33 
     34 /*
     35  * Ref: UG1087 (v1.7) February 8, 2019
     36  * https://www.xilinx.com/html_docs/registers/ug1087/ug1087-zynq-ultrascale-registers.html
     37  * CSUDMA Module section
     38  */
     39 REG32(ADDR, 0x0)
     40     FIELD(ADDR, ADDR, 2, 30) /* wo */
     41 REG32(SIZE, 0x4)
     42     FIELD(SIZE, SIZE, 2, 27) /* wo */
     43     FIELD(SIZE, LAST_WORD, 0, 1) /* rw, only exists in SRC */
     44 REG32(STATUS, 0x8)
     45     FIELD(STATUS, DONE_CNT, 13, 3) /* wtc */
     46     FIELD(STATUS, FIFO_LEVEL, 5, 8) /* ro */
     47     FIELD(STATUS, OUTSTANDING, 1, 4) /* ro */
     48     FIELD(STATUS, BUSY, 0, 1) /* ro */
     49 REG32(CTRL, 0xc)
     50     FIELD(CTRL, FIFOTHRESH, 25, 7) /* rw, only exists in DST, reset 0x40 */
     51     FIELD(CTRL, APB_ERR_RESP, 24, 1) /* rw */
     52     FIELD(CTRL, ENDIANNESS, 23, 1) /* rw */
     53     FIELD(CTRL, AXI_BRST_TYPE, 22, 1) /* rw */
     54     FIELD(CTRL, TIMEOUT_VAL, 10, 12) /* rw, reset: 0xFFE */
     55     FIELD(CTRL, FIFO_THRESH, 2, 8) /* rw, reset: 0x80 */
     56     FIELD(CTRL, PAUSE_STRM, 1, 1) /* rw */
     57     FIELD(CTRL, PAUSE_MEM, 0, 1) /* rw */
     58 REG32(CRC, 0x10)
     59 REG32(INT_STATUS, 0x14)
     60     FIELD(INT_STATUS, FIFO_OVERFLOW, 7, 1) /* wtc */
     61     FIELD(INT_STATUS, INVALID_APB, 6, 1) /* wtc */
     62     FIELD(INT_STATUS, THRESH_HIT, 5, 1) /* wtc */
     63     FIELD(INT_STATUS, TIMEOUT_MEM, 4, 1) /* wtc */
     64     FIELD(INT_STATUS, TIMEOUT_STRM, 3, 1) /* wtc */
     65     FIELD(INT_STATUS, AXI_BRESP_ERR, 2, 1) /* wtc, SRC: AXI_RDERR */
     66     FIELD(INT_STATUS, DONE, 1, 1) /* wtc */
     67     FIELD(INT_STATUS, MEM_DONE, 0, 1) /* wtc */
     68 REG32(INT_ENABLE, 0x18)
     69     FIELD(INT_ENABLE, FIFO_OVERFLOW, 7, 1) /* wtc */
     70     FIELD(INT_ENABLE, INVALID_APB, 6, 1) /* wtc */
     71     FIELD(INT_ENABLE, THRESH_HIT, 5, 1) /* wtc */
     72     FIELD(INT_ENABLE, TIMEOUT_MEM, 4, 1) /* wtc */
     73     FIELD(INT_ENABLE, TIMEOUT_STRM, 3, 1) /* wtc */
     74     FIELD(INT_ENABLE, AXI_BRESP_ERR, 2, 1) /* wtc, SRC: AXI_RDERR */
     75     FIELD(INT_ENABLE, DONE, 1, 1) /* wtc */
     76     FIELD(INT_ENABLE, MEM_DONE, 0, 1) /* wtc */
     77 REG32(INT_DISABLE, 0x1c)
     78     FIELD(INT_DISABLE, FIFO_OVERFLOW, 7, 1) /* wtc */
     79     FIELD(INT_DISABLE, INVALID_APB, 6, 1) /* wtc */
     80     FIELD(INT_DISABLE, THRESH_HIT, 5, 1) /* wtc */
     81     FIELD(INT_DISABLE, TIMEOUT_MEM, 4, 1) /* wtc */
     82     FIELD(INT_DISABLE, TIMEOUT_STRM, 3, 1) /* wtc */
     83     FIELD(INT_DISABLE, AXI_BRESP_ERR, 2, 1) /* wtc, SRC: AXI_RDERR */
     84     FIELD(INT_DISABLE, DONE, 1, 1) /* wtc */
     85     FIELD(INT_DISABLE, MEM_DONE, 0, 1) /* wtc */
     86 REG32(INT_MASK, 0x20)
     87     FIELD(INT_MASK, FIFO_OVERFLOW, 7, 1) /* ro, reset: 0x1 */
     88     FIELD(INT_MASK, INVALID_APB, 6, 1) /* ro, reset: 0x1 */
     89     FIELD(INT_MASK, THRESH_HIT, 5, 1) /* ro, reset: 0x1 */
     90     FIELD(INT_MASK, TIMEOUT_MEM, 4, 1) /* ro, reset: 0x1 */
     91     FIELD(INT_MASK, TIMEOUT_STRM, 3, 1) /* ro, reset: 0x1 */
     92     FIELD(INT_MASK, AXI_BRESP_ERR, 2, 1) /* ro, reset: 0x1, SRC: AXI_RDERR */
     93     FIELD(INT_MASK, DONE, 1, 1) /* ro, reset: 0x1 */
     94     FIELD(INT_MASK, MEM_DONE, 0, 1) /* ro, reset: 0x1 */
     95 REG32(CTRL2, 0x24)
     96     FIELD(CTRL2, ARCACHE, 24, 3) /* rw */
     97     FIELD(CTRL2, ROUTE_BIT, 23, 1) /* rw */
     98     FIELD(CTRL2, TIMEOUT_EN, 22, 1) /* rw */
     99     FIELD(CTRL2, TIMEOUT_PRE, 4, 12) /* rw, reset: 0xFFF */
    100     FIELD(CTRL2, MAX_OUTS_CMDS, 0, 4) /* rw, reset: 0x8 */
    101 REG32(ADDR_MSB, 0x28)
    102     FIELD(ADDR_MSB, ADDR_MSB, 0, 17) /* wo */
    103 
    104 #define R_CTRL_TIMEOUT_VAL_RESET    (0xFFE)
    105 #define R_CTRL_FIFO_THRESH_RESET    (0x80)
    106 #define R_CTRL_FIFOTHRESH_RESET     (0x40)
    107 
    108 #define R_CTRL2_TIMEOUT_PRE_RESET   (0xFFF)
    109 #define R_CTRL2_MAX_OUTS_CMDS_RESET (0x8)
    110 
    111 #define XLNX_CSU_DMA_ERR_DEBUG      (0)
    112 #define XLNX_CSU_DMA_INT_R_MASK     (0xff)
    113 
    114 /* UG1807: Set the prescaler value for the timeout in clk (~2.5ns) cycles */
    115 #define XLNX_CSU_DMA_TIMER_FREQ     (400 * 1000 * 1000)
    116 
    117 static bool xlnx_csu_dma_is_paused(XlnxCSUDMA *s)
    118 {
    119     bool paused;
    120 
    121     paused = !!(s->regs[R_CTRL] & R_CTRL_PAUSE_STRM_MASK);
    122     paused |= !!(s->regs[R_CTRL] & R_CTRL_PAUSE_MEM_MASK);
    123 
    124     return paused;
    125 }
    126 
    127 static bool xlnx_csu_dma_get_eop(XlnxCSUDMA *s)
    128 {
    129     return s->r_size_last_word;
    130 }
    131 
    132 static bool xlnx_csu_dma_burst_is_fixed(XlnxCSUDMA *s)
    133 {
    134     return !!(s->regs[R_CTRL] & R_CTRL_AXI_BRST_TYPE_MASK);
    135 }
    136 
    137 static bool xlnx_csu_dma_timeout_enabled(XlnxCSUDMA *s)
    138 {
    139     return !!(s->regs[R_CTRL2] & R_CTRL2_TIMEOUT_EN_MASK);
    140 }
    141 
    142 static void xlnx_csu_dma_update_done_cnt(XlnxCSUDMA *s, int a)
    143 {
    144     int cnt;
    145 
    146     /* Increase DONE_CNT */
    147     cnt = ARRAY_FIELD_EX32(s->regs, STATUS, DONE_CNT) + a;
    148     ARRAY_FIELD_DP32(s->regs, STATUS, DONE_CNT, cnt);
    149 }
    150 
    151 static void xlnx_csu_dma_data_process(XlnxCSUDMA *s, uint8_t *buf, uint32_t len)
    152 {
    153     uint32_t bswap;
    154     uint32_t i;
    155 
    156     bswap = s->regs[R_CTRL] & R_CTRL_ENDIANNESS_MASK;
    157     if (s->is_dst && !bswap) {
    158         /* Fast when ENDIANNESS cleared */
    159         return;
    160     }
    161 
    162     for (i = 0; i < len; i += 4) {
    163         uint8_t *b = &buf[i];
    164         union {
    165             uint8_t u8[4];
    166             uint32_t u32;
    167         } v = {
    168             .u8 = { b[0], b[1], b[2], b[3] }
    169         };
    170 
    171         if (!s->is_dst) {
    172             s->regs[R_CRC] += v.u32;
    173         }
    174         if (bswap) {
    175             /*
    176              * No point using bswap, we need to writeback
    177              * into a potentially unaligned pointer.
    178              */
    179             b[0] = v.u8[3];
    180             b[1] = v.u8[2];
    181             b[2] = v.u8[1];
    182             b[3] = v.u8[0];
    183         }
    184     }
    185 }
    186 
    187 static void xlnx_csu_dma_update_irq(XlnxCSUDMA *s)
    188 {
    189     qemu_set_irq(s->irq, !!(s->regs[R_INT_STATUS] & ~s->regs[R_INT_MASK]));
    190 }
    191 
    192 /* len is in bytes */
    193 static uint32_t xlnx_csu_dma_read(XlnxCSUDMA *s, uint8_t *buf, uint32_t len)
    194 {
    195     hwaddr addr = (hwaddr)s->regs[R_ADDR_MSB] << 32 | s->regs[R_ADDR];
    196     MemTxResult result = MEMTX_OK;
    197 
    198     if (xlnx_csu_dma_burst_is_fixed(s)) {
    199         uint32_t i;
    200 
    201         for (i = 0; i < len && (result == MEMTX_OK); i += s->width) {
    202             uint32_t mlen = MIN(len - i, s->width);
    203 
    204             result = address_space_rw(&s->dma_as, addr, s->attr,
    205                                       buf + i, mlen, false);
    206         }
    207     } else {
    208         result = address_space_rw(&s->dma_as, addr, s->attr, buf, len, false);
    209     }
    210 
    211     if (result == MEMTX_OK) {
    212         xlnx_csu_dma_data_process(s, buf, len);
    213     } else {
    214         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address " TARGET_FMT_plx
    215                       " for mem read", __func__, addr);
    216         s->regs[R_INT_STATUS] |= R_INT_STATUS_AXI_BRESP_ERR_MASK;
    217         xlnx_csu_dma_update_irq(s);
    218     }
    219     return len;
    220 }
    221 
    222 /* len is in bytes */
    223 static uint32_t xlnx_csu_dma_write(XlnxCSUDMA *s, uint8_t *buf, uint32_t len)
    224 {
    225     hwaddr addr = (hwaddr)s->regs[R_ADDR_MSB] << 32 | s->regs[R_ADDR];
    226     MemTxResult result = MEMTX_OK;
    227 
    228     xlnx_csu_dma_data_process(s, buf, len);
    229     if (xlnx_csu_dma_burst_is_fixed(s)) {
    230         uint32_t i;
    231 
    232         for (i = 0; i < len && (result == MEMTX_OK); i += s->width) {
    233             uint32_t mlen = MIN(len - i, s->width);
    234 
    235             result = address_space_rw(&s->dma_as, addr, s->attr,
    236                                       buf, mlen, true);
    237             buf += mlen;
    238         }
    239     } else {
    240         result = address_space_rw(&s->dma_as, addr, s->attr, buf, len, true);
    241     }
    242 
    243     if (result != MEMTX_OK) {
    244         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address " TARGET_FMT_plx
    245                       " for mem write", __func__, addr);
    246         s->regs[R_INT_STATUS] |= R_INT_STATUS_AXI_BRESP_ERR_MASK;
    247         xlnx_csu_dma_update_irq(s);
    248     }
    249     return len;
    250 }
    251 
    252 static void xlnx_csu_dma_done(XlnxCSUDMA *s)
    253 {
    254     s->regs[R_STATUS] &= ~R_STATUS_BUSY_MASK;
    255     s->regs[R_INT_STATUS] |= R_INT_STATUS_DONE_MASK;
    256 
    257     if (!s->is_dst) {
    258         s->regs[R_INT_STATUS] |= R_INT_STATUS_MEM_DONE_MASK;
    259     }
    260 
    261     xlnx_csu_dma_update_done_cnt(s, 1);
    262 }
    263 
    264 static uint32_t xlnx_csu_dma_advance(XlnxCSUDMA *s, uint32_t len)
    265 {
    266     uint32_t size = s->regs[R_SIZE];
    267     hwaddr dst = (hwaddr)s->regs[R_ADDR_MSB] << 32 | s->regs[R_ADDR];
    268 
    269     assert(len <= size);
    270 
    271     size -= len;
    272     s->regs[R_SIZE] = size;
    273 
    274     if (!xlnx_csu_dma_burst_is_fixed(s)) {
    275         dst += len;
    276         s->regs[R_ADDR] = (uint32_t) dst;
    277         s->regs[R_ADDR_MSB] = dst >> 32;
    278     }
    279 
    280     if (size == 0) {
    281         xlnx_csu_dma_done(s);
    282     }
    283 
    284     return size;
    285 }
    286 
    287 static void xlnx_csu_dma_src_notify(void *opaque)
    288 {
    289     XlnxCSUDMA *s = XLNX_CSU_DMA(opaque);
    290     unsigned char buf[4 * 1024];
    291     size_t rlen = 0;
    292 
    293     ptimer_transaction_begin(s->src_timer);
    294     /* Stop the backpreassure timer */
    295     ptimer_stop(s->src_timer);
    296 
    297     while (s->regs[R_SIZE] && !xlnx_csu_dma_is_paused(s) &&
    298            stream_can_push(s->tx_dev, xlnx_csu_dma_src_notify, s)) {
    299         uint32_t plen = MIN(s->regs[R_SIZE], sizeof buf);
    300         bool eop = false;
    301 
    302         /* Did we fit it all? */
    303         if (s->regs[R_SIZE] == plen && xlnx_csu_dma_get_eop(s)) {
    304             eop = true;
    305         }
    306 
    307         /* DMA transfer */
    308         xlnx_csu_dma_read(s, buf, plen);
    309         rlen = stream_push(s->tx_dev, buf, plen, eop);
    310         xlnx_csu_dma_advance(s, rlen);
    311     }
    312 
    313     if (xlnx_csu_dma_timeout_enabled(s) && s->regs[R_SIZE] &&
    314         !stream_can_push(s->tx_dev, xlnx_csu_dma_src_notify, s)) {
    315         uint32_t timeout = ARRAY_FIELD_EX32(s->regs, CTRL, TIMEOUT_VAL);
    316         uint32_t div = ARRAY_FIELD_EX32(s->regs, CTRL2, TIMEOUT_PRE) + 1;
    317         uint32_t freq = XLNX_CSU_DMA_TIMER_FREQ;
    318 
    319         freq /= div;
    320         ptimer_set_freq(s->src_timer, freq);
    321         ptimer_set_count(s->src_timer, timeout);
    322         ptimer_run(s->src_timer, 1);
    323     }
    324 
    325     ptimer_transaction_commit(s->src_timer);
    326     xlnx_csu_dma_update_irq(s);
    327 }
    328 
    329 static uint64_t addr_pre_write(RegisterInfo *reg, uint64_t val)
    330 {
    331     /* Address is word aligned */
    332     return val & R_ADDR_ADDR_MASK;
    333 }
    334 
    335 static uint64_t size_pre_write(RegisterInfo *reg, uint64_t val)
    336 {
    337     XlnxCSUDMA *s = XLNX_CSU_DMA(reg->opaque);
    338 
    339     if (s->regs[R_SIZE] != 0) {
    340         qemu_log_mask(LOG_GUEST_ERROR,
    341                       "%s: Starting DMA while already running.\n", __func__);
    342     }
    343 
    344     if (!s->is_dst) {
    345         s->r_size_last_word = !!(val & R_SIZE_LAST_WORD_MASK);
    346     }
    347 
    348     /* Size is word aligned */
    349     return val & R_SIZE_SIZE_MASK;
    350 }
    351 
    352 static uint64_t size_post_read(RegisterInfo *reg, uint64_t val)
    353 {
    354     XlnxCSUDMA *s = XLNX_CSU_DMA(reg->opaque);
    355 
    356     return val | s->r_size_last_word;
    357 }
    358 
    359 static void size_post_write(RegisterInfo *reg, uint64_t val)
    360 {
    361     XlnxCSUDMA *s = XLNX_CSU_DMA(reg->opaque);
    362 
    363     s->regs[R_STATUS] |= R_STATUS_BUSY_MASK;
    364 
    365     /*
    366      * Note that if SIZE is programmed to 0, and the DMA is started,
    367      * the interrupts DONE and MEM_DONE will be asserted.
    368      */
    369     if (s->regs[R_SIZE] == 0) {
    370         xlnx_csu_dma_done(s);
    371         xlnx_csu_dma_update_irq(s);
    372         return;
    373     }
    374 
    375     /* Set SIZE is considered the last step in transfer configuration */
    376     if (!s->is_dst) {
    377         xlnx_csu_dma_src_notify(s);
    378     } else {
    379         if (s->notify) {
    380             s->notify(s->notify_opaque);
    381         }
    382     }
    383 }
    384 
    385 static uint64_t status_pre_write(RegisterInfo *reg, uint64_t val)
    386 {
    387     return val & (R_STATUS_DONE_CNT_MASK | R_STATUS_BUSY_MASK);
    388 }
    389 
    390 static void ctrl_post_write(RegisterInfo *reg, uint64_t val)
    391 {
    392     XlnxCSUDMA *s = XLNX_CSU_DMA(reg->opaque);
    393 
    394     if (!s->is_dst) {
    395         if (!xlnx_csu_dma_is_paused(s)) {
    396             xlnx_csu_dma_src_notify(s);
    397         }
    398     } else {
    399         if (!xlnx_csu_dma_is_paused(s) && s->notify) {
    400             s->notify(s->notify_opaque);
    401         }
    402     }
    403 }
    404 
    405 static uint64_t int_status_pre_write(RegisterInfo *reg, uint64_t val)
    406 {
    407     XlnxCSUDMA *s = XLNX_CSU_DMA(reg->opaque);
    408 
    409     /* DMA counter decrements when flag 'DONE' is cleared */
    410     if ((val & s->regs[R_INT_STATUS] & R_INT_STATUS_DONE_MASK)) {
    411         xlnx_csu_dma_update_done_cnt(s, -1);
    412     }
    413 
    414     return s->regs[R_INT_STATUS] & ~val;
    415 }
    416 
    417 static void int_status_post_write(RegisterInfo *reg, uint64_t val)
    418 {
    419     XlnxCSUDMA *s = XLNX_CSU_DMA(reg->opaque);
    420 
    421     xlnx_csu_dma_update_irq(s);
    422 }
    423 
    424 static uint64_t int_enable_pre_write(RegisterInfo *reg, uint64_t val)
    425 {
    426     XlnxCSUDMA *s = XLNX_CSU_DMA(reg->opaque);
    427     uint32_t v32 = val;
    428 
    429     /*
    430      * R_INT_ENABLE doesn't have its own state.
    431      * It is used to indirectly modify R_INT_MASK.
    432      *
    433      * 1: Enable this interrupt field (the mask bit will be cleared to 0)
    434      * 0: No effect
    435      */
    436     s->regs[R_INT_MASK] &= ~v32;
    437     return 0;
    438 }
    439 
    440 static void int_enable_post_write(RegisterInfo *reg, uint64_t val)
    441 {
    442     XlnxCSUDMA *s = XLNX_CSU_DMA(reg->opaque);
    443 
    444     xlnx_csu_dma_update_irq(s);
    445 }
    446 
    447 static uint64_t int_disable_pre_write(RegisterInfo *reg, uint64_t val)
    448 {
    449     XlnxCSUDMA *s = XLNX_CSU_DMA(reg->opaque);
    450     uint32_t v32 = val;
    451 
    452     /*
    453      * R_INT_DISABLE doesn't have its own state.
    454      * It is used to indirectly modify R_INT_MASK.
    455      *
    456      * 1: Disable this interrupt field (the mask bit will be set to 1)
    457      * 0: No effect
    458      */
    459     s->regs[R_INT_MASK] |= v32;
    460     return 0;
    461 }
    462 
    463 static void int_disable_post_write(RegisterInfo *reg, uint64_t val)
    464 {
    465     XlnxCSUDMA *s = XLNX_CSU_DMA(reg->opaque);
    466 
    467     xlnx_csu_dma_update_irq(s);
    468 }
    469 
    470 static uint64_t addr_msb_pre_write(RegisterInfo *reg, uint64_t val)
    471 {
    472     return val & R_ADDR_MSB_ADDR_MSB_MASK;
    473 }
    474 
    475 static MemTxResult xlnx_csu_dma_class_read(XlnxCSUDMA *s, hwaddr addr,
    476                                            uint32_t len)
    477 {
    478     RegisterInfo *reg = &s->regs_info[R_SIZE];
    479     uint64_t we = MAKE_64BIT_MASK(0, 4 * 8);
    480 
    481     s->regs[R_ADDR] = addr;
    482     s->regs[R_ADDR_MSB] = (uint64_t)addr >> 32;
    483 
    484     register_write(reg, len, we, object_get_typename(OBJECT(s)), false);
    485 
    486     return (s->regs[R_SIZE] == 0) ? MEMTX_OK : MEMTX_ERROR;
    487 }
    488 
    489 static const RegisterAccessInfo *xlnx_csu_dma_regs_info[] = {
    490 #define DMACH_REGINFO(NAME, snd)                                              \
    491     (const RegisterAccessInfo []) {                                           \
    492         {                                                                     \
    493             .name = #NAME "_ADDR",                                            \
    494             .addr = A_ADDR,                                                   \
    495             .pre_write = addr_pre_write                                       \
    496         }, {                                                                  \
    497             .name = #NAME "_SIZE",                                            \
    498             .addr = A_SIZE,                                                   \
    499             .pre_write = size_pre_write,                                      \
    500             .post_write = size_post_write,                                    \
    501             .post_read = size_post_read                                       \
    502         }, {                                                                  \
    503             .name = #NAME "_STATUS",                                          \
    504             .addr = A_STATUS,                                                 \
    505             .pre_write = status_pre_write,                                    \
    506             .w1c = R_STATUS_DONE_CNT_MASK,                                    \
    507             .ro = (R_STATUS_BUSY_MASK                                         \
    508                    | R_STATUS_FIFO_LEVEL_MASK                                 \
    509                    | R_STATUS_OUTSTANDING_MASK)                               \
    510         }, {                                                                  \
    511             .name = #NAME "_CTRL",                                            \
    512             .addr = A_CTRL,                                                   \
    513             .post_write = ctrl_post_write,                                    \
    514             .reset = ((R_CTRL_TIMEOUT_VAL_RESET << R_CTRL_TIMEOUT_VAL_SHIFT)  \
    515                       | (R_CTRL_FIFO_THRESH_RESET << R_CTRL_FIFO_THRESH_SHIFT)\
    516                       | (snd ? 0 : R_CTRL_FIFOTHRESH_RESET                    \
    517                          << R_CTRL_FIFOTHRESH_SHIFT))                         \
    518         }, {                                                                  \
    519             .name = #NAME "_CRC",                                             \
    520             .addr = A_CRC,                                                    \
    521         }, {                                                                  \
    522             .name =  #NAME "_INT_STATUS",                                     \
    523             .addr = A_INT_STATUS,                                             \
    524             .pre_write = int_status_pre_write,                                \
    525             .post_write = int_status_post_write                               \
    526         }, {                                                                  \
    527             .name = #NAME "_INT_ENABLE",                                      \
    528             .addr = A_INT_ENABLE,                                             \
    529             .pre_write = int_enable_pre_write,                                \
    530             .post_write = int_enable_post_write                               \
    531         }, {                                                                  \
    532             .name = #NAME "_INT_DISABLE",                                     \
    533             .addr = A_INT_DISABLE,                                            \
    534             .pre_write = int_disable_pre_write,                               \
    535             .post_write = int_disable_post_write                              \
    536         }, {                                                                  \
    537             .name = #NAME "_INT_MASK",                                        \
    538             .addr = A_INT_MASK,                                               \
    539             .ro = ~0,                                                         \
    540             .reset = XLNX_CSU_DMA_INT_R_MASK                                  \
    541         }, {                                                                  \
    542             .name = #NAME "_CTRL2",                                           \
    543             .addr = A_CTRL2,                                                  \
    544             .reset = ((R_CTRL2_TIMEOUT_PRE_RESET                              \
    545                        << R_CTRL2_TIMEOUT_PRE_SHIFT)                          \
    546                       | (R_CTRL2_MAX_OUTS_CMDS_RESET                          \
    547                          << R_CTRL2_MAX_OUTS_CMDS_SHIFT))                     \
    548         }, {                                                                  \
    549             .name = #NAME "_ADDR_MSB",                                        \
    550             .addr = A_ADDR_MSB,                                               \
    551             .pre_write = addr_msb_pre_write                                   \
    552         }                                                                     \
    553     }
    554 
    555     DMACH_REGINFO(DMA_SRC, true),
    556     DMACH_REGINFO(DMA_DST, false)
    557 };
    558 
    559 static const MemoryRegionOps xlnx_csu_dma_ops = {
    560     .read = register_read_memory,
    561     .write = register_write_memory,
    562     .endianness = DEVICE_LITTLE_ENDIAN,
    563     .valid = {
    564         .min_access_size = 4,
    565         .max_access_size = 4,
    566     }
    567 };
    568 
    569 static void xlnx_csu_dma_src_timeout_hit(void *opaque)
    570 {
    571     XlnxCSUDMA *s = XLNX_CSU_DMA(opaque);
    572 
    573     /* Ignore if the timeout is masked */
    574     if (!xlnx_csu_dma_timeout_enabled(s)) {
    575         return;
    576     }
    577 
    578     s->regs[R_INT_STATUS] |= R_INT_STATUS_TIMEOUT_STRM_MASK;
    579     xlnx_csu_dma_update_irq(s);
    580 }
    581 
    582 static size_t xlnx_csu_dma_stream_push(StreamSink *obj, uint8_t *buf,
    583                                        size_t len, bool eop)
    584 {
    585     XlnxCSUDMA *s = XLNX_CSU_DMA(obj);
    586     uint32_t size = s->regs[R_SIZE];
    587     uint32_t mlen = MIN(size, len) & (~3); /* Size is word aligned */
    588 
    589     /* Be called when it's DST */
    590     assert(s->is_dst);
    591 
    592     if (size == 0 || len <= 0) {
    593         return 0;
    594     }
    595 
    596     if (len && (xlnx_csu_dma_is_paused(s) || mlen == 0)) {
    597         qemu_log_mask(LOG_GUEST_ERROR,
    598                       "csu-dma: DST channel dropping %zd b of data.\n", len);
    599         s->regs[R_INT_STATUS] |= R_INT_STATUS_FIFO_OVERFLOW_MASK;
    600         return len;
    601     }
    602 
    603     if (xlnx_csu_dma_write(s, buf, mlen) != mlen) {
    604         return 0;
    605     }
    606 
    607     xlnx_csu_dma_advance(s, mlen);
    608     xlnx_csu_dma_update_irq(s);
    609 
    610     return mlen;
    611 }
    612 
    613 static bool xlnx_csu_dma_stream_can_push(StreamSink *obj,
    614                                          StreamCanPushNotifyFn notify,
    615                                          void *notify_opaque)
    616 {
    617     XlnxCSUDMA *s = XLNX_CSU_DMA(obj);
    618 
    619     if (s->regs[R_SIZE] != 0) {
    620         return true;
    621     } else {
    622         s->notify = notify;
    623         s->notify_opaque = notify_opaque;
    624         return false;
    625     }
    626 }
    627 
    628 static void xlnx_csu_dma_reset(DeviceState *dev)
    629 {
    630     XlnxCSUDMA *s = XLNX_CSU_DMA(dev);
    631     unsigned int i;
    632 
    633     for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
    634         register_reset(&s->regs_info[i]);
    635     }
    636 }
    637 
    638 static void xlnx_csu_dma_realize(DeviceState *dev, Error **errp)
    639 {
    640     XlnxCSUDMA *s = XLNX_CSU_DMA(dev);
    641     RegisterInfoArray *reg_array;
    642 
    643     if (!s->is_dst && !s->tx_dev) {
    644         error_setg(errp, "zynqmp.csu-dma: Stream not connected");
    645         return;
    646     }
    647 
    648     if (!s->dma_mr) {
    649         error_setg(errp, TYPE_XLNX_CSU_DMA " 'dma' link not set");
    650         return;
    651     }
    652     address_space_init(&s->dma_as, s->dma_mr, "csu-dma");
    653 
    654     reg_array =
    655         register_init_block32(dev, xlnx_csu_dma_regs_info[!!s->is_dst],
    656                               XLNX_CSU_DMA_R_MAX,
    657                               s->regs_info, s->regs,
    658                               &xlnx_csu_dma_ops,
    659                               XLNX_CSU_DMA_ERR_DEBUG,
    660                               XLNX_CSU_DMA_R_MAX * 4);
    661     memory_region_add_subregion(&s->iomem,
    662                                 0x0,
    663                                 &reg_array->mem);
    664 
    665     sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
    666     sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
    667 
    668     s->src_timer = ptimer_init(xlnx_csu_dma_src_timeout_hit,
    669                                s, PTIMER_POLICY_LEGACY);
    670 
    671     s->attr = MEMTXATTRS_UNSPECIFIED;
    672 
    673     s->r_size_last_word = 0;
    674 }
    675 
    676 static const VMStateDescription vmstate_xlnx_csu_dma = {
    677     .name = TYPE_XLNX_CSU_DMA,
    678     .version_id = 0,
    679     .minimum_version_id = 0,
    680     .fields = (VMStateField[]) {
    681         VMSTATE_PTIMER(src_timer, XlnxCSUDMA),
    682         VMSTATE_UINT16(width, XlnxCSUDMA),
    683         VMSTATE_BOOL(is_dst, XlnxCSUDMA),
    684         VMSTATE_BOOL(r_size_last_word, XlnxCSUDMA),
    685         VMSTATE_UINT32_ARRAY(regs, XlnxCSUDMA, XLNX_CSU_DMA_R_MAX),
    686         VMSTATE_END_OF_LIST(),
    687     }
    688 };
    689 
    690 static Property xlnx_csu_dma_properties[] = {
    691     /*
    692      * Ref PG021, Stream Data Width:
    693      * Data width in bits of the AXI S2MM AXI4-Stream Data bus.
    694      * This value must be equal or less than the Memory Map Data Width.
    695      * Valid values are 8, 16, 32, 64, 128, 512 and 1024.
    696      * "dma-width" is the byte value of the "Stream Data Width".
    697      */
    698     DEFINE_PROP_UINT16("dma-width", XlnxCSUDMA, width, 4),
    699     /*
    700      * The CSU DMA is a two-channel, simple DMA, allowing separate control of
    701      * the SRC (read) channel and DST (write) channel. "is-dst" is used to mark
    702      * which channel the device is connected to.
    703      */
    704     DEFINE_PROP_BOOL("is-dst", XlnxCSUDMA, is_dst, true),
    705     DEFINE_PROP_END_OF_LIST(),
    706 };
    707 
    708 static void xlnx_csu_dma_class_init(ObjectClass *klass, void *data)
    709 {
    710     DeviceClass *dc = DEVICE_CLASS(klass);
    711     StreamSinkClass *ssc = STREAM_SINK_CLASS(klass);
    712     XlnxCSUDMAClass *xcdc = XLNX_CSU_DMA_CLASS(klass);
    713 
    714     dc->reset = xlnx_csu_dma_reset;
    715     dc->realize = xlnx_csu_dma_realize;
    716     dc->vmsd = &vmstate_xlnx_csu_dma;
    717     device_class_set_props(dc, xlnx_csu_dma_properties);
    718 
    719     ssc->push = xlnx_csu_dma_stream_push;
    720     ssc->can_push = xlnx_csu_dma_stream_can_push;
    721 
    722     xcdc->read = xlnx_csu_dma_class_read;
    723 }
    724 
    725 static void xlnx_csu_dma_init(Object *obj)
    726 {
    727     XlnxCSUDMA *s = XLNX_CSU_DMA(obj);
    728 
    729     memory_region_init(&s->iomem, obj, TYPE_XLNX_CSU_DMA,
    730                        XLNX_CSU_DMA_R_MAX * 4);
    731 
    732     object_property_add_link(obj, "stream-connected-dma", TYPE_STREAM_SINK,
    733                              (Object **)&s->tx_dev,
    734                              qdev_prop_allow_set_link_before_realize,
    735                              OBJ_PROP_LINK_STRONG);
    736     object_property_add_link(obj, "dma", TYPE_MEMORY_REGION,
    737                              (Object **)&s->dma_mr,
    738                              qdev_prop_allow_set_link_before_realize,
    739                              OBJ_PROP_LINK_STRONG);
    740 }
    741 
    742 static const TypeInfo xlnx_csu_dma_info = {
    743     .name          = TYPE_XLNX_CSU_DMA,
    744     .parent        = TYPE_SYS_BUS_DEVICE,
    745     .instance_size = sizeof(XlnxCSUDMA),
    746     .class_init    = xlnx_csu_dma_class_init,
    747     .class_size    = sizeof(XlnxCSUDMAClass),
    748     .instance_init = xlnx_csu_dma_init,
    749     .interfaces = (InterfaceInfo[]) {
    750         { TYPE_STREAM_SINK },
    751         { }
    752     }
    753 };
    754 
    755 static void xlnx_csu_dma_register_types(void)
    756 {
    757     type_register_static(&xlnx_csu_dma_info);
    758 }
    759 
    760 type_init(xlnx_csu_dma_register_types)