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