Software APIs
sleep_pin_wake_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 
9 #include "sw/device/lib/runtime/irq.h"
11 #include "sw/device/lib/testing/flash_ctrl_testutils.h"
12 #include "sw/device/lib/testing/pwrmgr_testutils.h"
13 #include "sw/device/lib/testing/rand_testutils.h"
14 #include "sw/device/lib/testing/rv_plic_testutils.h"
15 #include "sw/device/lib/testing/test_framework/check.h"
17 #include "sw/device/lib/testing/test_framework/ottf_utils.h"
18 
20 #include "sw/device/lib/testing/autogen/isr_testutils.h"
21 // Below includes are generated during compile time.
22 #include "flash_ctrl_regs.h"
23 #include "pinmux_regs.h"
24 
25 /* We need control flow for the ujson messages exchanged
26  * with the host in OTTF_WAIT_FOR on real devices. */
27 OTTF_DEFINE_TEST_CONFIG(.enable_uart_flow_control = true);
28 
29 // PLIC structures
30 static dif_pwrmgr_t pwrmgr;
31 static dif_pinmux_t pinmux;
32 static dif_rv_plic_t plic;
33 static dif_flash_ctrl_state_t flash_ctrl_state;
34 
35 static const uint32_t kNumDio = 16; // top_earlgrey has 16 DIOs
36 
37 // kDirectDio is a list of Dio index that TB cannot control the PAD value.
38 // The list should be incremental order (see the code below)
39 #define NUM_DIRECT_DIO 5
40 static const uint32_t kDirectDio[NUM_DIRECT_DIO] = {6, 12, 13, 14, 15};
41 
42 static plic_isr_ctx_t plic_ctx = {.rv_plic = &plic,
43  .hart_id = kTopEarlgreyPlicTargetIbex0};
44 
45 static pwrmgr_isr_ctx_t pwrmgr_isr_ctx = {
46  .pwrmgr = &pwrmgr,
47  .plic_pwrmgr_start_irq_id = kTopEarlgreyPlicIrqIdPwrmgrAonWakeup,
48  .expected_irq = kDifPwrmgrIrqWakeup,
49  .is_only_irq = true};
50 
51 // Preserve wakeup_detector_selected over multiple resets
52 OT_SET_BSS_SECTION(".non_volatile_scratch", uint32_t wakeup_detector_idx;)
53 
54 OTTF_BACKDOOR_VAR
55 int8_t sival_mio_pad = -1; // -1 means not assigned yet.
56 OTTF_BACKDOOR_VAR
57 int8_t sival_wakeup_detector_idx = -1; // -1 means not assigned yet.
58 OTTF_BACKDOOR_VAR
59 bool sival_ready_to_sleep = false;
60 
61 /**
62  * External interrupt handler.
63  */
64 void ottf_external_isr(uint32_t *exc_info) {
65  dif_pwrmgr_irq_t irq_id;
67 
68  isr_testutils_pwrmgr_isr(plic_ctx, pwrmgr_isr_ctx, &peripheral, &irq_id);
69 
70  // Check that both the peripheral and the irq id is correct
71  CHECK(peripheral == kTopEarlgreyPlicPeripheralPwrmgrAon,
72  "IRQ peripheral: %d is incorrect", peripheral);
73  CHECK(irq_id == kDifPwrmgrIrqWakeup, "IRQ ID: %d is incorrect", irq_id);
74 }
75 
76 bool test_main(void) {
77  dif_pinmux_wakeup_config_t wakeup_cfg;
78 
79  // Default Deep Power Down
80  dif_pwrmgr_domain_config_t pwrmgr_domain_cfg = 0;
81 
82  // Enable global and external IRQ at Ibex.
83  irq_global_ctrl(true);
84  irq_external_ctrl(true);
85 
86  // Initialize power manager
87  CHECK_DIF_OK(dif_pwrmgr_init(
89  CHECK_DIF_OK(dif_rv_plic_init(
91  CHECK_DIF_OK(dif_pinmux_init(
93  CHECK_DIF_OK(dif_flash_ctrl_init_state(
94  &flash_ctrl_state,
96 
97  if (kDeviceType == kDeviceSimDV) {
98  // Enable access to flash for storing info across resets.
99  CHECK_STATUS_OK(
100  flash_ctrl_testutils_default_region_access(&flash_ctrl_state,
101  /*rd_en*/ true,
102  /*prog_en*/ true,
103  /*erase_en*/ true,
104  /*scramble_en*/ false,
105  /*ecc_en*/ false,
106  /*he_en*/ false));
107  }
108 
109  // Randomly pick one of the wakeup detectors
110  // only after the first boot.
111  dif_pinmux_index_t wakeup_detector_selected = 0;
112 
113  if (UNWRAP(pwrmgr_testutils_is_wakeup_reason(&pwrmgr, 0)) == true) {
114  LOG_INFO("Test in POR phase");
115 
116  // After randomly generated wake detector index,
117  // store to non volatile area to preserve from the reset event.
118  wakeup_detector_selected =
119  rand_testutils_gen32_range(0, PINMUX_PARAM_N_WKUP_DETECT - 1);
120  if (kDeviceType == kDeviceSimDV) {
121  CHECK_STATUS_OK(flash_ctrl_testutils_write(
122  &flash_ctrl_state,
123  (uint32_t)(&wakeup_detector_idx) -
125  0, &wakeup_detector_selected, kDifFlashCtrlPartitionTypeData, 1));
126  }
127  LOG_INFO("detector %d is selected", wakeup_detector_selected);
128  // TODO(lowrisc/opentitan#15889): The weak pull on IOC3 needs to be
129  // disabled for this test. Remove this later.
130  dif_pinmux_pad_attr_t out_attr;
131  dif_pinmux_pad_attr_t in_attr = {0};
132  CHECK_DIF_OK(dif_pinmux_pad_write_attrs(&pinmux, kTopEarlgreyMuxedPadsIoc3,
133  kDifPinmuxPadKindMio, in_attr,
134  &out_attr));
135 
136  // This print is placed here on purpose.
137  // sv sequence is waiting for this print log followed by
138  // Pad Section. So do not put any other print between
139  // this LOG_INFO and LOG_INFO("Pad Selection");
140  LOG_INFO("pinmux_init end");
141  // Random choose low power or deep powerdown
142  uint32_t deep_powerdown_en = rand_testutils_gen32_range(0, 1);
143 
144  // Prepare which PAD SW want to select. In SiVal we only test the MIO pads,
145  // as the DIO ones are generally not testable with our setup.
146  uint32_t mio0_dio1 =
147  (kDeviceType == kDeviceSimDV) ? rand_testutils_gen32_range(0, 1) : 0;
148  uint32_t pad_sel = 0;
149 
150  // Enable AonWakeup Interrupt if normal sleep
151  if (deep_powerdown_en == 0) {
152  // Enable all the AON interrupts used in this test.
153  rv_plic_testutils_irq_range_enable(&plic, kTopEarlgreyPlicTargetIbex0,
156  // Enable pwrmgr interrupt
157  CHECK_DIF_OK(dif_pwrmgr_irq_set_enabled(&pwrmgr, 0, kDifToggleEnabled));
158  }
159 
160  // SpiDev CLK(idx 12), CS#(idx 13), D0(idx 6) and SpiHost CLK (14), CS#
161  // (15) are directly connected to the SPI IF. Cannot control them. Roll 3
162  // less and compensated later.
163  if (mio0_dio1) {
164  // DIO
165  pad_sel = rand_testutils_gen32_range(0, kNumDio - 1 - NUM_DIRECT_DIO);
166 
167  for (int i = 0; i < NUM_DIRECT_DIO; i++) {
168  if (pad_sel >= kDirectDio[i]) {
169  pad_sel++;
170  }
171  }
172  LOG_INFO("Pad Selection: %d / %d", mio0_dio1, pad_sel);
173  } else {
174  // MIO: 0, 1 are tie-0, tie-1
175  if (kDeviceType == kDeviceSimDV) {
176  pad_sel = rand_testutils_gen32_range(2, kTopEarlgreyPinmuxInselLast);
177  } else {
178  OTTF_WAIT_FOR(sival_mio_pad != -1, 1000000);
179  pad_sel = (uint32_t)sival_mio_pad + 2; // skip 0, 1 (see above)
180  }
181 
182  LOG_INFO("Pad Selection: %d / %d", mio0_dio1, pad_sel - 2);
183  }
184 
185  if (mio0_dio1 == 0) {
186  // TODO: Check if the PAD is locked (kDifPinmuxLockTargetOutsel), then
187  // skip if locked.
188  // Turn off Pinmux output selection
189  CHECK_DIF_OK(dif_pinmux_output_select(
190  &pinmux, pad_sel - 2, kTopEarlgreyPinmuxOutselConstantHighZ));
191  }
192 
194  wakeup_cfg.signal_filter = false;
195  wakeup_cfg.pad_type = mio0_dio1;
196  wakeup_cfg.pad_select = pad_sel;
197 
198  // TODO: A better test would be to program ALL wakeup detectors with
199  // randomly chosen pin wakeup sources and prove the right wakeup source
200  // woke up the chip from sleep.
202  &pinmux, wakeup_detector_selected, wakeup_cfg));
203 
204  if (deep_powerdown_en == 0) {
205  CHECK_DIF_OK(dif_pwrmgr_get_domain_config(&pwrmgr, &pwrmgr_domain_cfg));
206  pwrmgr_domain_cfg |= kDifPwrmgrDomainOptionMainPowerInLowPower;
207  }
208 
209  if (kDeviceType != kDeviceSimDV) {
210  OTTF_WAIT_FOR(sival_ready_to_sleep != 0, 1000000);
211  }
212 
213  // Enter low power
214  CHECK_STATUS_OK(pwrmgr_testutils_enable_low_power(
215  &pwrmgr, kDifPwrmgrWakeupRequestSourceThree, pwrmgr_domain_cfg));
216 
217  LOG_INFO("Entering low power mode.");
219  }
220 
221  if (UNWRAP(pwrmgr_testutils_is_wakeup_reason(
222  &pwrmgr, kDifPwrmgrWakeupRequestSourceThree)) == true) {
223  LOG_INFO("Test in post-sleep pin wakeup phase");
224  uint32_t wakeup_cause;
225  CHECK_DIF_OK(dif_pinmux_wakeup_cause_get(&pinmux, &wakeup_cause));
226  // Get the wakeup dectector index from stored variable.
227  if (kDeviceType == kDeviceSimDV) {
228  wakeup_detector_selected = wakeup_detector_idx;
229  } else {
230  OTTF_WAIT_FOR(sival_wakeup_detector_idx != -1, 1000000);
231  wakeup_detector_selected = (uint32_t)sival_wakeup_detector_idx;
232  }
233 
234  LOG_INFO("wakeup_cause: %x %d %d", wakeup_cause,
235  1 << wakeup_detector_selected, wakeup_detector_selected);
236  CHECK(wakeup_cause == 1 << wakeup_detector_selected);
237  CHECK_DIF_OK(
238  dif_pinmux_wakeup_detector_disable(&pinmux, wakeup_detector_selected));
239  return true;
240 
241  } else {
242  // Other wakeup. This is a failure.
243  dif_pwrmgr_wakeup_reason_t wakeup_reason;
244  CHECK_DIF_OK(dif_pwrmgr_wakeup_reason_get(&pwrmgr, &wakeup_reason));
245  LOG_ERROR("Unexpected wakeup detected: type = %d, request_source = %d",
246  wakeup_reason.types, wakeup_reason.request_sources);
247  return false;
248  }
249 
250  return false;
251 }
252 
253 #undef NUM_DIRECT_DIO
254 #undef NUM_LOCKED_MIO