20
#include "qemu/osdep.h"
21
#include "qemu/error-report.h"
22
#include "qemu/timer.h"
23
#include "hw/arm/soc_dma.h"
25
static void transfer_mem2mem(struct soc_dma_ch_s *ch)
27
memcpy(ch->paddr[0], ch->paddr[1], ch->bytes);
28
ch->paddr[0] += ch->bytes;
29
ch->paddr[1] += ch->bytes;
32
static void transfer_mem2fifo(struct soc_dma_ch_s *ch)
34
ch->io_fn[1](ch->io_opaque[1], ch->paddr[0], ch->bytes);
35
ch->paddr[0] += ch->bytes;
38
static void transfer_fifo2mem(struct soc_dma_ch_s *ch)
40
ch->io_fn[0](ch->io_opaque[0], ch->paddr[1], ch->bytes);
41
ch->paddr[1] += ch->bytes;
49
static void transfer_fifo2fifo(struct soc_dma_ch_s *ch)
51
if (ch->bytes > fifo_size)
52
fifo_buf = g_realloc(fifo_buf, fifo_size = ch->bytes);
55
ch->io_fn[0](ch->io_opaque[0], fifo_buf, ch->bytes);
56
ch->io_fn[1](ch->io_opaque[1], fifo_buf, ch->bytes);
62
uint64_t ch_enable_mask;
66
struct memmap_entry_s {
67
enum soc_dma_port_type type;
83
struct soc_dma_ch_s ch[];
86
static void soc_dma_ch_schedule(struct soc_dma_ch_s *ch, int delay_bytes)
88
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
89
struct dma_s *dma = (struct dma_s *) ch->dma;
91
timer_mod(ch->timer, now + delay_bytes / dma->channel_freq);
94
static void soc_dma_ch_run(void *opaque)
96
struct soc_dma_ch_s *ch = (struct soc_dma_ch_s *) opaque;
99
ch->dma->setup_fn(ch);
104
soc_dma_ch_schedule(ch, ch->bytes);
108
static inline struct memmap_entry_s *soc_dma_lookup(struct dma_s *dma,
111
struct memmap_entry_s *lo;
115
hi = dma->memmap_size;
119
if (lo[hi].addr <= addr)
126
static inline enum soc_dma_port_type soc_dma_ch_update_type(
127
struct soc_dma_ch_s *ch, int port)
129
struct dma_s *dma = (struct dma_s *) ch->dma;
130
struct memmap_entry_s *entry = soc_dma_lookup(dma, ch->vaddr[port]);
132
if (entry->type == soc_dma_port_fifo) {
133
while (entry < dma->memmap + dma->memmap_size &&
134
entry->u.fifo.out != port)
136
if (entry->addr != ch->vaddr[port] || entry->u.fifo.out != port)
137
return soc_dma_port_other;
139
if (ch->type[port] != soc_dma_access_const)
140
return soc_dma_port_other;
142
ch->io_fn[port] = entry->u.fifo.fn;
143
ch->io_opaque[port] = entry->u.fifo.opaque;
144
return soc_dma_port_fifo;
145
} else if (entry->type == soc_dma_port_mem) {
146
if (entry->addr > ch->vaddr[port] ||
147
entry->addr + entry->u.mem.size <= ch->vaddr[port])
148
return soc_dma_port_other;
152
if (ch->type[port] != soc_dma_access_const)
153
return soc_dma_port_other;
155
ch->paddr[port] = (uint8_t *) entry->u.mem.base +
156
(ch->vaddr[port] - entry->addr);
159
return soc_dma_port_mem;
161
return soc_dma_port_other;
164
void soc_dma_ch_update(struct soc_dma_ch_s *ch)
166
enum soc_dma_port_type src, dst;
168
src = soc_dma_ch_update_type(ch, 0);
169
if (src == soc_dma_port_other) {
171
ch->transfer_fn = ch->dma->transfer_fn;
174
dst = soc_dma_ch_update_type(ch, 1);
177
if (src == soc_dma_port_mem && dst == soc_dma_port_mem)
178
ch->transfer_fn = transfer_mem2mem;
179
else if (src == soc_dma_port_mem && dst == soc_dma_port_fifo)
180
ch->transfer_fn = transfer_mem2fifo;
181
else if (src == soc_dma_port_fifo && dst == soc_dma_port_mem)
182
ch->transfer_fn = transfer_fifo2mem;
183
else if (src == soc_dma_port_fifo && dst == soc_dma_port_fifo)
184
ch->transfer_fn = transfer_fifo2fifo;
186
ch->transfer_fn = ch->dma->transfer_fn;
188
ch->update = (dst != soc_dma_port_other);
191
static void soc_dma_ch_freq_update(struct dma_s *s)
193
if (s->enabled_count)
195
s->channel_freq = s->soc.freq / s->enabled_count;
205
void soc_dma_set_request(struct soc_dma_ch_s *ch, int level)
207
struct dma_s *dma = (struct dma_s *) ch->dma;
209
dma->enabled_count += level - ch->enable;
212
dma->ch_enable_mask |= (uint64_t)1 << ch->num;
214
dma->ch_enable_mask &= ~((uint64_t)1 << ch->num);
216
if (level != ch->enable) {
217
soc_dma_ch_freq_update(dma);
221
timer_del(ch->timer);
222
else if (!ch->running)
225
soc_dma_ch_schedule(ch, 1);
229
void soc_dma_reset(struct soc_dma_s *soc)
231
struct dma_s *s = (struct dma_s *) soc;
234
s->ch_enable_mask = 0;
235
s->enabled_count = 0;
236
soc_dma_ch_freq_update(s);
240
struct soc_dma_s *soc_dma_init(int n)
243
struct dma_s *s = g_malloc0(sizeof(*s) + n * sizeof(*s->ch));
247
for (i = 0; i < n; i ++) {
248
s->ch[i].dma = &s->soc;
250
s->ch[i].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, soc_dma_ch_run, &s->ch[i]);
253
soc_dma_reset(&s->soc);
259
void soc_dma_port_add_fifo(struct soc_dma_s *soc, hwaddr virt_base,
260
soc_dma_io_t fn, void *opaque, int out)
262
struct memmap_entry_s *entry;
263
struct dma_s *dma = (struct dma_s *) soc;
265
dma->memmap = g_realloc(dma->memmap, sizeof(*entry) *
266
(dma->memmap_size + 1));
267
entry = soc_dma_lookup(dma, virt_base);
269
if (dma->memmap_size) {
270
if (entry->type == soc_dma_port_mem) {
271
if (entry->addr <= virt_base &&
272
entry->addr + entry->u.mem.size > virt_base) {
273
error_report("%s: FIFO at %"PRIx64
274
" collides with RAM region at %"PRIx64
275
"-%"PRIx64, __func__,
276
virt_base, entry->addr,
277
(entry->addr + entry->u.mem.size));
281
if (entry->addr <= virt_base)
284
while (entry < dma->memmap + dma->memmap_size &&
285
entry->addr <= virt_base) {
286
if (entry->addr == virt_base && entry->u.fifo.out == out) {
287
error_report("%s: FIFO at %"PRIx64
288
" collides FIFO at %"PRIx64,
289
__func__, virt_base, entry->addr);
296
memmove(entry + 1, entry,
297
(uint8_t *) (dma->memmap + dma->memmap_size ++) -
302
entry->addr = virt_base;
303
entry->type = soc_dma_port_fifo;
304
entry->u.fifo.fn = fn;
305
entry->u.fifo.opaque = opaque;
306
entry->u.fifo.out = out;
309
void soc_dma_port_add_mem(struct soc_dma_s *soc, uint8_t *phys_base,
310
hwaddr virt_base, size_t size)
312
struct memmap_entry_s *entry;
313
struct dma_s *dma = (struct dma_s *) soc;
315
dma->memmap = g_realloc(dma->memmap, sizeof(*entry) *
316
(dma->memmap_size + 1));
317
entry = soc_dma_lookup(dma, virt_base);
319
if (dma->memmap_size) {
320
if (entry->type == soc_dma_port_mem) {
321
if ((entry->addr >= virt_base && entry->addr < virt_base + size) ||
322
(entry->addr <= virt_base &&
323
entry->addr + entry->u.mem.size > virt_base)) {
324
error_report("%s: RAM at %"PRIx64 "-%"PRIx64
325
" collides with RAM region at %"PRIx64
326
"-%"PRIx64, __func__,
327
virt_base, virt_base + size,
328
entry->addr, entry->addr + entry->u.mem.size);
332
if (entry->addr <= virt_base)
335
if (entry->addr >= virt_base &&
336
entry->addr < virt_base + size) {
337
error_report("%s: RAM at %"PRIx64 "-%"PRIx64
338
" collides with FIFO at %"PRIx64,
339
__func__, virt_base, virt_base + size,
344
while (entry < dma->memmap + dma->memmap_size &&
345
entry->addr <= virt_base)
349
memmove(entry + 1, entry,
350
(uint8_t *) (dma->memmap + dma->memmap_size ++) -
355
entry->addr = virt_base;
356
entry->type = soc_dma_port_mem;
357
entry->u.mem.base = phys_base;
358
entry->u.mem.size = size;