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