qemu/hw/misc/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 "qemu/osdep.h"
  21#include "hw/arm/omap.h"
  22
  23struct omap_l4_s {
  24    MemoryRegion *address_space;
  25    hwaddr base;
  26    int ta_num;
  27    struct omap_target_agent_s ta[0];
  28};
  29
  30struct omap_l4_s *omap_l4_init(MemoryRegion *address_space,
  31                               hwaddr base, int ta_num)
  32{
  33    struct omap_l4_s *bus = g_malloc0(
  34                    sizeof(*bus) + ta_num * sizeof(*bus->ta));
  35
  36    bus->address_space = address_space;
  37    bus->ta_num = ta_num;
  38    bus->base = base;
  39
  40    return bus;
  41}
  42
  43hwaddr omap_l4_region_base(struct omap_target_agent_s *ta,
  44                                       int region)
  45{
  46    return ta->bus->base + ta->start[region].offset;
  47}
  48
  49hwaddr omap_l4_region_size(struct omap_target_agent_s *ta,
  50                                       int region)
  51{
  52    return ta->start[region].size;
  53}
  54
  55static uint64_t omap_l4ta_read(void *opaque, hwaddr addr,
  56                               unsigned size)
  57{
  58    struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque;
  59
  60    if (size != 2) {
  61        return omap_badwidth_read16(opaque, addr);
  62    }
  63
  64    switch (addr) {
  65    case 0x00:  /* COMPONENT */
  66        return s->component;
  67
  68    case 0x20:  /* AGENT_CONTROL */
  69        return s->control;
  70
  71    case 0x28:  /* AGENT_STATUS */
  72        return s->status;
  73    }
  74
  75    OMAP_BAD_REG(addr);
  76    return 0;
  77}
  78
  79static void omap_l4ta_write(void *opaque, hwaddr addr,
  80                            uint64_t value, unsigned size)
  81{
  82    struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque;
  83
  84    if (size != 4) {
  85        omap_badwidth_write32(opaque, addr, value);
  86        return;
  87    }
  88
  89    switch (addr) {
  90    case 0x00:  /* COMPONENT */
  91    case 0x28:  /* AGENT_STATUS */
  92        OMAP_RO_REG(addr);
  93        break;
  94
  95    case 0x20:  /* AGENT_CONTROL */
  96        s->control = value & 0x01000700;
  97        if (value & 1)                                  /* OCP_RESET */
  98            s->status &= ~1;                            /* REQ_TIMEOUT */
  99        break;
 100
 101    default:
 102        OMAP_BAD_REG(addr);
 103    }
 104}
 105
 106static const MemoryRegionOps omap_l4ta_ops = {
 107    .read = omap_l4ta_read,
 108    .write = omap_l4ta_write,
 109    .endianness = DEVICE_NATIVE_ENDIAN,
 110};
 111
 112struct omap_target_agent_s *omap_l4ta_get(struct omap_l4_s *bus,
 113        const struct omap_l4_region_s *regions,
 114        const struct omap_l4_agent_info_s *agents,
 115        int cs)
 116{
 117    int i;
 118    struct omap_target_agent_s *ta = NULL;
 119    const struct omap_l4_agent_info_s *info = NULL;
 120
 121    for (i = 0; i < bus->ta_num; i ++)
 122        if (agents[i].ta == cs) {
 123            ta = &bus->ta[i];
 124            info = &agents[i];
 125            break;
 126        }
 127    if (!ta) {
 128        fprintf(stderr, "%s: bad target agent (%i)\n", __func__, cs);
 129        exit(-1);
 130    }
 131
 132    ta->bus = bus;
 133    ta->start = &regions[info->region];
 134    ta->regions = info->regions;
 135
 136    ta->component = ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
 137    ta->status = 0x00000000;
 138    ta->control = 0x00000200;   /* XXX 01000200 for L4TAO */
 139
 140    memory_region_init_io(&ta->iomem, NULL, &omap_l4ta_ops, ta, "omap.l4ta",
 141                          omap_l4_region_size(ta, info->ta_region));
 142    omap_l4_attach(ta, info->ta_region, &ta->iomem);
 143
 144    return ta;
 145}
 146
 147hwaddr omap_l4_attach(struct omap_target_agent_s *ta,
 148                                         int region, MemoryRegion *mr)
 149{
 150    hwaddr base;
 151
 152    if (region < 0 || region >= ta->regions) {
 153        fprintf(stderr, "%s: bad io region (%i)\n", __func__, region);
 154        exit(-1);
 155    }
 156
 157    base = ta->bus->base + ta->start[region].offset;
 158    if (mr) {
 159        memory_region_add_subregion(ta->bus->address_space, base, mr);
 160    }
 161
 162    return base;
 163}
 164