2 * Cortex-A9MPCore Snoop Control Unit (SCU) emulation.
4 * Copyright (c) 2009 CodeSourcery.
5 * Copyright (c) 2011 Linaro Limited.
6 * Written by Paul Brook, Peter Maydell.
8 * This code is licensed under the GPL.
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"
17 #include "qemu/module.h"
19 #define A9_SCU_CPU_MAX 4
21 static uint64_t a9_scu_read(void *opaque
, hwaddr offset
,
24 A9SCUState
*s
= (A9SCUState
*)opaque
;
26 case 0x00: /* Control */
28 case 0x04: /* Configuration */
29 return (((1 << s
->num_cpu
) - 1) << 4) | (s
->num_cpu
- 1);
30 case 0x08: /* CPU Power Status */
32 case 0x0c: /* Invalidate All Registers In Secure State */
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 */
38 case 0x50: /* SCU Access Control Register */
39 case 0x54: /* SCU Non-secure Access Control Register */
40 /* unimplemented, fall through */
42 qemu_log_mask(LOG_UNIMP
, "%s: Unsupported offset 0x%"HWADDR_PRIx
"\n",
48 static void a9_scu_write(void *opaque
, hwaddr offset
,
49 uint64_t value
, unsigned size
)
51 A9SCUState
*s
= (A9SCUState
*)opaque
;
54 case 0x00: /* Control */
55 s
->control
= value
& 1;
57 case 0x4: /* Configuration: RO */
59 case 0x08: case 0x09: case 0x0A: case 0x0B: /* Power Control */
62 case 0x0c: /* Invalidate All Registers In Secure State */
63 /* no-op as we do not implement caches */
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 */
69 case 0x50: /* SCU Access Control Register */
70 case 0x54: /* SCU Non-secure Access Control Register */
71 /* unimplemented, fall through */
73 qemu_log_mask(LOG_UNIMP
, "%s: Unsupported offset 0x%"HWADDR_PRIx
74 " value 0x%"PRIx64
"\n",
75 __func__
, offset
, value
);
80 static const MemoryRegionOps a9_scu_ops
= {
82 .write
= a9_scu_write
,
91 .endianness
= DEVICE_NATIVE_ENDIAN
,
94 static void a9_scu_reset(DeviceState
*dev
)
96 A9SCUState
*s
= A9_SCU(dev
);
100 static void a9_scu_realize(DeviceState
*dev
, Error
**errp
)
102 A9SCUState
*s
= A9_SCU(dev
);
103 SysBusDevice
*sbd
= SYS_BUS_DEVICE(dev
);
105 if (!s
->num_cpu
|| s
->num_cpu
> A9_SCU_CPU_MAX
) {
106 error_setg(errp
, "Illegal CPU count: %u", s
->num_cpu
);
110 memory_region_init_io(&s
->iomem
, OBJECT(s
), &a9_scu_ops
, s
,
112 sysbus_init_mmio(sbd
, &s
->iomem
);
115 static const VMStateDescription vmstate_a9_scu
= {
118 .minimum_version_id
= 1,
119 .fields
= (const VMStateField
[]) {
120 VMSTATE_UINT32(control
, A9SCUState
),
121 VMSTATE_UINT32(status
, A9SCUState
),
122 VMSTATE_END_OF_LIST()
126 static Property a9_scu_properties
[] = {
127 DEFINE_PROP_UINT32("num-cpu", A9SCUState
, num_cpu
, 1),
128 DEFINE_PROP_END_OF_LIST(),
131 static void a9_scu_class_init(ObjectClass
*klass
, void *data
)
133 DeviceClass
*dc
= DEVICE_CLASS(klass
);
135 device_class_set_props(dc
, a9_scu_properties
);
136 dc
->vmsd
= &vmstate_a9_scu
;
137 device_class_set_legacy_reset(dc
, a9_scu_reset
);
138 dc
->realize
= a9_scu_realize
;
141 static const TypeInfo a9_scu_info
= {
143 .parent
= TYPE_SYS_BUS_DEVICE
,
144 .instance_size
= sizeof(A9SCUState
),
145 .class_init
= a9_scu_class_init
,
148 static void a9mp_register_types(void)
150 type_register_static(&a9_scu_info
);
153 type_init(a9mp_register_types
)