13cbee15bSj_mayer /* 23cbee15bSj_mayer * PowerMac descriptor-based DMA emulation 33cbee15bSj_mayer * 43cbee15bSj_mayer * Copyright (c) 2005-2007 Fabrice Bellard 53cbee15bSj_mayer * Copyright (c) 2007 Jocelyn Mayer 628ce5ce6Saurel32 * Copyright (c) 2009 Laurent Vivier 728ce5ce6Saurel32 * 828ce5ce6Saurel32 * some parts from linux-2.6.28, arch/powerpc/include/asm/dbdma.h 928ce5ce6Saurel32 * 1028ce5ce6Saurel32 * Definitions for using the Apple Descriptor-Based DMA controller 1128ce5ce6Saurel32 * in Power Macintosh computers. 1228ce5ce6Saurel32 * 1328ce5ce6Saurel32 * Copyright (C) 1996 Paul Mackerras. 1428ce5ce6Saurel32 * 1528ce5ce6Saurel32 * some parts from mol 0.9.71 1628ce5ce6Saurel32 * 1728ce5ce6Saurel32 * Descriptor based DMA emulation 1828ce5ce6Saurel32 * 1928ce5ce6Saurel32 * Copyright (C) 1998-2004 Samuel Rydh (samuel@ibrium.se) 203cbee15bSj_mayer * 213cbee15bSj_mayer * Permission is hereby granted, free of charge, to any person obtaining a copy 223cbee15bSj_mayer * of this software and associated documentation files (the "Software"), to deal 233cbee15bSj_mayer * in the Software without restriction, including without limitation the rights 243cbee15bSj_mayer * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 253cbee15bSj_mayer * copies of the Software, and to permit persons to whom the Software is 263cbee15bSj_mayer * furnished to do so, subject to the following conditions: 273cbee15bSj_mayer * 283cbee15bSj_mayer * The above copyright notice and this permission notice shall be included in 293cbee15bSj_mayer * all copies or substantial portions of the Software. 303cbee15bSj_mayer * 313cbee15bSj_mayer * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 323cbee15bSj_mayer * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 333cbee15bSj_mayer * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 343cbee15bSj_mayer * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 353cbee15bSj_mayer * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 363cbee15bSj_mayer * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 373cbee15bSj_mayer * THE SOFTWARE. 383cbee15bSj_mayer */ 3983c9f4caSPaolo Bonzini #include "hw/hw.h" 400d09e41aSPaolo Bonzini #include "hw/isa/isa.h" 410d09e41aSPaolo Bonzini #include "hw/ppc/mac_dbdma.h" 421de7afc9SPaolo Bonzini #include "qemu/main-loop.h" 433cbee15bSj_mayer 44ea026b2fSblueswir1 /* debug DBDMA */ 45ea026b2fSblueswir1 //#define DEBUG_DBDMA 46ea026b2fSblueswir1 47ea026b2fSblueswir1 #ifdef DEBUG_DBDMA 48001faf32SBlue Swirl #define DBDMA_DPRINTF(fmt, ...) \ 49001faf32SBlue Swirl do { printf("DBDMA: " fmt , ## __VA_ARGS__); } while (0) 50ea026b2fSblueswir1 #else 51001faf32SBlue Swirl #define DBDMA_DPRINTF(fmt, ...) 52ea026b2fSblueswir1 #endif 53ea026b2fSblueswir1 5428ce5ce6Saurel32 /* 5528ce5ce6Saurel32 */ 563cbee15bSj_mayer 5728ce5ce6Saurel32 /* 5828ce5ce6Saurel32 * DBDMA control/status registers. All little-endian. 5928ce5ce6Saurel32 */ 6028ce5ce6Saurel32 6128ce5ce6Saurel32 #define DBDMA_CONTROL 0x00 6228ce5ce6Saurel32 #define DBDMA_STATUS 0x01 6328ce5ce6Saurel32 #define DBDMA_CMDPTR_HI 0x02 6428ce5ce6Saurel32 #define DBDMA_CMDPTR_LO 0x03 6528ce5ce6Saurel32 #define DBDMA_INTR_SEL 0x04 6628ce5ce6Saurel32 #define DBDMA_BRANCH_SEL 0x05 6728ce5ce6Saurel32 #define DBDMA_WAIT_SEL 0x06 6828ce5ce6Saurel32 #define DBDMA_XFER_MODE 0x07 6928ce5ce6Saurel32 #define DBDMA_DATA2PTR_HI 0x08 7028ce5ce6Saurel32 #define DBDMA_DATA2PTR_LO 0x09 7128ce5ce6Saurel32 #define DBDMA_RES1 0x0A 7228ce5ce6Saurel32 #define DBDMA_ADDRESS_HI 0x0B 7328ce5ce6Saurel32 #define DBDMA_BRANCH_ADDR_HI 0x0C 7428ce5ce6Saurel32 #define DBDMA_RES2 0x0D 7528ce5ce6Saurel32 #define DBDMA_RES3 0x0E 7628ce5ce6Saurel32 #define DBDMA_RES4 0x0F 7728ce5ce6Saurel32 7828ce5ce6Saurel32 #define DBDMA_REGS 16 7928ce5ce6Saurel32 #define DBDMA_SIZE (DBDMA_REGS * sizeof(uint32_t)) 8028ce5ce6Saurel32 8128ce5ce6Saurel32 #define DBDMA_CHANNEL_SHIFT 7 8228ce5ce6Saurel32 #define DBDMA_CHANNEL_SIZE (1 << DBDMA_CHANNEL_SHIFT) 8328ce5ce6Saurel32 8428ce5ce6Saurel32 #define DBDMA_CHANNELS (0x1000 >> DBDMA_CHANNEL_SHIFT) 8528ce5ce6Saurel32 8628ce5ce6Saurel32 /* Bits in control and status registers */ 8728ce5ce6Saurel32 8828ce5ce6Saurel32 #define RUN 0x8000 8928ce5ce6Saurel32 #define PAUSE 0x4000 9028ce5ce6Saurel32 #define FLUSH 0x2000 9128ce5ce6Saurel32 #define WAKE 0x1000 9228ce5ce6Saurel32 #define DEAD 0x0800 9328ce5ce6Saurel32 #define ACTIVE 0x0400 9428ce5ce6Saurel32 #define BT 0x0100 9528ce5ce6Saurel32 #define DEVSTAT 0x00ff 9628ce5ce6Saurel32 9728ce5ce6Saurel32 /* 9828ce5ce6Saurel32 * DBDMA command structure. These fields are all little-endian! 9928ce5ce6Saurel32 */ 10028ce5ce6Saurel32 10128ce5ce6Saurel32 typedef struct dbdma_cmd { 10228ce5ce6Saurel32 uint16_t req_count; /* requested byte transfer count */ 10328ce5ce6Saurel32 uint16_t command; /* command word (has bit-fields) */ 10428ce5ce6Saurel32 uint32_t phy_addr; /* physical data address */ 10528ce5ce6Saurel32 uint32_t cmd_dep; /* command-dependent field */ 10628ce5ce6Saurel32 uint16_t res_count; /* residual count after completion */ 10728ce5ce6Saurel32 uint16_t xfer_status; /* transfer status */ 10828ce5ce6Saurel32 } dbdma_cmd; 10928ce5ce6Saurel32 11028ce5ce6Saurel32 /* DBDMA command values in command field */ 11128ce5ce6Saurel32 11228ce5ce6Saurel32 #define COMMAND_MASK 0xf000 11328ce5ce6Saurel32 #define OUTPUT_MORE 0x0000 /* transfer memory data to stream */ 11428ce5ce6Saurel32 #define OUTPUT_LAST 0x1000 /* ditto followed by end marker */ 11528ce5ce6Saurel32 #define INPUT_MORE 0x2000 /* transfer stream data to memory */ 11628ce5ce6Saurel32 #define INPUT_LAST 0x3000 /* ditto, expect end marker */ 11728ce5ce6Saurel32 #define STORE_WORD 0x4000 /* write word (4 bytes) to device reg */ 11828ce5ce6Saurel32 #define LOAD_WORD 0x5000 /* read word (4 bytes) from device reg */ 11928ce5ce6Saurel32 #define DBDMA_NOP 0x6000 /* do nothing */ 12028ce5ce6Saurel32 #define DBDMA_STOP 0x7000 /* suspend processing */ 12128ce5ce6Saurel32 12228ce5ce6Saurel32 /* Key values in command field */ 12328ce5ce6Saurel32 12428ce5ce6Saurel32 #define KEY_MASK 0x0700 12528ce5ce6Saurel32 #define KEY_STREAM0 0x0000 /* usual data stream */ 12628ce5ce6Saurel32 #define KEY_STREAM1 0x0100 /* control/status stream */ 12728ce5ce6Saurel32 #define KEY_STREAM2 0x0200 /* device-dependent stream */ 12828ce5ce6Saurel32 #define KEY_STREAM3 0x0300 /* device-dependent stream */ 12928ce5ce6Saurel32 #define KEY_STREAM4 0x0400 /* reserved */ 13028ce5ce6Saurel32 #define KEY_REGS 0x0500 /* device register space */ 13128ce5ce6Saurel32 #define KEY_SYSTEM 0x0600 /* system memory-mapped space */ 13228ce5ce6Saurel32 #define KEY_DEVICE 0x0700 /* device memory-mapped space */ 13328ce5ce6Saurel32 13428ce5ce6Saurel32 /* Interrupt control values in command field */ 13528ce5ce6Saurel32 13628ce5ce6Saurel32 #define INTR_MASK 0x0030 13728ce5ce6Saurel32 #define INTR_NEVER 0x0000 /* don't interrupt */ 13828ce5ce6Saurel32 #define INTR_IFSET 0x0010 /* intr if condition bit is 1 */ 13928ce5ce6Saurel32 #define INTR_IFCLR 0x0020 /* intr if condition bit is 0 */ 14028ce5ce6Saurel32 #define INTR_ALWAYS 0x0030 /* always interrupt */ 14128ce5ce6Saurel32 14228ce5ce6Saurel32 /* Branch control values in command field */ 14328ce5ce6Saurel32 14428ce5ce6Saurel32 #define BR_MASK 0x000c 14528ce5ce6Saurel32 #define BR_NEVER 0x0000 /* don't branch */ 14628ce5ce6Saurel32 #define BR_IFSET 0x0004 /* branch if condition bit is 1 */ 14728ce5ce6Saurel32 #define BR_IFCLR 0x0008 /* branch if condition bit is 0 */ 14828ce5ce6Saurel32 #define BR_ALWAYS 0x000c /* always branch */ 14928ce5ce6Saurel32 15028ce5ce6Saurel32 /* Wait control values in command field */ 15128ce5ce6Saurel32 15228ce5ce6Saurel32 #define WAIT_MASK 0x0003 15328ce5ce6Saurel32 #define WAIT_NEVER 0x0000 /* don't wait */ 15428ce5ce6Saurel32 #define WAIT_IFSET 0x0001 /* wait if condition bit is 1 */ 15528ce5ce6Saurel32 #define WAIT_IFCLR 0x0002 /* wait if condition bit is 0 */ 15628ce5ce6Saurel32 #define WAIT_ALWAYS 0x0003 /* always wait */ 15728ce5ce6Saurel32 15828ce5ce6Saurel32 typedef struct DBDMA_channel { 15928ce5ce6Saurel32 int channel; 16028ce5ce6Saurel32 uint32_t regs[DBDMA_REGS]; 16128ce5ce6Saurel32 qemu_irq irq; 162b42ec42dSaurel32 DBDMA_io io; 163b42ec42dSaurel32 DBDMA_rw rw; 164862c9280Saurel32 DBDMA_flush flush; 16528ce5ce6Saurel32 dbdma_cmd current; 166b42ec42dSaurel32 int processing; 16728ce5ce6Saurel32 } DBDMA_channel; 16828ce5ce6Saurel32 169c20df14bSJuan Quintela typedef struct { 17023c5e4caSAvi Kivity MemoryRegion mem; 171c20df14bSJuan Quintela DBDMA_channel channels[DBDMA_CHANNELS]; 172c20df14bSJuan Quintela } DBDMAState; 173c20df14bSJuan Quintela 17428ce5ce6Saurel32 #ifdef DEBUG_DBDMA 17528ce5ce6Saurel32 static void dump_dbdma_cmd(dbdma_cmd *cmd) 1763cbee15bSj_mayer { 17728ce5ce6Saurel32 printf("dbdma_cmd %p\n", cmd); 17828ce5ce6Saurel32 printf(" req_count 0x%04x\n", le16_to_cpu(cmd->req_count)); 17928ce5ce6Saurel32 printf(" command 0x%04x\n", le16_to_cpu(cmd->command)); 18028ce5ce6Saurel32 printf(" phy_addr 0x%08x\n", le32_to_cpu(cmd->phy_addr)); 18128ce5ce6Saurel32 printf(" cmd_dep 0x%08x\n", le32_to_cpu(cmd->cmd_dep)); 18228ce5ce6Saurel32 printf(" res_count 0x%04x\n", le16_to_cpu(cmd->res_count)); 18328ce5ce6Saurel32 printf(" xfer_status 0x%04x\n", le16_to_cpu(cmd->xfer_status)); 18428ce5ce6Saurel32 } 18528ce5ce6Saurel32 #else 18628ce5ce6Saurel32 static void dump_dbdma_cmd(dbdma_cmd *cmd) 18728ce5ce6Saurel32 { 18828ce5ce6Saurel32 } 18928ce5ce6Saurel32 #endif 19028ce5ce6Saurel32 static void dbdma_cmdptr_load(DBDMA_channel *ch) 19128ce5ce6Saurel32 { 19228ce5ce6Saurel32 DBDMA_DPRINTF("dbdma_cmdptr_load 0x%08x\n", 193ad674e53SAurelien Jarno ch->regs[DBDMA_CMDPTR_LO]); 194ad674e53SAurelien Jarno cpu_physical_memory_read(ch->regs[DBDMA_CMDPTR_LO], 195e1fe50dcSStefan Weil &ch->current, sizeof(dbdma_cmd)); 1963cbee15bSj_mayer } 1973cbee15bSj_mayer 19828ce5ce6Saurel32 static void dbdma_cmdptr_save(DBDMA_channel *ch) 1993cbee15bSj_mayer { 20028ce5ce6Saurel32 DBDMA_DPRINTF("dbdma_cmdptr_save 0x%08x\n", 201ad674e53SAurelien Jarno ch->regs[DBDMA_CMDPTR_LO]); 20228ce5ce6Saurel32 DBDMA_DPRINTF("xfer_status 0x%08x res_count 0x%04x\n", 20328ce5ce6Saurel32 le16_to_cpu(ch->current.xfer_status), 20428ce5ce6Saurel32 le16_to_cpu(ch->current.res_count)); 205ad674e53SAurelien Jarno cpu_physical_memory_write(ch->regs[DBDMA_CMDPTR_LO], 206e1fe50dcSStefan Weil &ch->current, sizeof(dbdma_cmd)); 20728ce5ce6Saurel32 } 20828ce5ce6Saurel32 20928ce5ce6Saurel32 static void kill_channel(DBDMA_channel *ch) 21028ce5ce6Saurel32 { 21128ce5ce6Saurel32 DBDMA_DPRINTF("kill_channel\n"); 21228ce5ce6Saurel32 213ad674e53SAurelien Jarno ch->regs[DBDMA_STATUS] |= DEAD; 214ad674e53SAurelien Jarno ch->regs[DBDMA_STATUS] &= ~ACTIVE; 21528ce5ce6Saurel32 21628ce5ce6Saurel32 qemu_irq_raise(ch->irq); 21728ce5ce6Saurel32 } 21828ce5ce6Saurel32 21928ce5ce6Saurel32 static void conditional_interrupt(DBDMA_channel *ch) 22028ce5ce6Saurel32 { 22128ce5ce6Saurel32 dbdma_cmd *current = &ch->current; 22228ce5ce6Saurel32 uint16_t intr; 22328ce5ce6Saurel32 uint16_t sel_mask, sel_value; 22428ce5ce6Saurel32 uint32_t status; 22528ce5ce6Saurel32 int cond; 22628ce5ce6Saurel32 22733ce36bbSAlexander Graf DBDMA_DPRINTF("%s\n", __func__); 22828ce5ce6Saurel32 229b42ec42dSaurel32 intr = le16_to_cpu(current->command) & INTR_MASK; 23028ce5ce6Saurel32 23128ce5ce6Saurel32 switch(intr) { 23228ce5ce6Saurel32 case INTR_NEVER: /* don't interrupt */ 23328ce5ce6Saurel32 return; 23428ce5ce6Saurel32 case INTR_ALWAYS: /* always interrupt */ 23528ce5ce6Saurel32 qemu_irq_raise(ch->irq); 23633ce36bbSAlexander Graf DBDMA_DPRINTF("%s: raise\n", __func__); 23728ce5ce6Saurel32 return; 23828ce5ce6Saurel32 } 23928ce5ce6Saurel32 240ad674e53SAurelien Jarno status = ch->regs[DBDMA_STATUS] & DEVSTAT; 24128ce5ce6Saurel32 242ad674e53SAurelien Jarno sel_mask = (ch->regs[DBDMA_INTR_SEL] >> 16) & 0x0f; 243ad674e53SAurelien Jarno sel_value = ch->regs[DBDMA_INTR_SEL] & 0x0f; 24428ce5ce6Saurel32 24528ce5ce6Saurel32 cond = (status & sel_mask) == (sel_value & sel_mask); 24628ce5ce6Saurel32 24728ce5ce6Saurel32 switch(intr) { 24828ce5ce6Saurel32 case INTR_IFSET: /* intr if condition bit is 1 */ 24933ce36bbSAlexander Graf if (cond) { 25028ce5ce6Saurel32 qemu_irq_raise(ch->irq); 25133ce36bbSAlexander Graf DBDMA_DPRINTF("%s: raise\n", __func__); 25233ce36bbSAlexander Graf } 25328ce5ce6Saurel32 return; 25428ce5ce6Saurel32 case INTR_IFCLR: /* intr if condition bit is 0 */ 25533ce36bbSAlexander Graf if (!cond) { 25628ce5ce6Saurel32 qemu_irq_raise(ch->irq); 25733ce36bbSAlexander Graf DBDMA_DPRINTF("%s: raise\n", __func__); 25833ce36bbSAlexander Graf } 25928ce5ce6Saurel32 return; 26028ce5ce6Saurel32 } 26128ce5ce6Saurel32 } 26228ce5ce6Saurel32 26328ce5ce6Saurel32 static int conditional_wait(DBDMA_channel *ch) 26428ce5ce6Saurel32 { 26528ce5ce6Saurel32 dbdma_cmd *current = &ch->current; 26628ce5ce6Saurel32 uint16_t wait; 26728ce5ce6Saurel32 uint16_t sel_mask, sel_value; 26828ce5ce6Saurel32 uint32_t status; 26928ce5ce6Saurel32 int cond; 27028ce5ce6Saurel32 27128ce5ce6Saurel32 DBDMA_DPRINTF("conditional_wait\n"); 27228ce5ce6Saurel32 273b42ec42dSaurel32 wait = le16_to_cpu(current->command) & WAIT_MASK; 27428ce5ce6Saurel32 27528ce5ce6Saurel32 switch(wait) { 27628ce5ce6Saurel32 case WAIT_NEVER: /* don't wait */ 27728ce5ce6Saurel32 return 0; 27828ce5ce6Saurel32 case WAIT_ALWAYS: /* always wait */ 27928ce5ce6Saurel32 return 1; 28028ce5ce6Saurel32 } 28128ce5ce6Saurel32 282ad674e53SAurelien Jarno status = ch->regs[DBDMA_STATUS] & DEVSTAT; 28328ce5ce6Saurel32 284ad674e53SAurelien Jarno sel_mask = (ch->regs[DBDMA_WAIT_SEL] >> 16) & 0x0f; 285ad674e53SAurelien Jarno sel_value = ch->regs[DBDMA_WAIT_SEL] & 0x0f; 28628ce5ce6Saurel32 28728ce5ce6Saurel32 cond = (status & sel_mask) == (sel_value & sel_mask); 28828ce5ce6Saurel32 28928ce5ce6Saurel32 switch(wait) { 29028ce5ce6Saurel32 case WAIT_IFSET: /* wait if condition bit is 1 */ 29128ce5ce6Saurel32 if (cond) 29228ce5ce6Saurel32 return 1; 29328ce5ce6Saurel32 return 0; 29428ce5ce6Saurel32 case WAIT_IFCLR: /* wait if condition bit is 0 */ 29528ce5ce6Saurel32 if (!cond) 29628ce5ce6Saurel32 return 1; 29728ce5ce6Saurel32 return 0; 29828ce5ce6Saurel32 } 29928ce5ce6Saurel32 return 0; 30028ce5ce6Saurel32 } 30128ce5ce6Saurel32 30228ce5ce6Saurel32 static void next(DBDMA_channel *ch) 30328ce5ce6Saurel32 { 30428ce5ce6Saurel32 uint32_t cp; 30528ce5ce6Saurel32 306ad674e53SAurelien Jarno ch->regs[DBDMA_STATUS] &= ~BT; 30728ce5ce6Saurel32 308ad674e53SAurelien Jarno cp = ch->regs[DBDMA_CMDPTR_LO]; 309ad674e53SAurelien Jarno ch->regs[DBDMA_CMDPTR_LO] = cp + sizeof(dbdma_cmd); 31028ce5ce6Saurel32 dbdma_cmdptr_load(ch); 31128ce5ce6Saurel32 } 31228ce5ce6Saurel32 31328ce5ce6Saurel32 static void branch(DBDMA_channel *ch) 31428ce5ce6Saurel32 { 31528ce5ce6Saurel32 dbdma_cmd *current = &ch->current; 31628ce5ce6Saurel32 31728ce5ce6Saurel32 ch->regs[DBDMA_CMDPTR_LO] = current->cmd_dep; 318ad674e53SAurelien Jarno ch->regs[DBDMA_STATUS] |= BT; 31928ce5ce6Saurel32 dbdma_cmdptr_load(ch); 32028ce5ce6Saurel32 } 32128ce5ce6Saurel32 32228ce5ce6Saurel32 static void conditional_branch(DBDMA_channel *ch) 32328ce5ce6Saurel32 { 32428ce5ce6Saurel32 dbdma_cmd *current = &ch->current; 32528ce5ce6Saurel32 uint16_t br; 32628ce5ce6Saurel32 uint16_t sel_mask, sel_value; 32728ce5ce6Saurel32 uint32_t status; 32828ce5ce6Saurel32 int cond; 32928ce5ce6Saurel32 33028ce5ce6Saurel32 DBDMA_DPRINTF("conditional_branch\n"); 33128ce5ce6Saurel32 33228ce5ce6Saurel32 /* check if we must branch */ 33328ce5ce6Saurel32 334b42ec42dSaurel32 br = le16_to_cpu(current->command) & BR_MASK; 33528ce5ce6Saurel32 33628ce5ce6Saurel32 switch(br) { 33728ce5ce6Saurel32 case BR_NEVER: /* don't branch */ 33828ce5ce6Saurel32 next(ch); 33928ce5ce6Saurel32 return; 34028ce5ce6Saurel32 case BR_ALWAYS: /* always branch */ 34128ce5ce6Saurel32 branch(ch); 34228ce5ce6Saurel32 return; 34328ce5ce6Saurel32 } 34428ce5ce6Saurel32 345ad674e53SAurelien Jarno status = ch->regs[DBDMA_STATUS] & DEVSTAT; 34628ce5ce6Saurel32 347ad674e53SAurelien Jarno sel_mask = (ch->regs[DBDMA_BRANCH_SEL] >> 16) & 0x0f; 348ad674e53SAurelien Jarno sel_value = ch->regs[DBDMA_BRANCH_SEL] & 0x0f; 34928ce5ce6Saurel32 35028ce5ce6Saurel32 cond = (status & sel_mask) == (sel_value & sel_mask); 35128ce5ce6Saurel32 35228ce5ce6Saurel32 switch(br) { 35328ce5ce6Saurel32 case BR_IFSET: /* branch if condition bit is 1 */ 35428ce5ce6Saurel32 if (cond) 35528ce5ce6Saurel32 branch(ch); 35628ce5ce6Saurel32 else 35728ce5ce6Saurel32 next(ch); 35828ce5ce6Saurel32 return; 35928ce5ce6Saurel32 case BR_IFCLR: /* branch if condition bit is 0 */ 36028ce5ce6Saurel32 if (!cond) 36128ce5ce6Saurel32 branch(ch); 36228ce5ce6Saurel32 else 36328ce5ce6Saurel32 next(ch); 36428ce5ce6Saurel32 return; 36528ce5ce6Saurel32 } 36628ce5ce6Saurel32 } 36728ce5ce6Saurel32 368b42ec42dSaurel32 static QEMUBH *dbdma_bh; 369b42ec42dSaurel32 static void channel_run(DBDMA_channel *ch); 370b42ec42dSaurel32 371b42ec42dSaurel32 static void dbdma_end(DBDMA_io *io) 37228ce5ce6Saurel32 { 37328ce5ce6Saurel32 DBDMA_channel *ch = io->channel; 37428ce5ce6Saurel32 dbdma_cmd *current = &ch->current; 37528ce5ce6Saurel32 37633ce36bbSAlexander Graf DBDMA_DPRINTF("%s\n", __func__); 37733ce36bbSAlexander Graf 378b42ec42dSaurel32 if (conditional_wait(ch)) 379b42ec42dSaurel32 goto wait; 38028ce5ce6Saurel32 381ad674e53SAurelien Jarno current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]); 382ad674e53SAurelien Jarno current->res_count = cpu_to_le16(io->len); 383b42ec42dSaurel32 dbdma_cmdptr_save(ch); 384862c9280Saurel32 if (io->is_last) 385ad674e53SAurelien Jarno ch->regs[DBDMA_STATUS] &= ~FLUSH; 38628ce5ce6Saurel32 387b42ec42dSaurel32 conditional_interrupt(ch); 388b42ec42dSaurel32 conditional_branch(ch); 389b42ec42dSaurel32 390b42ec42dSaurel32 wait: 391b42ec42dSaurel32 ch->processing = 0; 392ad674e53SAurelien Jarno if ((ch->regs[DBDMA_STATUS] & RUN) && 393ad674e53SAurelien Jarno (ch->regs[DBDMA_STATUS] & ACTIVE)) 394b42ec42dSaurel32 channel_run(ch); 39528ce5ce6Saurel32 } 39628ce5ce6Saurel32 397b42ec42dSaurel32 static void start_output(DBDMA_channel *ch, int key, uint32_t addr, 39828ce5ce6Saurel32 uint16_t req_count, int is_last) 39928ce5ce6Saurel32 { 40028ce5ce6Saurel32 DBDMA_DPRINTF("start_output\n"); 40128ce5ce6Saurel32 40228ce5ce6Saurel32 /* KEY_REGS, KEY_DEVICE and KEY_STREAM 40328ce5ce6Saurel32 * are not implemented in the mac-io chip 40428ce5ce6Saurel32 */ 40528ce5ce6Saurel32 40628ce5ce6Saurel32 DBDMA_DPRINTF("addr 0x%x key 0x%x\n", addr, key); 40728ce5ce6Saurel32 if (!addr || key > KEY_STREAM3) { 40828ce5ce6Saurel32 kill_channel(ch); 409b42ec42dSaurel32 return; 41028ce5ce6Saurel32 } 41128ce5ce6Saurel32 412b42ec42dSaurel32 ch->io.addr = addr; 41328ce5ce6Saurel32 ch->io.len = req_count; 41428ce5ce6Saurel32 ch->io.is_last = is_last; 415b42ec42dSaurel32 ch->io.dma_end = dbdma_end; 416b42ec42dSaurel32 ch->io.is_dma_out = 1; 417b42ec42dSaurel32 ch->processing = 1; 418a9ceb76dSAlexander Graf if (ch->rw) { 419b42ec42dSaurel32 ch->rw(&ch->io); 42028ce5ce6Saurel32 } 421a9ceb76dSAlexander Graf } 42228ce5ce6Saurel32 423b42ec42dSaurel32 static void start_input(DBDMA_channel *ch, int key, uint32_t addr, 42428ce5ce6Saurel32 uint16_t req_count, int is_last) 42528ce5ce6Saurel32 { 42628ce5ce6Saurel32 DBDMA_DPRINTF("start_input\n"); 42728ce5ce6Saurel32 42828ce5ce6Saurel32 /* KEY_REGS, KEY_DEVICE and KEY_STREAM 42928ce5ce6Saurel32 * are not implemented in the mac-io chip 43028ce5ce6Saurel32 */ 43128ce5ce6Saurel32 43233ce36bbSAlexander Graf DBDMA_DPRINTF("addr 0x%x key 0x%x\n", addr, key); 43328ce5ce6Saurel32 if (!addr || key > KEY_STREAM3) { 43428ce5ce6Saurel32 kill_channel(ch); 435b42ec42dSaurel32 return; 43628ce5ce6Saurel32 } 43728ce5ce6Saurel32 438b42ec42dSaurel32 ch->io.addr = addr; 43928ce5ce6Saurel32 ch->io.len = req_count; 44028ce5ce6Saurel32 ch->io.is_last = is_last; 441b42ec42dSaurel32 ch->io.dma_end = dbdma_end; 442b42ec42dSaurel32 ch->io.is_dma_out = 0; 443b42ec42dSaurel32 ch->processing = 1; 444a9ceb76dSAlexander Graf if (ch->rw) { 445b42ec42dSaurel32 ch->rw(&ch->io); 44628ce5ce6Saurel32 } 447a9ceb76dSAlexander Graf } 44828ce5ce6Saurel32 449b42ec42dSaurel32 static void load_word(DBDMA_channel *ch, int key, uint32_t addr, 45028ce5ce6Saurel32 uint16_t len) 45128ce5ce6Saurel32 { 45228ce5ce6Saurel32 dbdma_cmd *current = &ch->current; 45328ce5ce6Saurel32 uint32_t val; 45428ce5ce6Saurel32 45528ce5ce6Saurel32 DBDMA_DPRINTF("load_word\n"); 45628ce5ce6Saurel32 45728ce5ce6Saurel32 /* only implements KEY_SYSTEM */ 45828ce5ce6Saurel32 45928ce5ce6Saurel32 if (key != KEY_SYSTEM) { 46028ce5ce6Saurel32 printf("DBDMA: LOAD_WORD, unimplemented key %x\n", key); 46128ce5ce6Saurel32 kill_channel(ch); 462b42ec42dSaurel32 return; 46328ce5ce6Saurel32 } 46428ce5ce6Saurel32 465e1fe50dcSStefan Weil cpu_physical_memory_read(addr, &val, len); 46628ce5ce6Saurel32 46728ce5ce6Saurel32 if (len == 2) 46828ce5ce6Saurel32 val = (val << 16) | (current->cmd_dep & 0x0000ffff); 46928ce5ce6Saurel32 else if (len == 1) 47028ce5ce6Saurel32 val = (val << 24) | (current->cmd_dep & 0x00ffffff); 47128ce5ce6Saurel32 47228ce5ce6Saurel32 current->cmd_dep = val; 47328ce5ce6Saurel32 47428ce5ce6Saurel32 if (conditional_wait(ch)) 475b42ec42dSaurel32 goto wait; 47628ce5ce6Saurel32 477ad674e53SAurelien Jarno current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]); 47828ce5ce6Saurel32 dbdma_cmdptr_save(ch); 479ad674e53SAurelien Jarno ch->regs[DBDMA_STATUS] &= ~FLUSH; 48028ce5ce6Saurel32 48128ce5ce6Saurel32 conditional_interrupt(ch); 48228ce5ce6Saurel32 next(ch); 48328ce5ce6Saurel32 484b42ec42dSaurel32 wait: 485b42ec42dSaurel32 qemu_bh_schedule(dbdma_bh); 48628ce5ce6Saurel32 } 48728ce5ce6Saurel32 488b42ec42dSaurel32 static void store_word(DBDMA_channel *ch, int key, uint32_t addr, 48928ce5ce6Saurel32 uint16_t len) 49028ce5ce6Saurel32 { 49128ce5ce6Saurel32 dbdma_cmd *current = &ch->current; 49228ce5ce6Saurel32 uint32_t val; 49328ce5ce6Saurel32 49428ce5ce6Saurel32 DBDMA_DPRINTF("store_word\n"); 49528ce5ce6Saurel32 49628ce5ce6Saurel32 /* only implements KEY_SYSTEM */ 49728ce5ce6Saurel32 49828ce5ce6Saurel32 if (key != KEY_SYSTEM) { 49928ce5ce6Saurel32 printf("DBDMA: STORE_WORD, unimplemented key %x\n", key); 50028ce5ce6Saurel32 kill_channel(ch); 501b42ec42dSaurel32 return; 50228ce5ce6Saurel32 } 50328ce5ce6Saurel32 50428ce5ce6Saurel32 val = current->cmd_dep; 50528ce5ce6Saurel32 if (len == 2) 50628ce5ce6Saurel32 val >>= 16; 50728ce5ce6Saurel32 else if (len == 1) 50828ce5ce6Saurel32 val >>= 24; 50928ce5ce6Saurel32 510e1fe50dcSStefan Weil cpu_physical_memory_write(addr, &val, len); 51128ce5ce6Saurel32 51228ce5ce6Saurel32 if (conditional_wait(ch)) 513b42ec42dSaurel32 goto wait; 51428ce5ce6Saurel32 515ad674e53SAurelien Jarno current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]); 51628ce5ce6Saurel32 dbdma_cmdptr_save(ch); 517ad674e53SAurelien Jarno ch->regs[DBDMA_STATUS] &= ~FLUSH; 51828ce5ce6Saurel32 51928ce5ce6Saurel32 conditional_interrupt(ch); 52028ce5ce6Saurel32 next(ch); 52128ce5ce6Saurel32 522b42ec42dSaurel32 wait: 523b42ec42dSaurel32 qemu_bh_schedule(dbdma_bh); 52428ce5ce6Saurel32 } 52528ce5ce6Saurel32 526b42ec42dSaurel32 static void nop(DBDMA_channel *ch) 52728ce5ce6Saurel32 { 52828ce5ce6Saurel32 dbdma_cmd *current = &ch->current; 52928ce5ce6Saurel32 53028ce5ce6Saurel32 if (conditional_wait(ch)) 531b42ec42dSaurel32 goto wait; 53228ce5ce6Saurel32 533ad674e53SAurelien Jarno current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]); 53428ce5ce6Saurel32 dbdma_cmdptr_save(ch); 53528ce5ce6Saurel32 53628ce5ce6Saurel32 conditional_interrupt(ch); 53728ce5ce6Saurel32 conditional_branch(ch); 53828ce5ce6Saurel32 539b42ec42dSaurel32 wait: 540b42ec42dSaurel32 qemu_bh_schedule(dbdma_bh); 54128ce5ce6Saurel32 } 54228ce5ce6Saurel32 543b42ec42dSaurel32 static void stop(DBDMA_channel *ch) 54428ce5ce6Saurel32 { 545ad674e53SAurelien Jarno ch->regs[DBDMA_STATUS] &= ~(ACTIVE|DEAD|FLUSH); 54628ce5ce6Saurel32 54728ce5ce6Saurel32 /* the stop command does not increment command pointer */ 54828ce5ce6Saurel32 } 54928ce5ce6Saurel32 550b42ec42dSaurel32 static void channel_run(DBDMA_channel *ch) 55128ce5ce6Saurel32 { 55228ce5ce6Saurel32 dbdma_cmd *current = &ch->current; 55328ce5ce6Saurel32 uint16_t cmd, key; 55428ce5ce6Saurel32 uint16_t req_count; 55528ce5ce6Saurel32 uint32_t phy_addr; 55628ce5ce6Saurel32 55728ce5ce6Saurel32 DBDMA_DPRINTF("channel_run\n"); 55828ce5ce6Saurel32 dump_dbdma_cmd(current); 55928ce5ce6Saurel32 56028ce5ce6Saurel32 /* clear WAKE flag at command fetch */ 56128ce5ce6Saurel32 562ad674e53SAurelien Jarno ch->regs[DBDMA_STATUS] &= ~WAKE; 56328ce5ce6Saurel32 56428ce5ce6Saurel32 cmd = le16_to_cpu(current->command) & COMMAND_MASK; 56528ce5ce6Saurel32 56628ce5ce6Saurel32 switch (cmd) { 56728ce5ce6Saurel32 case DBDMA_NOP: 568b42ec42dSaurel32 nop(ch); 569b42ec42dSaurel32 return; 57028ce5ce6Saurel32 57128ce5ce6Saurel32 case DBDMA_STOP: 572b42ec42dSaurel32 stop(ch); 573b42ec42dSaurel32 return; 57428ce5ce6Saurel32 } 57528ce5ce6Saurel32 57628ce5ce6Saurel32 key = le16_to_cpu(current->command) & 0x0700; 57728ce5ce6Saurel32 req_count = le16_to_cpu(current->req_count); 57828ce5ce6Saurel32 phy_addr = le32_to_cpu(current->phy_addr); 57928ce5ce6Saurel32 58028ce5ce6Saurel32 if (key == KEY_STREAM4) { 58128ce5ce6Saurel32 printf("command %x, invalid key 4\n", cmd); 58228ce5ce6Saurel32 kill_channel(ch); 583b42ec42dSaurel32 return; 58428ce5ce6Saurel32 } 58528ce5ce6Saurel32 58628ce5ce6Saurel32 switch (cmd) { 58728ce5ce6Saurel32 case OUTPUT_MORE: 588b42ec42dSaurel32 start_output(ch, key, phy_addr, req_count, 0); 589b42ec42dSaurel32 return; 59028ce5ce6Saurel32 59128ce5ce6Saurel32 case OUTPUT_LAST: 592b42ec42dSaurel32 start_output(ch, key, phy_addr, req_count, 1); 593b42ec42dSaurel32 return; 59428ce5ce6Saurel32 59528ce5ce6Saurel32 case INPUT_MORE: 596b42ec42dSaurel32 start_input(ch, key, phy_addr, req_count, 0); 597b42ec42dSaurel32 return; 59828ce5ce6Saurel32 59928ce5ce6Saurel32 case INPUT_LAST: 600b42ec42dSaurel32 start_input(ch, key, phy_addr, req_count, 1); 601b42ec42dSaurel32 return; 60228ce5ce6Saurel32 } 60328ce5ce6Saurel32 60428ce5ce6Saurel32 if (key < KEY_REGS) { 60528ce5ce6Saurel32 printf("command %x, invalid key %x\n", cmd, key); 60628ce5ce6Saurel32 key = KEY_SYSTEM; 60728ce5ce6Saurel32 } 60828ce5ce6Saurel32 60928ce5ce6Saurel32 /* for LOAD_WORD and STORE_WORD, req_count is on 3 bits 61028ce5ce6Saurel32 * and BRANCH is invalid 61128ce5ce6Saurel32 */ 61228ce5ce6Saurel32 61328ce5ce6Saurel32 req_count = req_count & 0x0007; 61428ce5ce6Saurel32 if (req_count & 0x4) { 61528ce5ce6Saurel32 req_count = 4; 61628ce5ce6Saurel32 phy_addr &= ~3; 61728ce5ce6Saurel32 } else if (req_count & 0x2) { 61828ce5ce6Saurel32 req_count = 2; 61928ce5ce6Saurel32 phy_addr &= ~1; 62028ce5ce6Saurel32 } else 62128ce5ce6Saurel32 req_count = 1; 62228ce5ce6Saurel32 62328ce5ce6Saurel32 switch (cmd) { 62428ce5ce6Saurel32 case LOAD_WORD: 625b42ec42dSaurel32 load_word(ch, key, phy_addr, req_count); 626b42ec42dSaurel32 return; 62728ce5ce6Saurel32 62828ce5ce6Saurel32 case STORE_WORD: 629b42ec42dSaurel32 store_word(ch, key, phy_addr, req_count); 630b42ec42dSaurel32 return; 63128ce5ce6Saurel32 } 63228ce5ce6Saurel32 } 63328ce5ce6Saurel32 634c20df14bSJuan Quintela static void DBDMA_run(DBDMAState *s) 63528ce5ce6Saurel32 { 63628ce5ce6Saurel32 int channel; 63728ce5ce6Saurel32 638c20df14bSJuan Quintela for (channel = 0; channel < DBDMA_CHANNELS; channel++) { 639c20df14bSJuan Quintela DBDMA_channel *ch = &s->channels[channel]; 640ad674e53SAurelien Jarno uint32_t status = ch->regs[DBDMA_STATUS]; 641c20df14bSJuan Quintela if (!ch->processing && (status & RUN) && (status & ACTIVE)) { 642b42ec42dSaurel32 channel_run(ch); 64328ce5ce6Saurel32 } 64428ce5ce6Saurel32 } 645c20df14bSJuan Quintela } 64628ce5ce6Saurel32 64728ce5ce6Saurel32 static void DBDMA_run_bh(void *opaque) 64828ce5ce6Saurel32 { 649c20df14bSJuan Quintela DBDMAState *s = opaque; 65028ce5ce6Saurel32 65128ce5ce6Saurel32 DBDMA_DPRINTF("DBDMA_run_bh\n"); 65228ce5ce6Saurel32 653c20df14bSJuan Quintela DBDMA_run(s); 65428ce5ce6Saurel32 } 65528ce5ce6Saurel32 65628ce5ce6Saurel32 void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq, 657862c9280Saurel32 DBDMA_rw rw, DBDMA_flush flush, 65828ce5ce6Saurel32 void *opaque) 65928ce5ce6Saurel32 { 660c20df14bSJuan Quintela DBDMAState *s = dbdma; 661c20df14bSJuan Quintela DBDMA_channel *ch = &s->channels[nchan]; 66228ce5ce6Saurel32 66328ce5ce6Saurel32 DBDMA_DPRINTF("DBDMA_register_channel 0x%x\n", nchan); 66428ce5ce6Saurel32 66528ce5ce6Saurel32 ch->irq = irq; 66628ce5ce6Saurel32 ch->channel = nchan; 667b42ec42dSaurel32 ch->rw = rw; 668862c9280Saurel32 ch->flush = flush; 66928ce5ce6Saurel32 ch->io.opaque = opaque; 67028ce5ce6Saurel32 ch->io.channel = ch; 67128ce5ce6Saurel32 } 67228ce5ce6Saurel32 67328ce5ce6Saurel32 static void 67428ce5ce6Saurel32 dbdma_control_write(DBDMA_channel *ch) 67528ce5ce6Saurel32 { 67628ce5ce6Saurel32 uint16_t mask, value; 67728ce5ce6Saurel32 uint32_t status; 67828ce5ce6Saurel32 679ad674e53SAurelien Jarno mask = (ch->regs[DBDMA_CONTROL] >> 16) & 0xffff; 680ad674e53SAurelien Jarno value = ch->regs[DBDMA_CONTROL] & 0xffff; 68128ce5ce6Saurel32 68228ce5ce6Saurel32 value &= (RUN | PAUSE | FLUSH | WAKE | DEVSTAT); 68328ce5ce6Saurel32 684ad674e53SAurelien Jarno status = ch->regs[DBDMA_STATUS]; 68528ce5ce6Saurel32 68628ce5ce6Saurel32 status = (value & mask) | (status & ~mask); 68728ce5ce6Saurel32 68828ce5ce6Saurel32 if (status & WAKE) 68928ce5ce6Saurel32 status |= ACTIVE; 69028ce5ce6Saurel32 if (status & RUN) { 69128ce5ce6Saurel32 status |= ACTIVE; 69228ce5ce6Saurel32 status &= ~DEAD; 69328ce5ce6Saurel32 } 69428ce5ce6Saurel32 if (status & PAUSE) 69528ce5ce6Saurel32 status &= ~ACTIVE; 696ad674e53SAurelien Jarno if ((ch->regs[DBDMA_STATUS] & RUN) && !(status & RUN)) { 69728ce5ce6Saurel32 /* RUN is cleared */ 69828ce5ce6Saurel32 status &= ~(ACTIVE|DEAD); 699987422bcSAmadeusz Sławiński if ((status & FLUSH) && ch->flush) { 700987422bcSAmadeusz Sławiński ch->flush(&ch->io); 701987422bcSAmadeusz Sławiński status &= ~FLUSH; 702987422bcSAmadeusz Sławiński } 70328ce5ce6Saurel32 } 70428ce5ce6Saurel32 70528ce5ce6Saurel32 DBDMA_DPRINTF(" status 0x%08x\n", status); 70628ce5ce6Saurel32 707ad674e53SAurelien Jarno ch->regs[DBDMA_STATUS] = status; 70828ce5ce6Saurel32 709b42ec42dSaurel32 if (status & ACTIVE) 710b42ec42dSaurel32 qemu_bh_schedule(dbdma_bh); 711a9ceb76dSAlexander Graf if ((status & FLUSH) && ch->flush) 712862c9280Saurel32 ch->flush(&ch->io); 7133cbee15bSj_mayer } 7143cbee15bSj_mayer 715a8170e5eSAvi Kivity static void dbdma_write(void *opaque, hwaddr addr, 71623c5e4caSAvi Kivity uint64_t value, unsigned size) 7173cbee15bSj_mayer { 71828ce5ce6Saurel32 int channel = addr >> DBDMA_CHANNEL_SHIFT; 719c20df14bSJuan Quintela DBDMAState *s = opaque; 720c20df14bSJuan Quintela DBDMA_channel *ch = &s->channels[channel]; 72128ce5ce6Saurel32 int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2; 72228ce5ce6Saurel32 723*58c0c311SAlexander Graf DBDMA_DPRINTF("writel 0x" TARGET_FMT_plx " <= 0x%08"PRIx64"\n", 724*58c0c311SAlexander Graf addr, value); 72528ce5ce6Saurel32 DBDMA_DPRINTF("channel 0x%x reg 0x%x\n", 72628ce5ce6Saurel32 (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg); 72728ce5ce6Saurel32 72828ce5ce6Saurel32 /* cmdptr cannot be modified if channel is RUN or ACTIVE */ 72928ce5ce6Saurel32 73028ce5ce6Saurel32 if (reg == DBDMA_CMDPTR_LO && 731ad674e53SAurelien Jarno (ch->regs[DBDMA_STATUS] & (RUN | ACTIVE))) 73228ce5ce6Saurel32 return; 73328ce5ce6Saurel32 73428ce5ce6Saurel32 ch->regs[reg] = value; 73528ce5ce6Saurel32 73628ce5ce6Saurel32 switch(reg) { 73728ce5ce6Saurel32 case DBDMA_CONTROL: 73828ce5ce6Saurel32 dbdma_control_write(ch); 73928ce5ce6Saurel32 break; 74028ce5ce6Saurel32 case DBDMA_CMDPTR_LO: 74128ce5ce6Saurel32 /* 16-byte aligned */ 742ad674e53SAurelien Jarno ch->regs[DBDMA_CMDPTR_LO] &= ~0xf; 74328ce5ce6Saurel32 dbdma_cmdptr_load(ch); 74428ce5ce6Saurel32 break; 74528ce5ce6Saurel32 case DBDMA_STATUS: 74628ce5ce6Saurel32 case DBDMA_INTR_SEL: 74728ce5ce6Saurel32 case DBDMA_BRANCH_SEL: 74828ce5ce6Saurel32 case DBDMA_WAIT_SEL: 74928ce5ce6Saurel32 /* nothing to do */ 75028ce5ce6Saurel32 break; 75128ce5ce6Saurel32 case DBDMA_XFER_MODE: 75228ce5ce6Saurel32 case DBDMA_CMDPTR_HI: 75328ce5ce6Saurel32 case DBDMA_DATA2PTR_HI: 75428ce5ce6Saurel32 case DBDMA_DATA2PTR_LO: 75528ce5ce6Saurel32 case DBDMA_ADDRESS_HI: 75628ce5ce6Saurel32 case DBDMA_BRANCH_ADDR_HI: 75728ce5ce6Saurel32 case DBDMA_RES1: 75828ce5ce6Saurel32 case DBDMA_RES2: 75928ce5ce6Saurel32 case DBDMA_RES3: 76028ce5ce6Saurel32 case DBDMA_RES4: 76128ce5ce6Saurel32 /* unused */ 76228ce5ce6Saurel32 break; 7633cbee15bSj_mayer } 7643cbee15bSj_mayer } 7653cbee15bSj_mayer 766a8170e5eSAvi Kivity static uint64_t dbdma_read(void *opaque, hwaddr addr, 76723c5e4caSAvi Kivity unsigned size) 7683cbee15bSj_mayer { 76928ce5ce6Saurel32 uint32_t value; 77028ce5ce6Saurel32 int channel = addr >> DBDMA_CHANNEL_SHIFT; 771c20df14bSJuan Quintela DBDMAState *s = opaque; 772c20df14bSJuan Quintela DBDMA_channel *ch = &s->channels[channel]; 77328ce5ce6Saurel32 int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2; 774ea026b2fSblueswir1 77528ce5ce6Saurel32 value = ch->regs[reg]; 77628ce5ce6Saurel32 77728ce5ce6Saurel32 DBDMA_DPRINTF("readl 0x" TARGET_FMT_plx " => 0x%08x\n", addr, value); 77828ce5ce6Saurel32 DBDMA_DPRINTF("channel 0x%x reg 0x%x\n", 77928ce5ce6Saurel32 (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg); 78028ce5ce6Saurel32 78128ce5ce6Saurel32 switch(reg) { 78228ce5ce6Saurel32 case DBDMA_CONTROL: 78328ce5ce6Saurel32 value = 0; 78428ce5ce6Saurel32 break; 78528ce5ce6Saurel32 case DBDMA_STATUS: 78628ce5ce6Saurel32 case DBDMA_CMDPTR_LO: 78728ce5ce6Saurel32 case DBDMA_INTR_SEL: 78828ce5ce6Saurel32 case DBDMA_BRANCH_SEL: 78928ce5ce6Saurel32 case DBDMA_WAIT_SEL: 79028ce5ce6Saurel32 /* nothing to do */ 79128ce5ce6Saurel32 break; 79228ce5ce6Saurel32 case DBDMA_XFER_MODE: 79328ce5ce6Saurel32 case DBDMA_CMDPTR_HI: 79428ce5ce6Saurel32 case DBDMA_DATA2PTR_HI: 79528ce5ce6Saurel32 case DBDMA_DATA2PTR_LO: 79628ce5ce6Saurel32 case DBDMA_ADDRESS_HI: 79728ce5ce6Saurel32 case DBDMA_BRANCH_ADDR_HI: 79828ce5ce6Saurel32 /* unused */ 79928ce5ce6Saurel32 value = 0; 80028ce5ce6Saurel32 break; 80128ce5ce6Saurel32 case DBDMA_RES1: 80228ce5ce6Saurel32 case DBDMA_RES2: 80328ce5ce6Saurel32 case DBDMA_RES3: 80428ce5ce6Saurel32 case DBDMA_RES4: 80528ce5ce6Saurel32 /* reserved */ 80628ce5ce6Saurel32 break; 80728ce5ce6Saurel32 } 80828ce5ce6Saurel32 80928ce5ce6Saurel32 return value; 8103cbee15bSj_mayer } 8113cbee15bSj_mayer 81223c5e4caSAvi Kivity static const MemoryRegionOps dbdma_ops = { 81323c5e4caSAvi Kivity .read = dbdma_read, 81423c5e4caSAvi Kivity .write = dbdma_write, 81523c5e4caSAvi Kivity .endianness = DEVICE_LITTLE_ENDIAN, 81623c5e4caSAvi Kivity .valid = { 81723c5e4caSAvi Kivity .min_access_size = 4, 81823c5e4caSAvi Kivity .max_access_size = 4, 81923c5e4caSAvi Kivity }, 8203cbee15bSj_mayer }; 8213cbee15bSj_mayer 822da26fdc3SJuan Quintela static const VMStateDescription vmstate_dbdma_channel = { 823da26fdc3SJuan Quintela .name = "dbdma_channel", 824da26fdc3SJuan Quintela .version_id = 0, 825da26fdc3SJuan Quintela .minimum_version_id = 0, 826da26fdc3SJuan Quintela .minimum_version_id_old = 0, 827da26fdc3SJuan Quintela .fields = (VMStateField[]) { 828da26fdc3SJuan Quintela VMSTATE_UINT32_ARRAY(regs, struct DBDMA_channel, DBDMA_REGS), 829da26fdc3SJuan Quintela VMSTATE_END_OF_LIST() 8309b64997fSblueswir1 } 831da26fdc3SJuan Quintela }; 8329b64997fSblueswir1 833da26fdc3SJuan Quintela static const VMStateDescription vmstate_dbdma = { 834da26fdc3SJuan Quintela .name = "dbdma", 835da26fdc3SJuan Quintela .version_id = 2, 836da26fdc3SJuan Quintela .minimum_version_id = 2, 837da26fdc3SJuan Quintela .minimum_version_id_old = 2, 838da26fdc3SJuan Quintela .fields = (VMStateField[]) { 839da26fdc3SJuan Quintela VMSTATE_STRUCT_ARRAY(channels, DBDMAState, DBDMA_CHANNELS, 1, 840da26fdc3SJuan Quintela vmstate_dbdma_channel, DBDMA_channel), 841da26fdc3SJuan Quintela VMSTATE_END_OF_LIST() 8429b64997fSblueswir1 } 843da26fdc3SJuan Quintela }; 8449b64997fSblueswir1 8456e6b7363Sblueswir1 static void dbdma_reset(void *opaque) 8466e6b7363Sblueswir1 { 847c20df14bSJuan Quintela DBDMAState *s = opaque; 84828ce5ce6Saurel32 int i; 84928ce5ce6Saurel32 85028ce5ce6Saurel32 for (i = 0; i < DBDMA_CHANNELS; i++) 851c20df14bSJuan Quintela memset(s->channels[i].regs, 0, DBDMA_SIZE); 8526e6b7363Sblueswir1 } 8536e6b7363Sblueswir1 85423c5e4caSAvi Kivity void* DBDMA_init (MemoryRegion **dbdma_mem) 8553cbee15bSj_mayer { 856c20df14bSJuan Quintela DBDMAState *s; 85728ce5ce6Saurel32 8587267c094SAnthony Liguori s = g_malloc0(sizeof(DBDMAState)); 85928ce5ce6Saurel32 8602c9b15caSPaolo Bonzini memory_region_init_io(&s->mem, NULL, &dbdma_ops, s, "dbdma", 0x1000); 86123c5e4caSAvi Kivity *dbdma_mem = &s->mem; 862da26fdc3SJuan Quintela vmstate_register(NULL, -1, &vmstate_dbdma, s); 863a08d4367SJan Kiszka qemu_register_reset(dbdma_reset, s); 86428ce5ce6Saurel32 86528ce5ce6Saurel32 dbdma_bh = qemu_bh_new(DBDMA_run_bh, s); 86628ce5ce6Saurel32 86728ce5ce6Saurel32 return s; 8683cbee15bSj_mayer } 869