Software APIs
chip_power_sleep_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 // Included code:
6 
7 #include <stdint.h>
8 
18 #include "sw/device/lib/dif/dif_rv_core_ibex.h"
21 #include "sw/device/lib/runtime/irq.h"
23 #include "sw/device/lib/testing/alert_handler_testutils.h"
24 #include "sw/device/lib/testing/aon_timer_testutils.h"
25 #include "sw/device/lib/testing/pwrmgr_testutils.h"
26 #include "sw/device/lib/testing/test_framework/check.h"
27 #include "sw/device/lib/testing/test_framework/ottf_isrs.h"
29 
30 #include "alert_handler_regs.h"
31 #include "aon_timer_regs.h"
33 #include "pwm_regs.h"
34 
35 typedef void (*isr_handler)(void);
36 static volatile isr_handler expected_isr_handler;
37 static volatile dif_rv_core_ibex_nmi_state_t nmi_state;
38 static volatile bool nmi_fired = false;
39 static volatile bool ext_irq_fired = false;
40 static volatile bool irq_is_pending = false;
41 
42 static dif_aon_timer_t aon_timer;
43 static dif_rv_core_ibex_t rv_core_ibex;
44 static dif_rv_plic_t rv_plic;
45 static dif_pwrmgr_t pwrmgr;
46 static dif_rv_timer_t rv_timer;
47 static dif_alert_handler_t alert_handler;
48 static dif_pwm_t pwm;
49 static dif_pinmux_t pinmux;
50 static dif_otp_ctrl_t otp_ctrl;
51 static dif_gpio_t gpio;
52 static dif_adc_ctrl_t adc_ctrl;
53 
54 static volatile const bool kCoreClkOff = false;
55 static volatile const bool kIoClkOff = false;
56 static volatile const bool kUsbSlpOff = false;
57 static volatile const bool kUsbActOff = false;
58 static volatile const bool kDeepSleep = false;
59 
60 static const uint32_t kPlicTarget = kTopEarlgreyPlicTargetIbex0;
61 
62 OTTF_DEFINE_TEST_CONFIG();
63 
64 void ottf_external_isr(uint32_t *exc_info) {
65  LOG_INFO("got external IRQ");
66  ext_irq_fired = true;
67 }
68 
69 void ottf_external_nmi_handler(uint32_t *exc_info) {
70  nmi_fired = true;
71 
72  expected_isr_handler();
73 
74  CHECK_DIF_OK(dif_rv_core_ibex_get_nmi_state(
75  &rv_core_ibex, (dif_rv_core_ibex_nmi_state_t *)&nmi_state));
76  CHECK_DIF_OK(dif_rv_core_ibex_clear_nmi_state(&rv_core_ibex,
77  kDifRvCoreIbexNmiSourceAll));
78 }
79 
80 // Specific handlee for the wdog bark NMI IRQ.
81 static void wdog_irq_handler(void) {
82  bool is_pending;
83 
84  CHECK_DIF_OK(dif_aon_timer_irq_is_pending(
85  &aon_timer, kDifAonTimerIrqWdogTimerBark, &is_pending));
86  irq_is_pending = is_pending;
87 
88  // Stop the watchdog.
89  CHECK_DIF_OK(dif_aon_timer_watchdog_stop(&aon_timer));
90 
91  CHECK_DIF_OK(
92  dif_aon_timer_irq_acknowledge(&aon_timer, kDifAonTimerIrqWdogTimerBark));
93 
94  // Signal a software interrupt.
95  dif_rv_plic_t rv_plic_isr;
96  mmio_region_t plic_base_addr =
98  CHECK_DIF_OK(dif_rv_plic_init(plic_base_addr, &rv_plic_isr));
99  CHECK_DIF_OK(dif_rv_plic_software_irq_force(&rv_plic_isr, kPlicTarget));
100 }
101 
102 static void prepare_to_exit(void) {
104 
105  CHECK_DIF_OK(dif_gpio_write(&gpio, 2, 0));
106 
107  LOG_INFO("Prepare to exit");
108 
109  // Check that no external interrupts have occurred.
110  CHECK(ext_irq_fired == false, "Unexpected external interrupt triggered.");
111 
112  CHECK_STATUS_OK(aon_timer_testutils_shutdown(&aon_timer));
113 
114  // Set the test status flag back to "TestStatusInTest".
115  test_status_set(kTestStatusInTest);
116 }
117 
118 bool test_main(void) {
119  // Define access to DUT IPs:
120  CHECK_DIF_OK(dif_aon_timer_init(
122  CHECK_DIF_OK(dif_rv_core_ibex_init(
124  &rv_core_ibex));
125  CHECK_DIF_OK(dif_pwrmgr_init(
127  CHECK_DIF_OK(dif_rv_timer_init(
129  CHECK_DIF_OK(dif_alert_handler_init(
131  &alert_handler));
132  CHECK_DIF_OK(dif_pwm_init(
134  CHECK_DIF_OK(dif_pinmux_init(
136  CHECK_DIF_OK(dif_otp_ctrl_init(
138  CHECK_DIF_OK(
139  dif_gpio_init(mmio_region_from_addr(TOP_EARLGREY_GPIO_BASE_ADDR), &gpio));
140  CHECK_DIF_OK(dif_adc_ctrl_init(
142 
143  LOG_INFO("Running CHIP Power Sleep Load test");
144 
145  // Testplan: "The test should set a GPIO (mapped to the IOA2 pin) to high
146  // while the power state of interest is active".
147 
148  const uint32_t kGpioMask = 0x00000004;
149 
150  // PINMUX.
151  CHECK_DIF_OK(
154 
155  // Set output modes of all GPIO pins.
156  CHECK_DIF_OK(dif_gpio_output_set_enabled_all(&gpio, kGpioMask));
157 
158  // Write to set IOA2 low at the start of the test:
159  CHECK_DIF_OK(dif_gpio_write(&gpio, 2, 0));
160 
161  LOG_INFO("GPIO active");
162 
163  // PWRMGR- Read wakeup reason.
164 
165  dif_pwrmgr_wakeup_reason_t wakeup_reason;
166  CHECK_DIF_OK(dif_pwrmgr_wakeup_reason_get(&pwrmgr, &wakeup_reason));
167  LOG_INFO("wakeup type:%d. wakeup reason: 0x%02X", wakeup_reason.types,
168  wakeup_reason.request_sources);
169 
170  if (wakeup_reason.types == 0) {
171  // Wakeup due to Power Up - DO NOTHING HERE - go on with the rest of the
172  // test's flow....
173  } else if ((wakeup_reason.types == kDifPwrmgrWakeupTypeRequest) &&
174  (wakeup_reason.request_sources ==
175  kDifPwrmgrWakeupRequestSourceFive)) {
176  // Wakeup due to a peripheral request and reason is AON Timer.
177  prepare_to_exit();
178  return true;
179  } else {
180  LOG_ERROR("unexpected wakeup reason! type=0x%x, source=0x%x",
181  wakeup_reason.types, wakeup_reason.request_sources);
182  return false;
183  }
184 
185  // RV Timer.
186  enum {
187  kHart = (uint32_t)kTopEarlgreyPlicTargetIbex0,
188  kComparator = 0,
189  kTickFreqHz = 1000000,
190  kDeadline = UINT32_MAX,
191  };
192 
193  CHECK_DIF_OK(dif_rv_timer_reset(&rv_timer));
194 
195  dif_rv_timer_tick_params_t rv_timer_tick_params;
197  kClockFreqPeripheralHz, kTickFreqHz, &rv_timer_tick_params));
198  // Configure the tick params for a particular hart's counter.
199  CHECK_DIF_OK(
200  dif_rv_timer_set_tick_params(&rv_timer, kHart, rv_timer_tick_params));
201 
202  uint64_t current_time;
203  CHECK_DIF_OK(dif_rv_timer_counter_read(&rv_timer, kHart, &current_time));
204  CHECK_DIF_OK(dif_rv_timer_arm(&rv_timer, kHart, kComparator,
205  (current_time + kDeadline)));
206  CHECK_DIF_OK(
208 
209  LOG_INFO("RV Timer active");
210 
211  // Alert Ping.
212 
213  // 1. Config structs for all Incoming Alerts:
214  dif_alert_handler_alert_t alerts[ALERT_HANDLER_PARAM_N_ALERTS];
215  dif_alert_handler_class_t alert_classes[ALERT_HANDLER_PARAM_N_ALERTS];
216  for (size_t i = 0; i < ALERT_HANDLER_PARAM_N_ALERTS; ++i) {
217  alerts[i] = i;
218  alert_classes[i] = kDifAlertHandlerClassA;
219  }
220 
221  // 2. Config structs for Local Alerts:
222  dif_alert_handler_local_alert_t loc_alerts[] = {
223  kDifAlertHandlerLocalAlertAlertPingFail};
224  dif_alert_handler_class_t loc_alert_classes[] = {kDifAlertHandlerClassB};
225 
226  // 3. Config structs for Escalation phase:
227  dif_alert_handler_escalation_phase_t esc_phases[] = {
229  .signal = 0,
230  .duration_cycles = 2000}};
231  // Escalation protocol (struct) for an alert class.
232  dif_alert_handler_class_config_t class_config = {
234  .accumulator_threshold = UINT16_MAX,
235  .irq_deadline_cycles = UINT32_MAX,
236  .escalation_phases = esc_phases,
237  .escalation_phases_len = ARRAYSIZE(esc_phases),
238  .crashdump_escalation_phase = kDifAlertHandlerClassStatePhase1,
239  };
240  dif_alert_handler_class_config_t class_configs[] = {class_config,
241  class_config};
242  dif_alert_handler_class_t classes[] = {kDifAlertHandlerClassA,
243  kDifAlertHandlerClassB};
244 
245  // 4. Runtime configuration (struct) for the alert handler:
246  dif_alert_handler_config_t config = {
247  .alerts = alerts,
248  .alert_classes = alert_classes,
249  .alerts_len = ARRAYSIZE(alerts),
250  .local_alerts = loc_alerts,
251  .local_alert_classes = loc_alert_classes,
252  .local_alerts_len = ARRAYSIZE(loc_alerts),
253  .classes = classes,
254  .class_configs = class_configs,
255  .classes_len = ARRAYSIZE(class_configs),
256  .ping_timeout = UINT16_MAX,
257  };
258 
259  // 5. Configure Alerts:
260  CHECK_STATUS_OK(alert_handler_testutils_configure_all(&alert_handler, config,
262 
263  // Checks whether alert handler's ping timer is locked.
264  bool is_locked;
265  CHECK_DIF_OK(
266  dif_alert_handler_is_ping_timer_locked(&alert_handler, &is_locked));
267  CHECK(is_locked, "Expected alerts to be locked");
268 
269  LOG_INFO("Alert ping is active");
270 
271  // PWM
272  // Configuration struct for PWM general.
273  const dif_pwm_config_t kConfig_ = {
274  .clock_divisor = 0,
275  .beats_per_pulse_cycle = 32,
276  };
277 
278  // Configuration struct for a specific PWM channel.
279  const dif_pwm_channel_config_t kDefaultChCfg_ = {
280  .duty_cycle_a = 0,
281  .duty_cycle_b = 0,
282  .phase_delay = 0,
283  .mode = kDifPwmModeFirmware,
284  .polarity = kDifPwmPolarityActiveHigh,
285  .blink_parameter_x = 0,
286  .blink_parameter_y = 0,
287  };
288  const dif_pwm_channel_t kPwmChannel[PWM_PARAM_N_OUTPUTS] = {
289  kDifPwmChannel0, kDifPwmChannel1, kDifPwmChannel2,
290  kDifPwmChannel3, kDifPwmChannel4, kDifPwmChannel5,
291  };
292  // Duty cycle (arbitrary) values (in the beats).
293  const uint16_t kPwmDutycycle[PWM_PARAM_N_OUTPUTS] = {
294  6, 11, 27, 8, 17, 7,
295  };
296 
297  const dif_pinmux_index_t kPinmuxMioOut[PWM_PARAM_N_OUTPUTS] = {
301  };
302  const dif_pinmux_index_t kPinmuxOutsel[PWM_PARAM_N_OUTPUTS] = {
306  };
307 
308  CHECK_DIF_OK(dif_pwm_configure(&pwm, kConfig_));
309 
310  // Configure each of the PWM channels:
311  dif_pwm_channel_config_t channel_config_ = kDefaultChCfg_;
312  for (size_t i = 0; i < PWM_PARAM_N_OUTPUTS; ++i) {
313  CHECK_DIF_OK(
314  dif_pwm_channel_set_enabled(&pwm, kPwmChannel[i], kDifToggleDisabled));
315  channel_config_.duty_cycle_a = kPwmDutycycle[i];
316  CHECK_DIF_OK(
317  dif_pwm_configure_channel(&pwm, kPwmChannel[i], channel_config_));
318  CHECK_DIF_OK(
319  dif_pwm_channel_set_enabled(&pwm, kPwmChannel[i], kDifToggleEnabled));
320  }
321 
322  // Enable all PWM channels.
324 
325  // PINMUX.
326  for (size_t i = 0; i < PWM_PARAM_N_OUTPUTS; ++i) {
327  CHECK_DIF_OK(
328  dif_pinmux_output_select(&pinmux, kPinmuxMioOut[i], kPinmuxOutsel[i]));
329  }
330 
331  LOG_INFO("PWM active");
332 
333  // OTP.
334  if (kBootStage != kBootStageOwner) {
335  // The ROM_EXT locks up the OTP register in the ePMP, any attempt to
336  // write to it would generate an exception. Therfore we can't test the
337  // OTP periodic checks when the test runs after the ROM_EXT.
338 
339  // Configure OTP Control to do periodic "consistency" & "integrity" checks.
340  const dif_otp_ctrl_config_t kOtpCtrlConfig = {
341  .check_timeout = UINT32_MAX,
342  .integrity_period_mask = 0x1,
343  .consistency_period_mask = 0x1,
344  };
345 
346  CHECK_DIF_OK(dif_otp_ctrl_configure(&otp_ctrl, kOtpCtrlConfig));
347 
348  LOG_INFO("OTP periodic checks active");
349  } else {
350  LOG_INFO("Skipping OTP periodic checks due to ROM_EXT ePMP configuration");
351  }
352 
353  // AON Timer.
354  const uint64_t kTimeTillBark = 1000;
355 
356  CHECK_DIF_OK(dif_aon_timer_watchdog_stop(&aon_timer));
357  CHECK_DIF_OK(dif_aon_timer_clear_wakeup_cause(&aon_timer));
358  expected_isr_handler = wdog_irq_handler;
359  nmi_fired = false;
360  nmi_state = (dif_rv_core_ibex_nmi_state_t){0};
361  CHECK_DIF_OK(
362  dif_rv_core_ibex_enable_nmi(&rv_core_ibex, kDifRvCoreIbexNmiSourceWdog));
363  uint32_t count_cycles = 0;
364  CHECK_STATUS_OK(aon_timer_testutils_get_aon_cycles_32_from_us(kTimeTillBark,
365  &count_cycles));
366 
367  if (kDeepSleep) {
368  // Activate in Wakeup mode (no need for IRQ).
369  CHECK_STATUS_OK(
370  aon_timer_testutils_wakeup_config(&aon_timer, kTimeTillBark));
371  } else {
372  // Unmask the software interrupt so it can be used to bring the CPU out of
373  // sleep without having an NMI race WFI.
374  irq_software_ctrl(/*en=*/true);
375 
376  // Activate in Watchdog mode & IRQ.
377  CHECK_STATUS_OK(aon_timer_testutils_watchdog_config(
378  &aon_timer, count_cycles, UINT32_MAX, false));
379  }
380  LOG_INFO("AON Timer active");
381 
382  // ADC Controller.
383  enum {
384  kNumLowPowerSamples = 2,
385  kNumNormalPowerSamples = 1,
386  kPowerUpTime = 30,
387  kWakeUpTime = 500,
388  };
389  uint32_t power_up_time_aon_cycles = 0;
390  CHECK_STATUS_OK(aon_timer_testutils_get_aon_cycles_32_from_us(
391  kPowerUpTime, &power_up_time_aon_cycles));
392  uint32_t wake_up_time_aon_cycles = 0;
393  CHECK_STATUS_OK(aon_timer_testutils_get_aon_cycles_32_from_us(
394  kWakeUpTime, &wake_up_time_aon_cycles));
395 
396  // ADC configuration.
397  CHECK_DIF_OK(dif_adc_ctrl_set_enabled(&adc_ctrl, kDifToggleDisabled));
398  CHECK_DIF_OK(dif_adc_ctrl_reset(&adc_ctrl));
399  CHECK(power_up_time_aon_cycles < UINT8_MAX,
400  "power_up_time_aon_cycles must fit into uint8_t");
401  CHECK_DIF_OK(dif_adc_ctrl_configure(
402  &adc_ctrl,
405  .num_low_power_samples = kNumLowPowerSamples,
406  .num_normal_power_samples = kNumNormalPowerSamples,
407  .power_up_time_aon_cycles = (uint8_t)power_up_time_aon_cycles + 1,
408  .wake_up_time_aon_cycles = wake_up_time_aon_cycles}));
409  CHECK_DIF_OK(dif_adc_ctrl_set_enabled(&adc_ctrl, kDifToggleEnabled));
410 
411  LOG_INFO("ADC Controller active");
412 
413  // Power Manager.
414  dif_pwrmgr_domain_config_t pwrmgr_cfg;
415  dif_pwrmgr_request_sources_t pwrmgr_wakeups;
416 
417  // Specify which request sources are enabled for wake-up.
418  pwrmgr_wakeups =
419  (kDifPwrmgrWakeupRequestSourceOne | kDifPwrmgrWakeupRequestSourceTwo |
420  kDifPwrmgrWakeupRequestSourceThree | kDifPwrmgrWakeupRequestSourceFour |
421  kDifPwrmgrWakeupRequestSourceFive | kDifPwrmgrWakeupRequestSourceSix);
422 
423  // Power manager configuration.
424  pwrmgr_cfg = ((kCoreClkOff ? 0 : kDifPwrmgrDomainOptionCoreClockInLowPower) |
425  (kIoClkOff ? 0 : kDifPwrmgrDomainOptionIoClockInLowPower) |
426  (kUsbSlpOff ? 0 : kDifPwrmgrDomainOptionUsbClockInLowPower) |
427  (kUsbActOff ? 0 : kDifPwrmgrDomainOptionUsbClockInActivePower) |
428  (kDeepSleep ? 0 : kDifPwrmgrDomainOptionMainPowerInLowPower));
429  CHECK_STATUS_OK(
430  pwrmgr_testutils_enable_low_power(&pwrmgr, pwrmgr_wakeups, pwrmgr_cfg));
431  LOG_INFO("Power Manage configured");
432 
433  CHECK_DIF_OK(dif_gpio_write(&gpio, 2, 1));
434  LOG_INFO("all HW is active");
435  test_status_set(0xff20);
437 
438  // Check for software interrupt and clear. Re-initialize the struct in case
439  // the software interrupt did not happen.
440  mmio_region_t plic_base_addr =
442  CHECK_DIF_OK(dif_rv_plic_init(plic_base_addr, &rv_plic));
443  bool software_irq_pending;
444  CHECK_DIF_OK(dif_rv_plic_software_irq_is_pending(&rv_plic, kPlicTarget,
445  &software_irq_pending));
446  CHECK(software_irq_pending,
447  "Software IRQ unexpectedly not pending after WFI");
448  CHECK_DIF_OK(dif_rv_plic_software_irq_acknowledge(&rv_plic, kPlicTarget));
449 
450  // We expect the watchdog bark interrupt to be pending on the peripheral side.
451  CHECK(irq_is_pending, "Expected watchdog bark interrupt to be pending");
452 
453  // Check NMI previous state (before clearing):
454  CHECK(nmi_state.wdog_enabled && nmi_state.wdog_barked,
455  "WDOG NMI state check1 not expected! wdog_enable:%x, wdog_raised:%x",
456  nmi_state.wdog_enabled, nmi_state.wdog_barked);
457 
458  CHECK_DIF_OK(dif_rv_core_ibex_get_nmi_state(
459  &rv_core_ibex, (dif_rv_core_ibex_nmi_state_t *)&nmi_state));
460  // Check NMI current state (after clearing):
461  CHECK(nmi_state.wdog_enabled && !nmi_state.wdog_barked,
462  "WDOG NMI state check2 not expected! wdog_enable:%x wdog_raised:%x",
463  nmi_state.wdog_enabled, nmi_state.wdog_barked);
464 
465  prepare_to_exit();
466  return true;
467 }