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 dt_pwrmgr_t kPwrmgrDt = 0;
43 static_assert(kDtPwrmgrCount == 1, "this test expects a pwrmgr");
44 static const dt_pinmux_t kPinmuxDt = 0;
45 static_assert(kDtPinmuxCount == 1, "this test expects a pinmux");
46 static const dt_rstmgr_t kRstmgrDt = 0;
47 static_assert(kDtRstmgrCount == 1, "this test expects a rstmgr");
48 static const dt_aon_timer_t kAonTimerDt = 0;
49 static_assert(kDtAonTimerCount == 1, "this test expects an aon_timer");
50 static const dt_pwm_t kPwmDt = 0;
51 static_assert(kDtPwmCount == 1, "this test expects a pwm");
52 
53 static const dif_pinmux_index_t kPinmuxOutsel[PWM_PARAM_N_OUTPUTS] = {
57 };
58 
59 static const dif_pinmux_index_t kPinmuxMioOut[PWM_PARAM_N_OUTPUTS] = {
63 };
64 
65 static const dif_pwm_channel_t kPwmChannel[PWM_PARAM_N_OUTPUTS] = {
66  kDifPwmChannel0, kDifPwmChannel1, kDifPwmChannel2,
67  kDifPwmChannel3, kDifPwmChannel4, kDifPwmChannel5,
68 };
69 
70 // Duty cycle in the unit of beat
71 // These are random numbers betwen [1,beats_per_pulse_cycle)
72 // make 'static volatile' to overwrite from
73 // hw/top_earlgrey/dv/env/seq_lib/chip_sw_pwm_pulses_vseq.sv
74 // via backdoor
75 static volatile const uint16_t kPwmDutycycle[PWM_PARAM_N_OUTPUTS] = {
76  6, 11, 27, 8, 17, 7,
77 };
78 
79 static const dif_pwm_config_t config_ = {
80  // set beat period to 3
81  .clock_divisor = 2,
82 
83  // upper 5bits of phase cntr only matter
84  // and total(on+off) beats per cycle will be 32
85  .beats_per_pulse_cycle = 32,
86 };
87 
88 // This is initial value of config variable
89 static const dif_pwm_channel_config_t default_ch_cfg_ = {
90  .duty_cycle_a = 0,
91  .duty_cycle_b = 0,
92  .phase_delay = 0,
93  .mode = kDifPwmModeFirmware,
94  .polarity = kDifPwmPolarityActiveHigh,
95  .blink_parameter_x = 0,
96  .blink_parameter_y = 0,
97 };
98 
99 // Configure pwm channel register for all 6 channels.
100 // This also contain disable and enable each channel.
101 void config_pwm_channels(dif_pwm_t *pwm) {
102  dif_pwm_channel_config_t channel_config_ = default_ch_cfg_;
103 
104  for (int i = 0; i < PWM_PARAM_N_OUTPUTS; ++i) {
105  CHECK_DIF_OK(
106  dif_pwm_channel_set_enabled(pwm, kPwmChannel[i], kDifToggleDisabled));
107  channel_config_.duty_cycle_a = kPwmDutycycle[i];
108  CHECK_DIF_OK(
109  dif_pwm_configure_channel(pwm, kPwmChannel[i], channel_config_));
110  CHECK_DIF_OK(
111  dif_pwm_channel_set_enabled(pwm, kPwmChannel[i], kDifToggleEnabled));
112  }
113 }
114 
115 bool test_main(void) {
116  dif_pwrmgr_t pwrmgr;
117  dif_rstmgr_t rstmgr;
118 
119  // Issue a wakeup signal in ~150us through the AON timer.
120  //
121  // At 200kHz, threshold of 30 is equal to 150us. There is an additional
122  // ~4 cycle overhead for the CSR value to synchronize with the AON clock.
123  // We should expect the wake up to trigger in ~170us. This is sufficient
124  // time to allow pwrmgr config and the low power entry on WFI to complete.
125  //
126  // Adjust the threshold for Verilator since it runs on different clock
127  // frequencies.
128  uint64_t wakeup_threshold = 30;
130  wakeup_threshold = 300;
131  }
132 
133  // Initialize pwrmgr
134  CHECK_DIF_OK(dif_pwrmgr_init_from_dt(kPwrmgrDt, &pwrmgr));
135 
136  dif_pwrmgr_request_sources_t wakeup_sources;
137  CHECK_DIF_OK(dif_pwrmgr_find_request_source(
138  &pwrmgr, kDifPwrmgrReqTypeWakeup, dt_aon_timer_instance_id(kAonTimerDt),
139  kDtAonTimerWakeupWkupReq, &wakeup_sources));
140 
141  // Initialize rstmgr since this will check some registers.
142  CHECK_DIF_OK(dif_rstmgr_init_from_dt(kRstmgrDt, &rstmgr));
143 
144  dif_aon_timer_t aon_timer;
145  CHECK_DIF_OK(dif_aon_timer_init_from_dt(kAonTimerDt, &aon_timer));
146 
147  // Assuming the chip hasn't slept yet, wakeup reason should be empty.
148 
149  // Notice we are clearing rstmgr's RESET_INFO, so after the aon wakeup there
150  // is only one bit set.
151  if (UNWRAP(pwrmgr_testutils_is_wakeup_reason(&pwrmgr, 0)) == true) {
152  dif_pwm_t pwm;
153  dif_pinmux_t pinmux;
154  // Initialize pwm
155  CHECK_DIF_OK(dif_pwm_init_from_dt(kPwmDt, &pwm));
156 
157  // Update pwm.CFG
158  CHECK_DIF_OK(dif_pwm_configure(&pwm, config_));
159 
160  // Update all 6 pwm channels
161  config_pwm_channels(&pwm);
162 
163  // enable phase count to make the change effective
165 
166  // Initialize pinmux - this assigns PwmAonPwm[0..5] to
167  // IOB10..12 and IOC10..12
168  // LOG_INFO is used to indicate pwmout is available to
169  // SV pwm_monitor
170  CHECK_DIF_OK(dif_pinmux_init_from_dt(kPinmuxDt, &pinmux));
171 
172  LOG_INFO("pinmux_init begin");
173  for (int i = 0; i < PWM_PARAM_N_OUTPUTS; ++i) {
174  CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kPinmuxMioOut[i],
175  kPinmuxOutsel[i]));
176  }
177  LOG_INFO("pinmux_init end");
178 
179  // Add 1ms to initial pulses go through before sleep event
180  busy_spin_micros(1 * 1000);
181 
182  LOG_INFO("POR reset");
183  CHECK(UNWRAP(
184  rstmgr_testutils_reset_info_any(&rstmgr, kDifRstmgrResetInfoPor)));
185 
186  // Prepare rstmgr for a reset.
187  CHECK_STATUS_OK(rstmgr_testutils_pre_reset(&rstmgr));
188 
189  CHECK_STATUS_OK(
190  aon_timer_testutils_wakeup_config(&aon_timer, wakeup_threshold));
191  // Deep sleep.
192  CHECK_STATUS_OK(
193  pwrmgr_testutils_enable_low_power(&pwrmgr, wakeup_sources, 0));
194 
195  // Enter low power mode.
196  LOG_INFO("Issue WFI to enter sleep");
198 
199  } else if (UNWRAP(pwrmgr_testutils_is_wakeup_reason(
200  &pwrmgr, wakeup_sources)) == true) {
201  LOG_INFO("Wakeup reset");
202 
203  CHECK(UNWRAP(rstmgr_testutils_is_reset_info(
205  LOG_INFO("Aon timer wakeup detected");
206  CHECK_STATUS_OK(rstmgr_testutils_post_reset(
207  &rstmgr, kDifRstmgrResetInfoLowPowerExit, 0, 0, 0, 0));
208 
209  // add another 2ms to give more time to pwm pulses sequences
210  busy_spin_micros(2 * 1000);
211 
212  return true;
213  } else {
214  dif_pwrmgr_wakeup_reason_t wakeup_reason;
215  CHECK_DIF_OK(dif_pwrmgr_wakeup_reason_get(&pwrmgr, &wakeup_reason));
216  LOG_ERROR("Unexpected wakeup detected: type = %d, request_source = %d",
217  wakeup_reason.types, wakeup_reason.request_sources);
218  return false;
219  }
220 
221  return false;
222 }