2 * SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2024 IBM Corp.
5 * IBM Flexible Service Interface master
8 #include "qemu/osdep.h"
9 #include "qapi/error.h"
13 #include "hw/fsi/fsi-master.h"
15 #define TYPE_OP_BUS "opb"
17 #define TO_REG(x) ((x) >> 2)
19 #define FSI_MENP0 TO_REG(0x010)
20 #define FSI_MENP32 TO_REG(0x014)
21 #define FSI_MSENP0 TO_REG(0x018)
22 #define FSI_MLEVP0 TO_REG(0x018)
23 #define FSI_MSENP32 TO_REG(0x01c)
24 #define FSI_MLEVP32 TO_REG(0x01c)
25 #define FSI_MCENP0 TO_REG(0x020)
26 #define FSI_MREFP0 TO_REG(0x020)
27 #define FSI_MCENP32 TO_REG(0x024)
28 #define FSI_MREFP32 TO_REG(0x024)
30 #define FSI_MVER TO_REG(0x074)
31 #define FSI_MRESP0 TO_REG(0x0d0)
33 #define FSI_MRESB0 TO_REG(0x1d0)
34 #define FSI_MRESB0_RESET_GENERAL BIT(31)
35 #define FSI_MRESB0_RESET_ERROR BIT(30)
37 static uint64_t fsi_master_read(void *opaque
, hwaddr addr
, unsigned size
)
39 FSIMasterState
*s
= FSI_MASTER(opaque
);
40 int reg
= TO_REG(addr
);
42 trace_fsi_master_read(addr
, size
);
44 if (reg
>= FSI_MASTER_NR_REGS
) {
45 qemu_log_mask(LOG_GUEST_ERROR
,
46 "%s: Out of bounds read: 0x%"HWADDR_PRIx
" for %u\n",
47 __func__
, addr
, size
);
54 static void fsi_master_write(void *opaque
, hwaddr addr
, uint64_t data
,
57 FSIMasterState
*s
= FSI_MASTER(opaque
);
58 int reg
= TO_REG(addr
);
60 trace_fsi_master_write(addr
, size
, data
);
62 if (reg
>= FSI_MASTER_NR_REGS
) {
63 qemu_log_mask(LOG_GUEST_ERROR
,
64 "%s: Out of bounds write: %"HWADDR_PRIx
" for %u\n",
65 __func__
, addr
, size
);
71 s
->regs
[FSI_MENP0
] = data
;
74 s
->regs
[FSI_MENP32
] = data
;
77 s
->regs
[FSI_MENP0
] |= data
;
80 s
->regs
[FSI_MENP32
] |= data
;
83 s
->regs
[FSI_MENP0
] &= ~data
;
86 s
->regs
[FSI_MENP32
] &= ~data
;
89 /* Perform necessary resets leave register 0 to indicate no errors */
92 if (data
& FSI_MRESB0_RESET_GENERAL
) {
93 device_cold_reset(DEVICE(opaque
));
95 if (data
& FSI_MRESB0_RESET_ERROR
) {
96 /* FIXME: this seems dubious */
97 device_cold_reset(DEVICE(opaque
));
105 static const struct MemoryRegionOps fsi_master_ops
= {
106 .read
= fsi_master_read
,
107 .write
= fsi_master_write
,
108 .endianness
= DEVICE_BIG_ENDIAN
,
111 static void fsi_master_init(Object
*o
)
113 FSIMasterState
*s
= FSI_MASTER(o
);
115 object_initialize_child(o
, "cfam", &s
->cfam
, TYPE_FSI_CFAM
);
117 qbus_init(&s
->bus
, sizeof(s
->bus
), TYPE_FSI_BUS
, DEVICE(s
), NULL
);
119 memory_region_init_io(&s
->iomem
, OBJECT(s
), &fsi_master_ops
, s
,
120 TYPE_FSI_MASTER
, 0x10000000);
121 memory_region_init(&s
->opb2fsi
, OBJECT(s
), "fsi.opb2fsi", 0x10000000);
124 static void fsi_master_realize(DeviceState
*dev
, Error
**errp
)
126 FSIMasterState
*s
= FSI_MASTER(dev
);
128 if (!qdev_realize(DEVICE(&s
->cfam
), BUS(&s
->bus
), errp
)) {
133 memory_region_add_subregion(&s
->opb2fsi
, 0, &s
->cfam
.mr
);
136 static void fsi_master_reset(DeviceState
*dev
)
138 FSIMasterState
*s
= FSI_MASTER(dev
);
140 /* Initialize registers */
141 memset(s
->regs
, 0, sizeof(s
->regs
));
144 s
->regs
[FSI_MVER
] = 0xe0050101;
147 static void fsi_master_class_init(ObjectClass
*klass
, void *data
)
149 DeviceClass
*dc
= DEVICE_CLASS(klass
);
151 dc
->bus_type
= TYPE_OP_BUS
;
152 dc
->desc
= "FSI Master";
153 dc
->realize
= fsi_master_realize
;
154 device_class_set_legacy_reset(dc
, fsi_master_reset
);
157 static const TypeInfo fsi_master_info
= {
158 .name
= TYPE_FSI_MASTER
,
159 .parent
= TYPE_DEVICE
,
160 .instance_init
= fsi_master_init
,
161 .instance_size
= sizeof(FSIMasterState
),
162 .class_init
= fsi_master_class_init
,
165 static void fsi_register_types(void)
167 type_register_static(&fsi_master_info
);
170 type_init(fsi_register_types
);