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 "qapi/error.h"
  16#include "qemu/log.h"
  17#include "qemu/module.h"
  18
  19#define A9_SCU_CPU_MAX  4
  20
  21static uint64_t a9_scu_read(void *opaque, hwaddr offset,
  22                            unsigned size)
  23{
  24    A9SCUState *s = (A9SCUState *)opaque;
  25    switch (offset) {
  26    case 0x00: /* Control */
  27        return s->control;
  28    case 0x04: /* Configuration */
  29        return (((1 << s->num_cpu) - 1) << 4) | (s->num_cpu - 1);
  30    case 0x08: /* CPU Power Status */
  31        return s->status;
  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        qemu_log_mask(LOG_UNIMP, "%s: Unsupported offset 0x%"HWADDR_PRIx"\n",
  43                      __func__, offset);
  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
  53    switch (offset) {
  54    case 0x00: /* Control */
  55        s->control = value & 1;
  56        break;
  57    case 0x4: /* Configuration: RO */
  58        break;
  59    case 0x08: case 0x09: case 0x0A: case 0x0B: /* Power Control */
  60        s->status = value;
  61        break;
  62    case 0x0c: /* Invalidate All Registers In Secure State */
  63        /* no-op as we do not implement caches */
  64        break;
  65    case 0x40: /* Filtering Start Address Register */
  66    case 0x44: /* Filtering End Address Register */
  67        /* RAZ/WI, like an implementation with only one AXI master */
  68        break;
  69    case 0x50: /* SCU Access Control Register */
  70    case 0x54: /* SCU Non-secure Access Control Register */
  71        /* unimplemented, fall through */
  72    default:
  73        qemu_log_mask(LOG_UNIMP, "%s: Unsupported offset 0x%"HWADDR_PRIx
  74                                 " value 0x%"PRIx64"\n",
  75                      __func__, offset, value);
  76        break;
  77    }
  78}
  79
  80static const MemoryRegionOps a9_scu_ops = {
  81    .read = a9_scu_read,
  82    .write = a9_scu_write,
  83    .impl = {
  84        .min_access_size = 4,
  85        .max_access_size = 4,
  86    },
  87    .valid = {
  88        .min_access_size = 1,
  89        .max_access_size = 4,
  90    },
  91    .endianness = DEVICE_NATIVE_ENDIAN,
  92};
  93
  94static void a9_scu_reset(DeviceState *dev)
  95{
  96    A9SCUState *s = A9_SCU(dev);
  97    s->control = 0;
  98}
  99
 100static void a9_scu_realize(DeviceState *dev, Error **errp)
 101{
 102    A9SCUState *s = A9_SCU(dev);
 103    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
 104
 105    if (!s->num_cpu || s->num_cpu > A9_SCU_CPU_MAX) {
 106        error_setg(errp, "Illegal CPU count: %u", s->num_cpu);
 107        return;
 108    }
 109
 110    memory_region_init_io(&s->iomem, OBJECT(s), &a9_scu_ops, s,
 111                          "a9-scu", 0x100);
 112    sysbus_init_mmio(sbd, &s->iomem);
 113}
 114
 115static const VMStateDescription vmstate_a9_scu = {
 116    .name = "a9-scu",
 117    .version_id = 1,
 118    .minimum_version_id = 1,
 119    .fields = (VMStateField[]) {
 120        VMSTATE_UINT32(control, A9SCUState),
 121        VMSTATE_UINT32(status, A9SCUState),
 122        VMSTATE_END_OF_LIST()
 123    }
 124};
 125
 126static Property a9_scu_properties[] = {
 127    DEFINE_PROP_UINT32("num-cpu", A9SCUState, num_cpu, 1),
 128    DEFINE_PROP_END_OF_LIST(),
 129};
 130
 131static void a9_scu_class_init(ObjectClass *klass, void *data)
 132{
 133    DeviceClass *dc = DEVICE_CLASS(klass);
 134
 135    device_class_set_props(dc, a9_scu_properties);
 136    dc->vmsd = &vmstate_a9_scu;
 137    dc->reset = a9_scu_reset;
 138    dc->realize = a9_scu_realize;
 139}
 140
 141static const TypeInfo a9_scu_info = {
 142    .name          = TYPE_A9_SCU,
 143    .parent        = TYPE_SYS_BUS_DEVICE,
 144    .instance_size = sizeof(A9SCUState),
 145    .class_init    = a9_scu_class_init,
 146};
 147
 148static void a9mp_register_types(void)
 149{
 150    type_register_static(&a9_scu_info);
 151}
 152
 153type_init(a9mp_register_types)
 154