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

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

unix.superglobalmegacorp.com

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