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