|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.