aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/dma/sifive_pdma.c177
1 files changed, 155 insertions, 22 deletions
diff --git a/hw/dma/sifive_pdma.c b/hw/dma/sifive_pdma.c
index 85fe34f..f4df164 100644
--- a/hw/dma/sifive_pdma.c
+++ b/hw/dma/sifive_pdma.c
@@ -177,18 +177,44 @@ static inline void sifive_pdma_update_irq(SiFivePDMAState *s, int ch)
s->chan[ch].state = DMA_CHAN_STATE_IDLE;
}
-static uint64_t sifive_pdma_read(void *opaque, hwaddr offset, unsigned size)
+static uint64_t sifive_pdma_readq(SiFivePDMAState *s, int ch, hwaddr offset)
{
- SiFivePDMAState *s = opaque;
- int ch = SIFIVE_PDMA_CHAN_NO(offset);
uint64_t val = 0;
- if (ch >= SIFIVE_PDMA_CHANS) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid channel no %d\n",
- __func__, ch);
- return 0;
+ offset &= 0xfff;
+ switch (offset) {
+ case DMA_NEXT_BYTES:
+ val = s->chan[ch].next_bytes;
+ break;
+ case DMA_NEXT_DST:
+ val = s->chan[ch].next_dst;
+ break;
+ case DMA_NEXT_SRC:
+ val = s->chan[ch].next_src;
+ break;
+ case DMA_EXEC_BYTES:
+ val = s->chan[ch].exec_bytes;
+ break;
+ case DMA_EXEC_DST:
+ val = s->chan[ch].exec_dst;
+ break;
+ case DMA_EXEC_SRC:
+ val = s->chan[ch].exec_src;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Unexpected 64-bit access to 0x%" HWADDR_PRIX "\n",
+ __func__, offset);
+ break;
}
+ return val;
+}
+
+static uint32_t sifive_pdma_readl(SiFivePDMAState *s, int ch, hwaddr offset)
+{
+ uint32_t val = 0;
+
offset &= 0xfff;
switch (offset) {
case DMA_CONTROL:
@@ -198,28 +224,47 @@ static uint64_t sifive_pdma_read(void *opaque, hwaddr offset, unsigned size)
val = s->chan[ch].next_config;
break;
case DMA_NEXT_BYTES:
- val = s->chan[ch].next_bytes;
+ val = extract64(s->chan[ch].next_bytes, 0, 32);
+ break;
+ case DMA_NEXT_BYTES + 4:
+ val = extract64(s->chan[ch].next_bytes, 32, 32);
break;
case DMA_NEXT_DST:
- val = s->chan[ch].next_dst;
+ val = extract64(s->chan[ch].next_dst, 0, 32);
+ break;
+ case DMA_NEXT_DST + 4:
+ val = extract64(s->chan[ch].next_dst, 32, 32);
break;
case DMA_NEXT_SRC:
- val = s->chan[ch].next_src;
+ val = extract64(s->chan[ch].next_src, 0, 32);
+ break;
+ case DMA_NEXT_SRC + 4:
+ val = extract64(s->chan[ch].next_src, 32, 32);
break;
case DMA_EXEC_CONFIG:
val = s->chan[ch].exec_config;
break;
case DMA_EXEC_BYTES:
- val = s->chan[ch].exec_bytes;
+ val = extract64(s->chan[ch].exec_bytes, 0, 32);
+ break;
+ case DMA_EXEC_BYTES + 4:
+ val = extract64(s->chan[ch].exec_bytes, 32, 32);
break;
case DMA_EXEC_DST:
- val = s->chan[ch].exec_dst;
+ val = extract64(s->chan[ch].exec_dst, 0, 32);
+ break;
+ case DMA_EXEC_DST + 4:
+ val = extract64(s->chan[ch].exec_dst, 32, 32);
break;
case DMA_EXEC_SRC:
- val = s->chan[ch].exec_src;
+ val = extract64(s->chan[ch].exec_src, 0, 32);
+ break;
+ case DMA_EXEC_SRC + 4:
+ val = extract64(s->chan[ch].exec_src, 32, 32);
break;
default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Unexpected 32-bit access to 0x%" HWADDR_PRIX "\n",
__func__, offset);
break;
}
@@ -227,19 +272,66 @@ static uint64_t sifive_pdma_read(void *opaque, hwaddr offset, unsigned size)
return val;
}
-static void sifive_pdma_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
+static uint64_t sifive_pdma_read(void *opaque, hwaddr offset, unsigned size)
{
SiFivePDMAState *s = opaque;
int ch = SIFIVE_PDMA_CHAN_NO(offset);
- bool claimed, run;
+ uint64_t val = 0;
if (ch >= SIFIVE_PDMA_CHANS) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid channel no %d\n",
__func__, ch);
- return;
+ return 0;
+ }
+
+ switch (size) {
+ case 8:
+ val = sifive_pdma_readq(s, ch, offset);
+ break;
+ case 4:
+ val = sifive_pdma_readl(s, ch, offset);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid read size %u to PDMA\n",
+ __func__, size);
+ return 0;
}
+ return val;
+}
+
+static void sifive_pdma_writeq(SiFivePDMAState *s, int ch,
+ hwaddr offset, uint64_t value)
+{
+ offset &= 0xfff;
+ switch (offset) {
+ case DMA_NEXT_BYTES:
+ s->chan[ch].next_bytes = value;
+ break;
+ case DMA_NEXT_DST:
+ s->chan[ch].next_dst = value;
+ break;
+ case DMA_NEXT_SRC:
+ s->chan[ch].next_src = value;
+ break;
+ case DMA_EXEC_BYTES:
+ case DMA_EXEC_DST:
+ case DMA_EXEC_SRC:
+ /* these are read-only registers */
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Unexpected 64-bit access to 0x%" HWADDR_PRIX "\n",
+ __func__, offset);
+ break;
+ }
+}
+
+static void sifive_pdma_writel(SiFivePDMAState *s, int ch,
+ hwaddr offset, uint32_t value)
+{
+ bool claimed, run;
+
offset &= 0xfff;
switch (offset) {
case DMA_CONTROL:
@@ -282,27 +374,68 @@ static void sifive_pdma_write(void *opaque, hwaddr offset,
s->chan[ch].next_config = value;
break;
case DMA_NEXT_BYTES:
- s->chan[ch].next_bytes = value;
+ s->chan[ch].next_bytes =
+ deposit64(s->chan[ch].next_bytes, 0, 32, value);
+ break;
+ case DMA_NEXT_BYTES + 4:
+ s->chan[ch].next_bytes =
+ deposit64(s->chan[ch].next_bytes, 32, 32, value);
break;
case DMA_NEXT_DST:
- s->chan[ch].next_dst = value;
+ s->chan[ch].next_dst = deposit64(s->chan[ch].next_dst, 0, 32, value);
+ break;
+ case DMA_NEXT_DST + 4:
+ s->chan[ch].next_dst = deposit64(s->chan[ch].next_dst, 32, 32, value);
break;
case DMA_NEXT_SRC:
- s->chan[ch].next_src = value;
+ s->chan[ch].next_src = deposit64(s->chan[ch].next_src, 0, 32, value);
+ break;
+ case DMA_NEXT_SRC + 4:
+ s->chan[ch].next_src = deposit64(s->chan[ch].next_src, 32, 32, value);
break;
case DMA_EXEC_CONFIG:
case DMA_EXEC_BYTES:
+ case DMA_EXEC_BYTES + 4:
case DMA_EXEC_DST:
+ case DMA_EXEC_DST + 4:
case DMA_EXEC_SRC:
+ case DMA_EXEC_SRC + 4:
/* these are read-only registers */
break;
default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Unexpected 32-bit access to 0x%" HWADDR_PRIX "\n",
__func__, offset);
break;
}
}
+static void sifive_pdma_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ SiFivePDMAState *s = opaque;
+ int ch = SIFIVE_PDMA_CHAN_NO(offset);
+
+ if (ch >= SIFIVE_PDMA_CHANS) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid channel no %d\n",
+ __func__, ch);
+ return;
+ }
+
+ switch (size) {
+ case 8:
+ sifive_pdma_writeq(s, ch, offset, value);
+ break;
+ case 4:
+ sifive_pdma_writel(s, ch, offset, (uint32_t) value);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid write size %u to PDMA\n",
+ __func__, size);
+ break;
+ }
+}
+
static const MemoryRegionOps sifive_pdma_ops = {
.read = sifive_pdma_read,
.write = sifive_pdma_write,