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

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
        !            47: #define DBDMA_DPRINTF(fmt, args...) \
        !            48: do { printf("DBDMA: " fmt , ##args); } while (0)
        !            49: #else
        !            50: #define DBDMA_DPRINTF(fmt, args...)
        !            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",
        !           187:                   be32_to_cpu(ch->regs[DBDMA_CMDPTR_LO]));
        !           188:     cpu_physical_memory_read(be32_to_cpu(ch->regs[DBDMA_CMDPTR_LO]),
        !           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",
        !           195:                   be32_to_cpu(ch->regs[DBDMA_CMDPTR_LO]));
        !           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));
        !           199:     cpu_physical_memory_write(be32_to_cpu(ch->regs[DBDMA_CMDPTR_LO]),
        !           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: 
        !           207:     ch->regs[DBDMA_STATUS] |= cpu_to_be32(DEAD);
        !           208:     ch->regs[DBDMA_STATUS] &= cpu_to_be32(~ACTIVE);
        !           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: 
        !           233:     status = be32_to_cpu(ch->regs[DBDMA_STATUS]) & DEVSTAT;
        !           234: 
        !           235:     sel_mask = (be32_to_cpu(ch->regs[DBDMA_INTR_SEL]) >> 16) & 0x0f;
        !           236:     sel_value = be32_to_cpu(ch->regs[DBDMA_INTR_SEL]) & 0x0f;
        !           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: 
        !           271:     status = be32_to_cpu(ch->regs[DBDMA_STATUS]) & DEVSTAT;
        !           272: 
        !           273:     sel_mask = (be32_to_cpu(ch->regs[DBDMA_WAIT_SEL]) >> 16) & 0x0f;
        !           274:     sel_value = be32_to_cpu(ch->regs[DBDMA_WAIT_SEL]) & 0x0f;
        !           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: 
        !           295:     ch->regs[DBDMA_STATUS] &= cpu_to_be32(~BT);
        !           296: 
        !           297:     cp = be32_to_cpu(ch->regs[DBDMA_CMDPTR_LO]);
        !           298:     ch->regs[DBDMA_CMDPTR_LO] = cpu_to_be32(cp + sizeof(dbdma_cmd));
        !           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;
        !           307:     ch->regs[DBDMA_STATUS] |= cpu_to_be32(BT);
        !           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: 
        !           334:     status = be32_to_cpu(ch->regs[DBDMA_STATUS]) & DEVSTAT;
        !           335: 
        !           336:     sel_mask = (be32_to_cpu(ch->regs[DBDMA_BRANCH_SEL]) >> 16) & 0x0f;
        !           337:     sel_value = be32_to_cpu(ch->regs[DBDMA_BRANCH_SEL]) & 0x0f;
        !           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: 
        !           368:     current->xfer_status = cpu_to_le16(be32_to_cpu(ch->regs[DBDMA_STATUS]));
        !           369:     current->res_count = cpu_to_le16(be32_to_cpu(io->len));
        !           370:     dbdma_cmdptr_save(ch);
        !           371:     if (io->is_last)
        !           372:         ch->regs[DBDMA_STATUS] &= cpu_to_be32(~FLUSH);
        !           373: 
        !           374:     conditional_interrupt(ch);
        !           375:     conditional_branch(ch);
        !           376: 
        !           377: wait:
        !           378:     ch->processing = 0;
        !           379:     if ((ch->regs[DBDMA_STATUS] & cpu_to_be32(RUN)) &&
        !           380:         (ch->regs[DBDMA_STATUS] & cpu_to_be32(ACTIVE)))
        !           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;
        !           405:     ch->rw(&ch->io);
        !           406: }
        !           407: 
        !           408: static void start_input(DBDMA_channel *ch, int key, uint32_t addr,
        !           409:                        uint16_t req_count, int is_last)
        !           410: {
        !           411:     DBDMA_DPRINTF("start_input\n");
        !           412: 
        !           413:     /* KEY_REGS, KEY_DEVICE and KEY_STREAM
        !           414:      * are not implemented in the mac-io chip
        !           415:      */
        !           416: 
        !           417:     if (!addr || key > KEY_STREAM3) {
        !           418:         kill_channel(ch);
        !           419:         return;
        !           420:     }
        !           421: 
        !           422:     ch->io.addr = addr;
        !           423:     ch->io.len = req_count;
        !           424:     ch->io.is_last = is_last;
        !           425:     ch->io.dma_end = dbdma_end;
        !           426:     ch->io.is_dma_out = 0;
        !           427:     ch->processing = 1;
        !           428:     ch->rw(&ch->io);
        !           429: }
        !           430: 
        !           431: static void load_word(DBDMA_channel *ch, int key, uint32_t addr,
        !           432:                      uint16_t len)
        !           433: {
        !           434:     dbdma_cmd *current = &ch->current;
        !           435:     uint32_t val;
        !           436: 
        !           437:     DBDMA_DPRINTF("load_word\n");
        !           438: 
        !           439:     /* only implements KEY_SYSTEM */
        !           440: 
        !           441:     if (key != KEY_SYSTEM) {
        !           442:         printf("DBDMA: LOAD_WORD, unimplemented key %x\n", key);
        !           443:         kill_channel(ch);
        !           444:         return;
        !           445:     }
        !           446: 
        !           447:     cpu_physical_memory_read(addr, (uint8_t*)&val, len);
        !           448: 
        !           449:     if (len == 2)
        !           450:         val = (val << 16) | (current->cmd_dep & 0x0000ffff);
        !           451:     else if (len == 1)
        !           452:         val = (val << 24) | (current->cmd_dep & 0x00ffffff);
        !           453: 
        !           454:     current->cmd_dep = val;
        !           455: 
        !           456:     if (conditional_wait(ch))
        !           457:         goto wait;
        !           458: 
        !           459:     current->xfer_status = cpu_to_le16(be32_to_cpu(ch->regs[DBDMA_STATUS]));
        !           460:     dbdma_cmdptr_save(ch);
        !           461:     ch->regs[DBDMA_STATUS] &= cpu_to_be32(~FLUSH);
        !           462: 
        !           463:     conditional_interrupt(ch);
        !           464:     next(ch);
        !           465: 
        !           466: wait:
        !           467:     qemu_bh_schedule(dbdma_bh);
        !           468: }
        !           469: 
        !           470: static void store_word(DBDMA_channel *ch, int key, uint32_t addr,
        !           471:                       uint16_t len)
        !           472: {
        !           473:     dbdma_cmd *current = &ch->current;
        !           474:     uint32_t val;
        !           475: 
        !           476:     DBDMA_DPRINTF("store_word\n");
        !           477: 
        !           478:     /* only implements KEY_SYSTEM */
        !           479: 
        !           480:     if (key != KEY_SYSTEM) {
        !           481:         printf("DBDMA: STORE_WORD, unimplemented key %x\n", key);
        !           482:         kill_channel(ch);
        !           483:         return;
        !           484:     }
        !           485: 
        !           486:     val = current->cmd_dep;
        !           487:     if (len == 2)
        !           488:         val >>= 16;
        !           489:     else if (len == 1)
        !           490:         val >>= 24;
        !           491: 
        !           492:     cpu_physical_memory_write(addr, (uint8_t*)&val, len);
        !           493: 
        !           494:     if (conditional_wait(ch))
        !           495:         goto wait;
        !           496: 
        !           497:     current->xfer_status = cpu_to_le16(be32_to_cpu(ch->regs[DBDMA_STATUS]));
        !           498:     dbdma_cmdptr_save(ch);
        !           499:     ch->regs[DBDMA_STATUS] &= cpu_to_be32(~FLUSH);
        !           500: 
        !           501:     conditional_interrupt(ch);
        !           502:     next(ch);
        !           503: 
        !           504: wait:
        !           505:     qemu_bh_schedule(dbdma_bh);
        !           506: }
        !           507: 
        !           508: static void nop(DBDMA_channel *ch)
        !           509: {
        !           510:     dbdma_cmd *current = &ch->current;
        !           511: 
        !           512:     if (conditional_wait(ch))
        !           513:         goto wait;
        !           514: 
        !           515:     current->xfer_status = cpu_to_le16(be32_to_cpu(ch->regs[DBDMA_STATUS]));
        !           516:     dbdma_cmdptr_save(ch);
        !           517: 
        !           518:     conditional_interrupt(ch);
        !           519:     conditional_branch(ch);
        !           520: 
        !           521: wait:
        !           522:     qemu_bh_schedule(dbdma_bh);
        !           523: }
        !           524: 
        !           525: static void stop(DBDMA_channel *ch)
        !           526: {
        !           527:     ch->regs[DBDMA_STATUS] &= cpu_to_be32(~(ACTIVE|DEAD|FLUSH));
        !           528: 
        !           529:     /* the stop command does not increment command pointer */
        !           530: }
        !           531: 
        !           532: static void channel_run(DBDMA_channel *ch)
        !           533: {
        !           534:     dbdma_cmd *current = &ch->current;
        !           535:     uint16_t cmd, key;
        !           536:     uint16_t req_count;
        !           537:     uint32_t phy_addr;
        !           538: 
        !           539:     DBDMA_DPRINTF("channel_run\n");
        !           540:     dump_dbdma_cmd(current);
        !           541: 
        !           542:     /* clear WAKE flag at command fetch */
        !           543: 
        !           544:     ch->regs[DBDMA_STATUS] &= cpu_to_be32(~WAKE);
        !           545: 
        !           546:     cmd = le16_to_cpu(current->command) & COMMAND_MASK;
        !           547: 
        !           548:     switch (cmd) {
        !           549:     case DBDMA_NOP:
        !           550:         nop(ch);
        !           551:        return;
        !           552: 
        !           553:     case DBDMA_STOP:
        !           554:         stop(ch);
        !           555:        return;
        !           556:     }
        !           557: 
        !           558:     key = le16_to_cpu(current->command) & 0x0700;
        !           559:     req_count = le16_to_cpu(current->req_count);
        !           560:     phy_addr = le32_to_cpu(current->phy_addr);
        !           561: 
        !           562:     if (key == KEY_STREAM4) {
        !           563:         printf("command %x, invalid key 4\n", cmd);
        !           564:         kill_channel(ch);
        !           565:         return;
        !           566:     }
        !           567: 
        !           568:     switch (cmd) {
        !           569:     case OUTPUT_MORE:
        !           570:         start_output(ch, key, phy_addr, req_count, 0);
        !           571:        return;
        !           572: 
        !           573:     case OUTPUT_LAST:
        !           574:         start_output(ch, key, phy_addr, req_count, 1);
        !           575:        return;
        !           576: 
        !           577:     case INPUT_MORE:
        !           578:         start_input(ch, key, phy_addr, req_count, 0);
        !           579:        return;
        !           580: 
        !           581:     case INPUT_LAST:
        !           582:         start_input(ch, key, phy_addr, req_count, 1);
        !           583:        return;
        !           584:     }
        !           585: 
        !           586:     if (key < KEY_REGS) {
        !           587:         printf("command %x, invalid key %x\n", cmd, key);
        !           588:         key = KEY_SYSTEM;
        !           589:     }
        !           590: 
        !           591:     /* for LOAD_WORD and STORE_WORD, req_count is on 3 bits
        !           592:      * and BRANCH is invalid
        !           593:      */
        !           594: 
        !           595:     req_count = req_count & 0x0007;
        !           596:     if (req_count & 0x4) {
        !           597:         req_count = 4;
        !           598:         phy_addr &= ~3;
        !           599:     } else if (req_count & 0x2) {
        !           600:         req_count = 2;
        !           601:         phy_addr &= ~1;
        !           602:     } else
        !           603:         req_count = 1;
        !           604: 
        !           605:     switch (cmd) {
        !           606:     case LOAD_WORD:
        !           607:         load_word(ch, key, phy_addr, req_count);
        !           608:        return;
        !           609: 
        !           610:     case STORE_WORD:
        !           611:         store_word(ch, key, phy_addr, req_count);
        !           612:        return;
        !           613:     }
        !           614: }
        !           615: 
        !           616: static void DBDMA_run (DBDMA_channel *ch)
        !           617: {
        !           618:     int channel;
        !           619: 
        !           620:     for (channel = 0; channel < DBDMA_CHANNELS; channel++, ch++) {
        !           621:             uint32_t status = be32_to_cpu(ch->regs[DBDMA_STATUS]);
        !           622:             if (!ch->processing && (status & RUN) && (status & ACTIVE))
        !           623:                 channel_run(ch);
        !           624:     }
        !           625: }
        !           626: 
        !           627: static void DBDMA_run_bh(void *opaque)
        !           628: {
        !           629:     DBDMA_channel *ch = opaque;
        !           630: 
        !           631:     DBDMA_DPRINTF("DBDMA_run_bh\n");
        !           632: 
        !           633:     DBDMA_run(ch);
        !           634: }
        !           635: 
        !           636: void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
        !           637:                             DBDMA_rw rw, DBDMA_flush flush,
        !           638:                             void *opaque)
        !           639: {
        !           640:     DBDMA_channel *ch = ( DBDMA_channel *)dbdma + nchan;
        !           641: 
        !           642:     DBDMA_DPRINTF("DBDMA_register_channel 0x%x\n", nchan);
        !           643: 
        !           644:     ch->irq = irq;
        !           645:     ch->channel = nchan;
        !           646:     ch->rw = rw;
        !           647:     ch->flush = flush;
        !           648:     ch->io.opaque = opaque;
        !           649:     ch->io.channel = ch;
        !           650: }
        !           651: 
        !           652: void DBDMA_schedule(void)
        !           653: {
        !           654:     CPUState *env = cpu_single_env;
        !           655:     if (env)
        !           656:         cpu_interrupt(env, CPU_INTERRUPT_EXIT);
        !           657: }
        !           658: 
        !           659: static void
        !           660: dbdma_control_write(DBDMA_channel *ch)
        !           661: {
        !           662:     uint16_t mask, value;
        !           663:     uint32_t status;
        !           664: 
        !           665:     mask = (be32_to_cpu(ch->regs[DBDMA_CONTROL]) >> 16) & 0xffff;
        !           666:     value = be32_to_cpu(ch->regs[DBDMA_CONTROL]) & 0xffff;
        !           667: 
        !           668:     value &= (RUN | PAUSE | FLUSH | WAKE | DEVSTAT);
        !           669: 
        !           670:     status = be32_to_cpu(ch->regs[DBDMA_STATUS]);
        !           671: 
        !           672:     status = (value & mask) | (status & ~mask);
        !           673: 
        !           674:     if (status & WAKE)
        !           675:         status |= ACTIVE;
        !           676:     if (status & RUN) {
        !           677:         status |= ACTIVE;
        !           678:         status &= ~DEAD;
        !           679:     }
        !           680:     if (status & PAUSE)
        !           681:         status &= ~ACTIVE;
        !           682:     if ((be32_to_cpu(ch->regs[DBDMA_STATUS]) & RUN) && !(status & RUN)) {
        !           683:         /* RUN is cleared */
        !           684:         status &= ~(ACTIVE|DEAD);
        !           685:     }
        !           686: 
        !           687:     DBDMA_DPRINTF("    status 0x%08x\n", status);
        !           688: 
        !           689:     ch->regs[DBDMA_STATUS] = cpu_to_be32(status);
        !           690: 
        !           691:     if (status & ACTIVE)
        !           692:         qemu_bh_schedule(dbdma_bh);
        !           693:     if (status & FLUSH)
        !           694:         ch->flush(&ch->io);
        !           695: }
        !           696: 
        !           697: static void dbdma_writel (void *opaque,
        !           698:                           target_phys_addr_t addr, uint32_t value)
        !           699: {
        !           700:     int channel = addr >> DBDMA_CHANNEL_SHIFT;
        !           701:     DBDMA_channel *ch = (DBDMA_channel *)opaque + channel;
        !           702:     int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
        !           703: 
        !           704:     DBDMA_DPRINTF("writel 0x" TARGET_FMT_plx " <= 0x%08x\n", addr, value);
        !           705:     DBDMA_DPRINTF("channel 0x%x reg 0x%x\n",
        !           706:                   (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
        !           707: 
        !           708:     /* cmdptr cannot be modified if channel is RUN or ACTIVE */
        !           709: 
        !           710:     if (reg == DBDMA_CMDPTR_LO &&
        !           711:         (ch->regs[DBDMA_STATUS] & cpu_to_be32(RUN | ACTIVE)))
        !           712:        return;
        !           713: 
        !           714:     ch->regs[reg] = value;
        !           715: 
        !           716:     switch(reg) {
        !           717:     case DBDMA_CONTROL:
        !           718:         dbdma_control_write(ch);
        !           719:         break;
        !           720:     case DBDMA_CMDPTR_LO:
        !           721:         /* 16-byte aligned */
        !           722:         ch->regs[DBDMA_CMDPTR_LO] &= cpu_to_be32(~0xf);
        !           723:         dbdma_cmdptr_load(ch);
        !           724:         break;
        !           725:     case DBDMA_STATUS:
        !           726:     case DBDMA_INTR_SEL:
        !           727:     case DBDMA_BRANCH_SEL:
        !           728:     case DBDMA_WAIT_SEL:
        !           729:         /* nothing to do */
        !           730:         break;
        !           731:     case DBDMA_XFER_MODE:
        !           732:     case DBDMA_CMDPTR_HI:
        !           733:     case DBDMA_DATA2PTR_HI:
        !           734:     case DBDMA_DATA2PTR_LO:
        !           735:     case DBDMA_ADDRESS_HI:
        !           736:     case DBDMA_BRANCH_ADDR_HI:
        !           737:     case DBDMA_RES1:
        !           738:     case DBDMA_RES2:
        !           739:     case DBDMA_RES3:
        !           740:     case DBDMA_RES4:
        !           741:         /* unused */
        !           742:         break;
        !           743:     }
1.1       root      744: }
                    745: 
                    746: static uint32_t dbdma_readl (void *opaque, target_phys_addr_t addr)
                    747: {
1.1.1.2 ! root      748:     uint32_t value;
        !           749:     int channel = addr >> DBDMA_CHANNEL_SHIFT;
        !           750:     DBDMA_channel *ch = (DBDMA_channel *)opaque + channel;
        !           751:     int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
        !           752: 
        !           753:     value = ch->regs[reg];
        !           754: 
        !           755:     DBDMA_DPRINTF("readl 0x" TARGET_FMT_plx " => 0x%08x\n", addr, value);
        !           756:     DBDMA_DPRINTF("channel 0x%x reg 0x%x\n",
        !           757:                   (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
        !           758: 
        !           759:     switch(reg) {
        !           760:     case DBDMA_CONTROL:
        !           761:         value = 0;
        !           762:         break;
        !           763:     case DBDMA_STATUS:
        !           764:     case DBDMA_CMDPTR_LO:
        !           765:     case DBDMA_INTR_SEL:
        !           766:     case DBDMA_BRANCH_SEL:
        !           767:     case DBDMA_WAIT_SEL:
        !           768:         /* nothing to do */
        !           769:         break;
        !           770:     case DBDMA_XFER_MODE:
        !           771:     case DBDMA_CMDPTR_HI:
        !           772:     case DBDMA_DATA2PTR_HI:
        !           773:     case DBDMA_DATA2PTR_LO:
        !           774:     case DBDMA_ADDRESS_HI:
        !           775:     case DBDMA_BRANCH_ADDR_HI:
        !           776:         /* unused */
        !           777:         value = 0;
        !           778:         break;
        !           779:     case DBDMA_RES1:
        !           780:     case DBDMA_RES2:
        !           781:     case DBDMA_RES3:
        !           782:     case DBDMA_RES4:
        !           783:         /* reserved */
        !           784:         break;
        !           785:     }
        !           786: 
        !           787:     return value;
1.1       root      788: }
                    789: 
                    790: static CPUWriteMemoryFunc *dbdma_write[] = {
1.1.1.2 ! root      791:     NULL,
        !           792:     NULL,
        !           793:     dbdma_writel,
1.1       root      794: };
                    795: 
                    796: static CPUReadMemoryFunc *dbdma_read[] = {
1.1.1.2 ! root      797:     NULL,
        !           798:     NULL,
        !           799:     dbdma_readl,
1.1       root      800: };
                    801: 
1.1.1.2 ! root      802: static void dbdma_save(QEMUFile *f, void *opaque)
        !           803: {
        !           804:     DBDMA_channel *s = opaque;
        !           805:     unsigned int i, j;
        !           806: 
        !           807:     for (i = 0; i < DBDMA_CHANNELS; i++)
        !           808:         for (j = 0; j < DBDMA_REGS; j++)
        !           809:             qemu_put_be32s(f, &s[i].regs[j]);
        !           810: }
        !           811: 
        !           812: static int dbdma_load(QEMUFile *f, void *opaque, int version_id)
1.1       root      813: {
1.1.1.2 ! root      814:     DBDMA_channel *s = opaque;
        !           815:     unsigned int i, j;
        !           816: 
        !           817:     if (version_id != 2)
        !           818:         return -EINVAL;
        !           819: 
        !           820:     for (i = 0; i < DBDMA_CHANNELS; i++)
        !           821:         for (j = 0; j < DBDMA_REGS; j++)
        !           822:             qemu_get_be32s(f, &s[i].regs[j]);
        !           823: 
        !           824:     return 0;
1.1       root      825: }
                    826: 
1.1.1.2 ! root      827: static void dbdma_reset(void *opaque)
        !           828: {
        !           829:     DBDMA_channel *s = opaque;
        !           830:     int i;
        !           831: 
        !           832:     for (i = 0; i < DBDMA_CHANNELS; i++)
        !           833:         memset(s[i].regs, 0, DBDMA_SIZE);
        !           834: }
        !           835: 
        !           836: void* DBDMA_init (int *dbdma_mem_index)
        !           837: {
        !           838:     DBDMA_channel *s;
        !           839: 
        !           840:     s = qemu_mallocz(sizeof(DBDMA_channel) * DBDMA_CHANNELS);
        !           841: 
        !           842:     *dbdma_mem_index = cpu_register_io_memory(0, dbdma_read, dbdma_write, s);
        !           843:     register_savevm("dbdma", -1, 1, dbdma_save, dbdma_load, s);
        !           844:     qemu_register_reset(dbdma_reset, s);
        !           845:     dbdma_reset(s);
        !           846: 
        !           847:     dbdma_bh = qemu_bh_new(DBDMA_run_bh, s);
        !           848: 
        !           849:     return s;
        !           850: }

unix.superglobalmegacorp.com

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