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