qemu/hw/omap_l4.c
<<
>>
Prefs
   1/*
   2 * TI OMAP L4 interconnect emulation.
   3 *
   4 * Copyright (C) 2007-2009 Nokia Corporation
   5 * Written by Andrzej Zaborowski <andrew@openedhand.com>
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU General Public License as
   9 * published by the Free Software Foundation; either version 2 or
  10 * (at your option) any later version of the License.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License along
  18 * with this program; if not, see <http://www.gnu.org/licenses/>.
  19 */
  20#include "hw.h"
  21#include "omap.h"
  22
  23#ifdef L4_MUX_HACK
  24static int omap_l4_io_entries;
  25static int omap_cpu_io_entry;
  26static struct omap_l4_entry {
  27        CPUReadMemoryFunc * const *mem_read;
  28        CPUWriteMemoryFunc * const *mem_write;
  29        void *opaque;
  30} *omap_l4_io_entry;
  31static CPUReadMemoryFunc * const *omap_l4_io_readb_fn;
  32static CPUReadMemoryFunc * const *omap_l4_io_readh_fn;
  33static CPUReadMemoryFunc * const *omap_l4_io_readw_fn;
  34static CPUWriteMemoryFunc * const *omap_l4_io_writeb_fn;
  35static CPUWriteMemoryFunc * const *omap_l4_io_writeh_fn;
  36static CPUWriteMemoryFunc * const *omap_l4_io_writew_fn;
  37static void **omap_l4_io_opaque;
  38
  39int l4_register_io_memory(CPUReadMemoryFunc * const *mem_read,
  40                CPUWriteMemoryFunc * const *mem_write, void *opaque)
  41{
  42    omap_l4_io_entry[omap_l4_io_entries].mem_read = mem_read;
  43    omap_l4_io_entry[omap_l4_io_entries].mem_write = mem_write;
  44    omap_l4_io_entry[omap_l4_io_entries].opaque = opaque;
  45
  46    return omap_l4_io_entries ++;
  47}
  48
  49static uint32_t omap_l4_io_readb(void *opaque, target_phys_addr_t addr)
  50{
  51    unsigned int i = (addr - OMAP2_L4_BASE) >> TARGET_PAGE_BITS;
  52
  53    return omap_l4_io_readb_fn[i](omap_l4_io_opaque[i], addr);
  54}
  55
  56static uint32_t omap_l4_io_readh(void *opaque, target_phys_addr_t addr)
  57{
  58    unsigned int i = (addr - OMAP2_L4_BASE) >> TARGET_PAGE_BITS;
  59
  60    return omap_l4_io_readh_fn[i](omap_l4_io_opaque[i], addr);
  61}
  62
  63static uint32_t omap_l4_io_readw(void *opaque, target_phys_addr_t addr)
  64{
  65    unsigned int i = (addr - OMAP2_L4_BASE) >> TARGET_PAGE_BITS;
  66
  67    return omap_l4_io_readw_fn[i](omap_l4_io_opaque[i], addr);
  68}
  69
  70static void omap_l4_io_writeb(void *opaque, target_phys_addr_t addr,
  71                uint32_t value)
  72{
  73    unsigned int i = (addr - OMAP2_L4_BASE) >> TARGET_PAGE_BITS;
  74
  75    return omap_l4_io_writeb_fn[i](omap_l4_io_opaque[i], addr, value);
  76}
  77
  78static void omap_l4_io_writeh(void *opaque, target_phys_addr_t addr,
  79                uint32_t value)
  80{
  81    unsigned int i = (addr - OMAP2_L4_BASE) >> TARGET_PAGE_BITS;
  82
  83    return omap_l4_io_writeh_fn[i](omap_l4_io_opaque[i], addr, value);
  84}
  85
  86static void omap_l4_io_writew(void *opaque, target_phys_addr_t addr,
  87                uint32_t value)
  88{
  89    unsigned int i = (addr - OMAP2_L4_BASE) >> TARGET_PAGE_BITS;
  90
  91    return omap_l4_io_writew_fn[i](omap_l4_io_opaque[i], addr, value);
  92}
  93
  94static CPUReadMemoryFunc * const omap_l4_io_readfn[] = {
  95    omap_l4_io_readb,
  96    omap_l4_io_readh,
  97    omap_l4_io_readw,
  98};
  99
 100static CPUWriteMemoryFunc * const omap_l4_io_writefn[] = {
 101    omap_l4_io_writeb,
 102    omap_l4_io_writeh,
 103    omap_l4_io_writew,
 104};
 105#else
 106int l4_register_io_memory(CPUReadMemoryFunc * const *mem_read,
 107                          CPUWriteMemoryFunc * const *mem_write,
 108                          void *opaque)
 109{
 110    return cpu_register_io_memory(mem_read, mem_write, opaque);
 111}
 112#endif
 113
 114struct omap_l4_s {
 115    target_phys_addr_t base;
 116    int ta_num;
 117    struct omap_target_agent_s ta[0];
 118};
 119
 120struct omap_l4_s *omap_l4_init(target_phys_addr_t base, int ta_num)
 121{
 122    struct omap_l4_s *bus = qemu_mallocz(
 123                    sizeof(*bus) + ta_num * sizeof(*bus->ta));
 124
 125    bus->ta_num = ta_num;
 126    bus->base = base;
 127
 128#ifdef L4_MUX_HACK
 129    omap_l4_io_entries = 1;
 130    omap_l4_io_entry = qemu_mallocz(125 * sizeof(*omap_l4_io_entry));
 131
 132    omap_cpu_io_entry =
 133            cpu_register_io_memory(omap_l4_io_readfn,
 134                            omap_l4_io_writefn, bus);
 135# define L4_PAGES       (0xb4000 / TARGET_PAGE_SIZE)
 136    omap_l4_io_readb_fn = qemu_mallocz(sizeof(void *) * L4_PAGES);
 137    omap_l4_io_readh_fn = qemu_mallocz(sizeof(void *) * L4_PAGES);
 138    omap_l4_io_readw_fn = qemu_mallocz(sizeof(void *) * L4_PAGES);
 139    omap_l4_io_writeb_fn = qemu_mallocz(sizeof(void *) * L4_PAGES);
 140    omap_l4_io_writeh_fn = qemu_mallocz(sizeof(void *) * L4_PAGES);
 141    omap_l4_io_writew_fn = qemu_mallocz(sizeof(void *) * L4_PAGES);
 142    omap_l4_io_opaque = qemu_mallocz(sizeof(void *) * L4_PAGES);
 143#endif
 144
 145    return bus;
 146}
 147
 148static uint32_t omap_l4ta_read(void *opaque, target_phys_addr_t addr)
 149{
 150    struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque;
 151
 152    switch (addr) {
 153    case 0x00:  /* COMPONENT */
 154        return s->component;
 155
 156    case 0x20:  /* AGENT_CONTROL */
 157        return s->control;
 158
 159    case 0x28:  /* AGENT_STATUS */
 160        return s->status;
 161    }
 162
 163    OMAP_BAD_REG(addr);
 164    return 0;
 165}
 166
 167static void omap_l4ta_write(void *opaque, target_phys_addr_t addr,
 168                uint32_t value)
 169{
 170    struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque;
 171
 172    switch (addr) {
 173    case 0x00:  /* COMPONENT */
 174    case 0x28:  /* AGENT_STATUS */
 175        OMAP_RO_REG(addr);
 176        break;
 177
 178    case 0x20:  /* AGENT_CONTROL */
 179        s->control = value & 0x01000700;
 180        if (value & 1)                                  /* OCP_RESET */
 181            s->status &= ~1;                            /* REQ_TIMEOUT */
 182        break;
 183
 184    default:
 185        OMAP_BAD_REG(addr);
 186    }
 187}
 188
 189static CPUReadMemoryFunc * const omap_l4ta_readfn[] = {
 190    omap_badwidth_read16,
 191    omap_l4ta_read,
 192    omap_badwidth_read16,
 193};
 194
 195static CPUWriteMemoryFunc * const omap_l4ta_writefn[] = {
 196    omap_badwidth_write32,
 197    omap_badwidth_write32,
 198    omap_l4ta_write,
 199};
 200
 201struct omap_target_agent_s *omap_l4ta_get(struct omap_l4_s *bus,
 202        const struct omap_l4_region_s *regions,
 203        const struct omap_l4_agent_info_s *agents,
 204        int cs)
 205{
 206    int i, iomemtype;
 207    struct omap_target_agent_s *ta = NULL;
 208    const struct omap_l4_agent_info_s *info = NULL;
 209
 210    for (i = 0; i < bus->ta_num; i ++)
 211        if (agents[i].ta == cs) {
 212            ta = &bus->ta[i];
 213            info = &agents[i];
 214            break;
 215        }
 216    if (!ta) {
 217        fprintf(stderr, "%s: bad target agent (%i)\n", __FUNCTION__, cs);
 218        exit(-1);
 219    }
 220
 221    ta->bus = bus;
 222    ta->start = &regions[info->region];
 223    ta->regions = info->regions;
 224
 225    ta->component = ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
 226    ta->status = 0x00000000;
 227    ta->control = 0x00000200;   /* XXX 01000200 for L4TAO */
 228
 229    iomemtype = l4_register_io_memory(omap_l4ta_readfn,
 230                    omap_l4ta_writefn, ta);
 231    ta->base = omap_l4_attach(ta, info->ta_region, iomemtype);
 232
 233    return ta;
 234}
 235
 236target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta, int region,
 237                int iotype)
 238{
 239    target_phys_addr_t base;
 240    ssize_t size;
 241#ifdef L4_MUX_HACK
 242    int i;
 243#endif
 244
 245    if (region < 0 || region >= ta->regions) {
 246        fprintf(stderr, "%s: bad io region (%i)\n", __FUNCTION__, region);
 247        exit(-1);
 248    }
 249
 250    base = ta->bus->base + ta->start[region].offset;
 251    size = ta->start[region].size;
 252    if (iotype) {
 253#ifndef L4_MUX_HACK
 254        cpu_register_physical_memory(base, size, iotype);
 255#else
 256        cpu_register_physical_memory(base, size, omap_cpu_io_entry);
 257        i = (base - ta->bus->base) / TARGET_PAGE_SIZE;
 258        for (; size > 0; size -= TARGET_PAGE_SIZE, i ++) {
 259            omap_l4_io_readb_fn[i] = omap_l4_io_entry[iotype].mem_read[0];
 260            omap_l4_io_readh_fn[i] = omap_l4_io_entry[iotype].mem_read[1];
 261            omap_l4_io_readw_fn[i] = omap_l4_io_entry[iotype].mem_read[2];
 262            omap_l4_io_writeb_fn[i] = omap_l4_io_entry[iotype].mem_write[0];
 263            omap_l4_io_writeh_fn[i] = omap_l4_io_entry[iotype].mem_write[1];
 264            omap_l4_io_writew_fn[i] = omap_l4_io_entry[iotype].mem_write[2];
 265            omap_l4_io_opaque[i] = omap_l4_io_entry[iotype].opaque;
 266        }
 267#endif
 268    }
 269
 270    return base;
 271}
 272