Software APIs
pwrmgr_lowpower_cancel_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 
11 #include "sw/device/lib/runtime/irq.h"
13 #include "sw/device/lib/testing/aon_timer_testutils.h"
14 #include "sw/device/lib/testing/pwrmgr_testutils.h"
15 #include "sw/device/lib/testing/rv_plic_testutils.h"
16 #include "sw/device/lib/testing/test_framework/check.h"
18 
20 #include "pwrmgr_regs.h"
21 
22 dif_pwrmgr_t pwrmgr;
23 dif_rv_plic_t rv_plic;
24 
25 static dif_pwrmgr_request_sources_t wakeup_src =
26  kDifPwrmgrWakeupRequestSourceFive;
27 static uint32_t wakeup_source = PWRMGR_PARAM_AON_TIMER_AON_WKUP_REQ_IDX;
28 
29 static dif_aon_timer_t timer;
30 
31 void ottf_external_isr(uint32_t *exc_info) {
32  dif_rv_plic_irq_id_t irq_id;
33  CHECK_DIF_OK(
35 
38 
39  if (peripheral == kTopEarlgreyPlicPeripheralAonTimerAon) {
40  LOG_INFO("AON Timer ISR");
41  dif_aon_timer_irq_t irq =
42  (dif_aon_timer_irq_t)(irq_id -
45 
47  CHECK_DIF_OK(dif_aon_timer_wakeup_stop(&timer));
48  } else if (irq_id == kTopEarlgreyPlicIrqIdAonTimerAonWdogTimerBark) {
49  CHECK_DIF_OK(dif_aon_timer_watchdog_stop(&timer));
50  }
51  CHECK_DIF_OK(dif_aon_timer_irq_acknowledge(&timer, irq));
52  bool is_pending = true;
53  CHECK_DIF_OK(dif_aon_timer_irq_is_pending(
54  &timer, kDifAonTimerIrqWkupTimerExpired, &is_pending));
55  CHECK(!is_pending);
56  } else if (peripheral == kTopEarlgreyPlicPeripheralPwrmgrAon) {
57  LOG_INFO("Pwrmgr ISR");
58  dif_pwrmgr_irq_t irq =
59  (dif_pwrmgr_irq_t)(irq_id - (dif_rv_plic_irq_id_t)
61  CHECK(irq == kDifPwrmgrIrqWakeup, "Pwrmgr IRQ ID: %d is incorrect", irq);
62  CHECK_DIF_OK(dif_pwrmgr_irq_acknowledge(&pwrmgr, irq));
63  } else {
64  CHECK(false, "IRQ peripheral: %d is incorrect", peripheral);
65  }
66 
67  // Complete the IRQ by writing the IRQ source to the Ibex specific CC.
68  // register
69  CHECK_DIF_OK(
71 }
72 
73 static bool get_wakeup_status(void) {
74  dif_pwrmgr_request_sources_t wake_req = ~0u;
76  &pwrmgr, kDifPwrmgrReqTypeWakeup, &wake_req));
77  return (wake_req > 0);
78 }
79 
80 static void clear_wakeup(void) {
81  CHECK_DIF_OK(dif_aon_timer_clear_wakeup_cause(&timer));
82  // Ensure the de-asserted events have cleared from the wakeup pipeline
83  // within 100us.
84  IBEX_SPIN_FOR(!get_wakeup_status(), 100);
85  CHECK_DIF_OK(dif_pwrmgr_wakeup_reason_clear(&pwrmgr));
86 }
87 
88 static void test_init(void) {
89  irq_global_ctrl(true);
90  irq_external_ctrl(true);
91 
92  CHECK_DIF_OK(dif_pwrmgr_init(
94  CHECK_DIF_OK(dif_rv_plic_init(
96 
97  // Enable AON interrupts.
98  rv_plic_testutils_irq_range_enable(&rv_plic, kTopEarlgreyPlicTargetIbex0,
101  rv_plic_testutils_irq_range_enable(
102  &rv_plic, kTopEarlgreyPlicTargetIbex0,
105 
106  // Enable pwrmgr interrupt
107  CHECK_DIF_OK(dif_pwrmgr_irq_set_enabled(&pwrmgr, 0, kDifToggleEnabled));
108 
109  CHECK_DIF_OK(dif_aon_timer_init(
111  CHECK_DIF_OK(dif_aon_timer_wakeup_stop(&timer));
112 }
113 
114 static void set_timer(uint64_t time) {
115  uint32_t cycles = 0;
116  CHECK_STATUS_OK(aon_timer_testutils_get_aon_cycles_32_from_us(time, &cycles));
117  CHECK_STATUS_OK(aon_timer_testutils_wakeup_config(&timer, cycles));
118 }
119 
120 static bool lowpower_hint_is_cleared(void) {
121  dif_toggle_t low_power_enabled = kDifToggleEnabled;
122  CHECK_DIF_OK(dif_pwrmgr_low_power_get_enabled(&pwrmgr, &low_power_enabled));
123  return low_power_enabled == kDifToggleDisabled;
124 }
125 
126 static void test_sleep(bool wfi_fallthrough) {
127  LOG_INFO("Low power WFI (fallthrough=%d)", wfi_fallthrough);
128 
129  dif_pwrmgr_domain_config_t domain_config =
130  kDifPwrmgrDomainOptionMainPowerInLowPower;
131  CHECK_STATUS_OK(
132  pwrmgr_testutils_enable_low_power(&pwrmgr, wakeup_src, domain_config));
133  irq_global_ctrl(false);
134  if (wfi_fallthrough) {
135  LOG_INFO("Fallthough WFI due to timer pending");
136  set_timer(100);
137  busy_spin_micros(200);
138  } else {
139  set_timer(100);
140  }
142  LOG_INFO("Woke up by source %d", wakeup_source);
145  IBEX_SPIN_FOR(lowpower_hint_is_cleared(), 100);
146  irq_global_ctrl(true);
147  clear_wakeup();
148 
149  LOG_INFO("Normal WFI");
150  // Now do WFI without the LOW_POWER_HINT.
151  irq_global_ctrl(false);
152  set_timer(100);
154  irq_global_ctrl(true);
155 }
156 
157 OTTF_DEFINE_TEST_CONFIG();
158 
159 bool test_main(void) {
160  test_init();
161  if (UNWRAP(pwrmgr_testutils_is_wakeup_reason(&pwrmgr, 0)) != true) {
162  return false;
163  }
164  test_sleep(false);
165  test_sleep(true);
166  return true;
167 }