Annotation of qemu/hw/mac_dbdma.c, revision 1.1.1.7

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.