Software APIs
pwrmgr_sleep_disabled_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 
9 #include "sw/device/lib/runtime/irq.h"
11 #include "sw/device/lib/testing/aon_timer_testutils.h"
12 #include "sw/device/lib/testing/pwrmgr_testutils.h"
13 #include "sw/device/lib/testing/test_framework/check.h"
15 
16 OTTF_DEFINE_TEST_CONFIG();
17 
18 static_assert(kDtPwrmgrCount == 1, "this test expects exactly one pwrmgr");
19 static const dt_pwrmgr_t kPwrmgrDt = 0;
20 static_assert(kDtRvPlicCount == 1, "this test expects exactly one rv_plic");
21 static const dt_rv_plic_t kRvPlicDt = 0;
22 static_assert(kDtAonTimerCount >= 1,
23  "this test expects at least one aon_timer");
24 static const dt_aon_timer_t kAonTimerDt = 0;
25 
26 static const uint32_t kPlicTarget = 0;
27 static const uint32_t kSourcePriority = 1;
28 static dif_aon_timer_t aon_timer;
29 static dif_rv_plic_t plic;
30 
31 // Volatile globals accessed from the ISR.
32 static volatile dif_aon_timer_irq_t irq;
33 static volatile bool interrupt_serviced = false;
34 
35 static bool is_pwrmgr_irq_pending(void) {
36  bool status;
37  dif_rv_plic_irq_id_t irq_id =
38  dt_pwrmgr_irq_to_plic_id(kPwrmgrDt, kDtPwrmgrIrqWakeup);
39  CHECK_DIF_OK(dif_rv_plic_irq_is_pending(&plic, irq_id, &status));
40  return status;
41 }
42 
43 /**
44  * External interrupt handler.
45  */
46 bool ottf_handle_irq(uint32_t *exc_info, dt_instance_id_t devid,
47  dif_rv_plic_irq_id_t irq_id) {
48  if (devid == dt_aon_timer_instance_id(kAonTimerDt) &&
49  irq_id == dt_aon_timer_irq_to_plic_id(kAonTimerDt,
50  kDtAonTimerIrqWkupTimerExpired)) {
51  CHECK_DIF_OK(dif_aon_timer_wakeup_stop(&aon_timer));
52  CHECK_DIF_OK(dif_aon_timer_irq_acknowledge(&aon_timer, irq));
53  interrupt_serviced = true;
54  return true;
55  } else {
56  return false;
57  }
58 }
59 
60 bool test_main(void) {
61  dif_pwrmgr_t pwrmgr;
62 
63  // Issue a wakeup signal in 200us through the AON timer.
64  //
65  // Adjust the cycles for Verilator since it runs on different clock
66  // frequencies.
67  uint64_t wakeup_cycles = 0;
68  uint32_t wakeup_time_micros = 200;
69  CHECK_STATUS_OK(aon_timer_testutils_get_aon_cycles_64_from_us(
70  wakeup_time_micros, &wakeup_cycles));
72  wakeup_cycles *= 10;
73  }
74 
75  // Initialize unit difs.
76  CHECK_DIF_OK(dif_pwrmgr_init_from_dt(kPwrmgrDt, &pwrmgr));
77  CHECK_DIF_OK(dif_aon_timer_init_from_dt(kAonTimerDt, &aon_timer));
78  CHECK_DIF_OK(dif_rv_plic_init_from_dt(kRvPlicDt, &plic));
79  dif_pwrmgr_request_sources_t wakeup_sources;
80  CHECK_DIF_OK(dif_pwrmgr_find_request_source(
81  &pwrmgr, kDifPwrmgrReqTypeWakeup, dt_aon_timer_instance_id(kAonTimerDt),
82  kDtAonTimerWakeupWkupReq, &wakeup_sources));
83 
84  // Notice we are clearing rstmgr's RESET_INFO, so after the aon wakeup there
85  // is only one bit set.
86  if (UNWRAP(pwrmgr_testutils_is_wakeup_reason(&pwrmgr, 0)) == true) {
87  LOG_INFO("POR reset");
88 
89  // Enable aon wakeup.
90  CHECK_DIF_OK(dif_pwrmgr_set_request_sources(
91  &pwrmgr, kDifPwrmgrReqTypeWakeup, wakeup_sources, kDifToggleEnabled));
92  LOG_INFO("Enabled aon wakeup");
93 
94  // Enable the AON wakeup interrupt.
95  dif_rv_plic_irq_id_t plic_id = dt_aon_timer_irq_to_plic_id(
96  kAonTimerDt, kDtAonTimerIrqWkupTimerExpired);
97  CHECK_DIF_OK(dif_rv_plic_irq_set_enabled(&plic, plic_id, kPlicTarget,
99  LOG_INFO("Enabled aon wakeup interrupt");
100  CHECK_DIF_OK(dif_rv_plic_irq_set_priority(&plic, plic_id, kSourcePriority));
101  LOG_INFO("Set aon wakeup interrupt priority");
102 
103  // Enable pwrmgr wakeup interrupt, so it triggers an interrupt even though
104  // it should not.
105  CHECK_DIF_OK(dif_pwrmgr_irq_set_enabled(&pwrmgr, kDifPwrmgrIrqWakeup,
107  plic_id = dt_pwrmgr_irq_to_plic_id(kPwrmgrDt, kDtPwrmgrIrqWakeup);
108  CHECK_DIF_OK(dif_rv_plic_irq_set_enabled(&plic, plic_id, kPlicTarget,
110  LOG_INFO("Enabled pwrmgr wakeup interrupt");
111  CHECK_DIF_OK(dif_rv_plic_irq_set_priority(&plic, plic_id, kSourcePriority));
112  LOG_INFO("Set pwrmgr wakeup interrupt priority");
113 
114  // Prepare for interrupt.
115  LOG_INFO("Issue WFI without sleep");
116 
117  // Start wakeup timer close enough to the WFI to avoid it happening
118  // too early.
119  CHECK_STATUS_OK(
120  aon_timer_testutils_wakeup_config(&aon_timer, wakeup_cycles));
121  irq_global_ctrl(true);
122  irq_external_ctrl(true);
123  ATOMIC_WAIT_FOR_INTERRUPT(interrupt_serviced);
124 
125  LOG_INFO("The interrupt was processed");
126  // And to be extra safe, check there is no pwrmgr interrupt pending.
127  CHECK(!is_pwrmgr_irq_pending());
128 
129  return true;
130  } else if (UNWRAP(pwrmgr_testutils_is_wakeup_reason(
131  &pwrmgr, wakeup_sources)) == true) {
132  LOG_ERROR("Unexpected wakeup request");
133  return false;
134  }
135 
136  return false;
137 }