Software APIs
sram_ctrl_sleep_sram_ret_contents_impl.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/runtime/irq.h"
12 #include "sw/device/lib/testing/aon_timer_testutils.h"
13 #include "sw/device/lib/testing/flash_ctrl_testutils.h"
14 #include "sw/device/lib/testing/pwrmgr_testutils.h"
15 #include "sw/device/lib/testing/rstmgr_testutils.h"
16 #include "sw/device/lib/testing/rv_plic_testutils.h"
17 #include "sw/device/lib/testing/sram_ctrl_testutils.h"
18 #include "sw/device/lib/testing/test_framework/check.h"
19 #include "sw/device/silicon_creator/lib/drivers/retention_sram.h"
20 
21 enum {
22  kTestBufferSizeWords = 16,
23  kPlicTarget = 0,
24 };
25 
26 static dif_rv_plic_t rv_plic;
27 static dif_aon_timer_t aon_timer;
28 static dif_pwrmgr_t pwrmgr;
29 static dif_rstmgr_t rstmgr;
30 
31 static const dt_rstmgr_t kRstmgrDt = 0;
32 static_assert(kDtRstmgrCount == 1, "this test expects a rstmgr");
33 static const dt_pwrmgr_t kPwrmgrDt = 0;
34 static_assert(kDtPwrmgrCount == 1, "this library expects exactly one pwrmgr");
35 static const dt_aon_timer_t kAonTimerDt = 0;
36 static_assert(kDtAonTimerCount == 1,
37  "this library expects exactly one aon_timer");
38 static const dt_rv_plic_t kRvPlicDt = 0;
39 static_assert(kDtRvPlicCount >= 1, "this test expects at least one rv_plic");
40 
41 static const dt_sram_ctrl_t kRetSramCtrlDt = kDtSramCtrlRetAon;
42 
43 static dif_pwrmgr_request_sources_t aon_timer_wakeup_sources;
44 
45 // Random data to read/write to/from retention SRAM.
46 const uint32_t kTestData[kTestBufferSizeWords] = {
47  0xe647e5d5, 0x4b5fe6f6, 0x1608a98a, 0x5e347116, 0xb2dc5e92, 0x899e3c0f,
48  0xc98295c2, 0x0fa84434, 0x15747561, 0xfecb5aa1, 0x7a78bb8c, 0x8f9c5d0f,
49  0x49338fbd, 0x093e82cb, 0xaaa58121, 0x5b806f96,
50 };
51 
52 typedef struct {
53  bool do_write;
54  bool is_equal;
56 
57 static void retention_sram_check(check_config_t config) {
58  uintptr_t ret_sram_owner_addr =
59  dt_sram_ctrl_reg_block(kRetSramCtrlDt, kDtSramCtrlRegBlockRam) +
60  offsetof(retention_sram_t, owner);
61 
62  if (config.do_write) {
63  sram_ctrl_testutils_write(
64  ret_sram_owner_addr,
65  (sram_ctrl_testutils_data_t){.words = kTestData,
66  .len = kTestBufferSizeWords});
67  }
68 
69  uint32_t tmp_buffer[kTestBufferSizeWords];
70  memcpy(tmp_buffer, (uint8_t *)ret_sram_owner_addr, sizeof(tmp_buffer));
71 
72  if (config.is_equal) {
73  CHECK_ARRAYS_EQ(tmp_buffer, kTestData, kTestBufferSizeWords);
74  } else {
75  CHECK_ARRAYS_NE(tmp_buffer, kTestData, kTestBufferSizeWords);
76  }
77  LOG_INFO("retention ram check with write=%d and is_equal=%d succeeded",
78  config.do_write, config.is_equal);
79 }
80 
81 /**
82  * Override internal interrupt handler to handle the ECC errors when reading the
83  * scrambled memory.
84  */
85 void ottf_internal_isr(uint32_t *exc_info) {}
86 
87 /**
88  * Override external interrupt handler to handle the normal sleep IRQ.
89  */
90 bool ottf_handle_irq(uint32_t *exc_info, dt_instance_id_t devid,
91  dif_rv_plic_irq_id_t irq_id) {
92  if (devid == dt_pwrmgr_instance_id(kPwrmgrDt) &&
93  irq_id == dt_pwrmgr_irq_to_plic_id(kPwrmgrDt, kDtPwrmgrIrqWakeup)) {
94  LOG_INFO("Receive irq in normal sleep");
95  CHECK_DIF_OK(dif_pwrmgr_irq_acknowledge(&pwrmgr, kDtPwrmgrIrqWakeup));
96  return true;
97  } else {
98  return false;
99  }
100 }
101 
102 // test these 2 cases:
103 // normal sleep, no scrambling -> data preserved
104 // normal sleep, with scrambling -> data preserved
105 void test_ret_sram_in_normal_sleep(void) {
106  // Write data to retention SRAM and readback (to test basic functionality.)
107  retention_sram_check((check_config_t){.do_write = true, .is_equal = true});
108 
109  // set up wakeup timer
110  CHECK_STATUS_OK(aon_timer_testutils_wakeup_config(&aon_timer, 20));
111  // Enable all the AON interrupts used in this test.
112  dif_rv_plic_irq_id_t irq_id =
113  dt_pwrmgr_irq_to_plic_id(kPwrmgrDt, kDtPwrmgrIrqWakeup);
114  rv_plic_testutils_irq_range_enable(&rv_plic, kPlicTarget, irq_id, irq_id);
115  CHECK_DIF_OK(dif_pwrmgr_irq_set_enabled(&pwrmgr, 0, kDifToggleEnabled));
116 
117  // Normal sleep.
118  CHECK_STATUS_OK(pwrmgr_testutils_enable_low_power(
119  &pwrmgr, /*wakeups=*/aon_timer_wakeup_sources,
121  kDifPwrmgrDomainOptionUsbClockInActivePower |
122  kDifPwrmgrDomainOptionMainPowerInLowPower));
123  // Enter low power mode.
124  LOG_INFO("Issue WFI to enter normal sleep");
126  // data preserved
127  retention_sram_check((check_config_t){.do_write = false, .is_equal = true});
128 }
129 
130 // test these 2 cases:
131 // deep sleep, no scrambling -> data preserved
132 // deep sleep, with scrambling -> data preserved
133 void enter_deep_sleep(void) {
134  // Prepare rstmgr for a reset.
135  CHECK_STATUS_OK(rstmgr_testutils_pre_reset(&rstmgr));
136  // set up wakeup timer
137  CHECK_STATUS_OK(aon_timer_testutils_wakeup_config(&aon_timer, 20));
138  // Deep sleep.
139  CHECK_STATUS_OK(
140  pwrmgr_testutils_enable_low_power(&pwrmgr, aon_timer_wakeup_sources, 0));
141 
142  // Enter low power mode.
143  LOG_INFO("Issue WFI to enter deep sleep");
145  CHECK(false, "Should have a reset to CPU before this line");
146 }
147 
148 void set_up_reset_request(void) {
149  // Prepare rstmgr for a reset.
150  CHECK_STATUS_OK(rstmgr_testutils_pre_reset(&rstmgr));
151  dif_pwrmgr_request_sources_t reset_sources;
152  CHECK_DIF_OK(dif_pwrmgr_find_request_source(
153  &pwrmgr, kDifPwrmgrReqTypeReset, dt_aon_timer_instance_id(kAonTimerDt),
154  kDtAonTimerResetReqAonTimer, &reset_sources));
155  CHECK_DIF_OK(dif_pwrmgr_set_request_sources(
156  &pwrmgr, kDifPwrmgrReqTypeReset, reset_sources, kDifToggleEnabled));
157 
158  CHECK_DIF_OK(dif_aon_timer_wakeup_stop(&aon_timer));
159 
160  // Enter low power mode. Use UINT32_MAX as wakeup threshold as UINT64_MAX far
161  // too long a timeout.
162  CHECK_STATUS_OK(aon_timer_testutils_watchdog_config(
163  &aon_timer, (uint64_t)UINT32_MAX, 20, false));
164  LOG_INFO("wait for reset");
166  CHECK(false, "Should have a reset to CPU and ret_sram before this line");
167 }
168 
169 bool execute_sram_ctrl_sleep_ret_sram_contents_test(bool scramble) {
170  // Enable global and external IRQ at Ibex.
171  irq_global_ctrl(true);
172  irq_external_ctrl(true);
173 
174  CHECK_DIF_OK(dif_pwrmgr_init_from_dt(kPwrmgrDt, &pwrmgr));
175  CHECK_DIF_OK(dif_rstmgr_init_from_dt(kRstmgrDt, &rstmgr));
176  CHECK_DIF_OK(dif_aon_timer_init_from_dt(kAonTimerDt, &aon_timer));
177  CHECK_DIF_OK(dif_rv_plic_init_from_dt(kRvPlicDt, &rv_plic));
178 
179  CHECK_DIF_OK(dif_pwrmgr_find_request_source(
180  &pwrmgr, kDifPwrmgrReqTypeWakeup, dt_aon_timer_instance_id(kAonTimerDt),
181  kDtAonTimerWakeupWkupReq, &aon_timer_wakeup_sources));
182 
183  dif_rstmgr_reset_info_bitfield_t rstmgr_reset_info;
184  rstmgr_reset_info = rstmgr_testutils_reason_get();
185 
186  LOG_INFO("Reset info = %08x", rstmgr_reset_info);
187 
188  if (rstmgr_reset_info == kDifRstmgrResetInfoPor) {
189  LOG_INFO("POR reset");
190  LOG_INFO("Start to test retention sram %sscrambled",
191  scramble ? "" : "not ");
192 
193  if (scramble) {
194  dif_sram_ctrl_t ret_sram;
195  CHECK_DIF_OK(dif_sram_ctrl_init_from_dt(kRetSramCtrlDt, &ret_sram));
196  LOG_INFO("Wiping ret_sram...");
197  CHECK_STATUS_OK(sram_ctrl_testutils_wipe(&ret_sram));
198  LOG_INFO("Scrambling ret_sram...");
199  CHECK_STATUS_OK(sram_ctrl_testutils_scramble(&ret_sram));
200  }
201  test_ret_sram_in_normal_sleep();
202 
203  enter_deep_sleep();
204  } else if (rstmgr_reset_info & kDifRstmgrResetInfoLowPowerExit) {
205  LOG_INFO("Wake up from deep sleep");
206 
207  CHECK(UNWRAP(pwrmgr_testutils_is_wakeup_reason(
208  &pwrmgr, aon_timer_wakeup_sources)) == true);
209  // data preserved
210  retention_sram_check((check_config_t){.do_write = false, .is_equal = true});
211 
212  set_up_reset_request();
213  } else if (rstmgr_reset_info & kDifRstmgrResetInfoWatchdog) {
214  LOG_INFO("watchdog reset");
215  // reset due to a reset request, if scramble data is not preserved.
216  retention_sram_check(
217  (check_config_t){.do_write = false, .is_equal = !scramble});
218  } else {
219  LOG_FATAL("Unexepected reset type detected.");
220  return false;
221  }
222 
223  return true;
224 }