]>
Commit | Line | Data |
---|---|---|
353575f0 PC |
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 | ||
8ef94f0b | 11 | #include "qemu/osdep.h" |
fc719d77 | 12 | #include "hw/misc/a9scu.h" |
a27bd6c7 | 13 | #include "hw/qdev-properties.h" |
d6454270 | 14 | #include "migration/vmstate.h" |
0b8fa32f | 15 | #include "qemu/module.h" |
353575f0 PC |
16 | |
17 | static 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 | ||
48 | static 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 | ||
96 | static const MemoryRegionOps a9_scu_ops = { | |
97 | .read = a9_scu_read, | |
98 | .write = a9_scu_write, | |
99 | .endianness = DEVICE_NATIVE_ENDIAN, | |
100 | }; | |
101 | ||
102 | static void a9_scu_reset(DeviceState *dev) | |
103 | { | |
104 | A9SCUState *s = A9_SCU(dev); | |
105 | s->control = 0; | |
106 | } | |
107 | ||
9eb39db5 | 108 | static void a9_scu_init(Object *obj) |
353575f0 | 109 | { |
9eb39db5 AF |
110 | A9SCUState *s = A9_SCU(obj); |
111 | SysBusDevice *sbd = SYS_BUS_DEVICE(obj); | |
353575f0 | 112 | |
9eb39db5 | 113 | memory_region_init_io(&s->iomem, obj, &a9_scu_ops, s, |
3c161542 | 114 | "a9-scu", 0x100); |
353575f0 PC |
115 | sysbus_init_mmio(sbd, &s->iomem); |
116 | } | |
117 | ||
118 | static 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 | ||
129 | static Property a9_scu_properties[] = { | |
130 | DEFINE_PROP_UINT32("num-cpu", A9SCUState, num_cpu, 1), | |
131 | DEFINE_PROP_END_OF_LIST(), | |
132 | }; | |
133 | ||
134 | static void a9_scu_class_init(ObjectClass *klass, void *data) | |
135 | { | |
136 | DeviceClass *dc = DEVICE_CLASS(klass); | |
137 | ||
353575f0 PC |
138 | dc->props = a9_scu_properties; |
139 | dc->vmsd = &vmstate_a9_scu; | |
140 | dc->reset = a9_scu_reset; | |
141 | } | |
142 | ||
143 | static const TypeInfo a9_scu_info = { | |
144 | .name = TYPE_A9_SCU, | |
145 | .parent = TYPE_SYS_BUS_DEVICE, | |
146 | .instance_size = sizeof(A9SCUState), | |
9eb39db5 | 147 | .instance_init = a9_scu_init, |
353575f0 PC |
148 | .class_init = a9_scu_class_init, |
149 | }; | |
150 | ||
151 | static void a9mp_register_types(void) | |
152 | { | |
153 | type_register_static(&a9_scu_info); | |
154 | } | |
155 | ||
156 | type_init(a9mp_register_types) |