summary refs log tree commit diff stats
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;
 }