Skip to content

Commit 49896ee

Browse files
ziuziakowskaAlexJones0
authored andcommitted
[ot] hw/opentitan: ot_i2c: use matched address for acq, not bus address
This is a bugfix for target mode address masking. Previously, the OT I2C's bus address would be used for the address byte on a start condition. Now that address masking is implemented, the address that matched may not be exactly the bus address (as some bits are ignored). Hardware presents the matched address in the start condition byte so that software can perform different actions based on different target transaction addresses. Signed-off-by: Alice Ziuziakowska <[email protected]>
1 parent b2b7f09 commit 49896ee

File tree

1 file changed

+24
-4
lines changed

1 file changed

+24
-4
lines changed

hw/opentitan/ot_i2c.c

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,9 @@ struct OtI2CState {
355355
/* Target mode first address mask */
356356
uint8_t address_mask_0;
357357

358+
/* Address that was matched to us */
359+
uint8_t matched_address;
360+
358361
uint32_t pclk; /* Current input clock */
359362
const char *clock_src_name; /* IRQ name once connected */
360363

@@ -372,6 +375,11 @@ struct OtI2CTarget {
372375
I2CSlave i2c;
373376
};
374377

378+
static uint8_t ot_i2c_address_abyte(uint8_t address, bool read)
379+
{
380+
return (address << 1u) | (read ? 1u : 0);
381+
}
382+
375383
static void ot_i2c_update_irqs(OtI2CState *s)
376384
{
377385
uint32_t state_masked = s->regs[R_INTR_STATE] & s->regs[R_INTR_ENABLE];
@@ -1166,13 +1174,18 @@ static int ot_i2c_target_event(I2CSlave *target, enum i2c_event event)
11661174

11671175
switch (event) {
11681176
case I2C_START_SEND_ASYNC:
1169-
/* Set the first byte to the target address + RW bit as 0. */
1170-
ot_i2c_target_set_acqdata(s, target->address << 1u, SIGNAL_START);
1177+
/* Set the first byte to the matched target address + RW bit as 0. */
1178+
ot_i2c_target_set_acqdata(s,
1179+
ot_i2c_address_abyte(s->matched_address,
1180+
false),
1181+
SIGNAL_START);
11711182
i2c_ack(s->bus);
11721183
break;
11731184
case I2C_START_RECV:
1174-
/* Set the first byte to the target address + RW bit as 1. */
1175-
ot_i2c_target_set_acqdata(s, target->address << 1u | 1u, SIGNAL_START);
1185+
ot_i2c_target_set_acqdata(s,
1186+
ot_i2c_address_abyte(s->matched_address,
1187+
true),
1188+
SIGNAL_START);
11761189
if (ot_fifo32_num_used(&s->target_rx_fifo) > 1) {
11771190
/*
11781191
* Potentially an unhandled condition in the ACQ fifo. Datasheet
@@ -1251,6 +1264,12 @@ static bool ot_i2c_target_match_and_add(I2CSlave *candidate, uint8_t address,
12511264
/* Check address, subject to address masking. */
12521265
if (broadcast || (s->address_mask_0 &&
12531266
(address & s->address_mask_0) == candidate->address)) {
1267+
/*
1268+
* Store the address that successfully matched to
1269+
* use the correct address for start condition
1270+
*/
1271+
s->matched_address = address;
1272+
12541273
I2CNode *node = g_new0(struct I2CNode, 1u);
12551274
node->elt = candidate;
12561275
QLIST_INSERT_HEAD(current_devs, node, next);
@@ -1333,6 +1352,7 @@ static void ot_i2c_reset_enter(Object *obj, ResetType type)
13331352

13341353
s->check_timings = true;
13351354
s->address_mask_0 = 0x0u;
1355+
s->matched_address = 0x0u;
13361356
}
13371357

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

0 commit comments

Comments
 (0)