199f0c046SNinad Palsule /* 299f0c046SNinad Palsule * SPDX-License-Identifier: GPL-2.0-or-later 399f0c046SNinad Palsule * Copyright (C) 2024 IBM Corp. 499f0c046SNinad Palsule * 599f0c046SNinad Palsule * IBM Local bus where FSI slaves are connected 699f0c046SNinad Palsule */ 799f0c046SNinad Palsule 899f0c046SNinad Palsule #include "qemu/osdep.h" 999f0c046SNinad Palsule #include "qapi/error.h" 1099f0c046SNinad Palsule #include "hw/fsi/lbus.h" 1199f0c046SNinad Palsule #include "hw/qdev-properties.h" 12*ca782334SNinad Palsule #include "qemu/log.h" 1399f0c046SNinad Palsule #include "trace.h" 1499f0c046SNinad Palsule 15*ca782334SNinad Palsule #define TO_REG(offset) ((offset) >> 2) 16*ca782334SNinad Palsule 1799f0c046SNinad Palsule static void fsi_lbus_init(Object *o) 1899f0c046SNinad Palsule { 1999f0c046SNinad Palsule FSILBus *lbus = FSI_LBUS(o); 2099f0c046SNinad Palsule 2199f0c046SNinad Palsule memory_region_init(&lbus->mr, OBJECT(lbus), TYPE_FSI_LBUS, 1 * MiB); 2299f0c046SNinad Palsule } 2399f0c046SNinad Palsule 2499f0c046SNinad Palsule static const TypeInfo fsi_lbus_info = { 2599f0c046SNinad Palsule .name = TYPE_FSI_LBUS, 2699f0c046SNinad Palsule .parent = TYPE_BUS, 2799f0c046SNinad Palsule .instance_init = fsi_lbus_init, 2899f0c046SNinad Palsule .instance_size = sizeof(FSILBus), 2999f0c046SNinad Palsule }; 3099f0c046SNinad Palsule 3199f0c046SNinad Palsule static const TypeInfo fsi_lbus_device_type_info = { 3299f0c046SNinad Palsule .name = TYPE_FSI_LBUS_DEVICE, 3399f0c046SNinad Palsule .parent = TYPE_DEVICE, 3499f0c046SNinad Palsule .instance_size = sizeof(FSILBusDevice), 3599f0c046SNinad Palsule .abstract = true, 3699f0c046SNinad Palsule }; 3799f0c046SNinad Palsule 38*ca782334SNinad Palsule static uint64_t fsi_scratchpad_read(void *opaque, hwaddr addr, unsigned size) 39*ca782334SNinad Palsule { 40*ca782334SNinad Palsule FSIScratchPad *s = SCRATCHPAD(opaque); 41*ca782334SNinad Palsule int reg = TO_REG(addr); 42*ca782334SNinad Palsule 43*ca782334SNinad Palsule trace_fsi_scratchpad_read(addr, size); 44*ca782334SNinad Palsule 45*ca782334SNinad Palsule if (reg >= FSI_SCRATCHPAD_NR_REGS) { 46*ca782334SNinad Palsule qemu_log_mask(LOG_GUEST_ERROR, 47*ca782334SNinad Palsule "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n", 48*ca782334SNinad Palsule __func__, addr); 49*ca782334SNinad Palsule return 0; 50*ca782334SNinad Palsule } 51*ca782334SNinad Palsule 52*ca782334SNinad Palsule return s->regs[reg]; 53*ca782334SNinad Palsule } 54*ca782334SNinad Palsule 55*ca782334SNinad Palsule static void fsi_scratchpad_write(void *opaque, hwaddr addr, uint64_t data, 56*ca782334SNinad Palsule unsigned size) 57*ca782334SNinad Palsule { 58*ca782334SNinad Palsule FSIScratchPad *s = SCRATCHPAD(opaque); 59*ca782334SNinad Palsule 60*ca782334SNinad Palsule trace_fsi_scratchpad_write(addr, size, data); 61*ca782334SNinad Palsule int reg = TO_REG(addr); 62*ca782334SNinad Palsule 63*ca782334SNinad Palsule if (reg >= FSI_SCRATCHPAD_NR_REGS) { 64*ca782334SNinad Palsule qemu_log_mask(LOG_GUEST_ERROR, 65*ca782334SNinad Palsule "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", 66*ca782334SNinad Palsule __func__, addr); 67*ca782334SNinad Palsule return; 68*ca782334SNinad Palsule } 69*ca782334SNinad Palsule 70*ca782334SNinad Palsule s->regs[reg] = data; 71*ca782334SNinad Palsule } 72*ca782334SNinad Palsule 73*ca782334SNinad Palsule static const struct MemoryRegionOps scratchpad_ops = { 74*ca782334SNinad Palsule .read = fsi_scratchpad_read, 75*ca782334SNinad Palsule .write = fsi_scratchpad_write, 76*ca782334SNinad Palsule .endianness = DEVICE_BIG_ENDIAN, 77*ca782334SNinad Palsule }; 78*ca782334SNinad Palsule 79*ca782334SNinad Palsule static void fsi_scratchpad_realize(DeviceState *dev, Error **errp) 80*ca782334SNinad Palsule { 81*ca782334SNinad Palsule FSILBusDevice *ldev = FSI_LBUS_DEVICE(dev); 82*ca782334SNinad Palsule 83*ca782334SNinad Palsule memory_region_init_io(&ldev->iomem, OBJECT(ldev), &scratchpad_ops, 84*ca782334SNinad Palsule ldev, TYPE_FSI_SCRATCHPAD, 0x400); 85*ca782334SNinad Palsule } 86*ca782334SNinad Palsule 87*ca782334SNinad Palsule static void fsi_scratchpad_reset(DeviceState *dev) 88*ca782334SNinad Palsule { 89*ca782334SNinad Palsule FSIScratchPad *s = SCRATCHPAD(dev); 90*ca782334SNinad Palsule 91*ca782334SNinad Palsule memset(s->regs, 0, sizeof(s->regs)); 92*ca782334SNinad Palsule } 93*ca782334SNinad Palsule 94*ca782334SNinad Palsule static void fsi_scratchpad_class_init(ObjectClass *klass, void *data) 95*ca782334SNinad Palsule { 96*ca782334SNinad Palsule DeviceClass *dc = DEVICE_CLASS(klass); 97*ca782334SNinad Palsule 98*ca782334SNinad Palsule dc->bus_type = TYPE_FSI_LBUS; 99*ca782334SNinad Palsule dc->realize = fsi_scratchpad_realize; 100*ca782334SNinad Palsule dc->reset = fsi_scratchpad_reset; 101*ca782334SNinad Palsule } 102*ca782334SNinad Palsule 103*ca782334SNinad Palsule static const TypeInfo fsi_scratchpad_info = { 104*ca782334SNinad Palsule .name = TYPE_FSI_SCRATCHPAD, 105*ca782334SNinad Palsule .parent = TYPE_FSI_LBUS_DEVICE, 106*ca782334SNinad Palsule .instance_size = sizeof(FSIScratchPad), 107*ca782334SNinad Palsule .class_init = fsi_scratchpad_class_init, 108*ca782334SNinad Palsule }; 109*ca782334SNinad Palsule 11099f0c046SNinad Palsule static void fsi_lbus_register_types(void) 11199f0c046SNinad Palsule { 11299f0c046SNinad Palsule type_register_static(&fsi_lbus_info); 11399f0c046SNinad Palsule type_register_static(&fsi_lbus_device_type_info); 114*ca782334SNinad Palsule type_register_static(&fsi_scratchpad_info); 11599f0c046SNinad Palsule } 11699f0c046SNinad Palsule 11799f0c046SNinad Palsule type_init(fsi_lbus_register_types); 118