xref: /openbmc/qemu/hw/fsi/aspeed_apb2opb.c (revision 764a6ee9)
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 
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 
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 
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 
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 
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 
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 
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 
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 
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     device_class_set_legacy_reset(dc, 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 
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 
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 
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