aboutsummaryrefslogtreecommitdiff
path: root/hw/misc/macio/mac_dbdma.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/misc/macio/mac_dbdma.c')
-rw-r--r--hw/misc/macio/mac_dbdma.c193
1 files changed, 49 insertions, 144 deletions
diff --git a/hw/misc/macio/mac_dbdma.c b/hw/misc/macio/mac_dbdma.c
index a1d7862a66..f47a736182 100644
--- a/hw/misc/macio/mac_dbdma.c
+++ b/hw/misc/macio/mac_dbdma.c
@@ -54,122 +54,10 @@
/*
*/
-/*
- * DBDMA control/status registers. All little-endian.
- */
-
-#define DBDMA_CONTROL 0x00
-#define DBDMA_STATUS 0x01
-#define DBDMA_CMDPTR_HI 0x02
-#define DBDMA_CMDPTR_LO 0x03
-#define DBDMA_INTR_SEL 0x04
-#define DBDMA_BRANCH_SEL 0x05
-#define DBDMA_WAIT_SEL 0x06
-#define DBDMA_XFER_MODE 0x07
-#define DBDMA_DATA2PTR_HI 0x08
-#define DBDMA_DATA2PTR_LO 0x09
-#define DBDMA_RES1 0x0A
-#define DBDMA_ADDRESS_HI 0x0B
-#define DBDMA_BRANCH_ADDR_HI 0x0C
-#define DBDMA_RES2 0x0D
-#define DBDMA_RES3 0x0E
-#define DBDMA_RES4 0x0F
-
-#define DBDMA_REGS 16
-#define DBDMA_SIZE (DBDMA_REGS * sizeof(uint32_t))
-
-#define DBDMA_CHANNEL_SHIFT 7
-#define DBDMA_CHANNEL_SIZE (1 << DBDMA_CHANNEL_SHIFT)
-
-#define DBDMA_CHANNELS (0x1000 >> DBDMA_CHANNEL_SHIFT)
-
-/* Bits in control and status registers */
-
-#define RUN 0x8000
-#define PAUSE 0x4000
-#define FLUSH 0x2000
-#define WAKE 0x1000
-#define DEAD 0x0800
-#define ACTIVE 0x0400
-#define BT 0x0100
-#define DEVSTAT 0x00ff
-
-/*
- * DBDMA command structure. These fields are all little-endian!
- */
-
-typedef struct dbdma_cmd {
- uint16_t req_count; /* requested byte transfer count */
- uint16_t command; /* command word (has bit-fields) */
- uint32_t phy_addr; /* physical data address */
- uint32_t cmd_dep; /* command-dependent field */
- uint16_t res_count; /* residual count after completion */
- uint16_t xfer_status; /* transfer status */
-} dbdma_cmd;
-
-/* DBDMA command values in command field */
-
-#define COMMAND_MASK 0xf000
-#define OUTPUT_MORE 0x0000 /* transfer memory data to stream */
-#define OUTPUT_LAST 0x1000 /* ditto followed by end marker */
-#define INPUT_MORE 0x2000 /* transfer stream data to memory */
-#define INPUT_LAST 0x3000 /* ditto, expect end marker */
-#define STORE_WORD 0x4000 /* write word (4 bytes) to device reg */
-#define LOAD_WORD 0x5000 /* read word (4 bytes) from device reg */
-#define DBDMA_NOP 0x6000 /* do nothing */
-#define DBDMA_STOP 0x7000 /* suspend processing */
-
-/* Key values in command field */
-
-#define KEY_MASK 0x0700
-#define KEY_STREAM0 0x0000 /* usual data stream */
-#define KEY_STREAM1 0x0100 /* control/status stream */
-#define KEY_STREAM2 0x0200 /* device-dependent stream */
-#define KEY_STREAM3 0x0300 /* device-dependent stream */
-#define KEY_STREAM4 0x0400 /* reserved */
-#define KEY_REGS 0x0500 /* device register space */
-#define KEY_SYSTEM 0x0600 /* system memory-mapped space */
-#define KEY_DEVICE 0x0700 /* device memory-mapped space */
-
-/* Interrupt control values in command field */
-
-#define INTR_MASK 0x0030
-#define INTR_NEVER 0x0000 /* don't interrupt */
-#define INTR_IFSET 0x0010 /* intr if condition bit is 1 */
-#define INTR_IFCLR 0x0020 /* intr if condition bit is 0 */
-#define INTR_ALWAYS 0x0030 /* always interrupt */
-
-/* Branch control values in command field */
-
-#define BR_MASK 0x000c
-#define BR_NEVER 0x0000 /* don't branch */
-#define BR_IFSET 0x0004 /* branch if condition bit is 1 */
-#define BR_IFCLR 0x0008 /* branch if condition bit is 0 */
-#define BR_ALWAYS 0x000c /* always branch */
-
-/* Wait control values in command field */
-
-#define WAIT_MASK 0x0003
-#define WAIT_NEVER 0x0000 /* don't wait */
-#define WAIT_IFSET 0x0001 /* wait if condition bit is 1 */
-#define WAIT_IFCLR 0x0002 /* wait if condition bit is 0 */
-#define WAIT_ALWAYS 0x0003 /* always wait */
-
-typedef struct DBDMA_channel {
- int channel;
- uint32_t regs[DBDMA_REGS];
- qemu_irq irq;
- DBDMA_io io;
- DBDMA_rw rw;
- DBDMA_flush flush;
- dbdma_cmd current;
- int processing;
-} DBDMA_channel;
-
-typedef struct {
- MemoryRegion mem;
- DBDMA_channel channels[DBDMA_CHANNELS];
-} DBDMAState;
+static DBDMAState *dbdma_from_ch(DBDMA_channel *ch)
+{
+ return container_of(ch, DBDMAState, channels[ch->channel]);
+}
#ifdef DEBUG_DBDMA
static void dump_dbdma_cmd(dbdma_cmd *cmd)
@@ -224,7 +112,7 @@ static void conditional_interrupt(DBDMA_channel *ch)
uint32_t status;
int cond;
- DBDMA_DPRINTF("conditional_interrupt\n");
+ DBDMA_DPRINTF("%s\n", __func__);
intr = le16_to_cpu(current->command) & INTR_MASK;
@@ -233,6 +121,7 @@ static void conditional_interrupt(DBDMA_channel *ch)
return;
case INTR_ALWAYS: /* always interrupt */
qemu_irq_raise(ch->irq);
+ DBDMA_DPRINTF("%s: raise\n", __func__);
return;
}
@@ -245,12 +134,16 @@ static void conditional_interrupt(DBDMA_channel *ch)
switch(intr) {
case INTR_IFSET: /* intr if condition bit is 1 */
- if (cond)
+ if (cond) {
qemu_irq_raise(ch->irq);
+ DBDMA_DPRINTF("%s: raise\n", __func__);
+ }
return;
case INTR_IFCLR: /* intr if condition bit is 0 */
- if (!cond)
+ if (!cond) {
qemu_irq_raise(ch->irq);
+ DBDMA_DPRINTF("%s: raise\n", __func__);
+ }
return;
}
}
@@ -360,7 +253,6 @@ static void conditional_branch(DBDMA_channel *ch)
}
}
-static QEMUBH *dbdma_bh;
static void channel_run(DBDMA_channel *ch);
static void dbdma_end(DBDMA_io *io)
@@ -368,6 +260,8 @@ static void dbdma_end(DBDMA_io *io)
DBDMA_channel *ch = io->channel;
dbdma_cmd *current = &ch->current;
+ DBDMA_DPRINTF("%s\n", __func__);
+
if (conditional_wait(ch))
goto wait;
@@ -381,7 +275,9 @@ static void dbdma_end(DBDMA_io *io)
conditional_branch(ch);
wait:
- ch->processing = 0;
+ /* Indicate that we're ready for a new DMA round */
+ ch->io.processing = false;
+
if ((ch->regs[DBDMA_STATUS] & RUN) &&
(ch->regs[DBDMA_STATUS] & ACTIVE))
channel_run(ch);
@@ -407,7 +303,7 @@ static void start_output(DBDMA_channel *ch, int key, uint32_t addr,
ch->io.is_last = is_last;
ch->io.dma_end = dbdma_end;
ch->io.is_dma_out = 1;
- ch->processing = 1;
+ ch->io.processing = true;
if (ch->rw) {
ch->rw(&ch->io);
}
@@ -422,6 +318,7 @@ static void start_input(DBDMA_channel *ch, int key, uint32_t addr,
* are not implemented in the mac-io chip
*/
+ DBDMA_DPRINTF("addr 0x%x key 0x%x\n", addr, key);
if (!addr || key > KEY_STREAM3) {
kill_channel(ch);
return;
@@ -432,7 +329,7 @@ static void start_input(DBDMA_channel *ch, int key, uint32_t addr,
ch->io.is_last = is_last;
ch->io.dma_end = dbdma_end;
ch->io.is_dma_out = 0;
- ch->processing = 1;
+ ch->io.processing = true;
if (ch->rw) {
ch->rw(&ch->io);
}
@@ -474,7 +371,7 @@ static void load_word(DBDMA_channel *ch, int key, uint32_t addr,
next(ch);
wait:
- qemu_bh_schedule(dbdma_bh);
+ DBDMA_kick(dbdma_from_ch(ch));
}
static void store_word(DBDMA_channel *ch, int key, uint32_t addr,
@@ -512,7 +409,7 @@ static void store_word(DBDMA_channel *ch, int key, uint32_t addr,
next(ch);
wait:
- qemu_bh_schedule(dbdma_bh);
+ DBDMA_kick(dbdma_from_ch(ch));
}
static void nop(DBDMA_channel *ch)
@@ -529,7 +426,7 @@ static void nop(DBDMA_channel *ch)
conditional_branch(ch);
wait:
- qemu_bh_schedule(dbdma_bh);
+ DBDMA_kick(dbdma_from_ch(ch));
}
static void stop(DBDMA_channel *ch)
@@ -558,11 +455,11 @@ static void channel_run(DBDMA_channel *ch)
switch (cmd) {
case DBDMA_NOP:
nop(ch);
- return;
+ return;
case DBDMA_STOP:
stop(ch);
- return;
+ return;
}
key = le16_to_cpu(current->command) & 0x0700;
@@ -578,19 +475,19 @@ static void channel_run(DBDMA_channel *ch)
switch (cmd) {
case OUTPUT_MORE:
start_output(ch, key, phy_addr, req_count, 0);
- return;
+ return;
case OUTPUT_LAST:
start_output(ch, key, phy_addr, req_count, 1);
- return;
+ return;
case INPUT_MORE:
start_input(ch, key, phy_addr, req_count, 0);
- return;
+ return;
case INPUT_LAST:
start_input(ch, key, phy_addr, req_count, 1);
- return;
+ return;
}
if (key < KEY_REGS) {
@@ -615,11 +512,11 @@ static void channel_run(DBDMA_channel *ch)
switch (cmd) {
case LOAD_WORD:
load_word(ch, key, phy_addr, req_count);
- return;
+ return;
case STORE_WORD:
store_word(ch, key, phy_addr, req_count);
- return;
+ return;
}
}
@@ -630,7 +527,7 @@ static void DBDMA_run(DBDMAState *s)
for (channel = 0; channel < DBDMA_CHANNELS; channel++) {
DBDMA_channel *ch = &s->channels[channel];
uint32_t status = ch->regs[DBDMA_STATUS];
- if (!ch->processing && (status & RUN) && (status & ACTIVE)) {
+ if (!ch->io.processing && (status & RUN) && (status & ACTIVE)) {
channel_run(ch);
}
}
@@ -645,6 +542,11 @@ static void DBDMA_run_bh(void *opaque)
DBDMA_run(s);
}
+void DBDMA_kick(DBDMAState *dbdma)
+{
+ qemu_bh_schedule(dbdma->bh);
+}
+
void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
DBDMA_rw rw, DBDMA_flush flush,
void *opaque)
@@ -698,10 +600,12 @@ dbdma_control_write(DBDMA_channel *ch)
ch->regs[DBDMA_STATUS] = status;
- if (status & ACTIVE)
- qemu_bh_schedule(dbdma_bh);
- if ((status & FLUSH) && ch->flush)
+ if (status & ACTIVE) {
+ DBDMA_kick(dbdma_from_ch(ch));
+ }
+ if ((status & FLUSH) && ch->flush) {
ch->flush(&ch->io);
+ }
}
static void dbdma_write(void *opaque, hwaddr addr,
@@ -712,15 +616,16 @@ static void dbdma_write(void *opaque, hwaddr addr,
DBDMA_channel *ch = &s->channels[channel];
int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
- DBDMA_DPRINTF("writel 0x" TARGET_FMT_plx " <= 0x%08x\n", addr, value);
+ DBDMA_DPRINTF("writel 0x" TARGET_FMT_plx " <= 0x%08"PRIx64"\n",
+ addr, value);
DBDMA_DPRINTF("channel 0x%x reg 0x%x\n",
(uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
- /* cmdptr cannot be modified if channel is RUN or ACTIVE */
+ /* cmdptr cannot be modified if channel is ACTIVE */
- if (reg == DBDMA_CMDPTR_LO &&
- (ch->regs[DBDMA_STATUS] & (RUN | ACTIVE)))
- return;
+ if (reg == DBDMA_CMDPTR_LO && (ch->regs[DBDMA_STATUS] & ACTIVE)) {
+ return;
+ }
ch->regs[reg] = value;
@@ -853,7 +758,7 @@ void* DBDMA_init (MemoryRegion **dbdma_mem)
vmstate_register(NULL, -1, &vmstate_dbdma, s);
qemu_register_reset(dbdma_reset, s);
- dbdma_bh = qemu_bh_new(DBDMA_run_bh, s);
+ s->bh = qemu_bh_new(DBDMA_run_bh, s);
return s;
}