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