Software APIs
adc_ctrl_sleep_debug_cable_wakeup_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 
11 #include "sw/device/lib/runtime/irq.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 
18 OTTF_DEFINE_TEST_CONFIG();
19 
20 static const dt_adc_ctrl_t kAdcCtrlDt = 0;
21 static_assert(kDtAdcCtrlCount == 1, "this test expects a adc_ctrl");
22 static const dt_rv_plic_t kRvPlicDt = 0;
23 static_assert(kDtRvPlicCount == 1, "this test expects exactly one rv_plic");
24 static const dt_rstmgr_t kRstmgrDt = 0;
25 static_assert(kDtRstmgrCount == 1, "this test expects a rstmgr");
26 static const dt_pwrmgr_t kPwrmgrDt = 0;
27 static_assert(kDtPwrmgrCount == 1, "this test expects a pwrmgr");
28 
29 enum {
30  kPowerUpTimeAonCycles = 7,
31  kPlicTarget = 0,
32 };
33 
34 // These constants will be setup from the testbench
35 // using sw_symbol_backdoor_overwrite.
36 
37 static volatile const uint8_t kNumLowPowerSamples;
38 static volatile const uint8_t kNumNormalPowerSamples;
39 static volatile const uint8_t kWakeUpTimeAonCycles;
40 
41 static volatile const uint8_t kChannel0MaxLowByte;
42 static volatile const uint8_t kChannel0MaxHighByte;
43 static volatile const uint8_t kChannel0MinLowByte;
44 static volatile const uint8_t kChannel0MinHighByte;
45 
46 static volatile const uint8_t kChannel1MaxLowByte;
47 static volatile const uint8_t kChannel1MaxHighByte;
48 static volatile const uint8_t kChannel1MinLowByte;
49 static volatile const uint8_t kChannel1MinHighByte;
50 
51 static void configure_adc_ctrl(const dif_adc_ctrl_t *adc_ctrl) {
52  CHECK_DIF_OK(dif_adc_ctrl_set_enabled(adc_ctrl, kDifToggleDisabled));
53  CHECK_DIF_OK(dif_adc_ctrl_reset(adc_ctrl));
54  CHECK_DIF_OK(dif_adc_ctrl_configure(
55  adc_ctrl, (dif_adc_ctrl_config_t){
57  .num_low_power_samples = kNumLowPowerSamples,
58  .num_normal_power_samples = kNumNormalPowerSamples,
59  .power_up_time_aon_cycles = kPowerUpTimeAonCycles,
60  .wake_up_time_aon_cycles = kWakeUpTimeAonCycles}));
61 }
62 
63 static dif_adc_ctrl_t adc_ctrl;
64 static dif_rv_plic_t plic;
65 static volatile bool interrupt_expected = false;
66 static volatile bool interrupt_serviced = false;
67 
68 bool ottf_handle_irq(uint32_t *exc_info, dt_instance_id_t devid,
69  dif_rv_plic_irq_id_t irq_id) {
70  if (devid == dt_adc_ctrl_instance_id(kAdcCtrlDt) &&
71  irq_id ==
72  dt_adc_ctrl_irq_to_plic_id(kAdcCtrlDt, kDtAdcCtrlIrqMatchPending)) {
73  // Verify this interrupt was actually expected.
74  CHECK(interrupt_expected);
75  interrupt_serviced = true;
76  CHECK_DIF_OK(
77  dif_adc_ctrl_irq_acknowledge(&adc_ctrl, kDtAdcCtrlIrqMatchPending));
78  return true;
79  } else {
80  return false;
81  }
82 }
83 
84 static void en_plic_irqs(dif_rv_plic_t *plic) {
85  dif_rv_plic_irq_id_t plic_id =
86  dt_adc_ctrl_irq_to_plic_id(kAdcCtrlDt, kDtAdcCtrlIrqMatchPending);
87  CHECK_DIF_OK(dif_rv_plic_irq_set_enabled(plic, plic_id, kPlicTarget,
89 
90  // Assign a default priority
91  CHECK_DIF_OK(dif_rv_plic_irq_set_priority(plic, plic_id, 0x1));
92 
93  // Enable the external IRQ at Ibex.
94  irq_global_ctrl(true);
95  irq_external_ctrl(true);
96 }
97 
98 bool test_main(void) {
99  dif_pwrmgr_t pwrmgr;
100  dif_rstmgr_t rstmgr;
101 
102  CHECK_DIF_OK(dif_adc_ctrl_init_from_dt(kAdcCtrlDt, &adc_ctrl));
103  CHECK_DIF_OK(dif_pwrmgr_init_from_dt(kPwrmgrDt, &pwrmgr));
104  CHECK_DIF_OK(dif_rstmgr_init_from_dt(kRstmgrDt, &rstmgr));
105  CHECK_DIF_OK(dif_rv_plic_init_from_dt(kRvPlicDt, &plic));
106 
107  dif_pwrmgr_request_sources_t wakeup_sources;
108  CHECK_DIF_OK(dif_pwrmgr_find_request_source(
109  &pwrmgr, kDifPwrmgrReqTypeWakeup, dt_adc_ctrl_instance_id(kAdcCtrlDt),
110  kDtAdcCtrlWakeupWkupReq, &wakeup_sources));
111 
112  // Enable adc interrupts.
113  CHECK_DIF_OK(dif_adc_ctrl_irq_set_enabled(
114  &adc_ctrl, kDifAdcCtrlIrqMatchPending, kDifToggleEnabled));
115 
116  uint16_t channel0_filter0_max =
117  (uint16_t)(kChannel0MaxHighByte << 8) | kChannel0MaxLowByte;
118  uint16_t channel0_filter0_min =
119  (uint16_t)(kChannel0MinHighByte << 8) | kChannel0MinLowByte;
120  uint16_t channel1_filter0_max =
121  (uint16_t)(kChannel1MaxHighByte << 8) | kChannel1MaxLowByte;
122  uint16_t channel1_filter0_min =
123  (uint16_t)(kChannel1MinHighByte << 8) | kChannel1MinLowByte;
124 
125  // Assuming the chip hasn't slept yet, wakeup reason should be empty.
126  if (UNWRAP(pwrmgr_testutils_is_wakeup_reason(&pwrmgr, 0)) == true) {
127  LOG_INFO("POR reset.");
128  interrupt_expected = false;
129  en_plic_irqs(&plic);
130 
131  CHECK(UNWRAP(
132  rstmgr_testutils_is_reset_info(&rstmgr, kDifRstmgrResetInfoPor)));
133 
134  // Setup ADC configuration.
135  configure_adc_ctrl(&adc_ctrl);
136 
137  // Setup ADC filters. There is one filter for each channel.
138  CHECK_DIF_OK(dif_adc_ctrl_configure_filter(
139  &adc_ctrl, kDifAdcCtrlChannel0,
140  (dif_adc_ctrl_filter_config_t){.filter = kDifAdcCtrlFilter0,
141  .generate_irq_on_match = true,
142  .generate_wakeup_on_match = true,
143  .in_range = true,
144  .max_voltage = channel0_filter0_max,
145  .min_voltage = channel0_filter0_min},
147  CHECK_DIF_OK(dif_adc_ctrl_configure_filter(
148  &adc_ctrl, kDifAdcCtrlChannel1,
149  (dif_adc_ctrl_filter_config_t){.filter = kDifAdcCtrlFilter0,
150  .generate_irq_on_match = true,
151  .generate_wakeup_on_match = true,
152  .in_range = true,
153  .max_voltage = channel1_filter0_max,
154  .min_voltage = channel1_filter0_min},
156 
157  // enable filters.
158  CHECK_DIF_OK(dif_adc_ctrl_filter_set_enabled(
159  &adc_ctrl, kDifAdcCtrlChannel0, kDifAdcCtrlFilter0, kDifToggleEnabled));
160  CHECK_DIF_OK(dif_adc_ctrl_filter_set_enabled(
161  &adc_ctrl, kDifAdcCtrlChannel1, kDifAdcCtrlFilter0, kDifToggleEnabled));
162 
163  CHECK_DIF_OK(dif_adc_ctrl_set_enabled(&adc_ctrl, kDifToggleEnabled));
164 
165  // Setup low power.
166  CHECK_STATUS_OK(rstmgr_testutils_pre_reset(&rstmgr));
167  CHECK_STATUS_OK(
168  pwrmgr_testutils_enable_low_power(&pwrmgr, wakeup_sources, 0));
169  // Enter low power mode.
170  LOG_INFO("Issued WFI to enter sleep.");
171  test_status_set(kTestStatusInWfi);
173  } else if (UNWRAP(pwrmgr_testutils_is_wakeup_reason(
174  &pwrmgr, wakeup_sources)) == true) {
175  LOG_INFO("Wakeup reset.");
176  interrupt_expected = true;
177  en_plic_irqs(&plic);
178 
179  CHECK(UNWRAP(rstmgr_testutils_is_reset_info(
181  uint16_t adc_value;
183  &adc_ctrl, kDifAdcCtrlChannel0, &adc_value));
184  CHECK(channel0_filter0_min <= adc_value &&
185  adc_value <= channel0_filter0_max);
186 
188  &adc_ctrl, kDifAdcCtrlChannel1, &adc_value));
189  CHECK(channel1_filter0_min <= adc_value &&
190  adc_value <= channel1_filter0_max);
191 
192  // Interrupt should have been serviced.
193  CHECK(interrupt_serviced);
194  return true;
195 
196  } else {
197  dif_pwrmgr_wakeup_reason_t wakeup_reason;
198  CHECK_DIF_OK(dif_pwrmgr_wakeup_reason_get(&pwrmgr, &wakeup_reason));
199  LOG_ERROR("Unexpected wakeup detected: type = %d, request_source = %d",
200  wakeup_reason.types, wakeup_reason.request_sources);
201  return false;
202  }
203  return false;
204 }