Software APIs
sensor_ctrl_wakeup_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 
10 #include "sw/device/lib/runtime/irq.h"
12 #include "sw/device/lib/testing/pwrmgr_testutils.h"
13 #include "sw/device/lib/testing/rv_plic_testutils.h"
14 #include "sw/device/lib/testing/test_framework/check.h"
16 
18 #include "sensor_ctrl_regs.h" // Generated.
19 #include "sw/device/lib/testing/autogen/isr_testutils.h"
20 
21 OTTF_DEFINE_TEST_CONFIG();
22 
23 static dif_pwrmgr_t pwrmgr;
24 static dif_rv_plic_t plic;
25 static plic_isr_ctx_t plic_ctx = {.rv_plic = &plic,
26  .hart_id = kTopEarlgreyPlicTargetIbex0};
27 
28 static pwrmgr_isr_ctx_t pwrmgr_isr_ctx = {
29  .pwrmgr = &pwrmgr,
30  .plic_pwrmgr_start_irq_id = kTopEarlgreyPlicIrqIdPwrmgrAonWakeup,
31  .expected_irq = kDifPwrmgrIrqWakeup,
32  .is_only_irq = true};
33 
34 static bool get_wakeup_status(void) {
35  dif_pwrmgr_request_sources_t wake_req = ~0u;
37  &pwrmgr, kDifPwrmgrReqTypeWakeup, &wake_req));
38  return (wake_req > 0);
39 }
40 
41 /**
42  * External interrupt handler.
43  */
44 void ottf_external_isr(uint32_t *exc_info) {
45  dif_pwrmgr_irq_t irq_id;
47 
48  isr_testutils_pwrmgr_isr(plic_ctx, pwrmgr_isr_ctx, &peripheral, &irq_id);
49 
50  // Check that both the peripheral and the irq id is correct
51  CHECK(peripheral == kTopEarlgreyPlicPeripheralPwrmgrAon,
52  "IRQ peripheral: %d is incorrect", peripheral);
53  CHECK(irq_id == kDifPwrmgrIrqWakeup, "IRQ ID: %d is incorrect", irq_id);
54 }
55 
56 bool test_main(void) {
57  dif_sensor_ctrl_t sensor_ctrl;
58 
59  // Enable global and external IRQ at Ibex.
60  irq_global_ctrl(true);
61  irq_external_ctrl(true);
62 
63  // Initialize the PLIC.
64  mmio_region_t plic_base_addr =
66  CHECK_DIF_OK(dif_rv_plic_init(plic_base_addr, &plic));
67 
68  // Initialize pwrmgr
69  CHECK_DIF_OK(dif_pwrmgr_init(
71 
72  // Initialize sensor_ctrl
73  CHECK_DIF_OK(dif_sensor_ctrl_init(
75  &sensor_ctrl));
76 
77  // Enable all the AON interrupts used in this test.
78  rv_plic_testutils_irq_range_enable(&plic, kTopEarlgreyPlicTargetIbex0,
81 
82  // Enable pwrmgr interrupt
83  CHECK_DIF_OK(dif_pwrmgr_irq_set_enabled(&pwrmgr, 0, kDifToggleEnabled));
84 
85  // Capture the number of events to test
86  uint32_t sensor_ctrl_events = SENSOR_CTRL_PARAM_NUM_ALERT_EVENTS;
87 
88  dif_pwrmgr_domain_config_t sleep_config =
89  kDifPwrmgrDomainOptionMainPowerInLowPower;
90 
91  // Clear any prior events before we start the test
92  for (size_t i = 0; i < sensor_ctrl_events; ++i) {
93  CHECK_DIF_OK(dif_sensor_ctrl_clear_recov_event(&sensor_ctrl, i));
94  }
95 
96  for (size_t i = 0; i < sensor_ctrl_events; ++i) {
97  LOG_INFO("Testing sensor_ctrl event %d", i);
98 
99  // Enable the alert on the sensor_ctrl side
100  CHECK_DIF_OK(
102 
103  // Setup event trigger
104  CHECK_DIF_OK(dif_sensor_ctrl_set_ast_event_trigger(&sensor_ctrl, i,
106 
107  // Normal sleep.
108  CHECK_STATUS_OK(pwrmgr_testutils_enable_low_power(
109  &pwrmgr, kDifPwrmgrWakeupRequestSourceSix, sleep_config));
110 
111  // Enter low power mode.
112  LOG_INFO("Issue WFI to enter sleep");
114 
115  // Wakeup from sleep.
116  LOG_INFO("Wake from sleep");
117 
119  CHECK_DIF_OK(dif_sensor_ctrl_get_recov_events(&sensor_ctrl, &events));
120 
121  if (events != (1 << i)) {
122  LOG_ERROR("Recoverable event 0x%x does not match expectation %d", events,
123  i);
124  }
125 
126  // Disable the alert on the sensor_ctrl side
127  CHECK_DIF_OK(
129 
130  // clear event trigger
131  CHECK_DIF_OK(dif_sensor_ctrl_set_ast_event_trigger(&sensor_ctrl, i,
133 
134  // since there is synchronization delay to trigger clearing and actual event
135  // de-assertion, clear and poll until it is finished before moving on
136  while (events) {
137  CHECK_DIF_OK(dif_sensor_ctrl_clear_recov_event(&sensor_ctrl, i));
138  CHECK_DIF_OK(dif_sensor_ctrl_get_recov_events(&sensor_ctrl, &events));
139  }
140 
141  // ensure the de-asserted events have cleared from the wakeup pipeline
142  // within 30us
143  IBEX_SPIN_FOR(!get_wakeup_status(), 30);
144  }
145 
146  return true;
147 }