Software APIs
i2c_host_eeprom_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 
14 #include "sw/device/lib/testing/i2c_testutils.h"
15 #include "sw/device/lib/testing/rv_core_ibex_testutils.h"
16 #include "sw/device/lib/testing/test_framework/check.h"
18 
20 #include "i2c_regs.h" // Generated.
21 
22 static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__,
23  "This test assumes the target platform is little endian.");
24 
25 OTTF_DEFINE_TEST_CONFIG();
26 
27 enum {
28  kDeviceAddr = 0x52,
29  // Default timeout for i2c reads.
30  kDefaultTimeoutMicros = 5000,
31  // "Acknowledgement polling" timeout - used for waiting until EEPROM has
32  // finished writing.
33  kAckPollTimeoutMicros = 80000,
34 };
35 
36 static status_t write_byte(dif_i2c_t *i2c, const uint8_t addr[2],
37  uint8_t byte) {
38  uint8_t data[3] = {addr[0], addr[1], byte};
39  return i2c_testutils_write(i2c, kDeviceAddr, sizeof(data), data, false);
40 }
41 
42 static status_t read_byte(dif_i2c_t *i2c, const uint8_t addr[2],
43  uint8_t *byte) {
44  TRY(i2c_testutils_write(i2c, kDeviceAddr, 2, addr, true));
45  return i2c_testutils_read(i2c, kDeviceAddr, 1, byte, kDefaultTimeoutMicros);
46 }
47 
48 /**
49  * Poll the EEPROM device until it is no longer busy writing.
50  *
51  * This function performs a zero-byte read with a `kAckPollTimeoutMicros`
52  * microsecond timeout. The EEPROM device will not acknowledge the device
53  * address until it is finished writing.
54  */
55 static status_t poll_while_busy(dif_i2c_t *i2c) {
56  return i2c_testutils_read(i2c, kDeviceAddr, 0, NULL, kAckPollTimeoutMicros);
57 }
58 
59 /**
60  * Check if the given irq is in the expected state.
61  */
62 static status_t check_irq(dif_i2c_t *i2c, dif_i2c_irq_t irq, bool expected) {
63  bool asserted = false;
64  TRY(dif_i2c_irq_is_pending(i2c, irq, &asserted));
65  TRY_CHECK(expected == asserted, "Irq %u not in the expected state", irq);
66  return OK_STATUS();
67 }
68 
69 static status_t write_read_random(dif_i2c_t *i2c) {
70  int32_t naks = 0;
71  // Write a byte to some random address.
72  const uint8_t kAddr[2] = {0x03, 0x21};
73  TRY(write_byte(i2c, kAddr, 0xAB));
74 
75  // Wait for the write to finish.
76  naks = TRY(poll_while_busy(i2c));
77  TRY_CHECK(naks > 0, "We should have received naks");
78 
79  // Read back the data at that address.
80  uint8_t read_data = 0x00;
81  TRY(read_byte(i2c, kAddr, &read_data));
82 
83  // Check the written byte matches what we wrote.
84  TRY_CHECK(read_data == 0xAB, "Unexpected value: 0x%02x", read_data);
85 
86  // Erase the value we just wrote to prevent the success state persisting to
87  // subsequent runs of the test.
88  TRY(write_byte(i2c, kAddr, 0xFF));
89  naks = TRY(poll_while_busy(i2c));
90  TRY_CHECK(naks > 0, "We should have received naks");
91  TRY(read_byte(i2c, kAddr, &read_data));
92 
93  // Check the over-written byte matches the new value.
94  TRY_CHECK(read_data == 0xFF, "Unexpected value: 0x%02x", read_data);
95 
96  return OK_STATUS();
97 }
98 
99 static status_t write_read_page(dif_i2c_t *i2c, bool use_irq) {
100  // Write multiple bytes to the 9th page (of 64 bytes each).
101  const uint8_t kAddr[2] = {0x02, 0x01};
102  uint8_t data[10] = {kAddr[0], kAddr[1], 0x01, 0x23, 0x45,
103  0x67, 0x89, 0xAB, 0xCD, 0xEF};
104  TRY(i2c_testutils_write(i2c, kDeviceAddr, sizeof(data), data, false));
105  if (use_irq) {
106  // Check immediately that the FmtThreshold Status-type interrupt has been
107  // deasserted.
108  TRY(check_irq(i2c, kDifI2cIrqFmtThreshold, false));
109  }
110 
111  // Wait for the write to finish.
112  TRY(poll_while_busy(i2c));
113 
114  // Read back the data at that address.
115  uint8_t read_data[8] = {
116  0x00,
117  };
118  TRY(i2c_testutils_write(i2c, kDeviceAddr, sizeof(kAddr), kAddr, true));
119  TRY(i2c_testutils_read(i2c, kDeviceAddr, sizeof(read_data), read_data,
120  kDefaultTimeoutMicros));
121 
122  // Check the written bytes match what we wrote.
123  TRY_CHECK_ARRAYS_EQ(read_data, data + 2, sizeof(read_data));
124 
125  // Erase the values we just wrote to prevent the success state persisting to
126  // subsequent runs of the test.
127  memset(&data[2], 0xFF, sizeof(read_data));
128  TRY(i2c_testutils_write(i2c, kDeviceAddr, sizeof(data), data, false));
129  TRY(poll_while_busy(i2c));
130  TRY(i2c_testutils_write(i2c, kDeviceAddr, sizeof(kAddr), kAddr, true));
131  if (use_irq) {
132  // Wait with a timeout until the RxThreshold interrupt is observed.
133  ibex_timeout_t timeout = ibex_timeout_init(kDefaultTimeoutMicros);
134  bool asserted = false;
135  do {
136  TRY(dif_i2c_irq_is_pending(i2c, kDifI2cIrqRxThreshold, &asserted));
137  } while (!asserted && !ibex_timeout_check(&timeout));
138  TRY_CHECK(asserted, "RxThreshold interrupt not asserted");
139  }
140  TRY(i2c_testutils_read(i2c, kDeviceAddr, sizeof(read_data), read_data,
141  kDefaultTimeoutMicros));
142 
143  // Check the over-written bytes match the new erased value.
144  TRY_CHECK_ARRAYS_EQ(read_data, data + 2, sizeof(read_data));
145 
146  return OK_STATUS();
147 }
148 
149 static status_t write_read_page_with_irq(dif_i2c_t *i2c) {
150  TRY(dif_i2c_irq_acknowledge_all(i2c));
151  TRY(dif_i2c_set_host_watermarks(i2c, /*rx_level=*/3u, /*fmt_level=*/5u));
152 
153  TRY(write_read_page(i2c, true));
154 
155  // FMT FIFO should empty, so interrupt should no longer be asserted.
156  TRY(check_irq(i2c, kDifI2cIrqFmtThreshold, true));
157  // All data should have been read from the RX FIFO
158  return check_irq(i2c, kDifI2cIrqRxThreshold, false);
159 }
160 
161 static status_t i2c_configure(dif_i2c_t *i2c, dif_pinmux_t *pinmux,
162  uint8_t i2c_instance,
163  i2c_pinmux_platform_id_t platform) {
164  const uintptr_t kI2cBaseAddrTable[] = {TOP_EARLGREY_I2C0_BASE_ADDR,
167  TRY_CHECK(i2c_instance < ARRAYSIZE(kI2cBaseAddrTable));
168 
169  mmio_region_t base_addr =
170  mmio_region_from_addr(kI2cBaseAddrTable[i2c_instance]);
171  TRY(dif_i2c_init(base_addr, i2c));
172 
174 
175  TRY(i2c_testutils_select_pinmux(pinmux, i2c_instance, platform));
176 
178 
179  return OK_STATUS();
180 }
181 
182 static status_t test_shutdown(dif_i2c_t *i2c, dif_pinmux_t *pinmux,
183  uint8_t i2c_instance) {
185  return i2c_testutils_detach_pinmux(pinmux, i2c_instance);
186 }
187 
188 bool test_main(void) {
189  dif_pinmux_t pinmux;
190  dif_i2c_t i2c;
191  CHECK_DIF_OK(dif_pinmux_init(
193 
194  i2c_pinmux_platform_id_t platform = I2cPinmuxPlatformIdCw310Pmod;
195  status_t test_result = OK_STATUS();
196  for (uint8_t i2c_instance = 0; i2c_instance < 3; ++i2c_instance) {
197  LOG_INFO("Testing i2c%d", i2c_instance);
198  CHECK_STATUS_OK(i2c_configure(&i2c, &pinmux, i2c_instance, platform));
199 
202 
203  for (size_t i = 0; i < ARRAYSIZE(kSpeeds); ++i) {
204  CHECK_STATUS_OK(i2c_testutils_set_speed(&i2c, kSpeeds[i]));
205  EXECUTE_TEST(test_result, write_read_random, &i2c);
206  EXECUTE_TEST(test_result, write_read_page, &i2c, false);
207  EXECUTE_TEST(test_result, write_read_page_with_irq, &i2c);
208  }
209  CHECK_STATUS_OK(test_shutdown(&i2c, &pinmux, i2c_instance));
210  }
211 
212  return status_ok(test_result);
213 }