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 */ 390d75590dSPeter Maydell #include "qemu/osdep.h" 4083c9f4caSPaolo Bonzini #include "hw/hw.h" 410d09e41aSPaolo Bonzini #include "hw/isa/isa.h" 420d09e41aSPaolo Bonzini #include "hw/ppc/mac_dbdma.h" 431de7afc9SPaolo Bonzini #include "qemu/main-loop.h" 4403dd024fSPaolo Bonzini #include "qemu/log.h" 4588655881SMark Cave-Ayland #include "sysemu/dma.h" 463cbee15bSj_mayer 47ea026b2fSblueswir1 /* debug DBDMA */ 48ba0b17ddSMark Cave-Ayland #define DEBUG_DBDMA 0 493e49c439SMark Cave-Ayland #define DEBUG_DBDMA_CHANMASK ((1ull << DBDMA_CHANNELS) - 1) 50ea026b2fSblueswir1 51ba0b17ddSMark Cave-Ayland #define DBDMA_DPRINTF(fmt, ...) do { \ 52ba0b17ddSMark Cave-Ayland if (DEBUG_DBDMA) { \ 53ba0b17ddSMark Cave-Ayland printf("DBDMA: " fmt , ## __VA_ARGS__); \ 54ba0b17ddSMark Cave-Ayland } \ 55ba0b17ddSMark Cave-Ayland } while (0); 56ea026b2fSblueswir1 573e49c439SMark Cave-Ayland #define DBDMA_DPRINTFCH(ch, fmt, ...) do { \ 583e49c439SMark Cave-Ayland if (DEBUG_DBDMA) { \ 593e49c439SMark Cave-Ayland if ((1ul << (ch)->channel) & DEBUG_DBDMA_CHANMASK) { \ 603e49c439SMark Cave-Ayland printf("DBDMA[%02x]: " fmt , (ch)->channel, ## __VA_ARGS__); \ 613e49c439SMark Cave-Ayland } \ 623e49c439SMark Cave-Ayland } \ 633e49c439SMark Cave-Ayland } while (0); 643e49c439SMark Cave-Ayland 6528ce5ce6Saurel32 /* 6628ce5ce6Saurel32 */ 673cbee15bSj_mayer 68d2f0ce21SAlexander Graf static DBDMAState *dbdma_from_ch(DBDMA_channel *ch) 69d2f0ce21SAlexander Graf { 70d2f0ce21SAlexander Graf return container_of(ch, DBDMAState, channels[ch->channel]); 71d2f0ce21SAlexander Graf } 72d2f0ce21SAlexander Graf 73ba0b17ddSMark Cave-Ayland #if DEBUG_DBDMA 7428ce5ce6Saurel32 static void dump_dbdma_cmd(dbdma_cmd *cmd) 753cbee15bSj_mayer { 7628ce5ce6Saurel32 printf("dbdma_cmd %p\n", cmd); 7728ce5ce6Saurel32 printf(" req_count 0x%04x\n", le16_to_cpu(cmd->req_count)); 7828ce5ce6Saurel32 printf(" command 0x%04x\n", le16_to_cpu(cmd->command)); 7928ce5ce6Saurel32 printf(" phy_addr 0x%08x\n", le32_to_cpu(cmd->phy_addr)); 8028ce5ce6Saurel32 printf(" cmd_dep 0x%08x\n", le32_to_cpu(cmd->cmd_dep)); 8128ce5ce6Saurel32 printf(" res_count 0x%04x\n", le16_to_cpu(cmd->res_count)); 8228ce5ce6Saurel32 printf(" xfer_status 0x%04x\n", le16_to_cpu(cmd->xfer_status)); 8328ce5ce6Saurel32 } 8428ce5ce6Saurel32 #else 8528ce5ce6Saurel32 static void dump_dbdma_cmd(dbdma_cmd *cmd) 8628ce5ce6Saurel32 { 8728ce5ce6Saurel32 } 8828ce5ce6Saurel32 #endif 8928ce5ce6Saurel32 static void dbdma_cmdptr_load(DBDMA_channel *ch) 9028ce5ce6Saurel32 { 913e49c439SMark Cave-Ayland DBDMA_DPRINTFCH(ch, "dbdma_cmdptr_load 0x%08x\n", 92ad674e53SAurelien Jarno ch->regs[DBDMA_CMDPTR_LO]); 9388655881SMark Cave-Ayland dma_memory_read(&address_space_memory, ch->regs[DBDMA_CMDPTR_LO], 94e1fe50dcSStefan Weil &ch->current, sizeof(dbdma_cmd)); 953cbee15bSj_mayer } 963cbee15bSj_mayer 9728ce5ce6Saurel32 static void dbdma_cmdptr_save(DBDMA_channel *ch) 983cbee15bSj_mayer { 993e49c439SMark Cave-Ayland DBDMA_DPRINTFCH(ch, "dbdma_cmdptr_save 0x%08x\n", 100ad674e53SAurelien Jarno ch->regs[DBDMA_CMDPTR_LO]); 1013e49c439SMark Cave-Ayland DBDMA_DPRINTFCH(ch, "xfer_status 0x%08x res_count 0x%04x\n", 10228ce5ce6Saurel32 le16_to_cpu(ch->current.xfer_status), 10328ce5ce6Saurel32 le16_to_cpu(ch->current.res_count)); 10488655881SMark Cave-Ayland dma_memory_write(&address_space_memory, ch->regs[DBDMA_CMDPTR_LO], 105e1fe50dcSStefan Weil &ch->current, sizeof(dbdma_cmd)); 10628ce5ce6Saurel32 } 10728ce5ce6Saurel32 10828ce5ce6Saurel32 static void kill_channel(DBDMA_channel *ch) 10928ce5ce6Saurel32 { 1103e49c439SMark Cave-Ayland DBDMA_DPRINTFCH(ch, "kill_channel\n"); 11128ce5ce6Saurel32 112ad674e53SAurelien Jarno ch->regs[DBDMA_STATUS] |= DEAD; 113ad674e53SAurelien Jarno ch->regs[DBDMA_STATUS] &= ~ACTIVE; 11428ce5ce6Saurel32 11528ce5ce6Saurel32 qemu_irq_raise(ch->irq); 11628ce5ce6Saurel32 } 11728ce5ce6Saurel32 11828ce5ce6Saurel32 static void conditional_interrupt(DBDMA_channel *ch) 11928ce5ce6Saurel32 { 12028ce5ce6Saurel32 dbdma_cmd *current = &ch->current; 12128ce5ce6Saurel32 uint16_t intr; 12228ce5ce6Saurel32 uint16_t sel_mask, sel_value; 12328ce5ce6Saurel32 uint32_t status; 12428ce5ce6Saurel32 int cond; 12528ce5ce6Saurel32 1263e49c439SMark Cave-Ayland DBDMA_DPRINTFCH(ch, "%s\n", __func__); 12728ce5ce6Saurel32 128b42ec42dSaurel32 intr = le16_to_cpu(current->command) & INTR_MASK; 12928ce5ce6Saurel32 13028ce5ce6Saurel32 switch(intr) { 13128ce5ce6Saurel32 case INTR_NEVER: /* don't interrupt */ 13228ce5ce6Saurel32 return; 13328ce5ce6Saurel32 case INTR_ALWAYS: /* always interrupt */ 13428ce5ce6Saurel32 qemu_irq_raise(ch->irq); 1353e49c439SMark Cave-Ayland DBDMA_DPRINTFCH(ch, "%s: raise\n", __func__); 13628ce5ce6Saurel32 return; 13728ce5ce6Saurel32 } 13828ce5ce6Saurel32 139ad674e53SAurelien Jarno status = ch->regs[DBDMA_STATUS] & DEVSTAT; 14028ce5ce6Saurel32 141ad674e53SAurelien Jarno sel_mask = (ch->regs[DBDMA_INTR_SEL] >> 16) & 0x0f; 142ad674e53SAurelien Jarno sel_value = ch->regs[DBDMA_INTR_SEL] & 0x0f; 14328ce5ce6Saurel32 14428ce5ce6Saurel32 cond = (status & sel_mask) == (sel_value & sel_mask); 14528ce5ce6Saurel32 14628ce5ce6Saurel32 switch(intr) { 14728ce5ce6Saurel32 case INTR_IFSET: /* intr if condition bit is 1 */ 14833ce36bbSAlexander Graf if (cond) { 14928ce5ce6Saurel32 qemu_irq_raise(ch->irq); 1503e49c439SMark Cave-Ayland DBDMA_DPRINTFCH(ch, "%s: raise\n", __func__); 15133ce36bbSAlexander Graf } 15228ce5ce6Saurel32 return; 15328ce5ce6Saurel32 case INTR_IFCLR: /* intr if condition bit is 0 */ 15433ce36bbSAlexander Graf if (!cond) { 15528ce5ce6Saurel32 qemu_irq_raise(ch->irq); 1563e49c439SMark Cave-Ayland DBDMA_DPRINTFCH(ch, "%s: raise\n", __func__); 15733ce36bbSAlexander Graf } 15828ce5ce6Saurel32 return; 15928ce5ce6Saurel32 } 16028ce5ce6Saurel32 } 16128ce5ce6Saurel32 16228ce5ce6Saurel32 static int conditional_wait(DBDMA_channel *ch) 16328ce5ce6Saurel32 { 16428ce5ce6Saurel32 dbdma_cmd *current = &ch->current; 16528ce5ce6Saurel32 uint16_t wait; 16628ce5ce6Saurel32 uint16_t sel_mask, sel_value; 16728ce5ce6Saurel32 uint32_t status; 16828ce5ce6Saurel32 int cond; 16928ce5ce6Saurel32 1703e49c439SMark Cave-Ayland DBDMA_DPRINTFCH(ch, "conditional_wait\n"); 17128ce5ce6Saurel32 172b42ec42dSaurel32 wait = le16_to_cpu(current->command) & WAIT_MASK; 17328ce5ce6Saurel32 17428ce5ce6Saurel32 switch(wait) { 17528ce5ce6Saurel32 case WAIT_NEVER: /* don't wait */ 17628ce5ce6Saurel32 return 0; 17728ce5ce6Saurel32 case WAIT_ALWAYS: /* always wait */ 17828ce5ce6Saurel32 return 1; 17928ce5ce6Saurel32 } 18028ce5ce6Saurel32 181ad674e53SAurelien Jarno status = ch->regs[DBDMA_STATUS] & DEVSTAT; 18228ce5ce6Saurel32 183ad674e53SAurelien Jarno sel_mask = (ch->regs[DBDMA_WAIT_SEL] >> 16) & 0x0f; 184ad674e53SAurelien Jarno sel_value = ch->regs[DBDMA_WAIT_SEL] & 0x0f; 18528ce5ce6Saurel32 18628ce5ce6Saurel32 cond = (status & sel_mask) == (sel_value & sel_mask); 18728ce5ce6Saurel32 18828ce5ce6Saurel32 switch(wait) { 18928ce5ce6Saurel32 case WAIT_IFSET: /* wait if condition bit is 1 */ 19028ce5ce6Saurel32 if (cond) 19128ce5ce6Saurel32 return 1; 19228ce5ce6Saurel32 return 0; 19328ce5ce6Saurel32 case WAIT_IFCLR: /* wait if condition bit is 0 */ 19428ce5ce6Saurel32 if (!cond) 19528ce5ce6Saurel32 return 1; 19628ce5ce6Saurel32 return 0; 19728ce5ce6Saurel32 } 19828ce5ce6Saurel32 return 0; 19928ce5ce6Saurel32 } 20028ce5ce6Saurel32 20128ce5ce6Saurel32 static void next(DBDMA_channel *ch) 20228ce5ce6Saurel32 { 20328ce5ce6Saurel32 uint32_t cp; 20428ce5ce6Saurel32 205ad674e53SAurelien Jarno ch->regs[DBDMA_STATUS] &= ~BT; 20628ce5ce6Saurel32 207ad674e53SAurelien Jarno cp = ch->regs[DBDMA_CMDPTR_LO]; 208ad674e53SAurelien Jarno ch->regs[DBDMA_CMDPTR_LO] = cp + sizeof(dbdma_cmd); 20928ce5ce6Saurel32 dbdma_cmdptr_load(ch); 21028ce5ce6Saurel32 } 21128ce5ce6Saurel32 21228ce5ce6Saurel32 static void branch(DBDMA_channel *ch) 21328ce5ce6Saurel32 { 21428ce5ce6Saurel32 dbdma_cmd *current = &ch->current; 21528ce5ce6Saurel32 216*3f0d4128SMark Cave-Ayland ch->regs[DBDMA_CMDPTR_LO] = le32_to_cpu(current->cmd_dep); 217ad674e53SAurelien Jarno ch->regs[DBDMA_STATUS] |= BT; 21828ce5ce6Saurel32 dbdma_cmdptr_load(ch); 21928ce5ce6Saurel32 } 22028ce5ce6Saurel32 22128ce5ce6Saurel32 static void conditional_branch(DBDMA_channel *ch) 22228ce5ce6Saurel32 { 22328ce5ce6Saurel32 dbdma_cmd *current = &ch->current; 22428ce5ce6Saurel32 uint16_t br; 22528ce5ce6Saurel32 uint16_t sel_mask, sel_value; 22628ce5ce6Saurel32 uint32_t status; 22728ce5ce6Saurel32 int cond; 22828ce5ce6Saurel32 2293e49c439SMark Cave-Ayland DBDMA_DPRINTFCH(ch, "conditional_branch\n"); 23028ce5ce6Saurel32 23128ce5ce6Saurel32 /* check if we must branch */ 23228ce5ce6Saurel32 233b42ec42dSaurel32 br = le16_to_cpu(current->command) & BR_MASK; 23428ce5ce6Saurel32 23528ce5ce6Saurel32 switch(br) { 23628ce5ce6Saurel32 case BR_NEVER: /* don't branch */ 23728ce5ce6Saurel32 next(ch); 23828ce5ce6Saurel32 return; 23928ce5ce6Saurel32 case BR_ALWAYS: /* always branch */ 24028ce5ce6Saurel32 branch(ch); 24128ce5ce6Saurel32 return; 24228ce5ce6Saurel32 } 24328ce5ce6Saurel32 244ad674e53SAurelien Jarno status = ch->regs[DBDMA_STATUS] & DEVSTAT; 24528ce5ce6Saurel32 246ad674e53SAurelien Jarno sel_mask = (ch->regs[DBDMA_BRANCH_SEL] >> 16) & 0x0f; 247ad674e53SAurelien Jarno sel_value = ch->regs[DBDMA_BRANCH_SEL] & 0x0f; 24828ce5ce6Saurel32 24928ce5ce6Saurel32 cond = (status & sel_mask) == (sel_value & sel_mask); 25028ce5ce6Saurel32 25128ce5ce6Saurel32 switch(br) { 25228ce5ce6Saurel32 case BR_IFSET: /* branch if condition bit is 1 */ 25328ce5ce6Saurel32 if (cond) 25428ce5ce6Saurel32 branch(ch); 25528ce5ce6Saurel32 else 25628ce5ce6Saurel32 next(ch); 25728ce5ce6Saurel32 return; 25828ce5ce6Saurel32 case BR_IFCLR: /* branch if condition bit is 0 */ 25928ce5ce6Saurel32 if (!cond) 26028ce5ce6Saurel32 branch(ch); 26128ce5ce6Saurel32 else 26228ce5ce6Saurel32 next(ch); 26328ce5ce6Saurel32 return; 26428ce5ce6Saurel32 } 26528ce5ce6Saurel32 } 26628ce5ce6Saurel32 267b42ec42dSaurel32 static void channel_run(DBDMA_channel *ch); 268b42ec42dSaurel32 269b42ec42dSaurel32 static void dbdma_end(DBDMA_io *io) 27028ce5ce6Saurel32 { 27128ce5ce6Saurel32 DBDMA_channel *ch = io->channel; 27228ce5ce6Saurel32 dbdma_cmd *current = &ch->current; 27328ce5ce6Saurel32 2743e49c439SMark Cave-Ayland DBDMA_DPRINTFCH(ch, "%s\n", __func__); 27533ce36bbSAlexander Graf 276b42ec42dSaurel32 if (conditional_wait(ch)) 277b42ec42dSaurel32 goto wait; 27828ce5ce6Saurel32 279ad674e53SAurelien Jarno current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]); 280ad674e53SAurelien Jarno current->res_count = cpu_to_le16(io->len); 281b42ec42dSaurel32 dbdma_cmdptr_save(ch); 282862c9280Saurel32 if (io->is_last) 283ad674e53SAurelien Jarno ch->regs[DBDMA_STATUS] &= ~FLUSH; 28428ce5ce6Saurel32 285b42ec42dSaurel32 conditional_interrupt(ch); 286b42ec42dSaurel32 conditional_branch(ch); 287b42ec42dSaurel32 288b42ec42dSaurel32 wait: 28903ee3b1eSAlexander Graf /* Indicate that we're ready for a new DMA round */ 29003ee3b1eSAlexander Graf ch->io.processing = false; 29103ee3b1eSAlexander Graf 292ad674e53SAurelien Jarno if ((ch->regs[DBDMA_STATUS] & RUN) && 293ad674e53SAurelien Jarno (ch->regs[DBDMA_STATUS] & ACTIVE)) 294b42ec42dSaurel32 channel_run(ch); 29528ce5ce6Saurel32 } 29628ce5ce6Saurel32 297b42ec42dSaurel32 static void start_output(DBDMA_channel *ch, int key, uint32_t addr, 29828ce5ce6Saurel32 uint16_t req_count, int is_last) 29928ce5ce6Saurel32 { 3003e49c439SMark Cave-Ayland DBDMA_DPRINTFCH(ch, "start_output\n"); 30128ce5ce6Saurel32 30228ce5ce6Saurel32 /* KEY_REGS, KEY_DEVICE and KEY_STREAM 30328ce5ce6Saurel32 * are not implemented in the mac-io chip 30428ce5ce6Saurel32 */ 30528ce5ce6Saurel32 3063e49c439SMark Cave-Ayland DBDMA_DPRINTFCH(ch, "addr 0x%x key 0x%x\n", addr, key); 30728ce5ce6Saurel32 if (!addr || key > KEY_STREAM3) { 30828ce5ce6Saurel32 kill_channel(ch); 309b42ec42dSaurel32 return; 31028ce5ce6Saurel32 } 31128ce5ce6Saurel32 312b42ec42dSaurel32 ch->io.addr = addr; 31328ce5ce6Saurel32 ch->io.len = req_count; 31428ce5ce6Saurel32 ch->io.is_last = is_last; 315b42ec42dSaurel32 ch->io.dma_end = dbdma_end; 316b42ec42dSaurel32 ch->io.is_dma_out = 1; 31703ee3b1eSAlexander Graf ch->io.processing = true; 318a9ceb76dSAlexander Graf if (ch->rw) { 319b42ec42dSaurel32 ch->rw(&ch->io); 32028ce5ce6Saurel32 } 321a9ceb76dSAlexander Graf } 32228ce5ce6Saurel32 323b42ec42dSaurel32 static void start_input(DBDMA_channel *ch, int key, uint32_t addr, 32428ce5ce6Saurel32 uint16_t req_count, int is_last) 32528ce5ce6Saurel32 { 3263e49c439SMark Cave-Ayland DBDMA_DPRINTFCH(ch, "start_input\n"); 32728ce5ce6Saurel32 32828ce5ce6Saurel32 /* KEY_REGS, KEY_DEVICE and KEY_STREAM 32928ce5ce6Saurel32 * are not implemented in the mac-io chip 33028ce5ce6Saurel32 */ 33128ce5ce6Saurel32 3323e49c439SMark Cave-Ayland DBDMA_DPRINTFCH(ch, "addr 0x%x key 0x%x\n", addr, key); 33328ce5ce6Saurel32 if (!addr || key > KEY_STREAM3) { 33428ce5ce6Saurel32 kill_channel(ch); 335b42ec42dSaurel32 return; 33628ce5ce6Saurel32 } 33728ce5ce6Saurel32 338b42ec42dSaurel32 ch->io.addr = addr; 33928ce5ce6Saurel32 ch->io.len = req_count; 34028ce5ce6Saurel32 ch->io.is_last = is_last; 341b42ec42dSaurel32 ch->io.dma_end = dbdma_end; 342b42ec42dSaurel32 ch->io.is_dma_out = 0; 34303ee3b1eSAlexander Graf ch->io.processing = true; 344a9ceb76dSAlexander Graf if (ch->rw) { 345b42ec42dSaurel32 ch->rw(&ch->io); 34628ce5ce6Saurel32 } 347a9ceb76dSAlexander Graf } 34828ce5ce6Saurel32 349b42ec42dSaurel32 static void load_word(DBDMA_channel *ch, int key, uint32_t addr, 35028ce5ce6Saurel32 uint16_t len) 35128ce5ce6Saurel32 { 35228ce5ce6Saurel32 dbdma_cmd *current = &ch->current; 35328ce5ce6Saurel32 uint32_t val; 35428ce5ce6Saurel32 3553e49c439SMark Cave-Ayland DBDMA_DPRINTFCH(ch, "load_word\n"); 35628ce5ce6Saurel32 35728ce5ce6Saurel32 /* only implements KEY_SYSTEM */ 35828ce5ce6Saurel32 35928ce5ce6Saurel32 if (key != KEY_SYSTEM) { 36028ce5ce6Saurel32 printf("DBDMA: LOAD_WORD, unimplemented key %x\n", key); 36128ce5ce6Saurel32 kill_channel(ch); 362b42ec42dSaurel32 return; 36328ce5ce6Saurel32 } 36428ce5ce6Saurel32 36588655881SMark Cave-Ayland dma_memory_read(&address_space_memory, addr, &val, len); 36628ce5ce6Saurel32 36728ce5ce6Saurel32 if (len == 2) 36828ce5ce6Saurel32 val = (val << 16) | (current->cmd_dep & 0x0000ffff); 36928ce5ce6Saurel32 else if (len == 1) 37028ce5ce6Saurel32 val = (val << 24) | (current->cmd_dep & 0x00ffffff); 37128ce5ce6Saurel32 37228ce5ce6Saurel32 current->cmd_dep = val; 37328ce5ce6Saurel32 37428ce5ce6Saurel32 if (conditional_wait(ch)) 375b42ec42dSaurel32 goto wait; 37628ce5ce6Saurel32 377ad674e53SAurelien Jarno current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]); 37828ce5ce6Saurel32 dbdma_cmdptr_save(ch); 379ad674e53SAurelien Jarno ch->regs[DBDMA_STATUS] &= ~FLUSH; 38028ce5ce6Saurel32 38128ce5ce6Saurel32 conditional_interrupt(ch); 38228ce5ce6Saurel32 next(ch); 38328ce5ce6Saurel32 384b42ec42dSaurel32 wait: 385d2f0ce21SAlexander Graf DBDMA_kick(dbdma_from_ch(ch)); 38628ce5ce6Saurel32 } 38728ce5ce6Saurel32 388b42ec42dSaurel32 static void store_word(DBDMA_channel *ch, int key, uint32_t addr, 38928ce5ce6Saurel32 uint16_t len) 39028ce5ce6Saurel32 { 39128ce5ce6Saurel32 dbdma_cmd *current = &ch->current; 39228ce5ce6Saurel32 uint32_t val; 39328ce5ce6Saurel32 3943e49c439SMark Cave-Ayland DBDMA_DPRINTFCH(ch, "store_word\n"); 39528ce5ce6Saurel32 39628ce5ce6Saurel32 /* only implements KEY_SYSTEM */ 39728ce5ce6Saurel32 39828ce5ce6Saurel32 if (key != KEY_SYSTEM) { 39928ce5ce6Saurel32 printf("DBDMA: STORE_WORD, unimplemented key %x\n", key); 40028ce5ce6Saurel32 kill_channel(ch); 401b42ec42dSaurel32 return; 40228ce5ce6Saurel32 } 40328ce5ce6Saurel32 40428ce5ce6Saurel32 val = current->cmd_dep; 40528ce5ce6Saurel32 if (len == 2) 40628ce5ce6Saurel32 val >>= 16; 40728ce5ce6Saurel32 else if (len == 1) 40828ce5ce6Saurel32 val >>= 24; 40928ce5ce6Saurel32 41088655881SMark Cave-Ayland dma_memory_write(&address_space_memory, addr, &val, len); 41128ce5ce6Saurel32 41228ce5ce6Saurel32 if (conditional_wait(ch)) 413b42ec42dSaurel32 goto wait; 41428ce5ce6Saurel32 415ad674e53SAurelien Jarno current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]); 41628ce5ce6Saurel32 dbdma_cmdptr_save(ch); 417ad674e53SAurelien Jarno ch->regs[DBDMA_STATUS] &= ~FLUSH; 41828ce5ce6Saurel32 41928ce5ce6Saurel32 conditional_interrupt(ch); 42028ce5ce6Saurel32 next(ch); 42128ce5ce6Saurel32 422b42ec42dSaurel32 wait: 423d2f0ce21SAlexander Graf DBDMA_kick(dbdma_from_ch(ch)); 42428ce5ce6Saurel32 } 42528ce5ce6Saurel32 426b42ec42dSaurel32 static void nop(DBDMA_channel *ch) 42728ce5ce6Saurel32 { 42828ce5ce6Saurel32 dbdma_cmd *current = &ch->current; 42928ce5ce6Saurel32 43028ce5ce6Saurel32 if (conditional_wait(ch)) 431b42ec42dSaurel32 goto wait; 43228ce5ce6Saurel32 433ad674e53SAurelien Jarno current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]); 43428ce5ce6Saurel32 dbdma_cmdptr_save(ch); 43528ce5ce6Saurel32 43628ce5ce6Saurel32 conditional_interrupt(ch); 43728ce5ce6Saurel32 conditional_branch(ch); 43828ce5ce6Saurel32 439b42ec42dSaurel32 wait: 440d2f0ce21SAlexander Graf DBDMA_kick(dbdma_from_ch(ch)); 44128ce5ce6Saurel32 } 44228ce5ce6Saurel32 443b42ec42dSaurel32 static void stop(DBDMA_channel *ch) 44428ce5ce6Saurel32 { 445ad674e53SAurelien Jarno ch->regs[DBDMA_STATUS] &= ~(ACTIVE|DEAD|FLUSH); 44628ce5ce6Saurel32 44728ce5ce6Saurel32 /* the stop command does not increment command pointer */ 44828ce5ce6Saurel32 } 44928ce5ce6Saurel32 450b42ec42dSaurel32 static void channel_run(DBDMA_channel *ch) 45128ce5ce6Saurel32 { 45228ce5ce6Saurel32 dbdma_cmd *current = &ch->current; 45328ce5ce6Saurel32 uint16_t cmd, key; 45428ce5ce6Saurel32 uint16_t req_count; 45528ce5ce6Saurel32 uint32_t phy_addr; 45628ce5ce6Saurel32 4573e49c439SMark Cave-Ayland DBDMA_DPRINTFCH(ch, "channel_run\n"); 45828ce5ce6Saurel32 dump_dbdma_cmd(current); 45928ce5ce6Saurel32 46028ce5ce6Saurel32 /* clear WAKE flag at command fetch */ 46128ce5ce6Saurel32 462ad674e53SAurelien Jarno ch->regs[DBDMA_STATUS] &= ~WAKE; 46328ce5ce6Saurel32 46428ce5ce6Saurel32 cmd = le16_to_cpu(current->command) & COMMAND_MASK; 46528ce5ce6Saurel32 46628ce5ce6Saurel32 switch (cmd) { 46728ce5ce6Saurel32 case DBDMA_NOP: 468b42ec42dSaurel32 nop(ch); 469b42ec42dSaurel32 return; 47028ce5ce6Saurel32 47128ce5ce6Saurel32 case DBDMA_STOP: 472b42ec42dSaurel32 stop(ch); 473b42ec42dSaurel32 return; 47428ce5ce6Saurel32 } 47528ce5ce6Saurel32 47628ce5ce6Saurel32 key = le16_to_cpu(current->command) & 0x0700; 47728ce5ce6Saurel32 req_count = le16_to_cpu(current->req_count); 47828ce5ce6Saurel32 phy_addr = le32_to_cpu(current->phy_addr); 47928ce5ce6Saurel32 48028ce5ce6Saurel32 if (key == KEY_STREAM4) { 48128ce5ce6Saurel32 printf("command %x, invalid key 4\n", cmd); 48228ce5ce6Saurel32 kill_channel(ch); 483b42ec42dSaurel32 return; 48428ce5ce6Saurel32 } 48528ce5ce6Saurel32 48628ce5ce6Saurel32 switch (cmd) { 48728ce5ce6Saurel32 case OUTPUT_MORE: 488b42ec42dSaurel32 start_output(ch, key, phy_addr, req_count, 0); 489b42ec42dSaurel32 return; 49028ce5ce6Saurel32 49128ce5ce6Saurel32 case OUTPUT_LAST: 492b42ec42dSaurel32 start_output(ch, key, phy_addr, req_count, 1); 493b42ec42dSaurel32 return; 49428ce5ce6Saurel32 49528ce5ce6Saurel32 case INPUT_MORE: 496b42ec42dSaurel32 start_input(ch, key, phy_addr, req_count, 0); 497b42ec42dSaurel32 return; 49828ce5ce6Saurel32 49928ce5ce6Saurel32 case INPUT_LAST: 500b42ec42dSaurel32 start_input(ch, key, phy_addr, req_count, 1); 501b42ec42dSaurel32 return; 50228ce5ce6Saurel32 } 50328ce5ce6Saurel32 50428ce5ce6Saurel32 if (key < KEY_REGS) { 50528ce5ce6Saurel32 printf("command %x, invalid key %x\n", cmd, key); 50628ce5ce6Saurel32 key = KEY_SYSTEM; 50728ce5ce6Saurel32 } 50828ce5ce6Saurel32 50928ce5ce6Saurel32 /* for LOAD_WORD and STORE_WORD, req_count is on 3 bits 51028ce5ce6Saurel32 * and BRANCH is invalid 51128ce5ce6Saurel32 */ 51228ce5ce6Saurel32 51328ce5ce6Saurel32 req_count = req_count & 0x0007; 51428ce5ce6Saurel32 if (req_count & 0x4) { 51528ce5ce6Saurel32 req_count = 4; 51628ce5ce6Saurel32 phy_addr &= ~3; 51728ce5ce6Saurel32 } else if (req_count & 0x2) { 51828ce5ce6Saurel32 req_count = 2; 51928ce5ce6Saurel32 phy_addr &= ~1; 52028ce5ce6Saurel32 } else 52128ce5ce6Saurel32 req_count = 1; 52228ce5ce6Saurel32 52328ce5ce6Saurel32 switch (cmd) { 52428ce5ce6Saurel32 case LOAD_WORD: 525b42ec42dSaurel32 load_word(ch, key, phy_addr, req_count); 526b42ec42dSaurel32 return; 52728ce5ce6Saurel32 52828ce5ce6Saurel32 case STORE_WORD: 529b42ec42dSaurel32 store_word(ch, key, phy_addr, req_count); 530b42ec42dSaurel32 return; 53128ce5ce6Saurel32 } 53228ce5ce6Saurel32 } 53328ce5ce6Saurel32 534c20df14bSJuan Quintela static void DBDMA_run(DBDMAState *s) 53528ce5ce6Saurel32 { 53628ce5ce6Saurel32 int channel; 53728ce5ce6Saurel32 538c20df14bSJuan Quintela for (channel = 0; channel < DBDMA_CHANNELS; channel++) { 539c20df14bSJuan Quintela DBDMA_channel *ch = &s->channels[channel]; 540ad674e53SAurelien Jarno uint32_t status = ch->regs[DBDMA_STATUS]; 54103ee3b1eSAlexander Graf if (!ch->io.processing && (status & RUN) && (status & ACTIVE)) { 542b42ec42dSaurel32 channel_run(ch); 54328ce5ce6Saurel32 } 54428ce5ce6Saurel32 } 545c20df14bSJuan Quintela } 54628ce5ce6Saurel32 54728ce5ce6Saurel32 static void DBDMA_run_bh(void *opaque) 54828ce5ce6Saurel32 { 549c20df14bSJuan Quintela DBDMAState *s = opaque; 55028ce5ce6Saurel32 5513e49c439SMark Cave-Ayland DBDMA_DPRINTF("-> DBDMA_run_bh\n"); 552c20df14bSJuan Quintela DBDMA_run(s); 5533e49c439SMark Cave-Ayland DBDMA_DPRINTF("<- DBDMA_run_bh\n"); 55428ce5ce6Saurel32 } 55528ce5ce6Saurel32 556d1e562deSAlexander Graf void DBDMA_kick(DBDMAState *dbdma) 557d1e562deSAlexander Graf { 558d2f0ce21SAlexander Graf qemu_bh_schedule(dbdma->bh); 559d1e562deSAlexander Graf } 560d1e562deSAlexander Graf 56128ce5ce6Saurel32 void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq, 562862c9280Saurel32 DBDMA_rw rw, DBDMA_flush flush, 56328ce5ce6Saurel32 void *opaque) 56428ce5ce6Saurel32 { 565c20df14bSJuan Quintela DBDMAState *s = dbdma; 566c20df14bSJuan Quintela DBDMA_channel *ch = &s->channels[nchan]; 56728ce5ce6Saurel32 5683e49c439SMark Cave-Ayland DBDMA_DPRINTFCH(ch, "DBDMA_register_channel 0x%x\n", nchan); 56928ce5ce6Saurel32 5702d7d06d8SHervé Poussineau assert(rw); 5712d7d06d8SHervé Poussineau assert(flush); 5722d7d06d8SHervé Poussineau 57328ce5ce6Saurel32 ch->irq = irq; 574b42ec42dSaurel32 ch->rw = rw; 575862c9280Saurel32 ch->flush = flush; 57628ce5ce6Saurel32 ch->io.opaque = opaque; 57728ce5ce6Saurel32 } 57828ce5ce6Saurel32 57928ce5ce6Saurel32 static void 58028ce5ce6Saurel32 dbdma_control_write(DBDMA_channel *ch) 58128ce5ce6Saurel32 { 58228ce5ce6Saurel32 uint16_t mask, value; 58328ce5ce6Saurel32 uint32_t status; 58428ce5ce6Saurel32 585ad674e53SAurelien Jarno mask = (ch->regs[DBDMA_CONTROL] >> 16) & 0xffff; 586ad674e53SAurelien Jarno value = ch->regs[DBDMA_CONTROL] & 0xffff; 58728ce5ce6Saurel32 58828ce5ce6Saurel32 value &= (RUN | PAUSE | FLUSH | WAKE | DEVSTAT); 58928ce5ce6Saurel32 590ad674e53SAurelien Jarno status = ch->regs[DBDMA_STATUS]; 59128ce5ce6Saurel32 59228ce5ce6Saurel32 status = (value & mask) | (status & ~mask); 59328ce5ce6Saurel32 59428ce5ce6Saurel32 if (status & WAKE) 59528ce5ce6Saurel32 status |= ACTIVE; 59628ce5ce6Saurel32 if (status & RUN) { 59728ce5ce6Saurel32 status |= ACTIVE; 59828ce5ce6Saurel32 status &= ~DEAD; 59928ce5ce6Saurel32 } 60028ce5ce6Saurel32 if (status & PAUSE) 60128ce5ce6Saurel32 status &= ~ACTIVE; 602ad674e53SAurelien Jarno if ((ch->regs[DBDMA_STATUS] & RUN) && !(status & RUN)) { 60328ce5ce6Saurel32 /* RUN is cleared */ 60428ce5ce6Saurel32 status &= ~(ACTIVE|DEAD); 6051cde732dSMark Cave-Ayland } 6061cde732dSMark Cave-Ayland 607987422bcSAmadeusz Sławiński if ((status & FLUSH) && ch->flush) { 608987422bcSAmadeusz Sławiński ch->flush(&ch->io); 609987422bcSAmadeusz Sławiński status &= ~FLUSH; 610987422bcSAmadeusz Sławiński } 61128ce5ce6Saurel32 6123e49c439SMark Cave-Ayland DBDMA_DPRINTFCH(ch, " status 0x%08x\n", status); 61328ce5ce6Saurel32 614ad674e53SAurelien Jarno ch->regs[DBDMA_STATUS] = status; 61528ce5ce6Saurel32 616d2f0ce21SAlexander Graf if (status & ACTIVE) { 617d2f0ce21SAlexander Graf DBDMA_kick(dbdma_from_ch(ch)); 618d2f0ce21SAlexander Graf } 619d2f0ce21SAlexander Graf } 6203cbee15bSj_mayer 621a8170e5eSAvi Kivity static void dbdma_write(void *opaque, hwaddr addr, 62223c5e4caSAvi Kivity uint64_t value, unsigned size) 6233cbee15bSj_mayer { 62428ce5ce6Saurel32 int channel = addr >> DBDMA_CHANNEL_SHIFT; 625c20df14bSJuan Quintela DBDMAState *s = opaque; 626c20df14bSJuan Quintela DBDMA_channel *ch = &s->channels[channel]; 62728ce5ce6Saurel32 int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2; 62828ce5ce6Saurel32 6293e49c439SMark Cave-Ayland DBDMA_DPRINTFCH(ch, "writel 0x" TARGET_FMT_plx " <= 0x%08"PRIx64"\n", 63058c0c311SAlexander Graf addr, value); 6313e49c439SMark Cave-Ayland DBDMA_DPRINTFCH(ch, "channel 0x%x reg 0x%x\n", 63228ce5ce6Saurel32 (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg); 63328ce5ce6Saurel32 6347eaba824SAlexander Graf /* cmdptr cannot be modified if channel is ACTIVE */ 63528ce5ce6Saurel32 6367eaba824SAlexander Graf if (reg == DBDMA_CMDPTR_LO && (ch->regs[DBDMA_STATUS] & ACTIVE)) { 63728ce5ce6Saurel32 return; 6387eaba824SAlexander Graf } 63928ce5ce6Saurel32 64028ce5ce6Saurel32 ch->regs[reg] = value; 64128ce5ce6Saurel32 64228ce5ce6Saurel32 switch(reg) { 64328ce5ce6Saurel32 case DBDMA_CONTROL: 64428ce5ce6Saurel32 dbdma_control_write(ch); 64528ce5ce6Saurel32 break; 64628ce5ce6Saurel32 case DBDMA_CMDPTR_LO: 64728ce5ce6Saurel32 /* 16-byte aligned */ 648ad674e53SAurelien Jarno ch->regs[DBDMA_CMDPTR_LO] &= ~0xf; 64928ce5ce6Saurel32 dbdma_cmdptr_load(ch); 65028ce5ce6Saurel32 break; 65128ce5ce6Saurel32 case DBDMA_STATUS: 65228ce5ce6Saurel32 case DBDMA_INTR_SEL: 65328ce5ce6Saurel32 case DBDMA_BRANCH_SEL: 65428ce5ce6Saurel32 case DBDMA_WAIT_SEL: 65528ce5ce6Saurel32 /* nothing to do */ 65628ce5ce6Saurel32 break; 65728ce5ce6Saurel32 case DBDMA_XFER_MODE: 65828ce5ce6Saurel32 case DBDMA_CMDPTR_HI: 65928ce5ce6Saurel32 case DBDMA_DATA2PTR_HI: 66028ce5ce6Saurel32 case DBDMA_DATA2PTR_LO: 66128ce5ce6Saurel32 case DBDMA_ADDRESS_HI: 66228ce5ce6Saurel32 case DBDMA_BRANCH_ADDR_HI: 66328ce5ce6Saurel32 case DBDMA_RES1: 66428ce5ce6Saurel32 case DBDMA_RES2: 66528ce5ce6Saurel32 case DBDMA_RES3: 66628ce5ce6Saurel32 case DBDMA_RES4: 66728ce5ce6Saurel32 /* unused */ 66828ce5ce6Saurel32 break; 6693cbee15bSj_mayer } 6703cbee15bSj_mayer } 6713cbee15bSj_mayer 672a8170e5eSAvi Kivity static uint64_t dbdma_read(void *opaque, hwaddr addr, 67323c5e4caSAvi Kivity unsigned size) 6743cbee15bSj_mayer { 67528ce5ce6Saurel32 uint32_t value; 67628ce5ce6Saurel32 int channel = addr >> DBDMA_CHANNEL_SHIFT; 677c20df14bSJuan Quintela DBDMAState *s = opaque; 678c20df14bSJuan Quintela DBDMA_channel *ch = &s->channels[channel]; 67928ce5ce6Saurel32 int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2; 680ea026b2fSblueswir1 68128ce5ce6Saurel32 value = ch->regs[reg]; 68228ce5ce6Saurel32 6833e49c439SMark Cave-Ayland DBDMA_DPRINTFCH(ch, "readl 0x" TARGET_FMT_plx " => 0x%08x\n", addr, value); 6843e49c439SMark Cave-Ayland DBDMA_DPRINTFCH(ch, "channel 0x%x reg 0x%x\n", 68528ce5ce6Saurel32 (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg); 68628ce5ce6Saurel32 68728ce5ce6Saurel32 switch(reg) { 68828ce5ce6Saurel32 case DBDMA_CONTROL: 68928ce5ce6Saurel32 value = 0; 69028ce5ce6Saurel32 break; 69128ce5ce6Saurel32 case DBDMA_STATUS: 69228ce5ce6Saurel32 case DBDMA_CMDPTR_LO: 69328ce5ce6Saurel32 case DBDMA_INTR_SEL: 69428ce5ce6Saurel32 case DBDMA_BRANCH_SEL: 69528ce5ce6Saurel32 case DBDMA_WAIT_SEL: 69628ce5ce6Saurel32 /* nothing to do */ 69728ce5ce6Saurel32 break; 69828ce5ce6Saurel32 case DBDMA_XFER_MODE: 69928ce5ce6Saurel32 case DBDMA_CMDPTR_HI: 70028ce5ce6Saurel32 case DBDMA_DATA2PTR_HI: 70128ce5ce6Saurel32 case DBDMA_DATA2PTR_LO: 70228ce5ce6Saurel32 case DBDMA_ADDRESS_HI: 70328ce5ce6Saurel32 case DBDMA_BRANCH_ADDR_HI: 70428ce5ce6Saurel32 /* unused */ 70528ce5ce6Saurel32 value = 0; 70628ce5ce6Saurel32 break; 70728ce5ce6Saurel32 case DBDMA_RES1: 70828ce5ce6Saurel32 case DBDMA_RES2: 70928ce5ce6Saurel32 case DBDMA_RES3: 71028ce5ce6Saurel32 case DBDMA_RES4: 71128ce5ce6Saurel32 /* reserved */ 71228ce5ce6Saurel32 break; 71328ce5ce6Saurel32 } 71428ce5ce6Saurel32 71528ce5ce6Saurel32 return value; 7163cbee15bSj_mayer } 7173cbee15bSj_mayer 71823c5e4caSAvi Kivity static const MemoryRegionOps dbdma_ops = { 71923c5e4caSAvi Kivity .read = dbdma_read, 72023c5e4caSAvi Kivity .write = dbdma_write, 72123c5e4caSAvi Kivity .endianness = DEVICE_LITTLE_ENDIAN, 72223c5e4caSAvi Kivity .valid = { 72323c5e4caSAvi Kivity .min_access_size = 4, 72423c5e4caSAvi Kivity .max_access_size = 4, 72523c5e4caSAvi Kivity }, 7263cbee15bSj_mayer }; 7273cbee15bSj_mayer 728627be2f2SMark Cave-Ayland static const VMStateDescription vmstate_dbdma_io = { 729627be2f2SMark Cave-Ayland .name = "dbdma_io", 730da26fdc3SJuan Quintela .version_id = 0, 731da26fdc3SJuan Quintela .minimum_version_id = 0, 732da26fdc3SJuan Quintela .fields = (VMStateField[]) { 733627be2f2SMark Cave-Ayland VMSTATE_UINT64(addr, struct DBDMA_io), 734627be2f2SMark Cave-Ayland VMSTATE_INT32(len, struct DBDMA_io), 735627be2f2SMark Cave-Ayland VMSTATE_INT32(is_last, struct DBDMA_io), 736627be2f2SMark Cave-Ayland VMSTATE_INT32(is_dma_out, struct DBDMA_io), 737627be2f2SMark Cave-Ayland VMSTATE_BOOL(processing, struct DBDMA_io), 738627be2f2SMark Cave-Ayland VMSTATE_END_OF_LIST() 739627be2f2SMark Cave-Ayland } 740627be2f2SMark Cave-Ayland }; 741627be2f2SMark Cave-Ayland 742627be2f2SMark Cave-Ayland static const VMStateDescription vmstate_dbdma_cmd = { 743627be2f2SMark Cave-Ayland .name = "dbdma_cmd", 744627be2f2SMark Cave-Ayland .version_id = 0, 745627be2f2SMark Cave-Ayland .minimum_version_id = 0, 746627be2f2SMark Cave-Ayland .fields = (VMStateField[]) { 747627be2f2SMark Cave-Ayland VMSTATE_UINT16(req_count, dbdma_cmd), 748627be2f2SMark Cave-Ayland VMSTATE_UINT16(command, dbdma_cmd), 749627be2f2SMark Cave-Ayland VMSTATE_UINT32(phy_addr, dbdma_cmd), 750627be2f2SMark Cave-Ayland VMSTATE_UINT32(cmd_dep, dbdma_cmd), 751627be2f2SMark Cave-Ayland VMSTATE_UINT16(res_count, dbdma_cmd), 752627be2f2SMark Cave-Ayland VMSTATE_UINT16(xfer_status, dbdma_cmd), 753627be2f2SMark Cave-Ayland VMSTATE_END_OF_LIST() 754627be2f2SMark Cave-Ayland } 755627be2f2SMark Cave-Ayland }; 756627be2f2SMark Cave-Ayland 757627be2f2SMark Cave-Ayland static const VMStateDescription vmstate_dbdma_channel = { 758627be2f2SMark Cave-Ayland .name = "dbdma_channel", 759627be2f2SMark Cave-Ayland .version_id = 1, 760627be2f2SMark Cave-Ayland .minimum_version_id = 1, 761627be2f2SMark Cave-Ayland .fields = (VMStateField[]) { 762da26fdc3SJuan Quintela VMSTATE_UINT32_ARRAY(regs, struct DBDMA_channel, DBDMA_REGS), 763627be2f2SMark Cave-Ayland VMSTATE_STRUCT(io, struct DBDMA_channel, 0, vmstate_dbdma_io, DBDMA_io), 764627be2f2SMark Cave-Ayland VMSTATE_STRUCT(current, struct DBDMA_channel, 0, vmstate_dbdma_cmd, 765627be2f2SMark Cave-Ayland dbdma_cmd), 766da26fdc3SJuan Quintela VMSTATE_END_OF_LIST() 7679b64997fSblueswir1 } 768da26fdc3SJuan Quintela }; 7699b64997fSblueswir1 770da26fdc3SJuan Quintela static const VMStateDescription vmstate_dbdma = { 771da26fdc3SJuan Quintela .name = "dbdma", 772627be2f2SMark Cave-Ayland .version_id = 3, 773627be2f2SMark Cave-Ayland .minimum_version_id = 3, 774da26fdc3SJuan Quintela .fields = (VMStateField[]) { 775da26fdc3SJuan Quintela VMSTATE_STRUCT_ARRAY(channels, DBDMAState, DBDMA_CHANNELS, 1, 776da26fdc3SJuan Quintela vmstate_dbdma_channel, DBDMA_channel), 777da26fdc3SJuan Quintela VMSTATE_END_OF_LIST() 7789b64997fSblueswir1 } 779da26fdc3SJuan Quintela }; 7809b64997fSblueswir1 7816e6b7363Sblueswir1 static void dbdma_reset(void *opaque) 7826e6b7363Sblueswir1 { 783c20df14bSJuan Quintela DBDMAState *s = opaque; 78428ce5ce6Saurel32 int i; 78528ce5ce6Saurel32 78628ce5ce6Saurel32 for (i = 0; i < DBDMA_CHANNELS; i++) 787c20df14bSJuan Quintela memset(s->channels[i].regs, 0, DBDMA_SIZE); 7886e6b7363Sblueswir1 } 7896e6b7363Sblueswir1 7902d7d06d8SHervé Poussineau static void dbdma_unassigned_rw(DBDMA_io *io) 7912d7d06d8SHervé Poussineau { 7922d7d06d8SHervé Poussineau DBDMA_channel *ch = io->channel; 7932d7d06d8SHervé Poussineau qemu_log_mask(LOG_GUEST_ERROR, "%s: use of unassigned channel %d\n", 7942d7d06d8SHervé Poussineau __func__, ch->channel); 7952d7d06d8SHervé Poussineau } 7962d7d06d8SHervé Poussineau 7972d7d06d8SHervé Poussineau static void dbdma_unassigned_flush(DBDMA_io *io) 7982d7d06d8SHervé Poussineau { 7992d7d06d8SHervé Poussineau DBDMA_channel *ch = io->channel; 8002d7d06d8SHervé Poussineau qemu_log_mask(LOG_GUEST_ERROR, "%s: use of unassigned channel %d\n", 8012d7d06d8SHervé Poussineau __func__, ch->channel); 8022d7d06d8SHervé Poussineau } 8032d7d06d8SHervé Poussineau 80423c5e4caSAvi Kivity void* DBDMA_init (MemoryRegion **dbdma_mem) 8053cbee15bSj_mayer { 806c20df14bSJuan Quintela DBDMAState *s; 8073e300fa6SAlexander Graf int i; 80828ce5ce6Saurel32 8097267c094SAnthony Liguori s = g_malloc0(sizeof(DBDMAState)); 81028ce5ce6Saurel32 8113e300fa6SAlexander Graf for (i = 0; i < DBDMA_CHANNELS; i++) { 8123e300fa6SAlexander Graf DBDMA_io *io = &s->channels[i].io; 8132d7d06d8SHervé Poussineau DBDMA_channel *ch = &s->channels[i]; 8143e300fa6SAlexander Graf qemu_iovec_init(&io->iov, 1); 8152d7d06d8SHervé Poussineau 8162d7d06d8SHervé Poussineau ch->rw = dbdma_unassigned_rw; 8172d7d06d8SHervé Poussineau ch->flush = dbdma_unassigned_flush; 8182d7d06d8SHervé Poussineau ch->channel = i; 8192d7d06d8SHervé Poussineau ch->io.channel = ch; 8203e300fa6SAlexander Graf } 8213e300fa6SAlexander Graf 8222c9b15caSPaolo Bonzini memory_region_init_io(&s->mem, NULL, &dbdma_ops, s, "dbdma", 0x1000); 82323c5e4caSAvi Kivity *dbdma_mem = &s->mem; 824da26fdc3SJuan Quintela vmstate_register(NULL, -1, &vmstate_dbdma, s); 825a08d4367SJan Kiszka qemu_register_reset(dbdma_reset, s); 82628ce5ce6Saurel32 827d2f0ce21SAlexander Graf s->bh = qemu_bh_new(DBDMA_run_bh, s); 82828ce5ce6Saurel32 82928ce5ce6Saurel32 return s; 8303cbee15bSj_mayer } 831