xref: /openbmc/qemu/hw/i3c/core.c (revision c2339f050b8230402628bf0a66f7c6b408653f86)
1*c2339f05SJoe Komlodi /*
2*c2339f05SJoe Komlodi  * QEMU I3C bus interface.
3*c2339f05SJoe Komlodi  *
4*c2339f05SJoe Komlodi  * Copyright 2023 Google LLC
5*c2339f05SJoe Komlodi  *
6*c2339f05SJoe Komlodi  * This program is free software; you can redistribute it and/or modify it
7*c2339f05SJoe Komlodi  * under the terms of the GNU General Public License as published by the
8*c2339f05SJoe Komlodi  * Free Software Foundation; either version 2 of the License, or
9*c2339f05SJoe Komlodi  * (at your option) any later version.
10*c2339f05SJoe Komlodi  *
11*c2339f05SJoe Komlodi  * This program is distributed in the hope that it will be useful, but WITHOUT
12*c2339f05SJoe Komlodi  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13*c2339f05SJoe Komlodi  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14*c2339f05SJoe Komlodi  * for more details.
15*c2339f05SJoe Komlodi  */
16*c2339f05SJoe Komlodi 
17*c2339f05SJoe Komlodi #include "qemu/osdep.h"
18*c2339f05SJoe Komlodi #include "qemu/log.h"
19*c2339f05SJoe Komlodi #include "qapi/error.h"
20*c2339f05SJoe Komlodi #include "trace.h"
21*c2339f05SJoe Komlodi #include "hw/i3c/i3c.h"
22*c2339f05SJoe Komlodi #include "hw/qdev-properties.h"
23*c2339f05SJoe Komlodi 
24*c2339f05SJoe Komlodi static Property i3c_props[] = {
25*c2339f05SJoe Komlodi     DEFINE_PROP_UINT8("static-address", struct I3CTarget, static_address, 0),
26*c2339f05SJoe Komlodi     DEFINE_PROP_UINT8("dcr", struct I3CTarget, dcr, 0),
27*c2339f05SJoe Komlodi     DEFINE_PROP_UINT8("bcr", struct I3CTarget, bcr, 0),
28*c2339f05SJoe Komlodi     DEFINE_PROP_UINT64("pid", struct I3CTarget, pid, 0),
29*c2339f05SJoe Komlodi     DEFINE_PROP_END_OF_LIST(),
30*c2339f05SJoe Komlodi };
31*c2339f05SJoe Komlodi 
32*c2339f05SJoe Komlodi static const TypeInfo i3c_bus_info = {
33*c2339f05SJoe Komlodi     .name = TYPE_I3C_BUS,
34*c2339f05SJoe Komlodi     .parent = TYPE_BUS,
35*c2339f05SJoe Komlodi     .instance_size = sizeof(I3CBus),
36*c2339f05SJoe Komlodi     .class_size = sizeof(I3CBusClass),
37*c2339f05SJoe Komlodi };
38*c2339f05SJoe Komlodi 
39*c2339f05SJoe Komlodi I3CBus *i3c_init_bus(DeviceState *parent, const char *name)
40*c2339f05SJoe Komlodi {
41*c2339f05SJoe Komlodi     return i3c_init_bus_type(TYPE_I3C_BUS, parent, name);
42*c2339f05SJoe Komlodi }
43*c2339f05SJoe Komlodi 
44*c2339f05SJoe Komlodi I3CBus *i3c_init_bus_type(const char *type, DeviceState *parent,
45*c2339f05SJoe Komlodi                           const char *name)
46*c2339f05SJoe Komlodi {
47*c2339f05SJoe Komlodi     I3CBus *bus;
48*c2339f05SJoe Komlodi 
49*c2339f05SJoe Komlodi     bus = I3C_BUS(qbus_new(type, parent, name));
50*c2339f05SJoe Komlodi     QLIST_INIT(&bus->current_devs);
51*c2339f05SJoe Komlodi     bus->broadcast = false;
52*c2339f05SJoe Komlodi     bus->in_entdaa = false;
53*c2339f05SJoe Komlodi     bus->in_ccc = false;
54*c2339f05SJoe Komlodi 
55*c2339f05SJoe Komlodi     /* I2C init. */
56*c2339f05SJoe Komlodi     g_autofree gchar *i2c_bus_name = g_strdup_printf("%s-legacy-i2c", name);
57*c2339f05SJoe Komlodi     bus->i2c_bus = i2c_init_bus(parent, i2c_bus_name);
58*c2339f05SJoe Komlodi 
59*c2339f05SJoe Komlodi     return bus;
60*c2339f05SJoe Komlodi }
61*c2339f05SJoe Komlodi 
62*c2339f05SJoe Komlodi bool i3c_bus_busy(I3CBus *bus)
63*c2339f05SJoe Komlodi {
64*c2339f05SJoe Komlodi     return !QLIST_EMPTY(&bus->current_devs);
65*c2339f05SJoe Komlodi }
66*c2339f05SJoe Komlodi 
67*c2339f05SJoe Komlodi bool i3c_target_match(I3CBus *bus, I3CTarget *target, uint8_t address)
68*c2339f05SJoe Komlodi {
69*c2339f05SJoe Komlodi     /* Once a target has a dynamic address, it only responds to that. */
70*c2339f05SJoe Komlodi     uint8_t targ_addr = target->address ? target->address :
71*c2339f05SJoe Komlodi                                           target->static_address;
72*c2339f05SJoe Komlodi 
73*c2339f05SJoe Komlodi     if (bus->in_entdaa) {
74*c2339f05SJoe Komlodi         if (address != I3C_BROADCAST) {
75*c2339f05SJoe Komlodi             qemu_log_mask(LOG_GUEST_ERROR, "%s: I3C Address 0x%.2x sent during "
76*c2339f05SJoe Komlodi                           "ENTDAA instead of a broadcast address\n",
77*c2339f05SJoe Komlodi                           object_get_canonical_path(OBJECT(bus)), address);
78*c2339f05SJoe Komlodi                 return false;
79*c2339f05SJoe Komlodi         }
80*c2339f05SJoe Komlodi 
81*c2339f05SJoe Komlodi         /*
82*c2339f05SJoe Komlodi          * Targets should only ACK ENTDAA broadcasts if they have no dynamic
83*c2339f05SJoe Komlodi          * address.
84*c2339f05SJoe Komlodi          */
85*c2339f05SJoe Komlodi         if (target->address == 0) {
86*c2339f05SJoe Komlodi             I3CNode *node = g_new(struct I3CNode, 1);
87*c2339f05SJoe Komlodi             node->target = target;
88*c2339f05SJoe Komlodi             QLIST_INSERT_HEAD(&bus->current_devs, node, next);
89*c2339f05SJoe Komlodi         }
90*c2339f05SJoe Komlodi         return target->address == 0;
91*c2339f05SJoe Komlodi     }
92*c2339f05SJoe Komlodi 
93*c2339f05SJoe Komlodi     if ((targ_addr == address) || bus->broadcast) {
94*c2339f05SJoe Komlodi         I3CNode *node = g_new(struct I3CNode, 1);
95*c2339f05SJoe Komlodi         node->target = target;
96*c2339f05SJoe Komlodi         QLIST_INSERT_HEAD(&bus->current_devs, node, next);
97*c2339f05SJoe Komlodi         return true;
98*c2339f05SJoe Komlodi     }
99*c2339f05SJoe Komlodi 
100*c2339f05SJoe Komlodi     return false;
101*c2339f05SJoe Komlodi }
102*c2339f05SJoe Komlodi 
103*c2339f05SJoe Komlodi bool i3c_scan_bus(I3CBus *bus, uint8_t address)
104*c2339f05SJoe Komlodi {
105*c2339f05SJoe Komlodi     BusChild *child;
106*c2339f05SJoe Komlodi     I3CNode *node, *next;
107*c2339f05SJoe Komlodi 
108*c2339f05SJoe Komlodi     /* Clear out any devices from a previous (re-)START. */
109*c2339f05SJoe Komlodi     QLIST_FOREACH_SAFE(node, &bus->current_devs, next, next) {
110*c2339f05SJoe Komlodi         QLIST_REMOVE(node, next);
111*c2339f05SJoe Komlodi         g_free(node);
112*c2339f05SJoe Komlodi     }
113*c2339f05SJoe Komlodi 
114*c2339f05SJoe Komlodi     QTAILQ_FOREACH(child, &bus->qbus.children, sibling) {
115*c2339f05SJoe Komlodi         DeviceState *qdev = child->child;
116*c2339f05SJoe Komlodi         I3CTarget *target = I3C_TARGET(qdev);
117*c2339f05SJoe Komlodi 
118*c2339f05SJoe Komlodi         if (i3c_target_match(bus, target, address)) {
119*c2339f05SJoe Komlodi             return true;
120*c2339f05SJoe Komlodi         }
121*c2339f05SJoe Komlodi     }
122*c2339f05SJoe Komlodi 
123*c2339f05SJoe Komlodi     /* No one on the bus could respond. */
124*c2339f05SJoe Komlodi     return false;
125*c2339f05SJoe Komlodi }
126*c2339f05SJoe Komlodi 
127*c2339f05SJoe Komlodi /* Class-level event handling, since we do some CCCs at the class level. */
128*c2339f05SJoe Komlodi static int i3c_target_event(I3CTarget *t, enum I3CEvent event)
129*c2339f05SJoe Komlodi {
130*c2339f05SJoe Komlodi     I3CTargetClass *tc = I3C_TARGET_GET_CLASS(t);
131*c2339f05SJoe Komlodi     trace_i3c_target_event(t->address, event);
132*c2339f05SJoe Komlodi 
133*c2339f05SJoe Komlodi     if (event == I3C_STOP) {
134*c2339f05SJoe Komlodi         t->curr_ccc = 0;
135*c2339f05SJoe Komlodi         t->ccc_byte_offset = 0;
136*c2339f05SJoe Komlodi         t->in_ccc = false;
137*c2339f05SJoe Komlodi     }
138*c2339f05SJoe Komlodi     return tc->event(t, event);
139*c2339f05SJoe Komlodi }
140*c2339f05SJoe Komlodi 
141*c2339f05SJoe Komlodi /*
142*c2339f05SJoe Komlodi  * Sends a START or repeated START and the address for an I3C transaction.
143*c2339f05SJoe Komlodi  *
144*c2339f05SJoe Komlodi  * This function returns 0 if a device on the bus was able to respond to the
145*c2339f05SJoe Komlodi  * address, and non-zero otherwise.
146*c2339f05SJoe Komlodi  * A non-zero return represents a NACK.
147*c2339f05SJoe Komlodi  */
148*c2339f05SJoe Komlodi static int i3c_do_start_transfer(I3CBus *bus, uint8_t address,
149*c2339f05SJoe Komlodi                                  enum I3CEvent event)
150*c2339f05SJoe Komlodi {
151*c2339f05SJoe Komlodi     I3CTargetClass *tc;
152*c2339f05SJoe Komlodi     I3CNode *node;
153*c2339f05SJoe Komlodi 
154*c2339f05SJoe Komlodi     if (address == I3C_BROADCAST) {
155*c2339f05SJoe Komlodi         bus->broadcast = true;
156*c2339f05SJoe Komlodi         /* If we're not in ENTDAA, a broadcast is the start of a new CCC. */
157*c2339f05SJoe Komlodi         if (!bus->in_entdaa) {
158*c2339f05SJoe Komlodi             bus->in_ccc = false;
159*c2339f05SJoe Komlodi         }
160*c2339f05SJoe Komlodi     } else {
161*c2339f05SJoe Komlodi         bus->broadcast = false;
162*c2339f05SJoe Komlodi     }
163*c2339f05SJoe Komlodi 
164*c2339f05SJoe Komlodi     /* No one responded to the address, NACK it. */
165*c2339f05SJoe Komlodi     if (!i3c_scan_bus(bus, address)) {
166*c2339f05SJoe Komlodi         return -1;
167*c2339f05SJoe Komlodi     }
168*c2339f05SJoe Komlodi 
169*c2339f05SJoe Komlodi     QLIST_FOREACH(node, &bus->current_devs, next) {
170*c2339f05SJoe Komlodi         I3CTarget *t = node->target;
171*c2339f05SJoe Komlodi 
172*c2339f05SJoe Komlodi         tc = I3C_TARGET_GET_CLASS(t);
173*c2339f05SJoe Komlodi         if (tc->event) {
174*c2339f05SJoe Komlodi             int rv = i3c_target_event(t, event);
175*c2339f05SJoe Komlodi             if (rv && !bus->broadcast) {
176*c2339f05SJoe Komlodi                 return rv;
177*c2339f05SJoe Komlodi             }
178*c2339f05SJoe Komlodi         }
179*c2339f05SJoe Komlodi     }
180*c2339f05SJoe Komlodi 
181*c2339f05SJoe Komlodi     return 0;
182*c2339f05SJoe Komlodi }
183*c2339f05SJoe Komlodi 
184*c2339f05SJoe Komlodi int i3c_start_transfer(I3CBus *bus, uint8_t address, bool is_recv)
185*c2339f05SJoe Komlodi {
186*c2339f05SJoe Komlodi     trace_i3c_start_transfer(address, is_recv);
187*c2339f05SJoe Komlodi     return i3c_do_start_transfer(bus, address, is_recv
188*c2339f05SJoe Komlodi                                                ? I3C_START_RECV
189*c2339f05SJoe Komlodi                                                : I3C_START_SEND);
190*c2339f05SJoe Komlodi }
191*c2339f05SJoe Komlodi 
192*c2339f05SJoe Komlodi int i3c_start_recv(I3CBus *bus, uint8_t address)
193*c2339f05SJoe Komlodi {
194*c2339f05SJoe Komlodi     trace_i3c_start_transfer(address, true);
195*c2339f05SJoe Komlodi     return i3c_do_start_transfer(bus, address, I3C_START_RECV);
196*c2339f05SJoe Komlodi }
197*c2339f05SJoe Komlodi 
198*c2339f05SJoe Komlodi int i3c_start_send(I3CBus *bus, uint8_t address)
199*c2339f05SJoe Komlodi {
200*c2339f05SJoe Komlodi     trace_i3c_start_transfer(address, false);
201*c2339f05SJoe Komlodi     return i3c_do_start_transfer(bus, address, I3C_START_SEND);
202*c2339f05SJoe Komlodi }
203*c2339f05SJoe Komlodi 
204*c2339f05SJoe Komlodi void i3c_end_transfer(I3CBus *bus)
205*c2339f05SJoe Komlodi {
206*c2339f05SJoe Komlodi     I3CTargetClass *tc;
207*c2339f05SJoe Komlodi     I3CNode *node, *next;
208*c2339f05SJoe Komlodi 
209*c2339f05SJoe Komlodi     trace_i3c_end_transfer();
210*c2339f05SJoe Komlodi 
211*c2339f05SJoe Komlodi     /*
212*c2339f05SJoe Komlodi      * If we're in ENTDAA, we need to notify all devices when ENTDAA is done.
213*c2339f05SJoe Komlodi      * This is because everyone initially participates due to the broadcast,
214*c2339f05SJoe Komlodi      * but gradually drops out as they get assigned addresses.
215*c2339f05SJoe Komlodi      * Since the current_devs list only stores who's currently participating,
216*c2339f05SJoe Komlodi      * and not everyone who previously participated, we send the STOP to all
217*c2339f05SJoe Komlodi      * children.
218*c2339f05SJoe Komlodi      */
219*c2339f05SJoe Komlodi     if (bus->in_entdaa) {
220*c2339f05SJoe Komlodi         BusChild *child;
221*c2339f05SJoe Komlodi 
222*c2339f05SJoe Komlodi         QTAILQ_FOREACH(child, &bus->qbus.children, sibling) {
223*c2339f05SJoe Komlodi             DeviceState *qdev = child->child;
224*c2339f05SJoe Komlodi             I3CTarget *t = I3C_TARGET(qdev);
225*c2339f05SJoe Komlodi             tc = I3C_TARGET_GET_CLASS(t);
226*c2339f05SJoe Komlodi             if (tc->event) {
227*c2339f05SJoe Komlodi                 i3c_target_event(t, I3C_STOP);
228*c2339f05SJoe Komlodi             }
229*c2339f05SJoe Komlodi         }
230*c2339f05SJoe Komlodi     } else {
231*c2339f05SJoe Komlodi         QLIST_FOREACH_SAFE(node, &bus->current_devs, next, next) {
232*c2339f05SJoe Komlodi             I3CTarget *t = node->target;
233*c2339f05SJoe Komlodi             tc = I3C_TARGET_GET_CLASS(t);
234*c2339f05SJoe Komlodi             if (tc->event) {
235*c2339f05SJoe Komlodi                 i3c_target_event(t, I3C_STOP);
236*c2339f05SJoe Komlodi             }
237*c2339f05SJoe Komlodi             QLIST_REMOVE(node, next);
238*c2339f05SJoe Komlodi             g_free(node);
239*c2339f05SJoe Komlodi         }
240*c2339f05SJoe Komlodi     }
241*c2339f05SJoe Komlodi     bus->broadcast = false;
242*c2339f05SJoe Komlodi     bus->in_entdaa = false;
243*c2339f05SJoe Komlodi     bus->in_ccc = false;
244*c2339f05SJoe Komlodi }
245*c2339f05SJoe Komlodi 
246*c2339f05SJoe Komlodi /*
247*c2339f05SJoe Komlodi  * Any CCCs that are universal across all I3C devices should be handled here.
248*c2339f05SJoe Komlodi  * Once they're handled, we pass the CCC up to the I3C target to do anything
249*c2339f05SJoe Komlodi  * else it may want with the bytes.
250*c2339f05SJoe Komlodi  */
251*c2339f05SJoe Komlodi static int i3c_target_handle_ccc_write(I3CTarget *t, const uint8_t *data,
252*c2339f05SJoe Komlodi                                        uint32_t num_to_send, uint32_t *num_sent)
253*c2339f05SJoe Komlodi {
254*c2339f05SJoe Komlodi     I3CTargetClass *tc = I3C_TARGET_GET_CLASS(t);
255*c2339f05SJoe Komlodi     *num_sent = 0;
256*c2339f05SJoe Komlodi 
257*c2339f05SJoe Komlodi     /* Is this the start of a new CCC? */
258*c2339f05SJoe Komlodi     if (!t->in_ccc) {
259*c2339f05SJoe Komlodi         t->curr_ccc = *data;
260*c2339f05SJoe Komlodi         t->in_ccc = true;
261*c2339f05SJoe Komlodi         *num_sent = 1;
262*c2339f05SJoe Komlodi         trace_i3c_target_handle_ccc(t->address, t->curr_ccc);
263*c2339f05SJoe Komlodi     }
264*c2339f05SJoe Komlodi 
265*c2339f05SJoe Komlodi     switch (t->curr_ccc) {
266*c2339f05SJoe Komlodi     case I3C_CCC_ENTDAA:
267*c2339f05SJoe Komlodi         /*
268*c2339f05SJoe Komlodi          * This is the last byte of ENTDAA, the controller is assigning us an
269*c2339f05SJoe Komlodi          * address.
270*c2339f05SJoe Komlodi          */
271*c2339f05SJoe Komlodi         if (t->ccc_byte_offset == 8) {
272*c2339f05SJoe Komlodi             t->address = *data;
273*c2339f05SJoe Komlodi             t->in_ccc = false;
274*c2339f05SJoe Komlodi             t->curr_ccc = 0;
275*c2339f05SJoe Komlodi             t->ccc_byte_offset = 0;
276*c2339f05SJoe Komlodi             *num_sent = 1;
277*c2339f05SJoe Komlodi         }
278*c2339f05SJoe Komlodi         break;
279*c2339f05SJoe Komlodi     case I3C_CCCD_SETDASA:
280*c2339f05SJoe Komlodi         t->address = t->static_address;
281*c2339f05SJoe Komlodi         break;
282*c2339f05SJoe Komlodi     case I3C_CCC_SETAASA:
283*c2339f05SJoe Komlodi         t->address = t->static_address;
284*c2339f05SJoe Komlodi         break;
285*c2339f05SJoe Komlodi     case I3C_CCC_RSTDAA:
286*c2339f05SJoe Komlodi         t->address = 0;
287*c2339f05SJoe Komlodi         break;
288*c2339f05SJoe Komlodi     case I3C_CCCD_SETNEWDA:
289*c2339f05SJoe Komlodi         /* If this isn't the CCC byte, it's our new address. */
290*c2339f05SJoe Komlodi         if (*num_sent == 0) {
291*c2339f05SJoe Komlodi             t->address = *data;
292*c2339f05SJoe Komlodi             *num_sent = 1;
293*c2339f05SJoe Komlodi         }
294*c2339f05SJoe Komlodi         break;
295*c2339f05SJoe Komlodi     /* Ignore other CCCs it's better to handle on a device-by-device basis. */
296*c2339f05SJoe Komlodi     default:
297*c2339f05SJoe Komlodi         break;
298*c2339f05SJoe Komlodi     }
299*c2339f05SJoe Komlodi     return tc->handle_ccc_write(t, data, num_to_send, num_sent);
300*c2339f05SJoe Komlodi }
301*c2339f05SJoe Komlodi 
302*c2339f05SJoe Komlodi int i3c_send_byte(I3CBus *bus, uint8_t data)
303*c2339f05SJoe Komlodi {
304*c2339f05SJoe Komlodi     /*
305*c2339f05SJoe Komlodi      * Ignored, the caller can determine how many were sent based on if this was
306*c2339f05SJoe Komlodi      * ACKed/NACKed.
307*c2339f05SJoe Komlodi      */
308*c2339f05SJoe Komlodi     uint32_t num_sent;
309*c2339f05SJoe Komlodi     return i3c_send(bus, &data, 1, &num_sent);
310*c2339f05SJoe Komlodi }
311*c2339f05SJoe Komlodi 
312*c2339f05SJoe Komlodi int i3c_send(I3CBus *bus, const uint8_t *data, uint32_t num_to_send,
313*c2339f05SJoe Komlodi              uint32_t *num_sent)
314*c2339f05SJoe Komlodi {
315*c2339f05SJoe Komlodi     I3CTargetClass *tc;
316*c2339f05SJoe Komlodi     I3CTarget *t;
317*c2339f05SJoe Komlodi     I3CNode *node;
318*c2339f05SJoe Komlodi     int ret = 0;
319*c2339f05SJoe Komlodi 
320*c2339f05SJoe Komlodi     /* If this message is a broadcast and no CCC has been found, grab it. */
321*c2339f05SJoe Komlodi     if (bus->broadcast && !bus->in_ccc) {
322*c2339f05SJoe Komlodi         bus->ccc = *data;
323*c2339f05SJoe Komlodi         bus->in_ccc = true;
324*c2339f05SJoe Komlodi         /*
325*c2339f05SJoe Komlodi          * We need to keep track if we're currently in ENTDAA.
326*c2339f05SJoe Komlodi          * On any other CCC, the CCC is over on a RESTART or STOP, but ENTDAA
327*c2339f05SJoe Komlodi          * is only over on a STOP.
328*c2339f05SJoe Komlodi          */
329*c2339f05SJoe Komlodi         if (bus->ccc == I3C_CCC_ENTDAA) {
330*c2339f05SJoe Komlodi             bus->in_entdaa = true;
331*c2339f05SJoe Komlodi         }
332*c2339f05SJoe Komlodi     }
333*c2339f05SJoe Komlodi 
334*c2339f05SJoe Komlodi     QLIST_FOREACH(node, &bus->current_devs, next) {
335*c2339f05SJoe Komlodi         t = node->target;
336*c2339f05SJoe Komlodi         tc = I3C_TARGET_GET_CLASS(t);
337*c2339f05SJoe Komlodi         if (bus->in_ccc) {
338*c2339f05SJoe Komlodi             if (!tc->handle_ccc_write) {
339*c2339f05SJoe Komlodi                 ret = -1;
340*c2339f05SJoe Komlodi                 continue;
341*c2339f05SJoe Komlodi             }
342*c2339f05SJoe Komlodi             ret = i3c_target_handle_ccc_write(t, data, num_to_send, num_sent);
343*c2339f05SJoe Komlodi             /* Targets should only NACK on a direct CCC. */
344*c2339f05SJoe Komlodi             if (ret && !CCC_IS_DIRECT(bus->ccc)) {
345*c2339f05SJoe Komlodi                 ret = 0;
346*c2339f05SJoe Komlodi             }
347*c2339f05SJoe Komlodi         } else {
348*c2339f05SJoe Komlodi             if (tc->send) {
349*c2339f05SJoe Komlodi                 ret = ret || tc->send(t, data, num_to_send, num_sent);
350*c2339f05SJoe Komlodi             } else {
351*c2339f05SJoe Komlodi                 ret = -1;
352*c2339f05SJoe Komlodi             }
353*c2339f05SJoe Komlodi         }
354*c2339f05SJoe Komlodi     }
355*c2339f05SJoe Komlodi 
356*c2339f05SJoe Komlodi     trace_i3c_send(*num_sent, num_to_send, ret == 0);
357*c2339f05SJoe Komlodi 
358*c2339f05SJoe Komlodi     return ret ? -1 : 0;
359*c2339f05SJoe Komlodi }
360*c2339f05SJoe Komlodi 
361*c2339f05SJoe Komlodi static int i3c_target_handle_ccc_read(I3CTarget *t, uint8_t *data,
362*c2339f05SJoe Komlodi                                       uint32_t num_to_read, uint32_t *num_read)
363*c2339f05SJoe Komlodi {
364*c2339f05SJoe Komlodi     I3CTargetClass *tc = I3C_TARGET_GET_CLASS(t);
365*c2339f05SJoe Komlodi     uint8_t read_count = 0;
366*c2339f05SJoe Komlodi 
367*c2339f05SJoe Komlodi     switch (t->curr_ccc) {
368*c2339f05SJoe Komlodi     case I3C_CCC_ENTDAA:
369*c2339f05SJoe Komlodi         /* Return the 6-byte PID, followed by BCR then DCR. */
370*c2339f05SJoe Komlodi         while (t->ccc_byte_offset < 6) {
371*c2339f05SJoe Komlodi             if (read_count >= num_to_read) {
372*c2339f05SJoe Komlodi                 break;
373*c2339f05SJoe Komlodi             }
374*c2339f05SJoe Komlodi             data[read_count] = (t->pid >> (t->ccc_byte_offset * 8)) & 0xff;
375*c2339f05SJoe Komlodi             t->ccc_byte_offset++;
376*c2339f05SJoe Komlodi             read_count++;
377*c2339f05SJoe Komlodi         }
378*c2339f05SJoe Komlodi         if (read_count < num_to_read) {
379*c2339f05SJoe Komlodi             data[read_count] = t->bcr;
380*c2339f05SJoe Komlodi             t->ccc_byte_offset++;
381*c2339f05SJoe Komlodi             read_count++;
382*c2339f05SJoe Komlodi         }
383*c2339f05SJoe Komlodi         if (read_count < num_to_read) {
384*c2339f05SJoe Komlodi             data[read_count] = t->dcr;
385*c2339f05SJoe Komlodi             t->ccc_byte_offset++;
386*c2339f05SJoe Komlodi             read_count++;
387*c2339f05SJoe Komlodi         }
388*c2339f05SJoe Komlodi         *num_read = read_count;
389*c2339f05SJoe Komlodi         break;
390*c2339f05SJoe Komlodi     case I3C_CCCD_GETPID:
391*c2339f05SJoe Komlodi         while (t->ccc_byte_offset < 6) {
392*c2339f05SJoe Komlodi             if (read_count >= num_to_read) {
393*c2339f05SJoe Komlodi                 break;
394*c2339f05SJoe Komlodi             }
395*c2339f05SJoe Komlodi             data[read_count] = (t->pid >> (t->ccc_byte_offset * 8)) & 0xff;
396*c2339f05SJoe Komlodi             t->ccc_byte_offset++;
397*c2339f05SJoe Komlodi             read_count++;
398*c2339f05SJoe Komlodi         }
399*c2339f05SJoe Komlodi         *num_read = read_count;
400*c2339f05SJoe Komlodi         break;
401*c2339f05SJoe Komlodi     case I3C_CCCD_GETBCR:
402*c2339f05SJoe Komlodi         *data = t->bcr;
403*c2339f05SJoe Komlodi         *num_read = 1;
404*c2339f05SJoe Komlodi         break;
405*c2339f05SJoe Komlodi     case I3C_CCCD_GETDCR:
406*c2339f05SJoe Komlodi         *data = t->dcr;
407*c2339f05SJoe Komlodi         *num_read = 1;
408*c2339f05SJoe Komlodi         break;
409*c2339f05SJoe Komlodi     default:
410*c2339f05SJoe Komlodi         /* Unhandled on the I3CTarget class level. */
411*c2339f05SJoe Komlodi         break;
412*c2339f05SJoe Komlodi     }
413*c2339f05SJoe Komlodi 
414*c2339f05SJoe Komlodi     return tc->handle_ccc_read(t, data, num_to_read, num_read);
415*c2339f05SJoe Komlodi }
416*c2339f05SJoe Komlodi 
417*c2339f05SJoe Komlodi int i3c_recv_byte(I3CBus *bus, uint8_t *data)
418*c2339f05SJoe Komlodi {
419*c2339f05SJoe Komlodi      /*
420*c2339f05SJoe Komlodi       * Ignored, the caller can determine how many bytes were read based on if
421*c2339f05SJoe Komlodi       * this is ACKed/NACKed.
422*c2339f05SJoe Komlodi       */
423*c2339f05SJoe Komlodi     uint32_t num_read;
424*c2339f05SJoe Komlodi     return i3c_recv(bus, data, 1, &num_read);
425*c2339f05SJoe Komlodi }
426*c2339f05SJoe Komlodi 
427*c2339f05SJoe Komlodi int i3c_recv(I3CBus *bus, uint8_t *data, uint32_t num_to_read,
428*c2339f05SJoe Komlodi              uint32_t *num_read)
429*c2339f05SJoe Komlodi {
430*c2339f05SJoe Komlodi     int ret = 0;
431*c2339f05SJoe Komlodi     I3CTargetClass *tc;
432*c2339f05SJoe Komlodi     I3CTarget *t;
433*c2339f05SJoe Komlodi 
434*c2339f05SJoe Komlodi     *data = 0xff;
435*c2339f05SJoe Komlodi     if (!QLIST_EMPTY(&bus->current_devs)) {
436*c2339f05SJoe Komlodi         tc = I3C_TARGET_GET_CLASS(QLIST_FIRST(&bus->current_devs)->target);
437*c2339f05SJoe Komlodi         t = QLIST_FIRST(&bus->current_devs)->target;
438*c2339f05SJoe Komlodi         if (bus->in_ccc) {
439*c2339f05SJoe Komlodi             if (!tc->handle_ccc_read) {
440*c2339f05SJoe Komlodi                 return -1;
441*c2339f05SJoe Komlodi             }
442*c2339f05SJoe Komlodi             ret = i3c_target_handle_ccc_read(t, data, num_to_read, num_read);
443*c2339f05SJoe Komlodi         } else {
444*c2339f05SJoe Komlodi             if (tc->recv) {
445*c2339f05SJoe Komlodi                 /*
446*c2339f05SJoe Komlodi                  * Targets cannot NACK on a direct transfer, so the data
447*c2339f05SJoe Komlodi                  * is returned directly.
448*c2339f05SJoe Komlodi                  */
449*c2339f05SJoe Komlodi                 *num_read = tc->recv(t, data, num_to_read);
450*c2339f05SJoe Komlodi             }
451*c2339f05SJoe Komlodi         }
452*c2339f05SJoe Komlodi     }
453*c2339f05SJoe Komlodi 
454*c2339f05SJoe Komlodi     trace_i3c_recv(*num_read, num_to_read, ret == 0);
455*c2339f05SJoe Komlodi 
456*c2339f05SJoe Komlodi     return ret;
457*c2339f05SJoe Komlodi }
458*c2339f05SJoe Komlodi 
459*c2339f05SJoe Komlodi void i3c_nack(I3CBus *bus)
460*c2339f05SJoe Komlodi {
461*c2339f05SJoe Komlodi     I3CTargetClass *tc;
462*c2339f05SJoe Komlodi     I3CNode *node;
463*c2339f05SJoe Komlodi 
464*c2339f05SJoe Komlodi     if (QLIST_EMPTY(&bus->current_devs)) {
465*c2339f05SJoe Komlodi         return;
466*c2339f05SJoe Komlodi     }
467*c2339f05SJoe Komlodi 
468*c2339f05SJoe Komlodi     QLIST_FOREACH(node, &bus->current_devs, next) {
469*c2339f05SJoe Komlodi         tc = I3C_TARGET_GET_CLASS(node->target);
470*c2339f05SJoe Komlodi         if (tc->event) {
471*c2339f05SJoe Komlodi             i3c_target_event(node->target, I3C_NACK);
472*c2339f05SJoe Komlodi         }
473*c2339f05SJoe Komlodi     }
474*c2339f05SJoe Komlodi }
475*c2339f05SJoe Komlodi 
476*c2339f05SJoe Komlodi int i3c_target_send_ibi(I3CTarget *t, uint8_t addr, bool is_recv)
477*c2339f05SJoe Komlodi {
478*c2339f05SJoe Komlodi     I3CBus *bus = I3C_BUS(t->qdev.parent_bus);
479*c2339f05SJoe Komlodi     I3CBusClass *bc = I3C_BUS_GET_CLASS(bus);
480*c2339f05SJoe Komlodi     trace_i3c_target_send_ibi(addr, is_recv);
481*c2339f05SJoe Komlodi     return bc->ibi_handle(bus, t, addr, is_recv);
482*c2339f05SJoe Komlodi }
483*c2339f05SJoe Komlodi 
484*c2339f05SJoe Komlodi int i3c_target_send_ibi_bytes(I3CTarget *t, uint8_t data)
485*c2339f05SJoe Komlodi {
486*c2339f05SJoe Komlodi     I3CBus *bus = I3C_BUS(t->qdev.parent_bus);
487*c2339f05SJoe Komlodi     I3CBusClass *bc = I3C_BUS_GET_CLASS(bus);
488*c2339f05SJoe Komlodi     trace_i3c_target_send_ibi_bytes(data);
489*c2339f05SJoe Komlodi     return bc->ibi_recv(bus, data);
490*c2339f05SJoe Komlodi }
491*c2339f05SJoe Komlodi 
492*c2339f05SJoe Komlodi int i3c_target_ibi_finish(I3CTarget *t, uint8_t data)
493*c2339f05SJoe Komlodi {
494*c2339f05SJoe Komlodi     I3CBus *bus = I3C_BUS(t->qdev.parent_bus);
495*c2339f05SJoe Komlodi     I3CBusClass *bc = I3C_BUS_GET_CLASS(bus);
496*c2339f05SJoe Komlodi     trace_i3c_target_ibi_finish();
497*c2339f05SJoe Komlodi     return bc->ibi_finish(bus);
498*c2339f05SJoe Komlodi }
499*c2339f05SJoe Komlodi 
500*c2339f05SJoe Komlodi static bool i3c_addr_is_rsvd(uint8_t addr)
501*c2339f05SJoe Komlodi {
502*c2339f05SJoe Komlodi     const bool is_rsvd[255] = {
503*c2339f05SJoe Komlodi         [0x00] = true,
504*c2339f05SJoe Komlodi         [0x01] = true,
505*c2339f05SJoe Komlodi         [0x02] = true,
506*c2339f05SJoe Komlodi         [0x3e] = true,
507*c2339f05SJoe Komlodi         [0x5e] = true,
508*c2339f05SJoe Komlodi         [0x6e] = true,
509*c2339f05SJoe Komlodi         [0x76] = true,
510*c2339f05SJoe Komlodi         [0x7a] = true,
511*c2339f05SJoe Komlodi         [0x7c] = true,
512*c2339f05SJoe Komlodi         [0x7e] = true,
513*c2339f05SJoe Komlodi         [0x7f] = true,
514*c2339f05SJoe Komlodi     };
515*c2339f05SJoe Komlodi 
516*c2339f05SJoe Komlodi     return is_rsvd[addr];
517*c2339f05SJoe Komlodi }
518*c2339f05SJoe Komlodi 
519*c2339f05SJoe Komlodi I3CTarget *i3c_target_new(const char *name, uint8_t addr, uint8_t dcr,
520*c2339f05SJoe Komlodi                           uint8_t bcr, uint64_t pid)
521*c2339f05SJoe Komlodi {
522*c2339f05SJoe Komlodi     DeviceState *dev;
523*c2339f05SJoe Komlodi 
524*c2339f05SJoe Komlodi     dev = qdev_new(name);
525*c2339f05SJoe Komlodi     qdev_prop_set_uint8(dev, "static-address", addr);
526*c2339f05SJoe Komlodi     qdev_prop_set_uint8(dev, "dcr", dcr);
527*c2339f05SJoe Komlodi     qdev_prop_set_uint8(dev, "bcr", bcr);
528*c2339f05SJoe Komlodi     qdev_prop_set_uint64(dev, "pid", pid);
529*c2339f05SJoe Komlodi 
530*c2339f05SJoe Komlodi     if (i3c_addr_is_rsvd(addr)) {
531*c2339f05SJoe Komlodi         qemu_log_mask(LOG_GUEST_ERROR, "%s: I3C target created with reserved "
532*c2339f05SJoe Komlodi                       "address 0x%.2x\n",
533*c2339f05SJoe Komlodi                       object_get_canonical_path(OBJECT(dev)), addr);
534*c2339f05SJoe Komlodi     }
535*c2339f05SJoe Komlodi     return I3C_TARGET(dev);
536*c2339f05SJoe Komlodi }
537*c2339f05SJoe Komlodi 
538*c2339f05SJoe Komlodi bool i3c_target_realize_and_unref(I3CTarget *dev, I3CBus *bus, Error **errp)
539*c2339f05SJoe Komlodi {
540*c2339f05SJoe Komlodi     return qdev_realize_and_unref(&dev->qdev, &bus->qbus, errp);
541*c2339f05SJoe Komlodi }
542*c2339f05SJoe Komlodi 
543*c2339f05SJoe Komlodi I3CTarget *i3c_target_create_simple(I3CBus *bus, const char *name, uint8_t addr,
544*c2339f05SJoe Komlodi                                     uint8_t dcr, uint8_t bcr, uint64_t pid)
545*c2339f05SJoe Komlodi {
546*c2339f05SJoe Komlodi     I3CTarget *dev = i3c_target_new(name, addr, dcr, bcr, pid);
547*c2339f05SJoe Komlodi     dev->address = 0;
548*c2339f05SJoe Komlodi     i3c_target_realize_and_unref(dev, bus, &error_abort);
549*c2339f05SJoe Komlodi 
550*c2339f05SJoe Komlodi     return dev;
551*c2339f05SJoe Komlodi }
552*c2339f05SJoe Komlodi 
553*c2339f05SJoe Komlodi /* Legacy I2C functions. */
554*c2339f05SJoe Komlodi void legacy_i2c_nack(I3CBus *bus)
555*c2339f05SJoe Komlodi {
556*c2339f05SJoe Komlodi     trace_legacy_i2c_nack();
557*c2339f05SJoe Komlodi     i2c_nack(bus->i2c_bus);
558*c2339f05SJoe Komlodi }
559*c2339f05SJoe Komlodi 
560*c2339f05SJoe Komlodi uint8_t legacy_i2c_recv(I3CBus *bus)
561*c2339f05SJoe Komlodi {
562*c2339f05SJoe Komlodi     uint8_t byte = i2c_recv(bus->i2c_bus);
563*c2339f05SJoe Komlodi     trace_legacy_i2c_recv(byte);
564*c2339f05SJoe Komlodi     return byte;
565*c2339f05SJoe Komlodi }
566*c2339f05SJoe Komlodi 
567*c2339f05SJoe Komlodi int legacy_i2c_send(I3CBus *bus, uint8_t data)
568*c2339f05SJoe Komlodi {
569*c2339f05SJoe Komlodi     trace_legacy_i2c_send(data);
570*c2339f05SJoe Komlodi     return i2c_send(bus->i2c_bus, data);
571*c2339f05SJoe Komlodi }
572*c2339f05SJoe Komlodi 
573*c2339f05SJoe Komlodi int legacy_i2c_start_transfer(I3CBus *bus, uint8_t address, bool is_recv)
574*c2339f05SJoe Komlodi {
575*c2339f05SJoe Komlodi     trace_legacy_i2c_start_transfer(address, is_recv);
576*c2339f05SJoe Komlodi     return i2c_start_transfer(bus->i2c_bus, address, is_recv);
577*c2339f05SJoe Komlodi }
578*c2339f05SJoe Komlodi 
579*c2339f05SJoe Komlodi int legacy_i2c_start_recv(I3CBus *bus, uint8_t address)
580*c2339f05SJoe Komlodi {
581*c2339f05SJoe Komlodi     trace_legacy_i2c_start_transfer(address, true);
582*c2339f05SJoe Komlodi     return i2c_start_transfer(bus->i2c_bus, address, /*is_recv=*/true);
583*c2339f05SJoe Komlodi }
584*c2339f05SJoe Komlodi 
585*c2339f05SJoe Komlodi int legacy_i2c_start_send(I3CBus *bus, uint8_t address)
586*c2339f05SJoe Komlodi {
587*c2339f05SJoe Komlodi     trace_legacy_i2c_start_transfer(address, false);
588*c2339f05SJoe Komlodi     return i2c_start_transfer(bus->i2c_bus, address, /*is_recv=*/false);
589*c2339f05SJoe Komlodi }
590*c2339f05SJoe Komlodi 
591*c2339f05SJoe Komlodi void legacy_i2c_end_transfer(I3CBus *bus)
592*c2339f05SJoe Komlodi {
593*c2339f05SJoe Komlodi     trace_legacy_i2c_end_transfer();
594*c2339f05SJoe Komlodi     i2c_end_transfer(bus->i2c_bus);
595*c2339f05SJoe Komlodi }
596*c2339f05SJoe Komlodi 
597*c2339f05SJoe Komlodi I2CSlave *legacy_i2c_device_create_simple(I3CBus *bus, const char *name,
598*c2339f05SJoe Komlodi                                           uint8_t addr)
599*c2339f05SJoe Komlodi {
600*c2339f05SJoe Komlodi     I2CSlave *dev = i2c_slave_new(name, addr);
601*c2339f05SJoe Komlodi 
602*c2339f05SJoe Komlodi     i2c_slave_realize_and_unref(dev, bus->i2c_bus, &error_abort);
603*c2339f05SJoe Komlodi     return dev;
604*c2339f05SJoe Komlodi }
605*c2339f05SJoe Komlodi 
606*c2339f05SJoe Komlodi static void i3c_target_class_init(ObjectClass *klass, void *data)
607*c2339f05SJoe Komlodi {
608*c2339f05SJoe Komlodi     DeviceClass *k = DEVICE_CLASS(klass);
609*c2339f05SJoe Komlodi     set_bit(DEVICE_CATEGORY_MISC, k->categories);
610*c2339f05SJoe Komlodi     k->bus_type = TYPE_I3C_BUS;
611*c2339f05SJoe Komlodi     device_class_set_props(k, i3c_props);
612*c2339f05SJoe Komlodi }
613*c2339f05SJoe Komlodi 
614*c2339f05SJoe Komlodi static const TypeInfo i3c_target_type_info = {
615*c2339f05SJoe Komlodi     .name = TYPE_I3C_TARGET,
616*c2339f05SJoe Komlodi     .parent = TYPE_DEVICE,
617*c2339f05SJoe Komlodi     .instance_size = sizeof(I3CTarget),
618*c2339f05SJoe Komlodi     .abstract = true,
619*c2339f05SJoe Komlodi     .class_size = sizeof(I3CTargetClass),
620*c2339f05SJoe Komlodi     .class_init = i3c_target_class_init,
621*c2339f05SJoe Komlodi };
622*c2339f05SJoe Komlodi 
623*c2339f05SJoe Komlodi static void i3c_register_types(void)
624*c2339f05SJoe Komlodi {
625*c2339f05SJoe Komlodi     type_register_static(&i3c_bus_info);
626*c2339f05SJoe Komlodi     type_register_static(&i3c_target_type_info);
627*c2339f05SJoe Komlodi }
628*c2339f05SJoe Komlodi 
629*c2339f05SJoe Komlodi type_init(i3c_register_types)
630