Software APIs
i2c_target_smbus_arp_test.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 /**
6  * This test consists of multiple parts:
7  * - First, the test controller configures the UDID and the Message command
8  * value (a "register" address of sorts).
9  * - Then, the test controller sets kTestInitDone to indicate that
10  * initialization via the ujson command processor is complete.
11  * - Next, the test controller issues SMBus ARP commands to configure the
12  * DUT's secondary I2C address. Currently, the PEC is neither generated
13  * nor checked, but the DUT stretches on the PEC byte so it looks like it
14  * checks. Plus, it gets time to assign the new address.
15  * - Finally, the test controller issues a write to the Message register, and
16  * the DUT writes the value. Then the test controller issue a read to the
17  * Message register, and the DUT responds with the current value. The test
18  * passes if the host successfully communicates and receives this value.
19  */
20 #include <assert.h>
21 
30 #include "sw/device/lib/runtime/irq.h"
33 #include "sw/device/lib/testing/i2c_testutils.h"
34 #include "sw/device/lib/testing/json/command.h"
35 #include "sw/device/lib/testing/rv_plic_testutils.h"
36 #include "sw/device/lib/testing/test_framework/check.h"
37 #include "sw/device/lib/testing/test_framework/ottf_console.h"
39 #include "sw/device/lib/testing/test_framework/ujson_ottf.h"
40 #include "sw/device/lib/testing/test_framework/ujson_ottf_commands.h"
41 #include "sw/device/lib/ujson/ujson.h"
42 
44 #include "i2c_regs.h" // Generated.
45 
46 static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__,
47  "This test assumes the target platform is little endian.");
48 
49 OTTF_DEFINE_TEST_CONFIG(.enable_uart_flow_control = true);
50 
51 enum {
52  kArpCmdPrepareToArp = 0x01,
53  kArpCmdResetDevice = 0x02,
54  kArpCmdGetUdid = 0x03,
55  kArpCmdAssignAddress = 0x04,
56 };
57 
58 static const uint8_t pec_lut[256] = {
59  [0x00] = 0x00, [0x01] = 0x07, [0x02] = 0x0e, [0x03] = 0x09, [0x04] = 0x1c,
60  [0x05] = 0x1b, [0x06] = 0x12, [0x07] = 0x15, [0x08] = 0x38, [0x09] = 0x3f,
61  [0x0a] = 0x36, [0x0b] = 0x31, [0x0c] = 0x24, [0x0d] = 0x23, [0x0e] = 0x2a,
62  [0x0f] = 0x2d, [0x10] = 0x70, [0x11] = 0x77, [0x12] = 0x7e, [0x13] = 0x79,
63  [0x14] = 0x6c, [0x15] = 0x6b, [0x16] = 0x62, [0x17] = 0x65, [0x18] = 0x48,
64  [0x19] = 0x4f, [0x1a] = 0x46, [0x1b] = 0x41, [0x1c] = 0x54, [0x1d] = 0x53,
65  [0x1e] = 0x5a, [0x1f] = 0x5d, [0x20] = 0xe0, [0x21] = 0xe7, [0x22] = 0xee,
66  [0x23] = 0xe9, [0x24] = 0xfc, [0x25] = 0xfb, [0x26] = 0xf2, [0x27] = 0xf5,
67  [0x28] = 0xd8, [0x29] = 0xdf, [0x2a] = 0xd6, [0x2b] = 0xd1, [0x2c] = 0xc4,
68  [0x2d] = 0xc3, [0x2e] = 0xca, [0x2f] = 0xcd, [0x30] = 0x90, [0x31] = 0x97,
69  [0x32] = 0x9e, [0x33] = 0x99, [0x34] = 0x8c, [0x35] = 0x8b, [0x36] = 0x82,
70  [0x37] = 0x85, [0x38] = 0xa8, [0x39] = 0xaf, [0x3a] = 0xa6, [0x3b] = 0xa1,
71  [0x3c] = 0xb4, [0x3d] = 0xb3, [0x3e] = 0xba, [0x3f] = 0xbd, [0x40] = 0xc7,
72  [0x41] = 0xc0, [0x42] = 0xc9, [0x43] = 0xce, [0x44] = 0xdb, [0x45] = 0xdc,
73  [0x46] = 0xd5, [0x47] = 0xd2, [0x48] = 0xff, [0x49] = 0xf8, [0x4a] = 0xf1,
74  [0x4b] = 0xf6, [0x4c] = 0xe3, [0x4d] = 0xe4, [0x4e] = 0xed, [0x4f] = 0xea,
75  [0x50] = 0xb7, [0x51] = 0xb0, [0x52] = 0xb9, [0x53] = 0xbe, [0x54] = 0xab,
76  [0x55] = 0xac, [0x56] = 0xa5, [0x57] = 0xa2, [0x58] = 0x8f, [0x59] = 0x88,
77  [0x5a] = 0x81, [0x5b] = 0x86, [0x5c] = 0x93, [0x5d] = 0x94, [0x5e] = 0x9d,
78  [0x5f] = 0x9a, [0x60] = 0x27, [0x61] = 0x20, [0x62] = 0x29, [0x63] = 0x2e,
79  [0x64] = 0x3b, [0x65] = 0x3c, [0x66] = 0x35, [0x67] = 0x32, [0x68] = 0x1f,
80  [0x69] = 0x18, [0x6a] = 0x11, [0x6b] = 0x16, [0x6c] = 0x03, [0x6d] = 0x04,
81  [0x6e] = 0x0d, [0x6f] = 0x0a, [0x70] = 0x57, [0x71] = 0x50, [0x72] = 0x59,
82  [0x73] = 0x5e, [0x74] = 0x4b, [0x75] = 0x4c, [0x76] = 0x45, [0x77] = 0x42,
83  [0x78] = 0x6f, [0x79] = 0x68, [0x7a] = 0x61, [0x7b] = 0x66, [0x7c] = 0x73,
84  [0x7d] = 0x74, [0x7e] = 0x7d, [0x7f] = 0x7a, [0x80] = 0x89, [0x81] = 0x8e,
85  [0x82] = 0x87, [0x83] = 0x80, [0x84] = 0x95, [0x85] = 0x92, [0x86] = 0x9b,
86  [0x87] = 0x9c, [0x88] = 0xb1, [0x89] = 0xb6, [0x8a] = 0xbf, [0x8b] = 0xb8,
87  [0x8c] = 0xad, [0x8d] = 0xaa, [0x8e] = 0xa3, [0x8f] = 0xa4, [0x90] = 0xf9,
88  [0x91] = 0xfe, [0x92] = 0xf7, [0x93] = 0xf0, [0x94] = 0xe5, [0x95] = 0xe2,
89  [0x96] = 0xeb, [0x97] = 0xec, [0x98] = 0xc1, [0x99] = 0xc6, [0x9a] = 0xcf,
90  [0x9b] = 0xc8, [0x9c] = 0xdd, [0x9d] = 0xda, [0x9e] = 0xd3, [0x9f] = 0xd4,
91  [0xa0] = 0x69, [0xa1] = 0x6e, [0xa2] = 0x67, [0xa3] = 0x60, [0xa4] = 0x75,
92  [0xa5] = 0x72, [0xa6] = 0x7b, [0xa7] = 0x7c, [0xa8] = 0x51, [0xa9] = 0x56,
93  [0xaa] = 0x5f, [0xab] = 0x58, [0xac] = 0x4d, [0xad] = 0x4a, [0xae] = 0x43,
94  [0xaf] = 0x44, [0xb0] = 0x19, [0xb1] = 0x1e, [0xb2] = 0x17, [0xb3] = 0x10,
95  [0xb4] = 0x05, [0xb5] = 0x02, [0xb6] = 0x0b, [0xb7] = 0x0c, [0xb8] = 0x21,
96  [0xb9] = 0x26, [0xba] = 0x2f, [0xbb] = 0x28, [0xbc] = 0x3d, [0xbd] = 0x3a,
97  [0xbe] = 0x33, [0xbf] = 0x34, [0xc0] = 0x4e, [0xc1] = 0x49, [0xc2] = 0x40,
98  [0xc3] = 0x47, [0xc4] = 0x52, [0xc5] = 0x55, [0xc6] = 0x5c, [0xc7] = 0x5b,
99  [0xc8] = 0x76, [0xc9] = 0x71, [0xca] = 0x78, [0xcb] = 0x7f, [0xcc] = 0x6a,
100  [0xcd] = 0x6d, [0xce] = 0x64, [0xcf] = 0x63, [0xd0] = 0x3e, [0xd1] = 0x39,
101  [0xd2] = 0x30, [0xd3] = 0x37, [0xd4] = 0x22, [0xd5] = 0x25, [0xd6] = 0x2c,
102  [0xd7] = 0x2b, [0xd8] = 0x06, [0xd9] = 0x01, [0xda] = 0x08, [0xdb] = 0x0f,
103  [0xdc] = 0x1a, [0xdd] = 0x1d, [0xde] = 0x14, [0xdf] = 0x13, [0xe0] = 0xae,
104  [0xe1] = 0xa9, [0xe2] = 0xa0, [0xe3] = 0xa7, [0xe4] = 0xb2, [0xe5] = 0xb5,
105  [0xe6] = 0xbc, [0xe7] = 0xbb, [0xe8] = 0x96, [0xe9] = 0x91, [0xea] = 0x98,
106  [0xeb] = 0x9f, [0xec] = 0x8a, [0xed] = 0x8d, [0xee] = 0x84, [0xef] = 0x83,
107  [0xf0] = 0xde, [0xf1] = 0xd9, [0xf2] = 0xd0, [0xf3] = 0xd7, [0xf4] = 0xc2,
108  [0xf5] = 0xc5, [0xf6] = 0xcc, [0xf7] = 0xcb, [0xf8] = 0xe6, [0xf9] = 0xe1,
109  [0xfa] = 0xe8, [0xfb] = 0xef, [0xfc] = 0xfa, [0xfd] = 0xfd, [0xfe] = 0xf4,
110  [0xff] = 0xf3,
111 };
112 
113 static dif_pinmux_t pinmux;
114 static dif_rv_plic_t plic;
115 static dif_i2c_t i2c;
116 
117 /** The UDID for SMBus ARP purposes. Configured by ujson command. */
118 volatile uint8_t kSmbusUdid[16] = {0};
119 
120 /**
121  * Message command/address value (for the function on the dynamically-configured
122  * I2C address). Configured by ujson command.
123  *
124  * Two commands come from this address:
125  * - Write Message Register:
126  * S - A/Wr - kMessageAddr - data[0] - data[1] - ... - P
127  * - Read Message Register:
128  * S - A/Wr - kMessageAddr - Sr - A/Rd - data[0] - data[1] - ... - P
129  */
130 volatile uint32_t kMessageAddr = 0;
131 
132 /** Test ready indication. Configured by ujson command. */
133 volatile uint32_t kTestInitDone = 0;
134 
135 typedef enum i2c_state {
136  kI2cStateIdle = 0,
137  /** Waiting to check the PEC for a pending ARP command. */
138  kI2cStateArpPec,
139  /** Waiting for the Read transfer to begin after decoding Get UDID. */
140  kI2cStateArpGetUdidWait,
141  /** Waiting to complete transmission of the Get UDID response. */
142  kI2cStateArpGetUdidTransmit,
143  /** Waiting to check the complete UDID for an Assign Address command. */
144  kI2cStateArpCheckUdid,
145  /**
146  * Waiting for either a block length to write or a repeated start for the
147  * Message register commands.
148  */
149  kI2cStateMessageWait,
150  /**
151  * Waiting to receive the complete message to be written to the Message
152  * register.
153  */
154  kI2cStateMessageReceive,
155  /** Waiting to complete transmission of the Message register contents. */
156  kI2cStateMessageTransmit,
157  /** Waiting for the Stop after the Message register read. */
158  kI2cStateMessageFinish,
159  /** Waiting for the PEC and Stop for Assign Address. */
160  kI2cStateAssignAddressComplete,
161  /** Waiting for the transaction to complete (with NACK). */
162  kI2cStateTransactionNack,
163 } i2c_state_t;
164 
165 // Current running PEC.
166 static uint8_t running_pec;
167 
168 // SMBus ARP flags
169 static bool arp_av = false;
170 static bool arp_ar = false;
171 
172 // Which ARP command is currently being processed. 0 is reserved.
173 static uint8_t arp_cmd_pending = 0;
174 
175 // The SMBus ARP address.
176 static const dif_i2c_id_t kSmbusArpId = {
177  .address = 0x61,
178  .mask = 0x7f,
179 };
180 
181 // The dynamic address. To be assigned by SMBus ARP.
182 static dif_i2c_id_t i2c_id = {
183  .address = 0x7f,
184  .mask = 0x7f,
185 };
186 
187 // The enables get saved by the ISR, then restored in normal context.
188 static volatile dif_i2c_irq_enable_snapshot_t i2c_irq_enables;
189 
190 // This gets set in the ISR and reset in normal context. It's used to indcate
191 // that the I2C routine needs to do some processing.
192 static volatile bool i2c_event = false;
193 
194 // Current state of the I2C processing state machine.
195 static i2c_state_t state;
196 
197 /**
198  * A message scratch register assigned to the function on the
199  * dynamically-configured address.
200  */
201 static uint8_t message[32];
202 
203 /**
204  * Process i2c interrupts. Only a few interrupts should ever occur during this
205  * test. All work is deferred to the bottom half.
206  */
207 void i2c_isr(dif_i2c_irq_t irq) {
208  switch (irq) {
209  case kDifI2cIrqFmtThreshold:
210  case kDifI2cIrqRxThreshold:
211  case kDifI2cIrqTxThreshold:
212  case kDifI2cIrqRxOverflow:
213  case kDifI2cIrqControllerHalt:
214  case kDifI2cIrqSclInterference:
215  case kDifI2cIrqSdaInterference:
216  case kDifI2cIrqStretchTimeout:
217  case kDifI2cIrqSdaUnstable:
218  case kDifI2cIrqUnexpStop:
219  case kDifI2cIrqHostTimeout:
220  CHECK(false, "Unexpected I2C IRQ %d", irq);
221  break;
222  case kDifI2cIrqAcqThreshold:
223  case kDifI2cIrqCmdComplete:
224  case kDifI2cIrqTxStretch:
225  case kDifI2cIrqAcqStretch:
226  i2c_event = true;
227  break;
228  default:
229  CHECK(false, "invalid interrupt %d", irq);
230  }
231  dif_i2c_irq_enable_snapshot_t enables;
232  CHECK_DIF_OK(dif_i2c_irq_disable_all(&i2c, &enables));
233  i2c_irq_enables = enables;
234 }
235 
236 /**
237  * External interrupt handler.
238  */
239 void ottf_external_isr(uint32_t *exc_info) {
240  const uint32_t kPlicTarget = kTopEarlgreyPlicTargetIbex0;
241  dif_rv_plic_irq_id_t plic_irq_id = 0;
242  CHECK_DIF_OK(dif_rv_plic_irq_claim(&plic, kPlicTarget, &plic_irq_id));
243 
246 
247  switch (peripheral) {
249  if (!ottf_console_flow_control_isr(exc_info)) {
250  goto unexpected_irq;
251  };
252  break;
254  // Check that the ID matches the expected interrupt, then mask it, since
255  // it's a status type.
256  dif_i2c_irq_t irq =
257  (dif_i2c_irq_t)(plic_irq_id - kTopEarlgreyPlicIrqIdI2c0FmtThreshold);
258  i2c_isr(irq);
259  } break;
260  default:
261  goto unexpected_irq;
262  }
263 
264  // Complete the IRQ at PLIC.
265  CHECK_DIF_OK(dif_rv_plic_irq_complete(&plic, kPlicTarget, plic_irq_id));
266  return;
267 
268  // A label to jump to for common error handling.
269 unexpected_irq:
270  CHECK(false, "Unexpected external IRQ %d", plic_irq_id);
271 }
272 
273 /** This is only used during test initialization. */
274 static status_t command_processor(ujson_t *uj) {
275  while (!kTestInitDone) {
276  test_command_t command;
277  TRY(UJSON_WITH_CRC(ujson_deserialize_test_command_t, uj, &command));
278  status_t status = ujson_ottf_dispatch(uj, command);
279  if (status_err(status) == kUnimplemented) {
280  RESP_ERR(uj, status);
281  } else if (status_err(status) != kOk) {
282  return status;
283  }
284  }
285  return OK_STATUS();
286 }
287 
288 static status_t test_init(void) {
289  mmio_region_t base_addr =
291  TRY(dif_pinmux_init(base_addr, &pinmux));
292 
294  TRY(dif_rv_plic_init(base_addr, &plic));
295 
297  TRY(dif_i2c_init(base_addr, &i2c));
298 
299  TRY(i2c_testutils_select_pinmux(&pinmux, 0, I2cPinmuxPlatformIdHyper310));
300  TRY(i2c_testutils_set_speed(&i2c, kDifI2cSpeedStandard));
301 
302  // 25 ms bus timeout. The upper limit of support is ~1 GHz for the IP, so OK
303  // to make the frequency a uint32_t.
304  uint32_t kBusTimeoutCycles = ((uint32_t)kClockFreqPeripheralHz / (1000 / 25));
306  kBusTimeoutCycles));
307 
308  // 50 us bus idle timeout.
309  uint32_t kIdleCycles = ((uint32_t)kClockFreqPeripheralHz / (1000000 / 50));
310  TRY(dif_i2c_set_host_timeout(&i2c, kIdleCycles));
311 
312  // Enable TX stretch controls. Stale TX data should not be left in the FIFO.
313  // This test shouldn't actually run into the scenario for which these controls
314  // were created, but it still handles the mechanisms that guard against it.
316 
317  // Enable N-byte ACK control.
319  TRY(dif_i2c_reset_tx_fifo(&i2c));
320  TRY(dif_i2c_reset_acq_fifo(&i2c));
321 
322  TRY(dif_i2c_set_target_watermarks(&i2c, /*tx_level=*/0,
323  I2C_PARAM_ACQ_FIFO_DEPTH));
324  TRY(dif_i2c_set_device_id(&i2c, &kSmbusArpId, NULL));
327 
328  // Enable all I2C interrupts.
329  const uint32_t kPlicTarget = kTopEarlgreyPlicTargetIbex0;
330  for (dif_i2c_irq_t irq = kDifI2cIrqFmtThreshold; irq <= kDifI2cIrqHostTimeout;
331  ++irq) {
332  CHECK_DIF_OK(dif_i2c_irq_set_enabled(&i2c, irq, kDifToggleEnabled));
333  }
334  rv_plic_testutils_irq_range_enable(&plic, kPlicTarget,
337 
338  // Initialize the message buffer.
339  memset(message, 0, sizeof(message));
340 
341  // Enable global and external IRQ at Ibex.
342  irq_global_ctrl(true);
343  irq_external_ctrl(true);
344 
345  ujson_t uj = ujson_ottf_console();
346  TRY(command_processor(&uj));
347  return OK_STATUS();
348 }
349 
350 /**
351  * Calculate the PEC / CRC-8, given the running and new values.
352  */
353 static uint8_t calc_pec(uint8_t remainder, uint8_t next) {
354  return pec_lut[remainder ^ next];
355 }
356 
357 /**
358  * This is the entry function for all new transactions that match one of our
359  * addresses. This is the processing function for the kI2cStateIdle state.
360  *
361  * When we reach this state, the ACQ FIFO should have a single entry in it, the
362  * address + rnw byte with a Start preceding it. In addition, the Target module
363  * should be stretching on the first byte of the Write command, since the Auto
364  * Ack Counter starts at 0 for every transfer. From here, we observe the pending
365  * command byte and dispatch.
366  */
367 static status_t process_new_command(dif_i2c_irq_state_snapshot_t irq_snapshot,
368  dif_i2c_status_t i2c_status) {
369  if (bitfield_bit32_read(irq_snapshot, kDifI2cIrqAcqStretch)) {
370  TRY_CHECK(!i2c_status.acq_fifo_empty);
371 
372  uint8_t data;
373  dif_i2c_signal_t signal;
374  TRY(dif_i2c_acquire_byte(&i2c, &data, &signal));
375  TRY_CHECK(signal == kDifI2cSignalStart);
376  running_pec = 0;
377 
378  // All transactions to either address should begin with a write.
379  TRY_CHECK((data & 0x1) == 0, "Expected a write command, but got read");
380  TRY_CHECK(i2c_status.ack_ctrl_stretch);
381 
382  if ((data >> 1) == kSmbusArpId.address) {
383  // Received an SMBus ARP command. Check what it is.
384  uint8_t command;
385  TRY(dif_i2c_get_pending_acq_byte(&i2c, &command));
386  if (command == kArpCmdPrepareToArp) {
387  arp_cmd_pending = command;
388  state = kI2cStateArpPec;
389  TRY(dif_i2c_set_auto_ack_count(&i2c, 2));
390  } else if (command == kArpCmdResetDevice) {
391  arp_cmd_pending = command;
392  state = kI2cStateArpPec;
393  TRY(dif_i2c_set_auto_ack_count(&i2c, 2));
394  } else if (command == kArpCmdGetUdid) {
395  if (arp_ar) {
396  // NACK if AR is 0 for the general Get UDID command.
397  state = kI2cStateTransactionNack;
398  TRY(dif_i2c_nack_transaction(&i2c));
399  } else {
400  // Prepare to receive the beginning of the Read transfer.
401  arp_cmd_pending = command;
402  state = kI2cStateArpGetUdidWait;
403  TRY(dif_i2c_set_auto_ack_count(&i2c, 1));
404  }
405  } else if (command == kArpCmdAssignAddress) {
406  // Prepare to receive the Byte Count and UDID for targeting.
407  // The spec is a bit unclear about whether we absolutely must stop at
408  // every other byte and NACK a mismatch. We wait for the end of the UDID
409  // here.
410  arp_cmd_pending = command;
411  state = kI2cStateArpCheckUdid;
412  TRY(dif_i2c_set_auto_ack_count(&i2c, 17));
413  } else if (command == ((i2c_id.address < 1) | 0)) {
414  // This is the directed Reset device ARP command.
415  if (arp_av) {
416  arp_cmd_pending = kArpCmdResetDevice;
417  state = kI2cStateArpPec;
418  TRY(dif_i2c_set_auto_ack_count(&i2c, 2));
419  } else {
420  // i2c_id is actually not valid, so reject this command.
421  state = kI2cStateTransactionNack;
422  TRY(dif_i2c_nack_transaction(&i2c));
423  }
424  } else if (command == ((i2c_id.address < 1) | 1)) {
425  // This is the directed Get UDID command.
426  if (arp_av) {
427  // Prepare to receive the beginning of the Read transfer.
428  arp_cmd_pending = kArpCmdGetUdid;
429  state = kI2cStateArpGetUdidWait;
430  TRY(dif_i2c_set_auto_ack_count(&i2c, 1));
431  } else {
432  // NACK if AV is 0 for the general Get UDID command.
433  state = kI2cStateTransactionNack;
434  TRY(dif_i2c_nack_transaction(&i2c));
435  }
436  } else {
437  state = kI2cStateTransactionNack;
438  TRY(dif_i2c_nack_transaction(&i2c));
439  }
440  } else if (arp_av && ((data >> 1) == i2c_id.address)) {
441  uint8_t command;
442  TRY(dif_i2c_get_pending_acq_byte(&i2c, &command));
443  if (command == (kMessageAddr & 0xffu)) {
444  // We'll need to wait and see whether this is a write or the beginning
445  // of a read.
446  state = kI2cStateMessageWait;
447  TRY(dif_i2c_set_auto_ack_count(&i2c, 1));
448  } else {
449  // Got an unsupported command. NACK the transaction.
450  state = kI2cStateTransactionNack;
451  TRY(dif_i2c_nack_transaction(&i2c));
452  }
453  } else {
454  TRY_CHECK(false, "Unexpected 7-bit addr match: 0x%x", (data >> 1));
455  }
456  } else {
457  TRY_CHECK(false, "Unexpected INTR_STATE=0x%x", irq_snapshot);
458  }
459  return OK_STATUS();
460 }
461 
462 /**
463  * This state is the final state for the Prepare to ARP and Reset Device
464  * commands. They will have automatically ACK'd the 2 data bytes and the PEC
465  * byte, and that means the Stop will have smoothly hit the ACQ FIFO with no
466  * interruptions. These commands completely finish, and the FSM goes back to
467  * Idle.
468  *
469  * The Assign Address command also passes through this state, but it's not the
470  * final state for it. It did *not* automatically accept the PEC byte, so that
471  * byte hasn't hit the ACQ FIFO yet. Instead, it is stopped here to check the
472  * PEC byte, so it may decide whether to NACK the whole transaction.
473  *
474  * Upon entering this state, the Assign Address command will have already
475  * validated the UDID when it had the last byte still pending. It would then
476  * have set the Auto ACK Counter to ACK that last UDID byte *and* the new
477  * address byte, so the ACQ FIFO should only have those two bytes in it. From
478  * here, the Assign Address command will go to the AssignAddressComplete stage
479  * or it would NACK (on a PEC failure).
480  */
481 static status_t check_arp_pec(dif_i2c_irq_state_snapshot_t irq_snapshot,
482  dif_i2c_status_t i2c_status) {
483  switch (arp_cmd_pending) {
484  case kArpCmdPrepareToArp:
485  TRY_CHECK(bitfield_bit32_read(irq_snapshot, kDifI2cIrqCmdComplete));
486  TRY_CHECK(!i2c_status.acq_fifo_empty);
487 
488  // Check that the FIFO has the expected number of bytes, the command, the
489  // PEC, and a Stop.
490  dif_i2c_level_t acq_fifo_level;
491  TRY(dif_i2c_get_fifo_levels(&i2c, NULL, NULL, NULL, &acq_fifo_level));
492  TRY_CHECK(acq_fifo_level >= 3);
493 
494  // Pop the command byte. It should match.
495  uint8_t data = 0;
496  dif_i2c_signal_t signal;
497  TRY(dif_i2c_acquire_byte(&i2c, &data, &signal));
498  TRY_CHECK(signal == kDifI2cSignalNone);
499  TRY_CHECK(data == arp_cmd_pending);
500  running_pec = calc_pec(running_pec, data);
501 
502  // The next byte is the PEC.
503  TRY(dif_i2c_acquire_byte(&i2c, &data, &signal));
504  TRY_CHECK(signal == kDifI2cSignalNone);
505  running_pec = calc_pec(running_pec, data);
506 
507  // Finally, there should be a Stop.
508  TRY(dif_i2c_acquire_byte(&i2c, &data, &signal));
509  TRY_CHECK(signal == kDifI2cSignalStop);
510 
511  TRY(dif_i2c_irq_acknowledge(&i2c, kDifI2cIrqCmdComplete));
512  arp_cmd_pending = 0;
513  state = kI2cStateIdle;
514  TRY_CHECK(running_pec == 0, "PEC failure");
515  arp_ar = false;
516  break;
517  case kArpCmdResetDevice: {
518  TRY_CHECK(bitfield_bit32_read(irq_snapshot, kDifI2cIrqCmdComplete));
519  TRY_CHECK(!i2c_status.acq_fifo_empty);
520 
521  // Check that the FIFO has the expected number of bytes, the command, the
522  // PEC, and a Stop.
523  dif_i2c_level_t acq_fifo_level;
524  TRY(dif_i2c_get_fifo_levels(&i2c, NULL, NULL, NULL, &acq_fifo_level));
525  TRY_CHECK(acq_fifo_level >= 3);
526 
527  // Pop the command byte. It should match.
528  uint8_t data = 0;
529  dif_i2c_signal_t signal;
530  TRY(dif_i2c_acquire_byte(&i2c, &data, &signal));
531  TRY_CHECK(signal == kDifI2cSignalNone);
532  TRY_CHECK(data == arp_cmd_pending);
533  running_pec = calc_pec(running_pec, data);
534 
535  // The next byte is the PEC.
536  TRY(dif_i2c_acquire_byte(&i2c, &data, &signal));
537  TRY_CHECK(signal == kDifI2cSignalNone);
538  running_pec = calc_pec(running_pec, data);
539 
540  // Finally, there should be a Stop.
541  TRY(dif_i2c_acquire_byte(&i2c, &data, &signal));
542  TRY_CHECK(signal == kDifI2cSignalStop);
543 
544  TRY(dif_i2c_irq_acknowledge(&i2c, kDifI2cIrqCmdComplete));
545  arp_cmd_pending = 0;
546  state = kI2cStateIdle;
547  TRY_CHECK(running_pec == 0, "PEC failure");
548  arp_ar = false;
549  arp_av = false;
550  } break;
551  case kArpCmdAssignAddress: {
552  // For AssignAddress, we have validated the UDID, and the last byte of the
553  // UDID and the new address should be in the ACQ FIFO. In addition, we
554  // should be stopped on the PEC's ACK pending.
555  TRY_CHECK(bitfield_bit32_read(irq_snapshot, kDifI2cIrqAcqStretch));
556  TRY_CHECK(i2c_status.ack_ctrl_stretch);
557  TRY_CHECK(!i2c_status.acq_fifo_empty);
558 
559  // Check that the FIFO has the expected number of bytes, the last byte of
560  // the UDID and the proposed address. The Target module is waiting for us
561  // to decide whether to ACK the PEC, so it's still pending.
562  dif_i2c_level_t acq_fifo_level;
563  TRY(dif_i2c_get_fifo_levels(&i2c, NULL, NULL, NULL, &acq_fifo_level));
564  TRY_CHECK(acq_fifo_level >= 2);
565 
566  // Pop the last UDID byte and drop it.
567  uint8_t data = 0;
568  dif_i2c_signal_t signal;
569  TRY(dif_i2c_acquire_byte(&i2c, &data, &signal));
570  TRY_CHECK(signal == kDifI2cSignalNone);
571  TRY_CHECK(data == kSmbusUdid[15]);
572  running_pec = calc_pec(running_pec, data);
573 
574  // The next byte is the address.
575  uint8_t new_address = 0;
576  TRY(dif_i2c_acquire_byte(&i2c, &new_address, &signal));
577  TRY_CHECK(signal == kDifI2cSignalNone);
578  running_pec = calc_pec(running_pec, new_address);
579 
580  // Next would be the pending PEC.
581  TRY(dif_i2c_get_pending_acq_byte(&i2c, &data));
582  TRY_CHECK(running_pec == data, "PEC failure");
583 
584  i2c_id.address = new_address >> 1;
585  TRY(dif_i2c_set_device_id(&i2c, &kSmbusArpId, &i2c_id));
586  arp_ar = true;
587  arp_av = true;
588  state = kI2cStateAssignAddressComplete;
589  TRY(dif_i2c_set_auto_ack_count(&i2c, 1));
590  // arp_cmd_pending will be zeroed out in the finish state
591  } break;
592  default:
593  TRY_CHECK(false, "Found unexpected arp_cmd_pending 0x%x",
594  arp_cmd_pending);
595  break;
596  }
597  return OK_STATUS();
598 }
599 
600 /**
601  * This function prepares the UDID response to be transmitted from the Target
602  * on a Get UDID command. We will have reached this state after decoding the
603  * command in process_command(), and the ACQ FIFO will have that byte inside.
604  *
605  * However, the CmdComplete interrupt doesn't coincide with the Restart byte
606  * hitting the ACQ FIFO, so if we only have the CmdComplete interrupt and are
607  * not stretching on the TX FIFO being empty, we only clear that interrupt and
608  * remove the last byte of the Write command that completed.
609  *
610  * Once the Target module is stretching on the TX FIFO, we make sure the next
611  * ACQ FIFO entry is a Restart that still targets this function, then proceed
612  * to fill the TX FIFO with the data to be returned on the Read.
613  *
614  * The next state awaits the completion of the Read command, which should be via
615  * a Stop.
616  */
617 static status_t prepare_udid_reply(dif_i2c_irq_state_snapshot_t irq_snapshot,
618  dif_i2c_status_t i2c_status) {
619  TRY_CHECK(arp_cmd_pending == kArpCmdGetUdid);
620 
621  bool cmd_complete = bitfield_bit32_read(irq_snapshot, kDifI2cIrqCmdComplete);
622  bool tx_stretch = bitfield_bit32_read(irq_snapshot, kDifI2cIrqTxStretch);
623  if (cmd_complete) {
624  // Should see the command byte still there.
625  TRY_CHECK(!i2c_status.acq_fifo_empty);
626 
627  uint8_t data = 0;
628  dif_i2c_signal_t signal;
629  TRY(dif_i2c_acquire_byte(&i2c, &data, &signal));
630  TRY_CHECK(signal == kDifI2cSignalNone);
631  TRY_CHECK((data == ((i2c_id.address << 1) | 1)) ||
632  (data == kArpCmdGetUdid));
633  TRY(dif_i2c_irq_acknowledge(&i2c, kDifI2cIrqCmdComplete));
634 
635  if (!tx_stretch) {
636  // Come back when we've reached the stretch. "Command complete" will
637  // arrive before the FIFO has prepared the new command for the read.
638  return OK_STATUS();
639  }
640  }
641  TRY_CHECK(tx_stretch);
642  TRY_CHECK(i2c_status.tx_fifo_empty);
643 
644  // Clear the TX pending bit.
645  dif_i2c_target_tx_halt_events_t events = {0};
646  TRY(dif_i2c_get_target_tx_halt_events(&i2c, &events));
647  TRY_CHECK(events.tx_pending);
648  TRY_CHECK(!events.bus_timeout);
649  TRY(dif_i2c_clear_target_tx_halt_events(&i2c, events));
650 
651  // Should see a Restart with the read to the ARP default address here.
652  uint8_t data = 0;
653  dif_i2c_signal_t signal;
654  TRY(dif_i2c_acquire_byte(&i2c, &data, &signal));
655  TRY_CHECK(signal == kDifI2cSignalRepeat);
656  TRY_CHECK(data == ((kSmbusArpId.address << 1) | 1));
657 
658  // First is the byte count.
659  TRY(dif_i2c_transmit_byte(&i2c, sizeof(kSmbusUdid) + 1));
660  uint8_t pec = calc_pec(0, sizeof(kSmbusUdid) + 1);
661 
662  // Next, transmit the UDID.
663  for (size_t i = 0; i < sizeof(kSmbusUdid); ++i) {
664  TRY(dif_i2c_transmit_byte(&i2c, kSmbusUdid[i]));
665  pec = calc_pec(pec, kSmbusUdid[i]);
666  }
667 
668  // Transmit the current address, if any.
669  uint8_t current_address = 0xff;
670  if (arp_av) {
671  current_address = (uint8_t)((i2c_id.address << 1) | 1);
672  }
673  TRY(dif_i2c_transmit_byte(&i2c, current_address));
674  pec = calc_pec(pec, current_address);
675 
676  // Then, transmit the PEC.
677  TRY(dif_i2c_transmit_byte(&i2c, pec));
678  state = kI2cStateArpGetUdidTransmit;
679  return OK_STATUS();
680 }
681 
682 /**
683  * This state completes the Get UDID command. It expects to get the CmdComplete
684  * interrupt and an accompanying Stop. Afterwards, the FSM proceeds to Idle.
685  */
686 static status_t complete_get_udid(dif_i2c_irq_state_snapshot_t irq_snapshot,
687  dif_i2c_status_t i2c_status) {
688  TRY_CHECK(arp_cmd_pending == kArpCmdGetUdid);
689  TRY_CHECK(bitfield_bit32_read(irq_snapshot, kDifI2cIrqCmdComplete));
690  TRY_CHECK(!i2c_status.acq_fifo_empty);
691 
692  uint8_t data = 0;
693  dif_i2c_signal_t signal;
694  // There should only be a Stop next.
695  TRY(dif_i2c_acquire_byte(&i2c, &data, &signal));
696  TRY_CHECK(signal == kDifI2cSignalStop);
697 
698  // Make a superfluous check for lost arbitration. If arbitration were lost,
699  // the ACQ FIFO would have kDifI2cSignalNackStop instead.
700  dif_i2c_target_tx_halt_events_t events = {0};
701  TRY(dif_i2c_get_target_tx_halt_events(&i2c, &events));
702  TRY_CHECK(!events.tx_pending);
703  TRY_CHECK(!events.bus_timeout);
704  TRY_CHECK(!events.arbitration_lost);
705 
706  // Return to idle.
707  TRY(dif_i2c_irq_acknowledge(&i2c, kDifI2cIrqCmdComplete));
708  arp_cmd_pending = 0;
709  state = kI2cStateIdle;
710  return OK_STATUS();
711 }
712 
713 /**
714  * This state is the next stop for Assign Address after command dispatch. We
715  * will have set the Auto ACK Counter to ACK all bytes up to, but not including,
716  * the last UDID byte. The Target module will be stretching on the ACK phase,
717  * waiting for software to decide whether to ACK or NACK.
718  *
719  * We check the UDID and only ACK if all data matches the expectation. The last
720  * byte of the UDID is in the pending area, not the ACQ FIFO. If everything
721  * matches, we proceed to ACK the last UDID byte and the address assignment,
722  * and the Target module will stop on the PEC byte. The next state is the PEC
723  * check.
724  */
725 static status_t check_received_udid(dif_i2c_irq_state_snapshot_t irq_snapshot,
726  dif_i2c_status_t i2c_status) {
727  TRY_CHECK(arp_cmd_pending == kArpCmdAssignAddress);
728  TRY_CHECK(bitfield_bit32_read(irq_snapshot, kDifI2cIrqAcqStretch));
729  TRY_CHECK(!i2c_status.acq_fifo_empty);
730 
731  // Check that the FIFO has the expected number of bytes, the command, the
732  // byte count, and 15 of 16 UDID bytes.
733  dif_i2c_level_t acq_fifo_level;
734  TRY(dif_i2c_get_fifo_levels(&i2c, NULL, NULL, NULL, &acq_fifo_level));
735  TRY_CHECK(acq_fifo_level >= 17);
736 
737  uint8_t data = 0;
738  dif_i2c_signal_t signal;
739  // First is the command.
740  TRY(dif_i2c_acquire_byte(&i2c, &data, &signal));
741  TRY_CHECK(signal == kDifI2cSignalNone);
742  TRY_CHECK(data == arp_cmd_pending);
743  running_pec = calc_pec(running_pec, data);
744 
745  // Next is the byte count.
746  TRY(dif_i2c_acquire_byte(&i2c, &data, &signal));
747  TRY_CHECK(signal == kDifI2cSignalNone);
748  TRY_CHECK(data == 17);
749  running_pec = calc_pec(running_pec, data);
750 
751  // Then 15 bytes of the UDID.
752  bool udid_match = true;
753  for (size_t i = 0; i < 15; ++i) {
754  TRY(dif_i2c_acquire_byte(&i2c, &data, &signal));
755  TRY_CHECK(signal == kDifI2cSignalNone);
756  if (data != kSmbusUdid[i]) {
757  udid_match = false;
758  }
759  running_pec = calc_pec(running_pec, data);
760  }
761 
762  // Then the last byte of the UDID is currently pending.
763  TRY(dif_i2c_get_pending_acq_byte(&i2c, &data));
764  if (data != kSmbusUdid[15]) {
765  udid_match = false;
766  }
767  if (udid_match) {
768  // Advance to the PEC byte if the UDID matches. ACK both the last UDID byte
769  // and the address, then hold at the PEC byte before committing the address.
770  state = kI2cStateArpPec;
771  TRY(dif_i2c_set_auto_ack_count(&i2c, 2));
772  } else {
773  // NACK if the UDID doesn't match.
774  state = kI2cStateTransactionNack;
775  TRY(dif_i2c_nack_transaction(&i2c));
776  LOG_INFO("AssignAddress: UDID mismatch");
777  }
778  return OK_STATUS();
779 }
780 
781 /**
782  * This is the final state for the Assign Address command.
783  *
784  * Because we hadn't ACK'd the PEC until the PEC Check state, the ACQ FIFO
785  * should have both the PEC data byte and the Stop here. The next state is Idle.
786  */
787 static status_t finish_assign_addr(dif_i2c_irq_state_snapshot_t irq_snapshot,
788  dif_i2c_status_t i2c_status) {
789  TRY_CHECK(bitfield_bit32_read(irq_snapshot, kDifI2cIrqCmdComplete));
790  TRY_CHECK(!i2c_status.acq_fifo_empty);
791 
792  uint8_t data = 0;
793  dif_i2c_signal_t signal;
794  // Pull out the PEC first. No need to validate it again.
795  TRY(dif_i2c_acquire_byte(&i2c, &data, &signal));
796  TRY_CHECK(signal == kDifI2cSignalNone);
797  // We only expect a Stop next.
798  TRY(dif_i2c_acquire_byte(&i2c, &data, &signal));
799  TRY_CHECK(signal == kDifI2cSignalStop);
800 
801  TRY(dif_i2c_irq_acknowledge(&i2c, kDifI2cIrqCmdComplete));
802  arp_cmd_pending = 0;
803  state = kI2cStateIdle;
804  LOG_INFO("New i2c address assigned: 0x%x", i2c_id.address);
805 
806  return OK_STATUS();
807 }
808 
809 /**
810  * This state handles all NACKs and drains the ACQ FIFO until we see the end of
811  * the transaction, a NackStop signal. It makes use of the ACQ FIFO watermark to
812  * get further interrupts if we don't see the NackStop the first time.
813  */
814 static status_t finish_nack(dif_i2c_irq_state_snapshot_t irq_snapshot,
815  dif_i2c_status_t i2c_status) {
816  bool saw_stop = false;
817  if (bitfield_bit32_read(irq_snapshot, kDifI2cIrqCmdComplete)) {
818  TRY(dif_i2c_irq_acknowledge(&i2c, kDifI2cIrqCmdComplete));
819  }
820 
821  if (!i2c_status.acq_fifo_empty) {
822  dif_i2c_level_t acq_fifo_level;
823  TRY(dif_i2c_get_fifo_levels(&i2c, NULL, NULL, NULL, &acq_fifo_level));
824 
825  for (size_t i = 0; i < acq_fifo_level; ++i) {
826  uint8_t data = 0;
827  dif_i2c_signal_t signal;
828  TRY(dif_i2c_acquire_byte(&i2c, &data, &signal));
829  if (signal == kDifI2cSignalNackStop) {
830  saw_stop = true;
831  break;
832  }
833  }
834  }
835  if (!saw_stop) {
836  // Set the threshold interrupt so we return here.
837  TRY(dif_i2c_set_target_watermarks(&i2c, /*tx_level=*/0, /*acq_level=*/0));
838  } else {
839  // Set the threshold interrupt back to inert.
840  TRY(dif_i2c_set_target_watermarks(&i2c, /*tx_level=*/0,
841  I2C_PARAM_ACQ_FIFO_DEPTH));
842 
843  // Done with the command.
844  arp_cmd_pending = 0;
845  state = kI2cStateIdle;
846  }
847 
848  return OK_STATUS();
849 }
850 
851 /**
852  * This function handles dispatch between the Write Message and Read Message
853  * commands. For Write Message, we'll see another data byte and stretching on
854  * the ACQ FIFO. For Read Message, we'll see the CmdComplete interrupt, but we
855  * won't necessarily see the possibly late-arriving address byte in the ACQ
856  * FIFO.
857  *
858  * A Write Message cause a state transition to MessageReceive, and the Auto ACK
859  * Counter will be set to receive all data bytes.
860  *
861  * A Read Message causes a state transition to MessageTransmit, and no further
862  * action is taken in this state. We expect to get a TX FIFO stretch interrupt
863  * that activates the next state's handler.
864  */
865 static status_t message_cmd_dispatch(dif_i2c_irq_state_snapshot_t irq_snapshot,
866  dif_i2c_status_t i2c_status) {
867  bool acq_stretch = bitfield_bit32_read(irq_snapshot, kDifI2cIrqAcqStretch);
868  bool cmd_complete = bitfield_bit32_read(irq_snapshot, kDifI2cIrqCmdComplete);
869  const uint8_t message_addr = (uint8_t)kMessageAddr;
870 
871  // The command byte should at least still be in the FIFO.
872  TRY_CHECK(!i2c_status.acq_fifo_empty);
873 
874  uint8_t data = 0;
875  dif_i2c_signal_t signal;
876  TRY(dif_i2c_acquire_byte(&i2c, &data, &signal));
877  TRY_CHECK(signal == kDifI2cSignalNone);
878  TRY_CHECK(data == message_addr);
879 
880  if (acq_stretch && !cmd_complete) {
881  // This is a write command. ACK the bytes and let them in.
882  state = kI2cStateMessageReceive;
883  TRY(dif_i2c_set_auto_ack_count(&i2c, sizeof(message)));
884  } else if (cmd_complete) {
885  // A read should be coming, but don't process it here. There may be a delay
886  // between the "command complete" IRQ and the push of the Repeated Start to
887  // the ACQ FIFO. Assume it hasn't arrived yet, and process the Read in the
888  // next state.
889  TRY(dif_i2c_irq_acknowledge(&i2c, kDifI2cIrqCmdComplete));
890  state = kI2cStateMessageTransmit;
891  } else {
892  TRY_CHECK(false, "Unknown state of message command");
893  }
894 
895  return OK_STATUS();
896 }
897 
898 /**
899  * This function handles the data of the Message Receive command. Because we set
900  * up the Auto ACK Counter to ACK all data bytes, we expect to see even the Stop
901  * in the ACQ FIFO in this state. We write the Message register with all the
902  * received data.
903  */
904 static status_t message_receive(dif_i2c_irq_state_snapshot_t irq_snapshot,
905  dif_i2c_status_t i2c_status) {
906  TRY_CHECK(!bitfield_bit32_read(irq_snapshot, kDifI2cIrqAcqStretch));
907  TRY_CHECK(bitfield_bit32_read(irq_snapshot, kDifI2cIrqCmdComplete));
908  TRY_CHECK(!i2c_status.acq_fifo_empty);
909 
910  // Check that the FIFO has the expected number of bytes, all 32 bytes of the
911  // message, plus the STOP.
912  dif_i2c_level_t acq_fifo_level;
913  TRY(dif_i2c_get_fifo_levels(&i2c, NULL, NULL, NULL, &acq_fifo_level));
914  TRY_CHECK(acq_fifo_level >= sizeof(message) + 1);
915 
916  uint8_t data = 0;
917  dif_i2c_signal_t signal;
918  for (size_t i = 0; i < sizeof(message); ++i) {
919  TRY(dif_i2c_acquire_byte(&i2c, &data, &signal));
920  TRY_CHECK(signal == kDifI2cSignalNone);
921  message[i] = data;
922  }
923 
924  // Then the Stop finishes the command.
925  TRY(dif_i2c_acquire_byte(&i2c, &data, &signal));
926  TRY_CHECK(signal == kDifI2cSignalStop);
927  TRY(dif_i2c_irq_acknowledge(&i2c, kDifI2cIrqCmdComplete));
928  state = kI2cStateIdle;
929 
930  return OK_STATUS();
931 }
932 
933 /**
934  * This state handles preparing the TX FIFO for a Read Message command.
935  */
936 static status_t message_transmit(dif_i2c_irq_state_snapshot_t irq_snapshot,
937  dif_i2c_status_t i2c_status) {
938  TRY_CHECK(bitfield_bit32_read(irq_snapshot, kDifI2cIrqTxStretch));
939  TRY_CHECK(i2c_status.tx_fifo_empty);
940  // Should see the address byte still there.
941  TRY_CHECK(!i2c_status.acq_fifo_empty);
942 
943  uint8_t data = 0;
944  dif_i2c_signal_t signal;
945  TRY(dif_i2c_acquire_byte(&i2c, &data, &signal));
946  TRY_CHECK(signal == kDifI2cSignalRepeat);
947  TRY_CHECK(data == ((i2c_id.address << 1) | 1));
948 
949  // Clear the TX pending bit.
950  dif_i2c_target_tx_halt_events_t events = {0};
951  TRY(dif_i2c_get_target_tx_halt_events(&i2c, &events));
952  TRY_CHECK(events.tx_pending);
953  TRY_CHECK(!events.bus_timeout);
954  TRY(dif_i2c_clear_target_tx_halt_events(&i2c, events));
955 
956  // Prepare the TX FIFO.
957  for (size_t i = 0; i < sizeof(message); ++i) {
958  TRY(dif_i2c_transmit_byte(&i2c, message[i]));
959  }
960 
961  state = kI2cStateMessageFinish;
962  return OK_STATUS();
963 }
964 
965 /**
966  * This state completes the Read Message command. It drains the Stop from the
967  * ACQ FIFO and clears the CmdComplete interrupt.
968  */
969 static status_t message_finish(dif_i2c_irq_state_snapshot_t irq_snapshot,
970  dif_i2c_status_t i2c_status) {
971  TRY_CHECK(bitfield_bit32_read(irq_snapshot, kDifI2cIrqCmdComplete));
972  TRY_CHECK(!i2c_status.acq_fifo_empty);
973 
974  // Expecting only the STOP.
975  uint8_t data = 0;
976  dif_i2c_signal_t signal;
977  TRY(dif_i2c_acquire_byte(&i2c, &data, &signal));
978  TRY_CHECK(signal == kDifI2cSignalStop);
979 
980  TRY(dif_i2c_irq_acknowledge(&i2c, kDifI2cIrqCmdComplete));
981  state = kI2cStateIdle;
982  return OK_STATUS();
983 }
984 
985 static status_t smbus_arp_test(void) {
986  bool message_received = false;
987  state = kI2cStateIdle;
988  test_status_set(kTestStatusInWfi);
989  while (!message_received) {
990  ATOMIC_WAIT_FOR_INTERRUPT(i2c_event == true);
991  i2c_event = false;
992 
993  dif_i2c_irq_state_snapshot_t irq_snapshot = {0};
994  CHECK_DIF_OK(dif_i2c_irq_get_state(&i2c, &irq_snapshot));
995 
996  dif_i2c_status_t i2c_status = {0};
997  CHECK_DIF_OK(dif_i2c_get_status(&i2c, &i2c_status));
998 
999  switch (state) {
1000  case kI2cStateIdle:
1001  TRY(process_new_command(irq_snapshot, i2c_status));
1002  break;
1003  case kI2cStateArpPec:
1004  TRY(check_arp_pec(irq_snapshot, i2c_status));
1005  break;
1006  case kI2cStateArpGetUdidWait:
1007  TRY(prepare_udid_reply(irq_snapshot, i2c_status));
1008  break;
1009  case kI2cStateArpGetUdidTransmit:
1010  TRY(complete_get_udid(irq_snapshot, i2c_status));
1011  break;
1012  case kI2cStateArpCheckUdid:
1013  TRY(check_received_udid(irq_snapshot, i2c_status));
1014  break;
1015  case kI2cStateMessageWait:
1016  TRY(message_cmd_dispatch(irq_snapshot, i2c_status));
1017  break;
1018  case kI2cStateMessageReceive:
1019  TRY(message_receive(irq_snapshot, i2c_status));
1020  break;
1021  case kI2cStateMessageTransmit:
1022  TRY(message_transmit(irq_snapshot, i2c_status));
1023  break;
1024  case kI2cStateMessageFinish:
1025  TRY(message_finish(irq_snapshot, i2c_status));
1026  message_received = true;
1027  break;
1028  case kI2cStateAssignAddressComplete:
1029  TRY(finish_assign_addr(irq_snapshot, i2c_status));
1030  break;
1031  case kI2cStateTransactionNack:
1032  TRY(finish_nack(irq_snapshot, i2c_status));
1033  break;
1034  default:
1035  TRY_CHECK(false, "Reached invalid state %d", state);
1036  }
1037 
1038  dif_i2c_irq_enable_snapshot_t enables = i2c_irq_enables;
1039  CHECK_DIF_OK(dif_i2c_irq_restore_all(&i2c, &enables));
1040  }
1041  return OK_STATUS();
1042 }
1043 
1044 bool test_main(void) {
1045  CHECK_STATUS_OK(test_init());
1046  status_t result = OK_STATUS();
1047  EXECUTE_TEST(result, smbus_arp_test);
1048  return status_ok(result);
1049 }