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

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: 
                    168: #ifdef DEBUG_DBDMA
                    169: static void dump_dbdma_cmd(dbdma_cmd *cmd)
                    170: {
                    171:     printf("dbdma_cmd %p\n", cmd);
                    172:     printf("    req_count 0x%04x\n", le16_to_cpu(cmd->req_count));
                    173:     printf("    command 0x%04x\n", le16_to_cpu(cmd->command));
                    174:     printf("    phy_addr 0x%08x\n", le32_to_cpu(cmd->phy_addr));
                    175:     printf("    cmd_dep 0x%08x\n", le32_to_cpu(cmd->cmd_dep));
                    176:     printf("    res_count 0x%04x\n", le16_to_cpu(cmd->res_count));
                    177:     printf("    xfer_status 0x%04x\n", le16_to_cpu(cmd->xfer_status));
                    178: }
                    179: #else
                    180: static void dump_dbdma_cmd(dbdma_cmd *cmd)
1.1       root      181: {
1.1.1.2   root      182: }
                    183: #endif
                    184: static void dbdma_cmdptr_load(DBDMA_channel *ch)
                    185: {
                    186:     DBDMA_DPRINTF("dbdma_cmdptr_load 0x%08x\n",
1.1.1.5   root      187:                   ch->regs[DBDMA_CMDPTR_LO]);
                    188:     cpu_physical_memory_read(ch->regs[DBDMA_CMDPTR_LO],
1.1.1.2   root      189:                              (uint8_t*)&ch->current, sizeof(dbdma_cmd));
1.1       root      190: }
                    191: 
1.1.1.2   root      192: static void dbdma_cmdptr_save(DBDMA_channel *ch)
1.1       root      193: {
1.1.1.2   root      194:     DBDMA_DPRINTF("dbdma_cmdptr_save 0x%08x\n",
1.1.1.5   root      195:                   ch->regs[DBDMA_CMDPTR_LO]);
1.1.1.2   root      196:     DBDMA_DPRINTF("xfer_status 0x%08x res_count 0x%04x\n",
                    197:                   le16_to_cpu(ch->current.xfer_status),
                    198:                   le16_to_cpu(ch->current.res_count));
1.1.1.5   root      199:     cpu_physical_memory_write(ch->regs[DBDMA_CMDPTR_LO],
1.1.1.2   root      200:                               (uint8_t*)&ch->current, sizeof(dbdma_cmd));
1.1       root      201: }
                    202: 
1.1.1.2   root      203: static void kill_channel(DBDMA_channel *ch)
1.1       root      204: {
1.1.1.2   root      205:     DBDMA_DPRINTF("kill_channel\n");
                    206: 
1.1.1.5   root      207:     ch->regs[DBDMA_STATUS] |= DEAD;
                    208:     ch->regs[DBDMA_STATUS] &= ~ACTIVE;
1.1.1.2   root      209: 
                    210:     qemu_irq_raise(ch->irq);
1.1       root      211: }
                    212: 
1.1.1.2   root      213: static void conditional_interrupt(DBDMA_channel *ch)
1.1       root      214: {
1.1.1.2   root      215:     dbdma_cmd *current = &ch->current;
                    216:     uint16_t intr;
                    217:     uint16_t sel_mask, sel_value;
                    218:     uint32_t status;
                    219:     int cond;
                    220: 
                    221:     DBDMA_DPRINTF("conditional_interrupt\n");
                    222: 
                    223:     intr = le16_to_cpu(current->command) & INTR_MASK;
                    224: 
                    225:     switch(intr) {
                    226:     case INTR_NEVER:  /* don't interrupt */
                    227:         return;
                    228:     case INTR_ALWAYS: /* always interrupt */
                    229:         qemu_irq_raise(ch->irq);
                    230:         return;
                    231:     }
                    232: 
1.1.1.5   root      233:     status = ch->regs[DBDMA_STATUS] & DEVSTAT;
1.1.1.2   root      234: 
1.1.1.5   root      235:     sel_mask = (ch->regs[DBDMA_INTR_SEL] >> 16) & 0x0f;
                    236:     sel_value = ch->regs[DBDMA_INTR_SEL] & 0x0f;
1.1.1.2   root      237: 
                    238:     cond = (status & sel_mask) == (sel_value & sel_mask);
                    239: 
                    240:     switch(intr) {
                    241:     case INTR_IFSET:  /* intr if condition bit is 1 */
                    242:         if (cond)
                    243:             qemu_irq_raise(ch->irq);
                    244:         return;
                    245:     case INTR_IFCLR:  /* intr if condition bit is 0 */
                    246:         if (!cond)
                    247:             qemu_irq_raise(ch->irq);
                    248:         return;
                    249:     }
                    250: }
