1 /*
2 * SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2024 IBM Corp.
4 *
5 * ASPEED APB-OPB FSI interface
6 * IBM On-chip Peripheral Bus
7 */
8
9 #include "qemu/osdep.h"
10 #include "qemu/log.h"
11 #include "qom/object.h"
12 #include "qapi/error.h"
13 #include "trace.h"
14
15 #include "hw/fsi/aspeed_apb2opb.h"
16 #include "hw/qdev-core.h"
17
18 #define TO_REG(x) (x >> 2)
19
20 #define APB2OPB_VERSION TO_REG(0x00)
21 #define APB2OPB_TRIGGER TO_REG(0x04)
22
23 #define APB2OPB_CONTROL TO_REG(0x08)
24 #define APB2OPB_CONTROL_OFF BE_GENMASK(31, 13)
25
26 #define APB2OPB_OPB2FSI TO_REG(0x0c)
27 #define APB2OPB_OPB2FSI_OFF BE_GENMASK(31, 22)
28
29 #define APB2OPB_OPB0_SEL TO_REG(0x10)
30 #define APB2OPB_OPB1_SEL TO_REG(0x28)
31 #define APB2OPB_OPB_SEL_EN BIT(0)
32
33 #define APB2OPB_OPB0_MODE TO_REG(0x14)
34 #define APB2OPB_OPB1_MODE TO_REG(0x2c)
35 #define APB2OPB_OPB_MODE_RD BIT(0)
36
37 #define APB2OPB_OPB0_XFER TO_REG(0x18)
38 #define APB2OPB_OPB1_XFER TO_REG(0x30)
39 #define APB2OPB_OPB_XFER_FULL BIT(1)
40 #define APB2OPB_OPB_XFER_HALF BIT(0)
41
42 #define APB2OPB_OPB0_ADDR TO_REG(0x1c)
43 #define APB2OPB_OPB0_WRITE_DATA TO_REG(0x20)
44
45 #define APB2OPB_OPB1_ADDR TO_REG(0x34)
46 #define APB2OPB_OPB1_WRITE_DATA TO_REG(0x38)
47
48 #define APB2OPB_IRQ_STS TO_REG(0x48)
49 #define APB2OPB_IRQ_STS_OPB1_TX_ACK BIT(17)
50 #define APB2OPB_IRQ_STS_OPB0_TX_ACK BIT(16)
51
52 #define APB2OPB_OPB0_WRITE_WORD_ENDIAN TO_REG(0x4c)
53 #define APB2OPB_OPB0_WRITE_WORD_ENDIAN_BE 0x0011101b
54 #define APB2OPB_OPB0_WRITE_BYTE_ENDIAN TO_REG(0x50)
55 #define APB2OPB_OPB0_WRITE_BYTE_ENDIAN_BE 0x0c330f3f
56 #define APB2OPB_OPB1_WRITE_WORD_ENDIAN TO_REG(0x54)
57 #define APB2OPB_OPB1_WRITE_BYTE_ENDIAN TO_REG(0x58)
58 #define APB2OPB_OPB0_READ_BYTE_ENDIAN TO_REG(0x5c)
59 #define APB2OPB_OPB1_READ_BYTE_ENDIAN TO_REG(0x60)
60 #define APB2OPB_OPB0_READ_WORD_ENDIAN_BE 0x00030b1b
61
62 #define APB2OPB_OPB0_READ_DATA TO_REG(0x84)
63 #define APB2OPB_OPB1_READ_DATA TO_REG(0x90)
64
65 /*
66 * The following magic values came from AST2600 data sheet
67 * The register values are defined under section "FSI controller"
68 * as initial values.
69 */
70 static const uint32_t aspeed_apb2opb_reset[ASPEED_APB2OPB_NR_REGS] = {
71 [APB2OPB_VERSION] = 0x000000a1,
72 [APB2OPB_OPB0_WRITE_WORD_ENDIAN] = 0x0044eee4,
73 [APB2OPB_OPB0_WRITE_BYTE_ENDIAN] = 0x0055aaff,
74 [APB2OPB_OPB1_WRITE_WORD_ENDIAN] = 0x00117717,
75 [APB2OPB_OPB1_WRITE_BYTE_ENDIAN] = 0xffaa5500,
76 [APB2OPB_OPB0_READ_BYTE_ENDIAN] = 0x0044eee4,
77 [APB2OPB_OPB1_READ_BYTE_ENDIAN] = 0x00117717
78 };
79
fsi_opb_fsi_master_address(FSIMasterState * fsi,hwaddr addr)80 static void fsi_opb_fsi_master_address(FSIMasterState *fsi, hwaddr addr)
81 {
82 memory_region_transaction_begin();
83 memory_region_set_address(&fsi->iomem, addr);
84 memory_region_transaction_commit();
85 }
86
fsi_opb_opb2fsi_address(FSIMasterState * fsi,hwaddr addr)87 static void fsi_opb_opb2fsi_address(FSIMasterState *fsi, hwaddr addr)
88 {
89 memory_region_transaction_begin();
90 memory_region_set_address(&fsi->opb2fsi, addr);
91 memory_region_transaction_commit();
92 }
93
fsi_aspeed_apb2opb_read(void * opaque,hwaddr addr,unsigned size)94 static uint64_t fsi_aspeed_apb2opb_read(void *opaque, hwaddr addr,
95 unsigned size)
96 {
97 AspeedAPB2OPBState *s = ASPEED_APB2OPB(opaque);
98 unsigned int reg = TO_REG(addr);
99
100 trace_fsi_aspeed_apb2opb_read(addr, size);
101
102 if (reg >= ASPEED_APB2OPB_NR_REGS) {
103 qemu_log_mask(LOG_GUEST_ERROR,
104 "%s: Out of bounds read: 0x%"HWADDR_PRIx" for %u\n",
105 __func__, addr, size);
106 return 0;
107 }
108
109 return s->regs[reg];
110 }
111
fsi_aspeed_apb2opb_rw(AddressSpace * as,hwaddr addr,MemTxAttrs attrs,uint32_t * data,uint32_t size,bool is_write)112 static MemTxResult fsi_aspeed_apb2opb_rw(AddressSpace *as, hwaddr addr,
113 MemTxAttrs attrs, uint32_t *data,
114 uint32_t size, bool is_write)
115 {
116 MemTxResult res;
117
118 if (is_write) {
119 switch (size) {
120 case 4:
121 address_space_stl_le(as, addr, *data, attrs, &res);
122 break;
123 case 2:
124 address_space_stw_le(as, addr, *data, attrs, &res);
125 break;
126 case 1:
127 address_space_stb(as, addr, *data, attrs, &res);
128 break;
129 default:
130 g_assert_not_reached();
131 }
132 } else {
133 switch (size) {
134 case 4:
135 *data = address_space_ldl_le(as, addr, attrs, &res);
136 break;
137 case 2:
138 *data = address_space_lduw_le(as, addr, attrs, &res);
139 break;
140 case 1:
141 *data = address_space_ldub(as, addr, attrs, &res);
142 break;
143 default:
144 g_assert_not_reached();
145 }
146 }
147 return res;
148 }
149
fsi_aspeed_apb2opb_write(void * opaque,hwaddr addr,uint64_t data,unsigned size)150 static void fsi_aspeed_apb2opb_write(void *opaque, hwaddr addr, uint64_t data,
151 unsigned size)
152 {
153 AspeedAPB2OPBState *s = ASPEED_APB2OPB(opaque);
154 unsigned int reg = TO_REG(addr);
155
156 trace_fsi_aspeed_apb2opb_write(addr, size, data);
157
158 if (reg >= ASPEED_APB2OPB_NR_REGS) {
159 qemu_log_mask(LOG_GUEST_ERROR,
160 "%s: Out of bounds write: %"HWADDR_PRIx" for %u\n",
161 __func__, addr, size);
162 return;
163 }
164
165 switch (reg) {
166 case APB2OPB_CONTROL:
167 fsi_opb_fsi_master_address(&s->fsi[0],
168 data & APB2OPB_CONTROL_OFF);
169 break;
170 case APB2OPB_OPB2FSI:
171 fsi_opb_opb2fsi_address(&s->fsi[0],
172 data & APB2OPB_OPB2FSI_OFF);
173 break;
174 case APB2OPB_OPB0_WRITE_WORD_ENDIAN:
175 if (data != APB2OPB_OPB0_WRITE_WORD_ENDIAN_BE) {
176 qemu_log_mask(LOG_GUEST_ERROR,
177 "%s: Bridge needs to be driven as BE (0x%x)\n",
178 __func__, APB2OPB_OPB0_WRITE_WORD_ENDIAN_BE);
179 }
180 break;
181 case APB2OPB_OPB0_WRITE_BYTE_ENDIAN:
182 if (data != APB2OPB_OPB0_WRITE_BYTE_ENDIAN_BE) {
183 qemu_log_mask(LOG_GUEST_ERROR,
184 "%s: Bridge needs to be driven as BE (0x%x)\n",
185 __func__, APB2OPB_OPB0_WRITE_BYTE_ENDIAN_BE);
186 }
187 break;
188 case APB2OPB_OPB0_READ_BYTE_ENDIAN:
189 if (data != APB2OPB_OPB0_READ_WORD_ENDIAN_BE) {
190 qemu_log_mask(LOG_GUEST_ERROR,
191 "%s: Bridge needs to be driven as BE (0x%x)\n",
192 __func__, APB2OPB_OPB0_READ_WORD_ENDIAN_BE);
193 }
194 break;
195 case APB2OPB_TRIGGER:
196 {
197 uint32_t opb, op_mode, op_size, op_addr, op_data;
198 MemTxResult result;
199 bool is_write;
200 int index;
201 AddressSpace *as;
202
203 assert((s->regs[APB2OPB_OPB0_SEL] & APB2OPB_OPB_SEL_EN) ^
204 (s->regs[APB2OPB_OPB1_SEL] & APB2OPB_OPB_SEL_EN));
205
206 if (s->regs[APB2OPB_OPB0_SEL] & APB2OPB_OPB_SEL_EN) {
207 opb = 0;
208 op_mode = s->regs[APB2OPB_OPB0_MODE];
209 op_size = s->regs[APB2OPB_OPB0_XFER];
210 op_addr = s->regs[APB2OPB_OPB0_ADDR];
211 op_data = s->regs[APB2OPB_OPB0_WRITE_DATA];
212 } else if (s->regs[APB2OPB_OPB1_SEL] & APB2OPB_OPB_SEL_EN) {
213 opb = 1;
214 op_mode = s->regs[APB2OPB_OPB1_MODE];
215 op_size = s->regs[APB2OPB_OPB1_XFER];
216 op_addr = s->regs[APB2OPB_OPB1_ADDR];
217 op_data = s->regs[APB2OPB_OPB1_WRITE_DATA];
218 } else {
219 qemu_log_mask(LOG_GUEST_ERROR,
220 "%s: Invalid operation: 0x%"HWADDR_PRIx" for %u\n",
221 __func__, addr, size);
222 return;
223 }
224
225 if (op_size & ~(APB2OPB_OPB_XFER_HALF | APB2OPB_OPB_XFER_FULL)) {
226 qemu_log_mask(LOG_GUEST_ERROR,
227 "OPB transaction failed: Unrecognized access width: %d\n",
228 op_size);
229 return;
230 }
231
232 op_size += 1;
233 is_write = !(op_mode & APB2OPB_OPB_MODE_RD);
234 index = opb ? APB2OPB_OPB1_READ_DATA : APB2OPB_OPB0_READ_DATA;
235 as = &s->opb[opb].as;
236
237 result = fsi_aspeed_apb2opb_rw(as, op_addr, MEMTXATTRS_UNSPECIFIED,
238 &op_data, op_size, is_write);
239 if (result != MEMTX_OK) {
240 qemu_log_mask(LOG_GUEST_ERROR, "%s: OPB %s failed @%08x\n",
241 __func__, is_write ? "write" : "read", op_addr);
242 return;
243 }
244
245 if (!is_write) {
246 s->regs[index] = op_data;
247 }
248
249 s->regs[APB2OPB_IRQ_STS] |= opb ? APB2OPB_IRQ_STS_OPB1_TX_ACK
250 : APB2OPB_IRQ_STS_OPB0_TX_ACK;
251 break;
252 }
253 }
254
255 s->regs[reg] = data;
256 }
257
258 static const struct MemoryRegionOps aspeed_apb2opb_ops = {
259 .read = fsi_aspeed_apb2opb_read,
260 .write = fsi_aspeed_apb2opb_write,
261 .valid.max_access_size = 4,
262 .valid.min_access_size = 4,
263 .impl.max_access_size = 4,
264 .impl.min_access_size = 4,
265 .endianness = DEVICE_LITTLE_ENDIAN,
266 };
267
fsi_aspeed_apb2opb_init(Object * o)268 static void fsi_aspeed_apb2opb_init(Object *o)
269 {
270 AspeedAPB2OPBState *s = ASPEED_APB2OPB(o);
271 int i;
272
273 for (i = 0; i < ASPEED_FSI_NUM; i++) {
274 object_initialize_child(o, "fsi-master[*]", &s->fsi[i],
275 TYPE_FSI_MASTER);
276 }
277 }
278
fsi_aspeed_apb2opb_realize(DeviceState * dev,Error ** errp)279 static void fsi_aspeed_apb2opb_realize(DeviceState *dev, Error **errp)
280 {
281 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
282 AspeedAPB2OPBState *s = ASPEED_APB2OPB(dev);
283 int i;
284
285 /*
286 * TODO: The OPBus model initializes the OPB address space in
287 * the .instance_init handler and this is problematic for test
288 * device-introspect-test. To avoid a memory corruption and a QEMU
289 * crash, qbus_init() should be called from realize(). Something to
290 * improve. Possibly, OPBus could also be removed.
291 */
292 for (i = 0; i < ASPEED_FSI_NUM; i++) {
293 qbus_init(&s->opb[i], sizeof(s->opb[i]), TYPE_OP_BUS, DEVICE(s),
294 NULL);
295 }
296
297 sysbus_init_irq(sbd, &s->irq);
298
299 memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_apb2opb_ops, s,
300 TYPE_ASPEED_APB2OPB, 0x1000);
301 sysbus_init_mmio(sbd, &s->iomem);
302
303 for (i = 0; i < ASPEED_FSI_NUM; i++) {
304 if (!qdev_realize(DEVICE(&s->fsi[i]), BUS(&s->opb[i]), errp)) {
305 return;
306 }
307
308 memory_region_add_subregion(&s->opb[i].mr, 0x80000000,
309 &s->fsi[i].iomem);
310
311 memory_region_add_subregion(&s->opb[i].mr, 0xa0000000,
312 &s->fsi[i].opb2fsi);
313 }
314 }
315
fsi_aspeed_apb2opb_reset(DeviceState * dev)316 static void fsi_aspeed_apb2opb_reset(DeviceState *dev)
317 {
318 AspeedAPB2OPBState *s = ASPEED_APB2OPB(dev);
319
320 memcpy(s->regs, aspeed_apb2opb_reset, ASPEED_APB2OPB_NR_REGS);
321 }
322
fsi_aspeed_apb2opb_class_init(ObjectClass * klass,void * data)323 static void fsi_aspeed_apb2opb_class_init(ObjectClass *klass, void *data)
324 {
325 DeviceClass *dc = DEVICE_CLASS(klass);
326
327 dc->desc = "ASPEED APB2OPB Bridge";
328 dc->realize = fsi_aspeed_apb2opb_realize;
329 dc->reset = fsi_aspeed_apb2opb_reset;
330 }
331
332 static const TypeInfo aspeed_apb2opb_info = {
333 .name = TYPE_ASPEED_APB2OPB,
334 .parent = TYPE_SYS_BUS_DEVICE,
335 .instance_init = fsi_aspeed_apb2opb_init,
336 .instance_size = sizeof(AspeedAPB2OPBState),
337 .class_init = fsi_aspeed_apb2opb_class_init,
338 };
339
aspeed_apb2opb_register_types(void)340 static void aspeed_apb2opb_register_types(void)
341 {
342 type_register_static(&aspeed_apb2opb_info);
343 }
344
345 type_init(aspeed_apb2opb_register_types);
346
fsi_opb_init(Object * o)347 static void fsi_opb_init(Object *o)
348 {
349 OPBus *opb = OP_BUS(o);
350
351 memory_region_init(&opb->mr, 0, TYPE_FSI_OPB, UINT32_MAX);
352 address_space_init(&opb->as, &opb->mr, TYPE_FSI_OPB);
353 }
354
355 static const TypeInfo opb_info = {
356 .name = TYPE_OP_BUS,
357 .parent = TYPE_BUS,
358 .instance_init = fsi_opb_init,
359 .instance_size = sizeof(OPBus),
360 };
361
fsi_opb_register_types(void)362 static void fsi_opb_register_types(void)
363 {
364 type_register_static(&opb_info);
365 }
366
367 type_init(fsi_opb_register_types);
368