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 */
23static 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 */
46inline 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 */
62const 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 */
76status_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 */
95status_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 */
106status_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 */
118status_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 */
128status_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 */
138status_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_