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