1 /*
2 * ASPEED I3C Controller
3 *
4 * Copyright (C) 2021 ASPEED Technology Inc.
5 * Copyright (C) 2025 Google, LLC.
6 *
7 * This code is licensed under the GPL version 2 or later. See
8 * the COPYING file in the top-level directory.
9 */
10
11 #include "qemu/osdep.h"
12 #include "qemu/log.h"
13 #include "qemu/error-report.h"
14 #include "hw/i3c/aspeed_i3c.h"
15 #include "hw/registerfields.h"
16 #include "hw/qdev-properties.h"
17 #include "qapi/error.h"
18 #include "migration/vmstate.h"
19 #include "trace.h"
20
21 /* I3C Controller Registers */
22 REG32(I3C1_REG0, 0x10)
23 REG32(I3C1_REG1, 0x14)
24 FIELD(I3C1_REG1, I2C_MODE, 0, 1)
25 FIELD(I3C1_REG1, SLV_TEST_MODE, 1, 1)
26 FIELD(I3C1_REG1, ACT_MODE, 2, 2)
27 FIELD(I3C1_REG1, PENDING_INT, 4, 4)
28 FIELD(I3C1_REG1, SA, 8, 7)
29 FIELD(I3C1_REG1, SA_EN, 15, 1)
30 FIELD(I3C1_REG1, INST_ID, 16, 4)
31 REG32(I3C2_REG0, 0x20)
32 REG32(I3C2_REG1, 0x24)
33 FIELD(I3C2_REG1, I2C_MODE, 0, 1)
34 FIELD(I3C2_REG1, SLV_TEST_MODE, 1, 1)
35 FIELD(I3C2_REG1, ACT_MODE, 2, 2)
36 FIELD(I3C2_REG1, PENDING_INT, 4, 4)
37 FIELD(I3C2_REG1, SA, 8, 7)
38 FIELD(I3C2_REG1, SA_EN, 15, 1)
39 FIELD(I3C2_REG1, INST_ID, 16, 4)
40 REG32(I3C3_REG0, 0x30)
41 REG32(I3C3_REG1, 0x34)
42 FIELD(I3C3_REG1, I2C_MODE, 0, 1)
43 FIELD(I3C3_REG1, SLV_TEST_MODE, 1, 1)
44 FIELD(I3C3_REG1, ACT_MODE, 2, 2)
45 FIELD(I3C3_REG1, PENDING_INT, 4, 4)
46 FIELD(I3C3_REG1, SA, 8, 7)
47 FIELD(I3C3_REG1, SA_EN, 15, 1)
48 FIELD(I3C3_REG1, INST_ID, 16, 4)
49 REG32(I3C4_REG0, 0x40)
50 REG32(I3C4_REG1, 0x44)
51 FIELD(I3C4_REG1, I2C_MODE, 0, 1)
52 FIELD(I3C4_REG1, SLV_TEST_MODE, 1, 1)
53 FIELD(I3C4_REG1, ACT_MODE, 2, 2)
54 FIELD(I3C4_REG1, PENDING_INT, 4, 4)
55 FIELD(I3C4_REG1, SA, 8, 7)
56 FIELD(I3C4_REG1, SA_EN, 15, 1)
57 FIELD(I3C4_REG1, INST_ID, 16, 4)
58 REG32(I3C5_REG0, 0x50)
59 REG32(I3C5_REG1, 0x54)
60 FIELD(I3C5_REG1, I2C_MODE, 0, 1)
61 FIELD(I3C5_REG1, SLV_TEST_MODE, 1, 1)
62 FIELD(I3C5_REG1, ACT_MODE, 2, 2)
63 FIELD(I3C5_REG1, PENDING_INT, 4, 4)
64 FIELD(I3C5_REG1, SA, 8, 7)
65 FIELD(I3C5_REG1, SA_EN, 15, 1)
66 FIELD(I3C5_REG1, INST_ID, 16, 4)
67 REG32(I3C6_REG0, 0x60)
68 REG32(I3C6_REG1, 0x64)
69 FIELD(I3C6_REG1, I2C_MODE, 0, 1)
70 FIELD(I3C6_REG1, SLV_TEST_MODE, 1, 1)
71 FIELD(I3C6_REG1, ACT_MODE, 2, 2)
72 FIELD(I3C6_REG1, PENDING_INT, 4, 4)
73 FIELD(I3C6_REG1, SA, 8, 7)
74 FIELD(I3C6_REG1, SA_EN, 15, 1)
75 FIELD(I3C6_REG1, INST_ID, 16, 4)
76
77 static const uint32_t ast2600_i3c_controller_ro[ASPEED_I3C_NR_REGS] = {
78 [R_I3C1_REG0] = 0xfc000000,
79 [R_I3C1_REG1] = 0xfff00000,
80 [R_I3C2_REG0] = 0xfc000000,
81 [R_I3C2_REG1] = 0xfff00000,
82 [R_I3C3_REG0] = 0xfc000000,
83 [R_I3C3_REG1] = 0xfff00000,
84 [R_I3C4_REG0] = 0xfc000000,
85 [R_I3C4_REG1] = 0xfff00000,
86 [R_I3C5_REG0] = 0xfc000000,
87 [R_I3C5_REG1] = 0xfff00000,
88 [R_I3C6_REG0] = 0xfc000000,
89 [R_I3C6_REG1] = 0xfff00000,
90 };
91
aspeed_i3c_read(void * opaque,hwaddr addr,unsigned int size)92 static uint64_t aspeed_i3c_read(void *opaque, hwaddr addr, unsigned int size)
93 {
94 AspeedI3CState *s = ASPEED_I3C(opaque);
95 uint64_t val = 0;
96
97 val = s->regs[addr >> 2];
98
99 trace_aspeed_i3c_read(addr, val);
100
101 return val;
102 }
103
aspeed_i3c_write(void * opaque,hwaddr addr,uint64_t data,unsigned int size)104 static void aspeed_i3c_write(void *opaque,
105 hwaddr addr,
106 uint64_t data,
107 unsigned int size)
108 {
109 AspeedI3CState *s = ASPEED_I3C(opaque);
110
111 trace_aspeed_i3c_write(addr, data);
112
113 addr >>= 2;
114
115 data &= ~ast2600_i3c_controller_ro[addr];
116 /* I3C controller register */
117 switch (addr) {
118 case R_I3C1_REG1:
119 case R_I3C2_REG1:
120 case R_I3C3_REG1:
121 case R_I3C4_REG1:
122 case R_I3C5_REG1:
123 case R_I3C6_REG1:
124 if (data & R_I3C1_REG1_I2C_MODE_MASK) {
125 qemu_log_mask(LOG_UNIMP,
126 "%s: Unsupported I2C mode [0x%08" HWADDR_PRIx
127 "]=%08" PRIx64 "\n",
128 __func__, addr << 2, data);
129 break;
130 }
131 if (data & R_I3C1_REG1_SA_EN_MASK) {
132 qemu_log_mask(LOG_UNIMP,
133 "%s: Unsupported slave mode [%08" HWADDR_PRIx
134 "]=0x%08" PRIx64 "\n",
135 __func__, addr << 2, data);
136 break;
137 }
138 s->regs[addr] = data;
139 break;
140 default:
141 s->regs[addr] = data;
142 break;
143 }
144 }
145
146 static const MemoryRegionOps aspeed_i3c_ops = {
147 .read = aspeed_i3c_read,
148 .write = aspeed_i3c_write,
149 .endianness = DEVICE_LITTLE_ENDIAN,
150 .valid = {
151 .min_access_size = 1,
152 .max_access_size = 4,
153 }
154 };
155
aspeed_i3c_get_bus(AspeedI3CState * s,uint8_t bus_num)156 I3CBus *aspeed_i3c_get_bus(AspeedI3CState *s, uint8_t bus_num)
157 {
158 if (bus_num < ARRAY_SIZE(s->devices)) {
159 return s->devices[bus_num].bus;
160 }
161 /* Developer error, fail fast. */
162 g_assert_not_reached();
163 }
164
aspeed_i3c_reset(DeviceState * dev)165 static void aspeed_i3c_reset(DeviceState *dev)
166 {
167 AspeedI3CState *s = ASPEED_I3C(dev);
168 memset(s->regs, 0, sizeof(s->regs));
169 }
170
aspeed_i3c_instance_init(Object * obj)171 static void aspeed_i3c_instance_init(Object *obj)
172 {
173 AspeedI3CState *s = ASPEED_I3C(obj);
174 int i;
175
176 for (i = 0; i < ASPEED_I3C_NR_DEVICES; ++i) {
177 object_initialize_child(obj, "device[*]", &s->devices[i],
178 TYPE_DW_I3C);
179 }
180 }
181
aspeed_i3c_realize(DeviceState * dev,Error ** errp)182 static void aspeed_i3c_realize(DeviceState *dev, Error **errp)
183 {
184 int i;
185 AspeedI3CState *s = ASPEED_I3C(dev);
186 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
187
188 memory_region_init(&s->iomem_container, OBJECT(s),
189 TYPE_ASPEED_I3C ".container", 0x8000);
190
191 sysbus_init_mmio(sbd, &s->iomem_container);
192
193 memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_i3c_ops, s,
194 TYPE_ASPEED_I3C ".regs", ASPEED_I3C_NR_REGS << 2);
195
196 memory_region_add_subregion(&s->iomem_container, 0x0, &s->iomem);
197
198 for (i = 0; i < ASPEED_I3C_NR_DEVICES; ++i) {
199 Object *i3c_dev = OBJECT(&s->devices[i]);
200
201 if (!object_property_set_uint(i3c_dev, "device-id", i, errp)) {
202 return;
203 }
204
205 if (!sysbus_realize(SYS_BUS_DEVICE(i3c_dev), errp)) {
206 return;
207 }
208
209 /*
210 * Register Address of I3CX Device =
211 * (Base Address of Global Register) + (Offset of I3CX) + Offset
212 * X = 0, 1, 2, 3, 4, 5
213 * Offset of I3C0 = 0x2000
214 * Offset of I3C1 = 0x3000
215 * Offset of I3C2 = 0x4000
216 * Offset of I3C3 = 0x5000
217 * Offset of I3C4 = 0x6000
218 * Offset of I3C5 = 0x7000
219 */
220 memory_region_add_subregion(&s->iomem_container,
221 0x2000 + i * 0x1000, &s->devices[i].mr);
222 }
223
224 }
225
226 static const VMStateDescription vmstate_aspeed_i3c = {
227 .name = TYPE_ASPEED_I3C,
228 .version_id = 1,
229 .minimum_version_id = 1,
230 .fields = (const VMStateField[]) {
231 VMSTATE_UINT32_ARRAY(regs, AspeedI3CState, ASPEED_I3C_NR_REGS),
232 VMSTATE_STRUCT_ARRAY(devices, AspeedI3CState, ASPEED_I3C_NR_DEVICES, 1,
233 vmstate_dw_i3c, DWI3C),
234 VMSTATE_END_OF_LIST(),
235 }
236 };
237
aspeed_i3c_class_init(ObjectClass * klass,const void * data)238 static void aspeed_i3c_class_init(ObjectClass *klass, const void *data)
239 {
240 DeviceClass *dc = DEVICE_CLASS(klass);
241
242 dc->realize = aspeed_i3c_realize;
243 device_class_set_legacy_reset(dc, aspeed_i3c_reset);
244 dc->desc = "Aspeed I3C Controller";
245 dc->vmsd = &vmstate_aspeed_i3c;
246 }
247
248 static const TypeInfo aspeed_i3c_info = {
249 .name = TYPE_ASPEED_I3C,
250 .parent = TYPE_SYS_BUS_DEVICE,
251 .instance_init = aspeed_i3c_instance_init,
252 .instance_size = sizeof(AspeedI3CState),
253 .class_init = aspeed_i3c_class_init,
254 };
255
aspeed_i3c_register_types(void)256 static void aspeed_i3c_register_types(void)
257 {
258 type_register_static(&aspeed_i3c_info);
259 }
260
261 type_init(aspeed_i3c_register_types);
262