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