Software APIs
clkmgr_sleep_frequency_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 
8 #include "sw/device/lib/runtime/irq.h"
10 #include "sw/device/lib/testing/aon_timer_testutils.h"
11 #include "sw/device/lib/testing/clkmgr_testutils.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/sensor_ctrl_testutils.h"
15 #include "sw/device/lib/testing/test_framework/check.h"
17 
19 #include "sw/device/lib/testing/autogen/isr_testutils.h"
20 
21 OTTF_DEFINE_TEST_CONFIG();
22 
23 /**
24  * This test measure clock counts with clkmgr frequency measurements, performing
25  * 100 measurements per round. Measurement errors (fast or slow clocks) are
26  * recorded as recoverable error in clkmgr.
27  *
28  * After 100 measurements, test kicks in regular sleep with IO and USB
29  * clocks turned off. Once the chip wakes up the measurements should be
30  * enabled, but no errors should be found even for stopped clocks.
31  */
32 enum {
33  kWaitForCSRPollingMicros = 1,
34  kMeasurementsPerRound = 100,
35 };
36 
37 static dif_clkmgr_t clkmgr;
38 static dif_pwrmgr_t pwrmgr;
39 static dif_rv_plic_t rv_plic;
40 
41 static plic_isr_ctx_t plic_ctx = {.rv_plic = &rv_plic,
42  .hart_id = kTopEarlgreyPlicTargetIbex0};
43 
44 static pwrmgr_isr_ctx_t pwrmgr_isr_ctx = {
45  .pwrmgr = &pwrmgr,
46  .plic_pwrmgr_start_irq_id = kTopEarlgreyPlicIrqIdPwrmgrAonWakeup,
47  .expected_irq = kDifPwrmgrIrqWakeup,
48  .is_only_irq = true};
49 
50 static volatile bool isr_entered;
51 
52 /**
53  * External interrupt handler.
54  */
55 void ottf_external_isr(uint32_t *exc_info) {
56  dif_pwrmgr_irq_t irq_id;
58 
59  isr_entered = true;
60  isr_testutils_pwrmgr_isr(plic_ctx, pwrmgr_isr_ctx, &peripheral, &irq_id);
61 
62  // Check that both the peripheral and the irq id are correct.
63  CHECK(peripheral == kTopEarlgreyPlicPeripheralPwrmgrAon,
64  "IRQ peripheral: %d is incorrect", peripheral);
65  CHECK(irq_id == kDifPwrmgrIrqWakeup, "IRQ ID: %d is incorrect", irq_id);
66 }
67 
68 bool test_main(void) {
69  dif_sensor_ctrl_t sensor_ctrl;
70  dif_aon_timer_t aon_timer;
71 
72  uint32_t delay_micros = 0;
73  CHECK_STATUS_OK(aon_timer_testutils_get_us_from_aon_cycles(
74  kMeasurementsPerRound, &delay_micros));
75 
76  // Enable global and external IRQ at Ibex.
77  irq_global_ctrl(true);
78  irq_external_ctrl(true);
79 
80  CHECK_DIF_OK(dif_clkmgr_init(
82  CHECK_DIF_OK(dif_sensor_ctrl_init(
84  &sensor_ctrl));
85  CHECK_DIF_OK(dif_pwrmgr_init(
87  CHECK_DIF_OK(dif_aon_timer_init(
89  CHECK_DIF_OK(dif_rv_plic_init(
91 
92  LOG_INFO("TEST: wait for ast init");
93  IBEX_SPIN_FOR(sensor_ctrl_ast_init_done(&sensor_ctrl), 1000);
94  LOG_INFO("TEST: done ast init");
95 
96  CHECK(UNWRAP(pwrmgr_testutils_is_wakeup_reason(&pwrmgr, 0)) == true);
97 
98  CHECK_STATUS_OK(clkmgr_testutils_enable_clock_counts_with_expected_thresholds(
99  &clkmgr, /*jitter_enabled=*/false, /*external_clk=*/false,
100  /*low_speed=*/false));
101  busy_spin_micros(delay_micros);
102 
103  // check results
104  CHECK_STATUS_OK(clkmgr_testutils_check_measurement_counts(&clkmgr));
105  CHECK_STATUS_OK(clkmgr_testutils_disable_clock_counts(&clkmgr));
106 
107  // Start new round of measurements.
108  CHECK_STATUS_OK(clkmgr_testutils_enable_clock_counts_with_expected_thresholds(
109  &clkmgr, /*jitter_enabled=*/false, /*external_clk=*/false,
110  /*low_speed=*/false));
111 
112  busy_spin_micros(delay_micros);
113 
114  // Set wakeup timer to 100 us to have enough down time, and also wait before
115  // entering sleep to have a chance to measure before sleeping. With normal
116  // sleep all measurements should remain enabled, and there should be no
117  // errors for clocks that were selectively turned off.
118  uint64_t wakeup_threshold = kDeviceType == kDeviceSimVerilator ? 1000 : 100;
119  CHECK_STATUS_OK(
120  aon_timer_testutils_wakeup_config(&aon_timer, wakeup_threshold));
121 
122  // Enable all the AON interrupts used in this test.
123  rv_plic_testutils_irq_range_enable(&rv_plic, kTopEarlgreyPlicTargetIbex0,
126  CHECK_DIF_OK(dif_pwrmgr_irq_set_enabled(&pwrmgr, 0, kDifToggleEnabled));
127 
128  // Put chip in normal sleep, and keep Core clock running. All io and usb
129  // clocks are stopped, but we expect the stoppage won't trigger errors.
130  CHECK_STATUS_OK(pwrmgr_testutils_enable_low_power(
131  &pwrmgr, /*wakeups=*/kDifPwrmgrWakeupRequestSourceFive,
133  kDifPwrmgrDomainOptionUsbClockInActivePower |
134  kDifPwrmgrDomainOptionMainPowerInLowPower));
135 
136  LOG_INFO("TEST: Issue WFI to enter sleep");
138 
139  CHECK(isr_entered);
140 
141  // Interrupt happened. Check the measurement state.
142  CHECK_STATUS_OK(clkmgr_testutils_check_measurement_counts(&clkmgr));
143  bool all_enabled = UNWRAP(
144  clkmgr_testutils_check_measurement_enables(&clkmgr, kDifToggleEnabled));
145  CHECK(all_enabled);
146 
147  return true;
148 }