Software APIs
aon_timer_smoketest.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 #include <stdint.h>
6 
9 #include "sw/device/lib/dif/dif_rv_core_ibex.h"
12 #include "sw/device/lib/testing/aon_timer_testutils.h"
13 #include "sw/device/lib/testing/test_framework/check.h"
15 
16 static_assert(kDtAonTimerCount >= 1,
17  "This test requires at least one AON Timer instance");
18 static_assert(kDtRvCoreIbexCount >= 1,
19  "This test requires at least one rv_core_ibex instance");
20 
21 static const dt_aon_timer_t kTestAonTimer = (dt_aon_timer_t)0;
22 static const dt_rv_core_ibex_t kTestRvCoreIbex = (dt_rv_core_ibex_t)0;
23 
24 OTTF_DEFINE_TEST_CONFIG();
25 
26 static dif_aon_timer_t aon;
27 static dif_rv_core_ibex_t rv_core_ibex;
28 static volatile bool wdog_fired = false;
29 
30 static void aon_timer_test_wakeup_timer(dif_aon_timer_t *aon) {
31  // Test the wake-up timer functionality by setting a single cycle counter.
32  // Delay to compensate for AON Timer 200kHz clock (less should suffice, but
33  // to be on a cautious side - lets keep it at 100 for now).
34  CHECK_STATUS_OK(aon_timer_testutils_wakeup_config(aon, 1));
35 
36  busy_spin_micros(100);
37 
38  // Make sure that the timer has expired.
39  bool is_pending;
40  CHECK_DIF_OK(dif_aon_timer_irq_is_pending(
41  aon, kDifAonTimerIrqWkupTimerExpired, &is_pending));
42  CHECK(is_pending);
43 
44  CHECK_DIF_OK(dif_aon_timer_wakeup_stop(aon));
45 
46  CHECK_DIF_OK(
47  dif_aon_timer_irq_acknowledge(aon, kDifAonTimerIrqWkupTimerExpired));
48 }
49 
50 /**
51  * OTTF external NMI internal IRQ handler.
52  * The ROM configures the watchdog to generates a NMI at bark, so we clean the
53  * NMI.
54  */
55 void ottf_external_nmi_handler(void) {
56  bool is_pending;
57  // The watchdog bark external interrupt is also connected to the NMI input
58  // of rv_core_ibex. We therefore expect the interrupt to be pending on the
59  // peripheral side.
60  CHECK_DIF_OK(dif_aon_timer_irq_is_pending(&aon, kDifAonTimerIrqWdogTimerBark,
61  &is_pending));
62  if (is_pending) {
63  wdog_fired = true;
64  CHECK_DIF_OK(dif_aon_timer_watchdog_stop(&aon));
65  // In order to handle the NMI we need to acknowledge the interrupt status
66  // bit at the peripheral side.
67  CHECK_DIF_OK(
68  dif_aon_timer_irq_acknowledge(&aon, kDifAonTimerIrqWdogTimerBark));
69 
70  CHECK_DIF_OK(dif_rv_core_ibex_clear_nmi_state(&rv_core_ibex,
71  kDifRvCoreIbexNmiSourceWdog));
72  }
73 }
74 
75 static void aon_timer_test_watchdog_timer(dif_aon_timer_t *aon) {
76  // Test the watchdog timer functionality by setting a single cycle "bark"
77  // counter. Delay to compensate for AON Timer 200kHz clock (less should
78  // suffice, but to be on a cautious side - lets keep it at 100 for now).
79  CHECK_STATUS_OK(
80  aon_timer_testutils_watchdog_config(aon, 1, UINT32_MAX, false));
81  busy_spin_micros(100);
82 
84  CHECK_DIF_OK(dif_rv_core_ibex_get_nmi_state(&rv_core_ibex, &nmi_state));
85 
86  // The TestROM does not enable NMI so we need to check that the IRQ was
87  // requested.
88  if (!nmi_state.wdog_enabled) {
89  // Make sure that the timer has expired.
90  bool is_pending;
91  CHECK_DIF_OK(dif_aon_timer_irq_is_pending(aon, kDifAonTimerIrqWdogTimerBark,
92  &is_pending));
93  CHECK(is_pending);
94 
95  CHECK_DIF_OK(dif_aon_timer_watchdog_stop(aon));
96 
97  CHECK_DIF_OK(
98  dif_aon_timer_irq_acknowledge(aon, kDifAonTimerIrqWdogTimerBark));
99  } else {
100  CHECK(wdog_fired);
101  }
102 }
103 
104 bool test_main(void) {
105  LOG_INFO("Running AON timer test");
106 
107  // Initialise AON Timer.
108  CHECK_DIF_OK(dif_aon_timer_init_from_dt(kTestAonTimer, &aon));
109  CHECK_DIF_OK(dif_rv_core_ibex_init_from_dt(kTestRvCoreIbex, &rv_core_ibex));
110 
111  aon_timer_test_wakeup_timer(&aon);
112  aon_timer_test_watchdog_timer(&aon);
113 
114  return true;
115 }