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