Software APIs
sysrst_ctrl_in_irq_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 
10 #include "sw/device/lib/runtime/irq.h"
12 #include "sw/device/lib/testing/rv_plic_testutils.h"
13 #include "sw/device/lib/testing/sysrst_ctrl_testutils.h"
14 #include "sw/device/lib/testing/test_framework/check.h"
15 #include "sw/device/lib/testing/test_framework/ottf_console.h"
17 #include "sw/device/lib/testing/test_framework/ottf_utils.h"
18 
20 
21 /* We need control flow for the ujson messages exchanged
22  * with the host in OTTF_WAIT_FOR on real devices. */
23 OTTF_DEFINE_TEST_CONFIG(.enable_uart_flow_control = true);
24 
25 static dif_sysrst_ctrl_t sysrst_ctrl;
26 static dif_rv_plic_t plic;
27 
28 enum {
29  kCurrentTestPhaseTimeoutUsecDV = 20,
30  kCurrentTestPhaseTimeoutUsecReal = 1000000,
31  kPlicTarget = kTopEarlgreyPlicTargetIbex0,
32 };
33 
34 static volatile bool irq_triggered;
35 
36 // On DV, we must use variables in flash.
37 // On a real device, we must use variables in RAM.
38 // In DV, the sequence can ensure that the pins are set even before the test
39 // runs. On a real device, this is not the case and if the initial value of
40 // kCurrentTestPhaseReal is 0, the very first OTTF_WAIT_FOR could succeed before
41 // the host can set the pins. To avoid this, and only on real devices, set the
42 // initial value to an invalid value so that we have to wait for the host.
43 static volatile const uint8_t kCurrentTestPhaseDV = 0;
44 static volatile uint8_t kCurrentTestPhaseReal = 0xff;
45 uint8_t phase = 0;
46 
47 enum {
48  kOutputNumPads = 0x8,
49  kOutputNumMioPads = 0x6,
50 };
51 
52 static const dif_pinmux_index_t kPeripheralInputs[] = {
59 };
60 
61 static const dif_pinmux_index_t kInputPadsDV[] = {
65 };
66 
67 // We need different pins on the hyperdebug boards since certain
68 // pins are not routed to the hyperdebug.
69 static const dif_pinmux_index_t kInputPadsReal[] = {
73 };
74 
75 void test_phase_sync(void) {
76  test_status_set(kTestStatusInTest);
77  test_status_set(kTestStatusInWfi);
78 }
79 
80 /**
81  * Configure for input change detection, sync with DV side, wait for input
82  * change interrupt, check the interrupt cause and clear it.
83  */
84 void sysrst_ctrl_input_change_detect(
85  dif_sysrst_ctrl_key_intr_src_t expected_key_intr_src) {
86  const uint32_t kCurrentTestPhaseTimeoutUsec =
87  kDeviceType == kDeviceSimDV ? kCurrentTestPhaseTimeoutUsecDV
88  : kCurrentTestPhaseTimeoutUsecReal;
89  const volatile uint8_t *kCurrentTestPhase = kDeviceType == kDeviceSimDV
90  ? &kCurrentTestPhaseDV
91  : &kCurrentTestPhaseReal;
92 
93  irq_triggered = false;
94  LOG_INFO("Wait for test to start: want phase %d", phase);
95  OTTF_WAIT_FOR(phase == *kCurrentTestPhase, kCurrentTestPhaseTimeoutUsec);
96  phase++;
97  LOG_INFO("Setup sysrst_ctrl");
98 
99  // Configure for input change.
101  .input_changes = (dif_sysrst_ctrl_input_change_t)expected_key_intr_src,
102  .debounce_time_threshold = 1, // 5us
103  };
104  CHECK_DIF_OK(
105  dif_sysrst_ctrl_input_change_detect_configure(&sysrst_ctrl, config));
106 
107  // Enable sysrst ctrl irq.
108  CHECK_DIF_OK(dif_sysrst_ctrl_irq_set_enabled(
109  &sysrst_ctrl, kDifSysrstCtrlIrqEventDetected, kDifToggleEnabled));
110 
111  LOG_INFO("Tell host we are ready");
112  test_phase_sync();
113 
114  OTTF_WAIT_FOR(phase == *kCurrentTestPhase, kCurrentTestPhaseTimeoutUsec);
115  phase++;
116  // Check that the interrupt isn't triggered at the first part of the test.
117  CHECK(!irq_triggered, "The interrupt is triggered during input glitch.");
118  LOG_INFO("Tell host we did not detect the glitch");
119  test_phase_sync();
120 
121  ATOMIC_WAIT_FOR_INTERRUPT(irq_triggered);
122 
123  uint32_t causes;
124  CHECK_DIF_OK(
125  dif_sysrst_ctrl_input_change_irq_get_causes(&sysrst_ctrl, &causes));
126  CHECK(causes == expected_key_intr_src, "Intr cause do not match: %d vs %d!",
127  causes, (int)expected_key_intr_src);
128 
129  CHECK_DIF_OK(
130  dif_sysrst_ctrl_input_change_irq_clear_causes(&sysrst_ctrl, causes));
131 
132  // Reset configuration for input change.
133  config.input_changes = 0;
134  CHECK_DIF_OK(
135  dif_sysrst_ctrl_input_change_detect_configure(&sysrst_ctrl, config));
136 
137  // Tell host to finish the test (only on real devices).
138  LOG_INFO("Tell host to finish the test");
139  if (kDeviceType != kDeviceSimDV)
140  test_phase_sync();
141 }
142 
143 /**
144  * Configure for key combo change detection, sync with DV side, wait for input
145  * change interrupt, check the interrupt cause and clear it.
146  */
147 void sysrst_ctrl_key_combo_detect(dif_sysrst_ctrl_key_combo_t key_combo,
148  uint32_t combo_keys) {
149  const uint32_t kCurrentTestPhaseTimeoutUsec =
150  kDeviceType == kDeviceSimDV ? kCurrentTestPhaseTimeoutUsecDV
151  : kCurrentTestPhaseTimeoutUsecReal;
152  const volatile uint8_t *kCurrentTestPhase = kDeviceType == kDeviceSimDV
153  ? &kCurrentTestPhaseDV
154  : &kCurrentTestPhaseReal;
155 
156  irq_triggered = false;
157  LOG_INFO("wait for test to start");
158  OTTF_WAIT_FOR(phase == *kCurrentTestPhase, kCurrentTestPhaseTimeoutUsec);
159  phase++;
160  LOG_INFO("configure sysrst interrupt");
161 
162  // Configure for key combo
163  dif_sysrst_ctrl_key_combo_config_t sysrst_ctrl_key_combo_config = {
164  .keys = combo_keys,
165  .detection_time_threshold = 1,
167  .embedded_controller_reset_duration = 1,
168  };
170  &sysrst_ctrl, key_combo, sysrst_ctrl_key_combo_config));
171 
172  // Enable sysrst ctrl irq.
173  CHECK_DIF_OK(dif_sysrst_ctrl_irq_set_enabled(
174  &sysrst_ctrl, kDifSysrstCtrlIrqEventDetected, kDifToggleEnabled));
175 
176  LOG_INFO("tell host we are ready");
177  test_phase_sync();
178 
179  OTTF_WAIT_FOR(phase == *kCurrentTestPhase, kCurrentTestPhaseTimeoutUsec);
180  phase++;
181  // Check that the interrupt isn't triggered at the first part of the test.
182  CHECK(!irq_triggered, "The interrupt is triggered during input glitch.");
183  LOG_INFO("tell host we did not detect the glitch");
184  test_phase_sync();
185 
186  LOG_INFO("wait for interrupt");
187  ATOMIC_WAIT_FOR_INTERRUPT(irq_triggered);
188  LOG_INFO("interrupt triggered, checks causes");
189 
190  uint32_t causes;
191  CHECK_DIF_OK(dif_sysrst_ctrl_key_combo_irq_get_causes(&sysrst_ctrl, &causes));
192  CHECK(causes == key_combo, "Intr cause do not match: %d vs %d!", causes,
193  (int)key_combo);
194 
195  CHECK_DIF_OK(
196  dif_sysrst_ctrl_key_combo_irq_clear_causes(&sysrst_ctrl, causes));
197 
198  // Reset configuration for key combo.
199  sysrst_ctrl_key_combo_config.keys = 0;
201  &sysrst_ctrl, key_combo, sysrst_ctrl_key_combo_config));
202 
203  // Tell host to finish the test (only on real devices).
204  LOG_INFO("Tell host to finish the test");
205  if (kDeviceType != kDeviceSimDV)
206  test_phase_sync();
207 }
208 
209 /**
210  * External interrupt handler.
211  */
212 void ottf_external_isr(uint32_t *exc_info) {
213  const uint32_t kPlicTarget = kTopEarlgreyPlicTargetIbex0;
214  dif_rv_plic_irq_id_t plic_irq_id = 0;
215  CHECK_DIF_OK(dif_rv_plic_irq_claim(&plic, kPlicTarget, &plic_irq_id));
216 
219 
220  switch (peripheral) {
222  if (!ottf_console_flow_control_isr(exc_info)) {
223  goto unexpected_irq;
224  };
225  break;
227  // Check that the ID matches the expected interrupt, then mask it, since
228  // it's a status type.
229  dif_sysrst_ctrl_irq_t irq =
230  (dif_sysrst_ctrl_irq_t)(plic_irq_id -
233  CHECK(irq == kDifSysrstCtrlIrqEventDetected);
234  CHECK_DIF_OK(dif_sysrst_ctrl_irq_set_enabled(&sysrst_ctrl, irq,
236  irq_triggered = true;
237  } break;
238  default:
239  goto unexpected_irq;
240  }
241 
242  // Complete the IRQ at PLIC.
243  CHECK_DIF_OK(dif_rv_plic_irq_complete(&plic, kPlicTarget, plic_irq_id));
244  return;
245 
246  // A label to jump to for common error handling.
247 unexpected_irq:
248  CHECK(false, "Unexpected external IRQ %d", plic_irq_id);
249 }
250 
251 bool test_main(void) {
252  // Enable global and external IRQ at Ibex.
253  irq_global_ctrl(true);
254  irq_external_ctrl(true);
255 
256  // Initialize the PLIC.
257  mmio_region_t plic_base_addr =
259  CHECK_DIF_OK(dif_rv_plic_init(plic_base_addr, &plic));
260 
261  // Enable all the SYSRST CTRL interrupts on PLIC.
262  rv_plic_testutils_irq_range_enable(
265 
266  // Initialize sysrst ctrl.
267  CHECK_DIF_OK(dif_sysrst_ctrl_init(
269  &sysrst_ctrl));
270 
271  // Set input pins.
272  dif_pinmux_t pinmux;
273  CHECK_DIF_OK(dif_pinmux_init(
275 
276  // On real devices, we also need to configure the DIO pins.
277  if (kDeviceType != kDeviceSimDV) {
278  sysrst_ctrl_testutils_setup_dio(&pinmux);
279  // Release pins so the host can control them.
280  sysrst_ctrl_testutils_release_dio(&sysrst_ctrl, true, true);
281  // Disable the EC reset pulse so that it does not interfere with the test.
282  sysrst_ctrl_testutils_set_ec_rst_pulse_width(&sysrst_ctrl, 0);
283  }
284  const dif_pinmux_index_t *kInputPads =
285  kDeviceType == kDeviceSimDV ? kInputPadsDV : kInputPadsReal;
286  for (int i = 0; i < kOutputNumMioPads; ++i) {
287  CHECK_DIF_OK(
288  dif_pinmux_input_select(&pinmux, kPeripheralInputs[i], kInputPads[i]));
289  }
290 
291  // Test 14 different input transition. 7 L2H and 7 H2L input transition.
295  sysrst_ctrl_input_change_detect(i);
296  }
297 
298  // Test 4 different combo key intr sources with 2, 3, 4 and 5 combo key
299  // transition H2L.
300  uint32_t combo_keys_0 = kDifSysrstCtrlKeyPowerButton | kDifSysrstCtrlKey0;
301  sysrst_ctrl_key_combo_detect(kDifSysrstCtrlKeyCombo0, combo_keys_0);
302 
303  uint32_t combo_keys_1 =
305  sysrst_ctrl_key_combo_detect(kDifSysrstCtrlKeyCombo1, combo_keys_1);
306 
307  uint32_t combo_keys_2 = kDifSysrstCtrlKeyPowerButton | kDifSysrstCtrlKey0 |
309  sysrst_ctrl_key_combo_detect(kDifSysrstCtrlKeyCombo2, combo_keys_2);
310 
311  uint32_t combo_keys_3 = kDifSysrstCtrlKeyPowerButton | kDifSysrstCtrlKey0 |
314  sysrst_ctrl_key_combo_detect(kDifSysrstCtrlKeyCombo3, combo_keys_3);
315 
316  // Last sync with dv side.
317  test_status_set(kTestStatusInTest);
318  return true;
319 }