Software APIs
clkmgr_testutils.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 "sw/device/lib/testing/clkmgr_testutils.h"
6
9
10#define MODULE_ID MAKE_MODULE_ID('c', 'm', 't')
11
12static const char *measure_clock_names[kDifClkmgrMeasureClockCount] = {
13#if defined(OPENTITAN_IS_EARLGREY)
14 "io_clk", "io_div2_clk",
15#elif defined(OPENTITAN_IS_DARJEELING)
16// Darjeeling does not have Io / IoDiv2 clock measurements
17#else
18#error Unsupported top
19#endif
20 "io_div4_clk", "main_clk", "usb_clk"};
21
22// `extern` declarations to give the inline functions in the
23// corresponding header a link location.
24
25extern bool clkmgr_testutils_get_trans_clock_status(
26 const dif_clkmgr_t *clkmgr, dif_clkmgr_hintable_clock_t clock);
27
28extern status_t clkmgr_testutils_check_trans_clock_gating(
29 const dif_clkmgr_t *clkmgr, dif_clkmgr_hintable_clock_t clock,
30 bool exp_clock_enabled, uint32_t timeout_usec);
31
32// The thresholds are encoded as
33// - max = count + variability
34// - min = count - variability
35typedef struct expected_count_info {
36 uint32_t count;
37 uint32_t variability;
38} expected_count_info_t;
39
40// The expected counts when jitter is disabled.
41static expected_count_info_t kNoJitterCountInfos[kDifClkmgrMeasureClockCount];
42
43// The expected counts when jitter is enabled.
44static expected_count_info_t kJitterCountInfos[kDifClkmgrMeasureClockCount];
45
46// Notice the expected variability is set to somewhat less than the added
47// variability of the AON and the measured clock.
48
49// The expected variability as a percentage. The AST guarantees 3% for all
50// clocks, including the AON, so the effective variability is set to 5%.
51static uint32_t kVariabilityPercentage = 5;
52
53// The expected variability when jitter is enabled as a percentage. The AST
54// guarantees 10% for jittery clocks and 3% for the AON clock, so the
55// effective variability is set to 12%.
56static uint32_t kJitterVariabilityPercentage = 12;
57
58// Compute the variability for a given number of cycles, adding an extra cycle
59// for synchronizers.
60static inline uint32_t get_count_variability(uint32_t cycles,
61 uint32_t variability_percentage) {
62 return ((cycles * variability_percentage) + 99) / 100 + 1;
63}
64
65static uint32_t cast_safely(uint64_t val) {
66 CHECK(val <= UINT32_MAX);
67 return (uint32_t)val;
68}
69
70void initialize_expected_counts(void) {
71 // The expected counts depend on the device, per sw/device/lib/arch/device.h.
72 // Notice the ratios are small enough to fit a uint32_t, even if the Hz number
73 // is in uint64_t.
74 // The expected counts are derived from the ratios of the frequencies of the
75 // various clocks to the AON clock. For example, 48 Mhz / 200 kHz = 240.
76 const uint32_t kDeviceCpuCount =
77 cast_safely(udiv64_slow(kClockFreqCpuHz, kClockFreqAonHz,
78 /*rem_out=*/NULL));
79 const uint32_t kDeviceIoCount =
80 cast_safely(udiv64_slow(kClockFreqPeripheralHz, kClockFreqAonHz,
81 /*rem_out=*/NULL) *
82 4);
83#if defined(OPENTITAN_IS_EARLGREY)
84 const uint32_t kDeviceIoDiv2Count =
85 cast_safely(udiv64_slow(kClockFreqPeripheralHz, kClockFreqAonHz,
86 /*rem_out=*/NULL) *
87 2);
88#endif
89 const uint32_t kDeviceIoDiv4Count =
90 cast_safely(udiv64_slow(kClockFreqPeripheralHz, kClockFreqAonHz,
91 /*rem_out=*/NULL));
92 const uint32_t kDeviceUsbCount =
93 cast_safely(udiv64_slow(kClockFreqUsbHz, kClockFreqAonHz,
94 /*rem_out=*/NULL));
95
96 LOG_INFO("Variability for Io %d is %d", kDeviceIoCount,
97 get_count_variability(kDeviceIoCount, kVariabilityPercentage));
98 LOG_INFO("Variability for Cpu %d is %d", kDeviceCpuCount,
99 get_count_variability(kDeviceCpuCount, kVariabilityPercentage));
100
101 // Each clock count is guaranteed by the AST +- 3%. This includes the AON
102 // clock, so we use an effective variability of +- 5%.
103#if defined(OPENTITAN_IS_EARLGREY)
104 kNoJitterCountInfos[kDifClkmgrMeasureClockIo] =
105 (expected_count_info_t){.count = kDeviceIoCount - 1,
106 .variability = get_count_variability(
107 kDeviceIoCount, kVariabilityPercentage)};
108 kNoJitterCountInfos[kDifClkmgrMeasureClockIoDiv2] =
109 (expected_count_info_t){.count = kDeviceIoDiv2Count - 1,
110 .variability = get_count_variability(
111 kDeviceIoDiv2Count, kVariabilityPercentage)};
112#endif
113 kNoJitterCountInfos[kDifClkmgrMeasureClockIoDiv4] =
114 (expected_count_info_t){.count = kDeviceIoDiv4Count - 1,
115 .variability = get_count_variability(
116 kDeviceIoDiv4Count, kVariabilityPercentage)};
117 kNoJitterCountInfos[kDifClkmgrMeasureClockMain] =
118 (expected_count_info_t){.count = kDeviceCpuCount - 1,
119 .variability = get_count_variability(
120 kDeviceCpuCount, kVariabilityPercentage)};
121 kNoJitterCountInfos[kDifClkmgrMeasureClockUsb] =
122 (expected_count_info_t){.count = kDeviceUsbCount - 1,
123 .variability = get_count_variability(
124 kDeviceUsbCount, kVariabilityPercentage)};
125
126 // When jitter is enabled only the main clk is affected: the low threshold
127 // should be up to 20% lower, so the expected count is set to 0.9 max, and
128 // the variability is set per kJitterVariabilityPercentage.
129#if defined(OPENTITAN_IS_EARLGREY)
130 kJitterCountInfos[kDifClkmgrMeasureClockIo] =
131 kNoJitterCountInfos[kDifClkmgrMeasureClockIo];
132 kJitterCountInfos[kDifClkmgrMeasureClockIoDiv2] =
133 kNoJitterCountInfos[kDifClkmgrMeasureClockIoDiv2];
134#endif
135 kJitterCountInfos[kDifClkmgrMeasureClockIoDiv4] =
136 kNoJitterCountInfos[kDifClkmgrMeasureClockIoDiv4];
137 kJitterCountInfos[kDifClkmgrMeasureClockMain] =
138 (expected_count_info_t){.count = kDeviceCpuCount - kDeviceCpuCount / 10,
139 .variability = get_count_variability(
140 kDeviceCpuCount - kDeviceCpuCount / 10,
141 kJitterVariabilityPercentage)};
142 kJitterCountInfos[kDifClkmgrMeasureClockUsb] =
143 kNoJitterCountInfos[kDifClkmgrMeasureClockUsb];
144}
145
146const char *clkmgr_testutils_measurement_name(
147 dif_clkmgr_measure_clock_t clock) {
148 switch (clock) {
149#if defined(OPENTITAN_IS_EARLGREY)
150 case kDifClkmgrMeasureClockIo:
151 return "io";
152 case kDifClkmgrMeasureClockIoDiv2:
153 return "io_div2";
154#endif
156 return "io_div4";
158 return "main";
160 return "usb";
161 default:
162 LOG_ERROR("Unexpected clock measurement %d", clock);
163 }
164 return "unexpected clock";
165}
166
167status_t clkmgr_testutils_enable_clock_count(const dif_clkmgr_t *clkmgr,
168 dif_clkmgr_measure_clock_t clock,
169 uint32_t lo_threshold,
170 uint32_t hi_threshold) {
171 LOG_INFO("Enabling clock count measurement for %s(%d) lo %d hi %d",
172 measure_clock_names[clock], clock, lo_threshold, hi_threshold);
173 TRY(dif_clkmgr_enable_measure_counts(clkmgr, clock, lo_threshold,
174 hi_threshold));
175 return OK_STATUS();
176}
177
178status_t clkmgr_testutils_enable_clock_counts_with_expected_thresholds(
179 const dif_clkmgr_t *clkmgr, bool jitter_enabled, bool external_clk,
180 bool low_speed) {
181 static bool counts_initialized = false;
182 if (!counts_initialized) {
183 initialize_expected_counts();
184 counts_initialized = true;
185 }
186 TRY_CHECK(!(external_clk && jitter_enabled));
187 for (int clk = 0; clk < ARRAYSIZE(kNoJitterCountInfos); ++clk) {
188 const expected_count_info_t *count_info;
189 if (jitter_enabled) {
190 count_info = &kJitterCountInfos[clk];
191 } else if (external_clk) {
192#if defined(OPENTITAN_IS_EARLGREY)
193 if (low_speed) {
194 if (clk == kDifClkmgrMeasureClockIo ||
196 count_info = &kNoJitterCountInfos[kDifClkmgrMeasureClockIoDiv2];
197 } else {
198 count_info = &kNoJitterCountInfos[clk];
199 }
200 } else {
201 if (clk == kDifClkmgrMeasureClockMain) {
202 count_info = &kNoJitterCountInfos[kDifClkmgrMeasureClockIo];
203 } else {
204 count_info = &kNoJitterCountInfos[clk];
205 }
206 }
207#elif defined(OPENTITAN_IS_DARJEELING)
208 TRY_CHECK(false, "Darjeeling has no external clock");
210#else
211#error Unsupported top
212#endif
213 } else {
214 count_info = &kNoJitterCountInfos[clk];
215 }
216 TRY(clkmgr_testutils_enable_clock_count(
217 clkmgr, (dif_clkmgr_measure_clock_t)clk,
218 count_info->count - count_info->variability,
219 count_info->count + count_info->variability));
220 }
221 return OK_STATUS();
222}
223
224status_t clkmgr_testutils_check_measurement_enables(
225 const dif_clkmgr_t *clkmgr, dif_toggle_t expected_status) {
226 bool success = true;
227 for (int i = 0; i < kDifClkmgrMeasureClockCount; ++i) {
228 dif_clkmgr_measure_clock_t clock = (dif_clkmgr_measure_clock_t)i;
229 dif_toggle_t actual_status;
230 TRY(dif_clkmgr_measure_counts_get_enable(clkmgr, clock, &actual_status));
231 if (actual_status != expected_status) {
232 LOG_INFO("Unexpected enable for clock %d: expected %s", i,
233 (expected_status == kDifToggleEnabled ? "enabled" : "disabled"));
234 success = false;
235 }
236 }
237 return OK_STATUS(success);
238}
239
240status_t clkmgr_testutils_disable_clock_counts(const dif_clkmgr_t *clkmgr) {
241 LOG_INFO("Disabling all clock count measurements");
242 for (int i = 0; i < kDifClkmgrMeasureClockCount; ++i) {
243 dif_clkmgr_measure_clock_t clock = (dif_clkmgr_measure_clock_t)i;
244 TRY(dif_clkmgr_disable_measure_counts(clkmgr, clock));
245 }
246 LOG_INFO("Disabling all clock count done");
247 return OK_STATUS();
248}
249
250status_t clkmgr_testutils_check_measurement_counts(const dif_clkmgr_t *clkmgr) {
251 status_t result = OK_STATUS();
253 TRY(dif_clkmgr_recov_err_code_get_codes(clkmgr, &err_codes));
254 if (err_codes != 0) {
255 LOG_ERROR("Unexpected recoverable error codes 0x%x", err_codes);
256 result = INTERNAL();
257 } else {
258 LOG_INFO("Clock measurements are okay");
259 }
260 // Clear recoverable errors.
261 TRY(dif_clkmgr_recov_err_code_clear_codes(clkmgr, ~0u));
262 return result;
263}
264
265status_t clkmgr_testutils_enable_external_clock_blocking(
266 const dif_clkmgr_t *clkmgr, bool is_low_speed) {
267 LOG_INFO("Configure clkmgr to enable external clock");
268 TRY(dif_clkmgr_external_clock_set_enabled(clkmgr, is_low_speed));
269 TRY(dif_clkmgr_wait_for_ext_clk_switch(clkmgr));
270 LOG_INFO("Switching to external clock completes");
271 return OK_STATUS();
272}