Software APIs
otp_ctrl_testutils.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 #include "sw/device/lib/testing/otp_ctrl_testutils.h"
6 
10 #include "sw/device/lib/testing/test_framework/check.h"
11 
12 #define MODULE_ID MAKE_MODULE_ID('o', 'c', 't')
13 
14 /*
15  * OTP the Direct Access Interface (DAI) operation time-out in micro seconds.
16  *
17  * It is not possible to predict the specific cycle count that a DAI operation
18  * takes, thus arbitrary value of 100us is used.
19  */
20 const uint16_t kOtpDaiTimeoutUs = 5000;
21 
22 /**
23  * Checks whether the DAI operation has finished.
24  */
25 static bool dai_finished(const dif_otp_ctrl_t *otp_ctrl) {
28  return res == kDifOk &&
30 }
31 
32 status_t otp_ctrl_testutils_dai_access_error_check(
33  const dif_otp_ctrl_t *otp_ctrl, exp_test_result_t exp_result,
34  int32_t address) {
36  TRY(dif_otp_ctrl_get_status(otp_ctrl, &status));
37  if (exp_result == kExpectFailed) {
39  LOG_ERROR("Expected a DAI error for access to 0x%x", address);
40  }
43  LOG_ERROR("Expected access locked error for access to 0x%x", address);
44  }
45  } else {
47  LOG_ERROR("No DAI error expected for access to 0x%x", address);
48  }
50  LOG_ERROR("No DAI error code expected for access to 0x%x", address);
51  }
52  }
53  return OK_STATUS();
54 }
55 
56 status_t otp_ctrl_testutils_wait_for_dai(const dif_otp_ctrl_t *otp_ctrl) {
57  IBEX_TRY_SPIN_FOR(dai_finished(otp_ctrl), kOtpDaiTimeoutUs);
58  return OK_STATUS();
59 }
60 
61 status_t otp_ctrl_testutils_lock_partition(const dif_otp_ctrl_t *otp,
62  dif_otp_ctrl_partition_t partition,
63  uint64_t digest) {
64  TRY(dif_otp_ctrl_dai_digest(otp, partition, digest));
65  return otp_ctrl_testutils_wait_for_dai(otp);
66 }
67 
68 status_t otp_ctrl_testutils_dai_read32(const dif_otp_ctrl_t *otp,
69  dif_otp_ctrl_partition_t partition,
70  uint32_t address, uint32_t *result) {
71  TRY(otp_ctrl_testutils_wait_for_dai(otp));
72  TRY(dif_otp_ctrl_dai_read_start(otp, partition, address));
73  TRY(otp_ctrl_testutils_wait_for_dai(otp));
74  TRY(dif_otp_ctrl_dai_read32_end(otp, result));
75  return OK_STATUS();
76 }
77 
78 status_t otp_ctrl_testutils_dai_read32_array(const dif_otp_ctrl_t *otp,
79  dif_otp_ctrl_partition_t partition,
80  uint32_t start_address,
81  uint32_t *buffer, size_t len) {
82  uint32_t stop_address = start_address + (len * sizeof(uint32_t));
83  for (uint32_t addr = start_address, i = 0; addr < stop_address;
84  addr += sizeof(uint32_t), ++i) {
85  TRY(otp_ctrl_testutils_wait_for_dai(otp));
86  TRY(dif_otp_ctrl_dai_read_start(otp, partition, addr));
87  TRY(otp_ctrl_testutils_wait_for_dai(otp));
88  TRY(dif_otp_ctrl_dai_read32_end(otp, &buffer[i]));
89  }
90  return OK_STATUS();
91 }
92 
93 status_t otp_ctrl_testutils_dai_read64(const dif_otp_ctrl_t *otp,
94  dif_otp_ctrl_partition_t partition,
95  uint32_t address, uint64_t *result) {
96  TRY(otp_ctrl_testutils_wait_for_dai(otp));
97  TRY(dif_otp_ctrl_dai_read_start(otp, partition, address));
98  TRY(otp_ctrl_testutils_wait_for_dai(otp));
99  TRY(dif_otp_ctrl_dai_read64_end(otp, result));
100  return OK_STATUS();
101 }
102 
103 status_t otp_ctrl_testutils_dai_read64_array(const dif_otp_ctrl_t *otp,
104  dif_otp_ctrl_partition_t partition,
105  uint32_t start_address,
106  uint64_t *buffer, size_t len) {
107  uint32_t stop_address = start_address + (len * sizeof(uint64_t));
108  for (uint32_t addr = start_address, i = 0; addr < stop_address;
109  addr += sizeof(uint64_t), ++i) {
110  TRY(otp_ctrl_testutils_wait_for_dai(otp));
111  TRY(dif_otp_ctrl_dai_read_start(otp, partition, addr));
112  TRY(otp_ctrl_testutils_wait_for_dai(otp));
113  TRY(dif_otp_ctrl_dai_read64_end(otp, &buffer[i]));
114  }
115  return OK_STATUS();
116 }
117 
118 /**
119  * Checks if there were any errors found after executing a DAI write transaction
120  * to the SECRET2 partition.
121  *
122  * @param otp otp_ctrl instance
123  * @return OK_STATUS if there were no errors detected.
124  */
126 static status_t otp_ctrl_dai_write_error_check(const dif_otp_ctrl_t *otp) {
128  TRY(dif_otp_ctrl_get_status(otp, &status));
129 
130  // TODO: Check for other OTP errors.
133  return OK_STATUS();
134  }
135  LOG_ERROR("dai_write_error_check code: 0x%x", status.codes);
136  return INTERNAL();
137 }
138 
139 status_t otp_ctrl_testutils_dai_write32(const dif_otp_ctrl_t *otp,
140  dif_otp_ctrl_partition_t partition,
141  uint32_t start_address,
142  const uint32_t *buffer, size_t len) {
143  // Software partitions don't have scrambling or ECC enabled, so it is possible
144  // to read the value and compare it against the expected value before
145  // performing the write.
146  bool check_before_write = (
147 #ifdef OPENTITAN_IS_EARLGREY
148  partition == kDifOtpCtrlPartitionRotCreatorAuthCodesign ||
149  partition == kDifOtpCtrlPartitionRotCreatorAuthState ||
150 #endif // OPENTITAN_IS_EARLGREY
151  partition == kDifOtpCtrlPartitionCreatorSwCfg ||
152  partition == kDifOtpCtrlPartitionOwnerSwCfg);
153  uint32_t stop_address = start_address + (len * sizeof(uint32_t));
154  for (uint32_t addr = start_address, i = 0; addr < stop_address;
155  addr += sizeof(uint32_t), ++i) {
156  uint32_t read_data;
157  if (check_before_write) {
158  TRY(otp_ctrl_testutils_dai_read32(otp, partition, addr, &read_data));
159  if (read_data == buffer[i]) {
160  continue;
161  }
162  if (read_data != 0) {
163  LOG_ERROR("OTP partition: %d addr[0x%x] got: 0x%08x, expected: 0x%08x",
164  partition, addr, read_data, buffer[i]);
165  return INTERNAL();
166  }
167  }
168 
169  TRY(otp_ctrl_testutils_wait_for_dai(otp));
170  TRY(dif_otp_ctrl_dai_program32(otp, partition, addr, buffer[i]));
171  TRY(otp_ctrl_testutils_wait_for_dai(otp));
172  TRY(otp_ctrl_dai_write_error_check(otp));
173 
174  TRY(otp_ctrl_testutils_dai_read32(otp, partition, addr, &read_data));
175  if (read_data != buffer[i]) {
176  return INTERNAL();
177  }
178  }
179  return OK_STATUS();
180 }
181 
182 status_t otp_ctrl_testutils_dai_write64(const dif_otp_ctrl_t *otp,
183  dif_otp_ctrl_partition_t partition,
184  uint32_t start_address,
185  const uint64_t *buffer, size_t len) {
186  uint32_t stop_address = start_address + (len * sizeof(uint64_t));
187  for (uint32_t addr = start_address, i = 0; addr < stop_address;
188  addr += sizeof(uint64_t), ++i) {
189  TRY(otp_ctrl_testutils_wait_for_dai(otp));
190  TRY(dif_otp_ctrl_dai_program64(otp, partition, addr, buffer[i]));
191  TRY(otp_ctrl_testutils_wait_for_dai(otp));
192  TRY(otp_ctrl_dai_write_error_check(otp));
193 
194  uint64_t read_data;
195  TRY(otp_ctrl_testutils_dai_read64(otp, partition, addr, &read_data));
196  if (read_data != buffer[i]) {
197  return INTERNAL();
198  }
199  }
200  return OK_STATUS();
201 }