Software APIs
sleep_pwm_pulses_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 
12 #include "sw/device/lib/testing/aon_timer_testutils.h"
13 #include "sw/device/lib/testing/pwrmgr_testutils.h"
14 #include "sw/device/lib/testing/rstmgr_testutils.h"
15 #include "sw/device/lib/testing/test_framework/check.h"
17 
19 #include "pwm_regs.h"
20 
21 /**
22  * SLEEP PWM PULSES test
23  *
24  * This test configure 6 pwm channels with a fixed duty cycle
25  * then kicks power manager sleep mode to see pwm pulses are
26  * not affected by power down event.
27  * pwm out --> pinmux setup is chosen arbitrary as below
28  * pwmout[0] -> IOB10
29  * pwmout[1] -> IOB11
30  * pwmout[2] -> IOB12
31  * pwmout[3] -> IOc10
32  * pwmout[4] -> IOc11
33  * pwmout[5] -> IOc12
34  *
35  * Since purpose of this test is to check pwm -> pinmux
36  * connectivity and pulse integrity under sleep event,
37  * Fixed pwm configuration, mode and 0 phase delay are chosen.
38  */
39 
40 OTTF_DEFINE_TEST_CONFIG();
41 
42 static const dif_pinmux_index_t kPinmuxOutsel[PWM_PARAM_N_OUTPUTS] = {
46 };
47 
48 static const dif_pinmux_index_t kPinmuxMioOut[PWM_PARAM_N_OUTPUTS] = {
52 };
53 
54 static const dif_pwm_channel_t kPwmChannel[PWM_PARAM_N_OUTPUTS] = {
55  kDifPwmChannel0, kDifPwmChannel1, kDifPwmChannel2,
56  kDifPwmChannel3, kDifPwmChannel4, kDifPwmChannel5,
57 };
58 
59 // Duty cycle in the unit of beat
60 // These are random numbers betwen [1,beats_per_pulse_cycle)
61 // make 'static volatile' to overwrite from
62 // hw/top_earlgrey/dv/env/seq_lib/chip_sw_pwm_pulses_vseq.sv
63 // via backdoor
64 static volatile const uint16_t kPwmDutycycle[PWM_PARAM_N_OUTPUTS] = {
65  6, 11, 27, 8, 17, 7,
66 };
67 
68 static const dif_pwm_config_t config_ = {
69  // set beat period to 3
70  .clock_divisor = 2,
71 
72  // upper 5bits of phase cntr only matter
73  // and total(on+off) beats per cycle will be 32
74  .beats_per_pulse_cycle = 32,
75 };
76 
77 // This is initial value of config variable
78 static const dif_pwm_channel_config_t default_ch_cfg_ = {
79  .duty_cycle_a = 0,
80  .duty_cycle_b = 0,
81  .phase_delay = 0,
82  .mode = kDifPwmModeFirmware,
83  .polarity = kDifPwmPolarityActiveHigh,
84  .blink_parameter_x = 0,
85  .blink_parameter_y = 0,
86 };
87 
88 // Configure pwm channel register for all 6 channels.
89 // This also contain disable and enable each channel.
90 void config_pwm_channels(dif_pwm_t *pwm) {
91  dif_pwm_channel_config_t channel_config_ = default_ch_cfg_;
92 
93  for (int i = 0; i < PWM_PARAM_N_OUTPUTS; ++i) {
94  CHECK_DIF_OK(
95  dif_pwm_channel_set_enabled(pwm, kPwmChannel[i], kDifToggleDisabled));
96  channel_config_.duty_cycle_a = kPwmDutycycle[i];
97  CHECK_DIF_OK(
98  dif_pwm_configure_channel(pwm, kPwmChannel[i], channel_config_));
99  CHECK_DIF_OK(
100  dif_pwm_channel_set_enabled(pwm, kPwmChannel[i], kDifToggleEnabled));
101  }
102 }
103 
104 bool test_main(void) {
105  dif_pwrmgr_t pwrmgr;
106  dif_rstmgr_t rstmgr;
107 
108  // Issue a wakeup signal in ~150us through the AON timer.
109  //
110  // At 200kHz, threshold of 30 is equal to 150us. There is an additional
111  // ~4 cycle overhead for the CSR value to synchronize with the AON clock.
112  // We should expect the wake up to trigger in ~170us. This is sufficient
113  // time to allow pwrmgr config and the low power entry on WFI to complete.
114  //
115  // Adjust the threshold for Verilator since it runs on different clock
116  // frequencies.
117  uint64_t wakeup_threshold = 30;
119  wakeup_threshold = 300;
120  }
121 
122  // Initialize pwrmgr
123  CHECK_DIF_OK(dif_pwrmgr_init(
125 
126  // Initialize rstmgr since this will check some registers.
127  CHECK_DIF_OK(dif_rstmgr_init(
129 
130  dif_aon_timer_t aon_timer;
131  CHECK_DIF_OK(dif_aon_timer_init(
133 
134  // Assuming the chip hasn't slept yet, wakeup reason should be empty.
135 
136  // Notice we are clearing rstmgr's RESET_INFO, so after the aon wakeup there
137  // is only one bit set.
138  if (UNWRAP(pwrmgr_testutils_is_wakeup_reason(&pwrmgr, 0)) == true) {
139  dif_pwm_t pwm;
140  dif_pinmux_t pinmux;
141  // Initialize pwm
142  CHECK_DIF_OK(dif_pwm_init(
144 
145  // Update pwm.CFG
146  CHECK_DIF_OK(dif_pwm_configure(&pwm, config_));
147 
148  // Update all 6 pwm channels
149  config_pwm_channels(&pwm);
150 
151  // enable phase count to make the change effective
153 
154  // Initialize pinmux - this assigns PwmAonPwm[0..5] to
155  // IOB10..12 and IOC10..12
156  // LOG_INFO is used to indicate pwmout is available to
157  // SV pwm_monitor
158  CHECK_DIF_OK(dif_pinmux_init(
160 
161  LOG_INFO("pinmux_init begin");
162  for (int i = 0; i < PWM_PARAM_N_OUTPUTS; ++i) {
163  CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kPinmuxMioOut[i],
164  kPinmuxOutsel[i]));
165  }
166  LOG_INFO("pinmux_init end");
167 
168  // Add 1ms to initial pulses go through before sleep event
169  busy_spin_micros(1 * 1000);
170 
171  LOG_INFO("POR reset");
172  CHECK(UNWRAP(
173  rstmgr_testutils_reset_info_any(&rstmgr, kDifRstmgrResetInfoPor)));
174 
175  // Prepare rstmgr for a reset.
176  CHECK_STATUS_OK(rstmgr_testutils_pre_reset(&rstmgr));
177 
178  CHECK_STATUS_OK(
179  aon_timer_testutils_wakeup_config(&aon_timer, wakeup_threshold));
180  // Deep sleep.
181  CHECK_STATUS_OK(pwrmgr_testutils_enable_low_power(
182  &pwrmgr, kDifPwrmgrWakeupRequestSourceFive, 0));
183 
184  // Enter low power mode.
185  LOG_INFO("Issue WFI to enter sleep");
187 
188  } else if (UNWRAP(pwrmgr_testutils_is_wakeup_reason(
189  &pwrmgr, kDifPwrmgrWakeupRequestSourceFive)) == true) {
190  LOG_INFO("Wakeup reset");
191 
192  CHECK(UNWRAP(rstmgr_testutils_is_reset_info(
194  LOG_INFO("Aon timer wakeup detected");
195  CHECK_STATUS_OK(rstmgr_testutils_post_reset(
196  &rstmgr, kDifRstmgrResetInfoLowPowerExit, 0, 0, 0, 0));
197 
198  // add another 2ms to give more time to pwm pulses sequences
199  busy_spin_micros(2 * 1000);
200 
201  return true;
202  } else {
203  dif_pwrmgr_wakeup_reason_t wakeup_reason;
204  CHECK_DIF_OK(dif_pwrmgr_wakeup_reason_get(&pwrmgr, &wakeup_reason));
205  LOG_ERROR("Unexpected wakeup detected: type = %d, request_source = %d",
206  wakeup_reason.types, wakeup_reason.request_sources);
207  return false;
208  }
209 
210  return false;
211 }