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