Software APIs
otp_ctrl_mem_access_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 
5 #include <assert.h>
6 #include <stdbool.h>
7 
14 #include "sw/device/lib/testing/otp_ctrl_testutils.h"
15 #include "sw/device/lib/testing/rstmgr_testutils.h"
16 #include "sw/device/lib/testing/test_framework/check.h"
18 
20 #include "otp_ctrl_regs.h"
21 
22 static dif_otp_ctrl_t otp;
23 static dif_rstmgr_t rstmgr;
24 
25 enum {
26  kLastWriteValue = 0x77778888,
27 };
28 
29 static const uint32_t kTestData[] = {
30  0x11112222,
31  0x33334444,
32  0x55556666,
33  kLastWriteValue,
34 };
35 
36 OTTF_DEFINE_TEST_CONFIG();
37 
38 typedef struct partition_data {
39  dif_otp_ctrl_partition_t partition;
40  size_t size;
42 
43 static const partition_data_t kPartitions[] = {
44  {
45  .partition = kDifOtpCtrlPartitionVendorTest,
46  .size = OTP_CTRL_PARAM_VENDOR_TEST_SIZE / sizeof(uint32_t),
47  },
48  {
50  .size = OTP_CTRL_PARAM_CREATOR_SW_CFG_SIZE / sizeof(uint32_t),
51  },
52  {
53  .partition = kDifOtpCtrlPartitionOwnerSwCfg,
54  .size = OTP_CTRL_PARAM_OWNER_SW_CFG_SIZE / sizeof(uint32_t),
55  },
56  {
57  .partition = kDifOtpCtrlPartitionRotCreatorAuthCodesign,
58  .size =
59  OTP_CTRL_PARAM_ROT_CREATOR_AUTH_CODESIGN_SIZE / sizeof(uint32_t),
60  },
61  {
62  .partition = kDifOtpCtrlPartitionRotCreatorAuthState,
63  .size = OTP_CTRL_PARAM_ROT_CREATOR_AUTH_STATE_SIZE / sizeof(uint32_t),
64  },
65 };
66 
67 static void peripheral_handles_init(void) {
68  CHECK_DIF_OK(dif_otp_ctrl_init(
70  CHECK_DIF_OK(dif_rstmgr_init(
72 }
73 
74 static void otp_ctrl_dai_write_test(bool expect_eq) {
75  for (uint32_t i = 0; i < ARRAYSIZE(kTestData); ++i) {
76  LOG_INFO("Programming word kTestData[%d] = 0x%08x.", i, kTestData[i]);
77  CHECK_STATUS_OK(otp_ctrl_testutils_wait_for_dai(&otp));
78 
79  uint32_t address = 0x10 + i * sizeof(uint32_t);
80  CHECK_DIF_OK(
82  address, kTestData[i]),
83  "Failed to program word kTestData[%d] = 0x%08x.", i, kTestData[i]);
84  }
85  CHECK_STATUS_OK(otp_ctrl_testutils_wait_for_dai(&otp));
86 
87  uint32_t readout[ARRAYSIZE(kTestData)] = {0};
88  CHECK_STATUS_OK(otp_ctrl_testutils_dai_read32_array(
89  &otp, kDifOtpCtrlPartitionVendorTest, 0x10, readout, ARRAYSIZE(readout)));
90 
91  if (expect_eq) {
92  CHECK_ARRAYS_EQ(readout, kTestData, ARRAYSIZE(kTestData));
93  } else {
94  CHECK_ARRAYS_NE(readout, kTestData, ARRAYSIZE(kTestData));
95  }
96 }
97 
98 static void dai_disable(void) {
99  CHECK_DIF_OK(dif_otp_ctrl_dai_lock(&otp));
100 
101  bool is_locked;
102  CHECK_DIF_OK(dif_otp_ctrl_dai_is_locked(&otp, &is_locked));
103  CHECK(is_locked);
104  CHECK_STATUS_OK(otp_ctrl_testutils_wait_for_dai(&otp));
105 }
106 
107 static void otp_ctrl_dai_disable_test(uint32_t last_dai_value) {
108  dai_disable();
109  LOG_INFO("Checking that the DAI is disabled.");
110  for (uint32_t i = 0; i < ARRAYSIZE(kPartitions); ++i) {
111  const partition_data_t *partition = &kPartitions[i];
112  LOG_INFO("Checking partition %d.", partition->partition);
113  uint32_t readout[partition->size];
114  CHECK_STATUS_OK(otp_ctrl_testutils_dai_read32_array(
115  &otp, partition->partition, 0, readout, ARRAYSIZE(readout)));
116 
117  // The current DAI locking mechanism just locks the register inteface, so
118  // all transactions should result in a DAI idle status.
120  CHECK_DIF_OK(dif_otp_ctrl_get_status(&otp, &status));
121  CHECK(status.codes == (1 << kDifOtpCtrlStatusCodeDaiIdle));
122 
123  // The last register value is preserved by the DAI interface. We compare
124  // all read values against this to ensure that the DAI interface is not
125  // returning any read values.
126  for (uint32_t j = 0; j < ARRAYSIZE(readout); ++j) {
127  CHECK(readout[j] == last_dai_value,
128  "Partition %d, word %d: expected 0x%08x, got 0x%08x.",
129  partition->partition, j, last_dai_value, readout[j]);
130  }
131  }
132 }
133 
134 bool test_main(void) {
135  peripheral_handles_init();
136 
137  CHECK_DIF_OK(
139  .check_timeout = 100000,
140  .integrity_period_mask = 0x3ffff,
141  .consistency_period_mask = 0x3ffffff,
142  }));
143 
144  const dif_rstmgr_reset_info_bitfield_t reset_info =
145  rstmgr_testutils_reason_get();
146  if (reset_info == kDifRstmgrResetInfoPor) {
147  LOG_INFO("Power-on reset detected.");
148  dai_disable();
149  otp_ctrl_dai_write_test(/*expect_eq=*/false);
150 
151  rstmgr_testutils_reason_clear();
152  CHECK_DIF_OK(dif_rstmgr_software_device_reset(&rstmgr));
153 
154  // Wait here until device reset.
156 
157  // Should never reach this.
158  return false;
159  }
160 
161  CHECK(reset_info == kDifRstmgrResetInfoSw, "Unexpected reset reason: %08x",
162  reset_info);
163  LOG_INFO("Software reset detected.");
164 
165  otp_ctrl_dai_write_test(/*expect_eq=*/true);
166  otp_ctrl_dai_disable_test(kLastWriteValue);
167  return true;
168 }