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 
19 #include "sw/device/lib/testing/autogen/isr_testutils.h"
20 
21 OTTF_DEFINE_TEST_CONFIG();
22 
23 enum {
24  kPowerUpTimeAonCycles = 7,
25 };
26 
27 // These constants will be setup from the testbench
28 // using sw_symbol_backdoor_overwrite.
29 
30 static volatile const uint8_t kNumLowPowerSamples;
31 static volatile const uint8_t kNumNormalPowerSamples;
32 static volatile const uint8_t kWakeUpTimeAonCycles;
33 
34 static volatile const uint8_t kChannel0MaxLowByte;
35 static volatile const uint8_t kChannel0MaxHighByte;
36 static volatile const uint8_t kChannel0MinLowByte;
37 static volatile const uint8_t kChannel0MinHighByte;
38 
39 static volatile const uint8_t kChannel1MaxLowByte;
40 static volatile const uint8_t kChannel1MaxHighByte;
41 static volatile const uint8_t kChannel1MinLowByte;
42 static volatile const uint8_t kChannel1MinHighByte;
43 
44 static void configure_adc_ctrl(const dif_adc_ctrl_t *adc_ctrl) {
45  CHECK_DIF_OK(dif_adc_ctrl_set_enabled(adc_ctrl, kDifToggleDisabled));
46  CHECK_DIF_OK(dif_adc_ctrl_reset(adc_ctrl));
47  CHECK_DIF_OK(dif_adc_ctrl_configure(
48  adc_ctrl, (dif_adc_ctrl_config_t){
50  .num_low_power_samples = kNumLowPowerSamples,
51  .num_normal_power_samples = kNumNormalPowerSamples,
52  .power_up_time_aon_cycles = kPowerUpTimeAonCycles,
53  .wake_up_time_aon_cycles = kWakeUpTimeAonCycles}));
54 }
55 
56 static dif_adc_ctrl_t adc_ctrl;
57 static dif_rv_plic_t plic;
58 static volatile bool interrupt_expected = false;
59 static volatile bool interrupt_serviced = false;
60 
61 void ottf_external_isr(uint32_t *exc_info) {
62  plic_isr_ctx_t plic_ctx = {.rv_plic = &plic,
63  .hart_id = kTopEarlgreyPlicTargetIbex0};
64 
65  adc_ctrl_isr_ctx_t adc_ctrl_ctx = {
66  .adc_ctrl = &adc_ctrl,
67  .plic_adc_ctrl_start_irq_id = kTopEarlgreyPlicIrqIdAdcCtrlAonMatchPending,
68  .expected_irq = 0,
69  .is_only_irq = true};
70 
72  dif_adc_ctrl_irq_t adc_ctrl_irq;
73  isr_testutils_adc_ctrl_isr(plic_ctx, adc_ctrl_ctx, false, &peripheral,
74  &adc_ctrl_irq);
75 
76  CHECK(peripheral == kTopEarlgreyPlicPeripheralAdcCtrlAon);
77  CHECK(adc_ctrl_irq == kDifAdcCtrlIrqMatchPending);
78  interrupt_serviced = true;
79 
80  // Verify this interrupt was actually expected.
81  CHECK(interrupt_expected);
82 }
83 
84 static void en_plic_irqs(dif_rv_plic_t *plic) {
85  top_earlgrey_plic_irq_id_t plic_irqs[] = {
87 
88  for (uint32_t i = 0; i < ARRAYSIZE(plic_irqs); ++i) {
89  CHECK_DIF_OK(dif_rv_plic_irq_set_enabled(
90  plic, plic_irqs[i], kTopEarlgreyPlicTargetIbex0, kDifToggleEnabled));
91 
92  // Assign a default priority
93  CHECK_DIF_OK(dif_rv_plic_irq_set_priority(plic, plic_irqs[i], 0x1));
94  }
95 
96  // Enable the external IRQ at Ibex.
97  irq_global_ctrl(true);
98  irq_external_ctrl(true);
99 }
100 
101 bool test_main(void) {
102  dif_pwrmgr_t pwrmgr;
103  dif_rstmgr_t rstmgr;
104 
105  CHECK_DIF_OK(dif_adc_ctrl_init(
107  CHECK_DIF_OK(dif_pwrmgr_init(
109  CHECK_DIF_OK(dif_rstmgr_init(
111  CHECK_DIF_OK(dif_rv_plic_init(
113 
114  // Enable adc interrupts.
115  CHECK_DIF_OK(dif_adc_ctrl_irq_set_enabled(
116  &adc_ctrl, kDifAdcCtrlIrqMatchPending, kDifToggleEnabled));
117 
118  uint16_t channel0_filter0_max =
119  (uint16_t)(kChannel0MaxHighByte << 8) | kChannel0MaxLowByte;
120  uint16_t channel0_filter0_min =
121  (uint16_t)(kChannel0MinHighByte << 8) | kChannel0MinLowByte;
122  uint16_t channel1_filter0_max =
123  (uint16_t)(kChannel1MaxHighByte << 8) | kChannel1MaxLowByte;
124  uint16_t channel1_filter0_min =
125  (uint16_t)(kChannel1MinHighByte << 8) | kChannel1MinLowByte;
126 
127  // Assuming the chip hasn't slept yet, wakeup reason should be empty.
128  if (UNWRAP(pwrmgr_testutils_is_wakeup_reason(&pwrmgr, 0)) == true) {
129  LOG_INFO("POR reset.");
130  interrupt_expected = false;
131  en_plic_irqs(&plic);
132 
133  CHECK(UNWRAP(
134  rstmgr_testutils_is_reset_info(&rstmgr, kDifRstmgrResetInfoPor)));
135 
136  // Setup ADC configuration.
137  configure_adc_ctrl(&adc_ctrl);
138 
139  // Setup ADC filters. There is one filter for each channel.
140  CHECK_DIF_OK(dif_adc_ctrl_configure_filter(
141  &adc_ctrl, kDifAdcCtrlChannel0,
142  (dif_adc_ctrl_filter_config_t){.filter = kDifAdcCtrlFilter0,
143  .generate_irq_on_match = true,
144  .generate_wakeup_on_match = true,
145  .in_range = true,
146  .max_voltage = channel0_filter0_max,
147  .min_voltage = channel0_filter0_min},
149  CHECK_DIF_OK(dif_adc_ctrl_configure_filter(
150  &adc_ctrl, kDifAdcCtrlChannel1,
151  (dif_adc_ctrl_filter_config_t){.filter = kDifAdcCtrlFilter0,
152  .generate_irq_on_match = true,
153  .generate_wakeup_on_match = true,
154  .in_range = true,
155  .max_voltage = channel1_filter0_max,
156  .min_voltage = channel1_filter0_min},
158 
159  // enable filters.
160  CHECK_DIF_OK(dif_adc_ctrl_filter_set_enabled(
161  &adc_ctrl, kDifAdcCtrlChannel0, kDifAdcCtrlFilter0, kDifToggleEnabled));
162  CHECK_DIF_OK(dif_adc_ctrl_filter_set_enabled(
163  &adc_ctrl, kDifAdcCtrlChannel1, kDifAdcCtrlFilter0, kDifToggleEnabled));
164 
165  CHECK_DIF_OK(dif_adc_ctrl_set_enabled(&adc_ctrl, kDifToggleEnabled));
166 
167  // Setup low power.
168  CHECK_STATUS_OK(rstmgr_testutils_pre_reset(&rstmgr));
169  CHECK_STATUS_OK(pwrmgr_testutils_enable_low_power(
170  &pwrmgr, kDifPwrmgrWakeupRequestSourceTwo, 0));
171  // Enter low power mode.
172  LOG_INFO("Issued WFI to enter sleep.");
173  test_status_set(kTestStatusInWfi);
175  } else if (UNWRAP(pwrmgr_testutils_is_wakeup_reason(
176  &pwrmgr, kDifPwrmgrWakeupRequestSourceTwo)) == true) {
177  LOG_INFO("Wakeup reset.");
178  interrupt_expected = true;
179  en_plic_irqs(&plic);
180 
181  CHECK(UNWRAP(rstmgr_testutils_is_reset_info(
183  uint16_t adc_value;
185  &adc_ctrl, kDifAdcCtrlChannel0, &adc_value));
186  CHECK(channel0_filter0_min <= adc_value &&
187  adc_value <= channel0_filter0_max);
188 
190  &adc_ctrl, kDifAdcCtrlChannel1, &adc_value));
191  CHECK(channel1_filter0_min <= adc_value &&
192  adc_value <= channel1_filter0_max);
193 
194  // Interrupt should have been serviced.
195  CHECK(interrupt_serviced);
196  return true;
197 
198  } else {
199  dif_pwrmgr_wakeup_reason_t wakeup_reason;
200  CHECK_DIF_OK(dif_pwrmgr_wakeup_reason_get(&pwrmgr, &wakeup_reason));
201  LOG_ERROR("Unexpected wakeup detected: type = %d, request_source = %d",
202  wakeup_reason.types, wakeup_reason.request_sources);
203  return false;
204  }
205  return false;
206 }