Software APIs
i2c_host_tx_rx_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 
12 #include "sw/device/lib/runtime/irq.h"
14 #include "sw/device/lib/testing/i2c_testutils.h"
15 #include "sw/device/lib/testing/rand_testutils.h"
16 #include "sw/device/lib/testing/test_framework/check.h"
18 #include "sw/device/lib/testing/test_framework/status.h"
19 
21 #include "sw/device/lib/testing/autogen/isr_testutils.h"
22 
23 // TODO, remove it once pinout configuration is provided
24 #include "pinmux_regs.h"
25 
26 static dif_i2c_t i2c;
27 static dif_pinmux_t pinmux;
28 static dif_rv_plic_t plic;
29 
30 OTTF_DEFINE_TEST_CONFIG();
31 
32 /**
33  * This symbol is meant to be backdoor loaded by the testbench.
34  * The testbench will inform the test the rough speed of the clock
35  * used by the I2C modules.
36  */
37 static volatile const uint8_t kClockPeriodNanos = 0;
38 static volatile const uint8_t kI2cRiseFallNanos = 0;
39 static volatile const uint32_t kI2cClockPeriodNanos = 0;
40 static volatile const uint8_t kI2cCdcInstrumentationEnabled = 0;
41 
42 /**
43  * This symbol is meant to be backdoor loaded by the testbench.
44  * to indicate which I2c is actually under test. It is not used
45  * at the moment, will connect it later.
46  */
47 static volatile const uint8_t kI2cIdx = 0;
48 
49 /**
50  * Provides external irq handling for this test.
51  *
52  * This function overrides the default OTTF external ISR.
53  */
54 static volatile bool fmt_irq_seen = false;
55 static volatile bool rx_irq_seen = false;
56 static volatile bool done_irq_seen = false;
57 /**
58  * these variables store values based on kI2cIdx
59  */
60 static uint32_t i2c_irq_fmt_threshold_id;
61 static uint32_t i2c_base_addr;
62 static top_earlgrey_plic_irq_id_t plic_irqs[8];
63 
64 void ottf_external_isr(uint32_t *exc_info) {
65  plic_isr_ctx_t plic_ctx = {.rv_plic = &plic,
66  .hart_id = kTopEarlgreyPlicTargetIbex0};
67 
68  i2c_isr_ctx_t i2c_ctx = {.i2c = &i2c,
69  .plic_i2c_start_irq_id = i2c_irq_fmt_threshold_id,
70  .expected_irq = 0,
71  .is_only_irq = false};
72 
74  dif_i2c_irq_t i2c_irq;
75  isr_testutils_i2c_isr(plic_ctx, i2c_ctx, false, &peripheral, &i2c_irq);
76 
77  bool disable = false;
78  switch (i2c_irq) {
79  case kDifI2cIrqFmtThreshold:
80  fmt_irq_seen = true;
81  i2c_irq = kDifI2cIrqFmtThreshold;
82  disable = true;
83  break;
84  case kDifI2cIrqRxThreshold:
85  rx_irq_seen = true;
86  i2c_irq = kDifI2cIrqRxThreshold;
87  disable = true;
88  break;
89  case kDifI2cIrqCmdComplete:
90  done_irq_seen = true;
91  i2c_irq = kDifI2cIrqCmdComplete;
92  break;
93  default:
94  LOG_ERROR("Unexpected interrupt (at I2C): %d", i2c_irq);
95  break;
96  }
97 
98  if (disable) {
99  // Status type interrupt must be disabled since it cannot be cleared
100  CHECK_DIF_OK(dif_i2c_irq_set_enabled(&i2c, i2c_irq, kDifToggleDisabled));
101  }
102 }
103 
104 static void en_plic_irqs(dif_rv_plic_t *plic) {
105  // Enable functional interrupts as well as error interrupts to make sure
106  // everything is behaving as expected.
107  for (uint32_t i = 0; i < ARRAYSIZE(plic_irqs); ++i) {
108  CHECK_DIF_OK(dif_rv_plic_irq_set_enabled(
109  plic, plic_irqs[i], kTopEarlgreyPlicTargetIbex0, kDifToggleEnabled));
110 
111  // Assign a default priority
112  CHECK_DIF_OK(dif_rv_plic_irq_set_priority(plic, plic_irqs[i],
114  }
115 
116  // Enable the external IRQ at Ibex.
117  irq_global_ctrl(true);
118  irq_external_ctrl(true);
119 }
120 
121 static void en_i2c_irqs(dif_i2c_t *i2c) {
122  dif_i2c_irq_t i2c_irqs[] = {
123  kDifI2cIrqRxThreshold, kDifI2cIrqRxOverflow, kDifI2cIrqControllerHalt,
124  kDifI2cIrqSclInterference, kDifI2cIrqSdaInterference,
125  kDifI2cIrqStretchTimeout,
126  // Removed for now, see plic_irqs above for
127  // explanation kDifI2cIrqSdaUnstable,
128  kDifI2cIrqCmdComplete};
129 
130  for (uint32_t i = 0; i < ARRAYSIZE(i2c_irqs); ++i) {
131  CHECK_DIF_OK(dif_i2c_irq_set_enabled(i2c, i2c_irqs[i], kDifToggleEnabled));
132  }
133 }
134 
135 static void en_i2c_status_irqs(dif_i2c_t *i2c) {
136  // Enable the FmtThreshold IRQ now that there is something in the FMT FIFO
137  CHECK_DIF_OK(
138  dif_i2c_irq_set_enabled(i2c, kDifI2cIrqFmtThreshold, kDifToggleEnabled));
139  // Enable the RxThreshold IRQ in anticipation of receiving data into the
140  // RX FIFO
141  CHECK_DIF_OK(
142  dif_i2c_irq_set_enabled(i2c, kDifI2cIrqRxThreshold, kDifToggleEnabled));
143 }
144 
145 // handle i2c index related configure
146 void config_i2c_with_index(void) {
147  uint8_t i = 0;
148  switch (kI2cIdx) {
149  case 0:
150  i2c_base_addr = TOP_EARLGREY_I2C0_BASE_ADDR;
151  i2c_irq_fmt_threshold_id = kTopEarlgreyPlicIrqIdI2c0FmtThreshold;
152 
153  plic_irqs[i++] = kTopEarlgreyPlicIrqIdI2c0FmtThreshold;
154  plic_irqs[i++] = kTopEarlgreyPlicIrqIdI2c0RxThreshold;
155  plic_irqs[i++] = kTopEarlgreyPlicIrqIdI2c0RxOverflow;
160  // TODO, leave out sda unstable for now until DV side is improved. Sda
161  // instability during the high cycle is intentionally being introduced
162  // right now.
163  // plic_irqs[i++] = kTopEarlgreyPlicIrqIdI2c0SdaUnstable;
164  plic_irqs[i++] = kTopEarlgreyPlicIrqIdI2c0CmdComplete;
165 
166  CHECK_DIF_OK(dif_pinmux_input_select(
169  CHECK_DIF_OK(dif_pinmux_input_select(
172  CHECK_DIF_OK(dif_pinmux_output_select(&pinmux,
175  CHECK_DIF_OK(dif_pinmux_output_select(&pinmux,
178  break;
179  case 1:
180  i2c_base_addr = TOP_EARLGREY_I2C1_BASE_ADDR;
181  i2c_irq_fmt_threshold_id = kTopEarlgreyPlicIrqIdI2c1FmtThreshold;
182 
183  plic_irqs[i++] = kTopEarlgreyPlicIrqIdI2c1FmtThreshold;
184  plic_irqs[i++] = kTopEarlgreyPlicIrqIdI2c1RxThreshold;
185  plic_irqs[i++] = kTopEarlgreyPlicIrqIdI2c1RxOverflow;
190  // TODO, leave out sda unstable for now until DV side is improved. Sda
191  // instability during the high cycle is intentionally being introduced
192  // right now.
193  // plic_irqs[i++] = kTopEarlgreyPlicIrqIdI2c1SdaUnstable;
194  plic_irqs[i++] = kTopEarlgreyPlicIrqIdI2c1CmdComplete;
195 
196  CHECK_DIF_OK(dif_pinmux_input_select(
199  CHECK_DIF_OK(dif_pinmux_input_select(
202  CHECK_DIF_OK(dif_pinmux_output_select(&pinmux,
205  CHECK_DIF_OK(dif_pinmux_output_select(&pinmux,
208  break;
209  case 2:
210  i2c_base_addr = TOP_EARLGREY_I2C2_BASE_ADDR;
211  i2c_irq_fmt_threshold_id = kTopEarlgreyPlicIrqIdI2c2FmtThreshold;
212 
213  plic_irqs[i++] = kTopEarlgreyPlicIrqIdI2c2FmtThreshold;
214  plic_irqs[i++] = kTopEarlgreyPlicIrqIdI2c2RxThreshold;
215  plic_irqs[i++] = kTopEarlgreyPlicIrqIdI2c2RxOverflow;
220  // TODO, leave out sda unstable for now until DV side is improved. Sda
221  // instability during the high cycle is intentionally being introduced
222  // right now.
223  // plic_irqs[i++] = kTopEarlgreyPlicIrqIdI2c2SdaUnstable;
224  plic_irqs[i++] = kTopEarlgreyPlicIrqIdI2c2CmdComplete;
225 
226  CHECK_DIF_OK(dif_pinmux_input_select(
229  CHECK_DIF_OK(dif_pinmux_input_select(
232  CHECK_DIF_OK(dif_pinmux_output_select(&pinmux,
235  CHECK_DIF_OK(dif_pinmux_output_select(&pinmux,
238  break;
239  default:
240  LOG_FATAL("Unsupported i2c index %d", kI2cIdx);
241  }
242 }
243 
244 /**
245  * Send a write transaction with random data, followed by a read transaction of
246  * the same length. Check that the read data matches the written data. Ensure
247  * the appropriate IRQs have been triggered.
248  *
249  * @param skip_stop True to use a repeated start to end the write transaction
250  * and start the read. False to use a STOP condition to end the
251  * write transaction and start the read.
252  */
253 void issue_test_transactions(bool skip_stop) {
254  // Randomize variables.
255  uint8_t byte_count = (uint8_t)rand_testutils_gen32_range(30, 64);
256  uint8_t device_addr = (uint8_t)rand_testutils_gen32_range(0, 16);
257  uint8_t expected_data[byte_count];
258  LOG_INFO("Loopback %d bytes with device %d", byte_count, device_addr);
259 
260  // Controlling the randomization from C side is a bit slow, but might be
261  // easier for portability to a different setup later.
262  for (uint32_t i = 0; i < byte_count; ++i) {
263  expected_data[i] = (uint8_t)rand_testutils_gen32_range(0, 0xff);
264  };
265 
266  // Write expected data to i2c device.
267  CHECK_STATUS_OK(i2c_testutils_write(&i2c, device_addr, byte_count,
268  expected_data, skip_stop));
269  CHECK(!fmt_irq_seen);
270  en_i2c_status_irqs(&i2c);
271 
272  dif_i2c_level_t fmt_fifo_lvl, rx_fifo_lvl;
273 
274  // Make sure all fifo entries have been drained.
275  do {
276  CHECK_DIF_OK(
277  dif_i2c_get_fifo_levels(&i2c, &fmt_fifo_lvl, &rx_fifo_lvl, NULL, NULL));
278  } while (fmt_fifo_lvl > 0);
279  CHECK(fmt_irq_seen);
280  fmt_irq_seen = false;
281 
282  // Read data from i2c device.
283  CHECK(!rx_irq_seen);
284  CHECK_STATUS_OK(i2c_testutils_issue_read(&i2c, device_addr, byte_count));
285 
286  // Make sure all data has been read back.
287  do {
288  CHECK_DIF_OK(
289  dif_i2c_get_fifo_levels(&i2c, &fmt_fifo_lvl, &rx_fifo_lvl, NULL, NULL));
290  } while (rx_fifo_lvl < byte_count);
291  CHECK(rx_irq_seen);
292 
293  // Make sure every read is the same.
294  for (uint32_t i = 0; i < byte_count; ++i) {
295  uint8_t byte;
296  CHECK_DIF_OK(dif_i2c_read_byte(&i2c, &byte));
297  if (expected_data[i] != byte) {
298  LOG_ERROR("Byte %d, Expected data 0x%x, read data 0x%x", i,
299  expected_data[i], byte);
300  }
301  };
302  CHECK(done_irq_seen);
303 }
304 
305 bool test_main(void) {
306  LOG_INFO("Testing I2C index %d", kI2cIdx);
307  CHECK_DIF_OK(dif_pinmux_init(
309 
310  config_i2c_with_index();
311 
312  CHECK_DIF_OK(dif_i2c_init(mmio_region_from_addr(i2c_base_addr), &i2c));
313  CHECK_DIF_OK(dif_rv_plic_init(
315 
316  en_plic_irqs(&plic);
317 
318  // I2C speed parameters.
319  dif_i2c_timing_config_t timing_config = {
321  .clock_period_nanos = kClockPeriodNanos,
322  .sda_rise_nanos = kI2cRiseFallNanos,
323  .sda_fall_nanos = kI2cRiseFallNanos,
324  .scl_period_nanos = kI2cClockPeriodNanos};
325 
326  dif_i2c_config_t config;
327  CHECK_DIF_OK(dif_i2c_compute_timing(timing_config, &config));
328  if (kI2cCdcInstrumentationEnabled) {
329  // Increase rise cycles to accommodate CDC incorrectly delaying the data
330  // change. Without this, the SDA interference interrupt will be triggered
331  // when the prim_flop_2sync randomly adds an extra cycle of delay.
332  config.rise_cycles++;
333  }
334  CHECK_DIF_OK(dif_i2c_configure(&i2c, config));
335  CHECK_DIF_OK(dif_i2c_host_set_enabled(&i2c, kDifToggleEnabled));
336  CHECK_DIF_OK(
337  dif_i2c_set_host_watermarks(&i2c, /*rx_level=*/29u, /*fmt_level=*/5u));
338 
339  en_i2c_irqs(&i2c);
340 
341  // Round 1: Test with a STOP between the write and read transactions.
342  CHECK(!fmt_irq_seen);
343  CHECK(!rx_irq_seen);
344  CHECK(!done_irq_seen);
345  issue_test_transactions(/*skip_stop=*/false);
346 
347  // Round 2: Test without a STOP between the write and read transactions. Use a
348  // repeated start instead.
349  fmt_irq_seen = false;
350  rx_irq_seen = false;
351  done_irq_seen = false;
352  issue_test_transactions(/*skip_stop=*/true);
353 
354  return true;
355 }