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