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