|
43 | 43 | * bus recover/override |
44 | 44 | * some interrupts will never be generated (except via INTR_TEST) |
45 | 45 | * bus timing registers are ignored |
46 | | - * - Target mode only supports TARGET_ID.ADDRESS0 with TARGET_ID.MASK0=0x7F. |
| 46 | + * - Target mode only supports TARGET_ID.ADDRESS0 and TARGET_ID.MASK0 |
47 | 47 | * - Loopback mode. Need more details about how it works in HW. |
48 | 48 | */ |
49 | 49 |
|
@@ -352,6 +352,9 @@ struct OtI2CState { |
352 | 352 | /* TX: Scheduled responses for target mode. */ |
353 | 353 | Fifo8 target_tx_fifo; |
354 | 354 |
|
| 355 | + /* Target mode first address mask */ |
| 356 | + uint8_t address_mask_0; |
| 357 | + |
355 | 358 | uint32_t pclk; /* Current input clock */ |
356 | 359 | const char *clock_src_name; /* IRQ name once connected */ |
357 | 360 |
|
@@ -982,22 +985,19 @@ static void ot_i2c_write(void *opaque, hwaddr addr, uint64_t val64, |
982 | 985 | break; |
983 | 986 | case R_TARGET_ID: |
984 | 987 | if (FIELD_EX32(val32, TARGET_ID, ADDRESS1)) { |
985 | | - qemu_log_mask(LOG_GUEST_ERROR, |
986 | | - "%s: %s: Target address 1 not supported.\n", __func__, |
987 | | - s->ot_id); |
988 | | - } |
989 | | - address = FIELD_EX32(val32, TARGET_ID, ADDRESS0); |
990 | | - if ((val32 & R_TARGET_ID_MASK0_MASK) != R_TARGET_ID_MASK0_MASK) { |
991 | 988 | qemu_log_mask( |
992 | 989 | LOG_UNIMP, |
993 | | - "%s: %s: Address Mask with any bits unset is not supported.\n", |
| 990 | + "%s: %s: Target mode second address is not supported.\n", |
994 | 991 | __func__, s->ot_id); |
995 | | - break; |
996 | 992 | } |
997 | | - if (address != 0) { |
998 | | - ARRAY_FIELD_DP32(s->regs, TARGET_ID, ADDRESS0, address); |
999 | | - mask = FIELD_EX32(val32, TARGET_ID, MASK0); |
1000 | | - ARRAY_FIELD_DP32(s->regs, TARGET_ID, MASK0, mask); |
| 993 | + address = FIELD_EX32(val32, TARGET_ID, ADDRESS0); |
| 994 | + mask = FIELD_EX32(val32, TARGET_ID, MASK0); |
| 995 | + |
| 996 | + ARRAY_FIELD_DP32(s->regs, TARGET_ID, ADDRESS0, address); |
| 997 | + ARRAY_FIELD_DP32(s->regs, TARGET_ID, MASK0, mask); |
| 998 | + /* Update the address mask of this target on the bus. */ |
| 999 | + s->address_mask_0 = (uint8_t)mask; |
| 1000 | + if (address != 0u) { |
1001 | 1001 | /* Update the address of this target on the bus. */ |
1002 | 1002 | i2c_slave_set_address(s->target, address); |
1003 | 1003 | } |
@@ -1241,13 +1241,34 @@ static void ot_i2c_target_send_async(I2CSlave *target, uint8_t data) |
1241 | 1241 | } |
1242 | 1242 | } |
1243 | 1243 |
|
| 1244 | +static bool ot_i2c_target_match_and_add(I2CSlave *candidate, uint8_t address, |
| 1245 | + bool broadcast, |
| 1246 | + I2CNodeList *current_devs) |
| 1247 | +{ |
| 1248 | + BusState *abus = qdev_get_parent_bus(DEVICE(candidate)); |
| 1249 | + OtI2CState *s = OT_I2C(abus->parent); |
| 1250 | + |
| 1251 | + /* Check address, subject to address masking. */ |
| 1252 | + if (broadcast || (s->address_mask_0 && |
| 1253 | + (address & s->address_mask_0) == candidate->address)) { |
| 1254 | + I2CNode *node = g_new0(struct I2CNode, 1u); |
| 1255 | + node->elt = candidate; |
| 1256 | + QLIST_INSERT_HEAD(current_devs, node, next); |
| 1257 | + return true; |
| 1258 | + } |
| 1259 | + |
| 1260 | + /* Not found and not broadcast. */ |
| 1261 | + return false; |
| 1262 | +} |
| 1263 | + |
1244 | 1264 | static void ot_i2c_target_class_init(ObjectClass *klass, void *data) |
1245 | 1265 | { |
1246 | 1266 | DeviceClass *dc = DEVICE_CLASS(klass); |
1247 | 1267 | I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); |
1248 | 1268 | (void)data; |
1249 | 1269 |
|
1250 | 1270 | dc->desc = "OpenTitan I2C Target"; |
| 1271 | + sc->match_and_add = &ot_i2c_target_match_and_add; |
1251 | 1272 | sc->event = &ot_i2c_target_event; |
1252 | 1273 | sc->send_async = &ot_i2c_target_send_async; |
1253 | 1274 | sc->recv = &ot_i2c_target_recv; |
@@ -1311,6 +1332,7 @@ static void ot_i2c_reset_enter(Object *obj, ResetType type) |
1311 | 1332 | } |
1312 | 1333 |
|
1313 | 1334 | s->check_timings = true; |
| 1335 | + s->address_mask_0 = 0x0u; |
1314 | 1336 | } |
1315 | 1337 |
|
1316 | 1338 | static void ot_i2c_realize(DeviceState *dev, Error **errp) |
|
0 commit comments