23
#include "qemu/osdep.h"
24
#include "qemu/bitops.h"
26
#include "qapi/error.h"
28
#include "hw/qdev-properties.h"
30
#include "migration/vmstate.h"
31
#include "sysemu/dma.h"
32
#include "hw/dma/sifive_pdma.h"
34
#define DMA_CONTROL 0x000
35
#define CONTROL_CLAIM BIT(0)
36
#define CONTROL_RUN BIT(1)
37
#define CONTROL_DONE_IE BIT(14)
38
#define CONTROL_ERR_IE BIT(15)
39
#define CONTROL_DONE BIT(30)
40
#define CONTROL_ERR BIT(31)
42
#define DMA_NEXT_CONFIG 0x004
43
#define CONFIG_REPEAT BIT(2)
44
#define CONFIG_ORDER BIT(3)
45
#define CONFIG_WRSZ_SHIFT 24
46
#define CONFIG_RDSZ_SHIFT 28
47
#define CONFIG_SZ_MASK 0xf
49
#define DMA_NEXT_BYTES 0x008
50
#define DMA_NEXT_DST 0x010
51
#define DMA_NEXT_SRC 0x018
52
#define DMA_EXEC_CONFIG 0x104
53
#define DMA_EXEC_BYTES 0x108
54
#define DMA_EXEC_DST 0x110
55
#define DMA_EXEC_SRC 0x118
61
#define CONFIG_WRSZ_DEFAULT 6
62
#define CONFIG_RDSZ_DEFAULT 6
66
DMA_CHAN_STATE_STARTED,
71
static void sifive_pdma_run(SiFivePDMAState *s, int ch)
73
uint64_t bytes = s->chan[ch].next_bytes;
74
uint64_t dst = s->chan[ch].next_dst;
75
uint64_t src = s->chan[ch].next_src;
76
uint32_t config = s->chan[ch].next_config;
77
int wsize, rsize, size, remainder;
92
wsize = (config >> CONFIG_WRSZ_SHIFT) & CONFIG_SZ_MASK;
93
rsize = (config >> CONFIG_RDSZ_SHIFT) & CONFIG_SZ_MASK;
109
remainder = bytes % size;
112
s->chan[ch].state = DMA_CHAN_STATE_STARTED;
113
s->chan[ch].control &= ~CONTROL_DONE;
114
s->chan[ch].control &= ~CONTROL_ERR;
117
s->chan[ch].exec_config = config;
118
s->chan[ch].exec_bytes = bytes;
119
s->chan[ch].exec_dst = dst;
120
s->chan[ch].exec_src = src;
122
for (n = 0; n < bytes / size; n++) {
123
cpu_physical_memory_read(s->chan[ch].exec_src, buf, size);
124
cpu_physical_memory_write(s->chan[ch].exec_dst, buf, size);
125
s->chan[ch].exec_src += size;
126
s->chan[ch].exec_dst += size;
127
s->chan[ch].exec_bytes -= size;
131
cpu_physical_memory_read(s->chan[ch].exec_src, buf, remainder);
132
cpu_physical_memory_write(s->chan[ch].exec_dst, buf, remainder);
133
s->chan[ch].exec_src += remainder;
134
s->chan[ch].exec_dst += remainder;
135
s->chan[ch].exec_bytes -= remainder;
139
if (s->chan[ch].next_config & CONFIG_REPEAT) {
140
s->chan[ch].exec_bytes = bytes;
141
s->chan[ch].exec_dst = dst;
142
s->chan[ch].exec_src = src;
147
s->chan[ch].state = DMA_CHAN_STATE_DONE;
148
s->chan[ch].control &= ~CONTROL_RUN;
149
s->chan[ch].control |= CONTROL_DONE;
153
s->chan[ch].state = DMA_CHAN_STATE_ERROR;
154
s->chan[ch].control |= CONTROL_ERR;
158
static inline void sifive_pdma_update_irq(SiFivePDMAState *s, int ch)
160
bool done_ie, err_ie;
162
done_ie = !!(s->chan[ch].control & CONTROL_DONE_IE);
163
err_ie = !!(s->chan[ch].control & CONTROL_ERR_IE);
165
if (done_ie && (s->chan[ch].control & CONTROL_DONE)) {
166
qemu_irq_raise(s->irq[ch * 2]);
168
qemu_irq_lower(s->irq[ch * 2]);
171
if (err_ie && (s->chan[ch].control & CONTROL_ERR)) {
172
qemu_irq_raise(s->irq[ch * 2 + 1]);
174
qemu_irq_lower(s->irq[ch * 2 + 1]);
177
s->chan[ch].state = DMA_CHAN_STATE_IDLE;
180
static uint64_t sifive_pdma_readq(SiFivePDMAState *s, int ch, hwaddr offset)
187
val = s->chan[ch].next_bytes;
190
val = s->chan[ch].next_dst;
193
val = s->chan[ch].next_src;
196
val = s->chan[ch].exec_bytes;
199
val = s->chan[ch].exec_dst;
202
val = s->chan[ch].exec_src;
205
qemu_log_mask(LOG_GUEST_ERROR,
206
"%s: Unexpected 64-bit access to 0x%" HWADDR_PRIX "\n",
214
static uint32_t sifive_pdma_readl(SiFivePDMAState *s, int ch, hwaddr offset)
221
val = s->chan[ch].control;
223
case DMA_NEXT_CONFIG:
224
val = s->chan[ch].next_config;
227
val = extract64(s->chan[ch].next_bytes, 0, 32);
229
case DMA_NEXT_BYTES + 4:
230
val = extract64(s->chan[ch].next_bytes, 32, 32);
233
val = extract64(s->chan[ch].next_dst, 0, 32);
235
case DMA_NEXT_DST + 4:
236
val = extract64(s->chan[ch].next_dst, 32, 32);
239
val = extract64(s->chan[ch].next_src, 0, 32);
241
case DMA_NEXT_SRC + 4:
242
val = extract64(s->chan[ch].next_src, 32, 32);
244
case DMA_EXEC_CONFIG:
245
val = s->chan[ch].exec_config;
248
val = extract64(s->chan[ch].exec_bytes, 0, 32);
250
case DMA_EXEC_BYTES + 4:
251
val = extract64(s->chan[ch].exec_bytes, 32, 32);
254
val = extract64(s->chan[ch].exec_dst, 0, 32);
256
case DMA_EXEC_DST + 4:
257
val = extract64(s->chan[ch].exec_dst, 32, 32);
260
val = extract64(s->chan[ch].exec_src, 0, 32);
262
case DMA_EXEC_SRC + 4:
263
val = extract64(s->chan[ch].exec_src, 32, 32);
266
qemu_log_mask(LOG_GUEST_ERROR,
267
"%s: Unexpected 32-bit access to 0x%" HWADDR_PRIX "\n",
275
static uint64_t sifive_pdma_read(void *opaque, hwaddr offset, unsigned size)
277
SiFivePDMAState *s = opaque;
278
int ch = SIFIVE_PDMA_CHAN_NO(offset);
281
if (ch >= SIFIVE_PDMA_CHANS) {
282
qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid channel no %d\n",
289
val = sifive_pdma_readq(s, ch, offset);
292
val = sifive_pdma_readl(s, ch, offset);
295
qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid read size %u to PDMA\n",
303
static void sifive_pdma_writeq(SiFivePDMAState *s, int ch,
304
hwaddr offset, uint64_t value)
309
s->chan[ch].next_bytes = value;
312
s->chan[ch].next_dst = value;
315
s->chan[ch].next_src = value;
323
qemu_log_mask(LOG_GUEST_ERROR,
324
"%s: Unexpected 64-bit access to 0x%" HWADDR_PRIX "\n",
330
static void sifive_pdma_writel(SiFivePDMAState *s, int ch,
331
hwaddr offset, uint32_t value)
338
claimed = !!(s->chan[ch].control & CONTROL_CLAIM);
339
run = !!(s->chan[ch].control & CONTROL_RUN);
341
if (!claimed && (value & CONTROL_CLAIM)) {
343
s->chan[ch].next_config = (CONFIG_RDSZ_DEFAULT << CONFIG_RDSZ_SHIFT) |
344
(CONFIG_WRSZ_DEFAULT << CONFIG_WRSZ_SHIFT);
345
s->chan[ch].next_bytes = 0;
346
s->chan[ch].next_dst = 0;
347
s->chan[ch].next_src = 0;
351
if (run && !(value & CONTROL_CLAIM)) {
352
value |= CONTROL_CLAIM;
355
s->chan[ch].control = value;
362
if (!claimed || (!run && !(value & CONTROL_CLAIM))) {
363
s->chan[ch].control &= ~CONTROL_RUN;
367
if (value & CONTROL_RUN) {
368
sifive_pdma_run(s, ch);
371
sifive_pdma_update_irq(s, ch);
373
case DMA_NEXT_CONFIG:
374
s->chan[ch].next_config = value;
377
s->chan[ch].next_bytes =
378
deposit64(s->chan[ch].next_bytes, 0, 32, value);
380
case DMA_NEXT_BYTES + 4:
381
s->chan[ch].next_bytes =
382
deposit64(s->chan[ch].next_bytes, 32, 32, value);
385
s->chan[ch].next_dst = deposit64(s->chan[ch].next_dst, 0, 32, value);
387
case DMA_NEXT_DST + 4:
388
s->chan[ch].next_dst = deposit64(s->chan[ch].next_dst, 32, 32, value);
391
s->chan[ch].next_src = deposit64(s->chan[ch].next_src, 0, 32, value);
393
case DMA_NEXT_SRC + 4:
394
s->chan[ch].next_src = deposit64(s->chan[ch].next_src, 32, 32, value);
396
case DMA_EXEC_CONFIG:
398
case DMA_EXEC_BYTES + 4:
400
case DMA_EXEC_DST + 4:
402
case DMA_EXEC_SRC + 4:
406
qemu_log_mask(LOG_GUEST_ERROR,
407
"%s: Unexpected 32-bit access to 0x%" HWADDR_PRIX "\n",
413
static void sifive_pdma_write(void *opaque, hwaddr offset,
414
uint64_t value, unsigned size)
416
SiFivePDMAState *s = opaque;
417
int ch = SIFIVE_PDMA_CHAN_NO(offset);
419
if (ch >= SIFIVE_PDMA_CHANS) {
420
qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid channel no %d\n",
427
sifive_pdma_writeq(s, ch, offset, value);
430
sifive_pdma_writel(s, ch, offset, (uint32_t) value);
433
qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid write size %u to PDMA\n",
439
static const MemoryRegionOps sifive_pdma_ops = {
440
.read = sifive_pdma_read,
441
.write = sifive_pdma_write,
442
.endianness = DEVICE_LITTLE_ENDIAN,
445
.min_access_size = 4,
446
.max_access_size = 8,
449
.min_access_size = 4,
450
.max_access_size = 8,
454
static void sifive_pdma_realize(DeviceState *dev, Error **errp)
456
SiFivePDMAState *s = SIFIVE_PDMA(dev);
459
memory_region_init_io(&s->iomem, OBJECT(dev), &sifive_pdma_ops, s,
460
TYPE_SIFIVE_PDMA, SIFIVE_PDMA_REG_SIZE);
461
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
463
for (i = 0; i < SIFIVE_PDMA_IRQS; i++) {
464
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]);
468
static void sifive_pdma_class_init(ObjectClass *klass, void *data)
470
DeviceClass *dc = DEVICE_CLASS(klass);
472
dc->desc = "SiFive Platform DMA controller";
473
dc->realize = sifive_pdma_realize;
476
static const TypeInfo sifive_pdma_info = {
477
.name = TYPE_SIFIVE_PDMA,
478
.parent = TYPE_SYS_BUS_DEVICE,
479
.instance_size = sizeof(SiFivePDMAState),
480
.class_init = sifive_pdma_class_init,
483
static void sifive_pdma_register_types(void)
485
type_register_static(&sifive_pdma_info);
488
type_init(sifive_pdma_register_types)