Software APIs
clkmgr_testutils.h
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 #ifndef OPENTITAN_SW_DEVICE_LIB_TESTING_CLKMGR_TESTUTILS_H_
6 #define OPENTITAN_SW_DEVICE_LIB_TESTING_CLKMGR_TESTUTILS_H_
7 
8 #include "sw/device/lib/base/status.h"
11 #include "sw/device/lib/testing/test_framework/check.h"
12 
13 #define MODULE_ID MAKE_MODULE_ID('c', 'm', 'h')
14 
15 /**
16  * Returns the transactional block's clock status.
17  *
18  * @param clkmgr A clkmgr DIF handle.
19  * @param params clkmgr hardware instance parameters.
20  * @param clock The transactional clock ID.
21  * @return The transactional block's clock status.
22  */
23 static inline bool clkmgr_testutils_get_trans_clock_status(
24  const dif_clkmgr_t *clkmgr, dif_clkmgr_hintable_clock_t clock) {
25  dif_toggle_t state;
26  dif_result_t res =
27  dif_clkmgr_hintable_clock_get_enabled(clkmgr, clock, &state);
28  return res == kDifOk && state == kDifToggleEnabled;
29 }
30 
31 /**
32  * Verifies clock gating for transactional clocks.
33  *
34  * For a transactional block, the clock is gated only if the software enables
35  * the clock gating AND the block is idle. This function sets the clock gating
36  * hint bit to 0 and spinwaits until the clock value matches the expected. It
37  * sets the hint back to 1 afterwards. Inlined due to latency-sensitivity.
38  *
39  * @param clkmgr A clkmgr DIF handle.
40  * @param clock The transactional clock ID.
41  * @param exp_clock_enabled Expected clock status.
42  * @param timeout_usec Timeout in microseconds.
43  * @return The result of the operation.
44  */
46 inline status_t clkmgr_testutils_check_trans_clock_gating(
47  const dif_clkmgr_t *clkmgr, dif_clkmgr_hintable_clock_t clock,
48  bool exp_clock_enabled, uint32_t timeout_usec) {
49  TRY(dif_clkmgr_hintable_clock_set_hint(clkmgr, clock, 0x0));
50 
51  IBEX_TRY_SPIN_FOR(clkmgr_testutils_get_trans_clock_status(clkmgr, clock) ==
52  exp_clock_enabled,
53  timeout_usec);
54 
55  TRY(dif_clkmgr_hintable_clock_set_hint(clkmgr, clock, 0x1));
56  return OK_STATUS();
57 }
58 
59 /**
60  * Returns the name of a measured clock.
61  */
62 const char *clkmgr_testutils_measurement_name(dif_clkmgr_measure_clock_t clock);
63 
64 /**
65  * Enables clock measurements.
66  *
67  * This enables measurements with lo and hi count bounds for a given clock.
68  *
69  * @param clkmgr A clkmgr DIF handle.
70  * @param clock The clock to be measured.
71  * @param lo_threshold Expected minimum cycle count.
72  * @param hi_threshold Expected maximum cycle count.
73  * @return The result of the operation.
74  */
76 status_t clkmgr_testutils_enable_clock_count(const dif_clkmgr_t *clkmgr,
77  dif_clkmgr_measure_clock_t clock,
78  uint32_t lo_threshold,
79  uint32_t hi_threshold);
80 
81 /**
82  * Enables all clock measurements with expected thresholds.
83  *
84  * If jitter is disabled the thresholds are configured tightly.
85  * If jitter is enabled the min threshold allows more variability.
86  *
87  * @param clkmgr A clkmgr DIF handle.
88  * @param jitter_enabled If true relax the min threshold.
89  * @param external_clk If true the external clock is enabled.
90  * @param low_speed If true and external clock is enabled, the external
91  * clock is running at 48 Mhz.
92  * @return The result of the operation.
93  */
95 status_t clkmgr_testutils_enable_clock_counts_with_expected_thresholds(
96  const dif_clkmgr_t *clkmgr, bool jitter_enabled, bool external_clk,
97  bool low_speed);
98 
99 /**
100  * Checks that there are no clock measurement errors.
101  *
102  * @param clkmgr A clkmgr DIF handle.
103  * @return Return `kInternal` if any measurement has errors, otherwise `kOk(0)`.
104  */
106 status_t clkmgr_testutils_check_measurement_counts(const dif_clkmgr_t *clkmgr);
107 
108 /**
109  * Check all measurement enables.
110  *
111  * @param clkmgr A clkmgr DIF handle.
112  * @param expected_status The expected status of the enables.
113  * @return False if any enable status is unexpected.
114  * @return Return `kInternal` in case of errors, otherwise `kOk(res)`, where
115  * `res` is false if any enable status is unexpected`.
116  */
118 status_t clkmgr_testutils_check_measurement_enables(
119  const dif_clkmgr_t *clkmgr, dif_toggle_t expected_status);
120 
121 /**
122  * Disable all clock measurements.
123  *
124  * @param clkmgr A clkmgr DIF handle.
125  * @return The result of the operation.
126  */
128 status_t clkmgr_testutils_disable_clock_counts(const dif_clkmgr_t *clkmgr);
129 
130 /**
131  * Switch to use external clock and wait until the switching is done.
132  *
133  * @param clkmgr A clkmgr DIF handle.
134  * @param is_low_speed Is external clock in low speed mode or not.
135  * @return The result of the operation.
136  */
138 status_t clkmgr_testutils_enable_external_clock_blocking(
139  const dif_clkmgr_t *clkmgr, bool is_low_speed);
140 
141 /**
142  * Verifies the given clock state.
143  *
144  * @param clkmgr A clkmgr DIF handle.
145  * @param clock_id The transactional clock ID.
146  * @param expected_state Expected clock state.
147  * @return Return `kInternal` in case of errors, otherwise `kOk(0)`.
148  */
149 #define CLKMGR_TESTUTILS_CHECK_CLOCK_HINT(clkmgr, clock_id, expected_state) \
150  ({ \
151  dif_toggle_t clock_state; \
152  TRY(dif_clkmgr_hintable_clock_get_enabled(&clkmgr, clock_id, \
153  &clock_state)); \
154  TRY_CHECK(clock_state == expected_state, \
155  "Clock enabled state is (%d) and not as expected (%d).", \
156  clock_state, expected_state); \
157  OK_STATUS(); \
158  })
159 
160 /**
161  * Set and verifies the given clock state.
162  *
163  * Note: The clkmgr register access occurs on a clock that is circa 4 times
164  * slower than the hintable clock being manipulated, which means that
165  * reading back immediately runs the risk of the hint state not yet
166  * having taken effect.
167  * Conversely if we delay too long - say one microsecond - then the
168  * controlled IP block may have returned to its idle state.
169  *
170  * @param clkmgr A clkmgr DIF handle.
171  * @param clock_id The transactional clock ID.
172  * @param new_state Clock state to be set.
173  * @param expected_state Expected clock state.
174  * @return Return `kInternal` in case of errors, otherwise `kOk(0)`.
175  */
176 #define CLKMGR_TESTUTILS_SET_AND_CHECK_CLOCK_HINT(clkmgr, clock_id, new_state, \
177  expected_state) \
178  ({ \
179  /* The hintable clock shall be read _almost_ immediately after setting it, \
180  * so we check for any errors afterwards. */ \
181  dif_result_t set_res = \
182  dif_clkmgr_hintable_clock_set_hint(&clkmgr, clock_id, new_state); \
183  dif_toggle_t hint_state; \
184  /* This read back mainly serves to introduce a sub-microsecond delay to \
185  * accommodate the fact that clkmgr register access occurs on a clock that \
186  * is circa 4 times slower than the software-hintable clock. */ \
187  dif_result_t hint_get_res = \
188  dif_clkmgr_hintable_clock_get_hint(&clkmgr, clock_id, &hint_state); \
189  /* Now check the new clock enable state. */ \
190  dif_toggle_t clock_state; \
191  dif_result_t get_res = dif_clkmgr_hintable_clock_get_enabled( \
192  &clkmgr, clock_id, &clock_state); \
193  TRY(set_res); \
194  TRY(hint_get_res); \
195  TRY(get_res); \
196  TRY_CHECK(hint_state == new_state, \
197  "Clock hint state is (%d) and not as requested (%d).", \
198  hint_state, new_state); \
199  TRY_CHECK(clock_state == expected_state, \
200  "Clock enabled state is (%d) and not as expected (%d).", \
201  clock_state, expected_state); \
202  OK_STATUS(); \
203  })
204 
205 #undef MODULE_ID
206 
207 #endif // OPENTITAN_SW_DEVICE_LIB_TESTING_CLKMGR_TESTUTILS_H_