1.1       root      251: 
1.1.1.2   root      252: static int conditional_wait(DBDMA_channel *ch)
                    253: {
                    254:     dbdma_cmd *current = &ch->current;
                    255:     uint16_t wait;
                    256:     uint16_t sel_mask, sel_value;
                    257:     uint32_t status;
                    258:     int cond;
                    259: 
                    260:     DBDMA_DPRINTF("conditional_wait\n");
                    261: 
                    262:     wait = le16_to_cpu(current->command) & WAIT_MASK;
                    263: 
                    264:     switch(wait) {
                    265:     case WAIT_NEVER:  /* don't wait */
                    266:         return 0;
                    267:     case WAIT_ALWAYS: /* always wait */
                    268:         return 1;
                    269:     }
                    270: 
1.1.1.5   root      271:     status = ch->regs[DBDMA_STATUS] & DEVSTAT;
1.1.1.2   root      272: 
1.1.1.5   root      273:     sel_mask = (ch->regs[DBDMA_WAIT_SEL] >> 16) & 0x0f;
                    274:     sel_value = ch->regs[DBDMA_WAIT_SEL] & 0x0f;
1.1.1.2   root      275: 
                    276:     cond = (status & sel_mask) == (sel_value & sel_mask);
                    277: 
                    278:     switch(wait) {
                    279:     case WAIT_IFSET:  /* wait if condition bit is 1 */
                    280:         if (cond)
                    281:             return 1;
                    282:         return 0;
                    283:     case WAIT_IFCLR:  /* wait if condition bit is 0 */
                    284:         if (!cond)
                    285:             return 1;
                    286:         return 0;
                    287:     }
1.1       root      288:     return 0;
                    289: }
                    290: 
