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 void init_peripherals(void) {
61  // Initialize pwrmgr.
62  CHECK_DIF_OK(
64  &pwrmgr_actual));
65  pwrmgr = &pwrmgr_actual;
66 
67  // Initialize sysrst_ctrl.
68  CHECK_DIF_OK(dif_sysrst_ctrl_init(
70  &sysrst_ctrl_aon_actual));
71  sysrst_ctrl_aon = &sysrst_ctrl_aon_actual;
72 
73  // Initialize rstmgr to check the reset reason.
74  CHECK_DIF_OK(
76  &rstmgr_actual));
77  rstmgr = &rstmgr_actual;
78 
79  // Initialize aon timer to use the wdog.
80  CHECK_DIF_OK(dif_aon_timer_init(
82  &aon_timer_actual));
83  aon_timer = &aon_timer_actual;
84 
85  // Initialize flash_ctrl
86  CHECK_DIF_OK(dif_flash_ctrl_init_state(
87  &flash_ctrl_actual,
89  flash_ctrl = &flash_ctrl_actual;
90 
91  // Initialize plic.
92  CHECK_DIF_OK(dif_rv_plic_init(
94  plic = &plic_actual;
95 
96  rv_plic_testutils_irq_range_enable(
99 
100  // Initialize alert handler.
101  CHECK_DIF_OK(dif_alert_handler_init(
103  &alert_handler_actual));
104  alert_handler = &alert_handler_actual;
105 }
106 
107 void config_alert_handler(void) {
109  dif_alert_handler_class_t alert_classes[] = {kDifAlertHandlerClassA};
110 
111  uint32_t cycles[4] = {0};
112  CHECK_STATUS_OK(alert_handler_testutils_get_cycles_from_us(
113  kEscalationPhase0Micros, &cycles[0]));
114  CHECK_STATUS_OK(alert_handler_testutils_get_cycles_from_us(
115  kEscalationPhase1Micros, &cycles[1]));
116  CHECK_STATUS_OK(alert_handler_testutils_get_cycles_from_us(
117  kEscalationPhase2Micros, &cycles[2]));
118  CHECK_STATUS_OK(alert_handler_testutils_get_cycles_from_us(10, &cycles[3]));
119 
120  dif_alert_handler_escalation_phase_t esc_phases[] = {
122  .signal = 0,
123  .duration_cycles =
124  cycles[0] * alert_handler_testutils_cycle_rescaling_factor()},
126  .signal = 1,
127  .duration_cycles =
128  cycles[1] * alert_handler_testutils_cycle_rescaling_factor()},
130  .signal = 3,
131  .duration_cycles =
132  cycles[2] * alert_handler_testutils_cycle_rescaling_factor()}};
133 
134  dif_alert_handler_class_config_t class_config[] = {{
136  .accumulator_threshold = 0,
137  .irq_deadline_cycles =
138  cycles[3] * alert_handler_testutils_cycle_rescaling_factor(),
139  .escalation_phases = esc_phases,
140  .escalation_phases_len = ARRAYSIZE(esc_phases),
141  .crashdump_escalation_phase = kDifAlertHandlerClassStatePhase3,
142  }};
143 
144  dif_alert_handler_class_t classes[] = {kDifAlertHandlerClassA};
145  dif_alert_handler_config_t config = {
146  .alerts = alerts,
147  .alert_classes = alert_classes,
148  .alerts_len = ARRAYSIZE(alerts),
149  .classes = classes,
150  .class_configs = class_config,
151  .classes_len = ARRAYSIZE(class_config),
152  .ping_timeout = kAlertHandlerTestutilsDefaultPingTimeout,
153  };
154 
155  CHECK_STATUS_OK(alert_handler_testutils_configure_all(alert_handler, config,
157  // Enables alert handler irq.
158  CHECK_DIF_OK(dif_alert_handler_irq_set_enabled(
159  alert_handler, kDifAlertHandlerIrqClassa, kDifToggleEnabled));
160 }
161 
162 void config_sysrst(dif_pinmux_index_t pad_pin) {
163  LOG_INFO("sysrst enabled");
164 
165  // Set sysrst as a reset source.
167  kDifPwrmgrResetRequestSourceOne,
169  LOG_INFO("Reset Request SourceOne is set");
170 
171  // Configure sysrst key combo
172  // reset pulse : 50 us
173  // detect duration : 50 us
174 
175  dif_sysrst_ctrl_key_combo_config_t sysrst_ctrl_key_combo_config = {
177  .detection_time_threshold = 10,
179  .embedded_controller_reset_duration = 10};
180 
182  sysrst_ctrl_aon, kDifSysrstCtrlKeyCombo0, sysrst_ctrl_key_combo_config));
183  // Configure sysrst input change
184  // debounce duration : 100 us
185  dif_sysrst_ctrl_input_change_config_t sysrst_ctrl_input_change_config = {
186  .input_changes = kDifSysrstCtrlInputAll, .debounce_time_threshold = 20};
187 
188  // Configure pinmux
189  dif_pinmux_t pinmux;
190  CHECK_DIF_OK(dif_pinmux_init(
192 
194  sysrst_ctrl_aon, sysrst_ctrl_input_change_config));
195 
196  CHECK_DIF_OK(dif_pinmux_input_select(
198 }
199 
200 void config_wdog(uint64_t bark_micros, uint64_t bite_micros) {
201  uint32_t bark_cycles = 0;
202  CHECK_STATUS_OK(
203  aon_timer_testutils_get_aon_cycles_32_from_us(bark_micros, &bark_cycles));
204  uint32_t bite_cycles = 0;
205  CHECK_STATUS_OK(
206  aon_timer_testutils_get_aon_cycles_32_from_us(bite_micros, &bite_cycles));
207 
208  LOG_INFO("Wdog will bark after %u microseconds (%u aon cycles)",
209  (uint32_t)bark_micros, bark_cycles);
210  LOG_INFO("Wdog will bite after %u microseconds (%u aon cycles)",
211  (uint32_t)bite_micros, bite_cycles);
212 
213  // Setup the wdog bark and bite timeouts.
214  CHECK_STATUS_OK(aon_timer_testutils_watchdog_config(aon_timer, bark_cycles,
215  bite_cycles, false));
216  // Set wdog as a reset source.
218  kDifPwrmgrResetRequestSourceTwo,
220 }
221 
222 void trigger_escalation(void) {
223  // The relative times of escalation, time, and bark are set so the aon timer
224  // won't trigger bark nor bite.
225  config_wdog(
226  kWdogBarkMicros * alert_handler_testutils_cycle_rescaling_factor(),
227  kWdogBiteMicros * alert_handler_testutils_cycle_rescaling_factor());
228  // Trigger the alert handler to escalate.
229  dif_pwrmgr_alert_t alert = kDifPwrmgrAlertFatalFault;
230  CHECK_DIF_OK(dif_pwrmgr_alert_force(pwrmgr, alert));
231 
232  // If this busy spin expires the escalation didn't occur as expected.
233  busy_spin_micros(kWdogBiteMicros);
234  CHECK(false, "Timeout waiting for escalation to occur.");
235 }
236 
237 void prepare_for_wdog(pwrmgr_sleep_resets_lib_modes_t mode) {
238  if (mode == kPwrmgrSleepResetsLibModesActive) {
239  // Just wait for a reset.
240  busy_spin_micros(kWaitWhileActiveMicros);
241  } else {
242  bool deep_sleep = mode == kPwrmgrSleepResetsLibModesDeepSleep;
243  // Place device into low power.
245  deep_sleep ? 0
246  : kDifPwrmgrDomainOptionUsbClockInLowPower |
249  kDifPwrmgrDomainOptionMainPowerInLowPower;
250 
251  // Program the pwrmgr to go to deep sleep state (clocks off).
252  // Enter in low power mode.
253  CHECK_STATUS_OK(pwrmgr_testutils_enable_low_power(
254  pwrmgr, kDifPwrmgrWakeupRequestSourceTwo, config));
256  }
257  // If we arrive here the test must fail.
258  CHECK(false, "Failed to reset!");
259 }
260 
261 void prepare_for_sysrst(pwrmgr_sleep_resets_lib_modes_t mode) {
262  if (mode == kPwrmgrSleepResetsLibModesActive) {
263  LOG_INFO("Sysrst reset in active mode");
264  // Just wait for a reset.
265  busy_spin_micros(kWaitWhileActiveMicros);
266  } else {
267  bool deep_sleep = mode == kPwrmgrSleepResetsLibModesDeepSleep;
268  // Place device into low power.
270  deep_sleep ? 0
271  : kDifPwrmgrDomainOptionUsbClockInLowPower |
274  kDifPwrmgrDomainOptionMainPowerInLowPower;
275  CHECK_STATUS_OK(pwrmgr_testutils_enable_low_power(
276  pwrmgr, kDifPwrmgrWakeupRequestSourceOne, config));
277  // Log message to synchronize with host side: emit it as close as
278  // possible before WFI so the host has no chance of sending the reset
279  // before it is enabled.
280  LOG_INFO("Sysrst reset in %s sleep mode", deep_sleep ? "deep" : "normal");
281  // Enter in low power mode.
283  }
284  // If we arrive here the test must fail.
285  CHECK(false, "Failed to reset!");
286 }
287 
288 void ottf_external_isr(uint32_t *exc_info) {
290  dif_rv_plic_irq_id_t irq_id;
291  uint32_t irq = 0;
292  uint32_t alert = 0;
293 
294  CHECK_DIF_OK(dif_rv_plic_irq_claim(plic, kPlicTarget, &irq_id));
295 
296  peripheral = (top_earlgrey_plic_peripheral_t)
298 
299  if (peripheral == kTopEarlgreyPlicPeripheralAonTimerAon) {
300  irq =
301  (dif_aon_timer_irq_t)(irq_id -
304 
305  // Stops escalation process.
306  CHECK_DIF_OK(dif_alert_handler_escalation_clear(alert_handler,
307  kDifAlertHandlerClassA));
308  CHECK_DIF_OK(dif_aon_timer_irq_acknowledge(aon_timer, irq));
309 
311  "AON Timer Wdog should not bark");
312 
313  } else if (peripheral == kTopEarlgreyPlicPeripheralAlertHandler) {
314  irq = (dif_rv_plic_irq_id_t)(irq_id -
317 
318  CHECK_DIF_OK(dif_alert_handler_alert_acknowledge(alert_handler, alert));
319 
322  alert_handler, kDifAlertHandlerClassA, &state));
323 
324  CHECK(state == kDifAlertHandlerClassStatePhase0, "Wrong phase %d", state);
325 
326  CHECK_DIF_OK(dif_alert_handler_irq_acknowledge(alert_handler, irq));
327  }
328 
329  // Complete the IRQ by writing the IRQ source to the Ibex specific CC
330  // register.
331  CHECK_DIF_OK(dif_rv_plic_irq_complete(plic, kPlicTarget, irq_id));
332 }