1*49ab747fSPaolo Bonzini /* 2*49ab747fSPaolo Bonzini * PowerMac descriptor-based DMA emulation 3*49ab747fSPaolo Bonzini * 4*49ab747fSPaolo Bonzini * Copyright (c) 2005-2007 Fabrice Bellard 5*49ab747fSPaolo Bonzini * Copyright (c) 2007 Jocelyn Mayer 6*49ab747fSPaolo Bonzini * Copyright (c) 2009 Laurent Vivier 7*49ab747fSPaolo Bonzini * 8*49ab747fSPaolo Bonzini * some parts from linux-2.6.28, arch/powerpc/include/asm/dbdma.h 9*49ab747fSPaolo Bonzini * 10*49ab747fSPaolo Bonzini * Definitions for using the Apple Descriptor-Based DMA controller 11*49ab747fSPaolo Bonzini * in Power Macintosh computers. 12*49ab747fSPaolo Bonzini * 13*49ab747fSPaolo Bonzini * Copyright (C) 1996 Paul Mackerras. 14*49ab747fSPaolo Bonzini * 15*49ab747fSPaolo Bonzini * some parts from mol 0.9.71 16*49ab747fSPaolo Bonzini * 17*49ab747fSPaolo Bonzini * Descriptor based DMA emulation 18*49ab747fSPaolo Bonzini * 19*49ab747fSPaolo Bonzini * Copyright (C) 1998-2004 Samuel Rydh (samuel@ibrium.se) 20*49ab747fSPaolo Bonzini * 21*49ab747fSPaolo Bonzini * Permission is hereby granted, free of charge, to any person obtaining a copy 22*49ab747fSPaolo Bonzini * of this software and associated documentation files (the "Software"), to deal 23*49ab747fSPaolo Bonzini * in the Software without restriction, including without limitation the rights 24*49ab747fSPaolo Bonzini * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 25*49ab747fSPaolo Bonzini * copies of the Software, and to permit persons to whom the Software is 26*49ab747fSPaolo Bonzini * furnished to do so, subject to the following conditions: 27*49ab747fSPaolo Bonzini * 28*49ab747fSPaolo Bonzini * The above copyright notice and this permission notice shall be included in 29*49ab747fSPaolo Bonzini * all copies or substantial portions of the Software. 30*49ab747fSPaolo Bonzini * 31*49ab747fSPaolo Bonzini * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 32*49ab747fSPaolo Bonzini * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 33*49ab747fSPaolo Bonzini * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 34*49ab747fSPaolo Bonzini * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 35*49ab747fSPaolo Bonzini * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 36*49ab747fSPaolo Bonzini * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 37*49ab747fSPaolo Bonzini * THE SOFTWARE. 38*49ab747fSPaolo Bonzini */ 39*49ab747fSPaolo Bonzini #include "hw/hw.h" 40*49ab747fSPaolo Bonzini #include "hw/isa/isa.h" 41*49ab747fSPaolo Bonzini #include "hw/ppc/mac_dbdma.h" 42*49ab747fSPaolo Bonzini #include "qemu/main-loop.h" 43*49ab747fSPaolo Bonzini 44*49ab747fSPaolo Bonzini /* debug DBDMA */ 45*49ab747fSPaolo Bonzini //#define DEBUG_DBDMA 46*49ab747fSPaolo Bonzini 47*49ab747fSPaolo Bonzini #ifdef DEBUG_DBDMA 48*49ab747fSPaolo Bonzini #define DBDMA_DPRINTF(fmt, ...) \ 49*49ab747fSPaolo Bonzini do { printf("DBDMA: " fmt , ## __VA_ARGS__); } while (0) 50*49ab747fSPaolo Bonzini #else 51*49ab747fSPaolo Bonzini #define DBDMA_DPRINTF(fmt, ...) 52*49ab747fSPaolo Bonzini #endif 53*49ab747fSPaolo Bonzini 54*49ab747fSPaolo Bonzini /* 55*49ab747fSPaolo Bonzini */ 56*49ab747fSPaolo Bonzini 57*49ab747fSPaolo Bonzini /* 58*49ab747fSPaolo Bonzini * DBDMA control/status registers. All little-endian. 59*49ab747fSPaolo Bonzini */ 60*49ab747fSPaolo Bonzini 61*49ab747fSPaolo Bonzini #define DBDMA_CONTROL 0x00 62*49ab747fSPaolo Bonzini #define DBDMA_STATUS 0x01 63*49ab747fSPaolo Bonzini #define DBDMA_CMDPTR_HI 0x02 64*49ab747fSPaolo Bonzini #define DBDMA_CMDPTR_LO 0x03 65*49ab747fSPaolo Bonzini #define DBDMA_INTR_SEL 0x04 66*49ab747fSPaolo Bonzini #define DBDMA_BRANCH_SEL 0x05 67*49ab747fSPaolo Bonzini #define DBDMA_WAIT_SEL 0x06 68*49ab747fSPaolo Bonzini #define DBDMA_XFER_MODE 0x07 69*49ab747fSPaolo Bonzini #define DBDMA_DATA2PTR_HI 0x08 70*49ab747fSPaolo Bonzini #define DBDMA_DATA2PTR_LO 0x09 71*49ab747fSPaolo Bonzini #define DBDMA_RES1 0x0A 72*49ab747fSPaolo Bonzini #define DBDMA_ADDRESS_HI 0x0B 73*49ab747fSPaolo Bonzini #define DBDMA_BRANCH_ADDR_HI 0x0C 74*49ab747fSPaolo Bonzini #define DBDMA_RES2 0x0D 75*49ab747fSPaolo Bonzini #define DBDMA_RES3 0x0E 76*49ab747fSPaolo Bonzini #define DBDMA_RES4 0x0F 77*49ab747fSPaolo Bonzini 78*49ab747fSPaolo Bonzini #define DBDMA_REGS 16 79*49ab747fSPaolo Bonzini #define DBDMA_SIZE (DBDMA_REGS * sizeof(uint32_t)) 80*49ab747fSPaolo Bonzini 81*49ab747fSPaolo Bonzini #define DBDMA_CHANNEL_SHIFT 7 82*49ab747fSPaolo Bonzini #define DBDMA_CHANNEL_SIZE (1 << DBDMA_CHANNEL_SHIFT) 83*49ab747fSPaolo Bonzini 84*49ab747fSPaolo Bonzini #define DBDMA_CHANNELS (0x1000 >> DBDMA_CHANNEL_SHIFT) 85*49ab747fSPaolo Bonzini 86*49ab747fSPaolo Bonzini /* Bits in control and status registers */ 87*49ab747fSPaolo Bonzini 88*49ab747fSPaolo Bonzini #define RUN 0x8000 89*49ab747fSPaolo Bonzini #define PAUSE 0x4000 90*49ab747fSPaolo Bonzini #define FLUSH 0x2000 91*49ab747fSPaolo Bonzini #define WAKE 0x1000 92*49ab747fSPaolo Bonzini #define DEAD 0x0800 93*49ab747fSPaolo Bonzini #define ACTIVE 0x0400 94*49ab747fSPaolo Bonzini #define BT 0x0100 95*49ab747fSPaolo Bonzini #define DEVSTAT 0x00ff 96*49ab747fSPaolo Bonzini 97*49ab747fSPaolo Bonzini /* 98*49ab747fSPaolo Bonzini * DBDMA command structure. These fields are all little-endian! 99*49ab747fSPaolo Bonzini */ 100*49ab747fSPaolo Bonzini 101*49ab747fSPaolo Bonzini typedef struct dbdma_cmd { 102*49ab747fSPaolo Bonzini uint16_t req_count; /* requested byte transfer count */ 103*49ab747fSPaolo Bonzini uint16_t command; /* command word (has bit-fields) */ 104*49ab747fSPaolo Bonzini uint32_t phy_addr; /* physical data address */ 105*49ab747fSPaolo Bonzini uint32_t cmd_dep; /* command-dependent field */ 106*49ab747fSPaolo Bonzini uint16_t res_count; /* residual count after completion */ 107*49ab747fSPaolo Bonzini uint16_t xfer_status; /* transfer status */ 108*49ab747fSPaolo Bonzini } dbdma_cmd; 109*49ab747fSPaolo Bonzini 110*49ab747fSPaolo Bonzini /* DBDMA command values in command field */ 111*49ab747fSPaolo Bonzini 112*49ab747fSPaolo Bonzini #define COMMAND_MASK 0xf000 113*49ab747fSPaolo Bonzini #define OUTPUT_MORE 0x0000 /* transfer memory data to stream */ 114*49ab747fSPaolo Bonzini #define OUTPUT_LAST 0x1000 /* ditto followed by end marker */ 115*49ab747fSPaolo Bonzini #define INPUT_MORE 0x2000 /* transfer stream data to memory */ 116*49ab747fSPaolo Bonzini #define INPUT_LAST 0x3000 /* ditto, expect end marker */ 117*49ab747fSPaolo Bonzini #define STORE_WORD 0x4000 /* write word (4 bytes) to device reg */ 118*49ab747fSPaolo Bonzini #define LOAD_WORD 0x5000 /* read word (4 bytes) from device reg */ 119*49ab747fSPaolo Bonzini #define DBDMA_NOP 0x6000 /* do nothing */ 120*49ab747fSPaolo Bonzini #define DBDMA_STOP 0x7000 /* suspend processing */ 121*49ab747fSPaolo Bonzini 122*49ab747fSPaolo Bonzini /* Key values in command field */ 123*49ab747fSPaolo Bonzini 124*49ab747fSPaolo Bonzini #define KEY_MASK 0x0700 125*49ab747fSPaolo Bonzini #define KEY_STREAM0 0x0000 /* usual data stream */ 126*49ab747fSPaolo Bonzini #define KEY_STREAM1 0x0100 /* control/status stream */ 127*49ab747fSPaolo Bonzini #define KEY_STREAM2 0x0200 /* device-dependent stream */ 128*49ab747fSPaolo Bonzini #define KEY_STREAM3 0x0300 /* device-dependent stream */ 129*49ab747fSPaolo Bonzini #define KEY_STREAM4 0x0400 /* reserved */ 130*49ab747fSPaolo Bonzini #define KEY_REGS 0x0500 /* device register space */ 131*49ab747fSPaolo Bonzini #define KEY_SYSTEM 0x0600 /* system memory-mapped space */ 132*49ab747fSPaolo Bonzini #define KEY_DEVICE 0x0700 /* device memory-mapped space */ 133*49ab747fSPaolo Bonzini 134*49ab747fSPaolo Bonzini /* Interrupt control values in command field */ 135*49ab747fSPaolo Bonzini 136*49ab747fSPaolo Bonzini #define INTR_MASK 0x0030 137*49ab747fSPaolo Bonzini #define INTR_NEVER 0x0000 /* don't interrupt */ 138*49ab747fSPaolo Bonzini #define INTR_IFSET 0x0010 /* intr if condition bit is 1 */ 139*49ab747fSPaolo Bonzini #define INTR_IFCLR 0x0020 /* intr if condition bit is 0 */ 140*49ab747fSPaolo Bonzini #define INTR_ALWAYS 0x0030 /* always interrupt */ 141*49ab747fSPaolo Bonzini 142*49ab747fSPaolo Bonzini /* Branch control values in command field */ 143*49ab747fSPaolo Bonzini 144*49ab747fSPaolo Bonzini #define BR_MASK 0x000c 145*49ab747fSPaolo Bonzini #define BR_NEVER 0x0000 /* don't branch */ 146*49ab747fSPaolo Bonzini #define BR_IFSET 0x0004 /* branch if condition bit is 1 */ 147*49ab747fSPaolo Bonzini #define BR_IFCLR 0x0008 /* branch if condition bit is 0 */ 148*49ab747fSPaolo Bonzini #define BR_ALWAYS 0x000c /* always branch */ 149*49ab747fSPaolo Bonzini 150*49ab747fSPaolo Bonzini /* Wait control values in command field */ 151*49ab747fSPaolo Bonzini 152*49ab747fSPaolo Bonzini #define WAIT_MASK 0x0003 153*49ab747fSPaolo Bonzini #define WAIT_NEVER 0x0000 /* don't wait */ 154*49ab747fSPaolo Bonzini #define WAIT_IFSET 0x0001 /* wait if condition bit is 1 */ 155*49ab747fSPaolo Bonzini #define WAIT_IFCLR 0x0002 /* wait if condition bit is 0 */ 156*49ab747fSPaolo Bonzini #define WAIT_ALWAYS 0x0003 /* always wait */ 157*49ab747fSPaolo Bonzini 158*49ab747fSPaolo Bonzini typedef struct DBDMA_channel { 159*49ab747fSPaolo Bonzini int channel; 160*49ab747fSPaolo Bonzini uint32_t regs[DBDMA_REGS]; 161*49ab747fSPaolo Bonzini qemu_irq irq; 162*49ab747fSPaolo Bonzini DBDMA_io io; 163*49ab747fSPaolo Bonzini DBDMA_rw rw; 164*49ab747fSPaolo Bonzini DBDMA_flush flush; 165*49ab747fSPaolo Bonzini dbdma_cmd current; 166*49ab747fSPaolo Bonzini int processing; 167*49ab747fSPaolo Bonzini } DBDMA_channel; 168*49ab747fSPaolo Bonzini 169*49ab747fSPaolo Bonzini typedef struct { 170*49ab747fSPaolo Bonzini MemoryRegion mem; 171*49ab747fSPaolo Bonzini DBDMA_channel channels[DBDMA_CHANNELS]; 172*49ab747fSPaolo Bonzini } DBDMAState; 173*49ab747fSPaolo Bonzini 174*49ab747fSPaolo Bonzini #ifdef DEBUG_DBDMA 175*49ab747fSPaolo Bonzini static void dump_dbdma_cmd(dbdma_cmd *cmd) 176*49ab747fSPaolo Bonzini { 177*49ab747fSPaolo Bonzini printf("dbdma_cmd %p\n", cmd); 178*49ab747fSPaolo Bonzini printf(" req_count 0x%04x\n", le16_to_cpu(cmd->req_count)); 179*49ab747fSPaolo Bonzini printf(" command 0x%04x\n", le16_to_cpu(cmd->command)); 180*49ab747fSPaolo Bonzini printf(" phy_addr 0x%08x\n", le32_to_cpu(cmd->phy_addr)); 181*49ab747fSPaolo Bonzini printf(" cmd_dep 0x%08x\n", le32_to_cpu(cmd->cmd_dep)); 182*49ab747fSPaolo Bonzini printf(" res_count 0x%04x\n", le16_to_cpu(cmd->res_count)); 183*49ab747fSPaolo Bonzini printf(" xfer_status 0x%04x\n", le16_to_cpu(cmd->xfer_status)); 184*49ab747fSPaolo Bonzini } 185*49ab747fSPaolo Bonzini #else 186*49ab747fSPaolo Bonzini static void dump_dbdma_cmd(dbdma_cmd *cmd) 187*49ab747fSPaolo Bonzini { 188*49ab747fSPaolo Bonzini } 189*49ab747fSPaolo Bonzini #endif 190*49ab747fSPaolo Bonzini static void dbdma_cmdptr_load(DBDMA_channel *ch) 191*49ab747fSPaolo Bonzini { 192*49ab747fSPaolo Bonzini DBDMA_DPRINTF("dbdma_cmdptr_load 0x%08x\n", 193*49ab747fSPaolo Bonzini ch->regs[DBDMA_CMDPTR_LO]); 194*49ab747fSPaolo Bonzini cpu_physical_memory_read(ch->regs[DBDMA_CMDPTR_LO], 195*49ab747fSPaolo Bonzini (uint8_t*)&ch->current, sizeof(dbdma_cmd)); 196*49ab747fSPaolo Bonzini } 197*49ab747fSPaolo Bonzini 198*49ab747fSPaolo Bonzini static void dbdma_cmdptr_save(DBDMA_channel *ch) 199*49ab747fSPaolo Bonzini { 200*49ab747fSPaolo Bonzini DBDMA_DPRINTF("dbdma_cmdptr_save 0x%08x\n", 201*49ab747fSPaolo Bonzini ch->regs[DBDMA_CMDPTR_LO]); 202*49ab747fSPaolo Bonzini DBDMA_DPRINTF("xfer_status 0x%08x res_count 0x%04x\n", 203*49ab747fSPaolo Bonzini le16_to_cpu(ch->current.xfer_status), 204*49ab747fSPaolo Bonzini le16_to_cpu(ch->current.res_count)); 205*49ab747fSPaolo Bonzini cpu_physical_memory_write(ch->regs[DBDMA_CMDPTR_LO], 206*49ab747fSPaolo Bonzini (uint8_t*)&ch->current, sizeof(dbdma_cmd)); 207*49ab747fSPaolo Bonzini } 208*49ab747fSPaolo Bonzini 209*49ab747fSPaolo Bonzini static void kill_channel(DBDMA_channel *ch) 210*49ab747fSPaolo Bonzini { 211*49ab747fSPaolo Bonzini DBDMA_DPRINTF("kill_channel\n"); 212*49ab747fSPaolo Bonzini 213*49ab747fSPaolo Bonzini ch->regs[DBDMA_STATUS] |= DEAD; 214*49ab747fSPaolo Bonzini ch->regs[DBDMA_STATUS] &= ~ACTIVE; 215*49ab747fSPaolo Bonzini 216*49ab747fSPaolo Bonzini qemu_irq_raise(ch->irq); 217*49ab747fSPaolo Bonzini } 218*49ab747fSPaolo Bonzini 219*49ab747fSPaolo Bonzini static void conditional_interrupt(DBDMA_channel *ch) 220*49ab747fSPaolo Bonzini { 221*49ab747fSPaolo Bonzini dbdma_cmd *current = &ch->current; 222*49ab747fSPaolo Bonzini uint16_t intr; 223*49ab747fSPaolo Bonzini uint16_t sel_mask, sel_value; 224*49ab747fSPaolo Bonzini uint32_t status; 225*49ab747fSPaolo Bonzini int cond; 226*49ab747fSPaolo Bonzini 227*49ab747fSPaolo Bonzini DBDMA_DPRINTF("conditional_interrupt\n"); 228*49ab747fSPaolo Bonzini 229*49ab747fSPaolo Bonzini intr = le16_to_cpu(current->command) & INTR_MASK; 230*49ab747fSPaolo Bonzini 231*49ab747fSPaolo Bonzini switch(intr) { 232*49ab747fSPaolo Bonzini case INTR_NEVER: /* don't interrupt */ 233*49ab747fSPaolo Bonzini return; 234*49ab747fSPaolo Bonzini case INTR_ALWAYS: /* always interrupt */ 235*49ab747fSPaolo Bonzini qemu_irq_raise(ch->irq); 236*49ab747fSPaolo Bonzini return; 237*49ab747fSPaolo Bonzini } 238*49ab747fSPaolo Bonzini 239*49ab747fSPaolo Bonzini status = ch->regs[DBDMA_STATUS] & DEVSTAT; 240*49ab747fSPaolo Bonzini 241*49ab747fSPaolo Bonzini sel_mask = (ch->regs[DBDMA_INTR_SEL] >> 16) & 0x0f; 242*49ab747fSPaolo Bonzini sel_value = ch->regs[DBDMA_INTR_SEL] & 0x0f; 243*49ab747fSPaolo Bonzini 244*49ab747fSPaolo Bonzini cond = (status & sel_mask) == (sel_value & sel_mask); 245*49ab747fSPaolo Bonzini 246*49ab747fSPaolo Bonzini switch(intr) { 247*49ab747fSPaolo Bonzini case INTR_IFSET: /* intr if condition bit is 1 */ 248*49ab747fSPaolo Bonzini if (cond) 249*49ab747fSPaolo Bonzini qemu_irq_raise(ch->irq); 250*49ab747fSPaolo Bonzini return; 251*49ab747fSPaolo Bonzini case INTR_IFCLR: /* intr if condition bit is 0 */ 252*49ab747fSPaolo Bonzini if (!cond) 253*49ab747fSPaolo Bonzini qemu_irq_raise(ch->irq); 254*49ab747fSPaolo Bonzini return; 255*49ab747fSPaolo Bonzini } 256*49ab747fSPaolo Bonzini } 257*49ab747fSPaolo Bonzini 258*49ab747fSPaolo Bonzini static int conditional_wait(DBDMA_channel *ch) 259*49ab747fSPaolo Bonzini { 260*49ab747fSPaolo Bonzini dbdma_cmd *current = &ch->current; 261*49ab747fSPaolo Bonzini uint16_t wait; 262*49ab747fSPaolo Bonzini uint16_t sel_mask, sel_value; 263*49ab747fSPaolo Bonzini uint32_t status; 264*49ab747fSPaolo Bonzini int cond; 265*49ab747fSPaolo Bonzini 266*49ab747fSPaolo Bonzini DBDMA_DPRINTF("conditional_wait\n"); 267*49ab747fSPaolo Bonzini 268*49ab747fSPaolo Bonzini wait = le16_to_cpu(current->command) & WAIT_MASK; 269*49ab747fSPaolo Bonzini 270*49ab747fSPaolo Bonzini switch(wait) { 271*49ab747fSPaolo Bonzini case WAIT_NEVER: /* don't wait */ 272*49ab747fSPaolo Bonzini return 0; 273*49ab747fSPaolo Bonzini case WAIT_ALWAYS: /* always wait */ 274*49ab747fSPaolo Bonzini return 1; 275*49ab747fSPaolo Bonzini } 276*49ab747fSPaolo Bonzini 277*49ab747fSPaolo Bonzini status = ch->regs[DBDMA_STATUS] & DEVSTAT; 278*49ab747fSPaolo Bonzini 279*49ab747fSPaolo Bonzini sel_mask = (ch->regs[DBDMA_WAIT_SEL] >> 16) & 0x0f; 280*49ab747fSPaolo Bonzini sel_value = ch->regs[DBDMA_WAIT_SEL] & 0x0f; 281*49ab747fSPaolo Bonzini 282*49ab747fSPaolo Bonzini cond = (status & sel_mask) == (sel_value & sel_mask); 283*49ab747fSPaolo Bonzini 284*49ab747fSPaolo Bonzini switch(wait) { 285*49ab747fSPaolo Bonzini case WAIT_IFSET: /* wait if condition bit is 1 */ 286*49ab747fSPaolo Bonzini if (cond) 287*49ab747fSPaolo Bonzini return 1; 288*49ab747fSPaolo Bonzini return 0; 289*49ab747fSPaolo Bonzini case WAIT_IFCLR: /* wait if condition bit is 0 */ 290*49ab747fSPaolo Bonzini if (!cond) 291*49ab747fSPaolo Bonzini return 1; 292*49ab747fSPaolo Bonzini return 0; 293*49ab747fSPaolo Bonzini } 294*49ab747fSPaolo Bonzini return 0; 295*49ab747fSPaolo Bonzini } 296*49ab747fSPaolo Bonzini 297*49ab747fSPaolo Bonzini static void next(DBDMA_channel *ch) 298*49ab747fSPaolo Bonzini { 299*49ab747fSPaolo Bonzini uint32_t cp; 300*49ab747fSPaolo Bonzini 301*49ab747fSPaolo Bonzini ch->regs[DBDMA_STATUS] &= ~BT; 302*49ab747fSPaolo Bonzini 303*49ab747fSPaolo Bonzini cp = ch->regs[DBDMA_CMDPTR_LO]; 304*49ab747fSPaolo Bonzini ch->regs[DBDMA_CMDPTR_LO] = cp + sizeof(dbdma_cmd); 305*49ab747fSPaolo Bonzini dbdma_cmdptr_load(ch); 306*49ab747fSPaolo Bonzini } 307*49ab747fSPaolo Bonzini 308*49ab747fSPaolo Bonzini static void branch(DBDMA_channel *ch) 309*49ab747fSPaolo Bonzini { 310*49ab747fSPaolo Bonzini dbdma_cmd *current = &ch->current; 311*49ab747fSPaolo Bonzini 312*49ab747fSPaolo Bonzini ch->regs[DBDMA_CMDPTR_LO] = current->cmd_dep; 313*49ab747fSPaolo Bonzini ch->regs[DBDMA_STATUS] |= BT; 314*49ab747fSPaolo Bonzini dbdma_cmdptr_load(ch); 315*49ab747fSPaolo Bonzini } 316*49ab747fSPaolo Bonzini 317*49ab747fSPaolo Bonzini static void conditional_branch(DBDMA_channel *ch) 318*49ab747fSPaolo Bonzini { 319*49ab747fSPaolo Bonzini dbdma_cmd *current = &ch->current; 320*49ab747fSPaolo Bonzini uint16_t br; 321*49ab747fSPaolo Bonzini uint16_t sel_mask, sel_value; 322*49ab747fSPaolo Bonzini uint32_t status; 323*49ab747fSPaolo Bonzini int cond; 324*49ab747fSPaolo Bonzini 325*49ab747fSPaolo Bonzini DBDMA_DPRINTF("conditional_branch\n"); 326*49ab747fSPaolo Bonzini 327*49ab747fSPaolo Bonzini /* check if we must branch */ 328*49ab747fSPaolo Bonzini 329*49ab747fSPaolo Bonzini br = le16_to_cpu(current->command) & BR_MASK; 330*49ab747fSPaolo Bonzini 331*49ab747fSPaolo Bonzini switch(br) { 332*49ab747fSPaolo Bonzini case BR_NEVER: /* don't branch */ 333*49ab747fSPaolo Bonzini next(ch); 334*49ab747fSPaolo Bonzini return; 335*49ab747fSPaolo Bonzini case BR_ALWAYS: /* always branch */ 336*49ab747fSPaolo Bonzini branch(ch); 337*49ab747fSPaolo Bonzini return; 338*49ab747fSPaolo Bonzini } 339*49ab747fSPaolo Bonzini 340*49ab747fSPaolo Bonzini status = ch->regs[DBDMA_STATUS] & DEVSTAT; 341*49ab747fSPaolo Bonzini 342*49ab747fSPaolo Bonzini sel_mask = (ch->regs[DBDMA_BRANCH_SEL] >> 16) & 0x0f; 343*49ab747fSPaolo Bonzini sel_value = ch->regs[DBDMA_BRANCH_SEL] & 0x0f; 344*49ab747fSPaolo Bonzini 345*49ab747fSPaolo Bonzini cond = (status & sel_mask) == (sel_value & sel_mask); 346*49ab747fSPaolo Bonzini 347*49ab747fSPaolo Bonzini switch(br) { 348*49ab747fSPaolo Bonzini case BR_IFSET: /* branch if condition bit is 1 */ 349*49ab747fSPaolo Bonzini if (cond) 350*49ab747fSPaolo Bonzini branch(ch); 351*49ab747fSPaolo Bonzini else 352*49ab747fSPaolo Bonzini next(ch); 353*49ab747fSPaolo Bonzini return; 354*49ab747fSPaolo Bonzini case BR_IFCLR: /* branch if condition bit is 0 */ 355*49ab747fSPaolo Bonzini if (!cond) 356*49ab747fSPaolo Bonzini branch(ch); 357*49ab747fSPaolo Bonzini else 358*49ab747fSPaolo Bonzini next(ch); 359*49ab747fSPaolo Bonzini return; 360*49ab747fSPaolo Bonzini } 361*49ab747fSPaolo Bonzini } 362*49ab747fSPaolo Bonzini 363*49ab747fSPaolo Bonzini static QEMUBH *dbdma_bh; 364*49ab747fSPaolo Bonzini static void channel_run(DBDMA_channel *ch); 365*49ab747fSPaolo Bonzini 366*49ab747fSPaolo Bonzini static void dbdma_end(DBDMA_io *io) 367*49ab747fSPaolo Bonzini { 368*49ab747fSPaolo Bonzini DBDMA_channel *ch = io->channel; 369*49ab747fSPaolo Bonzini dbdma_cmd *current = &ch->current; 370*49ab747fSPaolo Bonzini 371*49ab747fSPaolo Bonzini if (conditional_wait(ch)) 372*49ab747fSPaolo Bonzini goto wait; 373*49ab747fSPaolo Bonzini 374*49ab747fSPaolo Bonzini current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]); 375*49ab747fSPaolo Bonzini current->res_count = cpu_to_le16(io->len); 376*49ab747fSPaolo Bonzini dbdma_cmdptr_save(ch); 377*49ab747fSPaolo Bonzini if (io->is_last) 378*49ab747fSPaolo Bonzini ch->regs[DBDMA_STATUS] &= ~FLUSH; 379*49ab747fSPaolo Bonzini 380*49ab747fSPaolo Bonzini conditional_interrupt(ch); 381*49ab747fSPaolo Bonzini conditional_branch(ch); 382*49ab747fSPaolo Bonzini 383*49ab747fSPaolo Bonzini wait: 384*49ab747fSPaolo Bonzini ch->processing = 0; 385*49ab747fSPaolo Bonzini if ((ch->regs[DBDMA_STATUS] & RUN) && 386*49ab747fSPaolo Bonzini (ch->regs[DBDMA_STATUS] & ACTIVE)) 387*49ab747fSPaolo Bonzini channel_run(ch); 388*49ab747fSPaolo Bonzini } 389*49ab747fSPaolo Bonzini 390*49ab747fSPaolo Bonzini static void start_output(DBDMA_channel *ch, int key, uint32_t addr, 391*49ab747fSPaolo Bonzini uint16_t req_count, int is_last) 392*49ab747fSPaolo Bonzini { 393*49ab747fSPaolo Bonzini DBDMA_DPRINTF("start_output\n"); 394*49ab747fSPaolo Bonzini 395*49ab747fSPaolo Bonzini /* KEY_REGS, KEY_DEVICE and KEY_STREAM 396*49ab747fSPaolo Bonzini * are not implemented in the mac-io chip 397*49ab747fSPaolo Bonzini */ 398*49ab747fSPaolo Bonzini 399*49ab747fSPaolo Bonzini DBDMA_DPRINTF("addr 0x%x key 0x%x\n", addr, key); 400*49ab747fSPaolo Bonzini if (!addr || key > KEY_STREAM3) { 401*49ab747fSPaolo Bonzini kill_channel(ch); 402*49ab747fSPaolo Bonzini return; 403*49ab747fSPaolo Bonzini } 404*49ab747fSPaolo Bonzini 405*49ab747fSPaolo Bonzini ch->io.addr = addr; 406*49ab747fSPaolo Bonzini ch->io.len = req_count; 407*49ab747fSPaolo Bonzini ch->io.is_last = is_last; 408*49ab747fSPaolo Bonzini ch->io.dma_end = dbdma_end; 409*49ab747fSPaolo Bonzini ch->io.is_dma_out = 1; 410*49ab747fSPaolo Bonzini ch->processing = 1; 411*49ab747fSPaolo Bonzini if (ch->rw) { 412*49ab747fSPaolo Bonzini ch->rw(&ch->io); 413*49ab747fSPaolo Bonzini } 414*49ab747fSPaolo Bonzini } 415*49ab747fSPaolo Bonzini 416*49ab747fSPaolo Bonzini static void start_input(DBDMA_channel *ch, int key, uint32_t addr, 417*49ab747fSPaolo Bonzini uint16_t req_count, int is_last) 418*49ab747fSPaolo Bonzini { 419*49ab747fSPaolo Bonzini DBDMA_DPRINTF("start_input\n"); 420*49ab747fSPaolo Bonzini 421*49ab747fSPaolo Bonzini /* KEY_REGS, KEY_DEVICE and KEY_STREAM 422*49ab747fSPaolo Bonzini * are not implemented in the mac-io chip 423*49ab747fSPaolo Bonzini */ 424*49ab747fSPaolo Bonzini 425*49ab747fSPaolo Bonzini if (!addr || key > KEY_STREAM3) { 426*49ab747fSPaolo Bonzini kill_channel(ch); 427*49ab747fSPaolo Bonzini return; 428*49ab747fSPaolo Bonzini } 429*49ab747fSPaolo Bonzini 430*49ab747fSPaolo Bonzini ch->io.addr = addr; 431*49ab747fSPaolo Bonzini ch->io.len = req_count; 432*49ab747fSPaolo Bonzini ch->io.is_last = is_last; 433*49ab747fSPaolo Bonzini ch->io.dma_end = dbdma_end; 434*49ab747fSPaolo Bonzini ch->io.is_dma_out = 0; 435*49ab747fSPaolo Bonzini ch->processing = 1; 436*49ab747fSPaolo Bonzini if (ch->rw) { 437*49ab747fSPaolo Bonzini ch->rw(&ch->io); 438*49ab747fSPaolo Bonzini } 439*49ab747fSPaolo Bonzini } 440*49ab747fSPaolo Bonzini 441*49ab747fSPaolo Bonzini static void load_word(DBDMA_channel *ch, int key, uint32_t addr, 442*49ab747fSPaolo Bonzini uint16_t len) 443*49ab747fSPaolo Bonzini { 444*49ab747fSPaolo Bonzini dbdma_cmd *current = &ch->current; 445*49ab747fSPaolo Bonzini uint32_t val; 446*49ab747fSPaolo Bonzini 447*49ab747fSPaolo Bonzini DBDMA_DPRINTF("load_word\n"); 448*49ab747fSPaolo Bonzini 449*49ab747fSPaolo Bonzini /* only implements KEY_SYSTEM */ 450*49ab747fSPaolo Bonzini 451*49ab747fSPaolo Bonzini if (key != KEY_SYSTEM) { 452*49ab747fSPaolo Bonzini printf("DBDMA: LOAD_WORD, unimplemented key %x\n", key); 453*49ab747fSPaolo Bonzini kill_channel(ch); 454*49ab747fSPaolo Bonzini return; 455*49ab747fSPaolo Bonzini } 456*49ab747fSPaolo Bonzini 457*49ab747fSPaolo Bonzini cpu_physical_memory_read(addr, (uint8_t*)&val, len); 458*49ab747fSPaolo Bonzini 459*49ab747fSPaolo Bonzini if (len == 2) 460*49ab747fSPaolo Bonzini val = (val << 16) | (current->cmd_dep & 0x0000ffff); 461*49ab747fSPaolo Bonzini else if (len == 1) 462*49ab747fSPaolo Bonzini val = (val << 24) | (current->cmd_dep & 0x00ffffff); 463*49ab747fSPaolo Bonzini 464*49ab747fSPaolo Bonzini current->cmd_dep = val; 465*49ab747fSPaolo Bonzini 466*49ab747fSPaolo Bonzini if (conditional_wait(ch)) 467*49ab747fSPaolo Bonzini goto wait; 468*49ab747fSPaolo Bonzini 469*49ab747fSPaolo Bonzini current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]); 470*49ab747fSPaolo Bonzini dbdma_cmdptr_save(ch); 471*49ab747fSPaolo Bonzini ch->regs[DBDMA_STATUS] &= ~FLUSH; 472*49ab747fSPaolo Bonzini 473*49ab747fSPaolo Bonzini conditional_interrupt(ch); 474*49ab747fSPaolo Bonzini next(ch); 475*49ab747fSPaolo Bonzini 476*49ab747fSPaolo Bonzini wait: 477*49ab747fSPaolo Bonzini qemu_bh_schedule(dbdma_bh); 478*49ab747fSPaolo Bonzini } 479*49ab747fSPaolo Bonzini 480*49ab747fSPaolo Bonzini static void store_word(DBDMA_channel *ch, int key, uint32_t addr, 481*49ab747fSPaolo Bonzini uint16_t len) 482*49ab747fSPaolo Bonzini { 483*49ab747fSPaolo Bonzini dbdma_cmd *current = &ch->current; 484*49ab747fSPaolo Bonzini uint32_t val; 485*49ab747fSPaolo Bonzini 486*49ab747fSPaolo Bonzini DBDMA_DPRINTF("store_word\n"); 487*49ab747fSPaolo Bonzini 488*49ab747fSPaolo Bonzini /* only implements KEY_SYSTEM */ 489*49ab747fSPaolo Bonzini 490*49ab747fSPaolo Bonzini if (key != KEY_SYSTEM) { 491*49ab747fSPaolo Bonzini printf("DBDMA: STORE_WORD, unimplemented key %x\n", key); 492*49ab747fSPaolo Bonzini kill_channel(ch); 493*49ab747fSPaolo Bonzini return; 494*49ab747fSPaolo Bonzini } 495*49ab747fSPaolo Bonzini 496*49ab747fSPaolo Bonzini val = current->cmd_dep; 497*49ab747fSPaolo Bonzini if (len == 2) 498*49ab747fSPaolo Bonzini val >>= 16; 499*49ab747fSPaolo Bonzini else if (len == 1) 500*49ab747fSPaolo Bonzini val >>= 24; 501*49ab747fSPaolo Bonzini 502*49ab747fSPaolo Bonzini cpu_physical_memory_write(addr, (uint8_t*)&val, len); 503*49ab747fSPaolo Bonzini 504*49ab747fSPaolo Bonzini if (conditional_wait(ch)) 505*49ab747fSPaolo Bonzini goto wait; 506*49ab747fSPaolo Bonzini 507*49ab747fSPaolo Bonzini current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]); 508*49ab747fSPaolo Bonzini dbdma_cmdptr_save(ch); 509*49ab747fSPaolo Bonzini ch->regs[DBDMA_STATUS] &= ~FLUSH; 510*49ab747fSPaolo Bonzini 511*49ab747fSPaolo Bonzini conditional_interrupt(ch); 512*49ab747fSPaolo Bonzini next(ch); 513*49ab747fSPaolo Bonzini 514*49ab747fSPaolo Bonzini wait: 515*49ab747fSPaolo Bonzini qemu_bh_schedule(dbdma_bh); 516*49ab747fSPaolo Bonzini } 517*49ab747fSPaolo Bonzini 518*49ab747fSPaolo Bonzini static void nop(DBDMA_channel *ch) 519*49ab747fSPaolo Bonzini { 520*49ab747fSPaolo Bonzini dbdma_cmd *current = &ch->current; 521*49ab747fSPaolo Bonzini 522*49ab747fSPaolo Bonzini if (conditional_wait(ch)) 523*49ab747fSPaolo Bonzini goto wait; 524*49ab747fSPaolo Bonzini 525*49ab747fSPaolo Bonzini current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]); 526*49ab747fSPaolo Bonzini dbdma_cmdptr_save(ch); 527*49ab747fSPaolo Bonzini 528*49ab747fSPaolo Bonzini conditional_interrupt(ch); 529*49ab747fSPaolo Bonzini conditional_branch(ch); 530*49ab747fSPaolo Bonzini 531*49ab747fSPaolo Bonzini wait: 532*49ab747fSPaolo Bonzini qemu_bh_schedule(dbdma_bh); 533*49ab747fSPaolo Bonzini } 534*49ab747fSPaolo Bonzini 535*49ab747fSPaolo Bonzini static void stop(DBDMA_channel *ch) 536*49ab747fSPaolo Bonzini { 537*49ab747fSPaolo Bonzini ch->regs[DBDMA_STATUS] &= ~(ACTIVE|DEAD|FLUSH); 538*49ab747fSPaolo Bonzini 539*49ab747fSPaolo Bonzini /* the stop command does not increment command pointer */ 540*49ab747fSPaolo Bonzini } 541*49ab747fSPaolo Bonzini 542*49ab747fSPaolo Bonzini static void channel_run(DBDMA_channel *ch) 543*49ab747fSPaolo Bonzini { 544*49ab747fSPaolo Bonzini dbdma_cmd *current = &ch->current; 545*49ab747fSPaolo Bonzini uint16_t cmd, key; 546*49ab747fSPaolo Bonzini uint16_t req_count; 547*49ab747fSPaolo Bonzini uint32_t phy_addr; 548*49ab747fSPaolo Bonzini 549*49ab747fSPaolo Bonzini DBDMA_DPRINTF("channel_run\n"); 550*49ab747fSPaolo Bonzini dump_dbdma_cmd(current); 551*49ab747fSPaolo Bonzini 552*49ab747fSPaolo Bonzini /* clear WAKE flag at command fetch */ 553*49ab747fSPaolo Bonzini 554*49ab747fSPaolo Bonzini ch->regs[DBDMA_STATUS] &= ~WAKE; 555*49ab747fSPaolo Bonzini 556*49ab747fSPaolo Bonzini cmd = le16_to_cpu(current->command) & COMMAND_MASK; 557*49ab747fSPaolo Bonzini 558*49ab747fSPaolo Bonzini switch (cmd) { 559*49ab747fSPaolo Bonzini case DBDMA_NOP: 560*49ab747fSPaolo Bonzini nop(ch); 561*49ab747fSPaolo Bonzini return; 562*49ab747fSPaolo Bonzini 563*49ab747fSPaolo Bonzini case DBDMA_STOP: 564*49ab747fSPaolo Bonzini stop(ch); 565*49ab747fSPaolo Bonzini return; 566*49ab747fSPaolo Bonzini } 567*49ab747fSPaolo Bonzini 568*49ab747fSPaolo Bonzini key = le16_to_cpu(current->command) & 0x0700; 569*49ab747fSPaolo Bonzini req_count = le16_to_cpu(current->req_count); 570*49ab747fSPaolo Bonzini phy_addr = le32_to_cpu(current->phy_addr); 571*49ab747fSPaolo Bonzini 572*49ab747fSPaolo Bonzini if (key == KEY_STREAM4) { 573*49ab747fSPaolo Bonzini printf("command %x, invalid key 4\n", cmd); 574*49ab747fSPaolo Bonzini kill_channel(ch); 575*49ab747fSPaolo Bonzini return; 576*49ab747fSPaolo Bonzini } 577*49ab747fSPaolo Bonzini 578*49ab747fSPaolo Bonzini switch (cmd) { 579*49ab747fSPaolo Bonzini case OUTPUT_MORE: 580*49ab747fSPaolo Bonzini start_output(ch, key, phy_addr, req_count, 0); 581*49ab747fSPaolo Bonzini return; 582*49ab747fSPaolo Bonzini 583*49ab747fSPaolo Bonzini case OUTPUT_LAST: 584*49ab747fSPaolo Bonzini start_output(ch, key, phy_addr, req_count, 1); 585*49ab747fSPaolo Bonzini return; 586*49ab747fSPaolo Bonzini 587*49ab747fSPaolo Bonzini case INPUT_MORE: 588*49ab747fSPaolo Bonzini start_input(ch, key, phy_addr, req_count, 0); 589*49ab747fSPaolo Bonzini return; 590*49ab747fSPaolo Bonzini 591*49ab747fSPaolo Bonzini case INPUT_LAST: 592*49ab747fSPaolo Bonzini start_input(ch, key, phy_addr, req_count, 1); 593*49ab747fSPaolo Bonzini return; 594*49ab747fSPaolo Bonzini } 595*49ab747fSPaolo Bonzini 596*49ab747fSPaolo Bonzini if (key < KEY_REGS) { 597*49ab747fSPaolo Bonzini printf("command %x, invalid key %x\n", cmd, key); 598*49ab747fSPaolo Bonzini key = KEY_SYSTEM; 599*49ab747fSPaolo Bonzini } 600*49ab747fSPaolo Bonzini 601*49ab747fSPaolo Bonzini /* for LOAD_WORD and STORE_WORD, req_count is on 3 bits 602*49ab747fSPaolo Bonzini * and BRANCH is invalid 603*49ab747fSPaolo Bonzini */ 604*49ab747fSPaolo Bonzini 605*49ab747fSPaolo Bonzini req_count = req_count & 0x0007; 606*49ab747fSPaolo Bonzini if (req_count & 0x4) { 607*49ab747fSPaolo Bonzini req_count = 4; 608*49ab747fSPaolo Bonzini phy_addr &= ~3; 609*49ab747fSPaolo Bonzini } else if (req_count & 0x2) { 610*49ab747fSPaolo Bonzini req_count = 2; 611*49ab747fSPaolo Bonzini phy_addr &= ~1; 612*49ab747fSPaolo Bonzini } else 613*49ab747fSPaolo Bonzini req_count = 1; 614*49ab747fSPaolo Bonzini 615*49ab747fSPaolo Bonzini switch (cmd) { 616*49ab747fSPaolo Bonzini case LOAD_WORD: 617*49ab747fSPaolo Bonzini load_word(ch, key, phy_addr, req_count); 618*49ab747fSPaolo Bonzini return; 619*49ab747fSPaolo Bonzini 620*49ab747fSPaolo Bonzini case STORE_WORD: 621*49ab747fSPaolo Bonzini store_word(ch, key, phy_addr, req_count); 622*49ab747fSPaolo Bonzini return; 623*49ab747fSPaolo Bonzini } 624*49ab747fSPaolo Bonzini } 625*49ab747fSPaolo Bonzini 626*49ab747fSPaolo Bonzini static void DBDMA_run(DBDMAState *s) 627*49ab747fSPaolo Bonzini { 628*49ab747fSPaolo Bonzini int channel; 629*49ab747fSPaolo Bonzini 630*49ab747fSPaolo Bonzini for (channel = 0; channel < DBDMA_CHANNELS; channel++) { 631*49ab747fSPaolo Bonzini DBDMA_channel *ch = &s->channels[channel]; 632*49ab747fSPaolo Bonzini uint32_t status = ch->regs[DBDMA_STATUS]; 633*49ab747fSPaolo Bonzini if (!ch->processing && (status & RUN) && (status & ACTIVE)) { 634*49ab747fSPaolo Bonzini channel_run(ch); 635*49ab747fSPaolo Bonzini } 636*49ab747fSPaolo Bonzini } 637*49ab747fSPaolo Bonzini } 638*49ab747fSPaolo Bonzini 639*49ab747fSPaolo Bonzini static void DBDMA_run_bh(void *opaque) 640*49ab747fSPaolo Bonzini { 641*49ab747fSPaolo Bonzini DBDMAState *s = opaque; 642*49ab747fSPaolo Bonzini 643*49ab747fSPaolo Bonzini DBDMA_DPRINTF("DBDMA_run_bh\n"); 644*49ab747fSPaolo Bonzini 645*49ab747fSPaolo Bonzini DBDMA_run(s); 646*49ab747fSPaolo Bonzini } 647*49ab747fSPaolo Bonzini 648*49ab747fSPaolo Bonzini void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq, 649*49ab747fSPaolo Bonzini DBDMA_rw rw, DBDMA_flush flush, 650*49ab747fSPaolo Bonzini void *opaque) 651*49ab747fSPaolo Bonzini { 652*49ab747fSPaolo Bonzini DBDMAState *s = dbdma; 653*49ab747fSPaolo Bonzini DBDMA_channel *ch = &s->channels[nchan]; 654*49ab747fSPaolo Bonzini 655*49ab747fSPaolo Bonzini DBDMA_DPRINTF("DBDMA_register_channel 0x%x\n", nchan); 656*49ab747fSPaolo Bonzini 657*49ab747fSPaolo Bonzini ch->irq = irq; 658*49ab747fSPaolo Bonzini ch->channel = nchan; 659*49ab747fSPaolo Bonzini ch->rw = rw; 660*49ab747fSPaolo Bonzini ch->flush = flush; 661*49ab747fSPaolo Bonzini ch->io.opaque = opaque; 662*49ab747fSPaolo Bonzini ch->io.channel = ch; 663*49ab747fSPaolo Bonzini } 664*49ab747fSPaolo Bonzini 665*49ab747fSPaolo Bonzini static void 666*49ab747fSPaolo Bonzini dbdma_control_write(DBDMA_channel *ch) 667*49ab747fSPaolo Bonzini { 668*49ab747fSPaolo Bonzini uint16_t mask, value; 669*49ab747fSPaolo Bonzini uint32_t status; 670*49ab747fSPaolo Bonzini 671*49ab747fSPaolo Bonzini mask = (ch->regs[DBDMA_CONTROL] >> 16) & 0xffff; 672*49ab747fSPaolo Bonzini value = ch->regs[DBDMA_CONTROL] & 0xffff; 673*49ab747fSPaolo Bonzini 674*49ab747fSPaolo Bonzini value &= (RUN | PAUSE | FLUSH | WAKE | DEVSTAT); 675*49ab747fSPaolo Bonzini 676*49ab747fSPaolo Bonzini status = ch->regs[DBDMA_STATUS]; 677*49ab747fSPaolo Bonzini 678*49ab747fSPaolo Bonzini status = (value & mask) | (status & ~mask); 679*49ab747fSPaolo Bonzini 680*49ab747fSPaolo Bonzini if (status & WAKE) 681*49ab747fSPaolo Bonzini status |= ACTIVE; 682*49ab747fSPaolo Bonzini if (status & RUN) { 683*49ab747fSPaolo Bonzini status |= ACTIVE; 684*49ab747fSPaolo Bonzini status &= ~DEAD; 685*49ab747fSPaolo Bonzini } 686*49ab747fSPaolo Bonzini if (status & PAUSE) 687*49ab747fSPaolo Bonzini status &= ~ACTIVE; 688*49ab747fSPaolo Bonzini if ((ch->regs[DBDMA_STATUS] & RUN) && !(status & RUN)) { 689*49ab747fSPaolo Bonzini /* RUN is cleared */ 690*49ab747fSPaolo Bonzini status &= ~(ACTIVE|DEAD); 691*49ab747fSPaolo Bonzini if ((status & FLUSH) && ch->flush) { 692*49ab747fSPaolo Bonzini ch->flush(&ch->io); 693*49ab747fSPaolo Bonzini status &= ~FLUSH; 694*49ab747fSPaolo Bonzini } 695*49ab747fSPaolo Bonzini } 696*49ab747fSPaolo Bonzini 697*49ab747fSPaolo Bonzini DBDMA_DPRINTF(" status 0x%08x\n", status); 698*49ab747fSPaolo Bonzini 699*49ab747fSPaolo Bonzini ch->regs[DBDMA_STATUS] = status; 700*49ab747fSPaolo Bonzini 701*49ab747fSPaolo Bonzini if (status & ACTIVE) 702*49ab747fSPaolo Bonzini qemu_bh_schedule(dbdma_bh); 703*49ab747fSPaolo Bonzini if ((status & FLUSH) && ch->flush) 704*49ab747fSPaolo Bonzini ch->flush(&ch->io); 705*49ab747fSPaolo Bonzini } 706*49ab747fSPaolo Bonzini 707*49ab747fSPaolo Bonzini static void dbdma_write(void *opaque, hwaddr addr, 708*49ab747fSPaolo Bonzini uint64_t value, unsigned size) 709*49ab747fSPaolo Bonzini { 710*49ab747fSPaolo Bonzini int channel = addr >> DBDMA_CHANNEL_SHIFT; 711*49ab747fSPaolo Bonzini DBDMAState *s = opaque; 712*49ab747fSPaolo Bonzini DBDMA_channel *ch = &s->channels[channel]; 713*49ab747fSPaolo Bonzini int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2; 714*49ab747fSPaolo Bonzini 715*49ab747fSPaolo Bonzini DBDMA_DPRINTF("writel 0x" TARGET_FMT_plx " <= 0x%08x\n", addr, value); 716*49ab747fSPaolo Bonzini DBDMA_DPRINTF("channel 0x%x reg 0x%x\n", 717*49ab747fSPaolo Bonzini (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg); 718*49ab747fSPaolo Bonzini 719*49ab747fSPaolo Bonzini /* cmdptr cannot be modified if channel is RUN or ACTIVE */ 720*49ab747fSPaolo Bonzini 721*49ab747fSPaolo Bonzini if (reg == DBDMA_CMDPTR_LO && 722*49ab747fSPaolo Bonzini (ch->regs[DBDMA_STATUS] & (RUN | ACTIVE))) 723*49ab747fSPaolo Bonzini return; 724*49ab747fSPaolo Bonzini 725*49ab747fSPaolo Bonzini ch->regs[reg] = value; 726*49ab747fSPaolo Bonzini 727*49ab747fSPaolo Bonzini switch(reg) { 728*49ab747fSPaolo Bonzini case DBDMA_CONTROL: 729*49ab747fSPaolo Bonzini dbdma_control_write(ch); 730*49ab747fSPaolo Bonzini break; 731*49ab747fSPaolo Bonzini case DBDMA_CMDPTR_LO: 732*49ab747fSPaolo Bonzini /* 16-byte aligned */ 733*49ab747fSPaolo Bonzini ch->regs[DBDMA_CMDPTR_LO] &= ~0xf; 734*49ab747fSPaolo Bonzini dbdma_cmdptr_load(ch); 735*49ab747fSPaolo Bonzini break; 736*49ab747fSPaolo Bonzini case DBDMA_STATUS: 737*49ab747fSPaolo Bonzini case DBDMA_INTR_SEL: 738*49ab747fSPaolo Bonzini case DBDMA_BRANCH_SEL: 739*49ab747fSPaolo Bonzini case DBDMA_WAIT_SEL: 740*49ab747fSPaolo Bonzini /* nothing to do */ 741*49ab747fSPaolo Bonzini break; 742*49ab747fSPaolo Bonzini case DBDMA_XFER_MODE: 743*49ab747fSPaolo Bonzini case DBDMA_CMDPTR_HI: 744*49ab747fSPaolo Bonzini case DBDMA_DATA2PTR_HI: 745*49ab747fSPaolo Bonzini case DBDMA_DATA2PTR_LO: 746*49ab747fSPaolo Bonzini case DBDMA_ADDRESS_HI: 747*49ab747fSPaolo Bonzini case DBDMA_BRANCH_ADDR_HI: 748*49ab747fSPaolo Bonzini case DBDMA_RES1: 749*49ab747fSPaolo Bonzini case DBDMA_RES2: 750*49ab747fSPaolo Bonzini case DBDMA_RES3: 751*49ab747fSPaolo Bonzini case DBDMA_RES4: 752*49ab747fSPaolo Bonzini /* unused */ 753*49ab747fSPaolo Bonzini break; 754*49ab747fSPaolo Bonzini } 755*49ab747fSPaolo Bonzini } 756*49ab747fSPaolo Bonzini 757*49ab747fSPaolo Bonzini static uint64_t dbdma_read(void *opaque, hwaddr addr, 758*49ab747fSPaolo Bonzini unsigned size) 759*49ab747fSPaolo Bonzini { 760*49ab747fSPaolo Bonzini uint32_t value; 761*49ab747fSPaolo Bonzini int channel = addr >> DBDMA_CHANNEL_SHIFT; 762*49ab747fSPaolo Bonzini DBDMAState *s = opaque; 763*49ab747fSPaolo Bonzini DBDMA_channel *ch = &s->channels[channel]; 764*49ab747fSPaolo Bonzini int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2; 765*49ab747fSPaolo Bonzini 766*49ab747fSPaolo Bonzini value = ch->regs[reg]; 767*49ab747fSPaolo Bonzini 768*49ab747fSPaolo Bonzini DBDMA_DPRINTF("readl 0x" TARGET_FMT_plx " => 0x%08x\n", addr, value); 769*49ab747fSPaolo Bonzini DBDMA_DPRINTF("channel 0x%x reg 0x%x\n", 770*49ab747fSPaolo Bonzini (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg); 771*49ab747fSPaolo Bonzini 772*49ab747fSPaolo Bonzini switch(reg) { 773*49ab747fSPaolo Bonzini case DBDMA_CONTROL: 774*49ab747fSPaolo Bonzini value = 0; 775*49ab747fSPaolo Bonzini break; 776*49ab747fSPaolo Bonzini case DBDMA_STATUS: 777*49ab747fSPaolo Bonzini case DBDMA_CMDPTR_LO: 778*49ab747fSPaolo Bonzini case DBDMA_INTR_SEL: 779*49ab747fSPaolo Bonzini case DBDMA_BRANCH_SEL: 780*49ab747fSPaolo Bonzini case DBDMA_WAIT_SEL: 781*49ab747fSPaolo Bonzini /* nothing to do */ 782*49ab747fSPaolo Bonzini break; 783*49ab747fSPaolo Bonzini case DBDMA_XFER_MODE: 784*49ab747fSPaolo Bonzini case DBDMA_CMDPTR_HI: 785*49ab747fSPaolo Bonzini case DBDMA_DATA2PTR_HI: 786*49ab747fSPaolo Bonzini case DBDMA_DATA2PTR_LO: 787*49ab747fSPaolo Bonzini case DBDMA_ADDRESS_HI: 788*49ab747fSPaolo Bonzini case DBDMA_BRANCH_ADDR_HI: 789*49ab747fSPaolo Bonzini /* unused */ 790*49ab747fSPaolo Bonzini value = 0; 791*49ab747fSPaolo Bonzini break; 792*49ab747fSPaolo Bonzini case DBDMA_RES1: 793*49ab747fSPaolo Bonzini case DBDMA_RES2: 794*49ab747fSPaolo Bonzini case DBDMA_RES3: 795*49ab747fSPaolo Bonzini case DBDMA_RES4: 796*49ab747fSPaolo Bonzini /* reserved */ 797*49ab747fSPaolo Bonzini break; 798*49ab747fSPaolo Bonzini } 799*49ab747fSPaolo Bonzini 800*49ab747fSPaolo Bonzini return value; 801*49ab747fSPaolo Bonzini } 802*49ab747fSPaolo Bonzini 803*49ab747fSPaolo Bonzini static const MemoryRegionOps dbdma_ops = { 804*49ab747fSPaolo Bonzini .read = dbdma_read, 805*49ab747fSPaolo Bonzini .write = dbdma_write, 806*49ab747fSPaolo Bonzini .endianness = DEVICE_LITTLE_ENDIAN, 807*49ab747fSPaolo Bonzini .valid = { 808*49ab747fSPaolo Bonzini .min_access_size = 4, 809*49ab747fSPaolo Bonzini .max_access_size = 4, 810*49ab747fSPaolo Bonzini }, 811*49ab747fSPaolo Bonzini }; 812*49ab747fSPaolo Bonzini 813*49ab747fSPaolo Bonzini static const VMStateDescription vmstate_dbdma_channel = { 814*49ab747fSPaolo Bonzini .name = "dbdma_channel", 815*49ab747fSPaolo Bonzini .version_id = 0, 816*49ab747fSPaolo Bonzini .minimum_version_id = 0, 817*49ab747fSPaolo Bonzini .minimum_version_id_old = 0, 818*49ab747fSPaolo Bonzini .fields = (VMStateField[]) { 819*49ab747fSPaolo Bonzini VMSTATE_UINT32_ARRAY(regs, struct DBDMA_channel, DBDMA_REGS), 820*49ab747fSPaolo Bonzini VMSTATE_END_OF_LIST() 821*49ab747fSPaolo Bonzini } 822*49ab747fSPaolo Bonzini }; 823*49ab747fSPaolo Bonzini 824*49ab747fSPaolo Bonzini static const VMStateDescription vmstate_dbdma = { 825*49ab747fSPaolo Bonzini .name = "dbdma", 826*49ab747fSPaolo Bonzini .version_id = 2, 827*49ab747fSPaolo Bonzini .minimum_version_id = 2, 828*49ab747fSPaolo Bonzini .minimum_version_id_old = 2, 829*49ab747fSPaolo Bonzini .fields = (VMStateField[]) { 830*49ab747fSPaolo Bonzini VMSTATE_STRUCT_ARRAY(channels, DBDMAState, DBDMA_CHANNELS, 1, 831*49ab747fSPaolo Bonzini vmstate_dbdma_channel, DBDMA_channel), 832*49ab747fSPaolo Bonzini VMSTATE_END_OF_LIST() 833*49ab747fSPaolo Bonzini } 834*49ab747fSPaolo Bonzini }; 835*49ab747fSPaolo Bonzini 836*49ab747fSPaolo Bonzini static void dbdma_reset(void *opaque) 837*49ab747fSPaolo Bonzini { 838*49ab747fSPaolo Bonzini DBDMAState *s = opaque; 839*49ab747fSPaolo Bonzini int i; 840*49ab747fSPaolo Bonzini 841*49ab747fSPaolo Bonzini for (i = 0; i < DBDMA_CHANNELS; i++) 842*49ab747fSPaolo Bonzini memset(s->channels[i].regs, 0, DBDMA_SIZE); 843*49ab747fSPaolo Bonzini } 844*49ab747fSPaolo Bonzini 845*49ab747fSPaolo Bonzini void* DBDMA_init (MemoryRegion **dbdma_mem) 846*49ab747fSPaolo Bonzini { 847*49ab747fSPaolo Bonzini DBDMAState *s; 848*49ab747fSPaolo Bonzini 849*49ab747fSPaolo Bonzini s = g_malloc0(sizeof(DBDMAState)); 850*49ab747fSPaolo Bonzini 851*49ab747fSPaolo Bonzini memory_region_init_io(&s->mem, &dbdma_ops, s, "dbdma", 0x1000); 852*49ab747fSPaolo Bonzini *dbdma_mem = &s->mem; 853*49ab747fSPaolo Bonzini vmstate_register(NULL, -1, &vmstate_dbdma, s); 854*49ab747fSPaolo Bonzini qemu_register_reset(dbdma_reset, s); 855*49ab747fSPaolo Bonzini 856*49ab747fSPaolo Bonzini dbdma_bh = qemu_bh_new(DBDMA_run_bh, s); 857*49ab747fSPaolo Bonzini 858*49ab747fSPaolo Bonzini return s; 859*49ab747fSPaolo Bonzini } 860