xref: /openbmc/qemu/hw/misc/a9scu.c (revision db725815)
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 "migration/vmstate.h"
14 #include "qemu/module.h"
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 
107 static void a9_scu_init(Object *obj)
108 {
109     A9SCUState *s = A9_SCU(obj);
110     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
111 
112     memory_region_init_io(&s->iomem, obj, &a9_scu_ops, s,
113                           "a9-scu", 0x100);
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 
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),
146     .instance_init = a9_scu_init,
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)
156