Software APIs
chip_power_idle_load_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 
5 #include <stdint.h>
6 
15 #include "sw/device/lib/dif/dif_rv_core_ibex.h"
20 #include "sw/device/lib/testing/alert_handler_testutils.h"
21 #include "sw/device/lib/testing/aon_timer_testutils.h"
22 #include "sw/device/lib/testing/pwrmgr_testutils.h"
23 #include "sw/device/lib/testing/test_framework/check.h"
24 #include "sw/device/lib/testing/test_framework/ottf_isrs.h"
26 
27 #include "alert_handler_regs.h"
28 #include "aon_timer_regs.h"
29 #include "pwm_regs.h"
30 
31 typedef void (*isr_handler)(void);
32 static volatile isr_handler expected_isr_handler;
33 static volatile dif_rv_core_ibex_nmi_state_t nmi_state;
34 static volatile bool nmi_fired = false;
35 static volatile bool ext_irq_fired = false;
36 static volatile bool irq_is_pending = false;
37 
38 static dif_aon_timer_t aon_timer;
39 static dif_rv_core_ibex_t rv_core_ibex;
40 static dif_pwrmgr_t pwrmgr;
41 static dif_rv_timer_t rv_timer;
42 static dif_alert_handler_t alert_handler;
43 static dif_pwm_t pwm;
44 static dif_pinmux_t pinmux;
45 static dif_otp_ctrl_t otp_ctrl;
46 static dif_gpio_t gpio;
47 
48 static const dt_pwrmgr_t kPwrmgrDt = 0;
49 static_assert(kDtPwrmgrCount == 1, "this library expects exactly one pwrmgr");
50 static const dt_rv_core_ibex_t kRvCoreIbexDt = 0;
51 static_assert(kDtRvCoreIbexCount == 1,
52  "this library expects exactly one rv_core_ibex");
53 static const dt_alert_handler_t kAlertHandlerDt = 0;
54 static_assert(kDtAlertHandlerCount == 1,
55  "this library expects exactly one alert_handler");
56 static const dt_rv_timer_t kRvTimerDt = 0;
57 static_assert(kDtRvTimerCount >= 1,
58  "this library expects at least one rv_timer");
59 static const dt_aon_timer_t kAonTimerDt = 0;
60 static_assert(kDtAonTimerCount == 1,
61  "this library expects exactly one aon_timer");
62 static const dt_pinmux_t kPinmuxDt = 0;
63 static_assert(kDtPinmuxCount == 1, "this library expects exactly one pinmux");
64 static const dt_gpio_t kGpioDt = 0;
65 static_assert(kDtGpioCount == 1, "this library expects exactly one gpio");
66 static const dt_otp_ctrl_t kOtpCtrlDt = 0;
67 static_assert(kDtOtpCtrlCount == 1,
68  "this library expects exactly one otp_ctrl");
69 static const dt_pwm_t kPwmDt = 0;
70 static_assert(kDtPwmCount >= 1, "this library expects at least one pwm");
71 
72 OTTF_DEFINE_TEST_CONFIG();
73 
74 // ISRs
75 
76 void ottf_external_isr(uint32_t *exc_info) {
77  LOG_INFO("got external IRQ");
78  ext_irq_fired = true;
79 }
80 
81 void ottf_external_nmi_handler(uint32_t *exc_info) {
82  nmi_fired = true;
83 
84  expected_isr_handler();
85 
86  CHECK_DIF_OK(dif_rv_core_ibex_get_nmi_state(
87  &rv_core_ibex, (dif_rv_core_ibex_nmi_state_t *)&nmi_state));
88  CHECK_DIF_OK(dif_rv_core_ibex_clear_nmi_state(&rv_core_ibex,
89  kDifRvCoreIbexNmiSourceAll));
90 }
91 
92 static void wdog_irq_handler(void) {
93  bool is_pending;
94 
95  // The watchdog bark external interrupt is also connected to the NMI input of
96  // rv_core_ibex.
97  CHECK_DIF_OK(dif_aon_timer_irq_is_pending(
98  &aon_timer, kDifAonTimerIrqWdogTimerBark, &is_pending));
99  irq_is_pending = is_pending;
100 
101  // Stop the watchdog.
102  CHECK_DIF_OK(dif_aon_timer_watchdog_stop(&aon_timer));
103 
104  // In order to handle the NMI we need to acknowledge the interrupt status bit
105  // at the peripheral side.
106  CHECK_DIF_OK(
107  dif_aon_timer_irq_acknowledge(&aon_timer, kDifAonTimerIrqWdogTimerBark));
108 }
109 
110 bool test_main(void) {
111  // Define access to DUT IPs:
112  CHECK_DIF_OK(dif_aon_timer_init_from_dt(kAonTimerDt, &aon_timer));
113  CHECK_DIF_OK(dif_rv_core_ibex_init_from_dt(kRvCoreIbexDt, &rv_core_ibex));
114  CHECK_DIF_OK(dif_pwrmgr_init_from_dt(kPwrmgrDt, &pwrmgr));
115  CHECK_DIF_OK(dif_rv_timer_init_from_dt(kRvTimerDt, &rv_timer));
116  CHECK_DIF_OK(dif_alert_handler_init_from_dt(kAlertHandlerDt, &alert_handler));
117  CHECK_DIF_OK(dif_pwm_init_from_dt(kPwmDt, &pwm));
118  CHECK_DIF_OK(dif_pinmux_init_from_dt(kPinmuxDt, &pinmux));
119  CHECK_DIF_OK(dif_otp_ctrl_init_from_dt(kOtpCtrlDt, &otp_ctrl));
120  CHECK_DIF_OK(dif_gpio_init_from_dt(kGpioDt, &gpio));
121 
122  LOG_INFO("Running CHIP Power Idle Load test");
123 
124  static const uint32_t kGpioMask = 0x00000004;
125 
126  CHECK_DIF_OK(
129 
130  // Set output modes of all GPIO pins
131  CHECK_DIF_OK(dif_gpio_output_set_enabled_all(&gpio, kGpioMask));
132 
133  // Write to set IOA2 low at the start of the test:
134  CHECK_DIF_OK(dif_gpio_write(&gpio, 2, 0));
135 
136  LOG_INFO("GPIO active");
137 
138  // RV Timer
139  static const uint32_t kHart = (uint32_t)kTopEarlgreyPlicTargetIbex0;
140  static const uint32_t kComparator = 0;
141  static const uint64_t kTickFreqHz = 1000000;
142  static const uint64_t kDeadline = UINT32_MAX;
143 
144  CHECK_DIF_OK(dif_rv_timer_reset(&rv_timer));
145 
146  dif_rv_timer_tick_params_t rv_timer_tick_params;
148  kClockFreqPeripheralHz, kTickFreqHz, &rv_timer_tick_params));
149  // Configure the tick params for a particular hart's counter
150  CHECK_DIF_OK(
151  dif_rv_timer_set_tick_params(&rv_timer, kHart, rv_timer_tick_params));
152 
153  uint64_t current_time;
154  CHECK_DIF_OK(dif_rv_timer_counter_read(&rv_timer, kHart, &current_time));
155  CHECK_DIF_OK(dif_rv_timer_arm(&rv_timer, kHart, kComparator,
156  (current_time + kDeadline)));
157  CHECK_DIF_OK(
159 
160  LOG_INFO("RV Timer active");
161 
162  // Alert Ping
163 
164  // 1. Config structs for all Incoming Alerts:
165  dif_alert_handler_alert_t alerts[ALERT_HANDLER_PARAM_N_ALERTS];
166  dif_alert_handler_class_t alert_classes[ALERT_HANDLER_PARAM_N_ALERTS];
167  for (dif_alert_handler_alert_t i = 0; i < ALERT_HANDLER_PARAM_N_ALERTS; ++i) {
168  alerts[i] = i;
169  alert_classes[i] = kDifAlertHandlerClassA;
170  }
171 
172  // 2. Config structs for Local Alerts
173  dif_alert_handler_local_alert_t loc_alerts[] = {
174  kDifAlertHandlerLocalAlertAlertPingFail};
175  dif_alert_handler_class_t loc_alert_classes[] = {kDifAlertHandlerClassB};
176 
177  // 3. Config structs for Escalation phase
178  dif_alert_handler_escalation_phase_t esc_phases[] = {
180  .signal = 0,
181  .duration_cycles = 2000}};
182  // Escalation protocol (struct) for an alert class
183  dif_alert_handler_class_config_t class_config = {
185  .accumulator_threshold = UINT16_MAX,
186  .irq_deadline_cycles = UINT32_MAX,
187  .escalation_phases = esc_phases,
188  .escalation_phases_len = ARRAYSIZE(esc_phases),
189  .crashdump_escalation_phase = kDifAlertHandlerClassStatePhase1,
190  };
191  dif_alert_handler_class_config_t class_configs[] = {class_config,
192  class_config};
193  dif_alert_handler_class_t classes[] = {kDifAlertHandlerClassA,
194  kDifAlertHandlerClassB};
195 
196  // 4. Runtime configuration (struct) for the alert handler:
197  dif_alert_handler_config_t config = {
198  .alerts = alerts,
199  .alert_classes = alert_classes,
200  .alerts_len = ARRAYSIZE(alerts),
201  .local_alerts = loc_alerts,
202  .local_alert_classes = loc_alert_classes,
203  .local_alerts_len = ARRAYSIZE(loc_alerts),
204  .classes = classes,
205  .class_configs = class_configs,
206  .classes_len = ARRAYSIZE(class_configs),
207  .ping_timeout = UINT16_MAX,
208  };
209 
210  // 5. Configure Alerts as locked so pings are enabled.
211  CHECK_STATUS_OK(
212  alert_handler_testutils_configure_all(&alert_handler, config,
213  /*locked=*/kDifToggleEnabled));
214 
215  // Checks whether alert handler's ping timer is locked
216  bool is_locked;
217  CHECK_DIF_OK(
218  dif_alert_handler_is_ping_timer_locked(&alert_handler, &is_locked));
219  CHECK(is_locked, "Expected ping timer to be locked");
220 
221  LOG_INFO("Alert ping is active");
222 
223  // PWM
224  static const dif_pwm_config_t config_ = {
225  .clock_divisor = 0,
226  .beats_per_pulse_cycle = 32,
227  };
228 
229  // Configuration struct for a specific PWM channel
230  static const dif_pwm_channel_config_t default_ch_cfg_ = {
231  .duty_cycle_a = 0,
232  .duty_cycle_b = 0,
233  .phase_delay = 0,
234  .mode = kDifPwmModeFirmware,
235  .polarity = kDifPwmPolarityActiveHigh,
236  .blink_parameter_x = 0,
237  .blink_parameter_y = 0,
238  };
239  static const dif_pwm_channel_t kPwmChannel[PWM_PARAM_N_OUTPUTS] = {
240  kDifPwmChannel0, kDifPwmChannel1, kDifPwmChannel2,
241  kDifPwmChannel3, kDifPwmChannel4, kDifPwmChannel5,
242  };
243  // Duty cycle (arbitrary) values (in the beats)
244  static volatile const uint16_t kPwmDutycycle[PWM_PARAM_N_OUTPUTS] = {
245  6, 11, 27, 8, 17, 7,
246  };
247 
248  static const dif_pinmux_index_t kPinmuxMioOut[PWM_PARAM_N_OUTPUTS] = {
252  };
253  static const dif_pinmux_index_t kPinmuxOutsel[PWM_PARAM_N_OUTPUTS] = {
257  };
258 
259  CHECK_DIF_OK(dif_pwm_configure(&pwm, config_));
260 
261  // Confugure each of the PWM channels:
262  dif_pwm_channel_config_t channel_config_ = default_ch_cfg_;
263  for (int i = 0; i < PWM_PARAM_N_OUTPUTS; ++i) {
264  CHECK_DIF_OK(
265  dif_pwm_channel_set_enabled(&pwm, kPwmChannel[i], kDifToggleDisabled));
266  channel_config_.duty_cycle_a = kPwmDutycycle[i];
267  CHECK_DIF_OK(
268  dif_pwm_configure_channel(&pwm, kPwmChannel[i], channel_config_));
269  CHECK_DIF_OK(
270  dif_pwm_channel_set_enabled(&pwm, kPwmChannel[i], kDifToggleEnabled));
271  }
272 
273  // Enable all PWM channels
275 
276  // PINMUX
277  for (int i = 0; i < PWM_PARAM_N_OUTPUTS; ++i) {
278  CHECK_DIF_OK(
279  dif_pinmux_output_select(&pinmux, kPinmuxMioOut[i], kPinmuxOutsel[i]));
280  }
281 
282  LOG_INFO("PWM active");
283 
284  // OTP
285 
286  // Access to the OTP is locked by the ROM_EXT
287  if (kBootStage == kBootStageRom) {
288  static const dif_otp_ctrl_config_t otp_ctrl_config = {
289  .check_timeout = UINT32_MAX,
290  .integrity_period_mask = 0x1,
291  .consistency_period_mask = 0x1,
292  };
293 
294  CHECK_DIF_OK(dif_otp_ctrl_configure(&otp_ctrl, otp_ctrl_config));
295 
296  LOG_INFO("OTP periodic checks active");
297  }
298 
299  // AON Timer - activate in Watchdog mode (not wakeup mode) & IRQ
300  static const uint64_t kTimeTillBark = 1000;
301 
302  CHECK_DIF_OK(dif_aon_timer_watchdog_stop(&aon_timer));
303  CHECK_DIF_OK(dif_aon_timer_clear_wakeup_cause(&aon_timer));
304  expected_isr_handler = wdog_irq_handler;
305  nmi_fired = false;
306  nmi_state = (dif_rv_core_ibex_nmi_state_t){0};
307  CHECK_DIF_OK(
308  dif_rv_core_ibex_enable_nmi(&rv_core_ibex, kDifRvCoreIbexNmiSourceWdog));
309  uint32_t count_cycles = 0;
310  CHECK_STATUS_OK(aon_timer_testutils_get_aon_cycles_32_from_us(kTimeTillBark,
311  &count_cycles));
312  CHECK_STATUS_OK(aon_timer_testutils_watchdog_config(&aon_timer, count_cycles,
313  UINT32_MAX, false));
314 
315  LOG_INFO("AON Timer active");
316 
317  CHECK_DIF_OK(dif_gpio_write(&gpio, 2, 1));
318  LOG_INFO("all HW is active");
319  IBEX_SPIN_FOR(nmi_fired, kTimeTillBark * 2);
320 
321  // Note, if running on DV environment: We wait here for the AON Timer to issue
322  // an NMI. This will make the SW exit with "true" and the Verilog test to
323  // finish with "pass". Without this, the CPU will remain idle and the
324  // simulator will end the test (due to simulation timeout) with "fail".
325 
327  CHECK_DIF_OK(dif_gpio_write(&gpio, 2, 0));
328 
329  // Prepare to exit
330  LOG_INFO("Prepare to exit");
331 
332  // We expect the watchdog bark interrupt to be pending on the peripheral side.
333  CHECK(irq_is_pending, "Expected watchdog bark interrupt to be pending");
334 
335  // Check NMI previous state (before clearing):
336  CHECK(nmi_state.wdog_enabled && nmi_state.wdog_barked,
337  "WDOG NMI state check1 not expected! wdog_enable:%x, wdog_raised:%x",
338  nmi_state.wdog_enabled, nmi_state.wdog_barked);
339 
340  CHECK_DIF_OK(dif_rv_core_ibex_get_nmi_state(
341  &rv_core_ibex, (dif_rv_core_ibex_nmi_state_t *)&nmi_state));
342  // Check NMI current state (after clearing):
343  CHECK(nmi_state.wdog_enabled && !nmi_state.wdog_barked,
344  "WDOG NMI state check2 not expected! wdog_enable:%x wdog_raised:%x",
345  nmi_state.wdog_enabled, nmi_state.wdog_barked);
346 
347  // Check that no external interrupts have occurred.
348  CHECK(ext_irq_fired == false, "Unexpected external interrupt triggered.");
349 
350  // Check that the system has not been reset due to escalation and that the
351  // reset reason is still POR.
352  CHECK(UNWRAP(pwrmgr_testutils_is_wakeup_reason(&pwrmgr, 0)) == true);
353 
354  CHECK_STATUS_OK(aon_timer_testutils_shutdown(&aon_timer));
355 
356  test_status_set(kTestStatusInTest);
357 
358  return true;
359 }