qemu/hw/misc/a9scu.c
<<
>>
Prefs
   1/*
   2 * Cortex-A9MPCore Snoop Control Unit (SCU) emulation.
   3 *
   4 * Copyright (c) 2009 CodeSourcery.
   5 * Copyright (c) 2011 Linaro Limited.
   6 * Written by Paul Brook, Peter Maydell.
   7 *
   8 * This code is licensed under the GPL.
   9 */
  10
  11#include "qemu/osdep.h"
  12#include "hw/misc/a9scu.h"
  13#include "hw/fdt_generic_devices.h"
  14
  15static uint64_t a9_scu_read(void *opaque, hwaddr offset,
  16                            unsigned size)
  17{
  18    A9SCUState *s = (A9SCUState *)opaque;
  19    switch (offset) {
  20    case 0x00: /* Control */
  21        return s->control;
  22    case 0x04: /* Configuration */
  23        return (((1 << s->num_cpu) - 1) << 4) | (s->num_cpu - 1);
  24    case 0x08: /* CPU Power Status */
  25        return s->status;
  26    case 0x09: /* CPU status.  */
  27        return s->status >> 8;
  28    case 0x0a: /* CPU status.  */
  29        return s->status >> 16;
  30    case 0x0b: /* CPU status.  */
  31        return s->status >> 24;
  32    case 0x0c: /* Invalidate All Registers In Secure State */
  33        return 0;
  34    case 0x40: /* Filtering Start Address Register */
  35    case 0x44: /* Filtering End Address Register */
  36        /* RAZ/WI, like an implementation with only one AXI master */
  37        return 0;
  38    case 0x50: /* SCU Access Control Register */
  39    case 0x54: /* SCU Non-secure Access Control Register */
  40        /* unimplemented, fall through */
  41    default:
  42        return 0;
  43    }
  44}
  45
  46static void a9_scu_write(void *opaque, hwaddr offset,
  47                         uint64_t value, unsigned size)
  48{
  49    A9SCUState *s = (A9SCUState *)opaque;
  50    uint32_t mask;
  51    uint32_t shift;
  52    switch (size) {
  53    case 1:
  54        mask = 0xff;
  55        break;
  56    case 2:
  57        mask = 0xffff;
  58        break;
  59    case 4:
  60        mask = 0xffffffff;
  61        break;
  62    default:
  63        fprintf(stderr, "Invalid size %u in write to a9 scu register %x\n",
  64                size, (unsigned)offset);
  65        return;
  66    }
  67
  68    switch (offset) {
  69    case 0x00: /* Control */
  70        s->control = value & 1;
  71        break;
  72    case 0x4: /* Configuration: RO */
  73        break;
  74    case 0x08: case 0x09: case 0x0A: case 0x0B: /* Power Control */
  75        shift = (offset - 0x8) * 8;
  76        s->status &= ~(mask << shift);
  77        s->status |= ((value & mask) << shift);
  78        break;
  79    case 0x0c: /* Invalidate All Registers In Secure State */
  80        /* no-op as we do not implement caches */
  81        break;
  82    case 0x40: /* Filtering Start Address Register */
  83    case 0x44: /* Filtering End Address Register */
  84        /* RAZ/WI, like an implementation with only one AXI master */
  85        break;
  86    case 0x50: /* SCU Access Control Register */
  87    case 0x54: /* SCU Non-secure Access Control Register */
  88        /* unimplemented, fall through */
  89    default:
  90        break;
  91    }
  92}
  93
  94static const MemoryRegionOps a9_scu_ops = {
  95    .read = a9_scu_read,
  96    .write = a9_scu_write,
  97    .endianness = DEVICE_NATIVE_ENDIAN,
  98};
  99
 100static void a9_scu_reset(DeviceState *dev)
 101{
 102    A9SCUState *s = A9_SCU(dev);
 103    s->control = 0;
 104}
 105
 106static void a9_scu_init(Object *obj)
 107{
 108    A9SCUState *s = A9_SCU(obj);
 109    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 110
 111    if (!s->num_cpu) {
 112        s->num_cpu = fdt_generic_num_cpus;
 113    }
 114
 115    memory_region_init_io(&s->iomem, obj, &a9_scu_ops, s,
 116                          "a9-scu", 0x100);
 117    sysbus_init_mmio(sbd, &s->iomem);
 118}
 119
 120static const VMStateDescription vmstate_a9_scu = {
 121    .name = "a9-scu",
 122    .version_id = 1,
 123    .minimum_version_id = 1,
 124    .fields = (VMStateField[]) {
 125        VMSTATE_UINT32(control, A9SCUState),
 126        VMSTATE_UINT32(status, A9SCUState),
 127        VMSTATE_END_OF_LIST()
 128    }
 129};
 130
 131static Property a9_scu_properties[] = {
 132    DEFINE_PROP_UINT32("num-cpu", A9SCUState, num_cpu, 0),
 133    DEFINE_PROP_END_OF_LIST(),
 134};
 135
 136static void a9_scu_class_init(ObjectClass *klass, void *data)
 137{
 138    DeviceClass *dc = DEVICE_CLASS(klass);
 139
 140    dc->props = a9_scu_properties;
 141    dc->vmsd = &vmstate_a9_scu;
 142    dc->reset = a9_scu_reset;
 143}
 144
 145static const TypeInfo a9_scu_info = {
 146    .name          = TYPE_A9_SCU,
 147    .parent        = TYPE_SYS_BUS_DEVICE,
 148    .instance_size = sizeof(A9SCUState),
 149    .instance_init = a9_scu_init,
 150    .class_init    = a9_scu_class_init,
 151};
 152
 153static void a9mp_register_types(void)
 154{
 155    type_register_static(&a9_scu_info);
 156}
 157
 158type_init(a9mp_register_types)
 159