1d2c0bd84SPaolo Bonzini /* 2d2c0bd84SPaolo Bonzini * On-chip DMA controller framework. 3d2c0bd84SPaolo Bonzini * 4d2c0bd84SPaolo Bonzini * Copyright (C) 2008 Nokia Corporation 5d2c0bd84SPaolo Bonzini * Written by Andrzej Zaborowski <andrew@openedhand.com> 6d2c0bd84SPaolo Bonzini * 7d2c0bd84SPaolo Bonzini * This program is free software; you can redistribute it and/or 8d2c0bd84SPaolo Bonzini * modify it under the terms of the GNU General Public License as 9d2c0bd84SPaolo Bonzini * published by the Free Software Foundation; either version 2 or 10d2c0bd84SPaolo Bonzini * (at your option) version 3 of the License. 11d2c0bd84SPaolo Bonzini * 12d2c0bd84SPaolo Bonzini * This program is distributed in the hope that it will be useful, 13d2c0bd84SPaolo Bonzini * but WITHOUT ANY WARRANTY; without even the implied warranty of 14d2c0bd84SPaolo Bonzini * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15d2c0bd84SPaolo Bonzini * GNU General Public License for more details. 16d2c0bd84SPaolo Bonzini * 17d2c0bd84SPaolo Bonzini * You should have received a copy of the GNU General Public License along 18d2c0bd84SPaolo Bonzini * with this program; if not, see <http://www.gnu.org/licenses/>. 19d2c0bd84SPaolo Bonzini */ 20d2c0bd84SPaolo Bonzini #include "qemu-common.h" 21d2c0bd84SPaolo Bonzini #include "qemu/timer.h" 22d2c0bd84SPaolo Bonzini #include "hw/arm/soc_dma.h" 23d2c0bd84SPaolo Bonzini 24d2c0bd84SPaolo Bonzini static void transfer_mem2mem(struct soc_dma_ch_s *ch) 25d2c0bd84SPaolo Bonzini { 26d2c0bd84SPaolo Bonzini memcpy(ch->paddr[0], ch->paddr[1], ch->bytes); 27d2c0bd84SPaolo Bonzini ch->paddr[0] += ch->bytes; 28d2c0bd84SPaolo Bonzini ch->paddr[1] += ch->bytes; 29d2c0bd84SPaolo Bonzini } 30d2c0bd84SPaolo Bonzini 31d2c0bd84SPaolo Bonzini static void transfer_mem2fifo(struct soc_dma_ch_s *ch) 32d2c0bd84SPaolo Bonzini { 33d2c0bd84SPaolo Bonzini ch->io_fn[1](ch->io_opaque[1], ch->paddr[0], ch->bytes); 34d2c0bd84SPaolo Bonzini ch->paddr[0] += ch->bytes; 35d2c0bd84SPaolo Bonzini } 36d2c0bd84SPaolo Bonzini 37d2c0bd84SPaolo Bonzini static void transfer_fifo2mem(struct soc_dma_ch_s *ch) 38d2c0bd84SPaolo Bonzini { 39d2c0bd84SPaolo Bonzini ch->io_fn[0](ch->io_opaque[0], ch->paddr[1], ch->bytes); 40d2c0bd84SPaolo Bonzini ch->paddr[1] += ch->bytes; 41d2c0bd84SPaolo Bonzini } 42d2c0bd84SPaolo Bonzini 43d2c0bd84SPaolo Bonzini /* This is further optimisable but isn't very important because often 44d2c0bd84SPaolo Bonzini * DMA peripherals forbid this kind of transfers and even when they don't, 45d2c0bd84SPaolo Bonzini * oprating systems may not need to use them. */ 46d2c0bd84SPaolo Bonzini static void *fifo_buf; 47d2c0bd84SPaolo Bonzini static int fifo_size; 48d2c0bd84SPaolo Bonzini static void transfer_fifo2fifo(struct soc_dma_ch_s *ch) 49d2c0bd84SPaolo Bonzini { 50d2c0bd84SPaolo Bonzini if (ch->bytes > fifo_size) 51d2c0bd84SPaolo Bonzini fifo_buf = g_realloc(fifo_buf, fifo_size = ch->bytes); 52d2c0bd84SPaolo Bonzini 53d2c0bd84SPaolo Bonzini /* Implement as transfer_fifo2linear + transfer_linear2fifo. */ 54d2c0bd84SPaolo Bonzini ch->io_fn[0](ch->io_opaque[0], fifo_buf, ch->bytes); 55d2c0bd84SPaolo Bonzini ch->io_fn[1](ch->io_opaque[1], fifo_buf, ch->bytes); 56d2c0bd84SPaolo Bonzini } 57d2c0bd84SPaolo Bonzini 58d2c0bd84SPaolo Bonzini struct dma_s { 59d2c0bd84SPaolo Bonzini struct soc_dma_s soc; 60d2c0bd84SPaolo Bonzini int chnum; 61d2c0bd84SPaolo Bonzini uint64_t ch_enable_mask; 62d2c0bd84SPaolo Bonzini int64_t channel_freq; 63d2c0bd84SPaolo Bonzini int enabled_count; 64d2c0bd84SPaolo Bonzini 65d2c0bd84SPaolo Bonzini struct memmap_entry_s { 66d2c0bd84SPaolo Bonzini enum soc_dma_port_type type; 67d2c0bd84SPaolo Bonzini hwaddr addr; 68d2c0bd84SPaolo Bonzini union { 69d2c0bd84SPaolo Bonzini struct { 70d2c0bd84SPaolo Bonzini void *opaque; 71d2c0bd84SPaolo Bonzini soc_dma_io_t fn; 72d2c0bd84SPaolo Bonzini int out; 73d2c0bd84SPaolo Bonzini } fifo; 74d2c0bd84SPaolo Bonzini struct { 75d2c0bd84SPaolo Bonzini void *base; 76d2c0bd84SPaolo Bonzini size_t size; 77d2c0bd84SPaolo Bonzini } mem; 78d2c0bd84SPaolo Bonzini } u; 79d2c0bd84SPaolo Bonzini } *memmap; 80d2c0bd84SPaolo Bonzini int memmap_size; 81d2c0bd84SPaolo Bonzini 82d2c0bd84SPaolo Bonzini struct soc_dma_ch_s ch[0]; 83d2c0bd84SPaolo Bonzini }; 84d2c0bd84SPaolo Bonzini 85d2c0bd84SPaolo Bonzini static void soc_dma_ch_schedule(struct soc_dma_ch_s *ch, int delay_bytes) 86d2c0bd84SPaolo Bonzini { 87*bc72ad67SAlex Bligh int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 88d2c0bd84SPaolo Bonzini struct dma_s *dma = (struct dma_s *) ch->dma; 89d2c0bd84SPaolo Bonzini 90*bc72ad67SAlex Bligh timer_mod(ch->timer, now + delay_bytes / dma->channel_freq); 91d2c0bd84SPaolo Bonzini } 92d2c0bd84SPaolo Bonzini 93d2c0bd84SPaolo Bonzini static void soc_dma_ch_run(void *opaque) 94d2c0bd84SPaolo Bonzini { 95d2c0bd84SPaolo Bonzini struct soc_dma_ch_s *ch = (struct soc_dma_ch_s *) opaque; 96d2c0bd84SPaolo Bonzini 97d2c0bd84SPaolo Bonzini ch->running = 1; 98d2c0bd84SPaolo Bonzini ch->dma->setup_fn(ch); 99d2c0bd84SPaolo Bonzini ch->transfer_fn(ch); 100d2c0bd84SPaolo Bonzini ch->running = 0; 101d2c0bd84SPaolo Bonzini 102d2c0bd84SPaolo Bonzini if (ch->enable) 103d2c0bd84SPaolo Bonzini soc_dma_ch_schedule(ch, ch->bytes); 104d2c0bd84SPaolo Bonzini ch->bytes = 0; 105d2c0bd84SPaolo Bonzini } 106d2c0bd84SPaolo Bonzini 107d2c0bd84SPaolo Bonzini static inline struct memmap_entry_s *soc_dma_lookup(struct dma_s *dma, 108d2c0bd84SPaolo Bonzini hwaddr addr) 109d2c0bd84SPaolo Bonzini { 110d2c0bd84SPaolo Bonzini struct memmap_entry_s *lo; 111d2c0bd84SPaolo Bonzini int hi; 112d2c0bd84SPaolo Bonzini 113d2c0bd84SPaolo Bonzini lo = dma->memmap; 114d2c0bd84SPaolo Bonzini hi = dma->memmap_size; 115d2c0bd84SPaolo Bonzini 116d2c0bd84SPaolo Bonzini while (hi > 1) { 117d2c0bd84SPaolo Bonzini hi /= 2; 118d2c0bd84SPaolo Bonzini if (lo[hi].addr <= addr) 119d2c0bd84SPaolo Bonzini lo += hi; 120d2c0bd84SPaolo Bonzini } 121d2c0bd84SPaolo Bonzini 122d2c0bd84SPaolo Bonzini return lo; 123d2c0bd84SPaolo Bonzini } 124d2c0bd84SPaolo Bonzini 125d2c0bd84SPaolo Bonzini static inline enum soc_dma_port_type soc_dma_ch_update_type( 126d2c0bd84SPaolo Bonzini struct soc_dma_ch_s *ch, int port) 127d2c0bd84SPaolo Bonzini { 128d2c0bd84SPaolo Bonzini struct dma_s *dma = (struct dma_s *) ch->dma; 129d2c0bd84SPaolo Bonzini struct memmap_entry_s *entry = soc_dma_lookup(dma, ch->vaddr[port]); 130d2c0bd84SPaolo Bonzini 131d2c0bd84SPaolo Bonzini if (entry->type == soc_dma_port_fifo) { 132d2c0bd84SPaolo Bonzini while (entry < dma->memmap + dma->memmap_size && 133d2c0bd84SPaolo Bonzini entry->u.fifo.out != port) 134d2c0bd84SPaolo Bonzini entry ++; 135d2c0bd84SPaolo Bonzini if (entry->addr != ch->vaddr[port] || entry->u.fifo.out != port) 136d2c0bd84SPaolo Bonzini return soc_dma_port_other; 137d2c0bd84SPaolo Bonzini 138d2c0bd84SPaolo Bonzini if (ch->type[port] != soc_dma_access_const) 139d2c0bd84SPaolo Bonzini return soc_dma_port_other; 140d2c0bd84SPaolo Bonzini 141d2c0bd84SPaolo Bonzini ch->io_fn[port] = entry->u.fifo.fn; 142d2c0bd84SPaolo Bonzini ch->io_opaque[port] = entry->u.fifo.opaque; 143d2c0bd84SPaolo Bonzini return soc_dma_port_fifo; 144d2c0bd84SPaolo Bonzini } else if (entry->type == soc_dma_port_mem) { 145d2c0bd84SPaolo Bonzini if (entry->addr > ch->vaddr[port] || 146d2c0bd84SPaolo Bonzini entry->addr + entry->u.mem.size <= ch->vaddr[port]) 147d2c0bd84SPaolo Bonzini return soc_dma_port_other; 148d2c0bd84SPaolo Bonzini 149d2c0bd84SPaolo Bonzini /* TODO: support constant memory address for source port as used for 150d2c0bd84SPaolo Bonzini * drawing solid rectangles by PalmOS(R). */ 151d2c0bd84SPaolo Bonzini if (ch->type[port] != soc_dma_access_const) 152d2c0bd84SPaolo Bonzini return soc_dma_port_other; 153d2c0bd84SPaolo Bonzini 154d2c0bd84SPaolo Bonzini ch->paddr[port] = (uint8_t *) entry->u.mem.base + 155d2c0bd84SPaolo Bonzini (ch->vaddr[port] - entry->addr); 156d2c0bd84SPaolo Bonzini /* TODO: save bytes left to the end of the mapping somewhere so we 157d2c0bd84SPaolo Bonzini * can check we're not reading beyond it. */ 158d2c0bd84SPaolo Bonzini return soc_dma_port_mem; 159d2c0bd84SPaolo Bonzini } else 160d2c0bd84SPaolo Bonzini return soc_dma_port_other; 161d2c0bd84SPaolo Bonzini } 162d2c0bd84SPaolo Bonzini 163d2c0bd84SPaolo Bonzini void soc_dma_ch_update(struct soc_dma_ch_s *ch) 164d2c0bd84SPaolo Bonzini { 165d2c0bd84SPaolo Bonzini enum soc_dma_port_type src, dst; 166d2c0bd84SPaolo Bonzini 167d2c0bd84SPaolo Bonzini src = soc_dma_ch_update_type(ch, 0); 168d2c0bd84SPaolo Bonzini if (src == soc_dma_port_other) { 169d2c0bd84SPaolo Bonzini ch->update = 0; 170d2c0bd84SPaolo Bonzini ch->transfer_fn = ch->dma->transfer_fn; 171d2c0bd84SPaolo Bonzini return; 172d2c0bd84SPaolo Bonzini } 173d2c0bd84SPaolo Bonzini dst = soc_dma_ch_update_type(ch, 1); 174d2c0bd84SPaolo Bonzini 175d2c0bd84SPaolo Bonzini /* TODO: use src and dst as array indices. */ 176d2c0bd84SPaolo Bonzini if (src == soc_dma_port_mem && dst == soc_dma_port_mem) 177d2c0bd84SPaolo Bonzini ch->transfer_fn = transfer_mem2mem; 178d2c0bd84SPaolo Bonzini else if (src == soc_dma_port_mem && dst == soc_dma_port_fifo) 179d2c0bd84SPaolo Bonzini ch->transfer_fn = transfer_mem2fifo; 180d2c0bd84SPaolo Bonzini else if (src == soc_dma_port_fifo && dst == soc_dma_port_mem) 181d2c0bd84SPaolo Bonzini ch->transfer_fn = transfer_fifo2mem; 182d2c0bd84SPaolo Bonzini else if (src == soc_dma_port_fifo && dst == soc_dma_port_fifo) 183d2c0bd84SPaolo Bonzini ch->transfer_fn = transfer_fifo2fifo; 184d2c0bd84SPaolo Bonzini else 185d2c0bd84SPaolo Bonzini ch->transfer_fn = ch->dma->transfer_fn; 186d2c0bd84SPaolo Bonzini 187d2c0bd84SPaolo Bonzini ch->update = (dst != soc_dma_port_other); 188d2c0bd84SPaolo Bonzini } 189d2c0bd84SPaolo Bonzini 190d2c0bd84SPaolo Bonzini static void soc_dma_ch_freq_update(struct dma_s *s) 191d2c0bd84SPaolo Bonzini { 192d2c0bd84SPaolo Bonzini if (s->enabled_count) 193d2c0bd84SPaolo Bonzini /* We completely ignore channel priorities and stuff */ 194d2c0bd84SPaolo Bonzini s->channel_freq = s->soc.freq / s->enabled_count; 195d2c0bd84SPaolo Bonzini else { 196d2c0bd84SPaolo Bonzini /* TODO: Signal that we want to disable the functional clock and let 197d2c0bd84SPaolo Bonzini * the platform code decide what to do with it, i.e. check that 198d2c0bd84SPaolo Bonzini * auto-idle is enabled in the clock controller and if we are stopping 199d2c0bd84SPaolo Bonzini * the clock, do the same with any parent clocks that had only one 200d2c0bd84SPaolo Bonzini * user keeping them on and auto-idle enabled. */ 201d2c0bd84SPaolo Bonzini } 202d2c0bd84SPaolo Bonzini } 203d2c0bd84SPaolo Bonzini 204d2c0bd84SPaolo Bonzini void soc_dma_set_request(struct soc_dma_ch_s *ch, int level) 205d2c0bd84SPaolo Bonzini { 206d2c0bd84SPaolo Bonzini struct dma_s *dma = (struct dma_s *) ch->dma; 207d2c0bd84SPaolo Bonzini 208d2c0bd84SPaolo Bonzini dma->enabled_count += level - ch->enable; 209d2c0bd84SPaolo Bonzini 210d2c0bd84SPaolo Bonzini if (level) 211d2c0bd84SPaolo Bonzini dma->ch_enable_mask |= 1 << ch->num; 212d2c0bd84SPaolo Bonzini else 213d2c0bd84SPaolo Bonzini dma->ch_enable_mask &= ~(1 << ch->num); 214d2c0bd84SPaolo Bonzini 215d2c0bd84SPaolo Bonzini if (level != ch->enable) { 216d2c0bd84SPaolo Bonzini soc_dma_ch_freq_update(dma); 217d2c0bd84SPaolo Bonzini ch->enable = level; 218d2c0bd84SPaolo Bonzini 219d2c0bd84SPaolo Bonzini if (!ch->enable) 220*bc72ad67SAlex Bligh timer_del(ch->timer); 221d2c0bd84SPaolo Bonzini else if (!ch->running) 222d2c0bd84SPaolo Bonzini soc_dma_ch_run(ch); 223d2c0bd84SPaolo Bonzini else 224d2c0bd84SPaolo Bonzini soc_dma_ch_schedule(ch, 1); 225d2c0bd84SPaolo Bonzini } 226d2c0bd84SPaolo Bonzini } 227d2c0bd84SPaolo Bonzini 228d2c0bd84SPaolo Bonzini void soc_dma_reset(struct soc_dma_s *soc) 229d2c0bd84SPaolo Bonzini { 230d2c0bd84SPaolo Bonzini struct dma_s *s = (struct dma_s *) soc; 231d2c0bd84SPaolo Bonzini 232d2c0bd84SPaolo Bonzini s->soc.drqbmp = 0; 233d2c0bd84SPaolo Bonzini s->ch_enable_mask = 0; 234d2c0bd84SPaolo Bonzini s->enabled_count = 0; 235d2c0bd84SPaolo Bonzini soc_dma_ch_freq_update(s); 236d2c0bd84SPaolo Bonzini } 237d2c0bd84SPaolo Bonzini 238d2c0bd84SPaolo Bonzini /* TODO: take a functional-clock argument */ 239d2c0bd84SPaolo Bonzini struct soc_dma_s *soc_dma_init(int n) 240d2c0bd84SPaolo Bonzini { 241d2c0bd84SPaolo Bonzini int i; 242d2c0bd84SPaolo Bonzini struct dma_s *s = g_malloc0(sizeof(*s) + n * sizeof(*s->ch)); 243d2c0bd84SPaolo Bonzini 244d2c0bd84SPaolo Bonzini s->chnum = n; 245d2c0bd84SPaolo Bonzini s->soc.ch = s->ch; 246d2c0bd84SPaolo Bonzini for (i = 0; i < n; i ++) { 247d2c0bd84SPaolo Bonzini s->ch[i].dma = &s->soc; 248d2c0bd84SPaolo Bonzini s->ch[i].num = i; 249*bc72ad67SAlex Bligh s->ch[i].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, soc_dma_ch_run, &s->ch[i]); 250d2c0bd84SPaolo Bonzini } 251d2c0bd84SPaolo Bonzini 252d2c0bd84SPaolo Bonzini soc_dma_reset(&s->soc); 253d2c0bd84SPaolo Bonzini fifo_size = 0; 254d2c0bd84SPaolo Bonzini 255d2c0bd84SPaolo Bonzini return &s->soc; 256d2c0bd84SPaolo Bonzini } 257d2c0bd84SPaolo Bonzini 258d2c0bd84SPaolo Bonzini void soc_dma_port_add_fifo(struct soc_dma_s *soc, hwaddr virt_base, 259d2c0bd84SPaolo Bonzini soc_dma_io_t fn, void *opaque, int out) 260d2c0bd84SPaolo Bonzini { 261d2c0bd84SPaolo Bonzini struct memmap_entry_s *entry; 262d2c0bd84SPaolo Bonzini struct dma_s *dma = (struct dma_s *) soc; 263d2c0bd84SPaolo Bonzini 264d2c0bd84SPaolo Bonzini dma->memmap = g_realloc(dma->memmap, sizeof(*entry) * 265d2c0bd84SPaolo Bonzini (dma->memmap_size + 1)); 266d2c0bd84SPaolo Bonzini entry = soc_dma_lookup(dma, virt_base); 267d2c0bd84SPaolo Bonzini 268d2c0bd84SPaolo Bonzini if (dma->memmap_size) { 269d2c0bd84SPaolo Bonzini if (entry->type == soc_dma_port_mem) { 270d2c0bd84SPaolo Bonzini if (entry->addr <= virt_base && 271d2c0bd84SPaolo Bonzini entry->addr + entry->u.mem.size > virt_base) { 272d2c0bd84SPaolo Bonzini fprintf(stderr, "%s: FIFO at " TARGET_FMT_lx 273d2c0bd84SPaolo Bonzini " collides with RAM region at " TARGET_FMT_lx 274d2c0bd84SPaolo Bonzini "-" TARGET_FMT_lx "\n", __FUNCTION__, 275d2c0bd84SPaolo Bonzini (target_ulong) virt_base, 276d2c0bd84SPaolo Bonzini (target_ulong) entry->addr, (target_ulong) 277d2c0bd84SPaolo Bonzini (entry->addr + entry->u.mem.size)); 278d2c0bd84SPaolo Bonzini exit(-1); 279d2c0bd84SPaolo Bonzini } 280d2c0bd84SPaolo Bonzini 281d2c0bd84SPaolo Bonzini if (entry->addr <= virt_base) 282d2c0bd84SPaolo Bonzini entry ++; 283d2c0bd84SPaolo Bonzini } else 284d2c0bd84SPaolo Bonzini while (entry < dma->memmap + dma->memmap_size && 285d2c0bd84SPaolo Bonzini entry->addr <= virt_base) { 286d2c0bd84SPaolo Bonzini if (entry->addr == virt_base && entry->u.fifo.out == out) { 287d2c0bd84SPaolo Bonzini fprintf(stderr, "%s: FIFO at " TARGET_FMT_lx 288d2c0bd84SPaolo Bonzini " collides FIFO at " TARGET_FMT_lx "\n", 289d2c0bd84SPaolo Bonzini __FUNCTION__, (target_ulong) virt_base, 290d2c0bd84SPaolo Bonzini (target_ulong) entry->addr); 291d2c0bd84SPaolo Bonzini exit(-1); 292d2c0bd84SPaolo Bonzini } 293d2c0bd84SPaolo Bonzini 294d2c0bd84SPaolo Bonzini entry ++; 295d2c0bd84SPaolo Bonzini } 296d2c0bd84SPaolo Bonzini 297d2c0bd84SPaolo Bonzini memmove(entry + 1, entry, 298d2c0bd84SPaolo Bonzini (uint8_t *) (dma->memmap + dma->memmap_size ++) - 299d2c0bd84SPaolo Bonzini (uint8_t *) entry); 300d2c0bd84SPaolo Bonzini } else 301d2c0bd84SPaolo Bonzini dma->memmap_size ++; 302d2c0bd84SPaolo Bonzini 303d2c0bd84SPaolo Bonzini entry->addr = virt_base; 304d2c0bd84SPaolo Bonzini entry->type = soc_dma_port_fifo; 305d2c0bd84SPaolo Bonzini entry->u.fifo.fn = fn; 306d2c0bd84SPaolo Bonzini entry->u.fifo.opaque = opaque; 307d2c0bd84SPaolo Bonzini entry->u.fifo.out = out; 308d2c0bd84SPaolo Bonzini } 309d2c0bd84SPaolo Bonzini 310d2c0bd84SPaolo Bonzini void soc_dma_port_add_mem(struct soc_dma_s *soc, uint8_t *phys_base, 311d2c0bd84SPaolo Bonzini hwaddr virt_base, size_t size) 312d2c0bd84SPaolo Bonzini { 313d2c0bd84SPaolo Bonzini struct memmap_entry_s *entry; 314d2c0bd84SPaolo Bonzini struct dma_s *dma = (struct dma_s *) soc; 315d2c0bd84SPaolo Bonzini 316d2c0bd84SPaolo Bonzini dma->memmap = g_realloc(dma->memmap, sizeof(*entry) * 317d2c0bd84SPaolo Bonzini (dma->memmap_size + 1)); 318d2c0bd84SPaolo Bonzini entry = soc_dma_lookup(dma, virt_base); 319d2c0bd84SPaolo Bonzini 320d2c0bd84SPaolo Bonzini if (dma->memmap_size) { 321d2c0bd84SPaolo Bonzini if (entry->type == soc_dma_port_mem) { 322d2c0bd84SPaolo Bonzini if ((entry->addr >= virt_base && entry->addr < virt_base + size) || 323d2c0bd84SPaolo Bonzini (entry->addr <= virt_base && 324d2c0bd84SPaolo Bonzini entry->addr + entry->u.mem.size > virt_base)) { 325d2c0bd84SPaolo Bonzini fprintf(stderr, "%s: RAM at " TARGET_FMT_lx "-" TARGET_FMT_lx 326d2c0bd84SPaolo Bonzini " collides with RAM region at " TARGET_FMT_lx 327d2c0bd84SPaolo Bonzini "-" TARGET_FMT_lx "\n", __FUNCTION__, 328d2c0bd84SPaolo Bonzini (target_ulong) virt_base, 329d2c0bd84SPaolo Bonzini (target_ulong) (virt_base + size), 330d2c0bd84SPaolo Bonzini (target_ulong) entry->addr, (target_ulong) 331d2c0bd84SPaolo Bonzini (entry->addr + entry->u.mem.size)); 332d2c0bd84SPaolo Bonzini exit(-1); 333d2c0bd84SPaolo Bonzini } 334d2c0bd84SPaolo Bonzini 335d2c0bd84SPaolo Bonzini if (entry->addr <= virt_base) 336d2c0bd84SPaolo Bonzini entry ++; 337d2c0bd84SPaolo Bonzini } else { 338d2c0bd84SPaolo Bonzini if (entry->addr >= virt_base && 339d2c0bd84SPaolo Bonzini entry->addr < virt_base + size) { 340d2c0bd84SPaolo Bonzini fprintf(stderr, "%s: RAM at " TARGET_FMT_lx "-" TARGET_FMT_lx 341d2c0bd84SPaolo Bonzini " collides with FIFO at " TARGET_FMT_lx 342d2c0bd84SPaolo Bonzini "\n", __FUNCTION__, 343d2c0bd84SPaolo Bonzini (target_ulong) virt_base, 344d2c0bd84SPaolo Bonzini (target_ulong) (virt_base + size), 345d2c0bd84SPaolo Bonzini (target_ulong) entry->addr); 346d2c0bd84SPaolo Bonzini exit(-1); 347d2c0bd84SPaolo Bonzini } 348d2c0bd84SPaolo Bonzini 349d2c0bd84SPaolo Bonzini while (entry < dma->memmap + dma->memmap_size && 350d2c0bd84SPaolo Bonzini entry->addr <= virt_base) 351d2c0bd84SPaolo Bonzini entry ++; 352d2c0bd84SPaolo Bonzini } 353d2c0bd84SPaolo Bonzini 354d2c0bd84SPaolo Bonzini memmove(entry + 1, entry, 355d2c0bd84SPaolo Bonzini (uint8_t *) (dma->memmap + dma->memmap_size ++) - 356d2c0bd84SPaolo Bonzini (uint8_t *) entry); 357d2c0bd84SPaolo Bonzini } else 358d2c0bd84SPaolo Bonzini dma->memmap_size ++; 359d2c0bd84SPaolo Bonzini 360d2c0bd84SPaolo Bonzini entry->addr = virt_base; 361d2c0bd84SPaolo Bonzini entry->type = soc_dma_port_mem; 362d2c0bd84SPaolo Bonzini entry->u.mem.base = phys_base; 363d2c0bd84SPaolo Bonzini entry->u.mem.size = size; 364d2c0bd84SPaolo Bonzini } 365d2c0bd84SPaolo Bonzini 366d2c0bd84SPaolo Bonzini /* TODO: port removal for ports like PCMCIA memory */ 367