1f4de3ca1SNinad Palsule /*
2f4de3ca1SNinad Palsule * SPDX-License-Identifier: GPL-2.0-or-later
3f4de3ca1SNinad Palsule * Copyright (C) 2024 IBM Corp.
4f4de3ca1SNinad Palsule *
5f4de3ca1SNinad Palsule * IBM Flexible Service Interface
6f4de3ca1SNinad Palsule */
7f4de3ca1SNinad Palsule #include "qemu/osdep.h"
86a2897bbSNinad Palsule #include "qapi/error.h"
96a2897bbSNinad Palsule #include "qemu/log.h"
106a2897bbSNinad Palsule #include "trace.h"
11f4de3ca1SNinad Palsule
12f4de3ca1SNinad Palsule #include "hw/fsi/fsi.h"
13f4de3ca1SNinad Palsule
146a2897bbSNinad Palsule #define TO_REG(x) ((x) >> 2)
156a2897bbSNinad Palsule
16f4de3ca1SNinad Palsule static const TypeInfo fsi_bus_info = {
17f4de3ca1SNinad Palsule .name = TYPE_FSI_BUS,
18f4de3ca1SNinad Palsule .parent = TYPE_BUS,
19f4de3ca1SNinad Palsule .instance_size = sizeof(FSIBus),
20f4de3ca1SNinad Palsule };
21f4de3ca1SNinad Palsule
fsi_slave_read(void * opaque,hwaddr addr,unsigned size)226a2897bbSNinad Palsule static uint64_t fsi_slave_read(void *opaque, hwaddr addr, unsigned size)
23f4de3ca1SNinad Palsule {
246a2897bbSNinad Palsule FSISlaveState *s = FSI_SLAVE(opaque);
256a2897bbSNinad Palsule int reg = TO_REG(addr);
266a2897bbSNinad Palsule
276a2897bbSNinad Palsule trace_fsi_slave_read(addr, size);
286a2897bbSNinad Palsule
296a2897bbSNinad Palsule if (reg >= FSI_SLAVE_CONTROL_NR_REGS) {
306a2897bbSNinad Palsule qemu_log_mask(LOG_GUEST_ERROR,
316a2897bbSNinad Palsule "%s: Out of bounds read: 0x%"HWADDR_PRIx" for %u\n",
326a2897bbSNinad Palsule __func__, addr, size);
336a2897bbSNinad Palsule return 0;
34f4de3ca1SNinad Palsule }
35f4de3ca1SNinad Palsule
366a2897bbSNinad Palsule return s->regs[reg];
376a2897bbSNinad Palsule }
386a2897bbSNinad Palsule
fsi_slave_write(void * opaque,hwaddr addr,uint64_t data,unsigned size)396a2897bbSNinad Palsule static void fsi_slave_write(void *opaque, hwaddr addr, uint64_t data,
406a2897bbSNinad Palsule unsigned size)
416a2897bbSNinad Palsule {
426a2897bbSNinad Palsule FSISlaveState *s = FSI_SLAVE(opaque);
436a2897bbSNinad Palsule int reg = TO_REG(addr);
446a2897bbSNinad Palsule
456a2897bbSNinad Palsule trace_fsi_slave_write(addr, size, data);
466a2897bbSNinad Palsule
476a2897bbSNinad Palsule if (reg >= FSI_SLAVE_CONTROL_NR_REGS) {
486a2897bbSNinad Palsule qemu_log_mask(LOG_GUEST_ERROR,
496a2897bbSNinad Palsule "%s: Out of bounds write: 0x%"HWADDR_PRIx" for %u\n",
506a2897bbSNinad Palsule __func__, addr, size);
516a2897bbSNinad Palsule return;
526a2897bbSNinad Palsule }
536a2897bbSNinad Palsule
546a2897bbSNinad Palsule s->regs[reg] = data;
556a2897bbSNinad Palsule }
566a2897bbSNinad Palsule
576a2897bbSNinad Palsule static const struct MemoryRegionOps fsi_slave_ops = {
586a2897bbSNinad Palsule .read = fsi_slave_read,
596a2897bbSNinad Palsule .write = fsi_slave_write,
606a2897bbSNinad Palsule .endianness = DEVICE_BIG_ENDIAN,
616a2897bbSNinad Palsule };
626a2897bbSNinad Palsule
fsi_slave_reset(DeviceState * dev)636a2897bbSNinad Palsule static void fsi_slave_reset(DeviceState *dev)
646a2897bbSNinad Palsule {
656a2897bbSNinad Palsule FSISlaveState *s = FSI_SLAVE(dev);
666a2897bbSNinad Palsule
676a2897bbSNinad Palsule /* Initialize registers */
686a2897bbSNinad Palsule memset(s->regs, 0, sizeof(s->regs));
696a2897bbSNinad Palsule }
706a2897bbSNinad Palsule
fsi_slave_init(Object * o)716a2897bbSNinad Palsule static void fsi_slave_init(Object *o)
726a2897bbSNinad Palsule {
736a2897bbSNinad Palsule FSISlaveState *s = FSI_SLAVE(o);
746a2897bbSNinad Palsule
756a2897bbSNinad Palsule memory_region_init_io(&s->iomem, OBJECT(s), &fsi_slave_ops,
766a2897bbSNinad Palsule s, TYPE_FSI_SLAVE, 0x400);
776a2897bbSNinad Palsule }
786a2897bbSNinad Palsule
fsi_slave_class_init(ObjectClass * klass,void * data)796a2897bbSNinad Palsule static void fsi_slave_class_init(ObjectClass *klass, void *data)
806a2897bbSNinad Palsule {
816a2897bbSNinad Palsule DeviceClass *dc = DEVICE_CLASS(klass);
826a2897bbSNinad Palsule
836a2897bbSNinad Palsule dc->bus_type = TYPE_FSI_BUS;
846a2897bbSNinad Palsule dc->desc = "FSI Slave";
85*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, fsi_slave_reset);
866a2897bbSNinad Palsule }
876a2897bbSNinad Palsule
886a2897bbSNinad Palsule static const TypeInfo fsi_slave_info = {
896a2897bbSNinad Palsule .name = TYPE_FSI_SLAVE,
906a2897bbSNinad Palsule .parent = TYPE_DEVICE,
916a2897bbSNinad Palsule .instance_init = fsi_slave_init,
926a2897bbSNinad Palsule .instance_size = sizeof(FSISlaveState),
936a2897bbSNinad Palsule .class_init = fsi_slave_class_init,
946a2897bbSNinad Palsule };
956a2897bbSNinad Palsule
fsi_register_types(void)966a2897bbSNinad Palsule static void fsi_register_types(void)
976a2897bbSNinad Palsule {
986a2897bbSNinad Palsule type_register_static(&fsi_bus_info);
996a2897bbSNinad Palsule type_register_static(&fsi_slave_info);
1006a2897bbSNinad Palsule }
1016a2897bbSNinad Palsule
1026a2897bbSNinad Palsule type_init(fsi_register_types);
103