Software APIs
aon_timer_wdog_bite_reset_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 
5 #include <limits.h>
6 #include <stdbool.h>
7 #include <stdint.h>
8 
15 #include "sw/device/lib/testing/aon_timer_testutils.h"
16 #include "sw/device/lib/testing/pwrmgr_testutils.h"
17 #include "sw/device/lib/testing/rstmgr_testutils.h"
18 #include "sw/device/lib/testing/test_framework/check.h"
20 
21 static const dt_pwrmgr_t kPwrmgrDt = 0;
22 static_assert(kDtPwrmgrCount == 1, "this library expects exactly one pwrmgr");
23 static const dt_rstmgr_t kRstmgrDt = 0;
24 static_assert(kDtRstmgrCount == 1, "this library expects exactly one rstmgr");
25 static const dt_aon_timer_t kAonTimerDt = 0;
26 static_assert(kDtAonTimerCount == 1,
27  "this library expects exactly one aon_timer");
28 
29 OTTF_DEFINE_TEST_CONFIG();
30 
31 static dif_pwrmgr_request_sources_t wakeup_sources;
32 static dif_pwrmgr_request_sources_t reset_sources;
33 
34 /**
35  * Configure the wdog.
36  */
37 static void config_wdog(const dif_aon_timer_t *aon_timer,
38  const dif_pwrmgr_t *pwrmgr, uint64_t bark_time_us,
39  uint64_t bite_time_us) {
40  uint32_t bark_cycles = 0;
41  CHECK_STATUS_OK(aon_timer_testutils_get_aon_cycles_32_from_us(bark_time_us,
42  &bark_cycles));
43  uint32_t bite_cycles = 0;
44  CHECK_STATUS_OK(aon_timer_testutils_get_aon_cycles_32_from_us(bite_time_us,
45  &bite_cycles));
46 
47  LOG_INFO("Wdog will bark after %u us and bite after %u us",
48  (uint32_t)bark_time_us, (uint32_t)bite_time_us);
49 
50  // Set wdog as a reset source.
51  CHECK_DIF_OK(dif_pwrmgr_set_request_sources(
52  pwrmgr, kDifPwrmgrReqTypeReset, reset_sources, kDifToggleEnabled));
53 
54  // Setup the wdog bark and bite timeouts.
55  CHECK_STATUS_OK(aon_timer_testutils_watchdog_config(
56  aon_timer, (uint32_t)bark_cycles, (uint32_t)bite_cycles, false));
57 }
58 
59 /**
60  * Execute the aon timer wdog bite reset test.
61  */
62 static void wdog_bite_test(const dif_aon_timer_t *aon_timer,
63  const dif_pwrmgr_t *pwrmgr, uint64_t bark_time_us) {
64  uint64_t bite_time_us = bark_time_us * 2;
65  config_wdog(aon_timer, pwrmgr, bark_time_us, bite_time_us);
66 
67  CHECK(bark_time_us <= UINT32_MAX, "bark_time_us must fit in a uint32_t");
68 
69  // The `intr_state` takes 3 aon clock cycles to rise plus 2 extra cycles as a
70  // precaution.
71  uint64_t aon_timer_clock_freq_hz = dt_clock_frequency(
72  dt_aon_timer_clock(kDtAonTimerAon, kDtAonTimerClockAon));
73  uint32_t wait_us =
74  (uint32_t)bark_time_us +
75  (uint32_t)udiv64_slow(5 * 1000000 + aon_timer_clock_freq_hz - 1,
76  aon_timer_clock_freq_hz, NULL);
77 
78  // Wait bark time and check that the bark interrupt requested.
79  busy_spin_micros(wait_us);
80  bool is_pending = false;
81  CHECK_DIF_OK(dif_aon_timer_irq_is_pending(
82  aon_timer, kDifAonTimerIrqWdogTimerBark, &is_pending));
83  CHECK(is_pending, "Wdog bark irq did not rise after %u microseconds",
84  wait_us);
85 
86  // Wait for the remaining time to the wdog bite.
87  busy_spin_micros(wait_us);
88  // If we arrive here the test must fail.
89  CHECK(false, "Timeout waiting for Wdog bite reset!");
90 }
91 
92 /**
93  * Execute the aon timer wdog bite reset during sleep test.
94  */
95 static void sleep_wdog_bite_test(const dif_aon_timer_t *aon_timer,
96  const dif_pwrmgr_t *pwrmgr,
97  uint64_t bark_time_us) {
98  uint64_t bite_time_us = bark_time_us * 2;
99  config_wdog(aon_timer, pwrmgr, bark_time_us, bite_time_us);
100 
101  // Program the pwrmgr to go to deep sleep state (clocks off).
102  CHECK_STATUS_OK(pwrmgr_testutils_enable_low_power(pwrmgr, wakeup_sources, 0));
103  // Enter in low power mode.
105  // If we arrive here the test must fail.
106  CHECK(false, "Fail to enter in low power mode!");
107 }
108 
109 bool test_main(void) {
110  // Initialize pwrmgr.
111  dif_pwrmgr_t pwrmgr;
112  CHECK_DIF_OK(dif_pwrmgr_init_from_dt(kPwrmgrDt, &pwrmgr));
113 
114  // Find wakeup and reset sources.
115  CHECK_DIF_OK(dif_pwrmgr_find_request_source(
116  &pwrmgr, kDifPwrmgrReqTypeReset, dt_aon_timer_instance_id(kAonTimerDt),
117  kDtAonTimerResetReqAonTimer, &reset_sources));
118  CHECK_DIF_OK(dif_pwrmgr_find_request_source(
119  &pwrmgr, kDifPwrmgrReqTypeWakeup, dt_aon_timer_instance_id(kAonTimerDt),
120  kDtAonTimerWakeupWkupReq, &wakeup_sources));
121 
122  // Initialize rstmgr to check the reset reason.
123  dif_rstmgr_t rstmgr;
124  CHECK_DIF_OK(dif_rstmgr_init_from_dt(kRstmgrDt, &rstmgr));
125 
126  // Initialize aon timer to use the wdog.
127  dif_aon_timer_t aon_timer;
128  CHECK_DIF_OK(dif_aon_timer_init_from_dt(kAonTimerDt, &aon_timer));
129 
130  // Check if there was a HW reset caused by the wdog bite.
132  rst_info = rstmgr_testutils_reason_get();
133  rstmgr_testutils_reason_clear();
134 
135  CHECK(rst_info == kDifRstmgrResetInfoPor ||
136  rst_info == kDifRstmgrResetInfoWatchdog ||
137  rst_info ==
138  (kDifRstmgrResetInfoWatchdog | kDifRstmgrResetInfoLowPowerExit),
139  "Wrong reset reason %02X", rst_info);
140 
141  if (rst_info == kDifRstmgrResetInfoPor) {
142  LOG_INFO("Booting for the first time, setting wdog");
143  // Executing the wdog bite reset test.
144  wdog_bite_test(&aon_timer, &pwrmgr, /*bark_time_us=*/200);
145  } else if (rst_info == kDifRstmgrResetInfoWatchdog) {
146  LOG_INFO("Booting for the second time due to wdog bite reset");
147  // Executing the wdog bite reset during sleep test.
148  sleep_wdog_bite_test(&aon_timer, &pwrmgr, /*bark_time_us=*/200);
149  } else if (rst_info ==
150  (kDifRstmgrResetInfoWatchdog | kDifRstmgrResetInfoLowPowerExit)) {
151  LOG_INFO("Booting for the third time due to wdog bite reset during sleep");
152  return true;
153  }
154 
155  return false;
156 }