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