Software APIs
pwrmgr_sensor_ctrl_deep_sleep_wake_up.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/pwrmgr_testutils.h"
12 #include "sw/device/lib/testing/rv_plic_testutils.h"
13 #include "sw/device/lib/testing/test_framework/check.h"
15 
16 dif_pwrmgr_t pwrmgr;
17 dif_rv_plic_t rv_plic;
18 dif_sensor_ctrl_t sensor_ctrl;
19 
20 enum {
21  kPlicTarget = 0,
22 };
23 
24 static const dt_pwrmgr_t kPwrmgrDt = 0;
25 static_assert(kDtPwrmgrCount == 1, "this library expects exactly one pwrmgr");
26 static const dt_rv_plic_t kRvPlicDt = 0;
27 static_assert(kDtRvPlicCount == 1, "this library expects exactly one rv_plic");
28 static const dt_sensor_ctrl_t kSensorCtrlDt = 0;
29 static_assert(kDtSensorCtrlCount == 1,
30  "this library expects exactly one sensor_ctrl");
31 
32 /*
33  PWRMGR SENSOR_CTRL SLEEP WAKE UP TEST
34 
35  This test runs power manager wake up from deep sleep mode to be woken
36  up by sensor_ctrl via AST inputs.
37  */
38 
39 OTTF_DEFINE_TEST_CONFIG();
40 
41 /**
42  * Clean up pwrmgr wakeup reason register for the next round.
43  */
44 static bool pwrmgr_wake_status_is_clear(void) {
47  &pwrmgr, kDifPwrmgrReqTypeWakeup, &sources));
48  return sources == 0;
49 }
50 
51 static status_t wait_for_pwrmgr_wake_status_is_clear(void) {
52  IBEX_TRY_SPIN_FOR(pwrmgr_wake_status_is_clear(), 20);
53  return OK_STATUS();
54 }
55 
56 /**
57  * External interrupt handler.
58  */
59 bool ottf_handle_irq(uint32_t *exc_info, dt_instance_id_t devid,
60  dif_rv_plic_irq_id_t irq_id) {
61  if (devid == dt_pwrmgr_instance_id(kPwrmgrDt) &&
62  irq_id == dt_pwrmgr_irq_to_plic_id(kPwrmgrDt, kDtPwrmgrIrqWakeup)) {
63  CHECK_DIF_OK(dif_pwrmgr_irq_acknowledge(&pwrmgr, kDtPwrmgrIrqWakeup));
64  return true;
65  } else {
66  return false;
67  }
68 }
69 
70 bool test_main(void) {
71  // Enable global and external IRQ at Ibex.
72  irq_global_ctrl(true);
73  irq_external_ctrl(true);
74 
75  CHECK_DIF_OK(dif_pwrmgr_init_from_dt(kPwrmgrDt, &pwrmgr));
76  CHECK_DIF_OK(dif_rv_plic_init_from_dt(kRvPlicDt, &rv_plic));
77  CHECK_DIF_OK(dif_sensor_ctrl_init_from_dt(kSensorCtrlDt, &sensor_ctrl));
78  // Enable all the AON interrupts used in this test.
79  dif_rv_plic_irq_id_t irq_id =
80  dt_pwrmgr_irq_to_plic_id(kPwrmgrDt, kDtPwrmgrIrqWakeup);
81  rv_plic_testutils_irq_range_enable(&rv_plic, kPlicTarget, irq_id, irq_id);
82  // Enable pwrmgr interrupt
83  CHECK_DIF_OK(dif_pwrmgr_irq_set_enabled(&pwrmgr, 0, kDifToggleEnabled));
84 
85  dif_pwrmgr_wakeup_reason_t wakeup_reason;
86  CHECK_DIF_OK(dif_pwrmgr_wakeup_reason_get(&pwrmgr, &wakeup_reason));
87 
88  if (wakeup_reason.request_sources == 0) {
89  // This is a POR. Prepare to start the test.
90  CHECK_DIF_OK(dif_pwrmgr_wakeup_reason_clear(&pwrmgr));
92  &pwrmgr, kDifToggleEnabled));
93  // This enters deep sleep, so the clock control bits are irrelevant since
94  // they are reset on wakeup.
95  CHECK_STATUS_OK(pwrmgr_testutils_enable_low_power(
96  &pwrmgr, kDifPwrmgrWakeupRequestSourceSix, 0));
97  LOG_INFO("Issue WFI to enter sensor_ctrl sleep");
99 
100  // This is not reachable.
101  return false;
102  } else if (wakeup_reason.types != kDifPwrmgrWakeupTypeRequest) {
103  LOG_ERROR("Unexpected wakeup_reason.types 0x%x", wakeup_reason.types);
104  return false;
105  } else {
106  // This is a reset from deep_sleep due to sensor_ctrl wakeup.
107  LOG_INFO("Woke up by sensor_ctrl");
109  CHECK(!pwrmgr_wake_status_is_clear(), "Expected wake_status to be set");
110  CHECK_DIF_OK(dif_sensor_ctrl_get_recov_events(&sensor_ctrl, &events));
111  CHECK(events == 1, "Expected bit 0 to be set");
112  CHECK_DIF_OK(dif_sensor_ctrl_clear_recov_event(&sensor_ctrl, 0));
113  CHECK_DIF_OK(dif_sensor_ctrl_get_recov_events(&sensor_ctrl, &events));
114  CHECK(events == 0, "Expected recoverable events to clear");
115  CHECK_STATUS_OK(wait_for_pwrmgr_wake_status_is_clear(), 20);
116  return true;
117  }
118 }