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