Skip to content

Commit d72ef41

Browse files
ziuziakowskaAlexJones0
authored andcommitted
[ot] hw/opentitan: ot_i2c: implement target mode address masking
This implements target mode address masking as described in the documentation - OT I2C target mode will accept a transaction if the bitwise AND of an address and the device's address mask matches the device's address. This is implemented by overriding the default `I2CSlaveClass` `match_and_add` method. See `i2c_slave_match` in `hw/i2c/core.c`. Signed-off-by: Alice Ziuziakowska <[email protected]>
1 parent f5faf01 commit d72ef41

File tree

2 files changed

+36
-14
lines changed

2 files changed

+36
-14
lines changed

docs/opentitan/earlgrey.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ Devices in this group implement subset(s) of the real HW.
6666
* Initialization and scrambling with dummy key supported
6767
* Wait for init completion (bus stall) emulated
6868
* I2C controller
69+
* Supports only one target mode address - ADDRESS1 and MASK1 are not implemented
6970
* Timing features are not implemented
70-
* Only 7-bit addressing with all MASK0 bits set is supported
7171
* Loopback mode is not implemented
7272

7373
### Sparsely implemented devices

hw/opentitan/ot_i2c.c

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
* bus recover/override
4444
* some interrupts will never be generated (except via INTR_TEST)
4545
* 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
4747
* - Loopback mode. Need more details about how it works in HW.
4848
*/
4949

@@ -352,6 +352,9 @@ struct OtI2CState {
352352
/* TX: Scheduled responses for target mode. */
353353
Fifo8 target_tx_fifo;
354354

355+
/* Target mode first address mask */
356+
uint8_t address_mask_0;
357+
355358
uint32_t pclk; /* Current input clock */
356359
const char *clock_src_name; /* IRQ name once connected */
357360

@@ -982,22 +985,19 @@ static void ot_i2c_write(void *opaque, hwaddr addr, uint64_t val64,
982985
break;
983986
case R_TARGET_ID:
984987
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) {
991988
qemu_log_mask(
992989
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",
994991
__func__, s->ot_id);
995-
break;
996992
}
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) {
10011001
/* Update the address of this target on the bus. */
10021002
i2c_slave_set_address(s->target, address);
10031003
}
@@ -1241,13 +1241,34 @@ static void ot_i2c_target_send_async(I2CSlave *target, uint8_t data)
12411241
}
12421242
}
12431243

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+
12441264
static void ot_i2c_target_class_init(ObjectClass *klass, void *data)
12451265
{
12461266
DeviceClass *dc = DEVICE_CLASS(klass);
12471267
I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
12481268
(void)data;
12491269

12501270
dc->desc = "OpenTitan I2C Target";
1271+
sc->match_and_add = &ot_i2c_target_match_and_add;
12511272
sc->event = &ot_i2c_target_event;
12521273
sc->send_async = &ot_i2c_target_send_async;
12531274
sc->recv = &ot_i2c_target_recv;
@@ -1311,6 +1332,7 @@ static void ot_i2c_reset_enter(Object *obj, ResetType type)
13111332
}
13121333

13131334
s->check_timings = true;
1335+
s->address_mask_0 = 0x0u;
13141336
}
13151337

13161338
static void ot_i2c_realize(DeviceState *dev, Error **errp)

0 commit comments

Comments
 (0)