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