Software APIs
i2c_host_irq_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 #include <assert.h>
5 
13 #include "sw/device/lib/runtime/irq.h"
16 #include "sw/device/lib/testing/i2c_testutils.h"
17 #include "sw/device/lib/testing/rv_core_ibex_testutils.h"
18 #include "sw/device/lib/testing/rv_plic_testutils.h"
19 #include "sw/device/lib/testing/test_framework/check.h"
21 
23 #include "i2c_regs.h" // Generated.
24 
25 static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__,
26  "This test assumes the target platform is little endian.");
27 
28 OTTF_DEFINE_TEST_CONFIG();
29 
30 /**
31  * This test uses an EEPROM device on the BoB to test the host IRQs.
32  * The EEPROM was chosen because it easily allow to test the nak irq, since
33  * every attempt to read an address will return nak as a way to signal it is
34  * busy.
35  */
36 enum {
38  kIrqVoid = UINT32_MAX,
39  kDeviceAddr = 0x52,
40 
41  // Default timeout for i2c reads.
42  kDefaultTimeoutMicros = 5000,
43 };
44 
45 static dif_rv_core_ibex_t rv_core_ibex;
46 static dif_pinmux_t pinmux;
47 static dif_i2c_t i2c;
48 static dif_rv_plic_t plic;
49 
50 // Hold the test result.
51 static volatile status_t isr_result;
52 // Used to sync the irs and the main thread.
53 static volatile dif_i2c_irq_t irq_fired;
54 
55 /**
56  * Provides external IRQ handling for this test.
57  *
58  * This function overrides the default OTTF external ISR.
59  *
60  * For each IRQ, it performs the following:
61  * 1. Claims the IRQ that fired (finds PLIC IRQ index).
62  * 2. Checks that the index belongs to the expected peripheral.
63  * 3. Checks that only the correct / expected IRQ is triggered.
64  * 4. Clears or disables the IRQ at the peripheral.
65  * 5. Completes the IRQ service at PLIC.
66  */
67 static status_t external_isr(void) {
68  dif_rv_plic_irq_id_t plic_irq_id;
69  TRY(dif_rv_plic_irq_claim(&plic, kHart, &plic_irq_id));
70 
73  TRY_CHECK(peripheral == kTopEarlgreyPlicPeripheralI2c2,
74  "IRQ from incorrect peripheral: exp = %d(i2c2), found = %d",
75  kTopEarlgreyPlicPeripheralI2c2, peripheral);
76 
77  irq_fired =
78  (dif_i2c_irq_t)(plic_irq_id - (dif_rv_plic_irq_id_t)
80 
81  LOG_INFO("%s: plic:%d, i2c:%d", __func__, plic_irq_id, irq_fired);
82 
83  // Clear or Disable the interrupt as appropriate.
85  TRY(dif_i2c_irq_get_type(&i2c, irq_fired, &irq_type));
86 
87  if (irq_type == kDifIrqTypeEvent) {
88  TRY(dif_i2c_irq_acknowledge(&i2c, irq_fired));
89  } else {
90  TRY(dif_i2c_irq_set_enabled(&i2c, irq_fired, kDifToggleDisabled));
91  }
92 
93  // Complete the IRQ at PLIC.
94  TRY(dif_rv_plic_irq_complete(&plic, kHart, plic_irq_id));
95  return OK_STATUS();
96 }
97 
98 void ottf_external_isr(uint32_t *exc_info) {
99  status_t tmp = external_isr();
100  if (status_ok(isr_result)) {
101  isr_result = tmp;
102  }
103 }
104 
105 static status_t write_byte(const uint8_t addr[2], uint8_t byte) {
106  uint8_t data[3] = {addr[0], addr[1], byte};
107  return i2c_testutils_write(&i2c, kDeviceAddr, sizeof(data), data, false);
108 }
109 
110 static status_t nak_irq(void) {
111  // Clean any previous state.
112  dif_i2c_controller_halt_events_t halt_events = {0};
113  TRY(dif_i2c_get_controller_halt_events(&i2c, &halt_events));
114  TRY(dif_i2c_clear_controller_halt_events(&i2c, halt_events));
115  TRY(dif_i2c_irq_set_enabled(&i2c, kDifI2cIrqControllerHalt,
117 
118  // Write a byte to some random address.
119  const uint8_t kAddr[2] = {0x03, 0x21};
120  TRY(write_byte(kAddr, 0xAB));
121 
122  irq_global_ctrl(false);
123  irq_fired = kIrqVoid;
124  irq_global_ctrl(true);
125 
126  dif_i2c_fmt_flags_t flags = {.start = true,
127  .stop = false,
128  .read = false,
129  .read_cont = false,
130  .suppress_nak_irq = false};
131  // Address the device to read, which should return a NACK as it needs more
132  // time to be read.
133  TRY(dif_i2c_write_byte_raw(&i2c, kDeviceAddr << 1 | 0x01, flags));
134  ATOMIC_WAIT_FOR_INTERRUPT(irq_fired == kDifI2cIrqControllerHalt);
135 
136  TRY(dif_i2c_irq_set_enabled(&i2c, kDifI2cIrqControllerHalt,
138  TRY(dif_i2c_get_controller_halt_events(&i2c, &halt_events));
139  CHECK(halt_events.nack_received == true);
140  CHECK(halt_events.unhandled_nack_timeout == false);
141  TRY(dif_i2c_reset_fmt_fifo(&i2c));
142  TRY(dif_i2c_clear_controller_halt_events(&i2c, halt_events));
143  // Force Stop to be sent after the unexpected NACK.
146  return OK_STATUS();
147 }
148 
149 static status_t nak_irq_disabled(void) {
150  // Clean any previous state.
151  dif_i2c_controller_halt_events_t halt_events = {0};
152  TRY(dif_i2c_get_controller_halt_events(&i2c, &halt_events));
153  TRY(dif_i2c_clear_controller_halt_events(&i2c, halt_events));
154  TRY(dif_i2c_irq_set_enabled(&i2c, kDifI2cIrqControllerHalt,
156 
157  // Write a byte to some random address to be read.
158  const uint8_t kAddr[2] = {0x03, 0x21};
159  TRY(write_byte(kAddr, 0xAB));
160 
161  irq_global_ctrl(false);
162  irq_fired = kIrqVoid;
163  irq_global_ctrl(true);
164 
165  dif_i2c_fmt_flags_t flags = {.start = true,
166  .stop = false,
167  .read = false,
168  .read_cont = false,
169  .suppress_nak_irq = true};
170 
171  // Address the device to read, which should return a NACK as it needs more
172  // time to be read.
173  TRY(dif_i2c_write_byte_raw(&i2c, kDeviceAddr << 1 | 0x01, flags));
174 
175  TRY(i2c_testutils_wait_transaction_finish(&i2c));
176  TRY_CHECK(irq_fired != kDifI2cIrqControllerHalt, "Unexpected IRQ %u",
177  irq_fired);
178 
179  TRY(dif_i2c_irq_set_enabled(&i2c, kDifI2cIrqControllerHalt,
181  return OK_STATUS();
182 }
183 
184 static status_t cmd_complete_irq(void) {
185  // Clean any previous state.
186  TRY(dif_i2c_irq_acknowledge(&i2c, kDifI2cIrqCmdComplete));
187  TRY(dif_i2c_irq_set_enabled(&i2c, kDifI2cIrqCmdComplete, kDifToggleEnabled));
188 
189  irq_global_ctrl(false);
190  irq_fired = kIrqVoid;
191  irq_global_ctrl(true);
192 
193  // Write a byte to some random address.
194  const uint8_t kAddr[2] = {0x03, 0x21};
195  TRY(write_byte(kAddr, 0xAB));
196 
197  ATOMIC_WAIT_FOR_INTERRUPT(irq_fired == kDifI2cIrqCmdComplete);
198 
199  TRY(dif_i2c_irq_set_enabled(&i2c, kDifI2cIrqCmdComplete, kDifToggleDisabled));
200  return OK_STATUS();
201 }
202 
203 static status_t fmt_threshold_irq(void) {
204  // When the FmtThreshold interrupt fires depends upon whether it's an Event
205  // type (initial design) or a Status type (later versions).
206  dif_irq_type_t irq_type = kDifIrqTypeEvent;
207  TRY(dif_i2c_irq_get_type(&i2c, irq_fired, &irq_type));
208 
209  // Clean any previous state.
210  if (irq_type == kDifIrqTypeEvent) {
211  TRY(dif_i2c_irq_acknowledge(&i2c, kDifI2cIrqFmtThreshold));
212  } else {
213  TRY(dif_i2c_irq_set_enabled(&i2c, kDifI2cIrqFmtThreshold,
215  }
216  TRY(dif_i2c_set_host_watermarks(&i2c, /*rx_level=*/29u, /*fmt_level=*/5u));
217 
218  irq_global_ctrl(false);
219  irq_fired = kIrqVoid;
220  irq_global_ctrl(true);
221 
222  if (irq_type == kDifIrqTypeEvent) {
223  TRY(dif_i2c_irq_set_enabled(&i2c, kDifI2cIrqFmtThreshold,
225  }
226 
227  const uint8_t kAddr[2] = {0x03, 0x21};
228  // Put five transactions into the FIFO and expect an IRQ when the FMT FIFO
229  // level drops to four.
230  for (size_t i = 0; i < 5; ++i) {
231  TRY(write_byte(kAddr, 0xAB));
232  }
233  // Enable the Status-type interrupt immediately after presenting the data.
234  if (irq_type == kDifIrqTypeStatus) {
235  TRY(dif_i2c_irq_set_enabled(&i2c, kDifI2cIrqFmtThreshold,
237  }
238 
239  // Status and Event types will both fire when the FMT FIFO level drops below 5
240  // entries.
241  ATOMIC_WAIT_FOR_INTERRUPT(irq_fired == kDifI2cIrqFmtThreshold);
242 
243  TRY(dif_i2c_irq_set_enabled(&i2c, kDifI2cIrqFmtThreshold,
245  return OK_STATUS();
246 }
247 
248 static status_t rx_threshold_irq(void) {
249  // Clean any previous state.
250  TRY(dif_i2c_irq_acknowledge(&i2c, kDifI2cIrqRxThreshold));
251  TRY(dif_i2c_irq_set_enabled(&i2c, kDifI2cIrqRxThreshold, kDifToggleEnabled));
252  TRY(dif_i2c_set_host_watermarks(&i2c, /*rx_level=*/7u, /*fmt_level=*/5u));
253 
254  irq_global_ctrl(false);
255  irq_fired = kIrqVoid;
256  irq_global_ctrl(true);
257 
258  uint8_t bytes[16];
259  const uint8_t kAddr[2] = {0x03, 0x21};
260  TRY(i2c_testutils_write(&i2c, kDeviceAddr, 2, kAddr, true));
261  // Try to read more than the watermark to trigger the IRQ.
262  while (TRY(i2c_testutils_issue_read(&i2c, kDeviceAddr, sizeof(bytes))))
263  ;
264  TRY(dif_i2c_reset_rx_fifo(&i2c));
265 
266  ATOMIC_WAIT_FOR_INTERRUPT(irq_fired == kDifI2cIrqRxThreshold);
267 
268  TRY(dif_i2c_irq_set_enabled(&i2c, kDifI2cIrqRxThreshold, kDifToggleDisabled));
269  return OK_STATUS();
270 }
271 
272 static status_t rx_overflow_irq(void) {
273  // Clean any previous state.
274  TRY(dif_i2c_irq_acknowledge(&i2c, kDifI2cIrqRxOverflow));
275  TRY(dif_i2c_irq_set_enabled(&i2c, kDifI2cIrqRxOverflow, kDifToggleEnabled));
276 
277  irq_global_ctrl(false);
278  irq_fired = kIrqVoid;
279  irq_global_ctrl(true);
280 
281  const uint8_t kAddr[2] = {0x03, 0x21};
282  uint8_t bytes[I2C_PARAM_FIFO_DEPTH + 1];
283  TRY(i2c_testutils_write(&i2c, kDeviceAddr, 2, kAddr, true));
284  // Try to read more than the fifo depth to trigger the IRQ.
285  TRY(i2c_testutils_issue_read(&i2c, kDeviceAddr, sizeof(bytes)));
286  TRY(dif_i2c_reset_rx_fifo(&i2c));
287 
288  ATOMIC_WAIT_FOR_INTERRUPT(irq_fired == kDifI2cIrqRxOverflow);
289 
290  TRY(dif_i2c_irq_set_enabled(&i2c, kDifI2cIrqRxOverflow, kDifToggleDisabled));
291  return OK_STATUS();
292 }
293 
294 static status_t test_init(void) {
295  mmio_region_t base_addr =
297 
298  TRY(dif_rv_core_ibex_init(base_addr, &rv_core_ibex));
299 
301  TRY(dif_i2c_init(base_addr, &i2c));
302 
304  TRY(dif_pinmux_init(base_addr, &pinmux));
305 
306  TRY(i2c_testutils_select_pinmux(&pinmux, 2, I2cPinmuxPlatformIdCw310Pmod));
307 
309 
311  TRY(dif_rv_plic_init(base_addr, &plic));
312 
313  rv_plic_testutils_irq_range_enable(&plic, kHart,
316 
317  // Enable the external IRQ at Ibex.
318  irq_global_ctrl(true);
319  irq_external_ctrl(true);
320 
321  return OK_STATUS();
322 }
323 
324 bool test_main(void) {
325  status_t test_result;
326  CHECK_STATUS_OK(test_init());
327 
328  test_result = OK_STATUS();
329  CHECK_STATUS_OK(i2c_testutils_set_speed(&i2c, kDifI2cSpeedStandard));
330  EXECUTE_TEST(test_result, nak_irq);
331  EXECUTE_TEST(test_result, nak_irq_disabled);
332  EXECUTE_TEST(test_result, cmd_complete_irq);
333  EXECUTE_TEST(test_result, fmt_threshold_irq);
334  EXECUTE_TEST(test_result, rx_threshold_irq);
335  EXECUTE_TEST(test_result, rx_overflow_irq);
336 
337  return status_ok(test_result);
338 }