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 
22 #include "sw/device/lib/testing/autogen/isr_testutils.h"
23 
24 enum {
25  /**
26  * Retention SRAM start address (inclusive).
27  */
29 
30  kRetSramOwnerAddr = kRetSramBaseAddr + offsetof(retention_sram_t, owner),
31  kRetRamLastAddr =
32  kRetSramBaseAddr + TOP_EARLGREY_SRAM_CTRL_RET_AON_RAM_SIZE_BYTES - 1,
33 
34  kTestBufferSizeWords = 16,
35 };
36 
37 static dif_rv_plic_t rv_plic;
38 static dif_aon_timer_t aon_timer;
39 static dif_pwrmgr_t pwrmgr;
40 static dif_rstmgr_t rstmgr;
41 static plic_isr_ctx_t plic_ctx = {.rv_plic = &rv_plic,
42  .hart_id = kTopEarlgreyPlicTargetIbex0};
43 static pwrmgr_isr_ctx_t pwrmgr_isr_ctx = {
44  .pwrmgr = &pwrmgr,
45  .plic_pwrmgr_start_irq_id = kTopEarlgreyPlicIrqIdPwrmgrAonWakeup,
46  .expected_irq = kDifPwrmgrIrqWakeup,
47  .is_only_irq = true};
48 
49 // Random data to read/write to/from retention SRAM.
50 const uint32_t kTestData[kTestBufferSizeWords] = {
51  0xe647e5d5, 0x4b5fe6f6, 0x1608a98a, 0x5e347116, 0xb2dc5e92, 0x899e3c0f,
52  0xc98295c2, 0x0fa84434, 0x15747561, 0xfecb5aa1, 0x7a78bb8c, 0x8f9c5d0f,
53  0x49338fbd, 0x093e82cb, 0xaaa58121, 0x5b806f96,
54 };
55 
56 typedef struct {
57  bool do_write;
58  bool is_equal;
60 
61 static void retention_sram_check(check_config_t config) {
62  if (config.do_write) {
63  sram_ctrl_testutils_write(
64  kRetSramOwnerAddr,
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 *)kRetSramOwnerAddr, 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 void ottf_external_isr(uint32_t *exc_info) {
91  dif_pwrmgr_irq_t irq_id;
93 
94  isr_testutils_pwrmgr_isr(plic_ctx, pwrmgr_isr_ctx, &peripheral, &irq_id);
95 
96  LOG_INFO("Receive irq in normal sleep");
97  // Check that both the peripheral and the irq id are correct.
98  CHECK(peripheral == kTopEarlgreyPlicPeripheralPwrmgrAon,
99  "IRQ peripheral: %d is incorrect", peripheral);
100  CHECK(irq_id == kDifPwrmgrIrqWakeup, "IRQ ID: %d is incorrect", irq_id);
101 }
102 
103 // test these 2 cases:
104 // normal sleep, no scrambling -> data preserved
105 // normal sleep, with scrambling -> data preserved
106 void test_ret_sram_in_normal_sleep(void) {
107  // Write data to retention SRAM and readback (to test basic functionality.)
108  retention_sram_check((check_config_t){.do_write = true, .is_equal = true});
109 
110  // set up wakeup timer
111  CHECK_STATUS_OK(aon_timer_testutils_wakeup_config(&aon_timer, 20));
112  // Enable all the AON interrupts used in this test.
113  rv_plic_testutils_irq_range_enable(&rv_plic, kTopEarlgreyPlicTargetIbex0,
116  CHECK_DIF_OK(dif_pwrmgr_irq_set_enabled(&pwrmgr, 0, kDifToggleEnabled));
117 
118  // Normal sleep.
119  CHECK_STATUS_OK(pwrmgr_testutils_enable_low_power(
120  &pwrmgr, /*wakeups=*/kDifPwrmgrWakeupRequestSourceFive,
122  kDifPwrmgrDomainOptionUsbClockInActivePower |
123  kDifPwrmgrDomainOptionMainPowerInLowPower));
124  // Enter low power mode.
125  LOG_INFO("Issue WFI to enter normal sleep");
127  // data preserved
128  retention_sram_check((check_config_t){.do_write = false, .is_equal = true});
129 }
130 
131 // test these 2 cases:
132 // deep sleep, no scrambling -> data preserved
133 // deep sleep, with scrambling -> data preserved
134 void enter_deep_sleep(void) {
135  // Prepare rstmgr for a reset.
136  CHECK_STATUS_OK(rstmgr_testutils_pre_reset(&rstmgr));
137  // set up wakeup timer
138  CHECK_STATUS_OK(aon_timer_testutils_wakeup_config(&aon_timer, 20));
139  // Deep sleep.
140  CHECK_STATUS_OK(pwrmgr_testutils_enable_low_power(
141  &pwrmgr, kDifPwrmgrWakeupRequestSourceFive, 0));
142 
143  // Enter low power mode.
144  LOG_INFO("Issue WFI to enter deep sleep");
146  CHECK(false, "Should have a reset to CPU before this line");
147 }
148 
149 void set_up_reset_request(void) {
150  // Prepare rstmgr for a reset.
151  CHECK_STATUS_OK(rstmgr_testutils_pre_reset(&rstmgr));
153  kDifPwrmgrResetRequestSourceTwo,
155 
156  CHECK_DIF_OK(dif_aon_timer_wakeup_stop(&aon_timer));
157 
158  // Enter low power mode. Use UINT32_MAX as wakeup threshold as UINT64_MAX far
159  // too long a timeout.
160  CHECK_STATUS_OK(aon_timer_testutils_watchdog_config(
161  &aon_timer, (uint64_t)UINT32_MAX, 20, false));
162  LOG_INFO("wait for reset");
164  CHECK(false, "Should have a reset to CPU and ret_sram before this line");
165 }
166 
167 bool execute_sram_ctrl_sleep_ret_sram_contents_test(bool scramble) {
168  // Enable global and external IRQ at Ibex.
169  irq_global_ctrl(true);
170  irq_external_ctrl(true);
171 
173  CHECK_DIF_OK(dif_pwrmgr_init(addr, &pwrmgr));
175  CHECK_DIF_OK(dif_rstmgr_init(addr, &rstmgr));
177  CHECK_DIF_OK(dif_aon_timer_init(addr, &aon_timer));
179  CHECK_DIF_OK(dif_rv_plic_init(addr, &rv_plic));
180 
181  dif_rstmgr_reset_info_bitfield_t rstmgr_reset_info;
182  rstmgr_reset_info = rstmgr_testutils_reason_get();
183 
184  LOG_INFO("Reset info = %08x", rstmgr_reset_info);
185 
186  if (rstmgr_reset_info == kDifRstmgrResetInfoPor) {
187  LOG_INFO("POR reset");
188  LOG_INFO("Start to test retention sram %sscrambled",
189  scramble ? "" : "not ");
190 
191  if (scramble) {
192  dif_sram_ctrl_t ret_sram;
193  addr =
195  CHECK_DIF_OK(dif_sram_ctrl_init(addr, &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, kDifPwrmgrWakeupRequestSourceFive)) == 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 }