xref: /openbmc/qemu/hw/i3c/aspeed_i3c.c (revision e5b7dca64beab620a7810da6578600d73da1fb15)
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 uint64_t aspeed_i3c_read(void *opaque, hwaddr addr, unsigned int size)
78 {
79     AspeedI3CState *s = ASPEED_I3C(opaque);
80     uint64_t val = 0;
81 
82     val = s->regs[addr >> 2];
83 
84     trace_aspeed_i3c_read(addr, val);
85 
86     return val;
87 }
88 
89 static void aspeed_i3c_write(void *opaque,
90                              hwaddr addr,
91                              uint64_t data,
92                              unsigned int size)
93 {
94     AspeedI3CState *s = ASPEED_I3C(opaque);
95 
96     trace_aspeed_i3c_write(addr, data);
97 
98     addr >>= 2;
99 
100     /* I3C controller register */
101     switch (addr) {
102     case R_I3C1_REG1:
103     case R_I3C2_REG1:
104     case R_I3C3_REG1:
105     case R_I3C4_REG1:
106     case R_I3C5_REG1:
107     case R_I3C6_REG1:
108         if (data & R_I3C1_REG1_I2C_MODE_MASK) {
109             qemu_log_mask(LOG_UNIMP,
110                           "%s: Unsupported I2C mode [0x%08" HWADDR_PRIx
111                           "]=%08" PRIx64 "\n",
112                           __func__, addr << 2, data);
113             break;
114         }
115         if (data & R_I3C1_REG1_SA_EN_MASK) {
116             qemu_log_mask(LOG_UNIMP,
117                           "%s: Unsupported slave mode [%08" HWADDR_PRIx
118                           "]=0x%08" PRIx64 "\n",
119                           __func__, addr << 2, data);
120             break;
121         }
122         s->regs[addr] = data;
123         break;
124     default:
125         s->regs[addr] = data;
126         break;
127     }
128 }
129 
130 static const MemoryRegionOps aspeed_i3c_ops = {
131     .read = aspeed_i3c_read,
132     .write = aspeed_i3c_write,
133     .endianness = DEVICE_LITTLE_ENDIAN,
134     .valid = {
135         .min_access_size = 1,
136         .max_access_size = 4,
137     }
138 };
139 
140 static void aspeed_i3c_reset(DeviceState *dev)
141 {
142     AspeedI3CState *s = ASPEED_I3C(dev);
143     memset(s->regs, 0, sizeof(s->regs));
144 }
145 
146 static void aspeed_i3c_instance_init(Object *obj)
147 {
148     AspeedI3CState *s = ASPEED_I3C(obj);
149     int i;
150 
151     for (i = 0; i < ASPEED_I3C_NR_DEVICES; ++i) {
152         object_initialize_child(obj, "device[*]", &s->devices[i],
153                 TYPE_DW_I3C);
154     }
155 }
156 
157 static void aspeed_i3c_realize(DeviceState *dev, Error **errp)
158 {
159     int i;
160     AspeedI3CState *s = ASPEED_I3C(dev);
161     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
162 
163     memory_region_init(&s->iomem_container, OBJECT(s),
164             TYPE_ASPEED_I3C ".container", 0x8000);
165 
166     sysbus_init_mmio(sbd, &s->iomem_container);
167 
168     memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_i3c_ops, s,
169             TYPE_ASPEED_I3C ".regs", ASPEED_I3C_NR_REGS << 2);
170 
171     memory_region_add_subregion(&s->iomem_container, 0x0, &s->iomem);
172 
173     for (i = 0; i < ASPEED_I3C_NR_DEVICES; ++i) {
174         Object *i3c_dev = OBJECT(&s->devices[i]);
175 
176         if (!object_property_set_uint(i3c_dev, "device-id", i, errp)) {
177             return;
178         }
179 
180         if (!sysbus_realize(SYS_BUS_DEVICE(i3c_dev), errp)) {
181             return;
182         }
183 
184         /*
185          * Register Address of I3CX Device =
186          *     (Base Address of Global Register) + (Offset of I3CX) + Offset
187          * X = 0, 1, 2, 3, 4, 5
188          * Offset of I3C0 = 0x2000
189          * Offset of I3C1 = 0x3000
190          * Offset of I3C2 = 0x4000
191          * Offset of I3C3 = 0x5000
192          * Offset of I3C4 = 0x6000
193          * Offset of I3C5 = 0x7000
194          */
195         memory_region_add_subregion(&s->iomem_container,
196                 0x2000 + i * 0x1000, &s->devices[i].mr);
197     }
198 
199 }
200 
201 static const VMStateDescription vmstate_aspeed_i3c = {
202     .name = TYPE_ASPEED_I3C,
203     .version_id = 1,
204     .minimum_version_id = 1,
205     .fields = (const VMStateField[]) {
206         VMSTATE_UINT32_ARRAY(regs, AspeedI3CState, ASPEED_I3C_NR_REGS),
207         VMSTATE_STRUCT_ARRAY(devices, AspeedI3CState, ASPEED_I3C_NR_DEVICES, 1,
208                              vmstate_dw_i3c, DWI3C),
209         VMSTATE_END_OF_LIST(),
210     }
211 };
212 
213 static void aspeed_i3c_class_init(ObjectClass *klass, const void *data)
214 {
215     DeviceClass *dc = DEVICE_CLASS(klass);
216 
217     dc->realize = aspeed_i3c_realize;
218     device_class_set_legacy_reset(dc, aspeed_i3c_reset);
219     dc->desc = "Aspeed I3C Controller";
220     dc->vmsd = &vmstate_aspeed_i3c;
221 }
222 
223 static const TypeInfo aspeed_i3c_info = {
224     .name = TYPE_ASPEED_I3C,
225     .parent = TYPE_SYS_BUS_DEVICE,
226     .instance_init = aspeed_i3c_instance_init,
227     .instance_size = sizeof(AspeedI3CState),
228     .class_init = aspeed_i3c_class_init,
229 };
230 
231 static void aspeed_i3c_register_types(void)
232 {
233     type_register_static(&aspeed_i3c_info);
234 }
235 
236 type_init(aspeed_i3c_register_types);
237