|
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