1.1.1.2   root      291: static void next(DBDMA_channel *ch)
1.1       root      292: {
1.1.1.2   root      293:     uint32_t cp;
                    294: 
1.1.1.5   root      295:     ch->regs[DBDMA_STATUS] &= ~BT;
1.1.1.2   root      296: 
1.1.1.5   root      297:     cp = ch->regs[DBDMA_CMDPTR_LO];
                    298:     ch->regs[DBDMA_CMDPTR_LO] = cp + sizeof(dbdma_cmd);
1.1.1.2   root      299:     dbdma_cmdptr_load(ch);
                    300: }
                    301: 
                    302: static void branch(DBDMA_channel *ch)
                    303: {
                    304:     dbdma_cmd *current = &ch->current;
                    305: 
                    306:     ch->regs[DBDMA_CMDPTR_LO] = current->cmd_dep;
1.1.1.5   root      307:     ch->regs[DBDMA_STATUS] |= BT;
1.1.1.2   root      308:     dbdma_cmdptr_load(ch);
                    309: }
                    310: 
                    311: static void conditional_branch(DBDMA_channel *ch)
                    312: {
                    313:     dbdma_cmd *current = &ch->current;
                    314:     uint16_t br;
                    315:     uint16_t sel_mask, sel_value;
                    316:     uint32_t status;
                    317:     int cond;
                    318: 
                    319:     DBDMA_DPRINTF("conditional_branch\n");
                    320: 
                    321:     /* check if we must branch */
                    322: 
                    323:     br = le16_to_cpu(current->command) & BR_MASK;
                    324: 
                    325:     switch(br) {
                    326:     case BR_NEVER:  /* don't branch */
                    327:         next(ch);
                    328:         return;
                    329:     case BR_ALWAYS: /* always branch */
                    330:         branch(ch);
                    331:         return;
                    332:     }
                    333: 
1.1.1.5   root      334:     status = ch->regs[DBDMA_STATUS] & DEVSTAT;
1.1.1.2   root      335: 
1.1.1.5   root      336:     sel_mask = (ch->regs[DBDMA_BRANCH_SEL] >> 16) & 0x0f;
                    337:     sel_value = ch->regs[DBDMA_BRANCH_SEL] & 0x0f;
1.1.1.2   root      338: 
                    339:     cond = (status & sel_mask) == (sel_value & sel_mask);
                    340: 
                    341:     switch(br) {
                    342:     case BR_IFSET:  /* branch if condition bit is 1 */
                    343:         if (cond)
                    344:             branch(ch);
                    345:         else
                    346:             next(ch);
                    347:         return;
                    348:     case BR_IFCLR:  /* branch if condition bit is 0 */
                    349:         if (!cond)
                    350:             branch(ch);
                    351:         else
                    352:             next(ch);
                    353:         return;
                    354:     }
                    355: }
                    356: 
                    357: static QEMUBH *dbdma_bh;
                    358: static void channel_run(DBDMA_channel *ch);
                    359: 
                    360: static void dbdma_end(DBDMA_io *io)
                    361: {
                    362:     DBDMA_channel *ch = io->channel;
                    363:     dbdma_cmd *current = &ch->current;
                    364: 
                    365:     if (conditional_wait(ch))
                    366:         goto wait;
                    367: 
1.1.1.5   root      368:     current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
                    369:     current->res_count = cpu_to_le16(io->len);
1.1.1.2   root      370:     dbdma_cmdptr_save(ch);
                    371:     if (io->is_last)
1.1.1.5   root      372:         ch->regs[DBDMA_STATUS] &= ~FLUSH;
1.1.1.2   root      373: 
                    374:     conditional_interrupt(ch);
                    375:     conditional_branch(ch);
                    376: 
                    377: wait:
                    378:     ch->processing = 0;
1.1.1.5   root      379:     if ((ch->regs[DBDMA_STATUS] & RUN) &&
                    380:         (ch->regs[DBDMA_STATUS] & ACTIVE))
1.1.1.2   root      381:         channel_run(ch);
                    382: }
                    383: 
                    384: static void start_output(DBDMA_channel *ch, int key, uint32_t addr,
                    385:                         uint16_t req_count, int is_last)
                    386: {
                    387:     DBDMA_DPRINTF("start_output\n");
                    388: 
                    389:     /* KEY_REGS, KEY_DEVICE and KEY_STREAM
                    390:      * are not implemented in the mac-io chip
                    391:      */
                    392: 
                    393:     DBDMA_DPRINTF("addr 0x%x key 0x%x\n", addr, key);
                    394:     if (!addr || key > KEY_STREAM3) {
                    395:         kill_channel(ch);
                    396:         return;
                    397:     }
                    398: 
                    399:     ch->io.addr = addr;
                    400:     ch->io.len = req_count;
                    401:     ch->io.is_last = is_last;
                    402:     ch->io.dma_end = dbdma_end;
                    403:     ch->io.is_dma_out = 1;
                    404:     ch->processing = 1;
1.1.1.5   root      405:     if (ch->rw) {
                    406:         ch->rw(&ch->io);
                    407:     }
1.1.1.2   root      408: }
                    409: 
                    410: static void start_input(DBDMA_channel *ch, int key, uint32_t addr,
                    411:                        uint16_t req_count, int is_last)
                    412: {
                    413:     DBDMA_DPRINTF("start_input\n");
                    414: 
                    415:     /* KEY_REGS, KEY_DEVICE and KEY_STREAM
                    416:      * are not implemented in the mac-io chip
                    417:      */
                    418: 
                    419:     if (!addr || key > KEY_STREAM3) {
                    420:         kill_channel(ch);
                    421:         return;
                    422:     }
                    423: 
                    424:     ch->io.addr = addr;
                    425:     ch->io.len = req_count;
                    426:     ch->io.is_last = is_last;
                    427:     ch->io.dma_end = dbdma_end;
                    428:     ch->io.is_dma_out = 0;
                    429:     ch->processing = 1;
1.1.1.5   root      430:     if (ch->rw) {
                    431:         ch->rw(&ch->io);
                    432:     }
1.1.1.2   root      433: }
                    434: 
                    435: static void load_word(DBDMA_channel *ch, int key, uint32_t addr,
                    436:                      uint16_t len)
                    437: {
                    438:     dbdma_cmd *current = &ch->current;
                    439:     uint32_t val;
                    440: 
                    441:     DBDMA_DPRINTF("load_word\n");
                    442: 
                    443:     /* only implements KEY_SYSTEM */
                    444: 
                    445:     if (key != KEY_SYSTEM) {
                    446:         printf("DBDMA: LOAD_WORD, unimplemented key %x\n", key);
                    447:         kill_channel(ch);
                    448:         return;
                    449:     }
                    450: 
                    451:     cpu_physical_memory_read(addr, (uint8_t*)&val, len);
                    452: 
                    453:     if (len == 2)
                    454:         val = (val << 16) | (current->cmd_dep & 0x0000ffff);
                    455:     else if (len == 1)
                    456:         val = (val << 24) | (current->cmd_dep & 0x00ffffff);
                    457: 
                    458:     current->cmd_dep = val;
                    459: 
                    460:     if (conditional_wait(ch))
                    461:         goto wait;
                    462: 
1.1.1.5   root      463:     current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
1.1.1.2   root      464:     dbdma_cmdptr_save(ch);
1.1.1.5   root      465:     ch->regs[DBDMA_STATUS] &= ~FLUSH;
1.1.1.2   root      466: 
                    467:     conditional_interrupt(ch);
                    468:     next(ch);
                    469: 
                    470: wait:
                    471:     qemu_bh_schedule(dbdma_bh);
                    472: }
                    473: 
                    474: static void store_word(DBDMA_channel *ch, int key, uint32_t addr,
                    475:                       uint16_t len)
                    476: {
                    477:     dbdma_cmd *current = &ch->current;
                    478:     uint32_t val;
                    479: 
                    480:     DBDMA_DPRINTF("store_word\n");
                    481: 
                    482:     /* only implements KEY_SYSTEM */
                    483: 
                    484:     if (key != KEY_SYSTEM) {
                    485:         printf("DBDMA: STORE_WORD, unimplemented key %x\n", key);
                    486:         kill_channel(ch);
                    487:         return;
                    488:     }
                    489: 
                    490:     val = current->cmd_dep;
                    491:     if (len == 2)
                    492:         val >>= 16;
                    493:     else if (len == 1)
                    494:         val >>= 24;
                    495: 
                    496:     cpu_physical_memory_write(addr, (uint8_t*)&val, len);
                    497: 
                    498:     if (conditional_wait(ch))
                    499:         goto wait;
                    500: 
1.1.1.5   root      501:     current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
1.1.1.2   root      502:     dbdma_cmdptr_save(ch);
1.1.1.5   root      503:     ch->regs[DBDMA_STATUS] &= ~FLUSH;
1.1.1.2   root      504: 
                    505:     conditional_interrupt(ch);
                    506:     next(ch);
                    507: 
                    508: wait:
                    509:     qemu_bh_schedule(dbdma_bh);
                    510: }
                    511: 
                    512: static void nop(DBDMA_channel *ch)
                    513: {
                    514:     dbdma_cmd *current = &ch->current;
                    515: 
                    516:     if (conditional_wait(ch))
                    517:         goto wait;
                    518: 
1.1.1.5   root      519:     current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
1.1.1.2   root      520:     dbdma_cmdptr_save(ch);
                    521: 
                    522:     conditional_interrupt(ch);
                    523:     conditional_branch(ch);
                    524: 
                    525: wait:
                    526:     qemu_bh_schedule(dbdma_bh);
                    527: }
                    528: 
                    529: static void stop(DBDMA_channel *ch)
                    530: {
1.1.1.5   root      531:     ch->regs[DBDMA_STATUS] &= ~(ACTIVE|DEAD|FLUSH);
1.1.1.2   root      532: 
                    533:     /* the stop command does not increment command pointer */
                    534: }
                    535: 
                    536: static void channel_run(DBDMA_channel *ch)
                    537: {
                    538:     dbdma_cmd *current = &ch->current;
                    539:     uint16_t cmd, key;
                    540:     uint16_t req_count;
                    541:     uint32_t phy_addr;
                    542: 
                    543:     DBDMA_DPRINTF("channel_run\n");
                    544:     dump_dbdma_cmd(current);
                    545: 
                    546:     /* clear WAKE flag at command fetch */
                    547: 
1.1.1.5   root      548:     ch->regs[DBDMA_STATUS] &= ~WAKE;
1.1.1.2   root      549: 
                    550:     cmd = le16_to_cpu(current->command) & COMMAND_MASK;
                    551: 
                    552:     switch (cmd) {
                    553:     case DBDMA_NOP:
                    554:         nop(ch);
                    555:        return;
                    556: 
                    557:     case DBDMA_STOP:
                    558:         stop(ch);
                    559:        return;
                    560:     }
                    561: 
                    562:     key = le16_to_cpu(current->command) & 0x0700;
                    563:     req_count = le16_to_cpu(current->req_count);
                    564:     phy_addr = le32_to_cpu(current->phy_addr);
                    565: 
                    566:     if (key == KEY_STREAM4) {
                    567:         printf("command %x, invalid key 4\n", cmd);
                    568:         kill_channel(ch);
                    569:         return;
                    570:     }
                    571: 
                    572:     switch (cmd) {
                    573:     case OUTPUT_MORE:
                    574:         start_output(ch, key, phy_addr, req_count, 0);
                    575:        return;
                    576: 
                    577:     case OUTPUT_LAST:
                    578:         start_output(ch, key, phy_addr, req_count, 1);
                    579:        return;
                    580: 
                    581:     case INPUT_MORE:
                    582:         start_input(ch, key, phy_addr, req_count, 0);
                    583:        return;
                    584: 
                    585:     case INPUT_LAST:
                    586:         start_input(ch, key, phy_addr, req_count, 1);
                    587:        return;
                    588:     }
                    589: 
                    590:     if (key < KEY_REGS) {
                    591:         printf("command %x, invalid key %x\n", cmd, key);
                    592:         key = KEY_SYSTEM;
                    593:     }
                    594: 
                    595:     /* for LOAD_WORD and STORE_WORD, req_count is on 3 bits
                    596:      * and BRANCH is invalid
                    597:      */
                    598: 
                    599:     req_count = req_count & 0x0007;
                    600:     if (req_count & 0x4) {
                    601:         req_count = 4;
                    602:         phy_addr &= ~3;
                    603:     } else if (req_count & 0x2) {
                    604:         req_count = 2;
                    605:         phy_addr &= ~1;
                    606:     } else
                    607:         req_count = 1;
                    608: 
                    609:     switch (cmd) {
                    610:     case LOAD_WORD:
                    611:         load_word(ch, key, phy_addr, req_count);
                    612:        return;
                    613: 
                    614:     case STORE_WORD:
                    615:         store_word(ch, key, phy_addr, req_count);
                    616:        return;
                    617:     }
                    618: }
                    619: 
                    620: static void DBDMA_run (DBDMA_channel *ch)
                    621: {
                    622:     int channel;
                    623: 
                    624:     for (channel = 0; channel < DBDMA_CHANNELS; channel++, ch++) {
1.1.1.5   root      625:             uint32_t status = ch->regs[DBDMA_STATUS];
1.1.1.2   root      626:             if (!ch->processing && (status & RUN) && (status & ACTIVE))
                    627:                 channel_run(ch);
                    628:     }
                    629: }
                    630: 
                    631: static void DBDMA_run_bh(void *opaque)
                    632: {
                    633:     DBDMA_channel *ch = opaque;
                    634: 
                    635:     DBDMA_DPRINTF("DBDMA_run_bh\n");
                    636: 
                    637:     DBDMA_run(ch);
                    638: }
                    639: 
                    640: void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
                    641:                             DBDMA_rw rw, DBDMA_flush flush,
                    642:                             void *opaque)
                    643: {
                    644:     DBDMA_channel *ch = ( DBDMA_channel *)dbdma + nchan;
                    645: 
                    646:     DBDMA_DPRINTF("DBDMA_register_channel 0x%x\n", nchan);
                    647: 
                    648:     ch->irq = irq;
                    649:     ch->channel = nchan;
                    650:     ch->rw = rw;
                    651:     ch->flush = flush;
                    652:     ch->io.opaque = opaque;
                    653:     ch->io.channel = ch;
                    654: }
                    655: 
                    656: void DBDMA_schedule(void)
                    657: {
1.1.1.3   root      658:     qemu_notify_event();
1.1.1.2   root      659: }
                    660: 
                    661: static void
                    662: dbdma_control_write(DBDMA_channel *ch)
                    663: {
                    664:     uint16_t mask, value;
                    665:     uint32_t status;
                    666: 
1.1.1.5   root      667:     mask = (ch->regs[DBDMA_CONTROL] >> 16) & 0xffff;
                    668:     value = ch->regs[DBDMA_CONTROL] & 0xffff;
1.1.1.2   root      669: 
                    670:     value &= (RUN | PAUSE | FLUSH | WAKE | DEVSTAT);
                    671: 
1.1.1.5   root      672:     status = ch->regs[DBDMA_STATUS];
1.1.1.2   root      673: 
                    674:     status = (value & mask) | (status & ~mask);
                    675: 
                    676:     if (status & WAKE)
                    677:         status |= ACTIVE;
                    678:     if (status & RUN) {
                    679:         status |= ACTIVE;
                    680:         status &= ~DEAD;
                    681:     }
                    682:     if (status & PAUSE)
                    683:         status &= ~ACTIVE;
1.1.1.5   root      684:     if ((ch->regs[DBDMA_STATUS] & RUN) && !(status & RUN)) {
1.1.1.2   root      685:         /* RUN is cleared */
                    686:         status &= ~(ACTIVE|DEAD);
                    687:     }
                    688: 
                    689:     DBDMA_DPRINTF("    status 0x%08x\n", status);
                    690: 
1.1.1.5   root      691:     ch->regs[DBDMA_STATUS] = status;
1.1.1.2   root      692: 
                    693:     if (status & ACTIVE)
                    694:         qemu_bh_schedule(dbdma_bh);
1.1.1.5   root      695:     if ((status & FLUSH) && ch->flush)
1.1.1.2   root      696:         ch->flush(&ch->io);
                    697: }
                    698: 
                    699: static void dbdma_writel (void *opaque,
                    700:                           target_phys_addr_t addr, uint32_t value)
                    701: {
                    702:     int channel = addr >> DBDMA_CHANNEL_SHIFT;
                    703:     DBDMA_channel *ch = (DBDMA_channel *)opaque + channel;
                    704:     int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
                    705: 
                    706:     DBDMA_DPRINTF("writel 0x" TARGET_FMT_plx " <= 0x%08x\n", addr, value);
                    707:     DBDMA_DPRINTF("channel 0x%x reg 0x%x\n",
                    708:                   (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
                    709: 
                    710:     /* cmdptr cannot be modified if channel is RUN or ACTIVE */
                    711: 
                    712:     if (reg == DBDMA_CMDPTR_LO &&
1.1.1.5   root      713:         (ch->regs[DBDMA_STATUS] & (RUN | ACTIVE)))
1.1.1.2   root      714:        return;
                    715: 
                    716:     ch->regs[reg] = value;
                    717: 
                    718:     switch(reg) {
                    719:     case DBDMA_CONTROL:
                    720:         dbdma_control_write(ch);
                    721:         break;
                    722:     case DBDMA_CMDPTR_LO:
                    723:         /* 16-byte aligned */
1.1.1.5   root      724:         ch->regs[DBDMA_CMDPTR_LO] &= ~0xf;
1.1.1.2   root      725:         dbdma_cmdptr_load(ch);
                    726:         break;
                    727:     case DBDMA_STATUS:
                    728:     case DBDMA_INTR_SEL:
                    729:     case DBDMA_BRANCH_SEL:
                    730:     case DBDMA_WAIT_SEL:
                    731:         /* nothing to do */
                    732:         break;
                    733:     case DBDMA_XFER_MODE:
                    734:     case DBDMA_CMDPTR_HI:
                    735:     case DBDMA_DATA2PTR_HI:
                    736:     case DBDMA_DATA2PTR_LO:
                    737:     case DBDMA_ADDRESS_HI:
                    738:     case DBDMA_BRANCH_ADDR_HI:
                    739:     case DBDMA_RES1:
                    740:     case DBDMA_RES2:
                    741:     case DBDMA_RES3:
                    742:     case DBDMA_RES4:
                    743:         /* unused */
                    744:         break;
                    745:     }
1.1       root      746: }
                    747: 
                    748: static uint32_t dbdma_readl (void *opaque, target_phys_addr_t addr)
                    749: {
1.1.1.2   root      750:     uint32_t value;
                    751:     int channel = addr >> DBDMA_CHANNEL_SHIFT;
                    752:     DBDMA_channel *ch = (DBDMA_channel *)opaque + channel;
                    753:     int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
                    754: 
                    755:     value = ch->regs[reg];
                    756: 
                    757:     DBDMA_DPRINTF("readl 0x" TARGET_FMT_plx " => 0x%08x\n", addr, value);
                    758:     DBDMA_DPRINTF("channel 0x%x reg 0x%x\n",
                    759:                   (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
                    760: 
                    761:     switch(reg) {
                    762:     case DBDMA_CONTROL:
                    763:         value = 0;
                    764:         break;
                    765:     case DBDMA_STATUS:
                    766:     case DBDMA_CMDPTR_LO:
                    767:     case DBDMA_INTR_SEL:
                    768:     case DBDMA_BRANCH_SEL:
                    769:     case DBDMA_WAIT_SEL:
                    770:         /* nothing to do */
                    771:         break;
                    772:     case DBDMA_XFER_MODE:
                    773:     case DBDMA_CMDPTR_HI:
                    774:     case DBDMA_DATA2PTR_HI:
                    775:     case DBDMA_DATA2PTR_LO:
                    776:     case DBDMA_ADDRESS_HI:
                    777:     case DBDMA_BRANCH_ADDR_HI:
                    778:         /* unused */
                    779:         value = 0;
                    780:         break;
                    781:     case DBDMA_RES1:
                    782:     case DBDMA_RES2:
                    783:     case DBDMA_RES3:
                    784:     case DBDMA_RES4:
                    785:         /* reserved */
                    786:         break;
                    787:     }
                    788: 
                    789:     return value;
1.1       root      790: }
                    791: 
1.1.1.4   root      792: static CPUWriteMemoryFunc * const dbdma_write[] = {
1.1.1.2   root      793:     NULL,
                    794:     NULL,
                    795:     dbdma_writel,
1.1       root      796: };
                    797: 
1.1.1.4   root      798: static CPUReadMemoryFunc * const dbdma_read[] = {
1.1.1.2   root      799:     NULL,
                    800:     NULL,
                    801:     dbdma_readl,
1.1       root      802: };
                    803: 
1.1.1.2   root      804: static void dbdma_save(QEMUFile *f, void *opaque)
                    805: {
                    806:     DBDMA_channel *s = opaque;
                    807:     unsigned int i, j;
                    808: 
                    809:     for (i = 0; i < DBDMA_CHANNELS; i++)
                    810:         for (j = 0; j < DBDMA_REGS; j++)
                    811:             qemu_put_be32s(f, &s[i].regs[j]);
                    812: }
                    813: 
                    814: static int dbdma_load(QEMUFile *f, void *opaque, int version_id)
1.1       root      815: {
1.1.1.2   root      816:     DBDMA_channel *s = opaque;
                    817:     unsigned int i, j;
                    818: 
                    819:     if (version_id != 2)
                    820:         return -EINVAL;
                    821: 
                    822:     for (i = 0; i < DBDMA_CHANNELS; i++)
                    823:         for (j = 0; j < DBDMA_REGS; j++)
                    824:             qemu_get_be32s(f, &s[i].regs[j]);
                    825: 
                    826:     return 0;
1.1       root      827: }
                    828: 
1.1.1.2   root      829: static void dbdma_reset(void *opaque)
                    830: {
                    831:     DBDMA_channel *s = opaque;
                    832:     int i;
                    833: 
                    834:     for (i = 0; i < DBDMA_CHANNELS; i++)
                    835:         memset(s[i].regs, 0, DBDMA_SIZE);
                    836: }
                    837: 
                    838: void* DBDMA_init (int *dbdma_mem_index)
                    839: {
                    840:     DBDMA_channel *s;
                    841: 
                    842:     s = qemu_mallocz(sizeof(DBDMA_channel) * DBDMA_CHANNELS);
                    843: 
1.1.1.6 ! root      844:     *dbdma_mem_index = cpu_register_io_memory(dbdma_read, dbdma_write, s,
        !           845:                                               DEVICE_LITTLE_ENDIAN);
1.1.1.5   root      846:     register_savevm(NULL, "dbdma", -1, 1, dbdma_save, dbdma_load, s);
1.1.1.2   root      847:     qemu_register_reset(dbdma_reset, s);
                    848: 
                    849:     dbdma_bh = qemu_bh_new(DBDMA_run_bh, s);
                    850: 
                    851:     return s;
                    852: }

unix.superglobalmegacorp.com

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