Software APIs
pwrmgr_sleep_resets_lib.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/tests/pwrmgr_sleep_resets_lib.h"
6 
7 #include <assert.h>
8 #include <limits.h>
9 #include <stdbool.h>
10 #include <stdint.h>
11 
24 #include "sw/device/lib/runtime/irq.h"
26 #include "sw/device/lib/testing/alert_handler_testutils.h"
27 #include "sw/device/lib/testing/aon_timer_testutils.h"
28 #include "sw/device/lib/testing/pwrmgr_testutils.h"
29 #include "sw/device/lib/testing/rstmgr_testutils.h"
30 #include "sw/device/lib/testing/rv_plic_testutils.h"
31 #include "sw/device/lib/testing/test_framework/check.h"
32 
34 
35 static const uint32_t kPlicTarget = kTopEarlgreyPlicTargetIbex0;
36 
37 static_assert(
38  kWdogBarkMicros < kWdogBiteMicros &&
39  kWdogBarkMicros > kEscalationPhase0Micros &&
40  kWdogBarkMicros < (kEscalationPhase0Micros + kEscalationPhase1Micros) &&
41  kWdogBiteMicros < (kEscalationPhase0Micros + kEscalationPhase1Micros),
42  "The wdog bark and bite should happen during the escalation phase 1");
43 
44 dif_flash_ctrl_state_t *flash_ctrl;
45 dif_rv_plic_t *plic;
46 dif_alert_handler_t *alert_handler;
47 dif_aon_timer_t *aon_timer;
48 dif_pwrmgr_t *pwrmgr;
49 dif_sysrst_ctrl_t *sysrst_ctrl_aon;
50 dif_rstmgr_t *rstmgr;
51 
52 dif_flash_ctrl_state_t flash_ctrl_actual;
53 dif_rv_plic_t plic_actual;
54 dif_alert_handler_t alert_handler_actual;
55 dif_aon_timer_t aon_timer_actual;
56 dif_pwrmgr_t pwrmgr_actual;
57 dif_sysrst_ctrl_t sysrst_ctrl_aon_actual;
58 dif_rstmgr_t rstmgr_actual;
59 
60 static dif_pwrmgr_request_sources_t aon_timer_wakeup_sources;
61 static dif_pwrmgr_request_sources_t sysrst_ctrl_wakeup_sources;
62 
63 static const dt_rstmgr_t kRstmgrDt = 0;
64 static_assert(kDtRstmgrCount == 1, "this test expects a rstmgr");
65 static const dt_pwrmgr_t kPwrmgrDt = 0;
66 static_assert(kDtPwrmgrCount == 1, "this library expects exactly one pwrmgr");
67 static const dt_alert_handler_t kAlertHandlerDt = 0;
68 static_assert(kDtAlertHandlerCount == 1,
69  "this library expects exactly one alert_handler");
70 static const dt_aon_timer_t kAonTimerDt = 0;
71 static_assert(kDtAonTimerCount == 1,
72  "this library expects exactly one aon_timer");
73 static const dt_flash_ctrl_t kFlashCtrlDt = 0;
74 static_assert(kDtFlashCtrlCount >= 1,
75  "this test expects at least one flash_ctrl");
76 static_assert(kDtSysrstCtrlCount >= 1,
77  "this test expects at least one sysrst_ctrl");
78 static const dt_sysrst_ctrl_t kSysrstCtrlDt = 0;
79 static const dt_rv_plic_t kRvPlicDt = 0;
80 static_assert(kDtRvPlicCount >= 1, "this test expects at least one rv_plic");
81 
82 void init_peripherals(void) {
83  // Initialize pwrmgr.
84  CHECK_DIF_OK(dif_pwrmgr_init_from_dt(kPwrmgrDt, &pwrmgr_actual));
85  pwrmgr = &pwrmgr_actual;
86 
87  // Initialize sysrst_ctrl.
88  CHECK_DIF_OK(
89  dif_sysrst_ctrl_init_from_dt(kSysrstCtrlDt, &sysrst_ctrl_aon_actual));
90  sysrst_ctrl_aon = &sysrst_ctrl_aon_actual;
91 
92  // Initialize rstmgr to check the reset reason.
93  CHECK_DIF_OK(dif_rstmgr_init_from_dt(kRstmgrDt, &rstmgr_actual));
94  rstmgr = &rstmgr_actual;
95 
96  // Initialize aon timer to use the wdog.
97  CHECK_DIF_OK(dif_aon_timer_init_from_dt(kAonTimerDt, &aon_timer_actual));
98  aon_timer = &aon_timer_actual;
99 
100  // Initialize flash_ctrl
101  CHECK_DIF_OK(
102  dif_flash_ctrl_init_state_from_dt(&flash_ctrl_actual, kFlashCtrlDt));
103  flash_ctrl = &flash_ctrl_actual;
104 
105  // Initialize plic.
106  CHECK_DIF_OK(dif_rv_plic_init_from_dt(kRvPlicDt, &plic_actual));
107  plic = &plic_actual;
108 
109  rv_plic_testutils_irq_range_enable(
112 
113  // Initialize alert handler.
114  CHECK_DIF_OK(
115  dif_alert_handler_init_from_dt(kAlertHandlerDt, &alert_handler_actual));
116  alert_handler = &alert_handler_actual;
117 
118  // Wakeup sources.
119  CHECK_DIF_OK(dif_pwrmgr_find_request_source(
120  pwrmgr, kDifPwrmgrReqTypeWakeup, dt_aon_timer_instance_id(kAonTimerDt),
121  kDtAonTimerWakeupWkupReq, &aon_timer_wakeup_sources));
122  CHECK_DIF_OK(dif_pwrmgr_find_request_source(
123  pwrmgr, kDifPwrmgrReqTypeWakeup,
124  dt_sysrst_ctrl_instance_id(kSysrstCtrlDt), kDtSysrstCtrlWakeupWkupReq,
125  &sysrst_ctrl_wakeup_sources));
126 }
127 
128 void config_alert_handler(void) {
130  dif_alert_handler_class_t alert_classes[] = {kDifAlertHandlerClassA};
131 
132  uint32_t cycles[4] = {0};
133  CHECK_STATUS_OK(alert_handler_testutils_get_cycles_from_us(
134  kEscalationPhase0Micros, &cycles[0]));
135  CHECK_STATUS_OK(alert_handler_testutils_get_cycles_from_us(
136  kEscalationPhase1Micros, &cycles[1]));
137  CHECK_STATUS_OK(alert_handler_testutils_get_cycles_from_us(
138  kEscalationPhase2Micros, &cycles[2]));
139  CHECK_STATUS_OK(alert_handler_testutils_get_cycles_from_us(10, &cycles[3]));
140 
141  dif_alert_handler_escalation_phase_t esc_phases[] = {
143  .signal = 0,
144  .duration_cycles =
145  cycles[0] * alert_handler_testutils_cycle_rescaling_factor()},
147  .signal = 1,
148  .duration_cycles =
149  cycles[1] * alert_handler_testutils_cycle_rescaling_factor()},
151  .signal = 3,
152  .duration_cycles =
153  cycles[2] * alert_handler_testutils_cycle_rescaling_factor()}};
154 
155  dif_alert_handler_class_config_t class_config[] = {{
157  .accumulator_threshold = 0,
158  .irq_deadline_cycles =
159  cycles[3] * alert_handler_testutils_cycle_rescaling_factor(),
160  .escalation_phases = esc_phases,
161  .escalation_phases_len = ARRAYSIZE(esc_phases),
162  .crashdump_escalation_phase = kDifAlertHandlerClassStatePhase3,
163  }};
164 
165  dif_alert_handler_class_t classes[] = {kDifAlertHandlerClassA};
166  dif_alert_handler_config_t config = {
167  .alerts = alerts,
168  .alert_classes = alert_classes,
169  .alerts_len = ARRAYSIZE(alerts),
170  .classes = classes,
171  .class_configs = class_config,
172  .classes_len = ARRAYSIZE(class_config),
173  .ping_timeout = kAlertHandlerTestutilsDefaultPingTimeout,
174  };
175 
176  CHECK_STATUS_OK(alert_handler_testutils_configure_all(alert_handler, config,
178  // Enables alert handler irq.
179  CHECK_DIF_OK(dif_alert_handler_irq_set_enabled(
180  alert_handler, kDifAlertHandlerIrqClassa, kDifToggleEnabled));
181 }
182 
183 void config_sysrst(dif_pinmux_index_t pad_pin) {
184  LOG_INFO("sysrst enabled");
185 
186  // Set sysrst as a reset source.
187  dif_pwrmgr_request_sources_t reset_sources;
188  CHECK_DIF_OK(dif_pwrmgr_find_request_source(
189  pwrmgr, kDifPwrmgrReqTypeReset, dt_sysrst_ctrl_instance_id(kSysrstCtrlDt),
190  kDtSysrstCtrlResetReqRstReq, &reset_sources));
191  CHECK_DIF_OK(dif_pwrmgr_set_request_sources(
192  pwrmgr, kDifPwrmgrReqTypeReset, reset_sources, kDifToggleEnabled));
193  LOG_INFO("Reset Request SourceOne is set");
194 
195  // Configure sysrst key combo
196  // reset pulse : 50 us
197  // detect duration : 50 us
198 
199  dif_sysrst_ctrl_key_combo_config_t sysrst_ctrl_key_combo_config = {
201  .detection_time_threshold = 10,
203  .embedded_controller_reset_duration = 10};
204 
206  sysrst_ctrl_aon, kDifSysrstCtrlKeyCombo0, sysrst_ctrl_key_combo_config));
207  // Configure sysrst input change
208  // debounce duration : 100 us
209  dif_sysrst_ctrl_input_change_config_t sysrst_ctrl_input_change_config = {
210  .input_changes = kDifSysrstCtrlInputAll, .debounce_time_threshold = 20};
211 
212  // Configure pinmux
213  dif_pinmux_t pinmux;
214  CHECK_DIF_OK(dif_pinmux_init(
216 
218  sysrst_ctrl_aon, sysrst_ctrl_input_change_config));
219 
220  CHECK_DIF_OK(dif_pinmux_input_select(
222 }
223 
224 void config_wdog(uint64_t bark_micros, uint64_t bite_micros) {
225  uint32_t bark_cycles = 0;
226  CHECK_STATUS_OK(
227  aon_timer_testutils_get_aon_cycles_32_from_us(bark_micros, &bark_cycles));
228  uint32_t bite_cycles = 0;
229  CHECK_STATUS_OK(
230  aon_timer_testutils_get_aon_cycles_32_from_us(bite_micros, &bite_cycles));
231 
232  LOG_INFO("Wdog will bark after %u microseconds (%u aon cycles)",
233  (uint32_t)bark_micros, bark_cycles);
234  LOG_INFO("Wdog will bite after %u microseconds (%u aon cycles)",
235  (uint32_t)bite_micros, bite_cycles);
236 
237  // Setup the wdog bark and bite timeouts.
238  CHECK_STATUS_OK(aon_timer_testutils_watchdog_config(aon_timer, bark_cycles,
239  bite_cycles, false));
240  // Set wdog as a reset source.
241  dif_pwrmgr_request_sources_t reset_sources;
242  CHECK_DIF_OK(dif_pwrmgr_find_request_source(
243  pwrmgr, kDifPwrmgrReqTypeReset, dt_aon_timer_instance_id(kDtAonTimerAon),
244  kDtAonTimerResetReqAonTimer, &reset_sources));
245  CHECK_DIF_OK(dif_pwrmgr_set_request_sources(
246  pwrmgr, kDifPwrmgrReqTypeReset, reset_sources, kDifToggleEnabled));
247 }
248 
249 void trigger_escalation(void) {
250  // The relative times of escalation, time, and bark are set so the aon timer
251  // won't trigger bark nor bite.
252  config_wdog(
253  kWdogBarkMicros * alert_handler_testutils_cycle_rescaling_factor(),
254  kWdogBiteMicros * alert_handler_testutils_cycle_rescaling_factor());
255  // Trigger the alert handler to escalate.
256  dif_pwrmgr_alert_t alert = kDifPwrmgrAlertFatalFault;
257  CHECK_DIF_OK(dif_pwrmgr_alert_force(pwrmgr, alert));
258 
259  // If this busy spin expires the escalation didn't occur as expected.
260  busy_spin_micros(kWdogBiteMicros);
261  CHECK(false, "Timeout waiting for escalation to occur.");
262 }
263 
264 void prepare_for_wdog(pwrmgr_sleep_resets_lib_modes_t mode) {
265  if (mode == kPwrmgrSleepResetsLibModesActive) {
266  // Just wait for a reset.
267  busy_spin_micros(kWaitWhileActiveMicros);
268  } else {
269  bool deep_sleep = mode == kPwrmgrSleepResetsLibModesDeepSleep;
270  // Place device into low power.
272  deep_sleep ? 0
273  : kDifPwrmgrDomainOptionUsbClockInLowPower |
276  kDifPwrmgrDomainOptionMainPowerInLowPower;
277 
278  // Program the pwrmgr to go to deep sleep state (clocks off).
279  // Enter in low power mode. Choose a wakeup source different
280  // from the aon_timer (we expect a reset, not a wakeup).
281  CHECK_STATUS_OK(pwrmgr_testutils_enable_low_power(
282  pwrmgr, sysrst_ctrl_wakeup_sources, config));
284  }
285  // If we arrive here the test must fail.
286  CHECK(false, "Failed to reset!");
287 }
288 
289 void prepare_for_sysrst(pwrmgr_sleep_resets_lib_modes_t mode) {
290  if (mode == kPwrmgrSleepResetsLibModesActive) {
291  LOG_INFO("Sysrst reset in active mode");
292  // Just wait for a reset.
293  busy_spin_micros(kWaitWhileActiveMicros);
294  } else {
295  bool deep_sleep = mode == kPwrmgrSleepResetsLibModesDeepSleep;
296  // Place device into low power.
298  deep_sleep ? 0
299  : kDifPwrmgrDomainOptionUsbClockInLowPower |
302  kDifPwrmgrDomainOptionMainPowerInLowPower;
303  CHECK_STATUS_OK(pwrmgr_testutils_enable_low_power(
304  pwrmgr, sysrst_ctrl_wakeup_sources, config));
305  // Log message to synchronize with host side: emit it as close as
306  // possible before WFI so the host has no chance of sending the reset
307  // before it is enabled.
308  LOG_INFO("Sysrst reset in %s sleep mode", deep_sleep ? "deep" : "normal");
309  // Enter in low power mode.
311  }
312  // If we arrive here the test must fail.
313  CHECK(false, "Failed to reset!");
314 }
315 
316 void ottf_external_isr(uint32_t *exc_info) {
318  dif_rv_plic_irq_id_t irq_id;
319  uint32_t irq = 0;
320  uint32_t alert = 0;
321 
322  CHECK_DIF_OK(dif_rv_plic_irq_claim(plic, kPlicTarget, &irq_id));
323 
324  peripheral = (top_earlgrey_plic_peripheral_t)
326 
327  if (peripheral == kTopEarlgreyPlicPeripheralAonTimerAon) {
328  irq =
329  (dif_aon_timer_irq_t)(irq_id -
332 
333  // Stops escalation process.
334  CHECK_DIF_OK(dif_alert_handler_escalation_clear(alert_handler,
335  kDifAlertHandlerClassA));
336  CHECK_DIF_OK(dif_aon_timer_irq_acknowledge(aon_timer, irq));
337 
339  "AON Timer Wdog should not bark");
340 
341  } else if (peripheral == kTopEarlgreyPlicPeripheralAlertHandler) {
342  irq = (dif_rv_plic_irq_id_t)(irq_id -
345 
346  CHECK_DIF_OK(dif_alert_handler_alert_acknowledge(alert_handler, alert));
347 
350  alert_handler, kDifAlertHandlerClassA, &state));
351 
352  CHECK(state == kDifAlertHandlerClassStatePhase0, "Wrong phase %d", state);
353 
354  CHECK_DIF_OK(dif_alert_handler_irq_acknowledge(alert_handler, irq));
355  }
356 
357  // Complete the IRQ by writing the IRQ source to the Ibex specific CC
358  // register.
359  CHECK_DIF_OK(dif_rv_plic_irq_complete(plic, kPlicTarget, irq_id));
360 }