qemu/hw/dma/xlnx_dpdma.c
<<
>>
Prefs
   1/*
   2 * xlnx_dpdma.c
   3 *
   4 *  Copyright (C) 2015 : GreenSocs Ltd
   5 *      http://www.greensocs.com/ , email: info@greensocs.com
   6 *
   7 *  Developed by :
   8 *  Frederic Konrad   <fred.konrad@greensocs.com>
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License as published by
  12 * the Free Software Foundation, either version 2 of the License, or
  13 * (at your option) any later version.
  14 *
  15 * This program is distributed in the hope that it will be useful,
  16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18 * GNU General Public License for more details.
  19 *
  20 * You should have received a copy of the GNU General Public License along
  21 * with this program; if not, see <http://www.gnu.org/licenses/>.
  22 *
  23 */
  24
  25#include "qemu/osdep.h"
  26#include "qemu-common.h"
  27#include "qemu/log.h"
  28#include "qemu/module.h"
  29#include "hw/dma/xlnx_dpdma.h"
  30
  31#ifndef DEBUG_DPDMA
  32#define DEBUG_DPDMA 0
  33#endif
  34
  35#define DPRINTF(fmt, ...) do {                                                 \
  36    if (DEBUG_DPDMA) {                                                         \
  37        qemu_log("xlnx_dpdma: " fmt , ## __VA_ARGS__);                         \
  38    }                                                                          \
  39} while (0)
  40
  41/*
  42 * Registers offset for DPDMA.
  43 */
  44#define DPDMA_ERR_CTRL                        (0x0000)
  45#define DPDMA_ISR                             (0x0004 >> 2)
  46#define DPDMA_IMR                             (0x0008 >> 2)
  47#define DPDMA_IEN                             (0x000C >> 2)
  48#define DPDMA_IDS                             (0x0010 >> 2)
  49#define DPDMA_EISR                            (0x0014 >> 2)
  50#define DPDMA_EIMR                            (0x0018 >> 2)
  51#define DPDMA_EIEN                            (0x001C >> 2)
  52#define DPDMA_EIDS                            (0x0020 >> 2)
  53#define DPDMA_CNTL                            (0x0100 >> 2)
  54
  55#define DPDMA_GBL                             (0x0104 >> 2)
  56#define DPDMA_GBL_TRG_CH(n)                   (1 << n)
  57#define DPDMA_GBL_RTRG_CH(n)                  (1 << 6 << n)
  58
  59#define DPDMA_ALC0_CNTL                       (0x0108 >> 2)
  60#define DPDMA_ALC0_STATUS                     (0x010C >> 2)
  61#define DPDMA_ALC0_MAX                        (0x0110 >> 2)
  62#define DPDMA_ALC0_MIN                        (0x0114 >> 2)
  63#define DPDMA_ALC0_ACC                        (0x0118 >> 2)
  64#define DPDMA_ALC0_ACC_TRAN                   (0x011C >> 2)
  65#define DPDMA_ALC1_CNTL                       (0x0120 >> 2)
  66#define DPDMA_ALC1_STATUS                     (0x0124 >> 2)
  67#define DPDMA_ALC1_MAX                        (0x0128 >> 2)
  68#define DPDMA_ALC1_MIN                        (0x012C >> 2)
  69#define DPDMA_ALC1_ACC                        (0x0130 >> 2)
  70#define DPDMA_ALC1_ACC_TRAN                   (0x0134 >> 2)
  71
  72#define DPDMA_DSCR_STRT_ADDRE_CH(n)           ((0x0200 + n * 0x100) >> 2)
  73#define DPDMA_DSCR_STRT_ADDR_CH(n)            ((0x0204 + n * 0x100) >> 2)
  74#define DPDMA_DSCR_NEXT_ADDRE_CH(n)           ((0x0208 + n * 0x100) >> 2)
  75#define DPDMA_DSCR_NEXT_ADDR_CH(n)            ((0x020C + n * 0x100) >> 2)
  76#define DPDMA_PYLD_CUR_ADDRE_CH(n)            ((0x0210 + n * 0x100) >> 2)
  77#define DPDMA_PYLD_CUR_ADDR_CH(n)             ((0x0214 + n * 0x100) >> 2)
  78
  79#define DPDMA_CNTL_CH(n)                      ((0x0218 + n * 0x100) >> 2)
  80#define DPDMA_CNTL_CH_EN                      (1)
  81#define DPDMA_CNTL_CH_PAUSED                  (1 << 1)
  82
  83#define DPDMA_STATUS_CH(n)                    ((0x021C + n * 0x100) >> 2)
  84#define DPDMA_STATUS_BURST_TYPE               (1 << 4)
  85#define DPDMA_STATUS_MODE                     (1 << 5)
  86#define DPDMA_STATUS_EN_CRC                   (1 << 6)
  87#define DPDMA_STATUS_LAST_DSCR                (1 << 7)
  88#define DPDMA_STATUS_LDSCR_FRAME              (1 << 8)
  89#define DPDMA_STATUS_IGNR_DONE                (1 << 9)
  90#define DPDMA_STATUS_DSCR_DONE                (1 << 10)
  91#define DPDMA_STATUS_EN_DSCR_UP               (1 << 11)
  92#define DPDMA_STATUS_EN_DSCR_INTR             (1 << 12)
  93#define DPDMA_STATUS_PREAMBLE_OFF             (13)
  94
  95#define DPDMA_VDO_CH(n)                       ((0x0220 + n * 0x100) >> 2)
  96#define DPDMA_PYLD_SZ_CH(n)                   ((0x0224 + n * 0x100) >> 2)
  97#define DPDMA_DSCR_ID_CH(n)                   ((0x0228 + n * 0x100) >> 2)
  98
  99/*
 100 * Descriptor control field.
 101 */
 102#define CONTROL_PREAMBLE_VALUE                0xA5
 103
 104#define DSCR_CTRL_PREAMBLE                    0xFF
 105#define DSCR_CTRL_EN_DSCR_DONE_INTR           (1 << 8)
 106#define DSCR_CTRL_EN_DSCR_UPDATE              (1 << 9)
 107#define DSCR_CTRL_IGNORE_DONE                 (1 << 10)
 108#define DSCR_CTRL_AXI_BURST_TYPE              (1 << 11)
 109#define DSCR_CTRL_AXCACHE                     (0x0F << 12)
 110#define DSCR_CTRL_AXPROT                      (0x2 << 16)
 111#define DSCR_CTRL_DESCRIPTOR_MODE             (1 << 18)
 112#define DSCR_CTRL_LAST_DESCRIPTOR             (1 << 19)
 113#define DSCR_CTRL_ENABLE_CRC                  (1 << 20)
 114#define DSCR_CTRL_LAST_DESCRIPTOR_OF_FRAME    (1 << 21)
 115
 116/*
 117 * Descriptor timestamp field.
 118 */
 119#define STATUS_DONE                           (1 << 31)
 120
 121#define DPDMA_FRAG_MAX_SZ                     (4096)
 122
 123enum DPDMABurstType {
 124    DPDMA_INCR = 0,
 125    DPDMA_FIXED = 1
 126};
 127
 128enum DPDMAMode {
 129    DPDMA_CONTIGOUS = 0,
 130    DPDMA_FRAGMENTED = 1
 131};
 132
 133struct DPDMADescriptor {
 134    uint32_t control;
 135    uint32_t descriptor_id;
 136    /* transfer size in byte. */
 137    uint32_t xfer_size;
 138    uint32_t line_size_stride;
 139    uint32_t timestamp_lsb;
 140    uint32_t timestamp_msb;
 141    /* contains extension for both descriptor and source. */
 142    uint32_t address_extension;
 143    uint32_t next_descriptor;
 144    uint32_t source_address;
 145    uint32_t address_extension_23;
 146    uint32_t address_extension_45;
 147    uint32_t source_address2;
 148    uint32_t source_address3;
 149    uint32_t source_address4;
 150    uint32_t source_address5;
 151    uint32_t crc;
 152};
 153
 154typedef enum DPDMABurstType DPDMABurstType;
 155typedef enum DPDMAMode DPDMAMode;
 156typedef struct DPDMADescriptor DPDMADescriptor;
 157
 158static bool xlnx_dpdma_desc_is_last(DPDMADescriptor *desc)
 159{
 160    return ((desc->control & DSCR_CTRL_LAST_DESCRIPTOR) != 0);
 161}
 162
 163static bool xlnx_dpdma_desc_is_last_of_frame(DPDMADescriptor *desc)
 164{
 165    return ((desc->control & DSCR_CTRL_LAST_DESCRIPTOR_OF_FRAME) != 0);
 166}
 167
 168static uint64_t xlnx_dpdma_desc_get_source_address(DPDMADescriptor *desc,
 169                                                     uint8_t frag)
 170{
 171    uint64_t addr = 0;
 172    assert(frag < 5);
 173
 174    switch (frag) {
 175    case 0:
 176        addr = desc->source_address
 177            + (extract32(desc->address_extension, 16, 12) << 20);
 178        break;
 179    case 1:
 180        addr = desc->source_address2
 181            + (extract32(desc->address_extension_23, 0, 12) << 8);
 182        break;
 183    case 2:
 184        addr = desc->source_address3
 185            + (extract32(desc->address_extension_23, 16, 12) << 20);
 186        break;
 187    case 3:
 188        addr = desc->source_address4
 189            + (extract32(desc->address_extension_45, 0, 12) << 8);
 190        break;
 191    case 4:
 192        addr = desc->source_address5
 193            + (extract32(desc->address_extension_45, 16, 12) << 20);
 194        break;
 195    default:
 196        addr = 0;
 197        break;
 198    }
 199
 200    return addr;
 201}
 202
 203static uint32_t xlnx_dpdma_desc_get_transfer_size(DPDMADescriptor *desc)
 204{
 205    return desc->xfer_size;
 206}
 207
 208static uint32_t xlnx_dpdma_desc_get_line_size(DPDMADescriptor *desc)
 209{
 210    return extract32(desc->line_size_stride, 0, 18);
 211}
 212
 213static uint32_t xlnx_dpdma_desc_get_line_stride(DPDMADescriptor *desc)
 214{
 215    return extract32(desc->line_size_stride, 18, 14) * 16;
 216}
 217
 218static inline bool xlnx_dpdma_desc_crc_enabled(DPDMADescriptor *desc)
 219{
 220    return (desc->control & DSCR_CTRL_ENABLE_CRC) != 0;
 221}
 222
 223static inline bool xlnx_dpdma_desc_check_crc(DPDMADescriptor *desc)
 224{
 225    uint32_t *p = (uint32_t *)desc;
 226    uint32_t crc = 0;
 227    uint8_t i;
 228
 229    /*
 230     * CRC is calculated on the whole descriptor except the last 32bits word
 231     * using 32bits addition.
 232     */
 233    for (i = 0; i < 15; i++) {
 234        crc += p[i];
 235    }
 236
 237    return crc == desc->crc;
 238}
 239
 240static inline bool xlnx_dpdma_desc_completion_interrupt(DPDMADescriptor *desc)
 241{
 242    return (desc->control & DSCR_CTRL_EN_DSCR_DONE_INTR) != 0;
 243}
 244
 245static inline bool xlnx_dpdma_desc_is_valid(DPDMADescriptor *desc)
 246{
 247    return (desc->control & DSCR_CTRL_PREAMBLE) == CONTROL_PREAMBLE_VALUE;
 248}
 249
 250static inline bool xlnx_dpdma_desc_is_contiguous(DPDMADescriptor *desc)
 251{
 252    return (desc->control & DSCR_CTRL_DESCRIPTOR_MODE) == 0;
 253}
 254
 255static inline bool xlnx_dpdma_desc_update_enabled(DPDMADescriptor *desc)
 256{
 257    return (desc->control & DSCR_CTRL_EN_DSCR_UPDATE) != 0;
 258}
 259
 260static inline void xlnx_dpdma_desc_set_done(DPDMADescriptor *desc)
 261{
 262    desc->timestamp_msb |= STATUS_DONE;
 263}
 264
 265static inline bool xlnx_dpdma_desc_is_already_done(DPDMADescriptor *desc)
 266{
 267    return (desc->timestamp_msb & STATUS_DONE) != 0;
 268}
 269
 270static inline bool xlnx_dpdma_desc_ignore_done_bit(DPDMADescriptor *desc)
 271{
 272    return (desc->control & DSCR_CTRL_IGNORE_DONE) != 0;
 273}
 274
 275static const VMStateDescription vmstate_xlnx_dpdma = {
 276    .name = TYPE_XLNX_DPDMA,
 277    .version_id = 1,
 278    .fields = (VMStateField[]) {
 279        VMSTATE_UINT32_ARRAY(registers, XlnxDPDMAState,
 280                             XLNX_DPDMA_REG_ARRAY_SIZE),
 281        VMSTATE_BOOL_ARRAY(operation_finished, XlnxDPDMAState, 6),
 282        VMSTATE_END_OF_LIST()
 283    }
 284};
 285
 286static void xlnx_dpdma_update_irq(XlnxDPDMAState *s)
 287{
 288    bool flags;
 289
 290    flags = ((s->registers[DPDMA_ISR] & (~s->registers[DPDMA_IMR]))
 291          || (s->registers[DPDMA_EISR] & (~s->registers[DPDMA_EIMR])));
 292    qemu_set_irq(s->irq, flags);
 293}
 294
 295static uint64_t xlnx_dpdma_descriptor_start_address(XlnxDPDMAState *s,
 296                                                      uint8_t channel)
 297{
 298    return (s->registers[DPDMA_DSCR_STRT_ADDRE_CH(channel)] << 16)
 299          + s->registers[DPDMA_DSCR_STRT_ADDR_CH(channel)];
 300}
 301
 302static uint64_t xlnx_dpdma_descriptor_next_address(XlnxDPDMAState *s,
 303                                                     uint8_t channel)
 304{
 305    return ((uint64_t)s->registers[DPDMA_DSCR_NEXT_ADDRE_CH(channel)] << 32)
 306           + s->registers[DPDMA_DSCR_NEXT_ADDR_CH(channel)];
 307}
 308
 309static bool xlnx_dpdma_is_channel_enabled(XlnxDPDMAState *s,
 310                                            uint8_t channel)
 311{
 312    return (s->registers[DPDMA_CNTL_CH(channel)] & DPDMA_CNTL_CH_EN) != 0;
 313}
 314
 315static bool xlnx_dpdma_is_channel_paused(XlnxDPDMAState *s,
 316                                           uint8_t channel)
 317{
 318    return (s->registers[DPDMA_CNTL_CH(channel)] & DPDMA_CNTL_CH_PAUSED) != 0;
 319}
 320
 321static inline bool xlnx_dpdma_is_channel_retriggered(XlnxDPDMAState *s,
 322                                                       uint8_t channel)
 323{
 324    /* Clear the retriggered bit after reading it. */
 325    bool channel_is_retriggered = s->registers[DPDMA_GBL]
 326                                & DPDMA_GBL_RTRG_CH(channel);
 327    s->registers[DPDMA_GBL] &= ~DPDMA_GBL_RTRG_CH(channel);
 328    return channel_is_retriggered;
 329}
 330
 331static inline bool xlnx_dpdma_is_channel_triggered(XlnxDPDMAState *s,
 332                                                     uint8_t channel)
 333{
 334    return s->registers[DPDMA_GBL] & DPDMA_GBL_TRG_CH(channel);
 335}
 336
 337static void xlnx_dpdma_update_desc_info(XlnxDPDMAState *s, uint8_t channel,
 338                                          DPDMADescriptor *desc)
 339{
 340    s->registers[DPDMA_DSCR_NEXT_ADDRE_CH(channel)] =
 341                                extract32(desc->address_extension, 0, 16);
 342    s->registers[DPDMA_DSCR_NEXT_ADDR_CH(channel)] = desc->next_descriptor;
 343    s->registers[DPDMA_PYLD_CUR_ADDRE_CH(channel)] =
 344                                extract32(desc->address_extension, 16, 16);
 345    s->registers[DPDMA_PYLD_CUR_ADDR_CH(channel)] = desc->source_address;
 346    s->registers[DPDMA_VDO_CH(channel)] =
 347                                extract32(desc->line_size_stride, 18, 14)
 348                                + (extract32(desc->line_size_stride, 0, 18)
 349                                  << 14);
 350    s->registers[DPDMA_PYLD_SZ_CH(channel)] = desc->xfer_size;
 351    s->registers[DPDMA_DSCR_ID_CH(channel)] = desc->descriptor_id;
 352
 353    /* Compute the status register with the descriptor information. */
 354    s->registers[DPDMA_STATUS_CH(channel)] =
 355                                extract32(desc->control, 0, 8) << 13;
 356    if ((desc->control & DSCR_CTRL_EN_DSCR_DONE_INTR) != 0) {
 357        s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_EN_DSCR_INTR;
 358    }
 359    if ((desc->control & DSCR_CTRL_EN_DSCR_UPDATE) != 0) {
 360        s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_EN_DSCR_UP;
 361    }
 362    if ((desc->timestamp_msb & STATUS_DONE) != 0) {
 363        s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_DSCR_DONE;
 364    }
 365    if ((desc->control & DSCR_CTRL_IGNORE_DONE) != 0) {
 366        s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_IGNR_DONE;
 367    }
 368    if ((desc->control & DSCR_CTRL_LAST_DESCRIPTOR_OF_FRAME) != 0) {
 369        s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_LDSCR_FRAME;
 370    }
 371    if ((desc->control & DSCR_CTRL_LAST_DESCRIPTOR) != 0) {
 372        s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_LAST_DSCR;
 373    }
 374    if ((desc->control & DSCR_CTRL_ENABLE_CRC) != 0) {
 375        s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_EN_CRC;
 376    }
 377    if ((desc->control & DSCR_CTRL_DESCRIPTOR_MODE) != 0) {
 378        s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_MODE;
 379    }
 380    if ((desc->control & DSCR_CTRL_AXI_BURST_TYPE) != 0) {
 381        s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_BURST_TYPE;
 382    }
 383}
 384
 385static void xlnx_dpdma_dump_descriptor(DPDMADescriptor *desc)
 386{
 387    if (DEBUG_DPDMA) {
 388        qemu_log("DUMP DESCRIPTOR:\n");
 389        qemu_hexdump((char *)desc, stdout, "", sizeof(DPDMADescriptor));
 390    }
 391}
 392
 393static uint64_t xlnx_dpdma_read(void *opaque, hwaddr offset,
 394                                unsigned size)
 395{
 396    XlnxDPDMAState *s = XLNX_DPDMA(opaque);
 397
 398    DPRINTF("read @%" HWADDR_PRIx "\n", offset);
 399    offset = offset >> 2;
 400
 401    switch (offset) {
 402    /*
 403     * Trying to read a write only register.
 404     */
 405    case DPDMA_GBL:
 406        return 0;
 407    default:
 408        assert(offset <= (0xFFC >> 2));
 409        return s->registers[offset];
 410    }
 411    return 0;
 412}
 413
 414static void xlnx_dpdma_write(void *opaque, hwaddr offset,
 415                               uint64_t value, unsigned size)
 416{
 417    XlnxDPDMAState *s = XLNX_DPDMA(opaque);
 418
 419    DPRINTF("write @%" HWADDR_PRIx " = %" PRIx64 "\n", offset, value);
 420    offset = offset >> 2;
 421
 422    switch (offset) {
 423    case DPDMA_ISR:
 424        s->registers[DPDMA_ISR] &= ~value;
 425        xlnx_dpdma_update_irq(s);
 426        break;
 427    case DPDMA_IEN:
 428        s->registers[DPDMA_IMR] &= ~value;
 429        break;
 430    case DPDMA_IDS:
 431        s->registers[DPDMA_IMR] |= value;
 432        break;
 433    case DPDMA_EISR:
 434        s->registers[DPDMA_EISR] &= ~value;
 435        xlnx_dpdma_update_irq(s);
 436        break;
 437    case DPDMA_EIEN:
 438        s->registers[DPDMA_EIMR] &= ~value;
 439        break;
 440    case DPDMA_EIDS:
 441        s->registers[DPDMA_EIMR] |= value;
 442        break;
 443    case DPDMA_IMR:
 444    case DPDMA_EIMR:
 445    case DPDMA_DSCR_NEXT_ADDRE_CH(0):
 446    case DPDMA_DSCR_NEXT_ADDRE_CH(1):
 447    case DPDMA_DSCR_NEXT_ADDRE_CH(2):
 448    case DPDMA_DSCR_NEXT_ADDRE_CH(3):
 449    case DPDMA_DSCR_NEXT_ADDRE_CH(4):
 450    case DPDMA_DSCR_NEXT_ADDRE_CH(5):
 451    case DPDMA_DSCR_NEXT_ADDR_CH(0):
 452    case DPDMA_DSCR_NEXT_ADDR_CH(1):
 453    case DPDMA_DSCR_NEXT_ADDR_CH(2):
 454    case DPDMA_DSCR_NEXT_ADDR_CH(3):
 455    case DPDMA_DSCR_NEXT_ADDR_CH(4):
 456    case DPDMA_DSCR_NEXT_ADDR_CH(5):
 457    case DPDMA_PYLD_CUR_ADDRE_CH(0):
 458    case DPDMA_PYLD_CUR_ADDRE_CH(1):
 459    case DPDMA_PYLD_CUR_ADDRE_CH(2):
 460    case DPDMA_PYLD_CUR_ADDRE_CH(3):
 461    case DPDMA_PYLD_CUR_ADDRE_CH(4):
 462    case DPDMA_PYLD_CUR_ADDRE_CH(5):
 463    case DPDMA_PYLD_CUR_ADDR_CH(0):
 464    case DPDMA_PYLD_CUR_ADDR_CH(1):
 465    case DPDMA_PYLD_CUR_ADDR_CH(2):
 466    case DPDMA_PYLD_CUR_ADDR_CH(3):
 467    case DPDMA_PYLD_CUR_ADDR_CH(4):
 468    case DPDMA_PYLD_CUR_ADDR_CH(5):
 469    case DPDMA_STATUS_CH(0):
 470    case DPDMA_STATUS_CH(1):
 471    case DPDMA_STATUS_CH(2):
 472    case DPDMA_STATUS_CH(3):
 473    case DPDMA_STATUS_CH(4):
 474    case DPDMA_STATUS_CH(5):
 475    case DPDMA_VDO_CH(0):
 476    case DPDMA_VDO_CH(1):
 477    case DPDMA_VDO_CH(2):
 478    case DPDMA_VDO_CH(3):
 479    case DPDMA_VDO_CH(4):
 480    case DPDMA_VDO_CH(5):
 481    case DPDMA_PYLD_SZ_CH(0):
 482    case DPDMA_PYLD_SZ_CH(1):
 483    case DPDMA_PYLD_SZ_CH(2):
 484    case DPDMA_PYLD_SZ_CH(3):
 485    case DPDMA_PYLD_SZ_CH(4):
 486    case DPDMA_PYLD_SZ_CH(5):
 487    case DPDMA_DSCR_ID_CH(0):
 488    case DPDMA_DSCR_ID_CH(1):
 489    case DPDMA_DSCR_ID_CH(2):
 490    case DPDMA_DSCR_ID_CH(3):
 491    case DPDMA_DSCR_ID_CH(4):
 492    case DPDMA_DSCR_ID_CH(5):
 493        /*
 494         * Trying to write to a read only register..
 495         */
 496        break;
 497    case DPDMA_GBL:
 498        /*
 499         * This is a write only register so it's read as zero in the read
 500         * callback.
 501         * We store the value anyway so we can know if the channel is
 502         * enabled.
 503         */
 504        s->registers[offset] |= value & 0x00000FFF;
 505        break;
 506    case DPDMA_DSCR_STRT_ADDRE_CH(0):
 507    case DPDMA_DSCR_STRT_ADDRE_CH(1):
 508    case DPDMA_DSCR_STRT_ADDRE_CH(2):
 509    case DPDMA_DSCR_STRT_ADDRE_CH(3):
 510    case DPDMA_DSCR_STRT_ADDRE_CH(4):
 511    case DPDMA_DSCR_STRT_ADDRE_CH(5):
 512        value &= 0x0000FFFF;
 513        s->registers[offset] = value;
 514        break;
 515    case DPDMA_CNTL_CH(0):
 516        s->registers[DPDMA_GBL] &= ~DPDMA_GBL_TRG_CH(0);
 517        value &= 0x3FFFFFFF;
 518        s->registers[offset] = value;
 519        break;
 520    case DPDMA_CNTL_CH(1):
 521        s->registers[DPDMA_GBL] &= ~DPDMA_GBL_TRG_CH(1);
 522        value &= 0x3FFFFFFF;
 523        s->registers[offset] = value;
 524        break;
 525    case DPDMA_CNTL_CH(2):
 526        s->registers[DPDMA_GBL] &= ~DPDMA_GBL_TRG_CH(2);
 527        value &= 0x3FFFFFFF;
 528        s->registers[offset] = value;
 529        break;
 530    case DPDMA_CNTL_CH(3):
 531        s->registers[DPDMA_GBL] &= ~DPDMA_GBL_TRG_CH(3);
 532        value &= 0x3FFFFFFF;
 533        s->registers[offset] = value;
 534        break;
 535    case DPDMA_CNTL_CH(4):
 536        s->registers[DPDMA_GBL] &= ~DPDMA_GBL_TRG_CH(4);
 537        value &= 0x3FFFFFFF;
 538        s->registers[offset] = value;
 539        break;
 540    case DPDMA_CNTL_CH(5):
 541        s->registers[DPDMA_GBL] &= ~DPDMA_GBL_TRG_CH(5);
 542        value &= 0x3FFFFFFF;
 543        s->registers[offset] = value;
 544        break;
 545    default:
 546        assert(offset <= (0xFFC >> 2));
 547        s->registers[offset] = value;
 548        break;
 549    }
 550}
 551
 552static const MemoryRegionOps dma_ops = {
 553    .read = xlnx_dpdma_read,
 554    .write = xlnx_dpdma_write,
 555    .endianness = DEVICE_NATIVE_ENDIAN,
 556    .valid = {
 557        .min_access_size = 4,
 558        .max_access_size = 4,
 559    },
 560    .impl = {
 561        .min_access_size = 4,
 562        .max_access_size = 4,
 563    },
 564};
 565
 566static void xlnx_dpdma_init(Object *obj)
 567{
 568    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 569    XlnxDPDMAState *s = XLNX_DPDMA(obj);
 570
 571    memory_region_init_io(&s->iomem, obj, &dma_ops, s,
 572                          TYPE_XLNX_DPDMA, 0x1000);
 573    sysbus_init_mmio(sbd, &s->iomem);
 574    sysbus_init_irq(sbd, &s->irq);
 575}
 576
 577static void xlnx_dpdma_reset(DeviceState *dev)
 578{
 579    XlnxDPDMAState *s = XLNX_DPDMA(dev);
 580    size_t i;
 581
 582    memset(s->registers, 0, sizeof(s->registers));
 583    s->registers[DPDMA_IMR] =  0x07FFFFFF;
 584    s->registers[DPDMA_EIMR] = 0xFFFFFFFF;
 585    s->registers[DPDMA_ALC0_MIN] = 0x0000FFFF;
 586    s->registers[DPDMA_ALC1_MIN] = 0x0000FFFF;
 587
 588    for (i = 0; i < 6; i++) {
 589        s->data[i] = NULL;
 590        s->operation_finished[i] = true;
 591    }
 592}
 593
 594static void xlnx_dpdma_class_init(ObjectClass *oc, void *data)
 595{
 596    DeviceClass *dc = DEVICE_CLASS(oc);
 597
 598    dc->vmsd = &vmstate_xlnx_dpdma;
 599    dc->reset = xlnx_dpdma_reset;
 600}
 601
 602static const TypeInfo xlnx_dpdma_info = {
 603    .name          = TYPE_XLNX_DPDMA,
 604    .parent        = TYPE_SYS_BUS_DEVICE,
 605    .instance_size = sizeof(XlnxDPDMAState),
 606    .instance_init = xlnx_dpdma_init,
 607    .class_init    = xlnx_dpdma_class_init,
 608};
 609
 610static void xlnx_dpdma_register_types(void)
 611{
 612    type_register_static(&xlnx_dpdma_info);
 613}
 614
 615size_t xlnx_dpdma_start_operation(XlnxDPDMAState *s, uint8_t channel,
 616                                    bool one_desc)
 617{
 618    uint64_t desc_addr;
 619    uint64_t source_addr[6];
 620    DPDMADescriptor desc;
 621    bool done = false;
 622    size_t ptr = 0;
 623
 624    assert(channel <= 5);
 625
 626    DPRINTF("start dpdma channel 0x%" PRIX8 "\n", channel);
 627
 628    if (!xlnx_dpdma_is_channel_triggered(s, channel)) {
 629        DPRINTF("Channel isn't triggered..\n");
 630        return 0;
 631    }
 632
 633    if (!xlnx_dpdma_is_channel_enabled(s, channel)) {
 634        DPRINTF("Channel isn't enabled..\n");
 635        return 0;
 636    }
 637
 638    if (xlnx_dpdma_is_channel_paused(s, channel)) {
 639        DPRINTF("Channel is paused..\n");
 640        return 0;
 641    }
 642
 643    do {
 644        if ((s->operation_finished[channel])
 645          || xlnx_dpdma_is_channel_retriggered(s, channel)) {
 646            desc_addr = xlnx_dpdma_descriptor_start_address(s, channel);
 647            s->operation_finished[channel] = false;
 648        } else {
 649            desc_addr = xlnx_dpdma_descriptor_next_address(s, channel);
 650        }
 651
 652        if (dma_memory_read(&address_space_memory, desc_addr, &desc,
 653                            sizeof(DPDMADescriptor))) {
 654            s->registers[DPDMA_EISR] |= ((1 << 1) << channel);
 655            xlnx_dpdma_update_irq(s);
 656            s->operation_finished[channel] = true;
 657            DPRINTF("Can't get the descriptor.\n");
 658            break;
 659        }
 660
 661        xlnx_dpdma_update_desc_info(s, channel, &desc);
 662
 663#ifdef DEBUG_DPDMA
 664        xlnx_dpdma_dump_descriptor(&desc);
 665#endif
 666
 667        DPRINTF("location of the descriptor: %" PRIx64 "\n", desc_addr);
 668        if (!xlnx_dpdma_desc_is_valid(&desc)) {
 669            s->registers[DPDMA_EISR] |= ((1 << 7) << channel);
 670            xlnx_dpdma_update_irq(s);
 671            s->operation_finished[channel] = true;
 672            DPRINTF("Invalid descriptor..\n");
 673            break;
 674        }
 675
 676        if (xlnx_dpdma_desc_crc_enabled(&desc)
 677            && !xlnx_dpdma_desc_check_crc(&desc)) {
 678            s->registers[DPDMA_EISR] |= ((1 << 13) << channel);
 679            xlnx_dpdma_update_irq(s);
 680            s->operation_finished[channel] = true;
 681            DPRINTF("Bad CRC for descriptor..\n");
 682            break;
 683        }
 684
 685        if (xlnx_dpdma_desc_is_already_done(&desc)
 686            && !xlnx_dpdma_desc_ignore_done_bit(&desc)) {
 687            /* We are trying to process an already processed descriptor. */
 688            s->registers[DPDMA_EISR] |= ((1 << 25) << channel);
 689            xlnx_dpdma_update_irq(s);
 690            s->operation_finished[channel] = true;
 691            DPRINTF("Already processed descriptor..\n");
 692            break;
 693        }
 694
 695        done = xlnx_dpdma_desc_is_last(&desc)
 696             || xlnx_dpdma_desc_is_last_of_frame(&desc);
 697
 698        s->operation_finished[channel] = done;
 699        if (s->data[channel]) {
 700            int64_t transfer_len = xlnx_dpdma_desc_get_transfer_size(&desc);
 701            uint32_t line_size = xlnx_dpdma_desc_get_line_size(&desc);
 702            uint32_t line_stride = xlnx_dpdma_desc_get_line_stride(&desc);
 703            if (xlnx_dpdma_desc_is_contiguous(&desc)) {
 704                source_addr[0] = xlnx_dpdma_desc_get_source_address(&desc, 0);
 705                while (transfer_len != 0) {
 706                    if (dma_memory_read(&address_space_memory,
 707                                        source_addr[0],
 708                                        &s->data[channel][ptr],
 709                                        line_size)) {
 710                        s->registers[DPDMA_ISR] |= ((1 << 12) << channel);
 711                        xlnx_dpdma_update_irq(s);
 712                        DPRINTF("Can't get data.\n");
 713                        break;
 714                    }
 715                    ptr += line_size;
 716                    transfer_len -= line_size;
 717                    source_addr[0] += line_stride;
 718                }
 719            } else {
 720                DPRINTF("Source address:\n");
 721                int frag;
 722                for (frag = 0; frag < 5; frag++) {
 723                    source_addr[frag] =
 724                          xlnx_dpdma_desc_get_source_address(&desc, frag);
 725                    DPRINTF("Fragment %u: %" PRIx64 "\n", frag + 1,
 726                            source_addr[frag]);
 727                }
 728
 729                frag = 0;
 730                while ((transfer_len < 0) && (frag < 5)) {
 731                    size_t fragment_len = DPDMA_FRAG_MAX_SZ
 732                                    - (source_addr[frag] % DPDMA_FRAG_MAX_SZ);
 733
 734                    if (dma_memory_read(&address_space_memory,
 735                                        source_addr[frag],
 736                                        &(s->data[channel][ptr]),
 737                                        fragment_len)) {
 738                        s->registers[DPDMA_ISR] |= ((1 << 12) << channel);
 739                        xlnx_dpdma_update_irq(s);
 740                        DPRINTF("Can't get data.\n");
 741                        break;
 742                    }
 743                    ptr += fragment_len;
 744                    transfer_len -= fragment_len;
 745                    frag += 1;
 746                }
 747            }
 748        }
 749
 750        if (xlnx_dpdma_desc_update_enabled(&desc)) {
 751            /* The descriptor need to be updated when it's completed. */
 752            DPRINTF("update the descriptor with the done flag set.\n");
 753            xlnx_dpdma_desc_set_done(&desc);
 754            dma_memory_write(&address_space_memory, desc_addr, &desc,
 755                             sizeof(DPDMADescriptor));
 756        }
 757
 758        if (xlnx_dpdma_desc_completion_interrupt(&desc)) {
 759            DPRINTF("completion interrupt enabled!\n");
 760            s->registers[DPDMA_ISR] |= (1 << channel);
 761            xlnx_dpdma_update_irq(s);
 762        }
 763
 764    } while (!done && !one_desc);
 765
 766    return ptr;
 767}
 768
 769void xlnx_dpdma_set_host_data_location(XlnxDPDMAState *s, uint8_t channel,
 770                                         void *p)
 771{
 772    if (!s) {
 773        qemu_log_mask(LOG_UNIMP, "DPDMA client not attached to valid DPDMA"
 774                      " instance\n");
 775        return;
 776    }
 777
 778    assert(channel <= 5);
 779    s->data[channel] = p;
 780}
 781
 782void xlnx_dpdma_trigger_vsync_irq(XlnxDPDMAState *s)
 783{
 784    s->registers[DPDMA_ISR] |= (1 << 27);
 785    xlnx_dpdma_update_irq(s);
 786}
 787
 788type_init(xlnx_dpdma_register_types)
 789