Software APIs
i2c_host_fram_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 = 0x51,
29  kDeviceIdAddr = 0xF8 >> 1,
30 
31  // Registers values
32  kManufacturerId = 0x00A,
33  kProductId = 0x510,
34 
35  kDefaultTimeoutMicros = 5000,
36 
37  kI2cInstances = 3,
38 };
39 
40 static status_t write_byte(dif_i2c_t *i2c, const uint8_t addr[2],
41  uint8_t byte) {
42  uint8_t data[3] = {addr[0], addr[1], byte};
43  return i2c_testutils_write(i2c, kDeviceAddr, sizeof(data), data, false);
44 }
45 
46 static status_t read_byte(dif_i2c_t *i2c, const uint8_t addr[2],
47  uint8_t *byte) {
48  TRY(i2c_testutils_write(i2c, kDeviceAddr, 2, addr, true));
49  return i2c_testutils_read(i2c, kDeviceAddr, 1, byte, kDefaultTimeoutMicros);
50 }
51 
52 static status_t read_device_id(dif_i2c_t *i2c) {
53  // Reading the manufacturer and product IDs of this device works as follows:
54  // 1. Instead of the device address, use the "DeviceID address" word `F8`.
55  // 2. Write the device address of the FRAM device (`kDeviceAddr`).
56  // 3. Read 3 bytes - the manufacturer and product IDs are 12 bits each.
57 
58  uint8_t cmd = kDeviceAddr << 1;
59  uint8_t data[3] = {0x00, 0x00, 0x00};
60 
61  TRY(i2c_testutils_write(i2c, kDeviceIdAddr, 1, &cmd, true));
62  TRY(i2c_testutils_read(i2c, kDeviceIdAddr, sizeof(data), data,
63  kDefaultTimeoutMicros));
64 
65  // Extract the 12-bit manufacturer and product IDs from the 24 bits of data.
66 
67  uint16_t manuf_id = (uint16_t)((uint16_t)data[0] << 8) + (data[1] >> 4);
68  uint16_t product_id = (uint16_t)((uint16_t)(data[1] & 0x0F) << 8) + data[2];
69 
70  TRY_CHECK(manuf_id == kManufacturerId, "Unexpected value 0x%x", data);
71  TRY_CHECK(product_id == kProductId, "Unexpected value 0x%x", data);
72 
73  return OK_STATUS();
74 }
75 
76 static status_t write_read_byte(dif_i2c_t *i2c) {
77  // Write a byte to some random address.
78  const uint8_t kAddr[2] = {0x03, 0x21};
79  TRY(write_byte(i2c, kAddr, 0xAB));
80 
81  // Read back the data at that address.
82  uint8_t read_data = 0x00;
83  TRY(read_byte(i2c, kAddr, &read_data));
84 
85  TRY_CHECK(read_data == 0xAB, "Unexpected value: 0x%02x", read_data);
86 
87  // Overwrite the address that was just written to so that the success state
88  // doesn't persist between test runs.
89  TRY(write_byte(i2c, kAddr, 0xFF));
90  TRY(read_byte(i2c, kAddr, &read_data));
91  TRY_CHECK(read_data == 0xFF, "Unexpected value: 0x%02x", read_data);
92 
93  return OK_STATUS();
94 }
95 
96 static status_t write_read_page(dif_i2c_t *i2c) {
97  // Write multiple bytes at once to some address.
98  const uint8_t kAddr[2] = {0x02, 0x01};
99  uint8_t data[5] = {kAddr[0], kAddr[1], 0xAB, 0xCD, 0xEF};
100  TRY(i2c_testutils_write(i2c, kDeviceAddr, sizeof(data), data, false));
101 
102  // Read back 2 of the 3 bytes written to that address.
103  uint8_t read_data[2] = {0x00, 0x00};
104  TRY(i2c_testutils_write(i2c, kDeviceAddr, sizeof(kAddr), kAddr, true));
105  TRY(i2c_testutils_read(i2c, kDeviceAddr, sizeof(read_data), read_data,
106  kDefaultTimeoutMicros));
107 
108  // Check the read bytes match what we wrote.
109  TRY_CHECK_ARRAYS_EQ(read_data, data + 2, sizeof(read_data));
110 
111  // The address counter should now be at the third (and final) byte. Read it.
112  uint8_t last_byte = 0x00;
113  TRY(i2c_testutils_read(i2c, kDeviceAddr, 1, &last_byte,
114  kDefaultTimeoutMicros));
115 
116  TRY_CHECK(last_byte == data[4], "Unexpected value: 0x%02x", last_byte);
117 
118  // Erase the values we just wrote to prevent the success state persisting
119  // between test runs.
120  uint8_t erase_data[5] = {kAddr[0], kAddr[1], 0xFF, 0xFF, 0xFF};
121  TRY(i2c_testutils_write(i2c, kDeviceAddr, sizeof(erase_data), erase_data,
122  false));
123  TRY(i2c_testutils_write(i2c, kDeviceAddr, sizeof(kAddr), kAddr, true));
124  uint8_t erase_read[3] = {0x00, 0x00, 0x00};
125  TRY(i2c_testutils_read(i2c, kDeviceAddr, sizeof(erase_read), erase_read,
126  kDefaultTimeoutMicros));
127 
128  // Check the over-written byte match the new erased value.
129  TRY_CHECK_ARRAYS_EQ(erase_read, erase_data + 2, sizeof(erase_read));
130 
131  return OK_STATUS();
132 }
133 
134 static status_t throughput(dif_i2c_t *i2c, uint32_t expected_kbps) {
135  enum { kTimeoutMicros = 1000 * 1000, kTxSize = 512 };
136 
137  dif_rv_core_ibex_t rv_core_ibex;
138  CHECK_DIF_OK(dif_rv_core_ibex_init(
140  &rv_core_ibex));
141 
142  const uint8_t kAddr[2] = {0x04, 0x00};
143  uint8_t data[kTxSize + sizeof(kAddr)] = {kAddr[0], kAddr[1]};
144  // Init buffer with random data.
145  for (int i = sizeof(kAddr); i < sizeof(data); ++i) {
146  uint32_t rand;
147  TRY(rv_core_ibex_testutils_get_rnd_data(&rv_core_ibex, 2000, &rand));
148  data[i] = rand & 0xFF;
149  }
150  ibex_timeout_t timer = ibex_timeout_init(kTimeoutMicros);
151  TRY(i2c_testutils_write(i2c, kDeviceAddr, sizeof(data), data, false));
152  IBEX_TRY_SPIN_FOR(TRY(i2c_testutils_fmt_fifo_empty(i2c)) == true,
153  kTimeoutMicros);
154  uint64_t elapsed = ibex_timeout_elapsed(&timer);
155  uint32_t kbps = (kTxSize * 8 * 1000) / (uint32_t)elapsed;
156  LOG_INFO("Wrote %u bytes, in %u micros, %u kbps. Expected was %u kbps",
157  kTxSize, (uint32_t)elapsed, kbps, expected_kbps);
158  TRY_CHECK(kbps >= expected_kbps, "%u kbps is less than %u kpbs", kbps,
159  expected_kbps);
160 
161  uint8_t read_data[kTxSize] = {0};
162  TRY(i2c_testutils_write(i2c, kDeviceAddr, sizeof(kAddr), kAddr, true));
163  timer = ibex_timeout_init(kTimeoutMicros);
164  TRY(i2c_testutils_read(i2c, kDeviceAddr, kTxSize, read_data, kTimeoutMicros));
165  elapsed = ibex_timeout_elapsed(&timer);
166  kbps = (kTxSize * 8 * 1000) / (uint32_t)elapsed;
167  LOG_INFO("Read %u bytes, in %u micros, %u kbps. Expected was %u kbps",
168  kTxSize, (uint32_t)elapsed, kbps, expected_kbps);
169  TRY_CHECK(kbps >= expected_kbps);
170  // Check the read bytes match what we wrote.
171  TRY_CHECK_ARRAYS_EQ(read_data, data + 2, sizeof(read_data));
172 
173  return OK_STATUS();
174 }
175 
176 static status_t i2c_configure(dif_i2c_t *i2c, dif_pinmux_t *pinmux,
177  uint8_t i2c_instance,
178  i2c_pinmux_platform_id_t platform) {
179  const uintptr_t kI2cBaseAddrTable[] = {TOP_EARLGREY_I2C0_BASE_ADDR,
182  TRY_CHECK(i2c_instance < ARRAYSIZE(kI2cBaseAddrTable));
183 
184  mmio_region_t base_addr =
185  mmio_region_from_addr(kI2cBaseAddrTable[i2c_instance]);
186  TRY(dif_i2c_init(base_addr, i2c));
187 
189 
190  TRY(i2c_testutils_select_pinmux(pinmux, i2c_instance, platform));
191 
193 
194  return OK_STATUS();
195 }
196 
197 static status_t test_shutdown(dif_i2c_t *i2c, dif_pinmux_t *pinmux,
198  uint8_t i2c_instance) {
200  return i2c_testutils_detach_pinmux(pinmux, i2c_instance);
201 }
202 
203 typedef struct test_setup {
204  dif_i2c_speed_t speed;
205  uint32_t kbps;
206 } test_setup_t;
207 
208 const test_setup_t kSetup[] = {
209  // kbps: We discount 85% for the start and stop bits.
210  // We also have to discount a factor to account for rounding errors.
211  // The rounding error becomes higher with higher speeds, as the i2c clock
212  // approaches the peripheral clock.
213  {.speed = kDifI2cSpeedStandard, .kbps = (uint32_t)(100 * 0.984 * 0.85)},
214  {.speed = kDifI2cSpeedFast, .kbps = (uint32_t)(400 * 0.92 * 0.85)},
215  {.speed = kDifI2cSpeedFastPlus, .kbps = (uint32_t)(1000 * 0.55 * 0.75)}};
216 
217 bool test_main(void) {
218  dif_pinmux_t pinmux;
219  dif_i2c_t i2c;
220 
221  CHECK_DIF_OK(dif_pinmux_init(
223 
224  i2c_pinmux_platform_id_t platform = I2cPinmuxPlatformIdCw310Pmod;
225  status_t test_result = OK_STATUS();
226  for (uint8_t i2c_instance = 0; i2c_instance < kI2cInstances; ++i2c_instance) {
227  LOG_INFO("Testing i2c%d", i2c_instance);
228  CHECK_STATUS_OK(i2c_configure(&i2c, &pinmux, i2c_instance, platform));
229 
230  for (size_t i = 0; i < ARRAYSIZE(kSetup); ++i) {
231  CHECK_STATUS_OK(i2c_testutils_set_speed(&i2c, kSetup[i].speed));
232  EXECUTE_TEST(test_result, read_device_id, &i2c);
233  EXECUTE_TEST(test_result, write_read_byte, &i2c);
234  EXECUTE_TEST(test_result, write_read_page, &i2c);
235  EXECUTE_TEST(test_result, throughput, &i2c, kSetup[i].kbps);
236  CHECK_STATUS_OK(test_result);
237  }
238  CHECK_STATUS_OK(test_shutdown(&i2c, &pinmux, i2c_instance));
239  }
240  return status_ok(test_result);
241 }