Software APIs
rom_e2e_ret_ram_keep_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 
10 #include "sw/device/lib/testing/aon_timer_testutils.h"
11 #include "sw/device/lib/testing/pwrmgr_testutils.h"
12 #include "sw/device/lib/testing/test_framework/check.h"
14 #include "sw/device/silicon_creator/lib/drivers/retention_sram.h"
15 #include "sw/device/silicon_creator/lib/drivers/rstmgr.h"
16 
17 static const dt_pwrmgr_t kPwrmgrDt = 0;
18 static_assert(kDtPwrmgrCount == 1, "this test expects exactly one pwrmgr");
19 static const dt_aon_timer_t kAonTimerDt = 0;
20 static_assert(kDtAonTimerCount >= 1,
21  "this test expects at least one aon_timer");
22 
23 OTTF_DEFINE_TEST_CONFIG();
24 
25 enum {
26  kPattern = 0xab,
27 };
28 
29 /**
30  * Check that a region within the retention SRAM has not changed from kPattern.
31  *
32  * @param start A pointer to the start of the region to check.
33  * @param length The number of 32-bit words to check.
34  * @return Whether the region has changed.
35  */
36 bool check_ram_region_unchanged(char *start, size_t length) {
37  uint32_t pattern32;
38  memset(&pattern32, kPattern, sizeof(pattern32));
39 
40  bool unchanged = true;
41  for (size_t i = 0; i < length; i += sizeof(uint32_t)) {
42  uint32_t val = read_32(start + i);
43  if (val != pattern32) {
44  LOG_ERROR("Retention SRAM changed at word %u (%x --> %x).",
45  i / sizeof(uint32_t), pattern32, val);
46  unchanged = false;
47  }
48  }
49  return unchanged;
50 }
51 
52 /**
53  * Check that the values in the retention SRAM have not changed from kPattern.
54  * Only the reserved sections of the silicon_owner and siilicon_creator
55  * sections are checked as other entries may be updated during boot.
56  */
57 bool check_ram_unchanged(retention_sram_t *ret) {
58  LOG_INFO("Checking that retention SRAM values are unchanged");
59  bool unchanged = true;
60  const size_t creator_resv_size = sizeof(ret->creator.reserved);
61  const size_t owner_resv_size = sizeof(ret->owner.reserved);
62  // Ensure that the reserved section is sufficiently large for a robust check.
63  // 1 word is an arbitrary limit, but if the reserved section is filled up, a
64  // new testing approach will be needed.
65  CHECK(creator_resv_size > sizeof(uint32_t));
66  CHECK(owner_resv_size > sizeof(uint32_t));
67  unchanged &= check_ram_region_unchanged((char *)&ret->creator.reserved,
68  creator_resv_size);
69  unchanged &=
70  check_ram_region_unchanged((char *)&ret->owner.reserved, owner_resv_size);
71  return unchanged;
72 }
73 
74 rom_error_t retention_ram_keep_test(void) {
75  // Variables of type `retention_sram_t` are static to reduce stack usage.
76  retention_sram_t *ret = retention_sram_get();
77  uint32_t reset_reasons = ret->creator.reset_reasons;
78 
79  // Verify that reset_reasons reports POR.
80  if (bitfield_bit32_read(reset_reasons, kRstmgrReasonPowerOn)) {
81  // This branch runs after the POR after initializing the testing environment
82 
83  LOG_INFO("Checking boot_log.retention_ram_initialized: %x",
86  LOG_INFO("Writing known pattern to ret RAM");
87  memset(ret, kPattern, sizeof(retention_sram_t));
88 
89  // Initialize pwrmgr
90  dif_pwrmgr_t pwrmgr;
91  CHECK_DIF_OK(dif_pwrmgr_init_from_dt(kPwrmgrDt, &pwrmgr));
92  dif_pwrmgr_request_sources_t wakeup_sources;
93  CHECK_DIF_OK(dif_pwrmgr_find_request_source(
94  &pwrmgr, kDifPwrmgrReqTypeWakeup, dt_aon_timer_instance_id(kAonTimerDt),
95  kDtAonTimerWakeupWkupReq, &wakeup_sources));
96 
97  // Initialize aon timer
98  // Issue a wakeup signal in ~150us through the AON timer.
99  //
100  // At 200kHz, threshold of 30 is equal to 150us. There is an additional
101  // ~4 cycle overhead for the CSR value to synchronize with the AON clock.
102  // We should expect the wake up to trigger in ~170us. This is sufficient
103  // time to allow pwrmgr config and the low power entry on WFI to complete.
104  //
105  // Adjust the threshold for Verilator since it runs on different clock
106  // frequencies.
107  uint64_t wakeup_threshold = kDeviceType == kDeviceSimVerilator ? 300 : 30;
108 
109  dif_aon_timer_t aon_timer;
110  CHECK_DIF_OK(dif_aon_timer_init_from_dt(kAonTimerDt, &aon_timer));
111  CHECK_STATUS_OK(
112  aon_timer_testutils_wakeup_config(&aon_timer, wakeup_threshold));
113 
114  // Enter low-power
115  CHECK_STATUS_OK(
116  pwrmgr_testutils_enable_low_power(&pwrmgr, wakeup_sources, 0));
117  LOG_INFO("Issue WFI to enter sleep");
118  wait_for_interrupt(); // Enter low-power
119  } else if (bitfield_bit32_read(reset_reasons, kRstmgrReasonLowPowerExit)) {
120  LOG_INFO("Woke up from low power exit");
121  LOG_INFO("Checking boot_log.retention_ram_initialized: %x",
125  CHECK(check_ram_unchanged(ret));
126 
127  // Request a SW reset
128  LOG_INFO("Issuing a SW reset");
129  rstmgr_reset();
130  } else if (bitfield_bit32_read(reset_reasons, kRstmgrReasonSoftwareRequest)) {
131  LOG_INFO("Resuming from SW reset");
132  LOG_INFO("Checking boot_log.retention_ram_initialized: %x",
136  // This branch runs after the SW-requested reset
137  CHECK(check_ram_unchanged(ret));
138  return kErrorOk;
139  }
140  LOG_ERROR("Did not find a reset reason of Low-Power Exit or SW request");
141  return kErrorUnknown;
142 }
143 
144 bool test_main(void) {
145  status_t result = OK_STATUS();
146  EXECUTE_TEST(result, retention_ram_keep_test);
147  return status_ok(result);
148 }