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 ®_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) 761