xref: /openbmc/qemu/hw/misc/a9scu.c (revision 979a8902)
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 
11 #include "qemu/osdep.h"
12 #include "hw/misc/a9scu.h"
13 #include "hw/qdev-properties.h"
14 #include "migration/vmstate.h"
15 #include "qemu/module.h"
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 
108 static void a9_scu_init(Object *obj)
109 {
110     A9SCUState *s = A9_SCU(obj);
111     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
112 
113     memory_region_init_io(&s->iomem, obj, &a9_scu_ops, s,
114                           "a9-scu", 0x100);
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 
138     device_class_set_props(dc, 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),
147     .instance_init = a9_scu_init,
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)
157