xref: /openbmc/qemu/hw/fsi/cfam.c (revision dbfd61ce579af0f57c8be9099c03e1c5553df00c)
1 /*
2  * SPDX-License-Identifier: GPL-2.0-or-later
3  * Copyright (C) 2019 IBM Corp.
4  *
5  * IBM On-chip Peripheral Bus
6  */
7 
8 #include "qemu/osdep.h"
9 
10 #include "qapi/error.h"
11 #include "qemu/log.h"
12 
13 #include "hw/fsi/bits.h"
14 #include "hw/fsi/cfam.h"
15 #include "hw/fsi/fsi.h"
16 #include "hw/fsi/engine-scratchpad.h"
17 
18 #include "hw/qdev-properties.h"
19 
20 #define TO_REG(x)                          ((x) >> 2)
21 
22 #define CFAM_ENGINE_CONFIG                  TO_REG(0x04)
23 
24 #define CFAM_CONFIG_CHIP_ID                TO_REG(0x00)
25 #define CFAM_CONFIG_CHIP_ID_P9             0xc0022d15
26 #define   CFAM_CONFIG_CHIP_ID_BREAK        0xc0de0000
27 
28 static uint64_t cfam_config_read(void *opaque, hwaddr addr, unsigned size)
29 {
30     CFAMConfig *config;
31     CFAMState *cfam;
32     LBusNode *node;
33     int i;
34 
35     config = CFAM_CONFIG(opaque);
36     cfam = container_of(config, CFAMState, config);
37 
38     qemu_log_mask(LOG_UNIMP, "%s: read @0x%" HWADDR_PRIx " size=%d\n",
39                   __func__, addr, size);
40 
41     assert(size == 4);
42     assert(!(addr & 3));
43 
44 #if 0 /* FIXME: Make it dynamic */
45     if (addr + size > sizeof(s->regs)) {
46         qemu_log_mask(LOG_GUEST_ERROR, "%s: Out of bounds read: 0x%"HWADDR_PRIx" for %u\n",
47                       __func__, addr, size);
48         return 0;
49     }
50 
51     val = s->regs[TO_REG(addr)];
52     printf("%s: read 0x%x\n", __func__, val);
53 #endif
54 
55     switch (addr) {
56         case 0x00:
57             return CFAM_CONFIG_CHIP_ID_P9;
58         case 0x04:
59             return ENGINE_CONFIG_NEXT
60                 | 0x00010000                    /* slots */
61                 | 0x00001000                    /* version */
62                 | ENGINE_CONFIG_TYPE_PEEK   /* type */
63                 | 0x0000000c;                   /* crc */
64         case 0x08:
65             return ENGINE_CONFIG_NEXT
66                 | 0x00010000                    /* slots */
67                 | 0x00005000                    /* version */
68                 | ENGINE_CONFIG_TYPE_FSI    /* type */
69                 | 0x0000000a;                   /* crc */
70             break;
71         default:
72             /* FIXME: Improve this */
73             i = 0xc;
74             QLIST_FOREACH(node, &cfam->lbus.devices, next) {
75                 if (i == addr)
76                     return LBUS_DEVICE_GET_CLASS(node->ldev)->config;
77                 i += size;
78             }
79 
80             if (i == addr)
81                 return 0;
82 
83             return 0xc0de0000;
84     }
85 }
86 
87 static void cfam_config_write(void *opaque, hwaddr addr, uint64_t data,
88                                  unsigned size)
89 {
90     CFAMConfig *s = CFAM_CONFIG(opaque);
91 
92     qemu_log_mask(LOG_UNIMP, "%s: write @0x%" HWADDR_PRIx " size=%d "
93                   "value=%"PRIx64"\n", __func__, addr, size, data);
94 
95     assert(size == 4);
96     assert(!(addr & 3));
97 
98 #if 0
99     if (addr + size > sizeof(s->regs)) {
100         qemu_log_mask(LOG_GUEST_ERROR, "%s: Out of bounds write: 0x%"HWADDR_PRIx" for %u\n",
101                       __func__, addr, size);
102         return;
103     }
104 #endif
105 
106     switch (TO_REG(addr)) {
107         case CFAM_CONFIG_CHIP_ID:
108         case CFAM_CONFIG_CHIP_ID + 4:
109             if (data == CFAM_CONFIG_CHIP_ID_BREAK) {
110                 qbus_reset_all(qdev_get_parent_bus(DEVICE(s)));
111             }
112             break;
113     }
114 }
115 
116 static const struct MemoryRegionOps cfam_config_ops = {
117     .read = cfam_config_read,
118     .write = cfam_config_write,
119     .endianness = DEVICE_BIG_ENDIAN,
120 };
121 
122 static void cfam_config_realize(DeviceState *dev, Error **errp)
123 {
124     CFAMConfig *s = CFAM_CONFIG(dev);
125 
126     memory_region_init_io(&s->iomem, OBJECT(s), &cfam_config_ops, s,
127                           TYPE_CFAM_CONFIG, 0x400);
128 }
129 
130 static void cfam_config_reset(DeviceState *dev)
131 {
132     /* Config is read-only */
133 }
134 
135 static void cfam_config_class_init(ObjectClass *klass, void *data)
136 {
137     DeviceClass *dc = DEVICE_CLASS(klass);
138     dc->bus_type = TYPE_LBUS;
139     dc->realize = cfam_config_realize;
140     dc->reset = cfam_config_reset;
141 }
142 
143 static const TypeInfo cfam_config_info = {
144     .name = TYPE_CFAM_CONFIG,
145     .parent = TYPE_DEVICE,
146     .instance_size = sizeof(CFAMConfig),
147     .class_init = cfam_config_class_init,
148 };
149 
150 static void lbus_realize(BusState *bus, Error **errp)
151 {
152     LBusNode *node;
153     LBus *lbus = LBUS(bus);
154 
155     memory_region_init(&lbus->mr, OBJECT(lbus), TYPE_LBUS,
156                        (2 * 1024 * 1024) - 0x400);
157 
158     QLIST_FOREACH(node, &lbus->devices, next) {
159         memory_region_add_subregion(&lbus->mr, node->ldev->address,
160                                     &node->ldev->iomem);
161     }
162 }
163 
164 static void lbus_init(Object *o)
165 {
166 }
167 
168 static void lbus_class_init(ObjectClass *klass, void *data)
169 {
170     BusClass *k = BUS_CLASS(klass);
171     k->realize = lbus_realize;
172 }
173 
174 static const TypeInfo lbus_info = {
175     .name = TYPE_LBUS,
176     .parent = TYPE_BUS,
177     .instance_init = lbus_init,
178     .instance_size = sizeof(LBus),
179     .class_init = lbus_class_init,
180 };
181 
182 static Property lbus_device_props[] = {
183     DEFINE_PROP_UINT32("address", LBusDevice, address, 0),
184     DEFINE_PROP_END_OF_LIST(),
185 };
186 
187 DeviceState *lbus_create_device(LBus *bus, const char *type, uint32_t addr)
188 {
189     DeviceState *dev;
190     LBusNode *node;
191 
192     dev = qdev_new(type);
193     qdev_prop_set_uint8(dev, "address", addr);
194     qdev_realize_and_unref(dev, &bus->bus, &error_fatal);
195 
196     /* Move to post_load */
197     node = g_malloc(sizeof(struct LBusNode));
198     node->ldev = LBUS_DEVICE(dev);
199     QLIST_INSERT_HEAD(&bus->devices, node, next);
200 
201     return dev;
202 }
203 
204 static void lbus_device_class_init(ObjectClass *klass, void *data)
205 {
206     DeviceClass *dc = DEVICE_CLASS(klass);
207 
208     dc->bus_type = TYPE_LBUS;
209     device_class_set_props(dc, lbus_device_props);
210 }
211 
212 static const TypeInfo lbus_device_type_info = {
213     .name = TYPE_LBUS_DEVICE,
214     .parent = TYPE_DEVICE,
215     .instance_size = sizeof(LBusDevice),
216     .abstract = true,
217     .class_init = lbus_device_class_init,
218     .class_size = sizeof(LBusDeviceClass),
219 };
220 
221 static uint64_t cfam_unimplemented_read(void *opaque, hwaddr addr, unsigned size)
222 {
223     qemu_log_mask(LOG_UNIMP, "%s: read @0x%" HWADDR_PRIx " size=%d\n",
224                   __func__, addr, size);
225 
226     return 0;
227 }
228 
229 static void cfam_unimplemented_write(void *opaque, hwaddr addr, uint64_t data,
230                                  unsigned size)
231 {
232     qemu_log_mask(LOG_UNIMP, "%s: write @0x%" HWADDR_PRIx " size=%d "
233                   "value=%"PRIx64"\n", __func__, addr, size, data);
234 }
235 
236 static const struct MemoryRegionOps cfam_unimplemented_ops = {
237     .read = cfam_unimplemented_read,
238     .write = cfam_unimplemented_write,
239     .endianness = DEVICE_BIG_ENDIAN,
240 };
241 
242 static void cfam_realize(DeviceState *dev, Error **errp)
243 {
244     CFAMState *cfam = CFAM(dev);
245     FSISlaveState *slave = FSI_SLAVE(dev);
246     Error *err = NULL;
247 
248     /* Each slave has a 2MiB address space */
249     memory_region_init_io(&cfam->mr, OBJECT(cfam), &cfam_unimplemented_ops, cfam,
250                           TYPE_CFAM, 2 * 1024 * 1024);
251     address_space_init(&cfam->as, &cfam->mr, TYPE_CFAM);
252 
253     qbus_create_inplace(&cfam->lbus, sizeof(cfam->lbus), TYPE_LBUS,
254                         DEVICE(cfam), NULL);
255 
256     lbus_create_device(&cfam->lbus, TYPE_SCRATCHPAD, 0);
257 
258     object_property_set_bool(OBJECT(&cfam->config), "realized", true, &err);
259     if (err) {
260         error_propagate(errp, err);
261         return;
262     }
263     qdev_set_parent_bus(DEVICE(&cfam->config), BUS(&cfam->lbus), &error_abort);
264 
265     object_property_set_bool(OBJECT(&cfam->lbus), "realized", true, &err);
266     if (err) {
267         error_propagate(errp, err);
268         return;
269     }
270 
271     memory_region_add_subregion(&cfam->mr, 0, &cfam->config.iomem);
272     /* memory_region_add_subregion(&cfam->mr, 0x800, &cfam->lbus.peek.iomem); */
273     memory_region_add_subregion(&cfam->mr, 0x800, &slave->iomem);
274     memory_region_add_subregion(&cfam->mr, 0xc00, &cfam->lbus.mr);
275 }
276 
277 static void cfam_reset(DeviceState *dev)
278 {
279     /* TODO: Figure out how inherited reset works */
280 }
281 
282 static void cfam_init(Object *o)
283 {
284     CFAMState *s = CFAM(o);
285 
286     object_initialize_child(o, TYPE_CFAM_CONFIG, &s->config, TYPE_CFAM_CONFIG);
287 }
288 
289 static void cfam_finalize(Object *o)
290 {
291 #if 0 /* TODO (clg): fix device-introspect-test */
292     CFAMState *s = CFAM(o);
293 
294     address_space_destroy(&s->as);
295 #endif
296 }
297 
298 static void cfam_class_init(ObjectClass *klass, void *data)
299 {
300     DeviceClass *dc = DEVICE_CLASS(klass);
301     dc->bus_type = TYPE_FSI_BUS;
302     dc->realize = cfam_realize;
303     dc->reset = cfam_reset;
304 }
305 
306 static const TypeInfo cfam_info = {
307     .name = TYPE_CFAM,
308     .parent = TYPE_FSI_SLAVE,
309     .instance_init = cfam_init,
310     .instance_finalize = cfam_finalize,
311     .instance_size = sizeof(CFAMState),
312     .class_init = cfam_class_init,
313 };
314 
315 static void cfam_register_types(void)
316 {
317     type_register_static(&cfam_config_info);
318     type_register_static(&lbus_info);
319     type_register_static(&lbus_device_type_info);
320     type_register_static(&cfam_info);
321 }
322 
323 type_init(cfam_register_types);
324