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 
12 static 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 
25 extern bool clkmgr_testutils_get_trans_clock_status(
26  const dif_clkmgr_t *clkmgr, dif_clkmgr_hintable_clock_t clock);
27 
28 extern 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
35 typedef struct expected_count_info {
36  uint32_t count;
37  uint32_t variability;
39 
40 // The expected counts when jitter is disabled.
41 static expected_count_info_t kNoJitterCountInfos[kDifClkmgrMeasureClockCount];
42 
43 // The expected counts when jitter is enabled.
44 static 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%.
51 static 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%.
56 static uint32_t kJitterVariabilityPercentage = 12;
57 
58 // Compute the variability for a given number of cycles, adding an extra cycle
59 // for synchronizers.
60 static inline uint32_t get_count_variability(uint32_t cycles,
61  uint32_t variability_percentage) {
62  return ((cycles * variability_percentage) + 99) / 100 + 1;
63 }
64 
65 static uint32_t cast_safely(uint64_t val) {
66  CHECK(val <= UINT32_MAX);
67  return (uint32_t)val;
68 }
69 
70 void 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 =
78  /*rem_out=*/NULL));
79  const uint32_t kDeviceIoCount =
81  /*rem_out=*/NULL) *
82  4);
83 #if defined(OPENTITAN_IS_EARLGREY)
84  const uint32_t kDeviceIoDiv2Count =
86  /*rem_out=*/NULL) *
87  2);
88 #endif
89  const uint32_t kDeviceIoDiv4Count =
91  /*rem_out=*/NULL));
92  const uint32_t kDeviceUsbCount =
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 
146 const 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 
167 status_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 
178 status_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");
209  OT_UNREACHABLE();
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 
224 status_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 
240 status_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 
250 status_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 
265 status_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));
270  LOG_INFO("Switching to external clock completes");
271  return OK_STATUS();
272 }