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"
12ca782334SNinad Palsule #include "qemu/log.h"
1399f0c046SNinad Palsule #include "trace.h"
1499f0c046SNinad Palsule
15ca782334SNinad Palsule #define TO_REG(offset) ((offset) >> 2)
16ca782334SNinad Palsule
fsi_lbus_init(Object * o)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
fsi_scratchpad_read(void * opaque,hwaddr addr,unsigned size)38ca782334SNinad Palsule static uint64_t fsi_scratchpad_read(void *opaque, hwaddr addr, unsigned size)
39ca782334SNinad Palsule {
40ca782334SNinad Palsule FSIScratchPad *s = SCRATCHPAD(opaque);
41ca782334SNinad Palsule int reg = TO_REG(addr);
42ca782334SNinad Palsule
43ca782334SNinad Palsule trace_fsi_scratchpad_read(addr, size);
44ca782334SNinad Palsule
45ca782334SNinad Palsule if (reg >= FSI_SCRATCHPAD_NR_REGS) {
46ca782334SNinad Palsule qemu_log_mask(LOG_GUEST_ERROR,
47ca782334SNinad Palsule "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
48ca782334SNinad Palsule __func__, addr);
49ca782334SNinad Palsule return 0;
50ca782334SNinad Palsule }
51ca782334SNinad Palsule
52ca782334SNinad Palsule return s->regs[reg];
53ca782334SNinad Palsule }
54ca782334SNinad Palsule
fsi_scratchpad_write(void * opaque,hwaddr addr,uint64_t data,unsigned size)55ca782334SNinad Palsule static void fsi_scratchpad_write(void *opaque, hwaddr addr, uint64_t data,
56ca782334SNinad Palsule unsigned size)
57ca782334SNinad Palsule {
58ca782334SNinad Palsule FSIScratchPad *s = SCRATCHPAD(opaque);
59ca782334SNinad Palsule
60ca782334SNinad Palsule trace_fsi_scratchpad_write(addr, size, data);
61ca782334SNinad Palsule int reg = TO_REG(addr);
62ca782334SNinad Palsule
63ca782334SNinad Palsule if (reg >= FSI_SCRATCHPAD_NR_REGS) {
64ca782334SNinad Palsule qemu_log_mask(LOG_GUEST_ERROR,
65ca782334SNinad Palsule "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
66ca782334SNinad Palsule __func__, addr);
67ca782334SNinad Palsule return;
68ca782334SNinad Palsule }
69ca782334SNinad Palsule
70ca782334SNinad Palsule s->regs[reg] = data;
71ca782334SNinad Palsule }
72ca782334SNinad Palsule
73ca782334SNinad Palsule static const struct MemoryRegionOps scratchpad_ops = {
74ca782334SNinad Palsule .read = fsi_scratchpad_read,
75ca782334SNinad Palsule .write = fsi_scratchpad_write,
76ca782334SNinad Palsule .endianness = DEVICE_BIG_ENDIAN,
77ca782334SNinad Palsule };
78ca782334SNinad Palsule
fsi_scratchpad_realize(DeviceState * dev,Error ** errp)79ca782334SNinad Palsule static void fsi_scratchpad_realize(DeviceState *dev, Error **errp)
80ca782334SNinad Palsule {
81ca782334SNinad Palsule FSILBusDevice *ldev = FSI_LBUS_DEVICE(dev);
82ca782334SNinad Palsule
83ca782334SNinad Palsule memory_region_init_io(&ldev->iomem, OBJECT(ldev), &scratchpad_ops,
84ca782334SNinad Palsule ldev, TYPE_FSI_SCRATCHPAD, 0x400);
85ca782334SNinad Palsule }
86ca782334SNinad Palsule
fsi_scratchpad_reset(DeviceState * dev)87ca782334SNinad Palsule static void fsi_scratchpad_reset(DeviceState *dev)
88ca782334SNinad Palsule {
89ca782334SNinad Palsule FSIScratchPad *s = SCRATCHPAD(dev);
90ca782334SNinad Palsule
91ca782334SNinad Palsule memset(s->regs, 0, sizeof(s->regs));
92ca782334SNinad Palsule }
93ca782334SNinad Palsule
fsi_scratchpad_class_init(ObjectClass * klass,void * data)94ca782334SNinad Palsule static void fsi_scratchpad_class_init(ObjectClass *klass, void *data)
95ca782334SNinad Palsule {
96ca782334SNinad Palsule DeviceClass *dc = DEVICE_CLASS(klass);
97ca782334SNinad Palsule
98ca782334SNinad Palsule dc->bus_type = TYPE_FSI_LBUS;
99ca782334SNinad Palsule dc->realize = fsi_scratchpad_realize;
100*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, fsi_scratchpad_reset);
101ca782334SNinad Palsule }
102ca782334SNinad Palsule
103ca782334SNinad Palsule static const TypeInfo fsi_scratchpad_info = {
104ca782334SNinad Palsule .name = TYPE_FSI_SCRATCHPAD,
105ca782334SNinad Palsule .parent = TYPE_FSI_LBUS_DEVICE,
106ca782334SNinad Palsule .instance_size = sizeof(FSIScratchPad),
107ca782334SNinad Palsule .class_init = fsi_scratchpad_class_init,
108ca782334SNinad Palsule };
109ca782334SNinad Palsule
fsi_lbus_register_types(void)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);
114ca782334SNinad Palsule type_register_static(&fsi_scratchpad_info);
11599f0c046SNinad Palsule }
11699f0c046SNinad Palsule
11799f0c046SNinad Palsule type_init(fsi_lbus_register_types);
118